From 30a5271d4583ccaf22b4cb5b36caf254262dc113 Mon Sep 17 00:00:00 2001 From: Alexandre Belloni Date: Mon, 18 Jun 2018 10:52:01 +0200 Subject: [PATCH 01/34] rtc: ds1685: remove improper datetime access ABI The driver exposes an undocumented ABI to access the date and time registers. It is not actually used by any userspace tools. Remove it. Signed-off-by: Alexandre Belloni --- drivers/rtc/rtc-ds1685.c | 221 --------------------------------------- 1 file changed, 221 deletions(-) diff --git a/drivers/rtc/rtc-ds1685.c b/drivers/rtc/rtc-ds1685.c index 5c0db6c8134c..c3755d04575f 100644 --- a/drivers/rtc/rtc-ds1685.c +++ b/drivers/rtc/rtc-ds1685.c @@ -1520,217 +1520,6 @@ ds1685_rtc_sysfs_ctrl4b_grp = { .name = "ctrl4b", .attrs = ds1685_rtc_sysfs_ctrl4b_attrs, }; - - -/** - * struct ds1685_rtc_ctrl_regs. - * @name: char pointer for the bit name. - * @reg: control register the bit is in. - * @bit: the bit's offset in the register. - */ -struct ds1685_rtc_time_regs { - const char *name; - const u8 reg; - const u8 mask; - const u8 min; - const u8 max; -}; - -/* - * Time/Date register lookup tables. - */ -static const struct ds1685_rtc_time_regs -ds1685_time_regs_bcd_table[] = { - { "seconds", RTC_SECS, RTC_SECS_BCD_MASK, 0, 59 }, - { "minutes", RTC_MINS, RTC_MINS_BCD_MASK, 0, 59 }, - { "hours", RTC_HRS, RTC_HRS_24_BCD_MASK, 0, 23 }, - { "wday", RTC_WDAY, RTC_WDAY_MASK, 1, 7 }, - { "mday", RTC_MDAY, RTC_MDAY_BCD_MASK, 1, 31 }, - { "month", RTC_MONTH, RTC_MONTH_BCD_MASK, 1, 12 }, - { "year", RTC_YEAR, RTC_YEAR_BCD_MASK, 0, 99 }, - { "century", RTC_CENTURY, RTC_CENTURY_MASK, 0, 99 }, - { "alarm_seconds", RTC_SECS_ALARM, RTC_SECS_BCD_MASK, 0, 59 }, - { "alarm_minutes", RTC_MINS_ALARM, RTC_MINS_BCD_MASK, 0, 59 }, - { "alarm_hours", RTC_HRS_ALARM, RTC_HRS_24_BCD_MASK, 0, 23 }, - { "alarm_mday", RTC_MDAY_ALARM, RTC_MDAY_ALARM_MASK, 1, 31 }, - { NULL, 0, 0, 0, 0 }, -}; - -static const struct ds1685_rtc_time_regs -ds1685_time_regs_bin_table[] = { - { "seconds", RTC_SECS, RTC_SECS_BIN_MASK, 0x00, 0x3b }, - { "minutes", RTC_MINS, RTC_MINS_BIN_MASK, 0x00, 0x3b }, - { "hours", RTC_HRS, RTC_HRS_24_BIN_MASK, 0x00, 0x17 }, - { "wday", RTC_WDAY, RTC_WDAY_MASK, 0x01, 0x07 }, - { "mday", RTC_MDAY, RTC_MDAY_BIN_MASK, 0x01, 0x1f }, - { "month", RTC_MONTH, RTC_MONTH_BIN_MASK, 0x01, 0x0c }, - { "year", RTC_YEAR, RTC_YEAR_BIN_MASK, 0x00, 0x63 }, - { "century", RTC_CENTURY, RTC_CENTURY_MASK, 0x00, 0x63 }, - { "alarm_seconds", RTC_SECS_ALARM, RTC_SECS_BIN_MASK, 0x00, 0x3b }, - { "alarm_minutes", RTC_MINS_ALARM, RTC_MINS_BIN_MASK, 0x00, 0x3b }, - { "alarm_hours", RTC_HRS_ALARM, RTC_HRS_24_BIN_MASK, 0x00, 0x17 }, - { "alarm_mday", RTC_MDAY_ALARM, RTC_MDAY_ALARM_MASK, 0x01, 0x1f }, - { NULL, 0, 0, 0x00, 0x00 }, -}; - -/** - * ds1685_rtc_sysfs_time_regs_bcd_lookup - time/date reg bit lookup function. - * @name: register bit to look up in ds1685_time_regs_bcd_table. - */ -static const struct ds1685_rtc_time_regs* -ds1685_rtc_sysfs_time_regs_lookup(const char *name, bool bcd_mode) -{ - const struct ds1685_rtc_time_regs *p; - - if (bcd_mode) - p = ds1685_time_regs_bcd_table; - else - p = ds1685_time_regs_bin_table; - - for (; p->name != NULL; ++p) - if (strcmp(p->name, name) == 0) - return p; - - return NULL; -} - -/** - * ds1685_rtc_sysfs_time_regs_show - reads a time/date register via sysfs. - * @dev: pointer to device structure. - * @attr: pointer to device_attribute structure. - * @buf: pointer to char array to hold the output. - */ -static ssize_t -ds1685_rtc_sysfs_time_regs_show(struct device *dev, - struct device_attribute *attr, char *buf) -{ - u8 tmp; - struct ds1685_priv *rtc = dev_get_drvdata(dev); - const struct ds1685_rtc_time_regs *bcd_reg_info = - ds1685_rtc_sysfs_time_regs_lookup(attr->attr.name, true); - const struct ds1685_rtc_time_regs *bin_reg_info = - ds1685_rtc_sysfs_time_regs_lookup(attr->attr.name, false); - - /* Make sure we actually matched something. */ - if (!bcd_reg_info || !bin_reg_info) - return -EINVAL; - - /* bcd_reg_info->reg == bin_reg_info->reg. */ - ds1685_rtc_begin_data_access(rtc); - tmp = rtc->read(rtc, bcd_reg_info->reg); - ds1685_rtc_end_data_access(rtc); - - tmp = ds1685_rtc_bcd2bin(rtc, tmp, bcd_reg_info->mask, - bin_reg_info->mask); - - return sprintf(buf, "%d\n", tmp); -} - -/** - * ds1685_rtc_sysfs_time_regs_store - writes a time/date register via sysfs. - * @dev: pointer to device structure. - * @attr: pointer to device_attribute structure. - * @buf: pointer to char array to hold the output. - * @count: number of bytes written. - */ -static ssize_t -ds1685_rtc_sysfs_time_regs_store(struct device *dev, - struct device_attribute *attr, - const char *buf, size_t count) -{ - long int val = 0; - struct ds1685_priv *rtc = dev_get_drvdata(dev); - const struct ds1685_rtc_time_regs *bcd_reg_info = - ds1685_rtc_sysfs_time_regs_lookup(attr->attr.name, true); - const struct ds1685_rtc_time_regs *bin_reg_info = - ds1685_rtc_sysfs_time_regs_lookup(attr->attr.name, false); - - /* We only accept numbers. */ - if (kstrtol(buf, 10, &val) < 0) - return -EINVAL; - - /* Make sure we actually matched something. */ - if (!bcd_reg_info || !bin_reg_info) - return -EINVAL; - - /* Check for a valid range. */ - if (rtc->bcd_mode) { - if ((val < bcd_reg_info->min) || (val > bcd_reg_info->max)) - return -ERANGE; - } else { - if ((val < bin_reg_info->min) || (val > bin_reg_info->max)) - return -ERANGE; - } - - val = ds1685_rtc_bin2bcd(rtc, val, bin_reg_info->mask, - bcd_reg_info->mask); - - /* bcd_reg_info->reg == bin_reg_info->reg. */ - ds1685_rtc_begin_data_access(rtc); - rtc->write(rtc, bcd_reg_info->reg, val); - ds1685_rtc_end_data_access(rtc); - - return count; -} - -/** - * DS1685_RTC_SYSFS_REG_RW - device_attribute for a read-write time register. - * @reg: time/date register to read or write. - */ -#define DS1685_RTC_SYSFS_TIME_REG_RW(reg) \ - static DEVICE_ATTR(reg, S_IRUGO | S_IWUSR, \ - ds1685_rtc_sysfs_time_regs_show, \ - ds1685_rtc_sysfs_time_regs_store) - -/* - * Time/Date Register bits. - */ -DS1685_RTC_SYSFS_TIME_REG_RW(seconds); -DS1685_RTC_SYSFS_TIME_REG_RW(minutes); -DS1685_RTC_SYSFS_TIME_REG_RW(hours); -DS1685_RTC_SYSFS_TIME_REG_RW(wday); -DS1685_RTC_SYSFS_TIME_REG_RW(mday); -DS1685_RTC_SYSFS_TIME_REG_RW(month); -DS1685_RTC_SYSFS_TIME_REG_RW(year); -DS1685_RTC_SYSFS_TIME_REG_RW(century); -DS1685_RTC_SYSFS_TIME_REG_RW(alarm_seconds); -DS1685_RTC_SYSFS_TIME_REG_RW(alarm_minutes); -DS1685_RTC_SYSFS_TIME_REG_RW(alarm_hours); -DS1685_RTC_SYSFS_TIME_REG_RW(alarm_mday); - -static struct attribute* -ds1685_rtc_sysfs_time_attrs[] = { - &dev_attr_seconds.attr, - &dev_attr_minutes.attr, - &dev_attr_hours.attr, - &dev_attr_wday.attr, - &dev_attr_mday.attr, - &dev_attr_month.attr, - &dev_attr_year.attr, - &dev_attr_century.attr, - NULL, -}; - -static const struct attribute_group -ds1685_rtc_sysfs_time_grp = { - .name = "datetime", - .attrs = ds1685_rtc_sysfs_time_attrs, -}; - -static struct attribute* -ds1685_rtc_sysfs_alarm_attrs[] = { - &dev_attr_alarm_seconds.attr, - &dev_attr_alarm_minutes.attr, - &dev_attr_alarm_hours.attr, - &dev_attr_alarm_mday.attr, - NULL, -}; - -static const struct attribute_group -ds1685_rtc_sysfs_alarm_grp = { - .name = "alarm", - .attrs = ds1685_rtc_sysfs_alarm_attrs, -}; #endif /* CONFIG_RTC_DS1685_SYSFS_REGS */ @@ -1776,14 +1565,6 @@ ds1685_rtc_sysfs_register(struct device *dev) ret = sysfs_create_group(&dev->kobj, &ds1685_rtc_sysfs_ctrl4b_grp); if (ret) return ret; - - ret = sysfs_create_group(&dev->kobj, &ds1685_rtc_sysfs_time_grp); - if (ret) - return ret; - - ret = sysfs_create_group(&dev->kobj, &ds1685_rtc_sysfs_alarm_grp); - if (ret) - return ret; #endif return 0; } @@ -1805,8 +1586,6 @@ ds1685_rtc_sysfs_unregister(struct device *dev) sysfs_remove_group(&dev->kobj, &ds1685_rtc_sysfs_ctrld_grp); sysfs_remove_group(&dev->kobj, &ds1685_rtc_sysfs_ctrl4a_grp); sysfs_remove_group(&dev->kobj, &ds1685_rtc_sysfs_ctrl4b_grp); - sysfs_remove_group(&dev->kobj, &ds1685_rtc_sysfs_time_grp); - sysfs_remove_group(&dev->kobj, &ds1685_rtc_sysfs_alarm_grp); #endif return 0; From a41efe03e6110d7d85db272290aeed7e1ce9b63b Mon Sep 17 00:00:00 2001 From: Alexandre Belloni Date: Mon, 18 Jun 2018 10:52:02 +0200 Subject: [PATCH 02/34] rtc: ds1685: remove sysfs access to control registers Access to the control registers is mostly not needed and can cause runtime issues (like missed interrupts). Remove this debugging interface. Signed-off-by: Alexandre Belloni --- drivers/rtc/Kconfig | 12 -- drivers/rtc/rtc-ds1685.c | 369 --------------------------------------- 2 files changed, 381 deletions(-) diff --git a/drivers/rtc/Kconfig b/drivers/rtc/Kconfig index a2ba5db36145..2962fa09baf1 100644 --- a/drivers/rtc/Kconfig +++ b/drivers/rtc/Kconfig @@ -1027,18 +1027,6 @@ config RTC_DS1685_PROC_REGS Unless you are debugging this driver, choose N. -config RTC_DS1685_SYSFS_REGS - bool "SysFS access to RTC register bits" - depends on RTC_DRV_DS1685_FAMILY && SYSFS - help - Enable this to provide access to the RTC control register bits - in /sys. Some of the bits are read-write, others are read-only. - - Keep in mind that reading Control C's bits automatically clears - all pending IRQ flags - this can cause lost interrupts. - - If you know that you need access to these bits, choose Y, Else N. - config RTC_DRV_DS1742 tristate "Maxim/Dallas DS1742/1743" depends on HAS_IOMEM diff --git a/drivers/rtc/rtc-ds1685.c b/drivers/rtc/rtc-ds1685.c index c3755d04575f..6f39f683a98c 100644 --- a/drivers/rtc/rtc-ds1685.c +++ b/drivers/rtc/rtc-ds1685.c @@ -1188,341 +1188,6 @@ ds1685_rtc_sysfs_misc_grp = { .attrs = ds1685_rtc_sysfs_misc_attrs, }; -#ifdef CONFIG_RTC_DS1685_SYSFS_REGS -/** - * struct ds1685_rtc_ctrl_regs. - * @name: char pointer for the bit name. - * @reg: control register the bit is in. - * @bit: the bit's offset in the register. - */ -struct ds1685_rtc_ctrl_regs { - const char *name; - const u8 reg; - const u8 bit; -}; - -/* - * Ctrl register bit lookup table. - */ -static const struct ds1685_rtc_ctrl_regs -ds1685_ctrl_regs_table[] = { - { "uip", RTC_CTRL_A, RTC_CTRL_A_UIP }, - { "dv2", RTC_CTRL_A, RTC_CTRL_A_DV2 }, - { "dv1", RTC_CTRL_A, RTC_CTRL_A_DV1 }, - { "dv0", RTC_CTRL_A, RTC_CTRL_A_DV0 }, - { "rs3", RTC_CTRL_A, RTC_CTRL_A_RS3 }, - { "rs2", RTC_CTRL_A, RTC_CTRL_A_RS2 }, - { "rs1", RTC_CTRL_A, RTC_CTRL_A_RS1 }, - { "rs0", RTC_CTRL_A, RTC_CTRL_A_RS0 }, - { "set", RTC_CTRL_B, RTC_CTRL_B_SET }, - { "pie", RTC_CTRL_B, RTC_CTRL_B_PIE }, - { "aie", RTC_CTRL_B, RTC_CTRL_B_AIE }, - { "uie", RTC_CTRL_B, RTC_CTRL_B_UIE }, - { "sqwe", RTC_CTRL_B, RTC_CTRL_B_SQWE }, - { "dm", RTC_CTRL_B, RTC_CTRL_B_DM }, - { "2412", RTC_CTRL_B, RTC_CTRL_B_2412 }, - { "dse", RTC_CTRL_B, RTC_CTRL_B_DSE }, - { "irqf", RTC_CTRL_C, RTC_CTRL_C_IRQF }, - { "pf", RTC_CTRL_C, RTC_CTRL_C_PF }, - { "af", RTC_CTRL_C, RTC_CTRL_C_AF }, - { "uf", RTC_CTRL_C, RTC_CTRL_C_UF }, - { "vrt", RTC_CTRL_D, RTC_CTRL_D_VRT }, - { "vrt2", RTC_EXT_CTRL_4A, RTC_CTRL_4A_VRT2 }, - { "incr", RTC_EXT_CTRL_4A, RTC_CTRL_4A_INCR }, - { "pab", RTC_EXT_CTRL_4A, RTC_CTRL_4A_PAB }, - { "rf", RTC_EXT_CTRL_4A, RTC_CTRL_4A_RF }, - { "wf", RTC_EXT_CTRL_4A, RTC_CTRL_4A_WF }, - { "kf", RTC_EXT_CTRL_4A, RTC_CTRL_4A_KF }, -#if !defined(CONFIG_RTC_DRV_DS1685) && !defined(CONFIG_RTC_DRV_DS1689) - { "bme", RTC_EXT_CTRL_4A, RTC_CTRL_4A_BME }, -#endif - { "abe", RTC_EXT_CTRL_4B, RTC_CTRL_4B_ABE }, - { "e32k", RTC_EXT_CTRL_4B, RTC_CTRL_4B_E32K }, - { "cs", RTC_EXT_CTRL_4B, RTC_CTRL_4B_CS }, - { "rce", RTC_EXT_CTRL_4B, RTC_CTRL_4B_RCE }, - { "prs", RTC_EXT_CTRL_4B, RTC_CTRL_4B_PRS }, - { "rie", RTC_EXT_CTRL_4B, RTC_CTRL_4B_RIE }, - { "wie", RTC_EXT_CTRL_4B, RTC_CTRL_4B_WIE }, - { "kse", RTC_EXT_CTRL_4B, RTC_CTRL_4B_KSE }, - { NULL, 0, 0 }, -}; - -/** - * ds1685_rtc_sysfs_ctrl_regs_lookup - ctrl register bit lookup function. - * @name: ctrl register bit to look up in ds1685_ctrl_regs_table. - */ -static const struct ds1685_rtc_ctrl_regs* -ds1685_rtc_sysfs_ctrl_regs_lookup(const char *name) -{ - const struct ds1685_rtc_ctrl_regs *p = ds1685_ctrl_regs_table; - - for (; p->name != NULL; ++p) - if (strcmp(p->name, name) == 0) - return p; - - return NULL; -} - -/** - * ds1685_rtc_sysfs_ctrl_regs_show - reads a ctrl register bit via sysfs. - * @dev: pointer to device structure. - * @attr: pointer to device_attribute structure. - * @buf: pointer to char array to hold the output. - */ -static ssize_t -ds1685_rtc_sysfs_ctrl_regs_show(struct device *dev, - struct device_attribute *attr, char *buf) -{ - u8 tmp; - struct ds1685_priv *rtc = dev_get_drvdata(dev); - const struct ds1685_rtc_ctrl_regs *reg_info = - ds1685_rtc_sysfs_ctrl_regs_lookup(attr->attr.name); - - /* Make sure we actually matched something. */ - if (!reg_info) - return -EINVAL; - - /* No spinlock during a read -- mutex is already held. */ - ds1685_rtc_switch_to_bank1(rtc); - tmp = rtc->read(rtc, reg_info->reg) & reg_info->bit; - ds1685_rtc_switch_to_bank0(rtc); - - return sprintf(buf, "%d\n", (tmp ? 1 : 0)); -} - -/** - * ds1685_rtc_sysfs_ctrl_regs_store - writes a ctrl register bit via sysfs. - * @dev: pointer to device structure. - * @attr: pointer to device_attribute structure. - * @buf: pointer to char array to hold the output. - * @count: number of bytes written. - */ -static ssize_t -ds1685_rtc_sysfs_ctrl_regs_store(struct device *dev, - struct device_attribute *attr, - const char *buf, size_t count) -{ - struct ds1685_priv *rtc = dev_get_drvdata(dev); - u8 reg = 0, bit = 0, tmp; - unsigned long flags; - long int val = 0; - const struct ds1685_rtc_ctrl_regs *reg_info = - ds1685_rtc_sysfs_ctrl_regs_lookup(attr->attr.name); - - /* We only accept numbers. */ - if (kstrtol(buf, 10, &val) < 0) - return -EINVAL; - - /* bits are binary, 0 or 1 only. */ - if ((val != 0) && (val != 1)) - return -ERANGE; - - /* Make sure we actually matched something. */ - if (!reg_info) - return -EINVAL; - - reg = reg_info->reg; - bit = reg_info->bit; - - /* Safe to spinlock during a write. */ - ds1685_rtc_begin_ctrl_access(rtc, &flags); - tmp = rtc->read(rtc, reg); - rtc->write(rtc, reg, (val ? (tmp | bit) : (tmp & ~(bit)))); - ds1685_rtc_end_ctrl_access(rtc, flags); - - return count; -} - -/** - * DS1685_RTC_SYSFS_CTRL_REG_RO - device_attribute for read-only register bit. - * @bit: bit to read. - */ -#define DS1685_RTC_SYSFS_CTRL_REG_RO(bit) \ - static DEVICE_ATTR(bit, S_IRUGO, \ - ds1685_rtc_sysfs_ctrl_regs_show, NULL) - -/** - * DS1685_RTC_SYSFS_CTRL_REG_RW - device_attribute for read-write register bit. - * @bit: bit to read or write. - */ -#define DS1685_RTC_SYSFS_CTRL_REG_RW(bit) \ - static DEVICE_ATTR(bit, S_IRUGO | S_IWUSR, \ - ds1685_rtc_sysfs_ctrl_regs_show, \ - ds1685_rtc_sysfs_ctrl_regs_store) - -/* - * Control Register A bits. - */ -DS1685_RTC_SYSFS_CTRL_REG_RO(uip); -DS1685_RTC_SYSFS_CTRL_REG_RW(dv2); -DS1685_RTC_SYSFS_CTRL_REG_RW(dv1); -DS1685_RTC_SYSFS_CTRL_REG_RO(dv0); -DS1685_RTC_SYSFS_CTRL_REG_RW(rs3); -DS1685_RTC_SYSFS_CTRL_REG_RW(rs2); -DS1685_RTC_SYSFS_CTRL_REG_RW(rs1); -DS1685_RTC_SYSFS_CTRL_REG_RW(rs0); - -static struct attribute* -ds1685_rtc_sysfs_ctrla_attrs[] = { - &dev_attr_uip.attr, - &dev_attr_dv2.attr, - &dev_attr_dv1.attr, - &dev_attr_dv0.attr, - &dev_attr_rs3.attr, - &dev_attr_rs2.attr, - &dev_attr_rs1.attr, - &dev_attr_rs0.attr, - NULL, -}; - -static const struct attribute_group -ds1685_rtc_sysfs_ctrla_grp = { - .name = "ctrla", - .attrs = ds1685_rtc_sysfs_ctrla_attrs, -}; - - -/* - * Control Register B bits. - */ -DS1685_RTC_SYSFS_CTRL_REG_RO(set); -DS1685_RTC_SYSFS_CTRL_REG_RW(pie); -DS1685_RTC_SYSFS_CTRL_REG_RW(aie); -DS1685_RTC_SYSFS_CTRL_REG_RW(uie); -DS1685_RTC_SYSFS_CTRL_REG_RW(sqwe); -DS1685_RTC_SYSFS_CTRL_REG_RO(dm); -DS1685_RTC_SYSFS_CTRL_REG_RO(2412); -DS1685_RTC_SYSFS_CTRL_REG_RO(dse); - -static struct attribute* -ds1685_rtc_sysfs_ctrlb_attrs[] = { - &dev_attr_set.attr, - &dev_attr_pie.attr, - &dev_attr_aie.attr, - &dev_attr_uie.attr, - &dev_attr_sqwe.attr, - &dev_attr_dm.attr, - &dev_attr_2412.attr, - &dev_attr_dse.attr, - NULL, -}; - -static const struct attribute_group -ds1685_rtc_sysfs_ctrlb_grp = { - .name = "ctrlb", - .attrs = ds1685_rtc_sysfs_ctrlb_attrs, -}; - -/* - * Control Register C bits. - * - * Reading Control C clears these bits! Reading them individually can - * possibly cause an interrupt to be missed. Use the /proc interface - * to see all the bits in this register simultaneously. - */ -DS1685_RTC_SYSFS_CTRL_REG_RO(irqf); -DS1685_RTC_SYSFS_CTRL_REG_RO(pf); -DS1685_RTC_SYSFS_CTRL_REG_RO(af); -DS1685_RTC_SYSFS_CTRL_REG_RO(uf); - -static struct attribute* -ds1685_rtc_sysfs_ctrlc_attrs[] = { - &dev_attr_irqf.attr, - &dev_attr_pf.attr, - &dev_attr_af.attr, - &dev_attr_uf.attr, - NULL, -}; - -static const struct attribute_group -ds1685_rtc_sysfs_ctrlc_grp = { - .name = "ctrlc", - .attrs = ds1685_rtc_sysfs_ctrlc_attrs, -}; - -/* - * Control Register D bits. - */ -DS1685_RTC_SYSFS_CTRL_REG_RO(vrt); - -static struct attribute* -ds1685_rtc_sysfs_ctrld_attrs[] = { - &dev_attr_vrt.attr, - NULL, -}; - -static const struct attribute_group -ds1685_rtc_sysfs_ctrld_grp = { - .name = "ctrld", - .attrs = ds1685_rtc_sysfs_ctrld_attrs, -}; - -/* - * Control Register 4A bits. - */ -DS1685_RTC_SYSFS_CTRL_REG_RO(vrt2); -DS1685_RTC_SYSFS_CTRL_REG_RO(incr); -DS1685_RTC_SYSFS_CTRL_REG_RW(pab); -DS1685_RTC_SYSFS_CTRL_REG_RW(rf); -DS1685_RTC_SYSFS_CTRL_REG_RW(wf); -DS1685_RTC_SYSFS_CTRL_REG_RW(kf); -#if !defined(CONFIG_RTC_DRV_DS1685) && !defined(CONFIG_RTC_DRV_DS1689) -DS1685_RTC_SYSFS_CTRL_REG_RO(bme); -#endif - -static struct attribute* -ds1685_rtc_sysfs_ctrl4a_attrs[] = { - &dev_attr_vrt2.attr, - &dev_attr_incr.attr, - &dev_attr_pab.attr, - &dev_attr_rf.attr, - &dev_attr_wf.attr, - &dev_attr_kf.attr, -#if !defined(CONFIG_RTC_DRV_DS1685) && !defined(CONFIG_RTC_DRV_DS1689) - &dev_attr_bme.attr, -#endif - NULL, -}; - -static const struct attribute_group -ds1685_rtc_sysfs_ctrl4a_grp = { - .name = "ctrl4a", - .attrs = ds1685_rtc_sysfs_ctrl4a_attrs, -}; - -/* - * Control Register 4B bits. - */ -DS1685_RTC_SYSFS_CTRL_REG_RW(abe); -DS1685_RTC_SYSFS_CTRL_REG_RW(e32k); -DS1685_RTC_SYSFS_CTRL_REG_RO(cs); -DS1685_RTC_SYSFS_CTRL_REG_RW(rce); -DS1685_RTC_SYSFS_CTRL_REG_RW(prs); -DS1685_RTC_SYSFS_CTRL_REG_RW(rie); -DS1685_RTC_SYSFS_CTRL_REG_RW(wie); -DS1685_RTC_SYSFS_CTRL_REG_RW(kse); - -static struct attribute* -ds1685_rtc_sysfs_ctrl4b_attrs[] = { - &dev_attr_abe.attr, - &dev_attr_e32k.attr, - &dev_attr_cs.attr, - &dev_attr_rce.attr, - &dev_attr_prs.attr, - &dev_attr_rie.attr, - &dev_attr_wie.attr, - &dev_attr_kse.attr, - NULL, -}; - -static const struct attribute_group -ds1685_rtc_sysfs_ctrl4b_grp = { - .name = "ctrl4b", - .attrs = ds1685_rtc_sysfs_ctrl4b_attrs, -}; -#endif /* CONFIG_RTC_DS1685_SYSFS_REGS */ - - /** * ds1685_rtc_sysfs_register - register sysfs files. * @dev: pointer to device structure. @@ -1541,31 +1206,6 @@ ds1685_rtc_sysfs_register(struct device *dev) if (ret) return ret; -#ifdef CONFIG_RTC_DS1685_SYSFS_REGS - ret = sysfs_create_group(&dev->kobj, &ds1685_rtc_sysfs_ctrla_grp); - if (ret) - return ret; - - ret = sysfs_create_group(&dev->kobj, &ds1685_rtc_sysfs_ctrlb_grp); - if (ret) - return ret; - - ret = sysfs_create_group(&dev->kobj, &ds1685_rtc_sysfs_ctrlc_grp); - if (ret) - return ret; - - ret = sysfs_create_group(&dev->kobj, &ds1685_rtc_sysfs_ctrld_grp); - if (ret) - return ret; - - ret = sysfs_create_group(&dev->kobj, &ds1685_rtc_sysfs_ctrl4a_grp); - if (ret) - return ret; - - ret = sysfs_create_group(&dev->kobj, &ds1685_rtc_sysfs_ctrl4b_grp); - if (ret) - return ret; -#endif return 0; } @@ -1579,15 +1219,6 @@ ds1685_rtc_sysfs_unregister(struct device *dev) sysfs_remove_bin_file(&dev->kobj, &ds1685_rtc_sysfs_nvram_attr); sysfs_remove_group(&dev->kobj, &ds1685_rtc_sysfs_misc_grp); -#ifdef CONFIG_RTC_DS1685_SYSFS_REGS - sysfs_remove_group(&dev->kobj, &ds1685_rtc_sysfs_ctrla_grp); - sysfs_remove_group(&dev->kobj, &ds1685_rtc_sysfs_ctrlb_grp); - sysfs_remove_group(&dev->kobj, &ds1685_rtc_sysfs_ctrlc_grp); - sysfs_remove_group(&dev->kobj, &ds1685_rtc_sysfs_ctrld_grp); - sysfs_remove_group(&dev->kobj, &ds1685_rtc_sysfs_ctrl4a_grp); - sysfs_remove_group(&dev->kobj, &ds1685_rtc_sysfs_ctrl4b_grp); -#endif - return 0; } #endif /* CONFIG_SYSFS */ From 7874b919866ba91bac253fa219d3d4c82bb944df Mon Sep 17 00:00:00 2001 From: Zhouyang Jia Date: Tue, 12 Jun 2018 12:40:03 +0800 Subject: [PATCH 03/34] rtc: bq4802: add error handling for devm_ioremap When devm_ioremap fails, the lack of error-handling code may cause unexpected results. This patch adds error-handling code after calling devm_ioremap. Signed-off-by: Zhouyang Jia Signed-off-by: Alexandre Belloni --- drivers/rtc/rtc-bq4802.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/drivers/rtc/rtc-bq4802.c b/drivers/rtc/rtc-bq4802.c index d768f6747961..113493b52149 100644 --- a/drivers/rtc/rtc-bq4802.c +++ b/drivers/rtc/rtc-bq4802.c @@ -162,6 +162,10 @@ static int bq4802_probe(struct platform_device *pdev) } else if (p->r->flags & IORESOURCE_MEM) { p->regs = devm_ioremap(&pdev->dev, p->r->start, resource_size(p->r)); + if (!p->regs){ + err = -ENOMEM; + goto out; + } p->read = bq4802_read_mem; p->write = bq4802_write_mem; } else { From cd7f3a249dbed2858e6c2f30e5be7f1f7a709ee2 Mon Sep 17 00:00:00 2001 From: Trent Piepho Date: Wed, 16 May 2018 16:45:51 -0700 Subject: [PATCH 04/34] rtc: snvs: Add timeouts to avoid kernel lockups In order to read correctly from asynchronously updated RTC registers, it's necessary to read repeatedly until their values do not change from read to read. It's also necessary to wait for three RTC clock ticks for certain operations. There are no timeouts in this code and these operations could possibly loop forever. To avoid kernel hangs, put in timeouts. The iMX7d can be configured to stop the SRTC on a tamper event, which will lockup the kernel inside this driver as described above. These hangs can happen when running under qemu, which doesn't emulate the SNVS RTC, though currently the driver will refuse to load on qemu due to a timeout in the driver probe method. It could also happen if the SRTC block where somehow placed into reset or the slow speed clock that drives the SRTC counter (but not the CPU) were to stop. The symptoms on a two core iMX7d are a work queue hang on rtc_timer_do_work(), which eventually blocks a systemd fsnotify operation that triggers a work queue flush, causing systemd to hang and thus causing all services that should be started by systemd, like a console getty, to fail to start or stop. Also optimize the wait code to wait less. It only needs to wait for the clock to advance three ticks, not to see it change three times. Cc: Alexandre Belloni Cc: Alessandro Zummo Cc: Fabio Estevam Cc: Shawn Guo Cc: Bryan O'Donoghue Signed-off-by: Trent Piepho Signed-off-by: Alexandre Belloni --- drivers/rtc/rtc-snvs.c | 103 +++++++++++++++++++++++++++-------------- 1 file changed, 69 insertions(+), 34 deletions(-) diff --git a/drivers/rtc/rtc-snvs.c b/drivers/rtc/rtc-snvs.c index 8a75cc3af6e7..b2483a749ac4 100644 --- a/drivers/rtc/rtc-snvs.c +++ b/drivers/rtc/rtc-snvs.c @@ -40,49 +40,83 @@ struct snvs_rtc_data { struct clk *clk; }; +/* Read 64 bit timer register, which could be in inconsistent state */ +static u64 rtc_read_lpsrt(struct snvs_rtc_data *data) +{ + u32 msb, lsb; + + regmap_read(data->regmap, data->offset + SNVS_LPSRTCMR, &msb); + regmap_read(data->regmap, data->offset + SNVS_LPSRTCLR, &lsb); + return (u64)msb << 32 | lsb; +} + +/* Read the secure real time counter, taking care to deal with the cases of the + * counter updating while being read. + */ static u32 rtc_read_lp_counter(struct snvs_rtc_data *data) { u64 read1, read2; - u32 val; + unsigned int timeout = 100; + /* As expected, the registers might update between the read of the LSB + * reg and the MSB reg. It's also possible that one register might be + * in partially modified state as well. + */ + read1 = rtc_read_lpsrt(data); do { - regmap_read(data->regmap, data->offset + SNVS_LPSRTCMR, &val); - read1 = val; - read1 <<= 32; - regmap_read(data->regmap, data->offset + SNVS_LPSRTCLR, &val); - read1 |= val; - - regmap_read(data->regmap, data->offset + SNVS_LPSRTCMR, &val); - read2 = val; - read2 <<= 32; - regmap_read(data->regmap, data->offset + SNVS_LPSRTCLR, &val); - read2 |= val; - } while (read1 != read2); + read2 = read1; + read1 = rtc_read_lpsrt(data); + } while (read1 != read2 && --timeout); + if (!timeout) + dev_err(&data->rtc->dev, "Timeout trying to get valid LPSRT Counter read\n"); /* Convert 47-bit counter to 32-bit raw second count */ return (u32) (read1 >> CNTR_TO_SECS_SH); } -static void rtc_write_sync_lp(struct snvs_rtc_data *data) +/* Just read the lsb from the counter, dealing with inconsistent state */ +static int rtc_read_lp_counter_lsb(struct snvs_rtc_data *data, u32 *lsb) { - u32 count1, count2, count3; - int i; + u32 count1, count2; + unsigned int timeout = 100; - /* Wait for 3 CKIL cycles */ - for (i = 0; i < 3; i++) { - do { - regmap_read(data->regmap, data->offset + SNVS_LPSRTCLR, &count1); - regmap_read(data->regmap, data->offset + SNVS_LPSRTCLR, &count2); - } while (count1 != count2); - - /* Now wait until counter value changes */ - do { - do { - regmap_read(data->regmap, data->offset + SNVS_LPSRTCLR, &count2); - regmap_read(data->regmap, data->offset + SNVS_LPSRTCLR, &count3); - } while (count2 != count3); - } while (count3 == count1); + regmap_read(data->regmap, data->offset + SNVS_LPSRTCLR, &count1); + do { + count2 = count1; + regmap_read(data->regmap, data->offset + SNVS_LPSRTCLR, &count1); + } while (count1 != count2 && --timeout); + if (!timeout) { + dev_err(&data->rtc->dev, "Timeout trying to get valid LPSRT Counter read\n"); + return -ETIMEDOUT; } + + *lsb = count1; + return 0; +} + +static int rtc_write_sync_lp(struct snvs_rtc_data *data) +{ + u32 count1, count2; + u32 elapsed; + unsigned int timeout = 1000; + int ret; + + ret = rtc_read_lp_counter_lsb(data, &count1); + if (ret) + return ret; + + /* Wait for 3 CKIL cycles, about 61.0-91.5 µs */ + do { + ret = rtc_read_lp_counter_lsb(data, &count2); + if (ret) + return ret; + elapsed = count2 - count1; /* wrap around _is_ handled! */ + } while (elapsed < 3 && --timeout); + if (!timeout) { + dev_err(&data->rtc->dev, "Timeout waiting for LPSRT Counter to change\n"); + return -ETIMEDOUT; + } + return 0; } static int snvs_rtc_enable(struct snvs_rtc_data *data, bool enable) @@ -166,9 +200,7 @@ static int snvs_rtc_alarm_irq_enable(struct device *dev, unsigned int enable) (SNVS_LPCR_LPTA_EN | SNVS_LPCR_LPWUI_EN), enable ? (SNVS_LPCR_LPTA_EN | SNVS_LPCR_LPWUI_EN) : 0); - rtc_write_sync_lp(data); - - return 0; + return rtc_write_sync_lp(data); } static int snvs_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alrm) @@ -176,11 +208,14 @@ static int snvs_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alrm) struct snvs_rtc_data *data = dev_get_drvdata(dev); struct rtc_time *alrm_tm = &alrm->time; unsigned long time; + int ret; rtc_tm_to_time(alrm_tm, &time); regmap_update_bits(data->regmap, data->offset + SNVS_LPCR, SNVS_LPCR_LPTA_EN, 0); - rtc_write_sync_lp(data); + ret = rtc_write_sync_lp(data); + if (ret) + return ret; regmap_write(data->regmap, data->offset + SNVS_LPTAR, time); /* Clear alarm interrupt status bit */ From d6c3029f32f72db7ba7b4183b0423cce2267ca3d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Uwe=20Kleine-K=C3=B6nig?= Date: Sun, 20 May 2018 15:37:23 +0200 Subject: [PATCH 05/34] rtc: pcf2127: add support for accessing internal static RAM MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The PCF2127 has 512 bytes of internal static RAM and this patch expands the driver to access this memory. Signed-off-by: Uwe Kleine-König Signed-off-by: Alexandre Belloni --- drivers/rtc/rtc-pcf2127.c | 68 +++++++++++++++++++++++++++++++++++---- 1 file changed, 62 insertions(+), 6 deletions(-) diff --git a/drivers/rtc/rtc-pcf2127.c b/drivers/rtc/rtc-pcf2127.c index e83be1852c2f..9f99a0966550 100644 --- a/drivers/rtc/rtc-pcf2127.c +++ b/drivers/rtc/rtc-pcf2127.c @@ -36,6 +36,11 @@ #define PCF2127_REG_MO (0x08) #define PCF2127_REG_YR (0x09) +/* the pcf2127 has 512 bytes nvmem, pcf2129 doesn't */ +#define PCF2127_REG_RAM_addr_MSB 0x1a +#define PCF2127_REG_RAM_wrt_cmd 0x1c +#define PCF2127_REG_RAM_rd_cmd 0x1d + #define PCF2127_OSF BIT(7) /* Oscillator Fail flag */ struct pcf2127 { @@ -183,10 +188,47 @@ static const struct rtc_class_ops pcf2127_rtc_ops = { .set_time = pcf2127_rtc_set_time, }; +static int pcf2127_nvmem_read(void *priv, unsigned int offset, + void *val, size_t bytes) +{ + struct pcf2127 *pcf2127 = priv; + int ret; + unsigned char offsetbuf[] = { offset >> 8, offset }; + + ret = regmap_bulk_write(pcf2127->regmap, PCF2127_REG_RAM_addr_MSB, + offsetbuf, 2); + if (ret) + return ret; + + ret = regmap_bulk_read(pcf2127->regmap, PCF2127_REG_RAM_rd_cmd, + val, bytes); + + return ret ?: bytes; +} + +static int pcf2127_nvmem_write(void *priv, unsigned int offset, + void *val, size_t bytes) +{ + struct pcf2127 *pcf2127 = priv; + int ret; + unsigned char offsetbuf[] = { offset >> 8, offset }; + + ret = regmap_bulk_write(pcf2127->regmap, PCF2127_REG_RAM_addr_MSB, + offsetbuf, 2); + if (ret) + return ret; + + ret = regmap_bulk_write(pcf2127->regmap, PCF2127_REG_RAM_wrt_cmd, + val, bytes); + + return ret ?: bytes; +} + static int pcf2127_probe(struct device *dev, struct regmap *regmap, - const char *name) + const char *name, bool has_nvmem) { struct pcf2127 *pcf2127; + int ret = 0; dev_dbg(dev, "%s\n", __func__); @@ -200,8 +242,21 @@ static int pcf2127_probe(struct device *dev, struct regmap *regmap, pcf2127->rtc = devm_rtc_device_register(dev, name, &pcf2127_rtc_ops, THIS_MODULE); + if (IS_ERR(pcf2127->rtc)) + return PTR_ERR(pcf2127->rtc); - return PTR_ERR_OR_ZERO(pcf2127->rtc); + if (has_nvmem) { + struct nvmem_config nvmem_cfg = { + .priv = pcf2127, + .reg_read = pcf2127_nvmem_read, + .reg_write = pcf2127_nvmem_write, + .size = 512, + }; + + ret = rtc_nvmem_register(pcf2127->rtc, &nvmem_cfg); + } + + return ret; } #ifdef CONFIG_OF @@ -309,11 +364,11 @@ static int pcf2127_i2c_probe(struct i2c_client *client, } return pcf2127_probe(&client->dev, regmap, - pcf2127_i2c_driver.driver.name); + pcf2127_i2c_driver.driver.name, id->driver_data); } static const struct i2c_device_id pcf2127_i2c_id[] = { - { "pcf2127", 0 }, + { "pcf2127", 1 }, { "pcf2129", 0 }, { } }; @@ -372,11 +427,12 @@ static int pcf2127_spi_probe(struct spi_device *spi) return PTR_ERR(regmap); } - return pcf2127_probe(&spi->dev, regmap, pcf2127_spi_driver.driver.name); + return pcf2127_probe(&spi->dev, regmap, pcf2127_spi_driver.driver.name, + spi_get_device_id(spi)->driver_data); } static const struct spi_device_id pcf2127_spi_id[] = { - { "pcf2127", 0 }, + { "pcf2127", 1 }, { "pcf2129", 0 }, { } }; From dff700fa81938d8947c86b7909920e5e5f772afc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Uwe=20Kleine-K=C3=B6nig?= Date: Sat, 9 Jun 2018 08:43:13 +0200 Subject: [PATCH 06/34] rtc: stmp3xxx: Don't reset the rtc in .probe() when watchdog is running MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit As pointed out in the added comment resetting the rtc also stops the included watchdog. This is bad if the bootloader started the watchdog to secure the boot process. So don't reset if the watchdog is running. Signed-off-by: Uwe Kleine-König Acked-by: Guenter Roeck Signed-off-by: Alexandre Belloni --- drivers/rtc/rtc-stmp3xxx.c | 20 ++++++++++++++++---- 1 file changed, 16 insertions(+), 4 deletions(-) diff --git a/drivers/rtc/rtc-stmp3xxx.c b/drivers/rtc/rtc-stmp3xxx.c index d578e40d5a50..b76318fd5bb0 100644 --- a/drivers/rtc/rtc-stmp3xxx.c +++ b/drivers/rtc/rtc-stmp3xxx.c @@ -288,10 +288,22 @@ static int stmp3xxx_rtc_probe(struct platform_device *pdev) platform_set_drvdata(pdev, rtc_data); - err = stmp_reset_block(rtc_data->io); - if (err) { - dev_err(&pdev->dev, "stmp_reset_block failed: %d\n", err); - return err; + /* + * Resetting the rtc stops the watchdog timer that is potentially + * running. So (assuming it is running on purpose) don't reset if the + * watchdog is enabled. + */ + if (readl(rtc_data->io + STMP3XXX_RTC_CTRL) & + STMP3XXX_RTC_CTRL_WATCHDOGEN) { + dev_info(&pdev->dev, + "Watchdog is running, skip resetting rtc\n"); + } else { + err = stmp_reset_block(rtc_data->io); + if (err) { + dev_err(&pdev->dev, "stmp_reset_block failed: %d\n", + err); + return err; + } } /* From 1a990fefb641398fb580a0ea0be99b0ff27cbb9b Mon Sep 17 00:00:00 2001 From: Baruch Siach Date: Thu, 21 Jun 2018 20:40:23 +0300 Subject: [PATCH 07/34] rtc: armada38x: reset after rtc power loss When the RTC block looses power it needs a reset sequence to make it usable again. Otherwise, writes to the time register have no effect. This reset sequence combines information from the mvebu_rtc driver in the Marvell provided U-Boot, and the SolidRun provided U-Boot repo. Tested on the Armada 388 based SolidRun Clearfog Base. Signed-off-by: Baruch Siach Acked-by: Gregory CLEMENT Signed-off-by: Alexandre Belloni --- drivers/rtc/rtc-armada38x.c | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) diff --git a/drivers/rtc/rtc-armada38x.c b/drivers/rtc/rtc-armada38x.c index 1e4978c96ffd..bde53c8ccee2 100644 --- a/drivers/rtc/rtc-armada38x.c +++ b/drivers/rtc/rtc-armada38x.c @@ -30,6 +30,8 @@ #define RTC_IRQ_FREQ_1HZ BIT(2) #define RTC_CCR 0x18 #define RTC_CCR_MODE BIT(15) +#define RTC_CONF_TEST 0x1C +#define RTC_NOMINAL_TIMING BIT(13) #define RTC_TIME 0xC #define RTC_ALARM1 0x10 @@ -75,6 +77,7 @@ struct armada38x_rtc { void __iomem *regs_soc; spinlock_t lock; int irq; + bool initialized; struct value_to_freq *val_to_freq; struct armada38x_rtc_data *data; }; @@ -226,6 +229,23 @@ static int armada38x_rtc_read_time(struct device *dev, struct rtc_time *tm) return 0; } +static void armada38x_rtc_reset(struct armada38x_rtc *rtc) +{ + u32 reg; + + reg = rtc->data->read_rtc_reg(rtc, RTC_CONF_TEST); + /* If bits [7:0] are non-zero, assume RTC was uninitialized */ + if (reg & 0xff) { + rtc_delayed_write(0, rtc, RTC_CONF_TEST); + msleep(500); /* Oscillator startup time */ + rtc_delayed_write(0, rtc, RTC_TIME); + rtc_delayed_write(SOC_RTC_ALARM1 | SOC_RTC_ALARM2, rtc, + RTC_STATUS); + rtc_delayed_write(RTC_NOMINAL_TIMING, rtc, RTC_CCR); + } + rtc->initialized = true; +} + static int armada38x_rtc_set_time(struct device *dev, struct rtc_time *tm) { struct armada38x_rtc *rtc = dev_get_drvdata(dev); @@ -237,6 +257,9 @@ static int armada38x_rtc_set_time(struct device *dev, struct rtc_time *tm) if (ret) goto out; + if (!rtc->initialized) + armada38x_rtc_reset(rtc); + spin_lock_irqsave(&rtc->lock, flags); rtc_delayed_write(time, rtc, RTC_TIME); spin_unlock_irqrestore(&rtc->lock, flags); From 2b4f07e99e97b3035ce354dd38010b92c34f6bb0 Mon Sep 17 00:00:00 2001 From: Colin Ian King Date: Sun, 24 Jun 2018 11:38:03 +0100 Subject: [PATCH 08/34] rtc: test: make array pdev static The array pdev is local to the source and does not need to be in global scope, so make it static. Cleans up sparse warning: symbol 'pdev' was not declared. Should it be static? Signed-off-by: Colin Ian King Signed-off-by: Alexandre Belloni --- drivers/rtc/rtc-test.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/rtc/rtc-test.c b/drivers/rtc/rtc-test.c index 8469256edc2a..ade6a82709be 100644 --- a/drivers/rtc/rtc-test.c +++ b/drivers/rtc/rtc-test.c @@ -22,7 +22,7 @@ struct rtc_test_data { bool alarm_en; }; -struct platform_device *pdev[MAX_RTC_TEST]; +static struct platform_device *pdev[MAX_RTC_TEST]; static int test_rtc_read_alarm(struct device *dev, struct rtc_wkalrm *alrm) { From 5c8b84f410b3819d14cb1ebf32e4b3714b5a6e0b Mon Sep 17 00:00:00 2001 From: Johan Hovold Date: Wed, 4 Jul 2018 11:05:55 +0200 Subject: [PATCH 09/34] rtc: omap: fix potential crash on power off Do not set the system power-off callback and omap power-off rtc pointer until we're done setting up our device to avoid leaving stale pointers around after a late probe error. Fixes: 97ea1906b3c2 ("rtc: omap: Support ext_wakeup configuration") Cc: stable # 4.9 Cc: Marcin Niestroj Cc: Tony Lindgren Signed-off-by: Johan Hovold Acked-by: Tony Lindgren Reviewed-by: Marcin Niestroj Signed-off-by: Alexandre Belloni --- drivers/rtc/rtc-omap.c | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/drivers/rtc/rtc-omap.c b/drivers/rtc/rtc-omap.c index 39086398833e..c214b69a8787 100644 --- a/drivers/rtc/rtc-omap.c +++ b/drivers/rtc/rtc-omap.c @@ -861,13 +861,6 @@ static int omap_rtc_probe(struct platform_device *pdev) goto err; } - if (rtc->is_pmic_controller) { - if (!pm_power_off) { - omap_rtc_power_off_rtc = rtc; - pm_power_off = omap_rtc_power_off; - } - } - /* Support ext_wakeup pinconf */ rtc_pinctrl_desc.name = dev_name(&pdev->dev); @@ -884,6 +877,13 @@ static int omap_rtc_probe(struct platform_device *pdev) rtc_nvmem_register(rtc->rtc, &omap_rtc_nvmem_config); + if (rtc->is_pmic_controller) { + if (!pm_power_off) { + omap_rtc_power_off_rtc = rtc; + pm_power_off = omap_rtc_power_off; + } + } + return 0; err: From 551757eb052986ec81cebcc6301cc1c4f8dca938 Mon Sep 17 00:00:00 2001 From: Johan Hovold Date: Wed, 4 Jul 2018 11:05:56 +0200 Subject: [PATCH 10/34] rtc: omap: fix resource leak in registration error path Make sure to deregister the pin controller in case rtc registration fails. Fixes: 57072758623f ("rtc: omap: switch to rtc_register_device") Cc: stable # 4.14 Cc: Alexandre Belloni Signed-off-by: Johan Hovold Signed-off-by: Alexandre Belloni --- drivers/rtc/rtc-omap.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/drivers/rtc/rtc-omap.c b/drivers/rtc/rtc-omap.c index c214b69a8787..6a7b804c3074 100644 --- a/drivers/rtc/rtc-omap.c +++ b/drivers/rtc/rtc-omap.c @@ -873,7 +873,7 @@ static int omap_rtc_probe(struct platform_device *pdev) ret = rtc_register_device(rtc->rtc); if (ret) - goto err; + goto err_deregister_pinctrl; rtc_nvmem_register(rtc->rtc, &omap_rtc_nvmem_config); @@ -886,6 +886,8 @@ static int omap_rtc_probe(struct platform_device *pdev) return 0; +err_deregister_pinctrl: + pinctrl_unregister(rtc->pctldev); err: clk_disable_unprepare(rtc->clk); device_init_wakeup(&pdev->dev, false); From 4425070a5cfe634bc8e5657ff819a7a0c2d39d33 Mon Sep 17 00:00:00 2001 From: Johan Hovold Date: Wed, 4 Jul 2018 11:05:57 +0200 Subject: [PATCH 11/34] rtc: omap: add missing register lock in error path For completeness re-lock the registers also in the power-off error path. Signed-off-by: Johan Hovold Signed-off-by: Alexandre Belloni --- drivers/rtc/rtc-omap.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/rtc/rtc-omap.c b/drivers/rtc/rtc-omap.c index 6a7b804c3074..7f9ee559dd99 100644 --- a/drivers/rtc/rtc-omap.c +++ b/drivers/rtc/rtc-omap.c @@ -449,6 +449,7 @@ static void omap_rtc_power_off(void) if (tm2bcd(&tm) < 0) { dev_err(&rtc->rtc->dev, "power off failed\n"); + rtc->type->lock(rtc); return; } From b9cfb3d1200bcfd4b275f65fa84b2348560b9e30 Mon Sep 17 00:00:00 2001 From: Johan Hovold Date: Wed, 4 Jul 2018 11:05:58 +0200 Subject: [PATCH 12/34] rtc: omap: drop unnecessary register unlock around reads Drop unnecessary register write-unlock around two read accesses. Signed-off-by: Johan Hovold Signed-off-by: Alexandre Belloni --- drivers/rtc/rtc-omap.c | 4 ---- 1 file changed, 4 deletions(-) diff --git a/drivers/rtc/rtc-omap.c b/drivers/rtc/rtc-omap.c index 7f9ee559dd99..323ff55cc165 100644 --- a/drivers/rtc/rtc-omap.c +++ b/drivers/rtc/rtc-omap.c @@ -583,9 +583,7 @@ static int rtc_pinconf_get(struct pinctrl_dev *pctldev, u32 val; u16 arg = 0; - rtc->type->unlock(rtc); val = rtc_readl(rtc, OMAP_RTC_PMIC_REG); - rtc->type->lock(rtc); switch (param) { case PIN_CONFIG_INPUT_ENABLE: @@ -615,9 +613,7 @@ static int rtc_pinconf_set(struct pinctrl_dev *pctldev, u32 param_val; int i; - rtc->type->unlock(rtc); val = rtc_readl(rtc, OMAP_RTC_PMIC_REG); - rtc->type->lock(rtc); /* active low by default */ val |= OMAP_RTC_PMIC_EXT_WKUP_POL(pin); From fed0b1bd1b64a680874e8cfa4c3da8dfc01e143f Mon Sep 17 00:00:00 2001 From: Colin Ian King Date: Wed, 11 Jul 2018 09:33:12 +0100 Subject: [PATCH 13/34] rtc: m48t59: remove redundant pointer 'name' Pointer 'name' is being assigned but is never used hence it is redundant and can be removed. Cleans up clang warning: warning: variable 'name' set but not used [-Wunused-but-set-variable] Signed-off-by: Colin Ian King Signed-off-by: Alexandre Belloni --- drivers/rtc/rtc-m48t59.c | 4 ---- 1 file changed, 4 deletions(-) diff --git a/drivers/rtc/rtc-m48t59.c b/drivers/rtc/rtc-m48t59.c index 1053a406b3aa..ac9ca1042889 100644 --- a/drivers/rtc/rtc-m48t59.c +++ b/drivers/rtc/rtc-m48t59.c @@ -373,7 +373,6 @@ static int m48t59_rtc_probe(struct platform_device *pdev) struct m48t59_private *m48t59 = NULL; struct resource *res; int ret = -ENOMEM; - char *name; const struct rtc_class_ops *ops; struct nvmem_config nvmem_cfg = { .name = "m48t59-", @@ -448,17 +447,14 @@ static int m48t59_rtc_probe(struct platform_device *pdev) } switch (pdata->type) { case M48T59RTC_TYPE_M48T59: - name = "m48t59"; ops = &m48t59_rtc_ops; pdata->offset = 0x1ff0; break; case M48T59RTC_TYPE_M48T02: - name = "m48t02"; ops = &m48t02_rtc_ops; pdata->offset = 0x7f0; break; case M48T59RTC_TYPE_M48T08: - name = "m48t08"; ops = &m48t02_rtc_ops; pdata->offset = 0x1ff0; break; From 5089ea15baa9e7b0cb49f36881f2cb27bf281789 Mon Sep 17 00:00:00 2001 From: Arnd Bergmann Date: Wed, 11 Jul 2018 14:47:12 +0200 Subject: [PATCH 14/34] rtc: use ktime_get_real_ts64() instead of getnstimeofday64() getnstimeofday64() is just a wrapper around the ktime accessor, so we should use that directly. I considered using ktime_get_boottime_ts64() (to avoid leap second problems) or ktime_get_real_seconds() (to simplify the calculation, but in the end concluded that the existing interface is probably the most appropriate in this case. Signed-off-by: Arnd Bergmann Signed-off-by: Alexandre Belloni --- drivers/rtc/class.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/rtc/class.c b/drivers/rtc/class.c index d37588f08055..7fa32c922617 100644 --- a/drivers/rtc/class.c +++ b/drivers/rtc/class.c @@ -68,7 +68,7 @@ static int rtc_suspend(struct device *dev) return 0; } - getnstimeofday64(&old_system); + ktime_get_real_ts64(&old_system); old_rtc.tv_sec = rtc_tm_to_time64(&tm); @@ -110,7 +110,7 @@ static int rtc_resume(struct device *dev) return 0; /* snapshot the current rtc and system time at resume */ - getnstimeofday64(&new_system); + ktime_get_real_ts64(&new_system); err = rtc_read_time(rtc, &tm); if (err < 0) { pr_debug("%s: fail to read rtc time\n", dev_name(&rtc->dev)); From 146a552c67b1adae50065d2c8f00169302f26c44 Mon Sep 17 00:00:00 2001 From: Giulio Benetti Date: Wed, 16 May 2018 23:08:39 +0200 Subject: [PATCH 15/34] rtc: ds1307: fix data pointer to m41t0 data field points to m41t00, instead it should point to m41t0. Driver works correctly because on both cases(m41t0 and m41t00) chip_desc are equal. Point to right enum m41t0 instead of m41t00. Signed-off-by: Giulio Benetti Signed-off-by: Alexandre Belloni --- drivers/rtc/rtc-ds1307.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/rtc/rtc-ds1307.c b/drivers/rtc/rtc-ds1307.c index e9ec4160d7f6..aa4a161bae98 100644 --- a/drivers/rtc/rtc-ds1307.c +++ b/drivers/rtc/rtc-ds1307.c @@ -299,7 +299,7 @@ static const struct of_device_id ds1307_of_match[] = { }, { .compatible = "st,m41t0", - .data = (void *)m41t00 + .data = (void *)m41t0 }, { .compatible = "st,m41t00", From 7e580769b79f1df2ac67cf935ee95ac1d42b8144 Mon Sep 17 00:00:00 2001 From: Giulio Benetti Date: Wed, 16 May 2018 23:08:40 +0200 Subject: [PATCH 16/34] rtc: ds1307: support m41t11 variant The m41t11 variant is very similar to the already supported m41t00 and m41t0, but it has also 56 bytes of NVRAM. Add it to driver taking into account NVRAM section. Signed-off-by: Giulio Benetti Reviewed-by: Rob Herring Signed-off-by: Alexandre Belloni --- .../devicetree/bindings/rtc/rtc-ds1307.txt | 1 + drivers/rtc/rtc-ds1307.c | 14 ++++++++++++++ 2 files changed, 15 insertions(+) diff --git a/Documentation/devicetree/bindings/rtc/rtc-ds1307.txt b/Documentation/devicetree/bindings/rtc/rtc-ds1307.txt index d28d6e7f6ae8..ce6469c1a516 100644 --- a/Documentation/devicetree/bindings/rtc/rtc-ds1307.txt +++ b/Documentation/devicetree/bindings/rtc/rtc-ds1307.txt @@ -13,6 +13,7 @@ Required properties: "maxim,ds3231", "st,m41t0", "st,m41t00", + "st,m41t11", "microchip,mcp7940x", "microchip,mcp7941x", "pericom,pt7c4338", diff --git a/drivers/rtc/rtc-ds1307.c b/drivers/rtc/rtc-ds1307.c index aa4a161bae98..0162a600ff1b 100644 --- a/drivers/rtc/rtc-ds1307.c +++ b/drivers/rtc/rtc-ds1307.c @@ -44,6 +44,7 @@ enum ds_type { ds_3231, m41t0, m41t00, + m41t11, mcp794xx, rx_8025, rx_8130, @@ -227,6 +228,11 @@ static const struct chip_desc chips[last_ds_type] = { .irq_handler = rx8130_irq, .rtc_ops = &rx8130_rtc_ops, }, + [m41t11] = { + /* this is battery backed SRAM */ + .nvram_offset = 8, + .nvram_size = 56, + }, [mcp794xx] = { .alarm = 1, /* this is battery backed SRAM */ @@ -249,6 +255,7 @@ static const struct i2c_device_id ds1307_id[] = { { "ds3231", ds_3231 }, { "m41t0", m41t0 }, { "m41t00", m41t00 }, + { "m41t11", m41t11 }, { "mcp7940x", mcp794xx }, { "mcp7941x", mcp794xx }, { "pt7c4338", ds_1307 }, @@ -305,6 +312,10 @@ static const struct of_device_id ds1307_of_match[] = { .compatible = "st,m41t00", .data = (void *)m41t00 }, + { + .compatible = "st,m41t11", + .data = (void *)m41t11 + }, { .compatible = "microchip,mcp7940x", .data = (void *)mcp794xx @@ -347,6 +358,7 @@ static const struct acpi_device_id ds1307_acpi_ids[] = { { .id = "DS3231", .driver_data = ds_3231 }, { .id = "M41T0", .driver_data = m41t0 }, { .id = "M41T00", .driver_data = m41t00 }, + { .id = "M41T11", .driver_data = m41t11 }, { .id = "MCP7940X", .driver_data = mcp794xx }, { .id = "MCP7941X", .driver_data = mcp794xx }, { .id = "PT7C4338", .driver_data = ds_1307 }, @@ -1576,6 +1588,7 @@ read_rtc: case ds_1307: case m41t0: case m41t00: + case m41t11: /* clock halted? turn it on, so clock can tick. */ if (tmp & DS1307_BIT_CH) { regmap_write(ds1307->regmap, DS1307_REG_SECS, 0); @@ -1641,6 +1654,7 @@ read_rtc: case ds_1340: case m41t0: case m41t00: + case m41t11: /* * NOTE: ignores century bits; fix before deploying * systems that will run through year 2100. From 1f28231c66b5381c07b4ff0ca919387d060d6f1b Mon Sep 17 00:00:00 2001 From: Alexandre Belloni Date: Wed, 25 Jul 2018 15:17:44 +0200 Subject: [PATCH 17/34] rtc: sa1100: don't set PIE frequency It doesn't make sense to set the PIE frequency from the driver. Let userspace do its job. Signed-off-by: Alexandre Belloni --- drivers/rtc/rtc-sa1100.c | 1 - 1 file changed, 1 deletion(-) diff --git a/drivers/rtc/rtc-sa1100.c b/drivers/rtc/rtc-sa1100.c index ed71d1113627..304d905cb23f 100644 --- a/drivers/rtc/rtc-sa1100.c +++ b/drivers/rtc/rtc-sa1100.c @@ -224,7 +224,6 @@ int sa1100_rtc_init(struct platform_device *pdev, struct sa1100_rtc *info) info->rtc = rtc; rtc->max_user_freq = RTC_FREQ; - rtc_irq_set_freq(rtc, NULL, RTC_FREQ); /* Fix for a nasty initialization problem the in SA11xx RTSR register. * See also the comments in sa1100_rtc_interrupt(). From ec623ff014c4e9c52d8ebf068d9801f5f9ab7348 Mon Sep 17 00:00:00 2001 From: Alexandre Belloni Date: Wed, 25 Jul 2018 16:45:39 +0200 Subject: [PATCH 18/34] rtc: sh: remove dead code Since commit 80d4bb515b78 ("RTC: Cleanup rtc_class_ops->irq_set_state") and commit 696160fec162 ("RTC: Cleanup rtc_class_ops->irq_set_freq()"), sh_rtc_irq_set_state and sh_rtc_irq_set_freq are never called. Remove them along with task handling. Signed-off-by: Alexandre Belloni --- drivers/rtc/rtc-sh.c | 89 +------------------------------------------- 1 file changed, 1 insertion(+), 88 deletions(-) diff --git a/drivers/rtc/rtc-sh.c b/drivers/rtc/rtc-sh.c index 4f98543d1ea5..abbce362f4df 100644 --- a/drivers/rtc/rtc-sh.c +++ b/drivers/rtc/rtc-sh.c @@ -143,7 +143,6 @@ static int __sh_rtc_alarm(struct sh_rtc *rtc) static int __sh_rtc_periodic(struct sh_rtc *rtc) { struct rtc_device *rtc_dev = rtc->rtc_dev; - struct rtc_task *irq_task; unsigned int tmp, pending; tmp = readb(rtc->regbase + RCR2); @@ -160,14 +159,7 @@ static int __sh_rtc_periodic(struct sh_rtc *rtc) else { if (rtc->periodic_freq & PF_HP) rtc->periodic_freq |= PF_COUNT; - if (rtc->periodic_freq & PF_KOU) { - spin_lock(&rtc_dev->irq_task_lock); - irq_task = rtc_dev->irq_task; - if (irq_task) - irq_task->func(irq_task->private_data); - spin_unlock(&rtc_dev->irq_task_lock); - } else - rtc_update_irq(rtc->rtc_dev, 1, RTC_PF | RTC_IRQF); + rtc_update_irq(rtc->rtc_dev, 1, RTC_PF | RTC_IRQF); } return pending; @@ -223,81 +215,6 @@ static irqreturn_t sh_rtc_shared(int irq, void *dev_id) return IRQ_RETVAL(ret); } -static int sh_rtc_irq_set_state(struct device *dev, int enable) -{ - struct sh_rtc *rtc = dev_get_drvdata(dev); - unsigned int tmp; - - spin_lock_irq(&rtc->lock); - - tmp = readb(rtc->regbase + RCR2); - - if (enable) { - rtc->periodic_freq |= PF_KOU; - tmp &= ~RCR2_PEF; /* Clear PES bit */ - tmp |= (rtc->periodic_freq & ~PF_HP); /* Set PES2-0 */ - } else { - rtc->periodic_freq &= ~PF_KOU; - tmp &= ~(RCR2_PESMASK | RCR2_PEF); - } - - writeb(tmp, rtc->regbase + RCR2); - - spin_unlock_irq(&rtc->lock); - - return 0; -} - -static int sh_rtc_irq_set_freq(struct device *dev, int freq) -{ - struct sh_rtc *rtc = dev_get_drvdata(dev); - int tmp, ret = 0; - - spin_lock_irq(&rtc->lock); - tmp = rtc->periodic_freq & PF_MASK; - - switch (freq) { - case 0: - rtc->periodic_freq = 0x00; - break; - case 1: - rtc->periodic_freq = 0x60; - break; - case 2: - rtc->periodic_freq = 0x50; - break; - case 4: - rtc->periodic_freq = 0x40; - break; - case 8: - rtc->periodic_freq = 0x30 | PF_HP; - break; - case 16: - rtc->periodic_freq = 0x30; - break; - case 32: - rtc->periodic_freq = 0x20 | PF_HP; - break; - case 64: - rtc->periodic_freq = 0x20; - break; - case 128: - rtc->periodic_freq = 0x10 | PF_HP; - break; - case 256: - rtc->periodic_freq = 0x10; - break; - default: - ret = -ENOTSUPP; - } - - if (ret == 0) - rtc->periodic_freq |= tmp; - - spin_unlock_irq(&rtc->lock); - return ret; -} - static inline void sh_rtc_setaie(struct device *dev, unsigned int enable) { struct sh_rtc *rtc = dev_get_drvdata(dev); @@ -674,8 +591,6 @@ static int __init sh_rtc_probe(struct platform_device *pdev) platform_set_drvdata(pdev, rtc); /* everything disabled by default */ - sh_rtc_irq_set_freq(&pdev->dev, 0); - sh_rtc_irq_set_state(&pdev->dev, 0); sh_rtc_setaie(&pdev->dev, 0); sh_rtc_setcie(&pdev->dev, 0); @@ -707,8 +622,6 @@ static int __exit sh_rtc_remove(struct platform_device *pdev) { struct sh_rtc *rtc = platform_get_drvdata(pdev); - sh_rtc_irq_set_state(&pdev->dev, 0); - sh_rtc_setaie(&pdev->dev, 0); sh_rtc_setcie(&pdev->dev, 0); From 1560d0848a1a84db6c1d9b17c14273c0dae41828 Mon Sep 17 00:00:00 2001 From: Alexandre Belloni Date: Wed, 25 Jul 2018 14:34:29 +0200 Subject: [PATCH 19/34] rtc: remove rtc_irq_register/rtc_irq_unregister The rtc_irq_* interface is not used from outside the RTC subsytem since 2016. Signed-off-by: Alexandre Belloni --- drivers/rtc/interface.c | 33 --------------------------------- include/linux/rtc.h | 4 ---- 2 files changed, 37 deletions(-) diff --git a/drivers/rtc/interface.c b/drivers/rtc/interface.c index 6d4012dd6922..2b1b9a0b9f8a 100644 --- a/drivers/rtc/interface.c +++ b/drivers/rtc/interface.c @@ -719,39 +719,6 @@ void rtc_class_close(struct rtc_device *rtc) } EXPORT_SYMBOL_GPL(rtc_class_close); -int rtc_irq_register(struct rtc_device *rtc, struct rtc_task *task) -{ - int retval = -EBUSY; - - if (task == NULL || task->func == NULL) - return -EINVAL; - - /* Cannot register while the char dev is in use */ - if (test_and_set_bit_lock(RTC_DEV_BUSY, &rtc->flags)) - return -EBUSY; - - spin_lock_irq(&rtc->irq_task_lock); - if (rtc->irq_task == NULL) { - rtc->irq_task = task; - retval = 0; - } - spin_unlock_irq(&rtc->irq_task_lock); - - clear_bit_unlock(RTC_DEV_BUSY, &rtc->flags); - - return retval; -} -EXPORT_SYMBOL_GPL(rtc_irq_register); - -void rtc_irq_unregister(struct rtc_device *rtc, struct rtc_task *task) -{ - spin_lock_irq(&rtc->irq_task_lock); - if (rtc->irq_task == task) - rtc->irq_task = NULL; - spin_unlock_irq(&rtc->irq_task_lock); -} -EXPORT_SYMBOL_GPL(rtc_irq_unregister); - static int rtc_update_hrtimer(struct rtc_device *rtc, int enabled) { /* diff --git a/include/linux/rtc.h b/include/linux/rtc.h index 6268208760e9..f868d6b619ab 100644 --- a/include/linux/rtc.h +++ b/include/linux/rtc.h @@ -204,10 +204,6 @@ extern void rtc_update_irq(struct rtc_device *rtc, extern struct rtc_device *rtc_class_open(const char *name); extern void rtc_class_close(struct rtc_device *rtc); -extern int rtc_irq_register(struct rtc_device *rtc, - struct rtc_task *task); -extern void rtc_irq_unregister(struct rtc_device *rtc, - struct rtc_task *task); extern int rtc_irq_set_state(struct rtc_device *rtc, struct rtc_task *task, int enabled); extern int rtc_irq_set_freq(struct rtc_device *rtc, From acecb3ad8b21a519ce4ad728106d45d4e978bb56 Mon Sep 17 00:00:00 2001 From: Alexandre Belloni Date: Wed, 25 Jul 2018 14:58:10 +0200 Subject: [PATCH 20/34] rtc: remove irq_task and irq_task_lock There is no way to set a periodic task anymore, remove task pointer and lock. Signed-off-by: Alexandre Belloni --- drivers/rtc/class.c | 1 - drivers/rtc/interface.c | 50 +++++++++-------------------------------- include/linux/rtc.h | 2 -- 3 files changed, 10 insertions(+), 43 deletions(-) diff --git a/drivers/rtc/class.c b/drivers/rtc/class.c index 7fa32c922617..0fca4d74c76b 100644 --- a/drivers/rtc/class.c +++ b/drivers/rtc/class.c @@ -172,7 +172,6 @@ static struct rtc_device *rtc_allocate_device(void) mutex_init(&rtc->ops_lock); spin_lock_init(&rtc->irq_lock); - spin_lock_init(&rtc->irq_task_lock); init_waitqueue_head(&rtc->irq_queue); /* Init timerqueue */ diff --git a/drivers/rtc/interface.c b/drivers/rtc/interface.c index 2b1b9a0b9f8a..ae0d67610c7b 100644 --- a/drivers/rtc/interface.c +++ b/drivers/rtc/interface.c @@ -605,12 +605,6 @@ void rtc_handle_legacy_irq(struct rtc_device *rtc, int num, int mode) rtc->irq_data = (rtc->irq_data + (num << 8)) | (RTC_IRQF|mode); spin_unlock_irqrestore(&rtc->irq_lock, flags); - /* call the task func */ - spin_lock_irqsave(&rtc->irq_task_lock, flags); - if (rtc->irq_task) - rtc->irq_task->func(rtc->irq_task->private_data); - spin_unlock_irqrestore(&rtc->irq_task_lock, flags); - wake_up_interruptible(&rtc->irq_queue); kill_fasync(&rtc->async_queue, SIGIO, POLL_IN); } @@ -750,28 +744,16 @@ static int rtc_update_hrtimer(struct rtc_device *rtc, int enabled) * Context: any * * Note that rtc_irq_set_freq() should previously have been used to - * specify the desired frequency of periodic IRQ task->func() callbacks. + * specify the desired frequency of periodic IRQ. */ int rtc_irq_set_state(struct rtc_device *rtc, struct rtc_task *task, int enabled) { int err = 0; - unsigned long flags; -retry: - spin_lock_irqsave(&rtc->irq_task_lock, flags); - if (rtc->irq_task != NULL && task == NULL) - err = -EBUSY; - else if (rtc->irq_task != task) - err = -EACCES; - else { - if (rtc_update_hrtimer(rtc, enabled) < 0) { - spin_unlock_irqrestore(&rtc->irq_task_lock, flags); - cpu_relax(); - goto retry; - } - rtc->pie_enabled = enabled; - } - spin_unlock_irqrestore(&rtc->irq_task_lock, flags); + while (rtc_update_hrtimer(rtc, enabled) < 0) + cpu_relax(); + + rtc->pie_enabled = enabled; trace_rtc_irq_set_state(enabled, err); return err; @@ -782,7 +764,7 @@ EXPORT_SYMBOL_GPL(rtc_irq_set_state); * rtc_irq_set_freq - set 2^N Hz periodic IRQ frequency for IRQ * @rtc: the rtc device * @task: currently registered with rtc_irq_register() - * @freq: positive frequency with which task->func() will be called + * @freq: positive frequency * Context: any * * Note that rtc_irq_set_state() is used to enable or disable the @@ -791,25 +773,13 @@ EXPORT_SYMBOL_GPL(rtc_irq_set_state); int rtc_irq_set_freq(struct rtc_device *rtc, struct rtc_task *task, int freq) { int err = 0; - unsigned long flags; if (freq <= 0 || freq > RTC_MAX_FREQ) return -EINVAL; -retry: - spin_lock_irqsave(&rtc->irq_task_lock, flags); - if (rtc->irq_task != NULL && task == NULL) - err = -EBUSY; - else if (rtc->irq_task != task) - err = -EACCES; - else { - rtc->irq_freq = freq; - if (rtc->pie_enabled && rtc_update_hrtimer(rtc, 1) < 0) { - spin_unlock_irqrestore(&rtc->irq_task_lock, flags); - cpu_relax(); - goto retry; - } - } - spin_unlock_irqrestore(&rtc->irq_task_lock, flags); + + rtc->irq_freq = freq; + while (rtc->pie_enabled && rtc_update_hrtimer(rtc, 1) < 0) + cpu_relax(); trace_rtc_irq_set_freq(freq, err); return err; diff --git a/include/linux/rtc.h b/include/linux/rtc.h index f868d6b619ab..8cc23fdfd4ee 100644 --- a/include/linux/rtc.h +++ b/include/linux/rtc.h @@ -121,8 +121,6 @@ struct rtc_device { wait_queue_head_t irq_queue; struct fasync_struct *async_queue; - struct rtc_task *irq_task; - spinlock_t irq_task_lock; int irq_freq; int max_user_freq; From 8719d3c9188b38db462a77ecd8c7a8e25e7e8c4c Mon Sep 17 00:00:00 2001 From: Alexandre Belloni Date: Wed, 25 Jul 2018 15:07:09 +0200 Subject: [PATCH 21/34] rtc: simplify rtc_irq_set_state/rtc_irq_set_freq The PIE doesn't handle tasks anymore, remove the pointer from the interface. Signed-off-by: Alexandre Belloni --- drivers/rtc/interface.c | 4 ++-- drivers/rtc/rtc-dev.c | 8 ++++---- include/linux/rtc.h | 6 ++---- 3 files changed, 8 insertions(+), 10 deletions(-) diff --git a/drivers/rtc/interface.c b/drivers/rtc/interface.c index ae0d67610c7b..76eb3a2957cc 100644 --- a/drivers/rtc/interface.c +++ b/drivers/rtc/interface.c @@ -746,7 +746,7 @@ static int rtc_update_hrtimer(struct rtc_device *rtc, int enabled) * Note that rtc_irq_set_freq() should previously have been used to * specify the desired frequency of periodic IRQ. */ -int rtc_irq_set_state(struct rtc_device *rtc, struct rtc_task *task, int enabled) +int rtc_irq_set_state(struct rtc_device *rtc, int enabled) { int err = 0; @@ -770,7 +770,7 @@ EXPORT_SYMBOL_GPL(rtc_irq_set_state); * Note that rtc_irq_set_state() is used to enable or disable the * periodic IRQs. */ -int rtc_irq_set_freq(struct rtc_device *rtc, struct rtc_task *task, int freq) +int rtc_irq_set_freq(struct rtc_device *rtc, int freq) { int err = 0; diff --git a/drivers/rtc/rtc-dev.c b/drivers/rtc/rtc-dev.c index efa221e8bc22..43d962a9c210 100644 --- a/drivers/rtc/rtc-dev.c +++ b/drivers/rtc/rtc-dev.c @@ -341,11 +341,11 @@ static long rtc_dev_ioctl(struct file *file, return rtc_set_time(rtc, &tm); case RTC_PIE_ON: - err = rtc_irq_set_state(rtc, NULL, 1); + err = rtc_irq_set_state(rtc, 1); break; case RTC_PIE_OFF: - err = rtc_irq_set_state(rtc, NULL, 0); + err = rtc_irq_set_state(rtc, 0); break; case RTC_AIE_ON: @@ -365,7 +365,7 @@ static long rtc_dev_ioctl(struct file *file, return rtc_update_irq_enable(rtc, 0); case RTC_IRQP_SET: - err = rtc_irq_set_freq(rtc, NULL, arg); + err = rtc_irq_set_freq(rtc, arg); break; case RTC_IRQP_READ: @@ -427,7 +427,7 @@ static int rtc_dev_release(struct inode *inode, struct file *file) /* Keep ioctl until all drivers are converted */ rtc_dev_ioctl(file, RTC_UIE_OFF, 0); rtc_update_irq_enable(rtc, 0); - rtc_irq_set_state(rtc, NULL, 0); + rtc_irq_set_state(rtc, 0); clear_bit_unlock(RTC_DEV_BUSY, &rtc->flags); return 0; diff --git a/include/linux/rtc.h b/include/linux/rtc.h index 8cc23fdfd4ee..bf4d375025d1 100644 --- a/include/linux/rtc.h +++ b/include/linux/rtc.h @@ -202,10 +202,8 @@ extern void rtc_update_irq(struct rtc_device *rtc, extern struct rtc_device *rtc_class_open(const char *name); extern void rtc_class_close(struct rtc_device *rtc); -extern int rtc_irq_set_state(struct rtc_device *rtc, - struct rtc_task *task, int enabled); -extern int rtc_irq_set_freq(struct rtc_device *rtc, - struct rtc_task *task, int freq); +extern int rtc_irq_set_state(struct rtc_device *rtc, int enabled); +extern int rtc_irq_set_freq(struct rtc_device *rtc, int freq); extern int rtc_update_irq_enable(struct rtc_device *rtc, unsigned int enabled); extern int rtc_alarm_irq_enable(struct rtc_device *rtc, unsigned int enabled); extern int rtc_dev_update_irq_enable_emul(struct rtc_device *rtc, From c842697c741e9dbf825e07d4c2724685d6464bd0 Mon Sep 17 00:00:00 2001 From: Alexandre Belloni Date: Wed, 25 Jul 2018 16:19:41 +0200 Subject: [PATCH 22/34] rtc: unexport rtc_irq_set_* Make the rtc_irq_set interface internale to the RTC subsystem. Signed-off-by: Alexandre Belloni --- drivers/rtc/interface.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/drivers/rtc/interface.c b/drivers/rtc/interface.c index 76eb3a2957cc..d0983ed6c842 100644 --- a/drivers/rtc/interface.c +++ b/drivers/rtc/interface.c @@ -758,7 +758,6 @@ int rtc_irq_set_state(struct rtc_device *rtc, int enabled) trace_rtc_irq_set_state(enabled, err); return err; } -EXPORT_SYMBOL_GPL(rtc_irq_set_state); /** * rtc_irq_set_freq - set 2^N Hz periodic IRQ frequency for IRQ @@ -784,7 +783,6 @@ int rtc_irq_set_freq(struct rtc_device *rtc, int freq) trace_rtc_irq_set_freq(freq, err); return err; } -EXPORT_SYMBOL_GPL(rtc_irq_set_freq); /** * rtc_timer_enqueue - Adds a rtc_timer to the rtc_device timerqueue From 8856541557f3626beec43aa0821b2e0f031f0153 Mon Sep 17 00:00:00 2001 From: Anders Roxell Date: Fri, 27 Jul 2018 17:10:15 +0200 Subject: [PATCH 23/34] rtc: sh: remove unused variable rtc_dev MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit When building rtc-sh, rtc_dev isn't used in function __sh_rtc_periodic. drivers/rtc/rtc-sh.c: In function ‘__sh_rtc_periodic’: drivers/rtc/rtc-sh.c:146:21: warning: unused variable ‘rtc_dev’ [-Wunused-variable] struct rtc_device *rtc_dev = rtc->rtc_dev; ^~~~~~~ Remove the declaration of rtc_dev to dispose the warning. Fixes: ec623ff014c4 ("rtc: sh: remove dead code") Signed-off-by: Anders Roxell Signed-off-by: Alexandre Belloni --- drivers/rtc/rtc-sh.c | 1 - 1 file changed, 1 deletion(-) diff --git a/drivers/rtc/rtc-sh.c b/drivers/rtc/rtc-sh.c index abbce362f4df..0fbd36e2afa6 100644 --- a/drivers/rtc/rtc-sh.c +++ b/drivers/rtc/rtc-sh.c @@ -142,7 +142,6 @@ static int __sh_rtc_alarm(struct sh_rtc *rtc) static int __sh_rtc_periodic(struct sh_rtc *rtc) { - struct rtc_device *rtc_dev = rtc->rtc_dev; unsigned int tmp, pending; tmp = readb(rtc->regbase + RCR2); From ec9cf1b7a6af2c0cffaa887351e7c7acced5290e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alvin=20=C5=A0ipraga?= Date: Sun, 15 Jul 2018 23:31:53 +0200 Subject: [PATCH 24/34] rtc: pcf85063: preserve control register value between stop and start MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Fix a bug that caused the Control_1 register to get zeroed whenever the RTC time is set. The problem occurred between stopping and starting the RTC clock, wherein the return value of a successful I2C write function would get written to the register. Also update variables of the start and stop functions to be more consistent with the rest of the driver. Signed-off-by: Alvin Šipraga Signed-off-by: Alexandre Belloni --- drivers/rtc/rtc-pcf85063.c | 21 +++++++++++---------- 1 file changed, 11 insertions(+), 10 deletions(-) diff --git a/drivers/rtc/rtc-pcf85063.c b/drivers/rtc/rtc-pcf85063.c index 49bcbb3d4a69..283c2335b01b 100644 --- a/drivers/rtc/rtc-pcf85063.c +++ b/drivers/rtc/rtc-pcf85063.c @@ -43,37 +43,38 @@ static struct i2c_driver pcf85063_driver; static int pcf85063_stop_clock(struct i2c_client *client, u8 *ctrl1) { - s32 ret; + int rc; + u8 reg; - ret = i2c_smbus_read_byte_data(client, PCF85063_REG_CTRL1); - if (ret < 0) { + rc = i2c_smbus_read_byte_data(client, PCF85063_REG_CTRL1); + if (rc < 0) { dev_err(&client->dev, "Failing to stop the clock\n"); return -EIO; } /* stop the clock */ - ret |= PCF85063_REG_CTRL1_STOP; + reg = rc | PCF85063_REG_CTRL1_STOP; - ret = i2c_smbus_write_byte_data(client, PCF85063_REG_CTRL1, ret); - if (ret < 0) { + rc = i2c_smbus_write_byte_data(client, PCF85063_REG_CTRL1, reg); + if (rc < 0) { dev_err(&client->dev, "Failing to stop the clock\n"); return -EIO; } - *ctrl1 = ret; + *ctrl1 = reg; return 0; } static int pcf85063_start_clock(struct i2c_client *client, u8 ctrl1) { - s32 ret; + int rc; /* start the clock */ ctrl1 &= ~PCF85063_REG_CTRL1_STOP; - ret = i2c_smbus_write_byte_data(client, PCF85063_REG_CTRL1, ctrl1); - if (ret < 0) { + rc = i2c_smbus_write_byte_data(client, PCF85063_REG_CTRL1, ctrl1); + if (rc < 0) { dev_err(&client->dev, "Failing to start the clock\n"); return -EIO; } From f7430151d8a324b36850fa0edf41e538f28ddf61 Mon Sep 17 00:00:00 2001 From: Alexandre Belloni Date: Thu, 26 Jul 2018 15:40:55 +0200 Subject: [PATCH 25/34] char: rtc: remove task handling Since commit 9e7002a70e42 ("char: rtc: remove unused rtc_control() API"), it is not possible to set a callback anymore, remove its handling from the interrupt handler. Cc: Arnd Bergmann Cc: Greg Kroah-Hartman Signed-off-by: Alexandre Belloni Acked-by: Greg Kroah-Hartman Signed-off-by: Alexandre Belloni --- drivers/char/rtc.c | 13 ------------- 1 file changed, 13 deletions(-) diff --git a/drivers/char/rtc.c b/drivers/char/rtc.c index 94fedeeec035..4948c8bda6b1 100644 --- a/drivers/char/rtc.c +++ b/drivers/char/rtc.c @@ -193,14 +193,6 @@ static unsigned long rtc_freq; /* Current periodic IRQ rate */ static unsigned long rtc_irq_data; /* our output to the world */ static unsigned long rtc_max_user_freq = 64; /* > this, need CAP_SYS_RESOURCE */ -#ifdef RTC_IRQ -/* - * rtc_task_lock nests inside rtc_lock. - */ -static DEFINE_SPINLOCK(rtc_task_lock); -static rtc_task_t *rtc_callback; -#endif - /* * If this driver ever becomes modularised, it will be really nice * to make the epoch retain its value across module reload... @@ -264,11 +256,6 @@ static irqreturn_t rtc_interrupt(int irq, void *dev_id) spin_unlock(&rtc_lock); - /* Now do the rest of the actions */ - spin_lock(&rtc_task_lock); - if (rtc_callback) - rtc_callback->func(rtc_callback->private_data); - spin_unlock(&rtc_task_lock); wake_up_interruptible(&rtc_wait); kill_fasync(&rtc_async_queue, SIGIO, POLL_IN); From 5a5ba10f44fa1cd081cec38389e1b47f438fe25b Mon Sep 17 00:00:00 2001 From: Alexandre Belloni Date: Thu, 26 Jul 2018 15:40:56 +0200 Subject: [PATCH 26/34] rtc: remove struct rtc_task Include rtc_task members directly in rtc_timer member. Signed-off-by: Alexandre Belloni --- drivers/rtc/interface.c | 8 ++++---- include/linux/rtc.h | 9 ++------- 2 files changed, 6 insertions(+), 11 deletions(-) diff --git a/drivers/rtc/interface.c b/drivers/rtc/interface.c index d0983ed6c842..a962540faf2e 100644 --- a/drivers/rtc/interface.c +++ b/drivers/rtc/interface.c @@ -912,8 +912,8 @@ again: timerqueue_del(&rtc->timerqueue, &timer->node); trace_rtc_timer_dequeue(timer); timer->enabled = 0; - if (timer->task.func) - timer->task.func(timer->task.private_data); + if (timer->func) + timer->func(timer->private_data); trace_rtc_timer_fired(timer); /* Re-add/fwd periodic timers */ @@ -968,8 +968,8 @@ void rtc_timer_init(struct rtc_timer *timer, void (*f)(void *p), void *data) { timerqueue_init(&timer->node); timer->enabled = 0; - timer->task.func = f; - timer->task.private_data = data; + timer->func = f; + timer->private_data = data; } /* rtc_timer_start - Sets an rtc_timer to fire in the future diff --git a/include/linux/rtc.h b/include/linux/rtc.h index bf4d375025d1..6aedc30003e7 100644 --- a/include/linux/rtc.h +++ b/include/linux/rtc.h @@ -87,16 +87,11 @@ struct rtc_class_ops { int (*set_offset)(struct device *, long offset); }; -typedef struct rtc_task { - void (*func)(void *private_data); - void *private_data; -} rtc_task_t; - - struct rtc_timer { - struct rtc_task task; struct timerqueue_node node; ktime_t period; + void (*func)(void *private_data); + void *private_data; int enabled; }; From a0a1a1ba303261d25814d11a05008d2931a69a8b Mon Sep 17 00:00:00 2001 From: Denis Osterland Date: Tue, 24 Jul 2018 11:31:22 +0000 Subject: [PATCH 27/34] rtc: sysfs: facilitate attribute add to rtc device This patches addresses following problem: rtc_allocate_device devm_device_add_group <-- kernel oops / null pointer, because sysfs entry does not yet exist rtc_register_device rc = devm_device_add_group if (rc) return rc; <-- forbidden to return error code after device register This patch adds rtc_add_group(s) functions. The functions store the sum of attribute groups as device resource. Signed-off-by: Denis Osterland Signed-off-by: Alexandre Belloni --- drivers/rtc/rtc-core.h | 14 ++++++++++++++ drivers/rtc/rtc-sysfs.c | 43 +++++++++++++++++++++++++++++++++++++++++ 2 files changed, 57 insertions(+) diff --git a/drivers/rtc/rtc-core.h b/drivers/rtc/rtc-core.h index 0abf98983e13..ccc17a2e293d 100644 --- a/drivers/rtc/rtc-core.h +++ b/drivers/rtc/rtc-core.h @@ -40,9 +40,23 @@ static inline void rtc_proc_del_device(struct rtc_device *rtc) #ifdef CONFIG_RTC_INTF_SYSFS const struct attribute_group **rtc_get_dev_attribute_groups(void); +int rtc_add_group(struct rtc_device *rtc, const struct attribute_group *grp); +int rtc_add_groups(struct rtc_device *rtc, const struct attribute_group **grps); #else static inline const struct attribute_group **rtc_get_dev_attribute_groups(void) { return NULL; } + +static inline +int rtc_add_group(struct rtc_device *rtc, const struct attribute_group *grp) +{ + return 0; +} + +static inline +int rtc_add_groups(struct rtc_device *rtc, const struct attribute_group **grps) +{ + return 0; +} #endif diff --git a/drivers/rtc/rtc-sysfs.c b/drivers/rtc/rtc-sysfs.c index 454da38c6012..f1ff30ade534 100644 --- a/drivers/rtc/rtc-sysfs.c +++ b/drivers/rtc/rtc-sysfs.c @@ -317,3 +317,46 @@ const struct attribute_group **rtc_get_dev_attribute_groups(void) { return rtc_attr_groups; } + +int rtc_add_groups(struct rtc_device *rtc, const struct attribute_group **grps) +{ + size_t old_cnt = 0, add_cnt = 0, new_cnt; + const struct attribute_group **groups, **old; + + if (rtc->registered) + return -EINVAL; + if (!grps) + return -EINVAL; + + groups = rtc->dev.groups; + if (groups) + for (; *groups; groups++) + old_cnt++; + + for (groups = grps; *groups; groups++) + add_cnt++; + + new_cnt = old_cnt + add_cnt + 1; + groups = devm_kcalloc(&rtc->dev, new_cnt, sizeof(*groups), GFP_KERNEL); + if (IS_ERR_OR_NULL(groups)) + return PTR_ERR(groups); + memcpy(groups, rtc->dev.groups, old_cnt * sizeof(*groups)); + memcpy(groups + old_cnt, grps, add_cnt * sizeof(*groups)); + groups[old_cnt + add_cnt] = NULL; + + old = rtc->dev.groups; + rtc->dev.groups = groups; + if (old && old != rtc_attr_groups) + devm_kfree(&rtc->dev, old); + + return 0; +} +EXPORT_SYMBOL(rtc_add_groups); + +int rtc_add_group(struct rtc_device *rtc, const struct attribute_group *grp) +{ + const struct attribute_group *groups[] = { grp, NULL }; + + return rtc_add_groups(rtc, groups); +} +EXPORT_SYMBOL(rtc_add_group); From dd35bdb0768f1d03b043c4ba704fe9760eaa5891 Mon Sep 17 00:00:00 2001 From: Michael Grzeschik Date: Tue, 24 Jul 2018 11:31:21 +0000 Subject: [PATCH 28/34] rtc: isl1208: add support for isl1219 with tamper detection We add support for the ISL1219 chip that got an integrated tamper detection function. This patch implements the feature by adding an additional timestamp0 file to sysfs device path. This file contains seconds since epoch, if an event occurred, or is empty, if none occurred. Signed-off-by: Michael Grzeschik Signed-off-by: Denis Osterland Signed-off-by: Alexandre Belloni --- drivers/rtc/rtc-isl1208.c | 131 ++++++++++++++++++++++++++++++++++++-- 1 file changed, 124 insertions(+), 7 deletions(-) diff --git a/drivers/rtc/rtc-isl1208.c b/drivers/rtc/rtc-isl1208.c index 1a2c38cc0178..d426eac965e9 100644 --- a/drivers/rtc/rtc-isl1208.c +++ b/drivers/rtc/rtc-isl1208.c @@ -14,6 +14,7 @@ #include #include #include +#include "rtc-core.h" /* Register map */ /* rtc section */ @@ -33,13 +34,15 @@ #define ISL1208_REG_SR_ARST (1<<7) /* auto reset */ #define ISL1208_REG_SR_XTOSCB (1<<6) /* crystal oscillator */ #define ISL1208_REG_SR_WRTC (1<<4) /* write rtc */ +#define ISL1208_REG_SR_EVT (1<<3) /* event */ #define ISL1208_REG_SR_ALM (1<<2) /* alarm */ #define ISL1208_REG_SR_BAT (1<<1) /* battery */ #define ISL1208_REG_SR_RTCF (1<<0) /* rtc fail */ #define ISL1208_REG_INT 0x08 #define ISL1208_REG_INT_ALME (1<<6) /* alarm enable */ #define ISL1208_REG_INT_IM (1<<7) /* interrupt/alarm mode */ -#define ISL1208_REG_09 0x09 /* reserved */ +#define ISL1219_REG_EV 0x09 +#define ISL1219_REG_EV_EVEN (1<<4) /* event detection enable */ #define ISL1208_REG_ATR 0x0a #define ISL1208_REG_DTR 0x0b @@ -57,8 +60,24 @@ #define ISL1208_REG_USR2 0x13 #define ISL1208_USR_SECTION_LEN 2 +/* event section */ +#define ISL1219_REG_SCT 0x14 +#define ISL1219_REG_MNT 0x15 +#define ISL1219_REG_HRT 0x16 +#define ISL1219_REG_DTT 0x17 +#define ISL1219_REG_MOT 0x18 +#define ISL1219_REG_YRT 0x19 +#define ISL1219_EVT_SECTION_LEN 6 + static struct i2c_driver isl1208_driver; +/* ISL1208 various variants */ +enum { + TYPE_ISL1208 = 0, + TYPE_ISL1218, + TYPE_ISL1219, +}; + /* block read */ static int isl1208_i2c_read_regs(struct i2c_client *client, u8 reg, u8 buf[], @@ -80,8 +99,8 @@ isl1208_i2c_read_regs(struct i2c_client *client, u8 reg, u8 buf[], }; int ret; - BUG_ON(reg > ISL1208_REG_USR2); - BUG_ON(reg + len > ISL1208_REG_USR2 + 1); + WARN_ON(reg > ISL1219_REG_YRT); + WARN_ON(reg + len > ISL1219_REG_YRT + 1); ret = i2c_transfer(client->adapter, msgs, 2); if (ret > 0) @@ -104,8 +123,8 @@ isl1208_i2c_set_regs(struct i2c_client *client, u8 reg, u8 const buf[], }; int ret; - BUG_ON(reg > ISL1208_REG_USR2); - BUG_ON(reg + len > ISL1208_REG_USR2 + 1); + WARN_ON(reg > ISL1219_REG_YRT); + WARN_ON(reg + len > ISL1219_REG_YRT + 1); i2c_buf[0] = reg; memcpy(&i2c_buf[1], &buf[0], len); @@ -493,6 +512,73 @@ isl1208_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alarm) return isl1208_i2c_set_alarm(to_i2c_client(dev), alarm); } +static ssize_t timestamp0_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) +{ + struct i2c_client *client = dev_get_drvdata(dev); + int sr; + + sr = isl1208_i2c_get_sr(client); + if (sr < 0) { + dev_err(dev, "%s: reading SR failed\n", __func__); + return sr; + } + + sr &= ~ISL1208_REG_SR_EVT; + + sr = i2c_smbus_write_byte_data(client, ISL1208_REG_SR, sr); + if (sr < 0) + dev_err(dev, "%s: writing SR failed\n", + __func__); + + return count; +}; + +static ssize_t timestamp0_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct i2c_client *client = dev_get_drvdata(dev); + u8 regs[ISL1219_EVT_SECTION_LEN] = { 0, }; + struct rtc_time tm; + int sr; + + sr = isl1208_i2c_get_sr(client); + if (sr < 0) { + dev_err(dev, "%s: reading SR failed\n", __func__); + return sr; + } + + if (!(sr & ISL1208_REG_SR_EVT)) + return 0; + + sr = isl1208_i2c_read_regs(client, ISL1219_REG_SCT, regs, + ISL1219_EVT_SECTION_LEN); + if (sr < 0) { + dev_err(dev, "%s: reading event section failed\n", + __func__); + return 0; + } + + /* MSB of each alarm register is an enable bit */ + tm.tm_sec = bcd2bin(regs[ISL1219_REG_SCT - ISL1219_REG_SCT] & 0x7f); + tm.tm_min = bcd2bin(regs[ISL1219_REG_MNT - ISL1219_REG_SCT] & 0x7f); + tm.tm_hour = bcd2bin(regs[ISL1219_REG_HRT - ISL1219_REG_SCT] & 0x3f); + tm.tm_mday = bcd2bin(regs[ISL1219_REG_DTT - ISL1219_REG_SCT] & 0x3f); + tm.tm_mon = + bcd2bin(regs[ISL1219_REG_MOT - ISL1219_REG_SCT] & 0x1f) - 1; + tm.tm_year = bcd2bin(regs[ISL1219_REG_YRT - ISL1219_REG_SCT]) + 100; + + sr = rtc_valid_tm(&tm); + if (sr) + return sr; + + return sprintf(buf, "%llu\n", + (unsigned long long)rtc_tm_to_time64(&tm)); +}; + +static DEVICE_ATTR_RW(timestamp0); + static irqreturn_t isl1208_rtc_interrupt(int irq, void *data) { @@ -538,6 +624,13 @@ isl1208_rtc_interrupt(int irq, void *data) return err; } + if (sr & ISL1208_REG_SR_EVT) { + sysfs_notify(&rtc->dev.kobj, NULL, + dev_attr_timestamp0.attr.name); + dev_warn(&client->dev, "event detected"); + handled = 1; + } + return handled ? IRQ_HANDLED : IRQ_NONE; } @@ -623,6 +716,15 @@ static const struct attribute_group isl1208_rtc_sysfs_files = { .attrs = isl1208_rtc_attrs, }; +static struct attribute *isl1219_rtc_attrs[] = { + &dev_attr_timestamp0.attr, + NULL +}; + +static const struct attribute_group isl1219_rtc_sysfs_files = { + .attrs = isl1219_rtc_attrs, +}; + static int isl1208_probe(struct i2c_client *client, const struct i2c_device_id *id) { @@ -642,6 +744,7 @@ isl1208_probe(struct i2c_client *client, const struct i2c_device_id *id) rtc->ops = &isl1208_rtc_ops; i2c_set_clientdata(client, rtc); + dev_set_drvdata(&rtc->dev, client); rc = isl1208_i2c_get_sr(client); if (rc < 0) { @@ -653,6 +756,18 @@ isl1208_probe(struct i2c_client *client, const struct i2c_device_id *id) dev_warn(&client->dev, "rtc power failure detected, " "please set clock.\n"); + if (id->driver_data == TYPE_ISL1219) { + rc = i2c_smbus_write_byte_data(client, ISL1219_REG_EV, + ISL1219_REG_EV_EVEN); + if (rc < 0) { + dev_err(&client->dev, "could not enable tamper detection\n"); + return rc; + } + rc = rtc_add_group(rtc, &isl1219_rtc_sysfs_files); + if (rc) + return rc; + } + rc = sysfs_create_group(&client->dev.kobj, &isl1208_rtc_sysfs_files); if (rc) return rc; @@ -686,8 +801,9 @@ isl1208_remove(struct i2c_client *client) } static const struct i2c_device_id isl1208_id[] = { - { "isl1208", 0 }, - { "isl1218", 0 }, + { "isl1208", TYPE_ISL1208 }, + { "isl1218", TYPE_ISL1218 }, + { "isl1219", TYPE_ISL1219 }, { } }; MODULE_DEVICE_TABLE(i2c, isl1208_id); @@ -695,6 +811,7 @@ MODULE_DEVICE_TABLE(i2c, isl1208_id); static const struct of_device_id isl1208_of_match[] = { { .compatible = "isil,isl1208" }, { .compatible = "isil,isl1218" }, + { .compatible = "isil,isl1219" }, { } }; MODULE_DEVICE_TABLE(of, isl1208_of_match); From 9ece7cd833a3e5e0740e2b681abe6ce5e6af6885 Mon Sep 17 00:00:00 2001 From: Denis Osterland Date: Tue, 24 Jul 2018 11:31:21 +0000 Subject: [PATCH 29/34] rtc: isl1208: Add "evdet" interrupt source for isl1219 Add support for "evdet" named interrupt source. The check if i2c client irq matches evdet irq is needed for the case that there is only one interrupt named "evdet". In this case i2c client code handles this like an unnamed interrupt souce and assigns the value. Signed-off-by: Denis Osterland Reviewed-by: Michael Grzeschik Signed-off-by: Alexandre Belloni --- drivers/rtc/rtc-isl1208.c | 46 +++++++++++++++++++++++++-------------- 1 file changed, 30 insertions(+), 16 deletions(-) diff --git a/drivers/rtc/rtc-isl1208.c b/drivers/rtc/rtc-isl1208.c index d426eac965e9..f4eb3e11de28 100644 --- a/drivers/rtc/rtc-isl1208.c +++ b/drivers/rtc/rtc-isl1208.c @@ -15,6 +15,7 @@ #include #include #include "rtc-core.h" +#include /* Register map */ /* rtc section */ @@ -725,11 +726,30 @@ static const struct attribute_group isl1219_rtc_sysfs_files = { .attrs = isl1219_rtc_attrs, }; +static int isl1208_setup_irq(struct i2c_client *client, int irq) +{ + int rc = devm_request_threaded_irq(&client->dev, irq, NULL, + isl1208_rtc_interrupt, + IRQF_SHARED | IRQF_ONESHOT, + isl1208_driver.driver.name, + client); + if (!rc) { + device_init_wakeup(&client->dev, 1); + enable_irq_wake(irq); + } else { + dev_err(&client->dev, + "Unable to request irq %d, no alarm support\n", + irq); + } + return rc; +} + static int isl1208_probe(struct i2c_client *client, const struct i2c_device_id *id) { int rc = 0; struct rtc_device *rtc; + int evdet_irq = -1; if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) return -ENODEV; @@ -766,28 +786,22 @@ isl1208_probe(struct i2c_client *client, const struct i2c_device_id *id) rc = rtc_add_group(rtc, &isl1219_rtc_sysfs_files); if (rc) return rc; + evdet_irq = of_irq_get_byname(client->dev.of_node, "evdet"); } rc = sysfs_create_group(&client->dev.kobj, &isl1208_rtc_sysfs_files); if (rc) return rc; - if (client->irq > 0) { - rc = devm_request_threaded_irq(&client->dev, client->irq, NULL, - isl1208_rtc_interrupt, - IRQF_SHARED | IRQF_ONESHOT, - isl1208_driver.driver.name, - client); - if (!rc) { - device_init_wakeup(&client->dev, 1); - enable_irq_wake(client->irq); - } else { - dev_err(&client->dev, - "Unable to request irq %d, no alarm support\n", - client->irq); - client->irq = 0; - } - } + if (client->irq > 0) + rc = isl1208_setup_irq(client, client->irq); + if (rc) + return rc; + + if (evdet_irq > 0 && evdet_irq != client->irq) + rc = isl1208_setup_irq(client, evdet_irq); + if (rc) + return rc; return rtc_register_device(rtc); } From cfa30622c854747aba9c920c7dd30e5a123a414f Mon Sep 17 00:00:00 2001 From: Denis Osterland Date: Tue, 24 Jul 2018 11:31:21 +0000 Subject: [PATCH 30/34] rtc: isl1208: set ev-evienb bit from device tree Add support to disable event in pull-up. Signed-off-by: Denis Osterland Signed-off-by: Alexandre Belloni --- drivers/rtc/rtc-isl1208.c | 21 ++++++++++++++++++--- 1 file changed, 18 insertions(+), 3 deletions(-) diff --git a/drivers/rtc/rtc-isl1208.c b/drivers/rtc/rtc-isl1208.c index f4eb3e11de28..ea18a8f4bce0 100644 --- a/drivers/rtc/rtc-isl1208.c +++ b/drivers/rtc/rtc-isl1208.c @@ -44,6 +44,7 @@ #define ISL1208_REG_INT_IM (1<<7) /* interrupt/alarm mode */ #define ISL1219_REG_EV 0x09 #define ISL1219_REG_EV_EVEN (1<<4) /* event detection enable */ +#define ISL1219_REG_EV_EVIENB (1<<7) /* event in pull-up disable */ #define ISL1208_REG_ATR 0x0a #define ISL1208_REG_DTR 0x0b @@ -777,8 +778,22 @@ isl1208_probe(struct i2c_client *client, const struct i2c_device_id *id) "please set clock.\n"); if (id->driver_data == TYPE_ISL1219) { - rc = i2c_smbus_write_byte_data(client, ISL1219_REG_EV, - ISL1219_REG_EV_EVEN); + struct device_node *np = client->dev.of_node; + u32 evienb; + + rc = i2c_smbus_read_byte_data(client, ISL1219_REG_EV); + if (rc < 0) { + dev_err(&client->dev, "failed to read EV reg\n"); + return rc; + } + rc |= ISL1219_REG_EV_EVEN; + if (!of_property_read_u32(np, "isil,ev-evienb", &evienb)) { + if (evienb) + rc |= ISL1219_REG_EV_EVIENB; + else + rc &= ~ISL1219_REG_EV_EVIENB; + } + rc = i2c_smbus_write_byte_data(client, ISL1219_REG_EV, rc); if (rc < 0) { dev_err(&client->dev, "could not enable tamper detection\n"); return rc; @@ -786,7 +801,7 @@ isl1208_probe(struct i2c_client *client, const struct i2c_device_id *id) rc = rtc_add_group(rtc, &isl1219_rtc_sysfs_files); if (rc) return rc; - evdet_irq = of_irq_get_byname(client->dev.of_node, "evdet"); + evdet_irq = of_irq_get_byname(np, "evdet"); } rc = sysfs_create_group(&client->dev.kobj, &isl1208_rtc_sysfs_files); From 6f7ea94acbb751f617bfd674086b388460ee5b3b Mon Sep 17 00:00:00 2001 From: Denis Osterland Date: Tue, 24 Jul 2018 11:31:22 +0000 Subject: [PATCH 31/34] rtc: isl1219: add device tree documentation The devicetree documentation for the ISL1219 device tree binding is added with a short example. It is not a trivial device, because it supports two interrupt sources. Signed-off-by: Denis Osterland Reviewed-by: Rob Herring Signed-off-by: Alexandre Belloni --- .../devicetree/bindings/rtc/isil,isl1219.txt | 29 +++++++++++++++++++ 1 file changed, 29 insertions(+) create mode 100644 Documentation/devicetree/bindings/rtc/isil,isl1219.txt diff --git a/Documentation/devicetree/bindings/rtc/isil,isl1219.txt b/Documentation/devicetree/bindings/rtc/isil,isl1219.txt new file mode 100644 index 000000000000..c3efd48e91c2 --- /dev/null +++ b/Documentation/devicetree/bindings/rtc/isil,isl1219.txt @@ -0,0 +1,29 @@ +Intersil ISL1219 I2C RTC/Alarm chip with event in + +ISL1219 has additional pins EVIN and #EVDET for tamper detection. + +Required properties supported by the device: + + - "compatible": must be "isil,isl1219" + - "reg": I2C bus address of the device + +Optional properties: + + - "interrupt-names": list which may contains "irq" and "evdet" + - "interrupts": list of interrupts for "irq" and "evdet" + - "isil,ev-evienb": if present EV.EVIENB bit is set to the specified + value for proper operation. + + +Example isl1219 node with #IRQ pin connected to SoC gpio1 pin12 + and #EVDET pin connected to SoC gpio2 pin 24: + + isl1219: rtc@68 { + compatible = "isil,isl1219"; + reg = <0x68>; + interrupt-names = "irq", "evdet"; + interrupts-extended = <&gpio1 12 IRQ_TYPE_EDGE_FALLING>, + <&gpio2 24 IRQ_TYPE_EDGE_FALLING>; + isil,ev-evienb = <1>; + }; + From 734c5cd5bc2f391ece9ab71b35abb33dfa5713ec Mon Sep 17 00:00:00 2001 From: Krzysztof Kozlowski Date: Tue, 7 Aug 2018 18:19:18 +0200 Subject: [PATCH 32/34] rtc: maxim: Add SPDX license identifiers Replace GPL v2.0+ license statements with SPDX license identifiers. Signed-off-by: Krzysztof Kozlowski Signed-off-by: Alexandre Belloni --- drivers/rtc/rtc-max77686.c | 20 +++++++------------- drivers/rtc/rtc-max8997.c | 20 +++++++------------- drivers/rtc/rtc-max8998.c | 20 +++++++------------- 3 files changed, 21 insertions(+), 39 deletions(-) diff --git a/drivers/rtc/rtc-max77686.c b/drivers/rtc/rtc-max77686.c index cefde273fae6..8a60900d6b8b 100644 --- a/drivers/rtc/rtc-max77686.c +++ b/drivers/rtc/rtc-max77686.c @@ -1,16 +1,10 @@ -/* - * RTC driver for Maxim MAX77686 and MAX77802 - * - * Copyright (C) 2012 Samsung Electronics Co.Ltd - * - * based on rtc-max8997.c - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the - * Free Software Foundation; either version 2 of the License, or (at your - * option) any later version. - * - */ +// SPDX-License-Identifier: GPL-2.0+ +// +// RTC driver for Maxim MAX77686 and MAX77802 +// +// Copyright (C) 2012 Samsung Electronics Co.Ltd +// +// based on rtc-max8997.c #include #include diff --git a/drivers/rtc/rtc-max8997.c b/drivers/rtc/rtc-max8997.c index e8cee123e8aa..08c661a332ec 100644 --- a/drivers/rtc/rtc-max8997.c +++ b/drivers/rtc/rtc-max8997.c @@ -1,16 +1,10 @@ -/* - * RTC driver for Maxim MAX8997 - * - * Copyright (C) 2013 Samsung Electronics Co.Ltd - * - * based on rtc-max8998.c - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the - * Free Software Foundation; either version 2 of the License, or (at your - * option) any later version. - * - */ +// SPDX-License-Identifier: GPL-2.0+ +// +// RTC driver for Maxim MAX8997 +// +// Copyright (C) 2013 Samsung Electronics Co.Ltd +// +// based on rtc-max8998.c #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt diff --git a/drivers/rtc/rtc-max8998.c b/drivers/rtc/rtc-max8998.c index d8c0f9b3f87d..c873b4509b3c 100644 --- a/drivers/rtc/rtc-max8998.c +++ b/drivers/rtc/rtc-max8998.c @@ -1,16 +1,10 @@ -/* - * RTC driver for Maxim MAX8998 - * - * Copyright (C) 2010 Samsung Electronics Co.Ltd - * Author: Minkyu Kang - * Author: Joonyoung Shim - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the - * Free Software Foundation; either version 2 of the License, or (at your - * option) any later version. - * - */ +// SPDX-License-Identifier: GPL-2.0+ +// +// RTC driver for Maxim MAX8998 +// +// Copyright (C) 2010 Samsung Electronics Co.Ltd +// Author: Minkyu Kang +// Author: Joonyoung Shim #include #include From 26dcc12c009e3222f8b975f23c605516a5d3b29f Mon Sep 17 00:00:00 2001 From: Krzysztof Kozlowski Date: Tue, 7 Aug 2018 18:19:19 +0200 Subject: [PATCH 33/34] rtc: s5m: Add SPDX license identifier Replace GPL v2.0+ license statement with SPDX license identifier. Signed-off-by: Krzysztof Kozlowski Signed-off-by: Alexandre Belloni --- drivers/rtc/rtc-s5m.c | 22 ++++++---------------- 1 file changed, 6 insertions(+), 16 deletions(-) diff --git a/drivers/rtc/rtc-s5m.c b/drivers/rtc/rtc-s5m.c index 8428455432ca..6495f84f7428 100644 --- a/drivers/rtc/rtc-s5m.c +++ b/drivers/rtc/rtc-s5m.c @@ -1,19 +1,9 @@ -/* - * Copyright (c) 2013-2014 Samsung Electronics Co., Ltd - * http://www.samsung.com - * - * Copyright (C) 2013 Google, Inc - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - */ +// SPDX-License-Identifier: GPL-2.0+ +// +// Copyright (c) 2013-2014 Samsung Electronics Co., Ltd +// http://www.samsung.com +// +// Copyright (C) 2013 Google, Inc #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt From 6b583a64fd1e019fd01626b46892ebf2361951c5 Mon Sep 17 00:00:00 2001 From: Heiner Kallweit Date: Wed, 27 Sep 2017 22:41:26 +0200 Subject: [PATCH 34/34] rtc: ds1307: simplify hwmon config We don't have to define an extra config symbol, IS_REACHABLE does what we need. And having this config symbol just to save the few bytes of hwmon support on non-DS3231 chips isn't worth it IMO (especially as the symbol is set per default). Signed-off-by: Heiner Kallweit Signed-off-by: Alexandre Belloni --- drivers/rtc/Kconfig | 9 --------- drivers/rtc/rtc-ds1307.c | 2 +- 2 files changed, 1 insertion(+), 10 deletions(-) diff --git a/drivers/rtc/Kconfig b/drivers/rtc/Kconfig index 2962fa09baf1..7d7be60a2413 100644 --- a/drivers/rtc/Kconfig +++ b/drivers/rtc/Kconfig @@ -244,15 +244,6 @@ config RTC_DRV_DS1307 This driver can also be built as a module. If so, the module will be called rtc-ds1307. -config RTC_DRV_DS1307_HWMON - bool "HWMON support for rtc-ds1307" - depends on RTC_DRV_DS1307 && HWMON - depends on !(RTC_DRV_DS1307=y && HWMON=m) - default y - help - Say Y here if you want to expose temperature sensor data on - rtc-ds1307 (only DS3231) - config RTC_DRV_DS1307_CENTURY bool "Century bit support for rtc-ds1307" depends on RTC_DRV_DS1307 diff --git a/drivers/rtc/rtc-ds1307.c b/drivers/rtc/rtc-ds1307.c index 0162a600ff1b..4b2b4627daeb 100644 --- a/drivers/rtc/rtc-ds1307.c +++ b/drivers/rtc/rtc-ds1307.c @@ -1042,7 +1042,7 @@ static u8 ds1307_trickle_init(struct ds1307 *ds1307, /*----------------------------------------------------------------------*/ -#ifdef CONFIG_RTC_DRV_DS1307_HWMON +#if IS_REACHABLE(CONFIG_HWMON) /* * Temperature sensor support for ds3231 devices.