]> git.proxmox.com Git - mirror_ubuntu-jammy-kernel.git/commitdiff
Merge tag 'clk-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/clk/linux
authorLinus Torvalds <torvalds@linux-foundation.org>
Wed, 12 Aug 2020 19:19:49 +0000 (12:19 -0700)
committerLinus Torvalds <torvalds@linux-foundation.org>
Wed, 12 Aug 2020 19:19:49 +0000 (12:19 -0700)
Pull more clk updates from Stephen Boyd:
 "Here's some more updates that missed the last pull request because I
  happened to tag the tree at an earlier point in the history of
  clk-next. I must have fat fingered it and checked out an older version
  of clk-next on this second computer I'm using.

  This time it actually includes more code for Qualcomm SoCs, the AT91
  major updates, and some Rockchip SoC clk driver updates as well. I've
  corrected this flow so this shouldn't happen again"

* tag 'clk-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/clk/linux: (83 commits)
  clk: bcm2835: Do not use prediv with bcm2711's PLLs
  clk: drop unused function __clk_get_flags
  clk: hsdk: Fix bad dependency on IOMEM
  dt-bindings: clock: Fix YAML schemas for LPASS clocks on SC7180
  clk: mmp: avoid missing prototype warning
  clk: sparx5: Add Sparx5 SoC DPLL clock driver
  dt-bindings: clock: sparx5: Add bindings include file
  clk: qoriq: add LS1021A core pll mux options
  clk: clk-atlas6: fix return value check in atlas6_clk_init()
  clk: tegra: pll: Improve PLLM enable-state detection
  clk: X1000: Add support for calculat REFCLK of USB PHY.
  clk: JZ4780: Reformat the code to align it.
  clk: JZ4780: Add functions for enable and disable USB PHY.
  clk: Ingenic: Add RTC related clocks for Ingenic SoCs.
  dt-bindings: clock: Add tabs to align code.
  dt-bindings: clock: Add RTC related clocks for Ingenic SoCs.
  clk: davinci: Use fallthrough pseudo-keyword
  clk: imx: Use fallthrough pseudo-keyword
  clk: qcom: gcc-sdm660: Fix up gcc_mss_mnoc_bimc_axi_clk
  clk: qcom: gcc-sdm660: Add missing modem reset
  ...

83 files changed:
Documentation/devicetree/bindings/arm/bcm/raspberrypi,bcm2835-firmware.yaml
Documentation/devicetree/bindings/clock/idt,versaclock5.txt [deleted file]
Documentation/devicetree/bindings/clock/idt,versaclock5.yaml [new file with mode: 0644]
Documentation/devicetree/bindings/clock/qcom,gpucc.yaml [new file with mode: 0644]
Documentation/devicetree/bindings/clock/qcom,msm8996-apcc.yaml
Documentation/devicetree/bindings/clock/qcom,sc7180-gpucc.yaml [deleted file]
Documentation/devicetree/bindings/clock/qcom,sc7180-lpasscorecc.yaml [new file with mode: 0644]
Documentation/devicetree/bindings/clock/qcom,sdm845-gpucc.yaml [deleted file]
Documentation/devicetree/bindings/clock/rockchip,rk3288-cru.txt
MAINTAINERS
drivers/clk/Kconfig
drivers/clk/Makefile
drivers/clk/actions/owl-s500.c
drivers/clk/at91/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-generated.c
drivers/clk/at91/clk-main.c
drivers/clk/at91/clk-master.c
drivers/clk/at91/clk-peripheral.c
drivers/clk/at91/clk-programmable.c
drivers/clk/at91/clk-sam9x60-pll.c
drivers/clk/at91/clk-system.c
drivers/clk/at91/clk-utmi.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 [new file with mode: 0644]
drivers/clk/at91/sckc.c
drivers/clk/bcm/clk-bcm2835.c
drivers/clk/bcm/clk-iproc-asiu.c
drivers/clk/clk-qoriq.c
drivers/clk/clk-sparx5.c [new file with mode: 0644]
drivers/clk/clk-versaclock5.c
drivers/clk/clk.c
drivers/clk/davinci/pll.c
drivers/clk/imx/clk-pllv3.c
drivers/clk/ingenic/jz4780-cgu.c
drivers/clk/ingenic/x1000-cgu.c
drivers/clk/ingenic/x1830-cgu.c
drivers/clk/mmp/clk-pxa168.c
drivers/clk/mmp/clk-pxa910.c
drivers/clk/qcom/Kconfig
drivers/clk/qcom/Makefile
drivers/clk/qcom/clk-alpha-pll.c
drivers/clk/qcom/clk-alpha-pll.h
drivers/clk/qcom/gcc-sc7180.c
drivers/clk/qcom/gcc-sdm660.c
drivers/clk/qcom/gcc-sm8150.c
drivers/clk/qcom/gdsc.c
drivers/clk/qcom/gdsc.h
drivers/clk/qcom/gpucc-sc7180.c
drivers/clk/qcom/gpucc-sdm845.c
drivers/clk/qcom/gpucc-sm8150.c [new file with mode: 0644]
drivers/clk/qcom/gpucc-sm8250.c [new file with mode: 0644]
drivers/clk/qcom/lpasscorecc-sc7180.c [new file with mode: 0644]
drivers/clk/rockchip/clk-pll.c
drivers/clk/rockchip/clk-rk3188.c
drivers/clk/rockchip/clk-rk3288.c
drivers/clk/rockchip/clk-rk3328.c
drivers/clk/sirf/clk-atlas6.c
drivers/clk/tegra/clk-pll.c
drivers/clk/x86/clk-cgu-pll.c
drivers/clk/x86/clk-cgu.c
include/dt-bindings/clock/actions,s500-cmu.h
include/dt-bindings/clock/jz4780-cgu.h
include/dt-bindings/clock/qcom,gcc-sc7180.h
include/dt-bindings/clock/qcom,gcc-sdm660.h
include/dt-bindings/clock/qcom,gpucc-sm8150.h [new file with mode: 0644]
include/dt-bindings/clock/qcom,gpucc-sm8250.h [new file with mode: 0644]
include/dt-bindings/clock/qcom,lpasscorecc-sc7180.h [new file with mode: 0644]
include/dt-bindings/clock/x1000-cgu.h
include/dt-bindings/clock/x1830-cgu.h
include/dt-bindings/reset/actions,s500-reset.h [new file with mode: 0644]
include/linux/clk-provider.h
include/linux/clk/at91_pmc.h

index b48ed875eb8e4535f716ac976afb53f724d29de3..17e4f20c8d39bc0e4779dff24f23197fe91d373d 100644 (file)
@@ -10,6 +10,15 @@ maintainers:
   - Eric Anholt <eric@anholt.net>
   - Stefan Wahren <wahrenst@gmx.net>
 
+select:
+  properties:
+    compatible:
+      contains:
+        const: raspberrypi,bcm2835-firmware
+
+  required:
+    - compatible
+
 properties:
   compatible:
     items:
diff --git a/Documentation/devicetree/bindings/clock/idt,versaclock5.txt b/Documentation/devicetree/bindings/clock/idt,versaclock5.txt
deleted file mode 100644 (file)
index 6165b6d..0000000
+++ /dev/null
@@ -1,125 +0,0 @@
-Binding for IDT VersaClock 5,6 programmable i2c clock generators.
-
-The IDT VersaClock 5 and VersaClock 6 are programmable i2c clock
-generators providing from 3 to 12 output clocks.
-
-==I2C device node==
-
-Required properties:
-- compatible:  shall be one of
-               "idt,5p49v5923"
-               "idt,5p49v5925"
-               "idt,5p49v5933"
-               "idt,5p49v5935"
-               "idt,5p49v6901"
-               "idt,5p49v6965"
-- reg:         i2c device address, shall be 0x68 or 0x6a.
-- #clock-cells:        from common clock binding; shall be set to 1.
-- clocks:      from common clock binding; list of parent clock handles,
-               - 5p49v5923 and
-                 5p49v5925 and
-                 5p49v6901: (required) either or both of XTAL or CLKIN
-                                       reference clock.
-               - 5p49v5933 and
-               - 5p49v5935: (optional) property not present (internal
-                                       Xtal used) or CLKIN reference
-                                       clock.
-- clock-names: from common clock binding; clock input names, can be
-               - 5p49v5923 and
-                 5p49v5925 and
-                 5p49v6901: (required) either or both of "xin", "clkin".
-               - 5p49v5933 and
-               - 5p49v5935: (optional) property not present or "clkin".
-
-For all output ports, a corresponding, optional child node named OUT1,
-OUT2, etc. can represent a each output, and the node can be used to
-specify the following:
-
-- itd,mode: can be one of the following:
-                 - VC5_LVPECL
-                 - VC5_CMOS
-                 - VC5_HCSL33
-                 - VC5_LVDS
-                 - VC5_CMOS2
-                 - VC5_CMOSD
-                 - VC5_HCSL25
-
-- idt,voltage-microvolts:  can be one of the following
-                 - 1800000
-                 - 2500000
-                 - 3300000
--  idt,slew-percent: Percent of normal, can be one of
-                 - 80
-                 - 85
-                 - 90
-                 - 100
-
-==Mapping between clock specifier and physical pins==
-
-When referencing the provided clock in the DT using phandle and
-clock specifier, the following mapping applies:
-
-5P49V5923:
-       0 -- OUT0_SEL_I2CB
-       1 -- OUT1
-       2 -- OUT2
-
-5P49V5933:
-       0 -- OUT0_SEL_I2CB
-       1 -- OUT1
-       2 -- OUT4
-
-5P49V5925 and
-5P49V5935:
-       0 -- OUT0_SEL_I2CB
-       1 -- OUT1
-       2 -- OUT2
-       3 -- OUT3
-       4 -- OUT4
-
-5P49V6901:
-       0 -- OUT0_SEL_I2CB
-       1 -- OUT1
-       2 -- OUT2
-       3 -- OUT3
-       4 -- OUT4
-
-==Example==
-
-/* 25MHz reference crystal */
-ref25: ref25m {
-       compatible = "fixed-clock";
-       #clock-cells = <0>;
-       clock-frequency = <25000000>;
-};
-
-i2c-master-node {
-
-       /* IDT 5P49V5923 i2c clock generator */
-       vc5: clock-generator@6a {
-               compatible = "idt,5p49v5923";
-               reg = <0x6a>;
-               #clock-cells = <1>;
-
-               /* Connect XIN input to 25MHz reference */
-               clocks = <&ref25m>;
-               clock-names = "xin";
-
-               OUT1 {
-                       itd,mode = <VC5_CMOS>;
-                       idt,voltage-microvolts = <1800000>;
-                       idt,slew-percent = <80>;
-               };
-               OUT2 {
-                       ...
-               };
-               ...
-       };
-};
-
-/* Consumer referencing the 5P49V5923 pin OUT1 */
-consumer {
-       ...
-       clocks = <&vc5 1>;
-       ...
-}
diff --git a/Documentation/devicetree/bindings/clock/idt,versaclock5.yaml b/Documentation/devicetree/bindings/clock/idt,versaclock5.yaml
new file mode 100644 (file)
index 0000000..3d4e168
--- /dev/null
@@ -0,0 +1,154 @@
+# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/clock/idt,versaclock5.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: Binding for IDT VersaClock 5 and 6 programmable I2C clock generators
+
+description: |
+  The IDT VersaClock 5 and VersaClock 6 are programmable I2C
+  clock generators providing from 3 to 12 output clocks.
+
+  When referencing the provided clock in the DT using phandle and clock
+  specifier, the following mapping applies:
+
+  - 5P49V5923:
+    0 -- OUT0_SEL_I2CB
+    1 -- OUT1
+    2 -- OUT2
+
+  - 5P49V5933:
+    0 -- OUT0_SEL_I2CB
+    1 -- OUT1
+    2 -- OUT4
+
+  - other parts:
+    0 -- OUT0_SEL_I2CB
+    1 -- OUT1
+    2 -- OUT2
+    3 -- OUT3
+    4 -- OUT4
+
+maintainers:
+  - Luca Ceresoli <luca@lucaceresoli.net>
+
+properties:
+  compatible:
+    enum:
+      - idt,5p49v5923
+      - idt,5p49v5925
+      - idt,5p49v5933
+      - idt,5p49v5935
+      - idt,5p49v6901
+      - idt,5p49v6965
+
+  reg:
+    description: I2C device address
+    enum: [ 0x68, 0x6a ]
+
+  '#clock-cells':
+    const: 1
+
+patternProperties:
+  "^OUT[1-4]$":
+    type: object
+    description:
+      Description of one of the outputs (OUT1..OUT4). See "Clock1 Output
+      Configuration" in the Versaclock 5/6/6E Family Register Description
+      and Programming Guide.
+    properties:
+      idt,mode:
+        description:
+          The output drive mode. Values defined in dt-bindings/clk/versaclock.h
+        $ref: /schemas/types.yaml#/definitions/uint32
+        minimum: 0
+        maximum: 6
+      idt,voltage-microvolt:
+        description: The output drive voltage.
+        enum: [ 1800000, 2500000, 3300000 ]
+      idt,slew-percent:
+        description: The Slew rate control for CMOS single-ended.
+        $ref: /schemas/types.yaml#/definitions/uint32
+        enum: [ 80, 85, 90, 100 ]
+
+required:
+  - compatible
+  - reg
+  - '#clock-cells'
+
+allOf:
+  - if:
+      properties:
+        compatible:
+          enum:
+            - idt,5p49v5933
+            - idt,5p49v5935
+    then:
+      # Devices with builtin crystal + optional external input
+      properties:
+        clock-names:
+          const: clkin
+        clocks:
+          maxItems: 1
+    else:
+      # Devices without builtin crystal
+      properties:
+        clock-names:
+            minItems: 1
+            maxItems: 2
+            items:
+              enum: [ xin, clkin ]
+        clocks:
+          minItems: 1
+          maxItems: 2
+      required:
+        - clock-names
+        - clocks
+
+examples:
+  - |
+    #include <dt-bindings/clk/versaclock.h>
+
+    /* 25MHz reference crystal */
+    ref25: ref25m {
+        compatible = "fixed-clock";
+        #clock-cells = <0>;
+        clock-frequency = <25000000>;
+    };
+
+    i2c@0 {
+        reg = <0x0 0x100>;
+        #address-cells = <1>;
+        #size-cells = <0>;
+
+        /* IDT 5P49V5923 I2C clock generator */
+        vc5: clock-generator@6a {
+            compatible = "idt,5p49v5923";
+            reg = <0x6a>;
+            #clock-cells = <1>;
+
+            /* Connect XIN input to 25MHz reference */
+            clocks = <&ref25m>;
+            clock-names = "xin";
+
+            OUT1 {
+                idt,drive-mode = <VC5_CMOSD>;
+                idt,voltage-microvolts = <1800000>;
+                idt,slew-percent = <80>;
+            };
+
+            OUT4 {
+                idt,drive-mode = <VC5_LVDS>;
+            };
+        };
+    };
+
+    /* Consumer referencing the 5P49V5923 pin OUT1 */
+    consumer {
+        /* ... */
+        clocks = <&vc5 1>;
+        /* ... */
+    };
+
+...
diff --git a/Documentation/devicetree/bindings/clock/qcom,gpucc.yaml b/Documentation/devicetree/bindings/clock/qcom,gpucc.yaml
new file mode 100644 (file)
index 0000000..df943c4
--- /dev/null
@@ -0,0 +1,82 @@
+# SPDX-License-Identifier: GPL-2.0-only
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/clock/qcom,gpucc.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: Qualcomm Graphics Clock & Reset Controller Binding
+
+maintainers:
+  - Taniya Das <tdas@codeaurora.org>
+
+description: |
+  Qualcomm graphics clock control module which supports the clocks, resets and
+  power domains on SDM845/SC7180/SM8150/SM8250.
+
+  See also:
+    dt-bindings/clock/qcom,gpucc-sdm845.h
+    dt-bindings/clock/qcom,gpucc-sc7180.h
+    dt-bindings/clock/qcom,gpucc-sm8150.h
+    dt-bindings/clock/qcom,gpucc-sm8250.h
+
+properties:
+  compatible:
+    enum:
+      - qcom,sdm845-gpucc
+      - qcom,sc7180-gpucc
+      - qcom,sm8150-gpucc
+      - qcom,sm8250-gpucc
+
+  clocks:
+    items:
+      - description: Board XO source
+      - description: GPLL0 main branch source
+      - description: GPLL0 div branch source
+
+  clock-names:
+    items:
+      - const: bi_tcxo
+      - const: gcc_gpu_gpll0_clk_src
+      - const: gcc_gpu_gpll0_div_clk_src
+
+  '#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-sdm845.h>
+    #include <dt-bindings/clock/qcom,rpmh.h>
+    clock-controller@5090000 {
+      compatible = "qcom,sdm845-gpucc";
+      reg = <0x05090000 0x9000>;
+      clocks = <&rpmhcc RPMH_CXO_CLK>,
+               <&gcc GCC_GPU_GPLL0_CLK_SRC>,
+               <&gcc GCC_GPU_GPLL0_DIV_CLK_SRC>;
+      clock-names = "bi_tcxo",
+                    "gcc_gpu_gpll0_clk_src",
+                    "gcc_gpu_gpll0_div_clk_src";
+      #clock-cells = <1>;
+      #reset-cells = <1>;
+      #power-domain-cells = <1>;
+    };
+...
index d673edeed98d11e6eabcc48ca2546dd8d490f78a..a20cb10636dd45bb731c0b11e5bead0804eca35a 100644 (file)
@@ -1,7 +1,7 @@
 # SPDX-License-Identifier: GPL-2.0-only
 %YAML 1.2
 ---
-$id: http://devicetree.org/schemas/clock/qcom,kryocc.yaml#
+$id: http://devicetree.org/schemas/clock/qcom,msm8996-apcc.yaml#
 $schema: http://devicetree.org/meta-schemas/core.yaml#
 
 title: Qualcomm clock controller for MSM8996 CPUs
@@ -46,11 +46,9 @@ required:
 additionalProperties: false
 
 examples:
-  # Example for msm8996
   - |
     kryocc: clock-controller@6400000 {
         compatible = "qcom,msm8996-apcc";
         reg = <0x6400000 0x90000>;
         #clock-cells = <1>;
-  };
-...
+    };
diff --git a/Documentation/devicetree/bindings/clock/qcom,sc7180-gpucc.yaml b/Documentation/devicetree/bindings/clock/qcom,sc7180-gpucc.yaml
deleted file mode 100644 (file)
index fe08461..0000000
+++ /dev/null
@@ -1,74 +0,0 @@
-# SPDX-License-Identifier: GPL-2.0-only
-%YAML 1.2
----
-$id: http://devicetree.org/schemas/clock/qcom,sc7180-gpucc.yaml#
-$schema: http://devicetree.org/meta-schemas/core.yaml#
-
-title: Qualcomm Graphics Clock & Reset Controller Binding for SC7180
-
-maintainers:
-  - Taniya Das <tdas@codeaurora.org>
-
-description: |
-  Qualcomm graphics clock control module which supports the clocks, resets and
-  power domains on SC7180.
-
-  See also dt-bindings/clock/qcom,gpucc-sc7180.h.
-
-properties:
-  compatible:
-    const: qcom,sc7180-gpucc
-
-  clocks:
-    items:
-      - description: Board XO source
-      - description: GPLL0 main branch source
-      - description: GPLL0 div branch source
-
-  clock-names:
-    items:
-      - const: bi_tcxo
-      - const: gcc_gpu_gpll0_clk_src
-      - const: gcc_gpu_gpll0_div_clk_src
-
-  '#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@5090000 {
-      compatible = "qcom,sc7180-gpucc";
-      reg = <0x05090000 0x9000>;
-      clocks = <&rpmhcc RPMH_CXO_CLK>,
-               <&gcc GCC_GPU_GPLL0_CLK_SRC>,
-               <&gcc GCC_GPU_GPLL0_DIV_CLK_SRC>;
-      clock-names = "bi_tcxo",
-                    "gcc_gpu_gpll0_clk_src",
-                    "gcc_gpu_gpll0_div_clk_src";
-      #clock-cells = <1>;
-      #reset-cells = <1>;
-      #power-domain-cells = <1>;
-    };
-...
diff --git a/Documentation/devicetree/bindings/clock/qcom,sc7180-lpasscorecc.yaml b/Documentation/devicetree/bindings/clock/qcom,sc7180-lpasscorecc.yaml
new file mode 100644 (file)
index 0000000..c54172f
--- /dev/null
@@ -0,0 +1,108 @@
+# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/clock/qcom,sc7180-lpasscorecc.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: Qualcomm LPASS Core Clock Controller Binding for SC7180
+
+maintainers:
+  - Taniya Das <tdas@codeaurora.org>
+
+description: |
+  Qualcomm LPASS core clock control module which supports the clocks and
+  power domains on SC7180.
+
+  See also:
+  - dt-bindings/clock/qcom,lpasscorecc-sc7180.h
+
+properties:
+  compatible:
+    enum:
+      - qcom,sc7180-lpasshm
+      - qcom,sc7180-lpasscorecc
+
+  clocks:
+    items:
+      - description: gcc_lpass_sway clock from GCC
+      - description: Board XO source
+
+  clock-names:
+    items:
+      - const: iface
+      - const: bi_tcxo
+
+  power-domains:
+    maxItems: 1
+
+  '#clock-cells':
+    const: 1
+
+  '#power-domain-cells':
+    const: 1
+
+  reg:
+    minItems: 1
+    items:
+      - description: lpass core cc register
+      - description: lpass audio cc register
+
+  reg-names:
+    items:
+      - const: lpass_core_cc
+      - const: lpass_audio_cc
+
+if:
+  properties:
+    compatible:
+      contains:
+        const: qcom,sc7180-lpasshm
+then:
+  properties:
+    reg:
+      maxItems: 1
+
+else:
+  properties:
+    reg:
+      minItems: 2
+
+required:
+  - compatible
+  - reg
+  - clocks
+  - clock-names
+  - '#clock-cells'
+  - '#power-domain-cells'
+
+additionalProperties: false
+
+examples:
+  - |
+    #include <dt-bindings/clock/qcom,rpmh.h>
+    #include <dt-bindings/clock/qcom,gcc-sc7180.h>
+    #include <dt-bindings/clock/qcom,lpasscorecc-sc7180.h>
+    clock-controller@63000000 {
+      compatible = "qcom,sc7180-lpasshm";
+      reg = <0x63000000 0x28>;
+      clocks = <&gcc GCC_LPASS_CFG_NOC_SWAY_CLK>, <&rpmhcc RPMH_CXO_CLK>;
+      clock-names = "iface", "bi_tcxo";
+      #clock-cells = <1>;
+      #power-domain-cells = <1>;
+    };
+
+  - |
+    #include <dt-bindings/clock/qcom,rpmh.h>
+    #include <dt-bindings/clock/qcom,gcc-sc7180.h>
+    #include <dt-bindings/clock/qcom,lpasscorecc-sc7180.h>
+    clock-controller@62d00000 {
+      compatible = "qcom,sc7180-lpasscorecc";
+      reg = <0x62d00000 0x50000>, <0x62780000 0x30000>;
+      reg-names = "lpass_core_cc", "lpass_audio_cc";
+      clocks = <&gcc GCC_LPASS_CFG_NOC_SWAY_CLK>, <&rpmhcc RPMH_CXO_CLK>;
+      clock-names = "iface", "bi_tcxo";
+      power-domains = <&lpass_hm LPASS_CORE_HM_GDSCR>;
+      #clock-cells = <1>;
+      #power-domain-cells = <1>;
+    };
+...
diff --git a/Documentation/devicetree/bindings/clock/qcom,sdm845-gpucc.yaml b/Documentation/devicetree/bindings/clock/qcom,sdm845-gpucc.yaml
deleted file mode 100644 (file)
index 8a0c576..0000000
+++ /dev/null
@@ -1,74 +0,0 @@
-# SPDX-License-Identifier: GPL-2.0-only
-%YAML 1.2
----
-$id: http://devicetree.org/schemas/clock/qcom,sdm845-gpucc.yaml#
-$schema: http://devicetree.org/meta-schemas/core.yaml#
-
-title: Qualcomm Graphics Clock & Reset Controller Binding for SDM845
-
-maintainers:
-  - Taniya Das <tdas@codeaurora.org>
-
-description: |
-  Qualcomm graphics clock control module which supports the clocks, resets and
-  power domains on SDM845.
-
-  See also dt-bindings/clock/qcom,gpucc-sdm845.h.
-
-properties:
-  compatible:
-    const: qcom,sdm845-gpucc
-
-  clocks:
-    items:
-      - description: Board XO source
-      - description: GPLL0 main branch source
-      - description: GPLL0 div branch source
-
-  clock-names:
-    items:
-      - const: bi_tcxo
-      - const: gcc_gpu_gpll0_clk_src
-      - const: gcc_gpu_gpll0_div_clk_src
-
-  '#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-sdm845.h>
-    #include <dt-bindings/clock/qcom,rpmh.h>
-    clock-controller@5090000 {
-      compatible = "qcom,sdm845-gpucc";
-      reg = <0x05090000 0x9000>;
-      clocks = <&rpmhcc RPMH_CXO_CLK>,
-               <&gcc GCC_GPU_GPLL0_CLK_SRC>,
-               <&gcc GCC_GPU_GPLL0_DIV_CLK_SRC>;
-      clock-names = "bi_tcxo",
-                    "gcc_gpu_gpll0_clk_src",
-                    "gcc_gpu_gpll0_div_clk_src";
-      #clock-cells = <1>;
-      #reset-cells = <1>;
-      #power-domain-cells = <1>;
-    };
-...
index 8cb47c39ba53922e100bff2efd10420ed5af626a..bf3a9ec1924168a8a569e4d26b31cff5d8917903 100644 (file)
@@ -4,9 +4,15 @@ The RK3288 clock controller generates and supplies clock to various
 controllers within the SoC and also implements a reset controller for SoC
 peripherals.
 
+A revision of this SoC is available: rk3288w. The clock tree is a bit
+different so another dt-compatible is available. Noticed that it is only
+setting the difference but there is no automatic revision detection. This
+should be performed by bootloaders.
+
 Required Properties:
 
-- compatible: should be "rockchip,rk3288-cru"
+- compatible: should be "rockchip,rk3288-cru" or "rockchip,rk3288w-cru" in
+  case of this revision of Rockchip rk3288.
 - reg: physical base address of the controller and length of memory mapped
   region.
 - #clock-cells: should be 1.
index bf12d9f808e911d605335bbdfef195045ff46ec1..68b51b70ac8f5eef599f1177c1ffc377ffd4edbf 100644 (file)
@@ -1540,6 +1540,7 @@ F:        drivers/mmc/host/owl-mmc.c
 F:     drivers/pinctrl/actions/*
 F:     drivers/soc/actions/
 F:     include/dt-bindings/power/owl-*
+F:     include/dt-bindings/reset/actions,*
 F:     include/linux/soc/actions/
 N:     owl
 
@@ -8409,8 +8410,9 @@ W:        https://github.com/o2genum/ideapad-slidebar
 F:     drivers/input/misc/ideapad_slidebar.c
 
 IDT VersaClock 5 CLOCK DRIVER
-M:     Marek Vasut <marek.vasut@gmail.com>
+M:     Luca Ceresoli <luca@lucaceresoli.net>
 S:     Maintained
+F:     Documentation/devicetree/bindings/clock/idt,versaclock5.yaml
 F:     drivers/clk/clk-versaclock5.c
 
 IEEE 802.15.4 SUBSYSTEM
index 690a2587e0c5af9c8b851a791ef983c80fcd6531..4026fac9fac33f2a30ee8888c25e112c8479df0b 100644 (file)
@@ -50,7 +50,7 @@ source "drivers/clk/versatile/Kconfig"
 config CLK_HSDK
        bool "PLL Driver for HSDK platform"
        depends on OF || COMPILE_TEST
-       depends on IOMEM
+       depends on HAS_IOMEM
        help
          This driver supports the HSDK core, system, ddr, tunnel and hdmi PLLs
          control.
index ca9af11d3391301fb938638ab9365a6e4aee81cf..da8fcf147eb132ce2a15f5f748912775d893ac5a 100644 (file)
@@ -28,6 +28,7 @@ obj-$(CONFIG_COMMON_CLK_CDCE925)      += clk-cdce925.o
 obj-$(CONFIG_ARCH_CLPS711X)            += clk-clps711x.o
 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_SAI)       += clk-fsl-sai.o
 obj-$(CONFIG_COMMON_CLK_GEMINI)                += clk-gemini.o
index e2007ac4d235dee22e672caf1e0542b2ddd8cbdc..61bb224f633093c5f247116a0a8b460764817543 100644 (file)
 #include "owl-gate.h"
 #include "owl-mux.h"
 #include "owl-pll.h"
+#include "owl-reset.h"
 
 #include <dt-bindings/clock/actions,s500-cmu.h>
+#include <dt-bindings/reset/actions,s500-reset.h>
 
 #define CMU_COREPLL                    (0x0000)
 #define CMU_DEVPLL                     (0x0004)
@@ -175,6 +177,8 @@ static OWL_MUX(dev_clk, "dev_clk", dev_clk_mux_p, CMU_DEVPLL, 12, 1, CLK_SET_RAT
 static OWL_MUX(ahbprediv_clk, "ahbprediv_clk", ahbprediv_clk_mux_p, CMU_BUSCLK1, 8, 3, CLK_SET_RATE_PARENT);
 
 /* gate clocks */
+static OWL_GATE(gpio_clk, "gpio_clk", "apb_clk", CMU_DEVCLKEN0, 18, 0, 0);
+static OWL_GATE(dmac_clk, "dmac_clk", "h_clk", CMU_DEVCLKEN0, 1, 0, 0);
 static OWL_GATE(spi0_clk, "spi0_clk", "ahb_clk", CMU_DEVCLKEN1, 10, 0, CLK_IGNORE_UNUSED);
 static OWL_GATE(spi1_clk, "spi1_clk", "ahb_clk", CMU_DEVCLKEN1, 11, 0, CLK_IGNORE_UNUSED);
 static OWL_GATE(spi2_clk, "spi2_clk", "ahb_clk", CMU_DEVCLKEN1, 12, 0, CLK_IGNORE_UNUSED);
@@ -183,7 +187,8 @@ static OWL_GATE(timer_clk, "timer_clk", "hosc", CMU_DEVCLKEN1, 27, 0, 0);
 static OWL_GATE(hdmi_clk, "hdmi_clk", "hosc", CMU_DEVCLKEN1, 3, 0, 0);
 
 /* divider clocks */
-static OWL_DIVIDER(h_clk, "h_clk", "ahbprevdiv_clk", CMU_BUSCLK1, 12, 2, NULL, 0, 0);
+static OWL_DIVIDER(h_clk, "h_clk", "ahbprediv_clk", CMU_BUSCLK1, 12, 2, NULL, 0, 0);
+static OWL_DIVIDER(apb_clk, "apb_clk", "ahb_clk", CMU_BUSCLK1, 14, 2, NULL, 0, 0);
 static OWL_DIVIDER(rmii_ref_clk, "rmii_ref_clk", "ethernet_pll_clk", CMU_ETHERNETPLL, 1, 1, rmii_ref_div_table, 0, 0);
 
 /* factor clocks */
@@ -428,6 +433,9 @@ static struct owl_clk_common *s500_clks[] = {
        &spdif_clk.common,
        &nand_clk.common,
        &ecc_clk.common,
+       &apb_clk.common,
+       &dmac_clk.common,
+       &gpio_clk.common,
 };
 
 static struct clk_hw_onecell_data s500_hw_clks = {
@@ -484,24 +492,103 @@ static struct clk_hw_onecell_data s500_hw_clks = {
                [CLK_SPDIF]             = &spdif_clk.common.hw,
                [CLK_NAND]              = &nand_clk.common.hw,
                [CLK_ECC]               = &ecc_clk.common.hw,
+               [CLK_APB]               = &apb_clk.common.hw,
+               [CLK_DMAC]              = &dmac_clk.common.hw,
+               [CLK_GPIO]              = &gpio_clk.common.hw,
        },
        .num = CLK_NR_CLKS,
 };
 
+static const struct owl_reset_map s500_resets[] = {
+       [RESET_DMAC]    = { CMU_DEVRST0, BIT(0) },
+       [RESET_NORIF]   = { CMU_DEVRST0, BIT(1) },
+       [RESET_DDR]     = { CMU_DEVRST0, BIT(2) },
+       [RESET_NANDC]   = { CMU_DEVRST0, BIT(3) },
+       [RESET_SD0]     = { CMU_DEVRST0, BIT(4) },
+       [RESET_SD1]     = { CMU_DEVRST0, BIT(5) },
+       [RESET_PCM1]    = { CMU_DEVRST0, BIT(6) },
+       [RESET_DE]      = { CMU_DEVRST0, BIT(7) },
+       [RESET_LCD]     = { CMU_DEVRST0, BIT(8) },
+       [RESET_SD2]     = { CMU_DEVRST0, BIT(9) },
+       [RESET_DSI]     = { CMU_DEVRST0, BIT(10) },
+       [RESET_CSI]     = { CMU_DEVRST0, BIT(11) },
+       [RESET_BISP]    = { CMU_DEVRST0, BIT(12) },
+       [RESET_KEY]     = { CMU_DEVRST0, BIT(14) },
+       [RESET_GPIO]    = { CMU_DEVRST0, BIT(15) },
+       [RESET_AUDIO]   = { CMU_DEVRST0, BIT(17) },
+       [RESET_PCM0]    = { CMU_DEVRST0, BIT(18) },
+       [RESET_VDE]     = { CMU_DEVRST0, BIT(19) },
+       [RESET_VCE]     = { CMU_DEVRST0, BIT(20) },
+       [RESET_GPU3D]   = { CMU_DEVRST0, BIT(22) },
+       [RESET_NIC301]  = { CMU_DEVRST0, BIT(23) },
+       [RESET_LENS]    = { CMU_DEVRST0, BIT(26) },
+       [RESET_PERIPHRESET] = { CMU_DEVRST0, BIT(27) },
+       [RESET_USB2_0]  = { CMU_DEVRST1, BIT(0) },
+       [RESET_TVOUT]   = { CMU_DEVRST1, BIT(1) },
+       [RESET_HDMI]    = { CMU_DEVRST1, BIT(2) },
+       [RESET_HDCP2TX] = { CMU_DEVRST1, BIT(3) },
+       [RESET_UART6]   = { CMU_DEVRST1, BIT(4) },
+       [RESET_UART0]   = { CMU_DEVRST1, BIT(5) },
+       [RESET_UART1]   = { CMU_DEVRST1, BIT(6) },
+       [RESET_UART2]   = { CMU_DEVRST1, BIT(7) },
+       [RESET_SPI0]    = { CMU_DEVRST1, BIT(8) },
+       [RESET_SPI1]    = { CMU_DEVRST1, BIT(9) },
+       [RESET_SPI2]    = { CMU_DEVRST1, BIT(10) },
+       [RESET_SPI3]    = { CMU_DEVRST1, BIT(11) },
+       [RESET_I2C0]    = { CMU_DEVRST1, BIT(12) },
+       [RESET_I2C1]    = { CMU_DEVRST1, BIT(13) },
+       [RESET_USB3]    = { CMU_DEVRST1, BIT(14) },
+       [RESET_UART3]   = { CMU_DEVRST1, BIT(15) },
+       [RESET_UART4]   = { CMU_DEVRST1, BIT(16) },
+       [RESET_UART5]   = { CMU_DEVRST1, BIT(17) },
+       [RESET_I2C2]    = { CMU_DEVRST1, BIT(18) },
+       [RESET_I2C3]    = { CMU_DEVRST1, BIT(19) },
+       [RESET_ETHERNET] = { CMU_DEVRST1, BIT(20) },
+       [RESET_CHIPID]  = { CMU_DEVRST1, BIT(21) },
+       [RESET_USB2_1]  = { CMU_DEVRST1, BIT(22) },
+       [RESET_WD0RESET] = { CMU_DEVRST1, BIT(24) },
+       [RESET_WD1RESET] = { CMU_DEVRST1, BIT(25) },
+       [RESET_WD2RESET] = { CMU_DEVRST1, BIT(26) },
+       [RESET_WD3RESET] = { CMU_DEVRST1, BIT(27) },
+       [RESET_DBG0RESET] = { CMU_DEVRST1, BIT(28) },
+       [RESET_DBG1RESET] = { CMU_DEVRST1, BIT(29) },
+       [RESET_DBG2RESET] = { CMU_DEVRST1, BIT(30) },
+       [RESET_DBG3RESET] = { CMU_DEVRST1, BIT(31) },
+};
+
 static struct owl_clk_desc s500_clk_desc = {
        .clks       = s500_clks,
        .num_clks   = ARRAY_SIZE(s500_clks),
 
        .hw_clks    = &s500_hw_clks,
+
+       .resets     = s500_resets,
+       .num_resets = ARRAY_SIZE(s500_resets),
 };
 
 static int s500_clk_probe(struct platform_device *pdev)
 {
        struct owl_clk_desc *desc;
+       struct owl_reset *reset;
+       int ret;
 
        desc = &s500_clk_desc;
        owl_clk_regmap_init(pdev, desc);
 
+       reset = devm_kzalloc(&pdev->dev, sizeof(*reset), GFP_KERNEL);
+       if (!reset)
+               return -ENOMEM;
+
+       reset->rcdev.of_node = pdev->dev.of_node;
+       reset->rcdev.ops = &owl_reset_ops;
+       reset->rcdev.nr_resets = desc->num_resets;
+       reset->reset_map = desc->resets;
+       reset->regmap = desc->regmap;
+
+       ret = devm_reset_controller_register(&pdev->dev, &reset->rcdev);
+       if (ret)
+               dev_err(&pdev->dev, "Failed to register reset controller\n");
+
        return owl_clk_probe(&pdev->dev, desc->hw_clks);
 }
 
index 8b90357f2a93cc66f6924423ff41855b3dce0c6a..79301e1c1c362598c8243a6026e8ab8ad16cbe6d 100644 (file)
@@ -23,3 +23,4 @@ obj-$(CONFIG_SOC_SAM9X60) += sam9x60.o
 obj-$(CONFIG_SOC_SAMA5D3) += sama5d3.o
 obj-$(CONFIG_SOC_SAMA5D4) += sama5d4.o
 obj-$(CONFIG_SOC_SAMA5D2) += sama5d2.o
+obj-$(CONFIG_SOC_SAMA7G5) += sama7g5.o
index 38bdb498131584d4c1270f1b37f0f5f8b40f9124..2c3d8e6ca63cacdfec37c8e9f468c2168af347ac 100644 (file)
@@ -160,7 +160,8 @@ static void __init at91rm9200_pmc_setup(struct device_node *np)
 
                hw = at91_clk_register_programmable(regmap, name,
                                                    parent_names, 4, i,
-                                                   &at91rm9200_programmable_layout);
+                                                   &at91rm9200_programmable_layout,
+                                                   NULL);
                if (IS_ERR(hw))
                        goto err_free;
 
index 6d0723aa8b1380e2419ba084ec5797b6605ee7be..bb81ff731ad83009fb8cc7a66219107f65e44b29 100644 (file)
@@ -436,7 +436,8 @@ static void __init at91sam926x_pmc_setup(struct device_node *np,
 
                hw = at91_clk_register_programmable(regmap, name,
                                                    parent_names, 4, i,
-                                                   &at91rm9200_programmable_layout);
+                                                   &at91rm9200_programmable_layout,
+                                                   NULL);
                if (IS_ERR(hw))
                        goto err_free;
 
index 9873b583c26045e1b807c7fde906da3f9fa0e1fb..c88ee20bee311576b5551c5a9dbd5fa07047dea9 100644 (file)
@@ -111,7 +111,7 @@ static void __init at91sam9g45_pmc_setup(struct device_node *np)
                return;
        mainxtal_name = of_clk_get_parent_name(np, i);
 
-       regmap = syscon_node_to_regmap(np);
+       regmap = device_node_to_regmap(np);
        if (IS_ERR(regmap))
                return;
 
@@ -181,7 +181,8 @@ static void __init at91sam9g45_pmc_setup(struct device_node *np)
 
                hw = at91_clk_register_programmable(regmap, name,
                                                    parent_names, 5, i,
-                                                   &at91sam9g45_programmable_layout);
+                                                   &at91sam9g45_programmable_layout,
+                                                   NULL);
                if (IS_ERR(hw))
                        goto err_free;
 
index 630dc5d87171ad74d7d95e841e915fe56d24f28f..93f7eb216122a4de1ec7176280a980aa672c8b83 100644 (file)
@@ -124,7 +124,7 @@ static void __init at91sam9n12_pmc_setup(struct device_node *np)
                return;
        mainxtal_name = of_clk_get_parent_name(np, i);
 
-       regmap = syscon_node_to_regmap(np);
+       regmap = device_node_to_regmap(np);
        if (IS_ERR(regmap))
                return;
 
@@ -199,7 +199,8 @@ static void __init at91sam9n12_pmc_setup(struct device_node *np)
 
                hw = at91_clk_register_programmable(regmap, name,
                                                    parent_names, 5, i,
-                                                   &at91sam9x5_programmable_layout);
+                                                   &at91sam9x5_programmable_layout,
+                                                   NULL);
                if (IS_ERR(hw))
                        goto err_free;
 
@@ -222,7 +223,7 @@ static void __init at91sam9n12_pmc_setup(struct device_node *np)
                                                         at91sam9n12_periphck[i].n,
                                                         "masterck",
                                                         at91sam9n12_periphck[i].id,
-                                                        &range);
+                                                        &range, INT_MIN);
                if (IS_ERR(hw))
                        goto err_free;
 
index 0d1cc44b056ff42e8aeff4386fb307f4a0a0b785..a343eb69bb353cd3049a3f42365dbfa5b345a741 100644 (file)
@@ -137,7 +137,8 @@ static void __init at91sam9rl_pmc_setup(struct device_node *np)
 
                hw = at91_clk_register_programmable(regmap, name,
                                                    parent_names, 5, i,
-                                                   &at91rm9200_programmable_layout);
+                                                   &at91rm9200_programmable_layout,
+                                                   NULL);
                if (IS_ERR(hw))
                        goto err_free;
 
index 0ce3da0802876af0ff0a8b6026e49c781b369b20..22b9aad9efb8dbb5d3780eb299e8be8e2ca12f35 100644 (file)
@@ -226,7 +226,8 @@ static void __init at91sam9x5_pmc_setup(struct device_node *np,
 
                hw = at91_clk_register_programmable(regmap, name,
                                                    parent_names, 5, i,
-                                                   &at91sam9x5_programmable_layout);
+                                                   &at91sam9x5_programmable_layout,
+                                                   NULL);
                if (IS_ERR(hw))
                        goto err_free;
 
@@ -257,7 +258,7 @@ static void __init at91sam9x5_pmc_setup(struct device_node *np,
                                                         at91sam9x5_periphck[i].n,
                                                         "masterck",
                                                         at91sam9x5_periphck[i].id,
-                                                        &range);
+                                                        &range, INT_MIN);
                if (IS_ERR(hw))
                        goto err_free;
 
@@ -270,7 +271,7 @@ static void __init at91sam9x5_pmc_setup(struct device_node *np,
                                                         extra_pcks[i].n,
                                                         "masterck",
                                                         extra_pcks[i].id,
-                                                        &range);
+                                                        &range, INT_MIN);
                if (IS_ERR(hw))
                        goto err_free;
 
index 44a46dcc0518b6516764f9a78832a7cbc427f047..b4fc8d71daf20fefeec201ac380984b99afa2d44 100644 (file)
 
 #define GENERATED_MAX_DIV      255
 
-#define GCK_INDEX_DT_AUDIO_PLL 5
-
 struct clk_generated {
        struct clk_hw hw;
        struct regmap *regmap;
        struct clk_range range;
        spinlock_t *lock;
+       u32 *mux_table;
        u32 id;
        u32 gckdiv;
        const struct clk_pcr_layout *layout;
        u8 parent_id;
-       bool audio_pll_allowed;
+       int chg_pid;
 };
 
 #define to_clk_generated(hw) \
@@ -83,7 +82,7 @@ static int clk_generated_is_enabled(struct clk_hw *hw)
        regmap_read(gck->regmap, gck->layout->offset, &status);
        spin_unlock_irqrestore(gck->lock, flags);
 
-       return status & AT91_PMC_PCR_GCKEN ? 1 : 0;
+       return !!(status & AT91_PMC_PCR_GCKEN);
 }
 
 static unsigned long
@@ -109,7 +108,7 @@ static void clk_generated_best_diff(struct clk_rate_request *req,
                tmp_rate = parent_rate / div;
        tmp_diff = abs(req->rate - tmp_rate);
 
-       if (*best_diff < 0 || *best_diff > tmp_diff) {
+       if (*best_diff < 0 || *best_diff >= tmp_diff) {
                *best_rate = tmp_rate;
                *best_diff = tmp_diff;
                req->best_parent_rate = parent_rate;
@@ -129,7 +128,10 @@ static int clk_generated_determine_rate(struct clk_hw *hw,
        int i;
        u32 div;
 
-       for (i = 0; i < clk_hw_get_num_parents(hw) - 1; i++) {
+       for (i = 0; i < clk_hw_get_num_parents(hw); i++) {
+               if (gck->chg_pid == i)
+                       continue;
+
                parent = clk_hw_get_parent_by_index(hw, i);
                if (!parent)
                        continue;
@@ -161,16 +163,17 @@ static int clk_generated_determine_rate(struct clk_hw *hw,
         * that the only clks able to modify gck rate are those of audio IPs.
         */
 
-       if (!gck->audio_pll_allowed)
+       if (gck->chg_pid < 0)
                goto end;
 
-       parent = clk_hw_get_parent_by_index(hw, GCK_INDEX_DT_AUDIO_PLL);
+       parent = clk_hw_get_parent_by_index(hw, gck->chg_pid);
        if (!parent)
                goto end;
 
        for (div = 1; div < GENERATED_MAX_DIV + 2; div++) {
                req_parent.rate = req->rate * div;
-               __clk_determine_rate(parent, &req_parent);
+               if (__clk_determine_rate(parent, &req_parent))
+                       continue;
                clk_generated_best_diff(req, parent, req_parent.rate, div,
                                        &best_diff, &best_rate);
 
@@ -184,8 +187,8 @@ end:
                 __clk_get_name((req->best_parent_hw)->clk),
                 req->best_parent_rate);
 
-       if (best_rate < 0)
-               return best_rate;
+       if (best_rate < 0 || (gck->range.max && best_rate > gck->range.max))
+               return -EINVAL;
 
        req->rate = best_rate;
        return 0;
@@ -199,7 +202,11 @@ static int clk_generated_set_parent(struct clk_hw *hw, u8 index)
        if (index >= clk_hw_get_num_parents(hw))
                return -EINVAL;
 
-       gck->parent_id = index;
+       if (gck->mux_table)
+               gck->parent_id = clk_mux_index_to_val(gck->mux_table, 0, index);
+       else
+               gck->parent_id = index;
+
        return 0;
 }
 
@@ -271,8 +278,9 @@ struct clk_hw * __init
 at91_clk_register_generated(struct regmap *regmap, spinlock_t *lock,
                            const struct clk_pcr_layout *layout,
                            const char *name, const char **parent_names,
-                           u8 num_parents, u8 id, bool pll_audio,
-                           const struct clk_range *range)
+                           u32 *mux_table, u8 num_parents, u8 id,
+                           const struct clk_range *range,
+                           int chg_pid)
 {
        struct clk_generated *gck;
        struct clk_init_data init;
@@ -287,16 +295,18 @@ at91_clk_register_generated(struct regmap *regmap, spinlock_t *lock,
        init.ops = &generated_ops;
        init.parent_names = parent_names;
        init.num_parents = num_parents;
-       init.flags = CLK_SET_RATE_GATE | CLK_SET_PARENT_GATE |
-               CLK_SET_RATE_PARENT;
+       init.flags = CLK_SET_RATE_GATE | CLK_SET_PARENT_GATE;
+       if (chg_pid >= 0)
+               init.flags |= CLK_SET_RATE_PARENT;
 
        gck->id = id;
        gck->hw.init = &init;
        gck->regmap = regmap;
        gck->lock = lock;
        gck->range = *range;
-       gck->audio_pll_allowed = pll_audio;
+       gck->chg_pid = chg_pid;
        gck->layout = layout;
+       gck->mux_table = mux_table;
 
        clk_generated_startup(gck);
        hw = &gck->hw;
index 37c22667e8319011aa5528613c26a9e0544e3e6e..5c83e899084ffe9e1d3955e5aa074991bc998b33 100644 (file)
@@ -175,7 +175,7 @@ static bool clk_main_rc_osc_ready(struct regmap *regmap)
 
        regmap_read(regmap, AT91_PMC_SR, &status);
 
-       return status & AT91_PMC_MOSCRCS;
+       return !!(status & AT91_PMC_MOSCRCS);
 }
 
 static int clk_main_rc_osc_prepare(struct clk_hw *hw)
@@ -336,7 +336,7 @@ static int clk_rm9200_main_is_prepared(struct clk_hw *hw)
 
        regmap_read(clkmain->regmap, AT91_CKGR_MCFR, &status);
 
-       return status & AT91_PMC_MAINRDY ? 1 : 0;
+       return !!(status & AT91_PMC_MAINRDY);
 }
 
 static unsigned long clk_rm9200_main_recalc_rate(struct clk_hw *hw,
@@ -398,7 +398,7 @@ static inline bool clk_sam9x5_main_ready(struct regmap *regmap)
 
        regmap_read(regmap, AT91_PMC_SR, &status);
 
-       return status & AT91_PMC_MOSCSELS ? 1 : 0;
+       return !!(status & AT91_PMC_MOSCSELS);
 }
 
 static int clk_sam9x5_main_prepare(struct clk_hw *hw)
index e7e0ba652de1aad8313342cc7a0ed6a8b32d1ee6..bd0d8a69a2cf88a5879dfe65ee67ded478a8c41c 100644 (file)
 #define MASTER_DIV_SHIFT       8
 #define MASTER_DIV_MASK                0x3
 
+#define PMC_MCR                        0x30
+#define PMC_MCR_ID_MSK         GENMASK(3, 0)
+#define PMC_MCR_CMD            BIT(7)
+#define PMC_MCR_DIV            GENMASK(10, 8)
+#define PMC_MCR_CSS            GENMASK(20, 16)
+#define PMC_MCR_CSS_SHIFT      (16)
+#define PMC_MCR_EN             BIT(28)
+
+#define PMC_MCR_ID(x)          ((x) & PMC_MCR_ID_MSK)
+
+#define MASTER_MAX_ID          4
+
 #define to_clk_master(hw) container_of(hw, struct clk_master, hw)
 
 struct clk_master {
        struct clk_hw hw;
        struct regmap *regmap;
+       spinlock_t *lock;
        const struct clk_master_layout *layout;
        const struct clk_master_characteristics *characteristics;
+       u32 *mux_table;
        u32 mckr;
+       int chg_pid;
+       u8 id;
+       u8 parent;
+       u8 div;
 };
 
-static inline bool clk_master_ready(struct regmap *regmap)
+static inline bool clk_master_ready(struct clk_master *master)
 {
+       unsigned int bit = master->id ? AT91_PMC_MCKXRDY : AT91_PMC_MCKRDY;
        unsigned int status;
 
-       regmap_read(regmap, AT91_PMC_SR, &status);
+       regmap_read(master->regmap, AT91_PMC_SR, &status);
 
-       return status & AT91_PMC_MCKRDY ? 1 : 0;
+       return !!(status & bit);
 }
 
 static int clk_master_prepare(struct clk_hw *hw)
 {
        struct clk_master *master = to_clk_master(hw);
 
-       while (!clk_master_ready(master->regmap))
+       while (!clk_master_ready(master))
                cpu_relax();
 
        return 0;
@@ -50,7 +69,7 @@ static int clk_master_is_prepared(struct clk_hw *hw)
 {
        struct clk_master *master = to_clk_master(hw);
 
-       return clk_master_ready(master->regmap);
+       return clk_master_ready(master);
 }
 
 static unsigned long clk_master_recalc_rate(struct clk_hw *hw,
@@ -143,6 +162,287 @@ 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_master *master = to_clk_master(hw);
+
+       return DIV_ROUND_CLOSEST_ULL(parent_rate, (1 << master->div));
+}
+
+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_sama7g5_master_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;
+       struct clk_hw *parent;
+       long best_rate = LONG_MIN, best_diff = LONG_MIN;
+       unsigned long parent_rate;
+       unsigned int div, i;
+
+       /* First: check the dividers of MCR. */
+       for (i = 0; i < clk_hw_get_num_parents(hw); i++) {
+               parent = clk_hw_get_parent_by_index(hw, i);
+               if (!parent)
+                       continue;
+
+               parent_rate = clk_hw_get_rate(parent);
+               if (!parent_rate)
+                       continue;
+
+               for (div = 0; div < MASTER_PRES_MAX + 1; div++) {
+                       clk_sama7g5_master_best_diff(req, parent, parent_rate,
+                                                    &best_rate, &best_diff,
+                                                    div);
+                       if (!best_diff)
+                               break;
+               }
+
+               if (!best_diff)
+                       break;
+       }
+
+       /* Second: try to request rate form changeable parent. */
+       if (master->chg_pid < 0)
+               goto end;
+
+       parent = clk_hw_get_parent_by_index(hw, master->chg_pid);
+       if (!parent)
+               goto end;
+
+       for (div = 0; div < MASTER_PRES_MAX + 1; div++) {
+               if (div == MASTER_PRES_MAX)
+                       req_parent.rate = req->rate * 3;
+               else
+                       req_parent.rate = req->rate << div;
+
+               if (__clk_determine_rate(parent, &req_parent))
+                       continue;
+
+               clk_sama7g5_master_best_diff(req, parent, req_parent.rate,
+                                            &best_rate, &best_diff, div);
+
+               if (!best_diff)
+                       break;
+       }
+
+end:
+       pr_debug("MCK: %s, best_rate = %ld, parent clk: %s @ %ld\n",
+                __func__, best_rate,
+                __clk_get_name((req->best_parent_hw)->clk),
+               req->best_parent_rate);
+
+       if (best_rate < 0)
+               return -EINVAL;
+
+       req->rate = best_rate;
+
+       return 0;
+}
+
+static u8 clk_sama7g5_master_get_parent(struct clk_hw *hw)
+{
+       struct clk_master *master = to_clk_master(hw);
+       unsigned long flags;
+       u8 index;
+
+       spin_lock_irqsave(master->lock, flags);
+       index = clk_mux_val_to_index(&master->hw, master->mux_table, 0,
+                                    master->parent);
+       spin_unlock_irqrestore(master->lock, flags);
+
+       return index;
+}
+
+static int clk_sama7g5_master_set_parent(struct clk_hw *hw, u8 index)
+{
+       struct clk_master *master = to_clk_master(hw);
+       unsigned long flags;
+
+       if (index >= clk_hw_get_num_parents(hw))
+               return -EINVAL;
+
+       spin_lock_irqsave(master->lock, flags);
+       master->parent = clk_mux_index_to_val(master->mux_table, 0, index);
+       spin_unlock_irqrestore(master->lock, flags);
+
+       return 0;
+}
+
+static int clk_sama7g5_master_enable(struct clk_hw *hw)
+{
+       struct clk_master *master = to_clk_master(hw);
+       unsigned long flags;
+       unsigned int val, cparent;
+
+       spin_lock_irqsave(master->lock, flags);
+
+       regmap_write(master->regmap, PMC_MCR, PMC_MCR_ID(master->id));
+       regmap_read(master->regmap, PMC_MCR, &val);
+       regmap_update_bits(master->regmap, PMC_MCR,
+                          PMC_MCR_EN | PMC_MCR_CSS | PMC_MCR_DIV |
+                          PMC_MCR_CMD | PMC_MCR_ID_MSK,
+                          PMC_MCR_EN | (master->parent << PMC_MCR_CSS_SHIFT) |
+                          (master->div << MASTER_DIV_SHIFT) |
+                          PMC_MCR_CMD | PMC_MCR_ID(master->id));
+
+       cparent = (val & PMC_MCR_CSS) >> PMC_MCR_CSS_SHIFT;
+
+       /* Wait here only if parent is being changed. */
+       while ((cparent != master->parent) && !clk_master_ready(master))
+               cpu_relax();
+
+       spin_unlock_irqrestore(master->lock, flags);
+
+       return 0;
+}
+
+static void clk_sama7g5_master_disable(struct clk_hw *hw)
+{
+       struct clk_master *master = to_clk_master(hw);
+       unsigned long flags;
+
+       spin_lock_irqsave(master->lock, flags);
+
+       regmap_write(master->regmap, PMC_MCR, master->id);
+       regmap_update_bits(master->regmap, PMC_MCR,
+                          PMC_MCR_EN | PMC_MCR_CMD | PMC_MCR_ID_MSK,
+                          PMC_MCR_CMD | PMC_MCR_ID(master->id));
+
+       spin_unlock_irqrestore(master->lock, flags);
+}
+
+static int clk_sama7g5_master_is_enabled(struct clk_hw *hw)
+{
+       struct clk_master *master = to_clk_master(hw);
+       unsigned long flags;
+       unsigned int val;
+
+       spin_lock_irqsave(master->lock, flags);
+
+       regmap_write(master->regmap, PMC_MCR, master->id);
+       regmap_read(master->regmap, PMC_MCR, &val);
+
+       spin_unlock_irqrestore(master->lock, flags);
+
+       return !!(val & PMC_MCR_EN);
+}
+
+static int clk_sama7g5_master_set_rate(struct clk_hw *hw, unsigned long rate,
+                                      unsigned long parent_rate)
+{
+       struct clk_master *master = to_clk_master(hw);
+       unsigned long div, flags;
+
+       div = DIV_ROUND_CLOSEST(parent_rate, rate);
+       if ((div > (1 << (MASTER_PRES_MAX - 1))) || (div & (div - 1)))
+               return -EINVAL;
+
+       if (div == 3)
+               div = MASTER_PRES_MAX;
+       else
+               div = ffs(div) - 1;
+
+       spin_lock_irqsave(master->lock, flags);
+       master->div = div;
+       spin_unlock_irqrestore(master->lock, flags);
+
+       return 0;
+}
+
+static const struct clk_ops sama7g5_master_ops = {
+       .enable = clk_sama7g5_master_enable,
+       .disable = clk_sama7g5_master_disable,
+       .is_enabled = clk_sama7g5_master_is_enabled,
+       .recalc_rate = clk_sama7g5_master_recalc_rate,
+       .determine_rate = clk_sama7g5_master_determine_rate,
+       .set_rate = clk_sama7g5_master_set_rate,
+       .get_parent = clk_sama7g5_master_get_parent,
+       .set_parent = clk_sama7g5_master_set_parent,
+};
+
+struct clk_hw * __init
+at91_clk_sama7g5_register_master(struct regmap *regmap,
+                                const char *name, int num_parents,
+                                const char **parent_names,
+                                u32 *mux_table,
+                                spinlock_t *lock, u8 id,
+                                bool critical, int chg_pid)
+{
+       struct clk_master *master;
+       struct clk_hw *hw;
+       struct clk_init_data init;
+       unsigned long flags;
+       unsigned int val;
+       int ret;
+
+       if (!name || !num_parents || !parent_names || !mux_table ||
+           !lock || id > MASTER_MAX_ID)
+               return ERR_PTR(-EINVAL);
+
+       master = kzalloc(sizeof(*master), GFP_KERNEL);
+       if (!master)
+               return ERR_PTR(-ENOMEM);
+
+       init.name = name;
+       init.ops = &sama7g5_master_ops;
+       init.parent_names = parent_names;
+       init.num_parents = num_parents;
+       init.flags = CLK_SET_RATE_GATE | CLK_SET_PARENT_GATE;
+       if (chg_pid >= 0)
+               init.flags |= CLK_SET_RATE_PARENT;
+       if (critical)
+               init.flags |= CLK_IS_CRITICAL;
+
+       master->hw.init = &init;
+       master->regmap = regmap;
+       master->id = id;
+       master->chg_pid = chg_pid;
+       master->lock = lock;
+       master->mux_table = mux_table;
+
+       spin_lock_irqsave(master->lock, flags);
+       regmap_write(master->regmap, PMC_MCR, master->id);
+       regmap_read(master->regmap, PMC_MCR, &val);
+       master->parent = (val & PMC_MCR_CSS) >> PMC_MCR_CSS_SHIFT;
+       master->div = (val & PMC_MCR_DIV) >> MASTER_DIV_SHIFT;
+       spin_unlock_irqrestore(master->lock, flags);
+
+       hw = &master->hw;
+       ret = clk_hw_register(NULL, &master->hw);
+       if (ret) {
+               kfree(master);
+               hw = ERR_PTR(ret);
+       }
+
+       return hw;
+}
+
 const struct clk_master_layout at91rm9200_master_layout = {
        .mask = 0x31F,
        .pres_shift = 2,
index c2ab4860a2bfdd56fd8fa48f7af6fbb3a0cbf589..7867eaf0447fe34e015a8996a2022e6bf10a137b 100644 (file)
@@ -38,6 +38,7 @@ struct clk_sam9x5_peripheral {
        u32 div;
        const struct clk_pcr_layout *layout;
        bool auto_div;
+       int chg_pid;
 };
 
 #define to_clk_sam9x5_peripheral(hw) \
@@ -208,7 +209,7 @@ static int clk_sam9x5_peripheral_is_enabled(struct clk_hw *hw)
        regmap_read(periph->regmap, periph->layout->offset, &status);
        spin_unlock_irqrestore(periph->lock, flags);
 
-       return status & AT91_PMC_PCR_EN ? 1 : 0;
+       return !!(status & AT91_PMC_PCR_EN);
 }
 
 static unsigned long
@@ -238,6 +239,87 @@ clk_sam9x5_peripheral_recalc_rate(struct clk_hw *hw,
        return parent_rate >> periph->div;
 }
 
+static void clk_sam9x5_peripheral_best_diff(struct clk_rate_request *req,
+                                           struct clk_hw *parent,
+                                           unsigned long parent_rate,
+                                           u32 shift, long *best_diff,
+                                           long *best_rate)
+{
+       unsigned long tmp_rate = parent_rate >> shift;
+       unsigned long 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_sam9x5_peripheral_determine_rate(struct clk_hw *hw,
+                                               struct clk_rate_request *req)
+{
+       struct clk_sam9x5_peripheral *periph = to_clk_sam9x5_peripheral(hw);
+       struct clk_hw *parent = clk_hw_get_parent(hw);
+       struct clk_rate_request req_parent = *req;
+       unsigned long parent_rate = clk_hw_get_rate(parent);
+       unsigned long tmp_rate;
+       long best_rate = LONG_MIN;
+       long best_diff = LONG_MIN;
+       u32 shift;
+
+       if (periph->id < PERIPHERAL_ID_MIN || !periph->range.max)
+               return parent_rate;
+
+       /* Fist step: check the available dividers. */
+       for (shift = 0; shift <= PERIPHERAL_MAX_SHIFT; shift++) {
+               tmp_rate = parent_rate >> shift;
+
+               if (periph->range.max && tmp_rate > periph->range.max)
+                       continue;
+
+               clk_sam9x5_peripheral_best_diff(req, parent, parent_rate,
+                                               shift, &best_diff, &best_rate);
+
+               if (!best_diff || best_rate <= req->rate)
+                       break;
+       }
+
+       if (periph->chg_pid < 0)
+               goto end;
+
+       /* Step two: try to request rate from parent. */
+       parent = clk_hw_get_parent_by_index(hw, periph->chg_pid);
+       if (!parent)
+               goto end;
+
+       for (shift = 0; shift <= PERIPHERAL_MAX_SHIFT; shift++) {
+               req_parent.rate = req->rate << shift;
+
+               if (__clk_determine_rate(parent, &req_parent))
+                       continue;
+
+               clk_sam9x5_peripheral_best_diff(req, parent, req_parent.rate,
+                                               shift, &best_diff, &best_rate);
+
+               if (!best_diff)
+                       break;
+       }
+end:
+       if (best_rate < 0 ||
+           (periph->range.max && best_rate > periph->range.max))
+               return -EINVAL;
+
+       pr_debug("PCK: %s, best_rate = %ld, parent clk: %s @ %ld\n",
+                __func__, best_rate,
+                __clk_get_name((req->best_parent_hw)->clk),
+                req->best_parent_rate);
+
+       req->rate = best_rate;
+
+       return 0;
+}
+
 static long clk_sam9x5_peripheral_round_rate(struct clk_hw *hw,
                                             unsigned long rate,
                                             unsigned long *parent_rate)
@@ -320,11 +402,21 @@ static const struct clk_ops sam9x5_peripheral_ops = {
        .set_rate = clk_sam9x5_peripheral_set_rate,
 };
 
+static const struct clk_ops sam9x5_peripheral_chg_ops = {
+       .enable = clk_sam9x5_peripheral_enable,
+       .disable = clk_sam9x5_peripheral_disable,
+       .is_enabled = clk_sam9x5_peripheral_is_enabled,
+       .recalc_rate = clk_sam9x5_peripheral_recalc_rate,
+       .determine_rate = clk_sam9x5_peripheral_determine_rate,
+       .set_rate = clk_sam9x5_peripheral_set_rate,
+};
+
 struct clk_hw * __init
 at91_clk_register_sam9x5_peripheral(struct regmap *regmap, spinlock_t *lock,
                                    const struct clk_pcr_layout *layout,
                                    const char *name, const char *parent_name,
-                                   u32 id, const struct clk_range *range)
+                                   u32 id, const struct clk_range *range,
+                                   int chg_pid)
 {
        struct clk_sam9x5_peripheral *periph;
        struct clk_init_data init;
@@ -339,10 +431,16 @@ at91_clk_register_sam9x5_peripheral(struct regmap *regmap, spinlock_t *lock,
                return ERR_PTR(-ENOMEM);
 
        init.name = name;
-       init.ops = &sam9x5_peripheral_ops;
-       init.parent_names = (parent_name ? &parent_name : NULL);
-       init.num_parents = (parent_name ? 1 : 0);
-       init.flags = 0;
+       init.parent_names = &parent_name;
+       init.num_parents = 1;
+       if (chg_pid < 0) {
+               init.flags = 0;
+               init.ops = &sam9x5_peripheral_ops;
+       } else {
+               init.flags = CLK_SET_RATE_GATE | CLK_SET_PARENT_GATE |
+                            CLK_SET_RATE_PARENT;
+               init.ops = &sam9x5_peripheral_chg_ops;
+       }
 
        periph->id = id;
        periph->hw.init = &init;
@@ -353,6 +451,7 @@ at91_clk_register_sam9x5_peripheral(struct regmap *regmap, spinlock_t *lock,
                periph->auto_div = true;
        periph->layout = layout;
        periph->range = *range;
+       periph->chg_pid = chg_pid;
 
        hw = &periph->hw;
        ret = clk_hw_register(NULL, &periph->hw);
index 8ee66fbee3d9e614a26f1b2a431ab5e6ada1eae8..fcf8f6a1c2c60ec1ddfc8920ccfb33d4fb6d466c 100644 (file)
@@ -21,6 +21,7 @@
 struct clk_programmable {
        struct clk_hw hw;
        struct regmap *regmap;
+       u32 *mux_table;
        u8 id;
        const struct clk_programmable_layout *layout;
 };
@@ -108,6 +109,9 @@ static int clk_programmable_set_parent(struct clk_hw *hw, u8 index)
        if (layout->have_slck_mck)
                mask |= AT91_PMC_CSSMCK_MCK;
 
+       if (prog->mux_table)
+               pckr = clk_mux_index_to_val(prog->mux_table, 0, index);
+
        if (index > layout->css_mask) {
                if (index > PROG_MAX_RM9200_CSS && !layout->have_slck_mck)
                        return -EINVAL;
@@ -134,6 +138,9 @@ static u8 clk_programmable_get_parent(struct clk_hw *hw)
        if (layout->have_slck_mck && (pckr & AT91_PMC_CSSMCK_MCK) && !ret)
                ret = PROG_MAX_RM9200_CSS + 1;
 
+       if (prog->mux_table)
+               ret = clk_mux_val_to_index(&prog->hw, prog->mux_table, 0, ret);
+
        return ret;
 }
 
@@ -182,7 +189,8 @@ struct clk_hw * __init
 at91_clk_register_programmable(struct regmap *regmap,
                               const char *name, const char **parent_names,
                               u8 num_parents, u8 id,
-                              const struct clk_programmable_layout *layout)
+                              const struct clk_programmable_layout *layout,
+                              u32 *mux_table)
 {
        struct clk_programmable *prog;
        struct clk_hw *hw;
@@ -206,6 +214,7 @@ at91_clk_register_programmable(struct regmap *regmap,
        prog->layout = layout;
        prog->hw.init = &init;
        prog->regmap = regmap;
+       prog->mux_table = mux_table;
 
        hw = &prog->hw;
        ret = clk_hw_register(NULL, &prog->hw);
index e699803986e507da2e7c3eeb978aade19cb7c496..b473298ef7e67c188fa44939304fa5dbc8767534 100644 (file)
 #include "pmc.h"
 
 #define        PMC_PLL_CTRL0_DIV_MSK   GENMASK(7, 0)
-#define        PMC_PLL_CTRL1_MUL_MSK   GENMASK(30, 24)
+#define        PMC_PLL_CTRL1_MUL_MSK   GENMASK(31, 24)
+#define        PMC_PLL_CTRL1_FRACR_MSK GENMASK(21, 0)
 
 #define PLL_DIV_MAX            (FIELD_GET(PMC_PLL_CTRL0_DIV_MSK, UINT_MAX) + 1)
 #define UPLL_DIV               2
 #define PLL_MUL_MAX            (FIELD_GET(PMC_PLL_CTRL1_MUL_MSK, UINT_MAX) + 1)
 
-#define PLL_MAX_ID             1
+#define FCORE_MIN              (600000000)
+#define FCORE_MAX              (1200000000)
 
-struct sam9x60_pll {
-       struct clk_hw hw;
+#define PLL_MAX_ID             7
+
+struct sam9x60_pll_core {
        struct regmap *regmap;
        spinlock_t *lock;
        const struct clk_pll_characteristics *characteristics;
-       u32 frac;
+       const struct clk_pll_layout *layout;
+       struct clk_hw hw;
        u8 id;
-       u8 div;
+};
+
+struct sam9x60_frac {
+       struct sam9x60_pll_core core;
+       u32 frac;
        u16 mul;
 };
 
-#define to_sam9x60_pll(hw) container_of(hw, struct sam9x60_pll, hw)
+struct sam9x60_div {
+       struct sam9x60_pll_core core;
+       u8 div;
+};
+
+#define to_sam9x60_pll_core(hw)        container_of(hw, struct sam9x60_pll_core, hw)
+#define to_sam9x60_frac(core)  container_of(core, struct sam9x60_frac, core)
+#define to_sam9x60_div(core)   container_of(core, struct sam9x60_div, core)
 
 static inline bool sam9x60_pll_ready(struct regmap *regmap, int id)
 {
@@ -45,41 +60,53 @@ static inline bool sam9x60_pll_ready(struct regmap *regmap, int id)
        return !!(status & BIT(id));
 }
 
-static int sam9x60_pll_prepare(struct clk_hw *hw)
+static bool sam9x60_frac_pll_ready(struct regmap *regmap, u8 id)
 {
-       struct sam9x60_pll *pll = to_sam9x60_pll(hw);
-       struct regmap *regmap = pll->regmap;
-       unsigned long flags;
-       u8 div;
-       u16 mul;
-       u32 val;
+       return sam9x60_pll_ready(regmap, id);
+}
 
-       spin_lock_irqsave(pll->lock, flags);
-       regmap_write(regmap, AT91_PMC_PLL_UPDT, pll->id);
+static unsigned long sam9x60_frac_pll_recalc_rate(struct clk_hw *hw,
+                                                 unsigned long parent_rate)
+{
+       struct sam9x60_pll_core *core = to_sam9x60_pll_core(hw);
+       struct sam9x60_frac *frac = to_sam9x60_frac(core);
 
-       regmap_read(regmap, AT91_PMC_PLL_CTRL0, &val);
-       div = FIELD_GET(PMC_PLL_CTRL0_DIV_MSK, val);
+       return (parent_rate * (frac->mul + 1) +
+               ((u64)parent_rate * frac->frac >> 22));
+}
 
+static int sam9x60_frac_pll_prepare(struct clk_hw *hw)
+{
+       struct sam9x60_pll_core *core = to_sam9x60_pll_core(hw);
+       struct sam9x60_frac *frac = to_sam9x60_frac(core);
+       struct regmap *regmap = core->regmap;
+       unsigned int val, cfrac, cmul;
+       unsigned long flags;
+
+       spin_lock_irqsave(core->lock, flags);
+
+       regmap_update_bits(regmap, AT91_PMC_PLL_UPDT,
+                          AT91_PMC_PLL_UPDT_ID_MSK, core->id);
        regmap_read(regmap, AT91_PMC_PLL_CTRL1, &val);
-       mul = FIELD_GET(PMC_PLL_CTRL1_MUL_MSK, val);
+       cmul = (val & core->layout->mul_mask) >> core->layout->mul_shift;
+       cfrac = (val & core->layout->frac_mask) >> core->layout->frac_shift;
 
-       if (sam9x60_pll_ready(regmap, pll->id) &&
-           (div == pll->div && mul == pll->mul)) {
-               spin_unlock_irqrestore(pll->lock, flags);
-               return 0;
-       }
+       if (sam9x60_frac_pll_ready(regmap, core->id) &&
+           (cmul == frac->mul && cfrac == frac->frac))
+               goto unlock;
 
-       /* Recommended value for AT91_PMC_PLL_ACR */
-       if (pll->characteristics->upll)
+       /* Recommended value for PMC_PLL_ACR */
+       if (core->characteristics->upll)
                val = AT91_PMC_PLL_ACR_DEFAULT_UPLL;
        else
                val = AT91_PMC_PLL_ACR_DEFAULT_PLLA;
        regmap_write(regmap, AT91_PMC_PLL_ACR, val);
 
        regmap_write(regmap, AT91_PMC_PLL_CTRL1,
-                    FIELD_PREP(PMC_PLL_CTRL1_MUL_MSK, pll->mul));
+                    (frac->mul << core->layout->mul_shift) |
+                    (frac->frac << core->layout->frac_shift));
 
-       if (pll->characteristics->upll) {
+       if (core->characteristics->upll) {
                /* Enable the UTMI internal bandgap */
                val |= AT91_PMC_PLL_ACR_UTMIBG;
                regmap_write(regmap, AT91_PMC_PLL_ACR, val);
@@ -94,221 +121,409 @@ static int sam9x60_pll_prepare(struct clk_hw *hw)
        }
 
        regmap_update_bits(regmap, AT91_PMC_PLL_UPDT,
-                          AT91_PMC_PLL_UPDT_UPDATE, AT91_PMC_PLL_UPDT_UPDATE);
+                          AT91_PMC_PLL_UPDT_UPDATE | AT91_PMC_PLL_UPDT_ID_MSK,
+                          AT91_PMC_PLL_UPDT_UPDATE | core->id);
 
-       regmap_write(regmap, AT91_PMC_PLL_CTRL0,
-                    AT91_PMC_PLL_CTRL0_ENLOCK | AT91_PMC_PLL_CTRL0_ENPLL |
-                    AT91_PMC_PLL_CTRL0_ENPLLCK | pll->div);
+       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_UPDATE);
+                          AT91_PMC_PLL_UPDT_UPDATE | AT91_PMC_PLL_UPDT_ID_MSK,
+                          AT91_PMC_PLL_UPDT_UPDATE | core->id);
 
-       while (!sam9x60_pll_ready(regmap, pll->id))
+       while (!sam9x60_pll_ready(regmap, core->id))
                cpu_relax();
 
-       spin_unlock_irqrestore(pll->lock, flags);
+unlock:
+       spin_unlock_irqrestore(core->lock, flags);
 
        return 0;
 }
 
-static int sam9x60_pll_is_prepared(struct clk_hw *hw)
+static void sam9x60_frac_pll_unprepare(struct clk_hw *hw)
 {
-       struct sam9x60_pll *pll = to_sam9x60_pll(hw);
+       struct sam9x60_pll_core *core = to_sam9x60_pll_core(hw);
+       struct regmap *regmap = core->regmap;
+       unsigned long flags;
+
+       spin_lock_irqsave(core->lock, flags);
 
-       return sam9x60_pll_ready(pll->regmap, pll->id);
+       regmap_update_bits(regmap, AT91_PMC_PLL_UPDT,
+                          AT91_PMC_PLL_UPDT_ID_MSK, core->id);
+
+       regmap_update_bits(regmap, AT91_PMC_PLL_CTRL0, AT91_PMC_PLL_CTRL0_ENPLL, 0);
+
+       if (core->characteristics->upll)
+               regmap_update_bits(regmap, AT91_PMC_PLL_ACR,
+                                  AT91_PMC_PLL_ACR_UTMIBG | AT91_PMC_PLL_ACR_UTMIVR, 0);
+
+       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);
+
+       spin_unlock_irqrestore(core->lock, flags);
 }
 
-static void sam9x60_pll_unprepare(struct clk_hw *hw)
+static int sam9x60_frac_pll_is_prepared(struct clk_hw *hw)
 {
-       struct sam9x60_pll *pll = to_sam9x60_pll(hw);
-       unsigned long flags;
+       struct sam9x60_pll_core *core = to_sam9x60_pll_core(hw);
 
-       spin_lock_irqsave(pll->lock, flags);
+       return sam9x60_pll_ready(core->regmap, core->id);
+}
 
-       regmap_write(pll->regmap, AT91_PMC_PLL_UPDT, pll->id);
+static long sam9x60_frac_pll_compute_mul_frac(struct sam9x60_pll_core *core,
+                                             unsigned long rate,
+                                             unsigned long parent_rate,
+                                             bool update)
+{
+       struct sam9x60_frac *frac = to_sam9x60_frac(core);
+       unsigned long tmprate, remainder;
+       unsigned long nmul = 0;
+       unsigned long nfrac = 0;
 
-       regmap_update_bits(pll->regmap, AT91_PMC_PLL_CTRL0,
-                          AT91_PMC_PLL_CTRL0_ENPLLCK, 0);
+       if (rate < FCORE_MIN || rate > FCORE_MAX)
+               return -ERANGE;
 
-       regmap_update_bits(pll->regmap, AT91_PMC_PLL_UPDT,
-                          AT91_PMC_PLL_UPDT_UPDATE, AT91_PMC_PLL_UPDT_UPDATE);
+       /*
+        * Calculate the multiplier associated with the current
+        * divider that provide the closest rate to the requested one.
+        */
+       nmul = mult_frac(rate, 1, parent_rate);
+       tmprate = mult_frac(parent_rate, nmul, 1);
+       remainder = rate - tmprate;
 
-       regmap_update_bits(pll->regmap, AT91_PMC_PLL_CTRL0,
-                          AT91_PMC_PLL_CTRL0_ENPLL, 0);
+       if (remainder) {
+               nfrac = DIV_ROUND_CLOSEST_ULL((u64)remainder * (1 << 22),
+                                             parent_rate);
 
-       if (pll->characteristics->upll)
-               regmap_update_bits(pll->regmap, AT91_PMC_PLL_ACR,
-                                  AT91_PMC_PLL_ACR_UTMIBG |
-                                  AT91_PMC_PLL_ACR_UTMIVR, 0);
+               tmprate += DIV_ROUND_CLOSEST_ULL((u64)nfrac * parent_rate,
+                                                (1 << 22));
+       }
 
-       regmap_update_bits(pll->regmap, AT91_PMC_PLL_UPDT,
-                          AT91_PMC_PLL_UPDT_UPDATE, AT91_PMC_PLL_UPDT_UPDATE);
+       /* Check if resulted rate is a valid.  */
+       if (tmprate < FCORE_MIN || tmprate > FCORE_MAX)
+               return -ERANGE;
 
-       spin_unlock_irqrestore(pll->lock, flags);
+       if (update) {
+               frac->mul = nmul - 1;
+               frac->frac = nfrac;
+       }
+
+       return tmprate;
 }
 
-static unsigned long sam9x60_pll_recalc_rate(struct clk_hw *hw,
-                                            unsigned long parent_rate)
+static long sam9x60_frac_pll_round_rate(struct clk_hw *hw, unsigned long rate,
+                                       unsigned long *parent_rate)
 {
-       struct sam9x60_pll *pll = to_sam9x60_pll(hw);
+       struct sam9x60_pll_core *core = to_sam9x60_pll_core(hw);
 
-       return (parent_rate * (pll->mul + 1)) / (pll->div + 1);
+       return sam9x60_frac_pll_compute_mul_frac(core, rate, *parent_rate, false);
 }
 
-static long sam9x60_pll_get_best_div_mul(struct sam9x60_pll *pll,
-                                        unsigned long rate,
-                                        unsigned long parent_rate,
-                                        bool update)
+static int sam9x60_frac_pll_set_rate(struct clk_hw *hw, unsigned long rate,
+                                    unsigned long parent_rate)
 {
-       const struct clk_pll_characteristics *characteristics =
-                                                       pll->characteristics;
-       unsigned long bestremainder = ULONG_MAX;
-       unsigned long maxdiv, mindiv, tmpdiv;
-       long bestrate = -ERANGE;
-       unsigned long bestdiv = 0;
-       unsigned long bestmul = 0;
-       unsigned long bestfrac = 0;
+       struct sam9x60_pll_core *core = to_sam9x60_pll_core(hw);
 
-       if (rate < characteristics->output[0].min ||
-           rate > characteristics->output[0].max)
-               return -ERANGE;
+       return sam9x60_frac_pll_compute_mul_frac(core, rate, parent_rate, true);
+}
 
-       if (!pll->characteristics->upll) {
-               mindiv = parent_rate / rate;
-               if (mindiv < 2)
-                       mindiv = 2;
+static const struct clk_ops sam9x60_frac_pll_ops = {
+       .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,
+};
 
-               maxdiv = DIV_ROUND_UP(parent_rate * PLL_MUL_MAX, rate);
-               if (maxdiv > PLL_DIV_MAX)
-                       maxdiv = PLL_DIV_MAX;
-       } else {
-               mindiv = maxdiv = UPLL_DIV;
-       }
+static int sam9x60_div_pll_prepare(struct clk_hw *hw)
+{
+       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 flags;
+       unsigned int val, cdiv;
 
-       for (tmpdiv = mindiv; tmpdiv <= maxdiv; tmpdiv++) {
-               unsigned long remainder;
-               unsigned long tmprate;
-               unsigned long tmpmul;
-               unsigned long tmpfrac = 0;
+       spin_lock_irqsave(core->lock, flags);
+       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;
 
-               /*
-                * Calculate the multiplier associated with the current
-                * divider that provide the closest rate to the requested one.
-                */
-               tmpmul = mult_frac(rate, tmpdiv, parent_rate);
-               tmprate = mult_frac(parent_rate, tmpmul, tmpdiv);
-               remainder = rate - tmprate;
+       /* Stop if enabled an nothing changed. */
+       if (!!(val & core->layout->endiv_mask) && cdiv == div->div)
+               goto unlock;
 
-               if (remainder) {
-                       tmpfrac = DIV_ROUND_CLOSEST_ULL((u64)remainder * tmpdiv * (1 << 22),
-                                                       parent_rate);
+       regmap_update_bits(regmap, AT91_PMC_PLL_CTRL0,
+                          core->layout->div_mask | core->layout->endiv_mask,
+                          (div->div << core->layout->div_shift) |
+                          (1 << core->layout->endiv_shift));
 
-                       tmprate += DIV_ROUND_CLOSEST_ULL((u64)tmpfrac * parent_rate,
-                                                        tmpdiv * (1 << 22));
+       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);
 
-                       if (tmprate > rate)
-                               remainder = tmprate - rate;
-                       else
-                               remainder = rate - tmprate;
-               }
+       while (!sam9x60_pll_ready(regmap, core->id))
+               cpu_relax();
 
-               /*
-                * Compare the remainder with the best remainder found until
-                * now and elect a new best multiplier/divider pair if the
-                * current remainder is smaller than the best one.
-                */
-               if (remainder < bestremainder) {
-                       bestremainder = remainder;
-                       bestdiv = tmpdiv;
-                       bestmul = tmpmul;
-                       bestrate = tmprate;
-                       bestfrac = tmpfrac;
+unlock:
+       spin_unlock_irqrestore(core->lock, flags);
+
+       return 0;
+}
+
+static void sam9x60_div_pll_unprepare(struct clk_hw *hw)
+{
+       struct sam9x60_pll_core *core = to_sam9x60_pll_core(hw);
+       struct regmap *regmap = core->regmap;
+       unsigned long flags;
+
+       spin_lock_irqsave(core->lock, flags);
+
+       regmap_update_bits(regmap, AT91_PMC_PLL_UPDT,
+                          AT91_PMC_PLL_UPDT_ID_MSK, core->id);
+
+       regmap_update_bits(regmap, AT91_PMC_PLL_CTRL0,
+                          core->layout->endiv_mask, 0);
+
+       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);
+
+       spin_unlock_irqrestore(core->lock, flags);
+}
+
+static int sam9x60_div_pll_is_prepared(struct clk_hw *hw)
+{
+       struct sam9x60_pll_core *core = to_sam9x60_pll_core(hw);
+       struct regmap *regmap = core->regmap;
+       unsigned long flags;
+       unsigned int val;
+
+       spin_lock_irqsave(core->lock, flags);
+
+       regmap_update_bits(regmap, AT91_PMC_PLL_UPDT,
+                          AT91_PMC_PLL_UPDT_ID_MSK, core->id);
+       regmap_read(regmap, AT91_PMC_PLL_CTRL0, &val);
+
+       spin_unlock_irqrestore(core->lock, flags);
+
+       return !!(val & core->layout->endiv_mask);
+}
+
+static unsigned long sam9x60_div_pll_recalc_rate(struct clk_hw *hw,
+                                                unsigned long parent_rate)
+{
+       struct sam9x60_pll_core *core = to_sam9x60_pll_core(hw);
+       struct sam9x60_div *div = to_sam9x60_div(core);
+
+       return DIV_ROUND_CLOSEST_ULL(parent_rate, (div->div + 1));
+}
+
+static long sam9x60_div_pll_compute_div(struct sam9x60_pll_core *core,
+                                       unsigned long *parent_rate,
+                                       unsigned long rate)
+{
+       const struct clk_pll_characteristics *characteristics =
+                                                       core->characteristics;
+       struct clk_hw *parent = clk_hw_get_parent(&core->hw);
+       unsigned long tmp_rate, tmp_parent_rate, tmp_diff;
+       long best_diff = -1, best_rate = -EINVAL;
+       u32 divid, best_div;
+
+       if (!rate)
+               return 0;
+
+       if (rate < characteristics->output[0].min ||
+           rate > characteristics->output[0].max)
+               return -ERANGE;
+
+       for (divid = 1; divid < core->layout->div_mask; divid++) {
+               tmp_parent_rate = clk_hw_round_rate(parent, rate * divid);
+               if (!tmp_parent_rate)
+                       continue;
+
+               tmp_rate = DIV_ROUND_CLOSEST_ULL(tmp_parent_rate, divid);
+               tmp_diff = abs(rate - tmp_rate);
+
+               if (best_diff < 0 || best_diff > tmp_diff) {
+                       *parent_rate = tmp_parent_rate;
+                       best_rate = tmp_rate;
+                       best_diff = tmp_diff;
+                       best_div = divid;
                }
 
-               /* We've found a perfect match!  */
-               if (!remainder)
+               if (!best_diff)
                        break;
        }
 
-       /* Check if bestrate is a valid output rate  */
-       if (bestrate < characteristics->output[0].min &&
-           bestrate > characteristics->output[0].max)
+       if (best_rate < characteristics->output[0].min ||
+           best_rate > characteristics->output[0].max)
                return -ERANGE;
 
-       if (update) {
-               pll->div = bestdiv - 1;
-               pll->mul = bestmul - 1;
-               pll->frac = bestfrac;
-       }
-
-       return bestrate;
+       return best_rate;
 }
 
-static long sam9x60_pll_round_rate(struct clk_hw *hw, unsigned long rate,
-                                  unsigned long *parent_rate)
+static long sam9x60_div_pll_round_rate(struct clk_hw *hw, unsigned long rate,
+                                      unsigned long *parent_rate)
 {
-       struct sam9x60_pll *pll = to_sam9x60_pll(hw);
+       struct sam9x60_pll_core *core = to_sam9x60_pll_core(hw);
 
-       return sam9x60_pll_get_best_div_mul(pll, rate, *parent_rate, false);
+       return sam9x60_div_pll_compute_div(core, parent_rate, rate);
 }
 
-static int sam9x60_pll_set_rate(struct clk_hw *hw, unsigned long rate,
-                               unsigned long parent_rate)
+static int sam9x60_div_pll_set_rate(struct clk_hw *hw, unsigned long rate,
+                                   unsigned long parent_rate)
 {
-       struct sam9x60_pll *pll = to_sam9x60_pll(hw);
+       struct sam9x60_pll_core *core = to_sam9x60_pll_core(hw);
+       struct sam9x60_div *div = to_sam9x60_div(core);
+
+       div->div = DIV_ROUND_CLOSEST(parent_rate, rate) - 1;
 
-       return sam9x60_pll_get_best_div_mul(pll, rate, parent_rate, true);
+       return 0;
 }
 
-static const struct clk_ops pll_ops = {
-       .prepare = sam9x60_pll_prepare,
-       .unprepare = sam9x60_pll_unprepare,
-       .is_prepared = sam9x60_pll_is_prepared,
-       .recalc_rate = sam9x60_pll_recalc_rate,
-       .round_rate = sam9x60_pll_round_rate,
-       .set_rate = sam9x60_pll_set_rate,
+static const struct clk_ops sam9x60_div_pll_ops = {
+       .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,
 };
 
 struct clk_hw * __init
-sam9x60_clk_register_pll(struct regmap *regmap, spinlock_t *lock,
-                        const char *name, const char *parent_name, u8 id,
-                        const struct clk_pll_characteristics *characteristics)
+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)
 {
-       struct sam9x60_pll *pll;
+       struct sam9x60_frac *frac;
        struct clk_hw *hw;
        struct clk_init_data init;
-       unsigned int pllr;
+       unsigned long parent_rate, flags;
+       unsigned int val;
        int ret;
 
-       if (id > PLL_MAX_ID)
+       if (id > PLL_MAX_ID || !lock || !parent_hw)
                return ERR_PTR(-EINVAL);
 
-       pll = kzalloc(sizeof(*pll), GFP_KERNEL);
-       if (!pll)
+       frac = kzalloc(sizeof(*frac), GFP_KERNEL);
+       if (!frac)
                return ERR_PTR(-ENOMEM);
 
        init.name = name;
-       init.ops = &pll_ops;
        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;
+
+       frac->core.id = id;
+       frac->core.hw.init = &init;
+       frac->core.characteristics = characteristics;
+       frac->core.layout = layout;
+       frac->core.regmap = regmap;
+       frac->core.lock = lock;
+
+       spin_lock_irqsave(frac->core.lock, flags);
+       if (sam9x60_pll_ready(regmap, id)) {
+               regmap_update_bits(regmap, AT91_PMC_PLL_UPDT,
+                                  AT91_PMC_PLL_UPDT_ID_MSK, id);
+               regmap_read(regmap, AT91_PMC_PLL_CTRL1, &val);
+               frac->mul = FIELD_GET(PMC_PLL_CTRL1_MUL_MSK, val);
+               frac->frac = FIELD_GET(PMC_PLL_CTRL1_FRACR_MSK, val);
+       } else {
+               /*
+                * This means the PLL is not setup by bootloaders. In this
+                * case we need to set the minimum rate for it. Otherwise
+                * a clock child of this PLL may be enabled before setting
+                * its rate leading to enabling this PLL with unsupported
+                * rate. This will lead to PLL not being locked at all.
+                */
+               parent_rate = clk_hw_get_rate(parent_hw);
+               if (!parent_rate) {
+                       hw = ERR_PTR(-EINVAL);
+                       goto free;
+               }
+
+               ret = sam9x60_frac_pll_compute_mul_frac(&frac->core, FCORE_MIN,
+                                                       parent_rate, true);
+               if (ret <= 0) {
+                       hw = ERR_PTR(ret);
+                       goto free;
+               }
+       }
+       spin_unlock_irqrestore(frac->core.lock, flags);
+
+       hw = &frac->core.hw;
+       ret = clk_hw_register(NULL, hw);
+       if (ret) {
+               kfree(frac);
+               hw = ERR_PTR(ret);
+       }
 
-       pll->id = id;
-       pll->hw.init = &init;
-       pll->characteristics = characteristics;
-       pll->regmap = regmap;
-       pll->lock = lock;
+       return hw;
+
+free:
+       spin_unlock_irqrestore(frac->core.lock, flags);
+       kfree(frac);
+       return hw;
+}
+
+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)
+{
+       struct sam9x60_div *div;
+       struct clk_hw *hw;
+       struct clk_init_data init;
+       unsigned long flags;
+       unsigned int val;
+       int ret;
+
+       if (id > PLL_MAX_ID || !lock)
+               return ERR_PTR(-EINVAL);
+
+       div = kzalloc(sizeof(*div), GFP_KERNEL);
+       if (!div)
+               return ERR_PTR(-ENOMEM);
+
+       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;
+
+       div->core.id = id;
+       div->core.hw.init = &init;
+       div->core.characteristics = characteristics;
+       div->core.layout = layout;
+       div->core.regmap = regmap;
+       div->core.lock = lock;
+
+       spin_lock_irqsave(div->core.lock, flags);
+
+       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);
 
-       regmap_write(regmap, AT91_PMC_PLL_UPDT, id);
-       regmap_read(regmap, AT91_PMC_PLL_CTRL0, &pllr);
-       pll->div = FIELD_GET(PMC_PLL_CTRL0_DIV_MSK, pllr);
-       regmap_read(regmap, AT91_PMC_PLL_CTRL1, &pllr);
-       pll->mul = FIELD_GET(PMC_PLL_CTRL1_MUL_MSK, pllr);
+       spin_unlock_irqrestore(div->core.lock, flags);
 
-       hw = &pll->hw;
+       hw = &div->core.hw;
        ret = clk_hw_register(NULL, hw);
        if (ret) {
-               kfree(pll);
+               kfree(div);
                hw = ERR_PTR(ret);
        }
 
index c4b3877aa445fc8c9f9284065c2308ac337ea171..f83ec0de86c36cf4aa505dd9deb6e75a2af7e746 100644 (file)
@@ -34,7 +34,7 @@ static inline bool clk_system_ready(struct regmap *regmap, int id)
 
        regmap_read(regmap, AT91_PMC_SR, &status);
 
-       return status & (1 << id) ? 1 : 0;
+       return !!(status & (1 << id));
 }
 
 static int clk_system_prepare(struct clk_hw *hw)
@@ -74,7 +74,7 @@ static int clk_system_is_prepared(struct clk_hw *hw)
 
        regmap_read(sys->regmap, AT91_PMC_SR, &status);
 
-       return status & (1 << sys->id) ? 1 : 0;
+       return !!(status & (1 << sys->id));
 }
 
 static const struct clk_ops system_ops = {
index f1ef4e1f41a97309055cda268b25422d9c17ebee..df9f3fc3b6a6519e2cf0dc4206ca62afcfb7fbea 100644 (file)
@@ -120,9 +120,11 @@ static const struct clk_ops utmi_ops = {
        .recalc_rate = clk_utmi_recalc_rate,
 };
 
-struct clk_hw * __init
-at91_clk_register_utmi(struct regmap *regmap_pmc, struct regmap *regmap_sfr,
-                      const char *name, const char *parent_name)
+static struct clk_hw * __init
+at91_clk_register_utmi_internal(struct regmap *regmap_pmc,
+                               struct regmap *regmap_sfr,
+                               const char *name, const char *parent_name,
+                               const struct clk_ops *ops, unsigned long flags)
 {
        struct clk_utmi *utmi;
        struct clk_hw *hw;
@@ -134,10 +136,10 @@ at91_clk_register_utmi(struct regmap *regmap_pmc, struct regmap *regmap_sfr,
                return ERR_PTR(-ENOMEM);
 
        init.name = name;
-       init.ops = &utmi_ops;
+       init.ops = ops;
        init.parent_names = parent_name ? &parent_name : NULL;
        init.num_parents = parent_name ? 1 : 0;
-       init.flags = CLK_SET_RATE_GATE;
+       init.flags = flags;
 
        utmi->hw.init = &init;
        utmi->regmap_pmc = regmap_pmc;
@@ -152,3 +154,94 @@ at91_clk_register_utmi(struct regmap *regmap_pmc, struct regmap *regmap_sfr,
 
        return hw;
 }
+
+struct clk_hw * __init
+at91_clk_register_utmi(struct regmap *regmap_pmc, struct regmap *regmap_sfr,
+                      const char *name, const char *parent_name)
+{
+       return at91_clk_register_utmi_internal(regmap_pmc, regmap_sfr, name,
+                       parent_name, &utmi_ops, CLK_SET_RATE_GATE);
+}
+
+static int clk_utmi_sama7g5_prepare(struct clk_hw *hw)
+{
+       struct clk_utmi *utmi = to_clk_utmi(hw);
+       struct clk_hw *hw_parent;
+       unsigned long parent_rate;
+       unsigned int val;
+
+       hw_parent = clk_hw_get_parent(hw);
+       parent_rate = clk_hw_get_rate(hw_parent);
+
+       switch (parent_rate) {
+       case 16000000:
+               val = 0;
+               break;
+       case 20000000:
+               val = 2;
+               break;
+       case 24000000:
+               val = 3;
+               break;
+       case 32000000:
+               val = 5;
+               break;
+       default:
+               pr_err("UTMICK: unsupported main_xtal rate\n");
+               return -EINVAL;
+       }
+
+       regmap_write(utmi->regmap_pmc, AT91_PMC_XTALF, val);
+
+       return 0;
+
+}
+
+static int clk_utmi_sama7g5_is_prepared(struct clk_hw *hw)
+{
+       struct clk_utmi *utmi = to_clk_utmi(hw);
+       struct clk_hw *hw_parent;
+       unsigned long parent_rate;
+       unsigned int val;
+
+       hw_parent = clk_hw_get_parent(hw);
+       parent_rate = clk_hw_get_rate(hw_parent);
+
+       regmap_read(utmi->regmap_pmc, AT91_PMC_XTALF, &val);
+       switch (val & 0x7) {
+       case 0:
+               if (parent_rate == 16000000)
+                       return 1;
+               break;
+       case 2:
+               if (parent_rate == 20000000)
+                       return 1;
+               break;
+       case 3:
+               if (parent_rate == 24000000)
+                       return 1;
+               break;
+       case 5:
+               if (parent_rate == 32000000)
+                       return 1;
+               break;
+       default:
+               break;
+       }
+
+       return 0;
+}
+
+static const struct clk_ops sama7g5_utmi_ops = {
+       .prepare = clk_utmi_sama7g5_prepare,
+       .is_prepared = clk_utmi_sama7g5_is_prepared,
+       .recalc_rate = clk_utmi_recalc_rate,
+};
+
+struct clk_hw * __init
+at91_clk_sama7g5_register_utmi(struct regmap *regmap_pmc, const char *name,
+                              const char *parent_name)
+{
+       return at91_clk_register_utmi_internal(regmap_pmc, NULL, name,
+                       parent_name, &sama7g5_utmi_ops, 0);
+}
index aa1754eac59fff6d3a09f7d4f03dbad4b77446cc..a50084de97d41b7919d0ad3f2af08a5c41d8cb57 100644 (file)
@@ -22,6 +22,8 @@
 
 #define SYSTEM_MAX_ID          31
 
+#define GCK_INDEX_DT_AUDIO_PLL 5
+
 #ifdef CONFIG_HAVE_AT91_AUDIO_PLL
 static void __init of_sama5d2_clk_audio_pll_frac_setup(struct device_node *np)
 {
@@ -135,7 +137,7 @@ static void __init of_sama5d2_clk_generated_setup(struct device_node *np)
                return;
 
        for_each_child_of_node(np, gcknp) {
-               bool pll_audio = false;
+               int chg_pid = INT_MIN;
 
                if (of_property_read_u32(gcknp, "reg", &id))
                        continue;
@@ -152,12 +154,13 @@ static void __init of_sama5d2_clk_generated_setup(struct device_node *np)
                if (of_device_is_compatible(np, "atmel,sama5d2-clk-generated") &&
                    (id == GCK_ID_I2S0 || id == GCK_ID_I2S1 ||
                     id == GCK_ID_CLASSD))
-                       pll_audio = true;
+                       chg_pid = GCK_INDEX_DT_AUDIO_PLL;
 
                hw = at91_clk_register_generated(regmap, &pmc_pcr_lock,
                                                 &dt_pcr_layout, name,
-                                                parent_names, num_parents,
-                                                id, pll_audio, &range);
+                                                parent_names, NULL,
+                                                num_parents, id, &range,
+                                                chg_pid);
                if (IS_ERR(hw))
                        continue;
 
@@ -460,7 +463,8 @@ of_at91_clk_periph_setup(struct device_node *np, u8 type)
                                                                 &dt_pcr_layout,
                                                                 name,
                                                                 parent_name,
-                                                                id, &range);
+                                                                id, &range,
+                                                                INT_MIN);
                }
 
                if (IS_ERR(hw))
@@ -673,7 +677,8 @@ CLK_OF_DECLARE(at91sam9x5_clk_plldiv, "atmel,at91sam9x5-clk-plldiv",
 
 static void __init
 of_at91_clk_prog_setup(struct device_node *np,
-                      const struct clk_programmable_layout *layout)
+                      const struct clk_programmable_layout *layout,
+                      u32 *mux_table)
 {
        int num;
        u32 id;
@@ -707,7 +712,7 @@ of_at91_clk_prog_setup(struct device_node *np,
 
                hw = at91_clk_register_programmable(regmap, name,
                                                    parent_names, num_parents,
-                                                   id, layout);
+                                                   id, layout, mux_table);
                if (IS_ERR(hw))
                        continue;
 
@@ -717,21 +722,21 @@ of_at91_clk_prog_setup(struct device_node *np,
 
 static void __init of_at91rm9200_clk_prog_setup(struct device_node *np)
 {
-       of_at91_clk_prog_setup(np, &at91rm9200_programmable_layout);
+       of_at91_clk_prog_setup(np, &at91rm9200_programmable_layout, NULL);
 }
 CLK_OF_DECLARE(at91rm9200_clk_prog, "atmel,at91rm9200-clk-programmable",
               of_at91rm9200_clk_prog_setup);
 
 static void __init of_at91sam9g45_clk_prog_setup(struct device_node *np)
 {
-       of_at91_clk_prog_setup(np, &at91sam9g45_programmable_layout);
+       of_at91_clk_prog_setup(np, &at91sam9g45_programmable_layout, NULL);
 }
 CLK_OF_DECLARE(at91sam9g45_clk_prog, "atmel,at91sam9g45-clk-programmable",
               of_at91sam9g45_clk_prog_setup);
 
 static void __init of_at91sam9x5_clk_prog_setup(struct device_node *np)
 {
-       of_at91_clk_prog_setup(np, &at91sam9x5_programmable_layout);
+       of_at91_clk_prog_setup(np, &at91sam9x5_programmable_layout, NULL);
 }
 CLK_OF_DECLARE(at91sam9x5_clk_prog, "atmel,at91sam9x5-clk-programmable",
               of_at91sam9x5_clk_prog_setup);
index df616f2937e70586ab5cc3ee28fe86566ebe07a9..7b86affc6d7c9fc615b8d7fcc65e28aa3942d2a6 100644 (file)
@@ -54,8 +54,14 @@ struct clk_master_characteristics {
 
 struct clk_pll_layout {
        u32 pllr_mask;
-       u16 mul_mask;
+       u32 mul_mask;
+       u32 frac_mask;
+       u32 div_mask;
+       u32 endiv_mask;
        u8 mul_shift;
+       u8 frac_shift;
+       u8 div_shift;
+       u8 endiv_shift;
 };
 
 extern const struct clk_pll_layout at91rm9200_pll_layout;
@@ -122,8 +128,8 @@ struct clk_hw * __init
 at91_clk_register_generated(struct regmap *regmap, spinlock_t *lock,
                            const struct clk_pcr_layout *layout,
                            const char *name, const char **parent_names,
-                           u8 num_parents, u8 id, bool pll_audio,
-                           const struct clk_range *range);
+                           u32 *mux_table, u8 num_parents, u8 id,
+                           const struct clk_range *range, int chg_pid);
 
 struct clk_hw * __init
 at91_clk_register_h32mx(struct regmap *regmap, const char *name,
@@ -154,6 +160,13 @@ at91_clk_register_master(struct regmap *regmap, const char *name,
                         const struct clk_master_layout *layout,
                         const struct clk_master_characteristics *characteristics);
 
+struct clk_hw * __init
+at91_clk_sama7g5_register_master(struct regmap *regmap,
+                                const char *name, int num_parents,
+                                const char **parent_names, u32 *mux_table,
+                                spinlock_t *lock, u8 id, bool critical,
+                                int chg_pid);
+
 struct clk_hw * __init
 at91_clk_register_peripheral(struct regmap *regmap, const char *name,
                             const char *parent_name, u32 id);
@@ -161,7 +174,8 @@ struct clk_hw * __init
 at91_clk_register_sam9x5_peripheral(struct regmap *regmap, spinlock_t *lock,
                                    const struct clk_pcr_layout *layout,
                                    const char *name, const char *parent_name,
-                                   u32 id, const struct clk_range *range);
+                                   u32 id, const struct clk_range *range,
+                                   int chg_pid);
 
 struct clk_hw * __init
 at91_clk_register_pll(struct regmap *regmap, const char *name,
@@ -173,14 +187,23 @@ at91_clk_register_plldiv(struct regmap *regmap, const char *name,
                         const char *parent_name);
 
 struct clk_hw * __init
-sam9x60_clk_register_pll(struct regmap *regmap, spinlock_t *lock,
-                        const char *name, const char *parent_name, u8 id,
-                        const struct clk_pll_characteristics *characteristics);
+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);
+
+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);
 
 struct clk_hw * __init
 at91_clk_register_programmable(struct regmap *regmap, const char *name,
                               const char **parent_names, u8 num_parents, u8 id,
-                              const struct clk_programmable_layout *layout);
+                              const struct clk_programmable_layout *layout,
+                              u32 *mux_table);
 
 struct clk_hw * __init
 at91_clk_register_sam9260_slow(struct regmap *regmap,
@@ -213,6 +236,10 @@ struct clk_hw * __init
 at91_clk_register_utmi(struct regmap *regmap_pmc, struct regmap *regmap_sfr,
                       const char *name, const char *parent_name);
 
+struct clk_hw * __init
+at91_clk_sama7g5_register_utmi(struct regmap *regmap, const char *name,
+                              const char *parent_name);
+
 #ifdef CONFIG_PM
 void pmc_register_id(u8 id);
 void pmc_register_pck(u8 pck);
index 3e20aa68259fd2aa9a7fb958baadf6b11b101c03..ab6318c0589e9e6aec9dae2e393696d7798cd533 100644 (file)
@@ -22,7 +22,7 @@ static const struct clk_master_layout sam9x60_master_layout = {
 };
 
 static const struct clk_range plla_outputs[] = {
-       { .min = 300000000, .max = 600000000 },
+       { .min = 2343750, .max = 1200000000 },
 };
 
 static const struct clk_pll_characteristics plla_characteristics = {
@@ -42,6 +42,20 @@ static const struct clk_pll_characteristics upll_characteristics = {
        .upll = true,
 };
 
+static const struct clk_pll_layout pll_frac_layout = {
+       .mul_mask = GENMASK(31, 24),
+       .frac_mask = GENMASK(21, 0),
+       .mul_shift = 24,
+       .frac_shift = 0,
+};
+
+static const struct clk_pll_layout pll_div_layout = {
+       .div_mask = GENMASK(7, 0),
+       .endiv_mask = BIT(29),
+       .div_shift = 0,
+       .endiv_shift = 29,
+};
+
 static const struct clk_programmable_layout sam9x60_programmable_layout = {
        .pres_mask = 0xff,
        .pres_shift = 8,
@@ -156,6 +170,7 @@ static void __init sam9x60_pmc_setup(struct device_node *np)
        const char *td_slck_name, *md_slck_name, *mainxtal_name;
        struct pmc_data *sam9x60_pmc;
        const char *parent_names[6];
+       struct clk_hw *main_osc_hw;
        struct regmap *regmap;
        struct clk_hw *hw;
        int i;
@@ -178,7 +193,7 @@ static void __init sam9x60_pmc_setup(struct device_node *np)
                return;
        mainxtal_name = of_clk_get_parent_name(np, i);
 
-       regmap = syscon_node_to_regmap(np);
+       regmap = device_node_to_regmap(np);
        if (IS_ERR(regmap))
                return;
 
@@ -189,7 +204,7 @@ static void __init sam9x60_pmc_setup(struct device_node *np)
        if (!sam9x60_pmc)
                return;
 
-       hw = at91_clk_register_main_rc_osc(regmap, "main_rc_osc", 24000000,
+       hw = at91_clk_register_main_rc_osc(regmap, "main_rc_osc", 12000000,
                                           50000000);
        if (IS_ERR(hw))
                goto err_free;
@@ -200,6 +215,7 @@ static void __init sam9x60_pmc_setup(struct device_node *np)
                                        bypass);
        if (IS_ERR(hw))
                goto err_free;
+       main_osc_hw = hw;
 
        parent_names[0] = "main_rc_osc";
        parent_names[1] = "main_osc";
@@ -209,15 +225,31 @@ static void __init sam9x60_pmc_setup(struct device_node *np)
 
        sam9x60_pmc->chws[PMC_MAIN] = hw;
 
-       hw = sam9x60_clk_register_pll(regmap, &pmc_pll_lock, "pllack",
-                                     "mainck", 0, &plla_characteristics);
+       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);
+       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);
        if (IS_ERR(hw))
                goto err_free;
 
        sam9x60_pmc->chws[PMC_PLLACK] = hw;
 
-       hw = sam9x60_clk_register_pll(regmap, &pmc_pll_lock, "upllck",
-                                     "main_osc", 1, &upll_characteristics);
+       hw = sam9x60_clk_register_frac_pll(regmap, &pmc_pll_lock, "upllck_fracck",
+                                          "main_osc", main_osc_hw, 1,
+                                          &upll_characteristics,
+                                          &pll_frac_layout, false);
+       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);
        if (IS_ERR(hw))
                goto err_free;
 
@@ -225,7 +257,7 @@ static void __init sam9x60_pmc_setup(struct device_node *np)
 
        parent_names[0] = md_slck_name;
        parent_names[1] = "mainck";
-       parent_names[2] = "pllack";
+       parent_names[2] = "pllack_divck";
        hw = at91_clk_register_master(regmap, "masterck", 3, parent_names,
                                      &sam9x60_master_layout,
                                      &mck_characteristics);
@@ -234,8 +266,8 @@ static void __init sam9x60_pmc_setup(struct device_node *np)
 
        sam9x60_pmc->chws[PMC_MCK] = hw;
 
-       parent_names[0] = "pllack";
-       parent_names[1] = "upllck";
+       parent_names[0] = "pllack_divck";
+       parent_names[1] = "upllck_divck";
        parent_names[2] = "main_osc";
        hw = sam9x60_clk_register_usb(regmap, "usbck", parent_names, 3);
        if (IS_ERR(hw))
@@ -245,8 +277,8 @@ static void __init sam9x60_pmc_setup(struct device_node *np)
        parent_names[1] = td_slck_name;
        parent_names[2] = "mainck";
        parent_names[3] = "masterck";
-       parent_names[4] = "pllack";
-       parent_names[5] = "upllck";
+       parent_names[4] = "pllack_divck";
+       parent_names[5] = "upllck_divck";
        for (i = 0; i < 8; i++) {
                char name[6];
 
@@ -254,7 +286,8 @@ static void __init sam9x60_pmc_setup(struct device_node *np)
 
                hw = at91_clk_register_programmable(regmap, name,
                                                    parent_names, 6, i,
-                                                   &sam9x60_programmable_layout);
+                                                   &sam9x60_programmable_layout,
+                                                   NULL);
                if (IS_ERR(hw))
                        goto err_free;
 
@@ -277,7 +310,7 @@ static void __init sam9x60_pmc_setup(struct device_node *np)
                                                         sam9x60_periphck[i].n,
                                                         "masterck",
                                                         sam9x60_periphck[i].id,
-                                                        &range);
+                                                        &range, INT_MIN);
                if (IS_ERR(hw))
                        goto err_free;
 
@@ -288,10 +321,9 @@ static void __init sam9x60_pmc_setup(struct device_node *np)
                hw = at91_clk_register_generated(regmap, &pmc_pcr_lock,
                                                 &sam9x60_pcr_layout,
                                                 sam9x60_gck[i].n,
-                                                parent_names, 6,
+                                                parent_names, NULL, 6,
                                                 sam9x60_gck[i].id,
-                                                false,
-                                                &sam9x60_gck[i].r);
+                                                &sam9x60_gck[i].r, INT_MIN);
                if (IS_ERR(hw))
                        goto err_free;
 
index d69421d71daf03948eafc383d7e89d1c6318afdd..8b220762941aba7d125fa23afdeb16435ea1f1d2 100644 (file)
@@ -116,21 +116,20 @@ static const struct {
        char *n;
        u8 id;
        struct clk_range r;
-       bool pll;
+       int chg_pid;
 } sama5d2_gck[] = {
-       { .n = "sdmmc0_gclk", .id = 31, },
-       { .n = "sdmmc1_gclk", .id = 32, },
-       { .n = "tcb0_gclk",   .id = 35, .r = { .min = 0, .max = 83000000 }, },
-       { .n = "tcb1_gclk",   .id = 36, .r = { .min = 0, .max = 83000000 }, },
-       { .n = "pwm_gclk",    .id = 38, .r = { .min = 0, .max = 83000000 }, },
-       { .n = "isc_gclk",    .id = 46, },
-       { .n = "pdmic_gclk",  .id = 48, },
-       { .n = "i2s0_gclk",   .id = 54, .pll = true },
-       { .n = "i2s1_gclk",   .id = 55, .pll = true },
-       { .n = "can0_gclk",   .id = 56, .r = { .min = 0, .max = 80000000 }, },
-       { .n = "can1_gclk",   .id = 57, .r = { .min = 0, .max = 80000000 }, },
-       { .n = "classd_gclk", .id = 59, .r = { .min = 0, .max = 100000000 },
-         .pll = true },
+       { .n = "sdmmc0_gclk", .id = 31, .chg_pid = INT_MIN, },
+       { .n = "sdmmc1_gclk", .id = 32, .chg_pid = INT_MIN, },
+       { .n = "tcb0_gclk",   .id = 35, .chg_pid = INT_MIN, .r = { .min = 0, .max = 83000000 }, },
+       { .n = "tcb1_gclk",   .id = 36, .chg_pid = INT_MIN, .r = { .min = 0, .max = 83000000 }, },
+       { .n = "pwm_gclk",    .id = 38, .chg_pid = INT_MIN, .r = { .min = 0, .max = 83000000 }, },
+       { .n = "isc_gclk",    .id = 46, .chg_pid = INT_MIN, },
+       { .n = "pdmic_gclk",  .id = 48, .chg_pid = INT_MIN, },
+       { .n = "i2s0_gclk",   .id = 54, .chg_pid = 5, },
+       { .n = "i2s1_gclk",   .id = 55, .chg_pid = 5, },
+       { .n = "can0_gclk",   .id = 56, .chg_pid = INT_MIN, .r = { .min = 0, .max = 80000000 }, },
+       { .n = "can1_gclk",   .id = 57, .chg_pid = INT_MIN, .r = { .min = 0, .max = 80000000 }, },
+       { .n = "classd_gclk", .id = 59, .chg_pid = 5, .r = { .min = 0, .max = 100000000 }, },
 };
 
 static const struct clk_programmable_layout sama5d2_programmable_layout = {
@@ -269,7 +268,8 @@ static void __init sama5d2_pmc_setup(struct device_node *np)
 
                hw = at91_clk_register_programmable(regmap, name,
                                                    parent_names, 6, i,
-                                                   &sama5d2_programmable_layout);
+                                                   &sama5d2_programmable_layout,
+                                                   NULL);
                if (IS_ERR(hw))
                        goto err_free;
 
@@ -292,7 +292,7 @@ static void __init sama5d2_pmc_setup(struct device_node *np)
                                                         sama5d2_periphck[i].n,
                                                         "masterck",
                                                         sama5d2_periphck[i].id,
-                                                        &range);
+                                                        &range, INT_MIN);
                if (IS_ERR(hw))
                        goto err_free;
 
@@ -305,7 +305,8 @@ static void __init sama5d2_pmc_setup(struct device_node *np)
                                                         sama5d2_periph32ck[i].n,
                                                         "h32mxck",
                                                         sama5d2_periph32ck[i].id,
-                                                        &sama5d2_periph32ck[i].r);
+                                                        &sama5d2_periph32ck[i].r,
+                                                        INT_MIN);
                if (IS_ERR(hw))
                        goto err_free;
 
@@ -322,10 +323,10 @@ static void __init sama5d2_pmc_setup(struct device_node *np)
                hw = at91_clk_register_generated(regmap, &pmc_pcr_lock,
                                                 &sama5d2_pcr_layout,
                                                 sama5d2_gck[i].n,
-                                                parent_names, 6,
+                                                parent_names, NULL, 6,
                                                 sama5d2_gck[i].id,
-                                                sama5d2_gck[i].pll,
-                                                &sama5d2_gck[i].r);
+                                                &sama5d2_gck[i].r,
+                                                sama5d2_gck[i].chg_pid);
                if (IS_ERR(hw))
                        goto err_free;
 
index 5e4e44dd4c37c39b22f5aeb28882e405563055f0..7c6e0a5b9dc87088caa2427a4b9197b87dc50a69 100644 (file)
@@ -121,7 +121,7 @@ static void __init sama5d3_pmc_setup(struct device_node *np)
                return;
        mainxtal_name = of_clk_get_parent_name(np, i);
 
-       regmap = syscon_node_to_regmap(np);
+       regmap = device_node_to_regmap(np);
        if (IS_ERR(regmap))
                return;
 
@@ -200,7 +200,8 @@ static void __init sama5d3_pmc_setup(struct device_node *np)
 
                hw = at91_clk_register_programmable(regmap, name,
                                                    parent_names, 5, i,
-                                                   &at91sam9x5_programmable_layout);
+                                                   &at91sam9x5_programmable_layout,
+                                                   NULL);
                if (IS_ERR(hw))
                        goto err_free;
 
@@ -223,7 +224,8 @@ static void __init sama5d3_pmc_setup(struct device_node *np)
                                                         sama5d3_periphck[i].n,
                                                         "masterck",
                                                         sama5d3_periphck[i].id,
-                                                        &sama5d3_periphck[i].r);
+                                                        &sama5d3_periphck[i].r,
+                                                        INT_MIN);
                if (IS_ERR(hw))
                        goto err_free;
 
index 662ff5fa6e9868f6a1a870ee915012ad08d8c938..92d8d4141b4335b1aa39dba170cc8f3f8ff47d48 100644 (file)
@@ -223,7 +223,8 @@ static void __init sama5d4_pmc_setup(struct device_node *np)
 
                hw = at91_clk_register_programmable(regmap, name,
                                                    parent_names, 5, i,
-                                                   &at91sam9x5_programmable_layout);
+                                                   &at91sam9x5_programmable_layout,
+                                                   NULL);
                if (IS_ERR(hw))
                        goto err_free;
 
@@ -246,7 +247,7 @@ static void __init sama5d4_pmc_setup(struct device_node *np)
                                                         sama5d4_periphck[i].n,
                                                         "masterck",
                                                         sama5d4_periphck[i].id,
-                                                        &range);
+                                                        &range, INT_MIN);
                if (IS_ERR(hw))
                        goto err_free;
 
@@ -259,7 +260,7 @@ static void __init sama5d4_pmc_setup(struct device_node *np)
                                                         sama5d4_periph32ck[i].n,
                                                         "h32mxck",
                                                         sama5d4_periph32ck[i].id,
-                                                        &range);
+                                                        &range, INT_MIN);
                if (IS_ERR(hw))
                        goto err_free;
 
diff --git a/drivers/clk/at91/sama7g5.c b/drivers/clk/at91/sama7g5.c
new file mode 100644 (file)
index 0000000..0db2ab3
--- /dev/null
@@ -0,0 +1,1059 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * SAMA7G5 PMC code.
+ *
+ * Copyright (C) 2020 Microchip Technology Inc. and its subsidiaries
+ *
+ * Author: Claudiu Beznea <claudiu.beznea@microchip.com>
+ *
+ */
+#include <linux/clk.h>
+#include <linux/clk-provider.h>
+#include <linux/mfd/syscon.h>
+#include <linux/slab.h>
+
+#include <dt-bindings/clock/at91.h>
+
+#include "pmc.h"
+
+#define SAMA7G5_INIT_TABLE(_table, _count)             \
+       do {                                            \
+               u8 _i;                                  \
+               for (_i = 0; _i < (_count); _i++)       \
+                       (_table)[_i] = _i;              \
+       } while (0)
+
+#define SAMA7G5_FILL_TABLE(_to, _from, _count)         \
+       do {                                            \
+               u8 _i;                                  \
+               for (_i = 0; _i < (_count); _i++) {     \
+                       (_to)[_i] = (_from)[_i];        \
+               }                                       \
+       } while (0)
+
+static DEFINE_SPINLOCK(pmc_pll_lock);
+static DEFINE_SPINLOCK(pmc_mckX_lock);
+
+/**
+ * PLL clocks identifiers
+ * @PLL_ID_CPU:                CPU PLL identifier
+ * @PLL_ID_SYS:                System PLL identifier
+ * @PLL_ID_DDR:                DDR PLL identifier
+ * @PLL_ID_IMG:                Image subsystem PLL identifier
+ * @PLL_ID_BAUD:       Baud PLL identifier
+ * @PLL_ID_AUDIO:      Audio PLL identifier
+ * @PLL_ID_ETH:                Ethernet PLL identifier
+ */
+enum pll_ids {
+       PLL_ID_CPU,
+       PLL_ID_SYS,
+       PLL_ID_DDR,
+       PLL_ID_IMG,
+       PLL_ID_BAUD,
+       PLL_ID_AUDIO,
+       PLL_ID_ETH,
+       PLL_ID_MAX,
+};
+
+/**
+ * PLL type identifiers
+ * @PLL_TYPE_FRAC:     fractional PLL identifier
+ * @PLL_TYPE_DIV:      divider PLL identifier
+ */
+enum pll_type {
+       PLL_TYPE_FRAC,
+       PLL_TYPE_DIV,
+};
+
+/* Layout for fractional PLLs. */
+static const struct clk_pll_layout pll_layout_frac = {
+       .mul_mask       = GENMASK(31, 24),
+       .frac_mask      = GENMASK(21, 0),
+       .mul_shift      = 24,
+       .frac_shift     = 0,
+};
+
+/* Layout for DIVPMC dividers. */
+static const struct clk_pll_layout pll_layout_divpmc = {
+       .div_mask       = GENMASK(7, 0),
+       .endiv_mask     = BIT(29),
+       .div_shift      = 0,
+       .endiv_shift    = 29,
+};
+
+/* Layout for DIVIO dividers. */
+static const struct clk_pll_layout pll_layout_divio = {
+       .div_mask       = GENMASK(19, 12),
+       .endiv_mask     = BIT(30),
+       .div_shift      = 12,
+       .endiv_shift    = 30,
+};
+
+/**
+ * PLL clocks description
+ * @n:         clock name
+ * @p:         clock parent
+ * @l:         clock layout
+ * @t:         clock type
+ * @f:         true if clock is critical and cannot be disabled
+ * @eid:       export index in sama7g5->chws[] array
+ */
+static const struct {
+       const char *n;
+       const char *p;
+       const struct clk_pll_layout *l;
+       u8 t;
+       u8 c;
+       u8 eid;
+} sama7g5_plls[][PLL_ID_MAX] = {
+       [PLL_ID_CPU] = {
+               { .n = "cpupll_fracck",
+                 .p = "mainck",
+                 .l = &pll_layout_frac,
+                 .t = PLL_TYPE_FRAC,
+                 .c = 1, },
+
+               { .n = "cpupll_divpmcck",
+                 .p = "cpupll_fracck",
+                 .l = &pll_layout_divpmc,
+                 .t = PLL_TYPE_DIV,
+                 .c = 1, },
+       },
+
+       [PLL_ID_SYS] = {
+               { .n = "syspll_fracck",
+                 .p = "mainck",
+                 .l = &pll_layout_frac,
+                 .t = PLL_TYPE_FRAC,
+                 .c = 1, },
+
+               { .n = "syspll_divpmcck",
+                 .p = "syspll_fracck",
+                 .l = &pll_layout_divpmc,
+                 .t = PLL_TYPE_DIV,
+                 .c = 1, },
+       },
+
+       [PLL_ID_DDR] = {
+               { .n = "ddrpll_fracck",
+                 .p = "mainck",
+                 .l = &pll_layout_frac,
+                 .t = PLL_TYPE_FRAC,
+                 .c = 1, },
+
+               { .n = "ddrpll_divpmcck",
+                 .p = "ddrpll_fracck",
+                 .l = &pll_layout_divpmc,
+                 .t = PLL_TYPE_DIV,
+                 .c = 1, },
+       },
+
+       [PLL_ID_IMG] = {
+               { .n = "imgpll_fracck",
+                 .p = "mainck",
+                 .l = &pll_layout_frac,
+                 .t = PLL_TYPE_FRAC, },
+
+               { .n = "imgpll_divpmcck",
+                 .p = "imgpll_fracck",
+                 .l = &pll_layout_divpmc,
+                 .t = PLL_TYPE_DIV, },
+       },
+
+       [PLL_ID_BAUD] = {
+               { .n = "baudpll_fracck",
+                 .p = "mainck",
+                 .l = &pll_layout_frac,
+                 .t = PLL_TYPE_FRAC, },
+
+               { .n = "baudpll_divpmcck",
+                 .p = "baudpll_fracck",
+                 .l = &pll_layout_divpmc,
+                 .t = PLL_TYPE_DIV, },
+       },
+
+       [PLL_ID_AUDIO] = {
+               { .n = "audiopll_fracck",
+                 .p = "main_xtal",
+                 .l = &pll_layout_frac,
+                 .t = PLL_TYPE_FRAC, },
+
+               { .n = "audiopll_divpmcck",
+                 .p = "audiopll_fracck",
+                 .l = &pll_layout_divpmc,
+                 .t = PLL_TYPE_DIV,
+                 .eid = PMC_I2S0_MUX, },
+
+               { .n = "audiopll_diviock",
+                 .p = "audiopll_fracck",
+                 .l = &pll_layout_divio,
+                 .t = PLL_TYPE_DIV,
+                 .eid = PMC_I2S1_MUX, },
+       },
+
+       [PLL_ID_ETH] = {
+               { .n = "ethpll_fracck",
+                 .p = "main_xtal",
+                 .l = &pll_layout_frac,
+                 .t = PLL_TYPE_FRAC, },
+
+               { .n = "ethpll_divpmcck",
+                 .p = "ethpll_fracck",
+                 .l = &pll_layout_divpmc,
+                 .t = PLL_TYPE_DIV, },
+       },
+};
+
+/**
+ * Master clock (MCK[1..4]) description
+ * @n:                 clock name
+ * @ep:                        extra parents names array
+ * @ep_chg_chg_id:     index in parents array that specifies the changeable
+ *                     parent
+ * @ep_count:          extra parents count
+ * @ep_mux_table:      mux table for extra parents
+ * @id:                        clock id
+ * @c:                 true if clock is critical and cannot be disabled
+ */
+static const struct {
+       const char *n;
+       const char *ep[4];
+       int ep_chg_id;
+       u8 ep_count;
+       u8 ep_mux_table[4];
+       u8 id;
+       u8 c;
+} sama7g5_mckx[] = {
+       { .n = "mck1",
+         .id = 1,
+         .ep = { "syspll_divpmcck", },
+         .ep_mux_table = { 5, },
+         .ep_count = 1,
+         .ep_chg_id = INT_MIN,
+         .c = 1, },
+
+       { .n = "mck2",
+         .id = 2,
+         .ep = { "ddrpll_divpmcck", },
+         .ep_mux_table = { 6, },
+         .ep_count = 1,
+         .ep_chg_id = INT_MIN,
+         .c = 1, },
+
+       { .n = "mck3",
+         .id = 3,
+         .ep = { "syspll_divpmcck", "ddrpll_divpmcck", "imgpll_divpmcck", },
+         .ep_mux_table = { 5, 6, 7, },
+         .ep_count = 3,
+         .ep_chg_id = 6, },
+
+       { .n = "mck4",
+         .id = 4,
+         .ep = { "syspll_divpmcck", },
+         .ep_mux_table = { 5, },
+         .ep_count = 1,
+         .ep_chg_id = INT_MIN,
+         .c = 1, },
+};
+
+/**
+ * System clock description
+ * @n: clock name
+ * @p: clock parent name
+ * @id: clock id
+ */
+static const struct {
+       const char *n;
+       const char *p;
+       u8 id;
+} sama7g5_systemck[] = {
+       { .n = "pck0",          .p = "prog0", .id = 8, },
+       { .n = "pck1",          .p = "prog1", .id = 9, },
+       { .n = "pck2",          .p = "prog2", .id = 10, },
+       { .n = "pck3",          .p = "prog3", .id = 11, },
+       { .n = "pck4",          .p = "prog4", .id = 12, },
+       { .n = "pck5",          .p = "prog5", .id = 13, },
+       { .n = "pck6",          .p = "prog6", .id = 14, },
+       { .n = "pck7",          .p = "prog7", .id = 15, },
+};
+
+/* Mux table for programmable clocks. */
+static u32 sama7g5_prog_mux_table[] = { 0, 1, 2, 3, 5, 6, 7, 8, 9, 10, };
+
+/**
+ * Peripheral clock description
+ * @n:         clock name
+ * @p:         clock parent name
+ * @r:         clock range values
+ * @id:                clock id
+ * @chgp:      index in parent array of the changeable parent
+ */
+static const struct {
+       const char *n;
+       const char *p;
+       struct clk_range r;
+       u8 chgp;
+       u8 id;
+} sama7g5_periphck[] = {
+       { .n = "pioA_clk",      .p = "mck0", .id = 11, },
+       { .n = "sfr_clk",       .p = "mck1", .id = 19, },
+       { .n = "hsmc_clk",      .p = "mck1", .id = 21, },
+       { .n = "xdmac0_clk",    .p = "mck1", .id = 22, },
+       { .n = "xdmac1_clk",    .p = "mck1", .id = 23, },
+       { .n = "xdmac2_clk",    .p = "mck1", .id = 24, },
+       { .n = "acc_clk",       .p = "mck1", .id = 25, },
+       { .n = "aes_clk",       .p = "mck1", .id = 27, },
+       { .n = "tzaesbasc_clk", .p = "mck1", .id = 28, },
+       { .n = "asrc_clk",      .p = "mck1", .id = 30, .r = { .max = 200000000, }, },
+       { .n = "cpkcc_clk",     .p = "mck0", .id = 32, },
+       { .n = "csi_clk",       .p = "mck3", .id = 33, .r = { .max = 266000000, }, .chgp = 1, },
+       { .n = "csi2dc_clk",    .p = "mck3", .id = 34, .r = { .max = 266000000, }, .chgp = 1, },
+       { .n = "eic_clk",       .p = "mck1", .id = 37, },
+       { .n = "flex0_clk",     .p = "mck1", .id = 38, },
+       { .n = "flex1_clk",     .p = "mck1", .id = 39, },
+       { .n = "flex2_clk",     .p = "mck1", .id = 40, },
+       { .n = "flex3_clk",     .p = "mck1", .id = 41, },
+       { .n = "flex4_clk",     .p = "mck1", .id = 42, },
+       { .n = "flex5_clk",     .p = "mck1", .id = 43, },
+       { .n = "flex6_clk",     .p = "mck1", .id = 44, },
+       { .n = "flex7_clk",     .p = "mck1", .id = 45, },
+       { .n = "flex8_clk",     .p = "mck1", .id = 46, },
+       { .n = "flex9_clk",     .p = "mck1", .id = 47, },
+       { .n = "flex10_clk",    .p = "mck1", .id = 48, },
+       { .n = "flex11_clk",    .p = "mck1", .id = 49, },
+       { .n = "gmac0_clk",     .p = "mck1", .id = 51, },
+       { .n = "gmac1_clk",     .p = "mck1", .id = 52, },
+       { .n = "icm_clk",       .p = "mck1", .id = 55, },
+       { .n = "isc_clk",       .p = "mck3", .id = 56, .r = { .max = 266000000, }, .chgp = 1, },
+       { .n = "i2smcc0_clk",   .p = "mck1", .id = 57, .r = { .max = 200000000, }, },
+       { .n = "i2smcc1_clk",   .p = "mck1", .id = 58, .r = { .max = 200000000, }, },
+       { .n = "matrix_clk",    .p = "mck1", .id = 60, },
+       { .n = "mcan0_clk",     .p = "mck1", .id = 61, .r = { .max = 200000000, }, },
+       { .n = "mcan1_clk",     .p = "mck1", .id = 62, .r = { .max = 200000000, }, },
+       { .n = "mcan2_clk",     .p = "mck1", .id = 63, .r = { .max = 200000000, }, },
+       { .n = "mcan3_clk",     .p = "mck1", .id = 64, .r = { .max = 200000000, }, },
+       { .n = "mcan4_clk",     .p = "mck1", .id = 65, .r = { .max = 200000000, }, },
+       { .n = "mcan5_clk",     .p = "mck1", .id = 66, .r = { .max = 200000000, }, },
+       { .n = "pdmc0_clk",     .p = "mck1", .id = 68, .r = { .max = 200000000, }, },
+       { .n = "pdmc1_clk",     .p = "mck1", .id = 69, .r = { .max = 200000000, }, },
+       { .n = "pit64b0_clk",   .p = "mck1", .id = 70, },
+       { .n = "pit64b1_clk",   .p = "mck1", .id = 71, },
+       { .n = "pit64b2_clk",   .p = "mck1", .id = 72, },
+       { .n = "pit64b3_clk",   .p = "mck1", .id = 73, },
+       { .n = "pit64b4_clk",   .p = "mck1", .id = 74, },
+       { .n = "pit64b5_clk",   .p = "mck1", .id = 75, },
+       { .n = "pwm_clk",       .p = "mck1", .id = 77, },
+       { .n = "qspi0_clk",     .p = "mck1", .id = 78, },
+       { .n = "qspi1_clk",     .p = "mck1", .id = 79, },
+       { .n = "sdmmc0_clk",    .p = "mck1", .id = 80, },
+       { .n = "sdmmc1_clk",    .p = "mck1", .id = 81, },
+       { .n = "sdmmc2_clk",    .p = "mck1", .id = 82, },
+       { .n = "sha_clk",       .p = "mck1", .id = 83, },
+       { .n = "spdifrx_clk",   .p = "mck1", .id = 84, .r = { .max = 200000000, }, },
+       { .n = "spdiftx_clk",   .p = "mck1", .id = 85, .r = { .max = 200000000, }, },
+       { .n = "ssc0_clk",      .p = "mck1", .id = 86, .r = { .max = 200000000, }, },
+       { .n = "ssc1_clk",      .p = "mck1", .id = 87, .r = { .max = 200000000, }, },
+       { .n = "tcb0_ch0_clk",  .p = "mck1", .id = 88, .r = { .max = 200000000, }, },
+       { .n = "tcb0_ch1_clk",  .p = "mck1", .id = 89, .r = { .max = 200000000, }, },
+       { .n = "tcb0_ch2_clk",  .p = "mck1", .id = 90, .r = { .max = 200000000, }, },
+       { .n = "tcb1_ch0_clk",  .p = "mck1", .id = 91, .r = { .max = 200000000, }, },
+       { .n = "tcb1_ch1_clk",  .p = "mck1", .id = 92, .r = { .max = 200000000, }, },
+       { .n = "tcb1_ch2_clk",  .p = "mck1", .id = 93, .r = { .max = 200000000, }, },
+       { .n = "tcpca_clk",     .p = "mck1", .id = 94, },
+       { .n = "tcpcb_clk",     .p = "mck1", .id = 95, },
+       { .n = "tdes_clk",      .p = "mck1", .id = 96, },
+       { .n = "trng_clk",      .p = "mck1", .id = 97, },
+       { .n = "udphsa_clk",    .p = "mck1", .id = 104, },
+       { .n = "udphsb_clk",    .p = "mck1", .id = 105, },
+       { .n = "uhphs_clk",     .p = "mck1", .id = 106, },
+};
+
+/**
+ * Generic clock description
+ * @n:                 clock name
+ * @pp:                        PLL parents
+ * @pp_mux_table:      PLL parents mux table
+ * @r:                 clock output range
+ * @pp_chg_id:         id in parrent array of changeable PLL parent
+ * @pp_count:          PLL parents count
+ * @id:                        clock id
+ */
+static const struct {
+       const char *n;
+       const char *pp[8];
+       const char pp_mux_table[8];
+       struct clk_range r;
+       int pp_chg_id;
+       u8 pp_count;
+       u8 id;
+} sama7g5_gck[] = {
+       { .n  = "adc_gclk",
+         .id = 26,
+         .r = { .max = 100000000, },
+         .pp = { "syspll_divpmcck", "imgpll_divpmcck", "audiopll_divpmcck", },
+         .pp_mux_table = { 5, 7, 9, },
+         .pp_count = 3,
+         .pp_chg_id = INT_MIN, },
+
+       { .n  = "asrc_gclk",
+         .id = 30,
+         .r = { .max = 200000000 },
+         .pp = { "audiopll_divpmcck", },
+         .pp_mux_table = { 9, },
+         .pp_count = 1,
+         .pp_chg_id = 4, },
+
+       { .n  = "csi_gclk",
+         .id = 33,
+         .r = { .max = 27000000  },
+         .pp = { "ddrpll_divpmcck", "imgpll_divpmcck", },
+         .pp_mux_table = { 6, 7, },
+         .pp_count = 2,
+         .pp_chg_id = INT_MIN, },
+
+       { .n  = "flex0_gclk",
+         .id = 38,
+         .r = { .max = 200000000 },
+         .pp = { "syspll_divpmcck", "baudpll_divpmcck", },
+         .pp_mux_table = { 5, 8, },
+         .pp_count = 2,
+         .pp_chg_id = INT_MIN, },
+
+       { .n  = "flex1_gclk",
+         .id = 39,
+         .r = { .max = 200000000 },
+         .pp = { "syspll_divpmcck", "baudpll_divpmcck", },
+         .pp_mux_table = { 5, 8, },
+         .pp_count = 2,
+         .pp_chg_id = INT_MIN, },
+
+       { .n  = "flex2_gclk",
+         .id = 40,
+         .r = { .max = 200000000 },
+         .pp = { "syspll_divpmcck", "baudpll_divpmcck", },
+         .pp_mux_table = { 5, 8, },
+         .pp_count = 2,
+         .pp_chg_id = INT_MIN, },
+
+       { .n  = "flex3_gclk",
+         .id = 41,
+         .r = { .max = 200000000 },
+         .pp = { "syspll_divpmcck", "baudpll_divpmcck", },
+         .pp_mux_table = { 5, 8, },
+         .pp_count = 2,
+         .pp_chg_id = INT_MIN, },
+
+       { .n  = "flex4_gclk",
+         .id = 42,
+         .r = { .max = 200000000 },
+         .pp = { "syspll_divpmcck", "baudpll_divpmcck", },
+         .pp_mux_table = { 5, 8, },
+         .pp_count = 2,
+         .pp_chg_id = INT_MIN, },
+
+       { .n  = "flex5_gclk",
+         .id = 43,
+         .r = { .max = 200000000 },
+         .pp = { "syspll_divpmcck", "baudpll_divpmcck", },
+         .pp_mux_table = { 5, 8, },
+         .pp_count = 2,
+         .pp_chg_id = INT_MIN, },
+
+       { .n  = "flex6_gclk",
+         .id = 44,
+         .r = { .max = 200000000 },
+         .pp = { "syspll_divpmcck", "baudpll_divpmcck", },
+         .pp_mux_table = { 5, 8, },
+         .pp_count = 2,
+         .pp_chg_id = INT_MIN, },
+
+       { .n  = "flex7_gclk",
+         .id = 45,
+         .r = { .max = 200000000 },
+         .pp = { "syspll_divpmcck", "baudpll_divpmcck", },
+         .pp_mux_table = { 5, 8, },
+         .pp_count = 2,
+         .pp_chg_id = INT_MIN, },
+
+       { .n  = "flex8_gclk",
+         .id = 46,
+         .r = { .max = 200000000 },
+         .pp = { "syspll_divpmcck", "baudpll_divpmcck", },
+         .pp_mux_table = { 5, 8, },
+         .pp_count = 2,
+         .pp_chg_id = INT_MIN, },
+
+       { .n  = "flex9_gclk",
+         .id = 47,
+         .r = { .max = 200000000 },
+         .pp = { "syspll_divpmcck", "baudpll_divpmcck", },
+         .pp_mux_table = { 5, 8, },
+         .pp_count = 2,
+         .pp_chg_id = INT_MIN, },
+
+       { .n  = "flex10_gclk",
+         .id = 48,
+         .r = { .max = 200000000 },
+         .pp = { "syspll_divpmcck", "baudpll_divpmcck", },
+         .pp_mux_table = { 5, 8, },
+         .pp_count = 2,
+         .pp_chg_id = INT_MIN, },
+
+       { .n  = "flex11_gclk",
+         .id = 49,
+         .r = { .max = 200000000 },
+         .pp = { "syspll_divpmcck", "baudpll_divpmcck", },
+         .pp_mux_table = { 5, 8, },
+         .pp_count = 2,
+         .pp_chg_id = INT_MIN, },
+
+       { .n  = "gmac0_gclk",
+         .id = 51,
+         .r = { .max = 125000000 },
+         .pp = { "ethpll_divpmcck", },
+         .pp_mux_table = { 10, },
+         .pp_count = 1,
+         .pp_chg_id = 4, },
+
+       { .n  = "gmac1_gclk",
+         .id = 52,
+         .r = { .max = 50000000  },
+         .pp = { "ethpll_divpmcck", },
+         .pp_mux_table = { 10, },
+         .pp_count = 1,
+         .pp_chg_id = INT_MIN, },
+
+       { .n  = "gmac0_tsu_gclk",
+         .id = 53,
+         .r = { .max = 300000000 },
+         .pp = { "audiopll_divpmcck", "ethpll_divpmcck", },
+         .pp_mux_table = { 9, 10, },
+         .pp_count = 2,
+         .pp_chg_id = INT_MIN, },
+
+       { .n  = "gmac1_tsu_gclk",
+         .id = 54,
+         .r = { .max = 300000000 },
+         .pp = { "audiopll_divpmcck", "ethpll_divpmcck", },
+         .pp_mux_table = { 9, 10, },
+         .pp_count = 2,
+         .pp_chg_id = INT_MIN, },
+
+       { .n  = "i2smcc0_gclk",
+         .id = 57,
+         .r = { .max = 100000000 },
+         .pp = { "syspll_divpmcck", "audiopll_divpmcck", },
+         .pp_mux_table = { 5, 9, },
+         .pp_count = 2,
+         .pp_chg_id = 5, },
+
+       { .n  = "i2smcc1_gclk",
+         .id = 58,
+         .r = { .max = 100000000 },
+         .pp = { "syspll_divpmcck", "audiopll_divpmcck", },
+         .pp_mux_table = { 5, 9, },
+         .pp_count = 2,
+         .pp_chg_id = 5, },
+
+       { .n  = "mcan0_gclk",
+         .id = 61,
+         .r = { .max = 200000000 },
+         .pp = { "syspll_divpmcck", "baudpll_divpmcck", },
+         .pp_mux_table = { 5, 8, },
+         .pp_count = 2,
+         .pp_chg_id = INT_MIN, },
+
+       { .n  = "mcan1_gclk",
+         .id = 62,
+         .r = { .max = 200000000 },
+         .pp = { "syspll_divpmcck", "baudpll_divpmcck", },
+         .pp_mux_table = { 5, 8, },
+         .pp_count = 2,
+         .pp_chg_id = INT_MIN, },
+
+       { .n  = "mcan2_gclk",
+         .id = 63,
+         .r = { .max = 200000000 },
+         .pp = { "syspll_divpmcck", "baudpll_divpmcck", },
+         .pp_mux_table = { 5, 8, },
+         .pp_count = 2,
+         .pp_chg_id = INT_MIN, },
+
+       { .n  = "mcan3_gclk",
+         .id = 64,
+         .r = { .max = 200000000 },
+         .pp = { "syspll_divpmcck", "baudpll_divpmcck", },
+         .pp_mux_table = { 5, 8, },
+         .pp_count = 2,
+         .pp_chg_id = INT_MIN, },
+
+       { .n  = "mcan4_gclk",
+         .id = 65,
+         .r = { .max = 200000000 },
+         .pp = { "syspll_divpmcck", "baudpll_divpmcck", },
+         .pp_mux_table = { 5, 8, },
+         .pp_count = 2,
+         .pp_chg_id = INT_MIN, },
+
+       { .n  = "mcan5_gclk",
+         .id = 66,
+         .r = { .max = 200000000 },
+         .pp = { "syspll_divpmcck", "baudpll_divpmcck", },
+         .pp_mux_table = { 5, 8, },
+         .pp_count = 2,
+         .pp_chg_id = INT_MIN, },
+
+       { .n  = "pdmc0_gclk",
+         .id = 68,
+         .r = { .max = 50000000  },
+         .pp = { "syspll_divpmcck", "baudpll_divpmcck", },
+         .pp_mux_table = { 5, 8, },
+         .pp_count = 2,
+         .pp_chg_id = INT_MIN, },
+
+       { .n  = "pdmc1_gclk",
+         .id = 69,
+         .r = { .max = 50000000, },
+         .pp = { "syspll_divpmcck", "baudpll_divpmcck", },
+         .pp_mux_table = { 5, 8, },
+         .pp_count = 2,
+         .pp_chg_id = INT_MIN, },
+
+       { .n  = "pit64b0_gclk",
+         .id = 70,
+         .r = { .max = 200000000 },
+         .pp = { "syspll_divpmcck", "imgpll_divpmcck", "baudpll_divpmcck",
+                 "audiopll_divpmcck", "ethpll_divpmcck", },
+         .pp_mux_table = { 5, 7, 8, 9, 10, },
+         .pp_count = 5,
+         .pp_chg_id = INT_MIN, },
+
+       { .n  = "pit64b1_gclk",
+         .id = 71,
+         .r = { .max = 200000000 },
+         .pp = { "syspll_divpmcck", "imgpll_divpmcck", "baudpll_divpmcck",
+                 "audiopll_divpmcck", "ethpll_divpmcck", },
+         .pp_mux_table = { 5, 7, 8, 9, 10, },
+         .pp_count = 5,
+         .pp_chg_id = INT_MIN, },
+
+       { .n  = "pit64b2_gclk",
+         .id = 72,
+         .r = { .max = 200000000 },
+         .pp = { "syspll_divpmcck", "imgpll_divpmcck", "baudpll_divpmcck",
+                 "audiopll_divpmcck", "ethpll_divpmcck", },
+         .pp_mux_table = { 5, 7, 8, 9, 10, },
+         .pp_count = 5,
+         .pp_chg_id = INT_MIN, },
+
+       { .n  = "pit64b3_gclk",
+         .id = 73,
+         .r = { .max = 200000000 },
+         .pp = { "syspll_divpmcck", "imgpll_divpmcck", "baudpll_divpmcck",
+                 "audiopll_divpmcck", "ethpll_divpmcck", },
+         .pp_mux_table = { 5, 7, 8, 9, 10, },
+         .pp_count = 5,
+         .pp_chg_id = INT_MIN, },
+
+       { .n  = "pit64b4_gclk",
+         .id = 74,
+         .r = { .max = 200000000 },
+         .pp = { "syspll_divpmcck", "imgpll_divpmcck", "baudpll_divpmcck",
+                 "audiopll_divpmcck", "ethpll_divpmcck", },
+         .pp_mux_table = { 5, 7, 8, 9, 10, },
+         .pp_count = 5,
+         .pp_chg_id = INT_MIN, },
+
+       { .n  = "pit64b5_gclk",
+         .id = 75,
+         .r = { .max = 200000000 },
+         .pp = { "syspll_divpmcck", "imgpll_divpmcck", "baudpll_divpmcck",
+                 "audiopll_divpmcck", "ethpll_divpmcck", },
+         .pp_mux_table = { 5, 7, 8, 9, 10, },
+         .pp_count = 5,
+         .pp_chg_id = INT_MIN, },
+
+       { .n  = "qspi0_gclk",
+         .id = 78,
+         .r = { .max = 200000000 },
+         .pp = { "syspll_divpmcck", "baudpll_divpmcck", },
+         .pp_mux_table = { 5, 8, },
+         .pp_count = 2,
+         .pp_chg_id = INT_MIN, },
+
+       { .n  = "qspi1_gclk",
+         .id = 79,
+         .r = { .max = 200000000 },
+         .pp = { "syspll_divpmcck", "baudpll_divpmcck", },
+         .pp_mux_table = { 5, 8, },
+         .pp_count = 2,
+         .pp_chg_id = INT_MIN, },
+
+       { .n  = "sdmmc0_gclk",
+         .id = 80,
+         .r = { .max = 208000000 },
+         .pp = { "syspll_divpmcck", "baudpll_divpmcck", },
+         .pp_mux_table = { 5, 8, },
+         .pp_count = 2,
+         .pp_chg_id = 5, },
+
+       { .n  = "sdmmc1_gclk",
+         .id = 81,
+         .r = { .max = 208000000 },
+         .pp = { "syspll_divpmcck", "baudpll_divpmcck", },
+         .pp_mux_table = { 5, 8, },
+         .pp_count = 2,
+         .pp_chg_id = 5, },
+
+       { .n  = "sdmmc2_gclk",
+         .id = 82,
+         .r = { .max = 208000000 },
+         .pp = { "syspll_divpmcck", "baudpll_divpmcck", },
+         .pp_mux_table = { 5, 8, },
+         .pp_count = 2,
+         .pp_chg_id = 5, },
+
+       { .n  = "spdifrx_gclk",
+         .id = 84,
+         .r = { .max = 150000000 },
+         .pp = { "syspll_divpmcck", "audiopll_divpmcck", },
+         .pp_mux_table = { 5, 9, },
+         .pp_count = 2,
+         .pp_chg_id = 5, },
+
+       { .n = "spdiftx_gclk",
+         .id = 85,
+         .r = { .max = 25000000  },
+         .pp = { "syspll_divpmcck", "audiopll_divpmcck", },
+         .pp_mux_table = { 5, 9, },
+         .pp_count = 2,
+         .pp_chg_id = 5, },
+
+       { .n  = "tcb0_ch0_gclk",
+         .id = 88,
+         .r = { .max = 200000000 },
+         .pp = { "syspll_divpmcck", "imgpll_divpmcck", "baudpll_divpmcck",
+                 "audiopll_divpmcck", "ethpll_divpmcck", },
+         .pp_mux_table = { 5, 7, 8, 9, 10, },
+         .pp_count = 5,
+         .pp_chg_id = INT_MIN, },
+
+       { .n  = "tcb1_ch0_gclk",
+         .id = 91,
+         .r = { .max = 200000000 },
+         .pp = { "syspll_divpmcck", "imgpll_divpmcck", "baudpll_divpmcck",
+                 "audiopll_divpmcck", "ethpll_divpmcck", },
+         .pp_mux_table = { 5, 7, 8, 9, 10, },
+         .pp_count = 5,
+         .pp_chg_id = INT_MIN, },
+
+       { .n  = "tcpca_gclk",
+         .id = 94,
+         .r = { .max = 32768, },
+         .pp_chg_id = INT_MIN, },
+
+       { .n  = "tcpcb_gclk",
+         .id = 95,
+         .r = { .max = 32768, },
+         .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 },
+       .have_div3_pres = 1,
+};
+
+/* MCK0 layout. */
+static const struct clk_master_layout mck0_layout = {
+       .mask = 0x373,
+       .pres_shift = 4,
+       .offset = 0x28,
+};
+
+/* Programmable clock layout. */
+static const struct clk_programmable_layout programmable_layout = {
+       .pres_mask = 0xff,
+       .pres_shift = 8,
+       .css_mask = 0x1f,
+       .have_slck_mck = 0,
+       .is_pres_direct = 1,
+};
+
+/* Peripheral clock layout. */
+static const struct clk_pcr_layout sama7g5_pcr_layout = {
+       .offset = 0x88,
+       .cmd = BIT(31),
+       .gckcss_mask = GENMASK(12, 8),
+       .pid_mask = GENMASK(6, 0),
+};
+
+static void __init sama7g5_pmc_setup(struct device_node *np)
+{
+       const char *td_slck_name, *md_slck_name, *mainxtal_name;
+       struct pmc_data *sama7g5_pmc;
+       const char *parent_names[10];
+       void **alloc_mem = NULL;
+       int alloc_mem_size = 0;
+       struct regmap *regmap;
+       struct clk_hw *hw;
+       bool bypass;
+       int i, j;
+
+       i = of_property_match_string(np, "clock-names", "td_slck");
+       if (i < 0)
+               return;
+
+       td_slck_name = of_clk_get_parent_name(np, i);
+
+       i = of_property_match_string(np, "clock-names", "md_slck");
+       if (i < 0)
+               return;
+
+       md_slck_name = of_clk_get_parent_name(np, i);
+
+       i = of_property_match_string(np, "clock-names", "main_xtal");
+       if (i < 0)
+               return;
+
+       mainxtal_name = of_clk_get_parent_name(np, i);
+
+       regmap = device_node_to_regmap(np);
+       if (IS_ERR(regmap))
+               return;
+
+       sama7g5_pmc = pmc_data_allocate(PMC_I2S1_MUX + 1,
+                                       nck(sama7g5_systemck),
+                                       nck(sama7g5_periphck),
+                                       nck(sama7g5_gck));
+       if (!sama7g5_pmc)
+               return;
+
+       alloc_mem = kmalloc(sizeof(void *) *
+                           (ARRAY_SIZE(sama7g5_mckx) + ARRAY_SIZE(sama7g5_gck)),
+                           GFP_KERNEL);
+       if (!alloc_mem)
+               goto err_free;
+
+       hw = at91_clk_register_main_rc_osc(regmap, "main_rc_osc", 12000000,
+                                          50000000);
+       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);
+       if (IS_ERR(hw))
+               goto err_free;
+
+       parent_names[0] = "main_rc_osc";
+       parent_names[1] = "main_osc";
+       hw = at91_clk_register_sam9x5_main(regmap, "mainck", parent_names, 2);
+       if (IS_ERR(hw))
+               goto err_free;
+
+       sama7g5_pmc->chws[PMC_MAIN] = hw;
+
+       for (i = 0; i < PLL_ID_MAX; i++) {
+               for (j = 0; j < 3; j++) {
+                       struct clk_hw *parent_hw;
+
+                       if (!sama7g5_plls[i][j].n)
+                               continue;
+
+                       switch (sama7g5_plls[i][j].t) {
+                       case PLL_TYPE_FRAC:
+                               if (!strcmp(sama7g5_plls[i][j].p, "mainck"))
+                                       parent_hw = sama7g5_pmc->chws[PMC_MAIN];
+                               else
+                                       parent_hw = __clk_get_hw(of_clk_get_by_name(np,
+                                               sama7g5_plls[i][j].p));
+
+                               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].l,
+                                       sama7g5_plls[i][j].c);
+                               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].l,
+                                       sama7g5_plls[i][j].c);
+                               break;
+
+                       default:
+                               continue;
+                       }
+
+                       if (IS_ERR(hw))
+                               goto err_free;
+
+                       if (sama7g5_plls[i][j].eid)
+                               sama7g5_pmc->chws[sama7g5_plls[i][j].eid] = hw;
+               }
+       }
+
+       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);
+       if (IS_ERR(hw))
+               goto err_free;
+
+       sama7g5_pmc->chws[PMC_MCK] = hw;
+
+       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;
+               u32 *mux_table;
+
+               mux_table = kmalloc_array(num_parents, sizeof(*mux_table),
+                                         GFP_KERNEL);
+               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_mckx[i].ep_count);
+               SAMA7G5_FILL_TABLE(&parent_names[4], sama7g5_mckx[i].ep,
+                                  sama7g5_mckx[i].ep_count);
+
+               hw = at91_clk_sama7g5_register_master(regmap, sama7g5_mckx[i].n,
+                                  num_parents, parent_names, mux_table,
+                                  &pmc_mckX_lock, sama7g5_mckx[i].id,
+                                  sama7g5_mckx[i].c,
+                                  sama7g5_mckx[i].ep_chg_id);
+               if (IS_ERR(hw))
+                       goto err_free;
+
+               alloc_mem[alloc_mem_size++] = mux_table;
+       }
+
+       hw = at91_clk_sama7g5_register_utmi(regmap, "utmick", "main_xtal");
+       if (IS_ERR(hw))
+               goto err_free;
+
+       sama7g5_pmc->chws[PMC_UTMI] = hw;
+
+       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";
+       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,
+                                                   &programmable_layout,
+                                                   sama7g5_prog_mux_table);
+               if (IS_ERR(hw))
+                       goto err_free;
+       }
+
+       for (i = 0; i < ARRAY_SIZE(sama7g5_systemck); i++) {
+               hw = at91_clk_register_system(regmap, sama7g5_systemck[i].n,
+                                             sama7g5_systemck[i].p,
+                                             sama7g5_systemck[i].id);
+               if (IS_ERR(hw))
+                       goto err_free;
+
+               sama7g5_pmc->shws[sama7g5_systemck[i].id] = hw;
+       }
+
+       for (i = 0; i < ARRAY_SIZE(sama7g5_periphck); i++) {
+               hw = at91_clk_register_sam9x5_peripheral(regmap, &pmc_pcr_lock,
+                                               &sama7g5_pcr_layout,
+                                               sama7g5_periphck[i].n,
+                                               sama7g5_periphck[i].p,
+                                               sama7g5_periphck[i].id,
+                                               &sama7g5_periphck[i].r,
+                                               sama7g5_periphck[i].chgp ? 0 :
+                                               INT_MIN);
+               if (IS_ERR(hw))
+                       goto err_free;
+
+               sama7g5_pmc->phws[sama7g5_periphck[i].id] = hw;
+       }
+
+       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;
+               u32 *mux_table;
+
+               mux_table = kmalloc_array(num_parents, sizeof(*mux_table),
+                                         GFP_KERNEL);
+               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_gck[i].pp_count);
+               SAMA7G5_FILL_TABLE(&parent_names[4], sama7g5_gck[i].pp,
+                                  sama7g5_gck[i].pp_count);
+
+               hw = at91_clk_register_generated(regmap, &pmc_pcr_lock,
+                                                &sama7g5_pcr_layout,
+                                                sama7g5_gck[i].n,
+                                                parent_names, mux_table,
+                                                num_parents,
+                                                sama7g5_gck[i].id,
+                                                &sama7g5_gck[i].r,
+                                                sama7g5_gck[i].pp_chg_id);
+               if (IS_ERR(hw))
+                       goto err_free;
+
+               sama7g5_pmc->ghws[sama7g5_gck[i].id] = hw;
+               alloc_mem[alloc_mem_size++] = mux_table;
+       }
+
+       of_clk_add_hw_provider(np, of_clk_hw_pmc_get, sama7g5_pmc);
+
+       return;
+
+err_free:
+       if (alloc_mem) {
+               for (i = 0; i < alloc_mem_size; i++)
+                       kfree(alloc_mem[i]);
+               kfree(alloc_mem);
+       }
+
+       pmc_data_free(sama7g5_pmc);
+}
+
+/* Some clks are used for a clocksource */
+CLK_OF_DECLARE(sama7g5_pmc, "microchip,sama7g5-pmc", sama7g5_pmc_setup);
index 15dc4cd86d763fc0f2c0f567f91c24a14340cf23..2d65770d8665171a69ebe1b8b9cd4fa9ca831d57 100644 (file)
@@ -471,8 +471,9 @@ static void __init of_sam9x60_sckc_setup(struct device_node *np)
        if (!regbase)
                return;
 
-       slow_rc = clk_hw_register_fixed_rate(NULL, parent_names[0], NULL, 0,
-                                            32768);
+       slow_rc = clk_hw_register_fixed_rate_with_accuracy(NULL, parent_names[0],
+                                                          NULL, 0, 32768,
+                                                          93750000);
        if (IS_ERR(slow_rc))
                return;
 
index 027eba31f79318f38a22359bf933cab0b270346f..3439bc65bb4e396c7f7a16c23a94fd31b9c991a4 100644 (file)
@@ -314,6 +314,7 @@ struct bcm2835_cprman {
        struct device *dev;
        void __iomem *regs;
        spinlock_t regs_lock; /* spinlock for all clocks */
+       unsigned int soc;
 
        /*
         * Real names of cprman clock parents looked up through
@@ -526,6 +527,20 @@ static int bcm2835_pll_is_on(struct clk_hw *hw)
                A2W_PLL_CTRL_PRST_DISABLE;
 }
 
+static u32 bcm2835_pll_get_prediv_mask(struct bcm2835_cprman *cprman,
+                                      const struct bcm2835_pll_data *data)
+{
+       /*
+        * On BCM2711 there isn't a pre-divisor available in the PLL feedback
+        * loop. Bits 13:14 of ANA1 (PLLA,PLLB,PLLC,PLLD) have been re-purposed
+        * for to for VCO RANGE bits.
+        */
+       if (cprman->soc & SOC_BCM2711)
+               return 0;
+
+       return data->ana->fb_prediv_mask;
+}
+
 static void bcm2835_pll_choose_ndiv_and_fdiv(unsigned long rate,
                                             unsigned long parent_rate,
                                             u32 *ndiv, u32 *fdiv)
@@ -583,7 +598,7 @@ static unsigned long bcm2835_pll_get_rate(struct clk_hw *hw,
        ndiv = (a2wctrl & A2W_PLL_CTRL_NDIV_MASK) >> A2W_PLL_CTRL_NDIV_SHIFT;
        pdiv = (a2wctrl & A2W_PLL_CTRL_PDIV_MASK) >> A2W_PLL_CTRL_PDIV_SHIFT;
        using_prediv = cprman_read(cprman, data->ana_reg_base + 4) &
-               data->ana->fb_prediv_mask;
+                      bcm2835_pll_get_prediv_mask(cprman, data);
 
        if (using_prediv) {
                ndiv *= 2;
@@ -666,6 +681,7 @@ static int bcm2835_pll_set_rate(struct clk_hw *hw,
        struct bcm2835_pll *pll = container_of(hw, struct bcm2835_pll, hw);
        struct bcm2835_cprman *cprman = pll->cprman;
        const struct bcm2835_pll_data *data = pll->data;
+       u32 prediv_mask = bcm2835_pll_get_prediv_mask(cprman, data);
        bool was_using_prediv, use_fb_prediv, do_ana_setup_first;
        u32 ndiv, fdiv, a2w_ctl;
        u32 ana[4];
@@ -683,7 +699,7 @@ static int bcm2835_pll_set_rate(struct clk_hw *hw,
        for (i = 3; i >= 0; i--)
                ana[i] = cprman_read(cprman, data->ana_reg_base + i * 4);
 
-       was_using_prediv = ana[1] & data->ana->fb_prediv_mask;
+       was_using_prediv = ana[1] & prediv_mask;
 
        ana[0] &= ~data->ana->mask0;
        ana[0] |= data->ana->set0;
@@ -693,10 +709,10 @@ static int bcm2835_pll_set_rate(struct clk_hw *hw,
        ana[3] |= data->ana->set3;
 
        if (was_using_prediv && !use_fb_prediv) {
-               ana[1] &= ~data->ana->fb_prediv_mask;
+               ana[1] &= ~prediv_mask;
                do_ana_setup_first = true;
        } else if (!was_using_prediv && use_fb_prediv) {
-               ana[1] |= data->ana->fb_prediv_mask;
+               ana[1] |= prediv_mask;
                do_ana_setup_first = false;
        } else {
                do_ana_setup_first = true;
@@ -2262,6 +2278,7 @@ static int bcm2835_clk_probe(struct platform_device *pdev)
        platform_set_drvdata(pdev, cprman);
 
        cprman->onecell.num = asize;
+       cprman->soc = pdata->soc;
        hws = cprman->onecell.hws;
 
        for (i = 0; i < asize; i++) {
index 6fb8af506777d9dd666f0560f4630cb1d4c074ea..e062dd4992ea5e2aec2d4de10f72b575e2c27db9 100644 (file)
@@ -119,7 +119,7 @@ static long iproc_asiu_clk_round_rate(struct clk_hw *hw, unsigned long rate,
        if (rate == *parent_rate)
                return *parent_rate;
 
-       div = DIV_ROUND_UP(*parent_rate, rate);
+       div = DIV_ROUND_CLOSEST(*parent_rate, rate);
        if (div < 2)
                return *parent_rate;
 
@@ -145,7 +145,7 @@ static int iproc_asiu_clk_set_rate(struct clk_hw *hw, unsigned long rate,
                return 0;
        }
 
-       div = DIV_ROUND_UP(parent_rate, rate);
+       div = DIV_ROUND_CLOSEST(parent_rate, rate);
        if (div < 2)
                return -EINVAL;
 
index 374afcab89af5978c076826c21699ab3d58b0b14..5942e9874bc08243bc5d5c7737a8daafb0b14cdd 100644 (file)
@@ -244,6 +244,14 @@ static const struct clockgen_muxinfo clockgen2_cmux_cgb = {
        },
 };
 
+static const struct clockgen_muxinfo ls1021a_cmux = {
+       {
+               { CLKSEL_VALID, CGA_PLL1, PLL_DIV1 },
+               { CLKSEL_VALID, CGA_PLL1, PLL_DIV2 },
+               { CLKSEL_VALID, CGA_PLL1, PLL_DIV4 },
+       }
+};
+
 static const struct clockgen_muxinfo ls1028a_hwa1 = {
        {
                { CLKSEL_VALID, PLATFORM_PLL, PLL_DIV1 },
@@ -577,7 +585,7 @@ static const struct clockgen_chipinfo chipinfo[] = {
        {
                .compat = "fsl,ls1021a-clockgen",
                .cmux_groups = {
-                       &t1023_cmux
+                       &ls1021a_cmux
                },
                .cmux_to_group = {
                        0, -1
diff --git a/drivers/clk/clk-sparx5.c b/drivers/clk/clk-sparx5.c
new file mode 100644 (file)
index 0000000..0fad0c1
--- /dev/null
@@ -0,0 +1,295 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * Microchip Sparx5 SoC Clock driver.
+ *
+ * Copyright (c) 2019 Microchip Inc.
+ *
+ * Author: Lars Povlsen <lars.povlsen@microchip.com>
+ */
+
+#include <linux/io.h>
+#include <linux/module.h>
+#include <linux/clk-provider.h>
+#include <linux/bitfield.h>
+#include <linux/of.h>
+#include <linux/slab.h>
+#include <linux/platform_device.h>
+#include <dt-bindings/clock/microchip,sparx5.h>
+
+#define PLL_DIV                GENMASK(7, 0)
+#define PLL_PRE_DIV    GENMASK(10, 8)
+#define PLL_ROT_DIR    BIT(11)
+#define PLL_ROT_SEL    GENMASK(13, 12)
+#define PLL_ROT_ENA    BIT(14)
+#define PLL_CLK_ENA    BIT(15)
+
+#define MAX_SEL 4
+#define MAX_PRE BIT(3)
+
+static const u8 sel_rates[MAX_SEL] = { 0, 2*8, 2*4, 2*2 };
+
+static const char *clk_names[N_CLOCKS] = {
+       "core", "ddr", "cpu2", "arm2",
+       "aux1", "aux2", "aux3", "aux4",
+       "synce",
+};
+
+struct s5_hw_clk {
+       struct clk_hw hw;
+       void __iomem *reg;
+};
+
+struct s5_clk_data {
+       void __iomem *base;
+       struct s5_hw_clk s5_hw[N_CLOCKS];
+};
+
+struct s5_pll_conf {
+       unsigned long freq;
+       u8 div;
+       bool rot_ena;
+       u8 rot_sel;
+       u8 rot_dir;
+       u8 pre_div;
+};
+
+#define to_s5_pll(hw) container_of(hw, struct s5_hw_clk, hw)
+
+static unsigned long s5_calc_freq(unsigned long parent_rate,
+                                 const struct s5_pll_conf *conf)
+{
+       unsigned long rate = parent_rate / conf->div;
+
+       if (conf->rot_ena) {
+               int sign = conf->rot_dir ? -1 : 1;
+               int divt = sel_rates[conf->rot_sel] * (1 + conf->pre_div);
+               int divb = divt + sign;
+
+               rate = mult_frac(rate, divt, divb);
+               rate = roundup(rate, 1000);
+       }
+
+       return rate;
+}
+
+static void s5_search_fractional(unsigned long rate,
+                                unsigned long parent_rate,
+                                int div,
+                                struct s5_pll_conf *conf)
+{
+       struct s5_pll_conf best;
+       ulong cur_offset, best_offset = rate;
+       int d, i, j;
+
+       memset(conf, 0, sizeof(*conf));
+       conf->div = div;
+       conf->rot_ena = 1;      /* Fractional rate */
+
+       for (d = 0; best_offset > 0 && d <= 1 ; d++) {
+               conf->rot_dir = !!d;
+               for (i = 0; best_offset > 0 && i < MAX_PRE; i++) {
+                       conf->pre_div = i;
+                       for (j = 1; best_offset > 0 && j < MAX_SEL; j++) {
+                               conf->rot_sel = j;
+                               conf->freq = s5_calc_freq(parent_rate, conf);
+                               cur_offset = abs(rate - conf->freq);
+                               if (cur_offset < best_offset) {
+                                       best_offset = cur_offset;
+                                       best = *conf;
+                               }
+                       }
+               }
+       }
+
+       /* Best match */
+       *conf = best;
+}
+
+static unsigned long s5_calc_params(unsigned long rate,
+                                   unsigned long parent_rate,
+                                   struct s5_pll_conf *conf)
+{
+       if (parent_rate % rate) {
+               struct s5_pll_conf alt1, alt2;
+               int div;
+
+               div = DIV_ROUND_CLOSEST_ULL(parent_rate, rate);
+               s5_search_fractional(rate, parent_rate, div, &alt1);
+
+               /* Straight match? */
+               if (alt1.freq == rate) {
+                       *conf = alt1;
+               } else {
+                       /* Try without rounding divider */
+                       div = parent_rate / rate;
+                       if (div != alt1.div) {
+                               s5_search_fractional(rate, parent_rate, div,
+                                                    &alt2);
+                               /* Select the better match */
+                               if (abs(rate - alt1.freq) <
+                                   abs(rate - alt2.freq))
+                                       *conf = alt1;
+                               else
+                                       *conf = alt2;
+                       }
+               }
+       } else {
+               /* Straight fit */
+               memset(conf, 0, sizeof(*conf));
+               conf->div = parent_rate / rate;
+       }
+
+       return conf->freq;
+}
+
+static int s5_pll_enable(struct clk_hw *hw)
+{
+       struct s5_hw_clk *pll = to_s5_pll(hw);
+       u32 val = readl(pll->reg);
+
+       val |= PLL_CLK_ENA;
+       writel(val, pll->reg);
+
+       return 0;
+}
+
+static void s5_pll_disable(struct clk_hw *hw)
+{
+       struct s5_hw_clk *pll = to_s5_pll(hw);
+       u32 val = readl(pll->reg);
+
+       val &= ~PLL_CLK_ENA;
+       writel(val, pll->reg);
+}
+
+static int s5_pll_set_rate(struct clk_hw *hw,
+                          unsigned long rate,
+                          unsigned long parent_rate)
+{
+       struct s5_hw_clk *pll = to_s5_pll(hw);
+       struct s5_pll_conf conf;
+       unsigned long eff_rate;
+       u32 val;
+
+       eff_rate = s5_calc_params(rate, parent_rate, &conf);
+       if (eff_rate != rate)
+               return -EOPNOTSUPP;
+
+       val = readl(pll->reg) & PLL_CLK_ENA;
+       val |= FIELD_PREP(PLL_DIV, conf.div);
+       if (conf.rot_ena) {
+               val |= PLL_ROT_ENA;
+               val |= FIELD_PREP(PLL_ROT_SEL, conf.rot_sel);
+               val |= FIELD_PREP(PLL_PRE_DIV, conf.pre_div);
+               if (conf.rot_dir)
+                       val |= PLL_ROT_DIR;
+       }
+       writel(val, pll->reg);
+
+       return 0;
+}
+
+static unsigned long s5_pll_recalc_rate(struct clk_hw *hw,
+                                       unsigned long parent_rate)
+{
+       struct s5_hw_clk *pll = to_s5_pll(hw);
+       struct s5_pll_conf conf;
+       u32 val;
+
+       val = readl(pll->reg);
+
+       if (val & PLL_CLK_ENA) {
+               conf.div     = FIELD_GET(PLL_DIV, val);
+               conf.pre_div = FIELD_GET(PLL_PRE_DIV, val);
+               conf.rot_ena = FIELD_GET(PLL_ROT_ENA, val);
+               conf.rot_dir = FIELD_GET(PLL_ROT_DIR, val);
+               conf.rot_sel = FIELD_GET(PLL_ROT_SEL, val);
+
+               conf.freq = s5_calc_freq(parent_rate, &conf);
+       } else {
+               conf.freq = 0;
+       }
+
+       return conf.freq;
+}
+
+static long s5_pll_round_rate(struct clk_hw *hw, unsigned long rate,
+                             unsigned long *parent_rate)
+{
+       struct s5_pll_conf conf;
+
+       return s5_calc_params(rate, *parent_rate, &conf);
+}
+
+static const struct clk_ops s5_pll_ops = {
+       .enable         = s5_pll_enable,
+       .disable        = s5_pll_disable,
+       .set_rate       = s5_pll_set_rate,
+       .round_rate     = s5_pll_round_rate,
+       .recalc_rate    = s5_pll_recalc_rate,
+};
+
+static struct clk_hw *s5_clk_hw_get(struct of_phandle_args *clkspec, void *data)
+{
+       struct s5_clk_data *s5_clk = data;
+       unsigned int idx = clkspec->args[0];
+
+       if (idx >= N_CLOCKS) {
+               pr_err("%s: invalid index %u\n", __func__, idx);
+               return ERR_PTR(-EINVAL);
+       }
+
+       return &s5_clk->s5_hw[idx].hw;
+}
+
+static int s5_clk_probe(struct platform_device *pdev)
+{
+       struct device *dev = &pdev->dev;
+       int i, ret;
+       struct s5_clk_data *s5_clk;
+       struct clk_parent_data pdata = { .index = 0 };
+       struct clk_init_data init = {
+               .ops = &s5_pll_ops,
+               .num_parents = 1,
+               .parent_data = &pdata,
+       };
+
+       s5_clk = devm_kzalloc(dev, sizeof(*s5_clk), GFP_KERNEL);
+       if (!s5_clk)
+               return -ENOMEM;
+
+       s5_clk->base = devm_platform_ioremap_resource(pdev, 0);
+       if (IS_ERR(s5_clk->base))
+               return PTR_ERR(s5_clk->base);
+
+       for (i = 0; i < N_CLOCKS; i++) {
+               struct s5_hw_clk *s5_hw = &s5_clk->s5_hw[i];
+
+               init.name = clk_names[i];
+               s5_hw->reg = s5_clk->base + (i * 4);
+               s5_hw->hw.init = &init;
+               ret = devm_clk_hw_register(dev, &s5_hw->hw);
+               if (ret) {
+                       dev_err(dev, "failed to register %s clock\n",
+                               init.name);
+                       return ret;
+               }
+       }
+
+       return devm_of_clk_add_hw_provider(dev, s5_clk_hw_get, s5_clk);
+}
+
+static const struct of_device_id s5_clk_dt_ids[] = {
+       { .compatible = "microchip,sparx5-dpll", },
+       { }
+};
+MODULE_DEVICE_TABLE(of, s5_clk_dt_ids);
+
+static struct platform_driver s5_clk_driver = {
+       .probe  = s5_clk_probe,
+       .driver = {
+               .name = "sparx5-clk",
+               .of_match_table = s5_clk_dt_ids,
+       },
+};
+builtin_platform_driver(s5_clk_driver);
index 9a5fb3834b9a4c874fe7afe5ae3ced41c969af80..c90460e7ef2153fe7b3bd3387e0c666f663c0e77 100644 (file)
@@ -167,6 +167,12 @@ struct vc5_hw_data {
        u32                     div_int;
        u32                     div_frc;
        unsigned int            num;
+};
+
+struct vc5_out_data {
+       struct clk_hw           hw;
+       struct vc5_driver_data  *vc5;
+       unsigned int            num;
        unsigned int            clk_output_cfg0;
        unsigned int            clk_output_cfg0_mask;
 };
@@ -184,7 +190,7 @@ struct vc5_driver_data {
        struct clk_hw           clk_pfd;
        struct vc5_hw_data      clk_pll;
        struct vc5_hw_data      clk_fod[VC5_MAX_FOD_NUM];
-       struct vc5_hw_data      clk_out[VC5_MAX_CLK_OUT_NUM];
+       struct vc5_out_data     clk_out[VC5_MAX_CLK_OUT_NUM];
 };
 
 /*
@@ -567,7 +573,7 @@ static const struct clk_ops vc5_fod_ops = {
 
 static int vc5_clk_out_prepare(struct clk_hw *hw)
 {
-       struct vc5_hw_data *hwdata = container_of(hw, struct vc5_hw_data, hw);
+       struct vc5_out_data *hwdata = container_of(hw, struct vc5_out_data, hw);
        struct vc5_driver_data *vc5 = hwdata->vc5;
        const u8 mask = VC5_OUT_DIV_CONTROL_SELB_NORM |
                        VC5_OUT_DIV_CONTROL_SEL_EXT |
@@ -609,7 +615,7 @@ static int vc5_clk_out_prepare(struct clk_hw *hw)
 
 static void vc5_clk_out_unprepare(struct clk_hw *hw)
 {
-       struct vc5_hw_data *hwdata = container_of(hw, struct vc5_hw_data, hw);
+       struct vc5_out_data *hwdata = container_of(hw, struct vc5_out_data, hw);
        struct vc5_driver_data *vc5 = hwdata->vc5;
 
        /* Disable the clock buffer */
@@ -619,7 +625,7 @@ static void vc5_clk_out_unprepare(struct clk_hw *hw)
 
 static unsigned char vc5_clk_out_get_parent(struct clk_hw *hw)
 {
-       struct vc5_hw_data *hwdata = container_of(hw, struct vc5_hw_data, hw);
+       struct vc5_out_data *hwdata = container_of(hw, struct vc5_out_data, hw);
        struct vc5_driver_data *vc5 = hwdata->vc5;
        const u8 mask = VC5_OUT_DIV_CONTROL_SELB_NORM |
                        VC5_OUT_DIV_CONTROL_SEL_EXT |
@@ -649,7 +655,7 @@ static unsigned char vc5_clk_out_get_parent(struct clk_hw *hw)
 
 static int vc5_clk_out_set_parent(struct clk_hw *hw, u8 index)
 {
-       struct vc5_hw_data *hwdata = container_of(hw, struct vc5_hw_data, hw);
+       struct vc5_out_data *hwdata = container_of(hw, struct vc5_out_data, hw);
        struct vc5_driver_data *vc5 = hwdata->vc5;
        const u8 mask = VC5_OUT_DIV_CONTROL_RESET |
                        VC5_OUT_DIV_CONTROL_SELB_NORM |
@@ -704,7 +710,7 @@ static int vc5_map_index_to_output(const enum vc5_model model,
 }
 
 static int vc5_update_mode(struct device_node *np_output,
-                          struct vc5_hw_data *clk_out)
+                          struct vc5_out_data *clk_out)
 {
        u32 value;
 
@@ -729,7 +735,7 @@ static int vc5_update_mode(struct device_node *np_output,
 }
 
 static int vc5_update_power(struct device_node *np_output,
-                           struct vc5_hw_data *clk_out)
+                           struct vc5_out_data *clk_out)
 {
        u32 value;
 
@@ -754,7 +760,7 @@ static int vc5_update_power(struct device_node *np_output,
 }
 
 static int vc5_update_slew(struct device_node *np_output,
-                          struct vc5_hw_data *clk_out)
+                          struct vc5_out_data *clk_out)
 {
        u32 value;
 
@@ -782,17 +788,20 @@ static int vc5_update_slew(struct device_node *np_output,
 }
 
 static int vc5_get_output_config(struct i2c_client *client,
-                                struct vc5_hw_data *clk_out)
+                                struct vc5_out_data *clk_out)
 {
        struct device_node *np_output;
        char *child_name;
        int ret = 0;
 
        child_name = kasprintf(GFP_KERNEL, "OUT%d", clk_out->num + 1);
+       if (!child_name)
+               return -ENOMEM;
+
        np_output = of_get_child_by_name(client->dev.of_node, child_name);
        kfree(child_name);
        if (!np_output)
-               goto output_done;
+               return 0;
 
        ret = vc5_update_mode(np_output, clk_out);
        if (ret)
@@ -813,7 +822,6 @@ output_error:
 
        of_node_put(np_output);
 
-output_done:
        return ret;
 }
 
@@ -828,7 +836,7 @@ static int vc5_probe(struct i2c_client *client, const struct i2c_device_id *id)
        int ret;
 
        vc5 = devm_kzalloc(&client->dev, sizeof(*vc5), GFP_KERNEL);
-       if (vc5 == NULL)
+       if (!vc5)
                return -ENOMEM;
 
        i2c_set_clientdata(client, vc5);
@@ -882,11 +890,9 @@ static int vc5_probe(struct i2c_client *client, const struct i2c_device_id *id)
        init.parent_names = parent_names;
        vc5->clk_mux.init = &init;
        ret = devm_clk_hw_register(&client->dev, &vc5->clk_mux);
+       if (ret)
+               goto err_clk_register;
        kfree(init.name);       /* clock framework made a copy of the name */
-       if (ret) {
-               dev_err(&client->dev, "unable to register %s\n", init.name);
-               goto err_clk;
-       }
 
        if (vc5->chip_info->flags & VC5_HAS_PFD_FREQ_DBL) {
                /* Register frequency doubler */
@@ -900,12 +906,9 @@ static int vc5_probe(struct i2c_client *client, const struct i2c_device_id *id)
                init.num_parents = 1;
                vc5->clk_mul.init = &init;
                ret = devm_clk_hw_register(&client->dev, &vc5->clk_mul);
+               if (ret)
+                       goto err_clk_register;
                kfree(init.name); /* clock framework made a copy of the name */
-               if (ret) {
-                       dev_err(&client->dev, "unable to register %s\n",
-                               init.name);
-                       goto err_clk;
-               }
        }
 
        /* Register PFD */
@@ -921,11 +924,9 @@ static int vc5_probe(struct i2c_client *client, const struct i2c_device_id *id)
        init.num_parents = 1;
        vc5->clk_pfd.init = &init;
        ret = devm_clk_hw_register(&client->dev, &vc5->clk_pfd);
+       if (ret)
+               goto err_clk_register;
        kfree(init.name);       /* clock framework made a copy of the name */
-       if (ret) {
-               dev_err(&client->dev, "unable to register %s\n", init.name);
-               goto err_clk;
-       }
 
        /* Register PLL */
        memset(&init, 0, sizeof(init));
@@ -939,11 +940,9 @@ static int vc5_probe(struct i2c_client *client, const struct i2c_device_id *id)
        vc5->clk_pll.vc5 = vc5;
        vc5->clk_pll.hw.init = &init;
        ret = devm_clk_hw_register(&client->dev, &vc5->clk_pll.hw);
+       if (ret)
+               goto err_clk_register;
        kfree(init.name); /* clock framework made a copy of the name */
-       if (ret) {
-               dev_err(&client->dev, "unable to register %s\n", init.name);
-               goto err_clk;
-       }
 
        /* Register FODs */
        for (n = 0; n < vc5->chip_info->clk_fod_cnt; n++) {
@@ -960,12 +959,9 @@ static int vc5_probe(struct i2c_client *client, const struct i2c_device_id *id)
                vc5->clk_fod[n].vc5 = vc5;
                vc5->clk_fod[n].hw.init = &init;
                ret = devm_clk_hw_register(&client->dev, &vc5->clk_fod[n].hw);
+               if (ret)
+                       goto err_clk_register;
                kfree(init.name); /* clock framework made a copy of the name */
-               if (ret) {
-                       dev_err(&client->dev, "unable to register %s\n",
-                               init.name);
-                       goto err_clk;
-               }
        }
 
        /* Register MUX-connected OUT0_I2C_SELB output */
@@ -981,11 +977,9 @@ static int vc5_probe(struct i2c_client *client, const struct i2c_device_id *id)
        vc5->clk_out[0].vc5 = vc5;
        vc5->clk_out[0].hw.init = &init;
        ret = devm_clk_hw_register(&client->dev, &vc5->clk_out[0].hw);
-       kfree(init.name);       /* clock framework made a copy of the name */
-       if (ret) {
-               dev_err(&client->dev, "unable to register %s\n", init.name);
-               goto err_clk;
-       }
+       if (ret)
+               goto err_clk_register;
+       kfree(init.name); /* clock framework made a copy of the name */
 
        /* Register FOD-connected OUTx outputs */
        for (n = 1; n < vc5->chip_info->clk_out_cnt; n++) {
@@ -1008,12 +1002,9 @@ static int vc5_probe(struct i2c_client *client, const struct i2c_device_id *id)
                vc5->clk_out[n].vc5 = vc5;
                vc5->clk_out[n].hw.init = &init;
                ret = devm_clk_hw_register(&client->dev, &vc5->clk_out[n].hw);
+               if (ret)
+                       goto err_clk_register;
                kfree(init.name); /* clock framework made a copy of the name */
-               if (ret) {
-                       dev_err(&client->dev, "unable to register %s\n",
-                               init.name);
-                       goto err_clk;
-               }
 
                /* Fetch Clock Output configuration from DT (if specified) */
                ret = vc5_get_output_config(client, &vc5->clk_out[n]);
@@ -1029,6 +1020,9 @@ static int vc5_probe(struct i2c_client *client, const struct i2c_device_id *id)
 
        return 0;
 
+err_clk_register:
+       dev_err(&client->dev, "unable to register %s\n", init.name);
+       kfree(init.name); /* clock framework made a copy of the name */
 err_clk:
        if (vc5->chip_info->flags & VC5_HAS_INTERNAL_XTAL)
                clk_unregister_fixed_rate(vc5->pin_xin);
index 236923b255431b8cbc76281ab3522d37a0f485c6..0a9261a099bd8fc9474dc04ddaa0670e9b8c0272 100644 (file)
@@ -500,12 +500,6 @@ static unsigned long clk_core_get_accuracy_no_lock(struct clk_core *core)
        return core->accuracy;
 }
 
-unsigned long __clk_get_flags(struct clk *clk)
-{
-       return !clk ? 0 : clk->core->flags;
-}
-EXPORT_SYMBOL_GPL(__clk_get_flags);
-
 unsigned long clk_hw_get_flags(const struct clk_hw *hw)
 {
        return hw->core->flags;
@@ -3054,6 +3048,31 @@ static int clk_rate_set(void *data, u64 val)
 }
 
 #define clk_rate_mode  0644
+
+static int clk_prepare_enable_set(void *data, u64 val)
+{
+       struct clk_core *core = data;
+       int ret = 0;
+
+       if (val)
+               ret = clk_prepare_enable(core->hw->clk);
+       else
+               clk_disable_unprepare(core->hw->clk);
+
+       return ret;
+}
+
+static int clk_prepare_enable_get(void *data, u64 *val)
+{
+       struct clk_core *core = data;
+
+       *val = core->enable_count && core->prepare_count;
+       return 0;
+}
+
+DEFINE_DEBUGFS_ATTRIBUTE(clk_prepare_enable_fops, clk_prepare_enable_get,
+                        clk_prepare_enable_set, "%llu\n");
+
 #else
 #define clk_rate_set   NULL
 #define clk_rate_mode  0444
@@ -3231,6 +3250,10 @@ static void clk_debug_create_one(struct clk_core *core, struct dentry *pdentry)
        debugfs_create_u32("clk_notifier_count", 0444, root, &core->notifier_count);
        debugfs_create_file("clk_duty_cycle", 0444, root, core,
                            &clk_duty_cycle_fops);
+#ifdef CLOCK_ALLOW_WRITE_DEBUGFS
+       debugfs_create_file("clk_prepare_enable", 0644, root, core,
+                           &clk_prepare_enable_fops);
+#endif
 
        if (core->num_parents > 0)
                debugfs_create_file("clk_parent", 0444, root, core,
@@ -4135,6 +4158,7 @@ static int devm_clk_hw_match(struct device *dev, void *res, void *data)
 
 /**
  * devm_clk_unregister - resource managed clk_unregister()
+ * @dev: device that is unregistering the clock data
  * @clk: clock to unregister
  *
  * Deallocate a clock allocated with devm_clk_register(). Normally
@@ -4324,6 +4348,8 @@ static void clk_core_reparent_orphans(void)
  * @node: Pointer to device tree node of clock provider
  * @get: Get clock callback.  Returns NULL or a struct clk for the
  *       given clock specifier
+ * @get_hw: Get clk_hw callback.  Returns NULL, ERR_PTR or a
+ *       struct clk_hw for the given clock specifier
  * @data: context pointer to be passed into @get callback
  */
 struct of_clk_provider {
index 8a23d5dfd1f8dbb6d6984c03e7d2e3f433a354c4..6c35e4bb79404b84e11997190e88ab6a18601dad 100644 (file)
@@ -651,7 +651,7 @@ static int davinci_pll_sysclk_rate_change(struct notifier_block *nb,
                pllcmd = readl(pll->base + PLLCMD);
                pllcmd |= PLLCMD_GOSET;
                writel(pllcmd, pll->base + PLLCMD);
-               /* fallthrough */
+               fallthrough;
        case PRE_RATE_CHANGE:
                /* Wait until for outstanding changes to take effect */
                do {
index a7db93030e025c12457fa95d39be3944df0615fc..b20cdea3e9cc378e83227de65ea860e13c289598 100644 (file)
@@ -433,7 +433,7 @@ struct clk_hw *imx_clk_hw_pllv3(enum imx_pllv3_type type, const char *name,
                break;
        case IMX_PLLV3_USB_VF610:
                pll->div_shift = 1;
-               /* fall through */
+               fallthrough;
        case IMX_PLLV3_USB:
                ops = &clk_pllv3_ops;
                pll->powerup_set = true;
@@ -441,7 +441,7 @@ struct clk_hw *imx_clk_hw_pllv3(enum imx_pllv3_type type, const char *name,
        case IMX_PLLV3_AV_IMX7:
                pll->num_offset = PLL_IMX7_NUM_OFFSET;
                pll->denom_offset = PLL_IMX7_DENOM_OFFSET;
-               /* fall through */
+               fallthrough;
        case IMX_PLLV3_AV:
                ops = &clk_pllv3_av_ops;
                break;
index 6c5b8029cc8ab615e60241fc3ac01aa0e77a30e7..0268d23ebe2e0b9a50e719876e0ec01e5f6e3d8b 100644 (file)
@@ -4,6 +4,7 @@
  *
  * Copyright (c) 2013-2015 Imagination Technologies
  * Author: Paul Burton <paul.burton@mips.com>
+ * Copyright (c) 2020 周琰杰 (Zhou Yanjie) <zhouyanjie@wanyeetech.com>
  */
 
 #include <linux/clk-provider.h>
 
 /* CGU register offsets */
 #define CGU_REG_CLOCKCONTROL   0x00
-#define CGU_REG_LCR                    0x04
-#define CGU_REG_APLL           0x10
-#define CGU_REG_MPLL           0x14
-#define CGU_REG_EPLL           0x18
-#define CGU_REG_VPLL           0x1c
-#define CGU_REG_CLKGR0         0x20
-#define CGU_REG_OPCR           0x24
-#define CGU_REG_CLKGR1         0x28
-#define CGU_REG_DDRCDR         0x2c
-#define CGU_REG_VPUCDR         0x30
-#define CGU_REG_USBPCR         0x3c
-#define CGU_REG_USBRDT         0x40
-#define CGU_REG_USBVBFIL       0x44
-#define CGU_REG_USBPCR1                0x48
-#define CGU_REG_LP0CDR         0x54
-#define CGU_REG_I2SCDR         0x60
-#define CGU_REG_LP1CDR         0x64
-#define CGU_REG_MSC0CDR                0x68
-#define CGU_REG_UHCCDR         0x6c
-#define CGU_REG_SSICDR         0x74
-#define CGU_REG_CIMCDR         0x7c
-#define CGU_REG_PCMCDR         0x84
-#define CGU_REG_GPUCDR         0x88
-#define CGU_REG_HDMICDR                0x8c
-#define CGU_REG_MSC1CDR                0xa4
-#define CGU_REG_MSC2CDR                0xa8
-#define CGU_REG_BCHCDR         0xac
-#define CGU_REG_CLOCKSTATUS    0xd4
+#define CGU_REG_LCR                            0x04
+#define CGU_REG_APLL                   0x10
+#define CGU_REG_MPLL                   0x14
+#define CGU_REG_EPLL                   0x18
+#define CGU_REG_VPLL                   0x1c
+#define CGU_REG_CLKGR0                 0x20
+#define CGU_REG_OPCR                   0x24
+#define CGU_REG_CLKGR1                 0x28
+#define CGU_REG_DDRCDR                 0x2c
+#define CGU_REG_VPUCDR                 0x30
+#define CGU_REG_USBPCR                 0x3c
+#define CGU_REG_USBRDT                 0x40
+#define CGU_REG_USBVBFIL               0x44
+#define CGU_REG_USBPCR1                        0x48
+#define CGU_REG_LP0CDR                 0x54
+#define CGU_REG_I2SCDR                 0x60
+#define CGU_REG_LP1CDR                 0x64
+#define CGU_REG_MSC0CDR                        0x68
+#define CGU_REG_UHCCDR                 0x6c
+#define CGU_REG_SSICDR                 0x74
+#define CGU_REG_CIMCDR                 0x7c
+#define CGU_REG_PCMCDR                 0x84
+#define CGU_REG_GPUCDR                 0x88
+#define CGU_REG_HDMICDR                        0x8c
+#define CGU_REG_MSC1CDR                        0xa4
+#define CGU_REG_MSC2CDR                        0xa8
+#define CGU_REG_BCHCDR                 0xac
+#define CGU_REG_CLOCKSTATUS            0xd4
 
 /* bits within the OPCR register */
-#define OPCR_SPENDN0           BIT(7)
-#define OPCR_SPENDN1           BIT(6)
+#define OPCR_SPENDN0                   BIT(7)
+#define OPCR_SPENDN1                   BIT(6)
 
 /* bits within the USBPCR register */
-#define USBPCR_USB_MODE                BIT(31)
+#define USBPCR_USB_MODE                        BIT(31)
 #define USBPCR_IDPULLUP_MASK   (0x3 << 28)
-#define USBPCR_COMMONONN       BIT(25)
-#define USBPCR_VBUSVLDEXT      BIT(24)
+#define USBPCR_COMMONONN               BIT(25)
+#define USBPCR_VBUSVLDEXT              BIT(24)
 #define USBPCR_VBUSVLDEXTSEL   BIT(23)
-#define USBPCR_POR             BIT(22)
-#define USBPCR_OTG_DISABLE     BIT(20)
+#define USBPCR_POR                             BIT(22)
+#define USBPCR_SIDDQ                   BIT(21)
+#define USBPCR_OTG_DISABLE             BIT(20)
 #define USBPCR_COMPDISTUNE_MASK        (0x7 << 17)
-#define USBPCR_OTGTUNE_MASK    (0x7 << 14)
+#define USBPCR_OTGTUNE_MASK            (0x7 << 14)
 #define USBPCR_SQRXTUNE_MASK   (0x7 << 11)
 #define USBPCR_TXFSLSTUNE_MASK (0xf << 7)
 #define USBPCR_TXPREEMPHTUNE   BIT(6)
 #define USBPCR1_REFCLKDIV_48   (0x2 << USBPCR1_REFCLKDIV_SHIFT)
 #define USBPCR1_REFCLKDIV_24   (0x1 << USBPCR1_REFCLKDIV_SHIFT)
 #define USBPCR1_REFCLKDIV_12   (0x0 << USBPCR1_REFCLKDIV_SHIFT)
-#define USBPCR1_USB_SEL                BIT(28)
-#define USBPCR1_WORD_IF0       BIT(19)
-#define USBPCR1_WORD_IF1       BIT(18)
+#define USBPCR1_USB_SEL                        BIT(28)
+#define USBPCR1_WORD_IF0               BIT(19)
+#define USBPCR1_WORD_IF1               BIT(18)
 
 /* bits within the USBRDT register */
-#define USBRDT_VBFIL_LD_EN     BIT(25)
-#define USBRDT_USBRDT_MASK     0x7fffff
+#define USBRDT_VBFIL_LD_EN             BIT(25)
+#define USBRDT_USBRDT_MASK             0x7fffff
 
 /* bits within the USBVBFIL register */
 #define USBVBFIL_IDDIGFIL_SHIFT        16
 #define USBVBFIL_USBVBFIL_MASK (0xffff)
 
 /* bits within the LCR register */
-#define LCR_PD_SCPU                    BIT(31)
-#define LCR_SCPUS                      BIT(27)
+#define LCR_PD_SCPU                            BIT(31)
+#define LCR_SCPUS                              BIT(27)
 
 /* bits within the CLKGR1 register */
-#define CLKGR1_CORE1           BIT(15)
+#define CLKGR1_CORE1                   BIT(15)
 
 static struct ingenic_cgu *cgu;
 
-static u8 jz4780_otg_phy_get_parent(struct clk_hw *hw)
-{
-       /* we only use CLKCORE, revisit if that ever changes */
-       return 0;
-}
-
-static int jz4780_otg_phy_set_parent(struct clk_hw *hw, u8 idx)
-{
-       unsigned long flags;
-       u32 usbpcr1;
-
-       if (idx > 0)
-               return -EINVAL;
-
-       spin_lock_irqsave(&cgu->lock, flags);
-
-       usbpcr1 = readl(cgu->base + CGU_REG_USBPCR1);
-       usbpcr1 &= ~USBPCR1_REFCLKSEL_MASK;
-       /* we only use CLKCORE */
-       usbpcr1 |= USBPCR1_REFCLKSEL_CORE;
-       writel(usbpcr1, cgu->base + CGU_REG_USBPCR1);
-
-       spin_unlock_irqrestore(&cgu->lock, flags);
-       return 0;
-}
-
 static unsigned long jz4780_otg_phy_recalc_rate(struct clk_hw *hw,
                                                unsigned long parent_rate)
 {
@@ -149,7 +125,6 @@ static unsigned long jz4780_otg_phy_recalc_rate(struct clk_hw *hw,
                return 19200000;
        }
 
-       BUG();
        return parent_rate;
 }
 
@@ -206,13 +181,43 @@ static int jz4780_otg_phy_set_rate(struct clk_hw *hw, unsigned long req_rate,
        return 0;
 }
 
-static const struct clk_ops jz4780_otg_phy_ops = {
-       .get_parent = jz4780_otg_phy_get_parent,
-       .set_parent = jz4780_otg_phy_set_parent,
+static int jz4780_otg_phy_enable(struct clk_hw *hw)
+{
+       void __iomem *reg_opcr          = cgu->base + CGU_REG_OPCR;
+       void __iomem *reg_usbpcr        = cgu->base + CGU_REG_USBPCR;
+
+       writel(readl(reg_opcr) | OPCR_SPENDN0, reg_opcr);
+       writel(readl(reg_usbpcr) & ~USBPCR_OTG_DISABLE & ~USBPCR_SIDDQ, reg_usbpcr);
+       return 0;
+}
 
+static void jz4780_otg_phy_disable(struct clk_hw *hw)
+{
+       void __iomem *reg_opcr          = cgu->base + CGU_REG_OPCR;
+       void __iomem *reg_usbpcr        = cgu->base + CGU_REG_USBPCR;
+
+       writel(readl(reg_opcr) & ~OPCR_SPENDN0, reg_opcr);
+       writel(readl(reg_usbpcr) | USBPCR_OTG_DISABLE | USBPCR_SIDDQ, reg_usbpcr);
+}
+
+static int jz4780_otg_phy_is_enabled(struct clk_hw *hw)
+{
+       void __iomem *reg_opcr          = cgu->base + CGU_REG_OPCR;
+       void __iomem *reg_usbpcr        = cgu->base + CGU_REG_USBPCR;
+
+       return (readl(reg_opcr) & OPCR_SPENDN0) &&
+               !(readl(reg_usbpcr) & USBPCR_SIDDQ) &&
+               !(readl(reg_usbpcr) & USBPCR_OTG_DISABLE);
+}
+
+static const struct clk_ops jz4780_otg_phy_ops = {
        .recalc_rate = jz4780_otg_phy_recalc_rate,
        .round_rate = jz4780_otg_phy_round_rate,
        .set_rate = jz4780_otg_phy_set_rate,
+
+       .enable         = jz4780_otg_phy_enable,
+       .disable        = jz4780_otg_phy_disable,
+       .is_enabled     = jz4780_otg_phy_is_enabled,
 };
 
 static int jz4780_core1_enable(struct clk_hw *hw)
@@ -516,6 +521,18 @@ static const struct ingenic_cgu_clk_info jz4780_cgu_clocks[] = {
                .gate = { CGU_REG_CLKGR0, 1 },
        },
 
+       [JZ4780_CLK_EXCLK_DIV512] = {
+               "exclk_div512", CGU_CLK_FIXDIV,
+               .parents = { JZ4780_CLK_EXCLK },
+               .fixdiv = { 512 },
+       },
+
+       [JZ4780_CLK_RTC] = {
+               "rtc_ercs", CGU_CLK_MUX | CGU_CLK_GATE,
+               .parents = { JZ4780_CLK_EXCLK_DIV512, JZ4780_CLK_RTCLK },
+               .mux = { CGU_REG_OPCR, 2, 1},
+       },
+
        /* Gate-only clocks */
 
        [JZ4780_CLK_NEMC] = {
index 453f3323cb99d4b8d475f566dc7e0ca58b06a05f..9aa20b52e1c320d758660d05dff68eefe7d4447f 100644 (file)
 #define USBPCR_SIDDQ           BIT(21)
 #define USBPCR_OTG_DISABLE     BIT(20)
 
+/* bits within the USBPCR1 register */
+#define USBPCR1_REFCLKSEL_SHIFT        26
+#define USBPCR1_REFCLKSEL_MASK (0x3 << USBPCR1_REFCLKSEL_SHIFT)
+#define USBPCR1_REFCLKSEL_CORE (0x2 << USBPCR1_REFCLKSEL_SHIFT)
+#define USBPCR1_REFCLKDIV_SHIFT        24
+#define USBPCR1_REFCLKDIV_MASK (0x3 << USBPCR1_REFCLKDIV_SHIFT)
+#define USBPCR1_REFCLKDIV_48   (0x2 << USBPCR1_REFCLKDIV_SHIFT)
+#define USBPCR1_REFCLKDIV_24   (0x1 << USBPCR1_REFCLKDIV_SHIFT)
+#define USBPCR1_REFCLKDIV_12   (0x0 << USBPCR1_REFCLKDIV_SHIFT)
+
 static struct ingenic_cgu *cgu;
 
+static unsigned long x1000_otg_phy_recalc_rate(struct clk_hw *hw,
+                                               unsigned long parent_rate)
+{
+       u32 usbpcr1;
+       unsigned refclk_div;
+
+       usbpcr1 = readl(cgu->base + CGU_REG_USBPCR1);
+       refclk_div = usbpcr1 & USBPCR1_REFCLKDIV_MASK;
+
+       switch (refclk_div) {
+       case USBPCR1_REFCLKDIV_12:
+               return 12000000;
+
+       case USBPCR1_REFCLKDIV_24:
+               return 24000000;
+
+       case USBPCR1_REFCLKDIV_48:
+               return 48000000;
+       }
+
+       return parent_rate;
+}
+
+static long x1000_otg_phy_round_rate(struct clk_hw *hw, unsigned long req_rate,
+                                     unsigned long *parent_rate)
+{
+       if (req_rate < 18000000)
+               return 12000000;
+
+       if (req_rate < 36000000)
+               return 24000000;
+
+       return 48000000;
+}
+
+static int x1000_otg_phy_set_rate(struct clk_hw *hw, unsigned long req_rate,
+                                  unsigned long parent_rate)
+{
+       unsigned long flags;
+       u32 usbpcr1, div_bits;
+
+       switch (req_rate) {
+       case 12000000:
+               div_bits = USBPCR1_REFCLKDIV_12;
+               break;
+
+       case 24000000:
+               div_bits = USBPCR1_REFCLKDIV_24;
+               break;
+
+       case 48000000:
+               div_bits = USBPCR1_REFCLKDIV_48;
+               break;
+
+       default:
+               return -EINVAL;
+       }
+
+       spin_lock_irqsave(&cgu->lock, flags);
+
+       usbpcr1 = readl(cgu->base + CGU_REG_USBPCR1);
+       usbpcr1 &= ~USBPCR1_REFCLKDIV_MASK;
+       usbpcr1 |= div_bits;
+       writel(usbpcr1, cgu->base + CGU_REG_USBPCR1);
+
+       spin_unlock_irqrestore(&cgu->lock, flags);
+       return 0;
+}
+
 static int x1000_usb_phy_enable(struct clk_hw *hw)
 {
        void __iomem *reg_opcr          = cgu->base + CGU_REG_OPCR;
@@ -80,6 +159,10 @@ static int x1000_usb_phy_is_enabled(struct clk_hw *hw)
 }
 
 static const struct clk_ops x1000_otg_phy_ops = {
+       .recalc_rate = x1000_otg_phy_recalc_rate,
+       .round_rate = x1000_otg_phy_round_rate,
+       .set_rate = x1000_otg_phy_set_rate,
+
        .enable         = x1000_usb_phy_enable,
        .disable        = x1000_usb_phy_disable,
        .is_enabled     = x1000_usb_phy_is_enabled,
@@ -144,7 +227,6 @@ static const struct ingenic_cgu_clk_info x1000_cgu_clocks[] = {
                },
        },
 
-
        /* Custom (SoC-specific) OTG PHY */
 
        [X1000_CLK_OTGPHY] = {
@@ -278,6 +360,19 @@ static const struct ingenic_cgu_clk_info x1000_cgu_clocks[] = {
                .mux = { CGU_REG_SSICDR, 30, 1 },
        },
 
+       [X1000_CLK_EXCLK_DIV512] = {
+               "exclk_div512", CGU_CLK_FIXDIV,
+               .parents = { X1000_CLK_EXCLK },
+               .fixdiv = { 512 },
+       },
+
+       [X1000_CLK_RTC] = {
+               "rtc_ercs", CGU_CLK_MUX | CGU_CLK_GATE,
+               .parents = { X1000_CLK_EXCLK_DIV512, X1000_CLK_RTCLK },
+               .mux = { CGU_REG_OPCR, 2, 1},
+               .gate = { CGU_REG_CLKGR, 27 },
+       },
+
        /* Gate-only clocks */
 
        [X1000_CLK_EMC] = {
index a1b2ff0ee48783130cc4efef197e9877c181d297..950aee243364edf193c5e4d152a943c7705cf55e 100644 (file)
@@ -329,6 +329,19 @@ static const struct ingenic_cgu_clk_info x1830_cgu_clocks[] = {
                .mux = { CGU_REG_SSICDR, 29, 1 },
        },
 
+       [X1830_CLK_EXCLK_DIV512] = {
+               "exclk_div512", CGU_CLK_FIXDIV,
+               .parents = { X1830_CLK_EXCLK },
+               .fixdiv = { 512 },
+       },
+
+       [X1830_CLK_RTC] = {
+               "rtc_ercs", CGU_CLK_MUX | CGU_CLK_GATE,
+               .parents = { X1830_CLK_EXCLK_DIV512, X1830_CLK_RTCLK },
+               .mux = { CGU_REG_OPCR, 2, 1},
+               .gate = { CGU_REG_CLKGR0, 29 },
+       },
+
        /* Gate-only clocks */
 
        [X1830_CLK_EMC] = {
index 8e2551ab846251ce4bdd0b4e13fc70e832db4782..b351039cac095fc8299ea3f18628468d97367214 100644 (file)
@@ -10,6 +10,7 @@
  */
 
 #include <linux/clk.h>
+#include <linux/clk/mmp.h>
 #include <linux/module.h>
 #include <linux/kernel.h>
 #include <linux/spinlock.h>
index 7a79651419183dfa044bcd8ccfd69d87953ce810..f254ceff3ea7c11fbf651d6c053e52dcccf1b255 100644 (file)
@@ -10,6 +10,7 @@
  */
 
 #include <linux/clk.h>
+#include <linux/clk/mmp.h>
 #include <linux/module.h>
 #include <linux/kernel.h>
 #include <linux/spinlock.h>
index 318c0adfaae11a83ad892ddb660336a27210d43e..058327310c25511bd0343e7883c082af830d6b3e 100644 (file)
@@ -308,6 +308,15 @@ config SC_GCC_7180
          Say Y if you want to use peripheral devices such as UART, SPI,
          I2C, USB, UFS, SDCC, etc.
 
+config SC_LPASS_CORECC_7180
+       tristate "SC7180 LPASS Core Clock Controller"
+       select SC_GCC_7180
+       help
+         Support for the LPASS(Low Power Audio Subsystem) core clock controller
+         on SC7180 devices.
+         Say Y if you want to use LPASS clocks and power domains of the LPASS
+         core clock controller.
+
 config SC_GPUCC_7180
        tristate "SC7180 Graphics Clock Controller"
        select SC_GCC_7180
@@ -419,6 +428,22 @@ config SM_GCC_8250
          Say Y if you want to use peripheral devices such as UART,
          SPI, I2C, USB, SD/UFS, PCIe etc.
 
+config SM_GPUCC_8150
+       tristate "SM8150 Graphics Clock Controller"
+       select SM_GCC_8150
+       help
+         Support for the graphics clock controller on SM8150 devices.
+         Say Y if you want to support graphics controller devices and
+         functionality such as 3D graphics.
+
+config SM_GPUCC_8250
+       tristate "SM8250 Graphics Clock Controller"
+       select SM_GCC_8250
+       help
+         Support for the graphics clock controller on SM8250 devices.
+         Say Y if you want to support graphics controller devices and
+         functionality such as 3D graphics.
+
 config SPMI_PMIC_CLKDIV
        tristate "SPMI PMIC clkdiv Support"
        depends on SPMI || COMPILE_TEST
index ae0979bebe1882e14b6fd324a9cfd84bd2cdd379..9677e769e7e956d2cfad700fdf4e50bd0ef78521 100644 (file)
@@ -54,6 +54,7 @@ obj-$(CONFIG_QCS_TURING_404) += turingcc-qcs404.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
+obj-$(CONFIG_SC_LPASS_CORECC_7180) += lpasscorecc-sc7180.o
 obj-$(CONFIG_SC_MSS_7180) += mss-sc7180.o
 obj-$(CONFIG_SC_VIDEOCC_7180) += videocc-sc7180.o
 obj-$(CONFIG_SDM_CAMCC_845) += camcc-sdm845.o
@@ -65,6 +66,8 @@ obj-$(CONFIG_SDM_LPASSCC_845) += lpasscc-sdm845.o
 obj-$(CONFIG_SDM_VIDEOCC_845) += videocc-sdm845.o
 obj-$(CONFIG_SM_GCC_8150) += gcc-sm8150.o
 obj-$(CONFIG_SM_GCC_8250) += gcc-sm8250.o
+obj-$(CONFIG_SM_GPUCC_8150) += gpucc-sm8150.o
+obj-$(CONFIG_SM_GPUCC_8250) += gpucc-sm8250.o
 obj-$(CONFIG_SPMI_PMIC_CLKDIV) += clk-spmi-pmic-div.o
 obj-$(CONFIG_KPSS_XCC) += kpss-xcc.o
 obj-$(CONFIG_QCOM_HFPLL) += hfpll.o
index 9b2dfa08acb2a4b6d81e8c1e2471c84b7e23cd65..26139ef005e48dd5af4e06598fbd21834c01456e 100644 (file)
@@ -56,7 +56,6 @@
 #define PLL_STATUS(p)          ((p)->offset + (p)->regs[PLL_OFF_STATUS])
 #define PLL_OPMODE(p)          ((p)->offset + (p)->regs[PLL_OFF_OPMODE])
 #define PLL_FRAC(p)            ((p)->offset + (p)->regs[PLL_OFF_FRAC])
-#define PLL_CAL_VAL(p)         ((p)->offset + (p)->regs[PLL_OFF_CAL_VAL])
 
 const u8 clk_alpha_pll_regs[][PLL_OFF_MAX_REGS] = {
        [CLK_ALPHA_PLL_TYPE_DEFAULT] =  {
@@ -102,22 +101,6 @@ const u8 clk_alpha_pll_regs[][PLL_OFF_MAX_REGS] = {
                [PLL_OFF_FRAC] = 0x38,
        },
        [CLK_ALPHA_PLL_TYPE_TRION] = {
-               [PLL_OFF_L_VAL] = 0x04,
-               [PLL_OFF_CAL_L_VAL] = 0x08,
-               [PLL_OFF_USER_CTL] = 0x0c,
-               [PLL_OFF_USER_CTL_U] = 0x10,
-               [PLL_OFF_USER_CTL_U1] = 0x14,
-               [PLL_OFF_CONFIG_CTL] = 0x18,
-               [PLL_OFF_CONFIG_CTL_U] = 0x1c,
-               [PLL_OFF_CONFIG_CTL_U1] = 0x20,
-               [PLL_OFF_TEST_CTL] = 0x24,
-               [PLL_OFF_TEST_CTL_U] = 0x28,
-               [PLL_OFF_STATUS] = 0x30,
-               [PLL_OFF_OPMODE] = 0x38,
-               [PLL_OFF_ALPHA_VAL] = 0x40,
-               [PLL_OFF_CAL_VAL] = 0x44,
-       },
-       [CLK_ALPHA_PLL_TYPE_LUCID] =  {
                [PLL_OFF_L_VAL] = 0x04,
                [PLL_OFF_CAL_L_VAL] = 0x08,
                [PLL_OFF_USER_CTL] = 0x0c,
@@ -156,9 +139,12 @@ EXPORT_SYMBOL_GPL(clk_alpha_pll_regs);
 #define PLL_OUT_MASK           0x7
 #define PLL_RATE_MARGIN                500
 
+/* TRION PLL specific settings and offsets */
+#define TRION_PLL_CAL_VAL      0x44
+#define TRION_PCAL_DONE                BIT(26)
+
 /* LUCID PLL specific settings and offsets */
-#define LUCID_PLL_CAL_VAL      0x44
-#define LUCID_PCAL_DONE                BIT(26)
+#define LUCID_PCAL_DONE                BIT(27)
 
 #define pll_alpha_width(p)                                     \
                ((PLL_ALPHA_VAL_U(p) - PLL_ALPHA_VAL(p) == 4) ? \
@@ -912,14 +898,14 @@ const struct clk_ops clk_alpha_pll_hwfsm_ops = {
 };
 EXPORT_SYMBOL_GPL(clk_alpha_pll_hwfsm_ops);
 
-const struct clk_ops clk_trion_fixed_pll_ops = {
+const struct clk_ops clk_alpha_pll_fixed_trion_ops = {
        .enable = clk_trion_pll_enable,
        .disable = clk_trion_pll_disable,
        .is_enabled = clk_trion_pll_is_enabled,
        .recalc_rate = clk_trion_pll_recalc_rate,
        .round_rate = clk_alpha_pll_round_rate,
 };
-EXPORT_SYMBOL_GPL(clk_trion_fixed_pll_ops);
+EXPORT_SYMBOL_GPL(clk_alpha_pll_fixed_trion_ops);
 
 static unsigned long
 clk_alpha_pll_postdiv_recalc_rate(struct clk_hw *hw, unsigned long parent_rate)
@@ -1339,12 +1325,12 @@ clk_trion_pll_postdiv_set_rate(struct clk_hw *hw, unsigned long rate,
                                  val << PLL_POST_DIV_SHIFT);
 }
 
-const struct clk_ops clk_trion_pll_postdiv_ops = {
+const struct clk_ops clk_alpha_pll_postdiv_trion_ops = {
        .recalc_rate = clk_trion_pll_postdiv_recalc_rate,
        .round_rate = clk_trion_pll_postdiv_round_rate,
        .set_rate = clk_trion_pll_postdiv_set_rate,
 };
-EXPORT_SYMBOL_GPL(clk_trion_pll_postdiv_ops);
+EXPORT_SYMBOL_GPL(clk_alpha_pll_postdiv_trion_ops);
 
 static long clk_alpha_pll_postdiv_fabia_round_rate(struct clk_hw *hw,
                                unsigned long rate, unsigned long *prate)
@@ -1399,13 +1385,13 @@ EXPORT_SYMBOL_GPL(clk_alpha_pll_postdiv_fabia_ops);
  * @regmap: register map
  * @config: configuration to apply for pll
  */
-void clk_lucid_pll_configure(struct clk_alpha_pll *pll, struct regmap *regmap,
+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);
 
-       regmap_write(regmap, PLL_CAL_L_VAL(pll), LUCID_PLL_CAL_VAL);
+       regmap_write(regmap, PLL_CAL_L_VAL(pll), TRION_PLL_CAL_VAL);
 
        if (config->alpha)
                regmap_write(regmap, PLL_ALPHA_VAL(pll), config->alpha);
@@ -1458,13 +1444,13 @@ void clk_lucid_pll_configure(struct clk_alpha_pll *pll, struct regmap *regmap,
        /* Place the PLL in STANDBY mode */
        regmap_update_bits(regmap, PLL_MODE(pll), PLL_RESET_N, PLL_RESET_N);
 }
-EXPORT_SYMBOL_GPL(clk_lucid_pll_configure);
+EXPORT_SYMBOL_GPL(clk_trion_pll_configure);
 
 /*
- * The Lucid PLL requires a power-on self-calibration which happens when the
+ * The TRION PLL requires a power-on self-calibration which happens when the
  * PLL comes out of reset. Calibrate in case it is not completed.
  */
-static int alpha_pll_lucid_prepare(struct clk_hw *hw)
+static int __alpha_pll_trion_prepare(struct clk_hw *hw, u32 pcal_done)
 {
        struct clk_alpha_pll *pll = to_clk_alpha_pll(hw);
        u32 regval;
@@ -1472,7 +1458,7 @@ static int alpha_pll_lucid_prepare(struct clk_hw *hw)
 
        /* Return early if calibration is not needed. */
        regmap_read(pll->clkr.regmap, PLL_STATUS(pll), &regval);
-       if (regval & LUCID_PCAL_DONE)
+       if (regval & pcal_done)
                return 0;
 
        /* On/off to calibrate */
@@ -1483,7 +1469,17 @@ static int alpha_pll_lucid_prepare(struct clk_hw *hw)
        return ret;
 }
 
-static int alpha_pll_lucid_set_rate(struct clk_hw *hw, unsigned long rate,
+static int alpha_pll_trion_prepare(struct clk_hw *hw)
+{
+       return __alpha_pll_trion_prepare(hw, TRION_PCAL_DONE);
+}
+
+static int alpha_pll_lucid_prepare(struct clk_hw *hw)
+{
+       return __alpha_pll_trion_prepare(hw, LUCID_PCAL_DONE);
+}
+
+static int alpha_pll_trion_set_rate(struct clk_hw *hw, unsigned long rate,
                                    unsigned long prate)
 {
        struct clk_alpha_pll *pll = to_clk_alpha_pll(hw);
@@ -1537,25 +1533,27 @@ static int alpha_pll_lucid_set_rate(struct clk_hw *hw, unsigned long rate,
        return 0;
 }
 
-const struct clk_ops clk_alpha_pll_lucid_ops = {
-       .prepare = alpha_pll_lucid_prepare,
+const struct clk_ops clk_alpha_pll_trion_ops = {
+       .prepare = alpha_pll_trion_prepare,
        .enable = clk_trion_pll_enable,
        .disable = clk_trion_pll_disable,
        .is_enabled = clk_trion_pll_is_enabled,
        .recalc_rate = clk_trion_pll_recalc_rate,
        .round_rate = clk_alpha_pll_round_rate,
-       .set_rate = alpha_pll_lucid_set_rate,
+       .set_rate = alpha_pll_trion_set_rate,
 };
-EXPORT_SYMBOL_GPL(clk_alpha_pll_lucid_ops);
+EXPORT_SYMBOL_GPL(clk_alpha_pll_trion_ops);
 
-const struct clk_ops clk_alpha_pll_fixed_lucid_ops = {
+const struct clk_ops clk_alpha_pll_lucid_ops = {
+       .prepare = alpha_pll_lucid_prepare,
        .enable = clk_trion_pll_enable,
        .disable = clk_trion_pll_disable,
        .is_enabled = clk_trion_pll_is_enabled,
        .recalc_rate = clk_trion_pll_recalc_rate,
        .round_rate = clk_alpha_pll_round_rate,
+       .set_rate = alpha_pll_trion_set_rate,
 };
-EXPORT_SYMBOL_GPL(clk_alpha_pll_fixed_lucid_ops);
+EXPORT_SYMBOL_GPL(clk_alpha_pll_lucid_ops);
 
 const struct clk_ops clk_alpha_pll_postdiv_lucid_ops = {
        .recalc_rate = clk_alpha_pll_postdiv_fabia_recalc_rate,
index 1ba82be93dd54884e764d753f5a9f37f3e5f325d..d3201b87c0cd4f744c1011a7989342e1b2fc9082 100644 (file)
@@ -14,7 +14,7 @@ enum {
        CLK_ALPHA_PLL_TYPE_BRAMMO,
        CLK_ALPHA_PLL_TYPE_FABIA,
        CLK_ALPHA_PLL_TYPE_TRION,
-       CLK_ALPHA_PLL_TYPE_LUCID,
+       CLK_ALPHA_PLL_TYPE_LUCID = CLK_ALPHA_PLL_TYPE_TRION,
        CLK_ALPHA_PLL_TYPE_MAX,
 };
 
@@ -134,18 +134,23 @@ extern const struct clk_ops clk_alpha_pll_fabia_ops;
 extern const struct clk_ops clk_alpha_pll_fixed_fabia_ops;
 extern const struct clk_ops clk_alpha_pll_postdiv_fabia_ops;
 
+extern const struct clk_ops clk_alpha_pll_trion_ops;
+extern const struct clk_ops clk_alpha_pll_fixed_trion_ops;
+extern const struct clk_ops clk_alpha_pll_postdiv_trion_ops;
+
 extern const struct clk_ops clk_alpha_pll_lucid_ops;
-extern const struct clk_ops clk_alpha_pll_fixed_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;
 
 void clk_alpha_pll_configure(struct clk_alpha_pll *pll, struct regmap *regmap,
                             const struct alpha_pll_config *config);
 void clk_fabia_pll_configure(struct clk_alpha_pll *pll, struct regmap *regmap,
                                const struct alpha_pll_config *config);
-void clk_lucid_pll_configure(struct clk_alpha_pll *pll, struct regmap *regmap,
+void clk_trion_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)
+
 
-extern const struct clk_ops clk_trion_fixed_pll_ops;
-extern const struct clk_ops clk_trion_pll_postdiv_ops;
 
 #endif
index 538677befb86f96dae10da32a65ec2218acb919f..68d8f7aaf64e1f0133400f727fac947ecb24ee30 100644 (file)
@@ -2251,6 +2251,19 @@ static struct clk_branch gcc_mss_q6_memnoc_axi_clk = {
        },
 };
 
+static struct clk_branch gcc_lpass_cfg_noc_sway_clk = {
+       .halt_reg = 0x47018,
+       .halt_check = BRANCH_HALT_DELAY,
+       .clkr = {
+               .enable_reg = 0x47018,
+               .enable_mask = BIT(0),
+               .hw.init = &(struct clk_init_data){
+                       .name = "gcc_lpass_cfg_noc_sway_clk",
+                       .ops = &clk_branch2_ops,
+               },
+       },
+};
+
 static struct gdsc ufs_phy_gdsc = {
        .gdscr = 0x77004,
        .pd = {
@@ -2428,6 +2441,7 @@ static struct clk_regmap *gcc_sc7180_clocks[] = {
        [GCC_MSS_Q6_MEMNOC_AXI_CLK] = &gcc_mss_q6_memnoc_axi_clk.clkr,
        [GCC_MSS_SNOC_AXI_CLK] = &gcc_mss_snoc_axi_clk.clkr,
        [GCC_SEC_CTRL_CLK_SRC] = &gcc_sec_ctrl_clk_src.clkr,
+       [GCC_LPASS_CFG_NOC_SWAY_CLK] = &gcc_lpass_cfg_noc_sway_clk.clkr,
 };
 
 static const struct qcom_reset_map gcc_sc7180_resets[] = {
index bf5730832ef3dea56fd1401a26fc9cb805041095..f0b47b7d50ca6af81c8cebd6207bab9ef59f78de 100644 (file)
@@ -1715,6 +1715,9 @@ static struct clk_branch gcc_mss_cfg_ahb_clk = {
 
 static struct clk_branch gcc_mss_mnoc_bimc_axi_clk = {
        .halt_reg = 0x8a004,
+       .halt_check = BRANCH_HALT,
+       .hwcg_reg = 0x8a004,
+       .hwcg_bit = 1,
        .clkr = {
                .enable_reg = 0x8a004,
                .enable_mask = BIT(0),
@@ -2402,6 +2405,7 @@ static const struct qcom_reset_map gcc_sdm660_resets[] = {
        [GCC_USB_20_BCR] = { 0x2f000 },
        [GCC_USB_30_BCR] = { 0xf000 },
        [GCC_USB_PHY_CFG_AHB2PHY_BCR] = { 0x6a000 },
+       [GCC_MSS_RESTART] = { 0x79000 },
 };
 
 static const struct regmap_config gcc_sdm660_regmap_config = {
index 72524cf11048744ba941a2cc19a9099c93a04f3c..8e9b5b3cceaf7590a879e94f7be7d92098ee4e69 100644 (file)
@@ -34,14 +34,8 @@ enum {
        P_SLEEP_CLK,
 };
 
-static const struct pll_vco trion_vco[] = {
-       { 249600000, 2000000000, 0 },
-};
-
 static struct clk_alpha_pll gpll0 = {
        .offset = 0x0,
-       .vco_table = trion_vco,
-       .num_vco = ARRAY_SIZE(trion_vco),
        .regs = clk_alpha_pll_regs[CLK_ALPHA_PLL_TYPE_TRION],
        .clkr = {
                .enable_reg = 0x52000,
@@ -53,7 +47,7 @@ static struct clk_alpha_pll gpll0 = {
                                .name = "bi_tcxo",
                        },
                        .num_parents = 1,
-                       .ops = &clk_trion_fixed_pll_ops,
+                       .ops = &clk_alpha_pll_fixed_trion_ops,
                },
        },
 };
@@ -79,14 +73,12 @@ static struct clk_alpha_pll_postdiv gpll0_out_even = {
                        .hw = &gpll0.clkr.hw,
                },
                .num_parents = 1,
-               .ops = &clk_trion_pll_postdiv_ops,
+               .ops = &clk_alpha_pll_postdiv_trion_ops,
        },
 };
 
 static struct clk_alpha_pll gpll7 = {
        .offset = 0x1a000,
-       .vco_table = trion_vco,
-       .num_vco = ARRAY_SIZE(trion_vco),
        .regs = clk_alpha_pll_regs[CLK_ALPHA_PLL_TYPE_TRION],
        .clkr = {
                .enable_reg = 0x52000,
@@ -98,15 +90,13 @@ static struct clk_alpha_pll gpll7 = {
                                .name = "bi_tcxo",
                        },
                        .num_parents = 1,
-                       .ops = &clk_trion_fixed_pll_ops,
+                       .ops = &clk_alpha_pll_fixed_trion_ops,
                },
        },
 };
 
 static struct clk_alpha_pll gpll9 = {
        .offset = 0x1c000,
-       .vco_table = trion_vco,
-       .num_vco = ARRAY_SIZE(trion_vco),
        .regs = clk_alpha_pll_regs[CLK_ALPHA_PLL_TYPE_TRION],
        .clkr = {
                .enable_reg = 0x52000,
@@ -118,7 +108,7 @@ static struct clk_alpha_pll gpll9 = {
                                .name = "bi_tcxo",
                        },
                        .num_parents = 1,
-                       .ops = &clk_trion_fixed_pll_ops,
+                       .ops = &clk_alpha_pll_fixed_trion_ops,
                },
        },
 };
@@ -1617,6 +1607,7 @@ static struct clk_branch gcc_gpu_cfg_ahb_clk = {
 };
 
 static struct clk_branch gcc_gpu_gpll0_clk_src = {
+       .halt_check = BRANCH_HALT_SKIP,
        .clkr = {
                .enable_reg = 0x52004,
                .enable_mask = BIT(15),
@@ -1632,13 +1623,14 @@ static struct clk_branch gcc_gpu_gpll0_clk_src = {
 };
 
 static struct clk_branch gcc_gpu_gpll0_div_clk_src = {
+       .halt_check = BRANCH_HALT_SKIP,
        .clkr = {
                .enable_reg = 0x52004,
                .enable_mask = BIT(16),
                .hw.init = &(struct clk_init_data){
                        .name = "gcc_gpu_gpll0_div_clk_src",
                        .parent_hws = (const struct clk_hw *[]){
-                               &gcc_gpu_gpll0_clk_src.clkr.hw },
+                               &gpll0_out_even.clkr.hw },
                        .num_parents = 1,
                        .flags = CLK_SET_RATE_PARENT,
                        .ops = &clk_branch2_ops,
@@ -1729,6 +1721,7 @@ static struct clk_branch gcc_npu_cfg_ahb_clk = {
 };
 
 static struct clk_branch gcc_npu_gpll0_clk_src = {
+       .halt_check = BRANCH_HALT_SKIP,
        .clkr = {
                .enable_reg = 0x52004,
                .enable_mask = BIT(18),
@@ -1744,13 +1737,14 @@ static struct clk_branch gcc_npu_gpll0_clk_src = {
 };
 
 static struct clk_branch gcc_npu_gpll0_div_clk_src = {
+       .halt_check = BRANCH_HALT_SKIP,
        .clkr = {
                .enable_reg = 0x52004,
                .enable_mask = BIT(19),
                .hw.init = &(struct clk_init_data){
                        .name = "gcc_npu_gpll0_div_clk_src",
                        .parent_hws = (const struct clk_hw *[]){
-                               &gcc_npu_gpll0_clk_src.clkr.hw },
+                               &gpll0_out_even.clkr.hw },
                        .num_parents = 1,
                        .flags = CLK_SET_RATE_PARENT,
                        .ops = &clk_branch2_ops,
index 04944f11659b659eaae355a8c4ce7290e387259e..bfc4ac02f9ea21c3766f6cbd7230f86784d93088 100644 (file)
@@ -6,6 +6,7 @@
 #include <linux/bitops.h>
 #include <linux/delay.h>
 #include <linux/err.h>
+#include <linux/export.h>
 #include <linux/jiffies.h>
 #include <linux/kernel.h>
 #include <linux/ktime.h>
@@ -29,6 +30,7 @@
 /* CFG_GDSCR */
 #define GDSC_POWER_UP_COMPLETE         BIT(16)
 #define GDSC_POWER_DOWN_COMPLETE       BIT(15)
+#define GDSC_RETAIN_FF_ENABLE          BIT(11)
 #define CFG_GDSCR_OFFSET               0x4
 
 /* Wait 2^n CXO cycles between all states. Here, n=2 (4 cycles). */
@@ -216,6 +218,14 @@ static inline void gdsc_assert_reset_aon(struct gdsc *sc)
        regmap_update_bits(sc->regmap, sc->clamp_io_ctrl,
                           GMEM_RESET_MASK, 0);
 }
+
+static void gdsc_retain_ff_on(struct gdsc *sc)
+{
+       u32 mask = GDSC_RETAIN_FF_ENABLE;
+
+       regmap_update_bits(sc->regmap, sc->gdscr, mask, mask);
+}
+
 static int gdsc_enable(struct generic_pm_domain *domain)
 {
        struct gdsc *sc = domain_to_gdsc(domain);
@@ -268,6 +278,9 @@ static int gdsc_enable(struct generic_pm_domain *domain)
                udelay(1);
        }
 
+       if (sc->flags & RETAIN_FF_ENABLE)
+               gdsc_retain_ff_on(sc);
+
        return 0;
 }
 
@@ -433,3 +446,29 @@ void gdsc_unregister(struct gdsc_desc *desc)
        }
        of_genpd_del_provider(dev->of_node);
 }
+
+/*
+ * On SDM845+ the GPU GX domain is *almost* entirely controlled by the GMU
+ * running in the CX domain so the CPU doesn't need to know anything about the
+ * GX domain EXCEPT....
+ *
+ * Hardware constraints dictate that the GX be powered down before the CX. If
+ * the GMU crashes it could leave the GX on. In order to successfully bring back
+ * the device the CPU needs to disable the GX headswitch. There being no sane
+ * way to reach in and touch that register from deep inside the GPU driver we
+ * need to set up the infrastructure to be able to ensure that the GPU can
+ * ensure that the GX is off during this super special case. We do this by
+ * defining a GX gdsc with a dummy enable function and a "default" disable
+ * function.
+ *
+ * This allows us to attach with genpd_dev_pm_attach_by_name() in the GPU
+ * driver. During power up, nothing will happen from the CPU (and the GMU will
+ * power up normally but during power down this will ensure that the GX domain
+ * is *really* off - this gives us a semi standard way of doing what we need.
+ */
+int gdsc_gx_do_nothing_enable(struct generic_pm_domain *domain)
+{
+       /* Do nothing but give genpd the impression that we were successful */
+       return 0;
+}
+EXPORT_SYMBOL_GPL(gdsc_gx_do_nothing_enable);
index c36fc26dcdffe125a6493c9d1edf6938425125b0..bd537438c79321a9d11c1d3a84bed3776a4e1984 100644 (file)
@@ -50,6 +50,7 @@ struct gdsc {
 #define AON_RESET      BIT(4)
 #define POLL_CFG_GDSCR BIT(5)
 #define ALWAYS_ON      BIT(6)
+#define RETAIN_FF_ENABLE       BIT(7)
        struct reset_controller_dev     *rcdev;
        unsigned int                    *resets;
        unsigned int                    reset_count;
@@ -68,6 +69,7 @@ struct gdsc_desc {
 int gdsc_register(struct gdsc_desc *desc, struct reset_controller_dev *,
                  struct regmap *);
 void gdsc_unregister(struct gdsc_desc *desc);
+int gdsc_gx_do_nothing_enable(struct generic_pm_domain *domain);
 #else
 static inline int gdsc_register(struct gdsc_desc *desc,
                                struct reset_controller_dev *rcdev,
index 7b656b6aecedb26cdcb2bd0b764126d05182b28c..88a739b6fec3997c55ef0dcdbeb8c2fde6bce3b0 100644 (file)
@@ -170,37 +170,12 @@ static struct gdsc cx_gdsc = {
        .flags = VOTABLE,
 };
 
-/*
- * On SC7180 the GPU GX domain is *almost* entirely controlled by the GMU
- * running in the CX domain so the CPU doesn't need to know anything about the
- * GX domain EXCEPT....
- *
- * Hardware constraints dictate that the GX be powered down before the CX. If
- * the GMU crashes it could leave the GX on. In order to successfully bring back
- * the device the CPU needs to disable the GX headswitch. There being no sane
- * way to reach in and touch that register from deep inside the GPU driver we
- * need to set up the infrastructure to be able to ensure that the GPU can
- * ensure that the GX is off during this super special case. We do this by
- * defining a GX gdsc with a dummy enable function and a "default" disable
- * function.
- *
- * This allows us to attach with genpd_dev_pm_attach_by_name() in the GPU
- * driver. During power up, nothing will happen from the CPU (and the GMU will
- * power up normally but during power down this will ensure that the GX domain
- * is *really* off - this gives us a semi standard way of doing what we need.
- */
-static int gx_gdsc_enable(struct generic_pm_domain *domain)
-{
-       /* Do nothing but give genpd the impression that we were successful */
-       return 0;
-}
-
 static struct gdsc gx_gdsc = {
        .gdscr = 0x100c,
        .clamp_io_ctrl = 0x1508,
        .pd = {
                .name = "gx_gdsc",
-               .power_on = gx_gdsc_enable,
+               .power_on = gdsc_gx_do_nothing_enable,
        },
        .pwrsts = PWRSTS_OFF_ON,
        .flags = CLAMP_IO,
index e40efba1bf7d4c9a63d5cd923bb3c68a80e90eb2..5663698b306b9df623a940076bdebf20052693ae 100644 (file)
@@ -131,37 +131,12 @@ static struct gdsc gpu_cx_gdsc = {
        .flags = VOTABLE,
 };
 
-/*
- * On SDM845 the GPU GX domain is *almost* entirely controlled by the GMU
- * running in the CX domain so the CPU doesn't need to know anything about the
- * GX domain EXCEPT....
- *
- * Hardware constraints dictate that the GX be powered down before the CX. If
- * the GMU crashes it could leave the GX on. In order to successfully bring back
- * the device the CPU needs to disable the GX headswitch. There being no sane
- * way to reach in and touch that register from deep inside the GPU driver we
- * need to set up the infrastructure to be able to ensure that the GPU can
- * ensure that the GX is off during this super special case. We do this by
- * defining a GX gdsc with a dummy enable function and a "default" disable
- * function.
- *
- * This allows us to attach with genpd_dev_pm_attach_by_name() in the GPU
- * driver. During power up, nothing will happen from the CPU (and the GMU will
- * power up normally but during power down this will ensure that the GX domain
- * is *really* off - this gives us a semi standard way of doing what we need.
- */
-static int gx_gdsc_enable(struct generic_pm_domain *domain)
-{
-       /* Do nothing but give genpd the impression that we were successful */
-       return 0;
-}
-
 static struct gdsc gpu_gx_gdsc = {
        .gdscr = 0x100c,
        .clamp_io_ctrl = 0x1508,
        .pd = {
                .name = "gpu_gx_gdsc",
-               .power_on = gx_gdsc_enable,
+               .power_on = gdsc_gx_do_nothing_enable,
        },
        .pwrsts = PWRSTS_OFF_ON,
        .flags = CLAMP_IO | AON_RESET | POLL_CFG_GDSCR,
diff --git a/drivers/clk/qcom/gpucc-sm8150.c b/drivers/clk/qcom/gpucc-sm8150.c
new file mode 100644 (file)
index 0000000..27c4075
--- /dev/null
@@ -0,0 +1,320 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (c) 2017-2020, The Linux Foundation. All rights reserved.
+ */
+
+#include <linux/clk-provider.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/regmap.h>
+
+#include <dt-bindings/clock/qcom,gpucc-sm8150.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 "reset.h"
+#include "gdsc.h"
+
+enum {
+       P_BI_TCXO,
+       P_CORE_BI_PLL_TEST_SE,
+       P_GPLL0_OUT_MAIN,
+       P_GPLL0_OUT_MAIN_DIV,
+       P_GPU_CC_PLL1_OUT_MAIN,
+};
+
+static const struct pll_vco trion_vco[] = {
+       { 249600000, 2000000000, 0 },
+};
+
+static struct alpha_pll_config gpu_cc_pll1_config = {
+       .l = 0x1a,
+       .alpha = 0xaaa,
+       .config_ctl_val = 0x20485699,
+       .config_ctl_hi_val = 0x00002267,
+       .config_ctl_hi1_val = 0x00000024,
+       .test_ctl_val = 0x00000000,
+       .test_ctl_hi_val = 0x00000002,
+       .test_ctl_hi1_val = 0x00000000,
+       .user_ctl_val = 0x00000000,
+       .user_ctl_hi_val = 0x00000805,
+       .user_ctl_hi1_val = 0x000000d0,
+};
+
+static struct clk_alpha_pll gpu_cc_pll1 = {
+       .offset = 0x100,
+       .vco_table = trion_vco,
+       .num_vco = ARRAY_SIZE(trion_vco),
+       .regs = clk_alpha_pll_regs[CLK_ALPHA_PLL_TYPE_TRION],
+       .clkr = {
+               .hw.init = &(struct clk_init_data){
+                       .name = "gpu_cc_pll1",
+                       .parent_data =  &(const struct clk_parent_data){
+                               .fw_name = "bi_tcxo",
+                       },
+                       .num_parents = 1,
+                       .ops = &clk_alpha_pll_trion_ops,
+               },
+       },
+};
+
+static const struct parent_map gpu_cc_parent_map_0[] = {
+       { P_BI_TCXO, 0 },
+       { P_GPU_CC_PLL1_OUT_MAIN, 3 },
+       { P_GPLL0_OUT_MAIN, 5 },
+       { P_GPLL0_OUT_MAIN_DIV, 6 },
+};
+
+static const struct clk_parent_data gpu_cc_parent_data_0[] = {
+       { .fw_name = "bi_tcxo" },
+       { .hw = &gpu_cc_pll1.clkr.hw },
+       { .fw_name = "gcc_gpu_gpll0_clk_src" },
+       { .fw_name = "gcc_gpu_gpll0_div_clk_src" },
+};
+
+static const struct freq_tbl ftbl_gpu_cc_gmu_clk_src[] = {
+       F(19200000, P_BI_TCXO, 1, 0, 0),
+       F(200000000, P_GPLL0_OUT_MAIN_DIV, 1.5, 0, 0),
+       F(500000000, P_GPU_CC_PLL1_OUT_MAIN, 1, 0, 0),
+       { }
+};
+
+static struct clk_rcg2 gpu_cc_gmu_clk_src = {
+       .cmd_rcgr = 0x1120,
+       .mnd_width = 0,
+       .hid_width = 5,
+       .parent_map = gpu_cc_parent_map_0,
+       .freq_tbl = ftbl_gpu_cc_gmu_clk_src,
+       .clkr.hw.init = &(struct clk_init_data){
+               .name = "gpu_cc_gmu_clk_src",
+               .parent_data = gpu_cc_parent_data_0,
+               .num_parents = ARRAY_SIZE(gpu_cc_parent_data_0),
+               .flags = CLK_SET_RATE_PARENT,
+               .ops = &clk_rcg2_ops,
+       },
+};
+
+static struct clk_branch gpu_cc_ahb_clk = {
+       .halt_reg = 0x1078,
+       .halt_check = BRANCH_HALT_DELAY,
+       .clkr = {
+               .enable_reg = 0x1078,
+               .enable_mask = BIT(0),
+               .hw.init = &(struct clk_init_data){
+                       .name = "gpu_cc_ahb_clk",
+                       .ops = &clk_branch2_ops,
+               },
+       },
+};
+
+static struct clk_branch gpu_cc_crc_ahb_clk = {
+       .halt_reg = 0x107c,
+       .halt_check = BRANCH_HALT,
+       .clkr = {
+               .enable_reg = 0x107c,
+               .enable_mask = BIT(0),
+               .hw.init = &(struct clk_init_data){
+                       .name = "gpu_cc_crc_ahb_clk",
+                       .ops = &clk_branch2_ops,
+               },
+       },
+};
+
+static struct clk_branch gpu_cc_cx_apb_clk = {
+       .halt_reg = 0x1088,
+       .halt_check = BRANCH_HALT,
+       .clkr = {
+               .enable_reg = 0x1088,
+               .enable_mask = BIT(0),
+               .hw.init = &(struct clk_init_data){
+                       .name = "gpu_cc_cx_apb_clk",
+                       .ops = &clk_branch2_ops,
+               },
+       },
+};
+
+static struct clk_branch gpu_cc_cx_gmu_clk = {
+       .halt_reg = 0x1098,
+       .halt_check = BRANCH_HALT,
+       .clkr = {
+               .enable_reg = 0x1098,
+               .enable_mask = BIT(0),
+               .hw.init = &(struct clk_init_data){
+                       .name = "gpu_cc_cx_gmu_clk",
+                       .parent_data =  &(const struct clk_parent_data){
+                               .hw = &gpu_cc_gmu_clk_src.clkr.hw,
+                       },
+                       .num_parents = 1,
+                       .flags = CLK_SET_RATE_PARENT,
+                       .ops = &clk_branch2_ops,
+               },
+       },
+};
+
+static struct clk_branch gpu_cc_cx_snoc_dvm_clk = {
+       .halt_reg = 0x108c,
+       .halt_check = BRANCH_HALT,
+       .clkr = {
+               .enable_reg = 0x108c,
+               .enable_mask = BIT(0),
+               .hw.init = &(struct clk_init_data){
+                       .name = "gpu_cc_cx_snoc_dvm_clk",
+                       .ops = &clk_branch2_ops,
+               },
+       },
+};
+
+static struct clk_branch gpu_cc_cxo_aon_clk = {
+       .halt_reg = 0x1004,
+       .halt_check = BRANCH_HALT,
+       .clkr = {
+               .enable_reg = 0x1004,
+               .enable_mask = BIT(0),
+               .hw.init = &(struct clk_init_data){
+                       .name = "gpu_cc_cxo_aon_clk",
+                       .ops = &clk_branch2_ops,
+               },
+       },
+};
+
+static struct clk_branch gpu_cc_cxo_clk = {
+       .halt_reg = 0x109c,
+       .halt_check = BRANCH_HALT,
+       .clkr = {
+               .enable_reg = 0x109c,
+               .enable_mask = BIT(0),
+               .hw.init = &(struct clk_init_data){
+                       .name = "gpu_cc_cxo_clk",
+                       .ops = &clk_branch2_ops,
+               },
+       },
+};
+
+static struct clk_branch gpu_cc_gx_gmu_clk = {
+       .halt_reg = 0x1064,
+       .halt_check = BRANCH_HALT,
+       .clkr = {
+               .enable_reg = 0x1064,
+               .enable_mask = BIT(0),
+               .hw.init = &(struct clk_init_data){
+                       .name = "gpu_cc_gx_gmu_clk",
+                       .parent_data =  &(const struct clk_parent_data){
+                               .hw = &gpu_cc_gmu_clk_src.clkr.hw,
+                       },
+                       .num_parents = 1,
+                       .flags = CLK_SET_RATE_PARENT,
+                       .ops = &clk_branch2_ops,
+               },
+       },
+};
+
+static struct gdsc gpu_cx_gdsc = {
+       .gdscr = 0x106c,
+       .gds_hw_ctrl = 0x1540,
+       .pd = {
+               .name = "gpu_cx_gdsc",
+       },
+       .pwrsts = PWRSTS_OFF_ON,
+       .flags = VOTABLE,
+};
+
+static struct gdsc gpu_gx_gdsc = {
+       .gdscr = 0x100c,
+       .clamp_io_ctrl = 0x1508,
+       .pd = {
+               .name = "gpu_gx_gdsc",
+               .power_on = gdsc_gx_do_nothing_enable,
+       },
+       .pwrsts = PWRSTS_OFF_ON,
+       .flags = CLAMP_IO | AON_RESET | POLL_CFG_GDSCR,
+};
+
+static struct clk_regmap *gpu_cc_sm8150_clocks[] = {
+       [GPU_CC_AHB_CLK] = &gpu_cc_ahb_clk.clkr,
+       [GPU_CC_CRC_AHB_CLK] = &gpu_cc_crc_ahb_clk.clkr,
+       [GPU_CC_CX_APB_CLK] = &gpu_cc_cx_apb_clk.clkr,
+       [GPU_CC_CX_GMU_CLK] = &gpu_cc_cx_gmu_clk.clkr,
+       [GPU_CC_CX_SNOC_DVM_CLK] = &gpu_cc_cx_snoc_dvm_clk.clkr,
+       [GPU_CC_CXO_AON_CLK] = &gpu_cc_cxo_aon_clk.clkr,
+       [GPU_CC_CXO_CLK] = &gpu_cc_cxo_clk.clkr,
+       [GPU_CC_GMU_CLK_SRC] = &gpu_cc_gmu_clk_src.clkr,
+       [GPU_CC_GX_GMU_CLK] = &gpu_cc_gx_gmu_clk.clkr,
+       [GPU_CC_PLL1] = &gpu_cc_pll1.clkr,
+};
+
+static const struct qcom_reset_map gpu_cc_sm8150_resets[] = {
+       [GPUCC_GPU_CC_CX_BCR] = { 0x1068 },
+       [GPUCC_GPU_CC_GMU_BCR] = { 0x111c },
+       [GPUCC_GPU_CC_GX_BCR] = { 0x1008 },
+       [GPUCC_GPU_CC_SPDM_BCR] = { 0x1110 },
+       [GPUCC_GPU_CC_XO_BCR] = { 0x1000 },
+};
+
+static struct gdsc *gpu_cc_sm8150_gdscs[] = {
+       [GPU_CX_GDSC] = &gpu_cx_gdsc,
+       [GPU_GX_GDSC] = &gpu_gx_gdsc,
+};
+
+static const struct regmap_config gpu_cc_sm8150_regmap_config = {
+       .reg_bits       = 32,
+       .reg_stride     = 4,
+       .val_bits       = 32,
+       .max_register   = 0x8008,
+       .fast_io        = true,
+};
+
+static const struct qcom_cc_desc gpu_cc_sm8150_desc = {
+       .config = &gpu_cc_sm8150_regmap_config,
+       .clks = gpu_cc_sm8150_clocks,
+       .num_clks = ARRAY_SIZE(gpu_cc_sm8150_clocks),
+       .resets = gpu_cc_sm8150_resets,
+       .num_resets = ARRAY_SIZE(gpu_cc_sm8150_resets),
+       .gdscs = gpu_cc_sm8150_gdscs,
+       .num_gdscs = ARRAY_SIZE(gpu_cc_sm8150_gdscs),
+};
+
+static const struct of_device_id gpu_cc_sm8150_match_table[] = {
+       { .compatible = "qcom,sm8150-gpucc" },
+       { }
+};
+MODULE_DEVICE_TABLE(of, gpu_cc_sm8150_match_table);
+
+static int gpu_cc_sm8150_probe(struct platform_device *pdev)
+{
+       struct regmap *regmap;
+
+       regmap = qcom_cc_map(pdev, &gpu_cc_sm8150_desc);
+       if (IS_ERR(regmap))
+               return PTR_ERR(regmap);
+
+       clk_trion_pll_configure(&gpu_cc_pll1, regmap, &gpu_cc_pll1_config);
+
+       return qcom_cc_really_probe(pdev, &gpu_cc_sm8150_desc, regmap);
+}
+
+static struct platform_driver gpu_cc_sm8150_driver = {
+       .probe = gpu_cc_sm8150_probe,
+       .driver = {
+               .name = "sm8150-gpucc",
+               .of_match_table = gpu_cc_sm8150_match_table,
+       },
+};
+
+static int __init gpu_cc_sm8150_init(void)
+{
+       return platform_driver_register(&gpu_cc_sm8150_driver);
+}
+subsys_initcall(gpu_cc_sm8150_init);
+
+static void __exit gpu_cc_sm8150_exit(void)
+{
+       platform_driver_unregister(&gpu_cc_sm8150_driver);
+}
+module_exit(gpu_cc_sm8150_exit);
+
+MODULE_DESCRIPTION("QTI GPUCC SM8150 Driver");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/clk/qcom/gpucc-sm8250.c b/drivers/clk/qcom/gpucc-sm8250.c
new file mode 100644 (file)
index 0000000..3fa7d1f
--- /dev/null
@@ -0,0 +1,348 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (c) 2018-2020, The Linux Foundation. All rights reserved.
+ */
+
+#include <linux/clk-provider.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/regmap.h>
+
+#include <dt-bindings/clock/qcom,gpucc-sm8250.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 "reset.h"
+#include "gdsc.h"
+
+#define CX_GMU_CBCR_SLEEP_MASK         0xf
+#define CX_GMU_CBCR_SLEEP_SHIFT                4
+#define CX_GMU_CBCR_WAKE_MASK          0xf
+#define CX_GMU_CBCR_WAKE_SHIFT         8
+
+enum {
+       P_BI_TCXO,
+       P_CORE_BI_PLL_TEST_SE,
+       P_GPLL0_OUT_MAIN,
+       P_GPLL0_OUT_MAIN_DIV,
+       P_GPU_CC_PLL0_OUT_MAIN,
+       P_GPU_CC_PLL1_OUT_MAIN,
+};
+
+static struct pll_vco lucid_vco[] = {
+       { 249600000, 2000000000, 0 },
+};
+
+static const struct alpha_pll_config gpu_cc_pll1_config = {
+       .l = 0x1a,
+       .alpha = 0xaaa,
+       .config_ctl_val = 0x20485699,
+       .config_ctl_hi_val = 0x00002261,
+       .config_ctl_hi1_val = 0x029a699c,
+       .user_ctl_val = 0x00000000,
+       .user_ctl_hi_val = 0x00000805,
+       .user_ctl_hi1_val = 0x00000000,
+};
+
+static struct clk_alpha_pll gpu_cc_pll1 = {
+       .offset = 0x100,
+       .vco_table = lucid_vco,
+       .num_vco = ARRAY_SIZE(lucid_vco),
+       .regs = clk_alpha_pll_regs[CLK_ALPHA_PLL_TYPE_LUCID],
+       .clkr = {
+               .hw.init = &(struct clk_init_data){
+                       .name = "gpu_cc_pll1",
+                       .parent_data =  &(const struct clk_parent_data){
+                               .fw_name = "bi_tcxo",
+                       },
+                       .num_parents = 1,
+                       .ops = &clk_alpha_pll_lucid_ops,
+               },
+       },
+};
+
+static const struct parent_map gpu_cc_parent_map_0[] = {
+       { P_BI_TCXO, 0 },
+       { P_GPU_CC_PLL1_OUT_MAIN, 3 },
+       { P_GPLL0_OUT_MAIN, 5 },
+       { P_GPLL0_OUT_MAIN_DIV, 6 },
+};
+
+static const struct clk_parent_data gpu_cc_parent_data_0[] = {
+       { .fw_name = "bi_tcxo" },
+       { .hw = &gpu_cc_pll1.clkr.hw },
+       { .fw_name = "gcc_gpu_gpll0_clk_src" },
+       { .fw_name = "gcc_gpu_gpll0_div_clk_src" },
+};
+
+static const struct freq_tbl ftbl_gpu_cc_gmu_clk_src[] = {
+       F(19200000, P_BI_TCXO, 1, 0, 0),
+       F(200000000, P_GPLL0_OUT_MAIN_DIV, 1.5, 0, 0),
+       F(500000000, P_GPU_CC_PLL1_OUT_MAIN, 1, 0, 0),
+       { }
+};
+
+static struct clk_rcg2 gpu_cc_gmu_clk_src = {
+       .cmd_rcgr = 0x1120,
+       .mnd_width = 0,
+       .hid_width = 5,
+       .parent_map = gpu_cc_parent_map_0,
+       .freq_tbl = ftbl_gpu_cc_gmu_clk_src,
+       .clkr.hw.init = &(struct clk_init_data){
+               .name = "gpu_cc_gmu_clk_src",
+               .parent_data = gpu_cc_parent_data_0,
+               .num_parents = ARRAY_SIZE(gpu_cc_parent_data_0),
+               .flags = CLK_SET_RATE_PARENT,
+               .ops = &clk_rcg2_ops,
+       },
+};
+
+static struct clk_branch gpu_cc_ahb_clk = {
+       .halt_reg = 0x1078,
+       .halt_check = BRANCH_HALT_DELAY,
+       .clkr = {
+               .enable_reg = 0x1078,
+               .enable_mask = BIT(0),
+               .hw.init = &(struct clk_init_data){
+                       .name = "gpu_cc_ahb_clk",
+                       .ops = &clk_branch2_ops,
+               },
+       },
+};
+
+static struct clk_branch gpu_cc_crc_ahb_clk = {
+       .halt_reg = 0x107c,
+       .halt_check = BRANCH_HALT_VOTED,
+       .clkr = {
+               .enable_reg = 0x107c,
+               .enable_mask = BIT(0),
+               .hw.init = &(struct clk_init_data){
+                       .name = "gpu_cc_crc_ahb_clk",
+                       .ops = &clk_branch2_ops,
+               },
+       },
+};
+
+static struct clk_branch gpu_cc_cx_apb_clk = {
+       .halt_reg = 0x1088,
+       .halt_check = BRANCH_HALT_VOTED,
+       .clkr = {
+               .enable_reg = 0x1088,
+               .enable_mask = BIT(0),
+               .hw.init = &(struct clk_init_data){
+                       .name = "gpu_cc_cx_apb_clk",
+                       .ops = &clk_branch2_ops,
+               },
+       },
+};
+
+static struct clk_branch gpu_cc_cx_gmu_clk = {
+       .halt_reg = 0x1098,
+       .halt_check = BRANCH_HALT,
+       .clkr = {
+               .enable_reg = 0x1098,
+               .enable_mask = BIT(0),
+               .hw.init = &(struct clk_init_data){
+                       .name = "gpu_cc_cx_gmu_clk",
+                       .parent_data =  &(const struct clk_parent_data){
+                               .hw = &gpu_cc_gmu_clk_src.clkr.hw,
+                       },
+                       .num_parents = 1,
+                       .flags = CLK_SET_RATE_PARENT,
+                       .ops = &clk_branch2_ops,
+               },
+       },
+};
+
+static struct clk_branch gpu_cc_cx_snoc_dvm_clk = {
+       .halt_reg = 0x108c,
+       .halt_check = BRANCH_HALT_VOTED,
+       .clkr = {
+               .enable_reg = 0x108c,
+               .enable_mask = BIT(0),
+               .hw.init = &(struct clk_init_data){
+                       .name = "gpu_cc_cx_snoc_dvm_clk",
+                       .ops = &clk_branch2_ops,
+               },
+       },
+};
+
+static struct clk_branch gpu_cc_cxo_aon_clk = {
+       .halt_reg = 0x1004,
+       .halt_check = BRANCH_HALT_VOTED,
+       .clkr = {
+               .enable_reg = 0x1004,
+               .enable_mask = BIT(0),
+               .hw.init = &(struct clk_init_data){
+                       .name = "gpu_cc_cxo_aon_clk",
+                       .ops = &clk_branch2_ops,
+               },
+       },
+};
+
+static struct clk_branch gpu_cc_cxo_clk = {
+       .halt_reg = 0x109c,
+       .halt_check = BRANCH_HALT,
+       .clkr = {
+               .enable_reg = 0x109c,
+               .enable_mask = BIT(0),
+               .hw.init = &(struct clk_init_data){
+                       .name = "gpu_cc_cxo_clk",
+                       .ops = &clk_branch2_ops,
+               },
+       },
+};
+
+static struct clk_branch gpu_cc_gx_gmu_clk = {
+       .halt_reg = 0x1064,
+       .halt_check = BRANCH_HALT,
+       .clkr = {
+               .enable_reg = 0x1064,
+               .enable_mask = BIT(0),
+               .hw.init = &(struct clk_init_data){
+                       .name = "gpu_cc_gx_gmu_clk",
+                       .parent_data =  &(const struct clk_parent_data){
+                               .hw = &gpu_cc_gmu_clk_src.clkr.hw,
+                       },
+                       .num_parents = 1,
+                       .flags = CLK_SET_RATE_PARENT,
+                       .ops = &clk_branch2_ops,
+               },
+       },
+};
+
+static struct clk_branch gpu_cc_hlos1_vote_gpu_smmu_clk = {
+       .halt_reg = 0x5000,
+       .halt_check = BRANCH_VOTED,
+       .clkr = {
+               .enable_reg = 0x5000,
+               .enable_mask = BIT(0),
+               .hw.init = &(struct clk_init_data){
+                        .name = "gpu_cc_hlos1_vote_gpu_smmu_clk",
+                        .ops = &clk_branch2_ops,
+               },
+       },
+};
+
+static struct gdsc gpu_cx_gdsc = {
+       .gdscr = 0x106c,
+       .gds_hw_ctrl = 0x1540,
+       .pd = {
+               .name = "gpu_cx_gdsc",
+       },
+       .pwrsts = PWRSTS_OFF_ON,
+       .flags = VOTABLE,
+};
+
+static struct gdsc gpu_gx_gdsc = {
+       .gdscr = 0x100c,
+       .clamp_io_ctrl = 0x1508,
+       .pd = {
+               .name = "gpu_gx_gdsc",
+               .power_on = gdsc_gx_do_nothing_enable,
+       },
+       .pwrsts = PWRSTS_OFF_ON,
+       .flags = CLAMP_IO | AON_RESET | POLL_CFG_GDSCR,
+};
+
+static struct clk_regmap *gpu_cc_sm8250_clocks[] = {
+       [GPU_CC_AHB_CLK] = &gpu_cc_ahb_clk.clkr,
+       [GPU_CC_CRC_AHB_CLK] = &gpu_cc_crc_ahb_clk.clkr,
+       [GPU_CC_CX_APB_CLK] = &gpu_cc_cx_apb_clk.clkr,
+       [GPU_CC_CX_GMU_CLK] = &gpu_cc_cx_gmu_clk.clkr,
+       [GPU_CC_CX_SNOC_DVM_CLK] = &gpu_cc_cx_snoc_dvm_clk.clkr,
+       [GPU_CC_CXO_AON_CLK] = &gpu_cc_cxo_aon_clk.clkr,
+       [GPU_CC_CXO_CLK] = &gpu_cc_cxo_clk.clkr,
+       [GPU_CC_GMU_CLK_SRC] = &gpu_cc_gmu_clk_src.clkr,
+       [GPU_CC_GX_GMU_CLK] = &gpu_cc_gx_gmu_clk.clkr,
+       [GPU_CC_PLL1] = &gpu_cc_pll1.clkr,
+       [GPU_CC_HLOS1_VOTE_GPU_SMMU_CLK] = &gpu_cc_hlos1_vote_gpu_smmu_clk.clkr,
+};
+
+static const struct qcom_reset_map gpu_cc_sm8250_resets[] = {
+       [GPUCC_GPU_CC_ACD_BCR] = { 0x1160 },
+       [GPUCC_GPU_CC_CX_BCR] = { 0x1068 },
+       [GPUCC_GPU_CC_GFX3D_AON_BCR] = { 0x10a0 },
+       [GPUCC_GPU_CC_GMU_BCR] = { 0x111c },
+       [GPUCC_GPU_CC_GX_BCR] = { 0x1008 },
+       [GPUCC_GPU_CC_XO_BCR] = { 0x1000 },
+};
+
+static struct gdsc *gpu_cc_sm8250_gdscs[] = {
+       [GPU_CX_GDSC] = &gpu_cx_gdsc,
+       [GPU_GX_GDSC] = &gpu_gx_gdsc,
+};
+
+static const struct regmap_config gpu_cc_sm8250_regmap_config = {
+       .reg_bits = 32,
+       .reg_stride = 4,
+       .val_bits = 32,
+       .max_register = 0x8008,
+       .fast_io = true,
+};
+
+static const struct qcom_cc_desc gpu_cc_sm8250_desc = {
+       .config = &gpu_cc_sm8250_regmap_config,
+       .clks = gpu_cc_sm8250_clocks,
+       .num_clks = ARRAY_SIZE(gpu_cc_sm8250_clocks),
+       .resets = gpu_cc_sm8250_resets,
+       .num_resets = ARRAY_SIZE(gpu_cc_sm8250_resets),
+       .gdscs = gpu_cc_sm8250_gdscs,
+       .num_gdscs = ARRAY_SIZE(gpu_cc_sm8250_gdscs),
+};
+
+static const struct of_device_id gpu_cc_sm8250_match_table[] = {
+       { .compatible = "qcom,sm8250-gpucc" },
+       { }
+};
+MODULE_DEVICE_TABLE(of, gpu_cc_sm8250_match_table);
+
+static int gpu_cc_sm8250_probe(struct platform_device *pdev)
+{
+       struct regmap *regmap;
+       unsigned int value, mask;
+
+       regmap = qcom_cc_map(pdev, &gpu_cc_sm8250_desc);
+       if (IS_ERR(regmap))
+               return PTR_ERR(regmap);
+
+       clk_lucid_pll_configure(&gpu_cc_pll1, regmap, &gpu_cc_pll1_config);
+
+       /*
+        * Configure gpu_cc_cx_gmu_clk with recommended
+        * wakeup/sleep settings
+        */
+       mask = CX_GMU_CBCR_WAKE_MASK << CX_GMU_CBCR_WAKE_SHIFT;
+       mask |= CX_GMU_CBCR_SLEEP_MASK << CX_GMU_CBCR_SLEEP_SHIFT;
+       value = 0xf << CX_GMU_CBCR_WAKE_SHIFT | 0xf << CX_GMU_CBCR_SLEEP_SHIFT;
+       regmap_update_bits(regmap, 0x1098, mask, value);
+
+       return qcom_cc_really_probe(pdev, &gpu_cc_sm8250_desc, regmap);
+}
+
+static struct platform_driver gpu_cc_sm8250_driver = {
+       .probe = gpu_cc_sm8250_probe,
+       .driver = {
+               .name = "sm8250-gpucc",
+               .of_match_table = gpu_cc_sm8250_match_table,
+       },
+};
+
+static int __init gpu_cc_sm8250_init(void)
+{
+       return platform_driver_register(&gpu_cc_sm8250_driver);
+}
+subsys_initcall(gpu_cc_sm8250_init);
+
+static void __exit gpu_cc_sm8250_exit(void)
+{
+       platform_driver_unregister(&gpu_cc_sm8250_driver);
+}
+module_exit(gpu_cc_sm8250_exit);
+
+MODULE_DESCRIPTION("QTI GPU_CC SM8250 Driver");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/clk/qcom/lpasscorecc-sc7180.c b/drivers/clk/qcom/lpasscorecc-sc7180.c
new file mode 100644 (file)
index 0000000..d4c1864
--- /dev/null
@@ -0,0 +1,476 @@
+// 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_device.h>
+#include <linux/pm_clock.h>
+#include <linux/pm_runtime.h>
+#include <linux/of.h>
+#include <linux/regmap.h>
+
+#include <dt-bindings/clock/qcom,lpasscorecc-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"
+
+enum {
+       P_BI_TCXO,
+       P_LPASS_LPAAUDIO_DIG_PLL_OUT_ODD,
+       P_SLEEP_CLK,
+};
+
+static struct pll_vco fabia_vco[] = {
+       { 249600000, 2000000000, 0 },
+};
+
+static const struct alpha_pll_config lpass_lpaaudio_dig_pll_config = {
+       .l = 0x20,
+       .alpha = 0x0,
+       .config_ctl_val = 0x20485699,
+       .config_ctl_hi_val = 0x00002067,
+       .test_ctl_val = 0x40000000,
+       .test_ctl_hi_val = 0x00000000,
+       .user_ctl_val = 0x00005105,
+       .user_ctl_hi_val = 0x00004805,
+};
+
+static const u8 clk_alpha_pll_regs_offset[][PLL_OFF_MAX_REGS] = {
+       [CLK_ALPHA_PLL_TYPE_FABIA] =  {
+               [PLL_OFF_L_VAL] = 0x04,
+               [PLL_OFF_CAL_L_VAL] = 0x8,
+               [PLL_OFF_USER_CTL] = 0x0c,
+               [PLL_OFF_USER_CTL_U] = 0x10,
+               [PLL_OFF_USER_CTL_U1] = 0x14,
+               [PLL_OFF_CONFIG_CTL] = 0x18,
+               [PLL_OFF_CONFIG_CTL_U] = 0x1C,
+               [PLL_OFF_CONFIG_CTL_U1] = 0x20,
+               [PLL_OFF_TEST_CTL] = 0x24,
+               [PLL_OFF_TEST_CTL_U] = 0x28,
+               [PLL_OFF_STATUS] = 0x30,
+               [PLL_OFF_OPMODE] = 0x38,
+               [PLL_OFF_FRAC] = 0x40,
+       },
+};
+
+static struct clk_alpha_pll lpass_lpaaudio_dig_pll = {
+       .offset = 0x1000,
+       .vco_table = fabia_vco,
+       .num_vco = ARRAY_SIZE(fabia_vco),
+       .regs = clk_alpha_pll_regs_offset[CLK_ALPHA_PLL_TYPE_FABIA],
+       .clkr = {
+               .hw.init = &(struct clk_init_data){
+                       .name = "lpass_lpaaudio_dig_pll",
+                       .parent_data = &(const struct clk_parent_data){
+                               .fw_name = "bi_tcxo",
+                       },
+                       .num_parents = 1,
+                       .ops = &clk_alpha_pll_fabia_ops,
+               },
+       },
+};
+
+static const struct clk_div_table
+                       post_div_table_lpass_lpaaudio_dig_pll_out_odd[] = {
+       { 0x5, 5 },
+       { }
+};
+
+static struct clk_alpha_pll_postdiv lpass_lpaaudio_dig_pll_out_odd = {
+       .offset = 0x1000,
+       .post_div_shift = 12,
+       .post_div_table = post_div_table_lpass_lpaaudio_dig_pll_out_odd,
+       .num_post_div =
+               ARRAY_SIZE(post_div_table_lpass_lpaaudio_dig_pll_out_odd),
+       .width = 4,
+       .regs = clk_alpha_pll_regs[CLK_ALPHA_PLL_TYPE_FABIA],
+       .clkr.hw.init = &(struct clk_init_data){
+               .name = "lpass_lpaaudio_dig_pll_out_odd",
+               .parent_data = &(const struct clk_parent_data){
+                       .hw = &lpass_lpaaudio_dig_pll.clkr.hw,
+               },
+               .num_parents = 1,
+               .flags = CLK_SET_RATE_PARENT,
+               .ops = &clk_alpha_pll_postdiv_fabia_ops,
+       },
+};
+
+static const struct parent_map lpass_core_cc_parent_map_0[] = {
+       { P_BI_TCXO, 0 },
+       { P_LPASS_LPAAUDIO_DIG_PLL_OUT_ODD, 5 },
+};
+
+static const struct clk_parent_data lpass_core_cc_parent_data_0[] = {
+       { .fw_name = "bi_tcxo" },
+       { .hw = &lpass_lpaaudio_dig_pll_out_odd.clkr.hw },
+};
+
+static const struct parent_map lpass_core_cc_parent_map_2[] = {
+       { P_BI_TCXO, 0 },
+};
+
+static struct clk_rcg2 core_clk_src = {
+       .cmd_rcgr = 0x1d000,
+       .mnd_width = 8,
+       .hid_width = 5,
+       .parent_map = lpass_core_cc_parent_map_2,
+       .clkr.hw.init = &(struct clk_init_data){
+               .name = "core_clk_src",
+               .parent_data = &(const struct clk_parent_data){
+                       .fw_name = "bi_tcxo",
+               },
+               .num_parents = 1,
+               .ops = &clk_rcg2_ops,
+       },
+};
+
+static const struct freq_tbl ftbl_ext_mclk0_clk_src[] = {
+       F(9600000, P_BI_TCXO, 2, 0, 0),
+       F(19200000, P_BI_TCXO, 1, 0, 0),
+       { }
+};
+
+static const struct freq_tbl ftbl_ext_lpaif_clk_src[] = {
+       F(256000, P_LPASS_LPAAUDIO_DIG_PLL_OUT_ODD, 15, 1, 32),
+       F(512000, P_LPASS_LPAAUDIO_DIG_PLL_OUT_ODD, 15, 1, 16),
+       F(768000, P_LPASS_LPAAUDIO_DIG_PLL_OUT_ODD, 10, 1, 16),
+       F(1024000, P_LPASS_LPAAUDIO_DIG_PLL_OUT_ODD, 15, 1, 8),
+       F(1536000, P_LPASS_LPAAUDIO_DIG_PLL_OUT_ODD, 10, 1, 8),
+       F(2048000, P_LPASS_LPAAUDIO_DIG_PLL_OUT_ODD, 15, 1, 4),
+       F(3072000, P_LPASS_LPAAUDIO_DIG_PLL_OUT_ODD, 10, 1, 4),
+       F(4096000, P_LPASS_LPAAUDIO_DIG_PLL_OUT_ODD, 15, 1, 2),
+       F(6144000, P_LPASS_LPAAUDIO_DIG_PLL_OUT_ODD, 10, 1, 2),
+       F(8192000, P_LPASS_LPAAUDIO_DIG_PLL_OUT_ODD, 15, 0, 0),
+       F(9600000, P_BI_TCXO, 2, 0, 0),
+       F(12288000, P_LPASS_LPAAUDIO_DIG_PLL_OUT_ODD, 10, 0, 0),
+       F(19200000, P_BI_TCXO, 1, 0, 0),
+       F(24576000, P_LPASS_LPAAUDIO_DIG_PLL_OUT_ODD, 5, 0, 0),
+       { }
+};
+
+static struct clk_rcg2 ext_mclk0_clk_src = {
+       .cmd_rcgr = 0x20000,
+       .mnd_width = 8,
+       .hid_width = 5,
+       .parent_map = lpass_core_cc_parent_map_0,
+       .freq_tbl = ftbl_ext_mclk0_clk_src,
+       .clkr.hw.init = &(struct clk_init_data){
+               .name = "ext_mclk0_clk_src",
+               .parent_data = lpass_core_cc_parent_data_0,
+               .num_parents = 2,
+               .flags = CLK_SET_RATE_PARENT,
+               .ops = &clk_rcg2_ops,
+       },
+};
+
+static struct clk_rcg2 lpaif_pri_clk_src = {
+       .cmd_rcgr = 0x10000,
+       .mnd_width = 16,
+       .hid_width = 5,
+       .parent_map = lpass_core_cc_parent_map_0,
+       .freq_tbl = ftbl_ext_lpaif_clk_src,
+       .clkr.hw.init = &(struct clk_init_data){
+               .name = "lpaif_pri_clk_src",
+               .parent_data = lpass_core_cc_parent_data_0,
+               .num_parents = 2,
+               .flags = CLK_SET_RATE_PARENT,
+               .ops = &clk_rcg2_ops,
+       },
+};
+
+static struct clk_rcg2 lpaif_sec_clk_src = {
+       .cmd_rcgr = 0x11000,
+       .mnd_width = 16,
+       .hid_width = 5,
+       .parent_map = lpass_core_cc_parent_map_0,
+       .freq_tbl = ftbl_ext_lpaif_clk_src,
+       .clkr.hw.init = &(struct clk_init_data){
+               .name = "lpaif_sec_clk_src",
+               .parent_data = lpass_core_cc_parent_data_0,
+               .num_parents = 2,
+               .flags = CLK_SET_RATE_PARENT,
+               .ops = &clk_rcg2_ops,
+       },
+};
+
+static struct clk_branch lpass_audio_core_ext_mclk0_clk = {
+       .halt_reg = 0x20014,
+       .halt_check = BRANCH_HALT,
+       .hwcg_reg = 0x20014,
+       .hwcg_bit = 1,
+       .clkr = {
+               .enable_reg = 0x20014,
+               .enable_mask = BIT(0),
+               .hw.init = &(struct clk_init_data){
+                       .name = "lpass_audio_core_ext_mclk0_clk",
+                       .parent_data = &(const struct clk_parent_data){
+                               .hw = &ext_mclk0_clk_src.clkr.hw,
+                       },
+                       .num_parents = 1,
+                       .flags = CLK_SET_RATE_PARENT,
+                       .ops = &clk_branch2_ops,
+               },
+       },
+};
+
+static struct clk_branch lpass_audio_core_lpaif_pri_ibit_clk = {
+       .halt_reg = 0x10018,
+       .halt_check = BRANCH_HALT,
+       .hwcg_reg = 0x10018,
+       .hwcg_bit = 1,
+       .clkr = {
+               .enable_reg = 0x10018,
+               .enable_mask = BIT(0),
+               .hw.init = &(struct clk_init_data){
+                       .name = "lpass_audio_core_lpaif_pri_ibit_clk",
+                       .parent_data = &(const struct clk_parent_data){
+                               .hw = &lpaif_pri_clk_src.clkr.hw,
+                       },
+                       .num_parents = 1,
+                       .flags = CLK_SET_RATE_PARENT,
+                       .ops = &clk_branch2_ops,
+               },
+       },
+};
+
+static struct clk_branch lpass_audio_core_lpaif_sec_ibit_clk = {
+       .halt_reg = 0x11018,
+       .halt_check = BRANCH_HALT,
+       .hwcg_reg = 0x11018,
+       .hwcg_bit = 1,
+       .clkr = {
+               .enable_reg = 0x11018,
+               .enable_mask = BIT(0),
+               .hw.init = &(struct clk_init_data){
+                       .name = "lpass_audio_core_lpaif_sec_ibit_clk",
+                       .parent_data = &(const struct clk_parent_data){
+                               .hw = &lpaif_sec_clk_src.clkr.hw,
+                       },
+                       .num_parents = 1,
+                       .flags = CLK_SET_RATE_PARENT,
+                       .ops = &clk_branch2_ops,
+               },
+       },
+};
+
+static struct clk_branch lpass_audio_core_sysnoc_mport_core_clk = {
+       .halt_reg = 0x23000,
+       .halt_check = BRANCH_HALT,
+       .hwcg_reg = 0x23000,
+       .hwcg_bit = 1,
+       .clkr = {
+               .enable_reg = 0x23000,
+               .enable_mask = BIT(0),
+               .hw.init = &(struct clk_init_data){
+                       .name = "lpass_audio_core_sysnoc_mport_core_clk",
+                       .parent_data = &(const struct clk_parent_data){
+                               .hw = &core_clk_src.clkr.hw,
+                       },
+                       .num_parents = 1,
+                       .flags = CLK_SET_RATE_PARENT,
+                       .ops = &clk_branch2_ops,
+               },
+       },
+};
+
+static struct clk_regmap *lpass_core_cc_sc7180_clocks[] = {
+       [EXT_MCLK0_CLK_SRC] = &ext_mclk0_clk_src.clkr,
+       [LPAIF_PRI_CLK_SRC] = &lpaif_pri_clk_src.clkr,
+       [LPAIF_SEC_CLK_SRC] = &lpaif_sec_clk_src.clkr,
+       [CORE_CLK_SRC] = &core_clk_src.clkr,
+       [LPASS_AUDIO_CORE_EXT_MCLK0_CLK] = &lpass_audio_core_ext_mclk0_clk.clkr,
+       [LPASS_AUDIO_CORE_LPAIF_PRI_IBIT_CLK] =
+               &lpass_audio_core_lpaif_pri_ibit_clk.clkr,
+       [LPASS_AUDIO_CORE_LPAIF_SEC_IBIT_CLK] =
+               &lpass_audio_core_lpaif_sec_ibit_clk.clkr,
+       [LPASS_AUDIO_CORE_SYSNOC_MPORT_CORE_CLK] =
+               &lpass_audio_core_sysnoc_mport_core_clk.clkr,
+       [LPASS_LPAAUDIO_DIG_PLL] = &lpass_lpaaudio_dig_pll.clkr,
+       [LPASS_LPAAUDIO_DIG_PLL_OUT_ODD] = &lpass_lpaaudio_dig_pll_out_odd.clkr,
+};
+
+static struct gdsc lpass_pdc_hm_gdsc = {
+       .gdscr = 0x3090,
+       .pd = {
+               .name = "lpass_pdc_hm_gdsc",
+       },
+       .pwrsts = PWRSTS_OFF_ON,
+       .flags = VOTABLE,
+};
+
+static struct gdsc lpass_audio_hm_gdsc = {
+       .gdscr = 0x9090,
+       .pd = {
+               .name = "lpass_audio_hm_gdsc",
+       },
+       .pwrsts = PWRSTS_OFF_ON,
+};
+
+static struct gdsc lpass_core_hm_gdsc = {
+       .gdscr = 0x0,
+       .pd = {
+               .name = "lpass_core_hm_gdsc",
+       },
+       .pwrsts = PWRSTS_OFF_ON,
+       .flags = RETAIN_FF_ENABLE,
+};
+
+static struct gdsc *lpass_core_hm_sc7180_gdscs[] = {
+       [LPASS_CORE_HM_GDSCR] = &lpass_core_hm_gdsc,
+};
+
+static struct gdsc *lpass_audio_hm_sc7180_gdscs[] = {
+       [LPASS_PDC_HM_GDSCR] = &lpass_pdc_hm_gdsc,
+       [LPASS_AUDIO_HM_GDSCR] = &lpass_audio_hm_gdsc,
+};
+
+static struct regmap_config lpass_core_cc_sc7180_regmap_config = {
+       .reg_bits = 32,
+       .reg_stride = 4,
+       .val_bits = 32,
+       .fast_io = true,
+};
+
+static const struct qcom_cc_desc lpass_core_hm_sc7180_desc = {
+       .config = &lpass_core_cc_sc7180_regmap_config,
+       .gdscs = lpass_core_hm_sc7180_gdscs,
+       .num_gdscs = ARRAY_SIZE(lpass_core_hm_sc7180_gdscs),
+};
+
+static const struct qcom_cc_desc lpass_core_cc_sc7180_desc = {
+       .config = &lpass_core_cc_sc7180_regmap_config,
+       .clks = lpass_core_cc_sc7180_clocks,
+       .num_clks = ARRAY_SIZE(lpass_core_cc_sc7180_clocks),
+};
+
+static const struct qcom_cc_desc lpass_audio_hm_sc7180_desc = {
+       .config = &lpass_core_cc_sc7180_regmap_config,
+       .gdscs = lpass_audio_hm_sc7180_gdscs,
+       .num_gdscs = ARRAY_SIZE(lpass_audio_hm_sc7180_gdscs),
+};
+
+static int lpass_core_cc_sc7180_probe(struct platform_device *pdev)
+{
+       const struct qcom_cc_desc *desc;
+       struct regmap *regmap;
+       int 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);
+       if (ret)
+               return ret;
+
+       lpass_core_cc_sc7180_regmap_config.name = "lpass_core_cc";
+       regmap = qcom_cc_map(pdev, &lpass_core_cc_sc7180_desc);
+       if (IS_ERR(regmap))
+               return PTR_ERR(regmap);
+
+       /*
+        * Keep the CLK always-ON
+        * LPASS_AUDIO_CORE_SYSNOC_SWAY_CORE_CLK
+        */
+       regmap_update_bits(regmap, 0x24000, BIT(0), BIT(0));
+
+       /* PLL settings */
+       regmap_write(regmap, 0x1008, 0x20);
+       regmap_update_bits(regmap, 0x1014, BIT(0), BIT(0));
+
+       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);
+}
+
+static int lpass_hm_core_probe(struct platform_device *pdev)
+{
+       const struct qcom_cc_desc *desc;
+
+       lpass_core_cc_sc7180_regmap_config.name = "lpass_hm_core";
+       desc = &lpass_core_hm_sc7180_desc;
+
+       return qcom_cc_probe_by_index(pdev, 0, desc);
+}
+
+static const struct of_device_id lpass_core_cc_sc7180_match_table[] = {
+       {
+               .compatible = "qcom,sc7180-lpasshm",
+               .data = lpass_hm_core_probe,
+       },
+       {
+               .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)
+               return ret;
+
+       ret = pm_clk_add(&pdev->dev, "iface");
+       if (ret < 0) {
+               dev_err(&pdev->dev, "failed to acquire iface clock\n");
+               goto disable_pm_runtime;
+       }
+
+       clk_probe = of_device_get_match_data(&pdev->dev);
+       if (!clk_probe)
+               return -EINVAL;
+
+       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,
+       .driver = {
+               .name = "lpass_core_cc-sc7180",
+               .of_match_table = lpass_core_cc_sc7180_match_table,
+               .pm = &lpass_core_cc_pm_ops,
+       },
+};
+
+static int __init lpass_core_cc_sc7180_init(void)
+{
+       return platform_driver_register(&lpass_core_cc_sc7180_driver);
+}
+subsys_initcall(lpass_core_cc_sc7180_init);
+
+static void __exit lpass_core_cc_sc7180_exit(void)
+{
+       platform_driver_unregister(&lpass_core_cc_sc7180_driver);
+}
+module_exit(lpass_core_cc_sc7180_exit);
+
+MODULE_DESCRIPTION("QTI LPASS_CORE_CC SC7180 Driver");
+MODULE_LICENSE("GPL v2");
index 10560d963baf6217a4d403d48f44abd6f844e427..4c6c9167ef50944988291ac89ddf70203dff2fc7 100644 (file)
@@ -12,6 +12,7 @@
 #include <linux/io.h>
 #include <linux/delay.h>
 #include <linux/clk-provider.h>
+#include <linux/iopoll.h>
 #include <linux/regmap.h>
 #include <linux/clk.h>
 #include "clk.h"
@@ -86,23 +87,14 @@ static int rockchip_pll_wait_lock(struct rockchip_clk_pll *pll)
 {
        struct regmap *grf = pll->ctx->grf;
        unsigned int val;
-       int delay = 24000000, ret;
-
-       while (delay > 0) {
-               ret = regmap_read(grf, pll->lock_offset, &val);
-               if (ret) {
-                       pr_err("%s: failed to read pll lock status: %d\n",
-                              __func__, ret);
-                       return ret;
-               }
+       int ret;
 
-               if (val & BIT(pll->lock_shift))
-                       return 0;
-               delay--;
-       }
+       ret = regmap_read_poll_timeout(grf, pll->lock_offset, val,
+                                      val & BIT(pll->lock_shift), 0, 1000);
+       if (ret)
+               pr_err("%s: timeout waiting for pll to lock\n", __func__);
 
-       pr_err("%s: timeout waiting for pll to lock\n", __func__);
-       return -ETIMEDOUT;
+       return ret;
 }
 
 /**
@@ -118,12 +110,31 @@ static int rockchip_pll_wait_lock(struct rockchip_clk_pll *pll)
 #define RK3036_PLLCON1_REFDIV_SHIFT            0
 #define RK3036_PLLCON1_POSTDIV2_MASK           0x7
 #define RK3036_PLLCON1_POSTDIV2_SHIFT          6
+#define RK3036_PLLCON1_LOCK_STATUS             BIT(10)
 #define RK3036_PLLCON1_DSMPD_MASK              0x1
 #define RK3036_PLLCON1_DSMPD_SHIFT             12
+#define RK3036_PLLCON1_PWRDOWN                 BIT(13)
 #define RK3036_PLLCON2_FRAC_MASK               0xffffff
 #define RK3036_PLLCON2_FRAC_SHIFT              0
 
-#define RK3036_PLLCON1_PWRDOWN                 (1 << 13)
+static int rockchip_rk3036_pll_wait_lock(struct rockchip_clk_pll *pll)
+{
+       u32 pllcon;
+       int ret;
+
+       /*
+        * Lock time typical 250, max 500 input clock cycles @24MHz
+        * So define a very safe maximum of 1000us, meaning 24000 cycles.
+        */
+       ret = readl_relaxed_poll_timeout(pll->reg_base + RK3036_PLLCON(1),
+                                        pllcon,
+                                        pllcon & RK3036_PLLCON1_LOCK_STATUS,
+                                        0, 1000);
+       if (ret)
+               pr_err("%s: timeout waiting for pll to lock\n", __func__);
+
+       return ret;
+}
 
 static void rockchip_rk3036_pll_get_params(struct rockchip_clk_pll *pll,
                                        struct rockchip_pll_rate_table *rate)
@@ -221,7 +232,7 @@ static int rockchip_rk3036_pll_set_params(struct rockchip_clk_pll *pll,
        writel_relaxed(pllcon, pll->reg_base + RK3036_PLLCON(2));
 
        /* wait for the pll to lock */
-       ret = rockchip_pll_wait_lock(pll);
+       ret = rockchip_rk3036_pll_wait_lock(pll);
        if (ret) {
                pr_warn("%s: pll update unsuccessful, trying to restore old params\n",
                        __func__);
@@ -260,7 +271,7 @@ static int rockchip_rk3036_pll_enable(struct clk_hw *hw)
 
        writel(HIWORD_UPDATE(0, RK3036_PLLCON1_PWRDOWN, 0),
               pll->reg_base + RK3036_PLLCON(1));
-       rockchip_pll_wait_lock(pll);
+       rockchip_rk3036_pll_wait_lock(pll);
 
        return 0;
 }
@@ -589,19 +600,20 @@ static const struct clk_ops rockchip_rk3066_pll_clk_ops = {
 static int rockchip_rk3399_pll_wait_lock(struct rockchip_clk_pll *pll)
 {
        u32 pllcon;
-       int delay = 24000000;
-
-       /* poll check the lock status in rk3399 xPLLCON2 */
-       while (delay > 0) {
-               pllcon = readl_relaxed(pll->reg_base + RK3399_PLLCON(2));
-               if (pllcon & RK3399_PLLCON2_LOCK_STATUS)
-                       return 0;
+       int ret;
 
-               delay--;
-       }
+       /*
+        * Lock time typical 250, max 500 input clock cycles @24MHz
+        * So define a very safe maximum of 1000us, meaning 24000 cycles.
+        */
+       ret = readl_relaxed_poll_timeout(pll->reg_base + RK3399_PLLCON(2),
+                                        pllcon,
+                                        pllcon & RK3399_PLLCON2_LOCK_STATUS,
+                                        0, 1000);
+       if (ret)
+               pr_err("%s: timeout waiting for pll to lock\n", __func__);
 
-       pr_err("%s: timeout waiting for pll to lock\n", __func__);
-       return -ETIMEDOUT;
+       return ret;
 }
 
 static void rockchip_rk3399_pll_get_params(struct rockchip_clk_pll *pll,
index 77aebfb1d6d5b0cfaebd5b42c932ee24e12ab0cc..730020fcc7fed5ea65d61a1ff7fe27e202498d06 100644 (file)
@@ -751,6 +751,7 @@ static const char *const rk3188_critical_clocks[] __initconst = {
        "pclk_peri",
        "hclk_cpubus",
        "hclk_vio_bus",
+       "sclk_mac_lbtest",
 };
 
 static struct rockchip_clk_provider *__init rk3188_common_clk_init(struct device_node *np)
index cc2a177bbdbf44937ece153a6c0b98711baaab41..93c794695c469bd1d6282aedc2365fcfdc3d9d2f 100644 (file)
 #define RK3288_GRF_SOC_CON(x)  (0x244 + x * 4)
 #define RK3288_GRF_SOC_STATUS1 0x284
 
+enum rk3288_variant {
+       RK3288_CRU,
+       RK3288W_CRU,
+};
+
 enum rk3288_plls {
        apll, dpll, cpll, gpll, npll,
 };
@@ -425,8 +430,6 @@ static struct rockchip_clk_branch rk3288_clk_branches[] __initdata = {
        COMPOSITE(0, "aclk_vio0", mux_pll_src_cpll_gpll_usb480m_p, CLK_IGNORE_UNUSED,
                        RK3288_CLKSEL_CON(31), 6, 2, MFLAGS, 0, 5, DFLAGS,
                        RK3288_CLKGATE_CON(3), 0, GFLAGS),
-       DIV(0, "hclk_vio", "aclk_vio0", 0,
-                       RK3288_CLKSEL_CON(28), 8, 5, DFLAGS),
        COMPOSITE(0, "aclk_vio1", mux_pll_src_cpll_gpll_usb480m_p, CLK_IGNORE_UNUSED,
                        RK3288_CLKSEL_CON(31), 14, 2, MFLAGS, 8, 5, DFLAGS,
                        RK3288_CLKGATE_CON(3), 2, GFLAGS),
@@ -819,6 +822,16 @@ static struct rockchip_clk_branch rk3288_clk_branches[] __initdata = {
        INVERTER(0, "pclk_isp", "pclk_isp_in", RK3288_CLKSEL_CON(29), 3, IFLAGS),
 };
 
+static struct rockchip_clk_branch rk3288w_hclkvio_branch[] __initdata = {
+       DIV(0, "hclk_vio", "aclk_vio1", 0,
+                       RK3288_CLKSEL_CON(28), 8, 5, DFLAGS),
+};
+
+static struct rockchip_clk_branch rk3288_hclkvio_branch[] __initdata = {
+       DIV(0, "hclk_vio", "aclk_vio0", 0,
+                       RK3288_CLKSEL_CON(28), 8, 5, DFLAGS),
+};
+
 static const char *const rk3288_critical_clocks[] __initconst = {
        "aclk_cpu",
        "aclk_peri",
@@ -914,7 +927,8 @@ static struct syscore_ops rk3288_clk_syscore_ops = {
        .resume = rk3288_clk_resume,
 };
 
-static void __init rk3288_clk_init(struct device_node *np)
+static void __init rk3288_common_init(struct device_node *np,
+                                     enum rk3288_variant soc)
 {
        struct rockchip_clk_provider *ctx;
 
@@ -936,6 +950,14 @@ static void __init rk3288_clk_init(struct device_node *np)
                                   RK3288_GRF_SOC_STATUS1);
        rockchip_clk_register_branches(ctx, rk3288_clk_branches,
                                  ARRAY_SIZE(rk3288_clk_branches));
+
+       if (soc == RK3288W_CRU)
+               rockchip_clk_register_branches(ctx, rk3288w_hclkvio_branch,
+                                              ARRAY_SIZE(rk3288w_hclkvio_branch));
+       else
+               rockchip_clk_register_branches(ctx, rk3288_hclkvio_branch,
+                                              ARRAY_SIZE(rk3288_hclkvio_branch));
+
        rockchip_clk_protect_critical(rk3288_critical_clocks,
                                      ARRAY_SIZE(rk3288_critical_clocks));
 
@@ -954,4 +976,15 @@ static void __init rk3288_clk_init(struct device_node *np)
 
        rockchip_clk_of_add_provider(np, ctx);
 }
+
+static void __init rk3288_clk_init(struct device_node *np)
+{
+       rk3288_common_init(np, RK3288_CRU);
+}
 CLK_OF_DECLARE(rk3288_cru, "rockchip,rk3288-cru", rk3288_clk_init);
+
+static void __init rk3288w_clk_init(struct device_node *np)
+{
+       rk3288_common_init(np, RK3288W_CRU);
+}
+CLK_OF_DECLARE(rk3288w_cru, "rockchip,rk3288w-cru", rk3288w_clk_init);
index c186a1985bf4ebf30411e91a8e550dec4eb1ea7c..2429b7c2a8b31f359a570fa57dd0bca25778bf5f 100644 (file)
@@ -808,22 +808,22 @@ static struct rockchip_clk_branch rk3328_clk_branches[] __initdata = {
        MMC(SCLK_SDMMC_DRV, "sdmmc_drv", "clk_sdmmc",
            RK3328_SDMMC_CON0, 1),
        MMC(SCLK_SDMMC_SAMPLE, "sdmmc_sample", "clk_sdmmc",
-           RK3328_SDMMC_CON1, 0),
+           RK3328_SDMMC_CON1, 1),
 
        MMC(SCLK_SDIO_DRV, "sdio_drv", "clk_sdio",
            RK3328_SDIO_CON0, 1),
        MMC(SCLK_SDIO_SAMPLE, "sdio_sample", "clk_sdio",
-           RK3328_SDIO_CON1, 0),
+           RK3328_SDIO_CON1, 1),
 
        MMC(SCLK_EMMC_DRV, "emmc_drv", "clk_emmc",
            RK3328_EMMC_CON0, 1),
        MMC(SCLK_EMMC_SAMPLE, "emmc_sample", "clk_emmc",
-           RK3328_EMMC_CON1, 0),
+           RK3328_EMMC_CON1, 1),
 
        MMC(SCLK_SDMMC_EXT_DRV, "sdmmc_ext_drv", "clk_sdmmc_ext",
            RK3328_SDMMC_EXT_CON0, 1),
        MMC(SCLK_SDMMC_EXT_SAMPLE, "sdmmc_ext_sample", "clk_sdmmc_ext",
-           RK3328_SDMMC_EXT_CON1, 0),
+           RK3328_SDMMC_EXT_CON1, 1),
 };
 
 static const char *const rk3328_critical_clocks[] __initconst = {
index c84d5bab7ac28800ce612a47bdbd6fc66c96af8a..b95483bb6a5ecd7e5638d670df2f6251638ea756 100644 (file)
@@ -135,7 +135,7 @@ static void __init atlas6_clk_init(struct device_node *np)
 
        for (i = pll1; i < maxclk; i++) {
                atlas6_clks[i] = clk_register(NULL, atlas6_clk_hw_array[i]);
-               BUG_ON(!atlas6_clks[i]);
+               BUG_ON(IS_ERR(atlas6_clks[i]));
        }
        clk_register_clkdev(atlas6_clks[cpu], NULL, "cpu");
        clk_register_clkdev(atlas6_clks[io],  NULL, "io");
index 0b212cf2e7942126243eee266bf542525853e2d8..f180c055d33f1268883ae080cf07f20e904011ed 100644 (file)
@@ -327,16 +327,26 @@ int tegra_pll_wait_for_lock(struct tegra_clk_pll *pll)
        return clk_pll_wait_for_lock(pll);
 }
 
+static bool pllm_clk_is_gated_by_pmc(struct tegra_clk_pll *pll)
+{
+       u32 val = readl_relaxed(pll->pmc + PMC_PLLP_WB0_OVERRIDE);
+
+       return (val & PMC_PLLP_WB0_OVERRIDE_PLLM_OVERRIDE) &&
+             !(val & PMC_PLLP_WB0_OVERRIDE_PLLM_ENABLE);
+}
+
 static int clk_pll_is_enabled(struct clk_hw *hw)
 {
        struct tegra_clk_pll *pll = to_clk_pll(hw);
        u32 val;
 
-       if (pll->params->flags & TEGRA_PLLM) {
-               val = readl_relaxed(pll->pmc + PMC_PLLP_WB0_OVERRIDE);
-               if (val & PMC_PLLP_WB0_OVERRIDE_PLLM_OVERRIDE)
-                       return val & PMC_PLLP_WB0_OVERRIDE_PLLM_ENABLE ? 1 : 0;
-       }
+       /*
+        * Power Management Controller (PMC) can override the PLLM clock
+        * settings, including the enable-state. The PLLM is enabled when
+        * PLLM's CaR state is ON and when PLLM isn't gated by PMC.
+        */
+       if ((pll->params->flags & TEGRA_PLLM) && pllm_clk_is_gated_by_pmc(pll))
+               return 0;
 
        val = pll_readl_base(pll);
 
index c03cc6b85b9f1678e76a35f87c6b692c0c55a60a..3179557b5f784f5394bc196924251538a2cf601d 100644 (file)
@@ -128,7 +128,7 @@ lgm_clk_register_pll(struct lgm_clk_provider *ctx,
        pll->hw.init = &init;
 
        hw = &pll->hw;
-       ret = clk_hw_register(dev, hw);
+       ret = devm_clk_hw_register(dev, hw);
        if (ret)
                return ERR_PTR(ret);
 
index 56af0e04ec1e32c5cc36969912318f216cc1ea7f..33de600e0c38e4664a0fa667978284c1fee76d8e 100644 (file)
@@ -119,7 +119,7 @@ lgm_clk_register_mux(struct lgm_clk_provider *ctx,
        mux->hw.init = &init;
 
        hw = &mux->hw;
-       ret = clk_hw_register(dev, hw);
+       ret = devm_clk_hw_register(dev, hw);
        if (ret)
                return ERR_PTR(ret);
 
@@ -247,7 +247,7 @@ lgm_clk_register_divider(struct lgm_clk_provider *ctx,
        div->hw.init = &init;
 
        hw = &div->hw;
-       ret = clk_hw_register(dev, hw);
+       ret = devm_clk_hw_register(dev, hw);
        if (ret)
                return ERR_PTR(ret);
 
@@ -361,7 +361,7 @@ lgm_clk_register_gate(struct lgm_clk_provider *ctx,
        gate->hw.init = &init;
 
        hw = &gate->hw;
-       ret = clk_hw_register(dev, hw);
+       ret = devm_clk_hw_register(dev, hw);
        if (ret)
                return ERR_PTR(ret);
 
@@ -420,18 +420,14 @@ lgm_clk_ddiv_recalc_rate(struct clk_hw *hw, unsigned long parent_rate)
 {
        struct lgm_clk_ddiv *ddiv = to_lgm_clk_ddiv(hw);
        unsigned int div0, div1, exdiv;
-       unsigned long flags;
        u64 prate;
 
-       spin_lock_irqsave(&ddiv->lock, flags);
        div0 = lgm_get_clk_val(ddiv->membase, ddiv->reg,
                               ddiv->shift0, ddiv->width0) + 1;
        div1 = lgm_get_clk_val(ddiv->membase, ddiv->reg,
                               ddiv->shift1, ddiv->width1) + 1;
        exdiv = lgm_get_clk_val(ddiv->membase, ddiv->reg,
                                ddiv->shift2, ddiv->width2);
-       spin_unlock_irqrestore(&ddiv->lock, flags);
-
        prate = (u64)parent_rate;
        do_div(prate, div0);
        do_div(prate, div1);
@@ -548,24 +544,21 @@ lgm_clk_ddiv_round_rate(struct clk_hw *hw, unsigned long rate,
                div = div * 2;
                div = DIV_ROUND_CLOSEST_ULL((u64)div, 5);
        }
+       spin_unlock_irqrestore(&ddiv->lock, flags);
 
-       if (div <= 0) {
-               spin_unlock_irqrestore(&ddiv->lock, flags);
+       if (div <= 0)
                return *prate;
-       }
 
-       if (lgm_clk_get_ddiv_val(div, &ddiv1, &ddiv2) != 0) {
-               if (lgm_clk_get_ddiv_val(div + 1, &ddiv1, &ddiv2) != 0) {
-                       spin_unlock_irqrestore(&ddiv->lock, flags);
+       if (lgm_clk_get_ddiv_val(div, &ddiv1, &ddiv2) != 0)
+               if (lgm_clk_get_ddiv_val(div + 1, &ddiv1, &ddiv2) != 0)
                        return -EINVAL;
-               }
-       }
 
        rate64 = *prate;
        do_div(rate64, ddiv1);
        do_div(rate64, ddiv2);
 
        /* if predivide bit is enabled, modify rounded rate by factor of 2.5 */
+       spin_lock_irqsave(&ddiv->lock, flags);
        if (lgm_get_clk_val(ddiv->membase, ddiv->reg, ddiv->shift2, 1)) {
                rate64 = rate64 * 2;
                rate64 = DIV_ROUND_CLOSEST_ULL(rate64, 5);
@@ -588,19 +581,18 @@ int lgm_clk_register_ddiv(struct lgm_clk_provider *ctx,
                          unsigned int nr_clk)
 {
        struct device *dev = ctx->dev;
-       struct clk_init_data init = {};
-       struct lgm_clk_ddiv *ddiv;
        struct clk_hw *hw;
        unsigned int idx;
        int ret;
 
        for (idx = 0; idx < nr_clk; idx++, list++) {
-               ddiv = NULL;
+               struct clk_init_data init = {};
+               struct lgm_clk_ddiv *ddiv;
+
                ddiv = devm_kzalloc(dev, sizeof(*ddiv), GFP_KERNEL);
                if (!ddiv)
                        return -ENOMEM;
 
-               memset(&init, 0, sizeof(init));
                init.name = list->name;
                init.ops = &lgm_clk_ddiv_ops;
                init.flags = list->flags;
@@ -624,7 +616,7 @@ int lgm_clk_register_ddiv(struct lgm_clk_provider *ctx,
                ddiv->hw.init = &init;
 
                hw = &ddiv->hw;
-               ret = clk_hw_register(dev, hw);
+               ret = devm_clk_hw_register(dev, hw);
                if (ret) {
                        dev_err(dev, "register clk: %s failed!\n", list->name);
                        return ret;
index 030981cd2d563b96a6cd923170e588b537cc6ab8..a250a52a6192bdb48af1bd959d0363e996febcd6 100644 (file)
 #define CLK_NAND               52
 #define CLK_ECC                        53
 #define CLK_RMII_REF           54
+#define CLK_GPIO               55
 
-#define CLK_NR_CLKS           (CLK_RMII_REF + 1)
+/* system clock (part 2) */
+#define CLK_APB                        56
+#define CLK_DMAC               57
+
+#define CLK_NR_CLKS            (CLK_DMAC + 1)
 
 #endif /* __DT_BINDINGS_CLOCK_S500_CMU_H */
index 1859ce53ee388d4e21f82950cb9e072959737a47..85cf8eb5081b7d4995154506be7660ac9bd94a18 100644 (file)
 #ifndef __DT_BINDINGS_CLOCK_JZ4780_CGU_H__
 #define __DT_BINDINGS_CLOCK_JZ4780_CGU_H__
 
-#define JZ4780_CLK_EXCLK       0
-#define JZ4780_CLK_RTCLK       1
-#define JZ4780_CLK_APLL                2
-#define JZ4780_CLK_MPLL                3
-#define JZ4780_CLK_EPLL                4
-#define JZ4780_CLK_VPLL                5
-#define JZ4780_CLK_OTGPHY      6
-#define JZ4780_CLK_SCLKA       7
-#define JZ4780_CLK_CPUMUX      8
-#define JZ4780_CLK_CPU         9
-#define JZ4780_CLK_L2CACHE     10
-#define JZ4780_CLK_AHB0                11
-#define JZ4780_CLK_AHB2PMUX    12
-#define JZ4780_CLK_AHB2                13
-#define JZ4780_CLK_PCLK                14
-#define JZ4780_CLK_DDR         15
-#define JZ4780_CLK_VPU         16
-#define JZ4780_CLK_I2SPLL      17
-#define JZ4780_CLK_I2S         18
+#define JZ4780_CLK_EXCLK               0
+#define JZ4780_CLK_RTCLK               1
+#define JZ4780_CLK_APLL                        2
+#define JZ4780_CLK_MPLL                        3
+#define JZ4780_CLK_EPLL                        4
+#define JZ4780_CLK_VPLL                        5
+#define JZ4780_CLK_OTGPHY              6
+#define JZ4780_CLK_SCLKA               7
+#define JZ4780_CLK_CPUMUX              8
+#define JZ4780_CLK_CPU                 9
+#define JZ4780_CLK_L2CACHE             10
+#define JZ4780_CLK_AHB0                        11
+#define JZ4780_CLK_AHB2PMUX            12
+#define JZ4780_CLK_AHB2                        13
+#define JZ4780_CLK_PCLK                        14
+#define JZ4780_CLK_DDR                 15
+#define JZ4780_CLK_VPU                 16
+#define JZ4780_CLK_I2SPLL              17
+#define JZ4780_CLK_I2S                 18
 #define JZ4780_CLK_LCD0PIXCLK  19
 #define JZ4780_CLK_LCD1PIXCLK  20
-#define JZ4780_CLK_MSCMUX      21
-#define JZ4780_CLK_MSC0                22
-#define JZ4780_CLK_MSC1                23
-#define JZ4780_CLK_MSC2                24
-#define JZ4780_CLK_UHC         25
-#define JZ4780_CLK_SSIPLL      26
-#define JZ4780_CLK_SSI         27
-#define JZ4780_CLK_CIMMCLK     28
-#define JZ4780_CLK_PCMPLL      29
-#define JZ4780_CLK_PCM         30
-#define JZ4780_CLK_GPU         31
-#define JZ4780_CLK_HDMI                32
-#define JZ4780_CLK_BCH         33
-#define JZ4780_CLK_NEMC                34
-#define JZ4780_CLK_OTG0                35
-#define JZ4780_CLK_SSI0                36
-#define JZ4780_CLK_SMB0                37
-#define JZ4780_CLK_SMB1                38
-#define JZ4780_CLK_SCC         39
-#define JZ4780_CLK_AIC         40
-#define JZ4780_CLK_TSSI0       41
-#define JZ4780_CLK_OWI         42
-#define JZ4780_CLK_KBC         43
-#define JZ4780_CLK_SADC                44
-#define JZ4780_CLK_UART0       45
-#define JZ4780_CLK_UART1       46
-#define JZ4780_CLK_UART2       47
-#define JZ4780_CLK_UART3       48
-#define JZ4780_CLK_SSI1                49
-#define JZ4780_CLK_SSI2                50
-#define JZ4780_CLK_PDMA                51
-#define JZ4780_CLK_GPS         52
-#define JZ4780_CLK_MAC         53
-#define JZ4780_CLK_SMB2                54
-#define JZ4780_CLK_CIM         55
-#define JZ4780_CLK_LCD         56
-#define JZ4780_CLK_TVE         57
-#define JZ4780_CLK_IPU         58
-#define JZ4780_CLK_DDR0                59
-#define JZ4780_CLK_DDR1                60
-#define JZ4780_CLK_SMB3                61
-#define JZ4780_CLK_TSSI1       62
-#define JZ4780_CLK_COMPRESS    63
-#define JZ4780_CLK_AIC1                64
-#define JZ4780_CLK_GPVLC       65
-#define JZ4780_CLK_OTG1                66
-#define JZ4780_CLK_UART4       67
-#define JZ4780_CLK_AHBMON      68
-#define JZ4780_CLK_SMB4                69
-#define JZ4780_CLK_DES         70
-#define JZ4780_CLK_X2D         71
-#define JZ4780_CLK_CORE1       72
+#define JZ4780_CLK_MSCMUX              21
+#define JZ4780_CLK_MSC0                        22
+#define JZ4780_CLK_MSC1                        23
+#define JZ4780_CLK_MSC2                        24
+#define JZ4780_CLK_UHC                 25
+#define JZ4780_CLK_SSIPLL              26
+#define JZ4780_CLK_SSI                 27
+#define JZ4780_CLK_CIMMCLK             28
+#define JZ4780_CLK_PCMPLL              29
+#define JZ4780_CLK_PCM                 30
+#define JZ4780_CLK_GPU                 31
+#define JZ4780_CLK_HDMI                        32
+#define JZ4780_CLK_BCH                 33
+#define JZ4780_CLK_NEMC                        34
+#define JZ4780_CLK_OTG0                        35
+#define JZ4780_CLK_SSI0                        36
+#define JZ4780_CLK_SMB0                        37
+#define JZ4780_CLK_SMB1                        38
+#define JZ4780_CLK_SCC                 39
+#define JZ4780_CLK_AIC                 40
+#define JZ4780_CLK_TSSI0               41
+#define JZ4780_CLK_OWI                 42
+#define JZ4780_CLK_KBC                 43
+#define JZ4780_CLK_SADC                        44
+#define JZ4780_CLK_UART0               45
+#define JZ4780_CLK_UART1               46
+#define JZ4780_CLK_UART2               47
+#define JZ4780_CLK_UART3               48
+#define JZ4780_CLK_SSI1                        49
+#define JZ4780_CLK_SSI2                        50
+#define JZ4780_CLK_PDMA                        51
+#define JZ4780_CLK_GPS                 52
+#define JZ4780_CLK_MAC                 53
+#define JZ4780_CLK_SMB2                        54
+#define JZ4780_CLK_CIM                 55
+#define JZ4780_CLK_LCD                 56
+#define JZ4780_CLK_TVE                 57
+#define JZ4780_CLK_IPU                 58
+#define JZ4780_CLK_DDR0                        59
+#define JZ4780_CLK_DDR1                        60
+#define JZ4780_CLK_SMB3                        61
+#define JZ4780_CLK_TSSI1               62
+#define JZ4780_CLK_COMPRESS            63
+#define JZ4780_CLK_AIC1                        64
+#define JZ4780_CLK_GPVLC               65
+#define JZ4780_CLK_OTG1                        66
+#define JZ4780_CLK_UART4               67
+#define JZ4780_CLK_AHBMON              68
+#define JZ4780_CLK_SMB4                        69
+#define JZ4780_CLK_DES                 70
+#define JZ4780_CLK_X2D                 71
+#define JZ4780_CLK_CORE1               72
+#define JZ4780_CLK_EXCLK_DIV512        73
+#define JZ4780_CLK_RTC                 74
 
 #endif /* __DT_BINDINGS_CLOCK_JZ4780_CGU_H__ */
index 992b67b7e5e4d7f58ae611ade3aa66363ce5ab85..bdf43adc7897a88d5d0bcab94f92097da75a91de 100644 (file)
 #define GCC_MSS_Q6_MEMNOC_AXI_CLK                              128
 #define GCC_MSS_SNOC_AXI_CLK                                   129
 #define GCC_SEC_CTRL_CLK_SRC                                   130
+#define GCC_LPASS_CFG_NOC_SWAY_CLK                             131
 
 /* GCC resets */
 #define GCC_QUSB2PHY_PRIM_BCR                                  0
index 4683022829135ed679fa3e4a90184a66236d003f..df8a6f3d367e065313b909c4b9743044b1767bb7 100644 (file)
 #define GCC_USB_20_BCR                  6
 #define GCC_USB_30_BCR                 7
 #define GCC_USB_PHY_CFG_AHB2PHY_BCR    8
+#define GCC_MSS_RESTART                        9
 
 #endif
diff --git a/include/dt-bindings/clock/qcom,gpucc-sm8150.h b/include/dt-bindings/clock/qcom,gpucc-sm8150.h
new file mode 100644 (file)
index 0000000..c5b70aa
--- /dev/null
@@ -0,0 +1,33 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * Copyright (c) 2017-2020, The Linux Foundation. All rights reserved.
+ */
+
+#ifndef _DT_BINDINGS_CLK_QCOM_GPU_CC_SM8150_H
+#define _DT_BINDINGS_CLK_QCOM_GPU_CC_SM8150_H
+
+/* GPU_CC clock registers */
+#define GPU_CC_AHB_CLK                         0
+#define GPU_CC_CRC_AHB_CLK                     1
+#define GPU_CC_CX_APB_CLK                      2
+#define GPU_CC_CX_GMU_CLK                      3
+#define GPU_CC_CX_SNOC_DVM_CLK                 4
+#define GPU_CC_CXO_AON_CLK                     5
+#define GPU_CC_CXO_CLK                         6
+#define GPU_CC_GMU_CLK_SRC                     7
+#define GPU_CC_GX_GMU_CLK                      8
+#define GPU_CC_PLL1                            9
+
+/* GPU_CC Resets */
+#define GPUCC_GPU_CC_CX_BCR                    0
+#define GPUCC_GPU_CC_GFX3D_AON_BCR             1
+#define GPUCC_GPU_CC_GMU_BCR                   2
+#define GPUCC_GPU_CC_GX_BCR                    3
+#define GPUCC_GPU_CC_SPDM_BCR                  4
+#define GPUCC_GPU_CC_XO_BCR                    5
+
+/* GPU_CC GDSCRs */
+#define GPU_CX_GDSC                            0
+#define GPU_GX_GDSC                            1
+
+#endif
diff --git a/include/dt-bindings/clock/qcom,gpucc-sm8250.h b/include/dt-bindings/clock/qcom,gpucc-sm8250.h
new file mode 100644 (file)
index 0000000..dc8e387
--- /dev/null
@@ -0,0 +1,34 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * Copyright (c) 2017-2020, The Linux Foundation. All rights reserved.
+ */
+
+#ifndef _DT_BINDINGS_CLK_QCOM_GPU_CC_SM8250_H
+#define _DT_BINDINGS_CLK_QCOM_GPU_CC_SM8250_H
+
+/* GPU_CC clock registers */
+#define GPU_CC_AHB_CLK                         0
+#define GPU_CC_CRC_AHB_CLK                     1
+#define GPU_CC_CX_APB_CLK                      2
+#define GPU_CC_CX_GMU_CLK                      3
+#define GPU_CC_CX_SNOC_DVM_CLK                 4
+#define GPU_CC_CXO_AON_CLK                     5
+#define GPU_CC_CXO_CLK                         6
+#define GPU_CC_GMU_CLK_SRC                     7
+#define GPU_CC_GX_GMU_CLK                      8
+#define GPU_CC_PLL1                            9
+#define GPU_CC_HLOS1_VOTE_GPU_SMMU_CLK         10
+
+/* GPU_CC Resets */
+#define GPUCC_GPU_CC_ACD_BCR                   0
+#define GPUCC_GPU_CC_CX_BCR                    1
+#define GPUCC_GPU_CC_GFX3D_AON_BCR             2
+#define GPUCC_GPU_CC_GMU_BCR                   3
+#define GPUCC_GPU_CC_GX_BCR                    4
+#define GPUCC_GPU_CC_XO_BCR                    5
+
+/* GPU_CC GDSCRs */
+#define GPU_CX_GDSC                            0
+#define GPU_GX_GDSC                            1
+
+#endif
diff --git a/include/dt-bindings/clock/qcom,lpasscorecc-sc7180.h b/include/dt-bindings/clock/qcom,lpasscorecc-sc7180.h
new file mode 100644 (file)
index 0000000..a55d01d
--- /dev/null
@@ -0,0 +1,29 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+/*
+ * Copyright (c) 2020, The Linux Foundation. All rights reserved.
+ */
+
+#ifndef _DT_BINDINGS_CLK_QCOM_LPASS_CORE_CC_SC7180_H
+#define _DT_BINDINGS_CLK_QCOM_LPASS_CORE_CC_SC7180_H
+
+/* LPASS_CORE_CC clocks */
+#define LPASS_LPAAUDIO_DIG_PLL                         0
+#define LPASS_LPAAUDIO_DIG_PLL_OUT_ODD                 1
+#define CORE_CLK_SRC                                   2
+#define EXT_MCLK0_CLK_SRC                              3
+#define LPAIF_PRI_CLK_SRC                              4
+#define LPAIF_SEC_CLK_SRC                              5
+#define LPASS_AUDIO_CORE_CORE_CLK                      6
+#define LPASS_AUDIO_CORE_EXT_MCLK0_CLK                 7
+#define LPASS_AUDIO_CORE_LPAIF_PRI_IBIT_CLK            8
+#define LPASS_AUDIO_CORE_LPAIF_SEC_IBIT_CLK            9
+#define LPASS_AUDIO_CORE_SYSNOC_MPORT_CORE_CLK         10
+
+/* LPASS Core power domains */
+#define LPASS_CORE_HM_GDSCR                            0
+
+/* LPASS Audio power domains */
+#define LPASS_AUDIO_HM_GDSCR                           0
+#define LPASS_PDC_HM_GDSCR                             1
+
+#endif
index 0367c8c02e16e5a60e2ffd042b8e14c0a51187a0..f187e0719fd394b6a47b0f599e4dfc6c7276913f 100644 (file)
@@ -48,5 +48,7 @@
 #define X1000_CLK_SSI                  33
 #define X1000_CLK_OST                  34
 #define X1000_CLK_PDMA                 35
+#define X1000_CLK_EXCLK_DIV512 36
+#define X1000_CLK_RTC                  37
 
 #endif /* __DT_BINDINGS_CLOCK_X1000_CGU_H__ */
index 801e1d09c881ba498e9e79b6125e3cd980a1cd5e..88455376a9501888a0ae48ba4f6038cede051bc1 100644 (file)
@@ -51,5 +51,7 @@
 #define X1830_CLK_TCU                  36
 #define X1830_CLK_DTRNG                        37
 #define X1830_CLK_OST                  38
+#define X1830_CLK_EXCLK_DIV512 39
+#define X1830_CLK_RTC                  40
 
 #endif /* __DT_BINDINGS_CLOCK_X1830_CGU_H__ */
diff --git a/include/dt-bindings/reset/actions,s500-reset.h b/include/dt-bindings/reset/actions,s500-reset.h
new file mode 100644 (file)
index 0000000..f5d9417
--- /dev/null
@@ -0,0 +1,67 @@
+/* SPDX-License-Identifier: GPL-2.0+ */
+/*
+ * Device Tree binding constants for Actions Semi S500 Reset Management Unit
+ *
+ * Copyright (c) 2014 Actions Semi Inc.
+ * Copyright (c) 2020 Cristian Ciocaltea <cristian.ciocaltea@gmail.com>
+ */
+
+#ifndef __DT_BINDINGS_ACTIONS_S500_RESET_H
+#define __DT_BINDINGS_ACTIONS_S500_RESET_H
+
+#define RESET_DMAC                             0
+#define RESET_NORIF                            1
+#define RESET_DDR                              2
+#define RESET_NANDC                            3
+#define RESET_SD0                              4
+#define RESET_SD1                              5
+#define RESET_PCM1                             6
+#define RESET_DE                               7
+#define RESET_LCD                              8
+#define RESET_SD2                              9
+#define RESET_DSI                              10
+#define RESET_CSI                              11
+#define RESET_BISP                             12
+#define RESET_KEY                              13
+#define RESET_GPIO                             14
+#define RESET_AUDIO                            15
+#define RESET_PCM0                             16
+#define RESET_VDE                              17
+#define RESET_VCE                              18
+#define RESET_GPU3D                            19
+#define RESET_NIC301                           20
+#define RESET_LENS                             21
+#define RESET_PERIPHRESET                      22
+#define RESET_USB2_0                           23
+#define RESET_TVOUT                            24
+#define RESET_HDMI                             25
+#define RESET_HDCP2TX                          26
+#define RESET_UART6                            27
+#define RESET_UART0                            28
+#define RESET_UART1                            29
+#define RESET_UART2                            30
+#define RESET_SPI0                             31
+#define RESET_SPI1                             32
+#define RESET_SPI2                             33
+#define RESET_SPI3                             34
+#define RESET_I2C0                             35
+#define RESET_I2C1                             36
+#define RESET_USB3                             37
+#define RESET_UART3                            38
+#define RESET_UART4                            39
+#define RESET_UART5                            40
+#define RESET_I2C2                             41
+#define RESET_I2C3                             42
+#define RESET_ETHERNET                         43
+#define RESET_CHIPID                           44
+#define RESET_USB2_1                           45
+#define RESET_WD0RESET                         46
+#define RESET_WD1RESET                         47
+#define RESET_WD2RESET                         48
+#define RESET_WD3RESET                         49
+#define RESET_DBG0RESET                                50
+#define RESET_DBG1RESET                                51
+#define RESET_DBG2RESET                                52
+#define RESET_DBG3RESET                                53
+
+#endif /* __DT_BINDINGS_ACTIONS_S500_RESET_H */
index 6f815be99b77752e2c3c13e21da84e66f9706fe8..03a5de5f99f4a3f5bae8dac7a0f3218ee256f027 100644 (file)
@@ -1096,7 +1096,6 @@ int clk_hw_get_parent_index(struct clk_hw *hw);
 int clk_hw_set_parent(struct clk_hw *hw, struct clk_hw *new_parent);
 unsigned int __clk_get_enable_count(struct clk *clk);
 unsigned long clk_hw_get_rate(const struct clk_hw *hw);
-unsigned long __clk_get_flags(struct clk *clk);
 unsigned long clk_hw_get_flags(const struct clk_hw *hw);
 #define clk_hw_can_set_rate_parent(hw) \
        (clk_hw_get_flags((hw)) & CLK_SET_RATE_PARENT)
index 49a53a1376101750a841464ad821b1fa325fd40b..a4f82e836a7cd1e89ab0a1b0f282ce0c427ebcbb 100644 (file)
@@ -59,6 +59,7 @@
 #define AT91_PMC_PLL_UPDT              0x1C            /* PMC PLL update register [for SAM9X60] */
 #define                AT91_PMC_PLL_UPDT_UPDATE        (1 << 8)        /* Update PLL settings */
 #define                AT91_PMC_PLL_UPDT_ID            (1 << 0)        /* PLL ID */
+#define                AT91_PMC_PLL_UPDT_ID_MSK        (0xf)           /* PLL ID mask */
 #define                AT91_PMC_PLL_UPDT_STUPTIM       (0xff << 16)    /* Startup time */
 
 #define        AT91_CKGR_MOR           0x20                    /* Main Oscillator Register [not on SAM9RL] */
 #define                        AT91_PMC_PLLADIV2_ON            (1 << 12)
 #define                AT91_PMC_H32MXDIV       BIT(24)
 
+#define AT91_PMC_XTALF         0x34                    /* Main XTAL Frequency Register [SAMA7G5 only] */
+
 #define        AT91_PMC_USB            0x38                    /* USB Clock Register [some SAM9 only] */
 #define                AT91_PMC_USBS           (0x1 <<  0)             /* USB OHCI Input clock selection */
 #define                        AT91_PMC_USBS_PLLA              (0 << 0)
 #define                AT91_PMC_MOSCRCS        (1 << 17)               /* Main On-Chip RC [some SAM9] */
 #define                AT91_PMC_CFDEV          (1 << 18)               /* Clock Failure Detector Event [some SAM9] */
 #define                AT91_PMC_GCKRDY         (1 << 24)               /* Generated Clocks */
+#define                AT91_PMC_MCKXRDY        (1 << 26)               /* Master Clock x [x=1..4] Ready Status */
 #define        AT91_PMC_IMR            0x6c                    /* Interrupt Mask Register */
 
 #define AT91_PMC_FSMR          0x70            /* Fast Startup Mode Register */