Commit ff6e6ded authored by Linus Torvalds's avatar Linus Torvalds

Merge tag 'rtc-6.6' of git://git.kernel.org/pub/scm/linux/kernel/git/abelloni/linux

Pull RTC updates from Alexandre Belloni:
 "Subsystem:

   - Add a way for drivers to tell the core the supported alarm range is
     smaller than the date range. This is not used yet but will be
     useful for the alarmtimers in the next release.

   - fix Wvoid-pointer-to-enum-cast warnings

   - remove redundant of_match_ptr()

   - stop warning for invalid alarms when the alarm is disabled

  Drivers:

   - isl12022: allow setting the trip level for battery level detection

   - pcf2127: add support for PCF2131 and multiple timestamps

   - stm32: time precision improvement, many fixes

   - twl: NVRAM support"

* tag 'rtc-6.6' of git://git.kernel.org/pub/scm/linux/kernel/git/abelloni/linux: (73 commits)
  dt-bindings: rtc: ds3231: Remove text binding
  rtc: wm8350: remove unnecessary messages
  rtc: twl: remove unnecessary messages
  rtc: sun6i: remove unnecessary message
  rtc: stop warning for invalid alarms when the alarm is disabled
  rtc: twl: add NVRAM support
  rtc: pcf85363: Allow to wake up system without IRQ
  rtc: m48t86: add DT support for m48t86
  dt-bindings: rtc: Add ST M48T86
  rtc: pcf2127: remove useless check
  rtc: rzn1: Report maximum alarm limit to rtc core
  rtc: ds1305: Report maximum alarm limit to rtc core
  rtc: tps6586x: Report maximum alarm limit to rtc core
  rtc: cmos: Report supported alarm limit to rtc infrastructure
  rtc: cros-ec: Detect and report supported alarm window size
  rtc: Add support for limited alarm timer offsets
  rtc: isl1208: Fix incorrect logic in isl1208_set_xtoscb()
  MAINTAINERS: remove obsolete pattern in RTC SUBSYSTEM section
  rtc: tps65910: Remove redundant dev_warn() and do not check for 0 return after calling platform_get_irq()
  rtc: omap: Do not check for 0 return after calling platform_get_irq()
  ...
