* Re: [PATCH v2 02/11] dt-bindings: hwmon: Add Apple System Management Controller hwmon schema
From: Janne Grunau @ 2025-09-25 20:49 UTC (permalink / raw)
To: Rob Herring
Cc: James Calligeros, Sven Peter, Alyssa Rosenzweig, Neal Gompa,
Lee Jones, Krzysztof Kozlowski, Conor Dooley, Alexandre Belloni,
Jean Delvare, Guenter Roeck, Dmitry Torokhov, asahi,
linux-arm-kernel, devicetree, linux-kernel, linux-rtc,
linux-hwmon, linux-input
In-Reply-To: <20250829164057.GA976361-robh@kernel.org>
On Fri, Aug 29, 2025 at 11:40:57AM -0500, Rob Herring wrote:
> On Wed, Aug 27, 2025 at 09:22:36PM +1000, James Calligeros wrote:
> > Apple Silicon devices integrate a vast array of sensors, monitoring
> > current, power, temperature, and voltage across almost every part of
> > the system. The sensors themselves are all connected to the System
> > Management Controller (SMC). The SMC firmware exposes the data
> > reported by these sensors via its standard FourCC-based key-value
> > API. The SMC is also responsible for monitoring and controlling any
> > fans connected to the system, exposing them in the same way.
> >
> > For reasons known only to Apple, each device exposes its sensors with
> > an almost totally unique set of keys. This is true even for devices
> > which share an SoC. An M1 Mac mini, for example, will report its core
> > temperatures on different keys to an M1 MacBook Pro. Worse still, the
> > SMC does not provide a way to enumerate the available keys at runtime,
> > nor do the keys follow any sort of reasonable or consistent naming
> > rules that could be used to deduce their purpose. We must therefore
> > know which keys are present on any given device, and which function
> > they serve, ahead of time.
> >
> > Add a schema so that we can describe the available sensors for a given
> > Apple Silicon device in the Devicetree.
> >
> > Signed-off-by: James Calligeros <jcalligeros99@gmail.com>
> > ---
> > .../bindings/hwmon/apple,smc-hwmon.yaml | 132 +++++++++++++++++++++++++
> > .../bindings/mfd/apple,smc.yaml | 36 +++++++
> > MAINTAINERS | 1 +
> > 3 files changed, 169 insertions(+)
> >
> > diff --git a/Documentation/devicetree/bindings/hwmon/apple,smc-hwmon.yaml b/Documentation/devicetree/bindings/hwmon/apple,smc-hwmon.yaml
> > new file mode 100644
> > index 0000000000000000000000000000000000000000..08cc4f55f3a41ca8b3b428088f96240266fa42e8
> > --- /dev/null
> > +++ b/Documentation/devicetree/bindings/hwmon/apple,smc-hwmon.yaml
> > @@ -0,0 +1,132 @@
>
> This should be something like this:
>
> "^current-[A-Za-z0-9]{4}$":
> $ref: "#/$defs/sensor"
> unevaluatedProperties: false
>
> With the $defs/sensor being:
>
> $defs:
> sensor:
> type: object
>
> properties:
> apple,key-id:
> $ref: /schemas/types.yaml#/definitions/string
> pattern: "^[A-Za-z0-9]{4}$"
> description:
> The SMC FourCC key of the desired sensor. Must match the
> node's suffix.
>
> label:
> description: Human-readable name for the sensor
>
> required:
> - apple,key-id
> - label
>
> Though in general, 'label' should never be required being just for human
> convenience.
That does not sound as it would be compatible with skipping nodes in the
driver if the node misses label. The driver could of course fall back
to create a hwmon sensors without labels. I looks to me it would be a
stretch to call the presence of the labels human convenience.
Janne
^ permalink raw reply
* RE: [PATCH V2] rtc: zynqmp: Restore alarm functionality after kexec transition
From: T, Harini @ 2025-09-25 6:04 UTC (permalink / raw)
To: alexandre.belloni@bootlin.com, Simek, Michal
Cc: linux-rtc@vger.kernel.org, linux-arm-kernel@lists.infradead.org,
linux-kernel@vger.kernel.org, git (AMD-Xilinx)
In-Reply-To: <DS7PR12MB606995B08A344C01711C7BCC9201A@DS7PR12MB6069.namprd12.prod.outlook.com>
[Public]
Ping!
> -----Original Message-----
> From: T, Harini
> Sent: Wednesday, September 3, 2025 8:53 PM
> To: Harini T <harini.t@amd.com>; alexandre.belloni@bootlin.com; Simek,
> Michal <michal.simek@amd.com>
> Cc: linux-rtc@vger.kernel.org; linux-arm-kernel@lists.infradead.org; linux-
> kernel@vger.kernel.org; git (AMD-Xilinx) <git@amd.com>
> Subject: RE: [PATCH V2] rtc: zynqmp: Restore alarm functionality after kexec
> transition
>
> Hi Alexandre,
>
> > -----Original Message-----
> > From: Harini T <harini.t@amd.com>
> > Sent: Wednesday, July 30, 2025 7:51 PM
> > To: alexandre.belloni@bootlin.com; Simek, Michal
> > <michal.simek@amd.com>
> > Cc: linux-rtc@vger.kernel.org; linux-arm-kernel@lists.infradead.org;
> > linux- kernel@vger.kernel.org; git (AMD-Xilinx) <git@amd.com>; T,
> > Harini <Harini.T@amd.com>
> > Subject: [PATCH V2] rtc: zynqmp: Restore alarm functionality after
> > kexec transition
> >
> > Caution: This message originated from an External Source. Use proper
> > caution when opening attachments, clicking links, or responding.
> >
> >
> > During kexec reboots, RTC alarms that are fired during the kernel
> > transition experience delayed execution. The new kernel would
> > eventually honor these alarms, but the interrupt handlers would only
> > execute after the driver probe is completed rather than at the intended alarm
> time.
> >
> > This is because pending alarm interrupt status from the previous
> > kernel is not properly cleared during driver initialization, causing
> > timing discrepancies in alarm delivery.
> >
> > To ensure precise alarm timing across kexec transitions, enhance the
> > probe function to:
> > 1. Clear any pending alarm interrupt status from previous boot.
> > 2. Detect existing valid alarms and preserve their state.
> > 3. Re-enable alarm interrupts for future alarms.
> >
> > Signed-off-by: Harini T <harini.t@amd.com>
> > ---
> > Changes in V2:
> > - Remove shutdown handler to prevent alarm interrupts from being
> > disabled during kexec transitions.
> > - Add alarm state detection and restoration in probe.
> >
> > V1 link: https://lore.kernel.org/linux-rtc/20250724170517.974356-1-
> > harini.t@amd.com/T/#u
> > ---
> > drivers/rtc/rtc-zynqmp.c | 19 +++++++++++++++++++
> > 1 file changed, 19 insertions(+)
> >
> > diff --git a/drivers/rtc/rtc-zynqmp.c b/drivers/rtc/rtc-zynqmp.c index
> > f39102b66eac..3baa2b481d9f 100644
> > --- a/drivers/rtc/rtc-zynqmp.c
> > +++ b/drivers/rtc/rtc-zynqmp.c
> > @@ -277,6 +277,10 @@ static irqreturn_t xlnx_rtc_interrupt(int irq,
> > void *id) static int xlnx_rtc_probe(struct platform_device *pdev) {
> > struct xlnx_rtc_dev *xrtcdev;
> > + bool is_alarm_set = false;
> > + u32 pending_alrm_irq;
> > + u32 current_time;
> > + u32 alarm_time;
> > int ret;
> >
> > xrtcdev = devm_kzalloc(&pdev->dev, sizeof(*xrtcdev),
> > GFP_KERNEL); @@
> > -296,6 +300,17 @@ static int xlnx_rtc_probe(struct platform_device *pdev)
> > if (IS_ERR(xrtcdev->reg_base))
> > return PTR_ERR(xrtcdev->reg_base);
> >
> > + /* Clear any pending alarm interrupts from previous kernel/boot */
> > + pending_alrm_irq = readl(xrtcdev->reg_base + RTC_INT_STS) &
> > RTC_INT_ALRM;
> > + if (pending_alrm_irq)
> > + writel(pending_alrm_irq, xrtcdev->reg_base +
> > + RTC_INT_STS);
> > +
> > + /* Check if a valid alarm is already set from previous kernel/boot */
> > + alarm_time = readl(xrtcdev->reg_base + RTC_ALRM);
> > + current_time = readl(xrtcdev->reg_base + RTC_CUR_TM);
> > + if (alarm_time > current_time && alarm_time != 0)
> > + is_alarm_set = true;
> > +
> > xrtcdev->alarm_irq = platform_get_irq_byname(pdev, "alarm");
> > if (xrtcdev->alarm_irq < 0)
> > return xrtcdev->alarm_irq; @@ -337,6 +352,10 @@ static
> > int xlnx_rtc_probe(struct platform_device *pdev)
> >
> > xlnx_init_rtc(xrtcdev);
> >
> > + /* Re-enable alarm interrupt if a valid alarm was found */
> > + if (is_alarm_set)
> > + writel(RTC_INT_ALRM, xrtcdev->reg_base + RTC_INT_EN);
> > +
> > device_init_wakeup(&pdev->dev, true);
> >
> > return devm_rtc_register_device(xrtcdev->rtc);
> > --
> > 2.43.0
> >
>
> Kindly following up on this patch. I would appreciate it if you could review it
> when convenient and let me know if any updates are needed.
>
> Thank you for your time.
>
> Best regards,
> Harini T
^ permalink raw reply
* Re: [PATCH v6 1/4] dt-bindings: rtc: Document NVIDIA VRS RTC
From: Shubhi Garg @ 2025-09-25 5:36 UTC (permalink / raw)
To: Jon Hunter, Rob Herring
Cc: Lee Jones, Krzysztof Kozlowski, Conor Dooley, Catalin Marinas,
Will Deacon, Alexandre Belloni, devicetree, linux-arm-kernel,
linux-rtc, linux-tegra
In-Reply-To: <a1d6955c-ac43-4cd3-bb7a-9b627aecc47c@nvidia.com>
On 23/09/25 1:38 am, Jon Hunter wrote:
>
> On 22/09/2025 20:53, Rob Herring wrote:
>> On Fri, Sep 19, 2025 at 01:59:50PM +0000, Shubhi Garg wrote:
>>> Add device tree bindings for NVIDIA VRS (Voltage Regulator
>>> Specification)
>>> RTC device. NVIDIA VRS is a Power Management IC (PMIC) that implements a
>>> power sequencing solution with I2C interface. The device includes RTC
>>> which provides functionality to get/set system time, retain system
>>> time across boot, wake system from suspend and shutdown state.
>>
>> I only see this patch. The threading of this is broken.
>
> Yep I see the same. I am not sure what happened here, but let me work
> with Shubhi to get this resent.
Yes, patches got sent individually so threading is broken.
I am fixing it and will send V7 version with more fixes.
--
Regards,
Shubhi
^ permalink raw reply
* [PATCH] dt-bindings: rtc: Convert apm,xgene-rtc to DT schema
From: Rob Herring (Arm) @ 2025-09-24 22:28 UTC (permalink / raw)
To: Alexandre Belloni, Krzysztof Kozlowski, Conor Dooley, Khuong Dinh
Cc: linux-rtc, devicetree, linux-kernel
Convert the APM XGene RTC binding to DT schema format. It's a
straight-forward conversion.
Signed-off-by: Rob Herring (Arm) <robh@kernel.org>
---
.../bindings/rtc/apm,xgene-rtc.yaml | 45 +++++++++++++++++++
.../devicetree/bindings/rtc/xgene-rtc.txt | 28 ------------
2 files changed, 45 insertions(+), 28 deletions(-)
create mode 100644 Documentation/devicetree/bindings/rtc/apm,xgene-rtc.yaml
delete mode 100644 Documentation/devicetree/bindings/rtc/xgene-rtc.txt
diff --git a/Documentation/devicetree/bindings/rtc/apm,xgene-rtc.yaml b/Documentation/devicetree/bindings/rtc/apm,xgene-rtc.yaml
new file mode 100644
index 000000000000..b8f46536fd5a
--- /dev/null
+++ b/Documentation/devicetree/bindings/rtc/apm,xgene-rtc.yaml
@@ -0,0 +1,45 @@
+# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/rtc/apm,xgene-rtc.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: APM X-Gene Real Time Clock
+
+maintainers:
+ - Khuong Dinh <khuong@os.amperecomputing.com>
+
+properties:
+ compatible:
+ const: apm,xgene-rtc
+
+ reg:
+ maxItems: 1
+
+ interrupts:
+ maxItems: 1
+
+ '#clock-cells':
+ const: 1
+
+ clocks:
+ maxItems: 1
+
+required:
+ - compatible
+ - reg
+ - interrupts
+ - '#clock-cells'
+ - clocks
+
+additionalProperties: false
+
+examples:
+ - |
+ rtc@10510000 {
+ compatible = "apm,xgene-rtc";
+ reg = <0x10510000 0x400>;
+ interrupts = <0x0 0x46 0x4>;
+ #clock-cells = <1>;
+ clocks = <&rtcclk 0>;
+ };
diff --git a/Documentation/devicetree/bindings/rtc/xgene-rtc.txt b/Documentation/devicetree/bindings/rtc/xgene-rtc.txt
deleted file mode 100644
index fd195c358446..000000000000
--- a/Documentation/devicetree/bindings/rtc/xgene-rtc.txt
+++ /dev/null
@@ -1,28 +0,0 @@
-* APM X-Gene Real Time Clock
-
-RTC controller for the APM X-Gene Real Time Clock
-
-Required properties:
-- compatible : Should be "apm,xgene-rtc"
-- reg: physical base address of the controller and length of memory mapped
- region.
-- interrupts: IRQ line for the RTC.
-- #clock-cells: Should be 1.
-- clocks: Reference to the clock entry.
-
-Example:
-
-rtcclk: rtcclk {
- compatible = "fixed-clock";
- #clock-cells = <1>;
- clock-frequency = <100000000>;
- clock-output-names = "rtcclk";
-};
-
-rtc: rtc@10510000 {
- compatible = "apm,xgene-rtc";
- reg = <0x0 0x10510000 0x0 0x400>;
- interrupts = <0x0 0x46 0x4>;
- #clock-cells = <1>;
- clocks = <&rtcclk 0>;
-};
--
2.51.0
^ permalink raw reply related
* Re: [PATCH v1 3/7] dt-bindings: clock: samsung,s2mps11: document the S2MPS16 compatible
From: Rob Herring (Arm) @ 2025-09-24 15:13 UTC (permalink / raw)
To: Ivaylo Ivanov
Cc: Conor Dooley, Alexandre Belloni, Alim Akhtar, Krzysztof Kozlowski,
Sylwester Nawrocki, Liam Girdwood, André Draszik,
linux-samsung-soc, Michael Turquette, linux-kernel, linux-rtc,
Stephen Boyd, Mark Brown, linux-clk, Chanwoo Choi, Lee Jones,
devicetree
In-Reply-To: <20250914124227.2619925-4-ivo.ivanov.ivanov1@gmail.com>
On Sun, 14 Sep 2025 15:42:23 +0300, Ivaylo Ivanov wrote:
> The S2MPS16 PMIC, alongside regulators and an rtc, provides 3 clock
> outputs, just like most of the other S2MPS PMICs. Document the S2MPS16
> clock compatible.
>
> Signed-off-by: Ivaylo Ivanov <ivo.ivanov.ivanov1@gmail.com>
> ---
> Documentation/devicetree/bindings/clock/samsung,s2mps11.yaml | 3 ++-
> 1 file changed, 2 insertions(+), 1 deletion(-)
>
Acked-by: Rob Herring (Arm) <robh@kernel.org>
^ permalink raw reply
* Re: [PATCH v1 2/7] dt-bindings: mfd: samsung,s2mps11: add compatible for s2mps16-pmic
From: Rob Herring (Arm) @ 2025-09-24 15:13 UTC (permalink / raw)
To: Ivaylo Ivanov
Cc: Sylwester Nawrocki, Chanwoo Choi, Lee Jones, Krzysztof Kozlowski,
Stephen Boyd, André Draszik, devicetree, Alexandre Belloni,
Conor Dooley, linux-samsung-soc, Alim Akhtar, linux-kernel,
Liam Girdwood, Mark Brown, linux-rtc, linux-clk,
Michael Turquette
In-Reply-To: <20250914124227.2619925-3-ivo.ivanov.ivanov1@gmail.com>
On Sun, 14 Sep 2025 15:42:22 +0300, Ivaylo Ivanov wrote:
> S2MPS16 is a PMIC present in Samsung's exynos8890 devices. It houses
> voltage regulators (38 LDOs and 11 BUCKs), an RTC and a clocks module.
> Add the compatible string "samsung,s2mps16-pmic" to the PMIC.
>
> Signed-off-by: Ivaylo Ivanov <ivo.ivanov.ivanov1@gmail.com>
> ---
> .../bindings/mfd/samsung,s2mps11.yaml | 17 +++++++++++++++--
> 1 file changed, 15 insertions(+), 2 deletions(-)
>
Reviewed-by: Rob Herring (Arm) <robh@kernel.org>
^ permalink raw reply
* Re: [PATCH v1 1/7] regulator: dt-bindings: add documentation for s2mps16-pmic regulators
From: Rob Herring @ 2025-09-24 15:12 UTC (permalink / raw)
To: Ivaylo Ivanov
Cc: Krzysztof Kozlowski, André Draszik, Sylwester Nawrocki,
Chanwoo Choi, Alim Akhtar, Michael Turquette, Stephen Boyd,
Conor Dooley, Lee Jones, Liam Girdwood, Mark Brown,
Alexandre Belloni, linux-samsung-soc, devicetree, linux-clk,
linux-rtc, linux-kernel
In-Reply-To: <20250914124227.2619925-2-ivo.ivanov.ivanov1@gmail.com>
On Sun, Sep 14, 2025 at 03:42:21PM +0300, Ivaylo Ivanov wrote:
> The S2MPS16 is a PMIC found in exynos8890 devices, which controls voltage
> regulators - 38 LDOs, of which 11 are used for CP, and 11 BUCKs, of which
> 1 is used for CP. Provide documentation for devicetree definitions,
> regulator naming patterns, etc.
Also, drop 'documentation for' in the subject.
>
> Signed-off-by: Ivaylo Ivanov <ivo.ivanov.ivanov1@gmail.com>
> ---
> .../bindings/regulator/samsung,s2mps16.yaml | 50 +++++++++++++++++++
> 1 file changed, 50 insertions(+)
> create mode 100644 Documentation/devicetree/bindings/regulator/samsung,s2mps16.yaml
>
> diff --git a/Documentation/devicetree/bindings/regulator/samsung,s2mps16.yaml b/Documentation/devicetree/bindings/regulator/samsung,s2mps16.yaml
> new file mode 100644
> index 000000000..ede87d3b9
> --- /dev/null
> +++ b/Documentation/devicetree/bindings/regulator/samsung,s2mps16.yaml
> @@ -0,0 +1,50 @@
> +# SPDX-License-Identifier: GPL-2.0-only OR BSD-2-Clause
> +%YAML 1.2
> +---
> +$id: http://devicetree.org/schemas/regulator/samsung,s2mps16.yaml#
> +$schema: http://devicetree.org/meta-schemas/core.yaml#
> +
> +title: Samsung S2MPS16 Power Management IC regulators
> +
> +maintainers:
> + - Ivaylo Ivanov <ivo.ivanov.ivanov1@gmail.com>
> +
> +description: |
> + This is a part of device tree bindings for S2M and S5M family of Power
> + Management IC (PMIC).
> +
> + The S2MPS16 provides buck and LDO regulators.
> +
> + See also Documentation/devicetree/bindings/mfd/samsung,s2mps11.yaml for
> + additional information and example.
> +
> +patternProperties:
> + # 27 LDOs
> + "^ldo([1-9]|1[0-3]|2[5-9]|3[0-8])$":
> + type: object
> + $ref: regulator.yaml#
> + unevaluatedProperties: false
> + description:
> + Properties for single LDO regulator.
> +
> + LDOs 14-24 are used for CP, and they're left unimplemented due to lack
> + of documentation on them.
> +
> + required:
> + - regulator-name
> +
> + # 10 bucks
> + "^buck([1-9]|1[0-1])$":
> + type: object
> + $ref: regulator.yaml#
> + unevaluatedProperties: false
> + description:
> + Properties for single BUCK regulator.
> +
> + BUCK 10 is used for CP, and it's left unimplemented due to lack of
> + documentation on it.
> +
> + required:
> + - regulator-name
> +
> +additionalProperties: false
> --
> 2.43.0
>
^ permalink raw reply
* Re: [PATCH v1 1/7] regulator: dt-bindings: add documentation for s2mps16-pmic regulators
From: Rob Herring @ 2025-09-24 15:11 UTC (permalink / raw)
To: Ivaylo Ivanov
Cc: Krzysztof Kozlowski, André Draszik, Sylwester Nawrocki,
Chanwoo Choi, Alim Akhtar, Michael Turquette, Stephen Boyd,
Conor Dooley, Lee Jones, Liam Girdwood, Mark Brown,
Alexandre Belloni, linux-samsung-soc, devicetree, linux-clk,
linux-rtc, linux-kernel
In-Reply-To: <20250914124227.2619925-2-ivo.ivanov.ivanov1@gmail.com>
On Sun, Sep 14, 2025 at 03:42:21PM +0300, Ivaylo Ivanov wrote:
> The S2MPS16 is a PMIC found in exynos8890 devices, which controls voltage
> regulators - 38 LDOs, of which 11 are used for CP, and 11 BUCKs, of which
> 1 is used for CP. Provide documentation for devicetree definitions,
> regulator naming patterns, etc.
>
> Signed-off-by: Ivaylo Ivanov <ivo.ivanov.ivanov1@gmail.com>
> ---
> .../bindings/regulator/samsung,s2mps16.yaml | 50 +++++++++++++++++++
> 1 file changed, 50 insertions(+)
> create mode 100644 Documentation/devicetree/bindings/regulator/samsung,s2mps16.yaml
>
> diff --git a/Documentation/devicetree/bindings/regulator/samsung,s2mps16.yaml b/Documentation/devicetree/bindings/regulator/samsung,s2mps16.yaml
> new file mode 100644
> index 000000000..ede87d3b9
> --- /dev/null
> +++ b/Documentation/devicetree/bindings/regulator/samsung,s2mps16.yaml
> @@ -0,0 +1,50 @@
> +# SPDX-License-Identifier: GPL-2.0-only OR BSD-2-Clause
> +%YAML 1.2
> +---
> +$id: http://devicetree.org/schemas/regulator/samsung,s2mps16.yaml#
> +$schema: http://devicetree.org/meta-schemas/core.yaml#
> +
> +title: Samsung S2MPS16 Power Management IC regulators
> +
> +maintainers:
> + - Ivaylo Ivanov <ivo.ivanov.ivanov1@gmail.com>
> +
> +description: |
> + This is a part of device tree bindings for S2M and S5M family of Power
> + Management IC (PMIC).
> +
> + The S2MPS16 provides buck and LDO regulators.
> +
> + See also Documentation/devicetree/bindings/mfd/samsung,s2mps11.yaml for
> + additional information and example.
> +
> +patternProperties:
> + # 27 LDOs
> + "^ldo([1-9]|1[0-3]|2[5-9]|3[0-8])$":
> + type: object
> + $ref: regulator.yaml#
> + unevaluatedProperties: false
> + description:
You need '>' modifier to preserve paragraphs.
> + Properties for single LDO regulator.
> +
> + LDOs 14-24 are used for CP, and they're left unimplemented due to lack
> + of documentation on them.
What does unimplemented mean? In some driver? If so, that's specific to
a driver and not relevant to the binding.
> +
> + required:
> + - regulator-name
> +
> + # 10 bucks
> + "^buck([1-9]|1[0-1])$":
> + type: object
> + $ref: regulator.yaml#
> + unevaluatedProperties: false
> + description:
> + Properties for single BUCK regulator.
> +
> + BUCK 10 is used for CP, and it's left unimplemented due to lack of
> + documentation on it.
> +
> + required:
> + - regulator-name
> +
> +additionalProperties: false
> --
> 2.43.0
>
^ permalink raw reply
* Re: [PATCH v4 1/2] dt-bindings: rtc: Add pcf85053 support
From: Conor Dooley @ 2025-09-23 18:57 UTC (permalink / raw)
To: Lakshay Piplani
Cc: alexandre.belloni, linux-rtc, linux-kernel, robh, krzk+dt,
conor+dt, devicetree, pankit.garg, vikash.bansal, priyanka.jain,
shashank.rebbapragada
In-Reply-To: <20250923113441.555284-1-lakshay.piplani@nxp.com>
[-- Attachment #1: Type: text/plain, Size: 5975 bytes --]
On Tue, Sep 23, 2025 at 05:04:40PM +0530, Lakshay Piplani wrote:
> Add device tree bindings for NXP PCF85053 RTC chip.
>
> Signed-off-by: Pankit Garg <pankit.garg@nxp.com>
> Signed-off-by: Lakshay Piplani <lakshay.piplani@nxp.com>
> ---
> V3 -> V4: Add dedicated nxp,pcf85053.yaml.
> Remove entry from trivial-rtc.yaml.
> V2 -> V3: Moved MAINTAINERS file changes to the driver patch
> V1 -> V2: Handled dt-bindings by trivial-rtc.yaml
>
> .../devicetree/bindings/rtc/nxp,pcf85053.yaml | 128 ++++++++++++++++++
> 1 file changed, 128 insertions(+)
> create mode 100644 Documentation/devicetree/bindings/rtc/nxp,pcf85053.yaml
>
> diff --git a/Documentation/devicetree/bindings/rtc/nxp,pcf85053.yaml b/Documentation/devicetree/bindings/rtc/nxp,pcf85053.yaml
> new file mode 100644
> index 000000000000..6b1c97358486
> --- /dev/null
> +++ b/Documentation/devicetree/bindings/rtc/nxp,pcf85053.yaml
> @@ -0,0 +1,128 @@
> +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
> +# Copyright 2025 NXP
> +%YAML 1.2
> +---
> +$id: http://devicetree.org/schemas/rtc/nxp,pcf85053.yaml#
> +$schema: http://devicetree.org/meta-schemas/core.yaml#
> +
> +title: NXP PCF85053 Real Time Clock
> +
> +maintainers:
> + - Pankit Garg <pankit.garg@nxp.com>
> + - Lakshay Piplani <lakshay.piplani@nxp.com>
> +
> +properties:
> + compatible:
> + enum:
> + - nxp,pcf85053
> +
> + reg:
> + maxItems: 1
> +
> + interrupts:
> + maxItems: 1
> +
> + nxp,interface:
> + $ref: /schemas/types.yaml#/definitions/string
> + enum: [ primary, secondary ]
> + description: |
> + Identifies this host's logical role in a multi-host topology for the
> + PCF85053 RTC. The device exposes a "TWO" ownership bit in the CTRL
> + register that gates which host may write time/alarm registers.
> + - "primary": Designated host that *may* claim write ownership (set
> + CTRL.TWO=1) **if** write-access is explicitly requested.
> + - "secondary": Peer host that writes only when CTRL.TWO=0 (default).
> +
> + nxp,write-access:
> + type: boolean
> + description: |
> + Request the driver to claim write ownership at probe time by setting
> + CTRL.TWO=1. This property is only valid when nxp,interface="primary".
> + The driver will not modify any other CTRL bits (HF/DM/etc.) and will not
> + clear any status/interrupt flags at probe.
> +
> +required:
> + - compatible
> + - reg
> + - nxp,interface
> +
> +additionalProperties: false
> +
> +# Schema constraints matching driver:
> +# 1) If nxp,write-access is present, nxp,interface must be "primary".
> +# Rationale: only the primary may claim ownership; driver will set TWO=1.
> +# 2) If nxp,interface is "secondary", nxp,write-access must not be present.
> +# Rationale: secondary never claims ownership and cannot write CTRL/ST/alarm.
> +#
> +# Practical effect:
> +# - Primary without 'nxp,write-access'; primary is read only; secondary may
> +# write time registers.
> +# - Primary with 'nxp,write-access'; primary owns writes, secondary is read only.
> +allOf:
> + - $ref: rtc.yaml#
> + - oneOf:
> + # Case 1: primary with write-access
> + - required: [ "nxp,write-access" ]
> + properties:
> + nxp,interface:
> + const: primary
> +
> + # Case 2: primary without write-access
> + - properties:
> + nxp,interface:
> + const: primary
> + not:
> + required: [ "nxp,write-access" ]
Aren't case 1 and case 2 here redundant? All you need to do is block
interface == secondary when nxp,write-access is present, which your case
3 should be able to be modified to do via
if:
properties:
nxp,interface:
const: secondary
then:
properties:
nxp,write-access: false
I think your description for nxp,write-access gets the point across
about when it can be used, and the additional commentary is not really
helpful.
> +
> + # Case 3: secondary (must not have write-access)
> + - properties:
> + nxp,interface:
> + const: secondary
> + not:
> + required: [ "nxp,write-access" ]
> +
> +examples:
> + # Single host example.
> + - |
> + #include <dt-bindings/interrupt-controller/irq.h>
> + i2c {
> + #address-cells = <1>;
> + #size-cells = <0>;
> +
> + rtc@6f {
> + compatible = "nxp,pcf85053";
> + reg = <0x6f>;
> + nxp,interface = "primary";
> + nxp,write-access;
> + interrupt-parent = <&gpio2>;
> + interrupts = <3 IRQ_TYPE_EDGE_FALLING>;
> + };
> + };
> +
> + # Dual-host example: one primary that claims writes; one secondary that never claims writes.
> + - |
> + #include <dt-bindings/interrupt-controller/irq.h>
> + i2c0 {
> + #address-cells = <1>;
> + #size-cells = <0>;
> +
> + rtc@6f {
> + compatible = "nxp,pcf85053";
> + reg = <0x6f>;
> + nxp,interface = "primary";
> + nxp,write-access;
> + interrupt-parent = <&gpio2>;
> + interrupts = <3 IRQ_TYPE_EDGE_FALLING>;
> + };
> + };
> +
> + i2c1 {
> + #address-cells = <1>;
> + #size-cells = <0>;
> +
> + rtc@6f {
> + compatible = "nxp,pcf85053";
> + reg = <0x6f>;
> + nxp,interface = "secondary";
Maybe a silly question, but if you have a system that wants to have two
pairs of RTCs, how would you determine which primary a secondary belongs
to? I notice you have no link between these devices in dt so I am
curious. Would it be better to eschew nxp,interface and have a phandle
from the secondary to the primary?
I don't know anything about your use case or features, so maybe knowing
the relationship just is not relevant at all, or it can be determined at
runtime.
Cheers,
Conor.
[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 228 bytes --]
^ permalink raw reply
* Re: [PATCH v6 3/4] rtc: nvvrs: add NVIDIA VRS RTC device driver
From: Alexandre Belloni @ 2025-09-23 15:40 UTC (permalink / raw)
To: Shubhi Garg
Cc: Lee Jones, Rob Herring, Krzysztof Kozlowski, Conor Dooley,
Catalin Marinas, Will Deacon, Jonathan Hunter, devicetree,
linux-arm-kernel, linux-rtc, linux-tegra
In-Reply-To: <20250919140229.10546-1-shgarg@nvidia.com>
On 19/09/2025 14:02:29+0000, Shubhi Garg wrote:
> +static int nvvrs_rtc_enable_alarm(struct nvvrs_rtc_info *info)
> +{
> + int ret;
> +
> + /* Set RTC_WAKE bit for autonomous wake from sleep */
> + ret = nvvrs_update_bits(info, NVVRS_REG_CTL_2, NVVRS_REG_CTL_2_RTC_WAKE,
> + NVVRS_REG_CTL_2_RTC_WAKE);
> + if (ret < 0) {
> + dev_err(info->dev, "Failed to set RTC_WAKE bit (%d)\n", ret);
This should be either a dev_dbg or removed
> + return ret;
> + }
> +
> + /* Set RTC_PU bit for autonomous wake from shutdown */
> + ret = nvvrs_update_bits(info, NVVRS_REG_CTL_2, NVVRS_REG_CTL_2_RTC_PU,
> + NVVRS_REG_CTL_2_RTC_PU);
> + if (ret < 0) {
> + dev_err(info->dev, "Failed to set RTC_PU bit (%d)\n", ret);
Ditto
> + return ret;
> + }
> +
> + return 0;
> +}
> +
> +static int nvvrs_rtc_disable_alarm(struct nvvrs_rtc_info *info)
> +{
> + struct i2c_client *client = info->client;
> + u8 val[4];
> + int ret;
> +
> + /* Clear RTC_WAKE bit */
> + ret = nvvrs_update_bits(info, NVVRS_REG_CTL_2, NVVRS_REG_CTL_2_RTC_WAKE,
> + 0);
> + if (ret < 0) {
> + dev_err(info->dev, "Failed to clear RTC_WAKE bit (%d)\n", ret);
Ditto
> + return ret;
> + }
> +
> + /* Clear RTC_PU bit */
> + ret = nvvrs_update_bits(info, NVVRS_REG_CTL_2, NVVRS_REG_CTL_2_RTC_PU,
> + 0);
> + if (ret < 0) {
> + dev_err(info->dev, "Failed to clear RTC_PU bit (%d)\n", ret);
Ditto
> + return ret;
> + }
> +
> + /* Write ALARM_RESET_VAL in RTC Alarm register to disable alarm */
> + val[0] = 0xff;
> + val[1] = 0xff;
> + val[2] = 0xff;
> + val[3] = 0xff;
> +
> + ret = nvvrs_rtc_write_alarm(client, val);
> + if (ret < 0)
> + dev_err(info->dev, "Failed to disable Alarm (%d)\n", ret);
Ditto
> +
> + return 0;
Plus it fails but then returns 0
> +}
> +
> +static int nvvrs_rtc_read_time(struct device *dev, struct rtc_time *tm)
> +{
> + struct nvvrs_rtc_info *info = dev_get_drvdata(dev);
> + time64_t secs = 0;
> + int ret;
> + u8 val;
> +
> + mutex_lock(&info->lock);
This lock is unnecessary once you use rtc_lock/rtc_unlock in the IRQ
handler.
> +
> + /*
> + * Multi-byte transfers are not supported with PEC enabled
> + * Read MSB first to avoid coherency issues
> + */
> + ret = i2c_smbus_read_byte_data(info->client, NVVRS_REG_RTC_T3);
> + if (ret < 0)
> + goto out;
> +
> + val = (u8)ret;
> + secs |= (time64_t)val << 24;
> +
> + ret = i2c_smbus_read_byte_data(info->client, NVVRS_REG_RTC_T2);
> + if (ret < 0)
> + goto out;
> +
> + val = (u8)ret;
> + secs |= (time64_t)val << 16;
> +
> + ret = i2c_smbus_read_byte_data(info->client, NVVRS_REG_RTC_T1);
> + if (ret < 0)
> + goto out;
> +
> + val = (u8)ret;
> + secs |= (time64_t)val << 8;
> +
> + ret = i2c_smbus_read_byte_data(info->client, NVVRS_REG_RTC_T0);
> + if (ret < 0)
> + goto out;
> +
> + val = (u8)ret;
> + secs |= val;
> +
> + rtc_time64_to_tm(secs, tm);
> + ret = 0;
> +out:
> + mutex_unlock(&info->lock);
> + return ret;
> +}
> +
> +static int nvvrs_rtc_set_time(struct device *dev, struct rtc_time *tm)
> +{
> + struct nvvrs_rtc_info *info = dev_get_drvdata(dev);
> + time64_t secs;
> + u8 time[4];
> + int ret;
> +
> + mutex_lock(&info->lock);
Ditto
> +
> + secs = rtc_tm_to_time64(tm);
> + time[0] = secs & 0xff;
> + time[1] = (secs >> 8) & 0xff;
> + time[2] = (secs >> 16) & 0xff;
> + time[3] = (secs >> 24) & 0xff;
> +
> + ret = i2c_smbus_write_byte_data(info->client, NVVRS_REG_RTC_T3, time[3]);
> + if (ret < 0)
> + goto out;
> +
> + ret = i2c_smbus_write_byte_data(info->client, NVVRS_REG_RTC_T2, time[2]);
> + if (ret < 0)
> + goto out;
> +
> + ret = i2c_smbus_write_byte_data(info->client, NVVRS_REG_RTC_T1, time[1]);
> + if (ret < 0)
> + goto out;
> +
> + ret = i2c_smbus_write_byte_data(info->client, NVVRS_REG_RTC_T0, time[0]);
> +out:
> + mutex_unlock(&info->lock);
> + return ret;
> +}
> +
> +static int nvvrs_rtc_read_alarm(struct device *dev, struct rtc_wkalrm *alrm)
> +{
> + struct nvvrs_rtc_info *info = dev_get_drvdata(dev);
> + time64_t alarm_val = 0;
> + int ret;
> + u8 val;
> +
> + mutex_lock(&info->lock);
Ditto
> +
> + /* Multi-byte transfers are not supported with PEC enabled */
> + ret = i2c_smbus_read_byte_data(info->client, NVVRS_REG_RTC_A3);
> + if (ret < 0)
> + goto out;
> +
> + val = (u8)ret;
> + alarm_val |= (time64_t)val << 24;
> +
> + ret = i2c_smbus_read_byte_data(info->client, NVVRS_REG_RTC_A2);
> + if (ret < 0)
> + goto out;
> +
> + val = (u8)ret;
> + alarm_val |= (time64_t)val << 16;
> +
> + ret = i2c_smbus_read_byte_data(info->client, NVVRS_REG_RTC_A1);
> + if (ret < 0)
> + goto out;
> +
> + val = (u8)ret;
> + alarm_val |= (time64_t)val << 8;
> +
> + ret = i2c_smbus_read_byte_data(info->client, NVVRS_REG_RTC_A0);
> + if (ret < 0)
> + goto out;
> +
> + val = (u8)ret;
> + alarm_val |= val;
> +
> + if (alarm_val == ALARM_RESET_VAL)
> + alrm->enabled = 0;
> + else
> + alrm->enabled = 1;
> +
> + rtc_time64_to_tm(alarm_val, &alrm->time);
> + ret = 0;
> +out:
> + mutex_unlock(&info->lock);
> + return ret;
> +}
> +
> +static int nvvrs_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alrm)
> +{
> + struct nvvrs_rtc_info *info = dev_get_drvdata(dev);
> + time64_t secs;
> + u8 time[4];
> + int ret;
> +
> + mutex_lock(&info->lock);
> +
Ditto
> + if (!alrm->enabled) {
> + ret = nvvrs_rtc_disable_alarm(info);
> + if (ret < 0)
> + goto out;
> + }
> +
> + ret = nvvrs_rtc_enable_alarm(info);
> + if (ret < 0)
> + goto out;
> +
> + secs = rtc_tm_to_time64(&alrm->time);
> + time[0] = secs & 0xff;
> + time[1] = (secs >> 8) & 0xff;
> + time[2] = (secs >> 16) & 0xff;
> + time[3] = (secs >> 24) & 0xff;
> +
> + ret = nvvrs_rtc_write_alarm(info->client, time);
> +
> +out:
> + mutex_unlock(&info->lock);
> + return ret;
> +}
> +
> +static int nvvrs_pseq_irq_clear(struct nvvrs_rtc_info *info)
> +{
> + unsigned int i;
> + int ret;
> +
> + for (i = 0; i < NVVRS_IRQ_REG_COUNT; i++) {
> + ret = i2c_smbus_read_byte_data(info->client,
> + NVVRS_REG_INT_SRC1 + i);
> + if (ret < 0) {
> + dev_err(info->dev, "Failed to read INT_SRC%d : %d\n",
> + i + 1, ret);
> + return ret;
> + }
> +
> + ret = i2c_smbus_write_byte_data(info->client,
> + NVVRS_REG_INT_SRC1 + i,
> + (u8)ret);
> + if (ret < 0) {
> + dev_err(info->dev, "Failed to clear INT_SRC%d : %d\n",
> + i + 1, ret);
> + return ret;
> + }
> + }
> +
> + return 0;
> +}
> +
> +static irqreturn_t nvvrs_rtc_irq_handler(int irq, void *data)
> +{
> + struct nvvrs_rtc_info *info = data;
> + int ret;
> +
> + /* Check for RTC alarm interrupt */
> + ret = i2c_smbus_read_byte_data(info->client, NVVRS_REG_INT_SRC1);
> + if (ret < 0) {
> + dev_err(info->dev, "Failed to read INT_SRC1: %d\n", ret);
dev_dbg or remove
> + return IRQ_NONE;
> + }
> +
> + if (ret & NVVRS_INT_SRC1_RTC_MASK) {
> + rtc_lock(info->rtc);
> + rtc_update_irq(info->rtc, 1, RTC_IRQF | RTC_AF);
> + rtc_unlock(info->rtc);
> + }
> +
> + /* Clear all interrupts */
> + if (nvvrs_pseq_irq_clear(info) < 0)
> + return IRQ_NONE;
> +
> + return IRQ_HANDLED;
> +}
> +
> diff --git a/include/linux/rtc/rtc-nvidia-vrs10.h b/include/linux/rtc/rtc-nvidia-vrs10.h
> new file mode 100644
> index 000000000000..3c9c46abf555
> --- /dev/null
> +++ b/include/linux/rtc/rtc-nvidia-vrs10.h
Just to be sure, do you expect to use this include in another driver?
Else you should merge it back in the c file.
--
Alexandre Belloni, co-owner and COO, Bootlin
Embedded Linux and Kernel engineering
https://bootlin.com
^ permalink raw reply
* [PATCH v4 2/2] rtc: Add NXP PCF85053 driver support
From: Lakshay Piplani @ 2025-09-23 11:34 UTC (permalink / raw)
To: alexandre.belloni, linux-rtc, linux-kernel, robh, krzk+dt,
conor+dt, devicetree
Cc: pankit.garg, vikash.bansal, priyanka.jain, shashank.rebbapragada,
Lakshay Piplani, Daniel Aguirre
In-Reply-To: <20250923113441.555284-1-lakshay.piplani@nxp.com>
PCF85053 is i2c based RTC which supports timer and calendar
functionality.
Features supported:
1. Read/Write time
2. Get/Set Alarm
3. Wakeup Source
4. Generate up to 32768Hz clock output
5. Primary/Secondary i2c bus
Signed-off-by: Daniel Aguirre <daniel.aguirre@nxp.com>
Signed-off-by: Pankit Garg <pankit.garg@nxp.com>
Signed-off-by: Lakshay Piplani <lakshay.piplani@nxp.com>
---
V3 -> V4: - Handle multi-host ownership explicitly using primary/secondary bus hadling.
- Probe no longer changes any CTRL bits unconditionally and do not clear ST/AF/OF
avoiding lost interrupts or silent mode changes.
- Read/Set time & alarm now respect HF(12/24h) and DM(BCD/BIN) converting
hour fields correctly for all combinations.
- Minor changes: drop noisy warnings, tidy error paths/comments.
V2 -> V3: Add MAINTAINERS file changes to this patch
V1 -> V2: no changes
MAINTAINERS | 7 +
drivers/rtc/Kconfig | 10 +
drivers/rtc/Makefile | 1 +
drivers/rtc/rtc-pcf85053.c | 734 +++++++++++++++++++++++++++++++++++++
4 files changed, 752 insertions(+)
create mode 100644 drivers/rtc/rtc-pcf85053.c
diff --git a/MAINTAINERS b/MAINTAINERS
index 6bbe4b4f8ec0..b835c2787e63 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -18352,6 +18352,13 @@ S: Maintained
F: Documentation/devicetree/bindings/sound/nxp,tfa989x.yaml
F: sound/soc/codecs/tfa989x.c
+NXP RTC PCF85053 DRIVER
+M: Pankit Gargi <pankit.garg@nxp.com>
+M: Lakshay Piplani <lakshay.piplani@nxp.com>
+L: linux-kernel@vger.kernel.org
+S: Maintained
+F: drivers/rtc/rtc-pcf85053.c
+
NZXT-KRAKEN2 HARDWARE MONITORING DRIVER
M: Jonas Malaco <jonas@protocubo.io>
L: linux-hwmon@vger.kernel.org
diff --git a/drivers/rtc/Kconfig b/drivers/rtc/Kconfig
index 64f6e9756aff..59ef0b6a53a7 100644
--- a/drivers/rtc/Kconfig
+++ b/drivers/rtc/Kconfig
@@ -974,6 +974,16 @@ config RTC_DRV_PCF85063
This driver can also be built as a module. If so, the module
will be called rtc-pcf85063.
+config RTC_DRV_PCF85053
+ tristate "NXP PCF85053"
+ depends on OF
+ help
+ If you say yes here you get support for the NXP PCF85053 I2C Bootable CPU RTC
+ chip.
+
+ This driver can also be built as a module. If so, the module
+ will be called rtc-pcf85053.
+
config RTC_DRV_RV3029C2
tristate "Micro Crystal RV3029/3049"
depends on RTC_I2C_AND_SPI
diff --git a/drivers/rtc/Makefile b/drivers/rtc/Makefile
index 789bddfea99d..7b2f379d10a9 100644
--- a/drivers/rtc/Makefile
+++ b/drivers/rtc/Makefile
@@ -128,6 +128,7 @@ obj-$(CONFIG_RTC_DRV_PCAP) += rtc-pcap.o
obj-$(CONFIG_RTC_DRV_PCF2123) += rtc-pcf2123.o
obj-$(CONFIG_RTC_DRV_PCF2127) += rtc-pcf2127.o
obj-$(CONFIG_RTC_DRV_PCF85063) += rtc-pcf85063.o
+obj-$(CONFIG_RTC_DRV_PCF85053) += rtc-pcf85053.o
obj-$(CONFIG_RTC_DRV_PCF8523) += rtc-pcf8523.o
obj-$(CONFIG_RTC_DRV_PCF85363) += rtc-pcf85363.o
obj-$(CONFIG_RTC_DRV_PCF8563) += rtc-pcf8563.o
diff --git a/drivers/rtc/rtc-pcf85053.c b/drivers/rtc/rtc-pcf85053.c
new file mode 100644
index 000000000000..4eec1a661b6b
--- /dev/null
+++ b/drivers/rtc/rtc-pcf85053.c
@@ -0,0 +1,734 @@
+// SPDX-License-Identifier: GPL-2.0
+// Copyright 2025 NXP
+
+#include <linux/bcd.h>
+#include <linux/clk-provider.h>
+#include <linux/err.h>
+#include <linux/i2c.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/rtc.h>
+#include <linux/slab.h>
+#include <linux/pm_wakeirq.h>
+#include <linux/regmap.h>
+
+#define PCF85053_REG_SC 0x00 /* seconds */
+#define PCF85053_REG_SCA 0x01 /* alarm */
+#define PCF85053_REG_MN 0x02 /* minutes */
+#define PCF85053_REG_MNA 0x03 /* alarm */
+#define PCF85053_REG_HR 0x04 /* hour */
+#define PCF85053_REG_HRA 0x05 /* alarm */
+#define PCF85053_REG_DW 0x06 /* day of week */
+#define PCF85053_REG_DM 0x07 /* day of month */
+#define PCF85053_REG_MO 0x08 /* month */
+#define PCF85053_REG_YR 0x09 /* year */
+#define PCF85053_REG_CTRL 0x0A /* timer control */
+#define PCF85053_REG_ST 0x0B /* status */
+#define PCF85053_REG_CLKO 0x0C /* clock out */
+#define PCF85053_REG_ACC 0x14 /* xclk access */
+
+#define PCF85053_BIT_AF BIT(7)
+#define PCF85053_BIT_ST BIT(7)
+#define PCF85053_BIT_DM BIT(6)
+#define PCF85053_BIT_HF BIT(5)
+#define PCF85053_BIT_DSM BIT(4)
+#define PCF85053_BIT_AIE BIT(3)
+#define PCF85053_BIT_OFIE BIT(2)
+#define PCF85053_BIT_CIE BIT(1)
+#define PCF85053_BIT_TWO BIT(0)
+#define PCF85053_BIT_XCLK BIT(7)
+
+#define PCF85053_REG_BAT_MASK 0x07 /* Battery mask */
+#define PCF85053A_BVL_MASK 0x07
+#define PCF85053A_BVL_LOW_THRESHOLD 0x02
+#define PCF85053_REG_CLKO_F_MASK 0x03 /* Frequenc mask */
+#define PCF85053_REG_CLKO_CKE 0x80 /* clock out enabled */
+#define PCF85053_BIT_OF BIT(6)
+
+#define PCF85053_HR_PM BIT(7)
+#define PCF85053_HR_24H_MASK GENMASK(5, 0)
+
+struct pcf85053_config {
+ const struct regmap_config regmap;
+ unsigned has_alarms:1;
+};
+
+struct pcf85053 {
+ struct rtc_device *rtc;
+ struct i2c_client *client;
+ struct regmap *regmap;
+#ifdef CONFIG_COMMON_CLK
+ struct clk_hw clkout_hw;
+#endif
+ bool is_primary;
+};
+
+static inline int pcf85053_read_two_bit(struct pcf85053 *pcf85053, bool *two)
+{
+ unsigned int ctrl;
+ int err;
+
+ err = regmap_read(pcf85053->regmap, PCF85053_REG_CTRL, &ctrl);
+ if (err)
+ return err;
+
+ *two = !!(ctrl & PCF85053_BIT_TWO);
+
+ return 0;
+}
+
+static inline bool pcf85053_time_write_access(struct pcf85053 *pcf85053)
+{
+ bool two;
+
+ if (pcf85053_read_two_bit(pcf85053, &two))
+ return false;
+
+ /* Primary writes iff TWO=1; secondary writes iff TWO=0 */
+ return pcf85053->is_primary ? two : !two;
+}
+
+static int pcf85053_set_alarm_mode(struct device *dev, bool on)
+{
+ struct pcf85053 *pcf85053 = dev_get_drvdata(dev);
+ unsigned int val;
+ int err;
+
+ val = on ? PCF85053_BIT_AIE : 0;
+ val &= ~(PCF85053_BIT_CIE | PCF85053_BIT_OFIE);
+
+ err = regmap_update_bits(pcf85053->regmap, PCF85053_REG_CTRL,
+ PCF85053_BIT_AIE | PCF85053_BIT_CIE | PCF85053_BIT_OFIE,
+ val);
+ if (err)
+ return err;
+
+ return regmap_update_bits(pcf85053->regmap, PCF85053_REG_ST,
+ PCF85053_BIT_AF, 0);
+}
+
+static int pcf85053_get_alarm_mode(struct device *dev,
+ unsigned char *alarm_enable, unsigned char *alarm_flag)
+{
+ struct pcf85053 *pcf85053 = dev_get_drvdata(dev);
+ unsigned int val;
+ int err;
+
+ if (alarm_enable) {
+ err = regmap_read(pcf85053->regmap, PCF85053_REG_CTRL, &val);
+ if (err)
+ return err;
+
+ *alarm_enable = val & PCF85053_BIT_AIE;
+ }
+
+ if (alarm_flag) {
+ err = regmap_read(pcf85053->regmap, PCF85053_REG_ST, &val);
+ if (err)
+ return err;
+
+ *alarm_flag = val & PCF85053_BIT_AF;
+ }
+
+ return 0;
+}
+
+static irqreturn_t pcf85053_irq(int irq, void *dev_id)
+{
+ struct pcf85053 *pcf85053 = i2c_get_clientdata(dev_id);
+ unsigned char alarm_flag;
+ unsigned char alarm_enable;
+ int err;
+
+ err = pcf85053_get_alarm_mode(&pcf85053->client->dev, &alarm_enable, &alarm_flag);
+ if (err)
+ return IRQ_NONE;
+
+ if (!alarm_flag)
+ return IRQ_NONE;
+
+ rtc_update_irq(pcf85053->rtc, 1, RTC_IRQF | RTC_AF);
+ pcf85053_set_alarm_mode(&pcf85053->client->dev, false);
+
+ return IRQ_HANDLED;
+}
+
+/*
+ * In the routines that deal directly with the PCF85053 hardware, we use
+ * rtc_time -- month 0-11, hour 0-23, yr = calendar year-epoch.
+ */
+static int pcf85053_rtc_read_time(struct device *dev, struct rtc_time *tm)
+{
+ struct pcf85053 *pcf85053 = dev_get_drvdata(dev);
+ unsigned int ctrl, st, h12;
+ bool is_24h, is_bin;
+ u8 regs[10], hr;
+ int err;
+
+ err = regmap_read(pcf85053->regmap, PCF85053_REG_CTRL, &ctrl);
+ if (err)
+ return err;
+
+ err = regmap_read(pcf85053->regmap, PCF85053_REG_ST, &st);
+ if (err)
+ return err;
+
+ if (ctrl & PCF85053_BIT_ST)
+ dev_warn(dev, "RTC is stopped; time may be invalid\n");
+
+ err = regmap_bulk_read(pcf85053->regmap, PCF85053_REG_SC, regs, sizeof(regs));
+ if (err)
+ return err;
+
+ if (ctrl & PCF85053_BIT_DM) {
+ tm->tm_sec = regs[PCF85053_REG_SC] & 0x7F;
+ tm->tm_min = regs[PCF85053_REG_MN] & 0x7F;
+ tm->tm_mday = regs[PCF85053_REG_DM] & 0x3F;
+ tm->tm_mon = (regs[PCF85053_REG_MO] & 0x1F) - 1;
+ tm->tm_year = regs[PCF85053_REG_YR] + 100;
+ } else {
+ tm->tm_sec = bcd2bin(regs[PCF85053_REG_SC] & 0x7F);
+ tm->tm_min = bcd2bin(regs[PCF85053_REG_MN] & 0x7F);
+ tm->tm_mday = bcd2bin(regs[PCF85053_REG_DM] & 0x3F);
+ tm->tm_mon = bcd2bin(regs[PCF85053_REG_MO] & 0x1F) - 1;
+ tm->tm_year = bcd2bin(regs[PCF85053_REG_YR]) + 100;
+ }
+ tm->tm_wday = regs[PCF85053_REG_DW] & 0x07;
+
+ hr = regs[PCF85053_REG_HR];
+ is_24h = ctrl & PCF85053_BIT_HF;
+ is_bin = ctrl & PCF85053_BIT_DM;
+
+ if (is_24h) {
+ tm->tm_hour = is_bin
+ ? (hr & PCF85053_HR_24H_MASK)
+ : bcd2bin(hr & PCF85053_HR_24H_MASK);
+ } else {
+ if (is_bin) {
+ h12 = hr & PCF85053_HR_24H_MASK;
+ } else {
+ h12 = is_bin ? (hr & PCF85053_HR_24H_MASK) :
+ bcd2bin(hr & PCF85053_HR_24H_MASK);
+
+ tm->tm_hour = (h12 == 12) ? ((hr & PCF85053_HR_PM) ? 12 : 0) :
+ ((hr & PCF85053_HR_PM) ? h12 + 12 : h12);
+ }
+ }
+
+ return 0;
+}
+
+static int pcf85053_rtc_set_time(struct device *dev, struct rtc_time *tm)
+
+{
+ struct pcf85053 *pcf85053 = dev_get_drvdata(dev);
+ unsigned int ctrl, h12;
+ int err, ret;
+ u8 buf[10];
+ bool pm;
+
+ /*
+ * By default, secondary have write access to time registers as TWO
+ * bit is 0 by default, if we set nxp,interface = "primary" and the
+ * nxp,write-access in device tree, then TWO bits gets set and primary
+ * gets write access to time registers.
+ */
+ if (!pcf85053_time_write_access(pcf85053))
+ return -EACCES;
+
+ err = regmap_read(pcf85053->regmap, PCF85053_REG_CTRL, &ctrl);
+ if (err)
+ return err;
+
+ buf[0] = tm->tm_sec & 0x7F;
+ buf[1] = 0;
+ buf[2] = tm->tm_min & 0x7F;
+ buf[3] = 0;
+ buf[5] = 0;
+ buf[6] = tm->tm_wday & 0x07;
+ buf[7] = tm->tm_mday & 0x3F;
+ buf[8] = (tm->tm_mon + 1) & 0x1F;
+ buf[9] = (tm->tm_year - 100) & 0xFF;
+
+ if (ctrl & PCF85053_BIT_HF) {
+ buf[4] = tm->tm_hour & PCF85053_HR_24H_MASK;
+ } else {
+ pm = tm->tm_hour >= 12;
+ h12 = (tm->tm_hour % 12) ? (tm->tm_hour % 12) : 12;
+ buf[4] = (h12 & PCF85053_HR_24H_MASK) | (pm << 7);
+ }
+
+ if (!(ctrl & PCF85053_BIT_DM)) {
+ buf[0] = bin2bcd(buf[0]);
+ buf[2] = bin2bcd(buf[2]);
+ buf[4] = bin2bcd(buf[4] & PCF85053_HR_24H_MASK) | (buf[4] & PCF85053_HR_PM);
+ buf[7] = bin2bcd(buf[7]);
+ buf[8] = bin2bcd(buf[8]);
+ buf[9] = bin2bcd(buf[9]);
+ }
+
+ if (pcf85053->is_primary) {
+ err = regmap_update_bits(pcf85053->regmap, PCF85053_REG_CTRL,
+ PCF85053_BIT_ST, PCF85053_BIT_ST);
+ if (err)
+ return err;
+
+ ret = regmap_bulk_write(pcf85053->regmap, PCF85053_REG_SC, buf, sizeof(buf));
+ err = regmap_update_bits(pcf85053->regmap, PCF85053_REG_CTRL,
+ PCF85053_BIT_ST, 0);
+ return ret ? ret : err;
+ }
+
+ return regmap_bulk_write(pcf85053->regmap, PCF85053_REG_SC, buf, sizeof(buf));
+}
+
+static int pcf85053_rtc_read_alarm(struct device *dev, struct rtc_wkalrm *tm)
+{
+ struct pcf85053 *pcf85053 = dev_get_drvdata(dev);
+ unsigned int ctrl, h12;
+ bool is_24h, is_bin, pm;
+ u8 buf[5];
+ u8 hr;
+ int err;
+
+ err = regmap_read(pcf85053->regmap, PCF85053_REG_CTRL, &ctrl);
+ if (err)
+ return err;
+
+ err = regmap_bulk_read(pcf85053->regmap, PCF85053_REG_SCA, buf, sizeof(buf));
+ if (err)
+ return err;
+
+ if (ctrl & PCF85053_BIT_DM) {
+ tm->time.tm_sec = buf[0] & 0x7F; /* SCA */
+ tm->time.tm_min = buf[2] & 0x7F; /* MNA */
+ } else {
+ tm->time.tm_sec = bcd2bin(buf[0] & 0x7F);
+ tm->time.tm_min = bcd2bin(buf[2] & 0x7F);
+ }
+
+ hr = buf[4];
+ is_24h = !!(ctrl & PCF85053_BIT_HF);
+ is_bin = !!(ctrl & PCF85053_BIT_DM);
+
+ if (is_24h) {
+ tm->time.tm_hour = is_bin
+ ? (hr & PCF85053_HR_24H_MASK)
+ : bcd2bin(hr & PCF85053_HR_24H_MASK);
+ } else {
+ pm = !!(hr & PCF85053_HR_PM);
+
+ if (is_bin)
+ h12 = (hr & PCF85053_HR_24H_MASK);
+ else
+ h12 = (bcd2bin(hr & PCF85053_HR_24H_MASK));
+
+ if (h12 == 12)
+ h12 = 0;
+ tm->time.tm_hour = pm ? (h12 + 12) : h12;
+ }
+
+ return pcf85053_get_alarm_mode(dev, &tm->enabled, &tm->pending);
+}
+
+static int pcf85053_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *tm)
+{
+ struct pcf85053 *pcf85053 = dev_get_drvdata(dev);
+ bool is_24h, is_bin, pm;
+ unsigned int ctrl, h12;
+ u8 sec, min, hra;
+ int err;
+
+ /*
+ * Only primary can set alarm, as secondary have read only access
+ * to alarm, control and status registers
+ */
+ if (!pcf85053->is_primary)
+ return -EACCES;
+
+ err = regmap_read(pcf85053->regmap, PCF85053_REG_CTRL, &ctrl);
+ if (err)
+ return err;
+
+ err = regmap_update_bits(pcf85053->regmap, PCF85053_REG_ST,
+ PCF85053_BIT_AF, 0);
+ if (err)
+ return err;
+
+ is_24h = !!(ctrl & PCF85053_BIT_HF);
+ is_bin = !!(ctrl & PCF85053_BIT_DM);
+
+ sec = tm->time.tm_sec & 0x7F;
+ min = tm->time.tm_min & 0x7F;
+
+ if (is_24h) {
+ hra = tm->time.tm_hour & PCF85053_HR_24H_MASK;
+ if (!is_bin)
+ hra = bin2bcd(hra) & PCF85053_HR_24H_MASK;
+ } else {
+ h12 = tm->time.tm_hour % 12;
+ pm = tm->time.tm_hour >= 12;
+ if (h12 == 0)
+ h12 = 12;
+
+ if (is_bin)
+ hra = (h12 & PCF85053_HR_24H_MASK) | (pm << 7);
+ else
+ hra = (bin2bcd(h12) & PCF85053_HR_24H_MASK) | (pm << 7);
+ }
+
+ if (!is_bin) {
+ sec = bin2bcd(sec);
+ min = bin2bcd(min);
+ }
+
+ err = regmap_write(pcf85053->regmap, PCF85053_REG_SCA, sec);
+ if (err)
+ return err;
+
+ err = regmap_write(pcf85053->regmap, PCF85053_REG_MNA, min);
+ if (err)
+ return err;
+
+ err = regmap_write(pcf85053->regmap, PCF85053_REG_HRA, hra);
+ if (err)
+ return err;
+
+ return pcf85053_set_alarm_mode(dev, tm->enabled);
+}
+
+static int pcf85053_irq_enable(struct device *dev, unsigned int enabled)
+{
+ dev_dbg(dev, "%s: alarm enable=%d\n", __func__, enabled);
+
+ return pcf85053_set_alarm_mode(dev, enabled);
+}
+
+static int pcf85053_ioctl(struct device *dev, unsigned int cmd, unsigned long arg)
+{
+ struct pcf85053 *pcf85053 = dev_get_drvdata(dev);
+ unsigned int val = 0, vl_status = 0;
+ unsigned int bvl;
+ int status;
+
+ switch (cmd) {
+ case RTC_VL_READ:
+ status = regmap_read(pcf85053->regmap, PCF85053_REG_ST, &val);
+ if (status)
+ return status;
+
+ if (val & PCF85053_BIT_OF)
+ vl_status |= RTC_VL_DATA_INVALID;
+
+ bvl = val & PCF85053A_BVL_MASK;
+
+ if (bvl == 0x00)
+ vl_status |= RTC_VL_BACKUP_EMPTY;
+ else if (bvl <= PCF85053A_BVL_LOW_THRESHOLD)
+ vl_status |= RTC_VL_BACKUP_LOW;
+
+ return put_user(vl_status, (unsigned int __user *)arg);
+
+ default:
+ return -ENOIOCTLCMD;
+ }
+}
+
+#ifdef CONFIG_COMMON_CLK
+/*
+ * Handling of the clkout
+ */
+
+#define clkout_hw_to_pcf85053(_hw) container_of(_hw, struct pcf85053, clkout_hw)
+
+static const int clkout_rates[] = {
+ 32768,
+ 1024,
+ 32,
+ 1,
+};
+
+static unsigned long pcf85053_clkout_recalc_rate(struct clk_hw *hw,
+ unsigned long parent_rate)
+{
+ struct pcf85053 *pcf85053 = clkout_hw_to_pcf85053(hw);
+ unsigned int val = 0;
+ int err;
+
+ err = regmap_read(pcf85053->regmap, PCF85053_REG_CLKO, &val);
+ if (err)
+ return 0;
+
+ val &= PCF85053_REG_CLKO_F_MASK;
+ return clkout_rates[val];
+}
+
+static int pcf85053_clkout_determine_rate(struct clk_hw *hw,
+ struct clk_rate_request *req)
+{
+ int i;
+ unsigned long best = 0;
+
+ for (i = 0; i < ARRAY_SIZE(clkout_rates); i++) {
+ if (clkout_rates[i] <= req->rate) {
+ best = clkout_rates[i];
+ break;
+ }
+ }
+ if (!best)
+ best = clkout_rates[ARRAY_SIZE(clkout_rates) - 1];
+
+ req->rate = best;
+ return 0;
+}
+
+static int pcf85053_clkout_set_rate(struct clk_hw *hw, unsigned long rate,
+ unsigned long parent_rate)
+{
+ struct pcf85053 *pcf85053 = clkout_hw_to_pcf85053(hw);
+ unsigned int val = 0;
+ int err, i;
+
+ err = regmap_read(pcf85053->regmap, PCF85053_REG_CLKO, &val);
+ if (err)
+ return err;
+
+ for (i = 0; i < ARRAY_SIZE(clkout_rates); i++)
+ if (clkout_rates[i] == rate) {
+ val &= ~PCF85053_REG_CLKO_F_MASK;
+ val |= i;
+ return regmap_write(pcf85053->regmap, PCF85053_REG_CLKO, val);
+ }
+
+ return -EINVAL;
+}
+
+static int pcf85053_clkout_control(struct clk_hw *hw, bool enable)
+{
+ struct pcf85053 *pcf85053 = clkout_hw_to_pcf85053(hw);
+ unsigned int val = 0;
+ int err;
+
+ if (!pcf85053->is_primary)
+ return -EACCES;
+
+ val = PCF85053_BIT_XCLK;
+ err = regmap_write(pcf85053->regmap, PCF85053_REG_ACC, val);
+ if (err)
+ return err;
+
+ err = regmap_read(pcf85053->regmap, PCF85053_REG_CLKO, &val);
+ if (err)
+ return err;
+
+ if (enable)
+ val |= PCF85053_REG_CLKO_CKE;
+ else
+ val &= ~PCF85053_REG_CLKO_CKE;
+
+ return regmap_write(pcf85053->regmap, PCF85053_REG_CLKO, val);
+}
+
+static int pcf85053_clkout_prepare(struct clk_hw *hw)
+{
+ return pcf85053_clkout_control(hw, 1);
+}
+
+static void pcf85053_clkout_unprepare(struct clk_hw *hw)
+{
+ pcf85053_clkout_control(hw, 0);
+}
+
+static int pcf85053_clkout_is_prepared(struct clk_hw *hw)
+{
+ struct pcf85053 *pcf85053 = clkout_hw_to_pcf85053(hw);
+ unsigned int val = 0;
+ int err;
+
+ err = regmap_read(pcf85053->regmap, PCF85053_REG_CLKO, &val);
+ if (err)
+ return err;
+
+ return val & PCF85053_REG_CLKO_CKE;
+}
+
+static const struct clk_ops pcf85053_clkout_ops = {
+ .prepare = pcf85053_clkout_prepare,
+ .unprepare = pcf85053_clkout_unprepare,
+ .is_prepared = pcf85053_clkout_is_prepared,
+ .recalc_rate = pcf85053_clkout_recalc_rate,
+ .determine_rate = pcf85053_clkout_determine_rate,
+ .set_rate = pcf85053_clkout_set_rate,
+};
+
+static struct clk *pcf85053_clkout_register_clk(struct pcf85053 *pcf85053)
+{
+ struct i2c_client *client = pcf85053->client;
+ struct device_node *node = client->dev.of_node;
+ struct clk *clk;
+ struct clk_init_data init;
+
+ init.name = "pcf85053-clkout";
+ init.ops = &pcf85053_clkout_ops;
+ init.flags = 0;
+ init.parent_names = NULL;
+ init.num_parents = 0;
+ pcf85053->clkout_hw.init = &init;
+
+ /* optional override of the clockname */
+ of_property_read_string(node, "clock-output-names", &init.name);
+
+ /* register the clock */
+ clk = devm_clk_register(&client->dev, &pcf85053->clkout_hw);
+
+ if (!IS_ERR(clk))
+ of_clk_add_provider(node, of_clk_src_simple_get, clk);
+
+ return clk;
+}
+#endif
+
+static const struct rtc_class_ops pcf85053_rtc_ops = {
+ .read_time = pcf85053_rtc_read_time,
+ .set_time = pcf85053_rtc_set_time,
+ .read_alarm = pcf85053_rtc_read_alarm,
+ .set_alarm = pcf85053_rtc_set_alarm,
+ .alarm_irq_enable = pcf85053_irq_enable,
+ .ioctl = pcf85053_ioctl,
+};
+
+static const struct pcf85053_config config_pcf85053 = {
+ .regmap = {
+ .reg_bits = 8,
+ .val_bits = 8,
+ .max_register = 0x1D,
+ },
+ .has_alarms = 1,
+};
+
+static int pcf85053_probe(struct i2c_client *client)
+{
+ struct pcf85053 *pcf85053;
+ const struct pcf85053_config *config;
+ const char *iface = NULL;
+ int err;
+
+ if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C |
+ I2C_FUNC_SMBUS_BYTE |
+ I2C_FUNC_SMBUS_BLOCK_DATA))
+ return -ENODEV;
+
+ pcf85053 = devm_kzalloc(&client->dev, sizeof(struct pcf85053),
+ GFP_KERNEL);
+ if (!pcf85053)
+ return -ENOMEM;
+
+ config = i2c_get_match_data(client);
+ if (!config)
+ return -ENODEV;
+
+ pcf85053->regmap = devm_regmap_init_i2c(client, &config->regmap);
+ if (IS_ERR(pcf85053->regmap))
+ return PTR_ERR(pcf85053->regmap);
+
+ i2c_set_clientdata(client, pcf85053);
+
+ pcf85053->client = client;
+ device_set_wakeup_capable(&client->dev, 1);
+
+ pcf85053->is_primary = true;
+
+ if (of_property_read_string(client->dev.of_node, "nxp,interface", &iface))
+ return dev_err_probe(&client->dev, -EINVAL,
+ "Missing mandatory property: nxp,interface\n");
+ if (!strcmp(iface, "primary"))
+ pcf85053->is_primary = true;
+ else if (!strcmp(iface, "secondary"))
+ pcf85053->is_primary = false;
+ else
+ return dev_err_probe(&client->dev, -EINVAL,
+ "Invalid value for nxp,interface: %s\n", iface);
+
+ if (pcf85053->is_primary) {
+ unsigned int ctrl;
+ int err;
+
+ err = regmap_read(pcf85053->regmap, PCF85053_REG_CTRL, &ctrl);
+ if (err)
+ return err;
+
+ if (of_property_read_bool(client->dev.of_node, "nxp,write-access")) {
+ if (!(ctrl & PCF85053_BIT_TWO)) {
+ err = regmap_update_bits(pcf85053->regmap, PCF85053_REG_CTRL,
+ PCF85053_BIT_TWO, PCF85053_BIT_TWO);
+ if (err)
+ return err;
+ }
+ dev_dbg(&client->dev, "Ownership set: TWO=1 (primary writes)\n");
+ } else {
+ /* TWO (Time Write Ownership) bit defaults to 0 (Secondary) */
+ dev_dbg(&client->dev, "Default ownership set: TWO=0 (secondary writes)\n");
+ }
+ }
+
+ pcf85053->rtc = devm_rtc_allocate_device(&client->dev);
+ if (IS_ERR(pcf85053->rtc))
+ return PTR_ERR(pcf85053->rtc);
+
+ pcf85053->rtc->ops = &pcf85053_rtc_ops;
+ pcf85053->rtc->range_min = RTC_TIMESTAMP_BEGIN_2000;
+ pcf85053->rtc->range_max = RTC_TIMESTAMP_END_2099;
+ clear_bit(RTC_FEATURE_UPDATE_INTERRUPT, pcf85053->rtc->features);
+ clear_bit(RTC_FEATURE_ALARM, pcf85053->rtc->features);
+
+ if (config->has_alarms && client->irq > 0) {
+ err = devm_request_threaded_irq(&client->dev, client->irq,
+ NULL, pcf85053_irq,
+ IRQF_ONESHOT | IRQF_TRIGGER_FALLING,
+ "pcf85053", client);
+ if (err) {
+ dev_err(&client->dev, "unable to request IRQ %d\n", client->irq);
+ } else {
+ set_bit(RTC_FEATURE_ALARM, pcf85053->rtc->features);
+ device_init_wakeup(&client->dev, true);
+ err = dev_pm_set_wake_irq(&client->dev, client->irq);
+ if (err)
+ dev_err(&client->dev, "failed to enable irq wake\n");
+ }
+ }
+
+#ifdef CONFIG_COMMON_CLK
+ /* register clk in common clk framework */
+ pcf85053_clkout_register_clk(pcf85053);
+#endif
+
+ return devm_rtc_register_device(pcf85053->rtc);
+}
+
+static const struct i2c_device_id pcf85053_id[] = {
+ { "pcf85053", .driver_data = (kernel_ulong_t)&config_pcf85053 },
+ { }
+};
+MODULE_DEVICE_TABLE(i2c, pcf85053_id);
+
+static const struct of_device_id pcf85053_of_match[] = {
+ { .compatible = "nxp,pcf85053", .data = &config_pcf85053 },
+ {}
+};
+MODULE_DEVICE_TABLE(of, pcf85053_of_match);
+
+static struct i2c_driver pcf85053_driver = {
+ .driver = {
+ .name = "rtc-pcf85053",
+ .of_match_table = of_match_ptr(pcf85053_of_match),
+ },
+ .probe = pcf85053_probe,
+ .id_table = pcf85053_id,
+};
+
+module_i2c_driver(pcf85053_driver);
+
+MODULE_AUTHOR("Pankit Garg <pankit.garg@nxp.com>");
+MODULE_AUTHOR("Lakshay Piplani <lakshay.piplani@nxp.com>");
+MODULE_DESCRIPTION("NXP pcf85053 RTC driver");
+MODULE_LICENSE("GPL");
--
2.25.1
^ permalink raw reply related
* [PATCH v4 1/2] dt-bindings: rtc: Add pcf85053 support
From: Lakshay Piplani @ 2025-09-23 11:34 UTC (permalink / raw)
To: alexandre.belloni, linux-rtc, linux-kernel, robh, krzk+dt,
conor+dt, devicetree
Cc: pankit.garg, vikash.bansal, priyanka.jain, shashank.rebbapragada,
Lakshay Piplani
Add device tree bindings for NXP PCF85053 RTC chip.
Signed-off-by: Pankit Garg <pankit.garg@nxp.com>
Signed-off-by: Lakshay Piplani <lakshay.piplani@nxp.com>
---
V3 -> V4: Add dedicated nxp,pcf85053.yaml.
Remove entry from trivial-rtc.yaml.
V2 -> V3: Moved MAINTAINERS file changes to the driver patch
V1 -> V2: Handled dt-bindings by trivial-rtc.yaml
.../devicetree/bindings/rtc/nxp,pcf85053.yaml | 128 ++++++++++++++++++
1 file changed, 128 insertions(+)
create mode 100644 Documentation/devicetree/bindings/rtc/nxp,pcf85053.yaml
diff --git a/Documentation/devicetree/bindings/rtc/nxp,pcf85053.yaml b/Documentation/devicetree/bindings/rtc/nxp,pcf85053.yaml
new file mode 100644
index 000000000000..6b1c97358486
--- /dev/null
+++ b/Documentation/devicetree/bindings/rtc/nxp,pcf85053.yaml
@@ -0,0 +1,128 @@
+# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
+# Copyright 2025 NXP
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/rtc/nxp,pcf85053.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: NXP PCF85053 Real Time Clock
+
+maintainers:
+ - Pankit Garg <pankit.garg@nxp.com>
+ - Lakshay Piplani <lakshay.piplani@nxp.com>
+
+properties:
+ compatible:
+ enum:
+ - nxp,pcf85053
+
+ reg:
+ maxItems: 1
+
+ interrupts:
+ maxItems: 1
+
+ nxp,interface:
+ $ref: /schemas/types.yaml#/definitions/string
+ enum: [ primary, secondary ]
+ description: |
+ Identifies this host's logical role in a multi-host topology for the
+ PCF85053 RTC. The device exposes a "TWO" ownership bit in the CTRL
+ register that gates which host may write time/alarm registers.
+ - "primary": Designated host that *may* claim write ownership (set
+ CTRL.TWO=1) **if** write-access is explicitly requested.
+ - "secondary": Peer host that writes only when CTRL.TWO=0 (default).
+
+ nxp,write-access:
+ type: boolean
+ description: |
+ Request the driver to claim write ownership at probe time by setting
+ CTRL.TWO=1. This property is only valid when nxp,interface="primary".
+ The driver will not modify any other CTRL bits (HF/DM/etc.) and will not
+ clear any status/interrupt flags at probe.
+
+required:
+ - compatible
+ - reg
+ - nxp,interface
+
+additionalProperties: false
+
+# Schema constraints matching driver:
+# 1) If nxp,write-access is present, nxp,interface must be "primary".
+# Rationale: only the primary may claim ownership; driver will set TWO=1.
+# 2) If nxp,interface is "secondary", nxp,write-access must not be present.
+# Rationale: secondary never claims ownership and cannot write CTRL/ST/alarm.
+#
+# Practical effect:
+# - Primary without 'nxp,write-access'; primary is read only; secondary may
+# write time registers.
+# - Primary with 'nxp,write-access'; primary owns writes, secondary is read only.
+allOf:
+ - $ref: rtc.yaml#
+ - oneOf:
+ # Case 1: primary with write-access
+ - required: [ "nxp,write-access" ]
+ properties:
+ nxp,interface:
+ const: primary
+
+ # Case 2: primary without write-access
+ - properties:
+ nxp,interface:
+ const: primary
+ not:
+ required: [ "nxp,write-access" ]
+
+ # Case 3: secondary (must not have write-access)
+ - properties:
+ nxp,interface:
+ const: secondary
+ not:
+ required: [ "nxp,write-access" ]
+
+examples:
+ # Single host example.
+ - |
+ #include <dt-bindings/interrupt-controller/irq.h>
+ i2c {
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ rtc@6f {
+ compatible = "nxp,pcf85053";
+ reg = <0x6f>;
+ nxp,interface = "primary";
+ nxp,write-access;
+ interrupt-parent = <&gpio2>;
+ interrupts = <3 IRQ_TYPE_EDGE_FALLING>;
+ };
+ };
+
+ # Dual-host example: one primary that claims writes; one secondary that never claims writes.
+ - |
+ #include <dt-bindings/interrupt-controller/irq.h>
+ i2c0 {
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ rtc@6f {
+ compatible = "nxp,pcf85053";
+ reg = <0x6f>;
+ nxp,interface = "primary";
+ nxp,write-access;
+ interrupt-parent = <&gpio2>;
+ interrupts = <3 IRQ_TYPE_EDGE_FALLING>;
+ };
+ };
+
+ i2c1 {
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ rtc@6f {
+ compatible = "nxp,pcf85053";
+ reg = <0x6f>;
+ nxp,interface = "secondary";
+ };
+ };
--
2.25.1
^ permalink raw reply related
* Re: [PATCH v3 1/6] dt-bindings: rtc: Add ST m41t93
From: Rob Herring (Arm) @ 2025-09-22 20:27 UTC (permalink / raw)
To: Akhilesh Patil
Cc: conor+dt, akhileshpatilvnit, alexandre.belloni, krzk+dt,
linux-rtc, linux-kernel, devicetree, skhan
In-Reply-To: <b1b1f7abde8a4ee8b625361bca32934679bf1e1a.1758379856.git.akhilesh@ee.iitb.ac.in>
On Sat, 20 Sep 2025 20:31:24 +0530, Akhilesh Patil wrote:
> Document DT bindings for m41t93 rtc which supports time, date,
> alarm, watchdog, square wave clock output provider, user sram
> and 8 bit timer.
>
> Signed-off-by: Akhilesh Patil <akhilesh@ee.iitb.ac.in>
> ---
> .../devicetree/bindings/rtc/st,m41t93.yaml | 50 +++++++++++++++++++
> 1 file changed, 50 insertions(+)
> create mode 100644 Documentation/devicetree/bindings/rtc/st,m41t93.yaml
>
Reviewed-by: Rob Herring (Arm) <robh@kernel.org>
^ permalink raw reply
* Re: [PATCH v6 1/4] dt-bindings: rtc: Document NVIDIA VRS RTC
From: Jon Hunter @ 2025-09-22 20:08 UTC (permalink / raw)
To: Rob Herring, Shubhi Garg
Cc: Lee Jones, Krzysztof Kozlowski, Conor Dooley, Catalin Marinas,
Will Deacon, Alexandre Belloni, devicetree, linux-arm-kernel,
linux-rtc, linux-tegra
In-Reply-To: <20250922195354.GA1065946-robh@kernel.org>
On 22/09/2025 20:53, Rob Herring wrote:
> On Fri, Sep 19, 2025 at 01:59:50PM +0000, Shubhi Garg wrote:
>> Add device tree bindings for NVIDIA VRS (Voltage Regulator Specification)
>> RTC device. NVIDIA VRS is a Power Management IC (PMIC) that implements a
>> power sequencing solution with I2C interface. The device includes RTC
>> which provides functionality to get/set system time, retain system
>> time across boot, wake system from suspend and shutdown state.
>
> I only see this patch. The threading of this is broken.
Yep I see the same. I am not sure what happened here, but let me work
with Shubhi to get this resent.
Jon
--
nvpublic
^ permalink raw reply
* Re: [PATCH v6 1/4] dt-bindings: rtc: Document NVIDIA VRS RTC
From: Rob Herring @ 2025-09-22 19:53 UTC (permalink / raw)
To: Shubhi Garg
Cc: Lee Jones, Krzysztof Kozlowski, Conor Dooley, Catalin Marinas,
Will Deacon, Alexandre Belloni, Jonathan Hunter, devicetree,
linux-arm-kernel, linux-rtc, linux-tegra
In-Reply-To: <20250919135950.10403-1-shgarg@nvidia.com>
On Fri, Sep 19, 2025 at 01:59:50PM +0000, Shubhi Garg wrote:
> Add device tree bindings for NVIDIA VRS (Voltage Regulator Specification)
> RTC device. NVIDIA VRS is a Power Management IC (PMIC) that implements a
> power sequencing solution with I2C interface. The device includes RTC
> which provides functionality to get/set system time, retain system
> time across boot, wake system from suspend and shutdown state.
I only see this patch. The threading of this is broken.
>
> Supported platforms:
> - NVIDIA Jetson AGX Orin Developer Kit
> - NVIDIA IGX Orin Development Kit
> - NVIDIA Jetson Orin NX Developer Kit
> - NVIDIA Jetson Orin Nano Developer Kit
>
> Signed-off-by: Shubhi Garg <shgarg@nvidia.com>
> ---
>
> v6:
> - compatible name fixes to "nvidia,vrs-10"
> - changed dtb node name to pmic@3c
>
> v5:
> - moved device tree bindings from mfd to rtc
> - changed dtb node name to rtc@3c
> - changed compatible string to "nvidia,vrs10-rtc"
>
> v4:
> - no changes
>
> v3:
> - fixed device tree node name to generic "pmic@3c"
> - fixed indentation
>
> v2:
> - fixed copyrights
> - updated description with RTC information
> - added status node in dtb node example
>
> .../bindings/rtc/nvidia,vrs10-rtc.yaml | 59 +++++++++++++++++++
Filename should match compatible string.
> 1 file changed, 59 insertions(+)
> create mode 100644 Documentation/devicetree/bindings/rtc/nvidia,vrs10-rtc.yaml
>
> diff --git a/Documentation/devicetree/bindings/rtc/nvidia,vrs10-rtc.yaml b/Documentation/devicetree/bindings/rtc/nvidia,vrs10-rtc.yaml
> new file mode 100644
> index 000000000000..e8f3c25607e0
> --- /dev/null
> +++ b/Documentation/devicetree/bindings/rtc/nvidia,vrs10-rtc.yaml
> @@ -0,0 +1,59 @@
> +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
> +%YAML 1.2
> +---
> +$id: http://devicetree.org/schemas/rtc/nvidia,vrs10-rtc.yaml#
> +$schema: http://devicetree.org/meta-schemas/core.yaml#
> +
> +title: NVIDIA Voltage Regulator Specification Real Time Clock
> +
> +maintainers:
> + - Shubhi Garg <shgarg@nvidia.com>
> +
> +description:
> + NVIDIA VRS-10 (Voltage Regulator Specification) is a Power Management IC
> + (PMIC) that implements a power sequencing solution with I2C interface.
> + The device includes a real-time clock (RTC) with 32kHz clock output and
> + backup battery support, alarm functionality for system wake-up from
> + suspend and shutdown states, OTP memory for power sequencing configuration,
> + and an interrupt controller for managing VRS events.
> +
> +properties:
> + compatible:
> + const: nvidia,vrs-10
> +
> + reg:
> + maxItems: 1
> +
> + interrupts:
> + maxItems: 1
> +
> + interrupt-controller: true
> +
> + '#interrupt-cells':
> + const: 2
> +
> +required:
> + - compatible
> + - reg
> + - interrupts
> + - interrupt-controller
> + - '#interrupt-cells'
> +
> +additionalProperties: false
> +
> +examples:
> + - |
> + #include <dt-bindings/interrupt-controller/irq.h>
> + i2c {
> + #address-cells = <1>;
> + #size-cells = <0>;
> +
> + pmic@3c {
> + compatible = "nvidia,vrs-10";
> + reg = <0x3c>;
> + interrupt-parent = <&pmc>;
> + interrupts = <24 IRQ_TYPE_LEVEL_LOW>;
> + interrupt-controller;
> + #interrupt-cells = <2>;
> + };
> + };
> --
> 2.43.0
>
^ permalink raw reply
* [PATCH 6.12 098/105] rtc: pcf2127: fix SPI command byte for PCF2131 backport
From: Greg Kroah-Hartman @ 2025-09-22 19:30 UTC (permalink / raw)
To: stable, linux-rtc
Cc: Greg Kroah-Hartman, patches, Alexandre Belloni, Elena Popa,
Hugo Villeneuve, Bruno Thomsen
In-Reply-To: <20250922192408.913556629@linuxfoundation.org>
6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Bruno Thomsen <bruno.thomsen@gmail.com>
When commit fa78e9b606a472495ef5b6b3d8b45c37f7727f9d upstream was
backported to LTS branches linux-6.12.y and linux-6.6.y, the SPI regmap
config fix got applied to the I2C regmap config. Most likely due to a new
RTC get/set parm feature introduced in 6.14 causing regmap config sections
in the buttom of the driver to move. LTS branch linux-6.1.y and earlier
does not have PCF2131 device support.
Issue can be seen in buttom of this diff in stable/linux.git tree:
git diff master..linux-6.12.y -- drivers/rtc/rtc-pcf2127.c
Fixes: ee61aec8529e ("rtc: pcf2127: fix SPI command byte for PCF2131")
Fixes: 5cdd1f73401d ("rtc: pcf2127: fix SPI command byte for PCF2131")
Cc: stable@vger.kernel.org
Cc: Alexandre Belloni <alexandre.belloni@bootlin.com>
Cc: Elena Popa <elena.popa@nxp.com>
Cc: Hugo Villeneuve <hvilleneuve@dimonoff.com>
Signed-off-by: Bruno Thomsen <bruno.thomsen@gmail.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
---
drivers/rtc/rtc-pcf2127.c | 10 +++++-----
1 file changed, 5 insertions(+), 5 deletions(-)
--- a/drivers/rtc/rtc-pcf2127.c
+++ b/drivers/rtc/rtc-pcf2127.c
@@ -1383,11 +1383,6 @@ static int pcf2127_i2c_probe(struct i2c_
variant = &pcf21xx_cfg[type];
}
- if (variant->type == PCF2131) {
- config.read_flag_mask = 0x0;
- config.write_flag_mask = 0x0;
- }
-
config.max_register = variant->max_register,
regmap = devm_regmap_init(&client->dev, &pcf2127_i2c_regmap,
@@ -1461,6 +1456,11 @@ static int pcf2127_spi_probe(struct spi_
variant = &pcf21xx_cfg[type];
}
+ if (variant->type == PCF2131) {
+ config.read_flag_mask = 0x0;
+ config.write_flag_mask = 0x0;
+ }
+
config.max_register = variant->max_register;
regmap = devm_regmap_init_spi(spi, &config);
^ permalink raw reply
* [PATCH 6.6 65/70] rtc: pcf2127: fix SPI command byte for PCF2131 backport
From: Greg Kroah-Hartman @ 2025-09-22 19:30 UTC (permalink / raw)
To: stable, linux-rtc
Cc: Greg Kroah-Hartman, patches, Alexandre Belloni, Elena Popa,
Hugo Villeneuve, Bruno Thomsen
In-Reply-To: <20250922192404.455120315@linuxfoundation.org>
6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Bruno Thomsen <bruno.thomsen@gmail.com>
When commit fa78e9b606a472495ef5b6b3d8b45c37f7727f9d upstream was
backported to LTS branches linux-6.12.y and linux-6.6.y, the SPI regmap
config fix got applied to the I2C regmap config. Most likely due to a new
RTC get/set parm feature introduced in 6.14 causing regmap config sections
in the buttom of the driver to move. LTS branch linux-6.1.y and earlier
does not have PCF2131 device support.
Issue can be seen in buttom of this diff in stable/linux.git tree:
git diff master..linux-6.12.y -- drivers/rtc/rtc-pcf2127.c
Fixes: ee61aec8529e ("rtc: pcf2127: fix SPI command byte for PCF2131")
Fixes: 5cdd1f73401d ("rtc: pcf2127: fix SPI command byte for PCF2131")
Cc: stable@vger.kernel.org
Cc: Alexandre Belloni <alexandre.belloni@bootlin.com>
Cc: Elena Popa <elena.popa@nxp.com>
Cc: Hugo Villeneuve <hvilleneuve@dimonoff.com>
Signed-off-by: Bruno Thomsen <bruno.thomsen@gmail.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
---
drivers/rtc/rtc-pcf2127.c | 10 +++++-----
1 file changed, 5 insertions(+), 5 deletions(-)
--- a/drivers/rtc/rtc-pcf2127.c
+++ b/drivers/rtc/rtc-pcf2127.c
@@ -1383,11 +1383,6 @@ static int pcf2127_i2c_probe(struct i2c_
variant = &pcf21xx_cfg[type];
}
- if (variant->type == PCF2131) {
- config.read_flag_mask = 0x0;
- config.write_flag_mask = 0x0;
- }
-
config.max_register = variant->max_register,
regmap = devm_regmap_init(&client->dev, &pcf2127_i2c_regmap,
@@ -1461,6 +1456,11 @@ static int pcf2127_spi_probe(struct spi_
variant = &pcf21xx_cfg[type];
}
+ if (variant->type == PCF2131) {
+ config.read_flag_mask = 0x0;
+ config.write_flag_mask = 0x0;
+ }
+
config.max_register = variant->max_register;
regmap = devm_regmap_init_spi(spi, &config);
^ permalink raw reply
* [PATCH 5.10] rtc: fix error return in pm80x_rtc_set_alarm()
From: Alexandr Sapozhnkiov @ 2025-09-22 14:42 UTC (permalink / raw)
To: Alexandre Belloni, linux-rtc, linux-kernel
Cc: Alexandr Sapozhnikov, linux-media, lvc-project
From: Alexandr Sapozhnikov <alsp705@gmail.com>
Return value of function 'regmap_raw_write', called at rtc-88pm80x.c:205,
is not checked, but it is usually checked for this function
Found by Linux Verification Center (linuxtesting.org) with SVACE.
Signed-off-by: Alexandr Sapozhnikov <alsp705@gmail.com>
---
drivers/rtc/rtc-88pm80x.c | 6 ++++--
1 file changed, 4 insertions(+), 2 deletions(-)
diff --git a/drivers/rtc/rtc-88pm80x.c b/drivers/rtc/rtc-88pm80x.c
index f40cc06b0979..82984a58dca7 100644
--- a/drivers/rtc/rtc-88pm80x.c
+++ b/drivers/rtc/rtc-88pm80x.c
@@ -173,7 +173,7 @@ static int pm80x_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alrm)
struct rtc_time now_tm, alarm_tm;
unsigned long ticks, base, data;
unsigned char buf[4];
- int mask;
+ int mask, ret;
regmap_update_bits(info->map, PM800_RTC_CONTROL, PM800_ALARM1_EN, 0);
@@ -202,7 +202,9 @@ static int pm80x_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alrm)
buf[1] = (data >> 8) & 0xff;
buf[2] = (data >> 16) & 0xff;
buf[3] = (data >> 24) & 0xff;
- regmap_raw_write(info->map, PM800_RTC_EXPIRE1_1, buf, 4);
+ ret = regmap_raw_write(info->map, PM800_RTC_EXPIRE1_1, buf, 4);
+ if (ret)
+ return ret;
if (alrm->enabled) {
mask = PM800_ALARM | PM800_ALARM_WAKEUP | PM800_ALARM1_EN;
regmap_update_bits(info->map, PM800_RTC_CONTROL, mask, mask);
--
2.43.0
^ permalink raw reply related
* Re: [PATCH v5 2/2] clk: s2mps11: add support for S2MPG10 PMIC clock
From: Stephen Boyd @ 2025-09-21 17:43 UTC (permalink / raw)
To: Alexandre Belloni, Alim Akhtar, André Draszik,
Catalin Marinas, Chanwoo Choi, Conor Dooley, Krzysztof Kozlowski,
Lee Jones, Michael Turquette, Rob Herring, Russell King,
Sylwester Nawrocki, Will Deacon
Cc: Peter Griffin, Tudor Ambarus, Will McVicker, kernel-team,
linux-kernel, linux-samsung-soc, devicetree, linux-clk,
linux-arm-kernel, linux-rtc, André Draszik,
Krzysztof Kozlowski
In-Reply-To: <20250730-s2mpg10-v5-2-cd133963626c@linaro.org>
Quoting André Draszik (2025-07-30 02:31:35)
> Add support for Samsung's S2MPG10 PMIC clock, which is similar to the
> existing PMIC clocks supported by this driver.
>
> S2MPG10 has three clock outputs @ 32kHz: AP, peri1 and peri2.
>
> Acked-by: Stephen Boyd <sboyd@kernel.org>
> Reviewed-by: Krzysztof Kozlowski <krzysztof.kozlowski@linaro.org>
> Signed-off-by: André Draszik <andre.draszik@linaro.org>
> ---
Applied to clk-next
^ permalink raw reply
* Re: [PATCH v5 1/2] dt-bindings: clock: samsung,s2mps11: add s2mpg10
From: Stephen Boyd @ 2025-09-21 17:43 UTC (permalink / raw)
To: Alexandre Belloni, Alim Akhtar, André Draszik,
Catalin Marinas, Chanwoo Choi, Conor Dooley, Krzysztof Kozlowski,
Lee Jones, Michael Turquette, Rob Herring, Russell King,
Sylwester Nawrocki, Will Deacon
Cc: Peter Griffin, Tudor Ambarus, Will McVicker, kernel-team,
linux-kernel, linux-samsung-soc, devicetree, linux-clk,
linux-arm-kernel, linux-rtc, André Draszik
In-Reply-To: <20250730-s2mpg10-v5-1-cd133963626c@linaro.org>
Quoting André Draszik (2025-07-30 02:31:34)
> The Samsung S2MPG10 clock controller is similar to the existing clock
> controllers supported by this binding. Register offsets / layout are
> slightly different, so it needs its own compatible.
>
> Acked-by: Stephen Boyd <sboyd@kernel.org>
> Acked-by: Rob Herring (Arm) <robh@kernel.org>
> Signed-off-by: André Draszik <andre.draszik@linaro.org>
> ---
Applied to clk-next
^ permalink raw reply
* Re: [PATCH v1 5/7] clk: s2mps11: add the support for S2MPS16 PMIC clock
From: Stephen Boyd @ 2025-09-21 16:28 UTC (permalink / raw)
To: Alexandre Belloni, Alim Akhtar, André Draszik, Chanwoo Choi,
Conor Dooley, Ivaylo Ivanov, Krzysztof Kozlowski, Lee Jones,
Liam Girdwood, Mark Brown, Michael Turquette, Rob Herring,
Sylwester Nawrocki
Cc: linux-samsung-soc, devicetree, linux-clk, linux-rtc, linux-kernel
In-Reply-To: <20250914124227.2619925-6-ivo.ivanov.ivanov1@gmail.com>
Quoting Ivaylo Ivanov (2025-09-14 05:42:25)
> Add the support for S2MPS16 PMIC clock, which is functionally the same
> as the currently supported ones, with the exception of a different
> register.
>
> Signed-off-by: Ivaylo Ivanov <ivo.ivanov.ivanov1@gmail.com>
> ---
Acked-by: Stephen Boyd <sboyd@kernel.org>
^ permalink raw reply
* Re: [PATCH v1 3/7] dt-bindings: clock: samsung,s2mps11: document the S2MPS16 compatible
From: Stephen Boyd @ 2025-09-21 16:27 UTC (permalink / raw)
To: Alexandre Belloni, Alim Akhtar, André Draszik, Chanwoo Choi,
Conor Dooley, Ivaylo Ivanov, Krzysztof Kozlowski, Lee Jones,
Liam Girdwood, Mark Brown, Michael Turquette, Rob Herring,
Sylwester Nawrocki
Cc: linux-samsung-soc, devicetree, linux-clk, linux-rtc, linux-kernel
In-Reply-To: <20250914124227.2619925-4-ivo.ivanov.ivanov1@gmail.com>
Quoting Ivaylo Ivanov (2025-09-14 05:42:23)
> The S2MPS16 PMIC, alongside regulators and an rtc, provides 3 clock
> outputs, just like most of the other S2MPS PMICs. Document the S2MPS16
> clock compatible.
>
> Signed-off-by: Ivaylo Ivanov <ivo.ivanov.ivanov1@gmail.com>
> ---
Acked-by: Stephen Boyd <sboyd@kernel.org>
^ permalink raw reply
* [PATCH] rtc: s35390a: use u8 instead of char for register buffer
From: Nick Huang @ 2025-09-20 17:42 UTC (permalink / raw)
To: alexandre.belloni
Cc: linux-rtc, linux-kernel, kusogame68, byron.bbradley, Nick Huang
The register buffer in s35390a_get_reg() was previously defined as
`char *buf`. This is not ideal since register data represents raw
binary values rather than textual data.
Switch the type to `u8 *buf` to better reflect its intended usage and
to avoid potential issues with sign extension when handling register
values on platforms where `char` is signed by default.
This change improves type safety and makes the code consistent with
other RTC drivers that operate on raw register data.
Signed-off-by: Nick Huang <sef1548@gmail.com>
---
drivers/rtc/rtc-s35390a.c | 18 +++++++++---------
1 file changed, 9 insertions(+), 9 deletions(-)
diff --git a/drivers/rtc/rtc-s35390a.c b/drivers/rtc/rtc-s35390a.c
index 3408d2ab27..07bd983b56 100644
--- a/drivers/rtc/rtc-s35390a.c
+++ b/drivers/rtc/rtc-s35390a.c
@@ -66,7 +66,7 @@ struct s35390a {
int twentyfourhour;
};
-static int s35390a_set_reg(struct s35390a *s35390a, int reg, char *buf, int len)
+static int s35390a_set_reg(struct s35390a *s35390a, int reg, u8 *buf, int len)
{
struct i2c_client *client = s35390a->client[reg];
struct i2c_msg msg[] = {
@@ -83,7 +83,7 @@ static int s35390a_set_reg(struct s35390a *s35390a, int reg, char *buf, int len)
return 0;
}
-static int s35390a_get_reg(struct s35390a *s35390a, int reg, char *buf, int len)
+static int s35390a_get_reg(struct s35390a *s35390a, int reg, u8 *buf, int len)
{
struct i2c_client *client = s35390a->client[reg];
struct i2c_msg msg[] = {
@@ -168,7 +168,7 @@ static int s35390a_read_status(struct s35390a *s35390a, char *status1)
static int s35390a_disable_test_mode(struct s35390a *s35390a)
{
- char buf[1];
+ u8 buf[1];
if (s35390a_get_reg(s35390a, S35390A_CMD_STATUS2, buf, sizeof(buf)) < 0)
return -EIO;
@@ -210,7 +210,7 @@ static int s35390a_rtc_set_time(struct device *dev, struct rtc_time *tm)
struct i2c_client *client = to_i2c_client(dev);
struct s35390a *s35390a = i2c_get_clientdata(client);
int i;
- char buf[7], status;
+ u8 buf[7], status;
dev_dbg(&client->dev, "%s: tm is secs=%d, mins=%d, hours=%d mday=%d, "
"mon=%d, year=%d, wday=%d\n", __func__, tm->tm_sec,
@@ -239,7 +239,7 @@ static int s35390a_rtc_read_time(struct device *dev, struct rtc_time *tm)
{
struct i2c_client *client = to_i2c_client(dev);
struct s35390a *s35390a = i2c_get_clientdata(client);
- char buf[7], status;
+ u8 buf[7], status;
int i, err;
if (s35390a_read_status(s35390a, &status) == 1)
@@ -273,7 +273,7 @@ static int s35390a_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alm)
{
struct i2c_client *client = to_i2c_client(dev);
struct s35390a *s35390a = i2c_get_clientdata(client);
- char buf[3], sts = 0;
+ u8 buf[3], sts = 0;
int err, i;
dev_dbg(&client->dev, "%s: alm is secs=%d, mins=%d, hours=%d mday=%d, "\
@@ -326,7 +326,7 @@ static int s35390a_rtc_read_alarm(struct device *dev, struct rtc_wkalrm *alm)
{
struct i2c_client *client = to_i2c_client(dev);
struct s35390a *s35390a = i2c_get_clientdata(client);
- char buf[3], sts;
+ u8 buf[3], sts;
int i, err;
err = s35390a_get_reg(s35390a, S35390A_CMD_STATUS2, &sts, sizeof(sts));
@@ -383,7 +383,7 @@ static int s35390a_rtc_ioctl(struct device *dev, unsigned int cmd,
{
struct i2c_client *client = to_i2c_client(dev);
struct s35390a *s35390a = i2c_get_clientdata(client);
- char sts;
+ u8 sts;
int err;
switch (cmd) {
@@ -422,7 +422,7 @@ static int s35390a_probe(struct i2c_client *client)
unsigned int i;
struct s35390a *s35390a;
struct rtc_device *rtc;
- char buf, status1;
+ u8 buf, status1;
struct device *dev = &client->dev;
if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C))
--
2.48.1
^ permalink raw reply related
* [PATCH v3 6/6] rtc: m41t93: Add watchdog support
From: Akhilesh Patil @ 2025-09-20 15:03 UTC (permalink / raw)
To: alexandre.belloni, krzk+dt, robh, conor+dt
Cc: skhan, linux-rtc, devicetree, linux-kernel, akhileshpatilvnit
In-Reply-To: <cover.1758379856.git.akhilesh@ee.iitb.ac.in>
Implement watchdog feature for m41t93 rtc with 1s resolution.
Implement alarm only support (WDIOF_ALARMONLY) in this commit.
Define start, stop, ping, and set_timeout callbacks as needed
by the watchdog framework.
Use selftests/watchdog/watchdog-test kselftest for testing.
Observed IRQ pin(12) of rtc chip going low after late pinging
the watchdog.
Signed-off-by: Akhilesh Patil <akhilesh@ee.iitb.ac.in>
---
drivers/rtc/rtc-m41t93.c | 99 ++++++++++++++++++++++++++++++++++++++++
1 file changed, 99 insertions(+)
diff --git a/drivers/rtc/rtc-m41t93.c b/drivers/rtc/rtc-m41t93.c
index 46703e32f212..483fc6a5ad21 100644
--- a/drivers/rtc/rtc-m41t93.c
+++ b/drivers/rtc/rtc-m41t93.c
@@ -14,6 +14,7 @@
#include <linux/spi/spi.h>
#include <linux/regmap.h>
#include <linux/clk-provider.h>
+#include <linux/watchdog.h>
#define M41T93_REG_SSEC 0
#define M41T93_REG_ST_SEC 1
@@ -36,6 +37,10 @@
#define M41T93_SQW_RS_MASK 0xf0
#define M41T93_SQW_RS_SHIFT 4
#define M41T93_BIT_SQWE BIT(6)
+#define M41T93_REG_WATCHDOG 0x9
+#define M41T93_WDT_RB_MASK 0x3
+#define M41T93_WDT_BMB_MASK 0x7c
+#define M41T93_WDT_BMB_SHIFT 2
#define M41T93_REG_ALM_HOUR_HT 0xc
#define M41T93_REG_FLAGS 0xf
@@ -51,6 +56,9 @@ struct m41t93_data {
#ifdef CONFIG_COMMON_CLK
struct clk_hw clks;
#endif
+#ifdef CONFIG_WATCHDOG
+ struct watchdog_device wdd;
+#endif
};
static int m41t93_set_time(struct device *dev, struct rtc_time *tm)
@@ -412,6 +420,92 @@ static int rtc_m41t93_clks_register(struct device *dev, struct m41t93_data *m41t
}
#endif
+#ifdef CONFIG_WATCHDOG
+static int m41t93_wdt_ping(struct watchdog_device *wdd)
+{
+ u8 resolution, mult;
+ u8 val = 0;
+ int ret;
+ struct m41t93_data *m41t93 = watchdog_get_drvdata(wdd);
+
+ /* Resolution supported by hardware
+ * 0b00 : 1/16 seconds
+ * 0b01 : 1/4 second
+ * 0b10 : 1 second
+ * 0b11 : 4 seconds
+ */
+ resolution = 0x2; /* hardcode resolution to 1s */
+ mult = wdd->timeout;
+ val = resolution | (mult << M41T93_WDT_BMB_SHIFT & M41T93_WDT_BMB_MASK);
+
+ ret = regmap_write_bits(m41t93->regmap, M41T93_REG_WATCHDOG,
+ M41T93_WDT_RB_MASK | M41T93_WDT_BMB_MASK, val);
+
+ return ret;
+}
+
+static int m41t93_wdt_start(struct watchdog_device *wdd)
+{
+ return m41t93_wdt_ping(wdd);
+}
+
+static int m41t93_wdt_stop(struct watchdog_device *wdd)
+{
+ struct m41t93_data *m41t93 = watchdog_get_drvdata(wdd);
+
+ /* Write 0 to watchdog register */
+ return regmap_write_bits(m41t93->regmap, M41T93_REG_WATCHDOG,
+ M41T93_WDT_RB_MASK | M41T93_WDT_BMB_MASK, 0);
+}
+
+static int m41t93_wdt_set_timeout(struct watchdog_device *wdd,
+ unsigned int new_timeout)
+{
+ wdd->timeout = new_timeout;
+
+ return 0;
+}
+
+static const struct watchdog_info m41t93_wdt_info = {
+ .identity = "m41t93 rtc Watchdog",
+ .options = WDIOF_ALARMONLY | WDIOF_SETTIMEOUT | WDIOF_KEEPALIVEPING,
+};
+
+static const struct watchdog_ops m41t93_watchdog_ops = {
+ .owner = THIS_MODULE,
+ .start = m41t93_wdt_start,
+ .stop = m41t93_wdt_stop,
+ .ping = m41t93_wdt_ping,
+ .set_timeout = m41t93_wdt_set_timeout,
+};
+
+static int m41t93_watchdog_register(struct device *dev, struct m41t93_data *m41t93)
+{
+ int ret;
+
+ m41t93->wdd.parent = dev;
+ m41t93->wdd.info = &m41t93_wdt_info;
+ m41t93->wdd.ops = &m41t93_watchdog_ops;
+ m41t93->wdd.min_timeout = 0;
+ m41t93->wdd.max_timeout = 10;
+ m41t93->wdd.timeout = 3; /* Default timeout is 3 sec */
+ m41t93->wdd.status = WATCHDOG_NOWAYOUT_INIT_STATUS;
+
+ watchdog_set_drvdata(&m41t93->wdd, m41t93);
+
+ ret = devm_watchdog_register_device(dev, &m41t93->wdd);
+ if (ret) {
+ dev_warn(dev, "Failed to register watchdog\n");
+ return ret;
+ }
+
+ /* Disable watchdog at start */
+ ret = m41t93_wdt_stop(&m41t93->wdd);
+
+ return ret;
+}
+#endif
+
static struct spi_driver m41t93_driver;
static const struct regmap_config regmap_config = {
@@ -465,6 +559,11 @@ static int m41t93_probe(struct spi_device *spi)
if (ret)
dev_warn(&spi->dev, "Unable to register clock\n");
#endif
+#ifdef CONFIG_WATCHDOG
+ ret = m41t93_watchdog_register(&spi->dev, m41t93);
+ if (ret)
+ dev_warn(&spi->dev, "Unable to register watchdog\n");
+#endif
return 0;
}
--
2.34.1
^ permalink raw reply related
* [PATCH v3 5/6] rtc: m41t93: Add square wave clock provider support
From: Akhilesh Patil @ 2025-09-20 15:03 UTC (permalink / raw)
To: alexandre.belloni, krzk+dt, robh, conor+dt
Cc: skhan, linux-rtc, devicetree, linux-kernel, akhileshpatilvnit
In-Reply-To: <cover.1758379856.git.akhilesh@ee.iitb.ac.in>
Implement support to configure square wave output (SQW) of m41t93 rtc
via common clock framework clock provider api. Add clock provider
callbacks to control output frequency ranging from 1Hz to 32KHz as
supported by this rtc chip.
Use clock framework debugfs interface or clock consumer DT node to test.
Tested by measuring various frequencies on pull-up connected SWQ(7) pin
of m41t93 rtc chip using logic analyzer.
Signed-off-by: Akhilesh Patil <akhilesh@ee.iitb.ac.in>
---
drivers/rtc/rtc-m41t93.c | 156 ++++++++++++++++++++++++++++++++++++++-
1 file changed, 155 insertions(+), 1 deletion(-)
diff --git a/drivers/rtc/rtc-m41t93.c b/drivers/rtc/rtc-m41t93.c
index b86e7a12eba6..46703e32f212 100644
--- a/drivers/rtc/rtc-m41t93.c
+++ b/drivers/rtc/rtc-m41t93.c
@@ -13,6 +13,7 @@
#include <linux/rtc.h>
#include <linux/spi/spi.h>
#include <linux/regmap.h>
+#include <linux/clk-provider.h>
#define M41T93_REG_SSEC 0
#define M41T93_REG_ST_SEC 1
@@ -30,7 +31,11 @@
#define M41T93_BIT_A1IE BIT(7)
#define M41T93_BIT_ABE BIT(5)
#define M41T93_FLAG_AF1 BIT(6)
-
+#define M41T93_SRAM_BASE 0x19
+#define M41T93_REG_SQW 0x13
+#define M41T93_SQW_RS_MASK 0xf0
+#define M41T93_SQW_RS_SHIFT 4
+#define M41T93_BIT_SQWE BIT(6)
#define M41T93_REG_ALM_HOUR_HT 0xc
#define M41T93_REG_FLAGS 0xf
@@ -43,6 +48,9 @@
struct m41t93_data {
struct rtc_device *rtc;
struct regmap *regmap;
+#ifdef CONFIG_COMMON_CLK
+ struct clk_hw clks;
+#endif
};
static int m41t93_set_time(struct device *dev, struct rtc_time *tm)
@@ -264,6 +272,146 @@ static const struct rtc_class_ops m41t93_rtc_ops = {
.alarm_irq_enable = m41t93_alarm_irq_enable,
};
+#ifdef CONFIG_COMMON_CLK
+#define clk_sqw_to_m41t93_data(clk) \
+ container_of(clk, struct m41t93_data, clks)
+
+/* m41t93 RTC clock output support */
+static unsigned long m41t93_clk_rates[] = {
+ 0,
+ 32768, /* RS3:RS0 = 0b0001 */
+ 8192,
+ 4096,
+ 2048,
+ 1024,
+ 512,
+ 256,
+ 128,
+ 64,
+ 32,
+ 16,
+ 8,
+ 4,
+ 2,
+ 1, /* RS3:RS0 = 0b1111 */
+};
+
+static unsigned long m41t93_clk_sqw_recalc_rate(struct clk_hw *hw,
+ unsigned long parent_rate)
+{
+ int ret;
+ unsigned int rate_id;
+ struct m41t93_data *m41t93 = clk_sqw_to_m41t93_data(hw);
+
+ ret = regmap_read(m41t93->regmap, M41T93_REG_SQW, &rate_id);
+ if (ret)
+ return ret;
+
+ rate_id &= M41T93_SQW_RS_MASK;
+ rate_id >>= M41T93_SQW_RS_SHIFT;
+
+ return m41t93_clk_rates[rate_id];
+}
+
+static int m41t93_clk_sqw_determine_rate(struct clk_hw *hw,
+ struct clk_rate_request *req)
+{
+ int i;
+
+ for (i = 1; i < ARRAY_SIZE(m41t93_clk_rates); i++) {
+ if (req->rate >= m41t93_clk_rates[i]) {
+ req->rate = m41t93_clk_rates[i];
+ return 0;
+ }
+ }
+
+ return 0;
+}
+
+static int m41t93_clk_sqw_set_rate(struct clk_hw *hw, unsigned long rate,
+ unsigned long parent_rate)
+{
+ int id, ret;
+ struct m41t93_data *m41t93 = clk_sqw_to_m41t93_data(hw);
+
+ for (id = 0; id < ARRAY_SIZE(m41t93_clk_rates); id++) {
+ if (m41t93_clk_rates[id] == rate)
+ break;
+ }
+
+ if (id >= ARRAY_SIZE(m41t93_clk_rates))
+ return -EINVAL;
+
+ ret = regmap_update_bits(m41t93->regmap, M41T93_REG_SQW,
+ M41T93_SQW_RS_MASK, id << M41T93_SQW_RS_SHIFT);
+
+ return ret;
+}
+
+static int m41t93_clk_sqw_prepare(struct clk_hw *hw)
+{
+ int ret;
+ struct m41t93_data *m41t93 = clk_sqw_to_m41t93_data(hw);
+
+ ret = regmap_update_bits(m41t93->regmap, M41T93_REG_AL1_MONTH,
+ M41T93_BIT_SQWE, M41T93_BIT_SQWE);
+
+ return ret;
+}
+
+static void m41t93_clk_sqw_unprepare(struct clk_hw *hw)
+{
+ struct m41t93_data *m41t93 = clk_sqw_to_m41t93_data(hw);
+
+ regmap_update_bits(m41t93->regmap, M41T93_REG_AL1_MONTH,
+ M41T93_BIT_SQWE, 0);
+}
+
+static int m41t93_clk_sqw_is_prepared(struct clk_hw *hw)
+{
+ int ret;
+ struct m41t93_data *m41t93 = clk_sqw_to_m41t93_data(hw);
+ unsigned int status;
+
+ ret = regmap_read(m41t93->regmap, M41T93_REG_AL1_MONTH, &status);
+ if (ret)
+ return ret;
+
+ return !!(status & M41T93_BIT_SQWE);
+}
+
+static const struct clk_ops m41t93_clk_sqw_ops = {
+ .prepare = m41t93_clk_sqw_prepare,
+ .unprepare = m41t93_clk_sqw_unprepare,
+ .is_prepared = m41t93_clk_sqw_is_prepared,
+ .recalc_rate = m41t93_clk_sqw_recalc_rate,
+ .set_rate = m41t93_clk_sqw_set_rate,
+ .determine_rate = m41t93_clk_sqw_determine_rate,
+};
+
+static int rtc_m41t93_clks_register(struct device *dev, struct m41t93_data *m41t93)
+{
+ struct device_node *node = dev->of_node;
+ struct clk *clk;
+ struct clk_init_data init = {0};
+
+ init.name = "m41t93_clk_sqw";
+ init.ops = &m41t93_clk_sqw_ops;
+
+ m41t93->clks.init = &init;
+
+ /* Register the clock with CCF */
+ clk = devm_clk_register(dev, &m41t93->clks);
+ if (IS_ERR(clk))
+ return PTR_ERR(clk);
+
+ if (node)
+ of_clk_add_provider(node, of_clk_src_simple_get, clk);
+
+ return 0;
+}
+#endif
+
static struct spi_driver m41t93_driver;
static const struct regmap_config regmap_config = {
@@ -312,6 +460,12 @@ static int m41t93_probe(struct spi_device *spi)
if (IS_ERR(m41t93->rtc))
return PTR_ERR(m41t93->rtc);
+#ifdef CONFIG_COMMON_CLK
+ ret = rtc_m41t93_clks_register(&spi->dev, m41t93);
+ if (ret)
+ dev_warn(&spi->dev, "Unable to register clock\n");
+#endif
+
return 0;
}
--
2.34.1
^ permalink raw reply related
page: next (older) | prev (newer) | latest
- recent:[subjects (threaded)|topics (new)|topics (active)]
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox