From 071a1e33bac5c4ff8667d074be58365bd164b350 Mon Sep 17 00:00:00 2001 From: Paul Mundt Date: Wed, 27 Oct 2010 15:30:32 +0900 Subject: rtc: rtc-rs5c313: ctrl_in/outX to __raw_read/writeX conversion. The ctrl_xxx routines are deprecated, switch over to the __raw_xxx versions. Signed-off-by: Paul Mundt --- drivers/rtc/rtc-rs5c313.c | 34 +++++++++++++++++----------------- 1 file changed, 17 insertions(+), 17 deletions(-) (limited to 'drivers/rtc') diff --git a/drivers/rtc/rtc-rs5c313.c b/drivers/rtc/rtc-rs5c313.c index e6ea3f5ee1eb..e3ff179b99ca 100644 --- a/drivers/rtc/rtc-rs5c313.c +++ b/drivers/rtc/rtc-rs5c313.c @@ -80,21 +80,21 @@ /* SCSPTR1 data */ unsigned char scsptr1_data; -#define RS5C313_CEENABLE ctrl_outb(RS5C313_CE_RTCCE, RS5C313_CE); -#define RS5C313_CEDISABLE ctrl_outb(0x00, RS5C313_CE) -#define RS5C313_MISCOP ctrl_outb(0x02, 0xB0000008) +#define RS5C313_CEENABLE __raw_writeb(RS5C313_CE_RTCCE, RS5C313_CE); +#define RS5C313_CEDISABLE __raw_writeb(0x00, RS5C313_CE) +#define RS5C313_MISCOP __raw_writeb(0x02, 0xB0000008) static void rs5c313_init_port(void) { /* Set SCK as I/O port and Initialize SCSPTR1 data & I/O port. */ - ctrl_outb(ctrl_inb(SCSMR1) & ~SCSMR1_CA, SCSMR1); - ctrl_outb(ctrl_inb(SCSCR1) & ~SCSCR1_CKE, SCSCR1); + __raw_writeb(__raw_readb(SCSMR1) & ~SCSMR1_CA, SCSMR1); + __raw_writeb(__raw_readb(SCSCR1) & ~SCSCR1_CKE, SCSCR1); /* And Initialize SCL for RS5C313 clock */ - scsptr1_data = ctrl_inb(SCSPTR1) | SCL; /* SCL:H */ - ctrl_outb(scsptr1_data, SCSPTR1); - scsptr1_data = ctrl_inb(SCSPTR1) | SCL_OEN; /* SCL output enable */ - ctrl_outb(scsptr1_data, SCSPTR1); + scsptr1_data = __raw_readb(SCSPTR1) | SCL; /* SCL:H */ + __raw_writeb(scsptr1_data, SCSPTR1); + scsptr1_data = __raw_readb(SCSPTR1) | SCL_OEN; /* SCL output enable */ + __raw_writeb(scsptr1_data, SCSPTR1); RS5C313_CEDISABLE; /* CE:L */ } @@ -106,21 +106,21 @@ static void rs5c313_write_data(unsigned char data) /* SDA:Write Data */ scsptr1_data = (scsptr1_data & ~SDA) | ((((0x80 >> i) & data) >> (7 - i)) << 2); - ctrl_outb(scsptr1_data, SCSPTR1); + __raw_writeb(scsptr1_data, SCSPTR1); if (i == 0) { scsptr1_data |= SDA_OEN; /* SDA:output enable */ - ctrl_outb(scsptr1_data, SCSPTR1); + __raw_writeb(scsptr1_data, SCSPTR1); } ndelay(700); scsptr1_data &= ~SCL; /* SCL:L */ - ctrl_outb(scsptr1_data, SCSPTR1); + __raw_writeb(scsptr1_data, SCSPTR1); ndelay(700); scsptr1_data |= SCL; /* SCL:H */ - ctrl_outb(scsptr1_data, SCSPTR1); + __raw_writeb(scsptr1_data, SCSPTR1); } scsptr1_data &= ~SDA_OEN; /* SDA:output disable */ - ctrl_outb(scsptr1_data, SCSPTR1); + __raw_writeb(scsptr1_data, SCSPTR1); } static unsigned char rs5c313_read_data(void) @@ -131,12 +131,12 @@ static unsigned char rs5c313_read_data(void) for (i = 0; i < 8; i++) { ndelay(700); /* SDA:Read Data */ - data |= ((ctrl_inb(SCSPTR1) & SDA) >> 2) << (7 - i); + data |= ((__raw_readb(SCSPTR1) & SDA) >> 2) << (7 - i); scsptr1_data &= ~SCL; /* SCL:L */ - ctrl_outb(scsptr1_data, SCSPTR1); + __raw_writeb(scsptr1_data, SCSPTR1); ndelay(700); scsptr1_data |= SCL; /* SCL:H */ - ctrl_outb(scsptr1_data, SCSPTR1); + __raw_writeb(scsptr1_data, SCSPTR1); } return data & 0x0F; } -- cgit v1.2.2 From 9aa449bed21515a3406f60238ce4747e4118b628 Mon Sep 17 00:00:00 2001 From: Kevin Wells Date: Wed, 27 Oct 2010 15:33:01 -0700 Subject: rtc: rtc-lpc32xx: introduce RTC driver for the LPC32XX SoC Add an RTC driver for the built-in RTC in the LPC32XX SoC. This patch includes updates from the initial review comments and updates from the v3 review. Signed-off-by: Kevin Wells Signed-off-by: Durgesh Pattamatta Reviewed-by: Wolfram Sang Cc: Alessandro Zummo Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/rtc/Kconfig | 9 + drivers/rtc/Makefile | 1 + drivers/rtc/rtc-lpc32xx.c | 414 ++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 424 insertions(+) create mode 100644 drivers/rtc/rtc-lpc32xx.c (limited to 'drivers/rtc') diff --git a/drivers/rtc/Kconfig b/drivers/rtc/Kconfig index 2785a0f16c9f..636ba8224884 100644 --- a/drivers/rtc/Kconfig +++ b/drivers/rtc/Kconfig @@ -952,4 +952,13 @@ config RTC_DRV_JZ4740 This driver can also be buillt as a module. If so, the module will be called rtc-jz4740. +config RTC_DRV_LPC32XX + depends on ARCH_LPC32XX + tristate "NXP LPC32XX RTC" + help + This enables support for the NXP RTC in the LPC32XX + + This driver can also be buillt as a module. If so, the module + will be called rtc-lpc32xx. + endif # RTC_CLASS diff --git a/drivers/rtc/Makefile b/drivers/rtc/Makefile index 0f207b3b5833..7a7cb3228a1d 100644 --- a/drivers/rtc/Makefile +++ b/drivers/rtc/Makefile @@ -51,6 +51,7 @@ obj-$(CONFIG_RTC_DRV_IMXDI) += rtc-imxdi.o obj-$(CONFIG_RTC_DRV_ISL1208) += rtc-isl1208.o obj-$(CONFIG_RTC_DRV_ISL12022) += rtc-isl12022.o obj-$(CONFIG_RTC_DRV_JZ4740) += rtc-jz4740.o +obj-$(CONFIG_RTC_DRV_LPC32XX) += rtc-lpc32xx.o obj-$(CONFIG_RTC_DRV_M41T80) += rtc-m41t80.o obj-$(CONFIG_RTC_DRV_M41T94) += rtc-m41t94.o obj-$(CONFIG_RTC_DRV_M48T35) += rtc-m48t35.o diff --git a/drivers/rtc/rtc-lpc32xx.c b/drivers/rtc/rtc-lpc32xx.c new file mode 100644 index 000000000000..ec8701ce99f9 --- /dev/null +++ b/drivers/rtc/rtc-lpc32xx.c @@ -0,0 +1,414 @@ +/* + * Copyright (C) 2010 NXP Semiconductors + * + * 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. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +/* + * Clock and Power control register offsets + */ +#define LPC32XX_RTC_UCOUNT 0x00 +#define LPC32XX_RTC_DCOUNT 0x04 +#define LPC32XX_RTC_MATCH0 0x08 +#define LPC32XX_RTC_MATCH1 0x0C +#define LPC32XX_RTC_CTRL 0x10 +#define LPC32XX_RTC_INTSTAT 0x14 +#define LPC32XX_RTC_KEY 0x18 +#define LPC32XX_RTC_SRAM 0x80 + +#define LPC32XX_RTC_CTRL_MATCH0 (1 << 0) +#define LPC32XX_RTC_CTRL_MATCH1 (1 << 1) +#define LPC32XX_RTC_CTRL_ONSW_MATCH0 (1 << 2) +#define LPC32XX_RTC_CTRL_ONSW_MATCH1 (1 << 3) +#define LPC32XX_RTC_CTRL_SW_RESET (1 << 4) +#define LPC32XX_RTC_CTRL_CNTR_DIS (1 << 6) +#define LPC32XX_RTC_CTRL_ONSW_FORCE_HI (1 << 7) + +#define LPC32XX_RTC_INTSTAT_MATCH0 (1 << 0) +#define LPC32XX_RTC_INTSTAT_MATCH1 (1 << 1) +#define LPC32XX_RTC_INTSTAT_ONSW (1 << 2) + +#define LPC32XX_RTC_KEY_ONSW_LOADVAL 0xB5C13F27 + +#define RTC_NAME "rtc-lpc32xx" + +#define rtc_readl(dev, reg) \ + __raw_readl((dev)->rtc_base + (reg)) +#define rtc_writel(dev, reg, val) \ + __raw_writel((val), (dev)->rtc_base + (reg)) + +struct lpc32xx_rtc { + void __iomem *rtc_base; + int irq; + unsigned char alarm_enabled; + struct rtc_device *rtc; + spinlock_t lock; +}; + +static int lpc32xx_rtc_read_time(struct device *dev, struct rtc_time *time) +{ + unsigned long elapsed_sec; + struct lpc32xx_rtc *rtc = dev_get_drvdata(dev); + + elapsed_sec = rtc_readl(rtc, LPC32XX_RTC_UCOUNT); + rtc_time_to_tm(elapsed_sec, time); + + return rtc_valid_tm(time); +} + +static int lpc32xx_rtc_set_mmss(struct device *dev, unsigned long secs) +{ + struct lpc32xx_rtc *rtc = dev_get_drvdata(dev); + u32 tmp; + + spin_lock_irq(&rtc->lock); + + /* RTC must be disabled during count update */ + tmp = rtc_readl(rtc, LPC32XX_RTC_CTRL); + rtc_writel(rtc, LPC32XX_RTC_CTRL, tmp | LPC32XX_RTC_CTRL_CNTR_DIS); + rtc_writel(rtc, LPC32XX_RTC_UCOUNT, secs); + rtc_writel(rtc, LPC32XX_RTC_DCOUNT, 0xFFFFFFFF - secs); + rtc_writel(rtc, LPC32XX_RTC_CTRL, tmp &= ~LPC32XX_RTC_CTRL_CNTR_DIS); + + spin_unlock_irq(&rtc->lock); + + return 0; +} + +static int lpc32xx_rtc_read_alarm(struct device *dev, + struct rtc_wkalrm *wkalrm) +{ + struct lpc32xx_rtc *rtc = dev_get_drvdata(dev); + + rtc_time_to_tm(rtc_readl(rtc, LPC32XX_RTC_MATCH0), &wkalrm->time); + wkalrm->enabled = rtc->alarm_enabled; + wkalrm->pending = !!(rtc_readl(rtc, LPC32XX_RTC_INTSTAT) & + LPC32XX_RTC_INTSTAT_MATCH0); + + return rtc_valid_tm(&wkalrm->time); +} + +static int lpc32xx_rtc_set_alarm(struct device *dev, + struct rtc_wkalrm *wkalrm) +{ + struct lpc32xx_rtc *rtc = dev_get_drvdata(dev); + unsigned long alarmsecs; + u32 tmp; + int ret; + + ret = rtc_tm_to_time(&wkalrm->time, &alarmsecs); + if (ret < 0) { + dev_warn(dev, "Failed to convert time: %d\n", ret); + return ret; + } + + spin_lock_irq(&rtc->lock); + + /* Disable alarm during update */ + tmp = rtc_readl(rtc, LPC32XX_RTC_CTRL); + rtc_writel(rtc, LPC32XX_RTC_CTRL, tmp & ~LPC32XX_RTC_CTRL_MATCH0); + + rtc_writel(rtc, LPC32XX_RTC_MATCH0, alarmsecs); + + rtc->alarm_enabled = wkalrm->enabled; + if (wkalrm->enabled) { + rtc_writel(rtc, LPC32XX_RTC_INTSTAT, + LPC32XX_RTC_INTSTAT_MATCH0); + rtc_writel(rtc, LPC32XX_RTC_CTRL, tmp | + LPC32XX_RTC_CTRL_MATCH0); + } + + spin_unlock_irq(&rtc->lock); + + return 0; +} + +static int lpc32xx_rtc_alarm_irq_enable(struct device *dev, + unsigned int enabled) +{ + struct lpc32xx_rtc *rtc = dev_get_drvdata(dev); + u32 tmp; + + spin_lock_irq(&rtc->lock); + tmp = rtc_readl(rtc, LPC32XX_RTC_CTRL); + + if (enabled) { + rtc->alarm_enabled = 1; + tmp |= LPC32XX_RTC_CTRL_MATCH0; + } else { + rtc->alarm_enabled = 0; + tmp &= ~LPC32XX_RTC_CTRL_MATCH0; + } + + rtc_writel(rtc, LPC32XX_RTC_CTRL, tmp); + spin_unlock_irq(&rtc->lock); + + return 0; +} + +static irqreturn_t lpc32xx_rtc_alarm_interrupt(int irq, void *dev) +{ + struct lpc32xx_rtc *rtc = dev; + + spin_lock(&rtc->lock); + + /* Disable alarm interrupt */ + rtc_writel(rtc, LPC32XX_RTC_CTRL, + rtc_readl(rtc, LPC32XX_RTC_CTRL) & + ~LPC32XX_RTC_CTRL_MATCH0); + rtc->alarm_enabled = 0; + + /* + * Write a large value to the match value so the RTC won't + * keep firing the match status + */ + rtc_writel(rtc, LPC32XX_RTC_MATCH0, 0xFFFFFFFF); + rtc_writel(rtc, LPC32XX_RTC_INTSTAT, LPC32XX_RTC_INTSTAT_MATCH0); + + spin_unlock(&rtc->lock); + + rtc_update_irq(rtc->rtc, 1, RTC_IRQF | RTC_AF); + + return IRQ_HANDLED; +} + +static const struct rtc_class_ops lpc32xx_rtc_ops = { + .read_time = lpc32xx_rtc_read_time, + .set_mmss = lpc32xx_rtc_set_mmss, + .read_alarm = lpc32xx_rtc_read_alarm, + .set_alarm = lpc32xx_rtc_set_alarm, + .alarm_irq_enable = lpc32xx_rtc_alarm_irq_enable, +}; + +static int __devinit lpc32xx_rtc_probe(struct platform_device *pdev) +{ + struct resource *res; + struct lpc32xx_rtc *rtc; + resource_size_t size; + int rtcirq; + u32 tmp; + + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + if (!res) { + dev_err(&pdev->dev, "Can't get memory resource\n"); + return -ENOENT; + } + + rtcirq = platform_get_irq(pdev, 0); + if (rtcirq < 0 || rtcirq >= NR_IRQS) { + dev_warn(&pdev->dev, "Can't get interrupt resource\n"); + rtcirq = -1; + } + + rtc = devm_kzalloc(&pdev->dev, sizeof(*rtc), GFP_KERNEL); + if (unlikely(!rtc)) { + dev_err(&pdev->dev, "Can't allocate memory\n"); + return -ENOMEM; + } + rtc->irq = rtcirq; + + size = resource_size(res); + + if (!devm_request_mem_region(&pdev->dev, res->start, size, + pdev->name)) { + dev_err(&pdev->dev, "RTC registers are not free\n"); + return -EBUSY; + } + + rtc->rtc_base = devm_ioremap(&pdev->dev, res->start, size); + if (!rtc->rtc_base) { + dev_err(&pdev->dev, "Can't map memory\n"); + return -ENOMEM; + } + + spin_lock_init(&rtc->lock); + + /* + * The RTC is on a seperate power domain and can keep it's state + * across a chip power cycle. If the RTC has never been previously + * setup, then set it up now for the first time. + */ + tmp = rtc_readl(rtc, LPC32XX_RTC_CTRL); + if (rtc_readl(rtc, LPC32XX_RTC_KEY) != LPC32XX_RTC_KEY_ONSW_LOADVAL) { + tmp &= ~(LPC32XX_RTC_CTRL_SW_RESET | + LPC32XX_RTC_CTRL_CNTR_DIS | + LPC32XX_RTC_CTRL_MATCH0 | + LPC32XX_RTC_CTRL_MATCH1 | + LPC32XX_RTC_CTRL_ONSW_MATCH0 | + LPC32XX_RTC_CTRL_ONSW_MATCH1 | + LPC32XX_RTC_CTRL_ONSW_FORCE_HI); + rtc_writel(rtc, LPC32XX_RTC_CTRL, tmp); + + /* Clear latched interrupt states */ + rtc_writel(rtc, LPC32XX_RTC_MATCH0, 0xFFFFFFFF); + rtc_writel(rtc, LPC32XX_RTC_INTSTAT, + LPC32XX_RTC_INTSTAT_MATCH0 | + LPC32XX_RTC_INTSTAT_MATCH1 | + LPC32XX_RTC_INTSTAT_ONSW); + + /* Write key value to RTC so it won't reload on reset */ + rtc_writel(rtc, LPC32XX_RTC_KEY, + LPC32XX_RTC_KEY_ONSW_LOADVAL); + } else { + rtc_writel(rtc, LPC32XX_RTC_CTRL, + tmp & ~LPC32XX_RTC_CTRL_MATCH0); + } + + platform_set_drvdata(pdev, rtc); + + rtc->rtc = rtc_device_register(RTC_NAME, &pdev->dev, &lpc32xx_rtc_ops, + THIS_MODULE); + if (IS_ERR(rtc->rtc)) { + dev_err(&pdev->dev, "Can't get RTC\n"); + platform_set_drvdata(pdev, NULL); + return PTR_ERR(rtc->rtc); + } + + /* + * IRQ is enabled after device registration in case alarm IRQ + * is pending upon suspend exit. + */ + if (rtc->irq >= 0) { + if (devm_request_irq(&pdev->dev, rtc->irq, + lpc32xx_rtc_alarm_interrupt, + IRQF_DISABLED, pdev->name, rtc) < 0) { + dev_warn(&pdev->dev, "Can't request interrupt.\n"); + rtc->irq = -1; + } else { + device_init_wakeup(&pdev->dev, 1); + } + } + + return 0; +} + +static int __devexit lpc32xx_rtc_remove(struct platform_device *pdev) +{ + struct lpc32xx_rtc *rtc = platform_get_drvdata(pdev); + + if (rtc->irq >= 0) + device_init_wakeup(&pdev->dev, 0); + + platform_set_drvdata(pdev, NULL); + rtc_device_unregister(rtc->rtc); + + return 0; +} + +#ifdef CONFIG_PM +static int lpc32xx_rtc_suspend(struct device *dev) +{ + struct platform_device *pdev = to_platform_device(dev); + struct lpc32xx_rtc *rtc = platform_get_drvdata(pdev); + + if (rtc->irq >= 0) { + if (device_may_wakeup(&pdev->dev)) + enable_irq_wake(rtc->irq); + else + disable_irq_wake(rtc->irq); + } + + return 0; +} + +static int lpc32xx_rtc_resume(struct device *dev) +{ + struct platform_device *pdev = to_platform_device(dev); + struct lpc32xx_rtc *rtc = platform_get_drvdata(pdev); + + if (rtc->irq >= 0 && device_may_wakeup(&pdev->dev)) + disable_irq_wake(rtc->irq); + + return 0; +} + +/* Unconditionally disable the alarm */ +static int lpc32xx_rtc_freeze(struct device *dev) +{ + struct platform_device *pdev = to_platform_device(dev); + struct lpc32xx_rtc *rtc = platform_get_drvdata(pdev); + + spin_lock_irq(&rtc->lock); + + rtc_writel(rtc, LPC32XX_RTC_CTRL, + rtc_readl(rtc, LPC32XX_RTC_CTRL) & + ~LPC32XX_RTC_CTRL_MATCH0); + + spin_unlock_irq(&rtc->lock); + + return 0; +} + +static int lpc32xx_rtc_thaw(struct device *dev) +{ + struct platform_device *pdev = to_platform_device(dev); + struct lpc32xx_rtc *rtc = platform_get_drvdata(pdev); + + if (rtc->alarm_enabled) { + spin_lock_irq(&rtc->lock); + + rtc_writel(rtc, LPC32XX_RTC_CTRL, + rtc_readl(rtc, LPC32XX_RTC_CTRL) | + LPC32XX_RTC_CTRL_MATCH0); + + spin_unlock_irq(&rtc->lock); + } + + return 0; +} + +static const struct dev_pm_ops lpc32xx_rtc_pm_ops = { + .suspend = lpc32xx_rtc_suspend, + .resume = lpc32xx_rtc_resume, + .freeze = lpc32xx_rtc_freeze, + .thaw = lpc32xx_rtc_thaw, + .restore = lpc32xx_rtc_resume +}; + +#define LPC32XX_RTC_PM_OPS (&lpc32xx_rtc_pm_ops) +#else +#define LPC32XX_RTC_PM_OPS NULL +#endif + +static struct platform_driver lpc32xx_rtc_driver = { + .probe = lpc32xx_rtc_probe, + .remove = __devexit_p(lpc32xx_rtc_remove), + .driver = { + .name = RTC_NAME, + .owner = THIS_MODULE, + .pm = LPC32XX_RTC_PM_OPS + }, +}; + +static int __init lpc32xx_rtc_init(void) +{ + return platform_driver_register(&lpc32xx_rtc_driver); +} +module_init(lpc32xx_rtc_init); + +static void __exit lpc32xx_rtc_exit(void) +{ + platform_driver_unregister(&lpc32xx_rtc_driver); +} +module_exit(lpc32xx_rtc_exit); + +MODULE_AUTHOR("Kevin Wells Date: Wed, 27 Oct 2010 15:33:03 -0700 Subject: rtc-bfin: shrink/optimize interrupt handler a bit By unifying the RTC_ISTAT clearing steps, we shrink the interrupt handler and avoid multiple writes to the hardware registers. Signed-off-by: Mike Frysinger Acked-by: Alessandro Zummo Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/rtc/rtc-bfin.c | 27 ++++++++++++++++----------- 1 file changed, 16 insertions(+), 11 deletions(-) (limited to 'drivers/rtc') diff --git a/drivers/rtc/rtc-bfin.c b/drivers/rtc/rtc-bfin.c index d4fb82d85e9b..3506f330e97e 100644 --- a/drivers/rtc/rtc-bfin.c +++ b/drivers/rtc/rtc-bfin.c @@ -183,29 +183,33 @@ static irqreturn_t bfin_rtc_interrupt(int irq, void *dev_id) struct bfin_rtc *rtc = dev_get_drvdata(dev); unsigned long events = 0; bool write_complete = false; - u16 rtc_istat, rtc_ictl; + u16 rtc_istat, rtc_istat_clear, rtc_ictl, bits; dev_dbg_stamp(dev); rtc_istat = bfin_read_RTC_ISTAT(); rtc_ictl = bfin_read_RTC_ICTL(); + rtc_istat_clear = 0; - if (rtc_istat & RTC_ISTAT_WRITE_COMPLETE) { - bfin_write_RTC_ISTAT(RTC_ISTAT_WRITE_COMPLETE); + bits = RTC_ISTAT_WRITE_COMPLETE; + if (rtc_istat & bits) { + rtc_istat_clear |= bits; write_complete = true; complete(&bfin_write_complete); } - if (rtc_ictl & (RTC_ISTAT_ALARM | RTC_ISTAT_ALARM_DAY)) { - if (rtc_istat & (RTC_ISTAT_ALARM | RTC_ISTAT_ALARM_DAY)) { - bfin_write_RTC_ISTAT(RTC_ISTAT_ALARM | RTC_ISTAT_ALARM_DAY); + bits = (RTC_ISTAT_ALARM | RTC_ISTAT_ALARM_DAY); + if (rtc_ictl & bits) { + if (rtc_istat & bits) { + rtc_istat_clear |= bits; events |= RTC_AF | RTC_IRQF; } } - if (rtc_ictl & RTC_ISTAT_SEC) { - if (rtc_istat & RTC_ISTAT_SEC) { - bfin_write_RTC_ISTAT(RTC_ISTAT_SEC); + bits = RTC_ISTAT_SEC; + if (rtc_ictl & bits) { + if (rtc_istat & bits) { + rtc_istat_clear |= bits; events |= RTC_UF | RTC_IRQF; } } @@ -213,9 +217,10 @@ static irqreturn_t bfin_rtc_interrupt(int irq, void *dev_id) if (events) rtc_update_irq(rtc->rtc_dev, 1, events); - if (write_complete || events) + if (write_complete || events) { + bfin_write_RTC_ISTAT(rtc_istat_clear); return IRQ_HANDLED; - else + } else return IRQ_NONE; } -- cgit v1.2.2 From d7c7ef908b6497bb871e2e113e66e8fb0f757543 Mon Sep 17 00:00:00 2001 From: Mike Frysinger Date: Wed, 27 Oct 2010 15:33:04 -0700 Subject: rtc-bfin: add debug markers to suspend/resume paths The rest of the driver had debug markings already. This also standardizes the usage of "dev" a bit. Signed-off-by: Mike Frysinger Acked-by: Alessandro Zummo Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/rtc/rtc-bfin.c | 16 ++++++++++++---- 1 file changed, 12 insertions(+), 4 deletions(-) (limited to 'drivers/rtc') diff --git a/drivers/rtc/rtc-bfin.c b/drivers/rtc/rtc-bfin.c index 3506f330e97e..b4b6087f2234 100644 --- a/drivers/rtc/rtc-bfin.c +++ b/drivers/rtc/rtc-bfin.c @@ -2,7 +2,7 @@ * Blackfin On-Chip Real Time Clock Driver * Supports BF51x/BF52x/BF53[123]/BF53[467]/BF54x * - * Copyright 2004-2009 Analog Devices Inc. + * Copyright 2004-2010 Analog Devices Inc. * * Enter bugs at http://blackfin.uclinux.org/ * @@ -427,9 +427,13 @@ static int __devexit bfin_rtc_remove(struct platform_device *pdev) #ifdef CONFIG_PM static int bfin_rtc_suspend(struct platform_device *pdev, pm_message_t state) { - if (device_may_wakeup(&pdev->dev)) { + struct device *dev = &pdev->dev; + + dev_dbg_stamp(dev); + + if (device_may_wakeup(dev)) { enable_irq_wake(IRQ_RTC); - bfin_rtc_sync_pending(&pdev->dev); + bfin_rtc_sync_pending(dev); } else bfin_rtc_int_clear(0); @@ -438,7 +442,11 @@ static int bfin_rtc_suspend(struct platform_device *pdev, pm_message_t state) static int bfin_rtc_resume(struct platform_device *pdev) { - if (device_may_wakeup(&pdev->dev)) + struct device *dev = &pdev->dev; + + dev_dbg_stamp(dev); + + if (device_may_wakeup(dev)) disable_irq_wake(IRQ_RTC); /* -- cgit v1.2.2 From 59cca865f21e9e7beab73fcf79ba4eb776a4c228 Mon Sep 17 00:00:00 2001 From: Vasiliy Kulikov Date: Wed, 27 Oct 2010 15:33:04 -0700 Subject: drivers/rtc/class.c: fix device_register() error handling If device_register() fails then call put_device(). See comment to device_register. Signed-off-by: Vasiliy Kulikov Cc: Alessandro Zummo Cc: Wan ZongShun Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/rtc/class.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) (limited to 'drivers/rtc') diff --git a/drivers/rtc/class.c b/drivers/rtc/class.c index 565562ba6ac9..e6539cbabb35 100644 --- a/drivers/rtc/class.c +++ b/drivers/rtc/class.c @@ -158,8 +158,10 @@ struct rtc_device *rtc_device_register(const char *name, struct device *dev, rtc_dev_prepare(rtc); err = device_register(&rtc->dev); - if (err) + if (err) { + put_device(&rtc->dev); goto exit_kfree; + } rtc_dev_add_device(rtc); rtc_sysfs_add_device(rtc); -- cgit v1.2.2 From fa5b07820fe3a0fc06ac368516e71f10a59b9539 Mon Sep 17 00:00:00 2001 From: Sekhar Nori Date: Wed, 27 Oct 2010 15:33:05 -0700 Subject: rtc: omap: let device wakeup capability be configured from chip init logic The rtc-omap driver currently hardcodes the RTC wakeup capability to be "not capable". While this seems to be true for existing OMAP1 boards which are not wired for this, the DA850/OMAP-L138 SoC, the RTC can always be wake up source from its "deep sleep" mode. This patch lets the wakeup capability be set from platform data and does not override the setting from the driver. For DA850/OMAP-L138, this is done from arch/arm/mach-davinci/devices-da8xx.c:da8xx_register_rtc() Note that this patch does not change the behavior on any existing OMAP1 board since the platform device registration sets the wakeup capability to 0 by default. Signed-off-by: Sekhar Nori Signed-off-by: Kevin Hilman Cc: Alessandro Zummo Cc: Wan ZongShun Cc: Tony Lindgren Cc: David Brownell Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/rtc/rtc-omap.c | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) (limited to 'drivers/rtc') diff --git a/drivers/rtc/rtc-omap.c b/drivers/rtc/rtc-omap.c index 64d9727b7229..73377b0d65da 100644 --- a/drivers/rtc/rtc-omap.c +++ b/drivers/rtc/rtc-omap.c @@ -34,7 +34,8 @@ * Board-specific wiring options include using split power mode with * RTC_OFF_NOFF used as the reset signal (so the RTC won't be reset), * and wiring RTC_WAKE_INT (so the RTC alarm can wake the system from - * low power modes). See the BOARD-SPECIFIC CUSTOMIZATION comment. + * low power modes) for OMAP1 boards (OMAP-L138 has this built into + * the SoC). See the BOARD-SPECIFIC CUSTOMIZATION comment. */ #define OMAP_RTC_BASE 0xfffb4800 @@ -401,16 +402,17 @@ static int __init omap_rtc_probe(struct platform_device *pdev) /* BOARD-SPECIFIC CUSTOMIZATION CAN GO HERE: * - * - Boards wired so that RTC_WAKE_INT does something, and muxed - * right (W13_1610_RTC_WAKE_INT is the default after chip reset), - * should initialize the device wakeup flag appropriately. + * - Device wake-up capability setting should come through chip + * init logic. OMAP1 boards should initialize the "wakeup capable" + * flag in the platform device if the board is wired right for + * being woken up by RTC alarm. For OMAP-L138, this capability + * is built into the SoC by the "Deep Sleep" capability. * * - Boards wired so RTC_ON_nOFF is used as the reset signal, * rather than nPWRON_RESET, should forcibly enable split * power mode. (Some chip errata report that RTC_CTRL_SPLIT * is write-only, and always reads as zero...) */ - device_init_wakeup(&pdev->dev, 0); if (new_ctrl & (u8) OMAP_RTC_CTRL_SPLIT) pr_info("%s: split power mode\n", pdev->name); -- cgit v1.2.2 From f61ae6711d69717558e882a78487527705603a74 Mon Sep 17 00:00:00 2001 From: Changhwan Youn Date: Wed, 27 Oct 2010 15:33:06 -0700 Subject: rtc: rtc-s3c: fix access unit from byte to word on RTCCON S3C2410_RTCCON of TYPE_S3C64XX RTC should be read/written by readw and writew, because TYPE_S3C64XX RTC uses bit 8 and 9. And TYPE_S3C2410 RTC also can access it by readw and writew. [atul.dahiya@samsung.com: tested on smdk2416] [akpm@linux-foundation.org: coding-style fixes] Signed-off-by: Changhwan Youn Signed-off-by: Kukjin Kim Tested-by: Atul Dahiya Cc: Ben Dooks Cc: Wan ZongShun Cc: Alessandro Zummo Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/rtc/rtc-s3c.c | 39 +++++++++++++++++++++------------------ 1 file changed, 21 insertions(+), 18 deletions(-) (limited to 'drivers/rtc') diff --git a/drivers/rtc/rtc-s3c.c b/drivers/rtc/rtc-s3c.c index f57a87f4ae96..a87982d7cb70 100644 --- a/drivers/rtc/rtc-s3c.c +++ b/drivers/rtc/rtc-s3c.c @@ -100,7 +100,7 @@ static int s3c_rtc_setpie(struct device *dev, int enabled) spin_lock_irq(&s3c_rtc_pie_lock); if (s3c_rtc_cpu_type == TYPE_S3C64XX) { - tmp = readb(s3c_rtc_base + S3C2410_RTCCON); + tmp = readw(s3c_rtc_base + S3C2410_RTCCON); tmp &= ~S3C64XX_RTCCON_TICEN; if (enabled) @@ -318,7 +318,7 @@ static int s3c_rtc_proc(struct device *dev, struct seq_file *seq) unsigned int ticnt; if (s3c_rtc_cpu_type == TYPE_S3C64XX) { - ticnt = readb(s3c_rtc_base + S3C2410_RTCCON); + ticnt = readw(s3c_rtc_base + S3C2410_RTCCON); ticnt &= S3C64XX_RTCCON_TICEN; } else { ticnt = readb(s3c_rtc_base + S3C2410_TICNT); @@ -391,11 +391,11 @@ static void s3c_rtc_enable(struct platform_device *pdev, int en) return; if (!en) { - tmp = readb(base + S3C2410_RTCCON); + tmp = readw(base + S3C2410_RTCCON); if (s3c_rtc_cpu_type == TYPE_S3C64XX) tmp &= ~S3C64XX_RTCCON_TICEN; tmp &= ~S3C2410_RTCCON_RTCEN; - writeb(tmp, base + S3C2410_RTCCON); + writew(tmp, base + S3C2410_RTCCON); if (s3c_rtc_cpu_type == TYPE_S3C2410) { tmp = readb(base + S3C2410_TICNT); @@ -405,25 +405,28 @@ static void s3c_rtc_enable(struct platform_device *pdev, int en) } else { /* re-enable the device, and check it is ok */ - if ((readb(base+S3C2410_RTCCON) & S3C2410_RTCCON_RTCEN) == 0){ + if ((readw(base+S3C2410_RTCCON) & S3C2410_RTCCON_RTCEN) == 0) { dev_info(&pdev->dev, "rtc disabled, re-enabling\n"); - tmp = readb(base + S3C2410_RTCCON); - writeb(tmp|S3C2410_RTCCON_RTCEN, base+S3C2410_RTCCON); + tmp = readw(base + S3C2410_RTCCON); + writew(tmp | S3C2410_RTCCON_RTCEN, + base + S3C2410_RTCCON); } - if ((readb(base + S3C2410_RTCCON) & S3C2410_RTCCON_CNTSEL)){ + if ((readw(base + S3C2410_RTCCON) & S3C2410_RTCCON_CNTSEL)) { dev_info(&pdev->dev, "removing RTCCON_CNTSEL\n"); - tmp = readb(base + S3C2410_RTCCON); - writeb(tmp& ~S3C2410_RTCCON_CNTSEL, base+S3C2410_RTCCON); + tmp = readw(base + S3C2410_RTCCON); + writew(tmp & ~S3C2410_RTCCON_CNTSEL, + base + S3C2410_RTCCON); } - if ((readb(base + S3C2410_RTCCON) & S3C2410_RTCCON_CLKRST)){ + if ((readw(base + S3C2410_RTCCON) & S3C2410_RTCCON_CLKRST)) { dev_info(&pdev->dev, "removing RTCCON_CLKRST\n"); - tmp = readb(base + S3C2410_RTCCON); - writeb(tmp & ~S3C2410_RTCCON_CLKRST, base+S3C2410_RTCCON); + tmp = readw(base + S3C2410_RTCCON); + writew(tmp & ~S3C2410_RTCCON_CLKRST, + base + S3C2410_RTCCON); } } } @@ -514,8 +517,8 @@ static int __devinit s3c_rtc_probe(struct platform_device *pdev) s3c_rtc_enable(pdev, 1); - pr_debug("s3c2410_rtc: RTCCON=%02x\n", - readb(s3c_rtc_base + S3C2410_RTCCON)); + pr_debug("s3c2410_rtc: RTCCON=%02x\n", + readw(s3c_rtc_base + S3C2410_RTCCON)); device_init_wakeup(&pdev->dev, 1); @@ -578,7 +581,7 @@ static int s3c_rtc_suspend(struct platform_device *pdev, pm_message_t state) /* save TICNT for anyone using periodic interrupts */ ticnt_save = readb(s3c_rtc_base + S3C2410_TICNT); if (s3c_rtc_cpu_type == TYPE_S3C64XX) { - ticnt_en_save = readb(s3c_rtc_base + S3C2410_RTCCON); + ticnt_en_save = readw(s3c_rtc_base + S3C2410_RTCCON); ticnt_en_save &= S3C64XX_RTCCON_TICEN; } s3c_rtc_enable(pdev, 0); @@ -596,8 +599,8 @@ static int s3c_rtc_resume(struct platform_device *pdev) s3c_rtc_enable(pdev, 1); writeb(ticnt_save, s3c_rtc_base + S3C2410_TICNT); if (s3c_rtc_cpu_type == TYPE_S3C64XX && ticnt_en_save) { - tmp = readb(s3c_rtc_base + S3C2410_RTCCON); - writeb(tmp | ticnt_en_save, s3c_rtc_base + S3C2410_RTCCON); + tmp = readw(s3c_rtc_base + S3C2410_RTCCON); + writew(tmp | ticnt_en_save, s3c_rtc_base + S3C2410_RTCCON); } if (device_may_wakeup(&pdev->dev)) -- cgit v1.2.2 From dd061d1abe4e637bf755865f776f8088dacd1c0b Mon Sep 17 00:00:00 2001 From: Changhwan Youn Date: Wed, 27 Oct 2010 15:33:08 -0700 Subject: rtc: rtc-s3c: fix setting missing field of getalarm Current s3c_rtc_getalarm() sets missing field of alarm time with 0xff. But this value should be -1 according to drivers/rtc/interface.c. Signed-off-by: Changhwan Youn Signed-off-by: Kukjin Kim Acked-by: Ben Dooks Cc: Wan ZongShun Cc: Alessandro Zummo Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/rtc/rtc-s3c.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) (limited to 'drivers/rtc') diff --git a/drivers/rtc/rtc-s3c.c b/drivers/rtc/rtc-s3c.c index a87982d7cb70..75b009a17e5b 100644 --- a/drivers/rtc/rtc-s3c.c +++ b/drivers/rtc/rtc-s3c.c @@ -242,34 +242,34 @@ static int s3c_rtc_getalarm(struct device *dev, struct rtc_wkalrm *alrm) if (alm_en & S3C2410_RTCALM_SECEN) alm_tm->tm_sec = bcd2bin(alm_tm->tm_sec); else - alm_tm->tm_sec = 0xff; + alm_tm->tm_sec = -1; if (alm_en & S3C2410_RTCALM_MINEN) alm_tm->tm_min = bcd2bin(alm_tm->tm_min); else - alm_tm->tm_min = 0xff; + alm_tm->tm_min = -1; if (alm_en & S3C2410_RTCALM_HOUREN) alm_tm->tm_hour = bcd2bin(alm_tm->tm_hour); else - alm_tm->tm_hour = 0xff; + alm_tm->tm_hour = -1; if (alm_en & S3C2410_RTCALM_DAYEN) alm_tm->tm_mday = bcd2bin(alm_tm->tm_mday); else - alm_tm->tm_mday = 0xff; + alm_tm->tm_mday = -1; if (alm_en & S3C2410_RTCALM_MONEN) { alm_tm->tm_mon = bcd2bin(alm_tm->tm_mon); alm_tm->tm_mon -= 1; } else { - alm_tm->tm_mon = 0xff; + alm_tm->tm_mon = -1; } if (alm_en & S3C2410_RTCALM_YEAREN) alm_tm->tm_year = bcd2bin(alm_tm->tm_year); else - alm_tm->tm_year = 0xffff; + alm_tm->tm_year = -1; return 0; } -- cgit v1.2.2 From e6eb524e6e6df4027530b36f76b84a6a076a3249 Mon Sep 17 00:00:00 2001 From: Changhwan Youn Date: Wed, 27 Oct 2010 15:33:09 -0700 Subject: rtc: rtc-s3c: fix on support RTC Alarm The alarm_irq_enable function should be implemented to support RTC alarm. And fix tabs instead of white space around the proc field. Signed-off-by: Changhwan Youn Signed-off-by: Kukjin Kim Acked-by: Ben Dooks Cc: Wan ZongShun Cc: Alessandro Zummo Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/rtc/rtc-s3c.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'drivers/rtc') diff --git a/drivers/rtc/rtc-s3c.c b/drivers/rtc/rtc-s3c.c index 75b009a17e5b..a53c27f30745 100644 --- a/drivers/rtc/rtc-s3c.c +++ b/drivers/rtc/rtc-s3c.c @@ -379,7 +379,8 @@ static const struct rtc_class_ops s3c_rtcops = { .set_alarm = s3c_rtc_setalarm, .irq_set_freq = s3c_rtc_setfreq, .irq_set_state = s3c_rtc_setpie, - .proc = s3c_rtc_proc, + .proc = s3c_rtc_proc, + .alarm_irq_enable = s3c_rtc_setaie, }; static void s3c_rtc_enable(struct platform_device *pdev, int en) -- cgit v1.2.2 From 30ffc40cf52cd68782b50cb699b5eca076ca23ab Mon Sep 17 00:00:00 2001 From: Kukjin Kim Date: Wed, 27 Oct 2010 15:33:09 -0700 Subject: rtc: rtc-s3c: Fix debug message format on RTC Fix debug message format. Signed-off-by: Kukjin Kim Acked-by: Ben Dooks Cc: Wan ZongShun Cc: Alessandro Zummo Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/rtc/rtc-s3c.c | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) (limited to 'drivers/rtc') diff --git a/drivers/rtc/rtc-s3c.c b/drivers/rtc/rtc-s3c.c index a53c27f30745..ead217b1857a 100644 --- a/drivers/rtc/rtc-s3c.c +++ b/drivers/rtc/rtc-s3c.c @@ -171,8 +171,8 @@ static int s3c_rtc_gettime(struct device *dev, struct rtc_time *rtc_tm) goto retry_get_time; } - pr_debug("read time %02x.%02x.%02x %02x/%02x/%02x\n", - rtc_tm->tm_year, rtc_tm->tm_mon, rtc_tm->tm_mday, + pr_debug("read time %04d.%02d.%02d %02d:%02d:%02d\n", + 1900 + rtc_tm->tm_year, rtc_tm->tm_mon, rtc_tm->tm_mday, rtc_tm->tm_hour, rtc_tm->tm_min, rtc_tm->tm_sec); rtc_tm->tm_sec = bcd2bin(rtc_tm->tm_sec); @@ -193,8 +193,8 @@ static int s3c_rtc_settime(struct device *dev, struct rtc_time *tm) void __iomem *base = s3c_rtc_base; int year = tm->tm_year - 100; - pr_debug("set time %02d.%02d.%02d %02d/%02d/%02d\n", - tm->tm_year, tm->tm_mon, tm->tm_mday, + pr_debug("set time %04d.%02d.%02d %02d:%02d:%02d\n", + 1900 + tm->tm_year, tm->tm_mon, tm->tm_mday, tm->tm_hour, tm->tm_min, tm->tm_sec); /* we get around y2k by simply not supporting it */ @@ -231,9 +231,9 @@ static int s3c_rtc_getalarm(struct device *dev, struct rtc_wkalrm *alrm) alrm->enabled = (alm_en & S3C2410_RTCALM_ALMEN) ? 1 : 0; - pr_debug("read alarm %02x %02x.%02x.%02x %02x/%02x/%02x\n", + pr_debug("read alarm %d, %04d.%02d.%02d %02d:%02d:%02d\n", alm_en, - alm_tm->tm_year, alm_tm->tm_mon, alm_tm->tm_mday, + 1900 + alm_tm->tm_year, alm_tm->tm_mon, alm_tm->tm_mday, alm_tm->tm_hour, alm_tm->tm_min, alm_tm->tm_sec); @@ -280,10 +280,10 @@ static int s3c_rtc_setalarm(struct device *dev, struct rtc_wkalrm *alrm) void __iomem *base = s3c_rtc_base; unsigned int alrm_en; - pr_debug("s3c_rtc_setalarm: %d, %02x/%02x/%02x %02x.%02x.%02x\n", + pr_debug("s3c_rtc_setalarm: %d, %04d.%02d.%02d %02d:%02d:%02d\n", alrm->enabled, - tm->tm_mday & 0xff, tm->tm_mon & 0xff, tm->tm_year & 0xff, - tm->tm_hour & 0xff, tm->tm_min & 0xff, tm->tm_sec); + 1900 + tm->tm_year, tm->tm_mon, tm->tm_mday, + tm->tm_hour, tm->tm_min, tm->tm_sec); alrm_en = readb(base + S3C2410_RTCALM) & S3C2410_RTCALM_ALMEN; -- cgit v1.2.2 From e1df962e6cdc431acb6a8da409b6a7d89c4f782e Mon Sep 17 00:00:00 2001 From: Changhwan Youn Date: Wed, 27 Oct 2010 15:33:10 -0700 Subject: rtc: rtc-s3c: fix RTC initialization method Change RTC initialization method in probe(). The 'rtc_valid_tm(tm)' can check whether RTC BCD is valid or not. And change the method of checking because the previous method cannot validate RTC BCD registers properly. Signed-off-by: Changhwan Youn Signed-off-by: Kukjin Kim Cc: Ben Dooks Cc: Wan ZongShun Cc: Alessandro Zummo Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/rtc/rtc-s3c.c | 18 +++++++++++++----- 1 file changed, 13 insertions(+), 5 deletions(-) (limited to 'drivers/rtc') diff --git a/drivers/rtc/rtc-s3c.c b/drivers/rtc/rtc-s3c.c index ead217b1857a..d0498a223f40 100644 --- a/drivers/rtc/rtc-s3c.c +++ b/drivers/rtc/rtc-s3c.c @@ -456,8 +456,8 @@ static int __devexit s3c_rtc_remove(struct platform_device *dev) static int __devinit s3c_rtc_probe(struct platform_device *pdev) { struct rtc_device *rtc; + struct rtc_time rtc_tm; struct resource *res; - unsigned int tmp, i; int ret; pr_debug("%s: probe=%p\n", __func__, pdev); @@ -538,11 +538,19 @@ static int __devinit s3c_rtc_probe(struct platform_device *pdev) /* Check RTC Time */ - for (i = S3C2410_RTCSEC; i <= S3C2410_RTCYEAR; i += 0x4) { - tmp = readb(s3c_rtc_base + i); + s3c_rtc_gettime(NULL, &rtc_tm); - if ((tmp & 0xf) > 0x9 || ((tmp >> 4) & 0xf) > 0x9) - writeb(0, s3c_rtc_base + i); + if (rtc_valid_tm(&rtc_tm)) { + rtc_tm.tm_year = 100; + rtc_tm.tm_mon = 0; + rtc_tm.tm_mday = 1; + rtc_tm.tm_hour = 0; + rtc_tm.tm_min = 0; + rtc_tm.tm_sec = 0; + + s3c_rtc_settime(NULL, &rtc_tm); + + dev_warn(&pdev->dev, "warning: invalid RTC value so initializing it\n"); } if (s3c_rtc_cpu_type == TYPE_S3C64XX) -- cgit v1.2.2 From 5b3ffddd8ddb4712dfe14ad3e23eb5494f11bf61 Mon Sep 17 00:00:00 2001 From: Kukjin Kim Date: Wed, 27 Oct 2010 15:33:11 -0700 Subject: rtc: rtc-s3c: add rtc_valid_tm in s3c_rtc_gettime() Add "rtc_valid_tm" in s3c_rtc_gettime() as per Wan ZongShun's suggestion. Suggested-by: Wan ZongShun Signed-off-by: Kukjin Kim Cc: Ben Dooks Cc: Alessandro Zummo Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/rtc/rtc-s3c.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/rtc') diff --git a/drivers/rtc/rtc-s3c.c b/drivers/rtc/rtc-s3c.c index d0498a223f40..cf953ecbfca9 100644 --- a/drivers/rtc/rtc-s3c.c +++ b/drivers/rtc/rtc-s3c.c @@ -185,7 +185,7 @@ static int s3c_rtc_gettime(struct device *dev, struct rtc_time *rtc_tm) rtc_tm->tm_year += 100; rtc_tm->tm_mon -= 1; - return 0; + return rtc_valid_tm(rtc_tm); } static int s3c_rtc_settime(struct device *dev, struct rtc_time *tm) -- cgit v1.2.2 From f46418c5cadfe76b15c630ff746ca859a8207d71 Mon Sep 17 00:00:00 2001 From: Lan Chunhe-B25806 Date: Wed, 27 Oct 2010 15:33:12 -0700 Subject: drivers/rtc/rtc-ds3232.c: add alarm function The DS3232 RTC driver only has the tick function. Add an alarm function so the driver is complete. Signed-off-by: Lan Chunhe-B25806 Cc: Alessandro Zummo Cc: Wan ZongShun Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/rtc/Kconfig | 3 +- drivers/rtc/rtc-ds3232.c | 181 +++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 183 insertions(+), 1 deletion(-) (limited to 'drivers/rtc') diff --git a/drivers/rtc/Kconfig b/drivers/rtc/Kconfig index 636ba8224884..6a77437d4f5a 100644 --- a/drivers/rtc/Kconfig +++ b/drivers/rtc/Kconfig @@ -171,7 +171,8 @@ config RTC_DRV_DS3232 depends on RTC_CLASS && I2C help If you say yes here you get support for Dallas Semiconductor - DS3232 real-time clock chips. + DS3232 real-time clock chips. If an interrupt is associated + with the device, the alarm functionality is supported. This driver can also be built as a module. If so, the module will be called rtc-ds3232. diff --git a/drivers/rtc/rtc-ds3232.c b/drivers/rtc/rtc-ds3232.c index 9de8516e3531..57063552d3b7 100644 --- a/drivers/rtc/rtc-ds3232.c +++ b/drivers/rtc/rtc-ds3232.c @@ -2,6 +2,7 @@ * RTC client/driver for the Maxim/Dallas DS3232 Real-Time Clock over I2C * * Copyright (C) 2009-2010 Freescale Semiconductor. + * Author: Jack Lan * * 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 @@ -175,6 +176,182 @@ static int ds3232_set_time(struct device *dev, struct rtc_time *time) DS3232_REG_SECONDS, 7, buf); } +/* + * DS3232 has two alarm, we only use alarm1 + * According to linux specification, only support one-shot alarm + * no periodic alarm mode + */ +static int ds3232_read_alarm(struct device *dev, struct rtc_wkalrm *alarm) +{ + struct i2c_client *client = to_i2c_client(dev); + struct ds3232 *ds3232 = i2c_get_clientdata(client); + int control, stat; + int ret; + u8 buf[4]; + + mutex_lock(&ds3232->mutex); + + ret = i2c_smbus_read_byte_data(client, DS3232_REG_SR); + if (ret < 0) + goto out; + stat = ret; + ret = i2c_smbus_read_byte_data(client, DS3232_REG_CR); + if (ret < 0) + goto out; + control = ret; + ret = i2c_smbus_read_i2c_block_data(client, DS3232_REG_ALARM1, 4, buf); + if (ret < 0) + goto out; + + alarm->time.tm_sec = bcd2bin(buf[0] & 0x7F); + alarm->time.tm_min = bcd2bin(buf[1] & 0x7F); + alarm->time.tm_hour = bcd2bin(buf[2] & 0x7F); + alarm->time.tm_mday = bcd2bin(buf[3] & 0x7F); + + alarm->time.tm_mon = -1; + alarm->time.tm_year = -1; + alarm->time.tm_wday = -1; + alarm->time.tm_yday = -1; + alarm->time.tm_isdst = -1; + + alarm->enabled = !!(control & DS3232_REG_CR_A1IE); + alarm->pending = !!(stat & DS3232_REG_SR_A1F); + + ret = 0; +out: + mutex_unlock(&ds3232->mutex); + return ret; +} + +/* + * linux rtc-module does not support wday alarm + * and only 24h time mode supported indeed + */ +static int ds3232_set_alarm(struct device *dev, struct rtc_wkalrm *alarm) +{ + struct i2c_client *client = to_i2c_client(dev); + struct ds3232 *ds3232 = i2c_get_clientdata(client); + int control, stat; + int ret; + u8 buf[4]; + + if (client->irq <= 0) + return -EINVAL; + + mutex_lock(&ds3232->mutex); + + buf[0] = bin2bcd(alarm->time.tm_sec); + buf[1] = bin2bcd(alarm->time.tm_min); + buf[2] = bin2bcd(alarm->time.tm_hour); + buf[3] = bin2bcd(alarm->time.tm_mday); + + /* clear alarm interrupt enable bit */ + ret = i2c_smbus_read_byte_data(client, DS3232_REG_CR); + if (ret < 0) + goto out; + control = ret; + control &= ~(DS3232_REG_CR_A1IE | DS3232_REG_CR_A2IE); + ret = i2c_smbus_write_byte_data(client, DS3232_REG_CR, control); + if (ret < 0) + goto out; + + /* clear any pending alarm flag */ + ret = i2c_smbus_read_byte_data(client, DS3232_REG_SR); + if (ret < 0) + goto out; + stat = ret; + stat &= ~(DS3232_REG_SR_A1F | DS3232_REG_SR_A2F); + ret = i2c_smbus_write_byte_data(client, DS3232_REG_SR, stat); + if (ret < 0) + goto out; + + ret = i2c_smbus_write_i2c_block_data(client, DS3232_REG_ALARM1, 4, buf); + + if (alarm->enabled) { + control |= DS3232_REG_CR_A1IE; + ret = i2c_smbus_write_byte_data(client, DS3232_REG_CR, control); + } +out: + mutex_unlock(&ds3232->mutex); + return ret; +} + +static void ds3232_update_alarm(struct i2c_client *client) +{ + struct ds3232 *ds3232 = i2c_get_clientdata(client); + int control; + int ret; + u8 buf[4]; + + mutex_lock(&ds3232->mutex); + + ret = i2c_smbus_read_i2c_block_data(client, DS3232_REG_ALARM1, 4, buf); + if (ret < 0) + goto unlock; + + buf[0] = bcd2bin(buf[0]) < 0 || (ds3232->rtc->irq_data & RTC_UF) ? + 0x80 : buf[0]; + buf[1] = bcd2bin(buf[1]) < 0 || (ds3232->rtc->irq_data & RTC_UF) ? + 0x80 : buf[1]; + buf[2] = bcd2bin(buf[2]) < 0 || (ds3232->rtc->irq_data & RTC_UF) ? + 0x80 : buf[2]; + buf[3] = bcd2bin(buf[3]) < 0 || (ds3232->rtc->irq_data & RTC_UF) ? + 0x80 : buf[3]; + + ret = i2c_smbus_write_i2c_block_data(client, DS3232_REG_ALARM1, 4, buf); + if (ret < 0) + goto unlock; + + control = i2c_smbus_read_byte_data(client, DS3232_REG_CR); + if (control < 0) + goto unlock; + + if (ds3232->rtc->irq_data & (RTC_AF | RTC_UF)) + /* enable alarm1 interrupt */ + control |= DS3232_REG_CR_A1IE; + else + /* disable alarm1 interrupt */ + control &= ~(DS3232_REG_CR_A1IE); + i2c_smbus_write_byte_data(client, DS3232_REG_CR, control); + +unlock: + mutex_unlock(&ds3232->mutex); +} + +static int ds3232_alarm_irq_enable(struct device *dev, unsigned int enabled) +{ + struct i2c_client *client = to_i2c_client(dev); + struct ds3232 *ds3232 = i2c_get_clientdata(client); + + if (client->irq <= 0) + return -EINVAL; + + if (enabled) + ds3232->rtc->irq_data |= RTC_AF; + else + ds3232->rtc->irq_data &= ~RTC_AF; + + ds3232_update_alarm(client); + return 0; +} + +static int ds3232_update_irq_enable(struct device *dev, unsigned int enabled) +{ + struct i2c_client *client = to_i2c_client(dev); + struct ds3232 *ds3232 = i2c_get_clientdata(client); + + if (client->irq <= 0) + return -EINVAL; + + if (enabled) + ds3232->rtc->irq_data |= RTC_UF; + else + ds3232->rtc->irq_data &= ~RTC_UF; + + ds3232_update_alarm(client); + return 0; +} + static irqreturn_t ds3232_irq(int irq, void *dev_id) { struct i2c_client *client = dev_id; @@ -222,6 +399,10 @@ unlock: static const struct rtc_class_ops ds3232_rtc_ops = { .read_time = ds3232_read_time, .set_time = ds3232_set_time, + .read_alarm = ds3232_read_alarm, + .set_alarm = ds3232_set_alarm, + .alarm_irq_enable = ds3232_alarm_irq_enable, + .update_irq_enable = ds3232_update_irq_enable, }; static int __devinit ds3232_probe(struct i2c_client *client, -- cgit v1.2.2 From d0f744c8cbd19a8d07eccb15bb08e6a29c4d5192 Mon Sep 17 00:00:00 2001 From: Paul Cercueil Date: Wed, 27 Oct 2010 15:33:12 -0700 Subject: drivers/rtc/rtc-jz4740.c: add alarm function Add the "alarm" function to the jz4740 RTC. Interrupts will now be raised when the "alarm" time is reached. [akpm@linux-foundation.org: coding-style fixes] Signed-off-by: Paul Cercueil Cc: Wan ZongShun Cc: Alessandro Zummo Cc: Lars-Peter Clausen Cc: Paul Gortmaker Cc: Ralf Baechle Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/rtc/rtc-jz4740.c | 45 ++++++++++++++++++++++++++++++++++++++++----- 1 file changed, 40 insertions(+), 5 deletions(-) (limited to 'drivers/rtc') diff --git a/drivers/rtc/rtc-jz4740.c b/drivers/rtc/rtc-jz4740.c index 2619d57b91d7..2e16f72c9056 100644 --- a/drivers/rtc/rtc-jz4740.c +++ b/drivers/rtc/rtc-jz4740.c @@ -1,5 +1,6 @@ /* * Copyright (C) 2009-2010, Lars-Peter Clausen + * Copyright (C) 2010, Paul Cercueil * JZ4740 SoC RTC driver * * This program is free software; you can redistribute it and/or modify it @@ -161,7 +162,8 @@ static int jz4740_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alrm) ret = jz4740_rtc_reg_write(rtc, JZ_REG_RTC_SEC_ALARM, secs); if (!ret) - ret = jz4740_rtc_ctrl_set_bits(rtc, JZ_RTC_CTRL_AE, alrm->enabled); + ret = jz4740_rtc_ctrl_set_bits(rtc, + JZ_RTC_CTRL_AE | JZ_RTC_CTRL_AF_IRQ, alrm->enabled); return ret; } @@ -258,6 +260,8 @@ static int __devinit jz4740_rtc_probe(struct platform_device *pdev) platform_set_drvdata(pdev, rtc); + device_init_wakeup(&pdev->dev, 1); + rtc->rtc = rtc_device_register(pdev->name, &pdev->dev, &jz4740_rtc_ops, THIS_MODULE); if (IS_ERR(rtc->rtc)) { @@ -318,12 +322,43 @@ static int __devexit jz4740_rtc_remove(struct platform_device *pdev) return 0; } + +#ifdef CONFIG_PM +static int jz4740_rtc_suspend(struct device *dev) +{ + struct jz4740_rtc *rtc = dev_get_drvdata(dev); + + if (device_may_wakeup(dev)) + enable_irq_wake(rtc->irq); + return 0; +} + +static int jz4740_rtc_resume(struct device *dev) +{ + struct jz4740_rtc *rtc = dev_get_drvdata(dev); + + if (device_may_wakeup(dev)) + disable_irq_wake(rtc->irq); + return 0; +} + +static const struct dev_pm_ops jz4740_pm_ops = { + .suspend = jz4740_rtc_suspend, + .resume = jz4740_rtc_resume, +}; +#define JZ4740_RTC_PM_OPS (&jz4740_pm_ops) + +#else +#define JZ4740_RTC_PM_OPS NULL +#endif /* CONFIG_PM */ + struct platform_driver jz4740_rtc_driver = { - .probe = jz4740_rtc_probe, - .remove = __devexit_p(jz4740_rtc_remove), - .driver = { - .name = "jz4740-rtc", + .probe = jz4740_rtc_probe, + .remove = __devexit_p(jz4740_rtc_remove), + .driver = { + .name = "jz4740-rtc", .owner = THIS_MODULE, + .pm = JZ4740_RTC_PM_OPS, }, }; -- cgit v1.2.2 From 9b16c0a43b74393cc18666a7748293812c61af1f Mon Sep 17 00:00:00 2001 From: Joonyoung Shim Date: Fri, 6 Aug 2010 11:28:08 +0900 Subject: rtc: Add MAX8998 rtc driver This adds support for the RTC provided by the Maxim 8998 chip. This driver was tested on a GONI board by using the rtc-test application from the Documentation/rtc.txt. Signed-off-by: Joonyoung Shim Signed-off-by: Kyungmin Park Acked-by: Alessandro Zummo Signed-off-by: Samuel Ortiz --- drivers/rtc/Kconfig | 10 ++ drivers/rtc/Makefile | 1 + drivers/rtc/rtc-max8998.c | 300 ++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 311 insertions(+) create mode 100644 drivers/rtc/rtc-max8998.c (limited to 'drivers/rtc') diff --git a/drivers/rtc/Kconfig b/drivers/rtc/Kconfig index 6a77437d4f5a..23579d6e4a6e 100644 --- a/drivers/rtc/Kconfig +++ b/drivers/rtc/Kconfig @@ -196,6 +196,16 @@ config RTC_DRV_MAX8925 This driver can also be built as a module. If so, the module will be called rtc-max8925. +config RTC_DRV_MAX8998 + tristate "Maxim MAX8998" + depends on MFD_MAX8998 + help + If you say yes here you will get support for the + RTC of Maxim MAX8998 PMIC. + + This driver can also be built as a module. If so, the module + will be called rtc-max8998. + config RTC_DRV_RS5C372 tristate "Ricoh R2025S/D, RS5C372A/B, RV5C386, RV5C387A" help diff --git a/drivers/rtc/Makefile b/drivers/rtc/Makefile index 7a7cb3228a1d..c3f3c2d9e1ed 100644 --- a/drivers/rtc/Makefile +++ b/drivers/rtc/Makefile @@ -60,6 +60,7 @@ 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_MAX8998) += rtc-max8998.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-max8998.c b/drivers/rtc/rtc-max8998.c new file mode 100644 index 000000000000..f22dee35f330 --- /dev/null +++ b/drivers/rtc/rtc-max8998.c @@ -0,0 +1,300 @@ +/* + * RTC driver for Maxim MAX8998 + * + * Copyright (C) 2010 Samsung Electronics Co.Ltd + * Author: Minkyu Kang + * Author: Joonyoung Shim + * + * 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 +#include +#include + +#define MAX8998_RTC_SEC 0x00 +#define MAX8998_RTC_MIN 0x01 +#define MAX8998_RTC_HOUR 0x02 +#define MAX8998_RTC_WEEKDAY 0x03 +#define MAX8998_RTC_DATE 0x04 +#define MAX8998_RTC_MONTH 0x05 +#define MAX8998_RTC_YEAR1 0x06 +#define MAX8998_RTC_YEAR2 0x07 +#define MAX8998_ALARM0_SEC 0x08 +#define MAX8998_ALARM0_MIN 0x09 +#define MAX8998_ALARM0_HOUR 0x0a +#define MAX8998_ALARM0_WEEKDAY 0x0b +#define MAX8998_ALARM0_DATE 0x0c +#define MAX8998_ALARM0_MONTH 0x0d +#define MAX8998_ALARM0_YEAR1 0x0e +#define MAX8998_ALARM0_YEAR2 0x0f +#define MAX8998_ALARM1_SEC 0x10 +#define MAX8998_ALARM1_MIN 0x11 +#define MAX8998_ALARM1_HOUR 0x12 +#define MAX8998_ALARM1_WEEKDAY 0x13 +#define MAX8998_ALARM1_DATE 0x14 +#define MAX8998_ALARM1_MONTH 0x15 +#define MAX8998_ALARM1_YEAR1 0x16 +#define MAX8998_ALARM1_YEAR2 0x17 +#define MAX8998_ALARM0_CONF 0x18 +#define MAX8998_ALARM1_CONF 0x19 +#define MAX8998_RTC_STATUS 0x1a +#define MAX8998_WTSR_SMPL_CNTL 0x1b +#define MAX8998_TEST 0x1f + +#define HOUR_12 (1 << 7) +#define HOUR_PM (1 << 5) +#define ALARM0_STATUS (1 << 1) +#define ALARM1_STATUS (1 << 2) + +enum { + RTC_SEC = 0, + RTC_MIN, + RTC_HOUR, + RTC_WEEKDAY, + RTC_DATE, + RTC_MONTH, + RTC_YEAR1, + RTC_YEAR2, +}; + +struct max8998_rtc_info { + struct device *dev; + struct max8998_dev *max8998; + struct i2c_client *rtc; + struct rtc_device *rtc_dev; + int irq; +}; + +static void max8998_data_to_tm(u8 *data, struct rtc_time *tm) +{ + tm->tm_sec = bcd2bin(data[RTC_SEC]); + tm->tm_min = bcd2bin(data[RTC_MIN]); + if (data[RTC_HOUR] & HOUR_12) { + tm->tm_hour = bcd2bin(data[RTC_HOUR] & 0x1f); + if (data[RTC_HOUR] & HOUR_PM) + tm->tm_hour += 12; + } else + tm->tm_hour = bcd2bin(data[RTC_HOUR] & 0x3f); + + tm->tm_wday = data[RTC_WEEKDAY] & 0x07; + tm->tm_mday = bcd2bin(data[RTC_DATE]); + tm->tm_mon = bcd2bin(data[RTC_MONTH]); + tm->tm_year = bcd2bin(data[RTC_YEAR1]) + bcd2bin(data[RTC_YEAR2]) * 100; + tm->tm_year -= 1900; +} + +static void max8998_tm_to_data(struct rtc_time *tm, u8 *data) +{ + data[RTC_SEC] = bin2bcd(tm->tm_sec); + data[RTC_MIN] = bin2bcd(tm->tm_min); + data[RTC_HOUR] = bin2bcd(tm->tm_hour); + data[RTC_WEEKDAY] = tm->tm_wday; + data[RTC_DATE] = bin2bcd(tm->tm_mday); + data[RTC_MONTH] = bin2bcd(tm->tm_mon); + data[RTC_YEAR1] = bin2bcd(tm->tm_year % 100); + data[RTC_YEAR2] = bin2bcd((tm->tm_year + 1900) / 100); +} + +static int max8998_rtc_read_time(struct device *dev, struct rtc_time *tm) +{ + struct max8998_rtc_info *info = dev_get_drvdata(dev); + u8 data[8]; + int ret; + + ret = max8998_bulk_read(info->rtc, MAX8998_RTC_SEC, 8, data); + if (ret < 0) + return ret; + + max8998_data_to_tm(data, tm); + + return rtc_valid_tm(tm); +} + +static int max8998_rtc_set_time(struct device *dev, struct rtc_time *tm) +{ + struct max8998_rtc_info *info = dev_get_drvdata(dev); + u8 data[8]; + + max8998_tm_to_data(tm, data); + + return max8998_bulk_write(info->rtc, MAX8998_RTC_SEC, 8, data); +} + +static int max8998_rtc_read_alarm(struct device *dev, struct rtc_wkalrm *alrm) +{ + struct max8998_rtc_info *info = dev_get_drvdata(dev); + u8 data[8]; + u8 val; + int ret; + + ret = max8998_bulk_read(info->rtc, MAX8998_ALARM0_SEC, 8, data); + if (ret < 0) + return ret; + + max8998_data_to_tm(data, &alrm->time); + + ret = max8998_read_reg(info->rtc, MAX8998_ALARM0_CONF, &val); + if (ret < 0) + return ret; + + alrm->enabled = !!val; + + ret = max8998_read_reg(info->rtc, MAX8998_RTC_STATUS, &val); + if (ret < 0) + return ret; + + if (val & ALARM0_STATUS) + alrm->pending = 1; + else + alrm->pending = 0; + + return 0; +} + +static int max8998_rtc_stop_alarm(struct max8998_rtc_info *info) +{ + return max8998_write_reg(info->rtc, MAX8998_ALARM0_CONF, 0); +} + +static int max8998_rtc_start_alarm(struct max8998_rtc_info *info) +{ + return max8998_write_reg(info->rtc, MAX8998_ALARM0_CONF, 0x77); +} + +static int max8998_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alrm) +{ + struct max8998_rtc_info *info = dev_get_drvdata(dev); + u8 data[8]; + int ret; + + max8998_tm_to_data(&alrm->time, data); + + ret = max8998_rtc_stop_alarm(info); + if (ret < 0) + return ret; + + ret = max8998_bulk_write(info->rtc, MAX8998_ALARM0_SEC, 8, data); + if (ret < 0) + return ret; + + if (alrm->enabled) + return max8998_rtc_start_alarm(info); + + return 0; +} + +static int max8998_rtc_alarm_irq_enable(struct device *dev, + unsigned int enabled) +{ + struct max8998_rtc_info *info = dev_get_drvdata(dev); + + if (enabled) + return max8998_rtc_start_alarm(info); + else + return max8998_rtc_stop_alarm(info); +} + +static irqreturn_t max8998_rtc_alarm_irq(int irq, void *data) +{ + struct max8998_rtc_info *info = data; + + rtc_update_irq(info->rtc_dev, 1, RTC_IRQF | RTC_AF); + + return IRQ_HANDLED; +} + +static const struct rtc_class_ops max8998_rtc_ops = { + .read_time = max8998_rtc_read_time, + .set_time = max8998_rtc_set_time, + .read_alarm = max8998_rtc_read_alarm, + .set_alarm = max8998_rtc_set_alarm, + .alarm_irq_enable = max8998_rtc_alarm_irq_enable, +}; + +static int __devinit max8998_rtc_probe(struct platform_device *pdev) +{ + struct max8998_dev *max8998 = dev_get_drvdata(pdev->dev.parent); + struct max8998_rtc_info *info; + int ret; + + info = kzalloc(sizeof(struct max8998_rtc_info), GFP_KERNEL); + if (!info) + return -ENOMEM; + + info->dev = &pdev->dev; + info->max8998 = max8998; + info->rtc = max8998->rtc; + info->irq = max8998->irq_base + MAX8998_IRQ_ALARM0; + + info->rtc_dev = rtc_device_register("max8998-rtc", &pdev->dev, + &max8998_rtc_ops, THIS_MODULE); + + if (IS_ERR(info->rtc_dev)) { + ret = PTR_ERR(info->rtc_dev); + dev_err(&pdev->dev, "Failed to register RTC device: %d\n", ret); + goto out_rtc; + } + + platform_set_drvdata(pdev, info); + + ret = request_threaded_irq(info->irq, NULL, max8998_rtc_alarm_irq, 0, + "rtc-alarm0", info); + if (ret < 0) + dev_err(&pdev->dev, "Failed to request alarm IRQ: %d: %d\n", + info->irq, ret); + + return 0; + +out_rtc: + kfree(info); + return ret; +} + +static int __devexit max8998_rtc_remove(struct platform_device *pdev) +{ + struct max8998_rtc_info *info = platform_get_drvdata(pdev); + + if (info) { + free_irq(info->irq, info); + rtc_device_unregister(info->rtc_dev); + kfree(info); + } + + return 0; +} + +static struct platform_driver max8998_rtc_driver = { + .driver = { + .name = "max8998-rtc", + .owner = THIS_MODULE, + }, + .probe = max8998_rtc_probe, + .remove = __devexit_p(max8998_rtc_remove), +}; + +static int __init max8998_rtc_init(void) +{ + return platform_driver_register(&max8998_rtc_driver); +} +module_init(max8998_rtc_init); + +static void __exit max8998_rtc_exit(void) +{ + platform_driver_unregister(&max8998_rtc_driver); +} +module_exit(max8998_rtc_exit); + +MODULE_AUTHOR("Minkyu Kang "); +MODULE_AUTHOR("Joonyoung Shim "); +MODULE_DESCRIPTION("Maxim MAX8998 RTC driver"); +MODULE_LICENSE("GPL"); -- cgit v1.2.2 From 47c1697508f2ec9f6b31ce6c825fe1017871dea6 Mon Sep 17 00:00:00 2001 From: Mattias Wallin Date: Fri, 10 Sep 2010 17:47:56 +0200 Subject: mfd: Align ab8500 with the abx500 interface This patch makes the ab8500 mixed signal chip expose the same interface for register access as the ab3100, ab3550 and ab5500 chip. The ab8500_read() and ab8500_write() is removed and replaced with abx500_get_register_interruptible() and abx500_set_register_interruptible(). Signed-off-by: Mattias Wallin Acked-by: Linus Walleij Acked-by: Mark Brown Signed-off-by: Samuel Ortiz --- drivers/rtc/rtc-ab8500.c | 103 ++++++++++++++++++++++++----------------------- 1 file changed, 53 insertions(+), 50 deletions(-) (limited to 'drivers/rtc') diff --git a/drivers/rtc/rtc-ab8500.c b/drivers/rtc/rtc-ab8500.c index 2fda03125e55..e346705aae92 100644 --- a/drivers/rtc/rtc-ab8500.c +++ b/drivers/rtc/rtc-ab8500.c @@ -14,26 +14,26 @@ #include #include #include +#include #include #include -#define AB8500_RTC_SOFF_STAT_REG 0x0F00 -#define AB8500_RTC_CC_CONF_REG 0x0F01 -#define AB8500_RTC_READ_REQ_REG 0x0F02 -#define AB8500_RTC_WATCH_TSECMID_REG 0x0F03 -#define AB8500_RTC_WATCH_TSECHI_REG 0x0F04 -#define AB8500_RTC_WATCH_TMIN_LOW_REG 0x0F05 -#define AB8500_RTC_WATCH_TMIN_MID_REG 0x0F06 -#define AB8500_RTC_WATCH_TMIN_HI_REG 0x0F07 -#define AB8500_RTC_ALRM_MIN_LOW_REG 0x0F08 -#define AB8500_RTC_ALRM_MIN_MID_REG 0x0F09 -#define AB8500_RTC_ALRM_MIN_HI_REG 0x0F0A -#define AB8500_RTC_STAT_REG 0x0F0B -#define AB8500_RTC_BKUP_CHG_REG 0x0F0C -#define AB8500_RTC_FORCE_BKUP_REG 0x0F0D -#define AB8500_RTC_CALIB_REG 0x0F0E -#define AB8500_RTC_SWITCH_STAT_REG 0x0F0F -#define AB8500_REV_REG 0x1080 +#define AB8500_RTC_SOFF_STAT_REG 0x00 +#define AB8500_RTC_CC_CONF_REG 0x01 +#define AB8500_RTC_READ_REQ_REG 0x02 +#define AB8500_RTC_WATCH_TSECMID_REG 0x03 +#define AB8500_RTC_WATCH_TSECHI_REG 0x04 +#define AB8500_RTC_WATCH_TMIN_LOW_REG 0x05 +#define AB8500_RTC_WATCH_TMIN_MID_REG 0x06 +#define AB8500_RTC_WATCH_TMIN_HI_REG 0x07 +#define AB8500_RTC_ALRM_MIN_LOW_REG 0x08 +#define AB8500_RTC_ALRM_MIN_MID_REG 0x09 +#define AB8500_RTC_ALRM_MIN_HI_REG 0x0A +#define AB8500_RTC_STAT_REG 0x0B +#define AB8500_RTC_BKUP_CHG_REG 0x0C +#define AB8500_RTC_FORCE_BKUP_REG 0x0D +#define AB8500_RTC_CALIB_REG 0x0E +#define AB8500_RTC_SWITCH_STAT_REG 0x0F /* RtcReadRequest bits */ #define RTC_READ_REQUEST 0x01 @@ -46,13 +46,13 @@ #define COUNTS_PER_SEC (0xF000 / 60) #define AB8500_RTC_EPOCH 2000 -static const unsigned long ab8500_rtc_time_regs[] = { +static const u8 ab8500_rtc_time_regs[] = { AB8500_RTC_WATCH_TMIN_HI_REG, AB8500_RTC_WATCH_TMIN_MID_REG, AB8500_RTC_WATCH_TMIN_LOW_REG, AB8500_RTC_WATCH_TSECHI_REG, AB8500_RTC_WATCH_TSECMID_REG }; -static const unsigned long ab8500_rtc_alarm_regs[] = { +static const u8 ab8500_rtc_alarm_regs[] = { AB8500_RTC_ALRM_MIN_HI_REG, AB8500_RTC_ALRM_MIN_MID_REG, AB8500_RTC_ALRM_MIN_LOW_REG }; @@ -76,29 +76,30 @@ static unsigned long get_elapsed_seconds(int year) static int ab8500_rtc_read_time(struct device *dev, struct rtc_time *tm) { - struct ab8500 *ab8500 = dev_get_drvdata(dev->parent); unsigned long timeout = jiffies + HZ; int retval, i; unsigned long mins, secs; unsigned char buf[ARRAY_SIZE(ab8500_rtc_time_regs)]; + u8 value; /* Request a data read */ - retval = ab8500_write(ab8500, AB8500_RTC_READ_REQ_REG, - RTC_READ_REQUEST); + retval = abx500_set_register_interruptible(dev, + AB8500_RTC, AB8500_RTC_READ_REQ_REG, RTC_READ_REQUEST); if (retval < 0) return retval; /* Early AB8500 chips will not clear the rtc read request bit */ - if (ab8500->revision == 0) { + if (abx500_get_chip_id(dev) == 0) { msleep(1); } else { /* Wait for some cycles after enabling the rtc read in ab8500 */ while (time_before(jiffies, timeout)) { - retval = ab8500_read(ab8500, AB8500_RTC_READ_REQ_REG); + retval = abx500_get_register_interruptible(dev, + AB8500_RTC, AB8500_RTC_READ_REQ_REG, &value); if (retval < 0) return retval; - if (!(retval & RTC_READ_REQUEST)) + if (!(value & RTC_READ_REQUEST)) break; msleep(1); @@ -107,10 +108,11 @@ static int ab8500_rtc_read_time(struct device *dev, struct rtc_time *tm) /* Read the Watchtime registers */ for (i = 0; i < ARRAY_SIZE(ab8500_rtc_time_regs); i++) { - retval = ab8500_read(ab8500, ab8500_rtc_time_regs[i]); + retval = abx500_get_register_interruptible(dev, + AB8500_RTC, ab8500_rtc_time_regs[i], &value); if (retval < 0) return retval; - buf[i] = retval; + buf[i] = value; } mins = (buf[0] << 16) | (buf[1] << 8) | buf[2]; @@ -128,7 +130,6 @@ static int ab8500_rtc_read_time(struct device *dev, struct rtc_time *tm) static int ab8500_rtc_set_time(struct device *dev, struct rtc_time *tm) { - struct ab8500 *ab8500 = dev_get_drvdata(dev->parent); int retval, i; unsigned char buf[ARRAY_SIZE(ab8500_rtc_time_regs)]; unsigned long no_secs, no_mins, secs = 0; @@ -162,27 +163,29 @@ static int ab8500_rtc_set_time(struct device *dev, struct rtc_time *tm) buf[0] = (no_mins >> 16) & 0xFF; for (i = 0; i < ARRAY_SIZE(ab8500_rtc_time_regs); i++) { - retval = ab8500_write(ab8500, ab8500_rtc_time_regs[i], buf[i]); + retval = abx500_set_register_interruptible(dev, AB8500_RTC, + ab8500_rtc_time_regs[i], buf[i]); if (retval < 0) return retval; } /* Request a data write */ - return ab8500_write(ab8500, AB8500_RTC_READ_REQ_REG, RTC_WRITE_REQUEST); + return abx500_set_register_interruptible(dev, AB8500_RTC, + AB8500_RTC_READ_REQ_REG, RTC_WRITE_REQUEST); } static int ab8500_rtc_read_alarm(struct device *dev, struct rtc_wkalrm *alarm) { - struct ab8500 *ab8500 = dev_get_drvdata(dev->parent); int retval, i; - int rtc_ctrl; + u8 rtc_ctrl, value; unsigned char buf[ARRAY_SIZE(ab8500_rtc_alarm_regs)]; unsigned long secs, mins; /* Check if the alarm is enabled or not */ - rtc_ctrl = ab8500_read(ab8500, AB8500_RTC_STAT_REG); - if (rtc_ctrl < 0) - return rtc_ctrl; + retval = abx500_get_register_interruptible(dev, AB8500_RTC, + AB8500_RTC_STAT_REG, &rtc_ctrl); + if (retval < 0) + return retval; if (rtc_ctrl & RTC_ALARM_ENA) alarm->enabled = 1; @@ -192,10 +195,11 @@ static int ab8500_rtc_read_alarm(struct device *dev, struct rtc_wkalrm *alarm) alarm->pending = 0; for (i = 0; i < ARRAY_SIZE(ab8500_rtc_alarm_regs); i++) { - retval = ab8500_read(ab8500, ab8500_rtc_alarm_regs[i]); + retval = abx500_get_register_interruptible(dev, AB8500_RTC, + ab8500_rtc_alarm_regs[i], &value); if (retval < 0) return retval; - buf[i] = retval; + buf[i] = value; } mins = (buf[0] << 16) | (buf[1] << 8) | (buf[2]); @@ -211,15 +215,13 @@ static int ab8500_rtc_read_alarm(struct device *dev, struct rtc_wkalrm *alarm) static int ab8500_rtc_irq_enable(struct device *dev, unsigned int enabled) { - struct ab8500 *ab8500 = dev_get_drvdata(dev->parent); - - return ab8500_set_bits(ab8500, AB8500_RTC_STAT_REG, RTC_ALARM_ENA, - enabled ? RTC_ALARM_ENA : 0); + return abx500_mask_and_set_register_interruptible(dev, AB8500_RTC, + AB8500_RTC_STAT_REG, RTC_ALARM_ENA, + enabled ? RTC_ALARM_ENA : 0); } static int ab8500_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alarm) { - struct ab8500 *ab8500 = dev_get_drvdata(dev->parent); int retval, i; unsigned char buf[ARRAY_SIZE(ab8500_rtc_alarm_regs)]; unsigned long mins, secs = 0; @@ -247,7 +249,8 @@ static int ab8500_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alarm) /* Set the alarm time */ for (i = 0; i < ARRAY_SIZE(ab8500_rtc_alarm_regs); i++) { - retval = ab8500_write(ab8500, ab8500_rtc_alarm_regs[i], buf[i]); + retval = abx500_set_register_interruptible(dev, AB8500_RTC, + ab8500_rtc_alarm_regs[i], buf[i]); if (retval < 0) return retval; } @@ -276,10 +279,9 @@ static const struct rtc_class_ops ab8500_rtc_ops = { static int __devinit ab8500_rtc_probe(struct platform_device *pdev) { - struct ab8500 *ab8500 = dev_get_drvdata(pdev->dev.parent); int err; struct rtc_device *rtc; - int rtc_ctrl; + u8 rtc_ctrl; int irq; irq = platform_get_irq_byname(pdev, "ALARM"); @@ -287,17 +289,18 @@ static int __devinit ab8500_rtc_probe(struct platform_device *pdev) return irq; /* For RTC supply test */ - err = ab8500_set_bits(ab8500, AB8500_RTC_STAT_REG, RTC_STATUS_DATA, - RTC_STATUS_DATA); + err = abx500_mask_and_set_register_interruptible(&pdev->dev, AB8500_RTC, + AB8500_RTC_STAT_REG, RTC_STATUS_DATA, RTC_STATUS_DATA); if (err < 0) return err; /* Wait for reset by the PorRtc */ msleep(1); - rtc_ctrl = ab8500_read(ab8500, AB8500_RTC_STAT_REG); - if (rtc_ctrl < 0) - return rtc_ctrl; + err = abx500_get_register_interruptible(&pdev->dev, AB8500_RTC, + AB8500_RTC_STAT_REG, &rtc_ctrl); + if (err < 0) + return err; /* Check if the RTC Supply fails */ if (!(rtc_ctrl & RTC_STATUS_DATA)) { -- cgit v1.2.2 From 1c97872b80691f6bd3e46ec431a0d59dc75cb8da Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Uwe=20Kleine-K=C3=B6nig?= Date: Thu, 28 Oct 2010 12:30:53 +0200 Subject: rtc: Add support for the rtc found in the MC13892 PMIC MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The mfd driver for MC13783 recently got support for MC13892 and was renamed accordingly from mc13783-core to mc13xxx-core. Do the same for rtc-mc13783. The only relevant change is to use platform id's to tell the platform bus that this driver is responsible for mc13892-rtc devices, too. Acked-by: Alessandro Zummo Signed-off-by: Uwe Kleine-König Signed-off-by: Samuel Ortiz --- drivers/rtc/Kconfig | 9 +- drivers/rtc/Makefile | 2 +- drivers/rtc/rtc-mc13783.c | 428 --------------------------------------------- drivers/rtc/rtc-mc13xxx.c | 437 ++++++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 443 insertions(+), 433 deletions(-) delete mode 100644 drivers/rtc/rtc-mc13783.c create mode 100644 drivers/rtc/rtc-mc13xxx.c (limited to 'drivers/rtc') diff --git a/drivers/rtc/Kconfig b/drivers/rtc/Kconfig index 23579d6e4a6e..2883428d5ac8 100644 --- a/drivers/rtc/Kconfig +++ b/drivers/rtc/Kconfig @@ -936,11 +936,12 @@ config RTC_DRV_PCAP If you say Y here you will get support for the RTC found on the PCAP2 ASIC used on some Motorola phones. -config RTC_DRV_MC13783 - depends on MFD_MC13783 - tristate "Freescale MC13783 RTC" +config RTC_DRV_MC13XXX + depends on MFD_MC13XXX + tristate "Freescale MC13xxx RTC" help - This enables support for the Freescale MC13783 PMIC RTC + This enables support for the RTCs found on Freescale's PMICs + MC13783 and MC13892. config RTC_DRV_MPC5121 tristate "Freescale MPC5121 built-in RTC" diff --git a/drivers/rtc/Makefile b/drivers/rtc/Makefile index c3f3c2d9e1ed..4c2832df4697 100644 --- a/drivers/rtc/Makefile +++ b/drivers/rtc/Makefile @@ -62,7 +62,7 @@ obj-$(CONFIG_RTC_DRV_MAX6900) += rtc-max6900.o obj-$(CONFIG_RTC_DRV_MAX8925) += rtc-max8925.o obj-$(CONFIG_RTC_DRV_MAX8998) += rtc-max8998.o obj-$(CONFIG_RTC_DRV_MAX6902) += rtc-max6902.o -obj-$(CONFIG_RTC_DRV_MC13783) += rtc-mc13783.o +obj-$(CONFIG_RTC_DRV_MC13XXX) += rtc-mc13xxx.o obj-$(CONFIG_RTC_DRV_MSM6242) += rtc-msm6242.o obj-$(CONFIG_RTC_DRV_MPC5121) += rtc-mpc5121.o obj-$(CONFIG_RTC_DRV_MV) += rtc-mv.o diff --git a/drivers/rtc/rtc-mc13783.c b/drivers/rtc/rtc-mc13783.c deleted file mode 100644 index 675bfb515367..000000000000 --- a/drivers/rtc/rtc-mc13783.c +++ /dev/null @@ -1,428 +0,0 @@ -/* - * Real Time Clock driver for Freescale MC13783 PMIC - * - * (C) 2009 Sascha Hauer, Pengutronix - * (C) 2009 Uwe Kleine-Koenig, Pengutronix - * - * 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 -#include - -#define DRIVER_NAME "mc13783-rtc" - -#define MC13783_RTCTOD 20 -#define MC13783_RTCTODA 21 -#define MC13783_RTCDAY 22 -#define MC13783_RTCDAYA 23 - -struct mc13783_rtc { - struct rtc_device *rtc; - struct mc13783 *mc13783; - 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); - unsigned int seconds, days1, days2; - unsigned long s1970; - int ret; - - mc13783_lock(priv->mc13783); - - if (!priv->valid) { - ret = -ENODATA; - goto out; - } - - ret = mc13783_reg_read(priv->mc13783, MC13783_RTCDAY, &days1); - if (unlikely(ret)) - goto out; - - ret = mc13783_reg_read(priv->mc13783, MC13783_RTCTOD, &seconds); - if (unlikely(ret)) - goto out; - - ret = mc13783_reg_read(priv->mc13783, MC13783_RTCDAY, &days2); -out: - mc13783_unlock(priv->mc13783); - - if (ret) - return ret; - - if (days2 == days1 + 1) { - if (seconds >= 86400 / 2) - days2 = days1; - else - days1 = days2; - } - - if (days1 != days2) - return -EIO; - - s1970 = days1 * 86400 + seconds; - - rtc_time_to_tm(s1970, tm); - - return rtc_valid_tm(tm); -} - -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; - days = secs / 86400; - - mc13783_lock(priv->mc13783); - - /* - * 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); - if (unlikely(ret)) - goto out; - - ret = mc13783_reg_write(priv->mc13783, MC13783_RTCDAY, days); - if (unlikely(ret)) - goto out; - - ret = mc13783_reg_write(priv->mc13783, MC13783_RTCTOD, seconds); - 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; - - ret = mc13783_irq_unmask(priv->mc13783, MC13783_IRQ_RTCRST); -out: - priv->valid = !ret; - - mc13783_unlock(priv->mc13783); - - 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; - struct mc13783 *mc13783 = priv->mc13783; - - dev_dbg(&priv->rtc->dev, "1HZ\n"); - - rtc_update_irq(priv->rtc, 1, RTC_IRQF | RTC_UF); - - mc13783_irq_ack(mc13783, irq); - - return IRQ_HANDLED; -} - -static int mc13783_rtc_update_irq_enable(struct device *dev, - unsigned int enabled) -{ - return mc13783_rtc_irq_enable(dev, enabled, MC13783_IRQ_1HZ); -} - -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, -}; - -static irqreturn_t mc13783_rtc_reset_handler(int irq, void *dev) -{ - struct mc13783_rtc *priv = dev; - struct mc13783 *mc13783 = priv->mc13783; - - dev_dbg(&priv->rtc->dev, "RTCRST\n"); - priv->valid = 0; - - mc13783_irq_mask(mc13783, irq); - - return IRQ_HANDLED; -} - -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; - - mc13783 = dev_get_drvdata(pdev->dev.parent); - priv->mc13783 = mc13783; - - platform_set_drvdata(pdev, priv); - - mc13783_lock(mc13783); - - 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(mc13783, MC13783_IRQ_RTCRST, - NULL, &rtcrst_pending); - if (ret) - goto err_reset_irq_status; - - priv->valid = !rtcrst_pending; - - 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(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(mc13783, MC13783_IRQ_TODA, priv); -err_alarm_irq_request: - - mc13783_irq_free(mc13783, MC13783_IRQ_1HZ, priv); -err_update_irq_request: - -err_reset_irq_status: - - mc13783_irq_free(mc13783, MC13783_IRQ_RTCRST, priv); -err_reset_irq_request: - - platform_set_drvdata(pdev, NULL); - kfree(priv); - } - - mc13783_unlock(mc13783); - - return ret; -} - -static int __devexit mc13783_rtc_remove(struct platform_device *pdev) -{ - struct mc13783_rtc *priv = platform_get_drvdata(pdev); - - mc13783_lock(priv->mc13783); - - 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); - - mc13783_unlock(priv->mc13783); - - platform_set_drvdata(pdev, NULL); - - kfree(priv); - - return 0; -} - -static struct platform_driver mc13783_rtc_driver = { - .remove = __devexit_p(mc13783_rtc_remove), - .driver = { - .name = DRIVER_NAME, - .owner = THIS_MODULE, - }, -}; - -static int __init mc13783_rtc_init(void) -{ - return platform_driver_probe(&mc13783_rtc_driver, &mc13783_rtc_probe); -} -module_init(mc13783_rtc_init); - -static void __exit mc13783_rtc_exit(void) -{ - platform_driver_unregister(&mc13783_rtc_driver); -} -module_exit(mc13783_rtc_exit); - -MODULE_AUTHOR("Sascha Hauer "); -MODULE_DESCRIPTION("RTC driver for Freescale MC13783 PMIC"); -MODULE_LICENSE("GPL v2"); -MODULE_ALIAS("platform:" DRIVER_NAME); diff --git a/drivers/rtc/rtc-mc13xxx.c b/drivers/rtc/rtc-mc13xxx.c new file mode 100644 index 000000000000..5314b153bfba --- /dev/null +++ b/drivers/rtc/rtc-mc13xxx.c @@ -0,0 +1,437 @@ +/* + * Real Time Clock driver for Freescale MC13XXX PMIC + * + * (C) 2009 Sascha Hauer, Pengutronix + * (C) 2009 Uwe Kleine-Koenig, Pengutronix + * + * 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 +#include + +#define DRIVER_NAME "mc13xxx-rtc" + +#define MC13XXX_RTCTOD 20 +#define MC13XXX_RTCTODA 21 +#define MC13XXX_RTCDAY 22 +#define MC13XXX_RTCDAYA 23 + +struct mc13xxx_rtc { + struct rtc_device *rtc; + struct mc13xxx *mc13xxx; + int valid; +}; + +static int mc13xxx_rtc_irq_enable_unlocked(struct device *dev, + unsigned int enabled, int irq) +{ + struct mc13xxx_rtc *priv = dev_get_drvdata(dev); + int (*func)(struct mc13xxx *mc13xxx, int irq); + + if (!priv->valid) + return -ENODATA; + + func = enabled ? mc13xxx_irq_unmask : mc13xxx_irq_mask; + return func(priv->mc13xxx, irq); +} + +static int mc13xxx_rtc_irq_enable(struct device *dev, + unsigned int enabled, int irq) +{ + struct mc13xxx_rtc *priv = dev_get_drvdata(dev); + int ret; + + mc13xxx_lock(priv->mc13xxx); + + ret = mc13xxx_rtc_irq_enable_unlocked(dev, enabled, irq); + + mc13xxx_unlock(priv->mc13xxx); + + return ret; +} + +static int mc13xxx_rtc_read_time(struct device *dev, struct rtc_time *tm) +{ + struct mc13xxx_rtc *priv = dev_get_drvdata(dev); + unsigned int seconds, days1, days2; + unsigned long s1970; + int ret; + + mc13xxx_lock(priv->mc13xxx); + + if (!priv->valid) { + ret = -ENODATA; + goto out; + } + + ret = mc13xxx_reg_read(priv->mc13xxx, MC13XXX_RTCDAY, &days1); + if (unlikely(ret)) + goto out; + + ret = mc13xxx_reg_read(priv->mc13xxx, MC13XXX_RTCTOD, &seconds); + if (unlikely(ret)) + goto out; + + ret = mc13xxx_reg_read(priv->mc13xxx, MC13XXX_RTCDAY, &days2); +out: + mc13xxx_unlock(priv->mc13xxx); + + if (ret) + return ret; + + if (days2 == days1 + 1) { + if (seconds >= 86400 / 2) + days2 = days1; + else + days1 = days2; + } + + if (days1 != days2) + return -EIO; + + s1970 = days1 * 86400 + seconds; + + rtc_time_to_tm(s1970, tm); + + return rtc_valid_tm(tm); +} + +static int mc13xxx_rtc_set_mmss(struct device *dev, unsigned long secs) +{ + struct mc13xxx_rtc *priv = dev_get_drvdata(dev); + unsigned int seconds, days; + unsigned int alarmseconds; + int ret; + + seconds = secs % 86400; + days = secs / 86400; + + mc13xxx_lock(priv->mc13xxx); + + /* + * temporarily invalidate alarm to prevent triggering it when the day is + * already updated while the time isn't yet. + */ + ret = mc13xxx_reg_read(priv->mc13xxx, MC13XXX_RTCTODA, &alarmseconds); + if (unlikely(ret)) + goto out; + + if (alarmseconds < 86400) { + ret = mc13xxx_reg_write(priv->mc13xxx, + MC13XXX_RTCTODA, 0x1ffff); + if (unlikely(ret)) + goto out; + } + + /* + * write seconds=0 to prevent a day switch between writing days + * and seconds below + */ + ret = mc13xxx_reg_write(priv->mc13xxx, MC13XXX_RTCTOD, 0); + if (unlikely(ret)) + goto out; + + ret = mc13xxx_reg_write(priv->mc13xxx, MC13XXX_RTCDAY, days); + if (unlikely(ret)) + goto out; + + ret = mc13xxx_reg_write(priv->mc13xxx, MC13XXX_RTCTOD, seconds); + if (unlikely(ret)) + goto out; + + /* restore alarm */ + if (alarmseconds < 86400) { + ret = mc13xxx_reg_write(priv->mc13xxx, + MC13XXX_RTCTODA, alarmseconds); + if (unlikely(ret)) + goto out; + } + + ret = mc13xxx_irq_ack(priv->mc13xxx, MC13XXX_IRQ_RTCRST); + if (unlikely(ret)) + goto out; + + ret = mc13xxx_irq_unmask(priv->mc13xxx, MC13XXX_IRQ_RTCRST); +out: + priv->valid = !ret; + + mc13xxx_unlock(priv->mc13xxx); + + return ret; +} + +static int mc13xxx_rtc_read_alarm(struct device *dev, struct rtc_wkalrm *alarm) +{ + struct mc13xxx_rtc *priv = dev_get_drvdata(dev); + unsigned seconds, days; + unsigned long s1970; + int enabled, pending; + int ret; + + mc13xxx_lock(priv->mc13xxx); + + ret = mc13xxx_reg_read(priv->mc13xxx, MC13XXX_RTCTODA, &seconds); + if (unlikely(ret)) + goto out; + if (seconds >= 86400) { + ret = -ENODATA; + goto out; + } + + ret = mc13xxx_reg_read(priv->mc13xxx, MC13XXX_RTCDAY, &days); + if (unlikely(ret)) + goto out; + + ret = mc13xxx_irq_status(priv->mc13xxx, MC13XXX_IRQ_TODA, + &enabled, &pending); + +out: + mc13xxx_unlock(priv->mc13xxx); + + 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 mc13xxx_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alarm) +{ + struct mc13xxx_rtc *priv = dev_get_drvdata(dev); + unsigned long s1970; + unsigned seconds, days; + int ret; + + mc13xxx_lock(priv->mc13xxx); + + /* disable alarm to prevent false triggering */ + ret = mc13xxx_reg_write(priv->mc13xxx, MC13XXX_RTCTODA, 0x1ffff); + if (unlikely(ret)) + goto out; + + ret = mc13xxx_irq_ack(priv->mc13xxx, MC13XXX_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 = mc13xxx_rtc_irq_enable_unlocked(dev, alarm->enabled, + MC13XXX_IRQ_TODA); + if (unlikely(ret)) + goto out; + + seconds = s1970 % 86400; + days = s1970 / 86400; + + ret = mc13xxx_reg_write(priv->mc13xxx, MC13XXX_RTCDAYA, days); + if (unlikely(ret)) + goto out; + + ret = mc13xxx_reg_write(priv->mc13xxx, MC13XXX_RTCTODA, seconds); + +out: + mc13xxx_unlock(priv->mc13xxx); + + return ret; +} + +static irqreturn_t mc13xxx_rtc_alarm_handler(int irq, void *dev) +{ + struct mc13xxx_rtc *priv = dev; + struct mc13xxx *mc13xxx = priv->mc13xxx; + + dev_dbg(&priv->rtc->dev, "Alarm\n"); + + rtc_update_irq(priv->rtc, 1, RTC_IRQF | RTC_AF); + + mc13xxx_irq_ack(mc13xxx, irq); + + return IRQ_HANDLED; +} + +static irqreturn_t mc13xxx_rtc_update_handler(int irq, void *dev) +{ + struct mc13xxx_rtc *priv = dev; + struct mc13xxx *mc13xxx = priv->mc13xxx; + + dev_dbg(&priv->rtc->dev, "1HZ\n"); + + rtc_update_irq(priv->rtc, 1, RTC_IRQF | RTC_UF); + + mc13xxx_irq_ack(mc13xxx, irq); + + return IRQ_HANDLED; +} + +static int mc13xxx_rtc_update_irq_enable(struct device *dev, + unsigned int enabled) +{ + return mc13xxx_rtc_irq_enable(dev, enabled, MC13XXX_IRQ_1HZ); +} + +static int mc13xxx_rtc_alarm_irq_enable(struct device *dev, + unsigned int enabled) +{ + return mc13xxx_rtc_irq_enable(dev, enabled, MC13XXX_IRQ_TODA); +} + +static const struct rtc_class_ops mc13xxx_rtc_ops = { + .read_time = mc13xxx_rtc_read_time, + .set_mmss = mc13xxx_rtc_set_mmss, + .read_alarm = mc13xxx_rtc_read_alarm, + .set_alarm = mc13xxx_rtc_set_alarm, + .alarm_irq_enable = mc13xxx_rtc_alarm_irq_enable, + .update_irq_enable = mc13xxx_rtc_update_irq_enable, +}; + +static irqreturn_t mc13xxx_rtc_reset_handler(int irq, void *dev) +{ + struct mc13xxx_rtc *priv = dev; + struct mc13xxx *mc13xxx = priv->mc13xxx; + + dev_dbg(&priv->rtc->dev, "RTCRST\n"); + priv->valid = 0; + + mc13xxx_irq_mask(mc13xxx, irq); + + return IRQ_HANDLED; +} + +static int __devinit mc13xxx_rtc_probe(struct platform_device *pdev) +{ + int ret; + struct mc13xxx_rtc *priv; + struct mc13xxx *mc13xxx; + int rtcrst_pending; + + priv = kzalloc(sizeof(*priv), GFP_KERNEL); + if (!priv) + return -ENOMEM; + + mc13xxx = dev_get_drvdata(pdev->dev.parent); + priv->mc13xxx = mc13xxx; + + platform_set_drvdata(pdev, priv); + + mc13xxx_lock(mc13xxx); + + ret = mc13xxx_irq_request(mc13xxx, MC13XXX_IRQ_RTCRST, + mc13xxx_rtc_reset_handler, DRIVER_NAME, priv); + if (ret) + goto err_reset_irq_request; + + ret = mc13xxx_irq_status(mc13xxx, MC13XXX_IRQ_RTCRST, + NULL, &rtcrst_pending); + if (ret) + goto err_reset_irq_status; + + priv->valid = !rtcrst_pending; + + ret = mc13xxx_irq_request_nounmask(mc13xxx, MC13XXX_IRQ_1HZ, + mc13xxx_rtc_update_handler, DRIVER_NAME, priv); + if (ret) + goto err_update_irq_request; + + ret = mc13xxx_irq_request_nounmask(mc13xxx, MC13XXX_IRQ_TODA, + mc13xxx_rtc_alarm_handler, DRIVER_NAME, priv); + if (ret) + goto err_alarm_irq_request; + + priv->rtc = rtc_device_register(pdev->name, + &pdev->dev, &mc13xxx_rtc_ops, THIS_MODULE); + if (IS_ERR(priv->rtc)) { + ret = PTR_ERR(priv->rtc); + + mc13xxx_irq_free(mc13xxx, MC13XXX_IRQ_TODA, priv); +err_alarm_irq_request: + + mc13xxx_irq_free(mc13xxx, MC13XXX_IRQ_1HZ, priv); +err_update_irq_request: + +err_reset_irq_status: + + mc13xxx_irq_free(mc13xxx, MC13XXX_IRQ_RTCRST, priv); +err_reset_irq_request: + + platform_set_drvdata(pdev, NULL); + kfree(priv); + } + + mc13xxx_unlock(mc13xxx); + + return ret; +} + +static int __devexit mc13xxx_rtc_remove(struct platform_device *pdev) +{ + struct mc13xxx_rtc *priv = platform_get_drvdata(pdev); + + mc13xxx_lock(priv->mc13xxx); + + rtc_device_unregister(priv->rtc); + + mc13xxx_irq_free(priv->mc13xxx, MC13XXX_IRQ_TODA, priv); + mc13xxx_irq_free(priv->mc13xxx, MC13XXX_IRQ_1HZ, priv); + mc13xxx_irq_free(priv->mc13xxx, MC13XXX_IRQ_RTCRST, priv); + + mc13xxx_unlock(priv->mc13xxx); + + platform_set_drvdata(pdev, NULL); + + kfree(priv); + + return 0; +} + +const struct platform_device_id mc13xxx_rtc_idtable[] = { + { + .name = "mc13783-rtc", + }, { + .name = "mc13892-rtc", + }, +}; + +static struct platform_driver mc13xxx_rtc_driver = { + .id_table = mc13xxx_rtc_idtable, + .remove = __devexit_p(mc13xxx_rtc_remove), + .driver = { + .name = DRIVER_NAME, + .owner = THIS_MODULE, + }, +}; + +static int __init mc13xxx_rtc_init(void) +{ + return platform_driver_probe(&mc13xxx_rtc_driver, &mc13xxx_rtc_probe); +} +module_init(mc13xxx_rtc_init); + +static void __exit mc13xxx_rtc_exit(void) +{ + platform_driver_unregister(&mc13xxx_rtc_driver); +} +module_exit(mc13xxx_rtc_exit); + +MODULE_AUTHOR("Sascha Hauer "); +MODULE_DESCRIPTION("RTC driver for Freescale MC13XXX PMIC"); +MODULE_LICENSE("GPL v2"); +MODULE_ALIAS("platform:" DRIVER_NAME); -- cgit v1.2.2 From f6eec8d66400714e47add3d8341688a1e86c5de9 Mon Sep 17 00:00:00 2001 From: Paul Mundt Date: Fri, 29 Oct 2010 19:06:53 +0900 Subject: sh: mach-snapgear: Kill off machtype, consolidate board def. Only the secureedge5410 was ever supported by this code, so make the board specification explicit rather than perpetuating a mach group. Signed-off-by: Paul Mundt --- drivers/rtc/rtc-ds1302.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/rtc') diff --git a/drivers/rtc/rtc-ds1302.c b/drivers/rtc/rtc-ds1302.c index 359d1e04626c..f0d638922644 100644 --- a/drivers/rtc/rtc-ds1302.c +++ b/drivers/rtc/rtc-ds1302.c @@ -35,7 +35,7 @@ #ifdef CONFIG_SH_SECUREEDGE5410 #include -#include +#include #define RTC_RESET 0x1000 #define RTC_IODATA 0x0800 -- cgit v1.2.2