RTC for 7.0

Drivers:
  - loongson: Loongson-2K0300 support
  - s35390a: nvmem support
  - zynqmp: rework calibration
 -----BEGIN PGP SIGNATURE-----
 
 iQIzBAABCgAdFiEEBqsFVZXh8s/0O5JiY6TcMGxwOjIFAmmaW6UACgkQY6TcMGxw
 OjIEBA//T+wV/SxNKwTZc5+f0nA2ndhvSNQduy1Diguj0yt0pxweENopkRUMtyVh
 5cHWqTNj9R7OWQiUBfAMCia4OgVHGVgp4zRONohFpwa1aKLTJJtgancRcrrKie5A
 MTyzWaOl0odk6utU1MEXMdA7cF1Wr2moPbMEvEyE7LhgT0dF+CM2jD8yGuZawum2
 vH9aTDc6xMOofpjTlxOyb64fK3BJ9PUaSi++HJ22VP88+XS5GOPgpoBnYdA5lSju
 XWW3hAWYekg8F4Km9omEfjXWnJ5qvrJUBNnGz5m5ipp1rU/ZD3eg/kJ5YeNQZOfq
 YALhaNXfkHbrQXXfNHVaL77od2zUvpOWaN6DPbbKlYlqsZnWmD++8w3hVZT5jEP4
 XJ3oNpHjMt2WT5GnF96Ya636ZR36PnZSgb3TgoDgJ9Xx8Ko4ov/v62Mz5v6oxh4P
 NeB0XqnwBxa0YJ/73XVNsiJ54U4LY4k3A9SqZ1mjpHEXFlf+MpErNmgTi0Q/BP81
 RUcNI3GQuTAX/MaXSbceFn0K8XJxG+HKWqW3j0rmjN5BFSYqPGPGNWZaS8SUNwlt
 Xj6aeJRV9RTEc+fZqLss/ztxGXyCGcgM0+OOlXyQsVLHcQZAH36c67auM+OzmZZH
 uMhix3OcawZDlpDugHdJJtau0Clj7xtrrdSZqTuAuJXFIGNNtow=
 =YiJy
 -----END PGP SIGNATURE-----

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

Pull RTC updates from Alexandre Belloni:

 - loongson: Loongson-2K0300 support

 - s35390a: nvmem support

 - zynqmp: rework calibration

* tag 'rtc-7.0' of git://git.kernel.org/pub/scm/linux/kernel/git/abelloni/linux:
  rtc: ds1390: fix number of bytes read from RTC
  rtc: class: Remove duplicate check for alarm
  rtc: optee: simplify OP-TEE context match
  rtc: interface: Alarm race handling should not discard preceding error
  rtc: s35390a: implement nvmem support
  rtc: loongson: Add Loongson-2K0300 support
  dt-bindings: rtc: loongson: Document Loongson-2K0300 compatible
  dt-bindings: rtc: loongson: Correct Loongson-1C interrupts property
  dt-bindings: rtc: renesas,rz-rtca3: Add RZ/V2N support
  dt-bindings: rtc: cpcap: convert to schema
  rtc: zynqmp: use dynamic max and min offset ranges
  rtc: zynqmp: rework set_offset
  rtc: zynqmp: rework read_offset
  rtc: zynqmp: check calibration max value
  rtc: zynqmp: correct frequency value
  rtc: amlogic-a4: Remove IRQF_ONESHOT
  rtc: pcf8563: use correct of_node for output clock
  rtc: max31335: use correct CONFIG symbol in IS_REACHABLE()
  rtc: nvvrs: Add ARCH_TEGRA to the NV VRS RTC driver
This commit is contained in:
Linus Torvalds 2026-02-22 09:43:11 -08:00
commit 5f2eac7767
14 changed files with 178 additions and 88 deletions

View file

@ -1,18 +0,0 @@
Motorola CPCAP PMIC RTC
-----------------------
This module is part of the CPCAP. For more details about the whole
chip see Documentation/devicetree/bindings/mfd/motorola-cpcap.txt.
Requires node properties:
- compatible: should contain "motorola,cpcap-rtc"
- interrupts: An interrupt specifier for alarm and 1 Hz irq
Example:
&cpcap {
cpcap_rtc: rtc {
compatible = "motorola,cpcap-rtc";
interrupts = <39 IRQ_TYPE_NONE>, <26 IRQ_TYPE_NONE>;
};
};

View file

