From 49908e739e23e2672d3efb9b1a35f877f8e86342 Mon Sep 17 00:00:00 2001 From: Alexander Beregalov Date: Fri, 5 Mar 2010 13:44:19 -0800 Subject: rtc: mxc: fix memory leak Free pdata before exit. Found by cppcheck. [yuasa@linux-mips.org: add missing iounmap()] Signed-off-by: Alexander Beregalov Reviewed-by: WANG Cong Acked-by: Daniel Mack Acked-by: Alessandro Zummo Cc Yoichi Yuasa Cc: Paul Gortmaker Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/rtc/rtc-mxc.c | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) (limited to 'drivers/rtc') diff --git a/drivers/rtc/rtc-mxc.c b/drivers/rtc/rtc-mxc.c index 6bd5072d4eb7..8710f9415d98 100644 --- a/drivers/rtc/rtc-mxc.c +++ b/drivers/rtc/rtc-mxc.c @@ -396,8 +396,11 @@ static int __init mxc_rtc_probe(struct platform_device *pdev) pdata->ioaddr = ioremap(res->start, resource_size(res)); clk = clk_get(&pdev->dev, "ckil"); - if (IS_ERR(clk)) - return PTR_ERR(clk); + if (IS_ERR(clk)) { + iounmap(pdata->ioaddr); + ret = PTR_ERR(clk); + goto exit_free_pdata; + } rate = clk_get_rate(clk); clk_put(clk); -- cgit v1.2.3 From b4877d2b3678f4455f2b8b0211868ac57c3b1ff6 Mon Sep 17 00:00:00 2001 From: H Hartley Sweeten Date: Fri, 5 Mar 2010 13:44:20 -0800 Subject: rtc-ep93xx.c: cleanup probe/remove routines Fix issue with rtc device not getting unregistered in probe error path. Use the devres managed resource functions in the probe routine to cleanup the error path. Use sysfs_{create/remove}_group to add/remove the sysfs files. Reduces the text size by 132 bytes, increases data by 12 bytes: text data bss dec hex filename - 937 124 0 1061 425 rtc-ep93xx.o + 805 136 0 941 3ad rtc-ep93xx.o Signed-off-by: H Hartley Sweeten Acked-by: Alessandro Zummo Cc: Paul Gortmaker Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/rtc/rtc-ep93xx.c | 71 +++++++++++++++++++----------------------------- 1 file changed, 28 insertions(+), 43 deletions(-) (limited to 'drivers/rtc') diff --git a/drivers/rtc/rtc-ep93xx.c b/drivers/rtc/rtc-ep93xx.c index 9da02d108b73..91bde976bc0f 100644 --- a/drivers/rtc/rtc-ep93xx.c +++ b/drivers/rtc/rtc-ep93xx.c @@ -115,6 +115,15 @@ static ssize_t ep93xx_rtc_show_comp_delete(struct device *dev, } static DEVICE_ATTR(comp_delete, S_IRUGO, ep93xx_rtc_show_comp_delete, NULL); +static struct attribute *ep93xx_rtc_attrs[] = { + &dev_attr_comp_preload.attr, + &dev_attr_comp_delete.attr, + NULL +}; + +static const struct attribute_group ep93xx_rtc_sysfs_files = { + .attrs = ep93xx_rtc_attrs, +}; static int __init ep93xx_rtc_probe(struct platform_device *pdev) { @@ -123,27 +132,22 @@ static int __init ep93xx_rtc_probe(struct platform_device *pdev) struct rtc_device *rtc; int err; - ep93xx_rtc = kzalloc(sizeof(struct ep93xx_rtc), GFP_KERNEL); - if (ep93xx_rtc == NULL) + ep93xx_rtc = devm_kzalloc(&pdev->dev, sizeof(*ep93xx_rtc), GFP_KERNEL); + if (!ep93xx_rtc) return -ENOMEM; res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - if (res == NULL) { - err = -ENXIO; - goto fail_free; - } + if (!res) + return -ENXIO; - res = request_mem_region(res->start, resource_size(res), pdev->name); - if (res == NULL) { - err = -EBUSY; - goto fail_free; - } + if (!devm_request_mem_region(&pdev->dev, res->start, + resource_size(res), pdev->name)) + return -EBUSY; - ep93xx_rtc->mmio_base = ioremap(res->start, resource_size(res)); - if (ep93xx_rtc->mmio_base == NULL) { - err = -ENXIO; - goto fail; - } + ep93xx_rtc->mmio_base = devm_ioremap(&pdev->dev, res->start, + resource_size(res)); + if (!ep93xx_rtc->mmio_base) + return -ENXIO; pdev->dev.platform_data = ep93xx_rtc; @@ -151,53 +155,34 @@ static int __init ep93xx_rtc_probe(struct platform_device *pdev) &pdev->dev, &ep93xx_rtc_ops, THIS_MODULE); if (IS_ERR(rtc)) { err = PTR_ERR(rtc); - goto fail; + goto exit; } platform_set_drvdata(pdev, rtc); - err = device_create_file(&pdev->dev, &dev_attr_comp_preload); + err = sysfs_create_group(&pdev->dev.kobj, &ep93xx_rtc_sysfs_files); if (err) goto fail; - err = device_create_file(&pdev->dev, &dev_attr_comp_delete); - if (err) { - device_remove_file(&pdev->dev, &dev_attr_comp_preload); - goto fail; - } return 0; fail: - if (ep93xx_rtc->mmio_base) { - iounmap(ep93xx_rtc->mmio_base); - pdev->dev.platform_data = NULL; - } - release_mem_region(res->start, resource_size(res)); -fail_free: - kfree(ep93xx_rtc); + platform_set_drvdata(pdev, NULL); + rtc_device_unregister(rtc); +exit: + pdev->dev.platform_data = NULL; return err; } static int __exit ep93xx_rtc_remove(struct platform_device *pdev) { struct rtc_device *rtc = platform_get_drvdata(pdev); - struct ep93xx_rtc *ep93xx_rtc = pdev->dev.platform_data; - struct resource *res; - - /* cleanup sysfs */ - device_remove_file(&pdev->dev, &dev_attr_comp_delete); - device_remove_file(&pdev->dev, &dev_attr_comp_preload); + sysfs_remove_group(&pdev->dev.kobj, &ep93xx_rtc_sysfs_files); + platform_set_drvdata(pdev, NULL); rtc_device_unregister(rtc); - - iounmap(ep93xx_rtc->mmio_base); pdev->dev.platform_data = NULL; - res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - release_mem_region(res->start, resource_size(res)); - - platform_set_drvdata(pdev, NULL); - return 0; } -- cgit v1.2.3 From b51e8293182764ca7b1a1bdb28a5c5dc60152c76 Mon Sep 17 00:00:00 2001 From: Uwe Kleine-König Date: Fri, 5 Mar 2010 13:44:21 -0800 Subject: rtc-pcf2123: move pcf2123_remove to .devexit.text MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The function pcf2123_remove is used only wrapped by __devexit_p so define it using __devexit. Signed-off-by: Uwe Kleine-König Signed-off-by: Alessandro Zummo Cc: Christian Pellegrin Cc: Chris Verges Cc: Paul Gortmaker Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/rtc/rtc-pcf2123.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/rtc') diff --git a/drivers/rtc/rtc-pcf2123.c b/drivers/rtc/rtc-pcf2123.c index e75df9d50e27..2ceb365533b2 100644 --- a/drivers/rtc/rtc-pcf2123.c +++ b/drivers/rtc/rtc-pcf2123.c @@ -315,7 +315,7 @@ kfree_exit: return ret; } -static int pcf2123_remove(struct spi_device *spi) +static int __devexit pcf2123_remove(struct spi_device *spi) { struct pcf2123_plat_data *pdata = spi->dev.platform_data; int i; -- cgit v1.2.3 From 870a2761a8df7dea7449b4225c9babcf22c6ead4 Mon Sep 17 00:00:00 2001 From: Julia Lawall Date: Fri, 5 Mar 2010 13:44:23 -0800 Subject: rtc-at91sam9: Correct size given to memset Memset should be given the size of the structure, not the size of the pointer. The semantic patch that makes this change is as follows: (http://coccinelle.lip6.fr/) // @@ type T; T *x; expression E; @@ memset(x, E, sizeof( + * x)) // Signed-off-by: Julia Lawall Signed-off-by: Alessandro Zummo Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/rtc/rtc-at91sam9.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/rtc') diff --git a/drivers/rtc/rtc-at91sam9.c b/drivers/rtc/rtc-at91sam9.c index 86c61f143515..78a018b5c941 100644 --- a/drivers/rtc/rtc-at91sam9.c +++ b/drivers/rtc/rtc-at91sam9.c @@ -161,7 +161,7 @@ static int at91_rtc_readalarm(struct device *dev, struct rtc_wkalrm *alrm) if (offset == 0) return -EILSEQ; - memset(alrm, 0, sizeof(alrm)); + memset(alrm, 0, sizeof(*alrm)); if (alarm != ALARM_DISABLED && offset != 0) { rtc_time_to_tm(offset + alarm, tm); -- cgit v1.2.3 From 2e84067b6e557b0b85cdbceaf9a9189fc2c26536 Mon Sep 17 00:00:00 2001 From: Tobias Klauser Date: Fri, 5 Mar 2010 13:44:23 -0800 Subject: rtc-twl: Storage class should be before const qualifier The C99 specification states in section 6.11.5: The placement of a storage-class specifier other than at the beginning of the declaration specifiers in a declaration is an obsolescent feature. Signed-off-by: Tobias Klauser Signed-off-by: Alessandro Zummo Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/rtc/rtc-twl.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers/rtc') diff --git a/drivers/rtc/rtc-twl.c b/drivers/rtc/rtc-twl.c index c6a83a2a722c..ed1b86828124 100644 --- a/drivers/rtc/rtc-twl.c +++ b/drivers/rtc/rtc-twl.c @@ -57,7 +57,7 @@ enum { REG_RTC_COMP_LSB_REG, REG_RTC_COMP_MSB_REG, }; -const static u8 twl4030_rtc_reg_map[] = { +static const u8 twl4030_rtc_reg_map[] = { [REG_SECONDS_REG] = 0x00, [REG_MINUTES_REG] = 0x01, [REG_HOURS_REG] = 0x02, @@ -80,7 +80,7 @@ const static u8 twl4030_rtc_reg_map[] = { [REG_RTC_COMP_LSB_REG] = 0x10, [REG_RTC_COMP_MSB_REG] = 0x11, }; -const static u8 twl6030_rtc_reg_map[] = { +static const u8 twl6030_rtc_reg_map[] = { [REG_SECONDS_REG] = 0x00, [REG_MINUTES_REG] = 0x01, [REG_HOURS_REG] = 0x02, -- cgit v1.2.3 From 2a7a06a0cdd86d572e91657603180da5992be6d3 Mon Sep 17 00:00:00 2001 From: Aaro Koskinen Date: Fri, 5 Mar 2010 13:44:24 -0800 Subject: rtc-core: fix memory leak The idr should be destroyed when the module is unloaded. Found with kmemleak. Signed-off-by: Aaro Koskinen Cc: Alessandro Zummo Cc: stable Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/rtc/class.c | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers/rtc') diff --git a/drivers/rtc/class.c b/drivers/rtc/class.c index be5a6b73e601..40845c7e9322 100644 --- a/drivers/rtc/class.c +++ b/drivers/rtc/class.c @@ -226,6 +226,7 @@ static void __exit rtc_exit(void) { rtc_dev_exit(); class_destroy(rtc_class); + idr_destroy(&rtc_idr); } subsys_initcall(rtc_init); -- cgit v1.2.3 From 4dd4dd655cedb7c5c0bf45bc1d012ebbe21e8319 Mon Sep 17 00:00:00 2001 From: Uwe Kleine-König Date: Fri, 5 Mar 2010 13:44:28 -0800 Subject: rtc/mc13783: don't use deprecated mc13783 API calls MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit mc13783_ackirq, mc13783_unmask and mc13783_mask are deprecated, use the drop in replacements with the nicer names. Signed-off-by: Uwe Kleine-König Cc: Alessandro Zummo Cc: Paul Gortmaker Cc: Valentin Longchamp Cc: Sascha Hauer Cc: Samuel Ortiz Cc: Dmitry Torokhov Cc: Luotao Fu Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/rtc/rtc-mc13783.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) (limited to 'drivers/rtc') diff --git a/drivers/rtc/rtc-mc13783.c b/drivers/rtc/rtc-mc13783.c index 850f983c039c..0a978a0e40fc 100644 --- a/drivers/rtc/rtc-mc13783.c +++ b/drivers/rtc/rtc-mc13783.c @@ -101,11 +101,11 @@ static int mc13783_rtc_set_mmss(struct device *dev, unsigned long secs) if (unlikely(ret)) goto out; - ret = mc13783_ackirq(priv->mc13783, MC13783_IRQ_RTCRST); + ret = mc13783_irq_ack(priv->mc13783, MC13783_IRQ_RTCRST); if (unlikely(ret)) goto out; - ret = mc13783_unmask(priv->mc13783, MC13783_IRQ_RTCRST); + ret = mc13783_irq_unmask(priv->mc13783, MC13783_IRQ_RTCRST); out: priv->valid = !ret; @@ -123,7 +123,7 @@ static irqreturn_t mc13783_rtc_update_handler(int irq, void *dev) rtc_update_irq(priv->rtc, 1, RTC_IRQF | RTC_UF); - mc13783_ackirq(mc13783, irq); + mc13783_irq_ack(mc13783, irq); return IRQ_HANDLED; } @@ -138,7 +138,7 @@ static int mc13783_rtc_update_irq_enable(struct device *dev, if (!priv->valid) goto out; - ret = (enabled ? mc13783_unmask : mc13783_mask)(priv->mc13783, + ret = (enabled ? mc13783_irq_unmask : mc13783_irq_mask)(priv->mc13783, MC13783_IRQ_1HZ); out: mc13783_unlock(priv->mc13783); @@ -160,7 +160,7 @@ static irqreturn_t mc13783_rtc_reset_handler(int irq, void *dev) dev_dbg(&priv->rtc->dev, "RTCRST\n"); priv->valid = 0; - mc13783_mask(mc13783, irq); + mc13783_irq_mask(mc13783, irq); return IRQ_HANDLED; } -- cgit v1.2.3 From 4c014e872e02baa5b0bde38b2b2867ccf1f9df76 Mon Sep 17 00:00:00 2001 From: Uwe Kleine-König Date: Fri, 5 Mar 2010 13:44:30 -0800 Subject: rtc/mc13783: protect rtc {,un}registration by mc13783 lock MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This is to protect from interrupt handlers using an unregistered rtc device. To assert that the reset irq is considered now before the rtc is registered the corresponding status is checked before. Signed-off-by: Uwe Kleine-König Cc: Alessandro Zummo Cc: Paul Gortmaker Cc: Valentin Longchamp Cc: Sascha Hauer Cc: Samuel Ortiz Cc: Dmitry Torokhov Cc: Luotao Fu Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/rtc/rtc-mc13783.c | 25 ++++++++++++++----------- 1 file changed, 14 insertions(+), 11 deletions(-) (limited to 'drivers/rtc') diff --git a/drivers/rtc/rtc-mc13783.c b/drivers/rtc/rtc-mc13783.c index 0a978a0e40fc..6a36201178a8 100644 --- a/drivers/rtc/rtc-mc13783.c +++ b/drivers/rtc/rtc-mc13783.c @@ -169,6 +169,7 @@ static int __devinit mc13783_rtc_probe(struct platform_device *pdev) { int ret; struct mc13783_rtc *priv; + int rtcrst_pending; priv = kzalloc(sizeof(*priv), GFP_KERNEL); if (!priv) @@ -177,8 +178,6 @@ static int __devinit mc13783_rtc_probe(struct platform_device *pdev) priv->mc13783 = dev_get_drvdata(pdev->dev.parent); platform_set_drvdata(pdev, priv); - priv->valid = 1; - mc13783_lock(priv->mc13783); ret = mc13783_irq_request(priv->mc13783, MC13783_IRQ_RTCRST, @@ -186,33 +185,37 @@ static int __devinit mc13783_rtc_probe(struct platform_device *pdev) if (ret) goto err_reset_irq_request; + ret = mc13783_irq_status(priv->mc13783, MC13783_IRQ_RTCRST, + NULL, &rtcrst_pending); + if (ret) + goto err_reset_irq_status; + + priv->valid = !rtcrst_pending; + ret = mc13783_irq_request_nounmask(priv->mc13783, MC13783_IRQ_1HZ, mc13783_rtc_update_handler, DRIVER_NAME, priv); if (ret) goto err_update_irq_request; - mc13783_unlock(priv->mc13783); - priv->rtc = rtc_device_register(pdev->name, &pdev->dev, &mc13783_rtc_ops, THIS_MODULE); - if (IS_ERR(priv->rtc)) { ret = PTR_ERR(priv->rtc); - mc13783_lock(priv->mc13783); - mc13783_irq_free(priv->mc13783, MC13783_IRQ_1HZ, priv); err_update_irq_request: +err_reset_irq_status: + mc13783_irq_free(priv->mc13783, MC13783_IRQ_RTCRST, priv); err_reset_irq_request: - mc13783_unlock(priv->mc13783); - platform_set_drvdata(pdev, NULL); kfree(priv); } + mc13783_unlock(priv->mc13783); + return ret; } @@ -220,10 +223,10 @@ static int __devexit mc13783_rtc_remove(struct platform_device *pdev) { struct mc13783_rtc *priv = platform_get_drvdata(pdev); - rtc_device_unregister(priv->rtc); - mc13783_lock(priv->mc13783); + rtc_device_unregister(priv->rtc); + mc13783_irq_free(priv->mc13783, MC13783_IRQ_1HZ, priv); mc13783_irq_free(priv->mc13783, MC13783_IRQ_RTCRST, priv); -- cgit v1.2.3 From 9407351d7cce01a9ada942f00201e92e2541d9cb Mon Sep 17 00:00:00 2001 From: Uwe Kleine-König Date: Fri, 5 Mar 2010 13:44:30 -0800 Subject: rtc/mc13783: implement alarm MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Uwe Kleine-König Cc: Alessandro Zummo Cc: Paul Gortmaker Cc: Valentin Longchamp Cc: Sascha Hauer Cc: Samuel Ortiz Cc: Dmitry Torokhov Cc: Luotao Fu Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/rtc/rtc-mc13783.c | 185 ++++++++++++++++++++++++++++++++++++++++++---- 1 file changed, 172 insertions(+), 13 deletions(-) (limited to 'drivers/rtc') diff --git a/drivers/rtc/rtc-mc13783.c b/drivers/rtc/rtc-mc13783.c index 6a36201178a8..d60c81b7b693 100644 --- a/drivers/rtc/rtc-mc13783.c +++ b/drivers/rtc/rtc-mc13783.c @@ -28,6 +28,34 @@ struct mc13783_rtc { int valid; }; +static int mc13783_rtc_irq_enable_unlocked(struct device *dev, + unsigned int enabled, int irq) +{ + struct mc13783_rtc *priv = dev_get_drvdata(dev); + int (*func)(struct mc13783 *mc13783, int irq); + + if (!priv->valid) + return -ENODATA; + + func = enabled ? mc13783_irq_unmask : mc13783_irq_mask; + return func(priv->mc13783, irq); +} + +static int mc13783_rtc_irq_enable(struct device *dev, + unsigned int enabled, int irq) +{ + struct mc13783_rtc *priv = dev_get_drvdata(dev); + int ret; + + mc13783_lock(priv->mc13783); + + ret = mc13783_rtc_irq_enable_unlocked(dev, enabled, irq); + + mc13783_unlock(priv->mc13783); + + return ret; +} + static int mc13783_rtc_read_time(struct device *dev, struct rtc_time *tm) { struct mc13783_rtc *priv = dev_get_drvdata(dev); @@ -78,6 +106,7 @@ static int mc13783_rtc_set_mmss(struct device *dev, unsigned long secs) { struct mc13783_rtc *priv = dev_get_drvdata(dev); unsigned int seconds, days; + unsigned int alarmseconds; int ret; seconds = secs % 86400; @@ -86,7 +115,22 @@ static int mc13783_rtc_set_mmss(struct device *dev, unsigned long secs) mc13783_lock(priv->mc13783); /* - * first write seconds=0 to prevent a day switch between writing days + * temporarily invalidate alarm to prevent triggering it when the day is + * already updated while the time isn't yet. + */ + ret = mc13783_reg_read(priv->mc13783, MC13783_RTCTODA, &alarmseconds); + if (unlikely(ret)) + goto out; + + if (alarmseconds < 86400) { + ret = mc13783_reg_write(priv->mc13783, + MC13783_RTCTODA, 0x1ffff); + if (unlikely(ret)) + goto out; + } + + /* + * write seconds=0 to prevent a day switch between writing days * and seconds below */ ret = mc13783_reg_write(priv->mc13783, MC13783_RTCTOD, 0); @@ -101,6 +145,14 @@ static int mc13783_rtc_set_mmss(struct device *dev, unsigned long secs) if (unlikely(ret)) goto out; + /* restore alarm */ + if (alarmseconds < 86400) { + ret = mc13783_reg_write(priv->mc13783, + MC13783_RTCTODA, alarmseconds); + if (unlikely(ret)) + goto out; + } + ret = mc13783_irq_ack(priv->mc13783, MC13783_IRQ_RTCRST); if (unlikely(ret)) goto out; @@ -114,6 +166,107 @@ out: return ret; } +static int mc13783_rtc_read_alarm(struct device *dev, struct rtc_wkalrm *alarm) +{ + struct mc13783_rtc *priv = dev_get_drvdata(dev); + unsigned seconds, days; + unsigned long s1970; + int enabled, pending; + int ret; + + mc13783_lock(priv->mc13783); + + ret = mc13783_reg_read(priv->mc13783, MC13783_RTCTODA, &seconds); + if (unlikely(ret)) + goto out; + if (seconds >= 86400) { + ret = -ENODATA; + goto out; + } + + ret = mc13783_reg_read(priv->mc13783, MC13783_RTCDAY, &days); + if (unlikely(ret)) + goto out; + + ret = mc13783_irq_status(priv->mc13783, MC13783_IRQ_TODA, + &enabled, &pending); + +out: + mc13783_unlock(priv->mc13783); + + if (ret) + return ret; + + alarm->enabled = enabled; + alarm->pending = pending; + + s1970 = days * 86400 + seconds; + + rtc_time_to_tm(s1970, &alarm->time); + dev_dbg(dev, "%s: %lu\n", __func__, s1970); + + return 0; +} + +static int mc13783_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alarm) +{ + struct mc13783_rtc *priv = dev_get_drvdata(dev); + unsigned long s1970; + unsigned seconds, days; + int ret; + + mc13783_lock(priv->mc13783); + + /* disable alarm to prevent false triggering */ + ret = mc13783_reg_write(priv->mc13783, MC13783_RTCTODA, 0x1ffff); + if (unlikely(ret)) + goto out; + + ret = mc13783_irq_ack(priv->mc13783, MC13783_IRQ_TODA); + if (unlikely(ret)) + goto out; + + ret = rtc_tm_to_time(&alarm->time, &s1970); + if (unlikely(ret)) + goto out; + + dev_dbg(dev, "%s: o%2.s %lu\n", __func__, alarm->enabled ? "n" : "ff", + s1970); + + ret = mc13783_rtc_irq_enable_unlocked(dev, alarm->enabled, + MC13783_IRQ_TODA); + if (unlikely(ret)) + goto out; + + seconds = s1970 % 86400; + days = s1970 / 86400; + + ret = mc13783_reg_write(priv->mc13783, MC13783_RTCDAYA, days); + if (unlikely(ret)) + goto out; + + ret = mc13783_reg_write(priv->mc13783, MC13783_RTCTODA, seconds); + +out: + mc13783_unlock(priv->mc13783); + + return ret; +} + +static irqreturn_t mc13783_rtc_alarm_handler(int irq, void *dev) +{ + struct mc13783_rtc *priv = dev; + struct mc13783 *mc13783 = priv->mc13783; + + dev_dbg(&priv->rtc->dev, "Alarm\n"); + + rtc_update_irq(priv->rtc, 1, RTC_IRQF | RTC_AF); + + mc13783_irq_ack(mc13783, irq); + + return IRQ_HANDLED; +} + static irqreturn_t mc13783_rtc_update_handler(int irq, void *dev) { struct mc13783_rtc *priv = dev; @@ -131,24 +284,21 @@ static irqreturn_t mc13783_rtc_update_handler(int irq, void *dev) static int mc13783_rtc_update_irq_enable(struct device *dev, unsigned int enabled) { - struct mc13783_rtc *priv = dev_get_drvdata(dev); - int ret = -ENODATA; - - mc13783_lock(priv->mc13783); - if (!priv->valid) - goto out; - - ret = (enabled ? mc13783_irq_unmask : mc13783_irq_mask)(priv->mc13783, - MC13783_IRQ_1HZ); -out: - mc13783_unlock(priv->mc13783); + return mc13783_rtc_irq_enable(dev, enabled, MC13783_IRQ_1HZ); +} - return ret; +static int mc13783_rtc_alarm_irq_enable(struct device *dev, + unsigned int enabled) +{ + return mc13783_rtc_irq_enable(dev, enabled, MC13783_IRQ_TODA); } static const struct rtc_class_ops mc13783_rtc_ops = { .read_time = mc13783_rtc_read_time, .set_mmss = mc13783_rtc_set_mmss, + .read_alarm = mc13783_rtc_read_alarm, + .set_alarm = mc13783_rtc_set_alarm, + .alarm_irq_enable = mc13783_rtc_alarm_irq_enable, .update_irq_enable = mc13783_rtc_update_irq_enable, }; @@ -197,11 +347,19 @@ static int __devinit mc13783_rtc_probe(struct platform_device *pdev) if (ret) goto err_update_irq_request; + ret = mc13783_irq_request_nounmask(priv->mc13783, MC13783_IRQ_TODA, + mc13783_rtc_alarm_handler, DRIVER_NAME, priv); + if (ret) + goto err_alarm_irq_request; + priv->rtc = rtc_device_register(pdev->name, &pdev->dev, &mc13783_rtc_ops, THIS_MODULE); if (IS_ERR(priv->rtc)) { ret = PTR_ERR(priv->rtc); + mc13783_irq_free(priv->mc13783, MC13783_IRQ_TODA, priv); +err_alarm_irq_request: + mc13783_irq_free(priv->mc13783, MC13783_IRQ_1HZ, priv); err_update_irq_request: @@ -227,6 +385,7 @@ static int __devexit mc13783_rtc_remove(struct platform_device *pdev) rtc_device_unregister(priv->rtc); + mc13783_irq_free(priv->mc13783, MC13783_IRQ_TODA, priv); mc13783_irq_free(priv->mc13783, MC13783_IRQ_1HZ, priv); mc13783_irq_free(priv->mc13783, MC13783_IRQ_RTCRST, priv); -- cgit v1.2.3 From 5a98c04d78c896d52baef20ffc11f6d1ba6eb786 Mon Sep 17 00:00:00 2001 From: James Hogan Date: Fri, 5 Mar 2010 13:44:31 -0800 Subject: rtc-coh901331: fix braces in resume code The else part of the if statement is indented but does not have braces around it. It clearly should since it uses clk_enable and clk_disable which are supposed to balance. Signed-off-by: James Hogan Acked-by: Linus Walleij Acked-by: Alessandro Zummo Cc: Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/rtc/rtc-coh901331.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) (limited to 'drivers/rtc') diff --git a/drivers/rtc/rtc-coh901331.c b/drivers/rtc/rtc-coh901331.c index 03ea530981d1..44c4399ee714 100644 --- a/drivers/rtc/rtc-coh901331.c +++ b/drivers/rtc/rtc-coh901331.c @@ -271,12 +271,13 @@ static int coh901331_resume(struct platform_device *pdev) { struct coh901331_port *rtap = dev_get_drvdata(&pdev->dev); - if (device_may_wakeup(&pdev->dev)) + if (device_may_wakeup(&pdev->dev)) { disable_irq_wake(rtap->irq); - else + } else { clk_enable(rtap->clk); writel(rtap->irqmaskstore, rtap->virtbase + COH901331_IRQ_MASK); clk_disable(rtap->clk); + } return 0; } #else -- cgit v1.2.3 From f99344fc69c3df46786a39ea4283a4175ea40b3f Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Tue, 5 Jan 2010 13:59:07 +0000 Subject: mfd: Add a data argument to the WM8350 IRQ free function To better match genirq. Signed-off-by: Mark Brown Signed-off-by: Samuel Ortiz --- drivers/mfd/wm8350-irq.c | 2 +- drivers/power/wm8350_power.c | 24 ++++++++++++------------ drivers/regulator/wm8350-regulator.c | 2 +- drivers/rtc/rtc-wm8350.c | 4 ++-- include/linux/mfd/wm8350/core.h | 3 ++- sound/soc/codecs/wm8350.c | 4 ++-- 6 files changed, 20 insertions(+), 19 deletions(-) (limited to 'drivers/rtc') diff --git a/drivers/mfd/wm8350-irq.c b/drivers/mfd/wm8350-irq.c index 9025f29e2707..655836bc69a0 100644 --- a/drivers/mfd/wm8350-irq.c +++ b/drivers/mfd/wm8350-irq.c @@ -451,7 +451,7 @@ int wm8350_register_irq(struct wm8350 *wm8350, int irq, } EXPORT_SYMBOL_GPL(wm8350_register_irq); -int wm8350_free_irq(struct wm8350 *wm8350, int irq) +int wm8350_free_irq(struct wm8350 *wm8350, int irq, void *data) { if (irq < 0 || irq >= WM8350_NUM_IRQ) return -EINVAL; diff --git a/drivers/power/wm8350_power.c b/drivers/power/wm8350_power.c index ad4f071e1287..3839a5e1c4a7 100644 --- a/drivers/power/wm8350_power.c +++ b/drivers/power/wm8350_power.c @@ -428,18 +428,18 @@ static void wm8350_init_charger(struct wm8350 *wm8350) static void free_charger_irq(struct wm8350 *wm8350) { - wm8350_free_irq(wm8350, WM8350_IRQ_CHG_BAT_HOT); - wm8350_free_irq(wm8350, WM8350_IRQ_CHG_BAT_COLD); - wm8350_free_irq(wm8350, WM8350_IRQ_CHG_BAT_FAIL); - wm8350_free_irq(wm8350, WM8350_IRQ_CHG_TO); - wm8350_free_irq(wm8350, WM8350_IRQ_CHG_END); - wm8350_free_irq(wm8350, WM8350_IRQ_CHG_START); - wm8350_free_irq(wm8350, WM8350_IRQ_CHG_VBATT_LT_3P9); - wm8350_free_irq(wm8350, WM8350_IRQ_CHG_VBATT_LT_3P1); - wm8350_free_irq(wm8350, WM8350_IRQ_CHG_VBATT_LT_2P85); - wm8350_free_irq(wm8350, WM8350_IRQ_EXT_USB_FB); - wm8350_free_irq(wm8350, WM8350_IRQ_EXT_WALL_FB); - wm8350_free_irq(wm8350, WM8350_IRQ_EXT_BAT_FB); + wm8350_free_irq(wm8350, WM8350_IRQ_CHG_BAT_HOT, wm8350); + wm8350_free_irq(wm8350, WM8350_IRQ_CHG_BAT_COLD, wm8350); + wm8350_free_irq(wm8350, WM8350_IRQ_CHG_BAT_FAIL, wm8350); + wm8350_free_irq(wm8350, WM8350_IRQ_CHG_TO, wm8350); + wm8350_free_irq(wm8350, WM8350_IRQ_CHG_END, wm8350); + wm8350_free_irq(wm8350, WM8350_IRQ_CHG_START, wm8350); + wm8350_free_irq(wm8350, WM8350_IRQ_CHG_VBATT_LT_3P9, wm8350); + wm8350_free_irq(wm8350, WM8350_IRQ_CHG_VBATT_LT_3P1, wm8350); + wm8350_free_irq(wm8350, WM8350_IRQ_CHG_VBATT_LT_2P85, wm8350); + wm8350_free_irq(wm8350, WM8350_IRQ_EXT_USB_FB, wm8350); + wm8350_free_irq(wm8350, WM8350_IRQ_EXT_WALL_FB, wm8350); + wm8350_free_irq(wm8350, WM8350_IRQ_EXT_BAT_FB, wm8350); } static __devinit int wm8350_power_probe(struct platform_device *pdev) diff --git a/drivers/regulator/wm8350-regulator.c b/drivers/regulator/wm8350-regulator.c index 94227dd6ba7b..723cd1fb4867 100644 --- a/drivers/regulator/wm8350-regulator.c +++ b/drivers/regulator/wm8350-regulator.c @@ -1453,7 +1453,7 @@ static int wm8350_regulator_remove(struct platform_device *pdev) struct regulator_dev *rdev = platform_get_drvdata(pdev); struct wm8350 *wm8350 = rdev_get_drvdata(rdev); - wm8350_free_irq(wm8350, wm8350_reg[pdev->id].irq); + wm8350_free_irq(wm8350, wm8350_reg[pdev->id].irq, rdev); regulator_unregister(rdev); diff --git a/drivers/rtc/rtc-wm8350.c b/drivers/rtc/rtc-wm8350.c index f1e440521c54..a5512f515998 100644 --- a/drivers/rtc/rtc-wm8350.c +++ b/drivers/rtc/rtc-wm8350.c @@ -478,8 +478,8 @@ static int __devexit wm8350_rtc_remove(struct platform_device *pdev) struct wm8350 *wm8350 = platform_get_drvdata(pdev); struct wm8350_rtc *wm_rtc = &wm8350->rtc; - wm8350_free_irq(wm8350, WM8350_IRQ_RTC_SEC); - wm8350_free_irq(wm8350, WM8350_IRQ_RTC_ALM); + wm8350_free_irq(wm8350, WM8350_IRQ_RTC_SEC, wm8350); + wm8350_free_irq(wm8350, WM8350_IRQ_RTC_ALM, wm8350); rtc_device_unregister(wm_rtc->rtc); diff --git a/include/linux/mfd/wm8350/core.h b/include/linux/mfd/wm8350/core.h index 43868899bf49..8883125ddea1 100644 --- a/include/linux/mfd/wm8350/core.h +++ b/include/linux/mfd/wm8350/core.h @@ -680,7 +680,8 @@ int wm8350_block_write(struct wm8350 *wm8350, int reg, int size, u16 *src); int wm8350_register_irq(struct wm8350 *wm8350, int irq, irq_handler_t handler, unsigned long flags, const char *name, void *data); -int wm8350_free_irq(struct wm8350 *wm8350, int irq); +int wm8350_free_irq(struct wm8350 *wm8350, int irq, void *data); + int wm8350_mask_irq(struct wm8350 *wm8350, int irq); int wm8350_unmask_irq(struct wm8350 *wm8350, int irq); int wm8350_irq_init(struct wm8350 *wm8350, int irq, diff --git a/sound/soc/codecs/wm8350.c b/sound/soc/codecs/wm8350.c index 718ef912e758..079bf745bf05 100644 --- a/sound/soc/codecs/wm8350.c +++ b/sound/soc/codecs/wm8350.c @@ -1521,8 +1521,8 @@ static int wm8350_remove(struct platform_device *pdev) WM8350_JDL_ENA | WM8350_JDR_ENA); wm8350_clear_bits(wm8350, WM8350_POWER_MGMT_4, WM8350_TOCLK_ENA); - wm8350_free_irq(wm8350, WM8350_IRQ_CODEC_JCK_DET_L); - wm8350_free_irq(wm8350, WM8350_IRQ_CODEC_JCK_DET_R); + wm8350_free_irq(wm8350, WM8350_IRQ_CODEC_JCK_DET_L, priv); + wm8350_free_irq(wm8350, WM8350_IRQ_CODEC_JCK_DET_R, priv); priv->hpl.jack = NULL; priv->hpr.jack = NULL; -- cgit v1.2.3 From 29c71b138c83c8191f1f7e46fcc28b9d6bc8a5dd Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Tue, 5 Jan 2010 13:59:08 +0000 Subject: rtc: Suppress duplicate enable/disable of WM8350 update interrupt Unlike the wm8350-custom code genirq nests enable and disable calls so we can't just unconditionally mask or unmask the interrupt, we need to remember the state we set and only mask or unmask when there is a real change. Signed-off-by: Mark Brown Acked-by: Alessandro Zummo Cc: rtc-linux@googlegroups.com Signed-off-by: Samuel Ortiz --- drivers/rtc/rtc-wm8350.c | 7 +++++++ include/linux/mfd/wm8350/rtc.h | 1 + 2 files changed, 8 insertions(+) (limited to 'drivers/rtc') diff --git a/drivers/rtc/rtc-wm8350.c b/drivers/rtc/rtc-wm8350.c index a5512f515998..3d0dc76b38af 100644 --- a/drivers/rtc/rtc-wm8350.c +++ b/drivers/rtc/rtc-wm8350.c @@ -307,11 +307,18 @@ static int wm8350_rtc_update_irq_enable(struct device *dev, { struct wm8350 *wm8350 = dev_get_drvdata(dev); + /* Suppress duplicate changes since genirq nests enable and + * disable calls. */ + if (enabled == wm8350->rtc.update_enabled) + return 0; + if (enabled) wm8350_unmask_irq(wm8350, WM8350_IRQ_RTC_SEC); else wm8350_mask_irq(wm8350, WM8350_IRQ_RTC_SEC); + wm8350->rtc.update_enabled = enabled; + return 0; } diff --git a/include/linux/mfd/wm8350/rtc.h b/include/linux/mfd/wm8350/rtc.h index 24add2bef6c9..ebd72ffc62d1 100644 --- a/include/linux/mfd/wm8350/rtc.h +++ b/include/linux/mfd/wm8350/rtc.h @@ -263,6 +263,7 @@ struct wm8350_rtc { struct platform_device *pdev; struct rtc_device *rtc; int alarm_enabled; /* used over suspend/resume */ + int update_enabled; }; #endif -- cgit v1.2.3 From a39069f6ce6500a5ca39e534108247f25169d8e0 Mon Sep 17 00:00:00 2001 From: Haojian Zhuang Date: Mon, 25 Jan 2010 06:30:29 -0500 Subject: rtc: Enable rtc in max8925 MAX8925 is a PMIC that contains RTC component. Signed-off-by: Haojian Zhuang Signed-off-by: Samuel Ortiz --- drivers/rtc/Kconfig | 10 ++ drivers/rtc/Makefile | 1 + drivers/rtc/rtc-max8925.c | 314 ++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 325 insertions(+) create mode 100644 drivers/rtc/rtc-max8925.c (limited to 'drivers/rtc') diff --git a/drivers/rtc/Kconfig b/drivers/rtc/Kconfig index 2bb8a8b7ffaf..6a1303759432 100644 --- a/drivers/rtc/Kconfig +++ b/drivers/rtc/Kconfig @@ -175,6 +175,16 @@ config RTC_DRV_MAX6900 This driver can also be built as a module. If so, the module will be called rtc-max6900. +config RTC_DRV_MAX8925 + tristate "Maxim MAX8925" + depends on MFD_MAX8925 + help + If you say yes here you will get support for the + RTC of Maxim MAX8925 PMIC. + + This driver can also be built as a module. If so, the module + will be called rtc-max8925. + config RTC_DRV_RS5C372 tristate "Ricoh R2025S/D, RS5C372A/B, RV5C386, RV5C387A" help diff --git a/drivers/rtc/Makefile b/drivers/rtc/Makefile index b7148afb8f55..44ef194a9573 100644 --- a/drivers/rtc/Makefile +++ b/drivers/rtc/Makefile @@ -52,6 +52,7 @@ obj-$(CONFIG_RTC_DRV_M48T59) += rtc-m48t59.o obj-$(CONFIG_RTC_DRV_M48T86) += rtc-m48t86.o obj-$(CONFIG_RTC_MXC) += rtc-mxc.o obj-$(CONFIG_RTC_DRV_MAX6900) += rtc-max6900.o +obj-$(CONFIG_RTC_DRV_MAX8925) += rtc-max8925.o obj-$(CONFIG_RTC_DRV_MAX6902) += rtc-max6902.o obj-$(CONFIG_RTC_DRV_MC13783) += rtc-mc13783.o obj-$(CONFIG_RTC_DRV_MSM6242) += rtc-msm6242.o diff --git a/drivers/rtc/rtc-max8925.c b/drivers/rtc/rtc-max8925.c new file mode 100644 index 000000000000..acdbb1760187 --- /dev/null +++ b/drivers/rtc/rtc-max8925.c @@ -0,0 +1,314 @@ +/* + * RTC driver for Maxim MAX8925 + * + * Copyright (C) 2009-2010 Marvell International Ltd. + * Haojian Zhuang + * + * 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 + +enum { + RTC_SEC = 0, + RTC_MIN, + RTC_HOUR, + RTC_WEEKDAY, + RTC_DATE, + RTC_MONTH, + RTC_YEAR1, + RTC_YEAR2, +}; + +#define MAX8925_RTC_SEC 0x00 +#define MAX8925_RTC_MIN 0x01 +#define MAX8925_RTC_HOUR 0x02 +#define MAX8925_RTC_WEEKDAY 0x03 +#define MAX8925_RTC_DATE 0x04 +#define MAX8925_RTC_MONTH 0x05 +#define MAX8925_RTC_YEAR1 0x06 +#define MAX8925_RTC_YEAR2 0x07 +#define MAX8925_ALARM0_SEC 0x08 +#define MAX8925_ALARM0_MIN 0x09 +#define MAX8925_ALARM0_HOUR 0x0a +#define MAX8925_ALARM0_WEEKDAY 0x0b +#define MAX8925_ALARM0_DATE 0x0c +#define MAX8925_ALARM0_MON 0x0d +#define MAX8925_ALARM0_YEAR1 0x0e +#define MAX8925_ALARM0_YEAR2 0x0f +#define MAX8925_ALARM1_SEC 0x10 +#define MAX8925_ALARM1_MIN 0x11 +#define MAX8925_ALARM1_HOUR 0x12 +#define MAX8925_ALARM1_WEEKDAY 0x13 +#define MAX8925_ALARM1_DATE 0x14 +#define MAX8925_ALARM1_MON 0x15 +#define MAX8925_ALARM1_YEAR1 0x16 +#define MAX8925_ALARM1_YEAR2 0x17 +#define MAX8925_RTC_CNTL 0x1b +#define MAX8925_RTC_STATUS 0x20 + +#define TIME_NUM 8 +#define ALARM_1SEC (1 << 7) +#define HOUR_12 (1 << 7) +#define HOUR_AM_PM (1 << 5) +#define ALARM0_IRQ (1 << 3) +#define ALARM1_IRQ (1 << 2) +#define ALARM0_STATUS (1 << 2) +#define ALARM1_STATUS (1 << 1) + + +struct max8925_rtc_info { + struct rtc_device *rtc_dev; + struct max8925_chip *chip; + struct i2c_client *rtc; + struct device *dev; +}; + +static irqreturn_t rtc_update_handler(int irq, void *data) +{ + struct max8925_rtc_info *info = (struct max8925_rtc_info *)data; + + /* disable ALARM0 except for 1SEC alarm */ + max8925_set_bits(info->rtc, MAX8925_ALARM0_CNTL, 0x7f, 0); + rtc_update_irq(info->rtc_dev, 1, RTC_IRQF | RTC_AF); + return IRQ_HANDLED; +} + +static int tm_calc(struct rtc_time *tm, unsigned char *buf, int len) +{ + if (len < TIME_NUM) + return -EINVAL; + tm->tm_year = (buf[RTC_YEAR2] >> 4) * 1000 + + (buf[RTC_YEAR2] & 0xf) * 100 + + (buf[RTC_YEAR1] >> 4) * 10 + + (buf[RTC_YEAR1] & 0xf); + tm->tm_year -= 1900; + tm->tm_mon = ((buf[RTC_MONTH] >> 4) & 0x01) * 10 + + (buf[RTC_MONTH] & 0x0f); + tm->tm_mday = ((buf[RTC_DATE] >> 4) & 0x03) * 10 + + (buf[RTC_DATE] & 0x0f); + tm->tm_wday = buf[RTC_WEEKDAY] & 0x07; + if (buf[RTC_HOUR] & HOUR_12) { + tm->tm_hour = ((buf[RTC_HOUR] >> 4) & 0x1) * 10 + + (buf[RTC_HOUR] & 0x0f); + if (buf[RTC_HOUR] & HOUR_AM_PM) + tm->tm_hour += 12; + } else + tm->tm_hour = ((buf[RTC_HOUR] >> 4) & 0x03) * 10 + + (buf[RTC_HOUR] & 0x0f); + tm->tm_min = ((buf[RTC_MIN] >> 4) & 0x7) * 10 + + (buf[RTC_MIN] & 0x0f); + tm->tm_sec = ((buf[RTC_SEC] >> 4) & 0x7) * 10 + + (buf[RTC_SEC] & 0x0f); + return 0; +} + +static int data_calc(unsigned char *buf, struct rtc_time *tm, int len) +{ + unsigned char high, low; + + if (len < TIME_NUM) + return -EINVAL; + + high = (tm->tm_year + 1900) / 1000; + low = (tm->tm_year + 1900) / 100; + low = low - high * 10; + buf[RTC_YEAR2] = (high << 4) + low; + high = (tm->tm_year + 1900) / 10; + low = tm->tm_year + 1900; + low = low - high * 10; + high = high - (high / 10) * 10; + buf[RTC_YEAR1] = (high << 4) + low; + high = tm->tm_mon / 10; + low = tm->tm_mon; + low = low - high * 10; + buf[RTC_MONTH] = (high << 4) + low; + high = tm->tm_mday / 10; + low = tm->tm_mday; + low = low - high * 10; + buf[RTC_DATE] = (high << 4) + low; + buf[RTC_WEEKDAY] = tm->tm_wday; + high = tm->tm_hour / 10; + low = tm->tm_hour; + low = low - high * 10; + buf[RTC_HOUR] = (high << 4) + low; + high = tm->tm_min / 10; + low = tm->tm_min; + low = low - high * 10; + buf[RTC_MIN] = (high << 4) + low; + high = tm->tm_sec / 10; + low = tm->tm_sec; + low = low - high * 10; + buf[RTC_SEC] = (high << 4) + low; + return 0; +} + +static int max8925_rtc_read_time(struct device *dev, struct rtc_time *tm) +{ + struct max8925_rtc_info *info = dev_get_drvdata(dev); + unsigned char buf[TIME_NUM]; + int ret; + + ret = max8925_bulk_read(info->rtc, MAX8925_RTC_SEC, TIME_NUM, buf); + if (ret < 0) + goto out; + ret = tm_calc(tm, buf, TIME_NUM); +out: + return ret; +} + +static int max8925_rtc_set_time(struct device *dev, struct rtc_time *tm) +{ + struct max8925_rtc_info *info = dev_get_drvdata(dev); + unsigned char buf[TIME_NUM]; + int ret; + + ret = data_calc(buf, tm, TIME_NUM); + if (ret < 0) + goto out; + ret = max8925_bulk_write(info->rtc, MAX8925_RTC_SEC, TIME_NUM, buf); +out: + return ret; +} + +static int max8925_rtc_read_alarm(struct device *dev, struct rtc_wkalrm *alrm) +{ + struct max8925_rtc_info *info = dev_get_drvdata(dev); + unsigned char buf[TIME_NUM]; + int ret; + + ret = max8925_bulk_read(info->rtc, MAX8925_ALARM0_SEC, TIME_NUM, buf); + if (ret < 0) + goto out; + ret = tm_calc(&alrm->time, buf, TIME_NUM); + if (ret < 0) + goto out; + ret = max8925_reg_read(info->rtc, MAX8925_RTC_IRQ_MASK); + if (ret < 0) + goto out; + if ((ret & ALARM0_IRQ) == 0) + alrm->enabled = 1; + else + alrm->enabled = 0; + ret = max8925_reg_read(info->rtc, MAX8925_RTC_STATUS); + if (ret < 0) + goto out; + if (ret & ALARM0_STATUS) + alrm->pending = 1; + else + alrm->pending = 0; +out: + return ret; +} + +static int max8925_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alrm) +{ + struct max8925_rtc_info *info = dev_get_drvdata(dev); + unsigned char buf[TIME_NUM]; + int ret; + + ret = data_calc(buf, &alrm->time, TIME_NUM); + if (ret < 0) + goto out; + ret = max8925_bulk_write(info->rtc, MAX8925_ALARM0_SEC, TIME_NUM, buf); + if (ret < 0) + goto out; + /* only enable alarm on year/month/day/hour/min/sec */ + ret = max8925_reg_write(info->rtc, MAX8925_ALARM0_CNTL, 0x77); + if (ret < 0) + goto out; +out: + return ret; +} + +static const struct rtc_class_ops max8925_rtc_ops = { + .read_time = max8925_rtc_read_time, + .set_time = max8925_rtc_set_time, + .read_alarm = max8925_rtc_read_alarm, + .set_alarm = max8925_rtc_set_alarm, +}; + +static int __devinit max8925_rtc_probe(struct platform_device *pdev) +{ + struct max8925_chip *chip = dev_get_drvdata(pdev->dev.parent); + struct max8925_rtc_info *info; + int irq, ret; + + info = kzalloc(sizeof(struct max8925_rtc_info), GFP_KERNEL); + if (!info) + return -ENOMEM; + info->chip = chip; + info->rtc = chip->rtc; + info->dev = &pdev->dev; + irq = chip->irq_base + MAX8925_IRQ_RTC_ALARM0; + + ret = request_threaded_irq(irq, NULL, rtc_update_handler, + IRQF_ONESHOT, "rtc-alarm0", info); + if (ret < 0) { + dev_err(chip->dev, "Failed to request IRQ: #%d: %d\n", + irq, ret); + goto out_irq; + } + + info->rtc_dev = rtc_device_register("max8925-rtc", &pdev->dev, + &max8925_rtc_ops, THIS_MODULE); + ret = PTR_ERR(info->rtc_dev); + if (IS_ERR(info->rtc_dev)) { + dev_err(&pdev->dev, "Failed to register RTC device: %d\n", ret); + goto out_rtc; + } + + dev_set_drvdata(&pdev->dev, info); + platform_set_drvdata(pdev, info); + + return 0; +out_rtc: + free_irq(chip->irq_base + MAX8925_IRQ_RTC_ALARM0, info); +out_irq: + kfree(info); + return ret; +} + +static int __devexit max8925_rtc_remove(struct platform_device *pdev) +{ + struct max8925_rtc_info *info = platform_get_drvdata(pdev); + + if (info) { + free_irq(info->chip->irq_base + MAX8925_IRQ_RTC_ALARM0, info); + rtc_device_unregister(info->rtc_dev); + kfree(info); + } + return 0; +} + +static struct platform_driver max8925_rtc_driver = { + .driver = { + .name = "max8925-rtc", + .owner = THIS_MODULE, + }, + .probe = max8925_rtc_probe, + .remove = __devexit_p(max8925_rtc_remove), +}; + +static int __init max8925_rtc_init(void) +{ + return platform_driver_register(&max8925_rtc_driver); +} +module_init(max8925_rtc_init); + +static void __exit max8925_rtc_exit(void) +{ + platform_driver_unregister(&max8925_rtc_driver); +} +module_exit(max8925_rtc_exit); + +MODULE_DESCRIPTION("Maxim MAX8925 RTC driver"); +MODULE_AUTHOR("Haojian Zhuang "); +MODULE_LICENSE("GPL"); + -- cgit v1.2.3 From d0ab4a4d5094e5d17b103dc5073529a04f00a469 Mon Sep 17 00:00:00 2001 From: Uwe Kleine-König Date: Wed, 10 Mar 2010 15:20:35 -0800 Subject: rtc/hctosys: only claim the RTC provided the system time if it did MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Without this patch /sys/class/rtc/$CONFIG_RTC_HCTOSYS_DEVICE/hctosys contains a 1 (meaning "This rtc was used to initialize the system clock") even if reading the time at bootup failed. Moreover change error handling in rtc_hctosys() to use goto and so reduce the indention level. Signed-off-by: Uwe Kleine-König Cc: Paul Gortmaker Acked-by: Alessandro Zummo Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/rtc/hctosys.c | 59 ++++++++++++++++++++++++++++--------------------- drivers/rtc/rtc-sysfs.c | 5 +++-- include/linux/rtc.h | 6 +++++ 3 files changed, 43 insertions(+), 27 deletions(-) (limited to 'drivers/rtc') diff --git a/drivers/rtc/hctosys.c b/drivers/rtc/hctosys.c index 33c0e98243ee..bc90b091f195 100644 --- a/drivers/rtc/hctosys.c +++ b/drivers/rtc/hctosys.c @@ -22,48 +22,57 @@ * the best guess is to add 0.5s. */ +int rtc_hctosys_ret = -ENODEV; + static int __init rtc_hctosys(void) { - int err; + int err = -ENODEV; struct rtc_time tm; + struct timespec tv = { + .tv_nsec = NSEC_PER_SEC >> 1, + }; struct rtc_device *rtc = rtc_class_open(CONFIG_RTC_HCTOSYS_DEVICE); if (rtc == NULL) { - printk("%s: unable to open rtc device (%s)\n", + pr_err("%s: unable to open rtc device (%s)\n", __FILE__, CONFIG_RTC_HCTOSYS_DEVICE); - return -ENODEV; + goto err_open; } err = rtc_read_time(rtc, &tm); - if (err == 0) { - err = rtc_valid_tm(&tm); - if (err == 0) { - struct timespec tv; + if (err) { + dev_err(rtc->dev.parent, + "hctosys: unable to read the hardware clock\n"); + goto err_read; - tv.tv_nsec = NSEC_PER_SEC >> 1; + } - rtc_tm_to_time(&tm, &tv.tv_sec); + err = rtc_valid_tm(&tm); + if (err) { + dev_err(rtc->dev.parent, + "hctosys: invalid date/time\n"); + goto err_invalid; + } - do_settimeofday(&tv); + rtc_tm_to_time(&tm, &tv.tv_sec); - dev_info(rtc->dev.parent, - "setting system clock to " - "%d-%02d-%02d %02d:%02d:%02d UTC (%u)\n", - tm.tm_year + 1900, tm.tm_mon + 1, tm.tm_mday, - tm.tm_hour, tm.tm_min, tm.tm_sec, - (unsigned int) tv.tv_sec); - } - else - dev_err(rtc->dev.parent, - "hctosys: invalid date/time\n"); - } - else - dev_err(rtc->dev.parent, - "hctosys: unable to read the hardware clock\n"); + do_settimeofday(&tv); + dev_info(rtc->dev.parent, + "setting system clock to " + "%d-%02d-%02d %02d:%02d:%02d UTC (%u)\n", + tm.tm_year + 1900, tm.tm_mon + 1, tm.tm_mday, + tm.tm_hour, tm.tm_min, tm.tm_sec, + (unsigned int) tv.tv_sec); + +err_invalid: +err_read: rtc_class_close(rtc); - return 0; +err_open: + rtc_hctosys_ret = err; + + return err; } late_initcall(rtc_hctosys); diff --git a/drivers/rtc/rtc-sysfs.c b/drivers/rtc/rtc-sysfs.c index 7dd23a6fc825..380083ca572f 100644 --- a/drivers/rtc/rtc-sysfs.c +++ b/drivers/rtc/rtc-sysfs.c @@ -107,8 +107,9 @@ rtc_sysfs_show_hctosys(struct device *dev, struct device_attribute *attr, char *buf) { #ifdef CONFIG_RTC_HCTOSYS_DEVICE - if (strcmp(dev_name(&to_rtc_device(dev)->dev), - CONFIG_RTC_HCTOSYS_DEVICE) == 0) + if (rtc_hctosys_ret == 0 && + strcmp(dev_name(&to_rtc_device(dev)->dev), + CONFIG_RTC_HCTOSYS_DEVICE) == 0) return sprintf(buf, "1\n"); else #endif diff --git a/include/linux/rtc.h b/include/linux/rtc.h index 60f88a7fb13d..14dbc83ded20 100644 --- a/include/linux/rtc.h +++ b/include/linux/rtc.h @@ -238,6 +238,12 @@ static inline bool is_leap_year(unsigned int year) return (!(year % 4) && (year % 100)) || !(year % 400); } +#ifdef CONFIG_RTC_HCTOSYS +extern int rtc_hctosys_ret; +#else +#define rtc_hctosys_ret -ENODEV +#endif + #endif /* __KERNEL__ */ #endif /* _LINUX_RTC_H_ */ -- cgit v1.2.3 From f937331b3f92cb2f67bc81baa1b8cc5198c439e5 Mon Sep 17 00:00:00 2001 From: Wolfram Sang Date: Mon, 15 Mar 2010 01:29:41 +0100 Subject: init dynamic bin_attribute structures Commit 6992f5334995af474c2b58d010d08bc597f0f2fe ("sysfs: Use one lockdep class per sysfs attribute.") introduced this requirement. First, at25 was fixed manually. Then, other occurences were found with coccinelle and the following semantic patch. Results were reviewed and fixed up: @ init @ identifier struct_name, bin; @@ struct struct_name { ... struct bin_attribute bin; ... }; @ main extends init @ expression E; statement S; identifier name, err; @@ ( struct struct_name *name; | - struct struct_name *name = NULL; + struct struct_name *name; ) ... ( sysfs_bin_attr_init(&name->bin); | + sysfs_bin_attr_init(&name->bin); if (sysfs_create_bin_file(E, &name->bin)) S | + sysfs_bin_attr_init(&name->bin); err = sysfs_create_bin_file(E, &name->bin); ) Signed-off-by: Wolfram Sang Cc: Eric W. Biederman Signed-off-by: Linus Torvalds --- arch/mips/txx9/generic/setup.c | 1 + drivers/misc/eeprom/at25.c | 1 + drivers/rtc/rtc-ds1742.c | 1 + 3 files changed, 3 insertions(+) (limited to 'drivers/rtc') diff --git a/arch/mips/txx9/generic/setup.c b/arch/mips/txx9/generic/setup.c index 7174d830dd05..95184a0a1ae6 100644 --- a/arch/mips/txx9/generic/setup.c +++ b/arch/mips/txx9/generic/setup.c @@ -956,6 +956,7 @@ void __init txx9_sramc_init(struct resource *r) if (!dev->base) goto exit; dev->dev.cls = &txx9_sramc_sysdev_class; + sysfs_bin_attr_init(&dev->bindata_attr); dev->bindata_attr.attr.name = "bindata"; dev->bindata_attr.attr.mode = S_IRUSR | S_IWUSR; dev->bindata_attr.read = txx9_sram_read; diff --git a/drivers/misc/eeprom/at25.c b/drivers/misc/eeprom/at25.c index d902d81dde39..d194212a41f6 100644 --- a/drivers/misc/eeprom/at25.c +++ b/drivers/misc/eeprom/at25.c @@ -347,6 +347,7 @@ static int at25_probe(struct spi_device *spi) * that's sensitive for read and/or write, like ethernet addresses, * security codes, board-specific manufacturing calibrations, etc. */ + sysfs_bin_attr_init(&at25->bin); at25->bin.attr.name = "eeprom"; at25->bin.attr.mode = S_IRUSR; at25->bin.read = at25_bin_read; diff --git a/drivers/rtc/rtc-ds1742.c b/drivers/rtc/rtc-ds1742.c index a1273360a44e..cad9ceb89baf 100644 --- a/drivers/rtc/rtc-ds1742.c +++ b/drivers/rtc/rtc-ds1742.c @@ -184,6 +184,7 @@ static int __devinit ds1742_rtc_probe(struct platform_device *pdev) pdata->size_nvram = pdata->size - RTC_SIZE; pdata->ioaddr_rtc = ioaddr + pdata->size_nvram; + sysfs_bin_attr_init(&pdata->nvram_attr); pdata->nvram_attr.attr.name = "nvram"; pdata->nvram_attr.attr.mode = S_IRUGO | S_IWUSR; pdata->nvram_attr.read = ds1742_nvram_read; -- cgit v1.2.3 From 05731b979476969d4d1cbbcb535fc0f5ea90dba7 Mon Sep 17 00:00:00 2001 From: Uwe Kleine-König Date: Tue, 23 Mar 2010 13:35:13 -0700 Subject: rtc/mc13783: fix use after free bug MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This was introduced by v2.6.34-rc1~38: 4c014e8 (rtc/mc13783: protect rtc {,un}registration by mc13783 lock) Signed-off-by: Uwe Kleine-König Reported-by: Dan Carpenter Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/rtc/rtc-mc13783.c | 23 +++++++++++++---------- 1 file changed, 13 insertions(+), 10 deletions(-) (limited to 'drivers/rtc') diff --git a/drivers/rtc/rtc-mc13783.c b/drivers/rtc/rtc-mc13783.c index d60c81b7b693..1379c7faa448 100644 --- a/drivers/rtc/rtc-mc13783.c +++ b/drivers/rtc/rtc-mc13783.c @@ -319,35 +319,38 @@ static int __devinit mc13783_rtc_probe(struct platform_device *pdev) { int ret; struct mc13783_rtc *priv; + struct mc13783 *mc13783; int rtcrst_pending; priv = kzalloc(sizeof(*priv), GFP_KERNEL); if (!priv) return -ENOMEM; - priv->mc13783 = dev_get_drvdata(pdev->dev.parent); + mc13783 = dev_get_drvdata(pdev->dev.parent); + priv->mc13783 = mc13783; + platform_set_drvdata(pdev, priv); - mc13783_lock(priv->mc13783); + mc13783_lock(mc13783); - ret = mc13783_irq_request(priv->mc13783, MC13783_IRQ_RTCRST, + ret = mc13783_irq_request(mc13783, MC13783_IRQ_RTCRST, mc13783_rtc_reset_handler, DRIVER_NAME, priv); if (ret) goto err_reset_irq_request; - ret = mc13783_irq_status(priv->mc13783, MC13783_IRQ_RTCRST, + ret = mc13783_irq_status(mc13783, MC13783_IRQ_RTCRST, NULL, &rtcrst_pending); if (ret) goto err_reset_irq_status; priv->valid = !rtcrst_pending; - ret = mc13783_irq_request_nounmask(priv->mc13783, MC13783_IRQ_1HZ, + ret = mc13783_irq_request_nounmask(mc13783, MC13783_IRQ_1HZ, mc13783_rtc_update_handler, DRIVER_NAME, priv); if (ret) goto err_update_irq_request; - ret = mc13783_irq_request_nounmask(priv->mc13783, MC13783_IRQ_TODA, + ret = mc13783_irq_request_nounmask(mc13783, MC13783_IRQ_TODA, mc13783_rtc_alarm_handler, DRIVER_NAME, priv); if (ret) goto err_alarm_irq_request; @@ -357,22 +360,22 @@ static int __devinit mc13783_rtc_probe(struct platform_device *pdev) if (IS_ERR(priv->rtc)) { ret = PTR_ERR(priv->rtc); - mc13783_irq_free(priv->mc13783, MC13783_IRQ_TODA, priv); + mc13783_irq_free(mc13783, MC13783_IRQ_TODA, priv); err_alarm_irq_request: - mc13783_irq_free(priv->mc13783, MC13783_IRQ_1HZ, priv); + mc13783_irq_free(mc13783, MC13783_IRQ_1HZ, priv); err_update_irq_request: err_reset_irq_status: - mc13783_irq_free(priv->mc13783, MC13783_IRQ_RTCRST, priv); + mc13783_irq_free(mc13783, MC13783_IRQ_RTCRST, priv); err_reset_irq_request: platform_set_drvdata(pdev, NULL); kfree(priv); } - mc13783_unlock(priv->mc13783); + mc13783_unlock(mc13783); return ret; } -- cgit v1.2.3