* [PATCH v8 0/7] clk: nuvoton: ma35d1: Fix mux parenting and peripheral clock rates
@ 2026-10-04 20:45 Miquel Raynal
2026-10-04 20:45 ` [PATCH v8 1/7] clk: nuvoton: ma35d1: Use clk_hw pointers as mux parents Miquel Raynal
` (6 more replies)
0 siblings, 7 replies; 15+ messages in thread
From: Miquel Raynal @ 2026-10-04 20:45 UTC (permalink / raw)
To: Jacky Huang, Shan-Chun Hung, Michael Turquette, Stephen Boyd,
Richard Cochran, Arnd Bergmann, Brian Masney, Jerome Brunet,
Rob Herring, Krzysztof Kozlowski, Conor Dooley, Andrew Jeffery,
Avi Fishman, Tomer Maimon, Tali Perry, Patrick Venture,
Nancy Yuen, Benjamin Fair
Cc: Thomas Petazzoni, Steam Lin, linux-arm-kernel, linux-clk,
linux-kernel, Krzysztof Kozlowski, devicetree, openbmc,
Miquel Raynal, stable
I am in possession of an MA35D1 NuMaker board. The SPI controller has
been contributed, but at this stage it does not work with the current
clock driver.
The clock controller registers its muxes with .fw_name parent data,
which requires every internal clock name to be declared in the DT. As
the DT does not declare them, all parent lookups fail: muxes end up
registered as root clocks and most peripherals read a zero rate.
This conversion exposed a first issue with the WDT/WWDT parents which
were actually missing in the clock driver. I am not using these clocks
myself but it is worth fixing.
The second round of reviews raised another problem with the
crystals. HXT and LXT are external crystal oscillators wired on the
board, while HIRC and LIRC are on-chip RC oscillators. HXT was described
whereas LXT was not. The series now also takes the two crystal inputs
from the DT: they get documented in the bindings, described in the
boards and looked up by the driver (with a fallback for backward
compatibility).
Finally, I was still unsatisfied by the clock tree because there were
too many root clocks. Many "gates" were wrongly set aside from the
downstream clocks they would gate, and SYSPLL was simply not parented at
all (?).
The clock tree now looks much more accurate.
Signed-off-by: Miquel Raynal <miquel.raynal@bootlin.com>
---
Changes in v8:
- Fix an out-of-bound bug (syspll parenting structure was wrongly
defined).
- Make sure HXT_GATE is validated before being reused (and possibly
dereferencced blindly by the core.
- Link to v7: https://lore.kernel.org/r/20261002-perso-ma35d1-upstream-clk-v7-0-cbd991fa6270@bootlin.com
Changes in v7:
- Avoid opencoding core helpers, replace them with existing helpers
(mentioned by Jerome)
- Rebased on top of clk-next since the first patches have been applied
- Link to v6: https://lore.kernel.org/r/20260930-perso-ma35d1-upstream-clk-v6-0-48937ee6c9bb@bootlin.com
Changes in v6:
- Drop the clock output names entirely, they are not relevant.
- Error out when the crystal providers defer probing.
- Make sure gates are correctly parented.
- Make sure SYSPLL is parented.
- Link to v5: https://lore.kernel.org/r/20260929-perso-ma35d1-upstream-clk-v5-0-68533e935ee4@bootlin.com
Changes in v5:
- Fix the bindings wrt HXT and LXT.
- Fix the DT descriptions of HXT and LXT.
- Collect tags.
- Link to v4: https://lore.kernel.org/r/20260925-perso-ma35d1-upstream-clk-v4-0-f3697553391f@bootlin.com
Changes in v4:
- I forgot to bump the clock counter in the driver after adding the two
new clocks in the bindings. Sashiko will keep complaining about the
incoherency though. Since binding and driver changes should be kept
separated, I cannot do both at the same time.
- Link to v3: https://lore.kernel.org/r/20260925-perso-ma35d1-upstream-clk-v3-0-ffbae7e020a8@bootlin.com
Changes in v3:
- Drop the number of clocks from the binding, set it in the driver only
- Split the binding/driver patches completely
- Link to v2: https://lore.kernel.org/r/20260921-perso-ma35d1-upstream-clk-v2-0-209fd32a8b00@bootlin.com
Changes in v2:
- New patch 1/3: register the missing WDT/WWDT parent clocks
- New patch 3/3: harden the code
- Link to v1: https://lore.kernel.org/r/20260813-perso-ma35d1-upstream-clk-v1-1-e78e5e6172ea@bootlin.com
---
Miquel Raynal (7):
clk: nuvoton: ma35d1: Use clk_hw pointers as mux parents
clk: nuvoton: ma35d1: Avoid possible error pointer dereferencing
clk: nuvoton: ma35d1: Retrieve HXT/LXT from DT when possible
clk: nuvoton: ma35d1: Reparent the gates correctly
clk: nuvoton: ma35d1: Reparent SYSPLL correctly
arm64: dts: nuvoton: ma35d1: Drop HXT clock output name
arm64: dts: nuvoton: ma35d1: Add LXT crystal and clock-names
arch/arm64/boot/dts/nuvoton/ma35d1-iot-512m.dts | 7 +-
arch/arm64/boot/dts/nuvoton/ma35d1-som-256m.dts | 7 +-
arch/arm64/boot/dts/nuvoton/ma35d1.dtsi | 3 +-
drivers/clk/nuvoton/clk-ma35d1-divider.c | 3 +
drivers/clk/nuvoton/clk-ma35d1-pll.c | 3 +
drivers/clk/nuvoton/clk-ma35d1.c | 710 +++++++++---------------
6 files changed, 267 insertions(+), 466 deletions(-)
---
base-commit: 6b78cda327cc2dbcd0e60f411ae014997a684b55
change-id: 20260813-perso-ma35d1-upstream-clk-65cacfc1a86b
Best regards,
--
Miquel Raynal <miquel.raynal@bootlin.com>
^ permalink raw reply [flat|nested] 15+ messages in thread* [PATCH v8 1/7] clk: nuvoton: ma35d1: Use clk_hw pointers as mux parents 2026-10-04 20:45 [PATCH v8 0/7] clk: nuvoton: ma35d1: Fix mux parenting and peripheral clock rates Miquel Raynal @ 2026-10-04 20:45 ` Miquel Raynal 2026-10-04 20:45 ` [PATCH v8 2/7] clk: nuvoton: ma35d1: Avoid possible error pointer dereferencing Miquel Raynal ` (5 subsequent siblings) 6 siblings, 0 replies; 15+ messages in thread From: Miquel Raynal @ 2026-10-04 20:45 UTC (permalink / raw) To: Jacky Huang, Shan-Chun Hung, Michael Turquette, Stephen Boyd, Richard Cochran, Arnd Bergmann, Brian Masney, Jerome Brunet, Rob Herring, Krzysztof Kozlowski, Conor Dooley, Andrew Jeffery, Avi Fishman, Tomer Maimon, Tali Perry, Patrick Venture, Nancy Yuen, Benjamin Fair Cc: Thomas Petazzoni, Steam Lin, linux-arm-kernel, linux-clk, linux-kernel, Krzysztof Kozlowski, devicetree, openbmc, Miquel Raynal, stable The MA35D1 clock provider registers its muxes with parent data structures filling .fw_name. This is not the ideal approach since that would require a massive amount of internal clock names declaration in the DT. Since the DT does not play the game of exposing all these names, none of the parent lookups performed when instantiating the muxes succeed. As a result, these muxes get registered as root clocks, leading to a sadly flat clock tree and no frequency assigned to most of the peripheral clocks: enable prepare protect clock count count count rate usbphy1 0 0 0 480000000 usbphy0 0 0 0 480000000 husbh1_gate 0 0 0 480000000 husbh0_gate 0 0 0 480000000 usbh_gate 0 0 0 480000000 usbd_gate 0 0 0 480000000 syspll 0 0 0 180000000 lirc 0 0 0 32000 lirc_gate 0 0 0 32000 hirc 0 0 0 12000000 gtmr_gate 0 0 0 12000000 hirc_gate 0 0 0 12000000 lxt 0 0 0 32768 rtc_gate 0 0 0 32768 lxt_gate 0 0 0 32768 hxt 0 0 0 24000000 vpll 0 0 0 1224000000 dcup_div 0 0 0 612000000 epll 0 0 0 6000000000 epll_div8 0 0 0 750000000 epll_div4 0 0 0 1500000000 epll_div2 0 0 0 3000000000 emac1_gate 0 0 0 3000000000 emac0_gate 0 0 0 3000000000 apll 0 0 0 6048000000 ddrpll 0 0 0 266460000 ddr_gate 0 0 0 266460000 ddr6_gate 0 0 0 266460000 ddr0_gate 0 0 0 266460000 capll 0 0 0 2400000000 hxt_gate 0 0 0 24000000 clk_hxt 0 0 0 24000000 spi3_mux 0 0 0 0 spi3_gate 0 0 0 0 spi2_mux 0 0 0 0 spi2_gate 0 0 0 0 spi1_mux 0 0 0 0 spi1_gate 0 0 0 0 spi0_mux 0 0 0 0 spi0_gate 0 0 0 0 i2s1_mux 0 0 0 0 i2s1_gate 0 0 0 0 i2s0_mux 0 0 0 0 i2s0_gate 0 0 0 0 ... Apart from the wrong clock tree representation, it means that none of the device drivers (spi & i2c in the excerpt above) can actually query their clock rate, or they would get 0Hz. Instead of declaring the parents in the clk_parent_data structure, use the actual HW clocks to lookup the parents directly: parents are described by an array of indices into the controller's main clock table (like in other clock controller drivers), which the "new" mux helper now resolves. The WDT and WWDT muxes list the /4096 children of PCLK3 and PCLK4 among their possible parents. Those two clocks are now registered by the previous commit, so their entries in the parent tables are restored instead of being turned into invalid slots. enable prepare protect clock count count count rate usbphy1 0 0 0 480000000 usbphy0 0 0 0 480000000 husbh1_gate 0 0 0 480000000 husbh0_gate 0 0 0 480000000 usbh_gate 0 0 0 480000000 usbd_gate 0 0 0 480000000 syspll 1 1 0 180000000 dbg_mux 0 0 0 180000000 sdh1_mux 0 0 0 180000000 sdh1_gate 0 0 0 180000000 sdh0_mux 0 0 0 180000000 sdh0_gate 0 0 0 180000000 sysclk1_mux 2 2 0 180000000 pclk4 0 0 0 90000000 pclk3 0 0 0 90000000 sspcc_gate 0 0 0 90000000 ssmcc_gate 0 0 0 90000000 hclk3 0 0 0 90000000 pclk2 0 0 0 180000000 eadc_div 0 0 0 90000000 eadc_gate 0 0 0 90000000 qei1_gate 0 0 0 180000000 ecap1_gate 0 0 0 180000000 spi3_mux 0 0 0 180000000 spi3_gate 0 0 0 180000000 spi1_mux 0 0 0 180000000 spi1_gate 0 0 0 180000000 epwm1_gate 0 0 0 180000000 i2c5_gate 0 0 0 180000000 i2c2_gate 0 0 0 180000000 pclk1 0 0 0 180000000 qei2_gate 0 0 0 180000000 qei0_gate 0 0 0 180000000 ecap2_gate 0 0 0 180000000 ecap0_gate 0 0 0 180000000 spi2_mux 0 0 0 180000000 spi2_gate 0 0 0 180000000 spi0_mux 0 0 0 180000000 spi0_gate 0 0 0 180000000 epwm2_gate 0 0 0 180000000 epwm0_gate 0 0 0 180000000 i2c4_gate 0 0 0 180000000 i2c1_gate 0 0 0 180000000 pclk0 1 1 0 180000000 adc_div 0 0 0 90000000 adc_gate 0 0 0 90000000 qspi1_mux 0 0 0 180000000 qspi1_gate 0 0 0 180000000 qspi0_mux 1 1 0 180000000 qspi0_gate 1 1 0 180000000 i2c3_gate 0 0 0 180000000 i2c0_gate 0 0 0 180000000 Fixes: f50a000b4219 ("clk: nuvoton: Use clk_parent_data instead of string for parent clock") Cc: stable@vger.kernel.org Signed-off-by: Miquel Raynal <miquel.raynal@bootlin.com> --- drivers/clk/nuvoton/clk-ma35d1.c | 626 +++++++++++---------------------------- 1 file changed, 177 insertions(+), 449 deletions(-) diff --git a/drivers/clk/nuvoton/clk-ma35d1.c b/drivers/clk/nuvoton/clk-ma35d1.c index c914079cee2d..1a857f28310f 100644 --- a/drivers/clk/nuvoton/clk-ma35d1.c +++ b/drivers/clk/nuvoton/clk-ma35d1.c @@ -63,300 +63,49 @@ static DEFINE_SPINLOCK(ma35d1_lock); #define PLL_MODE_FRAC 1 #define PLL_MODE_SS 2 -static const struct clk_parent_data ca35clk_sel_clks[] = { - { .fw_name = "hxt", }, - { .fw_name = "capll", }, - { .fw_name = "ddrpll", }, -}; +#define MA35D1_MUX_MAX_PARENTS 10 -static const struct clk_parent_data sysclk0_sel_clks[] = { - { .fw_name = "epll_div2", }, - { .fw_name = "syspll", }, -}; - -static const struct clk_parent_data sysclk1_sel_clks[] = { - { .fw_name = "hxt", }, - { .fw_name = "syspll", }, -}; - -static const struct clk_parent_data axiclk_sel_clks[] = { - { .fw_name = "capll_div2", }, - { .fw_name = "capll_div4", }, -}; - -static const struct clk_parent_data ccap_sel_clks[] = { - { .fw_name = "hxt", }, - { .fw_name = "vpll", }, - { .fw_name = "apll", }, - { .fw_name = "syspll", }, -}; - -static const struct clk_parent_data sdh_sel_clks[] = { - { .fw_name = "syspll", }, - { .fw_name = "apll", }, -}; - -static const struct clk_parent_data dcu_sel_clks[] = { - { .fw_name = "epll_div2", }, - { .fw_name = "syspll", }, -}; - -static const struct clk_parent_data gfx_sel_clks[] = { - { .fw_name = "epll", }, - { .fw_name = "syspll", }, -}; - -static const struct clk_parent_data dbg_sel_clks[] = { - { .fw_name = "hirc", }, - { .fw_name = "syspll", }, -}; - -static const struct clk_parent_data timer0_sel_clks[] = { - { .fw_name = "hxt", }, - { .fw_name = "lxt", }, - { .fw_name = "pclk0", }, - { .index = -1, }, - { .index = -1, }, - { .fw_name = "lirc", }, - { .index = -1, }, - { .fw_name = "hirc", }, -}; - -static const struct clk_parent_data timer1_sel_clks[] = { - { .fw_name = "hxt", }, - { .fw_name = "lxt", }, - { .fw_name = "pclk0", }, - { .index = -1, }, - { .index = -1, }, - { .fw_name = "lirc", }, - { .index = -1, }, - { .fw_name = "hirc", }, -}; - -static const struct clk_parent_data timer2_sel_clks[] = { - { .fw_name = "hxt", }, - { .fw_name = "lxt", }, - { .fw_name = "pclk1", }, - { .index = -1, }, - { .index = -1, }, - { .fw_name = "lirc", }, - { .index = -1, }, - { .fw_name = "hirc", }, -}; - -static const struct clk_parent_data timer3_sel_clks[] = { - { .fw_name = "hxt", }, - { .fw_name = "lxt", }, - { .fw_name = "pclk1", }, - { .index = -1, }, - { .index = -1, }, - { .fw_name = "lirc", }, - { .index = -1, }, - { .fw_name = "hirc", }, -}; - -static const struct clk_parent_data timer4_sel_clks[] = { - { .fw_name = "hxt", }, - { .fw_name = "lxt", }, - { .fw_name = "pclk2", }, - { .index = -1, }, - { .index = -1, }, - { .fw_name = "lirc", }, - { .index = -1, }, - { .fw_name = "hirc", }, -}; - -static const struct clk_parent_data timer5_sel_clks[] = { - { .fw_name = "hxt", }, - { .fw_name = "lxt", }, - { .fw_name = "pclk2", }, - { .index = -1, }, - { .index = -1, }, - { .fw_name = "lirc", }, - { .index = -1, }, - { .fw_name = "hirc", }, -}; - -static const struct clk_parent_data timer6_sel_clks[] = { - { .fw_name = "hxt", }, - { .fw_name = "lxt", }, - { .fw_name = "pclk0", }, - { .index = -1, }, - { .index = -1, }, - { .fw_name = "lirc", }, - { .index = -1, }, - { .fw_name = "hirc", }, -}; - -static const struct clk_parent_data timer7_sel_clks[] = { - { .fw_name = "hxt", }, - { .fw_name = "lxt", }, - { .fw_name = "pclk0", }, - { .index = -1, }, - { .index = -1, }, - { .fw_name = "lirc", }, - { .index = -1, }, - { .fw_name = "hirc", }, -}; - -static const struct clk_parent_data timer8_sel_clks[] = { - { .fw_name = "hxt", }, - { .fw_name = "lxt", }, - { .fw_name = "pclk1", }, - { .index = -1, }, - { .index = -1, }, - { .fw_name = "lirc", }, - { .index = -1, }, - { .fw_name = "hirc", }, -}; - -static const struct clk_parent_data timer9_sel_clks[] = { - { .fw_name = "hxt", }, - { .fw_name = "lxt", }, - { .fw_name = "pclk1", }, - { .index = -1, }, - { .index = -1, }, - { .fw_name = "lirc", }, - { .index = -1, }, - { .fw_name = "hirc", }, -}; - -static const struct clk_parent_data timer10_sel_clks[] = { - { .fw_name = "hxt", }, - { .fw_name = "lxt", }, - { .fw_name = "pclk2", }, - { .index = -1, }, - { .index = -1, }, - { .fw_name = "lirc", }, - { .index = -1, }, - { .fw_name = "hirc", }, -}; - -static const struct clk_parent_data timer11_sel_clks[] = { - { .fw_name = "hxt", }, - { .fw_name = "lxt", }, - { .fw_name = "pclk2", }, - { .index = -1, }, - { .index = -1, }, - { .fw_name = "lirc", }, - { .index = -1, }, - { .fw_name = "hirc", }, -}; - -static const struct clk_parent_data uart_sel_clks[] = { - { .fw_name = "hxt", }, - { .fw_name = "sysclk1_div2", }, -}; - -static const struct clk_parent_data wdt0_sel_clks[] = { - { .index = -1, }, - { .fw_name = "lxt", }, - { .fw_name = "pclk3_div4096", }, - { .fw_name = "lirc", }, -}; - -static const struct clk_parent_data wdt1_sel_clks[] = { - { .index = -1, }, - { .fw_name = "lxt", }, - { .fw_name = "pclk3_div4096", }, - { .fw_name = "lirc", }, -}; - -static const struct clk_parent_data wdt2_sel_clks[] = { - { .index = -1, }, - { .fw_name = "lxt", }, - { .fw_name = "pclk4_div4096", }, - { .fw_name = "lirc", }, -}; - -static const struct clk_parent_data wwdt0_sel_clks[] = { - { .index = -1, }, - { .index = -1, }, - { .fw_name = "pclk3_div4096", }, - { .fw_name = "lirc", }, -}; - -static const struct clk_parent_data wwdt1_sel_clks[] = { - { .index = -1, }, - { .index = -1, }, - { .fw_name = "pclk3_div4096", }, - { .fw_name = "lirc", }, -}; - -static const struct clk_parent_data wwdt2_sel_clks[] = { - { .index = -1, }, - { .index = -1, }, - { .fw_name = "pclk4_div4096", }, - { .fw_name = "lirc", }, -}; - -static const struct clk_parent_data spi0_sel_clks[] = { - { .fw_name = "pclk1", }, - { .fw_name = "apll", }, -}; - -static const struct clk_parent_data spi1_sel_clks[] = { - { .fw_name = "pclk2", }, - { .fw_name = "apll", }, -}; - -static const struct clk_parent_data spi2_sel_clks[] = { - { .fw_name = "pclk1", }, - { .fw_name = "apll", }, -}; - -static const struct clk_parent_data spi3_sel_clks[] = { - { .fw_name = "pclk2", }, - { .fw_name = "apll", }, -}; - -static const struct clk_parent_data qspi0_sel_clks[] = { - { .fw_name = "pclk0", }, - { .fw_name = "apll", }, -}; - -static const struct clk_parent_data qspi1_sel_clks[] = { - { .fw_name = "pclk0", }, - { .fw_name = "apll", }, -}; - -static const struct clk_parent_data i2s0_sel_clks[] = { - { .fw_name = "apll", }, - { .fw_name = "sysclk1_div2", }, -}; - -static const struct clk_parent_data i2s1_sel_clks[] = { - { .fw_name = "apll", }, - { .fw_name = "sysclk1_div2", }, -}; - -static const struct clk_parent_data can_sel_clks[] = { - { .fw_name = "apll", }, - { .fw_name = "vpll", }, -}; - -static const struct clk_parent_data cko_sel_clks[] = { - { .fw_name = "hxt", }, - { .fw_name = "lxt", }, - { .fw_name = "hirc", }, - { .fw_name = "lirc", }, - { .fw_name = "capll_div4", }, - { .fw_name = "syspll", }, - { .fw_name = "ddrpll", }, - { .fw_name = "epll_div2", }, - { .fw_name = "apll", }, - { .fw_name = "vpll", }, -}; - -static const struct clk_parent_data smc_sel_clks[] = { - { .fw_name = "hxt", }, - { .fw_name = "pclk4", }, -}; - -static const struct clk_parent_data kpi_sel_clks[] = { - { .fw_name = "hxt", }, - { .fw_name = "lxt", }, -}; +/* Mux parent selection, by index into the controller's clock table */ +static const int ca35clk_parent_idx[] = { HXT, CAPLL, DDRPLL }; +static const int sysclk0_parent_idx[] = { EPLL_DIV2, SYSPLL }; +static const int sysclk1_parent_idx[] = { HXT, SYSPLL }; +static const int axiclk_parent_idx[] = { AXICLK_DIV2, AXICLK_DIV4 }; +static const int ccap_parent_idx[] = { HXT, VPLL, APLL, SYSPLL }; +static const int sdh_parent_idx[] = { SYSPLL, APLL }; +static const int dcu_parent_idx[] = { EPLL_DIV2, SYSPLL }; +static const int gfx_parent_idx[] = { EPLL, SYSPLL }; +static const int dbg_parent_idx[] = { HIRC, SYSPLL }; +static const int timer0_parent_idx[] = { HXT, LXT, PCLK0, -1, -1, LIRC, -1, HIRC }; +static const int timer1_parent_idx[] = { HXT, LXT, PCLK0, -1, -1, LIRC, -1, HIRC }; +static const int timer2_parent_idx[] = { HXT, LXT, PCLK1, -1, -1, LIRC, -1, HIRC }; +static const int timer3_parent_idx[] = { HXT, LXT, PCLK1, -1, -1, LIRC, -1, HIRC }; +static const int timer4_parent_idx[] = { HXT, LXT, PCLK2, -1, -1, LIRC, -1, HIRC }; +static const int timer5_parent_idx[] = { HXT, LXT, PCLK2, -1, -1, LIRC, -1, HIRC }; +static const int timer6_parent_idx[] = { HXT, LXT, PCLK0, -1, -1, LIRC, -1, HIRC }; +static const int timer7_parent_idx[] = { HXT, LXT, PCLK0, -1, -1, LIRC, -1, HIRC }; +static const int timer8_parent_idx[] = { HXT, LXT, PCLK1, -1, -1, LIRC, -1, HIRC }; +static const int timer9_parent_idx[] = { HXT, LXT, PCLK1, -1, -1, LIRC, -1, HIRC }; +static const int timer10_parent_idx[] = { HXT, LXT, PCLK2, -1, -1, LIRC, -1, HIRC }; +static const int timer11_parent_idx[] = { HXT, LXT, PCLK2, -1, -1, LIRC, -1, HIRC }; +static const int uart_parent_idx[] = { HXT, SYSCLK1_DIV2 }; +static const int wdt0_parent_idx[] = { -1, LXT, PCLK3_DIV4096, LIRC }; +static const int wdt1_parent_idx[] = { -1, LXT, PCLK3_DIV4096, LIRC }; +static const int wdt2_parent_idx[] = { -1, LXT, PCLK4_DIV4096, LIRC }; +static const int wwdt0_parent_idx[] = { -1, -1, PCLK3_DIV4096, LIRC }; +static const int wwdt1_parent_idx[] = { -1, -1, PCLK3_DIV4096, LIRC }; +static const int wwdt2_parent_idx[] = { -1, -1, PCLK4_DIV4096, LIRC }; +static const int spi0_parent_idx[] = { PCLK1, APLL }; +static const int spi1_parent_idx[] = { PCLK2, APLL }; +static const int spi2_parent_idx[] = { PCLK1, APLL }; +static const int spi3_parent_idx[] = { PCLK2, APLL }; +static const int qspi_parent_idx[] = { PCLK0, APLL }; +static const int i2s_parent_idx[] = { APLL, SYSCLK1_DIV2 }; +static const int can_parent_idx[] = { APLL, VPLL }; +static const int cko_parent_idx[] = { HXT, LXT, HIRC, LIRC, + AXICLK_DIV4, SYSPLL, DDRPLL, + EPLL_DIV2, APLL, VPLL }; +static const int smc_parent_idx[] = { HXT, PCLK4 }; +static const int kpi_parent_idx[] = { HXT, LXT }; static const struct clk_div_table ip_div_table[] = { {0, 2}, {1, 4}, {2, 6}, {3, 8}, {4, 10}, @@ -375,24 +124,20 @@ static struct clk_hw *ma35d1_clk_fixed(const char *name, int rate) return clk_hw_register_fixed_rate(NULL, name, NULL, 0, rate); } -static struct clk_hw *ma35d1_clk_mux_parent(struct device *dev, const char *name, - void __iomem *reg, u8 shift, u8 width, - const struct clk_parent_data *pdata, - int num_pdata) -{ - return clk_hw_register_mux_parent_data(dev, name, pdata, num_pdata, - CLK_SET_RATE_NO_REPARENT, reg, shift, - width, 0, &ma35d1_lock); -} - static struct clk_hw *ma35d1_clk_mux(struct device *dev, const char *name, void __iomem *reg, u8 shift, u8 width, - const struct clk_parent_data *pdata, - int num_pdata) + struct clk_hw **hws, + const int *parent_idx, int num_parents) { - return clk_hw_register_mux_parent_data(dev, name, pdata, num_pdata, - CLK_SET_RATE_NO_REPARENT, reg, shift, - width, 0, &ma35d1_lock); + const struct clk_hw *parent_hws[MA35D1_MUX_MAX_PARENTS] = {}; + int i; + + for (i = 0; i < num_parents; i++) + parent_hws[i] = (parent_idx[i] >= 0) ? hws[parent_idx[i]] : NULL; + + return clk_hw_register_mux_hws(dev, name, parent_hws, num_parents, + CLK_SET_RATE_NO_REPARENT, reg, shift, + width, 0, &ma35d1_lock); } static struct clk_hw *ma35d1_clk_divider(struct device *dev, const char *name, @@ -515,22 +260,17 @@ static int ma35d1_clocks_probe(struct platform_device *pdev) hws[EPLL_DIV4] = ma35d1_clk_fixed_factor(dev, "epll_div4", "epll", 1, 4); hws[EPLL_DIV8] = ma35d1_clk_fixed_factor(dev, "epll_div8", "epll", 1, 8); - hws[CA35CLK_MUX] = ma35d1_clk_mux_parent(dev, "ca35clk_mux", - clk_base + REG_CLK_CLKSEL0, 0, 2, - ca35clk_sel_clks, - ARRAY_SIZE(ca35clk_sel_clks)); + hws[CA35CLK_MUX] = ma35d1_clk_mux(dev, "ca35clk_mux", clk_base + REG_CLK_CLKSEL0, 0, 2, hws, + ca35clk_parent_idx, ARRAY_SIZE(ca35clk_parent_idx)); hws[AXICLK_DIV2] = ma35d1_clk_fixed_factor(dev, "capll_div2", "ca35clk_mux", 1, 2); hws[AXICLK_DIV4] = ma35d1_clk_fixed_factor(dev, "capll_div4", "ca35clk_mux", 1, 4); - hws[AXICLK_MUX] = ma35d1_clk_mux(dev, "axiclk_mux", clk_base + REG_CLK_CLKDIV0, - 26, 1, axiclk_sel_clks, - ARRAY_SIZE(axiclk_sel_clks)); - hws[SYSCLK0_MUX] = ma35d1_clk_mux(dev, "sysclk0_mux", clk_base + REG_CLK_CLKSEL0, - 2, 1, sysclk0_sel_clks, - ARRAY_SIZE(sysclk0_sel_clks)); - hws[SYSCLK1_MUX] = ma35d1_clk_mux(dev, "sysclk1_mux", clk_base + REG_CLK_CLKSEL0, - 4, 1, sysclk1_sel_clks, - ARRAY_SIZE(sysclk1_sel_clks)); + hws[AXICLK_MUX] = ma35d1_clk_mux(dev, "axiclk_mux", clk_base + REG_CLK_CLKDIV0, 26, 1, hws, + axiclk_parent_idx, ARRAY_SIZE(axiclk_parent_idx)); + hws[SYSCLK0_MUX] = ma35d1_clk_mux(dev, "sysclk0_mux", clk_base + REG_CLK_CLKSEL0, 2, 1, hws, + sysclk0_parent_idx, ARRAY_SIZE(sysclk0_parent_idx)); + hws[SYSCLK1_MUX] = ma35d1_clk_mux(dev, "sysclk1_mux", clk_base + REG_CLK_CLKSEL0, 4, 1, hws, + sysclk1_parent_idx, ARRAY_SIZE(sysclk1_parent_idx)); hws[SYSCLK1_DIV2] = ma35d1_clk_fixed_factor(dev, "sysclk1_div2", "sysclk1_mux", 1, 2); /* HCLK0~3 & PCLK0~4 */ @@ -556,41 +296,41 @@ static int ma35d1_clocks_probe(struct platform_device *pdev) hws[DDR6_GATE] = ma35d1_clk_gate(dev, "ddr6_gate", "ddrpll", clk_base + REG_CLK_SYSCLK0, 5); - hws[CAN0_MUX] = ma35d1_clk_mux(dev, "can0_mux", clk_base + REG_CLK_CLKSEL4, - 16, 1, can_sel_clks, ARRAY_SIZE(can_sel_clks)); + hws[CAN0_MUX] = ma35d1_clk_mux(dev, "can0_mux", clk_base + REG_CLK_CLKSEL4, 16, 1, hws, + can_parent_idx, ARRAY_SIZE(can_parent_idx)); hws[CAN0_DIV] = ma35d1_clk_divider_table(dev, "can0_div", "can0_mux", clk_base + REG_CLK_CLKDIV0, 0, 3, ip_div_table); hws[CAN0_GATE] = ma35d1_clk_gate(dev, "can0_gate", "can0_div", clk_base + REG_CLK_SYSCLK0, 8); - hws[CAN1_MUX] = ma35d1_clk_mux(dev, "can1_mux", clk_base + REG_CLK_CLKSEL4, - 17, 1, can_sel_clks, ARRAY_SIZE(can_sel_clks)); + hws[CAN1_MUX] = ma35d1_clk_mux(dev, "can1_mux", clk_base + REG_CLK_CLKSEL4, 17, 1, hws, + can_parent_idx, ARRAY_SIZE(can_parent_idx)); hws[CAN1_DIV] = ma35d1_clk_divider_table(dev, "can1_div", "can1_mux", clk_base + REG_CLK_CLKDIV0, 4, 3, ip_div_table); hws[CAN1_GATE] = ma35d1_clk_gate(dev, "can1_gate", "can1_div", clk_base + REG_CLK_SYSCLK0, 9); - hws[CAN2_MUX] = ma35d1_clk_mux(dev, "can2_mux", clk_base + REG_CLK_CLKSEL4, - 18, 1, can_sel_clks, ARRAY_SIZE(can_sel_clks)); + hws[CAN2_MUX] = ma35d1_clk_mux(dev, "can2_mux", clk_base + REG_CLK_CLKSEL4, 18, 1, hws, + can_parent_idx, ARRAY_SIZE(can_parent_idx)); hws[CAN2_DIV] = ma35d1_clk_divider_table(dev, "can2_div", "can2_mux", clk_base + REG_CLK_CLKDIV0, 8, 3, ip_div_table); hws[CAN2_GATE] = ma35d1_clk_gate(dev, "can2_gate", "can2_div", clk_base + REG_CLK_SYSCLK0, 10); - hws[CAN3_MUX] = ma35d1_clk_mux(dev, "can3_mux", clk_base + REG_CLK_CLKSEL4, - 19, 1, can_sel_clks, ARRAY_SIZE(can_sel_clks)); + hws[CAN3_MUX] = ma35d1_clk_mux(dev, "can3_mux", clk_base + REG_CLK_CLKSEL4, 19, 1, hws, + can_parent_idx, ARRAY_SIZE(can_parent_idx)); hws[CAN3_DIV] = ma35d1_clk_divider_table(dev, "can3_div", "can3_mux", clk_base + REG_CLK_CLKDIV0, 12, 3, ip_div_table); hws[CAN3_GATE] = ma35d1_clk_gate(dev, "can3_gate", "can3_div", clk_base + REG_CLK_SYSCLK0, 11); - hws[SDH0_MUX] = ma35d1_clk_mux(dev, "sdh0_mux", clk_base + REG_CLK_CLKSEL0, - 16, 2, sdh_sel_clks, ARRAY_SIZE(sdh_sel_clks)); + hws[SDH0_MUX] = ma35d1_clk_mux(dev, "sdh0_mux", clk_base + REG_CLK_CLKSEL0, 16, 2, hws, + sdh_parent_idx, ARRAY_SIZE(sdh_parent_idx)); hws[SDH0_GATE] = ma35d1_clk_gate(dev, "sdh0_gate", "sdh0_mux", clk_base + REG_CLK_SYSCLK0, 16); - hws[SDH1_MUX] = ma35d1_clk_mux(dev, "sdh1_mux", clk_base + REG_CLK_CLKSEL0, - 18, 2, sdh_sel_clks, ARRAY_SIZE(sdh_sel_clks)); + hws[SDH1_MUX] = ma35d1_clk_mux(dev, "sdh1_mux", clk_base + REG_CLK_CLKSEL0, 18, 2, hws, + sdh_parent_idx, ARRAY_SIZE(sdh_parent_idx)); hws[SDH1_GATE] = ma35d1_clk_gate(dev, "sdh1_gate", "sdh1_mux", clk_base + REG_CLK_SYSCLK0, 17); @@ -606,14 +346,14 @@ static int ma35d1_clocks_probe(struct platform_device *pdev) hws[HUSBH1_GATE] = ma35d1_clk_gate(dev, "husbh1_gate", "usbphy0", clk_base + REG_CLK_SYSCLK0, 22); - hws[GFX_MUX] = ma35d1_clk_mux(dev, "gfx_mux", clk_base + REG_CLK_CLKSEL0, - 26, 1, gfx_sel_clks, ARRAY_SIZE(gfx_sel_clks)); + hws[GFX_MUX] = ma35d1_clk_mux(dev, "gfx_mux", clk_base + REG_CLK_CLKSEL0, 26, 1, hws, + gfx_parent_idx, ARRAY_SIZE(gfx_parent_idx)); hws[GFX_GATE] = ma35d1_clk_gate(dev, "gfx_gate", "gfx_mux", clk_base + REG_CLK_SYSCLK0, 24); hws[VC8K_GATE] = ma35d1_clk_gate(dev, "vc8k_gate", "sysclk0_mux", clk_base + REG_CLK_SYSCLK0, 25); - hws[DCU_MUX] = ma35d1_clk_mux(dev, "dcu_mux", clk_base + REG_CLK_CLKSEL0, - 24, 1, dcu_sel_clks, ARRAY_SIZE(dcu_sel_clks)); + hws[DCU_MUX] = ma35d1_clk_mux(dev, "dcu_mux", clk_base + REG_CLK_CLKSEL0, 24, 1, hws, + dcu_parent_idx, ARRAY_SIZE(dcu_parent_idx)); hws[DCU_GATE] = ma35d1_clk_gate(dev, "dcu_gate", "dcu_mux", clk_base + REG_CLK_SYSCLK0, 26); hws[DCUP_DIV] = ma35d1_clk_divider_table(dev, "dcup_div", "vpll", @@ -625,14 +365,14 @@ static int ma35d1_clocks_probe(struct platform_device *pdev) hws[EMAC1_GATE] = ma35d1_clk_gate(dev, "emac1_gate", "epll_div2", clk_base + REG_CLK_SYSCLK0, 28); - hws[CCAP0_MUX] = ma35d1_clk_mux(dev, "ccap0_mux", clk_base + REG_CLK_CLKSEL0, - 12, 1, ccap_sel_clks, ARRAY_SIZE(ccap_sel_clks)); + hws[CCAP0_MUX] = ma35d1_clk_mux(dev, "ccap0_mux", clk_base + REG_CLK_CLKSEL0, 12, 1, hws, + ccap_parent_idx, ARRAY_SIZE(ccap_parent_idx)); hws[CCAP0_DIV] = ma35d1_clk_divider(dev, "ccap0_div", "ccap0_mux", clk_base + REG_CLK_CLKDIV1, 8, 4); hws[CCAP0_GATE] = ma35d1_clk_gate(dev, "ccap0_gate", "ccap0_div", clk_base + REG_CLK_SYSCLK0, 29); - hws[CCAP1_MUX] = ma35d1_clk_mux(dev, "ccap1_mux", clk_base + REG_CLK_CLKSEL0, - 14, 1, ccap_sel_clks, ARRAY_SIZE(ccap_sel_clks)); + hws[CCAP1_MUX] = ma35d1_clk_mux(dev, "ccap1_mux", clk_base + REG_CLK_CLKSEL0, 14, 1, hws, + ccap_parent_idx, ARRAY_SIZE(ccap_parent_idx)); hws[CCAP1_DIV] = ma35d1_clk_divider(dev, "ccap1_div", "ccap1_mux", clk_base + REG_CLK_CLKDIV1, 12, 4); @@ -670,13 +410,13 @@ static int ma35d1_clocks_probe(struct platform_device *pdev) hws[TRA_GATE] = ma35d1_clk_gate(dev, "tra_gate", "hclk0", clk_base + REG_CLK_SYSCLK1, 11); - hws[DBG_MUX] = ma35d1_clk_mux(dev, "dbg_mux", clk_base + REG_CLK_CLKSEL0, - 27, 1, dbg_sel_clks, ARRAY_SIZE(dbg_sel_clks)); + hws[DBG_MUX] = ma35d1_clk_mux(dev, "dbg_mux", clk_base + REG_CLK_CLKSEL0, 27, 1, hws, + dbg_parent_idx, ARRAY_SIZE(dbg_parent_idx)); hws[DBG_GATE] = ma35d1_clk_gate(dev, "dbg_gate", "hclk0", clk_base + REG_CLK_SYSCLK1, 12); - hws[CKO_MUX] = ma35d1_clk_mux(dev, "cko_mux", clk_base + REG_CLK_CLKSEL4, - 24, 4, cko_sel_clks, ARRAY_SIZE(cko_sel_clks)); + hws[CKO_MUX] = ma35d1_clk_mux(dev, "cko_mux", clk_base + REG_CLK_CLKSEL4, 24, 4, hws, + cko_parent_idx, ARRAY_SIZE(cko_parent_idx)); hws[CKO_DIV] = ma35d1_clk_divider_pow2(dev, "cko_div", "cko_mux", clk_base + REG_CLK_CLKOCTL, 0, 4); hws[CKO_GATE] = ma35d1_clk_gate(dev, "cko_gate", "cko_div", @@ -714,181 +454,169 @@ static int ma35d1_clocks_probe(struct platform_device *pdev) hws[GPN_GATE] = ma35d1_clk_gate(dev, "gpn_gate", "hclk0", clk_base + REG_CLK_SYSCLK1, 29); - hws[TMR0_MUX] = ma35d1_clk_mux(dev, "tmr0_mux", clk_base + REG_CLK_CLKSEL1, - 0, 3, timer0_sel_clks, - ARRAY_SIZE(timer0_sel_clks)); + hws[TMR0_MUX] = ma35d1_clk_mux(dev, "tmr0_mux", clk_base + REG_CLK_CLKSEL1, 0, 3, hws, + timer0_parent_idx, ARRAY_SIZE(timer0_parent_idx)); hws[TMR0_GATE] = ma35d1_clk_gate(dev, "tmr0_gate", "tmr0_mux", clk_base + REG_CLK_APBCLK0, 0); - hws[TMR1_MUX] = ma35d1_clk_mux(dev, "tmr1_mux", clk_base + REG_CLK_CLKSEL1, - 4, 3, timer1_sel_clks, - ARRAY_SIZE(timer1_sel_clks)); + hws[TMR1_MUX] = ma35d1_clk_mux(dev, "tmr1_mux", clk_base + REG_CLK_CLKSEL1, 4, 3, hws, + timer1_parent_idx, ARRAY_SIZE(timer1_parent_idx)); hws[TMR1_GATE] = ma35d1_clk_gate(dev, "tmr1_gate", "tmr1_mux", clk_base + REG_CLK_APBCLK0, 1); - hws[TMR2_MUX] = ma35d1_clk_mux(dev, "tmr2_mux", clk_base + REG_CLK_CLKSEL1, - 8, 3, timer2_sel_clks, - ARRAY_SIZE(timer2_sel_clks)); + hws[TMR2_MUX] = ma35d1_clk_mux(dev, "tmr2_mux", clk_base + REG_CLK_CLKSEL1, 8, 3, hws, + timer2_parent_idx, ARRAY_SIZE(timer2_parent_idx)); hws[TMR2_GATE] = ma35d1_clk_gate(dev, "tmr2_gate", "tmr2_mux", clk_base + REG_CLK_APBCLK0, 2); - hws[TMR3_MUX] = ma35d1_clk_mux(dev, "tmr3_mux", clk_base + REG_CLK_CLKSEL1, - 12, 3, timer3_sel_clks, - ARRAY_SIZE(timer3_sel_clks)); + hws[TMR3_MUX] = ma35d1_clk_mux(dev, "tmr3_mux", clk_base + REG_CLK_CLKSEL1, 12, 3, hws, + timer3_parent_idx, ARRAY_SIZE(timer3_parent_idx)); hws[TMR3_GATE] = ma35d1_clk_gate(dev, "tmr3_gate", "tmr3_mux", clk_base + REG_CLK_APBCLK0, 3); - hws[TMR4_MUX] = ma35d1_clk_mux(dev, "tmr4_mux", clk_base + REG_CLK_CLKSEL1, - 16, 3, timer4_sel_clks, - ARRAY_SIZE(timer4_sel_clks)); + hws[TMR4_MUX] = ma35d1_clk_mux(dev, "tmr4_mux", clk_base + REG_CLK_CLKSEL1, 16, 3, hws, + timer4_parent_idx, ARRAY_SIZE(timer4_parent_idx)); hws[TMR4_GATE] = ma35d1_clk_gate(dev, "tmr4_gate", "tmr4_mux", clk_base + REG_CLK_APBCLK0, 4); - hws[TMR5_MUX] = ma35d1_clk_mux(dev, "tmr5_mux", clk_base + REG_CLK_CLKSEL1, - 20, 3, timer5_sel_clks, - ARRAY_SIZE(timer5_sel_clks)); + hws[TMR5_MUX] = ma35d1_clk_mux(dev, "tmr5_mux", clk_base + REG_CLK_CLKSEL1, 20, 3, hws, + timer5_parent_idx, ARRAY_SIZE(timer5_parent_idx)); hws[TMR5_GATE] = ma35d1_clk_gate(dev, "tmr5_gate", "tmr5_mux", clk_base + REG_CLK_APBCLK0, 5); - hws[TMR6_MUX] = ma35d1_clk_mux(dev, "tmr6_mux", clk_base + REG_CLK_CLKSEL1, - 24, 3, timer6_sel_clks, - ARRAY_SIZE(timer6_sel_clks)); + hws[TMR6_MUX] = ma35d1_clk_mux(dev, "tmr6_mux", clk_base + REG_CLK_CLKSEL1, 24, 3, hws, + timer6_parent_idx, ARRAY_SIZE(timer6_parent_idx)); hws[TMR6_GATE] = ma35d1_clk_gate(dev, "tmr6_gate", "tmr6_mux", clk_base + REG_CLK_APBCLK0, 6); - hws[TMR7_MUX] = ma35d1_clk_mux(dev, "tmr7_mux", clk_base + REG_CLK_CLKSEL1, - 28, 3, timer7_sel_clks, - ARRAY_SIZE(timer7_sel_clks)); + hws[TMR7_MUX] = ma35d1_clk_mux(dev, "tmr7_mux", clk_base + REG_CLK_CLKSEL1, 28, 3, hws, + timer7_parent_idx, ARRAY_SIZE(timer7_parent_idx)); hws[TMR7_GATE] = ma35d1_clk_gate(dev, "tmr7_gate", "tmr7_mux", clk_base + REG_CLK_APBCLK0, 7); - hws[TMR8_MUX] = ma35d1_clk_mux(dev, "tmr8_mux", clk_base + REG_CLK_CLKSEL2, - 0, 3, timer8_sel_clks, - ARRAY_SIZE(timer8_sel_clks)); + hws[TMR8_MUX] = ma35d1_clk_mux(dev, "tmr8_mux", clk_base + REG_CLK_CLKSEL2, 0, 3, hws, + timer8_parent_idx, ARRAY_SIZE(timer8_parent_idx)); hws[TMR8_GATE] = ma35d1_clk_gate(dev, "tmr8_gate", "tmr8_mux", clk_base + REG_CLK_APBCLK0, 8); - hws[TMR9_MUX] = ma35d1_clk_mux(dev, "tmr9_mux", clk_base + REG_CLK_CLKSEL2, - 4, 3, timer9_sel_clks, - ARRAY_SIZE(timer9_sel_clks)); + hws[TMR9_MUX] = ma35d1_clk_mux(dev, "tmr9_mux", clk_base + REG_CLK_CLKSEL2, 4, 3, hws, + timer9_parent_idx, ARRAY_SIZE(timer9_parent_idx)); hws[TMR9_GATE] = ma35d1_clk_gate(dev, "tmr9_gate", "tmr9_mux", clk_base + REG_CLK_APBCLK0, 9); - hws[TMR10_MUX] = ma35d1_clk_mux(dev, "tmr10_mux", clk_base + REG_CLK_CLKSEL2, - 8, 3, timer10_sel_clks, - ARRAY_SIZE(timer10_sel_clks)); + hws[TMR10_MUX] = ma35d1_clk_mux(dev, "tmr10_mux", clk_base + REG_CLK_CLKSEL2, 8, 3, hws, + timer10_parent_idx, ARRAY_SIZE(timer10_parent_idx)); hws[TMR10_GATE] = ma35d1_clk_gate(dev, "tmr10_gate", "tmr10_mux", clk_base + REG_CLK_APBCLK0, 10); - hws[TMR11_MUX] = ma35d1_clk_mux(dev, "tmr11_mux", clk_base + REG_CLK_CLKSEL2, - 12, 3, timer11_sel_clks, - ARRAY_SIZE(timer11_sel_clks)); + hws[TMR11_MUX] = ma35d1_clk_mux(dev, "tmr11_mux", clk_base + REG_CLK_CLKSEL2, 12, 3, hws, + timer11_parent_idx, ARRAY_SIZE(timer11_parent_idx)); hws[TMR11_GATE] = ma35d1_clk_gate(dev, "tmr11_gate", "tmr11_mux", clk_base + REG_CLK_APBCLK0, 11); - hws[UART0_MUX] = ma35d1_clk_mux(dev, "uart0_mux", clk_base + REG_CLK_CLKSEL2, - 16, 2, uart_sel_clks, ARRAY_SIZE(uart_sel_clks)); + hws[UART0_MUX] = ma35d1_clk_mux(dev, "uart0_mux", clk_base + REG_CLK_CLKSEL2, 16, 2, hws, + uart_parent_idx, ARRAY_SIZE(uart_parent_idx)); hws[UART0_DIV] = ma35d1_clk_divider(dev, "uart0_div", "uart0_mux", clk_base + REG_CLK_CLKDIV1, 16, 4); hws[UART0_GATE] = ma35d1_clk_gate(dev, "uart0_gate", "uart0_div", clk_base + REG_CLK_APBCLK0, 12); - hws[UART1_MUX] = ma35d1_clk_mux(dev, "uart1_mux", clk_base + REG_CLK_CLKSEL2, - 18, 2, uart_sel_clks, ARRAY_SIZE(uart_sel_clks)); + hws[UART1_MUX] = ma35d1_clk_mux(dev, "uart1_mux", clk_base + REG_CLK_CLKSEL2, 18, 2, hws, + uart_parent_idx, ARRAY_SIZE(uart_parent_idx)); hws[UART1_DIV] = ma35d1_clk_divider(dev, "uart1_div", "uart1_mux", clk_base + REG_CLK_CLKDIV1, 20, 4); hws[UART1_GATE] = ma35d1_clk_gate(dev, "uart1_gate", "uart1_div", clk_base + REG_CLK_APBCLK0, 13); - hws[UART2_MUX] = ma35d1_clk_mux(dev, "uart2_mux", clk_base + REG_CLK_CLKSEL2, - 20, 2, uart_sel_clks, ARRAY_SIZE(uart_sel_clks)); + hws[UART2_MUX] = ma35d1_clk_mux(dev, "uart2_mux", clk_base + REG_CLK_CLKSEL2, 20, 2, hws, + uart_parent_idx, ARRAY_SIZE(uart_parent_idx)); hws[UART2_DIV] = ma35d1_clk_divider(dev, "uart2_div", "uart2_mux", clk_base + REG_CLK_CLKDIV1, 24, 4); hws[UART2_GATE] = ma35d1_clk_gate(dev, "uart2_gate", "uart2_div", clk_base + REG_CLK_APBCLK0, 14); - hws[UART3_MUX] = ma35d1_clk_mux(dev, "uart3_mux", clk_base + REG_CLK_CLKSEL2, - 22, 2, uart_sel_clks, ARRAY_SIZE(uart_sel_clks)); + hws[UART3_MUX] = ma35d1_clk_mux(dev, "uart3_mux", clk_base + REG_CLK_CLKSEL2, 22, 2, hws, + uart_parent_idx, ARRAY_SIZE(uart_parent_idx)); hws[UART3_DIV] = ma35d1_clk_divider(dev, "uart3_div", "uart3_mux", clk_base + REG_CLK_CLKDIV1, 28, 4); hws[UART3_GATE] = ma35d1_clk_gate(dev, "uart3_gate", "uart3_div", clk_base + REG_CLK_APBCLK0, 15); - hws[UART4_MUX] = ma35d1_clk_mux(dev, "uart4_mux", clk_base + REG_CLK_CLKSEL2, - 24, 2, uart_sel_clks, ARRAY_SIZE(uart_sel_clks)); + hws[UART4_MUX] = ma35d1_clk_mux(dev, "uart4_mux", clk_base + REG_CLK_CLKSEL2, 24, 2, hws, + uart_parent_idx, ARRAY_SIZE(uart_parent_idx)); hws[UART4_DIV] = ma35d1_clk_divider(dev, "uart4_div", "uart4_mux", clk_base + REG_CLK_CLKDIV2, 0, 4); hws[UART4_GATE] = ma35d1_clk_gate(dev, "uart4_gate", "uart4_div", clk_base + REG_CLK_APBCLK0, 16); - hws[UART5_MUX] = ma35d1_clk_mux(dev, "uart5_mux", clk_base + REG_CLK_CLKSEL2, - 26, 2, uart_sel_clks, ARRAY_SIZE(uart_sel_clks)); + hws[UART5_MUX] = ma35d1_clk_mux(dev, "uart5_mux", clk_base + REG_CLK_CLKSEL2, 26, 2, hws, + uart_parent_idx, ARRAY_SIZE(uart_parent_idx)); hws[UART5_DIV] = ma35d1_clk_divider(dev, "uart5_div", "uart5_mux", clk_base + REG_CLK_CLKDIV2, 4, 4); hws[UART5_GATE] = ma35d1_clk_gate(dev, "uart5_gate", "uart5_div", clk_base + REG_CLK_APBCLK0, 17); - hws[UART6_MUX] = ma35d1_clk_mux(dev, "uart6_mux", clk_base + REG_CLK_CLKSEL2, - 28, 2, uart_sel_clks, ARRAY_SIZE(uart_sel_clks)); + hws[UART6_MUX] = ma35d1_clk_mux(dev, "uart6_mux", clk_base + REG_CLK_CLKSEL2, 28, 2, hws, + uart_parent_idx, ARRAY_SIZE(uart_parent_idx)); hws[UART6_DIV] = ma35d1_clk_divider(dev, "uart6_div", "uart6_mux", clk_base + REG_CLK_CLKDIV2, 8, 4); hws[UART6_GATE] = ma35d1_clk_gate(dev, "uart6_gate", "uart6_div", clk_base + REG_CLK_APBCLK0, 18); - hws[UART7_MUX] = ma35d1_clk_mux(dev, "uart7_mux", clk_base + REG_CLK_CLKSEL2, - 30, 2, uart_sel_clks, ARRAY_SIZE(uart_sel_clks)); + hws[UART7_MUX] = ma35d1_clk_mux(dev, "uart7_mux", clk_base + REG_CLK_CLKSEL2, 30, 2, hws, + uart_parent_idx, ARRAY_SIZE(uart_parent_idx)); hws[UART7_DIV] = ma35d1_clk_divider(dev, "uart7_div", "uart7_mux", clk_base + REG_CLK_CLKDIV2, 12, 4); hws[UART7_GATE] = ma35d1_clk_gate(dev, "uart7_gate", "uart7_div", clk_base + REG_CLK_APBCLK0, 19); - hws[UART8_MUX] = ma35d1_clk_mux(dev, "uart8_mux", clk_base + REG_CLK_CLKSEL3, - 0, 2, uart_sel_clks, ARRAY_SIZE(uart_sel_clks)); + hws[UART8_MUX] = ma35d1_clk_mux(dev, "uart8_mux", clk_base + REG_CLK_CLKSEL3, 0, 2, hws, + uart_parent_idx, ARRAY_SIZE(uart_parent_idx)); hws[UART8_DIV] = ma35d1_clk_divider(dev, "uart8_div", "uart8_mux", clk_base + REG_CLK_CLKDIV2, 16, 4); hws[UART8_GATE] = ma35d1_clk_gate(dev, "uart8_gate", "uart8_div", clk_base + REG_CLK_APBCLK0, 20); - hws[UART9_MUX] = ma35d1_clk_mux(dev, "uart9_mux", clk_base + REG_CLK_CLKSEL3, - 2, 2, uart_sel_clks, ARRAY_SIZE(uart_sel_clks)); + hws[UART9_MUX] = ma35d1_clk_mux(dev, "uart9_mux", clk_base + REG_CLK_CLKSEL3, 2, 2, hws, + uart_parent_idx, ARRAY_SIZE(uart_parent_idx)); hws[UART9_DIV] = ma35d1_clk_divider(dev, "uart9_div", "uart9_mux", clk_base + REG_CLK_CLKDIV2, 20, 4); hws[UART9_GATE] = ma35d1_clk_gate(dev, "uart9_gate", "uart9_div", clk_base + REG_CLK_APBCLK0, 21); - hws[UART10_MUX] = ma35d1_clk_mux(dev, "uart10_mux", clk_base + REG_CLK_CLKSEL3, - 4, 2, uart_sel_clks, ARRAY_SIZE(uart_sel_clks)); + hws[UART10_MUX] = ma35d1_clk_mux(dev, "uart10_mux", clk_base + REG_CLK_CLKSEL3, 4, 2, hws, + uart_parent_idx, ARRAY_SIZE(uart_parent_idx)); hws[UART10_DIV] = ma35d1_clk_divider(dev, "uart10_div", "uart10_mux", clk_base + REG_CLK_CLKDIV2, 24, 4); hws[UART10_GATE] = ma35d1_clk_gate(dev, "uart10_gate", "uart10_div", clk_base + REG_CLK_APBCLK0, 22); - hws[UART11_MUX] = ma35d1_clk_mux(dev, "uart11_mux", clk_base + REG_CLK_CLKSEL3, - 6, 2, uart_sel_clks, ARRAY_SIZE(uart_sel_clks)); + hws[UART11_MUX] = ma35d1_clk_mux(dev, "uart11_mux", clk_base + REG_CLK_CLKSEL3, 6, 2, hws, + uart_parent_idx, ARRAY_SIZE(uart_parent_idx)); hws[UART11_DIV] = ma35d1_clk_divider(dev, "uart11_div", "uart11_mux", clk_base + REG_CLK_CLKDIV2, 28, 4); hws[UART11_GATE] = ma35d1_clk_gate(dev, "uart11_gate", "uart11_div", clk_base + REG_CLK_APBCLK0, 23); - hws[UART12_MUX] = ma35d1_clk_mux(dev, "uart12_mux", clk_base + REG_CLK_CLKSEL3, - 8, 2, uart_sel_clks, ARRAY_SIZE(uart_sel_clks)); + hws[UART12_MUX] = ma35d1_clk_mux(dev, "uart12_mux", clk_base + REG_CLK_CLKSEL3, 8, 2, hws, + uart_parent_idx, ARRAY_SIZE(uart_parent_idx)); hws[UART12_DIV] = ma35d1_clk_divider(dev, "uart12_div", "uart12_mux", clk_base + REG_CLK_CLKDIV3, 0, 4); hws[UART12_GATE] = ma35d1_clk_gate(dev, "uart12_gate", "uart12_div", clk_base + REG_CLK_APBCLK0, 24); - hws[UART13_MUX] = ma35d1_clk_mux(dev, "uart13_mux", clk_base + REG_CLK_CLKSEL3, - 10, 2, uart_sel_clks, ARRAY_SIZE(uart_sel_clks)); + hws[UART13_MUX] = ma35d1_clk_mux(dev, "uart13_mux", clk_base + REG_CLK_CLKSEL3, 10, 2, hws, + uart_parent_idx, ARRAY_SIZE(uart_parent_idx)); hws[UART13_DIV] = ma35d1_clk_divider(dev, "uart13_div", "uart13_mux", clk_base + REG_CLK_CLKDIV3, 4, 4); hws[UART13_GATE] = ma35d1_clk_gate(dev, "uart13_gate", "uart13_div", clk_base + REG_CLK_APBCLK0, 25); - hws[UART14_MUX] = ma35d1_clk_mux(dev, "uart14_mux", clk_base + REG_CLK_CLKSEL3, - 12, 2, uart_sel_clks, ARRAY_SIZE(uart_sel_clks)); + hws[UART14_MUX] = ma35d1_clk_mux(dev, "uart14_mux", clk_base + REG_CLK_CLKSEL3, 12, 2, hws, + uart_parent_idx, ARRAY_SIZE(uart_parent_idx)); hws[UART14_DIV] = ma35d1_clk_divider(dev, "uart14_div", "uart14_mux", clk_base + REG_CLK_CLKDIV3, 8, 4); hws[UART14_GATE] = ma35d1_clk_gate(dev, "uart14_gate", "uart14_div", clk_base + REG_CLK_APBCLK0, 26); - hws[UART15_MUX] = ma35d1_clk_mux(dev, "uart15_mux", clk_base + REG_CLK_CLKSEL3, - 14, 2, uart_sel_clks, ARRAY_SIZE(uart_sel_clks)); + hws[UART15_MUX] = ma35d1_clk_mux(dev, "uart15_mux", clk_base + REG_CLK_CLKSEL3, 14, 2, hws, + uart_parent_idx, ARRAY_SIZE(uart_parent_idx)); hws[UART15_DIV] = ma35d1_clk_divider(dev, "uart15_div", "uart15_mux", clk_base + REG_CLK_CLKDIV3, 12, 4); hws[UART15_GATE] = ma35d1_clk_gate(dev, "uart15_gate", "uart15_div", clk_base + REG_CLK_APBCLK0, 27); - hws[UART16_MUX] = ma35d1_clk_mux(dev, "uart16_mux", clk_base + REG_CLK_CLKSEL3, - 16, 2, uart_sel_clks, ARRAY_SIZE(uart_sel_clks)); + hws[UART16_MUX] = ma35d1_clk_mux(dev, "uart16_mux", clk_base + REG_CLK_CLKSEL3, 16, 2, hws, + uart_parent_idx, ARRAY_SIZE(uart_parent_idx)); hws[UART16_DIV] = ma35d1_clk_divider(dev, "uart16_div", "uart16_mux", clk_base + REG_CLK_CLKDIV3, 16, 4); @@ -900,8 +628,8 @@ static int ma35d1_clocks_probe(struct platform_device *pdev) hws[DDR_GATE] = ma35d1_clk_gate(dev, "ddr_gate", "ddrpll", clk_base + REG_CLK_APBCLK0, 30); - hws[KPI_MUX] = ma35d1_clk_mux(dev, "kpi_mux", clk_base + REG_CLK_CLKSEL4, - 30, 1, kpi_sel_clks, ARRAY_SIZE(kpi_sel_clks)); + hws[KPI_MUX] = ma35d1_clk_mux(dev, "kpi_mux", clk_base + REG_CLK_CLKSEL4, 30, 1, hws, + kpi_parent_idx, ARRAY_SIZE(kpi_parent_idx)); hws[KPI_DIV] = ma35d1_clk_divider(dev, "kpi_div", "kpi_mux", clk_base + REG_CLK_CLKDIV4, 24, 8); @@ -921,49 +649,49 @@ static int ma35d1_clocks_probe(struct platform_device *pdev) hws[I2C5_GATE] = ma35d1_clk_gate(dev, "i2c5_gate", "pclk2", clk_base + REG_CLK_APBCLK1, 5); - hws[QSPI0_MUX] = ma35d1_clk_mux(dev, "qspi0_mux", clk_base + REG_CLK_CLKSEL4, - 8, 2, qspi0_sel_clks, ARRAY_SIZE(qspi0_sel_clks)); + hws[QSPI0_MUX] = ma35d1_clk_mux(dev, "qspi0_mux", clk_base + REG_CLK_CLKSEL4, 8, 2, hws, + qspi_parent_idx, ARRAY_SIZE(qspi_parent_idx)); hws[QSPI0_GATE] = ma35d1_clk_gate(dev, "qspi0_gate", "qspi0_mux", clk_base + REG_CLK_APBCLK1, 6); - hws[QSPI1_MUX] = ma35d1_clk_mux(dev, "qspi1_mux", clk_base + REG_CLK_CLKSEL4, - 10, 2, qspi1_sel_clks, ARRAY_SIZE(qspi1_sel_clks)); + hws[QSPI1_MUX] = ma35d1_clk_mux(dev, "qspi1_mux", clk_base + REG_CLK_CLKSEL4, 10, 2, hws, + qspi_parent_idx, ARRAY_SIZE(qspi_parent_idx)); hws[QSPI1_GATE] = ma35d1_clk_gate(dev, "qspi1_gate", "qspi1_mux", clk_base + REG_CLK_APBCLK1, 7); - hws[SMC0_MUX] = ma35d1_clk_mux(dev, "smc0_mux", clk_base + REG_CLK_CLKSEL4, - 28, 1, smc_sel_clks, ARRAY_SIZE(smc_sel_clks)); + hws[SMC0_MUX] = ma35d1_clk_mux(dev, "smc0_mux", clk_base + REG_CLK_CLKSEL4, 28, 1, hws, + smc_parent_idx, ARRAY_SIZE(smc_parent_idx)); hws[SMC0_DIV] = ma35d1_clk_divider(dev, "smc0_div", "smc0_mux", clk_base + REG_CLK_CLKDIV1, 0, 4); hws[SMC0_GATE] = ma35d1_clk_gate(dev, "smc0_gate", "smc0_div", clk_base + REG_CLK_APBCLK1, 12); - hws[SMC1_MUX] = ma35d1_clk_mux(dev, "smc1_mux", clk_base + REG_CLK_CLKSEL4, - 29, 1, smc_sel_clks, ARRAY_SIZE(smc_sel_clks)); + hws[SMC1_MUX] = ma35d1_clk_mux(dev, "smc1_mux", clk_base + REG_CLK_CLKSEL4, 29, 1, hws, + smc_parent_idx, ARRAY_SIZE(smc_parent_idx)); hws[SMC1_DIV] = ma35d1_clk_divider(dev, "smc1_div", "smc1_mux", clk_base + REG_CLK_CLKDIV1, 4, 4); hws[SMC1_GATE] = ma35d1_clk_gate(dev, "smc1_gate", "smc1_div", clk_base + REG_CLK_APBCLK1, 13); - hws[WDT0_MUX] = ma35d1_clk_mux(dev, "wdt0_mux", clk_base + REG_CLK_CLKSEL3, - 20, 2, wdt0_sel_clks, ARRAY_SIZE(wdt0_sel_clks)); + hws[WDT0_MUX] = ma35d1_clk_mux(dev, "wdt0_mux", clk_base + REG_CLK_CLKSEL3, 20, 2, hws, + wdt0_parent_idx, ARRAY_SIZE(wdt0_parent_idx)); hws[WDT0_GATE] = ma35d1_clk_gate(dev, "wdt0_gate", "wdt0_mux", clk_base + REG_CLK_APBCLK1, 16); - hws[WDT1_MUX] = ma35d1_clk_mux(dev, "wdt1_mux", clk_base + REG_CLK_CLKSEL3, - 24, 2, wdt1_sel_clks, ARRAY_SIZE(wdt1_sel_clks)); + hws[WDT1_MUX] = ma35d1_clk_mux(dev, "wdt1_mux", clk_base + REG_CLK_CLKSEL3, 24, 2, hws, + wdt1_parent_idx, ARRAY_SIZE(wdt1_parent_idx)); hws[WDT1_GATE] = ma35d1_clk_gate(dev, "wdt1_gate", "wdt1_mux", clk_base + REG_CLK_APBCLK1, 17); - hws[WDT2_MUX] = ma35d1_clk_mux(dev, "wdt2_mux", clk_base + REG_CLK_CLKSEL3, - 28, 2, wdt2_sel_clks, ARRAY_SIZE(wdt2_sel_clks)); + hws[WDT2_MUX] = ma35d1_clk_mux(dev, "wdt2_mux", clk_base + REG_CLK_CLKSEL3, 28, 2, hws, + wdt2_parent_idx, ARRAY_SIZE(wdt2_parent_idx)); hws[WDT2_GATE] = ma35d1_clk_gate(dev, "wdt2_gate", "wdt2_mux", clk_base + REG_CLK_APBCLK1, 18); - hws[WWDT0_MUX] = ma35d1_clk_mux(dev, "wwdt0_mux", clk_base + REG_CLK_CLKSEL3, - 22, 2, wwdt0_sel_clks, ARRAY_SIZE(wwdt0_sel_clks)); - hws[WWDT1_MUX] = ma35d1_clk_mux(dev, "wwdt1_mux", clk_base + REG_CLK_CLKSEL3, - 26, 2, wwdt1_sel_clks, ARRAY_SIZE(wwdt1_sel_clks)); - hws[WWDT2_MUX] = ma35d1_clk_mux(dev, "wwdt2_mux", clk_base + REG_CLK_CLKSEL3, - 30, 2, wwdt2_sel_clks, ARRAY_SIZE(wwdt2_sel_clks)); + hws[WWDT0_MUX] = ma35d1_clk_mux(dev, "wwdt0_mux", clk_base + REG_CLK_CLKSEL3, 22, 2, hws, + wwdt0_parent_idx, ARRAY_SIZE(wwdt0_parent_idx)); + hws[WWDT1_MUX] = ma35d1_clk_mux(dev, "wwdt1_mux", clk_base + REG_CLK_CLKSEL3, 26, 2, hws, + wwdt1_parent_idx, ARRAY_SIZE(wwdt1_parent_idx)); + hws[WWDT2_MUX] = ma35d1_clk_mux(dev, "wwdt2_mux", clk_base + REG_CLK_CLKSEL3, 30, 2, hws, + wwdt2_parent_idx, ARRAY_SIZE(wwdt2_parent_idx)); hws[EPWM0_GATE] = ma35d1_clk_gate(dev, "epwm0_gate", "pclk1", clk_base + REG_CLK_APBCLK1, 24); @@ -972,12 +700,12 @@ static int ma35d1_clocks_probe(struct platform_device *pdev) hws[EPWM2_GATE] = ma35d1_clk_gate(dev, "epwm2_gate", "pclk1", clk_base + REG_CLK_APBCLK1, 26); - hws[I2S0_MUX] = ma35d1_clk_mux(dev, "i2s0_mux", clk_base + REG_CLK_CLKSEL4, - 12, 2, i2s0_sel_clks, ARRAY_SIZE(i2s0_sel_clks)); + hws[I2S0_MUX] = ma35d1_clk_mux(dev, "i2s0_mux", clk_base + REG_CLK_CLKSEL4, 12, 2, hws, + i2s_parent_idx, ARRAY_SIZE(i2s_parent_idx)); hws[I2S0_GATE] = ma35d1_clk_gate(dev, "i2s0_gate", "i2s0_mux", clk_base + REG_CLK_APBCLK2, 0); - hws[I2S1_MUX] = ma35d1_clk_mux(dev, "i2s1_mux", clk_base + REG_CLK_CLKSEL4, - 14, 2, i2s1_sel_clks, ARRAY_SIZE(i2s1_sel_clks)); + hws[I2S1_MUX] = ma35d1_clk_mux(dev, "i2s1_mux", clk_base + REG_CLK_CLKSEL4, 14, 2, hws, + i2s_parent_idx, ARRAY_SIZE(i2s_parent_idx)); hws[I2S1_GATE] = ma35d1_clk_gate(dev, "i2s1_gate", "i2s1_mux", clk_base + REG_CLK_APBCLK2, 1); @@ -986,20 +714,20 @@ static int ma35d1_clocks_probe(struct platform_device *pdev) hws[SSPCC_GATE] = ma35d1_clk_gate(dev, "sspcc_gate", "pclk3", clk_base + REG_CLK_APBCLK2, 3); - hws[SPI0_MUX] = ma35d1_clk_mux(dev, "spi0_mux", clk_base + REG_CLK_CLKSEL4, - 0, 2, spi0_sel_clks, ARRAY_SIZE(spi0_sel_clks)); + hws[SPI0_MUX] = ma35d1_clk_mux(dev, "spi0_mux", clk_base + REG_CLK_CLKSEL4, 0, 2, hws, + spi0_parent_idx, ARRAY_SIZE(spi0_parent_idx)); hws[SPI0_GATE] = ma35d1_clk_gate(dev, "spi0_gate", "spi0_mux", clk_base + REG_CLK_APBCLK2, 4); - hws[SPI1_MUX] = ma35d1_clk_mux(dev, "spi1_mux", clk_base + REG_CLK_CLKSEL4, - 2, 2, spi1_sel_clks, ARRAY_SIZE(spi1_sel_clks)); + hws[SPI1_MUX] = ma35d1_clk_mux(dev, "spi1_mux", clk_base + REG_CLK_CLKSEL4, 2, 2, hws, + spi1_parent_idx, ARRAY_SIZE(spi1_parent_idx)); hws[SPI1_GATE] = ma35d1_clk_gate(dev, "spi1_gate", "spi1_mux", clk_base + REG_CLK_APBCLK2, 5); - hws[SPI2_MUX] = ma35d1_clk_mux(dev, "spi2_mux", clk_base + REG_CLK_CLKSEL4, - 4, 2, spi2_sel_clks, ARRAY_SIZE(spi2_sel_clks)); + hws[SPI2_MUX] = ma35d1_clk_mux(dev, "spi2_mux", clk_base + REG_CLK_CLKSEL4, 4, 2, hws, + spi2_parent_idx, ARRAY_SIZE(spi2_parent_idx)); hws[SPI2_GATE] = ma35d1_clk_gate(dev, "spi2_gate", "spi2_mux", clk_base + REG_CLK_APBCLK2, 6); - hws[SPI3_MUX] = ma35d1_clk_mux(dev, "spi3_mux", clk_base + REG_CLK_CLKSEL4, - 6, 2, spi3_sel_clks, ARRAY_SIZE(spi3_sel_clks)); + hws[SPI3_MUX] = ma35d1_clk_mux(dev, "spi3_mux", clk_base + REG_CLK_CLKSEL4, 6, 2, hws, + spi3_parent_idx, ARRAY_SIZE(spi3_parent_idx)); hws[SPI3_GATE] = ma35d1_clk_gate(dev, "spi3_gate", "spi3_mux", clk_base + REG_CLK_APBCLK2, 7); -- 2.55.0 ^ permalink raw reply related [flat|nested] 15+ messages in thread
* [PATCH v8 2/7] clk: nuvoton: ma35d1: Avoid possible error pointer dereferencing 2026-10-04 20:45 [PATCH v8 0/7] clk: nuvoton: ma35d1: Fix mux parenting and peripheral clock rates Miquel Raynal 2026-10-04 20:45 ` [PATCH v8 1/7] clk: nuvoton: ma35d1: Use clk_hw pointers as mux parents Miquel Raynal @ 2026-10-04 20:45 ` Miquel Raynal 2026-10-04 20:45 ` [PATCH v8 3/7] clk: nuvoton: ma35d1: Retrieve HXT/LXT from DT when possible Miquel Raynal ` (4 subsequent siblings) 6 siblings, 0 replies; 15+ messages in thread From: Miquel Raynal @ 2026-10-04 20:45 UTC (permalink / raw) To: Jacky Huang, Shan-Chun Hung, Michael Turquette, Stephen Boyd, Richard Cochran, Arnd Bergmann, Brian Masney, Jerome Brunet, Rob Herring, Krzysztof Kozlowski, Conor Dooley, Andrew Jeffery, Avi Fishman, Tomer Maimon, Tali Perry, Patrick Venture, Nancy Yuen, Benjamin Fair Cc: Thomas Petazzoni, Steam Lin, linux-arm-kernel, linux-clk, linux-kernel, Krzysztof Kozlowski, devicetree, openbmc, Miquel Raynal MA35D1 registration helpers store their parent_hw argument straight into the parent data, without checking it first. In case of registration failure an error pointer will be stored in the table, which is then forwarded to the clk core, which treats any non-NULL parent as valid handles. Bail out early when the parent is an error pointer, instead of building the parent data. This issue is mostly theoretical in practice, since reaching such an error would involve a very early -ENOMEM. Signed-off-by: Miquel Raynal <miquel.raynal@bootlin.com> --- drivers/clk/nuvoton/clk-ma35d1-divider.c | 3 +++ drivers/clk/nuvoton/clk-ma35d1-pll.c | 3 +++ drivers/clk/nuvoton/clk-ma35d1.c | 13 +++++++++++-- 3 files changed, 17 insertions(+), 2 deletions(-) diff --git a/drivers/clk/nuvoton/clk-ma35d1-divider.c b/drivers/clk/nuvoton/clk-ma35d1-divider.c index e992e7c30341..57a7b4ed3b5e 100644 --- a/drivers/clk/nuvoton/clk-ma35d1-divider.c +++ b/drivers/clk/nuvoton/clk-ma35d1-divider.c @@ -90,6 +90,9 @@ struct clk_hw *ma35d1_reg_adc_clkdiv(struct device *dev, const char *name, int ret; int i; + if (IS_ERR(parent_hw)) + return parent_hw; + div = devm_kzalloc(dev, sizeof(*div), GFP_KERNEL); if (!div) return ERR_PTR(-ENOMEM); diff --git a/drivers/clk/nuvoton/clk-ma35d1-pll.c b/drivers/clk/nuvoton/clk-ma35d1-pll.c index c7c0dc91a012..92424e9c669d 100644 --- a/drivers/clk/nuvoton/clk-ma35d1-pll.c +++ b/drivers/clk/nuvoton/clk-ma35d1-pll.c @@ -336,6 +336,9 @@ struct clk_hw *ma35d1_reg_clk_pll(struct device *dev, u32 id, u8 u8mode, const c struct clk_hw *hw; int ret; + if (IS_ERR(parent_hw)) + return parent_hw; + pll = devm_kzalloc(dev, sizeof(*pll), GFP_KERNEL); if (!pll) return ERR_PTR(-ENOMEM); diff --git a/drivers/clk/nuvoton/clk-ma35d1.c b/drivers/clk/nuvoton/clk-ma35d1.c index 1a857f28310f..ceebcbd8c18b 100644 --- a/drivers/clk/nuvoton/clk-ma35d1.c +++ b/drivers/clk/nuvoton/clk-ma35d1.c @@ -130,10 +130,19 @@ static struct clk_hw *ma35d1_clk_mux(struct device *dev, const char *name, const int *parent_idx, int num_parents) { const struct clk_hw *parent_hws[MA35D1_MUX_MAX_PARENTS] = {}; + struct clk_hw *parent; int i; - for (i = 0; i < num_parents; i++) - parent_hws[i] = (parent_idx[i] >= 0) ? hws[parent_idx[i]] : NULL; + for (i = 0; i < num_parents; i++) { + if (parent_idx[i] < 0) + continue; + + parent = hws[parent_idx[i]]; + if (IS_ERR(parent)) + return parent; + + parent_hws[i] = parent; + } return clk_hw_register_mux_hws(dev, name, parent_hws, num_parents, CLK_SET_RATE_NO_REPARENT, reg, shift, -- 2.55.0 ^ permalink raw reply related [flat|nested] 15+ messages in thread
* [PATCH v8 3/7] clk: nuvoton: ma35d1: Retrieve HXT/LXT from DT when possible 2026-10-04 20:45 [PATCH v8 0/7] clk: nuvoton: ma35d1: Fix mux parenting and peripheral clock rates Miquel Raynal 2026-10-04 20:45 ` [PATCH v8 1/7] clk: nuvoton: ma35d1: Use clk_hw pointers as mux parents Miquel Raynal 2026-10-04 20:45 ` [PATCH v8 2/7] clk: nuvoton: ma35d1: Avoid possible error pointer dereferencing Miquel Raynal @ 2026-10-04 20:45 ` Miquel Raynal 2026-10-04 20:59 ` sashiko-bot 2026-10-04 20:45 ` [PATCH v8 4/7] clk: nuvoton: ma35d1: Reparent the gates correctly Miquel Raynal ` (3 subsequent siblings) 6 siblings, 1 reply; 15+ messages in thread From: Miquel Raynal @ 2026-10-04 20:45 UTC (permalink / raw) To: Jacky Huang, Shan-Chun Hung, Michael Turquette, Stephen Boyd, Richard Cochran, Arnd Bergmann, Brian Masney, Jerome Brunet, Rob Herring, Krzysztof Kozlowski, Conor Dooley, Andrew Jeffery, Avi Fishman, Tomer Maimon, Tali Perry, Patrick Venture, Nancy Yuen, Benjamin Fair Cc: Thomas Petazzoni, Steam Lin, linux-arm-kernel, linux-clk, linux-kernel, Krzysztof Kozlowski, devicetree, openbmc, Miquel Raynal, stable HXT and LXT are crystal oscillator inputs of the clock controller. As such, they are external clock sources which should not be registered by this driver. HXT is already described in the DT, but is not named. In order to point to this parent from its direct child which is HXT_GATE, we must provide a fw_name (when it is named, new DTs) and a .name (for when it's not named, but the fixed clock node name is used). LXT is missing in old DTs, so we must create that clock and register it for backward compatibility reasons. It should however be described and pointed at in updated DTs. describe LXT at all, we assume that HXT must be present, and fallback to creating a fixed clock for LXT if it is not described (for backward compatibility purposes). Fixes: 691521a367cf ("clk: nuvoton: Add clock driver for ma35d1 clock controller") Cc: stable@vger.kernel.org Signed-off-by: Miquel Raynal <miquel.raynal@bootlin.com> --- drivers/clk/nuvoton/clk-ma35d1.c | 37 ++++++++++++++++++++++++++++++------- 1 file changed, 30 insertions(+), 7 deletions(-) diff --git a/drivers/clk/nuvoton/clk-ma35d1.c b/drivers/clk/nuvoton/clk-ma35d1.c index ceebcbd8c18b..ed61a990870e 100644 --- a/drivers/clk/nuvoton/clk-ma35d1.c +++ b/drivers/clk/nuvoton/clk-ma35d1.c @@ -65,6 +65,14 @@ static DEFINE_SPINLOCK(ma35d1_lock); #define MA35D1_MUX_MAX_PARENTS 10 +static const struct clk_parent_data hxtg_parent_data[] = { + { .fw_name = "hxt", .name = "clk_hxt" }, +}; + +static const struct clk_parent_data lxtg_parent_data[] = { + { .fw_name = "lxt", .name = "lxt" }, +}; + /* Mux parent selection, by index into the controller's clock table */ static const int ca35clk_parent_idx[] = { HXT, CAPLL, DDRPLL }; static const int sysclk0_parent_idx[] = { EPLL_DIV2, SYSPLL }; @@ -191,6 +199,15 @@ static struct clk_hw *ma35d1_clk_gate(struct device *dev, const char *name, cons reg, shift, 0, &ma35d1_lock); } +static struct clk_hw *ma35d1_clk_gate_parent_data(struct device *dev, const char *name, + const struct clk_parent_data *parent_data, + void __iomem *reg, u8 shift) +{ + return devm_clk_hw_register_gate_parent_data(dev, name, parent_data, + CLK_SET_RATE_PARENT, + reg, shift, 0, &ma35d1_lock); +} + static int ma35d1_get_pll_setting(struct device_node *clk_node, u32 *pllmode) { const char *of_str; @@ -219,7 +236,7 @@ static int ma35d1_clocks_probe(struct platform_device *pdev) static struct clk_hw **hws; static struct clk_hw_onecell_data *ma35d1_hw_data; u32 pllmode[PLL_MAX_NUM]; - int ret; + int ret, num_clks; ma35d1_hw_data = devm_kzalloc(dev, struct_size(ma35d1_hw_data, hws, MA35D1_CLK_COUNT), @@ -240,12 +257,18 @@ static int ma35d1_clocks_probe(struct platform_device *pdev) return -EINVAL; } - hws[HXT] = ma35d1_clk_fixed("hxt", 24000000); - hws[HXT_GATE] = ma35d1_clk_gate(dev, "hxt_gate", "hxt", - clk_base + REG_CLK_PWRCTL, 0); - hws[LXT] = ma35d1_clk_fixed("lxt", 32768); - hws[LXT_GATE] = ma35d1_clk_gate(dev, "lxt_gate", "lxt", - clk_base + REG_CLK_PWRCTL, 1); + num_clks = of_clk_get_parent_count(clk_node); + if (num_clks < 1 || num_clks > 2) + return -EINVAL; + + /* Old DTs do not describe the low-speed crystal */ + if (num_clks == 1) + hws[LXT] = ma35d1_clk_fixed("lxt", 32768); + + hws[HXT_GATE] = ma35d1_clk_gate_parent_data(dev, "hxt_gate", hxtg_parent_data, + clk_base + REG_CLK_PWRCTL, 0); + hws[LXT_GATE] = ma35d1_clk_gate_parent_data(dev, "lxt_gate", lxtg_parent_data, + clk_base + REG_CLK_PWRCTL, 1); hws[HIRC] = ma35d1_clk_fixed("hirc", 12000000); hws[HIRC_GATE] = ma35d1_clk_gate(dev, "hirc_gate", "hirc", clk_base + REG_CLK_PWRCTL, 2); -- 2.55.0 ^ permalink raw reply related [flat|nested] 15+ messages in thread
* Re: [PATCH v8 3/7] clk: nuvoton: ma35d1: Retrieve HXT/LXT from DT when possible 2026-10-04 20:45 ` [PATCH v8 3/7] clk: nuvoton: ma35d1: Retrieve HXT/LXT from DT when possible Miquel Raynal @ 2026-10-04 20:59 ` sashiko-bot 2026-10-04 21:16 ` Miquel Raynal 0 siblings, 1 reply; 15+ messages in thread From: sashiko-bot @ 2026-10-04 20:59 UTC (permalink / raw) To: Miquel Raynal; +Cc: conor+dt, linux-clk, devicetree, robh Thank you for your contribution! Sashiko AI review found 1 potential issue(s) to consider: - [Critical] clk: nuvoton: ABI breakage by removing HXT from provider's hws array -- commit 0466ee8e1824bb9d740e5cd18be8fe01b5d4fbe1 Author: Miquel Raynal <miquel.raynal@bootlin.com> clk: nuvoton: ma35d1: Retrieve HXT/LXT from DT when possible This commit modifies the clock driver to retrieve the external HXT and LXT clocks from the device tree instead of registering them directly. It falls back to registering LXT for backward compatibility with older device trees. > diff --git a/drivers/clk/nuvoton/clk-ma35d1.c b/drivers/clk/nuvoton/clk-ma35d1.c > index ceebcbd8c18b3..ed61a990870e4 100644 > --- a/drivers/clk/nuvoton/clk-ma35d1.c > +++ b/drivers/clk/nuvoton/clk-ma35d1.c [ ... ] > @@ -240,12 +257,18 @@ static int ma35d1_clocks_probe(struct platform_device *pdev) > return -EINVAL; > } > > - hws[HXT] = ma35d1_clk_fixed("hxt", 24000000); [Severity: Critical] Does this unconditional removal break ABI compatibility with older device trees? Because HXT (index 0) is exported as a public ABI in the DT bindings, removing its explicit registration leaves hws[HXT] as NULL in the provider's clock array. If an existing downstream or older device tree consumer explicitly references this clock via clocks = <&clk HXT>, won't the provider's of_clk_hw_onecell_get() fail to resolve the clock and return an error? > - hws[HXT_GATE] = ma35d1_clk_gate(dev, "hxt_gate", "hxt", > - clk_base + REG_CLK_PWRCTL, 0); > - hws[LXT] = ma35d1_clk_fixed("lxt", 32768); > - hws[LXT_GATE] = ma35d1_clk_gate(dev, "lxt_gate", "lxt", > - clk_base + REG_CLK_PWRCTL, 1); > + num_clks = of_clk_get_parent_count(clk_node); > + if (num_clks < 1 || num_clks > 2) > + return -EINVAL; > + > + /* Old DTs do not describe the low-speed crystal */ > + if (num_clks == 1) > + hws[LXT] = ma35d1_clk_fixed("lxt", 32768); -- Sashiko AI review · https://sashiko.dev/#/patchset/20261004-perso-ma35d1-upstream-clk-v8-0-e1a106a128c0@bootlin.com?part=3 ^ permalink raw reply [flat|nested] 15+ messages in thread
* Re: [PATCH v8 3/7] clk: nuvoton: ma35d1: Retrieve HXT/LXT from DT when possible 2026-10-04 20:59 ` sashiko-bot @ 2026-10-04 21:16 ` Miquel Raynal 2026-10-05 9:06 ` Jerome Brunet 0 siblings, 1 reply; 15+ messages in thread From: Miquel Raynal @ 2026-10-04 21:16 UTC (permalink / raw) To: sashiko-bot; +Cc: sashiko-reviews, conor+dt, linux-clk, devicetree, robh > This commit modifies the clock driver to retrieve the external HXT and LXT > clocks from the device tree instead of registering them directly. It falls > back to registering LXT for backward compatibility with older device trees. > >> diff --git a/drivers/clk/nuvoton/clk-ma35d1.c b/drivers/clk/nuvoton/clk-ma35d1.c >> index ceebcbd8c18b3..ed61a990870e4 100644 >> --- a/drivers/clk/nuvoton/clk-ma35d1.c >> +++ b/drivers/clk/nuvoton/clk-ma35d1.c > [ ... ] >> @@ -240,12 +257,18 @@ static int ma35d1_clocks_probe(struct platform_device *pdev) >> return -EINVAL; >> } >> >> - hws[HXT] = ma35d1_clk_fixed("hxt", 24000000); > > [Severity: Critical] > Does this unconditional removal break ABI compatibility with older device > trees? > > Because HXT (index 0) is exported as a public ABI in the DT bindings, > removing its explicit registration leaves hws[HXT] as NULL in the provider's > clock array. If an existing downstream or older device tree consumer explicitly > references this clock via clocks = <&clk HXT>, won't the provider's > of_clk_hw_onecell_get() fail to resolve the clock and return an error? Jerome, your wisdom matters here :-) For me this is a false positive, because nobody outside this driver should access hws[HXT] and the clock is still referenced through the DT, just not provided by this driver. For me this is not an issue we should consider, let me know otherwise. Miquèl ^ permalink raw reply [flat|nested] 15+ messages in thread
* Re: [PATCH v8 3/7] clk: nuvoton: ma35d1: Retrieve HXT/LXT from DT when possible 2026-10-04 21:16 ` Miquel Raynal @ 2026-10-05 9:06 ` Jerome Brunet 0 siblings, 0 replies; 15+ messages in thread From: Jerome Brunet @ 2026-10-05 9:06 UTC (permalink / raw) To: Miquel Raynal, sashiko-bot Cc: sashiko-reviews, conor+dt, linux-clk, devicetree, robh On Sun 04 Oct 2026 at 23:16, Miquel Raynal <miquel.raynal@bootlin.com> wrote: >> This commit modifies the clock driver to retrieve the external HXT and LXT >> clocks from the device tree instead of registering them directly. It falls >> back to registering LXT for backward compatibility with older device trees. >> >>> diff --git a/drivers/clk/nuvoton/clk-ma35d1.c b/drivers/clk/nuvoton/clk-ma35d1.c >>> index ceebcbd8c18b3..ed61a990870e4 100644 >>> --- a/drivers/clk/nuvoton/clk-ma35d1.c >>> +++ b/drivers/clk/nuvoton/clk-ma35d1.c >> [ ... ] >>> @@ -240,12 +257,18 @@ static int ma35d1_clocks_probe(struct platform_device *pdev) >>> return -EINVAL; >>> } >>> >>> - hws[HXT] = ma35d1_clk_fixed("hxt", 24000000); >> >> [Severity: Critical] >> Does this unconditional removal break ABI compatibility with older device >> trees? >> >> Because HXT (index 0) is exported as a public ABI in the DT bindings, >> removing its explicit registration leaves hws[HXT] as NULL in the provider's >> clock array. If an existing downstream or older device tree consumer explicitly >> references this clock via clocks = <&clk HXT>, won't the provider's >> of_clk_hw_onecell_get() fail to resolve the clock and return an error? > > Jerome, your wisdom matters here :-) For me this is a false positive, > because nobody outside this driver should access hws[HXT] and the clock > is still referenced through the DT, just not provided by this > driver. For me this is not an issue we should consider, let me know > otherwise. Strictly speaking there is (used to be) a clock at this index so it is not a false positive. Someone crazy enough could have gone through here to get the OSC even if does not make a lot of sense. This clock should never have existed to start with but it got in the bindings ... and that is the pain of dealing with bad bindings :/ You've got 2 options: * Removing the ID from the bindings explaining clearly that it conflicts with the fact this clock is actually an input according to the same bindings. I suspect the DT maintainers won't like this much ... * Keep the bad support binding in the driver: You'll need a pass-through clock element where the parent data is the fw_name and a fallback to an `hxt-fake-internal' fixed clock. Feel free to add a comment explaining how bad it is to use that clock and what user should be doing instead. You'll probably need to play that last trick with the lxt anyway ? > > Miquèl -- Jerome ^ permalink raw reply [flat|nested] 15+ messages in thread
* [PATCH v8 4/7] clk: nuvoton: ma35d1: Reparent the gates correctly 2026-10-04 20:45 [PATCH v8 0/7] clk: nuvoton: ma35d1: Fix mux parenting and peripheral clock rates Miquel Raynal ` (2 preceding siblings ...) 2026-10-04 20:45 ` [PATCH v8 3/7] clk: nuvoton: ma35d1: Retrieve HXT/LXT from DT when possible Miquel Raynal @ 2026-10-04 20:45 ` Miquel Raynal 2026-10-04 20:45 ` [PATCH v8 5/7] clk: nuvoton: ma35d1: Reparent SYSPLL correctly Miquel Raynal ` (2 subsequent siblings) 6 siblings, 0 replies; 15+ messages in thread From: Miquel Raynal @ 2026-10-04 20:45 UTC (permalink / raw) To: Jacky Huang, Shan-Chun Hung, Michael Turquette, Stephen Boyd, Richard Cochran, Arnd Bergmann, Brian Masney, Jerome Brunet, Rob Herring, Krzysztof Kozlowski, Conor Dooley, Andrew Jeffery, Avi Fishman, Tomer Maimon, Tali Perry, Patrick Venture, Nancy Yuen, Benjamin Fair Cc: Thomas Petazzoni, Steam Lin, linux-arm-kernel, linux-clk, linux-kernel, Krzysztof Kozlowski, devicetree, openbmc, Miquel Raynal, stable The clock tree is still incorrect. There are four main clocks in this system: - HXT: external high-speed crystal oscillator - LXT: external low-speed crystal oscillator - HIRC: internal high-speed RC oscillator - LIRC: internal low-speed RC oscillator Each clock has a 'gate' control to disable it. While in the TRM the 'gate' appears aside, in the CCF topology, the gates should be below. This is because if we gate one of those clocks, none of the children clocks continue ticking. Reparent hxt_gate under hxt, and all hxt children under hxt_gate. Do the same for the three other clock sources listed above. After this change, the frequencies are identical, but the clock tree looks much closer to the reality. Fixes: 691521a367cf ("clk: nuvoton: Add clock driver for ma35d1 clock controller") Cc: stable@vger.kernel.org Signed-off-by: Miquel Raynal <miquel.raynal@bootlin.com> --- drivers/clk/nuvoton/clk-ma35d1.c | 78 +++++++++++++++++++++++----------------- 1 file changed, 45 insertions(+), 33 deletions(-) diff --git a/drivers/clk/nuvoton/clk-ma35d1.c b/drivers/clk/nuvoton/clk-ma35d1.c index ed61a990870e..2e6e1c65d01e 100644 --- a/drivers/clk/nuvoton/clk-ma35d1.c +++ b/drivers/clk/nuvoton/clk-ma35d1.c @@ -74,34 +74,46 @@ static const struct clk_parent_data lxtg_parent_data[] = { }; /* Mux parent selection, by index into the controller's clock table */ -static const int ca35clk_parent_idx[] = { HXT, CAPLL, DDRPLL }; +static const int ca35clk_parent_idx[] = { HXT_GATE, CAPLL, DDRPLL }; static const int sysclk0_parent_idx[] = { EPLL_DIV2, SYSPLL }; -static const int sysclk1_parent_idx[] = { HXT, SYSPLL }; +static const int sysclk1_parent_idx[] = { HXT_GATE, SYSPLL }; static const int axiclk_parent_idx[] = { AXICLK_DIV2, AXICLK_DIV4 }; -static const int ccap_parent_idx[] = { HXT, VPLL, APLL, SYSPLL }; +static const int ccap_parent_idx[] = { HXT_GATE, VPLL, APLL, SYSPLL }; static const int sdh_parent_idx[] = { SYSPLL, APLL }; static const int dcu_parent_idx[] = { EPLL_DIV2, SYSPLL }; static const int gfx_parent_idx[] = { EPLL, SYSPLL }; -static const int dbg_parent_idx[] = { HIRC, SYSPLL }; -static const int timer0_parent_idx[] = { HXT, LXT, PCLK0, -1, -1, LIRC, -1, HIRC }; -static const int timer1_parent_idx[] = { HXT, LXT, PCLK0, -1, -1, LIRC, -1, HIRC }; -static const int timer2_parent_idx[] = { HXT, LXT, PCLK1, -1, -1, LIRC, -1, HIRC }; -static const int timer3_parent_idx[] = { HXT, LXT, PCLK1, -1, -1, LIRC, -1, HIRC }; -static const int timer4_parent_idx[] = { HXT, LXT, PCLK2, -1, -1, LIRC, -1, HIRC }; -static const int timer5_parent_idx[] = { HXT, LXT, PCLK2, -1, -1, LIRC, -1, HIRC }; -static const int timer6_parent_idx[] = { HXT, LXT, PCLK0, -1, -1, LIRC, -1, HIRC }; -static const int timer7_parent_idx[] = { HXT, LXT, PCLK0, -1, -1, LIRC, -1, HIRC }; -static const int timer8_parent_idx[] = { HXT, LXT, PCLK1, -1, -1, LIRC, -1, HIRC }; -static const int timer9_parent_idx[] = { HXT, LXT, PCLK1, -1, -1, LIRC, -1, HIRC }; -static const int timer10_parent_idx[] = { HXT, LXT, PCLK2, -1, -1, LIRC, -1, HIRC }; -static const int timer11_parent_idx[] = { HXT, LXT, PCLK2, -1, -1, LIRC, -1, HIRC }; -static const int uart_parent_idx[] = { HXT, SYSCLK1_DIV2 }; -static const int wdt0_parent_idx[] = { -1, LXT, PCLK3_DIV4096, LIRC }; -static const int wdt1_parent_idx[] = { -1, LXT, PCLK3_DIV4096, LIRC }; -static const int wdt2_parent_idx[] = { -1, LXT, PCLK4_DIV4096, LIRC }; -static const int wwdt0_parent_idx[] = { -1, -1, PCLK3_DIV4096, LIRC }; -static const int wwdt1_parent_idx[] = { -1, -1, PCLK3_DIV4096, LIRC }; -static const int wwdt2_parent_idx[] = { -1, -1, PCLK4_DIV4096, LIRC }; +static const int dbg_parent_idx[] = { HIRC_GATE, SYSPLL }; +static const int timer0_parent_idx[] = { HXT_GATE, LXT_GATE, PCLK0, -1, -1, + LIRC_GATE, -1, HIRC_GATE }; +static const int timer1_parent_idx[] = { HXT_GATE, LXT_GATE, PCLK0, -1, -1, + LIRC_GATE, -1, HIRC_GATE }; +static const int timer2_parent_idx[] = { HXT_GATE, LXT_GATE, PCLK1, -1, -1, + LIRC_GATE, -1, HIRC_GATE }; +static const int timer3_parent_idx[] = { HXT_GATE, LXT_GATE, PCLK1, -1, -1, + LIRC_GATE, -1, HIRC_GATE }; +static const int timer4_parent_idx[] = { HXT_GATE, LXT_GATE, PCLK2, -1, -1, + LIRC_GATE, -1, HIRC_GATE }; +static const int timer5_parent_idx[] = { HXT_GATE, LXT_GATE, PCLK2, -1, -1, + LIRC_GATE, -1, HIRC_GATE }; +static const int timer6_parent_idx[] = { HXT_GATE, LXT_GATE, PCLK0, -1, -1, + LIRC_GATE, -1, HIRC_GATE }; +static const int timer7_parent_idx[] = { HXT_GATE, LXT_GATE, PCLK0, -1, -1, + LIRC_GATE, -1, HIRC_GATE }; +static const int timer8_parent_idx[] = { HXT_GATE, LXT_GATE, PCLK1, -1, -1, + LIRC_GATE, -1, HIRC_GATE }; +static const int timer9_parent_idx[] = { HXT_GATE, LXT_GATE, PCLK1, -1, -1, + LIRC_GATE, -1, HIRC_GATE }; +static const int timer10_parent_idx[] = { HXT_GATE, LXT_GATE, PCLK2, -1, -1, + LIRC_GATE, -1, HIRC_GATE }; +static const int timer11_parent_idx[] = { HXT_GATE, LXT_GATE, PCLK2, -1, -1, + LIRC_GATE, -1, HIRC_GATE }; +static const int uart_parent_idx[] = { HXT_GATE, SYSCLK1_DIV2 }; +static const int wdt0_parent_idx[] = { -1, LXT_GATE, PCLK3_DIV4096, LIRC_GATE }; +static const int wdt1_parent_idx[] = { -1, LXT_GATE, PCLK3_DIV4096, LIRC_GATE }; +static const int wdt2_parent_idx[] = { -1, LXT_GATE, PCLK4_DIV4096, LIRC_GATE }; +static const int wwdt0_parent_idx[] = { -1, -1, PCLK3_DIV4096, LIRC_GATE }; +static const int wwdt1_parent_idx[] = { -1, -1, PCLK3_DIV4096, LIRC_GATE }; +static const int wwdt2_parent_idx[] = { -1, -1, PCLK4_DIV4096, LIRC_GATE }; static const int spi0_parent_idx[] = { PCLK1, APLL }; static const int spi1_parent_idx[] = { PCLK2, APLL }; static const int spi2_parent_idx[] = { PCLK1, APLL }; @@ -109,11 +121,11 @@ static const int spi3_parent_idx[] = { PCLK2, APLL }; static const int qspi_parent_idx[] = { PCLK0, APLL }; static const int i2s_parent_idx[] = { APLL, SYSCLK1_DIV2 }; static const int can_parent_idx[] = { APLL, VPLL }; -static const int cko_parent_idx[] = { HXT, LXT, HIRC, LIRC, +static const int cko_parent_idx[] = { HXT_GATE, LXT_GATE, HIRC_GATE, LIRC_GATE, AXICLK_DIV4, SYSPLL, DDRPLL, EPLL_DIV2, APLL, VPLL }; -static const int smc_parent_idx[] = { HXT, PCLK4 }; -static const int kpi_parent_idx[] = { HXT, LXT }; +static const int smc_parent_idx[] = { HXT_GATE, PCLK4 }; +static const int kpi_parent_idx[] = { HXT_GATE, LXT_GATE }; static const struct clk_div_table ip_div_table[] = { {0, 2}, {1, 4}, {2, 6}, {3, 8}, {4, 10}, @@ -277,16 +289,16 @@ static int ma35d1_clocks_probe(struct platform_device *pdev) clk_base + REG_CLK_PWRCTL, 3); hws[CAPLL] = ma35d1_reg_clk_pll(dev, CAPLL, pllmode[0], "capll", - hws[HXT], clk_base + REG_CLK_PLL0CTL0); + hws[HXT_GATE], clk_base + REG_CLK_PLL0CTL0); hws[SYSPLL] = ma35d1_clk_fixed("syspll", 180000000); hws[DDRPLL] = ma35d1_reg_clk_pll(dev, DDRPLL, pllmode[1], "ddrpll", - hws[HXT], clk_base + REG_CLK_PLL2CTL0); + hws[HXT_GATE], clk_base + REG_CLK_PLL2CTL0); hws[APLL] = ma35d1_reg_clk_pll(dev, APLL, pllmode[2], "apll", - hws[HXT], clk_base + REG_CLK_PLL3CTL0); + hws[HXT_GATE], clk_base + REG_CLK_PLL3CTL0); hws[EPLL] = ma35d1_reg_clk_pll(dev, EPLL, pllmode[3], "epll", - hws[HXT], clk_base + REG_CLK_PLL4CTL0); + hws[HXT_GATE], clk_base + REG_CLK_PLL4CTL0); hws[VPLL] = ma35d1_reg_clk_pll(dev, VPLL, pllmode[4], "vpll", - hws[HXT], clk_base + REG_CLK_PLL5CTL0); + hws[HXT_GATE], clk_base + REG_CLK_PLL5CTL0); hws[EPLL_DIV2] = ma35d1_clk_fixed_factor(dev, "epll_div2", "epll", 1, 2); hws[EPLL_DIV4] = ma35d1_clk_fixed_factor(dev, "epll_div4", "epll", 1, 4); @@ -454,7 +466,7 @@ static int ma35d1_clocks_probe(struct platform_device *pdev) hws[CKO_GATE] = ma35d1_clk_gate(dev, "cko_gate", "cko_div", clk_base + REG_CLK_SYSCLK1, 13); - hws[GTMR_GATE] = ma35d1_clk_gate(dev, "gtmr_gate", "hirc", + hws[GTMR_GATE] = ma35d1_clk_gate(dev, "gtmr_gate", "hirc_gate", clk_base + REG_CLK_SYSCLK1, 14); hws[GPA_GATE] = ma35d1_clk_gate(dev, "gpa_gate", "hclk0", @@ -655,7 +667,7 @@ static int ma35d1_clocks_probe(struct platform_device *pdev) hws[UART16_GATE] = ma35d1_clk_gate(dev, "uart16_gate", "uart16_div", clk_base + REG_CLK_APBCLK0, 28); - hws[RTC_GATE] = ma35d1_clk_gate(dev, "rtc_gate", "lxt", + hws[RTC_GATE] = ma35d1_clk_gate(dev, "rtc_gate", "lxt_gate", clk_base + REG_CLK_APBCLK0, 29); hws[DDR_GATE] = ma35d1_clk_gate(dev, "ddr_gate", "ddrpll", clk_base + REG_CLK_APBCLK0, 30); -- 2.55.0 ^ permalink raw reply related [flat|nested] 15+ messages in thread
* [PATCH v8 5/7] clk: nuvoton: ma35d1: Reparent SYSPLL correctly 2026-10-04 20:45 [PATCH v8 0/7] clk: nuvoton: ma35d1: Fix mux parenting and peripheral clock rates Miquel Raynal ` (3 preceding siblings ...) 2026-10-04 20:45 ` [PATCH v8 4/7] clk: nuvoton: ma35d1: Reparent the gates correctly Miquel Raynal @ 2026-10-04 20:45 ` Miquel Raynal 2026-10-04 20:55 ` sashiko-bot 2026-10-04 20:45 ` [PATCH v8 6/7] arm64: dts: nuvoton: ma35d1: Drop HXT clock output name Miquel Raynal 2026-10-04 20:45 ` [PATCH v8 7/7] arm64: dts: nuvoton: ma35d1: Add LXT crystal and clock-names Miquel Raynal 6 siblings, 1 reply; 15+ messages in thread From: Miquel Raynal @ 2026-10-04 20:45 UTC (permalink / raw) To: Jacky Huang, Shan-Chun Hung, Michael Turquette, Stephen Boyd, Richard Cochran, Arnd Bergmann, Brian Masney, Jerome Brunet, Rob Herring, Krzysztof Kozlowski, Conor Dooley, Andrew Jeffery, Avi Fishman, Tomer Maimon, Tali Perry, Patrick Venture, Nancy Yuen, Benjamin Fair Cc: Thomas Petazzoni, Steam Lin, linux-arm-kernel, linux-clk, linux-kernel, Krzysztof Kozlowski, devicetree, openbmc, Miquel Raynal, stable The clock tree is still incorrect. SYSPLL is derived from HXT_GATE, very much like CAPLL, DDRPLL, VPLL, APLL and EPLL. SYSPLL has a fixed frequency, but if HXT gets gated, SYSPLL stops running. Reparent SYSPLL under HXT_GATE to properly define the clock tree topology. After this change, the frequencies are identical, but the clock tree looks (again) much closer to the reality. Since the TRM does not explicitly shows that HIRC and LIRC are internally sourced from HXT and LXT, respectively, I haven't reparented them (even though that was tempting). This can be done later anyway. Side effect: since I am moving to a devm_* clk helper for SYSPLL, I can reuse this helper to register the other fixed clocks, so they are also become device managed. Fixes: 691521a367cf ("clk: nuvoton: Add clock driver for ma35d1 clock controller") Cc: stable@vger.kernel.org Signed-off-by: Miquel Raynal <miquel.raynal@bootlin.com> --- drivers/clk/nuvoton/clk-ma35d1.c | 28 ++++++++++++++++++++-------- 1 file changed, 20 insertions(+), 8 deletions(-) diff --git a/drivers/clk/nuvoton/clk-ma35d1.c b/drivers/clk/nuvoton/clk-ma35d1.c index 2e6e1c65d01e..6763f0fddc94 100644 --- a/drivers/clk/nuvoton/clk-ma35d1.c +++ b/drivers/clk/nuvoton/clk-ma35d1.c @@ -73,6 +73,8 @@ static const struct clk_parent_data lxtg_parent_data[] = { { .fw_name = "lxt", .name = "lxt" }, }; +static struct clk_parent_data syspll_parent_data[1] = {}; + /* Mux parent selection, by index into the controller's clock table */ static const int ca35clk_parent_idx[] = { HXT_GATE, CAPLL, DDRPLL }; static const int sysclk0_parent_idx[] = { EPLL_DIV2, SYSPLL }; @@ -139,9 +141,15 @@ static const struct clk_div_table eadc_div_table[] = { {13, 28}, {14, 30}, {15, 32}, {0, 0}, }; -static struct clk_hw *ma35d1_clk_fixed(const char *name, int rate) +static struct clk_hw *ma35d1_clk_fixed_parent_data(struct device *dev, const char *name, int rate, + const struct clk_parent_data *parent_data) { - return clk_hw_register_fixed_rate(NULL, name, NULL, 0, rate); + return devm_clk_hw_register_fixed_rate_parent_data(dev, name, parent_data, 0, rate); +} + +static struct clk_hw *ma35d1_clk_fixed(struct device *dev, const char *name, int rate) +{ + return ma35d1_clk_fixed_parent_data(dev, name, rate, NULL); } static struct clk_hw *ma35d1_clk_mux(struct device *dev, const char *name, @@ -275,22 +283,26 @@ static int ma35d1_clocks_probe(struct platform_device *pdev) /* Old DTs do not describe the low-speed crystal */ if (num_clks == 1) - hws[LXT] = ma35d1_clk_fixed("lxt", 32768); + hws[LXT] = ma35d1_clk_fixed(dev, "lxt", 32768); hws[HXT_GATE] = ma35d1_clk_gate_parent_data(dev, "hxt_gate", hxtg_parent_data, clk_base + REG_CLK_PWRCTL, 0); + if (IS_ERR(hws[HXT_GATE])) + return PTR_ERR(hws[HXT_GATE]); + hws[LXT_GATE] = ma35d1_clk_gate_parent_data(dev, "lxt_gate", lxtg_parent_data, clk_base + REG_CLK_PWRCTL, 1); - hws[HIRC] = ma35d1_clk_fixed("hirc", 12000000); + hws[HIRC] = ma35d1_clk_fixed(dev, "hirc", 12000000); hws[HIRC_GATE] = ma35d1_clk_gate(dev, "hirc_gate", "hirc", clk_base + REG_CLK_PWRCTL, 2); - hws[LIRC] = ma35d1_clk_fixed("lirc", 32000); + hws[LIRC] = ma35d1_clk_fixed(dev, "lirc", 32000); hws[LIRC_GATE] = ma35d1_clk_gate(dev, "lirc_gate", "lirc", clk_base + REG_CLK_PWRCTL, 3); hws[CAPLL] = ma35d1_reg_clk_pll(dev, CAPLL, pllmode[0], "capll", hws[HXT_GATE], clk_base + REG_CLK_PLL0CTL0); - hws[SYSPLL] = ma35d1_clk_fixed("syspll", 180000000); + syspll_parent_data[0].hw = hws[HXT_GATE]; + hws[SYSPLL] = ma35d1_clk_fixed_parent_data(dev, "syspll", 180000000, syspll_parent_data); hws[DDRPLL] = ma35d1_reg_clk_pll(dev, DDRPLL, pllmode[1], "ddrpll", hws[HXT_GATE], clk_base + REG_CLK_PLL2CTL0); hws[APLL] = ma35d1_reg_clk_pll(dev, APLL, pllmode[2], "apll", @@ -331,8 +343,8 @@ static int ma35d1_clocks_probe(struct platform_device *pdev) hws[PCLK3_DIV4096] = ma35d1_clk_fixed_factor(dev, "pclk3_div4096", "pclk3", 1, 4096); hws[PCLK4_DIV4096] = ma35d1_clk_fixed_factor(dev, "pclk4_div4096", "pclk4", 1, 4096); - hws[USBPHY0] = ma35d1_clk_fixed("usbphy0", 480000000); - hws[USBPHY1] = ma35d1_clk_fixed("usbphy1", 480000000); + hws[USBPHY0] = ma35d1_clk_fixed(dev, "usbphy0", 480000000); + hws[USBPHY1] = ma35d1_clk_fixed(dev, "usbphy1", 480000000); /* DDR */ hws[DDR0_GATE] = ma35d1_clk_gate(dev, "ddr0_gate", "ddrpll", -- 2.55.0 ^ permalink raw reply related [flat|nested] 15+ messages in thread
* Re: [PATCH v8 5/7] clk: nuvoton: ma35d1: Reparent SYSPLL correctly 2026-10-04 20:45 ` [PATCH v8 5/7] clk: nuvoton: ma35d1: Reparent SYSPLL correctly Miquel Raynal @ 2026-10-04 20:55 ` sashiko-bot 2026-10-04 21:19 ` Miquel Raynal 0 siblings, 1 reply; 15+ messages in thread From: sashiko-bot @ 2026-10-04 20:55 UTC (permalink / raw) To: Miquel Raynal; +Cc: conor+dt, linux-clk, robh, devicetree Thank you for your contribution! Sashiko AI review found 1 potential issue(s) to consider: - [Low] clk: nuvoton: ma35d1: Modification of global static state during probe -- commit ee5a5a1eb9fdc7516949d10347d8380f083a7848 Author: Miquel Raynal <miquel.raynal@bootlin.com> clk: nuvoton: ma35d1: Reparent SYSPLL correctly This commit reparents SYSPLL under HXT_GATE to properly define the clock tree topology. It also reuses a devm_ helper for fixed clocks to make them device managed. > diff --git a/drivers/clk/nuvoton/clk-ma35d1.c b/drivers/clk/nuvoton/clk-ma35d1.c > index 2e6e1c65d01e5..6763f0fddc944 100644 > --- a/drivers/clk/nuvoton/clk-ma35d1.c > +++ b/drivers/clk/nuvoton/clk-ma35d1.c > @@ -73,6 +73,8 @@ static const struct clk_parent_data lxtg_parent_data[] = { > { .fw_name = "lxt", .name = "lxt" }, > }; > > +static struct clk_parent_data syspll_parent_data[1] = {}; > + > /* Mux parent selection, by index into the controller's clock table */ > static const int ca35clk_parent_idx[] = { HXT_GATE, CAPLL, DDRPLL }; [ ... ] > @@ -275,22 +283,26 @@ static int ma35d1_clocks_probe(struct platform_device *pdev) [ ... ] > hws[CAPLL] = ma35d1_reg_clk_pll(dev, CAPLL, pllmode[0], "capll", > hws[HXT_GATE], clk_base + REG_CLK_PLL0CTL0); > - hws[SYSPLL] = ma35d1_clk_fixed("syspll", 180000000); > + syspll_parent_data[0].hw = hws[HXT_GATE]; > + hws[SYSPLL] = ma35d1_clk_fixed_parent_data(dev, "syspll", 180000000, syspll_parent_data); [Severity: Low] Is it safe to modify this global static array in the probe function? In drivers/clk/nuvoton/clk-ma35d1.c, syspll_parent_data is declared as a global static array and then modified here in ma35d1_clocks_probe() by assigning it an instance-specific dynamically allocated hardware pointer. Since the clock framework copies clk_parent_data during registration, could syspll_parent_data be safely declared as a local stack variable inside ma35d1_clocks_probe() to avoid modifying global state? Modifying global state here violates device model isolation principles, which could lead to data races or dangling pointers if multiple driver instances were to exist. -- Sashiko AI review · https://sashiko.dev/#/patchset/20261004-perso-ma35d1-upstream-clk-v8-0-e1a106a128c0@bootlin.com?part=5 ^ permalink raw reply [flat|nested] 15+ messages in thread
* Re: [PATCH v8 5/7] clk: nuvoton: ma35d1: Reparent SYSPLL correctly 2026-10-04 20:55 ` sashiko-bot @ 2026-10-04 21:19 ` Miquel Raynal 2026-10-05 9:12 ` Jerome Brunet 0 siblings, 1 reply; 15+ messages in thread From: Miquel Raynal @ 2026-10-04 21:19 UTC (permalink / raw) To: sashiko-bot; +Cc: sashiko-reviews, conor+dt, linux-clk, robh, devicetree On 04/10/2026 at 20:55:50 GMT, sashiko-bot@kernel.org wrote: > Thank you for your contribution! Sashiko AI review found 1 potential issue(s) to consider: > - [Low] clk: nuvoton: ma35d1: Modification of global static state > during probe There is a single clock controller. Should never be a problem. I can certainly move it in to more local scope if someone asks, but it's not practically needed. Thanks, Miquèl ^ permalink raw reply [flat|nested] 15+ messages in thread
* Re: [PATCH v8 5/7] clk: nuvoton: ma35d1: Reparent SYSPLL correctly 2026-10-04 21:19 ` Miquel Raynal @ 2026-10-05 9:12 ` Jerome Brunet 2026-10-06 7:57 ` Miquel Raynal 0 siblings, 1 reply; 15+ messages in thread From: Jerome Brunet @ 2026-10-05 9:12 UTC (permalink / raw) To: Miquel Raynal, sashiko-bot Cc: sashiko-reviews, conor+dt, linux-clk, robh, devicetree On Sun 04 Oct 2026 at 23:19, Miquel Raynal <miquel.raynal@bootlin.com> wrote: > On 04/10/2026 at 20:55:50 GMT, sashiko-bot@kernel.org wrote: > >> Thank you for your contribution! Sashiko AI review found 1 potential issue(s) to consider: >> - [Low] clk: nuvoton: ma35d1: Modification of global static state >> during probe > > There is a single clock controller. Should never be a problem. I can > certainly move it in to more local scope if someone asks, but it's not > practically needed. I may be missing something key here but why is not in your defined indexes like the rest of the clocks ? > > Thanks, > Miquèl > -- Jerome ^ permalink raw reply [flat|nested] 15+ messages in thread
* Re: [PATCH v8 5/7] clk: nuvoton: ma35d1: Reparent SYSPLL correctly 2026-10-05 9:12 ` Jerome Brunet @ 2026-10-06 7:57 ` Miquel Raynal 0 siblings, 0 replies; 15+ messages in thread From: Miquel Raynal @ 2026-10-06 7:57 UTC (permalink / raw) To: Jerome Brunet Cc: sashiko-bot, sashiko-reviews, conor+dt, linux-clk, robh, devicetree On 05/10/2026 at 11:12:35 +02, Jerome Brunet <jbrunet@baylibre.com> wrote: > On Sun 04 Oct 2026 at 23:19, Miquel Raynal <miquel.raynal@bootlin.com> wrote: > >> On 04/10/2026 at 20:55:50 GMT, sashiko-bot@kernel.org wrote: >> >>> Thank you for your contribution! Sashiko AI review found 1 potential issue(s) to consider: >>> - [Low] clk: nuvoton: ma35d1: Modification of global static state >>> during probe >> >> There is a single clock controller. Should never be a problem. I can >> certainly move it in to more local scope if someone asks, but it's not >> practically needed. > > I may be missing something key here but why is not in your defined > indexes like the rest of the clocks ? SYSPLL and its parent (HXT_GATE) are in the hws[] array. Are you suggesting to use the hw_clk pointer directly there instead of using the parent data structure as an envelope? Because the issue raised is the global definition of the struct clk_parent_data and then its modification (since I need to reference the hws[SYSPLL] pointer inside). Thanks, Miquèl ^ permalink raw reply [flat|nested] 15+ messages in thread
* [PATCH v8 6/7] arm64: dts: nuvoton: ma35d1: Drop HXT clock output name 2026-10-04 20:45 [PATCH v8 0/7] clk: nuvoton: ma35d1: Fix mux parenting and peripheral clock rates Miquel Raynal ` (4 preceding siblings ...) 2026-10-04 20:45 ` [PATCH v8 5/7] clk: nuvoton: ma35d1: Reparent SYSPLL correctly Miquel Raynal @ 2026-10-04 20:45 ` Miquel Raynal 2026-10-04 20:45 ` [PATCH v8 7/7] arm64: dts: nuvoton: ma35d1: Add LXT crystal and clock-names Miquel Raynal 6 siblings, 0 replies; 15+ messages in thread From: Miquel Raynal @ 2026-10-04 20:45 UTC (permalink / raw) To: Jacky Huang, Shan-Chun Hung, Michael Turquette, Stephen Boyd, Richard Cochran, Arnd Bergmann, Brian Masney, Jerome Brunet, Rob Herring, Krzysztof Kozlowski, Conor Dooley, Andrew Jeffery, Avi Fishman, Tomer Maimon, Tali Perry, Patrick Venture, Nancy Yuen, Benjamin Fair Cc: Thomas Petazzoni, Steam Lin, linux-arm-kernel, linux-clk, linux-kernel, Krzysztof Kozlowski, devicetree, openbmc, Miquel Raynal The clock-output-names property is not useful since there is only one output clock, and the naming of that clock would already be clock-hxt after the node name if we were not providing that property (so very similar). Just drop it. I want to clean this name before introducing another very similar fixed clock in the DT: LXT Another solution could have been to rename it "hxt", which would have been more aligned with the other clock names. Sashiko complained that this could break DT compatibility with an -EEXIST error because of the colliding names. Signed-off-by: Miquel Raynal <miquel.raynal@bootlin.com> --- arch/arm64/boot/dts/nuvoton/ma35d1-iot-512m.dts | 1 - arch/arm64/boot/dts/nuvoton/ma35d1-som-256m.dts | 1 - 2 files changed, 2 deletions(-) diff --git a/arch/arm64/boot/dts/nuvoton/ma35d1-iot-512m.dts b/arch/arm64/boot/dts/nuvoton/ma35d1-iot-512m.dts index 78534d613486..d7670afb0a63 100644 --- a/arch/arm64/boot/dts/nuvoton/ma35d1-iot-512m.dts +++ b/arch/arm64/boot/dts/nuvoton/ma35d1-iot-512m.dts @@ -35,7 +35,6 @@ clk_hxt: clock-hxt { compatible = "fixed-clock"; #clock-cells = <0>; clock-frequency = <24000000>; - clock-output-names = "clk_hxt"; }; }; diff --git a/arch/arm64/boot/dts/nuvoton/ma35d1-som-256m.dts b/arch/arm64/boot/dts/nuvoton/ma35d1-som-256m.dts index a029b660e8dc..8f3cb18d39b6 100644 --- a/arch/arm64/boot/dts/nuvoton/ma35d1-som-256m.dts +++ b/arch/arm64/boot/dts/nuvoton/ma35d1-som-256m.dts @@ -35,7 +35,6 @@ clk_hxt: clock-hxt { compatible = "fixed-clock"; #clock-cells = <0>; clock-frequency = <24000000>; - clock-output-names = "clk_hxt"; }; }; -- 2.55.0 ^ permalink raw reply related [flat|nested] 15+ messages in thread
* [PATCH v8 7/7] arm64: dts: nuvoton: ma35d1: Add LXT crystal and clock-names 2026-10-04 20:45 [PATCH v8 0/7] clk: nuvoton: ma35d1: Fix mux parenting and peripheral clock rates Miquel Raynal ` (5 preceding siblings ...) 2026-10-04 20:45 ` [PATCH v8 6/7] arm64: dts: nuvoton: ma35d1: Drop HXT clock output name Miquel Raynal @ 2026-10-04 20:45 ` Miquel Raynal 6 siblings, 0 replies; 15+ messages in thread From: Miquel Raynal @ 2026-10-04 20:45 UTC (permalink / raw) To: Jacky Huang, Shan-Chun Hung, Michael Turquette, Stephen Boyd, Richard Cochran, Arnd Bergmann, Brian Masney, Jerome Brunet, Rob Herring, Krzysztof Kozlowski, Conor Dooley, Andrew Jeffery, Avi Fishman, Tomer Maimon, Tali Perry, Patrick Venture, Nancy Yuen, Benjamin Fair Cc: Thomas Petazzoni, Steam Lin, linux-arm-kernel, linux-clk, linux-kernel, Krzysztof Kozlowski, devicetree, openbmc, Miquel Raynal, stable The clock controller takes its two crystal oscillator inputs from the board: HXT and LXT. The LXT crystal is not described at all: add the fixed clock node for it and reference both inputs from the clock controller node, with their respective clock-names. Fixes: 691521a367cf ("clk: nuvoton: Add clock driver for ma35d1 clock controller") Fixes: b69af0984732 ("arm64: dts: nuvoton: Add initial ma35d1 device tree") Cc: stable@vger.kernel.org Signed-off-by: Miquel Raynal <miquel.raynal@bootlin.com> --- --- arch/arm64/boot/dts/nuvoton/ma35d1-iot-512m.dts | 6 ++++++ arch/arm64/boot/dts/nuvoton/ma35d1-som-256m.dts | 6 ++++++ arch/arm64/boot/dts/nuvoton/ma35d1.dtsi | 3 ++- 3 files changed, 14 insertions(+), 1 deletion(-) diff --git a/arch/arm64/boot/dts/nuvoton/ma35d1-iot-512m.dts b/arch/arm64/boot/dts/nuvoton/ma35d1-iot-512m.dts index d7670afb0a63..7752e85734ac 100644 --- a/arch/arm64/boot/dts/nuvoton/ma35d1-iot-512m.dts +++ b/arch/arm64/boot/dts/nuvoton/ma35d1-iot-512m.dts @@ -36,6 +36,12 @@ clk_hxt: clock-hxt { #clock-cells = <0>; clock-frequency = <24000000>; }; + + clk_lxt: clock-lxt { + compatible = "fixed-clock"; + #clock-cells = <0>; + clock-frequency = <32768>; + }; }; &clk { diff --git a/arch/arm64/boot/dts/nuvoton/ma35d1-som-256m.dts b/arch/arm64/boot/dts/nuvoton/ma35d1-som-256m.dts index 8f3cb18d39b6..5c65f1fe5da9 100644 --- a/arch/arm64/boot/dts/nuvoton/ma35d1-som-256m.dts +++ b/arch/arm64/boot/dts/nuvoton/ma35d1-som-256m.dts @@ -36,6 +36,12 @@ clk_hxt: clock-hxt { #clock-cells = <0>; clock-frequency = <24000000>; }; + + clk_lxt: clock-lxt { + compatible = "fixed-clock"; + #clock-cells = <0>; + clock-frequency = <32768>; + }; }; &clk { diff --git a/arch/arm64/boot/dts/nuvoton/ma35d1.dtsi b/arch/arm64/boot/dts/nuvoton/ma35d1.dtsi index 7228ad4735b5..9a341c2b1397 100644 --- a/arch/arm64/boot/dts/nuvoton/ma35d1.dtsi +++ b/arch/arm64/boot/dts/nuvoton/ma35d1.dtsi @@ -92,7 +92,8 @@ clk: clock-controller@40460200 { compatible = "nuvoton,ma35d1-clk"; reg = <0x00000000 0x40460200 0x0 0x100>; #clock-cells = <1>; - clocks = <&clk_hxt>; + clocks = <&clk_hxt>, <&clk_lxt>; + clock-names = "hxt", "lxt"; }; pinctrl: pinctrl@40040000 { -- 2.55.0 ^ permalink raw reply related [flat|nested] 15+ messages in thread
end of thread, other threads:[~2026-10-06 7:57 UTC | newest] Thread overview: 15+ messages (download: mbox.gz follow: Atom feed -- links below jump to the message on this page -- 2026-10-04 20:45 [PATCH v8 0/7] clk: nuvoton: ma35d1: Fix mux parenting and peripheral clock rates Miquel Raynal 2026-10-04 20:45 ` [PATCH v8 1/7] clk: nuvoton: ma35d1: Use clk_hw pointers as mux parents Miquel Raynal 2026-10-04 20:45 ` [PATCH v8 2/7] clk: nuvoton: ma35d1: Avoid possible error pointer dereferencing Miquel Raynal 2026-10-04 20:45 ` [PATCH v8 3/7] clk: nuvoton: ma35d1: Retrieve HXT/LXT from DT when possible Miquel Raynal 2026-10-04 20:59 ` sashiko-bot 2026-10-04 21:16 ` Miquel Raynal 2026-10-05 9:06 ` Jerome Brunet 2026-10-04 20:45 ` [PATCH v8 4/7] clk: nuvoton: ma35d1: Reparent the gates correctly Miquel Raynal 2026-10-04 20:45 ` [PATCH v8 5/7] clk: nuvoton: ma35d1: Reparent SYSPLL correctly Miquel Raynal 2026-10-04 20:55 ` sashiko-bot 2026-10-04 21:19 ` Miquel Raynal 2026-10-05 9:12 ` Jerome Brunet 2026-10-06 7:57 ` Miquel Raynal 2026-10-04 20:45 ` [PATCH v8 6/7] arm64: dts: nuvoton: ma35d1: Drop HXT clock output name Miquel Raynal 2026-10-04 20:45 ` [PATCH v8 7/7] arm64: dts: nuvoton: ma35d1: Add LXT crystal and clock-names Miquel Raynal
This is a public inbox, see mirroring instructions for how to clone and mirror all data and code used for this inbox