diff options
Diffstat (limited to 'drivers/rtc/rtc-at91sam9.c')
| -rw-r--r-- | drivers/rtc/rtc-at91sam9.c | 207 | 
1 files changed, 70 insertions, 137 deletions
diff --git a/drivers/rtc/rtc-at91sam9.c b/drivers/rtc/rtc-at91sam9.c index f677e0710ca..59637430453 100644 --- a/drivers/rtc/rtc-at91sam9.c +++ b/drivers/rtc/rtc-at91sam9.c @@ -19,11 +19,12 @@  #include <linux/interrupt.h>  #include <linux/ioctl.h>  #include <linux/slab.h> +#include <linux/platform_data/atmel.h> +#include <linux/io.h> -#include <mach/board.h>  #include <mach/at91_rtt.h>  #include <mach/cpu.h> - +#include <mach/hardware.h>  /*   * This driver uses two configurable hardware resources that live in the @@ -57,6 +58,8 @@ struct sam9_rtc {  	void __iomem		*rtt;  	struct rtc_device	*rtcdev;  	u32			imr; +	void __iomem		*gpbr; +	int 			irq;  };  #define rtt_readl(rtc, field) \ @@ -65,9 +68,9 @@ struct sam9_rtc {  	__raw_writel((val), (rtc)->rtt + AT91_RTT_ ## field)  #define gpbr_readl(rtc) \ -	at91_sys_read(AT91_GPBR + 4 * CONFIG_RTC_DRV_AT91SAM9_GPBR) +	__raw_readl((rtc)->gpbr)  #define gpbr_writel(rtc, val) \ -	at91_sys_write(AT91_GPBR + 4 * CONFIG_RTC_DRV_AT91SAM9_GPBR, (val)) +	__raw_writel((val), (rtc)->gpbr)  /*   * Read current time and date in RTC @@ -216,37 +219,17 @@ static int at91_rtc_setalarm(struct device *dev, struct rtc_wkalrm *alrm)  	return 0;  } -/* - * Handle commands from user-space - */ -static int at91_rtc_ioctl(struct device *dev, unsigned int cmd, -			unsigned long arg) +static int at91_rtc_alarm_irq_enable(struct device *dev, unsigned int enabled)  {  	struct sam9_rtc *rtc = dev_get_drvdata(dev); -	int ret = 0;  	u32 mr = rtt_readl(rtc, MR); -	dev_dbg(dev, "ioctl: cmd=%08x, arg=%08lx, mr %08x\n", cmd, arg, mr); - -	switch (cmd) { -	case RTC_AIE_OFF:		/* alarm off */ -		rtt_writel(rtc, MR, mr & ~AT91_RTT_ALMIEN); -		break; -	case RTC_AIE_ON:		/* alarm on */ +	dev_dbg(dev, "alarm_irq_enable: enabled=%08x, mr %08x\n", enabled, mr); +	if (enabled)  		rtt_writel(rtc, MR, mr | AT91_RTT_ALMIEN); -		break; -	case RTC_UIE_OFF:		/* update off */ -		rtt_writel(rtc, MR, mr & ~AT91_RTT_RTTINCIEN); -		break; -	case RTC_UIE_ON:		/* update on */ -		rtt_writel(rtc, MR, mr | AT91_RTT_RTTINCIEN); -		break; -	default: -		ret = -ENOIOCTLCMD; -		break; -	} - -	return ret; +	else +		rtt_writel(rtc, MR, mr & ~AT91_RTT_ALMIEN); +	return 0;  }  /* @@ -296,39 +279,60 @@ static irqreturn_t at91_rtc_interrupt(int irq, void *_rtc)  }  static const struct rtc_class_ops at91_rtc_ops = { -	.ioctl		= at91_rtc_ioctl,  	.read_time	= at91_rtc_readtime,  	.set_time	= at91_rtc_settime,  	.read_alarm	= at91_rtc_readalarm,  	.set_alarm	= at91_rtc_setalarm,  	.proc		= at91_rtc_proc, +	.alarm_irq_enable = at91_rtc_alarm_irq_enable,  };  /*   * Initialize and install RTC driver   */ -static int __init at91_rtc_probe(struct platform_device *pdev) +static int at91_rtc_probe(struct platform_device *pdev)  { -	struct resource	*r; +	struct resource	*r, *r_gpbr;  	struct sam9_rtc	*rtc; -	int		ret; +	int		ret, irq;  	u32		mr;  	r = platform_get_resource(pdev, IORESOURCE_MEM, 0); -	if (!r) +	r_gpbr = platform_get_resource(pdev, IORESOURCE_MEM, 1); +	if (!r || !r_gpbr) { +		dev_err(&pdev->dev, "need 2 ressources\n");  		return -ENODEV; +	} -	rtc = kzalloc(sizeof *rtc, GFP_KERNEL); +	irq = platform_get_irq(pdev, 0); +	if (irq < 0) { +		dev_err(&pdev->dev, "failed to get interrupt resource\n"); +		return irq; +	} + +	rtc = devm_kzalloc(&pdev->dev, sizeof(*rtc), GFP_KERNEL);  	if (!rtc)  		return -ENOMEM; +	rtc->irq = irq; +  	/* platform setup code should have handled this; sigh */  	if (!device_can_wakeup(&pdev->dev))  		device_init_wakeup(&pdev->dev, 1);  	platform_set_drvdata(pdev, rtc); -	rtc->rtt = (void __force __iomem *) (AT91_VA_BASE_SYS - AT91_BASE_SYS); -	rtc->rtt += r->start; +	rtc->rtt = devm_ioremap(&pdev->dev, r->start, resource_size(r)); +	if (!rtc->rtt) { +		dev_err(&pdev->dev, "failed to map registers, aborting.\n"); +		return -ENOMEM; +	} + +	rtc->gpbr = devm_ioremap(&pdev->dev, r_gpbr->start, +				resource_size(r_gpbr)); +	if (!rtc->gpbr) { +		dev_err(&pdev->dev, "failed to map gpbr registers, aborting.\n"); +		return -ENOMEM; +	}  	mr = rtt_readl(rtc, MR); @@ -342,21 +346,17 @@ static int __init at91_rtc_probe(struct platform_device *pdev)  	mr &= ~(AT91_RTT_ALMIEN | AT91_RTT_RTTINCIEN);  	rtt_writel(rtc, MR, mr); -	rtc->rtcdev = rtc_device_register(pdev->name, &pdev->dev, -				&at91_rtc_ops, THIS_MODULE); -	if (IS_ERR(rtc->rtcdev)) { -		ret = PTR_ERR(rtc->rtcdev); -		goto fail; -	} +	rtc->rtcdev = devm_rtc_device_register(&pdev->dev, pdev->name, +					&at91_rtc_ops, THIS_MODULE); +	if (IS_ERR(rtc->rtcdev)) +		return PTR_ERR(rtc->rtcdev);  	/* register irq handler after we know what name we'll use */ -	ret = request_irq(AT91_ID_SYS, at91_rtc_interrupt, -				IRQF_DISABLED | IRQF_SHARED, -				dev_name(&rtc->rtcdev->dev), rtc); +	ret = devm_request_irq(&pdev->dev, rtc->irq, at91_rtc_interrupt, +				IRQF_SHARED, dev_name(&rtc->rtcdev->dev), rtc);  	if (ret) { -		dev_dbg(&pdev->dev, "can't share IRQ %d?\n", AT91_ID_SYS); -		rtc_device_unregister(rtc->rtcdev); -		goto fail; +		dev_dbg(&pdev->dev, "can't share IRQ %d?\n", rtc->irq); +		return ret;  	}  	/* NOTE:  sam9260 rev A silicon has a ROM bug which resets the @@ -370,29 +370,19 @@ static int __init at91_rtc_probe(struct platform_device *pdev)  				dev_name(&rtc->rtcdev->dev));  	return 0; - -fail: -	platform_set_drvdata(pdev, NULL); -	kfree(rtc); -	return ret;  }  /*   * Disable and remove the RTC driver   */ -static int __exit at91_rtc_remove(struct platform_device *pdev) +static int at91_rtc_remove(struct platform_device *pdev)  {  	struct sam9_rtc	*rtc = platform_get_drvdata(pdev);  	u32		mr = rtt_readl(rtc, MR);  	/* disable all interrupts */  	rtt_writel(rtc, MR, mr & ~(AT91_RTT_ALMIEN | AT91_RTT_RTTINCIEN)); -	free_irq(AT91_ID_SYS, rtc); -	rtc_device_unregister(rtc->rtcdev); - -	platform_set_drvdata(pdev, NULL); -	kfree(rtc);  	return 0;  } @@ -405,14 +395,13 @@ static void at91_rtc_shutdown(struct platform_device *pdev)  	rtt_writel(rtc, MR, mr & ~rtc->imr);  } -#ifdef CONFIG_PM +#ifdef CONFIG_PM_SLEEP  /* AT91SAM9 RTC Power management control */ -static int at91_rtc_suspend(struct platform_device *pdev, -					pm_message_t state) +static int at91_rtc_suspend(struct device *dev)  { -	struct sam9_rtc	*rtc = platform_get_drvdata(pdev); +	struct sam9_rtc	*rtc = dev_get_drvdata(dev);  	u32		mr = rtt_readl(rtc, MR);  	/* @@ -421,8 +410,8 @@ static int at91_rtc_suspend(struct platform_device *pdev,  	 */  	rtc->imr = mr & (AT91_RTT_ALMIEN | AT91_RTT_RTTINCIEN);  	if (rtc->imr) { -		if (device_may_wakeup(&pdev->dev) && (mr & AT91_RTT_ALMIEN)) { -			enable_irq_wake(AT91_ID_SYS); +		if (device_may_wakeup(dev) && (mr & AT91_RTT_ALMIEN)) { +			enable_irq_wake(rtc->irq);  			/* don't let RTTINC cause wakeups */  			if (mr & AT91_RTT_RTTINCIEN)  				rtt_writel(rtc, MR, mr & ~AT91_RTT_RTTINCIEN); @@ -433,92 +422,36 @@ static int at91_rtc_suspend(struct platform_device *pdev,  	return 0;  } -static int at91_rtc_resume(struct platform_device *pdev) +static int at91_rtc_resume(struct device *dev)  { -	struct sam9_rtc	*rtc = platform_get_drvdata(pdev); +	struct sam9_rtc	*rtc = dev_get_drvdata(dev);  	u32		mr;  	if (rtc->imr) { -		if (device_may_wakeup(&pdev->dev)) -			disable_irq_wake(AT91_ID_SYS); +		if (device_may_wakeup(dev)) +			disable_irq_wake(rtc->irq);  		mr = rtt_readl(rtc, MR);  		rtt_writel(rtc, MR, mr | rtc->imr);  	}  	return 0;  } -#else -#define at91_rtc_suspend	NULL -#define at91_rtc_resume		NULL  #endif +static SIMPLE_DEV_PM_OPS(at91_rtc_pm_ops, at91_rtc_suspend, at91_rtc_resume); +  static struct platform_driver at91_rtc_driver = { -	.driver.name	= "rtc-at91sam9", -	.driver.owner	= THIS_MODULE, -	.remove		= __exit_p(at91_rtc_remove), +	.probe		= at91_rtc_probe, +	.remove		= at91_rtc_remove,  	.shutdown	= at91_rtc_shutdown, -	.suspend	= at91_rtc_suspend, -	.resume		= at91_rtc_resume, +	.driver		= { +		.name	= "rtc-at91sam9", +		.owner	= THIS_MODULE, +		.pm	= &at91_rtc_pm_ops, +	},  }; -/* Chips can have more than one RTT module, and they can be used for more - * than just RTCs.  So we can't just register as "the" RTT driver. - * - * A normal approach in such cases is to create a library to allocate and - * free the modules.  Here we just use bus_find_device() as like such a - * library, binding directly ... no runtime "library" footprint is needed. - */ -static int __init at91_rtc_match(struct device *dev, void *v) -{ -	struct platform_device *pdev = to_platform_device(dev); -	int ret; - -	/* continue searching if this isn't the RTT we need */ -	if (strcmp("at91_rtt", pdev->name) != 0 -			|| pdev->id != CONFIG_RTC_DRV_AT91SAM9_RTT) -		goto fail; - -	/* else we found it ... but fail unless we can bind to the RTC driver */ -	if (dev->driver) { -		dev_dbg(dev, "busy, can't use as RTC!\n"); -		goto fail; -	} -	dev->driver = &at91_rtc_driver.driver; -	if (device_attach(dev) == 0) { -		dev_dbg(dev, "can't attach RTC!\n"); -		goto fail; -	} -	ret = at91_rtc_probe(pdev); -	if (ret == 0) -		return true; - -	dev_dbg(dev, "RTC probe err %d!\n", ret); -fail: -	return false; -} - -static int __init at91_rtc_init(void) -{ -	int status; -	struct device *rtc; - -	status = platform_driver_register(&at91_rtc_driver); -	if (status) -		return status; -	rtc = bus_find_device(&platform_bus_type, NULL, -			NULL, at91_rtc_match); -	if (!rtc) -		platform_driver_unregister(&at91_rtc_driver); -	return rtc ? 0 : -ENODEV; -} -module_init(at91_rtc_init); - -static void __exit at91_rtc_exit(void) -{ -	platform_driver_unregister(&at91_rtc_driver); -} -module_exit(at91_rtc_exit); - +module_platform_driver(at91_rtc_driver);  MODULE_AUTHOR("Michel Benoit");  MODULE_DESCRIPTION("RTC driver for Atmel AT91SAM9x");  | 
