From 5e084a1586a864d4e9b3f2edbb1bd3429909d652 Mon Sep 17 00:00:00 2001 From: Magnus Damm Date: Tue, 24 Feb 2009 22:11:03 +0900 Subject: rtc: sh-rtc: Add Single IRQ Support Add support for single IRQ hardware to the sh-rtc driver. This is useful for processors with limited interrupt masking support such as sh7750 and sh7780. With this patch in place we can add logic to the intc code that merges all RTC vectors into a single linux interrupt with proper masking/unmasking support. Specify a single IRQ in the platform data to use this new shared IRQ feature. Separate Periodic/Carry/Alarm IRQs are still supported. Signed-off-by: Magnus Damm Signed-off-by: Paul Mundt --- drivers/rtc/rtc-sh.c | 190 +++++++++++++++++++++++++++++++-------------------- 1 file changed, 117 insertions(+), 73 deletions(-) (limited to 'drivers/rtc') diff --git a/drivers/rtc/rtc-sh.c b/drivers/rtc/rtc-sh.c index 1c3fc6b428e9..b37f44b0406e 100644 --- a/drivers/rtc/rtc-sh.c +++ b/drivers/rtc/rtc-sh.c @@ -99,56 +99,51 @@ struct sh_rtc { unsigned short periodic_freq; }; -static irqreturn_t sh_rtc_interrupt(int irq, void *dev_id) +static int __sh_rtc_interrupt(struct sh_rtc *rtc) { - struct sh_rtc *rtc = dev_id; - unsigned int tmp; - - spin_lock(&rtc->lock); + unsigned int tmp, pending; tmp = readb(rtc->regbase + RCR1); + pending = tmp & RCR1_CF; tmp &= ~RCR1_CF; writeb(tmp, rtc->regbase + RCR1); /* Users have requested One x Second IRQ */ - if (rtc->periodic_freq & PF_OXS) + if (pending && rtc->periodic_freq & PF_OXS) rtc_update_irq(rtc->rtc_dev, 1, RTC_UF | RTC_IRQF); - spin_unlock(&rtc->lock); - - return IRQ_HANDLED; + return pending; } -static irqreturn_t sh_rtc_alarm(int irq, void *dev_id) +static int __sh_rtc_alarm(struct sh_rtc *rtc) { - struct sh_rtc *rtc = dev_id; - unsigned int tmp; - - spin_lock(&rtc->lock); + unsigned int tmp, pending; tmp = readb(rtc->regbase + RCR1); + pending = tmp & RCR1_AF; tmp &= ~(RCR1_AF | RCR1_AIE); - writeb(tmp, rtc->regbase + RCR1); - - rtc_update_irq(rtc->rtc_dev, 1, RTC_AF | RTC_IRQF); + writeb(tmp, rtc->regbase + RCR1); - spin_unlock(&rtc->lock); + if (pending) + rtc_update_irq(rtc->rtc_dev, 1, RTC_AF | RTC_IRQF); - return IRQ_HANDLED; + return pending; } -static irqreturn_t sh_rtc_periodic(int irq, void *dev_id) +static int __sh_rtc_periodic(struct sh_rtc *rtc) { - struct sh_rtc *rtc = dev_id; struct rtc_device *rtc_dev = rtc->rtc_dev; - unsigned int tmp; - - spin_lock(&rtc->lock); + struct rtc_task *irq_task; + unsigned int tmp, pending; tmp = readb(rtc->regbase + RCR2); + pending = tmp & RCR2_PEF; tmp &= ~RCR2_PEF; writeb(tmp, rtc->regbase + RCR2); + if (!pending) + return 0; + /* Half period enabled than one skipped and the next notified */ if ((rtc->periodic_freq & PF_HP) && (rtc->periodic_freq & PF_COUNT)) rtc->periodic_freq &= ~PF_COUNT; @@ -157,16 +152,65 @@ static irqreturn_t sh_rtc_periodic(int irq, void *dev_id) rtc->periodic_freq |= PF_COUNT; if (rtc->periodic_freq & PF_KOU) { spin_lock(&rtc_dev->irq_task_lock); - if (rtc_dev->irq_task) - rtc_dev->irq_task->func(rtc_dev->irq_task->private_data); + irq_task = rtc_dev->irq_task; + if (irq_task) + irq_task->func(irq_task->private_data); spin_unlock(&rtc_dev->irq_task_lock); } else rtc_update_irq(rtc->rtc_dev, 1, RTC_PF | RTC_IRQF); } + return pending; +} + +static irqreturn_t sh_rtc_interrupt(int irq, void *dev_id) +{ + struct sh_rtc *rtc = dev_id; + int ret; + + spin_lock(&rtc->lock); + ret = __sh_rtc_interrupt(rtc); + spin_unlock(&rtc->lock); + + return IRQ_RETVAL(ret); +} + +static irqreturn_t sh_rtc_alarm(int irq, void *dev_id) +{ + struct sh_rtc *rtc = dev_id; + int ret; + + spin_lock(&rtc->lock); + ret = __sh_rtc_alarm(rtc); + spin_unlock(&rtc->lock); + + return IRQ_RETVAL(ret); +} + +static irqreturn_t sh_rtc_periodic(int irq, void *dev_id) +{ + struct sh_rtc *rtc = dev_id; + int ret; + + spin_lock(&rtc->lock); + ret = __sh_rtc_periodic(rtc); spin_unlock(&rtc->lock); - return IRQ_HANDLED; + return IRQ_RETVAL(ret); +} + +static irqreturn_t sh_rtc_shared(int irq, void *dev_id) +{ + struct sh_rtc *rtc = dev_id; + int ret; + + spin_lock(&rtc->lock); + ret = __sh_rtc_interrupt(rtc); + ret |= __sh_rtc_alarm(rtc); + ret |= __sh_rtc_periodic(rtc); + spin_unlock(&rtc->lock); + + return IRQ_RETVAL(ret); } static inline void sh_rtc_setpie(struct device *dev, unsigned int enable) @@ -585,26 +629,12 @@ static int __devinit sh_rtc_probe(struct platform_device *pdev) ret = platform_get_irq(pdev, 0); if (unlikely(ret <= 0)) { ret = -ENOENT; - dev_err(&pdev->dev, "No IRQ for period\n"); + dev_err(&pdev->dev, "No IRQ resource\n"); goto err_badres; } rtc->periodic_irq = ret; - - ret = platform_get_irq(pdev, 1); - if (unlikely(ret <= 0)) { - ret = -ENOENT; - dev_err(&pdev->dev, "No IRQ for carry\n"); - goto err_badres; - } - rtc->carry_irq = ret; - - ret = platform_get_irq(pdev, 2); - if (unlikely(ret <= 0)) { - ret = -ENOENT; - dev_err(&pdev->dev, "No IRQ for alarm\n"); - goto err_badres; - } - rtc->alarm_irq = ret; + rtc->carry_irq = platform_get_irq(pdev, 1); + rtc->alarm_irq = platform_get_irq(pdev, 2); res = platform_get_resource(pdev, IORESOURCE_IO, 0); if (unlikely(res == NULL)) { @@ -651,35 +681,47 @@ static int __devinit sh_rtc_probe(struct platform_device *pdev) platform_set_drvdata(pdev, rtc); - /* register periodic/carry/alarm irqs */ - ret = request_irq(rtc->periodic_irq, sh_rtc_periodic, IRQF_DISABLED, - "sh-rtc period", rtc); - if (unlikely(ret)) { - dev_err(&pdev->dev, - "request period IRQ failed with %d, IRQ %d\n", ret, - rtc->periodic_irq); - goto err_unmap; - } + if (rtc->carry_irq <= 0) { + /* register shared periodic/carry/alarm irq */ + ret = request_irq(rtc->periodic_irq, sh_rtc_shared, + IRQF_DISABLED, "sh-rtc", rtc); + if (unlikely(ret)) { + dev_err(&pdev->dev, + "request IRQ failed with %d, IRQ %d\n", ret, + rtc->periodic_irq); + goto err_unmap; + } + } else { + /* register periodic/carry/alarm irqs */ + ret = request_irq(rtc->periodic_irq, sh_rtc_periodic, + IRQF_DISABLED, "sh-rtc period", rtc); + if (unlikely(ret)) { + dev_err(&pdev->dev, + "request period IRQ failed with %d, IRQ %d\n", + ret, rtc->periodic_irq); + goto err_unmap; + } - ret = request_irq(rtc->carry_irq, sh_rtc_interrupt, IRQF_DISABLED, - "sh-rtc carry", rtc); - if (unlikely(ret)) { - dev_err(&pdev->dev, - "request carry IRQ failed with %d, IRQ %d\n", ret, - rtc->carry_irq); - free_irq(rtc->periodic_irq, rtc); - goto err_unmap; - } + ret = request_irq(rtc->carry_irq, sh_rtc_interrupt, + IRQF_DISABLED, "sh-rtc carry", rtc); + if (unlikely(ret)) { + dev_err(&pdev->dev, + "request carry IRQ failed with %d, IRQ %d\n", + ret, rtc->carry_irq); + free_irq(rtc->periodic_irq, rtc); + goto err_unmap; + } - ret = request_irq(rtc->alarm_irq, sh_rtc_alarm, IRQF_DISABLED, - "sh-rtc alarm", rtc); - if (unlikely(ret)) { - dev_err(&pdev->dev, - "request alarm IRQ failed with %d, IRQ %d\n", ret, - rtc->alarm_irq); - free_irq(rtc->carry_irq, rtc); - free_irq(rtc->periodic_irq, rtc); - goto err_unmap; + ret = request_irq(rtc->alarm_irq, sh_rtc_alarm, + IRQF_DISABLED, "sh-rtc alarm", rtc); + if (unlikely(ret)) { + dev_err(&pdev->dev, + "request alarm IRQ failed with %d, IRQ %d\n", + ret, rtc->alarm_irq); + free_irq(rtc->carry_irq, rtc); + free_irq(rtc->periodic_irq, rtc); + goto err_unmap; + } } tmp = readb(rtc->regbase + RCR1); @@ -709,9 +751,11 @@ static int __devexit sh_rtc_remove(struct platform_device *pdev) sh_rtc_setpie(&pdev->dev, 0); sh_rtc_setaie(&pdev->dev, 0); - free_irq(rtc->carry_irq, rtc); free_irq(rtc->periodic_irq, rtc); - free_irq(rtc->alarm_irq, rtc); + if (rtc->carry_irq > 0) { + free_irq(rtc->carry_irq, rtc); + free_irq(rtc->alarm_irq, rtc); + } release_resource(rtc->res); -- cgit v1.2.2 From e26b926a561ba24bfeb8a15bfc848f97052a50f4 Mon Sep 17 00:00:00 2001 From: Paul Mundt Date: Fri, 6 Mar 2009 18:51:33 +0900 Subject: rtc: rtc-sh: Bump version up to reflect single IRQ support changes. Signed-off-by: Paul Mundt --- drivers/rtc/rtc-sh.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/rtc') diff --git a/drivers/rtc/rtc-sh.c b/drivers/rtc/rtc-sh.c index b37f44b0406e..aeff25111979 100644 --- a/drivers/rtc/rtc-sh.c +++ b/drivers/rtc/rtc-sh.c @@ -28,7 +28,7 @@ #include #define DRV_NAME "sh-rtc" -#define DRV_VERSION "0.2.0" +#define DRV_VERSION "0.2.1" #define RTC_REG(r) ((r) * rtc_reg_size) -- cgit v1.2.2 From 5bf3df3f00f507119a26ba0780aa8799e741615c Mon Sep 17 00:00:00 2001 From: Eric Miao Date: Tue, 20 Jan 2009 11:04:16 +0800 Subject: [ARM] pxa: separate definitions from pxa-regs.h and remove it finally The remaining registers are separated into: - - - and then we can remove pxa-regs.h completely. Instead of #include this file, let's: 1. include the specific with care (if that's absolutely necessary) 2. define the registers in the driver, make cleanly defined API to expose the register access to external with sufficient reason Signed-off-by: Eric Miao --- drivers/rtc/rtc-sa1100.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'drivers/rtc') diff --git a/drivers/rtc/rtc-sa1100.c b/drivers/rtc/rtc-sa1100.c index d26a5f82aaba..4f247e4dd3f9 100644 --- a/drivers/rtc/rtc-sa1100.c +++ b/drivers/rtc/rtc-sa1100.c @@ -35,7 +35,8 @@ #include #ifdef CONFIG_ARCH_PXA -#include +#include +#include #endif #define RTC_DEF_DIVIDER 32768 - 1 -- cgit v1.2.2 From 9cd88b90a6008b0d744187fab80ade4c81c6536f Mon Sep 17 00:00:00 2001 From: Magnus Damm Date: Thu, 19 Mar 2009 10:05:58 +0000 Subject: sh: sh-rtc carry interrupt rework This patch modifies the SuperH RTC driver to only enable carry interrupts when needed. So by default no interrupts are enabled with this patch. Without this patch a suspending system will most likely wake up by the carry interrupt regardless if the alarm interrupt has been enabled or not. Signed-off-by: Magnus Damm Signed-off-by: Paul Mundt --- drivers/rtc/rtc-sh.c | 40 ++++++++++++++++++++++++++++++++-------- 1 file changed, 32 insertions(+), 8 deletions(-) (limited to 'drivers/rtc') diff --git a/drivers/rtc/rtc-sh.c b/drivers/rtc/rtc-sh.c index aeff25111979..21e7435daecb 100644 --- a/drivers/rtc/rtc-sh.c +++ b/drivers/rtc/rtc-sh.c @@ -319,6 +319,25 @@ static int sh_rtc_proc(struct device *dev, struct seq_file *seq) return 0; } +static inline void sh_rtc_setcie(struct device *dev, unsigned int enable) +{ + struct sh_rtc *rtc = dev_get_drvdata(dev); + unsigned int tmp; + + spin_lock_irq(&rtc->lock); + + tmp = readb(rtc->regbase + RCR1); + + if (!enable) + tmp &= ~RCR1_CIE; + else + tmp |= RCR1_CIE; + + writeb(tmp, rtc->regbase + RCR1); + + spin_unlock_irq(&rtc->lock); +} + static int sh_rtc_ioctl(struct device *dev, unsigned int cmd, unsigned long arg) { struct sh_rtc *rtc = dev_get_drvdata(dev); @@ -335,9 +354,11 @@ static int sh_rtc_ioctl(struct device *dev, unsigned int cmd, unsigned long arg) break; case RTC_UIE_OFF: rtc->periodic_freq &= ~PF_OXS; + sh_rtc_setcie(dev, 0); break; case RTC_UIE_ON: rtc->periodic_freq |= PF_OXS; + sh_rtc_setcie(dev, 1); break; case RTC_IRQP_READ: ret = put_user(rtc->rtc_dev->irq_freq, @@ -400,6 +421,10 @@ static int sh_rtc_read_time(struct device *dev, struct rtc_time *tm) tm->tm_sec--; #endif + /* only keep the carry interrupt enabled if UIE is on */ + if (!(rtc->periodic_freq & PF_OXS)) + sh_rtc_setcie(dev, 0); + dev_dbg(dev, "%s: tm is secs=%d, mins=%d, hours=%d, " "mday=%d, mon=%d, year=%d, wday=%d\n", __func__, @@ -616,7 +641,6 @@ static int __devinit sh_rtc_probe(struct platform_device *pdev) { struct sh_rtc *rtc; struct resource *res; - unsigned int tmp; int ret; rtc = kzalloc(sizeof(struct sh_rtc), GFP_KERNEL); @@ -676,8 +700,6 @@ static int __devinit sh_rtc_probe(struct platform_device *pdev) } rtc->rtc_dev->max_user_freq = 256; - rtc->rtc_dev->irq_freq = 1; - rtc->periodic_freq = 0x60; platform_set_drvdata(pdev, rtc); @@ -724,11 +746,12 @@ static int __devinit sh_rtc_probe(struct platform_device *pdev) } } - tmp = readb(rtc->regbase + RCR1); - tmp &= ~RCR1_CF; - tmp |= RCR1_CIE; - writeb(tmp, rtc->regbase + RCR1); - + /* everything disabled by default */ + rtc->periodic_freq = 0; + rtc->rtc_dev->irq_freq = 0; + sh_rtc_setpie(&pdev->dev, 0); + sh_rtc_setaie(&pdev->dev, 0); + sh_rtc_setcie(&pdev->dev, 0); return 0; err_unmap: @@ -750,6 +773,7 @@ static int __devexit sh_rtc_remove(struct platform_device *pdev) sh_rtc_setpie(&pdev->dev, 0); sh_rtc_setaie(&pdev->dev, 0); + sh_rtc_setcie(&pdev->dev, 0); free_irq(rtc->periodic_irq, rtc); if (rtc->carry_irq > 0) { -- cgit v1.2.2 From edf22477dab5ff3be612af56ee4300ca63e11d06 Mon Sep 17 00:00:00 2001 From: Magnus Damm Date: Thu, 19 Mar 2009 10:10:44 +0000 Subject: sh: sh-rtc invalid time rework This patch modifies invalid time handling in the SuperH RTC driver. Instead of zeroing the returned value at read-out time we just return an error code and reset invalid values during probe. Signed-off-by: Magnus Damm Signed-off-by: Paul Mundt --- drivers/rtc/rtc-sh.c | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) (limited to 'drivers/rtc') diff --git a/drivers/rtc/rtc-sh.c b/drivers/rtc/rtc-sh.c index 21e7435daecb..9ab660c28fee 100644 --- a/drivers/rtc/rtc-sh.c +++ b/drivers/rtc/rtc-sh.c @@ -431,12 +431,7 @@ static int sh_rtc_read_time(struct device *dev, struct rtc_time *tm) tm->tm_sec, tm->tm_min, tm->tm_hour, tm->tm_mday, tm->tm_mon + 1, tm->tm_year, tm->tm_wday); - if (rtc_valid_tm(tm) < 0) { - dev_err(dev, "invalid date\n"); - rtc_time_to_tm(0, tm); - } - - return 0; + return rtc_valid_tm(tm); } static int sh_rtc_set_time(struct device *dev, struct rtc_time *tm) @@ -641,6 +636,7 @@ static int __devinit sh_rtc_probe(struct platform_device *pdev) { struct sh_rtc *rtc; struct resource *res; + struct rtc_time r; int ret; rtc = kzalloc(sizeof(struct sh_rtc), GFP_KERNEL); @@ -752,6 +748,13 @@ static int __devinit sh_rtc_probe(struct platform_device *pdev) sh_rtc_setpie(&pdev->dev, 0); sh_rtc_setaie(&pdev->dev, 0); sh_rtc_setcie(&pdev->dev, 0); + + /* reset rtc to epoch 0 if time is invalid */ + if (rtc_read_time(rtc->rtc_dev, &r) < 0) { + rtc_time_to_tm(0, &r); + rtc_set_time(rtc->rtc_dev, &r); + } + return 0; err_unmap: -- cgit v1.2.2 From 7a8fe8e320251d25274e89f610ffee936769250a Mon Sep 17 00:00:00 2001 From: Magnus Damm Date: Thu, 19 Mar 2009 10:14:41 +0000 Subject: sh: sh-rtc wakeup support Flag that the SuperH RTC supports wakeup. Signed-off-by: Magnus Damm Signed-off-by: Paul Mundt --- drivers/rtc/rtc-sh.c | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers/rtc') diff --git a/drivers/rtc/rtc-sh.c b/drivers/rtc/rtc-sh.c index 9ab660c28fee..4898f7fe8518 100644 --- a/drivers/rtc/rtc-sh.c +++ b/drivers/rtc/rtc-sh.c @@ -755,6 +755,7 @@ static int __devinit sh_rtc_probe(struct platform_device *pdev) rtc_set_time(rtc->rtc_dev, &r); } + device_init_wakeup(&pdev->dev, 1); return 0; err_unmap: -- cgit v1.2.2 From 9d1d4f9eabbca276a2a618a94ed3149d5971063e Mon Sep 17 00:00:00 2001 From: Nicolas Pitre Date: Mon, 23 Mar 2009 20:42:29 -0400 Subject: [ARM] Kirkwood: fail the probe if internal RTC does not work Having a RTC that doesn't maintain proper time across a reboot is one thing. But a RTC that doesn't work at all and only causes timeouts is another. Tested-by: Martin Michlmayr Signed-off-by: Nicolas Pitre --- drivers/rtc/rtc-mv.c | 11 +++++++++++ 1 file changed, 11 insertions(+) (limited to 'drivers/rtc') diff --git a/drivers/rtc/rtc-mv.c b/drivers/rtc/rtc-mv.c index 45f12dcd3716..e0263d2005ee 100644 --- a/drivers/rtc/rtc-mv.c +++ b/drivers/rtc/rtc-mv.c @@ -12,6 +12,7 @@ #include #include #include +#include #define RTC_TIME_REG_OFFS 0 @@ -119,6 +120,16 @@ static int __init mv_rtc_probe(struct platform_device *pdev) return -EINVAL; } + /* make sure it is actually functional */ + if (rtc_time == 0x01000000) { + ssleep(1); + rtc_time = readl(pdata->ioaddr + RTC_TIME_REG_OFFS); + if (rtc_time == 0x01000000) { + dev_err(&pdev->dev, "internal RTC not ticking\n"); + return -ENODEV; + } + } + platform_set_drvdata(pdev, pdata); pdata->rtc = rtc_device_register(pdev->name, &pdev->dev, &mv_rtc_ops, THIS_MODULE); -- cgit v1.2.2 From 744bcb13d376b38ff1df3bbcc810493e1b999502 Mon Sep 17 00:00:00 2001 From: Kay Sievers Date: Tue, 24 Mar 2009 16:38:22 -0700 Subject: rtc: struct device - replace bus_id with dev_name(), dev_set_name() Cc: a.zummo@towertech.it Cc: rtc-linux@googlegroups.com Signed-off-by: Kay Sievers Signed-off-by: Alessandro Zummo Signed-off-by: Greg Kroah-Hartman --- drivers/rtc/rtc-at91sam9.c | 4 ++-- drivers/rtc/rtc-omap.c | 4 ++-- drivers/rtc/rtc-twl4030.c | 2 +- 3 files changed, 5 insertions(+), 5 deletions(-) (limited to 'drivers/rtc') diff --git a/drivers/rtc/rtc-at91sam9.c b/drivers/rtc/rtc-at91sam9.c index d5e4e637ddec..86c61f143515 100644 --- a/drivers/rtc/rtc-at91sam9.c +++ b/drivers/rtc/rtc-at91sam9.c @@ -351,7 +351,7 @@ static int __init at91_rtc_probe(struct platform_device *pdev) /* register irq handler after we know what name we'll use */ ret = request_irq(AT91_ID_SYS, at91_rtc_interrupt, IRQF_DISABLED | IRQF_SHARED, - rtc->rtcdev->dev.bus_id, rtc); + 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); @@ -366,7 +366,7 @@ static int __init at91_rtc_probe(struct platform_device *pdev) if (gpbr_readl(rtc) == 0) dev_warn(&pdev->dev, "%s: SET TIME!\n", - rtc->rtcdev->dev.bus_id); + dev_name(&rtc->rtcdev->dev)); return 0; diff --git a/drivers/rtc/rtc-omap.c b/drivers/rtc/rtc-omap.c index 2cbeb0794f14..bd1ce8e2bc18 100644 --- a/drivers/rtc/rtc-omap.c +++ b/drivers/rtc/rtc-omap.c @@ -377,13 +377,13 @@ static int __init omap_rtc_probe(struct platform_device *pdev) /* handle periodic and alarm irqs */ if (request_irq(omap_rtc_timer, rtc_irq, IRQF_DISABLED, - rtc->dev.bus_id, rtc)) { + dev_name(&rtc->dev), rtc)) { pr_debug("%s: RTC timer interrupt IRQ%d already claimed\n", pdev->name, omap_rtc_timer); goto fail0; } if (request_irq(omap_rtc_alarm, rtc_irq, IRQF_DISABLED, - rtc->dev.bus_id, rtc)) { + dev_name(&rtc->dev), rtc)) { pr_debug("%s: RTC alarm interrupt IRQ%d already claimed\n", pdev->name, omap_rtc_alarm); goto fail1; diff --git a/drivers/rtc/rtc-twl4030.c b/drivers/rtc/rtc-twl4030.c index ad35f76c46b7..a6341e4f9a0f 100644 --- a/drivers/rtc/rtc-twl4030.c +++ b/drivers/rtc/rtc-twl4030.c @@ -426,7 +426,7 @@ static int __devinit twl4030_rtc_probe(struct platform_device *pdev) ret = request_irq(irq, twl4030_rtc_interrupt, IRQF_TRIGGER_RISING, - rtc->dev.bus_id, rtc); + dev_name(&rtc->dev), rtc); if (ret < 0) { dev_err(&pdev->dev, "IRQ is not free.\n"); goto out1; -- cgit v1.2.2 From 99b76233803beab302123d243eea9e41149804f3 Mon Sep 17 00:00:00 2001 From: Alexey Dobriyan Date: Wed, 25 Mar 2009 22:48:06 +0300 Subject: proc 2/2: remove struct proc_dir_entry::owner Setting ->owner as done currently (pde->owner = THIS_MODULE) is racy as correctly noted at bug #12454. Someone can lookup entry with NULL ->owner, thus not pinning enything, and release it later resulting in module refcount underflow. We can keep ->owner and supply it at registration time like ->proc_fops and ->data. But this leaves ->owner as easy-manipulative field (just one C assignment) and somebody will forget to unpin previous/pin current module when switching ->owner. ->proc_fops is declared as "const" which should give some thoughts. ->read_proc/->write_proc were just fixed to not require ->owner for protection. rmmod'ed directories will be empty and return "." and ".." -- no harm. And directories with tricky enough readdir and lookup shouldn't be modular. We definitely don't want such modular code. Removing ->owner will also make PDE smaller. So, let's nuke it. Kudos to Jeff Layton for reminding about this, let's say, oversight. http://bugzilla.kernel.org/show_bug.cgi?id=12454 Signed-off-by: Alexey Dobriyan --- drivers/rtc/rtc-proc.c | 10 ++-------- 1 file changed, 2 insertions(+), 8 deletions(-) (limited to 'drivers/rtc') diff --git a/drivers/rtc/rtc-proc.c b/drivers/rtc/rtc-proc.c index 0c6257a034ff..c086fc30a84c 100644 --- a/drivers/rtc/rtc-proc.c +++ b/drivers/rtc/rtc-proc.c @@ -105,14 +105,8 @@ static const struct file_operations rtc_proc_fops = { void rtc_proc_add_device(struct rtc_device *rtc) { - if (rtc->id == 0) { - struct proc_dir_entry *ent; - - ent = proc_create_data("driver/rtc", 0, NULL, - &rtc_proc_fops, rtc); - if (ent) - ent->owner = rtc->owner; - } + if (rtc->id == 0) + proc_create_data("driver/rtc", 0, NULL, &rtc_proc_fops, rtc); } void rtc_proc_del_device(struct rtc_device *rtc) -- cgit v1.2.2 From 47367a3ba425d70467af0009782098235ddbf204 Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Tue, 31 Mar 2009 15:24:46 -0700 Subject: rtc: convert wm8350 use new alarm and update operations These are the only two ioctls so the ioctl() function is also removed. Signed-off-by: Mark Brown Cc: Acked-by: Alessandro Zummo Cc: David Brownell Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/rtc/rtc-wm8350.c | 39 ++++++++++++++++++--------------------- 1 file changed, 18 insertions(+), 21 deletions(-) (limited to 'drivers/rtc') diff --git a/drivers/rtc/rtc-wm8350.c b/drivers/rtc/rtc-wm8350.c index 5c5e3aa91385..616630d1e317 100644 --- a/drivers/rtc/rtc-wm8350.c +++ b/drivers/rtc/rtc-wm8350.c @@ -236,6 +236,17 @@ static int wm8350_rtc_start_alarm(struct wm8350 *wm8350) return 0; } +static int wm8350_rtc_alarm_irq_enable(struct device *dev, + unsigned int enabled) +{ + struct wm8350 *wm8350 = dev_get_drvdata(dev); + + if (enabled) + return wm8350_rtc_start_alarm(wm8350); + else + return wm8350_rtc_stop_alarm(wm8350); +} + static int wm8350_rtc_setalarm(struct device *dev, struct rtc_wkalrm *alrm) { struct wm8350 *wm8350 = dev_get_drvdata(dev); @@ -291,30 +302,15 @@ static int wm8350_rtc_setalarm(struct device *dev, struct rtc_wkalrm *alrm) return ret; } -/* - * Handle commands from user-space - */ -static int wm8350_rtc_ioctl(struct device *dev, unsigned int cmd, - unsigned long arg) +static int wm8350_rtc_update_irq_enable(struct device *dev, + unsigned int enabled) { struct wm8350 *wm8350 = dev_get_drvdata(dev); - switch (cmd) { - case RTC_AIE_OFF: - return wm8350_rtc_stop_alarm(wm8350); - case RTC_AIE_ON: - return wm8350_rtc_start_alarm(wm8350); - - case RTC_UIE_OFF: - wm8350_mask_irq(wm8350, WM8350_IRQ_RTC_SEC); - break; - case RTC_UIE_ON: + if (enabled) wm8350_unmask_irq(wm8350, WM8350_IRQ_RTC_SEC); - break; - - default: - return -ENOIOCTLCMD; - } + else + wm8350_mask_irq(wm8350, WM8350_IRQ_RTC_SEC); return 0; } @@ -345,11 +341,12 @@ static void wm8350_rtc_update_handler(struct wm8350 *wm8350, int irq, } static const struct rtc_class_ops wm8350_rtc_ops = { - .ioctl = wm8350_rtc_ioctl, .read_time = wm8350_rtc_readtime, .set_time = wm8350_rtc_settime, .read_alarm = wm8350_rtc_readalarm, .set_alarm = wm8350_rtc_setalarm, + .alarm_irq_enable = wm8350_rtc_alarm_irq_enable, + .update_irq_enable = wm8350_rtc_update_irq_enable, }; #ifdef CONFIG_PM -- cgit v1.2.2 From 78d89ef40c2ff7265df077e20c4d76be7d415204 Mon Sep 17 00:00:00 2001 From: Andrew Morton Date: Tue, 31 Mar 2009 15:24:48 -0700 Subject: rtc: convert LEAP_YEAR into an inline - the LEAP_YEAR macro is buggy - it references its arg multiple times. Fix this by turning it into a C function. - give it a more approriate name - Move it to rtc.h so that other .c files can use it, instead of copying it. Cc: dann frazier Acked-by: Alessandro Zummo Cc: stephane eranian Cc: "Luck, Tony" Cc: David Brownell Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/rtc/rtc-lib.c | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) (limited to 'drivers/rtc') diff --git a/drivers/rtc/rtc-lib.c b/drivers/rtc/rtc-lib.c index dd70bf73ce9d..773851f338b8 100644 --- a/drivers/rtc/rtc-lib.c +++ b/drivers/rtc/rtc-lib.c @@ -26,14 +26,13 @@ static const unsigned short rtc_ydays[2][13] = { }; #define LEAPS_THRU_END_OF(y) ((y)/4 - (y)/100 + (y)/400) -#define LEAP_YEAR(year) ((!(year % 4) && (year % 100)) || !(year % 400)) /* * The number of days in the month. */ int rtc_month_days(unsigned int month, unsigned int year) { - return rtc_days_in_month[month] + (LEAP_YEAR(year) && month == 1); + return rtc_days_in_month[month] + (is_leap_year(year) && month == 1); } EXPORT_SYMBOL(rtc_month_days); @@ -42,7 +41,7 @@ EXPORT_SYMBOL(rtc_month_days); */ int rtc_year_days(unsigned int day, unsigned int month, unsigned int year) { - return rtc_ydays[LEAP_YEAR(year)][month] + day-1; + return rtc_ydays[is_leap_year(year)][month] + day-1; } EXPORT_SYMBOL(rtc_year_days); @@ -66,7 +65,7 @@ void rtc_time_to_tm(unsigned long time, struct rtc_time *tm) - LEAPS_THRU_END_OF(1970 - 1); if (days < 0) { year -= 1; - days += 365 + LEAP_YEAR(year); + days += 365 + is_leap_year(year); } tm->tm_year = year - 1900; tm->tm_yday = days + 1; -- cgit v1.2.2 From 5e3fd9e5810f141c9c70c36992d4ed72b3aa1fed Mon Sep 17 00:00:00 2001 From: dann frazier Date: Tue, 31 Mar 2009 15:24:48 -0700 Subject: rtc: add platform driver for EFI Munge Stephane Eranian's efirtc.c code into an rtc platform driver [akpm@linux-foundation.org: use is_leap_year()] Signed-off-by: dann frazier Cc: Alessandro Zummo Cc: stephane eranian Cc: "Luck, Tony" Cc: David Brownell Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/rtc/Kconfig | 10 +++ drivers/rtc/Makefile | 1 + drivers/rtc/rtc-efi.c | 235 ++++++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 246 insertions(+) create mode 100644 drivers/rtc/rtc-efi.c (limited to 'drivers/rtc') diff --git a/drivers/rtc/Kconfig b/drivers/rtc/Kconfig index 81450fbd8b12..d669b9169278 100644 --- a/drivers/rtc/Kconfig +++ b/drivers/rtc/Kconfig @@ -440,6 +440,16 @@ config RTC_DRV_DS1742 This driver can also be built as a module. If so, the module will be called rtc-ds1742. +config RTC_DRV_EFI + tristate "EFI RTC" + depends on IA64 + help + If you say yes here you will get support for the EFI + Real Time Clock. + + This driver can also be built as a module. If so, the module + will be called rtc-efi. + config RTC_DRV_STK17TA8 tristate "Simtek STK17TA8" depends on RTC_CLASS diff --git a/drivers/rtc/Makefile b/drivers/rtc/Makefile index 0e697aa51caa..e7b09986d26e 100644 --- a/drivers/rtc/Makefile +++ b/drivers/rtc/Makefile @@ -36,6 +36,7 @@ obj-$(CONFIG_RTC_DRV_DS1553) += rtc-ds1553.o obj-$(CONFIG_RTC_DRV_DS1672) += rtc-ds1672.o obj-$(CONFIG_RTC_DRV_DS1742) += rtc-ds1742.o obj-$(CONFIG_RTC_DRV_DS3234) += rtc-ds3234.o +obj-$(CONFIG_RTC_DRV_EFI) += rtc-efi.o obj-$(CONFIG_RTC_DRV_EP93XX) += rtc-ep93xx.o obj-$(CONFIG_RTC_DRV_FM3130) += rtc-fm3130.o obj-$(CONFIG_RTC_DRV_ISL1208) += rtc-isl1208.o diff --git a/drivers/rtc/rtc-efi.c b/drivers/rtc/rtc-efi.c new file mode 100644 index 000000000000..550292304b0f --- /dev/null +++ b/drivers/rtc/rtc-efi.c @@ -0,0 +1,235 @@ +/* + * rtc-efi: RTC Class Driver for EFI-based systems + * + * Copyright (C) 2009 Hewlett-Packard Development Company, L.P. + * + * Author: dann frazier + * Based on efirtc.c by Stephane Eranian + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + * + */ + +#include +#include +#include +#include +#include +#include + +#define EFI_ISDST (EFI_TIME_ADJUST_DAYLIGHT|EFI_TIME_IN_DAYLIGHT) +/* + * EFI Epoch is 1/1/1998 + */ +#define EFI_RTC_EPOCH 1998 + +/* + * returns day of the year [0-365] + */ +static inline int +compute_yday(efi_time_t *eft) +{ + /* efi_time_t.month is in the [1-12] so, we need -1 */ + return rtc_year_days(eft->day - 1, eft->month - 1, eft->year); +} +/* + * returns day of the week [0-6] 0=Sunday + * + * Don't try to provide a year that's before 1998, please ! + */ +static int +compute_wday(efi_time_t *eft) +{ + int y; + int ndays = 0; + + if (eft->year < 1998) { + printk(KERN_ERR "efirtc: EFI year < 1998, invalid date\n"); + return -1; + } + + for (y = EFI_RTC_EPOCH; y < eft->year; y++) + ndays += 365 + (is_leap_year(y) ? 1 : 0); + + ndays += compute_yday(eft); + + /* + * 4=1/1/1998 was a Thursday + */ + return (ndays + 4) % 7; +} + +static void +convert_to_efi_time(struct rtc_time *wtime, efi_time_t *eft) +{ + eft->year = wtime->tm_year + 1900; + eft->month = wtime->tm_mon + 1; + eft->day = wtime->tm_mday; + eft->hour = wtime->tm_hour; + eft->minute = wtime->tm_min; + eft->second = wtime->tm_sec; + eft->nanosecond = 0; + eft->daylight = wtime->tm_isdst ? EFI_ISDST : 0; + eft->timezone = EFI_UNSPECIFIED_TIMEZONE; +} + +static void +convert_from_efi_time(efi_time_t *eft, struct rtc_time *wtime) +{ + memset(wtime, 0, sizeof(*wtime)); + wtime->tm_sec = eft->second; + wtime->tm_min = eft->minute; + wtime->tm_hour = eft->hour; + wtime->tm_mday = eft->day; + wtime->tm_mon = eft->month - 1; + wtime->tm_year = eft->year - 1900; + + /* day of the week [0-6], Sunday=0 */ + wtime->tm_wday = compute_wday(eft); + + /* day in the year [1-365]*/ + wtime->tm_yday = compute_yday(eft); + + + switch (eft->daylight & EFI_ISDST) { + case EFI_ISDST: + wtime->tm_isdst = 1; + break; + case EFI_TIME_ADJUST_DAYLIGHT: + wtime->tm_isdst = 0; + break; + default: + wtime->tm_isdst = -1; + } +} + +static int efi_read_alarm(struct device *dev, struct rtc_wkalrm *wkalrm) +{ + efi_time_t eft; + efi_status_t status; + + /* + * As of EFI v1.10, this call always returns an unsupported status + */ + status = efi.get_wakeup_time((efi_bool_t *)&wkalrm->enabled, + (efi_bool_t *)&wkalrm->pending, &eft); + + if (status != EFI_SUCCESS) + return -EINVAL; + + convert_from_efi_time(&eft, &wkalrm->time); + + return rtc_valid_tm(&wkalrm->time); +} + +static int efi_set_alarm(struct device *dev, struct rtc_wkalrm *wkalrm) +{ + efi_time_t eft; + efi_status_t status; + + convert_to_efi_time(&wkalrm->time, &eft); + + /* + * XXX Fixme: + * As of EFI 0.92 with the firmware I have on my + * machine this call does not seem to work quite + * right + * + * As of v1.10, this call always returns an unsupported status + */ + status = efi.set_wakeup_time((efi_bool_t)wkalrm->enabled, &eft); + + printk(KERN_WARNING "write status is %d\n", (int)status); + + return status == EFI_SUCCESS ? 0 : -EINVAL; +} + +static int efi_read_time(struct device *dev, struct rtc_time *tm) +{ + efi_status_t status; + efi_time_t eft; + efi_time_cap_t cap; + + status = efi.get_time(&eft, &cap); + + if (status != EFI_SUCCESS) { + /* should never happen */ + printk(KERN_ERR "efitime: can't read time\n"); + return -EINVAL; + } + + convert_from_efi_time(&eft, tm); + + return rtc_valid_tm(tm); +} + +static int efi_set_time(struct device *dev, struct rtc_time *tm) +{ + efi_status_t status; + efi_time_t eft; + + convert_to_efi_time(tm, &eft); + + status = efi.set_time(&eft); + + return status == EFI_SUCCESS ? 0 : -EINVAL; +} + +static const struct rtc_class_ops efi_rtc_ops = { + .read_time = efi_read_time, + .set_time = efi_set_time, + .read_alarm = efi_read_alarm, + .set_alarm = efi_set_alarm, +}; + +static int __init efi_rtc_probe(struct platform_device *dev) +{ + struct rtc_device *rtc; + + rtc = rtc_device_register("rtc-efi", &dev->dev, &efi_rtc_ops, + THIS_MODULE); + if (IS_ERR(rtc)) + return PTR_ERR(rtc); + + platform_set_drvdata(dev, rtc); + + return 0; +} + +static int __exit efi_rtc_remove(struct platform_device *dev) +{ + struct rtc_device *rtc = platform_get_drvdata(dev); + + rtc_device_unregister(rtc); + + return 0; +} + +static struct platform_driver efi_rtc_driver = { + .driver = { + .name = "rtc-efi", + .owner = THIS_MODULE, + }, + .probe = efi_rtc_probe, + .remove = __exit_p(efi_rtc_remove), +}; + +static int __init efi_rtc_init(void) +{ + return platform_driver_probe(&efi_rtc_driver, efi_rtc_probe); +} + +static void __exit efi_rtc_exit(void) +{ + platform_driver_unregister(&efi_rtc_driver); +} + +module_init(efi_rtc_init); +module_exit(efi_rtc_exit); + +MODULE_AUTHOR("dann frazier "); +MODULE_LICENSE("GPL"); +MODULE_DESCRIPTION("EFI RTC driver"); -- cgit v1.2.2 From 93d456d9802a40859ecc3d67be8c759b03aa487d Mon Sep 17 00:00:00 2001 From: dann frazier Date: Tue, 31 Mar 2009 15:24:49 -0700 Subject: rtc-parisc: add a missing include for linux/rtc.h Signed-off-by: dann frazier Cc: Alessandro Zummo Cc: Kyle McMartin Cc: Grant Grundler Cc: Matthew Wilcox Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/rtc/rtc-parisc.c | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers/rtc') diff --git a/drivers/rtc/rtc-parisc.c b/drivers/rtc/rtc-parisc.c index c6bfa6fe1a2a..319bb5d445ea 100644 --- a/drivers/rtc/rtc-parisc.c +++ b/drivers/rtc/rtc-parisc.c @@ -7,6 +7,7 @@ #include #include #include +#include #include -- cgit v1.2.2 From 05439f1f89aebbdb791c49e980f0f31652e4055b Mon Sep 17 00:00:00 2001 From: dann frazier Date: Tue, 31 Mar 2009 15:24:50 -0700 Subject: rtc-parisc: remove redundant locking The RTC subsystem proides ops locking, no need to implement our own Signed-off-by: dann frazier Cc: Alessandro Zummo Cc: Kyle McMartin Cc: Grant Grundler Cc: Matthew Wilcox Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/rtc/rtc-parisc.c | 12 +----------- 1 file changed, 1 insertion(+), 11 deletions(-) (limited to 'drivers/rtc') diff --git a/drivers/rtc/rtc-parisc.c b/drivers/rtc/rtc-parisc.c index 319bb5d445ea..cb087ad407f6 100644 --- a/drivers/rtc/rtc-parisc.c +++ b/drivers/rtc/rtc-parisc.c @@ -14,17 +14,13 @@ /* as simple as can be, and no simpler. */ struct parisc_rtc { struct rtc_device *rtc; - spinlock_t lock; }; static int parisc_get_time(struct device *dev, struct rtc_time *tm) { - struct parisc_rtc *p = dev_get_drvdata(dev); - unsigned long flags, ret; + unsigned long ret; - spin_lock_irqsave(&p->lock, flags); ret = get_rtc_time(tm); - spin_unlock_irqrestore(&p->lock, flags); if (ret & RTC_BATT_BAD) return -EOPNOTSUPP; @@ -34,13 +30,9 @@ static int parisc_get_time(struct device *dev, struct rtc_time *tm) static int parisc_set_time(struct device *dev, struct rtc_time *tm) { - struct parisc_rtc *p = dev_get_drvdata(dev); - unsigned long flags; int ret; - spin_lock_irqsave(&p->lock, flags); ret = set_rtc_time(tm); - spin_unlock_irqrestore(&p->lock, flags); if (ret < 0) return -EOPNOTSUPP; @@ -61,8 +53,6 @@ static int __devinit parisc_rtc_probe(struct platform_device *dev) if (!p) return -ENOMEM; - spin_lock_init(&p->lock); - p->rtc = rtc_device_register("rtc-parisc", &dev->dev, &parisc_rtc_ops, THIS_MODULE); if (IS_ERR(p->rtc)) { -- cgit v1.2.2 From 6b318f66dca829a72c974083cc10fd5556eec6f1 Mon Sep 17 00:00:00 2001 From: dann frazier Date: Tue, 31 Mar 2009 15:24:51 -0700 Subject: rtc-parisc: remove struct parisc_rtc parisc_rtc now only includes an rtc_device pointer, so let's just use the rtc_device type directly. Signed-off-by: dann frazier Cc: Alessandro Zummo Cc: Kyle McMartin Cc: Grant Grundler Cc: Matthew Wilcox Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/rtc/rtc-parisc.c | 19 +++++++------------ 1 file changed, 7 insertions(+), 12 deletions(-) (limited to 'drivers/rtc') diff --git a/drivers/rtc/rtc-parisc.c b/drivers/rtc/rtc-parisc.c index cb087ad407f6..ee4e9a3fb583 100644 --- a/drivers/rtc/rtc-parisc.c +++ b/drivers/rtc/rtc-parisc.c @@ -11,11 +11,6 @@ #include -/* as simple as can be, and no simpler. */ -struct parisc_rtc { - struct rtc_device *rtc; -}; - static int parisc_get_time(struct device *dev, struct rtc_time *tm) { unsigned long ret; @@ -47,16 +42,16 @@ static const struct rtc_class_ops parisc_rtc_ops = { static int __devinit parisc_rtc_probe(struct platform_device *dev) { - struct parisc_rtc *p; + struct rtc_device *p; p = kzalloc(sizeof (*p), GFP_KERNEL); if (!p) return -ENOMEM; - p->rtc = rtc_device_register("rtc-parisc", &dev->dev, &parisc_rtc_ops, - THIS_MODULE); - if (IS_ERR(p->rtc)) { - int err = PTR_ERR(p->rtc); + p = rtc_device_register("rtc-parisc", &dev->dev, &parisc_rtc_ops, + THIS_MODULE); + if (IS_ERR(p)) { + int err = PTR_ERR(p); kfree(p); return err; } @@ -68,9 +63,9 @@ static int __devinit parisc_rtc_probe(struct platform_device *dev) static int __devexit parisc_rtc_remove(struct platform_device *dev) { - struct parisc_rtc *p = platform_get_drvdata(dev); + struct rtc_device *p = platform_get_drvdata(dev); - rtc_device_unregister(p->rtc); + rtc_device_unregister(p); kfree(p); return 0; -- cgit v1.2.2 From f62bacd4d48a1a6b8931a0140fb2324a06dd89fe Mon Sep 17 00:00:00 2001 From: dann frazier Date: Tue, 31 Mar 2009 15:24:52 -0700 Subject: rtc-parisc: use rtc_valid_tm() in parisc_get_time Use the return value of rtc_valid_tm() instead of just returning 0. Signed-off-by: dann frazier Cc: Alessandro Zummo Cc: Kyle McMartin Cc: Grant Grundler Cc: Matthew Wilcox Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/rtc/rtc-parisc.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/rtc') diff --git a/drivers/rtc/rtc-parisc.c b/drivers/rtc/rtc-parisc.c index ee4e9a3fb583..0477cc129c6d 100644 --- a/drivers/rtc/rtc-parisc.c +++ b/drivers/rtc/rtc-parisc.c @@ -20,7 +20,7 @@ static int parisc_get_time(struct device *dev, struct rtc_time *tm) if (ret & RTC_BATT_BAD) return -EOPNOTSUPP; - return 0; + return rtc_valid_tm(tm); } static int parisc_set_time(struct device *dev, struct rtc_time *tm) -- cgit v1.2.2 From 2b93cff4dc184bf7b4858dc7a9bd2e8d33c1a3eb Mon Sep 17 00:00:00 2001 From: dann frazier Date: Tue, 31 Mar 2009 15:24:52 -0700 Subject: rtc-parisc: use platform_driver_probe This isn't a hotpluggable device, so call platform_driver_probe directly in parisc_rtc_init Signed-off-by: dann frazier Cc: Alessandro Zummo Cc: Kyle McMartin Cc: Grant Grundler Cc: Matthew Wilcox Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/rtc/rtc-parisc.c | 12 +++--------- 1 file changed, 3 insertions(+), 9 deletions(-) (limited to 'drivers/rtc') diff --git a/drivers/rtc/rtc-parisc.c b/drivers/rtc/rtc-parisc.c index 0477cc129c6d..a2ca07ad42cb 100644 --- a/drivers/rtc/rtc-parisc.c +++ b/drivers/rtc/rtc-parisc.c @@ -40,19 +40,14 @@ static const struct rtc_class_ops parisc_rtc_ops = { .set_time = parisc_set_time, }; -static int __devinit parisc_rtc_probe(struct platform_device *dev) +static int __init parisc_rtc_probe(struct platform_device *dev) { struct rtc_device *p; - p = kzalloc(sizeof (*p), GFP_KERNEL); - if (!p) - return -ENOMEM; - p = rtc_device_register("rtc-parisc", &dev->dev, &parisc_rtc_ops, THIS_MODULE); if (IS_ERR(p)) { int err = PTR_ERR(p); - kfree(p); return err; } @@ -61,12 +56,11 @@ static int __devinit parisc_rtc_probe(struct platform_device *dev) return 0; } -static int __devexit parisc_rtc_remove(struct platform_device *dev) +static int __exit parisc_rtc_remove(struct platform_device *dev) { struct rtc_device *p = platform_get_drvdata(dev); rtc_device_unregister(p); - kfree(p); return 0; } @@ -82,7 +76,7 @@ static struct platform_driver parisc_rtc_driver = { static int __init parisc_rtc_init(void) { - return platform_driver_register(&parisc_rtc_driver); + return platform_driver_probe(&parisc_rtc_driver, parisc_rtc_probe); } static void __exit parisc_rtc_fini(void) -- cgit v1.2.2 From a8c20cd3f7e2e223898c53adfb74420db5d9ac47 Mon Sep 17 00:00:00 2001 From: dann frazier Date: Tue, 31 Mar 2009 15:24:55 -0700 Subject: rtc-parisc: remove a couple unnecessary variables Signed-off-by: dann frazier Reviewed-by: Grant Grundler Cc: Alessandro Zummo Cc: Kyle McMartin Cc: Matthew Wilcox Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/rtc/rtc-parisc.c | 12 +++--------- 1 file changed, 3 insertions(+), 9 deletions(-) (limited to 'drivers/rtc') diff --git a/drivers/rtc/rtc-parisc.c b/drivers/rtc/rtc-parisc.c index a2ca07ad42cb..c29e91814c9a 100644 --- a/drivers/rtc/rtc-parisc.c +++ b/drivers/rtc/rtc-parisc.c @@ -25,11 +25,7 @@ static int parisc_get_time(struct device *dev, struct rtc_time *tm) static int parisc_set_time(struct device *dev, struct rtc_time *tm) { - int ret; - - ret = set_rtc_time(tm); - - if (ret < 0) + if (set_rtc_time(tm) < 0) return -EOPNOTSUPP; return 0; @@ -46,10 +42,8 @@ static int __init parisc_rtc_probe(struct platform_device *dev) p = rtc_device_register("rtc-parisc", &dev->dev, &parisc_rtc_ops, THIS_MODULE); - if (IS_ERR(p)) { - int err = PTR_ERR(p); - return err; - } + if (IS_ERR(p)) + return PTR_ERR(p); platform_set_drvdata(dev, p); -- cgit v1.2.2 From b250c96ea9d7bc0b9ac3ff6e878b254b0b0b6abc Mon Sep 17 00:00:00 2001 From: dann frazier Date: Tue, 31 Mar 2009 15:24:55 -0700 Subject: rtc-parisc: rename p pointer to rtc Signed-off-by: dann frazier Cc: Alessandro Zummo Cc: Kyle McMartin Cc: Grant Grundler Cc: Matthew Wilcox Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/rtc/rtc-parisc.c | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) (limited to 'drivers/rtc') diff --git a/drivers/rtc/rtc-parisc.c b/drivers/rtc/rtc-parisc.c index c29e91814c9a..b966f56da976 100644 --- a/drivers/rtc/rtc-parisc.c +++ b/drivers/rtc/rtc-parisc.c @@ -38,23 +38,23 @@ static const struct rtc_class_ops parisc_rtc_ops = { static int __init parisc_rtc_probe(struct platform_device *dev) { - struct rtc_device *p; + struct rtc_device *rtc; - p = rtc_device_register("rtc-parisc", &dev->dev, &parisc_rtc_ops, - THIS_MODULE); - if (IS_ERR(p)) - return PTR_ERR(p); + rtc = rtc_device_register("rtc-parisc", &dev->dev, &parisc_rtc_ops, + THIS_MODULE); + if (IS_ERR(rtc)) + return PTR_ERR(rtc); - platform_set_drvdata(dev, p); + platform_set_drvdata(dev, rtc); return 0; } static int __exit parisc_rtc_remove(struct platform_device *dev) { - struct rtc_device *p = platform_get_drvdata(dev); + struct rtc_device *rtc = platform_get_drvdata(dev); - rtc_device_unregister(p); + rtc_device_unregister(rtc); return 0; } -- cgit v1.2.2 From 30e7b039b1f9a6d5a4e50df5469a4f347ea1aa77 Mon Sep 17 00:00:00 2001 From: Ed Swierk Date: Tue, 31 Mar 2009 15:24:56 -0700 Subject: rtc-ds1307: true SMBus compatibility Allow the rtc-ds1307 driver to work with SMBus controllers like nforce2 that do not support i2c block transfers. Signed-off-by: Ed Swierk Acked-by: Jean Delvare Acked-by: David Brownell Cc: Alessandro Zummo Cc: BARRE Sebastien Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/rtc/rtc-ds1307.c | 109 +++++++++++++++++++++++++++++++++++++++++------ 1 file changed, 97 insertions(+), 12 deletions(-) (limited to 'drivers/rtc') diff --git a/drivers/rtc/rtc-ds1307.c b/drivers/rtc/rtc-ds1307.c index 7e5155e88ac7..1c975e6439b3 100644 --- a/drivers/rtc/rtc-ds1307.c +++ b/drivers/rtc/rtc-ds1307.c @@ -94,6 +94,10 @@ struct ds1307 { struct i2c_client *client; struct rtc_device *rtc; struct work_struct work; + s32 (*read_block_data)(struct i2c_client *client, u8 command, + u8 length, u8 *values); + s32 (*write_block_data)(struct i2c_client *client, u8 command, + u8 length, const u8 *values); }; struct chip_desc { @@ -132,6 +136,79 @@ MODULE_DEVICE_TABLE(i2c, ds1307_id); /*----------------------------------------------------------------------*/ +#define BLOCK_DATA_MAX_TRIES 10 + +static s32 ds1307_read_block_data_once(struct i2c_client *client, u8 command, + u8 length, u8 *values) +{ + s32 i, data; + + for (i = 0; i < length; i++) { + data = i2c_smbus_read_byte_data(client, command + i); + if (data < 0) + return data; + values[i] = data; + } + return i; +} + +static s32 ds1307_read_block_data(struct i2c_client *client, u8 command, + u8 length, u8 *values) +{ + u8 oldvalues[I2C_SMBUS_BLOCK_MAX]; + s32 ret; + int tries = 0; + + dev_dbg(&client->dev, "ds1307_read_block_data (length=%d)\n", length); + ret = ds1307_read_block_data_once(client, command, length, values); + if (ret < 0) + return ret; + do { + if (++tries > BLOCK_DATA_MAX_TRIES) { + dev_err(&client->dev, + "ds1307_read_block_data failed\n"); + return -EIO; + } + memcpy(oldvalues, values, length); + ret = ds1307_read_block_data_once(client, command, length, + values); + if (ret < 0) + return ret; + } while (memcmp(oldvalues, values, length)); + return length; +} + +static s32 ds1307_write_block_data(struct i2c_client *client, u8 command, + u8 length, const u8 *values) +{ + u8 currvalues[I2C_SMBUS_BLOCK_MAX]; + int tries = 0; + + dev_dbg(&client->dev, "ds1307_write_block_data (length=%d)\n", length); + do { + s32 i, ret; + + if (++tries > BLOCK_DATA_MAX_TRIES) { + dev_err(&client->dev, + "ds1307_write_block_data failed\n"); + return -EIO; + } + for (i = 0; i < length; i++) { + ret = i2c_smbus_write_byte_data(client, command + i, + values[i]); + if (ret < 0) + return ret; + } + ret = ds1307_read_block_data_once(client, command, length, + currvalues); + if (ret < 0) + return ret; + } while (memcmp(currvalues, values, length)); + return length; +} + +/*----------------------------------------------------------------------*/ + /* * The IRQ logic includes a "real" handler running in IRQ context just * long enough to schedule this workqueue entry. We need a task context @@ -202,7 +279,7 @@ static int ds1307_get_time(struct device *dev, struct rtc_time *t) int tmp; /* read the RTC date and time registers all at once */ - tmp = i2c_smbus_read_i2c_block_data(ds1307->client, + tmp = ds1307->read_block_data(ds1307->client, DS1307_REG_SECS, 7, ds1307->regs); if (tmp != 7) { dev_err(dev, "%s error %d\n", "read", tmp); @@ -279,7 +356,7 @@ static int ds1307_set_time(struct device *dev, struct rtc_time *t) "write", buf[0], buf[1], buf[2], buf[3], buf[4], buf[5], buf[6]); - result = i2c_smbus_write_i2c_block_data(ds1307->client, 0, 7, buf); + result = ds1307->write_block_data(ds1307->client, 0, 7, buf); if (result < 0) { dev_err(dev, "%s error %d\n", "write", result); return result; @@ -297,7 +374,7 @@ static int ds1337_read_alarm(struct device *dev, struct rtc_wkalrm *t) return -EINVAL; /* read all ALARM1, ALARM2, and status registers at once */ - ret = i2c_smbus_read_i2c_block_data(client, + ret = ds1307->read_block_data(client, DS1339_REG_ALARM1_SECS, 9, ds1307->regs); if (ret != 9) { dev_err(dev, "%s error %d\n", "alarm read", ret); @@ -356,7 +433,7 @@ static int ds1337_set_alarm(struct device *dev, struct rtc_wkalrm *t) t->enabled, t->pending); /* read current status of both alarms and the chip */ - ret = i2c_smbus_read_i2c_block_data(client, + ret = ds1307->read_block_data(client, DS1339_REG_ALARM1_SECS, 9, buf); if (ret != 9) { dev_err(dev, "%s error %d\n", "alarm write", ret); @@ -391,7 +468,7 @@ static int ds1337_set_alarm(struct device *dev, struct rtc_wkalrm *t) } buf[8] = status & ~(DS1337_BIT_A1I | DS1337_BIT_A2I); - ret = i2c_smbus_write_i2c_block_data(client, + ret = ds1307->write_block_data(client, DS1339_REG_ALARM1_SECS, 9, buf); if (ret < 0) { dev_err(dev, "can't set alarm time\n"); @@ -479,7 +556,7 @@ ds1307_nvram_read(struct kobject *kobj, struct bin_attribute *attr, if (unlikely(!count)) return count; - result = i2c_smbus_read_i2c_block_data(client, 8 + off, count, buf); + result = ds1307->read_block_data(client, 8 + off, count, buf); if (result < 0) dev_err(&client->dev, "%s error %d\n", "nvram read", result); return result; @@ -490,9 +567,11 @@ ds1307_nvram_write(struct kobject *kobj, struct bin_attribute *attr, char *buf, loff_t off, size_t count) { struct i2c_client *client; + struct ds1307 *ds1307; int result; client = kobj_to_i2c_client(kobj); + ds1307 = i2c_get_clientdata(client); if (unlikely(off >= NVRAM_SIZE)) return -EFBIG; @@ -501,7 +580,7 @@ ds1307_nvram_write(struct kobject *kobj, struct bin_attribute *attr, if (unlikely(!count)) return count; - result = i2c_smbus_write_i2c_block_data(client, 8 + off, count, buf); + result = ds1307->write_block_data(client, 8 + off, count, buf); if (result < 0) { dev_err(&client->dev, "%s error %d\n", "nvram write", result); return result; @@ -535,9 +614,8 @@ static int __devinit ds1307_probe(struct i2c_client *client, int want_irq = false; unsigned char *buf; - if (!i2c_check_functionality(adapter, - I2C_FUNC_SMBUS_WRITE_BYTE_DATA | - I2C_FUNC_SMBUS_I2C_BLOCK)) + if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA) + && !i2c_check_functionality(adapter, I2C_FUNC_SMBUS_I2C_BLOCK)) return -EIO; if (!(ds1307 = kzalloc(sizeof(struct ds1307), GFP_KERNEL))) @@ -547,6 +625,13 @@ static int __devinit ds1307_probe(struct i2c_client *client, i2c_set_clientdata(client, ds1307); ds1307->type = id->driver_data; buf = ds1307->regs; + if (i2c_check_functionality(adapter, I2C_FUNC_SMBUS_I2C_BLOCK)) { + ds1307->read_block_data = i2c_smbus_read_i2c_block_data; + ds1307->write_block_data = i2c_smbus_write_i2c_block_data; + } else { + ds1307->read_block_data = ds1307_read_block_data; + ds1307->write_block_data = ds1307_write_block_data; + } switch (ds1307->type) { case ds_1337: @@ -557,7 +642,7 @@ static int __devinit ds1307_probe(struct i2c_client *client, want_irq = true; } /* get registers that the "rtc" read below won't read... */ - tmp = i2c_smbus_read_i2c_block_data(ds1307->client, + tmp = ds1307->read_block_data(ds1307->client, DS1337_REG_CONTROL, 2, buf); if (tmp != 2) { pr_debug("read error %d\n", tmp); @@ -595,7 +680,7 @@ static int __devinit ds1307_probe(struct i2c_client *client, read_rtc: /* read RTC registers */ - tmp = i2c_smbus_read_i2c_block_data(ds1307->client, 0, 8, buf); + tmp = ds1307->read_block_data(ds1307->client, 0, 8, buf); if (tmp != 8) { pr_debug("read error %d\n", tmp); err = -EIO; -- cgit v1.2.2 From a216685818a54b4f15235068b53908f954850251 Mon Sep 17 00:00:00 2001 From: Matthias Fuchs Date: Tue, 31 Mar 2009 15:24:58 -0700 Subject: rtc: add EPSON RX8025 support to DS1307 RTC driver Add support for the EPSON RX8025 RTC. The date/time registers of this chip are compatible with the DS1307. Signed-off-by: Matthias Fuchs Signed-off-by: Alessandro Zummo Cc: David Brownell Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/rtc/Kconfig | 7 +++-- drivers/rtc/rtc-ds1307.c | 80 ++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 84 insertions(+), 3 deletions(-) (limited to 'drivers/rtc') diff --git a/drivers/rtc/Kconfig b/drivers/rtc/Kconfig index d669b9169278..09d5cd33a3f6 100644 --- a/drivers/rtc/Kconfig +++ b/drivers/rtc/Kconfig @@ -129,13 +129,14 @@ comment "I2C RTC drivers" if I2C config RTC_DRV_DS1307 - tristate "Dallas/Maxim DS1307/37/38/39/40, ST M41T00" + tristate "Dallas/Maxim DS1307/37/38/39/40, ST M41T00, EPSON RX-8025" help If you say yes here you get support for various compatible RTC chips (often with battery backup) connected with I2C. This driver should handle DS1307, DS1337, DS1338, DS1339, DS1340, ST M41T00, - and probably other chips. In some cases the RTC must already - have been initialized (by manufacturing or a bootloader). + EPSON RX-8025 and probably other chips. In some cases the RTC + must already have been initialized (by manufacturing or a + bootloader). The first seven registers on these chips hold an RTC, and other registers may add features such as NVRAM, a trickle charger for diff --git a/drivers/rtc/rtc-ds1307.c b/drivers/rtc/rtc-ds1307.c index 1c975e6439b3..2c4a65302a9d 100644 --- a/drivers/rtc/rtc-ds1307.c +++ b/drivers/rtc/rtc-ds1307.c @@ -3,6 +3,7 @@ * * Copyright (C) 2005 James Chapman (ds1337 core) * Copyright (C) 2006 David Brownell + * Copyright (C) 2009 Matthias Fuchs (rx8025 support) * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 as @@ -31,6 +32,7 @@ enum ds_type { ds_1339, ds_1340, m41t00, + rx_8025, // rs5c372 too? different address... }; @@ -83,6 +85,12 @@ enum ds_type { #define DS1339_REG_ALARM1_SECS 0x07 #define DS1339_REG_TRICKLE 0x10 +#define RX8025_REG_CTRL1 0x0e +# define RX8025_BIT_2412 0x20 +#define RX8025_REG_CTRL2 0x0f +# define RX8025_BIT_PON 0x10 +# define RX8025_BIT_VDET 0x40 +# define RX8025_BIT_XST 0x20 struct ds1307 { @@ -121,6 +129,8 @@ static const struct chip_desc chips[] = { [ds_1340] = { }, [m41t00] = { +}, +[rx_8025] = { }, }; static const struct i2c_device_id ds1307_id[] = { @@ -130,6 +140,7 @@ static const struct i2c_device_id ds1307_id[] = { { "ds1339", ds_1339 }, { "ds1340", ds_1340 }, { "m41t00", m41t00 }, + { "rx8025", rx_8025 }, { } }; MODULE_DEVICE_TABLE(i2c, ds1307_id); @@ -674,6 +685,72 @@ static int __devinit ds1307_probe(struct i2c_client *client, dev_warn(&client->dev, "SET TIME!\n"); } break; + + case rx_8025: + tmp = i2c_smbus_read_i2c_block_data(ds1307->client, + RX8025_REG_CTRL1 << 4 | 0x08, 2, buf); + if (tmp != 2) { + pr_debug("read error %d\n", tmp); + err = -EIO; + goto exit_free; + } + + /* oscillator off? turn it on, so clock can tick. */ + if (!(ds1307->regs[1] & RX8025_BIT_XST)) { + ds1307->regs[1] |= RX8025_BIT_XST; + i2c_smbus_write_byte_data(client, + RX8025_REG_CTRL2 << 4 | 0x08, + ds1307->regs[1]); + dev_warn(&client->dev, + "oscillator stop detected - SET TIME!\n"); + } + + if (ds1307->regs[1] & RX8025_BIT_PON) { + ds1307->regs[1] &= ~RX8025_BIT_PON; + i2c_smbus_write_byte_data(client, + RX8025_REG_CTRL2 << 4 | 0x08, + ds1307->regs[1]); + dev_warn(&client->dev, "power-on detected\n"); + } + + if (ds1307->regs[1] & RX8025_BIT_VDET) { + ds1307->regs[1] &= ~RX8025_BIT_VDET; + i2c_smbus_write_byte_data(client, + RX8025_REG_CTRL2 << 4 | 0x08, + ds1307->regs[1]); + dev_warn(&client->dev, "voltage drop detected\n"); + } + + /* make sure we are running in 24hour mode */ + if (!(ds1307->regs[0] & RX8025_BIT_2412)) { + u8 hour; + + /* switch to 24 hour mode */ + i2c_smbus_write_byte_data(client, + RX8025_REG_CTRL1 << 4 | 0x08, + ds1307->regs[0] | + RX8025_BIT_2412); + + tmp = i2c_smbus_read_i2c_block_data(ds1307->client, + RX8025_REG_CTRL1 << 4 | 0x08, 2, buf); + if (tmp != 2) { + pr_debug("read error %d\n", tmp); + err = -EIO; + goto exit_free; + } + + /* correct hour */ + hour = bcd2bin(ds1307->regs[DS1307_REG_HOUR]); + if (hour == 12) + hour = 0; + if (ds1307->regs[DS1307_REG_HOUR] & DS1307_BIT_PM) + hour += 12; + + i2c_smbus_write_byte_data(client, + DS1307_REG_HOUR << 4 | 0x08, + hour); + } + break; default: break; } @@ -734,6 +811,7 @@ read_rtc: dev_warn(&client->dev, "SET TIME!\n"); } break; + case rx_8025: case ds_1337: case ds_1339: break; @@ -747,6 +825,8 @@ read_rtc: * systems that will run through year 2100. */ break; + case rx_8025: + break; default: if (!(tmp & DS1307_BIT_12HR)) break; -- cgit v1.2.2 From 62da659a7057f7227a99a42eea6aa606b09c1e8c Mon Sep 17 00:00:00 2001 From: Roel Kluin Date: Tue, 31 Mar 2009 15:24:59 -0700 Subject: rtc-wm8350: retries will reach -1 With a postfix decrement retries will reach -1 rather than 0, so the warning and error-out will not occur. Signed-off-by: Roel Kluin Acked-by: Mark Brown Cc: Alessandro Zummo Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/rtc/rtc-wm8350.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers/rtc') diff --git a/drivers/rtc/rtc-wm8350.c b/drivers/rtc/rtc-wm8350.c index 616630d1e317..c91edc572eb6 100644 --- a/drivers/rtc/rtc-wm8350.c +++ b/drivers/rtc/rtc-wm8350.c @@ -122,7 +122,7 @@ static int wm8350_rtc_settime(struct device *dev, struct rtc_time *tm) do { rtc_ctrl = wm8350_reg_read(wm8350, WM8350_RTC_TIME_CONTROL); schedule_timeout_uninterruptible(msecs_to_jiffies(1)); - } while (retries-- && !(rtc_ctrl & WM8350_RTC_STS)); + } while (--retries && !(rtc_ctrl & WM8350_RTC_STS)); if (!retries) { dev_err(dev, "timed out on set confirmation\n"); @@ -437,7 +437,7 @@ static int wm8350_rtc_probe(struct platform_device *pdev) do { timectl = wm8350_reg_read(wm8350, WM8350_RTC_TIME_CONTROL); - } while (timectl & WM8350_RTC_STS && retries--); + } while (timectl & WM8350_RTC_STS && --retries); if (retries == 0) { dev_err(&pdev->dev, "failed to start: timeout\n"); -- cgit v1.2.2 From c08cf9daf66844c60ebe9f89885d3a3e1893e61f Mon Sep 17 00:00:00 2001 From: Mike Rapoport Date: Tue, 31 Mar 2009 15:24:59 -0700 Subject: rtc-v3020: coding style cleanup Signed-off-by: Mike Rapoport Acked-by: Alessandro Zummo Cc: David Brownell Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/rtc/rtc-v3020.c | 40 ++++++++++++++++++---------------------- 1 file changed, 18 insertions(+), 22 deletions(-) (limited to 'drivers/rtc') diff --git a/drivers/rtc/rtc-v3020.c b/drivers/rtc/rtc-v3020.c index 14d4f036a768..66955cc9c746 100644 --- a/drivers/rtc/rtc-v3020.c +++ b/drivers/rtc/rtc-v3020.c @@ -28,7 +28,7 @@ #include #include -#include +#include #undef DEBUG @@ -63,7 +63,7 @@ static void v3020_set_reg(struct v3020 *chip, unsigned char address, static unsigned char v3020_get_reg(struct v3020 *chip, unsigned char address) { - unsigned int data=0; + unsigned int data = 0; int i; for (i = 0; i < 4; i++) { @@ -106,16 +106,14 @@ static int v3020_read_time(struct device *dev, struct rtc_time *dt) tmp = v3020_get_reg(chip, V3020_YEAR); dt->tm_year = bcd2bin(tmp)+100; -#ifdef DEBUG - printk("\n%s : Read RTC values\n",__func__); - printk("tm_hour: %i\n",dt->tm_hour); - printk("tm_min : %i\n",dt->tm_min); - printk("tm_sec : %i\n",dt->tm_sec); - printk("tm_year: %i\n",dt->tm_year); - printk("tm_mon : %i\n",dt->tm_mon); - printk("tm_mday: %i\n",dt->tm_mday); - printk("tm_wday: %i\n",dt->tm_wday); -#endif + dev_dbg(dev, "\n%s : Read RTC values\n", __func__); + dev_dbg(dev, "tm_hour: %i\n", dt->tm_hour); + dev_dbg(dev, "tm_min : %i\n", dt->tm_min); + dev_dbg(dev, "tm_sec : %i\n", dt->tm_sec); + dev_dbg(dev, "tm_year: %i\n", dt->tm_year); + dev_dbg(dev, "tm_mon : %i\n", dt->tm_mon); + dev_dbg(dev, "tm_mday: %i\n", dt->tm_mday); + dev_dbg(dev, "tm_wday: %i\n", dt->tm_wday); return 0; } @@ -125,15 +123,13 @@ static int v3020_set_time(struct device *dev, struct rtc_time *dt) { struct v3020 *chip = dev_get_drvdata(dev); -#ifdef DEBUG - printk("\n%s : Setting RTC values\n",__func__); - printk("tm_sec : %i\n",dt->tm_sec); - printk("tm_min : %i\n",dt->tm_min); - printk("tm_hour: %i\n",dt->tm_hour); - printk("tm_mday: %i\n",dt->tm_mday); - printk("tm_wday: %i\n",dt->tm_wday); - printk("tm_year: %i\n",dt->tm_year); -#endif + dev_dbg(dev, "\n%s : Setting RTC values\n", __func__); + dev_dbg(dev, "tm_sec : %i\n", dt->tm_sec); + dev_dbg(dev, "tm_min : %i\n", dt->tm_min); + dev_dbg(dev, "tm_hour: %i\n", dt->tm_hour); + dev_dbg(dev, "tm_mday: %i\n", dt->tm_mday); + dev_dbg(dev, "tm_wday: %i\n", dt->tm_wday); + dev_dbg(dev, "tm_year: %i\n", dt->tm_year); /* Write all the values to ram... */ v3020_set_reg(chip, V3020_SECONDS, bin2bcd(dt->tm_sec)); @@ -191,7 +187,7 @@ static int rtc_probe(struct platform_device *pdev) /* Test chip by doing a write/read sequence * to the chip ram */ v3020_set_reg(chip, V3020_SECONDS, 0x33); - if(v3020_get_reg(chip, V3020_SECONDS) != 0x33) { + if (v3020_get_reg(chip, V3020_SECONDS) != 0x33) { retval = -ENODEV; goto err_io; } -- cgit v1.2.2 From fa7af8b1bb6dfca7a0c8541683a9bfffbc8dd345 Mon Sep 17 00:00:00 2001 From: Roel Kluin Date: Tue, 31 Mar 2009 15:25:00 -0700 Subject: rtc: test before subtraction on unsigned new_alarm is unsigned so test before the subtraction. [akpm@linux-foundation.org: time-wrapping fix] Signed-off-by: Roel Kluin Cc: David Brownell Cc: Alessandro Zummo Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/rtc/rtc-ds1374.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'drivers/rtc') diff --git a/drivers/rtc/rtc-ds1374.c b/drivers/rtc/rtc-ds1374.c index a5b0fc09f0c6..4d32e328f6cd 100644 --- a/drivers/rtc/rtc-ds1374.c +++ b/drivers/rtc/rtc-ds1374.c @@ -222,16 +222,16 @@ static int ds1374_set_alarm(struct device *dev, struct rtc_wkalrm *alarm) rtc_tm_to_time(&alarm->time, &new_alarm); rtc_tm_to_time(&now, &itime); - new_alarm -= itime; - /* This can happen due to races, in addition to dates that are * truly in the past. To avoid requiring the caller to check for * races, dates in the past are assumed to be in the recent past * (i.e. not something that we'd rather the caller know about via * an error), and the alarm is set to go off as soon as possible. */ - if (new_alarm <= 0) + if (time_before_eq(new_alarm, itime)) new_alarm = 1; + else + new_alarm -= itime; mutex_lock(&ds1374->mutex); -- cgit v1.2.2 From 55457161fdbdb5fe9eeb5027e720462a3fbdcb57 Mon Sep 17 00:00:00 2001 From: Geert Uytterhoeven Date: Fri, 6 Mar 2009 15:54:54 +0100 Subject: parisc: rtc: get_rtc_time() returns unsigned int Signed-off-by: Geert Uytterhoeven Acked-by: Alessandro Zummo Signed-off-by: Kyle McMartin --- drivers/rtc/rtc-parisc.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) (limited to 'drivers/rtc') diff --git a/drivers/rtc/rtc-parisc.c b/drivers/rtc/rtc-parisc.c index b966f56da976..620b949e4f3d 100644 --- a/drivers/rtc/rtc-parisc.c +++ b/drivers/rtc/rtc-parisc.c @@ -13,9 +13,7 @@ static int parisc_get_time(struct device *dev, struct rtc_time *tm) { - unsigned long ret; - - ret = get_rtc_time(tm); + unsigned int ret = get_rtc_time(tm); if (ret & RTC_BATT_BAD) return -EOPNOTSUPP; -- cgit v1.2.2 From 2c83071ead8e2668de69e8659944599c887a12c7 Mon Sep 17 00:00:00 2001 From: Geert Uytterhoeven Date: Fri, 6 Mar 2009 15:57:06 +0100 Subject: parisc: rtc: platform_driver_probe() fixups When using platform_driver_probe(), it's not needed to setup a .probe function, and .remove should be marked __exit_p(), not __devexit_p(). Signed-off-by: Geert Uytterhoeven Acked-by: Alessandro Zummo Cc: dann frazier Signed-off-by: Kyle McMartin --- drivers/rtc/rtc-parisc.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) (limited to 'drivers/rtc') diff --git a/drivers/rtc/rtc-parisc.c b/drivers/rtc/rtc-parisc.c index 620b949e4f3d..f4e871c30d25 100644 --- a/drivers/rtc/rtc-parisc.c +++ b/drivers/rtc/rtc-parisc.c @@ -62,8 +62,7 @@ static struct platform_driver parisc_rtc_driver = { .name = "rtc-parisc", .owner = THIS_MODULE, }, - .probe = parisc_rtc_probe, - .remove = __devexit_p(parisc_rtc_remove), + .remove = __exit_p(parisc_rtc_remove), }; static int __init parisc_rtc_init(void) -- cgit v1.2.2 From 8c534e95d595750d888a7aa8b6151f196d06c75b Mon Sep 17 00:00:00 2001 From: Geert Uytterhoeven Date: Thu, 19 Feb 2009 15:50:53 +0100 Subject: parisc: rtc: Add missing module alias Make udev autoload the driver Signed-off-by: Geert Uytterhoeven Acked-by: Alessandro Zummo Signed-off-by: Kyle McMartin --- drivers/rtc/rtc-parisc.c | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers/rtc') diff --git a/drivers/rtc/rtc-parisc.c b/drivers/rtc/rtc-parisc.c index f4e871c30d25..48ef5b4d016a 100644 --- a/drivers/rtc/rtc-parisc.c +++ b/drivers/rtc/rtc-parisc.c @@ -81,3 +81,4 @@ module_exit(parisc_rtc_fini); MODULE_AUTHOR("Kyle McMartin "); MODULE_LICENSE("GPL"); MODULE_DESCRIPTION("HP PA-RISC RTC driver"); +MODULE_ALIAS("platform:rtc-parisc"); -- cgit v1.2.2 From 3afe6d04626f8de87b15150a30b78df492ab68ee Mon Sep 17 00:00:00 2001 From: Geert Uytterhoeven Date: Thu, 19 Feb 2009 16:46:49 +0100 Subject: parisc: rtc: Rename rtc-parisc to rtc-generic The rtc-parisc driver is not PA-RISC specific at all, as it uses the existing (but deprecated) generic RTC infrastructure ([gs]et_rtc_time()). Rename the driver from rtc-parisc to rtc-generic. Signed-off-by: Geert Uytterhoeven Acked-by: Alessandro Zummo Signed-off-by: Kyle McMartin --- drivers/rtc/Kconfig | 10 +++--- drivers/rtc/Makefile | 2 +- drivers/rtc/rtc-generic.c | 84 +++++++++++++++++++++++++++++++++++++++++++++++ drivers/rtc/rtc-parisc.c | 84 ----------------------------------------------- 4 files changed, 91 insertions(+), 89 deletions(-) create mode 100644 drivers/rtc/rtc-generic.c delete mode 100644 drivers/rtc/rtc-parisc.c (limited to 'drivers/rtc') diff --git a/drivers/rtc/Kconfig b/drivers/rtc/Kconfig index 09d5cd33a3f6..13df5133020a 100644 --- a/drivers/rtc/Kconfig +++ b/drivers/rtc/Kconfig @@ -688,12 +688,14 @@ config RTC_DRV_RS5C313 help If you say yes here you get support for the Ricoh RS5C313 RTC chips. -config RTC_DRV_PARISC - tristate "PA-RISC firmware RTC support" +config RTC_DRV_GENERIC + tristate "Generic RTC support" + # Please consider writing a new RTC driver instead of using the generic + # RTC abstraction depends on PARISC help - Say Y or M here to enable RTC support on PA-RISC systems using - firmware calls. If you do not know what you are doing, you should + Say Y or M here to enable RTC support on systems using the generic + RTC abstraction. If you do not know what you are doing, you should just say Y. config RTC_DRV_PPC diff --git a/drivers/rtc/Makefile b/drivers/rtc/Makefile index e7b09986d26e..39cdb9799de6 100644 --- a/drivers/rtc/Makefile +++ b/drivers/rtc/Makefile @@ -56,7 +56,7 @@ obj-$(CONFIG_RTC_DRV_PCF8563) += rtc-pcf8563.o obj-$(CONFIG_RTC_DRV_PCF8583) += rtc-pcf8583.o obj-$(CONFIG_RTC_DRV_PL030) += rtc-pl030.o obj-$(CONFIG_RTC_DRV_PL031) += rtc-pl031.o -obj-$(CONFIG_RTC_DRV_PARISC) += rtc-parisc.o +obj-$(CONFIG_RTC_DRV_GENERIC) += rtc-generic.o obj-$(CONFIG_RTC_DRV_PPC) += rtc-ppc.o obj-$(CONFIG_RTC_DRV_PXA) += rtc-pxa.o obj-$(CONFIG_RTC_DRV_R9701) += rtc-r9701.o diff --git a/drivers/rtc/rtc-generic.c b/drivers/rtc/rtc-generic.c new file mode 100644 index 000000000000..98322004ad2e --- /dev/null +++ b/drivers/rtc/rtc-generic.c @@ -0,0 +1,84 @@ +/* rtc-generic: RTC driver using the generic RTC abstraction + * + * Copyright (C) 2008 Kyle McMartin + */ + +#include +#include +#include +#include +#include + +#include + +static int generic_get_time(struct device *dev, struct rtc_time *tm) +{ + unsigned int ret = get_rtc_time(tm); + + if (ret & RTC_BATT_BAD) + return -EOPNOTSUPP; + + return rtc_valid_tm(tm); +} + +static int generic_set_time(struct device *dev, struct rtc_time *tm) +{ + if (set_rtc_time(tm) < 0) + return -EOPNOTSUPP; + + return 0; +} + +static const struct rtc_class_ops generic_rtc_ops = { + .read_time = generic_get_time, + .set_time = generic_set_time, +}; + +static int __init generic_rtc_probe(struct platform_device *dev) +{ + struct rtc_device *rtc; + + rtc = rtc_device_register("rtc-generic", &dev->dev, &generic_rtc_ops, + THIS_MODULE); + if (IS_ERR(rtc)) + return PTR_ERR(rtc); + + platform_set_drvdata(dev, rtc); + + return 0; +} + +static int __exit generic_rtc_remove(struct platform_device *dev) +{ + struct rtc_device *rtc = platform_get_drvdata(dev); + + rtc_device_unregister(rtc); + + return 0; +} + +static struct platform_driver generic_rtc_driver = { + .driver = { + .name = "rtc-generic", + .owner = THIS_MODULE, + }, + .remove = __exit_p(generic_rtc_remove), +}; + +static int __init generic_rtc_init(void) +{ + return platform_driver_probe(&generic_rtc_driver, generic_rtc_probe); +} + +static void __exit generic_rtc_fini(void) +{ + platform_driver_unregister(&generic_rtc_driver); +} + +module_init(generic_rtc_init); +module_exit(generic_rtc_fini); + +MODULE_AUTHOR("Kyle McMartin "); +MODULE_LICENSE("GPL"); +MODULE_DESCRIPTION("Generic RTC driver"); +MODULE_ALIAS("platform:rtc-generic"); diff --git a/drivers/rtc/rtc-parisc.c b/drivers/rtc/rtc-parisc.c deleted file mode 100644 index 48ef5b4d016a..000000000000 --- a/drivers/rtc/rtc-parisc.c +++ /dev/null @@ -1,84 +0,0 @@ -/* rtc-parisc: RTC for HP PA-RISC firmware - * - * Copyright (C) 2008 Kyle McMartin - */ - -#include -#include -#include -#include -#include - -#include - -static int parisc_get_time(struct device *dev, struct rtc_time *tm) -{ - unsigned int ret = get_rtc_time(tm); - - if (ret & RTC_BATT_BAD) - return -EOPNOTSUPP; - - return rtc_valid_tm(tm); -} - -static int parisc_set_time(struct device *dev, struct rtc_time *tm) -{ - if (set_rtc_time(tm) < 0) - return -EOPNOTSUPP; - - return 0; -} - -static const struct rtc_class_ops parisc_rtc_ops = { - .read_time = parisc_get_time, - .set_time = parisc_set_time, -}; - -static int __init parisc_rtc_probe(struct platform_device *dev) -{ - struct rtc_device *rtc; - - rtc = rtc_device_register("rtc-parisc", &dev->dev, &parisc_rtc_ops, - THIS_MODULE); - if (IS_ERR(rtc)) - return PTR_ERR(rtc); - - platform_set_drvdata(dev, rtc); - - return 0; -} - -static int __exit parisc_rtc_remove(struct platform_device *dev) -{ - struct rtc_device *rtc = platform_get_drvdata(dev); - - rtc_device_unregister(rtc); - - return 0; -} - -static struct platform_driver parisc_rtc_driver = { - .driver = { - .name = "rtc-parisc", - .owner = THIS_MODULE, - }, - .remove = __exit_p(parisc_rtc_remove), -}; - -static int __init parisc_rtc_init(void) -{ - return platform_driver_probe(&parisc_rtc_driver, parisc_rtc_probe); -} - -static void __exit parisc_rtc_fini(void) -{ - platform_driver_unregister(&parisc_rtc_driver); -} - -module_init(parisc_rtc_init); -module_exit(parisc_rtc_fini); - -MODULE_AUTHOR("Kyle McMartin "); -MODULE_LICENSE("GPL"); -MODULE_DESCRIPTION("HP PA-RISC RTC driver"); -MODULE_ALIAS("platform:rtc-parisc"); -- cgit v1.2.2 From 2ceb3ad705aa1abe6656b038bb9f4a6b1201cc35 Mon Sep 17 00:00:00 2001 From: Geert Uytterhoeven Date: Thu, 19 Feb 2009 16:50:46 +0100 Subject: m68k: Hook up rtc-generic m68k has been a long time user of the generic RTC abstraction, so hook up rtc-generic: - Create the "rtc-generic" platform device if mach_hwclk is set, - Add checks for mach_hwclk, in anticipation of RTC chip drivers being moved to drivers/rtc/. Signed-off-by: Geert Uytterhoeven Acked-by: Alessandro Zummo Signed-off-by: Kyle McMartin --- drivers/rtc/Kconfig | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/rtc') diff --git a/drivers/rtc/Kconfig b/drivers/rtc/Kconfig index 13df5133020a..5aab5b917c8b 100644 --- a/drivers/rtc/Kconfig +++ b/drivers/rtc/Kconfig @@ -692,7 +692,7 @@ config RTC_DRV_GENERIC tristate "Generic RTC support" # Please consider writing a new RTC driver instead of using the generic # RTC abstraction - depends on PARISC + depends on PARISC || M68K help Say Y or M here to enable RTC support on systems using the generic RTC abstraction. If you do not know what you are doing, you should -- cgit v1.2.2 From bcd68a70cb0eee556d86d93133aa150319bd9f53 Mon Sep 17 00:00:00 2001 From: Geert Uytterhoeven Date: Thu, 19 Feb 2009 16:50:46 +0100 Subject: powerpc: Hook up rtc-generic, and kill rtc-ppc PowerPC has been a long time user of the generic RTC abstraction, so hook up rtc-generic: - Create the "rtc-generic" platform device if ppc_md.get_rtc_time is set, - Kill rtc-ppc, as rtc-generic offers the same functionality in a more generic way, and supports autoloading through udev. Signed-off-by: Geert Uytterhoeven Acked-by: David Woodhouse Acked-by: Alessandro Zummo Acked-by: Benjamin Herrenschmidt Signed-off-by: Kyle McMartin --- drivers/rtc/Kconfig | 10 +------- drivers/rtc/Makefile | 1 - drivers/rtc/rtc-ppc.c | 69 --------------------------------------------------- 3 files changed, 1 insertion(+), 79 deletions(-) delete mode 100644 drivers/rtc/rtc-ppc.c (limited to 'drivers/rtc') diff --git a/drivers/rtc/Kconfig b/drivers/rtc/Kconfig index 5aab5b917c8b..fa66d10dd5a0 100644 --- a/drivers/rtc/Kconfig +++ b/drivers/rtc/Kconfig @@ -692,20 +692,12 @@ config RTC_DRV_GENERIC tristate "Generic RTC support" # Please consider writing a new RTC driver instead of using the generic # RTC abstraction - depends on PARISC || M68K + depends on PARISC || M68K || PPC help Say Y or M here to enable RTC support on systems using the generic RTC abstraction. If you do not know what you are doing, you should just say Y. -config RTC_DRV_PPC - tristate "PowerPC machine dependent RTC support" - depends on PPC - help - The PowerPC kernel has machine-specific functions for accessing - the RTC. This exposes that functionality through the generic RTC - class. - config RTC_DRV_PXA tristate "PXA27x/PXA3xx" depends on ARCH_PXA diff --git a/drivers/rtc/Makefile b/drivers/rtc/Makefile index 39cdb9799de6..2b022f19a6ed 100644 --- a/drivers/rtc/Makefile +++ b/drivers/rtc/Makefile @@ -57,7 +57,6 @@ obj-$(CONFIG_RTC_DRV_PCF8583) += rtc-pcf8583.o obj-$(CONFIG_RTC_DRV_PL030) += rtc-pl030.o obj-$(CONFIG_RTC_DRV_PL031) += rtc-pl031.o obj-$(CONFIG_RTC_DRV_GENERIC) += rtc-generic.o -obj-$(CONFIG_RTC_DRV_PPC) += rtc-ppc.o obj-$(CONFIG_RTC_DRV_PXA) += rtc-pxa.o obj-$(CONFIG_RTC_DRV_R9701) += rtc-r9701.o obj-$(CONFIG_RTC_DRV_RS5C313) += rtc-rs5c313.o diff --git a/drivers/rtc/rtc-ppc.c b/drivers/rtc/rtc-ppc.c deleted file mode 100644 index c8e97e25ef7e..000000000000 --- a/drivers/rtc/rtc-ppc.c +++ /dev/null @@ -1,69 +0,0 @@ -/* - * RTC driver for ppc_md RTC functions - * - * © 2007 Red Hat, Inc. - * - * Author: David Woodhouse - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - */ - - -#include -#include -#include -#include -#include - -static int ppc_rtc_read_time(struct device *dev, struct rtc_time *tm) -{ - ppc_md.get_rtc_time(tm); - return 0; -} - -static int ppc_rtc_set_time(struct device *dev, struct rtc_time *tm) -{ - return ppc_md.set_rtc_time(tm); -} - -static const struct rtc_class_ops ppc_rtc_ops = { - .set_time = ppc_rtc_set_time, - .read_time = ppc_rtc_read_time, -}; - -static struct rtc_device *rtc; -static struct platform_device *ppc_rtc_pdev; - -static int __init ppc_rtc_init(void) -{ - if (!ppc_md.get_rtc_time || !ppc_md.set_rtc_time) - return -ENODEV; - - ppc_rtc_pdev = platform_device_register_simple("ppc-rtc", 0, NULL, 0); - if (IS_ERR(ppc_rtc_pdev)) - return PTR_ERR(ppc_rtc_pdev); - - rtc = rtc_device_register("ppc_md", &ppc_rtc_pdev->dev, - &ppc_rtc_ops, THIS_MODULE); - if (IS_ERR(rtc)) { - platform_device_unregister(ppc_rtc_pdev); - return PTR_ERR(rtc); - } - - return 0; -} - -static void __exit ppc_rtc_exit(void) -{ - rtc_device_unregister(rtc); - platform_device_unregister(ppc_rtc_pdev); -} - -module_init(ppc_rtc_init); -module_exit(ppc_rtc_exit); - -MODULE_LICENSE("GPL"); -MODULE_AUTHOR("David Woodhouse "); -MODULE_DESCRIPTION("Generic RTC class driver for PowerPC"); -- cgit v1.2.2 From 0b5f037a4dc495f9c40eed7f076fc6c23af3359b Mon Sep 17 00:00:00 2001 From: Geert Uytterhoeven Date: Tue, 24 Feb 2009 14:04:20 +0100 Subject: powerpc/ps3: Add rtc-ps3 Create a real RTC driver for PS3, and unhook the deprecated ppc_md.[gs]et_rtc_time. Signed-off-by: Geert Uytterhoeven Acked-by: Alessandro Zummo Acked-by: Geoff Levand Signed-off-by: Kyle McMartin --- drivers/rtc/Kconfig | 9 +++++ drivers/rtc/Makefile | 1 + drivers/rtc/rtc-ps3.c | 104 ++++++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 114 insertions(+) create mode 100644 drivers/rtc/rtc-ps3.c (limited to 'drivers/rtc') diff --git a/drivers/rtc/Kconfig b/drivers/rtc/Kconfig index fa66d10dd5a0..b072826c9ee1 100644 --- a/drivers/rtc/Kconfig +++ b/drivers/rtc/Kconfig @@ -741,4 +741,13 @@ config RTC_DRV_MV This driver can also be built as a module. If so, the module will be called rtc-mv. +config RTC_DRV_PS3 + tristate "PS3 RTC" + depends on PPC_PS3 + help + If you say yes here you will get support for the RTC on PS3. + + This driver can also be built as a module. If so, the module + will be called rtc-ps3. + endif # RTC_CLASS diff --git a/drivers/rtc/Makefile b/drivers/rtc/Makefile index 2b022f19a6ed..6c0639a14f09 100644 --- a/drivers/rtc/Makefile +++ b/drivers/rtc/Makefile @@ -76,3 +76,4 @@ obj-$(CONFIG_RTC_DRV_VR41XX) += rtc-vr41xx.o obj-$(CONFIG_RTC_DRV_WM8350) += rtc-wm8350.o obj-$(CONFIG_RTC_DRV_X1205) += rtc-x1205.o obj-$(CONFIG_RTC_DRV_PCF50633) += rtc-pcf50633.o +obj-$(CONFIG_RTC_DRV_PS3) += rtc-ps3.o diff --git a/drivers/rtc/rtc-ps3.c b/drivers/rtc/rtc-ps3.c new file mode 100644 index 000000000000..968133ce1ee8 --- /dev/null +++ b/drivers/rtc/rtc-ps3.c @@ -0,0 +1,104 @@ +/* + * PS3 RTC Driver + * + * Copyright 2009 Sony Corporation + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; version 2 of the License. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. + * If not, see . + */ + +#include +#include +#include +#include + +#include +#include + + +static u64 read_rtc(void) +{ + int result; + u64 rtc_val; + u64 tb_val; + + result = lv1_get_rtc(&rtc_val, &tb_val); + BUG_ON(result); + + return rtc_val; +} + +static int ps3_get_time(struct device *dev, struct rtc_time *tm) +{ + rtc_time_to_tm(read_rtc() + ps3_os_area_get_rtc_diff(), tm); + return rtc_valid_tm(tm); +} + +static int ps3_set_time(struct device *dev, struct rtc_time *tm) +{ + unsigned long now; + + rtc_tm_to_time(tm, &now); + ps3_os_area_set_rtc_diff(now - read_rtc()); + return 0; +} + +static const struct rtc_class_ops ps3_rtc_ops = { + .read_time = ps3_get_time, + .set_time = ps3_set_time, +}; + +static int __init ps3_rtc_probe(struct platform_device *dev) +{ + struct rtc_device *rtc; + + rtc = rtc_device_register("rtc-ps3", &dev->dev, &ps3_rtc_ops, + THIS_MODULE); + if (IS_ERR(rtc)) + return PTR_ERR(rtc); + + platform_set_drvdata(dev, rtc); + return 0; +} + +static int __exit ps3_rtc_remove(struct platform_device *dev) +{ + rtc_device_unregister(platform_get_drvdata(dev)); + return 0; +} + +static struct platform_driver ps3_rtc_driver = { + .driver = { + .name = "rtc-ps3", + .owner = THIS_MODULE, + }, + .remove = __exit_p(ps3_rtc_remove), +}; + +static int __init ps3_rtc_init(void) +{ + return platform_driver_probe(&ps3_rtc_driver, ps3_rtc_probe); +} + +static void __exit ps3_rtc_fini(void) +{ + platform_driver_unregister(&ps3_rtc_driver); +} + +module_init(ps3_rtc_init); +module_exit(ps3_rtc_fini); + +MODULE_AUTHOR("Sony Corporation"); +MODULE_LICENSE("GPL"); +MODULE_DESCRIPTION("ps3 RTC driver"); +MODULE_ALIAS("platform:rtc-ps3"); -- cgit v1.2.2 From faa9fa8e448ba4c0a9d61778fd3cda1313bf1533 Mon Sep 17 00:00:00 2001 From: Magnus Damm Date: Wed, 1 Apr 2009 14:45:17 +0000 Subject: rtc: rtc-sh: use set_irq_wake() Modify the sh_rtc driver to use set_irq_wake() during suspend and resume. These functions are used to enable the rtc interrupts in the interrupt controller so the rtc can be used to wakeup the system from suspend. Signed-off-by: Magnus Damm Signed-off-by: Paul Mundt --- drivers/rtc/rtc-sh.c | 36 ++++++++++++++++++++++++++++++++++++ 1 file changed, 36 insertions(+) (limited to 'drivers/rtc') diff --git a/drivers/rtc/rtc-sh.c b/drivers/rtc/rtc-sh.c index 4898f7fe8518..9b1ff12bf947 100644 --- a/drivers/rtc/rtc-sh.c +++ b/drivers/rtc/rtc-sh.c @@ -795,10 +795,46 @@ static int __devexit sh_rtc_remove(struct platform_device *pdev) return 0; } + +static void sh_rtc_set_irq_wake(struct device *dev, int enabled) +{ + struct platform_device *pdev = to_platform_device(dev); + struct sh_rtc *rtc = platform_get_drvdata(pdev); + + set_irq_wake(rtc->periodic_irq, enabled); + if (rtc->carry_irq > 0) { + set_irq_wake(rtc->carry_irq, enabled); + set_irq_wake(rtc->alarm_irq, enabled); + } + +} + +static int sh_rtc_suspend(struct device *dev) +{ + if (device_may_wakeup(dev)) + sh_rtc_set_irq_wake(dev, 1); + + return 0; +} + +static int sh_rtc_resume(struct device *dev) +{ + if (device_may_wakeup(dev)) + sh_rtc_set_irq_wake(dev, 0); + + return 0; +} + +static struct dev_pm_ops sh_rtc_dev_pm_ops = { + .suspend = sh_rtc_suspend, + .resume = sh_rtc_resume, +}; + static struct platform_driver sh_rtc_platform_driver = { .driver = { .name = DRV_NAME, .owner = THIS_MODULE, + .pm = &sh_rtc_dev_pm_ops, }, .probe = sh_rtc_probe, .remove = __devexit_p(sh_rtc_remove), -- cgit v1.2.2 From 96615841e170f0108832e64a90d51b469573a472 Mon Sep 17 00:00:00 2001 From: Mike Rapoport Date: Thu, 2 Apr 2009 16:57:01 -0700 Subject: rtc-v3020: add ability to access v3020 chip with GPIOs The v3020 RTC can be connected to GPIOs as well as to memory-like interface. Add ability to use GPIO bit-bang for v3020 read-write access. [akpm@linux-foundation.org: fix off-by-one in error path] Signed-off-by: Mike Rapoport Acked-by: Alessandro Zummo Cc: David Brownell Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/rtc/rtc-v3020.c | 190 +++++++++++++++++++++++++++++++++++++++++++----- 1 file changed, 170 insertions(+), 20 deletions(-) (limited to 'drivers/rtc') diff --git a/drivers/rtc/rtc-v3020.c b/drivers/rtc/rtc-v3020.c index 66955cc9c746..ad164056feb6 100644 --- a/drivers/rtc/rtc-v3020.c +++ b/drivers/rtc/rtc-v3020.c @@ -27,17 +27,162 @@ #include #include #include +#include #include #undef DEBUG +struct v3020; + +struct v3020_chip_ops { + int (*map_io)(struct v3020 *chip, struct platform_device *pdev, + struct v3020_platform_data *pdata); + void (*unmap_io)(struct v3020 *chip); + unsigned char (*read_bit)(struct v3020 *chip); + void (*write_bit)(struct v3020 *chip, unsigned char bit); +}; + +#define V3020_CS 0 +#define V3020_WR 1 +#define V3020_RD 2 +#define V3020_IO 3 + +struct v3020_gpio { + const char *name; + unsigned int gpio; +}; + struct v3020 { + /* MMIO access */ void __iomem *ioaddress; int leftshift; + + /* GPIO access */ + struct v3020_gpio *gpio; + + struct v3020_chip_ops *ops; + struct rtc_device *rtc; }; + +static int v3020_mmio_map(struct v3020 *chip, struct platform_device *pdev, + struct v3020_platform_data *pdata) +{ + if (pdev->num_resources != 1) + return -EBUSY; + + if (pdev->resource[0].flags != IORESOURCE_MEM) + return -EBUSY; + + chip->leftshift = pdata->leftshift; + chip->ioaddress = ioremap(pdev->resource[0].start, 1); + if (chip->ioaddress == NULL) + return -EBUSY; + + return 0; +} + +static void v3020_mmio_unmap(struct v3020 *chip) +{ + iounmap(chip->ioaddress); +} + +static void v3020_mmio_write_bit(struct v3020 *chip, unsigned char bit) +{ + writel(bit << chip->leftshift, chip->ioaddress); +} + +static unsigned char v3020_mmio_read_bit(struct v3020 *chip) +{ + return readl(chip->ioaddress) & (1 << chip->leftshift); +} + +static struct v3020_chip_ops v3020_mmio_ops = { + .map_io = v3020_mmio_map, + .unmap_io = v3020_mmio_unmap, + .read_bit = v3020_mmio_read_bit, + .write_bit = v3020_mmio_write_bit, +}; + +static struct v3020_gpio v3020_gpio[] = { + { "RTC CS", 0 }, + { "RTC WR", 0 }, + { "RTC RD", 0 }, + { "RTC IO", 0 }, +}; + +static int v3020_gpio_map(struct v3020 *chip, struct platform_device *pdev, + struct v3020_platform_data *pdata) +{ + int i, err; + + v3020_gpio[V3020_CS].gpio = pdata->gpio_cs; + v3020_gpio[V3020_WR].gpio = pdata->gpio_wr; + v3020_gpio[V3020_RD].gpio = pdata->gpio_rd; + v3020_gpio[V3020_IO].gpio = pdata->gpio_io; + + for (i = 0; i < ARRAY_SIZE(v3020_gpio); i++) { + err = gpio_request(v3020_gpio[i].gpio, v3020_gpio[i].name); + if (err) + goto err_request; + + gpio_direction_output(v3020_gpio[i].gpio, 1); + } + + chip->gpio = v3020_gpio; + + return 0; + +err_request: + while (--i >= 0) + gpio_free(v3020_gpio[i].gpio); + + return err; +} + +static void v3020_gpio_unmap(struct v3020 *chip) +{ + int i; + + for (i = 0; i < ARRAY_SIZE(v3020_gpio); i++) + gpio_free(v3020_gpio[i].gpio); +} + +static void v3020_gpio_write_bit(struct v3020 *chip, unsigned char bit) +{ + gpio_direction_output(chip->gpio[V3020_IO].gpio, bit); + gpio_set_value(chip->gpio[V3020_CS].gpio, 0); + gpio_set_value(chip->gpio[V3020_WR].gpio, 0); + udelay(1); + gpio_set_value(chip->gpio[V3020_WR].gpio, 1); + gpio_set_value(chip->gpio[V3020_CS].gpio, 1); +} + +static unsigned char v3020_gpio_read_bit(struct v3020 *chip) +{ + int bit; + + gpio_direction_input(chip->gpio[V3020_IO].gpio); + gpio_set_value(chip->gpio[V3020_CS].gpio, 0); + gpio_set_value(chip->gpio[V3020_RD].gpio, 0); + udelay(1); + bit = !!gpio_get_value(chip->gpio[V3020_IO].gpio); + udelay(1); + gpio_set_value(chip->gpio[V3020_RD].gpio, 1); + gpio_set_value(chip->gpio[V3020_CS].gpio, 1); + + return bit; +} + +static struct v3020_chip_ops v3020_gpio_ops = { + .map_io = v3020_gpio_map, + .unmap_io = v3020_gpio_unmap, + .read_bit = v3020_gpio_read_bit, + .write_bit = v3020_gpio_write_bit, +}; + static void v3020_set_reg(struct v3020 *chip, unsigned char address, unsigned char data) { @@ -46,7 +191,7 @@ static void v3020_set_reg(struct v3020 *chip, unsigned char address, tmp = address; for (i = 0; i < 4; i++) { - writel((tmp & 1) << chip->leftshift, chip->ioaddress); + chip->ops->write_bit(chip, (tmp & 1)); tmp >>= 1; udelay(1); } @@ -54,7 +199,7 @@ static void v3020_set_reg(struct v3020 *chip, unsigned char address, /* Commands dont have data */ if (!V3020_IS_COMMAND(address)) { for (i = 0; i < 8; i++) { - writel((data & 1) << chip->leftshift, chip->ioaddress); + chip->ops->write_bit(chip, (data & 1)); data >>= 1; udelay(1); } @@ -67,14 +212,14 @@ static unsigned char v3020_get_reg(struct v3020 *chip, unsigned char address) int i; for (i = 0; i < 4; i++) { - writel((address & 1) << chip->leftshift, chip->ioaddress); + chip->ops->write_bit(chip, (address & 1)); address >>= 1; udelay(1); } for (i = 0; i < 8; i++) { data >>= 1; - if (readl(chip->ioaddress) & (1 << chip->leftshift)) + if (chip->ops->read_bit(chip)) data |= 0x80; udelay(1); } @@ -164,25 +309,23 @@ static int rtc_probe(struct platform_device *pdev) int i; int temp; - if (pdev->num_resources != 1) - return -EBUSY; - - if (pdev->resource[0].flags != IORESOURCE_MEM) - return -EBUSY; - chip = kzalloc(sizeof *chip, GFP_KERNEL); if (!chip) return -ENOMEM; - chip->leftshift = pdata->leftshift; - chip->ioaddress = ioremap(pdev->resource[0].start, 1); - if (chip->ioaddress == NULL) + if (pdata->use_gpio) + chip->ops = &v3020_gpio_ops; + else + chip->ops = &v3020_mmio_ops; + + retval = chip->ops->map_io(chip, pdev, pdata); + if (retval) goto err_chip; /* Make sure the v3020 expects a communication cycle * by reading 8 times */ for (i = 0; i < 8; i++) - temp = readl(chip->ioaddress); + temp = chip->ops->read_bit(chip); /* Test chip by doing a write/read sequence * to the chip ram */ @@ -196,10 +339,17 @@ static int rtc_probe(struct platform_device *pdev) * are all disabled */ v3020_set_reg(chip, V3020_STATUS_0, 0x0); - dev_info(&pdev->dev, "Chip available at physical address 0x%llx," - "data connected to D%d\n", - (unsigned long long)pdev->resource[0].start, - chip->leftshift); + if (pdata->use_gpio) + dev_info(&pdev->dev, "Chip available at GPIOs " + "%d, %d, %d, %d\n", + chip->gpio[V3020_CS].gpio, chip->gpio[V3020_WR].gpio, + chip->gpio[V3020_RD].gpio, chip->gpio[V3020_IO].gpio); + else + dev_info(&pdev->dev, "Chip available at " + "physical address 0x%llx," + "data connected to D%d\n", + (unsigned long long)pdev->resource[0].start, + chip->leftshift); platform_set_drvdata(pdev, chip); @@ -214,7 +364,7 @@ static int rtc_probe(struct platform_device *pdev) return 0; err_io: - iounmap(chip->ioaddress); + chip->ops->unmap_io(chip); err_chip: kfree(chip); @@ -229,7 +379,7 @@ static int rtc_remove(struct platform_device *dev) if (rtc) rtc_device_unregister(rtc); - iounmap(chip->ioaddress); + chip->ops->unmap_io(chip); kfree(chip); return 0; -- cgit v1.2.2 From f30281f4f7c2a0efcfeddad12277dfdada8f08a7 Mon Sep 17 00:00:00 2001 From: Daniel Glockner Date: Thu, 2 Apr 2009 16:57:03 -0700 Subject: rtc: add m41t62 support to rtc-m41t80 driver Compared to the other supported chips, the m41t62 uses a different register to set the square wave frequency. Signed-off-by: Daniel Glockner Cc: Chris Zankel Cc: David Brownell Cc: Alessandro Zummo Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/rtc/Kconfig | 4 ++-- drivers/rtc/rtc-m41t80.c | 18 +++++++++++++----- 2 files changed, 15 insertions(+), 7 deletions(-) (limited to 'drivers/rtc') diff --git a/drivers/rtc/Kconfig b/drivers/rtc/Kconfig index 09d5cd33a3f6..56002f7d26bd 100644 --- a/drivers/rtc/Kconfig +++ b/drivers/rtc/Kconfig @@ -225,11 +225,11 @@ config RTC_DRV_PCF8583 will be called rtc-pcf8583. config RTC_DRV_M41T80 - tristate "ST M41T65/M41T80/81/82/83/84/85/87" + tristate "ST M41T62/65/M41T80/81/82/83/84/85/87" help If you say Y here you will get support for the ST M41T60 and M41T80 RTC chips series. Currently, the following chips are - supported: M41T65, M41T80, M41T81, M41T82, M41T83, M41ST84, + supported: M41T62, M41T65, M41T80, M41T81, M41T82, M41T83, M41ST84, M41ST85, and M41ST87. This driver can also be built as a module. If so, the module diff --git a/drivers/rtc/rtc-m41t80.c b/drivers/rtc/rtc-m41t80.c index 893f7dece239..60fe266f0f49 100644 --- a/drivers/rtc/rtc-m41t80.c +++ b/drivers/rtc/rtc-m41t80.c @@ -64,10 +64,12 @@ #define M41T80_FEATURE_BL (1 << 1) /* Battery low indicator */ #define M41T80_FEATURE_SQ (1 << 2) /* Squarewave feature */ #define M41T80_FEATURE_WD (1 << 3) /* Extra watchdog resolution */ +#define M41T80_FEATURE_SQ_ALT (1 << 4) /* RSx bits are in reg 4 */ #define DRV_VERSION "0.05" static const struct i2c_device_id m41t80_id[] = { + { "m41t62", M41T80_FEATURE_SQ | M41T80_FEATURE_SQ_ALT }, { "m41t65", M41T80_FEATURE_HT | M41T80_FEATURE_WD }, { "m41t80", M41T80_FEATURE_SQ }, { "m41t81", M41T80_FEATURE_HT | M41T80_FEATURE_SQ}, @@ -393,12 +395,15 @@ static ssize_t m41t80_sysfs_show_sqwfreq(struct device *dev, { struct i2c_client *client = to_i2c_client(dev); struct m41t80_data *clientdata = i2c_get_clientdata(client); - int val; + int val, reg_sqw; if (!(clientdata->features & M41T80_FEATURE_SQ)) return -EINVAL; - val = i2c_smbus_read_byte_data(client, M41T80_REG_SQW); + reg_sqw = M41T80_REG_SQW; + if (clientdata->features & M41T80_FEATURE_SQ_ALT) + reg_sqw = M41T80_REG_WDAY; + val = i2c_smbus_read_byte_data(client, reg_sqw); if (val < 0) return -EIO; val = (val >> 4) & 0xf; @@ -419,7 +424,7 @@ static ssize_t m41t80_sysfs_set_sqwfreq(struct device *dev, { struct i2c_client *client = to_i2c_client(dev); struct m41t80_data *clientdata = i2c_get_clientdata(client); - int almon, sqw; + int almon, sqw, reg_sqw; int val = simple_strtoul(buf, NULL, 0); if (!(clientdata->features & M41T80_FEATURE_SQ)) @@ -440,13 +445,16 @@ static ssize_t m41t80_sysfs_set_sqwfreq(struct device *dev, almon = i2c_smbus_read_byte_data(client, M41T80_REG_ALARM_MON); if (almon < 0) return -EIO; - sqw = i2c_smbus_read_byte_data(client, M41T80_REG_SQW); + reg_sqw = M41T80_REG_SQW; + if (clientdata->features & M41T80_FEATURE_SQ_ALT) + reg_sqw = M41T80_REG_WDAY; + sqw = i2c_smbus_read_byte_data(client, reg_sqw); if (sqw < 0) return -EIO; sqw = (sqw & 0x0f) | (val << 4); if (i2c_smbus_write_byte_data(client, M41T80_REG_ALARM_MON, almon & ~M41T80_ALMON_SQWE) < 0 || - i2c_smbus_write_byte_data(client, M41T80_REG_SQW, sqw) < 0) + i2c_smbus_write_byte_data(client, reg_sqw, sqw) < 0) return -EIO; if (val && i2c_smbus_write_byte_data(client, M41T80_REG_ALARM_MON, almon | M41T80_ALMON_SQWE) < 0) -- cgit v1.2.2