From 01a4ca16c897882635c937bf8f967584883669a2 Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Thu, 21 Feb 2013 16:44:22 -0800 Subject: drivers/rtc: dump small buffers via %*ph Signed-off-by: Andy Shevchenko Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/rtc/rtc-ds1305.c | 8 ++------ drivers/rtc/rtc-ds1307.c | 11 ++--------- drivers/rtc/rtc-fm3130.c | 33 ++++----------------------------- 3 files changed, 8 insertions(+), 44 deletions(-) (limited to 'drivers/rtc') diff --git a/drivers/rtc/rtc-ds1305.c b/drivers/rtc/rtc-ds1305.c index d578773f5ce2..b05a6dc96405 100644 --- a/drivers/rtc/rtc-ds1305.c +++ b/drivers/rtc/rtc-ds1305.c @@ -635,9 +635,7 @@ static int ds1305_probe(struct spi_device *spi) goto fail0; } - dev_dbg(&spi->dev, "ctrl %s: %02x %02x %02x\n", - "read", ds1305->ctrl[0], - ds1305->ctrl[1], ds1305->ctrl[2]); + dev_dbg(&spi->dev, "ctrl %s: %3ph\n", "read", ds1305->ctrl); /* Sanity check register values ... partially compensating for the * fact that SPI has no device handshake. A pullup on MISO would @@ -723,9 +721,7 @@ static int ds1305_probe(struct spi_device *spi) goto fail0; } - dev_dbg(&spi->dev, "ctrl %s: %02x %02x %02x\n", - "write", ds1305->ctrl[0], - ds1305->ctrl[1], ds1305->ctrl[2]); + dev_dbg(&spi->dev, "ctrl %s: %3ph\n", "write", ds1305->ctrl); } /* see if non-Linux software set up AM/PM mode */ diff --git a/drivers/rtc/rtc-ds1307.c b/drivers/rtc/rtc-ds1307.c index e0d0ba4de03f..970a236b147a 100644 --- a/drivers/rtc/rtc-ds1307.c +++ b/drivers/rtc/rtc-ds1307.c @@ -322,12 +322,7 @@ static int ds1307_get_time(struct device *dev, struct rtc_time *t) return -EIO; } - dev_dbg(dev, "%s: %02x %02x %02x %02x %02x %02x %02x\n", - "read", - ds1307->regs[0], ds1307->regs[1], - ds1307->regs[2], ds1307->regs[3], - ds1307->regs[4], ds1307->regs[5], - ds1307->regs[6]); + dev_dbg(dev, "%s: %7ph\n", "read", ds1307->regs); t->tm_sec = bcd2bin(ds1307->regs[DS1307_REG_SECS] & 0x7f); t->tm_min = bcd2bin(ds1307->regs[DS1307_REG_MIN] & 0x7f); @@ -398,9 +393,7 @@ static int ds1307_set_time(struct device *dev, struct rtc_time *t) break; } - dev_dbg(dev, "%s: %02x %02x %02x %02x %02x %02x %02x\n", - "write", buf[0], buf[1], buf[2], buf[3], - buf[4], buf[5], buf[6]); + dev_dbg(dev, "%s: %7ph\n", "write", buf); result = ds1307->write_block_data(ds1307->client, ds1307->offset, 7, buf); diff --git a/drivers/rtc/rtc-fm3130.c b/drivers/rtc/rtc-fm3130.c index 04e93c6597f8..bff3cdc5140e 100644 --- a/drivers/rtc/rtc-fm3130.c +++ b/drivers/rtc/rtc-fm3130.c @@ -116,17 +116,7 @@ static int fm3130_get_time(struct device *dev, struct rtc_time *t) fm3130_rtc_mode(dev, FM3130_MODE_NORMAL); - dev_dbg(dev, "%s: %02x %02x %02x %02x %02x %02x %02x %02x" - "%02x %02x %02x %02x %02x %02x %02x\n", - "read", - fm3130->regs[0], fm3130->regs[1], - fm3130->regs[2], fm3130->regs[3], - fm3130->regs[4], fm3130->regs[5], - fm3130->regs[6], fm3130->regs[7], - fm3130->regs[8], fm3130->regs[9], - fm3130->regs[0xa], fm3130->regs[0xb], - fm3130->regs[0xc], fm3130->regs[0xd], - fm3130->regs[0xe]); + dev_dbg(dev, "%s: %15ph\n", "read", fm3130->regs); t->tm_sec = bcd2bin(fm3130->regs[FM3130_RTC_SECONDS] & 0x7f); t->tm_min = bcd2bin(fm3130->regs[FM3130_RTC_MINUTES] & 0x7f); @@ -175,12 +165,7 @@ static int fm3130_set_time(struct device *dev, struct rtc_time *t) tmp = t->tm_year - 100; buf[FM3130_RTC_YEARS] = bin2bcd(tmp); - dev_dbg(dev, "%s: %02x %02x %02x %02x %02x %02x %02x" - "%02x %02x %02x %02x %02x %02x %02x %02x\n", - "write", buf[0], buf[1], buf[2], buf[3], - buf[4], buf[5], buf[6], buf[7], - buf[8], buf[9], buf[0xa], buf[0xb], - buf[0xc], buf[0xd], buf[0xe]); + dev_dbg(dev, "%s: %15ph\n", "write", buf); fm3130_rtc_mode(dev, FM3130_MODE_WRITE); @@ -517,18 +502,8 @@ bad_alarm: bad_clock: if (!fm3130->data_valid || !fm3130->alarm_valid) - dev_dbg(&client->dev, - "%s: %02x %02x %02x %02x %02x %02x %02x %02x" - "%02x %02x %02x %02x %02x %02x %02x\n", - "bogus registers", - fm3130->regs[0], fm3130->regs[1], - fm3130->regs[2], fm3130->regs[3], - fm3130->regs[4], fm3130->regs[5], - fm3130->regs[6], fm3130->regs[7], - fm3130->regs[8], fm3130->regs[9], - fm3130->regs[0xa], fm3130->regs[0xb], - fm3130->regs[0xc], fm3130->regs[0xd], - fm3130->regs[0xe]); + dev_dbg(&client->dev, "%s: %15ph\n", "bogus registers", + fm3130->regs); /* We won't bail out here because we just got invalid data. Time setting from u-boot doesn't work anyway */ -- cgit v1.2.3 From c4243de70f7d536d95196b8a31539298bb15238c Mon Sep 17 00:00:00 2001 From: Leo Song Date: Thu, 21 Feb 2013 16:44:23 -0800 Subject: drivers/rtc/rtc-pxa.c: fix alarm not match issue Fix pxa rtc alarm issue by setting week of month and day of week in rdar/rdcr or it would not match. Signed-off-by: Leo Song Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/rtc/rtc-pxa.c | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) (limited to 'drivers/rtc') diff --git a/drivers/rtc/rtc-pxa.c b/drivers/rtc/rtc-pxa.c index f771b2ee4b18..2695e556f141 100644 --- a/drivers/rtc/rtc-pxa.c +++ b/drivers/rtc/rtc-pxa.c @@ -62,6 +62,10 @@ #define RYxR_MONTH_S 5 #define RYxR_MONTH_MASK (0xf << RYxR_MONTH_S) #define RYxR_DAY_MASK 0x1f +#define RDxR_WOM_S 20 +#define RDxR_WOM_MASK (0x7 << RDxR_WOM_S) +#define RDxR_DOW_S 17 +#define RDxR_DOW_MASK (0x7 << RDxR_DOW_S) #define RDxR_HOUR_S 12 #define RDxR_HOUR_MASK (0x1f << RDxR_HOUR_S) #define RDxR_MIN_S 6 @@ -91,6 +95,7 @@ struct pxa_rtc { spinlock_t lock; /* Protects this structure */ }; + static u32 ryxr_calc(struct rtc_time *tm) { return ((tm->tm_year + 1900) << RYxR_YEAR_S) @@ -100,7 +105,10 @@ static u32 ryxr_calc(struct rtc_time *tm) static u32 rdxr_calc(struct rtc_time *tm) { - return (tm->tm_hour << RDxR_HOUR_S) | (tm->tm_min << RDxR_MIN_S) + return ((((tm->tm_mday + 6) / 7) << RDxR_WOM_S) & RDxR_WOM_MASK) + | (((tm->tm_wday + 1) << RDxR_DOW_S) & RDxR_DOW_MASK) + | (tm->tm_hour << RDxR_HOUR_S) + | (tm->tm_min << RDxR_MIN_S) | tm->tm_sec; } @@ -109,6 +117,7 @@ static void tm_calc(u32 rycr, u32 rdcr, struct rtc_time *tm) tm->tm_year = ((rycr & RYxR_YEAR_MASK) >> RYxR_YEAR_S) - 1900; tm->tm_mon = (((rycr & RYxR_MONTH_MASK) >> RYxR_MONTH_S)) - 1; tm->tm_mday = (rycr & RYxR_DAY_MASK); + tm->tm_wday = ((rycr & RDxR_DOW_MASK) >> RDxR_DOW_S) - 1; tm->tm_hour = (rdcr & RDxR_HOUR_MASK) >> RDxR_HOUR_S; tm->tm_min = (rdcr & RDxR_MIN_MASK) >> RDxR_MIN_S; tm->tm_sec = rdcr & RDxR_SEC_MASK; -- cgit v1.2.3 From a44802f8fb7e593adabc6ef53c8df45a1717fa9b Mon Sep 17 00:00:00 2001 From: Leo Song Date: Thu, 21 Feb 2013 16:44:24 -0800 Subject: drivers/rtc/rtc-pxa.c: fix alarm can't wake up system issue Fix alarm can't wake up system issue Signed-off-by: Leo Song Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/rtc/rtc-pxa.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) (limited to 'drivers/rtc') diff --git a/drivers/rtc/rtc-pxa.c b/drivers/rtc/rtc-pxa.c index 2695e556f141..dbc24e948fe8 100644 --- a/drivers/rtc/rtc-pxa.c +++ b/drivers/rtc/rtc-pxa.c @@ -309,8 +309,6 @@ static int pxa_rtc_proc(struct device *dev, struct seq_file *seq) } static const struct rtc_class_ops pxa_rtc_ops = { - .open = pxa_rtc_open, - .release = pxa_rtc_release, .read_time = pxa_rtc_read_time, .set_time = pxa_rtc_set_time, .read_alarm = pxa_rtc_read_alarm, @@ -350,7 +348,7 @@ static int __init pxa_rtc_probe(struct platform_device *pdev) dev_err(dev, "No alarm IRQ resource defined\n"); goto err_ress; } - + pxa_rtc_open(dev); ret = -ENOMEM; pxa_rtc->base = ioremap(pxa_rtc->ress->start, resource_size(pxa_rtc->ress)); @@ -396,6 +394,9 @@ static int __exit pxa_rtc_remove(struct platform_device *pdev) { struct pxa_rtc *pxa_rtc = platform_get_drvdata(pdev); + struct device *dev = &pdev->dev; + pxa_rtc_release(dev); + rtc_device_unregister(pxa_rtc->rtc); spin_lock_irq(&pxa_rtc->lock); -- cgit v1.2.3 From fca1dd031a28da74db3df4921dc36fa78941c99f Mon Sep 17 00:00:00 2001 From: Jonghwa Lee Date: Thu, 21 Feb 2013 16:44:26 -0800 Subject: rtc: max77686: add Maxim 77686 driver Add a driver to support max77686 rtc. MAX77686 rtc support smpl and wtsr mode. It has two alarm register which can be used for alarming to wake system up. This drvier uses regmap to access its register. [akpm@linux-foundation.org: remove inline, __devinit annotations] [jg1.han@samsung.com: fix build warnings] [akpm@linux-foundation.org: simplify code] Signed-off-by: Chiwoong Byun Signed-off-by: Jonghwa Lee Signed-off-by: Myugnjoo Ham Signed-off-by: Kyungmin Park Signed-off-by: Jingoo Han Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/rtc/Kconfig | 10 + drivers/rtc/Makefile | 1 + drivers/rtc/rtc-max77686.c | 641 +++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 652 insertions(+) create mode 100644 drivers/rtc/rtc-max77686.c (limited to 'drivers/rtc') diff --git a/drivers/rtc/Kconfig b/drivers/rtc/Kconfig index 5e44eaabf457..7a8dd0c2cae4 100644 --- a/drivers/rtc/Kconfig +++ b/drivers/rtc/Kconfig @@ -243,6 +243,16 @@ config RTC_DRV_MAX8998 This driver can also be built as a module. If so, the module will be called rtc-max8998. +config RTC_DRV_MAX77686 + tristate "Maxim MAX77686" + depends on MFD_MAX77686 + help + If you say yes here you will get support for the + RTC of Maxim MAX77686 PMIC. + + This driver can also be built as a module. If so, the module + will be called rtc-max77686. + config RTC_DRV_RS5C372 tristate "Ricoh R2025S/D, RS5C372A/B, RV5C386, RV5C387A" help diff --git a/drivers/rtc/Makefile b/drivers/rtc/Makefile index ec2988b00a44..327c430fdb9f 100644 --- a/drivers/rtc/Makefile +++ b/drivers/rtc/Makefile @@ -71,6 +71,7 @@ obj-$(CONFIG_RTC_DRV_MAX8907) += rtc-max8907.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_MAX77686) += rtc-max77686.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 diff --git a/drivers/rtc/rtc-max77686.c b/drivers/rtc/rtc-max77686.c new file mode 100644 index 000000000000..8ab56b00e693 --- /dev/null +++ b/drivers/rtc/rtc-max77686.c @@ -0,0 +1,641 @@ +/* + * RTC driver for Maxim MAX77686 + * + * Copyright (C) 2012 Samsung Electronics Co.Ltd + * + * based on rtc-max8997.c + * + * 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 +#include + +/* RTC Control Register */ +#define BCD_EN_SHIFT 0 +#define BCD_EN_MASK (1 << BCD_EN_SHIFT) +#define MODEL24_SHIFT 1 +#define MODEL24_MASK (1 << MODEL24_SHIFT) +/* RTC Update Register1 */ +#define RTC_UDR_SHIFT 0 +#define RTC_UDR_MASK (1 << RTC_UDR_SHIFT) +#define RTC_RBUDR_SHIFT 4 +#define RTC_RBUDR_MASK (1 << RTC_RBUDR_SHIFT) +/* WTSR and SMPL Register */ +#define WTSRT_SHIFT 0 +#define SMPLT_SHIFT 2 +#define WTSR_EN_SHIFT 6 +#define SMPL_EN_SHIFT 7 +#define WTSRT_MASK (3 << WTSRT_SHIFT) +#define SMPLT_MASK (3 << SMPLT_SHIFT) +#define WTSR_EN_MASK (1 << WTSR_EN_SHIFT) +#define SMPL_EN_MASK (1 << SMPL_EN_SHIFT) +/* RTC Hour register */ +#define HOUR_PM_SHIFT 6 +#define HOUR_PM_MASK (1 << HOUR_PM_SHIFT) +/* RTC Alarm Enable */ +#define ALARM_ENABLE_SHIFT 7 +#define ALARM_ENABLE_MASK (1 << ALARM_ENABLE_SHIFT) + +#define MAX77686_RTC_UPDATE_DELAY 16 +#undef MAX77686_RTC_WTSR_SMPL + +enum { + RTC_SEC = 0, + RTC_MIN, + RTC_HOUR, + RTC_WEEKDAY, + RTC_MONTH, + RTC_YEAR, + RTC_DATE, + RTC_NR_TIME +}; + +struct max77686_rtc_info { + struct device *dev; + struct max77686_dev *max77686; + struct i2c_client *rtc; + struct rtc_device *rtc_dev; + struct mutex lock; + + struct regmap *regmap; + + int virq; + int rtc_24hr_mode; +}; + +enum MAX77686_RTC_OP { + MAX77686_RTC_WRITE, + MAX77686_RTC_READ, +}; + +static inline int max77686_rtc_calculate_wday(u8 shifted) +{ + int counter = -1; + while (shifted) { + shifted >>= 1; + counter++; + } + return counter; +} + +static void max77686_rtc_data_to_tm(u8 *data, struct rtc_time *tm, + int rtc_24hr_mode) +{ + tm->tm_sec = data[RTC_SEC] & 0x7f; + tm->tm_min = data[RTC_MIN] & 0x7f; + if (rtc_24hr_mode) + tm->tm_hour = data[RTC_HOUR] & 0x1f; + else { + tm->tm_hour = data[RTC_HOUR] & 0x0f; + if (data[RTC_HOUR] & HOUR_PM_MASK) + tm->tm_hour += 12; + } + + tm->tm_wday = max77686_rtc_calculate_wday(data[RTC_WEEKDAY] & 0x7f); + tm->tm_mday = data[RTC_DATE] & 0x1f; + tm->tm_mon = (data[RTC_MONTH] & 0x0f) - 1; + tm->tm_year = (data[RTC_YEAR] & 0x7f) + 100; + tm->tm_yday = 0; + tm->tm_isdst = 0; +} + +static int max77686_rtc_tm_to_data(struct rtc_time *tm, u8 *data) +{ + data[RTC_SEC] = tm->tm_sec; + data[RTC_MIN] = tm->tm_min; + data[RTC_HOUR] = tm->tm_hour; + data[RTC_WEEKDAY] = 1 << tm->tm_wday; + data[RTC_DATE] = tm->tm_mday; + data[RTC_MONTH] = tm->tm_mon + 1; + data[RTC_YEAR] = tm->tm_year > 100 ? (tm->tm_year - 100) : 0 ; + + if (tm->tm_year < 100) { + pr_warn("%s: MAX77686 RTC cannot handle the year %d." + "Assume it's 2000.\n", __func__, 1900 + tm->tm_year); + return -EINVAL; + } + return 0; +} + +static int max77686_rtc_update(struct max77686_rtc_info *info, + enum MAX77686_RTC_OP op) +{ + int ret; + unsigned int data; + + if (op == MAX77686_RTC_WRITE) + data = 1 << RTC_UDR_SHIFT; + else + data = 1 << RTC_RBUDR_SHIFT; + + ret = regmap_update_bits(info->max77686->rtc_regmap, + MAX77686_RTC_UPDATE0, data, data); + if (ret < 0) + dev_err(info->dev, "%s: fail to write update reg(ret=%d, data=0x%x)\n", + __func__, ret, data); + else { + /* Minimum 16ms delay required before RTC update. */ + msleep(MAX77686_RTC_UPDATE_DELAY); + } + + return ret; +} + +static int max77686_rtc_read_time(struct device *dev, struct rtc_time *tm) +{ + struct max77686_rtc_info *info = dev_get_drvdata(dev); + u8 data[RTC_NR_TIME]; + int ret; + + mutex_lock(&info->lock); + + ret = max77686_rtc_update(info, MAX77686_RTC_READ); + if (ret < 0) + goto out; + + ret = regmap_bulk_read(info->max77686->rtc_regmap, + MAX77686_RTC_SEC, data, RTC_NR_TIME); + if (ret < 0) { + dev_err(info->dev, "%s: fail to read time reg(%d)\n", __func__, ret); + goto out; + } + + max77686_rtc_data_to_tm(data, tm, info->rtc_24hr_mode); + + ret = rtc_valid_tm(tm); + +out: + mutex_unlock(&info->lock); + return ret; +} + +static int max77686_rtc_set_time(struct device *dev, struct rtc_time *tm) +{ + struct max77686_rtc_info *info = dev_get_drvdata(dev); + u8 data[RTC_NR_TIME]; + int ret; + + ret = max77686_rtc_tm_to_data(tm, data); + if (ret < 0) + return ret; + + mutex_lock(&info->lock); + + ret = regmap_bulk_write(info->max77686->rtc_regmap, + MAX77686_RTC_SEC, data, RTC_NR_TIME); + if (ret < 0) { + dev_err(info->dev, "%s: fail to write time reg(%d)\n", __func__, + ret); + goto out; + } + + ret = max77686_rtc_update(info, MAX77686_RTC_WRITE); + +out: + mutex_unlock(&info->lock); + return ret; +} + +static int max77686_rtc_read_alarm(struct device *dev, struct rtc_wkalrm *alrm) +{ + struct max77686_rtc_info *info = dev_get_drvdata(dev); + u8 data[RTC_NR_TIME]; + unsigned int val; + int i, ret; + + mutex_lock(&info->lock); + + ret = max77686_rtc_update(info, MAX77686_RTC_READ); + if (ret < 0) + goto out; + + ret = regmap_bulk_read(info->max77686->rtc_regmap, + MAX77686_ALARM1_SEC, data, RTC_NR_TIME); + if (ret < 0) { + dev_err(info->dev, "%s:%d fail to read alarm reg(%d)\n", + __func__, __LINE__, ret); + goto out; + } + + max77686_rtc_data_to_tm(data, &alrm->time, info->rtc_24hr_mode); + + alrm->enabled = 0; + for (i = 0; i < RTC_NR_TIME; i++) { + if (data[i] & ALARM_ENABLE_MASK) { + alrm->enabled = 1; + break; + } + } + + alrm->pending = 0; + ret = regmap_read(info->max77686->regmap, MAX77686_REG_STATUS1, &val); + if (ret < 0) { + dev_err(info->dev, "%s:%d fail to read status1 reg(%d)\n", + __func__, __LINE__, ret); + goto out; + } + + if (val & (1 << 4)) /* RTCA1 */ + alrm->pending = 1; + +out: + mutex_unlock(&info->lock); + return 0; +} + +static int max77686_rtc_stop_alarm(struct max77686_rtc_info *info) +{ + u8 data[RTC_NR_TIME]; + int ret, i; + struct rtc_time tm; + + if (!mutex_is_locked(&info->lock)) + dev_warn(info->dev, "%s: should have mutex locked\n", __func__); + + ret = max77686_rtc_update(info, MAX77686_RTC_READ); + if (ret < 0) + goto out; + + ret = regmap_bulk_read(info->max77686->rtc_regmap, + MAX77686_ALARM1_SEC, data, RTC_NR_TIME); + if (ret < 0) { + dev_err(info->dev, "%s: fail to read alarm reg(%d)\n", + __func__, ret); + goto out; + } + + max77686_rtc_data_to_tm(data, &tm, info->rtc_24hr_mode); + + for (i = 0; i < RTC_NR_TIME; i++) + data[i] &= ~ALARM_ENABLE_MASK; + + ret = regmap_bulk_write(info->max77686->rtc_regmap, + MAX77686_ALARM1_SEC, data, RTC_NR_TIME); + if (ret < 0) { + dev_err(info->dev, "%s: fail to write alarm reg(%d)\n", + __func__, ret); + goto out; + } + + ret = max77686_rtc_update(info, MAX77686_RTC_WRITE); +out: + return ret; +} + +static int max77686_rtc_start_alarm(struct max77686_rtc_info *info) +{ + u8 data[RTC_NR_TIME]; + int ret; + struct rtc_time tm; + + if (!mutex_is_locked(&info->lock)) + dev_warn(info->dev, "%s: should have mutex locked\n", __func__); + + ret = max77686_rtc_update(info, MAX77686_RTC_READ); + if (ret < 0) + goto out; + + ret = regmap_bulk_read(info->max77686->rtc_regmap, + MAX77686_ALARM1_SEC, data, RTC_NR_TIME); + if (ret < 0) { + dev_err(info->dev, "%s: fail to read alarm reg(%d)\n", + __func__, ret); + goto out; + } + + max77686_rtc_data_to_tm(data, &tm, info->rtc_24hr_mode); + + data[RTC_SEC] |= (1 << ALARM_ENABLE_SHIFT); + data[RTC_MIN] |= (1 << ALARM_ENABLE_SHIFT); + data[RTC_HOUR] |= (1 << ALARM_ENABLE_SHIFT); + data[RTC_WEEKDAY] &= ~ALARM_ENABLE_MASK; + if (data[RTC_MONTH] & 0xf) + data[RTC_MONTH] |= (1 << ALARM_ENABLE_SHIFT); + if (data[RTC_YEAR] & 0x7f) + data[RTC_YEAR] |= (1 << ALARM_ENABLE_SHIFT); + if (data[RTC_DATE] & 0x1f) + data[RTC_DATE] |= (1 << ALARM_ENABLE_SHIFT); + + ret = regmap_bulk_write(info->max77686->rtc_regmap, + MAX77686_ALARM1_SEC, data, RTC_NR_TIME); + if (ret < 0) { + dev_err(info->dev, "%s: fail to write alarm reg(%d)\n", + __func__, ret); + goto out; + } + + ret = max77686_rtc_update(info, MAX77686_RTC_WRITE); +out: + return ret; +} + +static int max77686_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alrm) +{ + struct max77686_rtc_info *info = dev_get_drvdata(dev); + u8 data[RTC_NR_TIME]; + int ret; + + ret = max77686_rtc_tm_to_data(&alrm->time, data); + if (ret < 0) + return ret; + + mutex_lock(&info->lock); + + ret = max77686_rtc_stop_alarm(info); + if (ret < 0) + goto out; + + ret = regmap_bulk_write(info->max77686->rtc_regmap, + MAX77686_ALARM1_SEC, data, RTC_NR_TIME); + + if (ret < 0) { + dev_err(info->dev, "%s: fail to write alarm reg(%d)\n", + __func__, ret); + goto out; + } + + ret = max77686_rtc_update(info, MAX77686_RTC_WRITE); + if (ret < 0) + goto out; + + if (alrm->enabled) + ret = max77686_rtc_start_alarm(info); +out: + mutex_unlock(&info->lock); + return ret; +} + +static int max77686_rtc_alarm_irq_enable(struct device *dev, + unsigned int enabled) +{ + struct max77686_rtc_info *info = dev_get_drvdata(dev); + int ret; + + mutex_lock(&info->lock); + if (enabled) + ret = max77686_rtc_start_alarm(info); + else + ret = max77686_rtc_stop_alarm(info); + mutex_unlock(&info->lock); + + return ret; +} + +static irqreturn_t max77686_rtc_alarm_irq(int irq, void *data) +{ + struct max77686_rtc_info *info = data; + + dev_info(info->dev, "%s:irq(%d)\n", __func__, irq); + + rtc_update_irq(info->rtc_dev, 1, RTC_IRQF | RTC_AF); + + return IRQ_HANDLED; +} + +static const struct rtc_class_ops max77686_rtc_ops = { + .read_time = max77686_rtc_read_time, + .set_time = max77686_rtc_set_time, + .read_alarm = max77686_rtc_read_alarm, + .set_alarm = max77686_rtc_set_alarm, + .alarm_irq_enable = max77686_rtc_alarm_irq_enable, +}; + +#ifdef MAX77686_RTC_WTSR_SMPL +static void max77686_rtc_enable_wtsr(struct max77686_rtc_info *info, bool enable) +{ + int ret; + unsigned int val, mask; + + if (enable) + val = (1 << WTSR_EN_SHIFT) | (3 << WTSRT_SHIFT); + else + val = 0; + + mask = WTSR_EN_MASK | WTSRT_MASK; + + dev_info(info->dev, "%s: %s WTSR\n", __func__, + enable ? "enable" : "disable"); + + ret = regmap_update_bits(info->max77686->rtc_regmap, + MAX77686_WTSR_SMPL_CNTL, mask, val); + if (ret < 0) { + dev_err(info->dev, "%s: fail to update WTSR reg(%d)\n", + __func__, ret); + return; + } + + max77686_rtc_update(info, MAX77686_RTC_WRITE); +} + +static void max77686_rtc_enable_smpl(struct max77686_rtc_info *info, bool enable) +{ + int ret; + unsigned int val, mask; + + if (enable) + val = (1 << SMPL_EN_SHIFT) | (0 << SMPLT_SHIFT); + else + val = 0; + + mask = SMPL_EN_MASK | SMPLT_MASK; + + dev_info(info->dev, "%s: %s SMPL\n", __func__, + enable ? "enable" : "disable"); + + ret = regmap_update_bits(info->max77686->rtc_regmap, + MAX77686_WTSR_SMPL_CNTL, mask, val); + if (ret < 0) { + dev_err(info->dev, "%s: fail to update SMPL reg(%d)\n", + __func__, ret); + return; + } + + max77686_rtc_update(info, MAX77686_RTC_WRITE); + + val = 0; + regmap_read(info->max77686->rtc_regmap, MAX77686_WTSR_SMPL_CNTL, &val); + pr_info("%s: WTSR_SMPL(0x%02x)\n", __func__, val); +} +#endif /* MAX77686_RTC_WTSR_SMPL */ + +static int max77686_rtc_init_reg(struct max77686_rtc_info *info) +{ + u8 data[2]; + int ret; + + /* Set RTC control register : Binary mode, 24hour mdoe */ + data[0] = (1 << BCD_EN_SHIFT) | (1 << MODEL24_SHIFT); + data[1] = (0 << BCD_EN_SHIFT) | (1 << MODEL24_SHIFT); + + info->rtc_24hr_mode = 1; + + ret = regmap_bulk_write(info->max77686->rtc_regmap, MAX77686_RTC_CONTROLM, data, 2); + if (ret < 0) { + dev_err(info->dev, "%s: fail to write controlm reg(%d)\n", + __func__, ret); + return ret; + } + + ret = max77686_rtc_update(info, MAX77686_RTC_WRITE); + return ret; +} + +static struct regmap_config max77686_rtc_regmap_config = { + .reg_bits = 8, + .val_bits = 8, +}; + +static int max77686_rtc_probe(struct platform_device *pdev) +{ + struct max77686_dev *max77686 = dev_get_drvdata(pdev->dev.parent); + struct max77686_rtc_info *info; + int ret, virq; + + printk(KERN_INFO "%s\n", __func__); + + info = kzalloc(sizeof(struct max77686_rtc_info), GFP_KERNEL); + if (!info) + return -ENOMEM; + + mutex_init(&info->lock); + info->dev = &pdev->dev; + info->max77686 = max77686; + info->rtc = max77686->rtc; + info->max77686->rtc_regmap = regmap_init_i2c(info->max77686->rtc, + &max77686_rtc_regmap_config); + if (IS_ERR(info->max77686->rtc_regmap)) { + ret = PTR_ERR(info->max77686->rtc_regmap); + dev_err(info->max77686->dev, "Failed to allocate register map: %d\n", + ret); + kfree(info); + return ret; + } + platform_set_drvdata(pdev, info); + + ret = max77686_rtc_init_reg(info); + + if (ret < 0) { + dev_err(&pdev->dev, "Failed to initialize RTC reg:%d\n", ret); + goto err_rtc; + } + +#ifdef MAX77686_RTC_WTSR_SMPL + max77686_rtc_enable_wtsr(info, true); + max77686_rtc_enable_smpl(info, true); +#endif + + device_init_wakeup(&pdev->dev, 1); + + info->rtc_dev = rtc_device_register("max77686-rtc", &pdev->dev, + &max77686_rtc_ops, THIS_MODULE); + + if (IS_ERR(info->rtc_dev)) { + printk(KERN_INFO "%s: fail\n", __func__); + + ret = PTR_ERR(info->rtc_dev); + dev_err(&pdev->dev, "Failed to register RTC device: %d\n", ret); + if (ret == 0) + ret = -EINVAL; + goto err_rtc; + } + virq = irq_create_mapping(max77686->irq_domain, MAX77686_RTCIRQ_RTCA1); + if (!virq) + goto err_rtc; + info->virq = virq; + + ret = request_threaded_irq(virq, NULL, max77686_rtc_alarm_irq, 0, + "rtc-alarm0", info); + if (ret < 0) { + dev_err(&pdev->dev, "Failed to request alarm IRQ: %d: %d\n", + info->virq, ret); + goto err_rtc; + } + + goto out; +err_rtc: + kfree(info); + return ret; +out: + return ret; +} + +static int max77686_rtc_remove(struct platform_device *pdev) +{ + struct max77686_rtc_info *info = platform_get_drvdata(pdev); + + if (info) { + free_irq(info->virq, info); + rtc_device_unregister(info->rtc_dev); + kfree(info); + } + + return 0; +} + +static void max77686_rtc_shutdown(struct platform_device *pdev) +{ +#ifdef MAX77686_RTC_WTSR_SMPL + struct max77686_rtc_info *info = platform_get_drvdata(pdev); + int i; + u8 val = 0; + + for (i = 0; i < 3; i++) { + max77686_rtc_enable_wtsr(info, false); + regmap_read(info->max77686->rtc_regmap, MAX77686_WTSR_SMPL_CNTL, &val); + pr_info("%s: WTSR_SMPL reg(0x%02x)\n", __func__, val); + if (val & WTSR_EN_MASK) + pr_emerg("%s: fail to disable WTSR\n", __func__); + else { + pr_info("%s: success to disable WTSR\n", __func__); + break; + } + } + + /* Disable SMPL when power off */ + max77686_rtc_enable_smpl(info, false); +#endif /* MAX77686_RTC_WTSR_SMPL */ +} + +static const struct platform_device_id rtc_id[] = { + { "max77686-rtc", 0 }, + {}, +}; + +static struct platform_driver max77686_rtc_driver = { + .driver = { + .name = "max77686-rtc", + .owner = THIS_MODULE, + }, + .probe = max77686_rtc_probe, + .remove = max77686_rtc_remove, + .shutdown = max77686_rtc_shutdown, + .id_table = rtc_id, +}; + +static int __init max77686_rtc_init(void) +{ + return platform_driver_register(&max77686_rtc_driver); +} +module_init(max77686_rtc_init); + +static void __exit max77686_rtc_exit(void) +{ + platform_driver_unregister(&max77686_rtc_driver); +} +module_exit(max77686_rtc_exit); + +MODULE_DESCRIPTION("Maxim MAX77686 RTC driver"); +MODULE_AUTHOR(""); +MODULE_LICENSE("GPL"); -- cgit v1.2.3 From f32bc70d5f938cfef3e534c9db6d38a3759eac6d Mon Sep 17 00:00:00 2001 From: Jesper Nilsson Date: Thu, 21 Feb 2013 16:44:27 -0800 Subject: rtc-pcf8523: add low battery voltage support Implement reading of the battery voltage low signal for rtc-pcf8523. The bit is read-only and cannot be cleared by software, so no clear function is implemented. [akpm@linux-foundation.org: omit pcf8563_rtc_ioctl() if CONFIG_RTC_INTF_DEV=n] Signed-off-by: Jesper Nilsson Reviewed-by: Thierry Reding Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/rtc/rtc-pcf8523.c | 31 +++++++++++++++++++++++++++++++ 1 file changed, 31 insertions(+) (limited to 'drivers/rtc') diff --git a/drivers/rtc/rtc-pcf8523.c b/drivers/rtc/rtc-pcf8523.c index be05a645f99e..889e3160e701 100644 --- a/drivers/rtc/rtc-pcf8523.c +++ b/drivers/rtc/rtc-pcf8523.c @@ -23,6 +23,7 @@ #define REG_CONTROL3_PM_VDD (1 << 6) /* switch-over disabled */ #define REG_CONTROL3_PM_DSM (1 << 5) /* direct switching mode */ #define REG_CONTROL3_PM_MASK 0xe0 +#define REG_CONTROL3_BLF (1 << 2) /* battery low bit, read-only */ #define REG_SECONDS 0x03 #define REG_SECONDS_OS (1 << 7) @@ -250,9 +251,39 @@ static int pcf8523_rtc_set_time(struct device *dev, struct rtc_time *tm) return pcf8523_start_rtc(client); } +#ifdef CONFIG_RTC_INTF_DEV +static int pcf8523_rtc_ioctl(struct device *dev, unsigned int cmd, + unsigned long arg) +{ + struct i2c_client *client = to_i2c_client(dev); + u8 value; + int ret = 0, err; + + switch (cmd) { + case RTC_VL_READ: + err = pcf8523_read(client, REG_CONTROL3, &value); + if (err < 0) + return err; + + if (value & REG_CONTROL3_BLF) + ret = 1; + + if (copy_to_user((void __user *)arg, &ret, sizeof(int))) + return -EFAULT; + + return 0; + default: + return -ENOIOCTLCMD; + } +} +#else +#define pcf8523_rtc_ioctl NULL +#endif + static const struct rtc_class_ops pcf8523_rtc_ops = { .read_time = pcf8523_rtc_read_time, .set_time = pcf8523_rtc_set_time, + .ioctl = pcf8523_rtc_ioctl, }; static int pcf8523_probe(struct i2c_client *client, -- cgit v1.2.3 From c8a6046e1e0bb03406e4fc6c0a204ef58a1868e4 Mon Sep 17 00:00:00 2001 From: Sachin Kamat Date: Thu, 21 Feb 2013 16:44:28 -0800 Subject: drivers/rtc: use of_match_ptr() macro This eliminates having an #ifdef returning NULL for the case when OF is disabled. Maintains consistency in cases where OF is always selected. Signed-off-by: Sachin Kamat Cc: Alessandro Zummo Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/rtc/rtc-cmos.c | 3 +-- drivers/rtc/rtc-mpc5121.c | 5 ++++- drivers/rtc/rtc-sa1100.c | 4 +++- drivers/rtc/rtc-snvs.c | 2 +- drivers/rtc/rtc-stmp3xxx.c | 3 ++- drivers/rtc/rtc-twl.c | 6 +++++- 6 files changed, 16 insertions(+), 7 deletions(-) (limited to 'drivers/rtc') diff --git a/drivers/rtc/rtc-cmos.c b/drivers/rtc/rtc-cmos.c index 16630aa87f45..9deb9e47a67c 100644 --- a/drivers/rtc/rtc-cmos.c +++ b/drivers/rtc/rtc-cmos.c @@ -1098,7 +1098,6 @@ static __init void cmos_of_init(struct platform_device *pdev) } #else static inline void cmos_of_init(struct platform_device *pdev) {} -#define of_cmos_match NULL #endif /*----------------------------------------------------------------*/ @@ -1140,7 +1139,7 @@ static struct platform_driver cmos_platform_driver = { #ifdef CONFIG_PM .pm = &cmos_pm_ops, #endif - .of_match_table = of_cmos_match, + .of_match_table = of_match_ptr(of_cmos_match), } }; diff --git a/drivers/rtc/rtc-mpc5121.c b/drivers/rtc/rtc-mpc5121.c index bec10be96f84..bdcc60830aec 100644 --- a/drivers/rtc/rtc-mpc5121.c +++ b/drivers/rtc/rtc-mpc5121.c @@ -13,6 +13,7 @@ #include #include #include +#include #include #include #include @@ -403,17 +404,19 @@ static int mpc5121_rtc_remove(struct platform_device *op) return 0; } +#ifdef CONFIG_OF static struct of_device_id mpc5121_rtc_match[] = { { .compatible = "fsl,mpc5121-rtc", }, { .compatible = "fsl,mpc5200-rtc", }, {}, }; +#endif static struct platform_driver mpc5121_rtc_driver = { .driver = { .name = "mpc5121-rtc", .owner = THIS_MODULE, - .of_match_table = mpc5121_rtc_match, + .of_match_table = of_match_ptr(mpc5121_rtc_match), }, .probe = mpc5121_rtc_probe, .remove = mpc5121_rtc_remove, diff --git a/drivers/rtc/rtc-sa1100.c b/drivers/rtc/rtc-sa1100.c index 50a5c4adee48..df9180e80e3a 100644 --- a/drivers/rtc/rtc-sa1100.c +++ b/drivers/rtc/rtc-sa1100.c @@ -349,12 +349,14 @@ static const struct dev_pm_ops sa1100_rtc_pm_ops = { }; #endif +#ifdef CONFIG_OF static struct of_device_id sa1100_rtc_dt_ids[] = { { .compatible = "mrvl,sa1100-rtc", }, { .compatible = "mrvl,mmp-rtc", }, {} }; MODULE_DEVICE_TABLE(of, sa1100_rtc_dt_ids); +#endif static struct platform_driver sa1100_rtc_driver = { .probe = sa1100_rtc_probe, @@ -364,7 +366,7 @@ static struct platform_driver sa1100_rtc_driver = { #ifdef CONFIG_PM .pm = &sa1100_rtc_pm_ops, #endif - .of_match_table = sa1100_rtc_dt_ids, + .of_match_table = of_match_ptr(sa1100_rtc_dt_ids), }, }; diff --git a/drivers/rtc/rtc-snvs.c b/drivers/rtc/rtc-snvs.c index d5ec7854a651..9b795db3ecce 100644 --- a/drivers/rtc/rtc-snvs.c +++ b/drivers/rtc/rtc-snvs.c @@ -338,7 +338,7 @@ static struct platform_driver snvs_rtc_driver = { .name = "snvs_rtc", .owner = THIS_MODULE, .pm = &snvs_rtc_pm_ops, - .of_match_table = snvs_dt_ids, + .of_match_table = of_match_ptr(snvs_dt_ids), }, .probe = snvs_rtc_probe, .remove = snvs_rtc_remove, diff --git a/drivers/rtc/rtc-stmp3xxx.c b/drivers/rtc/rtc-stmp3xxx.c index 739ef55694f4..b2a8ed99b2bf 100644 --- a/drivers/rtc/rtc-stmp3xxx.c +++ b/drivers/rtc/rtc-stmp3xxx.c @@ -26,6 +26,7 @@ #include #include #include +#include #include @@ -280,7 +281,7 @@ static struct platform_driver stmp3xxx_rtcdrv = { .driver = { .name = "stmp3xxx-rtc", .owner = THIS_MODULE, - .of_match_table = rtc_dt_ids, + .of_match_table = of_match_ptr(rtc_dt_ids), }, }; diff --git a/drivers/rtc/rtc-twl.c b/drivers/rtc/rtc-twl.c index ccd4ad370b32..8bc6c80b184c 100644 --- a/drivers/rtc/rtc-twl.c +++ b/drivers/rtc/rtc-twl.c @@ -27,6 +27,7 @@ #include #include #include +#include #include @@ -588,11 +589,14 @@ static int twl_rtc_resume(struct platform_device *pdev) #define twl_rtc_resume NULL #endif +#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 = { @@ -604,7 +608,7 @@ static struct platform_driver twl4030rtc_driver = { .driver = { .owner = THIS_MODULE, .name = "twl_rtc", - .of_match_table = twl_rtc_of_match, + .of_match_table = of_match_ptr(twl_rtc_of_match), }, }; -- cgit v1.2.3 From 95fe8347b6ccb68c3bc0082332bffa861160c935 Mon Sep 17 00:00:00 2001 From: Haojian Zhuang Date: Thu, 21 Feb 2013 16:44:29 -0800 Subject: drivers/rtc/rtc-pxa.c: avoid cpuid checking pxa-rtc is widely used in pxa27x/pxa3xx/pxa93x/pxa95x. Checking cpuid in pxa-rtc driver is unnecessary since we assign on-chip device in soc files. Signed-off-by: Haojian Zhuang Cc: Alessandro Zummo Cc: Grant Likely Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/rtc/rtc-pxa.c | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) (limited to 'drivers/rtc') diff --git a/drivers/rtc/rtc-pxa.c b/drivers/rtc/rtc-pxa.c index dbc24e948fe8..03c85ee719a7 100644 --- a/drivers/rtc/rtc-pxa.c +++ b/drivers/rtc/rtc-pxa.c @@ -454,10 +454,7 @@ static struct platform_driver pxa_rtc_driver = { static int __init pxa_rtc_init(void) { - if (cpu_is_pxa27x() || cpu_is_pxa3xx()) - return platform_driver_probe(&pxa_rtc_driver, pxa_rtc_probe); - - return -ENODEV; + return platform_driver_probe(&pxa_rtc_driver, pxa_rtc_probe); } static void __exit pxa_rtc_exit(void) -- cgit v1.2.3 From 0b7e039243425b07a952b81ea5b4d86f46d9cf25 Mon Sep 17 00:00:00 2001 From: Peter Senna Tschudin Date: Thu, 21 Feb 2013 16:44:30 -0800 Subject: drivers/rtc: remove unnecessary semicolons Found by Coccinelle: http://coccinelle.lip6.fr/ Signed-off-by: Peter Senna Tschudin Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/rtc/rtc-isl12022.c | 2 +- drivers/rtc/rtc-pcf8563.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers/rtc') diff --git a/drivers/rtc/rtc-isl12022.c b/drivers/rtc/rtc-isl12022.c index 1850104705c0..6b4298ea683d 100644 --- a/drivers/rtc/rtc-isl12022.c +++ b/drivers/rtc/rtc-isl12022.c @@ -227,7 +227,7 @@ static int isl12022_set_datetime(struct i2c_client *client, struct rtc_time *tm) buf[ISL12022_REG_SC + i]); if (ret) return -EIO; - }; + } return 0; } diff --git a/drivers/rtc/rtc-pcf8563.c b/drivers/rtc/rtc-pcf8563.c index 7098ee89bd29..f7daf18a112e 100644 --- a/drivers/rtc/rtc-pcf8563.c +++ b/drivers/rtc/rtc-pcf8563.c @@ -181,7 +181,7 @@ static int pcf8563_set_datetime(struct i2c_client *client, struct rtc_time *tm) __func__, err, data[0], data[1]); return -EIO; } - }; + } return 0; } -- cgit v1.2.3 From 56ae1b8e420015f1428bf9443f1b3321ad789b02 Mon Sep 17 00:00:00 2001 From: Srinivas Kandagatla Date: Thu, 21 Feb 2013 16:44:31 -0800 Subject: drivers/rtc/rtc-ds2404.c: use module_platform_driver macro Remove removes some code duplication by using module_platform_driver(). Signed-off-by: Srinivas Kandagatla Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/rtc/rtc-ds2404.c | 14 +------------- 1 file changed, 1 insertion(+), 13 deletions(-) (limited to 'drivers/rtc') diff --git a/drivers/rtc/rtc-ds2404.c b/drivers/rtc/rtc-ds2404.c index 5ea9df7c8c31..4539e37c2238 100644 --- a/drivers/rtc/rtc-ds2404.c +++ b/drivers/rtc/rtc-ds2404.c @@ -283,19 +283,7 @@ static struct platform_driver rtc_device_driver = { .owner = THIS_MODULE, }, }; - -static __init int ds2404_init(void) -{ - return platform_driver_register(&rtc_device_driver); -} - -static __exit void ds2404_exit(void) -{ - platform_driver_unregister(&rtc_device_driver); -} - -module_init(ds2404_init); -module_exit(ds2404_exit); +module_platform_driver(rtc_device_driver); MODULE_DESCRIPTION("DS2404 RTC"); MODULE_AUTHOR("Sven Schnelle"); -- cgit v1.2.3 From 38ae176e01f6f9ef8159325703ef5985dee40034 Mon Sep 17 00:00:00 2001 From: "Kim, Milo" Date: Thu, 21 Feb 2013 16:44:32 -0800 Subject: rtc: add new lp8788 rtc driver TI LP8788 PMU supports regulators, battery charger, RTC, ADC, backlight driver and current sinks. This patch enables LP8788 rtc module. Signed-off-by: Milo(Woogyom) Kim Cc: "devendra.aaru" Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/rtc/Kconfig | 6 + drivers/rtc/Makefile | 1 + drivers/rtc/rtc-lp8788.c | 344 +++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 351 insertions(+) create mode 100644 drivers/rtc/rtc-lp8788.c (limited to 'drivers/rtc') diff --git a/drivers/rtc/Kconfig b/drivers/rtc/Kconfig index 7a8dd0c2cae4..e94ae65af171 100644 --- a/drivers/rtc/Kconfig +++ b/drivers/rtc/Kconfig @@ -204,6 +204,12 @@ config RTC_DRV_DS3232 This driver can also be built as a module. If so, the module will be called rtc-ds3232. +config RTC_DRV_LP8788 + tristate "TI LP8788 RTC driver" + depends on MFD_LP8788 + help + Say Y to enable support for the LP8788 RTC/ALARM driver. + config RTC_DRV_MAX6900 tristate "Maxim MAX6900" help diff --git a/drivers/rtc/Makefile b/drivers/rtc/Makefile index 327c430fdb9f..1a837767b68d 100644 --- a/drivers/rtc/Makefile +++ b/drivers/rtc/Makefile @@ -57,6 +57,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_LP8788) += rtc-lp8788.o obj-$(CONFIG_RTC_DRV_LPC32XX) += rtc-lpc32xx.o obj-$(CONFIG_RTC_DRV_LOONGSON1) += rtc-ls1x.o obj-$(CONFIG_RTC_DRV_M41T80) += rtc-m41t80.o diff --git a/drivers/rtc/rtc-lp8788.c b/drivers/rtc/rtc-lp8788.c new file mode 100644 index 000000000000..4a4e78e2231c --- /dev/null +++ b/drivers/rtc/rtc-lp8788.c @@ -0,0 +1,344 @@ +/* + * TI LP8788 MFD - rtc driver + * + * Copyright 2012 Texas Instruments + * + * Author: Milo(Woogyom) Kim + * + * 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 +#include + +/* register address */ +#define LP8788_INTEN_3 0x05 +#define LP8788_RTC_UNLOCK 0x64 +#define LP8788_RTC_SEC 0x70 +#define LP8788_ALM1_SEC 0x77 +#define LP8788_ALM1_EN 0x7D +#define LP8788_ALM2_SEC 0x7E +#define LP8788_ALM2_EN 0x84 + +/* mask/shift bits */ +#define LP8788_INT_RTC_ALM1_M BIT(1) /* Addr 05h */ +#define LP8788_INT_RTC_ALM1_S 1 +#define LP8788_INT_RTC_ALM2_M BIT(2) /* Addr 05h */ +#define LP8788_INT_RTC_ALM2_S 2 +#define LP8788_ALM_EN_M BIT(7) /* Addr 7Dh or 84h */ +#define LP8788_ALM_EN_S 7 + +#define DEFAULT_ALARM_SEL LP8788_ALARM_1 +#define LP8788_MONTH_OFFSET 1 +#define LP8788_BASE_YEAR 2000 +#define MAX_WDAY_BITS 7 +#define LP8788_WDAY_SET 1 +#define RTC_UNLOCK 0x1 +#define RTC_LATCH 0x2 +#define ALARM_IRQ_FLAG (RTC_IRQF | RTC_AF) + +enum lp8788_time { + LPTIME_SEC, + LPTIME_MIN, + LPTIME_HOUR, + LPTIME_MDAY, + LPTIME_MON, + LPTIME_YEAR, + LPTIME_WDAY, + LPTIME_MAX, +}; + +struct lp8788_rtc { + struct lp8788 *lp; + struct rtc_device *rdev; + enum lp8788_alarm_sel alarm; + int irq; +}; + +static const u8 addr_alarm_sec[LP8788_ALARM_MAX] = { + LP8788_ALM1_SEC, + LP8788_ALM2_SEC, +}; + +static const u8 addr_alarm_en[LP8788_ALARM_MAX] = { + LP8788_ALM1_EN, + LP8788_ALM2_EN, +}; + +static const u8 mask_alarm_en[LP8788_ALARM_MAX] = { + LP8788_INT_RTC_ALM1_M, + LP8788_INT_RTC_ALM2_M, +}; + +static const u8 shift_alarm_en[LP8788_ALARM_MAX] = { + LP8788_INT_RTC_ALM1_S, + LP8788_INT_RTC_ALM2_S, +}; + +static int _to_tm_wday(u8 lp8788_wday) +{ + int i; + + if (lp8788_wday == 0) + return 0; + + /* lookup defined weekday from read register value */ + for (i = 0; i < MAX_WDAY_BITS; i++) { + if ((lp8788_wday >> i) == LP8788_WDAY_SET) + break; + } + + return i + 1; +} + +static inline int _to_lp8788_wday(int tm_wday) +{ + return LP8788_WDAY_SET << (tm_wday - 1); +} + +static void lp8788_rtc_unlock(struct lp8788 *lp) +{ + lp8788_write_byte(lp, LP8788_RTC_UNLOCK, RTC_UNLOCK); + lp8788_write_byte(lp, LP8788_RTC_UNLOCK, RTC_LATCH); +} + +static int lp8788_rtc_read_time(struct device *dev, struct rtc_time *tm) +{ + struct lp8788_rtc *rtc = dev_get_drvdata(dev); + struct lp8788 *lp = rtc->lp; + u8 data[LPTIME_MAX]; + int ret; + + lp8788_rtc_unlock(lp); + + ret = lp8788_read_multi_bytes(lp, LP8788_RTC_SEC, data, LPTIME_MAX); + if (ret) + return ret; + + tm->tm_sec = data[LPTIME_SEC]; + tm->tm_min = data[LPTIME_MIN]; + tm->tm_hour = data[LPTIME_HOUR]; + tm->tm_mday = data[LPTIME_MDAY]; + tm->tm_mon = data[LPTIME_MON] - LP8788_MONTH_OFFSET; + tm->tm_year = data[LPTIME_YEAR] + LP8788_BASE_YEAR - 1900; + tm->tm_wday = _to_tm_wday(data[LPTIME_WDAY]); + + return 0; +} + +static int lp8788_rtc_set_time(struct device *dev, struct rtc_time *tm) +{ + struct lp8788_rtc *rtc = dev_get_drvdata(dev); + struct lp8788 *lp = rtc->lp; + u8 data[LPTIME_MAX - 1]; + int ret, i, year; + + year = tm->tm_year + 1900 - LP8788_BASE_YEAR; + if (year < 0) { + dev_err(lp->dev, "invalid year: %d\n", year); + return -EINVAL; + } + + /* because rtc weekday is a readonly register, do not update */ + data[LPTIME_SEC] = tm->tm_sec; + data[LPTIME_MIN] = tm->tm_min; + data[LPTIME_HOUR] = tm->tm_hour; + data[LPTIME_MDAY] = tm->tm_mday; + data[LPTIME_MON] = tm->tm_mon + LP8788_MONTH_OFFSET; + data[LPTIME_YEAR] = year; + + for (i = 0; i < ARRAY_SIZE(data); i++) { + ret = lp8788_write_byte(lp, LP8788_RTC_SEC + i, data[i]); + if (ret) + return ret; + } + + return 0; +} + +static int lp8788_read_alarm(struct device *dev, struct rtc_wkalrm *alarm) +{ + struct lp8788_rtc *rtc = dev_get_drvdata(dev); + struct lp8788 *lp = rtc->lp; + struct rtc_time *tm = &alarm->time; + u8 addr, data[LPTIME_MAX]; + int ret; + + addr = addr_alarm_sec[rtc->alarm]; + ret = lp8788_read_multi_bytes(lp, addr, data, LPTIME_MAX); + if (ret) + return ret; + + tm->tm_sec = data[LPTIME_SEC]; + tm->tm_min = data[LPTIME_MIN]; + tm->tm_hour = data[LPTIME_HOUR]; + tm->tm_mday = data[LPTIME_MDAY]; + tm->tm_mon = data[LPTIME_MON] - LP8788_MONTH_OFFSET; + tm->tm_year = data[LPTIME_YEAR] + LP8788_BASE_YEAR - 1900; + tm->tm_wday = _to_tm_wday(data[LPTIME_WDAY]); + alarm->enabled = data[LPTIME_WDAY] & LP8788_ALM_EN_M; + + return 0; +} + +static int lp8788_set_alarm(struct device *dev, struct rtc_wkalrm *alarm) +{ + struct lp8788_rtc *rtc = dev_get_drvdata(dev); + struct lp8788 *lp = rtc->lp; + struct rtc_time *tm = &alarm->time; + u8 addr, data[LPTIME_MAX]; + int ret, i, year; + + year = tm->tm_year + 1900 - LP8788_BASE_YEAR; + if (year < 0) { + dev_err(lp->dev, "invalid year: %d\n", year); + return -EINVAL; + } + + data[LPTIME_SEC] = tm->tm_sec; + data[LPTIME_MIN] = tm->tm_min; + data[LPTIME_HOUR] = tm->tm_hour; + data[LPTIME_MDAY] = tm->tm_mday; + data[LPTIME_MON] = tm->tm_mon + LP8788_MONTH_OFFSET; + data[LPTIME_YEAR] = year; + data[LPTIME_WDAY] = _to_lp8788_wday(tm->tm_wday); + + for (i = 0; i < ARRAY_SIZE(data); i++) { + addr = addr_alarm_sec[rtc->alarm] + i; + ret = lp8788_write_byte(lp, addr, data[i]); + if (ret) + return ret; + } + + alarm->enabled = 1; + addr = addr_alarm_en[rtc->alarm]; + + return lp8788_update_bits(lp, addr, LP8788_ALM_EN_M, + alarm->enabled << LP8788_ALM_EN_S); +} + +static int lp8788_alarm_irq_enable(struct device *dev, unsigned int enable) +{ + struct lp8788_rtc *rtc = dev_get_drvdata(dev); + struct lp8788 *lp = rtc->lp; + u8 mask, shift; + + if (!rtc->irq) + return -EIO; + + mask = mask_alarm_en[rtc->alarm]; + shift = shift_alarm_en[rtc->alarm]; + + return lp8788_update_bits(lp, LP8788_INTEN_3, mask, enable << shift); +} + +static const struct rtc_class_ops lp8788_rtc_ops = { + .read_time = lp8788_rtc_read_time, + .set_time = lp8788_rtc_set_time, + .read_alarm = lp8788_read_alarm, + .set_alarm = lp8788_set_alarm, + .alarm_irq_enable = lp8788_alarm_irq_enable, +}; + +static irqreturn_t lp8788_alarm_irq_handler(int irq, void *ptr) +{ + struct lp8788_rtc *rtc = ptr; + + rtc_update_irq(rtc->rdev, 1, ALARM_IRQ_FLAG); + return IRQ_HANDLED; +} + +static int lp8788_alarm_irq_register(struct platform_device *pdev, + struct lp8788_rtc *rtc) +{ + struct resource *r; + struct lp8788 *lp = rtc->lp; + struct irq_domain *irqdm = lp->irqdm; + int irq; + + rtc->irq = 0; + + /* even the alarm IRQ number is not specified, rtc time should work */ + r = platform_get_resource_byname(pdev, IORESOURCE_IRQ, LP8788_ALM_IRQ); + if (!r) + return 0; + + if (rtc->alarm == LP8788_ALARM_1) + irq = r->start; + else + irq = r->end; + + rtc->irq = irq_create_mapping(irqdm, irq); + + return request_threaded_irq(rtc->irq, NULL, lp8788_alarm_irq_handler, + 0, LP8788_ALM_IRQ, rtc); +} + +static void lp8788_alarm_irq_unregister(struct lp8788_rtc *rtc) +{ + if (rtc->irq) + free_irq(rtc->irq, rtc); +} + +static int lp8788_rtc_probe(struct platform_device *pdev) +{ + struct lp8788 *lp = dev_get_drvdata(pdev->dev.parent); + struct lp8788_rtc *rtc; + struct device *dev = &pdev->dev; + + rtc = devm_kzalloc(dev, sizeof(struct lp8788_rtc), GFP_KERNEL); + if (!rtc) + return -ENOMEM; + + rtc->lp = lp; + rtc->alarm = lp->pdata ? lp->pdata->alarm_sel : DEFAULT_ALARM_SEL; + platform_set_drvdata(pdev, rtc); + + device_init_wakeup(dev, 1); + + rtc->rdev = rtc_device_register("lp8788_rtc", dev, + &lp8788_rtc_ops, THIS_MODULE); + if (IS_ERR(rtc->rdev)) { + dev_err(dev, "can not register rtc device\n"); + return PTR_ERR(rtc->rdev); + } + + if (lp8788_alarm_irq_register(pdev, rtc)) + dev_warn(lp->dev, "no rtc irq handler\n"); + + return 0; +} + +static int lp8788_rtc_remove(struct platform_device *pdev) +{ + struct lp8788_rtc *rtc = platform_get_drvdata(pdev); + + lp8788_alarm_irq_unregister(rtc); + rtc_device_unregister(rtc->rdev); + platform_set_drvdata(pdev, NULL); + + return 0; +} + +static struct platform_driver lp8788_rtc_driver = { + .probe = lp8788_rtc_probe, + .remove = lp8788_rtc_remove, + .driver = { + .name = LP8788_DEV_RTC, + .owner = THIS_MODULE, + }, +}; +module_platform_driver(lp8788_rtc_driver); + +MODULE_DESCRIPTION("Texas Instruments LP8788 RTC Driver"); +MODULE_AUTHOR("Milo Kim"); +MODULE_LICENSE("GPL"); +MODULE_ALIAS("platform:lp8788-rtc"); -- cgit v1.2.3 From 36d6182411b9f597f9f85ec0c4bb00909fd16d59 Mon Sep 17 00:00:00 2001 From: Laxman Dewangan Date: Thu, 21 Feb 2013 16:44:34 -0800 Subject: rtc: add RTC driver for TPS80031/TPS80032 Add an RTC driver for TPS80031/TPS80032 chips by TI. This driver supports: - Setting and getting time and date. - Setting and reading alarm time. - Alarm and interrupt functionlity. [akpm@linux-foundation.org: remove obsolete __devinit/__devexit] Signed-off-by: Laxman Dewangan Reviewed-by: Devendra Naga Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/rtc/Kconfig | 8 ++ drivers/rtc/Makefile | 1 + drivers/rtc/rtc-tps80031.c | 349 +++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 358 insertions(+) create mode 100644 drivers/rtc/rtc-tps80031.c (limited to 'drivers/rtc') diff --git a/drivers/rtc/Kconfig b/drivers/rtc/Kconfig index e94ae65af171..d52183440691 100644 --- a/drivers/rtc/Kconfig +++ b/drivers/rtc/Kconfig @@ -396,6 +396,14 @@ config RTC_DRV_TPS65910 This driver can also be built as a module. If so, the module will be called rtc-tps65910. +config RTC_DRV_TPS80031 + tristate "TI TPS80031/TPS80032 RTC driver" + depends on MFD_TPS80031 + help + TI Power Managment IC TPS80031 supports RTC functionality + along with alarm. This driver supports the RTC driver for + the TPS80031 RTC module. + config RTC_DRV_RC5T583 tristate "RICOH 5T583 RTC driver" depends on MFD_RC5T583 diff --git a/drivers/rtc/Makefile b/drivers/rtc/Makefile index 1a837767b68d..cd03fb33c14c 100644 --- a/drivers/rtc/Makefile +++ b/drivers/rtc/Makefile @@ -116,6 +116,7 @@ obj-$(CONFIG_RTC_DRV_TILE) += rtc-tile.o obj-$(CONFIG_RTC_DRV_TWL4030) += rtc-twl.o obj-$(CONFIG_RTC_DRV_TPS6586X) += rtc-tps6586x.o obj-$(CONFIG_RTC_DRV_TPS65910) += rtc-tps65910.o +obj-$(CONFIG_RTC_DRV_TPS80031) += rtc-tps80031.o obj-$(CONFIG_RTC_DRV_TX4939) += rtc-tx4939.o obj-$(CONFIG_RTC_DRV_V3020) += rtc-v3020.o obj-$(CONFIG_RTC_DRV_VR41XX) += rtc-vr41xx.o diff --git a/drivers/rtc/rtc-tps80031.c b/drivers/rtc/rtc-tps80031.c new file mode 100644 index 000000000000..97406411d58c --- /dev/null +++ b/drivers/rtc/rtc-tps80031.c @@ -0,0 +1,349 @@ +/* + * rtc-tps80031.c -- TI TPS80031/TPS80032 RTC driver + * + * RTC driver for TI TPS80031/TPS80032 Fully Integrated + * Power Management with Power Path and Battery Charger + * + * Copyright (c) 2012, NVIDIA Corporation. + * + * Author: Laxman Dewangan + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation version 2. + * + * This program is distributed "as is" WITHOUT ANY WARRANTY of any kind, + * whether express or implied; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + * 02111-1307, USA + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define ENABLE_ALARM_INT 0x08 +#define ALARM_INT_STATUS 0x40 + +/** + * Setting bit to 1 in STOP_RTC will run the RTC and + * setting this bit to 0 will freeze RTC. + */ +#define STOP_RTC 0x1 + +/* Power on reset Values of RTC registers */ +#define TPS80031_RTC_POR_YEAR 0 +#define TPS80031_RTC_POR_MONTH 1 +#define TPS80031_RTC_POR_DAY 1 + +/* Numbers of registers for time and alarms */ +#define TPS80031_RTC_TIME_NUM_REGS 7 +#define TPS80031_RTC_ALARM_NUM_REGS 6 + +/** + * PMU RTC have only 2 nibbles to store year information, so using an + * offset of 100 to set the base year as 2000 for our driver. + */ +#define RTC_YEAR_OFFSET 100 + +struct tps80031_rtc { + struct rtc_device *rtc; + int irq; +}; + +static int tps80031_rtc_read_time(struct device *dev, struct rtc_time *tm) +{ + u8 buff[TPS80031_RTC_TIME_NUM_REGS]; + int ret; + + ret = tps80031_reads(dev->parent, TPS80031_SLAVE_ID1, + TPS80031_SECONDS_REG, TPS80031_RTC_TIME_NUM_REGS, buff); + if (ret < 0) { + dev_err(dev, "reading RTC_SECONDS_REG failed, err = %d\n", ret); + return ret; + } + + tm->tm_sec = bcd2bin(buff[0]); + tm->tm_min = bcd2bin(buff[1]); + tm->tm_hour = bcd2bin(buff[2]); + tm->tm_mday = bcd2bin(buff[3]); + tm->tm_mon = bcd2bin(buff[4]) - 1; + tm->tm_year = bcd2bin(buff[5]) + RTC_YEAR_OFFSET; + tm->tm_wday = bcd2bin(buff[6]); + return 0; +} + +static int tps80031_rtc_set_time(struct device *dev, struct rtc_time *tm) +{ + u8 buff[7]; + int ret; + + buff[0] = bin2bcd(tm->tm_sec); + buff[1] = bin2bcd(tm->tm_min); + buff[2] = bin2bcd(tm->tm_hour); + buff[3] = bin2bcd(tm->tm_mday); + buff[4] = bin2bcd(tm->tm_mon + 1); + buff[5] = bin2bcd(tm->tm_year % RTC_YEAR_OFFSET); + buff[6] = bin2bcd(tm->tm_wday); + + /* Stop RTC while updating the RTC time registers */ + ret = tps80031_clr_bits(dev->parent, TPS80031_SLAVE_ID1, + TPS80031_RTC_CTRL_REG, STOP_RTC); + if (ret < 0) { + dev_err(dev->parent, "Stop RTC failed, err = %d\n", ret); + return ret; + } + + ret = tps80031_writes(dev->parent, TPS80031_SLAVE_ID1, + TPS80031_SECONDS_REG, + TPS80031_RTC_TIME_NUM_REGS, buff); + if (ret < 0) { + dev_err(dev, "writing RTC_SECONDS_REG failed, err %d\n", ret); + return ret; + } + + ret = tps80031_set_bits(dev->parent, TPS80031_SLAVE_ID1, + TPS80031_RTC_CTRL_REG, STOP_RTC); + if (ret < 0) + dev_err(dev->parent, "Start RTC failed, err = %d\n", ret); + return ret; +} + +static int tps80031_rtc_alarm_irq_enable(struct device *dev, + unsigned int enable) +{ + int ret; + + if (enable) + ret = tps80031_set_bits(dev->parent, TPS80031_SLAVE_ID1, + TPS80031_RTC_INTERRUPTS_REG, ENABLE_ALARM_INT); + else + ret = tps80031_clr_bits(dev->parent, TPS80031_SLAVE_ID1, + TPS80031_RTC_INTERRUPTS_REG, ENABLE_ALARM_INT); + if (ret < 0) { + dev_err(dev, "Update on RTC_INT failed, err = %d\n", ret); + return ret; + } + return 0; +} + +static int tps80031_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alrm) +{ + u8 buff[TPS80031_RTC_ALARM_NUM_REGS]; + int ret; + + buff[0] = bin2bcd(alrm->time.tm_sec); + buff[1] = bin2bcd(alrm->time.tm_min); + buff[2] = bin2bcd(alrm->time.tm_hour); + buff[3] = bin2bcd(alrm->time.tm_mday); + buff[4] = bin2bcd(alrm->time.tm_mon + 1); + buff[5] = bin2bcd(alrm->time.tm_year % RTC_YEAR_OFFSET); + ret = tps80031_writes(dev->parent, TPS80031_SLAVE_ID1, + TPS80031_ALARM_SECONDS_REG, + TPS80031_RTC_ALARM_NUM_REGS, buff); + if (ret < 0) { + dev_err(dev, "Writing RTC_ALARM failed, err %d\n", ret); + return ret; + } + return tps80031_rtc_alarm_irq_enable(dev, alrm->enabled); +} + +static int tps80031_rtc_read_alarm(struct device *dev, struct rtc_wkalrm *alrm) +{ + u8 buff[6]; + int ret; + + ret = tps80031_reads(dev->parent, TPS80031_SLAVE_ID1, + TPS80031_ALARM_SECONDS_REG, + TPS80031_RTC_ALARM_NUM_REGS, buff); + if (ret < 0) { + dev_err(dev->parent, + "reading RTC_ALARM failed, err = %d\n", ret); + return ret; + } + + alrm->time.tm_sec = bcd2bin(buff[0]); + alrm->time.tm_min = bcd2bin(buff[1]); + alrm->time.tm_hour = bcd2bin(buff[2]); + alrm->time.tm_mday = bcd2bin(buff[3]); + alrm->time.tm_mon = bcd2bin(buff[4]) - 1; + alrm->time.tm_year = bcd2bin(buff[5]) + RTC_YEAR_OFFSET; + return 0; +} + +static int clear_alarm_int_status(struct device *dev, struct tps80031_rtc *rtc) +{ + int ret; + u8 buf; + + /** + * As per datasheet, A dummy read of this RTC_STATUS_REG register + * is necessary before each I2C read in order to update the status + * register value. + */ + ret = tps80031_read(dev->parent, TPS80031_SLAVE_ID1, + TPS80031_RTC_STATUS_REG, &buf); + if (ret < 0) { + dev_err(dev, "reading RTC_STATUS failed. err = %d\n", ret); + return ret; + } + + /* clear Alarm status bits.*/ + ret = tps80031_set_bits(dev->parent, TPS80031_SLAVE_ID1, + TPS80031_RTC_STATUS_REG, ALARM_INT_STATUS); + if (ret < 0) { + dev_err(dev, "clear Alarm INT failed, err = %d\n", ret); + return ret; + } + return 0; +} + +static irqreturn_t tps80031_rtc_irq(int irq, void *data) +{ + struct device *dev = data; + struct tps80031_rtc *rtc = dev_get_drvdata(dev); + int ret; + + ret = clear_alarm_int_status(dev, rtc); + if (ret < 0) + return ret; + + rtc_update_irq(rtc->rtc, 1, RTC_IRQF | RTC_AF); + return IRQ_HANDLED; +} + +static const struct rtc_class_ops tps80031_rtc_ops = { + .read_time = tps80031_rtc_read_time, + .set_time = tps80031_rtc_set_time, + .set_alarm = tps80031_rtc_set_alarm, + .read_alarm = tps80031_rtc_read_alarm, + .alarm_irq_enable = tps80031_rtc_alarm_irq_enable, +}; + +static int tps80031_rtc_probe(struct platform_device *pdev) +{ + struct tps80031_rtc *rtc; + struct rtc_time tm; + int ret; + + rtc = devm_kzalloc(&pdev->dev, sizeof(*rtc), GFP_KERNEL); + if (!rtc) + return -ENOMEM; + + rtc->irq = platform_get_irq(pdev, 0); + platform_set_drvdata(pdev, rtc); + + /* Start RTC */ + ret = tps80031_set_bits(pdev->dev.parent, TPS80031_SLAVE_ID1, + TPS80031_RTC_CTRL_REG, STOP_RTC); + if (ret < 0) { + dev_err(&pdev->dev, "failed to start RTC. err = %d\n", ret); + return ret; + } + + /* If RTC have POR values, set time 01:01:2000 */ + tps80031_rtc_read_time(&pdev->dev, &tm); + if ((tm.tm_year == RTC_YEAR_OFFSET + TPS80031_RTC_POR_YEAR) && + (tm.tm_mon == (TPS80031_RTC_POR_MONTH - 1)) && + (tm.tm_mday == TPS80031_RTC_POR_DAY)) { + tm.tm_year = 2000; + tm.tm_mday = 1; + tm.tm_mon = 1; + ret = tps80031_rtc_set_time(&pdev->dev, &tm); + if (ret < 0) { + dev_err(&pdev->dev, + "RTC set time failed, err = %d\n", ret); + return ret; + } + } + + /* Clear alarm intretupt status if it is there */ + ret = clear_alarm_int_status(&pdev->dev, rtc); + if (ret < 0) { + dev_err(&pdev->dev, "Clear alarm int failed, err = %d\n", ret); + return ret; + } + + rtc->rtc = rtc_device_register(pdev->name, &pdev->dev, + &tps80031_rtc_ops, THIS_MODULE); + if (IS_ERR(rtc->rtc)) { + ret = PTR_ERR(rtc->rtc); + dev_err(&pdev->dev, "RTC registration failed, err %d\n", ret); + return ret; + } + + ret = request_threaded_irq(rtc->irq, NULL, tps80031_rtc_irq, + IRQF_ONESHOT | IRQF_EARLY_RESUME, + dev_name(&pdev->dev), rtc); + if (ret < 0) { + dev_err(&pdev->dev, "request IRQ:%d failed, err = %d\n", + rtc->irq, ret); + rtc_device_unregister(rtc->rtc); + return ret; + } + device_set_wakeup_capable(&pdev->dev, 1); + return 0; +} + +static int tps80031_rtc_remove(struct platform_device *pdev) +{ + struct tps80031_rtc *rtc = platform_get_drvdata(pdev); + + free_irq(rtc->irq, rtc); + rtc_device_unregister(rtc->rtc); + return 0; +} + +#ifdef CONFIG_PM_SLEEP +static int tps80031_rtc_suspend(struct device *dev) +{ + struct tps80031_rtc *rtc = dev_get_drvdata(dev); + + if (device_may_wakeup(dev)) + enable_irq_wake(rtc->irq); + return 0; +} + +static int tps80031_rtc_resume(struct device *dev) +{ + struct tps80031_rtc *rtc = dev_get_drvdata(dev); + + if (device_may_wakeup(dev)) + disable_irq_wake(rtc->irq); + return 0; +}; +#endif + +static const struct dev_pm_ops tps80031_pm_ops = { + SET_SYSTEM_SLEEP_PM_OPS(tps80031_rtc_suspend, tps80031_rtc_resume) +}; + +static struct platform_driver tps80031_rtc_driver = { + .driver = { + .name = "tps80031-rtc", + .owner = THIS_MODULE, + .pm = &tps80031_pm_ops, + }, + .probe = tps80031_rtc_probe, + .remove = tps80031_rtc_remove, +}; + +module_platform_driver(tps80031_rtc_driver); + +MODULE_ALIAS("platform:tps80031-rtc"); +MODULE_DESCRIPTION("TI TPS80031/TPS80032 RTC driver"); +MODULE_AUTHOR("Laxman Dewangan "); +MODULE_LICENSE("GPL v2"); -- cgit v1.2.3 From eb5eba4ef72248b976465906cfed5fca2e9d8831 Mon Sep 17 00:00:00 2001 From: Laxman Dewangan Date: Thu, 21 Feb 2013 16:44:35 -0800 Subject: drivers/rtc/rtc-tps65910.c: enable/disable wake in suspend/resume Making the rtc driver as wakeup capabale and leaving the wake enable/disable decision to user space through a sysfs attribute. In suspend, enable wake if device wakeup enabled. In resume disable wake again. This change is inline with the Documentation/power/devices.txt# /sys/devices/.../power/wakeup files Signed-off-by: Laxman Dewangan Cc: Mark Brown Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/rtc/rtc-tps65910.c | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) (limited to 'drivers/rtc') diff --git a/drivers/rtc/rtc-tps65910.c b/drivers/rtc/rtc-tps65910.c index e5fef141a0e2..932a655aa41c 100644 --- a/drivers/rtc/rtc-tps65910.c +++ b/drivers/rtc/rtc-tps65910.c @@ -27,6 +27,7 @@ struct tps65910_rtc { struct rtc_device *rtc; + int irq; /* To store the list of enabled interrupts */ u32 irqstat; }; @@ -273,7 +274,8 @@ static int tps65910_rtc_probe(struct platform_device *pdev) dev_err(&pdev->dev, "IRQ is not free.\n"); return ret; } - device_init_wakeup(&pdev->dev, 1); + tps_rtc->irq = irq; + device_set_wakeup_capable(&pdev->dev, 1); tps_rtc->rtc = rtc_device_register(pdev->name, &pdev->dev, &tps65910_rtc_ops, THIS_MODULE); @@ -308,9 +310,13 @@ static int tps65910_rtc_remove(struct platform_device *pdev) static int tps65910_rtc_suspend(struct device *dev) { struct tps65910 *tps = dev_get_drvdata(dev->parent); + struct tps65910_rtc *tps_rtc = dev_get_drvdata(dev); u8 alarm = TPS65910_RTC_INTERRUPTS_IT_ALARM; int ret; + if (device_may_wakeup(dev)) + enable_irq_wake(tps_rtc->irq); + /* Store current list of enabled interrupts*/ ret = regmap_read(tps->regmap, TPS65910_RTC_INTERRUPTS, &tps->rtc->irqstat); @@ -324,6 +330,10 @@ static int tps65910_rtc_suspend(struct device *dev) static int tps65910_rtc_resume(struct device *dev) { struct tps65910 *tps = dev_get_drvdata(dev->parent); + struct tps65910_rtc *tps_rtc = dev_get_drvdata(dev); + + if (device_may_wakeup(dev)) + disable_irq_wake(tps_rtc->irq); /* Restore list of enabled interrupts before suspend */ return regmap_write(tps->regmap, TPS65910_RTC_INTERRUPTS, -- cgit v1.2.3 From dfaf09ac8555141b7311bb69b456bd96886fd90c Mon Sep 17 00:00:00 2001 From: Laxman Dewangan Date: Thu, 21 Feb 2013 16:44:36 -0800 Subject: drivers/rtc/rtc-tps65910.c: remove unnecessary irq stat save and restore The driver stores the interrupt enable register before going to suspend and restore in resume. Also it enables alarm before going to suspend. The driver only write the Interrupt enable register for enabling ALARM and does not enable any other bits. So it is not require to save complete register and enable ALARM interrupt before suspend and restore in resume. Also ALARM interrupt already enable if alarm is enabled before going to suspend and hence it is not require to enable explictly in suspend. Removing such above code. Signed-off-by: Laxman Dewangan Cc: Mark Brown Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/rtc/rtc-tps65910.c | 21 ++------------------- 1 file changed, 2 insertions(+), 19 deletions(-) (limited to 'drivers/rtc') diff --git a/drivers/rtc/rtc-tps65910.c b/drivers/rtc/rtc-tps65910.c index 932a655aa41c..7ef42c25358c 100644 --- a/drivers/rtc/rtc-tps65910.c +++ b/drivers/rtc/rtc-tps65910.c @@ -28,8 +28,6 @@ struct tps65910_rtc { struct rtc_device *rtc; int irq; - /* To store the list of enabled interrupts */ - u32 irqstat; }; /* Total number of RTC registers needed to set time*/ @@ -309,35 +307,20 @@ static int tps65910_rtc_remove(struct platform_device *pdev) static int tps65910_rtc_suspend(struct device *dev) { - struct tps65910 *tps = dev_get_drvdata(dev->parent); struct tps65910_rtc *tps_rtc = dev_get_drvdata(dev); - u8 alarm = TPS65910_RTC_INTERRUPTS_IT_ALARM; - int ret; if (device_may_wakeup(dev)) enable_irq_wake(tps_rtc->irq); - - /* Store current list of enabled interrupts*/ - ret = regmap_read(tps->regmap, TPS65910_RTC_INTERRUPTS, - &tps->rtc->irqstat); - if (ret < 0) - return ret; - - /* Enable RTC ALARM interrupt only */ - return regmap_write(tps->regmap, TPS65910_RTC_INTERRUPTS, alarm); + return 0; } static int tps65910_rtc_resume(struct device *dev) { - struct tps65910 *tps = dev_get_drvdata(dev->parent); struct tps65910_rtc *tps_rtc = dev_get_drvdata(dev); if (device_may_wakeup(dev)) disable_irq_wake(tps_rtc->irq); - - /* Restore list of enabled interrupts before suspend */ - return regmap_write(tps->regmap, TPS65910_RTC_INTERRUPTS, - tps->rtc->irqstat); + return 0; } static const struct dev_pm_ops tps65910_rtc_pm_ops = { -- cgit v1.2.3 From 176a9f20d29de594c07faaeb10fecff664c956c6 Mon Sep 17 00:00:00 2001 From: Laxman Dewangan Date: Thu, 21 Feb 2013 16:44:37 -0800 Subject: drivers/rtc/rtc-tps65910.c: use sleep_pm_ops macro for initialising suspend/resume callbacks Use SET_SYSTEM_SLEEP_PM_OPS for setting suspend/resume callbacks for dev_pm_ops. Signed-off-by: Laxman Dewangan Cc: Mark Brown Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/rtc/rtc-tps65910.c | 13 ++++--------- 1 file changed, 4 insertions(+), 9 deletions(-) (limited to 'drivers/rtc') diff --git a/drivers/rtc/rtc-tps65910.c b/drivers/rtc/rtc-tps65910.c index 7ef42c25358c..ff7cfe90b0c0 100644 --- a/drivers/rtc/rtc-tps65910.c +++ b/drivers/rtc/rtc-tps65910.c @@ -22,6 +22,7 @@ #include #include #include +#include #include #include @@ -304,7 +305,6 @@ static int tps65910_rtc_remove(struct platform_device *pdev) } #ifdef CONFIG_PM_SLEEP - static int tps65910_rtc_suspend(struct device *dev) { struct tps65910_rtc *tps_rtc = dev_get_drvdata(dev); @@ -322,24 +322,19 @@ static int tps65910_rtc_resume(struct device *dev) disable_irq_wake(tps_rtc->irq); return 0; } +#endif static const struct dev_pm_ops tps65910_rtc_pm_ops = { - .suspend = tps65910_rtc_suspend, - .resume = tps65910_rtc_resume, + SET_SYSTEM_SLEEP_PM_OPS(tps65910_rtc_suspend, tps65910_rtc_resume) }; -#define DEV_PM_OPS (&tps65910_rtc_pm_ops) -#else -#define DEV_PM_OPS NULL -#endif - static struct platform_driver tps65910_rtc_driver = { .probe = tps65910_rtc_probe, .remove = tps65910_rtc_remove, .driver = { .owner = THIS_MODULE, .name = "tps65910-rtc", - .pm = DEV_PM_OPS, + .pm = &tps65910_rtc_pm_ops, }, }; -- cgit v1.2.3 From 225ccc28726ca8849e5bfc9148c343e258737f3b Mon Sep 17 00:00:00 2001 From: Laxman Dewangan Date: Thu, 21 Feb 2013 16:44:38 -0800 Subject: drivers/rtc/rtc-tps65910.c: set irq flag to IRQF_EARLY_RESUME during irq request All interrupt get disabled during system suspend and enabled during system resume. The enabling/disabling of interrupt happen in sequence of interrupt registration with framework. Therefore, in resume, the parent interrupt of this device enabled before the RTC irq interrupt enabled. If RTC is enabled for alarm wake and if system wake by alarm then there is interrupt pending for RTC. In resume, the parent interrupt get enabled before the rtc interrupt and hence ISR get served. In ISR, it founds that rtc interrupt is disabled and so it does not call the rtc isr handler and hence it misses the interrupt. Setting flag for early resume so that rtc interrupt get enabled before parent interrupt and so rtc interrupt get enabled when parent interrupt handler check for interrupt of device and call the rtc handler if it is there. This way it will not miss the interrupt. Signed-off-by: Laxman Dewangan Cc: Mark Brown Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/rtc/rtc-tps65910.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/rtc') diff --git a/drivers/rtc/rtc-tps65910.c b/drivers/rtc/rtc-tps65910.c index ff7cfe90b0c0..8bd8115329b5 100644 --- a/drivers/rtc/rtc-tps65910.c +++ b/drivers/rtc/rtc-tps65910.c @@ -267,7 +267,7 @@ static int tps65910_rtc_probe(struct platform_device *pdev) } ret = devm_request_threaded_irq(&pdev->dev, irq, NULL, - tps65910_rtc_interrupt, IRQF_TRIGGER_LOW, + tps65910_rtc_interrupt, IRQF_TRIGGER_LOW | IRQF_EARLY_RESUME, dev_name(&pdev->dev), &pdev->dev); if (ret < 0) { dev_err(&pdev->dev, "IRQ is not free.\n"); -- cgit v1.2.3 From cce2da9a1fc6ef144d830587080476fec283d670 Mon Sep 17 00:00:00 2001 From: Torben Hohn Date: Thu, 21 Feb 2013 16:44:40 -0800 Subject: rtc: add support for spi rtc rx4581 [akpm@linux-foundation.org: checkpatch fixes] Signed-off-by: Torben Hohn Cc: Dan Carpenter Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/rtc/Kconfig | 8 ++ drivers/rtc/Makefile | 1 + drivers/rtc/rtc-rx4581.c | 314 +++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 323 insertions(+) create mode 100644 drivers/rtc/rtc-rx4581.c (limited to 'drivers/rtc') diff --git a/drivers/rtc/Kconfig b/drivers/rtc/Kconfig index d52183440691..2e340763ba47 100644 --- a/drivers/rtc/Kconfig +++ b/drivers/rtc/Kconfig @@ -561,6 +561,14 @@ config RTC_DRV_PCF2123 This driver can also be built as a module. If so, the module will be called rtc-pcf2123. +config RTC_DRV_RX4581 + tristate "Epson RX-4581" + help + If you say yes here you will get support for the Epson RX-4581. + + This driver can also be built as a module. If so the module + will be called rtc-rx4581. + endif # SPI_MASTER comment "Platform RTC drivers" diff --git a/drivers/rtc/Makefile b/drivers/rtc/Makefile index cd03fb33c14c..afd284d33714 100644 --- a/drivers/rtc/Makefile +++ b/drivers/rtc/Makefile @@ -98,6 +98,7 @@ obj-$(CONFIG_RTC_DRV_RS5C313) += rtc-rs5c313.o obj-$(CONFIG_RTC_DRV_RS5C348) += rtc-rs5c348.o obj-$(CONFIG_RTC_DRV_RS5C372) += rtc-rs5c372.o obj-$(CONFIG_RTC_DRV_RV3029C2) += rtc-rv3029c2.o +obj-$(CONFIG_RTC_DRV_RX4581) += rtc-rx4581.o obj-$(CONFIG_RTC_DRV_RX8025) += rtc-rx8025.o obj-$(CONFIG_RTC_DRV_RX8581) += rtc-rx8581.o obj-$(CONFIG_RTC_DRV_S35390A) += rtc-s35390a.o diff --git a/drivers/rtc/rtc-rx4581.c b/drivers/rtc/rtc-rx4581.c new file mode 100644 index 000000000000..599ec73ec886 --- /dev/null +++ b/drivers/rtc/rtc-rx4581.c @@ -0,0 +1,314 @@ +/* drivers/rtc/rtc-rx4581.c + * + * written by Torben Hohn + * + * Based on: + * drivers/rtc/rtc-max6902.c + * + * Copyright (C) 2006 8D Technologies inc. + * Copyright (C) 2004 Compulab Ltd. + * + * 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. + * + * Driver for MAX6902 spi RTC + * + * and based on: + * drivers/rtc/rtc-rx8581.c + * + * An I2C driver for the Epson RX8581 RTC + * + * Author: Martyn Welch + * Copyright 2008 GE Intelligent Platforms Embedded Systems, Inc. + * + * 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. + * + * Based on: rtc-pcf8563.c (An I2C driver for the Philips PCF8563 RTC) + * Copyright 2005-06 Tower Technologies + * + */ + +#include +#include +#include +#include +#include +#include +#include + +#define RX4581_REG_SC 0x00 /* Second in BCD */ +#define RX4581_REG_MN 0x01 /* Minute in BCD */ +#define RX4581_REG_HR 0x02 /* Hour in BCD */ +#define RX4581_REG_DW 0x03 /* Day of Week */ +#define RX4581_REG_DM 0x04 /* Day of Month in BCD */ +#define RX4581_REG_MO 0x05 /* Month in BCD */ +#define RX4581_REG_YR 0x06 /* Year in BCD */ +#define RX4581_REG_RAM 0x07 /* RAM */ +#define RX4581_REG_AMN 0x08 /* Alarm Min in BCD*/ +#define RX4581_REG_AHR 0x09 /* Alarm Hour in BCD */ +#define RX4581_REG_ADM 0x0A +#define RX4581_REG_ADW 0x0A +#define RX4581_REG_TMR0 0x0B +#define RX4581_REG_TMR1 0x0C +#define RX4581_REG_EXT 0x0D /* Extension Register */ +#define RX4581_REG_FLAG 0x0E /* Flag Register */ +#define RX4581_REG_CTRL 0x0F /* Control Register */ + + +/* Flag Register bit definitions */ +#define RX4581_FLAG_UF 0x20 /* Update */ +#define RX4581_FLAG_TF 0x10 /* Timer */ +#define RX4581_FLAG_AF 0x08 /* Alarm */ +#define RX4581_FLAG_VLF 0x02 /* Voltage Low */ + +/* Control Register bit definitions */ +#define RX4581_CTRL_UIE 0x20 /* Update Interrupt Enable */ +#define RX4581_CTRL_TIE 0x10 /* Timer Interrupt Enable */ +#define RX4581_CTRL_AIE 0x08 /* Alarm Interrupt Enable */ +#define RX4581_CTRL_STOP 0x02 /* STOP bit */ +#define RX4581_CTRL_RESET 0x01 /* RESET bit */ + +static int rx4581_set_reg(struct device *dev, unsigned char address, + unsigned char data) +{ + struct spi_device *spi = to_spi_device(dev); + unsigned char buf[2]; + + /* high nibble must be '0' to write */ + buf[0] = address & 0x0f; + buf[1] = data; + + return spi_write_then_read(spi, buf, 2, NULL, 0); +} + +static int rx4581_get_reg(struct device *dev, unsigned char address, + unsigned char *data) +{ + struct spi_device *spi = to_spi_device(dev); + + /* Set MSB to indicate read */ + *data = address | 0x80; + + return spi_write_then_read(spi, data, 1, data, 1); +} + +/* + * In the routines that deal directly with the rx8581 hardware, we use + * rtc_time -- month 0-11, hour 0-23, yr = calendar year-epoch. + */ +static int rx4581_get_datetime(struct device *dev, struct rtc_time *tm) +{ + struct spi_device *spi = to_spi_device(dev); + unsigned char date[7]; + unsigned char data; + int err; + + /* First we ensure that the "update flag" is not set, we read the + * time and date then re-read the "update flag". If the update flag + * has been set, we know that the time has changed during the read so + * we repeat the whole process again. + */ + err = rx4581_get_reg(dev, RX4581_REG_FLAG, &data); + if (err != 0) { + dev_err(dev, "Unable to read device flags\n"); + return -EIO; + } + + do { + /* If update flag set, clear it */ + if (data & RX4581_FLAG_UF) { + err = rx4581_set_reg(dev, + RX4581_REG_FLAG, (data & ~RX4581_FLAG_UF)); + if (err != 0) { + dev_err(dev, "Unable to write device " + "flags\n"); + return -EIO; + } + } + + /* Now read time and date */ + date[0] = 0x80; + err = spi_write_then_read(spi, date, 1, date, 7); + if (err < 0) { + dev_err(dev, "Unable to read date\n"); + return -EIO; + } + + /* Check flag register */ + err = rx4581_get_reg(dev, RX4581_REG_FLAG, &data); + if (err != 0) { + dev_err(dev, "Unable to read device flags\n"); + return -EIO; + } + } while (data & RX4581_FLAG_UF); + + if (data & RX4581_FLAG_VLF) + dev_info(dev, + "low voltage detected, date/time is not reliable.\n"); + + dev_dbg(dev, + "%s: raw data is sec=%02x, min=%02x, hr=%02x, " + "wday=%02x, mday=%02x, mon=%02x, year=%02x\n", + __func__, + date[0], date[1], date[2], date[3], date[4], date[5], date[6]); + + tm->tm_sec = bcd2bin(date[RX4581_REG_SC] & 0x7F); + tm->tm_min = bcd2bin(date[RX4581_REG_MN] & 0x7F); + tm->tm_hour = bcd2bin(date[RX4581_REG_HR] & 0x3F); /* rtc hr 0-23 */ + tm->tm_wday = ilog2(date[RX4581_REG_DW] & 0x7F); + tm->tm_mday = bcd2bin(date[RX4581_REG_DM] & 0x3F); + tm->tm_mon = bcd2bin(date[RX4581_REG_MO] & 0x1F) - 1; /* rtc mn 1-12 */ + tm->tm_year = bcd2bin(date[RX4581_REG_YR]); + if (tm->tm_year < 70) + tm->tm_year += 100; /* assume we are in 1970...2069 */ + + + dev_dbg(dev, "%s: tm is secs=%d, mins=%d, hours=%d, " + "mday=%d, mon=%d, year=%d, wday=%d\n", + __func__, + tm->tm_sec, tm->tm_min, tm->tm_hour, + tm->tm_mday, tm->tm_mon, tm->tm_year, tm->tm_wday); + + err = rtc_valid_tm(tm); + if (err < 0) + dev_err(dev, "retrieved date/time is not valid.\n"); + + return err; +} + +static int rx4581_set_datetime(struct device *dev, struct rtc_time *tm) +{ + struct spi_device *spi = to_spi_device(dev); + int err; + unsigned char buf[8], data; + + dev_dbg(dev, "%s: secs=%d, mins=%d, hours=%d, " + "mday=%d, mon=%d, year=%d, wday=%d\n", + __func__, + tm->tm_sec, tm->tm_min, tm->tm_hour, + tm->tm_mday, tm->tm_mon, tm->tm_year, tm->tm_wday); + + buf[0] = 0x00; + /* hours, minutes and seconds */ + buf[RX4581_REG_SC+1] = bin2bcd(tm->tm_sec); + buf[RX4581_REG_MN+1] = bin2bcd(tm->tm_min); + buf[RX4581_REG_HR+1] = bin2bcd(tm->tm_hour); + + buf[RX4581_REG_DM+1] = bin2bcd(tm->tm_mday); + + /* month, 1 - 12 */ + buf[RX4581_REG_MO+1] = bin2bcd(tm->tm_mon + 1); + + /* year and century */ + buf[RX4581_REG_YR+1] = bin2bcd(tm->tm_year % 100); + buf[RX4581_REG_DW+1] = (0x1 << tm->tm_wday); + + /* Stop the clock */ + err = rx4581_get_reg(dev, RX4581_REG_CTRL, &data); + if (err != 0) { + dev_err(dev, "Unable to read control register\n"); + return -EIO; + } + + err = rx4581_set_reg(dev, RX4581_REG_CTRL, + (data | RX4581_CTRL_STOP)); + if (err != 0) { + dev_err(dev, "Unable to write control register\n"); + return -EIO; + } + + /* write register's data */ + err = spi_write_then_read(spi, buf, 8, NULL, 0); + if (err != 0) { + dev_err(dev, "Unable to write to date registers\n"); + return -EIO; + } + + /* get VLF and clear it */ + err = rx4581_get_reg(dev, RX4581_REG_FLAG, &data); + if (err != 0) { + dev_err(dev, "Unable to read flag register\n"); + return -EIO; + } + + err = rx4581_set_reg(dev, RX4581_REG_FLAG, + (data & ~(RX4581_FLAG_VLF))); + if (err != 0) { + dev_err(dev, "Unable to write flag register\n"); + return -EIO; + } + + /* Restart the clock */ + err = rx4581_get_reg(dev, RX4581_REG_CTRL, &data); + if (err != 0) { + dev_err(dev, "Unable to read control register\n"); + return -EIO; + } + + err = rx4581_set_reg(dev, RX4581_REG_CTRL, + (data & ~(RX4581_CTRL_STOP))); + if (err != 0) { + dev_err(dev, "Unable to write control register\n"); + return -EIO; + } + + return 0; +} + +static const struct rtc_class_ops rx4581_rtc_ops = { + .read_time = rx4581_get_datetime, + .set_time = rx4581_set_datetime, +}; + +static int rx4581_probe(struct spi_device *spi) +{ + struct rtc_device *rtc; + unsigned char tmp; + int res; + + res = rx4581_get_reg(&spi->dev, RX4581_REG_SC, &tmp); + if (res != 0) + return res; + + rtc = rtc_device_register("rx4581", + &spi->dev, &rx4581_rtc_ops, THIS_MODULE); + if (IS_ERR(rtc)) + return PTR_ERR(rtc); + + dev_set_drvdata(&spi->dev, rtc); + return 0; +} + +static int rx4581_remove(struct spi_device *spi) +{ + struct rtc_device *rtc = dev_get_drvdata(&spi->dev); + + rtc_device_unregister(rtc); + return 0; +} + +static const struct spi_device_id rx4581_id[] = { + { "rx4581", 0 }, + { } +}; +MODULE_DEVICE_TABLE(spi, rx4581_id); + +static struct spi_driver rx4581_driver = { + .driver = { + .name = "rtc-rx4581", + .owner = THIS_MODULE, + }, + .probe = rx4581_probe, + .remove = rx4581_remove, + .id_table = rx4581_id, +}; + +module_spi_driver(rx4581_driver); + +MODULE_DESCRIPTION("rx4581 spi RTC driver"); +MODULE_AUTHOR("Torben Hohn"); +MODULE_LICENSE("GPL"); +MODULE_ALIAS("spi:rtc-rx4581"); -- cgit v1.2.3 From b06eef45cab7231f59b23d98ce78c090896b6103 Mon Sep 17 00:00:00 2001 From: Rob Herring Date: Thu, 21 Feb 2013 16:44:54 -0800 Subject: drivers/rtc/rtc-pl031.c: add wakeup support Mark the pl031 as wake-up capable so that rtcwake and suspend test can work. Signed-off-by: Rob Herring Cc: Srinidhi Kasagar Cc: Linus Walleij Cc: Alessandro Zummo Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/rtc/rtc-pl031.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'drivers/rtc') diff --git a/drivers/rtc/rtc-pl031.c b/drivers/rtc/rtc-pl031.c index 81c5077feff3..8900ea784817 100644 --- a/drivers/rtc/rtc-pl031.c +++ b/drivers/rtc/rtc-pl031.c @@ -384,6 +384,8 @@ static int pl031_probe(struct amba_device *adev, const struct amba_id *id) goto out_no_irq; } + device_init_wakeup(&adev->dev, 1); + return 0; out_no_irq: -- cgit v1.2.3 From d4a48c2ad75b063c54949a271e193b1bfe4934be Mon Sep 17 00:00:00 2001 From: Jingoo Han Date: Thu, 21 Feb 2013 16:45:06 -0800 Subject: drivers/rtc/rtc-s3c.c: use dev_dbg() instaed of pr_debug() Use dev_dbg() instaed of pr_debug() to be consistent. Signed-off-by: Jingoo Han 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 404651464d45..8ff5ec1c4746 100644 --- a/drivers/rtc/rtc-s3c.c +++ b/drivers/rtc/rtc-s3c.c @@ -115,7 +115,7 @@ static int s3c_rtc_setaie(struct device *dev, unsigned int enabled) { unsigned int tmp; - pr_debug("%s: aie=%d\n", __func__, enabled); + dev_dbg(dev, "%s: aie=%d\n", __func__, enabled); clk_enable(rtc_clk); tmp = readb(s3c_rtc_base + S3C2410_RTCALM) & ~S3C2410_RTCALM_ALMEN; @@ -203,7 +203,7 @@ static int s3c_rtc_gettime(struct device *dev, struct rtc_time *rtc_tm) rtc_tm->tm_year += 100; - pr_debug("read time %04d.%02d.%02d %02d:%02d:%02d\n", + dev_dbg(dev, "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); @@ -218,7 +218,7 @@ 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 %04d.%02d.%02d %02d:%02d:%02d\n", + dev_dbg(dev, "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); @@ -259,7 +259,7 @@ 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 %d, %04d.%02d.%02d %02d:%02d:%02d\n", + dev_dbg(dev, "read alarm %d, %04d.%02d.%02d %02d:%02d:%02d\n", alm_en, 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); @@ -310,7 +310,7 @@ static int s3c_rtc_setalarm(struct device *dev, struct rtc_wkalrm *alrm) unsigned int alrm_en; clk_enable(rtc_clk); - pr_debug("s3c_rtc_setalarm: %d, %04d.%02d.%02d %02d:%02d:%02d\n", + dev_dbg(dev, "s3c_rtc_setalarm: %d, %04d.%02d.%02d %02d:%02d:%02d\n", alrm->enabled, 1900 + tm->tm_year, tm->tm_mon + 1, tm->tm_mday, tm->tm_hour, tm->tm_min, tm->tm_sec); @@ -333,7 +333,7 @@ static int s3c_rtc_setalarm(struct device *dev, struct rtc_wkalrm *alrm) writeb(bin2bcd(tm->tm_hour), base + S3C2410_ALMHOUR); } - pr_debug("setting S3C2410_RTCALM to %08x\n", alrm_en); + dev_dbg(dev, "setting S3C2410_RTCALM to %08x\n", alrm_en); writeb(alrm_en, base + S3C2410_RTCALM); @@ -459,7 +459,7 @@ static int s3c_rtc_probe(struct platform_device *pdev) int ret; int tmp; - pr_debug("%s: probe=%p\n", __func__, pdev); + dev_dbg(&pdev->dev, "%s: probe=%p\n", __func__, pdev); /* find the IRQs */ @@ -475,7 +475,7 @@ static int s3c_rtc_probe(struct platform_device *pdev) return s3c_rtc_alarmno; } - pr_debug("s3c2410_rtc: tick irq %d, alarm irq %d\n", + dev_dbg(&pdev->dev, "s3c2410_rtc: tick irq %d, alarm irq %d\n", s3c_rtc_tickno, s3c_rtc_alarmno); /* get the memory region */ @@ -506,7 +506,7 @@ static int s3c_rtc_probe(struct platform_device *pdev) s3c_rtc_enable(pdev, 1); - pr_debug("s3c2410_rtc: RTCCON=%02x\n", + dev_dbg(&pdev->dev, "s3c2410_rtc: RTCCON=%02x\n", readw(s3c_rtc_base + S3C2410_RTCCON)); device_init_wakeup(&pdev->dev, 1); -- cgit v1.2.3 From 5e0b2704a1d5c246c8282303bbc952cba17f94fc Mon Sep 17 00:00:00 2001 From: Jonghwa Lee Date: Thu, 21 Feb 2013 16:45:07 -0800 Subject: rtc: max8997: add driver for max8997 rtc Add an rtc driver for Maxim 8997 multifunction chip. Max8997 has rtc module in it. and it can be used for timekeeping clock and system alarm. It provide various operational mode those are BCD/binary, 24/12hour, am/pm. Driver sets binary/24/ for default. Maxim 8997 also supports SMPL(Sudden Momentary Power Loss), WTSR (Watchdog Timeout and Software Reset). Signed-off-by: Jonghwa Lee Cc: Devendra Naga Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/rtc/Kconfig | 10 + drivers/rtc/Makefile | 1 + drivers/rtc/rtc-max8997.c | 553 ++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 564 insertions(+) create mode 100644 drivers/rtc/rtc-max8997.c (limited to 'drivers/rtc') diff --git a/drivers/rtc/Kconfig b/drivers/rtc/Kconfig index 2e340763ba47..d6394c87ad6d 100644 --- a/drivers/rtc/Kconfig +++ b/drivers/rtc/Kconfig @@ -249,6 +249,16 @@ config RTC_DRV_MAX8998 This driver can also be built as a module. If so, the module will be called rtc-max8998. +config RTC_DRV_MAX8997 + tristate "Maxim MAX8997" + depends on MFD_MAX8997 + help + If you say yes here you will get support for the + RTC of Maxim MAX8997 PMIC. + + This driver can also be built as a module. If so, the module + will be called rtc-max8997. + config RTC_DRV_MAX77686 tristate "Maxim MAX77686" depends on MFD_MAX77686 diff --git a/drivers/rtc/Makefile b/drivers/rtc/Makefile index afd284d33714..c694d2644a6c 100644 --- a/drivers/rtc/Makefile +++ b/drivers/rtc/Makefile @@ -71,6 +71,7 @@ obj-$(CONFIG_RTC_DRV_MAX6900) += rtc-max6900.o obj-$(CONFIG_RTC_DRV_MAX8907) += rtc-max8907.o obj-$(CONFIG_RTC_DRV_MAX8925) += rtc-max8925.o obj-$(CONFIG_RTC_DRV_MAX8998) += rtc-max8998.o +obj-$(CONFIG_RTC_DRV_MAX8997) += rtc-max8997.o obj-$(CONFIG_RTC_DRV_MAX6902) += rtc-max6902.o obj-$(CONFIG_RTC_DRV_MAX77686) += rtc-max77686.o obj-$(CONFIG_RTC_DRV_MC13XXX) += rtc-mc13xxx.o diff --git a/drivers/rtc/rtc-max8997.c b/drivers/rtc/rtc-max8997.c new file mode 100644 index 000000000000..a4e7079fb863 --- /dev/null +++ b/drivers/rtc/rtc-max8997.c @@ -0,0 +1,553 @@ +/* + * RTC driver for Maxim MAX8997 + * + * Copyright (C) 2013 Samsung Electronics Co.Ltd + * + * based on rtc-max8998.c + * + * 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 + +/* Module parameter for WTSR function control */ +static int wtsr_en = 1; +module_param(wtsr_en, int, 0444); +MODULE_PARM_DESC(wtsr_en, "Wachdog Timeout & Sofware Reset (default=on)"); +/* Module parameter for SMPL function control */ +static int smpl_en = 1; +module_param(smpl_en, int, 0444); +MODULE_PARM_DESC(smpl_en, "Sudden Momentary Power Loss (default=on)"); + +/* RTC Control Register */ +#define BCD_EN_SHIFT 0 +#define BCD_EN_MASK (1 << BCD_EN_SHIFT) +#define MODEL24_SHIFT 1 +#define MODEL24_MASK (1 << MODEL24_SHIFT) +/* RTC Update Register1 */ +#define RTC_UDR_SHIFT 0 +#define RTC_UDR_MASK (1 << RTC_UDR_SHIFT) +/* WTSR and SMPL Register */ +#define WTSRT_SHIFT 0 +#define SMPLT_SHIFT 2 +#define WTSR_EN_SHIFT 6 +#define SMPL_EN_SHIFT 7 +#define WTSRT_MASK (3 << WTSRT_SHIFT) +#define SMPLT_MASK (3 << SMPLT_SHIFT) +#define WTSR_EN_MASK (1 << WTSR_EN_SHIFT) +#define SMPL_EN_MASK (1 << SMPL_EN_SHIFT) +/* RTC Hour register */ +#define HOUR_PM_SHIFT 6 +#define HOUR_PM_MASK (1 << HOUR_PM_SHIFT) +/* RTC Alarm Enable */ +#define ALARM_ENABLE_SHIFT 7 +#define ALARM_ENABLE_MASK (1 << ALARM_ENABLE_SHIFT) + +enum { + RTC_SEC = 0, + RTC_MIN, + RTC_HOUR, + RTC_WEEKDAY, + RTC_MONTH, + RTC_YEAR, + RTC_DATE, + RTC_NR_TIME +}; + +struct max8997_rtc_info { + struct device *dev; + struct max8997_dev *max8997; + struct i2c_client *rtc; + struct rtc_device *rtc_dev; + struct mutex lock; + int virq; + int rtc_24hr_mode; +}; + +static void max8997_rtc_data_to_tm(u8 *data, struct rtc_time *tm, + int rtc_24hr_mode) +{ + tm->tm_sec = data[RTC_SEC] & 0x7f; + tm->tm_min = data[RTC_MIN] & 0x7f; + if (rtc_24hr_mode) + tm->tm_hour = data[RTC_HOUR] & 0x1f; + else { + tm->tm_hour = data[RTC_HOUR] & 0x0f; + if (data[RTC_HOUR] & HOUR_PM_MASK) + tm->tm_hour += 12; + } + + tm->tm_wday = fls(data[RTC_WEEKDAY] & 0x7f) - 1; + tm->tm_mday = data[RTC_DATE] & 0x1f; + tm->tm_mon = (data[RTC_MONTH] & 0x0f) - 1; + tm->tm_year = (data[RTC_YEAR] & 0x7f) + 100; + tm->tm_yday = 0; + tm->tm_isdst = 0; +} + +static int max8997_rtc_tm_to_data(struct rtc_time *tm, u8 *data) +{ + data[RTC_SEC] = tm->tm_sec; + data[RTC_MIN] = tm->tm_min; + data[RTC_HOUR] = tm->tm_hour; + data[RTC_WEEKDAY] = 1 << tm->tm_wday; + data[RTC_DATE] = tm->tm_mday; + data[RTC_MONTH] = tm->tm_mon + 1; + data[RTC_YEAR] = tm->tm_year > 100 ? (tm->tm_year - 100) : 0 ; + + if (tm->tm_year < 100) { + pr_warn("%s: MAX8997 RTC cannot handle the year %d." + "Assume it's 2000.\n", __func__, 1900 + tm->tm_year); + return -EINVAL; + } + return 0; +} + +static inline int max8997_rtc_set_update_reg(struct max8997_rtc_info *info) +{ + int ret; + + ret = max8997_write_reg(info->rtc, MAX8997_RTC_UPDATE1, + RTC_UDR_MASK); + if (ret < 0) + dev_err(info->dev, "%s: fail to write update reg(%d)\n", + __func__, ret); + else { + /* Minimum 16ms delay required before RTC update. + * Otherwise, we may read and update based on out-of-date + * value */ + msleep(20); + } + + return ret; +} + +static int max8997_rtc_read_time(struct device *dev, struct rtc_time *tm) +{ + struct max8997_rtc_info *info = dev_get_drvdata(dev); + u8 data[RTC_NR_TIME]; + int ret; + + mutex_lock(&info->lock); + ret = max8997_bulk_read(info->rtc, MAX8997_RTC_SEC, RTC_NR_TIME, data); + mutex_unlock(&info->lock); + + if (ret < 0) { + dev_err(info->dev, "%s: fail to read time reg(%d)\n", __func__, + ret); + return ret; + } + + max8997_rtc_data_to_tm(data, tm, info->rtc_24hr_mode); + + return rtc_valid_tm(tm); +} + +static int max8997_rtc_set_time(struct device *dev, struct rtc_time *tm) +{ + struct max8997_rtc_info *info = dev_get_drvdata(dev); + u8 data[RTC_NR_TIME]; + int ret; + + ret = max8997_rtc_tm_to_data(tm, data); + if (ret < 0) + return ret; + + mutex_lock(&info->lock); + + ret = max8997_bulk_write(info->rtc, MAX8997_RTC_SEC, RTC_NR_TIME, data); + if (ret < 0) { + dev_err(info->dev, "%s: fail to write time reg(%d)\n", __func__, + ret); + goto out; + } + + ret = max8997_rtc_set_update_reg(info); +out: + mutex_unlock(&info->lock); + return ret; +} + +static int max8997_rtc_read_alarm(struct device *dev, struct rtc_wkalrm *alrm) +{ + struct max8997_rtc_info *info = dev_get_drvdata(dev); + u8 data[RTC_NR_TIME]; + u8 val; + int i, ret; + + mutex_lock(&info->lock); + + ret = max8997_bulk_read(info->rtc, MAX8997_RTC_ALARM1_SEC, RTC_NR_TIME, + data); + if (ret < 0) { + dev_err(info->dev, "%s:%d fail to read alarm reg(%d)\n", + __func__, __LINE__, ret); + goto out; + } + + max8997_rtc_data_to_tm(data, &alrm->time, info->rtc_24hr_mode); + + alrm->enabled = 0; + for (i = 0; i < RTC_NR_TIME; i++) { + if (data[i] & ALARM_ENABLE_MASK) { + alrm->enabled = 1; + break; + } + } + + alrm->pending = 0; + ret = max8997_read_reg(info->max8997->i2c, MAX8997_REG_STATUS1, &val); + if (ret < 0) { + dev_err(info->dev, "%s:%d fail to read status1 reg(%d)\n", + __func__, __LINE__, ret); + goto out; + } + + if (val & (1 << 4)) /* RTCA1 */ + alrm->pending = 1; + +out: + mutex_unlock(&info->lock); + return 0; +} + +static int max8997_rtc_stop_alarm(struct max8997_rtc_info *info) +{ + u8 data[RTC_NR_TIME]; + int ret, i; + + if (!mutex_is_locked(&info->lock)) + dev_warn(info->dev, "%s: should have mutex locked\n", __func__); + + ret = max8997_bulk_read(info->rtc, MAX8997_RTC_ALARM1_SEC, RTC_NR_TIME, + data); + if (ret < 0) { + dev_err(info->dev, "%s: fail to read alarm reg(%d)\n", + __func__, ret); + goto out; + } + + for (i = 0; i < RTC_NR_TIME; i++) + data[i] &= ~ALARM_ENABLE_MASK; + + ret = max8997_bulk_write(info->rtc, MAX8997_RTC_ALARM1_SEC, RTC_NR_TIME, + data); + if (ret < 0) { + dev_err(info->dev, "%s: fail to write alarm reg(%d)\n", + __func__, ret); + goto out; + } + + ret = max8997_rtc_set_update_reg(info); +out: + return ret; +} + +static int max8997_rtc_start_alarm(struct max8997_rtc_info *info) +{ + u8 data[RTC_NR_TIME]; + int ret; + + if (!mutex_is_locked(&info->lock)) + dev_warn(info->dev, "%s: should have mutex locked\n", __func__); + + ret = max8997_bulk_read(info->rtc, MAX8997_RTC_ALARM1_SEC, RTC_NR_TIME, + data); + if (ret < 0) { + dev_err(info->dev, "%s: fail to read alarm reg(%d)\n", + __func__, ret); + goto out; + } + + data[RTC_SEC] |= (1 << ALARM_ENABLE_SHIFT); + data[RTC_MIN] |= (1 << ALARM_ENABLE_SHIFT); + data[RTC_HOUR] |= (1 << ALARM_ENABLE_SHIFT); + data[RTC_WEEKDAY] &= ~ALARM_ENABLE_MASK; + if (data[RTC_MONTH] & 0xf) + data[RTC_MONTH] |= (1 << ALARM_ENABLE_SHIFT); + if (data[RTC_YEAR] & 0x7f) + data[RTC_YEAR] |= (1 << ALARM_ENABLE_SHIFT); + if (data[RTC_DATE] & 0x1f) + data[RTC_DATE] |= (1 << ALARM_ENABLE_SHIFT); + + ret = max8997_bulk_write(info->rtc, MAX8997_RTC_ALARM1_SEC, RTC_NR_TIME, + data); + if (ret < 0) { + dev_err(info->dev, "%s: fail to write alarm reg(%d)\n", + __func__, ret); + goto out; + } + + ret = max8997_rtc_set_update_reg(info); +out: + return ret; +} +static int max8997_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alrm) +{ + struct max8997_rtc_info *info = dev_get_drvdata(dev); + u8 data[RTC_NR_TIME]; + int ret; + + ret = max8997_rtc_tm_to_data(&alrm->time, data); + if (ret < 0) + return ret; + + dev_info(info->dev, "%s: %d-%02d-%02d %02d:%02d:%02d\n", __func__, + data[RTC_YEAR] + 2000, data[RTC_MONTH], data[RTC_DATE], + data[RTC_HOUR], data[RTC_MIN], data[RTC_SEC]); + + mutex_lock(&info->lock); + + ret = max8997_rtc_stop_alarm(info); + if (ret < 0) + goto out; + + ret = max8997_bulk_write(info->rtc, MAX8997_RTC_ALARM1_SEC, RTC_NR_TIME, + data); + if (ret < 0) { + dev_err(info->dev, "%s: fail to write alarm reg(%d)\n", + __func__, ret); + goto out; + } + + ret = max8997_rtc_set_update_reg(info); + if (ret < 0) + goto out; + + if (alrm->enabled) + ret = max8997_rtc_start_alarm(info); +out: + mutex_unlock(&info->lock); + return ret; +} + +static int max8997_rtc_alarm_irq_enable(struct device *dev, + unsigned int enabled) +{ + struct max8997_rtc_info *info = dev_get_drvdata(dev); + int ret; + + mutex_lock(&info->lock); + if (enabled) + ret = max8997_rtc_start_alarm(info); + else + ret = max8997_rtc_stop_alarm(info); + mutex_unlock(&info->lock); + + return ret; +} + +static irqreturn_t max8997_rtc_alarm_irq(int irq, void *data) +{ + struct max8997_rtc_info *info = data; + + dev_info(info->dev, "%s:irq(%d)\n", __func__, irq); + + rtc_update_irq(info->rtc_dev, 1, RTC_IRQF | RTC_AF); + + return IRQ_HANDLED; +} + +static const struct rtc_class_ops max8997_rtc_ops = { + .read_time = max8997_rtc_read_time, + .set_time = max8997_rtc_set_time, + .read_alarm = max8997_rtc_read_alarm, + .set_alarm = max8997_rtc_set_alarm, + .alarm_irq_enable = max8997_rtc_alarm_irq_enable, +}; + +static void max8997_rtc_enable_wtsr(struct max8997_rtc_info *info, bool enable) +{ + int ret; + u8 val, mask; + + if (!wtsr_en) + return; + + if (enable) + val = (1 << WTSR_EN_SHIFT) | (3 << WTSRT_SHIFT); + else + val = 0; + + mask = WTSR_EN_MASK | WTSRT_MASK; + + dev_info(info->dev, "%s: %s WTSR\n", __func__, + enable ? "enable" : "disable"); + + ret = max8997_update_reg(info->rtc, MAX8997_RTC_WTSR_SMPL, val, mask); + if (ret < 0) { + dev_err(info->dev, "%s: fail to update WTSR reg(%d)\n", + __func__, ret); + return; + } + + max8997_rtc_set_update_reg(info); +} + +static void max8997_rtc_enable_smpl(struct max8997_rtc_info *info, bool enable) +{ + int ret; + u8 val, mask; + + if (!smpl_en) + return; + + if (enable) + val = (1 << SMPL_EN_SHIFT) | (0 << SMPLT_SHIFT); + else + val = 0; + + mask = SMPL_EN_MASK | SMPLT_MASK; + + dev_info(info->dev, "%s: %s SMPL\n", __func__, + enable ? "enable" : "disable"); + + ret = max8997_update_reg(info->rtc, MAX8997_RTC_WTSR_SMPL, val, mask); + if (ret < 0) { + dev_err(info->dev, "%s: fail to update SMPL reg(%d)\n", + __func__, ret); + return; + } + + max8997_rtc_set_update_reg(info); + + val = 0; + max8997_read_reg(info->rtc, MAX8997_RTC_WTSR_SMPL, &val); + pr_info("%s: WTSR_SMPL(0x%02x)\n", __func__, val); +} + +static int max8997_rtc_init_reg(struct max8997_rtc_info *info) +{ + u8 data[2]; + int ret; + + /* Set RTC control register : Binary mode, 24hour mdoe */ + data[0] = (1 << BCD_EN_SHIFT) | (1 << MODEL24_SHIFT); + data[1] = (0 << BCD_EN_SHIFT) | (1 << MODEL24_SHIFT); + + info->rtc_24hr_mode = 1; + + ret = max8997_bulk_write(info->rtc, MAX8997_RTC_CTRLMASK, 2, data); + if (ret < 0) { + dev_err(info->dev, "%s: fail to write controlm reg(%d)\n", + __func__, ret); + return ret; + } + + ret = max8997_rtc_set_update_reg(info); + return ret; +} + +static int max8997_rtc_probe(struct platform_device *pdev) +{ + struct max8997_dev *max8997 = dev_get_drvdata(pdev->dev.parent); + struct max8997_rtc_info *info; + int ret, virq; + + info = devm_kzalloc(&pdev->dev, sizeof(struct max8997_rtc_info), + GFP_KERNEL); + if (!info) + return -ENOMEM; + + mutex_init(&info->lock); + info->dev = &pdev->dev; + info->max8997 = max8997; + info->rtc = max8997->rtc; + + platform_set_drvdata(pdev, info); + + ret = max8997_rtc_init_reg(info); + + if (ret < 0) { + dev_err(&pdev->dev, "Failed to initialize RTC reg:%d\n", ret); + return ret; + } + + max8997_rtc_enable_wtsr(info, true); + max8997_rtc_enable_smpl(info, true); + + device_init_wakeup(&pdev->dev, 1); + + info->rtc_dev = rtc_device_register("max8997-rtc", &pdev->dev, + &max8997_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); + return ret; + } + + virq = irq_create_mapping(max8997->irq_domain, MAX8997_PMICIRQ_RTCA1); + if (!virq) { + dev_err(&pdev->dev, "Failed to create mapping alarm IRQ\n"); + goto err_out; + } + info->virq = virq; + + ret = request_threaded_irq(virq, NULL, max8997_rtc_alarm_irq, 0, + "rtc-alarm0", info); + if (ret < 0) { + dev_err(&pdev->dev, "Failed to request alarm IRQ: %d: %d\n", + info->virq, ret); + goto err_out; + } + + return ret; + +err_out: + rtc_device_unregister(info->rtc_dev); + return ret; +} + +static int max8997_rtc_remove(struct platform_device *pdev) +{ + struct max8997_rtc_info *info = platform_get_drvdata(pdev); + + if (info) { + free_irq(info->virq, info); + rtc_device_unregister(info->rtc_dev); + } + + return 0; +} + +static void max8997_rtc_shutdown(struct platform_device *pdev) +{ + struct max8997_rtc_info *info = platform_get_drvdata(pdev); + + max8997_rtc_enable_wtsr(info, false); + max8997_rtc_enable_smpl(info, false); +} + +static const struct platform_device_id rtc_id[] = { + { "max8997-rtc", 0 }, + {}, +}; + +static struct platform_driver max8997_rtc_driver = { + .driver = { + .name = "max8997-rtc", + .owner = THIS_MODULE, + }, + .probe = max8997_rtc_probe, + .remove = max8997_rtc_remove, + .shutdown = max8997_rtc_shutdown, + .id_table = rtc_id, +}; + +module_platform_driver(max8997_rtc_driver); + +MODULE_DESCRIPTION("Maxim MAX8997 RTC driver"); +MODULE_AUTHOR(""); +MODULE_LICENSE("GPL"); -- cgit v1.2.3 From 0cc0c38e91392d2da769c9831739df43787d99e3 Mon Sep 17 00:00:00 2001 From: Chao Xie Date: Thu, 21 Feb 2013 16:45:17 -0800 Subject: drivers/rtc/rtc-sa1100.c: move clock enable/disable to probe/remove The original sa1100_rtc_open/sa1100_rtc_release will be called when the /dev/rtc0 is opened or closed. In fact, these two functions will enable/disable the clock. Disabling clock will make rtc not work. So only enable/disable clock when probe/remove the device. Signed-off-by: Chao Xie Acked-by: Haojian Zhuang Cc: Leo Song Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/rtc/rtc-sa1100.c | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) (limited to 'drivers/rtc') diff --git a/drivers/rtc/rtc-sa1100.c b/drivers/rtc/rtc-sa1100.c index df9180e80e3a..5ec5036df0bc 100644 --- a/drivers/rtc/rtc-sa1100.c +++ b/drivers/rtc/rtc-sa1100.c @@ -108,9 +108,6 @@ static int sa1100_rtc_open(struct device *dev) struct rtc_device *rtc = info->rtc; int ret; - ret = clk_prepare_enable(info->clk); - if (ret) - goto fail_clk; ret = request_irq(info->irq_1hz, sa1100_rtc_interrupt, 0, "rtc 1Hz", dev); if (ret) { dev_err(dev, "IRQ %d already in use.\n", info->irq_1hz); @@ -130,7 +127,6 @@ static int sa1100_rtc_open(struct device *dev) free_irq(info->irq_1hz, dev); fail_ui: clk_disable_unprepare(info->clk); - fail_clk: return ret; } @@ -144,7 +140,6 @@ static void sa1100_rtc_release(struct device *dev) free_irq(info->irq_alarm, dev); free_irq(info->irq_1hz, dev); - clk_disable_unprepare(info->clk); } static int sa1100_rtc_alarm_irq_enable(struct device *dev, unsigned int enabled) @@ -253,6 +248,9 @@ static int sa1100_rtc_probe(struct platform_device *pdev) spin_lock_init(&info->lock); platform_set_drvdata(pdev, info); + ret = clk_prepare_enable(info->clk); + if (ret) + goto err_enable_clk; /* * According to the manual we should be able to let RTTR be zero * and then a default diviser for a 32.768KHz clock is used. @@ -305,6 +303,8 @@ static int sa1100_rtc_probe(struct platform_device *pdev) return 0; err_dev: + clk_disable_unprepare(info->clk); +err_enable_clk: platform_set_drvdata(pdev, NULL); clk_put(info->clk); err_clk: @@ -318,6 +318,7 @@ static int sa1100_rtc_remove(struct platform_device *pdev) if (info) { rtc_device_unregister(info->rtc); + clk_disable_unprepare(info->clk); clk_put(info->clk); platform_set_drvdata(pdev, NULL); kfree(info); -- cgit v1.2.3 From c100a5e0255777c783646791e98434f300a94c4c Mon Sep 17 00:00:00 2001 From: Jingoo Han Date: Thu, 21 Feb 2013 16:45:23 -0800 Subject: rtc: use dev_warn()/dev_dbg()/pr_err() instead of printk() Fix the checkpatch warning as below: WARNING: Prefer netdev_err(netdev, ... then dev_err(dev, ... then pr_err(... to printk(KERN_ERR ... Signed-off-by: Jingoo Han Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/rtc/class.c | 4 +++- drivers/rtc/rtc-dev.c | 11 ++++++----- 2 files changed, 9 insertions(+), 6 deletions(-) (limited to 'drivers/rtc') diff --git a/drivers/rtc/class.c b/drivers/rtc/class.c index 26388f182594..9b742d3ffb94 100644 --- a/drivers/rtc/class.c +++ b/drivers/rtc/class.c @@ -11,6 +11,8 @@ * published by the Free Software Foundation. */ +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt + #include #include #include @@ -261,7 +263,7 @@ static int __init rtc_init(void) { rtc_class = class_create(THIS_MODULE, "rtc"); if (IS_ERR(rtc_class)) { - printk(KERN_ERR "%s: couldn't create class\n", __FILE__); + pr_err("couldn't create class\n"); return PTR_ERR(rtc_class); } rtc_class->suspend = rtc_suspend; diff --git a/drivers/rtc/rtc-dev.c b/drivers/rtc/rtc-dev.c index 9a86b4bd8699..d04939369251 100644 --- a/drivers/rtc/rtc-dev.c +++ b/drivers/rtc/rtc-dev.c @@ -11,6 +11,8 @@ * published by the Free Software Foundation. */ +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt + #include #include #include @@ -462,7 +464,7 @@ void rtc_dev_prepare(struct rtc_device *rtc) return; if (rtc->id >= RTC_DEV_MAX) { - pr_debug("%s: too many RTC devices\n", rtc->name); + dev_dbg(&rtc->dev, "%s: too many RTC devices\n", rtc->name); return; } @@ -480,10 +482,10 @@ void rtc_dev_prepare(struct rtc_device *rtc) void rtc_dev_add_device(struct rtc_device *rtc) { if (cdev_add(&rtc->char_dev, rtc->dev.devt, 1)) - printk(KERN_WARNING "%s: failed to add char device %d:%d\n", + dev_warn(&rtc->dev, "%s: failed to add char device %d:%d\n", rtc->name, MAJOR(rtc_devt), rtc->id); else - pr_debug("%s: dev (%d:%d)\n", rtc->name, + dev_dbg(&rtc->dev, "%s: dev (%d:%d)\n", rtc->name, MAJOR(rtc_devt), rtc->id); } @@ -499,8 +501,7 @@ void __init rtc_dev_init(void) err = alloc_chrdev_region(&rtc_devt, 0, RTC_DEV_MAX, "rtc"); if (err < 0) - printk(KERN_ERR "%s: failed to allocate char dev region\n", - __FILE__); + pr_err("failed to allocate char dev region\n"); } void __exit rtc_dev_exit(void) -- cgit v1.2.3 From 3cebeb53d921c2079be0f1bf20f8cae68c20ecc0 Mon Sep 17 00:00:00 2001 From: Jingoo Han Date: Thu, 21 Feb 2013 16:45:24 -0800 Subject: rtc: max77686: use dev_info() instead of printk() Fix the checkpatch warning as below: WARNING: Prefer netdev_err(netdev, ... then dev_err(dev, ... then pr_err(... to printk(KERN_ERR ... Signed-off-by: Jingoo Han Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/rtc/rtc-max77686.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers/rtc') diff --git a/drivers/rtc/rtc-max77686.c b/drivers/rtc/rtc-max77686.c index 8ab56b00e693..6b1337f9baf4 100644 --- a/drivers/rtc/rtc-max77686.c +++ b/drivers/rtc/rtc-max77686.c @@ -503,7 +503,7 @@ static int max77686_rtc_probe(struct platform_device *pdev) struct max77686_rtc_info *info; int ret, virq; - printk(KERN_INFO "%s\n", __func__); + dev_info(&pdev->dev, "%s\n", __func__); info = kzalloc(sizeof(struct max77686_rtc_info), GFP_KERNEL); if (!info) @@ -542,7 +542,7 @@ static int max77686_rtc_probe(struct platform_device *pdev) &max77686_rtc_ops, THIS_MODULE); if (IS_ERR(info->rtc_dev)) { - printk(KERN_INFO "%s: fail\n", __func__); + dev_info(&pdev->dev, "%s: fail\n", __func__); ret = PTR_ERR(info->rtc_dev); dev_err(&pdev->dev, "Failed to register RTC device: %d\n", ret); -- cgit v1.2.3 From 34650f9ea128a124d325b67b38f59c82635741eb Mon Sep 17 00:00:00 2001 From: Jingoo Han Date: Thu, 21 Feb 2013 16:45:25 -0800 Subject: rtc: rtc-efi: use dev_err()/dev_warn()/pr_err() instead of printk() Fix the checkpatch warnings as below: WARNING: Prefer netdev_err(netdev, ... then dev_err(dev, ... then pr_err(... to printk(KERN_ERR ... WARNING: please, no space before tabs Signed-off-by: Jingoo Han Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/rtc/rtc-efi.c | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) (limited to 'drivers/rtc') diff --git a/drivers/rtc/rtc-efi.c b/drivers/rtc/rtc-efi.c index c9f890b088da..1a0c37c9152b 100644 --- a/drivers/rtc/rtc-efi.c +++ b/drivers/rtc/rtc-efi.c @@ -13,6 +13,8 @@ * */ +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt + #include #include #include @@ -47,7 +49,7 @@ compute_wday(efi_time_t *eft) int ndays = 0; if (eft->year < 1998) { - printk(KERN_ERR "efirtc: EFI year < 1998, invalid date\n"); + pr_err("EFI year < 1998, invalid date\n"); return -1; } @@ -70,7 +72,7 @@ convert_to_efi_time(struct rtc_time *wtime, efi_time_t *eft) eft->day = wtime->tm_mday; eft->hour = wtime->tm_hour; eft->minute = wtime->tm_min; - eft->second = wtime->tm_sec; + eft->second = wtime->tm_sec; eft->nanosecond = 0; eft->daylight = wtime->tm_isdst ? EFI_ISDST : 0; eft->timezone = EFI_UNSPECIFIED_TIMEZONE; @@ -142,7 +144,7 @@ static int efi_set_alarm(struct device *dev, struct rtc_wkalrm *wkalrm) */ status = efi.set_wakeup_time((efi_bool_t)wkalrm->enabled, &eft); - printk(KERN_WARNING "write status is %d\n", (int)status); + dev_warn(dev, "write status is %d\n", (int)status); return status == EFI_SUCCESS ? 0 : -EINVAL; } @@ -157,7 +159,7 @@ static int efi_read_time(struct device *dev, struct rtc_time *tm) if (status != EFI_SUCCESS) { /* should never happen */ - printk(KERN_ERR "efitime: can't read time\n"); + dev_err(dev, "can't read time\n"); return -EINVAL; } -- cgit v1.2.3 From 0fae82378ad55a7dfd03f5f6fb092798d8019bc3 Mon Sep 17 00:00:00 2001 From: Jingoo Han Date: Thu, 21 Feb 2013 16:45:26 -0800 Subject: rtc: rtc-ds2404: use dev_err() instead of printk() Fix the checkpatch warning as below: WARNING: Prefer netdev_err(netdev, ... then dev_err(dev, ... then pr_err(... to printk(KERN_ERR ... Signed-off-by: Jingoo Han Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/rtc/rtc-ds2404.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers/rtc') diff --git a/drivers/rtc/rtc-ds2404.c b/drivers/rtc/rtc-ds2404.c index 4539e37c2238..b04fc4272fb3 100644 --- a/drivers/rtc/rtc-ds2404.c +++ b/drivers/rtc/rtc-ds2404.c @@ -70,7 +70,7 @@ static int ds2404_gpio_map(struct ds2404 *chip, struct platform_device *pdev, for (i = 0; i < ARRAY_SIZE(ds2404_gpio); i++) { err = gpio_request(ds2404_gpio[i].gpio, ds2404_gpio[i].name); if (err) { - printk(KERN_ERR "error mapping gpio %s: %d\n", + dev_err(&pdev->dev, "error mapping gpio %s: %d\n", ds2404_gpio[i].name, err); goto err_request; } @@ -177,7 +177,7 @@ static void ds2404_write_memory(struct device *dev, u16 offset, for (i = 0; i < length; i++) { if (out[i] != ds2404_read_byte(dev)) { - printk(KERN_ERR "read invalid data\n"); + dev_err(dev, "read invalid data\n"); return; } } -- cgit v1.2.3 From 0c6516ea46191e0385a9f8489c672ebfbc10d490 Mon Sep 17 00:00:00 2001 From: Jingoo Han Date: Thu, 21 Feb 2013 16:45:27 -0800 Subject: rtc: rtc-rs5c372: use dev_dbg()/dev_warn() instead of printk()/pr_debug() Fix the checkpatch warning as below: WARNING: Prefer netdev_err(netdev, ... then dev_err(dev, ... then pr_err(... to printk(KERN_ERR ... Signed-off-by: Jingoo Han Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/rtc/rtc-rs5c372.c | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) (limited to 'drivers/rtc') diff --git a/drivers/rtc/rtc-rs5c372.c b/drivers/rtc/rtc-rs5c372.c index 76f565ae384d..581739f40097 100644 --- a/drivers/rtc/rtc-rs5c372.c +++ b/drivers/rtc/rtc-rs5c372.c @@ -311,8 +311,7 @@ static int rs5c_rtc_alarm_irq_enable(struct device *dev, unsigned int enabled) buf &= ~RS5C_CTRL1_AALE; if (i2c_smbus_write_byte_data(client, addr, buf) < 0) { - printk(KERN_WARNING "%s: can't update alarm\n", - rs5c->rtc->name); + dev_warn(dev, "can't update alarm\n"); status = -EIO; } else rs5c->regs[RS5C_REG_CTRL1] = buf; @@ -381,7 +380,7 @@ static int rs5c_set_alarm(struct device *dev, struct rtc_wkalrm *t) addr = RS5C_ADDR(RS5C_REG_CTRL1); buf[0] = rs5c->regs[RS5C_REG_CTRL1] & ~RS5C_CTRL1_AALE; if (i2c_smbus_write_byte_data(client, addr, buf[0]) < 0) { - pr_debug("%s: can't disable alarm\n", rs5c->rtc->name); + dev_dbg(dev, "can't disable alarm\n"); return -EIO; } rs5c->regs[RS5C_REG_CTRL1] = buf[0]; @@ -395,7 +394,7 @@ static int rs5c_set_alarm(struct device *dev, struct rtc_wkalrm *t) for (i = 0; i < sizeof(buf); i++) { addr = RS5C_ADDR(RS5C_REG_ALARM_A_MIN + i); if (i2c_smbus_write_byte_data(client, addr, buf[i]) < 0) { - pr_debug("%s: can't set alarm time\n", rs5c->rtc->name); + dev_dbg(dev, "can't set alarm time\n"); return -EIO; } } @@ -405,8 +404,7 @@ static int rs5c_set_alarm(struct device *dev, struct rtc_wkalrm *t) addr = RS5C_ADDR(RS5C_REG_CTRL1); buf[0] = rs5c->regs[RS5C_REG_CTRL1] | RS5C_CTRL1_AALE; if (i2c_smbus_write_byte_data(client, addr, buf[0]) < 0) - printk(KERN_WARNING "%s: can't enable alarm\n", - rs5c->rtc->name); + dev_warn(dev, "can't enable alarm\n"); rs5c->regs[RS5C_REG_CTRL1] = buf[0]; } -- cgit v1.2.3 From 6588208cb2be4ab05e9dc0d1f5879eacf3dbcd1c Mon Sep 17 00:00:00 2001 From: Jingoo Han Date: Thu, 21 Feb 2013 16:45:28 -0800 Subject: rtc: rtc-at91rm9200: use dev_dbg()/dev_err() instead of printk()/pr_debug() Fix the checkpatch warning as below: WARNING: Prefer netdev_err(netdev, ... then dev_err(dev, ... then pr_err(... to printk(KERN_ERR ... Signed-off-by: Jingoo Han Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/rtc/rtc-at91rm9200.c | 17 ++++++++--------- 1 file changed, 8 insertions(+), 9 deletions(-) (limited to 'drivers/rtc') diff --git a/drivers/rtc/rtc-at91rm9200.c b/drivers/rtc/rtc-at91rm9200.c index b6469e2cae89..434ebc3a99dc 100644 --- a/drivers/rtc/rtc-at91rm9200.c +++ b/drivers/rtc/rtc-at91rm9200.c @@ -86,7 +86,7 @@ static int at91_rtc_readtime(struct device *dev, struct rtc_time *tm) tm->tm_yday = rtc_year_days(tm->tm_mday, tm->tm_mon, tm->tm_year); tm->tm_year = tm->tm_year - 1900; - pr_debug("%s(): %4d-%02d-%02d %02d:%02d:%02d\n", __func__, + dev_dbg(dev, "%s(): %4d-%02d-%02d %02d:%02d:%02d\n", __func__, 1900 + tm->tm_year, tm->tm_mon, tm->tm_mday, tm->tm_hour, tm->tm_min, tm->tm_sec); @@ -100,7 +100,7 @@ static int at91_rtc_settime(struct device *dev, struct rtc_time *tm) { unsigned long cr; - pr_debug("%s(): %4d-%02d-%02d %02d:%02d:%02d\n", __func__, + dev_dbg(dev, "%s(): %4d-%02d-%02d %02d:%02d:%02d\n", __func__, 1900 + tm->tm_year, tm->tm_mon, tm->tm_mday, tm->tm_hour, tm->tm_min, tm->tm_sec); @@ -145,7 +145,7 @@ static int at91_rtc_readalarm(struct device *dev, struct rtc_wkalrm *alrm) alrm->enabled = (at91_rtc_read(AT91_RTC_IMR) & AT91_RTC_ALARM) ? 1 : 0; - pr_debug("%s(): %4d-%02d-%02d %02d:%02d:%02d\n", __func__, + dev_dbg(dev, "%s(): %4d-%02d-%02d %02d:%02d:%02d\n", __func__, 1900 + tm->tm_year, tm->tm_mon, tm->tm_mday, tm->tm_hour, tm->tm_min, tm->tm_sec); @@ -183,7 +183,7 @@ static int at91_rtc_setalarm(struct device *dev, struct rtc_wkalrm *alrm) at91_rtc_write(AT91_RTC_IER, AT91_RTC_ALARM); } - pr_debug("%s(): %4d-%02d-%02d %02d:%02d:%02d\n", __func__, + dev_dbg(dev, "%s(): %4d-%02d-%02d %02d:%02d:%02d\n", __func__, at91_alarm_year, tm.tm_mon, tm.tm_mday, tm.tm_hour, tm.tm_min, tm.tm_sec); @@ -192,7 +192,7 @@ static int at91_rtc_setalarm(struct device *dev, struct rtc_wkalrm *alrm) static int at91_rtc_alarm_irq_enable(struct device *dev, unsigned int enabled) { - pr_debug("%s(): cmd=%08x\n", __func__, enabled); + dev_dbg(dev, "%s(): cmd=%08x\n", __func__, enabled); if (enabled) { at91_rtc_write(AT91_RTC_SCCR, AT91_RTC_ALARM); @@ -240,7 +240,7 @@ static irqreturn_t at91_rtc_interrupt(int irq, void *dev_id) rtc_update_irq(rtc, 1, events); - pr_debug("%s(): num=%ld, events=0x%02lx\n", __func__, + dev_dbg(&pdev->dev, "%s(): num=%ld, events=0x%02lx\n", __func__, events >> 8, events & 0x000000FF); return IRQ_HANDLED; @@ -296,8 +296,7 @@ static int __init at91_rtc_probe(struct platform_device *pdev) IRQF_SHARED, "at91_rtc", pdev); if (ret) { - printk(KERN_ERR "at91_rtc: IRQ %d already in use.\n", - irq); + dev_err(&pdev->dev, "IRQ %d already in use.\n", irq); return ret; } @@ -315,7 +314,7 @@ static int __init at91_rtc_probe(struct platform_device *pdev) } platform_set_drvdata(pdev, rtc); - printk(KERN_INFO "AT91 Real Time Clock driver.\n"); + dev_info(&pdev->dev, "AT91 Real Time Clock driver.\n"); return 0; } -- cgit v1.2.3 From aa161902ecae9ef55f8ec2190d2be7877402374d Mon Sep 17 00:00:00 2001 From: Jingoo Han Date: Thu, 21 Feb 2013 16:45:29 -0800 Subject: rtc: rtc-rs5c313: use pr_err() instead of printk() Fix the checkpatch warning as below: WARNING: Prefer netdev_err(netdev, ... then dev_err(dev, ... then pr_err(... to printk(KERN_ERR ... Signed-off-by: Jingoo Han Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/rtc/rtc-rs5c313.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) (limited to 'drivers/rtc') diff --git a/drivers/rtc/rtc-rs5c313.c b/drivers/rtc/rtc-rs5c313.c index d1aee793ecc8..d98ea5b759c8 100644 --- a/drivers/rtc/rtc-rs5c313.c +++ b/drivers/rtc/rtc-rs5c313.c @@ -39,6 +39,8 @@ * 1.13 Nobuhiro Iwamatsu: Updata driver. */ +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt + #include #include #include @@ -352,8 +354,7 @@ static void rs5c313_check_xstp_bit(void) tm.tm_year = 2000 - 1900; rs5c313_rtc_set_time(NULL, &tm); - printk(KERN_ERR "RICHO RS5C313: invalid value, resetting to " - "1 Jan 2000\n"); + pr_err("invalid value, resetting to 1 Jan 2000\n"); } RS5C313_CEDISABLE; ndelay(700); /* CE:L */ -- cgit v1.2.3 From d75dcd3349a4e0916cec37e7b838c83c95b9fa95 Mon Sep 17 00:00:00 2001 From: Jingoo Han Date: Thu, 21 Feb 2013 16:45:30 -0800 Subject: rtc: rtc-vr41xx: use dev_info() instead of printk() Fix the checkpatch warning as below: WARNING: Prefer netdev_err(netdev, ... then dev_err(dev, ... then pr_err(... to printk(KERN_ERR ... Signed-off-by: Jingoo Han Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/rtc/rtc-vr41xx.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/rtc') diff --git a/drivers/rtc/rtc-vr41xx.c b/drivers/rtc/rtc-vr41xx.c index 6c3774cf5a24..f91be04b9050 100644 --- a/drivers/rtc/rtc-vr41xx.c +++ b/drivers/rtc/rtc-vr41xx.c @@ -352,7 +352,7 @@ static int rtc_probe(struct platform_device *pdev) disable_irq(aie_irq); disable_irq(pie_irq); - printk(KERN_INFO "rtc: Real Time Clock of NEC VR4100 series\n"); + dev_info(&pdev->dev, "Real Time Clock of NEC VR4100 series\n"); return 0; -- cgit v1.2.3 From d959f7319adf58e4bfcada15cc088941dee79f36 Mon Sep 17 00:00:00 2001 From: Jingoo Han Date: Thu, 21 Feb 2013 16:45:32 -0800 Subject: rtc: rtc-sun4v: use pr_warn() instead of printk() Fix the checkpatch warning as below: WARNING: Prefer netdev_err(netdev, ... then dev_err(dev, ... then pr_err(... to printk(KERN_ERR ... Signed-off-by: Jingoo Han Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/rtc/rtc-sun4v.c | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) (limited to 'drivers/rtc') diff --git a/drivers/rtc/rtc-sun4v.c b/drivers/rtc/rtc-sun4v.c index 5b2261052a65..59b5c2dcb58c 100644 --- a/drivers/rtc/rtc-sun4v.c +++ b/drivers/rtc/rtc-sun4v.c @@ -3,6 +3,8 @@ * Copyright (C) 2008 David S. Miller */ +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt + #include #include #include @@ -26,10 +28,10 @@ retry: udelay(100); goto retry; } - printk(KERN_WARNING "SUN4V: tod_get() timed out.\n"); + pr_warn("tod_get() timed out.\n"); return 0; } - printk(KERN_WARNING "SUN4V: tod_get() not supported.\n"); + pr_warn("tod_get() not supported.\n"); return 0; } @@ -53,10 +55,10 @@ retry: udelay(100); goto retry; } - printk(KERN_WARNING "SUN4V: tod_set() timed out.\n"); + pr_warn("tod_set() timed out.\n"); return -EAGAIN; } - printk(KERN_WARNING "SUN4V: tod_set() not supported.\n"); + pr_warn("tod_set() not supported.\n"); return -EOPNOTSUPP; } -- cgit v1.2.3 From 79d134058f15e25c6b6724704a8f046c2ff6c1f9 Mon Sep 17 00:00:00 2001 From: Jingoo Han Date: Thu, 21 Feb 2013 16:45:33 -0800 Subject: rtc: rtc-pcf8583: use dev_warn() instead of printk() Fix the checkpatch warning as below: WARNING: Prefer netdev_err(netdev, ... then dev_err(dev, ... then pr_err(... to printk(KERN_ERR ... Signed-off-by: Jingoo Han Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/rtc/rtc-pcf8583.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers/rtc') diff --git a/drivers/rtc/rtc-pcf8583.c b/drivers/rtc/rtc-pcf8583.c index 3415b8f18555..5f97c61247d5 100644 --- a/drivers/rtc/rtc-pcf8583.c +++ b/drivers/rtc/rtc-pcf8583.c @@ -185,8 +185,8 @@ static int pcf8583_rtc_read_time(struct device *dev, struct rtc_time *tm) if (ctrl & (CTRL_STOP | CTRL_HOLD)) { unsigned char new_ctrl = ctrl & ~(CTRL_STOP | CTRL_HOLD); - printk(KERN_WARNING "RTC: resetting control %02x -> %02x\n", - ctrl, new_ctrl); + dev_warn(dev, "resetting control %02x -> %02x\n", + ctrl, new_ctrl); if ((err = pcf8583_set_ctrl(client, &new_ctrl)) < 0) return err; -- cgit v1.2.3 From ee4433573b02f817c3ac62ed8f07027938dc9201 Mon Sep 17 00:00:00 2001 From: Jingoo Han Date: Thu, 21 Feb 2013 16:45:34 -0800 Subject: rtc: rtc-cmos: use dev_warn()/dev_dbg() instead of printk()/pr_debug() Fix the checkpatch warning as below: WARNING: Prefer netdev_err(netdev, ... then dev_err(dev, ... then pr_err(... to printk(KERN_ERR ... Signed-off-by: Jingoo Han Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/rtc/rtc-cmos.c | 12 ++++-------- 1 file changed, 4 insertions(+), 8 deletions(-) (limited to 'drivers/rtc') diff --git a/drivers/rtc/rtc-cmos.c b/drivers/rtc/rtc-cmos.c index 9deb9e47a67c..af97c94e8a3a 100644 --- a/drivers/rtc/rtc-cmos.c +++ b/drivers/rtc/rtc-cmos.c @@ -706,7 +706,7 @@ cmos_do_probe(struct device *dev, struct resource *ports, int rtc_irq) rtc_cmos_int_handler = hpet_rtc_interrupt; err = hpet_register_irq_handler(cmos_interrupt); if (err != 0) { - printk(KERN_WARNING "hpet_register_irq_handler " + dev_warn(dev, "hpet_register_irq_handler " " failed in rtc_init()."); goto cleanup1; } @@ -731,8 +731,7 @@ cmos_do_probe(struct device *dev, struct resource *ports, int rtc_irq) goto cleanup2; } - pr_info("%s: %s%s, %zd bytes nvram%s\n", - dev_name(&cmos_rtc.rtc->dev), + dev_info(dev, "%s%s, %zd bytes nvram%s\n", !is_valid_irq(rtc_irq) ? "no alarms" : cmos_rtc.mon_alrm ? "alarms up to one year" : cmos_rtc.day_alrm ? "alarms up to one month" : @@ -820,8 +819,7 @@ static int cmos_suspend(struct device *dev) enable_irq_wake(cmos->irq); } - pr_debug("%s: suspend%s, ctrl %02x\n", - dev_name(&cmos_rtc.rtc->dev), + dev_dbg(dev, "suspend%s, ctrl %02x\n", (tmp & RTC_AIE) ? ", alarm may wake" : "", tmp); @@ -876,9 +874,7 @@ static int cmos_resume(struct device *dev) spin_unlock_irq(&rtc_lock); } - pr_debug("%s: resume, ctrl %02x\n", - dev_name(&cmos_rtc.rtc->dev), - tmp); + dev_dbg(dev, "resume, ctrl %02x\n", tmp); return 0; } -- cgit v1.2.3 From 9510853cfde2223ef39b4a7fbbb7fb100d780661 Mon Sep 17 00:00:00 2001 From: Jingoo Han Date: Thu, 21 Feb 2013 16:45:35 -0800 Subject: rtc: rtc-imxdi: use devm_clk_get() Use devm_clk_get() to make cleanup paths more simple. Signed-off-by: Jingoo Han Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/rtc/rtc-imxdi.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) (limited to 'drivers/rtc') diff --git a/drivers/rtc/rtc-imxdi.c b/drivers/rtc/rtc-imxdi.c index 75d307ab37f4..82aad695979e 100644 --- a/drivers/rtc/rtc-imxdi.c +++ b/drivers/rtc/rtc-imxdi.c @@ -406,7 +406,7 @@ static int dryice_rtc_probe(struct platform_device *pdev) mutex_init(&imxdi->write_mutex); - imxdi->clk = clk_get(&pdev->dev, NULL); + imxdi->clk = devm_clk_get(&pdev->dev, NULL); if (IS_ERR(imxdi->clk)) return PTR_ERR(imxdi->clk); clk_prepare_enable(imxdi->clk); @@ -475,7 +475,6 @@ static int dryice_rtc_probe(struct platform_device *pdev) err: clk_disable_unprepare(imxdi->clk); - clk_put(imxdi->clk); return rc; } @@ -492,7 +491,6 @@ static int dryice_rtc_remove(struct platform_device *pdev) rtc_device_unregister(imxdi->rtc); clk_disable_unprepare(imxdi->clk); - clk_put(imxdi->clk); return 0; } -- cgit v1.2.3 From 190ab4af143d10e7b81a94050d94570b8054a870 Mon Sep 17 00:00:00 2001 From: Jingoo Han Date: Thu, 21 Feb 2013 16:45:36 -0800 Subject: rtc: rtc-tps6586x: use devm_request_threaded_irq() Use devm_request_threaded_irq() to make cleanup paths more simple. Signed-off-by: Jingoo Han Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/rtc/rtc-tps6586x.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers/rtc') diff --git a/drivers/rtc/rtc-tps6586x.c b/drivers/rtc/rtc-tps6586x.c index 70f61b8e9e6f..aab4e8c93622 100644 --- a/drivers/rtc/rtc-tps6586x.c +++ b/drivers/rtc/rtc-tps6586x.c @@ -282,7 +282,8 @@ static int tps6586x_rtc_probe(struct platform_device *pdev) goto fail_rtc_register; } - ret = request_threaded_irq(rtc->irq, NULL, tps6586x_rtc_irq, + ret = devm_request_threaded_irq(&pdev->dev, rtc->irq, NULL, + tps6586x_rtc_irq, IRQF_ONESHOT | IRQF_EARLY_RESUME, dev_name(&pdev->dev), rtc); if (ret < 0) { @@ -311,7 +312,6 @@ static int tps6586x_rtc_remove(struct platform_device *pdev) tps6586x_update(tps_dev, RTC_CTRL, 0, RTC_ENABLE | OSC_SRC_SEL | PRE_BYPASS | CL_SEL_MASK); rtc_device_unregister(rtc->rtc); - free_irq(rtc->irq, rtc); return 0; } -- cgit v1.2.3 From 0db29c1da74b9fb08abaebc386300c60ef99cd29 Mon Sep 17 00:00:00 2001 From: Jingoo Han Date: Thu, 21 Feb 2013 16:45:37 -0800 Subject: rtc: rtc-vt8500: use devm_*() functions Use devm_*() functions to make cleanup paths more simple. Signed-off-by: Jingoo Han Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/rtc/rtc-vt8500.c | 28 ++++++++++------------------ 1 file changed, 10 insertions(+), 18 deletions(-) (limited to 'drivers/rtc') diff --git a/drivers/rtc/rtc-vt8500.c b/drivers/rtc/rtc-vt8500.c index 2730533e2d2d..a000bc0a8bff 100644 --- a/drivers/rtc/rtc-vt8500.c +++ b/drivers/rtc/rtc-vt8500.c @@ -231,20 +231,21 @@ static int vt8500_rtc_probe(struct platform_device *pdev) return -ENXIO; } - vt8500_rtc->res = request_mem_region(vt8500_rtc->res->start, - resource_size(vt8500_rtc->res), - "vt8500-rtc"); + vt8500_rtc->res = devm_request_mem_region(&pdev->dev, + vt8500_rtc->res->start, + resource_size(vt8500_rtc->res), + "vt8500-rtc"); if (vt8500_rtc->res == NULL) { dev_err(&pdev->dev, "failed to request I/O memory\n"); return -EBUSY; } - vt8500_rtc->regbase = ioremap(vt8500_rtc->res->start, + vt8500_rtc->regbase = devm_ioremap(&pdev->dev, vt8500_rtc->res->start, resource_size(vt8500_rtc->res)); if (!vt8500_rtc->regbase) { dev_err(&pdev->dev, "Unable to map RTC I/O memory\n"); ret = -EBUSY; - goto err_release; + goto err_return; } /* Enable RTC and set it to 24-hour mode */ @@ -257,11 +258,11 @@ static int vt8500_rtc_probe(struct platform_device *pdev) ret = PTR_ERR(vt8500_rtc->rtc); dev_err(&pdev->dev, "Failed to register RTC device -> %d\n", ret); - goto err_unmap; + goto err_return; } - ret = request_irq(vt8500_rtc->irq_alarm, vt8500_rtc_irq, 0, - "rtc alarm", vt8500_rtc); + ret = devm_request_irq(&pdev->dev, vt8500_rtc->irq_alarm, + vt8500_rtc_irq, 0, "rtc alarm", vt8500_rtc); if (ret < 0) { dev_err(&pdev->dev, "can't get irq %i, err %d\n", vt8500_rtc->irq_alarm, ret); @@ -272,11 +273,7 @@ static int vt8500_rtc_probe(struct platform_device *pdev) err_unreg: rtc_device_unregister(vt8500_rtc->rtc); -err_unmap: - iounmap(vt8500_rtc->regbase); -err_release: - release_mem_region(vt8500_rtc->res->start, - resource_size(vt8500_rtc->res)); +err_return: return ret; } @@ -284,15 +281,10 @@ static int vt8500_rtc_remove(struct platform_device *pdev) { struct vt8500_rtc *vt8500_rtc = platform_get_drvdata(pdev); - free_irq(vt8500_rtc->irq_alarm, vt8500_rtc); - rtc_device_unregister(vt8500_rtc->rtc); /* Disable alarm matching */ writel(0, vt8500_rtc->regbase + VT8500_RTC_IS); - iounmap(vt8500_rtc->regbase); - release_mem_region(vt8500_rtc->res->start, - resource_size(vt8500_rtc->res)); platform_set_drvdata(pdev, NULL); -- cgit v1.2.3 From 3b759d7f749f09617814587d4f2f448d8432afcb Mon Sep 17 00:00:00 2001 From: Jingoo Han Date: Thu, 21 Feb 2013 16:45:38 -0800 Subject: rtc: rtc-coh901331: use devm_clk_get() Use devm_clk_get() to make cleanup paths more simple. Signed-off-by: Jingoo Han Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/rtc/rtc-coh901331.c | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) (limited to 'drivers/rtc') diff --git a/drivers/rtc/rtc-coh901331.c b/drivers/rtc/rtc-coh901331.c index c8115b83e5ab..2d28ec1aa1cd 100644 --- a/drivers/rtc/rtc-coh901331.c +++ b/drivers/rtc/rtc-coh901331.c @@ -157,7 +157,6 @@ static int __exit coh901331_remove(struct platform_device *pdev) if (rtap) { rtc_device_unregister(rtap->rtc); clk_unprepare(rtap->clk); - clk_put(rtap->clk); platform_set_drvdata(pdev, NULL); } @@ -196,7 +195,7 @@ static int __init coh901331_probe(struct platform_device *pdev) "RTC COH 901 331 Alarm", rtap)) return -EIO; - rtap->clk = clk_get(&pdev->dev, NULL); + rtap->clk = devm_clk_get(&pdev->dev, NULL); if (IS_ERR(rtap->clk)) { ret = PTR_ERR(rtap->clk); dev_err(&pdev->dev, "could not get clock\n"); @@ -207,7 +206,7 @@ static int __init coh901331_probe(struct platform_device *pdev) ret = clk_prepare_enable(rtap->clk); if (ret) { dev_err(&pdev->dev, "could not enable clock\n"); - goto out_no_clk_prepenable; + return ret; } clk_disable(rtap->clk); @@ -224,8 +223,6 @@ static int __init coh901331_probe(struct platform_device *pdev) out_no_rtc: platform_set_drvdata(pdev, NULL); clk_unprepare(rtap->clk); - out_no_clk_prepenable: - clk_put(rtap->clk); return ret; } -- cgit v1.2.3 From 14b149ebd252029b41ed432024ee1db1b6afb028 Mon Sep 17 00:00:00 2001 From: Jingoo Han Date: Thu, 21 Feb 2013 16:45:39 -0800 Subject: rtc: rtc-lp8788: use devm_request_threaded_irq() Use devm_request_threaded_irq() to make cleanup paths more simple. Signed-off-by: Jingoo Han Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/rtc/rtc-lp8788.c | 10 ++-------- 1 file changed, 2 insertions(+), 8 deletions(-) (limited to 'drivers/rtc') diff --git a/drivers/rtc/rtc-lp8788.c b/drivers/rtc/rtc-lp8788.c index 4a4e78e2231c..9a4631218f41 100644 --- a/drivers/rtc/rtc-lp8788.c +++ b/drivers/rtc/rtc-lp8788.c @@ -278,16 +278,11 @@ static int lp8788_alarm_irq_register(struct platform_device *pdev, rtc->irq = irq_create_mapping(irqdm, irq); - return request_threaded_irq(rtc->irq, NULL, lp8788_alarm_irq_handler, + return devm_request_threaded_irq(&pdev->dev, rtc->irq, NULL, + lp8788_alarm_irq_handler, 0, LP8788_ALM_IRQ, rtc); } -static void lp8788_alarm_irq_unregister(struct lp8788_rtc *rtc) -{ - if (rtc->irq) - free_irq(rtc->irq, rtc); -} - static int lp8788_rtc_probe(struct platform_device *pdev) { struct lp8788 *lp = dev_get_drvdata(pdev->dev.parent); @@ -321,7 +316,6 @@ static int lp8788_rtc_remove(struct platform_device *pdev) { struct lp8788_rtc *rtc = platform_get_drvdata(pdev); - lp8788_alarm_irq_unregister(rtc); rtc_device_unregister(rtc->rdev); platform_set_drvdata(pdev, NULL); -- cgit v1.2.3 From 6d77bdca22da510ce1ea43ea07441bbba3ff8881 Mon Sep 17 00:00:00 2001 From: Jingoo Han Date: Thu, 21 Feb 2013 16:45:40 -0800 Subject: rtc: rtc-tps80031: use devm_request_threaded_irq() Use devm_request_threaded_irq() to make cleanup paths more simple. Signed-off-by: Jingoo Han Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/rtc/rtc-tps80031.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers/rtc') diff --git a/drivers/rtc/rtc-tps80031.c b/drivers/rtc/rtc-tps80031.c index 97406411d58c..9aaf8aaebae9 100644 --- a/drivers/rtc/rtc-tps80031.c +++ b/drivers/rtc/rtc-tps80031.c @@ -285,7 +285,8 @@ static int tps80031_rtc_probe(struct platform_device *pdev) return ret; } - ret = request_threaded_irq(rtc->irq, NULL, tps80031_rtc_irq, + ret = devm_request_threaded_irq(&pdev->dev, rtc->irq, NULL, + tps80031_rtc_irq, IRQF_ONESHOT | IRQF_EARLY_RESUME, dev_name(&pdev->dev), rtc); if (ret < 0) { @@ -302,7 +303,6 @@ static int tps80031_rtc_remove(struct platform_device *pdev) { struct tps80031_rtc *rtc = platform_get_drvdata(pdev); - free_irq(rtc->irq, rtc); rtc_device_unregister(rtc->rtc); return 0; } -- cgit v1.2.3 From fd5231ce336e038037b4f0190a6838bdd6e17c6d Mon Sep 17 00:00:00 2001 From: Jingoo Han Date: Thu, 21 Feb 2013 16:45:41 -0800 Subject: rtc: rtc-wm831x: use devm_request_threaded_irq() Use devm_request_threaded_irq() to make cleanup paths more simple. Signed-off-by: Jingoo Han Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/rtc/rtc-wm831x.c | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) (limited to 'drivers/rtc') diff --git a/drivers/rtc/rtc-wm831x.c b/drivers/rtc/rtc-wm831x.c index 1b0affbe2659..2f0ac7b30a0c 100644 --- a/drivers/rtc/rtc-wm831x.c +++ b/drivers/rtc/rtc-wm831x.c @@ -443,9 +443,10 @@ static int wm831x_rtc_probe(struct platform_device *pdev) goto err; } - ret = request_threaded_irq(alm_irq, NULL, wm831x_alm_irq, - IRQF_TRIGGER_RISING, "RTC alarm", - wm831x_rtc); + ret = devm_request_threaded_irq(&pdev->dev, alm_irq, NULL, + wm831x_alm_irq, + IRQF_TRIGGER_RISING, "RTC alarm", + wm831x_rtc); if (ret != 0) { dev_err(&pdev->dev, "Failed to request alarm IRQ %d: %d\n", alm_irq, ret); @@ -462,9 +463,7 @@ err: static int wm831x_rtc_remove(struct platform_device *pdev) { struct wm831x_rtc *wm831x_rtc = platform_get_drvdata(pdev); - int alm_irq = platform_get_irq_byname(pdev, "ALM"); - free_irq(alm_irq, wm831x_rtc); rtc_device_unregister(wm831x_rtc->rtc); return 0; -- cgit v1.2.3 From 27239a1498f85c16306fdc614658d0bc1ee685ef Mon Sep 17 00:00:00 2001 From: Jingoo Han Date: Thu, 21 Feb 2013 16:45:42 -0800 Subject: rtc: rtc-da9052: use devm_request_threaded_irq() Use devm_request_threaded_irq() to make cleanup paths more simple. Signed-off-by: Jingoo Han Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/rtc/rtc-da9052.c | 18 ++++++------------ 1 file changed, 6 insertions(+), 12 deletions(-) (limited to 'drivers/rtc') diff --git a/drivers/rtc/rtc-da9052.c b/drivers/rtc/rtc-da9052.c index 60b826e520e2..0dde688ca09b 100644 --- a/drivers/rtc/rtc-da9052.c +++ b/drivers/rtc/rtc-da9052.c @@ -240,9 +240,10 @@ static int da9052_rtc_probe(struct platform_device *pdev) rtc->da9052 = dev_get_drvdata(pdev->dev.parent); platform_set_drvdata(pdev, rtc); rtc->irq = platform_get_irq_byname(pdev, "ALM"); - ret = request_threaded_irq(rtc->irq, NULL, da9052_rtc_irq, - IRQF_TRIGGER_LOW | IRQF_ONESHOT, - "ALM", rtc); + ret = devm_request_threaded_irq(&pdev->dev, rtc->irq, NULL, + da9052_rtc_irq, + IRQF_TRIGGER_LOW | IRQF_ONESHOT, + "ALM", rtc); if (ret != 0) { rtc_err(rtc->da9052, "irq registration failed: %d\n", ret); return ret; @@ -250,16 +251,10 @@ static int da9052_rtc_probe(struct platform_device *pdev) rtc->rtc = rtc_device_register(pdev->name, &pdev->dev, &da9052_rtc_ops, THIS_MODULE); - if (IS_ERR(rtc->rtc)) { - ret = PTR_ERR(rtc->rtc); - goto err_free_irq; - } + if (IS_ERR(rtc->rtc)) + return PTR_ERR(rtc->rtc); return 0; - -err_free_irq: - free_irq(rtc->irq, rtc); - return ret; } static int da9052_rtc_remove(struct platform_device *pdev) @@ -267,7 +262,6 @@ static int da9052_rtc_remove(struct platform_device *pdev) struct da9052_rtc *rtc = pdev->dev.platform_data; rtc_device_unregister(rtc->rtc); - free_irq(rtc->irq, rtc); platform_set_drvdata(pdev, NULL); return 0; -- cgit v1.2.3 From 83a72c87e9d52820e9d3058004874af4df377a4d Mon Sep 17 00:00:00 2001 From: Jingoo Han Date: Thu, 21 Feb 2013 16:45:43 -0800 Subject: rtc: rtc-max8907: use devm_request_threaded_irq() Use devm_request_threaded_irq() to make cleanup paths more simple. Signed-off-by: Jingoo Han Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/rtc/rtc-max8907.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'drivers/rtc') diff --git a/drivers/rtc/rtc-max8907.c b/drivers/rtc/rtc-max8907.c index 1d049da16c85..31ca8faf9f05 100644 --- a/drivers/rtc/rtc-max8907.c +++ b/drivers/rtc/rtc-max8907.c @@ -205,8 +205,9 @@ static int max8907_rtc_probe(struct platform_device *pdev) goto err_unregister; } - ret = request_threaded_irq(rtc->irq, NULL, max8907_irq_handler, - IRQF_ONESHOT, "max8907-alarm0", rtc); + ret = devm_request_threaded_irq(&pdev->dev, rtc->irq, NULL, + max8907_irq_handler, + IRQF_ONESHOT, "max8907-alarm0", rtc); if (ret < 0) { dev_err(&pdev->dev, "Failed to request IRQ%d: %d\n", rtc->irq, ret); @@ -224,7 +225,6 @@ static int max8907_rtc_remove(struct platform_device *pdev) { struct max8907_rtc *rtc = platform_get_drvdata(pdev); - free_irq(rtc->irq, rtc); rtc_device_unregister(rtc->rtc_dev); return 0; -- cgit v1.2.3 From c1879fe80c61f3be6f2ddb82509c2e7f92a484fe Mon Sep 17 00:00:00 2001 From: Jingoo Han Date: Thu, 21 Feb 2013 16:45:44 -0800 Subject: rtc: rtc-max8997: use devm_request_threaded_irq() Use devm_request_threaded_irq() to make cleanup paths more simple. Signed-off-by: Jingoo Han Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/rtc/rtc-max8997.c | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) (limited to 'drivers/rtc') diff --git a/drivers/rtc/rtc-max8997.c b/drivers/rtc/rtc-max8997.c index a4e7079fb863..00e505b6bee3 100644 --- a/drivers/rtc/rtc-max8997.c +++ b/drivers/rtc/rtc-max8997.c @@ -495,7 +495,8 @@ static int max8997_rtc_probe(struct platform_device *pdev) } info->virq = virq; - ret = request_threaded_irq(virq, NULL, max8997_rtc_alarm_irq, 0, + ret = devm_request_threaded_irq(&pdev->dev, virq, NULL, + max8997_rtc_alarm_irq, 0, "rtc-alarm0", info); if (ret < 0) { dev_err(&pdev->dev, "Failed to request alarm IRQ: %d: %d\n", @@ -514,10 +515,8 @@ static int max8997_rtc_remove(struct platform_device *pdev) { struct max8997_rtc_info *info = platform_get_drvdata(pdev); - if (info) { - free_irq(info->virq, info); + if (info) rtc_device_unregister(info->rtc_dev); - } return 0; } -- cgit v1.2.3 From a47a376f1c025e23e836c0376813c0424de665c2 Mon Sep 17 00:00:00 2001 From: Jingoo Han Date: Thu, 21 Feb 2013 16:45:45 -0800 Subject: rtc: rtc-davinci: use devm_*() functions Use devm_*() functions to make cleanup paths more simple. Signed-off-by: Jingoo Han Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/rtc/rtc-davinci.c | 28 ++++++++++------------------ 1 file changed, 10 insertions(+), 18 deletions(-) (limited to 'drivers/rtc') diff --git a/drivers/rtc/rtc-davinci.c b/drivers/rtc/rtc-davinci.c index 5f7982f7c1b5..56b73089bb29 100644 --- a/drivers/rtc/rtc-davinci.c +++ b/drivers/rtc/rtc-davinci.c @@ -506,19 +506,19 @@ static int __init davinci_rtc_probe(struct platform_device *pdev) davinci_rtc->pbase = res->start; davinci_rtc->base_size = resource_size(res); - mem = request_mem_region(davinci_rtc->pbase, davinci_rtc->base_size, - pdev->name); + mem = devm_request_mem_region(dev, davinci_rtc->pbase, + davinci_rtc->base_size, pdev->name); if (!mem) { dev_err(dev, "RTC registers at %08x are not free\n", davinci_rtc->pbase); return -EBUSY; } - davinci_rtc->base = ioremap(davinci_rtc->pbase, davinci_rtc->base_size); + davinci_rtc->base = devm_ioremap(dev, davinci_rtc->pbase, + davinci_rtc->base_size); if (!davinci_rtc->base) { dev_err(dev, "unable to ioremap MEM resource\n"); - ret = -ENOMEM; - goto fail2; + return -ENOMEM; } platform_set_drvdata(pdev, davinci_rtc); @@ -529,7 +529,7 @@ static int __init davinci_rtc_probe(struct platform_device *pdev) ret = PTR_ERR(davinci_rtc->rtc); dev_err(dev, "unable to register RTC device, err %d\n", ret); - goto fail3; + goto fail1; } rtcif_write(davinci_rtc, PRTCIF_INTFLG_RTCSS, PRTCIF_INTFLG); @@ -539,11 +539,11 @@ static int __init davinci_rtc_probe(struct platform_device *pdev) rtcss_write(davinci_rtc, 0, PRTCSS_RTC_CTRL); rtcss_write(davinci_rtc, 0, PRTCSS_RTC_CCTRL); - ret = request_irq(davinci_rtc->irq, davinci_rtc_interrupt, + ret = devm_request_irq(dev, davinci_rtc->irq, davinci_rtc_interrupt, 0, "davinci_rtc", davinci_rtc); if (ret < 0) { dev_err(dev, "unable to register davinci RTC interrupt\n"); - goto fail4; + goto fail2; } /* Enable interrupts */ @@ -557,13 +557,10 @@ static int __init davinci_rtc_probe(struct platform_device *pdev) return 0; -fail4: +fail2: rtc_device_unregister(davinci_rtc->rtc); -fail3: +fail1: platform_set_drvdata(pdev, NULL); - iounmap(davinci_rtc->base); -fail2: - release_mem_region(davinci_rtc->pbase, davinci_rtc->base_size); return ret; } @@ -575,13 +572,8 @@ static int davinci_rtc_remove(struct platform_device *pdev) rtcif_write(davinci_rtc, 0, PRTCIF_INTEN); - free_irq(davinci_rtc->irq, davinci_rtc); - rtc_device_unregister(davinci_rtc->rtc); - iounmap(davinci_rtc->base); - release_mem_region(davinci_rtc->pbase, davinci_rtc->base_size); - platform_set_drvdata(pdev, NULL); return 0; -- cgit v1.2.3