From fbbf53f70225c82ba877de780486be5bc81b29e2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Uwe=20Kleine-K=C3=B6nig?= 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 diff --git a/drivers/rtc/rtc-pcf8523.c b/drivers/rtc/rtc-pcf8523.c index e7ebcc0b7..988566c 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 v0.10.2 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 diff --git a/drivers/rtc/rtc-proc.c b/drivers/rtc/rtc-proc.c index ffa69e1..31e7e23 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 v0.10.2 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 diff --git a/drivers/rtc/rtc-efi.c b/drivers/rtc/rtc-efi.c index 3806961..96d3860 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 v0.10.2 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 diff --git a/drivers/rtc/rtc-gemini.c b/drivers/rtc/rtc-gemini.c index e841846..f46b6d4 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 v0.10.2 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 diff --git a/drivers/rtc/rtc-sunxi.c b/drivers/rtc/rtc-sunxi.c index 52543ae..b4f35ac 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 v0.10.2 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 diff --git a/drivers/rtc/rtc-sunxi.c b/drivers/rtc/rtc-sunxi.c index b4f35ac..0c08a5b 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 v0.10.2 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 diff --git a/drivers/rtc/rtc-sunxi.c b/drivers/rtc/rtc-sunxi.c index 0c08a5b..abada60 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 v0.10.2 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 diff --git a/drivers/rtc/rtc-da9063.c b/drivers/rtc/rtc-da9063.c index d6c853b..f85cae2 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 v0.10.2 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 diff --git a/drivers/rtc/rtc-ds1305.c b/drivers/rtc/rtc-ds1305.c index 85706a9..f39691e 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 aa705bb..cf685f6 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 05a51ef..5038122 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 v0.10.2 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 diff --git a/drivers/rtc/rtc-ds1685.c b/drivers/rtc/rtc-ds1685.c index 5038122..535050f 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 v0.10.2 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 diff --git a/drivers/rtc/rtc-imxdi.c b/drivers/rtc/rtc-imxdi.c index 7bffd7f..8d8049bd 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 v0.10.2 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 diff --git a/drivers/rtc/rtc-lpc32xx.c b/drivers/rtc/rtc-lpc32xx.c index f923f73..887871c 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 v0.10.2 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 diff --git a/drivers/rtc/Kconfig b/drivers/rtc/Kconfig index 2a52424..376322f 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 231f764..62d61b2 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 0000000..772d221 --- /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 v0.10.2 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 diff --git a/drivers/rtc/rtc-rv8803.c b/drivers/rtc/rtc-rv8803.c index e7329e2..f883aa2 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 v0.10.2 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 diff --git a/drivers/rtc/rtc-rv8803.c b/drivers/rtc/rtc-rv8803.c index f883aa2..7155c08 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 v0.10.2 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 diff --git a/drivers/rtc/rtc-v3020.c b/drivers/rtc/rtc-v3020.c index f9f9709..7a04363 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 v0.10.2 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 diff --git a/drivers/rtc/rtc-abx80x.c b/drivers/rtc/rtc-abx80x.c index afea84c..203e661 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 v0.10.2 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 diff --git a/drivers/rtc/rtc-abx80x.c b/drivers/rtc/rtc-abx80x.c index 203e661..d41bbcd 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 v0.10.2 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 diff --git a/drivers/rtc/rtc-sysfs.c b/drivers/rtc/rtc-sysfs.c index 7273855..463e286 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 v0.10.2 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 diff --git a/drivers/rtc/rtc-s5m.c b/drivers/rtc/rtc-s5m.c index 0d68a85..8564986 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 v0.10.2 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 diff --git a/drivers/rtc/rtc-s5m.c b/drivers/rtc/rtc-s5m.c index 8564986..559db8f 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 v0.10.2 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 diff --git a/drivers/rtc/rtc-s5m.c b/drivers/rtc/rtc-s5m.c index 559db8f..7407d73 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 a65e465..48c3c5b 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 v0.10.2 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 diff --git a/drivers/rtc/rtc-ds2404.c b/drivers/rtc/rtc-ds2404.c index 7885edd..16310fe 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 v0.10.2 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 diff --git a/drivers/rtc/rtc-cmos.c b/drivers/rtc/rtc-cmos.c index 8f7034b..84fb541 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 v0.10.2