@ -23,6 +23,7 @@ properties:
- loongson,ls1b-rtc
- loongson,ls1c-rtc
- loongson,ls7a-rtc
- loongson,ls2k0300-rtc
- loongson,ls2k1000-rtc
- items:
- enum:
@ -42,6 +43,18 @@ required:
unevaluatedProperties: false
if:
properties:
compatible:
contains:
enum:
- loongson,ls1c-rtc
- loongson,ls2k0300-rtc
then:
properties:
interrupts: false
examples:
- |
#include <dt-bindings/interrupt-controller/irq.h>

View file

@ -0,0 +1,32 @@
# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause)
%YAML 1.2
---
$id: http://devicetree.org/schemas/rtc/motorola,cpcap-rtc.yaml#
$schema: http://devicetree.org/meta-schemas/core.yaml#
title: Motorola CPCAP PMIC RTC
maintainers:
- Svyatoslav Ryhel <clamor95@gmail.com>
description:
This module is part of the Motorola CPCAP MFD device. For more details
see Documentation/devicetree/bindings/mfd/motorola,cpcap.yaml. The
RTC is represented as a sub-node of the PMIC node on the device tree.
properties:
compatible:
const: motorola,cpcap-rtc
interrupts:
items:
- description: alarm interrupt
- description: 1 Hz interrupt
required:
- compatible
- interrupts
additionalProperties: false
...

View file

@ -14,6 +14,7 @@ properties:
items:
- enum:
- renesas,r9a08g045-rtca3 # RZ/G3S
- renesas,r9a09g056-rtca3 # RZ/V2N
- renesas,r9a09g057-rtca3 # RZ/V2H
- const: renesas,rz-rtca3
@ -82,7 +83,9 @@ allOf:
properties:
compatible:
contains:
const: renesas,r9a09g057-rtca3
enum:
- renesas,r9a09g056-rtca3
- renesas,r9a09g057-rtca3
then:
properties:
resets:

View file

@ -418,6 +418,7 @@ config RTC_DRV_SPACEMIT_P1
config RTC_DRV_NVIDIA_VRS10
tristate "NVIDIA VRS10 RTC device"
depends on ARCH_TEGRA || COMPILE_TEST
help
If you say yes here you will get support for the battery backed RTC device
of NVIDIA VRS (Voltage Regulator Specification). The RTC is connected via

View file

@ -410,7 +410,7 @@ int __devm_rtc_register_device(struct module *owner, struct rtc_device *rtc)
/* Check to see if there is an ALARM already set in hw */
err = __rtc_read_alarm(rtc, &alrm);
if (!err && !rtc_valid_tm(&alrm.time))
if (!err)
rtc_initialize_alarm(rtc, &alrm);
rtc_dev_prepare(rtc);

View file

