diff options
Diffstat (limited to 'drivers/rtc/rtc-twl.c')
| -rw-r--r-- | drivers/rtc/rtc-twl.c | 269 |
1 files changed, 140 insertions, 129 deletions
diff --git a/drivers/rtc/rtc-twl.c b/drivers/rtc/rtc-twl.c index ed1b8682812..1915464e4cd 100644 --- a/drivers/rtc/rtc-twl.c +++ b/drivers/rtc/rtc-twl.c @@ -27,6 +27,7 @@ #include <linux/bcd.h> #include <linux/platform_device.h> #include <linux/interrupt.h> +#include <linux/of.h> #include <linux/i2c/twl.h> @@ -112,6 +113,7 @@ static const u8 twl6030_rtc_reg_map[] = { #define BIT_RTC_CTRL_REG_TEST_MODE_M 0x10 #define BIT_RTC_CTRL_REG_SET_32_COUNTER_M 0x20 #define BIT_RTC_CTRL_REG_GET_TIME_M 0x40 +#define BIT_RTC_CTRL_REG_RTC_V_OPT 0x80 /* RTC_STATUS_REG bitfields */ #define BIT_RTC_STATUS_REG_RUN_M 0x02 @@ -176,6 +178,10 @@ static int set_rtc_irq_bit(unsigned char bit) unsigned char val; int ret; + /* if the bit is set, return from here */ + if (rtc_irq_bits & bit) + return 0; + val = rtc_irq_bits | bit; val &= ~BIT_RTC_INTERRUPTS_REG_EVERY_M; ret = twl_rtc_write_u8(val, REG_RTC_INTERRUPTS_REG); @@ -193,6 +199,10 @@ static int mask_rtc_irq_bit(unsigned char bit) unsigned char val; int ret; + /* if the bit is clear, return from here */ + if (!(rtc_irq_bits & bit)) + return 0; + val = rtc_irq_bits & ~bit; ret = twl_rtc_write_u8(val, REG_RTC_INTERRUPTS_REG); if (ret == 0) @@ -203,24 +213,24 @@ static int mask_rtc_irq_bit(unsigned char bit) static int twl_rtc_alarm_irq_enable(struct device *dev, unsigned enabled) { + struct platform_device *pdev = to_platform_device(dev); + int irq = platform_get_irq(pdev, 0); + static bool twl_rtc_wake_enabled; int ret; - if (enabled) + if (enabled) { ret = set_rtc_irq_bit(BIT_RTC_INTERRUPTS_REG_IT_ALARM_M); - else + if (device_can_wakeup(dev) && !twl_rtc_wake_enabled) { + enable_irq_wake(irq); + twl_rtc_wake_enabled = true; + } + } else { ret = mask_rtc_irq_bit(BIT_RTC_INTERRUPTS_REG_IT_ALARM_M); - - return ret; -} - -static int twl_rtc_update_irq_enable(struct device *dev, unsigned enabled) -{ - int ret; - - if (enabled) - ret = set_rtc_irq_bit(BIT_RTC_INTERRUPTS_REG_IT_TIMER_M); - else - ret = mask_rtc_irq_bit(BIT_RTC_INTERRUPTS_REG_IT_TIMER_M); + if (twl_rtc_wake_enabled) { + disable_irq_wake(irq); + twl_rtc_wake_enabled = false; + } + } return ret; } @@ -236,28 +246,60 @@ static int twl_rtc_update_irq_enable(struct device *dev, unsigned enabled) */ static int twl_rtc_read_time(struct device *dev, struct rtc_time *tm) { - unsigned char rtc_data[ALL_TIME_REGS + 1]; + unsigned char rtc_data[ALL_TIME_REGS]; int ret; u8 save_control; + u8 rtc_control; ret = twl_rtc_read_u8(&save_control, REG_RTC_CTRL_REG); - if (ret < 0) + if (ret < 0) { + dev_err(dev, "%s: reading CTRL_REG, error %d\n", __func__, ret); return ret; + } + /* for twl6030/32 make sure BIT_RTC_CTRL_REG_GET_TIME_M is clear */ + if (twl_class_is_6030()) { + if (save_control & BIT_RTC_CTRL_REG_GET_TIME_M) { + save_control &= ~BIT_RTC_CTRL_REG_GET_TIME_M; + ret = twl_rtc_write_u8(save_control, REG_RTC_CTRL_REG); + if (ret < 0) { + dev_err(dev, "%s clr GET_TIME, error %d\n", + __func__, ret); + return ret; + } + } + } - save_control |= BIT_RTC_CTRL_REG_GET_TIME_M; + /* Copy RTC counting registers to static registers or latches */ + rtc_control = save_control | BIT_RTC_CTRL_REG_GET_TIME_M; - ret = twl_rtc_write_u8(save_control, REG_RTC_CTRL_REG); - if (ret < 0) + /* for twl6030/32 enable read access to static shadowed registers */ + if (twl_class_is_6030()) + rtc_control |= BIT_RTC_CTRL_REG_RTC_V_OPT; + + ret = twl_rtc_write_u8(rtc_control, REG_RTC_CTRL_REG); + if (ret < 0) { + dev_err(dev, "%s: writing CTRL_REG, error %d\n", __func__, ret); return ret; + } ret = twl_i2c_read(TWL_MODULE_RTC, rtc_data, (rtc_reg_map[REG_SECONDS_REG]), ALL_TIME_REGS); if (ret < 0) { - dev_err(dev, "rtc_read_time error %d\n", ret); + dev_err(dev, "%s: reading data, error %d\n", __func__, ret); return ret; } + /* for twl6030 restore original state of rtc control register */ + if (twl_class_is_6030()) { + ret = twl_rtc_write_u8(save_control, REG_RTC_CTRL_REG); + if (ret < 0) { + dev_err(dev, "%s: restore CTRL_REG, error %d\n", + __func__, ret); + return ret; + } + } + tm->tm_sec = bcd2bin(rtc_data[0]); tm->tm_min = bcd2bin(rtc_data[1]); tm->tm_hour = bcd2bin(rtc_data[2]); @@ -271,15 +313,15 @@ static int twl_rtc_read_time(struct device *dev, struct rtc_time *tm) static int twl_rtc_set_time(struct device *dev, struct rtc_time *tm) { unsigned char save_control; - unsigned char rtc_data[ALL_TIME_REGS + 1]; + unsigned char rtc_data[ALL_TIME_REGS]; int ret; - rtc_data[1] = bin2bcd(tm->tm_sec); - rtc_data[2] = bin2bcd(tm->tm_min); - rtc_data[3] = bin2bcd(tm->tm_hour); - rtc_data[4] = bin2bcd(tm->tm_mday); - rtc_data[5] = bin2bcd(tm->tm_mon + 1); - rtc_data[6] = bin2bcd(tm->tm_year - 100); + rtc_data[0] = bin2bcd(tm->tm_sec); + rtc_data[1] = bin2bcd(tm->tm_min); + rtc_data[2] = bin2bcd(tm->tm_hour); + rtc_data[3] = bin2bcd(tm->tm_mday); + rtc_data[4] = bin2bcd(tm->tm_mon + 1); + rtc_data[5] = bin2bcd(tm->tm_year - 100); /* Stop RTC while updating the TC registers */ ret = twl_rtc_read_u8(&save_control, REG_RTC_CTRL_REG); @@ -287,7 +329,7 @@ static int twl_rtc_set_time(struct device *dev, struct rtc_time *tm) goto out; save_control &= ~BIT_RTC_CTRL_REG_STOP_RTC_M; - twl_rtc_write_u8(save_control, REG_RTC_CTRL_REG); + ret = twl_rtc_write_u8(save_control, REG_RTC_CTRL_REG); if (ret < 0) goto out; @@ -312,7 +354,7 @@ out: */ static int twl_rtc_read_alarm(struct device *dev, struct rtc_wkalrm *alm) { - unsigned char rtc_data[ALL_TIME_REGS + 1]; + unsigned char rtc_data[ALL_TIME_REGS]; int ret; ret = twl_i2c_read(TWL_MODULE_RTC, rtc_data, @@ -339,19 +381,19 @@ static int twl_rtc_read_alarm(struct device *dev, struct rtc_wkalrm *alm) static int twl_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alm) { - unsigned char alarm_data[ALL_TIME_REGS + 1]; + unsigned char alarm_data[ALL_TIME_REGS]; int ret; ret = twl_rtc_alarm_irq_enable(dev, 0); if (ret) goto out; - alarm_data[1] = bin2bcd(alm->time.tm_sec); - alarm_data[2] = bin2bcd(alm->time.tm_min); - alarm_data[3] = bin2bcd(alm->time.tm_hour); - alarm_data[4] = bin2bcd(alm->time.tm_mday); - alarm_data[5] = bin2bcd(alm->time.tm_mon + 1); - alarm_data[6] = bin2bcd(alm->time.tm_year - 100); + alarm_data[0] = bin2bcd(alm->time.tm_sec); + alarm_data[1] = bin2bcd(alm->time.tm_min); + alarm_data[2] = bin2bcd(alm->time.tm_hour); + alarm_data[3] = bin2bcd(alm->time.tm_mday); + alarm_data[4] = bin2bcd(alm->time.tm_mon + 1); + alarm_data[5] = bin2bcd(alm->time.tm_year - 100); /* update all the alarm registers in one shot */ ret = twl_i2c_write(TWL_MODULE_RTC, alarm_data, @@ -369,19 +411,11 @@ out: static irqreturn_t twl_rtc_interrupt(int irq, void *rtc) { - unsigned long events = 0; + unsigned long events; int ret = IRQ_NONE; int res; u8 rd_reg; -#ifdef CONFIG_LOCKDEP - /* WORKAROUND for lockdep forcing IRQF_DISABLED on us, which - * we don't want and can't tolerate. Although it might be - * friendlier not to borrow this thread context... - */ - local_irq_enable(); -#endif - res = twl_rtc_read_u8(&rd_reg, REG_RTC_STATUS_REG); if (res) goto out; @@ -392,11 +426,11 @@ static irqreturn_t twl_rtc_interrupt(int irq, void *rtc) * by reading RTS_INTERRUPTS_REGISTER[IT_TIMER,IT_ALARM] */ if (rd_reg & BIT_RTC_STATUS_REG_ALARM_M) - events |= RTC_IRQF | RTC_AF; + events = RTC_IRQF | RTC_AF; else - events |= RTC_IRQF | RTC_UF; + events = RTC_IRQF | RTC_PF; - res = twl_rtc_write_u8(rd_reg | BIT_RTC_STATUS_REG_ALARM_M, + res = twl_rtc_write_u8(BIT_RTC_STATUS_REG_ALARM_M, REG_RTC_STATUS_REG); if (res) goto out; @@ -433,36 +467,29 @@ static struct rtc_class_ops twl_rtc_ops = { .read_alarm = twl_rtc_read_alarm, .set_alarm = twl_rtc_set_alarm, .alarm_irq_enable = twl_rtc_alarm_irq_enable, - .update_irq_enable = twl_rtc_update_irq_enable, }; /*----------------------------------------------------------------------*/ -static int __devinit twl_rtc_probe(struct platform_device *pdev) +static int twl_rtc_probe(struct platform_device *pdev) { struct rtc_device *rtc; - int ret = 0; + int ret = -EINVAL; int irq = platform_get_irq(pdev, 0); u8 rd_reg; if (irq <= 0) - return -EINVAL; - - rtc = rtc_device_register(pdev->name, - &pdev->dev, &twl_rtc_ops, THIS_MODULE); - if (IS_ERR(rtc)) { - ret = PTR_ERR(rtc); - dev_err(&pdev->dev, "can't register RTC device, err %ld\n", - PTR_ERR(rtc)); - goto out0; - - } + return ret; - platform_set_drvdata(pdev, rtc); + /* Initialize the register map */ + if (twl_class_is_4030()) + rtc_reg_map = (u8 *)twl4030_rtc_reg_map; + else + rtc_reg_map = (u8 *)twl6030_rtc_reg_map; ret = twl_rtc_read_u8(&rd_reg, REG_RTC_STATUS_REG); if (ret < 0) - goto out1; + return ret; if (rd_reg & BIT_RTC_STATUS_REG_POWER_UP_M) dev_warn(&pdev->dev, "Power up reset detected.\n"); @@ -473,15 +500,7 @@ static int __devinit twl_rtc_probe(struct platform_device *pdev) /* Clear RTC Power up reset and pending alarm interrupts */ ret = twl_rtc_write_u8(rd_reg, REG_RTC_STATUS_REG); if (ret < 0) - goto out1; - - ret = request_irq(irq, twl_rtc_interrupt, - IRQF_TRIGGER_RISING, - dev_name(&rtc->dev), rtc); - if (ret < 0) { - dev_err(&pdev->dev, "IRQ is not free.\n"); - goto out1; - } + return ret; if (twl_class_is_6030()) { twl6030_interrupt_unmask(TWL6030_RTC_INT_MASK, @@ -490,44 +509,51 @@ static int __devinit twl_rtc_probe(struct platform_device *pdev) REG_INT_MSK_STS_A); } - /* Check RTC module status, Enable if it is off */ - ret = twl_rtc_read_u8(&rd_reg, REG_RTC_CTRL_REG); + dev_info(&pdev->dev, "Enabling TWL-RTC\n"); + ret = twl_rtc_write_u8(BIT_RTC_CTRL_REG_STOP_RTC_M, REG_RTC_CTRL_REG); if (ret < 0) - goto out2; - - if (!(rd_reg & BIT_RTC_CTRL_REG_STOP_RTC_M)) { - dev_info(&pdev->dev, "Enabling TWL-RTC.\n"); - rd_reg = BIT_RTC_CTRL_REG_STOP_RTC_M; - ret = twl_rtc_write_u8(rd_reg, REG_RTC_CTRL_REG); - if (ret < 0) - goto out2; - } + return ret; + + /* ensure interrupts are disabled, bootloaders can be strange */ + ret = twl_rtc_write_u8(0, REG_RTC_INTERRUPTS_REG); + if (ret < 0) + dev_warn(&pdev->dev, "unable to disable interrupt\n"); /* init cached IRQ enable bits */ ret = twl_rtc_read_u8(&rtc_irq_bits, REG_RTC_INTERRUPTS_REG); if (ret < 0) - goto out2; + return ret; - return ret; + device_init_wakeup(&pdev->dev, 1); -out2: - free_irq(irq, rtc); -out1: - rtc_device_unregister(rtc); -out0: - return ret; + rtc = devm_rtc_device_register(&pdev->dev, pdev->name, + &twl_rtc_ops, THIS_MODULE); + if (IS_ERR(rtc)) { + dev_err(&pdev->dev, "can't register RTC device, err %ld\n", + PTR_ERR(rtc)); + return PTR_ERR(rtc); + } + + ret = devm_request_threaded_irq(&pdev->dev, irq, NULL, + twl_rtc_interrupt, + IRQF_TRIGGER_RISING | IRQF_ONESHOT, + dev_name(&rtc->dev), rtc); + if (ret < 0) { + dev_err(&pdev->dev, "IRQ is not free.\n"); + return ret; + } + + platform_set_drvdata(pdev, rtc); + return 0; } /* * Disable all TWL RTC module interrupts. * Sets status flag to free. */ -static int __devexit twl_rtc_remove(struct platform_device *pdev) +static int twl_rtc_remove(struct platform_device *pdev) { /* leave rtc running, but disable irqs */ - struct rtc_device *rtc = platform_get_drvdata(pdev); - int irq = platform_get_irq(pdev, 0); - mask_rtc_irq_bit(BIT_RTC_INTERRUPTS_REG_IT_ALARM_M); mask_rtc_irq_bit(BIT_RTC_INTERRUPTS_REG_IT_TIMER_M); if (twl_class_is_6030()) { @@ -537,11 +563,6 @@ static int __devexit twl_rtc_remove(struct platform_device *pdev) REG_INT_MSK_STS_A); } - - free_irq(irq, rtc); - - rtc_device_unregister(rtc); - platform_set_drvdata(pdev, NULL); return 0; } @@ -552,11 +573,10 @@ static void twl_rtc_shutdown(struct platform_device *pdev) mask_rtc_irq_bit(BIT_RTC_INTERRUPTS_REG_IT_TIMER_M); } -#ifdef CONFIG_PM - +#ifdef CONFIG_PM_SLEEP static unsigned char irqstat; -static int twl_rtc_suspend(struct platform_device *pdev, pm_message_t state) +static int twl_rtc_suspend(struct device *dev) { irqstat = rtc_irq_bits; @@ -564,47 +584,38 @@ static int twl_rtc_suspend(struct platform_device *pdev, pm_message_t state) return 0; } -static int twl_rtc_resume(struct platform_device *pdev) +static int twl_rtc_resume(struct device *dev) { set_rtc_irq_bit(irqstat); return 0; } +#endif -#else -#define twl_rtc_suspend NULL -#define twl_rtc_resume NULL +static SIMPLE_DEV_PM_OPS(twl_rtc_pm_ops, twl_rtc_suspend, twl_rtc_resume); + +#ifdef CONFIG_OF +static const struct of_device_id twl_rtc_of_match[] = { + {.compatible = "ti,twl4030-rtc", }, + { }, +}; +MODULE_DEVICE_TABLE(of, twl_rtc_of_match); #endif MODULE_ALIAS("platform:twl_rtc"); static struct platform_driver twl4030rtc_driver = { .probe = twl_rtc_probe, - .remove = __devexit_p(twl_rtc_remove), + .remove = twl_rtc_remove, .shutdown = twl_rtc_shutdown, - .suspend = twl_rtc_suspend, - .resume = twl_rtc_resume, .driver = { - .owner = THIS_MODULE, - .name = "twl_rtc", + .owner = THIS_MODULE, + .name = "twl_rtc", + .pm = &twl_rtc_pm_ops, + .of_match_table = of_match_ptr(twl_rtc_of_match), }, }; -static int __init twl_rtc_init(void) -{ - if (twl_class_is_4030()) - rtc_reg_map = (u8 *) twl4030_rtc_reg_map; - else - rtc_reg_map = (u8 *) twl6030_rtc_reg_map; - - return platform_driver_register(&twl4030rtc_driver); -} -module_init(twl_rtc_init); - -static void __exit twl_rtc_exit(void) -{ - platform_driver_unregister(&twl4030rtc_driver); -} -module_exit(twl_rtc_exit); +module_platform_driver(twl4030rtc_driver); MODULE_AUTHOR("Texas Instruments, MontaVista Software"); MODULE_LICENSE("GPL"); |
