From a65e5efa7c5faa8c320fe56cc351d47fcd006749 Mon Sep 17 00:00:00 2001 From: Alim Akhtar Date: Fri, 20 Nov 2015 16:07:53 +0530 Subject: rtc: s5m.c: Add support for S2MPS15 RTC RTC found in s2mps15 is almost same as one found on s2mps13 with few differences in RTC_UPDATE register fields, like: 1> Bit[4] and Bit[1] are reversed - On s2mps13 WUDR -> bit[4], AUDR -> bit[1] - On s2mps15 WUDR -> bit[1], AUDR -> bit[4] 2> In case of s2mps13, for alarm register, need to set both WDUR and ADUR high, whereas for s2mps15 only set AUDR to high. 3> On s2mps15, WUDR, RUDR and AUDR functions should never be used at the same time. This patch add required changes to enable s2mps15 rtc timer. Signed-off-by: Alim Akhtar Reviewed-by: Krzysztof Kozlowski Acked-by: Alexandre Belloni Signed-off-by: Lee Jones --- drivers/rtc/rtc-s5m.c | 37 +++++++++++++++++++++++++++++++++---- 1 file changed, 33 insertions(+), 4 deletions(-) (limited to 'drivers/rtc') diff --git a/drivers/rtc/rtc-s5m.c b/drivers/rtc/rtc-s5m.c index f2504b4eef34..0d68a85dd429 100644 --- a/drivers/rtc/rtc-s5m.c +++ b/drivers/rtc/rtc-s5m.c @@ -188,6 +188,7 @@ static inline int s5m_check_peding_alarm_interrupt(struct s5m_rtc_info *info, ret = regmap_read(info->regmap, S5M_RTC_STATUS, &val); val &= S5M_ALARM0_STATUS; break; + case S2MPS15X: case S2MPS14X: case S2MPS13X: ret = regmap_read(info->s5m87xx->regmap_pmic, S2MPS14_REG_ST2, @@ -219,9 +220,22 @@ static inline int s5m8767_rtc_set_time_reg(struct s5m_rtc_info *info) return ret; } - data |= info->regs->rtc_udr_mask; - if (info->device_type == S5M8763X || info->device_type == S5M8767X) - data |= S5M_RTC_TIME_EN_MASK; + switch (info->device_type) { + case S5M8763X: + case S5M8767X: + data |= info->regs->rtc_udr_mask | S5M_RTC_TIME_EN_MASK; + case S2MPS15X: + /* As per UM, for write time register, set WUDR bit to high */ + data |= S2MPS15_RTC_WUDR_MASK; + break; + case S2MPS14X: + case S2MPS13X: + data |= info->regs->rtc_udr_mask; + break; + default: + return -EINVAL; + } + ret = regmap_write(info->regmap, info->regs->rtc_udr_update, data); if (ret < 0) { @@ -252,6 +266,11 @@ static inline int s5m8767_rtc_set_alarm_reg(struct s5m_rtc_info *info) case S5M8767X: data &= ~S5M_RTC_TIME_EN_MASK; break; + case S2MPS15X: + /* As per UM, for write alarm, set A_UDR(bit[4]) to high + * rtc_udr_mask above sets bit[4] + */ + break; case S2MPS14X: data |= S2MPS_RTC_RUDR_MASK; break; @@ -317,7 +336,8 @@ static int s5m_rtc_read_time(struct device *dev, struct rtc_time *tm) u8 data[info->regs->regs_count]; int ret; - if (info->device_type == S2MPS14X || info->device_type == S2MPS13X) { + if (info->device_type == S2MPS15X || info->device_type == S2MPS14X || + info->device_type == S2MPS13X) { ret = regmap_update_bits(info->regmap, info->regs->rtc_udr_update, S2MPS_RTC_RUDR_MASK, S2MPS_RTC_RUDR_MASK); @@ -339,6 +359,7 @@ static int s5m_rtc_read_time(struct device *dev, struct rtc_time *tm) break; case S5M8767X: + case S2MPS15X: case S2MPS14X: case S2MPS13X: s5m8767_data_to_tm(data, tm, info->rtc_24hr_mode); @@ -366,6 +387,7 @@ static int s5m_rtc_set_time(struct device *dev, struct rtc_time *tm) s5m8763_tm_to_data(tm, data); break; case S5M8767X: + case S2MPS15X: case S2MPS14X: case S2MPS13X: ret = s5m8767_tm_to_data(tm, data); @@ -414,6 +436,7 @@ static int s5m_rtc_read_alarm(struct device *dev, struct rtc_wkalrm *alrm) break; case S5M8767X: + case S2MPS15X: case S2MPS14X: case S2MPS13X: s5m8767_data_to_tm(data, &alrm->time, info->rtc_24hr_mode); @@ -463,6 +486,7 @@ static int s5m_rtc_stop_alarm(struct s5m_rtc_info *info) break; case S5M8767X: + case S2MPS15X: case S2MPS14X: case S2MPS13X: for (i = 0; i < info->regs->regs_count; i++) @@ -508,6 +532,7 @@ static int s5m_rtc_start_alarm(struct s5m_rtc_info *info) break; case S5M8767X: + case S2MPS15X: case S2MPS14X: case S2MPS13X: data[RTC_SEC] |= ALARM_ENABLE_MASK; @@ -548,6 +573,7 @@ static int s5m_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alrm) break; case S5M8767X: + case S2MPS15X: case S2MPS14X: case S2MPS13X: s5m8767_tm_to_data(&alrm->time, data); @@ -631,6 +657,7 @@ static int s5m8767_rtc_init_reg(struct s5m_rtc_info *info) ret = regmap_raw_write(info->regmap, S5M_ALARM0_CONF, data, 2); break; + case S2MPS15X: case S2MPS14X: case S2MPS13X: data[0] = (0 << BCD_EN_SHIFT) | (1 << MODEL24_SHIFT); @@ -679,6 +706,7 @@ static int s5m_rtc_probe(struct platform_device *pdev) return -ENOMEM; switch (platform_get_device_id(pdev)->driver_data) { + case S2MPS15X: case S2MPS14X: case S2MPS13X: regmap_cfg = &s2mps14_rtc_regmap_config; @@ -805,6 +833,7 @@ static const struct platform_device_id s5m_rtc_id[] = { { "s5m-rtc", S5M8767X }, { "s2mps13-rtc", S2MPS13X }, { "s2mps14-rtc", S2MPS14X }, + { "s2mps15-rtc", S2MPS15X }, { }, }; MODULE_DEVICE_TABLE(platform, s5m_rtc_id); -- cgit v1.2.3 From 51c4cfef568fe8ebac06761ed7c754fac1f9b5a8 Mon Sep 17 00:00:00 2001 From: Felipe Balbi Date: Wed, 11 Nov 2015 10:11:01 -0600 Subject: rtc: ds1307: fix kernel splat due to wakeup irq handling Since commit 3fffd1283927 ("i2c: allow specifying separate wakeup interrupt in device tree") we have automatic wakeup irq support for i2c devices. That commit missed the fact that rtc-1307 had its own wakeup irq handling and ended up introducing a kernel splat for at least Beagle x15 boards. Fix that by reverting original commit _and_ passing correct interrupt names on DTS so i2c-core can choose correct IRQ as wakeup. Now that we have automatic wakeirq support, we can revert the original commit which did it manually. Fixes the following warning: [ 10.346582] WARNING: CPU: 1 PID: 263 at linux/drivers/base/power/wakeirq.c:43 dev_pm_attach_wake_irq+0xbc/0xd4() [ 10.359244] rtc-ds1307 2-006f: wake irq already initialized Cc: Tony Lindgren Cc: Nishanth Menon Signed-off-by: Felipe Balbi Acked-by: Tony Lindgren Acked-by: Arnd Bergmann Signed-off-by: Alexandre Belloni --- arch/arm/boot/dts/am57xx-beagle-x15.dts | 1 + drivers/rtc/rtc-ds1307.c | 36 +++------------------------------ 2 files changed, 4 insertions(+), 33 deletions(-) (limited to 'drivers/rtc') diff --git a/arch/arm/boot/dts/am57xx-beagle-x15.dts b/arch/arm/boot/dts/am57xx-beagle-x15.dts index d9ba6b879fc1..00352e761b8c 100644 --- a/arch/arm/boot/dts/am57xx-beagle-x15.dts +++ b/arch/arm/boot/dts/am57xx-beagle-x15.dts @@ -604,6 +604,7 @@ reg = <0x6f>; interrupts-extended = <&crossbar_mpu GIC_SPI 2 IRQ_TYPE_EDGE_RISING>, <&dra7_pmx_core 0x424>; + interrupt-names = "irq", "wakeup"; pinctrl-names = "default"; pinctrl-0 = <&mcp79410_pins_default>; diff --git a/drivers/rtc/rtc-ds1307.c b/drivers/rtc/rtc-ds1307.c index 188006c55ce0..325836818826 100644 --- a/drivers/rtc/rtc-ds1307.c +++ b/drivers/rtc/rtc-ds1307.c @@ -15,9 +15,6 @@ #include #include #include -#include -#include -#include #include #include #include @@ -117,7 +114,6 @@ struct ds1307 { #define HAS_ALARM 1 /* bit 1 == irq claimed */ struct i2c_client *client; struct rtc_device *rtc; - int wakeirq; s32 (*read_block_data)(const struct i2c_client *client, u8 command, u8 length, u8 *values); s32 (*write_block_data)(const struct i2c_client *client, u8 command, @@ -1146,8 +1142,6 @@ read_rtc: } if (want_irq) { - struct device_node *node = client->dev.of_node; - err = devm_request_threaded_irq(&client->dev, client->irq, NULL, irq_handler, IRQF_SHARED | IRQF_ONESHOT, @@ -1155,34 +1149,13 @@ read_rtc: if (err) { client->irq = 0; dev_err(&client->dev, "unable to request IRQ!\n"); - goto no_irq; - } - - set_bit(HAS_ALARM, &ds1307->flags); - dev_dbg(&client->dev, "got IRQ %d\n", client->irq); - - /* Currently supported by OF code only! */ - if (!node) - goto no_irq; - - err = of_irq_get(node, 1); - if (err <= 0) { - if (err == -EPROBE_DEFER) - goto exit; - goto no_irq; - } - ds1307->wakeirq = err; + } else { - err = dev_pm_set_dedicated_wake_irq(&client->dev, - ds1307->wakeirq); - if (err) { - dev_err(&client->dev, "unable to setup wakeIRQ %d!\n", - err); - goto exit; + set_bit(HAS_ALARM, &ds1307->flags); + dev_dbg(&client->dev, "got IRQ %d\n", client->irq); } } -no_irq: if (chip->nvram_size) { ds1307->nvram = devm_kzalloc(&client->dev, @@ -1226,9 +1199,6 @@ static int ds1307_remove(struct i2c_client *client) { struct ds1307 *ds1307 = i2c_get_clientdata(client); - if (ds1307->wakeirq) - dev_pm_clear_wake_irq(&client->dev); - if (test_and_clear_bit(HAS_NVRAM, &ds1307->flags)) sysfs_remove_bin_file(&client->dev.kobj, ds1307->nvram); -- cgit v1.2.3 From 3abb1ada21a4fb5b2920457a2e5c8483abb09a45 Mon Sep 17 00:00:00 2001 From: Simon Guinot Date: Thu, 26 Nov 2015 15:37:13 +0100 Subject: rtc: ds1307: fix alarm reading at probe time With the actual code, read_alarm() always returns -EINVAL when called during the RTC device registration. This prevents from retrieving an already configured alarm in hardware. This patch fixes the issue by moving the HAS_ALARM bit configuration (if supported by the hardware) above the rtc_device_register() call. Signed-off-by: Simon Guinot Signed-off-by: Alexandre Belloni --- drivers/rtc/rtc-ds1307.c | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) (limited to 'drivers/rtc') diff --git a/drivers/rtc/rtc-ds1307.c b/drivers/rtc/rtc-ds1307.c index 325836818826..aa705bb4748c 100644 --- a/drivers/rtc/rtc-ds1307.c +++ b/drivers/rtc/rtc-ds1307.c @@ -1134,7 +1134,10 @@ read_rtc: bin2bcd(tmp)); } - device_set_wakeup_capable(&client->dev, want_irq); + if (want_irq) { + device_set_wakeup_capable(&client->dev, true); + set_bit(HAS_ALARM, &ds1307->flags); + } ds1307->rtc = devm_rtc_device_register(&client->dev, client->name, rtc_ops, THIS_MODULE); if (IS_ERR(ds1307->rtc)) { @@ -1148,12 +1151,11 @@ read_rtc: ds1307->rtc->name, client); if (err) { client->irq = 0; + device_set_wakeup_capable(&client->dev, false); + clear_bit(HAS_ALARM, &ds1307->flags); dev_err(&client->dev, "unable to request IRQ!\n"); - } else { - - set_bit(HAS_ALARM, &ds1307->flags); + } else dev_dbg(&client->dev, "got IRQ %d\n", client->irq); - } } if (chip->nvram_size) { -- cgit v1.2.3 From 00b912b0c88e690b1662067497182454357b18b0 Mon Sep 17 00:00:00 2001 From: Daniel Axtens Date: Tue, 15 Dec 2015 18:09:14 +1100 Subject: powerpc: Remove broken GregorianDay() GregorianDay() is supposed to calculate the day of the week (tm->tm_wday) for a given day/month/year. In that calcuation it indexed into an array called MonthOffset using tm->tm_mon-1. However tm_mon is zero-based, not one-based, so this is off-by-one. It also means that every January, GregoiranDay() will access element -1 of the MonthOffset array. It also doesn't appear to be a correct algorithm either: see in contrast kernel/time/timeconv.c's time_to_tm function. It's been broken forever, which suggests no-one in userland uses this. It looks like no-one in the kernel uses tm->tm_wday either (see e.g. drivers/rtc/rtc-ds1305.c:319). tm->tm_wday is conventionally set to -1 when not available in hardware so we can simply set it to -1 and drop the function. (There are over a dozen other drivers in drivers/rtc that do this.) Found using UBSAN. Cc: Andrey Ryabinin Cc: Andrew Morton # as an example of what UBSan finds. Cc: Alessandro Zummo Cc: Alexandre Belloni Cc: rtc-linux@googlegroups.com Signed-off-by: Daniel Axtens Acked-by: Alexandre Belloni Signed-off-by: Michael Ellerman --- arch/powerpc/include/asm/time.h | 1 - arch/powerpc/kernel/time.c | 36 ++----------------------------- arch/powerpc/platforms/maple/time.c | 2 +- arch/powerpc/platforms/powernv/opal-rtc.c | 3 +-- drivers/rtc/rtc-opal.c | 2 +- 5 files changed, 5 insertions(+), 39 deletions(-) (limited to 'drivers/rtc') diff --git a/arch/powerpc/include/asm/time.h b/arch/powerpc/include/asm/time.h index 10fc784a2ad4..2d7109a8d296 100644 --- a/arch/powerpc/include/asm/time.h +++ b/arch/powerpc/include/asm/time.h @@ -27,7 +27,6 @@ extern struct clock_event_device decrementer_clockevent; struct rtc_time; extern void to_tm(int tim, struct rtc_time * tm); -extern void GregorianDay(struct rtc_time *tm); extern void tick_broadcast_ipi_handler(void); extern void generic_calibrate_decr(void); diff --git a/arch/powerpc/kernel/time.c b/arch/powerpc/kernel/time.c index 1be1092c7204..81b0900a39ee 100644 --- a/arch/powerpc/kernel/time.c +++ b/arch/powerpc/kernel/time.c @@ -1002,38 +1002,6 @@ static int month_days[12] = { 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 }; -/* - * This only works for the Gregorian calendar - i.e. after 1752 (in the UK) - */ -void GregorianDay(struct rtc_time * tm) -{ - int leapsToDate; - int lastYear; - int day; - int MonthOffset[] = { 0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334 }; - - lastYear = tm->tm_year - 1; - - /* - * Number of leap corrections to apply up to end of last year - */ - leapsToDate = lastYear / 4 - lastYear / 100 + lastYear / 400; - - /* - * This year is a leap year if it is divisible by 4 except when it is - * divisible by 100 unless it is divisible by 400 - * - * e.g. 1904 was a leap year, 1900 was not, 1996 is, and 2000 was - */ - day = tm->tm_mon > 2 && leapyear(tm->tm_year); - - day += lastYear*365 + leapsToDate + MonthOffset[tm->tm_mon-1] + - tm->tm_mday; - - tm->tm_wday = day % 7; -} -EXPORT_SYMBOL_GPL(GregorianDay); - void to_tm(int tim, struct rtc_time * tm) { register int i; @@ -1064,9 +1032,9 @@ void to_tm(int tim, struct rtc_time * tm) tm->tm_mday = day + 1; /* - * Determine the day of week + * No-one uses the day of the week. */ - GregorianDay(tm); + tm->tm_wday = -1; } EXPORT_SYMBOL(to_tm); diff --git a/arch/powerpc/platforms/maple/time.c b/arch/powerpc/platforms/maple/time.c index b4a369dac3a8..81799d70a1ee 100644 --- a/arch/powerpc/platforms/maple/time.c +++ b/arch/powerpc/platforms/maple/time.c @@ -77,7 +77,7 @@ void maple_get_rtc_time(struct rtc_time *tm) if ((tm->tm_year + 1900) < 1970) tm->tm_year += 100; - GregorianDay(tm); + tm->tm_wday = -1; } int maple_set_rtc_time(struct rtc_time *tm) diff --git a/arch/powerpc/platforms/powernv/opal-rtc.c b/arch/powerpc/platforms/powernv/opal-rtc.c index 37dbee15769f..1b149c92fca1 100644 --- a/arch/powerpc/platforms/powernv/opal-rtc.c +++ b/arch/powerpc/platforms/powernv/opal-rtc.c @@ -31,8 +31,7 @@ static void opal_to_tm(u32 y_m_d, u64 h_m_s_ms, struct rtc_time *tm) tm->tm_hour = bcd2bin((h_m_s_ms >> 56) & 0xff); tm->tm_min = bcd2bin((h_m_s_ms >> 48) & 0xff); tm->tm_sec = bcd2bin((h_m_s_ms >> 40) & 0xff); - - GregorianDay(tm); + tm->tm_wday = -1; } unsigned long __init opal_get_boot_time(void) diff --git a/drivers/rtc/rtc-opal.c b/drivers/rtc/rtc-opal.c index df39ce02a99d..9c18d6fd8107 100644 --- a/drivers/rtc/rtc-opal.c +++ b/drivers/rtc/rtc-opal.c @@ -40,7 +40,7 @@ static void opal_to_tm(u32 y_m_d, u64 h_m_s_ms, struct rtc_time *tm) tm->tm_min = bcd2bin((h_m_s_ms >> 48) & 0xff); tm->tm_sec = bcd2bin((h_m_s_ms >> 40) & 0xff); - GregorianDay(tm); + tm->tm_wday = -1; } static void tm_to_opal(struct rtc_time *tm, u32 *y_m_d, u64 *h_m_s_ms) -- cgit v1.2.3 From f076ef44a44d02ed91543f820c14c2c7dff53716 Mon Sep 17 00:00:00 2001 From: Julius Werner Date: Tue, 15 Dec 2015 15:02:49 -0800 Subject: rtc: rk808: Compensate for Rockchip calendar deviation on November 31st In A.D. 1582 Pope Gregory XIII found that the existing Julian calendar insufficiently represented reality, and changed the rules about calculating leap years to account for this. Similarly, in A.D. 2013 Rockchip hardware engineers found that the new Gregorian calendar still contained flaws, and that the month of November should be counted up to 31 days instead. Unfortunately it takes a long time for calendar changes to gain widespread adoption, and just like more than 300 years went by before the last Protestant nation implemented Greg's proposal, we will have to wait a while until all religions and operating system kernels acknowledge the inherent advantages of the Rockchip system. Until then we need to translate dates read from (and written to) Rockchip hardware back to the Gregorian format. This patch works by defining Jan 1st, 2016 as the arbitrary anchor date on which Rockchip and Gregorian calendars are in sync. From that we can translate arbitrary later dates back and forth by counting the number of November/December transitons since the anchor date to determine the offset between the calendars. We choose this method (rather than trying to regularly "correct" the date stored in hardware) since it's the only way to ensure perfect time-keeping even if the system may be shut down for an unknown number of years. The drawback is that other software reading the same hardware (e.g. mainboard firmware) must use the same translation convention (including the same anchor date) to be able to read and write correct timestamps from/to the RTC. Signed-off-by: Julius Werner Reviewed-by: Douglas Anderson Signed-off-by: Alexandre Belloni --- drivers/rtc/rtc-rk808.c | 48 ++++++++++++++++++++++++++++++++++++++++++++---- 1 file changed, 44 insertions(+), 4 deletions(-) (limited to 'drivers/rtc') diff --git a/drivers/rtc/rtc-rk808.c b/drivers/rtc/rtc-rk808.c index 91ca0bc1b484..35c9aada07c8 100644 --- a/drivers/rtc/rtc-rk808.c +++ b/drivers/rtc/rtc-rk808.c @@ -56,6 +56,42 @@ struct rk808_rtc { int irq; }; +/* + * The Rockchip calendar used by the RK808 counts November with 31 days. We use + * these translation functions to convert its dates to/from the Gregorian + * calendar used by the rest of the world. We arbitrarily define Jan 1st, 2016 + * as the day when both calendars were in sync, and treat all other dates + * relative to that. + * NOTE: Other system software (e.g. firmware) that reads the same hardware must + * implement this exact same conversion algorithm, with the same anchor date. + */ +static time64_t nov2dec_transitions(struct rtc_time *tm) +{ + return (tm->tm_year + 1900) - 2016 + (tm->tm_mon + 1 > 11 ? 1 : 0); +} + +static void rockchip_to_gregorian(struct rtc_time *tm) +{ + /* If it's Nov 31st, rtc_tm_to_time64() will count that like Dec 1st */ + time64_t time = rtc_tm_to_time64(tm); + rtc_time64_to_tm(time + nov2dec_transitions(tm) * 86400, tm); +} + +static void gregorian_to_rockchip(struct rtc_time *tm) +{ + time64_t extra_days = nov2dec_transitions(tm); + time64_t time = rtc_tm_to_time64(tm); + rtc_time64_to_tm(time - extra_days * 86400, tm); + + /* Compensate if we went back over Nov 31st (will work up to 2381) */ + if (nov2dec_transitions(tm) < extra_days) { + if (tm->tm_mon + 1 == 11) + tm->tm_mday++; /* This may result in 31! */ + else + rtc_time64_to_tm(time - (extra_days - 1) * 86400, tm); + } +} + /* Read current time and date in RTC */ static int rk808_rtc_readtime(struct device *dev, struct rtc_time *tm) { @@ -101,9 +137,10 @@ static int rk808_rtc_readtime(struct device *dev, struct rtc_time *tm) tm->tm_mon = (bcd2bin(rtc_data[4] & MONTHS_REG_MSK)) - 1; tm->tm_year = (bcd2bin(rtc_data[5] & YEARS_REG_MSK)) + 100; tm->tm_wday = bcd2bin(rtc_data[6] & WEEKS_REG_MSK); + rockchip_to_gregorian(tm); dev_dbg(dev, "RTC date/time %4d-%02d-%02d(%d) %02d:%02d:%02d\n", 1900 + tm->tm_year, tm->tm_mon + 1, tm->tm_mday, - tm->tm_wday, tm->tm_hour , tm->tm_min, tm->tm_sec); + tm->tm_wday, tm->tm_hour, tm->tm_min, tm->tm_sec); return ret; } @@ -116,6 +153,10 @@ static int rk808_rtc_set_time(struct device *dev, struct rtc_time *tm) u8 rtc_data[NUM_TIME_REGS]; int ret; + dev_dbg(dev, "set RTC date/time %4d-%02d-%02d(%d) %02d:%02d:%02d\n", + 1900 + tm->tm_year, tm->tm_mon + 1, tm->tm_mday, + tm->tm_wday, tm->tm_hour, tm->tm_min, tm->tm_sec); + gregorian_to_rockchip(tm); rtc_data[0] = bin2bcd(tm->tm_sec); rtc_data[1] = bin2bcd(tm->tm_min); rtc_data[2] = bin2bcd(tm->tm_hour); @@ -123,9 +164,6 @@ static int rk808_rtc_set_time(struct device *dev, struct rtc_time *tm) rtc_data[4] = bin2bcd(tm->tm_mon + 1); rtc_data[5] = bin2bcd(tm->tm_year - 100); rtc_data[6] = bin2bcd(tm->tm_wday); - dev_dbg(dev, "set RTC date/time %4d-%02d-%02d(%d) %02d:%02d:%02d\n", - 1900 + tm->tm_year, tm->tm_mon + 1, tm->tm_mday, - tm->tm_wday, tm->tm_hour , tm->tm_min, tm->tm_sec); /* Stop RTC while updating the RTC registers */ ret = regmap_update_bits(rk808->regmap, RK808_RTC_CTRL_REG, @@ -170,6 +208,7 @@ static int rk808_rtc_readalarm(struct device *dev, struct rtc_wkalrm *alrm) alrm->time.tm_mday = bcd2bin(alrm_data[3] & DAYS_REG_MSK); alrm->time.tm_mon = (bcd2bin(alrm_data[4] & MONTHS_REG_MSK)) - 1; alrm->time.tm_year = (bcd2bin(alrm_data[5] & YEARS_REG_MSK)) + 100; + rockchip_to_gregorian(&alrm->time); ret = regmap_read(rk808->regmap, RK808_RTC_INT_REG, &int_reg); if (ret) { @@ -227,6 +266,7 @@ static int rk808_rtc_setalarm(struct device *dev, struct rtc_wkalrm *alrm) alrm->time.tm_mday, alrm->time.tm_wday, alrm->time.tm_hour, alrm->time.tm_min, alrm->time.tm_sec); + gregorian_to_rockchip(&alrm->time); alrm_data[0] = bin2bcd(alrm->time.tm_sec); alrm_data[1] = bin2bcd(alrm->time.tm_min); alrm_data[2] = bin2bcd(alrm->time.tm_hour); -- cgit v1.2.3 From 77535acedc26627f16a1a39c1471f942689fe11e Mon Sep 17 00:00:00 2001 From: Steve Twiss Date: Tue, 8 Dec 2015 16:28:39 +0000 Subject: rtc: da9063: fix access ordering error during RTC interrupt at system power on This fix alters the ordering of the IRQ and device registrations in the RTC driver probe function. This change will apply to the RTC driver that supports both DA9063 and DA9062 PMICs. A problem could occur with the existing RTC driver if: A system is started from a cold boot using the PMIC RTC IRQ to initiate a power on operation. For instance, if an RTC alarm is used to start a platform from power off. The existing driver IRQ is requested before the device has been properly registered. i.e. ret = devm_request_threaded_irq() comes before rtc->rtc_dev = devm_rtc_device_register(); In this case, the interrupt can be called before the device has been registered and the handler can be called immediately. The IRQ handler da9063_alarm_event() contains the function call rtc_update_irq(rtc->rtc_dev, 1, RTC_IRQF | RTC_AF); which in turn tries to access the unavailable rtc->rtc_dev. The fix is to reorder the functions inside the RTC probe. The IRQ is requested after the RTC device resource has been registered so that get_irq_byname is the last thing to happen. Signed-off-by: Steve Twiss Signed-off-by: Alexandre Belloni --- drivers/rtc/rtc-da9063.c | 19 +++++++++---------- 1 file changed, 9 insertions(+), 10 deletions(-) (limited to 'drivers/rtc') diff --git a/drivers/rtc/rtc-da9063.c b/drivers/rtc/rtc-da9063.c index 284b587da65c..d6c853bbfa9f 100644 --- a/drivers/rtc/rtc-da9063.c +++ b/drivers/rtc/rtc-da9063.c @@ -483,24 +483,23 @@ static int da9063_rtc_probe(struct platform_device *pdev) platform_set_drvdata(pdev, rtc); + rtc->rtc_dev = devm_rtc_device_register(&pdev->dev, DA9063_DRVNAME_RTC, + &da9063_rtc_ops, THIS_MODULE); + if (IS_ERR(rtc->rtc_dev)) + return PTR_ERR(rtc->rtc_dev); + + da9063_data_to_tm(data, &rtc->alarm_time, rtc); + rtc->rtc_sync = false; + irq_alarm = platform_get_irq_byname(pdev, "ALARM"); ret = devm_request_threaded_irq(&pdev->dev, irq_alarm, NULL, da9063_alarm_event, IRQF_TRIGGER_LOW | IRQF_ONESHOT, "ALARM", rtc); - if (ret) { + if (ret) dev_err(&pdev->dev, "Failed to request ALARM IRQ %d: %d\n", irq_alarm, ret); - return ret; - } - - rtc->rtc_dev = devm_rtc_device_register(&pdev->dev, DA9063_DRVNAME_RTC, - &da9063_rtc_ops, THIS_MODULE); - if (IS_ERR(rtc->rtc_dev)) - return PTR_ERR(rtc->rtc_dev); - da9063_data_to_tm(data, &rtc->alarm_time, rtc); - rtc->rtc_sync = false; return ret; } -- cgit v1.2.3 From fbbf53f70225c82ba877de780486be5bc81b29e2 Mon Sep 17 00:00:00 2001 From: Uwe Kleine-König Date: Fri, 6 Nov 2015 17:37:56 +0100 Subject: rtc: pcf8523: refuse to write dates later than 2099 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit When the chip increments the YEAR register and it already holds bin2bcd(99) it reads as 0 afterwards. With this behaviour the last valid day (without trickery) that has a representation is 2099-12-31 23:59:59. So refuse to write later dates. Signed-off-by: Uwe Kleine-König Signed-off-by: Alexandre Belloni --- drivers/rtc/rtc-pcf8523.c | 11 +++++++++++ 1 file changed, 11 insertions(+) (limited to 'drivers/rtc') diff --git a/drivers/rtc/rtc-pcf8523.c b/drivers/rtc/rtc-pcf8523.c index e7ebcc0b7e59..988566caaaa6 100644 --- a/drivers/rtc/rtc-pcf8523.c +++ b/drivers/rtc/rtc-pcf8523.c @@ -219,6 +219,17 @@ static int pcf8523_rtc_set_time(struct device *dev, struct rtc_time *tm) u8 regs[8]; int err; + /* + * The hardware can only store values between 0 and 99 in it's YEAR + * register (with 99 overflowing to 0 on increment). + * After 2100-02-28 we could start interpreting the year to be in the + * interval [2100, 2199], but there is no path to switch in a smooth way + * because the chip handles YEAR=0x00 (and the out-of-spec + * YEAR=0xa0) as a leap year, but 2100 isn't. + */ + if (tm->tm_year < 100 || tm->tm_year >= 200) + return -EINVAL; + err = pcf8523_stop_rtc(client); if (err < 0) return err; -- cgit v1.2.3 From b01079be449b895913ce17a47933820af708d5dd Mon Sep 17 00:00:00 2001 From: Geliang Tang Date: Sat, 7 Nov 2015 12:00:21 +0800 Subject: rtc: fix module reference count in rtc-proc rtc-proc.c is not built as a module. Thus, rather than dealing with THIS_MODULE's reference count, we should deal with rtc->owner's reference count. Signed-off-by: Geliang Tang Signed-off-by: Alexandre Belloni --- drivers/rtc/rtc-proc.c | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) (limited to 'drivers/rtc') diff --git a/drivers/rtc/rtc-proc.c b/drivers/rtc/rtc-proc.c index ffa69e1c9245..31e7e23cc5be 100644 --- a/drivers/rtc/rtc-proc.c +++ b/drivers/rtc/rtc-proc.c @@ -112,19 +112,21 @@ static int rtc_proc_open(struct inode *inode, struct file *file) int ret; struct rtc_device *rtc = PDE_DATA(inode); - if (!try_module_get(THIS_MODULE)) + if (!try_module_get(rtc->owner)) return -ENODEV; ret = single_open(file, rtc_proc_show, rtc); if (ret) - module_put(THIS_MODULE); + module_put(rtc->owner); return ret; } static int rtc_proc_release(struct inode *inode, struct file *file) { int res = single_release(inode, file); - module_put(THIS_MODULE); + struct rtc_device *rtc = PDE_DATA(inode); + + module_put(rtc->owner); return res; } -- cgit v1.2.3 From 501385f2a783c0a6cc52c8b984892c57175857f9 Mon Sep 17 00:00:00 2001 From: Geliang Tang Date: Sat, 7 Nov 2015 12:00:22 +0800 Subject: rtc: efi: add efi_procfs in efi_rtc_ops Add efi_procfs in efi_rtc_ops to show rtc-efi info in /proc/driver/rtc. Most of the code comes from efi_rtc_proc_show() in efirtc. Signed-off-by: Geliang Tang Signed-off-by: Alexandre Belloni --- drivers/rtc/rtc-efi.c | 66 +++++++++++++++++++++++++++++++++++++++++++++++---- 1 file changed, 62 insertions(+), 4 deletions(-) (limited to 'drivers/rtc') diff --git a/drivers/rtc/rtc-efi.c b/drivers/rtc/rtc-efi.c index 3806961b4348..96d38609d803 100644 --- a/drivers/rtc/rtc-efi.c +++ b/drivers/rtc/rtc-efi.c @@ -191,11 +191,69 @@ static int efi_set_time(struct device *dev, struct rtc_time *tm) return status == EFI_SUCCESS ? 0 : -EINVAL; } +static int efi_procfs(struct device *dev, struct seq_file *seq) +{ + efi_time_t eft, alm; + efi_time_cap_t cap; + efi_bool_t enabled, pending; + + memset(&eft, 0, sizeof(eft)); + memset(&alm, 0, sizeof(alm)); + memset(&cap, 0, sizeof(cap)); + + efi.get_time(&eft, &cap); + efi.get_wakeup_time(&enabled, &pending, &alm); + + seq_printf(seq, + "Time\t\t: %u:%u:%u.%09u\n" + "Date\t\t: %u-%u-%u\n" + "Daylight\t: %u\n", + eft.hour, eft.minute, eft.second, eft.nanosecond, + eft.year, eft.month, eft.day, + eft.daylight); + + if (eft.timezone == EFI_UNSPECIFIED_TIMEZONE) + seq_puts(seq, "Timezone\t: unspecified\n"); + else + /* XXX fixme: convert to string? */ + seq_printf(seq, "Timezone\t: %u\n", eft.timezone); + + seq_printf(seq, + "Alarm Time\t: %u:%u:%u.%09u\n" + "Alarm Date\t: %u-%u-%u\n" + "Alarm Daylight\t: %u\n" + "Enabled\t\t: %s\n" + "Pending\t\t: %s\n", + alm.hour, alm.minute, alm.second, alm.nanosecond, + alm.year, alm.month, alm.day, + alm.daylight, + enabled == 1 ? "yes" : "no", + pending == 1 ? "yes" : "no"); + + if (eft.timezone == EFI_UNSPECIFIED_TIMEZONE) + seq_puts(seq, "Timezone\t: unspecified\n"); + else + /* XXX fixme: convert to string? */ + seq_printf(seq, "Timezone\t: %u\n", alm.timezone); + + /* + * now prints the capabilities + */ + seq_printf(seq, + "Resolution\t: %u\n" + "Accuracy\t: %u\n" + "SetstoZero\t: %u\n", + cap.resolution, cap.accuracy, cap.sets_to_zero); + + return 0; +} + static const struct rtc_class_ops efi_rtc_ops = { - .read_time = efi_read_time, - .set_time = efi_set_time, - .read_alarm = efi_read_alarm, - .set_alarm = efi_set_alarm, + .read_time = efi_read_time, + .set_time = efi_set_time, + .read_alarm = efi_read_alarm, + .set_alarm = efi_set_alarm, + .proc = efi_procfs, }; static int __init efi_rtc_probe(struct platform_device *dev) -- cgit v1.2.3 From 3fc2c14acaf925768db37cf439c628bfa71dff09 Mon Sep 17 00:00:00 2001 From: Nizam Haider Date: Sat, 14 Nov 2015 01:51:29 +0530 Subject: rtc: gemini: Remove unnecessary platform_set_drvdata() The driver core clears the driver data to NULL after device_release or on probe failure Signed-off-by: Nizam Haider Acked-by: Hans Ulli Kroll Signed-off-by: Alexandre Belloni --- drivers/rtc/rtc-gemini.c | 1 - 1 file changed, 1 deletion(-) (limited to 'drivers/rtc') diff --git a/drivers/rtc/rtc-gemini.c b/drivers/rtc/rtc-gemini.c index e84184647d15..f46b6d46a51b 100644 --- a/drivers/rtc/rtc-gemini.c +++ b/drivers/rtc/rtc-gemini.c @@ -156,7 +156,6 @@ static int gemini_rtc_remove(struct platform_device *pdev) struct gemini_rtc *rtc = platform_get_drvdata(pdev); rtc_device_unregister(rtc->rtc_dev); - platform_set_drvdata(pdev, NULL); return 0; } -- cgit v1.2.3 From f8947feb2c0196dafa7683f557eb8dddfb1ae167 Mon Sep 17 00:00:00 2001 From: LABBE Corentin Date: Thu, 19 Nov 2015 11:50:08 +0100 Subject: rtc: sunxi: fix signedness issues The variable year must be set as unsigned since it is used with sunxi_rtc_data_year{.min|.max} and as parameter of is_leap_year() which wait for unsigned int. Only tm_year is not unsigned, but it is long. This patch fix also the format of printing of min/max. (must use %u since they are unsigned) The parameter to of sunxi_rtc_setaie() must be set to uint since callers give always uint data. Signed-off-by: LABBE Corentin Acked-by: Chen-Yu Tsai Signed-off-by: Alexandre Belloni --- drivers/rtc/rtc-sunxi.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) (limited to 'drivers/rtc') diff --git a/drivers/rtc/rtc-sunxi.c b/drivers/rtc/rtc-sunxi.c index 52543ae37c98..b4f35acc1e12 100644 --- a/drivers/rtc/rtc-sunxi.c +++ b/drivers/rtc/rtc-sunxi.c @@ -175,7 +175,7 @@ static irqreturn_t sunxi_rtc_alarmirq(int irq, void *id) return IRQ_NONE; } -static void sunxi_rtc_setaie(int to, struct sunxi_rtc_dev *chip) +static void sunxi_rtc_setaie(unsigned int to, struct sunxi_rtc_dev *chip) { u32 alrm_val = 0; u32 alrm_irq_val = 0; @@ -343,7 +343,7 @@ static int sunxi_rtc_settime(struct device *dev, struct rtc_time *rtc_tm) struct sunxi_rtc_dev *chip = dev_get_drvdata(dev); u32 date = 0; u32 time = 0; - int year; + unsigned int year; /* * the input rtc_tm->tm_year is the offset relative to 1900. We use @@ -353,8 +353,8 @@ static int sunxi_rtc_settime(struct device *dev, struct rtc_time *rtc_tm) year = rtc_tm->tm_year + 1900; if (year < chip->data_year->min || year > chip->data_year->max) { - dev_err(dev, "rtc only supports year in range %d - %d\n", - chip->data_year->min, chip->data_year->max); + dev_err(dev, "rtc only supports year in range %u - %u\n", + chip->data_year->min, chip->data_year->max); return -EINVAL; } -- cgit v1.2.3 From 6ddab92faa2d7d7b38cb2b228f7fdfd1eecba5e2 Mon Sep 17 00:00:00 2001 From: LABBE Corentin Date: Thu, 19 Nov 2015 11:50:09 +0100 Subject: rtc: sunxi: constify the data_year_param structure The data_year_param struct is never modified, so lets constify it. This permit to remove cast since of_device_id is const also. Signed-off-by: LABBE Corentin Acked-by: Chen-Yu Tsai Signed-off-by: Alexandre Belloni --- drivers/rtc/rtc-sunxi.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'drivers/rtc') diff --git a/drivers/rtc/rtc-sunxi.c b/drivers/rtc/rtc-sunxi.c index b4f35acc1e12..0c08a5b7dc61 100644 --- a/drivers/rtc/rtc-sunxi.c +++ b/drivers/rtc/rtc-sunxi.c @@ -133,7 +133,7 @@ struct sunxi_rtc_data_year { unsigned char leap_shift; /* bit shift to get the leap year */ }; -static struct sunxi_rtc_data_year data_year_param[] = { +static const struct sunxi_rtc_data_year data_year_param[] = { [0] = { .min = 2010, .max = 2073, @@ -151,7 +151,7 @@ static struct sunxi_rtc_data_year data_year_param[] = { struct sunxi_rtc_dev { struct rtc_device *rtc; struct device *dev; - struct sunxi_rtc_data_year *data_year; + const struct sunxi_rtc_data_year *data_year; void __iomem *base; int irq; }; @@ -468,7 +468,7 @@ static int sunxi_rtc_probe(struct platform_device *pdev) dev_err(&pdev->dev, "Unable to setup RTC data\n"); return -ENODEV; } - chip->data_year = (struct sunxi_rtc_data_year *) of_id->data; + chip->data_year = of_id->data; /* clear the alarm count value */ writel(0, chip->base + SUNXI_ALRM_DHMS); -- cgit v1.2.3 From 4d833d601332b00a1ef5f0249e97481d02f3ad02 Mon Sep 17 00:00:00 2001 From: LABBE Corentin Date: Thu, 19 Nov 2015 11:50:10 +0100 Subject: rtc: sunxi: use of_device_get_match_data The usage of of_device_get_match_data reduce the code size a bit. Signed-off-by: LABBE Corentin Acked-by: Chen-Yu Tsai Signed-off-by: Alexandre Belloni --- drivers/rtc/rtc-sunxi.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) (limited to 'drivers/rtc') diff --git a/drivers/rtc/rtc-sunxi.c b/drivers/rtc/rtc-sunxi.c index 0c08a5b7dc61..abada609ddc7 100644 --- a/drivers/rtc/rtc-sunxi.c +++ b/drivers/rtc/rtc-sunxi.c @@ -436,7 +436,6 @@ static int sunxi_rtc_probe(struct platform_device *pdev) { struct sunxi_rtc_dev *chip; struct resource *res; - const struct of_device_id *of_id; int ret; chip = devm_kzalloc(&pdev->dev, sizeof(*chip), GFP_KERNEL); @@ -463,12 +462,11 @@ static int sunxi_rtc_probe(struct platform_device *pdev) return ret; } - of_id = of_match_device(sunxi_rtc_dt_ids, &pdev->dev); - if (!of_id) { + chip->data_year = of_device_get_match_data(&pdev->dev); + if (!chip->data_year) { dev_err(&pdev->dev, "Unable to setup RTC data\n"); return -ENODEV; } - chip->data_year = of_id->data; /* clear the alarm count value */ writel(0, chip->base + SUNXI_ALRM_DHMS); -- cgit v1.2.3 From 2ad2c17480b6208a35a4ffb937effe0ba1ed39de Mon Sep 17 00:00:00 2001 From: Enrico Scholz Date: Fri, 27 Nov 2015 13:02:55 +0100 Subject: rtc: da9063: avoid writing undefined data to rtc driver did | static void da9063_tm_to_data(struct rtc_time *tm, u8 *data, | { | const struct da9063_compatible_rtc_regmap *config = rtc->config; | | data[RTC_SEC] &= ~config->rtc_count_sec_mask; | data[RTC_SEC] |= tm->tm_sec & config->rtc_count_sec_mask; | ... | } | ... | static int da9063_rtc_set_time(struct device *dev, struct rtc_time *tm) | { | ... | u8 data[RTC_DATA_LEN]; | int ret; | | da9063_tm_to_data(tm, data, rtc); which means that some bits of stack content (in 'data[]') was masked out and written to the RTC. Because da9063_tm_to_data() is used only by da9063_rtc_set_time() and da9063_rtc_set_alarm(), we can write fields directly. Signed-off-by: Enrico Scholz Acked-by: Steve Twiss Tested-by: Steve Twiss Signed-off-by: Alexandre Belloni --- drivers/rtc/rtc-da9063.c | 23 ++++++----------------- 1 file changed, 6 insertions(+), 17 deletions(-) (limited to 'drivers/rtc') diff --git a/drivers/rtc/rtc-da9063.c b/drivers/rtc/rtc-da9063.c index d6c853bbfa9f..f85cae240f12 100644 --- a/drivers/rtc/rtc-da9063.c +++ b/drivers/rtc/rtc-da9063.c @@ -191,24 +191,13 @@ static void da9063_tm_to_data(struct rtc_time *tm, u8 *data, { const struct da9063_compatible_rtc_regmap *config = rtc->config; - data[RTC_SEC] &= ~config->rtc_count_sec_mask; - data[RTC_SEC] |= tm->tm_sec & config->rtc_count_sec_mask; - - data[RTC_MIN] &= ~config->rtc_count_min_mask; - data[RTC_MIN] |= tm->tm_min & config->rtc_count_min_mask; - - data[RTC_HOUR] &= ~config->rtc_count_hour_mask; - data[RTC_HOUR] |= tm->tm_hour & config->rtc_count_hour_mask; - - data[RTC_DAY] &= ~config->rtc_count_day_mask; - data[RTC_DAY] |= tm->tm_mday & config->rtc_count_day_mask; - - data[RTC_MONTH] &= ~config->rtc_count_month_mask; - data[RTC_MONTH] |= MONTHS_TO_DA9063(tm->tm_mon) & + data[RTC_SEC] = tm->tm_sec & config->rtc_count_sec_mask; + data[RTC_MIN] = tm->tm_min & config->rtc_count_min_mask; + data[RTC_HOUR] = tm->tm_hour & config->rtc_count_hour_mask; + data[RTC_DAY] = tm->tm_mday & config->rtc_count_day_mask; + data[RTC_MONTH] = MONTHS_TO_DA9063(tm->tm_mon) & config->rtc_count_month_mask; - - data[RTC_YEAR] &= ~config->rtc_count_year_mask; - data[RTC_YEAR] |= YEARS_TO_DA9063(tm->tm_year) & + data[RTC_YEAR] = YEARS_TO_DA9063(tm->tm_year) & config->rtc_count_year_mask; } -- cgit v1.2.3 From ff67abd236ca7b65ea632f476f0f0cfc83aea711 Mon Sep 17 00:00:00 2001 From: Rasmus Villemoes Date: Tue, 24 Nov 2015 14:51:23 +0100 Subject: rtc: use %ph for short hex dumps This makes the generated code slightly smaller. Signed-off-by: Rasmus Villemoes Signed-off-by: Alexandre Belloni --- drivers/rtc/rtc-ds1305.c | 8 ++------ drivers/rtc/rtc-ds1307.c | 17 ++++------------- drivers/rtc/rtc-ds1685.c | 12 +++++------- 3 files changed, 11 insertions(+), 26 deletions(-) (limited to 'drivers/rtc') diff --git a/drivers/rtc/rtc-ds1305.c b/drivers/rtc/rtc-ds1305.c index 85706a9f82c9..f39691eea736 100644 --- a/drivers/rtc/rtc-ds1305.c +++ b/drivers/rtc/rtc-ds1305.c @@ -186,9 +186,7 @@ static int ds1305_get_time(struct device *dev, struct rtc_time *time) if (status < 0) return status; - dev_vdbg(dev, "%s: %02x %02x %02x, %02x %02x %02x %02x\n", - "read", buf[0], buf[1], buf[2], buf[3], - buf[4], buf[5], buf[6]); + dev_vdbg(dev, "%s: %3ph, %4ph\n", "read", &buf[0], &buf[3]); /* Decode the registers */ time->tm_sec = bcd2bin(buf[DS1305_SEC]); @@ -232,9 +230,7 @@ static int ds1305_set_time(struct device *dev, struct rtc_time *time) *bp++ = bin2bcd(time->tm_mon + 1); *bp++ = bin2bcd(time->tm_year - 100); - dev_dbg(dev, "%s: %02x %02x %02x, %02x %02x %02x %02x\n", - "write", buf[1], buf[2], buf[3], - buf[4], buf[5], buf[6], buf[7]); + dev_dbg(dev, "%s: %3ph, %4ph\n", "write", &buf[1], &buf[4]); /* use write-then-read since dma from stack is nonportable */ return spi_write_then_read(ds1305->spi, buf, sizeof(buf), diff --git a/drivers/rtc/rtc-ds1307.c b/drivers/rtc/rtc-ds1307.c index aa705bb4748c..cf685f67b391 100644 --- a/drivers/rtc/rtc-ds1307.c +++ b/drivers/rtc/rtc-ds1307.c @@ -460,13 +460,8 @@ static int ds1337_read_alarm(struct device *dev, struct rtc_wkalrm *t) return -EIO; } - dev_dbg(dev, "%s: %02x %02x %02x %02x, %02x %02x %02x, %02x %02x\n", - "alarm read", - ds1307->regs[0], ds1307->regs[1], - ds1307->regs[2], ds1307->regs[3], - ds1307->regs[4], ds1307->regs[5], - ds1307->regs[6], ds1307->regs[7], - ds1307->regs[8]); + dev_dbg(dev, "%s: %4ph, %3ph, %2ph\n", "alarm read", + &ds1307->regs[0], &ds1307->regs[4], &ds1307->regs[7]); /* * report alarm time (ALARM1); assume 24 hour and day-of-month modes, @@ -522,12 +517,8 @@ static int ds1337_set_alarm(struct device *dev, struct rtc_wkalrm *t) control = ds1307->regs[7]; status = ds1307->regs[8]; - dev_dbg(dev, "%s: %02x %02x %02x %02x, %02x %02x %02x, %02x %02x\n", - "alarm set (old status)", - ds1307->regs[0], ds1307->regs[1], - ds1307->regs[2], ds1307->regs[3], - ds1307->regs[4], ds1307->regs[5], - ds1307->regs[6], control, status); + dev_dbg(dev, "%s: %4ph, %3ph, %02x %02x\n", "alarm set (old status)", + &ds1307->regs[0], &ds1307->regs[4], control, status); /* set ALARM1, using 24 hour and day-of-month modes */ buf[0] = bin2bcd(t->time.tm_sec); diff --git a/drivers/rtc/rtc-ds1685.c b/drivers/rtc/rtc-ds1685.c index 05a51ef52703..5038122aa8de 100644 --- a/drivers/rtc/rtc-ds1685.c +++ b/drivers/rtc/rtc-ds1685.c @@ -853,7 +853,7 @@ ds1685_rtc_proc(struct device *dev, struct seq_file *seq) "Periodic Rate\t: %s\n" "SQW Freq\t: %s\n" #ifdef CONFIG_RTC_DS1685_PROC_REGS - "Serial #\t: %02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x\n" + "Serial #\t: %8phC\n" "Register Status\t:\n" " Ctrl A\t: UIP DV2 DV1 DV0 RS3 RS2 RS1 RS0\n" "\t\t: %s\n" @@ -872,7 +872,7 @@ ds1685_rtc_proc(struct device *dev, struct seq_file *seq) " Ctrl 4B\t: ABE E32k CS RCE PRS RIE WIE KSE\n" "\t\t: %s\n", #else - "Serial #\t: %02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x\n", + "Serial #\t: %8phC\n", #endif model, ((ctrla & RTC_CTRL_A_DV1) ? "enabled" : "disabled"), @@ -888,7 +888,7 @@ ds1685_rtc_proc(struct device *dev, struct seq_file *seq) (!((ctrl4b & RTC_CTRL_4B_E32K)) ? ds1685_rtc_sqw_freq[(ctrla & RTC_CTRL_A_RS_MASK)] : "32768Hz"), #ifdef CONFIG_RTC_DS1685_PROC_REGS - ssn[0], ssn[1], ssn[2], ssn[3], ssn[4], ssn[5], ssn[6], ssn[7], + ssn, ds1685_rtc_print_regs(ctrla, bits[0]), ds1685_rtc_print_regs(ctrlb, bits[1]), ds1685_rtc_print_regs(ctrlc, bits[2]), @@ -896,7 +896,7 @@ ds1685_rtc_proc(struct device *dev, struct seq_file *seq) ds1685_rtc_print_regs(ctrl4a, bits[4]), ds1685_rtc_print_regs(ctrl4b, bits[5])); #else - ssn[0], ssn[1], ssn[2], ssn[3], ssn[4], ssn[5], ssn[6], ssn[7]); + ssn); #endif return 0; } @@ -1160,9 +1160,7 @@ ds1685_rtc_sysfs_serial_show(struct device *dev, ds1685_rtc_get_ssn(rtc, ssn); ds1685_rtc_switch_to_bank0(rtc); - return snprintf(buf, 24, "%02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x\n", - ssn[0], ssn[1], ssn[2], ssn[3], ssn[4], ssn[5], - ssn[6], ssn[7]); + return snprintf(buf, 24, "%8phC\n", ssn); return 0; } -- cgit v1.2.3 From 9c25a106c0dfc1656a147663c353e3805e6165da Mon Sep 17 00:00:00 2001 From: Rasmus Villemoes Date: Tue, 24 Nov 2015 14:51:24 +0100 Subject: rtc: ds1685: don't try to micromanage sysfs output size ...and don't do it wrong. "not ok or N/A" has length 13. Add the trailing newline, and the snprintf return value will be 14. However, we lied to snprintf and told it that only 13 bytes were available. Hence snprintf has only written "not ok or N/" and a trailing '\0' to the buffer. Next we continue lying, this time to the upper sysfs layer, claiming that we wrote 14 meaningful bytes to the buffer. That'll make the upper layer copy "not ok or N/" plus two nul bytes to user space (one nul byte from snprintf, the other since sysfs takes care to clear the buffer before giving it to the ->show method). In the other cases, the claimed buffer size is closer to sufficient, but we'll still get a nul byte instead of a newline written to user space. There's absolutely no reason to try to predict the output size, and there's plenty of room in the buffer, so just use sprintf. Signed-off-by: Rasmus Villemoes Signed-off-by: Alexandre Belloni --- drivers/rtc/rtc-ds1685.c | 12 +++++------- 1 file changed, 5 insertions(+), 7 deletions(-) (limited to 'drivers/rtc') diff --git a/drivers/rtc/rtc-ds1685.c b/drivers/rtc/rtc-ds1685.c index 5038122aa8de..535050fc5e9f 100644 --- a/drivers/rtc/rtc-ds1685.c +++ b/drivers/rtc/rtc-ds1685.c @@ -1114,7 +1114,7 @@ ds1685_rtc_sysfs_battery_show(struct device *dev, ctrld = rtc->read(rtc, RTC_CTRL_D); - return snprintf(buf, 13, "%s\n", + return sprintf(buf, "%s\n", (ctrld & RTC_CTRL_D_VRT) ? "ok" : "not ok or N/A"); } static DEVICE_ATTR(battery, S_IRUGO, ds1685_rtc_sysfs_battery_show, NULL); @@ -1137,7 +1137,7 @@ ds1685_rtc_sysfs_auxbatt_show(struct device *dev, ctrl4a = rtc->read(rtc, RTC_EXT_CTRL_4A); ds1685_rtc_switch_to_bank0(rtc); - return snprintf(buf, 13, "%s\n", + return sprintf(buf, "%s\n", (ctrl4a & RTC_CTRL_4A_VRT2) ? "ok" : "not ok or N/A"); } static DEVICE_ATTR(auxbatt, S_IRUGO, ds1685_rtc_sysfs_auxbatt_show, NULL); @@ -1160,9 +1160,7 @@ ds1685_rtc_sysfs_serial_show(struct device *dev, ds1685_rtc_get_ssn(rtc, ssn); ds1685_rtc_switch_to_bank0(rtc); - return snprintf(buf, 24, "%8phC\n", ssn); - - return 0; + return sprintf(buf, "%8phC\n", ssn); } static DEVICE_ATTR(serial, S_IRUGO, ds1685_rtc_sysfs_serial_show, NULL); @@ -1285,7 +1283,7 @@ ds1685_rtc_sysfs_ctrl_regs_show(struct device *dev, tmp = rtc->read(rtc, reg_info->reg) & reg_info->bit; ds1685_rtc_switch_to_bank0(rtc); - return snprintf(buf, 2, "%d\n", (tmp ? 1 : 0)); + return sprintf(buf, "%d\n", (tmp ? 1 : 0)); } /** @@ -1621,7 +1619,7 @@ ds1685_rtc_sysfs_time_regs_show(struct device *dev, tmp = ds1685_rtc_bcd2bin(rtc, tmp, bcd_reg_info->mask, bin_reg_info->mask); - return snprintf(buf, 4, "%d\n", tmp); + return sprintf(buf, "%d\n", tmp); } /** -- cgit v1.2.3 From d5878a869fe8c272d3a843a47ef0716c91ba3e25 Mon Sep 17 00:00:00 2001 From: Colin Ian King Date: Sat, 28 Nov 2015 16:38:40 +0000 Subject: rtc: imxdi: fix spelling mistake in warning message Minor issue, fix spelling mistake, happend -> happened Signed-off-by: Colin Ian King Signed-off-by: Alexandre Belloni --- drivers/rtc/rtc-imxdi.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/rtc') diff --git a/drivers/rtc/rtc-imxdi.c b/drivers/rtc/rtc-imxdi.c index 7bffd7f0e306..8d8049bdfaf6 100644 --- a/drivers/rtc/rtc-imxdi.c +++ b/drivers/rtc/rtc-imxdi.c @@ -303,7 +303,7 @@ static int di_handle_invalid_state(struct imxdi_dev *imxdi, u32 dsr) sec = readl(imxdi->ioaddr + DTCMR); if (sec != 0) dev_warn(&imxdi->pdev->dev, - "The security violation has happend at %u seconds\n", + "The security violation has happened at %u seconds\n", sec); /* * the timer cannot be set/modified if -- cgit v1.2.3 From 529af7d1982562eafdc01760d44d990c7e3dcd82 Mon Sep 17 00:00:00 2001 From: Vladimir Zapolskiy Date: Wed, 2 Dec 2015 08:10:28 +0200 Subject: rtc: lpc32xx: remove irq > NR_IRQS check from probe() If the driver is used on an ARM platform with SPARSE_IRQ defined, semantics of NR_IRQS is different (minimal value of virtual irqs) and by default it is set to 16, see arch/arm/include/asm/irq.h. This value may be less than the actual number of virtual irqs, which may break the driver initialization. The check removal allows to use the driver on such a platform, and, if irq controller driver works correctly, the check is not needed on legacy platforms. Fixes a runtime problem: rtc-lpc32xx 40024000.rtc: Can't get interrupt resource Signed-off-by: Vladimir Zapolskiy Signed-off-by: Alexandre Belloni --- drivers/rtc/rtc-lpc32xx.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/rtc') diff --git a/drivers/rtc/rtc-lpc32xx.c b/drivers/rtc/rtc-lpc32xx.c index f923f7324788..887871c3d526 100644 --- a/drivers/rtc/rtc-lpc32xx.c +++ b/drivers/rtc/rtc-lpc32xx.c @@ -205,7 +205,7 @@ static int lpc32xx_rtc_probe(struct platform_device *pdev) u32 tmp; rtcirq = platform_get_irq(pdev, 0); - if (rtcirq < 0 || rtcirq >= NR_IRQS) { + if (rtcirq < 0) { dev_warn(&pdev->dev, "Can't get interrupt resource\n"); rtcirq = -1; } -- cgit v1.2.3 From ed13d89b08e392cd347aaa54ddc17f7d3e26b175 Mon Sep 17 00:00:00 2001 From: Akshay Bhat Date: Thu, 3 Dec 2015 14:41:21 -0500 Subject: rtc: Add Epson RX8010SJ RTC driver This driver supports the following functions: - reading and setting time - alarms when connected to an IRQ - reading and clearing the voltage low flags Datasheet: http://www.epsondevice.com/docs/qd/en/DownloadServlet?id=ID000956 Signed-off-by: Akshay Bhat Signed-off-by: Alexandre Belloni --- drivers/rtc/Kconfig | 10 + drivers/rtc/Makefile | 1 + drivers/rtc/rtc-rx8010.c | 523 +++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 534 insertions(+) create mode 100644 drivers/rtc/rtc-rx8010.c (limited to 'drivers/rtc') diff --git a/drivers/rtc/Kconfig b/drivers/rtc/Kconfig index 2a524244afec..376322f71fd5 100644 --- a/drivers/rtc/Kconfig +++ b/drivers/rtc/Kconfig @@ -558,6 +558,16 @@ config RTC_DRV_FM3130 This driver can also be built as a module. If so the module will be called rtc-fm3130. +config RTC_DRV_RX8010 + tristate "Epson RX8010SJ" + depends on I2C + help + If you say yes here you get support for the Epson RX8010SJ RTC + chip. + + This driver can also be built as a module. If so, the module + will be called rtc-rx8010. + config RTC_DRV_RX8581 tristate "Epson RX-8581" help diff --git a/drivers/rtc/Makefile b/drivers/rtc/Makefile index 231f76451615..62d61b26ca7e 100644 --- a/drivers/rtc/Makefile +++ b/drivers/rtc/Makefile @@ -128,6 +128,7 @@ obj-$(CONFIG_RTC_DRV_RS5C372) += rtc-rs5c372.o obj-$(CONFIG_RTC_DRV_RV3029C2) += rtc-rv3029c2.o obj-$(CONFIG_RTC_DRV_RV8803) += rtc-rv8803.o obj-$(CONFIG_RTC_DRV_RX4581) += rtc-rx4581.o +obj-$(CONFIG_RTC_DRV_RX8010) += rtc-rx8010.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-rx8010.c b/drivers/rtc/rtc-rx8010.c new file mode 100644 index 000000000000..772d221ec2d9 --- /dev/null +++ b/drivers/rtc/rtc-rx8010.c @@ -0,0 +1,523 @@ +/* + * Driver for the Epson RTC module RX-8010 SJ + * + * Copyright(C) Timesys Corporation 2015 + * Copyright(C) General Electric Company 2015 + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + */ + +#include +#include +#include +#include +#include +#include + +#define RX8010_SEC 0x10 +#define RX8010_MIN 0x11 +#define RX8010_HOUR 0x12 +#define RX8010_WDAY 0x13 +#define RX8010_MDAY 0x14 +#define RX8010_MONTH 0x15 +#define RX8010_YEAR 0x16 +#define RX8010_YEAR 0x16 +#define RX8010_RESV17 0x17 +#define RX8010_ALMIN 0x18 +#define RX8010_ALHOUR 0x19 +#define RX8010_ALWDAY 0x1A +#define RX8010_TCOUNT0 0x1B +#define RX8010_TCOUNT1 0x1C +#define RX8010_EXT 0x1D +#define RX8010_FLAG 0x1E +#define RX8010_CTRL 0x1F +/* 0x20 to 0x2F are user registers */ +#define RX8010_RESV30 0x30 +#define RX8010_RESV31 0x32 +#define RX8010_IRQ 0x32 + +#define RX8010_EXT_WADA BIT(3) + +#define RX8010_FLAG_VLF BIT(1) +#define RX8010_FLAG_AF BIT(3) +#define RX8010_FLAG_TF BIT(4) +#define RX8010_FLAG_UF BIT(5) + +#define RX8010_CTRL_AIE BIT(3) +#define RX8010_CTRL_UIE BIT(5) +#define RX8010_CTRL_STOP BIT(6) +#define RX8010_CTRL_TEST BIT(7) + +#define RX8010_ALARM_AE BIT(7) + +static const struct i2c_device_id rx8010_id[] = { + { "rx8010", 0 }, + { } +}; +MODULE_DEVICE_TABLE(i2c, rx8010_id); + +struct rx8010_data { + struct i2c_client *client; + struct rtc_device *rtc; + u8 ctrlreg; + spinlock_t flags_lock; +}; + +static irqreturn_t rx8010_irq_1_handler(int irq, void *dev_id) +{ + struct i2c_client *client = dev_id; + struct rx8010_data *rx8010 = i2c_get_clientdata(client); + int flagreg; + + spin_lock(&rx8010->flags_lock); + + flagreg = i2c_smbus_read_byte_data(client, RX8010_FLAG); + + if (flagreg <= 0) { + spin_unlock(&rx8010->flags_lock); + return IRQ_NONE; + } + + if (flagreg & RX8010_FLAG_VLF) + dev_warn(&client->dev, "Frequency stop detected\n"); + + if (flagreg & RX8010_FLAG_TF) { + flagreg &= ~RX8010_FLAG_TF; + rtc_update_irq(rx8010->rtc, 1, RTC_PF | RTC_IRQF); + } + + if (flagreg & RX8010_FLAG_AF) { + flagreg &= ~RX8010_FLAG_AF; + rtc_update_irq(rx8010->rtc, 1, RTC_AF | RTC_IRQF); + } + + if (flagreg & RX8010_FLAG_UF) { + flagreg &= ~RX8010_FLAG_UF; + rtc_update_irq(rx8010->rtc, 1, RTC_UF | RTC_IRQF); + } + + i2c_smbus_write_byte_data(client, RX8010_FLAG, flagreg); + + spin_unlock(&rx8010->flags_lock); + return IRQ_HANDLED; +} + +static int rx8010_get_time(struct device *dev, struct rtc_time *dt) +{ + struct rx8010_data *rx8010 = dev_get_drvdata(dev); + u8 date[7]; + int flagreg; + int err; + + flagreg = i2c_smbus_read_byte_data(rx8010->client, RX8010_FLAG); + if (flagreg < 0) + return flagreg; + + if (flagreg & RX8010_FLAG_VLF) { + dev_warn(dev, "Frequency stop detected\n"); + return -EINVAL; + } + + err = i2c_smbus_read_i2c_block_data(rx8010->client, RX8010_SEC, + 7, date); + if (err != 7) + return err < 0 ? err : -EIO; + + dt->tm_sec = bcd2bin(date[RX8010_SEC - RX8010_SEC] & 0x7f); + dt->tm_min = bcd2bin(date[RX8010_MIN - RX8010_SEC] & 0x7f); + dt->tm_hour = bcd2bin(date[RX8010_HOUR - RX8010_SEC] & 0x3f); + dt->tm_mday = bcd2bin(date[RX8010_MDAY - RX8010_SEC] & 0x3f); + dt->tm_mon = bcd2bin(date[RX8010_MONTH - RX8010_SEC] & 0x1f) - 1; + dt->tm_year = bcd2bin(date[RX8010_YEAR - RX8010_SEC]) + 100; + dt->tm_wday = ffs(date[RX8010_WDAY - RX8010_SEC] & 0x7f); + + return rtc_valid_tm(dt); +} + +static int rx8010_set_time(struct device *dev, struct rtc_time *dt) +{ + struct rx8010_data *rx8010 = dev_get_drvdata(dev); + u8 date[7]; + int ctrl, flagreg; + int ret; + unsigned long irqflags; + + if ((dt->tm_year < 100) || (dt->tm_year > 199)) + return -EINVAL; + + /* set STOP bit before changing clock/calendar */ + ctrl = i2c_smbus_read_byte_data(rx8010->client, RX8010_CTRL); + if (ctrl < 0) + return ctrl; + rx8010->ctrlreg = ctrl | RX8010_CTRL_STOP; + ret = i2c_smbus_write_byte_data(rx8010->client, RX8010_CTRL, + rx8010->ctrlreg); + if (ret < 0) + return ret; + + date[RX8010_SEC - RX8010_SEC] = bin2bcd(dt->tm_sec); + date[RX8010_MIN - RX8010_SEC] = bin2bcd(dt->tm_min); + date[RX8010_HOUR - RX8010_SEC] = bin2bcd(dt->tm_hour); + date[RX8010_MDAY - RX8010_SEC] = bin2bcd(dt->tm_mday); + date[RX8010_MONTH - RX8010_SEC] = bin2bcd(dt->tm_mon + 1); + date[RX8010_YEAR - RX8010_SEC] = bin2bcd(dt->tm_year - 100); + date[RX8010_WDAY - RX8010_SEC] = bin2bcd(1 << dt->tm_wday); + + ret = i2c_smbus_write_i2c_block_data(rx8010->client, + RX8010_SEC, 7, date); + if (ret < 0) + return ret; + + /* clear STOP bit after changing clock/calendar */ + ctrl = i2c_smbus_read_byte_data(rx8010->client, RX8010_CTRL); + if (ctrl < 0) + return ctrl; + rx8010->ctrlreg = ctrl & ~RX8010_CTRL_STOP; + ret = i2c_smbus_write_byte_data(rx8010->client, RX8010_CTRL, + rx8010->ctrlreg); + if (ret < 0) + return ret; + + spin_lock_irqsave(&rx8010->flags_lock, irqflags); + + flagreg = i2c_smbus_read_byte_data(rx8010->client, RX8010_FLAG); + if (flagreg < 0) { + spin_unlock_irqrestore(&rx8010->flags_lock, irqflags); + return flagreg; + } + + if (flagreg & RX8010_FLAG_VLF) + ret = i2c_smbus_write_byte_data(rx8010->client, RX8010_FLAG, + flagreg & ~RX8010_FLAG_VLF); + + spin_unlock_irqrestore(&rx8010->flags_lock, irqflags); + + return 0; +} + +static int rx8010_init_client(struct i2c_client *client) +{ + struct rx8010_data *rx8010 = i2c_get_clientdata(client); + u8 ctrl[2]; + int need_clear = 0, err = 0; + + /* Initialize reserved registers as specified in datasheet */ + err = i2c_smbus_write_byte_data(client, RX8010_RESV17, 0xD8); + if (err < 0) + return err; + + err = i2c_smbus_write_byte_data(client, RX8010_RESV30, 0x00); + if (err < 0) + return err; + + err = i2c_smbus_write_byte_data(client, RX8010_RESV31, 0x08); + if (err < 0) + return err; + + err = i2c_smbus_write_byte_data(client, RX8010_IRQ, 0x00); + if (err < 0) + return err; + + err = i2c_smbus_read_i2c_block_data(rx8010->client, RX8010_FLAG, + 2, ctrl); + if (err != 2) + return err < 0 ? err : -EIO; + + if (ctrl[0] & RX8010_FLAG_VLF) + dev_warn(&client->dev, "Frequency stop was detected\n"); + + if (ctrl[0] & RX8010_FLAG_AF) { + dev_warn(&client->dev, "Alarm was detected\n"); + need_clear = 1; + } + + if (ctrl[0] & RX8010_FLAG_TF) + need_clear = 1; + + if (ctrl[0] & RX8010_FLAG_UF) + need_clear = 1; + + if (need_clear) { + ctrl[0] &= ~(RX8010_FLAG_AF | RX8010_FLAG_TF | RX8010_FLAG_UF); + err = i2c_smbus_write_byte_data(client, RX8010_FLAG, ctrl[0]); + if (err < 0) + return err; + } + + rx8010->ctrlreg = (ctrl[1] & ~RX8010_CTRL_TEST); + + return err; +} + +static int rx8010_read_alarm(struct device *dev, struct rtc_wkalrm *t) +{ + struct rx8010_data *rx8010 = dev_get_drvdata(dev); + struct i2c_client *client = rx8010->client; + u8 alarmvals[3]; + int flagreg; + int err; + + err = i2c_smbus_read_i2c_block_data(client, RX8010_ALMIN, 3, alarmvals); + if (err != 3) + return err < 0 ? err : -EIO; + + flagreg = i2c_smbus_read_byte_data(client, RX8010_FLAG); + if (flagreg < 0) + return flagreg; + + t->time.tm_sec = 0; + t->time.tm_min = bcd2bin(alarmvals[0] & 0x7f); + t->time.tm_hour = bcd2bin(alarmvals[1] & 0x3f); + + if (alarmvals[2] & RX8010_ALARM_AE) + t->time.tm_mday = -1; + else + t->time.tm_mday = bcd2bin(alarmvals[2] & 0x7f); + + t->time.tm_wday = -1; + t->time.tm_mon = -1; + t->time.tm_year = -1; + + t->enabled = !!(rx8010->ctrlreg & RX8010_CTRL_AIE); + t->pending = (flagreg & RX8010_FLAG_AF) && t->enabled; + + return err; +} + +static int rx8010_set_alarm(struct device *dev, struct rtc_wkalrm *t) +{ + struct i2c_client *client = to_i2c_client(dev); + struct rx8010_data *rx8010 = dev_get_drvdata(dev); + u8 alarmvals[3]; + int extreg, flagreg; + int err; + unsigned long irqflags; + + spin_lock_irqsave(&rx8010->flags_lock, irqflags); + flagreg = i2c_smbus_read_byte_data(client, RX8010_FLAG); + if (flagreg < 0) { + spin_unlock_irqrestore(&rx8010->flags_lock, irqflags); + return flagreg; + } + + if (rx8010->ctrlreg & (RX8010_CTRL_AIE | RX8010_CTRL_UIE)) { + rx8010->ctrlreg &= ~(RX8010_CTRL_AIE | RX8010_CTRL_UIE); + err = i2c_smbus_write_byte_data(rx8010->client, RX8010_CTRL, + rx8010->ctrlreg); + if (err < 0) { + spin_unlock_irqrestore(&rx8010->flags_lock, irqflags); + return err; + } + } + + flagreg &= ~RX8010_FLAG_AF; + err = i2c_smbus_write_byte_data(rx8010->client, RX8010_FLAG, flagreg); + spin_unlock_irqrestore(&rx8010->flags_lock, irqflags); + if (err < 0) + return err; + + alarmvals[0] = bin2bcd(t->time.tm_min); + alarmvals[1] = bin2bcd(t->time.tm_hour); + alarmvals[2] = bin2bcd(t->time.tm_mday); + + err = i2c_smbus_write_i2c_block_data(rx8010->client, RX8010_ALMIN, + 2, alarmvals); + if (err < 0) + return err; + + extreg = i2c_smbus_read_byte_data(client, RX8010_EXT); + if (extreg < 0) + return extreg; + + extreg |= RX8010_EXT_WADA; + err = i2c_smbus_write_byte_data(rx8010->client, RX8010_EXT, extreg); + if (err < 0) + return err; + + if (alarmvals[2] == 0) + alarmvals[2] |= RX8010_ALARM_AE; + + err = i2c_smbus_write_byte_data(rx8010->client, RX8010_ALWDAY, + alarmvals[2]); + if (err < 0) + return err; + + if (t->enabled) { + if (rx8010->rtc->uie_rtctimer.enabled) + rx8010->ctrlreg |= RX8010_CTRL_UIE; + if (rx8010->rtc->aie_timer.enabled) + rx8010->ctrlreg |= + (RX8010_CTRL_AIE | RX8010_CTRL_UIE); + + err = i2c_smbus_write_byte_data(rx8010->client, RX8010_CTRL, + rx8010->ctrlreg); + if (err < 0) + return err; + } + + return 0; +} + +static int rx8010_alarm_irq_enable(struct device *dev, + unsigned int enabled) +{ + struct i2c_client *client = to_i2c_client(dev); + struct rx8010_data *rx8010 = dev_get_drvdata(dev); + int flagreg; + u8 ctrl; + int err; + + ctrl = rx8010->ctrlreg; + + if (enabled) { + if (rx8010->rtc->uie_rtctimer.enabled) + ctrl |= RX8010_CTRL_UIE; + if (rx8010->rtc->aie_timer.enabled) + ctrl |= (RX8010_CTRL_AIE | RX8010_CTRL_UIE); + } else { + if (!rx8010->rtc->uie_rtctimer.enabled) + ctrl &= ~RX8010_CTRL_UIE; + if (!rx8010->rtc->aie_timer.enabled) + ctrl &= ~RX8010_CTRL_AIE; + } + + flagreg = i2c_smbus_read_byte_data(client, RX8010_FLAG); + if (flagreg < 0) + return flagreg; + + flagreg &= ~RX8010_FLAG_AF; + err = i2c_smbus_write_byte_data(rx8010->client, RX8010_FLAG, flagreg); + if (err < 0) + return err; + + if (ctrl != rx8010->ctrlreg) { + rx8010->ctrlreg = ctrl; + err = i2c_smbus_write_byte_data(rx8010->client, RX8010_CTRL, + rx8010->ctrlreg); + if (err < 0) + return err; + } + + return 0; +} + +static int rx8010_ioctl(struct device *dev, unsigned int cmd, unsigned long arg) +{ + struct i2c_client *client = to_i2c_client(dev); + struct rx8010_data *rx8010 = dev_get_drvdata(dev); + int ret, tmp; + int flagreg; + unsigned long irqflags; + + switch (cmd) { + case RTC_VL_READ: + flagreg = i2c_smbus_read_byte_data(rx8010->client, RX8010_FLAG); + if (flagreg < 0) + return flagreg; + + tmp = !!(flagreg & RX8010_FLAG_VLF); + if (copy_to_user((void __user *)arg, &tmp, sizeof(int))) + return -EFAULT; + + return 0; + + case RTC_VL_CLR: + spin_lock_irqsave(&rx8010->flags_lock, irqflags); + flagreg = i2c_smbus_read_byte_data(rx8010->client, RX8010_FLAG); + if (flagreg < 0) { + spin_unlock_irqrestore(&rx8010->flags_lock, irqflags); + return flagreg; + } + + flagreg &= ~RX8010_FLAG_VLF; + ret = i2c_smbus_write_byte_data(client, RX8010_FLAG, flagreg); + spin_unlock_irqrestore(&rx8010->flags_lock, irqflags); + if (ret < 0) + return ret; + + return 0; + + default: + return -ENOIOCTLCMD; + } +} + +static struct rtc_class_ops rx8010_rtc_ops = { + .read_time = rx8010_get_time, + .set_time = rx8010_set_time, + .ioctl = rx8010_ioctl, +}; + +static int rx8010_probe(struct i2c_client *client, + const struct i2c_device_id *id) +{ + struct i2c_adapter *adapter = to_i2c_adapter(client->dev.parent); + struct rx8010_data *rx8010; + int err = 0; + + if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA + | I2C_FUNC_SMBUS_I2C_BLOCK)) { + dev_err(&adapter->dev, "doesn't support required functionality\n"); + return -EIO; + } + + rx8010 = devm_kzalloc(&client->dev, sizeof(struct rx8010_data), + GFP_KERNEL); + if (!rx8010) + return -ENOMEM; + + rx8010->client = client; + i2c_set_clientdata(client, rx8010); + + spin_lock_init(&rx8010->flags_lock); + + err = rx8010_init_client(client); + if (err) + return err; + + if (client->irq > 0) { + dev_info(&client->dev, "IRQ %d supplied\n", client->irq); + err = devm_request_threaded_irq(&client->dev, client->irq, NULL, + rx8010_irq_1_handler, + IRQF_TRIGGER_LOW | IRQF_ONESHOT, + "rx8010", client); + + if (err) { + dev_err(&client->dev, "unable to request IRQ\n"); + client->irq = 0; + } else { + rx8010_rtc_ops.read_alarm = rx8010_read_alarm; + rx8010_rtc_ops.set_alarm = rx8010_set_alarm; + rx8010_rtc_ops.alarm_irq_enable = rx8010_alarm_irq_enable; + } + } + + rx8010->rtc = devm_rtc_device_register(&client->dev, client->name, + &rx8010_rtc_ops, THIS_MODULE); + + if (IS_ERR(rx8010->rtc)) { + dev_err(&client->dev, "unable to register the class device\n"); + return PTR_ERR(rx8010->rtc); + } + + rx8010->rtc->max_user_freq = 1; + + return err; +} + +static struct i2c_driver rx8010_driver = { + .driver = { + .name = "rtc-rx8010", + }, + .probe = rx8010_probe, + .id_table = rx8010_id, +}; + +module_i2c_driver(rx8010_driver); + +MODULE_AUTHOR("Akshay Bhat "); +MODULE_DESCRIPTION("Epson RX8010SJ RTC driver"); +MODULE_LICENSE("GPL v2"); -- cgit v1.2.3 From 68c85f2916222b15556ca44e2da0ee94f61f02da Mon Sep 17 00:00:00 2001 From: Andrzej Hajda Date: Thu, 10 Dec 2015 08:55:33 +0100 Subject: rtc: rv8803: fix handling return value of i2c_smbus_read_byte_data The function can return negative values, so its result should be assigned to signed variable. The problem has been detected using proposed semantic patch scripts/coccinelle/tests/assign_signed_to_unsigned.cocci [1]. [1]: http://permalink.gmane.org/gmane.linux.kernel/2046107 Signed-off-by: Andrzej Hajda Signed-off-by: Alexandre Belloni --- drivers/rtc/rtc-rv8803.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/rtc') diff --git a/drivers/rtc/rtc-rv8803.c b/drivers/rtc/rtc-rv8803.c index e7329e21bfe3..f883aa266d0c 100644 --- a/drivers/rtc/rtc-rv8803.c +++ b/drivers/rtc/rtc-rv8803.c @@ -61,7 +61,7 @@ static irqreturn_t rv8803_handle_irq(int irq, void *dev_id) struct i2c_client *client = dev_id; struct rv8803_data *rv8803 = i2c_get_clientdata(client); unsigned long events = 0; - u8 flags; + int flags; spin_lock(&rv8803->flags_lock); -- cgit v1.2.3 From 78ef5f2d2d8c9234d80b4e01e8b736e7241cd5ce Mon Sep 17 00:00:00 2001 From: Gregory CLEMENT Date: Fri, 11 Dec 2015 12:43:05 +0100 Subject: rtc: rv8803: Extend compatibility with the rx8900 The Seiko Epson's RTC RX8900 layout register is compatible with the RV8803. So let's add its ID in order to reuse the same driver. Signed-off-by: Gregory CLEMENT Signed-off-by: Alexandre Belloni --- drivers/rtc/rtc-rv8803.c | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers/rtc') diff --git a/drivers/rtc/rtc-rv8803.c b/drivers/rtc/rtc-rv8803.c index f883aa266d0c..7155c0816aa6 100644 --- a/drivers/rtc/rtc-rv8803.c +++ b/drivers/rtc/rtc-rv8803.c @@ -502,6 +502,7 @@ static int rv8803_remove(struct i2c_client *client) static const struct i2c_device_id rv8803_id[] = { { "rv8803", 0 }, + { "rx8900", 0 }, { } }; MODULE_DEVICE_TABLE(i2c, rv8803_id); -- cgit v1.2.3 From 7432a850b5139b24b9288416a2ae796e4da295d6 Mon Sep 17 00:00:00 2001 From: Julia Lawall Date: Fri, 11 Dec 2015 18:50:50 +0100 Subject: rtc: v3020: constify v3020_chip_ops structures The v3020_chip_ops structures are never modified, so declare them as const. Done with the help of Coccinelle. Signed-off-by: Julia Lawall Signed-off-by: Alexandre Belloni --- drivers/rtc/rtc-v3020.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'drivers/rtc') diff --git a/drivers/rtc/rtc-v3020.c b/drivers/rtc/rtc-v3020.c index f9f97098c254..7a0436329d6c 100644 --- a/drivers/rtc/rtc-v3020.c +++ b/drivers/rtc/rtc-v3020.c @@ -57,7 +57,7 @@ struct v3020 { /* GPIO access */ struct gpio *gpio; - struct v3020_chip_ops *ops; + const struct v3020_chip_ops *ops; struct rtc_device *rtc; }; @@ -95,7 +95,7 @@ static unsigned char v3020_mmio_read_bit(struct v3020 *chip) return !!(readl(chip->ioaddress) & (1 << chip->leftshift)); } -static struct v3020_chip_ops v3020_mmio_ops = { +static const struct v3020_chip_ops v3020_mmio_ops = { .map_io = v3020_mmio_map, .unmap_io = v3020_mmio_unmap, .read_bit = v3020_mmio_read_bit, @@ -158,7 +158,7 @@ static unsigned char v3020_gpio_read_bit(struct v3020 *chip) return bit; } -static struct v3020_chip_ops v3020_gpio_ops = { +static const struct v3020_chip_ops v3020_gpio_ops = { .map_io = v3020_gpio_map, .unmap_io = v3020_gpio_unmap, .read_bit = v3020_gpio_read_bit, -- cgit v1.2.3 From fca733a14ea549dbc4f759578704c48f5fb0ab45 Mon Sep 17 00:00:00 2001 From: Alexandre Belloni Date: Thu, 17 Dec 2015 00:36:21 +0100 Subject: rtc: abx80x: Add Microcrystal rv1805 support Microcrystal RV-1805 is compatible with Abracon 1805. Signed-off-by: Alexandre Belloni --- drivers/rtc/rtc-abx80x.c | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers/rtc') diff --git a/drivers/rtc/rtc-abx80x.c b/drivers/rtc/rtc-abx80x.c index afea84c7a155..203e6616d413 100644 --- a/drivers/rtc/rtc-abx80x.c +++ b/drivers/rtc/rtc-abx80x.c @@ -286,6 +286,7 @@ static const struct i2c_device_id abx80x_id[] = { { "ab1803", AB1803 }, { "ab1804", AB1804 }, { "ab1805", AB1805 }, + { "rv1805", AB1805 }, { } }; MODULE_DEVICE_TABLE(i2c, abx80x_id); -- cgit v1.2.3 From 718a820a303ca60645ab703451ecfebf045c896b Mon Sep 17 00:00:00 2001 From: Alexandre Belloni Date: Thu, 17 Dec 2015 00:36:22 +0100 Subject: rtc: abx80x: add alarm support Add alarm support to the abx80x driver. Signed-off-by: Alexandre Belloni --- drivers/rtc/rtc-abx80x.c | 145 +++++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 141 insertions(+), 4 deletions(-) (limited to 'drivers/rtc') diff --git a/drivers/rtc/rtc-abx80x.c b/drivers/rtc/rtc-abx80x.c index 203e6616d413..d41bbcd653f6 100644 --- a/drivers/rtc/rtc-abx80x.c +++ b/drivers/rtc/rtc-abx80x.c @@ -27,10 +27,28 @@ #define ABX8XX_REG_YR 0x06 #define ABX8XX_REG_WD 0x07 +#define ABX8XX_REG_AHTH 0x08 +#define ABX8XX_REG_ASC 0x09 +#define ABX8XX_REG_AMN 0x0a +#define ABX8XX_REG_AHR 0x0b +#define ABX8XX_REG_ADA 0x0c +#define ABX8XX_REG_AMO 0x0d +#define ABX8XX_REG_AWD 0x0e + +#define ABX8XX_REG_STATUS 0x0f +#define ABX8XX_STATUS_AF BIT(2) + #define ABX8XX_REG_CTRL1 0x10 #define ABX8XX_CTRL_WRITE BIT(0) +#define ABX8XX_CTRL_ARST BIT(2) #define ABX8XX_CTRL_12_24 BIT(6) +#define ABX8XX_REG_IRQ 0x12 +#define ABX8XX_IRQ_AIE BIT(2) +#define ABX8XX_IRQ_IM_1_4 (0x3 << 5) + +#define ABX8XX_REG_CD_TIMER_CTL 0x18 + #define ABX8XX_REG_CFG_KEY 0x1f #define ABX8XX_CFG_KEY_MISC 0x9d @@ -63,8 +81,6 @@ static struct abx80x_cap abx80x_caps[] = { [ABX80X] = {.pn = 0} }; -static struct i2c_driver abx80x_driver; - static int abx80x_enable_trickle_charger(struct i2c_client *client, u8 trickle_cfg) { @@ -148,9 +164,111 @@ static int abx80x_rtc_set_time(struct device *dev, struct rtc_time *tm) return 0; } +static irqreturn_t abx80x_handle_irq(int irq, void *dev_id) +{ + struct i2c_client *client = dev_id; + struct rtc_device *rtc = i2c_get_clientdata(client); + int status; + + status = i2c_smbus_read_byte_data(client, ABX8XX_REG_STATUS); + if (status < 0) + return IRQ_NONE; + + if (status & ABX8XX_STATUS_AF) + rtc_update_irq(rtc, 1, RTC_AF | RTC_IRQF); + + i2c_smbus_write_byte_data(client, ABX8XX_REG_STATUS, 0); + + return IRQ_HANDLED; +} + +static int abx80x_read_alarm(struct device *dev, struct rtc_wkalrm *t) +{ + struct i2c_client *client = to_i2c_client(dev); + unsigned char buf[7]; + + int irq_mask, err; + + if (client->irq <= 0) + return -EINVAL; + + err = i2c_smbus_read_i2c_block_data(client, ABX8XX_REG_ASC, + sizeof(buf), buf); + if (err) + return err; + + irq_mask = i2c_smbus_read_byte_data(client, ABX8XX_REG_IRQ); + if (irq_mask < 0) + return irq_mask; + + t->time.tm_sec = bcd2bin(buf[0] & 0x7F); + t->time.tm_min = bcd2bin(buf[1] & 0x7F); + t->time.tm_hour = bcd2bin(buf[2] & 0x3F); + t->time.tm_mday = bcd2bin(buf[3] & 0x3F); + t->time.tm_mon = bcd2bin(buf[4] & 0x1F) - 1; + t->time.tm_wday = buf[5] & 0x7; + + t->enabled = !!(irq_mask & ABX8XX_IRQ_AIE); + t->pending = (buf[6] & ABX8XX_STATUS_AF) && t->enabled; + + return err; +} + +static int abx80x_set_alarm(struct device *dev, struct rtc_wkalrm *t) +{ + struct i2c_client *client = to_i2c_client(dev); + u8 alarm[6]; + int err; + + if (client->irq <= 0) + return -EINVAL; + + alarm[0] = 0x0; + alarm[1] = bin2bcd(t->time.tm_sec); + alarm[2] = bin2bcd(t->time.tm_min); + alarm[3] = bin2bcd(t->time.tm_hour); + alarm[4] = bin2bcd(t->time.tm_mday); + alarm[5] = bin2bcd(t->time.tm_mon + 1); + + err = i2c_smbus_write_i2c_block_data(client, ABX8XX_REG_AHTH, + sizeof(alarm), alarm); + if (err < 0) { + dev_err(&client->dev, "Unable to write alarm registers\n"); + return -EIO; + } + + if (t->enabled) { + err = i2c_smbus_write_byte_data(client, ABX8XX_REG_IRQ, + (ABX8XX_IRQ_IM_1_4 | + ABX8XX_IRQ_AIE)); + if (err) + return err; + } + + return 0; +} + +static int abx80x_alarm_irq_enable(struct device *dev, unsigned int enabled) +{ + struct i2c_client *client = to_i2c_client(dev); + int err; + + if (enabled) + err = i2c_smbus_write_byte_data(client, ABX8XX_REG_IRQ, + (ABX8XX_IRQ_IM_1_4 | + ABX8XX_IRQ_AIE)); + else + err = i2c_smbus_write_byte_data(client, ABX8XX_REG_IRQ, + ABX8XX_IRQ_IM_1_4); + return err; +} + static const struct rtc_class_ops abx80x_rtc_ops = { .read_time = abx80x_rtc_read_time, .set_time = abx80x_rtc_set_time, + .read_alarm = abx80x_read_alarm, + .set_alarm = abx80x_set_alarm, + .alarm_irq_enable = abx80x_alarm_irq_enable, }; static int abx80x_dt_trickle_cfg(struct device_node *np) @@ -225,7 +343,8 @@ static int abx80x_probe(struct i2c_client *client, } err = i2c_smbus_write_byte_data(client, ABX8XX_REG_CTRL1, - ((data & ~ABX8XX_CTRL_12_24) | + ((data & ~(ABX8XX_CTRL_12_24 | + ABX8XX_CTRL_ARST)) | ABX8XX_CTRL_WRITE)); if (err < 0) { dev_err(&client->dev, "Unable to write control register\n"); @@ -260,7 +379,12 @@ static int abx80x_probe(struct i2c_client *client, abx80x_enable_trickle_charger(client, trickle_cfg); } - rtc = devm_rtc_device_register(&client->dev, abx80x_driver.driver.name, + err = i2c_smbus_write_byte_data(client, ABX8XX_REG_CD_TIMER_CTL, + BIT(2)); + if (err) + return err; + + rtc = devm_rtc_device_register(&client->dev, "abx8xx", &abx80x_rtc_ops, THIS_MODULE); if (IS_ERR(rtc)) @@ -268,6 +392,19 @@ static int abx80x_probe(struct i2c_client *client, i2c_set_clientdata(client, rtc); + if (client->irq > 0) { + dev_info(&client->dev, "IRQ %d supplied\n", client->irq); + err = devm_request_threaded_irq(&client->dev, client->irq, NULL, + abx80x_handle_irq, + IRQF_SHARED | IRQF_ONESHOT, + "abx8xx", + client); + if (err) { + dev_err(&client->dev, "unable to request IRQ, alarms disabled\n"); + client->irq = 0; + } + } + return 0; } -- cgit v1.2.3 From f571287bda5390751ab4e4d5e3f54fa2d1788667 Mon Sep 17 00:00:00 2001 From: LABBE Corentin Date: Thu, 17 Dec 2015 14:11:04 +0100 Subject: rtc: Replace simple_strtoul by kstrtoul The simple_strtoul function is obsolete. This patch replace it by kstrtoul. Since kstrtoul is more strict, it permits to filter some invalid input that simple_strtoul accept. For example: echo '1022xxx' > /sys/devices/pnp0/00:03/rtc/rtc0/max_user_freq cat /sys/devices/pnp0/00:03/rtc/rtc0/max_user_freq 1022 Signed-off-by: LABBE Corentin Signed-off-by: Alexandre Belloni --- drivers/rtc/rtc-sysfs.c | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) (limited to 'drivers/rtc') diff --git a/drivers/rtc/rtc-sysfs.c b/drivers/rtc/rtc-sysfs.c index 7273855ed02e..463e286064ab 100644 --- a/drivers/rtc/rtc-sysfs.c +++ b/drivers/rtc/rtc-sysfs.c @@ -91,7 +91,12 @@ max_user_freq_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t n) { struct rtc_device *rtc = to_rtc_device(dev); - unsigned long val = simple_strtoul(buf, NULL, 0); + unsigned long val; + int err; + + err = kstrtoul(buf, 0, &val); + if (err) + return err; if (val >= 4096 || val == 0) return -EINVAL; @@ -175,7 +180,9 @@ wakealarm_store(struct device *dev, struct device_attribute *attr, } else adjust = 1; } - alarm = simple_strtoul(buf_ptr, NULL, 0); + retval = kstrtoul(buf_ptr, 0, &alarm); + if (retval) + return retval; if (adjust) { alarm += now; } -- cgit v1.2.3 From a83a793ad433d24f67aba4d88169235379004235 Mon Sep 17 00:00:00 2001 From: Krzysztof Kozlowski Date: Wed, 30 Dec 2015 13:47:25 +0900 Subject: rtc: s5m: Cleanup by removing useless 'rtc' prefix from fields Remove the 'rtc' prefix from some of the fields in struct s5m_rtc_reg_config because it is obvious - this is a RTC driver. No functional changes. Signed-off-by: Krzysztof Kozlowski Reviewed-by: Alim Akhtar Tested-by: Alim Akhtar Signed-off-by: Alexandre Belloni --- drivers/rtc/rtc-s5m.c | 40 +++++++++++++++++++--------------------- 1 file changed, 19 insertions(+), 21 deletions(-) (limited to 'drivers/rtc') diff --git a/drivers/rtc/rtc-s5m.c b/drivers/rtc/rtc-s5m.c index 0d68a85dd429..85649861a6b0 100644 --- a/drivers/rtc/rtc-s5m.c +++ b/drivers/rtc/rtc-s5m.c @@ -55,9 +55,9 @@ struct s5m_rtc_reg_config { * will enable update of time or alarm register. Then it will be * auto-cleared after successful update. */ - unsigned int rtc_udr_update; - /* Mask for UDR field in 'rtc_udr_update' register */ - unsigned int rtc_udr_mask; + unsigned int udr_update; + /* Mask for UDR field in 'udr_update' register */ + unsigned int udr_mask; }; /* Register map for S5M8763 and S5M8767 */ @@ -67,8 +67,8 @@ static const struct s5m_rtc_reg_config s5m_rtc_regs = { .ctrl = S5M_ALARM1_CONF, .alarm0 = S5M_ALARM0_SEC, .alarm1 = S5M_ALARM1_SEC, - .rtc_udr_update = S5M_RTC_UDR_CON, - .rtc_udr_mask = S5M_RTC_UDR_MASK, + .udr_update = S5M_RTC_UDR_CON, + .udr_mask = S5M_RTC_UDR_MASK, }; /* @@ -81,8 +81,8 @@ static const struct s5m_rtc_reg_config s2mps_rtc_regs = { .ctrl = S2MPS_RTC_CTRL, .alarm0 = S2MPS_ALARM0_SEC, .alarm1 = S2MPS_ALARM1_SEC, - .rtc_udr_update = S2MPS_RTC_UDR_CON, - .rtc_udr_mask = S2MPS_RTC_WUDR_MASK, + .udr_update = S2MPS_RTC_UDR_CON, + .udr_mask = S2MPS_RTC_WUDR_MASK, }; struct s5m_rtc_info { @@ -166,9 +166,8 @@ static inline int s5m8767_wait_for_udr_update(struct s5m_rtc_info *info) unsigned int data; do { - ret = regmap_read(info->regmap, info->regs->rtc_udr_update, - &data); - } while (--retry && (data & info->regs->rtc_udr_mask) && !ret); + ret = regmap_read(info->regmap, info->regs->udr_update, &data); + } while (--retry && (data & info->regs->udr_mask) && !ret); if (!retry) dev_err(info->dev, "waiting for UDR update, reached max number of retries\n"); @@ -214,7 +213,7 @@ static inline int s5m8767_rtc_set_time_reg(struct s5m_rtc_info *info) int ret; unsigned int data; - ret = regmap_read(info->regmap, info->regs->rtc_udr_update, &data); + ret = regmap_read(info->regmap, info->regs->udr_update, &data); if (ret < 0) { dev_err(info->dev, "failed to read update reg(%d)\n", ret); return ret; @@ -223,21 +222,20 @@ static inline int s5m8767_rtc_set_time_reg(struct s5m_rtc_info *info) switch (info->device_type) { case S5M8763X: case S5M8767X: - data |= info->regs->rtc_udr_mask | S5M_RTC_TIME_EN_MASK; + data |= info->regs->udr_mask | S5M_RTC_TIME_EN_MASK; case S2MPS15X: /* As per UM, for write time register, set WUDR bit to high */ data |= S2MPS15_RTC_WUDR_MASK; break; case S2MPS14X: case S2MPS13X: - data |= info->regs->rtc_udr_mask; + data |= info->regs->udr_mask; break; default: return -EINVAL; } - - ret = regmap_write(info->regmap, info->regs->rtc_udr_update, data); + ret = regmap_write(info->regmap, info->regs->udr_update, data); if (ret < 0) { dev_err(info->dev, "failed to write update reg(%d)\n", ret); return ret; @@ -253,14 +251,14 @@ static inline int s5m8767_rtc_set_alarm_reg(struct s5m_rtc_info *info) int ret; unsigned int data; - ret = regmap_read(info->regmap, info->regs->rtc_udr_update, &data); + ret = regmap_read(info->regmap, info->regs->udr_update, &data); if (ret < 0) { dev_err(info->dev, "%s: fail to read update reg(%d)\n", __func__, ret); return ret; } - data |= info->regs->rtc_udr_mask; + data |= info->regs->udr_mask; switch (info->device_type) { case S5M8763X: case S5M8767X: @@ -268,7 +266,7 @@ static inline int s5m8767_rtc_set_alarm_reg(struct s5m_rtc_info *info) break; case S2MPS15X: /* As per UM, for write alarm, set A_UDR(bit[4]) to high - * rtc_udr_mask above sets bit[4] + * udr_mask above sets bit[4] */ break; case S2MPS14X: @@ -281,7 +279,7 @@ static inline int s5m8767_rtc_set_alarm_reg(struct s5m_rtc_info *info) return -EINVAL; } - ret = regmap_write(info->regmap, info->regs->rtc_udr_update, data); + ret = regmap_write(info->regmap, info->regs->udr_update, data); if (ret < 0) { dev_err(info->dev, "%s: fail to write update reg(%d)\n", __func__, ret); @@ -292,7 +290,7 @@ static inline int s5m8767_rtc_set_alarm_reg(struct s5m_rtc_info *info) /* On S2MPS13 the AUDR is not auto-cleared */ if (info->device_type == S2MPS13X) - regmap_update_bits(info->regmap, info->regs->rtc_udr_update, + regmap_update_bits(info->regmap, info->regs->udr_update, S2MPS13_RTC_AUDR_MASK, 0); return ret; @@ -339,7 +337,7 @@ static int s5m_rtc_read_time(struct device *dev, struct rtc_time *tm) if (info->device_type == S2MPS15X || info->device_type == S2MPS14X || info->device_type == S2MPS13X) { ret = regmap_update_bits(info->regmap, - info->regs->rtc_udr_update, + info->regs->udr_update, S2MPS_RTC_RUDR_MASK, S2MPS_RTC_RUDR_MASK); if (ret) { dev_err(dev, -- cgit v1.2.3 From 67a6025a77be7c6bcb4baeb9424509fcb4ca1e32 Mon Sep 17 00:00:00 2001 From: Krzysztof Kozlowski Date: Wed, 30 Dec 2015 13:47:26 +0900 Subject: rtc: s5m: Add separate field for storing auto-cleared mask in register config Some devices from S2M/S5M family use different register update masks for different operations (alarm and register update). Now the driver uses common register configuration and a lot of exceptions per device in code. Before eliminating the exceptions and using specific register configuration for given device, make the auto-cleared mask a separate field. This is merely a refactoring. Signed-off-by: Krzysztof Kozlowski Reviewed-by: Alim Akhtar Tested-by: Alim Akhtar Signed-off-by: Alexandre Belloni --- drivers/rtc/rtc-s5m.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) (limited to 'drivers/rtc') diff --git a/drivers/rtc/rtc-s5m.c b/drivers/rtc/rtc-s5m.c index 85649861a6b0..559db8f72117 100644 --- a/drivers/rtc/rtc-s5m.c +++ b/drivers/rtc/rtc-s5m.c @@ -56,6 +56,8 @@ struct s5m_rtc_reg_config { * auto-cleared after successful update. */ unsigned int udr_update; + /* Auto-cleared mask in UDR field for writing time and alarm */ + unsigned int autoclear_udr_mask; /* Mask for UDR field in 'udr_update' register */ unsigned int udr_mask; }; @@ -68,6 +70,7 @@ static const struct s5m_rtc_reg_config s5m_rtc_regs = { .alarm0 = S5M_ALARM0_SEC, .alarm1 = S5M_ALARM1_SEC, .udr_update = S5M_RTC_UDR_CON, + .autoclear_udr_mask = S5M_RTC_UDR_MASK, .udr_mask = S5M_RTC_UDR_MASK, }; @@ -82,6 +85,7 @@ static const struct s5m_rtc_reg_config s2mps_rtc_regs = { .alarm0 = S2MPS_ALARM0_SEC, .alarm1 = S2MPS_ALARM1_SEC, .udr_update = S2MPS_RTC_UDR_CON, + .autoclear_udr_mask = S2MPS_RTC_WUDR_MASK, .udr_mask = S2MPS_RTC_WUDR_MASK, }; @@ -167,7 +171,7 @@ static inline int s5m8767_wait_for_udr_update(struct s5m_rtc_info *info) do { ret = regmap_read(info->regmap, info->regs->udr_update, &data); - } while (--retry && (data & info->regs->udr_mask) && !ret); + } while (--retry && (data & info->regs->autoclear_udr_mask) && !ret); if (!retry) dev_err(info->dev, "waiting for UDR update, reached max number of retries\n"); -- cgit v1.2.3 From 8ae83b6f76fc74eb6535b9d331a3310a59c32f84 Mon Sep 17 00:00:00 2001 From: Krzysztof Kozlowski Date: Wed, 30 Dec 2015 13:47:27 +0900 Subject: rtc: s5m: Make register configuration per S2MPS device to remove exceptions Before updating time and alarm the driver must set appropriate mask in UDR register. For that purpose the driver uses common register configuration and a lot of exceptions per device in the code. The exceptions are not obvious, for example except the change in the logic sometimes the fields are swapped (WUDR and AUDR between S2MPS14 and S2MPS15). This leads to quite complicated code. Try to make it more obvious by: 1. Documenting the UDR masks for devices and operations. 2. Adding fields in register configuration structure for each operation (read time, write time and alarm). 3. Splitting the configuration per S2MPS13, S2MPS14 and S2MPS15 thus removing exceptions for them. Signed-off-by: Krzysztof Kozlowski Reviewed-by: Alim Akhtar Tested-by: Alim Akhtar Acked-by: Lee Jones Signed-off-by: Alexandre Belloni --- drivers/rtc/rtc-s5m.c | 110 +++++++++++++++++++++++++++------------- include/linux/mfd/samsung/rtc.h | 2 + 2 files changed, 77 insertions(+), 35 deletions(-) (limited to 'drivers/rtc') diff --git a/drivers/rtc/rtc-s5m.c b/drivers/rtc/rtc-s5m.c index 559db8f72117..7407d7394bb4 100644 --- a/drivers/rtc/rtc-s5m.c +++ b/drivers/rtc/rtc-s5m.c @@ -38,7 +38,22 @@ */ #define UDR_READ_RETRY_CNT 5 -/* Registers used by the driver which are different between chipsets. */ +/* + * Registers used by the driver which are different between chipsets. + * + * Operations like read time and write alarm/time require updating + * specific fields in UDR register. These fields usually are auto-cleared + * (with some exceptions). + * + * Table of operations per device: + * + * Device | Write time | Read time | Write alarm + * ================================================= + * S5M8767 | UDR + TIME | | UDR + * S2MPS11/14 | WUDR | RUDR | WUDR + RUDR + * S2MPS13 | WUDR | RUDR | WUDR + AUDR + * S2MPS15 | WUDR | RUDR | AUDR + */ struct s5m_rtc_reg_config { /* Number of registers used for setting time/alarm0/alarm1 */ unsigned int regs_count; @@ -58,8 +73,13 @@ struct s5m_rtc_reg_config { unsigned int udr_update; /* Auto-cleared mask in UDR field for writing time and alarm */ unsigned int autoclear_udr_mask; - /* Mask for UDR field in 'udr_update' register */ - unsigned int udr_mask; + /* + * Masks in UDR field for time and alarm operations. + * The read time mask can be 0. Rest should not. + */ + unsigned int read_time_udr_mask; + unsigned int write_time_udr_mask; + unsigned int write_alarm_udr_mask; }; /* Register map for S5M8763 and S5M8767 */ @@ -71,14 +91,44 @@ static const struct s5m_rtc_reg_config s5m_rtc_regs = { .alarm1 = S5M_ALARM1_SEC, .udr_update = S5M_RTC_UDR_CON, .autoclear_udr_mask = S5M_RTC_UDR_MASK, - .udr_mask = S5M_RTC_UDR_MASK, + .read_time_udr_mask = 0, /* Not needed */ + .write_time_udr_mask = S5M_RTC_UDR_MASK | S5M_RTC_TIME_EN_MASK, + .write_alarm_udr_mask = S5M_RTC_UDR_MASK, +}; + +/* Register map for S2MPS13 */ +static const struct s5m_rtc_reg_config s2mps13_rtc_regs = { + .regs_count = 7, + .time = S2MPS_RTC_SEC, + .ctrl = S2MPS_RTC_CTRL, + .alarm0 = S2MPS_ALARM0_SEC, + .alarm1 = S2MPS_ALARM1_SEC, + .udr_update = S2MPS_RTC_UDR_CON, + .autoclear_udr_mask = S2MPS_RTC_WUDR_MASK, + .read_time_udr_mask = S2MPS_RTC_RUDR_MASK, + .write_time_udr_mask = S2MPS_RTC_WUDR_MASK, + .write_alarm_udr_mask = S2MPS_RTC_WUDR_MASK | S2MPS13_RTC_AUDR_MASK, +}; + +/* Register map for S2MPS11/14 */ +static const struct s5m_rtc_reg_config s2mps14_rtc_regs = { + .regs_count = 7, + .time = S2MPS_RTC_SEC, + .ctrl = S2MPS_RTC_CTRL, + .alarm0 = S2MPS_ALARM0_SEC, + .alarm1 = S2MPS_ALARM1_SEC, + .udr_update = S2MPS_RTC_UDR_CON, + .autoclear_udr_mask = S2MPS_RTC_WUDR_MASK, + .read_time_udr_mask = S2MPS_RTC_RUDR_MASK, + .write_time_udr_mask = S2MPS_RTC_WUDR_MASK, + .write_alarm_udr_mask = S2MPS_RTC_WUDR_MASK | S2MPS_RTC_RUDR_MASK, }; /* - * Register map for S2MPS14. - * It may be also suitable for S2MPS11 but this was not tested. + * Register map for S2MPS15 - in comparison to S2MPS14 the WUDR and AUDR bits + * are swapped. */ -static const struct s5m_rtc_reg_config s2mps_rtc_regs = { +static const struct s5m_rtc_reg_config s2mps15_rtc_regs = { .regs_count = 7, .time = S2MPS_RTC_SEC, .ctrl = S2MPS_RTC_CTRL, @@ -86,7 +136,9 @@ static const struct s5m_rtc_reg_config s2mps_rtc_regs = { .alarm1 = S2MPS_ALARM1_SEC, .udr_update = S2MPS_RTC_UDR_CON, .autoclear_udr_mask = S2MPS_RTC_WUDR_MASK, - .udr_mask = S2MPS_RTC_WUDR_MASK, + .read_time_udr_mask = S2MPS_RTC_RUDR_MASK, + .write_time_udr_mask = S2MPS15_RTC_WUDR_MASK, + .write_alarm_udr_mask = S2MPS15_RTC_AUDR_MASK, }; struct s5m_rtc_info { @@ -223,21 +275,7 @@ static inline int s5m8767_rtc_set_time_reg(struct s5m_rtc_info *info) return ret; } - switch (info->device_type) { - case S5M8763X: - case S5M8767X: - data |= info->regs->udr_mask | S5M_RTC_TIME_EN_MASK; - case S2MPS15X: - /* As per UM, for write time register, set WUDR bit to high */ - data |= S2MPS15_RTC_WUDR_MASK; - break; - case S2MPS14X: - case S2MPS13X: - data |= info->regs->udr_mask; - break; - default: - return -EINVAL; - } + data |= info->regs->write_time_udr_mask; ret = regmap_write(info->regmap, info->regs->udr_update, data); if (ret < 0) { @@ -262,22 +300,16 @@ static inline int s5m8767_rtc_set_alarm_reg(struct s5m_rtc_info *info) return ret; } - data |= info->regs->udr_mask; + data |= info->regs->write_alarm_udr_mask; switch (info->device_type) { case S5M8763X: case S5M8767X: data &= ~S5M_RTC_TIME_EN_MASK; break; case S2MPS15X: - /* As per UM, for write alarm, set A_UDR(bit[4]) to high - * udr_mask above sets bit[4] - */ - break; case S2MPS14X: - data |= S2MPS_RTC_RUDR_MASK; - break; case S2MPS13X: - data |= S2MPS13_RTC_AUDR_MASK; + /* No exceptions needed */ break; default: return -EINVAL; @@ -338,11 +370,11 @@ static int s5m_rtc_read_time(struct device *dev, struct rtc_time *tm) u8 data[info->regs->regs_count]; int ret; - if (info->device_type == S2MPS15X || info->device_type == S2MPS14X || - info->device_type == S2MPS13X) { + if (info->regs->read_time_udr_mask) { ret = regmap_update_bits(info->regmap, info->regs->udr_update, - S2MPS_RTC_RUDR_MASK, S2MPS_RTC_RUDR_MASK); + info->regs->read_time_udr_mask, + info->regs->read_time_udr_mask); if (ret) { dev_err(dev, "Failed to prepare registers for time reading: %d\n", @@ -709,10 +741,18 @@ static int s5m_rtc_probe(struct platform_device *pdev) switch (platform_get_device_id(pdev)->driver_data) { case S2MPS15X: + regmap_cfg = &s2mps14_rtc_regmap_config; + info->regs = &s2mps15_rtc_regs; + alarm_irq = S2MPS14_IRQ_RTCA0; + break; case S2MPS14X: + regmap_cfg = &s2mps14_rtc_regmap_config; + info->regs = &s2mps14_rtc_regs; + alarm_irq = S2MPS14_IRQ_RTCA0; + break; case S2MPS13X: regmap_cfg = &s2mps14_rtc_regmap_config; - info->regs = &s2mps_rtc_regs; + info->regs = &s2mps13_rtc_regs; alarm_irq = S2MPS14_IRQ_RTCA0; break; case S5M8763X: diff --git a/include/linux/mfd/samsung/rtc.h b/include/linux/mfd/samsung/rtc.h index a65e4655d470..48c3c5be7eb1 100644 --- a/include/linux/mfd/samsung/rtc.h +++ b/include/linux/mfd/samsung/rtc.h @@ -105,6 +105,8 @@ enum s2mps_rtc_reg { #define S5M_RTC_UDR_MASK (1 << S5M_RTC_UDR_SHIFT) #define S2MPS_RTC_WUDR_SHIFT 4 #define S2MPS_RTC_WUDR_MASK (1 << S2MPS_RTC_WUDR_SHIFT) +#define S2MPS15_RTC_AUDR_SHIFT 4 +#define S2MPS15_RTC_AUDR_MASK (1 << S2MPS15_RTC_AUDR_SHIFT) #define S2MPS13_RTC_AUDR_SHIFT 1 #define S2MPS13_RTC_AUDR_MASK (1 << S2MPS13_RTC_AUDR_SHIFT) #define S2MPS15_RTC_WUDR_SHIFT 1 -- cgit v1.2.3 From c4c23f58a96dcce177c996511363b85bf114ae8f Mon Sep 17 00:00:00 2001 From: Julia Lawall Date: Wed, 30 Dec 2015 21:59:34 +0100 Subject: rtc: rtc-ds2404: constify ds2404_chip_ops structures The ds2404_chip_ops structure is never modified, so declare it as const. Done with the help of Coccinelle. Signed-off-by: Julia Lawall Signed-off-by: Alexandre Belloni --- 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 7885edd3d507..16310fe79d76 100644 --- a/drivers/rtc/rtc-ds2404.c +++ b/drivers/rtc/rtc-ds2404.c @@ -48,7 +48,7 @@ struct ds2404_gpio { struct ds2404 { struct ds2404_gpio *gpio; - struct ds2404_chip_ops *ops; + const struct ds2404_chip_ops *ops; struct rtc_device *rtc; }; @@ -95,7 +95,7 @@ static void ds2404_gpio_unmap(struct ds2404 *chip) gpio_free(ds2404_gpio[i].gpio); } -static struct ds2404_chip_ops ds2404_gpio_ops = { +static const struct ds2404_chip_ops ds2404_gpio_ops = { .map_io = ds2404_gpio_map, .unmap_io = ds2404_gpio_unmap, }; -- cgit v1.2.3 From 079062b28fb4c58e30d024fdf974e00de53158fd Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Wed, 23 Dec 2015 19:37:19 +0200 Subject: rtc: cmos: prevent kernel warning on IRQ flags mismatch The Microsoft Surface 3 tablet shares interrupt line between RTC and one of SPI controllers. However, the rtc_cmos driver doesn't allow shared interrupts and user sees the following warning genirq: Flags mismatch irq 8. 00000080 (8086228E:02) vs. 00000000 (rtc0) ... [] pxa2xx_spi_probe+0x151/0x600 [spi_pxa2xx_platform] Allow RTC driver to use shared interrupts. Seems we are on the safe side to do just this simple change since cmos_interrupt() handler checks for the actual hardware status anyway. Signed-off-by: Andy Shevchenko Signed-off-by: Alexandre Belloni --- drivers/rtc/rtc-cmos.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/rtc') diff --git a/drivers/rtc/rtc-cmos.c b/drivers/rtc/rtc-cmos.c index 8f7034ba7d9e..84fb541038be 100644 --- a/drivers/rtc/rtc-cmos.c +++ b/drivers/rtc/rtc-cmos.c @@ -725,7 +725,7 @@ cmos_do_probe(struct device *dev, struct resource *ports, int rtc_irq) rtc_cmos_int_handler = cmos_interrupt; retval = request_irq(rtc_irq, rtc_cmos_int_handler, - 0, dev_name(&cmos_rtc.rtc->dev), + IRQF_SHARED, dev_name(&cmos_rtc.rtc->dev), cmos_rtc.rtc); if (retval < 0) { dev_dbg(dev, "IRQ %d is already in use\n", rtc_irq); -- cgit v1.2.3