* Re: [PATCH 7/7] clk: sunxi-ng: Add Allwinner A733 RTC CCU support
From: Junhui Liu @ 2026-04-10 9:49 UTC (permalink / raw)
To: wens, Junhui Liu
Cc: Michael Turquette, Stephen Boyd, Jernej Skrabec, Samuel Holland,
Alexandre Belloni, Rob Herring, Krzysztof Kozlowski, Conor Dooley,
Maxime Ripard, linux-clk, linux-arm-kernel, linux-sunxi,
linux-kernel, linux-rtc, devicetree, André Przywara
In-Reply-To: <CAGb2v64euL+QNXiJdTn0JygYLXg0WoguPSprKT4sKGZGVZbwug@mail.gmail.com>
On Sat Mar 28, 2026 at 10:41 PM CST, Chen-Yu Tsai wrote:
> On Wed, Jan 21, 2026 at 7:04 PM Junhui Liu <junhui.liu@pigmoral.tech> wrote:
>>
>> Add support for the internal CCU found in the RTC module of the Allwinner
>> A733 SoC. While the basic 16MHz (IOSC) and 32kHz logic remains compatible
>> with older SoCs like the sun6i, the A733 introduces several new features.
>>
>> The A733 RTC CCU supports choosing one of three external crystal
>> frequencies: 19.2MHz, 24MHz, and 26MHz. It features hardware detection
>> logic to automatically identify the frequency used on the board and
>> exports this DCXO signal as the "hosc" clock.
>>
>> Furthermore, the driver implements logic to derive a 32kHz reference
>> from the HOSC. This is achieved through a muxed clock path using fixed
>> pre-dividers to normalize the different crystal frequencies to ~32kHz.
>
> Have you tested whether the actually normalizes the frequency, i.e.
> selects a different divider based on the DCXO frequency? Otherwise
> we're just lying about the frequency.
I only have A733 boards with 26MHz crystals, so I couldn't test all
crystal configurations. However, I exported the "hosc_32k" clock
(referred to as dcxo24M_div32k_clk in the vendor driver) to a physical
pin via the fanout path and measured it with the oscilloscope.
Observations:
- Normal conditions: The frequency remains stable within the 32.744 kHz
to 32.791 kHz range.
- Forced condition: I grounded the R24 resistor on radxa A7A board to
trick the SoC into detecting a 24MHz crystal while the actual input
remained 26MHz. In this case, the frequency became unstable but still
stayed around the 32.2 kHz to 33.3 kHz range.
Based on these results, it appears the hardware does attempt to
normalize the frequency towards 32.768 kHz via some internal logic.
>
>> This path reuses the same hardware mux registers as the HOSC clock.
>>
>> Additionally, this CCU provides several gate clocks for specific
>> peripherals, including SerDes, HDMI, and UFS. The driver is implemented
>> as an auxiliary driver to be bound to the sun6i-rtc driver.
>>
>> Signed-off-by: Junhui Liu <junhui.liu@pigmoral.tech>
>> ---
>> drivers/clk/sunxi-ng/Kconfig | 5 +
>> drivers/clk/sunxi-ng/Makefile | 2 +
>> drivers/clk/sunxi-ng/ccu-sun60i-a733-rtc.c | 204 +++++++++++++++++++++++++++++
>> drivers/clk/sunxi-ng/ccu-sun60i-a733-rtc.h | 18 +++
>> drivers/clk/sunxi-ng/ccu_rtc.h | 7 +
>> 5 files changed, 236 insertions(+)
>>
[...]
>> +
>> +static const struct clk_parent_data hosc_parents[] = {
>> + { .fw_name = "osc24M" },
>> + { .fw_name = "osc19M" },
>> + { .fw_name = "osc26M" },
>> + { .fw_name = "osc24M" },
>> +};
>
> As mentioned in my reply to the binding, this is wrong. There is only
> one input.
>
> The most you can do is check the rate of the parent clock against the
> detected one, and _scream_ that the DT is wrong. And maybe override
> the reported frequency.
I will add a warning message if the frequency detected by the driver
does not match the one in the DT.
>
> If you want to do the latter, you could add a new fixed rate gated
> clock type to our library. You would fill in the rate before the
> clocks get registered. I probably wouldn't go that far. We want people
> to have correct hardware descriptions.
>
> Funnily enough Allwinner's BSP actually implements a fixed rate gate
> for the next 24M-to-32k divider clock.
Yes, I noticed that as well. I agree, and I will model this path as a
simple fixed-rate clock (32768Hz) in v2.
>
>> +
>> +struct ccu_mux hosc_clk = {
>> + .enable = DCXO_CTRL_DCXO_EN,
>> + .mux = _SUNXI_CCU_MUX(14, 2),
>> + .common = {
>> + .reg = DCXO_CTRL_REG,
>> + .hw.init = CLK_HW_INIT_PARENTS_DATA("hosc",
>> + hosc_parents,
>> + &ccu_mux_ro_ops,
>> + 0),
>> + },
>> +};
>
> So this is wrong.
>
>> +
>> +static const struct ccu_mux_fixed_prediv hosc_32k_predivs[] = {
>> + { .index = 0, .div = 732 },
>
> Why is it 732 instead of 750?
As mentioned above, the target frequency is 32.768kHz rather than
32.0kHz. However, since I will drop this prediv array and use a
fixed-rate clock instead, I think this will no longer be an issue.
--
Best regards,
Junhui Liu
^ permalink raw reply
* Re: [PATCH 1/7] dt-bindings: rtc: sun6i: Add Allwinner A733 support
From: Junhui Liu @ 2026-04-10 9:18 UTC (permalink / raw)
To: wens, Junhui Liu
Cc: Michael Turquette, Stephen Boyd, Jernej Skrabec, Samuel Holland,
Alexandre Belloni, Rob Herring, Krzysztof Kozlowski, Conor Dooley,
Maxime Ripard, linux-clk, linux-arm-kernel, linux-sunxi,
linux-kernel, linux-rtc, devicetree
In-Reply-To: <CAGb2v67844OPwE6VJ0PAs5LsmCa2h0FvXOBUomZ50dM5tZ0Zow@mail.gmail.com>
Hi ChenYu,
Thanks for your patient review.
On Sat Mar 28, 2026 at 8:37 PM CST, Chen-Yu Tsai wrote:
> On Wed, Jan 21, 2026 at 7:03 PM Junhui Liu <junhui.liu@pigmoral.tech> wrote:
>>
>> The RTC module in the Allwinner A733 SoC is functionally compatible with
>> the sun6i RTC, but its internal Clock Control Unit (CCU) has significant
>> changes.
>>
>> The A733 supports selecting the oscillator between three frequencies:
>> 19.2MHz, 24MHz, and 26MHz. The RTC CCU relies on hardware to detect
>> which frequency is actually used on the board. By defining all three
>> frequencies as fixed-clocks in the device tree, the driver can identify
>> the hardware-detected frequency and expose it to the rest of the system.
>
> No. The board device tree shall have the exact and correct frequency
> defined in the external crystal device node. The operating system can
> use the hardware-detected frequency to "fix" the in-system representation
> if it is off.
Okay, I will keep only one main external crystal in the device tree.
>
>> Additionally, the A733 RTC CCU provides several new DCXO gate clocks for
>> specific modules, including SerDes, HDMI, and UFS.
>>
>> Signed-off-by: Junhui Liu <junhui.liu@pigmoral.tech>
>> ---
>> .../bindings/rtc/allwinner,sun6i-a31-rtc.yaml | 38 ++++++++++++++++++++--
>> include/dt-bindings/clock/sun60i-a733-rtc.h | 16 +++++++++
>> 2 files changed, 52 insertions(+), 2 deletions(-)
>>
[...]
>> diff --git a/include/dt-bindings/clock/sun60i-a733-rtc.h b/include/dt-bindings/clock/sun60i-a733-rtc.h
>> new file mode 100644
>> index 000000000000..8a2b5facad73
>> --- /dev/null
>> +++ b/include/dt-bindings/clock/sun60i-a733-rtc.h
>> @@ -0,0 +1,16 @@
>> +/* SPDX-License-Identifier: GPL-2.0-only OR MIT */
>> +
>> +#ifndef _DT_BINDINGS_CLK_SUN60I_A733_RTC_H_
>> +#define _DT_BINDINGS_CLK_SUN60I_A733_RTC_H_
>> +
>> +#define CLK_IOSC 0
>> +#define CLK_OSC32K 1
>> +#define CLK_HOSC 2
>
> The DCXO enable control has been present since at least the H6. We just
> never added it, as we would never disable it anyway.
I will remove it.
>
> If you compare the RTC clock trees of the A733 and A523, the only addition
> besides the new gates seems to be the LOSC auto selection. But even that
> is just an illusion, as the A523 has the same registers for that.
>
> One could say the A733 RTC is almost backward compatible to the A523, if
> not for the two fastboot registers the A523 has at 0x120 and 0x124.
>
> So I ask that you try to integrate the differences into the existing
> driver and bindings. You can tweak and export internal clks if you
> need.
Okay, I will try to integrate the A733 RTC support into the existing
driver and bindings.
But first I would like to ask for your advice on how to correctly
organize the device tree binding header for the clocks? I have two ideas
in mind:
1. Add the common internal clocks (e.g., CLK_RTC_32K) to the existing
sun6i-rtc.h. Then, create a new sun60i-a733-rtc.h which includes
the old sun6i-rtc.h and appends the A733-specific clock gates.
2. Simply append all the new A733-specific clock IDs directly to the
bottom of the existing sun6i-rtc.h, sharing the same header file for all
SoCs utilizing this driver.
>
>> +#define CLK_RTC_32K 3
>
> AFAICT besides being an internal clock, this is also fed to GPIO for
> debounce? We probably need to expose this on the A523 as well.
>
I will do it.
>
> Thanks
> ChenYu
>
--
Best regards,
Junhui Liu
^ permalink raw reply
* Re: [PATCH 1/2] dt-bindings: rtc: nct3018y: add nuvoton,ctrl-reg-val property
From: Alexandre Belloni @ 2026-04-09 13:30 UTC (permalink / raw)
To: David Wang
Cc: Krzysztof Kozlowski, a.zummo, robh, krzk+dt, conor+dt, andrew,
avi.fishman, tmaimon77, tali.perry1, venture, yuenn, benjaminfair,
ctcchien, mimi05633, openbmc, linux-rtc, devicetree, linux-kernel,
davidwang
In-Reply-To: <CADSQSY1rAnZ69JAjosV_AWBw9OL77dyzHkewW5YGvpCZRwXq5A@mail.gmail.com>
On 09/04/2026 15:44:43+0800, David Wang wrote:
> On Apr 9, 2026, at 15:23, Krzysztof Kozlowski wrote:
> >
> > On 09/04/2026 09:21, David Wang wrote:
> > > Add "nuvoton,ctrl-reg-val" vendor property to allow optional
> > > initialization of the RTC control register (0x0A).
> > >
> > > This allows platform-specific configurations like 24h mode and
> > > write ownership to be defined via Device Tree.
> > >
> > > Signed-off-by: David Wang <tomato1220@gmail.com>
> > > ---
> > > Documentation/devicetree/bindings/rtc/nuvoton,nct3018y.yaml | 5 +++++
> > > 1 file changed, 5 insertions(+)
> > >
> > > diff --git a/Documentation/devicetree/bindings/rtc/nuvoton,nct3018y.yaml b/Documentation/devicetree/bindings/rtc/nuvoton,nct3018y.yaml
> > > index 4f9b5604acd9..0984dfb77170 100644
> > > --- a/Documentation/devicetree/bindings/rtc/nuvoton,nct3018y.yaml
> > > +++ b/Documentation/devicetree/bindings/rtc/nuvoton,nct3018y.yaml
> > > @@ -24,6 +24,10 @@ properties:
> > >
> > > reset-source: true
> > >
> > > + nuvoton,ctrl-reg-val:
> > > + $ref: /schemas/types.yaml#/definitions/uint32
> > > + description: Initial value for the control register (0x0A).
> >
> > 24h mode is not a property of a board. I don't know what "write
> > ownership" is.
> >
> > Best regards,
> > Krzysztof
>
> Hi Krzysztof,
>
> Thanks for your feedback. Let me clarify these two points based on the
> NCT3018Y datasheet:
> 1. Regarding "write ownership": The NCT3018Y features two I2C
> interfaces (Primary and Secondary). The TWO (Time Write Ownership) bit
> in the control register determines which interface has the authority
> to write to the RTC. We need to ensure the interface connected to our
> SoC is granted this ownership during probe—especially for factory-new
> chips—to ensure the RTC is writable.
You need a write-access property. For NXP, we settled with
nxp,write-access.
> 2. Regarding "24h mode": This bit determines the internal data format
> in which time is stored within the RTC hardware. Setting this ensures
> the hardware's internal storage layout matches the driver's
> expectation from the start.
The driver needs to always write 24h mode but can support reading both.
--
Alexandre Belloni, co-owner and COO, Bootlin
Embedded Linux and Kernel engineering
https://bootlin.com
^ permalink raw reply
* Re: [QUESTION] rtc: zynqmp: CALIB_RD reset behavior differs between ZynqMP and Versal
From: T, Harini @ 2026-04-09 11:11 UTC (permalink / raw)
To: Takumi Ando
Cc: Alexandre Belloni, Tomas Melin, linux-rtc@vger.kernel.org,
Simek, Michal, Yasushi SHOJI, kanta tamura
In-Reply-To: <CAJACUapT3cNwQtyE1zmQcGfDex2jmrbvvd9vOvZhC3v8+h3cZQ@mail.gmail.com>
Hi,
On 3/11/2026 12:22 PM, Takumi Ando wrote:
> [You don't often get email from takumi@spacecubics.com. Learn why this is important at https://aka.ms/LearnAboutSenderIdentification ]
>
> Caution: This message originated from an External Source. Use proper caution when opening attachments, clicking links, or responding.
>
>
> Hi Tomas,
>
> Thanks for the clarification.
>
> My understanding is that the fractional correction (fract_data) should
> indeed be managed from userspace since it represents oscillator drift
> and may change over time.
>
> However, the Max_Tick field seems to have a different role: it defines
> the number of RTC oscillator cycles corresponding to one second.
> For example, with a 32.768 kHz oscillator the value should be 32768-1.
>
> This is how I interpreted the documentation as well.
> In the AM012, the description of Max_Tick says that the
> register value multiplied by the oscillator period should equal one
> second, and it explicitly states that for a 32.768 kHz oscillator the
> value will be 0x7FFF.
>
> Because of this, it appears that Max_Tick depends only on the oscillator
> frequency and should not change dynamically like the fractional
> correction.
>
> Did I misunderstand the purpose of the Max_Tick field?
Your understanding of the Max_Tick field is correct. However, in the
driver's set_offset() implementation, the ppb offset is decomposed into
a whole-tick adjustment (which modifies the Max_Tick) and a
fractional-tick adjustment (fract_data).
Both fields are written together to the calibration register in a single
operation. This is what Tomas was referring to when he said both may change.
Since the crystal is never exactly 32.678 kHz and its frequency varies
with temperature and aging, userspace must always compute and apply
correct offset. When it does so via /sys/class/rtc/rtcX/offset, the
entire calibration register including Max_Tick is programmed to the
appropriate value.
Additionally writing Max_Tick unconditionally during probe would destroy
a valid calibration value that may have been preserved across a warm
reboot on a battery-backed RTC.
Thanks,
Harini T
>
> Best regards,
>
> 2026年3月11日(水) 14:23 Tomas Melin <tomas.melin@vaisala.com>:
>>
>> Hi,
>>
>> On 11/03/2026 05:19, Takumi Ando wrote:
>>> [You don't often get email from takumi@spacecubics.com. Learn why this is important at https://aka.ms/LearnAboutSenderIdentification ]
>>>
>>> Hi Tomas, Alexandre,
>>>
>>> Thank you for the explanations.
>>>
>>> So if I understand correctly, both on Zynq UltraScale+ and Versal,
>>> CALIB_RD may return a non-zero (or otherwise undefined) value after
>>> reset, meaning that it cannot reliably be used to determine whether
>>> the calibration register has already been initialized.
>>>
>>> While the fractional calibration should indeed be handled from
>>> userspace (e.g. via the RTC offset interface), it seems that the
>>> Max_Tick field should still always be programmed according to the
>>> value provided in Device Tree, since it depends only on the RTC
>>> oscillator frequency.
>>
>> Both max_tick and fract_data might change, it depends on how big
>>
>> the calibrator drift/offset is and if it is negative/positive.
>>
>>>
>>> Would it make sense for the driver to always program Max_Tick from the
>>> Device Tree "calibration" property while preserving the fractional
>>> calibration bits currently stored in hardware?
>>
>> As Alexandre mentioned, user space needs to ensure calibration is what
>> it should be.
>>
>>
>> thanks,
>>
>> Tomas
>>
>>
>>>
>>> If this approach sounds reasonable, I would like to prepare a patch
>>> for upstream.
>>>
>>> Best regards,
>>>
>>> 2026年3月6日(金) 20:13 Alexandre Belloni <alexandre.belloni@bootlin.com>:
>>>> On 06/03/2026 12:09:40+0200, Tomas Melin wrote:
>>>>>> On Zynq UltraScale+ Devices Register Reference (UG1087) [2],
>>>>>> CALIB_RD resets to 0, so the current logic works correctly there.
>>>>>> However, this assumption does not appear to hold for Versal.
>>>>> For Ultrascale+ the calibration register also gives random values after
>>>>> reset, perhaps you have noticed this:
>>>>> https://adaptivesupport.amd.com/s/article/000036886?language=en_US. Maybe
>>>>> the same can occur also on Versal.
>>>>>
>>>>> AFAIK there is no way of knowing if the value is correct or not after reset,
>>>>> so user space helpers might be needed to maintain the calibration value at a
>>>>> desired value.
>>>>>
>>>> Userspace is always needed to put the proper calibration, there is no
>>>> way for the kernel to know what value to put there. In the support case
>>>> above, the crystal will never be exactly 32768Hz and this value will
>>>> change over time and also depends on the temperature. The value always
>>>> needs to be computed, if your device can do NTP, chrony will provide the
>>>> proper offsets. If you don't have a way to measure the deviation, then
>>>> userspace can always forcefully set /sys/class/rtc/rtcX/offset if it
>>>> doesn't hold the correct value.
>>>> There is no need for devmem here.
>>>>
>>>> --
>>>> Alexandre Belloni, co-owner and COO, Bootlin
>>>> Embedded Linux and Kernel engineering
>>>> https://bootlin.com/
>>>
>>>
>>> --
>>> Takumi Ando
>>> Space Cubics Inc.
>
>
>
> --
> Takumi Ando
> Space Cubics Inc.
>
^ permalink raw reply
* Re: [PATCH 1/2] dt-bindings: rtc: nct3018y: add nuvoton,ctrl-reg-val property
From: David Wang @ 2026-04-09 7:44 UTC (permalink / raw)
To: Krzysztof Kozlowski
Cc: a.zummo, alexandre.belloni, robh, krzk+dt, conor+dt, andrew,
avi.fishman, tmaimon77, tali.perry1, venture, yuenn, benjaminfair,
ctcchien, mimi05633, openbmc, linux-rtc, devicetree, linux-kernel,
davidwang
In-Reply-To: <a1e24b69-b90a-47d7-b952-bca45fcc6281@kernel.org>
On Apr 9, 2026, at 15:23, Krzysztof Kozlowski wrote:
>
> On 09/04/2026 09:21, David Wang wrote:
> > Add "nuvoton,ctrl-reg-val" vendor property to allow optional
> > initialization of the RTC control register (0x0A).
> >
> > This allows platform-specific configurations like 24h mode and
> > write ownership to be defined via Device Tree.
> >
> > Signed-off-by: David Wang <tomato1220@gmail.com>
> > ---
> > Documentation/devicetree/bindings/rtc/nuvoton,nct3018y.yaml | 5 +++++
> > 1 file changed, 5 insertions(+)
> >
> > diff --git a/Documentation/devicetree/bindings/rtc/nuvoton,nct3018y.yaml b/Documentation/devicetree/bindings/rtc/nuvoton,nct3018y.yaml
> > index 4f9b5604acd9..0984dfb77170 100644
> > --- a/Documentation/devicetree/bindings/rtc/nuvoton,nct3018y.yaml
> > +++ b/Documentation/devicetree/bindings/rtc/nuvoton,nct3018y.yaml
> > @@ -24,6 +24,10 @@ properties:
> >
> > reset-source: true
> >
> > + nuvoton,ctrl-reg-val:
> > + $ref: /schemas/types.yaml#/definitions/uint32
> > + description: Initial value for the control register (0x0A).
>
> 24h mode is not a property of a board. I don't know what "write
> ownership" is.
>
> Best regards,
> Krzysztof
Hi Krzysztof,
Thanks for your feedback. Let me clarify these two points based on the
NCT3018Y datasheet:
1. Regarding "write ownership": The NCT3018Y features two I2C
interfaces (Primary and Secondary). The TWO (Time Write Ownership) bit
in the control register determines which interface has the authority
to write to the RTC. We need to ensure the interface connected to our
SoC is granted this ownership during probe—especially for factory-new
chips—to ensure the RTC is writable.
2. Regarding "24h mode": This bit determines the internal data format
in which time is stored within the RTC hardware. Setting this ensures
the hardware's internal storage layout matches the driver's
expectation from the start.
Best regards,
David Wang
^ permalink raw reply
* Re: [PATCH 1/2] dt-bindings: rtc: nct3018y: add nuvoton,ctrl-reg-val property
From: Krzysztof Kozlowski @ 2026-04-09 7:23 UTC (permalink / raw)
To: David Wang, a.zummo, alexandre.belloni, robh, krzk+dt, conor+dt
Cc: andrew, avi.fishman, tmaimon77, tali.perry1, venture, yuenn,
benjaminfair, ctcchien, mimi05633, openbmc, linux-rtc, devicetree,
linux-kernel, davidwang
In-Reply-To: <ba0845c590eda42a28b3799a6f40294ba74a726e.1775717959.git.tomato1220@gmail.com>
On 09/04/2026 09:21, David Wang wrote:
> Add "nuvoton,ctrl-reg-val" vendor property to allow optional
> initialization of the RTC control register (0x0A).
>
> This allows platform-specific configurations like 24h mode and
> write ownership to be defined via Device Tree.
>
> Signed-off-by: David Wang <tomato1220@gmail.com>
> ---
> Documentation/devicetree/bindings/rtc/nuvoton,nct3018y.yaml | 5 +++++
> 1 file changed, 5 insertions(+)
>
> diff --git a/Documentation/devicetree/bindings/rtc/nuvoton,nct3018y.yaml b/Documentation/devicetree/bindings/rtc/nuvoton,nct3018y.yaml
> index 4f9b5604acd9..0984dfb77170 100644
> --- a/Documentation/devicetree/bindings/rtc/nuvoton,nct3018y.yaml
> +++ b/Documentation/devicetree/bindings/rtc/nuvoton,nct3018y.yaml
> @@ -24,6 +24,10 @@ properties:
>
> reset-source: true
>
> + nuvoton,ctrl-reg-val:
> + $ref: /schemas/types.yaml#/definitions/uint32
> + description: Initial value for the control register (0x0A).
24h mode is not a property of a board. I don't know what "write
ownership" is.
Best regards,
Krzysztof
^ permalink raw reply
* [PATCH 2/2] rtc: nct3018y: add optional control register initialization
From: David Wang @ 2026-04-09 7:21 UTC (permalink / raw)
To: a.zummo, alexandre.belloni, robh, krzk+dt, conor+dt
Cc: andrew, avi.fishman, tmaimon77, tali.perry1, venture, yuenn,
benjaminfair, ctcchien, mimi05633, openbmc, linux-rtc, devicetree,
linux-kernel, davidwang, David Wang
In-Reply-To: <cover.1775717959.git.tomato1220@gmail.com>
Support the "nuvoton,ctrl-reg-val" Device Tree property to initialize
the RTC control register (0x0A) during the probe phase.
This provides flexibility for different platforms to override default
hardware settings.
Signed-off-by: David Wang <tomato1220@gmail.com>
---
drivers/rtc/rtc-nct3018y.c | 9 +++++++++
1 file changed, 9 insertions(+)
diff --git a/drivers/rtc/rtc-nct3018y.c b/drivers/rtc/rtc-nct3018y.c
index cd4b1db902e9..4bc47b4ac935 100644
--- a/drivers/rtc/rtc-nct3018y.c
+++ b/drivers/rtc/rtc-nct3018y.c
@@ -534,6 +534,15 @@ static int nct3018y_probe(struct i2c_client *client)
}
}
+ if (!of_property_read_u32(client->dev.of_node, "nuvoton,ctrl-reg-val", &flags)) {
+
+ err = i2c_smbus_write_byte_data(client, NCT3018Y_REG_CTRL, (u8)flags);
+ if (err < 0) {
+ dev_dbg(&client->dev, "Unable to write NCT3018Y_REG_CTRL.\n");
+ return err;
+ }
+ }
+
flags = 0;
err = i2c_smbus_write_byte_data(client, NCT3018Y_REG_ST, flags);
if (err < 0) {
--
2.34.1
^ permalink raw reply related
* [PATCH 1/2] dt-bindings: rtc: nct3018y: add nuvoton,ctrl-reg-val property
From: David Wang @ 2026-04-09 7:21 UTC (permalink / raw)
To: a.zummo, alexandre.belloni, robh, krzk+dt, conor+dt
Cc: andrew, avi.fishman, tmaimon77, tali.perry1, venture, yuenn,
benjaminfair, ctcchien, mimi05633, openbmc, linux-rtc, devicetree,
linux-kernel, davidwang, David Wang
In-Reply-To: <cover.1775717959.git.tomato1220@gmail.com>
Add "nuvoton,ctrl-reg-val" vendor property to allow optional
initialization of the RTC control register (0x0A).
This allows platform-specific configurations like 24h mode and
write ownership to be defined via Device Tree.
Signed-off-by: David Wang <tomato1220@gmail.com>
---
Documentation/devicetree/bindings/rtc/nuvoton,nct3018y.yaml | 5 +++++
1 file changed, 5 insertions(+)
diff --git a/Documentation/devicetree/bindings/rtc/nuvoton,nct3018y.yaml b/Documentation/devicetree/bindings/rtc/nuvoton,nct3018y.yaml
index 4f9b5604acd9..0984dfb77170 100644
--- a/Documentation/devicetree/bindings/rtc/nuvoton,nct3018y.yaml
+++ b/Documentation/devicetree/bindings/rtc/nuvoton,nct3018y.yaml
@@ -24,6 +24,10 @@ properties:
reset-source: true
+ nuvoton,ctrl-reg-val:
+ $ref: /schemas/types.yaml#/definitions/uint32
+ description: Initial value for the control register (0x0A).
+
required:
- compatible
- reg
@@ -39,6 +43,7 @@ examples:
rtc@6f {
compatible = "nuvoton,nct3018y";
reg = <0x6f>;
+ nuvoton,ctrl-reg-val = <0x21>;
};
};
--
2.34.1
^ permalink raw reply related
* [PATCH 0/2] rtc: nct3018y: add support for control register initialization
From: David Wang @ 2026-04-09 7:21 UTC (permalink / raw)
To: a.zummo, alexandre.belloni, robh, krzk+dt, conor+dt
Cc: andrew, avi.fishman, tmaimon77, tali.perry1, venture, yuenn,
benjaminfair, ctcchien, mimi05633, openbmc, linux-rtc, devicetree,
linux-kernel, davidwang, David Wang
This series adds support for an optional Device Tree property
"nuvoton,ctrl-reg-val" to initialize the RTC control register (0x0A).
This provides flexibility for different platforms (especially in
server environments) to configure behaviors such as 24h mode and
write ownership without driver source modifications.
David Wang (2):
dt-bindings: rtc: nct3018y: add nuvoton,ctrl-reg-val property
rtc: nct3018y: add optional control register initialization
.../devicetree/bindings/rtc/nuvoton,nct3018y.yaml | 5 +++++
drivers/rtc/rtc-nct3018y.c | 9 +++++++++
2 files changed, 14 insertions(+)
--
2.34.1
^ permalink raw reply
* Re: [PATCH v2 1/2] mfd: nct6694: Switch to devm_mfd_add_devices() and drop IDA
From: Bartosz Golaszewski @ 2026-04-08 7:25 UTC (permalink / raw)
To: a0282524688
Cc: tmyu0, linusw, linux, andi.shyti, lee, mkl, mailhol,
alexandre.belloni, wim, linux-kernel, linux-gpio, linux-i2c,
linux-can, netdev, linux-watchdog, linux-hwmon, linux-rtc,
linux-usb
In-Reply-To: <20260408053037.1867092-2-a0282524688@gmail.com>
On Wed, Apr 8, 2026 at 7:31 AM <a0282524688@gmail.com> wrote:
>
> From: Ming Yu <a0282524688@gmail.com>
>
> Currently, the nct6694 core driver uses mfd_add_hotplug_devices()
> and an IDA to manage subdevice IDs.
>
> Switch the core implementation to use the managed
> devm_mfd_add_devices() API, which simplifies the error handling and
> device lifecycle management. Concurrently, drop the custom IDA
> implementation and transition to using pdev->id.
>
> Signed-off-by: Ming Yu <a0282524688@gmail.com>
> ---
This does result in a nice code shrink but I'd split this commit into
two: one switching to using MFD_CELL_BASIC() with hard-coded devices
IDs and one completing the transition to devres.
Bart
^ permalink raw reply
* [PATCH v2 2/2] mfd: Add Host Interface (HIF) support for Nuvoton NCT6694
From: a0282524688 @ 2026-04-08 5:30 UTC (permalink / raw)
To: tmyu0, linusw, brgl, linux, andi.shyti, lee, mkl, mailhol,
alexandre.belloni, wim
Cc: linux-kernel, linux-gpio, linux-i2c, linux-can, netdev,
linux-watchdog, linux-hwmon, linux-rtc, linux-usb, Ming Yu
In-Reply-To: <20260408053037.1867092-1-a0282524688@gmail.com>
From: Ming Yu <a0282524688@gmail.com>
The Nuvoton NCT6694 also provides a Host Interface (HIF) via eSPI
to the host to access its features.
Sub-devices can use the common functions nct6694_read_msg() and
nct6694_write_msg() to issue a command. They can also request
interrupts that will be called when the HIF device triggers a
shared memory interrupt.
To support multiple transports, the driver configuration is
updated to allow selecting between the USB and HIF interfaces.
Signed-off-by: Ming Yu <a0282524688@gmail.com>
---
Changes since version 1:
- Drop function pointers from Super-I/O access and use static inline
helpers with proper types.
MAINTAINERS | 1 +
drivers/gpio/gpio-nct6694.c | 7 -
drivers/hwmon/nct6694-hwmon.c | 21 -
drivers/i2c/busses/i2c-nct6694.c | 7 -
drivers/mfd/Kconfig | 47 ++-
drivers/mfd/Makefile | 3 +-
drivers/mfd/nct6694-hif.c | 634 ++++++++++++++++++++++++++++
drivers/mfd/nct6694.c | 97 +++--
drivers/net/can/usb/nct6694_canfd.c | 6 -
drivers/rtc/rtc-nct6694.c | 7 -
drivers/watchdog/nct6694_wdt.c | 7 -
include/linux/mfd/nct6694.h | 51 ++-
12 files changed, 772 insertions(+), 116 deletions(-)
create mode 100644 drivers/mfd/nct6694-hif.c
diff --git a/MAINTAINERS b/MAINTAINERS
index c3fe46d7c4bc..7b6241faa6df 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -18899,6 +18899,7 @@ S: Supported
F: drivers/gpio/gpio-nct6694.c
F: drivers/hwmon/nct6694-hwmon.c
F: drivers/i2c/busses/i2c-nct6694.c
+F: drivers/mfd/nct6694-hif.c
F: drivers/mfd/nct6694.c
F: drivers/net/can/usb/nct6694_canfd.c
F: drivers/rtc/rtc-nct6694.c
diff --git a/drivers/gpio/gpio-nct6694.c b/drivers/gpio/gpio-nct6694.c
index 3703a61209e6..a279510ece89 100644
--- a/drivers/gpio/gpio-nct6694.c
+++ b/drivers/gpio/gpio-nct6694.c
@@ -12,13 +12,6 @@
#include <linux/module.h>
#include <linux/platform_device.h>
-/*
- * USB command module type for NCT6694 GPIO controller.
- * This defines the module type used for communication with the NCT6694
- * GPIO controller over the USB interface.
- */
-#define NCT6694_GPIO_MOD 0xFF
-
#define NCT6694_GPIO_VER 0x90
#define NCT6694_GPIO_VALID 0x110
#define NCT6694_GPI_DATA 0x120
diff --git a/drivers/hwmon/nct6694-hwmon.c b/drivers/hwmon/nct6694-hwmon.c
index 6dcf22ca5018..581451875f2c 100644
--- a/drivers/hwmon/nct6694-hwmon.c
+++ b/drivers/hwmon/nct6694-hwmon.c
@@ -15,13 +15,6 @@
#include <linux/platform_device.h>
#include <linux/slab.h>
-/*
- * USB command module type for NCT6694 report channel
- * This defines the module type used for communication with the NCT6694
- * report channel over the USB interface.
- */
-#define NCT6694_RPT_MOD 0xFF
-
/* Report channel */
/*
* The report channel is used to report the status of the hardware monitor
@@ -38,13 +31,6 @@
#define NCT6694_TIN_STS(x) (0x6A + (x))
#define NCT6694_FIN_STS(x) (0x6E + (x))
-/*
- * USB command module type for NCT6694 HWMON controller.
- * This defines the module type used for communication with the NCT6694
- * HWMON controller over the USB interface.
- */
-#define NCT6694_HWMON_MOD 0x00
-
/* Command 00h - Hardware Monitor Control */
#define NCT6694_HWMON_CONTROL 0x00
#define NCT6694_HWMON_CONTROL_SEL 0x00
@@ -53,13 +39,6 @@
#define NCT6694_HWMON_ALARM 0x02
#define NCT6694_HWMON_ALARM_SEL 0x00
-/*
- * USB command module type for NCT6694 PWM controller.
- * This defines the module type used for communication with the NCT6694
- * PWM controller over the USB interface.
- */
-#define NCT6694_PWM_MOD 0x01
-
/* PWM Command - Manual Control */
#define NCT6694_PWM_CONTROL 0x01
#define NCT6694_PWM_CONTROL_SEL 0x00
diff --git a/drivers/i2c/busses/i2c-nct6694.c b/drivers/i2c/busses/i2c-nct6694.c
index 7d8ad997f6d2..7ee209a04d16 100644
--- a/drivers/i2c/busses/i2c-nct6694.c
+++ b/drivers/i2c/busses/i2c-nct6694.c
@@ -11,13 +11,6 @@
#include <linux/module.h>
#include <linux/platform_device.h>
-/*
- * USB command module type for NCT6694 I2C controller.
- * This defines the module type used for communication with the NCT6694
- * I2C controller over the USB interface.
- */
-#define NCT6694_I2C_MOD 0x03
-
/* Command 00h - I2C Deliver */
#define NCT6694_I2C_DELIVER 0x00
#define NCT6694_I2C_DELIVER_SEL 0x00
diff --git a/drivers/mfd/Kconfig b/drivers/mfd/Kconfig
index 7192c9d1d268..8a715ec2f79f 100644
--- a/drivers/mfd/Kconfig
+++ b/drivers/mfd/Kconfig
@@ -1164,19 +1164,46 @@ config MFD_MENF21BMC
will be called menf21bmc.
config MFD_NCT6694
- tristate "Nuvoton NCT6694 support"
+ tristate
select MFD_CORE
+ help
+ Core MFD support for the Nuvoton NCT6694 peripheral expander.
+ This provides the common APIs and shared structures used by all
+ interfaces (USB, HIF) to access the NCT6694 hardware features
+ such as GPIO, I2C, CAN-FD, Watchdog, ADC, PWM, and RTC.
+
+ It is selected automatically by the transport interface drivers.
+
+config MFD_NCT6694_HIF
+ tristate "Nuvoton NCT6694 HIF (eSPI) interface support"
+ depends on HAS_IOPORT && ACPI
+ select MFD_NCT6694
+ select REGMAP_MMIO
+ help
+ This enables support for the Nuvoton NCT6694 peripheral expander
+ connected via the Host Interface (HIF) using eSPI transport.
+
+ The transport driver uses Super-I/O mapping and shared memory to
+ communicate with the NCT6694 firmware. Enable this option if you
+ are using the NCT6694 over an eSPI interface on an ACPI platform.
+
+ To compile this driver as a module, choose M here: the module
+ will be called nct6694-hif.
+
+config MFD_NCT6694_USB
+ tristate "Nuvoton NCT6694 USB interface support"
+ select MFD_NCT6694
depends on USB
help
- This enables support for the Nuvoton USB device NCT6694, which shares
- peripherals.
- The Nuvoton NCT6694 is a peripheral expander with 16 GPIO chips,
- 6 I2C controllers, 2 CANfd controllers, 2 Watchdog timers, ADC,
- PWM, and RTC.
- This driver provides core APIs to access the NCT6694 hardware
- monitoring and control features.
- Additional drivers must be enabled to utilize the specific
- functionalities of the device.
+ This enables support for the Nuvoton NCT6694 peripheral expander
+ connected via the USB interface.
+
+ The transport driver uses USB bulk and interrupt transfers to
+ communicate with the NCT6694 firmware. Enable this option if you
+ are using the NCT6694 via a USB connection.
+
+ To compile this driver as a module, choose M here: the module
+ will be called nct6694.
config MFD_OCELOT
tristate "Microsemi Ocelot External Control Support"
diff --git a/drivers/mfd/Makefile b/drivers/mfd/Makefile
index e75e8045c28a..4cee9b74978c 100644
--- a/drivers/mfd/Makefile
+++ b/drivers/mfd/Makefile
@@ -124,7 +124,8 @@ obj-$(CONFIG_MFD_MC13XXX_I2C) += mc13xxx-i2c.o
obj-$(CONFIG_MFD_PF1550) += pf1550.o
-obj-$(CONFIG_MFD_NCT6694) += nct6694.o
+obj-$(CONFIG_MFD_NCT6694_HIF) += nct6694-hif.o
+obj-$(CONFIG_MFD_NCT6694_USB) += nct6694.o
obj-$(CONFIG_MFD_CORE) += mfd-core.o
diff --git a/drivers/mfd/nct6694-hif.c b/drivers/mfd/nct6694-hif.c
new file mode 100644
index 000000000000..7560754e7481
--- /dev/null
+++ b/drivers/mfd/nct6694-hif.c
@@ -0,0 +1,634 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (C) 2026 Nuvoton Technology Corp.
+ *
+ * Nuvoton NCT6694 host-interface (eSPI) transport driver.
+ */
+
+#include <linux/acpi.h>
+#include <linux/bits.h>
+#include <linux/interrupt.h>
+#include <linux/io.h>
+#include <linux/iopoll.h>
+#include <linux/irq.h>
+#include <linux/irqdomain.h>
+#include <linux/kernel.h>
+#include <linux/mfd/core.h>
+#include <linux/mfd/nct6694.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/regmap.h>
+#include <linux/unaligned.h>
+
+#define DRVNAME "nct6694-hif"
+
+#define NCT6694_POLL_INTERVAL_US 10
+#define NCT6694_POLL_TIMEOUT_US 10000
+
+/*
+ * Super-I/O registers
+ */
+#define SIO_REG_LDSEL 0x07 /* Logical device select */
+#define SIO_REG_DEVID 0x20 /* Device ID (2 bytes) */
+#define SIO_REG_LD_SHM 0x0F /* Logical device shared memory control */
+
+#define SIO_REG_SHM_ENABLE 0x30 /* Enable shared memory */
+#define SIO_REG_SHM_BASE_ADDR 0x60 /* Shared memory base address (2 bytes) */
+#define SIO_REG_SHM_IRQ_NR 0x70 /* Shared memory interrupt number */
+
+#define SIO_REG_UNLOCK_KEY 0x87 /* Key to enable Super-I/O */
+#define SIO_REG_LOCK_KEY 0xAA /* Key to disable Super-I/O */
+
+#define SIO_NCT6694B_ID 0xD029
+#define SIO_NCT6694D_ID 0x5832
+
+/*
+ * Super-I/O Shared Memory Logical Device registers
+ */
+#define NCT6694_SHM_COFS_STS 0x2E
+#define NCT6694_SHM_COFS_STS_COFS4W BIT(7)
+
+#define NCT6694_SHM_COFS_CTL2 0x3B
+#define NCT6694_SHM_COFS_CTL2_COFS4W_IE BIT(3)
+
+#define NCT6694_SHM_INTR_STATUS 0x9C /* Interrupt status register (4 bytes) */
+
+enum nct6694_chips {
+ NCT6694B = 0,
+ NCT6694D,
+};
+
+enum nct6694_module_id {
+ NCT6694_GPIO0 = 0,
+ NCT6694_GPIO1,
+ NCT6694_GPIO2,
+ NCT6694_GPIO3,
+ NCT6694_GPIO4,
+ NCT6694_GPIO5,
+ NCT6694_GPIO6,
+ NCT6694_GPIO7,
+ NCT6694_GPIO8,
+ NCT6694_GPIO9,
+ NCT6694_GPIOA,
+ NCT6694_GPIOB,
+ NCT6694_GPIOC,
+ NCT6694_GPIOD,
+ NCT6694_GPIOE,
+ NCT6694_GPIOF,
+ NCT6694_I2C0,
+ NCT6694_I2C1,
+ NCT6694_I2C2,
+ NCT6694_I2C3,
+ NCT6694_I2C4,
+ NCT6694_I2C5,
+ NCT6694_CAN0,
+ NCT6694_CAN1,
+};
+
+struct __packed nct6694_msg {
+ struct nct6694_cmd_header cmd_header;
+ struct nct6694_response_header response_header;
+ unsigned char *data;
+};
+
+struct nct6694_sio_data {
+ enum nct6694_chips chip;
+ int sioreg; /* Super-I/O index port */
+};
+
+struct nct6694_hif_data {
+ struct regmap *regmap;
+ struct mutex msg_lock;
+ struct nct6694_sio_data *sio_data;
+ void __iomem *msg_base;
+ unsigned int shm_base;
+};
+
+static const char * const nct6694_chip_names[] = {
+ "NCT6694D",
+ "NCT6694B"
+};
+
+/*
+ * Super-I/O functions.
+ */
+static inline int superio_enter(struct nct6694_sio_data *sio_data)
+{
+ int ioreg = sio_data->sioreg;
+
+ /*
+ * Try to reserve <ioreg> and <ioreg + 1> for exclusive access.
+ */
+ if (!request_muxed_region(ioreg, 2, DRVNAME))
+ return -EBUSY;
+
+ outb(SIO_REG_UNLOCK_KEY, ioreg);
+ outb(SIO_REG_UNLOCK_KEY, ioreg);
+
+ return 0;
+}
+
+static inline void superio_exit(struct nct6694_sio_data *sio_data)
+{
+ int ioreg = sio_data->sioreg;
+
+ outb(SIO_REG_LOCK_KEY, ioreg);
+
+ release_region(ioreg, 2);
+}
+
+static inline void superio_select(struct nct6694_sio_data *sio_data, int ld)
+{
+ int ioreg = sio_data->sioreg;
+
+ outb(SIO_REG_LDSEL, ioreg);
+ outb(ld, ioreg + 1);
+}
+
+static inline int superio_inb(struct nct6694_sio_data *sio_data, int reg)
+{
+ int ioreg = sio_data->sioreg;
+
+ outb(reg, ioreg);
+ return inb(ioreg + 1);
+}
+
+static inline int superio_inw(struct nct6694_sio_data *sio_data, int reg)
+{
+ int ioreg = sio_data->sioreg;
+ int val;
+
+ outb(reg++, ioreg);
+ val = inb(ioreg + 1) << 8;
+ outb(reg, ioreg);
+ val |= inb(ioreg + 1);
+
+ return val;
+}
+
+static inline void superio_outb(struct nct6694_sio_data *sio_data, int reg, u8 val)
+{
+ int ioreg = sio_data->sioreg;
+
+ outb(reg, ioreg);
+ outb(val, ioreg + 1);
+}
+
+static int nct6694_sio_find(struct nct6694_sio_data *sio_data, u8 sioreg)
+{
+ int ret;
+ u16 devid;
+
+ sio_data->sioreg = sioreg;
+
+ ret = superio_enter(sio_data);
+ if (ret)
+ return ret;
+
+ /* Check Chip ID */
+ devid = superio_inw(sio_data, SIO_REG_DEVID);
+ switch (devid) {
+ case SIO_NCT6694B_ID:
+ sio_data->chip = NCT6694B;
+ break;
+ case SIO_NCT6694D_ID:
+ sio_data->chip = NCT6694D;
+ break;
+ default:
+ pr_err("Unsupported device 0x%04x\n", devid);
+ goto err;
+ }
+
+ pr_info("Found %s at %#x\n", nct6694_chip_names[sio_data->chip], sio_data->sioreg);
+
+ superio_exit(sio_data);
+
+ return 0;
+
+err:
+ superio_exit(sio_data);
+ return -ENODEV;
+}
+
+static const struct mfd_cell_acpi_match nct6694_acpi_match_gpio[] = {
+ { .adr = NCT6694_GPIO0 },
+ { .adr = NCT6694_GPIO1 },
+ { .adr = NCT6694_GPIO2 },
+ { .adr = NCT6694_GPIO3 },
+ { .adr = NCT6694_GPIO4 },
+ { .adr = NCT6694_GPIO5 },
+ { .adr = NCT6694_GPIO6 },
+ { .adr = NCT6694_GPIO7 },
+ { .adr = NCT6694_GPIO8 },
+ { .adr = NCT6694_GPIO9 },
+ { .adr = NCT6694_GPIOA },
+ { .adr = NCT6694_GPIOB },
+ { .adr = NCT6694_GPIOC },
+ { .adr = NCT6694_GPIOD },
+ { .adr = NCT6694_GPIOE },
+ { .adr = NCT6694_GPIOF },
+};
+
+static const struct mfd_cell_acpi_match nct6694_acpi_match_i2c[] = {
+ { .adr = NCT6694_I2C0 },
+ { .adr = NCT6694_I2C1 },
+ { .adr = NCT6694_I2C2 },
+ { .adr = NCT6694_I2C3 },
+ { .adr = NCT6694_I2C4 },
+ { .adr = NCT6694_I2C5 },
+};
+
+static const struct mfd_cell_acpi_match nct6694_acpi_match_can[] = {
+ { .adr = NCT6694_CAN0 },
+ { .adr = NCT6694_CAN1 },
+};
+
+static const struct mfd_cell nct6694_devs[] = {
+ MFD_CELL_ACPI("nct6694-gpio", NULL, NULL, 0, 0, &nct6694_acpi_match_gpio[0]),
+ MFD_CELL_ACPI("nct6694-gpio", NULL, NULL, 0, 1, &nct6694_acpi_match_gpio[1]),
+ MFD_CELL_ACPI("nct6694-gpio", NULL, NULL, 0, 2, &nct6694_acpi_match_gpio[2]),
+ MFD_CELL_ACPI("nct6694-gpio", NULL, NULL, 0, 3, &nct6694_acpi_match_gpio[3]),
+ MFD_CELL_ACPI("nct6694-gpio", NULL, NULL, 0, 4, &nct6694_acpi_match_gpio[4]),
+ MFD_CELL_ACPI("nct6694-gpio", NULL, NULL, 0, 5, &nct6694_acpi_match_gpio[5]),
+ MFD_CELL_ACPI("nct6694-gpio", NULL, NULL, 0, 6, &nct6694_acpi_match_gpio[6]),
+ MFD_CELL_ACPI("nct6694-gpio", NULL, NULL, 0, 7, &nct6694_acpi_match_gpio[7]),
+ MFD_CELL_ACPI("nct6694-gpio", NULL, NULL, 0, 8, &nct6694_acpi_match_gpio[8]),
+ MFD_CELL_ACPI("nct6694-gpio", NULL, NULL, 0, 9, &nct6694_acpi_match_gpio[9]),
+ MFD_CELL_ACPI("nct6694-gpio", NULL, NULL, 0, 10, &nct6694_acpi_match_gpio[10]),
+ MFD_CELL_ACPI("nct6694-gpio", NULL, NULL, 0, 11, &nct6694_acpi_match_gpio[11]),
+ MFD_CELL_ACPI("nct6694-gpio", NULL, NULL, 0, 12, &nct6694_acpi_match_gpio[12]),
+ MFD_CELL_ACPI("nct6694-gpio", NULL, NULL, 0, 13, &nct6694_acpi_match_gpio[13]),
+ MFD_CELL_ACPI("nct6694-gpio", NULL, NULL, 0, 14, &nct6694_acpi_match_gpio[14]),
+ MFD_CELL_ACPI("nct6694-gpio", NULL, NULL, 0, 15, &nct6694_acpi_match_gpio[15]),
+
+ MFD_CELL_ACPI("nct6694-i2c", NULL, NULL, 0, 0, &nct6694_acpi_match_i2c[0]),
+ MFD_CELL_ACPI("nct6694-i2c", NULL, NULL, 0, 1, &nct6694_acpi_match_i2c[1]),
+ MFD_CELL_ACPI("nct6694-i2c", NULL, NULL, 0, 2, &nct6694_acpi_match_i2c[2]),
+ MFD_CELL_ACPI("nct6694-i2c", NULL, NULL, 0, 3, &nct6694_acpi_match_i2c[3]),
+ MFD_CELL_ACPI("nct6694-i2c", NULL, NULL, 0, 4, &nct6694_acpi_match_i2c[4]),
+ MFD_CELL_ACPI("nct6694-i2c", NULL, NULL, 0, 5, &nct6694_acpi_match_i2c[5]),
+
+ MFD_CELL_ACPI("nct6694-canfd", NULL, NULL, 0, 0, &nct6694_acpi_match_can[0]),
+ MFD_CELL_ACPI("nct6694-canfd", NULL, NULL, 0, 1, &nct6694_acpi_match_can[1]),
+};
+
+static int nct6694_response_err_handling(struct nct6694 *nct6694, unsigned char err_status)
+{
+ switch (err_status) {
+ case NCT6694_NO_ERROR:
+ return 0;
+ case NCT6694_NOT_SUPPORT_ERROR:
+ dev_err(nct6694->dev, "Command is not supported!\n");
+ break;
+ case NCT6694_NO_RESPONSE_ERROR:
+ dev_warn(nct6694->dev, "Command received no response!\n");
+ break;
+ case NCT6694_TIMEOUT_ERROR:
+ dev_warn(nct6694->dev, "Command timed out!\n");
+ break;
+ case NCT6694_PENDING:
+ dev_err(nct6694->dev, "Command is pending!\n");
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ return -EIO;
+}
+
+static int nct6694_xfer_msg(struct nct6694 *nct6694,
+ const struct nct6694_cmd_header *cmd_hd,
+ u8 hctrl, void *buf)
+{
+ struct nct6694_hif_data *hdata = nct6694->priv;
+ void __iomem *hdr = hdata->msg_base + offsetof(struct nct6694_msg, cmd_header);
+ struct nct6694_cmd_header cmd = *cmd_hd;
+ struct nct6694_response_header resp;
+ u16 len = le16_to_cpu(cmd.len);
+ u8 status;
+ int ret;
+
+ guard(mutex)(&hdata->msg_lock);
+
+ /* Wait until the previous command is completed */
+ ret = readb_poll_timeout(hdr + offsetof(struct nct6694_cmd_header, hctrl),
+ status, status == 0, NCT6694_POLL_INTERVAL_US,
+ NCT6694_POLL_TIMEOUT_US);
+ if (ret)
+ return ret;
+
+ /*
+ * Write cmd header fields, but skip hctrl — writing to it triggers
+ * firmware command processing and must be deferred until data is ready.
+ */
+ memcpy_toio(hdr, &cmd, offsetof(struct nct6694_cmd_header, hctrl));
+ memcpy_toio(hdr + offsetof(struct nct6694_cmd_header, rsv2), &cmd.rsv2,
+ sizeof(cmd) - offsetof(struct nct6694_cmd_header, rsv2));
+
+ if (hctrl == NCT6694_HCTRL_SET && len)
+ memcpy_toio(hdata->msg_base + offsetof(struct nct6694_msg, data),
+ buf, len);
+
+ /* Write hctrl last to trigger command processing */
+ writeb(hctrl, hdr + offsetof(struct nct6694_cmd_header, hctrl));
+
+ ret = readb_poll_timeout(hdr + offsetof(struct nct6694_cmd_header, hctrl),
+ status, status == 0, NCT6694_POLL_INTERVAL_US,
+ NCT6694_POLL_TIMEOUT_US);
+ if (ret)
+ return ret;
+
+ memcpy_fromio(&resp, hdata->msg_base + offsetof(struct nct6694_msg, response_header),
+ sizeof(resp));
+
+ ret = nct6694_response_err_handling(nct6694, resp.sts);
+ if (ret)
+ return ret;
+
+ if (le16_to_cpu(resp.len))
+ memcpy_fromio(buf, hdata->msg_base + offsetof(struct nct6694_msg, data),
+ min(len, le16_to_cpu(resp.len)));
+
+ return 0;
+}
+
+/**
+ * nct6694_hif_read_msg() - Send a command and read response data via HIF
+ * @nct6694: NCT6694 device data
+ * @cmd_hd: command header
+ * @buf: buffer to store response data
+ *
+ * Return: 0 on success or negative errno on failure.
+ */
+static int nct6694_hif_read_msg(struct nct6694 *nct6694,
+ const struct nct6694_cmd_header *cmd_hd,
+ void *buf)
+{
+ struct nct6694_hif_data *hdata = nct6694->priv;
+
+ if (cmd_hd->mod == NCT6694_RPT_MOD)
+ return regmap_bulk_read(hdata->regmap,
+ le16_to_cpu(cmd_hd->offset),
+ buf, le16_to_cpu(cmd_hd->len));
+ return nct6694_xfer_msg(nct6694, cmd_hd, NCT6694_HCTRL_GET, buf);
+}
+
+/**
+ * nct6694_hif_write_msg() - Send a command with data payload via HIF
+ * @nct6694: NCT6694 device data
+ * @cmd_hd: command header
+ * @buf: buffer containing data to send
+ *
+ * Return: 0 on success or negative errno on failure.
+ */
+static int nct6694_hif_write_msg(struct nct6694 *nct6694,
+ const struct nct6694_cmd_header *cmd_hd,
+ void *buf)
+{
+ struct nct6694_hif_data *hdata = nct6694->priv;
+
+ if (cmd_hd->mod == NCT6694_RPT_MOD)
+ return regmap_bulk_write(hdata->regmap,
+ le16_to_cpu(cmd_hd->offset),
+ buf, le16_to_cpu(cmd_hd->len));
+ return nct6694_xfer_msg(nct6694, cmd_hd, NCT6694_HCTRL_SET, buf);
+}
+
+static const struct regmap_config nct6694_regmap_config = {
+ .reg_bits = 8,
+ .val_bits = 8,
+ .reg_stride = 1,
+};
+
+static irqreturn_t nct6694_irq_handler(int irq, void *data)
+{
+ struct nct6694 *nct6694 = data;
+ struct nct6694_hif_data *hdata = nct6694->priv;
+ u8 reg_data[4];
+ u32 intr_status;
+ int ret;
+
+ /* Check interrupt status is set */
+ if (!(inb(hdata->shm_base + NCT6694_SHM_COFS_STS) & NCT6694_SHM_COFS_STS_COFS4W))
+ return IRQ_NONE;
+
+ /* Clear interrupt status */
+ outb(NCT6694_SHM_COFS_STS_COFS4W, hdata->shm_base + NCT6694_SHM_COFS_STS);
+
+ ret = regmap_bulk_read(hdata->regmap, NCT6694_SHM_INTR_STATUS,
+ reg_data, ARRAY_SIZE(reg_data));
+ if (ret)
+ return IRQ_NONE;
+
+ intr_status = get_unaligned_le32(reg_data);
+
+ while (intr_status) {
+ int irq = __ffs(intr_status);
+
+ generic_handle_irq_safe(irq_find_mapping(nct6694->domain, irq));
+ intr_status &= ~BIT(irq);
+ }
+
+ return IRQ_HANDLED;
+}
+
+static void nct6694_irq_release(void *data)
+{
+ struct nct6694 *nct6694 = data;
+ struct nct6694_hif_data *hdata = nct6694->priv;
+ unsigned char cofs_ctl2;
+
+ /* Disable SIRQ interrupt */
+ cofs_ctl2 = inb(hdata->shm_base + NCT6694_SHM_COFS_CTL2);
+ cofs_ctl2 &= ~NCT6694_SHM_COFS_CTL2_COFS4W_IE;
+ outb(cofs_ctl2, hdata->shm_base + NCT6694_SHM_COFS_CTL2);
+}
+
+static int nct6694_irq_init(struct nct6694 *nct6694, int irq)
+{
+ struct nct6694_hif_data *hdata = nct6694->priv;
+ struct nct6694_sio_data *sio_data = hdata->sio_data;
+ unsigned char cofs_ctl2;
+
+ /* Set SIRQ number */
+ superio_enter(sio_data);
+ superio_select(sio_data, SIO_REG_LD_SHM);
+ if (!superio_inb(sio_data, SIO_REG_SHM_ENABLE)) {
+ superio_exit(sio_data);
+ return -EIO;
+ }
+ hdata->shm_base = superio_inw(sio_data, SIO_REG_SHM_BASE_ADDR);
+
+ superio_outb(sio_data, SIO_REG_SHM_IRQ_NR, irq);
+
+ superio_exit(sio_data);
+
+ /* Enable SIRQ interrupt */
+ cofs_ctl2 = inb(hdata->shm_base + NCT6694_SHM_COFS_CTL2);
+ cofs_ctl2 |= NCT6694_SHM_COFS_CTL2_COFS4W_IE;
+ outb(cofs_ctl2, hdata->shm_base + NCT6694_SHM_COFS_CTL2);
+
+ return 0;
+}
+
+static void nct6694_irq_enable(struct irq_data *data)
+{
+ struct nct6694 *nct6694 = irq_data_get_irq_chip_data(data);
+ irq_hw_number_t hwirq = irqd_to_hwirq(data);
+
+ guard(spinlock_irqsave)(&nct6694->irq_lock);
+
+ nct6694->irq_enable |= BIT(hwirq);
+}
+
+static void nct6694_irq_disable(struct irq_data *data)
+{
+ struct nct6694 *nct6694 = irq_data_get_irq_chip_data(data);
+ irq_hw_number_t hwirq = irqd_to_hwirq(data);
+
+ guard(spinlock_irqsave)(&nct6694->irq_lock);
+
+ nct6694->irq_enable &= ~BIT(hwirq);
+}
+
+static const struct irq_chip nct6694_irq_chip = {
+ .name = "nct6694-irq",
+ .flags = IRQCHIP_SKIP_SET_WAKE,
+ .irq_enable = nct6694_irq_enable,
+ .irq_disable = nct6694_irq_disable,
+};
+
+static void nct6694_irq_domain_remove(void *data)
+{
+ struct nct6694 *nct6694 = data;
+
+ irq_domain_remove(nct6694->domain);
+}
+
+static int nct6694_irq_domain_map(struct irq_domain *d, unsigned int irq, irq_hw_number_t hw)
+{
+ struct nct6694 *nct6694 = d->host_data;
+
+ irq_set_chip_data(irq, nct6694);
+ irq_set_chip_and_handler(irq, &nct6694_irq_chip, handle_simple_irq);
+
+ return 0;
+}
+
+static void nct6694_irq_domain_unmap(struct irq_domain *d, unsigned int irq)
+{
+ irq_set_chip_and_handler(irq, NULL, NULL);
+ irq_set_chip_data(irq, NULL);
+}
+
+static const struct irq_domain_ops nct6694_irq_domain_ops = {
+ .map = nct6694_irq_domain_map,
+ .unmap = nct6694_irq_domain_unmap,
+};
+
+static const u8 sio_addrs[] = { 0x2e, 0x4e };
+
+static int nct6694_probe(struct platform_device *pdev)
+{
+ struct device *dev = &pdev->dev;
+ struct nct6694_sio_data *sio_data;
+ struct nct6694_hif_data *hdata;
+ struct nct6694 *data;
+ void __iomem *rpt_base, *msg_base;
+ int ret, i, irq;
+
+ sio_data = devm_kzalloc(dev, sizeof(*sio_data), GFP_KERNEL);
+ if (!sio_data)
+ return -ENOMEM;
+
+ data = devm_kzalloc(dev, sizeof(*data), GFP_KERNEL);
+ if (!data)
+ return -ENOMEM;
+
+ hdata = devm_kzalloc(dev, sizeof(*hdata), GFP_KERNEL);
+ if (!hdata)
+ return -ENOMEM;
+
+ rpt_base = devm_platform_ioremap_resource(pdev, 0);
+ if (IS_ERR(rpt_base))
+ return PTR_ERR(rpt_base);
+ msg_base = devm_platform_ioremap_resource(pdev, 1);
+ if (IS_ERR(msg_base))
+ return PTR_ERR(msg_base);
+
+ irq = platform_get_irq(pdev, 0);
+ if (irq < 0)
+ return irq;
+
+ for (i = 0; i < ARRAY_SIZE(sio_addrs); i++) {
+ ret = nct6694_sio_find(sio_data, sio_addrs[i]);
+ if (!ret)
+ break;
+ }
+ if (ret)
+ return ret;
+
+ hdata->sio_data = sio_data;
+ hdata->msg_base = msg_base;
+ hdata->regmap = devm_regmap_init_mmio(dev, rpt_base,
+ &nct6694_regmap_config);
+ if (IS_ERR(hdata->regmap))
+ return PTR_ERR(hdata->regmap);
+
+ data->dev = dev;
+ data->priv = hdata;
+ data->read_msg = nct6694_hif_read_msg;
+ data->write_msg = nct6694_hif_write_msg;
+
+ spin_lock_init(&data->irq_lock);
+
+ data->domain = irq_domain_create_simple(NULL, NCT6694_NR_IRQS, 0,
+ &nct6694_irq_domain_ops,
+ data);
+ if (!data->domain)
+ return -ENODEV;
+
+ ret = devm_add_action_or_reset(dev, nct6694_irq_domain_remove, data);
+ if (ret)
+ return ret;
+
+ ret = nct6694_irq_init(data, irq);
+ if (ret)
+ return ret;
+
+ ret = devm_add_action_or_reset(dev, nct6694_irq_release, data);
+ if (ret)
+ return ret;
+
+ ret = devm_request_threaded_irq(dev, irq, NULL, nct6694_irq_handler,
+ IRQF_ONESHOT | IRQF_SHARED,
+ dev_name(dev), data);
+ if (ret)
+ return ret;
+
+ ret = devm_mutex_init(dev, &hdata->msg_lock);
+ if (ret)
+ return ret;
+
+ platform_set_drvdata(pdev, data);
+
+ return devm_mfd_add_devices(dev, 0, nct6694_devs, ARRAY_SIZE(nct6694_devs), NULL, 0, NULL);
+}
+
+static const struct acpi_device_id nct6694_acpi_ids[] = {
+ { "NTN0538", 0 },
+ {}
+};
+
+static struct platform_driver nct6694_driver = {
+ .driver = {
+ .name = DRVNAME,
+ .acpi_match_table = nct6694_acpi_ids,
+ },
+ .probe = nct6694_probe,
+};
+module_platform_driver(nct6694_driver);
+
+MODULE_DESCRIPTION("Nuvoton NCT6694 host-interface transport driver");
+MODULE_AUTHOR("Ming Yu <tmyu0@nuvoton.com>");
+MODULE_LICENSE("GPL");
diff --git a/drivers/mfd/nct6694.c b/drivers/mfd/nct6694.c
index 8ce2c4985aab..903a0a7f0694 100644
--- a/drivers/mfd/nct6694.c
+++ b/drivers/mfd/nct6694.c
@@ -21,6 +21,27 @@
#include <linux/spinlock.h>
#include <linux/usb.h>
+#define NCT6694_VENDOR_ID 0x0416
+#define NCT6694_PRODUCT_ID 0x200B
+#define NCT6694_INT_IN_EP 0x81
+#define NCT6694_BULK_IN_EP 0x02
+#define NCT6694_BULK_OUT_EP 0x03
+
+#define NCT6694_URB_TIMEOUT 1000
+
+union __packed nct6694_usb_msg {
+ struct nct6694_cmd_header cmd_header;
+ struct nct6694_response_header response_header;
+};
+
+struct nct6694_usb_data {
+ struct mutex access_lock;
+ struct urb *int_in_urb;
+ struct usb_device *udev;
+ union nct6694_usb_msg *usb_msg;
+ __le32 *int_buffer;
+};
+
static const struct mfd_cell nct6694_devs[] = {
MFD_CELL_BASIC("nct6694-gpio", NULL, NULL, 0, 0),
MFD_CELL_BASIC("nct6694-gpio", NULL, NULL, 0, 1),
@@ -57,7 +78,8 @@ static const struct mfd_cell nct6694_devs[] = {
MFD_CELL_NAME("nct6694-rtc"),
};
-static int nct6694_response_err_handling(struct nct6694 *nct6694, unsigned char err_status)
+static int nct6694_usb_err_handling(struct nct6694 *nct6694,
+ unsigned char err_status)
{
switch (err_status) {
case NCT6694_NO_ERROR:
@@ -82,7 +104,7 @@ static int nct6694_response_err_handling(struct nct6694 *nct6694, unsigned char
}
/**
- * nct6694_read_msg() - Read message from NCT6694 device
+ * nct6694_usb_read_msg() - Read message from NCT6694 device via USB
* @nct6694: NCT6694 device pointer
* @cmd_hd: command header structure
* @buf: buffer to store the response data
@@ -93,13 +115,16 @@ static int nct6694_response_err_handling(struct nct6694 *nct6694, unsigned char
*
* Return: Negative value on error or 0 on success.
*/
-int nct6694_read_msg(struct nct6694 *nct6694, const struct nct6694_cmd_header *cmd_hd, void *buf)
+static int nct6694_usb_read_msg(struct nct6694 *nct6694,
+ const struct nct6694_cmd_header *cmd_hd,
+ void *buf)
{
- union nct6694_usb_msg *msg = nct6694->usb_msg;
- struct usb_device *udev = nct6694->udev;
+ struct nct6694_usb_data *udata = nct6694->priv;
+ union nct6694_usb_msg *msg = udata->usb_msg;
+ struct usb_device *udev = udata->udev;
int tx_len, rx_len, ret;
- guard(mutex)(&nct6694->access_lock);
+ guard(mutex)(&udata->access_lock);
memcpy(&msg->cmd_header, cmd_hd, sizeof(*cmd_hd));
msg->cmd_header.hctrl = NCT6694_HCTRL_GET;
@@ -128,12 +153,11 @@ int nct6694_read_msg(struct nct6694 *nct6694, const struct nct6694_cmd_header *c
return -EIO;
}
- return nct6694_response_err_handling(nct6694, msg->response_header.sts);
+ return nct6694_usb_err_handling(nct6694, msg->response_header.sts);
}
-EXPORT_SYMBOL_GPL(nct6694_read_msg);
/**
- * nct6694_write_msg() - Write message to NCT6694 device
+ * nct6694_usb_write_msg() - Write message to NCT6694 device via USB
* @nct6694: NCT6694 device pointer
* @cmd_hd: command header structure
* @buf: buffer containing the data to be sent
@@ -143,13 +167,16 @@ EXPORT_SYMBOL_GPL(nct6694_read_msg);
*
* Return: Negative value on error or 0 on success.
*/
-int nct6694_write_msg(struct nct6694 *nct6694, const struct nct6694_cmd_header *cmd_hd, void *buf)
+static int nct6694_usb_write_msg(struct nct6694 *nct6694,
+ const struct nct6694_cmd_header *cmd_hd,
+ void *buf)
{
- union nct6694_usb_msg *msg = nct6694->usb_msg;
- struct usb_device *udev = nct6694->udev;
+ struct nct6694_usb_data *udata = nct6694->priv;
+ union nct6694_usb_msg *msg = udata->usb_msg;
+ struct usb_device *udev = udata->udev;
int tx_len, rx_len, ret;
- guard(mutex)(&nct6694->access_lock);
+ guard(mutex)(&udata->access_lock);
memcpy(&msg->cmd_header, cmd_hd, sizeof(*cmd_hd));
msg->cmd_header.hctrl = NCT6694_HCTRL_SET;
@@ -184,9 +211,8 @@ int nct6694_write_msg(struct nct6694 *nct6694, const struct nct6694_cmd_header *
return -EIO;
}
- return nct6694_response_err_handling(nct6694, msg->response_header.sts);
+ return nct6694_usb_err_handling(nct6694, msg->response_header.sts);
}
-EXPORT_SYMBOL_GPL(nct6694_write_msg);
static void usb_int_callback(struct urb *urb)
{
@@ -276,6 +302,7 @@ static int nct6694_usb_probe(struct usb_interface *iface,
struct usb_endpoint_descriptor *int_endpoint;
struct usb_host_interface *interface;
struct device *dev = &iface->dev;
+ struct nct6694_usb_data *udata;
struct nct6694 *nct6694;
int ret;
@@ -283,18 +310,28 @@ static int nct6694_usb_probe(struct usb_interface *iface,
if (!nct6694)
return -ENOMEM;
- nct6694->usb_msg = devm_kzalloc(dev, sizeof(union nct6694_usb_msg), GFP_KERNEL);
- if (!nct6694->usb_msg)
+ udata = devm_kzalloc(dev, sizeof(*udata), GFP_KERNEL);
+ if (!udata)
+ return -ENOMEM;
+
+ udata->usb_msg = devm_kzalloc(dev, sizeof(*udata->usb_msg), GFP_KERNEL);
+ if (!udata->usb_msg)
return -ENOMEM;
- nct6694->int_buffer = devm_kzalloc(dev, sizeof(*nct6694->int_buffer), GFP_KERNEL);
- if (!nct6694->int_buffer)
+ udata->int_buffer = devm_kzalloc(dev, sizeof(*udata->int_buffer), GFP_KERNEL);
+ if (!udata->int_buffer)
return -ENOMEM;
- nct6694->int_in_urb = usb_alloc_urb(0, GFP_KERNEL);
- if (!nct6694->int_in_urb)
+ udata->int_in_urb = usb_alloc_urb(0, GFP_KERNEL);
+ if (!udata->int_in_urb)
return -ENOMEM;
+ udata->udev = udev;
+
+ nct6694->priv = udata;
+ nct6694->read_msg = nct6694_usb_read_msg;
+ nct6694->write_msg = nct6694_usb_write_msg;
+
nct6694->domain = irq_domain_create_simple(NULL, NCT6694_NR_IRQS, 0,
&nct6694_irq_domain_ops,
nct6694);
@@ -304,11 +341,10 @@ static int nct6694_usb_probe(struct usb_interface *iface,
}
nct6694->dev = dev;
- nct6694->udev = udev;
spin_lock_init(&nct6694->irq_lock);
- ret = devm_mutex_init(dev, &nct6694->access_lock);
+ ret = devm_mutex_init(dev, &udata->access_lock);
if (ret)
goto err_irq_domain;
@@ -320,11 +356,11 @@ static int nct6694_usb_probe(struct usb_interface *iface,
goto err_irq_domain;
}
- usb_fill_int_urb(nct6694->int_in_urb, udev, usb_rcvintpipe(udev, NCT6694_INT_IN_EP),
- nct6694->int_buffer, sizeof(*nct6694->int_buffer), usb_int_callback,
+ usb_fill_int_urb(udata->int_in_urb, udev, usb_rcvintpipe(udev, NCT6694_INT_IN_EP),
+ udata->int_buffer, sizeof(*udata->int_buffer), usb_int_callback,
nct6694, int_endpoint->bInterval);
- ret = usb_submit_urb(nct6694->int_in_urb, GFP_KERNEL);
+ ret = usb_submit_urb(udata->int_in_urb, GFP_KERNEL);
if (ret)
goto err_irq_domain;
@@ -337,21 +373,22 @@ static int nct6694_usb_probe(struct usb_interface *iface,
return 0;
err_mfd:
- usb_kill_urb(nct6694->int_in_urb);
+ usb_kill_urb(udata->int_in_urb);
err_irq_domain:
irq_domain_remove(nct6694->domain);
err_urb:
- usb_free_urb(nct6694->int_in_urb);
+ usb_free_urb(udata->int_in_urb);
return ret;
}
static void nct6694_usb_disconnect(struct usb_interface *iface)
{
struct nct6694 *nct6694 = usb_get_intfdata(iface);
+ struct nct6694_usb_data *udata = nct6694->priv;
- usb_kill_urb(nct6694->int_in_urb);
+ usb_kill_urb(udata->int_in_urb);
irq_domain_remove(nct6694->domain);
- usb_free_urb(nct6694->int_in_urb);
+ usb_free_urb(udata->int_in_urb);
}
static const struct usb_device_id nct6694_ids[] = {
diff --git a/drivers/net/can/usb/nct6694_canfd.c b/drivers/net/can/usb/nct6694_canfd.c
index 29282c56430f..05db00455f63 100644
--- a/drivers/net/can/usb/nct6694_canfd.c
+++ b/drivers/net/can/usb/nct6694_canfd.c
@@ -17,12 +17,6 @@
#define DEVICE_NAME "nct6694-canfd"
-/* USB command module type for NCT6694 CANfd controller.
- * This defines the module type used for communication with the NCT6694
- * CANfd controller over the USB interface.
- */
-#define NCT6694_CANFD_MOD 0x05
-
/* Command 00h - CAN Setting and Initialization */
#define NCT6694_CANFD_SETTING 0x00
#define NCT6694_CANFD_SETTING_ACTIVE_CTRL1 BIT(0)
diff --git a/drivers/rtc/rtc-nct6694.c b/drivers/rtc/rtc-nct6694.c
index 35401a0d9cf5..c06902f150c9 100644
--- a/drivers/rtc/rtc-nct6694.c
+++ b/drivers/rtc/rtc-nct6694.c
@@ -14,13 +14,6 @@
#include <linux/rtc.h>
#include <linux/slab.h>
-/*
- * USB command module type for NCT6694 RTC controller.
- * This defines the module type used for communication with the NCT6694
- * RTC controller over the USB interface.
- */
-#define NCT6694_RTC_MOD 0x08
-
/* Command 00h - RTC Time */
#define NCT6694_RTC_TIME 0x0000
#define NCT6694_RTC_TIME_SEL 0x00
diff --git a/drivers/watchdog/nct6694_wdt.c b/drivers/watchdog/nct6694_wdt.c
index 2b4b804a1739..847d8f1d1830 100644
--- a/drivers/watchdog/nct6694_wdt.c
+++ b/drivers/watchdog/nct6694_wdt.c
@@ -19,13 +19,6 @@
#define NCT6694_WDT_MAX_DEVS 2
-/*
- * USB command module type for NCT6694 WDT controller.
- * This defines the module type used for communication with the NCT6694
- * WDT controller over the USB interface.
- */
-#define NCT6694_WDT_MOD 0x07
-
/* Command 00h - WDT Setup */
#define NCT6694_WDT_SETUP 0x00
#define NCT6694_WDT_SETUP_SEL(idx) (idx ? 0x01 : 0x00)
diff --git a/include/linux/mfd/nct6694.h b/include/linux/mfd/nct6694.h
index 496da72949d9..ff0814dc82d4 100644
--- a/include/linux/mfd/nct6694.h
+++ b/include/linux/mfd/nct6694.h
@@ -2,7 +2,8 @@
/*
* Copyright (C) 2025 Nuvoton Technology Corp.
*
- * Nuvoton NCT6694 USB transaction and data structure.
+ * Nuvoton NCT6694 core definitions shared by all transport drivers
+ * and sub-device drivers.
*/
#ifndef __MFD_NCT6694_H
@@ -12,16 +13,17 @@
#include <linux/spinlock.h>
#include <linux/types.h>
-#define NCT6694_VENDOR_ID 0x0416
-#define NCT6694_PRODUCT_ID 0x200B
-#define NCT6694_INT_IN_EP 0x81
-#define NCT6694_BULK_IN_EP 0x02
-#define NCT6694_BULK_OUT_EP 0x03
-
#define NCT6694_HCTRL_SET 0x40
#define NCT6694_HCTRL_GET 0x80
-#define NCT6694_URB_TIMEOUT 1000
+#define NCT6694_HWMON_MOD 0x00
+#define NCT6694_PWM_MOD 0x01
+#define NCT6694_I2C_MOD 0x03
+#define NCT6694_CANFD_MOD 0x05
+#define NCT6694_WDT_MOD 0x07
+#define NCT6694_RTC_MOD 0x08
+#define NCT6694_RPT_MOD 0xFF
+#define NCT6694_GPIO_MOD NCT6694_RPT_MOD
enum nct6694_irq_id {
NCT6694_IRQ_GPIO0 = 0,
@@ -79,24 +81,33 @@ struct __packed nct6694_response_header {
__le16 len;
};
-union __packed nct6694_usb_msg {
- struct nct6694_cmd_header cmd_header;
- struct nct6694_response_header response_header;
-};
-
struct nct6694 {
struct device *dev;
struct irq_domain *domain;
- struct mutex access_lock;
spinlock_t irq_lock;
- struct urb *int_in_urb;
- struct usb_device *udev;
- union nct6694_usb_msg *usb_msg;
- __le32 *int_buffer;
unsigned int irq_enable;
+
+ void *priv;
+ int (*read_msg)(struct nct6694 *nct6694,
+ const struct nct6694_cmd_header *cmd_hd,
+ void *buf);
+ int (*write_msg)(struct nct6694 *nct6694,
+ const struct nct6694_cmd_header *cmd_hd,
+ void *buf);
};
-int nct6694_read_msg(struct nct6694 *nct6694, const struct nct6694_cmd_header *cmd_hd, void *buf);
-int nct6694_write_msg(struct nct6694 *nct6694, const struct nct6694_cmd_header *cmd_hd, void *buf);
+static inline int nct6694_read_msg(struct nct6694 *nct6694,
+ const struct nct6694_cmd_header *cmd_hd,
+ void *buf)
+{
+ return nct6694->read_msg(nct6694, cmd_hd, buf);
+}
+
+static inline int nct6694_write_msg(struct nct6694 *nct6694,
+ const struct nct6694_cmd_header *cmd_hd,
+ void *buf)
+{
+ return nct6694->write_msg(nct6694, cmd_hd, buf);
+}
#endif
--
2.34.1
^ permalink raw reply related
* [PATCH v2 1/2] mfd: nct6694: Switch to devm_mfd_add_devices() and drop IDA
From: a0282524688 @ 2026-04-08 5:30 UTC (permalink / raw)
To: tmyu0, linusw, brgl, linux, andi.shyti, lee, mkl, mailhol,
alexandre.belloni, wim
Cc: linux-kernel, linux-gpio, linux-i2c, linux-can, netdev,
linux-watchdog, linux-hwmon, linux-rtc, linux-usb, Ming Yu
In-Reply-To: <20260408053037.1867092-1-a0282524688@gmail.com>
From: Ming Yu <a0282524688@gmail.com>
Currently, the nct6694 core driver uses mfd_add_hotplug_devices()
and an IDA to manage subdevice IDs.
Switch the core implementation to use the managed
devm_mfd_add_devices() API, which simplifies the error handling and
device lifecycle management. Concurrently, drop the custom IDA
implementation and transition to using pdev->id.
Signed-off-by: Ming Yu <a0282524688@gmail.com>
---
drivers/gpio/gpio-nct6694.c | 19 +------
drivers/i2c/busses/i2c-nct6694.c | 19 +------
drivers/mfd/nct6694.c | 83 ++++++++++++-----------------
drivers/net/can/usb/nct6694_canfd.c | 12 +----
drivers/watchdog/nct6694_wdt.c | 20 +------
include/linux/mfd/nct6694.h | 8 +--
6 files changed, 43 insertions(+), 118 deletions(-)
diff --git a/drivers/gpio/gpio-nct6694.c b/drivers/gpio/gpio-nct6694.c
index a8607f0d9915..3703a61209e6 100644
--- a/drivers/gpio/gpio-nct6694.c
+++ b/drivers/gpio/gpio-nct6694.c
@@ -7,7 +7,6 @@
#include <linux/bits.h>
#include <linux/gpio/driver.h>
-#include <linux/idr.h>
#include <linux/interrupt.h>
#include <linux/mfd/nct6694.h>
#include <linux/module.h>
@@ -381,14 +380,6 @@ static void nct6694_irq_dispose_mapping(void *d)
irq_dispose_mapping(data->irq);
}
-static void nct6694_gpio_ida_free(void *d)
-{
- struct nct6694_gpio_data *data = d;
- struct nct6694 *nct6694 = data->nct6694;
-
- ida_free(&nct6694->gpio_ida, data->group);
-}
-
static int nct6694_gpio_probe(struct platform_device *pdev)
{
struct device *dev = &pdev->dev;
@@ -403,15 +394,7 @@ static int nct6694_gpio_probe(struct platform_device *pdev)
return -ENOMEM;
data->nct6694 = nct6694;
-
- ret = ida_alloc(&nct6694->gpio_ida, GFP_KERNEL);
- if (ret < 0)
- return ret;
- data->group = ret;
-
- ret = devm_add_action_or_reset(dev, nct6694_gpio_ida_free, data);
- if (ret)
- return ret;
+ data->group = pdev->id;
names = devm_kcalloc(dev, NCT6694_NR_GPIO, sizeof(char *),
GFP_KERNEL);
diff --git a/drivers/i2c/busses/i2c-nct6694.c b/drivers/i2c/busses/i2c-nct6694.c
index 1413ab6f9462..7d8ad997f6d2 100644
--- a/drivers/i2c/busses/i2c-nct6694.c
+++ b/drivers/i2c/busses/i2c-nct6694.c
@@ -6,7 +6,6 @@
*/
#include <linux/i2c.h>
-#include <linux/idr.h>
#include <linux/kernel.h>
#include <linux/mfd/nct6694.h>
#include <linux/module.h>
@@ -134,14 +133,6 @@ static int nct6694_i2c_set_baudrate(struct nct6694_i2c_data *data)
return 0;
}
-static void nct6694_i2c_ida_free(void *d)
-{
- struct nct6694_i2c_data *data = d;
- struct nct6694 *nct6694 = data->nct6694;
-
- ida_free(&nct6694->i2c_ida, data->port);
-}
-
static int nct6694_i2c_probe(struct platform_device *pdev)
{
struct device *dev = &pdev->dev;
@@ -155,15 +146,7 @@ static int nct6694_i2c_probe(struct platform_device *pdev)
data->dev = dev;
data->nct6694 = nct6694;
-
- ret = ida_alloc(&nct6694->i2c_ida, GFP_KERNEL);
- if (ret < 0)
- return ret;
- data->port = ret;
-
- ret = devm_add_action_or_reset(dev, nct6694_i2c_ida_free, data);
- if (ret)
- return ret;
+ data->port = pdev->id;
ret = nct6694_i2c_set_baudrate(data);
if (ret)
diff --git a/drivers/mfd/nct6694.c b/drivers/mfd/nct6694.c
index 308b2fda3055..8ce2c4985aab 100644
--- a/drivers/mfd/nct6694.c
+++ b/drivers/mfd/nct6694.c
@@ -11,7 +11,6 @@
#include <linux/bits.h>
#include <linux/interrupt.h>
-#include <linux/idr.h>
#include <linux/irq.h>
#include <linux/irqdomain.h>
#include <linux/kernel.h>
@@ -23,35 +22,35 @@
#include <linux/usb.h>
static const struct mfd_cell nct6694_devs[] = {
- MFD_CELL_NAME("nct6694-gpio"),
- MFD_CELL_NAME("nct6694-gpio"),
- MFD_CELL_NAME("nct6694-gpio"),
- MFD_CELL_NAME("nct6694-gpio"),
- MFD_CELL_NAME("nct6694-gpio"),
- MFD_CELL_NAME("nct6694-gpio"),
- MFD_CELL_NAME("nct6694-gpio"),
- MFD_CELL_NAME("nct6694-gpio"),
- MFD_CELL_NAME("nct6694-gpio"),
- MFD_CELL_NAME("nct6694-gpio"),
- MFD_CELL_NAME("nct6694-gpio"),
- MFD_CELL_NAME("nct6694-gpio"),
- MFD_CELL_NAME("nct6694-gpio"),
- MFD_CELL_NAME("nct6694-gpio"),
- MFD_CELL_NAME("nct6694-gpio"),
- MFD_CELL_NAME("nct6694-gpio"),
-
- MFD_CELL_NAME("nct6694-i2c"),
- MFD_CELL_NAME("nct6694-i2c"),
- MFD_CELL_NAME("nct6694-i2c"),
- MFD_CELL_NAME("nct6694-i2c"),
- MFD_CELL_NAME("nct6694-i2c"),
- MFD_CELL_NAME("nct6694-i2c"),
-
- MFD_CELL_NAME("nct6694-canfd"),
- MFD_CELL_NAME("nct6694-canfd"),
-
- MFD_CELL_NAME("nct6694-wdt"),
- MFD_CELL_NAME("nct6694-wdt"),
+ MFD_CELL_BASIC("nct6694-gpio", NULL, NULL, 0, 0),
+ MFD_CELL_BASIC("nct6694-gpio", NULL, NULL, 0, 1),
+ MFD_CELL_BASIC("nct6694-gpio", NULL, NULL, 0, 2),
+ MFD_CELL_BASIC("nct6694-gpio", NULL, NULL, 0, 3),
+ MFD_CELL_BASIC("nct6694-gpio", NULL, NULL, 0, 4),
+ MFD_CELL_BASIC("nct6694-gpio", NULL, NULL, 0, 5),
+ MFD_CELL_BASIC("nct6694-gpio", NULL, NULL, 0, 6),
+ MFD_CELL_BASIC("nct6694-gpio", NULL, NULL, 0, 7),
+ MFD_CELL_BASIC("nct6694-gpio", NULL, NULL, 0, 8),
+ MFD_CELL_BASIC("nct6694-gpio", NULL, NULL, 0, 9),
+ MFD_CELL_BASIC("nct6694-gpio", NULL, NULL, 0, 10),
+ MFD_CELL_BASIC("nct6694-gpio", NULL, NULL, 0, 11),
+ MFD_CELL_BASIC("nct6694-gpio", NULL, NULL, 0, 12),
+ MFD_CELL_BASIC("nct6694-gpio", NULL, NULL, 0, 13),
+ MFD_CELL_BASIC("nct6694-gpio", NULL, NULL, 0, 14),
+ MFD_CELL_BASIC("nct6694-gpio", NULL, NULL, 0, 15),
+
+ MFD_CELL_BASIC("nct6694-i2c", NULL, NULL, 0, 0),
+ MFD_CELL_BASIC("nct6694-i2c", NULL, NULL, 0, 1),
+ MFD_CELL_BASIC("nct6694-i2c", NULL, NULL, 0, 2),
+ MFD_CELL_BASIC("nct6694-i2c", NULL, NULL, 0, 3),
+ MFD_CELL_BASIC("nct6694-i2c", NULL, NULL, 0, 4),
+ MFD_CELL_BASIC("nct6694-i2c", NULL, NULL, 0, 5),
+
+ MFD_CELL_BASIC("nct6694-canfd", NULL, NULL, 0, 0),
+ MFD_CELL_BASIC("nct6694-canfd", NULL, NULL, 0, 1),
+
+ MFD_CELL_BASIC("nct6694-wdt", NULL, NULL, 0, 0),
+ MFD_CELL_BASIC("nct6694-wdt", NULL, NULL, 0, 1),
MFD_CELL_NAME("nct6694-hwmon"),
@@ -307,23 +306,18 @@ static int nct6694_usb_probe(struct usb_interface *iface,
nct6694->dev = dev;
nct6694->udev = udev;
- ida_init(&nct6694->gpio_ida);
- ida_init(&nct6694->i2c_ida);
- ida_init(&nct6694->canfd_ida);
- ida_init(&nct6694->wdt_ida);
-
spin_lock_init(&nct6694->irq_lock);
ret = devm_mutex_init(dev, &nct6694->access_lock);
if (ret)
- goto err_ida;
+ goto err_irq_domain;
interface = iface->cur_altsetting;
int_endpoint = &interface->endpoint[0].desc;
if (!usb_endpoint_is_int_in(int_endpoint)) {
ret = -ENODEV;
- goto err_ida;
+ goto err_irq_domain;
}
usb_fill_int_urb(nct6694->int_in_urb, udev, usb_rcvintpipe(udev, NCT6694_INT_IN_EP),
@@ -332,11 +326,11 @@ static int nct6694_usb_probe(struct usb_interface *iface,
ret = usb_submit_urb(nct6694->int_in_urb, GFP_KERNEL);
if (ret)
- goto err_ida;
+ goto err_irq_domain;
usb_set_intfdata(iface, nct6694);
- ret = mfd_add_hotplug_devices(dev, nct6694_devs, ARRAY_SIZE(nct6694_devs));
+ ret = devm_mfd_add_devices(dev, 0, nct6694_devs, ARRAY_SIZE(nct6694_devs), NULL, 0, NULL);
if (ret)
goto err_mfd;
@@ -344,11 +338,7 @@ static int nct6694_usb_probe(struct usb_interface *iface,
err_mfd:
usb_kill_urb(nct6694->int_in_urb);
-err_ida:
- ida_destroy(&nct6694->wdt_ida);
- ida_destroy(&nct6694->canfd_ida);
- ida_destroy(&nct6694->i2c_ida);
- ida_destroy(&nct6694->gpio_ida);
+err_irq_domain:
irq_domain_remove(nct6694->domain);
err_urb:
usb_free_urb(nct6694->int_in_urb);
@@ -359,12 +349,7 @@ static void nct6694_usb_disconnect(struct usb_interface *iface)
{
struct nct6694 *nct6694 = usb_get_intfdata(iface);
- mfd_remove_devices(nct6694->dev);
usb_kill_urb(nct6694->int_in_urb);
- ida_destroy(&nct6694->wdt_ida);
- ida_destroy(&nct6694->canfd_ida);
- ida_destroy(&nct6694->i2c_ida);
- ida_destroy(&nct6694->gpio_ida);
irq_domain_remove(nct6694->domain);
usb_free_urb(nct6694->int_in_urb);
}
diff --git a/drivers/net/can/usb/nct6694_canfd.c b/drivers/net/can/usb/nct6694_canfd.c
index e5f7f8849a73..29282c56430f 100644
--- a/drivers/net/can/usb/nct6694_canfd.c
+++ b/drivers/net/can/usb/nct6694_canfd.c
@@ -8,7 +8,6 @@
#include <linux/can/dev.h>
#include <linux/can/rx-offload.h>
#include <linux/ethtool.h>
-#include <linux/idr.h>
#include <linux/irqdomain.h>
#include <linux/kernel.h>
#include <linux/mfd/nct6694.h>
@@ -725,15 +724,13 @@ static int nct6694_canfd_probe(struct platform_device *pdev)
struct net_device *ndev;
int port, irq, ret, can_clk;
- port = ida_alloc(&nct6694->canfd_ida, GFP_KERNEL);
- if (port < 0)
- return port;
+ port = pdev->id;
irq = irq_create_mapping(nct6694->domain,
NCT6694_IRQ_CAN0 + port);
if (!irq) {
ret = -EINVAL;
- goto free_ida;
+ return ret;
}
ndev = alloc_candev(sizeof(struct nct6694_canfd_priv), 1);
@@ -796,24 +793,19 @@ static int nct6694_canfd_probe(struct platform_device *pdev)
free_candev(ndev);
dispose_irq:
irq_dispose_mapping(irq);
-free_ida:
- ida_free(&nct6694->canfd_ida, port);
return ret;
}
static void nct6694_canfd_remove(struct platform_device *pdev)
{
struct nct6694_canfd_priv *priv = platform_get_drvdata(pdev);
- struct nct6694 *nct6694 = priv->nct6694;
struct net_device *ndev = priv->ndev;
- int port = ndev->dev_port;
int irq = ndev->irq;
unregister_candev(ndev);
can_rx_offload_del(&priv->offload);
free_candev(ndev);
irq_dispose_mapping(irq);
- ida_free(&nct6694->canfd_ida, port);
}
static struct platform_driver nct6694_canfd_driver = {
diff --git a/drivers/watchdog/nct6694_wdt.c b/drivers/watchdog/nct6694_wdt.c
index bc3689bd4b6b..2b4b804a1739 100644
--- a/drivers/watchdog/nct6694_wdt.c
+++ b/drivers/watchdog/nct6694_wdt.c
@@ -5,7 +5,6 @@
* Copyright (C) 2025 Nuvoton Technology Corp.
*/
-#include <linux/idr.h>
#include <linux/kernel.h>
#include <linux/mfd/nct6694.h>
#include <linux/module.h>
@@ -233,21 +232,12 @@ static const struct watchdog_ops nct6694_wdt_ops = {
.ping = nct6694_wdt_ping,
};
-static void nct6694_wdt_ida_free(void *d)
-{
- struct nct6694_wdt_data *data = d;
- struct nct6694 *nct6694 = data->nct6694;
-
- ida_free(&nct6694->wdt_ida, data->wdev_idx);
-}
-
static int nct6694_wdt_probe(struct platform_device *pdev)
{
struct device *dev = &pdev->dev;
struct nct6694 *nct6694 = dev_get_drvdata(dev->parent);
struct nct6694_wdt_data *data;
struct watchdog_device *wdev;
- int ret;
data = devm_kzalloc(dev, sizeof(*data), GFP_KERNEL);
if (!data)
@@ -260,15 +250,7 @@ static int nct6694_wdt_probe(struct platform_device *pdev)
data->dev = dev;
data->nct6694 = nct6694;
-
- ret = ida_alloc(&nct6694->wdt_ida, GFP_KERNEL);
- if (ret < 0)
- return ret;
- data->wdev_idx = ret;
-
- ret = devm_add_action_or_reset(dev, nct6694_wdt_ida_free, data);
- if (ret)
- return ret;
+ data->wdev_idx = pdev->id;
wdev = &data->wdev;
wdev->info = &nct6694_wdt_info;
diff --git a/include/linux/mfd/nct6694.h b/include/linux/mfd/nct6694.h
index 6eb9be2cd4a0..496da72949d9 100644
--- a/include/linux/mfd/nct6694.h
+++ b/include/linux/mfd/nct6694.h
@@ -8,6 +8,10 @@
#ifndef __MFD_NCT6694_H
#define __MFD_NCT6694_H
+#include <linux/mutex.h>
+#include <linux/spinlock.h>
+#include <linux/types.h>
+
#define NCT6694_VENDOR_ID 0x0416
#define NCT6694_PRODUCT_ID 0x200B
#define NCT6694_INT_IN_EP 0x81
@@ -82,10 +86,6 @@ union __packed nct6694_usb_msg {
struct nct6694 {
struct device *dev;
- struct ida gpio_ida;
- struct ida i2c_ida;
- struct ida canfd_ida;
- struct ida wdt_ida;
struct irq_domain *domain;
struct mutex access_lock;
spinlock_t irq_lock;
--
2.34.1
^ permalink raw reply related
* [PATCH v2 0/2] mfd: nct6694: Refactor transport layer and add HIF (eSPI) support
From: a0282524688 @ 2026-04-08 5:30 UTC (permalink / raw)
To: tmyu0, linusw, brgl, linux, andi.shyti, lee, mkl, mailhol,
alexandre.belloni, wim
Cc: linux-kernel, linux-gpio, linux-i2c, linux-can, netdev,
linux-watchdog, linux-hwmon, linux-rtc, linux-usb, Ming Yu
From: Ming Yu <a0282524688@gmail.com>
The Nuvoton NCT6694 is a peripheral expander that provides GPIO, I2C,
CAN-FD, Watchdog, HWMON, PWM, and RTC sub-devices. Currently, the
driver only supports USB as the host transport interface.
This series refactors the NCT6694 MFD core to support multiple transport
backends and adds a new Host Interface (HIF) transport driver that
communicates over eSPI using Super-I/O shared memory.
Changes since version 1:
- Reworked the Super-I/O access helpers.
Ming Yu (2):
mfd: nct6694: Switch to devm_mfd_add_devices() and drop IDA
mfd: Add Host Interface (HIF) support for Nuvoton NCT6694
MAINTAINERS | 1 +
drivers/gpio/gpio-nct6694.c | 26 +-
drivers/hwmon/nct6694-hwmon.c | 21 -
drivers/i2c/busses/i2c-nct6694.c | 26 +-
drivers/mfd/Kconfig | 47 ++-
drivers/mfd/Makefile | 3 +-
drivers/mfd/nct6694-hif.c | 634 ++++++++++++++++++++++++++++
drivers/mfd/nct6694.c | 180 ++++----
drivers/net/can/usb/nct6694_canfd.c | 18 +-
drivers/rtc/rtc-nct6694.c | 7 -
drivers/watchdog/nct6694_wdt.c | 27 +-
include/linux/mfd/nct6694.h | 57 ++-
12 files changed, 814 insertions(+), 233 deletions(-)
create mode 100644 drivers/mfd/nct6694-hif.c
--
2.34.1
^ permalink raw reply
* [PATCH] rtc: ntxec: fix OF node reference imbalance
From: Johan Hovold @ 2026-04-07 12:27 UTC (permalink / raw)
To: Jonathan Neuschäfer, Alexandre Belloni
Cc: linux-rtc, linux-kernel, Johan Hovold, stable
The driver reuses the OF node of the parent multi-function device but
fails to take another reference to balance the one dropped by the
platform bus code when unbinding the MFD and deregistering the child
devices.
Fix this by using the intended helper for reusing OF nodes.
Fixes: 435af89786c6 ("rtc: New driver for RTC in Netronix embedded controller")
Cc: stable@vger.kernel.org # 5.13
Cc: Jonathan Neuschäfer <j.neuschaefer@gmx.net>
Signed-off-by: Johan Hovold <johan@kernel.org>
---
drivers/rtc/rtc-ntxec.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/drivers/rtc/rtc-ntxec.c b/drivers/rtc/rtc-ntxec.c
index 850ca49186fd..d28ddb34e19e 100644
--- a/drivers/rtc/rtc-ntxec.c
+++ b/drivers/rtc/rtc-ntxec.c
@@ -110,7 +110,7 @@ static int ntxec_rtc_probe(struct platform_device *pdev)
struct rtc_device *dev;
struct ntxec_rtc *rtc;
- pdev->dev.of_node = pdev->dev.parent->of_node;
+ device_set_of_node_from_dev(&pdev->dev, pdev->dev.parent);
rtc = devm_kzalloc(&pdev->dev, sizeof(*rtc), GFP_KERNEL);
if (!rtc)
--
2.52.0
^ permalink raw reply related
* Re: [PATCH] dt-bindings: rtc: moxa,moxart-rtc: convert to YAML
From: Krzysztof Kozlowski @ 2026-04-06 8:44 UTC (permalink / raw)
To: Avi Radinsky
Cc: alexandre.belloni, robh, krzk+dt, conor+dt, linux-rtc, devicetree,
linux-kernel
In-Reply-To: <CAK=E+3BLMV35g1hC2=aQ57yKxgw1y8qR8ufpHQdKcx4MdT9ioA@mail.gmail.com>
On Sun, Apr 05, 2026 at 09:31:36PM -0400, Avi Radinsky wrote:
> Convert the MOXA ART Real Time Clock text binding to YAML schema.
>
Same comments as for other try.
Also, do not duplicate work.
I don't find hopping on this entire GSoC program, while doing duplicated
and uncoordinated work with same issues, helpful.
Best regards,
Krzysztof
^ permalink raw reply
* [PATCH] dt-bindings: rtc: moxa,moxart-rtc: convert to YAML
From: Avi Radinsky @ 2026-04-06 1:31 UTC (permalink / raw)
To: alexandre.belloni, robh
Cc: krzk+dt, conor+dt, linux-rtc, devicetree, linux-kernel
Convert the MOXA ART Real Time Clock text binding to YAML schema.
Signed-off-by: Avi Radinsky <avi.radinsky@gmail.com>
---
.../bindings/rtc/moxa,moxart-rtc.txt | 17 --------
.../bindings/rtc/moxa,moxart-rtc.yaml | 43 +++++++++++++++++++
2 files changed, 43 insertions(+), 17 deletions(-)
delete mode 100644 Documentation/devicetree/bindings/rtc/moxa,moxart-rtc.txt
create mode 100644 Documentation/devicetree/bindings/rtc/moxa,moxart-rtc.yaml
diff --git a/Documentation/devicetree/bindings/rtc/moxa,moxart-rtc.txt
b/Documentation/devicetree/bindings/rtc/moxa,moxart-rtc.txt
deleted file mode 100644
index 1374df7bf9d6..000000000000
--- a/Documentation/devicetree/bindings/rtc/moxa,moxart-rtc.txt
+++ /dev/null
@@ -1,17 +0,0 @@
-MOXA ART real-time clock
-
-Required properties:
-
-- compatible : Should be "moxa,moxart-rtc"
-- rtc-sclk-gpios : RTC sclk gpio, with zero flags
-- rtc-data-gpios : RTC data gpio, with zero flags
-- rtc-reset-gpios : RTC reset gpio, with zero flags
-
-Example:
-
- rtc: rtc {
- compatible = "moxa,moxart-rtc";
- rtc-sclk-gpios = <&gpio 5 0>;
- rtc-data-gpios = <&gpio 6 0>;
- rtc-reset-gpios = <&gpio 7 0>;
- };
diff --git a/Documentation/devicetree/bindings/rtc/moxa,moxart-rtc.yaml
b/Documentation/devicetree/bindings/rtc/moxa,moxart-rtc.yaml
new file mode 100644
index 000000000000..9693c96a9f27
--- /dev/null
+++ b/Documentation/devicetree/bindings/rtc/moxa,moxart-rtc.yaml
@@ -0,0 +1,43 @@
+# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/rtc/moxa,moxart-rtc.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: MOXA ART Real Time Clock
+
+maintainers:
+ - Alexandre Belloni <alexandre.belloni@bootlin.com>
+
+properties:
+ compatible:
+ const: moxa,moxart-rtc
+
+ rtc-sclk-gpios:
+ maxItems: 1
+ description: GPIO line for the RTC serial clock.
+
+ rtc-data-gpios:
+ maxItems: 1
+ description: GPIO line for the RTC data input/output.
+
+ rtc-reset-gpios:
+ maxItems: 1
+ description: GPIO line for the RTC reset.
+
+required:
+ - compatible
+ - rtc-sclk-gpios
+ - rtc-data-gpios
+ - rtc-reset-gpios
+
+additionalProperties: false
+
+examples:
+ - |
+ rtc {
+ compatible = "moxa,moxart-rtc";
+ rtc-sclk-gpios = <&gpio 5 0>;
+ rtc-data-gpios = <&gpio 6 0>;
+ rtc-reset-gpios = <&gpio 7 0>;
+ };
--
2.51.0
^ permalink raw reply related
* Re: [PATCH] rtc: cmos: Remove redundant include of linux/acpi.h
From: Alexandre Belloni @ 2026-04-04 10:19 UTC (permalink / raw)
To: Chen Ni; +Cc: linux-rtc
In-Reply-To: <177523251878.1559844.5790356423146303538.b4-ty@b4>
On 03/04/2026 18:08:50+0200, Alexandre Belloni wrote:
> On Wed, 04 Mar 2026 10:35:33 +0800, Chen Ni wrote:
> > The header file <linux/acpi.h> is already included globally at the top
> > of the file. The second inclusion inside the #ifdef CONFIG_ACPI block is
> > redundant because the header uses include guards to prevent multiple
> > inclusions.
> >
> > Remove the duplicate line to clean up the code and slightly reduce
> > preprocessing overhead.
> >
> > [...]
>
> Applied, thanks!
>
> [1/1] rtc: cmos: Remove redundant include of linux/acpi.h
> https://git.kernel.org/abelloni/c/a33bf4b6adf7
>
I'm dropping this as AI seemed to agree with you but acpi.h has actually
never been included twice in this file.
--
Alexandre Belloni, co-owner and COO, Bootlin
Embedded Linux and Kernel engineering
https://bootlin.com
^ permalink raw reply
* Re: (subset) [PATCH 05/15] dt-bindings: rtc: ingenic,rtc: Use generic power-controller schema
From: Peng Fan @ 2026-04-04 1:33 UTC (permalink / raw)
To: Alexandre Belloni
Cc: Rob Herring, Krzysztof Kozlowski, Conor Dooley, Rafael J. Wysocki,
Ulf Hansson, Florian Fainelli,
Broadcom internal kernel review list, Ray Jui, Scott Branden,
Saenz Julienne, Lee Jones, Liam Girdwood, Mark Brown,
Shree Ramamoorthy, Jerome Neanne, Paul Cercueil, Dmitry Osipenko,
Heiko Stuebner, Joseph Chen, Chris Zhong, Zhang Qing,
Sebastian Reichel, Andreas Kemnade, Jonathan Neuschäfer,
Lubomir Rintel, Julien Panis, Matti Vaittinen, Alexander Kurz,
Krzysztof Kozlowski, André Draszik, devicetree, linux-kernel,
linux-rpi-kernel, linux-arm-kernel, linux-rtc, linux-rockchip,
linux-samsung-soc, Peng Fan
In-Reply-To: <177523251875.1559844.9690289848283345069.b4-ty@b4>
Hi Alexandre,
On Fri, Apr 03, 2026 at 06:09:00PM +0200, Alexandre Belloni wrote:
>On Mon, 16 Mar 2026 22:47:40 +0800, Peng Fan (OSS) wrote:
>> Convert the binding to use the generic power-controller schema instead by
>> referencing power-controller.yaml and removing the local
>> `system-power-controller` property definition.
>
>Applied, thanks!
Thanks, but patch [01/15] has not been accepted, so please drop 05/15.
Thanks,
Peng
>
>[05/15] dt-bindings: rtc: ingenic,rtc: Use generic power-controller schema
> https://git.kernel.org/abelloni/c/0452290110cc
>
>Best regards,
>
>--
>Alexandre Belloni, co-owner and COO, Bootlin
>Embedded Linux and Kernel engineering
>https://bootlin.com
>
^ permalink raw reply
* Re: [PATCH v2] rtc: cmos: Use platform_get_irq_optional() in cmos_platform_probe()
From: Alexandre Belloni @ 2026-04-03 16:09 UTC (permalink / raw)
To: Linux ACPI, Rafael J. Wysocki; +Cc: LKML, Nathan Chancellor, linux-rtc
In-Reply-To: <12857714.O9o76ZdvQC@rafael.j.wysocki>
On Wed, 04 Mar 2026 13:55:43 +0100, Rafael J. Wysocki wrote:
> The rtc-cmos driver can live without an IRQ and returning an error
> code from platform_get_irq() is not a problem for it in general, so
> make it call platform_get_irq_optional() in cmos_platform_probe()
> instead of platform_get_irq() to avoid a confusing error message
> printed by the latter if an IRQ cannot be found for index 0, which
> is possible on x86 platforms.
>
> [...]
Applied, thanks!
[1/1] rtc: cmos: Use platform_get_irq_optional() in cmos_platform_probe()
https://git.kernel.org/abelloni/c/92bad323175e
Best regards,
--
Alexandre Belloni, co-owner and COO, Bootlin
Embedded Linux and Kernel engineering
https://bootlin.com
^ permalink raw reply
* Re: (subset) [PATCH 05/15] dt-bindings: rtc: ingenic,rtc: Use generic power-controller schema
From: Alexandre Belloni @ 2026-04-03 16:09 UTC (permalink / raw)
To: Rob Herring, Krzysztof Kozlowski, Conor Dooley, Rafael J. Wysocki,
Ulf Hansson, Florian Fainelli,
Broadcom internal kernel review list, Ray Jui, Scott Branden,
Saenz Julienne, Lee Jones, Liam Girdwood, Mark Brown,
Shree Ramamoorthy, Jerome Neanne, Paul Cercueil, Dmitry Osipenko,
Heiko Stuebner, Joseph Chen, Chris Zhong, Zhang Qing,
Sebastian Reichel, Andreas Kemnade, Jonathan Neuschäfer,
Lubomir Rintel, Julien Panis, Matti Vaittinen, Alexander Kurz,
Krzysztof Kozlowski, André Draszik, Peng Fan (OSS)
Cc: devicetree, linux-kernel, linux-rpi-kernel, linux-arm-kernel,
linux-rtc, linux-rockchip, linux-samsung-soc, Peng Fan
In-Reply-To: <20260316-power-controller-v1-5-92c80e5e1744@nxp.com>
On Mon, 16 Mar 2026 22:47:40 +0800, Peng Fan (OSS) wrote:
> Convert the binding to use the generic power-controller schema instead by
> referencing power-controller.yaml and removing the local
> `system-power-controller` property definition.
Applied, thanks!
[05/15] dt-bindings: rtc: ingenic,rtc: Use generic power-controller schema
https://git.kernel.org/abelloni/c/0452290110cc
Best regards,
--
Alexandre Belloni, co-owner and COO, Bootlin
Embedded Linux and Kernel engineering
https://bootlin.com
^ permalink raw reply
* Re: [PATCH] rtc: cmos: Remove redundant include of linux/acpi.h
From: Alexandre Belloni @ 2026-04-03 16:08 UTC (permalink / raw)
To: Chen Ni; +Cc: linux-rtc
In-Reply-To: <20260304023533.503066-1-nichen@iscas.ac.cn>
On Wed, 04 Mar 2026 10:35:33 +0800, Chen Ni wrote:
> The header file <linux/acpi.h> is already included globally at the top
> of the file. The second inclusion inside the #ifdef CONFIG_ACPI block is
> redundant because the header uses include guards to prevent multiple
> inclusions.
>
> Remove the duplicate line to clean up the code and slightly reduce
> preprocessing overhead.
>
> [...]
Applied, thanks!
[1/1] rtc: cmos: Remove redundant include of linux/acpi.h
https://git.kernel.org/abelloni/c/a33bf4b6adf7
Best regards,
--
Alexandre Belloni, co-owner and COO, Bootlin
Embedded Linux and Kernel engineering
https://bootlin.com
^ permalink raw reply
* Re: [PATCH v1 0/4] ACPI: TAD: Add alarm support to RTC class device interface
From: Alexandre Belloni @ 2026-04-03 15:34 UTC (permalink / raw)
To: Rafael J. Wysocki; +Cc: Linux ACPI, linux-rtc, LKML
In-Reply-To: <2366642.iZASKD2KPV@rafael.j.wysocki>
On 31/03/2026 21:23:26+0200, Rafael J. Wysocki wrote:
> Hi All,
>
> This series adds alarm support via the RTC class device interface
> of the ACPI time and alarm device (TAD) driver.
>
> The code is first rearranged to facilitate re-use (patches [1-3/4]
> and then the RTC class interface of the driver is extended to
> support alarm (patch [4/4]).
>
> Thanks!
>
Reviewed-by: Alexandre Belloni <alexandre.belloni@bootlin.com>
>
>
--
Alexandre Belloni, co-owner and COO, Bootlin
Embedded Linux and Kernel engineering
https://bootlin.com
^ permalink raw reply
* Re: [PATCH v2] dt-bindings: rtc: add olpc,xo1-rtc to trivial-rtc
From: Alexandre Belloni @ 2026-04-03 14:57 UTC (permalink / raw)
To: Anushka Badhe
Cc: conor+dt, devicetree, dsd, krzk+dt, linux-kernel, linux-rtc, robh
In-Reply-To: <20260325093003.44051-1-anushkabadhe@gmail.com>
On Wed, 25 Mar 2026 15:00:03 +0530, Anushka Badhe wrote:
> Add the OLPC XO-1 RTC compatible string to the trivial-rtc schema
> instead of creating a standalone binding file, as it only requires
> a compatible property with no additional configuration.
Applied, thanks!
[1/1] dt-bindings: rtc: add olpc,xo1-rtc to trivial-rtc
https://git.kernel.org/abelloni/c/d1b091aaba8c
Best regards,
--
Alexandre Belloni, co-owner and COO, Bootlin
Embedded Linux and Kernel engineering
https://bootlin.com
^ permalink raw reply
* Re: (subset) [PATCH] rtc: add data_race() in rtc_dev_poll()
From: Alexandre Belloni @ 2026-04-03 14:54 UTC (permalink / raw)
To: Mauricio Faria de Oliveira
Cc: linux-rtc, linux-kernel, kernel-dev, syzbot+2d4127acca35ed7b31ad
In-Reply-To: <20260317-irq_data-v1-1-a2741002be60@igalia.com>
On Tue, 17 Mar 2026 20:22:16 -0300, Mauricio Faria de Oliveira wrote:
> rtc: add data_race() in rtc_dev_poll()
Applied, thanks!
Best regards,
^ permalink raw reply
* Re: (subset) [PATCH v3 1/5] dt-bindings: rtc: sc2731: Add compatible for SC2730
From: Alexandre Belloni @ 2026-04-03 14:53 UTC (permalink / raw)
To: Rob Herring, Krzysztof Kozlowski, Conor Dooley, Orson Zhai,
Baolin Wang, Chunyan Zhang, Lee Jones, Pavel Machek,
Liam Girdwood, Mark Brown, Sebastian Reichel, Otto Pflüger
Cc: linux-rtc, devicetree, linux-kernel, linux-leds, linux-pm
In-Reply-To: <20260329-sc27xx-mfd-cells-v3-1-9158dee41f74@abscue.de>
On Sun, 29 Mar 2026 09:27:45 +0200, Otto Pflüger wrote:
> The RTC block found in the SC2730 PMIC is compatible with the one found
> in the SC2731 PMIC.
Applied, thanks!
[1/5] dt-bindings: rtc: sc2731: Add compatible for SC2730
https://git.kernel.org/abelloni/c/b2b0dcaa28d2
Best regards,
--
Alexandre Belloni, co-owner and COO, Bootlin
Embedded Linux and Kernel engineering
https://bootlin.com
^ permalink raw reply
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