@ -457,7 +457,7 @@ static int __rtc_set_alarm(struct rtc_device *rtc, struct rtc_wkalrm *alarm)
* are in, we can return -ETIME to signal that the timer has already
* expired, which is true in both cases.
*/
if ((scheduled - now) <= 1) {
if (!err && (scheduled - now) <= 1) {
err = __rtc_read_time(rtc, &tm);
if (err)
return err;

View file

@ -134,7 +134,7 @@ static int ds1390_read_time(struct device *dev, struct rtc_time *dt)
chip->txrx_buf[0] = DS1390_REG_SECONDS;
/* do the i/o */
status = spi_write_then_read(spi, chip->txrx_buf, 1, chip->txrx_buf, 8);
status = spi_write_then_read(spi, chip->txrx_buf, 1, chip->txrx_buf, 7);
if (status != 0)
return status;

View file

@ -66,7 +66,8 @@
* According to the LS1C manual, RTC_CTRL and alarm-related registers are not defined.
* Accessing the relevant registers will cause the system to hang.
*/
#define LS1C_RTC_CTRL_WORKAROUND BIT(0)
#define LOONGSON_RTC_CTRL_WORKAROUND BIT(0)
#define LOONGSON_RTC_ALARM_WORKAROUND BIT(1)
struct loongson_rtc_config {
u32 pm_offset; /* Offset of PM domain, for RTC alarm wakeup */
@ -89,7 +90,7 @@ static const struct loongson_rtc_config ls1b_rtc_config = {
static const struct loongson_rtc_config ls1c_rtc_config = {
.pm_offset = 0,
.flags = LS1C_RTC_CTRL_WORKAROUND,
.flags = LOONGSON_RTC_CTRL_WORKAROUND | LOONGSON_RTC_ALARM_WORKAROUND,
};
static const struct loongson_rtc_config generic_rtc_config = {
@ -97,6 +98,11 @@ static const struct loongson_rtc_config generic_rtc_config = {
.flags = 0,
};
static const struct loongson_rtc_config ls2k0300_rtc_config = {
.pm_offset = 0x0,
.flags = LOONGSON_RTC_ALARM_WORKAROUND,
};
static const struct loongson_rtc_config ls2k1000_rtc_config = {
.pm_offset = 0x800,
.flags = 0,
@ -153,7 +159,7 @@ static int loongson_rtc_set_enabled(struct device *dev)
{
struct loongson_rtc_priv *priv = dev_get_drvdata(dev);
if (priv->config->flags & LS1C_RTC_CTRL_WORKAROUND)
if (priv->config->flags & LOONGSON_RTC_CTRL_WORKAROUND)
return 0;
/* Enable RTC TOY counters and crystal */
@ -167,7 +173,7 @@ static bool loongson_rtc_get_enabled(struct device *dev)
u32 ctrl_data;
struct loongson_rtc_priv *priv = dev_get_drvdata(dev);
if (priv->config->flags & LS1C_RTC_CTRL_WORKAROUND)
if (priv->config->flags & LOONGSON_RTC_CTRL_WORKAROUND)
return true;
ret = regmap_read(priv->regmap, RTC_CTRL_REG, &ctrl_data);
@ -299,9 +305,41 @@ static const struct rtc_class_ops loongson_rtc_ops = {
.alarm_irq_enable = loongson_rtc_alarm_irq_enable,
};
static int loongson_rtc_alarm_setting(struct platform_device *pdev, void __iomem *regs)
{
int ret = 0, alarm_irq;
struct device *dev = &pdev->dev;
struct loongson_rtc_priv *priv = dev_get_drvdata(dev);
if (priv->config->flags & LOONGSON_RTC_ALARM_WORKAROUND) {
/* Loongson-1C/Loongson-2K0300 RTC does not support alarm */
clear_bit(RTC_FEATURE_ALARM, priv->rtcdev->features);
return 0;
}
/* Get RTC alarm irq */
alarm_irq = platform_get_irq(pdev, 0);
if (alarm_irq < 0)
return alarm_irq;
ret = devm_request_irq(dev, alarm_irq, loongson_rtc_isr, 0, "loongson-alarm",
priv);
if (ret < 0)
return ret;
priv->pm_base = regs - priv->config->pm_offset;
device_init_wakeup(dev, true);
if (has_acpi_companion(dev))
acpi_install_fixed_event_handler(ACPI_EVENT_RTC,
loongson_rtc_handler, priv);
return ret;
}
static int loongson_rtc_probe(struct platform_device *pdev)
{
int ret, alarm_irq;
int ret;
void __iomem *regs;
struct loongson_rtc_priv *priv;
struct device *dev = &pdev->dev;
@ -330,25 +368,9 @@ static int loongson_rtc_probe(struct platform_device *pdev)
return dev_err_probe(dev, PTR_ERR(priv->rtcdev),
"devm_rtc_allocate_device failed\n");
/* Get RTC alarm irq */
alarm_irq = platform_get_irq(pdev, 0);
if (alarm_irq > 0) {
ret = devm_request_irq(dev, alarm_irq, loongson_rtc_isr,
0, "loongson-alarm", priv);
if (ret < 0)
return dev_err_probe(dev, ret, "Unable to request irq %d\n",
alarm_irq);
priv->pm_base = regs - priv->config->pm_offset;
device_init_wakeup(dev, true);
if (has_acpi_companion(dev))
acpi_install_fixed_event_handler(ACPI_EVENT_RTC,
loongson_rtc_handler, priv);
} else {
/* Loongson-1C RTC does not support alarm */
clear_bit(RTC_FEATURE_ALARM, priv->rtcdev->features);
}
ret = loongson_rtc_alarm_setting(pdev, regs);
if (ret)
return ret;
/* Loongson RTC does not support UIE */
clear_bit(RTC_FEATURE_UPDATE_INTERRUPT, priv->rtcdev->features);
@ -379,6 +401,7 @@ static const struct of_device_id loongson_rtc_of_match[] = {
{ .compatible = "loongson,ls1b-rtc", .data = &ls1b_rtc_config },
{ .compatible = "loongson,ls1c-rtc", .data = &ls1c_rtc_config },
{ .compatible = "loongson,ls7a-rtc", .data = &generic_rtc_config },
{ .compatible = "loongson,ls2k0300-rtc", .data = &ls2k0300_rtc_config },
{ .compatible = "loongson,ls2k1000-rtc", .data = &ls2k1000_rtc_config },
{ /* sentinel */ }
};

View file

@ -591,7 +591,7 @@ static struct nvmem_config max31335_nvmem_cfg = {
.size = MAX31335_RAM_SIZE,
};
#if IS_REACHABLE(HWMON)
#if IS_REACHABLE(CONFIG_HWMON)
static int max31335_read_temp(struct device *dev, enum hwmon_sensor_types type,
u32 attr, int channel, long *val)
{
@ -672,7 +672,7 @@ static int max31335_clkout_register(struct device *dev)
static int max31335_probe(struct i2c_client *client)
{
struct max31335_data *max31335;
#if IS_REACHABLE(HWMON)
#if IS_REACHABLE(CONFIG_HWMON)
struct device *hwmon;
#endif
const struct chip_desc *match;
@ -727,7 +727,7 @@ static int max31335_probe(struct i2c_client *client)
return dev_err_probe(&client->dev, ret,
"cannot register rtc nvmem\n");
#if IS_REACHABLE(HWMON)
#if IS_REACHABLE(CONFIG_HWMON)
if (max31335->chip->temp_reg) {
hwmon = devm_hwmon_device_register_with_info(&client->dev, client->name, max31335,
&max31335_chip_info, NULL);

View file

@ -541,10 +541,7 @@ static int optee_rtc_read_info(struct device *dev, struct rtc_device *rtc,
static int optee_ctx_match(struct tee_ioctl_version_data *ver, const void *data)
{
if (ver->impl_id == TEE_IMPL_ID_OPTEE)
return 1;
else
return 0;
return (ver->impl_id == TEE_IMPL_ID_OPTEE);
}
static int optee_rtc_probe(struct tee_client_device *rtc_device)

View file

@ -424,7 +424,7 @@ static const struct clk_ops pcf8563_clkout_ops = {
static struct clk *pcf8563_clkout_register_clk(struct pcf8563 *pcf8563)
{
struct device_node *node = pcf8563->rtc->dev.of_node;
struct device_node *node = pcf8563->rtc->dev.parent->of_node;
struct clk_init_data init;
struct clk *clk;
int ret;

View file

@ -18,6 +18,7 @@
#define S35390A_CMD_TIME1 2
#define S35390A_CMD_TIME2 3
#define S35390A_CMD_INT2_REG1 5
#define S35390A_CMD_FREE_REG 7
#define S35390A_BYTE_YEAR 0
#define S35390A_BYTE_MONTH 1
@ -416,6 +417,23 @@ static const struct rtc_class_ops s35390a_rtc_ops = {
.ioctl = s35390a_rtc_ioctl,
};
static int s35390a_nvmem_read(void *priv, unsigned int offset, void *val,
size_t bytes)
{
struct s35390a *s35390a = priv;
/* The offset is ignored because the NVMEM region is only 1 byte */
return s35390a_get_reg(s35390a, S35390A_CMD_FREE_REG, val, bytes);
}
static int s35390a_nvmem_write(void *priv, unsigned int offset, void *val,
size_t bytes)
{
struct s35390a *s35390a = priv;
return s35390a_set_reg(s35390a, S35390A_CMD_FREE_REG, val, bytes);
}
static int s35390a_probe(struct i2c_client *client)
{
int err, err_read;
@ -424,6 +442,15 @@ static int s35390a_probe(struct i2c_client *client)
struct rtc_device *rtc;
u8 buf, status1;
struct device *dev = &client->dev;
struct nvmem_config nvmem_cfg = {
.name = "s35390a_nvram",
.type = NVMEM_TYPE_BATTERY_BACKED,
.word_size = 1,
.stride = 1,
.size = 1,
.reg_read = s35390a_nvmem_read,
.reg_write = s35390a_nvmem_write,
};
if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C))
return -ENODEV;
@ -490,6 +517,11 @@ static int s35390a_probe(struct i2c_client *client)
if (status1 & S35390A_FLAG_INT2)
rtc_update_irq(rtc, 1, RTC_AF);
nvmem_cfg.priv = s35390a;
err = devm_rtc_nvmem_register(rtc, &nvmem_cfg);
if (err)
return err;
return devm_rtc_register_device(rtc);
}

View file

@ -43,9 +43,7 @@
#define RTC_MSEC 1000
#define RTC_FR_MASK 0xF0000
#define RTC_FR_MAX_TICKS 16
#define RTC_PPB 1000000000LL
#define RTC_MIN_OFFSET -32768000
#define RTC_MAX_OFFSET 32767000
#define RTC_PPB 1000000000
struct xlnx_rtc_dev {
struct rtc_device *rtc;
@ -178,21 +176,28 @@ static void xlnx_init_rtc(struct xlnx_rtc_dev *xrtcdev)
static int xlnx_rtc_read_offset(struct device *dev, long *offset)
{
struct xlnx_rtc_dev *xrtcdev = dev_get_drvdata(dev);
unsigned long long rtc_ppb = RTC_PPB;
unsigned int tick_mult = do_div(rtc_ppb, xrtcdev->freq);
unsigned int calibval;
unsigned int calibval, fract_data, fract_part;
int freq = xrtcdev->freq;
int max_tick, tick_mult;
long offset_val;
/* Tick to offset multiplier */
tick_mult = DIV_ROUND_CLOSEST(RTC_PPB, freq);
calibval = readl(xrtcdev->reg_base + RTC_CALIB_RD);
/* Offset with seconds ticks */
offset_val = calibval & RTC_TICK_MASK;
offset_val = offset_val - RTC_CALIB_DEF;
offset_val = offset_val * tick_mult;
max_tick = calibval & RTC_TICK_MASK;
offset_val = max_tick - freq;
/* Convert to ppb */
offset_val *= tick_mult;
/* Offset with fractional ticks */
if (calibval & RTC_FR_EN)
offset_val += ((calibval & RTC_FR_MASK) >> RTC_FR_DATSHIFT)
* (tick_mult / RTC_FR_MAX_TICKS);
if (calibval & RTC_FR_EN) {
fract_data = (calibval & RTC_FR_MASK) >> RTC_FR_DATSHIFT;
fract_part = DIV_ROUND_UP(tick_mult, RTC_FR_MAX_TICKS);
offset_val += (fract_part * fract_data);
}
*offset = offset_val;
return 0;
@ -201,44 +206,38 @@ static int xlnx_rtc_read_offset(struct device *dev, long *offset)
static int xlnx_rtc_set_offset(struct device *dev, long offset)
{
struct xlnx_rtc_dev *xrtcdev = dev_get_drvdata(dev);
unsigned long long rtc_ppb = RTC_PPB;
unsigned int tick_mult = do_div(rtc_ppb, xrtcdev->freq);
unsigned char fract_tick = 0;
int max_tick, tick_mult, fract_offset, fract_part;
int freq = xrtcdev->freq;
unsigned int calibval;
short int max_tick;
int fract_offset;
int fract_data = 0;
if (offset < RTC_MIN_OFFSET || offset > RTC_MAX_OFFSET)
return -ERANGE;
/* Tick to offset multiplier */
tick_mult = DIV_ROUND_CLOSEST(RTC_PPB, freq);
/* Number ticks for given offset */
max_tick = div_s64_rem(offset, tick_mult, &fract_offset);
if (freq + max_tick > RTC_TICK_MASK || (freq + max_tick < 1))
return -ERANGE;
/* Number fractional ticks for given offset */
if (fract_offset) {
if (fract_offset < 0) {
fract_offset = fract_offset + tick_mult;
fract_part = DIV_ROUND_UP(tick_mult, RTC_FR_MAX_TICKS);
fract_data = fract_offset / fract_part;
/* Subtract one from max_tick while adding fract_offset */
if (fract_offset < 0 && fract_data) {
max_tick--;
}
if (fract_offset > (tick_mult / RTC_FR_MAX_TICKS)) {
for (fract_tick = 1; fract_tick < 16; fract_tick++) {
if (fract_offset <=
(fract_tick *
(tick_mult / RTC_FR_MAX_TICKS)))
break;
}
fract_data += RTC_FR_MAX_TICKS;
}
}
/* Zynqmp RTC uses second and fractional tick
* counters for compensation
*/
calibval = max_tick + RTC_CALIB_DEF;
calibval = max_tick + freq;
if (fract_tick)
calibval |= RTC_FR_EN;
calibval |= (fract_tick << RTC_FR_DATSHIFT);
if (fract_data)
calibval |= (RTC_FR_EN | (fract_data << RTC_FR_DATSHIFT));
writel(calibval, (xrtcdev->reg_base + RTC_CALIB_WR));
@ -345,7 +344,15 @@ static int xlnx_rtc_probe(struct platform_device *pdev)
&xrtcdev->freq);
if (ret)
xrtcdev->freq = RTC_CALIB_DEF;
} else {
xrtcdev->freq--;
}
if (xrtcdev->freq > RTC_TICK_MASK) {
dev_err(&pdev->dev, "Invalid RTC calibration value\n");
return -EINVAL;
}
ret = readl(xrtcdev->reg_base + RTC_CALIB_RD);
if (!ret)
writel(xrtcdev->freq, (xrtcdev->reg_base + RTC_CALIB_WR));