History

Merge tag 'clk-misc-round-two-for-v7.3' of ssh://github.com/masneyb/linux into clk-pile

Pull clk patches from Brian Masney: - New clock controller drivers for the Cix Sky1 audio subsystem (AUDSS), UltraRISC DP1000, and MediaTek MT8173 MFG_TOP, along with their devicetree bindings. Si549 support was added to the existing si544 driver. - New clock and reset support for the Aspeed AST2700 PECI controller and Airoha EN7523 PCIe PERSTOUT reset lines. - The clk core gains devm_clk_bulk_get_enable() as the mandatory counterpart to the existing optional variant, and exports devm_clk_hw_register_composite_pdata() for modular drivers. - Tegra gets a proper EMC clock implementation for Tegra114, 48MHz pll_p_out1 support needed for UEFI on Surface2, and the Xilinx clocking-wizard gains PLL charge pump/lock parameter programming during dynamic reconfiguration. - Bug fixes for a NULL pointer dereference from uninitialized clk_init_data in the eswin driver, an IO remap leak in the MediaTek pllfh error path, inverted gate control for MT8135 devapc_ck, a missing OF node put in tegra124-emc on registration failure, a prepare reference leak in the palmas driver, unregistered PLLs on MT6735 probe failure, a missing kasprintf NULL check in pmc_atom, PCIe warm boot instability in the Airoha EN7523 driver, and a clocking-wizard clock difference detection bug. - Various cleanups across tegra, st, and mvebu providers to stop misusing the consumer clock API, along with other minor fixes and improvements. Signed-off-by: Brian Masney <bmasney@redhat.com> * tag 'clk-misc-round-two-for-v7.3' of ssh://github.com/masneyb/linux: (45 commits) clk: tegra: set up proper EMC clock implementation for Tegra114 clk: clocking-wizard: remove 20kHz restriction clk: clocking-wizard: optimize clock search clk: clocking-wizard: fix clock difference detection clk: mediatek: mt8135: Fix inverted gate control for devapc_ck clk: clocking-wizard: Program PLL CP/RES and lock parameters on reconfig clk: tegra: support 48MHz clock for pll_p_out1 clk: aspeed: add AST2700 PECI clock dt-bindings: clock: ast2700: add PECI clock clk: mediatek: Add mt8173-mfgtop driver dt-bindings: clock: mediatek: Add mt8173 mfgtop clk: tegra: clean-up simple provider misuse of the consumer API clk: st: clean-up simple provider misuse of the consumer API clk: mvebu: clean-up simple provider misuse of the consumer API clk: remove conditional return with no effect clk: Add devm_clk_bulk_get_enable() clk: en7523: add support for dedicated PCIe PERSTOUT reset dt-bindings: clock: airoha: Add additional reset for PCIe PERSTOUT arm64: dts: cix: sky1: add audss cru reset: cix: add sky1 audss auxiliary reset driver ...

Stephen Boyd committed 3 months ago

Commit df822f22 parents 804b10d cf5612856 files · +3063 −151Browse files

Unified · Split

56 files
  1. Documentation/devicetree/bindings/clock/mediatek,mt8173-mfgtop.yaml +70 −0
  2. Documentation/devicetree/bindings/clock/silabs,si544.yaml +7 −3
  3. Documentation/devicetree/bindings/clock/ultrarisc,dp1000-clk.yaml +60 −0
  4. Documentation/devicetree/bindings/soc/cix/cix,sky1-audss-cru.yaml +92 −0
  5. Documentation/driver-api/driver-model/devres.rst +1 −0
  6. MAINTAINERS +8 −0
  7. arch/arm64/boot/dts/cix/sky1.dtsi +18 −0
  8. drivers/clk/Kconfig +6 −4
  9. drivers/clk/Makefile +3 −1
  10. drivers/clk/aspeed/clk-ast2700.c +10 −0
  11. drivers/clk/cix/Kconfig +16 −0
  12. drivers/clk/cix/Makefile +3 −0
  13. drivers/clk/cix/clk-sky1-audss.c +1206 −0
  14. drivers/clk/clk-composite.c +1 −0
  15. drivers/clk/clk-cs2000-cp.c +1 −5
  16. drivers/clk/clk-devres.c +7 −0
  17. drivers/clk/clk-en7523.c +33 −10
  18. drivers/clk/clk-lmk04832.c +4 −8
  19. drivers/clk/clk-palmas.c +15 −9
  20. drivers/clk/clk-si544.c +65 −17
  21. drivers/clk/eswin/clk.c +2 −2
  22. drivers/clk/hisilicon/clk-hi3660-stub.c +3 −7
  23. drivers/clk/mediatek/Kconfig +10 −0
  24. drivers/clk/mediatek/Makefile +1 −0
  25. drivers/clk/mediatek/clk-mt6735-apmixedsys.c +4 −1
  26. drivers/clk/mediatek/clk-mt6735-vdecsys.c +1 −0
  27. drivers/clk/mediatek/clk-mt6735-vencsys.c +1 −0
  28. drivers/clk/mediatek/clk-mt8135.c +4 −1
  29. drivers/clk/mediatek/clk-mt8173-mfgtop.c +242 −0
  30. drivers/clk/mediatek/clk-mt8196-vlpckgen.c +0 −1
  31. drivers/clk/mediatek/clk-pllfh.c +49 −49
  32. drivers/clk/mmp/clk-pxa1908-apbc.c +1 −1
  33. drivers/clk/mmp/clk-pxa1908-apbcp.c +1 −1
  34. drivers/clk/mvebu/clk-cpu.c +1 −1
  35. drivers/clk/st/clkgen-pll.c +10 −10
  36. drivers/clk/tegra/clk-pll.c +1 −0
  37. drivers/clk/tegra/clk-tegra114.c +25 −14
  38. drivers/clk/tegra/clk-tegra124-emc.c +1 −0
  39. drivers/clk/tegra/clk-tegra210.c +1 −1
  40. drivers/clk/ultrarisc/Kconfig +18 −0
  41. drivers/clk/ultrarisc/Makefile +4 −0
  42. drivers/clk/ultrarisc/clk-dp1000.c +154 −0
  43. drivers/clk/ultrarisc/clk-ultrarisc.c +399 −0
  44. drivers/clk/ultrarisc/clk-ultrarisc.h +71 −0
  45. drivers/clk/x86/clk-pmc-atom.c +3 −0
  46. drivers/clk/xilinx/clk-xlnx-clock-wizard.c +139 −3
  47. drivers/reset/Kconfig +13 −0
  48. drivers/reset/Makefile +1 −0
  49. drivers/reset/reset-sky1-audss.c +127 −0
  50. include/dt-bindings/clock/aspeed,ast2700-scu.h +2 −0
  51. include/dt-bindings/clock/cix,sky1-audss-cru.h +60 −0
  52. include/dt-bindings/clock/mt8173-clk.h +7 −0
  53. include/dt-bindings/clock/ultrarisc,dp1000-clk.h +27 −0
  54. include/dt-bindings/reset/airoha,en7581-reset.h +4 −0
  55. include/dt-bindings/reset/cix,sky1-audss-cru.h +25 −0
  56. include/linux/clk.h +25 −2