parents e59a698b ce413486
...@@ -14,13 +14,17 @@ maintainers: ...@@ -14,13 +14,17 @@ maintainers:
properties: properties:
compatible: compatible:
enum: oneOf:
- atmel,at91rm9200-rtc - enum:
- atmel,at91sam9x5-rtc - atmel,at91rm9200-rtc
- atmel,sama5d4-rtc - atmel,at91sam9x5-rtc
- atmel,sama5d2-rtc - atmel,sama5d4-rtc
- microchip,sam9x60-rtc - atmel,sama5d2-rtc
- microchip,sama7g5-rtc - microchip,sam9x60-rtc
- microchip,sama7g5-rtc
- items:
- const: microchip,sam9x7-rtc
- const: microchip,sam9x60-rtc
reg: reg:
maxItems: 1 maxItems: 1
......
# SPDX-License-Identifier: GPL-2.0-only OR BSD-2-Clause
%YAML 1.2
---
$id: http://devicetree.org/schemas/rtc/intersil,isl12022.yaml#
$schema: http://devicetree.org/meta-schemas/core.yaml#
title: Intersil ISL12022 Real-time Clock
maintainers:
- Alexandre Belloni <alexandre.belloni@bootlin.com>
properties:
compatible:
const: isil,isl12022
reg:
maxItems: 1
interrupts:
maxItems: 1
'#clock-cells':
const: 0
isil,battery-trip-levels-microvolt:
description:
The battery voltages at which the first alarm and second alarm
should trigger (normally ~85% and ~75% of nominal V_BAT).
items:
- enum: [2125000, 2295000, 2550000, 2805000, 3060000, 4250000, 4675000]
- enum: [1875000, 2025000, 2250000, 2475000, 2700000, 3750000, 4125000]
required:
- compatible
- reg
allOf:
- $ref: rtc.yaml#
# If #clock-cells is present, interrupts must not be present
- if:
required:
- '#clock-cells'
then:
properties:
interrupts: false
unevaluatedProperties: false
examples:
- |
#include <dt-bindings/interrupt-controller/irq.h>
i2c {
#address-cells = <1>;
#size-cells = <0>;
rtc@6f {
compatible = "isil,isl12022";
reg = <0x6f>;
interrupts-extended = <&gpio1 5 IRQ_TYPE_LEVEL_LOW>;
isil,battery-trip-levels-microvolt = <2550000>, <2250000>;
};
};
...
* Maxim DS3231 Real Time Clock
Required properties:
- compatible: Should contain "maxim,ds3231".
- reg: I2C address for chip.
Optional property:
- #clock-cells: Should be 1.
- clock-output-names:
overwrite the default clock names "ds3231_clk_sqw" and "ds3231_clk_32khz".
Each clock is assigned an identifier and client nodes can use this identifier
to specify the clock which they consume. Following indices are allowed:
- 0: square-wave output on the SQW pin
- 1: square-wave output on the 32kHz pin
- interrupts: rtc alarm/event interrupt. When this property is selected,
clock on the SQW pin cannot be used.
Example:
ds3231: ds3231@51 {
compatible = "maxim,ds3231";
reg = <0x68>;
#clock-cells = <1>;
};
device1 {
...
clocks = <&ds3231 0>;
...
};
device2 {
...
clocks = <&ds3231 1>;
...
};
...@@ -18,6 +18,7 @@ properties: ...@@ -18,6 +18,7 @@ properties:
- nxp,pca2129 - nxp,pca2129
- nxp,pcf2127 - nxp,pcf2127
- nxp,pcf2129 - nxp,pcf2129
- nxp,pcf2131
reg: reg:
maxItems: 1 maxItems: 1
......
# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
%YAML 1.2
---
$id: http://devicetree.org/schemas/rtc/st,m48t86.yaml#
$schema: http://devicetree.org/meta-schemas/core.yaml#
title: ST M48T86 / Dallas DS12887 RTC with SRAM
maintainers:
- Alexandre Belloni <alexandre.belloni@bootlin.com>
allOf:
- $ref: rtc.yaml
properties:
compatible:
enum:
- st,m48t86
reg:
items:
- description: index register
- description: data register
required:
- compatible
- reg
unevaluatedProperties: false
examples:
- |
rtc@10800000 {
compatible = "st,m48t86";
reg = <0x10800000 0x1>, <0x11700000 0x1>;
};
...
...@@ -45,8 +45,6 @@ properties: ...@@ -45,8 +45,6 @@ properties:
- isil,isl1208 - isil,isl1208
# Intersil ISL1218 Low Power RTC with Battery Backed SRAM # Intersil ISL1218 Low Power RTC with Battery Backed SRAM
- isil,isl1218 - isil,isl1218
# Intersil ISL12022 Real-time Clock
- isil,isl12022
# Real Time Clock Module with I2C-Bus # Real Time Clock Module with I2C-Bus
- microcrystal,rv3029 - microcrystal,rv3029
# Real Time Clock # Real Time Clock
......
...@@ -18084,7 +18084,6 @@ T: git git://git.kernel.org/pub/scm/linux/kernel/git/abelloni/linux.git ...@@ -18084,7 +18084,6 @@ T: git git://git.kernel.org/pub/scm/linux/kernel/git/abelloni/linux.git
F: Documentation/admin-guide/rtc.rst F: Documentation/admin-guide/rtc.rst
F: Documentation/devicetree/bindings/rtc/ F: Documentation/devicetree/bindings/rtc/
F: drivers/rtc/ F: drivers/rtc/
F: include/linux/platform_data/rtc-*
F: include/linux/rtc.h F: include/linux/rtc.h
F: include/linux/rtc/ F: include/linux/rtc/
F: include/uapi/linux/rtc.h F: include/uapi/linux/rtc.h
......
...@@ -904,9 +904,9 @@ config RTC_DRV_PCF2127 ...@@ -904,9 +904,9 @@ config RTC_DRV_PCF2127
select REGMAP_SPI if SPI_MASTER select REGMAP_SPI if SPI_MASTER
select WATCHDOG_CORE if WATCHDOG select WATCHDOG_CORE if WATCHDOG
help 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. 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. features.
PCF2127 has an additional feature of 512 bytes battery backed PCF2127 has an additional feature of 512 bytes battery backed
...@@ -1196,6 +1196,7 @@ config RTC_DRV_MSM6242 ...@@ -1196,6 +1196,7 @@ config RTC_DRV_MSM6242
config RTC_DRV_BQ4802 config RTC_DRV_BQ4802
tristate "TI BQ4802" tristate "TI BQ4802"
depends on HAS_IOMEM && HAS_IOPORT depends on HAS_IOMEM && HAS_IOPORT
depends on SPARC || COMPILE_TEST
help help
If you say Y here you will get support for the TI If you say Y here you will get support for the TI
BQ4802 RTC chip. BQ4802 RTC chip.
......
...@@ -376,7 +376,7 @@ int __rtc_read_alarm(struct rtc_device *rtc, struct rtc_wkalrm *alarm) ...@@ -376,7 +376,7 @@ int __rtc_read_alarm(struct rtc_device *rtc, struct rtc_wkalrm *alarm)
err = rtc_valid_tm(&alarm->time); err = rtc_valid_tm(&alarm->time);
done: done:
if (err) if (err && alarm->enabled)
dev_warn(&rtc->dev, "invalid alarm value: %ptR\n", dev_warn(&rtc->dev, "invalid alarm value: %ptR\n",
&alarm->time); &alarm->time);
......
...@@ -15,7 +15,7 @@ ...@@ -15,7 +15,7 @@
#include <linux/i2c.h> #include <linux/i2c.h>
#include <linux/kstrtox.h> #include <linux/kstrtox.h>
#include <linux/module.h> #include <linux/module.h>
#include <linux/of_device.h> #include <linux/of.h>
#include <linux/rtc.h> #include <linux/rtc.h>
#include <linux/watchdog.h> #include <linux/watchdog.h>
......
...@@ -11,7 +11,6 @@ ...@@ -11,7 +11,6 @@
#include <linux/io.h> #include <linux/io.h>
#include <linux/module.h> #include <linux/module.h>
#include <linux/of.h> #include <linux/of.h>
#include <linux/of_device.h>
#include <linux/platform_device.h> #include <linux/platform_device.h>
#include <linux/rtc.h> #include <linux/rtc.h>
...@@ -474,7 +473,6 @@ static const struct armada38x_rtc_data armada8k_data = { ...@@ -474,7 +473,6 @@ static const struct armada38x_rtc_data armada8k_data = {
.alarm = ALARM2, .alarm = ALARM2,
}; };
#ifdef CONFIG_OF
static const struct of_device_id armada38x_rtc_of_match_table[] = { static const struct of_device_id armada38x_rtc_of_match_table[] = {
{ {
.compatible = "marvell,armada-380-rtc", .compatible = "marvell,armada-380-rtc",
...@@ -487,7 +485,6 @@ static const struct of_device_id armada38x_rtc_of_match_table[] = { ...@@ -487,7 +485,6 @@ static const struct of_device_id armada38x_rtc_of_match_table[] = {
{} {}
}; };
MODULE_DEVICE_TABLE(of, 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) static __init int armada38x_rtc_probe(struct platform_device *pdev)
{ {
...@@ -577,7 +574,7 @@ static struct platform_driver armada38x_rtc_driver = { ...@@ -577,7 +574,7 @@ static struct platform_driver armada38x_rtc_driver = {
.driver = { .driver = {
.name = "armada38x-rtc", .name = "armada38x-rtc",
.pm = &armada38x_rtc_pm_ops, .pm = &armada38x_rtc_pm_ops,
.of_match_table = of_match_ptr(armada38x_rtc_of_match_table), .of_match_table = armada38x_rtc_of_match_table,
}, },
}; };
......
...@@ -118,7 +118,7 @@ MODULE_DEVICE_TABLE(of, aspeed_rtc_match); ...@@ -118,7 +118,7 @@ MODULE_DEVICE_TABLE(of, aspeed_rtc_match);
static struct platform_driver aspeed_rtc_driver = { static struct platform_driver aspeed_rtc_driver = {
.driver = { .driver = {
.name = "aspeed-rtc", .name = "aspeed-rtc",
.of_match_table = of_match_ptr(aspeed_rtc_match), .of_match_table = aspeed_rtc_match,
}, },
}; };
......
...@@ -22,7 +22,6 @@ ...@@ -22,7 +22,6 @@
#include <linux/io.h> #include <linux/io.h>
#include <linux/kernel.h> #include <linux/kernel.h>
#include <linux/module.h> #include <linux/module.h>
#include <linux/of_device.h>
#include <linux/of.h> #include <linux/of.h>
#include <linux/platform_device.h> #include <linux/platform_device.h>
#include <linux/rtc.h> #include <linux/rtc.h>
...@@ -642,7 +641,7 @@ static struct platform_driver at91_rtc_driver = { ...@@ -642,7 +641,7 @@ static struct platform_driver at91_rtc_driver = {
.driver = { .driver = {
.name = "at91_rtc", .name = "at91_rtc",
.pm = &at91_rtc_pm_ops, .pm = &at91_rtc_pm_ops,
.of_match_table = of_match_ptr(at91_rtc_dt_ids), .of_match_table = at91_rtc_dt_ids,
}, },
}; };
......
...@@ -534,7 +534,7 @@ static struct platform_driver at91_rtc_driver = { ...@@ -534,7 +534,7 @@ static struct platform_driver at91_rtc_driver = {
.driver = { .driver = {
.name = "rtc-at91sam9", .name = "rtc-at91sam9",
.pm = &at91_rtc_pm_ops, .pm = &at91_rtc_pm_ops,
.of_match_table = of_match_ptr(at91_rtc_dt_ids), .of_match_table = at91_rtc_dt_ids,
}, },
}; };
......
...@@ -913,6 +913,10 @@ static inline void cmos_check_acpi_rtc_status(struct device *dev, ...@@ -913,6 +913,10 @@ static inline void cmos_check_acpi_rtc_status(struct device *dev,
#define INITSECTION __init #define INITSECTION __init
#endif #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 static int INITSECTION
cmos_do_probe(struct device *dev, struct resource *ports, int rtc_irq) 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) ...@@ -1019,6 +1023,13 @@ cmos_do_probe(struct device *dev, struct resource *ports, int rtc_irq)
goto cleanup0; 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)); rename_region(ports, dev_name(&cmos_rtc.rtc->dev));
if (!mc146818_does_rtc_work()) { if (!mc146818_does_rtc_work()) {
......
...@@ -182,21 +182,15 @@ static int cros_ec_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alrm) ...@@ -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); ret = cros_ec_rtc_set(cros_ec, EC_CMD_RTC_SET_ALARM, alarm_offset);
if (ret < 0) { if (ret < 0) {
if (ret == -EINVAL && alarm_offset >= SECS_PER_DAY) { dev_err(dev, "error setting alarm in %u seconds: %d\n",
/* alarm_offset, ret);
* RTC chips on some older Chromebooks can only handle /*
* alarms up to 24h in the future. Try to set an alarm * The EC code returns -EINVAL if the alarm time is too
* below that limit to avoid suspend failures. * far in the future. Convert it to the expected error code.
*/ */
ret = cros_ec_rtc_set(cros_ec, EC_CMD_RTC_SET_ALARM, if (ret == -EINVAL)
SECS_PER_DAY - 1); ret = -ERANGE;
} return ret;
if (ret < 0) {
dev_err(dev, "error setting alarm in %u seconds: %d\n",
alarm_offset, ret);
return ret;
}
} }
return 0; return 0;
...@@ -355,6 +349,20 @@ static int cros_ec_rtc_probe(struct platform_device *pdev) ...@@ -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->ops = &cros_ec_rtc_ops;
cros_ec_rtc->rtc->range_max = U32_MAX; 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); ret = devm_rtc_register_device(cros_ec_rtc->rtc);
if (ret) if (ret)
return ret; return ret;
......
...@@ -11,6 +11,7 @@ ...@@ -11,6 +11,7 @@
#include <linux/module.h> #include <linux/module.h>
#include <linux/of.h> #include <linux/of.h>
#include <linux/platform_device.h> #include <linux/platform_device.h>
#include <linux/pm_wakeirq.h>
#include <linux/regmap.h> #include <linux/regmap.h>
#include <linux/rtc.h> #include <linux/rtc.h>
#include <linux/slab.h> #include <linux/slab.h>
...@@ -496,6 +497,12 @@ static int da9063_rtc_probe(struct platform_device *pdev) ...@@ -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", dev_err(&pdev->dev, "Failed to request ALARM IRQ %d: %d\n",
irq_alarm, ret); 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); device_init_wakeup(&pdev->dev, true);
return devm_rtc_register_device(rtc->rtc_dev); return devm_rtc_register_device(rtc->rtc_dev);
......
...@@ -336,8 +336,8 @@ static int ds1305_set_alarm(struct device *dev, struct rtc_wkalrm *alm) ...@@ -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 */ /* make sure alarm fires within the next 24 hours */
if (later <= now) if (later <= now)
return -EINVAL; return -EINVAL;
if ((later - now) > 24 * 60 * 60) if ((later - now) > ds1305->rtc->alarm_offset_max)
return -EDOM; return -ERANGE;
/* disable alarm if needed */ /* disable alarm if needed */
if (ds1305->ctrl[0] & DS1305_AEI0) { if (ds1305->ctrl[0] & DS1305_AEI0) {
...@@ -691,6 +691,7 @@ static int ds1305_probe(struct spi_device *spi) ...@@ -691,6 +691,7 @@ static int ds1305_probe(struct spi_device *spi)
ds1305->rtc->ops = &ds1305_ops; ds1305->rtc->ops = &ds1305_ops;
ds1305->rtc->range_min = RTC_TIMESTAMP_BEGIN_2000; ds1305->rtc->range_min = RTC_TIMESTAMP_BEGIN_2000;
ds1305->rtc->range_max = RTC_TIMESTAMP_END_2099; ds1305->rtc->range_max = RTC_TIMESTAMP_END_2099;
ds1305->rtc->alarm_offset_max = 24 * 60 * 60;
ds1305_nvmem_cfg.priv = ds1305; ds1305_nvmem_cfg.priv = ds1305;
status = devm_rtc_register_device(ds1305->rtc); status = devm_rtc_register_device(ds1305->rtc);
......
...@@ -1744,7 +1744,7 @@ static int ds1307_probe(struct i2c_client *client) ...@@ -1744,7 +1744,7 @@ static int ds1307_probe(struct i2c_client *client)
match = device_get_match_data(&client->dev); match = device_get_match_data(&client->dev);
if (match) { if (match) {
ds1307->type = (enum ds_type)match; ds1307->type = (uintptr_t)match;
chip = &chips[ds1307->type]; chip = &chips[ds1307->type];
} else if (id) { } else if (id) {
chip = &chips[id->driver_data]; chip = &chips[id->driver_data];
......
...@@ -16,7 +16,6 @@ ...@@ -16,7 +16,6 @@
#include <linux/jiffies.h> #include <linux/jiffies.h>
#include <linux/rtc.h> #include <linux/rtc.h>
#include <linux/of.h> #include <linux/of.h>
#include <linux/of_device.h>
#include <linux/platform_device.h> #include <linux/platform_device.h>
#include <linux/io.h> #include <linux/io.h>
#include <linux/module.h> #include <linux/module.h>
......
...@@ -7,9 +7,8 @@ ...@@ -7,9 +7,8 @@
#include <linux/rtc.h> #include <linux/rtc.h>
#include <linux/types.h> #include <linux/types.h>
#include <linux/bcd.h> #include <linux/bcd.h>
#include <linux/platform_data/rtc-ds2404.h>
#include <linux/delay.h> #include <linux/delay.h>
#include <linux/gpio.h> #include <linux/gpio/consumer.h>
#include <linux/slab.h> #include <linux/slab.h>
#include <linux/io.h> #include <linux/io.h>
...@@ -27,164 +26,140 @@ ...@@ -27,164 +26,140 @@
#define DS2404_CLK 1 #define DS2404_CLK 1
#define DS2404_DQ 2 #define DS2404_DQ 2
struct ds2404_gpio {
const char *name;
unsigned int gpio;
};
struct ds2404 { 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; struct rtc_device *rtc;
}; };
static struct ds2404_gpio ds2404_gpio[] = { static int ds2404_gpio_map(struct ds2404 *chip, struct platform_device *pdev)
{ "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)
{ {
int i, err; struct device *dev = &pdev->dev;
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);
}
chip->gpio = ds2404_gpio; /* This will de-assert RESET, declare this GPIO as GPIOD_ACTIVE_LOW */
return 0; 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: chip->clk_gpiod = devm_gpiod_get(dev, "clk", GPIOD_OUT_HIGH);
while (--i >= 0) if (IS_ERR(chip->clk_gpiod))
gpio_free(ds2404_gpio[i].gpio); return PTR_ERR(chip->clk_gpiod);
return err;
}
static void ds2404_gpio_unmap(void *data) chip->dq_gpiod = devm_gpiod_get(dev, "dq", GPIOD_ASIS);
{ if (IS_ERR(chip->dq_gpiod))
int i; return PTR_ERR(chip->dq_gpiod);
for (i = 0; i < ARRAY_SIZE(ds2404_gpio); i++) return 0;
gpio_free(ds2404_gpio[i].gpio);
} }
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); udelay(1000);
gpio_set_value(ds2404_gpio[DS2404_RST].gpio, 1); gpiod_set_value(chip->rst_gpiod, 0);
gpio_set_value(ds2404_gpio[DS2404_CLK].gpio, 0); gpiod_set_value(chip->clk_gpiod, 0);
gpio_direction_output(ds2404_gpio[DS2404_DQ].gpio, 0); gpiod_direction_output(chip->dq_gpiod, 0);
udelay(10); udelay(10);
} }
static void ds2404_write_byte(struct device *dev, u8 byte) static void ds2404_write_byte(struct ds2404 *chip, u8 byte)
{ {
int i; int i;
gpio_direction_output(ds2404_gpio[DS2404_DQ].gpio, 1); gpiod_direction_output(chip->dq_gpiod, 1);
for (i = 0; i < 8; i++) { 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); udelay(10);
gpio_set_value(ds2404_gpio[DS2404_CLK].gpio, 1); gpiod_set_value(chip->clk_gpiod, 1);
udelay(10); udelay(10);
gpio_set_value(ds2404_gpio[DS2404_CLK].gpio, 0); gpiod_set_value(chip->clk_gpiod, 0);
udelay(10); udelay(10);
} }
} }
static u8 ds2404_read_byte(struct device *dev) static u8 ds2404_read_byte(struct ds2404 *chip)
{ {
int i; int i;
u8 ret = 0; u8 ret = 0;
gpio_direction_input(ds2404_gpio[DS2404_DQ].gpio); gpiod_direction_input(chip->dq_gpiod);
for (i = 0; i < 8; i++) { for (i = 0; i < 8; i++) {
gpio_set_value(ds2404_gpio[DS2404_CLK].gpio, 0); gpiod_set_value(chip->clk_gpiod, 0);
udelay(10); udelay(10);
if (gpio_get_value(ds2404_gpio[DS2404_DQ].gpio)) if (gpiod_get_value(chip->dq_gpiod))
ret |= 1 << i; ret |= 1 << i;
gpio_set_value(ds2404_gpio[DS2404_CLK].gpio, 1); gpiod_set_value(chip->clk_gpiod, 1);
udelay(10); udelay(10);
} }
return ret; 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) int length, u8 *out)
{ {
ds2404_reset(dev); ds2404_reset(chip);
ds2404_write_byte(dev, DS2404_READ_MEMORY_CMD); ds2404_write_byte(chip, DS2404_READ_MEMORY_CMD);
ds2404_write_byte(dev, offset & 0xff); ds2404_write_byte(chip, offset & 0xff);
ds2404_write_byte(dev, (offset >> 8) & 0xff); ds2404_write_byte(chip, (offset >> 8) & 0xff);
while (length--) 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 length, u8 *out)
{ {
int i; int i;
u8 ta01, ta02, es; u8 ta01, ta02, es;
ds2404_reset(dev); ds2404_reset(chip);
ds2404_write_byte(dev, DS2404_WRITE_SCRATCHPAD_CMD); ds2404_write_byte(chip, DS2404_WRITE_SCRATCHPAD_CMD);
ds2404_write_byte(dev, offset & 0xff); ds2404_write_byte(chip, offset & 0xff);
ds2404_write_byte(dev, (offset >> 8) & 0xff); ds2404_write_byte(chip, (offset >> 8) & 0xff);
for (i = 0; i < length; i++) for (i = 0; i < length; i++)
ds2404_write_byte(dev, out[i]); ds2404_write_byte(chip, out[i]);
ds2404_reset(dev); ds2404_reset(chip);
ds2404_write_byte(dev, DS2404_READ_SCRATCHPAD_CMD); ds2404_write_byte(chip, DS2404_READ_SCRATCHPAD_CMD);
ta01 = ds2404_read_byte(dev); ta01 = ds2404_read_byte(chip);
ta02 = ds2404_read_byte(dev); ta02 = ds2404_read_byte(chip);
es = ds2404_read_byte(dev); es = ds2404_read_byte(chip);
for (i = 0; i < length; i++) { for (i = 0; i < length; i++) {
if (out[i] != ds2404_read_byte(dev)) { if (out[i] != ds2404_read_byte(chip)) {
dev_err(dev, "read invalid data\n"); dev_err(chip->dev, "read invalid data\n");
return; return;
} }
} }
ds2404_reset(dev); ds2404_reset(chip);
ds2404_write_byte(dev, DS2404_COPY_SCRATCHPAD_CMD); ds2404_write_byte(chip, DS2404_COPY_SCRATCHPAD_CMD);
ds2404_write_byte(dev, ta01); ds2404_write_byte(chip, ta01);
ds2404_write_byte(dev, ta02); ds2404_write_byte(chip, ta02);
ds2404_write_byte(dev, es); ds2404_write_byte(chip, es);
gpio_direction_input(ds2404_gpio[DS2404_DQ].gpio); while (gpiod_get_value(chip->dq_gpiod))
while (gpio_get_value(ds2404_gpio[DS2404_DQ].gpio))
; ;
} }
static void ds2404_enable_osc(struct device *dev) static void ds2404_enable_osc(struct ds2404 *chip)
{ {
u8 in[1] = { 0x10 }; /* enable oscillator */ 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) static int ds2404_read_time(struct device *dev, struct rtc_time *dt)
{ {
struct ds2404 *chip = dev_get_drvdata(dev);
unsigned long time = 0; unsigned long time = 0;
__le32 hw_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); time = le32_to_cpu(hw_time);
rtc_time64_to_tm(time, dt); rtc_time64_to_tm(time, dt);
...@@ -193,8 +168,9 @@ static int ds2404_read_time(struct device *dev, struct rtc_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) 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)); 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; return 0;
} }
...@@ -205,7 +181,6 @@ static const struct rtc_class_ops ds2404_rtc_ops = { ...@@ -205,7 +181,6 @@ static const struct rtc_class_ops ds2404_rtc_ops = {
static int rtc_probe(struct platform_device *pdev) static int rtc_probe(struct platform_device *pdev)
{ {
struct ds2404_platform_data *pdata = dev_get_platdata(&pdev->dev);
struct ds2404 *chip; struct ds2404 *chip;
int retval = -EBUSY; int retval = -EBUSY;
...@@ -213,22 +188,16 @@ static int rtc_probe(struct platform_device *pdev) ...@@ -213,22 +188,16 @@ static int rtc_probe(struct platform_device *pdev)
if (!chip) if (!chip)
return -ENOMEM; return -ENOMEM;
chip->dev = &pdev->dev;
chip->rtc = devm_rtc_allocate_device(&pdev->dev); chip->rtc = devm_rtc_allocate_device(&pdev->dev);
if (IS_ERR(chip->rtc)) if (IS_ERR(chip->rtc))
return PTR_ERR(chip->rtc); return PTR_ERR(chip->rtc);
retval = ds2404_gpio_map(chip, pdev, pdata); retval = ds2404_gpio_map(chip, pdev);
if (retval) if (retval)
return 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); platform_set_drvdata(pdev, chip);
chip->rtc->ops = &ds2404_rtc_ops; chip->rtc->ops = &ds2404_rtc_ops;
...@@ -238,7 +207,7 @@ static int rtc_probe(struct platform_device *pdev) ...@@ -238,7 +207,7 @@ static int rtc_probe(struct platform_device *pdev)
if (retval) if (retval)
return retval; return retval;
ds2404_enable_osc(&pdev->dev); ds2404_enable_osc(chip);
return 0; return 0;
} }
......
...@@ -11,11 +11,8 @@ ...@@ -11,11 +11,8 @@
#include <linux/err.h> #include <linux/err.h>
#include <linux/interrupt.h> #include <linux/interrupt.h>
#include <linux/io.h> #include <linux/io.h>
#include <linux/of_address.h>
#include <linux/of_irq.h>
#include <linux/platform_device.h> #include <linux/platform_device.h>
#include <linux/of.h> #include <linux/mod_devicetable.h>
#include <linux/of_device.h>
#include <linux/module.h> #include <linux/module.h>
#include <linux/fsl/ftm.h> #include <linux/fsl/ftm.h>
#include <linux/rtc.h> #include <linux/rtc.h>
......
...@@ -9,6 +9,8 @@ ...@@ -9,6 +9,8 @@
*/ */
#include <linux/bcd.h> #include <linux/bcd.h>
#include <linux/bitfield.h>
#include <linux/clk-provider.h>
#include <linux/err.h> #include <linux/err.h>
#include <linux/hwmon.h> #include <linux/hwmon.h>
#include <linux/i2c.h> #include <linux/i2c.h>
...@@ -31,6 +33,8 @@ ...@@ -31,6 +33,8 @@
#define ISL12022_REG_SR 0x07 #define ISL12022_REG_SR 0x07
#define ISL12022_REG_INT 0x08 #define ISL12022_REG_INT 0x08
#define ISL12022_REG_PWR_VBAT 0x0a
#define ISL12022_REG_BETA 0x0d #define ISL12022_REG_BETA 0x0d
#define ISL12022_REG_TEMP_L 0x28 #define ISL12022_REG_TEMP_L 0x28
...@@ -41,6 +45,12 @@ ...@@ -41,6 +45,12 @@
#define ISL12022_SR_LBAT75 (1 << 1) #define ISL12022_SR_LBAT75 (1 << 1)
#define ISL12022_INT_WRTC (1 << 6) #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) #define ISL12022_BETA_TSE (1 << 7)
...@@ -141,12 +151,6 @@ static int isl12022_rtc_read_time(struct device *dev, struct rtc_time *tm) ...@@ -141,12 +151,6 @@ static int isl12022_rtc_read_time(struct device *dev, struct rtc_time *tm)
if (ret) if (ret)
return 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, dev_dbg(dev,
"raw data is sec=%02x, min=%02x, hr=%02x, mday=%02x, mon=%02x, year=%02x, wday=%02x, sr=%02x, int=%02x", "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], buf[ISL12022_REG_SC],
...@@ -204,7 +208,34 @@ static int isl12022_rtc_set_time(struct device *dev, struct rtc_time *tm) ...@@ -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)); 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 = { static const struct rtc_class_ops isl12022_rtc_ops = {
.ioctl = isl12022_rtc_ioctl,
.read_time = isl12022_rtc_read_time, .read_time = isl12022_rtc_read_time,
.set_time = isl12022_rtc_set_time, .set_time = isl12022_rtc_set_time,
}; };
...@@ -215,10 +246,88 @@ static const struct regmap_config regmap_config = { ...@@ -215,10 +246,88 @@ static const struct regmap_config regmap_config = {
.use_single_write = true, .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) static int isl12022_probe(struct i2c_client *client)
{ {
struct rtc_device *rtc; struct rtc_device *rtc;
struct regmap *regmap; struct regmap *regmap;
int ret;
if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C))
return -ENODEV; return -ENODEV;
...@@ -231,6 +340,11 @@ static int isl12022_probe(struct i2c_client *client) ...@@ -231,6 +340,11 @@ static int isl12022_probe(struct i2c_client *client)
dev_set_drvdata(&client->dev, regmap); 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); isl12022_hwmon_register(&client->dev);
rtc = devm_rtc_allocate_device(&client->dev); rtc = devm_rtc_allocate_device(&client->dev);
......
...@@ -11,7 +11,6 @@ ...@@ -11,7 +11,6 @@
#include <linux/mutex.h> #include <linux/mutex.h>
#include <linux/nvmem-provider.h> #include <linux/nvmem-provider.h>
#include <linux/of.h> #include <linux/of.h>
#include <linux/of_device.h>
#include <linux/rtc.h> #include <linux/rtc.h>
#include <linux/slab.h> #include <linux/slab.h>
...@@ -429,7 +428,7 @@ static void isl12026_force_power_modes(struct i2c_client *client) ...@@ -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; struct isl12026 *priv;
int ret; int ret;
...@@ -490,7 +489,7 @@ static struct i2c_driver isl12026_driver = { ...@@ -490,7 +489,7 @@ static struct i2c_driver isl12026_driver = {
.name = "rtc-isl12026", .name = "rtc-isl12026",
.of_match_table = isl12026_dt_match, .of_match_table = isl12026_dt_match,
}, },
.probe = isl12026_probe_new, .probe = isl12026_probe,
.remove = isl12026_remove, .remove = isl12026_remove,
}; };
......
...@@ -9,7 +9,7 @@ ...@@ -9,7 +9,7 @@
#include <linux/clk.h> #include <linux/clk.h>
#include <linux/i2c.h> #include <linux/i2c.h>
#include <linux/module.h> #include <linux/module.h>
#include <linux/of_device.h> #include <linux/of.h>
#include <linux/of_irq.h> #include <linux/of_irq.h>
#include <linux/rtc.h> #include <linux/rtc.h>
...@@ -188,7 +188,7 @@ isl1208_i2c_validate_client(struct i2c_client *client) ...@@ -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) static int isl1208_set_xtoscb(struct i2c_client *client, int sr, int xtosb_val)
{ {
/* Do nothing if bit is already set to desired value */ /* 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; return 0;
if (xtosb_val) if (xtosb_val)
...@@ -862,17 +862,9 @@ isl1208_probe(struct i2c_client *client) ...@@ -862,17 +862,9 @@ isl1208_probe(struct i2c_client *client)
i2c_set_clientdata(client, isl1208); i2c_set_clientdata(client, isl1208);
/* Determine which chip we have */ /* Determine which chip we have */
if (client->dev.of_node) { isl1208->config = i2c_get_match_data(client);
isl1208->config = of_device_get_match_data(&client->dev); if (!isl1208->config)
if (!isl1208->config) return -ENODEV;
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;
}
rc = isl1208_clk_present(client, "xin"); rc = isl1208_clk_present(client, "xin");
if (rc < 0) if (rc < 0)
...@@ -952,7 +944,6 @@ isl1208_probe(struct i2c_client *client) ...@@ -952,7 +944,6 @@ isl1208_probe(struct i2c_client *client)
rc = isl1208_setup_irq(client, client->irq); rc = isl1208_setup_irq(client, client->irq);
if (rc) if (rc)
return rc; return rc;
} else { } else {
clear_bit(RTC_FEATURE_UPDATE_INTERRUPT, isl1208->rtc->features); clear_bit(RTC_FEATURE_UPDATE_INTERRUPT, isl1208->rtc->features);
} }
......
...@@ -11,7 +11,7 @@ ...@@ -11,7 +11,7 @@
#include <linux/iopoll.h> #include <linux/iopoll.h>
#include <linux/kernel.h> #include <linux/kernel.h>
#include <linux/module.h> #include <linux/module.h>
#include <linux/of_device.h> #include <linux/of.h>
#include <linux/platform_device.h> #include <linux/platform_device.h>
#include <linux/pm_wakeirq.h> #include <linux/pm_wakeirq.h>
#include <linux/property.h> #include <linux/property.h>
...@@ -349,7 +349,7 @@ static int jz4740_rtc_probe(struct platform_device *pdev) ...@@ -349,7 +349,7 @@ static int jz4740_rtc_probe(struct platform_device *pdev)
if (!rtc) if (!rtc)
return -ENOMEM; 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); irq = platform_get_irq(pdev, 0);
if (irq < 0) if (irq < 0)
......
...@@ -9,9 +9,8 @@ ...@@ -9,9 +9,8 @@
#include <linux/clk.h> #include <linux/clk.h>
#include <linux/io.h> #include <linux/io.h>
#include <linux/kernel.h> #include <linux/kernel.h>
#include <linux/mod_devicetable.h>
#include <linux/module.h> #include <linux/module.h>
#include <linux/of.h>
#include <linux/of_device.h>
#include <linux/platform_device.h> #include <linux/platform_device.h>
#include <linux/rtc.h> #include <linux/rtc.h>
......
...@@ -17,7 +17,7 @@ ...@@ -17,7 +17,7 @@
#include <linux/init.h> #include <linux/init.h>
#include <linux/kernel.h> #include <linux/kernel.h>
#include <linux/module.h> #include <linux/module.h>
#include <linux/of_device.h> #include <linux/of.h>
#include <linux/rtc.h> #include <linux/rtc.h>
#include <linux/slab.h> #include <linux/slab.h>
#include <linux/mutex.h> #include <linux/mutex.h>
......
...@@ -11,6 +11,7 @@ ...@@ -11,6 +11,7 @@
*/ */
#include <linux/module.h> #include <linux/module.h>
#include <linux/mod_devicetable.h>
#include <linux/rtc.h> #include <linux/rtc.h>
#include <linux/platform_device.h> #include <linux/platform_device.h>
#include <linux/bcd.h> #include <linux/bcd.h>
...@@ -269,9 +270,16 @@ static int m48t86_rtc_probe(struct platform_device *pdev) ...@@ -269,9 +270,16 @@ static int m48t86_rtc_probe(struct platform_device *pdev)
return 0; 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 = { static struct platform_driver m48t86_rtc_platform_driver = {
.driver = { .driver = {
.name = "rtc-m48t86", .name = "rtc-m48t86",
.of_match_table = m48t86_rtc_of_ids,
}, },
.probe = m48t86_rtc_probe, .probe = m48t86_rtc_probe,
}; };
......
...@@ -11,10 +11,8 @@ ...@@ -11,10 +11,8 @@
#include <linux/module.h> #include <linux/module.h>
#include <linux/rtc.h> #include <linux/rtc.h>
#include <linux/of.h> #include <linux/of.h>
#include <linux/of_address.h>
#include <linux/of_device.h>
#include <linux/of_irq.h> #include <linux/of_irq.h>
#include <linux/of_platform.h> #include <linux/platform_device.h>
#include <linux/io.h> #include <linux/io.h>
#include <linux/slab.h> #include <linux/slab.h>
......
...@@ -9,7 +9,7 @@ ...@@ -9,7 +9,7 @@
#include <linux/mfd/mt6397/core.h> #include <linux/mfd/mt6397/core.h>
#include <linux/module.h> #include <linux/module.h>
#include <linux/mutex.h> #include <linux/mutex.h>
#include <linux/of_device.h> #include <linux/of.h>
#include <linux/platform_device.h> #include <linux/platform_device.h>
#include <linux/regmap.h> #include <linux/regmap.h>
#include <linux/rtc.h> #include <linux/rtc.h>
......
...@@ -7,9 +7,9 @@ ...@@ -7,9 +7,9 @@
#include <linux/clk.h> #include <linux/clk.h>
#include <linux/interrupt.h> #include <linux/interrupt.h>
#include <linux/io.h>
#include <linux/mod_devicetable.h>
#include <linux/module.h> #include <linux/module.h>
#include <linux/of_address.h>
#include <linux/of_device.h>
#include <linux/platform_device.h> #include <linux/platform_device.h>
#include <linux/rtc.h> #include <linux/rtc.h>
......
...@@ -11,7 +11,6 @@ ...@@ -11,7 +11,6 @@
#include <linux/pm_wakeirq.h> #include <linux/pm_wakeirq.h>
#include <linux/clk.h> #include <linux/clk.h>
#include <linux/of.h> #include <linux/of.h>
#include <linux/of_device.h>
#define RTC_INPUT_CLK_32768HZ (0x00 << 5) #define RTC_INPUT_CLK_32768HZ (0x00 << 5)
#define RTC_INPUT_CLK_32000HZ (0x01 << 5) #define RTC_INPUT_CLK_32000HZ (0x01 << 5)
......
...@@ -538,7 +538,7 @@ MODULE_DEVICE_TABLE(of, nct3018y_of_match); ...@@ -538,7 +538,7 @@ MODULE_DEVICE_TABLE(of, nct3018y_of_match);
static struct i2c_driver nct3018y_driver = { static struct i2c_driver nct3018y_driver = {
.driver = { .driver = {
.name = "rtc-nct3018y", .name = "rtc-nct3018y",
.of_match_table = of_match_ptr(nct3018y_of_match), .of_match_table = nct3018y_of_match,
}, },
.probe = nct3018y_probe, .probe = nct3018y_probe,
.id_table = nct3018y_id, .id_table = nct3018y_id,
......
...@@ -747,12 +747,12 @@ static int omap_rtc_probe(struct platform_device *pdev) ...@@ -747,12 +747,12 @@ static int omap_rtc_probe(struct platform_device *pdev)
} }
rtc->irq_timer = platform_get_irq(pdev, 0); rtc->irq_timer = platform_get_irq(pdev, 0);
if (rtc->irq_timer <= 0) if (rtc->irq_timer < 0)
return -ENOENT; return rtc->irq_timer;
rtc->irq_alarm = platform_get_irq(pdev, 1); rtc->irq_alarm = platform_get_irq(pdev, 1);
if (rtc->irq_alarm <= 0) if (rtc->irq_alarm < 0)
return -ENOENT; return rtc->irq_alarm;
rtc->clk = devm_clk_get(&pdev->dev, "ext-clk"); rtc->clk = devm_clk_get(&pdev->dev, "ext-clk");
if (!IS_ERR(rtc->clk)) if (!IS_ERR(rtc->clk))
......
// SPDX-License-Identifier: GPL-2.0-only // 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 * Copyright 2013 Til-Technologies
* *
* Author: Renaud Cerrato <r.cerrato@til-technologies.fr> * Author: Renaud Cerrato <r.cerrato@til-technologies.fr>
...@@ -8,9 +8,13 @@ ...@@ -8,9 +8,13 @@
* Watchdog and tamper functions * Watchdog and tamper functions
* Author: Bruno Thomsen <bruno.thomsen@gmail.com> * Author: Bruno Thomsen <bruno.thomsen@gmail.com>
* *
* PCF2131 support
* Author: Hugo Villeneuve <hvilleneuve@dimonoff.com>
*
* based on the other drivers in this same directory. * 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> #include <linux/i2c.h>
...@@ -21,6 +25,7 @@ ...@@ -21,6 +25,7 @@
#include <linux/module.h> #include <linux/module.h>
#include <linux/of.h> #include <linux/of.h>
#include <linux/of_irq.h> #include <linux/of_irq.h>
#include <linux/of_device.h>
#include <linux/regmap.h> #include <linux/regmap.h>
#include <linux/watchdog.h> #include <linux/watchdog.h>
...@@ -28,6 +33,7 @@ ...@@ -28,6 +33,7 @@
#define PCF2127_REG_CTRL1 0x00 #define PCF2127_REG_CTRL1 0x00
#define PCF2127_BIT_CTRL1_POR_OVRD BIT(3) #define PCF2127_BIT_CTRL1_POR_OVRD BIT(3)
#define PCF2127_BIT_CTRL1_TSF1 BIT(4) #define PCF2127_BIT_CTRL1_TSF1 BIT(4)
#define PCF2127_BIT_CTRL1_STOP BIT(5)
/* Control register 2 */ /* Control register 2 */
#define PCF2127_REG_CTRL2 0x01 #define PCF2127_REG_CTRL2 0x01
#define PCF2127_BIT_CTRL2_AIE BIT(1) #define PCF2127_BIT_CTRL2_AIE BIT(1)
...@@ -43,20 +49,10 @@ ...@@ -43,20 +49,10 @@
#define PCF2127_BIT_CTRL3_BF BIT(3) #define PCF2127_BIT_CTRL3_BF BIT(3)
#define PCF2127_BIT_CTRL3_BTSE BIT(4) #define PCF2127_BIT_CTRL3_BTSE BIT(4)
/* Time and date registers */ /* Time and date registers */
#define PCF2127_REG_SC 0x03 #define PCF2127_REG_TIME_BASE 0x03
#define PCF2127_BIT_SC_OSF BIT(7) #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 */ /* Alarm registers */
#define PCF2127_REG_ALARM_SC 0x0A #define PCF2127_REG_ALARM_BASE 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_BIT_ALARM_AE BIT(7) #define PCF2127_BIT_ALARM_AE BIT(7)
/* CLKOUT control register */ /* CLKOUT control register */
#define PCF2127_REG_CLKOUT 0x0f #define PCF2127_REG_CLKOUT 0x0f
...@@ -68,21 +64,15 @@ ...@@ -68,21 +64,15 @@
#define PCF2127_BIT_WD_CTL_CD0 BIT(6) #define PCF2127_BIT_WD_CTL_CD0 BIT(6)
#define PCF2127_BIT_WD_CTL_CD1 BIT(7) #define PCF2127_BIT_WD_CTL_CD1 BIT(7)
#define PCF2127_REG_WD_VAL 0x11 #define PCF2127_REG_WD_VAL 0x11
/* Tamper timestamp registers */ /* Tamper timestamp1 registers */
#define PCF2127_REG_TS_CTRL 0x12 #define PCF2127_REG_TS1_BASE 0x12
#define PCF2127_BIT_TS_CTRL_TSOFF BIT(6) #define PCF2127_BIT_TS_CTRL_TSOFF BIT(6)
#define PCF2127_BIT_TS_CTRL_TSM BIT(7) #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 * RAM registers
* PCF2127 has 512 bytes general-purpose static RAM (SRAM) that is * PCF2127 has 512 bytes general-purpose static RAM (SRAM) that is
* battery backed and can survive a power outage. * 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_ADDR_MSB 0x1A
#define PCF2127_REG_RAM_WRT_CMD 0x1C #define PCF2127_REG_RAM_WRT_CMD 0x1C
...@@ -90,9 +80,14 @@ ...@@ -90,9 +80,14 @@
/* Watchdog timer value constants */ /* Watchdog timer value constants */
#define PCF2127_WD_VAL_STOP 0 #define PCF2127_WD_VAL_STOP 0
#define PCF2127_WD_VAL_MIN 2 /* PCF2127/29 watchdog timer value constants */
#define PCF2127_WD_VAL_MAX 255 #define PCF2127_WD_CLOCK_HZ_X1000 1000 /* 1Hz */
#define PCF2127_WD_VAL_DEFAULT 60 #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 */ /* Mask for currently enabled interrupts */
#define PCF2127_CTRL1_IRQ_MASK (PCF2127_BIT_CTRL1_TSF1) #define PCF2127_CTRL1_IRQ_MASK (PCF2127_BIT_CTRL1_TSF1)
...@@ -101,13 +96,117 @@ ...@@ -101,13 +96,117 @@
PCF2127_BIT_CTRL2_WDTF | \ PCF2127_BIT_CTRL2_WDTF | \
PCF2127_BIT_CTRL2_TSF2) 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 pcf2127 {
struct rtc_device *rtc; struct rtc_device *rtc;
struct watchdog_device wdd; struct watchdog_device wdd;
struct regmap *regmap; struct regmap *regmap;
time64_t ts; const struct pcf21xx_config *cfg;
bool ts_valid;
bool irq_enabled; 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 { ...@@ -117,27 +216,22 @@ struct pcf2127 {
static int pcf2127_rtc_read_time(struct device *dev, struct rtc_time *tm) static int pcf2127_rtc_read_time(struct device *dev, struct rtc_time *tm)
{ {
struct pcf2127 *pcf2127 = dev_get_drvdata(dev); struct pcf2127 *pcf2127 = dev_get_drvdata(dev);
unsigned char buf[10]; unsigned char buf[7];
int ret; int ret;
/* /*
* Avoid reading CTRL2 register as it causes WD_VAL register * Avoid reading CTRL2 register as it causes WD_VAL register
* value to reset to 0 which means watchdog is stopped. * value to reset to 0 which means watchdog is stopped.
*/ */
ret = regmap_bulk_read(pcf2127->regmap, PCF2127_REG_CTRL3, ret = regmap_bulk_read(pcf2127->regmap, pcf2127->cfg->reg_time_base,
(buf + PCF2127_REG_CTRL3), buf, sizeof(buf));
ARRAY_SIZE(buf) - PCF2127_REG_CTRL3);
if (ret) { if (ret) {
dev_err(dev, "%s: read error\n", __func__); dev_err(dev, "%s: read error\n", __func__);
return ret; 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. */ /* 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, * no need clear the flag here,
* it will be cleared once the new date is saved * 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) ...@@ -148,20 +242,17 @@ static int pcf2127_rtc_read_time(struct device *dev, struct rtc_time *tm)
} }
dev_dbg(dev, 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", "mday=%02x, wday=%02x, mon=%02x, year=%02x\n",
__func__, buf[PCF2127_REG_CTRL3], buf[PCF2127_REG_SC], __func__, buf[0], buf[1], buf[2], buf[3], buf[4], buf[5], buf[6]);
buf[PCF2127_REG_MN], buf[PCF2127_REG_HR],
buf[PCF2127_REG_DM], buf[PCF2127_REG_DW], tm->tm_sec = bcd2bin(buf[0] & 0x7F);
buf[PCF2127_REG_MO], buf[PCF2127_REG_YR]); tm->tm_min = bcd2bin(buf[1] & 0x7F);
tm->tm_hour = bcd2bin(buf[2] & 0x3F);
tm->tm_sec = bcd2bin(buf[PCF2127_REG_SC] & 0x7F); tm->tm_mday = bcd2bin(buf[3] & 0x3F);
tm->tm_min = bcd2bin(buf[PCF2127_REG_MN] & 0x7F); tm->tm_wday = buf[4] & 0x07;
tm->tm_hour = bcd2bin(buf[PCF2127_REG_HR] & 0x3F); /* rtc hr 0-23 */ tm->tm_mon = bcd2bin(buf[5] & 0x1F) - 1;
tm->tm_mday = bcd2bin(buf[PCF2127_REG_DM] & 0x3F); tm->tm_year = bcd2bin(buf[6]);
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]);
tm->tm_year += 100; tm->tm_year += 100;
dev_dbg(dev, "%s: tm is secs=%d, mins=%d, hours=%d, " 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) ...@@ -198,14 +289,45 @@ static int pcf2127_rtc_set_time(struct device *dev, struct rtc_time *tm)
/* year */ /* year */
buf[i++] = bin2bcd(tm->tm_year - 100); buf[i++] = bin2bcd(tm->tm_year - 100);
/* write register's data */ /* Write access to time registers:
err = regmap_bulk_write(pcf2127->regmap, PCF2127_REG_SC, buf, i); * 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) { if (err) {
dev_err(dev, dev_dbg(dev, "%s: err=%d", __func__, err);
"%s: err=%d", __func__, err);
return 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; return 0;
} }
...@@ -275,9 +397,16 @@ static int pcf2127_nvmem_write(void *priv, unsigned int offset, ...@@ -275,9 +397,16 @@ static int pcf2127_nvmem_write(void *priv, unsigned int offset,
static int pcf2127_wdt_ping(struct watchdog_device *wdd) static int pcf2127_wdt_ping(struct watchdog_device *wdd)
{ {
int wd_val;
struct pcf2127 *pcf2127 = watchdog_get_drvdata(wdd); 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) ...@@ -311,7 +440,7 @@ static int pcf2127_wdt_stop(struct watchdog_device *wdd)
{ {
struct pcf2127 *pcf2127 = watchdog_get_drvdata(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); PCF2127_WD_VAL_STOP);
} }
...@@ -339,9 +468,25 @@ static const struct watchdog_ops pcf2127_watchdog_ops = { ...@@ -339,9 +468,25 @@ static const struct watchdog_ops pcf2127_watchdog_ops = {
.set_timeout = pcf2127_wdt_set_timeout, .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) static int pcf2127_watchdog_init(struct device *dev, struct pcf2127 *pcf2127)
{ {
u32 wdd_timeout;
int ret; int ret;
if (!IS_ENABLED(CONFIG_WATCHDOG) || if (!IS_ENABLED(CONFIG_WATCHDOG) ||
...@@ -351,21 +496,35 @@ static int pcf2127_watchdog_init(struct device *dev, struct pcf2127 *pcf2127) ...@@ -351,21 +496,35 @@ static int pcf2127_watchdog_init(struct device *dev, struct pcf2127 *pcf2127)
pcf2127->wdd.parent = dev; pcf2127->wdd.parent = dev;
pcf2127->wdd.info = &pcf2127_wdt_info; pcf2127->wdd.info = &pcf2127_wdt_info;
pcf2127->wdd.ops = &pcf2127_watchdog_ops; pcf2127->wdd.ops = &pcf2127_watchdog_ops;
pcf2127->wdd.min_timeout = PCF2127_WD_VAL_MIN;
pcf2127->wdd.max_timeout = PCF2127_WD_VAL_MAX; pcf2127->wdd.min_timeout =
pcf2127->wdd.timeout = PCF2127_WD_VAL_DEFAULT; pcf2127_watchdog_get_period(
pcf2127->wdd.min_hw_heartbeat_ms = 500; 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; pcf2127->wdd.status = WATCHDOG_NOWAYOUT_INIT_STATUS;
watchdog_set_drvdata(&pcf2127->wdd, pcf2127); watchdog_set_drvdata(&pcf2127->wdd, pcf2127);
/* Test if watchdog timer is started by bootloader */ /* Test if watchdog timer is started by bootloader */
ret = regmap_read(pcf2127->regmap, PCF2127_REG_WD_VAL, &wdd_timeout); if (pcf2127->cfg->wd_val_reg_readable) {
if (ret) u32 wdd_timeout;
return ret;
if (wdd_timeout) ret = regmap_read(pcf2127->regmap, pcf2127->cfg->reg_wd_val,
set_bit(WDOG_HW_RUNNING, &pcf2127->wdd.status); &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); 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) ...@@ -386,8 +545,8 @@ static int pcf2127_rtc_read_alarm(struct device *dev, struct rtc_wkalrm *alrm)
if (ret) if (ret)
return ret; return ret;
ret = regmap_bulk_read(pcf2127->regmap, PCF2127_REG_ALARM_SC, buf, ret = regmap_bulk_read(pcf2127->regmap, pcf2127->cfg->regs_alarm_base,
sizeof(buf)); buf, sizeof(buf));
if (ret) if (ret)
return ret; return ret;
...@@ -437,8 +596,8 @@ static int pcf2127_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alrm) ...@@ -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[3] = bin2bcd(alrm->time.tm_mday);
buf[4] = PCF2127_BIT_ALARM_AE; /* Do not match on week day */ buf[4] = PCF2127_BIT_ALARM_AE; /* Do not match on week day */
ret = regmap_bulk_write(pcf2127->regmap, PCF2127_REG_ALARM_SC, buf, ret = regmap_bulk_write(pcf2127->regmap, pcf2127->cfg->regs_alarm_base,
sizeof(buf)); buf, sizeof(buf));
if (ret) if (ret)
return ret; return ret;
...@@ -446,38 +605,35 @@ static int pcf2127_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alrm) ...@@ -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 * This function reads one timestamp function data, caller is responsible for
* pcf2127_wdt_active_ping() * 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 pcf2127 *pcf2127 = dev_get_drvdata(dev);
struct rtc_time tm; struct rtc_time tm;
int ret; int ret;
unsigned char data[25]; unsigned char data[7];
ret = regmap_bulk_read(pcf2127->regmap, PCF2127_REG_CTRL1, data, ret = regmap_bulk_read(pcf2127->regmap, pcf2127->cfg->ts[ts_id].reg_base,
sizeof(data)); data, sizeof(data));
if (ret) { if (ret) {
dev_err(dev, "%s: read error ret=%d\n", __func__, ret); dev_err(dev, "%s: read error ret=%d\n", __func__, ret);
return ret; return ret;
} }
dev_dbg(dev, 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", "%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[PCF2127_REG_CTRL1], data[PCF2127_REG_CTRL2], __func__, data[1], data[2], data[3], data[4], data[5], data[6]);
data[PCF2127_REG_CTRL3], data[PCF2127_REG_TS_SC],
data[PCF2127_REG_TS_MN], data[PCF2127_REG_TS_HR], tm.tm_sec = bcd2bin(data[1] & 0x7F);
data[PCF2127_REG_TS_DM], data[PCF2127_REG_TS_MO], tm.tm_min = bcd2bin(data[2] & 0x7F);
data[PCF2127_REG_TS_YR]); tm.tm_hour = bcd2bin(data[3] & 0x3F);
tm.tm_mday = bcd2bin(data[4] & 0x3F);
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);
/* TS_MO register (month) value range: 1-12 */ /* TS_MO register (month) value range: 1-12 */
tm.tm_mon = bcd2bin(data[PCF2127_REG_TS_MO] & 0x1F) - 1; tm.tm_mon = bcd2bin(data[5] & 0x1F) - 1;
tm.tm_year = bcd2bin(data[PCF2127_REG_TS_YR]); tm.tm_year = bcd2bin(data[6]);
if (tm.tm_year < 70) if (tm.tm_year < 70)
tm.tm_year += 100; /* assume we are in 1970...2069 */ 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) ...@@ -491,47 +647,84 @@ static int pcf2127_rtc_ts_read(struct device *dev, time64_t *ts)
return 0; 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); struct pcf2127 *pcf2127 = dev_get_drvdata(dev);
int ret; int ret;
if (ts_id >= pcf2127->cfg->ts_count)
return;
/* Let userspace read the first timestamp */ /* Let userspace read the first timestamp */
if (pcf2127->ts_valid) if (pcf2127->ts_valid[ts_id])
return; return;
ret = pcf2127_rtc_ts_read(dev, &pcf2127->ts); ret = pcf2127_rtc_ts_read(dev, &pcf2127->ts[ts_id], ts_id);
if (!ret) if (!ret)
pcf2127->ts_valid = true; pcf2127->ts_valid[ts_id] = true;
} }
static irqreturn_t pcf2127_rtc_irq(int irq, void *dev) static irqreturn_t pcf2127_rtc_irq(int irq, void *dev)
{ {
struct pcf2127 *pcf2127 = dev_get_drvdata(dev); struct pcf2127 *pcf2127 = dev_get_drvdata(dev);
unsigned int ctrl1, ctrl2; unsigned int ctrl2;
int ret = 0; 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); ret = regmap_read(pcf2127->regmap, PCF2127_REG_CTRL2, &ctrl2);
if (ret) if (ret)
return IRQ_NONE; return IRQ_NONE;
if (!(ctrl1 & PCF2127_CTRL1_IRQ_MASK || ctrl2 & PCF2127_CTRL2_IRQ_MASK)) if (pcf2127->cfg->ts_count == 1) {
return IRQ_NONE; /* 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) if (ctrl4 & PCF2131_CTRL4_IRQ_MASK) {
pcf2127_rtc_ts_snapshot(dev); int i;
int tsf_bit = PCF2131_BIT_CTRL4_TSF1; /* Start at bit 7. */
if (ctrl1 & PCF2127_CTRL1_IRQ_MASK) for (i = 0; i < pcf2127->cfg->ts_count; i++) {
regmap_write(pcf2127->regmap, PCF2127_REG_CTRL1, if (ctrl4 & tsf_bit)
ctrl1 & ~PCF2127_CTRL1_IRQ_MASK); pcf2127_rtc_ts_snapshot(dev, i);
if (ctrl2 & PCF2127_CTRL2_IRQ_MASK) tsf_bit = tsf_bit >> 1;
regmap_write(pcf2127->regmap, PCF2127_REG_CTRL2, }
ctrl2 & ~PCF2127_CTRL2_IRQ_MASK);
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) if (ctrl2 & PCF2127_BIT_CTRL2_AF)
rtc_update_irq(pcf2127->rtc, 1, RTC_IRQF | RTC_AF); rtc_update_irq(pcf2127->rtc, 1, RTC_IRQF | RTC_AF);
...@@ -552,28 +745,41 @@ static const struct rtc_class_ops pcf2127_rtc_ops = { ...@@ -552,28 +745,41 @@ static const struct rtc_class_ops pcf2127_rtc_ops = {
/* sysfs interface */ /* sysfs interface */
static ssize_t timestamp0_store(struct device *dev, static ssize_t timestamp_store(struct device *dev,
struct device_attribute *attr, struct device_attribute *attr,
const char *buf, size_t count) const char *buf, size_t count, int ts_id)
{ {
struct pcf2127 *pcf2127 = dev_get_drvdata(dev->parent); struct pcf2127 *pcf2127 = dev_get_drvdata(dev->parent);
int ret; int ret;
if (ts_id >= pcf2127->cfg->ts_count)
return 0;
if (pcf2127->irq_enabled) { if (pcf2127->irq_enabled) {
pcf2127->ts_valid = false; pcf2127->ts_valid[ts_id] = false;
} else { } else {
ret = regmap_update_bits(pcf2127->regmap, PCF2127_REG_CTRL1, /* Always clear GND interrupt bit. */
PCF2127_BIT_CTRL1_TSF1, 0); 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) { 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; return ret;
} }
ret = regmap_update_bits(pcf2127->regmap, PCF2127_REG_CTRL2, if (pcf2127->cfg->ts[ts_id].inter_detect_bit) {
PCF2127_BIT_CTRL2_TSF2, 0); /* Clear intermediate level interrupt bit if supported. */
if (ret) { ret = regmap_update_bits(pcf2127->regmap,
dev_err(dev, "%s: update ctrl2 ret=%d\n", __func__, ret); pcf2127->cfg->ts[ts_id].inter_detect_reg,
return ret; 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); ret = pcf2127_wdt_active_ping(&pcf2127->wdd);
...@@ -582,34 +788,84 @@ static ssize_t timestamp0_store(struct device *dev, ...@@ -582,34 +788,84 @@ static ssize_t timestamp0_store(struct device *dev,
} }
return count; 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, static ssize_t timestamp1_store(struct device *dev,
struct device_attribute *attr, char *buf) 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); struct pcf2127 *pcf2127 = dev_get_drvdata(dev->parent);
unsigned int ctrl1, ctrl2;
int ret; int ret;
time64_t ts; time64_t ts;
if (ts_id >= pcf2127->cfg->ts_count)
return 0;
if (pcf2127->irq_enabled) { if (pcf2127->irq_enabled) {
if (!pcf2127->ts_valid) if (!pcf2127->ts_valid[ts_id])
return 0; return 0;
ts = pcf2127->ts; ts = pcf2127->ts[ts_id];
} else { } else {
ret = regmap_read(pcf2127->regmap, PCF2127_REG_CTRL1, &ctrl1); u8 valid_low = 0;
if (ret) u8 valid_inter = 0;
return 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) if (ret)
return 0; return 0;
if (!(ctrl1 & PCF2127_BIT_CTRL1_TSF1) && valid_low = ctrl & pcf2127->cfg->ts[ts_id].gnd_detect_bit;
!(ctrl2 & PCF2127_BIT_CTRL2_TSF2))
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; return 0;
ret = pcf2127_rtc_ts_read(dev->parent, &ts); ret = pcf2127_rtc_ts_read(dev->parent, &ts, ts_id);
if (ret) if (ret)
return 0; return 0;
...@@ -618,21 +874,227 @@ static ssize_t timestamp0_show(struct device *dev, ...@@ -618,21 +874,227 @@ static ssize_t timestamp0_show(struct device *dev,
return ret; return ret;
} }
return sprintf(buf, "%llu\n", (unsigned long long)ts); 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(timestamp0);
static DEVICE_ATTR_RW(timestamp1);
static DEVICE_ATTR_RW(timestamp2);
static DEVICE_ATTR_RW(timestamp3);
static struct attribute *pcf2127_attrs[] = { static struct attribute *pcf2127_attrs[] = {
&dev_attr_timestamp0.attr, &dev_attr_timestamp0.attr,
NULL NULL
}; };
static const struct attribute_group pcf2127_attr_group = { static struct attribute *pcf2131_attrs[] = {
.attrs = pcf2127_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, 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; struct pcf2127 *pcf2127;
int ret = 0; int ret = 0;
...@@ -645,6 +1107,7 @@ static int pcf2127_probe(struct device *dev, struct regmap *regmap, ...@@ -645,6 +1107,7 @@ static int pcf2127_probe(struct device *dev, struct regmap *regmap,
return -ENOMEM; return -ENOMEM;
pcf2127->regmap = regmap; pcf2127->regmap = regmap;
pcf2127->cfg = config;
dev_set_drvdata(dev, pcf2127); dev_set_drvdata(dev, pcf2127);
...@@ -656,8 +1119,16 @@ static int pcf2127_probe(struct device *dev, struct regmap *regmap, ...@@ -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_min = RTC_TIMESTAMP_BEGIN_2000;
pcf2127->rtc->range_max = RTC_TIMESTAMP_END_2099; pcf2127->rtc->range_max = RTC_TIMESTAMP_END_2099;
pcf2127->rtc->set_start_time = true; /* Sets actual start to 1970 */ 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); clear_bit(RTC_FEATURE_ALARM, pcf2127->rtc->features);
if (alarm_irq > 0) { if (alarm_irq > 0) {
...@@ -688,7 +1159,16 @@ static int pcf2127_probe(struct device *dev, struct regmap *regmap, ...@@ -688,7 +1159,16 @@ static int pcf2127_probe(struct device *dev, struct regmap *regmap,
set_bit(RTC_FEATURE_ALARM, pcf2127->rtc->features); 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 = { struct nvmem_config nvmem_cfg = {
.priv = pcf2127, .priv = pcf2127,
.reg_read = pcf2127_nvmem_read, .reg_read = pcf2127_nvmem_read,
...@@ -703,15 +1183,17 @@ static int pcf2127_probe(struct device *dev, struct regmap *regmap, ...@@ -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 * The "Power-On Reset Override" facility prevents the RTC to do a reset
* after power on. For normal operation the PORO must be disabled. * 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); 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) if (ret < 0)
return ret; return ret;
if (!(val & PCF2127_BIT_CLKOUT_OTPR)) { 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); PCF2127_BIT_CLKOUT_OTPR);
if (ret < 0) if (ret < 0)
return ret; return ret;
...@@ -721,20 +1203,20 @@ static int pcf2127_probe(struct device *dev, struct regmap *regmap, ...@@ -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. * 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. * 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 * of register watchdg_tim_ctl. The bit[6] is labeled
* as T. Bits labeled as T must always be written with * as T. Bits labeled as T must always be written with
* logic 0. * 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_CD1 |
PCF2127_BIT_WD_CTL_CD0 | PCF2127_BIT_WD_CTL_CD0 |
PCF2127_BIT_WD_CTL_TF1 | PCF2127_BIT_WD_CTL_TF1 |
PCF2127_BIT_WD_CTL_TF0, PCF2127_BIT_WD_CTL_TF0,
PCF2127_BIT_WD_CTL_CD1 | 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); PCF2127_BIT_WD_CTL_TF1);
if (ret) { if (ret) {
dev_err(dev, "%s: watchdog config (wd_ctl) failed\n", __func__); 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, ...@@ -760,34 +1242,15 @@ static int pcf2127_probe(struct device *dev, struct regmap *regmap,
} }
/* /*
* Enable timestamp function and store timestamp of first trigger * Enable timestamp functions 1 to 4.
* 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.
*/ */
ret = regmap_update_bits(pcf2127->regmap, PCF2127_REG_CTRL2, for (int i = 0; i < pcf2127->cfg->ts_count; i++) {
PCF2127_BIT_CTRL2_TSIE, ret = pcf2127_enable_ts(dev, i);
PCF2127_BIT_CTRL2_TSIE); if (ret)
if (ret) { return ret;
dev_err(dev, "%s: tamper detection config (ctrl2) failed\n",
__func__);
return ret;
} }
ret = rtc_add_group(pcf2127->rtc, &pcf2127_attr_group); ret = rtc_add_group(pcf2127->rtc, &pcf2127->cfg->attribute_group);
if (ret) { if (ret) {
dev_err(dev, "%s: tamper sysfs registering failed\n", dev_err(dev, "%s: tamper sysfs registering failed\n",
__func__); __func__);
...@@ -799,9 +1262,10 @@ static int pcf2127_probe(struct device *dev, struct regmap *regmap, ...@@ -799,9 +1262,10 @@ static int pcf2127_probe(struct device *dev, struct regmap *regmap,
#ifdef CONFIG_OF #ifdef CONFIG_OF
static const struct of_device_id pcf2127_of_match[] = { static const struct of_device_id pcf2127_of_match[] = {
{ .compatible = "nxp,pcf2127" }, { .compatible = "nxp,pcf2127", .data = &pcf21xx_cfg[PCF2127] },
{ .compatible = "nxp,pcf2129" }, { .compatible = "nxp,pcf2129", .data = &pcf21xx_cfg[PCF2129] },
{ .compatible = "nxp,pca2129" }, { .compatible = "nxp,pca2129", .data = &pcf21xx_cfg[PCF2129] },
{ .compatible = "nxp,pcf2131", .data = &pcf21xx_cfg[PCF2131] },
{} {}
}; };
MODULE_DEVICE_TABLE(of, pcf2127_of_match); MODULE_DEVICE_TABLE(of, pcf2127_of_match);
...@@ -886,26 +1350,41 @@ static const struct regmap_bus pcf2127_i2c_regmap = { ...@@ -886,26 +1350,41 @@ static const struct regmap_bus pcf2127_i2c_regmap = {
static struct i2c_driver pcf2127_i2c_driver; static struct i2c_driver pcf2127_i2c_driver;
static const struct i2c_device_id pcf2127_i2c_id[] = { static const struct i2c_device_id pcf2127_i2c_id[] = {
{ "pcf2127", 1 }, { "pcf2127", PCF2127 },
{ "pcf2129", 0 }, { "pcf2129", PCF2129 },
{ "pca2129", 0 }, { "pca2129", PCF2129 },
{ "pcf2131", PCF2131 },
{ } { }
}; };
MODULE_DEVICE_TABLE(i2c, pcf2127_i2c_id); MODULE_DEVICE_TABLE(i2c, pcf2127_i2c_id);
static int pcf2127_i2c_probe(struct i2c_client *client) 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; struct regmap *regmap;
static const struct regmap_config config = { static struct regmap_config config = {
.reg_bits = 8, .reg_bits = 8,
.val_bits = 8, .val_bits = 8,
.max_register = 0x1d,
}; };
const struct pcf21xx_config *variant;
if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C))
return -ENODEV; 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, regmap = devm_regmap_init(&client->dev, &pcf2127_i2c_regmap,
&client->dev, &config); &client->dev, &config);
if (IS_ERR(regmap)) { if (IS_ERR(regmap)) {
...@@ -914,8 +1393,7 @@ static int pcf2127_i2c_probe(struct i2c_client *client) ...@@ -914,8 +1393,7 @@ static int pcf2127_i2c_probe(struct i2c_client *client)
return PTR_ERR(regmap); return PTR_ERR(regmap);
} }
return pcf2127_probe(&client->dev, regmap, client->irq, return pcf2127_probe(&client->dev, regmap, client->irq, variant);
pcf2127_i2c_driver.driver.name, id->driver_data);
} }
static struct i2c_driver pcf2127_i2c_driver = { static struct i2c_driver pcf2127_i2c_driver = {
...@@ -953,17 +1431,32 @@ static void pcf2127_i2c_unregister_driver(void) ...@@ -953,17 +1431,32 @@ static void pcf2127_i2c_unregister_driver(void)
#if IS_ENABLED(CONFIG_SPI_MASTER) #if IS_ENABLED(CONFIG_SPI_MASTER)
static struct spi_driver pcf2127_spi_driver; 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 int pcf2127_spi_probe(struct spi_device *spi)
{ {
static const struct regmap_config config = { static struct regmap_config config = {
.reg_bits = 8, .reg_bits = 8,
.val_bits = 8, .val_bits = 8,
.read_flag_mask = 0xa0, .read_flag_mask = 0xa0,
.write_flag_mask = 0x20, .write_flag_mask = 0x20,
.max_register = 0x1d,
}; };
struct regmap *regmap; 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); regmap = devm_regmap_init_spi(spi, &config);
if (IS_ERR(regmap)) { if (IS_ERR(regmap)) {
...@@ -972,15 +1465,14 @@ static int pcf2127_spi_probe(struct spi_device *spi) ...@@ -972,15 +1465,14 @@ static int pcf2127_spi_probe(struct spi_device *spi)
return PTR_ERR(regmap); return PTR_ERR(regmap);
} }
return pcf2127_probe(&spi->dev, regmap, spi->irq, return pcf2127_probe(&spi->dev, regmap, spi->irq, variant);
pcf2127_spi_driver.driver.name,
spi_get_device_id(spi)->driver_data);
} }
static const struct spi_device_id pcf2127_spi_id[] = { static const struct spi_device_id pcf2127_spi_id[] = {
{ "pcf2127", 1 }, { "pcf2127", PCF2127 },
{ "pcf2129", 0 }, { "pcf2129", PCF2129 },
{ "pca2129", 0 }, { "pca2129", PCF2129 },
{ "pcf2131", PCF2131 },
{ } { }
}; };
MODULE_DEVICE_TABLE(spi, pcf2127_spi_id); MODULE_DEVICE_TABLE(spi, pcf2127_spi_id);
...@@ -1045,5 +1537,5 @@ static void __exit pcf2127_exit(void) ...@@ -1045,5 +1537,5 @@ static void __exit pcf2127_exit(void)
module_exit(pcf2127_exit) module_exit(pcf2127_exit)
MODULE_AUTHOR("Renaud Cerrato <r.cerrato@til-technologies.fr>"); 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"); MODULE_LICENSE("GPL v2");
...@@ -14,7 +14,7 @@ ...@@ -14,7 +14,7 @@
#include <linux/bcd.h> #include <linux/bcd.h>
#include <linux/rtc.h> #include <linux/rtc.h>
#include <linux/module.h> #include <linux/module.h>
#include <linux/of_device.h> #include <linux/of.h>
#include <linux/pm_wakeirq.h> #include <linux/pm_wakeirq.h>
#include <linux/regmap.h> #include <linux/regmap.h>
...@@ -514,49 +514,40 @@ static struct clk *pcf85063_clkout_register_clk(struct pcf85063 *pcf85063) ...@@ -514,49 +514,40 @@ static struct clk *pcf85063_clkout_register_clk(struct pcf85063 *pcf85063)
} }
#endif #endif
enum pcf85063_type { static const struct pcf85063_config config_pcf85063 = {
PCF85063, .regmap = {
PCF85063TP, .reg_bits = 8,
PCF85063A, .val_bits = 8,
RV8263, .max_register = 0x0a,
PCF85063_LAST_ID },
}; };
static struct pcf85063_config pcf85063_cfg[] = { static const struct pcf85063_config config_pcf85063tp = {
[PCF85063] = { .regmap = {
.regmap = { .reg_bits = 8,
.reg_bits = 8, .val_bits = 8,
.val_bits = 8, .max_register = 0x0a,
.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,
}, },
[RV8263] = { };
.regmap = {
.reg_bits = 8, static const struct pcf85063_config config_pcf85063a = {
.val_bits = 8, .regmap = {
.max_register = 0x11, .reg_bits = 8,
}, .val_bits = 8,
.has_alarms = 1, .max_register = 0x11,
.force_cap_7000 = 1,
}, },
.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) static int pcf85063_probe(struct i2c_client *client)
{ {
...@@ -579,17 +570,9 @@ static int pcf85063_probe(struct i2c_client *client) ...@@ -579,17 +570,9 @@ static int pcf85063_probe(struct i2c_client *client)
if (!pcf85063) if (!pcf85063)
return -ENOMEM; return -ENOMEM;
if (client->dev.of_node) { config = i2c_get_match_data(client);
config = of_device_get_match_data(&client->dev); if (!config)
if (!config) return -ENODEV;
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];
}
pcf85063->regmap = devm_regmap_init_i2c(client, &config->regmap); pcf85063->regmap = devm_regmap_init_i2c(client, &config->regmap);
if (IS_ERR(pcf85063->regmap)) if (IS_ERR(pcf85063->regmap))
...@@ -655,22 +638,22 @@ static int pcf85063_probe(struct i2c_client *client) ...@@ -655,22 +638,22 @@ static int pcf85063_probe(struct i2c_client *client)
} }
static const struct i2c_device_id pcf85063_ids[] = { static const struct i2c_device_id pcf85063_ids[] = {
{ "pca85073a", PCF85063A }, { "pca85073a", .driver_data = (kernel_ulong_t)&config_pcf85063a },
{ "pcf85063", PCF85063 }, { "pcf85063", .driver_data = (kernel_ulong_t)&config_pcf85063 },
{ "pcf85063tp", PCF85063TP }, { "pcf85063tp", .driver_data = (kernel_ulong_t)&config_pcf85063tp },
{ "pcf85063a", PCF85063A }, { "pcf85063a", .driver_data = (kernel_ulong_t)&config_pcf85063a },
{ "rv8263", RV8263 }, { "rv8263", .driver_data = (kernel_ulong_t)&config_rv8263 },
{} {}
}; };
MODULE_DEVICE_TABLE(i2c, pcf85063_ids); MODULE_DEVICE_TABLE(i2c, pcf85063_ids);
#ifdef CONFIG_OF #ifdef CONFIG_OF
static const struct of_device_id pcf85063_of_match[] = { static const struct of_device_id pcf85063_of_match[] = {
{ .compatible = "nxp,pca85073a", .data = &pcf85063_cfg[PCF85063A] }, { .compatible = "nxp,pca85073a", .data = &config_pcf85063a },
{ .compatible = "nxp,pcf85063", .data = &pcf85063_cfg[PCF85063] }, { .compatible = "nxp,pcf85063", .data = &config_pcf85063 },
{ .compatible = "nxp,pcf85063tp", .data = &pcf85063_cfg[PCF85063TP] }, { .compatible = "nxp,pcf85063tp", .data = &config_pcf85063tp },
{ .compatible = "nxp,pcf85063a", .data = &pcf85063_cfg[PCF85063A] }, { .compatible = "nxp,pcf85063a", .data = &config_pcf85063a },
{ .compatible = "microcrystal,rv8263", .data = &pcf85063_cfg[RV8263] }, { .compatible = "microcrystal,rv8263", .data = &config_rv8263 },
{} {}
}; };
MODULE_DEVICE_TABLE(of, pcf85063_of_match); MODULE_DEVICE_TABLE(of, pcf85063_of_match);
......
...@@ -15,7 +15,6 @@ ...@@ -15,7 +15,6 @@
#include <linux/errno.h> #include <linux/errno.h>
#include <linux/bcd.h> #include <linux/bcd.h>
#include <linux/of.h> #include <linux/of.h>
#include <linux/of_device.h>
#include <linux/regmap.h> #include <linux/regmap.h>
/* /*
...@@ -403,6 +402,7 @@ static int pcf85363_probe(struct i2c_client *client) ...@@ -403,6 +402,7 @@ static int pcf85363_probe(struct i2c_client *client)
}, },
}; };
int ret, i, err; int ret, i, err;
bool wakeup_source;
if (data) if (data)
config = data; config = data;
...@@ -432,25 +432,36 @@ static int pcf85363_probe(struct i2c_client *client) ...@@ -432,25 +432,36 @@ static int pcf85363_probe(struct i2c_client *client)
pcf85363->rtc->ops = &rtc_ops; pcf85363->rtc->ops = &rtc_ops;
pcf85363->rtc->range_min = RTC_TIMESTAMP_BEGIN_2000; pcf85363->rtc->range_min = RTC_TIMESTAMP_BEGIN_2000;
pcf85363->rtc->range_max = RTC_TIMESTAMP_END_2099; 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) { if (client->irq > 0) {
unsigned long irqflags = IRQF_TRIGGER_LOW; unsigned long irqflags = IRQF_TRIGGER_LOW;
if (dev_fwnode(&client->dev)) if (dev_fwnode(&client->dev))
irqflags = 0; 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, ret = devm_request_threaded_irq(&client->dev, client->irq,
NULL, pcf85363_rtc_handle_irq, NULL, pcf85363_rtc_handle_irq,
irqflags | IRQF_ONESHOT, irqflags | IRQF_ONESHOT,
"pcf85363", client); "pcf85363", client);
if (ret) if (ret) {
dev_warn(&client->dev, "unable to request IRQ, alarms disabled\n"); dev_warn(&client->dev,
else "unable to request IRQ, alarms disabled\n");
set_bit(RTC_FEATURE_ALARM, pcf85363->rtc->features); 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); ret = devm_rtc_register_device(pcf85363->rtc);
......
...@@ -14,7 +14,6 @@ ...@@ -14,7 +14,6 @@
#include <linux/io.h> #include <linux/io.h>
#include <linux/slab.h> #include <linux/slab.h>
#include <linux/of.h> #include <linux/of.h>
#include <linux/of_device.h>
#include "rtc-sa1100.h" #include "rtc-sa1100.h"
......
...@@ -12,7 +12,7 @@ ...@@ -12,7 +12,7 @@
#include <linux/bcd.h> #include <linux/bcd.h>
#include <linux/slab.h> #include <linux/slab.h>
#include <linux/module.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 * 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) ...@@ -826,8 +826,7 @@ static int rs5c372_probe(struct i2c_client *client)
rs5c372->client = client; rs5c372->client = client;
i2c_set_clientdata(client, rs5c372); i2c_set_clientdata(client, rs5c372);
if (client->dev.of_node) { if (client->dev.of_node) {
rs5c372->type = (enum rtc_type) rs5c372->type = (uintptr_t)of_device_get_match_data(&client->dev);
of_device_get_match_data(&client->dev);
} else { } else {
const struct i2c_device_id *id = i2c_match_id(rs5c372_id, client); const struct i2c_device_id *id = i2c_match_id(rs5c372_id, client);
rs5c372->type = id->driver_data; rs5c372->type = id->driver_data;
......
...@@ -17,7 +17,7 @@ ...@@ -17,7 +17,7 @@
#include <linux/kernel.h> #include <linux/kernel.h>
#include <linux/log2.h> #include <linux/log2.h>
#include <linux/module.h> #include <linux/module.h>
#include <linux/of_device.h> #include <linux/of.h>
#include <linux/regmap.h> #include <linux/regmap.h>
#include <linux/rtc.h> #include <linux/rtc.h>
...@@ -855,11 +855,68 @@ static const struct regmap_config regmap_config = { ...@@ -855,11 +855,68 @@ static const struct regmap_config regmap_config = {
.max_register = 0x37, .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) static int rv3028_probe(struct i2c_client *client)
{ {
struct rv3028_data *rv3028; struct rv3028_data *rv3028;
int ret, status; int ret, status;
u32 ohms;
struct nvmem_config nvmem_cfg = { struct nvmem_config nvmem_cfg = {
.name = "rv3028_nvram", .name = "rv3028_nvram",
.word_size = 1, .word_size = 1,
...@@ -937,24 +994,9 @@ static int rv3028_probe(struct i2c_client *client) ...@@ -937,24 +994,9 @@ static int rv3028_probe(struct i2c_client *client)
if (ret) if (ret)
return ret; return ret;
/* setup trickle charger */ ret = rv3028_set_trickle_charger(rv3028, client);
if (!device_property_read_u32(&client->dev, "trickle-resistor-ohms", if (ret)
&ohms)) { return ret;
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 = rtc_add_group(rv3028->rtc, &rv3028_attr_group); ret = rtc_add_group(rv3028->rtc, &rv3028_attr_group);
if (ret) if (ret)
......
...@@ -19,7 +19,7 @@ ...@@ -19,7 +19,7 @@
#include <linux/kernel.h> #include <linux/kernel.h>
#include <linux/log2.h> #include <linux/log2.h>
#include <linux/module.h> #include <linux/module.h>
#include <linux/of_device.h> #include <linux/of.h>
#include <linux/regmap.h> #include <linux/regmap.h>
#include <linux/rtc.h> #include <linux/rtc.h>
......
...@@ -15,7 +15,7 @@ ...@@ -15,7 +15,7 @@
#include <linux/interrupt.h> #include <linux/interrupt.h>
#include <linux/kernel.h> #include <linux/kernel.h>
#include <linux/module.h> #include <linux/module.h>
#include <linux/of_device.h> #include <linux/of.h>
#include <linux/rtc.h> #include <linux/rtc.h>
#define RV8803_I2C_TRY_COUNT 4 #define RV8803_I2C_TRY_COUNT 4
...@@ -645,8 +645,7 @@ static int rv8803_probe(struct i2c_client *client) ...@@ -645,8 +645,7 @@ static int rv8803_probe(struct i2c_client *client)
mutex_init(&rv8803->flags_lock); mutex_init(&rv8803->flags_lock);
rv8803->client = client; rv8803->client = client;
if (client->dev.of_node) { if (client->dev.of_node) {
rv8803->type = (enum rv8803_type) rv8803->type = (uintptr_t)of_device_get_match_data(&client->dev);
of_device_get_match_data(&client->dev);
} else { } else {
const struct i2c_device_id *id = i2c_match_id(rv8803_id, client); const struct i2c_device_id *id = i2c_match_id(rv8803_id, client);
......
...@@ -13,7 +13,6 @@ ...@@ -13,7 +13,6 @@
#include <linux/regmap.h> #include <linux/regmap.h>
#include <linux/rtc.h> #include <linux/rtc.h>
#include <linux/of.h> #include <linux/of.h>
#include <linux/of_device.h>
#include <linux/spi/spi.h> #include <linux/spi/spi.h>
#include <linux/i2c.h> #include <linux/i2c.h>
......
...@@ -13,7 +13,6 @@ ...@@ -13,7 +13,6 @@
#include <linux/i2c.h> #include <linux/i2c.h>
#include <linux/bcd.h> #include <linux/bcd.h>
#include <linux/of.h> #include <linux/of.h>
#include <linux/of_device.h>
#include <linux/regmap.h> #include <linux/regmap.h>
#include <linux/rtc.h> #include <linux/rtc.h>
#include <linux/log2.h> #include <linux/log2.h>
......
...@@ -15,7 +15,7 @@ ...@@ -15,7 +15,7 @@
#include <linux/init.h> #include <linux/init.h>
#include <linux/iopoll.h> #include <linux/iopoll.h>
#include <linux/module.h> #include <linux/module.h>
#include <linux/of_device.h> #include <linux/mod_devicetable.h>
#include <linux/platform_device.h> #include <linux/platform_device.h>
#include <linux/pm_runtime.h> #include <linux/pm_runtime.h>
#include <linux/rtc.h> #include <linux/rtc.h>
...@@ -227,7 +227,7 @@ static int rzn1_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alrm) ...@@ -227,7 +227,7 @@ static int rzn1_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alrm)
return ret; return ret;
/* We cannot set alarms more than one week ahead */ /* 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); alarm = rtc_tm_to_time64(tm);
if (time_after(alarm, farest)) if (time_after(alarm, farest))
return -ERANGE; return -ERANGE;
...@@ -351,6 +351,7 @@ static int rzn1_rtc_probe(struct platform_device *pdev) ...@@ -351,6 +351,7 @@ static int rzn1_rtc_probe(struct platform_device *pdev)
rtc->rtcdev->range_min = RTC_TIMESTAMP_BEGIN_2000; rtc->rtcdev->range_min = RTC_TIMESTAMP_BEGIN_2000;
rtc->rtcdev->range_max = RTC_TIMESTAMP_END_2099; rtc->rtcdev->range_max = RTC_TIMESTAMP_END_2099;
rtc->rtcdev->alarm_offset_max = 7 * 86400;
rtc->rtcdev->ops = &rzn1_rtc_ops; rtc->rtcdev->ops = &rzn1_rtc_ops;
set_bit(RTC_FEATURE_ALARM_RES_MINUTE, rtc->rtcdev->features); set_bit(RTC_FEATURE_ALARM_RES_MINUTE, rtc->rtcdev->features);
clear_bit(RTC_FEATURE_UPDATE_INTERRUPT, rtc->rtcdev->features); clear_bit(RTC_FEATURE_UPDATE_INTERRUPT, rtc->rtcdev->features);
......
...@@ -23,7 +23,6 @@ ...@@ -23,7 +23,6 @@
#include <linux/log2.h> #include <linux/log2.h>
#include <linux/slab.h> #include <linux/slab.h>
#include <linux/of.h> #include <linux/of.h>
#include <linux/of_device.h>
#include <linux/uaccess.h> #include <linux/uaccess.h>
#include <linux/io.h> #include <linux/io.h>
......
...@@ -6,11 +6,13 @@ ...@@ -6,11 +6,13 @@
#include <linux/bcd.h> #include <linux/bcd.h>
#include <linux/clk.h> #include <linux/clk.h>
#include <linux/errno.h>
#include <linux/iopoll.h> #include <linux/iopoll.h>
#include <linux/ioport.h> #include <linux/ioport.h>
#include <linux/mfd/syscon.h> #include <linux/mfd/syscon.h>
#include <linux/module.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/pm_wakeirq.h>
#include <linux/regmap.h> #include <linux/regmap.h>
#include <linux/rtc.h> #include <linux/rtc.h>
...@@ -89,6 +91,9 @@ ...@@ -89,6 +91,9 @@
/* Max STM32 RTC register offset is 0x3FC */ /* Max STM32 RTC register offset is 0x3FC */
#define UNDEF_REG 0xFFFF #define UNDEF_REG 0xFFFF
/* STM32 RTC driver time helpers */
#define SEC_PER_DAY (24 * 60 * 60)
struct stm32_rtc; struct stm32_rtc;
struct stm32_rtc_registers { struct stm32_rtc_registers {
...@@ -114,6 +119,7 @@ struct stm32_rtc_data { ...@@ -114,6 +119,7 @@ struct stm32_rtc_data {
void (*clear_events)(struct stm32_rtc *rtc, unsigned int flags); void (*clear_events)(struct stm32_rtc *rtc, unsigned int flags);
bool has_pclk; bool has_pclk;
bool need_dbp; bool need_dbp;
bool need_accuracy;
}; };
struct stm32_rtc { struct stm32_rtc {
...@@ -158,10 +164,9 @@ static int stm32_rtc_enter_init_mode(struct stm32_rtc *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 * slowest rtc_ck frequency may be 32kHz and highest should be
* 1MHz, we poll every 10 us with a timeout of 100ms. * 1MHz, we poll every 10 us with a timeout of 100ms.
*/ */
return readl_relaxed_poll_timeout_atomic( return readl_relaxed_poll_timeout_atomic(rtc->base + regs->isr, isr,
rtc->base + regs->isr, (isr & STM32_RTC_ISR_INITF),
isr, (isr & STM32_RTC_ISR_INITF), 10, 100000);
10, 100000);
} }
return 0; return 0;
...@@ -425,40 +430,42 @@ static int stm32_rtc_alarm_irq_enable(struct device *dev, unsigned int enabled) ...@@ -425,40 +430,42 @@ static int stm32_rtc_alarm_irq_enable(struct device *dev, unsigned int enabled)
return 0; 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; static struct rtc_time now;
int cur_day, cur_mon, cur_year, cur_hour, cur_min, cur_sec; time64_t max_alarm_time64;
unsigned int dr = readl_relaxed(rtc->base + regs->dr); int max_day_forward;
unsigned int tr = readl_relaxed(rtc->base + regs->tr); int next_month;
int next_year;
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;
/* /*
* Assuming current date is M-D-Y H:M:S. * Assuming current date is M-D-Y H:M:S.
* RTC alarm can't be set on a specific month and year. * RTC alarm can't be set on a specific month and year.
* So the valid alarm range is: * So the valid alarm range is:
* M-D-Y H:M:S < alarm <= (M+1)-D-Y H:M:S * 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) && stm32_rtc_read_time(dev, &now);
(tm->tm_mon == 0x1) && (cur_mon == 0x12)) ||
((tm->tm_year == cur_year) && /*
(tm->tm_mon <= cur_mon + 1))) && * Find the next month and the year of the next month.
((tm->tm_mday > cur_day) || * Note: tm_mon and next_month are from 0 to 11
((tm->tm_mday == cur_day) && */
((tm->tm_hour > cur_hour) || next_month = now.tm_mon + 1;
((tm->tm_hour == cur_hour) && (tm->tm_min > cur_min)) || if (next_month == 12) {
((tm->tm_hour == cur_hour) && (tm->tm_min == cur_min) && next_month = 0;
(tm->tm_sec >= cur_sec)))))) next_year = now.tm_year + 1;
return 0; } 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) 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) ...@@ -469,17 +476,17 @@ static int stm32_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alrm)
unsigned int cr, isr, alrmar; unsigned int cr, isr, alrmar;
int ret = 0; int ret = 0;
tm2bcd(tm);
/* /*
* RTC alarm can't be set on a specific date, unless this date is * RTC alarm can't be set on a specific date, unless this date is
* up to the same day of month next month. * 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"); dev_err(dev, "Alarm can be set only on upcoming month.\n");
return -EINVAL; return -EINVAL;
} }
tm2bcd(tm);
alrmar = 0; alrmar = 0;
/* tm_year and tm_mon are not used because not supported by RTC */ /* tm_year and tm_mon are not used because not supported by RTC */
alrmar |= (tm->tm_mday << STM32_RTC_ALRMXR_DATE_SHIFT) & alrmar |= (tm->tm_mday << STM32_RTC_ALRMXR_DATE_SHIFT) &
...@@ -545,6 +552,7 @@ static void stm32_rtc_clear_events(struct stm32_rtc *rtc, ...@@ -545,6 +552,7 @@ static void stm32_rtc_clear_events(struct stm32_rtc *rtc,
static const struct stm32_rtc_data stm32_rtc_data = { static const struct stm32_rtc_data stm32_rtc_data = {
.has_pclk = false, .has_pclk = false,
.need_dbp = true, .need_dbp = true,
.need_accuracy = false,
.regs = { .regs = {
.tr = 0x00, .tr = 0x00,
.dr = 0x04, .dr = 0x04,
...@@ -566,6 +574,7 @@ static const struct stm32_rtc_data stm32_rtc_data = { ...@@ -566,6 +574,7 @@ static const struct stm32_rtc_data stm32_rtc_data = {
static const struct stm32_rtc_data stm32h7_rtc_data = { static const struct stm32_rtc_data stm32h7_rtc_data = {
.has_pclk = true, .has_pclk = true,
.need_dbp = true, .need_dbp = true,
.need_accuracy = false,
.regs = { .regs = {
.tr = 0x00, .tr = 0x00,
.dr = 0x04, .dr = 0x04,
...@@ -596,6 +605,7 @@ static void stm32mp1_rtc_clear_events(struct stm32_rtc *rtc, ...@@ -596,6 +605,7 @@ static void stm32mp1_rtc_clear_events(struct stm32_rtc *rtc,
static const struct stm32_rtc_data stm32mp1_data = { static const struct stm32_rtc_data stm32mp1_data = {
.has_pclk = true, .has_pclk = true,
.need_dbp = false, .need_dbp = false,
.need_accuracy = true,
.regs = { .regs = {
.tr = 0x00, .tr = 0x00,
.dr = 0x04, .dr = 0x04,
...@@ -628,7 +638,7 @@ static int stm32_rtc_init(struct platform_device *pdev, ...@@ -628,7 +638,7 @@ static int stm32_rtc_init(struct platform_device *pdev,
const struct stm32_rtc_registers *regs = &rtc->data->regs; 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 prer, pred_a, pred_s, pred_a_max, pred_s_max, cr;
unsigned int rate; unsigned int rate;
int ret = 0; int ret;
rate = clk_get_rate(rtc->rtc_ck); rate = clk_get_rate(rtc->rtc_ck);
...@@ -636,18 +646,32 @@ static int stm32_rtc_init(struct platform_device *pdev, ...@@ -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_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; 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--) { if (rate > (pred_a_max + 1) * (pred_s_max + 1)) {
pred_s = (rate / (pred_a + 1)) - 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) if (((pred_s + 1) * (pred_a + 1)) == rate)
break; break;
}
} }
/* /*
* Can't find a 1Hz, so give priority to RTC power consumption * Can't find a 1Hz, so give priority to RTC power consumption
* by choosing the higher possible value for prediv_a * 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_a = pred_a_max;
pred_s = (rate / (pred_a + 1)) - 1; pred_s = (rate / (pred_a + 1)) - 1;
...@@ -656,6 +680,20 @@ static int stm32_rtc_init(struct platform_device *pdev, ...@@ -656,6 +680,20 @@ static int stm32_rtc_init(struct platform_device *pdev,
"fast" : "slow"); "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); stm32_rtc_wpr_unlock(rtc);
ret = stm32_rtc_enter_init_mode(rtc); ret = stm32_rtc_enter_init_mode(rtc);
...@@ -665,13 +703,10 @@ static int stm32_rtc_init(struct platform_device *pdev, ...@@ -665,13 +703,10 @@ static int stm32_rtc_init(struct platform_device *pdev,
goto end; goto end;
} }
prer = (pred_s << STM32_RTC_PRER_PRED_S_SHIFT) & STM32_RTC_PRER_PRED_S; writel_relaxed(pred_s, rtc->base + regs->prer);
writel_relaxed(prer, rtc->base + regs->prer); writel_relaxed(pred_a | pred_s, 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);
/* Force 24h time format */ /* Force 24h time format */
cr = readl_relaxed(rtc->base + regs->cr);
cr &= ~STM32_RTC_CR_FMT; cr &= ~STM32_RTC_CR_FMT;
writel_relaxed(cr, rtc->base + regs->cr); writel_relaxed(cr, rtc->base + regs->cr);
...@@ -730,16 +765,13 @@ static int stm32_rtc_probe(struct platform_device *pdev) ...@@ -730,16 +765,13 @@ static int stm32_rtc_probe(struct platform_device *pdev)
rtc->rtc_ck = devm_clk_get(&pdev->dev, NULL); rtc->rtc_ck = devm_clk_get(&pdev->dev, NULL);
} else { } else {
rtc->pclk = devm_clk_get(&pdev->dev, "pclk"); rtc->pclk = devm_clk_get(&pdev->dev, "pclk");
if (IS_ERR(rtc->pclk)) { if (IS_ERR(rtc->pclk))
dev_err(&pdev->dev, "no pclk clock"); return dev_err_probe(&pdev->dev, PTR_ERR(rtc->pclk), "no pclk clock");
return PTR_ERR(rtc->pclk);
}
rtc->rtc_ck = devm_clk_get(&pdev->dev, "rtc_ck"); rtc->rtc_ck = devm_clk_get(&pdev->dev, "rtc_ck");
} }
if (IS_ERR(rtc->rtc_ck)) { if (IS_ERR(rtc->rtc_ck))
dev_err(&pdev->dev, "no rtc_ck clock"); return dev_err_probe(&pdev->dev, PTR_ERR(rtc->rtc_ck), "no rtc_ck clock");
return PTR_ERR(rtc->rtc_ck);
}
if (rtc->data->has_pclk) { if (rtc->data->has_pclk) {
ret = clk_prepare_enable(rtc->pclk); ret = clk_prepare_enable(rtc->pclk);
...@@ -859,7 +891,6 @@ static void stm32_rtc_remove(struct platform_device *pdev) ...@@ -859,7 +891,6 @@ static void stm32_rtc_remove(struct platform_device *pdev)
device_init_wakeup(&pdev->dev, false); device_init_wakeup(&pdev->dev, false);
} }
#ifdef CONFIG_PM_SLEEP
static int stm32_rtc_suspend(struct device *dev) static int stm32_rtc_suspend(struct device *dev)
{ {
struct stm32_rtc *rtc = dev_get_drvdata(dev); struct stm32_rtc *rtc = dev_get_drvdata(dev);
...@@ -890,10 +921,10 @@ static int stm32_rtc_resume(struct device *dev) ...@@ -890,10 +921,10 @@ static int stm32_rtc_resume(struct device *dev)
return ret; return ret;
} }
#endif
static SIMPLE_DEV_PM_OPS(stm32_rtc_pm_ops, static const struct dev_pm_ops stm32_rtc_pm_ops = {
stm32_rtc_suspend, stm32_rtc_resume); NOIRQ_SYSTEM_SLEEP_PM_OPS(stm32_rtc_suspend, stm32_rtc_resume)
};
static struct platform_driver stm32_rtc_driver = { static struct platform_driver stm32_rtc_driver = {
.probe = stm32_rtc_probe, .probe = stm32_rtc_probe,
......
...@@ -18,7 +18,6 @@ ...@@ -18,7 +18,6 @@
#include <linux/delay.h> #include <linux/delay.h>
#include <linux/rtc.h> #include <linux/rtc.h>
#include <linux/slab.h> #include <linux/slab.h>
#include <linux/of_device.h>
#include <linux/of.h> #include <linux/of.h>
#include <linux/stmp_device.h> #include <linux/stmp_device.h>
#include <linux/stmp3xxx_rtc_wdt.h> #include <linux/stmp3xxx_rtc_wdt.h>
......
...@@ -24,7 +24,6 @@ ...@@ -24,7 +24,6 @@
#include <linux/module.h> #include <linux/module.h>
#include <linux/of.h> #include <linux/of.h>
#include <linux/of_address.h> #include <linux/of_address.h>
#include <linux/of_device.h>
#include <linux/platform_device.h> #include <linux/platform_device.h>
#include <linux/rtc.h> #include <linux/rtc.h>
#include <linux/slab.h> #include <linux/slab.h>
...@@ -847,8 +846,6 @@ static int sun6i_rtc_probe(struct platform_device *pdev) ...@@ -847,8 +846,6 @@ static int sun6i_rtc_probe(struct platform_device *pdev)
if (ret) if (ret)
return ret; return ret;
dev_info(&pdev->dev, "RTC enabled\n");
return 0; return 0;
} }
......
...@@ -244,7 +244,7 @@ static int sp_rtc_probe(struct platform_device *plat_dev) ...@@ -244,7 +244,7 @@ static int sp_rtc_probe(struct platform_device *plat_dev)
sp_rtc->irq = platform_get_irq(plat_dev, 0); sp_rtc->irq = platform_get_irq(plat_dev, 0);
if (sp_rtc->irq < 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, ret = devm_request_irq(&plat_dev->dev, sp_rtc->irq, sp_rtc_irq_handler,
IRQF_TRIGGER_RISING, "rtc irq", plat_dev); IRQF_TRIGGER_RISING, "rtc irq", plat_dev);
......
...@@ -14,8 +14,6 @@ ...@@ -14,8 +14,6 @@
#include <linux/kernel.h> #include <linux/kernel.h>
#include <linux/module.h> #include <linux/module.h>
#include <linux/of.h> #include <linux/of.h>
#include <linux/of_address.h>
#include <linux/of_device.h>
#include <linux/platform_device.h> #include <linux/platform_device.h>
#include <linux/rtc.h> #include <linux/rtc.h>
#include <linux/types.h> #include <linux/types.h>
......
...@@ -9,7 +9,7 @@ ...@@ -9,7 +9,7 @@
#include <linux/delay.h> #include <linux/delay.h>
#include <linux/mod_devicetable.h> #include <linux/mod_devicetable.h>
#include <linux/module.h> #include <linux/module.h>
#include <linux/of_device.h> #include <linux/of.h>
#include <linux/platform_device.h> #include <linux/platform_device.h>
#include <linux/sys_soc.h> #include <linux/sys_soc.h>
#include <linux/property.h> #include <linux/property.h>
......
...@@ -252,6 +252,7 @@ static int tps6586x_rtc_probe(struct platform_device *pdev) ...@@ -252,6 +252,7 @@ static int tps6586x_rtc_probe(struct platform_device *pdev)
rtc->rtc->ops = &tps6586x_rtc_ops; rtc->rtc->ops = &tps6586x_rtc_ops;
rtc->rtc->range_max = (1ULL << 30) - 1; /* 30-bit seconds */ 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->start_secs = mktime64(2009, 1, 1, 0, 0, 0);
rtc->rtc->set_start_time = true; rtc->rtc->set_start_time = true;
......
...@@ -406,11 +406,8 @@ static int tps65910_rtc_probe(struct platform_device *pdev) ...@@ -406,11 +406,8 @@ static int tps65910_rtc_probe(struct platform_device *pdev)
platform_set_drvdata(pdev, tps_rtc); platform_set_drvdata(pdev, tps_rtc);
irq = platform_get_irq(pdev, 0); irq = platform_get_irq(pdev, 0);
if (irq <= 0) { if (irq < 0)
dev_warn(&pdev->dev, "Wake up is not possible as irq = %d\n", return irq;
irq);
return -ENXIO;
}
ret = devm_request_threaded_irq(&pdev->dev, irq, NULL, ret = devm_request_threaded_irq(&pdev->dev, irq, NULL,
tps65910_rtc_interrupt, IRQF_TRIGGER_LOW, tps65910_rtc_interrupt, IRQF_TRIGGER_LOW,
......
...@@ -487,11 +487,24 @@ static const struct rtc_class_ops twl_rtc_ops = { ...@@ -487,11 +487,24 @@ static const struct rtc_class_ops twl_rtc_ops = {
.alarm_irq_enable = twl_rtc_alarm_irq_enable, .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) static int twl_rtc_probe(struct platform_device *pdev)
{ {
struct twl_rtc *twl_rtc; struct twl_rtc *twl_rtc;
struct nvmem_config nvmem_cfg;
struct device_node *np = pdev->dev.of_node; struct device_node *np = pdev->dev.of_node;
int ret = -EINVAL; int ret = -EINVAL;
int irq = platform_get_irq(pdev, 0); int irq = platform_get_irq(pdev, 0);
...@@ -542,7 +555,6 @@ static int twl_rtc_probe(struct platform_device *pdev) ...@@ -542,7 +555,6 @@ static int twl_rtc_probe(struct platform_device *pdev)
REG_INT_MSK_STS_A); 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, ret = twl_rtc_write_u8(twl_rtc, BIT_RTC_CTRL_REG_STOP_RTC_M,
REG_RTC_CTRL_REG); REG_RTC_CTRL_REG);
if (ret < 0) if (ret < 0)
...@@ -564,11 +576,8 @@ static int twl_rtc_probe(struct platform_device *pdev) ...@@ -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->rtc = devm_rtc_device_register(&pdev->dev, pdev->name,
&twl_rtc_ops, THIS_MODULE); &twl_rtc_ops, THIS_MODULE);
if (IS_ERR(twl_rtc->rtc)) { if (IS_ERR(twl_rtc->rtc))
dev_err(&pdev->dev, "can't register RTC device, err %ld\n",
PTR_ERR(twl_rtc->rtc));
return PTR_ERR(twl_rtc->rtc); return PTR_ERR(twl_rtc->rtc);
}
ret = devm_request_threaded_irq(&pdev->dev, irq, NULL, ret = devm_request_threaded_irq(&pdev->dev, irq, NULL,
twl_rtc_interrupt, twl_rtc_interrupt,
...@@ -579,6 +588,30 @@ static int twl_rtc_probe(struct platform_device *pdev) ...@@ -579,6 +588,30 @@ static int twl_rtc_probe(struct platform_device *pdev)
return ret; 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; return 0;
} }
......
...@@ -386,8 +386,6 @@ static int wm8350_rtc_probe(struct platform_device *pdev) ...@@ -386,8 +386,6 @@ static int wm8350_rtc_probe(struct platform_device *pdev)
/* enable the RTC if it's not already enabled */ /* enable the RTC if it's not already enabled */
power5 = wm8350_reg_read(wm8350, WM8350_POWER_MGMT_5); power5 = wm8350_reg_read(wm8350, WM8350_POWER_MGMT_5);
if (!(power5 & WM8350_RTC_TICK_ENA)) { if (!(power5 & WM8350_RTC_TICK_ENA)) {
dev_info(wm8350->dev, "Starting RTC\n");
wm8350_reg_unlock(wm8350); wm8350_reg_unlock(wm8350);
ret = wm8350_set_bits(wm8350, WM8350_POWER_MGMT_5, ret = wm8350_set_bits(wm8350, WM8350_POWER_MGMT_5,
...@@ -426,11 +424,8 @@ static int wm8350_rtc_probe(struct platform_device *pdev) ...@@ -426,11 +424,8 @@ static int wm8350_rtc_probe(struct platform_device *pdev)
wm_rtc->rtc = devm_rtc_device_register(&pdev->dev, "wm8350", wm_rtc->rtc = devm_rtc_device_register(&pdev->dev, "wm8350",
&wm8350_rtc_ops, THIS_MODULE); &wm8350_rtc_ops, THIS_MODULE);
if (IS_ERR(wm_rtc->rtc)) { if (IS_ERR(wm_rtc->rtc))
ret = PTR_ERR(wm_rtc->rtc); return PTR_ERR(wm_rtc->rtc);
dev_err(&pdev->dev, "failed to register RTC: %d\n", ret);
return ret;
}
ret = wm8350_register_irq(wm8350, WM8350_IRQ_RTC_SEC, ret = wm8350_register_irq(wm8350, WM8350_IRQ_RTC_SEC,
wm8350_rtc_update_handler, 0, wm8350_rtc_update_handler, 0,
......
/*
* ds2404.h - platform data structure for the DS2404 RTC.
*
* This file is subject to the terms and conditions of the GNU General Public
* License. See the file "COPYING" in the main directory of this archive
* for more details.
*
* Copyright (C) 2012 Sven Schnelle <svens@stackframe.org>
*/
#ifndef __LINUX_DS2404_H
#define __LINUX_DS2404_H
struct ds2404_platform_data {
unsigned int gpio_rst;
unsigned int gpio_clk;
unsigned int gpio_dq;
};
#endif
...@@ -146,6 +146,7 @@ struct rtc_device { ...@@ -146,6 +146,7 @@ struct rtc_device {
time64_t range_min; time64_t range_min;
timeu64_t range_max; timeu64_t range_max;
timeu64_t alarm_offset_max;
time64_t start_secs; time64_t start_secs;
time64_t offset_secs; time64_t offset_secs;
bool set_start_time; bool set_start_time;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment