Merge branches 'clk-ti', 'clk-analog', 'clk-trace', 'clk-at91' and 'clk-silabs' into...
authorStephen Boyd <sboyd@kernel.org>
Mon, 21 Dec 2020 01:17:51 +0000 (17:17 -0800)
committerStephen Boyd <sboyd@kernel.org>
Mon, 21 Dec 2020 01:17:51 +0000 (17:17 -0800)
 - Add some trace points for clk_set_rate() "range" functions
 - DVFS support for AT91 clk driver

* clk-ti:
  clk: ti: omap5: Fix reboot DPLL lock failure when using ABE TIMERs
  clk: ti: Fix memleak in ti_fapll_synth_setup

* clk-analog:
  clk: axi-clkgen: move the OF table at the bottom of the file
  clk: axi-clkgen: wrap limits in a struct and keep copy on the state object
  dt-bindings: clock: adi,axi-clkgen: convert old binding to yaml format

* clk-trace:
  clk: Trace clk_set_rate() "range" functions

* clk-at91:
  clk: at91: sam9x60: remove atmel,osc-bypass support
  clk: at91: sama7g5: register cpu clock
  clk: at91: clk-master: re-factor master clock
  clk: at91: sama7g5: do not allow cpu pll to go higher than 1GHz
  clk: at91: sama7g5: decrease lower limit for MCK0 rate
  clk: at91: sama7g5: remove mck0 from parent list of other clocks
  clk: at91: clk-sam9x60-pll: allow runtime changes for pll
  clk: at91: sama7g5: add 5th divisor for mck0 layout and characteristics
  clk: at91: clk-master: add 5th divisor for mck master
  clk: at91: sama7g5: allow SYS and CPU PLLs to be exported and referenced in DT
  dt-bindings: clock: at91: add sama7g5 pll defines
  clk: at91: sama7g5: fix compilation error

* clk-silabs:
  clk: si5351: Wait for bit clear after PLL reset

120 files changed:
Documentation/devicetree/bindings/clock/adi,axi-clkgen.yaml [new file with mode: 0644]
Documentation/devicetree/bindings/clock/axi-clkgen.txt [deleted file]
Documentation/devicetree/bindings/clock/fsl,flexspi-clock.yaml [new file with mode: 0644]
Documentation/devicetree/bindings/clock/qcom,aoncc-sm8250.yaml [new file with mode: 0644]
Documentation/devicetree/bindings/clock/qcom,audiocc-sm8250.yaml [new file with mode: 0644]
Documentation/devicetree/bindings/clock/qcom,gcc-sdx55.yaml [new file with mode: 0644]
Documentation/devicetree/bindings/clock/qcom,rpmhcc.yaml
Documentation/devicetree/bindings/clock/qcom,sc7180-camcc.yaml [new file with mode: 0644]
Documentation/devicetree/bindings/clock/renesas,rcar-usb2-clock-sel.txt [deleted file]
Documentation/devicetree/bindings/clock/renesas,rcar-usb2-clock-sel.yaml [new file with mode: 0644]
Documentation/devicetree/bindings/clock/sifive/fu740-prci.yaml [new file with mode: 0644]
MAINTAINERS
arch/riscv/Kconfig.socs
arch/sh/boards/of-generic.c
arch/xtensa/kernel/time.c
drivers/clk/Kconfig
drivers/clk/Makefile
drivers/clk/at91/at91rm9200.c
drivers/clk/at91/at91sam9260.c
drivers/clk/at91/at91sam9g45.c
drivers/clk/at91/at91sam9n12.c
drivers/clk/at91/at91sam9rl.c
drivers/clk/at91/at91sam9x5.c
drivers/clk/at91/clk-master.c
drivers/clk/at91/clk-sam9x60-pll.c
drivers/clk/at91/dt-compat.c
drivers/clk/at91/pmc.h
drivers/clk/at91/sam9x60.c
drivers/clk/at91/sama5d2.c
drivers/clk/at91/sama5d3.c
drivers/clk/at91/sama5d4.c
drivers/clk/at91/sama7g5.c
drivers/clk/clk-axi-clkgen.c
drivers/clk/clk-composite.c
drivers/clk/clk-divider.c
drivers/clk/clk-fsl-flexspi.c [new file with mode: 0644]
drivers/clk/clk-fsl-sai.c
drivers/clk/clk-pwm.c
drivers/clk/clk-qoriq.c
drivers/clk/clk-scpi.c
drivers/clk/clk-si5351.c
drivers/clk/clk.c
drivers/clk/imx/clk-gate2.c
drivers/clk/imx/clk-imx8mm.c
drivers/clk/imx/clk-imx8mn.c
drivers/clk/imx/clk-imx8mp.c
drivers/clk/imx/clk-imx8mq.c
drivers/clk/imx/clk-imx8qxp-lpcg.c
drivers/clk/imx/clk-imx8qxp.c
drivers/clk/imx/clk-lpcg-scu.c
drivers/clk/imx/clk-pll14xx.c
drivers/clk/imx/clk-scu.c
drivers/clk/imx/clk-scu.h
drivers/clk/imx/clk.h
drivers/clk/mediatek/clk-mux.c
drivers/clk/mediatek/clk-mux.h
drivers/clk/meson/Kconfig
drivers/clk/meson/axg-aoclk.c
drivers/clk/meson/axg.c
drivers/clk/meson/axg.h
drivers/clk/meson/g12a-aoclk.c
drivers/clk/meson/g12a.c
drivers/clk/meson/g12a.h
drivers/clk/meson/gxbb-aoclk.c
drivers/clk/meson/gxbb.c
drivers/clk/meson/meson-aoclk.c
drivers/clk/meson/meson-eeclk.c
drivers/clk/qcom/Kconfig
drivers/clk/qcom/Makefile
drivers/clk/qcom/camcc-sc7180.c [new file with mode: 0644]
drivers/clk/qcom/clk-alpha-pll.c
drivers/clk/qcom/clk-alpha-pll.h
drivers/clk/qcom/clk-rpmh.c
drivers/clk/qcom/dispcc-sm8250.c
drivers/clk/qcom/gcc-sc7180.c
drivers/clk/qcom/gcc-sdx55.c [new file with mode: 0644]
drivers/clk/qcom/lpass-gfm-sm8250.c [new file with mode: 0644]
drivers/clk/qcom/lpasscorecc-sc7180.c
drivers/clk/renesas/clk-sh73a0.c
drivers/clk/renesas/r8a774a1-cpg-mssr.c
drivers/clk/renesas/r8a774b1-cpg-mssr.c
drivers/clk/renesas/r8a774c0-cpg-mssr.c
drivers/clk/renesas/r8a779a0-cpg-mssr.c
drivers/clk/renesas/rcar-gen3-cpg.c
drivers/clk/renesas/rcar-gen3-cpg.h
drivers/clk/renesas/rcar-usb2-clock-sel.c
drivers/clk/renesas/renesas-cpg-mssr.c
drivers/clk/rockchip/Kconfig
drivers/clk/rockchip/clk-rk3188.c
drivers/clk/rockchip/clk.c
drivers/clk/samsung/Kconfig
drivers/clk/samsung/Makefile
drivers/clk/samsung/clk-pll.c
drivers/clk/sifive/Kconfig
drivers/clk/sifive/Makefile
drivers/clk/sifive/fu540-prci.c
drivers/clk/sifive/fu540-prci.h [new file with mode: 0644]
drivers/clk/sifive/fu740-prci.c [new file with mode: 0644]
drivers/clk/sifive/fu740-prci.h [new file with mode: 0644]
drivers/clk/sifive/sifive-prci.c [new file with mode: 0644]
drivers/clk/sifive/sifive-prci.h [new file with mode: 0644]
drivers/clk/tegra/clk-bpmp.c
drivers/clk/tegra/clk-dfll.c
drivers/clk/tegra/clk-id.h
drivers/clk/tegra/clk-tegra-periph.c
drivers/clk/ti/clk-54xx.c
drivers/clk/ti/fapll.c
include/dt-bindings/clock/at91.h
include/dt-bindings/clock/axg-clkc.h
include/dt-bindings/clock/fsl,qoriq-clockgen.h [new file with mode: 0644]
include/dt-bindings/clock/g12a-clkc.h
include/dt-bindings/clock/qcom,camcc-sc7180.h [new file with mode: 0644]
include/dt-bindings/clock/qcom,gcc-sdx55.h [new file with mode: 0644]
include/dt-bindings/clock/qcom,rpmh.h
include/dt-bindings/clock/qcom,sm8250-lpass-aoncc.h [new file with mode: 0644]
include/dt-bindings/clock/qcom,sm8250-lpass-audiocc.h [new file with mode: 0644]
include/dt-bindings/clock/sifive-fu740-prci.h [new file with mode: 0644]
include/linux/clk-provider.h
include/linux/clk.h
include/linux/clk/samsung.h

diff --git a/Documentation/devicetree/bindings/clock/adi,axi-clkgen.yaml b/Documentation/devicetree/bindings/clock/adi,axi-clkgen.yaml
new file mode 100644 (file)
index 0000000..0d06387
--- /dev/null
@@ -0,0 +1,53 @@
+# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/clock/adi,axi-clkgen.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: Binding for Analog Devices AXI clkgen pcore clock generator
+
+maintainers:
+  - Lars-Peter Clausen <lars@metafoo.de>
+  - Michael Hennerich <michael.hennerich@analog.com>
+
+description: |
+  The axi_clkgen IP core is a software programmable clock generator,
+  that can be synthesized on various FPGA platforms.
+
+  Link: https://wiki.analog.com/resources/fpga/docs/axi_clkgen
+
+properties:
+  compatible:
+    enum:
+      - adi,axi-clkgen-2.00.a
+
+  clocks:
+    description:
+      Specifies the reference clock(s) from which the output frequency is
+      derived. This must either reference one clock if only the first clock
+      input is connected or two if both clock inputs are connected.
+    minItems: 1
+    maxItems: 2
+
+  '#clock-cells':
+    const: 0
+
+  reg:
+    maxItems: 1
+
+required:
+  - compatible
+  - reg
+  - clocks
+  - '#clock-cells'
+
+additionalProperties: false
+
+examples:
+  - |
+    clock-controller@ff000000 {
+      compatible = "adi,axi-clkgen-2.00.a";
+      #clock-cells = <0>;
+      reg = <0xff000000 0x1000>;
+      clocks = <&osc 1>;
+    };
diff --git a/Documentation/devicetree/bindings/clock/axi-clkgen.txt b/Documentation/devicetree/bindings/clock/axi-clkgen.txt
deleted file mode 100644 (file)
index aca94fe..0000000
+++ /dev/null
@@ -1,25 +0,0 @@
-Binding for the axi-clkgen clock generator
-
-This binding uses the common clock binding[1].
-
-[1] Documentation/devicetree/bindings/clock/clock-bindings.txt
-
-Required properties:
-- compatible : shall be "adi,axi-clkgen-1.00.a" or "adi,axi-clkgen-2.00.a".
-- #clock-cells : from common clock binding; Should always be set to 0.
-- reg : Address and length of the axi-clkgen register set.
-- clocks : Phandle and clock specifier for the parent clock(s). This must
-       either reference one clock if only the first clock input is connected or two
-       if both clock inputs are connected. For the later case the clock connected
-       to the first input must be specified first.
-
-Optional properties:
-- clock-output-names : From common clock binding.
-
-Example:
-       clock@ff000000 {
-               compatible = "adi,axi-clkgen";
-               #clock-cells = <0>;
-               reg = <0xff000000 0x1000>;
-               clocks = <&osc 1>;
-       };
diff --git a/Documentation/devicetree/bindings/clock/fsl,flexspi-clock.yaml b/Documentation/devicetree/bindings/clock/fsl,flexspi-clock.yaml
new file mode 100644 (file)
index 0000000..1fa390e
--- /dev/null
@@ -0,0 +1,55 @@
+# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/clock/fsl,flexspi-clock.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: Freescale FlexSPI clock driver for Layerscape SoCs
+
+maintainers:
+  - Michael Walle <michael@walle.cc>
+
+description:
+  The Freescale Layerscape SoCs have a special FlexSPI clock which is
+  derived from the platform PLL.
+
+properties:
+  compatible:
+    enum:
+      - fsl,ls1028a-flexspi-clk
+      - fsl,lx2160a-flexspi-clk
+
+  reg:
+    maxItems: 1
+
+  clocks:
+    maxItems: 1
+
+  '#clock-cells':
+    const: 0
+
+  clock-output-names:
+    maxItems: 1
+
+required:
+  - compatible
+  - reg
+  - clocks
+  - '#clock-cells'
+
+additionalProperties: false
+
+examples:
+  - |
+    dcfg {
+        #address-cells = <1>;
+        #size-cells = <1>;
+
+        fspi_clk: clock-controller@900 {
+            compatible = "fsl,ls1028a-flexspi-clk";
+            reg = <0x900 0x4>;
+            #clock-cells = <0>;
+            clocks = <&parentclk>;
+            clock-output-names = "fspi_clk";
+        };
+    };
diff --git a/Documentation/devicetree/bindings/clock/qcom,aoncc-sm8250.yaml b/Documentation/devicetree/bindings/clock/qcom,aoncc-sm8250.yaml
new file mode 100644 (file)
index 0000000..c40a74b
--- /dev/null
@@ -0,0 +1,58 @@
+# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/clock/qcom,aoncc-sm8250.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: Clock bindings for LPASS Always ON Clock Controller on SM8250 SoCs
+
+maintainers:
+  - Srinivas Kandagatla <srinivas.kandagatla@linaro.org>
+
+description: |
+  The clock consumer should specify the desired clock by having the clock
+  ID in its "clocks" phandle cell.
+  See include/dt-bindings/clock/qcom,sm8250-lpass-aoncc.h for the full list
+  of Audio Clock controller clock IDs.
+
+properties:
+  compatible:
+    const: qcom,sm8250-lpass-aon
+
+  reg:
+    maxItems: 1
+
+  '#clock-cells':
+    const: 1
+
+  clocks:
+    items:
+      - description: LPASS Core voting clock
+      - description: Glitch Free Mux register clock
+
+  clock-names:
+    items:
+      - const: core
+      - const: bus
+
+required:
+  - compatible
+  - reg
+  - '#clock-cells'
+  - clocks
+  - clock-names
+
+additionalProperties: false
+
+examples:
+  - |
+    #include <dt-bindings/clock/qcom,sm8250-lpass-aoncc.h>
+    #include <dt-bindings/sound/qcom,q6afe.h>
+    clock-controller@3800000 {
+      #clock-cells = <1>;
+      compatible = "qcom,sm8250-lpass-aon";
+      reg = <0x03380000 0x40000>;
+      clocks = <&q6afecc LPASS_HW_MACRO_VOTE LPASS_CLK_ATTRIBUTE_COUPLE_NO>,
+               <&q6afecc LPASS_CLK_ID_TX_CORE_MCLK LPASS_CLK_ATTRIBUTE_COUPLE_NO>;
+      clock-names = "core", "bus";
+    };
diff --git a/Documentation/devicetree/bindings/clock/qcom,audiocc-sm8250.yaml b/Documentation/devicetree/bindings/clock/qcom,audiocc-sm8250.yaml
new file mode 100644 (file)
index 0000000..915d762
--- /dev/null
@@ -0,0 +1,58 @@
+# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/clock/qcom,audiocc-sm8250.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: Clock bindings for LPASS Audio Clock Controller on SM8250 SoCs
+
+maintainers:
+  - Srinivas Kandagatla <srinivas.kandagatla@linaro.org>
+
+description: |
+  The clock consumer should specify the desired clock by having the clock
+  ID in its "clocks" phandle cell.
+  See include/dt-bindings/clock/qcom,sm8250-lpass-audiocc.h for the full list
+  of Audio Clock controller clock IDs.
+
+properties:
+  compatible:
+    const: qcom,sm8250-lpass-audiocc
+
+  reg:
+    maxItems: 1
+
+  '#clock-cells':
+    const: 1
+
+  clocks:
+    items:
+      - description: LPASS Core voting clock
+      - description: Glitch Free Mux register clock
+
+  clock-names:
+    items:
+      - const: core
+      - const: bus
+
+required:
+  - compatible
+  - reg
+  - '#clock-cells'
+  - clocks
+  - clock-names
+
+additionalProperties: false
+
+examples:
+  - |
+    #include <dt-bindings/clock/qcom,sm8250-lpass-audiocc.h>
+    #include <dt-bindings/sound/qcom,q6afe.h>
+    clock-controller@3300000 {
+      #clock-cells = <1>;
+      compatible = "qcom,sm8250-lpass-audiocc";
+      reg = <0x03300000 0x30000>;
+      clocks = <&q6afecc LPASS_HW_MACRO_VOTE LPASS_CLK_ATTRIBUTE_COUPLE_NO>,
+               <&q6afecc LPASS_CLK_ID_TX_CORE_MCLK LPASS_CLK_ATTRIBUTE_COUPLE_NO>;
+      clock-names = "core", "bus";
+    };
diff --git a/Documentation/devicetree/bindings/clock/qcom,gcc-sdx55.yaml b/Documentation/devicetree/bindings/clock/qcom,gcc-sdx55.yaml
new file mode 100644 (file)
index 0000000..1121b39
--- /dev/null
@@ -0,0 +1,77 @@
+# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/clock/qcom,gcc-sdx55.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: Qualcomm Global Clock & Reset Controller Binding for SDX55
+
+maintainers:
+  - Vinod Koul <vkoul@kernel.org>
+  - Manivannan Sadhasivam <manivannan.sadhasivam@linaro.org>
+
+description: |
+  Qualcomm global clock control module which supports the clocks, resets and
+  power domains on SDX55
+
+  See also:
+  - dt-bindings/clock/qcom,gcc-sdx55.h
+
+properties:
+  compatible:
+    const: qcom,gcc-sdx55
+
+  clocks:
+    items:
+      - description: Board XO source
+      - description: Sleep clock source
+      - description: PLL test clock source (Optional clock)
+    minItems: 2
+    maxItems: 3
+
+  clock-names:
+    items:
+      - const: bi_tcxo
+      - const: sleep_clk
+      - const: core_bi_pll_test_se # Optional clock
+    minItems: 2
+    maxItems: 3
+
+  '#clock-cells':
+    const: 1
+
+  '#reset-cells':
+    const: 1
+
+  '#power-domain-cells':
+    const: 1
+
+  reg:
+    maxItems: 1
+
+required:
+  - compatible
+  - clocks
+  - clock-names
+  - reg
+  - '#clock-cells'
+  - '#reset-cells'
+  - '#power-domain-cells'
+
+additionalProperties: false
+
+examples:
+  - |
+    #include <dt-bindings/clock/qcom,rpmh.h>
+    clock-controller@100000 {
+      compatible = "qcom,gcc-sdx55";
+      reg = <0x00100000 0x1f0000>;
+      clocks = <&rpmhcc RPMH_CXO_CLK>,
+               <&sleep_clk>, <&pll_test_clk>;
+      clock-names = "bi_tcxo", "sleep_clk", "core_bi_pll_test_se";
+      #clock-cells = <1>;
+      #reset-cells = <1>;
+      #power-domain-cells = <1>;
+    };
+
+...
index a46a3a7..12c9cbc 100644 (file)
@@ -19,8 +19,10 @@ properties:
     enum:
       - qcom,sc7180-rpmh-clk
       - qcom,sdm845-rpmh-clk
+      - qcom,sdx55-rpmh-clk
       - qcom,sm8150-rpmh-clk
       - qcom,sm8250-rpmh-clk
+      - qcom,sm8350-rpmh-clk
 
   clocks:
     maxItems: 1
diff --git a/Documentation/devicetree/bindings/clock/qcom,sc7180-camcc.yaml b/Documentation/devicetree/bindings/clock/qcom,sc7180-camcc.yaml
new file mode 100644 (file)
index 0000000..f49027e
--- /dev/null
@@ -0,0 +1,73 @@
+# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/clock/qcom,sc7180-camcc.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: Qualcomm Camera Clock & Reset Controller Binding for SC7180
+
+maintainers:
+  - Taniya Das <tdas@codeaurora.org>
+
+description: |
+  Qualcomm camera clock control module which supports the clocks, resets and
+  power domains on SC7180.
+
+  See also:
+  - dt-bindings/clock/qcom,camcc-sc7180.h
+
+properties:
+  compatible:
+    const: qcom,sc7180-camcc
+
+  clocks:
+    items:
+      - description: Board XO source
+      - description: Camera_ahb clock from GCC
+      - description: Camera XO clock from GCC
+
+  clock-names:
+    items:
+      - const: bi_tcxo
+      - const: iface
+      - const: xo
+
+  '#clock-cells':
+    const: 1
+
+  '#reset-cells':
+    const: 1
+
+  '#power-domain-cells':
+    const: 1
+
+  reg:
+    maxItems: 1
+
+required:
+  - compatible
+  - reg
+  - clocks
+  - clock-names
+  - '#clock-cells'
+  - '#reset-cells'
+  - '#power-domain-cells'
+
+additionalProperties: false
+
+examples:
+  - |
+    #include <dt-bindings/clock/qcom,gcc-sc7180.h>
+    #include <dt-bindings/clock/qcom,rpmh.h>
+    clock-controller@ad00000 {
+      compatible = "qcom,sc7180-camcc";
+      reg = <0x0ad00000 0x10000>;
+      clocks = <&rpmhcc RPMH_CXO_CLK>,
+               <&gcc GCC_CAMERA_AHB_CLK>,
+               <&gcc GCC_CAMERA_XO_CLK>;
+      clock-names = "bi_tcxo", "iface", "xo";
+      #clock-cells = <1>;
+      #reset-cells = <1>;
+      #power-domain-cells = <1>;
+    };
+...
diff --git a/Documentation/devicetree/bindings/clock/renesas,rcar-usb2-clock-sel.txt b/Documentation/devicetree/bindings/clock/renesas,rcar-usb2-clock-sel.txt
deleted file mode 100644 (file)
index da92f57..0000000
+++ /dev/null
@@ -1,68 +0,0 @@
-* Renesas R-Car USB 2.0 clock selector
-
-This file provides information on what the device node for the R-Car USB 2.0
-clock selector.
-
-If you connect an external clock to the USB_EXTAL pin only, you should set
-the clock rate to "usb_extal" node only.
-If you connect an oscillator to both the USB_XTAL and USB_EXTAL, this module
-is not needed because this is default setting. (Of course, you can set the
-clock rates to both "usb_extal" and "usb_xtal" nodes.
-
-Case 1: An external clock connects to R-Car SoC
-       +----------+   +--- R-Car ---------------------+
-       |External  |---|USB_EXTAL ---> all usb channels|
-       |clock     |   |USB_XTAL                       |
-       +----------+   +-------------------------------+
-In this case, we need this driver with "usb_extal" clock.
-
-Case 2: An oscillator connects to R-Car SoC
-       +----------+   +--- R-Car ---------------------+
-       |Oscillator|---|USB_EXTAL -+-> all usb channels|
-       |          |---|USB_XTAL --+                   |
-       +----------+   +-------------------------------+
-In this case, we don't need this selector.
-
-Required properties:
-- compatible: "renesas,r8a7795-rcar-usb2-clock-sel" if the device is a part of
-             an R8A7795 SoC.
-             "renesas,r8a7796-rcar-usb2-clock-sel" if the device if a part of
-             an R8A77960 SoC.
-             "renesas,r8a77961-rcar-usb2-clock-sel" if the device if a part of
-             an R8A77961 SoC.
-             "renesas,rcar-gen3-usb2-clock-sel" for a generic R-Car Gen3
-             compatible device.
-
-             When compatible with the generic version, nodes must list the
-             SoC-specific version corresponding to the platform first
-             followed by the generic version.
-
-- reg: offset and length of the USB 2.0 clock selector register block.
-- clocks: A list of phandles and specifier pairs.
-- clock-names: Name of the clocks.
- - The functional clock of USB 2.0 host side must be "ehci_ohci"
- - The functional clock of HS-USB side must be "hs-usb-if"
- - The USB_EXTAL clock pin must be "usb_extal"
- - The USB_XTAL clock pin must be "usb_xtal"
-- #clock-cells: Must be 0
-- power-domains: A phandle and symbolic PM domain specifier.
-                 See power/renesas,rcar-sysc.yaml.
-- resets: A list of phandles and specifier pairs.
-- reset-names: Name of the resets.
- - The reset of USB 2.0 host side must be "ehci_ohci"
- - The reset of HS-USB side must be "hs-usb-if"
-
-Example (R-Car H3):
-
-       usb2_clksel: clock-controller@e6590630 {
-               compatible = "renesas,r8a7795-rcar-usb2-clock-sel",
-                            "renesas,rcar-gen3-usb2-clock-sel";
-               reg = <0 0xe6590630 0 0x02>;
-               clocks = <&cpg CPG_MOD 703>, <&cpg CPG_MOD 704>,
-                        <&usb_extal>, <&usb_xtal>;
-               clock-names = "ehci_ohci", "hs-usb-if", "usb_extal", "usb_xtal";
-               #clock-cells = <0>;
-               power-domains = <&sysc R8A7795_PD_ALWAYS_ON>;
-               resets = <&cpg 703>, <&cpg 704>;
-               reset-names = "ehci_ohci", "hs-usb-if";
-       };
diff --git a/Documentation/devicetree/bindings/clock/renesas,rcar-usb2-clock-sel.yaml b/Documentation/devicetree/bindings/clock/renesas,rcar-usb2-clock-sel.yaml
new file mode 100644 (file)
index 0000000..5be1229
--- /dev/null
@@ -0,0 +1,100 @@
+# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
+%YAML 1.2
+---
+$id: "http://devicetree.org/schemas/clock/renesas,rcar-usb2-clock-sel.yaml#"
+$schema: "http://devicetree.org/meta-schemas/core.yaml#"
+
+title: Renesas R-Car USB 2.0 clock selector
+
+maintainers:
+  - Yoshihiro Shimoda <yoshihiro.shimoda.uh@renesas.com>
+
+description: |
+  If you connect an external clock to the USB_EXTAL pin only, you should set
+  the clock rate to "usb_extal" node only.
+  If you connect an oscillator to both the USB_XTAL and USB_EXTAL, this module
+  is not needed because this is default setting. (Of course, you can set the
+  clock rates to both "usb_extal" and "usb_xtal" nodes.
+
+  Case 1: An external clock connects to R-Car SoC
+    +----------+   +--- R-Car ---------------------+
+    |External  |---|USB_EXTAL ---> all usb channels|
+    |clock     |   |USB_XTAL                       |
+    +----------+   +-------------------------------+
+
+  In this case, we need this driver with "usb_extal" clock.
+
+  Case 2: An oscillator connects to R-Car SoC
+    +----------+   +--- R-Car ---------------------+
+    |Oscillator|---|USB_EXTAL -+-> all usb channels|
+    |          |---|USB_XTAL --+                   |
+    +----------+   +-------------------------------+
+  In this case, we don't need this selector.
+
+properties:
+  compatible:
+    items:
+      - enum:
+          - renesas,r8a7795-rcar-usb2-clock-sel  # R-Car H3
+          - renesas,r8a7796-rcar-usb2-clock-sel  # R-Car M3-W
+          - renesas,r8a77961-rcar-usb2-clock-sel # R-Car M3-W+
+      - const: renesas,rcar-gen3-usb2-clock-sel
+
+  reg:
+    maxItems: 1
+
+  clocks:
+    minItems: 4
+    maxItems: 4
+
+  clock-names:
+    items:
+      - const: ehci_ohci
+      - const: hs-usb-if
+      - const: usb_extal
+      - const: usb_xtal
+
+  '#clock-cells':
+    const: 0
+
+  power-domains:
+    maxItems: 1
+
+  resets:
+    minItems: 2
+    maxItems: 2
+
+  reset-names:
+    items:
+      - const: ehci_ohci
+      - const: hs-usb-if
+
+required:
+  - compatible
+  - reg
+  - clocks
+  - clock-names
+  - '#clock-cells'
+  - power-domains
+  - resets
+  - reset-names
+
+additionalProperties: false
+
+examples:
+  - |
+    #include <dt-bindings/clock/r8a7795-cpg-mssr.h>
+    #include <dt-bindings/power/r8a7795-sysc.h>
+
+    usb2_clksel: clock-controller@e6590630 {
+        compatible = "renesas,r8a7795-rcar-usb2-clock-sel",
+                     "renesas,rcar-gen3-usb2-clock-sel";
+        reg = <0xe6590630 0x02>;
+        clocks = <&cpg CPG_MOD 703>, <&cpg CPG_MOD 704>,
+                 <&usb_extal>, <&usb_xtal>;
+        clock-names = "ehci_ohci", "hs-usb-if", "usb_extal", "usb_xtal";
+        #clock-cells = <0>;
+        power-domains = <&sysc R8A7795_PD_ALWAYS_ON>;
+        resets = <&cpg 703>, <&cpg 704>;
+        reset-names = "ehci_ohci", "hs-usb-if";
+    };
diff --git a/Documentation/devicetree/bindings/clock/sifive/fu740-prci.yaml b/Documentation/devicetree/bindings/clock/sifive/fu740-prci.yaml
new file mode 100644 (file)
index 0000000..e17143c
--- /dev/null
@@ -0,0 +1,60 @@
+# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
+# Copyright (C) 2020 SiFive, Inc.
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/clock/sifive/fu740-prci.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: SiFive FU740 Power Reset Clock Interrupt Controller (PRCI)
+
+maintainers:
+  - Zong Li <zong.li@sifive.com>
+  - Paul Walmsley  <paul.walmsley@sifive.com>
+
+description:
+  On the FU740 family of SoCs, most system-wide clock and reset integration
+  is via the PRCI IP block.
+  The clock consumer should specify the desired clock via the clock ID
+  macros defined in include/dt-bindings/clock/sifive-fu740-prci.h.
+  These macros begin with PRCI_CLK_.
+
+  The hfclk and rtcclk nodes are required, and represent physical
+  crystals or resonators located on the PCB.  These nodes should be present
+  underneath /, rather than /soc.
+
+properties:
+  compatible:
+    const: sifive,fu740-c000-prci
+
+  reg:
+    maxItems: 1
+
+  clocks:
+    items:
+      - description: high frequency clock.
+      - description: RTL clock.
+
+  clock-names:
+    items:
+      - const: hfclk
+      - const: rtcclk
+
+  "#clock-cells":
+    const: 1
+
+required:
+  - compatible
+  - reg
+  - clocks
+  - "#clock-cells"
+
+additionalProperties: false
+
+examples:
+  - |
+    prci: clock-controller@10000000 {
+      compatible = "sifive,fu740-c000-prci";
+      reg = <0x10000000 0x1000>;
+      clocks = <&hfclk>, <&rtcclk>;
+      #clock-cells = <1>;
+    };
index e73636b..595e102 100644 (file)
@@ -14888,7 +14888,7 @@ RENESAS CLOCK DRIVERS
 M:     Geert Uytterhoeven <geert+renesas@glider.be>
 L:     linux-renesas-soc@vger.kernel.org
 S:     Supported
-T:     git git://git.kernel.org/pub/scm/linux/kernel/git/geert/renesas-drivers.git clk-renesas
+T:     git git://git.kernel.org/pub/scm/linux/kernel/git/geert/renesas-drivers.git renesas-clk
 F:     Documentation/devicetree/bindings/clock/renesas,*
 F:     drivers/clk/renesas/
 
index 8a55f61..3284d5c 100644 (file)
@@ -5,7 +5,7 @@ config SOC_SIFIVE
        select SERIAL_SIFIVE if TTY
        select SERIAL_SIFIVE_CONSOLE if TTY
        select CLK_SIFIVE
-       select CLK_SIFIVE_FU540_PRCI
+       select CLK_SIFIVE_PRCI
        select SIFIVE_PLIC
        help
          This enables support for SiFive SoC platform hardware.
index bffbe69..921d76f 100644 (file)
@@ -6,10 +6,10 @@
  */
 
 #include <linux/of.h>
+#include <linux/of_clk.h>
 #include <linux/of_fdt.h>
 #include <linux/clocksource.h>
 #include <linux/irqchip.h>
-#include <linux/clk-provider.h>
 #include <asm/machvec.h>
 #include <asm/rtc.h>
 
index 77971fe..e8ceb15 100644 (file)
@@ -13,7 +13,7 @@
  */
 
 #include <linux/clk.h>
-#include <linux/clk-provider.h>
+#include <linux/of_clk.h>
 #include <linux/errno.h>
 #include <linux/sched.h>
 #include <linux/time.h>
index c715d46..85856cf 100644 (file)
@@ -188,6 +188,14 @@ config COMMON_CLK_CS2000_CP
        help
          If you say yes here you get support for the CS2000 clock multiplier.
 
+config COMMON_CLK_FSL_FLEXSPI
+       tristate "Clock driver for FlexSPI on Layerscape SoCs"
+       depends on ARCH_LAYERSCAPE || COMPILE_TEST
+       default ARCH_LAYERSCAPE && SPI_NXP_FLEXSPI
+       help
+         On Layerscape SoCs there is a special clock for the FlexSPI
+         interface.
+
 config COMMON_CLK_FSL_SAI
        bool "Clock driver for BCLK of Freescale SAI cores"
        depends on ARCH_LAYERSCAPE || COMPILE_TEST
@@ -246,7 +254,8 @@ config COMMON_CLK_AXI_CLKGEN
 
 config CLK_QORIQ
        bool "Clock driver for Freescale QorIQ platforms"
-       depends on (PPC_E500MC || ARM || ARM64 || COMPILE_TEST) && OF
+       depends on OF
+       depends on PPC_E500MC || SOC_LS1021A || ARCH_LAYERSCAPE || COMPILE_TEST
        help
          This adds the clock driver support for Freescale QorIQ platforms
          using common clock framework.
index da8fcf1..dbdc590 100644 (file)
@@ -30,6 +30,7 @@ obj-$(CONFIG_COMMON_CLK_CS2000_CP)    += clk-cs2000-cp.o
 obj-$(CONFIG_ARCH_EFM32)               += clk-efm32gg.o
 obj-$(CONFIG_ARCH_SPARX5)              += clk-sparx5.o
 obj-$(CONFIG_COMMON_CLK_FIXED_MMIO)    += clk-fixed-mmio.o
+obj-$(CONFIG_COMMON_CLK_FSL_FLEXSPI)   += clk-fsl-flexspi.o
 obj-$(CONFIG_COMMON_CLK_FSL_SAI)       += clk-fsl-sai.o
 obj-$(CONFIG_COMMON_CLK_GEMINI)                += clk-gemini.o
 obj-$(CONFIG_COMMON_CLK_ASPEED)                += clk-aspeed.o
index 2c3d8e6..0fad100 100644 (file)
@@ -7,6 +7,8 @@
 
 #include "pmc.h"
 
+static DEFINE_SPINLOCK(rm9200_mck_lock);
+
 struct sck {
        char *n;
        char *p;
@@ -137,9 +139,20 @@ static void __init at91rm9200_pmc_setup(struct device_node *np)
        parent_names[1] = "mainck";
        parent_names[2] = "pllack";
        parent_names[3] = "pllbck";
-       hw = at91_clk_register_master(regmap, "masterck", 4, parent_names,
-                                     &at91rm9200_master_layout,
-                                     &rm9200_mck_characteristics);
+       hw = at91_clk_register_master_pres(regmap, "masterck_pres", 4,
+                                          parent_names,
+                                          &at91rm9200_master_layout,
+                                          &rm9200_mck_characteristics,
+                                          &rm9200_mck_lock, CLK_SET_RATE_GATE,
+                                          INT_MIN);
+       if (IS_ERR(hw))
+               goto err_free;
+
+       hw = at91_clk_register_master_div(regmap, "masterck_div",
+                                         "masterck_pres",
+                                         &at91rm9200_master_layout,
+                                         &rm9200_mck_characteristics,
+                                         &rm9200_mck_lock, CLK_SET_RATE_GATE);
        if (IS_ERR(hw))
                goto err_free;
 
@@ -181,7 +194,7 @@ static void __init at91rm9200_pmc_setup(struct device_node *np)
        for (i = 0; i < ARRAY_SIZE(at91rm9200_periphck); i++) {
                hw = at91_clk_register_peripheral(regmap,
                                                  at91rm9200_periphck[i].n,
-                                                 "masterck",
+                                                 "masterck_div",
                                                  at91rm9200_periphck[i].id);
                if (IS_ERR(hw))
                        goto err_free;
index bb81ff7..ceb5495 100644 (file)
@@ -32,6 +32,8 @@ struct at91sam926x_data {
        bool has_slck;
 };
 
+static DEFINE_SPINLOCK(at91sam9260_mck_lock);
+
 static const struct clk_master_characteristics sam9260_mck_characteristics = {
        .output = { .min = 0, .max = 105000000 },
        .divisors = { 1, 2, 4, 0 },
@@ -218,8 +220,8 @@ static const struct sck at91sam9261_systemck[] = {
        { .n = "pck1",  .p = "prog1",    .id = 9 },
        { .n = "pck2",  .p = "prog2",    .id = 10 },
        { .n = "pck3",  .p = "prog3",    .id = 11 },
-       { .n = "hclk0", .p = "masterck", .id = 16 },
-       { .n = "hclk1", .p = "masterck", .id = 17 },
+       { .n = "hclk0", .p = "masterck_div", .id = 16 },
+       { .n = "hclk1", .p = "masterck_div", .id = 17 },
 };
 
 static const struct pck at91sam9261_periphck[] = {
@@ -413,9 +415,21 @@ static void __init at91sam926x_pmc_setup(struct device_node *np,
        parent_names[1] = "mainck";
        parent_names[2] = "pllack";
        parent_names[3] = "pllbck";
-       hw = at91_clk_register_master(regmap, "masterck", 4, parent_names,
-                                     &at91rm9200_master_layout,
-                                     data->mck_characteristics);
+       hw = at91_clk_register_master_pres(regmap, "masterck_pres", 4,
+                                          parent_names,
+                                          &at91rm9200_master_layout,
+                                          data->mck_characteristics,
+                                          &at91sam9260_mck_lock,
+                                          CLK_SET_RATE_GATE, INT_MIN);
+       if (IS_ERR(hw))
+               goto err_free;
+
+       hw = at91_clk_register_master_div(regmap, "masterck_div",
+                                         "masterck_pres",
+                                         &at91rm9200_master_layout,
+                                         data->mck_characteristics,
+                                         &at91sam9260_mck_lock,
+                                         CLK_SET_RATE_GATE);
        if (IS_ERR(hw))
                goto err_free;
 
@@ -457,7 +471,7 @@ static void __init at91sam926x_pmc_setup(struct device_node *np,
        for (i = 0; i < data->num_pck; i++) {
                hw = at91_clk_register_peripheral(regmap,
                                                  data->pck[i].n,
-                                                 "masterck",
+                                                 "masterck_div",
                                                  data->pck[i].id);
                if (IS_ERR(hw))
                        goto err_free;
index cb4a406..0214333 100644 (file)
@@ -7,6 +7,8 @@
 
 #include "pmc.h"
 
+static DEFINE_SPINLOCK(at91sam9g45_mck_lock);
+
 static const struct clk_master_characteristics mck_characteristics = {
        .output = { .min = 0, .max = 133333333 },
        .divisors = { 1, 2, 4, 3 },
@@ -40,10 +42,10 @@ static const struct {
        char *p;
        u8 id;
 } at91sam9g45_systemck[] = {
-       { .n = "ddrck", .p = "masterck", .id = 2 },
-       { .n = "uhpck", .p = "usbck",    .id = 6 },
-       { .n = "pck0",  .p = "prog0",    .id = 8 },
-       { .n = "pck1",  .p = "prog1",    .id = 9 },
+       { .n = "ddrck", .p = "masterck_div", .id = 2 },
+       { .n = "uhpck", .p = "usbck",        .id = 6 },
+       { .n = "pck0",  .p = "prog0",        .id = 8 },
+       { .n = "pck1",  .p = "prog1",        .id = 9 },
 };
 
 struct pck {
@@ -148,9 +150,21 @@ static void __init at91sam9g45_pmc_setup(struct device_node *np)
        parent_names[1] = "mainck";
        parent_names[2] = "plladivck";
        parent_names[3] = "utmick";
-       hw = at91_clk_register_master(regmap, "masterck", 4, parent_names,
-                                     &at91rm9200_master_layout,
-                                     &mck_characteristics);
+       hw = at91_clk_register_master_pres(regmap, "masterck_pres", 4,
+                                          parent_names,
+                                          &at91rm9200_master_layout,
+                                          &mck_characteristics,
+                                          &at91sam9g45_mck_lock,
+                                          CLK_SET_RATE_GATE, INT_MIN);
+       if (IS_ERR(hw))
+               goto err_free;
+
+       hw = at91_clk_register_master_div(regmap, "masterck_div",
+                                         "masterck_pres",
+                                         &at91rm9200_master_layout,
+                                         &mck_characteristics,
+                                         &at91sam9g45_mck_lock,
+                                         CLK_SET_RATE_GATE);
        if (IS_ERR(hw))
                goto err_free;
 
@@ -166,7 +180,7 @@ static void __init at91sam9g45_pmc_setup(struct device_node *np)
        parent_names[1] = "mainck";
        parent_names[2] = "plladivck";
        parent_names[3] = "utmick";
-       parent_names[4] = "masterck";
+       parent_names[4] = "masterck_div";
        for (i = 0; i < 2; i++) {
                char name[6];
 
@@ -195,7 +209,7 @@ static void __init at91sam9g45_pmc_setup(struct device_node *np)
        for (i = 0; i < ARRAY_SIZE(at91sam9g45_periphck); i++) {
                hw = at91_clk_register_peripheral(regmap,
                                                  at91sam9g45_periphck[i].n,
-                                                 "masterck",
+                                                 "masterck_div",
                                                  at91sam9g45_periphck[i].id);
                if (IS_ERR(hw))
                        goto err_free;
index 93f7eb2..f9db531 100644 (file)
@@ -7,6 +7,8 @@
 
 #include "pmc.h"
 
+static DEFINE_SPINLOCK(at91sam9n12_mck_lock);
+
 static const struct clk_master_characteristics mck_characteristics = {
        .output = { .min = 0, .max = 133333333 },
        .divisors = { 1, 2, 4, 3 },
@@ -54,12 +56,12 @@ static const struct {
        char *p;
        u8 id;
 } at91sam9n12_systemck[] = {
-       { .n = "ddrck", .p = "masterck", .id = 2 },
-       { .n = "lcdck", .p = "masterck", .id = 3 },
-       { .n = "uhpck", .p = "usbck",    .id = 6 },
-       { .n = "udpck", .p = "usbck",    .id = 7 },
-       { .n = "pck0",  .p = "prog0",    .id = 8 },
-       { .n = "pck1",  .p = "prog1",    .id = 9 },
+       { .n = "ddrck", .p = "masterck_div", .id = 2 },
+       { .n = "lcdck", .p = "masterck_div", .id = 3 },
+       { .n = "uhpck", .p = "usbck",        .id = 6 },
+       { .n = "udpck", .p = "usbck",        .id = 7 },
+       { .n = "pck0",  .p = "prog0",        .id = 8 },
+       { .n = "pck1",  .p = "prog1",        .id = 9 },
 };
 
 static const struct clk_pcr_layout at91sam9n12_pcr_layout = {
@@ -175,9 +177,21 @@ static void __init at91sam9n12_pmc_setup(struct device_node *np)
        parent_names[1] = "mainck";
        parent_names[2] = "plladivck";
        parent_names[3] = "pllbck";
-       hw = at91_clk_register_master(regmap, "masterck", 4, parent_names,
-                                     &at91sam9x5_master_layout,
-                                     &mck_characteristics);
+       hw = at91_clk_register_master_pres(regmap, "masterck_pres", 4,
+                                          parent_names,
+                                          &at91sam9x5_master_layout,
+                                          &mck_characteristics,
+                                          &at91sam9n12_mck_lock,
+                                          CLK_SET_RATE_GATE, INT_MIN);
+       if (IS_ERR(hw))
+               goto err_free;
+
+       hw = at91_clk_register_master_div(regmap, "masterck_div",
+                                         "masterck_pres",
+                                         &at91sam9x5_master_layout,
+                                         &mck_characteristics,
+                                         &at91sam9n12_mck_lock,
+                                         CLK_SET_RATE_GATE);
        if (IS_ERR(hw))
                goto err_free;
 
@@ -191,7 +205,7 @@ static void __init at91sam9n12_pmc_setup(struct device_node *np)
        parent_names[1] = "mainck";
        parent_names[2] = "plladivck";
        parent_names[3] = "pllbck";
-       parent_names[4] = "masterck";
+       parent_names[4] = "masterck_div";
        for (i = 0; i < 2; i++) {
                char name[6];
 
@@ -221,7 +235,7 @@ static void __init at91sam9n12_pmc_setup(struct device_node *np)
                hw = at91_clk_register_sam9x5_peripheral(regmap, &pmc_pcr_lock,
                                                         &at91sam9n12_pcr_layout,
                                                         at91sam9n12_periphck[i].n,
-                                                        "masterck",
+                                                        "masterck_div",
                                                         at91sam9n12_periphck[i].id,
                                                         &range, INT_MIN);
                if (IS_ERR(hw))
index a343eb6..66736e0 100644 (file)
@@ -7,6 +7,8 @@
 
 #include "pmc.h"
 
+static DEFINE_SPINLOCK(sam9rl_mck_lock);
+
 static const struct clk_master_characteristics sam9rl_mck_characteristics = {
        .output = { .min = 0, .max = 94000000 },
        .divisors = { 1, 2, 4, 0 },
@@ -117,9 +119,20 @@ static void __init at91sam9rl_pmc_setup(struct device_node *np)
        parent_names[1] = "mainck";
        parent_names[2] = "pllack";
        parent_names[3] = "utmick";
-       hw = at91_clk_register_master(regmap, "masterck", 4, parent_names,
-                                     &at91rm9200_master_layout,
-                                     &sam9rl_mck_characteristics);
+       hw = at91_clk_register_master_pres(regmap, "masterck_pres", 4,
+                                          parent_names,
+                                          &at91rm9200_master_layout,
+                                          &sam9rl_mck_characteristics,
+                                          &sam9rl_mck_lock, CLK_SET_RATE_GATE,
+                                          INT_MIN);
+       if (IS_ERR(hw))
+               goto err_free;
+
+       hw = at91_clk_register_master_div(regmap, "masterck_div",
+                                         "masterck_pres",
+                                         &at91rm9200_master_layout,
+                                         &sam9rl_mck_characteristics,
+                                         &sam9rl_mck_lock, CLK_SET_RATE_GATE);
        if (IS_ERR(hw))
                goto err_free;
 
@@ -129,7 +142,7 @@ static void __init at91sam9rl_pmc_setup(struct device_node *np)
        parent_names[1] = "mainck";
        parent_names[2] = "pllack";
        parent_names[3] = "utmick";
-       parent_names[4] = "masterck";
+       parent_names[4] = "masterck_div";
        for (i = 0; i < 2; i++) {
                char name[6];
 
@@ -158,7 +171,7 @@ static void __init at91sam9rl_pmc_setup(struct device_node *np)
        for (i = 0; i < ARRAY_SIZE(at91sam9rl_periphck); i++) {
                hw = at91_clk_register_peripheral(regmap,
                                                  at91sam9rl_periphck[i].n,
-                                                 "masterck",
+                                                 "masterck_div",
                                                  at91sam9rl_periphck[i].id);
                if (IS_ERR(hw))
                        goto err_free;
index 22b9aad..79b9d36 100644 (file)
@@ -7,6 +7,8 @@
 
 #include "pmc.h"
 
+static DEFINE_SPINLOCK(mck_lock);
+
 static const struct clk_master_characteristics mck_characteristics = {
        .output = { .min = 0, .max = 133333333 },
        .divisors = { 1, 2, 4, 3 },
@@ -41,7 +43,7 @@ static const struct {
        char *p;
        u8 id;
 } at91sam9x5_systemck[] = {
-       { .n = "ddrck", .p = "masterck", .id = 2 },
+       { .n = "ddrck", .p = "masterck_div", .id = 2 },
        { .n = "smdck", .p = "smdclk",   .id = 4 },
        { .n = "uhpck", .p = "usbck",    .id = 6 },
        { .n = "udpck", .p = "usbck",    .id = 7 },
@@ -196,9 +198,19 @@ static void __init at91sam9x5_pmc_setup(struct device_node *np,
        parent_names[1] = "mainck";
        parent_names[2] = "plladivck";
        parent_names[3] = "utmick";
-       hw = at91_clk_register_master(regmap, "masterck", 4, parent_names,
-                                     &at91sam9x5_master_layout,
-                                     &mck_characteristics);
+       hw = at91_clk_register_master_pres(regmap, "masterck_pres", 4,
+                                          parent_names,
+                                          &at91sam9x5_master_layout,
+                                          &mck_characteristics, &mck_lock,
+                                          CLK_SET_RATE_GATE, INT_MIN);
+       if (IS_ERR(hw))
+               goto err_free;
+
+       hw = at91_clk_register_master_div(regmap, "masterck_div",
+                                         "masterck_pres",
+                                         &at91sam9x5_master_layout,
+                                         &mck_characteristics, &mck_lock,
+                                         CLK_SET_RATE_GATE);
        if (IS_ERR(hw))
                goto err_free;
 
@@ -218,7 +230,7 @@ static void __init at91sam9x5_pmc_setup(struct device_node *np,
        parent_names[1] = "mainck";
        parent_names[2] = "plladivck";
        parent_names[3] = "utmick";
-       parent_names[4] = "masterck";
+       parent_names[4] = "masterck_div";
        for (i = 0; i < 2; i++) {
                char name[6];
 
@@ -245,7 +257,7 @@ static void __init at91sam9x5_pmc_setup(struct device_node *np,
        }
 
        if (has_lcdck) {
-               hw = at91_clk_register_system(regmap, "lcdck", "masterck", 3);
+               hw = at91_clk_register_system(regmap, "lcdck", "masterck_div", 3);
                if (IS_ERR(hw))
                        goto err_free;
 
@@ -256,7 +268,7 @@ static void __init at91sam9x5_pmc_setup(struct device_node *np,
                hw = at91_clk_register_sam9x5_peripheral(regmap, &pmc_pcr_lock,
                                                         &at91sam9x5_pcr_layout,
                                                         at91sam9x5_periphck[i].n,
-                                                        "masterck",
+                                                        "masterck_div",
                                                         at91sam9x5_periphck[i].id,
                                                         &range, INT_MIN);
                if (IS_ERR(hw))
@@ -269,7 +281,7 @@ static void __init at91sam9x5_pmc_setup(struct device_node *np,
                hw = at91_clk_register_sam9x5_peripheral(regmap, &pmc_pcr_lock,
                                                         &at91sam9x5_pcr_layout,
                                                         extra_pcks[i].n,
-                                                        "masterck",
+                                                        "masterck_div",
                                                         extra_pcks[i].id,
                                                         &range, INT_MIN);
                if (IS_ERR(hw))
index bd0d8a6..a804279 100644 (file)
@@ -15,7 +15,7 @@
 #define MASTER_PRES_MASK       0x7
 #define MASTER_PRES_MAX                MASTER_PRES_MASK
 #define MASTER_DIV_SHIFT       8
-#define MASTER_DIV_MASK                0x3
+#define MASTER_DIV_MASK                0x7
 
 #define PMC_MCR                        0x30
 #define PMC_MCR_ID_MSK         GENMASK(3, 0)
@@ -58,83 +58,309 @@ static inline bool clk_master_ready(struct clk_master *master)
 static int clk_master_prepare(struct clk_hw *hw)
 {
        struct clk_master *master = to_clk_master(hw);
+       unsigned long flags;
+
+       spin_lock_irqsave(master->lock, flags);
 
        while (!clk_master_ready(master))
                cpu_relax();
 
+       spin_unlock_irqrestore(master->lock, flags);
+
        return 0;
 }
 
 static int clk_master_is_prepared(struct clk_hw *hw)
 {
        struct clk_master *master = to_clk_master(hw);
+       unsigned long flags;
+       bool status;
 
-       return clk_master_ready(master);
+       spin_lock_irqsave(master->lock, flags);
+       status = clk_master_ready(master);
+       spin_unlock_irqrestore(master->lock, flags);
+
+       return status;
 }
 
-static unsigned long clk_master_recalc_rate(struct clk_hw *hw,
-                                           unsigned long parent_rate)
+static unsigned long clk_master_div_recalc_rate(struct clk_hw *hw,
+                                               unsigned long parent_rate)
 {
-       u8 pres;
        u8 div;
-       unsigned long rate = parent_rate;
+       unsigned long flags, rate = parent_rate;
        struct clk_master *master = to_clk_master(hw);
        const struct clk_master_layout *layout = master->layout;
        const struct clk_master_characteristics *characteristics =
                                                master->characteristics;
        unsigned int mckr;
 
+       spin_lock_irqsave(master->lock, flags);
        regmap_read(master->regmap, master->layout->offset, &mckr);
+       spin_unlock_irqrestore(master->lock, flags);
+
        mckr &= layout->mask;
 
-       pres = (mckr >> layout->pres_shift) & MASTER_PRES_MASK;
        div = (mckr >> MASTER_DIV_SHIFT) & MASTER_DIV_MASK;
 
-       if (characteristics->have_div3_pres && pres == MASTER_PRES_MAX)
-               rate /= 3;
-       else
-               rate >>= pres;
-
        rate /= characteristics->divisors[div];
 
        if (rate < characteristics->output.min)
-               pr_warn("master clk is underclocked");
+               pr_warn("master clk div is underclocked");
        else if (rate > characteristics->output.max)
-               pr_warn("master clk is overclocked");
+               pr_warn("master clk div is overclocked");
 
        return rate;
 }
 
-static u8 clk_master_get_parent(struct clk_hw *hw)
+static const struct clk_ops master_div_ops = {
+       .prepare = clk_master_prepare,
+       .is_prepared = clk_master_is_prepared,
+       .recalc_rate = clk_master_div_recalc_rate,
+};
+
+static int clk_master_div_set_rate(struct clk_hw *hw, unsigned long rate,
+                                  unsigned long parent_rate)
+{
+       struct clk_master *master = to_clk_master(hw);
+       const struct clk_master_characteristics *characteristics =
+                                               master->characteristics;
+       unsigned long flags;
+       int div, i;
+
+       div = DIV_ROUND_CLOSEST(parent_rate, rate);
+       if (div > ARRAY_SIZE(characteristics->divisors))
+               return -EINVAL;
+
+       for (i = 0; i < ARRAY_SIZE(characteristics->divisors); i++) {
+               if (!characteristics->divisors[i])
+                       break;
+
+               if (div == characteristics->divisors[i]) {
+                       div = i;
+                       break;
+               }
+       }
+
+       if (i == ARRAY_SIZE(characteristics->divisors))
+               return -EINVAL;
+
+       spin_lock_irqsave(master->lock, flags);
+       regmap_update_bits(master->regmap, master->layout->offset,
+                          (MASTER_DIV_MASK << MASTER_DIV_SHIFT),
+                          (div << MASTER_DIV_SHIFT));
+       while (!clk_master_ready(master))
+               cpu_relax();
+       spin_unlock_irqrestore(master->lock, flags);
+
+       return 0;
+}
+
+static int clk_master_div_determine_rate(struct clk_hw *hw,
+                                        struct clk_rate_request *req)
+{
+       struct clk_master *master = to_clk_master(hw);
+       const struct clk_master_characteristics *characteristics =
+                                               master->characteristics;
+       struct clk_hw *parent;
+       unsigned long parent_rate, tmp_rate, best_rate = 0;
+       int i, best_diff = INT_MIN, tmp_diff;
+
+       parent = clk_hw_get_parent(hw);
+       if (!parent)
+               return -EINVAL;
+
+       parent_rate = clk_hw_get_rate(parent);
+       if (!parent_rate)
+               return -EINVAL;
+
+       for (i = 0; i < ARRAY_SIZE(characteristics->divisors); i++) {
+               if (!characteristics->divisors[i])
+                       break;
+
+               tmp_rate = DIV_ROUND_CLOSEST_ULL(parent_rate,
+                                                characteristics->divisors[i]);
+               tmp_diff = abs(tmp_rate - req->rate);
+
+               if (!best_rate || best_diff > tmp_diff) {
+                       best_diff = tmp_diff;
+                       best_rate = tmp_rate;
+               }
+
+               if (!best_diff)
+                       break;
+       }
+
+       req->best_parent_rate = best_rate;
+       req->best_parent_hw = parent;
+       req->rate = best_rate;
+
+       return 0;
+}
+
+static const struct clk_ops master_div_ops_chg = {
+       .prepare = clk_master_prepare,
+       .is_prepared = clk_master_is_prepared,
+       .recalc_rate = clk_master_div_recalc_rate,
+       .determine_rate = clk_master_div_determine_rate,
+       .set_rate = clk_master_div_set_rate,
+};
+
+static void clk_sama7g5_master_best_diff(struct clk_rate_request *req,
+                                        struct clk_hw *parent,
+                                        unsigned long parent_rate,
+                                        long *best_rate,
+                                        long *best_diff,
+                                        u32 div)
+{
+       unsigned long tmp_rate, tmp_diff;
+
+       if (div == MASTER_PRES_MAX)
+               tmp_rate = parent_rate / 3;
+       else
+               tmp_rate = parent_rate >> div;
+
+       tmp_diff = abs(req->rate - tmp_rate);
+
+       if (*best_diff < 0 || *best_diff >= tmp_diff) {
+               *best_rate = tmp_rate;
+               *best_diff = tmp_diff;
+               req->best_parent_rate = parent_rate;
+               req->best_parent_hw = parent;
+       }
+}
+
+static int clk_master_pres_determine_rate(struct clk_hw *hw,
+                                         struct clk_rate_request *req)
 {
        struct clk_master *master = to_clk_master(hw);
+       struct clk_rate_request req_parent = *req;
+       const struct clk_master_characteristics *characteristics =
+                                                       master->characteristics;
+       struct clk_hw *parent;
+       long best_rate = LONG_MIN, best_diff = LONG_MIN;
+       u32 pres;
+       int i;
+
+       if (master->chg_pid < 0)
+               return -EOPNOTSUPP;
+
+       parent = clk_hw_get_parent_by_index(hw, master->chg_pid);
+       if (!parent)
+               return -EOPNOTSUPP;
+
+       for (i = 0; i <= MASTER_PRES_MAX; i++) {
+               if (characteristics->have_div3_pres && i == MASTER_PRES_MAX)
+                       pres = 3;
+               else
+                       pres = 1 << i;
+
+               req_parent.rate = req->rate * pres;
+               if (__clk_determine_rate(parent, &req_parent))
+                       continue;
+
+               clk_sama7g5_master_best_diff(req, parent, req_parent.rate,
+                                            &best_diff, &best_rate, pres);
+               if (!best_diff)
+                       break;
+       }
+
+       return 0;
+}
+
+static int clk_master_pres_set_rate(struct clk_hw *hw, unsigned long rate,
+                                   unsigned long parent_rate)
+{
+       struct clk_master *master = to_clk_master(hw);
+       unsigned long flags;
+       unsigned int pres;
+
+       pres = DIV_ROUND_CLOSEST(parent_rate, rate);
+       if (pres > MASTER_PRES_MAX)
+               return -EINVAL;
+
+       else if (pres == 3)
+               pres = MASTER_PRES_MAX;
+       else
+               pres = ffs(pres) - 1;
+
+       spin_lock_irqsave(master->lock, flags);
+       regmap_update_bits(master->regmap, master->layout->offset,
+                          (MASTER_PRES_MASK << master->layout->pres_shift),
+                          (pres << master->layout->pres_shift));
+
+       while (!clk_master_ready(master))
+               cpu_relax();
+       spin_unlock_irqrestore(master->lock, flags);
+
+       return 0;
+}
+
+static unsigned long clk_master_pres_recalc_rate(struct clk_hw *hw,
+                                                unsigned long parent_rate)
+{
+       struct clk_master *master = to_clk_master(hw);
+       const struct clk_master_characteristics *characteristics =
+                                               master->characteristics;
+       unsigned long flags;
+       unsigned int val, pres;
+
+       spin_lock_irqsave(master->lock, flags);
+       regmap_read(master->regmap, master->layout->offset, &val);
+       spin_unlock_irqrestore(master->lock, flags);
+
+       pres = (val >> master->layout->pres_shift) & MASTER_PRES_MASK;
+       if (pres == 3 && characteristics->have_div3_pres)
+               pres = 3;
+       else
+               pres = (1 << pres);
+
+       return DIV_ROUND_CLOSEST_ULL(parent_rate, pres);
+}
+
+static u8 clk_master_pres_get_parent(struct clk_hw *hw)
+{
+       struct clk_master *master = to_clk_master(hw);
+       unsigned long flags;
        unsigned int mckr;
 
+       spin_lock_irqsave(master->lock, flags);
        regmap_read(master->regmap, master->layout->offset, &mckr);
+       spin_unlock_irqrestore(master->lock, flags);
 
        return mckr & AT91_PMC_CSS;
 }
 
-static const struct clk_ops master_ops = {
+static const struct clk_ops master_pres_ops = {
        .prepare = clk_master_prepare,
        .is_prepared = clk_master_is_prepared,
-       .recalc_rate = clk_master_recalc_rate,
-       .get_parent = clk_master_get_parent,
+       .recalc_rate = clk_master_pres_recalc_rate,
+       .get_parent = clk_master_pres_get_parent,
 };
 
-struct clk_hw * __init
-at91_clk_register_master(struct regmap *regmap,
+static const struct clk_ops master_pres_ops_chg = {
+       .prepare = clk_master_prepare,
+       .is_prepared = clk_master_is_prepared,
+       .determine_rate = clk_master_pres_determine_rate,
+       .recalc_rate = clk_master_pres_recalc_rate,
+       .get_parent = clk_master_pres_get_parent,
+       .set_rate = clk_master_pres_set_rate,
+};
+
+static struct clk_hw * __init
+at91_clk_register_master_internal(struct regmap *regmap,
                const char *name, int num_parents,
                const char **parent_names,
                const struct clk_master_layout *layout,
-               const struct clk_master_characteristics *characteristics)
+               const struct clk_master_characteristics *characteristics,
+               const struct clk_ops *ops, spinlock_t *lock, u32 flags,
+               int chg_pid)
 {
        struct clk_master *master;
        struct clk_init_data init;
        struct clk_hw *hw;
        int ret;
 
-       if (!name || !num_parents || !parent_names)
+       if (!name || !num_parents || !parent_names || !lock)
                return ERR_PTR(-EINVAL);
 
        master = kzalloc(sizeof(*master), GFP_KERNEL);
@@ -142,15 +368,17 @@ at91_clk_register_master(struct regmap *regmap,
                return ERR_PTR(-ENOMEM);
 
        init.name = name;
-       init.ops = &master_ops;
+       init.ops = ops;
        init.parent_names = parent_names;
        init.num_parents = num_parents;
-       init.flags = 0;
+       init.flags = flags;
 
        master->hw.init = &init;
        master->layout = layout;
        master->characteristics = characteristics;
        master->regmap = regmap;
+       master->chg_pid = chg_pid;
+       master->lock = lock;
 
        hw = &master->hw;
        ret = clk_hw_register(NULL, &master->hw);
@@ -162,37 +390,54 @@ at91_clk_register_master(struct regmap *regmap,
        return hw;
 }
 
-static unsigned long
-clk_sama7g5_master_recalc_rate(struct clk_hw *hw,
-                              unsigned long parent_rate)
+struct clk_hw * __init
+at91_clk_register_master_pres(struct regmap *regmap,
+               const char *name, int num_parents,
+               const char **parent_names,
+               const struct clk_master_layout *layout,
+               const struct clk_master_characteristics *characteristics,
+               spinlock_t *lock, u32 flags, int chg_pid)
 {
-       struct clk_master *master = to_clk_master(hw);
+       const struct clk_ops *ops;
 
-       return DIV_ROUND_CLOSEST_ULL(parent_rate, (1 << master->div));
+       if (flags & CLK_SET_RATE_GATE)
+               ops = &master_pres_ops;
+       else
+               ops = &master_pres_ops_chg;
+
+       return at91_clk_register_master_internal(regmap, name, num_parents,
+                                                parent_names, layout,
+                                                characteristics, ops,
+                                                lock, flags, chg_pid);
 }
 
-static void clk_sama7g5_master_best_diff(struct clk_rate_request *req,
-                                        struct clk_hw *parent,
-                                        unsigned long parent_rate,
-                                        long *best_rate,
-                                        long *best_diff,
-                                        u32 div)
+struct clk_hw * __init
+at91_clk_register_master_div(struct regmap *regmap,
+               const char *name, const char *parent_name,
+               const struct clk_master_layout *layout,
+               const struct clk_master_characteristics *characteristics,
+               spinlock_t *lock, u32 flags)
 {
-       unsigned long tmp_rate, tmp_diff;
+       const struct clk_ops *ops;
 
-       if (div == MASTER_PRES_MAX)
-               tmp_rate = parent_rate / 3;
+       if (flags & CLK_SET_RATE_GATE)
+               ops = &master_div_ops;
        else
-               tmp_rate = parent_rate >> div;
+               ops = &master_div_ops_chg;
 
-       tmp_diff = abs(req->rate - tmp_rate);
+       return at91_clk_register_master_internal(regmap, name, 1,
+                                                &parent_name, layout,
+                                                characteristics, ops,
+                                                lock, flags, -EINVAL);
+}
 
-       if (*best_diff < 0 || *best_diff >= tmp_diff) {
-               *best_rate = tmp_rate;
-               *best_diff = tmp_diff;
-               req->best_parent_rate = parent_rate;
-               req->best_parent_hw = parent;
-       }
+static unsigned long
+clk_sama7g5_master_recalc_rate(struct clk_hw *hw,
+                              unsigned long parent_rate)
+{
+       struct clk_master *master = to_clk_master(hw);
+
+       return DIV_ROUND_CLOSEST_ULL(parent_rate, (1 << master->div));
 }
 
 static int clk_sama7g5_master_determine_rate(struct clk_hw *hw,
index 78f458a..34e3ab1 100644 (file)
@@ -229,6 +229,57 @@ static int sam9x60_frac_pll_set_rate(struct clk_hw *hw, unsigned long rate,
        return sam9x60_frac_pll_compute_mul_frac(core, rate, parent_rate, true);
 }
 
+static int sam9x60_frac_pll_set_rate_chg(struct clk_hw *hw, unsigned long rate,
+                                        unsigned long parent_rate)
+{
+       struct sam9x60_pll_core *core = to_sam9x60_pll_core(hw);
+       struct sam9x60_frac *frac = to_sam9x60_frac(core);
+       struct regmap *regmap = core->regmap;
+       unsigned long irqflags;
+       unsigned int val, cfrac, cmul;
+       long ret;
+
+       ret = sam9x60_frac_pll_compute_mul_frac(core, rate, parent_rate, true);
+       if (ret <= 0)
+               return ret;
+
+       spin_lock_irqsave(core->lock, irqflags);
+
+       regmap_update_bits(regmap, AT91_PMC_PLL_UPDT, AT91_PMC_PLL_UPDT_ID_MSK,
+                          core->id);
+       regmap_read(regmap, AT91_PMC_PLL_CTRL1, &val);
+       cmul = (val & core->layout->mul_mask) >> core->layout->mul_shift;
+       cfrac = (val & core->layout->frac_mask) >> core->layout->frac_shift;
+
+       if (cmul == frac->mul && cfrac == frac->frac)
+               goto unlock;
+
+       regmap_write(regmap, AT91_PMC_PLL_CTRL1,
+                    (frac->mul << core->layout->mul_shift) |
+                    (frac->frac << core->layout->frac_shift));
+
+       regmap_update_bits(regmap, AT91_PMC_PLL_UPDT,
+                          AT91_PMC_PLL_UPDT_UPDATE | AT91_PMC_PLL_UPDT_ID_MSK,
+                          AT91_PMC_PLL_UPDT_UPDATE | core->id);
+
+       regmap_update_bits(regmap, AT91_PMC_PLL_CTRL0,
+                          AT91_PMC_PLL_CTRL0_ENLOCK | AT91_PMC_PLL_CTRL0_ENPLL,
+                          AT91_PMC_PLL_CTRL0_ENLOCK |
+                          AT91_PMC_PLL_CTRL0_ENPLL);
+
+       regmap_update_bits(regmap, AT91_PMC_PLL_UPDT,
+                          AT91_PMC_PLL_UPDT_UPDATE | AT91_PMC_PLL_UPDT_ID_MSK,
+                          AT91_PMC_PLL_UPDT_UPDATE | core->id);
+
+       while (!sam9x60_pll_ready(regmap, core->id))
+               cpu_relax();
+
+unlock:
+       spin_unlock_irqrestore(core->lock, irqflags);
+
+       return ret;
+}
+
 static const struct clk_ops sam9x60_frac_pll_ops = {
        .prepare = sam9x60_frac_pll_prepare,
        .unprepare = sam9x60_frac_pll_unprepare,
@@ -238,6 +289,15 @@ static const struct clk_ops sam9x60_frac_pll_ops = {
        .set_rate = sam9x60_frac_pll_set_rate,
 };
 
+static const struct clk_ops sam9x60_frac_pll_ops_chg = {
+       .prepare = sam9x60_frac_pll_prepare,
+       .unprepare = sam9x60_frac_pll_unprepare,
+       .is_prepared = sam9x60_frac_pll_is_prepared,
+       .recalc_rate = sam9x60_frac_pll_recalc_rate,
+       .round_rate = sam9x60_frac_pll_round_rate,
+       .set_rate = sam9x60_frac_pll_set_rate_chg,
+};
+
 static int sam9x60_div_pll_prepare(struct clk_hw *hw)
 {
        struct sam9x60_pll_core *core = to_sam9x60_pll_core(hw);
@@ -384,6 +444,44 @@ static int sam9x60_div_pll_set_rate(struct clk_hw *hw, unsigned long rate,
        return 0;
 }
 
+static int sam9x60_div_pll_set_rate_chg(struct clk_hw *hw, unsigned long rate,
+                                       unsigned long parent_rate)
+{
+       struct sam9x60_pll_core *core = to_sam9x60_pll_core(hw);
+       struct sam9x60_div *div = to_sam9x60_div(core);
+       struct regmap *regmap = core->regmap;
+       unsigned long irqflags;
+       unsigned int val, cdiv;
+
+       div->div = DIV_ROUND_CLOSEST(parent_rate, rate) - 1;
+
+       spin_lock_irqsave(core->lock, irqflags);
+       regmap_update_bits(regmap, AT91_PMC_PLL_UPDT, AT91_PMC_PLL_UPDT_ID_MSK,
+                          core->id);
+       regmap_read(regmap, AT91_PMC_PLL_CTRL0, &val);
+       cdiv = (val & core->layout->div_mask) >> core->layout->div_shift;
+
+       /* Stop if nothing changed. */
+       if (cdiv == div->div)
+               goto unlock;
+
+       regmap_update_bits(regmap, AT91_PMC_PLL_CTRL0,
+                          core->layout->div_mask,
+                          (div->div << core->layout->div_shift));
+
+       regmap_update_bits(regmap, AT91_PMC_PLL_UPDT,
+                          AT91_PMC_PLL_UPDT_UPDATE | AT91_PMC_PLL_UPDT_ID_MSK,
+                          AT91_PMC_PLL_UPDT_UPDATE | core->id);
+
+       while (!sam9x60_pll_ready(regmap, core->id))
+               cpu_relax();
+
+unlock:
+       spin_unlock_irqrestore(core->lock, irqflags);
+
+       return 0;
+}
+
 static const struct clk_ops sam9x60_div_pll_ops = {
        .prepare = sam9x60_div_pll_prepare,
        .unprepare = sam9x60_div_pll_unprepare,
@@ -393,17 +491,26 @@ static const struct clk_ops sam9x60_div_pll_ops = {
        .set_rate = sam9x60_div_pll_set_rate,
 };
 
+static const struct clk_ops sam9x60_div_pll_ops_chg = {
+       .prepare = sam9x60_div_pll_prepare,
+       .unprepare = sam9x60_div_pll_unprepare,
+       .is_prepared = sam9x60_div_pll_is_prepared,
+       .recalc_rate = sam9x60_div_pll_recalc_rate,
+       .round_rate = sam9x60_div_pll_round_rate,
+       .set_rate = sam9x60_div_pll_set_rate_chg,
+};
+
 struct clk_hw * __init
 sam9x60_clk_register_frac_pll(struct regmap *regmap, spinlock_t *lock,
                              const char *name, const char *parent_name,
                              struct clk_hw *parent_hw, u8 id,
                              const struct clk_pll_characteristics *characteristics,
-                             const struct clk_pll_layout *layout, bool critical)
+                             const struct clk_pll_layout *layout, u32 flags)
 {
        struct sam9x60_frac *frac;
        struct clk_hw *hw;
        struct clk_init_data init;
-       unsigned long parent_rate, flags;
+       unsigned long parent_rate, irqflags;
        unsigned int val;
        int ret;
 
@@ -417,10 +524,12 @@ sam9x60_clk_register_frac_pll(struct regmap *regmap, spinlock_t *lock,
        init.name = name;
        init.parent_names = &parent_name;
        init.num_parents = 1;
-       init.ops = &sam9x60_frac_pll_ops;
-       init.flags = CLK_SET_RATE_GATE;
-       if (critical)
-               init.flags |= CLK_IS_CRITICAL;
+       if (flags & CLK_SET_RATE_GATE)
+               init.ops = &sam9x60_frac_pll_ops;
+       else
+               init.ops = &sam9x60_frac_pll_ops_chg;
+
+       init.flags = flags;
 
        frac->core.id = id;
        frac->core.hw.init = &init;
@@ -429,7 +538,7 @@ sam9x60_clk_register_frac_pll(struct regmap *regmap, spinlock_t *lock,
        frac->core.regmap = regmap;
        frac->core.lock = lock;
 
-       spin_lock_irqsave(frac->core.lock, flags);
+       spin_lock_irqsave(frac->core.lock, irqflags);
        if (sam9x60_pll_ready(regmap, id)) {
                regmap_update_bits(regmap, AT91_PMC_PLL_UPDT,
                                   AT91_PMC_PLL_UPDT_ID_MSK, id);
@@ -457,7 +566,7 @@ sam9x60_clk_register_frac_pll(struct regmap *regmap, spinlock_t *lock,
                        goto free;
                }
        }
-       spin_unlock_irqrestore(frac->core.lock, flags);
+       spin_unlock_irqrestore(frac->core.lock, irqflags);
 
        hw = &frac->core.hw;
        ret = clk_hw_register(NULL, hw);
@@ -469,7 +578,7 @@ sam9x60_clk_register_frac_pll(struct regmap *regmap, spinlock_t *lock,
        return hw;
 
 free:
-       spin_unlock_irqrestore(frac->core.lock, flags);
+       spin_unlock_irqrestore(frac->core.lock, irqflags);
        kfree(frac);
        return hw;
 }
@@ -478,12 +587,12 @@ struct clk_hw * __init
 sam9x60_clk_register_div_pll(struct regmap *regmap, spinlock_t *lock,
                             const char *name, const char *parent_name, u8 id,
                             const struct clk_pll_characteristics *characteristics,
-                            const struct clk_pll_layout *layout, bool critical)
+                            const struct clk_pll_layout *layout, u32 flags)
 {
        struct sam9x60_div *div;
        struct clk_hw *hw;
        struct clk_init_data init;
-       unsigned long flags;
+       unsigned long irqflags;
        unsigned int val;
        int ret;
 
@@ -497,11 +606,11 @@ sam9x60_clk_register_div_pll(struct regmap *regmap, spinlock_t *lock,
        init.name = name;
        init.parent_names = &parent_name;
        init.num_parents = 1;
-       init.ops = &sam9x60_div_pll_ops;
-       init.flags = CLK_SET_RATE_GATE | CLK_SET_PARENT_GATE |
-                    CLK_SET_RATE_PARENT;
-       if (critical)
-               init.flags |= CLK_IS_CRITICAL;
+       if (flags & CLK_SET_RATE_GATE)
+               init.ops = &sam9x60_div_pll_ops;
+       else
+               init.ops = &sam9x60_div_pll_ops_chg;
+       init.flags = flags;
 
        div->core.id = id;
        div->core.hw.init = &init;
@@ -510,14 +619,14 @@ sam9x60_clk_register_div_pll(struct regmap *regmap, spinlock_t *lock,
        div->core.regmap = regmap;
        div->core.lock = lock;
 
-       spin_lock_irqsave(div->core.lock, flags);
+       spin_lock_irqsave(div->core.lock, irqflags);
 
        regmap_update_bits(regmap, AT91_PMC_PLL_UPDT,
                           AT91_PMC_PLL_UPDT_ID_MSK, id);
        regmap_read(regmap, AT91_PMC_PLL_CTRL0, &val);
        div->div = FIELD_GET(PMC_PLL_CTRL0_DIV_MSK, val);
 
-       spin_unlock_irqrestore(div->core.lock, flags);
+       spin_unlock_irqrestore(div->core.lock, irqflags);
 
        hw = &div->core.hw;
        ret = clk_hw_register(NULL, hw);
index a50084d..a97b99c 100644 (file)
@@ -24,6 +24,8 @@
 
 #define GCK_INDEX_DT_AUDIO_PLL 5
 
+static DEFINE_SPINLOCK(mck_lock);
+
 #ifdef CONFIG_HAVE_AT91_AUDIO_PLL
 static void __init of_sama5d2_clk_audio_pll_frac_setup(struct device_node *np)
 {
@@ -388,9 +390,16 @@ of_at91_clk_master_setup(struct device_node *np,
        if (IS_ERR(regmap))
                return;
 
-       hw = at91_clk_register_master(regmap, name, num_parents,
-                                     parent_names, layout,
-                                     characteristics);
+       hw = at91_clk_register_master_pres(regmap, "masterck_pres", num_parents,
+                                          parent_names, layout,
+                                          characteristics, &mck_lock,
+                                          CLK_SET_RATE_GATE, INT_MIN);
+       if (IS_ERR(hw))
+               goto out_free_characteristics;
+
+       hw = at91_clk_register_master_div(regmap, name, "masterck_pres",
+                                         layout, characteristics,
+                                         &mck_lock, CLK_SET_RATE_GATE);
        if (IS_ERR(hw))
                goto out_free_characteristics;
 
index 7b86aff..a49076c 100644 (file)
@@ -48,7 +48,7 @@ extern const struct clk_master_layout at91sam9x5_master_layout;
 
 struct clk_master_characteristics {
        struct clk_range output;
-       u32 divisors[4];
+       u32 divisors[5];
        u8 have_div3_pres;
 };
 
@@ -155,10 +155,18 @@ at91_clk_register_sam9x5_main(struct regmap *regmap, const char *name,
                              const char **parent_names, int num_parents);
 
 struct clk_hw * __init
-at91_clk_register_master(struct regmap *regmap, const char *name,
-                        int num_parents, const char **parent_names,
-                        const struct clk_master_layout *layout,
-                        const struct clk_master_characteristics *characteristics);
+at91_clk_register_master_pres(struct regmap *regmap, const char *name,
+                             int num_parents, const char **parent_names,
+                             const struct clk_master_layout *layout,
+                             const struct clk_master_characteristics *characteristics,
+                             spinlock_t *lock, u32 flags, int chg_pid);
+
+struct clk_hw * __init
+at91_clk_register_master_div(struct regmap *regmap, const char *name,
+                            const char *parent_names,
+                            const struct clk_master_layout *layout,
+                            const struct clk_master_characteristics *characteristics,
+                            spinlock_t *lock, u32 flags);
 
 struct clk_hw * __init
 at91_clk_sama7g5_register_master(struct regmap *regmap,
@@ -190,14 +198,14 @@ struct clk_hw * __init
 sam9x60_clk_register_div_pll(struct regmap *regmap, spinlock_t *lock,
                             const char *name, const char *parent_name, u8 id,
                             const struct clk_pll_characteristics *characteristics,
-                            const struct clk_pll_layout *layout, bool critical);
+                            const struct clk_pll_layout *layout, u32 flags);
 
 struct clk_hw * __init
 sam9x60_clk_register_frac_pll(struct regmap *regmap, spinlock_t *lock,
                              const char *name, const char *parent_name,
                              struct clk_hw *parent_hw, u8 id,
                              const struct clk_pll_characteristics *characteristics,
-                             const struct clk_pll_layout *layout, bool critical);
+                             const struct clk_pll_layout *layout, u32 flags);
 
 struct clk_hw * __init
 at91_clk_register_programmable(struct regmap *regmap, const char *name,
index 3c4c956..5f6fa89 100644 (file)
@@ -8,6 +8,7 @@
 #include "pmc.h"
 
 static DEFINE_SPINLOCK(pmc_pll_lock);
+static DEFINE_SPINLOCK(mck_lock);
 
 static const struct clk_master_characteristics mck_characteristics = {
        .output = { .min = 140000000, .max = 200000000 },
@@ -76,11 +77,11 @@ static const struct {
        char *p;
        u8 id;
 } sam9x60_systemck[] = {
-       { .n = "ddrck",  .p = "masterck", .id = 2 },
+       { .n = "ddrck",  .p = "masterck_div", .id = 2 },
        { .n = "uhpck",  .p = "usbck",    .id = 6 },
        { .n = "pck0",   .p = "prog0",    .id = 8 },
        { .n = "pck1",   .p = "prog1",    .id = 9 },
-       { .n = "qspick", .p = "masterck", .id = 19 },
+       { .n = "qspick", .p = "masterck_div", .id = 19 },
 };
 
 static const struct {
@@ -174,7 +175,6 @@ static void __init sam9x60_pmc_setup(struct device_node *np)
        struct regmap *regmap;
        struct clk_hw *hw;
        int i;
-       bool bypass;
 
        i = of_property_match_string(np, "clock-names", "td_slck");
        if (i < 0)
@@ -209,10 +209,7 @@ static void __init sam9x60_pmc_setup(struct device_node *np)
        if (IS_ERR(hw))
                goto err_free;
 
-       bypass = of_property_read_bool(np, "atmel,osc-bypass");
-
-       hw = at91_clk_register_main_osc(regmap, "main_osc", mainxtal_name,
-                                       bypass);
+       hw = at91_clk_register_main_osc(regmap, "main_osc", mainxtal_name, 0);
        if (IS_ERR(hw))
                goto err_free;
        main_osc_hw = hw;
@@ -228,13 +225,24 @@ static void __init sam9x60_pmc_setup(struct device_node *np)
        hw = sam9x60_clk_register_frac_pll(regmap, &pmc_pll_lock, "pllack_fracck",
                                           "mainck", sam9x60_pmc->chws[PMC_MAIN],
                                           0, &plla_characteristics,
-                                          &pll_frac_layout, true);
+                                          &pll_frac_layout,
+                                          /*
+                                           * This feeds pllack_divck which
+                                           * feeds CPU. It should not be
+                                           * disabled.
+                                           */
+                                          CLK_IS_CRITICAL | CLK_SET_RATE_GATE);
        if (IS_ERR(hw))
                goto err_free;
 
        hw = sam9x60_clk_register_div_pll(regmap, &pmc_pll_lock, "pllack_divck",
                                          "pllack_fracck", 0, &plla_characteristics,
-                                         &pll_div_layout, true);
+                                         &pll_div_layout,
+                                          /*
+                                           * This feeds CPU. It should not
+                                           * be disabled.
+                                           */
+                                         CLK_IS_CRITICAL | CLK_SET_RATE_GATE);
        if (IS_ERR(hw))
                goto err_free;
 
@@ -243,13 +251,16 @@ static void __init sam9x60_pmc_setup(struct device_node *np)
        hw = sam9x60_clk_register_frac_pll(regmap, &pmc_pll_lock, "upllck_fracck",
                                           "main_osc", main_osc_hw, 1,
                                           &upll_characteristics,
-                                          &pll_frac_layout, false);
+                                          &pll_frac_layout, CLK_SET_RATE_GATE);
        if (IS_ERR(hw))
                goto err_free;
 
        hw = sam9x60_clk_register_div_pll(regmap, &pmc_pll_lock, "upllck_divck",
                                          "upllck_fracck", 1, &upll_characteristics,
-                                         &pll_div_layout, false);
+                                         &pll_div_layout,
+                                         CLK_SET_RATE_GATE |
+                                         CLK_SET_PARENT_GATE |
+                                         CLK_SET_RATE_PARENT);
        if (IS_ERR(hw))
                goto err_free;
 
@@ -258,9 +269,17 @@ static void __init sam9x60_pmc_setup(struct device_node *np)
        parent_names[0] = md_slck_name;
        parent_names[1] = "mainck";
        parent_names[2] = "pllack_divck";
-       hw = at91_clk_register_master(regmap, "masterck", 3, parent_names,
-                                     &sam9x60_master_layout,
-                                     &mck_characteristics);
+       hw = at91_clk_register_master_pres(regmap, "masterck_pres", 3,
+                                          parent_names, &sam9x60_master_layout,
+                                          &mck_characteristics, &mck_lock,
+                                          CLK_SET_RATE_GATE, INT_MIN);
+       if (IS_ERR(hw))
+               goto err_free;
+
+       hw = at91_clk_register_master_div(regmap, "masterck_div",
+                                         "masterck_pres", &sam9x60_master_layout,
+                                         &mck_characteristics, &mck_lock,
+                                         CLK_SET_RATE_GATE);
        if (IS_ERR(hw))
                goto err_free;
 
@@ -276,7 +295,7 @@ static void __init sam9x60_pmc_setup(struct device_node *np)
        parent_names[0] = md_slck_name;
        parent_names[1] = td_slck_name;
        parent_names[2] = "mainck";
-       parent_names[3] = "masterck";
+       parent_names[3] = "masterck_div";
        parent_names[4] = "pllack_divck";
        parent_names[5] = "upllck_divck";
        for (i = 0; i < 2; i++) {
@@ -308,7 +327,7 @@ static void __init sam9x60_pmc_setup(struct device_node *np)
                hw = at91_clk_register_sam9x5_peripheral(regmap, &pmc_pcr_lock,
                                                         &sam9x60_pcr_layout,
                                                         sam9x60_periphck[i].n,
-                                                        "masterck",
+                                                        "masterck_div",
                                                         sam9x60_periphck[i].id,
                                                         &range, INT_MIN);
                if (IS_ERR(hw))
index 8b22076..9a5cbc7 100644 (file)
@@ -7,6 +7,8 @@
 
 #include "pmc.h"
 
+static DEFINE_SPINLOCK(mck_lock);
+
 static const struct clk_master_characteristics mck_characteristics = {
        .output = { .min = 124000000, .max = 166000000 },
        .divisors = { 1, 2, 4, 3 },
@@ -40,14 +42,14 @@ static const struct {
        char *p;
        u8 id;
 } sama5d2_systemck[] = {
-       { .n = "ddrck", .p = "masterck", .id = 2 },
-       { .n = "lcdck", .p = "masterck", .id = 3 },
-       { .n = "uhpck", .p = "usbck",    .id = 6 },
-       { .n = "udpck", .p = "usbck",    .id = 7 },
-       { .n = "pck0",  .p = "prog0",    .id = 8 },
-       { .n = "pck1",  .p = "prog1",    .id = 9 },
-       { .n = "pck2",  .p = "prog2",    .id = 10 },
-       { .n = "iscck", .p = "masterck", .id = 18 },
+       { .n = "ddrck", .p = "masterck_div", .id = 2 },
+       { .n = "lcdck", .p = "masterck_div", .id = 3 },
+       { .n = "uhpck", .p = "usbck",        .id = 6 },
+       { .n = "udpck", .p = "usbck",        .id = 7 },
+       { .n = "pck0",  .p = "prog0",        .id = 8 },
+       { .n = "pck1",  .p = "prog1",        .id = 9 },
+       { .n = "pck2",  .p = "prog2",        .id = 10 },
+       { .n = "iscck", .p = "masterck_div", .id = 18 },
 };
 
 static const struct {
@@ -235,15 +237,25 @@ static void __init sama5d2_pmc_setup(struct device_node *np)
        parent_names[1] = "mainck";
        parent_names[2] = "plladivck";
        parent_names[3] = "utmick";
-       hw = at91_clk_register_master(regmap, "masterck", 4, parent_names,
-                                     &at91sam9x5_master_layout,
-                                     &mck_characteristics);
+       hw = at91_clk_register_master_pres(regmap, "masterck_pres", 4,
+                                          parent_names,
+                                          &at91sam9x5_master_layout,
+                                          &mck_characteristics, &mck_lock,
+                                          CLK_SET_RATE_GATE, INT_MIN);
+       if (IS_ERR(hw))
+               goto err_free;
+
+       hw = at91_clk_register_master_div(regmap, "masterck_div",
+                                         "masterck_pres",
+                                         &at91sam9x5_master_layout,
+                                         &mck_characteristics, &mck_lock,
+                                         CLK_SET_RATE_GATE);
        if (IS_ERR(hw))
                goto err_free;
 
        sama5d2_pmc->chws[PMC_MCK] = hw;
 
-       hw = at91_clk_register_h32mx(regmap, "h32mxck", "masterck");
+       hw = at91_clk_register_h32mx(regmap, "h32mxck", "masterck_div");
        if (IS_ERR(hw))
                goto err_free;
 
@@ -259,7 +271,7 @@ static void __init sama5d2_pmc_setup(struct device_node *np)
        parent_names[1] = "mainck";
        parent_names[2] = "plladivck";
        parent_names[3] = "utmick";
-       parent_names[4] = "masterck";
+       parent_names[4] = "masterck_div";
        parent_names[5] = "audiopll_pmcck";
        for (i = 0; i < 3; i++) {
                char name[6];
@@ -290,7 +302,7 @@ static void __init sama5d2_pmc_setup(struct device_node *np)
                hw = at91_clk_register_sam9x5_peripheral(regmap, &pmc_pcr_lock,
                                                         &sama5d2_pcr_layout,
                                                         sama5d2_periphck[i].n,
-                                                        "masterck",
+                                                        "masterck_div",
                                                         sama5d2_periphck[i].id,
                                                         &range, INT_MIN);
                if (IS_ERR(hw))
@@ -317,7 +329,7 @@ static void __init sama5d2_pmc_setup(struct device_node *np)
        parent_names[1] = "mainck";
        parent_names[2] = "plladivck";
        parent_names[3] = "utmick";
-       parent_names[4] = "masterck";
+       parent_names[4] = "masterck_div";
        parent_names[5] = "audiopll_pmcck";
        for (i = 0; i < ARRAY_SIZE(sama5d2_gck); i++) {
                hw = at91_clk_register_generated(regmap, &pmc_pcr_lock,
index 7c6e0a5..87009ee 100644 (file)
@@ -7,6 +7,8 @@
 
 #include "pmc.h"
 
+static DEFINE_SPINLOCK(mck_lock);
+
 static const struct clk_master_characteristics mck_characteristics = {
        .output = { .min = 0, .max = 166000000 },
        .divisors = { 1, 2, 4, 3 },
@@ -40,14 +42,14 @@ static const struct {
        char *p;
        u8 id;
 } sama5d3_systemck[] = {
-       { .n = "ddrck", .p = "masterck", .id = 2 },
-       { .n = "lcdck", .p = "masterck", .id = 3 },
-       { .n = "smdck", .p = "smdclk",   .id = 4 },
-       { .n = "uhpck", .p = "usbck",    .id = 6 },
-       { .n = "udpck", .p = "usbck",    .id = 7 },
-       { .n = "pck0",  .p = "prog0",    .id = 8 },
-       { .n = "pck1",  .p = "prog1",    .id = 9 },
-       { .n = "pck2",  .p = "prog2",    .id = 10 },
+       { .n = "ddrck", .p = "masterck_div", .id = 2 },
+       { .n = "lcdck", .p = "masterck_div", .id = 3 },
+       { .n = "smdck", .p = "smdclk",       .id = 4 },
+       { .n = "uhpck", .p = "usbck",        .id = 6 },
+       { .n = "udpck", .p = "usbck",        .id = 7 },
+       { .n = "pck0",  .p = "prog0",        .id = 8 },
+       { .n = "pck1",  .p = "prog1",        .id = 9 },
+       { .n = "pck2",  .p = "prog2",        .id = 10 },
 };
 
 static const struct {
@@ -170,9 +172,19 @@ static void __init sama5d3_pmc_setup(struct device_node *np)
        parent_names[1] = "mainck";
        parent_names[2] = "plladivck";
        parent_names[3] = "utmick";
-       hw = at91_clk_register_master(regmap, "masterck", 4, parent_names,
-                                     &at91sam9x5_master_layout,
-                                     &mck_characteristics);
+       hw = at91_clk_register_master_pres(regmap, "masterck_pres", 4,
+                                          parent_names,
+                                          &at91sam9x5_master_layout,
+                                          &mck_characteristics, &mck_lock,
+                                          CLK_SET_RATE_GATE, INT_MIN);
+       if (IS_ERR(hw))
+               goto err_free;
+
+       hw = at91_clk_register_master_div(regmap, "masterck_div",
+                                         "masterck_pres",
+                                         &at91sam9x5_master_layout,
+                                         &mck_characteristics, &mck_lock,
+                                         CLK_SET_RATE_GATE);
        if (IS_ERR(hw))
                goto err_free;
 
@@ -192,7 +204,7 @@ static void __init sama5d3_pmc_setup(struct device_node *np)
        parent_names[1] = "mainck";
        parent_names[2] = "plladivck";
        parent_names[3] = "utmick";
-       parent_names[4] = "masterck";
+       parent_names[4] = "masterck_div";
        for (i = 0; i < 3; i++) {
                char name[6];
 
@@ -222,7 +234,7 @@ static void __init sama5d3_pmc_setup(struct device_node *np)
                hw = at91_clk_register_sam9x5_peripheral(regmap, &pmc_pcr_lock,
                                                         &sama5d3_pcr_layout,
                                                         sama5d3_periphck[i].n,
-                                                        "masterck",
+                                                        "masterck_div",
                                                         sama5d3_periphck[i].id,
                                                         &sama5d3_periphck[i].r,
                                                         INT_MIN);
index 92d8d41..57fff79 100644 (file)
@@ -7,6 +7,8 @@
 
 #include "pmc.h"
 
+static DEFINE_SPINLOCK(mck_lock);
+
 static const struct clk_master_characteristics mck_characteristics = {
        .output = { .min = 125000000, .max = 200000000 },
        .divisors = { 1, 2, 4, 3 },
@@ -39,14 +41,14 @@ static const struct {
        char *p;
        u8 id;
 } sama5d4_systemck[] = {
-       { .n = "ddrck", .p = "masterck", .id = 2 },
-       { .n = "lcdck", .p = "masterck", .id = 3 },
-       { .n = "smdck", .p = "smdclk",   .id = 4 },
-       { .n = "uhpck", .p = "usbck",    .id = 6 },
-       { .n = "udpck", .p = "usbck",    .id = 7 },
-       { .n = "pck0",  .p = "prog0",    .id = 8 },
-       { .n = "pck1",  .p = "prog1",    .id = 9 },
-       { .n = "pck2",  .p = "prog2",    .id = 10 },
+       { .n = "ddrck", .p = "masterck_div", .id = 2 },
+       { .n = "lcdck", .p = "masterck_div", .id = 3 },
+       { .n = "smdck", .p = "smdclk",       .id = 4 },
+       { .n = "uhpck", .p = "usbck",        .id = 6 },
+       { .n = "udpck", .p = "usbck",        .id = 7 },
+       { .n = "pck0",  .p = "prog0",        .id = 8 },
+       { .n = "pck1",  .p = "prog1",        .id = 9 },
+       { .n = "pck2",  .p = "prog2",        .id = 10 },
 };
 
 static const struct {
@@ -185,15 +187,25 @@ static void __init sama5d4_pmc_setup(struct device_node *np)
        parent_names[1] = "mainck";
        parent_names[2] = "plladivck";
        parent_names[3] = "utmick";
-       hw = at91_clk_register_master(regmap, "masterck", 4, parent_names,
-                                     &at91sam9x5_master_layout,
-                                     &mck_characteristics);
+       hw = at91_clk_register_master_pres(regmap, "masterck_pres", 4,
+                                          parent_names,
+                                          &at91sam9x5_master_layout,
+                                          &mck_characteristics, &mck_lock,
+                                          CLK_SET_RATE_GATE, INT_MIN);
+       if (IS_ERR(hw))
+               goto err_free;
+
+       hw = at91_clk_register_master_div(regmap, "masterck_div",
+                                         "masterck_pres",
+                                         &at91sam9x5_master_layout,
+                                         &mck_characteristics, &mck_lock,
+                                         CLK_SET_RATE_GATE);
        if (IS_ERR(hw))
                goto err_free;
 
        sama5d4_pmc->chws[PMC_MCK] = hw;
 
-       hw = at91_clk_register_h32mx(regmap, "h32mxck", "masterck");
+       hw = at91_clk_register_h32mx(regmap, "h32mxck", "masterck_div");
        if (IS_ERR(hw))
                goto err_free;
 
@@ -215,7 +227,7 @@ static void __init sama5d4_pmc_setup(struct device_node *np)
        parent_names[1] = "mainck";
        parent_names[2] = "plladivck";
        parent_names[3] = "utmick";
-       parent_names[4] = "masterck";
+       parent_names[4] = "masterck_div";
        for (i = 0; i < 3; i++) {
                char name[6];
 
@@ -245,7 +257,7 @@ static void __init sama5d4_pmc_setup(struct device_node *np)
                hw = at91_clk_register_sam9x5_peripheral(regmap, &pmc_pcr_lock,
                                                         &sama5d4_pcr_layout,
                                                         sama5d4_periphck[i].n,
-                                                        "masterck",
+                                                        "masterck_div",
                                                         sama5d4_periphck[i].id,
                                                         &range, INT_MIN);
                if (IS_ERR(hw))
index 0db2ab3..a6e20b3 100644 (file)
@@ -32,6 +32,7 @@
        } while (0)
 
 static DEFINE_SPINLOCK(pmc_pll_lock);
+static DEFINE_SPINLOCK(pmc_mck0_lock);
 static DEFINE_SPINLOCK(pmc_mckX_lock);
 
 /**
@@ -89,118 +90,198 @@ static const struct clk_pll_layout pll_layout_divio = {
        .endiv_shift    = 30,
 };
 
+/*
+ * CPU PLL output range.
+ * Notice: The upper limit has been setup to 1000000002 due to hardware
+ * block which cannot output exactly 1GHz.
+ */
+static const struct clk_range cpu_pll_outputs[] = {
+       { .min = 2343750, .max = 1000000002 },
+};
+
+/* PLL output range. */
+static const struct clk_range pll_outputs[] = {
+       { .min = 2343750, .max = 1200000000 },
+};
+
+/* CPU PLL characteristics. */
+static const struct clk_pll_characteristics cpu_pll_characteristics = {
+       .input = { .min = 12000000, .max = 50000000 },
+       .num_output = ARRAY_SIZE(cpu_pll_outputs),
+       .output = cpu_pll_outputs,
+};
+
+/* PLL characteristics. */
+static const struct clk_pll_characteristics pll_characteristics = {
+       .input = { .min = 12000000, .max = 50000000 },
+       .num_output = ARRAY_SIZE(pll_outputs),
+       .output = pll_outputs,
+};
+
 /**
  * PLL clocks description
  * @n:         clock name
  * @p:         clock parent
  * @l:         clock layout
+ * @c:         clock characteristics
  * @t:         clock type
- * @f:         true if clock is critical and cannot be disabled
+ * @f:         clock flags
  * @eid:       export index in sama7g5->chws[] array
  */
 static const struct {
        const char *n;
        const char *p;
        const struct clk_pll_layout *l;
+       const struct clk_pll_characteristics *c;
+       unsigned long f;
        u8 t;
-       u8 c;
        u8 eid;
 } sama7g5_plls[][PLL_ID_MAX] = {
        [PLL_ID_CPU] = {
                { .n = "cpupll_fracck",
                  .p = "mainck",
                  .l = &pll_layout_frac,
+                 .c = &cpu_pll_characteristics,
                  .t = PLL_TYPE_FRAC,
-                 .c = 1, },
+                  /*
+                   * This feeds cpupll_divpmcck which feeds CPU. It should
+                   * not be disabled.
+                   */
+                 .f = CLK_IS_CRITICAL, },
 
                { .n = "cpupll_divpmcck",
                  .p = "cpupll_fracck",
                  .l = &pll_layout_divpmc,
+                 .c = &cpu_pll_characteristics,
                  .t = PLL_TYPE_DIV,
-                 .c = 1, },
+                  /* This feeds CPU. It should not be disabled. */
+                 .f = CLK_IS_CRITICAL | CLK_SET_RATE_PARENT,
+                 .eid = PMC_CPUPLL, },
        },
 
        [PLL_ID_SYS] = {
                { .n = "syspll_fracck",
                  .p = "mainck",
                  .l = &pll_layout_frac,
+                 .c = &pll_characteristics,
                  .t = PLL_TYPE_FRAC,
-                 .c = 1, },
+                  /*
+                   * This feeds syspll_divpmcck which may feed critial parts
+                   * of the systems like timers. Therefore it should not be
+                   * disabled.
+                   */
+                 .f = CLK_IS_CRITICAL | CLK_SET_RATE_GATE, },
 
                { .n = "syspll_divpmcck",
                  .p = "syspll_fracck",
                  .l = &pll_layout_divpmc,
+                 .c = &pll_characteristics,
                  .t = PLL_TYPE_DIV,
-                 .c = 1, },
+                  /*
+                   * This may feed critial parts of the systems like timers.
+                   * Therefore it should not be disabled.
+                   */
+                 .f = CLK_IS_CRITICAL | CLK_SET_RATE_GATE,
+                 .eid = PMC_SYSPLL, },
        },
 
        [PLL_ID_DDR] = {
                { .n = "ddrpll_fracck",
                  .p = "mainck",
                  .l = &pll_layout_frac,
+                 .c = &pll_characteristics,
                  .t = PLL_TYPE_FRAC,
-                 .c = 1, },
+                  /*
+                   * This feeds ddrpll_divpmcck which feeds DDR. It should not
+                   * be disabled.
+                   */
+                 .f = CLK_IS_CRITICAL | CLK_SET_RATE_GATE, },
 
                { .n = "ddrpll_divpmcck",
                  .p = "ddrpll_fracck",
                  .l = &pll_layout_divpmc,
+                 .c = &pll_characteristics,
                  .t = PLL_TYPE_DIV,
-                 .c = 1, },
+                  /* This feeds DDR. It should not be disabled. */
+                 .f = CLK_IS_CRITICAL | CLK_SET_RATE_GATE, },
        },
 
        [PLL_ID_IMG] = {
                { .n = "imgpll_fracck",
                  .p = "mainck",
                  .l = &pll_layout_frac,
-                 .t = PLL_TYPE_FRAC, },
+                 .c = &pll_characteristics,
+                 .t = PLL_TYPE_FRAC,
+                 .f = CLK_SET_RATE_GATE, },
 
                { .n = "imgpll_divpmcck",
                  .p = "imgpll_fracck",
                  .l = &pll_layout_divpmc,
-                 .t = PLL_TYPE_DIV, },
+                 .c = &pll_characteristics,
+                 .t = PLL_TYPE_DIV,
+                 .f = CLK_SET_RATE_GATE | CLK_SET_PARENT_GATE |
+                      CLK_SET_RATE_PARENT, },
        },
 
        [PLL_ID_BAUD] = {
                { .n = "baudpll_fracck",
                  .p = "mainck",
                  .l = &pll_layout_frac,
-                 .t = PLL_TYPE_FRAC, },
+                 .c = &pll_characteristics,
+                 .t = PLL_TYPE_FRAC,
+                 .f = CLK_SET_RATE_GATE, },
 
                { .n = "baudpll_divpmcck",
                  .p = "baudpll_fracck",
                  .l = &pll_layout_divpmc,
-                 .t = PLL_TYPE_DIV, },
+                 .c = &pll_characteristics,
+                 .t = PLL_TYPE_DIV,
+                 .f = CLK_SET_RATE_GATE | CLK_SET_PARENT_GATE |
+                      CLK_SET_RATE_PARENT, },
        },
 
        [PLL_ID_AUDIO] = {
                { .n = "audiopll_fracck",
                  .p = "main_xtal",
                  .l = &pll_layout_frac,
-                 .t = PLL_TYPE_FRAC, },
+                 .c = &pll_characteristics,
+                 .t = PLL_TYPE_FRAC,
+                 .f = CLK_SET_RATE_GATE, },
 
                { .n = "audiopll_divpmcck",
                  .p = "audiopll_fracck",
                  .l = &pll_layout_divpmc,
+                 .c = &pll_characteristics,
                  .t = PLL_TYPE_DIV,
-                 .eid = PMC_I2S0_MUX, },
+                 .f = CLK_SET_RATE_GATE | CLK_SET_PARENT_GATE |
+                      CLK_SET_RATE_PARENT,
+                 .eid = PMC_AUDIOPMCPLL, },
 
                { .n = "audiopll_diviock",
                  .p = "audiopll_fracck",
                  .l = &pll_layout_divio,
+                 .c = &pll_characteristics,
                  .t = PLL_TYPE_DIV,
-                 .eid = PMC_I2S1_MUX, },
+                 .f = CLK_SET_RATE_GATE | CLK_SET_PARENT_GATE |
+                      CLK_SET_RATE_PARENT,
+                 .eid = PMC_AUDIOIOPLL, },
        },
 
        [PLL_ID_ETH] = {
                { .n = "ethpll_fracck",
                  .p = "main_xtal",
                  .l = &pll_layout_frac,
-                 .t = PLL_TYPE_FRAC, },
+                 .c = &pll_characteristics,
+                 .t = PLL_TYPE_FRAC,
+                 .f = CLK_SET_RATE_GATE, },
 
                { .n = "ethpll_divpmcck",
                  .p = "ethpll_fracck",
                  .l = &pll_layout_divpmc,
-                 .t = PLL_TYPE_DIV, },
+                 .c = &pll_characteristics,
+                 .t = PLL_TYPE_DIV,
+                 .f = CLK_SET_RATE_GATE | CLK_SET_PARENT_GATE |
+                      CLK_SET_RATE_PARENT, },
        },
 };
 
@@ -245,7 +326,7 @@ static const struct {
          .ep = { "syspll_divpmcck", "ddrpll_divpmcck", "imgpll_divpmcck", },
          .ep_mux_table = { 5, 6, 7, },
          .ep_count = 3,
-         .ep_chg_id = 6, },
+         .ep_chg_id = 5, },
 
        { .n = "mck4",
          .id = 4,
@@ -278,7 +359,7 @@ static const struct {
 };
 
 /* Mux table for programmable clocks. */
-static u32 sama7g5_prog_mux_table[] = { 0, 1, 2, 3, 5, 6, 7, 8, 9, 10, };
+static u32 sama7g5_prog_mux_table[] = { 0, 1, 2, 5, 6, 7, 8, 9, 10, };
 
 /**
  * Peripheral clock description
@@ -401,7 +482,7 @@ static const struct {
          .pp = { "audiopll_divpmcck", },
          .pp_mux_table = { 9, },
          .pp_count = 1,
-         .pp_chg_id = 4, },
+         .pp_chg_id = 3, },
 
        { .n  = "csi_gclk",
          .id = 33,
@@ -513,7 +594,7 @@ static const struct {
          .pp = { "ethpll_divpmcck", },
          .pp_mux_table = { 10, },
          .pp_count = 1,
-         .pp_chg_id = 4, },
+         .pp_chg_id = 3, },
 
        { .n  = "gmac1_gclk",
          .id = 52,
@@ -545,7 +626,7 @@ static const struct {
          .pp = { "syspll_divpmcck", "audiopll_divpmcck", },
          .pp_mux_table = { 5, 9, },
          .pp_count = 2,
-         .pp_chg_id = 5, },
+         .pp_chg_id = 4, },
 
        { .n  = "i2smcc1_gclk",
          .id = 58,
@@ -553,7 +634,7 @@ static const struct {
          .pp = { "syspll_divpmcck", "audiopll_divpmcck", },
          .pp_mux_table = { 5, 9, },
          .pp_count = 2,
-         .pp_chg_id = 5, },
+         .pp_chg_id = 4, },
 
        { .n  = "mcan0_gclk",
          .id = 61,
@@ -695,7 +776,7 @@ static const struct {
          .pp = { "syspll_divpmcck", "baudpll_divpmcck", },
          .pp_mux_table = { 5, 8, },
          .pp_count = 2,
-         .pp_chg_id = 5, },
+         .pp_chg_id = 4, },
 
        { .n  = "sdmmc1_gclk",
          .id = 81,
@@ -703,7 +784,7 @@ static const struct {
          .pp = { "syspll_divpmcck", "baudpll_divpmcck", },
          .pp_mux_table = { 5, 8, },
          .pp_count = 2,
-         .pp_chg_id = 5, },
+         .pp_chg_id = 4, },
 
        { .n  = "sdmmc2_gclk",
          .id = 82,
@@ -711,7 +792,7 @@ static const struct {
          .pp = { "syspll_divpmcck", "baudpll_divpmcck", },
          .pp_mux_table = { 5, 8, },
          .pp_count = 2,
-         .pp_chg_id = 5, },
+         .pp_chg_id = 4, },
 
        { .n  = "spdifrx_gclk",
          .id = 84,
@@ -719,7 +800,7 @@ static const struct {
          .pp = { "syspll_divpmcck", "audiopll_divpmcck", },
          .pp_mux_table = { 5, 9, },
          .pp_count = 2,
-         .pp_chg_id = 5, },
+         .pp_chg_id = 4, },
 
        { .n = "spdiftx_gclk",
          .id = 85,
@@ -727,7 +808,7 @@ static const struct {
          .pp = { "syspll_divpmcck", "audiopll_divpmcck", },
          .pp_mux_table = { 5, 9, },
          .pp_count = 2,
-         .pp_chg_id = 5, },
+         .pp_chg_id = 4, },
 
        { .n  = "tcb0_ch0_gclk",
          .id = 88,
@@ -758,28 +839,16 @@ static const struct {
          .pp_chg_id = INT_MIN, },
 };
 
-/* PLL output range. */
-static const struct clk_range pll_outputs[] = {
-       { .min = 2343750, .max = 1200000000 },
-};
-
-/* PLL characteristics. */
-static const struct clk_pll_characteristics pll_characteristics = {
-       .input = { .min = 12000000, .max = 50000000 },
-       .num_output = ARRAY_SIZE(pll_outputs),
-       .output = pll_outputs,
-};
-
 /* MCK0 characteristics. */
 static const struct clk_master_characteristics mck0_characteristics = {
-       .output = { .min = 140000000, .max = 200000000 },
-       .divisors = { 1, 2, 4, 3 },
+       .output = { .min = 50000000, .max = 200000000 },
+       .divisors = { 1, 2, 4, 3, 5 },
        .have_div3_pres = 1,
 };
 
 /* MCK0 layout. */
 static const struct clk_master_layout mck0_layout = {
-       .mask = 0x373,
+       .mask = 0x773,
        .pres_shift = 4,
        .offset = 0x28,
 };
@@ -835,10 +904,10 @@ static void __init sama7g5_pmc_setup(struct device_node *np)
        if (IS_ERR(regmap))
                return;
 
-       sama7g5_pmc = pmc_data_allocate(PMC_I2S1_MUX + 1,
+       sama7g5_pmc = pmc_data_allocate(PMC_CPU + 1,
                                        nck(sama7g5_systemck),
                                        nck(sama7g5_periphck),
-                                       nck(sama7g5_gck));
+                                       nck(sama7g5_gck), 8);
        if (!sama7g5_pmc)
                return;
 
@@ -886,18 +955,18 @@ static void __init sama7g5_pmc_setup(struct device_node *np)
                                hw = sam9x60_clk_register_frac_pll(regmap,
                                        &pmc_pll_lock, sama7g5_plls[i][j].n,
                                        sama7g5_plls[i][j].p, parent_hw, i,
-                                       &pll_characteristics,
+                                       sama7g5_plls[i][j].c,
                                        sama7g5_plls[i][j].l,
-                                       sama7g5_plls[i][j].c);
+                                       sama7g5_plls[i][j].f);
                                break;
 
                        case PLL_TYPE_DIV:
                                hw = sam9x60_clk_register_div_pll(regmap,
                                        &pmc_pll_lock, sama7g5_plls[i][j].n,
                                        sama7g5_plls[i][j].p, i,
-                                       &pll_characteristics,
+                                       sama7g5_plls[i][j].c,
                                        sama7g5_plls[i][j].l,
-                                       sama7g5_plls[i][j].c);
+                                       sama7g5_plls[i][j].f);
                                break;
 
                        default:
@@ -912,12 +981,19 @@ static void __init sama7g5_pmc_setup(struct device_node *np)
                }
        }
 
-       parent_names[0] = md_slck_name;
-       parent_names[1] = "mainck";
-       parent_names[2] = "cpupll_divpmcck";
-       parent_names[3] = "syspll_divpmcck";
-       hw = at91_clk_register_master(regmap, "mck0", 4, parent_names,
-                                     &mck0_layout, &mck0_characteristics);
+       parent_names[0] = "cpupll_divpmcck";
+       hw = at91_clk_register_master_pres(regmap, "cpuck", 1, parent_names,
+                                          &mck0_layout, &mck0_characteristics,
+                                          &pmc_mck0_lock,
+                                          CLK_SET_RATE_PARENT, 0);
+       if (IS_ERR(hw))
+               goto err_free;
+
+       sama7g5_pmc->chws[PMC_CPU] = hw;
+
+       hw = at91_clk_register_master_div(regmap, "mck0", "cpuck",
+                                         &mck0_layout, &mck0_characteristics,
+                                         &pmc_mck0_lock, 0);
        if (IS_ERR(hw))
                goto err_free;
 
@@ -926,9 +1002,8 @@ static void __init sama7g5_pmc_setup(struct device_node *np)
        parent_names[0] = md_slck_name;
        parent_names[1] = td_slck_name;
        parent_names[2] = "mainck";
-       parent_names[3] = "mck0";
        for (i = 0; i < ARRAY_SIZE(sama7g5_mckx); i++) {
-               u8 num_parents = 4 + sama7g5_mckx[i].ep_count;
+               u8 num_parents = 3 + sama7g5_mckx[i].ep_count;
                u32 *mux_table;
 
                mux_table = kmalloc_array(num_parents, sizeof(*mux_table),
@@ -936,10 +1011,10 @@ static void __init sama7g5_pmc_setup(struct device_node *np)
                if (!mux_table)
                        goto err_free;
 
-               SAMA7G5_INIT_TABLE(mux_table, 4);
-               SAMA7G5_FILL_TABLE(&mux_table[4], sama7g5_mckx[i].ep_mux_table,
+               SAMA7G5_INIT_TABLE(mux_table, 3);
+               SAMA7G5_FILL_TABLE(&mux_table[3], sama7g5_mckx[i].ep_mux_table,
                                   sama7g5_mckx[i].ep_count);
-               SAMA7G5_FILL_TABLE(&parent_names[4], sama7g5_mckx[i].ep,
+               SAMA7G5_FILL_TABLE(&parent_names[3], sama7g5_mckx[i].ep,
                                   sama7g5_mckx[i].ep_count);
 
                hw = at91_clk_sama7g5_register_master(regmap, sama7g5_mckx[i].n,
@@ -962,24 +1037,25 @@ static void __init sama7g5_pmc_setup(struct device_node *np)
        parent_names[0] = md_slck_name;
        parent_names[1] = td_slck_name;
        parent_names[2] = "mainck";
-       parent_names[3] = "mck0";
-       parent_names[4] = "syspll_divpmcck";
-       parent_names[5] = "ddrpll_divpmcck";
-       parent_names[6] = "imgpll_divpmcck";
-       parent_names[7] = "baudpll_divpmcck";
-       parent_names[8] = "audiopll_divpmcck";
-       parent_names[9] = "ethpll_divpmcck";
+       parent_names[3] = "syspll_divpmcck";
+       parent_names[4] = "ddrpll_divpmcck";
+       parent_names[5] = "imgpll_divpmcck";
+       parent_names[6] = "baudpll_divpmcck";
+       parent_names[7] = "audiopll_divpmcck";
+       parent_names[8] = "ethpll_divpmcck";
        for (i = 0; i < 8; i++) {
                char name[6];
 
                snprintf(name, sizeof(name), "prog%d", i);
 
                hw = at91_clk_register_programmable(regmap, name, parent_names,
-                                                   10, i,
+                                                   9, i,
                                                    &programmable_layout,
                                                    sama7g5_prog_mux_table);
                if (IS_ERR(hw))
                        goto err_free;
+
+               sama7g5_pmc->pchws[i] = hw;
        }
 
        for (i = 0; i < ARRAY_SIZE(sama7g5_systemck); i++) {
@@ -1010,9 +1086,8 @@ static void __init sama7g5_pmc_setup(struct device_node *np)
        parent_names[0] = md_slck_name;
        parent_names[1] = td_slck_name;
        parent_names[2] = "mainck";
-       parent_names[3] = "mck0";
        for (i = 0; i < ARRAY_SIZE(sama7g5_gck); i++) {
-               u8 num_parents = 4 + sama7g5_gck[i].pp_count;
+               u8 num_parents = 3 + sama7g5_gck[i].pp_count;
                u32 *mux_table;
 
                mux_table = kmalloc_array(num_parents, sizeof(*mux_table),
@@ -1020,10 +1095,10 @@ static void __init sama7g5_pmc_setup(struct device_node *np)
                if (!mux_table)
                        goto err_free;
 
-               SAMA7G5_INIT_TABLE(mux_table, 4);
-               SAMA7G5_FILL_TABLE(&mux_table[4], sama7g5_gck[i].pp_mux_table,
+               SAMA7G5_INIT_TABLE(mux_table, 3);
+               SAMA7G5_FILL_TABLE(&mux_table[3], sama7g5_gck[i].pp_mux_table,
                                   sama7g5_gck[i].pp_count);
-               SAMA7G5_FILL_TABLE(&parent_names[4], sama7g5_gck[i].pp,
+               SAMA7G5_FILL_TABLE(&parent_names[3], sama7g5_gck[i].pp,
                                   sama7g5_gck[i].pp_count);
 
                hw = at91_clk_register_generated(regmap, &pmc_pcr_lock,
@@ -1052,7 +1127,7 @@ err_free:
                kfree(alloc_mem);
        }
 
-       pmc_data_free(sama7g5_pmc);
+       kfree(sama7g5_pmc);
 }
 
 /* Some clks are used for a clocksource */
index 14d803e..ad86e03 100644 (file)
 #define MMCM_CLK_DIV_DIVIDE    BIT(11)
 #define MMCM_CLK_DIV_NOCOUNT   BIT(12)
 
+struct axi_clkgen_limits {
+       unsigned int fpfd_min;
+       unsigned int fpfd_max;
+       unsigned int fvco_min;
+       unsigned int fvco_max;
+};
+
 struct axi_clkgen {
        void __iomem *base;
        struct clk_hw clk_hw;
+       struct axi_clkgen_limits limits;
 };
 
 static uint32_t axi_clkgen_lookup_filter(unsigned int m)
@@ -100,12 +108,15 @@ static uint32_t axi_clkgen_lookup_lock(unsigned int m)
        return 0x1f1f00fa;
 }
 
-static const unsigned int fpfd_min = 10000;
-static const unsigned int fpfd_max = 300000;
-static const unsigned int fvco_min = 600000;
-static const unsigned int fvco_max = 1200000;
+static const struct axi_clkgen_limits axi_clkgen_zynq_default_limits = {
+       .fpfd_min = 10000,
+       .fpfd_max = 300000,
+       .fvco_min = 600000,
+       .fvco_max = 1200000,
+};
 
-static void axi_clkgen_calc_params(unsigned long fin, unsigned long fout,
+static void axi_clkgen_calc_params(const struct axi_clkgen_limits *limits,
+       unsigned long fin, unsigned long fout,
        unsigned int *best_d, unsigned int *best_m, unsigned int *best_dout)
 {
        unsigned long d, d_min, d_max, _d_min, _d_max;
@@ -122,12 +133,12 @@ static void axi_clkgen_calc_params(unsigned long fin, unsigned long fout,
        *best_m = 0;
        *best_dout = 0;
 
-       d_min = max_t(unsigned long, DIV_ROUND_UP(fin, fpfd_max), 1);
-       d_max = min_t(unsigned long, fin / fpfd_min, 80);
+       d_min = max_t(unsigned long, DIV_ROUND_UP(fin, limits->fpfd_max), 1);
+       d_max = min_t(unsigned long, fin / limits->fpfd_min, 80);
 
 again:
-       fvco_min_fract = fvco_min << fract_shift;
-       fvco_max_fract = fvco_max << fract_shift;
+       fvco_min_fract = limits->fvco_min << fract_shift;
+       fvco_max_fract = limits->fvco_max << fract_shift;
 
        m_min = max_t(unsigned long, DIV_ROUND_UP(fvco_min_fract, fin) * d_min, 1);
        m_max = min_t(unsigned long, fvco_max_fract * d_max / fin, 64 << fract_shift);
@@ -319,6 +330,7 @@ static int axi_clkgen_set_rate(struct clk_hw *clk_hw,
        unsigned long rate, unsigned long parent_rate)
 {
        struct axi_clkgen *axi_clkgen = clk_hw_to_axi_clkgen(clk_hw);
+       const struct axi_clkgen_limits *limits = &axi_clkgen->limits;
        unsigned int d, m, dout;
        struct axi_clkgen_div_params params;
        uint32_t power = 0;
@@ -328,7 +340,7 @@ static int axi_clkgen_set_rate(struct clk_hw *clk_hw,
        if (parent_rate == 0 || rate == 0)
                return -EINVAL;
 
-       axi_clkgen_calc_params(parent_rate, rate, &d, &m, &dout);
+       axi_clkgen_calc_params(limits, parent_rate, rate, &d, &m, &dout);
 
        if (d == 0 || dout == 0 || m == 0)
                return -EINVAL;
@@ -368,10 +380,12 @@ static int axi_clkgen_set_rate(struct clk_hw *clk_hw,
 static long axi_clkgen_round_rate(struct clk_hw *hw, unsigned long rate,
        unsigned long *parent_rate)
 {
+       struct axi_clkgen *axi_clkgen = clk_hw_to_axi_clkgen(hw);
+       const struct axi_clkgen_limits *limits = &axi_clkgen->limits;
        unsigned int d, m, dout;
        unsigned long long tmp;
 
-       axi_clkgen_calc_params(*parent_rate, rate, &d, &m, &dout);
+       axi_clkgen_calc_params(limits, *parent_rate, rate, &d, &m, &dout);
 
        if (d == 0 || dout == 0 || m == 0)
                return -EINVAL;
@@ -482,17 +496,9 @@ static const struct clk_ops axi_clkgen_ops = {
        .get_parent = axi_clkgen_get_parent,
 };
 
-static const struct of_device_id axi_clkgen_ids[] = {
-       {
-               .compatible = "adi,axi-clkgen-2.00.a",
-       },
-       { },
-};
-MODULE_DEVICE_TABLE(of, axi_clkgen_ids);
-
 static int axi_clkgen_probe(struct platform_device *pdev)
 {
-       const struct of_device_id *id;
+       const struct axi_clkgen_limits *dflt_limits;
        struct axi_clkgen *axi_clkgen;
        struct clk_init_data init;
        const char *parent_names[2];
@@ -501,11 +507,8 @@ static int axi_clkgen_probe(struct platform_device *pdev)
        unsigned int i;
        int ret;
 
-       if (!pdev->dev.of_node)
-               return -ENODEV;
-
-       id = of_match_node(axi_clkgen_ids, pdev->dev.of_node);
-       if (!id)
+       dflt_limits = device_get_match_data(&pdev->dev);
+       if (!dflt_limits)
                return -ENODEV;
 
        axi_clkgen = devm_kzalloc(&pdev->dev, sizeof(*axi_clkgen), GFP_KERNEL);
@@ -527,6 +530,8 @@ static int axi_clkgen_probe(struct platform_device *pdev)
                        return -EINVAL;
        }
 
+       memcpy(&axi_clkgen->limits, dflt_limits, sizeof(axi_clkgen->limits));
+
        clk_name = pdev->dev.of_node->name;
        of_property_read_string(pdev->dev.of_node, "clock-output-names",
                &clk_name);
@@ -554,6 +559,15 @@ static int axi_clkgen_remove(struct platform_device *pdev)
        return 0;
 }
 
+static const struct of_device_id axi_clkgen_ids[] = {
+       {
+               .compatible = "adi,axi-clkgen-2.00.a",
+               .data = &axi_clkgen_zynq_default_limits,
+       },
+       { }
+};
+MODULE_DEVICE_TABLE(of, axi_clkgen_ids);
+
 static struct platform_driver axi_clkgen_driver = {
        .driver = {
                .name = "adi-axi-clkgen",
index 2ddb54f..0506046 100644 (file)
@@ -4,6 +4,7 @@
  */
 
 #include <linux/clk-provider.h>
+#include <linux/device.h>
 #include <linux/err.h>
 #include <linux/slab.h>
 
@@ -405,3 +406,52 @@ void clk_hw_unregister_composite(struct clk_hw *hw)
        kfree(composite);
 }
 EXPORT_SYMBOL_GPL(clk_hw_unregister_composite);
+
+static void devm_clk_hw_release_composite(struct device *dev, void *res)
+{
+       clk_hw_unregister_composite(*(struct clk_hw **)res);
+}
+
+static struct clk_hw *__devm_clk_hw_register_composite(struct device *dev,
+                       const char *name, const char * const *parent_names,
+                       const struct clk_parent_data *pdata, int num_parents,
+                       struct clk_hw *mux_hw, const struct clk_ops *mux_ops,
+                       struct clk_hw *rate_hw, const struct clk_ops *rate_ops,
+                       struct clk_hw *gate_hw, const struct clk_ops *gate_ops,
+                       unsigned long flags)
+{
+       struct clk_hw **ptr, *hw;
+
+       ptr = devres_alloc(devm_clk_hw_release_composite, sizeof(*ptr),
+                          GFP_KERNEL);
+       if (!ptr)
+               return ERR_PTR(-ENOMEM);
+
+       hw = __clk_hw_register_composite(dev, name, parent_names, pdata,
+                                        num_parents, mux_hw, mux_ops, rate_hw,
+                                        rate_ops, gate_hw, gate_ops, flags);
+
+       if (!IS_ERR(hw)) {
+               *ptr = hw;
+               devres_add(dev, ptr);
+       } else {
+               devres_free(ptr);
+       }
+
+       return hw;
+}
+
+struct clk_hw *devm_clk_hw_register_composite_pdata(struct device *dev,
+                       const char *name,
+                       const struct clk_parent_data *parent_data,
+                       int num_parents,
+                       struct clk_hw *mux_hw, const struct clk_ops *mux_ops,
+                       struct clk_hw *rate_hw, const struct clk_ops *rate_ops,
+                       struct clk_hw *gate_hw, const struct clk_ops *gate_ops,
+                       unsigned long flags)
+{
+       return __devm_clk_hw_register_composite(dev, name, NULL, parent_data,
+                                               num_parents, mux_hw, mux_ops,
+                                               rate_hw, rate_ops, gate_hw,
+                                               gate_ops, flags);
+}
index 8de12cb..c499799 100644 (file)
@@ -8,6 +8,7 @@
  */
 
 #include <linux/clk-provider.h>
+#include <linux/device.h>
 #include <linux/module.h>
 #include <linux/slab.h>
 #include <linux/io.h>
@@ -578,3 +579,36 @@ void clk_hw_unregister_divider(struct clk_hw *hw)
        kfree(div);
 }
 EXPORT_SYMBOL_GPL(clk_hw_unregister_divider);
+
+static void devm_clk_hw_release_divider(struct device *dev, void *res)
+{
+       clk_hw_unregister_divider(*(struct clk_hw **)res);
+}
+
+struct clk_hw *__devm_clk_hw_register_divider(struct device *dev,
+               struct device_node *np, const char *name,
+               const char *parent_name, const struct clk_hw *parent_hw,
+               const struct clk_parent_data *parent_data, unsigned long flags,
+               void __iomem *reg, u8 shift, u8 width, u8 clk_divider_flags,
+               const struct clk_div_table *table, spinlock_t *lock)
+{
+       struct clk_hw **ptr, *hw;
+
+       ptr = devres_alloc(devm_clk_hw_release_divider, sizeof(*ptr), GFP_KERNEL);
+       if (!ptr)
+               return ERR_PTR(-ENOMEM);
+
+       hw = __clk_hw_register_divider(dev, np, name, parent_name, parent_hw,
+                                      parent_data, flags, reg, shift, width,
+                                      clk_divider_flags, table, lock);
+
+       if (!IS_ERR(hw)) {
+               *ptr = hw;
+               devres_add(dev, ptr);
+       } else {
+               devres_free(ptr);
+       }
+
+       return hw;
+}
+EXPORT_SYMBOL_GPL(__devm_clk_hw_register_divider);
diff --git a/drivers/clk/clk-fsl-flexspi.c b/drivers/clk/clk-fsl-flexspi.c
new file mode 100644 (file)
index 0000000..8432d68
--- /dev/null
@@ -0,0 +1,106 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Layerscape FlexSPI clock driver
+ *
+ * Copyright 2020 Michael Walle <michael@walle.cc>
+ */
+
+#include <linux/clk-provider.h>
+#include <linux/io.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+
+static const struct clk_div_table ls1028a_flexspi_divs[] = {
+       { .val = 0, .div = 1, },
+       { .val = 1, .div = 2, },
+       { .val = 2, .div = 3, },
+       { .val = 3, .div = 4, },
+       { .val = 4, .div = 5, },
+       { .val = 5, .div = 6, },
+       { .val = 6, .div = 7, },
+       { .val = 7, .div = 8, },
+       { .val = 11, .div = 12, },
+       { .val = 15, .div = 16, },
+       { .val = 16, .div = 20, },
+       { .val = 17, .div = 24, },
+       { .val = 18, .div = 28, },
+       { .val = 19, .div = 32, },
+       { .val = 20, .div = 80, },
+       {}
+};
+
+static const struct clk_div_table lx2160a_flexspi_divs[] = {
+       { .val = 1, .div = 2, },
+       { .val = 3, .div = 4, },
+       { .val = 5, .div = 6, },
+       { .val = 7, .div = 8, },
+       { .val = 11, .div = 12, },
+       { .val = 15, .div = 16, },
+       { .val = 16, .div = 20, },
+       { .val = 17, .div = 24, },
+       { .val = 18, .div = 28, },
+       { .val = 19, .div = 32, },
+       { .val = 20, .div = 80, },
+       {}
+};
+
+static int fsl_flexspi_clk_probe(struct platform_device *pdev)
+{
+       struct device *dev = &pdev->dev;
+       struct device_node *np = dev->of_node;
+       const char *clk_name = np->name;
+       const char *clk_parent;
+       struct resource *res;
+       void __iomem *reg;
+       struct clk_hw *hw;
+       const struct clk_div_table *divs;
+
+       divs = device_get_match_data(dev);
+       if (!divs)
+               return -ENOENT;
+
+       res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+       if (!res)
+               return -ENOENT;
+
+       /*
+        * Can't use devm_ioremap_resource() or devm_of_iomap() because the
+        * resource might already be taken by the parent device.
+        */
+       reg = devm_ioremap(dev, res->start, resource_size(res));
+       if (!reg)
+               return -ENOMEM;
+
+       clk_parent = of_clk_get_parent_name(np, 0);
+       if (!clk_parent)
+               return -EINVAL;
+
+       of_property_read_string(np, "clock-output-names", &clk_name);
+
+       hw = devm_clk_hw_register_divider_table(dev, clk_name, clk_parent, 0,
+                                               reg, 0, 5, 0, divs, NULL);
+       if (IS_ERR(hw))
+               return PTR_ERR(hw);
+
+       return devm_of_clk_add_hw_provider(dev, of_clk_hw_simple_get, hw);
+}
+
+static const struct of_device_id fsl_flexspi_clk_dt_ids[] = {
+       { .compatible = "fsl,ls1028a-flexspi-clk", .data = &ls1028a_flexspi_divs },
+       { .compatible = "fsl,lx2160a-flexspi-clk", .data = &lx2160a_flexspi_divs },
+       {}
+};
+MODULE_DEVICE_TABLE(of, fsl_flexspi_clk_dt_ids);
+
+static struct platform_driver fsl_flexspi_clk_driver = {
+       .driver = {
+               .name = "fsl-flexspi-clk",
+               .of_match_table = fsl_flexspi_clk_dt_ids,
+       },
+       .probe = fsl_flexspi_clk_probe,
+};
+module_platform_driver(fsl_flexspi_clk_driver);
+
+MODULE_DESCRIPTION("FlexSPI clock driver for Layerscape SoCs");
+MODULE_AUTHOR("Michael Walle <michael@walle.cc>");
+MODULE_LICENSE("GPL");
index 0221180..6238fce 100644 (file)
@@ -58,13 +58,13 @@ static int fsl_sai_clk_probe(struct platform_device *pdev)
        /* set clock direction, we are the BCLK master */
        writel(CR2_BCD, base + I2S_CR2);
 
-       hw = clk_hw_register_composite_pdata(dev, dev->of_node->name,
-                                            &pdata, 1, NULL, NULL,
-                                            &sai_clk->div.hw,
-                                            &clk_divider_ops,
-                                            &sai_clk->gate.hw,
-                                            &clk_gate_ops,
-                                            CLK_SET_RATE_GATE);
+       hw = devm_clk_hw_register_composite_pdata(dev, dev->of_node->name,
+                                                 &pdata, 1, NULL, NULL,
+                                                 &sai_clk->div.hw,
+                                                 &clk_divider_ops,
+                                                 &sai_clk->gate.hw,
+                                                 &clk_gate_ops,
+                                                 CLK_SET_RATE_GATE);
        if (IS_ERR(hw))
                return PTR_ERR(hw);
 
index 86f2e2d..da2c8ed 100644 (file)
@@ -147,7 +147,7 @@ static struct platform_driver clk_pwm_driver = {
        .remove = clk_pwm_remove,
        .driver = {
                .name = "pwm-clock",
-               .of_match_table = of_match_ptr(clk_pwm_dt_ids),
+               .of_match_table = clk_pwm_dt_ids,
        },
 };
 
index 46101c6..70aa521 100644 (file)
@@ -7,6 +7,7 @@
 
 #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
 
+#include <dt-bindings/clock/fsl,qoriq-clockgen.h>
 #include <linux/clk.h>
 #include <linux/clk-provider.h>
 #include <linux/clkdev.h>
@@ -1368,33 +1369,33 @@ static struct clk *clockgen_clk_get(struct of_phandle_args *clkspec, void *data)
        idx = clkspec->args[1];
 
        switch (type) {
-       case 0:
+       case QORIQ_CLK_SYSCLK:
                if (idx != 0)
                        goto bad_args;
                clk = cg->sysclk;
                break;
-       case 1:
+       case QORIQ_CLK_CMUX:
                if (idx >= ARRAY_SIZE(cg->cmux))
                        goto bad_args;
                clk = cg->cmux[idx];
                break;
-       case 2:
+       case QORIQ_CLK_HWACCEL:
                if (idx >= ARRAY_SIZE(cg->hwaccel))
                        goto bad_args;
                clk = cg->hwaccel[idx];
                break;
-       case 3:
+       case QORIQ_CLK_FMAN:
                if (idx >= ARRAY_SIZE(cg->fman))
                        goto bad_args;
                clk = cg->fman[idx];
                break;
-       case 4:
+       case QORIQ_CLK_PLATFORM_PLL:
                pll = &cg->pll[PLATFORM_PLL];
                if (idx >= ARRAY_SIZE(pll->div))
                        goto bad_args;
                clk = pll->div[idx].clk;
                break;
-       case 5:
+       case QORIQ_CLK_CORECLK:
                if (idx != 0)
                        goto bad_args;
                clk = cg->coreclk;
index 5a9b140..a39af76 100644 (file)
@@ -129,7 +129,7 @@ static const struct clk_ops scpi_dvfs_ops = {
        .set_rate = scpi_dvfs_set_rate,
 };
 
-static const struct of_device_id scpi_clk_match[] = {
+static const struct of_device_id scpi_clk_match[] __maybe_unused = {
        { .compatible = "arm,scpi-dvfs-clocks", .data = &scpi_dvfs_ops, },
        { .compatible = "arm,scpi-variable-clocks", .data = &scpi_clk_ops, },
        {}
index 1e1702e..57e4597 100644 (file)
@@ -902,6 +902,10 @@ static int _si5351_clkout_set_disable_state(
 static void _si5351_clkout_reset_pll(struct si5351_driver_data *drvdata, int num)
 {
        u8 val = si5351_reg_read(drvdata, SI5351_CLK0_CTRL + num);
+       u8 mask = val & SI5351_CLK_PLL_SELECT ? SI5351_PLL_RESET_B :
+                                                      SI5351_PLL_RESET_A;
+       unsigned int v;
+       int err;
 
        switch (val & SI5351_CLK_INPUT_MASK) {
        case SI5351_CLK_INPUT_XTAL:
@@ -909,9 +913,12 @@ static void _si5351_clkout_reset_pll(struct si5351_driver_data *drvdata, int num
                return;  /* pll not used, no need to reset */
        }
 
-       si5351_reg_write(drvdata, SI5351_PLL_RESET,
-                        val & SI5351_CLK_PLL_SELECT ? SI5351_PLL_RESET_B :
-                                                      SI5351_PLL_RESET_A);
+       si5351_reg_write(drvdata, SI5351_PLL_RESET, mask);
+
+       err = regmap_read_poll_timeout(drvdata->regmap, SI5351_PLL_RESET, v,
+                                !(v & mask), 0, 20000);
+       if (err < 0)
+               dev_err(&drvdata->client->dev, "Reset bit didn't clear\n");
 
        dev_dbg(&drvdata->client->dev, "%s - %s: pll = %d\n",
                __func__, clk_hw_get_name(&drvdata->clkout[num].hw),
index b98415d..8c1d04d 100644 (file)
@@ -420,7 +420,7 @@ static struct clk_core *clk_core_get(struct clk_core *core, u8 p_index)
 static void clk_core_fill_parent_index(struct clk_core *core, u8 index)
 {
        struct clk_parent_map *entry = &core->parents[index];
-       struct clk_core *parent = ERR_PTR(-ENOENT);
+       struct clk_core *parent;
 
        if (entry->hw) {
                parent = entry->hw->core;
@@ -2937,7 +2937,14 @@ static void clk_summary_show_one(struct seq_file *s, struct clk_core *c,
        else
                seq_puts(s, "-----");
 
-       seq_printf(s, " %6d\n", clk_core_get_scaled_duty_cycle(c, 100000));
+       seq_printf(s, " %6d", clk_core_get_scaled_duty_cycle(c, 100000));
+
+       if (c->ops->is_enabled)
+               seq_printf(s, " %9c\n", clk_core_is_enabled(c) ? 'Y' : 'N');
+       else if (!c->ops->enable)
+               seq_printf(s, " %9c\n", 'Y');
+       else
+               seq_printf(s, " %9c\n", '?');
 }
 
 static void clk_summary_show_subtree(struct seq_file *s, struct clk_core *c,
@@ -2956,9 +2963,9 @@ static int clk_summary_show(struct seq_file *s, void *data)
        struct clk_core *c;
        struct hlist_head **lists = (struct hlist_head **)s->private;
 
-       seq_puts(s, "                                 enable  prepare  protect                                duty\n");
-       seq_puts(s, "   clock                          count    count    count        rate   accuracy phase  cycle\n");
-       seq_puts(s, "---------------------------------------------------------------------------------------------\n");
+       seq_puts(s, "                                 enable  prepare  protect                                duty  hardware\n");
+       seq_puts(s, "   clock                          count    count    count        rate   accuracy phase  cycle    enable\n");
+       seq_puts(s, "-------------------------------------------------------------------------------------------------------\n");
 
        clk_prepare_lock();
 
@@ -3673,6 +3680,24 @@ struct clk *clk_hw_create_clk(struct device *dev, struct clk_hw *hw,
        return clk;
 }
 
+/**
+ * clk_hw_get_clk - get clk consumer given an clk_hw
+ * @hw: clk_hw associated with the clk being consumed
+ * @con_id: connection ID string on device
+ *
+ * Returns: new clk consumer
+ * This is the function to be used by providers which need
+ * to get a consumer clk and act on the clock element
+ * Calls to this function must be balanced with calls clk_put()
+ */
+struct clk *clk_hw_get_clk(struct clk_hw *hw, const char *con_id)
+{
+       struct device *dev = hw->core->dev;
+
+       return clk_hw_create_clk(dev, hw, dev_name(dev), con_id);
+}
+EXPORT_SYMBOL(clk_hw_get_clk);
+
 static int clk_cpy_name(const char **dst_p, const char *src, bool must_exist)
 {
        const char *dst;
@@ -4074,12 +4099,12 @@ void clk_hw_unregister(struct clk_hw *hw)
 }
 EXPORT_SYMBOL_GPL(clk_hw_unregister);
 
-static void devm_clk_release(struct device *dev, void *res)
+static void devm_clk_unregister_cb(struct device *dev, void *res)
 {
        clk_unregister(*(struct clk **)res);
 }
 
-static void devm_clk_hw_release(struct device *dev, void *res)
+static void devm_clk_hw_unregister_cb(struct device *dev, void *res)
 {
        clk_hw_unregister(*(struct clk_hw **)res);
 }
@@ -4099,7 +4124,7 @@ struct clk *devm_clk_register(struct device *dev, struct clk_hw *hw)
        struct clk *clk;
        struct clk **clkp;
 
-       clkp = devres_alloc(devm_clk_release, sizeof(*clkp), GFP_KERNEL);
+       clkp = devres_alloc(devm_clk_unregister_cb, sizeof(*clkp), GFP_KERNEL);
        if (!clkp)
                return ERR_PTR(-ENOMEM);
 
@@ -4129,7 +4154,7 @@ int devm_clk_hw_register(struct device *dev, struct clk_hw *hw)
        struct clk_hw **hwp;
        int ret;
 
-       hwp = devres_alloc(devm_clk_hw_release, sizeof(*hwp), GFP_KERNEL);
+       hwp = devres_alloc(devm_clk_hw_unregister_cb, sizeof(*hwp), GFP_KERNEL);
        if (!hwp)
                return -ENOMEM;
 
@@ -4173,7 +4198,7 @@ static int devm_clk_hw_match(struct device *dev, void *res, void *data)
  */
 void devm_clk_unregister(struct device *dev, struct clk *clk)
 {
-       WARN_ON(devres_release(dev, devm_clk_release, devm_clk_match, clk));
+       WARN_ON(devres_release(dev, devm_clk_unregister_cb, devm_clk_match, clk));
 }
 EXPORT_SYMBOL_GPL(devm_clk_unregister);
 
@@ -4188,11 +4213,54 @@ EXPORT_SYMBOL_GPL(devm_clk_unregister);
  */
 void devm_clk_hw_unregister(struct device *dev, struct clk_hw *hw)
 {
-       WARN_ON(devres_release(dev, devm_clk_hw_release, devm_clk_hw_match,
+       WARN_ON(devres_release(dev, devm_clk_hw_unregister_cb, devm_clk_hw_match,
                                hw));
 }
 EXPORT_SYMBOL_GPL(devm_clk_hw_unregister);
 
+static void devm_clk_release(struct device *dev, void *res)
+{
+       clk_put(*(struct clk **)res);
+}
+
+/**
+ * devm_clk_hw_get_clk - resource managed clk_hw_get_clk()
+ * @dev: device that is registering this clock
+ * @hw: clk_hw associated with the clk being consumed
+ * @con_id: connection ID string on device
+ *
+ * Managed clk_hw_get_clk(). Clocks got with this function are
+ * automatically clk_put() on driver detach. See clk_put()
+ * for more information.
+ */
+struct clk *devm_clk_hw_get_clk(struct device *dev, struct clk_hw *hw,
+                               const char *con_id)
+{
+       struct clk *clk;
+       struct clk **clkp;
+
+       /* This should not happen because it would mean we have drivers
+        * passing around clk_hw pointers instead of having the caller use
+        * proper clk_get() style APIs
+        */
+       WARN_ON_ONCE(dev != hw->core->dev);
+
+       clkp = devres_alloc(devm_clk_release, sizeof(*clkp), GFP_KERNEL);
+       if (!clkp)
+               return ERR_PTR(-ENOMEM);
+
+       clk = clk_hw_get_clk(hw, con_id);
+       if (!IS_ERR(clk)) {
+               *clkp = clk;
+               devres_add(dev, clkp);
+       } else {
+               devres_free(clkp);
+       }
+
+       return clk;
+}
+EXPORT_SYMBOL_GPL(devm_clk_hw_get_clk);
+
 /*
  * clkdev helpers
  */
@@ -4340,6 +4408,42 @@ int clk_notifier_unregister(struct clk *clk, struct notifier_block *nb)
 }
 EXPORT_SYMBOL_GPL(clk_notifier_unregister);
 
+struct clk_notifier_devres {
+       struct clk *clk;
+       struct notifier_block *nb;
+};
+
+static void devm_clk_notifier_release(struct device *dev, void *res)
+{
+       struct clk_notifier_devres *devres = res;
+
+       clk_notifier_unregister(devres->clk, devres->nb);
+}
+
+int devm_clk_notifier_register(struct device *dev, struct clk *clk,
+                              struct notifier_block *nb)
+{
+       struct clk_notifier_devres *devres;
+       int ret;
+
+       devres = devres_alloc(devm_clk_notifier_release,
+                             sizeof(*devres), GFP_KERNEL);
+
+       if (!devres)
+               return -ENOMEM;
+
+       ret = clk_notifier_register(clk, nb);
+       if (!ret) {
+               devres->clk = clk;
+               devres->nb = nb;
+       } else {
+               devres_free(devres);
+       }
+
+       return ret;
+}
+EXPORT_SYMBOL_GPL(devm_clk_notifier_register);
+
 #ifdef CONFIG_OF
 static void clk_core_reparent_orphans(void)
 {
index 7eed708..f16c401 100644 (file)
@@ -30,6 +30,7 @@ struct clk_gate2 {
        void __iomem    *reg;
        u8              bit_idx;
        u8              cgr_val;
+       u8              cgr_mask;
        u8              flags;
        spinlock_t      *lock;
        unsigned int    *share_count;
@@ -37,37 +38,38 @@ struct clk_gate2 {
 
 #define to_clk_gate2(_hw) container_of(_hw, struct clk_gate2, hw)
 
-static int clk_gate2_enable(struct clk_hw *hw)
+static void clk_gate2_do_shared_clks(struct clk_hw *hw, bool enable)
 {
        struct clk_gate2 *gate = to_clk_gate2(hw);
        u32 reg;
+
+       reg = readl(gate->reg);
+       reg &= ~(gate->cgr_mask << gate->bit_idx);
+       if (enable)
+               reg |= (gate->cgr_val & gate->cgr_mask) << gate->bit_idx;
+       writel(reg, gate->reg);
+}
+
+static int clk_gate2_enable(struct clk_hw *hw)
+{
+       struct clk_gate2 *gate = to_clk_gate2(hw);
        unsigned long flags;
-       int ret = 0;
 
        spin_lock_irqsave(gate->lock, flags);
 
        if (gate->share_count && (*gate->share_count)++ > 0)
                goto out;
 
-       if (gate->flags & IMX_CLK_GATE2_SINGLE_BIT) {
-               ret = clk_gate_ops.enable(hw);
-       } else {
-               reg = readl(gate->reg);
-               reg &= ~(3 << gate->bit_idx);
-               reg |= gate->cgr_val << gate->bit_idx;
-               writel(reg, gate->reg);
-       }
-
+       clk_gate2_do_shared_clks(hw, true);
 out:
        spin_unlock_irqrestore(gate->lock, flags);
 
-       return ret;
+       return 0;
 }
 
 static void clk_gate2_disable(struct clk_hw *hw)
 {
        struct clk_gate2 *gate = to_clk_gate2(hw);
-       u32 reg;
        unsigned long flags;
 
        spin_lock_irqsave(gate->lock, flags);
@@ -79,23 +81,17 @@ static void clk_gate2_disable(struct clk_hw *hw)
                        goto out;
        }
 
-       if (gate->flags & IMX_CLK_GATE2_SINGLE_BIT) {
-               clk_gate_ops.disable(hw);
-       } else {
-               reg = readl(gate->reg);
-               reg &= ~(3 << gate->bit_idx);
-               writel(reg, gate->reg);
-       }
-
+       clk_gate2_do_shared_clks(hw, false);
 out:
        spin_unlock_irqrestore(gate->lock, flags);
 }
 
-static int clk_gate2_reg_is_enabled(void __iomem *reg, u8 bit_idx)
+static int clk_gate2_reg_is_enabled(void __iomem *reg, u8 bit_idx,
+                                       u8 cgr_val, u8 cgr_mask)
 {
        u32 val = readl(reg);
 
-       if (((val >> bit_idx) & 1) == 1)
+       if (((val >> bit_idx) & cgr_mask) == cgr_val)
                return 1;
 
        return 0;
@@ -104,29 +100,28 @@ static int clk_gate2_reg_is_enabled(void __iomem *reg, u8 bit_idx)
 static int clk_gate2_is_enabled(struct clk_hw *hw)
 {
        struct clk_gate2 *gate = to_clk_gate2(hw);
+       unsigned long flags;
+       int ret = 0;
+
+       spin_lock_irqsave(gate->lock, flags);
 
-       if (gate->flags & IMX_CLK_GATE2_SINGLE_BIT)
-               return clk_gate_ops.is_enabled(hw);
+       ret = clk_gate2_reg_is_enabled(gate->reg, gate->bit_idx,
+                                       gate->cgr_val, gate->cgr_mask);
 
-       return clk_gate2_reg_is_enabled(gate->reg, gate->bit_idx);
+       spin_unlock_irqrestore(gate->lock, flags);
+
+       return ret;
 }
 
 static void clk_gate2_disable_unused(struct clk_hw *hw)
 {
        struct clk_gate2 *gate = to_clk_gate2(hw);
        unsigned long flags;
-       u32 reg;
-
-       if (gate->flags & IMX_CLK_GATE2_SINGLE_BIT)
-               return;
 
        spin_lock_irqsave(gate->lock, flags);
 
-       if (!gate->share_count || *gate->share_count == 0) {
-               reg = readl(gate->reg);
-               reg &= ~(3 << gate->bit_idx);
-               writel(reg, gate->reg);
-       }
+       if (!gate->share_count || *gate->share_count == 0)
+               clk_gate2_do_shared_clks(hw, false);
 
        spin_unlock_irqrestore(gate->lock, flags);
 }
@@ -140,7 +135,7 @@ static const struct clk_ops clk_gate2_ops = {
 
 struct clk_hw *clk_hw_register_gate2(struct device *dev, const char *name,
                const char *parent_name, unsigned long flags,
-               void __iomem *reg, u8 bit_idx, u8 cgr_val,
+               void __iomem *reg, u8 bit_idx, u8 cgr_val, u8 cgr_mask,
                u8 clk_gate2_flags, spinlock_t *lock,
                unsigned int *share_count)
 {
@@ -157,6 +152,7 @@ struct clk_hw *clk_hw_register_gate2(struct device *dev, const char *name,
        gate->reg = reg;
        gate->bit_idx = bit_idx;
        gate->cgr_val = cgr_val;
+       gate->cgr_mask = cgr_mask;
        gate->flags = clk_gate2_flags;
        gate->lock = lock;
        gate->share_count = share_count;
index 0de0be0..e27890b 100644 (file)
@@ -653,7 +653,7 @@ static struct platform_driver imx8mm_clk_driver = {
                 * reloading the driver will crash or break devices.
                 */
                .suppress_bind_attrs = true,
-               .of_match_table = of_match_ptr(imx8mm_clk_of_match),
+               .of_match_table = imx8mm_clk_of_match,
        },
 };
 module_platform_driver(imx8mm_clk_driver);
index e984de5..18f8141 100644 (file)
@@ -604,7 +604,7 @@ static struct platform_driver imx8mn_clk_driver = {
                 * reloading the driver will crash or break devices.
                 */
                .suppress_bind_attrs = true,
-               .of_match_table = of_match_ptr(imx8mn_clk_of_match),
+               .of_match_table = imx8mn_clk_of_match,
        },
 };
 module_platform_driver(imx8mn_clk_driver);
index 12ce477..165bfe2 100644 (file)
@@ -425,7 +425,7 @@ static struct clk **uart_clks[ARRAY_SIZE(uart_clk_ids) + 1];
 static int imx8mp_clocks_probe(struct platform_device *pdev)
 {
        struct device *dev = &pdev->dev;
-       struct device_node *np = dev->of_node;
+       struct device_node *np;
        void __iomem *anatop_base, *ccm_base;
        int i;
 
@@ -763,7 +763,7 @@ static struct platform_driver imx8mp_clk_driver = {
                 * reloading the driver will crash or break devices.
                 */
                .suppress_bind_attrs = true,
-               .of_match_table = of_match_ptr(imx8mp_clk_of_match),
+               .of_match_table = imx8mp_clk_of_match,
        },
 };
 module_platform_driver(imx8mp_clk_driver);
index 8265d1d..7518688 100644 (file)
@@ -639,7 +639,7 @@ static struct platform_driver imx8mq_clk_driver = {
                 * reloading the driver will crash or break devices.
                 */
                .suppress_bind_attrs = true,
-               .of_match_table = of_match_ptr(imx8mq_clk_of_match),
+               .of_match_table = imx8mq_clk_of_match,
        },
 };
 module_platform_driver(imx8mq_clk_driver);
index e947a70..d3e905c 100644 (file)
@@ -9,8 +9,10 @@
 #include <linux/io.h>
 #include <linux/module.h>
 #include <linux/of.h>
+#include <linux/of_address.h>
 #include <linux/of_device.h>
 #include <linux/platform_device.h>
+#include <linux/pm_runtime.h>
 #include <linux/slab.h>
 
 #include "clk-scu.h"
@@ -157,6 +159,135 @@ static const struct imx8qxp_ss_lpcg imx8qxp_ss_lsio = {
        .num_max = IMX_LSIO_LPCG_CLK_END,
 };
 
+#define IMX_LPCG_MAX_CLKS      8
+
+static struct clk_hw *imx_lpcg_of_clk_src_get(struct of_phandle_args *clkspec,
+                                             void *data)
+{
+       struct clk_hw_onecell_data *hw_data = data;
+       unsigned int idx = clkspec->args[0] / 4;
+
+       if (idx >= hw_data->num) {
+               pr_err("%s: invalid index %u\n", __func__, idx);
+               return ERR_PTR(-EINVAL);
+       }
+
+       return hw_data->hws[idx];
+}
+
+static int imx_lpcg_parse_clks_from_dt(struct platform_device *pdev,
+                                      struct device_node *np)
+{
+       const char *output_names[IMX_LPCG_MAX_CLKS];
+       const char *parent_names[IMX_LPCG_MAX_CLKS];
+       unsigned int bit_offset[IMX_LPCG_MAX_CLKS];
+       struct clk_hw_onecell_data *clk_data;
+       struct clk_hw **clk_hws;
+       struct resource *res;
+       void __iomem *base;
+       int count;
+       int idx;
+       int ret;
+       int i;
+
+       if (!of_device_is_compatible(np, "fsl,imx8qxp-lpcg"))
+               return -EINVAL;
+
+       res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+       base = devm_ioremap_resource(&pdev->dev, res);
+       if (IS_ERR(base))
+               return PTR_ERR(base);
+
+       count = of_property_count_u32_elems(np, "clock-indices");
+       if (count < 0) {
+               dev_err(&pdev->dev, "failed to count clocks\n");
+               return -EINVAL;
+       }
+
+       /*
+        * A trick here is that we set the num of clks to the MAX instead
+        * of the count from clock-indices because one LPCG supports up to
+        * 8 clock outputs which each of them is fixed to 4 bits. Then we can
+        * easily get the clock by clk-indices (bit-offset) / 4.
+        * And the cost is very limited few pointers.
+        */
+
+       clk_data = devm_kzalloc(&pdev->dev, struct_size(clk_data, hws,
+                               IMX_LPCG_MAX_CLKS), GFP_KERNEL);
+       if (!clk_data)
+               return -ENOMEM;
+
+       clk_data->num = IMX_LPCG_MAX_CLKS;
+       clk_hws = clk_data->hws;
+
+       ret = of_property_read_u32_array(np, "clock-indices", bit_offset,
+                                        count);
+       if (ret < 0) {
+               dev_err(&pdev->dev, "failed to read clock-indices\n");
+               return -EINVAL;
+       }
+
+       ret = of_clk_parent_fill(np, parent_names, count);
+       if (ret != count) {
+               dev_err(&pdev->dev, "failed to get clock parent names\n");
+               return count;
+       }
+
+       ret = of_property_read_string_array(np, "clock-output-names",
+                                           output_names, count);
+       if (ret != count) {
+               dev_err(&pdev->dev, "failed to read clock-output-names\n");
+               return -EINVAL;
+       }
+
+       pm_runtime_get_noresume(&pdev->dev);
+       pm_runtime_set_active(&pdev->dev);
+       pm_runtime_set_autosuspend_delay(&pdev->dev, 500);
+       pm_runtime_use_autosuspend(&pdev->dev);
+       pm_runtime_enable(&pdev->dev);
+
+       for (i = 0; i < count; i++) {
+               idx = bit_offset[i] / 4;
+               if (idx > IMX_LPCG_MAX_CLKS) {
+                       dev_warn(&pdev->dev, "invalid bit offset of clock %d\n",
+                                i);
+                       ret = -EINVAL;
+                       goto unreg;
+               }
+
+               clk_hws[idx] = imx_clk_lpcg_scu_dev(&pdev->dev, output_names[i],
+                                                   parent_names[i], 0, base,
+                                                   bit_offset[i], false);
+               if (IS_ERR(clk_hws[idx])) {
+                       dev_warn(&pdev->dev, "failed to register clock %d\n",
+                                idx);
+                       ret = PTR_ERR(clk_hws[idx]);
+                       goto unreg;
+               }
+       }
+
+       ret = devm_of_clk_add_hw_provider(&pdev->dev, imx_lpcg_of_clk_src_get,
+                                         clk_data);
+       if (ret)
+               goto unreg;
+
+       pm_runtime_mark_last_busy(&pdev->dev);
+       pm_runtime_put_autosuspend(&pdev->dev);
+
+       return 0;
+
+unreg:
+       while (--i >= 0) {
+               idx = bit_offset[i] / 4;
+               if (clk_hws[idx])
+                       imx_clk_lpcg_scu_unregister(clk_hws[idx]);
+       }
+
+       pm_runtime_disable(&pdev->dev);
+
+       return ret;
+}
+
 static int imx8qxp_lpcg_clk_probe(struct platform_device *pdev)
 {
        struct device *dev = &pdev->dev;
@@ -167,8 +298,14 @@ static int imx8qxp_lpcg_clk_probe(struct platform_device *pdev)
        struct resource *res;
        struct clk_hw **clks;
        void __iomem *base;
+       int ret;
        int i;
 
+       /* try new binding to parse clocks from device tree first */
+       ret = imx_lpcg_parse_clks_from_dt(pdev, np);
+       if (!ret)
+               return 0;
+
        ss_lpcg = of_device_get_match_data(dev);
        if (!ss_lpcg)
                return -ENODEV;
@@ -219,6 +356,7 @@ static const struct of_device_id imx8qxp_lpcg_match[] = {
        { .compatible = "fsl,imx8qxp-lpcg-adma", &imx8qxp_ss_adma, },
        { .compatible = "fsl,imx8qxp-lpcg-conn", &imx8qxp_ss_conn, },
        { .compatible = "fsl,imx8qxp-lpcg-lsio", &imx8qxp_ss_lsio, },
+       { .compatible = "fsl,imx8qxp-lpcg", NULL },
        { /* sentinel */ }
 };
 
@@ -226,6 +364,7 @@ static struct platform_driver imx8qxp_lpcg_clk_driver = {
        .driver = {
                .name = "imx8qxp-lpcg-clk",
                .of_match_table = imx8qxp_lpcg_match,
+               .pm = &imx_clk_lpcg_scu_pm_ops,
                .suppress_bind_attrs = true,
        },
        .probe = imx8qxp_lpcg_clk_probe,
index d650ca3..5b3d4ed 100644 (file)
@@ -22,9 +22,10 @@ static int imx8qxp_clk_probe(struct platform_device *pdev)
        struct device_node *ccm_node = pdev->dev.of_node;
        struct clk_hw_onecell_data *clk_data;
        struct clk_hw **clks;
+       u32 clk_cells;
        int ret, i;
 
-       ret = imx_clk_scu_init();
+       ret = imx_clk_scu_init(ccm_node);
        if (ret)
                return ret;
 
@@ -33,6 +34,9 @@ static int imx8qxp_clk_probe(struct platform_device *pdev)
        if (!clk_data)
                return -ENOMEM;
 
+       if (of_property_read_u32(ccm_node, "#clock-cells", &clk_cells))
+               return -EINVAL;
+
        clk_data->num = IMX_SCU_CLK_END;
        clks = clk_data->hws;
 
@@ -55,78 +59,78 @@ static int imx8qxp_clk_probe(struct platform_device *pdev)
        clks[IMX_LSIO_BUS_CLK]          = clk_hw_register_fixed_rate(NULL, "lsio_bus_clk_root", NULL, 0, 100000000);
 
        /* ARM core */
-       clks[IMX_A35_CLK]               = imx_clk_scu("a35_clk", IMX_SC_R_A35, IMX_SC_PM_CLK_CPU);
+       clks[IMX_A35_CLK]               = imx_clk_scu("a35_clk", IMX_SC_R_A35, IMX_SC_PM_CLK_CPU, clk_cells);
 
        /* LSIO SS */
-       clks[IMX_LSIO_PWM0_CLK]         = imx_clk_scu("pwm0_clk", IMX_SC_R_PWM_0, IMX_SC_PM_CLK_PER);
-       clks[IMX_LSIO_PWM1_CLK]         = imx_clk_scu("pwm1_clk", IMX_SC_R_PWM_1, IMX_SC_PM_CLK_PER);
-       clks[IMX_LSIO_PWM2_CLK]         = imx_clk_scu("pwm2_clk", IMX_SC_R_PWM_2, IMX_SC_PM_CLK_PER);
-       clks[IMX_LSIO_PWM3_CLK]         = imx_clk_scu("pwm3_clk", IMX_SC_R_PWM_3, IMX_SC_PM_CLK_PER);
-       clks[IMX_LSIO_PWM4_CLK]         = imx_clk_scu("pwm4_clk", IMX_SC_R_PWM_4, IMX_SC_PM_CLK_PER);
-       clks[IMX_LSIO_PWM5_CLK]         = imx_clk_scu("pwm5_clk", IMX_SC_R_PWM_5, IMX_SC_PM_CLK_PER);
-       clks[IMX_LSIO_PWM6_CLK]         = imx_clk_scu("pwm6_clk", IMX_SC_R_PWM_6, IMX_SC_PM_CLK_PER);
-       clks[IMX_LSIO_PWM7_CLK]         = imx_clk_scu("pwm7_clk", IMX_SC_R_PWM_7, IMX_SC_PM_CLK_PER);
-       clks[IMX_LSIO_GPT0_CLK]         = imx_clk_scu("gpt0_clk", IMX_SC_R_GPT_0, IMX_SC_PM_CLK_PER);
-       clks[IMX_LSIO_GPT1_CLK]         = imx_clk_scu("gpt1_clk", IMX_SC_R_GPT_1, IMX_SC_PM_CLK_PER);
-       clks[IMX_LSIO_GPT2_CLK]         = imx_clk_scu("gpt2_clk", IMX_SC_R_GPT_2, IMX_SC_PM_CLK_PER);
-       clks[IMX_LSIO_GPT3_CLK]         = imx_clk_scu("gpt3_clk", IMX_SC_R_GPT_3, IMX_SC_PM_CLK_PER);
-       clks[IMX_LSIO_GPT4_CLK]         = imx_clk_scu("gpt4_clk", IMX_SC_R_GPT_4, IMX_SC_PM_CLK_PER);
-       clks[IMX_LSIO_FSPI0_CLK]        = imx_clk_scu("fspi0_clk", IMX_SC_R_FSPI_0, IMX_SC_PM_CLK_PER);
-       clks[IMX_LSIO_FSPI1_CLK]        = imx_clk_scu("fspi1_clk", IMX_SC_R_FSPI_1, IMX_SC_PM_CLK_PER);
+       clks[IMX_LSIO_PWM0_CLK]         = imx_clk_scu("pwm0_clk", IMX_SC_R_PWM_0, IMX_SC_PM_CLK_PER, clk_cells);
+       clks[IMX_LSIO_PWM1_CLK]         = imx_clk_scu("pwm1_clk", IMX_SC_R_PWM_1, IMX_SC_PM_CLK_PER, clk_cells);
+       clks[IMX_LSIO_PWM2_CLK]         = imx_clk_scu("pwm2_clk", IMX_SC_R_PWM_2, IMX_SC_PM_CLK_PER, clk_cells);
+       clks[IMX_LSIO_PWM3_CLK]         = imx_clk_scu("pwm3_clk", IMX_SC_R_PWM_3, IMX_SC_PM_CLK_PER, clk_cells);
+       clks[IMX_LSIO_PWM4_CLK]         = imx_clk_scu("pwm4_clk", IMX_SC_R_PWM_4, IMX_SC_PM_CLK_PER, clk_cells);
+       clks[IMX_LSIO_PWM5_CLK]         = imx_clk_scu("pwm5_clk", IMX_SC_R_PWM_5, IMX_SC_PM_CLK_PER, clk_cells);
+       clks[IMX_LSIO_PWM6_CLK]         = imx_clk_scu("pwm6_clk", IMX_SC_R_PWM_6, IMX_SC_PM_CLK_PER, clk_cells);
+       clks[IMX_LSIO_PWM7_CLK]         = imx_clk_scu("pwm7_clk", IMX_SC_R_PWM_7, IMX_SC_PM_CLK_PER, clk_cells);
+       clks[IMX_LSIO_GPT0_CLK]         = imx_clk_scu("gpt0_clk", IMX_SC_R_GPT_0, IMX_SC_PM_CLK_PER, clk_cells);
+       clks[IMX_LSIO_GPT1_CLK]         = imx_clk_scu("gpt1_clk", IMX_SC_R_GPT_1, IMX_SC_PM_CLK_PER, clk_cells);
+       clks[IMX_LSIO_GPT2_CLK]         = imx_clk_scu("gpt2_clk", IMX_SC_R_GPT_2, IMX_SC_PM_CLK_PER, clk_cells);
+       clks[IMX_LSIO_GPT3_CLK]         = imx_clk_scu("gpt3_clk", IMX_SC_R_GPT_3, IMX_SC_PM_CLK_PER, clk_cells);
+       clks[IMX_LSIO_GPT4_CLK]         = imx_clk_scu("gpt4_clk", IMX_SC_R_GPT_4, IMX_SC_PM_CLK_PER, clk_cells);
+       clks[IMX_LSIO_FSPI0_CLK]        = imx_clk_scu("fspi0_clk", IMX_SC_R_FSPI_0, IMX_SC_PM_CLK_PER, clk_cells);
+       clks[IMX_LSIO_FSPI1_CLK]        = imx_clk_scu("fspi1_clk", IMX_SC_R_FSPI_1, IMX_SC_PM_CLK_PER, clk_cells);
 
        /* ADMA SS */
-       clks[IMX_ADMA_UART0_CLK]        = imx_clk_scu("uart0_clk", IMX_SC_R_UART_0, IMX_SC_PM_CLK_PER);
-       clks[IMX_ADMA_UART1_CLK]        = imx_clk_scu("uart1_clk", IMX_SC_R_UART_1, IMX_SC_PM_CLK_PER);
-       clks[IMX_ADMA_UART2_CLK]        = imx_clk_scu("uart2_clk", IMX_SC_R_UART_2, IMX_SC_PM_CLK_PER);
-       clks[IMX_ADMA_UART3_CLK]        = imx_clk_scu("uart3_clk", IMX_SC_R_UART_3, IMX_SC_PM_CLK_PER);
-       clks[IMX_ADMA_SPI0_CLK]         = imx_clk_scu("spi0_clk",  IMX_SC_R_SPI_0, IMX_SC_PM_CLK_PER);
-       clks[IMX_ADMA_SPI1_CLK]         = imx_clk_scu("spi1_clk",  IMX_SC_R_SPI_1, IMX_SC_PM_CLK_PER);
-       clks[IMX_ADMA_SPI2_CLK]         = imx_clk_scu("spi2_clk",  IMX_SC_R_SPI_2, IMX_SC_PM_CLK_PER);
-       clks[IMX_ADMA_SPI3_CLK]         = imx_clk_scu("spi3_clk",  IMX_SC_R_SPI_3, IMX_SC_PM_CLK_PER);
-       clks[IMX_ADMA_CAN0_CLK]         = imx_clk_scu("can0_clk",  IMX_SC_R_CAN_0, IMX_SC_PM_CLK_PER);
-       clks[IMX_ADMA_I2C0_CLK]         = imx_clk_scu("i2c0_clk",  IMX_SC_R_I2C_0, IMX_SC_PM_CLK_PER);
-       clks[IMX_ADMA_I2C1_CLK]         = imx_clk_scu("i2c1_clk",  IMX_SC_R_I2C_1, IMX_SC_PM_CLK_PER);
-       clks[IMX_ADMA_I2C2_CLK]         = imx_clk_scu("i2c2_clk",  IMX_SC_R_I2C_2, IMX_SC_PM_CLK_PER);
-       clks[IMX_ADMA_I2C3_CLK]         = imx_clk_scu("i2c3_clk",  IMX_SC_R_I2C_3, IMX_SC_PM_CLK_PER);
-       clks[IMX_ADMA_FTM0_CLK]         = imx_clk_scu("ftm0_clk",  IMX_SC_R_FTM_0, IMX_SC_PM_CLK_PER);
-       clks[IMX_ADMA_FTM1_CLK]         = imx_clk_scu("ftm1_clk",  IMX_SC_R_FTM_1, IMX_SC_PM_CLK_PER);
-       clks[IMX_ADMA_ADC0_CLK]         = imx_clk_scu("adc0_clk",  IMX_SC_R_ADC_0, IMX_SC_PM_CLK_PER);
-       clks[IMX_ADMA_PWM_CLK]          = imx_clk_scu("pwm_clk",   IMX_SC_R_LCD_0_PWM_0, IMX_SC_PM_CLK_PER);
-       clks[IMX_ADMA_LCD_CLK]          = imx_clk_scu("lcd_clk",   IMX_SC_R_LCD_0, IMX_SC_PM_CLK_PER);
+       clks[IMX_ADMA_UART0_CLK]        = imx_clk_scu("uart0_clk", IMX_SC_R_UART_0, IMX_SC_PM_CLK_PER, clk_cells);
+       clks[IMX_ADMA_UART1_CLK]        = imx_clk_scu("uart1_clk", IMX_SC_R_UART_1, IMX_SC_PM_CLK_PER, clk_cells);
+       clks[IMX_ADMA_UART2_CLK]        = imx_clk_scu("uart2_clk", IMX_SC_R_UART_2, IMX_SC_PM_CLK_PER, clk_cells);
+       clks[IMX_ADMA_UART3_CLK]        = imx_clk_scu("uart3_clk", IMX_SC_R_UART_3, IMX_SC_PM_CLK_PER, clk_cells);
+       clks[IMX_ADMA_SPI0_CLK]         = imx_clk_scu("spi0_clk",  IMX_SC_R_SPI_0, IMX_SC_PM_CLK_PER, clk_cells);
+       clks[IMX_ADMA_SPI1_CLK]         = imx_clk_scu("spi1_clk",  IMX_SC_R_SPI_1, IMX_SC_PM_CLK_PER, clk_cells);
+       clks[IMX_ADMA_SPI2_CLK]         = imx_clk_scu("spi2_clk",  IMX_SC_R_SPI_2, IMX_SC_PM_CLK_PER, clk_cells);
+       clks[IMX_ADMA_SPI3_CLK]         = imx_clk_scu("spi3_clk",  IMX_SC_R_SPI_3, IMX_SC_PM_CLK_PER, clk_cells);
+       clks[IMX_ADMA_CAN0_CLK]         = imx_clk_scu("can0_clk",  IMX_SC_R_CAN_0, IMX_SC_PM_CLK_PER, clk_cells);
+       clks[IMX_ADMA_I2C0_CLK]         = imx_clk_scu("i2c0_clk",  IMX_SC_R_I2C_0, IMX_SC_PM_CLK_PER, clk_cells);
+       clks[IMX_ADMA_I2C1_CLK]         = imx_clk_scu("i2c1_clk",  IMX_SC_R_I2C_1, IMX_SC_PM_CLK_PER, clk_cells);
+       clks[IMX_ADMA_I2C2_CLK]         = imx_clk_scu("i2c2_clk",  IMX_SC_R_I2C_2, IMX_SC_PM_CLK_PER, clk_cells);
+       clks[IMX_ADMA_I2C3_CLK]         = imx_clk_scu("i2c3_clk",  IMX_SC_R_I2C_3, IMX_SC_PM_CLK_PER, clk_cells);
+       clks[IMX_ADMA_FTM0_CLK]         = imx_clk_scu("ftm0_clk",  IMX_SC_R_FTM_0, IMX_SC_PM_CLK_PER, clk_cells);
+       clks[IMX_ADMA_FTM1_CLK]         = imx_clk_scu("ftm1_clk",  IMX_SC_R_FTM_1, IMX_SC_PM_CLK_PER, clk_cells);
+       clks[IMX_ADMA_ADC0_CLK]         = imx_clk_scu("adc0_clk",  IMX_SC_R_ADC_0, IMX_SC_PM_CLK_PER, clk_cells);
+       clks[IMX_ADMA_PWM_CLK]          = imx_clk_scu("pwm_clk",   IMX_SC_R_LCD_0_PWM_0, IMX_SC_PM_CLK_PER, clk_cells);
+       clks[IMX_ADMA_LCD_CLK]          = imx_clk_scu("lcd_clk",   IMX_SC_R_LCD_0, IMX_SC_PM_CLK_PER, clk_cells);
 
        /* Connectivity */
-       clks[IMX_CONN_SDHC0_CLK]        = imx_clk_scu("sdhc0_clk", IMX_SC_R_SDHC_0, IMX_SC_PM_CLK_PER);
-       clks[IMX_CONN_SDHC1_CLK]        = imx_clk_scu("sdhc1_clk", IMX_SC_R_SDHC_1, IMX_SC_PM_CLK_PER);
-       clks[IMX_CONN_SDHC2_CLK]        = imx_clk_scu("sdhc2_clk", IMX_SC_R_SDHC_2, IMX_SC_PM_CLK_PER);
-       clks[IMX_CONN_ENET0_ROOT_CLK]   = imx_clk_scu("enet0_clk", IMX_SC_R_ENET_0, IMX_SC_PM_CLK_PER);
-       clks[IMX_CONN_ENET0_BYPASS_CLK] = imx_clk_scu("enet0_bypass_clk", IMX_SC_R_ENET_0, IMX_SC_PM_CLK_BYPASS);
-       clks[IMX_CONN_ENET0_RGMII_CLK]  = imx_clk_scu("enet0_rgmii_clk", IMX_SC_R_ENET_0, IMX_SC_PM_CLK_MISC0);
-       clks[IMX_CONN_ENET1_ROOT_CLK]   = imx_clk_scu("enet1_clk", IMX_SC_R_ENET_1, IMX_SC_PM_CLK_PER);
-       clks[IMX_CONN_ENET1_BYPASS_CLK] = imx_clk_scu("enet1_bypass_clk", IMX_SC_R_ENET_1, IMX_SC_PM_CLK_BYPASS);
-       clks[IMX_CONN_ENET1_RGMII_CLK]  = imx_clk_scu("enet1_rgmii_clk", IMX_SC_R_ENET_1, IMX_SC_PM_CLK_MISC0);
-       clks[IMX_CONN_GPMI_BCH_IO_CLK]  = imx_clk_scu("gpmi_io_clk", IMX_SC_R_NAND, IMX_SC_PM_CLK_MST_BUS);
-       clks[IMX_CONN_GPMI_BCH_CLK]     = imx_clk_scu("gpmi_bch_clk", IMX_SC_R_NAND, IMX_SC_PM_CLK_PER);
-       clks[IMX_CONN_USB2_ACLK]        = imx_clk_scu("usb3_aclk_div", IMX_SC_R_USB_2, IMX_SC_PM_CLK_PER);
-       clks[IMX_CONN_USB2_BUS_CLK]     = imx_clk_scu("usb3_bus_div", IMX_SC_R_USB_2, IMX_SC_PM_CLK_MST_BUS);
-       clks[IMX_CONN_USB2_LPM_CLK]     = imx_clk_scu("usb3_lpm_div", IMX_SC_R_USB_2, IMX_SC_PM_CLK_MISC);
+       clks[IMX_CONN_SDHC0_CLK]        = imx_clk_scu("sdhc0_clk", IMX_SC_R_SDHC_0, IMX_SC_PM_CLK_PER, clk_cells);
+       clks[IMX_CONN_SDHC1_CLK]        = imx_clk_scu("sdhc1_clk", IMX_SC_R_SDHC_1, IMX_SC_PM_CLK_PER, clk_cells);
+       clks[IMX_CONN_SDHC2_CLK]        = imx_clk_scu("sdhc2_clk", IMX_SC_R_SDHC_2, IMX_SC_PM_CLK_PER, clk_cells);
+       clks[IMX_CONN_ENET0_ROOT_CLK]   = imx_clk_scu("enet0_clk", IMX_SC_R_ENET_0, IMX_SC_PM_CLK_PER, clk_cells);
+       clks[IMX_CONN_ENET0_BYPASS_CLK] = imx_clk_scu("enet0_bypass_clk", IMX_SC_R_ENET_0, IMX_SC_PM_CLK_BYPASS, clk_cells);
+       clks[IMX_CONN_ENET0_RGMII_CLK]  = imx_clk_scu("enet0_rgmii_clk", IMX_SC_R_ENET_0, IMX_SC_PM_CLK_MISC0, clk_cells);
+       clks[IMX_CONN_ENET1_ROOT_CLK]   = imx_clk_scu("enet1_clk", IMX_SC_R_ENET_1, IMX_SC_PM_CLK_PER, clk_cells);
+       clks[IMX_CONN_ENET1_BYPASS_CLK] = imx_clk_scu("enet1_bypass_clk", IMX_SC_R_ENET_1, IMX_SC_PM_CLK_BYPASS, clk_cells);
+       clks[IMX_CONN_ENET1_RGMII_CLK]  = imx_clk_scu("enet1_rgmii_clk", IMX_SC_R_ENET_1, IMX_SC_PM_CLK_MISC0, clk_cells);
+       clks[IMX_CONN_GPMI_BCH_IO_CLK]  = imx_clk_scu("gpmi_io_clk", IMX_SC_R_NAND, IMX_SC_PM_CLK_MST_BUS, clk_cells);
+       clks[IMX_CONN_GPMI_BCH_CLK]     = imx_clk_scu("gpmi_bch_clk", IMX_SC_R_NAND, IMX_SC_PM_CLK_PER, clk_cells);
+       clks[IMX_CONN_USB2_ACLK]        = imx_clk_scu("usb3_aclk_div", IMX_SC_R_USB_2, IMX_SC_PM_CLK_PER, clk_cells);
+       clks[IMX_CONN_USB2_BUS_CLK]     = imx_clk_scu("usb3_bus_div", IMX_SC_R_USB_2, IMX_SC_PM_CLK_MST_BUS, clk_cells);
+       clks[IMX_CONN_USB2_LPM_CLK]     = imx_clk_scu("usb3_lpm_div", IMX_SC_R_USB_2, IMX_SC_PM_CLK_MISC, clk_cells);
 
        /* Display controller SS */
-       clks[IMX_DC0_DISP0_CLK]         = imx_clk_scu("dc0_disp0_clk", IMX_SC_R_DC_0, IMX_SC_PM_CLK_MISC0);
-       clks[IMX_DC0_DISP1_CLK]         = imx_clk_scu("dc0_disp1_clk", IMX_SC_R_DC_0, IMX_SC_PM_CLK_MISC1);
+       clks[IMX_DC0_DISP0_CLK]         = imx_clk_scu("dc0_disp0_clk", IMX_SC_R_DC_0, IMX_SC_PM_CLK_MISC0, clk_cells);
+       clks[IMX_DC0_DISP1_CLK]         = imx_clk_scu("dc0_disp1_clk", IMX_SC_R_DC_0, IMX_SC_PM_CLK_MISC1, clk_cells);
 
        /* MIPI-LVDS SS */
-       clks[IMX_MIPI0_I2C0_CLK]        = imx_clk_scu("mipi0_i2c0_clk", IMX_SC_R_MIPI_0_I2C_0, IMX_SC_PM_CLK_MISC2);
-       clks[IMX_MIPI0_I2C1_CLK]        = imx_clk_scu("mipi0_i2c1_clk", IMX_SC_R_MIPI_0_I2C_1, IMX_SC_PM_CLK_MISC2);
+       clks[IMX_MIPI0_I2C0_CLK]        = imx_clk_scu("mipi0_i2c0_clk", IMX_SC_R_MIPI_0_I2C_0, IMX_SC_PM_CLK_MISC2, clk_cells);
+       clks[IMX_MIPI0_I2C1_CLK]        = imx_clk_scu("mipi0_i2c1_clk", IMX_SC_R_MIPI_0_I2C_1, IMX_SC_PM_CLK_MISC2, clk_cells);
 
        /* MIPI CSI SS */
-       clks[IMX_CSI0_CORE_CLK]         = imx_clk_scu("mipi_csi0_core_clk", IMX_SC_R_CSI_0, IMX_SC_PM_CLK_PER);
-       clks[IMX_CSI0_ESC_CLK]          = imx_clk_scu("mipi_csi0_esc_clk",  IMX_SC_R_CSI_0, IMX_SC_PM_CLK_MISC);
-       clks[IMX_CSI0_I2C0_CLK]         = imx_clk_scu("mipi_csi0_i2c0_clk", IMX_SC_R_CSI_0_I2C_0, IMX_SC_PM_CLK_PER);
-       clks[IMX_CSI0_PWM0_CLK]         = imx_clk_scu("mipi_csi0_pwm0_clk", IMX_SC_R_CSI_0_PWM_0, IMX_SC_PM_CLK_PER);
+       clks[IMX_CSI0_CORE_CLK]         = imx_clk_scu("mipi_csi0_core_clk", IMX_SC_R_CSI_0, IMX_SC_PM_CLK_PER, clk_cells);
+       clks[IMX_CSI0_ESC_CLK]          = imx_clk_scu("mipi_csi0_esc_clk",  IMX_SC_R_CSI_0, IMX_SC_PM_CLK_MISC, clk_cells);
+       clks[IMX_CSI0_I2C0_CLK]         = imx_clk_scu("mipi_csi0_i2c0_clk", IMX_SC_R_CSI_0_I2C_0, IMX_SC_PM_CLK_PER, clk_cells);
+       clks[IMX_CSI0_PWM0_CLK]         = imx_clk_scu("mipi_csi0_pwm0_clk", IMX_SC_R_CSI_0_PWM_0, IMX_SC_PM_CLK_PER, clk_cells);
 
        /* GPU SS */
-       clks[IMX_GPU0_CORE_CLK]         = imx_clk_scu("gpu_core0_clk",   IMX_SC_R_GPU_0_PID0, IMX_SC_PM_CLK_PER);
-       clks[IMX_GPU0_SHADER_CLK]       = imx_clk_scu("gpu_shader0_clk", IMX_SC_R_GPU_0_PID0, IMX_SC_PM_CLK_MISC);
+       clks[IMX_GPU0_CORE_CLK]         = imx_clk_scu("gpu_core0_clk",   IMX_SC_R_GPU_0_PID0, IMX_SC_PM_CLK_PER, clk_cells);
+       clks[IMX_GPU0_SHADER_CLK]       = imx_clk_scu("gpu_shader0_clk", IMX_SC_R_GPU_0_PID0, IMX_SC_PM_CLK_MISC, clk_cells);
 
        for (i = 0; i < clk_data->num; i++) {
                if (IS_ERR(clks[i]))
@@ -134,7 +138,19 @@ static int imx8qxp_clk_probe(struct platform_device *pdev)
                                i, PTR_ERR(clks[i]));
        }
 
-       return of_clk_add_hw_provider(ccm_node, of_clk_hw_onecell_get, clk_data);
+       if (clk_cells == 2) {
+               ret = of_clk_add_hw_provider(ccm_node, imx_scu_of_clk_src_get, imx_scu_clks);
+               if (ret)
+                       imx_clk_scu_unregister();
+       } else {
+               /*
+                * legacy binding code path doesn't unregister here because
+                * it will be removed later.
+                */
+               ret = of_clk_add_hw_provider(ccm_node, of_clk_hw_onecell_get, clk_data);
+       }
+
+       return ret;
 }
 
 static const struct of_device_id imx8qxp_match[] = {
index 1f0e44f..77be763 100644 (file)
@@ -34,6 +34,9 @@ struct clk_lpcg_scu {
        void __iomem *reg;
        u8 bit_idx;
        bool hw_gate;
+
+       /* for state save&restore */
+       u32 state;
 };
 
 #define to_clk_lpcg_scu(_hw) container_of(_hw, struct clk_lpcg_scu, hw)
@@ -81,9 +84,9 @@ static const struct clk_ops clk_lpcg_scu_ops = {
        .disable = clk_lpcg_scu_disable,
 };
 
-struct clk_hw *imx_clk_lpcg_scu(const char *name, const char *parent_name,
-                               unsigned long flags, void __iomem *reg,
-                               u8 bit_idx, bool hw_gate)
+struct clk_hw *__imx_clk_lpcg_scu(struct device *dev, const char *name,
+                                 const char *parent_name, unsigned long flags,
+                                 void __iomem *reg, u8 bit_idx, bool hw_gate)
 {
        struct clk_lpcg_scu *clk;
        struct clk_init_data init;
@@ -107,11 +110,53 @@ struct clk_hw *imx_clk_lpcg_scu(const char *name, const char *parent_name,
        clk->hw.init = &init;
 
        hw = &clk->hw;
-       ret = clk_hw_register(NULL, hw);
+       ret = clk_hw_register(dev, hw);
        if (ret) {
                kfree(clk);
                hw = ERR_PTR(ret);
        }
 
+       if (dev)
+               dev_set_drvdata(dev, clk);
+
        return hw;
 }
+
+void imx_clk_lpcg_scu_unregister(struct clk_hw *hw)
+{
+       struct clk_lpcg_scu *clk = to_clk_lpcg_scu(hw);
+
+       clk_hw_unregister(&clk->hw);
+       kfree(clk);
+}
+
+static int __maybe_unused imx_clk_lpcg_scu_suspend(struct device *dev)
+{
+       struct clk_lpcg_scu *clk = dev_get_drvdata(dev);
+
+       clk->state = readl_relaxed(clk->reg);
+       dev_dbg(dev, "save lpcg state 0x%x\n", clk->state);
+
+       return 0;
+}
+
+static int __maybe_unused imx_clk_lpcg_scu_resume(struct device *dev)
+{
+       struct clk_lpcg_scu *clk = dev_get_drvdata(dev);
+
+       /*
+        * FIXME: Sometimes writes don't work unless the CPU issues
+        * them twice
+        */
+
+       writel(clk->state, clk->reg);
+       writel(clk->state, clk->reg);
+       dev_dbg(dev, "restore lpcg state 0x%x\n", clk->state);
+
+       return 0;
+}
+
+const struct dev_pm_ops imx_clk_lpcg_scu_pm_ops = {
+       SET_NOIRQ_SYSTEM_SLEEP_PM_OPS(imx_clk_lpcg_scu_suspend,
+                                     imx_clk_lpcg_scu_resume)
+};
index aba36e4..2b5ed86 100644 (file)
@@ -416,7 +416,7 @@ struct clk_hw *imx_dev_clk_hw_pll14xx(struct device *dev, const char *name,
                       __func__, name);
                kfree(pll);
                return ERR_PTR(-EINVAL);
-       };
+       }
 
        pll->base = base;
        pll->hw.init = &init;
index b8b2072..1f5518b 100644 (file)
@@ -8,6 +8,10 @@
 #include <linux/arm-smccc.h>
 #include <linux/clk-provider.h>
 #include <linux/err.h>
+#include <linux/of_platform.h>
+#include <linux/platform_device.h>
+#include <linux/pm_domain.h>
+#include <linux/pm_runtime.h>
 #include <linux/slab.h>
 
 #include "clk-scu.h"
 #define IMX_SIP_SET_CPUFREQ            0x00
 
 static struct imx_sc_ipc *ccm_ipc_handle;
+static struct device_node *pd_np;
+static struct platform_driver imx_clk_scu_driver;
+
+struct imx_scu_clk_node {
+       const char *name;
+       u32 rsrc;
+       u8 clk_type;
+       const char * const *parents;
+       int num_parents;
+
+       struct clk_hw *hw;
+       struct list_head node;
+};
+
+struct list_head imx_scu_clks[IMX_SC_R_LAST];
 
 /*
  * struct clk_scu - Description of one SCU clock
@@ -27,6 +46,10 @@ struct clk_scu {
        struct clk_hw hw;
        u16 rsrc_id;
        u8 clk_type;
+
+       /* for state save&restore */
+       bool is_enabled;
+       u32 rate;
 };
 
 /*
@@ -128,9 +151,28 @@ static inline struct clk_scu *to_clk_scu(struct clk_hw *hw)
        return container_of(hw, struct clk_scu, hw);
 }
 
-int imx_clk_scu_init(void)
+int imx_clk_scu_init(struct device_node *np)
 {
-       return imx_scu_get_handle(&ccm_ipc_handle);
+       u32 clk_cells;
+       int ret, i;
+
+       ret = imx_scu_get_handle(&ccm_ipc_handle);
+       if (ret)
+               return ret;
+
+       of_property_read_u32(np, "#clock-cells", &clk_cells);
+
+       if (clk_cells == 2) {
+               for (i = 0; i < IMX_SC_R_LAST; i++)
+                       INIT_LIST_HEAD(&imx_scu_clks[i]);
+
+               /* pd_np will be used to attach power domains later */
+               pd_np = of_find_compatible_node(NULL, NULL, "fsl,scu-pd");
+               if (!pd_np)
+                       return -EINVAL;
+       }
+
+       return platform_driver_register(&imx_clk_scu_driver);
 }
 
 /*
@@ -344,8 +386,9 @@ static const struct clk_ops clk_scu_cpu_ops = {
        .unprepare = clk_scu_unprepare,
 };
 
-struct clk_hw *__imx_clk_scu(const char *name, const char * const *parents,
-                            int num_parents, u32 rsrc_id, u8 clk_type)
+struct clk_hw *__imx_clk_scu(struct device *dev, const char *name,
+                            const char * const *parents, int num_parents,
+                            u32 rsrc_id, u8 clk_type)
 {
        struct clk_init_data init;
        struct clk_scu *clk;
@@ -379,11 +422,185 @@ struct clk_hw *__imx_clk_scu(const char *name, const char * const *parents,
        clk->hw.init = &init;
 
        hw = &clk->hw;
-       ret = clk_hw_register(NULL, hw);
+       ret = clk_hw_register(dev, hw);
        if (ret) {
                kfree(clk);
                hw = ERR_PTR(ret);
        }
 
+       if (dev)
+               dev_set_drvdata(dev, clk);
+
        return hw;
 }
+
+struct clk_hw *imx_scu_of_clk_src_get(struct of_phandle_args *clkspec,
+                                     void *data)
+{
+       unsigned int rsrc = clkspec->args[0];
+       unsigned int idx = clkspec->args[1];
+       struct list_head *scu_clks = data;
+       struct imx_scu_clk_node *clk;
+
+       list_for_each_entry(clk, &scu_clks[rsrc], node) {
+               if (clk->clk_type == idx)
+                       return clk->hw;
+       }
+
+       return ERR_PTR(-ENODEV);
+}
+
+static int imx_clk_scu_probe(struct platform_device *pdev)
+{
+       struct device *dev = &pdev->dev;
+       struct imx_scu_clk_node *clk = dev_get_platdata(dev);
+       struct clk_hw *hw;
+       int ret;
+
+       pm_runtime_set_suspended(dev);
+       pm_runtime_set_autosuspend_delay(dev, 50);
+       pm_runtime_use_autosuspend(&pdev->dev);
+       pm_runtime_enable(dev);
+
+       ret = pm_runtime_get_sync(dev);
+       if (ret) {
+               pm_runtime_disable(dev);
+               return ret;
+       }
+
+       hw = __imx_clk_scu(dev, clk->name, clk->parents, clk->num_parents,
+                          clk->rsrc, clk->clk_type);
+       if (IS_ERR(hw)) {
+               pm_runtime_disable(dev);
+               return PTR_ERR(hw);
+       }
+
+       clk->hw = hw;
+       list_add_tail(&clk->node, &imx_scu_clks[clk->rsrc]);
+
+       pm_runtime_mark_last_busy(&pdev->dev);
+       pm_runtime_put_autosuspend(&pdev->dev);
+
+       dev_dbg(dev, "register SCU clock rsrc:%d type:%d\n", clk->rsrc,
+               clk->clk_type);
+
+       return 0;
+}
+
+static int __maybe_unused imx_clk_scu_suspend(struct device *dev)
+{
+       struct clk_scu *clk = dev_get_drvdata(dev);
+
+       clk->rate = clk_hw_get_rate(&clk->hw);
+       clk->is_enabled = clk_hw_is_enabled(&clk->hw);
+
+       if (clk->rate)
+               dev_dbg(dev, "save rate %d\n", clk->rate);
+
+       if (clk->is_enabled)
+               dev_dbg(dev, "save enabled state\n");
+
+       return 0;
+}
+
+static int __maybe_unused imx_clk_scu_resume(struct device *dev)
+{
+       struct clk_scu *clk = dev_get_drvdata(dev);
+       int ret = 0;
+
+       if (clk->rate) {
+               ret = clk_scu_set_rate(&clk->hw, clk->rate, 0);
+               dev_dbg(dev, "restore rate %d %s\n", clk->rate,
+                       !ret ? "success" : "failed");
+       }
+
+       if (clk->is_enabled) {
+               ret = clk_scu_prepare(&clk->hw);
+               dev_dbg(dev, "restore enabled state %s\n",
+                       !ret ? "success" : "failed");
+       }
+
+       return ret;
+}
+
+static const struct dev_pm_ops imx_clk_scu_pm_ops = {
+       SET_NOIRQ_SYSTEM_SLEEP_PM_OPS(imx_clk_scu_suspend,
+                                     imx_clk_scu_resume)
+};
+
+static struct platform_driver imx_clk_scu_driver = {
+       .driver = {
+               .name = "imx-scu-clk",
+               .suppress_bind_attrs = true,
+               .pm = &imx_clk_scu_pm_ops,
+       },
+       .probe = imx_clk_scu_probe,
+};
+
+static int imx_clk_scu_attach_pd(struct device *dev, u32 rsrc_id)
+{
+       struct of_phandle_args genpdspec = {
+               .np = pd_np,
+               .args_count = 1,
+               .args[0] = rsrc_id,
+       };
+
+       if (rsrc_id == IMX_SC_R_A35 || rsrc_id == IMX_SC_R_A53 ||
+           rsrc_id == IMX_SC_R_A72)
+               return 0;
+
+       return of_genpd_add_device(&genpdspec, dev);
+}
+
+struct clk_hw *imx_clk_scu_alloc_dev(const char *name,
+                                    const char * const *parents,
+                                    int num_parents, u32 rsrc_id, u8 clk_type)
+{
+       struct imx_scu_clk_node clk = {
+               .name = name,
+               .rsrc = rsrc_id,
+               .clk_type = clk_type,
+               .parents = parents,
+               .num_parents = num_parents,
+       };
+       struct platform_device *pdev;
+       int ret;
+
+       pdev = platform_device_alloc(name, PLATFORM_DEVID_NONE);
+       if (!pdev) {
+               pr_err("%s: failed to allocate scu clk dev rsrc %d type %d\n",
+                      name, rsrc_id, clk_type);
+               return ERR_PTR(-ENOMEM);
+       }
+
+       ret = platform_device_add_data(pdev, &clk, sizeof(clk));
+       if (ret) {
+               platform_device_put(pdev);
+               return ERR_PTR(ret);
+       }
+
+       pdev->driver_override = "imx-scu-clk";
+
+       ret = imx_clk_scu_attach_pd(&pdev->dev, rsrc_id);
+       if (ret)
+               pr_warn("%s: failed to attached the power domain %d\n",
+                       name, ret);
+
+       platform_device_add(pdev);
+
+       /* For API backwards compatiblilty, simply return NULL for success */
+       return NULL;
+}
+
+void imx_clk_scu_unregister(void)
+{
+       struct imx_scu_clk_node *clk;
+       int i;
+
+       for (i = 0; i < IMX_SC_R_LAST; i++) {
+               list_for_each_entry(clk, &imx_scu_clks[i], node) {
+                       clk_hw_unregister(clk->hw);
+                       kfree(clk);
+               }
+       }
+}
index 2bcfaf0..e835216 100644 (file)
@@ -8,25 +8,61 @@
 #define __IMX_CLK_SCU_H
 
 #include <linux/firmware/imx/sci.h>
+#include <linux/of.h>
 
-int imx_clk_scu_init(void);
+extern struct list_head imx_scu_clks[];
+extern const struct dev_pm_ops imx_clk_lpcg_scu_pm_ops;
 
-struct clk_hw *__imx_clk_scu(const char *name, const char * const *parents,
-                            int num_parents, u32 rsrc_id, u8 clk_type);
+int imx_clk_scu_init(struct device_node *np);
+struct clk_hw *imx_scu_of_clk_src_get(struct of_phandle_args *clkspec,
+                                     void *data);
+struct clk_hw *imx_clk_scu_alloc_dev(const char *name,
+                                    const char * const *parents,
+                                    int num_parents, u32 rsrc_id, u8 clk_type);
+
+struct clk_hw *__imx_clk_scu(struct device *dev, const char *name,
+                            const char * const *parents, int num_parents,
+                            u32 rsrc_id, u8 clk_type);
+
+void imx_clk_scu_unregister(void);
+
+struct clk_hw *__imx_clk_lpcg_scu(struct device *dev, const char *name,
+                                 const char *parent_name, unsigned long flags,
+                                 void __iomem *reg, u8 bit_idx, bool hw_gate);
+void imx_clk_lpcg_scu_unregister(struct clk_hw *hw);
 
 static inline struct clk_hw *imx_clk_scu(const char *name, u32 rsrc_id,
-                                        u8 clk_type)
+                                        u8 clk_type, u8 clk_cells)
 {
-       return __imx_clk_scu(name, NULL, 0, rsrc_id, clk_type);
+       if (clk_cells == 2)
+               return imx_clk_scu_alloc_dev(name, NULL, 0, rsrc_id, clk_type);
+       else
+               return __imx_clk_scu(NULL, name, NULL, 0, rsrc_id, clk_type);
 }
 
 static inline struct clk_hw *imx_clk_scu2(const char *name, const char * const *parents,
-                                         int num_parents, u32 rsrc_id, u8 clk_type)
+                                         int num_parents, u32 rsrc_id, u8 clk_type,
+                                         u8 clk_cells)
+{
+       if (clk_cells == 2)
+               return imx_clk_scu_alloc_dev(name, parents, num_parents, rsrc_id, clk_type);
+       else
+               return __imx_clk_scu(NULL, name, parents, num_parents, rsrc_id, clk_type);
+}
+
+static inline struct clk_hw *imx_clk_lpcg_scu_dev(struct device *dev, const char *name,
+                                                 const char *parent_name, unsigned long flags,
+                                                 void __iomem *reg, u8 bit_idx, bool hw_gate)
 {
-       return __imx_clk_scu(name, parents, num_parents, rsrc_id, clk_type);
+       return __imx_clk_lpcg_scu(dev, name, parent_name, flags, reg,
+                                 bit_idx, hw_gate);
 }
 
-struct clk_hw *imx_clk_lpcg_scu(const char *name, const char *parent_name,
-                               unsigned long flags, void __iomem *reg,
-                               u8 bit_idx, bool hw_gate);
+static inline struct clk_hw *imx_clk_lpcg_scu(const char *name, const char *parent_name,
+                                             unsigned long flags, void __iomem *reg,
+                                             u8 bit_idx, bool hw_gate)
+{
+       return __imx_clk_lpcg_scu(NULL, name, parent_name, flags, reg,
+                                 bit_idx, hw_gate);
+}
 #endif
index 3b796b3..3d8e40b 100644 (file)
@@ -6,8 +6,6 @@
 #include <linux/spinlock.h>
 #include <linux/clk-provider.h>
 
-#define IMX_CLK_GATE2_SINGLE_BIT       1
-
 extern spinlock_t imx_ccm_lock;
 
 void imx_check_clocks(struct clk *clks[], unsigned int count);
@@ -68,9 +66,9 @@ extern struct imx_pll14xx_clk imx_1443x_dram_pll;
        to_clk(imx_clk_hw_cpu(name, parent_name, div, mux, pll, step))
 
 #define clk_register_gate2(dev, name, parent_name, flags, reg, bit_idx, \
-                               cgr_val, clk_gate_flags, lock, share_count) \
+                               cgr_val, cgr_mask, clk_gate_flags, lock, share_count) \
        to_clk(clk_hw_register_gate2(dev, name, parent_name, flags, reg, bit_idx, \
-                               cgr_val, clk_gate_flags, lock, share_count))
+                               cgr_val, cgr_mask, clk_gate_flags, lock, share_count))
 
 #define imx_clk_pllv3(type, name, parent_name, base, div_mask) \
        to_clk(imx_clk_hw_pllv3(type, name, parent_name, base, div_mask))
@@ -198,7 +196,7 @@ struct clk_hw *imx_clk_hw_pllv4(const char *name, const char *parent_name,
 
 struct clk_hw *clk_hw_register_gate2(struct device *dev, const char *name,
                const char *parent_name, unsigned long flags,
-               void __iomem *reg, u8 bit_idx, u8 cgr_val,
+               void __iomem *reg, u8 bit_idx, u8 cgr_val, u8 cgr_mask,
                u8 clk_gate_flags, spinlock_t *lock,
                unsigned int *share_count);
 
@@ -351,14 +349,14 @@ static inline struct clk_hw *imx_clk_hw_gate2(const char *name, const char *pare
                void __iomem *reg, u8 shift)
 {
        return clk_hw_register_gate2(NULL, name, parent, CLK_SET_RATE_PARENT, reg,
-                       shift, 0x3, 0, &imx_ccm_lock, NULL);
+                       shift, 0x3, 0x3, 0, &imx_ccm_lock, NULL);
 }
 
 static inline struct clk_hw *imx_clk_hw_gate2_flags(const char *name, const char *parent,
                void __iomem *reg, u8 shift, unsigned long flags)
 {
        return clk_hw_register_gate2(NULL, name, parent, flags | CLK_SET_RATE_PARENT, reg,
-                       shift, 0x3, 0, &imx_ccm_lock, NULL);
+                       shift, 0x3, 0x3, 0, &imx_ccm_lock, NULL);
 }
 
 static inline struct clk_hw *imx_clk_hw_gate2_shared(const char *name,
@@ -366,7 +364,7 @@ static inline struct clk_hw *imx_clk_hw_gate2_shared(const char *name,
                unsigned int *share_count)
 {
        return clk_hw_register_gate2(NULL, name, parent, CLK_SET_RATE_PARENT, reg,
-                       shift, 0x3, 0, &imx_ccm_lock, share_count);
+                       shift, 0x3, 0x3, 0, &imx_ccm_lock, share_count);
 }
 
 static inline struct clk_hw *imx_clk_hw_gate2_shared2(const char *name,
@@ -374,7 +372,7 @@ static inline struct clk_hw *imx_clk_hw_gate2_shared2(const char *name,
                unsigned int *share_count)
 {
        return clk_hw_register_gate2(NULL, name, parent, CLK_SET_RATE_PARENT |
-                                 CLK_OPS_PARENT_ENABLE, reg, shift, 0x3, 0,
+                                 CLK_OPS_PARENT_ENABLE, reg, shift, 0x3, 0x3, 0,
                                  &imx_ccm_lock, share_count);
 }
 
@@ -384,16 +382,15 @@ static inline struct clk_hw *imx_dev_clk_hw_gate_shared(struct device *dev,
                                unsigned int *share_count)
 {
        return clk_hw_register_gate2(NULL, name, parent, CLK_SET_RATE_PARENT |
-                                       CLK_OPS_PARENT_ENABLE, reg, shift, 0x3,
-                                       IMX_CLK_GATE2_SINGLE_BIT,
-                                       &imx_ccm_lock, share_count);
+                                       CLK_OPS_PARENT_ENABLE, reg, shift, 0x1,
+                                       0x1, 0, &imx_ccm_lock, share_count);
 }
 
 static inline struct clk *imx_clk_gate2_cgr(const char *name,
                const char *parent, void __iomem *reg, u8 shift, u8 cgr_val)
 {
        return clk_register_gate2(NULL, name, parent, CLK_SET_RATE_PARENT, reg,
-                       shift, cgr_val, 0, &imx_ccm_lock, NULL);
+                       shift, cgr_val, 0x3, 0, &imx_ccm_lock, NULL);
 }
 
 static inline struct clk_hw *imx_clk_hw_gate3(const char *name, const char *parent,
@@ -421,7 +418,7 @@ static inline struct clk_hw *imx_clk_hw_gate4(const char *name, const char *pare
 {
        return clk_hw_register_gate2(NULL, name, parent,
                        CLK_SET_RATE_PARENT | CLK_OPS_PARENT_ENABLE,
-                       reg, shift, 0x3, 0, &imx_ccm_lock, NULL);
+                       reg, shift, 0x3, 0x3, 0, &imx_ccm_lock, NULL);
 }
 
 static inline struct clk_hw *imx_clk_hw_gate4_flags(const char *name,
@@ -430,7 +427,7 @@ static inline struct clk_hw *imx_clk_hw_gate4_flags(const char *name,
 {
        return clk_hw_register_gate2(NULL, name, parent,
                        flags | CLK_SET_RATE_PARENT | CLK_OPS_PARENT_ENABLE,
-                       reg, shift, 0x3, 0, &imx_ccm_lock, NULL);
+                       reg, shift, 0x3, 0x3, 0, &imx_ccm_lock, NULL);
 }
 
 #define imx_clk_gate4_flags(name, parent, reg, shift, flags) \
index 14e127e..dcc1352 100644 (file)
@@ -155,7 +155,7 @@ const struct clk_ops mtk_mux_gate_clr_set_upd_ops = {
        .set_parent = mtk_clk_mux_set_parent_setclr_lock,
 };
 
-struct clk *mtk_clk_register_mux(const struct mtk_mux *mux,
+static struct clk *mtk_clk_register_mux(const struct mtk_mux *mux,
                                 struct regmap *regmap,
                                 spinlock_t *lock)
 {
index f5625f4..8e2f927 100644 (file)
@@ -77,10 +77,6 @@ extern const struct clk_ops mtk_mux_gate_clr_set_upd_ops;
                        _width, _gate, _upd_ofs, _upd,                  \
                        CLK_SET_RATE_PARENT)
 
-struct clk *mtk_clk_register_mux(const struct mtk_mux *mux,
-                                struct regmap *regmap,
-                                spinlock_t *lock);
-
 int mtk_clk_register_muxes(const struct mtk_mux *muxes,
                           int num, struct device_node *node,
                           spinlock_t *lock,
index 034da20..fc002c1 100644 (file)
@@ -58,7 +58,7 @@ config COMMON_CLK_MESON8B
          want peripherals and CPU frequency scaling to work.
 
 config COMMON_CLK_GXBB
-       bool "GXBB and GXL SoC clock controllers support"
+       tristate "GXBB and GXL SoC clock controllers support"
        depends on ARM64
        default y
        select COMMON_CLK_MESON_REGMAP
@@ -74,7 +74,7 @@ config COMMON_CLK_GXBB
          Say Y if you want peripherals and CPU frequency scaling to work.
 
 config COMMON_CLK_AXG
-       bool "AXG SoC clock controllers support"
+       tristate "AXG SoC clock controllers support"
        depends on ARM64
        default y
        select COMMON_CLK_MESON_REGMAP
@@ -100,7 +100,7 @@ config COMMON_CLK_AXG_AUDIO
          aka axg, Say Y if you want audio subsystem to work.
 
 config COMMON_CLK_G12A
-       bool "G12 and SM1 SoC clock controllers support"
+       tristate "G12 and SM1 SoC clock controllers support"
        depends on ARM64
        default y
        select COMMON_CLK_MESON_REGMAP
@@ -110,6 +110,7 @@ config COMMON_CLK_G12A
        select COMMON_CLK_MESON_AO_CLKC
        select COMMON_CLK_MESON_EE_CLKC
        select COMMON_CLK_MESON_CPU_DYNDIV
+       select COMMON_CLK_MESON_VID_PLL_DIV
        select MFD_SYSCON
        help
          Support for the clock controller on Amlogic S905D2, S905X2 and S905Y2
index b488b40..af6db43 100644 (file)
@@ -12,6 +12,7 @@
 #include <linux/platform_device.h>
 #include <linux/reset-controller.h>
 #include <linux/mfd/syscon.h>
+#include <linux/module.h>
 #include "meson-aoclk.h"
 #include "axg-aoclk.h"
 
@@ -326,6 +327,7 @@ static const struct of_device_id axg_aoclkc_match_table[] = {
        },
        { }
 };
+MODULE_DEVICE_TABLE(of, axg_aoclkc_match_table);
 
 static struct platform_driver axg_aoclkc_driver = {
        .probe          = meson_aoclkc_probe,
@@ -335,4 +337,5 @@ static struct platform_driver axg_aoclkc_driver = {
        },
 };
 
-builtin_platform_driver(axg_aoclkc_driver);
+module_platform_driver(axg_aoclkc_driver);
+MODULE_LICENSE("GPL v2");
index 13fc000..0e44695 100644 (file)
@@ -13,6 +13,7 @@
 #include <linux/init.h>
 #include <linux/of_device.h>
 #include <linux/platform_device.h>
+#include <linux/module.h>
 
 #include "clk-regmap.h"
 #include "clk-pll.h"
@@ -1026,6 +1027,743 @@ static struct clk_regmap axg_sd_emmc_c_clk0 = {
        },
 };
 
+/* VPU Clock */
+
+static const struct clk_hw *axg_vpu_parent_hws[] = {
+       &axg_fclk_div4.hw,
+       &axg_fclk_div3.hw,
+       &axg_fclk_div5.hw,
+       &axg_fclk_div7.hw,
+};
+
+static struct clk_regmap axg_vpu_0_sel = {
+       .data = &(struct clk_regmap_mux_data){
+               .offset = HHI_VPU_CLK_CNTL,
+               .mask = 0x3,
+               .shift = 9,
+       },
+       .hw.init = &(struct clk_init_data){
+               .name = "vpu_0_sel",
+               .ops = &clk_regmap_mux_ops,
+               .parent_hws = axg_vpu_parent_hws,
+               .num_parents = ARRAY_SIZE(axg_vpu_parent_hws),
+               /* We need a specific parent for VPU clock source, let it be set in DT */
+               .flags = CLK_SET_RATE_NO_REPARENT,
+       },
+};
+
+static struct clk_regmap axg_vpu_0_div = {
+       .data = &(struct clk_regmap_div_data){
+               .offset = HHI_VPU_CLK_CNTL,
+               .shift = 0,
+               .width = 7,
+       },
+       .hw.init = &(struct clk_init_data){
+               .name = "vpu_0_div",
+               .ops = &clk_regmap_divider_ops,
+               .parent_hws = (const struct clk_hw *[]) { &axg_vpu_0_sel.hw },
+               .num_parents = 1,
+               .flags = CLK_SET_RATE_PARENT,
+       },
+};
+
+static struct clk_regmap axg_vpu_0 = {
+       .data = &(struct clk_regmap_gate_data){
+               .offset = HHI_VPU_CLK_CNTL,
+               .bit_idx = 8,
+       },
+       .hw.init = &(struct clk_init_data) {
+               .name = "vpu_0",
+               .ops = &clk_regmap_gate_ops,
+               .parent_hws = (const struct clk_hw *[]) { &axg_vpu_0_div.hw },
+               .num_parents = 1,
+               /*
+                * We want to avoid CCF to disable the VPU clock if
+                * display has been set by Bootloader
+                */
+               .flags = CLK_SET_RATE_PARENT | CLK_IGNORE_UNUSED,
+       },
+};
+
+static struct clk_regmap axg_vpu_1_sel = {
+       .data = &(struct clk_regmap_mux_data){
+               .offset = HHI_VPU_CLK_CNTL,
+               .mask = 0x3,
+               .shift = 25,
+       },
+       .hw.init = &(struct clk_init_data){
+               .name = "vpu_1_sel",
+               .ops = &clk_regmap_mux_ops,
+               .parent_hws = axg_vpu_parent_hws,
+               .num_parents = ARRAY_SIZE(axg_vpu_parent_hws),
+               /* We need a specific parent for VPU clock source, let it be set in DT */
+               .flags = CLK_SET_RATE_NO_REPARENT,
+       },
+};
+
+static struct clk_regmap axg_vpu_1_div = {
+       .data = &(struct clk_regmap_div_data){
+               .offset = HHI_VPU_CLK_CNTL,
+               .shift = 16,
+               .width = 7,
+       },
+       .hw.init = &(struct clk_init_data){
+               .name = "vpu_1_div",
+               .ops = &clk_regmap_divider_ops,
+               .parent_hws = (const struct clk_hw *[]) { &axg_vpu_1_sel.hw },
+               .num_parents = 1,
+               .flags = CLK_SET_RATE_PARENT,
+       },
+};
+
+static struct clk_regmap axg_vpu_1 = {
+       .data = &(struct clk_regmap_gate_data){
+               .offset = HHI_VPU_CLK_CNTL,
+               .bit_idx = 24,
+       },
+       .hw.init = &(struct clk_init_data) {
+               .name = "vpu_1",
+               .ops = &clk_regmap_gate_ops,
+               .parent_hws = (const struct clk_hw *[]) { &axg_vpu_1_div.hw },
+               .num_parents = 1,
+               /*
+                * We want to avoid CCF to disable the VPU clock if
+                * display has been set by Bootloader
+                */
+               .flags = CLK_SET_RATE_PARENT | CLK_IGNORE_UNUSED,
+       },
+};
+
+static struct clk_regmap axg_vpu = {
+       .data = &(struct clk_regmap_mux_data){
+               .offset = HHI_VPU_CLK_CNTL,
+               .mask = 1,
+               .shift = 31,
+       },
+       .hw.init = &(struct clk_init_data){
+               .name = "vpu",
+               .ops = &clk_regmap_mux_ops,
+               .parent_hws = (const struct clk_hw *[]) {
+                       &axg_vpu_0.hw,
+                       &axg_vpu_1.hw
+               },
+               .num_parents = 2,
+               .flags = CLK_SET_RATE_NO_REPARENT,
+       },
+};
+
+/* VAPB Clock */
+
+static struct clk_regmap axg_vapb_0_sel = {
+       .data = &(struct clk_regmap_mux_data){
+               .offset = HHI_VAPBCLK_CNTL,
+               .mask = 0x3,
+               .shift = 9,
+       },
+       .hw.init = &(struct clk_init_data){
+               .name = "vapb_0_sel",
+               .ops = &clk_regmap_mux_ops,
+               .parent_hws = axg_vpu_parent_hws,
+               .num_parents = ARRAY_SIZE(axg_vpu_parent_hws),
+               .flags = CLK_SET_RATE_NO_REPARENT,
+       },
+};
+
+static struct clk_regmap axg_vapb_0_div = {
+       .data = &(struct clk_regmap_div_data){
+               .offset = HHI_VAPBCLK_CNTL,
+               .shift = 0,
+               .width = 7,
+       },
+       .hw.init = &(struct clk_init_data){
+               .name = "vapb_0_div",
+               .ops = &clk_regmap_divider_ops,
+               .parent_hws = (const struct clk_hw *[]) {
+                       &axg_vapb_0_sel.hw
+               },
+               .num_parents = 1,
+               .flags = CLK_SET_RATE_PARENT,
+       },
+};
+
+static struct clk_regmap axg_vapb_0 = {
+       .data = &(struct clk_regmap_gate_data){
+               .offset = HHI_VAPBCLK_CNTL,
+               .bit_idx = 8,
+       },
+       .hw.init = &(struct clk_init_data) {
+               .name = "vapb_0",
+               .ops = &clk_regmap_gate_ops,
+               .parent_hws = (const struct clk_hw *[]) {
+                       &axg_vapb_0_div.hw
+               },
+               .num_parents = 1,
+               .flags = CLK_SET_RATE_PARENT | CLK_IGNORE_UNUSED,
+       },
+};
+
+static struct clk_regmap axg_vapb_1_sel = {
+       .data = &(struct clk_regmap_mux_data){
+               .offset = HHI_VAPBCLK_CNTL,
+               .mask = 0x3,
+               .shift = 25,
+       },
+       .hw.init = &(struct clk_init_data){
+               .name = "vapb_1_sel",
+               .ops = &clk_regmap_mux_ops,
+               .parent_hws = axg_vpu_parent_hws,
+               .num_parents = ARRAY_SIZE(axg_vpu_parent_hws),
+               .flags = CLK_SET_RATE_NO_REPARENT,
+       },
+};
+
+static struct clk_regmap axg_vapb_1_div = {
+       .data = &(struct clk_regmap_div_data){
+               .offset = HHI_VAPBCLK_CNTL,
+               .shift = 16,
+               .width = 7,
+       },
+       .hw.init = &(struct clk_init_data){
+               .name = "vapb_1_div",
+               .ops = &clk_regmap_divider_ops,
+               .parent_hws = (const struct clk_hw *[]) {
+                       &axg_vapb_1_sel.hw
+               },
+               .num_parents = 1,
+               .flags = CLK_SET_RATE_PARENT,
+       },
+};
+
+static struct clk_regmap axg_vapb_1 = {
+       .data = &(struct clk_regmap_gate_data){
+               .offset = HHI_VAPBCLK_CNTL,
+               .bit_idx = 24,
+       },
+       .hw.init = &(struct clk_init_data) {
+               .name = "vapb_1",
+               .ops = &clk_regmap_gate_ops,
+               .parent_hws = (const struct clk_hw *[]) {
+                       &axg_vapb_1_div.hw
+               },
+               .num_parents = 1,
+               .flags = CLK_SET_RATE_PARENT | CLK_IGNORE_UNUSED,
+       },
+};
+
+static struct clk_regmap axg_vapb_sel = {
+       .data = &(struct clk_regmap_mux_data){
+               .offset = HHI_VAPBCLK_CNTL,
+               .mask = 1,
+               .shift = 31,
+       },
+       .hw.init = &(struct clk_init_data){
+               .name = "vapb_sel",
+               .ops = &clk_regmap_mux_ops,
+               .parent_hws = (const struct clk_hw *[]) {
+                       &axg_vapb_0.hw,
+                       &axg_vapb_1.hw
+               },
+               .num_parents = 2,
+               .flags = CLK_SET_RATE_NO_REPARENT,
+       },
+};
+
+static struct clk_regmap axg_vapb = {
+       .data = &(struct clk_regmap_gate_data){
+               .offset = HHI_VAPBCLK_CNTL,
+               .bit_idx = 30,
+       },
+       .hw.init = &(struct clk_init_data) {
+               .name = "vapb",
+               .ops = &clk_regmap_gate_ops,
+               .parent_hws = (const struct clk_hw *[]) { &axg_vapb_sel.hw },
+               .num_parents = 1,
+               .flags = CLK_SET_RATE_PARENT | CLK_IGNORE_UNUSED,
+       },
+};
+
+/* Video Clocks */
+
+static const struct clk_hw *axg_vclk_parent_hws[] = {
+       &axg_gp0_pll.hw,
+       &axg_fclk_div4.hw,
+       &axg_fclk_div3.hw,
+       &axg_fclk_div5.hw,
+       &axg_fclk_div2.hw,
+       &axg_fclk_div7.hw,
+       &axg_mpll1.hw,
+};
+
+static struct clk_regmap axg_vclk_sel = {
+       .data = &(struct clk_regmap_mux_data){
+               .offset = HHI_VID_CLK_CNTL,
+               .mask = 0x7,
+               .shift = 16,
+       },
+       .hw.init = &(struct clk_init_data){
+               .name = "vclk_sel",
+               .ops = &clk_regmap_mux_ops,
+               .parent_hws = axg_vclk_parent_hws,
+               .num_parents = ARRAY_SIZE(axg_vclk_parent_hws),
+               .flags = CLK_SET_RATE_NO_REPARENT | CLK_GET_RATE_NOCACHE,
+       },
+};
+
+static struct clk_regmap axg_vclk2_sel = {
+       .data = &(struct clk_regmap_mux_data){
+               .offset = HHI_VIID_CLK_CNTL,
+               .mask = 0x7,
+               .shift = 16,
+       },
+       .hw.init = &(struct clk_init_data){
+               .name = "vclk2_sel",
+               .ops = &clk_regmap_mux_ops,
+               .parent_hws = axg_vclk_parent_hws,
+               .num_parents = ARRAY_SIZE(axg_vclk_parent_hws),
+               .flags = CLK_SET_RATE_NO_REPARENT | CLK_GET_RATE_NOCACHE,
+       },
+};
+
+static struct clk_regmap axg_vclk_input = {
+       .data = &(struct clk_regmap_gate_data){
+               .offset = HHI_VID_CLK_DIV,
+               .bit_idx = 16,
+       },
+       .hw.init = &(struct clk_init_data) {
+               .name = "vclk_input",
+               .ops = &clk_regmap_gate_ops,
+               .parent_hws = (const struct clk_hw *[]) { &axg_vclk_sel.hw },
+               .num_parents = 1,
+               .flags = CLK_SET_RATE_PARENT | CLK_IGNORE_UNUSED,
+       },
+};
+
+static struct clk_regmap axg_vclk2_input = {
+       .data = &(struct clk_regmap_gate_data){
+               .offset = HHI_VIID_CLK_DIV,
+               .bit_idx = 16,
+       },
+       .hw.init = &(struct clk_init_data) {
+               .name = "vclk2_input",
+               .ops = &clk_regmap_gate_ops,
+               .parent_hws = (const struct clk_hw *[]) { &axg_vclk2_sel.hw },
+               .num_parents = 1,
+               .flags = CLK_SET_RATE_PARENT | CLK_IGNORE_UNUSED,
+       },
+};
+
+static struct clk_regmap axg_vclk_div = {
+       .data = &(struct clk_regmap_div_data){
+               .offset = HHI_VID_CLK_DIV,
+               .shift = 0,
+               .width = 8,
+       },
+       .hw.init = &(struct clk_init_data){
+               .name = "vclk_div",
+               .ops = &clk_regmap_divider_ops,
+               .parent_hws = (const struct clk_hw *[]) {
+                       &axg_vclk_input.hw
+               },
+               .num_parents = 1,
+               .flags = CLK_GET_RATE_NOCACHE,
+       },
+};
+
+static struct clk_regmap axg_vclk2_div = {
+       .data = &(struct clk_regmap_div_data){
+               .offset = HHI_VIID_CLK_DIV,
+               .shift = 0,
+               .width = 8,
+       },
+       .hw.init = &(struct clk_init_data){
+               .name = "vclk2_div",
+               .ops = &clk_regmap_divider_ops,
+               .parent_hws = (const struct clk_hw *[]) {
+                       &axg_vclk2_input.hw
+               },
+               .num_parents = 1,
+               .flags = CLK_GET_RATE_NOCACHE,
+       },
+};
+
+static struct clk_regmap axg_vclk = {
+       .data = &(struct clk_regmap_gate_data){
+               .offset = HHI_VID_CLK_CNTL,
+               .bit_idx = 19,
+       },
+       .hw.init = &(struct clk_init_data) {
+               .name = "vclk",
+               .ops = &clk_regmap_gate_ops,
+               .parent_hws = (const struct clk_hw *[]) { &axg_vclk_div.hw },
+               .num_parents = 1,
+               .flags = CLK_SET_RATE_PARENT | CLK_IGNORE_UNUSED,
+       },
+};
+
+static struct clk_regmap axg_vclk2 = {
+       .data = &(struct clk_regmap_gate_data){
+               .offset = HHI_VIID_CLK_CNTL,
+               .bit_idx = 19,
+       },
+       .hw.init = &(struct clk_init_data) {
+               .name = "vclk2",
+               .ops = &clk_regmap_gate_ops,
+               .parent_hws = (const struct clk_hw *[]) { &axg_vclk2_div.hw },
+               .num_parents = 1,
+               .flags = CLK_SET_RATE_PARENT | CLK_IGNORE_UNUSED,
+       },
+};
+
+static struct clk_regmap axg_vclk_div1 = {
+       .data = &(struct clk_regmap_gate_data){
+               .offset = HHI_VID_CLK_CNTL,
+               .bit_idx = 0,
+       },
+       .hw.init = &(struct clk_init_data) {
+               .name = "vclk_div1",
+               .ops = &clk_regmap_gate_ops,
+               .parent_hws = (const struct clk_hw *[]) { &axg_vclk.hw },
+               .num_parents = 1,
+               .flags = CLK_SET_RATE_PARENT | CLK_IGNORE_UNUSED,
+       },
+};
+
+static struct clk_regmap axg_vclk_div2_en = {
+       .data = &(struct clk_regmap_gate_data){
+               .offset = HHI_VID_CLK_CNTL,
+               .bit_idx = 1,
+       },
+       .hw.init = &(struct clk_init_data) {
+               .name = "vclk_div2_en",
+               .ops = &clk_regmap_gate_ops,
+               .parent_hws = (const struct clk_hw *[]) { &axg_vclk.hw },
+               .num_parents = 1,
+               .flags = CLK_SET_RATE_PARENT | CLK_IGNORE_UNUSED,
+       },
+};
+
+static struct clk_regmap axg_vclk_div4_en = {
+       .data = &(struct clk_regmap_gate_data){
+               .offset = HHI_VID_CLK_CNTL,
+               .bit_idx = 2,
+       },
+       .hw.init = &(struct clk_init_data) {
+               .name = "vclk_div4_en",
+               .ops = &clk_regmap_gate_ops,
+               .parent_hws = (const struct clk_hw *[]) { &axg_vclk.hw },
+               .num_parents = 1,
+               .flags = CLK_SET_RATE_PARENT | CLK_IGNORE_UNUSED,
+       },
+};
+
+static struct clk_regmap axg_vclk_div6_en = {
+       .data = &(struct clk_regmap_gate_data){
+               .offset = HHI_VID_CLK_CNTL,
+               .bit_idx = 3,
+       },
+       .hw.init = &(struct clk_init_data) {
+               .name = "vclk_div6_en",
+               .ops = &clk_regmap_gate_ops,
+               .parent_hws = (const struct clk_hw *[]) { &axg_vclk.hw },
+               .num_parents = 1,
+               .flags = CLK_SET_RATE_PARENT | CLK_IGNORE_UNUSED,
+       },
+};
+
+static struct clk_regmap axg_vclk_div12_en = {
+       .data = &(struct clk_regmap_gate_data){
+               .offset = HHI_VID_CLK_CNTL,
+               .bit_idx = 4,
+       },
+       .hw.init = &(struct clk_init_data) {
+               .name = "vclk_div12_en",
+               .ops = &clk_regmap_gate_ops,
+               .parent_hws = (const struct clk_hw *[]) { &axg_vclk.hw },
+               .num_parents = 1,
+               .flags = CLK_SET_RATE_PARENT | CLK_IGNORE_UNUSED,
+       },
+};
+
+static struct clk_regmap axg_vclk2_div1 = {
+       .data = &(struct clk_regmap_gate_data){
+               .offset = HHI_VIID_CLK_CNTL,
+               .bit_idx = 0,
+       },
+       .hw.init = &(struct clk_init_data) {
+               .name = "vclk2_div1",
+               .ops = &clk_regmap_gate_ops,
+               .parent_hws = (const struct clk_hw *[]) { &axg_vclk2.hw },
+               .num_parents = 1,
+               .flags = CLK_SET_RATE_PARENT | CLK_IGNORE_UNUSED,
+       },
+};
+
+static struct clk_regmap axg_vclk2_div2_en = {
+       .data = &(struct clk_regmap_gate_data){
+               .offset = HHI_VIID_CLK_CNTL,
+               .bit_idx = 1,
+       },
+       .hw.init = &(struct clk_init_data) {
+               .name = "vclk2_div2_en",
+               .ops = &clk_regmap_gate_ops,
+               .parent_hws = (const struct clk_hw *[]) { &axg_vclk2.hw },
+               .num_parents = 1,
+               .flags = CLK_SET_RATE_PARENT | CLK_IGNORE_UNUSED,
+       },
+};
+
+static struct clk_regmap axg_vclk2_div4_en = {
+       .data = &(struct clk_regmap_gate_data){
+               .offset = HHI_VIID_CLK_CNTL,
+               .bit_idx = 2,
+       },
+       .hw.init = &(struct clk_init_data) {
+               .name = "vclk2_div4_en",
+               .ops = &clk_regmap_gate_ops,
+               .parent_hws = (const struct clk_hw *[]) { &axg_vclk2.hw },
+               .num_parents = 1,
+               .flags = CLK_SET_RATE_PARENT | CLK_IGNORE_UNUSED,
+       },
+};
+
+static struct clk_regmap axg_vclk2_div6_en = {
+       .data = &(struct clk_regmap_gate_data){
+               .offset = HHI_VIID_CLK_CNTL,
+               .bit_idx = 3,
+       },
+       .hw.init = &(struct clk_init_data) {
+               .name = "vclk2_div6_en",
+               .ops = &clk_regmap_gate_ops,
+               .parent_hws = (const struct clk_hw *[]) { &axg_vclk2.hw },
+               .num_parents = 1,
+               .flags = CLK_SET_RATE_PARENT | CLK_IGNORE_UNUSED,
+       },
+};
+
+static struct clk_regmap axg_vclk2_div12_en = {
+       .data = &(struct clk_regmap_gate_data){
+               .offset = HHI_VIID_CLK_CNTL,
+               .bit_idx = 4,
+       },
+       .hw.init = &(struct clk_init_data) {
+               .name = "vclk2_div12_en",
+               .ops = &clk_regmap_gate_ops,
+               .parent_hws = (const struct clk_hw *[]) { &axg_vclk2.hw },
+               .num_parents = 1,
+               .flags = CLK_SET_RATE_PARENT | CLK_IGNORE_UNUSED,
+       },
+};
+
+static struct clk_fixed_factor axg_vclk_div2 = {
+       .mult = 1,
+       .div = 2,
+       .hw.init = &(struct clk_init_data){
+               .name = "vclk_div2",
+               .ops = &clk_fixed_factor_ops,
+               .parent_hws = (const struct clk_hw *[]) {
+                       &axg_vclk_div2_en.hw
+               },
+               .num_parents = 1,
+       },
+};
+
+static struct clk_fixed_factor axg_vclk_div4 = {
+       .mult = 1,
+       .div = 4,
+       .hw.init = &(struct clk_init_data){
+               .name = "vclk_div4",
+               .ops = &clk_fixed_factor_ops,
+               .parent_hws = (const struct clk_hw *[]) {
+                       &axg_vclk_div4_en.hw
+               },
+               .num_parents = 1,
+       },
+};
+
+static struct clk_fixed_factor axg_vclk_div6 = {
+       .mult = 1,
+       .div = 6,
+       .hw.init = &(struct clk_init_data){
+               .name = "vclk_div6",
+               .ops = &clk_fixed_factor_ops,
+               .parent_hws = (const struct clk_hw *[]) {
+                       &axg_vclk_div6_en.hw
+               },
+               .num_parents = 1,
+       },
+};
+
+static struct clk_fixed_factor axg_vclk_div12 = {
+       .mult = 1,
+       .div = 12,
+       .hw.init = &(struct clk_init_data){
+               .name = "vclk_div12",
+               .ops = &clk_fixed_factor_ops,
+               .parent_hws = (const struct clk_hw *[]) {
+                       &axg_vclk_div12_en.hw
+               },
+               .num_parents = 1,
+       },
+};
+
+static struct clk_fixed_factor axg_vclk2_div2 = {
+       .mult = 1,
+       .div = 2,
+       .hw.init = &(struct clk_init_data){
+               .name = "vclk2_div2",
+               .ops = &clk_fixed_factor_ops,
+               .parent_hws = (const struct clk_hw *[]) {
+                       &axg_vclk2_div2_en.hw
+               },
+               .num_parents = 1,
+       },
+};
+
+static struct clk_fixed_factor axg_vclk2_div4 = {
+       .mult = 1,
+       .div = 4,
+       .hw.init = &(struct clk_init_data){
+               .name = "vclk2_div4",
+               .ops = &clk_fixed_factor_ops,
+               .parent_hws = (const struct clk_hw *[]) {
+                       &axg_vclk2_div4_en.hw
+               },
+               .num_parents = 1,
+       },
+};
+
+static struct clk_fixed_factor axg_vclk2_div6 = {
+       .mult = 1,
+       .div = 6,
+       .hw.init = &(struct clk_init_data){
+               .name = "vclk2_div6",
+               .ops = &clk_fixed_factor_ops,
+               .parent_hws = (const struct clk_hw *[]) {
+                       &axg_vclk2_div6_en.hw
+               },
+               .num_parents = 1,
+       },
+};
+
+static struct clk_fixed_factor axg_vclk2_div12 = {
+       .mult = 1,
+       .div = 12,
+       .hw.init = &(struct clk_init_data){
+               .name = "vclk2_div12",
+               .ops = &clk_fixed_factor_ops,
+               .parent_hws = (const struct clk_hw *[]) {
+                       &axg_vclk2_div12_en.hw
+               },
+               .num_parents = 1,
+       },
+};
+
+static u32 mux_table_cts_sel[] = { 0, 1, 2, 3, 4, 8, 9, 10, 11, 12 };
+static const struct clk_hw *axg_cts_parent_hws[] = {
+       &axg_vclk_div1.hw,
+       &axg_vclk_div2.hw,
+       &axg_vclk_div4.hw,
+       &axg_vclk_div6.hw,
+       &axg_vclk_div12.hw,
+       &axg_vclk2_div1.hw,
+       &axg_vclk2_div2.hw,
+       &axg_vclk2_div4.hw,
+       &axg_vclk2_div6.hw,
+       &axg_vclk2_div12.hw,
+};
+
+static struct clk_regmap axg_cts_encl_sel = {
+       .data = &(struct clk_regmap_mux_data){
+               .offset = HHI_VIID_CLK_DIV,
+               .mask = 0xf,
+               .shift = 12,
+               .table = mux_table_cts_sel,
+       },
+       .hw.init = &(struct clk_init_data){
+               .name = "cts_encl_sel",
+               .ops = &clk_regmap_mux_ops,
+               .parent_hws = axg_cts_parent_hws,
+               .num_parents = ARRAY_SIZE(axg_cts_parent_hws),
+               .flags = CLK_SET_RATE_NO_REPARENT | CLK_GET_RATE_NOCACHE,
+       },
+};
+
+static struct clk_regmap axg_cts_encl = {
+       .data = &(struct clk_regmap_gate_data){
+               .offset = HHI_VID_CLK_CNTL2,
+               .bit_idx = 3,
+       },
+       .hw.init = &(struct clk_init_data) {
+               .name = "cts_encl",
+               .ops = &clk_regmap_gate_ops,
+               .parent_hws = (const struct clk_hw *[]) {
+                       &axg_cts_encl_sel.hw
+               },
+               .num_parents = 1,
+               .flags = CLK_SET_RATE_PARENT | CLK_IGNORE_UNUSED,
+       },
+};
+
+/* MIPI DSI Host Clock */
+
+static u32 mux_table_axg_vdin_meas[]    = { 0, 1, 2, 3, 6, 7 };
+static const struct clk_parent_data axg_vdin_meas_parent_data[] = {
+       { .fw_name = "xtal", },
+       { .hw = &axg_fclk_div4.hw },
+       { .hw = &axg_fclk_div3.hw },
+       { .hw = &axg_fclk_div5.hw },
+       { .hw = &axg_fclk_div2.hw },
+       { .hw = &axg_fclk_div7.hw },
+};
+
+static struct clk_regmap axg_vdin_meas_sel = {
+       .data = &(struct clk_regmap_mux_data){
+               .offset = HHI_VDIN_MEAS_CLK_CNTL,
+               .mask = 0x7,
+               .shift = 21,
+               .flags = CLK_MUX_ROUND_CLOSEST,
+               .table = mux_table_axg_vdin_meas,
+       },
+       .hw.init = &(struct clk_init_data){
+               .name = "vdin_meas_sel",
+               .ops = &clk_regmap_mux_ops,
+               .parent_data = axg_vdin_meas_parent_data,
+               .num_parents = ARRAY_SIZE(axg_vdin_meas_parent_data),
+               .flags = CLK_SET_RATE_PARENT,
+       },
+};
+
+static struct clk_regmap axg_vdin_meas_div = {
+       .data = &(struct clk_regmap_div_data){
+               .offset = HHI_VDIN_MEAS_CLK_CNTL,
+               .shift = 12,
+               .width = 7,
+       },
+       .hw.init = &(struct clk_init_data){
+               .name = "vdin_meas_div",
+               .ops = &clk_regmap_divider_ops,
+               .parent_hws = (const struct clk_hw *[]) {
+                       &axg_vdin_meas_sel.hw },
+               .num_parents = 1,
+               .flags = CLK_SET_RATE_PARENT,
+       },
+};
+
+static struct clk_regmap axg_vdin_meas = {
+       .data = &(struct clk_regmap_gate_data){
+               .offset = HHI_VDIN_MEAS_CLK_CNTL,
+               .bit_idx = 20,
+       },
+       .hw.init = &(struct clk_init_data) {
+               .name = "vdin_meas",
+               .ops = &clk_regmap_gate_ops,
+               .parent_hws = (const struct clk_hw *[]) {
+                       &axg_vdin_meas_div.hw },
+               .num_parents = 1,
+               .flags = CLK_SET_RATE_PARENT,
+       },
+};
+
 static u32 mux_table_gen_clk[] = { 0, 4, 5, 6, 7, 8,
                                    9, 10, 11, 13, 14, };
 static const struct clk_parent_data gen_clk_parent_data[] = {
@@ -1246,6 +1984,52 @@ static struct clk_hw_onecell_data axg_hw_onecell_data = {
                [CLKID_HIFI_PLL_DCO]            = &axg_hifi_pll_dco.hw,
                [CLKID_PCIE_PLL_DCO]            = &axg_pcie_pll_dco.hw,
                [CLKID_PCIE_PLL_OD]             = &axg_pcie_pll_od.hw,
+               [CLKID_VPU_0_DIV]               = &axg_vpu_0_div.hw,
+               [CLKID_VPU_0_SEL]               = &axg_vpu_0_sel.hw,
+               [CLKID_VPU_0]                   = &axg_vpu_0.hw,
+               [CLKID_VPU_1_DIV]               = &axg_vpu_1_div.hw,
+               [CLKID_VPU_1_SEL]               = &axg_vpu_1_sel.hw,
+               [CLKID_VPU_1]                   = &axg_vpu_1.hw,
+               [CLKID_VPU]                     = &axg_vpu.hw,
+               [CLKID_VAPB_0_DIV]              = &axg_vapb_0_div.hw,
+               [CLKID_VAPB_0_SEL]              = &axg_vapb_0_sel.hw,
+               [CLKID_VAPB_0]                  = &axg_vapb_0.hw,
+               [CLKID_VAPB_1_DIV]              = &axg_vapb_1_div.hw,
+               [CLKID_VAPB_1_SEL]              = &axg_vapb_1_sel.hw,
+               [CLKID_VAPB_1]                  = &axg_vapb_1.hw,
+               [CLKID_VAPB_SEL]                = &axg_vapb_sel.hw,
+               [CLKID_VAPB]                    = &axg_vapb.hw,
+               [CLKID_VCLK]                    = &axg_vclk.hw,
+               [CLKID_VCLK2]                   = &axg_vclk2.hw,
+               [CLKID_VCLK_SEL]                = &axg_vclk_sel.hw,
+               [CLKID_VCLK2_SEL]               = &axg_vclk2_sel.hw,
+               [CLKID_VCLK_INPUT]              = &axg_vclk_input.hw,
+               [CLKID_VCLK2_INPUT]             = &axg_vclk2_input.hw,
+               [CLKID_VCLK_DIV]                = &axg_vclk_div.hw,
+               [CLKID_VCLK2_DIV]               = &axg_vclk2_div.hw,
+               [CLKID_VCLK_DIV2_EN]            = &axg_vclk_div2_en.hw,
+               [CLKID_VCLK_DIV4_EN]            = &axg_vclk_div4_en.hw,
+               [CLKID_VCLK_DIV6_EN]            = &axg_vclk_div6_en.hw,
+               [CLKID_VCLK_DIV12_EN]           = &axg_vclk_div12_en.hw,
+               [CLKID_VCLK2_DIV2_EN]           = &axg_vclk2_div2_en.hw,
+               [CLKID_VCLK2_DIV4_EN]           = &axg_vclk2_div4_en.hw,
+               [CLKID_VCLK2_DIV6_EN]           = &axg_vclk2_div6_en.hw,
+               [CLKID_VCLK2_DIV12_EN]          = &axg_vclk2_div12_en.hw,
+               [CLKID_VCLK_DIV1]               = &axg_vclk_div1.hw,
+               [CLKID_VCLK_DIV2]               = &axg_vclk_div2.hw,
+               [CLKID_VCLK_DIV4]               = &axg_vclk_div4.hw,
+               [CLKID_VCLK_DIV6]               = &axg_vclk_div6.hw,
+               [CLKID_VCLK_DIV12]              = &axg_vclk_div12.hw,
+               [CLKID_VCLK2_DIV1]              = &axg_vclk2_div1.hw,
+               [CLKID_VCLK2_DIV2]              = &axg_vclk2_div2.hw,
+               [CLKID_VCLK2_DIV4]              = &axg_vclk2_div4.hw,
+               [CLKID_VCLK2_DIV6]              = &axg_vclk2_div6.hw,
+               [CLKID_VCLK2_DIV12]             = &axg_vclk2_div12.hw,
+               [CLKID_CTS_ENCL_SEL]            = &axg_cts_encl_sel.hw,
+               [CLKID_CTS_ENCL]                = &axg_cts_encl.hw,
+               [CLKID_VDIN_MEAS_SEL]           = &axg_vdin_meas_sel.hw,
+               [CLKID_VDIN_MEAS_DIV]           = &axg_vdin_meas_div.hw,
+               [CLKID_VDIN_MEAS]               = &axg_vdin_meas.hw,
                [NR_CLKS]                       = NULL,
        },
        .num = NR_CLKS,
@@ -1341,6 +2125,42 @@ static struct clk_regmap *const axg_clk_regmaps[] = {
        &axg_hifi_pll_dco,
        &axg_pcie_pll_dco,
        &axg_pcie_pll_od,
+       &axg_vpu_0_div,
+       &axg_vpu_0_sel,
+       &axg_vpu_0,
+       &axg_vpu_1_div,
+       &axg_vpu_1_sel,
+       &axg_vpu_1,
+       &axg_vpu,
+       &axg_vapb_0_div,
+       &axg_vapb_0_sel,
+       &axg_vapb_0,
+       &axg_vapb_1_div,
+       &axg_vapb_1_sel,
+       &axg_vapb_1,
+       &axg_vapb_sel,
+       &axg_vapb,
+       &axg_vclk,
+       &axg_vclk2,
+       &axg_vclk_sel,
+       &axg_vclk2_sel,
+       &axg_vclk_input,
+       &axg_vclk2_input,
+       &axg_vclk_div,
+       &axg_vclk2_div,
+       &axg_vclk_div2_en,
+       &axg_vclk_div4_en,
+       &axg_vclk_div6_en,
+       &axg_vclk_div12_en,
+       &axg_vclk2_div2_en,
+       &axg_vclk2_div4_en,
+       &axg_vclk2_div6_en,
+       &axg_vclk2_div12_en,
+       &axg_cts_encl_sel,
+       &axg_cts_encl,
+       &axg_vdin_meas_sel,
+       &axg_vdin_meas_div,
+       &axg_vdin_meas,
 };
 
 static const struct meson_eeclkc_data axg_clkc_data = {
@@ -1354,6 +2174,7 @@ static const struct of_device_id clkc_match_table[] = {
        { .compatible = "amlogic,axg-clkc", .data = &axg_clkc_data },
        {}
 };
+MODULE_DEVICE_TABLE(of, clkc_match_table);
 
 static struct platform_driver axg_driver = {
        .probe          = meson_eeclkc_probe,
@@ -1363,4 +2184,5 @@ static struct platform_driver axg_driver = {
        },
 };
 
-builtin_platform_driver(axg_driver);
+module_platform_driver(axg_driver);
+MODULE_LICENSE("GPL v2");
index 0431dab..481b307 100644 (file)
 #define CLKID_HIFI_PLL_DCO                     88
 #define CLKID_PCIE_PLL_DCO                     89
 #define CLKID_PCIE_PLL_OD                      90
+#define CLKID_VPU_0_DIV                                91
+#define CLKID_VPU_1_DIV                                94
+#define CLKID_VAPB_0_DIV                       98
+#define CLKID_VAPB_1_DIV                       101
+#define CLKID_VCLK_SEL                         108
+#define CLKID_VCLK2_SEL                                109
+#define CLKID_VCLK_INPUT                       110
+#define CLKID_VCLK2_INPUT                      111
+#define CLKID_VCLK_DIV                         112
+#define CLKID_VCLK2_DIV                                113
+#define CLKID_VCLK_DIV2_EN                     114
+#define CLKID_VCLK_DIV4_EN                     115
+#define CLKID_VCLK_DIV6_EN                     116
+#define CLKID_VCLK_DIV12_EN                    117
+#define CLKID_VCLK2_DIV2_EN                    118
+#define CLKID_VCLK2_DIV4_EN                    119
+#define CLKID_VCLK2_DIV6_EN                    120
+#define CLKID_VCLK2_DIV12_EN                   121
+#define CLKID_CTS_ENCL_SEL                     132
+#define CLKID_VDIN_MEAS_SEL                    134
+#define CLKID_VDIN_MEAS_DIV                    135
 
-#define NR_CLKS                                        91
+#define NR_CLKS                                        137
 
 /* include the CLKIDs that have been made part of the DT binding */
 #include <dt-bindings/clock/axg-clkc.h>
index 6249956..b52990e 100644 (file)
@@ -12,6 +12,7 @@
 #include <linux/platform_device.h>
 #include <linux/reset-controller.h>
 #include <linux/mfd/syscon.h>
+#include <linux/module.h>
 #include "meson-aoclk.h"
 #include "g12a-aoclk.h"
 
@@ -461,6 +462,7 @@ static const struct of_device_id g12a_aoclkc_match_table[] = {
        },
        { }
 };
+MODULE_DEVICE_TABLE(of, g12a_aoclkc_match_table);
 
 static struct platform_driver g12a_aoclkc_driver = {
        .probe          = meson_aoclkc_probe,
@@ -470,4 +472,5 @@ static struct platform_driver g12a_aoclkc_driver = {
        },
 };
 
-builtin_platform_driver(g12a_aoclkc_driver);
+module_platform_driver(g12a_aoclkc_driver);
+MODULE_LICENSE("GPL v2");
index b814d44..b080359 100644 (file)
@@ -15,6 +15,7 @@
 #include <linux/of_device.h>
 #include <linux/platform_device.h>
 #include <linux/clk.h>
+#include <linux/module.h>
 
 #include "clk-mpll.h"
 #include "clk-pll.h"
@@ -3657,6 +3658,68 @@ static struct clk_regmap g12a_hdmi_tx = {
        },
 };
 
+/* MIPI DSI Host Clocks */
+
+static const struct clk_hw *g12a_mipi_dsi_pxclk_parent_hws[] = {
+       &g12a_vid_pll.hw,
+       &g12a_gp0_pll.hw,
+       &g12a_hifi_pll.hw,
+       &g12a_mpll1.hw,
+       &g12a_fclk_div2.hw,
+       &g12a_fclk_div2p5.hw,
+       &g12a_fclk_div3.hw,
+       &g12a_fclk_div7.hw,
+};
+
+static struct clk_regmap g12a_mipi_dsi_pxclk_sel = {
+       .data = &(struct clk_regmap_mux_data){
+               .offset = HHI_MIPIDSI_PHY_CLK_CNTL,
+               .mask = 0x7,
+               .shift = 12,
+               .flags = CLK_MUX_ROUND_CLOSEST,
+       },
+       .hw.init = &(struct clk_init_data){
+               .name = "mipi_dsi_pxclk_sel",
+               .ops = &clk_regmap_mux_ops,
+               .parent_hws = g12a_mipi_dsi_pxclk_parent_hws,
+               .num_parents = ARRAY_SIZE(g12a_mipi_dsi_pxclk_parent_hws),
+               .flags = CLK_SET_RATE_NO_REPARENT,
+       },
+};
+
+static struct clk_regmap g12a_mipi_dsi_pxclk_div = {
+       .data = &(struct clk_regmap_div_data){
+               .offset = HHI_MIPIDSI_PHY_CLK_CNTL,
+               .shift = 0,
+               .width = 7,
+       },
+       .hw.init = &(struct clk_init_data){
+               .name = "mipi_dsi_pxclk_div",
+               .ops = &clk_regmap_divider_ops,
+               .parent_hws = (const struct clk_hw *[]) {
+                       &g12a_mipi_dsi_pxclk_sel.hw
+               },
+               .num_parents = 1,
+               .flags = CLK_SET_RATE_PARENT,
+       },
+};
+
+static struct clk_regmap g12a_mipi_dsi_pxclk = {
+       .data = &(struct clk_regmap_gate_data){
+               .offset = HHI_MIPIDSI_PHY_CLK_CNTL,
+               .bit_idx = 8,
+       },
+       .hw.init = &(struct clk_init_data) {
+               .name = "mipi_dsi_pxclk",
+               .ops = &clk_regmap_gate_ops,
+               .parent_hws = (const struct clk_hw *[]) {
+                       &g12a_mipi_dsi_pxclk_div.hw
+               },
+               .num_parents = 1,
+               .flags = CLK_SET_RATE_PARENT,
+       },
+};
+
 /* HDMI Clocks */
 
 static const struct clk_parent_data g12a_hdmi_parent_data[] = {
@@ -4402,6 +4465,9 @@ static struct clk_hw_onecell_data g12a_hw_onecell_data = {
                [CLKID_SPICC1_SCLK_SEL]         = &g12a_spicc1_sclk_sel.hw,
                [CLKID_SPICC1_SCLK_DIV]         = &g12a_spicc1_sclk_div.hw,
                [CLKID_SPICC1_SCLK]             = &g12a_spicc1_sclk.hw,
+               [CLKID_MIPI_DSI_PXCLK_SEL]      = &g12a_mipi_dsi_pxclk_sel.hw,
+               [CLKID_MIPI_DSI_PXCLK_DIV]      = &g12a_mipi_dsi_pxclk_div.hw,
+               [CLKID_MIPI_DSI_PXCLK]          = &g12a_mipi_dsi_pxclk.hw,
                [NR_CLKS]                       = NULL,
        },
        .num = NR_CLKS,
@@ -4657,6 +4723,9 @@ static struct clk_hw_onecell_data g12b_hw_onecell_data = {
                [CLKID_SPICC1_SCLK_SEL]         = &g12a_spicc1_sclk_sel.hw,
                [CLKID_SPICC1_SCLK_DIV]         = &g12a_spicc1_sclk_div.hw,
                [CLKID_SPICC1_SCLK]             = &g12a_spicc1_sclk.hw,
+               [CLKID_MIPI_DSI_PXCLK_SEL]      = &g12a_mipi_dsi_pxclk_sel.hw,
+               [CLKID_MIPI_DSI_PXCLK_DIV]      = &g12a_mipi_dsi_pxclk_div.hw,
+               [CLKID_MIPI_DSI_PXCLK]          = &g12a_mipi_dsi_pxclk.hw,
                [NR_CLKS]                       = NULL,
        },
        .num = NR_CLKS,
@@ -4903,6 +4972,9 @@ static struct clk_hw_onecell_data sm1_hw_onecell_data = {
                [CLKID_NNA_CORE_CLK_SEL]        = &sm1_nna_core_clk_sel.hw,
                [CLKID_NNA_CORE_CLK_DIV]        = &sm1_nna_core_clk_div.hw,
                [CLKID_NNA_CORE_CLK]            = &sm1_nna_core_clk.hw,
+               [CLKID_MIPI_DSI_PXCLK_SEL]      = &g12a_mipi_dsi_pxclk_sel.hw,
+               [CLKID_MIPI_DSI_PXCLK_DIV]      = &g12a_mipi_dsi_pxclk_div.hw,
+               [CLKID_MIPI_DSI_PXCLK]          = &g12a_mipi_dsi_pxclk.hw,
                [NR_CLKS]                       = NULL,
        },
        .num = NR_CLKS,
@@ -5150,16 +5222,20 @@ static struct clk_regmap *const g12a_clk_regmaps[] = {
        &sm1_nna_core_clk_sel,
        &sm1_nna_core_clk_div,
        &sm1_nna_core_clk,
+       &g12a_mipi_dsi_pxclk_sel,
+       &g12a_mipi_dsi_pxclk_div,
+       &g12a_mipi_dsi_pxclk,
 };
 
 static const struct reg_sequence g12a_init_regs[] = {
        { .reg = HHI_MPLL_CNTL0,        .def = 0x00000543 },
 };
 
-static int meson_g12a_dvfs_setup_common(struct platform_device *pdev,
+#define DVFS_CON_ID "dvfs"
+
+static int meson_g12a_dvfs_setup_common(struct device *dev,
                                        struct clk_hw **hws)
 {
-       const char *notifier_clk_name;
        struct clk *notifier_clk;
        struct clk_hw *xtal;
        int ret;
@@ -5168,21 +5244,22 @@ static int meson_g12a_dvfs_setup_common(struct platform_device *pdev,
 
        /* Setup clock notifier for cpu_clk_postmux0 */
        g12a_cpu_clk_postmux0_nb_data.xtal = xtal;
-       notifier_clk_name = clk_hw_get_name(&g12a_cpu_clk_postmux0.hw);
-       notifier_clk = __clk_lookup(notifier_clk_name);
-       ret = clk_notifier_register(notifier_clk,
-                                   &g12a_cpu_clk_postmux0_nb_data.nb);
+       notifier_clk = devm_clk_hw_get_clk(dev, &g12a_cpu_clk_postmux0.hw,
+                                          DVFS_CON_ID);
+       ret = devm_clk_notifier_register(dev, notifier_clk,
+                                        &g12a_cpu_clk_postmux0_nb_data.nb);
        if (ret) {
-               dev_err(&pdev->dev, "failed to register the cpu_clk_postmux0 notifier\n");
+               dev_err(dev, "failed to register the cpu_clk_postmux0 notifier\n");
                return ret;
        }
 
        /* Setup clock notifier for cpu_clk_dyn mux */
-       notifier_clk_name = clk_hw_get_name(&g12a_cpu_clk_dyn.hw);
-       notifier_clk = __clk_lookup(notifier_clk_name);
-       ret = clk_notifier_register(notifier_clk, &g12a_cpu_clk_mux_nb);
+       notifier_clk = devm_clk_hw_get_clk(dev, &g12a_cpu_clk_dyn.hw,
+                                          DVFS_CON_ID);
+       ret = devm_clk_notifier_register(dev, notifier_clk,
+                                        &g12a_cpu_clk_mux_nb);
        if (ret) {
-               dev_err(&pdev->dev, "failed to register the cpu_clk_dyn notifier\n");
+               dev_err(dev, "failed to register the cpu_clk_dyn notifier\n");
                return ret;
        }
 
@@ -5192,33 +5269,34 @@ static int meson_g12a_dvfs_setup_common(struct platform_device *pdev,
 static int meson_g12b_dvfs_setup(struct platform_device *pdev)
 {
        struct clk_hw **hws = g12b_hw_onecell_data.hws;
-       const char *notifier_clk_name;
+       struct device *dev = &pdev->dev;
        struct clk *notifier_clk;
        struct clk_hw *xtal;
        int ret;
 
-       ret = meson_g12a_dvfs_setup_common(pdev, hws);
+       ret = meson_g12a_dvfs_setup_common(dev, hws);
        if (ret)
                return ret;
 
        xtal = clk_hw_get_parent_by_index(hws[CLKID_CPU_CLK_DYN1_SEL], 0);
 
        /* Setup clock notifier for cpu_clk mux */
-       notifier_clk_name = clk_hw_get_name(&g12b_cpu_clk.hw);
-       notifier_clk = __clk_lookup(notifier_clk_name);
-       ret = clk_notifier_register(notifier_clk, &g12a_cpu_clk_mux_nb);
+       notifier_clk = devm_clk_hw_get_clk(dev, &g12b_cpu_clk.hw,
+                                          DVFS_CON_ID);
+       ret = devm_clk_notifier_register(dev, notifier_clk,
+                                        &g12a_cpu_clk_mux_nb);
        if (ret) {
-               dev_err(&pdev->dev, "failed to register the cpu_clk notifier\n");
+               dev_err(dev, "failed to register the cpu_clk notifier\n");
                return ret;
        }
 
        /* Setup clock notifier for sys1_pll */
-       notifier_clk_name = clk_hw_get_name(&g12b_sys1_pll.hw);
-       notifier_clk = __clk_lookup(notifier_clk_name);
-       ret = clk_notifier_register(notifier_clk,
-                                   &g12b_cpu_clk_sys1_pll_nb_data.nb);
+       notifier_clk = devm_clk_hw_get_clk(dev, &g12b_sys1_pll.hw,
+                                          DVFS_CON_ID);
+       ret = devm_clk_notifier_register(dev, notifier_clk,
+                                        &g12b_cpu_clk_sys1_pll_nb_data.nb);
        if (ret) {
-               dev_err(&pdev->dev, "failed to register the sys1_pll notifier\n");
+               dev_err(dev, "failed to register the sys1_pll notifier\n");
                return ret;
        }
 
@@ -5226,40 +5304,39 @@ static int meson_g12b_dvfs_setup(struct platform_device *pdev)
 
        /* Setup clock notifier for cpub_clk_postmux0 */
        g12b_cpub_clk_postmux0_nb_data.xtal = xtal;
-       notifier_clk_name = clk_hw_get_name(&g12b_cpub_clk_postmux0.hw);
-       notifier_clk = __clk_lookup(notifier_clk_name);
-       ret = clk_notifier_register(notifier_clk,
-                                   &g12b_cpub_clk_postmux0_nb_data.nb);
+       notifier_clk = devm_clk_hw_get_clk(dev, &g12b_cpub_clk_postmux0.hw,
+                                          DVFS_CON_ID);
+       ret = devm_clk_notifier_register(dev, notifier_clk,
+                                        &g12b_cpub_clk_postmux0_nb_data.nb);
        if (ret) {
-               dev_err(&pdev->dev, "failed to register the cpub_clk_postmux0 notifier\n");
+               dev_err(dev, "failed to register the cpub_clk_postmux0 notifier\n");
                return ret;
        }
 
        /* Setup clock notifier for cpub_clk_dyn mux */
-       notifier_clk_name = clk_hw_get_name(&g12b_cpub_clk_dyn.hw);
-       notifier_clk = __clk_lookup(notifier_clk_name);
-       ret = clk_notifier_register(notifier_clk, &g12a_cpu_clk_mux_nb);
+       notifier_clk = devm_clk_hw_get_clk(dev, &g12b_cpub_clk_dyn.hw, "dvfs");
+       ret = devm_clk_notifier_register(dev, notifier_clk,
+                                        &g12a_cpu_clk_mux_nb);
        if (ret) {
-               dev_err(&pdev->dev, "failed to register the cpub_clk_dyn notifier\n");
+               dev_err(dev, "failed to register the cpub_clk_dyn notifier\n");
                return ret;
        }
 
        /* Setup clock notifier for cpub_clk mux */
-       notifier_clk_name = clk_hw_get_name(&g12b_cpub_clk.hw);
-       notifier_clk = __clk_lookup(notifier_clk_name);
-       ret = clk_notifier_register(notifier_clk, &g12a_cpu_clk_mux_nb);
+       notifier_clk = devm_clk_hw_get_clk(dev, &g12b_cpub_clk.hw, DVFS_CON_ID);
+       ret = devm_clk_notifier_register(dev, notifier_clk,
+                                        &g12a_cpu_clk_mux_nb);
        if (ret) {
-               dev_err(&pdev->dev, "failed to register the cpub_clk notifier\n");
+               dev_err(dev, "failed to register the cpub_clk notifier\n");
                return ret;
        }
 
        /* Setup clock notifier for sys_pll */
-       notifier_clk_name = clk_hw_get_name(&g12a_sys_pll.hw);
-       notifier_clk = __clk_lookup(notifier_clk_name);
-       ret = clk_notifier_register(notifier_clk,
-                                   &g12b_cpub_clk_sys_pll_nb_data.nb);
+       notifier_clk = devm_clk_hw_get_clk(dev, &g12a_sys_pll.hw, DVFS_CON_ID);
+       ret = devm_clk_notifier_register(dev, notifier_clk,
+                                        &g12b_cpub_clk_sys_pll_nb_data.nb);
        if (ret) {
-               dev_err(&pdev->dev, "failed to register the sys_pll notifier\n");
+               dev_err(dev, "failed to register the sys_pll notifier\n");
                return ret;
        }
 
@@ -5269,29 +5346,29 @@ static int meson_g12b_dvfs_setup(struct platform_device *pdev)
 static int meson_g12a_dvfs_setup(struct platform_device *pdev)
 {
        struct clk_hw **hws = g12a_hw_onecell_data.hws;
-       const char *notifier_clk_name;
+       struct device *dev = &pdev->dev;
        struct clk *notifier_clk;
        int ret;
 
-       ret = meson_g12a_dvfs_setup_common(pdev, hws);
+       ret = meson_g12a_dvfs_setup_common(dev, hws);
        if (ret)
                return ret;
 
        /* Setup clock notifier for cpu_clk mux */
-       notifier_clk_name = clk_hw_get_name(&g12a_cpu_clk.hw);
-       notifier_clk = __clk_lookup(notifier_clk_name);
-       ret = clk_notifier_register(notifier_clk, &g12a_cpu_clk_mux_nb);
+       notifier_clk = devm_clk_hw_get_clk(dev, &g12a_cpu_clk.hw, DVFS_CON_ID);
+       ret = devm_clk_notifier_register(dev, notifier_clk,
+                                   &g12a_cpu_clk_mux_nb);
        if (ret) {
-               dev_err(&pdev->dev, "failed to register the cpu_clk notifier\n");
+               dev_err(dev, "failed to register the cpu_clk notifier\n");
                return ret;
        }
 
        /* Setup clock notifier for sys_pll */
-       notifier_clk_name = clk_hw_get_name(&g12a_sys_pll.hw);
-       notifier_clk = __clk_lookup(notifier_clk_name);
-       ret = clk_notifier_register(notifier_clk, &g12a_sys_pll_nb_data.nb);
+       notifier_clk = devm_clk_hw_get_clk(dev, &g12a_sys_pll.hw, DVFS_CON_ID);
+       ret = devm_clk_notifier_register(dev, notifier_clk,
+                                        &g12a_sys_pll_nb_data.nb);
        if (ret) {
-               dev_err(&pdev->dev, "failed to register the sys_pll notifier\n");
+               dev_err(dev, "failed to register the sys_pll notifier\n");
                return ret;
        }
 
@@ -5370,6 +5447,7 @@ static const struct of_device_id clkc_match_table[] = {
        },
        {}
 };
+MODULE_DEVICE_TABLE(of, clkc_match_table);
 
 static struct platform_driver g12a_driver = {
        .probe          = meson_g12a_probe,
@@ -5379,4 +5457,5 @@ static struct platform_driver g12a_driver = {
        },
 };
 
-builtin_platform_driver(g12a_driver);
+module_platform_driver(g12a_driver);
+MODULE_LICENSE("GPL v2");
index 69b6a69..a97613d 100644 (file)
 #define CLKID_NNA_AXI_CLK_DIV                  263
 #define CLKID_NNA_CORE_CLK_SEL                 265
 #define CLKID_NNA_CORE_CLK_DIV                 266
+#define CLKID_MIPI_DSI_PXCLK_DIV               268
 
-#define NR_CLKS                                        268
+#define NR_CLKS                                        271
 
 /* include the CLKIDs that have been made part of the DT binding */
 #include <dt-bindings/clock/g12a-clkc.h>
index e940861..fce95cf 100644 (file)
@@ -5,6 +5,7 @@
  */
 #include <linux/platform_device.h>
 #include <linux/mfd/syscon.h>
+#include <linux/module.h>
 #include "meson-aoclk.h"
 #include "gxbb-aoclk.h"
 
@@ -287,6 +288,7 @@ static const struct of_device_id gxbb_aoclkc_match_table[] = {
        },
        { }
 };
+MODULE_DEVICE_TABLE(of, gxbb_aoclkc_match_table);
 
 static struct platform_driver gxbb_aoclkc_driver = {
        .probe          = meson_aoclkc_probe,
@@ -295,4 +297,5 @@ static struct platform_driver gxbb_aoclkc_driver = {
                .of_match_table = gxbb_aoclkc_match_table,
        },
 };
-builtin_platform_driver(gxbb_aoclkc_driver);
+module_platform_driver(gxbb_aoclkc_driver);
+MODULE_LICENSE("GPL v2");
index 0a68af6..d6eed76 100644 (file)
@@ -8,6 +8,7 @@
 #include <linux/init.h>
 #include <linux/of_device.h>
 #include <linux/platform_device.h>
+#include <linux/module.h>
 
 #include "gxbb.h"
 #include "clk-regmap.h"
@@ -3519,6 +3520,7 @@ static const struct of_device_id clkc_match_table[] = {
        { .compatible = "amlogic,gxl-clkc", .data = &gxl_clkc_data },
        {},
 };
+MODULE_DEVICE_TABLE(of, clkc_match_table);
 
 static struct platform_driver gxbb_driver = {
        .probe          = meson_eeclkc_probe,
@@ -3528,4 +3530,5 @@ static struct platform_driver gxbb_driver = {
        },
 };
 
-builtin_platform_driver(gxbb_driver);
+module_platform_driver(gxbb_driver);
+MODULE_LICENSE("GPL v2");
index 3a6d84c..27cd2c1 100644 (file)
@@ -14,6 +14,8 @@
 #include <linux/reset-controller.h>
 #include <linux/mfd/syscon.h>
 #include <linux/of_device.h>
+#include <linux/module.h>
+
 #include <linux/slab.h>
 #include "meson-aoclk.h"
 
@@ -84,3 +86,5 @@ int meson_aoclkc_probe(struct platform_device *pdev)
        return devm_of_clk_add_hw_provider(dev, of_clk_hw_onecell_get,
                (void *) data->hw_data);
 }
+EXPORT_SYMBOL_GPL(meson_aoclkc_probe);
+MODULE_LICENSE("GPL v2");
index a7cb1e7..8d5a5da 100644 (file)
@@ -9,6 +9,7 @@
 #include <linux/platform_device.h>
 #include <linux/mfd/syscon.h>
 #include <linux/regmap.h>
+#include <linux/module.h>
 
 #include "clk-regmap.h"
 #include "meson-eeclk.h"
@@ -54,3 +55,5 @@ int meson_eeclkc_probe(struct platform_device *pdev)
        return devm_of_clk_add_hw_provider(dev, of_clk_hw_onecell_get,
                                           data->hw_onecell_data);
 }
+EXPORT_SYMBOL_GPL(meson_eeclkc_probe);
+MODULE_LICENSE("GPL v2");
index 3a965bd..d32bb12 100644 (file)
@@ -44,7 +44,7 @@ config QCOM_CLK_APCC_MSM8996
        help
          Support for the CPU clock controller on msm8996 devices.
          Say Y if you want to support CPU clock scaling using CPUfreq
-         drivers for dyanmic power management.
+         drivers for dynamic power management.
 
 config QCOM_CLK_RPM
        tristate "RPM based Clock Controller"
@@ -290,6 +290,15 @@ config QCS_GCC_404
          Say Y if you want to use multimedia devices or peripheral
          devices such as UART, SPI, I2C, USB, SD/eMMC, PCIe etc.
 
+config SC_CAMCC_7180
+       tristate "SC7180 Camera Clock Controller"
+       select SC_GCC_7180
+       help
+         Support for the camera clock controller on Qualcomm Technologies, Inc
+         SC7180 devices.
+         Say Y if you want to support camera devices and functionality such as
+         capturing pictures.
+
 config SC_DISPCC_7180
        tristate "SC7180 Display Clock Controller"
        select SC_GCC_7180
@@ -413,6 +422,14 @@ config SDM_LPASSCC_845
          Say Y if you want to use the LPASS branch clocks of the LPASS clock
          controller to reset the LPASS subsystem.
 
+config SDX_GCC_55
+       tristate "SDX55 Global Clock Controller"
+       select QCOM_GDSC
+       help
+         Support for the global clock controller on SDX55 devices.
+         Say Y if you want to use peripheral devices such as UART,
+         SPI, I2C, USB, SD/UFS, PCIe etc.
+
 config SM_DISPCC_8250
        tristate "SM8150 and SM8250 Display Clock Controller"
        depends on SM_GCC_8150 || SM_GCC_8250
@@ -502,4 +519,10 @@ config KRAITCC
          Support for the Krait CPU clocks on Qualcomm devices.
          Say Y if you want to support CPU frequency scaling.
 
+config CLK_GFM_LPASS_SM8250
+       tristate "SM8250 GFM LPASS Clocks"
+       help
+         Support for the Glitch Free Mux (GFM) Low power audio
+          subsystem (LPASS) clocks found on SM8250 SoCs.
+
 endif
index 11ae86f..9e5e0e3 100644 (file)
@@ -19,6 +19,7 @@ clk-qcom-$(CONFIG_QCOM_GDSC) += gdsc.o
 # Keep alphabetically sorted by config
 obj-$(CONFIG_APQ_GCC_8084) += gcc-apq8084.o
 obj-$(CONFIG_APQ_MMCC_8084) += mmcc-apq8084.o
+obj-$(CONFIG_CLK_GFM_LPASS_SM8250) += lpass-gfm-sm8250.o
 obj-$(CONFIG_IPQ_APSS_PLL) += apss-ipq-pll.o
 obj-$(CONFIG_IPQ_APSS_6018) += apss-ipq6018.o
 obj-$(CONFIG_IPQ_GCC_4019) += gcc-ipq4019.o
@@ -51,6 +52,7 @@ obj-$(CONFIG_QCOM_CLK_SMD_RPM) += clk-smd-rpm.o
 obj-$(CONFIG_QCS_GCC_404) += gcc-qcs404.o
 obj-$(CONFIG_QCS_Q6SSTOP_404) += q6sstop-qcs404.o
 obj-$(CONFIG_QCS_TURING_404) += turingcc-qcs404.o
+obj-$(CONFIG_SC_CAMCC_7180) += camcc-sc7180.o
 obj-$(CONFIG_SC_DISPCC_7180) += dispcc-sc7180.o
 obj-$(CONFIG_SC_GCC_7180) += gcc-sc7180.o
 obj-$(CONFIG_SC_GPUCC_7180) += gpucc-sc7180.o
@@ -64,6 +66,7 @@ obj-$(CONFIG_SDM_GCC_845) += gcc-sdm845.o
 obj-$(CONFIG_SDM_GPUCC_845) += gpucc-sdm845.o
 obj-$(CONFIG_SDM_LPASSCC_845) += lpasscc-sdm845.o
 obj-$(CONFIG_SDM_VIDEOCC_845) += videocc-sdm845.o
+obj-$(CONFIG_SDX_GCC_55) += gcc-sdx55.o
 obj-$(CONFIG_SM_DISPCC_8250) += dispcc-sm8250.o
 obj-$(CONFIG_SM_GCC_8150) += gcc-sm8150.o
 obj-$(CONFIG_SM_GCC_8250) += gcc-sm8250.o
diff --git a/drivers/clk/qcom/camcc-sc7180.c b/drivers/clk/qcom/camcc-sc7180.c
new file mode 100644 (file)
index 0000000..dbac565
--- /dev/null
@@ -0,0 +1,1732 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Copyright (c) 2020, The Linux Foundation. All rights reserved.
+ */
+
+#include <linux/clk-provider.h>
+#include <linux/err.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/of_device.h>
+#include <linux/pm_clock.h>
+#include <linux/pm_runtime.h>
+#include <linux/regmap.h>
+
+#include <dt-bindings/clock/qcom,camcc-sc7180.h>
+
+#include "clk-alpha-pll.h"
+#include "clk-branch.h"
+#include "clk-rcg.h"
+#include "clk-regmap.h"
+#include "common.h"
+#include "gdsc.h"
+#include "reset.h"
+
+enum {
+       P_BI_TCXO,
+       P_CAM_CC_PLL0_OUT_EVEN,
+       P_CAM_CC_PLL1_OUT_EVEN,
+       P_CAM_CC_PLL2_OUT_AUX,
+       P_CAM_CC_PLL2_OUT_EARLY,
+       P_CAM_CC_PLL3_OUT_MAIN,
+       P_CORE_BI_PLL_TEST_SE,
+};
+
+static const struct pll_vco agera_vco[] = {
+       { 600000000, 3300000000UL, 0 },
+};
+
+static const struct pll_vco fabia_vco[] = {
+       { 249600000, 2000000000UL, 0 },
+};
+
+/* 600MHz configuration */
+static const struct alpha_pll_config cam_cc_pll0_config = {
+       .l = 0x1f,
+       .alpha = 0x4000,
+       .config_ctl_val = 0x20485699,
+       .config_ctl_hi_val = 0x00002067,
+       .test_ctl_val = 0x40000000,
+       .user_ctl_hi_val = 0x00004805,
+       .user_ctl_val = 0x00000001,
+};
+
+static struct clk_alpha_pll cam_cc_pll0 = {
+       .offset = 0x0,
+       .vco_table = fabia_vco,
+       .num_vco = ARRAY_SIZE(fabia_vco),
+       .regs = clk_alpha_pll_regs[CLK_ALPHA_PLL_TYPE_FABIA],
+       .clkr = {
+               .hw.init = &(struct clk_init_data){
+                       .name = "cam_cc_pll0",
+                       .parent_data = &(const struct clk_parent_data){
+                               .fw_name = "bi_tcxo",
+                       },
+                       .num_parents = 1,
+                       .ops = &clk_alpha_pll_fabia_ops,
+               },
+       },
+};
+
+/* 860MHz configuration */
+static const struct alpha_pll_config cam_cc_pll1_config = {
+       .l = 0x2a,
+       .alpha = 0x1555,
+       .config_ctl_val = 0x20485699,
+       .config_ctl_hi_val = 0x00002067,
+       .test_ctl_val = 0x40000000,
+       .user_ctl_hi_val = 0x00004805,
+};
+
+static struct clk_alpha_pll cam_cc_pll1 = {
+       .offset = 0x1000,
+       .vco_table = fabia_vco,
+       .num_vco = ARRAY_SIZE(fabia_vco),
+       .regs = clk_alpha_pll_regs[CLK_ALPHA_PLL_TYPE_FABIA],
+       .clkr = {
+               .hw.init = &(struct clk_init_data){
+                       .name = "cam_cc_pll1",
+                       .parent_data = &(const struct clk_parent_data){
+                               .fw_name = "bi_tcxo",
+                       },
+                       .num_parents = 1,
+                       .ops = &clk_alpha_pll_fabia_ops,
+               },
+       },
+};
+
+/* 1920MHz configuration */
+static const struct alpha_pll_config cam_cc_pll2_config = {
+       .l = 0x64,
+       .config_ctl_val = 0x20000800,
+       .config_ctl_hi_val = 0x400003D2,
+       .test_ctl_val = 0x04000400,
+       .test_ctl_hi_val = 0x00004000,
+       .user_ctl_val = 0x0000030F,
+};
+
+static struct clk_alpha_pll cam_cc_pll2 = {
+       .offset = 0x2000,
+       .vco_table = agera_vco,
+       .num_vco = ARRAY_SIZE(agera_vco),
+       .regs = clk_alpha_pll_regs[CLK_ALPHA_PLL_TYPE_AGERA],
+       .clkr = {
+               .hw.init = &(struct clk_init_data){
+                       .name = "cam_cc_pll2",
+                       .parent_data = &(const struct clk_parent_data){
+                               .fw_name = "bi_tcxo",
+                       },
+                       .num_parents = 1,
+                       .ops = &clk_alpha_pll_agera_ops,
+               },
+       },
+};
+
+static struct clk_fixed_factor cam_cc_pll2_out_early = {
+       .mult = 1,
+       .div = 2,
+       .hw.init = &(struct clk_init_data){
+               .name = "cam_cc_pll2_out_early",
+               .parent_names = (const char *[]){ "cam_cc_pll2" },
+               .num_parents = 1,
+               .ops = &clk_fixed_factor_ops,
+       },
+};
+
+static const struct clk_div_table post_div_table_cam_cc_pll2_out_aux[] = {
+       { 0x3, 4 },
+       { }
+};
+
+static struct clk_alpha_pll_postdiv cam_cc_pll2_out_aux = {
+       .offset = 0x2000,
+       .post_div_shift = 8,
+       .post_div_table = post_div_table_cam_cc_pll2_out_aux,
+       .num_post_div = ARRAY_SIZE(post_div_table_cam_cc_pll2_out_aux),
+       .width = 2,
+       .regs = clk_alpha_pll_regs[CLK_ALPHA_PLL_TYPE_AGERA],
+       .clkr.hw.init = &(struct clk_init_data){
+               .name = "cam_cc_pll2_out_aux",
+               .parent_data = &(const struct clk_parent_data){
+                       .hw = &cam_cc_pll2.clkr.hw,
+               },
+               .num_parents = 1,
+               .flags = CLK_SET_RATE_PARENT,
+               .ops = &clk_alpha_pll_postdiv_ops,
+       },
+};
+
+/* 1080MHz configuration */
+static const struct alpha_pll_config cam_cc_pll3_config = {
+       .l = 0x38,
+       .alpha = 0x4000,
+       .config_ctl_val = 0x20485699,
+       .config_ctl_hi_val = 0x00002067,
+       .test_ctl_val = 0x40000000,
+       .user_ctl_hi_val = 0x00004805,
+};
+
+static struct clk_alpha_pll cam_cc_pll3 = {
+       .offset = 0x3000,
+       .vco_table = fabia_vco,
+       .num_vco = ARRAY_SIZE(fabia_vco),
+       .regs = clk_alpha_pll_regs[CLK_ALPHA_PLL_TYPE_FABIA],
+       .clkr = {
+               .hw.init = &(struct clk_init_data){
+                       .name = "cam_cc_pll3",
+                       .parent_data = &(const struct clk_parent_data){
+                               .fw_name = "bi_tcxo",
+                       },
+                       .num_parents = 1,
+                       .ops = &clk_alpha_pll_fabia_ops,
+               },
+       },
+};
+
+static const struct parent_map cam_cc_parent_map_0[] = {
+       { P_BI_TCXO, 0 },
+       { P_CAM_CC_PLL1_OUT_EVEN, 2 },
+       { P_CAM_CC_PLL0_OUT_EVEN, 6 },
+       { P_CORE_BI_PLL_TEST_SE, 7 },
+};
+
+static const struct clk_parent_data cam_cc_parent_data_0[] = {
+       { .fw_name = "bi_tcxo" },
+       { .hw = &cam_cc_pll1.clkr.hw },
+       { .hw = &cam_cc_pll0.clkr.hw },
+       { .fw_name = "core_bi_pll_test_se", .name = "core_bi_pll_test_se" },
+};
+
+static const struct parent_map cam_cc_parent_map_1[] = {
+       { P_BI_TCXO, 0 },
+       { P_CAM_CC_PLL2_OUT_AUX, 1 },
+       { P_CORE_BI_PLL_TEST_SE, 7 },
+};
+
+static const struct clk_parent_data cam_cc_parent_data_1[] = {
+       { .fw_name = "bi_tcxo" },
+       { .hw = &cam_cc_pll2_out_aux.clkr.hw },
+       { .fw_name = "core_bi_pll_test_se", .name = "core_bi_pll_test_se" },
+};
+
+static const struct parent_map cam_cc_parent_map_2[] = {
+       { P_BI_TCXO, 0 },
+       { P_CAM_CC_PLL2_OUT_EARLY, 4 },
+       { P_CAM_CC_PLL3_OUT_MAIN, 5 },
+       { P_CAM_CC_PLL0_OUT_EVEN, 6 },
+       { P_CORE_BI_PLL_TEST_SE, 7 },
+};
+
+static const struct clk_parent_data cam_cc_parent_data_2[] = {
+       { .fw_name = "bi_tcxo" },
+       { .hw = &cam_cc_pll2_out_early.hw },
+       { .hw = &cam_cc_pll3.clkr.hw },
+       { .hw = &cam_cc_pll0.clkr.hw },
+       { .fw_name = "core_bi_pll_test_se", .name = "core_bi_pll_test_se" },
+};
+
+static const struct parent_map cam_cc_parent_map_3[] = {
+       { P_BI_TCXO, 0 },
+       { P_CAM_CC_PLL1_OUT_EVEN, 2 },
+       { P_CAM_CC_PLL2_OUT_EARLY, 4 },
+       { P_CAM_CC_PLL3_OUT_MAIN, 5 },
+       { P_CAM_CC_PLL0_OUT_EVEN, 6 },
+       { P_CORE_BI_PLL_TEST_SE, 7 },
+};
+
+static const struct clk_parent_data cam_cc_parent_data_3[] = {
+       { .fw_name = "bi_tcxo" },
+       { .hw = &cam_cc_pll1.clkr.hw },
+       { .hw = &cam_cc_pll2_out_early.hw },
+       { .hw = &cam_cc_pll3.clkr.hw },
+       { .hw = &cam_cc_pll0.clkr.hw },
+       { .fw_name = "core_bi_pll_test_se", .name = "core_bi_pll_test_se" },
+};
+
+static const struct parent_map cam_cc_parent_map_4[] = {
+       { P_BI_TCXO, 0 },
+       { P_CAM_CC_PLL3_OUT_MAIN, 5 },
+       { P_CAM_CC_PLL0_OUT_EVEN, 6 },
+       { P_CORE_BI_PLL_TEST_SE, 7 },
+};
+
+static const struct clk_parent_data cam_cc_parent_data_4[] = {
+       { .fw_name = "bi_tcxo" },
+       { .hw = &cam_cc_pll3.clkr.hw },
+       { .hw = &cam_cc_pll0.clkr.hw },
+       { .fw_name = "core_bi_pll_test_se", .name = "core_bi_pll_test_se" },
+};
+
+static const struct parent_map cam_cc_parent_map_5[] = {
+       { P_BI_TCXO, 0 },
+       { P_CAM_CC_PLL0_OUT_EVEN, 6 },
+       { P_CORE_BI_PLL_TEST_SE, 7 },
+};
+
+static const struct clk_parent_data cam_cc_parent_data_5[] = {
+       { .fw_name = "bi_tcxo" },
+       { .hw = &cam_cc_pll0.clkr.hw },
+       { .fw_name = "core_bi_pll_test_se", .name = "core_bi_pll_test_se" },
+};
+
+static const struct parent_map cam_cc_parent_map_6[] = {
+       { P_BI_TCXO, 0 },
+       { P_CAM_CC_PLL1_OUT_EVEN, 2 },
+       { P_CAM_CC_PLL3_OUT_MAIN, 5 },
+       { P_CAM_CC_PLL0_OUT_EVEN, 6 },
+       { P_CORE_BI_PLL_TEST_SE, 7 },
+};
+
+static const struct clk_parent_data cam_cc_parent_data_6[] = {
+       { .fw_name = "bi_tcxo" },
+       { .hw = &cam_cc_pll1.clkr.hw },
+       { .hw = &cam_cc_pll3.clkr.hw },
+       { .hw = &cam_cc_pll0.clkr.hw },
+       { .fw_name = "core_bi_pll_test_se", .name = "core_bi_pll_test_se" },
+};
+
+static const struct freq_tbl ftbl_cam_cc_bps_clk_src[] = {
+       F(200000000, P_CAM_CC_PLL0_OUT_EVEN, 3, 0, 0),
+       F(360000000, P_CAM_CC_PLL3_OUT_MAIN, 3, 0, 0),
+       F(432000000, P_CAM_CC_PLL3_OUT_MAIN, 2.5, 0, 0),
+       F(480000000, P_CAM_CC_PLL2_OUT_EARLY, 2, 0, 0),
+       F(600000000, P_CAM_CC_PLL0_OUT_EVEN, 1, 0, 0),
+       { }
+};
+
+static struct clk_rcg2 cam_cc_bps_clk_src = {
+       .cmd_rcgr = 0x6010,
+       .mnd_width = 0,
+       .hid_width = 5,
+       .parent_map = cam_cc_parent_map_2,
+       .freq_tbl = ftbl_cam_cc_bps_clk_src,
+       .clkr.hw.init = &(struct clk_init_data){
+               .name = "cam_cc_bps_clk_src",
+               .parent_data = cam_cc_parent_data_2,
+               .num_parents = 5,
+               .ops = &clk_rcg2_ops,
+       },
+};
+
+static const struct freq_tbl ftbl_cam_cc_cci_0_clk_src[] = {
+       F(37500000, P_CAM_CC_PLL0_OUT_EVEN, 16, 0, 0),
+       F(50000000, P_CAM_CC_PLL0_OUT_EVEN, 12, 0, 0),
+       F(100000000, P_CAM_CC_PLL0_OUT_EVEN, 6, 0, 0),
+       { }
+};
+
+static struct clk_rcg2 cam_cc_cci_0_clk_src = {
+       .cmd_rcgr = 0xb0d8,
+       .mnd_width = 8,
+       .hid_width = 5,
+       .parent_map = cam_cc_parent_map_5,
+       .freq_tbl = ftbl_cam_cc_cci_0_clk_src,
+       .clkr.hw.init = &(struct clk_init_data){
+               .name = "cam_cc_cci_0_clk_src",
+               .parent_data = cam_cc_parent_data_5,
+               .num_parents = 3,
+               .ops = &clk_rcg2_ops,
+       },
+};
+
+static struct clk_rcg2 cam_cc_cci_1_clk_src = {
+       .cmd_rcgr = 0xb14c,
+       .mnd_width = 8,
+       .hid_width = 5,
+       .parent_map = cam_cc_parent_map_5,
+       .freq_tbl = ftbl_cam_cc_cci_0_clk_src,
+       .clkr.hw.init = &(struct clk_init_data){
+               .name = "cam_cc_cci_1_clk_src",
+               .parent_data = cam_cc_parent_data_5,
+               .num_parents = 3,
+               .ops = &clk_rcg2_ops,
+       },
+};
+
+static const struct freq_tbl ftbl_cam_cc_cphy_rx_clk_src[] = {
+       F(150000000, P_CAM_CC_PLL0_OUT_EVEN, 4, 0, 0),
+       F(270000000, P_CAM_CC_PLL3_OUT_MAIN, 4, 0, 0),
+       F(360000000, P_CAM_CC_PLL3_OUT_MAIN, 3, 0, 0),
+       { }
+};
+
+static struct clk_rcg2 cam_cc_cphy_rx_clk_src = {
+       .cmd_rcgr = 0x9064,
+       .mnd_width = 0,
+       .hid_width = 5,
+       .parent_map = cam_cc_parent_map_3,
+       .freq_tbl = ftbl_cam_cc_cphy_rx_clk_src,
+       .clkr.hw.init = &(struct clk_init_data){
+               .name = "cam_cc_cphy_rx_clk_src",
+               .parent_data = cam_cc_parent_data_3,
+               .num_parents = 6,
+               .ops = &clk_rcg2_ops,
+       },
+};
+
+static const struct freq_tbl ftbl_cam_cc_csi0phytimer_clk_src[] = {
+       F(300000000, P_CAM_CC_PLL0_OUT_EVEN, 2, 0, 0),
+       { }
+};
+
+static struct clk_rcg2 cam_cc_csi0phytimer_clk_src = {
+       .cmd_rcgr = 0x5004,
+       .mnd_width = 0,
+       .hid_width = 5,
+       .parent_map = cam_cc_parent_map_0,
+       .freq_tbl = ftbl_cam_cc_csi0phytimer_clk_src,
+       .clkr.hw.init = &(struct clk_init_data){
+               .name = "cam_cc_csi0phytimer_clk_src",
+               .parent_data = cam_cc_parent_data_0,
+               .num_parents = 4,
+               .ops = &clk_rcg2_ops,
+       },
+};
+
+static struct clk_rcg2 cam_cc_csi1phytimer_clk_src = {
+       .cmd_rcgr = 0x5028,
+       .mnd_width = 0,
+       .hid_width = 5,
+       .parent_map = cam_cc_parent_map_0,
+       .freq_tbl = ftbl_cam_cc_csi0phytimer_clk_src,
+       .clkr.hw.init = &(struct clk_init_data){
+               .name = "cam_cc_csi1phytimer_clk_src",
+               .parent_data = cam_cc_parent_data_0,
+               .num_parents = 4,
+               .ops = &clk_rcg2_ops,
+       },
+};
+
+static struct clk_rcg2 cam_cc_csi2phytimer_clk_src = {
+       .cmd_rcgr = 0x504c,
+       .mnd_width = 0,
+       .hid_width = 5,
+       .parent_map = cam_cc_parent_map_0,
+       .freq_tbl = ftbl_cam_cc_csi0phytimer_clk_src,
+       .clkr.hw.init = &(struct clk_init_data){
+               .name = "cam_cc_csi2phytimer_clk_src",
+               .parent_data = cam_cc_parent_data_0,
+               .num_parents = 4,
+               .ops = &clk_rcg2_ops,
+       },
+};
+
+static struct clk_rcg2 cam_cc_csi3phytimer_clk_src = {
+       .cmd_rcgr = 0x5070,
+       .mnd_width = 0,
+       .hid_width = 5,
+       .parent_map = cam_cc_parent_map_0,
+       .freq_tbl = ftbl_cam_cc_csi0phytimer_clk_src,
+       .clkr.hw.init = &(struct clk_init_data){
+               .name = "cam_cc_csi3phytimer_clk_src",
+               .parent_data = cam_cc_parent_data_0,
+               .num_parents = 4,
+               .ops = &clk_rcg2_ops,
+       },
+};
+
+static const struct freq_tbl ftbl_cam_cc_fast_ahb_clk_src[] = {
+       F(100000000, P_CAM_CC_PLL0_OUT_EVEN, 6, 0, 0),
+       F(200000000, P_CAM_CC_PLL0_OUT_EVEN, 3, 0, 0),
+       F(300000000, P_CAM_CC_PLL0_OUT_EVEN, 2, 0, 0),
+       F(404000000, P_CAM_CC_PLL1_OUT_EVEN, 2, 0, 0),
+       { }
+};
+
+static struct clk_rcg2 cam_cc_fast_ahb_clk_src = {
+       .cmd_rcgr = 0x603c,
+       .mnd_width = 0,
+       .hid_width = 5,
+       .parent_map = cam_cc_parent_map_0,
+       .freq_tbl = ftbl_cam_cc_fast_ahb_clk_src,
+       .clkr.hw.init = &(struct clk_init_data){
+               .name = "cam_cc_fast_ahb_clk_src",
+               .parent_data = cam_cc_parent_data_0,
+               .num_parents = 4,
+               .ops = &clk_rcg2_ops,
+       },
+};
+
+static const struct freq_tbl ftbl_cam_cc_icp_clk_src[] = {
+       F(240000000, P_CAM_CC_PLL0_OUT_EVEN, 2.5, 0, 0),
+       F(360000000, P_CAM_CC_PLL3_OUT_MAIN, 3, 0, 0),
+       F(432000000, P_CAM_CC_PLL3_OUT_MAIN, 2.5, 0, 0),
+       F(480000000, P_CAM_CC_PLL2_OUT_EARLY, 2, 0, 0),
+       F(600000000, P_CAM_CC_PLL0_OUT_EVEN, 1, 0, 0),
+       { }
+};
+
+static struct clk_rcg2 cam_cc_icp_clk_src = {
+       .cmd_rcgr = 0xb088,
+       .mnd_width = 0,
+       .hid_width = 5,
+       .parent_map = cam_cc_parent_map_2,
+       .freq_tbl = ftbl_cam_cc_icp_clk_src,
+       .clkr.hw.init = &(struct clk_init_data){
+               .name = "cam_cc_icp_clk_src",
+               .parent_data = cam_cc_parent_data_2,
+               .num_parents = 5,
+               .ops = &clk_rcg2_ops,
+       },
+};
+
+static const struct freq_tbl ftbl_cam_cc_ife_0_clk_src[] = {
+       F(240000000, P_CAM_CC_PLL0_OUT_EVEN, 2.5, 0, 0),
+       F(360000000, P_CAM_CC_PLL3_OUT_MAIN, 3, 0, 0),
+       F(432000000, P_CAM_CC_PLL3_OUT_MAIN, 2.5, 0, 0),
+       F(600000000, P_CAM_CC_PLL0_OUT_EVEN, 1, 0, 0),
+       { }
+};
+
+static struct clk_rcg2 cam_cc_ife_0_clk_src = {
+       .cmd_rcgr = 0x9010,
+       .mnd_width = 0,
+       .hid_width = 5,
+       .parent_map = cam_cc_parent_map_4,
+       .freq_tbl = ftbl_cam_cc_ife_0_clk_src,
+       .clkr.hw.init = &(struct clk_init_data){
+               .name = "cam_cc_ife_0_clk_src",
+               .parent_data = cam_cc_parent_data_4,
+               .num_parents = 4,
+               .ops = &clk_rcg2_ops,
+       },
+};
+
+static const struct freq_tbl ftbl_cam_cc_ife_0_csid_clk_src[] = {
+       F(150000000, P_CAM_CC_PLL0_OUT_EVEN, 4, 0, 0),
+       F(270000000, P_CAM_CC_PLL3_OUT_MAIN, 4, 0, 0),
+       F(360000000, P_CAM_CC_PLL3_OUT_MAIN, 3, 0, 0),
+       F(480000000, P_CAM_CC_PLL2_OUT_EARLY, 2, 0, 0),
+       { }
+};
+
+static struct clk_rcg2 cam_cc_ife_0_csid_clk_src = {
+       .cmd_rcgr = 0x903c,
+       .mnd_width = 0,
+       .hid_width = 5,
+       .parent_map = cam_cc_parent_map_3,
+       .freq_tbl = ftbl_cam_cc_ife_0_csid_clk_src,
+       .clkr.hw.init = &(struct clk_init_data){
+               .name = "cam_cc_ife_0_csid_clk_src",
+               .parent_data = cam_cc_parent_data_3,
+               .num_parents = 6,
+               .ops = &clk_rcg2_ops,
+       },
+};
+
+static struct clk_rcg2 cam_cc_ife_1_clk_src = {
+       .cmd_rcgr = 0xa010,
+       .mnd_width = 0,
+       .hid_width = 5,
+       .parent_map = cam_cc_parent_map_4,
+       .freq_tbl = ftbl_cam_cc_ife_0_clk_src,
+       .clkr.hw.init = &(struct clk_init_data){
+               .name = "cam_cc_ife_1_clk_src",
+               .parent_data = cam_cc_parent_data_4,
+               .num_parents = 4,
+               .ops = &clk_rcg2_ops,
+       },
+};
+
+static struct clk_rcg2 cam_cc_ife_1_csid_clk_src = {
+       .cmd_rcgr = 0xa034,
+       .mnd_width = 0,
+       .hid_width = 5,
+       .parent_map = cam_cc_parent_map_3,
+       .freq_tbl = ftbl_cam_cc_ife_0_csid_clk_src,
+       .clkr.hw.init = &(struct clk_init_data){
+               .name = "cam_cc_ife_1_csid_clk_src",
+               .parent_data = cam_cc_parent_data_3,
+               .num_parents = 6,
+               .ops = &clk_rcg2_ops,
+       },
+};
+
+static struct clk_rcg2 cam_cc_ife_lite_clk_src = {
+       .cmd_rcgr = 0xb004,
+       .mnd_width = 0,
+       .hid_width = 5,
+       .parent_map = cam_cc_parent_map_4,
+       .freq_tbl = ftbl_cam_cc_ife_0_clk_src,
+       .clkr.hw.init = &(struct clk_init_data){
+               .name = "cam_cc_ife_lite_clk_src",
+               .parent_data = cam_cc_parent_data_4,
+               .num_parents = 4,
+               .flags = CLK_SET_RATE_PARENT,
+               .ops = &clk_rcg2_ops,
+       },
+};
+
+static struct clk_rcg2 cam_cc_ife_lite_csid_clk_src = {
+       .cmd_rcgr = 0xb024,
+       .mnd_width = 0,
+       .hid_width = 5,
+       .parent_map = cam_cc_parent_map_3,
+       .freq_tbl = ftbl_cam_cc_ife_0_csid_clk_src,
+       .clkr.hw.init = &(struct clk_init_data){
+               .name = "cam_cc_ife_lite_csid_clk_src",
+               .parent_data = cam_cc_parent_data_3,
+               .num_parents = 6,
+               .ops = &clk_rcg2_ops,
+       },
+};
+
+static const struct freq_tbl ftbl_cam_cc_ipe_0_clk_src[] = {
+       F(240000000, P_CAM_CC_PLL0_OUT_EVEN, 2.5, 0, 0),
+       F(360000000, P_CAM_CC_PLL3_OUT_MAIN, 3, 0, 0),
+       F(432000000, P_CAM_CC_PLL3_OUT_MAIN, 2.5, 0, 0),
+       F(540000000, P_CAM_CC_PLL3_OUT_MAIN, 2, 0, 0),
+       F(600000000, P_CAM_CC_PLL0_OUT_EVEN, 1, 0, 0),
+       { }
+};
+
+static struct clk_rcg2 cam_cc_ipe_0_clk_src = {
+       .cmd_rcgr = 0x7010,
+       .mnd_width = 0,
+       .hid_width = 5,
+       .parent_map = cam_cc_parent_map_2,
+       .freq_tbl = ftbl_cam_cc_ipe_0_clk_src,
+       .clkr.hw.init = &(struct clk_init_data){
+               .name = "cam_cc_ipe_0_clk_src",
+               .parent_data = cam_cc_parent_data_2,
+               .num_parents = 5,
+               .ops = &clk_rcg2_ops,
+       },
+};
+
+static const struct freq_tbl ftbl_cam_cc_jpeg_clk_src[] = {
+       F(66666667, P_CAM_CC_PLL0_OUT_EVEN, 9, 0, 0),
+       F(133333333, P_CAM_CC_PLL0_OUT_EVEN, 4.5, 0, 0),
+       F(216000000, P_CAM_CC_PLL3_OUT_MAIN, 5, 0, 0),
+       F(320000000, P_CAM_CC_PLL2_OUT_EARLY, 3, 0, 0),
+       F(600000000, P_CAM_CC_PLL0_OUT_EVEN, 1, 0, 0),
+       { }
+};
+
+static struct clk_rcg2 cam_cc_jpeg_clk_src = {
+       .cmd_rcgr = 0xb04c,
+       .mnd_width = 0,
+       .hid_width = 5,
+       .parent_map = cam_cc_parent_map_2,
+       .freq_tbl = ftbl_cam_cc_jpeg_clk_src,
+       .clkr.hw.init = &(struct clk_init_data){
+               .name = "cam_cc_jpeg_clk_src",
+               .parent_data = cam_cc_parent_data_2,
+               .num_parents = 5,
+               .ops = &clk_rcg2_ops,
+       },
+};
+
+static const struct freq_tbl ftbl_cam_cc_lrme_clk_src[] = {
+       F(200000000, P_CAM_CC_PLL0_OUT_EVEN, 3, 0, 0),
+       F(216000000, P_CAM_CC_PLL3_OUT_MAIN, 5, 0, 0),
+       F(300000000, P_CAM_CC_PLL0_OUT_EVEN, 2, 0, 0),
+       F(404000000, P_CAM_CC_PLL1_OUT_EVEN, 2, 0, 0),
+       { }
+};
+
+static struct clk_rcg2 cam_cc_lrme_clk_src = {
+       .cmd_rcgr = 0xb0f8,
+       .mnd_width = 0,
+       .hid_width = 5,
+       .parent_map = cam_cc_parent_map_6,
+       .freq_tbl = ftbl_cam_cc_lrme_clk_src,
+       .clkr.hw.init = &(struct clk_init_data){
+               .name = "cam_cc_lrme_clk_src",
+               .parent_data = cam_cc_parent_data_6,
+               .num_parents = 5,
+               .ops = &clk_rcg2_ops,
+       },
+};
+
+static const struct freq_tbl ftbl_cam_cc_mclk0_clk_src[] = {
+       F(19200000, P_BI_TCXO, 1, 0, 0),
+       F(24000000, P_CAM_CC_PLL2_OUT_AUX, 10, 1, 2),
+       F(64000000, P_CAM_CC_PLL2_OUT_AUX, 7.5, 0, 0),
+       { }
+};
+
+static struct clk_rcg2 cam_cc_mclk0_clk_src = {
+       .cmd_rcgr = 0x4004,
+       .mnd_width = 8,
+       .hid_width = 5,
+       .parent_map = cam_cc_parent_map_1,
+       .freq_tbl = ftbl_cam_cc_mclk0_clk_src,
+       .clkr.hw.init = &(struct clk_init_data){
+               .name = "cam_cc_mclk0_clk_src",
+               .parent_data = cam_cc_parent_data_1,
+               .num_parents = 3,
+               .ops = &clk_rcg2_ops,
+       },
+};
+
+static struct clk_rcg2 cam_cc_mclk1_clk_src = {
+       .cmd_rcgr = 0x4024,
+       .mnd_width = 8,
+       .hid_width = 5,
+       .parent_map = cam_cc_parent_map_1,
+       .freq_tbl = ftbl_cam_cc_mclk0_clk_src,
+       .clkr.hw.init = &(struct clk_init_data){
+               .name = "cam_cc_mclk1_clk_src",
+               .parent_data = cam_cc_parent_data_1,
+               .num_parents = 3,
+               .ops = &clk_rcg2_ops,
+       },
+};
+
+static struct clk_rcg2 cam_cc_mclk2_clk_src = {
+       .cmd_rcgr = 0x4044,
+       .mnd_width = 8,
+       .hid_width = 5,
+       .parent_map = cam_cc_parent_map_1,
+       .freq_tbl = ftbl_cam_cc_mclk0_clk_src,
+       .clkr.hw.init = &(struct clk_init_data){
+               .name = "cam_cc_mclk2_clk_src",
+               .parent_data = cam_cc_parent_data_1,
+               .num_parents = 3,
+               .ops = &clk_rcg2_ops,
+       },
+};
+
+static struct clk_rcg2 cam_cc_mclk3_clk_src = {
+       .cmd_rcgr = 0x4064,
+       .mnd_width = 8,
+       .hid_width = 5,
+       .parent_map = cam_cc_parent_map_1,
+       .freq_tbl = ftbl_cam_cc_mclk0_clk_src,
+       .clkr.hw.init = &(struct clk_init_data){
+               .name = "cam_cc_mclk3_clk_src",
+               .parent_data = cam_cc_parent_data_1,
+               .num_parents = 3,
+               .ops = &clk_rcg2_ops,
+       },
+};
+
+static struct clk_rcg2 cam_cc_mclk4_clk_src = {
+       .cmd_rcgr = 0x4084,
+       .mnd_width = 8,
+       .hid_width = 5,
+       .parent_map = cam_cc_parent_map_1,
+       .freq_tbl = ftbl_cam_cc_mclk0_clk_src,
+       .clkr.hw.init = &(struct clk_init_data){
+               .name = "cam_cc_mclk4_clk_src",
+               .parent_data = cam_cc_parent_data_1,
+               .num_parents = 3,
+               .ops = &clk_rcg2_ops,
+       },
+};
+
+static const struct freq_tbl ftbl_cam_cc_slow_ahb_clk_src[] = {
+       F(80000000, P_CAM_CC_PLL0_OUT_EVEN, 7.5, 0, 0),
+       { }
+};
+
+static struct clk_rcg2 cam_cc_slow_ahb_clk_src = {
+       .cmd_rcgr = 0x6058,
+       .mnd_width = 0,
+       .hid_width = 5,
+       .parent_map = cam_cc_parent_map_0,
+       .freq_tbl = ftbl_cam_cc_slow_ahb_clk_src,
+       .clkr.hw.init = &(struct clk_init_data){
+               .name = "cam_cc_slow_ahb_clk_src",
+               .parent_data = cam_cc_parent_data_0,
+               .num_parents = 4,
+               .flags = CLK_SET_RATE_PARENT | CLK_OPS_PARENT_ENABLE,
+               .ops = &clk_rcg2_ops,
+       },
+};
+
+static struct clk_branch cam_cc_bps_ahb_clk = {
+       .halt_reg = 0x6070,
+       .halt_check = BRANCH_HALT,
+       .clkr = {
+               .enable_reg = 0x6070,
+               .enable_mask = BIT(0),
+               .hw.init = &(struct clk_init_data){
+                       .name = "cam_cc_bps_ahb_clk",
+                       .parent_data = &(const struct clk_parent_data){
+                               .hw = &cam_cc_slow_ahb_clk_src.clkr.hw,
+                       },
+                       .num_parents = 1,
+                       .flags = CLK_SET_RATE_PARENT,
+                       .ops = &clk_branch2_ops,
+               },
+       },
+};
+
+static struct clk_branch cam_cc_bps_areg_clk = {
+       .halt_reg = 0x6054,
+       .halt_check = BRANCH_HALT,
+       .clkr = {
+               .enable_reg = 0x6054,
+               .enable_mask = BIT(0),
+               .hw.init = &(struct clk_init_data){
+                       .name = "cam_cc_bps_areg_clk",
+                       .parent_data = &(const struct clk_parent_data){
+                               .hw = &cam_cc_fast_ahb_clk_src.clkr.hw,
+                       },
+                       .num_parents = 1,
+                       .flags = CLK_SET_RATE_PARENT,
+                       .ops = &clk_branch2_ops,
+               },
+       },
+};
+
+static struct clk_branch cam_cc_bps_axi_clk = {
+       .halt_reg = 0x6038,
+       .halt_check = BRANCH_HALT,
+       .clkr = {
+               .enable_reg = 0x6038,
+               .enable_mask = BIT(0),
+               .hw.init = &(struct clk_init_data){
+                       .name = "cam_cc_bps_axi_clk",
+                       .ops = &clk_branch2_ops,
+               },
+       },
+};
+
+static struct clk_branch cam_cc_bps_clk = {
+       .halt_reg = 0x6028,
+       .halt_check = BRANCH_HALT,
+       .clkr = {
+               .enable_reg = 0x6028,
+               .enable_mask = BIT(0),
+               .hw.init = &(struct clk_init_data){
+                       .name = "cam_cc_bps_clk",
+                       .parent_data = &(const struct clk_parent_data){
+                               .hw = &cam_cc_bps_clk_src.clkr.hw,
+                       },
+                       .num_parents = 1,
+                       .flags = CLK_SET_RATE_PARENT,
+                       .ops = &clk_branch2_ops,
+               },
+       },
+};
+
+static struct clk_branch cam_cc_camnoc_axi_clk = {
+       .halt_reg = 0xb124,
+       .halt_check = BRANCH_HALT,
+       .clkr = {
+               .enable_reg = 0xb124,
+               .enable_mask = BIT(0),
+               .hw.init = &(struct clk_init_data){
+                       .name = "cam_cc_camnoc_axi_clk",
+                       .ops = &clk_branch2_ops,
+               },
+       },
+};
+
+static struct clk_branch cam_cc_cci_0_clk = {
+       .halt_reg = 0xb0f0,
+       .halt_check = BRANCH_HALT,
+       .clkr = {
+               .enable_reg = 0xb0f0,
+               .enable_mask = BIT(0),
+               .hw.init = &(struct clk_init_data){
+                       .name = "cam_cc_cci_0_clk",
+                       .parent_data = &(const struct clk_parent_data){
+                               .hw = &cam_cc_cci_0_clk_src.clkr.hw,
+                       },
+                       .num_parents = 1,
+                       .flags = CLK_SET_RATE_PARENT,
+                       .ops = &clk_branch2_ops,
+               },
+       },
+};
+
+static struct clk_branch cam_cc_cci_1_clk = {
+       .halt_reg = 0xb164,
+       .halt_check = BRANCH_HALT,
+       .clkr = {
+               .enable_reg = 0xb164,
+               .enable_mask = BIT(0),
+               .hw.init = &(struct clk_init_data){
+                       .name = "cam_cc_cci_1_clk",
+                       .parent_data = &(const struct clk_parent_data){
+                               .hw = &cam_cc_cci_1_clk_src.clkr.hw,
+                       },
+                       .num_parents = 1,
+                       .flags = CLK_SET_RATE_PARENT,
+                       .ops = &clk_branch2_ops,
+               },
+       },
+};
+
+static struct clk_branch cam_cc_core_ahb_clk = {
+       .halt_reg = 0xb144,
+       .halt_check = BRANCH_HALT_DELAY,
+       .clkr = {
+               .enable_reg = 0xb144,
+               .enable_mask = BIT(0),
+               .hw.init = &(struct clk_init_data){
+                       .name = "cam_cc_core_ahb_clk",
+                       .parent_data = &(const struct clk_parent_data){
+                               .hw = &cam_cc_slow_ahb_clk_src.clkr.hw,
+                       },
+                       .num_parents = 1,
+                       .flags = CLK_SET_RATE_PARENT,
+                       .ops = &clk_branch2_ops,
+               },
+       },
+};
+
+static struct clk_branch cam_cc_cpas_ahb_clk = {
+       .halt_reg = 0xb11c,
+       .halt_check = BRANCH_HALT,
+       .clkr = {
+               .enable_reg = 0xb11c,
+               .enable_mask = BIT(0),
+               .hw.init = &(struct clk_init_data){
+                       .name = "cam_cc_cpas_ahb_clk",
+                       .parent_data = &(const struct clk_parent_data){
+                               .hw = &cam_cc_slow_ahb_clk_src.clkr.hw,
+                       },
+                       .num_parents = 1,
+                       .flags = CLK_SET_RATE_PARENT,
+                       .ops = &clk_branch2_ops,
+               },
+       },
+};
+
+static struct clk_branch cam_cc_csi0phytimer_clk = {
+       .halt_reg = 0x501c,
+       .halt_check = BRANCH_HALT,
+       .clkr = {
+               .enable_reg = 0x501c,
+               .enable_mask = BIT(0),
+               .hw.init = &(struct clk_init_data){
+                       .name = "cam_cc_csi0phytimer_clk",
+                       .parent_data = &(const struct clk_parent_data){
+                               .hw = &cam_cc_csi0phytimer_clk_src.clkr.hw,
+                       },
+                       .num_parents = 1,
+                       .flags = CLK_SET_RATE_PARENT,
+                       .ops = &clk_branch2_ops,
+               },
+       },
+};
+
+static struct clk_branch cam_cc_csi1phytimer_clk = {
+       .halt_reg = 0x5040,
+       .halt_check = BRANCH_HALT,
+       .clkr = {
+               .enable_reg = 0x5040,
+               .enable_mask = BIT(0),
+               .hw.init = &(struct clk_init_data){
+                       .name = "cam_cc_csi1phytimer_clk",
+                       .parent_data = &(const struct clk_parent_data){
+                               .hw = &cam_cc_csi1phytimer_clk_src.clkr.hw,
+                       },
+                       .num_parents = 1,
+                       .flags = CLK_SET_RATE_PARENT,
+                       .ops = &clk_branch2_ops,
+               },
+       },
+};
+
+static struct clk_branch cam_cc_csi2phytimer_clk = {
+       .halt_reg = 0x5064,
+       .halt_check = BRANCH_HALT,
+       .clkr = {
+               .enable_reg = 0x5064,
+               .enable_mask = BIT(0),
+               .hw.init = &(struct clk_init_data){
+                       .name = "cam_cc_csi2phytimer_clk",
+                       .parent_data = &(const struct clk_parent_data){
+                               .hw = &cam_cc_csi2phytimer_clk_src.clkr.hw,
+                       },
+                       .num_parents = 1,
+                       .flags = CLK_SET_RATE_PARENT,
+                       .ops = &clk_branch2_ops,
+               },
+       },
+};
+
+static struct clk_branch cam_cc_csi3phytimer_clk = {
+       .halt_reg = 0x5088,
+       .halt_check = BRANCH_HALT,
+       .clkr = {
+               .enable_reg = 0x5088,
+               .enable_mask = BIT(0),
+               .hw.init = &(struct clk_init_data){
+                       .name = "cam_cc_csi3phytimer_clk",
+                       .parent_data = &(const struct clk_parent_data){
+                               .hw = &cam_cc_csi3phytimer_clk_src.clkr.hw,
+                       },
+                       .num_parents = 1,
+                       .flags = CLK_SET_RATE_PARENT,
+                       .ops = &clk_branch2_ops,
+               },
+       },
+};
+
+static struct clk_branch cam_cc_csiphy0_clk = {
+       .halt_reg = 0x5020,
+       .halt_check = BRANCH_HALT,
+       .clkr = {
+               .enable_reg = 0x5020,
+               .enable_mask = BIT(0),
+               .hw.init = &(struct clk_init_data){
+                       .name = "cam_cc_csiphy0_clk",
+                       .parent_data = &(const struct clk_parent_data){
+                               .hw = &cam_cc_cphy_rx_clk_src.clkr.hw,
+                       },
+                       .num_parents = 1,
+                       .flags = CLK_SET_RATE_PARENT,
+                       .ops = &clk_branch2_ops,
+               },
+       },
+};
+
+static struct clk_branch cam_cc_csiphy1_clk = {
+       .halt_reg = 0x5044,
+       .halt_check = BRANCH_HALT,
+       .clkr = {
+               .enable_reg = 0x5044,
+               .enable_mask = BIT(0),
+               .hw.init = &(struct clk_init_data){
+                       .name = "cam_cc_csiphy1_clk",
+                       .parent_data = &(const struct clk_parent_data){
+                               .hw = &cam_cc_cphy_rx_clk_src.clkr.hw,
+                       },
+                       .num_parents = 1,
+                       .flags = CLK_SET_RATE_PARENT,
+                       .ops = &clk_branch2_ops,
+               },
+       },
+};
+
+static struct clk_branch cam_cc_csiphy2_clk = {
+       .halt_reg = 0x5068,
+       .halt_check = BRANCH_HALT,
+       .clkr = {
+               .enable_reg = 0x5068,
+               .enable_mask = BIT(0),
+               .hw.init = &(struct clk_init_data){
+                       .name = "cam_cc_csiphy2_clk",
+                       .parent_data = &(const struct clk_parent_data){
+                               .hw = &cam_cc_cphy_rx_clk_src.clkr.hw,
+                       },
+                       .num_parents = 1,
+                       .flags = CLK_SET_RATE_PARENT,
+                       .ops = &clk_branch2_ops,
+               },
+       },
+};
+
+static struct clk_branch cam_cc_csiphy3_clk = {
+       .halt_reg = 0x508c,
+       .halt_check = BRANCH_HALT,
+       .clkr = {
+               .enable_reg = 0x508c,
+               .enable_mask = BIT(0),
+               .hw.init = &(struct clk_init_data){
+                       .name = "cam_cc_csiphy3_clk",
+                       .parent_data = &(const struct clk_parent_data){
+                               .hw = &cam_cc_cphy_rx_clk_src.clkr.hw,
+                       },
+                       .num_parents = 1,
+                       .flags = CLK_SET_RATE_PARENT,
+                       .ops = &clk_branch2_ops,
+               },
+       },
+};
+
+static struct clk_branch cam_cc_icp_clk = {
+       .halt_reg = 0xb0a0,
+       .halt_check = BRANCH_HALT,
+       .clkr = {
+               .enable_reg = 0xb0a0,
+               .enable_mask = BIT(0),
+               .hw.init = &(struct clk_init_data){
+                       .name = "cam_cc_icp_clk",
+                       .parent_data = &(const struct clk_parent_data){
+                               .hw = &cam_cc_icp_clk_src.clkr.hw,
+                       },
+                       .num_parents = 1,
+                       .flags = CLK_SET_RATE_PARENT,
+                       .ops = &clk_branch2_ops,
+               },
+       },
+};
+
+static struct clk_branch cam_cc_ife_0_axi_clk = {
+       .halt_reg = 0x9080,
+       .halt_check = BRANCH_HALT,
+       .clkr = {
+               .enable_reg = 0x9080,
+               .enable_mask = BIT(0),
+               .hw.init = &(struct clk_init_data){
+                       .name = "cam_cc_ife_0_axi_clk",
+                       .ops = &clk_branch2_ops,
+               },
+       },
+};
+
+static struct clk_branch cam_cc_ife_0_clk = {
+       .halt_reg = 0x9028,
+       .halt_check = BRANCH_HALT,
+       .clkr = {
+               .enable_reg = 0x9028,
+               .enable_mask = BIT(0),
+               .hw.init = &(struct clk_init_data){
+                       .name = "cam_cc_ife_0_clk",
+                       .parent_data = &(const struct clk_parent_data){
+                               .hw = &cam_cc_ife_0_clk_src.clkr.hw,
+                       },
+                       .num_parents = 1,
+                       .flags = CLK_SET_RATE_PARENT,
+                       .ops = &clk_branch2_ops,
+               },
+       },
+};
+
+static struct clk_branch cam_cc_ife_0_cphy_rx_clk = {
+       .halt_reg = 0x907c,
+       .halt_check = BRANCH_HALT,
+       .clkr = {
+               .enable_reg = 0x907c,
+               .enable_mask = BIT(0),
+               .hw.init = &(struct clk_init_data){
+                       .name = "cam_cc_ife_0_cphy_rx_clk",
+                       .parent_data = &(const struct clk_parent_data){
+                               .hw = &cam_cc_cphy_rx_clk_src.clkr.hw,
+                       },
+                       .num_parents = 1,
+                       .flags = CLK_SET_RATE_PARENT,
+                       .ops = &clk_branch2_ops,
+               },
+       },
+};
+
+static struct clk_branch cam_cc_ife_0_csid_clk = {
+       .halt_reg = 0x9054,
+       .halt_check = BRANCH_HALT,
+       .clkr = {
+               .enable_reg = 0x9054,
+               .enable_mask = BIT(0),
+               .hw.init = &(struct clk_init_data){
+                       .name = "cam_cc_ife_0_csid_clk",
+                       .parent_data = &(const struct clk_parent_data){
+                               .hw = &cam_cc_ife_0_csid_clk_src.clkr.hw,
+                       },
+                       .num_parents = 1,
+                       .flags = CLK_SET_RATE_PARENT,
+                       .ops = &clk_branch2_ops,
+               },
+       },
+};
+
+static struct clk_branch cam_cc_ife_0_dsp_clk = {
+       .halt_reg = 0x9038,
+       .halt_check = BRANCH_HALT,
+       .clkr = {
+               .enable_reg = 0x9038,
+               .enable_mask = BIT(0),
+               .hw.init = &(struct clk_init_data){
+                       .name = "cam_cc_ife_0_dsp_clk",
+                       .parent_data = &(const struct clk_parent_data){
+                               .hw = &cam_cc_ife_0_clk_src.clkr.hw,
+                       },
+                       .num_parents = 1,
+                       .flags = CLK_SET_RATE_PARENT,
+                       .ops = &clk_branch2_ops,
+               },
+       },
+};
+
+static struct clk_branch cam_cc_ife_1_axi_clk = {
+       .halt_reg = 0xa058,
+       .halt_check = BRANCH_HALT,
+       .clkr = {
+               .enable_reg = 0xa058,
+               .enable_mask = BIT(0),
+               .hw.init = &(struct clk_init_data){
+                       .name = "cam_cc_ife_1_axi_clk",
+                       .ops = &clk_branch2_ops,
+               },
+       },
+};
+
+static struct clk_branch cam_cc_ife_1_clk = {
+       .halt_reg = 0xa028,
+       .halt_check = BRANCH_HALT,
+       .clkr = {
+               .enable_reg = 0xa028,
+               .enable_mask = BIT(0),
+               .hw.init = &(struct clk_init_data){
+                       .name = "cam_cc_ife_1_clk",
+                       .parent_data = &(const struct clk_parent_data){
+                               .hw = &cam_cc_ife_1_clk_src.clkr.hw,
+                       },
+                       .num_parents = 1,
+                       .flags = CLK_SET_RATE_PARENT,
+                       .ops = &clk_branch2_ops,
+               },
+       },
+};
+
+static struct clk_branch cam_cc_ife_1_cphy_rx_clk = {
+       .halt_reg = 0xa054,
+       .halt_check = BRANCH_HALT,
+       .clkr = {
+               .enable_reg = 0xa054,
+               .enable_mask = BIT(0),
+               .hw.init = &(struct clk_init_data){
+                       .name = "cam_cc_ife_1_cphy_rx_clk",
+                       .parent_data = &(const struct clk_parent_data){
+                               .hw = &cam_cc_cphy_rx_clk_src.clkr.hw,
+                       },
+                       .num_parents = 1,
+                       .flags = CLK_SET_RATE_PARENT,
+                       .ops = &clk_branch2_ops,
+               },
+       },
+};
+
+static struct clk_branch cam_cc_ife_1_csid_clk = {
+       .halt_reg = 0xa04c,
+       .halt_check = BRANCH_HALT,
+       .clkr = {
+               .enable_reg = 0xa04c,
+               .enable_mask = BIT(0),
+               .hw.init = &(struct clk_init_data){
+                       .name = "cam_cc_ife_1_csid_clk",
+                       .parent_data = &(const struct clk_parent_data){
+                               .hw = &cam_cc_ife_1_csid_clk_src.clkr.hw,
+                       },
+                       .num_parents = 1,
+                       .flags = CLK_SET_RATE_PARENT,
+                       .ops = &clk_branch2_ops,
+               },
+       },
+};
+
+static struct clk_branch cam_cc_ife_1_dsp_clk = {
+       .halt_reg = 0xa030,
+       .halt_check = BRANCH_HALT,
+       .clkr = {
+               .enable_reg = 0xa030,
+               .enable_mask = BIT(0),
+               .hw.init = &(struct clk_init_data){
+                       .name = "cam_cc_ife_1_dsp_clk",
+                       .parent_data = &(const struct clk_parent_data){
+                               .hw = &cam_cc_ife_1_clk_src.clkr.hw,
+                       },
+                       .num_parents = 1,
+                       .flags = CLK_SET_RATE_PARENT,
+                       .ops = &clk_branch2_ops,
+               },
+       },
+};
+
+static struct clk_branch cam_cc_ife_lite_clk = {
+       .halt_reg = 0xb01c,
+       .halt_check = BRANCH_HALT,
+       .clkr = {
+               .enable_reg = 0xb01c,
+               .enable_mask = BIT(0),
+               .hw.init = &(struct clk_init_data){
+                       .name = "cam_cc_ife_lite_clk",
+                       .parent_data = &(const struct clk_parent_data){
+                               .hw = &cam_cc_ife_lite_clk_src.clkr.hw,
+                       },
+                       .num_parents = 1,
+                       .flags = CLK_SET_RATE_PARENT,
+                       .ops = &clk_branch2_ops,
+               },
+       },
+};
+
+static struct clk_branch cam_cc_ife_lite_cphy_rx_clk = {
+       .halt_reg = 0xb044,
+       .halt_check = BRANCH_HALT,
+       .clkr = {
+               .enable_reg = 0xb044,
+               .enable_mask = BIT(0),
+               .hw.init = &(struct clk_init_data){
+                       .name = "cam_cc_ife_lite_cphy_rx_clk",
+                       .parent_data = &(const struct clk_parent_data){
+                               .hw = &cam_cc_cphy_rx_clk_src.clkr.hw,
+                       },
+                       .num_parents = 1,
+                       .flags = CLK_SET_RATE_PARENT,
+                       .ops = &clk_branch2_ops,
+               },
+       },
+};
+
+static struct clk_branch cam_cc_ife_lite_csid_clk = {
+       .halt_reg = 0xb03c,
+       .halt_check = BRANCH_HALT,
+       .clkr = {
+               .enable_reg = 0xb03c,
+               .enable_mask = BIT(0),
+               .hw.init = &(struct clk_init_data){
+                       .name = "cam_cc_ife_lite_csid_clk",
+                       .parent_data = &(const struct clk_parent_data){
+                               .hw = &cam_cc_ife_lite_csid_clk_src.clkr.hw,
+                       },
+                       .num_parents = 1,
+                       .flags = CLK_SET_RATE_PARENT,
+                       .ops = &clk_branch2_ops,
+               },
+       },
+};
+
+static struct clk_branch cam_cc_ipe_0_ahb_clk = {
+       .halt_reg = 0x7040,
+       .halt_check = BRANCH_HALT,
+       .clkr = {
+               .enable_reg = 0x7040,
+               .enable_mask = BIT(0),
+               .hw.init = &(struct clk_init_data){
+                       .name = "cam_cc_ipe_0_ahb_clk",
+                       .parent_data = &(const struct clk_parent_data){
+                               .hw = &cam_cc_slow_ahb_clk_src.clkr.hw,
+                       },
+                       .num_parents = 1,
+                       .flags = CLK_SET_RATE_PARENT,
+                       .ops = &clk_branch2_ops,
+               },
+       },
+};
+
+static struct clk_branch cam_cc_ipe_0_areg_clk = {
+       .halt_reg = 0x703c,
+       .halt_check = BRANCH_HALT,
+       .clkr = {
+               .enable_reg = 0x703c,
+               .enable_mask = BIT(0),
+               .hw.init = &(struct clk_init_data){
+                       .name = "cam_cc_ipe_0_areg_clk",
+                       .parent_data = &(const struct clk_parent_data){
+                               .hw = &cam_cc_fast_ahb_clk_src.clkr.hw,
+                       },
+                       .num_parents = 1,
+                       .flags = CLK_SET_RATE_PARENT,
+                       .ops = &clk_branch2_ops,
+               },
+       },
+};
+
+static struct clk_branch cam_cc_ipe_0_axi_clk = {
+       .halt_reg = 0x7038,
+       .halt_check = BRANCH_HALT,
+       .clkr = {
+               .enable_reg = 0x7038,
+               .enable_mask = BIT(0),
+               .hw.init = &(struct clk_init_data){
+                       .name = "cam_cc_ipe_0_axi_clk",
+                       .ops = &clk_branch2_ops,
+               },
+       },
+};
+
+static struct clk_branch cam_cc_ipe_0_clk = {
+       .halt_reg = 0x7028,
+       .halt_check = BRANCH_HALT,
+       .clkr = {
+               .enable_reg = 0x7028,
+               .enable_mask = BIT(0),
+               .hw.init = &(struct clk_init_data){
+                       .name = "cam_cc_ipe_0_clk",
+                       .parent_data = &(const struct clk_parent_data){
+                               .hw = &cam_cc_ipe_0_clk_src.clkr.hw,
+                       },
+                       .num_parents = 1,
+                       .flags = CLK_SET_RATE_PARENT,
+                       .ops = &clk_branch2_ops,
+               },
+       },
+};
+
+static struct clk_branch cam_cc_jpeg_clk = {
+       .halt_reg = 0xb064,
+       .halt_check = BRANCH_HALT,
+       .clkr = {
+               .enable_reg = 0xb064,
+               .enable_mask = BIT(0),
+               .hw.init = &(struct clk_init_data){
+                       .name = "cam_cc_jpeg_clk",
+                       .parent_data = &(const struct clk_parent_data){
+                               .hw = &cam_cc_jpeg_clk_src.clkr.hw,
+                       },
+                       .num_parents = 1,
+                       .flags = CLK_SET_RATE_PARENT,
+                       .ops = &clk_branch2_ops,
+               },
+       },
+};
+
+static struct clk_branch cam_cc_lrme_clk = {
+       .halt_reg = 0xb110,
+       .halt_check = BRANCH_HALT,
+       .clkr = {
+               .enable_reg = 0xb110,
+               .enable_mask = BIT(0),
+               .hw.init = &(struct clk_init_data){
+                       .name = "cam_cc_lrme_clk",
+                       .parent_data = &(const struct clk_parent_data){
+                               .hw = &cam_cc_lrme_clk_src.clkr.hw,
+                       },
+                       .num_parents = 1,
+                       .flags = CLK_SET_RATE_PARENT,
+                       .ops = &clk_branch2_ops,
+               },
+       },
+};
+
+static struct clk_branch cam_cc_mclk0_clk = {
+       .halt_reg = 0x401c,
+       .halt_check = BRANCH_HALT,
+       .clkr = {
+               .enable_reg = 0x401c,
+               .enable_mask = BIT(0),
+               .hw.init = &(struct clk_init_data){
+                       .name = "cam_cc_mclk0_clk",
+                       .parent_data = &(const struct clk_parent_data){
+                               .hw = &cam_cc_mclk0_clk_src.clkr.hw,
+                       },
+                       .num_parents = 1,
+                       .flags = CLK_SET_RATE_PARENT,
+                       .ops = &clk_branch2_ops,
+               },
+       },
+};
+
+static struct clk_branch cam_cc_mclk1_clk = {
+       .halt_reg = 0x403c,
+       .halt_check = BRANCH_HALT,
+       .clkr = {
+               .enable_reg = 0x403c,
+               .enable_mask = BIT(0),
+               .hw.init = &(struct clk_init_data){
+                       .name = "cam_cc_mclk1_clk",
+                       .parent_data = &(const struct clk_parent_data){
+                               .hw = &cam_cc_mclk1_clk_src.clkr.hw,
+                       },
+                       .num_parents = 1,
+                       .flags = CLK_SET_RATE_PARENT,
+                       .ops = &clk_branch2_ops,
+               },
+       },
+};
+
+static struct clk_branch cam_cc_mclk2_clk = {
+       .halt_reg = 0x405c,
+       .halt_check = BRANCH_HALT,
+       .clkr = {
+               .enable_reg = 0x405c,
+               .enable_mask = BIT(0),
+               .hw.init = &(struct clk_init_data){
+                       .name = "cam_cc_mclk2_clk",
+                       .parent_data = &(const struct clk_parent_data){
+                               .hw = &cam_cc_mclk2_clk_src.clkr.hw,
+                       },
+                       .num_parents = 1,
+                       .flags = CLK_SET_RATE_PARENT,
+                       .ops = &clk_branch2_ops,
+               },
+       },
+};
+
+static struct clk_branch cam_cc_mclk3_clk = {
+       .halt_reg = 0x407c,
+       .halt_check = BRANCH_HALT,
+       .clkr = {
+               .enable_reg = 0x407c,
+               .enable_mask = BIT(0),
+               .hw.init = &(struct clk_init_data){
+                       .name = "cam_cc_mclk3_clk",
+                       .parent_data = &(const struct clk_parent_data){
+                               .hw = &cam_cc_mclk3_clk_src.clkr.hw,
+                       },
+                       .num_parents = 1,
+                       .flags = CLK_SET_RATE_PARENT,
+                       .ops = &clk_branch2_ops,
+               },
+       },
+};
+
+static struct clk_branch cam_cc_mclk4_clk = {
+       .halt_reg = 0x409c,
+       .halt_check = BRANCH_HALT,
+       .clkr = {
+               .enable_reg = 0x409c,
+               .enable_mask = BIT(0),
+               .hw.init = &(struct clk_init_data){
+                       .name = "cam_cc_mclk4_clk",
+                       .parent_data = &(const struct clk_parent_data){
+                               .hw = &cam_cc_mclk4_clk_src.clkr.hw,
+                       },
+                       .num_parents = 1,
+                       .flags = CLK_SET_RATE_PARENT,
+                       .ops = &clk_branch2_ops,
+               },
+       },
+};
+
+static struct clk_branch cam_cc_soc_ahb_clk = {
+       .halt_reg = 0xb140,
+       .halt_check = BRANCH_HALT,
+       .clkr = {
+               .enable_reg = 0xb140,
+               .enable_mask = BIT(0),
+               .hw.init = &(struct clk_init_data){
+                       .name = "cam_cc_soc_ahb_clk",
+                       .ops = &clk_branch2_ops,
+               },
+       },
+};
+
+static struct clk_branch cam_cc_sys_tmr_clk = {
+       .halt_reg = 0xb0a8,
+       .halt_check = BRANCH_HALT,
+       .clkr = {
+               .enable_reg = 0xb0a8,
+               .enable_mask = BIT(0),
+               .hw.init = &(struct clk_init_data){
+                       .name = "cam_cc_sys_tmr_clk",
+                       .ops = &clk_branch2_ops,
+               },
+       },
+};
+
+static struct gdsc bps_gdsc = {
+       .gdscr = 0x6004,
+       .pd = {
+               .name = "bps_gdsc",
+       },
+       .pwrsts = PWRSTS_OFF_ON,
+       .flags = HW_CTRL,
+};
+
+static struct gdsc ife_0_gdsc = {
+       .gdscr = 0x9004,
+       .pd = {
+               .name = "ife_0_gdsc",
+       },
+       .pwrsts = PWRSTS_OFF_ON,
+};
+
+static struct gdsc ife_1_gdsc = {
+       .gdscr = 0xa004,
+       .pd = {
+               .name = "ife_1_gdsc",
+       },
+       .pwrsts = PWRSTS_OFF_ON,
+};
+
+static struct gdsc ipe_0_gdsc = {
+       .gdscr = 0x7004,
+       .pd = {
+               .name = "ipe_0_gdsc",
+       },
+       .pwrsts = PWRSTS_OFF_ON,
+       .flags = HW_CTRL,
+};
+
+static struct gdsc titan_top_gdsc = {
+       .gdscr = 0xb134,
+       .pd = {
+               .name = "titan_top_gdsc",
+       },
+       .pwrsts = PWRSTS_OFF_ON,
+};
+
+static struct clk_hw *cam_cc_sc7180_hws[] = {
+       [CAM_CC_PLL2_OUT_EARLY] = &cam_cc_pll2_out_early.hw,
+};
+
+static struct clk_regmap *cam_cc_sc7180_clocks[] = {
+       [CAM_CC_BPS_AHB_CLK] = &cam_cc_bps_ahb_clk.clkr,
+       [CAM_CC_BPS_AREG_CLK] = &cam_cc_bps_areg_clk.clkr,
+       [CAM_CC_BPS_AXI_CLK] = &cam_cc_bps_axi_clk.clkr,
+       [CAM_CC_BPS_CLK] = &cam_cc_bps_clk.clkr,
+       [CAM_CC_BPS_CLK_SRC] = &cam_cc_bps_clk_src.clkr,
+       [CAM_CC_CAMNOC_AXI_CLK] = &cam_cc_camnoc_axi_clk.clkr,
+       [CAM_CC_CCI_0_CLK] = &cam_cc_cci_0_clk.clkr,
+       [CAM_CC_CCI_0_CLK_SRC] = &cam_cc_cci_0_clk_src.clkr,
+       [CAM_CC_CCI_1_CLK] = &cam_cc_cci_1_clk.clkr,
+       [CAM_CC_CCI_1_CLK_SRC] = &cam_cc_cci_1_clk_src.clkr,
+       [CAM_CC_CORE_AHB_CLK] = &cam_cc_core_ahb_clk.clkr,
+       [CAM_CC_CPAS_AHB_CLK] = &cam_cc_cpas_ahb_clk.clkr,
+       [CAM_CC_CPHY_RX_CLK_SRC] = &cam_cc_cphy_rx_clk_src.clkr,
+       [CAM_CC_CSI0PHYTIMER_CLK] = &cam_cc_csi0phytimer_clk.clkr,
+       [CAM_CC_CSI0PHYTIMER_CLK_SRC] = &cam_cc_csi0phytimer_clk_src.clkr,
+       [CAM_CC_CSI1PHYTIMER_CLK] = &cam_cc_csi1phytimer_clk.clkr,
+       [CAM_CC_CSI1PHYTIMER_CLK_SRC] = &cam_cc_csi1phytimer_clk_src.clkr,
+       [CAM_CC_CSI2PHYTIMER_CLK] = &cam_cc_csi2phytimer_clk.clkr,
+       [CAM_CC_CSI2PHYTIMER_CLK_SRC] = &cam_cc_csi2phytimer_clk_src.clkr,
+       [CAM_CC_CSI3PHYTIMER_CLK] = &cam_cc_csi3phytimer_clk.clkr,
+       [CAM_CC_CSI3PHYTIMER_CLK_SRC] = &cam_cc_csi3phytimer_clk_src.clkr,
+       [CAM_CC_CSIPHY0_CLK] = &cam_cc_csiphy0_clk.clkr,
+       [CAM_CC_CSIPHY1_CLK] = &cam_cc_csiphy1_clk.clkr,
+       [CAM_CC_CSIPHY2_CLK] = &cam_cc_csiphy2_clk.clkr,
+       [CAM_CC_CSIPHY3_CLK] = &cam_cc_csiphy3_clk.clkr,
+       [CAM_CC_FAST_AHB_CLK_SRC] = &cam_cc_fast_ahb_clk_src.clkr,
+       [CAM_CC_ICP_CLK] = &cam_cc_icp_clk.clkr,
+       [CAM_CC_ICP_CLK_SRC] = &cam_cc_icp_clk_src.clkr,
+       [CAM_CC_IFE_0_AXI_CLK] = &cam_cc_ife_0_axi_clk.clkr,
+       [CAM_CC_IFE_0_CLK] = &cam_cc_ife_0_clk.clkr,
+       [CAM_CC_IFE_0_CLK_SRC] = &cam_cc_ife_0_clk_src.clkr,
+       [CAM_CC_IFE_0_CPHY_RX_CLK] = &cam_cc_ife_0_cphy_rx_clk.clkr,
+       [CAM_CC_IFE_0_CSID_CLK] = &cam_cc_ife_0_csid_clk.clkr,
+       [CAM_CC_IFE_0_CSID_CLK_SRC] = &cam_cc_ife_0_csid_clk_src.clkr,
+       [CAM_CC_IFE_0_DSP_CLK] = &cam_cc_ife_0_dsp_clk.clkr,
+       [CAM_CC_IFE_1_AXI_CLK] = &cam_cc_ife_1_axi_clk.clkr,
+       [CAM_CC_IFE_1_CLK] = &cam_cc_ife_1_clk.clkr,
+       [CAM_CC_IFE_1_CLK_SRC] = &cam_cc_ife_1_clk_src.clkr,
+       [CAM_CC_IFE_1_CPHY_RX_CLK] = &cam_cc_ife_1_cphy_rx_clk.clkr,
+       [CAM_CC_IFE_1_CSID_CLK] = &cam_cc_ife_1_csid_clk.clkr,
+       [CAM_CC_IFE_1_CSID_CLK_SRC] = &cam_cc_ife_1_csid_clk_src.clkr,
+       [CAM_CC_IFE_1_DSP_CLK] = &cam_cc_ife_1_dsp_clk.clkr,
+       [CAM_CC_IFE_LITE_CLK] = &cam_cc_ife_lite_clk.clkr,
+       [CAM_CC_IFE_LITE_CLK_SRC] = &cam_cc_ife_lite_clk_src.clkr,
+       [CAM_CC_IFE_LITE_CPHY_RX_CLK] = &cam_cc_ife_lite_cphy_rx_clk.clkr,
+       [CAM_CC_IFE_LITE_CSID_CLK] = &cam_cc_ife_lite_csid_clk.clkr,
+       [CAM_CC_IFE_LITE_CSID_CLK_SRC] = &cam_cc_ife_lite_csid_clk_src.clkr,
+       [CAM_CC_IPE_0_AHB_CLK] = &cam_cc_ipe_0_ahb_clk.clkr,
+       [CAM_CC_IPE_0_AREG_CLK] = &cam_cc_ipe_0_areg_clk.clkr,
+       [CAM_CC_IPE_0_AXI_CLK] = &cam_cc_ipe_0_axi_clk.clkr,
+       [CAM_CC_IPE_0_CLK] = &cam_cc_ipe_0_clk.clkr,
+       [CAM_CC_IPE_0_CLK_SRC] = &cam_cc_ipe_0_clk_src.clkr,
+       [CAM_CC_JPEG_CLK] = &cam_cc_jpeg_clk.clkr,
+       [CAM_CC_JPEG_CLK_SRC] = &cam_cc_jpeg_clk_src.clkr,
+       [CAM_CC_LRME_CLK] = &cam_cc_lrme_clk.clkr,
+       [CAM_CC_LRME_CLK_SRC] = &cam_cc_lrme_clk_src.clkr,
+       [CAM_CC_MCLK0_CLK] = &cam_cc_mclk0_clk.clkr,
+       [CAM_CC_MCLK0_CLK_SRC] = &cam_cc_mclk0_clk_src.clkr,
+       [CAM_CC_MCLK1_CLK] = &cam_cc_mclk1_clk.clkr,
+       [CAM_CC_MCLK1_CLK_SRC] = &cam_cc_mclk1_clk_src.clkr,
+       [CAM_CC_MCLK2_CLK] = &cam_cc_mclk2_clk.clkr,
+       [CAM_CC_MCLK2_CLK_SRC] = &cam_cc_mclk2_clk_src.clkr,
+       [CAM_CC_MCLK3_CLK] = &cam_cc_mclk3_clk.clkr,
+       [CAM_CC_MCLK3_CLK_SRC] = &cam_cc_mclk3_clk_src.clkr,
+       [CAM_CC_MCLK4_CLK] = &cam_cc_mclk4_clk.clkr,
+       [CAM_CC_MCLK4_CLK_SRC] = &cam_cc_mclk4_clk_src.clkr,
+       [CAM_CC_PLL0] = &cam_cc_pll0.clkr,
+       [CAM_CC_PLL1] = &cam_cc_pll1.clkr,
+       [CAM_CC_PLL2] = &cam_cc_pll2.clkr,
+       [CAM_CC_PLL2_OUT_AUX] = &cam_cc_pll2_out_aux.clkr,
+       [CAM_CC_PLL3] = &cam_cc_pll3.clkr,
+       [CAM_CC_SLOW_AHB_CLK_SRC] = &cam_cc_slow_ahb_clk_src.clkr,
+       [CAM_CC_SOC_AHB_CLK] = &cam_cc_soc_ahb_clk.clkr,
+       [CAM_CC_SYS_TMR_CLK] = &cam_cc_sys_tmr_clk.clkr,
+};
+static struct gdsc *cam_cc_sc7180_gdscs[] = {
+       [BPS_GDSC] = &bps_gdsc,
+       [IFE_0_GDSC] = &ife_0_gdsc,
+       [IFE_1_GDSC] = &ife_1_gdsc,
+       [IPE_0_GDSC] = &ipe_0_gdsc,
+       [TITAN_TOP_GDSC] = &titan_top_gdsc,
+};
+
+static const struct regmap_config cam_cc_sc7180_regmap_config = {
+       .reg_bits = 32,
+       .reg_stride = 4,
+       .val_bits = 32,
+       .max_register = 0xd028,
+       .fast_io = true,
+};
+
+static const struct qcom_cc_desc cam_cc_sc7180_desc = {
+       .config = &cam_cc_sc7180_regmap_config,
+       .clk_hws = cam_cc_sc7180_hws,
+       .num_clk_hws = ARRAY_SIZE(cam_cc_sc7180_hws),
+       .clks = cam_cc_sc7180_clocks,
+       .num_clks = ARRAY_SIZE(cam_cc_sc7180_clocks),
+       .gdscs = cam_cc_sc7180_gdscs,
+       .num_gdscs = ARRAY_SIZE(cam_cc_sc7180_gdscs),
+};
+
+static const struct of_device_id cam_cc_sc7180_match_table[] = {
+       { .compatible = "qcom,sc7180-camcc" },
+       { }
+};
+MODULE_DEVICE_TABLE(of, cam_cc_sc7180_match_table);
+
+static int cam_cc_sc7180_probe(struct platform_device *pdev)
+{
+       struct regmap *regmap;
+       int ret;
+
+       pm_runtime_enable(&pdev->dev);
+       ret = pm_clk_create(&pdev->dev);
+       if (ret < 0)
+               return ret;
+
+       ret = pm_clk_add(&pdev->dev, "xo");
+       if (ret < 0) {
+               dev_err(&pdev->dev, "Failed to acquire XO clock\n");
+               goto disable_pm_runtime;
+       }
+
+       ret = pm_clk_add(&pdev->dev, "iface");
+       if (ret < 0) {
+               dev_err(&pdev->dev, "Failed to acquire iface clock\n");
+               goto disable_pm_runtime;
+       }
+
+       ret = pm_runtime_get(&pdev->dev);
+       if (ret)
+               goto destroy_pm_clk;
+
+       regmap = qcom_cc_map(pdev, &cam_cc_sc7180_desc);
+       if (IS_ERR(regmap)) {
+               ret = PTR_ERR(regmap);
+               pm_runtime_put(&pdev->dev);
+               goto destroy_pm_clk;
+       }
+
+       clk_fabia_pll_configure(&cam_cc_pll0, regmap, &cam_cc_pll0_config);
+       clk_fabia_pll_configure(&cam_cc_pll1, regmap, &cam_cc_pll1_config);
+       clk_agera_pll_configure(&cam_cc_pll2, regmap, &cam_cc_pll2_config);
+       clk_fabia_pll_configure(&cam_cc_pll3, regmap, &cam_cc_pll3_config);
+
+       ret = qcom_cc_really_probe(pdev, &cam_cc_sc7180_desc, regmap);
+       pm_runtime_put(&pdev->dev);
+       if (ret < 0) {
+               dev_err(&pdev->dev, "Failed to register CAM CC clocks\n");
+               goto destroy_pm_clk;
+       }
+
+       return 0;
+
+destroy_pm_clk:
+       pm_clk_destroy(&pdev->dev);
+
+disable_pm_runtime:
+       pm_runtime_disable(&pdev->dev);
+
+       return ret;
+}
+
+static const struct dev_pm_ops cam_cc_pm_ops = {
+       SET_RUNTIME_PM_OPS(pm_clk_suspend, pm_clk_resume, NULL)
+};
+
+static struct platform_driver cam_cc_sc7180_driver = {
+       .probe = cam_cc_sc7180_probe,
+       .driver = {
+               .name = "cam_cc-sc7180",
+               .of_match_table = cam_cc_sc7180_match_table,
+               .pm = &cam_cc_pm_ops,
+       },
+};
+
+static int __init cam_cc_sc7180_init(void)
+{
+       return platform_driver_register(&cam_cc_sc7180_driver);
+}
+subsys_initcall(cam_cc_sc7180_init);
+
+static void __exit cam_cc_sc7180_exit(void)
+{
+       platform_driver_unregister(&cam_cc_sc7180_driver);
+}
+module_exit(cam_cc_sc7180_exit);
+
+MODULE_DESCRIPTION("QTI CAM_CC SC7180 Driver");
+MODULE_LICENSE("GPL v2");
index 5644311..21c357c 100644 (file)
@@ -116,6 +116,16 @@ const u8 clk_alpha_pll_regs[][PLL_OFF_MAX_REGS] = {
                [PLL_OFF_OPMODE] = 0x38,
                [PLL_OFF_ALPHA_VAL] = 0x40,
        },
+       [CLK_ALPHA_PLL_TYPE_AGERA] =  {
+               [PLL_OFF_L_VAL] = 0x04,
+               [PLL_OFF_ALPHA_VAL] = 0x08,
+               [PLL_OFF_USER_CTL] = 0x0c,
+               [PLL_OFF_CONFIG_CTL] = 0x10,
+               [PLL_OFF_CONFIG_CTL_U] = 0x14,
+               [PLL_OFF_TEST_CTL] = 0x18,
+               [PLL_OFF_TEST_CTL_U] = 0x1c,
+               [PLL_OFF_STATUS] = 0x2c,
+       },
 };
 EXPORT_SYMBOL_GPL(clk_alpha_pll_regs);
 
@@ -207,6 +217,13 @@ static int wait_for_pll(struct clk_alpha_pll *pll, u32 mask, bool inverse,
 #define wait_for_pll_update_ack_clear(pll) \
        wait_for_pll(pll, ALPHA_PLL_ACK_LATCH, 1, "update_ack_clear")
 
+static void clk_alpha_pll_write_config(struct regmap *regmap, unsigned int reg,
+                                       unsigned int val)
+{
+       if (val)
+               regmap_write(regmap, reg, val);
+}
+
 void clk_alpha_pll_configure(struct clk_alpha_pll *pll, struct regmap *regmap,
                             const struct alpha_pll_config *config)
 {
@@ -1004,33 +1021,19 @@ void clk_fabia_pll_configure(struct clk_alpha_pll *pll, struct regmap *regmap,
 {
        u32 val, mask;
 
-       if (config->l)
-               regmap_write(regmap, PLL_L_VAL(pll), config->l);
-
-       if (config->alpha)
-               regmap_write(regmap, PLL_FRAC(pll), config->alpha);
-
-       if (config->config_ctl_val)
-               regmap_write(regmap, PLL_CONFIG_CTL(pll),
+       clk_alpha_pll_write_config(regmap, PLL_L_VAL(pll), config->l);
+       clk_alpha_pll_write_config(regmap, PLL_FRAC(pll), config->alpha);
+       clk_alpha_pll_write_config(regmap, PLL_CONFIG_CTL(pll),
                                                config->config_ctl_val);
-
-       if (config->config_ctl_hi_val)
-               regmap_write(regmap, PLL_CONFIG_CTL_U(pll),
+       clk_alpha_pll_write_config(regmap, PLL_CONFIG_CTL_U(pll),
                                                config->config_ctl_hi_val);
-
-       if (config->user_ctl_val)
-               regmap_write(regmap, PLL_USER_CTL(pll), config->user_ctl_val);
-
-       if (config->user_ctl_hi_val)
-               regmap_write(regmap, PLL_USER_CTL_U(pll),
+       clk_alpha_pll_write_config(regmap, PLL_USER_CTL(pll),
+                                               config->user_ctl_val);
+       clk_alpha_pll_write_config(regmap, PLL_USER_CTL_U(pll),
                                                config->user_ctl_hi_val);
-
-       if (config->test_ctl_val)
-               regmap_write(regmap, PLL_TEST_CTL(pll),
+       clk_alpha_pll_write_config(regmap, PLL_TEST_CTL(pll),
                                                config->test_ctl_val);
-
-       if (config->test_ctl_hi_val)
-               regmap_write(regmap, PLL_TEST_CTL_U(pll),
+       clk_alpha_pll_write_config(regmap, PLL_TEST_CTL_U(pll),
                                                config->test_ctl_hi_val);
 
        if (config->post_div_mask) {
@@ -1145,25 +1148,38 @@ static unsigned long alpha_pll_fabia_recalc_rate(struct clk_hw *hw,
        return alpha_pll_calc_rate(parent_rate, l, frac, alpha_width);
 }
 
+/*
+ * Due to limited number of bits for fractional rate programming, the
+ * rounded up rate could be marginally higher than the requested rate.
+ */
+static int alpha_pll_check_rate_margin(struct clk_hw *hw,
+                       unsigned long rrate, unsigned long rate)
+{
+       unsigned long rate_margin = rate + PLL_RATE_MARGIN;
+
+       if (rrate > rate_margin || rrate < rate) {
+               pr_err("%s: Rounded rate %lu not within range [%lu, %lu)\n",
+                      clk_hw_get_name(hw), rrate, rate, rate_margin);
+               return -EINVAL;
+       }
+
+       return 0;
+}
+
 static int alpha_pll_fabia_set_rate(struct clk_hw *hw, unsigned long rate,
                                                unsigned long prate)
 {
        struct clk_alpha_pll *pll = to_clk_alpha_pll(hw);
        u32 l, alpha_width = pll_alpha_width(pll);
+       unsigned long rrate;
+       int ret;
        u64 a;
-       unsigned long rrate, max = rate + PLL_RATE_MARGIN;
 
        rrate = alpha_pll_round_rate(rate, prate, &l, &a, alpha_width);
 
-       /*
-        * Due to limited number of bits for fractional rate programming, the
-        * rounded up rate could be marginally higher than the requested rate.
-        */
-       if (rrate > (rate + PLL_RATE_MARGIN) || rrate < rate) {
-               pr_err("%s: Rounded rate %lu not within range [%lu, %lu)\n",
-                      clk_hw_get_name(hw), rrate, rate, max);
-               return -EINVAL;
-       }
+       ret = alpha_pll_check_rate_margin(hw, rrate, rate);
+       if (ret < 0)
+               return ret;
 
        regmap_write(pll->clkr.regmap, PLL_L_VAL(pll), l);
        regmap_write(pll->clkr.regmap, PLL_FRAC(pll), a);
@@ -1206,12 +1222,10 @@ static int alpha_pll_fabia_prepare(struct clk_hw *hw)
 
        rrate = alpha_pll_round_rate(cal_freq, clk_hw_get_rate(parent_hw),
                                        &cal_l, &a, alpha_width);
-       /*
-        * Due to a limited number of bits for fractional rate programming, the
-        * rounded up rate could be marginally higher than the requested rate.
-        */
-       if (rrate > (cal_freq + PLL_RATE_MARGIN) || rrate < cal_freq)
-               return -EINVAL;
+
+       ret = alpha_pll_check_rate_margin(hw, rrate, cal_freq);
+       if (ret < 0)
+               return ret;
 
        /* Setup PLL for calibration frequency */
        regmap_write(pll->clkr.regmap, PLL_ALPHA_VAL(pll), cal_l);
@@ -1388,49 +1402,27 @@ EXPORT_SYMBOL_GPL(clk_alpha_pll_postdiv_fabia_ops);
 void clk_trion_pll_configure(struct clk_alpha_pll *pll, struct regmap *regmap,
                             const struct alpha_pll_config *config)
 {
-       if (config->l)
-               regmap_write(regmap, PLL_L_VAL(pll), config->l);
-
+       clk_alpha_pll_write_config(regmap, PLL_L_VAL(pll), config->l);
        regmap_write(regmap, PLL_CAL_L_VAL(pll), TRION_PLL_CAL_VAL);
-
-       if (config->alpha)
-               regmap_write(regmap, PLL_ALPHA_VAL(pll), config->alpha);
-
-       if (config->config_ctl_val)
-               regmap_write(regmap, PLL_CONFIG_CTL(pll),
-                            config->config_ctl_val);
-
-       if (config->config_ctl_hi_val)
-               regmap_write(regmap, PLL_CONFIG_CTL_U(pll),
-                            config->config_ctl_hi_val);
-
-       if (config->config_ctl_hi1_val)
-               regmap_write(regmap, PLL_CONFIG_CTL_U1(pll),
-                            config->config_ctl_hi1_val);
-
-       if (config->user_ctl_val)
-               regmap_write(regmap, PLL_USER_CTL(pll),
-                            config->user_ctl_val);
-
-       if (config->user_ctl_hi_val)
-               regmap_write(regmap, PLL_USER_CTL_U(pll),
-                            config->user_ctl_hi_val);
-
-       if (config->user_ctl_hi1_val)
-               regmap_write(regmap, PLL_USER_CTL_U1(pll),
-                            config->user_ctl_hi1_val);
-
-       if (config->test_ctl_val)
-               regmap_write(regmap, PLL_TEST_CTL(pll),
-                            config->test_ctl_val);
-
-       if (config->test_ctl_hi_val)
-               regmap_write(regmap, PLL_TEST_CTL_U(pll),
-                            config->test_ctl_hi_val);
-
-       if (config->test_ctl_hi1_val)
-               regmap_write(regmap, PLL_TEST_CTL_U1(pll),
-                            config->test_ctl_hi1_val);
+       clk_alpha_pll_write_config(regmap, PLL_ALPHA_VAL(pll), config->alpha);
+       clk_alpha_pll_write_config(regmap, PLL_CONFIG_CTL(pll),
+                                    config->config_ctl_val);
+       clk_alpha_pll_write_config(regmap, PLL_CONFIG_CTL_U(pll),
+                                    config->config_ctl_hi_val);
+       clk_alpha_pll_write_config(regmap, PLL_CONFIG_CTL_U1(pll),
+                                    config->config_ctl_hi1_val);
+       clk_alpha_pll_write_config(regmap, PLL_USER_CTL(pll),
+                                       config->user_ctl_val);
+       clk_alpha_pll_write_config(regmap, PLL_USER_CTL_U(pll),
+                                       config->user_ctl_hi_val);
+       clk_alpha_pll_write_config(regmap, PLL_USER_CTL_U1(pll),
+                                       config->user_ctl_hi1_val);
+       clk_alpha_pll_write_config(regmap, PLL_TEST_CTL(pll),
+                                       config->test_ctl_val);
+       clk_alpha_pll_write_config(regmap, PLL_TEST_CTL_U(pll),
+                                       config->test_ctl_hi_val);
+       clk_alpha_pll_write_config(regmap, PLL_TEST_CTL_U1(pll),
+                                       config->test_ctl_hi1_val);
 
        regmap_update_bits(regmap, PLL_MODE(pll), PLL_UPDATE_BYPASS,
                           PLL_UPDATE_BYPASS);
@@ -1490,14 +1482,9 @@ static int alpha_pll_trion_set_rate(struct clk_hw *hw, unsigned long rate,
 
        rrate = alpha_pll_round_rate(rate, prate, &l, &a, alpha_width);
 
-       /*
-        * Due to a limited number of bits for fractional rate programming, the
-        * rounded up rate could be marginally higher than the requested rate.
-        */
-       if (rrate > (rate + PLL_RATE_MARGIN) || rrate < rate) {
-               pr_err("Call set rate on the PLL with rounded rates!\n");
-               return -EINVAL;
-       }
+       ret = alpha_pll_check_rate_margin(hw, rrate, rate);
+       if (ret < 0)
+               return ret;
 
        regmap_write(pll->clkr.regmap, PLL_L_VAL(pll), l);
        regmap_write(pll->clkr.regmap, PLL_ALPHA_VAL(pll), a);
@@ -1561,3 +1548,55 @@ const struct clk_ops clk_alpha_pll_postdiv_lucid_ops = {
        .set_rate = clk_alpha_pll_postdiv_fabia_set_rate,
 };
 EXPORT_SYMBOL_GPL(clk_alpha_pll_postdiv_lucid_ops);
+
+void clk_agera_pll_configure(struct clk_alpha_pll *pll, struct regmap *regmap,
+                       const struct alpha_pll_config *config)
+{
+       clk_alpha_pll_write_config(regmap, PLL_L_VAL(pll), config->l);
+       clk_alpha_pll_write_config(regmap, PLL_ALPHA_VAL(pll), config->alpha);
+       clk_alpha_pll_write_config(regmap, PLL_USER_CTL(pll),
+                                                       config->user_ctl_val);
+       clk_alpha_pll_write_config(regmap, PLL_CONFIG_CTL(pll),
+                                               config->config_ctl_val);
+       clk_alpha_pll_write_config(regmap, PLL_CONFIG_CTL_U(pll),
+                                               config->config_ctl_hi_val);
+       clk_alpha_pll_write_config(regmap, PLL_TEST_CTL(pll),
+                                               config->test_ctl_val);
+       clk_alpha_pll_write_config(regmap,  PLL_TEST_CTL_U(pll),
+                                               config->test_ctl_hi_val);
+}
+EXPORT_SYMBOL_GPL(clk_agera_pll_configure);
+
+static int clk_alpha_pll_agera_set_rate(struct clk_hw *hw, unsigned long rate,
+                                                       unsigned long prate)
+{
+       struct clk_alpha_pll *pll = to_clk_alpha_pll(hw);
+       u32 l, alpha_width = pll_alpha_width(pll);
+       int ret;
+       unsigned long rrate;
+       u64 a;
+
+       rrate = alpha_pll_round_rate(rate, prate, &l, &a, alpha_width);
+       ret = alpha_pll_check_rate_margin(hw, rrate, rate);
+       if (ret < 0)
+               return ret;
+
+       /* change L_VAL without having to go through the power on sequence */
+       regmap_write(pll->clkr.regmap, PLL_L_VAL(pll), l);
+       regmap_write(pll->clkr.regmap, PLL_ALPHA_VAL(pll), a);
+
+       if (clk_hw_is_enabled(hw))
+               return wait_for_pll_enable_lock(pll);
+
+       return 0;
+}
+
+const struct clk_ops clk_alpha_pll_agera_ops = {
+       .enable = clk_alpha_pll_enable,
+       .disable = clk_alpha_pll_disable,
+       .is_enabled = clk_alpha_pll_is_enabled,
+       .recalc_rate = alpha_pll_fabia_recalc_rate,
+       .round_rate = clk_alpha_pll_round_rate,
+       .set_rate = clk_alpha_pll_agera_set_rate,
+};
+EXPORT_SYMBOL_GPL(clk_alpha_pll_agera_ops);
index d3201b8..0ea30d2 100644 (file)
@@ -15,6 +15,7 @@ enum {
        CLK_ALPHA_PLL_TYPE_FABIA,
        CLK_ALPHA_PLL_TYPE_TRION,
        CLK_ALPHA_PLL_TYPE_LUCID = CLK_ALPHA_PLL_TYPE_TRION,
+       CLK_ALPHA_PLL_TYPE_AGERA,
        CLK_ALPHA_PLL_TYPE_MAX,
 };
 
@@ -141,6 +142,7 @@ extern const struct clk_ops clk_alpha_pll_postdiv_trion_ops;
 extern const struct clk_ops clk_alpha_pll_lucid_ops;
 #define clk_alpha_pll_fixed_lucid_ops clk_alpha_pll_fixed_trion_ops
 extern const struct clk_ops clk_alpha_pll_postdiv_lucid_ops;
+extern const struct clk_ops clk_alpha_pll_agera_ops;
 
 void clk_alpha_pll_configure(struct clk_alpha_pll *pll, struct regmap *regmap,
                             const struct alpha_pll_config *config);
@@ -148,6 +150,8 @@ void clk_fabia_pll_configure(struct clk_alpha_pll *pll, struct regmap *regmap,
                                const struct alpha_pll_config *config);
 void clk_trion_pll_configure(struct clk_alpha_pll *pll, struct regmap *regmap,
                             const struct alpha_pll_config *config);
+void clk_agera_pll_configure(struct clk_alpha_pll *pll, struct regmap *regmap,
+                               const struct alpha_pll_config *config);
 #define clk_lucid_pll_configure(pll, regmap, config) \
        clk_trion_pll_configure(pll, regmap, config)
 
index e2c669b..6a2a13c 100644 (file)
@@ -349,6 +349,7 @@ DEFINE_CLK_RPMH_VRM(sdm845, rf_clk2, rf_clk2_ao, "rfclka2", 1);
 DEFINE_CLK_RPMH_VRM(sdm845, rf_clk3, rf_clk3_ao, "rfclka3", 1);
 DEFINE_CLK_RPMH_VRM(sm8150, rf_clk3, rf_clk3_ao, "rfclka3", 1);
 DEFINE_CLK_RPMH_BCM(sdm845, ipa, "IP0");
+DEFINE_CLK_RPMH_BCM(sdm845, ce, "CE0");
 
 static struct clk_hw *sdm845_rpmh_clocks[] = {
        [RPMH_CXO_CLK]          = &sdm845_bi_tcxo.hw,
@@ -364,6 +365,7 @@ static struct clk_hw *sdm845_rpmh_clocks[] = {
        [RPMH_RF_CLK3]          = &sdm845_rf_clk3.hw,
        [RPMH_RF_CLK3_A]        = &sdm845_rf_clk3_ao.hw,
        [RPMH_IPA_CLK]          = &sdm845_ipa.hw,
+       [RPMH_CE_CLK]           = &sdm845_ce.hw,
 };
 
 static const struct clk_rpmh_desc clk_rpmh_sdm845 = {
@@ -371,6 +373,25 @@ static const struct clk_rpmh_desc clk_rpmh_sdm845 = {
        .num_clks = ARRAY_SIZE(sdm845_rpmh_clocks),
 };
 
+DEFINE_CLK_RPMH_VRM(sdx55, rf_clk1, rf_clk1_ao, "rfclkd1", 1);
+DEFINE_CLK_RPMH_VRM(sdx55, rf_clk2, rf_clk2_ao, "rfclkd2", 1);
+DEFINE_CLK_RPMH_BCM(sdx55, qpic_clk, "QP0");
+
+static struct clk_hw *sdx55_rpmh_clocks[] = {
+       [RPMH_CXO_CLK]          = &sdm845_bi_tcxo.hw,
+       [RPMH_CXO_CLK_A]        = &sdm845_bi_tcxo_ao.hw,
+       [RPMH_RF_CLK1]          = &sdx55_rf_clk1.hw,
+       [RPMH_RF_CLK1_A]        = &sdx55_rf_clk1_ao.hw,
+       [RPMH_RF_CLK2]          = &sdx55_rf_clk2.hw,
+       [RPMH_RF_CLK2_A]        = &sdx55_rf_clk2_ao.hw,
+       [RPMH_QPIC_CLK]         = &sdx55_qpic_clk.hw,
+};
+
+static const struct clk_rpmh_desc clk_rpmh_sdx55 = {
+       .clks = sdx55_rpmh_clocks,
+       .num_clks = ARRAY_SIZE(sdx55_rpmh_clocks),
+};
+
 static struct clk_hw *sm8150_rpmh_clocks[] = {
        [RPMH_CXO_CLK]          = &sdm845_bi_tcxo.hw,
        [RPMH_CXO_CLK_A]        = &sdm845_bi_tcxo_ao.hw,
@@ -432,6 +453,39 @@ static const struct clk_rpmh_desc clk_rpmh_sm8250 = {
        .num_clks = ARRAY_SIZE(sm8250_rpmh_clocks),
 };
 
+DEFINE_CLK_RPMH_VRM(sm8350, div_clk1, div_clk1_ao, "divclka1", 2);
+DEFINE_CLK_RPMH_VRM(sm8350, rf_clk4, rf_clk4_ao, "rfclka4", 1);
+DEFINE_CLK_RPMH_VRM(sm8350, rf_clk5, rf_clk5_ao, "rfclka5", 1);
+DEFINE_CLK_RPMH_BCM(sm8350, pka, "PKA0");
+DEFINE_CLK_RPMH_BCM(sm8350, hwkm, "HK0");
+
+static struct clk_hw *sm8350_rpmh_clocks[] = {
+       [RPMH_CXO_CLK]          = &sdm845_bi_tcxo.hw,
+       [RPMH_CXO_CLK_A]        = &sdm845_bi_tcxo_ao.hw,
+       [RPMH_DIV_CLK1]         = &sm8350_div_clk1.hw,
+       [RPMH_DIV_CLK1_A]       = &sm8350_div_clk1_ao.hw,
+       [RPMH_LN_BB_CLK1]       = &sm8250_ln_bb_clk1.hw,
+       [RPMH_LN_BB_CLK1_A]     = &sm8250_ln_bb_clk1_ao.hw,
+       [RPMH_LN_BB_CLK2]       = &sdm845_ln_bb_clk2.hw,
+       [RPMH_LN_BB_CLK2_A]     = &sdm845_ln_bb_clk2_ao.hw,
+       [RPMH_RF_CLK1]          = &sdm845_rf_clk1.hw,
+       [RPMH_RF_CLK1_A]        = &sdm845_rf_clk1_ao.hw,
+       [RPMH_RF_CLK3]          = &sdm845_rf_clk3.hw,
+       [RPMH_RF_CLK3_A]        = &sdm845_rf_clk3_ao.hw,
+       [RPMH_RF_CLK4]          = &sm8350_rf_clk4.hw,
+       [RPMH_RF_CLK4_A]        = &sm8350_rf_clk4_ao.hw,
+       [RPMH_RF_CLK5]          = &sm8350_rf_clk5.hw,
+       [RPMH_RF_CLK5_A]        = &sm8350_rf_clk5_ao.hw,
+       [RPMH_IPA_CLK]          = &sdm845_ipa.hw,
+       [RPMH_PKA_CLK]          = &sm8350_pka.hw,
+       [RPMH_HWKM_CLK]         = &sm8350_hwkm.hw,
+};
+
+static const struct clk_rpmh_desc clk_rpmh_sm8350 = {
+       .clks = sm8350_rpmh_clocks,
+       .num_clks = ARRAY_SIZE(sm8350_rpmh_clocks),
+};
+
 static struct clk_hw *of_clk_rpmh_hw_get(struct of_phandle_args *clkspec,
                                         void *data)
 {
@@ -517,8 +571,10 @@ static int clk_rpmh_probe(struct platform_device *pdev)
 static const struct of_device_id clk_rpmh_match_table[] = {
        { .compatible = "qcom,sc7180-rpmh-clk", .data = &clk_rpmh_sc7180},
        { .compatible = "qcom,sdm845-rpmh-clk", .data = &clk_rpmh_sdm845},
+       { .compatible = "qcom,sdx55-rpmh-clk",  .data = &clk_rpmh_sdx55},
        { .compatible = "qcom,sm8150-rpmh-clk", .data = &clk_rpmh_sm8150},
        { .compatible = "qcom,sm8250-rpmh-clk", .data = &clk_rpmh_sm8250},
+       { .compatible = "qcom,sm8350-rpmh-clk", .data = &clk_rpmh_sm8350},
        { }
 };
 MODULE_DEVICE_TABLE(of, clk_rpmh_match_table);
index 07a98d3..588575e 100644 (file)
@@ -963,6 +963,7 @@ static struct gdsc mdss_gdsc = {
        },
        .pwrsts = PWRSTS_OFF_ON,
        .flags = HW_CTRL,
+       .supply = "mmcx",
 };
 
 static struct clk_regmap *disp_cc_sm8250_clocks[] = {
index 68d8f7a..d82d725 100644 (file)
@@ -642,7 +642,7 @@ static struct clk_rcg2 gcc_sdcc1_ice_core_clk_src = {
                .name = "gcc_sdcc1_ice_core_clk_src",
                .parent_data = gcc_parent_data_0,
                .num_parents = 4,
-               .ops = &clk_rcg2_ops,
+               .ops = &clk_rcg2_floor_ops,
        },
 };
 
@@ -651,6 +651,7 @@ static const struct freq_tbl ftbl_gcc_sdcc2_apps_clk_src[] = {
        F(9600000, P_BI_TCXO, 2, 0, 0),
        F(19200000, P_BI_TCXO, 1, 0, 0),
        F(25000000, P_GPLL0_OUT_EVEN, 12, 0, 0),
+       F(50000000, P_GPLL0_OUT_EVEN, 6, 0, 0),
        F(100000000, P_GPLL0_OUT_EVEN, 3, 0, 0),
        F(202000000, P_GPLL7_OUT_MAIN, 4, 0, 0),
        { }
@@ -666,7 +667,7 @@ static struct clk_rcg2 gcc_sdcc2_apps_clk_src = {
                .name = "gcc_sdcc2_apps_clk_src",
                .parent_data = gcc_parent_data_5,
                .num_parents = 5,
-               .ops = &clk_rcg2_ops,
+               .ops = &clk_rcg2_floor_ops,
        },
 };
 
diff --git a/drivers/clk/qcom/gcc-sdx55.c b/drivers/clk/qcom/gcc-sdx55.c
new file mode 100644 (file)
index 0000000..e3b9030
--- /dev/null
@@ -0,0 +1,1659 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Copyright (c) 2018-2019, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2020, Linaro Ltd.
+ */
+
+#include <linux/clk-provider.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/regmap.h>
+
+#include <dt-bindings/clock/qcom,gcc-sdx55.h>
+
+#include "common.h"
+#include "clk-alpha-pll.h"
+#include "clk-branch.h"
+#include "clk-pll.h"
+#include "clk-rcg.h"
+#include "clk-regmap.h"
+#include "gdsc.h"
+#include "reset.h"
+
+enum {
+       P_BI_TCXO,
+       P_CORE_BI_PLL_TEST_SE,
+       P_GPLL0_OUT_EVEN,
+       P_GPLL0_OUT_MAIN,
+       P_GPLL4_OUT_EVEN,
+       P_GPLL5_OUT_MAIN,
+       P_SLEEP_CLK,
+};
+
+static const struct pll_vco lucid_vco[] = {
+       { 249600000, 2000000000, 0 },
+};
+
+static struct clk_alpha_pll gpll0 = {
+       .offset = 0x0,
+       .regs = clk_alpha_pll_regs[CLK_ALPHA_PLL_TYPE_LUCID],
+       .vco_table = lucid_vco,
+       .num_vco = ARRAY_SIZE(lucid_vco),
+       .clkr = {
+               .enable_reg = 0x6d000,
+               .enable_mask = BIT(0),
+               .hw.init = &(struct clk_init_data){
+                       .name = "gpll0",
+                       .parent_data = &(const struct clk_parent_data){
+                               .fw_name = "bi_tcxo",
+                       },
+                       .num_parents = 1,
+                       .ops = &clk_alpha_pll_fixed_lucid_ops,
+               },
+       },
+};
+
+static const struct clk_div_table post_div_table_lucid_even[] = {
+       { 0x0, 1 },
+       { 0x1, 2 },
+       { 0x3, 4 },
+       { 0x7, 8 },
+       { }
+};
+
+static struct clk_alpha_pll_postdiv gpll0_out_even = {
+       .offset = 0x0,
+       .regs = clk_alpha_pll_regs[CLK_ALPHA_PLL_TYPE_LUCID],
+       .post_div_shift = 8,
+       .post_div_table = post_div_table_lucid_even,
+       .num_post_div = ARRAY_SIZE(post_div_table_lucid_even),
+       .width = 4,
+       .clkr.hw.init = &(struct clk_init_data){
+               .name = "gpll0_out_even",
+               .parent_data = &(const struct clk_parent_data){
+                       .hw = &gpll0.clkr.hw,
+               },
+               .num_parents = 1,
+               .ops = &clk_alpha_pll_postdiv_lucid_ops,
+       },
+};
+
+static struct clk_alpha_pll gpll4 = {
+       .offset = 0x76000,
+       .regs = clk_alpha_pll_regs[CLK_ALPHA_PLL_TYPE_LUCID],
+       .vco_table = lucid_vco,
+       .num_vco = ARRAY_SIZE(lucid_vco),
+       .clkr = {
+               .enable_reg = 0x6d000,
+               .enable_mask = BIT(4),
+               .hw.init = &(struct clk_init_data){
+                       .name = "gpll4",
+                       .parent_data = &(const struct clk_parent_data){
+                               .fw_name = "bi_tcxo",
+                       },
+                       .num_parents = 1,
+                       .ops = &clk_alpha_pll_fixed_lucid_ops,
+               },
+       },
+};
+
+static struct clk_alpha_pll_postdiv gpll4_out_even = {
+       .offset = 0x76000,
+       .regs = clk_alpha_pll_regs[CLK_ALPHA_PLL_TYPE_LUCID],
+       .post_div_shift = 8,
+       .post_div_table = post_div_table_lucid_even,
+       .num_post_div = ARRAY_SIZE(post_div_table_lucid_even),
+       .width = 4,
+       .clkr.hw.init = &(struct clk_init_data){
+               .name = "gpll4_out_even",
+               .parent_data = &(const struct clk_parent_data){
+                       .hw = &gpll4.clkr.hw,
+               },
+               .num_parents = 1,
+               .ops = &clk_alpha_pll_postdiv_lucid_ops,
+       },
+};
+
+static struct clk_alpha_pll gpll5 = {
+       .offset = 0x74000,
+       .regs = clk_alpha_pll_regs[CLK_ALPHA_PLL_TYPE_LUCID],
+       .vco_table = lucid_vco,
+       .num_vco = ARRAY_SIZE(lucid_vco),
+       .clkr = {
+               .enable_reg = 0x6d000,
+               .enable_mask = BIT(5),
+               .hw.init = &(struct clk_init_data){
+                       .name = "gpll5",
+                       .parent_data = &(const struct clk_parent_data){
+                               .fw_name = "bi_tcxo",
+                       },
+                       .num_parents = 1,
+                       .ops = &clk_alpha_pll_fixed_lucid_ops,
+               },
+       },
+};
+
+static const struct parent_map gcc_parent_map_0[] = {
+       { P_BI_TCXO, 0 },
+       { P_GPLL0_OUT_MAIN, 1 },
+       { P_GPLL0_OUT_EVEN, 6 },
+       { P_CORE_BI_PLL_TEST_SE, 7 },
+};
+
+static const struct clk_parent_data gcc_parents_0[] = {
+       { .fw_name = "bi_tcxo" },
+       { .hw = &gpll0.clkr.hw },
+       { .hw = &gpll0_out_even.clkr.hw },
+       { .fw_name = "core_bi_pll_test_se" },
+};
+
+static const struct clk_parent_data gcc_parents_0_ao[] = {
+       { .fw_name = "bi_tcxo_ao" },
+       { .hw = &gpll0.clkr.hw },
+       { .hw = &gpll0_out_even.clkr.hw },
+       { .fw_name = "core_bi_pll_test_se" },
+};
+
+static const struct parent_map gcc_parent_map_2[] = {
+       { P_BI_TCXO, 0 },
+       { P_GPLL0_OUT_MAIN, 1 },
+       { P_GPLL4_OUT_EVEN, 2 },
+       { P_GPLL5_OUT_MAIN, 5 },
+       { P_GPLL0_OUT_EVEN, 6 },
+       { P_CORE_BI_PLL_TEST_SE, 7 },
+};
+
+static const struct clk_parent_data gcc_parents_2[] = {
+       { .fw_name = "bi_tcxo" },
+       { .hw = &gpll0.clkr.hw },
+       { .hw = &gpll4_out_even.clkr.hw },
+       { .hw = &gpll5.clkr.hw },
+       { .hw = &gpll0_out_even.clkr.hw },
+       { .fw_name = "core_bi_pll_test_se" },
+};
+
+static const struct parent_map gcc_parent_map_3[] = {
+       { P_BI_TCXO, 0 },
+       { P_GPLL0_OUT_MAIN, 1 },
+       { P_SLEEP_CLK, 5 },
+       { P_GPLL0_OUT_EVEN, 6 },
+       { P_CORE_BI_PLL_TEST_SE, 7 },
+};
+
+static const struct clk_parent_data gcc_parents_3[] = {
+       { .fw_name = "bi_tcxo" },
+       { .hw = &gpll0.clkr.hw },
+       { .fw_name = "sleep_clk", .name = "sleep_clk" },
+       { .hw = &gpll0_out_even.clkr.hw },
+       { .fw_name = "core_bi_pll_test_se" },
+};
+
+static const struct parent_map gcc_parent_map_4[] = {
+       { P_BI_TCXO, 0 },
+       { P_SLEEP_CLK, 5 },
+       { P_CORE_BI_PLL_TEST_SE, 7 },
+};
+
+static const struct clk_parent_data gcc_parents_4[] = {
+       { .fw_name = "bi_tcxo" },
+       { .fw_name = "sleep_clk", .name = "sleep_clk" },
+       { .fw_name = "core_bi_pll_test_se" },
+};
+
+static const struct parent_map gcc_parent_map_5[] = {
+       { P_BI_TCXO, 0 },
+       { P_GPLL0_OUT_MAIN, 1 },
+       { P_GPLL4_OUT_EVEN, 2 },
+       { P_GPLL0_OUT_EVEN, 6 },
+       { P_CORE_BI_PLL_TEST_SE, 7 },
+};
+
+static const struct clk_parent_data gcc_parents_5[] = {
+       { .fw_name = "bi_tcxo" },
+       { .hw = &gpll0.clkr.hw },
+       { .hw = &gpll4_out_even.clkr.hw },
+       { .hw = &gpll0_out_even.clkr.hw },
+       { .fw_name = "core_bi_pll_test_se" },
+};
+
+static const struct freq_tbl ftbl_gcc_blsp1_qup1_i2c_apps_clk_src[] = {
+       F(9600000, P_BI_TCXO, 2, 0, 0),
+       F(19200000, P_BI_TCXO, 1, 0, 0),
+       F(50000000, P_GPLL0_OUT_MAIN, 12, 0, 0),
+       { }
+};
+
+static struct clk_rcg2 gcc_blsp1_qup1_i2c_apps_clk_src = {
+       .cmd_rcgr = 0x11024,
+       .mnd_width = 8,
+       .hid_width = 5,
+       .parent_map = gcc_parent_map_0,
+       .freq_tbl = ftbl_gcc_blsp1_qup1_i2c_apps_clk_src,
+       .clkr.hw.init = &(struct clk_init_data){
+               .name = "gcc_blsp1_qup1_i2c_apps_clk_src",
+               .parent_data = gcc_parents_0,
+               .num_parents = 4,
+               .ops = &clk_rcg2_ops,
+       },
+};
+
+static const struct freq_tbl ftbl_gcc_blsp1_qup1_spi_apps_clk_src[] = {
+       F(960000, P_BI_TCXO, 10, 1, 2),
+       F(4800000, P_BI_TCXO, 4, 0, 0),
+       F(9600000, P_BI_TCXO, 2, 0, 0),
+       F(15000000, P_GPLL0_OUT_EVEN, 5, 1, 4),
+       F(19200000, P_BI_TCXO, 1, 0, 0),
+       F(24000000, P_GPLL0_OUT_MAIN, 12.5, 1, 2),
+       F(25000000, P_GPLL0_OUT_MAIN, 12, 1, 2),
+       F(50000000, P_GPLL0_OUT_MAIN, 12, 0, 0),
+       { }
+};
+
+static struct clk_rcg2 gcc_blsp1_qup1_spi_apps_clk_src = {
+       .cmd_rcgr = 0x1100c,
+       .mnd_width = 8,
+       .hid_width = 5,
+       .parent_map = gcc_parent_map_0,
+       .freq_tbl = ftbl_gcc_blsp1_qup1_spi_apps_clk_src,
+       .clkr.hw.init = &(struct clk_init_data){
+               .name = "gcc_blsp1_qup1_spi_apps_clk_src",
+               .parent_data = gcc_parents_0,
+               .num_parents = 4,
+               .ops = &clk_rcg2_ops,
+       },
+};
+
+static struct clk_rcg2 gcc_blsp1_qup2_i2c_apps_clk_src = {
+       .cmd_rcgr = 0x13024,
+       .mnd_width = 8,
+       .hid_width = 5,
+       .parent_map = gcc_parent_map_0,
+       .freq_tbl = ftbl_gcc_blsp1_qup1_i2c_apps_clk_src,
+       .clkr.hw.init = &(struct clk_init_data){
+               .name = "gcc_blsp1_qup2_i2c_apps_clk_src",
+               .parent_data = gcc_parents_0,
+               .num_parents = 4,
+               .ops = &clk_rcg2_ops,
+       },
+};
+
+static struct clk_rcg2 gcc_blsp1_qup2_spi_apps_clk_src = {
+       .cmd_rcgr = 0x1300c,
+       .mnd_width = 8,
+       .hid_width = 5,
+       .parent_map = gcc_parent_map_0,
+       .freq_tbl = ftbl_gcc_blsp1_qup1_spi_apps_clk_src,
+       .clkr.hw.init = &(struct clk_init_data){
+               .name = "gcc_blsp1_qup2_spi_apps_clk_src",
+               .parent_data = gcc_parents_0,
+               .num_parents = 4,
+               .ops = &clk_rcg2_ops,
+       },
+};
+
+static struct clk_rcg2 gcc_blsp1_qup3_i2c_apps_clk_src = {
+       .cmd_rcgr = 0x15024,
+       .mnd_width = 8,
+       .hid_width = 5,
+       .parent_map = gcc_parent_map_0,
+       .freq_tbl = ftbl_gcc_blsp1_qup1_i2c_apps_clk_src,
+       .clkr.hw.init = &(struct clk_init_data){
+               .name = "gcc_blsp1_qup3_i2c_apps_clk_src",
+               .parent_data = gcc_parents_0,
+               .num_parents = 4,
+               .ops = &clk_rcg2_ops,
+       },
+};
+
+static struct clk_rcg2 gcc_blsp1_qup3_spi_apps_clk_src = {
+       .cmd_rcgr = 0x1500c,
+       .mnd_width = 8,
+       .hid_width = 5,
+       .parent_map = gcc_parent_map_0,
+       .freq_tbl = ftbl_gcc_blsp1_qup1_spi_apps_clk_src,
+       .clkr.hw.init = &(struct clk_init_data){
+               .name = "gcc_blsp1_qup3_spi_apps_clk_src",
+               .parent_data = gcc_parents_0,
+               .num_parents = 4,
+               .ops = &clk_rcg2_ops,
+       },
+};
+
+static struct clk_rcg2 gcc_blsp1_qup4_i2c_apps_clk_src = {
+       .cmd_rcgr = 0x17024,
+       .mnd_width = 8,
+       .hid_width = 5,
+       .parent_map = gcc_parent_map_0,
+       .freq_tbl = ftbl_gcc_blsp1_qup1_i2c_apps_clk_src,
+       .clkr.hw.init = &(struct clk_init_data){
+               .name = "gcc_blsp1_qup4_i2c_apps_clk_src",
+               .parent_data = gcc_parents_0,
+               .num_parents = 4,
+               .ops = &clk_rcg2_ops,
+       },
+};
+
+static struct clk_rcg2 gcc_blsp1_qup4_spi_apps_clk_src = {
+       .cmd_rcgr = 0x1700c,
+       .mnd_width = 8,
+       .hid_width = 5,
+       .parent_map = gcc_parent_map_0,
+       .freq_tbl = ftbl_gcc_blsp1_qup1_spi_apps_clk_src,
+       .clkr.hw.init = &(struct clk_init_data){
+               .name = "gcc_blsp1_qup4_spi_apps_clk_src",
+               .parent_data = gcc_parents_0,
+               .num_parents = 4,
+               .ops = &clk_rcg2_ops,
+       },
+};
+
+static const struct freq_tbl ftbl_gcc_blsp1_uart1_apps_clk_src[] = {
+       F(3686400, P_GPLL0_OUT_EVEN, 1, 192, 15625),
+       F(7372800, P_GPLL0_OUT_EVEN, 1, 384, 15625),
+       F(9600000, P_BI_TCXO, 2, 0, 0),
+       F(14745600, P_GPLL0_OUT_EVEN, 1, 768, 15625),
+       F(16000000, P_GPLL0_OUT_EVEN, 1, 4, 75),
+       F(19200000, P_BI_TCXO, 1, 0, 0),
+       F(19354839, P_GPLL0_OUT_MAIN, 15.5, 1, 2),
+       F(20000000, P_GPLL0_OUT_MAIN, 15, 1, 2),
+       F(20689655, P_GPLL0_OUT_MAIN, 14.5, 1, 2),
+       F(21428571, P_GPLL0_OUT_MAIN, 14, 1, 2),
+       F(22222222, P_GPLL0_OUT_MAIN, 13.5, 1, 2),
+       F(23076923, P_GPLL0_OUT_MAIN, 13, 1, 2),
+       F(24000000, P_GPLL0_OUT_MAIN, 5, 1, 5),
+       F(25000000, P_GPLL0_OUT_MAIN, 12, 1, 2),
+       F(26086957, P_GPLL0_OUT_MAIN, 11.5, 1, 2),
+       F(27272727, P_GPLL0_OUT_MAIN, 11, 1, 2),
+       F(28571429, P_GPLL0_OUT_MAIN, 10.5, 1, 2),
+       F(32000000, P_GPLL0_OUT_MAIN, 1, 4, 75),
+       F(40000000, P_GPLL0_OUT_MAIN, 15, 0, 0),
+       F(46400000, P_GPLL0_OUT_MAIN, 1, 29, 375),
+       F(48000000, P_GPLL0_OUT_MAIN, 12.5, 0, 0),
+       F(51200000, P_GPLL0_OUT_MAIN, 1, 32, 375),
+       F(56000000, P_GPLL0_OUT_MAIN, 1, 7, 75),
+       F(58982400, P_GPLL0_OUT_MAIN, 1, 1536, 15625),
+       F(60000000, P_GPLL0_OUT_MAIN, 10, 0, 0),
+       F(63157895, P_GPLL0_OUT_MAIN, 9.5, 0, 0),
+       { }
+};
+
+static struct clk_rcg2 gcc_blsp1_uart1_apps_clk_src = {
+       .cmd_rcgr = 0x1200c,
+       .mnd_width = 16,
+       .hid_width = 5,
+       .parent_map = gcc_parent_map_0,
+       .freq_tbl = ftbl_gcc_blsp1_uart1_apps_clk_src,
+       .clkr.hw.init = &(struct clk_init_data){
+               .name = "gcc_blsp1_uart1_apps_clk_src",
+               .parent_data = gcc_parents_0,
+               .num_parents = 4,
+               .ops = &clk_rcg2_ops,
+       },
+};
+
+static struct clk_rcg2 gcc_blsp1_uart2_apps_clk_src = {
+       .cmd_rcgr = 0x1400c,
+       .mnd_width = 16,
+       .hid_width = 5,
+       .parent_map = gcc_parent_map_0,
+       .freq_tbl = ftbl_gcc_blsp1_uart1_apps_clk_src,
+       .clkr.hw.init = &(struct clk_init_data){
+               .name = "gcc_blsp1_uart2_apps_clk_src",
+               .parent_data = gcc_parents_0,
+               .num_parents = 4,
+               .ops = &clk_rcg2_ops,
+       },
+};
+
+static struct clk_rcg2 gcc_blsp1_uart3_apps_clk_src = {
+       .cmd_rcgr = 0x1600c,
+       .mnd_width = 16,
+       .hid_width = 5,
+       .parent_map = gcc_parent_map_0,
+       .freq_tbl = ftbl_gcc_blsp1_uart1_apps_clk_src,
+       .clkr.hw.init = &(struct clk_init_data){
+               .name = "gcc_blsp1_uart3_apps_clk_src",
+               .parent_data = gcc_parents_0,
+               .num_parents = 4,
+               .ops = &clk_rcg2_ops,
+       },
+};
+
+static struct clk_rcg2 gcc_blsp1_uart4_apps_clk_src = {
+       .cmd_rcgr = 0x1800c,
+       .mnd_width = 16,
+       .hid_width = 5,
+       .parent_map = gcc_parent_map_0,
+       .freq_tbl = ftbl_gcc_blsp1_uart1_apps_clk_src,
+       .clkr.hw.init = &(struct clk_init_data){
+               .name = "gcc_blsp1_uart4_apps_clk_src",
+               .parent_data = gcc_parents_0,
+               .num_parents = 4,
+               .ops = &clk_rcg2_ops,
+       },
+};
+
+static const struct freq_tbl ftbl_gcc_cpuss_ahb_clk_src[] = {
+       F(19200000, P_BI_TCXO, 1, 0, 0),
+       F(50000000, P_GPLL0_OUT_EVEN, 6, 0, 0),
+       F(100000000, P_GPLL0_OUT_MAIN, 6, 0, 0),
+       F(133333333, P_GPLL0_OUT_MAIN, 4.5, 0, 0),
+       { }
+};
+
+static struct clk_rcg2 gcc_cpuss_ahb_clk_src = {
+       .cmd_rcgr = 0x24010,
+       .mnd_width = 0,
+       .hid_width = 5,
+       .parent_map = gcc_parent_map_0,
+       .freq_tbl = ftbl_gcc_cpuss_ahb_clk_src,
+       .clkr.hw.init = &(struct clk_init_data){
+               .name = "gcc_cpuss_ahb_clk_src",
+               .parent_data = gcc_parents_0_ao,
+               .num_parents = 4,
+               .ops = &clk_rcg2_ops,
+       },
+};
+
+static const struct freq_tbl ftbl_gcc_cpuss_rbcpr_clk_src[] = {
+       F(19200000, P_BI_TCXO, 1, 0, 0),
+       { }
+};
+
+static struct clk_rcg2 gcc_cpuss_rbcpr_clk_src = {
+       .cmd_rcgr = 0x2402c,
+       .mnd_width = 0,
+       .hid_width = 5,
+       .parent_map = gcc_parent_map_0,
+       .freq_tbl = ftbl_gcc_cpuss_rbcpr_clk_src,
+       .clkr.hw.init = &(struct clk_init_data){
+               .name = "gcc_cpuss_rbcpr_clk_src",
+               .parent_data = gcc_parents_0_ao,
+               .num_parents = 4,
+               .ops = &clk_rcg2_ops,
+       },
+};
+
+static const struct freq_tbl ftbl_gcc_emac_clk_src[] = {
+       F(2500000, P_BI_TCXO, 1, 25, 192),
+       F(5000000, P_BI_TCXO, 1, 25, 96),
+       F(19200000, P_BI_TCXO, 1, 0, 0),
+       F(25000000, P_GPLL0_OUT_EVEN, 12, 0, 0),
+       F(50000000, P_GPLL0_OUT_EVEN, 6, 0, 0),
+       F(250000000, P_GPLL4_OUT_EVEN, 2, 0, 0),
+       { }
+};
+
+static struct clk_rcg2 gcc_emac_clk_src = {
+       .cmd_rcgr = 0x47020,
+       .mnd_width = 8,
+       .hid_width = 5,
+       .parent_map = gcc_parent_map_5,
+       .freq_tbl = ftbl_gcc_emac_clk_src,
+       .clkr.hw.init = &(struct clk_init_data){
+               .name = "gcc_emac_clk_src",
+               .parent_data = gcc_parents_5,
+               .num_parents = 5,
+               .ops = &clk_rcg2_ops,
+       },
+};
+
+static const struct freq_tbl ftbl_gcc_emac_ptp_clk_src[] = {
+       F(19200000, P_BI_TCXO, 1, 0, 0),
+       F(50000000, P_GPLL0_OUT_EVEN, 6, 0, 0),
+       F(230400000, P_GPLL5_OUT_MAIN, 3.5, 0, 0),
+       { }
+};
+
+static struct clk_rcg2 gcc_emac_ptp_clk_src = {
+       .cmd_rcgr = 0x47038,
+       .mnd_width = 0,
+       .hid_width = 5,
+       .parent_map = gcc_parent_map_2,
+       .freq_tbl = ftbl_gcc_emac_ptp_clk_src,
+       .clkr.hw.init = &(struct clk_init_data){
+               .name = "gcc_emac_ptp_clk_src",
+               .parent_data = gcc_parents_2,
+               .num_parents = 6,
+               .ops = &clk_rcg2_ops,
+       },
+};
+
+static const struct freq_tbl ftbl_gcc_gp1_clk_src[] = {
+       F(19200000, P_BI_TCXO, 1, 0, 0),
+       F(25000000, P_GPLL0_OUT_EVEN, 12, 0, 0),
+       F(50000000, P_GPLL0_OUT_EVEN, 6, 0, 0),
+       F(100000000, P_GPLL0_OUT_MAIN, 6, 0, 0),
+       F(200000000, P_GPLL0_OUT_MAIN, 3, 0, 0),
+       { }
+};
+
+static struct clk_rcg2 gcc_gp1_clk_src = {
+       .cmd_rcgr = 0x2b004,
+       .mnd_width = 8,
+       .hid_width = 5,
+       .parent_map = gcc_parent_map_3,
+       .freq_tbl = ftbl_gcc_gp1_clk_src,
+       .clkr.hw.init = &(struct clk_init_data){
+               .name = "gcc_gp1_clk_src",
+               .parent_data = gcc_parents_3,
+               .num_parents = 5,
+               .ops = &clk_rcg2_ops,
+       },
+};
+
+static struct clk_rcg2 gcc_gp2_clk_src = {
+       .cmd_rcgr = 0x2c004,
+       .mnd_width = 8,
+       .hid_width = 5,
+       .parent_map = gcc_parent_map_3,
+       .freq_tbl = ftbl_gcc_gp1_clk_src,
+       .clkr.hw.init = &(struct clk_init_data){
+               .name = "gcc_gp2_clk_src",
+               .parent_data = gcc_parents_3,
+               .num_parents = 5,
+               .ops = &clk_rcg2_ops,
+       },
+};
+
+static struct clk_rcg2 gcc_gp3_clk_src = {
+       .cmd_rcgr = 0x2d004,
+       .mnd_width = 8,
+       .hid_width = 5,
+       .parent_map = gcc_parent_map_3,
+       .freq_tbl = ftbl_gcc_gp1_clk_src,
+       .clkr.hw.init = &(struct clk_init_data){
+               .name = "gcc_gp3_clk_src",
+               .parent_data = gcc_parents_3,
+               .num_parents = 5,
+               .ops = &clk_rcg2_ops,
+       },
+};
+
+static struct clk_rcg2 gcc_pcie_aux_phy_clk_src = {
+       .cmd_rcgr = 0x37034,
+       .mnd_width = 16,
+       .hid_width = 5,
+       .parent_map = gcc_parent_map_4,
+       .freq_tbl = ftbl_gcc_cpuss_rbcpr_clk_src,
+       .clkr.hw.init = &(struct clk_init_data){
+               .name = "gcc_pcie_aux_phy_clk_src",
+               .parent_data = gcc_parents_4,
+               .num_parents = 3,
+               .ops = &clk_rcg2_ops,
+       },
+};
+
+static const struct freq_tbl ftbl_gcc_pcie_rchng_phy_clk_src[] = {
+       F(100000000, P_GPLL0_OUT_EVEN, 3, 0, 0),
+       { }
+};
+
+static struct clk_rcg2 gcc_pcie_rchng_phy_clk_src = {
+       .cmd_rcgr = 0x37050,
+       .mnd_width = 0,
+       .hid_width = 5,
+       .parent_map = gcc_parent_map_3,
+       .freq_tbl = ftbl_gcc_pcie_rchng_phy_clk_src,
+       .clkr.hw.init = &(struct clk_init_data){
+               .name = "gcc_pcie_rchng_phy_clk_src",
+               .parent_data = gcc_parents_3,
+               .num_parents = 5,
+               .ops = &clk_rcg2_ops,
+       },
+};
+
+static const struct freq_tbl ftbl_gcc_pdm2_clk_src[] = {
+       F(9600000, P_BI_TCXO, 2, 0, 0),
+       F(19200000, P_BI_TCXO, 1, 0, 0),
+       F(60000000, P_GPLL0_OUT_MAIN, 10, 0, 0),
+       { }
+};
+
+static struct clk_rcg2 gcc_pdm2_clk_src = {
+       .cmd_rcgr = 0x19010,
+       .mnd_width = 0,
+       .hid_width = 5,
+       .parent_map = gcc_parent_map_0,
+       .freq_tbl = ftbl_gcc_pdm2_clk_src,
+       .clkr.hw.init = &(struct clk_init_data){
+               .name = "gcc_pdm2_clk_src",
+               .parent_data = gcc_parents_0,
+               .num_parents = 4,
+               .ops = &clk_rcg2_ops,
+       },
+};
+
+static struct clk_rcg2 gcc_sdcc1_apps_clk_src = {
+       .cmd_rcgr = 0xf00c,
+       .mnd_width = 8,
+       .hid_width = 5,
+       .parent_map = gcc_parent_map_0,
+       .freq_tbl = ftbl_gcc_gp1_clk_src,
+       .clkr.hw.init = &(struct clk_init_data){
+               .name = "gcc_sdcc1_apps_clk_src",
+               .parent_data = gcc_parents_0,
+               .num_parents = 4,
+               .ops = &clk_rcg2_ops,
+       },
+};
+
+static const struct freq_tbl ftbl_gcc_usb30_master_clk_src[] = {
+       F(200000000, P_GPLL0_OUT_EVEN, 1.5, 0, 0),
+       { }
+};
+
+static struct clk_rcg2 gcc_usb30_master_clk_src = {
+       .cmd_rcgr = 0xb024,
+       .mnd_width = 8,
+       .hid_width = 5,
+       .parent_map = gcc_parent_map_0,
+       .freq_tbl = ftbl_gcc_usb30_master_clk_src,
+       .clkr.hw.init = &(struct clk_init_data){
+               .name = "gcc_usb30_master_clk_src",
+               .parent_data = gcc_parents_0,
+               .num_parents = 4,
+               .ops = &clk_rcg2_ops,
+       },
+};
+
+static const struct freq_tbl ftbl_gcc_usb30_mock_utmi_clk_src[] = {
+       F(19200000, P_BI_TCXO, 1, 0, 0),
+       { }
+};
+
+static struct clk_rcg2 gcc_usb30_mock_utmi_clk_src = {
+       .cmd_rcgr = 0xb03c,
+       .mnd_width = 0,
+       .hid_width = 5,
+       .parent_map = gcc_parent_map_0,
+       .freq_tbl = ftbl_gcc_usb30_mock_utmi_clk_src,
+       .clkr.hw.init = &(struct clk_init_data){
+               .name = "gcc_usb30_mock_utmi_clk_src",
+               .parent_data = gcc_parents_0,
+               .num_parents = 4,
+               .ops = &clk_rcg2_ops,
+       },
+};
+
+static const struct freq_tbl ftbl_gcc_usb3_phy_aux_clk_src[] = {
+       F(1000000, P_BI_TCXO, 1, 5, 96),
+       F(19200000, P_BI_TCXO, 1, 0, 0),
+       { }
+};
+
+static struct clk_rcg2 gcc_usb3_phy_aux_clk_src = {
+       .cmd_rcgr = 0xb064,
+       .mnd_width = 16,
+       .hid_width = 5,
+       .parent_map = gcc_parent_map_4,
+       .freq_tbl = ftbl_gcc_usb3_phy_aux_clk_src,
+       .clkr.hw.init = &(struct clk_init_data){
+               .name = "gcc_usb3_phy_aux_clk_src",
+               .parent_data = gcc_parents_4,
+               .num_parents = 3,
+               .ops = &clk_rcg2_ops,
+       },
+};
+
+static struct clk_branch gcc_ahb_pcie_link_clk = {
+       .halt_reg = 0x22004,
+       .halt_check = BRANCH_HALT,
+       .clkr = {
+               .enable_reg = 0x22004,
+               .enable_mask = BIT(0),
+               .hw.init = &(struct clk_init_data){
+                       .name = "gcc_ahb_pcie_link_clk",
+                       .ops = &clk_branch2_ops,
+               },
+       },
+};
+
+static struct clk_branch gcc_blsp1_ahb_clk = {
+       .halt_reg = 0x10004,
+       .halt_check = BRANCH_HALT_VOTED,
+       .clkr = {
+               .enable_reg = 0x6d008,
+               .enable_mask = BIT(14),
+               .hw.init = &(struct clk_init_data){
+                       .name = "gcc_blsp1_ahb_clk",
+                       .ops = &clk_branch2_ops,
+               },
+       },
+};
+
+static struct clk_branch gcc_blsp1_qup1_i2c_apps_clk = {
+       .halt_reg = 0x11008,
+       .halt_check = BRANCH_HALT,
+       .clkr = {
+               .enable_reg = 0x11008,
+               .enable_mask = BIT(0),
+               .hw.init = &(struct clk_init_data){
+                       .name = "gcc_blsp1_qup1_i2c_apps_clk",
+                       .parent_hws = (const struct clk_hw *[]){
+                               &gcc_blsp1_qup1_i2c_apps_clk_src.clkr.hw },
+                       .num_parents = 1,
+                       .flags = CLK_SET_RATE_PARENT,
+                       .ops = &clk_branch2_ops,
+               },
+       },
+};
+
+static struct clk_branch gcc_blsp1_qup1_spi_apps_clk = {
+       .halt_reg = 0x11004,
+       .halt_check = BRANCH_HALT,
+       .clkr = {
+               .enable_reg = 0x11004,
+               .enable_mask = BIT(0),
+               .hw.init = &(struct clk_init_data){
+                       .name = "gcc_blsp1_qup1_spi_apps_clk",
+                       .parent_hws = (const struct clk_hw *[]){
+                               &gcc_blsp1_qup1_spi_apps_clk_src.clkr.hw },
+                       .num_parents = 1,
+                       .flags = CLK_SET_RATE_PARENT,
+                       .ops = &clk_branch2_ops,
+               },
+       },
+};
+
+static struct clk_branch gcc_blsp1_qup2_i2c_apps_clk = {
+       .halt_reg = 0x13008,
+       .halt_check = BRANCH_HALT,
+       .clkr = {
+               .enable_reg = 0x13008,
+               .enable_mask = BIT(0),
+               .hw.init = &(struct clk_init_data){
+                       .name = "gcc_blsp1_qup2_i2c_apps_clk",
+                       .parent_hws = (const struct clk_hw *[]){
+                               &gcc_blsp1_qup2_i2c_apps_clk_src.clkr.hw },
+                       .num_parents = 1,
+                       .flags = CLK_SET_RATE_PARENT,
+                       .ops = &clk_branch2_ops,
+               },
+       },
+};
+
+static struct clk_branch gcc_blsp1_qup2_spi_apps_clk = {
+       .halt_reg = 0x13004,
+       .halt_check = BRANCH_HALT,
+       .clkr = {
+               .enable_reg = 0x13004,
+               .enable_mask = BIT(0),
+               .hw.init = &(struct clk_init_data){
+                       .name = "gcc_blsp1_qup2_spi_apps_clk",
+                       .parent_hws = (const struct clk_hw *[]){
+                               &gcc_blsp1_qup2_spi_apps_clk_src.clkr.hw },
+                       .num_parents = 1,
+                       .flags = CLK_SET_RATE_PARENT,
+                       .ops = &clk_branch2_ops,
+               },
+       },
+};
+
+static struct clk_branch gcc_blsp1_qup3_i2c_apps_clk = {
+       .halt_reg = 0x15008,
+       .halt_check = BRANCH_HALT,
+       .clkr = {
+               .enable_reg = 0x15008,
+               .enable_mask = BIT(0),
+               .hw.init = &(struct clk_init_data){
+                       .name = "gcc_blsp1_qup3_i2c_apps_clk",
+                       .parent_hws = (const struct clk_hw *[]){
+                               &gcc_blsp1_qup3_i2c_apps_clk_src.clkr.hw },
+                       .num_parents = 1,
+                       .flags = CLK_SET_RATE_PARENT,
+                       .ops = &clk_branch2_ops,
+               },
+       },
+};
+
+static struct clk_branch gcc_blsp1_qup3_spi_apps_clk = {
+       .halt_reg = 0x15004,
+       .halt_check = BRANCH_HALT,
+       .clkr = {
+               .enable_reg = 0x15004,
+               .enable_mask = BIT(0),
+               .hw.init = &(struct clk_init_data){
+                       .name = "gcc_blsp1_qup3_spi_apps_clk",
+                       .parent_hws = (const struct clk_hw *[]){
+                               &gcc_blsp1_qup3_spi_apps_clk_src.clkr.hw },
+                       .num_parents = 1,
+                       .flags = CLK_SET_RATE_PARENT,
+                       .ops = &clk_branch2_ops,
+               },
+       },
+};
+
+static struct clk_branch gcc_blsp1_qup4_i2c_apps_clk = {
+       .halt_reg = 0x17008,
+       .halt_check = BRANCH_HALT,
+       .clkr = {
+               .enable_reg = 0x17008,
+               .enable_mask = BIT(0),
+               .hw.init = &(struct clk_init_data){
+                       .name = "gcc_blsp1_qup4_i2c_apps_clk",
+                       .parent_hws = (const struct clk_hw *[]){
+                               &gcc_blsp1_qup4_i2c_apps_clk_src.clkr.hw },
+                       .num_parents = 1,
+                       .flags = CLK_SET_RATE_PARENT,
+                       .ops = &clk_branch2_ops,
+               },
+       },
+};
+
+static struct clk_branch gcc_blsp1_qup4_spi_apps_clk = {
+       .halt_reg = 0x17004,
+       .halt_check = BRANCH_HALT,
+       .clkr = {
+               .enable_reg = 0x17004,
+               .enable_mask = BIT(0),
+               .hw.init = &(struct clk_init_data){
+                       .name = "gcc_blsp1_qup4_spi_apps_clk",
+                       .parent_hws = (const struct clk_hw *[]){
+                               &gcc_blsp1_qup4_spi_apps_clk_src.clkr.hw },
+                       .num_parents = 1,
+                       .flags = CLK_SET_RATE_PARENT,
+                       .ops = &clk_branch2_ops,
+               },
+       },
+};
+
+static struct clk_branch gcc_blsp1_uart1_apps_clk = {
+       .halt_reg = 0x12004,
+       .halt_check = BRANCH_HALT,
+       .clkr = {
+               .enable_reg = 0x12004,
+               .enable_mask = BIT(0),
+               .hw.init = &(struct clk_init_data){
+                       .name = "gcc_blsp1_uart1_apps_clk",
+                       .parent_hws = (const struct clk_hw *[]){
+                               &gcc_blsp1_uart1_apps_clk_src.clkr.hw },
+                       .num_parents = 1,
+                       .flags = CLK_SET_RATE_PARENT,
+                       .ops = &clk_branch2_ops,
+               },
+       },
+};
+
+static struct clk_branch gcc_blsp1_uart2_apps_clk = {
+       .halt_reg = 0x14004,
+       .halt_check = BRANCH_HALT,
+       .clkr = {
+               .enable_reg = 0x14004,
+               .enable_mask = BIT(0),
+               .hw.init = &(struct clk_init_data){
+                       .name = "gcc_blsp1_uart2_apps_clk",
+                       .parent_hws = (const struct clk_hw *[]){
+                               &gcc_blsp1_uart2_apps_clk_src.clkr.hw },
+                       .num_parents = 1,
+                       .flags = CLK_SET_RATE_PARENT,
+                       .ops = &clk_branch2_ops,
+               },
+       },
+};
+
+static struct clk_branch gcc_blsp1_uart3_apps_clk = {
+       .halt_reg = 0x16004,
+       .halt_check = BRANCH_HALT,
+       .clkr = {
+               .enable_reg = 0x16004,
+               .enable_mask = BIT(0),
+               .hw.init = &(struct clk_init_data){
+                       .name = "gcc_blsp1_uart3_apps_clk",
+                       .parent_hws = (const struct clk_hw *[]){
+                               &gcc_blsp1_uart3_apps_clk_src.clkr.hw },
+                       .num_parents = 1,
+                       .flags = CLK_SET_RATE_PARENT,
+                       .ops = &clk_branch2_ops,
+               },
+       },
+};
+
+static struct clk_branch gcc_blsp1_uart4_apps_clk = {
+       .halt_reg = 0x18004,
+       .halt_check = BRANCH_HALT,
+       .clkr = {
+               .enable_reg = 0x18004,
+               .enable_mask = BIT(0),
+               .hw.init = &(struct clk_init_data){
+                       .name = "gcc_blsp1_uart4_apps_clk",
+                       .parent_hws = (const struct clk_hw *[]){
+                               &gcc_blsp1_uart4_apps_clk_src.clkr.hw },
+                       .num_parents = 1,
+                       .flags = CLK_SET_RATE_PARENT,
+                       .ops = &clk_branch2_ops,
+               },
+       },
+};
+
+static struct clk_branch gcc_boot_rom_ahb_clk = {
+       .halt_reg = 0x1c004,
+       .halt_check = BRANCH_HALT_VOTED,
+       .hwcg_reg = 0x1c004,
+       .hwcg_bit = 1,
+       .clkr = {
+               .enable_reg = 0x6d008,
+               .enable_mask = BIT(10),
+               .hw.init = &(struct clk_init_data){
+                       .name = "gcc_boot_rom_ahb_clk",
+                       .ops = &clk_branch2_ops,
+               },
+       },
+};
+
+static struct clk_branch gcc_ce1_ahb_clk = {
+       .halt_reg = 0x2100c,
+       .halt_check = BRANCH_HALT_VOTED,
+       .hwcg_reg = 0x2100c,
+       .hwcg_bit = 1,
+       .clkr = {
+               .enable_reg = 0x6d008,
+               .enable_mask = BIT(3),
+               .hw.init = &(struct clk_init_data){
+                       .name = "gcc_ce1_ahb_clk",
+                       .ops = &clk_branch2_ops,
+               },
+       },
+};
+
+static struct clk_branch gcc_ce1_axi_clk = {
+       .halt_reg = 0x21008,
+       .halt_check = BRANCH_HALT_VOTED,
+       .clkr = {
+               .enable_reg = 0x6d008,
+               .enable_mask = BIT(4),
+               .hw.init = &(struct clk_init_data){
+                       .name = "gcc_ce1_axi_clk",
+                       .ops = &clk_branch2_ops,
+               },
+       },
+};
+
+static struct clk_branch gcc_ce1_clk = {
+       .halt_reg = 0x21004,
+       .halt_check = BRANCH_HALT_VOTED,
+       .clkr = {
+               .enable_reg = 0x6d008,
+               .enable_mask = BIT(5),
+               .hw.init = &(struct clk_init_data){
+                       .name = "gcc_ce1_clk",
+                       .ops = &clk_branch2_ops,
+               },
+       },
+};
+
+static struct clk_branch gcc_cpuss_rbcpr_clk = {
+       .halt_reg = 0x24008,
+       .halt_check = BRANCH_HALT,
+       .clkr = {
+               .enable_reg = 0x24008,
+               .enable_mask = BIT(0),
+               .hw.init = &(struct clk_init_data){
+                       .name = "gcc_cpuss_rbcpr_clk",
+                       .parent_hws = (const struct clk_hw *[]){
+                               &gcc_cpuss_rbcpr_clk_src.clkr.hw },
+                       .num_parents = 1,
+                       .flags = CLK_SET_RATE_PARENT,
+                       .ops = &clk_branch2_ops,
+               },
+       },
+};
+
+static struct clk_branch gcc_eth_axi_clk = {
+       .halt_reg = 0x4701c,
+       .halt_check = BRANCH_HALT,
+       .clkr = {
+               .enable_reg = 0x4701c,
+               .enable_mask = BIT(0),
+               .hw.init = &(struct clk_init_data){
+                       .name = "gcc_eth_axi_clk",
+                       .ops = &clk_branch2_ops,
+               },
+       },
+};
+
+static struct clk_branch gcc_eth_ptp_clk = {
+       .halt_reg = 0x47018,
+       .halt_check = BRANCH_HALT,
+       .clkr = {
+               .enable_reg = 0x47018,
+               .enable_mask = BIT(0),
+               .hw.init = &(struct clk_init_data){
+                       .name = "gcc_eth_ptp_clk",
+                       .parent_hws = (const struct clk_hw *[]){
+                               &gcc_emac_ptp_clk_src.clkr.hw },
+                       .num_parents = 1,
+                       .flags = CLK_SET_RATE_PARENT,
+                       .ops = &clk_branch2_ops,
+               },
+       },
+};
+
+static struct clk_branch gcc_eth_rgmii_clk = {
+       .halt_reg = 0x47010,
+       .halt_check = BRANCH_HALT,
+       .clkr = {
+               .enable_reg = 0x47010,
+               .enable_mask = BIT(0),
+               .hw.init = &(struct clk_init_data){
+                       .name = "gcc_eth_rgmii_clk",
+                       .parent_hws = (const struct clk_hw *[]){
+                               &gcc_emac_clk_src.clkr.hw },
+                       .num_parents = 1,
+                       .flags = CLK_SET_RATE_PARENT,
+                       .ops = &clk_branch2_ops,
+               },
+       },
+};
+
+static struct clk_branch gcc_eth_slave_ahb_clk = {
+       .halt_reg = 0x47014,
+       .halt_check = BRANCH_HALT,
+       .clkr = {
+               .enable_reg = 0x47014,
+               .enable_mask = BIT(0),
+               .hw.init = &(struct clk_init_data){
+                       .name = "gcc_eth_slave_ahb_clk",
+                       .ops = &clk_branch2_ops,
+               },
+       },
+};
+
+static struct clk_branch gcc_gp1_clk = {
+       .halt_reg = 0x2b000,
+       .halt_check = BRANCH_HALT,
+       .clkr = {
+               .enable_reg = 0x2b000,
+               .enable_mask = BIT(0),
+               .hw.init = &(struct clk_init_data){
+                       .name = "gcc_gp1_clk",
+                       .parent_hws = (const struct clk_hw *[]){
+                               &gcc_gp1_clk_src.clkr.hw },
+                       .num_parents = 1,
+                       .flags = CLK_SET_RATE_PARENT,
+                       .ops = &clk_branch2_ops,
+               },
+       },
+};
+
+static struct clk_branch gcc_gp2_clk = {
+       .halt_reg = 0x2c000,
+       .halt_check = BRANCH_HALT,
+       .clkr = {
+               .enable_reg = 0x2c000,
+               .enable_mask = BIT(0),
+               .hw.init = &(struct clk_init_data){
+                       .name = "gcc_gp2_clk",
+                       .parent_hws = (const struct clk_hw *[]){
+                               &gcc_gp2_clk_src.clkr.hw },
+                       .num_parents = 1,
+                       .flags = CLK_SET_RATE_PARENT,
+                       .ops = &clk_branch2_ops,
+               },
+       },
+};
+
+static struct clk_branch gcc_gp3_clk = {
+       .halt_reg = 0x2d000,
+       .halt_check = BRANCH_HALT,
+       .clkr = {
+               .enable_reg = 0x2d000,
+               .enable_mask = BIT(0),
+               .hw.init = &(struct clk_init_data){
+                       .name = "gcc_gp3_clk",
+                       .parent_hws = (const struct clk_hw *[]){
+                               &gcc_gp3_clk_src.clkr.hw },
+                       .num_parents = 1,
+                       .flags = CLK_SET_RATE_PARENT,
+                       .ops = &clk_branch2_ops,
+               },
+       },
+};
+
+static struct clk_branch gcc_pcie_0_clkref_clk = {
+       .halt_reg = 0x88004,
+       .halt_check = BRANCH_HALT_DELAY,
+       .clkr = {
+               .enable_reg = 0x88004,
+               .enable_mask = BIT(0),
+               .hw.init = &(struct clk_init_data){
+                       .name = "gcc_pcie_0_clkref_clk",
+                       .ops = &clk_branch2_ops,
+               },
+       },
+};
+
+static struct clk_branch gcc_pcie_aux_clk = {
+       .halt_reg = 0x37024,
+       .halt_check = BRANCH_HALT_DELAY,
+       .clkr = {
+               .enable_reg = 0x6d010,
+               .enable_mask = BIT(3),
+               .hw.init = &(struct clk_init_data){
+                       .name = "gcc_pcie_aux_clk",
+                       .ops = &clk_branch2_ops,
+               },
+       },
+};
+
+static struct clk_branch gcc_pcie_cfg_ahb_clk = {
+       .halt_reg = 0x3701c,
+       .halt_check = BRANCH_HALT_VOTED,
+       .clkr = {
+               .enable_reg = 0x6d010,
+               .enable_mask = BIT(2),
+               .hw.init = &(struct clk_init_data){
+                       .name = "gcc_pcie_cfg_ahb_clk",
+                       .ops = &clk_branch2_ops,
+               },
+       },
+};
+
+static struct clk_branch gcc_pcie_mstr_axi_clk = {
+       .halt_reg = 0x37018,
+       .halt_check = BRANCH_HALT_VOTED,
+       .clkr = {
+               .enable_reg = 0x6d010,
+               .enable_mask = BIT(1),
+               .hw.init = &(struct clk_init_data){
+                       .name = "gcc_pcie_mstr_axi_clk",
+                       .ops = &clk_branch2_ops,
+               },
+       },
+};
+
+static struct clk_branch gcc_pcie_pipe_clk = {
+       .halt_reg = 0x3702c,
+       .halt_check = BRANCH_HALT_DELAY,
+       .clkr = {
+               .enable_reg = 0x6d010,
+               .enable_mask = BIT(4),
+               .hw.init = &(struct clk_init_data){
+                       .name = "gcc_pcie_pipe_clk",
+                       .ops = &clk_branch2_ops,
+               },
+       },
+};
+
+static struct clk_branch gcc_pcie_rchng_phy_clk = {
+       .halt_reg = 0x37020,
+       .halt_check = BRANCH_HALT_VOTED,
+       .clkr = {
+               .enable_reg = 0x6d010,
+               .enable_mask = BIT(7),
+               .hw.init = &(struct clk_init_data){
+                       .name = "gcc_pcie_rchng_phy_clk",
+                       .parent_hws = (const struct clk_hw *[]){
+                               &gcc_pcie_rchng_phy_clk_src.clkr.hw },
+                       .num_parents = 1,
+                       .flags = CLK_SET_RATE_PARENT,
+                       .ops = &clk_branch2_ops,
+               },
+       },
+};
+
+static struct clk_branch gcc_pcie_sleep_clk = {
+       .halt_reg = 0x37028,
+       .halt_check = BRANCH_HALT_VOTED,
+       .clkr = {
+               .enable_reg = 0x6d010,
+               .enable_mask = BIT(6),
+               .hw.init = &(struct clk_init_data){
+                       .name = "gcc_pcie_sleep_clk",
+                       .parent_hws = (const struct clk_hw *[]){
+                               &gcc_pcie_aux_phy_clk_src.clkr.hw },
+                       .num_parents = 1,
+                       .flags = CLK_SET_RATE_PARENT,
+                       .ops = &clk_branch2_ops,
+               },
+       },
+};
+
+static struct clk_branch gcc_pcie_slv_axi_clk = {
+       .halt_reg = 0x37014,
+       .halt_check = BRANCH_HALT_VOTED,
+       .hwcg_reg = 0x37014,
+       .hwcg_bit = 1,
+       .clkr = {
+               .enable_reg = 0x6d010,
+               .enable_mask = BIT(0),
+               .hw.init = &(struct clk_init_data){
+                       .name = "gcc_pcie_slv_axi_clk",
+                       .ops = &clk_branch2_ops,
+               },
+       },
+};
+
+static struct clk_branch gcc_pcie_slv_q2a_axi_clk = {
+       .halt_reg = 0x37010,
+       .halt_check = BRANCH_HALT_VOTED,
+       .clkr = {
+               .enable_reg = 0x6d010,
+               .enable_mask = BIT(5),
+               .hw.init = &(struct clk_init_data){
+                       .name = "gcc_pcie_slv_q2a_axi_clk",
+                       .ops = &clk_branch2_ops,
+               },
+       },
+};
+
+static struct clk_branch gcc_pdm2_clk = {
+       .halt_reg = 0x1900c,
+       .halt_check = BRANCH_HALT,
+       .clkr = {
+               .enable_reg = 0x1900c,
+               .enable_mask = BIT(0),
+               .hw.init = &(struct clk_init_data){
+                       .name = "gcc_pdm2_clk",
+                       .parent_hws = (const struct clk_hw *[]){
+                               &gcc_pdm2_clk_src.clkr.hw },
+                       .num_parents = 1,
+                       .flags = CLK_SET_RATE_PARENT,
+                       .ops = &clk_branch2_ops,
+               },
+       },
+};
+
+static struct clk_branch gcc_pdm_ahb_clk = {
+       .halt_reg = 0x19004,
+       .halt_check = BRANCH_HALT,
+       .hwcg_reg = 0x19004,
+       .hwcg_bit = 1,
+       .clkr = {
+               .enable_reg = 0x19004,
+               .enable_mask = BIT(0),
+               .hw.init = &(struct clk_init_data){
+                       .name = "gcc_pdm_ahb_clk",
+                       .ops = &clk_branch2_ops,
+               },
+       },
+};
+
+static struct clk_branch gcc_pdm_xo4_clk = {
+       .halt_reg = 0x19008,
+       .halt_check = BRANCH_HALT,
+       .clkr = {
+               .enable_reg = 0x19008,
+               .enable_mask = BIT(0),
+               .hw.init = &(struct clk_init_data){
+                       .name = "gcc_pdm_xo4_clk",
+                       .ops = &clk_branch2_ops,
+               },
+       },
+};
+
+static struct clk_branch gcc_sdcc1_ahb_clk = {
+       .halt_reg = 0xf008,
+       .halt_check = BRANCH_HALT,
+       .clkr = {
+               .enable_reg = 0xf008,
+               .enable_mask = BIT(0),
+               .hw.init = &(struct clk_init_data){
+                       .name = "gcc_sdcc1_ahb_clk",
+                       .ops = &clk_branch2_ops,
+               },
+       },
+};
+
+static struct clk_branch gcc_sdcc1_apps_clk = {
+       .halt_reg = 0xf004,
+       .halt_check = BRANCH_HALT,
+       .clkr = {
+               .enable_reg = 0xf004,
+               .enable_mask = BIT(0),
+               .hw.init = &(struct clk_init_data){
+                       .name = "gcc_sdcc1_apps_clk",
+                       .parent_hws = (const struct clk_hw *[]){
+                               &gcc_sdcc1_apps_clk_src.clkr.hw },
+                       .num_parents = 1,
+                       .flags = CLK_SET_RATE_PARENT,
+                       .ops = &clk_branch2_ops,
+               },
+       },
+};
+
+static struct clk_branch gcc_usb30_master_clk = {
+       .halt_reg = 0xb010,
+       .halt_check = BRANCH_HALT,
+       .clkr = {
+               .enable_reg = 0xb010,
+               .enable_mask = BIT(0),
+               .hw.init = &(struct clk_init_data){
+                       .name = "gcc_usb30_master_clk",
+                       .parent_hws = (const struct clk_hw *[]){
+                               &gcc_usb30_master_clk_src.clkr.hw },
+                       .num_parents = 1,
+                       .flags = CLK_SET_RATE_PARENT,
+                       .ops = &clk_branch2_ops,
+               },
+       },
+};
+
+static struct clk_branch gcc_usb30_mock_utmi_clk = {
+       .halt_reg = 0xb020,
+       .halt_check = BRANCH_HALT,
+       .clkr = {
+               .enable_reg = 0xb020,
+               .enable_mask = BIT(0),
+               .hw.init = &(struct clk_init_data){
+                       .name = "gcc_usb30_mock_utmi_clk",
+                       .parent_hws = (const struct clk_hw *[]){
+                               &gcc_usb30_mock_utmi_clk_src.clkr.hw },
+                       .num_parents = 1,
+                       .flags = CLK_SET_RATE_PARENT,
+                       .ops = &clk_branch2_ops,
+               },
+       },
+};
+
+static struct clk_branch gcc_usb30_mstr_axi_clk = {
+       .halt_reg = 0xb014,
+       .halt_check = BRANCH_HALT,
+       .clkr = {
+               .enable_reg = 0xb014,
+               .enable_mask = BIT(0),
+               .hw.init = &(struct clk_init_data){
+                       .name = "gcc_usb30_mstr_axi_clk",
+                       .ops = &clk_branch2_ops,
+               },
+       },
+};
+
+static struct clk_branch gcc_usb30_sleep_clk = {
+       .halt_reg = 0xb01c,
+       .halt_check = BRANCH_HALT,
+       .clkr = {
+               .enable_reg = 0xb01c,
+               .enable_mask = BIT(0),
+               .hw.init = &(struct clk_init_data){
+                       .name = "gcc_usb30_sleep_clk",
+                       .ops = &clk_branch2_ops,
+               },
+       },
+};
+
+static struct clk_branch gcc_usb30_slv_ahb_clk = {
+       .halt_reg = 0xb018,
+       .halt_check = BRANCH_HALT,
+       .clkr = {
+               .enable_reg = 0xb018,
+               .enable_mask = BIT(0),
+               .hw.init = &(struct clk_init_data){
+                       .name = "gcc_usb30_slv_ahb_clk",
+                       .ops = &clk_branch2_ops,
+               },
+       },
+};
+
+static struct clk_branch gcc_usb3_phy_aux_clk = {
+       .halt_reg = 0xb058,
+       .halt_check = BRANCH_HALT,
+       .clkr = {
+               .enable_reg = 0xb058,
+               .enable_mask = BIT(0),
+               .hw.init = &(struct clk_init_data){
+                       .name = "gcc_usb3_phy_aux_clk",
+                       .parent_hws = (const struct clk_hw *[]){
+                               &gcc_usb3_phy_aux_clk_src.clkr.hw },
+                       .num_parents = 1,
+                       .flags = CLK_SET_RATE_PARENT,
+                       .ops = &clk_branch2_ops,
+               },
+       },
+};
+
+static struct clk_branch gcc_usb3_phy_pipe_clk = {
+       .halt_reg = 0xb05c,
+       .halt_check = BRANCH_HALT_DELAY,
+       .clkr = {
+               .enable_reg = 0xb05c,
+               .enable_mask = BIT(0),
+               .hw.init = &(struct clk_init_data){
+                       .name = "gcc_usb3_phy_pipe_clk",
+                       .ops = &clk_branch2_ops,
+               },
+       },
+};
+
+static struct clk_branch gcc_usb3_prim_clkref_clk = {
+       .halt_reg = 0x88000,
+       .halt_check = BRANCH_HALT_DELAY,
+       .clkr = {
+               .enable_reg = 0x88000,
+               .enable_mask = BIT(0),
+               .hw.init = &(struct clk_init_data){
+                       .name = "gcc_usb3_prim_clkref_clk",
+                       .ops = &clk_branch2_ops,
+               },
+       },
+};
+
+static struct clk_branch gcc_usb_phy_cfg_ahb2phy_clk = {
+       .halt_reg = 0xe004,
+       .halt_check = BRANCH_HALT,
+       .hwcg_reg = 0xe004,
+       .hwcg_bit = 1,
+       .clkr = {
+               .enable_reg = 0xe004,
+               .enable_mask = BIT(0),
+               .hw.init = &(struct clk_init_data){
+                       .name = "gcc_usb_phy_cfg_ahb2phy_clk",
+                       .ops = &clk_branch2_ops,
+               },
+       },
+};
+
+static struct clk_branch gcc_xo_pcie_link_clk = {
+       .halt_reg = 0x22008,
+       .halt_check = BRANCH_HALT,
+       .clkr = {
+               .enable_reg = 0x22008,
+               .enable_mask = BIT(0),
+               .hw.init = &(struct clk_init_data){
+                       .name = "gcc_xo_pcie_link_clk",
+                       .ops = &clk_branch2_ops,
+               },
+       },
+};
+
+static struct gdsc usb30_gdsc = {
+       .gdscr = 0x0b004,
+       .pd = {
+               .name = "usb30_gdsc",
+       },
+       .pwrsts = PWRSTS_OFF_ON,
+};
+
+static struct gdsc pcie_gdsc = {
+       .gdscr = 0x37004,
+       .pd = {
+               .name = "pcie_gdsc",
+       },
+       .pwrsts = PWRSTS_OFF_ON,
+};
+
+static struct gdsc emac_gdsc = {
+       .gdscr = 0x47004,
+       .pd = {
+               .name = "emac_gdsc",
+       },
+       .pwrsts = PWRSTS_OFF_ON,
+};
+
+static struct clk_regmap *gcc_sdx55_clocks[] = {
+       [GCC_AHB_PCIE_LINK_CLK] = &gcc_ahb_pcie_link_clk.clkr,
+       [GCC_BLSP1_AHB_CLK] = &gcc_blsp1_ahb_clk.clkr,
+       [GCC_BLSP1_QUP1_I2C_APPS_CLK] = &gcc_blsp1_qup1_i2c_apps_clk.clkr,
+       [GCC_BLSP1_QUP1_I2C_APPS_CLK_SRC] =
+               &gcc_blsp1_qup1_i2c_apps_clk_src.clkr,
+       [GCC_BLSP1_QUP1_SPI_APPS_CLK] = &gcc_blsp1_qup1_spi_apps_clk.clkr,
+       [GCC_BLSP1_QUP1_SPI_APPS_CLK_SRC] =
+               &gcc_blsp1_qup1_spi_apps_clk_src.clkr,
+       [GCC_BLSP1_QUP2_I2C_APPS_CLK] = &gcc_blsp1_qup2_i2c_apps_clk.clkr,
+       [GCC_BLSP1_QUP2_I2C_APPS_CLK_SRC] =
+               &gcc_blsp1_qup2_i2c_apps_clk_src.clkr,
+       [GCC_BLSP1_QUP2_SPI_APPS_CLK] = &gcc_blsp1_qup2_spi_apps_clk.clkr,
+       [GCC_BLSP1_QUP2_SPI_APPS_CLK_SRC] =
+               &gcc_blsp1_qup2_spi_apps_clk_src.clkr,
+       [GCC_BLSP1_QUP3_I2C_APPS_CLK] = &gcc_blsp1_qup3_i2c_apps_clk.clkr,
+       [GCC_BLSP1_QUP3_I2C_APPS_CLK_SRC] =
+               &gcc_blsp1_qup3_i2c_apps_clk_src.clkr,
+       [GCC_BLSP1_QUP3_SPI_APPS_CLK] = &gcc_blsp1_qup3_spi_apps_clk.clkr,
+       [GCC_BLSP1_QUP3_SPI_APPS_CLK_SRC] =
+               &gcc_blsp1_qup3_spi_apps_clk_src.clkr,
+       [GCC_BLSP1_QUP4_I2C_APPS_CLK] = &gcc_blsp1_qup4_i2c_apps_clk.clkr,
+       [GCC_BLSP1_QUP4_I2C_APPS_CLK_SRC] =
+               &gcc_blsp1_qup4_i2c_apps_clk_src.clkr,
+       [GCC_BLSP1_QUP4_SPI_APPS_CLK] = &gcc_blsp1_qup4_spi_apps_clk.clkr,
+       [GCC_BLSP1_QUP4_SPI_APPS_CLK_SRC] =
+               &gcc_blsp1_qup4_spi_apps_clk_src.clkr,
+       [GCC_BLSP1_UART1_APPS_CLK] = &gcc_blsp1_uart1_apps_clk.clkr,
+       [GCC_BLSP1_UART1_APPS_CLK_SRC] = &gcc_blsp1_uart1_apps_clk_src.clkr,
+       [GCC_BLSP1_UART2_APPS_CLK] = &gcc_blsp1_uart2_apps_clk.clkr,
+       [GCC_BLSP1_UART2_APPS_CLK_SRC] = &gcc_blsp1_uart2_apps_clk_src.clkr,
+       [GCC_BLSP1_UART3_APPS_CLK] = &gcc_blsp1_uart3_apps_clk.clkr,
+       [GCC_BLSP1_UART3_APPS_CLK_SRC] = &gcc_blsp1_uart3_apps_clk_src.clkr,
+       [GCC_BLSP1_UART4_APPS_CLK] = &gcc_blsp1_uart4_apps_clk.clkr,
+       [GCC_BLSP1_UART4_APPS_CLK_SRC] = &gcc_blsp1_uart4_apps_clk_src.clkr,
+       [GCC_BOOT_ROM_AHB_CLK] = &gcc_boot_rom_ahb_clk.clkr,
+       [GCC_CE1_AHB_CLK] = &gcc_ce1_ahb_clk.clkr,
+       [GCC_CE1_AXI_CLK] = &gcc_ce1_axi_clk.clkr,
+       [GCC_CE1_CLK] = &gcc_ce1_clk.clkr,
+       [GCC_CPUSS_AHB_CLK_SRC] = &gcc_cpuss_ahb_clk_src.clkr,
+       [GCC_CPUSS_RBCPR_CLK] = &gcc_cpuss_rbcpr_clk.clkr,
+       [GCC_CPUSS_RBCPR_CLK_SRC] = &gcc_cpuss_rbcpr_clk_src.clkr,
+       [GCC_EMAC_CLK_SRC] = &gcc_emac_clk_src.clkr,
+       [GCC_EMAC_PTP_CLK_SRC] = &gcc_emac_ptp_clk_src.clkr,
+       [GCC_ETH_AXI_CLK] = &gcc_eth_axi_clk.clkr,
+       [GCC_ETH_PTP_CLK] = &gcc_eth_ptp_clk.clkr,
+       [GCC_ETH_RGMII_CLK] = &gcc_eth_rgmii_clk.clkr,
+       [GCC_ETH_SLAVE_AHB_CLK] = &gcc_eth_slave_ahb_clk.clkr,
+       [GCC_GP1_CLK] = &gcc_gp1_clk.clkr,
+       [GCC_GP1_CLK_SRC] = &gcc_gp1_clk_src.clkr,
+       [GCC_GP2_CLK] = &gcc_gp2_clk.clkr,
+       [GCC_GP2_CLK_SRC] = &gcc_gp2_clk_src.clkr,
+       [GCC_GP3_CLK] = &gcc_gp3_clk.clkr,
+       [GCC_GP3_CLK_SRC] = &gcc_gp3_clk_src.clkr,
+       [GCC_PCIE_0_CLKREF_CLK] = &gcc_pcie_0_clkref_clk.clkr,
+       [GCC_PCIE_AUX_CLK] = &gcc_pcie_aux_clk.clkr,
+       [GCC_PCIE_AUX_PHY_CLK_SRC] = &gcc_pcie_aux_phy_clk_src.clkr,
+       [GCC_PCIE_CFG_AHB_CLK] = &gcc_pcie_cfg_ahb_clk.clkr,
+       [GCC_PCIE_MSTR_AXI_CLK] = &gcc_pcie_mstr_axi_clk.clkr,
+       [GCC_PCIE_PIPE_CLK] = &gcc_pcie_pipe_clk.clkr,
+       [GCC_PCIE_RCHNG_PHY_CLK] = &gcc_pcie_rchng_phy_clk.clkr,
+       [GCC_PCIE_RCHNG_PHY_CLK_SRC] = &gcc_pcie_rchng_phy_clk_src.clkr,
+       [GCC_PCIE_SLEEP_CLK] = &gcc_pcie_sleep_clk.clkr,
+       [GCC_PCIE_SLV_AXI_CLK] = &gcc_pcie_slv_axi_clk.clkr,
+       [GCC_PCIE_SLV_Q2A_AXI_CLK] = &gcc_pcie_slv_q2a_axi_clk.clkr,
+       [GCC_PDM2_CLK] = &gcc_pdm2_clk.clkr,
+       [GCC_PDM2_CLK_SRC] = &gcc_pdm2_clk_src.clkr,
+       [GCC_PDM_AHB_CLK] = &gcc_pdm_ahb_clk.clkr,
+       [GCC_PDM_XO4_CLK] = &gcc_pdm_xo4_clk.clkr,
+       [GCC_SDCC1_AHB_CLK] = &gcc_sdcc1_ahb_clk.clkr,
+       [GCC_SDCC1_APPS_CLK] = &gcc_sdcc1_apps_clk.clkr,
+       [GCC_SDCC1_APPS_CLK_SRC] = &gcc_sdcc1_apps_clk_src.clkr,
+       [GCC_USB30_MASTER_CLK] = &gcc_usb30_master_clk.clkr,
+       [GCC_USB30_MASTER_CLK_SRC] = &gcc_usb30_master_clk_src.clkr,
+       [GCC_USB30_MOCK_UTMI_CLK] = &gcc_usb30_mock_utmi_clk.clkr,
+       [GCC_USB30_MOCK_UTMI_CLK_SRC] = &gcc_usb30_mock_utmi_clk_src.clkr,
+       [GCC_USB30_MSTR_AXI_CLK] = &gcc_usb30_mstr_axi_clk.clkr,
+       [GCC_USB30_SLEEP_CLK] = &gcc_usb30_sleep_clk.clkr,
+       [GCC_USB30_SLV_AHB_CLK] = &gcc_usb30_slv_ahb_clk.clkr,
+       [GCC_USB3_PHY_AUX_CLK] = &gcc_usb3_phy_aux_clk.clkr,
+       [GCC_USB3_PHY_AUX_CLK_SRC] = &gcc_usb3_phy_aux_clk_src.clkr,
+       [GCC_USB3_PHY_PIPE_CLK] = &gcc_usb3_phy_pipe_clk.clkr,
+       [GCC_USB3_PRIM_CLKREF_CLK] = &gcc_usb3_prim_clkref_clk.clkr,
+       [GCC_USB_PHY_CFG_AHB2PHY_CLK] = &gcc_usb_phy_cfg_ahb2phy_clk.clkr,
+       [GCC_XO_PCIE_LINK_CLK] = &gcc_xo_pcie_link_clk.clkr,
+       [GPLL0] = &gpll0.clkr,
+       [GPLL0_OUT_EVEN] = &gpll0_out_even.clkr,
+       [GPLL4] = &gpll4.clkr,
+       [GPLL4_OUT_EVEN] = &gpll4_out_even.clkr,
+       [GPLL5] = &gpll5.clkr,
+};
+
+static const struct qcom_reset_map gcc_sdx55_resets[] = {
+       [GCC_EMAC_BCR] = { 0x47000 },
+       [GCC_PCIE_BCR] = { 0x37000 },
+       [GCC_PCIE_LINK_DOWN_BCR] = { 0x77000 },
+       [GCC_PCIE_PHY_BCR] = { 0x39000 },
+       [GCC_PCIE_PHY_COM_BCR] = { 0x78004 },
+       [GCC_QUSB2PHY_BCR] = { 0xd000 },
+       [GCC_USB30_BCR] = { 0xb000 },
+       [GCC_USB3_PHY_BCR] = { 0xc000 },
+       [GCC_USB3PHY_PHY_BCR] = { 0xc004 },
+       [GCC_USB_PHY_CFG_AHB2PHY_BCR] = { 0xe000 },
+};
+
+static struct gdsc *gcc_sdx55_gdscs[] = {
+       [USB30_GDSC] = &usb30_gdsc,
+       [PCIE_GDSC] = &pcie_gdsc,
+       [EMAC_GDSC] = &emac_gdsc,
+};
+
+static const struct regmap_config gcc_sdx55_regmap_config = {
+       .reg_bits       = 32,
+       .reg_stride     = 4,
+       .val_bits       = 32,
+       .max_register   = 0x9b040,
+       .fast_io        = true,
+};
+
+static const struct qcom_cc_desc gcc_sdx55_desc = {
+       .config = &gcc_sdx55_regmap_config,
+       .clks = gcc_sdx55_clocks,
+       .num_clks = ARRAY_SIZE(gcc_sdx55_clocks),
+       .resets = gcc_sdx55_resets,
+       .num_resets = ARRAY_SIZE(gcc_sdx55_resets),
+       .gdscs = gcc_sdx55_gdscs,
+       .num_gdscs = ARRAY_SIZE(gcc_sdx55_gdscs),
+};
+
+static const struct of_device_id gcc_sdx55_match_table[] = {
+       { .compatible = "qcom,gcc-sdx55" },
+       { }
+};
+MODULE_DEVICE_TABLE(of, gcc_sdx55_match_table);
+
+static int gcc_sdx55_probe(struct platform_device *pdev)
+{
+       struct regmap *regmap;
+
+       regmap = qcom_cc_map(pdev, &gcc_sdx55_desc);
+       if (IS_ERR(regmap))
+               return PTR_ERR(regmap);
+
+       /*
+        * Keep the clocks always-ON as they are critical to the functioning
+        * of the system:
+        * GCC_SYS_NOC_CPUSS_AHB_CLK, GCC_CPUSS_AHB_CLK, GCC_CPUSS_GNOC_CLK
+        */
+       regmap_update_bits(regmap, 0x6d008, BIT(0), BIT(0));
+       regmap_update_bits(regmap, 0x6d008, BIT(21), BIT(21));
+       regmap_update_bits(regmap, 0x6d008, BIT(22), BIT(22));
+
+       return qcom_cc_really_probe(pdev, &gcc_sdx55_desc, regmap);
+}
+
+static struct platform_driver gcc_sdx55_driver = {
+       .probe = gcc_sdx55_probe,
+       .driver = {
+               .name = "gcc-sdx55",
+               .of_match_table = gcc_sdx55_match_table,
+       },
+};
+
+static int __init gcc_sdx55_init(void)
+{
+       return platform_driver_register(&gcc_sdx55_driver);
+}
+subsys_initcall(gcc_sdx55_init);
+
+static void __exit gcc_sdx55_exit(void)
+{
+       platform_driver_unregister(&gcc_sdx55_driver);
+}
+module_exit(gcc_sdx55_exit);
+
+MODULE_DESCRIPTION("QTI GCC SDX55 Driver");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/clk/qcom/lpass-gfm-sm8250.c b/drivers/clk/qcom/lpass-gfm-sm8250.c
new file mode 100644 (file)
index 0000000..d366c7c
--- /dev/null
@@ -0,0 +1,320 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * LPASS Audio CC and Always ON CC Glitch Free Mux clock driver
+ *
+ * Copyright (c) 2020 Linaro Ltd.
+ * Author: Srinivas Kandagatla <srinivas.kandagatla@linaro.org>
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/clk-provider.h>
+#include <linux/io.h>
+#include <linux/slab.h>
+#include <linux/err.h>
+#include <linux/pm_clock.h>
+#include <linux/pm_runtime.h>
+#include <linux/device.h>
+#include <linux/platform_device.h>
+#include <linux/of_device.h>
+#include <dt-bindings/clock/qcom,sm8250-lpass-audiocc.h>
+#include <dt-bindings/clock/qcom,sm8250-lpass-aoncc.h>
+
+struct lpass_gfm {
+       struct device *dev;
+       void __iomem *base;
+};
+
+struct clk_gfm {
+       unsigned int mux_reg;
+       unsigned int mux_mask;
+       struct clk_hw   hw;
+       struct lpass_gfm *priv;
+       void __iomem *gfm_mux;
+};
+
+#define GFM_MASK       BIT(1)
+#define to_clk_gfm(_hw) container_of(_hw, struct clk_gfm, hw)
+
+static u8 clk_gfm_get_parent(struct clk_hw *hw)
+{
+       struct clk_gfm *clk = to_clk_gfm(hw);
+
+       return readl(clk->gfm_mux) & GFM_MASK;
+}
+
+static int clk_gfm_set_parent(struct clk_hw *hw, u8 index)
+{
+       struct clk_gfm *clk = to_clk_gfm(hw);
+       unsigned int val;
+
+       val = readl(clk->gfm_mux);
+
+       if (index)
+               val |= GFM_MASK;
+       else
+               val &= ~GFM_MASK;
+
+       writel(val, clk->gfm_mux);
+
+       return 0;
+}
+
+static const struct clk_ops clk_gfm_ops = {
+       .get_parent = clk_gfm_get_parent,
+       .set_parent = clk_gfm_set_parent,
+       .determine_rate = __clk_mux_determine_rate,
+};
+
+static struct clk_gfm lpass_gfm_va_mclk = {
+       .mux_reg = 0x20000,
+       .mux_mask = BIT(0),
+       .hw.init = &(struct clk_init_data) {
+               .name = "VA_MCLK",
+               .ops = &clk_gfm_ops,
+               .flags = CLK_SET_RATE_PARENT | CLK_OPS_PARENT_ENABLE,
+               .num_parents = 2,
+               .parent_data = (const struct clk_parent_data[]){
+                       {
+                               .index = 0,
+                               .fw_name = "LPASS_CLK_ID_TX_CORE_MCLK",
+                       }, {
+                               .index = 1,
+                               .fw_name = "LPASS_CLK_ID_VA_CORE_MCLK",
+                       },
+               },
+       },
+};
+
+static struct clk_gfm lpass_gfm_tx_npl = {
+       .mux_reg = 0x20000,
+       .mux_mask = BIT(0),
+       .hw.init = &(struct clk_init_data) {
+               .name = "TX_NPL",
+               .ops = &clk_gfm_ops,
+               .flags = CLK_SET_RATE_PARENT | CLK_OPS_PARENT_ENABLE,
+               .parent_data = (const struct clk_parent_data[]){
+                       {
+                               .index = 0,
+                               .fw_name = "LPASS_CLK_ID_TX_CORE_NPL_MCLK",
+                       }, {
+                               .index = 1,
+                               .fw_name = "LPASS_CLK_ID_VA_CORE_2X_MCLK",
+                       },
+               },
+               .num_parents = 2,
+       },
+};
+
+static struct clk_gfm lpass_gfm_wsa_mclk = {
+       .mux_reg = 0x220d8,
+       .mux_mask = BIT(0),
+       .hw.init = &(struct clk_init_data) {
+               .name = "WSA_MCLK",
+               .ops = &clk_gfm_ops,
+               .flags = CLK_SET_RATE_PARENT | CLK_OPS_PARENT_ENABLE,
+               .parent_data = (const struct clk_parent_data[]){
+                       {
+                               .index = 0,
+                               .fw_name = "LPASS_CLK_ID_TX_CORE_MCLK",
+                       }, {
+                               .index = 1,
+                               .fw_name = "LPASS_CLK_ID_WSA_CORE_MCLK",
+                       },
+               },
+               .num_parents = 2,
+       },
+};
+
+static struct clk_gfm lpass_gfm_wsa_npl = {
+       .mux_reg = 0x220d8,
+       .mux_mask = BIT(0),
+       .hw.init = &(struct clk_init_data) {
+               .name = "WSA_NPL",
+               .ops = &clk_gfm_ops,
+               .flags = CLK_SET_RATE_PARENT | CLK_OPS_PARENT_ENABLE,
+               .parent_data = (const struct clk_parent_data[]){
+                       {
+                               .index = 0,
+                               .fw_name = "LPASS_CLK_ID_TX_CORE_NPL_MCLK",
+                       }, {
+                               .index = 1,
+                               .fw_name = "LPASS_CLK_ID_WSA_CORE_NPL_MCLK",
+                       },
+               },
+               .num_parents = 2,
+       },
+};
+
+static struct clk_gfm lpass_gfm_rx_mclk_mclk2 = {
+       .mux_reg = 0x240d8,
+       .mux_mask = BIT(0),
+       .hw.init = &(struct clk_init_data) {
+               .name = "RX_MCLK_MCLK2",
+               .ops = &clk_gfm_ops,
+               .flags = CLK_SET_RATE_PARENT | CLK_OPS_PARENT_ENABLE,
+               .parent_data = (const struct clk_parent_data[]){
+                       {
+                               .index = 0,
+                               .fw_name = "LPASS_CLK_ID_TX_CORE_MCLK",
+                       }, {
+                               .index = 1,
+                               .fw_name = "LPASS_CLK_ID_RX_CORE_MCLK",
+                       },
+               },
+               .num_parents = 2,
+       },
+};
+
+static struct clk_gfm lpass_gfm_rx_npl = {
+       .mux_reg = 0x240d8,
+       .mux_mask = BIT(0),
+       .hw.init = &(struct clk_init_data) {
+               .name = "RX_NPL",
+               .ops = &clk_gfm_ops,
+               .flags = CLK_SET_RATE_PARENT | CLK_OPS_PARENT_ENABLE,
+               .parent_data = (const struct clk_parent_data[]){
+                       {
+                               .index = 0,
+                               .fw_name = "LPASS_CLK_ID_TX_CORE_NPL_MCLK",
+                       }, {
+                               .index = 1,
+                               .fw_name = "LPASS_CLK_ID_RX_CORE_NPL_MCLK",
+                       },
+               },
+               .num_parents = 2,
+       },
+};
+
+static struct clk_gfm *aoncc_gfm_clks[] = {
+       [LPASS_CDC_VA_MCLK]             = &lpass_gfm_va_mclk,
+       [LPASS_CDC_TX_NPL]              = &lpass_gfm_tx_npl,
+};
+
+static struct clk_hw_onecell_data aoncc_hw_onecell_data = {
+       .hws = {
+               [LPASS_CDC_VA_MCLK]     = &lpass_gfm_va_mclk.hw,
+               [LPASS_CDC_TX_NPL]      = &lpass_gfm_tx_npl.hw,
+       },
+       .num = ARRAY_SIZE(aoncc_gfm_clks),
+};
+
+static struct clk_gfm *audiocc_gfm_clks[] = {
+       [LPASS_CDC_WSA_NPL]             = &lpass_gfm_wsa_npl,
+       [LPASS_CDC_WSA_MCLK]            = &lpass_gfm_wsa_mclk,
+       [LPASS_CDC_RX_NPL]              = &lpass_gfm_rx_npl,
+       [LPASS_CDC_RX_MCLK_MCLK2]       = &lpass_gfm_rx_mclk_mclk2,
+};
+
+static struct clk_hw_onecell_data audiocc_hw_onecell_data = {
+       .hws = {
+               [LPASS_CDC_WSA_NPL]     = &lpass_gfm_wsa_npl.hw,
+               [LPASS_CDC_WSA_MCLK]    = &lpass_gfm_wsa_mclk.hw,
+               [LPASS_CDC_RX_NPL]      = &lpass_gfm_rx_npl.hw,
+               [LPASS_CDC_RX_MCLK_MCLK2] = &lpass_gfm_rx_mclk_mclk2.hw,
+       },
+       .num = ARRAY_SIZE(audiocc_gfm_clks),
+};
+
+struct lpass_gfm_data {
+       struct clk_hw_onecell_data *onecell_data;
+       struct clk_gfm **gfm_clks;
+};
+
+static struct lpass_gfm_data audiocc_data = {
+       .onecell_data = &audiocc_hw_onecell_data,
+       .gfm_clks = audiocc_gfm_clks,
+};
+
+static struct lpass_gfm_data aoncc_data = {
+       .onecell_data = &aoncc_hw_onecell_data,
+       .gfm_clks = aoncc_gfm_clks,
+};
+
+static int lpass_gfm_clk_driver_probe(struct platform_device *pdev)
+{
+       const struct lpass_gfm_data *data;
+       struct device *dev = &pdev->dev;
+       struct clk_gfm *gfm;
+       struct lpass_gfm *cc;
+       int err, i;
+
+       data = of_device_get_match_data(dev);
+       if (!data)
+               return -EINVAL;
+
+       cc = devm_kzalloc(dev, sizeof(*cc), GFP_KERNEL);
+       if (!cc)
+               return -ENOMEM;
+
+       cc->base = devm_platform_ioremap_resource(pdev, 0);
+       if (IS_ERR(cc->base))
+               return PTR_ERR(cc->base);
+
+       pm_runtime_enable(dev);
+       err = pm_clk_create(dev);
+       if (err)
+               goto pm_clk_err;
+
+       err = of_pm_clk_add_clks(dev);
+       if (err < 0) {
+               dev_dbg(dev, "Failed to get lpass core voting clocks\n");
+               goto clk_reg_err;
+       }
+
+       for (i = 0; i < data->onecell_data->num; i++) {
+               if (!data->gfm_clks[i])
+                       continue;
+
+               gfm = data->gfm_clks[i];
+               gfm->priv = cc;
+               gfm->gfm_mux = cc->base;
+               gfm->gfm_mux = gfm->gfm_mux + data->gfm_clks[i]->mux_reg;
+
+               err = devm_clk_hw_register(dev, &data->gfm_clks[i]->hw);
+               if (err)
+                       goto clk_reg_err;
+
+       }
+
+       err = devm_of_clk_add_hw_provider(dev, of_clk_hw_onecell_get,
+                                         data->onecell_data);
+       if (err)
+               goto clk_reg_err;
+
+       return 0;
+
+clk_reg_err:
+       pm_clk_destroy(dev);
+pm_clk_err:
+       pm_runtime_disable(dev);
+       return err;
+}
+
+static const struct of_device_id lpass_gfm_clk_match_table[] = {
+       {
+               .compatible = "qcom,sm8250-lpass-aoncc",
+               .data = &aoncc_data,
+       },
+       {
+               .compatible = "qcom,sm8250-lpass-audiocc",
+               .data = &audiocc_data,
+       },
+       { }
+};
+MODULE_DEVICE_TABLE(of, lpass_gfm_clk_match_table);
+
+static const struct dev_pm_ops lpass_gfm_pm_ops = {
+       SET_RUNTIME_PM_OPS(pm_clk_suspend, pm_clk_resume, NULL)
+};
+
+static struct platform_driver lpass_gfm_clk_driver = {
+       .probe          = lpass_gfm_clk_driver_probe,
+       .driver         = {
+               .name   = "lpass-gfm-clk",
+               .of_match_table = lpass_gfm_clk_match_table,
+               .pm = &lpass_gfm_pm_ops,
+       },
+};
+module_platform_driver(lpass_gfm_clk_driver);
+MODULE_LICENSE("GPL v2");
index 228d08f..2e0ecc3 100644 (file)
@@ -356,12 +356,52 @@ static const struct qcom_cc_desc lpass_audio_hm_sc7180_desc = {
        .num_gdscs = ARRAY_SIZE(lpass_audio_hm_sc7180_gdscs),
 };
 
+static void lpass_pm_runtime_disable(void *data)
+{
+       pm_runtime_disable(data);
+}
+
+static void lpass_pm_clk_destroy(void *data)
+{
+       pm_clk_destroy(data);
+}
+
+static int lpass_create_pm_clks(struct platform_device *pdev)
+{
+       int ret;
+
+       pm_runtime_use_autosuspend(&pdev->dev);
+       pm_runtime_set_autosuspend_delay(&pdev->dev, 500);
+       pm_runtime_enable(&pdev->dev);
+
+       ret = devm_add_action_or_reset(&pdev->dev, lpass_pm_runtime_disable, &pdev->dev);
+       if (ret)
+               return ret;
+
+       ret = pm_clk_create(&pdev->dev);
+       if (ret)
+               return ret;
+       ret = devm_add_action_or_reset(&pdev->dev, lpass_pm_clk_destroy, &pdev->dev);
+       if (ret)
+               return ret;
+
+       ret = pm_clk_add(&pdev->dev, "iface");
+       if (ret < 0)
+               dev_err(&pdev->dev, "failed to acquire iface clock\n");
+
+       return ret;
+}
+
 static int lpass_core_cc_sc7180_probe(struct platform_device *pdev)
 {
        const struct qcom_cc_desc *desc;
        struct regmap *regmap;
        int ret;
 
+       ret = lpass_create_pm_clks(pdev);
+       if (ret)
+               return ret;
+
        lpass_core_cc_sc7180_regmap_config.name = "lpass_audio_cc";
        desc = &lpass_audio_hm_sc7180_desc;
        ret = qcom_cc_probe_by_index(pdev, 1, desc);
@@ -386,12 +426,22 @@ static int lpass_core_cc_sc7180_probe(struct platform_device *pdev)
        clk_fabia_pll_configure(&lpass_lpaaudio_dig_pll, regmap,
                                &lpass_lpaaudio_dig_pll_config);
 
-       return qcom_cc_really_probe(pdev, &lpass_core_cc_sc7180_desc, regmap);
+       ret = qcom_cc_really_probe(pdev, &lpass_core_cc_sc7180_desc, regmap);
+
+       pm_runtime_mark_last_busy(&pdev->dev);
+       pm_runtime_put_autosuspend(&pdev->dev);
+
+       return ret;
 }
 
 static int lpass_hm_core_probe(struct platform_device *pdev)
 {
        const struct qcom_cc_desc *desc;
+       int ret;
+
+       ret = lpass_create_pm_clks(pdev);
+       if (ret)
+               return ret;
 
        lpass_core_cc_sc7180_regmap_config.name = "lpass_hm_core";
        desc = &lpass_core_hm_sc7180_desc;
@@ -399,61 +449,28 @@ static int lpass_hm_core_probe(struct platform_device *pdev)
        return qcom_cc_probe_by_index(pdev, 0, desc);
 }
 
-static const struct of_device_id lpass_core_cc_sc7180_match_table[] = {
+static const struct of_device_id lpass_hm_sc7180_match_table[] = {
        {
                .compatible = "qcom,sc7180-lpasshm",
-               .data = lpass_hm_core_probe,
        },
+       { }
+};
+MODULE_DEVICE_TABLE(of, lpass_hm_sc7180_match_table);
+
+static const struct of_device_id lpass_core_cc_sc7180_match_table[] = {
        {
                .compatible = "qcom,sc7180-lpasscorecc",
-               .data = lpass_core_cc_sc7180_probe,
        },
        { }
 };
 MODULE_DEVICE_TABLE(of, lpass_core_cc_sc7180_match_table);
 
-static int lpass_core_sc7180_probe(struct platform_device *pdev)
-{
-       int (*clk_probe)(struct platform_device *p);
-       int ret;
-
-       pm_runtime_enable(&pdev->dev);
-       ret = pm_clk_create(&pdev->dev);
-       if (ret)
-               goto disable_pm_runtime;
-
-       ret = pm_clk_add(&pdev->dev, "iface");
-       if (ret < 0) {
-               dev_err(&pdev->dev, "failed to acquire iface clock\n");
-               goto destroy_pm_clk;
-       }
-
-       ret = -EINVAL;
-       clk_probe = of_device_get_match_data(&pdev->dev);
-       if (!clk_probe)
-               goto destroy_pm_clk;
-
-       ret = clk_probe(pdev);
-       if (ret)
-               goto destroy_pm_clk;
-
-       return 0;
-
-destroy_pm_clk:
-       pm_clk_destroy(&pdev->dev);
-
-disable_pm_runtime:
-       pm_runtime_disable(&pdev->dev);
-
-       return ret;
-}
-
 static const struct dev_pm_ops lpass_core_cc_pm_ops = {
        SET_RUNTIME_PM_OPS(pm_clk_suspend, pm_clk_resume, NULL)
 };
 
 static struct platform_driver lpass_core_cc_sc7180_driver = {
-       .probe = lpass_core_sc7180_probe,
+       .probe = lpass_core_cc_sc7180_probe,
        .driver = {
                .name = "lpass_core_cc-sc7180",
                .of_match_table = lpass_core_cc_sc7180_match_table,
@@ -461,17 +478,43 @@ static struct platform_driver lpass_core_cc_sc7180_driver = {
        },
 };
 
-static int __init lpass_core_cc_sc7180_init(void)
+static const struct dev_pm_ops lpass_hm_pm_ops = {
+       SET_RUNTIME_PM_OPS(pm_clk_suspend, pm_clk_resume, NULL)
+};
+
+static struct platform_driver lpass_hm_sc7180_driver = {
+       .probe = lpass_hm_core_probe,
+       .driver = {
+               .name = "lpass_hm-sc7180",
+               .of_match_table = lpass_hm_sc7180_match_table,
+               .pm = &lpass_hm_pm_ops,
+       },
+};
+
+static int __init lpass_sc7180_init(void)
 {
-       return platform_driver_register(&lpass_core_cc_sc7180_driver);
+       int ret;
+
+       ret = platform_driver_register(&lpass_core_cc_sc7180_driver);
+       if (ret)
+               return ret;
+
+       ret = platform_driver_register(&lpass_hm_sc7180_driver);
+       if (ret) {
+               platform_driver_unregister(&lpass_core_cc_sc7180_driver);
+               return ret;
+       }
+
+       return 0;
 }
-subsys_initcall(lpass_core_cc_sc7180_init);
+subsys_initcall(lpass_sc7180_init);
 
-static void __exit lpass_core_cc_sc7180_exit(void)
+static void __exit lpass_sc7180_exit(void)
 {
+       platform_driver_unregister(&lpass_hm_sc7180_driver);
        platform_driver_unregister(&lpass_core_cc_sc7180_driver);
 }
-module_exit(lpass_core_cc_sc7180_exit);
+module_exit(lpass_sc7180_exit);
 
 MODULE_DESCRIPTION("QTI LPASS_CORE_CC SC7180 Driver");
 MODULE_LICENSE("GPL v2");
index 5f25a70..4146c1d 100644 (file)
@@ -121,7 +121,7 @@ sh73a0_cpg_register_clock(struct device_node *np, struct sh73a0_cpg *cpg,
                        (phy_no ? CPG_DSI1PHYCR : CPG_DSI0PHYCR);
 
                parent_name = phy_no ? "dsi1pck" : "dsi0pck";
-               mult = __raw_readl(dsi_reg);
+               mult = readl(dsi_reg);
                if (!(mult & 0x8000))
                        mult = 1;
                else
index fd54b9f..4a43ebe 100644 (file)
@@ -41,6 +41,7 @@ enum clk_ids {
        CLK_S2,
        CLK_S3,
        CLK_SDSRC,
+       CLK_RPCSRC,
        CLK_RINT,
 
        /* Module Clocks */
@@ -67,6 +68,12 @@ static const struct cpg_core_clk r8a774a1_core_clks[] __initconst = {
        DEF_FIXED(".s2",        CLK_S2,            CLK_PLL1_DIV2,  4, 1),
        DEF_FIXED(".s3",        CLK_S3,            CLK_PLL1_DIV2,  6, 1),
        DEF_FIXED(".sdsrc",     CLK_SDSRC,         CLK_PLL1_DIV2,  2, 1),
+       DEF_BASE(".rpcsrc",     CLK_RPCSRC, CLK_TYPE_GEN3_RPCSRC, CLK_PLL1),
+
+       DEF_BASE("rpc",         R8A774A1_CLK_RPC, CLK_TYPE_GEN3_RPC,
+                CLK_RPCSRC),
+       DEF_BASE("rpcd2",       R8A774A1_CLK_RPCD2, CLK_TYPE_GEN3_RPCD2,
+                R8A774A1_CLK_RPC),
 
        DEF_GEN3_OSC(".r",      CLK_RINT,          CLK_EXTAL,      32),
 
@@ -200,6 +207,7 @@ static const struct mssr_mod_clk r8a774a1_mod_clks[] __initconst = {
        DEF_MOD("can-fd",                914,   R8A774A1_CLK_S3D2),
        DEF_MOD("can-if1",               915,   R8A774A1_CLK_S3D4),
        DEF_MOD("can-if0",               916,   R8A774A1_CLK_S3D4),
+       DEF_MOD("rpc-if",                917,   R8A774A1_CLK_RPCD2),
        DEF_MOD("i2c6",                  918,   R8A774A1_CLK_S0D6),
        DEF_MOD("i2c5",                  919,   R8A774A1_CLK_S0D6),
        DEF_MOD("i2c-dvfs",              926,   R8A774A1_CLK_CP),
index f436691..6f04c40 100644 (file)
@@ -40,6 +40,7 @@ enum clk_ids {
        CLK_S2,
        CLK_S3,
        CLK_SDSRC,
+       CLK_RPCSRC,
        CLK_RINT,
 
        /* Module Clocks */
@@ -65,6 +66,12 @@ static const struct cpg_core_clk r8a774b1_core_clks[] __initconst = {
        DEF_FIXED(".s2",        CLK_S2,            CLK_PLL1_DIV2,  4, 1),
        DEF_FIXED(".s3",        CLK_S3,            CLK_PLL1_DIV2,  6, 1),
        DEF_FIXED(".sdsrc",     CLK_SDSRC,         CLK_PLL1_DIV2,  2, 1),
+       DEF_BASE(".rpcsrc",     CLK_RPCSRC, CLK_TYPE_GEN3_RPCSRC, CLK_PLL1),
+
+       DEF_BASE("rpc",         R8A774B1_CLK_RPC, CLK_TYPE_GEN3_RPC,
+                CLK_RPCSRC),
+       DEF_BASE("rpcd2",       R8A774B1_CLK_RPCD2, CLK_TYPE_GEN3_RPCD2,
+                R8A774B1_CLK_RPC),
 
        DEF_GEN3_OSC(".r",      CLK_RINT,          CLK_EXTAL,      32),
 
@@ -196,6 +203,7 @@ static const struct mssr_mod_clk r8a774b1_mod_clks[] __initconst = {
        DEF_MOD("can-fd",                914,   R8A774B1_CLK_S3D2),
        DEF_MOD("can-if1",               915,   R8A774B1_CLK_S3D4),
        DEF_MOD("can-if0",               916,   R8A774B1_CLK_S3D4),
+       DEF_MOD("rpc-if",                917,   R8A774B1_CLK_RPCD2),
        DEF_MOD("i2c6",                  918,   R8A774B1_CLK_S0D6),
        DEF_MOD("i2c5",                  919,   R8A774B1_CLK_S0D6),
        DEF_MOD("i2c-dvfs",              926,   R8A774B1_CLK_CP),
index 9fc9fa9..ed3a2cf 100644 (file)
@@ -44,6 +44,7 @@ enum clk_ids {
        CLK_S2,
        CLK_S3,
        CLK_SDSRC,
+       CLK_RPCSRC,
        CLK_RINT,
        CLK_OCO,
 
@@ -74,6 +75,13 @@ static const struct cpg_core_clk r8a774c0_core_clks[] __initconst = {
        DEF_FIXED(".s3",       CLK_S3,             CLK_PLL1,       6, 1),
        DEF_FIXED(".sdsrc",    CLK_SDSRC,          CLK_PLL1,       2, 1),
 
+       DEF_FIXED_RPCSRC_E3(".rpcsrc", CLK_RPCSRC, CLK_PLL0, CLK_PLL1),
+
+       DEF_BASE("rpc",         R8A774C0_CLK_RPC, CLK_TYPE_GEN3_RPC,
+                CLK_RPCSRC),
+       DEF_BASE("rpcd2",       R8A774C0_CLK_RPCD2, CLK_TYPE_GEN3_RPCD2,
+                R8A774C0_CLK_RPC),
+
        DEF_DIV6_RO(".r",      CLK_RINT,           CLK_EXTAL, CPG_RCKCR, 32),
 
        DEF_RATE(".oco",       CLK_OCO,            8 * 1000 * 1000),
@@ -199,6 +207,7 @@ static const struct mssr_mod_clk r8a774c0_mod_clks[] __initconst = {
        DEF_MOD("can-fd",                914,   R8A774C0_CLK_S3D2),
        DEF_MOD("can-if1",               915,   R8A774C0_CLK_S3D4),
        DEF_MOD("can-if0",               916,   R8A774C0_CLK_S3D4),
+       DEF_MOD("rpc-if",                917,   R8A774C0_CLK_RPCD2),
        DEF_MOD("i2c6",                  918,   R8A774C0_CLK_S3D2),
        DEF_MOD("i2c5",                  919,   R8A774C0_CLK_S3D2),
        DEF_MOD("i2c-dvfs",              926,   R8A774C0_CLK_CP),
index 17ebbac..aa5389b 100644 (file)
@@ -26,7 +26,6 @@
 #include <dt-bindings/clock/r8a779a0-cpg-mssr.h>
 
 #include "renesas-cpg-mssr.h"
-#include "rcar-gen3-cpg.h"
 
 enum rcar_r8a779a0_clk_types {
        CLK_TYPE_R8A779A0_MAIN = CLK_TYPE_CUSTOM,
@@ -84,6 +83,14 @@ enum clk_ids {
        DEF_BASE(_name, _id, CLK_TYPE_R8A779A0_PLL2X_3X, CLK_MAIN, \
                 .offset = _offset)
 
+#define DEF_MDSEL(_name, _id, _md, _parent0, _div0, _parent1, _div1) \
+       DEF_BASE(_name, _id, CLK_TYPE_R8A779A0_MDSEL,   \
+                (_parent0) << 16 | (_parent1),         \
+                .div = (_div0) << 16 | (_div1), .offset = _md)
+
+#define DEF_OSC(_name, _id, _parent, _div)             \
+       DEF_BASE(_name, _id, CLK_TYPE_R8A779A0_OSC, _parent, .div = _div)
+
 static const struct cpg_core_clk r8a779a0_core_clks[] __initconst = {
        /* External Clock Inputs */
        DEF_INPUT("extal",  CLK_EXTAL),
@@ -136,15 +143,51 @@ static const struct cpg_core_clk r8a779a0_core_clks[] __initconst = {
        DEF_DIV6P1("canfd",     R8A779A0_CLK_CANFD,     CLK_PLL5_DIV4,  0x878),
        DEF_DIV6P1("csi0",      R8A779A0_CLK_CSI0,      CLK_PLL5_DIV4,  0x880),
 
-       DEF_GEN3_OSC("osc",     R8A779A0_CLK_OSC,       CLK_EXTAL,      8),
-       DEF_GEN3_MDSEL("r",     R8A779A0_CLK_R, 29, CLK_EXTALR, 1, CLK_OCO, 1),
+       DEF_OSC("osc",          R8A779A0_CLK_OSC,       CLK_EXTAL,      8),
+       DEF_MDSEL("r",          R8A779A0_CLK_R, 29, CLK_EXTALR, 1, CLK_OCO, 1),
 };
 
 static const struct mssr_mod_clk r8a779a0_mod_clks[] __initconst = {
+       DEF_MOD("csi40",        331,    R8A779A0_CLK_CSI0),
+       DEF_MOD("csi41",        400,    R8A779A0_CLK_CSI0),
+       DEF_MOD("csi42",        401,    R8A779A0_CLK_CSI0),
+       DEF_MOD("csi43",        402,    R8A779A0_CLK_CSI0),
        DEF_MOD("scif0",        702,    R8A779A0_CLK_S1D8),
        DEF_MOD("scif1",        703,    R8A779A0_CLK_S1D8),
        DEF_MOD("scif3",        704,    R8A779A0_CLK_S1D8),
        DEF_MOD("scif4",        705,    R8A779A0_CLK_S1D8),
+       DEF_MOD("vin00",        730,    R8A779A0_CLK_S1D1),
+       DEF_MOD("vin01",        731,    R8A779A0_CLK_S1D1),
+       DEF_MOD("vin02",        800,    R8A779A0_CLK_S1D1),
+       DEF_MOD("vin03",        801,    R8A779A0_CLK_S1D1),
+       DEF_MOD("vin04",        802,    R8A779A0_CLK_S1D1),
+       DEF_MOD("vin05",        803,    R8A779A0_CLK_S1D1),
+       DEF_MOD("vin06",        804,    R8A779A0_CLK_S1D1),
+       DEF_MOD("vin07",        805,    R8A779A0_CLK_S1D1),
+       DEF_MOD("vin10",        806,    R8A779A0_CLK_S1D1),
+       DEF_MOD("vin11",        807,    R8A779A0_CLK_S1D1),
+       DEF_MOD("vin12",        808,    R8A779A0_CLK_S1D1),
+       DEF_MOD("vin13",        809,    R8A779A0_CLK_S1D1),
+       DEF_MOD("vin14",        810,    R8A779A0_CLK_S1D1),
+       DEF_MOD("vin15",        811,    R8A779A0_CLK_S1D1),
+       DEF_MOD("vin16",        812,    R8A779A0_CLK_S1D1),
+       DEF_MOD("vin17",        813,    R8A779A0_CLK_S1D1),
+       DEF_MOD("vin20",        814,    R8A779A0_CLK_S1D1),
+       DEF_MOD("vin21",        815,    R8A779A0_CLK_S1D1),
+       DEF_MOD("vin22",        816,    R8A779A0_CLK_S1D1),
+       DEF_MOD("vin23",        817,    R8A779A0_CLK_S1D1),
+       DEF_MOD("vin24",        818,    R8A779A0_CLK_S1D1),
+       DEF_MOD("vin25",        819,    R8A779A0_CLK_S1D1),
+       DEF_MOD("vin26",        820,    R8A779A0_CLK_S1D1),
+       DEF_MOD("vin27",        821,    R8A779A0_CLK_S1D1),
+       DEF_MOD("vin30",        822,    R8A779A0_CLK_S1D1),
+       DEF_MOD("vin31",        823,    R8A779A0_CLK_S1D1),
+       DEF_MOD("vin32",        824,    R8A779A0_CLK_S1D1),
+       DEF_MOD("vin33",        825,    R8A779A0_CLK_S1D1),
+       DEF_MOD("vin34",        826,    R8A779A0_CLK_S1D1),
+       DEF_MOD("vin35",        827,    R8A779A0_CLK_S1D1),
+       DEF_MOD("vin36",        828,    R8A779A0_CLK_S1D1),
+       DEF_MOD("vin37",        829,    R8A779A0_CLK_S1D1),
 };
 
 static spinlock_t cpg_lock;
@@ -153,7 +196,7 @@ static const struct rcar_r8a779a0_cpg_pll_config *cpg_pll_config __initdata;
 static unsigned int cpg_clk_extalr __initdata;
 static u32 cpg_mode __initdata;
 
-struct clk * __init rcar_r8a779a0_cpg_clk_register(struct device *dev,
+static struct clk * __init rcar_r8a779a0_cpg_clk_register(struct device *dev,
        const struct cpg_core_clk *core, const struct cpg_mssr_info *info,
        struct clk **clks, void __iomem *base,
        struct raw_notifier_head *notifiers)
index 488f8b3..063b611 100644 (file)
@@ -224,10 +224,9 @@ static struct clk * __init cpg_z_clk_register(const char *name,
 #define CPG_SD_STP_MASK                (CPG_SD_STP_HCK | CPG_SD_STP_CK)
 #define CPG_SD_FC_MASK         (0x7 << 2 | 0x3 << 0)
 
-#define CPG_SD_DIV_TABLE_DATA(stp_hck, stp_ck, sd_srcfc, sd_fc, sd_div) \
+#define CPG_SD_DIV_TABLE_DATA(stp_hck, sd_srcfc, sd_fc, sd_div) \
 { \
        .val = ((stp_hck) ? CPG_SD_STP_HCK : 0) | \
-              ((stp_ck) ? CPG_SD_STP_CK : 0) | \
               ((sd_srcfc) << 2) | \
               ((sd_fc) << 0), \
        .div = (sd_div), \
@@ -247,36 +246,36 @@ struct sd_clock {
 };
 
 /* SDn divider
- *                     sd_srcfc   sd_fc   div
- * stp_hck   stp_ck    (div)      (div)     = sd_srcfc x sd_fc
- *-------------------------------------------------------------------
- *  0         0         0 (1)      1 (4)      4 : SDR104 / HS200 / HS400 (8 TAP)
- *  0         0         1 (2)      1 (4)      8 : SDR50
- *  1         0         2 (4)      1 (4)     16 : HS / SDR25
- *  1         0         3 (8)      1 (4)     32 : NS / SDR12
- *  1         0         4 (16)     1 (4)     64
- *  0         0         0 (1)      0 (2)      2
- *  0         0         1 (2)      0 (2)      4 : SDR104 / HS200 / HS400 (4 TAP)
- *  1         0         2 (4)      0 (2)      8
- *  1         0         3 (8)      0 (2)     16
- *  1         0         4 (16)     0 (2)     32
+ *           sd_srcfc   sd_fc   div
+ * stp_hck   (div)      (div)     = sd_srcfc x sd_fc
+ *---------------------------------------------------------
+ *  0         0 (1)      1 (4)      4 : SDR104 / HS200 / HS400 (8 TAP)
+ *  0         1 (2)      1 (4)      8 : SDR50
+ *  1         2 (4)      1 (4)     16 : HS / SDR25
+ *  1         3 (8)      1 (4)     32 : NS / SDR12
+ *  1         4 (16)     1 (4)     64
+ *  0         0 (1)      0 (2)      2
+ *  0         1 (2)      0 (2)      4 : SDR104 / HS200 / HS400 (4 TAP)
+ *  1         2 (4)      0 (2)      8
+ *  1         3 (8)      0 (2)     16
+ *  1         4 (16)     0 (2)     32
  *
  *  NOTE: There is a quirk option to ignore the first row of the dividers
  *  table when searching for suitable settings. This is because HS400 on
  *  early ES versions of H3 and M3-W requires a specific setting to work.
  */
 static const struct sd_div_table cpg_sd_div_table[] = {
-/*     CPG_SD_DIV_TABLE_DATA(stp_hck,  stp_ck,   sd_srcfc,   sd_fc,  sd_div) */
-       CPG_SD_DIV_TABLE_DATA(0,        0,        0,          1,        4),
-       CPG_SD_DIV_TABLE_DATA(0,        0,        1,          1,        8),
-       CPG_SD_DIV_TABLE_DATA(1,        0,        2,          1,       16),
-       CPG_SD_DIV_TABLE_DATA(1,        0,        3,          1,       32),
-       CPG_SD_DIV_TABLE_DATA(1,        0,        4,          1,       64),
-       CPG_SD_DIV_TABLE_DATA(0,        0,        0,          0,        2),
-       CPG_SD_DIV_TABLE_DATA(0,        0,        1,          0,        4),
-       CPG_SD_DIV_TABLE_DATA(1,        0,        2,          0,        8),
-       CPG_SD_DIV_TABLE_DATA(1,        0,        3,          0,       16),
-       CPG_SD_DIV_TABLE_DATA(1,        0,        4,          0,       32),
+/*     CPG_SD_DIV_TABLE_DATA(stp_hck,  sd_srcfc,   sd_fc,  sd_div) */
+       CPG_SD_DIV_TABLE_DATA(0,        0,          1,        4),
+       CPG_SD_DIV_TABLE_DATA(0,        1,          1,        8),
+       CPG_SD_DIV_TABLE_DATA(1,        2,          1,       16),
+       CPG_SD_DIV_TABLE_DATA(1,        3,          1,       32),
+       CPG_SD_DIV_TABLE_DATA(1,        4,          1,       64),
+       CPG_SD_DIV_TABLE_DATA(0,        0,          0,        2),
+       CPG_SD_DIV_TABLE_DATA(0,        1,          0,        4),
+       CPG_SD_DIV_TABLE_DATA(1,        2,          0,        8),
+       CPG_SD_DIV_TABLE_DATA(1,        3,          0,       16),
+       CPG_SD_DIV_TABLE_DATA(1,        4,          0,       32),
 };
 
 #define to_sd_clock(_hw) container_of(_hw, struct sd_clock, hw)
@@ -696,6 +695,34 @@ struct clk * __init rcar_gen3_cpg_clk_register(struct device *dev,
                                                  cpg_rpcsrc_div_table,
                                                  &cpg_lock);
 
+       case CLK_TYPE_GEN3_E3_RPCSRC:
+               /*
+                * Register RPCSRC as fixed factor clock based on the
+                * MD[4:1] pins and CPG_RPCCKCR[4:3] register value for
+                * which has been set prior to booting the kernel.
+                */
+               value = (readl(base + CPG_RPCCKCR) & GENMASK(4, 3)) >> 3;
+
+               switch (value) {
+               case 0:
+                       div = 5;
+                       break;
+               case 1:
+                       div = 3;
+                       break;
+               case 2:
+                       parent = clks[core->parent >> 16];
+                       if (IS_ERR(parent))
+                               return ERR_CAST(parent);
+                       div = core->div;
+                       break;
+               case 3:
+               default:
+                       div = 2;
+                       break;
+               }
+               break;
+
        case CLK_TYPE_GEN3_RPC:
                return cpg_rpc_clk_register(core->name, base,
                                            __clk_get_name(parent), notifiers);
index c4ac80c..3d949c4 100644 (file)
@@ -24,6 +24,7 @@ enum rcar_gen3_clk_types {
        CLK_TYPE_GEN3_OSC,      /* OSC EXTAL predivider and fixed divider */
        CLK_TYPE_GEN3_RCKSEL,   /* Select parent/divider using RCKCR.CKSEL */
        CLK_TYPE_GEN3_RPCSRC,
+       CLK_TYPE_GEN3_E3_RPCSRC,
        CLK_TYPE_GEN3_RPC,
        CLK_TYPE_GEN3_RPCD2,
 
@@ -54,6 +55,10 @@ enum rcar_gen3_clk_types {
 #define DEF_GEN3_Z(_name, _id, _type, _parent, _div, _offset)  \
        DEF_BASE(_name, _id, _type, _parent, .div = _div, .offset = _offset)
 
+#define DEF_FIXED_RPCSRC_E3(_name, _id, _parent0, _parent1)    \
+       DEF_BASE(_name, _id, CLK_TYPE_GEN3_E3_RPCSRC,   \
+                (_parent0) << 16 | (_parent1), .div = 8)
+
 struct rcar_gen3_cpg_pll_config {
        u8 extal_div;
        u8 pll1_mult;
index d4c0298..3abafd7 100644 (file)
@@ -160,7 +160,7 @@ static int rcar_usb2_clock_sel_probe(struct platform_device *pdev)
        if (ret < 0)
                return ret;
 
-       priv->rsts = devm_reset_control_array_get(dev, true, false);
+       priv->rsts = devm_reset_control_array_get_shared(dev);
        if (IS_ERR(priv->rsts))
                return PTR_ERR(priv->rsts);
 
index 94db883..1c3215d 100644 (file)
@@ -119,7 +119,8 @@ static const u16 srstclr_for_v3u[] = {
 };
 
 /**
- * Clock Pulse Generator / Module Standby and Software Reset Private Data
+ * struct cpg_mssr_priv - Clock Pulse Generator / Module Standby
+ *                        and Software Reset Private Data
  *
  * @rcdev: Optional reset controller entity
  * @dev: CPG/MSSR device
index 47cd6c5..effd050 100644 (file)
@@ -11,67 +11,77 @@ config COMMON_CLK_ROCKCHIP
 if COMMON_CLK_ROCKCHIP
 config CLK_PX30
        bool "Rockchip PX30 clock controller support"
+       depends on (ARM64 || COMPILE_TEST)
        default y
        help
          Build the driver for PX30 Clock Driver.
 
 config CLK_RV110X
        bool "Rockchip RV110x clock controller support"
+       depends on (ARM || COMPILE_TEST)
        default y
        help
          Build the driver for RV110x Clock Driver.
 
 config CLK_RK3036
        bool "Rockchip RK3036 clock controller support"
+       depends on (ARM || COMPILE_TEST)
        default y
        help
          Build the driver for RK3036 Clock Driver.
 
 config CLK_RK312X
        bool "Rockchip RK312x clock controller support"
+       depends on (ARM || COMPILE_TEST)
        default y
        help
          Build the driver for RK312x Clock Driver.
 
 config CLK_RK3188
        bool "Rockchip RK3188 clock controller support"
+       depends on (ARM || COMPILE_TEST)
        default y
        help
          Build the driver for RK3188 Clock Driver.
 
 config CLK_RK322X
        bool "Rockchip RK322x clock controller support"
+       depends on (ARM || COMPILE_TEST)
        default y
        help
          Build the driver for RK322x Clock Driver.
 
 config CLK_RK3288
        bool "Rockchip RK3288 clock controller support"
-       depends on ARM
+       depends on (ARM || COMPILE_TEST)
        default y
        help
          Build the driver for RK3288 Clock Driver.
 
 config CLK_RK3308
        bool "Rockchip RK3308 clock controller support"
+       depends on (ARM64 || COMPILE_TEST)
        default y
        help
          Build the driver for RK3308 Clock Driver.
 
 config CLK_RK3328
        bool "Rockchip RK3328 clock controller support"
+       depends on (ARM64 || COMPILE_TEST)
        default y
        help
          Build the driver for RK3328 Clock Driver.
 
 config CLK_RK3368
        bool "Rockchip RK3368 clock controller support"
+       depends on (ARM64 || COMPILE_TEST)
        default y
        help
          Build the driver for RK3368 Clock Driver.
 
 config CLK_RK3399
        tristate "Rockchip RK3399 clock controller support"
+       depends on (ARM64 || COMPILE_TEST)
        default y
        help
          Build the driver for RK3399 Clock Driver.
index 730020f..0b76ad3 100644 (file)
@@ -255,19 +255,19 @@ static struct rockchip_clk_branch common_spdif_fracmux __initdata =
                        RK2928_CLKSEL_CON(5), 8, 2, MFLAGS);
 
 static struct rockchip_clk_branch common_uart0_fracmux __initdata =
-       MUX(SCLK_UART0, "sclk_uart0", mux_sclk_uart0_p, 0,
+       MUX(SCLK_UART0, "sclk_uart0", mux_sclk_uart0_p, CLK_SET_RATE_PARENT,
                        RK2928_CLKSEL_CON(13), 8, 2, MFLAGS);
 
 static struct rockchip_clk_branch common_uart1_fracmux __initdata =
-       MUX(SCLK_UART1, "sclk_uart1", mux_sclk_uart1_p, 0,
+       MUX(SCLK_UART1, "sclk_uart1", mux_sclk_uart1_p, CLK_SET_RATE_PARENT,
                        RK2928_CLKSEL_CON(14), 8, 2, MFLAGS);
 
 static struct rockchip_clk_branch common_uart2_fracmux __initdata =
-       MUX(SCLK_UART2, "sclk_uart2", mux_sclk_uart2_p, 0,
+       MUX(SCLK_UART2, "sclk_uart2", mux_sclk_uart2_p, CLK_SET_RATE_PARENT,
                        RK2928_CLKSEL_CON(15), 8, 2, MFLAGS);
 
 static struct rockchip_clk_branch common_uart3_fracmux __initdata =
-       MUX(SCLK_UART3, "sclk_uart3", mux_sclk_uart3_p, 0,
+       MUX(SCLK_UART3, "sclk_uart3", mux_sclk_uart3_p, CLK_SET_RATE_PARENT,
                        RK2928_CLKSEL_CON(16), 8, 2, MFLAGS);
 
 static struct rockchip_clk_branch common_clk_branches[] __initdata = {
@@ -408,28 +408,28 @@ static struct rockchip_clk_branch common_clk_branches[] __initdata = {
        COMPOSITE_NOMUX(0, "uart0_pre", "uart_src", 0,
                        RK2928_CLKSEL_CON(13), 0, 7, DFLAGS,
                        RK2928_CLKGATE_CON(1), 8, GFLAGS),
-       COMPOSITE_FRACMUX(0, "uart0_frac", "uart0_pre", 0,
+       COMPOSITE_FRACMUX(0, "uart0_frac", "uart0_pre", CLK_SET_RATE_PARENT,
                        RK2928_CLKSEL_CON(17), 0,
                        RK2928_CLKGATE_CON(1), 9, GFLAGS,
                        &common_uart0_fracmux),
        COMPOSITE_NOMUX(0, "uart1_pre", "uart_src", 0,
                        RK2928_CLKSEL_CON(14), 0, 7, DFLAGS,
                        RK2928_CLKGATE_CON(1), 10, GFLAGS),
-       COMPOSITE_FRACMUX(0, "uart1_frac", "uart1_pre", 0,
+       COMPOSITE_FRACMUX(0, "uart1_frac", "uart1_pre", CLK_SET_RATE_PARENT,
                        RK2928_CLKSEL_CON(18), 0,
                        RK2928_CLKGATE_CON(1), 11, GFLAGS,
                        &common_uart1_fracmux),
        COMPOSITE_NOMUX(0, "uart2_pre", "uart_src", 0,
                        RK2928_CLKSEL_CON(15), 0, 7, DFLAGS,
                        RK2928_CLKGATE_CON(1), 12, GFLAGS),
-       COMPOSITE_FRACMUX(0, "uart2_frac", "uart2_pre", 0,
+       COMPOSITE_FRACMUX(0, "uart2_frac", "uart2_pre", CLK_SET_RATE_PARENT,
                        RK2928_CLKSEL_CON(19), 0,
                        RK2928_CLKGATE_CON(1), 13, GFLAGS,
                        &common_uart2_fracmux),
        COMPOSITE_NOMUX(0, "uart3_pre", "uart_src", 0,
                        RK2928_CLKSEL_CON(16), 0, 7, DFLAGS,
                        RK2928_CLKGATE_CON(1), 14, GFLAGS),
-       COMPOSITE_FRACMUX(0, "uart3_frac", "uart3_pre", 0,
+       COMPOSITE_FRACMUX(0, "uart3_frac", "uart3_pre", CLK_SET_RATE_PARENT,
                        RK2928_CLKSEL_CON(20), 0,
                        RK2928_CLKGATE_CON(1), 15, GFLAGS,
                        &common_uart3_fracmux),
@@ -449,7 +449,6 @@ static struct rockchip_clk_branch common_clk_branches[] __initdata = {
 
        /* hclk_cpu gates */
        GATE(HCLK_ROM, "hclk_rom", "hclk_cpu", 0, RK2928_CLKGATE_CON(5), 6, GFLAGS),
-       GATE(HCLK_I2S0, "hclk_i2s0", "hclk_cpu", 0, RK2928_CLKGATE_CON(7), 2, GFLAGS),
        GATE(HCLK_SPDIF, "hclk_spdif", "hclk_cpu", 0, RK2928_CLKGATE_CON(7), 1, GFLAGS),
        GATE(0, "hclk_cpubus", "hclk_cpu", 0, RK2928_CLKGATE_CON(4), 8, GFLAGS),
        /* hclk_ahb2apb is part of a clk branch */
@@ -543,15 +542,15 @@ static struct clk_div_table div_aclk_cpu_t[] = {
 };
 
 static struct rockchip_clk_branch rk3066a_i2s0_fracmux __initdata =
-       MUX(SCLK_I2S0, "sclk_i2s0", mux_sclk_i2s0_p, 0,
+       MUX(SCLK_I2S0, "sclk_i2s0", mux_sclk_i2s0_p, CLK_SET_RATE_PARENT,
                        RK2928_CLKSEL_CON(2), 8, 2, MFLAGS);
 
 static struct rockchip_clk_branch rk3066a_i2s1_fracmux __initdata =
-       MUX(SCLK_I2S1, "sclk_i2s1", mux_sclk_i2s1_p, 0,
+       MUX(SCLK_I2S1, "sclk_i2s1", mux_sclk_i2s1_p, CLK_SET_RATE_PARENT,
                        RK2928_CLKSEL_CON(3), 8, 2, MFLAGS);
 
 static struct rockchip_clk_branch rk3066a_i2s2_fracmux __initdata =
-       MUX(SCLK_I2S2, "sclk_i2s2", mux_sclk_i2s2_p, 0,
+       MUX(SCLK_I2S2, "sclk_i2s2", mux_sclk_i2s2_p, CLK_SET_RATE_PARENT,
                        RK2928_CLKSEL_CON(4), 8, 2, MFLAGS);
 
 static struct rockchip_clk_branch rk3066a_clk_branches[] __initdata = {
@@ -615,27 +614,28 @@ static struct rockchip_clk_branch rk3066a_clk_branches[] __initdata = {
        COMPOSITE_NOMUX(0, "i2s0_pre", "i2s_src", 0,
                        RK2928_CLKSEL_CON(2), 0, 7, DFLAGS,
                        RK2928_CLKGATE_CON(0), 7, GFLAGS),
-       COMPOSITE_FRACMUX(0, "i2s0_frac", "i2s0_pre", 0,
+       COMPOSITE_FRACMUX(0, "i2s0_frac", "i2s0_pre", CLK_SET_RATE_PARENT,
                        RK2928_CLKSEL_CON(6), 0,
                        RK2928_CLKGATE_CON(0), 8, GFLAGS,
                        &rk3066a_i2s0_fracmux),
        COMPOSITE_NOMUX(0, "i2s1_pre", "i2s_src", 0,
                        RK2928_CLKSEL_CON(3), 0, 7, DFLAGS,
                        RK2928_CLKGATE_CON(0), 9, GFLAGS),
-       COMPOSITE_FRACMUX(0, "i2s1_frac", "i2s1_pre", 0,
+       COMPOSITE_FRACMUX(0, "i2s1_frac", "i2s1_pre", CLK_SET_RATE_PARENT,
                        RK2928_CLKSEL_CON(7), 0,
                        RK2928_CLKGATE_CON(0), 10, GFLAGS,
                        &rk3066a_i2s1_fracmux),
        COMPOSITE_NOMUX(0, "i2s2_pre", "i2s_src", 0,
                        RK2928_CLKSEL_CON(4), 0, 7, DFLAGS,
                        RK2928_CLKGATE_CON(0), 11, GFLAGS),
-       COMPOSITE_FRACMUX(0, "i2s2_frac", "i2s2_pre", 0,
+       COMPOSITE_FRACMUX(0, "i2s2_frac", "i2s2_pre", CLK_SET_RATE_PARENT,
                        RK2928_CLKSEL_CON(8), 0,
                        RK2928_CLKGATE_CON(0), 12, GFLAGS,
                        &rk3066a_i2s2_fracmux),
 
-       GATE(HCLK_I2S1, "hclk_i2s1", "hclk_cpu", 0, RK2928_CLKGATE_CON(7), 3, GFLAGS),
-       GATE(HCLK_I2S2, "hclk_i2s2", "hclk_cpu", 0, RK2928_CLKGATE_CON(7), 4, GFLAGS),
+       GATE(HCLK_I2S0, "hclk_i2s0", "hclk_cpu", 0, RK2928_CLKGATE_CON(7), 4, GFLAGS),
+       GATE(HCLK_I2S1, "hclk_i2s1", "hclk_cpu", 0, RK2928_CLKGATE_CON(7), 2, GFLAGS),
+       GATE(HCLK_I2S2, "hclk_i2s2", "hclk_cpu", 0, RK2928_CLKGATE_CON(7), 3, GFLAGS),
        GATE(HCLK_CIF1, "hclk_cif1", "hclk_cpu", 0, RK2928_CLKGATE_CON(6), 6, GFLAGS),
        GATE(HCLK_HDMI, "hclk_hdmi", "hclk_cpu", 0, RK2928_CLKGATE_CON(4), 14, GFLAGS),
 
@@ -728,6 +728,7 @@ static struct rockchip_clk_branch rk3188_clk_branches[] __initdata = {
                        RK2928_CLKGATE_CON(0), 10, GFLAGS,
                        &rk3188_i2s0_fracmux),
 
+       GATE(HCLK_I2S0, "hclk_i2s0", "hclk_cpu", 0, RK2928_CLKGATE_CON(7), 2, GFLAGS),
        GATE(0, "hclk_imem0", "hclk_cpu", 0, RK2928_CLKGATE_CON(4), 14, GFLAGS),
        GATE(0, "hclk_imem1", "hclk_cpu", 0, RK2928_CLKGATE_CON(4), 15, GFLAGS),
 
index b443169..336481b 100644 (file)
@@ -603,8 +603,7 @@ void rockchip_clk_protect_critical(const char *const clocks[],
        for (i = 0; i < nclocks; i++) {
                struct clk *clk = __clk_lookup(clocks[i]);
 
-               if (clk)
-                       clk_prepare_enable(clk);
+               clk_prepare_enable(clk);
        }
 }
 EXPORT_SYMBOL_GPL(rockchip_clk_protect_critical);
index 57d4b3f..9323fcf 100644 (file)
@@ -2,10 +2,73 @@
 # Recent Exynos platforms should just select COMMON_CLK_SAMSUNG:
 config COMMON_CLK_SAMSUNG
        bool "Samsung Exynos clock controller support" if COMPILE_TEST
-       # Clocks on ARM64 SoCs (e.g. Exynos5433, Exynos7) are chosen by
-       # EXYNOS_ARM64_COMMON_CLK to avoid building them on ARMv7:
+       select S3C64XX_COMMON_CLK if ARM && ARCH_S3C64XX
+       select S5PV210_COMMON_CLK if ARM && ARCH_S5PV210
+       select EXYNOS_3250_COMMON_CLK if ARM && SOC_EXYNOS3250
+       select EXYNOS_4_COMMON_CLK if ARM && ARCH_EXYNOS4
+       select EXYNOS_5250_COMMON_CLK if ARM && SOC_EXYNOS5250
+       select EXYNOS_5260_COMMON_CLK if ARM && SOC_EXYNOS5260
+       select EXYNOS_5410_COMMON_CLK if ARM && SOC_EXYNOS5410
+       select EXYNOS_5420_COMMON_CLK if ARM && SOC_EXYNOS5420
        select EXYNOS_ARM64_COMMON_CLK if ARM64 && ARCH_EXYNOS
 
+config S3C64XX_COMMON_CLK
+       bool "Samsung S3C64xx clock controller support" if COMPILE_TEST
+       depends on COMMON_CLK_SAMSUNG
+       help
+         Support for the clock controller present on the Samsung S3C64xx SoCs.
+         Choose Y here only if you build for this SoC.
+
+config S5PV210_COMMON_CLK
+       bool "Samsung S5Pv210 clock controller support" if COMPILE_TEST
+       depends on COMMON_CLK_SAMSUNG
+       help
+         Support for the clock controller present on the Samsung S5Pv210 SoCs.
+         Choose Y here only if you build for this SoC.
+
+config EXYNOS_3250_COMMON_CLK
+       bool "Samsung Exynos3250 clock controller support" if COMPILE_TEST
+       depends on COMMON_CLK_SAMSUNG
+       help
+         Support for the clock controller present on the Samsung
+         Exynos3250 SoCs. Choose Y here only if you build for this SoC.
+
+config EXYNOS_4_COMMON_CLK
+       bool "Samsung Exynos4 clock controller support" if COMPILE_TEST
+       depends on COMMON_CLK_SAMSUNG
+       help
+         Support for the clock controller present on the Samsung
+         Exynos4212 and Exynos4412 SoCs. Choose Y here only if you build for
+         this SoC.
+
+config EXYNOS_5250_COMMON_CLK
+       bool "Samsung Exynos5250 clock controller support" if COMPILE_TEST
+       depends on COMMON_CLK_SAMSUNG
+       help
+         Support for the clock controller present on the Samsung
+         Exynos5250 SoCs. Choose Y here only if you build for this SoC.
+
+config EXYNOS_5260_COMMON_CLK
+       bool "Samsung Exynos5260 clock controller support" if COMPILE_TEST
+       depends on COMMON_CLK_SAMSUNG
+       help
+         Support for the clock controller present on the Samsung
+         Exynos5260 SoCs. Choose Y here only if you build for this SoC.
+
+config EXYNOS_5410_COMMON_CLK
+       bool "Samsung Exynos5410 clock controller support" if COMPILE_TEST
+       depends on COMMON_CLK_SAMSUNG
+       help
+         Support for the clock controller present on the Samsung
+         Exynos5410 SoCs. Choose Y here only if you build for this SoC.
+
+config EXYNOS_5420_COMMON_CLK
+       bool "Samsung Exynos5420 clock controller support" if COMPILE_TEST
+       depends on COMMON_CLK_SAMSUNG
+       help
+         Support for the clock controller present on the Samsung
+         Exynos5420 SoCs. Choose Y here only if you build for this SoC.
+
 config EXYNOS_ARM64_COMMON_CLK
        bool "Samsung Exynos ARMv8-family clock controller support" if COMPILE_TEST
        depends on COMMON_CLK_SAMSUNG
index 1a4e6b7..bb1433f 100644 (file)
@@ -4,15 +4,15 @@
 #
 
 obj-$(CONFIG_COMMON_CLK)       += clk.o clk-pll.o clk-cpu.o
-obj-$(CONFIG_SOC_EXYNOS3250)   += clk-exynos3250.o
-obj-$(CONFIG_ARCH_EXYNOS4)     += clk-exynos4.o
-obj-$(CONFIG_ARCH_EXYNOS4)     += clk-exynos4412-isp.o
-obj-$(CONFIG_SOC_EXYNOS5250)   += clk-exynos5250.o
-obj-$(CONFIG_SOC_EXYNOS5250)   += clk-exynos5-subcmu.o
-obj-$(CONFIG_SOC_EXYNOS5260)   += clk-exynos5260.o
-obj-$(CONFIG_SOC_EXYNOS5410)   += clk-exynos5410.o
-obj-$(CONFIG_SOC_EXYNOS5420)   += clk-exynos5420.o
-obj-$(CONFIG_SOC_EXYNOS5420)   += clk-exynos5-subcmu.o
+obj-$(CONFIG_EXYNOS_3250_COMMON_CLK)   += clk-exynos3250.o
+obj-$(CONFIG_EXYNOS_4_COMMON_CLK)      += clk-exynos4.o
+obj-$(CONFIG_EXYNOS_4_COMMON_CLK)      += clk-exynos4412-isp.o
+obj-$(CONFIG_EXYNOS_5250_COMMON_CLK)   += clk-exynos5250.o
+obj-$(CONFIG_EXYNOS_5250_COMMON_CLK)   += clk-exynos5-subcmu.o
+obj-$(CONFIG_EXYNOS_5260_COMMON_CLK)   += clk-exynos5260.o
+obj-$(CONFIG_EXYNOS_5410_COMMON_CLK)   += clk-exynos5410.o
+obj-$(CONFIG_EXYNOS_5420_COMMON_CLK)   += clk-exynos5420.o
+obj-$(CONFIG_EXYNOS_5420_COMMON_CLK)   += clk-exynos5-subcmu.o
 obj-$(CONFIG_EXYNOS_ARM64_COMMON_CLK)  += clk-exynos5433.o
 obj-$(CONFIG_EXYNOS_AUDSS_CLK_CON) += clk-exynos-audss.o
 obj-$(CONFIG_ARCH_EXYNOS)      += clk-exynos-clkout.o
@@ -21,5 +21,5 @@ obj-$(CONFIG_S3C2410_COMMON_CLK)+= clk-s3c2410.o
 obj-$(CONFIG_S3C2410_COMMON_DCLK)+= clk-s3c2410-dclk.o
 obj-$(CONFIG_S3C2412_COMMON_CLK)+= clk-s3c2412.o
 obj-$(CONFIG_S3C2443_COMMON_CLK)+= clk-s3c2443.o
-obj-$(CONFIG_ARCH_S3C64XX)     += clk-s3c64xx.o
-obj-$(CONFIG_ARCH_S5PV210)     += clk-s5pv210.o clk-s5pv210-audss.o
+obj-$(CONFIG_S3C64XX_COMMON_CLK)       += clk-s3c64xx.o
+obj-$(CONFIG_S5PV210_COMMON_CLK)       += clk-s5pv210.o clk-s5pv210-audss.o
index ac70ad7..5873a93 100644 (file)
@@ -8,14 +8,17 @@
 
 #include <linux/errno.h>
 #include <linux/hrtimer.h>
+#include <linux/iopoll.h>
 #include <linux/delay.h>
 #include <linux/slab.h>
+#include <linux/timekeeping.h>
 #include <linux/clk-provider.h>
 #include <linux/io.h>
 #include "clk.h"
 #include "clk-pll.h"
 
-#define PLL_TIMEOUT_MS         10
+#define PLL_TIMEOUT_US         20000U
+#define PLL_TIMEOUT_LOOPS      1000000U
 
 struct samsung_clk_pll {
        struct clk_hw           hw;
@@ -63,6 +66,53 @@ static long samsung_pll_round_rate(struct clk_hw *hw,
        return rate_table[i - 1].rate;
 }
 
+static bool pll_early_timeout = true;
+
+static int __init samsung_pll_disable_early_timeout(void)
+{
+       pll_early_timeout = false;
+       return 0;
+}
+arch_initcall(samsung_pll_disable_early_timeout);
+
+/* Wait until the PLL is locked */
+static int samsung_pll_lock_wait(struct samsung_clk_pll *pll,
+                                unsigned int reg_mask)
+{
+       int i, ret;
+       u32 val;
+
+       /*
+        * This function might be called when the timekeeping API can't be used
+        * to detect timeouts. One situation is when the clocksource is not yet
+        * initialized, another when the timekeeping is suspended. udelay() also
+        * cannot be used when the clocksource is not running on arm64, since
+        * the current timer is used as cycle counter. So a simple busy loop
+        * is used here in that special cases. The limit of iterations has been
+        * derived from experimental measurements of various PLLs on multiple
+        * Exynos SoC variants. Single register read time was usually in range
+        * 0.4...1.5 us, never less than 0.4 us.
+        */
+       if (pll_early_timeout || timekeeping_suspended) {
+               i = PLL_TIMEOUT_LOOPS;
+               while (i-- > 0) {
+                       if (readl_relaxed(pll->con_reg) & reg_mask)
+                               return 0;
+
+                       cpu_relax();
+               }
+               ret = -ETIMEDOUT;
+       } else {
+               ret = readl_relaxed_poll_timeout_atomic(pll->con_reg, val,
+                                       val & reg_mask, 0, PLL_TIMEOUT_US);
+       }
+
+       if (ret < 0)
+               pr_err("Could not lock PLL %s\n", clk_hw_get_name(&pll->hw));
+
+       return ret;
+}
+
 static int samsung_pll3xxx_enable(struct clk_hw *hw)
 {
        struct samsung_clk_pll *pll = to_clk_pll(hw);
@@ -72,13 +122,7 @@ static int samsung_pll3xxx_enable(struct clk_hw *hw)
        tmp |= BIT(pll->enable_offs);
        writel_relaxed(tmp, pll->con_reg);
 
-       /* wait lock time */
-       do {
-               cpu_relax();
-               tmp = readl_relaxed(pll->con_reg);
-       } while (!(tmp & BIT(pll->lock_offs)));
-
-       return 0;
+       return samsung_pll_lock_wait(pll, BIT(pll->lock_offs));
 }
 
 static void samsung_pll3xxx_disable(struct clk_hw *hw)
@@ -240,13 +284,10 @@ static int samsung_pll35xx_set_rate(struct clk_hw *hw, unsigned long drate,
                        (rate->sdiv << PLL35XX_SDIV_SHIFT);
        writel_relaxed(tmp, pll->con_reg);
 
-       /* Wait until the PLL is locked if it is enabled. */
-       if (tmp & BIT(pll->enable_offs)) {
-               do {
-                       cpu_relax();
-                       tmp = readl_relaxed(pll->con_reg);
-               } while (!(tmp & BIT(pll->lock_offs)));
-       }
+       /* Wait for PLL lock if the PLL is enabled */
+       if (tmp & BIT(pll->enable_offs))
+               return samsung_pll_lock_wait(pll, BIT(pll->lock_offs));
+
        return 0;
 }
 
@@ -318,7 +359,7 @@ static int samsung_pll36xx_set_rate(struct clk_hw *hw, unsigned long drate,
                                        unsigned long parent_rate)
 {
        struct samsung_clk_pll *pll = to_clk_pll(hw);
-       u32 tmp, pll_con0, pll_con1;
+       u32 pll_con0, pll_con1;
        const struct samsung_pll_rate_table *rate;
 
        rate = samsung_get_pll_settings(pll, drate);
@@ -356,13 +397,8 @@ static int samsung_pll36xx_set_rate(struct clk_hw *hw, unsigned long drate,
        pll_con1 |= rate->kdiv << PLL36XX_KDIV_SHIFT;
        writel_relaxed(pll_con1, pll->con_reg + 4);
 
-       /* wait_lock_time */
-       if (pll_con0 & BIT(pll->enable_offs)) {
-               do {
-                       cpu_relax();
-                       tmp = readl_relaxed(pll->con_reg);
-               } while (!(tmp & BIT(pll->lock_offs)));
-       }
+       if (pll_con0 & BIT(pll->enable_offs))
+               return samsung_pll_lock_wait(pll, BIT(pll->lock_offs));
 
        return 0;
 }
@@ -437,7 +473,6 @@ static int samsung_pll45xx_set_rate(struct clk_hw *hw, unsigned long drate,
        struct samsung_clk_pll *pll = to_clk_pll(hw);
        const struct samsung_pll_rate_table *rate;
        u32 con0, con1;
-       ktime_t start;
 
        /* Get required rate settings from table */
        rate = samsung_get_pll_settings(pll, drate);
@@ -488,21 +523,8 @@ static int samsung_pll45xx_set_rate(struct clk_hw *hw, unsigned long drate,
        writel_relaxed(con1, pll->con_reg + 0x4);
        writel_relaxed(con0, pll->con_reg);
 
-       /* Wait for locking. */
-       start = ktime_get();
-       while (!(readl_relaxed(pll->con_reg) & PLL45XX_LOCKED)) {
-               ktime_t delta = ktime_sub(ktime_get(), start);
-
-               if (ktime_to_ms(delta) > PLL_TIMEOUT_MS) {
-                       pr_err("%s: could not lock PLL %s\n",
-                                       __func__, clk_hw_get_name(hw));
-                       return -EFAULT;
-               }
-
-               cpu_relax();
-       }
-
-       return 0;
+       /* Wait for PLL lock */
+       return samsung_pll_lock_wait(pll, PLL45XX_LOCKED);
 }
 
 static const struct clk_ops samsung_pll45xx_clk_ops = {
@@ -588,7 +610,6 @@ static int samsung_pll46xx_set_rate(struct clk_hw *hw, unsigned long drate,
        struct samsung_clk_pll *pll = to_clk_pll(hw);
        const struct samsung_pll_rate_table *rate;
        u32 con0, con1, lock;
-       ktime_t start;
 
        /* Get required rate settings from table */
        rate = samsung_get_pll_settings(pll, drate);
@@ -647,21 +668,8 @@ static int samsung_pll46xx_set_rate(struct clk_hw *hw, unsigned long drate,
        writel_relaxed(con0, pll->con_reg);
        writel_relaxed(con1, pll->con_reg + 0x4);
 
-       /* Wait for locking. */
-       start = ktime_get();
-       while (!(readl_relaxed(pll->con_reg) & PLL46XX_LOCKED)) {
-               ktime_t delta = ktime_sub(ktime_get(), start);
-
-               if (ktime_to_ms(delta) > PLL_TIMEOUT_MS) {
-                       pr_err("%s: could not lock PLL %s\n",
-                                       __func__, clk_hw_get_name(hw));
-                       return -EFAULT;
-               }
-
-               cpu_relax();
-       }
-
-       return 0;
+       /* Wait for PLL lock */
+       return samsung_pll_lock_wait(pll, PLL46XX_LOCKED);
 }
 
 static const struct clk_ops samsung_pll46xx_clk_ops = {
@@ -1035,14 +1043,9 @@ static int samsung_pll2550xx_set_rate(struct clk_hw *hw, unsigned long drate,
                        (rate->sdiv << PLL2550XX_S_SHIFT);
        writel_relaxed(tmp, pll->con_reg);
 
-       /* wait_lock_time */
-       do {
-               cpu_relax();
-               tmp = readl_relaxed(pll->con_reg);
-       } while (!(tmp & (PLL2550XX_LOCK_STAT_MASK
-                       << PLL2550XX_LOCK_STAT_SHIFT)));
-
-       return 0;
+       /* Wait for PLL lock */
+       return samsung_pll_lock_wait(pll,
+                       PLL2550XX_LOCK_STAT_MASK << PLL2550XX_LOCK_STAT_SHIFT);
 }
 
 static const struct clk_ops samsung_pll2550xx_clk_ops = {
@@ -1132,13 +1135,9 @@ static int samsung_pll2650x_set_rate(struct clk_hw *hw, unsigned long drate,
        con1 |= ((rate->kdiv & PLL2650X_K_MASK) << PLL2650X_K_SHIFT);
        writel_relaxed(con1, pll->con_reg + 4);
 
-       do {
-               cpu_relax();
-               con0 = readl_relaxed(pll->con_reg);
-       } while (!(con0 & (PLL2650X_LOCK_STAT_MASK
-                       << PLL2650X_LOCK_STAT_SHIFT)));
-
-       return 0;
+       /* Wait for PLL lock */
+       return samsung_pll_lock_wait(pll,
+                       PLL2650X_LOCK_STAT_MASK << PLL2650X_LOCK_STAT_SHIFT);
 }
 
 static const struct clk_ops samsung_pll2650x_clk_ops = {
@@ -1196,7 +1195,7 @@ static int samsung_pll2650xx_set_rate(struct clk_hw *hw, unsigned long drate,
                                        unsigned long parent_rate)
 {
        struct samsung_clk_pll *pll = to_clk_pll(hw);
-       u32 tmp, pll_con0, pll_con2;
+       u32 pll_con0, pll_con2;
        const struct samsung_pll_rate_table *rate;
 
        rate = samsung_get_pll_settings(pll, drate);
@@ -1229,11 +1228,7 @@ static int samsung_pll2650xx_set_rate(struct clk_hw *hw, unsigned long drate,
        writel_relaxed(pll_con0, pll->con_reg);
        writel_relaxed(pll_con2, pll->con_reg + 8);
 
-       do {
-               tmp = readl_relaxed(pll->con_reg);
-       } while (!(tmp & (0x1 << PLL2650XX_PLL_LOCKTIME_SHIFT)));
-
-       return 0;
+       return samsung_pll_lock_wait(pll, 0x1 << PLL2650XX_PLL_LOCKTIME_SHIFT);
 }
 
 static const struct clk_ops samsung_pll2650xx_clk_ops = {
index f3b4eb9..1c14eb2 100644 (file)
@@ -8,12 +8,12 @@ menuconfig CLK_SIFIVE
 
 if CLK_SIFIVE
 
-config CLK_SIFIVE_FU540_PRCI
-       bool "PRCI driver for SiFive FU540 SoCs"
+config CLK_SIFIVE_PRCI
+       bool "PRCI driver for SiFive SoCs"
        select CLK_ANALOGBITS_WRPLL_CLN28HPC
        help
          Supports the Power Reset Clock interface (PRCI) IP block found in
-         FU540 SoCs.  If this kernel is meant to run on a SiFive FU540 SoC,
-         enable this driver.
+         FU540/FU740 SoCs. If this kernel is meant to run on a SiFive FU540/
+         FU740 SoCs, enable this driver.
 
 endif
index 0797f14..7b06fc0 100644 (file)
@@ -1,2 +1,2 @@
 # SPDX-License-Identifier: GPL-2.0-only
-obj-$(CONFIG_CLK_SIFIVE_FU540_PRCI)    += fu540-prci.o
+obj-$(CONFIG_CLK_SIFIVE_PRCI)  += sifive-prci.o fu540-prci.o fu740-prci.o
index a8901f9..29bab91 100644 (file)
@@ -1,17 +1,9 @@
 // SPDX-License-Identifier: GPL-2.0
 /*
  * Copyright (C) 2018-2019 SiFive, Inc.
- * Wesley Terpstra
- * Paul Walmsley
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
+ * Copyright (C) 2018-2019 Wesley Terpstra
+ * Copyright (C) 2018-2019 Paul Walmsley
+ * Copyright (C) 2020 Zong Li
  *
  * The FU540 PRCI implements clock and reset control for the SiFive
  * FU540-C000 chip.  This driver assumes that it has sole control
  * - SiFive FU540-C000 manual v1p0, Chapter 7 "Clocking and Reset"
  */
 
-#include <dt-bindings/clock/sifive-fu540-prci.h>
-#include <linux/clkdev.h>
-#include <linux/clk-provider.h>
-#include <linux/clk/analogbits-wrpll-cln28hpc.h>
-#include <linux/delay.h>
-#include <linux/err.h>
-#include <linux/io.h>
 #include <linux/module.h>
-#include <linux/of.h>
-#include <linux/of_clk.h>
-#include <linux/platform_device.h>
-#include <linux/slab.h>
-
-/*
- * EXPECTED_CLK_PARENT_COUNT: how many parent clocks this driver expects:
- *     hfclk and rtcclk
- */
-#define EXPECTED_CLK_PARENT_COUNT              2
-
-/*
- * Register offsets and bitmasks
- */
-
-/* COREPLLCFG0 */
-#define PRCI_COREPLLCFG0_OFFSET                        0x4
-# define PRCI_COREPLLCFG0_DIVR_SHIFT           0
-# define PRCI_COREPLLCFG0_DIVR_MASK            (0x3f << PRCI_COREPLLCFG0_DIVR_SHIFT)
-# define PRCI_COREPLLCFG0_DIVF_SHIFT           6
-# define PRCI_COREPLLCFG0_DIVF_MASK            (0x1ff << PRCI_COREPLLCFG0_DIVF_SHIFT)
-# define PRCI_COREPLLCFG0_DIVQ_SHIFT           15
-# define PRCI_COREPLLCFG0_DIVQ_MASK            (0x7 << PRCI_COREPLLCFG0_DIVQ_SHIFT)
-# define PRCI_COREPLLCFG0_RANGE_SHIFT          18
-# define PRCI_COREPLLCFG0_RANGE_MASK           (0x7 << PRCI_COREPLLCFG0_RANGE_SHIFT)
-# define PRCI_COREPLLCFG0_BYPASS_SHIFT         24
-# define PRCI_COREPLLCFG0_BYPASS_MASK          (0x1 << PRCI_COREPLLCFG0_BYPASS_SHIFT)
-# define PRCI_COREPLLCFG0_FSE_SHIFT            25
-# define PRCI_COREPLLCFG0_FSE_MASK             (0x1 << PRCI_COREPLLCFG0_FSE_SHIFT)
-# define PRCI_COREPLLCFG0_LOCK_SHIFT           31
-# define PRCI_COREPLLCFG0_LOCK_MASK            (0x1 << PRCI_COREPLLCFG0_LOCK_SHIFT)
 
-/* DDRPLLCFG0 */
-#define PRCI_DDRPLLCFG0_OFFSET                 0xc
-# define PRCI_DDRPLLCFG0_DIVR_SHIFT            0
-# define PRCI_DDRPLLCFG0_DIVR_MASK             (0x3f << PRCI_DDRPLLCFG0_DIVR_SHIFT)
-# define PRCI_DDRPLLCFG0_DIVF_SHIFT            6
-# define PRCI_DDRPLLCFG0_DIVF_MASK             (0x1ff << PRCI_DDRPLLCFG0_DIVF_SHIFT)
-# define PRCI_DDRPLLCFG0_DIVQ_SHIFT            15
-# define PRCI_DDRPLLCFG0_DIVQ_MASK             (0x7 << PRCI_DDRPLLCFG0_DIVQ_SHIFT)
-# define PRCI_DDRPLLCFG0_RANGE_SHIFT           18
-# define PRCI_DDRPLLCFG0_RANGE_MASK            (0x7 << PRCI_DDRPLLCFG0_RANGE_SHIFT)
-# define PRCI_DDRPLLCFG0_BYPASS_SHIFT          24
-# define PRCI_DDRPLLCFG0_BYPASS_MASK           (0x1 << PRCI_DDRPLLCFG0_BYPASS_SHIFT)
-# define PRCI_DDRPLLCFG0_FSE_SHIFT             25
-# define PRCI_DDRPLLCFG0_FSE_MASK              (0x1 << PRCI_DDRPLLCFG0_FSE_SHIFT)
-# define PRCI_DDRPLLCFG0_LOCK_SHIFT            31
-# define PRCI_DDRPLLCFG0_LOCK_MASK             (0x1 << PRCI_DDRPLLCFG0_LOCK_SHIFT)
-
-/* DDRPLLCFG1 */
-#define PRCI_DDRPLLCFG1_OFFSET                 0x10
-# define PRCI_DDRPLLCFG1_CKE_SHIFT             24
-# define PRCI_DDRPLLCFG1_CKE_MASK              (0x1 << PRCI_DDRPLLCFG1_CKE_SHIFT)
-
-/* GEMGXLPLLCFG0 */
-#define PRCI_GEMGXLPLLCFG0_OFFSET              0x1c
-# define PRCI_GEMGXLPLLCFG0_DIVR_SHIFT         0
-# define PRCI_GEMGXLPLLCFG0_DIVR_MASK          (0x3f << PRCI_GEMGXLPLLCFG0_DIVR_SHIFT)
-# define PRCI_GEMGXLPLLCFG0_DIVF_SHIFT         6
-# define PRCI_GEMGXLPLLCFG0_DIVF_MASK          (0x1ff << PRCI_GEMGXLPLLCFG0_DIVF_SHIFT)
-# define PRCI_GEMGXLPLLCFG0_DIVQ_SHIFT         15
-# define PRCI_GEMGXLPLLCFG0_DIVQ_MASK          (0x7 << PRCI_GEMGXLPLLCFG0_DIVQ_SHIFT)
-# define PRCI_GEMGXLPLLCFG0_RANGE_SHIFT                18
-# define PRCI_GEMGXLPLLCFG0_RANGE_MASK         (0x7 << PRCI_GEMGXLPLLCFG0_RANGE_SHIFT)
-# define PRCI_GEMGXLPLLCFG0_BYPASS_SHIFT       24
-# define PRCI_GEMGXLPLLCFG0_BYPASS_MASK                (0x1 << PRCI_GEMGXLPLLCFG0_BYPASS_SHIFT)
-# define PRCI_GEMGXLPLLCFG0_FSE_SHIFT          25
-# define PRCI_GEMGXLPLLCFG0_FSE_MASK           (0x1 << PRCI_GEMGXLPLLCFG0_FSE_SHIFT)
-# define PRCI_GEMGXLPLLCFG0_LOCK_SHIFT         31
-# define PRCI_GEMGXLPLLCFG0_LOCK_MASK          (0x1 << PRCI_GEMGXLPLLCFG0_LOCK_SHIFT)
-
-/* GEMGXLPLLCFG1 */
-#define PRCI_GEMGXLPLLCFG1_OFFSET              0x20
-# define PRCI_GEMGXLPLLCFG1_CKE_SHIFT          24
-# define PRCI_GEMGXLPLLCFG1_CKE_MASK           (0x1 << PRCI_GEMGXLPLLCFG1_CKE_SHIFT)
-
-/* CORECLKSEL */
-#define PRCI_CORECLKSEL_OFFSET                 0x24
-# define PRCI_CORECLKSEL_CORECLKSEL_SHIFT      0
-# define PRCI_CORECLKSEL_CORECLKSEL_MASK       (0x1 << PRCI_CORECLKSEL_CORECLKSEL_SHIFT)
-
-/* DEVICESRESETREG */
-#define PRCI_DEVICESRESETREG_OFFSET                    0x28
-# define PRCI_DEVICESRESETREG_DDR_CTRL_RST_N_SHIFT     0
-# define PRCI_DEVICESRESETREG_DDR_CTRL_RST_N_MASK      (0x1 << PRCI_DEVICESRESETREG_DDR_CTRL_RST_N_SHIFT)
-# define PRCI_DEVICESRESETREG_DDR_AXI_RST_N_SHIFT      1
-# define PRCI_DEVICESRESETREG_DDR_AXI_RST_N_MASK       (0x1 << PRCI_DEVICESRESETREG_DDR_AXI_RST_N_SHIFT)
-# define PRCI_DEVICESRESETREG_DDR_AHB_RST_N_SHIFT      2
-# define PRCI_DEVICESRESETREG_DDR_AHB_RST_N_MASK       (0x1 << PRCI_DEVICESRESETREG_DDR_AHB_RST_N_SHIFT)
-# define PRCI_DEVICESRESETREG_DDR_PHY_RST_N_SHIFT      3
-# define PRCI_DEVICESRESETREG_DDR_PHY_RST_N_MASK       (0x1 << PRCI_DEVICESRESETREG_DDR_PHY_RST_N_SHIFT)
-# define PRCI_DEVICESRESETREG_GEMGXL_RST_N_SHIFT       5
-# define PRCI_DEVICESRESETREG_GEMGXL_RST_N_MASK                (0x1 << PRCI_DEVICESRESETREG_GEMGXL_RST_N_SHIFT)
+#include <dt-bindings/clock/sifive-fu540-prci.h>
 
-/* CLKMUXSTATUSREG */
-#define PRCI_CLKMUXSTATUSREG_OFFSET                    0x2c
-# define PRCI_CLKMUXSTATUSREG_TLCLKSEL_STATUS_SHIFT    1
-# define PRCI_CLKMUXSTATUSREG_TLCLKSEL_STATUS_MASK     (0x1 << PRCI_CLKMUXSTATUSREG_TLCLKSEL_STATUS_SHIFT)
+#include "fu540-prci.h"
+#include "sifive-prci.h"
 
-/*
- * Private structures
- */
+/* PRCI integration data for each WRPLL instance */
 
-/**
- * struct __prci_data - per-device-instance data
- * @va: base virtual address of the PRCI IP block
- * @hw_clks: encapsulates struct clk_hw records
- *
- * PRCI per-device instance data
- */
-struct __prci_data {
-       void __iomem *va;
-       struct clk_hw_onecell_data hw_clks;
+static struct __prci_wrpll_data __prci_corepll_data = {
+       .cfg0_offs = PRCI_COREPLLCFG0_OFFSET,
+       .cfg1_offs = PRCI_COREPLLCFG1_OFFSET,
+       .enable_bypass = sifive_prci_coreclksel_use_hfclk,
+       .disable_bypass = sifive_prci_coreclksel_use_corepll,
 };
 
-/**
- * struct __prci_wrpll_data - WRPLL configuration and integration data
- * @c: WRPLL current configuration record
- * @enable_bypass: fn ptr to code to bypass the WRPLL (if applicable; else NULL)
- * @disable_bypass: fn ptr to code to not bypass the WRPLL (or NULL)
- * @cfg0_offs: WRPLL CFG0 register offset (in bytes) from the PRCI base address
- *
- * @enable_bypass and @disable_bypass are used for WRPLL instances
- * that contain a separate external glitchless clock mux downstream
- * from the PLL.  The WRPLL internal bypass mux is not glitchless.
- */
-struct __prci_wrpll_data {
-       struct wrpll_cfg c;
-       void (*enable_bypass)(struct __prci_data *pd);
-       void (*disable_bypass)(struct __prci_data *pd);
-       u8 cfg0_offs;
+static struct __prci_wrpll_data __prci_ddrpll_data = {
+       .cfg0_offs = PRCI_DDRPLLCFG0_OFFSET,
+       .cfg1_offs = PRCI_DDRPLLCFG1_OFFSET,
 };
 
-/**
- * struct __prci_clock - describes a clock device managed by PRCI
- * @name: user-readable clock name string - should match the manual
- * @parent_name: parent name for this clock
- * @ops: struct clk_ops for the Linux clock framework to use for control
- * @hw: Linux-private clock data
- * @pwd: WRPLL-specific data, associated with this clock (if not NULL)
- * @pd: PRCI-specific data associated with this clock (if not NULL)
- *
- * PRCI clock data.  Used by the PRCI driver to register PRCI-provided
- * clocks to the Linux clock infrastructure.
- */
-struct __prci_clock {
-       const char *name;
-       const char *parent_name;
-       const struct clk_ops *ops;
-       struct clk_hw hw;
-       struct __prci_wrpll_data *pwd;
-       struct __prci_data *pd;
+static struct __prci_wrpll_data __prci_gemgxlpll_data = {
+       .cfg0_offs = PRCI_GEMGXLPLLCFG0_OFFSET,
+       .cfg1_offs = PRCI_GEMGXLPLLCFG1_OFFSET,
 };
 
-#define clk_hw_to_prci_clock(pwd) container_of(pwd, struct __prci_clock, hw)
-
-/*
- * Private functions
- */
-
-/**
- * __prci_readl() - read from a PRCI register
- * @pd: PRCI context
- * @offs: register offset to read from (in bytes, from PRCI base address)
- *
- * Read the register located at offset @offs from the base virtual
- * address of the PRCI register target described by @pd, and return
- * the value to the caller.
- *
- * Context: Any context.
- *
- * Return: the contents of the register described by @pd and @offs.
- */
-static u32 __prci_readl(struct __prci_data *pd, u32 offs)
-{
-       return readl_relaxed(pd->va + offs);
-}
-
-static void __prci_writel(u32 v, u32 offs, struct __prci_data *pd)
-{
-       writel_relaxed(v, pd->va + offs);
-}
-
-/* WRPLL-related private functions */
-
-/**
- * __prci_wrpll_unpack() - unpack WRPLL configuration registers into parameters
- * @c: ptr to a struct wrpll_cfg record to write config into
- * @r: value read from the PRCI PLL configuration register
- *
- * Given a value @r read from an FU540 PRCI PLL configuration register,
- * split it into fields and populate it into the WRPLL configuration record
- * pointed to by @c.
- *
- * The COREPLLCFG0 macros are used below, but the other *PLLCFG0 macros
- * have the same register layout.
- *
- * Context: Any context.
- */
-static void __prci_wrpll_unpack(struct wrpll_cfg *c, u32 r)
-{
-       u32 v;
-
-       v = r & PRCI_COREPLLCFG0_DIVR_MASK;
-       v >>= PRCI_COREPLLCFG0_DIVR_SHIFT;
-       c->divr = v;
-
-       v = r & PRCI_COREPLLCFG0_DIVF_MASK;
-       v >>= PRCI_COREPLLCFG0_DIVF_SHIFT;
-       c->divf = v;
-
-       v = r & PRCI_COREPLLCFG0_DIVQ_MASK;
-       v >>= PRCI_COREPLLCFG0_DIVQ_SHIFT;
-       c->divq = v;
-
-       v = r & PRCI_COREPLLCFG0_RANGE_MASK;
-       v >>= PRCI_COREPLLCFG0_RANGE_SHIFT;
-       c->range = v;
-
-       c->flags &= (WRPLL_FLAGS_INT_FEEDBACK_MASK |
-                    WRPLL_FLAGS_EXT_FEEDBACK_MASK);
-
-       /* external feedback mode not supported */
-       c->flags |= WRPLL_FLAGS_INT_FEEDBACK_MASK;
-}
-
-/**
- * __prci_wrpll_pack() - pack PLL configuration parameters into a register value
- * @c: pointer to a struct wrpll_cfg record containing the PLL's cfg
- *
- * Using a set of WRPLL configuration values pointed to by @c,
- * assemble a PRCI PLL configuration register value, and return it to
- * the caller.
- *
- * Context: Any context.  Caller must ensure that the contents of the
- *          record pointed to by @c do not change during the execution
- *          of this function.
- *
- * Returns: a value suitable for writing into a PRCI PLL configuration
- *          register
- */
-static u32 __prci_wrpll_pack(const struct wrpll_cfg *c)
-{
-       u32 r = 0;
-
-       r |= c->divr << PRCI_COREPLLCFG0_DIVR_SHIFT;
-       r |= c->divf << PRCI_COREPLLCFG0_DIVF_SHIFT;
-       r |= c->divq << PRCI_COREPLLCFG0_DIVQ_SHIFT;
-       r |= c->range << PRCI_COREPLLCFG0_RANGE_SHIFT;
-
-       /* external feedback mode not supported */
-       r |= PRCI_COREPLLCFG0_FSE_MASK;
-
-       return r;
-}
-
-/**
- * __prci_wrpll_read_cfg() - read the WRPLL configuration from the PRCI
- * @pd: PRCI context
- * @pwd: PRCI WRPLL metadata
- *
- * Read the current configuration of the PLL identified by @pwd from
- * the PRCI identified by @pd, and store it into the local configuration
- * cache in @pwd.
- *
- * Context: Any context.  Caller must prevent the records pointed to by
- *          @pd and @pwd from changing during execution.
- */
-static void __prci_wrpll_read_cfg(struct __prci_data *pd,
-                                 struct __prci_wrpll_data *pwd)
-{
-       __prci_wrpll_unpack(&pwd->c, __prci_readl(pd, pwd->cfg0_offs));
-}
-
-/**
- * __prci_wrpll_write_cfg() - write WRPLL configuration into the PRCI
- * @pd: PRCI context
- * @pwd: PRCI WRPLL metadata
- * @c: WRPLL configuration record to write
- *
- * Write the WRPLL configuration described by @c into the WRPLL
- * configuration register identified by @pwd in the PRCI instance
- * described by @c.  Make a cached copy of the WRPLL's current
- * configuration so it can be used by other code.
- *
- * Context: Any context.  Caller must prevent the records pointed to by
- *          @pd and @pwd from changing during execution.
- */
-static void __prci_wrpll_write_cfg(struct __prci_data *pd,
-                                  struct __prci_wrpll_data *pwd,
-                                  struct wrpll_cfg *c)
-{
-       __prci_writel(__prci_wrpll_pack(c), pwd->cfg0_offs, pd);
-
-       memcpy(&pwd->c, c, sizeof(*c));
-}
-
-/* Core clock mux control */
-
-/**
- * __prci_coreclksel_use_hfclk() - switch the CORECLK mux to output HFCLK
- * @pd: struct __prci_data * for the PRCI containing the CORECLK mux reg
- *
- * Switch the CORECLK mux to the HFCLK input source; return once complete.
- *
- * Context: Any context.  Caller must prevent concurrent changes to the
- *          PRCI_CORECLKSEL_OFFSET register.
- */
-static void __prci_coreclksel_use_hfclk(struct __prci_data *pd)
-{
-       u32 r;
-
-       r = __prci_readl(pd, PRCI_CORECLKSEL_OFFSET);
-       r |= PRCI_CORECLKSEL_CORECLKSEL_MASK;
-       __prci_writel(r, PRCI_CORECLKSEL_OFFSET, pd);
-
-       r = __prci_readl(pd, PRCI_CORECLKSEL_OFFSET); /* barrier */
-}
-
-/**
- * __prci_coreclksel_use_corepll() - switch the CORECLK mux to output COREPLL
- * @pd: struct __prci_data * for the PRCI containing the CORECLK mux reg
- *
- * Switch the CORECLK mux to the PLL output clock; return once complete.
- *
- * Context: Any context.  Caller must prevent concurrent changes to the
- *          PRCI_CORECLKSEL_OFFSET register.
- */
-static void __prci_coreclksel_use_corepll(struct __prci_data *pd)
-{
-       u32 r;
-
-       r = __prci_readl(pd, PRCI_CORECLKSEL_OFFSET);
-       r &= ~PRCI_CORECLKSEL_CORECLKSEL_MASK;
-       __prci_writel(r, PRCI_CORECLKSEL_OFFSET, pd);
-
-       r = __prci_readl(pd, PRCI_CORECLKSEL_OFFSET); /* barrier */
-}
-
-/*
- * Linux clock framework integration
- *
- * See the Linux clock framework documentation for more information on
- * these functions.
- */
-
-static unsigned long sifive_fu540_prci_wrpll_recalc_rate(struct clk_hw *hw,
-                                                        unsigned long parent_rate)
-{
-       struct __prci_clock *pc = clk_hw_to_prci_clock(hw);
-       struct __prci_wrpll_data *pwd = pc->pwd;
-
-       return wrpll_calc_output_rate(&pwd->c, parent_rate);
-}
-
-static long sifive_fu540_prci_wrpll_round_rate(struct clk_hw *hw,
-                                              unsigned long rate,
-                                              unsigned long *parent_rate)
-{
-       struct __prci_clock *pc = clk_hw_to_prci_clock(hw);
-       struct __prci_wrpll_data *pwd = pc->pwd;
-       struct wrpll_cfg c;
-
-       memcpy(&c, &pwd->c, sizeof(c));
-
-       wrpll_configure_for_rate(&c, rate, *parent_rate);
-
-       return wrpll_calc_output_rate(&c, *parent_rate);
-}
-
-static int sifive_fu540_prci_wrpll_set_rate(struct clk_hw *hw,
-                                           unsigned long rate,
-                                           unsigned long parent_rate)
-{
-       struct __prci_clock *pc = clk_hw_to_prci_clock(hw);
-       struct __prci_wrpll_data *pwd = pc->pwd;
-       struct __prci_data *pd = pc->pd;
-       int r;
-
-       r = wrpll_configure_for_rate(&pwd->c, rate, parent_rate);
-       if (r)
-               return r;
-
-       if (pwd->enable_bypass)
-               pwd->enable_bypass(pd);
-
-       __prci_wrpll_write_cfg(pd, pwd, &pwd->c);
-
-       udelay(wrpll_calc_max_lock_us(&pwd->c));
-
-       if (pwd->disable_bypass)
-               pwd->disable_bypass(pd);
-
-       return 0;
-}
+/* Linux clock framework integration */
 
 static const struct clk_ops sifive_fu540_prci_wrpll_clk_ops = {
-       .set_rate = sifive_fu540_prci_wrpll_set_rate,
-       .round_rate = sifive_fu540_prci_wrpll_round_rate,
-       .recalc_rate = sifive_fu540_prci_wrpll_recalc_rate,
+       .set_rate = sifive_prci_wrpll_set_rate,
+       .round_rate = sifive_prci_wrpll_round_rate,
+       .recalc_rate = sifive_prci_wrpll_recalc_rate,
+       .enable = sifive_prci_clock_enable,
+       .disable = sifive_prci_clock_disable,
+       .is_enabled = sifive_clk_is_enabled,
 };
 
 static const struct clk_ops sifive_fu540_prci_wrpll_ro_clk_ops = {
-       .recalc_rate = sifive_fu540_prci_wrpll_recalc_rate,
+       .recalc_rate = sifive_prci_wrpll_recalc_rate,
 };
 
-/* TLCLKSEL clock integration */
-
-static unsigned long sifive_fu540_prci_tlclksel_recalc_rate(struct clk_hw *hw,
-                                                           unsigned long parent_rate)
-{
-       struct __prci_clock *pc = clk_hw_to_prci_clock(hw);
-       struct __prci_data *pd = pc->pd;
-       u32 v;
-       u8 div;
-
-       v = __prci_readl(pd, PRCI_CLKMUXSTATUSREG_OFFSET);
-       v &= PRCI_CLKMUXSTATUSREG_TLCLKSEL_STATUS_MASK;
-       div = v ? 1 : 2;
-
-       return div_u64(parent_rate, div);
-}
-
 static const struct clk_ops sifive_fu540_prci_tlclksel_clk_ops = {
-       .recalc_rate = sifive_fu540_prci_tlclksel_recalc_rate,
-};
-
-/*
- * PRCI integration data for each WRPLL instance
- */
-
-static struct __prci_wrpll_data __prci_corepll_data = {
-       .cfg0_offs = PRCI_COREPLLCFG0_OFFSET,
-       .enable_bypass = __prci_coreclksel_use_hfclk,
-       .disable_bypass = __prci_coreclksel_use_corepll,
-};
-
-static struct __prci_wrpll_data __prci_ddrpll_data = {
-       .cfg0_offs = PRCI_DDRPLLCFG0_OFFSET,
+       .recalc_rate = sifive_prci_tlclksel_recalc_rate,
 };
 
-static struct __prci_wrpll_data __prci_gemgxlpll_data = {
-       .cfg0_offs = PRCI_GEMGXLPLLCFG0_OFFSET,
-};
-
-/*
- * List of clock controls provided by the PRCI
- */
-
-static struct __prci_clock __prci_init_clocks[] = {
+/* List of clock controls provided by the PRCI */
+struct __prci_clock __prci_init_clocks_fu540[] = {
        [PRCI_CLK_COREPLL] = {
                .name = "corepll",
                .parent_name = "hfclk",
@@ -506,125 +87,3 @@ static struct __prci_clock __prci_init_clocks[] = {
                .ops = &sifive_fu540_prci_tlclksel_clk_ops,
        },
 };
-
-/**
- * __prci_register_clocks() - register clock controls in the PRCI with Linux
- * @dev: Linux struct device *
- *
- * Register the list of clock controls described in __prci_init_plls[] with
- * the Linux clock framework.
- *
- * Return: 0 upon success or a negative error code upon failure.
- */
-static int __prci_register_clocks(struct device *dev, struct __prci_data *pd)
-{
-       struct clk_init_data init = { };
-       struct __prci_clock *pic;
-       int parent_count, i, r;
-
-       parent_count = of_clk_get_parent_count(dev->of_node);
-       if (parent_count != EXPECTED_CLK_PARENT_COUNT) {
-               dev_err(dev, "expected only two parent clocks, found %d\n",
-                       parent_count);
-               return -EINVAL;
-       }
-
-       /* Register PLLs */
-       for (i = 0; i < ARRAY_SIZE(__prci_init_clocks); ++i) {
-               pic = &__prci_init_clocks[i];
-
-               init.name = pic->name;
-               init.parent_names = &pic->parent_name;
-               init.num_parents = 1;
-               init.ops = pic->ops;
-               pic->hw.init = &init;
-
-               pic->pd = pd;
-
-               if (pic->pwd)
-                       __prci_wrpll_read_cfg(pd, pic->pwd);
-
-               r = devm_clk_hw_register(dev, &pic->hw);
-               if (r) {
-                       dev_warn(dev, "Failed to register clock %s: %d\n",
-                                init.name, r);
-                       return r;
-               }
-
-               r = clk_hw_register_clkdev(&pic->hw, pic->name, dev_name(dev));
-               if (r) {
-                       dev_warn(dev, "Failed to register clkdev for %s: %d\n",
-                                init.name, r);
-                       return r;
-               }
-
-               pd->hw_clks.hws[i] = &pic->hw;
-       }
-
-       pd->hw_clks.num = i;
-
-       r = devm_of_clk_add_hw_provider(dev, of_clk_hw_onecell_get,
-                                       &pd->hw_clks);
-       if (r) {
-               dev_err(dev, "could not add hw_provider: %d\n", r);
-               return r;
-       }
-
-       return 0;
-}
-
-/*
- * Linux device model integration
- *
- * See the Linux device model documentation for more information about
- * these functions.
- */
-static int sifive_fu540_prci_probe(struct platform_device *pdev)
-{
-       struct device *dev = &pdev->dev;
-       struct resource *res;
-       struct __prci_data *pd;
-       int r;
-
-       pd = devm_kzalloc(dev,
-                         struct_size(pd, hw_clks.hws,
-                                     ARRAY_SIZE(__prci_init_clocks)),
-                         GFP_KERNEL);
-       if (!pd)
-               return -ENOMEM;
-
-       res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-       pd->va = devm_ioremap_resource(dev, res);
-       if (IS_ERR(pd->va))
-               return PTR_ERR(pd->va);
-
-       r = __prci_register_clocks(dev, pd);
-       if (r) {
-               dev_err(dev, "could not register clocks: %d\n", r);
-               return r;
-       }
-
-       dev_dbg(dev, "SiFive FU540 PRCI probed\n");
-
-       return 0;
-}
-
-static const struct of_device_id sifive_fu540_prci_of_match[] = {
-       { .compatible = "sifive,fu540-c000-prci", },
-       {}
-};
-MODULE_DEVICE_TABLE(of, sifive_fu540_prci_of_match);
-
-static struct platform_driver sifive_fu540_prci_driver = {
-       .driver = {
-               .name = "sifive-fu540-prci",
-               .of_match_table = sifive_fu540_prci_of_match,
-       },
-       .probe = sifive_fu540_prci_probe,
-};
-
-static int __init sifive_fu540_prci_init(void)
-{
-       return platform_driver_register(&sifive_fu540_prci_driver);
-}
-core_initcall(sifive_fu540_prci_init);
diff --git a/drivers/clk/sifive/fu540-prci.h b/drivers/clk/sifive/fu540-prci.h
new file mode 100644 (file)
index 0000000..c8271ef
--- /dev/null
@@ -0,0 +1,21 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * Copyright (C) 2020 SiFive, Inc.
+ * Zong Li
+ */
+
+#ifndef __SIFIVE_CLK_FU540_PRCI_H
+#define __SIFIVE_CLK_FU540_PRCI_H
+
+#include "sifive-prci.h"
+
+#define NUM_CLOCK_FU540        4
+
+extern struct __prci_clock __prci_init_clocks_fu540[NUM_CLOCK_FU540];
+
+static const struct prci_clk_desc prci_clk_fu540 = {
+       .clks = __prci_init_clocks_fu540,
+       .num_clks = ARRAY_SIZE(__prci_init_clocks_fu540),
+};
+
+#endif /* __SIFIVE_CLK_FU540_PRCI_H */
diff --git a/drivers/clk/sifive/fu740-prci.c b/drivers/clk/sifive/fu740-prci.c
new file mode 100644 (file)
index 0000000..764d109
--- /dev/null
@@ -0,0 +1,123 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (C) 2020 SiFive, Inc.
+ * Copyright (C) 2020 Zong Li
+ */
+
+#include <linux/module.h>
+
+#include <dt-bindings/clock/sifive-fu740-prci.h>
+
+#include "fu540-prci.h"
+#include "sifive-prci.h"
+
+/* PRCI integration data for each WRPLL instance */
+
+static struct __prci_wrpll_data __prci_corepll_data = {
+       .cfg0_offs = PRCI_COREPLLCFG0_OFFSET,
+       .cfg1_offs = PRCI_COREPLLCFG1_OFFSET,
+       .enable_bypass = sifive_prci_coreclksel_use_hfclk,
+       .disable_bypass = sifive_prci_coreclksel_use_final_corepll,
+};
+
+static struct __prci_wrpll_data __prci_ddrpll_data = {
+       .cfg0_offs = PRCI_DDRPLLCFG0_OFFSET,
+       .cfg1_offs = PRCI_DDRPLLCFG1_OFFSET,
+};
+
+static struct __prci_wrpll_data __prci_gemgxlpll_data = {
+       .cfg0_offs = PRCI_GEMGXLPLLCFG0_OFFSET,
+       .cfg1_offs = PRCI_GEMGXLPLLCFG1_OFFSET,
+};
+
+static struct __prci_wrpll_data __prci_dvfscorepll_data = {
+       .cfg0_offs = PRCI_DVFSCOREPLLCFG0_OFFSET,
+       .cfg1_offs = PRCI_DVFSCOREPLLCFG1_OFFSET,
+       .enable_bypass = sifive_prci_corepllsel_use_corepll,
+       .disable_bypass = sifive_prci_corepllsel_use_dvfscorepll,
+};
+
+static struct __prci_wrpll_data __prci_hfpclkpll_data = {
+       .cfg0_offs = PRCI_HFPCLKPLLCFG0_OFFSET,
+       .cfg1_offs = PRCI_HFPCLKPLLCFG1_OFFSET,
+       .enable_bypass = sifive_prci_hfpclkpllsel_use_hfclk,
+       .disable_bypass = sifive_prci_hfpclkpllsel_use_hfpclkpll,
+};
+
+static struct __prci_wrpll_data __prci_cltxpll_data = {
+       .cfg0_offs = PRCI_CLTXPLLCFG0_OFFSET,
+       .cfg1_offs = PRCI_CLTXPLLCFG1_OFFSET,
+};
+
+/* Linux clock framework integration */
+
+static const struct clk_ops sifive_fu740_prci_wrpll_clk_ops = {
+       .set_rate = sifive_prci_wrpll_set_rate,
+       .round_rate = sifive_prci_wrpll_round_rate,
+       .recalc_rate = sifive_prci_wrpll_recalc_rate,
+       .enable = sifive_prci_clock_enable,
+       .disable = sifive_prci_clock_disable,
+       .is_enabled = sifive_clk_is_enabled,
+};
+
+static const struct clk_ops sifive_fu740_prci_wrpll_ro_clk_ops = {
+       .recalc_rate = sifive_prci_wrpll_recalc_rate,
+};
+
+static const struct clk_ops sifive_fu740_prci_tlclksel_clk_ops = {
+       .recalc_rate = sifive_prci_tlclksel_recalc_rate,
+};
+
+static const struct clk_ops sifive_fu740_prci_hfpclkplldiv_clk_ops = {
+       .recalc_rate = sifive_prci_hfpclkplldiv_recalc_rate,
+};
+
+/* List of clock controls provided by the PRCI */
+struct __prci_clock __prci_init_clocks_fu740[] = {
+       [PRCI_CLK_COREPLL] = {
+               .name = "corepll",
+               .parent_name = "hfclk",
+               .ops = &sifive_fu740_prci_wrpll_clk_ops,
+               .pwd = &__prci_corepll_data,
+       },
+       [PRCI_CLK_DDRPLL] = {
+               .name = "ddrpll",
+               .parent_name = "hfclk",
+               .ops = &sifive_fu740_prci_wrpll_ro_clk_ops,
+               .pwd = &__prci_ddrpll_data,
+       },
+       [PRCI_CLK_GEMGXLPLL] = {
+               .name = "gemgxlpll",
+               .parent_name = "hfclk",
+               .ops = &sifive_fu740_prci_wrpll_clk_ops,
+               .pwd = &__prci_gemgxlpll_data,
+       },
+       [PRCI_CLK_DVFSCOREPLL] = {
+               .name = "dvfscorepll",
+               .parent_name = "hfclk",
+               .ops = &sifive_fu740_prci_wrpll_clk_ops,
+               .pwd = &__prci_dvfscorepll_data,
+       },
+       [PRCI_CLK_HFPCLKPLL] = {
+               .name = "hfpclkpll",
+               .parent_name = "hfclk",
+               .ops = &sifive_fu740_prci_wrpll_clk_ops,
+               .pwd = &__prci_hfpclkpll_data,
+       },
+       [PRCI_CLK_CLTXPLL] = {
+               .name = "cltxpll",
+               .parent_name = "hfclk",
+               .ops = &sifive_fu740_prci_wrpll_clk_ops,
+               .pwd = &__prci_cltxpll_data,
+       },
+       [PRCI_CLK_TLCLK] = {
+               .name = "tlclk",
+               .parent_name = "corepll",
+               .ops = &sifive_fu740_prci_tlclksel_clk_ops,
+       },
+       [PRCI_CLK_PCLK] = {
+               .name = "pclk",
+               .parent_name = "hfpclkpll",
+               .ops = &sifive_fu740_prci_hfpclkplldiv_clk_ops,
+       },
+};
diff --git a/drivers/clk/sifive/fu740-prci.h b/drivers/clk/sifive/fu740-prci.h
new file mode 100644 (file)
index 0000000..13ef971
--- /dev/null
@@ -0,0 +1,21 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * Copyright (C) 2020 SiFive, Inc.
+ * Zong Li
+ */
+
+#ifndef __SIFIVE_CLK_FU740_PRCI_H
+#define __SIFIVE_CLK_FU740_PRCI_H
+
+#include "sifive-prci.h"
+
+#define NUM_CLOCK_FU740        8
+
+extern struct __prci_clock __prci_init_clocks_fu740[NUM_CLOCK_FU740];
+
+static const struct prci_clk_desc prci_clk_fu740 = {
+       .clks = __prci_init_clocks_fu740,
+       .num_clks = ARRAY_SIZE(__prci_init_clocks_fu740),
+};
+
+#endif /* __SIFIVE_CLK_FU740_PRCI_H */
diff --git a/drivers/clk/sifive/sifive-prci.c b/drivers/clk/sifive/sifive-prci.c
new file mode 100644 (file)
index 0000000..c78b042
--- /dev/null
@@ -0,0 +1,574 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (C) 2020 SiFive, Inc.
+ * Copyright (C) 2020 Zong Li
+ */
+
+#include <linux/clkdev.h>
+#include <linux/delay.h>
+#include <linux/io.h>
+#include <linux/of_device.h>
+#include "sifive-prci.h"
+#include "fu540-prci.h"
+#include "fu740-prci.h"
+
+/*
+ * Private functions
+ */
+
+/**
+ * __prci_readl() - read from a PRCI register
+ * @pd: PRCI context
+ * @offs: register offset to read from (in bytes, from PRCI base address)
+ *
+ * Read the register located at offset @offs from the base virtual
+ * address of the PRCI register target described by @pd, and return
+ * the value to the caller.
+ *
+ * Context: Any context.
+ *
+ * Return: the contents of the register described by @pd and @offs.
+ */
+static u32 __prci_readl(struct __prci_data *pd, u32 offs)
+{
+       return readl_relaxed(pd->va + offs);
+}
+
+static void __prci_writel(u32 v, u32 offs, struct __prci_data *pd)
+{
+       writel_relaxed(v, pd->va + offs);
+}
+
+/* WRPLL-related private functions */
+
+/**
+ * __prci_wrpll_unpack() - unpack WRPLL configuration registers into parameters
+ * @c: ptr to a struct wrpll_cfg record to write config into
+ * @r: value read from the PRCI PLL configuration register
+ *
+ * Given a value @r read from an FU740 PRCI PLL configuration register,
+ * split it into fields and populate it into the WRPLL configuration record
+ * pointed to by @c.
+ *
+ * The COREPLLCFG0 macros are used below, but the other *PLLCFG0 macros
+ * have the same register layout.
+ *
+ * Context: Any context.
+ */
+static void __prci_wrpll_unpack(struct wrpll_cfg *c, u32 r)
+{
+       u32 v;
+
+       v = r & PRCI_COREPLLCFG0_DIVR_MASK;
+       v >>= PRCI_COREPLLCFG0_DIVR_SHIFT;
+       c->divr = v;
+
+       v = r & PRCI_COREPLLCFG0_DIVF_MASK;
+       v >>= PRCI_COREPLLCFG0_DIVF_SHIFT;
+       c->divf = v;
+
+       v = r & PRCI_COREPLLCFG0_DIVQ_MASK;
+       v >>= PRCI_COREPLLCFG0_DIVQ_SHIFT;
+       c->divq = v;
+
+       v = r & PRCI_COREPLLCFG0_RANGE_MASK;
+       v >>= PRCI_COREPLLCFG0_RANGE_SHIFT;
+       c->range = v;
+
+       c->flags &=
+           (WRPLL_FLAGS_INT_FEEDBACK_MASK | WRPLL_FLAGS_EXT_FEEDBACK_MASK);
+
+       /* external feedback mode not supported */
+       c->flags |= WRPLL_FLAGS_INT_FEEDBACK_MASK;
+}
+
+/**
+ * __prci_wrpll_pack() - pack PLL configuration parameters into a register value
+ * @c: pointer to a struct wrpll_cfg record containing the PLL's cfg
+ *
+ * Using a set of WRPLL configuration values pointed to by @c,
+ * assemble a PRCI PLL configuration register value, and return it to
+ * the caller.
+ *
+ * Context: Any context.  Caller must ensure that the contents of the
+ *          record pointed to by @c do not change during the execution
+ *          of this function.
+ *
+ * Returns: a value suitable for writing into a PRCI PLL configuration
+ *          register
+ */
+static u32 __prci_wrpll_pack(const struct wrpll_cfg *c)
+{
+       u32 r = 0;
+
+       r |= c->divr << PRCI_COREPLLCFG0_DIVR_SHIFT;
+       r |= c->divf << PRCI_COREPLLCFG0_DIVF_SHIFT;
+       r |= c->divq << PRCI_COREPLLCFG0_DIVQ_SHIFT;
+       r |= c->range << PRCI_COREPLLCFG0_RANGE_SHIFT;
+
+       /* external feedback mode not supported */
+       r |= PRCI_COREPLLCFG0_FSE_MASK;
+
+       return r;
+}
+
+/**
+ * __prci_wrpll_read_cfg0() - read the WRPLL configuration from the PRCI
+ * @pd: PRCI context
+ * @pwd: PRCI WRPLL metadata
+ *
+ * Read the current configuration of the PLL identified by @pwd from
+ * the PRCI identified by @pd, and store it into the local configuration
+ * cache in @pwd.
+ *
+ * Context: Any context.  Caller must prevent the records pointed to by
+ *          @pd and @pwd from changing during execution.
+ */
+static void __prci_wrpll_read_cfg0(struct __prci_data *pd,
+                                  struct __prci_wrpll_data *pwd)
+{
+       __prci_wrpll_unpack(&pwd->c, __prci_readl(pd, pwd->cfg0_offs));
+}
+
+/**
+ * __prci_wrpll_write_cfg0() - write WRPLL configuration into the PRCI
+ * @pd: PRCI context
+ * @pwd: PRCI WRPLL metadata
+ * @c: WRPLL configuration record to write
+ *
+ * Write the WRPLL configuration described by @c into the WRPLL
+ * configuration register identified by @pwd in the PRCI instance
+ * described by @c.  Make a cached copy of the WRPLL's current
+ * configuration so it can be used by other code.
+ *
+ * Context: Any context.  Caller must prevent the records pointed to by
+ *          @pd and @pwd from changing during execution.
+ */
+static void __prci_wrpll_write_cfg0(struct __prci_data *pd,
+                                   struct __prci_wrpll_data *pwd,
+                                   struct wrpll_cfg *c)
+{
+       __prci_writel(__prci_wrpll_pack(c), pwd->cfg0_offs, pd);
+
+       memcpy(&pwd->c, c, sizeof(*c));
+}
+
+/**
+ * __prci_wrpll_write_cfg1() - write Clock enable/disable configuration
+ * into the PRCI
+ * @pd: PRCI context
+ * @pwd: PRCI WRPLL metadata
+ * @enable: Clock enable or disable value
+ */
+static void __prci_wrpll_write_cfg1(struct __prci_data *pd,
+                                   struct __prci_wrpll_data *pwd,
+                                   u32 enable)
+{
+       __prci_writel(enable, pwd->cfg1_offs, pd);
+}
+
+/*
+ * Linux clock framework integration
+ *
+ * See the Linux clock framework documentation for more information on
+ * these functions.
+ */
+
+unsigned long sifive_prci_wrpll_recalc_rate(struct clk_hw *hw,
+                                           unsigned long parent_rate)
+{
+       struct __prci_clock *pc = clk_hw_to_prci_clock(hw);
+       struct __prci_wrpll_data *pwd = pc->pwd;
+
+       return wrpll_calc_output_rate(&pwd->c, parent_rate);
+}
+
+long sifive_prci_wrpll_round_rate(struct clk_hw *hw,
+                                 unsigned long rate,
+                                 unsigned long *parent_rate)
+{
+       struct __prci_clock *pc = clk_hw_to_prci_clock(hw);
+       struct __prci_wrpll_data *pwd = pc->pwd;
+       struct wrpll_cfg c;
+
+       memcpy(&c, &pwd->c, sizeof(c));
+
+       wrpll_configure_for_rate(&c, rate, *parent_rate);
+
+       return wrpll_calc_output_rate(&c, *parent_rate);
+}
+
+int sifive_prci_wrpll_set_rate(struct clk_hw *hw,
+                              unsigned long rate, unsigned long parent_rate)
+{
+       struct __prci_clock *pc = clk_hw_to_prci_clock(hw);
+       struct __prci_wrpll_data *pwd = pc->pwd;
+       struct __prci_data *pd = pc->pd;
+       int r;
+
+       r = wrpll_configure_for_rate(&pwd->c, rate, parent_rate);
+       if (r)
+               return r;
+
+       if (pwd->enable_bypass)
+               pwd->enable_bypass(pd);
+
+       __prci_wrpll_write_cfg0(pd, pwd, &pwd->c);
+
+       udelay(wrpll_calc_max_lock_us(&pwd->c));
+
+       return 0;
+}
+
+int sifive_clk_is_enabled(struct clk_hw *hw)
+{
+       struct __prci_clock *pc = clk_hw_to_prci_clock(hw);
+       struct __prci_wrpll_data *pwd = pc->pwd;
+       struct __prci_data *pd = pc->pd;
+       u32 r;
+
+       r = __prci_readl(pd, pwd->cfg1_offs);
+
+       if (r & PRCI_COREPLLCFG1_CKE_MASK)
+               return 1;
+       else
+               return 0;
+}
+
+int sifive_prci_clock_enable(struct clk_hw *hw)
+{
+       struct __prci_clock *pc = clk_hw_to_prci_clock(hw);
+       struct __prci_wrpll_data *pwd = pc->pwd;
+       struct __prci_data *pd = pc->pd;
+
+       if (sifive_clk_is_enabled(hw))
+               return 0;
+
+       __prci_wrpll_write_cfg1(pd, pwd, PRCI_COREPLLCFG1_CKE_MASK);
+
+       if (pwd->disable_bypass)
+               pwd->disable_bypass(pd);
+
+       return 0;
+}
+
+void sifive_prci_clock_disable(struct clk_hw *hw)
+{
+       struct __prci_clock *pc = clk_hw_to_prci_clock(hw);
+       struct __prci_wrpll_data *pwd = pc->pwd;
+       struct __prci_data *pd = pc->pd;
+       u32 r;
+
+       if (pwd->enable_bypass)
+               pwd->enable_bypass(pd);
+
+       r = __prci_readl(pd, pwd->cfg1_offs);
+       r &= ~PRCI_COREPLLCFG1_CKE_MASK;
+
+       __prci_wrpll_write_cfg1(pd, pwd, r);
+}
+
+/* TLCLKSEL clock integration */
+
+unsigned long sifive_prci_tlclksel_recalc_rate(struct clk_hw *hw,
+                                              unsigned long parent_rate)
+{
+       struct __prci_clock *pc = clk_hw_to_prci_clock(hw);
+       struct __prci_data *pd = pc->pd;
+       u32 v;
+       u8 div;
+
+       v = __prci_readl(pd, PRCI_CLKMUXSTATUSREG_OFFSET);
+       v &= PRCI_CLKMUXSTATUSREG_TLCLKSEL_STATUS_MASK;
+       div = v ? 1 : 2;
+
+       return div_u64(parent_rate, div);
+}
+
+/* HFPCLK clock integration */
+
+unsigned long sifive_prci_hfpclkplldiv_recalc_rate(struct clk_hw *hw,
+                                                  unsigned long parent_rate)
+{
+       struct __prci_clock *pc = clk_hw_to_prci_clock(hw);
+       struct __prci_data *pd = pc->pd;
+       u32 div = __prci_readl(pd, PRCI_HFPCLKPLLDIV_OFFSET);
+
+       return div_u64(parent_rate, div + 2);
+}
+
+/*
+ * Core clock mux control
+ */
+
+/**
+ * sifive_prci_coreclksel_use_hfclk() - switch the CORECLK mux to output HFCLK
+ * @pd: struct __prci_data * for the PRCI containing the CORECLK mux reg
+ *
+ * Switch the CORECLK mux to the HFCLK input source; return once complete.
+ *
+ * Context: Any context.  Caller must prevent concurrent changes to the
+ *          PRCI_CORECLKSEL_OFFSET register.
+ */
+void sifive_prci_coreclksel_use_hfclk(struct __prci_data *pd)
+{
+       u32 r;
+
+       r = __prci_readl(pd, PRCI_CORECLKSEL_OFFSET);
+       r |= PRCI_CORECLKSEL_CORECLKSEL_MASK;
+       __prci_writel(r, PRCI_CORECLKSEL_OFFSET, pd);
+
+       r = __prci_readl(pd, PRCI_CORECLKSEL_OFFSET);   /* barrier */
+}
+
+/**
+ * sifive_prci_coreclksel_use_corepll() - switch the CORECLK mux to output
+ * COREPLL
+ * @pd: struct __prci_data * for the PRCI containing the CORECLK mux reg
+ *
+ * Switch the CORECLK mux to the COREPLL output clock; return once complete.
+ *
+ * Context: Any context.  Caller must prevent concurrent changes to the
+ *          PRCI_CORECLKSEL_OFFSET register.
+ */
+void sifive_prci_coreclksel_use_corepll(struct __prci_data *pd)
+{
+       u32 r;
+
+       r = __prci_readl(pd, PRCI_CORECLKSEL_OFFSET);
+       r &= ~PRCI_CORECLKSEL_CORECLKSEL_MASK;
+       __prci_writel(r, PRCI_CORECLKSEL_OFFSET, pd);
+
+       r = __prci_readl(pd, PRCI_CORECLKSEL_OFFSET);   /* barrier */
+}
+
+/**
+ * sifive_prci_coreclksel_use_final_corepll() - switch the CORECLK mux to output
+ * FINAL_COREPLL
+ * @pd: struct __prci_data * for the PRCI containing the CORECLK mux reg
+ *
+ * Switch the CORECLK mux to the final COREPLL output clock; return once
+ * complete.
+ *
+ * Context: Any context.  Caller must prevent concurrent changes to the
+ *          PRCI_CORECLKSEL_OFFSET register.
+ */
+void sifive_prci_coreclksel_use_final_corepll(struct __prci_data *pd)
+{
+       u32 r;
+
+       r = __prci_readl(pd, PRCI_CORECLKSEL_OFFSET);
+       r &= ~PRCI_CORECLKSEL_CORECLKSEL_MASK;
+       __prci_writel(r, PRCI_CORECLKSEL_OFFSET, pd);
+
+       r = __prci_readl(pd, PRCI_CORECLKSEL_OFFSET);   /* barrier */
+}
+
+/**
+ * sifive_prci_corepllsel_use_dvfscorepll() - switch the COREPLL mux to
+ * output DVFS_COREPLL
+ * @pd: struct __prci_data * for the PRCI containing the COREPLL mux reg
+ *
+ * Switch the COREPLL mux to the DVFSCOREPLL output clock; return once complete.
+ *
+ * Context: Any context.  Caller must prevent concurrent changes to the
+ *          PRCI_COREPLLSEL_OFFSET register.
+ */
+void sifive_prci_corepllsel_use_dvfscorepll(struct __prci_data *pd)
+{
+       u32 r;
+
+       r = __prci_readl(pd, PRCI_COREPLLSEL_OFFSET);
+       r |= PRCI_COREPLLSEL_COREPLLSEL_MASK;
+       __prci_writel(r, PRCI_COREPLLSEL_OFFSET, pd);
+
+       r = __prci_readl(pd, PRCI_COREPLLSEL_OFFSET);   /* barrier */
+}
+
+/**
+ * sifive_prci_corepllsel_use_corepll() - switch the COREPLL mux to
+ * output COREPLL
+ * @pd: struct __prci_data * for the PRCI containing the COREPLL mux reg
+ *
+ * Switch the COREPLL mux to the COREPLL output clock; return once complete.
+ *
+ * Context: Any context.  Caller must prevent concurrent changes to the
+ *          PRCI_COREPLLSEL_OFFSET register.
+ */
+void sifive_prci_corepllsel_use_corepll(struct __prci_data *pd)
+{
+       u32 r;
+
+       r = __prci_readl(pd, PRCI_COREPLLSEL_OFFSET);
+       r &= ~PRCI_COREPLLSEL_COREPLLSEL_MASK;
+       __prci_writel(r, PRCI_COREPLLSEL_OFFSET, pd);
+
+       r = __prci_readl(pd, PRCI_COREPLLSEL_OFFSET);   /* barrier */
+}
+
+/**
+ * sifive_prci_hfpclkpllsel_use_hfclk() - switch the HFPCLKPLL mux to
+ * output HFCLK
+ * @pd: struct __prci_data * for the PRCI containing the HFPCLKPLL mux reg
+ *
+ * Switch the HFPCLKPLL mux to the HFCLK input source; return once complete.
+ *
+ * Context: Any context.  Caller must prevent concurrent changes to the
+ *          PRCI_HFPCLKPLLSEL_OFFSET register.
+ */
+void sifive_prci_hfpclkpllsel_use_hfclk(struct __prci_data *pd)
+{
+       u32 r;
+
+       r = __prci_readl(pd, PRCI_HFPCLKPLLSEL_OFFSET);
+       r |= PRCI_HFPCLKPLLSEL_HFPCLKPLLSEL_MASK;
+       __prci_writel(r, PRCI_HFPCLKPLLSEL_OFFSET, pd);
+
+       r = __prci_readl(pd, PRCI_HFPCLKPLLSEL_OFFSET); /* barrier */
+}
+
+/**
+ * sifive_prci_hfpclkpllsel_use_hfpclkpll() - switch the HFPCLKPLL mux to
+ * output HFPCLKPLL
+ * @pd: struct __prci_data * for the PRCI containing the HFPCLKPLL mux reg
+ *
+ * Switch the HFPCLKPLL mux to the HFPCLKPLL output clock; return once complete.
+ *
+ * Context: Any context.  Caller must prevent concurrent changes to the
+ *          PRCI_HFPCLKPLLSEL_OFFSET register.
+ */
+void sifive_prci_hfpclkpllsel_use_hfpclkpll(struct __prci_data *pd)
+{
+       u32 r;
+
+       r = __prci_readl(pd, PRCI_HFPCLKPLLSEL_OFFSET);
+       r &= ~PRCI_HFPCLKPLLSEL_HFPCLKPLLSEL_MASK;
+       __prci_writel(r, PRCI_HFPCLKPLLSEL_OFFSET, pd);
+
+       r = __prci_readl(pd, PRCI_HFPCLKPLLSEL_OFFSET); /* barrier */
+}
+
+/**
+ * __prci_register_clocks() - register clock controls in the PRCI
+ * @dev: Linux struct device
+ * @pd: The pointer for PRCI per-device instance data
+ * @desc: The pointer for the information of clocks of each SoCs
+ *
+ * Register the list of clock controls described in __prci_init_clocks[] with
+ * the Linux clock framework.
+ *
+ * Return: 0 upon success or a negative error code upon failure.
+ */
+static int __prci_register_clocks(struct device *dev, struct __prci_data *pd,
+                                 const struct prci_clk_desc *desc)
+{
+       struct clk_init_data init = { };
+       struct __prci_clock *pic;
+       int parent_count, i, r;
+
+       parent_count = of_clk_get_parent_count(dev->of_node);
+       if (parent_count != EXPECTED_CLK_PARENT_COUNT) {
+               dev_err(dev, "expected only two parent clocks, found %d\n",
+                       parent_count);
+               return -EINVAL;
+       }
+
+       /* Register PLLs */
+       for (i = 0; i < desc->num_clks; ++i) {
+               pic = &(desc->clks[i]);
+
+               init.name = pic->name;
+               init.parent_names = &pic->parent_name;
+               init.num_parents = 1;
+               init.ops = pic->ops;
+               pic->hw.init = &init;
+
+               pic->pd = pd;
+
+               if (pic->pwd)
+                       __prci_wrpll_read_cfg0(pd, pic->pwd);
+
+               r = devm_clk_hw_register(dev, &pic->hw);
+               if (r) {
+                       dev_warn(dev, "Failed to register clock %s: %d\n",
+                                init.name, r);
+                       return r;
+               }
+
+               r = clk_hw_register_clkdev(&pic->hw, pic->name, dev_name(dev));
+               if (r) {
+                       dev_warn(dev, "Failed to register clkdev for %s: %d\n",
+                                init.name, r);
+                       return r;
+               }
+
+               pd->hw_clks.hws[i] = &pic->hw;
+       }
+
+       pd->hw_clks.num = i;
+
+       r = devm_of_clk_add_hw_provider(dev, of_clk_hw_onecell_get,
+                                       &pd->hw_clks);
+       if (r) {
+               dev_err(dev, "could not add hw_provider: %d\n", r);
+               return r;
+       }
+
+       return 0;
+}
+
+/**
+ * sifive_prci_init() - initialize prci data and check parent count
+ * @pdev: platform device pointer for the prci
+ *
+ * Return: 0 upon success or a negative error code upon failure.
+ */
+static int sifive_prci_probe(struct platform_device *pdev)
+{
+       struct device *dev = &pdev->dev;
+       struct resource *res;
+       struct __prci_data *pd;
+       const struct prci_clk_desc *desc;
+       int r;
+
+       desc = of_device_get_match_data(&pdev->dev);
+
+       pd = devm_kzalloc(dev, struct_size(pd, hw_clks.hws, desc->num_clks), GFP_KERNEL);
+       if (!pd)
+               return -ENOMEM;
+
+       res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+       pd->va = devm_ioremap_resource(dev, res);
+       if (IS_ERR(pd->va))
+               return PTR_ERR(pd->va);
+
+       r = __prci_register_clocks(dev, pd, desc);
+       if (r) {
+               dev_err(dev, "could not register clocks: %d\n", r);
+               return r;
+       }
+
+       dev_dbg(dev, "SiFive PRCI probed\n");
+
+       return 0;
+}
+
+static const struct of_device_id sifive_prci_of_match[] = {
+       {.compatible = "sifive,fu540-c000-prci", .data = &prci_clk_fu540},
+       {.compatible = "sifive,fu740-c000-prci", .data = &prci_clk_fu740},
+       {}
+};
+
+static struct platform_driver sifive_prci_driver = {
+       .driver = {
+               .name = "sifive-clk-prci",
+               .of_match_table = sifive_prci_of_match,
+       },
+       .probe = sifive_prci_probe,
+};
+
+static int __init sifive_prci_init(void)
+{
+       return platform_driver_register(&sifive_prci_driver);
+}
+core_initcall(sifive_prci_init);
diff --git a/drivers/clk/sifive/sifive-prci.h b/drivers/clk/sifive/sifive-prci.h
new file mode 100644 (file)
index 0000000..dbdbd17
--- /dev/null
@@ -0,0 +1,299 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * Copyright (C) 2018-2019 SiFive, Inc.
+ * Wesley Terpstra
+ * Paul Walmsley
+ * Zong Li
+ */
+
+#ifndef __SIFIVE_CLK_SIFIVE_PRCI_H
+#define __SIFIVE_CLK_SIFIVE_PRCI_H
+
+#include <linux/clk/analogbits-wrpll-cln28hpc.h>
+#include <linux/clk-provider.h>
+#include <linux/platform_device.h>
+
+/*
+ * EXPECTED_CLK_PARENT_COUNT: how many parent clocks this driver expects:
+ *     hfclk and rtcclk
+ */
+#define EXPECTED_CLK_PARENT_COUNT 2
+
+/*
+ * Register offsets and bitmasks
+ */
+
+/* COREPLLCFG0 */
+#define PRCI_COREPLLCFG0_OFFSET                0x4
+#define PRCI_COREPLLCFG0_DIVR_SHIFT    0
+#define PRCI_COREPLLCFG0_DIVR_MASK     (0x3f << PRCI_COREPLLCFG0_DIVR_SHIFT)
+#define PRCI_COREPLLCFG0_DIVF_SHIFT    6
+#define PRCI_COREPLLCFG0_DIVF_MASK     (0x1ff << PRCI_COREPLLCFG0_DIVF_SHIFT)
+#define PRCI_COREPLLCFG0_DIVQ_SHIFT    15
+#define PRCI_COREPLLCFG0_DIVQ_MASK     (0x7 << PRCI_COREPLLCFG0_DIVQ_SHIFT)
+#define PRCI_COREPLLCFG0_RANGE_SHIFT   18
+#define PRCI_COREPLLCFG0_RANGE_MASK    (0x7 << PRCI_COREPLLCFG0_RANGE_SHIFT)
+#define PRCI_COREPLLCFG0_BYPASS_SHIFT  24
+#define PRCI_COREPLLCFG0_BYPASS_MASK   (0x1 << PRCI_COREPLLCFG0_BYPASS_SHIFT)
+#define PRCI_COREPLLCFG0_FSE_SHIFT     25
+#define PRCI_COREPLLCFG0_FSE_MASK      (0x1 << PRCI_COREPLLCFG0_FSE_SHIFT)
+#define PRCI_COREPLLCFG0_LOCK_SHIFT    31
+#define PRCI_COREPLLCFG0_LOCK_MASK     (0x1 << PRCI_COREPLLCFG0_LOCK_SHIFT)
+
+/* COREPLLCFG1 */
+#define PRCI_COREPLLCFG1_OFFSET                0x8
+#define PRCI_COREPLLCFG1_CKE_SHIFT     31
+#define PRCI_COREPLLCFG1_CKE_MASK      (0x1 << PRCI_COREPLLCFG1_CKE_SHIFT)
+
+/* DDRPLLCFG0 */
+#define PRCI_DDRPLLCFG0_OFFSET         0xc
+#define PRCI_DDRPLLCFG0_DIVR_SHIFT     0
+#define PRCI_DDRPLLCFG0_DIVR_MASK      (0x3f << PRCI_DDRPLLCFG0_DIVR_SHIFT)
+#define PRCI_DDRPLLCFG0_DIVF_SHIFT     6
+#define PRCI_DDRPLLCFG0_DIVF_MASK      (0x1ff << PRCI_DDRPLLCFG0_DIVF_SHIFT)
+#define PRCI_DDRPLLCFG0_DIVQ_SHIFT     15
+#define PRCI_DDRPLLCFG0_DIVQ_MASK      (0x7 << PRCI_DDRPLLCFG0_DIVQ_SHIFT)
+#define PRCI_DDRPLLCFG0_RANGE_SHIFT    18
+#define PRCI_DDRPLLCFG0_RANGE_MASK     (0x7 << PRCI_DDRPLLCFG0_RANGE_SHIFT)
+#define PRCI_DDRPLLCFG0_BYPASS_SHIFT   24
+#define PRCI_DDRPLLCFG0_BYPASS_MASK    (0x1 << PRCI_DDRPLLCFG0_BYPASS_SHIFT)
+#define PRCI_DDRPLLCFG0_FSE_SHIFT      25
+#define PRCI_DDRPLLCFG0_FSE_MASK       (0x1 << PRCI_DDRPLLCFG0_FSE_SHIFT)
+#define PRCI_DDRPLLCFG0_LOCK_SHIFT     31
+#define PRCI_DDRPLLCFG0_LOCK_MASK      (0x1 << PRCI_DDRPLLCFG0_LOCK_SHIFT)
+
+/* DDRPLLCFG1 */
+#define PRCI_DDRPLLCFG1_OFFSET         0x10
+#define PRCI_DDRPLLCFG1_CKE_SHIFT      31
+#define PRCI_DDRPLLCFG1_CKE_MASK       (0x1 << PRCI_DDRPLLCFG1_CKE_SHIFT)
+
+/* GEMGXLPLLCFG0 */
+#define PRCI_GEMGXLPLLCFG0_OFFSET      0x1c
+#define PRCI_GEMGXLPLLCFG0_DIVR_SHIFT  0
+#define PRCI_GEMGXLPLLCFG0_DIVR_MASK   (0x3f << PRCI_GEMGXLPLLCFG0_DIVR_SHIFT)
+#define PRCI_GEMGXLPLLCFG0_DIVF_SHIFT  6
+#define PRCI_GEMGXLPLLCFG0_DIVF_MASK   (0x1ff << PRCI_GEMGXLPLLCFG0_DIVF_SHIFT)
+#define PRCI_GEMGXLPLLCFG0_DIVQ_SHIFT  15
+#define PRCI_GEMGXLPLLCFG0_DIVQ_MASK   (0x7 << PRCI_GEMGXLPLLCFG0_DIVQ_SHIFT)
+#define PRCI_GEMGXLPLLCFG0_RANGE_SHIFT 18
+#define PRCI_GEMGXLPLLCFG0_RANGE_MASK  (0x7 << PRCI_GEMGXLPLLCFG0_RANGE_SHIFT)
+#define PRCI_GEMGXLPLLCFG0_BYPASS_SHIFT        24
+#define PRCI_GEMGXLPLLCFG0_BYPASS_MASK (0x1 << PRCI_GEMGXLPLLCFG0_BYPASS_SHIFT)
+#define PRCI_GEMGXLPLLCFG0_FSE_SHIFT   25
+#define PRCI_GEMGXLPLLCFG0_FSE_MASK    (0x1 << PRCI_GEMGXLPLLCFG0_FSE_SHIFT)
+#define PRCI_GEMGXLPLLCFG0_LOCK_SHIFT  31
+#define PRCI_GEMGXLPLLCFG0_LOCK_MASK   (0x1 << PRCI_GEMGXLPLLCFG0_LOCK_SHIFT)
+
+/* GEMGXLPLLCFG1 */
+#define PRCI_GEMGXLPLLCFG1_OFFSET      0x20
+#define PRCI_GEMGXLPLLCFG1_CKE_SHIFT   31
+#define PRCI_GEMGXLPLLCFG1_CKE_MASK    (0x1 << PRCI_GEMGXLPLLCFG1_CKE_SHIFT)
+
+/* CORECLKSEL */
+#define PRCI_CORECLKSEL_OFFSET                 0x24
+#define PRCI_CORECLKSEL_CORECLKSEL_SHIFT       0
+#define PRCI_CORECLKSEL_CORECLKSEL_MASK                                        \
+               (0x1 << PRCI_CORECLKSEL_CORECLKSEL_SHIFT)
+
+/* DEVICESRESETREG */
+#define PRCI_DEVICESRESETREG_OFFSET                            0x28
+#define PRCI_DEVICESRESETREG_DDR_CTRL_RST_N_SHIFT              0
+#define PRCI_DEVICESRESETREG_DDR_CTRL_RST_N_MASK                       \
+               (0x1 << PRCI_DEVICESRESETREG_DDR_CTRL_RST_N_SHIFT)
+#define PRCI_DEVICESRESETREG_DDR_AXI_RST_N_SHIFT               1
+#define PRCI_DEVICESRESETREG_DDR_AXI_RST_N_MASK                                \
+               (0x1 << PRCI_DEVICESRESETREG_DDR_AXI_RST_N_SHIFT)
+#define PRCI_DEVICESRESETREG_DDR_AHB_RST_N_SHIFT               2
+#define PRCI_DEVICESRESETREG_DDR_AHB_RST_N_MASK                                \
+               (0x1 << PRCI_DEVICESRESETREG_DDR_AHB_RST_N_SHIFT)
+#define PRCI_DEVICESRESETREG_DDR_PHY_RST_N_SHIFT               3
+#define PRCI_DEVICESRESETREG_DDR_PHY_RST_N_MASK                                \
+               (0x1 << PRCI_DEVICESRESETREG_DDR_PHY_RST_N_SHIFT)
+#define PRCI_DEVICESRESETREG_GEMGXL_RST_N_SHIFT                        5
+#define PRCI_DEVICESRESETREG_GEMGXL_RST_N_MASK                         \
+               (0x1 << PRCI_DEVICESRESETREG_GEMGXL_RST_N_SHIFT)
+#define PRCI_DEVICESRESETREG_CHIPLINK_RST_N_SHIFT              6
+#define PRCI_DEVICESRESETREG_CHIPLINK_RST_N_MASK                       \
+               (0x1 << PRCI_DEVICESRESETREG_CHIPLINK_RST_N_SHIFT)
+
+/* CLKMUXSTATUSREG */
+#define PRCI_CLKMUXSTATUSREG_OFFSET                            0x2c
+#define PRCI_CLKMUXSTATUSREG_TLCLKSEL_STATUS_SHIFT             1
+#define PRCI_CLKMUXSTATUSREG_TLCLKSEL_STATUS_MASK                      \
+               (0x1 << PRCI_CLKMUXSTATUSREG_TLCLKSEL_STATUS_SHIFT)
+
+/* CLTXPLLCFG0 */
+#define PRCI_CLTXPLLCFG0_OFFSET                0x30
+#define PRCI_CLTXPLLCFG0_DIVR_SHIFT    0
+#define PRCI_CLTXPLLCFG0_DIVR_MASK     (0x3f << PRCI_CLTXPLLCFG0_DIVR_SHIFT)
+#define PRCI_CLTXPLLCFG0_DIVF_SHIFT    6
+#define PRCI_CLTXPLLCFG0_DIVF_MASK     (0x1ff << PRCI_CLTXPLLCFG0_DIVF_SHIFT)
+#define PRCI_CLTXPLLCFG0_DIVQ_SHIFT    15
+#define PRCI_CLTXPLLCFG0_DIVQ_MASK     (0x7 << PRCI_CLTXPLLCFG0_DIVQ_SHIFT)
+#define PRCI_CLTXPLLCFG0_RANGE_SHIFT   18
+#define PRCI_CLTXPLLCFG0_RANGE_MASK    (0x7 << PRCI_CLTXPLLCFG0_RANGE_SHIFT)
+#define PRCI_CLTXPLLCFG0_BYPASS_SHIFT  24
+#define PRCI_CLTXPLLCFG0_BYPASS_MASK   (0x1 << PRCI_CLTXPLLCFG0_BYPASS_SHIFT)
+#define PRCI_CLTXPLLCFG0_FSE_SHIFT     25
+#define PRCI_CLTXPLLCFG0_FSE_MASK      (0x1 << PRCI_CLTXPLLCFG0_FSE_SHIFT)
+#define PRCI_CLTXPLLCFG0_LOCK_SHIFT    31
+#define PRCI_CLTXPLLCFG0_LOCK_MASK     (0x1 << PRCI_CLTXPLLCFG0_LOCK_SHIFT)
+
+/* CLTXPLLCFG1 */
+#define PRCI_CLTXPLLCFG1_OFFSET                0x34
+#define PRCI_CLTXPLLCFG1_CKE_SHIFT     31
+#define PRCI_CLTXPLLCFG1_CKE_MASK      (0x1 << PRCI_CLTXPLLCFG1_CKE_SHIFT)
+
+/* DVFSCOREPLLCFG0 */
+#define PRCI_DVFSCOREPLLCFG0_OFFSET    0x38
+
+/* DVFSCOREPLLCFG1 */
+#define PRCI_DVFSCOREPLLCFG1_OFFSET    0x3c
+#define PRCI_DVFSCOREPLLCFG1_CKE_SHIFT 31
+#define PRCI_DVFSCOREPLLCFG1_CKE_MASK  (0x1 << PRCI_DVFSCOREPLLCFG1_CKE_SHIFT)
+
+/* COREPLLSEL */
+#define PRCI_COREPLLSEL_OFFSET                 0x40
+#define PRCI_COREPLLSEL_COREPLLSEL_SHIFT       0
+#define PRCI_COREPLLSEL_COREPLLSEL_MASK                                        \
+               (0x1 << PRCI_COREPLLSEL_COREPLLSEL_SHIFT)
+
+/* HFPCLKPLLCFG0 */
+#define PRCI_HFPCLKPLLCFG0_OFFSET              0x50
+#define PRCI_HFPCLKPLL_CFG0_DIVR_SHIFT         0
+#define PRCI_HFPCLKPLL_CFG0_DIVR_MASK                                  \
+               (0x3f << PRCI_HFPCLKPLLCFG0_DIVR_SHIFT)
+#define PRCI_HFPCLKPLL_CFG0_DIVF_SHIFT         6
+#define PRCI_HFPCLKPLL_CFG0_DIVF_MASK                                  \
+               (0x1ff << PRCI_HFPCLKPLLCFG0_DIVF_SHIFT)
+#define PRCI_HFPCLKPLL_CFG0_DIVQ_SHIFT         15
+#define PRCI_HFPCLKPLL_CFG0_DIVQ_MASK                                  \
+               (0x7 << PRCI_HFPCLKPLLCFG0_DIVQ_SHIFT)
+#define PRCI_HFPCLKPLL_CFG0_RANGE_SHIFT                18
+#define PRCI_HFPCLKPLL_CFG0_RANGE_MASK                                 \
+               (0x7 << PRCI_HFPCLKPLLCFG0_RANGE_SHIFT)
+#define PRCI_HFPCLKPLL_CFG0_BYPASS_SHIFT       24
+#define PRCI_HFPCLKPLL_CFG0_BYPASS_MASK                                        \
+               (0x1 << PRCI_HFPCLKPLLCFG0_BYPASS_SHIFT)
+#define PRCI_HFPCLKPLL_CFG0_FSE_SHIFT          25
+#define PRCI_HFPCLKPLL_CFG0_FSE_MASK                                   \
+               (0x1 << PRCI_HFPCLKPLLCFG0_FSE_SHIFT)
+#define PRCI_HFPCLKPLL_CFG0_LOCK_SHIFT         31
+#define PRCI_HFPCLKPLL_CFG0_LOCK_MASK                                  \
+               (0x1 << PRCI_HFPCLKPLLCFG0_LOCK_SHIFT)
+
+/* HFPCLKPLLCFG1 */
+#define PRCI_HFPCLKPLLCFG1_OFFSET              0x54
+#define PRCI_HFPCLKPLLCFG1_CKE_SHIFT           31
+#define PRCI_HFPCLKPLLCFG1_CKE_MASK                                    \
+               (0x1 << PRCI_HFPCLKPLLCFG1_CKE_SHIFT)
+
+/* HFPCLKPLLSEL */
+#define PRCI_HFPCLKPLLSEL_OFFSET               0x58
+#define PRCI_HFPCLKPLLSEL_HFPCLKPLLSEL_SHIFT   0
+#define PRCI_HFPCLKPLLSEL_HFPCLKPLLSEL_MASK                            \
+               (0x1 << PRCI_HFPCLKPLLSEL_HFPCLKPLLSEL_SHIFT)
+
+/* HFPCLKPLLDIV */
+#define PRCI_HFPCLKPLLDIV_OFFSET               0x5c
+
+/* PRCIPLL */
+#define PRCI_PRCIPLL_OFFSET                    0xe0
+
+/* PROCMONCFG */
+#define PRCI_PROCMONCFG_OFFSET                 0xf0
+
+/*
+ * Private structures
+ */
+
+/**
+ * struct __prci_data - per-device-instance data
+ * @va: base virtual address of the PRCI IP block
+ * @hw_clks: encapsulates struct clk_hw records
+ *
+ * PRCI per-device instance data
+ */
+struct __prci_data {
+       void __iomem *va;
+       struct clk_hw_onecell_data hw_clks;
+};
+
+/**
+ * struct __prci_wrpll_data - WRPLL configuration and integration data
+ * @c: WRPLL current configuration record
+ * @enable_bypass: fn ptr to code to bypass the WRPLL (if applicable; else NULL)
+ * @disable_bypass: fn ptr to code to not bypass the WRPLL (or NULL)
+ * @cfg0_offs: WRPLL CFG0 register offset (in bytes) from the PRCI base address
+ * @cfg1_offs: WRPLL CFG1 register offset (in bytes) from the PRCI base address
+ *
+ * @enable_bypass and @disable_bypass are used for WRPLL instances
+ * that contain a separate external glitchless clock mux downstream
+ * from the PLL.  The WRPLL internal bypass mux is not glitchless.
+ */
+struct __prci_wrpll_data {
+       struct wrpll_cfg c;
+       void (*enable_bypass)(struct __prci_data *pd);
+       void (*disable_bypass)(struct __prci_data *pd);
+       u8 cfg0_offs;
+       u8 cfg1_offs;
+};
+
+/**
+ * struct __prci_clock - describes a clock device managed by PRCI
+ * @name: user-readable clock name string - should match the manual
+ * @parent_name: parent name for this clock
+ * @ops: struct clk_ops for the Linux clock framework to use for control
+ * @hw: Linux-private clock data
+ * @pwd: WRPLL-specific data, associated with this clock (if not NULL)
+ * @pd: PRCI-specific data associated with this clock (if not NULL)
+ *
+ * PRCI clock data.  Used by the PRCI driver to register PRCI-provided
+ * clocks to the Linux clock infrastructure.
+ */
+struct __prci_clock {
+       const char *name;
+       const char *parent_name;
+       const struct clk_ops *ops;
+       struct clk_hw hw;
+       struct __prci_wrpll_data *pwd;
+       struct __prci_data *pd;
+};
+
+#define clk_hw_to_prci_clock(pwd) container_of(pwd, struct __prci_clock, hw)
+
+/*
+ * struct prci_clk_desc - describes the information of clocks of each SoCs
+ * @clks: point to a array of __prci_clock
+ * @num_clks: the number of element of clks
+ */
+struct prci_clk_desc {
+       struct __prci_clock *clks;
+       size_t num_clks;
+};
+
+/* Core clock mux control */
+void sifive_prci_coreclksel_use_hfclk(struct __prci_data *pd);
+void sifive_prci_coreclksel_use_corepll(struct __prci_data *pd);
+void sifive_prci_coreclksel_use_final_corepll(struct __prci_data *pd);
+void sifive_prci_corepllsel_use_dvfscorepll(struct __prci_data *pd);
+void sifive_prci_corepllsel_use_corepll(struct __prci_data *pd);
+void sifive_prci_hfpclkpllsel_use_hfclk(struct __prci_data *pd);
+void sifive_prci_hfpclkpllsel_use_hfpclkpll(struct __prci_data *pd);
+
+/* Linux clock framework integration */
+long sifive_prci_wrpll_round_rate(struct clk_hw *hw, unsigned long rate,
+                                 unsigned long *parent_rate);
+int sifive_prci_wrpll_set_rate(struct clk_hw *hw, unsigned long rate,
+                              unsigned long parent_rate);
+int sifive_clk_is_enabled(struct clk_hw *hw);
+int sifive_prci_clock_enable(struct clk_hw *hw);
+void sifive_prci_clock_disable(struct clk_hw *hw);
+unsigned long sifive_prci_wrpll_recalc_rate(struct clk_hw *hw,
+                                           unsigned long parent_rate);
+unsigned long sifive_prci_tlclksel_recalc_rate(struct clk_hw *hw,
+                                              unsigned long parent_rate);
+unsigned long sifive_prci_hfpclkplldiv_recalc_rate(struct clk_hw *hw,
+                                                  unsigned long parent_rate);
+
+#endif /* __SIFIVE_CLK_SIFIVE_PRCI_H */
index a66263b..6ecf18f 100644 (file)
@@ -1,6 +1,6 @@
 // SPDX-License-Identifier: GPL-2.0-only
 /*
- * Copyright (C) 2016 NVIDIA Corporation
+ * Copyright (C) 2016-2020 NVIDIA Corporation
  */
 
 #include <linux/clk-provider.h>
@@ -174,7 +174,7 @@ static long tegra_bpmp_clk_round_rate(struct clk_hw *hw, unsigned long rate,
        int err;
 
        memset(&request, 0, sizeof(request));
-       request.rate = rate;
+       request.rate = min_t(u64, rate, S64_MAX);
 
        memset(&msg, 0, sizeof(msg));
        msg.cmd = CMD_CLK_ROUND_RATE;
@@ -256,7 +256,7 @@ static int tegra_bpmp_clk_set_rate(struct clk_hw *hw, unsigned long rate,
        struct tegra_bpmp_clk_message msg;
 
        memset(&request, 0, sizeof(request));
-       request.rate = rate;
+       request.rate = min_t(u64, rate, S64_MAX);
 
        memset(&msg, 0, sizeof(msg));
        msg.cmd = CMD_CLK_SET_RATE;
index cfbaa90..a5f526b 100644 (file)
@@ -1856,13 +1856,13 @@ static int dfll_fetch_pwm_params(struct tegra_dfll *td)
                            &td->reg_init_uV);
        if (!ret) {
                dev_err(td->dev, "couldn't get initialized voltage\n");
-               return ret;
+               return -EINVAL;
        }
 
        ret = read_dt_param(td, "nvidia,pwm-period-nanoseconds", &pwm_period);
        if (!ret) {
                dev_err(td->dev, "couldn't get PWM period\n");
-               return ret;
+               return -EINVAL;
        }
        td->pwm_rate = (NSEC_PER_SEC / pwm_period) * (MAX_DFLL_VOLTAGES - 1);
 
index ff7da2d..2441381 100644 (file)
@@ -227,6 +227,7 @@ enum clk_id {
        tegra_clk_sdmmc4,
        tegra_clk_sdmmc4_8,
        tegra_clk_se,
+       tegra_clk_se_10,
        tegra_clk_soc_therm,
        tegra_clk_soc_therm_8,
        tegra_clk_sor0,
index 2b2a3b8..60cc34f 100644 (file)
@@ -630,7 +630,7 @@ static struct tegra_periph_init_data periph_clks[] = {
        INT8("host1x", mux_pllm_pllc2_c_c3_pllp_plla, CLK_SOURCE_HOST1X, 28, 0, tegra_clk_host1x_8),
        INT8("host1x", mux_pllc4_out1_pllc_pllc4_out2_pllp_clkm_plla_pllc4_out0, CLK_SOURCE_HOST1X, 28, 0, tegra_clk_host1x_9),
        INT8("se", mux_pllp_pllc2_c_c3_pllm_clkm, CLK_SOURCE_SE, 127, TEGRA_PERIPH_ON_APB, tegra_clk_se),
-       INT8("se", mux_pllp_pllc2_c_c3_clkm, CLK_SOURCE_SE, 127, TEGRA_PERIPH_ON_APB, tegra_clk_se),
+       INT8("se", mux_pllp_pllc2_c_c3_clkm, CLK_SOURCE_SE, 127, TEGRA_PERIPH_ON_APB, tegra_clk_se_10),
        INT8("2d", mux_pllm_pllc2_c_c3_pllp_plla, CLK_SOURCE_2D, 21, 0, tegra_clk_gr2d_8),
        INT8("3d", mux_pllm_pllc2_c_c3_pllp_plla, CLK_SOURCE_3D, 24, 0, tegra_clk_gr3d_8),
        INT8("vic03", mux_pllm_pllc_pllp_plla_pllc2_c3_clkm, CLK_SOURCE_VIC03, 178, 0, tegra_clk_vic03),
index 8694bc9..f054239 100644 (file)
@@ -605,7 +605,7 @@ static struct ti_dt_clk omap54xx_clks[] = {
 int __init omap5xxx_dt_clk_init(void)
 {
        int rc;
-       struct clk *abe_dpll_ref, *abe_dpll, *sys_32k_ck, *usb_dpll;
+       struct clk *abe_dpll_ref, *abe_dpll, *abe_dpll_byp, *sys_32k_ck, *usb_dpll;
 
        ti_dt_clocks_register(omap54xx_clks);
 
@@ -616,6 +616,16 @@ int __init omap5xxx_dt_clk_init(void)
        abe_dpll_ref = clk_get_sys(NULL, "abe_dpll_clk_mux");
        sys_32k_ck = clk_get_sys(NULL, "sys_32k_ck");
        rc = clk_set_parent(abe_dpll_ref, sys_32k_ck);
+
+       /*
+        * This must also be set to sys_32k_ck to match or
+        * the ABE DPLL will not lock on a warm reboot when
+        * ABE timers are used.
+        */
+       abe_dpll_byp = clk_get_sys(NULL, "abe_dpll_bypass_clk_mux");
+       if (!rc)
+               rc = clk_set_parent(abe_dpll_byp, sys_32k_ck);
+
        abe_dpll = clk_get_sys(NULL, "dpll_abe_ck");
        if (!rc)
                rc = clk_set_rate(abe_dpll, OMAP5_DPLL_ABE_DEFFREQ);
index 95e36ba..8024c6d 100644 (file)
@@ -498,6 +498,7 @@ static struct clk * __init ti_fapll_synth_setup(struct fapll_data *fd,
 {
        struct clk_init_data *init;
        struct fapll_synth *synth;
+       struct clk *clk = ERR_PTR(-ENOMEM);
 
        init = kzalloc(sizeof(*init), GFP_KERNEL);
        if (!init)
@@ -520,13 +521,19 @@ static struct clk * __init ti_fapll_synth_setup(struct fapll_data *fd,
        synth->hw.init = init;
        synth->clk_pll = pll_clk;
 
-       return clk_register(NULL, &synth->hw);
+       clk = clk_register(NULL, &synth->hw);
+       if (IS_ERR(clk)) {
+               pr_err("failed to register clock\n");
+               goto free;
+       }
+
+       return clk;
 
 free:
        kfree(synth);
        kfree(init);
 
-       return ERR_PTR(-ENOMEM);
+       return clk;
 }
 
 static void __init ti_fapll_setup(struct device_node *node)
index eba1710..98e1b2a 100644 (file)
 #define PMC_PLLBCK             8
 #define PMC_AUDIOPLLCK         9
 
+/* SAMA7G5 */
+#define PMC_CPUPLL             (PMC_MAIN + 1)
+#define PMC_SYSPLL             (PMC_MAIN + 2)
+#define PMC_DDRPLL             (PMC_MAIN + 3)
+#define PMC_IMGPLL             (PMC_MAIN + 4)
+#define PMC_BAUDPLL            (PMC_MAIN + 5)
+#define PMC_AUDIOPMCPLL                (PMC_MAIN + 6)
+#define PMC_AUDIOIOPLL         (PMC_MAIN + 7)
+#define PMC_ETHPLL             (PMC_MAIN + 8)
+#define PMC_CPU                        (PMC_MAIN + 9)
+
 #ifndef AT91_PMC_MOSCS
 #define AT91_PMC_MOSCS         0               /* MOSCS Flag */
 #define AT91_PMC_LOCKA         1               /* PLLA Lock */
index fd1f938..e2749db 100644 (file)
 #define CLKID_PCIE_CML_EN1                     80
 #define CLKID_MIPI_ENABLE                      81
 #define CLKID_GEN_CLK                          84
+#define CLKID_VPU_0_SEL                                92
+#define CLKID_VPU_0                            93
+#define CLKID_VPU_1_SEL                                95
+#define CLKID_VPU_1                            96
+#define CLKID_VPU                              97
+#define CLKID_VAPB_0_SEL                       99
+#define CLKID_VAPB_0                           100
+#define CLKID_VAPB_1_SEL                       102
+#define CLKID_VAPB_1                           103
+#define CLKID_VAPB_SEL                         104
+#define CLKID_VAPB                             105
+#define CLKID_VCLK                             106
+#define CLKID_VCLK2                            107
+#define CLKID_VCLK_DIV1                                122
+#define CLKID_VCLK_DIV2                                123
+#define CLKID_VCLK_DIV4                                124
+#define CLKID_VCLK_DIV6                                125
+#define CLKID_VCLK_DIV12                       126
+#define CLKID_VCLK2_DIV1                       127
+#define CLKID_VCLK2_DIV2                       128
+#define CLKID_VCLK2_DIV4                       129
+#define CLKID_VCLK2_DIV6                       130
+#define CLKID_VCLK2_DIV12                      131
+#define CLKID_CTS_ENCL                         133
+#define CLKID_VDIN_MEAS                                136
 
 #endif /* __AXG_CLKC_H */
diff --git a/include/dt-bindings/clock/fsl,qoriq-clockgen.h b/include/dt-bindings/clock/fsl,qoriq-clockgen.h
new file mode 100644 (file)
index 0000000..ddec7d0
--- /dev/null
@@ -0,0 +1,15 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+
+#ifndef DT_CLOCK_FSL_QORIQ_CLOCKGEN_H
+#define DT_CLOCK_FSL_QORIQ_CLOCKGEN_H
+
+#define QORIQ_CLK_SYSCLK       0
+#define QORIQ_CLK_CMUX         1
+#define QORIQ_CLK_HWACCEL      2
+#define QORIQ_CLK_FMAN         3
+#define QORIQ_CLK_PLATFORM_PLL 4
+#define QORIQ_CLK_CORECLK      5
+
+#define QORIQ_CLK_PLL_DIV(x)   ((x) - 1)
+
+#endif /* DT_CLOCK_FSL_QORIQ_CLOCKGEN_H */
index 40d4994..a93b58c 100644 (file)
 #define CLKID_SPICC1_SCLK                      261
 #define CLKID_NNA_AXI_CLK                      264
 #define CLKID_NNA_CORE_CLK                     267
+#define CLKID_MIPI_DSI_PXCLK_SEL               269
+#define CLKID_MIPI_DSI_PXCLK                   270
 
 #endif /* __G12A_CLKC_H */
diff --git a/include/dt-bindings/clock/qcom,camcc-sc7180.h b/include/dt-bindings/clock/qcom,camcc-sc7180.h
new file mode 100644 (file)
index 0000000..ef7d3a0
--- /dev/null
@@ -0,0 +1,121 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+/*
+ * Copyright (c) 2020, The Linux Foundation. All rights reserved.
+ */
+
+#ifndef _DT_BINDINGS_CLK_QCOM_CAM_CC_SC7180_H
+#define _DT_BINDINGS_CLK_QCOM_CAM_CC_SC7180_H
+
+/* CAM_CC clocks */
+#define CAM_CC_PLL2_OUT_EARLY                                  0
+#define CAM_CC_PLL0                                            1
+#define CAM_CC_PLL1                                            2
+#define CAM_CC_PLL2                                            3
+#define CAM_CC_PLL2_OUT_AUX                                    4
+#define CAM_CC_PLL3                                            5
+#define CAM_CC_CAMNOC_AXI_CLK                                  6
+#define CAM_CC_CCI_0_CLK                                       7
+#define CAM_CC_CCI_0_CLK_SRC                                   8
+#define CAM_CC_CCI_1_CLK                                       9
+#define CAM_CC_CCI_1_CLK_SRC                                   10
+#define CAM_CC_CORE_AHB_CLK                                    11
+#define CAM_CC_CPAS_AHB_CLK                                    12
+#define CAM_CC_CPHY_RX_CLK_SRC                                 13
+#define CAM_CC_CSI0PHYTIMER_CLK                                        14
+#define CAM_CC_CSI0PHYTIMER_CLK_SRC                            15
+#define CAM_CC_CSI1PHYTIMER_CLK                                        16
+#define CAM_CC_CSI1PHYTIMER_CLK_SRC                            17
+#define CAM_CC_CSI2PHYTIMER_CLK                                        18
+#define CAM_CC_CSI2PHYTIMER_CLK_SRC                            19
+#define CAM_CC_CSI3PHYTIMER_CLK                                        20
+#define CAM_CC_CSI3PHYTIMER_CLK_SRC                            21
+#define CAM_CC_CSIPHY0_CLK                                     22
+#define CAM_CC_CSIPHY1_CLK                                     23
+#define CAM_CC_CSIPHY2_CLK                                     24
+#define CAM_CC_CSIPHY3_CLK                                     25
+#define CAM_CC_FAST_AHB_CLK_SRC                                        26
+#define CAM_CC_ICP_APB_CLK                                     27
+#define CAM_CC_ICP_ATB_CLK                                     28
+#define CAM_CC_ICP_CLK                                         29
+#define CAM_CC_ICP_CLK_SRC                                     30
+#define CAM_CC_ICP_CTI_CLK                                     31
+#define CAM_CC_ICP_TS_CLK                                      32
+#define CAM_CC_IFE_0_AXI_CLK                                   33
+#define CAM_CC_IFE_0_CLK                                       34
+#define CAM_CC_IFE_0_CLK_SRC                                   35
+#define CAM_CC_IFE_0_CPHY_RX_CLK                               36
+#define CAM_CC_IFE_0_CSID_CLK                                  37
+#define CAM_CC_IFE_0_CSID_CLK_SRC                              38
+#define CAM_CC_IFE_0_DSP_CLK                                   39
+#define CAM_CC_IFE_1_AXI_CLK                                   40
+#define CAM_CC_IFE_1_CLK                                       41
+#define CAM_CC_IFE_1_CLK_SRC                                   42
+#define CAM_CC_IFE_1_CPHY_RX_CLK                               43
+#define CAM_CC_IFE_1_CSID_CLK                                  44
+#define CAM_CC_IFE_1_CSID_CLK_SRC                              45
+#define CAM_CC_IFE_1_DSP_CLK                                   46
+#define CAM_CC_IFE_LITE_CLK                                    47
+#define CAM_CC_IFE_LITE_CLK_SRC                                        48
+#define CAM_CC_IFE_LITE_CPHY_RX_CLK                            49
+#define CAM_CC_IFE_LITE_CSID_CLK                               50
+#define CAM_CC_IFE_LITE_CSID_CLK_SRC                           51
+#define CAM_CC_IPE_0_AHB_CLK                                   52
+#define CAM_CC_IPE_0_AREG_CLK                                  53
+#define CAM_CC_IPE_0_AXI_CLK                                   54
+#define CAM_CC_IPE_0_CLK                                       55
+#define CAM_CC_IPE_0_CLK_SRC                                   56
+#define CAM_CC_JPEG_CLK                                                57
+#define CAM_CC_JPEG_CLK_SRC                                    58
+#define CAM_CC_LRME_CLK                                                59
+#define CAM_CC_LRME_CLK_SRC                                    60
+#define CAM_CC_MCLK0_CLK                                       61
+#define CAM_CC_MCLK0_CLK_SRC                                   62
+#define CAM_CC_MCLK1_CLK                                       63
+#define CAM_CC_MCLK1_CLK_SRC                                   64
+#define CAM_CC_MCLK2_CLK                                       65
+#define CAM_CC_MCLK2_CLK_SRC                                   66
+#define CAM_CC_MCLK3_CLK                                       67
+#define CAM_CC_MCLK3_CLK_SRC                                   68
+#define CAM_CC_MCLK4_CLK                                       69
+#define CAM_CC_MCLK4_CLK_SRC                                   70
+#define CAM_CC_BPS_AHB_CLK                                     71
+#define CAM_CC_BPS_AREG_CLK                                    72
+#define CAM_CC_BPS_AXI_CLK                                     73
+#define CAM_CC_BPS_CLK                                         74
+#define CAM_CC_BPS_CLK_SRC                                     75
+#define CAM_CC_SLOW_AHB_CLK_SRC                                        76
+#define CAM_CC_SOC_AHB_CLK                                     77
+#define CAM_CC_SYS_TMR_CLK                                     78
+
+/* CAM_CC power domains */
+#define BPS_GDSC                                               0
+#define IFE_0_GDSC                                             1
+#define IFE_1_GDSC                                             2
+#define IPE_0_GDSC                                             3
+#define TITAN_TOP_GDSC                                         4
+
+/* CAM_CC resets */
+#define CAM_CC_BPS_BCR                                         0
+#define CAM_CC_CAMNOC_BCR                                      1
+#define CAM_CC_CCI_0_BCR                                       2
+#define CAM_CC_CCI_1_BCR                                       3
+#define CAM_CC_CPAS_BCR                                                4
+#define CAM_CC_CSI0PHY_BCR                                     5
+#define CAM_CC_CSI1PHY_BCR                                     6
+#define CAM_CC_CSI2PHY_BCR                                     7
+#define CAM_CC_CSI3PHY_BCR                                     8
+#define CAM_CC_ICP_BCR                                         9
+#define CAM_CC_IFE_0_BCR                                       10
+#define CAM_CC_IFE_1_BCR                                       11
+#define CAM_CC_IFE_LITE_BCR                                    12
+#define CAM_CC_IPE_0_BCR                                       13
+#define CAM_CC_JPEG_BCR                                                14
+#define CAM_CC_LRME_BCR                                                15
+#define CAM_CC_MCLK0_BCR                                       16
+#define CAM_CC_MCLK1_BCR                                       17
+#define CAM_CC_MCLK2_BCR                                       18
+#define CAM_CC_MCLK3_BCR                                       19
+#define CAM_CC_MCLK4_BCR                                       20
+#define CAM_CC_TITAN_TOP_BCR                                   21
+
+#endif
diff --git a/include/dt-bindings/clock/qcom,gcc-sdx55.h b/include/dt-bindings/clock/qcom,gcc-sdx55.h
new file mode 100644 (file)
index 0000000..fb9a594
--- /dev/null
@@ -0,0 +1,117 @@
+/* SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) */
+/*
+ * Copyright (c) 2018, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2020, Linaro Ltd.
+ */
+
+#ifndef _DT_BINDINGS_CLK_QCOM_GCC_SDX55_H
+#define _DT_BINDINGS_CLK_QCOM_GCC_SDX55_H
+
+#define GPLL0                                                  3
+#define GPLL0_OUT_EVEN                                         4
+#define GPLL4                                                  5
+#define GPLL4_OUT_EVEN                                         6
+#define GPLL5                                                  7
+#define GCC_AHB_PCIE_LINK_CLK                                  8
+#define GCC_BLSP1_AHB_CLK                                      9
+#define GCC_BLSP1_QUP1_I2C_APPS_CLK                            10
+#define GCC_BLSP1_QUP1_I2C_APPS_CLK_SRC                                11
+#define GCC_BLSP1_QUP1_SPI_APPS_CLK                            12
+#define GCC_BLSP1_QUP1_SPI_APPS_CLK_SRC                                13
+#define GCC_BLSP1_QUP2_I2C_APPS_CLK                            14
+#define GCC_BLSP1_QUP2_I2C_APPS_CLK_SRC                                15
+#define GCC_BLSP1_QUP2_SPI_APPS_CLK                            16
+#define GCC_BLSP1_QUP2_SPI_APPS_CLK_SRC                                17
+#define GCC_BLSP1_QUP3_I2C_APPS_CLK                            18
+#define GCC_BLSP1_QUP3_I2C_APPS_CLK_SRC                                19
+#define GCC_BLSP1_QUP3_SPI_APPS_CLK                            20
+#define GCC_BLSP1_QUP3_SPI_APPS_CLK_SRC                                21
+#define GCC_BLSP1_QUP4_I2C_APPS_CLK                            22
+#define GCC_BLSP1_QUP4_I2C_APPS_CLK_SRC                                23
+#define GCC_BLSP1_QUP4_SPI_APPS_CLK                            24
+#define GCC_BLSP1_QUP4_SPI_APPS_CLK_SRC                                25
+#define GCC_BLSP1_UART1_APPS_CLK                               26
+#define GCC_BLSP1_UART1_APPS_CLK_SRC                           27
+#define GCC_BLSP1_UART2_APPS_CLK                               28
+#define GCC_BLSP1_UART2_APPS_CLK_SRC                           29
+#define GCC_BLSP1_UART3_APPS_CLK                               30
+#define GCC_BLSP1_UART3_APPS_CLK_SRC                           31
+#define GCC_BLSP1_UART4_APPS_CLK                               32
+#define GCC_BLSP1_UART4_APPS_CLK_SRC                           33
+#define GCC_BOOT_ROM_AHB_CLK                                   34
+#define GCC_CE1_AHB_CLK                                                35
+#define GCC_CE1_AXI_CLK                                                36
+#define GCC_CE1_CLK                                            37
+#define GCC_CPUSS_AHB_CLK                                      38
+#define GCC_CPUSS_AHB_CLK_SRC                                  39
+#define GCC_CPUSS_GNOC_CLK                                     40
+#define GCC_CPUSS_RBCPR_CLK                                    41
+#define GCC_CPUSS_RBCPR_CLK_SRC                                        42
+#define GCC_EMAC_CLK_SRC                                       43
+#define GCC_EMAC_PTP_CLK_SRC                                   44
+#define GCC_ETH_AXI_CLK                                                45
+#define GCC_ETH_PTP_CLK                                                46
+#define GCC_ETH_RGMII_CLK                                      47
+#define GCC_ETH_SLAVE_AHB_CLK                                  48
+#define GCC_GP1_CLK                                            49
+#define GCC_GP1_CLK_SRC                                                50
+#define GCC_GP2_CLK                                            51
+#define GCC_GP2_CLK_SRC                                                52
+#define GCC_GP3_CLK                                            53
+#define GCC_GP3_CLK_SRC                                                54
+#define GCC_PCIE_0_CLKREF_CLK                                  55
+#define GCC_PCIE_AUX_CLK                                       56
+#define GCC_PCIE_AUX_PHY_CLK_SRC                               57
+#define GCC_PCIE_CFG_AHB_CLK                                   58
+#define GCC_PCIE_MSTR_AXI_CLK                                  59
+#define GCC_PCIE_PIPE_CLK                                      60
+#define GCC_PCIE_RCHNG_PHY_CLK                                 61
+#define GCC_PCIE_RCHNG_PHY_CLK_SRC                             62
+#define GCC_PCIE_SLEEP_CLK                                     63
+#define GCC_PCIE_SLV_AXI_CLK                                   64
+#define GCC_PCIE_SLV_Q2A_AXI_CLK                               65
+#define GCC_PDM2_CLK                                           66
+#define GCC_PDM2_CLK_SRC                                       67
+#define GCC_PDM_AHB_CLK                                                68
+#define GCC_PDM_XO4_CLK                                                69
+#define GCC_SDCC1_AHB_CLK                                      70
+#define GCC_SDCC1_APPS_CLK                                     71
+#define GCC_SDCC1_APPS_CLK_SRC                                 72
+#define GCC_SYS_NOC_CPUSS_AHB_CLK                              73
+#define GCC_USB30_MASTER_CLK                                   74
+#define GCC_USB30_MASTER_CLK_SRC                               75
+#define GCC_USB30_MOCK_UTMI_CLK                                        76
+#define GCC_USB30_MOCK_UTMI_CLK_SRC                            77
+#define GCC_USB30_MSTR_AXI_CLK                                 78
+#define GCC_USB30_SLEEP_CLK                                    79
+#define GCC_USB30_SLV_AHB_CLK                                  80
+#define GCC_USB3_PHY_AUX_CLK                                   81
+#define GCC_USB3_PHY_AUX_CLK_SRC                               82
+#define GCC_USB3_PHY_PIPE_CLK                                  83
+#define GCC_USB3_PRIM_CLKREF_CLK                               84
+#define GCC_USB_PHY_CFG_AHB2PHY_CLK                            85
+#define GCC_XO_DIV4_CLK                                                86
+#define GCC_XO_PCIE_LINK_CLK                                   87
+
+#define GCC_EMAC_BCR                                           0
+#define GCC_PCIE_BCR                                           1
+#define GCC_PCIE_LINK_DOWN_BCR                                 2
+#define GCC_PCIE_NOCSR_COM_PHY_BCR                             3
+#define GCC_PCIE_PHY_BCR                                       4
+#define GCC_PCIE_PHY_CFG_AHB_BCR                               5
+#define GCC_PCIE_PHY_COM_BCR                                   6
+#define GCC_PCIE_PHY_NOCSR_COM_PHY_BCR                         7
+#define GCC_PDM_BCR                                            8
+#define GCC_QUSB2PHY_BCR                                       9
+#define GCC_TCSR_PCIE_BCR                                      10
+#define GCC_USB30_BCR                                          11
+#define GCC_USB3_PHY_BCR                                       12
+#define GCC_USB3PHY_PHY_BCR                                    13
+#define GCC_USB_PHY_CFG_AHB2PHY_BCR                            14
+
+/* GCC power domains */
+#define USB30_GDSC                                             0
+#define PCIE_GDSC                                              1
+#define EMAC_GDSC                                              2
+
+#endif
index 2e6c54e..583a991 100644 (file)
 #define RPMH_IPA_CLK                           12
 #define RPMH_LN_BB_CLK1                                13
 #define RPMH_LN_BB_CLK1_A                      14
+#define RPMH_CE_CLK                            15
+#define RPMH_QPIC_CLK                          16
+#define RPMH_DIV_CLK1                          17
+#define RPMH_DIV_CLK1_A                                18
+#define RPMH_RF_CLK4                           19
+#define RPMH_RF_CLK4_A                         20
+#define RPMH_RF_CLK5                           21
+#define RPMH_RF_CLK5_A                         22
+#define RPMH_PKA_CLK                           23
+#define RPMH_HWKM_CLK                          24
 
 #endif
diff --git a/include/dt-bindings/clock/qcom,sm8250-lpass-aoncc.h b/include/dt-bindings/clock/qcom,sm8250-lpass-aoncc.h
new file mode 100644 (file)
index 0000000..f5a1cfa
--- /dev/null
@@ -0,0 +1,11 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+
+#ifndef _DT_BINDINGS_CLK_LPASS_AONCC_SM8250_H
+#define _DT_BINDINGS_CLK_LPASS_AONCC_SM8250_H
+
+/* from AOCC */
+#define LPASS_CDC_VA_MCLK                              0
+#define LPASS_CDC_TX_NPL                               1
+#define LPASS_CDC_TX_MCLK                              2
+
+#endif /* _DT_BINDINGS_CLK_LPASS_AONCC_SM8250_H */
diff --git a/include/dt-bindings/clock/qcom,sm8250-lpass-audiocc.h b/include/dt-bindings/clock/qcom,sm8250-lpass-audiocc.h
new file mode 100644 (file)
index 0000000..a1aa6cb
--- /dev/null
@@ -0,0 +1,13 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+
+#ifndef _DT_BINDINGS_CLK_LPASS_AUDIOCC_SM8250_H
+#define _DT_BINDINGS_CLK_LPASS_AUDIOCC_SM8250_H
+
+/* From AudioCC */
+#define LPASS_CDC_WSA_NPL                              0
+#define LPASS_CDC_WSA_MCLK                             1
+#define LPASS_CDC_RX_MCLK                              2
+#define LPASS_CDC_RX_NPL                               3
+#define LPASS_CDC_RX_MCLK_MCLK2                                4
+
+#endif /* _DT_BINDINGS_CLK_LPASS_AUDIOCC_SM8250_H */
diff --git a/include/dt-bindings/clock/sifive-fu740-prci.h b/include/dt-bindings/clock/sifive-fu740-prci.h
new file mode 100644 (file)
index 0000000..cd7706e
--- /dev/null
@@ -0,0 +1,23 @@
+/* SPDX-License-Identifier: (GPL-2.0 OR MIT) */
+/*
+ * Copyright (C) 2019 SiFive, Inc.
+ * Wesley Terpstra
+ * Paul Walmsley
+ * Zong Li
+ */
+
+#ifndef __DT_BINDINGS_CLOCK_SIFIVE_FU740_PRCI_H
+#define __DT_BINDINGS_CLOCK_SIFIVE_FU740_PRCI_H
+
+/* Clock indexes for use by Device Tree data and the PRCI driver */
+
+#define PRCI_CLK_COREPLL              0
+#define PRCI_CLK_DDRPLL                       1
+#define PRCI_CLK_GEMGXLPLL            2
+#define PRCI_CLK_DVFSCOREPLL          3
+#define PRCI_CLK_HFPCLKPLL            4
+#define PRCI_CLK_CLTXPLL              5
+#define PRCI_CLK_TLCLK                6
+#define PRCI_CLK_PCLK                 7
+
+#endif /* __DT_BINDINGS_CLOCK_SIFIVE_FU740_PRCI_H */
index 03a5de5..e431689 100644 (file)
@@ -639,6 +639,12 @@ struct clk_hw *__clk_hw_register_divider(struct device *dev,
                const struct clk_parent_data *parent_data, unsigned long flags,
                void __iomem *reg, u8 shift, u8 width, u8 clk_divider_flags,
                const struct clk_div_table *table, spinlock_t *lock);
+struct clk_hw *__devm_clk_hw_register_divider(struct device *dev,
+               struct device_node *np, const char *name,
+               const char *parent_name, const struct clk_hw *parent_hw,
+               const struct clk_parent_data *parent_data, unsigned long flags,
+               void __iomem *reg, u8 shift, u8 width, u8 clk_divider_flags,
+               const struct clk_div_table *table, spinlock_t *lock);
 struct clk *clk_register_divider_table(struct device *dev, const char *name,
                const char *parent_name, unsigned long flags,
                void __iomem *reg, u8 shift, u8 width,
@@ -779,6 +785,27 @@ struct clk *clk_register_divider_table(struct device *dev, const char *name,
                                  (parent_data), (flags), (reg), (shift),     \
                                  (width), (clk_divider_flags), (table),      \
                                  (lock))
+/**
+ * devm_clk_hw_register_divider_table - register a table based divider clock
+ * with the clock framework (devres variant)
+ * @dev: device registering this clock
+ * @name: name of this clock
+ * @parent_name: name of clock's parent
+ * @flags: framework-specific flags
+ * @reg: register address to adjust divider
+ * @shift: number of bits to shift the bitfield
+ * @width: width of the bitfield
+ * @clk_divider_flags: divider-specific flags for this clock
+ * @table: array of divider/value pairs ending with a div set to 0
+ * @lock: shared register lock for this clock
+ */
+#define devm_clk_hw_register_divider_table(dev, name, parent_name, flags,     \
+                                          reg, shift, width,                 \
+                                          clk_divider_flags, table, lock)    \
+       __devm_clk_hw_register_divider((dev), NULL, (name), (parent_name),    \
+                                      NULL, NULL, (flags), (reg), (shift),   \
+                                      (width), (clk_divider_flags), (table), \
+                                      (lock))
 
 void clk_unregister_divider(struct clk *clk);
 void clk_hw_unregister_divider(struct clk_hw *hw);
@@ -1062,6 +1089,13 @@ struct clk_hw *clk_hw_register_composite_pdata(struct device *dev,
                struct clk_hw *rate_hw, const struct clk_ops *rate_ops,
                struct clk_hw *gate_hw, const struct clk_ops *gate_ops,
                unsigned long flags);
+struct clk_hw *devm_clk_hw_register_composite_pdata(struct device *dev,
+               const char *name, const struct clk_parent_data *parent_data,
+               int num_parents,
+               struct clk_hw *mux_hw, const struct clk_ops *mux_ops,
+               struct clk_hw *rate_hw, const struct clk_ops *rate_ops,
+               struct clk_hw *gate_hw, const struct clk_ops *gate_ops,
+               unsigned long flags);
 void clk_hw_unregister_composite(struct clk_hw *hw);
 
 struct clk *clk_register(struct device *dev, struct clk_hw *hw);
@@ -1088,6 +1122,11 @@ static inline struct clk_hw *__clk_get_hw(struct clk *clk)
        return (struct clk_hw *)clk;
 }
 #endif
+
+struct clk *clk_hw_get_clk(struct clk_hw *hw, const char *con_id);
+struct clk *devm_clk_hw_get_clk(struct device *dev, struct clk_hw *hw,
+                               const char *con_id);
+
 unsigned int clk_hw_get_num_parents(const struct clk_hw *hw);
 struct clk_hw *clk_hw_get_parent(const struct clk_hw *hw);
 struct clk_hw *clk_hw_get_parent_by_index(const struct clk_hw *hw,
index 7fd6a1f..31ff1bf 100644 (file)
@@ -109,6 +109,17 @@ int clk_notifier_register(struct clk *clk, struct notifier_block *nb);
  */
 int clk_notifier_unregister(struct clk *clk, struct notifier_block *nb);
 
+/**
+ * devm_clk_notifier_register - register a managed rate-change notifier callback
+ * @dev: device for clock "consumer"
+ * @clk: clock whose rate we are interested in
+ * @nb: notifier block with callback function pointer
+ *
+ * Returns 0 on success, -EERROR otherwise
+ */
+int devm_clk_notifier_register(struct device *dev, struct clk *clk,
+                              struct notifier_block *nb);
+
 /**
  * clk_get_accuracy - obtain the clock accuracy in ppb (parts per billion)
  *                   for a clock source.
@@ -150,7 +161,7 @@ int clk_get_phase(struct clk *clk);
 int clk_set_duty_cycle(struct clk *clk, unsigned int num, unsigned int den);
 
 /**
- * clk_get_duty_cycle - return the duty cycle ratio of a clock signal
+ * clk_get_scaled_duty_cycle - return the duty cycle ratio of a clock signal
  * @clk: clock signal source
  * @scale: scaling factor to be applied to represent the ratio as an integer
  *
@@ -186,6 +197,13 @@ static inline int clk_notifier_unregister(struct clk *clk,
        return -ENOTSUPP;
 }
 
+static inline int devm_clk_notifier_register(struct device *dev,
+                                            struct clk *clk,
+                                            struct notifier_block *nb)
+{
+       return -ENOTSUPP;
+}
+
 static inline long clk_get_accuracy(struct clk *clk)
 {
        return -ENOTSUPP;
index 79097e3..38b7740 100644 (file)
@@ -10,7 +10,7 @@
 
 struct device_node;
 
-#ifdef CONFIG_ARCH_S3C64XX
+#ifdef CONFIG_S3C64XX_COMMON_CLK
 void s3c64xx_clk_init(struct device_node *np, unsigned long xtal_f,
                      unsigned long xusbxti_f, bool s3c6400,
                      void __iomem *base);
@@ -19,7 +19,7 @@ static inline void s3c64xx_clk_init(struct device_node *np,
                                    unsigned long xtal_f,
                                    unsigned long xusbxti_f,
                                    bool s3c6400, void __iomem *base) { }
-#endif /* CONFIG_ARCH_S3C64XX */
+#endif /* CONFIG_S3C64XX_COMMON_CLK */
 
 #ifdef CONFIG_S3C2410_COMMON_CLK
 void s3c2410_common_clk_init(struct device_node *np, unsigned long xti_f,