diff options
Diffstat (limited to 'drivers/rtc')
-rw-r--r-- | drivers/rtc/rtc-max77663.c | 24 | ||||
-rw-r--r-- | drivers/rtc/rtc-tps6591x.c | 8 | ||||
-rw-r--r-- | drivers/rtc/rtc-tps80031.c | 49 |
3 files changed, 72 insertions, 9 deletions
diff --git a/drivers/rtc/rtc-max77663.c b/drivers/rtc/rtc-max77663.c index 874a2df86dc1..13d8062e1def 100644 --- a/drivers/rtc/rtc-max77663.c +++ b/drivers/rtc/rtc-max77663.c @@ -2,8 +2,8 @@ * drivers/rtc/rtc-max77663.c * Max77663 RTC driver * - * Copyright 2011 Maxim Integrated Products, Inc. - * Copyright (C) 2011 NVIDIA Corporation + * Copyright 2011-2012, Maxim Integrated Products, Inc. + * Copyright (c) 2011-2012, NVIDIA CORPORATION. All rights reserved. * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as @@ -97,6 +97,7 @@ struct max77663_rtc { struct mutex io_lock; int irq; u8 irq_mask; + bool shutdown_ongoing; }; static inline struct device *_to_parent(struct max77663_rtc *rtc) @@ -443,6 +444,11 @@ static int max77663_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alrm) u8 buf[RTC_NR]; int ret; + if (rtc->shutdown_ongoing) { + dev_warn(rtc->dev, "rtc_set_alarm: " + "Device shutdown on-going, skip alarm setting.\n"); + return -ESHUTDOWN; + } dev_dbg(rtc->dev, "rtc_set_alarm: " "tm: %d-%02d-%02d %02d:%02d:%02d, wday=%d [%s]\n", alrm->time.tm_year, alrm->time.tm_mon, alrm->time.tm_mday, @@ -534,7 +540,7 @@ static int max77663_rtc_probe(struct platform_device *pdev) dev_err(&pdev->dev, "probe: kzalloc() failed\n"); return -ENOMEM; } - + rtc->shutdown_ongoing = false; dev_set_drvdata(&pdev->dev, rtc); rtc->dev = &pdev->dev; mutex_init(&rtc->io_lock); @@ -591,6 +597,17 @@ static int __devexit max77663_rtc_remove(struct platform_device *pdev) return 0; } +static void max77663_rtc_shutdown(struct platform_device *pdev) +{ + struct max77663_rtc *rtc = dev_get_drvdata(&pdev->dev); + u8 buf[RTC_NR] = { 0x0, 0x0, 0x0, 0x1, 0x1, 0x0, 0x1 }; + + rtc->shutdown_ongoing = true; + dev_info(rtc->dev, "rtc_shutdown: clean alarm\n"); + max77663_rtc_write(rtc, MAX77663_RTC_ALARM_SEC1, buf, sizeof(buf), 1); + max77663_rtc_alarm_irq_enable(&pdev->dev, 0); +} + static struct platform_driver max77663_rtc_driver = { .probe = max77663_rtc_probe, .remove = __devexit_p(max77663_rtc_remove), @@ -598,6 +615,7 @@ static struct platform_driver max77663_rtc_driver = { .name = "max77663-rtc", .owner = THIS_MODULE, }, + .shutdown = max77663_rtc_shutdown, }; static int __init max77663_rtc_init(void) diff --git a/drivers/rtc/rtc-tps6591x.c b/drivers/rtc/rtc-tps6591x.c index 6223f1108f06..ebc46b4cf46e 100644 --- a/drivers/rtc/rtc-tps6591x.c +++ b/drivers/rtc/rtc-tps6591x.c @@ -162,7 +162,7 @@ static int tps6591x_rtc_read_time(struct device *dev, struct rtc_time *tm) tm->tm_hour = buff[2]; tm->tm_mday = buff[3]; tm->tm_mon = buff[4] - 1; - tm->tm_year = buff[5]; + tm->tm_year = buff[5] + RTC_YEAR_OFFSET; tm->tm_wday = buff[6]; print_time(dev, tm); return tps6591x_rtc_valid_tm(tm); @@ -250,7 +250,7 @@ static int tps6591x_rtc_set_time(struct device *dev, struct rtc_time *tm) buff[2] = tm->tm_hour; buff[3] = tm->tm_mday; buff[4] = tm->tm_mon + 1; - buff[5] = tm->tm_year; + buff[5] = tm->tm_year % RTC_YEAR_OFFSET; buff[6] = tm->tm_wday; print_time(dev, tm); @@ -345,7 +345,7 @@ static int tps6591x_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alrm) buff[2] = alrm->time.tm_hour; buff[3] = alrm->time.tm_mday; buff[4] = alrm->time.tm_mon + 1; - buff[5] = alrm->time.tm_year; + buff[5] = alrm->time.tm_year % RTC_YEAR_OFFSET; convert_decimal_to_bcd(buff, sizeof(buff)); err = tps6591x_write_regs(dev, RTC_ALARM, sizeof(buff), buff); if (err) @@ -369,7 +369,7 @@ static int tps6591x_rtc_read_alarm(struct device *dev, struct rtc_wkalrm *alrm) alrm->time.tm_hour = buff[2]; alrm->time.tm_mday = buff[3]; alrm->time.tm_mon = buff[4] - 1; - alrm->time.tm_year = buff[5]; + alrm->time.tm_year = buff[5] + RTC_YEAR_OFFSET; dev_info(dev->parent, "\n getting alarm time::\n"); print_time(dev, &alrm->time); diff --git a/drivers/rtc/rtc-tps80031.c b/drivers/rtc/rtc-tps80031.c index 70d6734a5708..b2b9d04171c5 100644 --- a/drivers/rtc/rtc-tps80031.c +++ b/drivers/rtc/rtc-tps80031.c @@ -31,6 +31,7 @@ #include <linux/platform_device.h> #include <linux/rtc.h> #include <linux/slab.h> +#include <linux/gpio.h> #define RTC_CTRL 0x10 #define RTC_STATUS 0x11 @@ -65,8 +66,25 @@ struct tps80031_rtc { int irq; struct rtc_device *rtc; u8 alarm_irq_enabled; + int msecure_gpio; }; +static inline void tps80031_enable_rtc_write(struct device *dev) +{ + struct tps80031_rtc *rtc = dev_get_drvdata(dev); + + if (rtc->msecure_gpio >= 0) + gpio_set_value(rtc->msecure_gpio, 1); +} + +static inline void tps80031_disable_rtc_write(struct device *dev) +{ + struct tps80031_rtc *rtc = dev_get_drvdata(dev); + + if (rtc->msecure_gpio >= 0) + gpio_set_value(rtc->msecure_gpio, 0); +} + static int tps80031_read_regs(struct device *dev, int reg, int len, uint8_t *val) { @@ -93,13 +111,16 @@ static int tps80031_write_regs(struct device *dev, int reg, int len, uint8_t *val) { int ret; + + tps80031_enable_rtc_write(dev); ret = tps80031_writes(dev->parent, 1, reg, len, val); if (ret < 0) { + tps80031_disable_rtc_write(dev); dev_err(dev->parent, "failed writing reg: %d\n", reg); WARN_ON(1); return ret; } - + tps80031_disable_rtc_write(dev); return 0; } @@ -150,18 +171,24 @@ static int tps80031_rtc_read_time(struct device *dev, struct rtc_time *tm) static int tps80031_rtc_stop(struct device *dev) { int err; + + tps80031_enable_rtc_write(dev); err = tps80031_clr_bits(dev->parent, 1, RTC_CTRL, STOP_RTC); if (err < 0) dev_err(dev->parent, "failed to stop RTC. err: %d\n", err); + tps80031_disable_rtc_write(dev); return err; } static int tps80031_rtc_start(struct device *dev) { int err; + + tps80031_enable_rtc_write(dev); err = tps80031_set_bits(dev->parent, 1, RTC_CTRL, STOP_RTC); if (err < 0) dev_err(dev->parent, "failed to start RTC. err: %d\n", err); + tps80031_disable_rtc_write(dev); return err; } @@ -262,7 +289,9 @@ static int tps80031_rtc_alarm_irq_enable(struct device *dev, if (rtc->alarm_irq_enabled) return 0; + tps80031_enable_rtc_write(dev); err = tps80031_set_bits(p, 1, RTC_INT, ENABLE_ALARM_INT); + tps80031_disable_rtc_write(dev); if (err < 0) { dev_err(p, "failed to set ALRM int. err: %d\n", err); return err; @@ -271,7 +300,9 @@ static int tps80031_rtc_alarm_irq_enable(struct device *dev, } else { if(!rtc->alarm_irq_enabled) return 0; + tps80031_enable_rtc_write(dev); err = tps80031_clr_bits(p, 1, RTC_INT, ENABLE_ALARM_INT); + tps80031_disable_rtc_write(dev); if (err < 0) { dev_err(p, "failed to clear ALRM int. err: %d\n", err); return err; @@ -303,8 +334,10 @@ static irqreturn_t tps80031_rtc_irq(int irq, void *data) return -EBUSY; } + tps80031_enable_rtc_write(dev); err = tps80031_force_update(dev->parent, 1, RTC_STATUS, ALARM_INT_STATUS, ALARM_INT_STATUS); + tps80031_disable_rtc_write(dev); if (err) { dev_err(dev->parent, "unable to set Alarm INT\n"); return -EBUSY; @@ -335,8 +368,19 @@ static int __devinit tps80031_rtc_probe(struct platform_device *pdev) if (pdata->irq < 0) dev_err(&pdev->dev, "no IRQ specified, wakeup is disabled\n"); + rtc->msecure_gpio = -1; + if (gpio_is_valid(pdata->msecure_gpio)) { + err = gpio_request(pdata->msecure_gpio, "tps80031 msecure"); + if (err == 0) { + rtc->msecure_gpio = pdata->msecure_gpio; + gpio_direction_output(rtc->msecure_gpio, 0); + } else + dev_warn(&pdev->dev, "could not get msecure GPIO\n"); + } + rtc->rtc = rtc_device_register(pdev->name, &pdev->dev, &tps80031_rtc_ops, THIS_MODULE); + dev_set_drvdata(&pdev->dev, rtc); if (IS_ERR(rtc->rtc)) { err = PTR_ERR(rtc->rtc); @@ -379,7 +423,9 @@ static int __devinit tps80031_rtc_probe(struct platform_device *pdev) return -EBUSY; } + tps80031_enable_rtc_write(&pdev->dev); err = tps80031_set_bits(pdev->dev.parent, 1, RTC_INT, ENABLE_ALARM_INT); + tps80031_disable_rtc_write(&pdev->dev); if (err) { dev_err(&pdev->dev, "unable to program Interrupt Mask reg\n"); err = -EBUSY; @@ -388,7 +434,6 @@ static int __devinit tps80031_rtc_probe(struct platform_device *pdev) } else rtc->alarm_irq_enabled = 1; - dev_set_drvdata(&pdev->dev, rtc); if (pdata && (pdata->irq >= 0)) { rtc->irq = pdata->irq; err = request_threaded_irq(pdata->irq, NULL, tps80031_rtc_irq, |