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
8title: MediaTek MT8173 MFG TOP controller
9
10maintainers:
11 - AngeloGioacchino Del Regno <angelogioacchino.delregno@collabora.com>
12
13description:
14 The MFG TOP glue layer controls various signals going to the MFG (GPU)
15 block on the MT8173.
16
17properties:
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
43required:
44 - compatible
45 - reg
46 - clocks
47 - clock-names
48 - power-domains
49 - '#clock-cells'
50 - '#power-domain-cells'
51
52additionalProperties: false
53
54examples:
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
4$id: http://devicetree.org/schemas/clock/silabs,si544.yaml#4$id: http://devicetree.org/schemas/clock/silabs,si544.yaml#
5$schema: http://devicetree.org/meta-schemas/core.yaml#5$schema: http://devicetree.org/meta-schemas/core.yaml#
6 6
7title: Silicon Labs SI514/SI544 clock generator7title: Silicon Labs SI514/SI544/SI549 clock generator
8 8
9maintainers:9maintainers:
10 - Mike Looijmans <mike.looijmans@topic.nl>10 - Mike Looijmans <mike.looijmans@topic.nl>
@@ -13,8 +13,9 @@ description: > · 2 unmodified lines
13 Silicon Labs 514/544 programmable I2C clock generator. Details about the device13 Silicon Labs 514/544 programmable I2C clock generator. Details about the device
14 can be found in the datasheet:14 can be found in the datasheet:
15 15
16 https://www.silabs.com/Support%20Documents/TechnicalDocs/si514.pdf16 https://www.skyworksinc.com/-/media/Skyworks/SL/documents/public/data-sheets/Si514.pdf
17 https://www.silabs.com/documents/public/data-sheets/si544-datasheet.pdf17 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
18 19
19properties:20properties:
20 compatible:21 compatible:
@@ -23,6 +24,9 @@ properties: · 2 unmodified lines
23 - silabs,si544a24 - silabs,si544a
24 - silabs,si544b25 - silabs,si544b
25 - silabs,si544c26 - silabs,si544c
27 - silabs,si549a
28 - silabs,si549b
29 - silabs,si549c
26 30
27 reg:31 reg:
28 maxItems: 132 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
7title: UltraRISC DP1000 Clock Controller
8
9maintainers:
10 - Jia Wang <wangjia@ultrarisc.com>
11
12description: |
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
23properties:
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
38required:
39 - compatible
40 - reg
41 - clocks
42 - "#clock-cells"
43
44additionalProperties: false
45
46examples:
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
7title: Cix Sky1 audio subsystem clock and reset unit
8
9maintainers:
10 - Joakim Zhang <joakim.zhang@cixtech.com>
11
12description: |
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
31properties:
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
68required:
69 - compatible
70 - reg
71 - '#clock-cells'
72 - '#reset-cells'
73 - clocks
74 - clock-names
75 - power-domains
76 - resets
77
78additionalProperties: false
79
80examples:
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
248 devm_clk_put()248 devm_clk_put()
249 devm_clk_bulk_get()249 devm_clk_bulk_get()
250 devm_clk_bulk_get_all()250 devm_clk_bulk_get_all()
251 devm_clk_bulk_get_enable()
251 devm_clk_bulk_get_optional()252 devm_clk_bulk_get_optional()
252 devm_get_clk_from_child()253 devm_get_clk_from_child()
253 devm_clk_hw_register()254 devm_clk_hw_register()
MAINTAINERS+8−0
@@ -27671,6 +27671,14 @@ S: Maintained · 27670 unmodified lines
27671F: drivers/usb/common/ulpi.c27671F: drivers/usb/common/ulpi.c
27672F: include/linux/ulpi/27672F: include/linux/ulpi/
27673 27673
27674ULTRARISC DP1000 CLOCK DRIVER
27675M: Jia Wang <wangjia@ultrarisc.com>
27676L: linux-clk@vger.kernel.org
27677S: Maintained
27678F: Documentation/devicetree/bindings/clock/ultrarisc,dp1000-clk.yaml
27679F: drivers/clk/ultrarisc/*
27680F: include/dt-bindings/clock/ultrarisc,dp1000-clk.h
27681
27674ULTRARISC DP1000 PINCTRL DRIVER27682ULTRARISC DP1000 PINCTRL DRIVER
27675M: Jia Wang <wangjia@ultrarisc.com>27683M: Jia Wang <wangjia@ultrarisc.com>
27676L: linux-gpio@vger.kernel.org27684L: linux-gpio@vger.kernel.org
arch/arm64/boot/dts/cix/sky1.dtsi+18−0
@@ -6,6 +6,10 @@ · 5 unmodified lines
6 6
7#include <dt-bindings/interrupt-controller/arm-gic.h>7#include <dt-bindings/interrupt-controller/arm-gic.h>
8#include <dt-bindings/clock/cix,sky1.h>8#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>
9#include "sky1-power.h"13#include "sky1-power.h"
10 14
11/ {15/ {
@@ -558,6 +562,20 @@ · 546 unmodified lines
558 cix,mbox-dir = "rx";562 cix,mbox-dir = "rx";
559 };563 };
560 564
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
561 mbox_sfh2ap: mailbox@8090000 {579 mbox_sfh2ap: mailbox@8090000 {
562 compatible = "cix,sky1-mbox";580 compatible = "cix,sky1-mbox";
563 reg = <0x0 0x08090000 0x0 0x10000>;581 reg = <0x0 0x08090000 0x0 0x10000>;
drivers/clk/Kconfig+6−4
@@ -155,12 +155,12 @@ config COMMON_CLK_SI514 · 154 unmodified lines
155 generator.155 generator.
156 156
157config COMMON_CLK_SI544157config COMMON_CLK_SI544
158 tristate "Clock driver for SiLabs 544 devices"158 tristate "Clock driver for SiLabs 544 and compatible devices"
159 depends on I2C159 depends on I2C
160 select REGMAP_I2C160 select REGMAP_I2C
161 help161 help
162 This driver supports the Silicon Labs 544 programmable clock162 This driver supports the Silicon Labs 544/549 programmable clock
163 generator.163 generators.
164 164
165config COMMON_CLK_SI570165config COMMON_CLK_SI570
166 tristate "Clock driver for SiLabs 570 and compatible devices"166 tristate "Clock driver for SiLabs 570 and compatible devices"
@@ -278,7 +278,7 @@ config COMMON_CLK_LAN966X · 111 unmodified lines
278 tristate "Generic Clock Controller driver for LAN966X SoC"278 tristate "Generic Clock Controller driver for LAN966X SoC"
279 depends on HAS_IOMEM279 depends on HAS_IOMEM
280 depends on OF280 depends on OF
281 depends on SOC_LAN966 || ARCH_LAN969X || COMPILE_TEST281 depends on SOC_LAN966 || ARCH_LAN969X || MCHP_LAN966X_PCI || COMPILE_TEST
282 help282 help
283 This driver provides support for Generic Clock Controller(GCK) on283 This driver provides support for Generic Clock Controller(GCK) on
284 LAN966X SoC. GCK generates and supplies clock to various peripherals284 LAN966X SoC. GCK generates and supplies clock to various peripherals
@@ -509,6 +509,7 @@ source "drivers/clk/actions/Kconfig" · 224 unmodified lines
509source "drivers/clk/analogbits/Kconfig"509source "drivers/clk/analogbits/Kconfig"
510source "drivers/clk/aspeed/Kconfig"510source "drivers/clk/aspeed/Kconfig"
511source "drivers/clk/bcm/Kconfig"511source "drivers/clk/bcm/Kconfig"
512source "drivers/clk/cix/Kconfig"
512source "drivers/clk/eswin/Kconfig"513source "drivers/clk/eswin/Kconfig"
513source "drivers/clk/hisilicon/Kconfig"514source "drivers/clk/hisilicon/Kconfig"
514source "drivers/clk/imgtec/Kconfig"515source "drivers/clk/imgtec/Kconfig"
@@ -541,6 +542,7 @@ source "drivers/clk/tenstorrent/Kconfig" · 26 unmodified lines
541source "drivers/clk/thead/Kconfig"542source "drivers/clk/thead/Kconfig"
542source "drivers/clk/stm32/Kconfig"543source "drivers/clk/stm32/Kconfig"
543source "drivers/clk/ti/Kconfig"544source "drivers/clk/ti/Kconfig"
545source "drivers/clk/ultrarisc/Kconfig"
544source "drivers/clk/uniphier/Kconfig"546source "drivers/clk/uniphier/Kconfig"
545source "drivers/clk/visconti/Kconfig"547source "drivers/clk/visconti/Kconfig"
546source "drivers/clk/x86/Kconfig"548source "drivers/clk/x86/Kconfig"
drivers/clk/Makefile+3−1
@@ -131,6 +131,7 @@ obj-$(CONFIG_ARCH_ARTPEC) += axis/ · 130 unmodified lines
131obj-$(CONFIG_ARC_PLAT_AXS10X) += axs10x/131obj-$(CONFIG_ARC_PLAT_AXS10X) += axs10x/
132obj-y += bcm/132obj-y += bcm/
133obj-$(CONFIG_ARCH_BERLIN) += berlin/133obj-$(CONFIG_ARCH_BERLIN) += berlin/
134obj-y += cix/
134obj-$(CONFIG_ARCH_DAVINCI) += davinci/135obj-$(CONFIG_ARCH_DAVINCI) += davinci/
135obj-$(CONFIG_COMMON_CLK_ESWIN) += eswin/136obj-$(CONFIG_COMMON_CLK_ESWIN) += eswin/
136obj-$(CONFIG_COMMON_CLK_HISI) += hisilicon/137obj-$(CONFIG_COMMON_CLK_HISI) += hisilicon/
@@ -163,7 +164,7 @@ obj-y += spacemit/ · 26 unmodified lines
163obj-$(CONFIG_PLAT_SPEAR) += spear/164obj-$(CONFIG_PLAT_SPEAR) += spear/
164obj-y += sprd/165obj-y += sprd/
165obj-$(CONFIG_ARCH_STI) += st/166obj-$(CONFIG_ARCH_STI) += st/
166obj-$(CONFIG_ARCH_STM32) += stm32/167obj-$(CONFIG_COMMON_CLK_STM32MP) += stm32/
167obj-y += starfive/168obj-y += starfive/
168obj-$(CONFIG_ARCH_SUNXI) += sunxi/169obj-$(CONFIG_ARCH_SUNXI) += sunxi/
169obj-y += sunxi-ng/170obj-y += sunxi-ng/
@@ -171,6 +172,7 @@ obj-$(CONFIG_ARCH_TEGRA) += tegra/ · 1 unmodified line
171obj-y += tenstorrent/172obj-y += tenstorrent/
172obj-$(CONFIG_ARCH_THEAD) += thead/173obj-$(CONFIG_ARCH_THEAD) += thead/
173obj-y += ti/174obj-y += ti/
175obj-y += ultrarisc/
174obj-$(CONFIG_CLK_UNIPHIER) += uniphier/176obj-$(CONFIG_CLK_UNIPHIER) += uniphier/
175obj-$(CONFIG_ARCH_U8500) += ux500/177obj-$(CONFIG_ARCH_U8500) += ux500/
176obj-y += versatile/178obj-y += versatile/
drivers/clk/aspeed/clk-ast2700.c+10−0
@@ -272,6 +272,13 @@ static const unsigned int sdclk_parent_ids[] = { · 271 unmodified lines
272 272
273static const struct clk_hw *sdclk_parent_hws[ARRAY_SIZE(sdclk_parent_ids)];273static const struct clk_hw *sdclk_parent_hws[ARRAY_SIZE(sdclk_parent_ids)];
274 274
275static const unsigned int peciclk_parent_ids[] = {
276 SCU1_CLKIN,
277 SCU1_CLK_HPLL_DIV4
278};
279
280static const struct clk_hw *peciclk_parent_hws[ARRAY_SIZE(peciclk_parent_ids)];
281
275#define FIXED_CLK(_id, _name, _rate) \282#define FIXED_CLK(_id, _name, _rate) \
276 { \283 { \
277 .id = _id, \284 .id = _id, \
@@ -457,6 +464,7 @@ static const struct ast2700_clk_info ast2700_scu1_clk_info[] __initconst = { · 179 unmodified lines
457 PLL_CLK(SCU1_CLK_HPLL, CLK_PLL, "soc1-hpll", SCU1_CLKIN, SCU1_HPLL_PARAM),464 PLL_CLK(SCU1_CLK_HPLL, CLK_PLL, "soc1-hpll", SCU1_CLKIN, SCU1_HPLL_PARAM),
458 PLL_CLK(SCU1_CLK_APLL, CLK_PLL, "soc1-apll", SCU1_CLKIN, SCU1_APLL_PARAM),465 PLL_CLK(SCU1_CLK_APLL, CLK_PLL, "soc1-apll", SCU1_CLKIN, SCU1_APLL_PARAM),
459 PLL_CLK(SCU1_CLK_DPLL, CLK_PLL, "soc1-dpll", SCU1_CLKIN, SCU1_DPLL_PARAM),466 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),
460 FIXED_FACTOR_CLK(SCU1_CLK_APLL_DIV2, "soc1-apll_div2", SCU1_CLK_APLL, 1, 2),468 FIXED_FACTOR_CLK(SCU1_CLK_APLL_DIV2, "soc1-apll_div2", SCU1_CLK_APLL, 1, 2),
461 FIXED_FACTOR_CLK(SCU1_CLK_APLL_DIV4, "soc1-apll_div4", SCU1_CLK_APLL, 1, 4),469 FIXED_FACTOR_CLK(SCU1_CLK_APLL_DIV4, "soc1-apll_div4", SCU1_CLK_APLL, 1, 4),
462 FIXED_FACTOR_CLK(SCU1_CLK_CAN, "canclk", SCU1_CLK_APLL, 1, 10),470 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
480 uxclk_parent_hws, SCU1_CLK_SEL2, 0, 2),488 uxclk_parent_hws, SCU1_CLK_SEL2, 0, 2),
481 MUX_CLK(SCU1_CLK_HUXCLK, "huxclk", uxclk_parent_ids, ARRAY_SIZE(uxclk_parent_ids),489 MUX_CLK(SCU1_CLK_HUXCLK, "huxclk", uxclk_parent_ids, ARRAY_SIZE(uxclk_parent_ids),
482 uxclk_parent_hws, SCU1_CLK_SEL2, 3, 2),490 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),
483 DIVIDER_CLK(SCU1_CLK_SDCLK, "sdclk", SCU1_CLK_SDMUX,493 DIVIDER_CLK(SCU1_CLK_SDCLK, "sdclk", SCU1_CLK_SDMUX,
484 SCU1_CLK_SEL1, 14, 3, ast2700_clk_div_table),494 SCU1_CLK_SEL1, 14, 3, ast2700_clk_div_table),
485 PLL_CLK(SCU1_CLK_UARTX, CLK_UART_PLL, "uartxclk", SCU1_CLK_UXCLK, SCU1_UXCLK_CTRL),495 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
3menu "Cixtech Audio Subsystem Clock Driver"
4
5config 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.
16endmenu
drivers/clk/cix/Makefile+3−0
@@ -0,0 +1,3 @@
1# SPDX-License-Identifier: GPL-2.0
2
3obj-$(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
26static 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
34static const char * const sky1_audss_clk_names[SKY1_AUDSS_CLK_PARENTS_CNT] = {
35 "x8k", "x11k", "sys", "48m",
36};
37
38static const u32 sky1_clk_rate_default[SKY1_AUDSS_CLK_PARENTS_CNT] = {
39 294912000,
40 270950400,
41 800000000,
42 48000000,
43};
44
45static const char * const dsp_clk_parent[] = {
46 "audio_clk4"
47};
48
49static const char * const dsp_bclk_parent[] = {
50 "audio_clk4_div2"
51};
52
53static const char * const dsp_pbclk_parent[] = {
54 "audio_clk4_div4"
55};
56
57static const char * const sram_axi_parent[] = {
58 "audio_clk4_div2"
59};
60
61static const char * const hda_sys_parent[] = {
62 "audio_clk4_div2"
63};
64
65static const char * const hda_hda_parent[] = {
66 "audio_clk5"
67};
68
69static const char * const dmac_axi_parent[] = {
70 "audio_clk4_div2"
71};
72
73static const char * const wdg_apb_parent[] = {
74 "audio_clk5_div2"
75};
76
77static const char * const wdg_wdg_parent[] = {
78 "audio_clk5_div2"
79};
80
81static const char * const timer_apb_parent[] = {
82 "audio_clk4_div4"
83};
84
85static const char * const timer_timer_parent[] = {
86 "audio_clk5_div2"
87};
88
89static const char * const mailbox_apb_parent[] = {
90 "audio_clk4_div4"
91};
92
93static const char * const i2s_apb_parent[] = {
94 "audio_clk4_div4"
95};
96
97static const char * const i2s0_parents[] = {
98 "audio_clk0", "audio_clk2"
99};
100
101static const char * const i2s1_parents[] = {
102 "audio_clk0", "audio_clk2"
103};
104
105static const char * const i2s2_parents[] = {
106 "audio_clk0", "audio_clk2"
107};
108
109static const char * const i2s3_parents[] = {
110 "audio_clk0", "audio_clk2"
111};
112
113static const char * const i2s4_parents[] = {
114 "audio_clk0", "audio_clk2"
115};
116
117static const char * const i2s5_parents[] = {
118 "audio_clk0", "audio_clk2"
119};
120
121static const char * const i2s6_parents[] = {
122 "audio_clk0", "audio_clk2"
123};
124
125static const char * const i2s7_parents[] = {
126 "audio_clk0", "audio_clk2"
127};
128
129static const char * const i2s8_parents[] = {
130 "audio_clk0", "audio_clk2"
131};
132
133static const char * const i2s9_parents[] = {
134 "audio_clk0", "audio_clk2"
135};
136
137static const char * const mclk_parents[] = {
138 "audio_clk0", "audio_clk2"
139};
140
141static const u32 i2s3_mux_table[] = { 0, 2 };
142static const u32 i2s4_mux_table[] = { 0, 2 };
143
144/*
145 * audss composite clock definition
146 */
147struct muxdiv_cfg {
148 int offset;
149 u8 shift;
150 u8 width;
151 u8 flags;
152};
153
154struct gate_cfg {
155 int offset;
156 u8 shift;
157 u8 flags;
158};
159
160struct 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
192static 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
508struct 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
518static const struct regmap_config sky1_audss_regmap_config = {
519 .reg_bits = 32,
520 .val_bits = 32,
521 .reg_stride = 4,
522};
523
524struct 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
536static 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
552static 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 */
562struct sky1_clk_divider {
563 struct clk_divider div;
564 struct regmap *regmap;
565 int offset;
566};
567
568struct sky1_clk_gate {
569 struct clk_gate gate;
570 struct regmap *regmap;
571 int offset;
572};
573
574struct sky1_clk_mux {
575 struct clk_mux mux;
576 struct regmap *regmap;
577 int offset;
578};
579
580static 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
585static 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
598static 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
629static 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
637static 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
643static 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
648static 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
663static 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
686static 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
723static 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
729static 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
734static 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
770static 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
777static void sky1_audss_clk_gate_disable(struct clk_hw *hw)
778{
779 sky1_audss_clk_gate_endisable(hw, 0);
780}
781
782static 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
799static 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
805static 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
893static 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
908static 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
924err_clks:
925 while (--i >= 0)
926 clk_disable_unprepare(priv->clks[i]);
927
928 return err;
929}
930
931static 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
940static 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
957static void sky1_audss_clk_rpm_cleanup(void *data)
958{
959 pm_runtime_force_suspend(data);
960}
961
962/* register sky1 audio subsystem clocks */
963static 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
1117fail_pm:
1118 pm_runtime_put_sync(dev);
1119 return ret;
1120}
1121
1122static 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
1142static 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
1170static 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
1177static 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
1187static const struct of_device_id sky1_audss_clk_of_match[] = {
1188 { .compatible = "cix,sky1-audss-cru", .data = &sky1_devtype_data, },
1189 { /* sentinel */ },
1190};
1191MODULE_DEVICE_TABLE(of, sky1_audss_clk_of_match);
1192
1193static 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};
1202module_platform_driver(sky1_audss_clk_driver);
1203
1204MODULE_LICENSE("GPL");
1205MODULE_AUTHOR("Joakim Zhang <joakim.zhang@cixtech.com>");
1206MODULE_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
462 rate_hw, rate_ops, gate_hw,462 rate_hw, rate_ops, gate_hw,
463 gate_ops, flags);463 gate_ops, flags);
464}464}
465EXPORT_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
404 if (ret < 0)404 if (ret < 0)
405 return ret;405 return ret;
406 406
407 ret = cs2000_wait_pll_lock(priv);407 return cs2000_wait_pll_lock(priv);
408 if (ret < 0)
409 return ret;
410
411 return ret;
412}408}
413 409
414static void cs2000_disable(struct clk_hw *hw)410static void cs2000_disable(struct clk_hw *hw)
drivers/clk/clk-devres.c+7−0
@@ -222,6 +222,13 @@ err_clk_get: · 221 unmodified lines
222 return ret;222 return ret;
223}223}
224 224
225int __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}
230EXPORT_SYMBOL_GPL(devm_clk_bulk_get_enable);
231
225int __must_check devm_clk_bulk_get_optional_enable(struct device *dev, int num_clks,232int __must_check devm_clk_bulk_get_optional_enable(struct device *dev, int num_clks,
226 struct clk_bulk_data *clks)233 struct clk_bulk_data *clks)
227{234{
drivers/clk/clk-en7523.c+33−10
@@ -57,6 +57,7 @@ · 56 unmodified lines
57 57
58#define REG_RST_CTRL2 0x83058#define REG_RST_CTRL2 0x830
59#define REG_RST_CTRL1 0x83459#define REG_RST_CTRL1 0x834
60#define REG_PCIE_HB_RST BIT(29)
60#define EN751221_REG_RST_DMT 0x8461#define EN751221_REG_RST_DMT 0x84
61#define EN751221_REG_RST_USB 0xec62#define EN751221_REG_RST_USB 0xec
62 63
@@ -338,6 +339,7 @@ static const struct en_clk_desc en7581_base_clks[] = { · 275 unmodified lines
338static const u16 en7581_rst_ofs[] = {339static const u16 en7581_rst_ofs[] = {
339 REG_RST_CTRL2,340 REG_RST_CTRL2,
340 REG_RST_CTRL1,341 REG_RST_CTRL1,
342 REG_NP_SCU_PCIC,
341};343};
342 344
343static const u16 en751221_rst_ofs[] = {345static const u16 en751221_rst_ofs[] = {
@@ -450,6 +452,11 @@ static const u16 en7581_rst_map[] = { · 106 unmodified lines
450 [EN7581_CPU_TIMER_RST] = RST_NR_PER_BANK + 28,452 [EN7581_CPU_TIMER_RST] = RST_NR_PER_BANK + 28,
451 [EN7581_PCIE_HB_RST] = RST_NR_PER_BANK + 29,453 [EN7581_PCIE_HB_RST] = RST_NR_PER_BANK + 29,
452 [EN7581_XPON_MAC_RST] = RST_NR_PER_BANK + 31,454 [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,
453};460};
454 461
455static const u16 en751221_rst_map[] = {462static const u16 en751221_rst_map[] = {
@@ -635,9 +642,7 @@ static int en7581_pci_enable(struct clk_hw *hw) · 179 unmodified lines
635 void __iomem *np_base = cg->base;642 void __iomem *np_base = cg->base;
636 u32 val, mask;643 u32 val, mask;
637 644
638 mask = REG_PCI_CONTROL_REFCLK_EN0 | REG_PCI_CONTROL_REFCLK_EN1 |645 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;
641 val = readl(np_base + REG_PCI_CONTROL);646 val = readl(np_base + REG_PCI_CONTROL);
642 writel(val | mask, np_base + REG_PCI_CONTROL);647 writel(val | mask, np_base + REG_PCI_CONTROL);
643 648
@@ -650,9 +655,7 @@ static void en7581_pci_disable(struct clk_hw *hw) · 6 unmodified lines
650 void __iomem *np_base = cg->base;655 void __iomem *np_base = cg->base;
651 u32 val, mask;656 u32 val, mask;
652 657
653 mask = REG_PCI_CONTROL_REFCLK_EN0 | REG_PCI_CONTROL_REFCLK_EN1 |658 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;
656 val = readl(np_base + REG_PCI_CONTROL);659 val = readl(np_base + REG_PCI_CONTROL);
657 writel(val & ~mask, np_base + REG_PCI_CONTROL);660 writel(val & ~mask, np_base + REG_PCI_CONTROL);
658 usleep_range(1000, 2000);661 usleep_range(1000, 2000);
@@ -754,11 +757,17 @@ static int en7523_reset_update(struct reset_controller_dev *rcdev, · 95 unmodified lines
754 unsigned long id, bool assert)757 unsigned long id, bool assert)
755{758{
756 struct en_rst_data *rst_data = container_of(rcdev, struct en_rst_data, rcdev);759 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;
758 u32 val;763 u32 val;
759 764
765 /* For PCIC reset logic is inverted, 0:assert 1:deassert */
766 if (offset == REG_NP_SCU_PCIC)
767 inverted = true;
768
760 val = readl(addr);769 val = readl(addr);
761 if (assert)770 if (assert ^ inverted)
762 val |= BIT(id % RST_NR_PER_BANK);771 val |= BIT(id % RST_NR_PER_BANK);
763 else772 else
764 val &= ~BIT(id % RST_NR_PER_BANK);773 val &= ~BIT(id % RST_NR_PER_BANK);
@@ -783,9 +792,17 @@ static int en7523_reset_status(struct reset_controller_dev *rcdev, · 18 unmodified lines
783 unsigned long id)792 unsigned long id)
784{793{
785 struct en_rst_data *rst_data = container_of(rcdev, struct en_rst_data, rcdev);794 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;
787 803
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;
789}806}
790 807
791static int en7523_reset_xlate(struct reset_controller_dev *rcdev,808static 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
853 val = readl(base + REG_NP_SCU_PCIC);870 val = readl(base + REG_NP_SCU_PCIC);
854 writel(val | 3, base + REG_NP_SCU_PCIC);871 writel(val | 3, base + REG_NP_SCU_PCIC);
855 872
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
856 return en7581_reset_register(&pdev->dev, base, en7581_rst_map,879 return en7581_reset_register(&pdev->dev, base, en7581_rst_map,
857 ARRAY_SIZE(en7581_rst_map),880 ARRAY_SIZE(en7581_rst_map),
858 en7581_rst_ofs);881 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
815 if (ret)815 if (ret)
816 return ret;816 return ret;
817 817
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
825 /*818 /*
826 * 9. (optional) if SCLKx_y_DIS_MODE was used to mute SYSREF outputs819 * 9. (optional) if SCLKx_y_DIS_MODE was used to mute SYSREF outputs
827 * during the SYNC event, restore SCLKx_y_DIS_MODE=0 for active state,820 * 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
836 * SYNC pulse to delay the output by some number of VCO counts).829 * SYNC pulse to delay the output by some number of VCO counts).
837 */830 */
838 831
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));
840}836}
841 837
842static int lmk04832_sclk_is_enabled(struct clk_hw *hw)838static 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
194 cinfo->ext_control_pin = prop;194 cinfo->ext_control_pin = prop;
195}195}
196 196
197static 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
197static int palmas_clks_init_configure(struct palmas_clock_info *cinfo)204static int palmas_clks_init_configure(struct palmas_clock_info *cinfo)
198{205{
199 int ret;206 int ret;
@@ -214,13 +221,18 @@ static int palmas_clks_init_configure(struct palmas_clock_info *cinfo) · 14 unmodified lines
214 return ret;221 return ret;
215 }222 }
216 223
224 ret = devm_add_action_or_reset(cinfo->dev,
225 palmas_clks_unprepare_ext_control,
226 cinfo);
227 if (ret)
228 return ret;
229
217 ret = palmas_ext_control_req_config(cinfo->palmas,230 ret = palmas_ext_control_req_config(cinfo->palmas,
218 cinfo->clk_desc->sleep_reqstr_id,231 cinfo->clk_desc->sleep_reqstr_id,
219 cinfo->ext_control_pin, true);232 cinfo->ext_control_pin, true);
220 if (ret < 0) {233 if (ret < 0) {
221 dev_err(cinfo->dev, "Ext config for %s failed, %d\n",234 dev_err(cinfo->dev, "Ext config for %s failed, %d\n",
222 cinfo->clk_desc->clk_name, ret);235 cinfo->clk_desc->clk_name, ret);
223 clk_unprepare(cinfo->hw.clk);
224 return ret;236 return ret;
225 }237 }
226 }238 }
@@ -230,7 +242,6 @@ static int palmas_clks_init_configure(struct palmas_clock_info *cinfo) · 3 unmodified lines
230static int palmas_clks_probe(struct platform_device *pdev)242static int palmas_clks_probe(struct platform_device *pdev)
231{243{
232 struct palmas *palmas = dev_get_drvdata(pdev->dev.parent);244 struct palmas *palmas = dev_get_drvdata(pdev->dev.parent);
233 struct device_node *node = pdev->dev.of_node;
234 const struct palmas_clks_of_match_data *match_data;245 const struct palmas_clks_of_match_data *match_data;
235 struct palmas_clock_info *cinfo;246 struct palmas_clock_info *cinfo;
236 int ret;247 int ret;
@@ -264,24 +275,19 @@ static int palmas_clks_probe(struct platform_device *pdev) · 27 unmodified lines
264 return ret;275 return ret;
265 }276 }
266 277
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);
268 if (ret < 0)280 if (ret < 0)
269 dev_err(&pdev->dev, "Fail to add clock driver, %d\n", ret);281 dev_err(&pdev->dev, "Fail to add clock driver, %d\n", ret);
270 return ret;282 return ret;
271}283}
272 284
273static void palmas_clks_remove(struct platform_device *pdev)
274{
275 of_clk_del_provider(pdev->dev.of_node);
276}
277
278static struct platform_driver palmas_clks_driver = {285static struct platform_driver palmas_clks_driver = {
279 .driver = {286 .driver = {
280 .name = "palmas-clk",287 .name = "palmas-clk",
281 .of_match_table = palmas_clks_of_match,288 .of_match_table = palmas_clks_of_match,
282 },289 },
283 .probe = palmas_clks_probe,290 .probe = palmas_clks_probe,
284 .remove = palmas_clks_remove,
285};291};
286 292
287module_platform_driver(palmas_clks_driver);293module_platform_driver(palmas_clks_driver);
drivers/clk/clk-si544.c+65−17
@@ -1,6 +1,6 @@
1// SPDX-License-Identifier: GPL-2.01// SPDX-License-Identifier: GPL-2.0
2/*2/*
3 * Driver for Silicon Labs Si544 Programmable Oscillator3 * Driver for Silicon Labs Si544/Si549 Programmable Oscillator
4 * Copyright (C) 2018 Topic Embedded Products4 * Copyright (C) 2018 Topic Embedded Products
5 * Author: Mike Looijmans <mike.looijmans@topic.nl>5 * Author: Mike Looijmans <mike.looijmans@topic.nl>
6 */6 */
@@ -40,7 +40,9 @@ · 33 unmodified lines
40#define SI544_MIN_FREQ 200000U40#define SI544_MIN_FREQ 200000U
41 41
42/* Si544 Internal oscillator runs at 55.05 MHz */42/* Si544 Internal oscillator runs at 55.05 MHz */
43#define FXO 55050000U43#define SI544_XO_FREQ 55050000U
44/* Si549 Internal oscilator runs at 152.60 MHz */
45#define SI549_XO_FREQ 152600000U
44 46
45/* VCO range is 10.8 .. 12.1 GHz, max depends on speed grade */47/* VCO range is 10.8 .. 12.1 GHz, max depends on speed grade */
46#define FVCO_MIN 10800000000ULL48#define FVCO_MIN 10800000000ULL
@@ -56,11 +58,16 @@ · 9 unmodified lines
56#define DELTA_M_FRAC_NUM 1958#define DELTA_M_FRAC_NUM 19
57#define DELTA_M_FRAC_DEN 2000059#define DELTA_M_FRAC_DEN 20000
58 60
61struct si544_clk_desc {
62 unsigned long max_freq;
63 unsigned long xo_freq;
64};
65
59struct clk_si544 {66struct clk_si544 {
60 struct clk_hw hw;67 struct clk_hw hw;
61 struct regmap *regmap;68 struct regmap *regmap;
62 struct i2c_client *i2c_client;69 struct i2c_client *i2c_client;
63 unsigned long max_freq;70 const struct si544_clk_desc *chip_info;
64};71};
65#define to_clk_si544(_hw) container_of(_hw, struct clk_si544, hw)72#define to_clk_si544(_hw) container_of(_hw, struct clk_si544, hw)
66 73
@@ -79,6 +86,7 @@ struct clk_si544_muldiv { · 12 unmodified lines
79 u16 hs_div;86 u16 hs_div;
80 u8 ls_div_bits;87 u8 ls_div_bits;
81 s32 delta_m;88 s32 delta_m;
89 u32 xo_freq;
82};90};
83 91
84/* Enables or disables the output driver */92/* Enables or disables the output driver */
@@ -145,6 +153,8 @@ static int si544_get_muldiv(struct clk_si544 *data, · 60 unmodified lines
145 settings->delta_m = reg[0] << 8 | reg[1] << 16 | reg[2] << 24;153 settings->delta_m = reg[0] << 8 | reg[1] << 16 | reg[2] << 24;
146 settings->delta_m >>= 8;154 settings->delta_m >>= 8;
147 155
156 settings->xo_freq = data->chip_info->xo_freq;
157
148 return 0;158 return 0;
149}159}
150 160
@@ -193,7 +203,7 @@ static bool is_valid_frequency(const struct clk_si544 *data, · 42 unmodified lines
193 if (frequency < SI544_MIN_FREQ)203 if (frequency < SI544_MIN_FREQ)
194 return false;204 return false;
195 205
196 return frequency <= data->max_freq;206 return frequency <= data->chip_info->max_freq;
197}207}
198 208
199/* Calculate divider settings for a given frequency */209/* Calculate divider settings for a given frequency */
@@ -201,6 +211,7 @@ static int si544_calc_muldiv(struct clk_si544_muldiv *settings, · 1 unmodified line
201 unsigned long frequency)211 unsigned long frequency)
202{212{
203 u64 vco;213 u64 vco;
214 u32 fxo = settings->xo_freq;
204 u32 ls_freq;215 u32 ls_freq;
205 u32 tmp;216 u32 tmp;
206 u8 res;217 u8 res;
@@ -238,13 +249,13 @@ static int si544_calc_muldiv(struct clk_si544_muldiv *settings, · 31 unmodified lines
238 vco = (u64)ls_freq * settings->hs_div;249 vco = (u64)ls_freq * settings->hs_div;
239 250
240 /* Calculate the integer part of the feedback divider */251 /* Calculate the integer part of the feedback divider */
241 tmp = do_div(vco, FXO);252 tmp = do_div(vco, fxo);
242 settings->fb_div_int = vco;253 settings->fb_div_int = vco;
243 254
244 /* And the fractional bits using the remainder */255 /* And the fractional bits using the remainder */
245 vco = (u64)tmp << 32;256 vco = (u64)tmp << 32;
246 vco += FXO / 2; /* Round to nearest multiple */257 vco += fxo / 2; /* Round to nearest multiple */
247 do_div(vco, FXO);258 do_div(vco, fxo);
248 settings->fb_div_frac = vco;259 settings->fb_div_frac = vco;
249 260
250 /* Reset the frequency adjustment */261 /* Reset the frequency adjustment */
@@ -258,15 +269,16 @@ static unsigned long si544_calc_center_rate( · 7 unmodified lines
258 const struct clk_si544_muldiv *settings)269 const struct clk_si544_muldiv *settings)
259{270{
260 u32 d = settings->hs_div * BIT(settings->ls_div_bits);271 u32 d = settings->hs_div * BIT(settings->ls_div_bits);
272 u32 fxo = settings->xo_freq;
261 u64 vco;273 u64 vco;
262 274
263 /* Calculate VCO from the fractional part */275 /* Calculate VCO from the fractional part */
264 vco = (u64)settings->fb_div_frac * FXO;276 vco = (u64)settings->fb_div_frac * fxo;
265 vco += (FXO / 2);277 vco += (fxo / 2);
266 vco >>= 32;278 vco >>= 32;
267 279
268 /* Add the integer part of the VCO frequency */280 /* Add the integer part of the VCO frequency */
269 vco += (u64)settings->fb_div_int * FXO;281 vco += (u64)settings->fb_div_int * fxo;
270 282
271 /* Apply divider to obtain the generated frequency */283 /* Apply divider to obtain the generated frequency */
272 do_div(vco, d);284 do_div(vco, d);
@@ -446,7 +458,7 @@ static int si544_probe(struct i2c_client *client) · 173 unmodified lines
446 init.num_parents = 0;458 init.num_parents = 0;
447 data->hw.init = &init;459 data->hw.init = &init;
448 data->i2c_client = client;460 data->i2c_client = client;
449 data->max_freq = (uintptr_t)i2c_get_match_data(client);461 data->chip_info = i2c_get_match_data(client);
450 462
451 if (of_property_read_string(client->dev.of_node, "clock-output-names",463 if (of_property_read_string(client->dev.of_node, "clock-output-names",
452 &init.name))464 &init.name))
@@ -478,18 +490,54 @@ static int si544_probe(struct i2c_client *client) · 25 unmodified lines
478 return 0;490 return 0;
479}491}
480 492
493static const struct si544_clk_desc clk_si544a_info = {
494 .xo_freq = SI544_XO_FREQ,
495 .max_freq = 1500000000,
496};
497
498static const struct si544_clk_desc clk_si544b_info = {
499 .xo_freq = SI544_XO_FREQ,
500 .max_freq = 800000000,
501};
502
503static const struct si544_clk_desc clk_si544c_info = {
504 .xo_freq = SI544_XO_FREQ,
505 .max_freq = 325000000,
506};
507
508static const struct si544_clk_desc clk_si549a_info = {
509 .xo_freq = SI549_XO_FREQ,
510 .max_freq = 1500000000,
511};
512
513static const struct si544_clk_desc clk_si549b_info = {
514 .xo_freq = SI549_XO_FREQ,
515 .max_freq = 800000000,
516};
517
518static const struct si544_clk_desc clk_si549c_info = {
519 .xo_freq = SI549_XO_FREQ,
520 .max_freq = 325000000,
521};
522
481static const struct i2c_device_id si544_id[] = {523static const struct i2c_device_id si544_id[] = {
482 { .name = "si544a", .driver_data = 1500000000 },524 { .name = "si544a", .driver_data = (kernel_ulong_t)&clk_si544a_info },
483 { .name = "si544b", .driver_data = 800000000 },525 { .name = "si544b", .driver_data = (kernel_ulong_t)&clk_si544b_info },
484 { .name = "si544c", .driver_data = 350000000 },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 },
485 { }530 { }
486};531};
487MODULE_DEVICE_TABLE(i2c, si544_id);532MODULE_DEVICE_TABLE(i2c, si544_id);
488 533
489static const struct of_device_id clk_si544_of_match[] = {534static const struct of_device_id clk_si544_of_match[] = {
490 { .compatible = "silabs,si544a", .data = (void *)1500000000 },535 { .compatible = "silabs,si544a", .data = &clk_si544a_info },
491 { .compatible = "silabs,si544b", .data = (void *)800000000 },536 { .compatible = "silabs,si544b", .data = &clk_si544b_info },
492 { .compatible = "silabs,si544c", .data = (void *)350000000 },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 },
493 { }541 { }
494};542};
495MODULE_DEVICE_TABLE(of, clk_si544_of_match);543MODULE_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
204 int nums, struct eswin_clock_data *data)204 int nums, struct eswin_clock_data *data)
205{205{
206 struct eswin_clk_pll *p_clk = NULL;206 struct eswin_clk_pll *p_clk = NULL;
207 struct clk_init_data init;207 struct clk_init_data init = {};
208 struct clk_hw *clk_hw;208 struct clk_hw *clk_hw;
209 int i, ret;209 int i, ret;
210 210
@@ -419,7 +419,7 @@ struct clk_hw *eswin_register_clkdiv(struct device *dev, unsigned int id, · 208 unmodified lines
419 unsigned long priv_flag, spinlock_t *lock)419 unsigned long priv_flag, spinlock_t *lock)
420{420{
421 struct eswin_divider_clock *dclk;421 struct eswin_divider_clock *dclk;
422 struct clk_init_data init;422 struct clk_init_data init = {};
423 struct clk_hw *clk_hw;423 struct clk_hw *clk_hw;
424 int ret;424 int ret;
425 425
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
114static int hi3660_stub_clk_probe(struct platform_device *pdev)114static int hi3660_stub_clk_probe(struct platform_device *pdev)
115{115{
116 struct device *dev = &pdev->dev;116 struct device *dev = &pdev->dev;
117 struct resource *res;
118 unsigned int i;117 unsigned int i;
119 int ret;118 int ret;
120 119
@@ -129,12 +128,9 @@ static int hi3660_stub_clk_probe(struct platform_device *pdev) · 8 unmodified lines
129 if (IS_ERR(stub_clk_chan.mbox))128 if (IS_ERR(stub_clk_chan.mbox))
130 return PTR_ERR(stub_clk_chan.mbox);129 return PTR_ERR(stub_clk_chan.mbox);
131 130
132 res = platform_get_resource(pdev, IORESOURCE_MEM, 0);131 freq_reg = devm_platform_ioremap_resource(pdev, 0);
133 if (!res)132 if (IS_ERR(freq_reg))
134 return -EINVAL;133 return PTR_ERR(freq_reg);
135 freq_reg = devm_ioremap(dev, res->start, resource_size(res));
136 if (!freq_reg)
137 return -ENOMEM;
138 134
139 freq_reg += HI3660_STUB_CLOCK_DATA;135 freq_reg += HI3660_STUB_CLOCK_DATA;
140 136
drivers/clk/mediatek/Kconfig+10−0
@@ -537,6 +537,16 @@ config COMMON_CLK_MT8173_IMGSYS · 536 unmodified lines
537 help537 help
538 This driver supports MediaTek MT8173 imgsys clocks.538 This driver supports MediaTek MT8173 imgsys clocks.
539 539
540config 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
540config COMMON_CLK_MT8173_MMSYS550config COMMON_CLK_MT8173_MMSYS
541 tristate "Clock driver for MediaTek MT8173 mmsys"551 tristate "Clock driver for MediaTek MT8173 mmsys"
542 depends on COMMON_CLK_MT8173552 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
82obj-$(CONFIG_COMMON_CLK_MT8173) += clk-mt8173-apmixedsys.o clk-mt8173-infracfg.o \82obj-$(CONFIG_COMMON_CLK_MT8173) += clk-mt8173-apmixedsys.o clk-mt8173-infracfg.o \
83 clk-mt8173-pericfg.o clk-mt8173-topckgen.o83 clk-mt8173-pericfg.o clk-mt8173-topckgen.o
84obj-$(CONFIG_COMMON_CLK_MT8173_IMGSYS) += clk-mt8173-img.o84obj-$(CONFIG_COMMON_CLK_MT8173_IMGSYS) += clk-mt8173-img.o
85obj-$(CONFIG_COMMON_CLK_MT8173_MFGTOP) += clk-mt8173-mfgtop.o
85obj-$(CONFIG_COMMON_CLK_MT8173_MMSYS) += clk-mt8173-mm.o86obj-$(CONFIG_COMMON_CLK_MT8173_MMSYS) += clk-mt8173-mm.o
86obj-$(CONFIG_COMMON_CLK_MT8173_VDECSYS) += clk-mt8173-vdecsys.o87obj-$(CONFIG_COMMON_CLK_MT8173_VDECSYS) += clk-mt8173-vdecsys.o
87obj-$(CONFIG_COMMON_CLK_MT8173_VENCSYS) += clk-mt8173-vencsys.o88obj-$(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
102 102
103 ret = devm_of_clk_add_hw_provider(&pdev->dev, of_clk_hw_onecell_get,103 ret = devm_of_clk_add_hw_provider(&pdev->dev, of_clk_hw_onecell_get,
104 clk_data);104 clk_data);
105 if (ret)105 if (ret) {
106 dev_err(&pdev->dev,106 dev_err(&pdev->dev,
107 "Failed to register clock provider: %d\n", ret);107 "Failed to register clock provider: %d\n", ret);
108 mtk_clk_unregister_plls(apmixedsys_plls, ARRAY_SIZE(apmixedsys_plls),
109 clk_data);
110 }
108 111
109 return ret;112 return ret;
110}113}
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
63 { .compatible = "mediatek,mt6735-vdecsys", .data = &vdecsys_clks },63 { .compatible = "mediatek,mt6735-vdecsys", .data = &vdecsys_clks },
64 { /* sentinel */ }64 { /* sentinel */ }
65};65};
66MODULE_DEVICE_TABLE(of, of_match_mt6735_vdecsys);
66 67
67static struct platform_driver clk_mt6735_vdecsys = {68static struct platform_driver clk_mt6735_vdecsys = {
68 .probe = mtk_clk_simple_probe,69 .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
37 { .compatible = "mediatek,mt6735-vencsys", .data = &vencsys_clks },37 { .compatible = "mediatek,mt6735-vencsys", .data = &vencsys_clks },
38 { /* sentinel */ }38 { /* sentinel */ }
39};39};
40MODULE_DEVICE_TABLE(of, of_match_mt6735_vencsys);
40 41
41static struct platform_driver clk_mt6735_vencsys = {42static struct platform_driver clk_mt6735_vencsys = {
42 .probe = mtk_clk_simple_probe,43 .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
409 GATE_MTK_FLAGS(_id, _name, _parent, &infra_cg_regs, _shift, \409 GATE_MTK_FLAGS(_id, _name, _parent, &infra_cg_regs, _shift, \
410 &mtk_clk_gate_ops_setclr, CLK_IS_CRITICAL)410 &mtk_clk_gate_ops_setclr, CLK_IS_CRITICAL)
411 411
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
412static const struct mtk_gate infra_clks[] = {415static const struct mtk_gate infra_clks[] = {
413 GATE_DUMMY(CLK_DUMMY, "infra_dummy"),416 GATE_DUMMY(CLK_DUMMY, "infra_dummy"),
414 GATE_ICG(CLK_INFRA_PMIC_WRAP, "pmic_wrap_ck", "axi_sel", 23),417 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
419 GATE_ICG(CLK_INFRA_CPUM, "cpum_ck", "cpum_tck_in", 15),422 GATE_ICG(CLK_INFRA_CPUM, "cpum_ck", "cpum_tck_in", 15),
420 GATE_ICG_AO(CLK_INFRA_M4U, "m4u_ck", "mem_sel", 8),423 GATE_ICG_AO(CLK_INFRA_M4U, "m4u_ck", "mem_sel", 8),
421 GATE_ICG(CLK_INFRA_MFGAXI, "mfgaxi_ck", "axi_sel", 7),424 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),
423 GATE_ICG(CLK_INFRA_AUDIO, "audio_ck", "aud_intbus_sel", 5),426 GATE_ICG(CLK_INFRA_AUDIO, "audio_ck", "aud_intbus_sel", 5),
424 GATE_ICG(CLK_INFRA_MFG_BUS, "mfg_bus_ck", "axi_sel", 2),427 GATE_ICG(CLK_INFRA_MFG_BUS, "mfg_bus_ck", "axi_sel", 2),
425 GATE_ICG(CLK_INFRA_SMI, "smi_ck", "smi_sel", 1),428 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
27static 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. */
37static 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
44struct 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
66static 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
98static 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
111static 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
194del_pd_provider:
195 of_genpd_del_provider(node);
196remove_pd:
197 pm_genpd_remove(&data->genpd);
198del_clk_provider:
199 of_clk_del_provider(node);
200put_26m_clk:
201 clk_put(data->clk_26m);
202unregister_clks:
203 mtk_clk_unregister_gates(mfg_clks, ARRAY_SIZE(mfg_clks), data->clk_data);
204put_pm_runtime:
205 pm_runtime_put_sync(dev);
206put_of_node:
207 of_node_put(data->parent_pd.np);
208 return ret;
209}
210
211static 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
225static const struct of_device_id of_match_clk_mt8173_mfgtop[] = {
226 { .compatible = "mediatek,mt8173-mfgtop" },
227 { /* sentinel */ }
228};
229MODULE_DEVICE_TABLE(of, of_match_clk_mt8173_mfgtop);
230
231static 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};
239module_platform_driver(clk_mt8173_mfgtop_drv);
240
241MODULE_DESCRIPTION("MediaTek MT8173 mfgtop clock driver");
242MODULE_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
629 .val_bits = 32,629 .val_bits = 32,
630 .reg_stride = 4,630 .reg_stride = 4,
631 .max_register = 0x1000,631 .max_register = 0x1000,
632 .fast_io = true,
633};632};
634 633
635static int clk_mt8196_vlp_probe(struct platform_device *pdev)634static 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
197 kfree(fh);197 kfree(fh);
198}198}
199 199
200static 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
200int mtk_clk_register_pllfhs(struct device *dev,244int mtk_clk_register_pllfhs(struct device *dev,
201 const struct mtk_pll_data *plls, int num_plls,245 const struct mtk_pll_data *plls, int num_plls,
202 struct mtk_pllfh_data *pllfhs, int num_fhs,246 struct mtk_pllfh_data *pllfhs, int num_fhs,
203 struct clk_hw_onecell_data *clk_data)247 struct clk_hw_onecell_data *clk_data)
204{248{
205 void __iomem *base;249 void __iomem *base, *fhctl_base = NULL;
206 int i;250 int i;
207 struct clk_hw *hw;251 struct clk_hw *hw;
208 252
@@ -238,24 +282,8 @@ int mtk_clk_register_pllfhs(struct device *dev, · 29 unmodified lines
238 return 0;282 return 0;
239 283
240err:284err:
241 while (--i >= 0) {285 mtk_clk_cleanup_pllfhs(base, plls, i, fhctl_base, pllfhs, num_fhs,
242 const struct mtk_pll_data *pll = &plls[i];286 clk_data);
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
259 return PTR_ERR(hw);287 return PTR_ERR(hw);
260}288}
261EXPORT_SYMBOL_GPL(mtk_clk_register_pllfhs);289EXPORT_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
264 struct mtk_pllfh_data *pllfhs, int num_fhs,292 struct mtk_pllfh_data *pllfhs, int num_fhs,
265 struct clk_hw_onecell_data *clk_data)293 struct clk_hw_onecell_data *clk_data)
266{294{
267 void __iomem *base = NULL, *fhctl_base = NULL;
268 int i;
269
270 if (!clk_data)295 if (!clk_data)
271 return;296 return;
272 297
273 for (i = num_plls; i > 0; i--) {298 mtk_clk_cleanup_pllfhs(NULL, plls, num_plls, NULL, pllfhs,
274 const struct mtk_pll_data *pll = &plls[i - 1];299 num_fhs, clk_data);
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);
300}300}
301EXPORT_SYMBOL_GPL(mtk_clk_unregister_pllfhs);301EXPORT_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
114 cells[i].bits = BIT(2);114 cells[i].bits = BIT(2);
115 cells[i].flags = 0;115 cells[i].flags = 0;
116 cells[i].lock = apbc_gate_clks[i].lock;116 cells[i].lock = apbc_gate_clks[i].lock;
117 };117 }
118 118
119 mmp_clk_reset_register(np, cells, nr_cells);119 mmp_clk_reset_register(np, cells, nr_cells);
120}120}
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
61 cells[i].bits = BIT(2);61 cells[i].bits = BIT(2);
62 cells[i].flags = 0;62 cells[i].flags = 0;
63 cells[i].lock = apbcp_gate_clks[i].lock;63 cells[i].lock = apbcp_gate_clks[i].lock;
64 };64 }
65 65
66 mmp_clk_reset_register(np, cells, nr_cells);66 mmp_clk_reset_register(np, cells, nr_cells);
67}67}
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
153static int clk_cpu_set_rate(struct clk_hw *hwclk, unsigned long rate,153static int clk_cpu_set_rate(struct clk_hw *hwclk, unsigned long rate,
154 unsigned long parent_rate)154 unsigned long parent_rate)
155{155{
156 if (__clk_is_enabled(hwclk->clk))156 if (clk_hw_is_enabled(hwclk))
157 return clk_cpu_on_set_rate(hwclk, rate, parent_rate);157 return clk_cpu_on_set_rate(hwclk, rate, parent_rate);
158 else158 else
159 return clk_cpu_off_set_rate(hwclk, rate, parent_rate);159 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
260 if (pll->data->switch2pll_en)260 if (pll->data->switch2pll_en)
261 CLKGEN_WRITE(pll, switch2pll, 0);261 CLKGEN_WRITE(pll, switch2pll, 0);
262 262
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__);
264 }264 }
265 265
266 return ret;266 return ret;
@@ -295,7 +295,7 @@ static void __clkgen_pll_disable(struct clk_hw *hw) · 28 unmodified lines
295 295
296 CLKGEN_WRITE(pll, pdn_ctrl, 1);296 CLKGEN_WRITE(pll, pdn_ctrl, 1);
297 297
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__);
299}299}
300 300
301static void clkgen_pll_disable(struct clk_hw *hw)301static 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
405 &req->rate);405 &req->rate);
406 else {406 else {
407 pr_debug("%s: %s rate %ld Invalid\n", __func__,407 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);
409 req->rate = 0;409 req->rate = 0;
410 410
411 return 0;411 return 0;
412 }412 }
413 413
414 pr_debug("%s: %s new rate %ld [ndiv=%u] [idf=%u]\n",414 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),
416 req->rate, (unsigned int)params.ndiv,416 req->rate, (unsigned int)params.ndiv,
417 (unsigned int)params.idf);417 (unsigned int)params.idf);
418 418
@@ -434,7 +434,7 @@ static int set_rate_stm_pll3200c32(struct clk_hw *hw, unsigned long rate, · 15 unmodified lines
434 clk_pll3200c32_get_rate(parent_rate, &params, &hwrate);434 clk_pll3200c32_get_rate(parent_rate, &params, &hwrate);
435 435
436 pr_debug("%s: %s new rate %ld [ndiv=0x%x] [idf=0x%x]\n",436 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),
438 hwrate, (unsigned int)params.ndiv,438 hwrate, (unsigned int)params.ndiv,
439 (unsigned int)params.idf);439 (unsigned int)params.idf);
440 440
@@ -547,7 +547,7 @@ static unsigned long recalc_stm_pll4600c28(struct clk_hw *hw, · 106 unmodified lines
547 547
548 clk_pll4600c28_get_rate(parent_rate, &params, &rate);548 clk_pll4600c28_get_rate(parent_rate, &params, &rate);
549 549
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);
551 551
552 return rate;552 return rate;
553}553}
@@ -562,14 +562,14 @@ static int stm_pll4600c28_determine_rate(struct clk_hw *hw, · 8 unmodified lines
562 &req->rate);562 &req->rate);
563 } else {563 } else {
564 pr_debug("%s: %s rate %ld Invalid\n", __func__,564 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);
566 req->rate = 0;566 req->rate = 0;
567 567
568 return 0;568 return 0;
569 }569 }
570 570
571 pr_debug("%s: %s new rate %ld [ndiv=%u] [idf=%u]\n",571 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),
573 req->rate, (unsigned int)params.ndiv,573 req->rate, (unsigned int)params.ndiv,
574 (unsigned int)params.idf);574 (unsigned int)params.idf);
575 575
@@ -591,12 +591,12 @@ static int set_rate_stm_pll4600c28(struct clk_hw *hw, unsigned long rate, · 15 unmodified lines
591 clk_pll4600c28_get_rate(parent_rate, &params, &hwrate);591 clk_pll4600c28_get_rate(parent_rate, &params, &hwrate);
592 } else {592 } else {
593 pr_debug("%s: %s rate %ld Invalid\n", __func__,593 pr_debug("%s: %s rate %ld Invalid\n", __func__,
594 __clk_get_name(hw->clk), rate);594 clk_hw_get_name(hw), rate);
595 return -EINVAL;595 return -EINVAL;
596 }596 }
597 597
598 pr_debug("%s: %s new rate %ld [ndiv=0x%x] [idf=0x%x]\n",598 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),
600 hwrate, (unsigned int)params.ndiv,600 hwrate, (unsigned int)params.ndiv,
601 (unsigned int)params.idf);601 (unsigned int)params.idf);
602 602
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
575 break;575 break;
576 case 9600000:576 case 9600000:
577 case 28800000:577 case 28800000:
578 case 48000000:
578 /*579 /*
579 * PLL_P_OUT1 rate is not listed in PLLA table580 * PLL_P_OUT1 rate is not listed in PLLA table
580 */581 */
drivers/clk/tegra/clk-tegra114.c+25−14
@@ -620,10 +620,6 @@ static const char *mux_plld_out0_plld2_out0[] = { · 619 unmodified lines
620};620};
621#define mux_plld_out0_plld2_out0_idx NULL621#define mux_plld_out0_plld2_out0_idx NULL
622 622
623static const char *mux_pllmcp_clkm[] = {
624 "pll_m_out0", "pll_c_out0", "pll_p_out0", "clk_m", "pll_m_ud",
625};
626
627static const struct clk_div_table pll_re_div_table[] = {623static const struct clk_div_table pll_re_div_table[] = {
628 { .val = 0, .div = 1 },624 { .val = 0, .div = 1 },
629 { .val = 1, .div = 2 },625 { .val = 1, .div = 2 },
@@ -670,7 +666,6 @@ static struct tegra_clk tegra114_clks[tegra_clk_max] __initdata = { · 40 unmodified lines
670 [tegra_clk_csi] = { .dt_id = TEGRA114_CLK_CSI, .present = true },666 [tegra_clk_csi] = { .dt_id = TEGRA114_CLK_CSI, .present = true },
671 [tegra_clk_i2c2] = { .dt_id = TEGRA114_CLK_I2C2, .present = true },667 [tegra_clk_i2c2] = { .dt_id = TEGRA114_CLK_I2C2, .present = true },
672 [tegra_clk_uartc] = { .dt_id = TEGRA114_CLK_UARTC, .present = true },668 [tegra_clk_uartc] = { .dt_id = TEGRA114_CLK_UARTC, .present = true },
673 [tegra_clk_emc] = { .dt_id = TEGRA114_CLK_EMC, .present = true },
674 [tegra_clk_usb2] = { .dt_id = TEGRA114_CLK_USB2, .present = true },669 [tegra_clk_usb2] = { .dt_id = TEGRA114_CLK_USB2, .present = true },
675 [tegra_clk_usb3] = { .dt_id = TEGRA114_CLK_USB3, .present = true },670 [tegra_clk_usb3] = { .dt_id = TEGRA114_CLK_USB3, .present = true },
676 [tegra_clk_vde_8] = { .dt_id = TEGRA114_CLK_VDE, .present = true },671 [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
1051 periph_clk_enb_refcnt);1046 periph_clk_enb_refcnt);
1052 clks[TEGRA114_CLK_CSUS] = clk;1047 clks[TEGRA114_CLK_CSUS] = clk;
1053 1048
1054 /* emc mux */1049 clk = tegra_clk_register_mc("mc", "emc", clk_base + CLK_SOURCE_EMC,
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,
1062 &emc_lock);1050 &emc_lock);
1063 clks[TEGRA114_CLK_MC] = clk;1051 clks[TEGRA114_CLK_MC] = clk;
1064 1052
@@ -1324,6 +1312,26 @@ static int tegra114_reset_deassert(unsigned long id) · 259 unmodified lines
1324 return 0;1312 return 0;
1325}1313}
1326 1314
1315static 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
1327static void __init tegra114_clock_init(struct device_node *np)1335static void __init tegra114_clock_init(struct device_node *np)
1328{1336{
1329 struct device_node *node;1337 struct device_node *node;
@@ -1371,7 +1379,10 @@ static void __init tegra114_clock_init(struct device_node *np) · 41 unmodified lines
1371 tegra_init_special_resets(1, tegra114_reset_assert,1379 tegra_init_special_resets(1, tegra114_reset_assert,
1372 tegra114_reset_deassert);1380 tegra114_reset_deassert);
1373 1381
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
1375 tegra_register_devclks(devclks, ARRAY_SIZE(devclks));1386 tegra_register_devclks(devclks, ARRAY_SIZE(devclks));
1376 1387
1377 tegra_clk_apply_init_table = tegra114_clock_apply_init_table;1388 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
537 537
538 clk = clk_register(NULL, &tegra->hw);538 clk = clk_register(NULL, &tegra->hw);
539 if (IS_ERR(clk)) {539 if (IS_ERR(clk)) {
540 of_node_put(tegra->emc_node);
540 kfree(tegra);541 kfree(tegra);
541 return clk;542 return clk;
542 }543 }
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
1460 udelay(1);1460 udelay(1);
1461 1461
1462 pr_debug("%s: dynamic ramp to m = %u n = %u p = %u, Fout = %lu kHz\n",1462 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,
1464 cfg->input_rate / cfg->m * cfg->n /1464 cfg->input_rate / cfg->m * cfg->n /
1465 pllx->params->pdiv_tohw[cfg->p].pdiv / 1000);1465 pllx->params->pdiv_tohw[cfg->p].pdiv / 1000);
1466 1466
drivers/clk/ultrarisc/Kconfig+18−0
@@ -0,0 +1,18 @@
1# SPDX-License-Identifier: GPL-2.0-only
2
3config CLK_ULTRARISC
4 tristate
5 depends on OF
6 depends on ARCH_ULTRARISC || COMPILE_TEST
7
8config 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
3obj-$(CONFIG_CLK_ULTRARISC) += clk-ultrarisc.o
4obj-$(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
26static 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
36static 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
77static 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
92static 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
106static 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
119static 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
132static int dp1000_clk_probe(struct platform_device *pdev)
133{
134 return ultrarisc_clk_probe(pdev, &dp1000_clk_soc_data);
135}
136
137static const struct of_device_id dp1000_clk_of_match[] = {
138 { .compatible = "ultrarisc,dp1000-clk" },
139 { }
140};
141MODULE_DEVICE_TABLE(of, dp1000_clk_of_match);
142
143static 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};
150module_platform_driver(dp1000_clk_driver);
151
152MODULE_IMPORT_NS("CLK_ULTRARISC");
153MODULE_DESCRIPTION("UltraRISC DP1000 clock controller");
154MODULE_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
15struct ultrarisc_pll_clk {
16 struct clk_hw hw;
17 void __iomem *base;
18 const struct ultrarisc_pll_layout *layout;
19};
20
21struct 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
30static 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
37static 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
74static const struct clk_ops ultrarisc_pll_ro_ops = {
75 .recalc_rate = ultrarisc_pll_recalc_rate,
76};
77
78static 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
91static 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
100static 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
132static 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
138static 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
169static struct clk_hw *
170ultrarisc_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
208static 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
240static 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
268static 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
304static 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
341int 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}
396EXPORT_SYMBOL_NS_GPL(ultrarisc_clk_probe, "CLK_ULTRARISC");
397
398MODULE_DESCRIPTION("UltraRISC clock core driver");
399MODULE_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
9struct 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
19struct ultrarisc_pll_desc {
20 u32 id;
21 const char *name;
22};
23
24struct ultrarisc_fixed_factor_desc {
25 u32 id;
26 const char *name;
27 u32 parent_id;
28 u32 mult;
29 u32 div;
30};
31
32struct 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
46struct 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
55struct 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
68int 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
160 return ERR_PTR(-ENOMEM);160 return ERR_PTR(-ENOMEM);
161 161
162 init.name = kasprintf(GFP_KERNEL, "%s_%d", PLT_CLK_NAME_BASE, id);162 init.name = kasprintf(GFP_KERNEL, "%s_%d", PLT_CLK_NAME_BASE, id);
163 if (!init.name)
164 return ERR_PTR(-ENOMEM);
165
163 init.ops = &plt_clk_ops;166 init.ops = &plt_clk_ops;
164 init.flags = 0;167 init.flags = 0;
165 init.parent_names = parent_names;168 init.parent_names = parent_names;
drivers/clk/xilinx/clk-xlnx-clock-wizard.c+139−3
@@ -35,6 +35,10 @@ · 34 unmodified lines
35#define WZRD_DIVCLK 2135#define WZRD_DIVCLK 21
36#define WZRD_CLKFBOUT_4 5136#define WZRD_CLKFBOUT_4 51
37#define WZRD_CLKFBOUT_3 4837#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
38#define WZRD_DUTY_CYCLE 242#define WZRD_DUTY_CYCLE 2
39#define WZRD_O_DIV 443#define WZRD_O_DIV 4
40 44
@@ -49,6 +53,10 @@ · 8 unmodified lines
49#define WZRD_P5FEDGE_SHIFT 1553#define WZRD_P5FEDGE_SHIFT 15
50#define WZRD_CLKOUT0_PREDIV2 BIT(11)54#define WZRD_CLKOUT0_PREDIV2 BIT(11)
51#define WZRD_EDGE_SHIFT 855#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)
52 60
53#define WZRD_CLKFBOUT_MULT_SHIFT 861#define WZRD_CLKFBOUT_MULT_SHIFT 8
54#define WZRD_CLKFBOUT_MULT_MASK (0xff << WZRD_CLKFBOUT_MULT_SHIFT)62#define WZRD_CLKFBOUT_MULT_MASK (0xff << WZRD_CLKFBOUT_MULT_SHIFT)
@@ -105,7 +113,6 @@ · 50 unmodified lines
105#define VER_WZRD_VCO_MAX 4320000000ULL113#define VER_WZRD_VCO_MAX 4320000000ULL
106#define VER_WZRD_O_MIN 2114#define VER_WZRD_O_MIN 2
107#define VER_WZRD_O_MAX 511115#define VER_WZRD_O_MAX 511
108#define WZRD_MIN_ERR 20000
109#define WZRD_FRAC_POINTS 1000116#define WZRD_FRAC_POINTS 1000
110 117
111/* Get the mask from width */118/* 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
406 if (o < omin || o > omax)413 if (o < omin || o > omax)
407 continue;414 continue;
408 freq = DIV_ROUND_CLOSEST_ULL(vco_freq, o);415 freq = DIV_ROUND_CLOSEST_ULL(vco_freq, o);
409 diff = freq - rate;416 diff = abs(freq - rate);
410 if (diff < best_diff) {417 if (diff < best_diff) {
411 best_diff = diff;418 best_diff = diff;
412 divider->m = m >> 3;419 divider->m = m >> 3;
@@ -414,10 +421,13 @@ static int clk_wzrd_get_divisors(struct clk_hw *hw, unsigned long rate, · 1 unmodified line
414 divider->d = d;421 divider->d = d;
415 divider->o = o >> 3;422 divider->o = o >> 3;
416 divider->o_frac = (o - (divider->o << 3)) * 125;423 divider->o_frac = (o - (divider->o << 3)) * 125;
424
425 if (!diff)
426 return 0;
417 }427 }
418 }428 }
419 }429 }
420 return best_diff < WZRD_MIN_ERR ? 0 : -EBUSY;430 return best_diff != -1ULL ? 0 : -EBUSY;
421}431}
422 432
423static int clk_wzrd_reconfig(struct clk_wzrd_divider *divider, void __iomem *div_addr)433static 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
440 WZRD_USEC_POLL, WZRD_TIMEOUT_POLL);450 WZRD_USEC_POLL, WZRD_TIMEOUT_POLL);
441}451}
442 452
453struct wzrd_pll_filter {
454 u32 m_min;
455 u32 m_max;
456 u32 cp;
457 u32 res;
458};
459
460static 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
496struct 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
504static 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
532static 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
443static int clk_wzrd_dynamic_ver_all_nolock(struct clk_hw *hw, unsigned long rate,577static int clk_wzrd_dynamic_ver_all_nolock(struct clk_hw *hw, unsigned long rate,
444 unsigned long parent_rate)578 unsigned long parent_rate)
445{579{
@@ -471,6 +605,8 @@ static int clk_wzrd_dynamic_ver_all_nolock(struct clk_hw *hw, unsigned long rate · 25 unmodified lines
471 writel(regval1, divider->base + WZRD_CLK_CFG_REG(1,605 writel(regval1, divider->base + WZRD_CLK_CFG_REG(1,
472 WZRD_CLKFBOUT_2));606 WZRD_CLKFBOUT_2));
473 607
608 clk_wzrd_update_cp_res_lock(divider, m);
609
474 value2 = divider->d;610 value2 = divider->d;
475 edged = value2 % WZRD_DUTY_CYCLE;611 edged = value2 % WZRD_DUTY_CYCLE;
476 regh = (value2 / WZRD_DUTY_CYCLE);612 regh = (value2 / WZRD_DUTY_CYCLE);
drivers/reset/Kconfig+13−0
@@ -311,6 +311,19 @@ config RESET_SKY1 · 310 unmodified lines
311 help311 help
312 This enables the reset controller for Cix Sky1.312 This enables the reset controller for Cix Sky1.
313 313
314config 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
314config RESET_SOCFPGA327config RESET_SOCFPGA
315 bool "SoCFPGA Reset Driver" if COMPILE_TEST && (!ARM || !ARCH_INTEL_SOCFPGA)328 bool "SoCFPGA Reset Driver" if COMPILE_TEST && (!ARM || !ARCH_INTEL_SOCFPGA)
316 default ARM && ARCH_INTEL_SOCFPGA329 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
40obj-$(CONFIG_RESET_SCMI) += reset-scmi.o40obj-$(CONFIG_RESET_SCMI) += reset-scmi.o
41obj-$(CONFIG_RESET_SIMPLE) += reset-simple.o41obj-$(CONFIG_RESET_SIMPLE) += reset-simple.o
42obj-$(CONFIG_RESET_SKY1) += reset-sky1.o42obj-$(CONFIG_RESET_SKY1) += reset-sky1.o
43obj-$(CONFIG_RESET_SKY1_AUDSS) += reset-sky1-audss.o
43obj-$(CONFIG_RESET_SOCFPGA) += reset-socfpga.o44obj-$(CONFIG_RESET_SOCFPGA) += reset-socfpga.o
44obj-$(CONFIG_RESET_SUNPLUS) += reset-sunplus.o45obj-$(CONFIG_RESET_SUNPLUS) += reset-sunplus.o
45obj-$(CONFIG_RESET_SUNXI) += reset-sunxi.o46obj-$(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
21struct sky1_audss_reset_map {
22 unsigned int offset;
23 unsigned int mask;
24};
25
26struct sky1_audss_reset {
27 struct reset_controller_dev rcdev;
28 struct regmap *regmap;
29 const struct sky1_audss_reset_map *map;
30};
31
32static 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
51static 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
56static 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
72static 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
78static 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
84static const struct reset_control_ops sky1_audss_reset_ops = {
85 .assert = sky1_audss_reset_assert,
86 .deassert = sky1_audss_reset_deassert,
87};
88
89static 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
113static const struct auxiliary_device_id sky1_audss_reset_ids[] = {
114 { .name = "clk_sky1_audss.reset" },
115 { }
116};
117MODULE_DEVICE_TABLE(auxiliary, sky1_audss_reset_ids);
118
119static struct auxiliary_driver sky1_audss_reset_driver = {
120 .probe = sky1_audss_reset_probe,
121 .id_table = sky1_audss_reset_ids,
122};
123module_auxiliary_driver(sky1_audss_reset_driver);
124
125MODULE_AUTHOR("Joakim Zhang <joakim.zhang@cixtech.com>");
126MODULE_DESCRIPTION("Cix Sky1 Audio Subsystem reset driver");
127MODULE_LICENSE("GPL");
include/dt-bindings/clock/aspeed,ast2700-scu.h+2−0
@@ -163,5 +163,7 @@ · 162 unmodified lines
163#define SCU1_CLK_GATE_PORTDUSB2CLK 85163#define SCU1_CLK_GATE_PORTDUSB2CLK 85
164#define SCU1_CLK_GATE_LTPI1TXCLK 86164#define SCU1_CLK_GATE_LTPI1TXCLK 86
165#define SCU1_CLK_I3C 87165#define SCU1_CLK_I3C 87
166#define SCU1_CLK_HPLL_DIV4 88
167#define SCU1_CLK_PECI 89
166 168
167#endif169#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
243#define CLK_IMG_FD 7243#define CLK_IMG_FD 7
244#define CLK_IMG_NR_CLK 8244#define CLK_IMG_NR_CLK 8
245 245
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
246/* MM_SYS */253/* MM_SYS */
247 254
248#define CLK_MM_SMI_COMMON 1255#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
62#define EN7581_CPU_TIMER_RST 5062#define EN7581_CPU_TIMER_RST 50
63#define EN7581_PCIE_HB_RST 5163#define EN7581_PCIE_HB_RST 51
64#define EN7581_XPON_MAC_RST 5264#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
65 69
66#endif /* __DT_BINDINGS_RESET_CONTROLLER_AIROHA_EN7581_H_ */70#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
502 */502 */
503int __must_check devm_clk_bulk_get_optional(struct device *dev, int num_clks,503int __must_check devm_clk_bulk_get_optional(struct device *dev, int num_clks,
504 struct clk_bulk_data *clks);504 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 */
519int __must_check devm_clk_bulk_get_enable(struct device *dev, int num_clks,
520 struct clk_bulk_data *clks);
505/**521/**
506 * devm_clk_bulk_get_optional_enable - Get and enable optional bulk clocks (managed)522 * devm_clk_bulk_get_optional_enable - Get and enable optional bulk clocks (managed)
507 * @dev: device for clock "consumer"523 * @dev: device for clock "consumer"
@@ -951,8 +967,8 @@ int clk_set_parent(struct clk *clk, struct clk *parent); · 443 unmodified lines
951 * clk_get_parent - get the parent clock source for this clock967 * clk_get_parent - get the parent clock source for this clock
952 * @clk: clock source968 * @clk: clock source
953 *969 *
954 * Returns struct clk corresponding to parent clock source, or970 * Returns struct clk corresponding to parent clock source, or NULL
955 * valid IS_ERR() condition containing errno.971 * if clk is NULL.
956 */972 */
957struct clk *clk_get_parent(struct clk *clk);973struct clk *clk_get_parent(struct clk *clk);
958 974
@@ -1052,6 +1068,13 @@ static inline int __must_check devm_clk_bulk_get_optional(struct device *dev, · 93 unmodified lines
1052 return 0;1068 return 0;
1053}1069}
1054 1070
1071static 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
1055static inline int __must_check devm_clk_bulk_get_optional_enable(struct device *dev,1078static inline int __must_check devm_clk_bulk_get_optional_enable(struct device *dev,
1056 int num_clks,1079 int num_clks,
1057 struct clk_bulk_data *clks)1080 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