Documentation/devicetree/bindings/clock/mediatek,mt8173-mfgtop.yaml+70−0
@@ -0,0 +1,70 @@
1+# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause)
2+%YAML 1.2
3+---
4+
5+$id: http://devicetree.org/schemas/clock/mediatek,mt8173-mfgtop.yaml#
6+$schema: http://devicetree.org/meta-schemas/core.yaml#
7+
8+title: MediaTek MT8173 MFG TOP controller
9+
10+maintainers:
11+ - AngeloGioacchino Del Regno <angelogioacchino.delregno@collabora.com>
12+
13+description:
14+ The MFG TOP glue layer controls various signals going to the MFG (GPU)
15+ block on the MT8173.
16+
17+properties:
18+ compatible:
19+ const: mediatek,mt8173-mfgtop
20+
21+ reg:
22+ maxItems: 1
23+
24+ clocks:
25+ maxItems: 4
26+
27+ clock-names:
28+ items:
29+ - const: sys
30+ - const: mem
31+ - const: core
32+ - const: clk26m
33+
34+ power-domains:
35+ maxItems: 1
36+
37+ '#clock-cells':
38+ const: 1
39+
40+ '#power-domain-cells':
41+ const: 0
42+
43+required:
44+ - compatible
45+ - reg
46+ - clocks
47+ - clock-names
48+ - power-domains
49+ - '#clock-cells'
50+ - '#power-domain-cells'
51+
52+additionalProperties: false
53+
54+examples:
55+ - |
56+ #include <dt-bindings/clock/mt8173-clk.h>
57+ #include <dt-bindings/power/mt8173-power.h>
58+
59+ clock-controller@13fff000 {
60+ compatible = "mediatek,mt8173-mfgtop";
61+ reg = <0x13fff000 0x1000>;
62+ clocks = <&topckgen CLK_TOP_AXI_MFG_IN_SEL>,
63+ <&topckgen CLK_TOP_MEM_MFG_IN_SEL>,
64+ <&topckgen CLK_TOP_MFG_SEL>,
65+ <&clk26m>;
66+ clock-names = "sys", "mem", "core", "clk26m";
67+ power-domains = <&spm MT8173_POWER_DOMAIN_MFG>;
68+ #clock-cells = <1>;
69+ #power-domain-cells = <0>;
70+ };
Documentation/devicetree/bindings/clock/silabs,si544.yaml+7−3
@@ -4,7 +4,7 @@ · 3 unmodified lines
44 $id: http://devicetree.org/schemas/clock/silabs,si544.yaml#
55 $schema: http://devicetree.org/meta-schemas/core.yaml#
66
7−title: Silicon Labs SI514/SI544 clock generator
7+title: Silicon Labs SI514/SI544/SI549 clock generator
88
99 maintainers:
1010 - Mike Looijmans <mike.looijmans@topic.nl>
@@ -13,8 +13,9 @@ description: > · 2 unmodified lines
1313 Silicon Labs 514/544 programmable I2C clock generator. Details about the device
1414 can be found in the datasheet:
1515
16− https://www.silabs.com/Support%20Documents/TechnicalDocs/si514.pdf
17− https://www.silabs.com/documents/public/data-sheets/si544-datasheet.pdf
16+ https://www.skyworksinc.com/-/media/Skyworks/SL/documents/public/data-sheets/Si514.pdf
17+ https://www.skyworksinc.com/-/media/Skyworks/SL/documents/public/data-sheets/si544-datasheet.pdf
18+ https://www.skyworksinc.com/-/media/Skyworks/SL/documents/public/data-sheets/si549-datasheet.pdf
1819
1920 properties:
2021 compatible:
@@ -23,6 +24,9 @@ properties: · 2 unmodified lines
2324 - silabs,si544a
2425 - silabs,si544b
2526 - silabs,si544c
27+ - silabs,si549a
28+ - silabs,si549b
29+ - silabs,si549c
2630
2731 reg:
2832 maxItems: 1
Documentation/devicetree/bindings/clock/ultrarisc,dp1000-clk.yaml+60−0
@@ -0,0 +1,60 @@
1+# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
2+%YAML 1.2
3+---
4+$id: http://devicetree.org/schemas/clock/ultrarisc,dp1000-clk.yaml#
5+$schema: http://devicetree.org/meta-schemas/core.yaml#
6+
7+title: UltraRISC DP1000 Clock Controller
8+
9+maintainers:
10+ - Jia Wang <wangjia@ultrarisc.com>
11+
12+description: |
13+ The UltraRISC DP1000 clock controller is driven from a single external
14+ oscillator input. It provides a system PLL with fractional multiplier
15+ and post-divider stages, several fixed-ratio derived clocks for
16+ the on-chip subsystem, Clock Configuration Register (CCR) divider
17+ outputs for GMAC and the UART, I2C, and SPI root clocks, and
18+ per-instance gate clocks for UART0-3, I2C0-3, and SPI0-1.
19+
20+ All available clocks are defined as preprocessor macros in
21+ include/dt-bindings/clock/ultrarisc,dp1000-clk.h
22+
23+properties:
24+ compatible:
25+ const: ultrarisc,dp1000-clk
26+
27+ reg:
28+ maxItems: 1
29+
30+ clocks:
31+ maxItems: 1
32+ description:
33+ External oscillator input clock used as the parent of the PLLs.
34+
35+ "#clock-cells":
36+ const: 1
37+
38+required:
39+ - compatible
40+ - reg
41+ - clocks
42+ - "#clock-cells"
43+
44+additionalProperties: false
45+
46+examples:
47+ - |
48+ #include <dt-bindings/clock/ultrarisc,dp1000-clk.h>
49+
50+ soc {
51+ #address-cells = <2>;
52+ #size-cells = <2>;
53+
54+ clock-controller@11080000 {
55+ compatible = "ultrarisc,dp1000-clk";
56+ reg = <0x0 0x11080000 0x0 0x1000>;
57+ clocks = <&osc>;
58+ #clock-cells = <1>;
59+ };
60+ };
Documentation/devicetree/bindings/soc/cix/cix,sky1-audss-cru.yaml+92−0
@@ -0,0 +1,92 @@
1+# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
2+%YAML 1.2
3+---
4+$id: http://devicetree.org/schemas/soc/cix/cix,sky1-audss-cru.yaml#
5+$schema: http://devicetree.org/meta-schemas/core.yaml#
6+
7+title: Cix Sky1 audio subsystem clock and reset unit
8+
9+maintainers:
10+ - Joakim Zhang <joakim.zhang@cixtech.com>
11+
12+description: |
13+ The Cix Sky1 Audio Subsystem (AUDSS) Clock and Reset Unit (CRU) groups
14+ audio-related clock muxing, gating and block-level software reset control
15+ in a single register block.
16+
17+ A single device node exposes both the clock controller and software reset
18+ lines. The clock driver registers as a platform driver; the reset controller
19+ is registered by an auxiliary driver bound from the clock driver.
20+
21+ Four SoC-level reference clocks listed in clocks/clock-names feed the AUDSS
22+ clock tree. Internal AUDSS clocks are exposed via #clock-cells; indices are
23+ defined in include/dt-bindings/clock/cix,sky1-audss-cru.h.
24+
25+ Block-level software reset indices are exposed via #reset-cells; indices
26+ are defined in include/dt-bindings/reset/cix,sky1-audss-cru.h.
27+
28+ The SoC syscon NoC (or bus) reset is described via resets. The audio
29+ subsystem power domain is described via power-domains.
30+
31+properties:
32+ compatible:
33+ const: cix,sky1-audss-cru
34+
35+ reg:
36+ maxItems: 1
37+
38+ '#clock-cells':
39+ const: 1
40+ description:
41+ Clock indices are defined in include/dt-bindings/clock/cix,sky1-audss-cru.h.
42+
43+ '#reset-cells':
44+ const: 1
45+ description:
46+ Reset indices are defined in include/dt-bindings/reset/cix,sky1-audss-cru.h.
47+
48+ clocks:
49+ items:
50+ - description: I2S parent clock for sampling rates multiple of 8kHz.
51+ - description: I2S parent clock for sampling rates multiple of 11.025kHz.
52+ - description: Clock feeding most devices in AUDSS (NOC, DSP, SRAM, HDA, DMAC, I2S, and mailbox).
53+ - description: Clock feeding HDA, timer and watchdog, which is a dedicated 48 MHz clock.
54+
55+ clock-names:
56+ items:
57+ - const: x8k
58+ - const: x11k
59+ - const: sys
60+ - const: 48m
61+
62+ power-domains:
63+ maxItems: 1
64+
65+ resets:
66+ maxItems: 1
67+
68+required:
69+ - compatible
70+ - reg
71+ - '#clock-cells'
72+ - '#reset-cells'
73+ - clocks
74+ - clock-names
75+ - power-domains
76+ - resets
77+
78+additionalProperties: false
79+
80+examples:
81+ - |
82+ audss_cru: clock-controller@7110000 {
83+ compatible = "cix,sky1-audss-cru";
84+ reg = <0x7110000 0x10000>;
85+ #clock-cells = <1>;
86+ #reset-cells = <1>;
87+ clocks = <&scmi_clk 76>, <&scmi_clk 78>,
88+ <&scmi_clk 70>, <&scmi_clk 71>;
89+ clock-names = "x8k", "x11k", "sys", "48m";
90+ power-domains = <&smc_devpd 0>;
91+ resets = <&s5_syscon 31>;
92+ };
Documentation/driver-api/driver-model/devres.rst+1−0
@@ -248,6 +248,7 @@ CLOCK · 247 unmodified lines
248248 devm_clk_put()
249249 devm_clk_bulk_get()
250250 devm_clk_bulk_get_all()
251+ devm_clk_bulk_get_enable()
251252 devm_clk_bulk_get_optional()
252253 devm_get_clk_from_child()
253254 devm_clk_hw_register()
MAINTAINERS+8−0
@@ -27671,6 +27671,14 @@ S: Maintained · 27670 unmodified lines
2767127671 F: drivers/usb/common/ulpi.c
2767227672 F: include/linux/ulpi/
2767327673
27674+ULTRARISC DP1000 CLOCK DRIVER
27675+M: Jia Wang <wangjia@ultrarisc.com>
27676+L: linux-clk@vger.kernel.org
27677+S: Maintained
27678+F: Documentation/devicetree/bindings/clock/ultrarisc,dp1000-clk.yaml
27679+F: drivers/clk/ultrarisc/*
27680+F: include/dt-bindings/clock/ultrarisc,dp1000-clk.h
27681+
2767427682 ULTRARISC DP1000 PINCTRL DRIVER
2767527683 M: Jia Wang <wangjia@ultrarisc.com>
2767627684 L: linux-gpio@vger.kernel.org
arch/arm64/boot/dts/cix/sky1.dtsi+18−0
@@ -6,6 +6,10 @@ · 5 unmodified lines
66
77 #include <dt-bindings/interrupt-controller/arm-gic.h>
88 #include <dt-bindings/clock/cix,sky1.h>
9+#include <dt-bindings/clock/cix,sky1-audss-cru.h>
10+#include <dt-bindings/reset/cix,sky1-system-control.h>
11+#include <dt-bindings/reset/cix,sky1-s5-system-control.h>
12+#include <dt-bindings/reset/cix,sky1-audss-cru.h>
913 #include "sky1-power.h"
1014
1115 / {
@@ -558,6 +562,20 @@ · 546 unmodified lines
558562 cix,mbox-dir = "rx";
559563 };
560564
565+ audss_cru: clock-controller@7110000 {
566+ compatible = "cix,sky1-audss-cru";
567+ reg = <0x0 0x07110000 0x0 0x10000>;
568+ #clock-cells = <1>;
569+ #reset-cells = <1>;
570+ clocks = <&scmi_clk CLK_TREE_AUDIO_CLK0>,
571+ <&scmi_clk CLK_TREE_AUDIO_CLK2>,
572+ <&scmi_clk CLK_TREE_AUDIO_CLK4>,
573+ <&scmi_clk CLK_TREE_AUDIO_CLK5>;
574+ clock-names = "x8k", "x11k", "sys", "48m";
575+ power-domains = <&smc_devpd SKY1_PD_AUDIO>;
576+ resets = <&s5_syscon SKY1_AUDIO_HIFI5_NOC_RESET_N>;
577+ };
578+
561579 mbox_sfh2ap: mailbox@8090000 {
562580 compatible = "cix,sky1-mbox";
563581 reg = <0x0 0x08090000 0x0 0x10000>;
drivers/clk/Kconfig+6−4
@@ -155,12 +155,12 @@ config COMMON_CLK_SI514 · 154 unmodified lines
155155 generator.
156156
157157 config COMMON_CLK_SI544
158− tristate "Clock driver for SiLabs 544 devices"
158+ tristate "Clock driver for SiLabs 544 and compatible devices"
159159 depends on I2C
160160 select REGMAP_I2C
161161 help
162− This driver supports the Silicon Labs 544 programmable clock
163− generator.
162+ This driver supports the Silicon Labs 544/549 programmable clock
163+ generators.
164164
165165 config COMMON_CLK_SI570
166166 tristate "Clock driver for SiLabs 570 and compatible devices"
@@ -278,7 +278,7 @@ config COMMON_CLK_LAN966X · 111 unmodified lines
278278 tristate "Generic Clock Controller driver for LAN966X SoC"
279279 depends on HAS_IOMEM
280280 depends on OF
281− depends on SOC_LAN966 || ARCH_LAN969X || COMPILE_TEST
281+ depends on SOC_LAN966 || ARCH_LAN969X || MCHP_LAN966X_PCI || COMPILE_TEST
282282 help
283283 This driver provides support for Generic Clock Controller(GCK) on
284284 LAN966X SoC. GCK generates and supplies clock to various peripherals
@@ -509,6 +509,7 @@ source "drivers/clk/actions/Kconfig" · 224 unmodified lines
509509 source "drivers/clk/analogbits/Kconfig"
510510 source "drivers/clk/aspeed/Kconfig"
511511 source "drivers/clk/bcm/Kconfig"
512+source "drivers/clk/cix/Kconfig"
512513 source "drivers/clk/eswin/Kconfig"
513514 source "drivers/clk/hisilicon/Kconfig"
514515 source "drivers/clk/imgtec/Kconfig"
@@ -541,6 +542,7 @@ source "drivers/clk/tenstorrent/Kconfig" · 26 unmodified lines
541542 source "drivers/clk/thead/Kconfig"
542543 source "drivers/clk/stm32/Kconfig"
543544 source "drivers/clk/ti/Kconfig"
545+source "drivers/clk/ultrarisc/Kconfig"
544546 source "drivers/clk/uniphier/Kconfig"
545547 source "drivers/clk/visconti/Kconfig"
546548 source "drivers/clk/x86/Kconfig"
drivers/clk/Makefile+3−1
@@ -131,6 +131,7 @@ obj-$(CONFIG_ARCH_ARTPEC) += axis/ · 130 unmodified lines
131131 obj-$(CONFIG_ARC_PLAT_AXS10X) += axs10x/
132132 obj-y += bcm/
133133 obj-$(CONFIG_ARCH_BERLIN) += berlin/
134+obj-y += cix/
134135 obj-$(CONFIG_ARCH_DAVINCI) += davinci/
135136 obj-$(CONFIG_COMMON_CLK_ESWIN) += eswin/
136137 obj-$(CONFIG_COMMON_CLK_HISI) += hisilicon/
@@ -163,7 +164,7 @@ obj-y += spacemit/ · 26 unmodified lines
163164 obj-$(CONFIG_PLAT_SPEAR) += spear/
164165 obj-y += sprd/
165166 obj-$(CONFIG_ARCH_STI) += st/
166−obj-$(CONFIG_ARCH_STM32) += stm32/
167+obj-$(CONFIG_COMMON_CLK_STM32MP) += stm32/
167168 obj-y += starfive/
168169 obj-$(CONFIG_ARCH_SUNXI) += sunxi/
169170 obj-y += sunxi-ng/
@@ -171,6 +172,7 @@ obj-$(CONFIG_ARCH_TEGRA) += tegra/ · 1 unmodified line
171172 obj-y += tenstorrent/
172173 obj-$(CONFIG_ARCH_THEAD) += thead/
173174 obj-y += ti/
175+obj-y += ultrarisc/
174176 obj-$(CONFIG_CLK_UNIPHIER) += uniphier/
175177 obj-$(CONFIG_ARCH_U8500) += ux500/
176178 obj-y += versatile/
drivers/clk/aspeed/clk-ast2700.c+10−0
@@ -272,6 +272,13 @@ static const unsigned int sdclk_parent_ids[] = { · 271 unmodified lines
272272
273273 static const struct clk_hw *sdclk_parent_hws[ARRAY_SIZE(sdclk_parent_ids)];
274274
275+static const unsigned int peciclk_parent_ids[] = {
276+ SCU1_CLKIN,
277+ SCU1_CLK_HPLL_DIV4
278+};
279+
280+static const struct clk_hw *peciclk_parent_hws[ARRAY_SIZE(peciclk_parent_ids)];
281+
275282 #define FIXED_CLK(_id, _name, _rate) \
276283 { \
277284 .id = _id, \
@@ -457,6 +464,7 @@ static const struct ast2700_clk_info ast2700_scu1_clk_info[] __initconst = { · 179 unmodified lines
457464 PLL_CLK(SCU1_CLK_HPLL, CLK_PLL, "soc1-hpll", SCU1_CLKIN, SCU1_HPLL_PARAM),
458465 PLL_CLK(SCU1_CLK_APLL, CLK_PLL, "soc1-apll", SCU1_CLKIN, SCU1_APLL_PARAM),
459466 PLL_CLK(SCU1_CLK_DPLL, CLK_PLL, "soc1-dpll", SCU1_CLKIN, SCU1_DPLL_PARAM),
467+ FIXED_FACTOR_CLK(SCU1_CLK_HPLL_DIV4, "soc1-hpll_div4", SCU1_CLK_HPLL, 1, 4),
460468 FIXED_FACTOR_CLK(SCU1_CLK_APLL_DIV2, "soc1-apll_div2", SCU1_CLK_APLL, 1, 2),
461469 FIXED_FACTOR_CLK(SCU1_CLK_APLL_DIV4, "soc1-apll_div4", SCU1_CLK_APLL, 1, 4),
462470 FIXED_FACTOR_CLK(SCU1_CLK_CAN, "canclk", SCU1_CLK_APLL, 1, 10),
@@ -480,6 +488,8 @@ static const struct ast2700_clk_info ast2700_scu1_clk_info[] __initconst = { · 17 unmodified lines
480488 uxclk_parent_hws, SCU1_CLK_SEL2, 0, 2),
481489 MUX_CLK(SCU1_CLK_HUXCLK, "huxclk", uxclk_parent_ids, ARRAY_SIZE(uxclk_parent_ids),
482490 uxclk_parent_hws, SCU1_CLK_SEL2, 3, 2),
491+ MUX_CLK(SCU1_CLK_PECI, "peciclk", peciclk_parent_ids, ARRAY_SIZE(peciclk_parent_ids),
492+ peciclk_parent_hws, SCU1_CLK_SEL2, 16, 1),
483493 DIVIDER_CLK(SCU1_CLK_SDCLK, "sdclk", SCU1_CLK_SDMUX,
484494 SCU1_CLK_SEL1, 14, 3, ast2700_clk_div_table),
485495 PLL_CLK(SCU1_CLK_UARTX, CLK_UART_PLL, "uartxclk", SCU1_CLK_UXCLK, SCU1_UXCLK_CTRL),
drivers/clk/cix/Kconfig+16−0
@@ -0,0 +1,16 @@
1+# SPDX-License-Identifier: GPL-2.0
2+# Audio subsystem clock support for Cixtech SoC family
3+menu "Cixtech Audio Subsystem Clock Driver"
4+
5+config CLK_SKY1_AUDSS
6+ tristate "Cixtech Sky1 Audio Subsystem Clock Driver"
7+ depends on ARCH_CIX || COMPILE_TEST
8+ select AUXILIARY_BUS
9+ select REGMAP_MMIO
10+ select RESET_CONTROLLER
11+ help
12+ Support for the Audio Subsystem clock controller present on
13+ Cixtech Sky1 SoC. This driver provides mux, divider and gate
14+ clocks for DSP, I2S, HDA and related blocks in the audio
15+ subsystem. Say M or Y here if you want to build this driver.
16+endmenu
drivers/clk/cix/Makefile+3−0
@@ -0,0 +1,3 @@
1+# SPDX-License-Identifier: GPL-2.0
2+
3+obj-$(CONFIG_CLK_SKY1_AUDSS) += clk-sky1-audss.o
drivers/clk/cix/clk-sky1-audss.c+1206−0
@@ -0,0 +1,1206 @@
1+// SPDX-License-Identifier: GPL-2.0-only
2+// Copyright 2026 Cix Technology Group Co., Ltd.
3+
4+#include <linux/auxiliary_bus.h>
5+#include <linux/clk.h>
6+#include <linux/clk-provider.h>
7+#include <linux/device.h>
8+#include <linux/module.h>
9+#include <linux/of.h>
10+#include <linux/platform_device.h>
11+#include <linux/pm_runtime.h>
12+#include <linux/regmap.h>
13+#include <linux/reset.h>
14+
15+#include <dt-bindings/clock/cix,sky1-audss-cru.h>
16+
17+#define INFO_HIFI0 0x00
18+#define INFO_CLK_GATE 0x10
19+#define INFO_CLK_DIV 0x14
20+#define INFO_CLK_MUX 0x18
21+#define INFO_MCLK 0x70
22+
23+#define SKY1_AUDSS_CLK_PARENTS_CNT 4
24+#define SKY1_AUDSS_NUM_CLKS (CLK_MCLK4 + 1)
25+
26+static u32 sky1_reg_save[][2] = {
27+ { INFO_HIFI0, 0 },
28+ { INFO_CLK_GATE, 0 },
29+ { INFO_CLK_DIV, 0 },
30+ { INFO_CLK_MUX, 0 },
31+ { INFO_MCLK, 0 },
32+};
33+
34+static const char * const sky1_audss_clk_names[SKY1_AUDSS_CLK_PARENTS_CNT] = {
35+ "x8k", "x11k", "sys", "48m",
36+};
37+
38+static const u32 sky1_clk_rate_default[SKY1_AUDSS_CLK_PARENTS_CNT] = {
39+ 294912000,
40+ 270950400,
41+ 800000000,
42+ 48000000,
43+};
44+
45+static const char * const dsp_clk_parent[] = {
46+ "audio_clk4"
47+};
48+
49+static const char * const dsp_bclk_parent[] = {
50+ "audio_clk4_div2"
51+};
52+
53+static const char * const dsp_pbclk_parent[] = {
54+ "audio_clk4_div4"
55+};
56+
57+static const char * const sram_axi_parent[] = {
58+ "audio_clk4_div2"
59+};
60+
61+static const char * const hda_sys_parent[] = {
62+ "audio_clk4_div2"
63+};
64+
65+static const char * const hda_hda_parent[] = {
66+ "audio_clk5"
67+};
68+
69+static const char * const dmac_axi_parent[] = {
70+ "audio_clk4_div2"
71+};
72+
73+static const char * const wdg_apb_parent[] = {
74+ "audio_clk5_div2"
75+};
76+
77+static const char * const wdg_wdg_parent[] = {
78+ "audio_clk5_div2"
79+};
80+
81+static const char * const timer_apb_parent[] = {
82+ "audio_clk4_div4"
83+};
84+
85+static const char * const timer_timer_parent[] = {
86+ "audio_clk5_div2"
87+};
88+
89+static const char * const mailbox_apb_parent[] = {
90+ "audio_clk4_div4"
91+};
92+
93+static const char * const i2s_apb_parent[] = {
94+ "audio_clk4_div4"
95+};
96+
97+static const char * const i2s0_parents[] = {
98+ "audio_clk0", "audio_clk2"
99+};
100+
101+static const char * const i2s1_parents[] = {
102+ "audio_clk0", "audio_clk2"
103+};
104+
105+static const char * const i2s2_parents[] = {
106+ "audio_clk0", "audio_clk2"
107+};
108+
109+static const char * const i2s3_parents[] = {
110+ "audio_clk0", "audio_clk2"
111+};
112+
113+static const char * const i2s4_parents[] = {
114+ "audio_clk0", "audio_clk2"
115+};
116+
117+static const char * const i2s5_parents[] = {
118+ "audio_clk0", "audio_clk2"
119+};
120+
121+static const char * const i2s6_parents[] = {
122+ "audio_clk0", "audio_clk2"
123+};
124+
125+static const char * const i2s7_parents[] = {
126+ "audio_clk0", "audio_clk2"
127+};
128+
129+static const char * const i2s8_parents[] = {
130+ "audio_clk0", "audio_clk2"
131+};
132+
133+static const char * const i2s9_parents[] = {
134+ "audio_clk0", "audio_clk2"
135+};
136+
137+static const char * const mclk_parents[] = {
138+ "audio_clk0", "audio_clk2"
139+};
140+
141+static const u32 i2s3_mux_table[] = { 0, 2 };
142+static const u32 i2s4_mux_table[] = { 0, 2 };
143+
144+/*
145+ * audss composite clock definition
146+ */
147+struct muxdiv_cfg {
148+ int offset;
149+ u8 shift;
150+ u8 width;
151+ u8 flags;
152+};
153+
154+struct gate_cfg {
155+ int offset;
156+ u8 shift;
157+ u8 flags;
158+};
159+
160+struct composite_clk_cfg {
161+ u32 id;
162+ const char * const name;
163+ const char * const *parent_names;
164+ int num_parents;
165+ const u32 *mux_table;
166+ struct muxdiv_cfg *mux_cfg;
167+ struct muxdiv_cfg *div_cfg;
168+ struct gate_cfg *gate_cfg;
169+ unsigned long flags;
170+};
171+
172+#define CFG(_id,\
173+ _name,\
174+ _parent_names,\
175+ _mux_table,\
176+ _mux_offset, _mux_shift, _mux_width, _mux_flags,\
177+ _div_offset, _div_shift, _div_width, _div_flags,\
178+ _gate_offset, _gate_shift, _gate_flags,\
179+ _flags)\
180+{\
181+ .id = _id,\
182+ .name = _name,\
183+ .parent_names = _parent_names,\
184+ .num_parents = ARRAY_SIZE(_parent_names),\
185+ .mux_table = _mux_table,\
186+ .mux_cfg = &(struct muxdiv_cfg) { _mux_offset, _mux_shift, _mux_width, _mux_flags },\
187+ .div_cfg = &(struct muxdiv_cfg) { _div_offset, _div_shift, _div_width, _div_flags },\
188+ .gate_cfg = &(struct gate_cfg) { _gate_offset, _gate_shift, _gate_flags },\
189+ .flags = _flags,\
190+}
191+
192+static const struct composite_clk_cfg sky1_audss_clks[] = {
193+ /* dsp */
194+ CFG(CLK_DSP_CLK,
195+ "audss_dsp_clk",
196+ dsp_clk_parent,
197+ NULL,
198+ -1, 0, 0, 0,
199+ INFO_CLK_DIV, 0, 2, 0,
200+ INFO_HIFI0, 0, 0,
201+ 0),
202+ CFG(CLK_DSP_BCLK,
203+ "audss_dsp_bclk",
204+ dsp_bclk_parent,
205+ NULL,
206+ -1, 0, 0, 0,
207+ INFO_CLK_DIV, 0, 2, 0,
208+ -1, 0, 0,
209+ 0),
210+ CFG(CLK_DSP_PBCLK,
211+ "audss_dsp_pbclk",
212+ dsp_pbclk_parent,
213+ NULL,
214+ -1, 0, 0, 0,
215+ INFO_CLK_DIV, 0, 2, 0,
216+ -1, 0, 0,
217+ 0),
218+ /* sram */
219+ CFG(CLK_SRAM_AXI,
220+ "audss_sram_axi",
221+ sram_axi_parent,
222+ NULL,
223+ -1, 0, 0, 0,
224+ INFO_CLK_DIV, 0, 2, 0,
225+ INFO_CLK_GATE, 16, 0,
226+ 0),
227+ /* hda */
228+ CFG(CLK_HDA_SYS,
229+ "audss_hda_sys",
230+ hda_sys_parent,
231+ NULL,
232+ -1, 0, 0, 0,
233+ INFO_CLK_DIV, 0, 2, 0,
234+ INFO_CLK_GATE, 14, 0,
235+ 0),
236+ CFG(CLK_HDA_HDA,
237+ "audss_hda_hda",
238+ hda_hda_parent,
239+ NULL,
240+ -1, 0, 0, 0,
241+ -1, 0, 0, 0,
242+ INFO_CLK_GATE, 14, 0,
243+ 0),
244+ /* dmac */
245+ CFG(CLK_DMAC_AXI,
246+ "audss_dmac_axi",
247+ dmac_axi_parent,
248+ NULL,
249+ -1, 0, 0, 0,
250+ INFO_CLK_DIV, 0, 2, 0,
251+ INFO_CLK_GATE, 15, 0,
252+ 0),
253+ /* wdg */
254+ CFG(CLK_WDG_APB,
255+ "audss_wdg_apb",
256+ wdg_apb_parent,
257+ NULL,
258+ -1, 0, 0, 0,
259+ -1, 0, 0, 0,
260+ INFO_CLK_GATE, 10, 0,
261+ 0),
262+ CFG(CLK_WDG_WDG,
263+ "audss_wdg_wdg",
264+ wdg_wdg_parent,
265+ NULL,
266+ -1, 0, 0, 0,
267+ -1, 0, 0, 0,
268+ INFO_CLK_GATE, 10, 0,
269+ 0),
270+ /* timer */
271+ CFG(CLK_TIMER_APB,
272+ "audss_timer_apb",
273+ timer_apb_parent,
274+ NULL,
275+ -1, 0, 0, 0,
276+ INFO_CLK_DIV, 0, 2, 0,
277+ INFO_CLK_GATE, 11, 0,
278+ 0),
279+ CFG(CLK_TIMER_TIMER,
280+ "audss_timer_timer",
281+ timer_timer_parent,
282+ NULL,
283+ -1, 0, 0, 0,
284+ -1, 0, 0, 0,
285+ INFO_CLK_GATE, 11, 0,
286+ 0),
287+ /* mailbox: mb0(ap->dsp), mb1(dsp->ap) */
288+ CFG(CLK_MB_0_APB,
289+ "audss_mb_0_apb",
290+ mailbox_apb_parent,
291+ NULL,
292+ -1, 0, 0, 0,
293+ -1, 0, 0, 0,
294+ INFO_CLK_GATE, 12, 0,
295+ 0),
296+ CFG(CLK_MB_1_APB,
297+ "audss_mb_1_apb",
298+ mailbox_apb_parent,
299+ NULL,
300+ -1, 0, 0, 0,
301+ -1, 0, 0, 0,
302+ INFO_CLK_GATE, 13, 0,
303+ 0),
304+ /* i2s */
305+ CFG(CLK_I2S0_APB,
306+ "audss_i2s0_apb",
307+ i2s_apb_parent,
308+ NULL,
309+ -1, 0, 0, 0,
310+ INFO_CLK_DIV, 0, 2, 0,
311+ INFO_CLK_GATE, 0, 0,
312+ 0),
313+ CFG(CLK_I2S1_APB,
314+ "audss_i2s1_apb",
315+ i2s_apb_parent,
316+ NULL,
317+ -1, 0, 0, 0,
318+ INFO_CLK_DIV, 0, 2, 0,
319+ INFO_CLK_GATE, 1, 0,
320+ 0),
321+ CFG(CLK_I2S2_APB,
322+ "audss_i2s2_apb",
323+ i2s_apb_parent,
324+ NULL,
325+ -1, 0, 0, 0,
326+ INFO_CLK_DIV, 0, 2, 0,
327+ INFO_CLK_GATE, 2, 0,
328+ 0),
329+ CFG(CLK_I2S3_APB,
330+ "audss_i2s3_apb",
331+ i2s_apb_parent,
332+ NULL,
333+ -1, 0, 0, 0,
334+ INFO_CLK_DIV, 0, 2, 0,
335+ INFO_CLK_GATE, 3, 0,
336+ 0),
337+ CFG(CLK_I2S4_APB,
338+ "audss_i2s4_apb",
339+ i2s_apb_parent,
340+ NULL,
341+ -1, 0, 0, 0,
342+ INFO_CLK_DIV, 0, 2, 0,
343+ INFO_CLK_GATE, 4, 0,
344+ 0),
345+ CFG(CLK_I2S5_APB,
346+ "audss_i2s5_apb",
347+ i2s_apb_parent,
348+ NULL,
349+ -1, 0, 0, 0,
350+ INFO_CLK_DIV, 0, 2, 0,
351+ INFO_CLK_GATE, 5, 0,
352+ 0),
353+ CFG(CLK_I2S6_APB,
354+ "audss_i2s6_apb",
355+ i2s_apb_parent,
356+ NULL,
357+ -1, 0, 0, 0,
358+ INFO_CLK_DIV, 0, 2, 0,
359+ INFO_CLK_GATE, 6, 0,
360+ 0),
361+ CFG(CLK_I2S7_APB,
362+ "audss_i2s7_apb",
363+ i2s_apb_parent,
364+ NULL,
365+ -1, 0, 0, 0,
366+ INFO_CLK_DIV, 0, 2, 0,
367+ INFO_CLK_GATE, 7, 0,
368+ 0),
369+ CFG(CLK_I2S8_APB,
370+ "audss_i2s8_apb",
371+ i2s_apb_parent,
372+ NULL,
373+ -1, 0, 0, 0,
374+ INFO_CLK_DIV, 0, 2, 0,
375+ INFO_CLK_GATE, 8, 0,
376+ 0),
377+ CFG(CLK_I2S9_APB,
378+ "audss_i2s9_apb",
379+ i2s_apb_parent,
380+ NULL,
381+ -1, 0, 0, 0,
382+ INFO_CLK_DIV, 0, 2, 0,
383+ INFO_CLK_GATE, 9, 0,
384+ 0),
385+ CFG(CLK_I2S0,
386+ "audss_i2s0",
387+ i2s0_parents,
388+ NULL,
389+ INFO_CLK_MUX, 0, 2, 0,
390+ INFO_CLK_DIV, 2, 2, 0,
391+ INFO_CLK_GATE, 0, 0,
392+ 0),
393+ CFG(CLK_I2S1,
394+ "audss_i2s1",
395+ i2s1_parents,
396+ NULL,
397+ INFO_CLK_MUX, 2, 2, 0,
398+ INFO_CLK_DIV, 4, 2, 0,
399+ INFO_CLK_GATE, 1, 0,
400+ 0),
401+ CFG(CLK_I2S2,
402+ "audss_i2s2",
403+ i2s2_parents,
404+ NULL,
405+ INFO_CLK_MUX, 4, 2, 0,
406+ INFO_CLK_DIV, 6, 2, 0,
407+ INFO_CLK_GATE, 2, 0,
408+ 0),
409+ CFG(CLK_I2S3,
410+ "audss_i2s3",
411+ i2s3_parents,
412+ i2s3_mux_table,
413+ INFO_CLK_MUX, 6, 2, 0,
414+ INFO_CLK_DIV, 8, 2, 0,
415+ INFO_CLK_GATE, 3, 0,
416+ 0),
417+ CFG(CLK_I2S4,
418+ "audss_i2s4",
419+ i2s4_parents,
420+ i2s4_mux_table,
421+ INFO_CLK_MUX, 8, 2, 0,
422+ INFO_CLK_DIV, 10, 2, 0,
423+ INFO_CLK_GATE, 4, 0,
424+ 0),
425+ CFG(CLK_I2S5,
426+ "audss_i2s5",
427+ i2s5_parents,
428+ NULL,
429+ INFO_CLK_MUX, 10, 2, 0,
430+ INFO_CLK_DIV, 12, 2, 0,
431+ INFO_CLK_GATE, 5, 0,
432+ 0),
433+ CFG(CLK_I2S6,
434+ "audss_i2s6",
435+ i2s6_parents,
436+ NULL,
437+ INFO_CLK_MUX, 12, 2, 0,
438+ INFO_CLK_DIV, 14, 2, 0,
439+ INFO_CLK_GATE, 6, 0,
440+ 0),
441+ CFG(CLK_I2S7,
442+ "audss_i2s7",
443+ i2s7_parents,
444+ NULL,
445+ INFO_CLK_MUX, 14, 2, 0,
446+ INFO_CLK_DIV, 16, 2, 0,
447+ INFO_CLK_GATE, 7, 0,
448+ 0),
449+ CFG(CLK_I2S8,
450+ "audss_i2s8",
451+ i2s8_parents,
452+ NULL,
453+ INFO_CLK_MUX, 16, 2, 0,
454+ INFO_CLK_DIV, 18, 2, 0,
455+ INFO_CLK_GATE, 8, 0,
456+ 0),
457+ CFG(CLK_I2S9,
458+ "audss_i2s9",
459+ i2s9_parents,
460+ NULL,
461+ INFO_CLK_MUX, 18, 2, 0,
462+ INFO_CLK_DIV, 20, 2, 0,
463+ INFO_CLK_GATE, 9, 0,
464+ 0),
465+ /* mclk */
466+ CFG(CLK_MCLK0,
467+ "audss_mclk0",
468+ mclk_parents,
469+ NULL,
470+ INFO_MCLK, 5, 1, 0,
471+ -1, 0, 0, 0,
472+ INFO_MCLK, 0, 0,
473+ 0),
474+ CFG(CLK_MCLK1,
475+ "audss_mclk1",
476+ mclk_parents,
477+ NULL,
478+ INFO_MCLK, 6, 1, 0,
479+ -1, 0, 0, 0,
480+ INFO_MCLK, 1, 0,
481+ 0),
482+ CFG(CLK_MCLK2,
483+ "audss_mclk2",
484+ mclk_parents,
485+ NULL,
486+ INFO_MCLK, 7, 1, 0,
487+ -1, 0, 0, 0,
488+ INFO_MCLK, 2, 0,
489+ 0),
490+ CFG(CLK_MCLK3,
491+ "audss_mclk3",
492+ mclk_parents,
493+ NULL,
494+ INFO_MCLK, 8, 1, 0,
495+ -1, 0, 0, 0,
496+ INFO_MCLK, 3, 0,
497+ 0),
498+ CFG(CLK_MCLK4,
499+ "audss_mclk4",
500+ mclk_parents,
501+ NULL,
502+ INFO_MCLK, 9, 1, 0,
503+ -1, 0, 0, 0,
504+ INFO_MCLK, 4, 0,
505+ 0),
506+};
507+
508+struct sky1_audss_clks_devtype_data {
509+ u32 (*reg_save)[2];
510+ size_t reg_save_size;
511+ const char * const *clk_names;
512+ size_t clk_num;
513+ const u32 *clk_rate_default;
514+ const struct composite_clk_cfg *clk_cfg;
515+ size_t clk_cfg_size;
516+};
517+
518+static const struct regmap_config sky1_audss_regmap_config = {
519+ .reg_bits = 32,
520+ .val_bits = 32,
521+ .reg_stride = 4,
522+};
523+
524+struct sky1_audss_clks_priv {
525+ struct device *dev;
526+ struct regmap *regmap_cru;
527+ struct reset_control *rst_noc;
528+ struct clk *clks[SKY1_AUDSS_CLK_PARENTS_CNT];
529+ const struct sky1_audss_clks_devtype_data *devtype_data;
530+ spinlock_t lock;
531+ struct clk_hw_onecell_data *clk_data;
532+};
533+
534+#if IS_ENABLED(CONFIG_RESET_SKY1_AUDSS)
535+
536+static int sky1_audss_reset_controller_register(struct device *dev)
537+{
538+ struct auxiliary_device *adev;
539+
540+ if (!of_property_present(dev->of_node, "#reset-cells"))
541+ return 0;
542+
543+ adev = devm_auxiliary_device_create(dev, "reset", NULL);
544+ if (!adev)
545+ return -ENODEV;
546+
547+ return 0;
548+}
549+
550+#else
551+
552+static int sky1_audss_reset_controller_register(struct device *dev)
553+{
554+ return 0;
555+}
556+
557+#endif
558+
559+/*
560+ * clk_ops for audss clock mux/divider/gate
561+ */
562+struct sky1_clk_divider {
563+ struct clk_divider div;
564+ struct regmap *regmap;
565+ int offset;
566+};
567+
568+struct sky1_clk_gate {
569+ struct clk_gate gate;
570+ struct regmap *regmap;
571+ int offset;
572+};
573+
574+struct sky1_clk_mux {
575+ struct clk_mux mux;
576+ struct regmap *regmap;
577+ int offset;
578+};
579+
580+static inline struct sky1_clk_mux *to_sky1_clk_mux(struct clk_mux *mux)
581+{
582+ return container_of(mux, struct sky1_clk_mux, mux);
583+}
584+
585+static u8 sky1_audss_clk_mux_get_parent(struct clk_hw *hw)
586+{
587+ struct clk_mux *mux = to_clk_mux(hw);
588+ struct sky1_clk_mux *sky1_mux = to_sky1_clk_mux(mux);
589+ u32 val;
590+
591+ regmap_read(sky1_mux->regmap, sky1_mux->offset, &val);
592+ val = val >> mux->shift;
593+ val &= mux->mask;
594+
595+ return clk_mux_val_to_index(hw, mux->table, mux->flags, val);
596+}
597+
598+static int sky1_audss_clk_mux_set_parent(struct clk_hw *hw, u8 index)
599+{
600+ struct clk_mux *mux = to_clk_mux(hw);
601+ u32 val = clk_mux_index_to_val(mux->table, mux->flags, index);
602+ struct sky1_clk_mux *sky1_mux = to_sky1_clk_mux(mux);
603+ unsigned long flags = 0;
604+ u32 reg;
605+
606+ if (mux->lock)
607+ spin_lock_irqsave(mux->lock, flags);
608+ else
609+ __acquire(mux->lock);
610+
611+ if (mux->flags & CLK_MUX_HIWORD_MASK) {
612+ reg = mux->mask << (mux->shift + 16);
613+ } else {
614+ regmap_read(sky1_mux->regmap, sky1_mux->offset, &reg);
615+ reg &= ~(mux->mask << mux->shift);
616+ }
617+ val = val << mux->shift;
618+ reg |= val;
619+ regmap_write(sky1_mux->regmap, sky1_mux->offset, reg);
620+
621+ if (mux->lock)
622+ spin_unlock_irqrestore(mux->lock, flags);
623+ else
624+ __release(mux->lock);
625+
626+ return 0;
627+}
628+
629+static int sky1_audss_clk_mux_determine_rate(struct clk_hw *hw,
630+ struct clk_rate_request *req)
631+{
632+ struct clk_mux *mux = to_clk_mux(hw);
633+
634+ return clk_mux_determine_rate_flags(hw, req, mux->flags);
635+}
636+
637+static const struct clk_ops sky1_audss_clk_mux_ops = {
638+ .get_parent = sky1_audss_clk_mux_get_parent,
639+ .set_parent = sky1_audss_clk_mux_set_parent,
640+ .determine_rate = sky1_audss_clk_mux_determine_rate,
641+};
642+
643+static inline struct sky1_clk_divider *to_sky1_clk_divider(struct clk_divider *div)
644+{
645+ return container_of(div, struct sky1_clk_divider, div);
646+}
647+
648+static unsigned long sky1_audss_clk_divider_recalc_rate(struct clk_hw *hw,
649+ unsigned long parent_rate)
650+{
651+ struct clk_divider *divider = to_clk_divider(hw);
652+ struct sky1_clk_divider *sky1_div = to_sky1_clk_divider(divider);
653+ unsigned int val;
654+
655+ regmap_read(sky1_div->regmap, sky1_div->offset, &val);
656+ val = val >> divider->shift;
657+ val &= clk_div_mask(divider->width);
658+
659+ return divider_recalc_rate(hw, parent_rate, val, divider->table,
660+ divider->flags, divider->width);
661+}
662+
663+static int sky1_audss_clk_divider_determine_rate(struct clk_hw *hw,
664+ struct clk_rate_request *req)
665+{
666+ struct clk_divider *divider = to_clk_divider(hw);
667+ struct sky1_clk_divider *sky1_div = to_sky1_clk_divider(divider);
668+
669+ /* if read only, just return current value */
670+ if (divider->flags & CLK_DIVIDER_READ_ONLY) {
671+ u32 val;
672+
673+ regmap_read(sky1_div->regmap, sky1_div->offset, &val);
674+ val = val >> divider->shift;
675+ val &= clk_div_mask(divider->width);
676+
677+ return divider_ro_determine_rate(hw, req, divider->table,
678+ divider->width,
679+ divider->flags, val);
680+ }
681+
682+ return divider_determine_rate(hw, req, divider->table, divider->width,
683+ divider->flags);
684+}
685+
686+static int sky1_audss_clk_divider_set_rate(struct clk_hw *hw,
687+ unsigned long rate,
688+ unsigned long parent_rate)
689+{
690+ struct clk_divider *divider = to_clk_divider(hw);
691+ struct sky1_clk_divider *sky1_div = to_sky1_clk_divider(divider);
692+ int value;
693+ unsigned long flags = 0;
694+ u32 val;
695+
696+ value = divider_get_val(rate, parent_rate, divider->table,
697+ divider->width, divider->flags);
698+ if (value < 0)
699+ return value;
700+
701+ if (divider->lock)
702+ spin_lock_irqsave(divider->lock, flags);
703+ else
704+ __acquire(divider->lock);
705+
706+ if (divider->flags & CLK_DIVIDER_HIWORD_MASK) {
707+ val = clk_div_mask(divider->width) << (divider->shift + 16);
708+ } else {
709+ regmap_read(sky1_div->regmap, sky1_div->offset, &val);
710+ val &= ~(clk_div_mask(divider->width) << divider->shift);
711+ }
712+ val |= (u32)value << divider->shift;
713+ regmap_write(sky1_div->regmap, sky1_div->offset, val);
714+
715+ if (divider->lock)
716+ spin_unlock_irqrestore(divider->lock, flags);
717+ else
718+ __release(divider->lock);
719+
720+ return 0;
721+}
722+
723+static const struct clk_ops sky1_audss_clk_divider_ops = {
724+ .recalc_rate = sky1_audss_clk_divider_recalc_rate,
725+ .determine_rate = sky1_audss_clk_divider_determine_rate,
726+ .set_rate = sky1_audss_clk_divider_set_rate,
727+};
728+
729+static inline struct sky1_clk_gate *to_sky1_clk_gate(struct clk_gate *gate)
730+{
731+ return container_of(gate, struct sky1_clk_gate, gate);
732+}
733+
734+static void sky1_audss_clk_gate_endisable(struct clk_hw *hw, int enable)
735+{
736+ struct clk_gate *gate = to_clk_gate(hw);
737+ struct sky1_clk_gate *sky1_gate = to_sky1_clk_gate(gate);
738+ int set = gate->flags & CLK_GATE_SET_TO_DISABLE ? 1 : 0;
739+ unsigned long flags = 0;
740+ u32 reg;
741+
742+ set ^= enable;
743+
744+ if (gate->lock)
745+ spin_lock_irqsave(gate->lock, flags);
746+ else
747+ __acquire(gate->lock);
748+
749+ if (gate->flags & CLK_GATE_HIWORD_MASK) {
750+ reg = BIT(gate->bit_idx + 16);
751+ if (set)
752+ reg |= BIT(gate->bit_idx);
753+ } else {
754+ regmap_read(sky1_gate->regmap, sky1_gate->offset, &reg);
755+
756+ if (set)
757+ reg |= BIT(gate->bit_idx);
758+ else
759+ reg &= ~BIT(gate->bit_idx);
760+ }
761+
762+ regmap_write(sky1_gate->regmap, sky1_gate->offset, reg);
763+
764+ if (gate->lock)
765+ spin_unlock_irqrestore(gate->lock, flags);
766+ else
767+ __release(gate->lock);
768+}
769+
770+static int sky1_audss_clk_gate_enable(struct clk_hw *hw)
771+{
772+ sky1_audss_clk_gate_endisable(hw, 1);
773+
774+ return 0;
775+}
776+
777+static void sky1_audss_clk_gate_disable(struct clk_hw *hw)
778+{
779+ sky1_audss_clk_gate_endisable(hw, 0);
780+}
781+
782+static int sky1_audss_clk_gate_is_enabled(struct clk_hw *hw)
783+{
784+ struct clk_gate *gate = to_clk_gate(hw);
785+ struct sky1_clk_gate *sky1_gate = to_sky1_clk_gate(gate);
786+ u32 reg;
787+
788+ regmap_read(sky1_gate->regmap, sky1_gate->offset, &reg);
789+
790+ /* if a set bit disables this clk, flip it before masking */
791+ if (gate->flags & CLK_GATE_SET_TO_DISABLE)
792+ reg ^= BIT(gate->bit_idx);
793+
794+ reg &= BIT(gate->bit_idx);
795+
796+ return !!reg;
797+}
798+
799+static const struct clk_ops sky1_audss_clk_gate_ops = {
800+ .enable = sky1_audss_clk_gate_enable,
801+ .disable = sky1_audss_clk_gate_disable,
802+ .is_enabled = sky1_audss_clk_gate_is_enabled,
803+};
804+
805+static struct clk_hw *sky1_audss_clk_register(struct device *dev,
806+ const char *name,
807+ const char * const *parent_names,
808+ int num_parents,
809+ struct regmap *regmap,
810+ const u32 *mux_table,
811+ struct muxdiv_cfg *mux_cfg,
812+ struct muxdiv_cfg *div_cfg,
813+ struct gate_cfg *gate_cfg,
814+ unsigned long flags,
815+ spinlock_t *lock)
816+{
817+ const struct clk_ops *sky1_gate_ops = NULL;
818+ const struct clk_ops *sky1_mux_ops = NULL;
819+ const struct clk_ops *sky1_div_ops = NULL;
820+ struct sky1_clk_divider *sky1_div = NULL;
821+ struct sky1_clk_gate *sky1_gate = NULL;
822+ struct sky1_clk_mux *sky1_mux = NULL;
823+ struct clk_hw *hw = ERR_PTR(-ENOMEM);
824+ struct clk_parent_data *parent_data;
825+ int i;
826+
827+ parent_data = devm_kcalloc(dev, num_parents, sizeof(*parent_data), GFP_KERNEL);
828+ if (!parent_data)
829+ return ERR_PTR(-ENOMEM);
830+
831+ for (i = 0; i < num_parents; i++)
832+ parent_data[i].name = parent_names[i];
833+
834+ if (mux_cfg->offset >= 0) {
835+ sky1_mux = devm_kzalloc(dev, sizeof(*sky1_mux), GFP_KERNEL);
836+ if (!sky1_mux)
837+ return ERR_PTR(-ENOMEM);
838+
839+ sky1_mux->mux.reg = NULL;
840+ sky1_mux->mux.shift = mux_cfg->shift;
841+ sky1_mux->mux.mask = BIT(mux_cfg->width) - 1;
842+ sky1_mux->mux.flags = mux_cfg->flags;
843+ sky1_mux->mux.table = mux_table;
844+ sky1_mux->mux.lock = lock;
845+ sky1_mux_ops = &sky1_audss_clk_mux_ops;
846+ sky1_mux->regmap = regmap;
847+ sky1_mux->offset = mux_cfg->offset;
848+ }
849+
850+ if (div_cfg->offset >= 0) {
851+ sky1_div = devm_kzalloc(dev, sizeof(*sky1_div), GFP_KERNEL);
852+ if (!sky1_div)
853+ return ERR_PTR(-ENOMEM);
854+
855+ sky1_div->div.reg = NULL;
856+ sky1_div->div.shift = div_cfg->shift;
857+ sky1_div->div.width = div_cfg->width;
858+ sky1_div->div.flags = div_cfg->flags | CLK_DIVIDER_POWER_OF_TWO;
859+ sky1_div->div.lock = lock;
860+ sky1_div_ops = &sky1_audss_clk_divider_ops;
861+ sky1_div->regmap = regmap;
862+ sky1_div->offset = div_cfg->offset;
863+ }
864+
865+ if (gate_cfg->offset >= 0) {
866+ sky1_gate = devm_kzalloc(dev, sizeof(*sky1_gate), GFP_KERNEL);
867+ if (!sky1_gate)
868+ return ERR_PTR(-ENOMEM);
869+
870+ sky1_gate->gate.reg = NULL;
871+ sky1_gate->gate.bit_idx = gate_cfg->shift;
872+ sky1_gate->gate.flags = gate_cfg->flags;
873+ sky1_gate->gate.lock = lock;
874+ sky1_gate_ops = &sky1_audss_clk_gate_ops;
875+ sky1_gate->regmap = regmap;
876+ sky1_gate->offset = gate_cfg->offset;
877+ }
878+
879+ hw = devm_clk_hw_register_composite_pdata(dev, name, parent_data, num_parents,
880+ sky1_mux ? &sky1_mux->mux.hw : NULL, sky1_mux_ops,
881+ sky1_div ? &sky1_div->div.hw : NULL, sky1_div_ops,
882+ sky1_gate ? &sky1_gate->gate.hw : NULL, sky1_gate_ops,
883+ flags);
884+ if (IS_ERR(hw)) {
885+ dev_err(dev, "register %s clock failed with err = %ld\n",
886+ name, PTR_ERR(hw));
887+ return hw;
888+ }
889+
890+ return hw;
891+}
892+
893+static int sky1_audss_clks_get(struct sky1_audss_clks_priv *priv)
894+{
895+ const struct sky1_audss_clks_devtype_data *devtype_data = priv->devtype_data;
896+ int i;
897+
898+ for (i = 0; i < devtype_data->clk_num; i++) {
899+ priv->clks[i] = devm_clk_get(priv->dev, devtype_data->clk_names[i]);
900+ if (IS_ERR(priv->clks[i]))
901+ return dev_err_probe(priv->dev, PTR_ERR(priv->clks[i]),
902+ "failed to get clock %s", devtype_data->clk_names[i]);
903+ }
904+
905+ return 0;
906+}
907+
908+static int sky1_audss_clks_enable(struct sky1_audss_clks_priv *priv)
909+{
910+ const struct sky1_audss_clks_devtype_data *devtype_data = priv->devtype_data;
911+ int i, err;
912+
913+ for (i = 0; i < devtype_data->clk_num; i++) {
914+ err = clk_prepare_enable(priv->clks[i]);
915+ if (err) {
916+ dev_err(priv->dev, "failed to enable clock %s\n",
917+ devtype_data->clk_names[i]);
918+ goto err_clks;
919+ }
920+ }
921+
922+ return 0;
923+
924+err_clks:
925+ while (--i >= 0)
926+ clk_disable_unprepare(priv->clks[i]);
927+
928+ return err;
929+}
930+
931+static void sky1_audss_clks_disable(struct sky1_audss_clks_priv *priv)
932+{
933+ const struct sky1_audss_clks_devtype_data *devtype_data = priv->devtype_data;
934+ int i;
935+
936+ for (i = 0; i < devtype_data->clk_num; i++)
937+ clk_disable_unprepare(priv->clks[i]);
938+}
939+
940+static int sky1_audss_clks_set_rate(struct sky1_audss_clks_priv *priv)
941+{
942+ const struct sky1_audss_clks_devtype_data *devtype_data = priv->devtype_data;
943+ int i, err;
944+
945+ for (i = 0; i < devtype_data->clk_num; i++) {
946+ err = clk_set_rate(priv->clks[i], devtype_data->clk_rate_default[i]);
947+ if (err) {
948+ dev_err(priv->dev, "failed to set clock rate %s\n",
949+ devtype_data->clk_names[i]);
950+ return err;
951+ }
952+ }
953+
954+ return 0;
955+}
956+
957+static void sky1_audss_clk_rpm_cleanup(void *data)
958+{
959+ pm_runtime_force_suspend(data);
960+}
961+
962+/* register sky1 audio subsystem clocks */
963+static int sky1_audss_clk_probe(struct platform_device *pdev)
964+{
965+ const struct sky1_audss_clks_devtype_data *devtype_data;
966+ struct sky1_audss_clks_priv *priv;
967+ struct device *dev = &pdev->dev;
968+ struct clk_hw **clk_table;
969+ void __iomem *base;
970+ int i, ret;
971+
972+ devtype_data = device_get_match_data(dev);
973+ if (!devtype_data)
974+ return -ENODEV;
975+
976+ priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
977+ if (!priv)
978+ return -ENOMEM;
979+
980+ spin_lock_init(&priv->lock);
981+
982+ priv->clk_data = devm_kzalloc(dev,
983+ struct_size(priv->clk_data, hws, SKY1_AUDSS_NUM_CLKS),
984+ GFP_KERNEL);
985+ if (!priv->clk_data)
986+ return -ENOMEM;
987+
988+ priv->clk_data->num = SKY1_AUDSS_NUM_CLKS;
989+ clk_table = priv->clk_data->hws;
990+
991+ base = devm_platform_ioremap_resource(pdev, 0);
992+ if (IS_ERR(base))
993+ return PTR_ERR(base);
994+
995+ priv->regmap_cru = devm_regmap_init_mmio(dev, base, &sky1_audss_regmap_config);
996+ if (IS_ERR(priv->regmap_cru))
997+ return dev_err_probe(dev, PTR_ERR(priv->regmap_cru),
998+ "failed to initialize regmap\n");
999+
1000+ priv->dev = dev;
1001+ priv->devtype_data = devtype_data;
1002+
1003+ priv->rst_noc = devm_reset_control_get_exclusive(dev, NULL);
1004+ if (IS_ERR(priv->rst_noc))
1005+ return dev_err_probe(dev, PTR_ERR(priv->rst_noc),
1006+ "failed to get audss noc reset");
1007+
1008+ platform_set_drvdata(pdev, priv);
1009+
1010+ reset_control_assert(priv->rst_noc);
1011+
1012+ ret = sky1_audss_clks_get(priv);
1013+ if (ret)
1014+ return ret;
1015+
1016+ ret = sky1_audss_clks_enable(priv);
1017+ if (ret)
1018+ return ret;
1019+
1020+ /* release noc reset after clock on */
1021+ ret = reset_control_deassert(priv->rst_noc);
1022+ if (ret) {
1023+ sky1_audss_clks_disable(priv);
1024+ return ret;
1025+ }
1026+
1027+ pm_runtime_get_noresume(dev);
1028+ pm_runtime_set_active(dev);
1029+ pm_runtime_enable(dev);
1030+
1031+ /*
1032+ * Register cleanup action before clocks/provider (released last under LIFO).
1033+ */
1034+ ret = devm_add_action_or_reset(dev, sky1_audss_clk_rpm_cleanup, dev);
1035+ if (ret)
1036+ return ret;
1037+
1038+ ret = sky1_audss_clks_set_rate(priv);
1039+ if (ret)
1040+ goto fail_pm;
1041+
1042+ /* audio_clk4 clock fixed divider */
1043+ clk_table[CLK_AUD_CLK4_DIV2] =
1044+ devm_clk_hw_register_fixed_factor(dev,
1045+ "audio_clk4_div2",
1046+ "audio_clk4",
1047+ 0,
1048+ 1, 2);
1049+ if (IS_ERR(clk_table[CLK_AUD_CLK4_DIV2])) {
1050+ ret = PTR_ERR(clk_table[CLK_AUD_CLK4_DIV2]);
1051+ dev_err(dev, "failed to register clock %d, ret:%d\n", CLK_AUD_CLK4_DIV2, ret);
1052+ goto fail_pm;
1053+ }
1054+
1055+ clk_table[CLK_AUD_CLK4_DIV4] =
1056+ devm_clk_hw_register_fixed_factor(dev,
1057+ "audio_clk4_div4",
1058+ "audio_clk4",
1059+ 0,
1060+ 1, 4);
1061+ if (IS_ERR(clk_table[CLK_AUD_CLK4_DIV4])) {
1062+ ret = PTR_ERR(clk_table[CLK_AUD_CLK4_DIV4]);
1063+ dev_err(dev, "failed to register clock %d, ret:%d\n", CLK_AUD_CLK4_DIV4, ret);
1064+ goto fail_pm;
1065+ }
1066+
1067+ /* audio_clk5 clock fixed divider */
1068+ clk_table[CLK_AUD_CLK5_DIV2] =
1069+ devm_clk_hw_register_fixed_factor(dev,
1070+ "audio_clk5_div2",
1071+ "audio_clk5",
1072+ 0,
1073+ 1, 2);
1074+ if (IS_ERR(clk_table[CLK_AUD_CLK5_DIV2])) {
1075+ ret = PTR_ERR(clk_table[CLK_AUD_CLK5_DIV2]);
1076+ dev_err(dev, "failed to register clock %d, ret:%d\n", CLK_AUD_CLK5_DIV2, ret);
1077+ goto fail_pm;
1078+ }
1079+
1080+ for (i = 0; i < devtype_data->clk_cfg_size; i++) {
1081+ clk_table[devtype_data->clk_cfg[i].id] =
1082+ sky1_audss_clk_register(dev,
1083+ devtype_data->clk_cfg[i].name,
1084+ devtype_data->clk_cfg[i].parent_names,
1085+ devtype_data->clk_cfg[i].num_parents,
1086+ priv->regmap_cru,
1087+ devtype_data->clk_cfg[i].mux_table,
1088+ devtype_data->clk_cfg[i].mux_cfg,
1089+ devtype_data->clk_cfg[i].div_cfg,
1090+ devtype_data->clk_cfg[i].gate_cfg,
1091+ devtype_data->clk_cfg[i].flags,
1092+ &priv->lock);
1093+ if (IS_ERR(clk_table[devtype_data->clk_cfg[i].id])) {
1094+ ret = PTR_ERR(clk_table[devtype_data->clk_cfg[i].id]);
1095+ dev_err(dev, "failed to register clock %d, ret:%d\n",
1096+ devtype_data->clk_cfg[i].id, ret);
1097+ goto fail_pm;
1098+ }
1099+ }
1100+
1101+ ret = devm_of_clk_add_hw_provider(dev, of_clk_hw_onecell_get, priv->clk_data);
1102+ if (ret) {
1103+ dev_err(dev, "failed to add clock provider: %d\n", ret);
1104+ goto fail_pm;
1105+ }
1106+
1107+ ret = sky1_audss_reset_controller_register(dev);
1108+ if (ret) {
1109+ dev_err(dev, "failed to register reset controller: %d\n", ret);
1110+ goto fail_pm;
1111+ }
1112+
1113+ pm_runtime_put_sync(dev);
1114+
1115+ return 0;
1116+
1117+fail_pm:
1118+ pm_runtime_put_sync(dev);
1119+ return ret;
1120+}
1121+
1122+static int __maybe_unused sky1_audss_clk_runtime_suspend(struct device *dev)
1123+{
1124+ struct sky1_audss_clks_priv *priv = dev_get_drvdata(dev);
1125+ const struct sky1_audss_clks_devtype_data *devtype_data = priv->devtype_data;
1126+ unsigned long flags;
1127+ int i;
1128+
1129+ spin_lock_irqsave(&priv->lock, flags);
1130+ for (i = 0; i < devtype_data->reg_save_size; i++)
1131+ regmap_read(priv->regmap_cru,
1132+ devtype_data->reg_save[i][0], &devtype_data->reg_save[i][1]);
1133+ spin_unlock_irqrestore(&priv->lock, flags);
1134+
1135+ reset_control_assert(priv->rst_noc);
1136+
1137+ sky1_audss_clks_disable(priv);
1138+
1139+ return 0;
1140+}
1141+
1142+static int __maybe_unused sky1_audss_clk_runtime_resume(struct device *dev)
1143+{
1144+ struct sky1_audss_clks_priv *priv = dev_get_drvdata(dev);
1145+ const struct sky1_audss_clks_devtype_data *devtype_data = priv->devtype_data;
1146+ unsigned long flags;
1147+ int i, ret;
1148+
1149+ ret = sky1_audss_clks_enable(priv);
1150+ if (ret) {
1151+ dev_err(dev, "failed to enable clocks\n");
1152+ return ret;
1153+ }
1154+
1155+ ret = reset_control_deassert(priv->rst_noc);
1156+ if (ret) {
1157+ sky1_audss_clks_disable(priv);
1158+ return ret;
1159+ }
1160+
1161+ spin_lock_irqsave(&priv->lock, flags);
1162+ for (i = 0; i < devtype_data->reg_save_size; i++)
1163+ regmap_write(priv->regmap_cru,
1164+ devtype_data->reg_save[i][0], devtype_data->reg_save[i][1]);
1165+ spin_unlock_irqrestore(&priv->lock, flags);
1166+
1167+ return 0;
1168+}
1169+
1170+static const struct dev_pm_ops sky1_audss_clk_pm_ops = {
1171+ SET_RUNTIME_PM_OPS(sky1_audss_clk_runtime_suspend,
1172+ sky1_audss_clk_runtime_resume, NULL)
1173+ SET_SYSTEM_SLEEP_PM_OPS(pm_runtime_force_suspend,
1174+ pm_runtime_force_resume)
1175+};
1176+
1177+static const struct sky1_audss_clks_devtype_data sky1_devtype_data = {
1178+ .reg_save = sky1_reg_save,
1179+ .reg_save_size = ARRAY_SIZE(sky1_reg_save),
1180+ .clk_names = sky1_audss_clk_names,
1181+ .clk_num = ARRAY_SIZE(sky1_audss_clk_names),
1182+ .clk_rate_default = sky1_clk_rate_default,
1183+ .clk_cfg = sky1_audss_clks,
1184+ .clk_cfg_size = ARRAY_SIZE(sky1_audss_clks),
1185+};
1186+
1187+static const struct of_device_id sky1_audss_clk_of_match[] = {
1188+ { .compatible = "cix,sky1-audss-cru", .data = &sky1_devtype_data, },
1189+ { /* sentinel */ },
1190+};
1191+MODULE_DEVICE_TABLE(of, sky1_audss_clk_of_match);
1192+
1193+static struct platform_driver sky1_audss_clk_driver = {
1194+ .probe = sky1_audss_clk_probe,
1195+ .driver = {
1196+ .name = "sky1-audss-clk",
1197+ .suppress_bind_attrs = true,
1198+ .of_match_table = sky1_audss_clk_of_match,
1199+ .pm = pm_ptr(&sky1_audss_clk_pm_ops),
1200+ },
1201+};
1202+module_platform_driver(sky1_audss_clk_driver);
1203+
1204+MODULE_LICENSE("GPL");
1205+MODULE_AUTHOR("Joakim Zhang <joakim.zhang@cixtech.com>");
1206+MODULE_DESCRIPTION("Cixtech Sky1 Audio Subsystem Clock Controller Driver");
drivers/clk/clk-composite.c+1−0
@@ -462,3 +462,4 @@ struct clk_hw *devm_clk_hw_register_composite_pdata(struct device *dev, · 461 unmodified lines
462462 rate_hw, rate_ops, gate_hw,
463463 gate_ops, flags);
464464 }
465+EXPORT_SYMBOL_GPL(devm_clk_hw_register_composite_pdata);
drivers/clk/clk-cs2000-cp.c+1−5
@@ -404,11 +404,7 @@ static int cs2000_enable(struct clk_hw *hw) · 403 unmodified lines
404404 if (ret < 0)
405405 return ret;
406406
407− ret = cs2000_wait_pll_lock(priv);
408− if (ret < 0)
409− return ret;
410−
411− return ret;
407+ return cs2000_wait_pll_lock(priv);
412408 }
413409
414410 static void cs2000_disable(struct clk_hw *hw)
drivers/clk/clk-devres.c+7−0
@@ -222,6 +222,13 @@ err_clk_get: · 221 unmodified lines
222222 return ret;
223223 }
224224
225+int __must_check devm_clk_bulk_get_enable(struct device *dev, int num_clks,
226+ struct clk_bulk_data *clks)
227+{
228+ return __devm_clk_bulk_get_enable(dev, num_clks, clks, false);
229+}
230+EXPORT_SYMBOL_GPL(devm_clk_bulk_get_enable);
231+
225232 int __must_check devm_clk_bulk_get_optional_enable(struct device *dev, int num_clks,
226233 struct clk_bulk_data *clks)
227234 {
drivers/clk/clk-en7523.c+33−10
@@ -57,6 +57,7 @@ · 56 unmodified lines
5757
5858 #define REG_RST_CTRL2 0x830
5959 #define REG_RST_CTRL1 0x834
60+#define REG_PCIE_HB_RST BIT(29)
6061 #define EN751221_REG_RST_DMT 0x84
6162 #define EN751221_REG_RST_USB 0xec
6263
@@ -338,6 +339,7 @@ static const struct en_clk_desc en7581_base_clks[] = { · 275 unmodified lines
338339 static const u16 en7581_rst_ofs[] = {
339340 REG_RST_CTRL2,
340341 REG_RST_CTRL1,
342+ REG_NP_SCU_PCIC,
341343 };
342344
343345 static const u16 en751221_rst_ofs[] = {
@@ -450,6 +452,11 @@ static const u16 en7581_rst_map[] = { · 106 unmodified lines
450452 [EN7581_CPU_TIMER_RST] = RST_NR_PER_BANK + 28,
451453 [EN7581_PCIE_HB_RST] = RST_NR_PER_BANK + 29,
452454 [EN7581_XPON_MAC_RST] = RST_NR_PER_BANK + 31,
455+
456+ /* RST_PCIC */
457+ [EN7581_PCIC_PERSTOUT0_RST] = 2 * RST_NR_PER_BANK + 29,
458+ [EN7581_PCIC_PERSTOUT1_RST] = 2 * RST_NR_PER_BANK + 26,
459+ [EN7581_PCIC_PERSTOUT2_RST] = 2 * RST_NR_PER_BANK + 16,
453460 };
454461
455462 static const u16 en751221_rst_map[] = {
@@ -635,9 +642,7 @@ static int en7581_pci_enable(struct clk_hw *hw) · 179 unmodified lines
635642 void __iomem *np_base = cg->base;
636643 u32 val, mask;
637644
638− mask = REG_PCI_CONTROL_REFCLK_EN0 | REG_PCI_CONTROL_REFCLK_EN1 |
639− REG_PCI_CONTROL_PERSTOUT1 | REG_PCI_CONTROL_PERSTOUT2 |
640− REG_PCI_CONTROL_PERSTOUT;
645+ mask = REG_PCI_CONTROL_REFCLK_EN0 | REG_PCI_CONTROL_REFCLK_EN1;
641646 val = readl(np_base + REG_PCI_CONTROL);
642647 writel(val | mask, np_base + REG_PCI_CONTROL);
643648
@@ -650,9 +655,7 @@ static void en7581_pci_disable(struct clk_hw *hw) · 6 unmodified lines
650655 void __iomem *np_base = cg->base;
651656 u32 val, mask;
652657
653− mask = REG_PCI_CONTROL_REFCLK_EN0 | REG_PCI_CONTROL_REFCLK_EN1 |
654− REG_PCI_CONTROL_PERSTOUT1 | REG_PCI_CONTROL_PERSTOUT2 |
655− REG_PCI_CONTROL_PERSTOUT;
658+ mask = REG_PCI_CONTROL_REFCLK_EN0 | REG_PCI_CONTROL_REFCLK_EN1;
656659 val = readl(np_base + REG_PCI_CONTROL);
657660 writel(val & ~mask, np_base + REG_PCI_CONTROL);
658661 usleep_range(1000, 2000);
@@ -754,11 +757,17 @@ static int en7523_reset_update(struct reset_controller_dev *rcdev, · 95 unmodified lines
754757 unsigned long id, bool assert)
755758 {
756759 struct en_rst_data *rst_data = container_of(rcdev, struct en_rst_data, rcdev);
757− void __iomem *addr = rst_data->base + rst_data->bank_ofs[id / RST_NR_PER_BANK];
760+ u32 offset = rst_data->bank_ofs[id / RST_NR_PER_BANK];
761+ void __iomem *addr = rst_data->base + offset;
762+ bool inverted = false;
758763 u32 val;
759764
765+ /* For PCIC reset logic is inverted, 0:assert 1:deassert */
766+ if (offset == REG_NP_SCU_PCIC)
767+ inverted = true;
768+
760769 val = readl(addr);
761− if (assert)
770+ if (assert ^ inverted)
762771 val |= BIT(id % RST_NR_PER_BANK);
763772 else
764773 val &= ~BIT(id % RST_NR_PER_BANK);
@@ -783,9 +792,17 @@ static int en7523_reset_status(struct reset_controller_dev *rcdev, · 18 unmodified lines
783792 unsigned long id)
784793 {
785794 struct en_rst_data *rst_data = container_of(rcdev, struct en_rst_data, rcdev);
786− void __iomem *addr = rst_data->base + rst_data->bank_ofs[id / RST_NR_PER_BANK];
795+ u32 offset = rst_data->bank_ofs[id / RST_NR_PER_BANK];
796+ void __iomem *addr = rst_data->base + offset;
797+ bool inverted = false;
798+ u32 val;
799+
800+ /* For PCIC reset logic is inverted, 0:assert 1:deassert */
801+ if (offset == REG_NP_SCU_PCIC)
802+ inverted = true;
787803
788− return !!(readl(addr) & BIT(id % RST_NR_PER_BANK));
804+ val = readl(addr) & BIT(id % RST_NR_PER_BANK);
805+ return inverted ? !val : !!val;
789806 }
790807
791808 static int en7523_reset_xlate(struct reset_controller_dev *rcdev,
@@ -853,6 +870,12 @@ static int en7581_clk_hw_init(struct platform_device *pdev, · 61 unmodified lines
853870 val = readl(base + REG_NP_SCU_PCIC);
854871 writel(val | 3, base + REG_NP_SCU_PCIC);
855872
873+ val = readl(base + REG_RST_CTRL1);
874+ val |= REG_PCIE_HB_RST;
875+ writel(val, base + REG_RST_CTRL1);
876+ val &= ~REG_PCIE_HB_RST;
877+ writel(val, base + REG_RST_CTRL1);
878+
856879 return en7581_reset_register(&pdev->dev, base, en7581_rst_map,
857880 ARRAY_SIZE(en7581_rst_map),
858881 en7581_rst_ofs);
drivers/clk/clk-lmk04832.c+4−8
@@ -815,13 +815,6 @@ static int lmk04832_sclk_sync_sequence(struct lmk04832 *lmk) · 814 unmodified lines
815815 if (ret)
816816 return ret;
817817
818− ret = regmap_update_bits(lmk->regmap, LMK04832_REG_SYNC,
819− LMK04832_BIT_SYNC_MODE,
820− FIELD_PREP(LMK04832_BIT_SYNC_MODE,
821− lmk->sync_mode));
822− if (ret)
823− return ret;
824−
825818 /*
826819 * 9. (optional) if SCLKx_y_DIS_MODE was used to mute SYSREF outputs
827820 * during the SYNC event, restore SCLKx_y_DIS_MODE=0 for active state,
@@ -836,7 +829,10 @@ static int lmk04832_sclk_sync_sequence(struct lmk04832 *lmk) · 8 unmodified lines
836829 * SYNC pulse to delay the output by some number of VCO counts).
837830 */
838831
839− return ret;
832+ return regmap_update_bits(lmk->regmap, LMK04832_REG_SYNC,
833+ LMK04832_BIT_SYNC_MODE,
834+ FIELD_PREP(LMK04832_BIT_SYNC_MODE,
835+ lmk->sync_mode));
840836 }
841837
842838 static int lmk04832_sclk_is_enabled(struct clk_hw *hw)
drivers/clk/clk-palmas.c+15−9
@@ -194,6 +194,13 @@ static void palmas_clks_get_clk_data(struct platform_device *pdev, · 193 unmodified lines
194194 cinfo->ext_control_pin = prop;
195195 }
196196
197+static void palmas_clks_unprepare_ext_control(void *data)
198+{
199+ struct palmas_clock_info *cinfo = data;
200+
201+ clk_unprepare(cinfo->hw.clk);
202+}
203+
197204 static int palmas_clks_init_configure(struct palmas_clock_info *cinfo)
198205 {
199206 int ret;
@@ -214,13 +221,18 @@ static int palmas_clks_init_configure(struct palmas_clock_info *cinfo) · 14 unmodified lines
214221 return ret;
215222 }
216223
224+ ret = devm_add_action_or_reset(cinfo->dev,
225+ palmas_clks_unprepare_ext_control,
226+ cinfo);
227+ if (ret)
228+ return ret;
229+
217230 ret = palmas_ext_control_req_config(cinfo->palmas,
218231 cinfo->clk_desc->sleep_reqstr_id,
219232 cinfo->ext_control_pin, true);
220233 if (ret < 0) {
221234 dev_err(cinfo->dev, "Ext config for %s failed, %d\n",
222235 cinfo->clk_desc->clk_name, ret);
223− clk_unprepare(cinfo->hw.clk);
224236 return ret;
225237 }
226238 }
@@ -230,7 +242,6 @@ static int palmas_clks_init_configure(struct palmas_clock_info *cinfo) · 3 unmodified lines
230242 static int palmas_clks_probe(struct platform_device *pdev)
231243 {
232244 struct palmas *palmas = dev_get_drvdata(pdev->dev.parent);
233− struct device_node *node = pdev->dev.of_node;
234245 const struct palmas_clks_of_match_data *match_data;
235246 struct palmas_clock_info *cinfo;
236247 int ret;
@@ -264,24 +275,19 @@ static int palmas_clks_probe(struct platform_device *pdev) · 27 unmodified lines
264275 return ret;
265276 }
266277
267− ret = of_clk_add_hw_provider(node, of_clk_hw_simple_get, &cinfo->hw);
278+ ret = devm_of_clk_add_hw_provider(&pdev->dev, of_clk_hw_simple_get,
279+ &cinfo->hw);
268280 if (ret < 0)
269281 dev_err(&pdev->dev, "Fail to add clock driver, %d\n", ret);
270282 return ret;
271283 }
272284
273−static void palmas_clks_remove(struct platform_device *pdev)
274−{
275− of_clk_del_provider(pdev->dev.of_node);
276−}
277−
278285 static struct platform_driver palmas_clks_driver = {
279286 .driver = {
280287 .name = "palmas-clk",
281288 .of_match_table = palmas_clks_of_match,
282289 },
283290 .probe = palmas_clks_probe,
284− .remove = palmas_clks_remove,
285291 };
286292
287293 module_platform_driver(palmas_clks_driver);
drivers/clk/clk-si544.c+65−17
@@ -1,6 +1,6 @@
11 // SPDX-License-Identifier: GPL-2.0
22 /*
3− * Driver for Silicon Labs Si544 Programmable Oscillator
3+ * Driver for Silicon Labs Si544/Si549 Programmable Oscillator
44 * Copyright (C) 2018 Topic Embedded Products
55 * Author: Mike Looijmans <mike.looijmans@topic.nl>
66 */
@@ -40,7 +40,9 @@ · 33 unmodified lines
4040 #define SI544_MIN_FREQ 200000U
4141
4242 /* Si544 Internal oscillator runs at 55.05 MHz */
43−#define FXO 55050000U
43+#define SI544_XO_FREQ 55050000U
44+/* Si549 Internal oscilator runs at 152.60 MHz */
45+#define SI549_XO_FREQ 152600000U
4446
4547 /* VCO range is 10.8 .. 12.1 GHz, max depends on speed grade */
4648 #define FVCO_MIN 10800000000ULL
@@ -56,11 +58,16 @@ · 9 unmodified lines
5658 #define DELTA_M_FRAC_NUM 19
5759 #define DELTA_M_FRAC_DEN 20000
5860
61+struct si544_clk_desc {
62+ unsigned long max_freq;
63+ unsigned long xo_freq;
64+};
65+
5966 struct clk_si544 {
6067 struct clk_hw hw;
6168 struct regmap *regmap;
6269 struct i2c_client *i2c_client;
63− unsigned long max_freq;
70+ const struct si544_clk_desc *chip_info;
6471 };
6572 #define to_clk_si544(_hw) container_of(_hw, struct clk_si544, hw)
6673
@@ -79,6 +86,7 @@ struct clk_si544_muldiv { · 12 unmodified lines
7986 u16 hs_div;
8087 u8 ls_div_bits;
8188 s32 delta_m;
89+ u32 xo_freq;
8290 };
8391
8492 /* Enables or disables the output driver */
@@ -145,6 +153,8 @@ static int si544_get_muldiv(struct clk_si544 *data, · 60 unmodified lines
145153 settings->delta_m = reg[0] << 8 | reg[1] << 16 | reg[2] << 24;
146154 settings->delta_m >>= 8;
147155
156+ settings->xo_freq = data->chip_info->xo_freq;
157+
148158 return 0;
149159 }
150160
@@ -193,7 +203,7 @@ static bool is_valid_frequency(const struct clk_si544 *data, · 42 unmodified lines
193203 if (frequency < SI544_MIN_FREQ)
194204 return false;
195205
196− return frequency <= data->max_freq;
206+ return frequency <= data->chip_info->max_freq;
197207 }
198208
199209 /* Calculate divider settings for a given frequency */
@@ -201,6 +211,7 @@ static int si544_calc_muldiv(struct clk_si544_muldiv *settings, · 1 unmodified line
201211 unsigned long frequency)
202212 {
203213 u64 vco;
214+ u32 fxo = settings->xo_freq;
204215 u32 ls_freq;
205216 u32 tmp;
206217 u8 res;
@@ -238,13 +249,13 @@ static int si544_calc_muldiv(struct clk_si544_muldiv *settings, · 31 unmodified lines
238249 vco = (u64)ls_freq * settings->hs_div;
239250
240251 /* Calculate the integer part of the feedback divider */
241− tmp = do_div(vco, FXO);
252+ tmp = do_div(vco, fxo);
242253 settings->fb_div_int = vco;
243254
244255 /* And the fractional bits using the remainder */
245256 vco = (u64)tmp << 32;
246− vco += FXO / 2; /* Round to nearest multiple */
247− do_div(vco, FXO);
257+ vco += fxo / 2; /* Round to nearest multiple */
258+ do_div(vco, fxo);
248259 settings->fb_div_frac = vco;
249260
250261 /* Reset the frequency adjustment */
@@ -258,15 +269,16 @@ static unsigned long si544_calc_center_rate( · 7 unmodified lines
258269 const struct clk_si544_muldiv *settings)
259270 {
260271 u32 d = settings->hs_div * BIT(settings->ls_div_bits);
272+ u32 fxo = settings->xo_freq;
261273 u64 vco;
262274
263275 /* Calculate VCO from the fractional part */
264− vco = (u64)settings->fb_div_frac * FXO;
265− vco += (FXO / 2);
276+ vco = (u64)settings->fb_div_frac * fxo;
277+ vco += (fxo / 2);
266278 vco >>= 32;
267279
268280 /* Add the integer part of the VCO frequency */
269− vco += (u64)settings->fb_div_int * FXO;
281+ vco += (u64)settings->fb_div_int * fxo;
270282
271283 /* Apply divider to obtain the generated frequency */
272284 do_div(vco, d);
@@ -446,7 +458,7 @@ static int si544_probe(struct i2c_client *client) · 173 unmodified lines
446458 init.num_parents = 0;
447459 data->hw.init = &init;
448460 data->i2c_client = client;
449− data->max_freq = (uintptr_t)i2c_get_match_data(client);
461+ data->chip_info = i2c_get_match_data(client);
450462
451463 if (of_property_read_string(client->dev.of_node, "clock-output-names",
452464 &init.name))
@@ -478,18 +490,54 @@ static int si544_probe(struct i2c_client *client) · 25 unmodified lines
478490 return 0;
479491 }
480492
493+static const struct si544_clk_desc clk_si544a_info = {
494+ .xo_freq = SI544_XO_FREQ,
495+ .max_freq = 1500000000,
496+};
497+
498+static const struct si544_clk_desc clk_si544b_info = {
499+ .xo_freq = SI544_XO_FREQ,
500+ .max_freq = 800000000,
501+};
502+
503+static const struct si544_clk_desc clk_si544c_info = {
504+ .xo_freq = SI544_XO_FREQ,
505+ .max_freq = 325000000,
506+};
507+
508+static const struct si544_clk_desc clk_si549a_info = {
509+ .xo_freq = SI549_XO_FREQ,
510+ .max_freq = 1500000000,
511+};
512+
513+static const struct si544_clk_desc clk_si549b_info = {
514+ .xo_freq = SI549_XO_FREQ,
515+ .max_freq = 800000000,
516+};
517+
518+static const struct si544_clk_desc clk_si549c_info = {
519+ .xo_freq = SI549_XO_FREQ,
520+ .max_freq = 325000000,
521+};
522+
481523 static const struct i2c_device_id si544_id[] = {
482− { .name = "si544a", .driver_data = 1500000000 },
483− { .name = "si544b", .driver_data = 800000000 },
484− { .name = "si544c", .driver_data = 350000000 },
524+ { .name = "si544a", .driver_data = (kernel_ulong_t)&clk_si544a_info },
525+ { .name = "si544b", .driver_data = (kernel_ulong_t)&clk_si544b_info },
526+ { .name = "si544c", .driver_data = (kernel_ulong_t)&clk_si544c_info },
527+ { .name = "si549a", .driver_data = (kernel_ulong_t)&clk_si549a_info },
528+ { .name = "si549b", .driver_data = (kernel_ulong_t)&clk_si549b_info },
529+ { .name = "si549c", .driver_data = (kernel_ulong_t)&clk_si549c_info },
485530 { }
486531 };
487532 MODULE_DEVICE_TABLE(i2c, si544_id);
488533
489534 static const struct of_device_id clk_si544_of_match[] = {
490− { .compatible = "silabs,si544a", .data = (void *)1500000000 },
491− { .compatible = "silabs,si544b", .data = (void *)800000000 },
492− { .compatible = "silabs,si544c", .data = (void *)350000000 },
535+ { .compatible = "silabs,si544a", .data = &clk_si544a_info },
536+ { .compatible = "silabs,si544b", .data = &clk_si544b_info },
537+ { .compatible = "silabs,si544c", .data = &clk_si544c_info },
538+ { .compatible = "silabs,si549a", .data = &clk_si549a_info },
539+ { .compatible = "silabs,si549b", .data = &clk_si549b_info },
540+ { .compatible = "silabs,si549c", .data = &clk_si549c_info },
493541 { }
494542 };
495543 MODULE_DEVICE_TABLE(of, clk_si544_of_match);
drivers/clk/eswin/clk.c+2−2
@@ -204,7 +204,7 @@ int eswin_clk_register_pll(struct device *dev, struct eswin_pll_clock *clks, · 203 unmodified lines
204204 int nums, struct eswin_clock_data *data)
205205 {
206206 struct eswin_clk_pll *p_clk = NULL;
207− struct clk_init_data init;
207+ struct clk_init_data init = {};
208208 struct clk_hw *clk_hw;
209209 int i, ret;
210210
@@ -419,7 +419,7 @@ struct clk_hw *eswin_register_clkdiv(struct device *dev, unsigned int id, · 208 unmodified lines
419419 unsigned long priv_flag, spinlock_t *lock)
420420 {
421421 struct eswin_divider_clock *dclk;
422− struct clk_init_data init;
422+ struct clk_init_data init = {};
423423 struct clk_hw *clk_hw;
424424 int ret;
425425
drivers/clk/hisilicon/clk-hi3660-stub.c+3−7
@@ -114,7 +114,6 @@ static struct clk_hw *hi3660_stub_clk_hw_get(struct of_phandle_args *clkspec, · 113 unmodified lines
114114 static int hi3660_stub_clk_probe(struct platform_device *pdev)
115115 {
116116 struct device *dev = &pdev->dev;
117− struct resource *res;
118117 unsigned int i;
119118 int ret;
120119
@@ -129,12 +128,9 @@ static int hi3660_stub_clk_probe(struct platform_device *pdev) · 8 unmodified lines
129128 if (IS_ERR(stub_clk_chan.mbox))
130129 return PTR_ERR(stub_clk_chan.mbox);
131130
132− res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
133− if (!res)
134− return -EINVAL;
135− freq_reg = devm_ioremap(dev, res->start, resource_size(res));
136− if (!freq_reg)
137− return -ENOMEM;
131+ freq_reg = devm_platform_ioremap_resource(pdev, 0);
132+ if (IS_ERR(freq_reg))
133+ return PTR_ERR(freq_reg);
138134
139135 freq_reg += HI3660_STUB_CLOCK_DATA;
140136
drivers/clk/mediatek/Kconfig+10−0
@@ -537,6 +537,16 @@ config COMMON_CLK_MT8173_IMGSYS · 536 unmodified lines
537537 help
538538 This driver supports MediaTek MT8173 imgsys clocks.
539539
540+config COMMON_CLK_MT8173_MFGTOP
541+ tristate "Clock and power driver for MediaTek MT8173 mfgtop"
542+ depends on COMMON_CLK_MT8173
543+ depends on PM
544+ default COMMON_CLK_MT8173
545+ select PM_GENERIC_DOMAINS
546+ select PM_GENERIC_DOMAINS_OF
547+ help
548+ This driver supports MediaTek MT8173 mfgtop clocks and power domain.
549+
540550 config COMMON_CLK_MT8173_MMSYS
541551 tristate "Clock driver for MediaTek MT8173 mmsys"
542552 depends on COMMON_CLK_MT8173
drivers/clk/mediatek/Makefile+1−0
@@ -82,6 +82,7 @@ obj-$(CONFIG_COMMON_CLK_MT8167_VDECSYS) += clk-mt8167-vdec.o · 81 unmodified lines
8282 obj-$(CONFIG_COMMON_CLK_MT8173) += clk-mt8173-apmixedsys.o clk-mt8173-infracfg.o \
8383 clk-mt8173-pericfg.o clk-mt8173-topckgen.o
8484 obj-$(CONFIG_COMMON_CLK_MT8173_IMGSYS) += clk-mt8173-img.o
85+obj-$(CONFIG_COMMON_CLK_MT8173_MFGTOP) += clk-mt8173-mfgtop.o
8586 obj-$(CONFIG_COMMON_CLK_MT8173_MMSYS) += clk-mt8173-mm.o
8687 obj-$(CONFIG_COMMON_CLK_MT8173_VDECSYS) += clk-mt8173-vdecsys.o
8788 obj-$(CONFIG_COMMON_CLK_MT8173_VENCSYS) += clk-mt8173-vencsys.o
drivers/clk/mediatek/clk-mt6735-apmixedsys.c+4−1
@@ -102,9 +102,12 @@ static int clk_mt6735_apmixed_probe(struct platform_device *pdev) · 101 unmodified lines
102102
103103 ret = devm_of_clk_add_hw_provider(&pdev->dev, of_clk_hw_onecell_get,
104104 clk_data);
105− if (ret)
105+ if (ret) {
106106 dev_err(&pdev->dev,
107107 "Failed to register clock provider: %d\n", ret);
108+ mtk_clk_unregister_plls(apmixedsys_plls, ARRAY_SIZE(apmixedsys_plls),
109+ clk_data);
110+ }
108111
109112 return ret;
110113 }
drivers/clk/mediatek/clk-mt6735-vdecsys.c+1−0
@@ -63,6 +63,7 @@ static const struct of_device_id of_match_mt6735_vdecsys[] = { · 62 unmodified lines
6363 { .compatible = "mediatek,mt6735-vdecsys", .data = &vdecsys_clks },
6464 { /* sentinel */ }
6565 };
66+MODULE_DEVICE_TABLE(of, of_match_mt6735_vdecsys);
6667
6768 static struct platform_driver clk_mt6735_vdecsys = {
6869 .probe = mtk_clk_simple_probe,
drivers/clk/mediatek/clk-mt6735-vencsys.c+1−0
@@ -37,6 +37,7 @@ static const struct of_device_id of_match_mt6735_vencsys[] = { · 36 unmodified lines
3737 { .compatible = "mediatek,mt6735-vencsys", .data = &vencsys_clks },
3838 { /* sentinel */ }
3939 };
40+MODULE_DEVICE_TABLE(of, of_match_mt6735_vencsys);
4041
4142 static struct platform_driver clk_mt6735_vencsys = {
4243 .probe = mtk_clk_simple_probe,
drivers/clk/mediatek/clk-mt8135.c+4−1
@@ -409,6 +409,9 @@ static const struct mtk_gate_regs infra_cg_regs = { · 408 unmodified lines
409409 GATE_MTK_FLAGS(_id, _name, _parent, &infra_cg_regs, _shift, \
410410 &mtk_clk_gate_ops_setclr, CLK_IS_CRITICAL)
411411
412+#define GATE_ICG_INV(_id, _name, _parent, _shift) \
413+ GATE_MTK(_id, _name, _parent, &infra_cg_regs, _shift, &mtk_clk_gate_ops_setclr_inv)
414+
412415 static const struct mtk_gate infra_clks[] = {
413416 GATE_DUMMY(CLK_DUMMY, "infra_dummy"),
414417 GATE_ICG(CLK_INFRA_PMIC_WRAP, "pmic_wrap_ck", "axi_sel", 23),
@@ -419,7 +422,7 @@ static const struct mtk_gate infra_clks[] = { · 4 unmodified lines
419422 GATE_ICG(CLK_INFRA_CPUM, "cpum_ck", "cpum_tck_in", 15),
420423 GATE_ICG_AO(CLK_INFRA_M4U, "m4u_ck", "mem_sel", 8),
421424 GATE_ICG(CLK_INFRA_MFGAXI, "mfgaxi_ck", "axi_sel", 7),
422− GATE_ICG(CLK_INFRA_DEVAPC, "devapc_ck", "axi_sel", 6),
425+ GATE_ICG_INV(CLK_INFRA_DEVAPC, "devapc_ck", "axi_sel", 6),
423426 GATE_ICG(CLK_INFRA_AUDIO, "audio_ck", "aud_intbus_sel", 5),
424427 GATE_ICG(CLK_INFRA_MFG_BUS, "mfg_bus_ck", "axi_sel", 2),
425428 GATE_ICG(CLK_INFRA_SMI, "smi_ck", "smi_sel", 1),
drivers/clk/mediatek/clk-mt8173-mfgtop.c+242−0
@@ -0,0 +1,242 @@
1+// SPDX-License-Identifier: GPL-2.0-only
2+/*
3+ * Copyright (c) 2024 Google LLC
4+ * Author: Chen-Yu Tsai <wenst@chromium.org>
5+ *
6+ * Based on driver in downstream ChromeOS v5.15 kernel.
7+ *
8+ * Copyright (c) 2014 MediaTek Inc.
9+ * Author: Chiawen Lee <chiawen.lee@mediatek.com>
10+ */
11+
12+#include <dt-bindings/clock/mt8173-clk.h>
13+
14+#include <linux/bitfield.h>
15+#include <linux/clk.h>
16+#include <linux/mfd/syscon.h>
17+#include <linux/module.h>
18+#include <linux/of.h>
19+#include <linux/platform_device.h>
20+#include <linux/pm_domain.h>
21+#include <linux/pm_runtime.h>
22+#include <linux/regmap.h>
23+
24+#include "clk-gate.h"
25+#include "clk-mtk.h"
26+
27+static const struct mtk_gate_regs mfg_cg_regs = {
28+ .sta_ofs = 0x0000,
29+ .clr_ofs = 0x0008,
30+ .set_ofs = 0x0004,
31+};
32+
33+#define GATE_MFG(_id, _name, _parent, _shift, _flags) \
34+ GATE_MTK_FLAGS(_id, _name, _parent, &mfg_cg_regs, _shift, &mtk_clk_gate_ops_setclr, _flags)
35+
36+/* TODO: The block actually has dividers for the core and mem clocks. */
37+static const struct mtk_gate mfg_clks[] = {
38+ GATE_MFG(CLK_MFG_AXI, "mfg_axi", "axi_mfg_in_sel", 0, CLK_SET_RATE_PARENT),
39+ GATE_MFG(CLK_MFG_MEM, "mfg_mem", "mem_mfg_in_sel", 1, CLK_SET_RATE_PARENT),
40+ GATE_MFG(CLK_MFG_G3D, "mfg_g3d", "mfg_sel", 2, CLK_SET_RATE_PARENT),
41+ GATE_MFG(CLK_MFG_26M, "mfg_26m", "clk26m", 3, 0),
42+};
43+
44+struct mt8173_mfgtop_data {
45+ struct clk_hw_onecell_data *clk_data;
46+ struct regmap *regmap;
47+ struct generic_pm_domain genpd;
48+ struct of_phandle_args parent_pd, child_pd;
49+ struct clk *clk_26m;
50+};
51+
52+/* Delay count in clock cycles */
53+#define MFG_ACTIVE_POWER_CON0 0x24
54+ #define RST_B_DELAY_CNT GENMASK(7, 0) /* pwr_rst_b de-assert delay during power-up */
55+ #define CLK_EN_DELAY_CNT GENMASK(15, 8) /* CLK_DIS deassert delay during power-up */
56+ #define CLK_DIS_DELAY_CNT GENMASK(23, 16) /* CLK_DIS assert delay during power-down */
57+ #define FORCE_ABORT BIT(30) /* write 1 to force abort a power event */
58+ #define ACTIVE_PWRCTL_EN BIT(31) /* enable ACTIVE_POWER */
59+
60+#define MFG_ACTIVE_POWER_CON1 0x28
61+ #define PWR_ON_S_DELAY_CNT GENMASK(7, 0) /* pwr_on_s assert delay during power-up */
62+ #define ISO_DELAY_CNT GENMASK(15, 8) /* ISO assert delay during power-down */
63+ #define ISOOFF_DELAY_CNT GENMASK(23, 16) /* ISO de-assert delay during power-up */
64+ #define RST_DELAY_CNT GENMASK(31, 24) /* pwr_rsb_b assert delay during power-down */
65+
66+static int clk_mt8173_mfgtop_power_on(struct generic_pm_domain *domain)
67+{
68+ struct mt8173_mfgtop_data *data = container_of(domain, struct mt8173_mfgtop_data, genpd);
69+ int ret;
70+
71+ /* drives internal power management */
72+ ret = clk_prepare_enable(data->clk_26m);
73+ if (ret)
74+ return ret;
75+
76+ /* Power on/off delays for various signals */
77+ regmap_write(data->regmap, MFG_ACTIVE_POWER_CON0,
78+ FIELD_PREP(RST_B_DELAY_CNT, 77) |
79+ FIELD_PREP(CLK_EN_DELAY_CNT, 61) |
80+ FIELD_PREP(CLK_DIS_DELAY_CNT, 60) |
81+ FIELD_PREP(ACTIVE_PWRCTL_EN, 0));
82+ regmap_write(data->regmap, MFG_ACTIVE_POWER_CON1,
83+ FIELD_PREP(PWR_ON_S_DELAY_CNT, 11) |
84+ FIELD_PREP(ISO_DELAY_CNT, 68) |
85+ FIELD_PREP(ISOOFF_DELAY_CNT, 69) |
86+ FIELD_PREP(RST_DELAY_CNT, 77));
87+
88+ /* Magic numbers related to core switch sequence and delays */
89+ regmap_write(data->regmap, 0xe0, 0x7a710184);
90+ regmap_write(data->regmap, 0xe4, 0x835f6856);
91+ regmap_write(data->regmap, 0xe8, 0x002b0234);
92+ regmap_write(data->regmap, 0xec, 0x80000000);
93+ regmap_write(data->regmap, 0xa0, 0x08000000);
94+
95+ return 0;
96+}
97+
98+static int clk_mt8173_mfgtop_power_off(struct generic_pm_domain *domain)
99+{
100+ struct mt8173_mfgtop_data *data = container_of(domain, struct mt8173_mfgtop_data, genpd);
101+
102+ /* Magic numbers related to core switch sequence and delays */
103+ regmap_write(data->regmap, 0xec, 0);
104+
105+ /* drives internal power management */
106+ clk_disable_unprepare(data->clk_26m);
107+
108+ return 0;
109+}
110+
111+static int clk_mt8173_mfgtop_probe(struct platform_device *pdev)
112+{
113+ struct device *dev = &pdev->dev;
114+ struct device_node *node = dev->of_node;
115+ struct mt8173_mfgtop_data *data;
116+ int ret;
117+
118+ data = devm_kzalloc(dev, sizeof(*data), GFP_KERNEL);
119+ if (!data)
120+ return -ENOMEM;
121+
122+ platform_set_drvdata(pdev, data);
123+
124+ data->clk_data = mtk_devm_alloc_clk_data(dev, ARRAY_SIZE(mfg_clks));
125+ if (!data->clk_data)
126+ return -ENOMEM;
127+
128+ /* MTK clock gates also uses regmap */
129+ data->regmap = device_node_to_regmap(node);
130+ if (IS_ERR(data->regmap))
131+ return dev_err_probe(dev, PTR_ERR(data->regmap), "Failed to get regmap\n");
132+
133+ data->child_pd.np = node;
134+ data->child_pd.args_count = 0;
135+ ret = of_parse_phandle_with_args(node, "power-domains", "#power-domain-cells", 0,
136+ &data->parent_pd);
137+ if (ret)
138+ return dev_err_probe(dev, ret, "Failed to parse power domain\n");
139+
140+ devm_pm_runtime_enable(dev);
141+ /*
142+ * Do a pm_runtime_resume_and_get() to workaround a possible
143+ * deadlock between clk_register() and the genpd framework.
144+ */
145+ ret = pm_runtime_resume_and_get(dev);
146+ if (ret) {
147+ dev_err_probe(dev, ret, "Failed to runtime resume device\n");
148+ goto put_of_node;
149+ }
150+
151+ ret = mtk_clk_register_gates(dev, node, mfg_clks, ARRAY_SIZE(mfg_clks),
152+ data->clk_data);
153+ if (ret) {
154+ dev_err_probe(dev, ret, "Failed to register clock gates\n");
155+ goto put_pm_runtime;
156+ }
157+
158+ data->clk_26m = clk_hw_get_clk(data->clk_data->hws[CLK_MFG_26M], "26m");
159+ if (IS_ERR(data->clk_26m)) {
160+ ret = dev_err_probe(dev, PTR_ERR(data->clk_26m), "Failed to get 26 MHz clock\n");
161+ goto unregister_clks;
162+ }
163+
164+ ret = of_clk_add_hw_provider(node, of_clk_hw_onecell_get, data->clk_data);
165+ if (ret) {
166+ dev_err_probe(dev, ret, "Failed to add clk OF provider\n");
167+ goto put_26m_clk;
168+ }
169+
170+ data->genpd.name = "mfg-top";
171+ data->genpd.power_on = clk_mt8173_mfgtop_power_on;
172+ data->genpd.power_off = clk_mt8173_mfgtop_power_off;
173+ ret = pm_genpd_init(&data->genpd, NULL, true);
174+ if (ret) {
175+ dev_err_probe(dev, ret, "Failed to add power domain\n");
176+ goto del_clk_provider;
177+ }
178+
179+ ret = of_genpd_add_provider_simple(node, &data->genpd);
180+ if (ret) {
181+ dev_err_probe(dev, ret, "Failed to add power domain OF provider\n");
182+ goto remove_pd;
183+ }
184+
185+ ret = of_genpd_add_subdomain(&data->parent_pd, &data->child_pd);
186+ if (ret) {
187+ dev_err_probe(dev, ret, "Failed to link PM domains\n");
188+ goto del_pd_provider;
189+ }
190+
191+ pm_runtime_put(dev);
192+ return 0;
193+
194+del_pd_provider:
195+ of_genpd_del_provider(node);
196+remove_pd:
197+ pm_genpd_remove(&data->genpd);
198+del_clk_provider:
199+ of_clk_del_provider(node);
200+put_26m_clk:
201+ clk_put(data->clk_26m);
202+unregister_clks:
203+ mtk_clk_unregister_gates(mfg_clks, ARRAY_SIZE(mfg_clks), data->clk_data);
204+put_pm_runtime:
205+ pm_runtime_put_sync(dev);
206+put_of_node:
207+ of_node_put(data->parent_pd.np);
208+ return ret;
209+}
210+
211+static void clk_mt8173_mfgtop_remove(struct platform_device *pdev)
212+{
213+ struct mt8173_mfgtop_data *data = platform_get_drvdata(pdev);
214+ struct device_node *node = pdev->dev.of_node;
215+
216+ of_genpd_remove_subdomain(&data->parent_pd, &data->child_pd);
217+ of_genpd_del_provider(node);
218+ pm_genpd_remove(&data->genpd);
219+ of_clk_del_provider(node);
220+ clk_put(data->clk_26m);
221+ mtk_clk_unregister_gates(mfg_clks, ARRAY_SIZE(mfg_clks), data->clk_data);
222+ of_node_put(data->parent_pd.np);
223+}
224+
225+static const struct of_device_id of_match_clk_mt8173_mfgtop[] = {
226+ { .compatible = "mediatek,mt8173-mfgtop" },
227+ { /* sentinel */ }
228+};
229+MODULE_DEVICE_TABLE(of, of_match_clk_mt8173_mfgtop);
230+
231+static struct platform_driver clk_mt8173_mfgtop_drv = {
232+ .probe = clk_mt8173_mfgtop_probe,
233+ .remove = clk_mt8173_mfgtop_remove,
234+ .driver = {
235+ .name = "clk-mt8173-mfgtop",
236+ .of_match_table = of_match_clk_mt8173_mfgtop,
237+ },
238+};
239+module_platform_driver(clk_mt8173_mfgtop_drv);
240+
241+MODULE_DESCRIPTION("MediaTek MT8173 mfgtop clock driver");
242+MODULE_LICENSE("GPL");
drivers/clk/mediatek/clk-mt8196-vlpckgen.c+0−1
@@ -629,7 +629,6 @@ static const struct regmap_config vlpckgen_regmap_config = { · 628 unmodified lines
629629 .val_bits = 32,
630630 .reg_stride = 4,
631631 .max_register = 0x1000,
632− .fast_io = true,
633632 };
634633
635634 static int clk_mt8196_vlp_probe(struct platform_device *pdev)
drivers/clk/mediatek/clk-pllfh.c+49−49
@@ -197,12 +197,56 @@ static void mtk_clk_unregister_pllfh(struct clk_hw *hw) · 196 unmodified lines
197197 kfree(fh);
198198 }
199199
200+static void mtk_clk_cleanup_pllfhs(void __iomem *iomem_base,
201+ const struct mtk_pll_data *plls, int num_plls,
202+ void __iomem *iomem_fhctl_base,
203+ struct mtk_pllfh_data *pllfhs, int num_fhs,
204+ struct clk_hw_onecell_data *clk_data)
205+{
206+ void __iomem *base = iomem_base;
207+ void __iomem *fhctl_base = iomem_fhctl_base;
208+ int i;
209+
210+ for (i = num_plls - 1; i >= 0; i--) {
211+ const struct mtk_pll_data *pll = &plls[i];
212+ struct mtk_pllfh_data *pllfh;
213+ bool use_fhctl;
214+
215+ if (IS_ERR_OR_NULL(clk_data->hws[pll->id]))
216+ continue;
217+
218+ pllfh = get_pllfh_by_id(pllfhs, num_fhs, pll->id);
219+ use_fhctl = fhctl_is_supported_and_enabled(pllfh);
220+
221+ if (!base)
222+ base = mtk_clk_pll_get_base(clk_data->hws[pll->id],
223+ pll);
224+
225+ if (use_fhctl) {
226+ if (!fhctl_base)
227+ fhctl_base = pllfh->state.base;
228+ mtk_clk_unregister_pllfh(clk_data->hws[pll->id]);
229+ } else {
230+ mtk_clk_unregister_pll(clk_data->hws[pll->id]);
231+ }
232+
233+ clk_data->hws[pll->id] = ERR_PTR(-ENOENT);
234+ }
235+
236+ if (fhctl_base)
237+ iounmap(fhctl_base);
238+
239+ if (base)
240+ iounmap(base);
241+}
242+
243+
200244 int mtk_clk_register_pllfhs(struct device *dev,
201245 const struct mtk_pll_data *plls, int num_plls,
202246 struct mtk_pllfh_data *pllfhs, int num_fhs,
203247 struct clk_hw_onecell_data *clk_data)
204248 {
205− void __iomem *base;
249+ void __iomem *base, *fhctl_base = NULL;
206250 int i;
207251 struct clk_hw *hw;
208252
@@ -238,24 +282,8 @@ int mtk_clk_register_pllfhs(struct device *dev, · 29 unmodified lines
238282 return 0;
239283
240284 err:
241− while (--i >= 0) {
242− const struct mtk_pll_data *pll = &plls[i];
243− struct mtk_pllfh_data *pllfh;
244− bool use_fhctl;
245−
246− pllfh = get_pllfh_by_id(pllfhs, num_fhs, pll->id);
247− use_fhctl = fhctl_is_supported_and_enabled(pllfh);
248−
249− if (use_fhctl)
250− mtk_clk_unregister_pllfh(clk_data->hws[pll->id]);
251− else
252− mtk_clk_unregister_pll(clk_data->hws[pll->id]);
253−
254− clk_data->hws[pll->id] = ERR_PTR(-ENOENT);
255− }
256−
257− iounmap(base);
258−
285+ mtk_clk_cleanup_pllfhs(base, plls, i, fhctl_base, pllfhs, num_fhs,
286+ clk_data);
259287 return PTR_ERR(hw);
260288 }
261289 EXPORT_SYMBOL_GPL(mtk_clk_register_pllfhs);
@@ -264,38 +292,10 @@ void mtk_clk_unregister_pllfhs(const struct mtk_pll_data *plls, int num_plls, · 2 unmodified lines
264292 struct mtk_pllfh_data *pllfhs, int num_fhs,
265293 struct clk_hw_onecell_data *clk_data)
266294 {
267− void __iomem *base = NULL, *fhctl_base = NULL;
268− int i;
269−
270295 if (!clk_data)
271296 return;
272297
273− for (i = num_plls; i > 0; i--) {
274− const struct mtk_pll_data *pll = &plls[i - 1];
275− struct mtk_pllfh_data *pllfh;
276− bool use_fhctl;
277−
278− if (IS_ERR_OR_NULL(clk_data->hws[pll->id]))
279− continue;
280−
281− pllfh = get_pllfh_by_id(pllfhs, num_fhs, pll->id);
282− use_fhctl = fhctl_is_supported_and_enabled(pllfh);
283−
284− if (use_fhctl) {
285− fhctl_base = pllfh->state.base;
286− mtk_clk_unregister_pllfh(clk_data->hws[pll->id]);
287− } else {
288− base = mtk_clk_pll_get_base(clk_data->hws[pll->id],
289− pll);
290− mtk_clk_unregister_pll(clk_data->hws[pll->id]);
291− }
292−
293− clk_data->hws[pll->id] = ERR_PTR(-ENOENT);
294− }
295−
296− if (fhctl_base)
297− iounmap(fhctl_base);
298−
299− iounmap(base);
298+ mtk_clk_cleanup_pllfhs(NULL, plls, num_plls, NULL, pllfhs,
299+ num_fhs, clk_data);
300300 }
301301 EXPORT_SYMBOL_GPL(mtk_clk_unregister_pllfhs);
drivers/clk/mmp/clk-pxa1908-apbc.c+1−1
@@ -114,7 +114,7 @@ static void pxa1908_clk_reset_init(struct device_node *np, · 113 unmodified lines
114114 cells[i].bits = BIT(2);
115115 cells[i].flags = 0;
116116 cells[i].lock = apbc_gate_clks[i].lock;
117− };
117+ }
118118
119119 mmp_clk_reset_register(np, cells, nr_cells);
120120 }
drivers/clk/mmp/clk-pxa1908-apbcp.c+1−1
@@ -61,7 +61,7 @@ static void pxa1908_clk_reset_init(struct device_node *np, · 60 unmodified lines
6161 cells[i].bits = BIT(2);
6262 cells[i].flags = 0;
6363 cells[i].lock = apbcp_gate_clks[i].lock;
64− };
64+ }
6565
6666 mmp_clk_reset_register(np, cells, nr_cells);
6767 }
drivers/clk/mvebu/clk-cpu.c+1−1
@@ -153,7 +153,7 @@ static int clk_cpu_on_set_rate(struct clk_hw *hwclk, unsigned long rate, · 152 unmodified lines
153153 static int clk_cpu_set_rate(struct clk_hw *hwclk, unsigned long rate,
154154 unsigned long parent_rate)
155155 {
156− if (__clk_is_enabled(hwclk->clk))
156+ if (clk_hw_is_enabled(hwclk))
157157 return clk_cpu_on_set_rate(hwclk, rate, parent_rate);
158158 else
159159 return clk_cpu_off_set_rate(hwclk, rate, parent_rate);
drivers/clk/st/clkgen-pll.c+10−10
@@ -260,7 +260,7 @@ static int __clkgen_pll_enable(struct clk_hw *hw) · 259 unmodified lines
260260 if (pll->data->switch2pll_en)
261261 CLKGEN_WRITE(pll, switch2pll, 0);
262262
263− pr_debug("%s:%s enabled\n", __clk_get_name(hw->clk), __func__);
263+ pr_debug("%s:%s enabled\n", clk_hw_get_name(hw), __func__);
264264 }
265265
266266 return ret;
@@ -295,7 +295,7 @@ static void __clkgen_pll_disable(struct clk_hw *hw) · 28 unmodified lines
295295
296296 CLKGEN_WRITE(pll, pdn_ctrl, 1);
297297
298− pr_debug("%s:%s disabled\n", __clk_get_name(hw->clk), __func__);
298+ pr_debug("%s:%s disabled\n", clk_hw_get_name(hw), __func__);
299299 }
300300
301301 static void clkgen_pll_disable(struct clk_hw *hw)
@@ -405,14 +405,14 @@ static int stm_pll3200c32_determine_rate(struct clk_hw *hw, · 103 unmodified lines
405405 &req->rate);
406406 else {
407407 pr_debug("%s: %s rate %ld Invalid\n", __func__,
408− __clk_get_name(hw->clk), req->rate);
408+ clk_hw_get_name(hw), req->rate);
409409 req->rate = 0;
410410
411411 return 0;
412412 }
413413
414414 pr_debug("%s: %s new rate %ld [ndiv=%u] [idf=%u]\n",
415− __func__, __clk_get_name(hw->clk),
415+ __func__, clk_hw_get_name(hw),
416416 req->rate, (unsigned int)params.ndiv,
417417 (unsigned int)params.idf);
418418
@@ -434,7 +434,7 @@ static int set_rate_stm_pll3200c32(struct clk_hw *hw, unsigned long rate, · 15 unmodified lines
434434 clk_pll3200c32_get_rate(parent_rate, &params, &hwrate);
435435
436436 pr_debug("%s: %s new rate %ld [ndiv=0x%x] [idf=0x%x]\n",
437− __func__, __clk_get_name(hw->clk),
437+ __func__, clk_hw_get_name(hw),
438438 hwrate, (unsigned int)params.ndiv,
439439 (unsigned int)params.idf);
440440
@@ -547,7 +547,7 @@ static unsigned long recalc_stm_pll4600c28(struct clk_hw *hw, · 106 unmodified lines
547547
548548 clk_pll4600c28_get_rate(parent_rate, &params, &rate);
549549
550− pr_debug("%s:%s rate %lu\n", __clk_get_name(hw->clk), __func__, rate);
550+ pr_debug("%s:%s rate %lu\n", clk_hw_get_name(hw), __func__, rate);
551551
552552 return rate;
553553 }
@@ -562,14 +562,14 @@ static int stm_pll4600c28_determine_rate(struct clk_hw *hw, · 8 unmodified lines
562562 &req->rate);
563563 } else {
564564 pr_debug("%s: %s rate %ld Invalid\n", __func__,
565− __clk_get_name(hw->clk), req->rate);
565+ clk_hw_get_name(hw), req->rate);
566566 req->rate = 0;
567567
568568 return 0;
569569 }
570570
571571 pr_debug("%s: %s new rate %ld [ndiv=%u] [idf=%u]\n",
572− __func__, __clk_get_name(hw->clk),
572+ __func__, clk_hw_get_name(hw),
573573 req->rate, (unsigned int)params.ndiv,
574574 (unsigned int)params.idf);
575575
@@ -591,12 +591,12 @@ static int set_rate_stm_pll4600c28(struct clk_hw *hw, unsigned long rate, · 15 unmodified lines
591591 clk_pll4600c28_get_rate(parent_rate, &params, &hwrate);
592592 } else {
593593 pr_debug("%s: %s rate %ld Invalid\n", __func__,
594− __clk_get_name(hw->clk), rate);
594+ clk_hw_get_name(hw), rate);
595595 return -EINVAL;
596596 }
597597
598598 pr_debug("%s: %s new rate %ld [ndiv=0x%x] [idf=0x%x]\n",
599− __func__, __clk_get_name(hw->clk),
599+ __func__, clk_hw_get_name(hw),
600600 hwrate, (unsigned int)params.ndiv,
601601 (unsigned int)params.idf);
602602
drivers/clk/tegra/clk-pll.c+1−0
@@ -575,6 +575,7 @@ static int _calc_rate(struct clk_hw *hw, struct tegra_clk_pll_freq_table *cfg, · 574 unmodified lines
575575 break;
576576 case 9600000:
577577 case 28800000:
578+ case 48000000:
578579 /*
579580 * PLL_P_OUT1 rate is not listed in PLLA table
580581 */
drivers/clk/tegra/clk-tegra114.c+25−14
@@ -620,10 +620,6 @@ static const char *mux_plld_out0_plld2_out0[] = { · 619 unmodified lines
620620 };
621621 #define mux_plld_out0_plld2_out0_idx NULL
622622
623−static const char *mux_pllmcp_clkm[] = {
624− "pll_m_out0", "pll_c_out0", "pll_p_out0", "clk_m", "pll_m_ud",
625−};
626−
627623 static const struct clk_div_table pll_re_div_table[] = {
628624 { .val = 0, .div = 1 },
629625 { .val = 1, .div = 2 },
@@ -670,7 +666,6 @@ static struct tegra_clk tegra114_clks[tegra_clk_max] __initdata = { · 40 unmodified lines
670666 [tegra_clk_csi] = { .dt_id = TEGRA114_CLK_CSI, .present = true },
671667 [tegra_clk_i2c2] = { .dt_id = TEGRA114_CLK_I2C2, .present = true },
672668 [tegra_clk_uartc] = { .dt_id = TEGRA114_CLK_UARTC, .present = true },
673− [tegra_clk_emc] = { .dt_id = TEGRA114_CLK_EMC, .present = true },
674669 [tegra_clk_usb2] = { .dt_id = TEGRA114_CLK_USB2, .present = true },
675670 [tegra_clk_usb3] = { .dt_id = TEGRA114_CLK_USB3, .present = true },
676671 [tegra_clk_vde_8] = { .dt_id = TEGRA114_CLK_VDE, .present = true },
@@ -1051,14 +1046,7 @@ static __init void tegra114_periph_clk_init(void __iomem *clk_base, · 374 unmodified lines
10511046 periph_clk_enb_refcnt);
10521047 clks[TEGRA114_CLK_CSUS] = clk;
10531048
1054− /* emc mux */
1055− clk = clk_register_mux(NULL, "emc_mux", mux_pllmcp_clkm,
1056− ARRAY_SIZE(mux_pllmcp_clkm),
1057− CLK_SET_RATE_NO_REPARENT,
1058− clk_base + CLK_SOURCE_EMC,
1059− 29, 3, 0, &emc_lock);
1060−
1061− clk = tegra_clk_register_mc("mc", "emc_mux", clk_base + CLK_SOURCE_EMC,
1049+ clk = tegra_clk_register_mc("mc", "emc", clk_base + CLK_SOURCE_EMC,
10621050 &emc_lock);
10631051 clks[TEGRA114_CLK_MC] = clk;
10641052
@@ -1324,6 +1312,26 @@ static int tegra114_reset_deassert(unsigned long id) · 259 unmodified lines
13241312 return 0;
13251313 }
13261314
1315+static struct clk *tegra114_clk_src_onecell_get(struct of_phandle_args *clkspec,
1316+ void *data)
1317+{
1318+ struct clk_hw *hw;
1319+ struct clk *clk;
1320+
1321+ clk = of_clk_src_onecell_get(clkspec, data);
1322+ if (IS_ERR(clk))
1323+ return clk;
1324+
1325+ hw = __clk_get_hw(clk);
1326+
1327+ if (clkspec->args[0] == TEGRA114_CLK_EMC) {
1328+ if (!tegra124_clk_emc_driver_available(hw))
1329+ return ERR_PTR(-EPROBE_DEFER);
1330+ }
1331+
1332+ return clk;
1333+}
1334+
13271335 static void __init tegra114_clock_init(struct device_node *np)
13281336 {
13291337 struct device_node *node;
@@ -1371,7 +1379,10 @@ static void __init tegra114_clock_init(struct device_node *np) · 41 unmodified lines
13711379 tegra_init_special_resets(1, tegra114_reset_assert,
13721380 tegra114_reset_deassert);
13731381
1374− tegra_add_of_provider(np, of_clk_src_onecell_get);
1382+ tegra_add_of_provider(np, tegra114_clk_src_onecell_get);
1383+ clks[TEGRA114_CLK_EMC] = tegra124_clk_register_emc(clk_base, np,
1384+ &emc_lock);
1385+
13751386 tegra_register_devclks(devclks, ARRAY_SIZE(devclks));
13761387
13771388 tegra_clk_apply_init_table = tegra114_clock_apply_init_table;
drivers/clk/tegra/clk-tegra124-emc.c+1−0
@@ -537,6 +537,7 @@ struct clk *tegra124_clk_register_emc(void __iomem *base, struct device_node *np · 536 unmodified lines
537537
538538 clk = clk_register(NULL, &tegra->hw);
539539 if (IS_ERR(clk)) {
540+ of_node_put(tegra->emc_node);
540541 kfree(tegra);
541542 return clk;
542543 }
drivers/clk/tegra/clk-tegra210.c+1−1
@@ -1460,7 +1460,7 @@ static int tegra210_pllx_dyn_ramp(struct tegra_clk_pll *pllx, · 1459 unmodified lines
14601460 udelay(1);
14611461
14621462 pr_debug("%s: dynamic ramp to m = %u n = %u p = %u, Fout = %lu kHz\n",
1463− __clk_get_name(pllx->hw.clk), cfg->m, cfg->n, cfg->p,
1463+ clk_hw_get_name(&pllx->hw), cfg->m, cfg->n, cfg->p,
14641464 cfg->input_rate / cfg->m * cfg->n /
14651465 pllx->params->pdiv_tohw[cfg->p].pdiv / 1000);
14661466
drivers/clk/ultrarisc/Kconfig+18−0
@@ -0,0 +1,18 @@
1+# SPDX-License-Identifier: GPL-2.0-only
2+
3+config CLK_ULTRARISC
4+ tristate
5+ depends on OF
6+ depends on ARCH_ULTRARISC || COMPILE_TEST
7+
8+config CLK_ULTRARISC_DP1000
9+ tristate "UltraRISC DP1000 clock controller"
10+ select CLK_ULTRARISC
11+ depends on OF && HAS_IOMEM
12+ depends on ARCH_ULTRARISC || COMPILE_TEST
13+ default ARCH_ULTRARISC
14+ help
15+ This driver provides the clock controller for the UltraRISC
16+ DP1000 SoC. It exposes the PLL output, derived fixed-factor
17+ clocks, programmable divider clocks, and peripheral gate
18+ clocks to Linux consumers.
drivers/clk/ultrarisc/Makefile+4−0
@@ -0,0 +1,4 @@
1+# SPDX-License-Identifier: GPL-2.0-only
2+
3+obj-$(CONFIG_CLK_ULTRARISC) += clk-ultrarisc.o
4+obj-$(CONFIG_CLK_ULTRARISC_DP1000) += clk-dp1000.o
drivers/clk/ultrarisc/clk-dp1000.c+154−0
@@ -0,0 +1,154 @@
1+// SPDX-License-Identifier: GPL-2.0-only
2+/*
3+ * Copyright (C) 2026 UltraRISC Technology (Shanghai) Co., Ltd.
4+ */
5+
6+#include <linux/module.h>
7+
8+#include <dt-bindings/clock/ultrarisc,dp1000-clk.h>
9+
10+#include "clk-ultrarisc.h"
11+
12+#define DP1000_PLL_CFG1_OFFSET 0x400
13+#define DP1000_PLL_CFG2_OFFSET 0x404
14+
15+#define DP1000_CCR_UART_OFFSET 0x220
16+#define DP1000_CCR_I2C_OFFSET 0x224
17+#define DP1000_CCR_GMAC_OFFSET 0x228
18+#define DP1000_CCR_SPI_OFFSET 0x22c
19+#define DP1000_PERI_CLKENA_OFFSET 0x270
20+
21+#define DP1000_CCR_LOAD BIT(16)
22+
23+#define DP1000_PERI_MAX_RATE 62500000UL
24+#define DP1000_CLK_NUM 21
25+
26+static const struct ultrarisc_pll_layout dp1000_pll_layout = {
27+ .cfg1_offset = DP1000_PLL_CFG1_OFFSET,
28+ .cfg2_offset = DP1000_PLL_CFG2_OFFSET,
29+ .frac_mask = GENMASK(23, 0),
30+ .m_mask = GENMASK(23, 16),
31+ .n_mask = GENMASK(11, 6),
32+ .oddiv1_mask = GENMASK(1, 0),
33+ .oddiv2_mask = GENMASK(4, 3),
34+};
35+
36+static const struct ultrarisc_pll_desc dp1000_plls[] = {
37+ {
38+ .id = DP1000_CLK_SYSPLL,
39+ .name = "syspll_clk",
40+ },
41+};
42+
43+#define DP1000_FIXED_FACTOR(_id, _name, _parent, _mult, _div) \
44+ { \
45+ .id = (_id), \
46+ .name = (_name), \
47+ .parent_id = (_parent), \
48+ .mult = (_mult), \
49+ .div = (_div), \
50+ }
51+
52+#define DP1000_DIV(_id, _name, _offset, _parent, _max_rate) \
53+ { \
54+ .id = (_id), \
55+ .name = (_name), \
56+ .offset = (_offset), \
57+ .parent_id = (_parent), \
58+ .max_rate = (_max_rate), \
59+ .load_mask = DP1000_CCR_LOAD, \
60+ .div_shift = 8, \
61+ .div_width = 4, \
62+ .gate_bit = 0, \
63+ .divider_flags = CLK_DIVIDER_ONE_BASED, \
64+ .gate_flags = 0, \
65+ }
66+
67+#define DP1000_GATE(_id, _name, _parent, _bit) \
68+ { \
69+ .id = (_id), \
70+ .name = (_name), \
71+ .offset = DP1000_PERI_CLKENA_OFFSET, \
72+ .parent_id = (_parent), \
73+ .gate_bit = (_bit), \
74+ .gate_flags = 0, \
75+ }
76+
77+static const struct ultrarisc_fixed_factor_desc dp1000_fixed_factor_clks[] = {
78+ DP1000_FIXED_FACTOR(DP1000_CLK_SYSPLL_DIV2, "syspll_div2_clk",
79+ DP1000_CLK_SYSPLL, 1, 2),
80+ DP1000_FIXED_FACTOR(DP1000_CLK_SUBSYS, "subsys_clk",
81+ DP1000_CLK_SYSPLL_DIV2, 1, 2),
82+ DP1000_FIXED_FACTOR(DP1000_CLK_PCIE_DBI, "pcie_dbi_clk",
83+ DP1000_CLK_SYSPLL, 1, 10),
84+ DP1000_FIXED_FACTOR(DP1000_CLK_PCIEX4_CORE, "pciex4_core_clk",
85+ DP1000_CLK_SYSPLL, 1, 2),
86+ DP1000_FIXED_FACTOR(DP1000_CLK_PCIEX16_CORE, "pciex16_core_clk",
87+ DP1000_CLK_SYSPLL, 1, 1),
88+ DP1000_FIXED_FACTOR(DP1000_CLK_PCIE_AUX, "pcie_aux_clk",
89+ DP1000_CLK_SYSPLL, 1, 40),
90+};
91+
92+static const struct ultrarisc_divider_desc dp1000_divider_clks[] = {
93+ DP1000_DIV(DP1000_CLK_GMAC, "gmac_clk", DP1000_CCR_GMAC_OFFSET,
94+ DP1000_CLK_SYSPLL_DIV2, 0),
95+ DP1000_DIV(DP1000_CLK_UART_ROOT, "uart_root_clk",
96+ DP1000_CCR_UART_OFFSET, DP1000_CLK_SUBSYS,
97+ DP1000_PERI_MAX_RATE),
98+ DP1000_DIV(DP1000_CLK_I2C_ROOT, "i2c_root_clk",
99+ DP1000_CCR_I2C_OFFSET, DP1000_CLK_SUBSYS,
100+ DP1000_PERI_MAX_RATE),
101+ DP1000_DIV(DP1000_CLK_SPI_ROOT, "spi_root_clk",
102+ DP1000_CCR_SPI_OFFSET, DP1000_CLK_SUBSYS,
103+ DP1000_PERI_MAX_RATE),
104+};
105+
106+static const struct ultrarisc_gate_desc dp1000_gate_clks[] = {
107+ DP1000_GATE(DP1000_CLK_UART0, "uart0_clk", DP1000_CLK_UART_ROOT, 0),
108+ DP1000_GATE(DP1000_CLK_UART1, "uart1_clk", DP1000_CLK_UART_ROOT, 1),
109+ DP1000_GATE(DP1000_CLK_UART2, "uart2_clk", DP1000_CLK_UART_ROOT, 2),
110+ DP1000_GATE(DP1000_CLK_UART3, "uart3_clk", DP1000_CLK_UART_ROOT, 3),
111+ DP1000_GATE(DP1000_CLK_I2C0, "i2c0_clk", DP1000_CLK_I2C_ROOT, 4),
112+ DP1000_GATE(DP1000_CLK_I2C1, "i2c1_clk", DP1000_CLK_I2C_ROOT, 5),
113+ DP1000_GATE(DP1000_CLK_I2C2, "i2c2_clk", DP1000_CLK_I2C_ROOT, 6),
114+ DP1000_GATE(DP1000_CLK_I2C3, "i2c3_clk", DP1000_CLK_I2C_ROOT, 7),
115+ DP1000_GATE(DP1000_CLK_SPI0, "spi0_clk", DP1000_CLK_SPI_ROOT, 8),
116+ DP1000_GATE(DP1000_CLK_SPI1, "spi1_clk", DP1000_CLK_SPI_ROOT, 9),
117+};
118+
119+static const struct ultrarisc_clk_soc_data dp1000_clk_soc_data = {
120+ .num_clks = DP1000_CLK_NUM,
121+ .pll_layout = &dp1000_pll_layout,
122+ .plls = dp1000_plls,
123+ .num_plls = ARRAY_SIZE(dp1000_plls),
124+ .fixed_factors = dp1000_fixed_factor_clks,
125+ .num_fixed_factors = ARRAY_SIZE(dp1000_fixed_factor_clks),
126+ .dividers = dp1000_divider_clks,
127+ .num_dividers = ARRAY_SIZE(dp1000_divider_clks),
128+ .gates = dp1000_gate_clks,
129+ .num_gates = ARRAY_SIZE(dp1000_gate_clks),
130+};
131+
132+static int dp1000_clk_probe(struct platform_device *pdev)
133+{
134+ return ultrarisc_clk_probe(pdev, &dp1000_clk_soc_data);
135+}
136+
137+static const struct of_device_id dp1000_clk_of_match[] = {
138+ { .compatible = "ultrarisc,dp1000-clk" },
139+ { }
140+};
141+MODULE_DEVICE_TABLE(of, dp1000_clk_of_match);
142+
143+static struct platform_driver dp1000_clk_driver = {
144+ .probe = dp1000_clk_probe,
145+ .driver = {
146+ .name = "ultrarisc-dp1000-clk",
147+ .of_match_table = dp1000_clk_of_match,
148+ },
149+};
150+module_platform_driver(dp1000_clk_driver);
151+
152+MODULE_IMPORT_NS("CLK_ULTRARISC");
153+MODULE_DESCRIPTION("UltraRISC DP1000 clock controller");
154+MODULE_LICENSE("GPL");
drivers/clk/ultrarisc/clk-ultrarisc.c+399−0
@@ -0,0 +1,399 @@
1+// SPDX-License-Identifier: GPL-2.0-only
2+/*
3+ * Copyright (C) 2026 UltraRISC Technology (Shanghai) Co., Ltd.
4+ */
5+
6+#include <linux/bitfield.h>
7+#include <linux/clk-provider.h>
8+#include <linux/io.h>
9+#include <linux/math64.h>
10+#include <linux/module.h>
11+#include <linux/platform_device.h>
12+
13+#include "clk-ultrarisc.h"
14+
15+struct ultrarisc_pll_clk {
16+ struct clk_hw hw;
17+ void __iomem *base;
18+ const struct ultrarisc_pll_layout *layout;
19+};
20+
21+struct ultrarisc_divider_clk {
22+ struct clk_divider divider;
23+ struct clk_gate gate;
24+ u32 load_mask;
25+};
26+
27+#define to_ultrarisc_pll_clk(_hw) \
28+ container_of(_hw, struct ultrarisc_pll_clk, hw)
29+
30+static inline struct ultrarisc_divider_clk *to_ultrarisc_divider_clk(struct clk_hw *hw)
31+{
32+ struct clk_divider *divider = to_clk_divider(hw);
33+
34+ return container_of(divider, struct ultrarisc_divider_clk, divider);
35+}
36+
37+static unsigned long ultrarisc_pll_recalc_rate(struct clk_hw *hw,
38+ unsigned long parent_rate)
39+{
40+ struct ultrarisc_pll_clk *pll = to_ultrarisc_pll_clk(hw);
41+ const struct ultrarisc_pll_layout *layout = pll->layout;
42+ u32 oddiv1_div, oddiv2_div;
43+ u64 mult, rate, den;
44+ u32 frac, m, n;
45+ u32 cfg1, cfg2;
46+
47+ cfg1 = readl_relaxed(pll->base + layout->cfg1_offset);
48+ cfg2 = readl_relaxed(pll->base + layout->cfg2_offset);
49+
50+ frac = field_get(layout->frac_mask, cfg1);
51+ m = field_get(layout->m_mask, cfg2);
52+ n = field_get(layout->n_mask, cfg2);
53+ if (!n)
54+ return 0;
55+
56+ oddiv1_div = 1U << field_get(layout->oddiv1_mask, cfg2);
57+ oddiv2_div = 1U << field_get(layout->oddiv2_mask, cfg2);
58+
59+ /*
60+ * The output frequency is calculated as:
61+ * fvco = parent * (m + frac / 2^24) / n
62+ * fout = fvco / (2^oddiv1_raw * 2^oddiv2_raw)
63+ *
64+ * The output divider values are derived from the raw register field values as:
65+ * oddivX_div = 1 << oddivX_raw
66+ */
67+ mult = ((u64)m << 24) + frac;
68+ rate = (u64)parent_rate * mult;
69+ den = ((u64)n << 24) * oddiv1_div * oddiv2_div;
70+
71+ return div64_u64(rate + (den >> 1), den);
72+}
73+
74+static const struct clk_ops ultrarisc_pll_ro_ops = {
75+ .recalc_rate = ultrarisc_pll_recalc_rate,
76+};
77+
78+static unsigned long ultrarisc_divider_recalc_rate(struct clk_hw *hw,
79+ unsigned long parent_rate)
80+{
81+ struct clk_divider *divider = to_clk_divider(hw);
82+ u32 val;
83+
84+ val = readl_relaxed(divider->reg) >> divider->shift;
85+ val &= clk_div_mask(divider->width);
86+
87+ return divider_recalc_rate(hw, parent_rate, val, divider->table,
88+ divider->flags, divider->width);
89+}
90+
91+static int ultrarisc_divider_determine_rate(struct clk_hw *hw,
92+ struct clk_rate_request *req)
93+{
94+ struct clk_divider *divider = to_clk_divider(hw);
95+
96+ return divider_determine_rate(hw, req, divider->table, divider->width,
97+ divider->flags);
98+}
99+
100+static int ultrarisc_divider_set_rate(struct clk_hw *hw, unsigned long rate,
101+ unsigned long parent_rate)
102+{
103+ struct ultrarisc_divider_clk *divider_clk = to_ultrarisc_divider_clk(hw);
104+ struct clk_divider *divider = &divider_clk->divider;
105+ int value;
106+ u32 val;
107+
108+ value = divider_get_val(rate, parent_rate, divider->table,
109+ divider->width, divider->flags);
110+ if (value < 0)
111+ return value;
112+
113+ scoped_guard(spinlock_irqsave, divider->lock) {
114+ val = readl_relaxed(divider->reg);
115+ val &= ~(clk_div_mask(divider->width) << divider->shift);
116+ val |= value << divider->shift;
117+ writel_relaxed(val, divider->reg);
118+
119+ if (divider_clk->load_mask) {
120+ /*
121+ * Program the new divider field, then write 1 to the
122+ * load bit to trigger the update. The load bit is
123+ * write-triggered and reads back as 0 on this hardware.
124+ */
125+ writel_relaxed(val | divider_clk->load_mask, divider->reg);
126+ }
127+ }
128+
129+ return 0;
130+}
131+
132+static const struct clk_ops ultrarisc_divider_ops = {
133+ .recalc_rate = ultrarisc_divider_recalc_rate,
134+ .determine_rate = ultrarisc_divider_determine_rate,
135+ .set_rate = ultrarisc_divider_set_rate,
136+};
137+
138+static struct clk_hw *ultrarisc_clk_register_pll(struct device *dev,
139+ const struct ultrarisc_pll_desc *desc,
140+ const struct ultrarisc_pll_layout *layout,
141+ void __iomem *base)
142+{
143+ struct clk_parent_data pdata = { .index = 0 };
144+ struct ultrarisc_pll_clk *pll;
145+ struct clk_init_data init = {
146+ .name = desc->name,
147+ .ops = &ultrarisc_pll_ro_ops,
148+ .parent_data = &pdata,
149+ .num_parents = 1,
150+ .flags = CLK_GET_RATE_NOCACHE,
151+ };
152+ int ret;
153+
154+ pll = devm_kzalloc(dev, sizeof(*pll), GFP_KERNEL);
155+ if (!pll)
156+ return ERR_PTR(-ENOMEM);
157+
158+ pll->base = base;
159+ pll->layout = layout;
160+ pll->hw.init = &init;
161+
162+ ret = devm_clk_hw_register(dev, &pll->hw);
163+ if (ret)
164+ return ERR_PTR(ret);
165+
166+ return &pll->hw;
167+}
168+
169+static struct clk_hw *
170+ultrarisc_clk_register_divider(struct device *dev,
171+ const struct ultrarisc_divider_desc *desc,
172+ struct clk_hw *parent_hw, void __iomem *base,
173+ spinlock_t *lock)
174+{
175+ const struct clk_parent_data pdata = { .hw = parent_hw };
176+ void __iomem *reg = base + desc->offset;
177+ struct ultrarisc_divider_clk *divider;
178+
179+ if (!desc->div_width)
180+ return ERR_PTR(-EINVAL);
181+
182+ if (!lock)
183+ return ERR_PTR(-EINVAL);
184+
185+ divider = devm_kzalloc(dev, sizeof(*divider), GFP_KERNEL);
186+ if (!divider)
187+ return ERR_PTR(-ENOMEM);
188+
189+ divider->divider.reg = reg;
190+ divider->divider.shift = desc->div_shift;
191+ divider->divider.width = desc->div_width;
192+ divider->divider.flags = desc->divider_flags;
193+ divider->divider.lock = lock;
194+ divider->load_mask = desc->load_mask;
195+ divider->gate.reg = reg;
196+ divider->gate.bit_idx = desc->gate_bit;
197+ divider->gate.flags = desc->gate_flags;
198+ divider->gate.lock = lock;
199+
200+ return devm_clk_hw_register_composite_pdata(dev, desc->name,
201+ &pdata, 1, NULL, NULL,
202+ &divider->divider.hw,
203+ &ultrarisc_divider_ops,
204+ &divider->gate.hw,
205+ &clk_gate_ops, 0);
206+}
207+
208+static int ultrarisc_clk_register_fixed_factors(struct device *dev,
209+ struct clk_hw_onecell_data *clk_data,
210+ const struct ultrarisc_clk_soc_data *soc_data)
211+{
212+ u32 i;
213+
214+ for (i = 0; i < soc_data->num_fixed_factors; i++) {
215+ const struct ultrarisc_fixed_factor_desc *desc;
216+ struct clk_hw *parent_hw;
217+ struct clk_hw *hw;
218+
219+ desc = &soc_data->fixed_factors[i];
220+ if (desc->id >= clk_data->num || desc->parent_id >= clk_data->num)
221+ return -EINVAL;
222+
223+ parent_hw = clk_data->hws[desc->parent_id];
224+ if (!parent_hw)
225+ return -EINVAL;
226+
227+ hw = devm_clk_hw_register_fixed_factor_parent_hw(dev, desc->name,
228+ parent_hw, 0,
229+ desc->mult,
230+ desc->div);
231+ if (IS_ERR(hw))
232+ return PTR_ERR(hw);
233+
234+ clk_data->hws[desc->id] = hw;
235+ }
236+
237+ return 0;
238+}
239+
240+static int ultrarisc_clk_register_plls(struct platform_device *pdev,
241+ struct clk_hw_onecell_data *clk_data,
242+ const struct ultrarisc_clk_soc_data *soc_data,
243+ void __iomem *base)
244+{
245+ struct device *dev = &pdev->dev;
246+ u32 i;
247+
248+ for (i = 0; i < soc_data->num_plls; i++) {
249+ const struct ultrarisc_pll_desc *desc = &soc_data->plls[i];
250+ struct clk_hw *hw;
251+
252+ if (desc->id >= clk_data->num) {
253+ dev_err(dev, "%s invalid clock ID %u >= %u\n",
254+ desc->name, desc->id, clk_data->num);
255+ return -EINVAL;
256+ }
257+
258+ hw = ultrarisc_clk_register_pll(dev, desc, soc_data->pll_layout, base);
259+ if (IS_ERR(hw))
260+ return PTR_ERR(hw);
261+
262+ clk_data->hws[desc->id] = hw;
263+ }
264+
265+ return 0;
266+}
267+
268+static int ultrarisc_clk_register_dividers(struct platform_device *pdev,
269+ struct clk_hw_onecell_data *clk_data,
270+ const struct ultrarisc_clk_soc_data *soc_data,
271+ void __iomem *base,
272+ spinlock_t *lock)
273+{
274+ struct device *dev = &pdev->dev;
275+ u32 i;
276+
277+ for (i = 0; i < soc_data->num_dividers; i++) {
278+ const struct ultrarisc_divider_desc *desc;
279+ struct clk_hw *parent_hw;
280+ struct clk_hw *hw;
281+
282+ desc = &soc_data->dividers[i];
283+ if (desc->id >= clk_data->num || desc->parent_id >= clk_data->num)
284+ return -EINVAL;
285+
286+ parent_hw = clk_data->hws[desc->parent_id];
287+ if (!parent_hw)
288+ return -EINVAL;
289+
290+ hw = ultrarisc_clk_register_divider(dev, desc, parent_hw, base,
291+ lock);
292+ if (IS_ERR(hw))
293+ return PTR_ERR(hw);
294+
295+ if (desc->max_rate)
296+ clk_hw_set_rate_range(hw, 0, desc->max_rate);
297+
298+ clk_data->hws[desc->id] = hw;
299+ }
300+
301+ return 0;
302+}
303+
304+static int ultrarisc_clk_register_gates(struct platform_device *pdev,
305+ struct clk_hw_onecell_data *clk_data,
306+ const struct ultrarisc_clk_soc_data *soc_data,
307+ void __iomem *base,
308+ spinlock_t *lock)
309+{
310+ struct device *dev = &pdev->dev;
311+ u32 i;
312+
313+ for (i = 0; i < soc_data->num_gates; i++) {
314+ const struct ultrarisc_gate_desc *desc;
315+ struct clk_hw *parent_hw;
316+ struct clk_hw *hw;
317+
318+ desc = &soc_data->gates[i];
319+ if (desc->id >= clk_data->num || desc->parent_id >= clk_data->num)
320+ return -EINVAL;
321+
322+ parent_hw = clk_data->hws[desc->parent_id];
323+ if (!parent_hw)
324+ return -EINVAL;
325+
326+ hw = devm_clk_hw_register_gate_parent_hw(dev, desc->name,
327+ parent_hw, 0,
328+ base + desc->offset,
329+ desc->gate_bit,
330+ desc->gate_flags,
331+ lock);
332+ if (IS_ERR(hw))
333+ return PTR_ERR(hw);
334+
335+ clk_data->hws[desc->id] = hw;
336+ }
337+
338+ return 0;
339+}
340+
341+int ultrarisc_clk_probe(struct platform_device *pdev,
342+ const struct ultrarisc_clk_soc_data *soc_data)
343+{
344+ struct clk_hw_onecell_data *clk_data;
345+ struct device *dev = &pdev->dev;
346+ void __iomem *base;
347+ spinlock_t *lock;
348+ int ret;
349+
350+ if (!soc_data)
351+ return -EINVAL;
352+
353+ lock = devm_kzalloc(dev, sizeof(*lock), GFP_KERNEL);
354+ if (!lock)
355+ return -ENOMEM;
356+
357+ spin_lock_init(lock);
358+
359+ clk_data = devm_kzalloc(dev, struct_size(clk_data, hws,
360+ soc_data->num_clks),
361+ GFP_KERNEL);
362+ if (!clk_data)
363+ return -ENOMEM;
364+
365+ clk_data->num = soc_data->num_clks;
366+
367+ base = devm_platform_ioremap_resource(pdev, 0);
368+ if (IS_ERR(base))
369+ return PTR_ERR(base);
370+
371+ ret = ultrarisc_clk_register_plls(pdev, clk_data, soc_data, base);
372+ if (ret)
373+ return ret;
374+
375+ ret = ultrarisc_clk_register_fixed_factors(dev, clk_data, soc_data);
376+ if (ret)
377+ return ret;
378+
379+ ret = ultrarisc_clk_register_dividers(pdev, clk_data, soc_data, base, lock);
380+ if (ret)
381+ return ret;
382+
383+ ret = ultrarisc_clk_register_gates(pdev, clk_data, soc_data, base, lock);
384+ if (ret)
385+ return ret;
386+
387+ for (int i = 0; i < clk_data->num; i++) {
388+ if (!clk_data->hws[i]) {
389+ dev_err(dev, "missing clock ID %u\n", i);
390+ return -EINVAL;
391+ }
392+ }
393+
394+ return devm_of_clk_add_hw_provider(dev, of_clk_hw_onecell_get, clk_data);
395+}
396+EXPORT_SYMBOL_NS_GPL(ultrarisc_clk_probe, "CLK_ULTRARISC");
397+
398+MODULE_DESCRIPTION("UltraRISC clock core driver");
399+MODULE_LICENSE("GPL");
drivers/clk/ultrarisc/clk-ultrarisc.h+71−0
@@ -0,0 +1,71 @@
1+/* SPDX-License-Identifier: GPL-2.0-only */
2+#ifndef __ULTRARISC_CLK_ULTRARISC_H
3+#define __ULTRARISC_CLK_ULTRARISC_H
4+
5+#include <linux/clk-provider.h>
6+#include <linux/platform_device.h>
7+#include <linux/types.h>
8+
9+struct ultrarisc_pll_layout {
10+ u32 cfg1_offset;
11+ u32 cfg2_offset;
12+ u32 frac_mask;
13+ u32 m_mask;
14+ u32 n_mask;
15+ u32 oddiv1_mask;
16+ u32 oddiv2_mask;
17+};
18+
19+struct ultrarisc_pll_desc {
20+ u32 id;
21+ const char *name;
22+};
23+
24+struct ultrarisc_fixed_factor_desc {
25+ u32 id;
26+ const char *name;
27+ u32 parent_id;
28+ u32 mult;
29+ u32 div;
30+};
31+
32+struct ultrarisc_divider_desc {
33+ u32 id;
34+ const char *name;
35+ u32 offset;
36+ u32 parent_id;
37+ unsigned long max_rate;
38+ u32 load_mask;
39+ u8 div_shift;
40+ u8 div_width;
41+ u8 gate_bit;
42+ u16 divider_flags;
43+ u8 gate_flags;
44+};
45+
46+struct ultrarisc_gate_desc {
47+ u32 id;
48+ const char *name;
49+ u32 offset;
50+ u32 parent_id;
51+ u8 gate_bit;
52+ u8 gate_flags;
53+};
54+
55+struct ultrarisc_clk_soc_data {
56+ const struct ultrarisc_pll_layout *pll_layout;
57+ const struct ultrarisc_pll_desc *plls;
58+ u32 num_plls;
59+ const struct ultrarisc_fixed_factor_desc *fixed_factors;
60+ u32 num_fixed_factors;
61+ const struct ultrarisc_divider_desc *dividers;
62+ u32 num_dividers;
63+ const struct ultrarisc_gate_desc *gates;
64+ u32 num_gates;
65+ u32 num_clks;
66+};
67+
68+int ultrarisc_clk_probe(struct platform_device *pdev,
69+ const struct ultrarisc_clk_soc_data *soc_data);
70+
71+#endif /* __ULTRARISC_CLK_ULTRARISC_H */
drivers/clk/x86/clk-pmc-atom.c+3−0
@@ -160,6 +160,9 @@ static struct clk_plt *plt_clk_register(struct platform_device *pdev, int id, · 159 unmodified lines
160160 return ERR_PTR(-ENOMEM);
161161
162162 init.name = kasprintf(GFP_KERNEL, "%s_%d", PLT_CLK_NAME_BASE, id);
163+ if (!init.name)
164+ return ERR_PTR(-ENOMEM);
165+
163166 init.ops = &plt_clk_ops;
164167 init.flags = 0;
165168 init.parent_names = parent_names;
drivers/clk/xilinx/clk-xlnx-clock-wizard.c+139−3
@@ -35,6 +35,10 @@ · 34 unmodified lines
3535 #define WZRD_DIVCLK 21
3636 #define WZRD_CLKFBOUT_4 51
3737 #define WZRD_CLKFBOUT_3 48
38+#define WZRD_CP 18
39+#define WZRD_LOCK 27
40+#define WZRD_LOCK_REF_DLY 28
41+#define WZRD_RES 30
3842 #define WZRD_DUTY_CYCLE 2
3943 #define WZRD_O_DIV 4
4044
@@ -49,6 +53,10 @@ · 8 unmodified lines
4953 #define WZRD_P5FEDGE_SHIFT 15
5054 #define WZRD_CLKOUT0_PREDIV2 BIT(11)
5155 #define WZRD_EDGE_SHIFT 8
56+#define WZRD_CP_MASK GENMASK(3, 0)
57+#define WZRD_RES_MASK GENMASK(4, 1)
58+#define WZRD_LOCK_FB_DLY_MASK GENMASK(14, 10)
59+#define WZRD_LOCK_REF_DLY_LOCK_REF_DLY_MASK GENMASK(14, 10)
5260
5361 #define WZRD_CLKFBOUT_MULT_SHIFT 8
5462 #define WZRD_CLKFBOUT_MULT_MASK (0xff << WZRD_CLKFBOUT_MULT_SHIFT)
@@ -105,7 +113,6 @@ · 50 unmodified lines
105113 #define VER_WZRD_VCO_MAX 4320000000ULL
106114 #define VER_WZRD_O_MIN 2
107115 #define VER_WZRD_O_MAX 511
108−#define WZRD_MIN_ERR 20000
109116 #define WZRD_FRAC_POINTS 1000
110117
111118 /* Get the mask from width */
@@ -406,7 +413,7 @@ static int clk_wzrd_get_divisors(struct clk_hw *hw, unsigned long rate, · 294 unmodified lines
406413 if (o < omin || o > omax)
407414 continue;
408415 freq = DIV_ROUND_CLOSEST_ULL(vco_freq, o);
409− diff = freq - rate;
416+ diff = abs(freq - rate);
410417 if (diff < best_diff) {
411418 best_diff = diff;
412419 divider->m = m >> 3;
@@ -414,10 +421,13 @@ static int clk_wzrd_get_divisors(struct clk_hw *hw, unsigned long rate, · 1 unmodified line
414421 divider->d = d;
415422 divider->o = o >> 3;
416423 divider->o_frac = (o - (divider->o << 3)) * 125;
424+
425+ if (!diff)
426+ return 0;
417427 }
418428 }
419429 }
420− return best_diff < WZRD_MIN_ERR ? 0 : -EBUSY;
430+ return best_diff != -1ULL ? 0 : -EBUSY;
421431 }
422432
423433 static int clk_wzrd_reconfig(struct clk_wzrd_divider *divider, void __iomem *div_addr)
@@ -440,6 +450,130 @@ static int clk_wzrd_reconfig(struct clk_wzrd_divider *divider, void __iomem *div · 16 unmodified lines
440450 WZRD_USEC_POLL, WZRD_TIMEOUT_POLL);
441451 }
442452
453+struct wzrd_pll_filter {
454+ u32 m_min;
455+ u32 m_max;
456+ u32 cp;
457+ u32 res;
458+};
459+
460+static const struct wzrd_pll_filter wzrd_cp_res_table[] = {
461+ { 4, 4, 5, 15 },
462+ { 5, 5, 6, 15 },
463+ { 6, 6, 7, 15 },
464+ { 7, 7, 13, 15 },
465+ { 8, 8, 14, 15 },
466+ { 9, 9, 15, 15 },
467+ { 10, 10, 14, 7 },
468+ { 11, 11, 15, 7 },
469+ { 12, 13, 15, 11 },
470+ { 14, 14, 15, 13 },
471+ { 15, 15, 15, 3 },
472+ { 16, 17, 14, 5 },
473+ { 18, 19, 15, 5 },
474+ { 20, 21, 15, 9 },
475+ { 22, 23, 14, 14 },
476+ { 24, 26, 15, 14 },
477+ { 27, 28, 14, 1 },
478+ { 29, 33, 15, 1 },
479+ { 34, 37, 14, 6 },
480+ { 38, 44, 15, 6 },
481+ { 45, 57, 15, 10 },
482+ { 58, 63, 13, 12 },
483+ { 64, 70, 14, 12 },
484+ { 71, 86, 15, 12 },
485+ { 87, 94, 14, 2 },
486+ { 95, 145, 15, 2 },
487+ { 146, 163, 12, 4 },
488+ { 164, 181, 13, 4 },
489+ { 182, 200, 14, 4 },
490+ { 201, 273, 15, 4 },
491+ { 274, 300, 13, 8 },
492+ { 301, 325, 14, 8 },
493+ { 326, 432, 15, 8 },
494+};
495+
496+struct wzrd_lock_timing {
497+ u32 m_min;
498+ u32 m_max;
499+ u32 ref_dly;
500+ u32 fb_dly;
501+ u32 lock_cnt;
502+};
503+
504+static const struct wzrd_lock_timing wzrd_lock_table[] = {
505+ { 4, 4, 4, 4, 1000 },
506+ { 5, 5, 6, 6, 1000 },
507+ { 6, 8, 7, 7, 1000 },
508+ { 9, 12, 8, 8, 1000 },
509+ { 13, 13, 10, 10, 1000 },
510+ { 14, 16, 13, 13, 1000 },
511+ { 17, 17, 16, 16, 825 },
512+ { 18, 18, 16, 16, 750 },
513+ { 19, 20, 16, 16, 700 },
514+ { 21, 21, 16, 16, 650 },
515+ { 22, 23, 16, 16, 625 },
516+ { 24, 24, 16, 16, 575 },
517+ { 25, 25, 16, 16, 550 },
518+ { 26, 28, 16, 16, 525 },
519+ { 29, 30, 16, 16, 475 },
520+ { 31, 31, 16, 16, 450 },
521+ { 32, 33, 16, 16, 425 },
522+ { 34, 36, 16, 16, 400 },
523+ { 37, 37, 16, 16, 375 },
524+ { 38, 40, 16, 16, 350 },
525+ { 41, 43, 16, 16, 325 },
526+ { 44, 47, 16, 16, 300 },
527+ { 48, 51, 16, 16, 275 },
528+ { 52, 205, 16, 16, 250 },
529+ { 206, 432, 16, 16, 225 },
530+};
531+
532+static void clk_wzrd_update_cp_res_lock(struct clk_wzrd_divider *divider, u32 m)
533+{
534+ u32 lock_ref_dly = 16, lock_fb_dly = 16, lock_cnt = 250, cp = 15, res = 15;
535+ void __iomem *base = divider->base;
536+ u32 reg;
537+ int i;
538+
539+ for (i = 0; i < ARRAY_SIZE(wzrd_cp_res_table); i++) {
540+ if (m >= wzrd_cp_res_table[i].m_min &&
541+ m <= wzrd_cp_res_table[i].m_max) {
542+ cp = wzrd_cp_res_table[i].cp;
543+ res = wzrd_cp_res_table[i].res;
544+ break;
545+ }
546+ }
547+
548+ for (i = 0; i < ARRAY_SIZE(wzrd_lock_table); i++) {
549+ if (m >= wzrd_lock_table[i].m_min &&
550+ m <= wzrd_lock_table[i].m_max) {
551+ lock_ref_dly = wzrd_lock_table[i].ref_dly;
552+ lock_fb_dly = wzrd_lock_table[i].fb_dly;
553+ lock_cnt = wzrd_lock_table[i].lock_cnt;
554+ break;
555+ }
556+ }
557+
558+ reg = readl(base + WZRD_CLK_CFG_REG(1, WZRD_CP));
559+ reg &= ~WZRD_CP_MASK;
560+ reg |= FIELD_PREP(WZRD_CP_MASK, cp);
561+ writel(reg, base + WZRD_CLK_CFG_REG(1, WZRD_CP));
562+
563+ reg = readl(base + WZRD_CLK_CFG_REG(1, WZRD_RES));
564+ reg &= ~WZRD_RES_MASK;
565+ reg |= FIELD_PREP(WZRD_RES_MASK, res);
566+ writel(reg, base + WZRD_CLK_CFG_REG(1, WZRD_RES));
567+
568+ reg = lock_cnt | FIELD_PREP(WZRD_LOCK_FB_DLY_MASK, lock_fb_dly);
569+ writel(reg, base + WZRD_CLK_CFG_REG(1, WZRD_LOCK));
570+
571+ reg = readl(base + WZRD_CLK_CFG_REG(1, WZRD_LOCK_REF_DLY));
572+ reg &= ~WZRD_LOCK_REF_DLY_LOCK_REF_DLY_MASK;
573+ reg |= FIELD_PREP(WZRD_LOCK_REF_DLY_LOCK_REF_DLY_MASK, lock_ref_dly);
574+ writel(reg, base + WZRD_CLK_CFG_REG(1, WZRD_LOCK_REF_DLY));
575+}
576+
443577 static int clk_wzrd_dynamic_ver_all_nolock(struct clk_hw *hw, unsigned long rate,
444578 unsigned long parent_rate)
445579 {
@@ -471,6 +605,8 @@ static int clk_wzrd_dynamic_ver_all_nolock(struct clk_hw *hw, unsigned long rate · 25 unmodified lines
471605 writel(regval1, divider->base + WZRD_CLK_CFG_REG(1,
472606 WZRD_CLKFBOUT_2));
473607
608+ clk_wzrd_update_cp_res_lock(divider, m);
609+
474610 value2 = divider->d;
475611 edged = value2 % WZRD_DUTY_CYCLE;
476612 regh = (value2 / WZRD_DUTY_CYCLE);
drivers/reset/Kconfig+13−0
@@ -311,6 +311,19 @@ config RESET_SKY1 · 310 unmodified lines
311311 help
312312 This enables the reset controller for Cix Sky1.
313313
314+config RESET_SKY1_AUDSS
315+ tristate "Cix Sky1 Audio Subsystem reset controller"
316+ depends on ARCH_CIX || COMPILE_TEST
317+ select AUXILIARY_BUS
318+ default CLK_SKY1_AUDSS
319+ help
320+ Support for block-level software reset lines in the Cix Sky1
321+ Audio Subsystem (AUDSS) Clock and Reset Unit. Sixteen reset
322+ outputs for audio peripherals are controlled through the CRU
323+ register map. The driver binds as an auxiliary device from
324+ the AUDSS clock driver. Say M or Y here if you want to build
325+ this driver.
326+
314327 config RESET_SOCFPGA
315328 bool "SoCFPGA Reset Driver" if COMPILE_TEST && (!ARM || !ARCH_INTEL_SOCFPGA)
316329 default ARM && ARCH_INTEL_SOCFPGA
drivers/reset/Makefile+1−0
@@ -40,6 +40,7 @@ obj-$(CONFIG_RESET_RZV2H_USB2PHY) += reset-rzv2h-usb2phy.o · 39 unmodified lines
4040 obj-$(CONFIG_RESET_SCMI) += reset-scmi.o
4141 obj-$(CONFIG_RESET_SIMPLE) += reset-simple.o
4242 obj-$(CONFIG_RESET_SKY1) += reset-sky1.o
43+obj-$(CONFIG_RESET_SKY1_AUDSS) += reset-sky1-audss.o
4344 obj-$(CONFIG_RESET_SOCFPGA) += reset-socfpga.o
4445 obj-$(CONFIG_RESET_SUNPLUS) += reset-sunplus.o
4546 obj-$(CONFIG_RESET_SUNXI) += reset-sunxi.o
drivers/reset/reset-sky1-audss.c+127−0
@@ -0,0 +1,127 @@
1+// SPDX-License-Identifier: GPL-2.0-only
2+/*
3+ * Cix Sky1 Audio Subsystem reset controller driver
4+ *
5+ * Copyright 2026 Cix Technology Group Co., Ltd.
6+ */
7+
8+#include <dt-bindings/reset/cix,sky1-audss-cru.h>
9+
10+#include <linux/auxiliary_bus.h>
11+#include <linux/delay.h>
12+#include <linux/device.h>
13+#include <linux/module.h>
14+#include <linux/regmap.h>
15+#include <linux/reset-controller.h>
16+
17+#define SKY1_RESET_SLEEP_US 50
18+
19+#define AUDSS_SW_RST 0x78
20+
21+struct sky1_audss_reset_map {
22+ unsigned int offset;
23+ unsigned int mask;
24+};
25+
26+struct sky1_audss_reset {
27+ struct reset_controller_dev rcdev;
28+ struct regmap *regmap;
29+ const struct sky1_audss_reset_map *map;
30+};
31+
32+static const struct sky1_audss_reset_map sky1_audss_reset_map[] = {
33+ [AUDSS_I2S0_SW_RST] = { AUDSS_SW_RST, BIT(0) },
34+ [AUDSS_I2S1_SW_RST] = { AUDSS_SW_RST, BIT(1) },
35+ [AUDSS_I2S2_SW_RST] = { AUDSS_SW_RST, BIT(2) },
36+ [AUDSS_I2S3_SW_RST] = { AUDSS_SW_RST, BIT(3) },
37+ [AUDSS_I2S4_SW_RST] = { AUDSS_SW_RST, BIT(4) },
38+ [AUDSS_I2S5_SW_RST] = { AUDSS_SW_RST, BIT(5) },
39+ [AUDSS_I2S6_SW_RST] = { AUDSS_SW_RST, BIT(6) },
40+ [AUDSS_I2S7_SW_RST] = { AUDSS_SW_RST, BIT(7) },
41+ [AUDSS_I2S8_SW_RST] = { AUDSS_SW_RST, BIT(8) },
42+ [AUDSS_I2S9_SW_RST] = { AUDSS_SW_RST, BIT(9) },
43+ [AUDSS_WDT_SW_RST] = { AUDSS_SW_RST, BIT(10) },
44+ [AUDSS_TIMER_SW_RST] = { AUDSS_SW_RST, BIT(11) },
45+ [AUDSS_MB0_SW_RST] = { AUDSS_SW_RST, BIT(12) },
46+ [AUDSS_MB1_SW_RST] = { AUDSS_SW_RST, BIT(13) },
47+ [AUDSS_HDA_SW_RST] = { AUDSS_SW_RST, BIT(14) },
48+ [AUDSS_DMAC_SW_RST] = { AUDSS_SW_RST, BIT(15) },
49+};
50+
51+static struct sky1_audss_reset *to_sky1_audss_reset(struct reset_controller_dev *rcdev)
52+{
53+ return container_of(rcdev, struct sky1_audss_reset, rcdev);
54+}
55+
56+static int sky1_audss_reset_set(struct reset_controller_dev *rcdev,
57+ unsigned long id, bool assert)
58+{
59+ struct sky1_audss_reset *priv = to_sky1_audss_reset(rcdev);
60+ const struct sky1_audss_reset_map *signal = &priv->map[id];
61+ int ret;
62+
63+ ret = regmap_assign_bits(priv->regmap, signal->offset,
64+ signal->mask, !assert);
65+ if (ret)
66+ return ret;
67+
68+ fsleep(SKY1_RESET_SLEEP_US);
69+ return 0;
70+}
71+
72+static int sky1_audss_reset_assert(struct reset_controller_dev *rcdev,
73+ unsigned long id)
74+{
75+ return sky1_audss_reset_set(rcdev, id, true);
76+}
77+
78+static int sky1_audss_reset_deassert(struct reset_controller_dev *rcdev,
79+ unsigned long id)
80+{
81+ return sky1_audss_reset_set(rcdev, id, false);
82+}
83+
84+static const struct reset_control_ops sky1_audss_reset_ops = {
85+ .assert = sky1_audss_reset_assert,
86+ .deassert = sky1_audss_reset_deassert,
87+};
88+
89+static int sky1_audss_reset_probe(struct auxiliary_device *adev,
90+ const struct auxiliary_device_id *id)
91+{
92+ struct sky1_audss_reset *priv;
93+ struct device *dev = &adev->dev;
94+
95+ priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
96+ if (!priv)
97+ return -ENOMEM;
98+
99+ priv->regmap = dev_get_regmap(dev->parent, NULL);
100+ if (!priv->regmap)
101+ return dev_err_probe(dev, -ENODEV, "failed to get parent regmap\n");
102+
103+ priv->map = sky1_audss_reset_map;
104+ priv->rcdev.owner = THIS_MODULE;
105+ priv->rcdev.nr_resets = ARRAY_SIZE(sky1_audss_reset_map);
106+ priv->rcdev.ops = &sky1_audss_reset_ops;
107+ priv->rcdev.of_node = dev->of_node;
108+ priv->rcdev.dev = dev;
109+
110+ return devm_reset_controller_register(dev, &priv->rcdev);
111+}
112+
113+static const struct auxiliary_device_id sky1_audss_reset_ids[] = {
114+ { .name = "clk_sky1_audss.reset" },
115+ { }
116+};
117+MODULE_DEVICE_TABLE(auxiliary, sky1_audss_reset_ids);
118+
119+static struct auxiliary_driver sky1_audss_reset_driver = {
120+ .probe = sky1_audss_reset_probe,
121+ .id_table = sky1_audss_reset_ids,
122+};
123+module_auxiliary_driver(sky1_audss_reset_driver);
124+
125+MODULE_AUTHOR("Joakim Zhang <joakim.zhang@cixtech.com>");
126+MODULE_DESCRIPTION("Cix Sky1 Audio Subsystem reset driver");
127+MODULE_LICENSE("GPL");
include/dt-bindings/clock/aspeed,ast2700-scu.h+2−0
@@ -163,5 +163,7 @@ · 162 unmodified lines
163163 #define SCU1_CLK_GATE_PORTDUSB2CLK 85
164164 #define SCU1_CLK_GATE_LTPI1TXCLK 86
165165 #define SCU1_CLK_I3C 87
166+#define SCU1_CLK_HPLL_DIV4 88
167+#define SCU1_CLK_PECI 89
166168
167169 #endif
include/dt-bindings/clock/cix,sky1-audss-cru.h+60−0
@@ -0,0 +1,60 @@
1+/* SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) */
2+/*
3+ * Copyright 2026 Cix Technology Group Co., Ltd.
4+ */
5+
6+#ifndef _DT_BINDINGS_CLOCK_CIX_SKY1_AUDSS_CRU_H
7+#define _DT_BINDINGS_CLOCK_CIX_SKY1_AUDSS_CRU_H
8+
9+#define CLK_AUD_CLK4_DIV2 0
10+#define CLK_AUD_CLK4_DIV4 1
11+#define CLK_AUD_CLK5_DIV2 2
12+
13+#define CLK_DSP_CLK 3
14+#define CLK_DSP_BCLK 4
15+#define CLK_DSP_PBCLK 5
16+
17+#define CLK_SRAM_AXI 6
18+
19+#define CLK_HDA_SYS 7
20+#define CLK_HDA_HDA 8
21+
22+#define CLK_DMAC_AXI 9
23+
24+#define CLK_WDG_APB 10
25+#define CLK_WDG_WDG 11
26+
27+#define CLK_TIMER_APB 12
28+#define CLK_TIMER_TIMER 13
29+
30+#define CLK_MB_0_APB 14 /* MB0: ap->dsp */
31+#define CLK_MB_1_APB 15 /* MB1: dsp->ap */
32+
33+#define CLK_I2S0_APB 16
34+#define CLK_I2S1_APB 17
35+#define CLK_I2S2_APB 18
36+#define CLK_I2S3_APB 19
37+#define CLK_I2S4_APB 20
38+#define CLK_I2S5_APB 21
39+#define CLK_I2S6_APB 22
40+#define CLK_I2S7_APB 23
41+#define CLK_I2S8_APB 24
42+#define CLK_I2S9_APB 25
43+#define CLK_I2S0 26
44+#define CLK_I2S1 27
45+#define CLK_I2S2 28
46+#define CLK_I2S3 29
47+#define CLK_I2S4 30
48+#define CLK_I2S5 31
49+#define CLK_I2S6 32
50+#define CLK_I2S7 33
51+#define CLK_I2S8 34
52+#define CLK_I2S9 35
53+
54+#define CLK_MCLK0 36
55+#define CLK_MCLK1 37
56+#define CLK_MCLK2 38
57+#define CLK_MCLK3 39
58+#define CLK_MCLK4 40
59+
60+#endif
include/dt-bindings/clock/mt8173-clk.h+7−0
@@ -243,6 +243,13 @@ · 242 unmodified lines
243243 #define CLK_IMG_FD 7
244244 #define CLK_IMG_NR_CLK 8
245245
246+/* MFG_SYS */
247+
248+#define CLK_MFG_AXI 0
249+#define CLK_MFG_MEM 1
250+#define CLK_MFG_G3D 2
251+#define CLK_MFG_26M 3
252+
246253 /* MM_SYS */
247254
248255 #define CLK_MM_SMI_COMMON 1
include/dt-bindings/clock/ultrarisc,dp1000-clk.h+27−0
@@ -0,0 +1,27 @@
1+/* SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) */
2+#ifndef _DT_BINDINGS_CLOCK_ULTRARISC_DP1000_CLK_H
3+#define _DT_BINDINGS_CLOCK_ULTRARISC_DP1000_CLK_H
4+
5+#define DP1000_CLK_SYSPLL 0
6+#define DP1000_CLK_SYSPLL_DIV2 1
7+#define DP1000_CLK_SUBSYS 2
8+#define DP1000_CLK_GMAC 3
9+#define DP1000_CLK_UART_ROOT 4
10+#define DP1000_CLK_I2C_ROOT 5
11+#define DP1000_CLK_SPI_ROOT 6
12+#define DP1000_CLK_PCIE_DBI 7
13+#define DP1000_CLK_PCIEX4_CORE 8
14+#define DP1000_CLK_PCIEX16_CORE 9
15+#define DP1000_CLK_PCIE_AUX 10
16+#define DP1000_CLK_UART0 11
17+#define DP1000_CLK_UART1 12
18+#define DP1000_CLK_UART2 13
19+#define DP1000_CLK_UART3 14
20+#define DP1000_CLK_I2C0 15
21+#define DP1000_CLK_I2C1 16
22+#define DP1000_CLK_I2C2 17
23+#define DP1000_CLK_I2C3 18
24+#define DP1000_CLK_SPI0 19
25+#define DP1000_CLK_SPI1 20
26+
27+#endif /* _DT_BINDINGS_CLOCK_ULTRARISC_DP1000_CLK_H */
include/dt-bindings/reset/airoha,en7581-reset.h+4−0
@@ -62,5 +62,9 @@ · 61 unmodified lines
6262 #define EN7581_CPU_TIMER_RST 50
6363 #define EN7581_PCIE_HB_RST 51
6464 #define EN7581_XPON_MAC_RST 52
65+/* RST_PCIC */
66+#define EN7581_PCIC_PERSTOUT0_RST 53
67+#define EN7581_PCIC_PERSTOUT1_RST 54
68+#define EN7581_PCIC_PERSTOUT2_RST 55
6569
6670 #endif /* __DT_BINDINGS_RESET_CONTROLLER_AIROHA_EN7581_H_ */
include/dt-bindings/reset/cix,sky1-audss-cru.h+25−0
@@ -0,0 +1,25 @@
1+/* SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) */
2+/*
3+ * Copyright 2026 Cix Technology Group Co., Ltd.
4+ */
5+#ifndef DT_BINDINGS_RESET_CIX_SKY1_AUDSS_CRU_H
6+#define DT_BINDINGS_RESET_CIX_SKY1_AUDSS_CRU_H
7+
8+#define AUDSS_I2S0_SW_RST 0
9+#define AUDSS_I2S1_SW_RST 1
10+#define AUDSS_I2S2_SW_RST 2
11+#define AUDSS_I2S3_SW_RST 3
12+#define AUDSS_I2S4_SW_RST 4
13+#define AUDSS_I2S5_SW_RST 5
14+#define AUDSS_I2S6_SW_RST 6
15+#define AUDSS_I2S7_SW_RST 7
16+#define AUDSS_I2S8_SW_RST 8
17+#define AUDSS_I2S9_SW_RST 9
18+#define AUDSS_WDT_SW_RST 10
19+#define AUDSS_TIMER_SW_RST 11
20+#define AUDSS_MB0_SW_RST 12
21+#define AUDSS_MB1_SW_RST 13
22+#define AUDSS_HDA_SW_RST 14
23+#define AUDSS_DMAC_SW_RST 15
24+
25+#endif
include/linux/clk.h+25−2
@@ -502,6 +502,22 @@ int __must_check devm_clk_bulk_get(struct device *dev, int num_clks, · 501 unmodified lines
502502 */
503503 int __must_check devm_clk_bulk_get_optional(struct device *dev, int num_clks,
504504 struct clk_bulk_data *clks);
505+/**
506+ * devm_clk_bulk_get_enable - Get and enable bulk clocks (managed)
507+ * @dev: device for clock "consumer"
508+ * @num_clks: the number of clk_bulk_data
509+ * @clks: pointer to the clk_bulk_data table of consumer
510+ *
511+ * Behaves the same as devm_clk_bulk_get() but also prepares and enables the
512+ * clocks in one operation with management. The clks will automatically be
513+ * disabled, unprepared and freed when the device is unbound.
514+ *
515+ * Return: 0 if all clocks specified in clk_bulk_data table are obtained and
516+ * enabled successfully. Otherwise returns valid IS_ERR() condition containing
517+ * errno.
518+ */
519+int __must_check devm_clk_bulk_get_enable(struct device *dev, int num_clks,
520+ struct clk_bulk_data *clks);
505521 /**
506522 * devm_clk_bulk_get_optional_enable - Get and enable optional bulk clocks (managed)
507523 * @dev: device for clock "consumer"
@@ -951,8 +967,8 @@ int clk_set_parent(struct clk *clk, struct clk *parent); · 443 unmodified lines
951967 * clk_get_parent - get the parent clock source for this clock
952968 * @clk: clock source
953969 *
954− * Returns struct clk corresponding to parent clock source, or
955− * valid IS_ERR() condition containing errno.
970+ * Returns struct clk corresponding to parent clock source, or NULL
971+ * if clk is NULL.
956972 */
957973 struct clk *clk_get_parent(struct clk *clk);
958974
@@ -1052,6 +1068,13 @@ static inline int __must_check devm_clk_bulk_get_optional(struct device *dev, · 93 unmodified lines
10521068 return 0;
10531069 }
10541070
1071+static inline int __must_check devm_clk_bulk_get_enable(struct device *dev,
1072+ int num_clks,
1073+ struct clk_bulk_data *clks)
1074+{
1075+ return 0;
1076+}
1077+
10551078 static inline int __must_check devm_clk_bulk_get_optional_enable(struct device *dev,
10561079 int num_clks,
10571080 struct clk_bulk_data *clks)

Keyboard shortcuts

General

Show keyboard shortcuts
?
Focus the current search
/

Issues and pull requests

Open filters
f

Issues, pull requests and Inbox

Select next item
j↓
Select previous item
k↑
Open selected item
Enter
Dismiss filters or clear selection
Esc

Repository code

Go to file
t