diff options
Diffstat (limited to 'drivers/rtc')
50 files changed, 1219 insertions, 548 deletions
diff --git a/drivers/rtc/Kconfig b/drivers/rtc/Kconfig index 05f4b2d66290..d7502433c78a 100644 --- a/drivers/rtc/Kconfig +++ b/drivers/rtc/Kconfig @@ -904,9 +904,9 @@ config RTC_DRV_PCF2127 select REGMAP_SPI if SPI_MASTER select WATCHDOG_CORE if WATCHDOG help - If you say yes here you get support for the NXP PCF2127/29 RTC + If you say yes here you get support for the NXP PCF2127/29/31 RTC chips with integrated quartz crystal for industrial applications. - Both chips also have watchdog timer and tamper switch detection + These chips also have watchdog timer and tamper switch detection features. PCF2127 has an additional feature of 512 bytes battery backed @@ -1196,6 +1196,7 @@ config RTC_DRV_MSM6242 config RTC_DRV_BQ4802 tristate "TI BQ4802" depends on HAS_IOMEM && HAS_IOPORT + depends on SPARC || COMPILE_TEST help If you say Y here you will get support for the TI BQ4802 RTC chip. diff --git a/drivers/rtc/interface.c b/drivers/rtc/interface.c index 499d89150afc..1b63111cdda2 100644 --- a/drivers/rtc/interface.c +++ b/drivers/rtc/interface.c @@ -376,7 +376,7 @@ int __rtc_read_alarm(struct rtc_device *rtc, struct rtc_wkalrm *alarm) err = rtc_valid_tm(&alarm->time); done: - if (err) + if (err && alarm->enabled) dev_warn(&rtc->dev, "invalid alarm value: %ptR\n", &alarm->time); diff --git a/drivers/rtc/rtc-abx80x.c b/drivers/rtc/rtc-abx80x.c index e08d3181bd2a..fde2b8054c2e 100644 --- a/drivers/rtc/rtc-abx80x.c +++ b/drivers/rtc/rtc-abx80x.c @@ -15,7 +15,7 @@ #include <linux/i2c.h> #include <linux/kstrtox.h> #include <linux/module.h> -#include <linux/of_device.h> +#include <linux/of.h> #include <linux/rtc.h> #include <linux/watchdog.h> diff --git a/drivers/rtc/rtc-armada38x.c b/drivers/rtc/rtc-armada38x.c index b4139c200676..569c1054d6b0 100644 --- a/drivers/rtc/rtc-armada38x.c +++ b/drivers/rtc/rtc-armada38x.c @@ -11,7 +11,6 @@ #include <linux/io.h> #include <linux/module.h> #include <linux/of.h> -#include <linux/of_device.h> #include <linux/platform_device.h> #include <linux/rtc.h> @@ -474,7 +473,6 @@ static const struct armada38x_rtc_data armada8k_data = { .alarm = ALARM2, }; -#ifdef CONFIG_OF static const struct of_device_id armada38x_rtc_of_match_table[] = { { .compatible = "marvell,armada-380-rtc", @@ -487,7 +485,6 @@ static const struct of_device_id armada38x_rtc_of_match_table[] = { {} }; MODULE_DEVICE_TABLE(of, armada38x_rtc_of_match_table); -#endif static __init int armada38x_rtc_probe(struct platform_device *pdev) { @@ -577,7 +574,7 @@ static struct platform_driver armada38x_rtc_driver = { .driver = { .name = "armada38x-rtc", .pm = &armada38x_rtc_pm_ops, - .of_match_table = of_match_ptr(armada38x_rtc_of_match_table), + .of_match_table = armada38x_rtc_of_match_table, }, }; diff --git a/drivers/rtc/rtc-aspeed.c b/drivers/rtc/rtc-aspeed.c index a93352ed3aec..880b015eebaf 100644 --- a/drivers/rtc/rtc-aspeed.c +++ b/drivers/rtc/rtc-aspeed.c @@ -118,7 +118,7 @@ MODULE_DEVICE_TABLE(of, aspeed_rtc_match); static struct platform_driver aspeed_rtc_driver = { .driver = { .name = "aspeed-rtc", - .of_match_table = of_match_ptr(aspeed_rtc_match), + .of_match_table = aspeed_rtc_match, }, }; diff --git a/drivers/rtc/rtc-at91rm9200.c b/drivers/rtc/rtc-at91rm9200.c index e9d17232d0a8..add4f71d7b3b 100644 --- a/drivers/rtc/rtc-at91rm9200.c +++ b/drivers/rtc/rtc-at91rm9200.c @@ -22,7 +22,6 @@ #include <linux/io.h> #include <linux/kernel.h> #include <linux/module.h> -#include <linux/of_device.h> #include <linux/of.h> #include <linux/platform_device.h> #include <linux/rtc.h> @@ -642,7 +641,7 @@ static struct platform_driver at91_rtc_driver = { .driver = { .name = "at91_rtc", .pm = &at91_rtc_pm_ops, - .of_match_table = of_match_ptr(at91_rtc_dt_ids), + .of_match_table = at91_rtc_dt_ids, }, }; diff --git a/drivers/rtc/rtc-at91sam9.c b/drivers/rtc/rtc-at91sam9.c index 610f27dfc462..f93bee96e362 100644 --- a/drivers/rtc/rtc-at91sam9.c +++ b/drivers/rtc/rtc-at91sam9.c @@ -534,7 +534,7 @@ static struct platform_driver at91_rtc_driver = { .driver = { .name = "rtc-at91sam9", .pm = &at91_rtc_pm_ops, - .of_match_table = of_match_ptr(at91_rtc_dt_ids), + .of_match_table = at91_rtc_dt_ids, }, }; diff --git a/drivers/rtc/rtc-cmos.c b/drivers/rtc/rtc-cmos.c index c9416fe8542d..228fb2d11c70 100644 --- a/drivers/rtc/rtc-cmos.c +++ b/drivers/rtc/rtc-cmos.c @@ -913,6 +913,10 @@ static inline void cmos_check_acpi_rtc_status(struct device *dev, #define INITSECTION __init #endif +#define SECS_PER_DAY (24 * 60 * 60) +#define SECS_PER_MONTH (28 * SECS_PER_DAY) +#define SECS_PER_YEAR (365 * SECS_PER_DAY) + static int INITSECTION cmos_do_probe(struct device *dev, struct resource *ports, int rtc_irq) { @@ -1019,6 +1023,13 @@ cmos_do_probe(struct device *dev, struct resource *ports, int rtc_irq) goto cleanup0; } + if (cmos_rtc.mon_alrm) + cmos_rtc.rtc->alarm_offset_max = SECS_PER_YEAR - 1; + else if (cmos_rtc.day_alrm) + cmos_rtc.rtc->alarm_offset_max = SECS_PER_MONTH - 1; + else + cmos_rtc.rtc->alarm_offset_max = SECS_PER_DAY - 1; + rename_region(ports, dev_name(&cmos_rtc.rtc->dev)); if (!mc146818_does_rtc_work()) { diff --git a/drivers/rtc/rtc-cros-ec.c b/drivers/rtc/rtc-cros-ec.c index 998ab8606f0b..0cd397c04ff0 100644 --- a/drivers/rtc/rtc-cros-ec.c +++ b/drivers/rtc/rtc-cros-ec.c @@ -182,21 +182,15 @@ static int cros_ec_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alrm) ret = cros_ec_rtc_set(cros_ec, EC_CMD_RTC_SET_ALARM, alarm_offset); if (ret < 0) { - if (ret == -EINVAL && alarm_offset >= SECS_PER_DAY) { - /* - * RTC chips on some older Chromebooks can only handle - * alarms up to 24h in the future. Try to set an alarm - * below that limit to avoid suspend failures. - */ - ret = cros_ec_rtc_set(cros_ec, EC_CMD_RTC_SET_ALARM, - SECS_PER_DAY - 1); - } - - if (ret < 0) { - dev_err(dev, "error setting alarm in %u seconds: %d\n", - alarm_offset, ret); - return ret; - } + dev_err(dev, "error setting alarm in %u seconds: %d\n", + alarm_offset, ret); + /* + * The EC code returns -EINVAL if the alarm time is too + * far in the future. Convert it to the expected error code. + */ + if (ret == -EINVAL) + ret = -ERANGE; + return ret; } return 0; @@ -355,6 +349,20 @@ static int cros_ec_rtc_probe(struct platform_device *pdev) cros_ec_rtc->rtc->ops = &cros_ec_rtc_ops; cros_ec_rtc->rtc->range_max = U32_MAX; + /* + * The RTC on some older Chromebooks can only handle alarms less than + * 24 hours in the future. The only way to find out is to try to set an + * alarm further in the future. If that fails, assume that the RTC + * connected to the EC can only handle less than 24 hours of alarm + * window. + */ + ret = cros_ec_rtc_set(cros_ec, EC_CMD_RTC_SET_ALARM, SECS_PER_DAY * 2); + if (ret == -EINVAL) + cros_ec_rtc->rtc->alarm_offset_max = SECS_PER_DAY - 1; + + (void)cros_ec_rtc_set(cros_ec, EC_CMD_RTC_SET_ALARM, + EC_RTC_ALARM_CLEAR); + ret = devm_rtc_register_device(cros_ec_rtc->rtc); if (ret) return ret; diff --git a/drivers/rtc/rtc-da9063.c b/drivers/rtc/rtc-da9063.c index ee2efb496174..2f5d60622564 100644 --- a/drivers/rtc/rtc-da9063.c +++ b/drivers/rtc/rtc-da9063.c @@ -11,6 +11,7 @@ #include <linux/module.h> #include <linux/of.h> #include <linux/platform_device.h> +#include <linux/pm_wakeirq.h> #include <linux/regmap.h> #include <linux/rtc.h> #include <linux/slab.h> @@ -496,6 +497,12 @@ static int da9063_rtc_probe(struct platform_device *pdev) dev_err(&pdev->dev, "Failed to request ALARM IRQ %d: %d\n", irq_alarm, ret); + ret = dev_pm_set_wake_irq(&pdev->dev, irq_alarm); + if (ret) + dev_warn(&pdev->dev, + "Failed to set IRQ %d as a wake IRQ: %d\n", + irq_alarm, ret); + device_init_wakeup(&pdev->dev, true); return devm_rtc_register_device(rtc->rtc_dev); diff --git a/drivers/rtc/rtc-ds1305.c b/drivers/rtc/rtc-ds1305.c index ed9360486953..d4de401548b4 100644 --- a/drivers/rtc/rtc-ds1305.c +++ b/drivers/rtc/rtc-ds1305.c @@ -336,8 +336,8 @@ static int ds1305_set_alarm(struct device *dev, struct rtc_wkalrm *alm) /* make sure alarm fires within the next 24 hours */ if (later <= now) return -EINVAL; - if ((later - now) > 24 * 60 * 60) - return -EDOM; + if ((later - now) > ds1305->rtc->alarm_offset_max) + return -ERANGE; /* disable alarm if needed */ if (ds1305->ctrl[0] & DS1305_AEI0) { @@ -691,6 +691,7 @@ static int ds1305_probe(struct spi_device *spi) ds1305->rtc->ops = &ds1305_ops; ds1305->rtc->range_min = RTC_TIMESTAMP_BEGIN_2000; ds1305->rtc->range_max = RTC_TIMESTAMP_END_2099; + ds1305->rtc->alarm_offset_max = 24 * 60 * 60; ds1305_nvmem_cfg.priv = ds1305; status = devm_rtc_register_device(ds1305->rtc); diff --git a/drivers/rtc/rtc-ds1307.c b/drivers/rtc/rtc-ds1307.c index cb5acecc11aa..506b7d1c2397 100644 --- a/drivers/rtc/rtc-ds1307.c +++ b/drivers/rtc/rtc-ds1307.c @@ -1744,7 +1744,7 @@ static int ds1307_probe(struct i2c_client *client) match = device_get_match_data(&client->dev); if (match) { - ds1307->type = (enum ds_type)match; + ds1307->type = (uintptr_t)match; chip = &chips[ds1307->type]; } else if (id) { chip = &chips[id->driver_data]; diff --git a/drivers/rtc/rtc-ds1742.c b/drivers/rtc/rtc-ds1742.c index a5026b0514e7..6ae8b9a294fe 100644 --- a/drivers/rtc/rtc-ds1742.c +++ b/drivers/rtc/rtc-ds1742.c @@ -16,7 +16,6 @@ #include <linux/jiffies.h> #include <linux/rtc.h> #include <linux/of.h> -#include <linux/of_device.h> #include <linux/platform_device.h> #include <linux/io.h> #include <linux/module.h> diff --git a/drivers/rtc/rtc-ds2404.c b/drivers/rtc/rtc-ds2404.c index 0480f592307e..3231fd9f61da 100644 --- a/drivers/rtc/rtc-ds2404.c +++ b/drivers/rtc/rtc-ds2404.c @@ -7,9 +7,8 @@ #include <linux/rtc.h> #include <linux/types.h> #include <linux/bcd.h> -#include <linux/platform_data/rtc-ds2404.h> #include <linux/delay.h> -#include <linux/gpio.h> +#include <linux/gpio/consumer.h> #include <linux/slab.h> #include <linux/io.h> @@ -27,164 +26,140 @@ #define DS2404_CLK 1 #define DS2404_DQ 2 -struct ds2404_gpio { - const char *name; - unsigned int gpio; -}; - struct ds2404 { - struct ds2404_gpio *gpio; + struct device *dev; + struct gpio_desc *rst_gpiod; + struct gpio_desc *clk_gpiod; + struct gpio_desc *dq_gpiod; struct rtc_device *rtc; }; -static struct ds2404_gpio ds2404_gpio[] = { - { "RTC RST", 0 }, - { "RTC CLK", 0 }, - { "RTC DQ", 0 }, -}; - -static int ds2404_gpio_map(struct ds2404 *chip, struct platform_device *pdev, - struct ds2404_platform_data *pdata) +static int ds2404_gpio_map(struct ds2404 *chip, struct platform_device *pdev) { - int i, err; - - ds2404_gpio[DS2404_RST].gpio = pdata->gpio_rst; - ds2404_gpio[DS2404_CLK].gpio = pdata->gpio_clk; - ds2404_gpio[DS2404_DQ].gpio = pdata->gpio_dq; - - for (i = 0; i < ARRAY_SIZE(ds2404_gpio); i++) { - err = gpio_request(ds2404_gpio[i].gpio, ds2404_gpio[i].name); - if (err) { - dev_err(&pdev->dev, "error mapping gpio %s: %d\n", - ds2404_gpio[i].name, err); - goto err_request; - } - if (i != DS2404_DQ) - gpio_direction_output(ds2404_gpio[i].gpio, 1); - } + struct device *dev = &pdev->dev; - chip->gpio = ds2404_gpio; - return 0; + /* This will de-assert RESET, declare this GPIO as GPIOD_ACTIVE_LOW */ + chip->rst_gpiod = devm_gpiod_get(dev, "rst", GPIOD_OUT_LOW); + if (IS_ERR(chip->rst_gpiod)) + return PTR_ERR(chip->rst_gpiod); -err_request: - while (--i >= 0) - gpio_free(ds2404_gpio[i].gpio); - return err; -} + chip->clk_gpiod = devm_gpiod_get(dev, "clk", GPIOD_OUT_HIGH); + if (IS_ERR(chip->clk_gpiod)) + return PTR_ERR(chip->clk_gpiod); -static void ds2404_gpio_unmap(void *data) -{ - int i; + chip->dq_gpiod = devm_gpiod_get(dev, "dq", GPIOD_ASIS); + if (IS_ERR(chip->dq_gpiod)) + return PTR_ERR(chip->dq_gpiod); - for (i = 0; i < ARRAY_SIZE(ds2404_gpio); i++) - gpio_free(ds2404_gpio[i].gpio); + return 0; } -static void ds2404_reset(struct device *dev) +static void ds2404_reset(struct ds2404 *chip) { - gpio_set_value(ds2404_gpio[DS2404_RST].gpio, 0); + gpiod_set_value(chip->rst_gpiod, 1); udelay(1000); - gpio_set_value(ds2404_gpio[DS2404_RST].gpio, 1); - gpio_set_value(ds2404_gpio[DS2404_CLK].gpio, 0); - gpio_direction_output(ds2404_gpio[DS2404_DQ].gpio, 0); + gpiod_set_value(chip->rst_gpiod, 0); + gpiod_set_value(chip->clk_gpiod, 0); + gpiod_direction_output(chip->dq_gpiod, 0); udelay(10); } -static void ds2404_write_byte(struct device *dev, u8 byte) +static void ds2404_write_byte(struct ds2404 *chip, u8 byte) { int i; - gpio_direction_output(ds2404_gpio[DS2404_DQ].gpio, 1); + gpiod_direction_output(chip->dq_gpiod, 1); for (i = 0; i < 8; i++) { - gpio_set_value(ds2404_gpio[DS2404_DQ].gpio, byte & (1 << i)); + gpiod_set_value(chip->dq_gpiod, byte & (1 << i)); udelay(10); - gpio_set_value(ds2404_gpio[DS2404_CLK].gpio, 1); + gpiod_set_value(chip->clk_gpiod, 1); udelay(10); - gpio_set_value(ds2404_gpio[DS2404_CLK].gpio, 0); + gpiod_set_value(chip->clk_gpiod, 0); udelay(10); } } -static u8 ds2404_read_byte(struct device *dev) +static u8 ds2404_read_byte(struct ds2404 *chip) { int i; u8 ret = 0; - gpio_direction_input(ds2404_gpio[DS2404_DQ].gpio); + gpiod_direction_input(chip->dq_gpiod); for (i = 0; i < 8; i++) { - gpio_set_value(ds2404_gpio[DS2404_CLK].gpio, 0); + gpiod_set_value(chip->clk_gpiod, 0); udelay(10); - if (gpio_get_value(ds2404_gpio[DS2404_DQ].gpio)) + if (gpiod_get_value(chip->dq_gpiod)) ret |= 1 << i; - gpio_set_value(ds2404_gpio[DS2404_CLK].gpio, 1); + gpiod_set_value(chip->clk_gpiod, 1); udelay(10); } return ret; } -static void ds2404_read_memory(struct device *dev, u16 offset, +static void ds2404_read_memory(struct ds2404 *chip, u16 offset, int length, u8 *out) { - ds2404_reset(dev); - ds2404_write_byte(dev, DS2404_READ_MEMORY_CMD); - ds2404_write_byte(dev, offset & 0xff); - ds2404_write_byte(dev, (offset >> 8) & 0xff); + ds2404_reset(chip); + ds2404_write_byte(chip, DS2404_READ_MEMORY_CMD); + ds2404_write_byte(chip, offset & 0xff); + ds2404_write_byte(chip, (offset >> 8) & 0xff); while (length--) - *out++ = ds2404_read_byte(dev); + *out++ = ds2404_read_byte(chip); } -static void ds2404_write_memory(struct device *dev, u16 offset, +static void ds2404_write_memory(struct ds2404 *chip, u16 offset, int length, u8 *out) { int i; u8 ta01, ta02, es; - ds2404_reset(dev); - ds2404_write_byte(dev, DS2404_WRITE_SCRATCHPAD_CMD); - ds2404_write_byte(dev, offset & 0xff); - ds2404_write_byte(dev, (offset >> 8) & 0xff); + ds2404_reset(chip); + ds2404_write_byte(chip, DS2404_WRITE_SCRATCHPAD_CMD); + ds2404_write_byte(chip, offset & 0xff); + ds2404_write_byte(chip, (offset >> 8) & 0xff); for (i = 0; i < length; i++) - ds2404_write_byte(dev, out[i]); + ds2404_write_byte(chip, out[i]); - ds2404_reset(dev); - ds2404_write_byte(dev, DS2404_READ_SCRATCHPAD_CMD); + ds2404_reset(chip); + ds2404_write_byte(chip, DS2404_READ_SCRATCHPAD_CMD); - ta01 = ds2404_read_byte(dev); - ta02 = ds2404_read_byte(dev); - es = ds2404_read_byte(dev); + ta01 = ds2404_read_byte(chip); + ta02 = ds2404_read_byte(chip); + es = ds2404_read_byte(chip); for (i = 0; i < length; i++) { - if (out[i] != ds2404_read_byte(dev)) { - dev_err(dev, "read invalid data\n"); + if (out[i] != ds2404_read_byte(chip)) { + dev_err(chip->dev, "read invalid data\n"); return; } } - ds2404_reset(dev); - ds2404_write_byte(dev, DS2404_COPY_SCRATCHPAD_CMD); - ds2404_write_byte(dev, ta01); - ds2404_write_byte(dev, ta02); - ds2404_write_byte(dev, es); + ds2404_reset(chip); + ds2404_write_byte(chip, DS2404_COPY_SCRATCHPAD_CMD); + ds2404_write_byte(chip, ta01); + ds2404_write_byte(chip, ta02); + ds2404_write_byte(chip, es); - gpio_direction_input(ds2404_gpio[DS2404_DQ].gpio); - while (gpio_get_value(ds2404_gpio[DS2404_DQ].gpio)) + while (gpiod_get_value(chip->dq_gpiod)) ; } -static void ds2404_enable_osc(struct device *dev) +static void ds2404_enable_osc(struct ds2404 *chip) { u8 in[1] = { 0x10 }; /* enable oscillator */ - ds2404_write_memory(dev, 0x201, 1, in); + + ds2404_write_memory(chip, 0x201, 1, in); } static int ds2404_read_time(struct device *dev, struct rtc_time *dt) { + struct ds2404 *chip = dev_get_drvdata(dev); unsigned long time = 0; __le32 hw_time = 0; - ds2404_read_memory(dev, 0x203, 4, (u8 *)&hw_time); + ds2404_read_memory(chip, 0x203, 4, (u8 *)&hw_time); time = le32_to_cpu(hw_time); rtc_time64_to_tm(time, dt); @@ -193,8 +168,9 @@ static int ds2404_read_time(struct device *dev, struct rtc_time *dt) static int ds2404_set_time(struct device *dev, struct rtc_time *dt) { + struct ds2404 *chip = dev_get_drvdata(dev); u32 time = cpu_to_le32(rtc_tm_to_time64(dt)); - ds2404_write_memory(dev, 0x203, 4, (u8 *)&time); + ds2404_write_memory(chip, 0x203, 4, (u8 *)&time); return 0; } @@ -205,7 +181,6 @@ static const struct rtc_class_ops ds2404_rtc_ops = { static int rtc_probe(struct platform_device *pdev) { - struct ds2404_platform_data *pdata = dev_get_platdata(&pdev->dev); struct ds2404 *chip; int retval = -EBUSY; @@ -213,22 +188,16 @@ static int rtc_probe(struct platform_device *pdev) if (!chip) return -ENOMEM; + chip->dev = &pdev->dev; + chip->rtc = devm_rtc_allocate_device(&pdev->dev); if (IS_ERR(chip->rtc)) return PTR_ERR(chip->rtc); - retval = ds2404_gpio_map(chip, pdev, pdata); + retval = ds2404_gpio_map(chip, pdev); if (retval) return retval; - retval = devm_add_action_or_reset(&pdev->dev, ds2404_gpio_unmap, chip); - if (retval) - return retval; - - dev_info(&pdev->dev, "using GPIOs RST:%d, CLK:%d, DQ:%d\n", - chip->gpio[DS2404_RST].gpio, chip->gpio[DS2404_CLK].gpio, - chip->gpio[DS2404_DQ].gpio); - platform_set_drvdata(pdev, chip); chip->rtc->ops = &ds2404_rtc_ops; @@ -238,7 +207,7 @@ static int rtc_probe(struct platform_device *pdev) if (retval) return retval; - ds2404_enable_osc(&pdev->dev); + ds2404_enable_osc(chip); return 0; } diff --git a/drivers/rtc/rtc-fsl-ftm-alarm.c b/drivers/rtc/rtc-fsl-ftm-alarm.c index 3d7c4077fe1c..a72c4ad0cec6 100644 --- a/drivers/rtc/rtc-fsl-ftm-alarm.c +++ b/drivers/rtc/rtc-fsl-ftm-alarm.c @@ -11,11 +11,8 @@ #include <linux/err.h> #include <linux/interrupt.h> #include <linux/io.h> -#include <linux/of_address.h> -#include <linux/of_irq.h> #include <linux/platform_device.h> -#include <linux/of.h> -#include <linux/of_device.h> +#include <linux/mod_devicetable.h> #include <linux/module.h> #include <linux/fsl/ftm.h> #include <linux/rtc.h> diff --git a/drivers/rtc/rtc-isl12022.c b/drivers/rtc/rtc-isl12022.c index a613257d1574..4eef7afcc8bc 100644 --- a/drivers/rtc/rtc-isl12022.c +++ b/drivers/rtc/rtc-isl12022.c @@ -9,6 +9,8 @@ */ #include <linux/bcd.h> +#include <linux/bitfield.h> +#include <linux/clk-provider.h> #include <linux/err.h> #include <linux/hwmon.h> #include <linux/i2c.h> @@ -31,6 +33,8 @@ #define ISL12022_REG_SR 0x07 #define ISL12022_REG_INT 0x08 +#define ISL12022_REG_PWR_VBAT 0x0a + #define ISL12022_REG_BETA 0x0d #define ISL12022_REG_TEMP_L 0x28 @@ -41,6 +45,12 @@ #define ISL12022_SR_LBAT75 (1 << 1) #define ISL12022_INT_WRTC (1 << 6) +#define ISL12022_INT_FO_MASK GENMASK(3, 0) +#define ISL12022_INT_FO_OFF 0x0 +#define ISL12022_INT_FO_32K 0x1 + +#define ISL12022_REG_VB85_MASK GENMASK(5, 3) +#define ISL12022_REG_VB75_MASK GENMASK(2, 0) #define ISL12022_BETA_TSE (1 << 7) @@ -141,12 +151,6 @@ static int isl12022_rtc_read_time(struct device *dev, struct rtc_time *tm) if (ret) return ret; - if (buf[ISL12022_REG_SR] & (ISL12022_SR_LBAT85 | ISL12022_SR_LBAT75)) { - dev_warn(dev, - "voltage dropped below %u%%, date and time is not reliable.\n", - buf[ISL12022_REG_SR] & ISL12022_SR_LBAT85 ? 85 : 75); - } - dev_dbg(dev, "raw data is sec=%02x, min=%02x, hr=%02x, mday=%02x, mon=%02x, year=%02x, wday=%02x, sr=%02x, int=%02x", buf[ISL12022_REG_SC], @@ -204,7 +208,34 @@ static int isl12022_rtc_set_time(struct device *dev, struct rtc_time *tm) return regmap_bulk_write(regmap, ISL12022_REG_SC, buf, sizeof(buf)); } +static int isl12022_rtc_ioctl(struct device *dev, unsigned int cmd, unsigned long arg) +{ + struct regmap *regmap = dev_get_drvdata(dev); + u32 user, val; + int ret; + + switch (cmd) { + case RTC_VL_READ: + ret = regmap_read(regmap, ISL12022_REG_SR, &val); + if (ret) + return ret; + + user = 0; + if (val & ISL12022_SR_LBAT85) + user |= RTC_VL_BACKUP_LOW; + + if (val & ISL12022_SR_LBAT75) + user |= RTC_VL_BACKUP_EMPTY; + + return put_user(user, (u32 __user *)arg); + + default: + return -ENOIOCTLCMD; + } +} + static const struct rtc_class_ops isl12022_rtc_ops = { + .ioctl = isl12022_rtc_ioctl, .read_time = isl12022_rtc_read_time, .set_time = isl12022_rtc_set_time, }; @@ -215,10 +246,88 @@ static const struct regmap_config regmap_config = { .use_single_write = true, }; +static int isl12022_register_clock(struct device *dev) +{ + struct regmap *regmap = dev_get_drvdata(dev); + struct clk_hw *hw; + int ret; + + if (!device_property_present(dev, "#clock-cells")) { + /* + * Disabling the F_OUT pin reduces the power + * consumption in battery mode by ~25%. + */ + regmap_update_bits(regmap, ISL12022_REG_INT, ISL12022_INT_FO_MASK, + ISL12022_INT_FO_OFF); + + return 0; + } + + if (!IS_ENABLED(CONFIG_COMMON_CLK)) + return 0; + + /* + * For now, only support a fixed clock of 32768Hz (the reset default). + */ + ret = regmap_update_bits(regmap, ISL12022_REG_INT, + ISL12022_INT_FO_MASK, ISL12022_INT_FO_32K); + if (ret) + return ret; + + hw = devm_clk_hw_register_fixed_rate(dev, "isl12022", NULL, 0, 32768); + if (IS_ERR(hw)) + return PTR_ERR(hw); + + return devm_of_clk_add_hw_provider(dev, of_clk_hw_simple_get, hw); +} + +static const u32 trip_levels[2][7] = { + { 2125000, 2295000, 2550000, 2805000, 3060000, 4250000, 4675000 }, + { 1875000, 2025000, 2250000, 2475000, 2700000, 3750000, 4125000 }, +}; + +static void isl12022_set_trip_levels(struct device *dev) +{ + struct regmap *regmap = dev_get_drvdata(dev); + u32 levels[2] = {0, 0}; + int ret, i, j, x[2]; + u8 val, mask; + + device_property_read_u32_array(dev, "isil,battery-trip-levels-microvolt", + levels, 2); + + for (i = 0; i < 2; i++) { + for (j = 0; j < ARRAY_SIZE(trip_levels[i]) - 1; j++) { + if (levels[i] <= trip_levels[i][j]) + break; + } + x[i] = j; + } + + val = FIELD_PREP(ISL12022_REG_VB85_MASK, x[0]) | + FIELD_PREP(ISL12022_REG_VB75_MASK, x[1]); + mask = ISL12022_REG_VB85_MASK | ISL12022_REG_VB75_MASK; + + ret = regmap_update_bits(regmap, ISL12022_REG_PWR_VBAT, mask, val); + if (ret) + dev_warn(dev, "unable to set battery alarm levels: %d\n", ret); + + /* + * Force a write of the TSE bit in the BETA register, in order + * to trigger an update of the LBAT75 and LBAT85 bits in the + * status register. In battery backup mode, those bits have + * another meaning, so without this, they may contain stale + * values for up to a minute after power-on. + */ + regmap_write_bits(regmap, ISL12022_REG_BETA, + ISL12022_BETA_TSE, ISL12022_BETA_TSE); +} + static int isl12022_probe(struct i2c_client *client) { struct rtc_device *rtc; struct regmap *regmap; + int ret; if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) return -ENODEV; @@ -231,6 +340,11 @@ static int isl12022_probe(struct i2c_client *client) dev_set_drvdata(&client->dev, regmap); + ret = isl12022_register_clock(&client->dev); + if (ret) + return ret; + + isl12022_set_trip_levels(&client->dev); isl12022_hwmon_register(&client->dev); rtc = devm_rtc_allocate_device(&client->dev); diff --git a/drivers/rtc/rtc-isl12026.c b/drivers/rtc/rtc-isl12026.c index 5abff5d348ac..2aabb9151d4c 100644 --- a/drivers/rtc/rtc-isl12026.c +++ b/drivers/rtc/rtc-isl12026.c @@ -11,7 +11,6 @@ #include <linux/mutex.h> #include <linux/nvmem-provider.h> #include <linux/of.h> -#include <linux/of_device.h> #include <linux/rtc.h> #include <linux/slab.h> @@ -429,7 +428,7 @@ static void isl12026_force_power_modes(struct i2c_client *client) } } -static int isl12026_probe_new(struct i2c_client *client) +static int isl12026_probe(struct i2c_client *client) { struct isl12026 *priv; int ret; @@ -490,7 +489,7 @@ static struct i2c_driver isl12026_driver = { .name = "rtc-isl12026", .of_match_table = isl12026_dt_match, }, - .probe = isl12026_probe_new, + .probe = isl12026_probe, .remove = isl12026_remove, }; diff --git a/drivers/rtc/rtc-isl1208.c b/drivers/rtc/rtc-isl1208.c index b0712b4e3648..e50c23ee1646 100644 --- a/drivers/rtc/rtc-isl1208.c +++ b/drivers/rtc/rtc-isl1208.c @@ -9,7 +9,7 @@ #include <linux/clk.h> #include <linux/i2c.h> #include <linux/module.h> -#include <linux/of_device.h> +#include <linux/of.h> #include <linux/of_irq.h> #include <linux/rtc.h> @@ -188,7 +188,7 @@ isl1208_i2c_validate_client(struct i2c_client *client) static int isl1208_set_xtoscb(struct i2c_client *client, int sr, int xtosb_val) { /* Do nothing if bit is already set to desired value */ - if ((sr & ISL1208_REG_SR_XTOSCB) == xtosb_val) + if (!!(sr & ISL1208_REG_SR_XTOSCB) == xtosb_val) return 0; if (xtosb_val) @@ -862,17 +862,9 @@ isl1208_probe(struct i2c_client *client) i2c_set_clientdata(client, isl1208); /* Determine which chip we have */ - if (client->dev.of_node) { - isl1208->config = of_device_get_match_data(&client->dev); - if (!isl1208->config) - return -ENODEV; - } else { - const struct i2c_device_id *id = i2c_match_id(isl1208_id, client); - - if (!id) - return -ENODEV; - isl1208->config = (struct isl1208_config *)id->driver_data; - } + isl1208->config = i2c_get_match_data(client); + if (!isl1208->config) + return -ENODEV; rc = isl1208_clk_present(client, "xin"); if (rc < 0) @@ -952,7 +944,6 @@ isl1208_probe(struct i2c_client *client) rc = isl1208_setup_irq(client, client->irq); if (rc) return rc; - } else { clear_bit(RTC_FEATURE_UPDATE_INTERRUPT, isl1208->rtc->features); } diff --git a/drivers/rtc/rtc-jz4740.c b/drivers/rtc/rtc-jz4740.c index 36453b008139..bafa7d1b9b88 100644 --- a/drivers/rtc/rtc-jz4740.c +++ b/drivers/rtc/rtc-jz4740.c @@ -11,7 +11,7 @@ #include <linux/iopoll.h> #include <linux/kernel.h> #include <linux/module.h> -#include <linux/of_device.h> +#include <linux/of.h> #include <linux/platform_device.h> #include <linux/pm_wakeirq.h> #include <linux/property.h> @@ -349,7 +349,7 @@ static int jz4740_rtc_probe(struct platform_device *pdev) if (!rtc) return -ENOMEM; - rtc->type = (enum jz4740_rtc_type)device_get_match_data(dev); + rtc->type = (uintptr_t)device_get_match_data(dev); irq = platform_get_irq(pdev, 0); if (irq < 0) diff --git a/drivers/rtc/rtc-lpc24xx.c b/drivers/rtc/rtc-lpc24xx.c index a4612e543f35..df17c48ff086 100644 --- a/drivers/rtc/rtc-lpc24xx.c +++ b/drivers/rtc/rtc-lpc24xx.c @@ -9,9 +9,8 @@ #include <linux/clk.h> #include <linux/io.h> #include <linux/kernel.h> +#include <linux/mod_devicetable.h> #include <linux/module.h> -#include <linux/of.h> -#include <linux/of_device.h> #include <linux/platform_device.h> #include <linux/rtc.h> diff --git a/drivers/rtc/rtc-m41t80.c b/drivers/rtc/rtc-m41t80.c index 3cc5151e0986..866489ad56d6 100644 --- a/drivers/rtc/rtc-m41t80.c +++ b/drivers/rtc/rtc-m41t80.c @@ -17,7 +17,7 @@ #include <linux/init.h> #include <linux/kernel.h> #include <linux/module.h> -#include <linux/of_device.h> +#include <linux/of.h> #include <linux/rtc.h> #include <linux/slab.h> #include <linux/mutex.h> diff --git a/drivers/rtc/rtc-m48t86.c b/drivers/rtc/rtc-m48t86.c index 481c9525b1dd..dd4a62e2d39c 100644 --- a/drivers/rtc/rtc-m48t86.c +++ b/drivers/rtc/rtc-m48t86.c @@ -11,6 +11,7 @@ */ #include <linux/module.h> +#include <linux/mod_devicetable.h> #include <linux/rtc.h> #include <linux/platform_device.h> #include <linux/bcd.h> @@ -269,9 +270,16 @@ static int m48t86_rtc_probe(struct platform_device *pdev) return 0; } +static const struct of_device_id m48t86_rtc_of_ids[] = { + { .compatible = "st,m48t86" }, + { /* sentinel */ } +}; +MODULE_DEVICE_TABLE(of, m48t86_rtc_of_ids); + static struct platform_driver m48t86_rtc_platform_driver = { .driver = { .name = "rtc-m48t86", + .of_match_table = m48t86_rtc_of_ids, }, .probe = m48t86_rtc_probe, }; diff --git a/drivers/rtc/rtc-mpc5121.c b/drivers/rtc/rtc-mpc5121.c index 07df43e4c4d0..28858fcaea8f 100644 --- a/drivers/rtc/rtc-mpc5121.c +++ b/drivers/rtc/rtc-mpc5121.c @@ -11,10 +11,8 @@ #include <linux/module.h> #include <linux/rtc.h> #include <linux/of.h> -#include <linux/of_address.h> -#include <linux/of_device.h> #include <linux/of_irq.h> -#include <linux/of_platform.h> +#include <linux/platform_device.h> #include <linux/io.h> #include <linux/slab.h> diff --git a/drivers/rtc/rtc-mt6397.c b/drivers/rtc/rtc-mt6397.c index 1d297af80f87..1617063669cc 100644 --- a/drivers/rtc/rtc-mt6397.c +++ b/drivers/rtc/rtc-mt6397.c @@ -9,7 +9,7 @@ #include <linux/mfd/mt6397/core.h> #include <linux/module.h> #include <linux/mutex.h> -#include <linux/of_device.h> +#include <linux/of.h> #include <linux/platform_device.h> #include <linux/regmap.h> #include <linux/rtc.h> diff --git a/drivers/rtc/rtc-mt7622.c b/drivers/rtc/rtc-mt7622.c index 81857a457c32..094c649fc137 100644 --- a/drivers/rtc/rtc-mt7622.c +++ b/drivers/rtc/rtc-mt7622.c @@ -7,9 +7,9 @@ #include <linux/clk.h> #include <linux/interrupt.h> +#include <linux/io.h> +#include <linux/mod_devicetable.h> #include <linux/module.h> -#include <linux/of_address.h> -#include <linux/of_device.h> #include <linux/platform_device.h> #include <linux/rtc.h> diff --git a/drivers/rtc/rtc-mxc.c b/drivers/rtc/rtc-mxc.c index 762cf03345f1..dbb935dbbd8a 100644 --- a/drivers/rtc/rtc-mxc.c +++ b/drivers/rtc/rtc-mxc.c @@ -11,7 +11,6 @@ #include <linux/pm_wakeirq.h> #include <linux/clk.h> #include <linux/of.h> -#include <linux/of_device.h> #define RTC_INPUT_CLK_32768HZ (0x00 << 5) #define RTC_INPUT_CLK_32000HZ (0x01 << 5) diff --git a/drivers/rtc/rtc-nct3018y.c b/drivers/rtc/rtc-nct3018y.c index a4e3f924837e..ed4e606be8e5 100644 --- a/drivers/rtc/rtc-nct3018y.c +++ b/drivers/rtc/rtc-nct3018y.c @@ -538,7 +538,7 @@ MODULE_DEVICE_TABLE(of, nct3018y_of_match); static struct i2c_driver nct3018y_driver = { .driver = { .name = "rtc-nct3018y", - .of_match_table = of_match_ptr(nct3018y_of_match), + .of_match_table = nct3018y_of_match, }, .probe = nct3018y_probe, .id_table = nct3018y_id, diff --git a/drivers/rtc/rtc-omap.c b/drivers/rtc/rtc-omap.c index 8ae4d7824ec9..5b10ab06cd2e 100644 --- a/drivers/rtc/rtc-omap.c +++ b/drivers/rtc/rtc-omap.c @@ -747,12 +747,12 @@ static int omap_rtc_probe(struct platform_device *pdev) } rtc->irq_timer = platform_get_irq(pdev, 0); - if (rtc->irq_timer <= 0) - return -ENOENT; + if (rtc->irq_timer < 0) + return rtc->irq_timer; rtc->irq_alarm = platform_get_irq(pdev, 1); - if (rtc->irq_alarm <= 0) - return -ENOENT; + if (rtc->irq_alarm < 0) + return rtc->irq_alarm; rtc->clk = devm_clk_get(&pdev->dev, "ext-clk"); if (!IS_ERR(rtc->clk)) diff --git a/drivers/rtc/rtc-pcf2127.c b/drivers/rtc/rtc-pcf2127.c index ee03b04b74ba..9c04c4e1a49c 100644 --- a/drivers/rtc/rtc-pcf2127.c +++ b/drivers/rtc/rtc-pcf2127.c @@ -1,6 +1,6 @@ // SPDX-License-Identifier: GPL-2.0-only /* - * An I2C and SPI driver for the NXP PCF2127/29 RTC + * An I2C and SPI driver for the NXP PCF2127/29/31 RTC * Copyright 2013 Til-Technologies * * Author: Renaud Cerrato <r.cerrato@til-technologies.fr> @@ -8,9 +8,13 @@ * Watchdog and tamper functions * Author: Bruno Thomsen <bruno.thomsen@gmail.com> * + * PCF2131 support + * Author: Hugo Villeneuve <hvilleneuve@dimonoff.com> + * * based on the other drivers in this same directory. * - * Datasheet: https://www.nxp.com/docs/en/data-sheet/PCF2127.pdf + * Datasheets: https://www.nxp.com/docs/en/data-sheet/PCF2127.pdf + * https://www.nxp.com/docs/en/data-sheet/PCF2131DS.pdf */ #include <linux/i2c.h> @@ -21,6 +25,7 @@ #include <linux/module.h> #include <linux/of.h> #include <linux/of_irq.h> +#include <linux/of_device.h> #include <linux/regmap.h> #include <linux/watchdog.h> @@ -28,6 +33,7 @@ #define PCF2127_REG_CTRL1 0x00 #define PCF2127_BIT_CTRL1_POR_OVRD BIT(3) #define PCF2127_BIT_CTRL1_TSF1 BIT(4) +#define PCF2127_BIT_CTRL1_STOP BIT(5) /* Control register 2 */ #define PCF2127_REG_CTRL2 0x01 #define PCF2127_BIT_CTRL2_AIE BIT(1) @@ -43,20 +49,10 @@ #define PCF2127_BIT_CTRL3_BF BIT(3) #define PCF2127_BIT_CTRL3_BTSE BIT(4) /* Time and date registers */ -#define PCF2127_REG_SC 0x03 +#define PCF2127_REG_TIME_BASE 0x03 #define PCF2127_BIT_SC_OSF BIT(7) -#define PCF2127_REG_MN 0x04 -#define PCF2127_REG_HR 0x05 -#define PCF2127_REG_DM 0x06 -#define PCF2127_REG_DW 0x07 -#define PCF2127_REG_MO 0x08 -#define PCF2127_REG_YR 0x09 /* Alarm registers */ -#define PCF2127_REG_ALARM_SC 0x0A -#define PCF2127_REG_ALARM_MN 0x0B -#define PCF2127_REG_ALARM_HR 0x0C -#define PCF2127_REG_ALARM_DM 0x0D -#define PCF2127_REG_ALARM_DW 0x0E +#define PCF2127_REG_ALARM_BASE 0x0A #define PCF2127_BIT_ALARM_AE BIT(7) /* CLKOUT control register */ #define PCF2127_REG_CLKOUT 0x0f @@ -68,21 +64,15 @@ #define PCF2127_BIT_WD_CTL_CD0 BIT(6) #define PCF2127_BIT_WD_CTL_CD1 BIT(7) #define PCF2127_REG_WD_VAL 0x11 -/* Tamper timestamp registers */ -#define PCF2127_REG_TS_CTRL 0x12 +/* Tamper timestamp1 registers */ +#define PCF2127_REG_TS1_BASE 0x12 #define PCF2127_BIT_TS_CTRL_TSOFF BIT(6) #define PCF2127_BIT_TS_CTRL_TSM BIT(7) -#define PCF2127_REG_TS_SC 0x13 -#define PCF2127_REG_TS_MN 0x14 -#define PCF2127_REG_TS_HR 0x15 -#define PCF2127_REG_TS_DM 0x16 -#define PCF2127_REG_TS_MO 0x17 -#define PCF2127_REG_TS_YR 0x18 /* * RAM registers * PCF2127 has 512 bytes general-purpose static RAM (SRAM) that is * battery backed and can survive a power outage. - * PCF2129 doesn't have this feature. + * PCF2129/31 doesn't have this feature. */ #define PCF2127_REG_RAM_ADDR_MSB 0x1A #define PCF2127_REG_RAM_WRT_CMD 0x1C @@ -90,9 +80,14 @@ /* Watchdog timer value constants */ #define PCF2127_WD_VAL_STOP 0 -#define PCF2127_WD_VAL_MIN 2 -#define PCF2127_WD_VAL_MAX 255 -#define PCF2127_WD_VAL_DEFAULT 60 +/* PCF2127/29 watchdog timer value constants */ +#define PCF2127_WD_CLOCK_HZ_X1000 1000 /* 1Hz */ +#define PCF2127_WD_MIN_HW_HEARTBEAT_MS 500 +/* PCF2131 watchdog timer value constants */ +#define PCF2131_WD_CLOCK_HZ_X1000 250 /* 1/4Hz */ +#define PCF2131_WD_MIN_HW_HEARTBEAT_MS 4000 + +#define PCF2127_WD_DEFAULT_TIMEOUT_S 60 /* Mask for currently enabled interrupts */ #define PCF2127_CTRL1_IRQ_MASK (PCF2127_BIT_CTRL1_TSF1) @@ -101,13 +96,117 @@ PCF2127_BIT_CTRL2_WDTF | \ PCF2127_BIT_CTRL2_TSF2) +#define PCF2127_MAX_TS_SUPPORTED 4 + +/* Control register 4 */ +#define PCF2131_REG_CTRL4 0x03 +#define PCF2131_BIT_CTRL4_TSF4 BIT(4) +#define PCF2131_BIT_CTRL4_TSF3 BIT(5) +#define PCF2131_BIT_CTRL4_TSF2 BIT(6) +#define PCF2131_BIT_CTRL4_TSF1 BIT(7) +/* Control register 5 */ +#define PCF2131_REG_CTRL5 0x04 +#define PCF2131_BIT_CTRL5_TSIE4 BIT(4) +#define PCF2131_BIT_CTRL5_TSIE3 BIT(5) +#define PCF2131_BIT_CTRL5_TSIE2 BIT(6) +#define PCF2131_BIT_CTRL5_TSIE1 BIT(7) +/* Software reset register */ +#define PCF2131_REG_SR_RESET 0x05 +#define PCF2131_SR_RESET_READ_PATTERN (BIT(2) | BIT(5)) +#define PCF2131_SR_RESET_CPR_CMD (PCF2131_SR_RESET_READ_PATTERN | BIT(7)) +/* Time and date registers */ +#define PCF2131_REG_TIME_BASE 0x07 +/* Alarm registers */ +#define PCF2131_REG_ALARM_BASE 0x0E +/* CLKOUT control register */ +#define PCF2131_REG_CLKOUT 0x13 +/* Watchdog registers */ +#define PCF2131_REG_WD_CTL 0x35 +#define PCF2131_REG_WD_VAL 0x36 +/* Tamper timestamp1 registers */ +#define PCF2131_REG_TS1_BASE 0x14 +/* Tamper timestamp2 registers */ +#define PCF2131_REG_TS2_BASE 0x1B +/* Tamper timestamp3 registers */ +#define PCF2131_REG_TS3_BASE 0x22 +/* Tamper timestamp4 registers */ +#define PCF2131_REG_TS4_BASE 0x29 +/* Interrupt mask registers */ +#define PCF2131_REG_INT_A_MASK1 0x31 +#define PCF2131_REG_INT_A_MASK2 0x32 +#define PCF2131_REG_INT_B_MASK1 0x33 +#define PCF2131_REG_INT_B_MASK2 0x34 +#define PCF2131_BIT_INT_BLIE BIT(0) +#define PCF2131_BIT_INT_BIE BIT(1) +#define PCF2131_BIT_INT_AIE BIT(2) +#define PCF2131_BIT_INT_WD_CD BIT(3) +#define PCF2131_BIT_INT_SI BIT(4) +#define PCF2131_BIT_INT_MI BIT(5) +#define PCF2131_CTRL2_IRQ_MASK ( \ + PCF2127_BIT_CTRL2_AF | \ + PCF2127_BIT_CTRL2_WDTF) +#define PCF2131_CTRL4_IRQ_MASK ( \ + PCF2131_BIT_CTRL4_TSF4 | \ + PCF2131_BIT_CTRL4_TSF3 | \ + PCF2131_BIT_CTRL4_TSF2 | \ + PCF2131_BIT_CTRL4_TSF1) + +enum pcf21xx_type { + PCF2127, + PCF2129, + PCF2131, + PCF21XX_LAST_ID +}; + +struct pcf21xx_ts_config { + u8 reg_base; /* Base register to read timestamp values. */ + + /* + * If the TS input pin is driven to GND, an interrupt can be generated + * (supported by all variants). + */ + u8 gnd_detect_reg; /* Interrupt control register address. */ + u8 gnd_detect_bit; /* Interrupt bit. */ + + /* + * If the TS input pin is driven to an intermediate level between GND + * and supply, an interrupt can be generated (optional feature depending + * on variant). + */ + u8 inter_detect_reg; /* Interrupt control register address. */ + u8 inter_detect_bit; /* Interrupt bit. */ + + u8 ie_reg; /* Interrupt enable control register. */ + u8 ie_bit; /* Interrupt enable bit. */ +}; + +struct pcf21xx_config { + int type; /* IC variant */ + int max_register; + unsigned int has_nvmem:1; + unsigned int has_bit_wd_ctl_cd0:1; + unsigned int wd_val_reg_readable:1; /* If watchdog value register can be read. */ + unsigned int has_int_a_b:1; /* PCF2131 supports two interrupt outputs. */ + u8 reg_time_base; /* Time/date base register. */ + u8 regs_alarm_base; /* Alarm function base registers. */ + u8 reg_wd_ctl; /* Watchdog control register. */ + u8 reg_wd_val; /* Watchdog value register. */ + u8 reg_clkout; /* Clkout register. */ + int wdd_clock_hz_x1000; /* Watchdog clock in Hz multiplicated by 1000 */ + int wdd_min_hw_heartbeat_ms; + unsigned int ts_count; + struct pcf21xx_ts_config ts[PCF2127_MAX_TS_SUPPORTED]; + struct attribute_group attribute_group; +}; + struct pcf2127 { struct rtc_device *rtc; struct watchdog_device wdd; struct regmap *regmap; - time64_t ts; - bool ts_valid; + const struct pcf21xx_config *cfg; bool irq_enabled; + time64_t ts[PCF2127_MAX_TS_SUPPORTED]; /* Timestamp values. */ + bool ts_valid[PCF2127_MAX_TS_SUPPORTED]; /* Timestamp valid indication. */ }; /* @@ -117,27 +216,22 @@ struct pcf2127 { static int pcf2127_rtc_read_time(struct device *dev, struct rtc_time *tm) { struct pcf2127 *pcf2127 = dev_get_drvdata(dev); - unsigned char buf[10]; + unsigned char buf[7]; int ret; /* * Avoid reading CTRL2 register as it causes WD_VAL register * value to reset to 0 which means watchdog is stopped. */ - ret = regmap_bulk_read(pcf2127->regmap, PCF2127_REG_CTRL3, - (buf + PCF2127_REG_CTRL3), - ARRAY_SIZE(buf) - PCF2127_REG_CTRL3); + ret = regmap_bulk_read(pcf2127->regmap, pcf2127->cfg->reg_time_base, + buf, sizeof(buf)); if (ret) { dev_err(dev, "%s: read error\n", __func__); return ret; } - if (buf[PCF2127_REG_CTRL3] & PCF2127_BIT_CTRL3_BLF) - dev_info(dev, - "low voltage detected, check/replace RTC battery.\n"); - /* Clock integrity is not guaranteed when OSF flag is set. */ - if (buf[PCF2127_REG_SC] & PCF2127_BIT_SC_OSF) { + if (buf[0] & PCF2127_BIT_SC_OSF) { /* * no need clear the flag here, * it will be cleared once the new date is saved @@ -148,20 +242,17 @@ static int pcf2127_rtc_read_time(struct device *dev, struct rtc_time *tm) } dev_dbg(dev, - "%s: raw data is cr3=%02x, sec=%02x, min=%02x, hr=%02x, " + "%s: raw data is sec=%02x, min=%02x, hr=%02x, " "mday=%02x, wday=%02x, mon=%02x, year=%02x\n", - __func__, buf[PCF2127_REG_CTRL3], buf[PCF2127_REG_SC], - buf[PCF2127_REG_MN], buf[PCF2127_REG_HR], - buf[PCF2127_REG_DM], buf[PCF2127_REG_DW], - buf[PCF2127_REG_MO], buf[PCF2127_REG_YR]); - - tm->tm_sec = bcd2bin(buf[PCF2127_REG_SC] & 0x7F); - tm->tm_min = bcd2bin(buf[PCF2127_REG_MN] & 0x7F); - tm->tm_hour = bcd2bin(buf[PCF2127_REG_HR] & 0x3F); /* rtc hr 0-23 */ - tm->tm_mday = bcd2bin(buf[PCF2127_REG_DM] & 0x3F); - tm->tm_wday = buf[PCF2127_REG_DW] & 0x07; - tm->tm_mon = bcd2bin(buf[PCF2127_REG_MO] & 0x1F) - 1; /* rtc mn 1-12 */ - tm->tm_year = bcd2bin(buf[PCF2127_REG_YR]); + __func__, buf[0], buf[1], buf[2], buf[3], buf[4], buf[5], buf[6]); + + tm->tm_sec = bcd2bin(buf[0] & 0x7F); + tm->tm_min = bcd2bin(buf[1] & 0x7F); + tm->tm_hour = bcd2bin(buf[2] & 0x3F); + tm->tm_mday = bcd2bin(buf[3] & 0x3F); + tm->tm_wday = buf[4] & 0x07; + tm->tm_mon = bcd2bin(buf[5] & 0x1F) - 1; + tm->tm_year = bcd2bin(buf[6]); tm->tm_year += 100; dev_dbg(dev, "%s: tm is secs=%d, mins=%d, hours=%d, " @@ -198,14 +289,45 @@ static int pcf2127_rtc_set_time(struct device *dev, struct rtc_time *tm) /* year */ buf[i++] = bin2bcd(tm->tm_year - 100); - /* write register's data */ - err = regmap_bulk_write(pcf2127->regmap, PCF2127_REG_SC, buf, i); + /* Write access to time registers: + * PCF2127/29: no special action required. + * PCF2131: requires setting the STOP and CPR bits. STOP bit needs to + * be cleared after time registers are updated. + */ + if (pcf2127->cfg->type == PCF2131) { + err = regmap_update_bits(pcf2127->regmap, PCF2127_REG_CTRL1, + PCF2127_BIT_CTRL1_STOP, + PCF2127_BIT_CTRL1_STOP); + if (err) { + dev_dbg(dev, "setting STOP bit failed\n"); + return err; + } + + err = regmap_write(pcf2127->regmap, PCF2131_REG_SR_RESET, + PCF2131_SR_RESET_CPR_CMD); + if (err) { + dev_dbg(dev, "sending CPR cmd failed\n"); + return err; + } + } + + /* write time register's data */ + err = regmap_bulk_write(pcf2127->regmap, pcf2127->cfg->reg_time_base, buf, i); if (err) { - dev_err(dev, - "%s: err=%d", __func__, err); + dev_dbg(dev, "%s: err=%d", __func__, err); return err; } + if (pcf2127->cfg->type == PCF2131) { + /* Clear STOP bit (PCF2131 only) after write is completed. */ + err = regmap_update_bits(pcf2127->regmap, PCF2127_REG_CTRL1, + PCF2127_BIT_CTRL1_STOP, 0); + if (err) { + dev_dbg(dev, "clearing STOP bit failed\n"); + return err; + } + } + return 0; } @@ -275,9 +397,16 @@ static int pcf2127_nvmem_write(void *priv, unsigned int offset, static int pcf2127_wdt_ping(struct watchdog_device *wdd) { + int wd_val; struct pcf2127 *pcf2127 = watchdog_get_drvdata(wdd); - return regmap_write(pcf2127->regmap, PCF2127_REG_WD_VAL, wdd->timeout); + /* + * Compute counter value of WATCHDG_TIM_VAL to obtain desired period + * in seconds, depending on the source clock frequency. + */ + wd_val = ((wdd->timeout * pcf2127->cfg->wdd_clock_hz_x1000) / 1000) + 1; + + return regmap_write(pcf2127->regmap, pcf2127->cfg->reg_wd_val, wd_val); } /* @@ -311,7 +440,7 @@ static int pcf2127_wdt_stop(struct watchdog_device *wdd) { struct pcf2127 *pcf2127 = watchdog_get_drvdata(wdd); - return regmap_write(pcf2127->regmap, PCF2127_REG_WD_VAL, + return regmap_write(pcf2127->regmap, pcf2127->cfg->reg_wd_val, PCF2127_WD_VAL_STOP); } @@ -339,9 +468,25 @@ static const struct watchdog_ops pcf2127_watchdog_ops = { .set_timeout = pcf2127_wdt_set_timeout, }; +/* + * Compute watchdog period, t, in seconds, from the WATCHDG_TIM_VAL register + * value, n, and the clock frequency, f1000, in Hz x 1000. + * + * The PCF2127/29 datasheet gives t as: + * t = n / f + * The PCF2131 datasheet gives t as: + * t = (n - 1) / f + * For both variants, the watchdog is triggered when the WATCHDG_TIM_VAL reaches + * the value 1, and not zero. Consequently, the equation from the PCF2131 + * datasheet seems to be the correct one for both variants. + */ +static int pcf2127_watchdog_get_period(int n, int f1000) +{ + return (1000 * (n - 1)) / f1000; +} + static int pcf2127_watchdog_init(struct device *dev, struct pcf2127 *pcf2127) { - u32 wdd_timeout; int ret; if (!IS_ENABLED(CONFIG_WATCHDOG) || @@ -351,21 +496,35 @@ static int pcf2127_watchdog_init(struct device *dev, struct pcf2127 *pcf2127) pcf2127->wdd.parent = dev; pcf2127->wdd.info = &pcf2127_wdt_info; pcf2127->wdd.ops = &pcf2127_watchdog_ops; - pcf2127->wdd.min_timeout = PCF2127_WD_VAL_MIN; - pcf2127->wdd.max_timeout = PCF2127_WD_VAL_MAX; - pcf2127->wdd.timeout = PCF2127_WD_VAL_DEFAULT; - pcf2127->wdd.min_hw_heartbeat_ms = 500; + + pcf2127->wdd.min_timeout = + pcf2127_watchdog_get_period( + 2, pcf2127->cfg->wdd_clock_hz_x1000); + pcf2127->wdd.max_timeout = + pcf2127_watchdog_get_period( + 255, pcf2127->cfg->wdd_clock_hz_x1000); + pcf2127->wdd.timeout = PCF2127_WD_DEFAULT_TIMEOUT_S; + + dev_dbg(dev, "%s clock = %d Hz / 1000\n", __func__, + pcf2127->cfg->wdd_clock_hz_x1000); + + pcf2127->wdd.min_hw_heartbeat_ms = pcf2127->cfg->wdd_min_hw_heartbeat_ms; pcf2127->wdd.status = WATCHDOG_NOWAYOUT_INIT_STATUS; watchdog_set_drvdata(&pcf2127->wdd, pcf2127); /* Test if watchdog timer is started by bootloader */ - ret = regmap_read(pcf2127->regmap, PCF2127_REG_WD_VAL, &wdd_timeout); - if (ret) - return ret; + if (pcf2127->cfg->wd_val_reg_readable) { + u32 wdd_timeout; - if (wdd_timeout) - set_bit(WDOG_HW_RUNNING, &pcf2127->wdd.status); + ret = regmap_read(pcf2127->regmap, pcf2127->cfg->reg_wd_val, + &wdd_timeout); + if (ret) + return ret; + + if (wdd_timeout) + set_bit(WDOG_HW_RUNNING, &pcf2127->wdd.status); + } return devm_watchdog_register_device(dev, &pcf2127->wdd); } @@ -386,8 +545,8 @@ static int pcf2127_rtc_read_alarm(struct device *dev, struct rtc_wkalrm *alrm) if (ret) return ret; - ret = regmap_bulk_read(pcf2127->regmap, PCF2127_REG_ALARM_SC, buf, - sizeof(buf)); + ret = regmap_bulk_read(pcf2127->regmap, pcf2127->cfg->regs_alarm_base, + buf, sizeof(buf)); if (ret) return ret; @@ -437,8 +596,8 @@ static int pcf2127_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alrm) buf[3] = bin2bcd(alrm->time.tm_mday); buf[4] = PCF2127_BIT_ALARM_AE; /* Do not match on week day */ - ret = regmap_bulk_write(pcf2127->regmap, PCF2127_REG_ALARM_SC, buf, - sizeof(buf)); + ret = regmap_bulk_write(pcf2127->regmap, pcf2127->cfg->regs_alarm_base, + buf, sizeof(buf)); if (ret) return ret; @@ -446,38 +605,35 @@ static int pcf2127_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alrm) } /* - * This function reads ctrl2 register, caller is responsible for calling - * pcf2127_wdt_active_ping() + * This function reads one timestamp function data, caller is responsible for + * calling pcf2127_wdt_active_ping() */ -static int pcf2127_rtc_ts_read(struct device *dev, time64_t *ts) +static int pcf2127_rtc_ts_read(struct device *dev, time64_t *ts, + int ts_id) { struct pcf2127 *pcf2127 = dev_get_drvdata(dev); struct rtc_time tm; int ret; - unsigned char data[25]; + unsigned char data[7]; - ret = regmap_bulk_read(pcf2127->regmap, PCF2127_REG_CTRL1, data, - sizeof(data)); + ret = regmap_bulk_read(pcf2127->regmap, pcf2127->cfg->ts[ts_id].reg_base, + data, sizeof(data)); if (ret) { dev_err(dev, "%s: read error ret=%d\n", __func__, ret); return ret; } dev_dbg(dev, - "%s: raw data is cr1=%02x, cr2=%02x, cr3=%02x, ts_sc=%02x, ts_mn=%02x, ts_hr=%02x, ts_dm=%02x, ts_mo=%02x, ts_yr=%02x\n", - __func__, data[PCF2127_REG_CTRL1], data[PCF2127_REG_CTRL2], - data[PCF2127_REG_CTRL3], data[PCF2127_REG_TS_SC], - data[PCF2127_REG_TS_MN], data[PCF2127_REG_TS_HR], - data[PCF2127_REG_TS_DM], data[PCF2127_REG_TS_MO], - data[PCF2127_REG_TS_YR]); - - tm.tm_sec = bcd2bin(data[PCF2127_REG_TS_SC] & 0x7F); - tm.tm_min = bcd2bin(data[PCF2127_REG_TS_MN] & 0x7F); - tm.tm_hour = bcd2bin(data[PCF2127_REG_TS_HR] & 0x3F); - tm.tm_mday = bcd2bin(data[PCF2127_REG_TS_DM] & 0x3F); + "%s: raw data is ts_sc=%02x, ts_mn=%02x, ts_hr=%02x, ts_dm=%02x, ts_mo=%02x, ts_yr=%02x\n", + __func__, data[1], data[2], data[3], data[4], data[5], data[6]); + + tm.tm_sec = bcd2bin(data[1] & 0x7F); + tm.tm_min = bcd2bin(data[2] & 0x7F); + tm.tm_hour = bcd2bin(data[3] & 0x3F); + tm.tm_mday = bcd2bin(data[4] & 0x3F); /* TS_MO register (month) value range: 1-12 */ - tm.tm_mon = bcd2bin(data[PCF2127_REG_TS_MO] & 0x1F) - 1; - tm.tm_year = bcd2bin(data[PCF2127_REG_TS_YR]); + tm.tm_mon = bcd2bin(data[5] & 0x1F) - 1; + tm.tm_year = bcd2bin(data[6]); if (tm.tm_year < 70) tm.tm_year += 100; /* assume we are in 1970...2069 */ @@ -491,47 +647,84 @@ static int pcf2127_rtc_ts_read(struct device *dev, time64_t *ts) return 0; }; -static void pcf2127_rtc_ts_snapshot(struct device *dev) +static void pcf2127_rtc_ts_snapshot(struct device *dev, int ts_id) { struct pcf2127 *pcf2127 = dev_get_drvdata(dev); int ret; + if (ts_id >= pcf2127->cfg->ts_count) + return; + /* Let userspace read the first timestamp */ - if (pcf2127->ts_valid) + if (pcf2127->ts_valid[ts_id]) return; - ret = pcf2127_rtc_ts_read(dev, &pcf2127->ts); + ret = pcf2127_rtc_ts_read(dev, &pcf2127->ts[ts_id], ts_id); if (!ret) - pcf2127->ts_valid = true; + pcf2127->ts_valid[ts_id] = true; } static irqreturn_t pcf2127_rtc_irq(int irq, void *dev) { struct pcf2127 *pcf2127 = dev_get_drvdata(dev); - unsigned int ctrl1, ctrl2; + unsigned int ctrl2; int ret = 0; - ret = regmap_read(pcf2127->regmap, PCF2127_REG_CTRL1, &ctrl1); - if (ret) - return IRQ_NONE; - ret = regmap_read(pcf2127->regmap, PCF2127_REG_CTRL2, &ctrl2); if (ret) return IRQ_NONE; - if (!(ctrl1 & PCF2127_CTRL1_IRQ_MASK || ctrl2 & PCF2127_CTRL2_IRQ_MASK)) - return IRQ_NONE; + if (pcf2127->cfg->ts_count == 1) { + /* PCF2127/29 */ + unsigned int ctrl1; + + ret = regmap_read(pcf2127->regmap, PCF2127_REG_CTRL1, &ctrl1); + if (ret) + return IRQ_NONE; + + if (!(ctrl1 & PCF2127_CTRL1_IRQ_MASK || ctrl2 & PCF2127_CTRL2_IRQ_MASK)) + return IRQ_NONE; + + if (ctrl1 & PCF2127_BIT_CTRL1_TSF1 || ctrl2 & PCF2127_BIT_CTRL2_TSF2) + pcf2127_rtc_ts_snapshot(dev, 0); + + if (ctrl1 & PCF2127_CTRL1_IRQ_MASK) + regmap_write(pcf2127->regmap, PCF2127_REG_CTRL1, + ctrl1 & ~PCF2127_CTRL1_IRQ_MASK); + + if (ctrl2 & PCF2127_CTRL2_IRQ_MASK) + regmap_write(pcf2127->regmap, PCF2127_REG_CTRL2, + ctrl2 & ~PCF2127_CTRL2_IRQ_MASK); + } else { + /* PCF2131. */ + unsigned int ctrl4; + + ret = regmap_read(pcf2127->regmap, PCF2131_REG_CTRL4, &ctrl4); + if (ret) + return IRQ_NONE; + + if (!(ctrl4 & PCF2131_CTRL4_IRQ_MASK || ctrl2 & PCF2131_CTRL2_IRQ_MASK)) + return IRQ_NONE; - if (ctrl1 & PCF2127_BIT_CTRL1_TSF1 || ctrl2 & PCF2127_BIT_CTRL2_TSF2) - pcf2127_rtc_ts_snapshot(dev); + if (ctrl4 & PCF2131_CTRL4_IRQ_MASK) { + int i; + int tsf_bit = PCF2131_BIT_CTRL4_TSF1; /* Start at bit 7. */ - if (ctrl1 & PCF2127_CTRL1_IRQ_MASK) - regmap_write(pcf2127->regmap, PCF2127_REG_CTRL1, - ctrl1 & ~PCF2127_CTRL1_IRQ_MASK); + for (i = 0; i < pcf2127->cfg->ts_count; i++) { + if (ctrl4 & tsf_bit) + pcf2127_rtc_ts_snapshot(dev, i); - if (ctrl2 & PCF2127_CTRL2_IRQ_MASK) - regmap_write(pcf2127->regmap, PCF2127_REG_CTRL2, - ctrl2 & ~PCF2127_CTRL2_IRQ_MASK); + tsf_bit = tsf_bit >> 1; + } + + regmap_write(pcf2127->regmap, PCF2131_REG_CTRL4, + ctrl4 & ~PCF2131_CTRL4_IRQ_MASK); + } + + if (ctrl2 & PCF2131_CTRL2_IRQ_MASK) + regmap_write(pcf2127->regmap, PCF2127_REG_CTRL2, + ctrl2 & ~PCF2131_CTRL2_IRQ_MASK); + } if (ctrl2 & PCF2127_BIT_CTRL2_AF) rtc_update_irq(pcf2127->rtc, 1, RTC_IRQF | RTC_AF); @@ -552,28 +745,41 @@ static const struct rtc_class_ops pcf2127_rtc_ops = { /* sysfs interface */ -static ssize_t timestamp0_store(struct device *dev, - struct device_attribute *attr, - const char *buf, size_t count) +static ssize_t timestamp_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count, int ts_id) { struct pcf2127 *pcf2127 = dev_get_drvdata(dev->parent); int ret; + if (ts_id >= pcf2127->cfg->ts_count) + return 0; + if (pcf2127->irq_enabled) { - pcf2127->ts_valid = false; + pcf2127->ts_valid[ts_id] = false; } else { - ret = regmap_update_bits(pcf2127->regmap, PCF2127_REG_CTRL1, - PCF2127_BIT_CTRL1_TSF1, 0); + /* Always clear GND interrupt bit. */ + ret = regmap_update_bits(pcf2127->regmap, + pcf2127->cfg->ts[ts_id].gnd_detect_reg, + pcf2127->cfg->ts[ts_id].gnd_detect_bit, + 0); + if (ret) { - dev_err(dev, "%s: update ctrl1 ret=%d\n", __func__, ret); + dev_err(dev, "%s: update TS gnd detect ret=%d\n", __func__, ret); return ret; } - ret = regmap_update_bits(pcf2127->regmap, PCF2127_REG_CTRL2, - PCF2127_BIT_CTRL2_TSF2, 0); - if (ret) { - dev_err(dev, "%s: update ctrl2 ret=%d\n", __func__, ret); - return ret; + if (pcf2127->cfg->ts[ts_id].inter_detect_bit) { + /* Clear intermediate level interrupt bit if supported. */ + ret = regmap_update_bits(pcf2127->regmap, + pcf2127->cfg->ts[ts_id].inter_detect_reg, + pcf2127->cfg->ts[ts_id].inter_detect_bit, + 0); + if (ret) { + dev_err(dev, "%s: update TS intermediate level detect ret=%d\n", + __func__, ret); + return ret; + } } ret = pcf2127_wdt_active_ping(&pcf2127->wdd); @@ -582,34 +788,84 @@ static ssize_t timestamp0_store(struct device *dev, } return count; +} + +static ssize_t timestamp0_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) +{ + return timestamp_store(dev, attr, buf, count, 0); }; -static ssize_t timestamp0_show(struct device *dev, - struct device_attribute *attr, char *buf) +static ssize_t timestamp1_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) +{ + return timestamp_store(dev, attr, buf, count, 1); +}; + +static ssize_t timestamp2_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) +{ + return timestamp_store(dev, attr, buf, count, 2); +}; + +static ssize_t timestamp3_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) +{ + return timestamp_store(dev, attr, buf, count, 3); +}; + +static ssize_t timestamp_show(struct device *dev, + struct device_attribute *attr, char *buf, + int ts_id) { struct pcf2127 *pcf2127 = dev_get_drvdata(dev->parent); - unsigned int ctrl1, ctrl2; int ret; time64_t ts; + if (ts_id >= pcf2127->cfg->ts_count) + return 0; + if (pcf2127->irq_enabled) { - if (!pcf2127->ts_valid) + if (!pcf2127->ts_valid[ts_id]) return 0; - ts = pcf2127->ts; + ts = pcf2127->ts[ts_id]; } else { - ret = regmap_read(pcf2127->regmap, PCF2127_REG_CTRL1, &ctrl1); - if (ret) - return 0; + u8 valid_low = 0; + u8 valid_inter = 0; + unsigned int ctrl; - ret = regmap_read(pcf2127->regmap, PCF2127_REG_CTRL2, &ctrl2); + /* Check if TS input pin is driven to GND, supported by all + * variants. + */ + ret = regmap_read(pcf2127->regmap, + pcf2127->cfg->ts[ts_id].gnd_detect_reg, + &ctrl); if (ret) return 0; - if (!(ctrl1 & PCF2127_BIT_CTRL1_TSF1) && - !(ctrl2 & PCF2127_BIT_CTRL2_TSF2)) + valid_low = ctrl & pcf2127->cfg->ts[ts_id].gnd_detect_bit; + + if (pcf2127->cfg->ts[ts_id].inter_detect_bit) { + /* Check if TS input pin is driven to intermediate level + * between GND and supply, if supported by variant. + */ + ret = regmap_read(pcf2127->regmap, + pcf2127->cfg->ts[ts_id].inter_detect_reg, + &ctrl); + if (ret) + return 0; + + valid_inter = ctrl & pcf2127->cfg->ts[ts_id].inter_detect_bit; + } + + if (!valid_low && !valid_inter) return 0; - ret = pcf2127_rtc_ts_read(dev->parent, &ts); + ret = pcf2127_rtc_ts_read(dev->parent, &ts, ts_id); if (ret) return 0; @@ -618,21 +874,227 @@ static ssize_t timestamp0_show(struct device *dev, return ret; } return sprintf(buf, "%llu\n", (unsigned long long)ts); +} + +static ssize_t timestamp0_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + return timestamp_show(dev, attr, buf, 0); +}; + +static ssize_t timestamp1_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + return timestamp_show(dev, attr, buf, 1); +}; + +static ssize_t timestamp2_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + return timestamp_show(dev, attr, buf, 2); +}; + +static ssize_t timestamp3_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + return timestamp_show(dev, attr, buf, 3); }; static DEVICE_ATTR_RW(timestamp0); +static DEVICE_ATTR_RW(timestamp1); +static DEVICE_ATTR_RW(timestamp2); +static DEVICE_ATTR_RW(timestamp3); static struct attribute *pcf2127_attrs[] = { &dev_attr_timestamp0.attr, NULL }; -static const struct attribute_group pcf2127_attr_group = { - .attrs = pcf2127_attrs, +static struct attribute *pcf2131_attrs[] = { + &dev_attr_timestamp0.attr, + &dev_attr_timestamp1.attr, + &dev_attr_timestamp2.attr, + &dev_attr_timestamp3.attr, + NULL }; +static struct pcf21xx_config pcf21xx_cfg[] = { + [PCF2127] = { + .type = PCF2127, + .max_register = 0x1d, + .has_nvmem = 1, + .has_bit_wd_ctl_cd0 = 1, + .wd_val_reg_readable = 1, + .has_int_a_b = 0, + .reg_time_base = PCF2127_REG_TIME_BASE, + .regs_alarm_base = PCF2127_REG_ALARM_BASE, + .reg_wd_ctl = PCF2127_REG_WD_CTL, + .reg_wd_val = PCF2127_REG_WD_VAL, + .reg_clkout = PCF2127_REG_CLKOUT, + .wdd_clock_hz_x1000 = PCF2127_WD_CLOCK_HZ_X1000, + .wdd_min_hw_heartbeat_ms = PCF2127_WD_MIN_HW_HEARTBEAT_MS, + .ts_count = 1, + .ts[0] = { + .reg_base = PCF2127_REG_TS1_BASE, + .gnd_detect_reg = PCF2127_REG_CTRL1, + .gnd_detect_bit = PCF2127_BIT_CTRL1_TSF1, + .inter_detect_reg = PCF2127_REG_CTRL2, + .inter_detect_bit = PCF2127_BIT_CTRL2_TSF2, + .ie_reg = PCF2127_REG_CTRL2, + .ie_bit = PCF2127_BIT_CTRL2_TSIE, + }, + .attribute_group = { + .attrs = pcf2127_attrs, + }, + }, + [PCF2129] = { + .type = PCF2129, + .max_register = 0x19, + .has_nvmem = 0, + .has_bit_wd_ctl_cd0 = 0, + .wd_val_reg_readable = 1, + .has_int_a_b = 0, + .reg_time_base = PCF2127_REG_TIME_BASE, + .regs_alarm_base = PCF2127_REG_ALARM_BASE, + .reg_wd_ctl = PCF2127_REG_WD_CTL, + .reg_wd_val = PCF2127_REG_WD_VAL, + .reg_clkout = PCF2127_REG_CLKOUT, + .wdd_clock_hz_x1000 = PCF2127_WD_CLOCK_HZ_X1000, + .wdd_min_hw_heartbeat_ms = PCF2127_WD_MIN_HW_HEARTBEAT_MS, + .ts_count = 1, + .ts[0] = { + .reg_base = PCF2127_REG_TS1_BASE, + .gnd_detect_reg = PCF2127_REG_CTRL1, + .gnd_detect_bit = PCF2127_BIT_CTRL1_TSF1, + .inter_detect_reg = PCF2127_REG_CTRL2, + .inter_detect_bit = PCF2127_BIT_CTRL2_TSF2, + .ie_reg = PCF2127_REG_CTRL2, + .ie_bit = PCF2127_BIT_CTRL2_TSIE, + }, + .attribute_group = { + .attrs = pcf2127_attrs, + }, + }, + [PCF2131] = { + .type = PCF2131, + .max_register = 0x36, + .has_nvmem = 0, + .has_bit_wd_ctl_cd0 = 0, + .wd_val_reg_readable = 0, + .has_int_a_b = 1, + .reg_time_base = PCF2131_REG_TIME_BASE, + .regs_alarm_base = PCF2131_REG_ALARM_BASE, + .reg_wd_ctl = PCF2131_REG_WD_CTL, + .reg_wd_val = PCF2131_REG_WD_VAL, + .reg_clkout = PCF2131_REG_CLKOUT, + .wdd_clock_hz_x1000 = PCF2131_WD_CLOCK_HZ_X1000, + .wdd_min_hw_heartbeat_ms = PCF2131_WD_MIN_HW_HEARTBEAT_MS, + .ts_count = 4, + .ts[0] = { + .reg_base = PCF2131_REG_TS1_BASE, + .gnd_detect_reg = PCF2131_REG_CTRL4, + .gnd_detect_bit = PCF2131_BIT_CTRL4_TSF1, + .inter_detect_bit = 0, + .ie_reg = PCF2131_REG_CTRL5, + .ie_bit = PCF2131_BIT_CTRL5_TSIE1, + }, + .ts[1] = { + .reg_base = PCF2131_REG_TS2_BASE, + .gnd_detect_reg = PCF2131_REG_CTRL4, + .gnd_detect_bit = PCF2131_BIT_CTRL4_TSF2, + .inter_detect_bit = 0, + .ie_reg = PCF2131_REG_CTRL5, + .ie_bit = PCF2131_BIT_CTRL5_TSIE2, + }, + .ts[2] = { + .reg_base = PCF2131_REG_TS3_BASE, + .gnd_detect_reg = PCF2131_REG_CTRL4, + .gnd_detect_bit = PCF2131_BIT_CTRL4_TSF3, + .inter_detect_bit = 0, + .ie_reg = PCF2131_REG_CTRL5, + .ie_bit = PCF2131_BIT_CTRL5_TSIE3, + }, + .ts[3] = { + .reg_base = PCF2131_REG_TS4_BASE, + .gnd_detect_reg = PCF2131_REG_CTRL4, + .gnd_detect_bit = PCF2131_BIT_CTRL4_TSF4, + .inter_detect_bit = 0, + .ie_reg = PCF2131_REG_CTRL5, + .ie_bit = PCF2131_BIT_CTRL5_TSIE4, + }, + .attribute_group = { + .attrs = pcf2131_attrs, + }, + }, +}; + +/* + * Enable timestamp function and corresponding interrupt(s). + */ +static int pcf2127_enable_ts(struct device *dev, int ts_id) +{ + struct pcf2127 *pcf2127 = dev_get_drvdata(dev); + int ret; + + if (ts_id >= pcf2127->cfg->ts_count) { + dev_err(dev, "%s: invalid tamper detection ID (%d)\n", + __func__, ts_id); + return -EINVAL; + } + + /* Enable timestamp function. */ + ret = regmap_update_bits(pcf2127->regmap, + pcf2127->cfg->ts[ts_id].reg_base, + PCF2127_BIT_TS_CTRL_TSOFF | + PCF2127_BIT_TS_CTRL_TSM, + PCF2127_BIT_TS_CTRL_TSM); + if (ret) { + dev_err(dev, "%s: tamper detection config (ts%d_ctrl) failed\n", + __func__, ts_id); + return ret; + } + + /* + * Enable interrupt generation when TSF timestamp flag is set. + * Interrupt signals are open-drain outputs and can be left floating if + * unused. + */ + ret = regmap_update_bits(pcf2127->regmap, pcf2127->cfg->ts[ts_id].ie_reg, + pcf2127->cfg->ts[ts_id].ie_bit, + pcf2127->cfg->ts[ts_id].ie_bit); + if (ret) { + dev_err(dev, "%s: tamper detection TSIE%d config failed\n", + __func__, ts_id); + return ret; + } + + return ret; +} + +/* Route all interrupt sources to INT A pin. */ +static int pcf2127_configure_interrupt_pins(struct device *dev) +{ + struct pcf2127 *pcf2127 = dev_get_drvdata(dev); + int ret; + + /* Mask bits need to be cleared to enable corresponding + * interrupt source. + */ + ret = regmap_write(pcf2127->regmap, + PCF2131_REG_INT_A_MASK1, 0); + if (ret) + return ret; + + ret = regmap_write(pcf2127->regmap, + PCF2131_REG_INT_A_MASK2, 0); + if (ret) + return ret; + + return ret; +} + static int pcf2127_probe(struct device *dev, struct regmap *regmap, - int alarm_irq, const char *name, bool is_pcf2127) + int alarm_irq, const struct pcf21xx_config *config) { struct pcf2127 *pcf2127; int ret = 0; @@ -645,6 +1107,7 @@ static int pcf2127_probe(struct device *dev, struct regmap *regmap, return -ENOMEM; pcf2127->regmap = regmap; + pcf2127->cfg = config; dev_set_drvdata(dev, pcf2127); @@ -656,8 +1119,16 @@ static int pcf2127_probe(struct device *dev, struct regmap *regmap, pcf2127->rtc->range_min = RTC_TIMESTAMP_BEGIN_2000; pcf2127->rtc->range_max = RTC_TIMESTAMP_END_2099; pcf2127->rtc->set_start_time = true; /* Sets actual start to 1970 */ - set_bit(RTC_FEATURE_ALARM_RES_2S, pcf2127->rtc->features); - clear_bit(RTC_FEATURE_UPDATE_INTERRUPT, pcf2127->rtc->features); + + /* + * PCF2127/29 do not work correctly when setting alarms at 1s intervals. + * PCF2131 is ok. + */ + if (pcf2127->cfg->type == PCF2127 || pcf2127->cfg->type == PCF2129) { + set_bit(RTC_FEATURE_ALARM_RES_2S, pcf2127->rtc->features); + clear_bit(RTC_FEATURE_UPDATE_INTERRUPT, pcf2127->rtc->features); + } + clear_bit(RTC_FEATURE_ALARM, pcf2127->rtc->features); if (alarm_irq > 0) { @@ -688,7 +1159,16 @@ static int pcf2127_probe(struct device *dev, struct regmap *regmap, set_bit(RTC_FEATURE_ALARM, pcf2127->rtc->features); } - if (is_pcf2127) { + if (pcf2127->cfg->has_int_a_b) { + /* Configure int A/B pins, independently of alarm_irq. */ + ret = pcf2127_configure_interrupt_pins(dev); + if (ret) { + dev_err(dev, "failed to configure interrupt pins\n"); + return ret; + } + } + + if (pcf2127->cfg->has_nvmem) { struct nvmem_config nvmem_cfg = { .priv = pcf2127, .reg_read = pcf2127_nvmem_read, @@ -703,15 +1183,17 @@ static int pcf2127_probe(struct device *dev, struct regmap *regmap, * The "Power-On Reset Override" facility prevents the RTC to do a reset * after power on. For normal operation the PORO must be disabled. */ - regmap_clear_bits(pcf2127->regmap, PCF2127_REG_CTRL1, + ret = regmap_clear_bits(pcf2127->regmap, PCF2127_REG_CTRL1, PCF2127_BIT_CTRL1_POR_OVRD); + if (ret < 0) + return ret; - ret = regmap_read(pcf2127->regmap, PCF2127_REG_CLKOUT, &val); + ret = regmap_read(pcf2127->regmap, pcf2127->cfg->reg_clkout, &val); if (ret < 0) return ret; if (!(val & PCF2127_BIT_CLKOUT_OTPR)) { - ret = regmap_set_bits(pcf2127->regmap, PCF2127_REG_CLKOUT, + ret = regmap_set_bits(pcf2127->regmap, pcf2127->cfg->reg_clkout, PCF2127_BIT_CLKOUT_OTPR); if (ret < 0) return ret; @@ -721,20 +1203,20 @@ static int pcf2127_probe(struct device *dev, struct regmap *regmap, /* * Watchdog timer enabled and reset pin /RST activated when timed out. - * Select 1Hz clock source for watchdog timer. + * Select 1Hz clock source for watchdog timer (1/4Hz for PCF2131). * Note: Countdown timer disabled and not available. - * For pca2129, pcf2129, only bit[7] is for Symbol WD_CD + * For pca2129, pcf2129 and pcf2131, only bit[7] is for Symbol WD_CD * of register watchdg_tim_ctl. The bit[6] is labeled * as T. Bits labeled as T must always be written with * logic 0. */ - ret = regmap_update_bits(pcf2127->regmap, PCF2127_REG_WD_CTL, + ret = regmap_update_bits(pcf2127->regmap, pcf2127->cfg->reg_wd_ctl, PCF2127_BIT_WD_CTL_CD1 | PCF2127_BIT_WD_CTL_CD0 | PCF2127_BIT_WD_CTL_TF1 | PCF2127_BIT_WD_CTL_TF0, PCF2127_BIT_WD_CTL_CD1 | - (is_pcf2127 ? PCF2127_BIT_WD_CTL_CD0 : 0) | + (pcf2127->cfg->has_bit_wd_ctl_cd0 ? PCF2127_BIT_WD_CTL_CD0 : 0) | PCF2127_BIT_WD_CTL_TF1); if (ret) { dev_err(dev, "%s: watchdog config (wd_ctl) failed\n", __func__); @@ -760,34 +1242,15 @@ static int pcf2127_probe(struct device *dev, struct regmap *regmap, } /* - * Enable timestamp function and store timestamp of first trigger - * event until TSF1 and TSF2 interrupt flags are cleared. - */ - ret = regmap_update_bits(pcf2127->regmap, PCF2127_REG_TS_CTRL, - PCF2127_BIT_TS_CTRL_TSOFF | - PCF2127_BIT_TS_CTRL_TSM, - PCF2127_BIT_TS_CTRL_TSM); - if (ret) { - dev_err(dev, "%s: tamper detection config (ts_ctrl) failed\n", - __func__); - return ret; - } - - /* - * Enable interrupt generation when TSF1 or TSF2 timestamp flags - * are set. Interrupt signal is an open-drain output and can be - * left floating if unused. + * Enable timestamp functions 1 to 4. */ - ret = regmap_update_bits(pcf2127->regmap, PCF2127_REG_CTRL2, - PCF2127_BIT_CTRL2_TSIE, - PCF2127_BIT_CTRL2_TSIE); - if (ret) { - dev_err(dev, "%s: tamper detection config (ctrl2) failed\n", - __func__); - return ret; + for (int i = 0; i < pcf2127->cfg->ts_count; i++) { + ret = pcf2127_enable_ts(dev, i); + if (ret) + return ret; } - ret = rtc_add_group(pcf2127->rtc, &pcf2127_attr_group); + ret = rtc_add_group(pcf2127->rtc, &pcf2127->cfg->attribute_group); if (ret) { dev_err(dev, "%s: tamper sysfs registering failed\n", __func__); @@ -799,9 +1262,10 @@ static int pcf2127_probe(struct device *dev, struct regmap *regmap, #ifdef CONFIG_OF static const struct of_device_id pcf2127_of_match[] = { - { .compatible = "nxp,pcf2127" }, - { .compatible = "nxp,pcf2129" }, - { .compatible = "nxp,pca2129" }, + { .compatible = "nxp,pcf2127", .data = &pcf21xx_cfg[PCF2127] }, + { .compatible = "nxp,pcf2129", .data = &pcf21xx_cfg[PCF2129] }, + { .compatible = "nxp,pca2129", .data = &pcf21xx_cfg[PCF2129] }, + { .compatible = "nxp,pcf2131", .data = &pcf21xx_cfg[PCF2131] }, {} }; MODULE_DEVICE_TABLE(of, pcf2127_of_match); @@ -886,26 +1350,41 @@ static const struct regmap_bus pcf2127_i2c_regmap = { static struct i2c_driver pcf2127_i2c_driver; static const struct i2c_device_id pcf2127_i2c_id[] = { - { "pcf2127", 1 }, - { "pcf2129", 0 }, - { "pca2129", 0 }, + { "pcf2127", PCF2127 }, + { "pcf2129", PCF2129 }, + { "pca2129", PCF2129 }, + { "pcf2131", PCF2131 }, { } }; MODULE_DEVICE_TABLE(i2c, pcf2127_i2c_id); static int pcf2127_i2c_probe(struct i2c_client *client) { - const struct i2c_device_id *id = i2c_match_id(pcf2127_i2c_id, client); struct regmap *regmap; - static const struct regmap_config config = { + static struct regmap_config config = { .reg_bits = 8, .val_bits = 8, - .max_register = 0x1d, }; + const struct pcf21xx_config *variant; if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) return -ENODEV; + if (client->dev.of_node) { + variant = of_device_get_match_data(&client->dev); + if (!variant) + return -ENODEV; + } else { + enum pcf21xx_type type = + i2c_match_id(pcf2127_i2c_id, client)->driver_data; + + if (type >= PCF21XX_LAST_ID) + return -ENODEV; + variant = &pcf21xx_cfg[type]; + } + + config.max_register = variant->max_register, + regmap = devm_regmap_init(&client->dev, &pcf2127_i2c_regmap, &client->dev, &config); if (IS_ERR(regmap)) { @@ -914,8 +1393,7 @@ static int pcf2127_i2c_probe(struct i2c_client *client) return PTR_ERR(regmap); } - return pcf2127_probe(&client->dev, regmap, client->irq, - pcf2127_i2c_driver.driver.name, id->driver_data); + return pcf2127_probe(&client->dev, regmap, client->irq, variant); } static struct i2c_driver pcf2127_i2c_driver = { @@ -953,17 +1431,32 @@ static void pcf2127_i2c_unregister_driver(void) #if IS_ENABLED(CONFIG_SPI_MASTER) static struct spi_driver pcf2127_spi_driver; +static const struct spi_device_id pcf2127_spi_id[]; static int pcf2127_spi_probe(struct spi_device *spi) { - static const struct regmap_config config = { + static struct regmap_config config = { .reg_bits = 8, .val_bits = 8, .read_flag_mask = 0xa0, .write_flag_mask = 0x20, - .max_register = 0x1d, }; struct regmap *regmap; + const struct pcf21xx_config *variant; + + if (spi->dev.of_node) { + variant = of_device_get_match_data(&spi->dev); + if (!variant) + return -ENODEV; + } else { + enum pcf21xx_type type = spi_get_device_id(spi)->driver_data; + + if (type >= PCF21XX_LAST_ID) + return -ENODEV; + variant = &pcf21xx_cfg[type]; + } + + config.max_register = variant->max_register, regmap = devm_regmap_init_spi(spi, &config); if (IS_ERR(regmap)) { @@ -972,15 +1465,14 @@ static int pcf2127_spi_probe(struct spi_device *spi) return PTR_ERR(regmap); } - return pcf2127_probe(&spi->dev, regmap, spi->irq, - pcf2127_spi_driver.driver.name, - spi_get_device_id(spi)->driver_data); + return pcf2127_probe(&spi->dev, regmap, spi->irq, variant); } static const struct spi_device_id pcf2127_spi_id[] = { - { "pcf2127", 1 }, - { "pcf2129", 0 }, - { "pca2129", 0 }, + { "pcf2127", PCF2127 }, + { "pcf2129", PCF2129 }, + { "pca2129", PCF2129 }, + { "pcf2131", PCF2131 }, { } }; MODULE_DEVICE_TABLE(spi, pcf2127_spi_id); @@ -1045,5 +1537,5 @@ static void __exit pcf2127_exit(void) module_exit(pcf2127_exit) MODULE_AUTHOR("Renaud Cerrato <r.cerrato@til-technologies.fr>"); -MODULE_DESCRIPTION("NXP PCF2127/29 RTC driver"); +MODULE_DESCRIPTION("NXP PCF2127/29/31 RTC driver"); MODULE_LICENSE("GPL v2"); diff --git a/drivers/rtc/rtc-pcf85063.c b/drivers/rtc/rtc-pcf85063.c index e517abfaee2a..fdbc07f14036 100644 --- a/drivers/rtc/rtc-pcf85063.c +++ b/drivers/rtc/rtc-pcf85063.c @@ -14,7 +14,7 @@ #include <linux/bcd.h> #include <linux/rtc.h> #include <linux/module.h> -#include <linux/of_device.h> +#include <linux/of.h> #include <linux/pm_wakeirq.h> #include <linux/regmap.h> @@ -514,49 +514,40 @@ static struct clk *pcf85063_clkout_register_clk(struct pcf85063 *pcf85063) } #endif -enum pcf85063_type { - PCF85063, - PCF85063TP, - PCF85063A, - RV8263, - PCF85063_LAST_ID +static const struct pcf85063_config config_pcf85063 = { + .regmap = { + .reg_bits = 8, + .val_bits = 8, + .max_register = 0x0a, + }, }; -static struct pcf85063_config pcf85063_cfg[] = { - [PCF85063] = { - .regmap = { - .reg_bits = 8, - .val_bits = 8, - .max_register = 0x0a, - }, - }, - [PCF85063TP] = { - .regmap = { - .reg_bits = 8, - .val_bits = 8, - .max_register = 0x0a, - }, - }, - [PCF85063A] = { - .regmap = { - .reg_bits = 8, - .val_bits = 8, - .max_register = 0x11, - }, - .has_alarms = 1, +static const struct pcf85063_config config_pcf85063tp = { + .regmap = { + .reg_bits = 8, + .val_bits = 8, + .max_register = 0x0a, }, - [RV8263] = { - .regmap = { - .reg_bits = 8, - .val_bits = 8, - .max_register = 0x11, - }, - .has_alarms = 1, - .force_cap_7000 = 1, +}; + +static const struct pcf85063_config config_pcf85063a = { + .regmap = { + .reg_bits = 8, + .val_bits = 8, + .max_register = 0x11, }, + .has_alarms = 1, }; -static const struct i2c_device_id pcf85063_ids[]; +static const struct pcf85063_config config_rv8263 = { + .regmap = { + .reg_bits = 8, + .val_bits = 8, + .max_register = 0x11, + }, + .has_alarms = 1, + .force_cap_7000 = 1, +}; static int pcf85063_probe(struct i2c_client *client) { @@ -579,17 +570,9 @@ static int pcf85063_probe(struct i2c_client *client) if (!pcf85063) return -ENOMEM; - if (client->dev.of_node) { - config = of_device_get_match_data(&client->dev); - if (!config) - return -ENODEV; - } else { - enum pcf85063_type type = - i2c_match_id(pcf85063_ids, client)->driver_data; - if (type >= PCF85063_LAST_ID) - return -ENODEV; - config = &pcf85063_cfg[type]; - } + config = i2c_get_match_data(client); + if (!config) + return -ENODEV; pcf85063->regmap = devm_regmap_init_i2c(client, &config->regmap); if (IS_ERR(pcf85063->regmap)) @@ -655,22 +638,22 @@ static int pcf85063_probe(struct i2c_client *client) } static const struct i2c_device_id pcf85063_ids[] = { - { "pca85073a", PCF85063A }, - { "pcf85063", PCF85063 }, - { "pcf85063tp", PCF85063TP }, - { "pcf85063a", PCF85063A }, - { "rv8263", RV8263 }, + { "pca85073a", .driver_data = (kernel_ulong_t)&config_pcf85063a }, + { "pcf85063", .driver_data = (kernel_ulong_t)&config_pcf85063 }, + { "pcf85063tp", .driver_data = (kernel_ulong_t)&config_pcf85063tp }, + { "pcf85063a", .driver_data = (kernel_ulong_t)&config_pcf85063a }, + { "rv8263", .driver_data = (kernel_ulong_t)&config_rv8263 }, {} }; MODULE_DEVICE_TABLE(i2c, pcf85063_ids); #ifdef CONFIG_OF static const struct of_device_id pcf85063_of_match[] = { - { .compatible = "nxp,pca85073a", .data = &pcf85063_cfg[PCF85063A] }, - { .compatible = "nxp,pcf85063", .data = &pcf85063_cfg[PCF85063] }, - { .compatible = "nxp,pcf85063tp", .data = &pcf85063_cfg[PCF85063TP] }, - { .compatible = "nxp,pcf85063a", .data = &pcf85063_cfg[PCF85063A] }, - { .compatible = "microcrystal,rv8263", .data = &pcf85063_cfg[RV8263] }, + { .compatible = "nxp,pca85073a", .data = &config_pcf85063a }, + { .compatible = "nxp,pcf85063", .data = &config_pcf85063 }, + { .compatible = "nxp,pcf85063tp", .data = &config_pcf85063tp }, + { .compatible = "nxp,pcf85063a", .data = &config_pcf85063a }, + { .compatible = "microcrystal,rv8263", .data = &config_rv8263 }, {} }; MODULE_DEVICE_TABLE(of, pcf85063_of_match); diff --git a/drivers/rtc/rtc-pcf85363.c b/drivers/rtc/rtc-pcf85363.c index 65b8b1338dbb..06194674d71c 100644 --- a/drivers/rtc/rtc-pcf85363.c +++ b/drivers/rtc/rtc-pcf85363.c @@ -15,7 +15,6 @@ #include <linux/errno.h> #include <linux/bcd.h> #include <linux/of.h> -#include <linux/of_device.h> #include <linux/regmap.h> /* @@ -403,6 +402,7 @@ static int pcf85363_probe(struct i2c_client *client) }, }; int ret, i, err; + bool wakeup_source; if (data) config = data; @@ -432,25 +432,36 @@ static int pcf85363_probe(struct i2c_client *client) pcf85363->rtc->ops = &rtc_ops; pcf85363->rtc->range_min = RTC_TIMESTAMP_BEGIN_2000; pcf85363->rtc->range_max = RTC_TIMESTAMP_END_2099; - clear_bit(RTC_FEATURE_ALARM, pcf85363->rtc->features); + + wakeup_source = device_property_read_bool(&client->dev, + "wakeup-source"); + if (client->irq > 0 || wakeup_source) { + regmap_write(pcf85363->regmap, CTRL_FLAGS, 0); + regmap_update_bits(pcf85363->regmap, CTRL_PIN_IO, + PIN_IO_INTA_OUT, PIN_IO_INTAPM); + } if (client->irq > 0) { unsigned long irqflags = IRQF_TRIGGER_LOW; if (dev_fwnode(&client->dev)) irqflags = 0; - - regmap_write(pcf85363->regmap, CTRL_FLAGS, 0); - regmap_update_bits(pcf85363->regmap, CTRL_PIN_IO, - PIN_IO_INTA_OUT, PIN_IO_INTAPM); ret = devm_request_threaded_irq(&client->dev, client->irq, NULL, pcf85363_rtc_handle_irq, irqflags | IRQF_ONESHOT, "pcf85363", client); - if (ret) - dev_warn(&client->dev, "unable to request IRQ, alarms disabled\n"); - else - set_bit(RTC_FEATURE_ALARM, pcf85363->rtc->features); + if (ret) { + dev_warn(&client->dev, + "unable to request IRQ, alarms disabled\n"); + client->irq = 0; + } + } + + if (client->irq > 0 || wakeup_source) { + device_init_wakeup(&client->dev, true); + set_bit(RTC_FEATURE_ALARM, pcf85363->rtc->features); + } else { + clear_bit(RTC_FEATURE_ALARM, pcf85363->rtc->features); } ret = devm_rtc_register_device(pcf85363->rtc); diff --git a/drivers/rtc/rtc-pxa.c b/drivers/rtc/rtc-pxa.c index eeacf480cf36..e400c78252e8 100644 --- a/drivers/rtc/rtc-pxa.c +++ b/drivers/rtc/rtc-pxa.c @@ -14,7 +14,6 @@ #include <linux/io.h> #include <linux/slab.h> #include <linux/of.h> -#include <linux/of_device.h> #include "rtc-sa1100.h" diff --git a/drivers/rtc/rtc-rs5c372.c b/drivers/rtc/rtc-rs5c372.c index a5a6c8772ecd..f8fab0205f8c 100644 --- a/drivers/rtc/rtc-rs5c372.c +++ b/drivers/rtc/rtc-rs5c372.c @@ -12,7 +12,7 @@ #include <linux/bcd.h> #include <linux/slab.h> #include <linux/module.h> -#include <linux/of_device.h> +#include <linux/of.h> /* * Ricoh has a family of I2C based RTCs, which differ only slightly from @@ -826,8 +826,7 @@ static int rs5c372_probe(struct i2c_client *client) rs5c372->client = client; i2c_set_clientdata(client, rs5c372); if (client->dev.of_node) { - rs5c372->type = (enum rtc_type) - of_device_get_match_data(&client->dev); + rs5c372->type = (uintptr_t)of_device_get_match_data(&client->dev); } else { const struct i2c_device_id *id = i2c_match_id(rs5c372_id, client); rs5c372->type = id->driver_data; diff --git a/drivers/rtc/rtc-rv3028.c b/drivers/rtc/rtc-rv3028.c index 076e56f4e01a..2f001c59c61d 100644 --- a/drivers/rtc/rtc-rv3028.c +++ b/drivers/rtc/rtc-rv3028.c @@ -17,7 +17,7 @@ #include <linux/kernel.h> #include <linux/log2.h> #include <linux/module.h> -#include <linux/of_device.h> +#include <linux/of.h> #include <linux/regmap.h> #include <linux/rtc.h> @@ -855,11 +855,68 @@ static const struct regmap_config regmap_config = { .max_register = 0x37, }; +static u8 rv3028_set_trickle_charger(struct rv3028_data *rv3028, + struct i2c_client *client) +{ + int ret, val_old, val; + u32 ohms, chargeable; + + ret = regmap_read(rv3028->regmap, RV3028_BACKUP, &val_old); + if (ret < 0) + return ret; + + /* mask out only trickle charger bits */ + val_old = val_old & (RV3028_BACKUP_TCE | RV3028_BACKUP_TCR_MASK); + val = val_old; + + /* setup trickle charger */ + if (!device_property_read_u32(&client->dev, "trickle-resistor-ohms", + &ohms)) { + int i; + + for (i = 0; i < ARRAY_SIZE(rv3028_trickle_resistors); i++) + if (ohms == rv3028_trickle_resistors[i]) + break; + + if (i < ARRAY_SIZE(rv3028_trickle_resistors)) { + /* enable trickle charger and its resistor */ + val = RV3028_BACKUP_TCE | i; + } else { + dev_warn(&client->dev, "invalid trickle resistor value\n"); + } + } + + if (!device_property_read_u32(&client->dev, "aux-voltage-chargeable", + &chargeable)) { + switch (chargeable) { + case 0: + val &= ~RV3028_BACKUP_TCE; + break; + case 1: + val |= RV3028_BACKUP_TCE; + break; + default: + dev_warn(&client->dev, + "unsupported aux-voltage-chargeable value\n"); + break; + } + } + + /* only update EEPROM if changes are necessary */ + if (val_old != val) { + ret = rv3028_update_cfg(rv3028, RV3028_BACKUP, RV3028_BACKUP_TCE | + RV3028_BACKUP_TCR_MASK, val); + if (ret) + return ret; + } + + return ret; +} + static int rv3028_probe(struct i2c_client *client) { struct rv3028_data *rv3028; int ret, status; - u32 ohms; struct nvmem_config nvmem_cfg = { .name = "rv3028_nvram", .word_size = 1, @@ -937,24 +994,9 @@ static int rv3028_probe(struct i2c_client *client) if (ret) return ret; - /* setup trickle charger */ - if (!device_property_read_u32(&client->dev, "trickle-resistor-ohms", - &ohms)) { - int i; - - for (i = 0; i < ARRAY_SIZE(rv3028_trickle_resistors); i++) - if (ohms == rv3028_trickle_resistors[i]) - break; - - if (i < ARRAY_SIZE(rv3028_trickle_resistors)) { - ret = rv3028_update_cfg(rv3028, RV3028_BACKUP, RV3028_BACKUP_TCE | - RV3028_BACKUP_TCR_MASK, RV3028_BACKUP_TCE | i); - if (ret) - return ret; - } else { - dev_warn(&client->dev, "invalid trickle resistor value\n"); - } - } + ret = rv3028_set_trickle_charger(rv3028, client); + if (ret) + return ret; ret = rtc_add_group(rv3028->rtc, &rv3028_attr_group); if (ret) diff --git a/drivers/rtc/rtc-rv3032.c b/drivers/rtc/rtc-rv3032.c index 6b8eb2039a33..35b2e36b426a 100644 --- a/drivers/rtc/rtc-rv3032.c +++ b/drivers/rtc/rtc-rv3032.c @@ -19,7 +19,7 @@ #include <linux/kernel.h> #include <linux/log2.h> #include <linux/module.h> -#include <linux/of_device.h> +#include <linux/of.h> #include <linux/regmap.h> #include <linux/rtc.h> diff --git a/drivers/rtc/rtc-rv8803.c b/drivers/rtc/rtc-rv8803.c index 98679cae13e8..1a3ec1bb5b81 100644 --- a/drivers/rtc/rtc-rv8803.c +++ b/drivers/rtc/rtc-rv8803.c @@ -15,7 +15,7 @@ #include <linux/interrupt.h> #include <linux/kernel.h> #include <linux/module.h> -#include <linux/of_device.h> +#include <linux/of.h> #include <linux/rtc.h> #define RV8803_I2C_TRY_COUNT 4 @@ -645,8 +645,7 @@ static int rv8803_probe(struct i2c_client *client) mutex_init(&rv8803->flags_lock); rv8803->client = client; if (client->dev.of_node) { - rv8803->type = (enum rv8803_type) - of_device_get_match_data(&client->dev); + rv8803->type = (uintptr_t)of_device_get_match_data(&client->dev); } else { const struct i2c_device_id *id = i2c_match_id(rv8803_id, client); diff --git a/drivers/rtc/rtc-rx6110.c b/drivers/rtc/rtc-rx6110.c index 8702db6096ba..834274db8c3f 100644 --- a/drivers/rtc/rtc-rx6110.c +++ b/drivers/rtc/rtc-rx6110.c @@ -13,7 +13,6 @@ #include <linux/regmap.h> #include <linux/rtc.h> #include <linux/of.h> -#include <linux/of_device.h> #include <linux/spi/spi.h> #include <linux/i2c.h> diff --git a/drivers/rtc/rtc-rx8581.c b/drivers/rtc/rtc-rx8581.c index 82881fd2e14a..48efd61a114d 100644 --- a/drivers/rtc/rtc-rx8581.c +++ b/drivers/rtc/rtc-rx8581.c @@ -13,7 +13,6 @@ #include <linux/i2c.h> #include <linux/bcd.h> #include <linux/of.h> -#include <linux/of_device.h> #include <linux/regmap.h> #include <linux/rtc.h> #include <linux/log2.h> diff --git a/drivers/rtc/rtc-rzn1.c b/drivers/rtc/rtc-rzn1.c index dca736caba85..56ebbd4d0481 100644 --- a/drivers/rtc/rtc-rzn1.c +++ b/drivers/rtc/rtc-rzn1.c @@ -15,7 +15,7 @@ #include <linux/init.h> #include <linux/iopoll.h> #include <linux/module.h> -#include <linux/of_device.h> +#include <linux/mod_devicetable.h> #include <linux/platform_device.h> #include <linux/pm_runtime.h> #include <linux/rtc.h> @@ -227,7 +227,7 @@ static int rzn1_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alrm) return ret; /* We cannot set alarms more than one week ahead */ - farest = rtc_tm_to_time64(&tm_now) + (7 * 86400); + farest = rtc_tm_to_time64(&tm_now) + rtc->rtcdev->alarm_offset_max; alarm = rtc_tm_to_time64(tm); if (time_after(alarm, farest)) return -ERANGE; @@ -351,6 +351,7 @@ static int rzn1_rtc_probe(struct platform_device *pdev) rtc->rtcdev->range_min = RTC_TIMESTAMP_BEGIN_2000; rtc->rtcdev->range_max = RTC_TIMESTAMP_END_2099; + rtc->rtcdev->alarm_offset_max = 7 * 86400; rtc->rtcdev->ops = &rzn1_rtc_ops; set_bit(RTC_FEATURE_ALARM_RES_MINUTE, rtc->rtcdev->features); clear_bit(RTC_FEATURE_UPDATE_INTERRUPT, rtc->rtcdev->features); diff --git a/drivers/rtc/rtc-s3c.c b/drivers/rtc/rtc-s3c.c index 70e1a18e5efd..282238818f63 100644 --- a/drivers/rtc/rtc-s3c.c +++ b/drivers/rtc/rtc-s3c.c @@ -23,7 +23,6 @@ #include <linux/log2.h> #include <linux/slab.h> #include <linux/of.h> -#include <linux/of_device.h> #include <linux/uaccess.h> #include <linux/io.h> diff --git a/drivers/rtc/rtc-stm32.c b/drivers/rtc/rtc-stm32.c index 3d36e11cff80..76753c71d92e 100644 --- a/drivers/rtc/rtc-stm32.c +++ b/drivers/rtc/rtc-stm32.c @@ -6,11 +6,13 @@ #include <linux/bcd.h> #include <linux/clk.h> +#include <linux/errno.h> #include <linux/iopoll.h> #include <linux/ioport.h> #include <linux/mfd/syscon.h> #include <linux/module.h> -#include <linux/of_device.h> +#include <linux/of.h> +#include <linux/platform_device.h> #include <linux/pm_wakeirq.h> #include <linux/regmap.h> #include <linux/rtc.h> @@ -89,6 +91,9 @@ /* Max STM32 RTC register offset is 0x3FC */ #define UNDEF_REG 0xFFFF +/* STM32 RTC driver time helpers */ +#define SEC_PER_DAY (24 * 60 * 60) + struct stm32_rtc; struct stm32_rtc_registers { @@ -114,6 +119,7 @@ struct stm32_rtc_data { void (*clear_events)(struct stm32_rtc *rtc, unsigned int flags); bool has_pclk; bool need_dbp; + bool need_accuracy; }; struct stm32_rtc { @@ -158,10 +164,9 @@ static int stm32_rtc_enter_init_mode(struct stm32_rtc *rtc) * slowest rtc_ck frequency may be 32kHz and highest should be * 1MHz, we poll every 10 us with a timeout of 100ms. */ - return readl_relaxed_poll_timeout_atomic( - rtc->base + regs->isr, - isr, (isr & STM32_RTC_ISR_INITF), - 10, 100000); + return readl_relaxed_poll_timeout_atomic(rtc->base + regs->isr, isr, + (isr & STM32_RTC_ISR_INITF), + 10, 100000); } return 0; @@ -425,40 +430,42 @@ static int stm32_rtc_alarm_irq_enable(struct device *dev, unsigned int enabled) return 0; } -static int stm32_rtc_valid_alrm(struct stm32_rtc *rtc, struct rtc_time *tm) +static int stm32_rtc_valid_alrm(struct device *dev, struct rtc_time *tm) { - const struct stm32_rtc_registers *regs = &rtc->data->regs; - int cur_day, cur_mon, cur_year, cur_hour, cur_min, cur_sec; - unsigned int dr = readl_relaxed(rtc->base + regs->dr); - unsigned int tr = readl_relaxed(rtc->base + regs->tr); - - cur_day = (dr & STM32_RTC_DR_DATE) >> STM32_RTC_DR_DATE_SHIFT; - cur_mon = (dr & STM32_RTC_DR_MONTH) >> STM32_RTC_DR_MONTH_SHIFT; - cur_year = (dr & STM32_RTC_DR_YEAR) >> STM32_RTC_DR_YEAR_SHIFT; - cur_sec = (tr & STM32_RTC_TR_SEC) >> STM32_RTC_TR_SEC_SHIFT; - cur_min = (tr & STM32_RTC_TR_MIN) >> STM32_RTC_TR_MIN_SHIFT; - cur_hour = (tr & STM32_RTC_TR_HOUR) >> STM32_RTC_TR_HOUR_SHIFT; + static struct rtc_time now; + time64_t max_alarm_time64; + int max_day_forward; + int next_month; + int next_year; /* * Assuming current date is M-D-Y H:M:S. * RTC alarm can't be set on a specific month and year. * So the valid alarm range is: * M-D-Y H:M:S < alarm <= (M+1)-D-Y H:M:S - * with a specific case for December... */ - if ((((tm->tm_year > cur_year) && - (tm->tm_mon == 0x1) && (cur_mon == 0x12)) || - ((tm->tm_year == cur_year) && - (tm->tm_mon <= cur_mon + 1))) && - ((tm->tm_mday > cur_day) || - ((tm->tm_mday == cur_day) && - ((tm->tm_hour > cur_hour) || - ((tm->tm_hour == cur_hour) && (tm->tm_min > cur_min)) || - ((tm->tm_hour == cur_hour) && (tm->tm_min == cur_min) && - (tm->tm_sec >= cur_sec)))))) - return 0; + stm32_rtc_read_time(dev, &now); + + /* + * Find the next month and the year of the next month. + * Note: tm_mon and next_month are from 0 to 11 + */ + next_month = now.tm_mon + 1; + if (next_month == 12) { + next_month = 0; + next_year = now.tm_year + 1; + } else { + next_year = now.tm_year; + } - return -EINVAL; + /* Find the maximum limit of alarm in days. */ + max_day_forward = rtc_month_days(now.tm_mon, now.tm_year) + - now.tm_mday + + min(rtc_month_days(next_month, next_year), now.tm_mday); + + /* Convert to timestamp and compare the alarm time and its upper limit */ + max_alarm_time64 = rtc_tm_to_time64(&now) + max_day_forward * SEC_PER_DAY; + return rtc_tm_to_time64(tm) <= max_alarm_time64 ? 0 : -EINVAL; } static int stm32_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alrm) @@ -469,17 +476,17 @@ static int stm32_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alrm) unsigned int cr, isr, alrmar; int ret = 0; - tm2bcd(tm); - /* * RTC alarm can't be set on a specific date, unless this date is * up to the same day of month next month. */ - if (stm32_rtc_valid_alrm(rtc, tm) < 0) { + if (stm32_rtc_valid_alrm(dev, tm) < 0) { dev_err(dev, "Alarm can be set only on upcoming month.\n"); return -EINVAL; } + tm2bcd(tm); + alrmar = 0; /* tm_year and tm_mon are not used because not supported by RTC */ alrmar |= (tm->tm_mday << STM32_RTC_ALRMXR_DATE_SHIFT) & @@ -545,6 +552,7 @@ static void stm32_rtc_clear_events(struct stm32_rtc *rtc, static const struct stm32_rtc_data stm32_rtc_data = { .has_pclk = false, .need_dbp = true, + .need_accuracy = false, .regs = { .tr = 0x00, .dr = 0x04, @@ -566,6 +574,7 @@ static const struct stm32_rtc_data stm32_rtc_data = { static const struct stm32_rtc_data stm32h7_rtc_data = { .has_pclk = true, .need_dbp = true, + .need_accuracy = false, .regs = { .tr = 0x00, .dr = 0x04, @@ -596,6 +605,7 @@ static void stm32mp1_rtc_clear_events(struct stm32_rtc *rtc, static const struct stm32_rtc_data stm32mp1_data = { .has_pclk = true, .need_dbp = false, + .need_accuracy = true, .regs = { .tr = 0x00, .dr = 0x04, @@ -628,7 +638,7 @@ static int stm32_rtc_init(struct platform_device *pdev, const struct stm32_rtc_registers *regs = &rtc->data->regs; unsigned int prer, pred_a, pred_s, pred_a_max, pred_s_max, cr; unsigned int rate; - int ret = 0; + int ret; rate = clk_get_rate(rtc->rtc_ck); @@ -636,18 +646,32 @@ static int stm32_rtc_init(struct platform_device *pdev, pred_a_max = STM32_RTC_PRER_PRED_A >> STM32_RTC_PRER_PRED_A_SHIFT; pred_s_max = STM32_RTC_PRER_PRED_S >> STM32_RTC_PRER_PRED_S_SHIFT; - for (pred_a = pred_a_max; pred_a + 1 > 0; pred_a--) { - pred_s = (rate / (pred_a + 1)) - 1; + if (rate > (pred_a_max + 1) * (pred_s_max + 1)) { + dev_err(&pdev->dev, "rtc_ck rate is too high: %dHz\n", rate); + return -EINVAL; + } + + if (rtc->data->need_accuracy) { + for (pred_a = 0; pred_a <= pred_a_max; pred_a++) { + pred_s = (rate / (pred_a + 1)) - 1; + + if (pred_s <= pred_s_max && ((pred_s + 1) * (pred_a + 1)) == rate) + break; + } + } else { + for (pred_a = pred_a_max; pred_a + 1 > 0; pred_a--) { + pred_s = (rate / (pred_a + 1)) - 1; - if (((pred_s + 1) * (pred_a + 1)) == rate) - break; + if (((pred_s + 1) * (pred_a + 1)) == rate) + break; + } } /* * Can't find a 1Hz, so give priority to RTC power consumption * by choosing the higher possible value for prediv_a */ - if ((pred_s > pred_s_max) || (pred_a > pred_a_max)) { + if (pred_s > pred_s_max || pred_a > pred_a_max) { pred_a = pred_a_max; pred_s = (rate / (pred_a + 1)) - 1; @@ -656,6 +680,20 @@ static int stm32_rtc_init(struct platform_device *pdev, "fast" : "slow"); } + cr = readl_relaxed(rtc->base + regs->cr); + + prer = readl_relaxed(rtc->base + regs->prer); + prer &= STM32_RTC_PRER_PRED_S | STM32_RTC_PRER_PRED_A; + + pred_s = (pred_s << STM32_RTC_PRER_PRED_S_SHIFT) & + STM32_RTC_PRER_PRED_S; + pred_a = (pred_a << STM32_RTC_PRER_PRED_A_SHIFT) & + STM32_RTC_PRER_PRED_A; + + /* quit if there is nothing to initialize */ + if ((cr & STM32_RTC_CR_FMT) == 0 && prer == (pred_s | pred_a)) + return 0; + stm32_rtc_wpr_unlock(rtc); ret = stm32_rtc_enter_init_mode(rtc); @@ -665,13 +703,10 @@ static int stm32_rtc_init(struct platform_device *pdev, goto end; } - prer = (pred_s << STM32_RTC_PRER_PRED_S_SHIFT) & STM32_RTC_PRER_PRED_S; - writel_relaxed(prer, rtc->base + regs->prer); - prer |= (pred_a << STM32_RTC_PRER_PRED_A_SHIFT) & STM32_RTC_PRER_PRED_A; - writel_relaxed(prer, rtc->base + regs->prer); + writel_relaxed(pred_s, rtc->base + regs->prer); + writel_relaxed(pred_a | pred_s, rtc->base + regs->prer); /* Force 24h time format */ - cr = readl_relaxed(rtc->base + regs->cr); cr &= ~STM32_RTC_CR_FMT; writel_relaxed(cr, rtc->base + regs->cr); @@ -730,16 +765,13 @@ static int stm32_rtc_probe(struct platform_device *pdev) rtc->rtc_ck = devm_clk_get(&pdev->dev, NULL); } else { rtc->pclk = devm_clk_get(&pdev->dev, "pclk"); - if (IS_ERR(rtc->pclk)) { - dev_err(&pdev->dev, "no pclk clock"); - return PTR_ERR(rtc->pclk); - } + if (IS_ERR(rtc->pclk)) + return dev_err_probe(&pdev->dev, PTR_ERR(rtc->pclk), "no pclk clock"); + rtc->rtc_ck = devm_clk_get(&pdev->dev, "rtc_ck"); } - if (IS_ERR(rtc->rtc_ck)) { - dev_err(&pdev->dev, "no rtc_ck clock"); - return PTR_ERR(rtc->rtc_ck); - } + if (IS_ERR(rtc->rtc_ck)) + return dev_err_probe(&pdev->dev, PTR_ERR(rtc->rtc_ck), "no rtc_ck clock"); if (rtc->data->has_pclk) { ret = clk_prepare_enable(rtc->pclk); @@ -859,7 +891,6 @@ static void stm32_rtc_remove(struct platform_device *pdev) device_init_wakeup(&pdev->dev, false); } -#ifdef CONFIG_PM_SLEEP static int stm32_rtc_suspend(struct device *dev) { struct stm32_rtc *rtc = dev_get_drvdata(dev); @@ -890,10 +921,10 @@ static int stm32_rtc_resume(struct device *dev) return ret; } -#endif -static SIMPLE_DEV_PM_OPS(stm32_rtc_pm_ops, - stm32_rtc_suspend, stm32_rtc_resume); +static const struct dev_pm_ops stm32_rtc_pm_ops = { + NOIRQ_SYSTEM_SLEEP_PM_OPS(stm32_rtc_suspend, stm32_rtc_resume) +}; static struct platform_driver stm32_rtc_driver = { .probe = stm32_rtc_probe, diff --git a/drivers/rtc/rtc-stmp3xxx.c b/drivers/rtc/rtc-stmp3xxx.c index 6f11b745f34d..7566d0a44af8 100644 --- a/drivers/rtc/rtc-stmp3xxx.c +++ b/drivers/rtc/rtc-stmp3xxx.c @@ -18,7 +18,6 @@ #include <linux/delay.h> #include <linux/rtc.h> #include <linux/slab.h> -#include <linux/of_device.h> #include <linux/of.h> #include <linux/stmp_device.h> #include <linux/stmp3xxx_rtc_wdt.h> diff --git a/drivers/rtc/rtc-sun6i.c b/drivers/rtc/rtc-sun6i.c index 71548dd59a3a..8e0c66906103 100644 --- a/drivers/rtc/rtc-sun6i.c +++ b/drivers/rtc/rtc-sun6i.c @@ -24,7 +24,6 @@ #include <linux/module.h> #include <linux/of.h> #include <linux/of_address.h> -#include <linux/of_device.h> #include <linux/platform_device.h> #include <linux/rtc.h> #include <linux/slab.h> @@ -847,8 +846,6 @@ static int sun6i_rtc_probe(struct platform_device *pdev) if (ret) return ret; - dev_info(&pdev->dev, "RTC enabled\n"); - return 0; } diff --git a/drivers/rtc/rtc-sunplus.c b/drivers/rtc/rtc-sunplus.c index f33dc301f301..20c7e97c2fc8 100644 --- a/drivers/rtc/rtc-sunplus.c +++ b/drivers/rtc/rtc-sunplus.c @@ -244,7 +244,7 @@ static int sp_rtc_probe(struct platform_device *plat_dev) sp_rtc->irq = platform_get_irq(plat_dev, 0); if (sp_rtc->irq < 0) - return dev_err_probe(&plat_dev->dev, sp_rtc->irq, "platform_get_irq failed\n"); + return sp_rtc->irq; ret = devm_request_irq(&plat_dev->dev, sp_rtc->irq, sp_rtc_irq_handler, IRQF_TRIGGER_RISING, "rtc irq", plat_dev); diff --git a/drivers/rtc/rtc-sunxi.c b/drivers/rtc/rtc-sunxi.c index 5d019e3a835a..5cab9953c44f 100644 --- a/drivers/rtc/rtc-sunxi.c +++ b/drivers/rtc/rtc-sunxi.c @@ -14,8 +14,6 @@ #include <linux/kernel.h> #include <linux/module.h> #include <linux/of.h> -#include <linux/of_address.h> -#include <linux/of_device.h> #include <linux/platform_device.h> #include <linux/rtc.h> #include <linux/types.h> diff --git a/drivers/rtc/rtc-ti-k3.c b/drivers/rtc/rtc-ti-k3.c index 0d90fe923355..ec759d8f7023 100644 --- a/drivers/rtc/rtc-ti-k3.c +++ b/drivers/rtc/rtc-ti-k3.c @@ -9,7 +9,7 @@ #include <linux/delay.h> #include <linux/mod_devicetable.h> #include <linux/module.h> -#include <linux/of_device.h> +#include <linux/of.h> #include <linux/platform_device.h> #include <linux/sys_soc.h> #include <linux/property.h> diff --git a/drivers/rtc/rtc-tps6586x.c b/drivers/rtc/rtc-tps6586x.c index 9f14e2475747..20faf08c254c 100644 --- a/drivers/rtc/rtc-tps6586x.c +++ b/drivers/rtc/rtc-tps6586x.c @@ -252,6 +252,7 @@ static int tps6586x_rtc_probe(struct platform_device *pdev) rtc->rtc->ops = &tps6586x_rtc_ops; rtc->rtc->range_max = (1ULL << 30) - 1; /* 30-bit seconds */ + rtc->rtc->alarm_offset_max = ALM1_VALID_RANGE_IN_SEC; rtc->rtc->start_secs = mktime64(2009, 1, 1, 0, 0, 0); rtc->rtc->set_start_time = true; diff --git a/drivers/rtc/rtc-tps65910.c b/drivers/rtc/rtc-tps65910.c index 75e4c2d777b9..411ff66c0468 100644 --- a/drivers/rtc/rtc-tps65910.c +++ b/drivers/rtc/rtc-tps65910.c @@ -406,11 +406,8 @@ static int tps65910_rtc_probe(struct platform_device *pdev) platform_set_drvdata(pdev, tps_rtc); irq = platform_get_irq(pdev, 0); - if (irq <= 0) { - dev_warn(&pdev->dev, "Wake up is not possible as irq = %d\n", - irq); - return -ENXIO; - } + if (irq < 0) + return irq; ret = devm_request_threaded_irq(&pdev->dev, irq, NULL, tps65910_rtc_interrupt, IRQF_TRIGGER_LOW, diff --git a/drivers/rtc/rtc-twl.c b/drivers/rtc/rtc-twl.c index 81b36948c2fa..13f8ce08243c 100644 --- a/drivers/rtc/rtc-twl.c +++ b/drivers/rtc/rtc-twl.c @@ -487,11 +487,24 @@ static const struct rtc_class_ops twl_rtc_ops = { .alarm_irq_enable = twl_rtc_alarm_irq_enable, }; +static int twl_nvram_read(void *priv, unsigned int offset, void *val, + size_t bytes) +{ + return twl_i2c_read((long)priv, val, offset, bytes); +} + +static int twl_nvram_write(void *priv, unsigned int offset, void *val, + size_t bytes) +{ + return twl_i2c_write((long)priv, val, offset, bytes); +} + /*----------------------------------------------------------------------*/ static int twl_rtc_probe(struct platform_device *pdev) { struct twl_rtc *twl_rtc; + struct nvmem_config nvmem_cfg; struct device_node *np = pdev->dev.of_node; int ret = -EINVAL; int irq = platform_get_irq(pdev, 0); @@ -542,7 +555,6 @@ static int twl_rtc_probe(struct platform_device *pdev) REG_INT_MSK_STS_A); } - dev_info(&pdev->dev, "Enabling TWL-RTC\n"); ret = twl_rtc_write_u8(twl_rtc, BIT_RTC_CTRL_REG_STOP_RTC_M, REG_RTC_CTRL_REG); if (ret < 0) @@ -564,11 +576,8 @@ static int twl_rtc_probe(struct platform_device *pdev) twl_rtc->rtc = devm_rtc_device_register(&pdev->dev, pdev->name, &twl_rtc_ops, THIS_MODULE); - if (IS_ERR(twl_rtc->rtc)) { - dev_err(&pdev->dev, "can't register RTC device, err %ld\n", - PTR_ERR(twl_rtc->rtc)); + if (IS_ERR(twl_rtc->rtc)) return PTR_ERR(twl_rtc->rtc); - } ret = devm_request_threaded_irq(&pdev->dev, irq, NULL, twl_rtc_interrupt, @@ -579,6 +588,30 @@ static int twl_rtc_probe(struct platform_device *pdev) return ret; } + memset(&nvmem_cfg, 0, sizeof(nvmem_cfg)); + nvmem_cfg.name = "twl-secured-"; + nvmem_cfg.type = NVMEM_TYPE_BATTERY_BACKED; + nvmem_cfg.reg_read = twl_nvram_read, + nvmem_cfg.reg_write = twl_nvram_write, + nvmem_cfg.word_size = 1; + nvmem_cfg.stride = 1; + if (twl_class_is_4030()) { + /* 20 bytes SECURED_REG area */ + nvmem_cfg.size = 20; + nvmem_cfg.priv = (void *)TWL_MODULE_SECURED_REG; + devm_rtc_nvmem_register(twl_rtc->rtc, &nvmem_cfg); + /* 8 bytes BACKUP area */ + nvmem_cfg.name = "twl-backup-"; + nvmem_cfg.size = 8; + nvmem_cfg.priv = (void *)TWL4030_MODULE_BACKUP; + devm_rtc_nvmem_register(twl_rtc->rtc, &nvmem_cfg); + } else { + /* 8 bytes SECURED_REG area */ + nvmem_cfg.size = 8; + nvmem_cfg.priv = (void *)TWL_MODULE_SECURED_REG; + devm_rtc_nvmem_register(twl_rtc->rtc, &nvmem_cfg); + } + return 0; } diff --git a/drivers/rtc/rtc-wm8350.c b/drivers/rtc/rtc-wm8350.c index 947f8071803f..3c773cff2b39 100644 --- a/drivers/rtc/rtc-wm8350.c +++ b/drivers/rtc/rtc-wm8350.c @@ -386,8 +386,6 @@ static int wm8350_rtc_probe(struct platform_device *pdev) /* enable the RTC if it's not already enabled */ power5 = wm8350_reg_read(wm8350, WM8350_POWER_MGMT_5); if (!(power5 & WM8350_RTC_TICK_ENA)) { - dev_info(wm8350->dev, "Starting RTC\n"); - wm8350_reg_unlock(wm8350); ret = wm8350_set_bits(wm8350, WM8350_POWER_MGMT_5, @@ -426,11 +424,8 @@ static int wm8350_rtc_probe(struct platform_device *pdev) wm_rtc->rtc = devm_rtc_device_register(&pdev->dev, "wm8350", &wm8350_rtc_ops, THIS_MODULE); - if (IS_ERR(wm_rtc->rtc)) { - ret = PTR_ERR(wm_rtc->rtc); - dev_err(&pdev->dev, "failed to register RTC: %d\n", ret); - return ret; - } + if (IS_ERR(wm_rtc->rtc)) + return PTR_ERR(wm_rtc->rtc); ret = wm8350_register_irq(wm8350, WM8350_IRQ_RTC_SEC, wm8350_rtc_update_handler, 0, |