Merge tag 'clk-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/clk/linux
authorLinus Torvalds <torvalds@linux-foundation.org>
Wed, 17 Jul 2019 17:07:48 +0000 (10:07 -0700)
committerLinus Torvalds <torvalds@linux-foundation.org>
Wed, 17 Jul 2019 17:07:48 +0000 (10:07 -0700)
Pull clk updates from Stephen Boyd:
 "This round of clk driver and framework updates is heavy on the driver
  update side. The two main highlights in the core framework are the
  addition of an bulk clk_get API that handles optional clks and an
  extra debugfs file that tells the developer about the current parent
  of a clk.

  The driver updates are dominated by i.MX in the diffstat, but that is
  mostly because that SoC has started converting to the clk_hw style of
  clk registration. The next big update is in the Amlogic meson clk
  driver that gained some support for audio, cpu, and temperature clks
  while fixing some PLL issues. Finally, the biggest thing that stands
  out is the conversion of a large part of the Allwinner sunxi-ng driver
  to the new clk parent scheme that uses less strings and more pointer
  comparisons to match clk parents and children up.

  In general, it looks like we have a lot of little fixes and tweaks
  here and there to clk data along with the normal addition of a handful
  of new drivers and a couple new core framework features.

  Core:
   - Add a 'clk_parent' file in clk debugfs
   - Add a clk_bulk_get_optional() API (with devm too)

  New Drivers:
   - Support gated clk controller on MIPS based BCM63XX SoCs
   - Support SiLabs Si5341 and Si5340 chips
   - Support for CPU clks on Raspberry Pi devices
   - Audsys clock driver for MediaTek MT8516 SoCs

  Updates:
   - Convert a large portion of the Allwinner sunxi-ng driver to new clk parent scheme
   - Small frequency support for SiLabs Si544 chips
   - Slow clk support for AT91 SAM9X60 SoCs
   - Remove dead code in various clk drivers (-Wunused)
   - Support for Marvell 98DX1135 SoCs
   - Get duty cycle of generic pwm clks
   - Improvement in mmc phase calculation and cleanup of some rate defintions
   - Switch i.MX6 and i.MX7 clock drivers to clk_hw based APIs
   - Add GPIO, SNVS and GIC clocks for i.MX8 drivers
   - Mark imx6sx/ul/ull/sll MMDC_P1_IPG and imx8mm DRAM_APB as critical clock
   - Correct imx7ulp nic1_bus_clk and imx8mm audio_pll2_clk clock setting
   - Add clks for new Exynos5422 Dynamic Memory Controller driver
   - Clock definition for Exynos4412 Mali
   - Add CMM (Color Management Module) clocks on Renesas R-Car H3, M3-N, E3, and D3
   - Add TPU (Timer Pulse Unit / PWM) clocks on Renesas RZ/G2M
   - Support for 32 bit clock IDs in TI's sci-clks for J721e SoCs
   - TI clock probing done from DT by default instead of firmware
   - Fix Amlogic Meson mpll fractional part and spread sprectrum issues
   - Add Amlogic meson8 audio clocks
   - Add Amlogic g12a temperature sensors clocks
   - Add Amlogic g12a and g12b cpu clocks
   - Add TPU (Timer Pulse Unit / PWM) clocks on Renesas R-Car H3, M3-W, and M3-N
   - Add CMM (Color Management Module) clocks on Renesas R-Car M3-W
   - Add Clock Domain support on Renesas RZ/N1"

* tag 'clk-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/clk/linux: (190 commits)
  clk: consoldiate the __clk_get_hw() declarations
  clk: sprd: Add check for return value of sprd_clk_regmap_init()
  clk: lochnagar: Update DT binding doc to include the primary SPDIF MCLK
  clk: Add Si5341/Si5340 driver
  dt-bindings: clock: Add silabs,si5341
  clk: clk-si544: Implement small frequency change support
  clk: add BCM63XX gated clock controller driver
  devicetree: document the BCM63XX gated clock bindings
  clk: at91: sckc: use dedicated functions to unregister clock
  clk: at91: sckc: improve error path for sama5d4 sck registration
  clk: at91: sckc: remove unnecessary line
  clk: at91: sckc: improve error path for sam9x5 sck register
  clk: at91: sckc: add support to free slow clock osclillator
  clk: at91: sckc: add support to free slow rc oscillator
  clk: at91: sckc: add support to free slow oscillator
  clk: rockchip: export HDMIPHY clock on rk3228
  clk: rockchip: add watchdog pclk on rk3328
  clk: rockchip: add clock id for hdmi_phy special clock on rk3228
  clk: rockchip: add clock id for watchdog pclk on rk3328
  clk: at91: sckc: add support for SAM9X60
  ...

148 files changed:
Documentation/devicetree/bindings/arm/mediatek/mediatek,audsys.txt
Documentation/devicetree/bindings/clock/allwinner,sun4i-a10-ccu.yaml [new file with mode: 0644]
Documentation/devicetree/bindings/clock/amlogic,gxbb-clkc.txt
Documentation/devicetree/bindings/clock/at91-clock.txt
Documentation/devicetree/bindings/clock/brcm,bcm63xx-clocks.txt [new file with mode: 0644]
Documentation/devicetree/bindings/clock/cirrus,lochnagar.txt
Documentation/devicetree/bindings/clock/mvebu-core-clock.txt
Documentation/devicetree/bindings/clock/qcom,gpucc.txt
Documentation/devicetree/bindings/clock/renesas,r9a06g032-sysctrl.txt
Documentation/devicetree/bindings/clock/silabs,si5341.txt [new file with mode: 0644]
Documentation/devicetree/bindings/clock/sunxi-ccu.txt [deleted file]
Documentation/driver-api/driver-model/devres.rst
arch/mips/include/asm/mach-jz4740/clock.h [deleted file]
arch/mips/jz4740/board-qi_lb60.c
arch/mips/jz4740/platform.c
arch/mips/jz4740/pm.c
arch/mips/jz4740/time.c
drivers/clk/Kconfig
drivers/clk/Makefile
drivers/clk/at91/sckc.c
drivers/clk/bcm/Kconfig
drivers/clk/bcm/Makefile
drivers/clk/bcm/clk-bcm2835.c
drivers/clk/bcm/clk-bcm63xx-gate.c [new file with mode: 0644]
drivers/clk/bcm/clk-raspberrypi.c [new file with mode: 0644]
drivers/clk/clk-bulk.c
drivers/clk/clk-cdce706.c
drivers/clk/clk-devres.c
drivers/clk/clk-lochnagar.c
drivers/clk/clk-pwm.c
drivers/clk/clk-qoriq.c
drivers/clk/clk-si5341.c [new file with mode: 0644]
drivers/clk/clk-si544.c
drivers/clk/clk.c
drivers/clk/clk.h
drivers/clk/imx/clk-busy.c
drivers/clk/imx/clk-cpu.c
drivers/clk/imx/clk-fixup-div.c
drivers/clk/imx/clk-fixup-mux.c
drivers/clk/imx/clk-gate-exclusive.c
drivers/clk/imx/clk-gate2.c
drivers/clk/imx/clk-imx6q.c
drivers/clk/imx/clk-imx6sl.c
drivers/clk/imx/clk-imx6sll.c
drivers/clk/imx/clk-imx6sx.c
drivers/clk/imx/clk-imx6ul.c
drivers/clk/imx/clk-imx7d.c
drivers/clk/imx/clk-imx7ulp.c
drivers/clk/imx/clk-imx8mm.c
drivers/clk/imx/clk-imx8mq.c
drivers/clk/imx/clk-pfd.c
drivers/clk/imx/clk-pllv3.c
drivers/clk/imx/clk.c
drivers/clk/imx/clk.h
drivers/clk/ingenic/Makefile
drivers/clk/ingenic/cgu.c
drivers/clk/ingenic/cgu.h
drivers/clk/ingenic/jz4725b-cgu.c
drivers/clk/ingenic/jz4740-cgu.c
drivers/clk/ingenic/jz4770-cgu.c
drivers/clk/ingenic/jz4780-cgu.c
drivers/clk/ingenic/pm.c [new file with mode: 0644]
drivers/clk/ingenic/pm.h [new file with mode: 0644]
drivers/clk/keystone/Kconfig
drivers/clk/keystone/sci-clk.c
drivers/clk/mediatek/Kconfig
drivers/clk/mediatek/Makefile
drivers/clk/mediatek/clk-mt8183.c
drivers/clk/mediatek/clk-mt8516-aud.c [new file with mode: 0644]
drivers/clk/mediatek/clk-mt8516.c
drivers/clk/meson/axg.c
drivers/clk/meson/clk-mpll.c
drivers/clk/meson/clk-mpll.h
drivers/clk/meson/g12a.c
drivers/clk/meson/g12a.h
drivers/clk/meson/gxbb.c
drivers/clk/meson/meson-eeclk.c
drivers/clk/meson/meson-eeclk.h
drivers/clk/meson/meson8b.c
drivers/clk/meson/meson8b.h
drivers/clk/mmp/clk-frac.c
drivers/clk/mvebu/kirkwood.c
drivers/clk/qcom/gcc-msm8996.c
drivers/clk/qcom/gcc-qcs404.c
drivers/clk/qcom/gdsc.c
drivers/clk/renesas/clk-div6.c
drivers/clk/renesas/clk-mstp.c
drivers/clk/renesas/r8a774a1-cpg-mssr.c
drivers/clk/renesas/r8a7795-cpg-mssr.c
drivers/clk/renesas/r8a7796-cpg-mssr.c
drivers/clk/renesas/r8a77965-cpg-mssr.c
drivers/clk/renesas/r8a77990-cpg-mssr.c
drivers/clk/renesas/r8a77995-cpg-mssr.c
drivers/clk/renesas/r9a06g032-clocks.c
drivers/clk/renesas/renesas-cpg-mssr.c
drivers/clk/rockchip/clk-mmc-phase.c
drivers/clk/rockchip/clk-px30.c
drivers/clk/rockchip/clk-rk3228.c
drivers/clk/rockchip/clk-rk3288.c
drivers/clk/rockchip/clk-rk3328.c
drivers/clk/rockchip/clk-rk3368.c
drivers/clk/rockchip/clk-rk3399.c
drivers/clk/rockchip/clk.h
drivers/clk/samsung/clk-exynos4.c
drivers/clk/samsung/clk-exynos5420.c
drivers/clk/samsung/clk-exynos5433.c
drivers/clk/socfpga/clk-s10.c
drivers/clk/sprd/common.c
drivers/clk/sprd/sc9860-clk.c
drivers/clk/sunxi-ng/ccu-sun4i-a10.c
drivers/clk/sunxi-ng/ccu-sun50i-a64.c
drivers/clk/sunxi-ng/ccu-sun50i-h6-r.c
drivers/clk/sunxi-ng/ccu-sun50i-h6.c
drivers/clk/sunxi-ng/ccu-sun5i.c
drivers/clk/sunxi-ng/ccu-sun6i-a31.c
drivers/clk/sunxi-ng/ccu-sun8i-a23.c
drivers/clk/sunxi-ng/ccu-sun8i-a33.c
drivers/clk/sunxi-ng/ccu-sun8i-h3.c
drivers/clk/sunxi-ng/ccu-sun8i-r.c
drivers/clk/sunxi-ng/ccu-sun8i-r40.c
drivers/clk/sunxi-ng/ccu-sun8i-v3s.c
drivers/clk/sunxi-ng/ccu-sun9i-a80-usb.c
drivers/clk/sunxi-ng/ccu-suniv-f1c100s.c
drivers/clk/sunxi-ng/ccu_common.c
drivers/clk/sunxi-ng/ccu_gate.h
drivers/clk/sunxi/clk-sunxi.c
drivers/clk/tegra/clk-tegra210.c
drivers/clk/ti/divider.c
drivers/clk/ti/gate.c
drivers/clk/ti/mux.c
drivers/firmware/raspberrypi.c
drivers/firmware/ti_sci.c
drivers/firmware/ti_sci.h
include/dt-bindings/clock/exynos4.h
include/dt-bindings/clock/exynos5420.h
include/dt-bindings/clock/g12a-clkc.h
include/dt-bindings/clock/imx8mm-clock.h
include/dt-bindings/clock/imx8mq-clock.h
include/dt-bindings/clock/meson8b-clkc.h
include/dt-bindings/clock/mt8516-clk.h
include/dt-bindings/clock/qcom,gcc-qcs404.h
include/dt-bindings/clock/qcom,gpucc-msm8998.h [new file with mode: 0644]
include/dt-bindings/clock/rk3228-cru.h
include/dt-bindings/clock/rk3328-cru.h
include/dt-bindings/clock/stratix10-clock.h
include/linux/clk-provider.h
include/linux/clk.h
include/linux/soc/ti/ti_sci_protocol.h

index f3cef1a..07c9d81 100644 (file)
@@ -10,6 +10,7 @@ Required Properties:
        - "mediatek,mt7622-audsys", "syscon"
        - "mediatek,mt7623-audsys", "mediatek,mt2701-audsys", "syscon"
        - "mediatek,mt8183-audiosys", "syscon"
+       - "mediatek,mt8516-audsys", "syscon"
 - #clock-cells: Must be 1
 
 The AUDSYS controller uses the common clk binding from
diff --git a/Documentation/devicetree/bindings/clock/allwinner,sun4i-a10-ccu.yaml b/Documentation/devicetree/bindings/clock/allwinner,sun4i-a10-ccu.yaml
new file mode 100644 (file)
index 0000000..c935405
--- /dev/null
@@ -0,0 +1,141 @@
+# SPDX-License-Identifier: GPL-2.0
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/phy/allwinner,sun4i-a10-ccu.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: Allwinner Clock Control Unit Device Tree Bindings
+
+maintainers:
+  - Chen-Yu Tsai <wens@csie.org>
+  - Maxime Ripard <maxime.ripard@bootlin.com>
+
+properties:
+  "#clock-cells":
+    const: 1
+
+  "#reset-cells":
+    const: 1
+
+  compatible:
+    enum:
+      - allwinner,sun4i-a10-ccu
+      - allwinner,sun5i-a10s-ccu
+      - allwinner,sun5i-a13-ccu
+      - allwinner,sun6i-a31-ccu
+      - allwinner,sun7i-a20-ccu
+      - allwinner,sun8i-a23-ccu
+      - allwinner,sun8i-a33-ccu
+      - allwinner,sun8i-a83t-ccu
+      - allwinner,sun8i-a83t-r-ccu
+      - allwinner,sun8i-h3-ccu
+      - allwinner,sun8i-h3-r-ccu
+      - allwinner,sun8i-r40-ccu
+      - allwinner,sun8i-v3s-ccu
+      - allwinner,sun9i-a80-ccu
+      - allwinner,sun50i-a64-ccu
+      - allwinner,sun50i-a64-r-ccu
+      - allwinner,sun50i-h5-ccu
+      - allwinner,sun50i-h6-ccu
+      - allwinner,sun50i-h6-r-ccu
+      - allwinner,suniv-f1c100s-ccu
+      - nextthing,gr8-ccu
+
+  reg:
+    maxItems: 1
+
+  clocks:
+    minItems: 2
+    maxItems: 4
+    items:
+      - description: High Frequency Oscillator (usually at 24MHz)
+      - description: Low Frequency Oscillator (usually at 32kHz)
+      - description: Internal Oscillator
+      - description: Peripherals PLL
+
+  clock-names:
+    minItems: 2
+    maxItems: 4
+    items:
+      - const: hosc
+      - const: losc
+      - const: iosc
+      - const: pll-periph
+
+required:
+  - "#clock-cells"
+  - "#reset-cells"
+  - compatible
+  - reg
+  - clocks
+  - clock-names
+
+if:
+  properties:
+    compatible:
+      enum:
+        - allwinner,sun8i-a83t-r-ccu
+        - allwinner,sun8i-h3-r-ccu
+        - allwinner,sun50i-a64-r-ccu
+        - allwinner,sun50i-h6-r-ccu
+
+then:
+  properties:
+    clocks:
+      minItems: 4
+      maxItems: 4
+
+    clock-names:
+      minItems: 4
+      maxItems: 4
+
+else:
+  if:
+    properties:
+      compatible:
+        const: allwinner,sun50i-h6-ccu
+
+  then:
+    properties:
+      clocks:
+        minItems: 3
+        maxItems: 3
+
+      clock-names:
+        minItems: 3
+        maxItems: 3
+
+  else:
+    properties:
+      clocks:
+        minItems: 2
+        maxItems: 2
+
+      clock-names:
+        minItems: 2
+        maxItems: 2
+
+additionalProperties: false
+
+examples:
+  - |
+    ccu: clock@1c20000 {
+        compatible = "allwinner,sun8i-h3-ccu";
+        reg = <0x01c20000 0x400>;
+        clocks = <&osc24M>, <&osc32k>;
+        clock-names = "hosc", "losc";
+        #clock-cells = <1>;
+        #reset-cells = <1>;
+    };
+
+  - |
+    r_ccu: clock@1f01400 {
+        compatible = "allwinner,sun50i-a64-r-ccu";
+        reg = <0x01f01400 0x100>;
+        clocks = <&osc24M>, <&osc32k>, <&iosc>, <&ccu 11>;
+        clock-names = "hosc", "losc", "iosc", "pll-periph";
+        #clock-cells = <1>;
+        #reset-cells = <1>;
+    };
+
+...
index 5c8b105..6eaa520 100644 (file)
@@ -10,6 +10,7 @@ Required Properties:
                "amlogic,gxl-clkc" for GXL and GXM SoC,
                "amlogic,axg-clkc" for AXG SoC.
                "amlogic,g12a-clkc" for G12A SoC.
+               "amlogic,g12b-clkc" for G12B SoC.
 - clocks : list of clock phandle, one for each entry clock-names.
 - clock-names : should contain the following:
   * "xtal": the platform xtal
index b520280..13f45db 100644 (file)
@@ -9,10 +9,11 @@ Slow Clock controller:
 Required properties:
 - compatible : shall be one of the following:
        "atmel,at91sam9x5-sckc",
-       "atmel,sama5d3-sckc" or
-       "atmel,sama5d4-sckc":
+       "atmel,sama5d3-sckc",
+       "atmel,sama5d4-sckc" or
+       "microchip,sam9x60-sckc":
                at91 SCKC (Slow Clock Controller)
-- #clock-cells : shall be 0.
+- #clock-cells : shall be 1 for "microchip,sam9x60-sckc" otherwise shall be 0.
 - clocks : shall be the input parent clock phandle for the clock.
 
 Optional properties:
diff --git a/Documentation/devicetree/bindings/clock/brcm,bcm63xx-clocks.txt b/Documentation/devicetree/bindings/clock/brcm,bcm63xx-clocks.txt
new file mode 100644 (file)
index 0000000..3041657
--- /dev/null
@@ -0,0 +1,22 @@
+Gated Clock Controller Bindings for MIPS based BCM63XX SoCs
+
+Required properties:
+- compatible: must be one of:
+        "brcm,bcm3368-clocks"
+        "brcm,bcm6328-clocks"
+        "brcm,bcm6358-clocks"
+        "brcm,bcm6362-clocks"
+        "brcm,bcm6368-clocks"
+        "brcm,bcm63268-clocks"
+
+- reg: Address and length of the register set
+- #clock-cells: must be <1>
+
+
+Example:
+
+clkctl: clock-controller@10000004 {
+       compatible = "brcm,bcm6328-clocks";
+       reg = <0x10000004 0x4>;
+       #clock-cells = <1>;
+};
index b8d8ef3..52a064c 100644 (file)
@@ -40,6 +40,7 @@ Optional properties:
        input audio clocks from host system.
      - ln-psia1-mclk, ln-psia2-mclk : Optional input audio clocks from
        external connector.
+     - ln-spdif-mclk : Optional input audio clock from SPDIF.
      - ln-spdif-clkout : Optional input audio clock from SPDIF.
      - ln-adat-mclk : Optional input audio clock from ADAT.
      - ln-pmic-32k : On board fixed clock.
index 796c260..d8f5c49 100644 (file)
@@ -59,6 +59,7 @@ Required properties:
        "marvell,dove-core-clock" - for Dove SoC core clocks
        "marvell,kirkwood-core-clock" - for Kirkwood SoC (except mv88f6180)
        "marvell,mv88f6180-core-clock" - for Kirkwood MV88f6180 SoC
+       "marvell,mv98dx1135-core-clock" - for Kirkwood 98dx1135 SoC
        "marvell,mv88f5181-core-clock" - for Orion MV88F5181 SoC
        "marvell,mv88f5182-core-clock" - for Orion MV88F5182 SoC
        "marvell,mv88f5281-core-clock" - for Orion MV88F5281 SoC
index 4e5215e..269afe8 100644 (file)
@@ -2,13 +2,15 @@ Qualcomm Graphics Clock & Reset Controller Binding
 --------------------------------------------------
 
 Required properties :
-- compatible : shall contain "qcom,sdm845-gpucc"
+- compatible : shall contain "qcom,sdm845-gpucc" or "qcom,msm8998-gpucc"
 - reg : shall contain base register location and length
 - #clock-cells : from common clock binding, shall contain 1
 - #reset-cells : from common reset binding, shall contain 1
 - #power-domain-cells : from generic power domain binding, shall contain 1
 - clocks : shall contain the XO clock
+          shall contain the gpll0 out main clock (msm8998)
 - clock-names : shall be "xo"
+               shall be "gpll0" (msm8998)
 
 Example:
        gpucc: clock-controller@5090000 {
index d60b997..aed713c 100644 (file)
@@ -13,6 +13,7 @@ Required Properties:
        - external (optional) RGMII_REFCLK
   - clock-names: Must be:
         clock-names = "mclk", "rtc", "jtag", "rgmii_ref_ext";
+  - #power-domain-cells: Must be 0
 
 Examples
 --------
@@ -27,6 +28,7 @@ Examples
                clocks = <&ext_mclk>, <&ext_rtc_clk>,
                                <&ext_jtag_clk>, <&ext_rgmii_ref>;
                clock-names = "mclk", "rtc", "jtag", "rgmii_ref_ext";
+               #power-domain-cells = <0>;
        };
 
   - Other nodes can use the clocks provided by SYSCTRL as in:
@@ -38,6 +40,7 @@ Examples
                interrupts = <GIC_SPI 6 IRQ_TYPE_LEVEL_HIGH>;
                reg-shift = <2>;
                reg-io-width = <4>;
-               clocks = <&sysctrl R9A06G032_CLK_UART0>;
-               clock-names = "baudclk";
+               clocks = <&sysctrl R9A06G032_CLK_UART0>, <&sysctrl R9A06G032_HCLK_UART0>;
+               clock-names = "baudclk", "apb_pclk";
+               power-domains = <&sysctrl>;
        };
diff --git a/Documentation/devicetree/bindings/clock/silabs,si5341.txt b/Documentation/devicetree/bindings/clock/silabs,si5341.txt
new file mode 100644 (file)
index 0000000..a70c333
--- /dev/null
@@ -0,0 +1,162 @@
+Binding for Silicon Labs Si5341 and Si5340 programmable i2c clock generator.
+
+Reference
+[1] Si5341 Data Sheet
+    https://www.silabs.com/documents/public/data-sheets/Si5341-40-D-DataSheet.pdf
+[2] Si5341 Reference Manual
+    https://www.silabs.com/documents/public/reference-manuals/Si5341-40-D-RM.pdf
+
+The Si5341 and Si5340 are programmable i2c clock generators with up to 10 output
+clocks. The chip contains a PLL that sources 5 (or 4) multisynth clocks, which
+in turn can be directed to any of the 10 (or 4) outputs through a divider.
+The internal structure of the clock generators can be found in [2].
+
+The driver can be used in "as is" mode, reading the current settings from the
+chip at boot, in case you have a (pre-)programmed device. If the PLL is not
+configured when the driver probes, it assumes the driver must fully initialize
+it.
+
+The device type, speed grade and revision are determined runtime by probing.
+
+The driver currently only supports XTAL input mode, and does not support any
+fancy input configurations. They can still be programmed into the chip and
+the driver will leave them "as is".
+
+==I2C device node==
+
+Required properties:
+- compatible: shall be one of the following:
+       "silabs,si5340" - Si5340 A/B/C/D
+       "silabs,si5341" - Si5341 A/B/C/D
+- reg: i2c device address, usually 0x74
+- #clock-cells: from common clock binding; shall be set to 2.
+       The first value is "0" for outputs, "1" for synthesizers.
+       The second value is the output or synthesizer index.
+- clocks: from common clock binding; list of parent clock  handles,
+       corresponding to inputs. Use a fixed clock for the "xtal" input.
+       At least one must be present.
+- clock-names: One of: "xtal", "in0", "in1", "in2"
+- vdd-supply: Regulator node for VDD
+
+Optional properties:
+- vdda-supply: Regulator node for VDDA
+- vdds-supply: Regulator node for VDDS
+- silabs,pll-m-num, silabs,pll-m-den: Numerator and denominator for PLL
+  feedback divider. Must be such that the PLL output is in the valid range. For
+  example, to create 14GHz from a 48MHz xtal, use m-num=14000 and m-den=48. Only
+  the fraction matters, using 3500 and 12 will deliver the exact same result.
+  If these are not specified, and the PLL is not yet programmed when the driver
+  probes, the PLL will be set to 14GHz.
+- silabs,reprogram: When present, the driver will always assume the device must
+  be initialized, and always performs the soft-reset routine. Since this will
+  temporarily stop all output clocks, don't do this if the chip is generating
+  the CPU clock for example.
+- interrupts: Interrupt for INTRb pin.
+- #address-cells: shall be set to 1.
+- #size-cells: shall be set to 0.
+
+
+== Child nodes: Outputs ==
+
+The child nodes list the output clocks.
+
+Each of the clock outputs can be overwritten individually by using a child node.
+If a child node for a clock output is not set, the configuration remains
+unchanged.
+
+Required child node properties:
+- reg: number of clock output.
+
+Optional child node properties:
+- vdd-supply: Regulator node for VDD for this output. The driver selects default
+       values for common-mode and amplitude based on the voltage.
+- silabs,format: Output format, one of:
+       1 = differential (defaults to LVDS levels)
+       2 = low-power (defaults to HCSL levels)
+       4 = LVCMOS
+- silabs,common-mode: Manually override output common mode, see [2] for values
+- silabs,amplitude: Manually override output amplitude, see [2] for values
+- silabs,synth-master: boolean. If present, this output is allowed to change the
+       multisynth frequency dynamically.
+- silabs,silabs,disable-high: boolean. If set, the clock output is driven HIGH
+       when disabled, otherwise it's driven LOW.
+
+==Example==
+
+/* 48MHz reference crystal */
+ref48: ref48M {
+       compatible = "fixed-clock";
+       #clock-cells = <0>;
+       clock-frequency = <48000000>;
+};
+
+i2c-master-node {
+       /* Programmable clock (for logic) */
+       si5341: clock-generator@74 {
+               reg = <0x74>;
+               compatible = "silabs,si5341";
+               #clock-cells = <2>;
+               #address-cells = <1>;
+               #size-cells = <0>;
+               clocks = <&ref48>;
+               clock-names = "xtal";
+
+               silabs,pll-m-num = <14000>; /* PLL at 14.0 GHz */
+               silabs,pll-m-den = <48>;
+               silabs,reprogram; /* Chips are not programmed, always reset */
+
+               out@0 {
+                       reg = <0>;
+                       silabs,format = <1>; /* LVDS 3v3 */
+                       silabs,common-mode = <3>;
+                       silabs,amplitude = <3>;
+                       silabs,synth-master;
+               };
+
+               /*
+                * Output 6 configuration:
+                *  LVDS 1v8
+                */
+               out@6 {
+                       reg = <6>;
+                       silabs,format = <1>; /* LVDS 1v8 */
+                       silabs,common-mode = <13>;
+                       silabs,amplitude = <3>;
+               };
+
+               /*
+                * Output 8 configuration:
+                *  HCSL 3v3
+                */
+               out@8 {
+                       reg = <8>;
+                       silabs,format = <2>;
+                       silabs,common-mode = <11>;
+                       silabs,amplitude = <3>;
+               };
+       };
+};
+
+some-video-node {
+       /* Standard clock bindings */
+       clock-names = "pixel";
+       clocks = <&si5341 0 7>; /* Output 7 */
+
+       /* Set output 7 to use syntesizer 3 as its parent */
+       assigned-clocks = <&si5341 0 7>, <&si5341 1 3>;
+       assigned-clock-parents = <&si5341 1 3>;
+       /* Set output 7 to 148.5 MHz using a synth frequency of 594 MHz */
+       assigned-clock-rates = <148500000>, <594000000>;
+};
+
+some-audio-node {
+       clock-names = "i2s-clk";
+       clocks = <&si5341 0 0>;
+       /*
+        * since output 0 is a synth-master, the synth will be automatically set
+        * to an appropriate frequency when the audio driver requests another
+        * frequency. We give control over synth 2 to this output here.
+        */
+       assigned-clocks = <&si5341 0 0>;
+       assigned-clock-parents = <&si5341 1 2>;
+};
diff --git a/Documentation/devicetree/bindings/clock/sunxi-ccu.txt b/Documentation/devicetree/bindings/clock/sunxi-ccu.txt
deleted file mode 100644 (file)
index e3bd88a..0000000
+++ /dev/null
@@ -1,62 +0,0 @@
-Allwinner Clock Control Unit Binding
-------------------------------------
-
-Required properties :
-- compatible: must contain one of the following compatibles:
-               - "allwinner,sun4i-a10-ccu"
-               - "allwinner,sun5i-a10s-ccu"
-               - "allwinner,sun5i-a13-ccu"
-               - "allwinner,sun6i-a31-ccu"
-               - "allwinner,sun7i-a20-ccu"
-               - "allwinner,sun8i-a23-ccu"
-               - "allwinner,sun8i-a33-ccu"
-               - "allwinner,sun8i-a83t-ccu"
-               - "allwinner,sun8i-a83t-r-ccu"
-               - "allwinner,sun8i-h3-ccu"
-               - "allwinner,sun8i-h3-r-ccu"
-+              - "allwinner,sun8i-r40-ccu"
-               - "allwinner,sun8i-v3s-ccu"
-               - "allwinner,sun9i-a80-ccu"
-               - "allwinner,sun50i-a64-ccu"
-               - "allwinner,sun50i-a64-r-ccu"
-               - "allwinner,sun50i-h5-ccu"
-               - "allwinner,sun50i-h6-ccu"
-               - "allwinner,sun50i-h6-r-ccu"
-               - "allwinner,suniv-f1c100s-ccu"
-               - "nextthing,gr8-ccu"
-
-- reg: Must contain the registers base address and length
-- clocks: phandle to the oscillators feeding the CCU. Two are needed:
-  - "hosc": the high frequency oscillator (usually at 24MHz)
-  - "losc": the low frequency oscillator (usually at 32kHz)
-           On the A83T, this is the internal 16MHz oscillator divided by 512
-- clock-names: Must contain the clock names described just above
-- #clock-cells : must contain 1
-- #reset-cells : must contain 1
-
-For the main CCU on H6, one more clock is needed:
-- "iosc": the SoC's internal frequency oscillator
-
-For the PRCM CCUs on A83T/H3/A64/H6, two more clocks are needed:
-- "pll-periph": the SoC's peripheral PLL from the main CCU
-- "iosc": the SoC's internal frequency oscillator
-
-Example for generic CCU:
-ccu: clock@1c20000 {
-       compatible = "allwinner,sun8i-h3-ccu";
-       reg = <0x01c20000 0x400>;
-       clocks = <&osc24M>, <&osc32k>;
-       clock-names = "hosc", "losc";
-       #clock-cells = <1>;
-       #reset-cells = <1>;
-};
-
-Example for PRCM CCU:
-r_ccu: clock@1f01400 {
-       compatible = "allwinner,sun50i-a64-r-ccu";
-       reg = <0x01f01400 0x100>;
-       clocks = <&osc24M>, <&osc32k>, <&iosc>, <&ccu CLK_PLL_PERIPH0>;
-       clock-names = "hosc", "losc", "iosc", "pll-periph";
-       #clock-cells = <1>;
-       #reset-cells = <1>;
-};
index 4ac9912..a100bef 100644 (file)
@@ -246,6 +246,10 @@ CLOCK
   devm_clk_get()
   devm_clk_get_optional()
   devm_clk_put()
+  devm_clk_bulk_get()
+  devm_clk_bulk_get_all()
+  devm_clk_bulk_get_optional()
+  devm_get_clk_from_childl()
   devm_clk_hw_register()
   devm_of_clk_add_hw_provider()
   devm_clk_hw_register_clkdev()
diff --git a/arch/mips/include/asm/mach-jz4740/clock.h b/arch/mips/include/asm/mach-jz4740/clock.h
deleted file mode 100644 (file)
index 600d505..0000000
+++ /dev/null
@@ -1,22 +0,0 @@
-/* SPDX-License-Identifier: GPL-2.0-or-later */
-/*
- *  Copyright (C) 2010, Lars-Peter Clausen <lars@metafoo.de>
- */
-
-#ifndef __ASM_JZ4740_CLOCK_H__
-#define __ASM_JZ4740_CLOCK_H__
-
-enum jz4740_wait_mode {
-       JZ4740_WAIT_MODE_IDLE,
-       JZ4740_WAIT_MODE_SLEEP,
-};
-
-void jz4740_clock_set_wait_mode(enum jz4740_wait_mode mode);
-
-void jz4740_clock_suspend(void);
-void jz4740_clock_resume(void);
-
-void jz4740_clock_udc_enable_auto_suspend(void);
-void jz4740_clock_udc_disable_auto_suspend(void);
-
-#endif
index daed44e..4a7a80c 100644 (file)
@@ -37,8 +37,6 @@
 
 #include <asm/mach-jz4740/platform.h>
 
-#include "clock.h"
-
 /* GPIOs */
 #define QI_LB60_GPIO_KEYOUT(x)         (JZ_GPIO_PORTC(10) + (x))
 #define QI_LB60_GPIO_KEYIN(x)          (JZ_GPIO_PORTD(18) + (x))
index 4b89abb..c74c99f 100644 (file)
@@ -21,8 +21,6 @@
 #include <linux/serial_core.h>
 #include <linux/serial_8250.h>
 
-#include "clock.h"
-
 /* USB Device Controller */
 struct platform_device jz4740_udc_xceiv_device = {
        .name = "usb_phy_generic",
index bbdd2b8..f9b551f 100644 (file)
@@ -9,21 +9,13 @@
 #include <linux/delay.h>
 #include <linux/suspend.h>
 
-#include <asm/mach-jz4740/clock.h>
-
 static int jz4740_pm_enter(suspend_state_t state)
 {
-       jz4740_clock_suspend();
-
-       jz4740_clock_set_wait_mode(JZ4740_WAIT_MODE_SLEEP);
-
        __asm__(".set\tmips3\n\t"
                "wait\n\t"
                ".set\tmips0");
 
-       jz4740_clock_set_wait_mode(JZ4740_WAIT_MODE_IDLE);
 
-       jz4740_clock_resume();
 
        return 0;
 }
index a3260c7..cb768e5 100644 (file)
 #include <linux/clockchips.h>
 #include <linux/sched_clock.h>
 
-#include <asm/mach-jz4740/clock.h>
 #include <asm/mach-jz4740/irq.h>
 #include <asm/mach-jz4740/timer.h>
 #include <asm/time.h>
 
-#include "clock.h"
-
 #define TIMER_CLOCKEVENT 0
 #define TIMER_CLOCKSOURCE 1
 
index 7376af2..801fa1c 100644 (file)
@@ -90,6 +90,17 @@ config COMMON_CLK_SCPI
          This driver uses SCPI Message Protocol to interact with the
          firmware providing all the clock controls.
 
+config COMMON_CLK_SI5341
+       tristate "Clock driver for SiLabs 5341 and 5340 A/B/C/D devices"
+       depends on I2C
+       select REGMAP_I2C
+       help
+         This driver supports Silicon Labs Si5341 and Si5340 programmable clock
+         generators. Not all features of these chips are currently supported
+         by the driver, in particular it only supports XTAL input. The chip can
+         be pre-programmed to support other configurations and features not yet
+         implemented in the driver.
+
 config COMMON_CLK_SI5351
        tristate "Clock driver for SiLabs 5351A/B/C"
        depends on I2C
@@ -214,7 +225,7 @@ config CLK_QORIQ
 
 config COMMON_CLK_XGENE
        bool "Clock driver for APM XGene SoC"
-       default y
+       default ARCH_XGENE
        depends on ARM64 || COMPILE_TEST
        ---help---
          Sypport for the APM X-Gene SoC reference, PLL, and device clocks.
index 9ef4305..0cad760 100644 (file)
@@ -49,6 +49,7 @@ obj-$(CONFIG_COMMON_CLK_HI655X)               += clk-hi655x.o
 obj-$(CONFIG_COMMON_CLK_S2MPS11)       += clk-s2mps11.o
 obj-$(CONFIG_COMMON_CLK_SCMI)           += clk-scmi.o
 obj-$(CONFIG_COMMON_CLK_SCPI)           += clk-scpi.o
+obj-$(CONFIG_COMMON_CLK_SI5341)                += clk-si5341.o
 obj-$(CONFIG_COMMON_CLK_SI5351)                += clk-si5351.o
 obj-$(CONFIG_COMMON_CLK_SI514)         += clk-si514.o
 obj-$(CONFIG_COMMON_CLK_SI544)         += clk-si544.o
index 45526f5..9bfe9a2 100644 (file)
                                 SLOW_CLOCK_FREQ)
 
 #define        AT91_SCKC_CR                    0x00
-#define                AT91_SCKC_RCEN          (1 << 0)
-#define                AT91_SCKC_OSC32EN       (1 << 1)
-#define                AT91_SCKC_OSC32BYP      (1 << 2)
-#define                AT91_SCKC_OSCSEL        (1 << 3)
+
+struct clk_slow_bits {
+       u32 cr_rcen;
+       u32 cr_osc32en;
+       u32 cr_osc32byp;
+       u32 cr_oscsel;
+};
 
 struct clk_slow_osc {
        struct clk_hw hw;
        void __iomem *sckcr;
+       const struct clk_slow_bits *bits;
        unsigned long startup_usec;
 };
 
@@ -34,6 +38,7 @@ struct clk_slow_osc {
 struct clk_sama5d4_slow_osc {
        struct clk_hw hw;
        void __iomem *sckcr;
+       const struct clk_slow_bits *bits;
        unsigned long startup_usec;
        bool prepared;
 };
@@ -43,6 +48,7 @@ struct clk_sama5d4_slow_osc {
 struct clk_slow_rc_osc {
        struct clk_hw hw;
        void __iomem *sckcr;
+       const struct clk_slow_bits *bits;
        unsigned long frequency;
        unsigned long accuracy;
        unsigned long startup_usec;
@@ -53,6 +59,7 @@ struct clk_slow_rc_osc {
 struct clk_sam9x5_slow {
        struct clk_hw hw;
        void __iomem *sckcr;
+       const struct clk_slow_bits *bits;
        u8 parent;
 };
 
@@ -64,10 +71,10 @@ static int clk_slow_osc_prepare(struct clk_hw *hw)
        void __iomem *sckcr = osc->sckcr;
        u32 tmp = readl(sckcr);
 
-       if (tmp & (AT91_SCKC_OSC32BYP | AT91_SCKC_OSC32EN))
+       if (tmp & (osc->bits->cr_osc32byp | osc->bits->cr_osc32en))
                return 0;
 
-       writel(tmp | AT91_SCKC_OSC32EN, sckcr);
+       writel(tmp | osc->bits->cr_osc32en, sckcr);
 
        usleep_range(osc->startup_usec, osc->startup_usec + 1);
 
@@ -80,10 +87,10 @@ static void clk_slow_osc_unprepare(struct clk_hw *hw)
        void __iomem *sckcr = osc->sckcr;
        u32 tmp = readl(sckcr);
 
-       if (tmp & AT91_SCKC_OSC32BYP)
+       if (tmp & osc->bits->cr_osc32byp)
                return;
 
-       writel(tmp & ~AT91_SCKC_OSC32EN, sckcr);
+       writel(tmp & ~osc->bits->cr_osc32en, sckcr);
 }
 
 static int clk_slow_osc_is_prepared(struct clk_hw *hw)
@@ -92,10 +99,10 @@ static int clk_slow_osc_is_prepared(struct clk_hw *hw)
        void __iomem *sckcr = osc->sckcr;
        u32 tmp = readl(sckcr);
 
-       if (tmp & AT91_SCKC_OSC32BYP)
+       if (tmp & osc->bits->cr_osc32byp)
                return 1;
 
-       return !!(tmp & AT91_SCKC_OSC32EN);
+       return !!(tmp & osc->bits->cr_osc32en);
 }
 
 static const struct clk_ops slow_osc_ops = {
@@ -109,7 +116,8 @@ at91_clk_register_slow_osc(void __iomem *sckcr,
                           const char *name,
                           const char *parent_name,
                           unsigned long startup,
-                          bool bypass)
+                          bool bypass,
+                          const struct clk_slow_bits *bits)
 {
        struct clk_slow_osc *osc;
        struct clk_hw *hw;
@@ -132,10 +140,11 @@ at91_clk_register_slow_osc(void __iomem *sckcr,
        osc->hw.init = &init;
        osc->sckcr = sckcr;
        osc->startup_usec = startup;
+       osc->bits = bits;
 
        if (bypass)
-               writel((readl(sckcr) & ~AT91_SCKC_OSC32EN) | AT91_SCKC_OSC32BYP,
-                      sckcr);
+               writel((readl(sckcr) & ~osc->bits->cr_osc32en) |
+                                       osc->bits->cr_osc32byp, sckcr);
 
        hw = &osc->hw;
        ret = clk_hw_register(NULL, &osc->hw);
@@ -147,6 +156,14 @@ at91_clk_register_slow_osc(void __iomem *sckcr,
        return hw;
 }
 
+static void at91_clk_unregister_slow_osc(struct clk_hw *hw)
+{
+       struct clk_slow_osc *osc = to_clk_slow_osc(hw);
+
+       clk_hw_unregister(hw);
+       kfree(osc);
+}
+
 static unsigned long clk_slow_rc_osc_recalc_rate(struct clk_hw *hw,
                                                 unsigned long parent_rate)
 {
@@ -168,7 +185,7 @@ static int clk_slow_rc_osc_prepare(struct clk_hw *hw)
        struct clk_slow_rc_osc *osc = to_clk_slow_rc_osc(hw);
        void __iomem *sckcr = osc->sckcr;
 
-       writel(readl(sckcr) | AT91_SCKC_RCEN, sckcr);
+       writel(readl(sckcr) | osc->bits->cr_rcen, sckcr);
 
        usleep_range(osc->startup_usec, osc->startup_usec + 1);
 
@@ -180,14 +197,14 @@ static void clk_slow_rc_osc_unprepare(struct clk_hw *hw)
        struct clk_slow_rc_osc *osc = to_clk_slow_rc_osc(hw);
        void __iomem *sckcr = osc->sckcr;
 
-       writel(readl(sckcr) & ~AT91_SCKC_RCEN, sckcr);
+       writel(readl(sckcr) & ~osc->bits->cr_rcen, sckcr);
 }
 
 static int clk_slow_rc_osc_is_prepared(struct clk_hw *hw)
 {
        struct clk_slow_rc_osc *osc = to_clk_slow_rc_osc(hw);
 
-       return !!(readl(osc->sckcr) & AT91_SCKC_RCEN);
+       return !!(readl(osc->sckcr) & osc->bits->cr_rcen);
 }
 
 static const struct clk_ops slow_rc_osc_ops = {
@@ -203,7 +220,8 @@ at91_clk_register_slow_rc_osc(void __iomem *sckcr,
                              const char *name,
                              unsigned long frequency,
                              unsigned long accuracy,
-                             unsigned long startup)
+                             unsigned long startup,
+                             const struct clk_slow_bits *bits)
 {
        struct clk_slow_rc_osc *osc;
        struct clk_hw *hw;
@@ -225,6 +243,7 @@ at91_clk_register_slow_rc_osc(void __iomem *sckcr,
 
        osc->hw.init = &init;
        osc->sckcr = sckcr;
+       osc->bits = bits;
        osc->frequency = frequency;
        osc->accuracy = accuracy;
        osc->startup_usec = startup;
@@ -239,6 +258,14 @@ at91_clk_register_slow_rc_osc(void __iomem *sckcr,
        return hw;
 }
 
+static void at91_clk_unregister_slow_rc_osc(struct clk_hw *hw)
+{
+       struct clk_slow_rc_osc *osc = to_clk_slow_rc_osc(hw);
+
+       clk_hw_unregister(hw);
+       kfree(osc);
+}
+
 static int clk_sam9x5_slow_set_parent(struct clk_hw *hw, u8 index)
 {
        struct clk_sam9x5_slow *slowck = to_clk_sam9x5_slow(hw);
@@ -250,14 +277,14 @@ static int clk_sam9x5_slow_set_parent(struct clk_hw *hw, u8 index)
 
        tmp = readl(sckcr);
 
-       if ((!index && !(tmp & AT91_SCKC_OSCSEL)) ||
-           (index && (tmp & AT91_SCKC_OSCSEL)))
+       if ((!index && !(tmp & slowck->bits->cr_oscsel)) ||
+           (index && (tmp & slowck->bits->cr_oscsel)))
                return 0;
 
        if (index)
-               tmp |= AT91_SCKC_OSCSEL;
+               tmp |= slowck->bits->cr_oscsel;
        else
-               tmp &= ~AT91_SCKC_OSCSEL;
+               tmp &= ~slowck->bits->cr_oscsel;
 
        writel(tmp, sckcr);
 
@@ -270,7 +297,7 @@ static u8 clk_sam9x5_slow_get_parent(struct clk_hw *hw)
 {
        struct clk_sam9x5_slow *slowck = to_clk_sam9x5_slow(hw);
 
-       return !!(readl(slowck->sckcr) & AT91_SCKC_OSCSEL);
+       return !!(readl(slowck->sckcr) & slowck->bits->cr_oscsel);
 }
 
 static const struct clk_ops sam9x5_slow_ops = {
@@ -282,7 +309,8 @@ static struct clk_hw * __init
 at91_clk_register_sam9x5_slow(void __iomem *sckcr,
                              const char *name,
                              const char **parent_names,
-                             int num_parents)
+                             int num_parents,
+                             const struct clk_slow_bits *bits)
 {
        struct clk_sam9x5_slow *slowck;
        struct clk_hw *hw;
@@ -304,7 +332,8 @@ at91_clk_register_sam9x5_slow(void __iomem *sckcr,
 
        slowck->hw.init = &init;
        slowck->sckcr = sckcr;
-       slowck->parent = !!(readl(sckcr) & AT91_SCKC_OSCSEL);
+       slowck->bits = bits;
+       slowck->parent = !!(readl(sckcr) & slowck->bits->cr_oscsel);
 
        hw = &slowck->hw;
        ret = clk_hw_register(NULL, &slowck->hw);
@@ -316,22 +345,33 @@ at91_clk_register_sam9x5_slow(void __iomem *sckcr,
        return hw;
 }
 
+static void at91_clk_unregister_sam9x5_slow(struct clk_hw *hw)
+{
+       struct clk_sam9x5_slow *slowck = to_clk_sam9x5_slow(hw);
+
+       clk_hw_unregister(hw);
+       kfree(slowck);
+}
+
 static void __init at91sam9x5_sckc_register(struct device_node *np,
-                                           unsigned int rc_osc_startup_us)
+                                           unsigned int rc_osc_startup_us,
+                                           const struct clk_slow_bits *bits)
 {
        const char *parent_names[2] = { "slow_rc_osc", "slow_osc" };
        void __iomem *regbase = of_iomap(np, 0);
        struct device_node *child = NULL;
        const char *xtal_name;
-       struct clk_hw *hw;
+       struct clk_hw *slow_rc, *slow_osc, *slowck;
        bool bypass;
+       int ret;
 
        if (!regbase)
                return;
 
-       hw = at91_clk_register_slow_rc_osc(regbase, parent_names[0], 32768,
-                                          50000000, rc_osc_startup_us);
-       if (IS_ERR(hw))
+       slow_rc = at91_clk_register_slow_rc_osc(regbase, parent_names[0],
+                                               32768, 50000000,
+                                               rc_osc_startup_us, bits);
+       if (IS_ERR(slow_rc))
                return;
 
        xtal_name = of_clk_get_parent_name(np, 0);
@@ -339,7 +379,7 @@ static void __init at91sam9x5_sckc_register(struct device_node *np,
                /* DT backward compatibility */
                child = of_get_compatible_child(np, "atmel,at91sam9x5-clk-slow-osc");
                if (!child)
-                       return;
+                       goto unregister_slow_rc;
 
                xtal_name = of_clk_get_parent_name(child, 0);
                bypass = of_property_read_bool(child, "atmel,osc-bypass");
@@ -350,38 +390,133 @@ static void __init at91sam9x5_sckc_register(struct device_node *np,
        }
 
        if (!xtal_name)
-               return;
-
-       hw = at91_clk_register_slow_osc(regbase, parent_names[1], xtal_name,
-                                       1200000, bypass);
-       if (IS_ERR(hw))
-               return;
+               goto unregister_slow_rc;
 
-       hw = at91_clk_register_sam9x5_slow(regbase, "slowck", parent_names, 2);
-       if (IS_ERR(hw))
-               return;
+       slow_osc = at91_clk_register_slow_osc(regbase, parent_names[1],
+                                             xtal_name, 1200000, bypass, bits);
+       if (IS_ERR(slow_osc))
+               goto unregister_slow_rc;
 
-       of_clk_add_hw_provider(np, of_clk_hw_simple_get, hw);
+       slowck = at91_clk_register_sam9x5_slow(regbase, "slowck", parent_names,
+                                              2, bits);
+       if (IS_ERR(slowck))
+               goto unregister_slow_osc;
 
        /* DT backward compatibility */
        if (child)
-               of_clk_add_hw_provider(child, of_clk_hw_simple_get, hw);
+               ret = of_clk_add_hw_provider(child, of_clk_hw_simple_get,
+                                            slowck);
+       else
+               ret = of_clk_add_hw_provider(np, of_clk_hw_simple_get, slowck);
+
+       if (WARN_ON(ret))
+               goto unregister_slowck;
+
+       return;
+
+unregister_slowck:
+       at91_clk_unregister_sam9x5_slow(slowck);
+unregister_slow_osc:
+       at91_clk_unregister_slow_osc(slow_osc);
+unregister_slow_rc:
+       at91_clk_unregister_slow_rc_osc(slow_rc);
 }
 
+static const struct clk_slow_bits at91sam9x5_bits = {
+       .cr_rcen = BIT(0),
+       .cr_osc32en = BIT(1),
+       .cr_osc32byp = BIT(2),
+       .cr_oscsel = BIT(3),
+};
+
 static void __init of_at91sam9x5_sckc_setup(struct device_node *np)
 {
-       at91sam9x5_sckc_register(np, 75);
+       at91sam9x5_sckc_register(np, 75, &at91sam9x5_bits);
 }
 CLK_OF_DECLARE(at91sam9x5_clk_sckc, "atmel,at91sam9x5-sckc",
               of_at91sam9x5_sckc_setup);
 
 static void __init of_sama5d3_sckc_setup(struct device_node *np)
 {
-       at91sam9x5_sckc_register(np, 500);
+       at91sam9x5_sckc_register(np, 500, &at91sam9x5_bits);
 }
 CLK_OF_DECLARE(sama5d3_clk_sckc, "atmel,sama5d3-sckc",
               of_sama5d3_sckc_setup);
 
+static const struct clk_slow_bits at91sam9x60_bits = {
+       .cr_osc32en = BIT(1),
+       .cr_osc32byp = BIT(2),
+       .cr_oscsel = BIT(24),
+};
+
+static void __init of_sam9x60_sckc_setup(struct device_node *np)
+{
+       void __iomem *regbase = of_iomap(np, 0);
+       struct clk_hw_onecell_data *clk_data;
+       struct clk_hw *slow_rc, *slow_osc;
+       const char *xtal_name;
+       const char *parent_names[2] = { "slow_rc_osc", "slow_osc" };
+       bool bypass;
+       int ret;
+
+       if (!regbase)
+               return;
+
+       slow_rc = clk_hw_register_fixed_rate(NULL, parent_names[0], NULL, 0,
+                                            32768);
+       if (IS_ERR(slow_rc))
+               return;
+
+       xtal_name = of_clk_get_parent_name(np, 0);
+       if (!xtal_name)
+               goto unregister_slow_rc;
+
+       bypass = of_property_read_bool(np, "atmel,osc-bypass");
+       slow_osc = at91_clk_register_slow_osc(regbase, parent_names[1],
+                                             xtal_name, 5000000, bypass,
+                                             &at91sam9x60_bits);
+       if (IS_ERR(slow_osc))
+               goto unregister_slow_rc;
+
+       clk_data = kzalloc(sizeof(*clk_data) + (2 * sizeof(struct clk_hw *)),
+                          GFP_KERNEL);
+       if (!clk_data)
+               goto unregister_slow_osc;
+
+       /* MD_SLCK and TD_SLCK. */
+       clk_data->num = 2;
+       clk_data->hws[0] = clk_hw_register_fixed_rate(NULL, "md_slck",
+                                                     parent_names[0],
+                                                     0, 32768);
+       if (IS_ERR(clk_data->hws[0]))
+               goto clk_data_free;
+
+       clk_data->hws[1] = at91_clk_register_sam9x5_slow(regbase, "td_slck",
+                                                        parent_names, 2,
+                                                        &at91sam9x60_bits);
+       if (IS_ERR(clk_data->hws[1]))
+               goto unregister_md_slck;
+
+       ret = of_clk_add_hw_provider(np, of_clk_hw_onecell_get, clk_data);
+       if (WARN_ON(ret))
+               goto unregister_td_slck;
+
+       return;
+
+unregister_td_slck:
+       at91_clk_unregister_sam9x5_slow(clk_data->hws[1]);
+unregister_md_slck:
+       clk_hw_unregister(clk_data->hws[0]);
+clk_data_free:
+       kfree(clk_data);
+unregister_slow_osc:
+       at91_clk_unregister_slow_osc(slow_osc);
+unregister_slow_rc:
+       clk_hw_unregister(slow_rc);
+}
+CLK_OF_DECLARE(sam9x60_clk_sckc, "microchip,sam9x60-sckc",
+              of_sam9x60_sckc_setup);
+
 static int clk_sama5d4_slow_osc_prepare(struct clk_hw *hw)
 {
        struct clk_sama5d4_slow_osc *osc = to_clk_sama5d4_slow_osc(hw);
@@ -393,7 +528,7 @@ static int clk_sama5d4_slow_osc_prepare(struct clk_hw *hw)
         * Assume that if it has already been selected (for example by the
         * bootloader), enough time has aready passed.
         */
-       if ((readl(osc->sckcr) & AT91_SCKC_OSCSEL)) {
+       if ((readl(osc->sckcr) & osc->bits->cr_oscsel)) {
                osc->prepared = true;
                return 0;
        }
@@ -416,33 +551,35 @@ static const struct clk_ops sama5d4_slow_osc_ops = {
        .is_prepared = clk_sama5d4_slow_osc_is_prepared,
 };
 
+static const struct clk_slow_bits at91sama5d4_bits = {
+       .cr_oscsel = BIT(3),
+};
+
 static void __init of_sama5d4_sckc_setup(struct device_node *np)
 {
        void __iomem *regbase = of_iomap(np, 0);
-       struct clk_hw *hw;
+       struct clk_hw *slow_rc, *slowck;
        struct clk_sama5d4_slow_osc *osc;
        struct clk_init_data init;
        const char *xtal_name;
        const char *parent_names[2] = { "slow_rc_osc", "slow_osc" };
-       bool bypass;
        int ret;
 
        if (!regbase)
                return;
 
-       hw = clk_hw_register_fixed_rate_with_accuracy(NULL, parent_names[0],
-                                                     NULL, 0, 32768,
-                                                     250000000);
-       if (IS_ERR(hw))
+       slow_rc = clk_hw_register_fixed_rate_with_accuracy(NULL,
+                                                          parent_names[0],
+                                                          NULL, 0, 32768,
+                                                          250000000);
+       if (IS_ERR(slow_rc))
                return;
 
        xtal_name = of_clk_get_parent_name(np, 0);
 
-       bypass = of_property_read_bool(np, "atmel,osc-bypass");
-
        osc = kzalloc(sizeof(*osc), GFP_KERNEL);
        if (!osc)
-               return;
+               goto unregister_slow_rc;
 
        init.name = parent_names[1];
        init.ops = &sama5d4_slow_osc_ops;
@@ -453,22 +590,32 @@ static void __init of_sama5d4_sckc_setup(struct device_node *np)
        osc->hw.init = &init;
        osc->sckcr = regbase;
        osc->startup_usec = 1200000;
+       osc->bits = &at91sama5d4_bits;
 
-       if (bypass)
-               writel((readl(regbase) | AT91_SCKC_OSC32BYP), regbase);
-
-       hw = &osc->hw;
        ret = clk_hw_register(NULL, &osc->hw);
-       if (ret) {
-               kfree(osc);
-               return;
-       }
-
-       hw = at91_clk_register_sam9x5_slow(regbase, "slowck", parent_names, 2);
-       if (IS_ERR(hw))
-               return;
-
-       of_clk_add_hw_provider(np, of_clk_hw_simple_get, hw);
+       if (ret)
+               goto free_slow_osc_data;
+
+       slowck = at91_clk_register_sam9x5_slow(regbase, "slowck",
+                                              parent_names, 2,
+                                              &at91sama5d4_bits);
+       if (IS_ERR(slowck))
+               goto unregister_slow_osc;
+
+       ret = of_clk_add_hw_provider(np, of_clk_hw_simple_get, slowck);
+       if (WARN_ON(ret))
+               goto unregister_slowck;
+
+       return;
+
+unregister_slowck:
+       at91_clk_unregister_sam9x5_slow(slowck);
+unregister_slow_osc:
+       clk_hw_unregister(&osc->hw);
+free_slow_osc_data:
+       kfree(osc);
+unregister_slow_rc:
+       clk_hw_unregister(slow_rc);
 }
 CLK_OF_DECLARE(sama5d4_clk_sckc, "atmel,sama5d4-sckc",
               of_sama5d4_sckc_setup);
index 29ee7b7..8c83977 100644 (file)
@@ -1,4 +1,13 @@
 # SPDX-License-Identifier: GPL-2.0-only
+config CLK_BCM2835
+       bool "Broadcom BCM2835 clock support"
+       depends on ARCH_BCM2835 || ARCH_BRCMSTB || COMPILE_TEST
+       depends on COMMON_CLK
+       default ARCH_BCM2835 || ARCH_BRCMSTB
+       help
+         Enable common clock framework support for Broadcom BCM2835
+         SoCs.
+
 config CLK_BCM_63XX
        bool "Broadcom BCM63xx clock support"
        depends on ARCH_BCM_63XX || COMPILE_TEST
@@ -8,6 +17,14 @@ config CLK_BCM_63XX
          Enable common clock framework support for Broadcom BCM63xx DSL SoCs
          based on the ARM architecture
 
+config CLK_BCM_63XX_GATE
+       bool "Broadcom BCM63xx gated clock support"
+       depends on BMIPS_GENERIC || COMPILE_TEST
+       default BMIPS_GENERIC
+       help
+         Enable common clock framework support for Broadcom BCM63xx DSL SoCs
+         based on the MIPS architecture
+
 config CLK_BCM_KONA
        bool "Broadcom Kona CCU clock support"
        depends on ARCH_BCM_MOBILE || COMPILE_TEST
@@ -64,3 +81,10 @@ config CLK_BCM_SR
        default ARCH_BCM_IPROC
        help
          Enable common clock framework support for the Broadcom Stingray SoC
+
+config CLK_RASPBERRYPI
+       tristate "Raspberry Pi firmware based clock support"
+       depends on RASPBERRYPI_FIRMWARE || (COMPILE_TEST && !RASPBERRYPI_FIRMWARE)
+       help
+         Enable common clock framework support for Raspberry Pi's firmware
+         dependent clocks
index 002661d..0070ddf 100644 (file)
@@ -1,12 +1,14 @@
 # SPDX-License-Identifier: GPL-2.0
 obj-$(CONFIG_CLK_BCM_63XX)     += clk-bcm63xx.o
+obj-$(CONFIG_CLK_BCM_63XX_GATE)        += clk-bcm63xx-gate.o
 obj-$(CONFIG_CLK_BCM_KONA)     += clk-kona.o
 obj-$(CONFIG_CLK_BCM_KONA)     += clk-kona-setup.o
 obj-$(CONFIG_CLK_BCM_KONA)     += clk-bcm281xx.o
 obj-$(CONFIG_CLK_BCM_KONA)     += clk-bcm21664.o
 obj-$(CONFIG_COMMON_CLK_IPROC) += clk-iproc-armpll.o clk-iproc-pll.o clk-iproc-asiu.o
-obj-$(CONFIG_ARCH_BCM2835)     += clk-bcm2835.o
-obj-$(CONFIG_ARCH_BCM2835)     += clk-bcm2835-aux.o
+obj-$(CONFIG_CLK_BCM2835)      += clk-bcm2835.o
+obj-$(CONFIG_CLK_BCM2835)      += clk-bcm2835-aux.o
+obj-$(CONFIG_CLK_RASPBERRYPI)  += clk-raspberrypi.o
 obj-$(CONFIG_ARCH_BCM_53573)   += clk-bcm53573-ilp.o
 obj-$(CONFIG_CLK_BCM_CYGNUS)   += clk-cygnus.o
 obj-$(CONFIG_CLK_BCM_HR2)      += clk-hr2.o
index 770bb01..867ae3c 100644 (file)
@@ -1651,30 +1651,10 @@ static const struct bcm2835_clk_desc clk_desc_array[] = {
                .fixed_divider = 1,
                .flags = CLK_SET_RATE_PARENT),
 
-       /* PLLB is used for the ARM's clock. */
-       [BCM2835_PLLB]          = REGISTER_PLL(
-               .name = "pllb",
-               .cm_ctrl_reg = CM_PLLB,
-               .a2w_ctrl_reg = A2W_PLLB_CTRL,
-               .frac_reg = A2W_PLLB_FRAC,
-               .ana_reg_base = A2W_PLLB_ANA0,
-               .reference_enable_mask = A2W_XOSC_CTRL_PLLB_ENABLE,
-               .lock_mask = CM_LOCK_FLOCKB,
-
-               .ana = &bcm2835_ana_default,
-
-               .min_rate = 600000000u,
-               .max_rate = 3000000000u,
-               .max_fb_rate = BCM2835_MAX_FB_RATE),
-       [BCM2835_PLLB_ARM]      = REGISTER_PLL_DIV(
-               .name = "pllb_arm",
-               .source_pll = "pllb",
-               .cm_reg = CM_PLLB,
-               .a2w_reg = A2W_PLLB_ARM,
-               .load_mask = CM_PLLB_LOADARM,
-               .hold_mask = CM_PLLB_HOLDARM,
-               .fixed_divider = 1,
-               .flags = CLK_SET_RATE_PARENT),
+       /*
+        * PLLB is used for the ARM's clock. Controlled by firmware, see
+        * clk-raspberrypi.c.
+        */
 
        /*
         * PLLC is the core PLL, used to drive the core VPU clock.
diff --git a/drivers/clk/bcm/clk-bcm63xx-gate.c b/drivers/clk/bcm/clk-bcm63xx-gate.c
new file mode 100644 (file)
index 0000000..9e1dcd4
--- /dev/null
@@ -0,0 +1,238 @@
+// SPDX-License-Identifier: GPL-2.0
+
+#include <linux/clk-provider.h>
+#include <linux/init.h>
+#include <linux/of.h>
+#include <linux/of_device.h>
+#include <linux/platform_device.h>
+
+struct clk_bcm63xx_table_entry {
+       const char * const name;
+       u8 bit;
+       unsigned long flags;
+};
+
+struct clk_bcm63xx_hw {
+       void __iomem *regs;
+       spinlock_t lock;
+
+       struct clk_hw_onecell_data data;
+};
+
+static const struct clk_bcm63xx_table_entry bcm3368_clocks[] = {
+       { .name = "mac", .bit = 3, },
+       { .name = "tc", .bit = 5, },
+       { .name = "us_top", .bit = 6, },
+       { .name = "ds_top", .bit = 7, },
+       { .name = "acm", .bit = 8, },
+       { .name = "spi", .bit = 9, },
+       { .name = "usbs", .bit = 10, },
+       { .name = "bmu", .bit = 11, },
+       { .name = "pcm", .bit = 12, },
+       { .name = "ntp", .bit = 13, },
+       { .name = "acp_b", .bit = 14, },
+       { .name = "acp_a", .bit = 15, },
+       { .name = "emusb", .bit = 17, },
+       { .name = "enet0", .bit = 18, },
+       { .name = "enet1", .bit = 19, },
+       { .name = "usbsu", .bit = 20, },
+       { .name = "ephy", .bit = 21, },
+       { },
+};
+
+static const struct clk_bcm63xx_table_entry bcm6328_clocks[] = {
+       { .name = "phy_mips", .bit = 0, },
+       { .name = "adsl_qproc", .bit = 1, },
+       { .name = "adsl_afe", .bit = 2, },
+       { .name = "adsl", .bit = 3, },
+       { .name = "mips", .bit = 4, .flags = CLK_IS_CRITICAL, },
+       { .name = "sar", .bit = 5, },
+       { .name = "pcm", .bit = 6, },
+       { .name = "usbd", .bit = 7, },
+       { .name = "usbh", .bit = 8, },
+       { .name = "hsspi", .bit = 9, },
+       { .name = "pcie", .bit = 10, },
+       { .name = "robosw", .bit = 11, },
+       { },
+};
+
+static const struct clk_bcm63xx_table_entry bcm6358_clocks[] = {
+       { .name = "enet", .bit = 4, },
+       { .name = "adslphy", .bit = 5, },
+       { .name = "pcm", .bit = 8, },
+       { .name = "spi", .bit = 9, },
+       { .name = "usbs", .bit = 10, },
+       { .name = "sar", .bit = 11, },
+       { .name = "emusb", .bit = 17, },
+       { .name = "enet0", .bit = 18, },
+       { .name = "enet1", .bit = 19, },
+       { .name = "usbsu", .bit = 20, },
+       { .name = "ephy", .bit = 21, },
+       { },
+};
+
+static const struct clk_bcm63xx_table_entry bcm6362_clocks[] = {
+       { .name = "adsl_qproc", .bit = 1, },
+       { .name = "adsl_afe", .bit = 2, },
+       { .name = "adsl", .bit = 3, },
+       { .name = "mips", .bit = 4, .flags = CLK_IS_CRITICAL, },
+       { .name = "wlan_ocp", .bit = 5, },
+       { .name = "swpkt_usb", .bit = 7, },
+       { .name = "swpkt_sar", .bit = 8, },
+       { .name = "sar", .bit = 9, },
+       { .name = "robosw", .bit = 10, },
+       { .name = "pcm", .bit = 11, },
+       { .name = "usbd", .bit = 12, },
+       { .name = "usbh", .bit = 13, },
+       { .name = "ipsec", .bit = 14, },
+       { .name = "spi", .bit = 15, },
+       { .name = "hsspi", .bit = 16, },
+       { .name = "pcie", .bit = 17, },
+       { .name = "fap", .bit = 18, },
+       { .name = "phymips", .bit = 19, },
+       { .name = "nand", .bit = 20, },
+       { },
+};
+
+static const struct clk_bcm63xx_table_entry bcm6368_clocks[] = {
+       { .name = "vdsl_qproc", .bit = 2, },
+       { .name = "vdsl_afe", .bit = 3, },
+       { .name = "vdsl_bonding", .bit = 4, },
+       { .name = "vdsl", .bit = 5, },
+       { .name = "phymips", .bit = 6, },
+       { .name = "swpkt_usb", .bit = 7, },
+       { .name = "swpkt_sar", .bit = 8, },
+       { .name = "spi", .bit = 9, },
+       { .name = "usbd", .bit = 10, },
+       { .name = "sar", .bit = 11, },
+       { .name = "robosw", .bit = 12, },
+       { .name = "utopia", .bit = 13, },
+       { .name = "pcm", .bit = 14, },
+       { .name = "usbh", .bit = 15, },
+       { .name = "disable_gless", .bit = 16, },
+       { .name = "nand", .bit = 17, },
+       { .name = "ipsec", .bit = 18, },
+       { },
+};
+
+static const struct clk_bcm63xx_table_entry bcm63268_clocks[] = {
+       { .name = "disable_gless", .bit = 0, },
+       { .name = "vdsl_qproc", .bit = 1, },
+       { .name = "vdsl_afe", .bit = 2, },
+       { .name = "vdsl", .bit = 3, },
+       { .name = "mips", .bit = 4, .flags = CLK_IS_CRITICAL, },
+       { .name = "wlan_ocp", .bit = 5, },
+       { .name = "dect", .bit = 6, },
+       { .name = "fap0", .bit = 7, },
+       { .name = "fap1", .bit = 8, },
+       { .name = "sar", .bit = 9, },
+       { .name = "robosw", .bit = 10, },
+       { .name = "pcm", .bit = 11, },
+       { .name = "usbd", .bit = 12, },
+       { .name = "usbh", .bit = 13, },
+       { .name = "ipsec", .bit = 14, },
+       { .name = "spi", .bit = 15, },
+       { .name = "hsspi", .bit = 16, },
+       { .name = "pcie", .bit = 17, },
+       { .name = "phymips", .bit = 18, },
+       { .name = "gmac", .bit = 19, },
+       { .name = "nand", .bit = 20, },
+       { .name = "tbus", .bit = 27, },
+       { .name = "robosw250", .bit = 31, },
+       { },
+};
+
+static int clk_bcm63xx_probe(struct platform_device *pdev)
+{
+       const struct clk_bcm63xx_table_entry *entry, *table;
+       struct clk_bcm63xx_hw *hw;
+       struct resource *r;
+       u8 maxbit = 0;
+       int i, ret;
+
+       table = of_device_get_match_data(&pdev->dev);
+       if (!table)
+               return -EINVAL;
+
+       for (entry = table; entry->name; entry++)
+               maxbit = max_t(u8, maxbit, entry->bit);
+
+       hw = devm_kzalloc(&pdev->dev, struct_size(hw, data.hws, maxbit),
+                         GFP_KERNEL);
+       if (!hw)
+               return -ENOMEM;
+
+       platform_set_drvdata(pdev, hw);
+
+       spin_lock_init(&hw->lock);
+
+       hw->data.num = maxbit;
+       for (i = 0; i < maxbit; i++)
+               hw->data.hws[i] = ERR_PTR(-ENODEV);
+
+       r = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+       hw->regs = devm_ioremap_resource(&pdev->dev, r);
+       if (IS_ERR(hw->regs))
+               return PTR_ERR(hw->regs);
+
+       for (entry = table; entry->name; entry++) {
+               struct clk_hw *clk;
+
+               clk = clk_hw_register_gate(&pdev->dev, entry->name, NULL,
+                                          entry->flags, hw->regs, entry->bit,
+                                          CLK_GATE_BIG_ENDIAN, &hw->lock);
+               if (IS_ERR(clk)) {
+                       ret = PTR_ERR(clk);
+                       goto out_err;
+               }
+
+               hw->data.hws[entry->bit] = clk;
+       }
+
+       ret = of_clk_add_hw_provider(pdev->dev.of_node, of_clk_hw_onecell_get,
+                                    &hw->data);
+       if (!ret)
+               return 0;
+out_err:
+       for (i = 0; i < hw->data.num; i++) {
+               if (!IS_ERR(hw->data.hws[i]))
+                       clk_hw_unregister_gate(hw->data.hws[i]);
+       }
+
+       return ret;
+}
+
+static int clk_bcm63xx_remove(struct platform_device *pdev)
+{
+       struct clk_bcm63xx_hw *hw = platform_get_drvdata(pdev);
+       int i;
+
+       of_clk_del_provider(pdev->dev.of_node);
+
+       for (i = 0; i < hw->data.num; i++) {
+               if (!IS_ERR(hw->data.hws[i]))
+                       clk_hw_unregister_gate(hw->data.hws[i]);
+       }
+
+       return 0;
+}
+
+static const struct of_device_id clk_bcm63xx_dt_ids[] = {
+       { .compatible = "brcm,bcm3368-clocks", .data = &bcm3368_clocks, },
+       { .compatible = "brcm,bcm6328-clocks", .data = &bcm6328_clocks, },
+       { .compatible = "brcm,bcm6358-clocks", .data = &bcm6358_clocks, },
+       { .compatible = "brcm,bcm6362-clocks", .data = &bcm6362_clocks, },
+       { .compatible = "brcm,bcm6368-clocks", .data = &bcm6368_clocks, },
+       { .compatible = "brcm,bcm63268-clocks", .data = &bcm63268_clocks, },
+       { }
+};
+
+static struct platform_driver clk_bcm63xx = {
+       .probe = clk_bcm63xx_probe,
+       .remove = clk_bcm63xx_remove,
+       .driver = {
+               .name = "bcm63xx-clock",
+               .of_match_table = clk_bcm63xx_dt_ids,
+       },
+};
+builtin_platform_driver(clk_bcm63xx);
diff --git a/drivers/clk/bcm/clk-raspberrypi.c b/drivers/clk/bcm/clk-raspberrypi.c
new file mode 100644 (file)
index 0000000..1654fd0
--- /dev/null
@@ -0,0 +1,315 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Raspberry Pi driver for firmware controlled clocks
+ *
+ * Even though clk-bcm2835 provides an interface to the hardware registers for
+ * the system clocks we've had to factor out 'pllb' as the firmware 'owns' it.
+ * We're not allowed to change it directly as we might race with the
+ * over-temperature and under-voltage protections provided by the firmware.
+ *
+ * Copyright (C) 2019 Nicolas Saenz Julienne <nsaenzjulienne@suse.de>
+ */
+
+#include <linux/clkdev.h>
+#include <linux/clk-provider.h>
+#include <linux/io.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+
+#include <soc/bcm2835/raspberrypi-firmware.h>
+
+#define RPI_FIRMWARE_ARM_CLK_ID                0x00000003
+
+#define RPI_FIRMWARE_STATE_ENABLE_BIT  BIT(0)
+#define RPI_FIRMWARE_STATE_WAIT_BIT    BIT(1)
+
+/*
+ * Even though the firmware interface alters 'pllb' the frequencies are
+ * provided as per 'pllb_arm'. We need to scale before passing them trough.
+ */
+#define RPI_FIRMWARE_PLLB_ARM_DIV_RATE 2
+
+#define A2W_PLL_FRAC_BITS              20
+
+struct raspberrypi_clk {
+       struct device *dev;
+       struct rpi_firmware *firmware;
+       struct platform_device *cpufreq;
+
+       unsigned long min_rate;
+       unsigned long max_rate;
+
+       struct clk_hw pllb;
+       struct clk_hw *pllb_arm;
+       struct clk_lookup *pllb_arm_lookup;
+};
+
+/*
+ * Structure of the message passed to Raspberry Pi's firmware in order to
+ * change clock rates. The 'disable_turbo' option is only available to the ARM
+ * clock (pllb) which we enable by default as turbo mode will alter multiple
+ * clocks at once.
+ *
+ * Even though we're able to access the clock registers directly we're bound to
+ * use the firmware interface as the firmware ultimately takes care of
+ * mitigating overheating/undervoltage situations and we would be changing
+ * frequencies behind his back.
+ *
+ * For more information on the firmware interface check:
+ * https://github.com/raspberrypi/firmware/wiki/Mailbox-property-interface
+ */
+struct raspberrypi_firmware_prop {
+       __le32 id;
+       __le32 val;
+       __le32 disable_turbo;
+} __packed;
+
+static int raspberrypi_clock_property(struct rpi_firmware *firmware, u32 tag,
+                                     u32 clk, u32 *val)
+{
+       struct raspberrypi_firmware_prop msg = {
+               .id = cpu_to_le32(clk),
+               .val = cpu_to_le32(*val),
+               .disable_turbo = cpu_to_le32(1),
+       };
+       int ret;
+
+       ret = rpi_firmware_property(firmware, tag, &msg, sizeof(msg));
+       if (ret)
+               return ret;
+
+       *val = le32_to_cpu(msg.val);
+
+       return 0;
+}
+
+static int raspberrypi_fw_pll_is_on(struct clk_hw *hw)
+{
+       struct raspberrypi_clk *rpi = container_of(hw, struct raspberrypi_clk,
+                                                  pllb);
+       u32 val = 0;
+       int ret;
+
+       ret = raspberrypi_clock_property(rpi->firmware,
+                                        RPI_FIRMWARE_GET_CLOCK_STATE,
+                                        RPI_FIRMWARE_ARM_CLK_ID, &val);
+       if (ret)
+               return 0;
+
+       return !!(val & RPI_FIRMWARE_STATE_ENABLE_BIT);
+}
+
+
+static unsigned long raspberrypi_fw_pll_get_rate(struct clk_hw *hw,
+                                                unsigned long parent_rate)
+{
+       struct raspberrypi_clk *rpi = container_of(hw, struct raspberrypi_clk,
+                                                  pllb);
+       u32 val = 0;
+       int ret;
+
+       ret = raspberrypi_clock_property(rpi->firmware,
+                                        RPI_FIRMWARE_GET_CLOCK_RATE,
+                                        RPI_FIRMWARE_ARM_CLK_ID,
+                                        &val);
+       if (ret)
+               return ret;
+
+       return val * RPI_FIRMWARE_PLLB_ARM_DIV_RATE;
+}
+
+static int raspberrypi_fw_pll_set_rate(struct clk_hw *hw, unsigned long rate,
+                                      unsigned long parent_rate)
+{
+       struct raspberrypi_clk *rpi = container_of(hw, struct raspberrypi_clk,
+                                                  pllb);
+       u32 new_rate = rate / RPI_FIRMWARE_PLLB_ARM_DIV_RATE;
+       int ret;
+
+       ret = raspberrypi_clock_property(rpi->firmware,
+                                        RPI_FIRMWARE_SET_CLOCK_RATE,
+                                        RPI_FIRMWARE_ARM_CLK_ID,
+                                        &new_rate);
+       if (ret)
+               dev_err_ratelimited(rpi->dev, "Failed to change %s frequency: %d",
+                                   clk_hw_get_name(hw), ret);
+
+       return ret;
+}
+
+/*
+ * Sadly there is no firmware rate rounding interface. We borrowed it from
+ * clk-bcm2835.
+ */
+static int raspberrypi_pll_determine_rate(struct clk_hw *hw,
+                                         struct clk_rate_request *req)
+{
+       struct raspberrypi_clk *rpi = container_of(hw, struct raspberrypi_clk,
+                                                  pllb);
+       u64 div, final_rate;
+       u32 ndiv, fdiv;
+
+       /* We can't use req->rate directly as it would overflow */
+       final_rate = clamp(req->rate, rpi->min_rate, rpi->max_rate);
+
+       div = (u64)final_rate << A2W_PLL_FRAC_BITS;
+       do_div(div, req->best_parent_rate);
+
+       ndiv = div >> A2W_PLL_FRAC_BITS;
+       fdiv = div & ((1 << A2W_PLL_FRAC_BITS) - 1);
+
+       final_rate = ((u64)req->best_parent_rate *
+                                       ((ndiv << A2W_PLL_FRAC_BITS) + fdiv));
+
+       req->rate = final_rate >> A2W_PLL_FRAC_BITS;
+
+       return 0;
+}
+
+static const struct clk_ops raspberrypi_firmware_pll_clk_ops = {
+       .is_prepared = raspberrypi_fw_pll_is_on,
+       .recalc_rate = raspberrypi_fw_pll_get_rate,
+       .set_rate = raspberrypi_fw_pll_set_rate,
+       .determine_rate = raspberrypi_pll_determine_rate,
+};
+
+static int raspberrypi_register_pllb(struct raspberrypi_clk *rpi)
+{
+       u32 min_rate = 0, max_rate = 0;
+       struct clk_init_data init;
+       int ret;
+
+       memset(&init, 0, sizeof(init));
+
+       /* All of the PLLs derive from the external oscillator. */
+       init.parent_names = (const char *[]){ "osc" };
+       init.num_parents = 1;
+       init.name = "pllb";
+       init.ops = &raspberrypi_firmware_pll_clk_ops;
+       init.flags = CLK_GET_RATE_NOCACHE | CLK_IGNORE_UNUSED;
+
+       /* Get min & max rates set by the firmware */
+       ret = raspberrypi_clock_property(rpi->firmware,
+                                        RPI_FIRMWARE_GET_MIN_CLOCK_RATE,
+                                        RPI_FIRMWARE_ARM_CLK_ID,
+                                        &min_rate);
+       if (ret) {
+               dev_err(rpi->dev, "Failed to get %s min freq: %d\n",
+                       init.name, ret);
+               return ret;
+       }
+
+       ret = raspberrypi_clock_property(rpi->firmware,
+                                        RPI_FIRMWARE_GET_MAX_CLOCK_RATE,
+                                        RPI_FIRMWARE_ARM_CLK_ID,
+                                        &max_rate);
+       if (ret) {
+               dev_err(rpi->dev, "Failed to get %s max freq: %d\n",
+                       init.name, ret);
+               return ret;
+       }
+
+       if (!min_rate || !max_rate) {
+               dev_err(rpi->dev, "Unexpected frequency range: min %u, max %u\n",
+                       min_rate, max_rate);
+               return -EINVAL;
+       }
+
+       dev_info(rpi->dev, "CPU frequency range: min %u, max %u\n",
+                min_rate, max_rate);
+
+       rpi->min_rate = min_rate * RPI_FIRMWARE_PLLB_ARM_DIV_RATE;
+       rpi->max_rate = max_rate * RPI_FIRMWARE_PLLB_ARM_DIV_RATE;
+
+       rpi->pllb.init = &init;
+
+       return devm_clk_hw_register(rpi->dev, &rpi->pllb);
+}
+
+static int raspberrypi_register_pllb_arm(struct raspberrypi_clk *rpi)
+{
+       rpi->pllb_arm = clk_hw_register_fixed_factor(rpi->dev,
+                               "pllb_arm", "pllb",
+                               CLK_SET_RATE_PARENT | CLK_GET_RATE_NOCACHE,
+                               1, 2);
+       if (IS_ERR(rpi->pllb_arm)) {
+               dev_err(rpi->dev, "Failed to initialize pllb_arm\n");
+               return PTR_ERR(rpi->pllb_arm);
+       }
+
+       rpi->pllb_arm_lookup = clkdev_hw_create(rpi->pllb_arm, NULL, "cpu0");
+       if (!rpi->pllb_arm_lookup) {
+               dev_err(rpi->dev, "Failed to initialize pllb_arm_lookup\n");
+               clk_hw_unregister_fixed_factor(rpi->pllb_arm);
+               return -ENOMEM;
+       }
+
+       return 0;
+}
+
+static int raspberrypi_clk_probe(struct platform_device *pdev)
+{
+       struct device_node *firmware_node;
+       struct device *dev = &pdev->dev;
+       struct rpi_firmware *firmware;
+       struct raspberrypi_clk *rpi;
+       int ret;
+
+       firmware_node = of_find_compatible_node(NULL, NULL,
+                                       "raspberrypi,bcm2835-firmware");
+       if (!firmware_node) {
+               dev_err(dev, "Missing firmware node\n");
+               return -ENOENT;
+       }
+
+       firmware = rpi_firmware_get(firmware_node);
+       of_node_put(firmware_node);
+       if (!firmware)
+               return -EPROBE_DEFER;
+
+       rpi = devm_kzalloc(dev, sizeof(*rpi), GFP_KERNEL);
+       if (!rpi)
+               return -ENOMEM;
+
+       rpi->dev = dev;
+       rpi->firmware = firmware;
+       platform_set_drvdata(pdev, rpi);
+
+       ret = raspberrypi_register_pllb(rpi);
+       if (ret) {
+               dev_err(dev, "Failed to initialize pllb, %d\n", ret);
+               return ret;
+       }
+
+       ret = raspberrypi_register_pllb_arm(rpi);
+       if (ret)
+               return ret;
+
+       rpi->cpufreq = platform_device_register_data(dev, "raspberrypi-cpufreq",
+                                                    -1, NULL, 0);
+
+       return 0;
+}
+
+static int raspberrypi_clk_remove(struct platform_device *pdev)
+{
+       struct raspberrypi_clk *rpi = platform_get_drvdata(pdev);
+
+       platform_device_unregister(rpi->cpufreq);
+
+       return 0;
+}
+
+static struct platform_driver raspberrypi_clk_driver = {
+       .driver = {
+               .name = "raspberrypi-clk",
+       },
+       .probe          = raspberrypi_clk_probe,
+       .remove         = raspberrypi_clk_remove,
+};
+module_platform_driver(raspberrypi_clk_driver);
+
+MODULE_AUTHOR("Nicolas Saenz Julienne <nsaenzjulienne@suse.de>");
+MODULE_DESCRIPTION("Raspberry Pi firmware clock driver");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS("platform:raspberrypi-clk");
index 0649956..524bf9a 100644 (file)
@@ -75,8 +75,8 @@ void clk_bulk_put(int num_clks, struct clk_bulk_data *clks)
 }
 EXPORT_SYMBOL_GPL(clk_bulk_put);
 
-int __must_check clk_bulk_get(struct device *dev, int num_clks,
-                             struct clk_bulk_data *clks)
+static int __clk_bulk_get(struct device *dev, int num_clks,
+                         struct clk_bulk_data *clks, bool optional)
 {
        int ret;
        int i;
@@ -88,10 +88,14 @@ int __must_check clk_bulk_get(struct device *dev, int num_clks,
                clks[i].clk = clk_get(dev, clks[i].id);
                if (IS_ERR(clks[i].clk)) {
                        ret = PTR_ERR(clks[i].clk);
+                       clks[i].clk = NULL;
+
+                       if (ret == -ENOENT && optional)
+                               continue;
+
                        if (ret != -EPROBE_DEFER)
                                dev_err(dev, "Failed to get clk '%s': %d\n",
                                        clks[i].id, ret);
-                       clks[i].clk = NULL;
                        goto err;
                }
        }
@@ -103,8 +107,21 @@ err:
 
        return ret;
 }
+
+int __must_check clk_bulk_get(struct device *dev, int num_clks,
+                             struct clk_bulk_data *clks)
+{
+       return __clk_bulk_get(dev, num_clks, clks, false);
+}
 EXPORT_SYMBOL(clk_bulk_get);
 
+int __must_check clk_bulk_get_optional(struct device *dev, int num_clks,
+                                      struct clk_bulk_data *clks)
+{
+       return __clk_bulk_get(dev, num_clks, clks, true);
+}
+EXPORT_SYMBOL_GPL(clk_bulk_get_optional);
+
 void clk_bulk_put_all(int num_clks, struct clk_bulk_data *clks)
 {
        if (IS_ERR_OR_NULL(clks))
index 0443dfc..239102e 100644 (file)
@@ -630,7 +630,7 @@ of_clk_cdce_get(struct of_phandle_args *clkspec, void *data)
 static int cdce706_probe(struct i2c_client *client,
                         const struct i2c_device_id *id)
 {
-       struct i2c_adapter *adapter = to_i2c_adapter(client->dev.parent);
+       struct i2c_adapter *adapter = client->adapter;
        struct cdce706_dev_data *cdce;
        int ret;
 
index daa1fc8..be16076 100644 (file)
@@ -52,8 +52,8 @@ static void devm_clk_bulk_release(struct device *dev, void *res)
        clk_bulk_put(devres->num_clks, devres->clks);
 }
 
-int __must_check devm_clk_bulk_get(struct device *dev, int num_clks,
-                     struct clk_bulk_data *clks)
+static int __devm_clk_bulk_get(struct device *dev, int num_clks,
+                              struct clk_bulk_data *clks, bool optional)
 {
        struct clk_bulk_devres *devres;
        int ret;
@@ -63,7 +63,10 @@ int __must_check devm_clk_bulk_get(struct device *dev, int num_clks,
        if (!devres)
                return -ENOMEM;
 
-       ret = clk_bulk_get(dev, num_clks, clks);
+       if (optional)
+               ret = clk_bulk_get_optional(dev, num_clks, clks);
+       else
+               ret = clk_bulk_get(dev, num_clks, clks);
        if (!ret) {
                devres->clks = clks;
                devres->num_clks = num_clks;
@@ -74,8 +77,21 @@ int __must_check devm_clk_bulk_get(struct device *dev, int num_clks,
 
        return ret;
 }
+
+int __must_check devm_clk_bulk_get(struct device *dev, int num_clks,
+                     struct clk_bulk_data *clks)
+{
+       return __devm_clk_bulk_get(dev, num_clks, clks, false);
+}
 EXPORT_SYMBOL_GPL(devm_clk_bulk_get);
 
+int __must_check devm_clk_bulk_get_optional(struct device *dev, int num_clks,
+                     struct clk_bulk_data *clks)
+{
+       return __devm_clk_bulk_get(dev, num_clks, clks, true);
+}
+EXPORT_SYMBOL_GPL(devm_clk_bulk_get_optional);
+
 int __must_check devm_clk_bulk_get_all(struct device *dev,
                                       struct clk_bulk_data **clks)
 {
index a2f31e5..fa8c917 100644 (file)
@@ -16,7 +16,6 @@
 #include <linux/platform_device.h>
 #include <linux/regmap.h>
 
-#include <linux/mfd/lochnagar.h>
 #include <linux/mfd/lochnagar1_regs.h>
 #include <linux/mfd/lochnagar2_regs.h>
 
@@ -40,48 +39,46 @@ struct lochnagar_clk {
 struct lochnagar_clk_priv {
        struct device *dev;
        struct regmap *regmap;
-       enum lochnagar_type type;
-
-       const char **parents;
-       unsigned int nparents;
 
        struct lochnagar_clk lclks[LOCHNAGAR_NUM_CLOCKS];
 };
 
-static const char * const lochnagar1_clk_parents[] = {
-       "ln-none",
-       "ln-spdif-mclk",
-       "ln-psia1-mclk",
-       "ln-psia2-mclk",
-       "ln-cdc-clkout",
-       "ln-dsp-clkout",
-       "ln-pmic-32k",
-       "ln-gf-mclk1",
-       "ln-gf-mclk3",
-       "ln-gf-mclk2",
-       "ln-gf-mclk4",
+#define LN_PARENT(NAME) { .name = NAME, .fw_name = NAME }
+
+static const struct clk_parent_data lochnagar1_clk_parents[] = {
+       LN_PARENT("ln-none"),
+       LN_PARENT("ln-spdif-mclk"),
+       LN_PARENT("ln-psia1-mclk"),
+       LN_PARENT("ln-psia2-mclk"),
+       LN_PARENT("ln-cdc-clkout"),
+       LN_PARENT("ln-dsp-clkout"),
+       LN_PARENT("ln-pmic-32k"),
+       LN_PARENT("ln-gf-mclk1"),
+       LN_PARENT("ln-gf-mclk3"),
+       LN_PARENT("ln-gf-mclk2"),
+       LN_PARENT("ln-gf-mclk4"),
 };
 
-static const char * const lochnagar2_clk_parents[] = {
-       "ln-none",
-       "ln-cdc-clkout",
-       "ln-dsp-clkout",
-       "ln-pmic-32k",
-       "ln-spdif-mclk",
-       "ln-clk-12m",
-       "ln-clk-11m",
-       "ln-clk-24m",
-       "ln-clk-22m",
-       "ln-clk-8m",
-       "ln-usb-clk-24m",
-       "ln-gf-mclk1",
-       "ln-gf-mclk3",
-       "ln-gf-mclk2",
-       "ln-psia1-mclk",
-       "ln-psia2-mclk",
-       "ln-spdif-clkout",
-       "ln-adat-mclk",
-       "ln-usb-clk-12m",
+static const struct clk_parent_data lochnagar2_clk_parents[] = {
+       LN_PARENT("ln-none"),
+       LN_PARENT("ln-cdc-clkout"),
+       LN_PARENT("ln-dsp-clkout"),
+       LN_PARENT("ln-pmic-32k"),
+       LN_PARENT("ln-spdif-mclk"),
+       LN_PARENT("ln-clk-12m"),
+       LN_PARENT("ln-clk-11m"),
+       LN_PARENT("ln-clk-24m"),
+       LN_PARENT("ln-clk-22m"),
+       LN_PARENT("ln-clk-8m"),
+       LN_PARENT("ln-usb-clk-24m"),
+       LN_PARENT("ln-gf-mclk1"),
+       LN_PARENT("ln-gf-mclk3"),
+       LN_PARENT("ln-gf-mclk2"),
+       LN_PARENT("ln-psia1-mclk"),
+       LN_PARENT("ln-psia2-mclk"),
+       LN_PARENT("ln-spdif-clkout"),
+       LN_PARENT("ln-adat-mclk"),
+       LN_PARENT("ln-usb-clk-12m"),
 };
 
 #define LN1_CLK(ID, NAME, REG) \
@@ -122,6 +119,24 @@ static const struct lochnagar_clk lochnagar2_clks[LOCHNAGAR_NUM_CLOCKS] = {
        LN2_CLK(SOUNDCARD_MCLK, "ln-soundcard-mclk"),
 };
 
+struct lochnagar_config {
+       const struct clk_parent_data *parents;
+       int nparents;
+       const struct lochnagar_clk *clks;
+};
+
+static const struct lochnagar_config lochnagar1_conf = {
+       .parents = lochnagar1_clk_parents,
+       .nparents = ARRAY_SIZE(lochnagar1_clk_parents),
+       .clks = lochnagar1_clks,
+};
+
+static const struct lochnagar_config lochnagar2_conf = {
+       .parents = lochnagar2_clk_parents,
+       .nparents = ARRAY_SIZE(lochnagar2_clk_parents),
+       .clks = lochnagar2_clks,
+};
+
 static inline struct lochnagar_clk *lochnagar_hw_to_lclk(struct clk_hw *hw)
 {
        return container_of(hw, struct lochnagar_clk, hw);
@@ -183,7 +198,7 @@ static u8 lochnagar_clk_get_parent(struct clk_hw *hw)
        if (ret < 0) {
                dev_dbg(priv->dev, "Failed to read parent of %s: %d\n",
                        lclk->name, ret);
-               return priv->nparents;
+               return hw->init->num_parents;
        }
 
        val &= lclk->src_mask;
@@ -198,46 +213,6 @@ static const struct clk_ops lochnagar_clk_ops = {
        .get_parent = lochnagar_clk_get_parent,
 };
 
-static int lochnagar_init_parents(struct lochnagar_clk_priv *priv)
-{
-       struct device_node *np = priv->dev->of_node;
-       int i, j;
-
-       switch (priv->type) {
-       case LOCHNAGAR1:
-               memcpy(priv->lclks, lochnagar1_clks, sizeof(lochnagar1_clks));
-
-               priv->nparents = ARRAY_SIZE(lochnagar1_clk_parents);
-               priv->parents = devm_kmemdup(priv->dev, lochnagar1_clk_parents,
-                                            sizeof(lochnagar1_clk_parents),
-                                            GFP_KERNEL);
-               break;
-       case LOCHNAGAR2:
-               memcpy(priv->lclks, lochnagar2_clks, sizeof(lochnagar2_clks));
-
-               priv->nparents = ARRAY_SIZE(lochnagar2_clk_parents);
-               priv->parents = devm_kmemdup(priv->dev, lochnagar2_clk_parents,
-                                            sizeof(lochnagar2_clk_parents),
-                                            GFP_KERNEL);
-               break;
-       default:
-               dev_err(priv->dev, "Unknown Lochnagar type: %d\n", priv->type);
-               return -EINVAL;
-       }
-
-       if (!priv->parents)
-               return -ENOMEM;
-
-       for (i = 0; i < priv->nparents; i++) {
-               j = of_property_match_string(np, "clock-names",
-                                            priv->parents[i]);
-               if (j >= 0)
-                       priv->parents[i] = of_clk_get_parent_name(np, j);
-       }
-
-       return 0;
-}
-
 static struct clk_hw *
 lochnagar_of_clk_hw_get(struct of_phandle_args *clkspec, void *data)
 {
@@ -252,16 +227,42 @@ lochnagar_of_clk_hw_get(struct of_phandle_args *clkspec, void *data)
        return &priv->lclks[idx].hw;
 }
 
-static int lochnagar_init_clks(struct lochnagar_clk_priv *priv)
+static const struct of_device_id lochnagar_of_match[] = {
+       { .compatible = "cirrus,lochnagar1-clk", .data = &lochnagar1_conf },
+       { .compatible = "cirrus,lochnagar2-clk", .data = &lochnagar2_conf },
+       {}
+};
+MODULE_DEVICE_TABLE(of, lochnagar_of_match);
+
+static int lochnagar_clk_probe(struct platform_device *pdev)
 {
        struct clk_init_data clk_init = {
                .ops = &lochnagar_clk_ops,
-               .parent_names = priv->parents,
-               .num_parents = priv->nparents,
        };
+       struct device *dev = &pdev->dev;
+       struct lochnagar_clk_priv *priv;
+       const struct of_device_id *of_id;
        struct lochnagar_clk *lclk;
+       struct lochnagar_config *conf;
        int ret, i;
 
+       of_id = of_match_device(lochnagar_of_match, dev);
+       if (!of_id)
+               return -EINVAL;
+
+       priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
+       if (!priv)
+               return -ENOMEM;
+
+       priv->dev = dev;
+       priv->regmap = dev_get_regmap(dev->parent, NULL);
+       conf = (struct lochnagar_config *)of_id->data;
+
+       memcpy(priv->lclks, conf->clks, sizeof(priv->lclks));
+
+       clk_init.parent_data = conf->parents;
+       clk_init.num_parents = conf->nparents;
+
        for (i = 0; i < ARRAY_SIZE(priv->lclks); i++) {
                lclk = &priv->lclks[i];
 
@@ -273,55 +274,21 @@ static int lochnagar_init_clks(struct lochnagar_clk_priv *priv)
                lclk->priv = priv;
                lclk->hw.init = &clk_init;
 
-               ret = devm_clk_hw_register(priv->dev, &lclk->hw);
+               ret = devm_clk_hw_register(dev, &lclk->hw);
                if (ret) {
-                       dev_err(priv->dev, "Failed to register %s: %d\n",
+                       dev_err(dev, "Failed to register %s: %d\n",
                                lclk->name, ret);
                        return ret;
                }
        }
 
-       ret = devm_of_clk_add_hw_provider(priv->dev, lochnagar_of_clk_hw_get,
-                                         priv);
+       ret = devm_of_clk_add_hw_provider(dev, lochnagar_of_clk_hw_get, priv);
        if (ret < 0)
-               dev_err(priv->dev, "Failed to register provider: %d\n", ret);
+               dev_err(dev, "Failed to register provider: %d\n", ret);
 
        return ret;
 }
 
-static const struct of_device_id lochnagar_of_match[] = {
-       { .compatible = "cirrus,lochnagar1-clk", .data = (void *)LOCHNAGAR1 },
-       { .compatible = "cirrus,lochnagar2-clk", .data = (void *)LOCHNAGAR2 },
-       {}
-};
-MODULE_DEVICE_TABLE(of, lochnagar_of_match);
-
-static int lochnagar_clk_probe(struct platform_device *pdev)
-{
-       struct device *dev = &pdev->dev;
-       struct lochnagar_clk_priv *priv;
-       const struct of_device_id *of_id;
-       int ret;
-
-       of_id = of_match_device(lochnagar_of_match, dev);
-       if (!of_id)
-               return -EINVAL;
-
-       priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
-       if (!priv)
-               return -ENOMEM;
-
-       priv->dev = dev;
-       priv->regmap = dev_get_regmap(dev->parent, NULL);
-       priv->type = (enum lochnagar_type)of_id->data;
-
-       ret = lochnagar_init_parents(priv);
-       if (ret)
-               return ret;
-
-       return lochnagar_init_clks(priv);
-}
-
 static struct platform_driver lochnagar_clk_driver = {
        .driver = {
                .name = "lochnagar-clk",
index 5f0490b..87fe0b0 100644 (file)
@@ -44,10 +44,24 @@ static unsigned long clk_pwm_recalc_rate(struct clk_hw *hw,
        return clk_pwm->fixed_rate;
 }
 
+static int clk_pwm_get_duty_cycle(struct clk_hw *hw, struct clk_duty *duty)
+{
+       struct clk_pwm *clk_pwm = to_clk_pwm(hw);
+       struct pwm_state state;
+
+       pwm_get_state(clk_pwm->pwm, &state);
+
+       duty->num = state.duty_cycle;
+       duty->den = state.period;
+
+       return 0;
+}
+
 static const struct clk_ops clk_pwm_ops = {
        .prepare = clk_pwm_prepare,
        .unprepare = clk_pwm_unprepare,
        .recalc_rate = clk_pwm_recalc_rate,
+       .get_duty_cycle = clk_pwm_get_duty_cycle,
 };
 
 static int clk_pwm_probe(struct platform_device *pdev)
index dd93d3a..07f3b25 100644 (file)
@@ -635,6 +635,17 @@ static const struct clockgen_chipinfo chipinfo[] = {
                .flags = CG_VER3 | CG_LITTLE_ENDIAN,
        },
        {
+               .compat = "fsl,lx2160a-clockgen",
+               .cmux_groups = {
+                       &clockgen2_cmux_cga12, &clockgen2_cmux_cgb
+               },
+               .cmux_to_group = {
+                       0, 0, 0, 0, 1, 1, 1, 1, -1
+               },
+               .pll_mask = 0x37,
+               .flags = CG_VER3 | CG_LITTLE_ENDIAN,
+       },
+       {
                .compat = "fsl,p2041-clockgen",
                .guts_compat = "fsl,qoriq-device-config-1.0",
                .init_periph = p2041_init_periph,
@@ -1493,6 +1504,7 @@ CLK_OF_DECLARE(qoriq_clockgen_ls1043a, "fsl,ls1043a-clockgen", clockgen_init);
 CLK_OF_DECLARE(qoriq_clockgen_ls1046a, "fsl,ls1046a-clockgen", clockgen_init);
 CLK_OF_DECLARE(qoriq_clockgen_ls1088a, "fsl,ls1088a-clockgen", clockgen_init);
 CLK_OF_DECLARE(qoriq_clockgen_ls2080a, "fsl,ls2080a-clockgen", clockgen_init);
+CLK_OF_DECLARE(qoriq_clockgen_lx2160a, "fsl,lx2160a-clockgen", clockgen_init);
 CLK_OF_DECLARE(qoriq_clockgen_p2041, "fsl,p2041-clockgen", clockgen_init);
 CLK_OF_DECLARE(qoriq_clockgen_p3041, "fsl,p3041-clockgen", clockgen_init);
 CLK_OF_DECLARE(qoriq_clockgen_p4080, "fsl,p4080-clockgen", clockgen_init);
diff --git a/drivers/clk/clk-si5341.c b/drivers/clk/clk-si5341.c
new file mode 100644 (file)
index 0000000..72424eb
--- /dev/null
@@ -0,0 +1,1346 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Driver for Silicon Labs Si5341/Si5340 Clock generator
+ * Copyright (C) 2019 Topic Embedded Products
+ * Author: Mike Looijmans <mike.looijmans@topic.nl>
+ */
+
+#include <linux/clk.h>
+#include <linux/clk-provider.h>
+#include <linux/delay.h>
+#include <linux/gcd.h>
+#include <linux/math64.h>
+#include <linux/i2c.h>
+#include <linux/module.h>
+#include <linux/regmap.h>
+#include <linux/slab.h>
+#include <asm/unaligned.h>
+
+#define SI5341_MAX_NUM_OUTPUTS 10
+#define SI5340_MAX_NUM_OUTPUTS 4
+
+#define SI5341_NUM_SYNTH 5
+#define SI5340_NUM_SYNTH 4
+
+/* Range of the synthesizer fractional divider */
+#define SI5341_SYNTH_N_MIN     10
+#define SI5341_SYNTH_N_MAX     4095
+
+/* The chip can get its input clock from 3 input pins or an XTAL */
+
+/* There is one PLL running at 13500–14256 MHz */
+#define SI5341_PLL_VCO_MIN 13500000000ull
+#define SI5341_PLL_VCO_MAX 14256000000ull
+
+/* The 5 frequency synthesizers obtain their input from the PLL */
+struct clk_si5341_synth {
+       struct clk_hw hw;
+       struct clk_si5341 *data;
+       u8 index;
+};
+#define to_clk_si5341_synth(_hw) \
+       container_of(_hw, struct clk_si5341_synth, hw)
+
+/* The output stages can be connected to any synth (full mux) */
+struct clk_si5341_output {
+       struct clk_hw hw;
+       struct clk_si5341 *data;
+       u8 index;
+};
+#define to_clk_si5341_output(_hw) \
+       container_of(_hw, struct clk_si5341_output, hw)
+
+struct clk_si5341 {
+       struct clk_hw hw;
+       struct regmap *regmap;
+       struct i2c_client *i2c_client;
+       struct clk_si5341_synth synth[SI5341_NUM_SYNTH];
+       struct clk_si5341_output clk[SI5341_MAX_NUM_OUTPUTS];
+       struct clk *pxtal;
+       const char *pxtal_name;
+       const u16 *reg_output_offset;
+       const u16 *reg_rdiv_offset;
+       u64 freq_vco; /* 13500–14256 MHz */
+       u8 num_outputs;
+       u8 num_synth;
+};
+#define to_clk_si5341(_hw)     container_of(_hw, struct clk_si5341, hw)
+
+struct clk_si5341_output_config {
+       u8 out_format_drv_bits;
+       u8 out_cm_ampl_bits;
+       bool synth_master;
+       bool always_on;
+};
+
+#define SI5341_PAGE            0x0001
+#define SI5341_PN_BASE         0x0002
+#define SI5341_DEVICE_REV      0x0005
+#define SI5341_STATUS          0x000C
+#define SI5341_SOFT_RST                0x001C
+
+/* Input dividers (48-bit) */
+#define SI5341_IN_PDIV(x)      (0x0208 + ((x) * 10))
+#define SI5341_IN_PSET(x)      (0x020E + ((x) * 10))
+
+/* PLL configuration */
+#define SI5341_PLL_M_NUM       0x0235
+#define SI5341_PLL_M_DEN       0x023B
+
+/* Output configuration */
+#define SI5341_OUT_CONFIG(output)      \
+                       ((output)->data->reg_output_offset[(output)->index])
+#define SI5341_OUT_FORMAT(output)      (SI5341_OUT_CONFIG(output) + 1)
+#define SI5341_OUT_CM(output)          (SI5341_OUT_CONFIG(output) + 2)
+#define SI5341_OUT_MUX_SEL(output)     (SI5341_OUT_CONFIG(output) + 3)
+#define SI5341_OUT_R_REG(output)       \
+                       ((output)->data->reg_rdiv_offset[(output)->index])
+
+/* Synthesize N divider */
+#define SI5341_SYNTH_N_NUM(x)  (0x0302 + ((x) * 11))
+#define SI5341_SYNTH_N_DEN(x)  (0x0308 + ((x) * 11))
+#define SI5341_SYNTH_N_UPD(x)  (0x030C + ((x) * 11))
+
+/* Synthesizer output enable, phase bypass, power mode */
+#define SI5341_SYNTH_N_CLK_TO_OUTX_EN  0x0A03
+#define SI5341_SYNTH_N_PIBYP           0x0A04
+#define SI5341_SYNTH_N_PDNB            0x0A05
+#define SI5341_SYNTH_N_CLK_DIS         0x0B4A
+
+#define SI5341_REGISTER_MAX    0xBFF
+
+/* SI5341_OUT_CONFIG bits */
+#define SI5341_OUT_CFG_PDN             BIT(0)
+#define SI5341_OUT_CFG_OE              BIT(1)
+#define SI5341_OUT_CFG_RDIV_FORCE2     BIT(2)
+
+/* Static configuration (to be moved to firmware) */
+struct si5341_reg_default {
+       u16 address;
+       u8 value;
+};
+
+/* Output configuration registers 0..9 are not quite logically organized */
+static const u16 si5341_reg_output_offset[] = {
+       0x0108,
+       0x010D,
+       0x0112,
+       0x0117,
+       0x011C,
+       0x0121,
+       0x0126,
+       0x012B,
+       0x0130,
+       0x013A,
+};
+
+static const u16 si5340_reg_output_offset[] = {
+       0x0112,
+       0x0117,
+       0x0126,
+       0x012B,
+};
+
+/* The location of the R divider registers */
+static const u16 si5341_reg_rdiv_offset[] = {
+       0x024A,
+       0x024D,
+       0x0250,
+       0x0253,
+       0x0256,
+       0x0259,
+       0x025C,
+       0x025F,
+       0x0262,
+       0x0268,
+};
+static const u16 si5340_reg_rdiv_offset[] = {
+       0x0250,
+       0x0253,
+       0x025C,
+       0x025F,
+};
+
+/*
+ * Programming sequence from ClockBuilder, settings to initialize the system
+ * using only the XTAL input, without pre-divider.
+ * This also contains settings that aren't mentioned anywhere in the datasheet.
+ * The "known" settings like synth and output configuration are done later.
+ */
+static const struct si5341_reg_default si5341_reg_defaults[] = {
+       { 0x0017, 0x3A }, /* INT mask (disable interrupts) */
+       { 0x0018, 0xFF }, /* INT mask */
+       { 0x0021, 0x0F }, /* Select XTAL as input */
+       { 0x0022, 0x00 }, /* Not in datasheet */
+       { 0x002B, 0x02 }, /* SPI config */
+       { 0x002C, 0x20 }, /* LOS enable for XTAL */
+       { 0x002D, 0x00 }, /* LOS timing */
+       { 0x002E, 0x00 },
+       { 0x002F, 0x00 },
+       { 0x0030, 0x00 },
+       { 0x0031, 0x00 },
+       { 0x0032, 0x00 },
+       { 0x0033, 0x00 },
+       { 0x0034, 0x00 },
+       { 0x0035, 0x00 },
+       { 0x0036, 0x00 },
+       { 0x0037, 0x00 },
+       { 0x0038, 0x00 }, /* LOS setting (thresholds) */
+       { 0x0039, 0x00 },
+       { 0x003A, 0x00 },
+       { 0x003B, 0x00 },
+       { 0x003C, 0x00 },
+       { 0x003D, 0x00 }, /* LOS setting (thresholds) end */
+       { 0x0041, 0x00 }, /* LOS0_DIV_SEL */
+       { 0x0042, 0x00 }, /* LOS1_DIV_SEL */
+       { 0x0043, 0x00 }, /* LOS2_DIV_SEL */
+       { 0x0044, 0x00 }, /* LOS3_DIV_SEL */
+       { 0x009E, 0x00 }, /* Not in datasheet */
+       { 0x0102, 0x01 }, /* Enable outputs */
+       { 0x013F, 0x00 }, /* Not in datasheet */
+       { 0x0140, 0x00 }, /* Not in datasheet */
+       { 0x0141, 0x40 }, /* OUT LOS */
+       { 0x0202, 0x00 }, /* XAXB_FREQ_OFFSET (=0)*/
+       { 0x0203, 0x00 },
+       { 0x0204, 0x00 },
+       { 0x0205, 0x00 },
+       { 0x0206, 0x00 }, /* PXAXB (2^x) */
+       { 0x0208, 0x00 }, /* Px divider setting (usually 0) */
+       { 0x0209, 0x00 },
+       { 0x020A, 0x00 },
+       { 0x020B, 0x00 },
+       { 0x020C, 0x00 },
+       { 0x020D, 0x00 },
+       { 0x020E, 0x00 },
+       { 0x020F, 0x00 },
+       { 0x0210, 0x00 },
+       { 0x0211, 0x00 },
+       { 0x0212, 0x00 },
+       { 0x0213, 0x00 },
+       { 0x0214, 0x00 },
+       { 0x0215, 0x00 },
+       { 0x0216, 0x00 },
+       { 0x0217, 0x00 },
+       { 0x0218, 0x00 },
+       { 0x0219, 0x00 },
+       { 0x021A, 0x00 },
+       { 0x021B, 0x00 },
+       { 0x021C, 0x00 },
+       { 0x021D, 0x00 },
+       { 0x021E, 0x00 },
+       { 0x021F, 0x00 },
+       { 0x0220, 0x00 },
+       { 0x0221, 0x00 },
+       { 0x0222, 0x00 },
+       { 0x0223, 0x00 },
+       { 0x0224, 0x00 },
+       { 0x0225, 0x00 },
+       { 0x0226, 0x00 },
+       { 0x0227, 0x00 },
+       { 0x0228, 0x00 },
+       { 0x0229, 0x00 },
+       { 0x022A, 0x00 },
+       { 0x022B, 0x00 },
+       { 0x022C, 0x00 },
+       { 0x022D, 0x00 },
+       { 0x022E, 0x00 },
+       { 0x022F, 0x00 }, /* Px divider setting (usually 0) end */
+       { 0x026B, 0x00 }, /* DESIGN_ID (ASCII string) */
+       { 0x026C, 0x00 },
+       { 0x026D, 0x00 },
+       { 0x026E, 0x00 },
+       { 0x026F, 0x00 },
+       { 0x0270, 0x00 },
+       { 0x0271, 0x00 },
+       { 0x0272, 0x00 }, /* DESIGN_ID (ASCII string) end */
+       { 0x0339, 0x1F }, /* N_FSTEP_MSK */
+       { 0x033B, 0x00 }, /* Nx_FSTEPW (Frequency step) */
+       { 0x033C, 0x00 },
+       { 0x033D, 0x00 },
+       { 0x033E, 0x00 },
+       { 0x033F, 0x00 },
+       { 0x0340, 0x00 },
+       { 0x0341, 0x00 },
+       { 0x0342, 0x00 },
+       { 0x0343, 0x00 },
+       { 0x0344, 0x00 },
+       { 0x0345, 0x00 },
+       { 0x0346, 0x00 },
+       { 0x0347, 0x00 },
+       { 0x0348, 0x00 },
+       { 0x0349, 0x00 },
+       { 0x034A, 0x00 },
+       { 0x034B, 0x00 },
+       { 0x034C, 0x00 },
+       { 0x034D, 0x00 },
+       { 0x034E, 0x00 },
+       { 0x034F, 0x00 },
+       { 0x0350, 0x00 },
+       { 0x0351, 0x00 },
+       { 0x0352, 0x00 },
+       { 0x0353, 0x00 },
+       { 0x0354, 0x00 },
+       { 0x0355, 0x00 },
+       { 0x0356, 0x00 },
+       { 0x0357, 0x00 },
+       { 0x0358, 0x00 }, /* Nx_FSTEPW (Frequency step) end */
+       { 0x0359, 0x00 }, /* Nx_DELAY */
+       { 0x035A, 0x00 },
+       { 0x035B, 0x00 },
+       { 0x035C, 0x00 },
+       { 0x035D, 0x00 },
+       { 0x035E, 0x00 },
+       { 0x035F, 0x00 },
+       { 0x0360, 0x00 },
+       { 0x0361, 0x00 },
+       { 0x0362, 0x00 }, /* Nx_DELAY end */
+       { 0x0802, 0x00 }, /* Not in datasheet */
+       { 0x0803, 0x00 }, /* Not in datasheet */
+       { 0x0804, 0x00 }, /* Not in datasheet */
+       { 0x090E, 0x02 }, /* XAXB_EXTCLK_EN=0 XAXB_PDNB=1 (use XTAL) */
+       { 0x091C, 0x04 }, /* ZDM_EN=4 (Normal mode) */
+       { 0x0943, 0x00 }, /* IO_VDD_SEL=0 (0=1v8, use 1=3v3) */
+       { 0x0949, 0x00 }, /* IN_EN (disable input clocks) */
+       { 0x094A, 0x00 }, /* INx_TO_PFD_EN (disabled) */
+       { 0x0A02, 0x00 }, /* Not in datasheet */
+       { 0x0B44, 0x0F }, /* PDIV_ENB (datasheet does not mention what it is) */
+};
+
+/* Read and interpret a 44-bit followed by a 32-bit value in the regmap */
+static int si5341_decode_44_32(struct regmap *regmap, unsigned int reg,
+       u64 *val1, u32 *val2)
+{
+       int err;
+       u8 r[10];
+
+       err = regmap_bulk_read(regmap, reg, r, 10);
+       if (err < 0)
+               return err;
+
+       *val1 = ((u64)((r[5] & 0x0f) << 8 | r[4]) << 32) |
+                (get_unaligned_le32(r));
+       *val2 = get_unaligned_le32(&r[6]);
+
+       return 0;
+}
+
+static int si5341_encode_44_32(struct regmap *regmap, unsigned int reg,
+       u64 n_num, u32 n_den)
+{
+       u8 r[10];
+
+       /* Shift left as far as possible without overflowing */
+       while (!(n_num & BIT_ULL(43)) && !(n_den & BIT(31))) {
+               n_num <<= 1;
+               n_den <<= 1;
+       }
+
+       /* 44 bits (6 bytes) numerator */
+       put_unaligned_le32(n_num, r);
+       r[4] = (n_num >> 32) & 0xff;
+       r[5] = (n_num >> 40) & 0x0f;
+       /* 32 bits denominator */
+       put_unaligned_le32(n_den, &r[6]);
+
+       /* Program the fraction */
+       return regmap_bulk_write(regmap, reg, r, sizeof(r));
+}
+
+/* VCO, we assume it runs at a constant frequency */
+static unsigned long si5341_clk_recalc_rate(struct clk_hw *hw,
+               unsigned long parent_rate)
+{
+       struct clk_si5341 *data = to_clk_si5341(hw);
+       int err;
+       u64 res;
+       u64 m_num;
+       u32 m_den;
+       unsigned int shift;
+
+       /* Assume that PDIV is not being used, just read the PLL setting */
+       err = si5341_decode_44_32(data->regmap, SI5341_PLL_M_NUM,
+                               &m_num, &m_den);
+       if (err < 0)
+               return 0;
+
+       if (!m_num || !m_den)
+               return 0;
+
+       /*
+        * Though m_num is 64-bit, only the upper bits are actually used. While
+        * calculating m_num and m_den, they are shifted as far as possible to
+        * the left. To avoid 96-bit division here, we just shift them back so
+        * we can do with just 64 bits.
+        */
+       shift = 0;
+       res = m_num;
+       while (res & 0xffff00000000ULL) {
+               ++shift;
+               res >>= 1;
+       }
+       res *= parent_rate;
+       do_div(res, (m_den >> shift));
+
+       /* We cannot return the actual frequency in 32 bit, store it locally */
+       data->freq_vco = res;
+
+       /* Report kHz since the value is out of range */
+       do_div(res, 1000);
+
+       return (unsigned long)res;
+}
+
+static const struct clk_ops si5341_clk_ops = {
+       .recalc_rate = si5341_clk_recalc_rate,
+};
+
+/* Synthesizers, there are 5 synthesizers that connect to any of the outputs */
+
+/* The synthesizer is on if all power and enable bits are set */
+static int si5341_synth_clk_is_on(struct clk_hw *hw)
+{
+       struct clk_si5341_synth *synth = to_clk_si5341_synth(hw);
+       int err;
+       u32 val;
+       u8 index = synth->index;
+
+       err = regmap_read(synth->data->regmap,
+                       SI5341_SYNTH_N_CLK_TO_OUTX_EN, &val);
+       if (err < 0)
+               return 0;
+
+       if (!(val & BIT(index)))
+               return 0;
+
+       err = regmap_read(synth->data->regmap, SI5341_SYNTH_N_PDNB, &val);
+       if (err < 0)
+               return 0;
+
+       if (!(val & BIT(index)))
+               return 0;
+
+       /* This bit must be 0 for the synthesizer to receive clock input */
+       err = regmap_read(synth->data->regmap, SI5341_SYNTH_N_CLK_DIS, &val);
+       if (err < 0)
+               return 0;
+
+       return !(val & BIT(index));
+}
+
+static void si5341_synth_clk_unprepare(struct clk_hw *hw)
+{
+       struct clk_si5341_synth *synth = to_clk_si5341_synth(hw);
+       u8 index = synth->index; /* In range 0..5 */
+       u8 mask = BIT(index);
+
+       /* Disable output */
+       regmap_update_bits(synth->data->regmap,
+               SI5341_SYNTH_N_CLK_TO_OUTX_EN, mask, 0);
+       /* Power down */
+       regmap_update_bits(synth->data->regmap,
+               SI5341_SYNTH_N_PDNB, mask, 0);
+       /* Disable clock input to synth (set to 1 to disable) */
+       regmap_update_bits(synth->data->regmap,
+               SI5341_SYNTH_N_CLK_DIS, mask, mask);
+}
+
+static int si5341_synth_clk_prepare(struct clk_hw *hw)
+{
+       struct clk_si5341_synth *synth = to_clk_si5341_synth(hw);
+       int err;
+       u8 index = synth->index;
+       u8 mask = BIT(index);
+
+       /* Power up */
+       err = regmap_update_bits(synth->data->regmap,
+               SI5341_SYNTH_N_PDNB, mask, mask);
+       if (err < 0)
+               return err;
+
+       /* Enable clock input to synth (set bit to 0 to enable) */
+       err = regmap_update_bits(synth->data->regmap,
+               SI5341_SYNTH_N_CLK_DIS, mask, 0);
+       if (err < 0)
+               return err;
+
+       /* Enable output */
+       return regmap_update_bits(synth->data->regmap,
+               SI5341_SYNTH_N_CLK_TO_OUTX_EN, mask, mask);
+}
+
+/* Synth clock frequency: Fvco * n_den / n_den, with Fvco in 13500-14256 MHz */
+static unsigned long si5341_synth_clk_recalc_rate(struct clk_hw *hw,
+               unsigned long parent_rate)
+{
+       struct clk_si5341_synth *synth = to_clk_si5341_synth(hw);
+       u64 f;
+       u64 n_num;
+       u32 n_den;
+       int err;
+
+       err = si5341_decode_44_32(synth->data->regmap,
+                       SI5341_SYNTH_N_NUM(synth->index), &n_num, &n_den);
+       if (err < 0)
+               return err;
+
+       /*
+        * n_num and n_den are shifted left as much as possible, so to prevent
+        * overflow in 64-bit math, we shift n_den 4 bits to the right
+        */
+       f = synth->data->freq_vco;
+       f *= n_den >> 4;
+
+       /* Now we need to to 64-bit division: f/n_num */
+       /* And compensate for the 4 bits we dropped */
+       f = div64_u64(f, (n_num >> 4));
+
+       return f;
+}
+
+static long si5341_synth_clk_round_rate(struct clk_hw *hw, unsigned long rate,
+               unsigned long *parent_rate)
+{
+       struct clk_si5341_synth *synth = to_clk_si5341_synth(hw);
+       u64 f;
+
+       /* The synthesizer accuracy is such that anything in range will work */
+       f = synth->data->freq_vco;
+       do_div(f, SI5341_SYNTH_N_MAX);
+       if (rate < f)
+               return f;
+
+       f = synth->data->freq_vco;
+       do_div(f, SI5341_SYNTH_N_MIN);
+       if (rate > f)
+               return f;
+
+       return rate;
+}
+
+static int si5341_synth_program(struct clk_si5341_synth *synth,
+       u64 n_num, u32 n_den, bool is_integer)
+{
+       int err;
+       u8 index = synth->index;
+
+       err = si5341_encode_44_32(synth->data->regmap,
+                       SI5341_SYNTH_N_NUM(index), n_num, n_den);
+
+       err = regmap_update_bits(synth->data->regmap,
+               SI5341_SYNTH_N_PIBYP, BIT(index), is_integer ? BIT(index) : 0);
+       if (err < 0)
+               return err;
+
+       return regmap_write(synth->data->regmap,
+               SI5341_SYNTH_N_UPD(index), 0x01);
+}
+
+
+static int si5341_synth_clk_set_rate(struct clk_hw *hw, unsigned long rate,
+               unsigned long parent_rate)
+{
+       struct clk_si5341_synth *synth = to_clk_si5341_synth(hw);
+       u64 n_num;
+       u32 n_den;
+       u32 r;
+       u32 g;
+       bool is_integer;
+
+       n_num = synth->data->freq_vco;
+       n_den = rate;
+
+       /* see if there's an integer solution */
+       r = do_div(n_num, rate);
+       is_integer = (r == 0);
+       if (is_integer) {
+               /* Integer divider equal to n_num */
+               n_den = 1;
+       } else {
+               /* Calculate a fractional solution */
+               g = gcd(r, rate);
+               n_den = rate / g;
+               n_num *= n_den;
+               n_num += r / g;
+       }
+
+       dev_dbg(&synth->data->i2c_client->dev,
+                       "%s(%u): n=0x%llx d=0x%x %s\n", __func__,
+                               synth->index, n_num, n_den,
+                               is_integer ? "int" : "frac");
+
+       return si5341_synth_program(synth, n_num, n_den, is_integer);
+}
+
+static const struct clk_ops si5341_synth_clk_ops = {
+       .is_prepared = si5341_synth_clk_is_on,
+       .prepare = si5341_synth_clk_prepare,
+       .unprepare = si5341_synth_clk_unprepare,
+       .recalc_rate = si5341_synth_clk_recalc_rate,
+       .round_rate = si5341_synth_clk_round_rate,
+       .set_rate = si5341_synth_clk_set_rate,
+};
+
+static int si5341_output_clk_is_on(struct clk_hw *hw)
+{
+       struct clk_si5341_output *output = to_clk_si5341_output(hw);
+       int err;
+       u32 val;
+
+       err = regmap_read(output->data->regmap,
+                       SI5341_OUT_CONFIG(output), &val);
+       if (err < 0)
+               return err;
+
+       /* Bit 0=PDN, 1=OE so only a value of 0x2 enables the output */
+       return (val & 0x03) == SI5341_OUT_CFG_OE;
+}
+
+/* Disables and then powers down the output */
+static void si5341_output_clk_unprepare(struct clk_hw *hw)
+{
+       struct clk_si5341_output *output = to_clk_si5341_output(hw);
+
+       regmap_update_bits(output->data->regmap,
+                       SI5341_OUT_CONFIG(output),
+                       SI5341_OUT_CFG_OE, 0);
+       regmap_update_bits(output->data->regmap,
+                       SI5341_OUT_CONFIG(output),
+                       SI5341_OUT_CFG_PDN, SI5341_OUT_CFG_PDN);
+}
+
+/* Powers up and then enables the output */
+static int si5341_output_clk_prepare(struct clk_hw *hw)
+{
+       struct clk_si5341_output *output = to_clk_si5341_output(hw);
+       int err;
+
+       err = regmap_update_bits(output->data->regmap,
+                       SI5341_OUT_CONFIG(output),
+                       SI5341_OUT_CFG_PDN, 0);
+       if (err < 0)
+               return err;
+
+       return regmap_update_bits(output->data->regmap,
+                       SI5341_OUT_CONFIG(output),
+                       SI5341_OUT_CFG_OE, SI5341_OUT_CFG_OE);
+}
+
+static unsigned long si5341_output_clk_recalc_rate(struct clk_hw *hw,
+               unsigned long parent_rate)
+{
+       struct clk_si5341_output *output = to_clk_si5341_output(hw);
+       int err;
+       u32 val;
+       u32 r_divider;
+       u8 r[3];
+
+       err = regmap_bulk_read(output->data->regmap,
+                       SI5341_OUT_R_REG(output), r, 3);
+       if (err < 0)
+               return err;
+
+       /* Calculate value as 24-bit integer*/
+       r_divider = r[2] << 16 | r[1] << 8 | r[0];
+
+       /* If Rx_REG is zero, the divider is disabled, so return a "0" rate */
+       if (!r_divider)
+               return 0;
+
+       /* Divider is 2*(Rx_REG+1) */
+       r_divider += 1;
+       r_divider <<= 1;
+
+       err = regmap_read(output->data->regmap,
+                       SI5341_OUT_CONFIG(output), &val);
+       if (err < 0)
+               return err;
+
+       if (val & SI5341_OUT_CFG_RDIV_FORCE2)
+               r_divider = 2;
+
+       return parent_rate / r_divider;
+}
+
+static long si5341_output_clk_round_rate(struct clk_hw *hw, unsigned long rate,
+               unsigned long *parent_rate)
+{
+       unsigned long r;
+
+       r = *parent_rate >> 1;
+
+       /* If rate is an even divisor, no changes to parent required */
+       if (r && !(r % rate))
+               return (long)rate;
+
+       if (clk_hw_get_flags(hw) & CLK_SET_RATE_PARENT) {
+               if (rate > 200000000) {
+                       /* minimum r-divider is 2 */
+                       r = 2;
+               } else {
+                       /* Take a parent frequency near 400 MHz */
+                       r = (400000000u / rate) & ~1;
+               }
+               *parent_rate = r * rate;
+       } else {
+               /* We cannot change our parent's rate, report what we can do */
+               r /= rate;
+               rate = *parent_rate / (r << 1);
+       }
+
+       return rate;
+}
+
+static int si5341_output_clk_set_rate(struct clk_hw *hw, unsigned long rate,
+               unsigned long parent_rate)
+{
+       struct clk_si5341_output *output = to_clk_si5341_output(hw);
+       /* Frequency divider is (r_div + 1) * 2 */
+       u32 r_div = (parent_rate / rate) >> 1;
+       int err;
+       u8 r[3];
+
+       if (r_div <= 1)
+               r_div = 0;
+       else if (r_div >= BIT(24))
+               r_div = BIT(24) - 1;
+       else
+               --r_div;
+
+       /* For a value of "2", we set the "OUT0_RDIV_FORCE2" bit */
+       err = regmap_update_bits(output->data->regmap,
+                       SI5341_OUT_CONFIG(output),
+                       SI5341_OUT_CFG_RDIV_FORCE2,
+                       (r_div == 0) ? SI5341_OUT_CFG_RDIV_FORCE2 : 0);
+       if (err < 0)
+               return err;
+
+       /* Always write Rx_REG, because a zero value disables the divider */
+       r[0] = r_div ? (r_div & 0xff) : 1;
+       r[1] = (r_div >> 8) & 0xff;
+       r[2] = (r_div >> 16) & 0xff;
+       err = regmap_bulk_write(output->data->regmap,
+                       SI5341_OUT_R_REG(output), r, 3);
+
+       return 0;
+}
+
+static int si5341_output_reparent(struct clk_si5341_output *output, u8 index)
+{
+       return regmap_update_bits(output->data->regmap,
+               SI5341_OUT_MUX_SEL(output), 0x07, index);
+}
+
+static int si5341_output_set_parent(struct clk_hw *hw, u8 index)
+{
+       struct clk_si5341_output *output = to_clk_si5341_output(hw);
+
+       if (index >= output->data->num_synth)
+               return -EINVAL;
+
+       return si5341_output_reparent(output, index);
+}
+
+static u8 si5341_output_get_parent(struct clk_hw *hw)
+{
+       struct clk_si5341_output *output = to_clk_si5341_output(hw);
+       int err;
+       u32 val;
+
+       err = regmap_read(output->data->regmap,
+                       SI5341_OUT_MUX_SEL(output), &val);
+
+       return val & 0x7;
+}
+
+static const struct clk_ops si5341_output_clk_ops = {
+       .is_prepared = si5341_output_clk_is_on,
+       .prepare = si5341_output_clk_prepare,
+       .unprepare = si5341_output_clk_unprepare,
+       .recalc_rate = si5341_output_clk_recalc_rate,
+       .round_rate = si5341_output_clk_round_rate,
+       .set_rate = si5341_output_clk_set_rate,
+       .set_parent = si5341_output_set_parent,
+       .get_parent = si5341_output_get_parent,
+};
+
+/*
+ * The chip can be bought in a pre-programmed version, or one can program the
+ * NVM in the chip to boot up in a preset mode. This routine tries to determine
+ * if that's the case, or if we need to reset and program everything from
+ * scratch. Returns negative error, or true/false.
+ */
+static int si5341_is_programmed_already(struct clk_si5341 *data)
+{
+       int err;
+       u8 r[4];
+
+       /* Read the PLL divider value, it must have a non-zero value */
+       err = regmap_bulk_read(data->regmap, SI5341_PLL_M_DEN,
+                       r, ARRAY_SIZE(r));
+       if (err < 0)
+               return err;
+
+       return !!get_unaligned_le32(r);
+}
+
+static struct clk_hw *
+of_clk_si5341_get(struct of_phandle_args *clkspec, void *_data)
+{
+       struct clk_si5341 *data = _data;
+       unsigned int idx = clkspec->args[1];
+       unsigned int group = clkspec->args[0];
+
+       switch (group) {
+       case 0:
+               if (idx >= data->num_outputs) {
+                       dev_err(&data->i2c_client->dev,
+                               "invalid output index %u\n", idx);
+                       return ERR_PTR(-EINVAL);
+               }
+               return &data->clk[idx].hw;
+       case 1:
+               if (idx >= data->num_synth) {
+                       dev_err(&data->i2c_client->dev,
+                               "invalid synthesizer index %u\n", idx);
+                       return ERR_PTR(-EINVAL);
+               }
+               return &data->synth[idx].hw;
+       case 2:
+               if (idx > 0) {
+                       dev_err(&data->i2c_client->dev,
+                               "invalid PLL index %u\n", idx);
+                       return ERR_PTR(-EINVAL);
+               }
+               return &data->hw;
+       default:
+               dev_err(&data->i2c_client->dev, "invalid group %u\n", group);
+               return ERR_PTR(-EINVAL);
+       }
+}
+
+static int si5341_probe_chip_id(struct clk_si5341 *data)
+{
+       int err;
+       u8 reg[4];
+       u16 model;
+
+       err = regmap_bulk_read(data->regmap, SI5341_PN_BASE, reg,
+                               ARRAY_SIZE(reg));
+       if (err < 0) {
+               dev_err(&data->i2c_client->dev, "Failed to read chip ID\n");
+               return err;
+       }
+
+       model = get_unaligned_le16(reg);
+
+       dev_info(&data->i2c_client->dev, "Chip: %x Grade: %u Rev: %u\n",
+                model, reg[2], reg[3]);
+
+       switch (model) {
+       case 0x5340:
+               data->num_outputs = SI5340_MAX_NUM_OUTPUTS;
+               data->num_synth = SI5340_NUM_SYNTH;
+               data->reg_output_offset = si5340_reg_output_offset;
+               data->reg_rdiv_offset = si5340_reg_rdiv_offset;
+               break;
+       case 0x5341:
+               data->num_outputs = SI5341_MAX_NUM_OUTPUTS;
+               data->num_synth = SI5341_NUM_SYNTH;
+               data->reg_output_offset = si5341_reg_output_offset;
+               data->reg_rdiv_offset = si5341_reg_rdiv_offset;
+               break;
+       default:
+               dev_err(&data->i2c_client->dev, "Model '%x' not supported\n",
+                       model);
+               return -EINVAL;
+       }
+
+       return 0;
+}
+
+/* Read active settings into the regmap cache for later reference */
+static int si5341_read_settings(struct clk_si5341 *data)
+{
+       int err;
+       u8 i;
+       u8 r[10];
+
+       err = regmap_bulk_read(data->regmap, SI5341_PLL_M_NUM, r, 10);
+       if (err < 0)
+               return err;
+
+       err = regmap_bulk_read(data->regmap,
+                               SI5341_SYNTH_N_CLK_TO_OUTX_EN, r, 3);
+       if (err < 0)
+               return err;
+
+       err = regmap_bulk_read(data->regmap,
+                               SI5341_SYNTH_N_CLK_DIS, r, 1);
+       if (err < 0)
+               return err;
+
+       for (i = 0; i < data->num_synth; ++i) {
+               err = regmap_bulk_read(data->regmap,
+                                       SI5341_SYNTH_N_NUM(i), r, 10);
+               if (err < 0)
+                       return err;
+       }
+
+       for (i = 0; i < data->num_outputs; ++i) {
+               err = regmap_bulk_read(data->regmap,
+                                       data->reg_output_offset[i], r, 4);
+               if (err < 0)
+                       return err;
+
+               err = regmap_bulk_read(data->regmap,
+                                       data->reg_rdiv_offset[i], r, 3);
+               if (err < 0)
+                       return err;
+       }
+
+       return 0;
+}
+
+static int si5341_write_multiple(struct clk_si5341 *data,
+       const struct si5341_reg_default *values, unsigned int num_values)
+{
+       unsigned int i;
+       int res;
+
+       for (i = 0; i < num_values; ++i) {
+               res = regmap_write(data->regmap,
+                       values[i].address, values[i].value);
+               if (res < 0) {
+                       dev_err(&data->i2c_client->dev,
+                               "Failed to write %#x:%#x\n",
+                               values[i].address, values[i].value);
+                       return res;
+               }
+       }
+
+       return 0;
+}
+
+static const struct si5341_reg_default si5341_preamble[] = {
+       { 0x0B25, 0x00 },
+       { 0x0502, 0x01 },
+       { 0x0505, 0x03 },
+       { 0x0957, 0x1F },
+       { 0x0B4E, 0x1A },
+};
+
+static int si5341_send_preamble(struct clk_si5341 *data)
+{
+       int res;
+       u32 revision;
+
+       /* For revision 2 and up, the values are slightly different */
+       res = regmap_read(data->regmap, SI5341_DEVICE_REV, &revision);
+       if (res < 0)
+               return res;
+
+       /* Write "preamble" as specified by datasheet */
+       res = regmap_write(data->regmap, 0xB24, revision < 2 ? 0xD8 : 0xC0);
+       if (res < 0)
+               return res;
+       res = si5341_write_multiple(data,
+               si5341_preamble, ARRAY_SIZE(si5341_preamble));
+       if (res < 0)
+               return res;
+
+       /* Datasheet specifies a 300ms wait after sending the preamble */
+       msleep(300);
+
+       return 0;
+}
+
+/* Perform a soft reset and write post-amble */
+static int si5341_finalize_defaults(struct clk_si5341 *data)
+{
+       int res;
+       u32 revision;
+
+       res = regmap_read(data->regmap, SI5341_DEVICE_REV, &revision);
+       if (res < 0)
+               return res;
+
+       dev_dbg(&data->i2c_client->dev, "%s rev=%u\n", __func__, revision);
+
+       res = regmap_write(data->regmap, SI5341_SOFT_RST, 0x01);
+       if (res < 0)
+               return res;
+
+       /* Datasheet does not explain these nameless registers */
+       res = regmap_write(data->regmap, 0xB24, revision < 2 ? 0xDB : 0xC3);
+       if (res < 0)
+               return res;
+       res = regmap_write(data->regmap, 0x0B25, 0x02);
+       if (res < 0)
+               return res;
+
+       return 0;
+}
+
+
+static const struct regmap_range si5341_regmap_volatile_range[] = {
+       regmap_reg_range(0x000C, 0x0012), /* Status */
+       regmap_reg_range(0x001C, 0x001E), /* reset, finc/fdec */
+       regmap_reg_range(0x00E2, 0x00FE), /* NVM, interrupts, device ready */
+       /* Update bits for synth config */
+       regmap_reg_range(SI5341_SYNTH_N_UPD(0), SI5341_SYNTH_N_UPD(0)),
+       regmap_reg_range(SI5341_SYNTH_N_UPD(1), SI5341_SYNTH_N_UPD(1)),
+       regmap_reg_range(SI5341_SYNTH_N_UPD(2), SI5341_SYNTH_N_UPD(2)),
+       regmap_reg_range(SI5341_SYNTH_N_UPD(3), SI5341_SYNTH_N_UPD(3)),
+       regmap_reg_range(SI5341_SYNTH_N_UPD(4), SI5341_SYNTH_N_UPD(4)),
+};
+
+static const struct regmap_access_table si5341_regmap_volatile = {
+       .yes_ranges = si5341_regmap_volatile_range,
+       .n_yes_ranges = ARRAY_SIZE(si5341_regmap_volatile_range),
+};
+
+/* Pages 0, 1, 2, 3, 9, A, B are valid, so there are 12 pages */
+static const struct regmap_range_cfg si5341_regmap_ranges[] = {
+       {
+               .range_min = 0,
+               .range_max = SI5341_REGISTER_MAX,
+               .selector_reg = SI5341_PAGE,
+               .selector_mask = 0xff,
+               .selector_shift = 0,
+               .window_start = 0,
+               .window_len = 256,
+       },
+};
+
+static const struct regmap_config si5341_regmap_config = {
+       .reg_bits = 8,
+       .val_bits = 8,
+       .cache_type = REGCACHE_RBTREE,
+       .ranges = si5341_regmap_ranges,
+       .num_ranges = ARRAY_SIZE(si5341_regmap_ranges),
+       .max_register = SI5341_REGISTER_MAX,
+       .volatile_table = &si5341_regmap_volatile,
+};
+
+static int si5341_dt_parse_dt(struct i2c_client *client,
+       struct clk_si5341_output_config *config)
+{
+       struct device_node *child;
+       struct device_node *np = client->dev.of_node;
+       u32 num;
+       u32 val;
+
+       memset(config, 0, sizeof(struct clk_si5341_output_config) *
+                               SI5341_MAX_NUM_OUTPUTS);
+
+       for_each_child_of_node(np, child) {
+               if (of_property_read_u32(child, "reg", &num)) {
+                       dev_err(&client->dev, "missing reg property of %s\n",
+                               child->name);
+                       goto put_child;
+               }
+
+               if (num >= SI5341_MAX_NUM_OUTPUTS) {
+                       dev_err(&client->dev, "invalid clkout %d\n", num);
+                       goto put_child;
+               }
+
+               if (!of_property_read_u32(child, "silabs,format", &val)) {
+                       /* Set cm and ampl conservatively to 3v3 settings */
+                       switch (val) {
+                       case 1: /* normal differential */
+                               config[num].out_cm_ampl_bits = 0x33;
+                               break;
+                       case 2: /* low-power differential */
+                               config[num].out_cm_ampl_bits = 0x13;
+                               break;
+                       case 4: /* LVCMOS */
+                               config[num].out_cm_ampl_bits = 0x33;
+                               /* Set SI recommended impedance for LVCMOS */
+                               config[num].out_format_drv_bits |= 0xc0;
+                               break;
+                       default:
+                               dev_err(&client->dev,
+                                       "invalid silabs,format %u for %u\n",
+                                       val, num);
+                               goto put_child;
+                       }
+                       config[num].out_format_drv_bits &= ~0x07;
+                       config[num].out_format_drv_bits |= val & 0x07;
+                       /* Always enable the SYNC feature */
+                       config[num].out_format_drv_bits |= 0x08;
+               }
+
+               if (!of_property_read_u32(child, "silabs,common-mode", &val)) {
+                       if (val > 0xf) {
+                               dev_err(&client->dev,
+                                       "invalid silabs,common-mode %u\n",
+                                       val);
+                               goto put_child;
+                       }
+                       config[num].out_cm_ampl_bits &= 0xf0;
+                       config[num].out_cm_ampl_bits |= val & 0x0f;
+               }
+
+               if (!of_property_read_u32(child, "silabs,amplitude", &val)) {
+                       if (val > 0xf) {
+                               dev_err(&client->dev,
+                                       "invalid silabs,amplitude %u\n",
+                                       val);
+                               goto put_child;
+                       }
+                       config[num].out_cm_ampl_bits &= 0x0f;
+                       config[num].out_cm_ampl_bits |= (val << 4) & 0xf0;
+               }
+
+               if (of_property_read_bool(child, "silabs,disable-high"))
+                       config[num].out_format_drv_bits |= 0x10;
+
+               config[num].synth_master =
+                       of_property_read_bool(child, "silabs,synth-master");
+
+               config[num].always_on =
+                       of_property_read_bool(child, "always-on");
+       }
+
+       return 0;
+
+put_child:
+       of_node_put(child);
+       return -EINVAL;
+}
+
+/*
+ * If not pre-configured, calculate and set the PLL configuration manually.
+ * For low-jitter performance, the PLL should be set such that the synthesizers
+ * only need integer division.
+ * Without any user guidance, we'll set the PLL to 14GHz, which still allows
+ * the chip to generate any frequency on its outputs, but jitter performance
+ * may be sub-optimal.
+ */
+static int si5341_initialize_pll(struct clk_si5341 *data)
+{
+       struct device_node *np = data->i2c_client->dev.of_node;
+       u32 m_num = 0;
+       u32 m_den = 0;
+
+       if (of_property_read_u32(np, "silabs,pll-m-num", &m_num)) {
+               dev_err(&data->i2c_client->dev,
+                       "PLL configuration requires silabs,pll-m-num\n");
+       }
+       if (of_property_read_u32(np, "silabs,pll-m-den", &m_den)) {
+               dev_err(&data->i2c_client->dev,
+                       "PLL configuration requires silabs,pll-m-den\n");
+       }
+
+       if (!m_num || !m_den) {
+               dev_err(&data->i2c_client->dev,
+                       "PLL configuration invalid, assume 14GHz\n");
+               m_den = clk_get_rate(data->pxtal) / 10;
+               m_num = 1400000000;
+       }
+
+       return si5341_encode_44_32(data->regmap,
+                       SI5341_PLL_M_NUM, m_num, m_den);
+}
+
+static int si5341_probe(struct i2c_client *client,
+               const struct i2c_device_id *id)
+{
+       struct clk_si5341 *data;
+       struct clk_init_data init;
+       const char *root_clock_name;
+       const char *synth_clock_names[SI5341_NUM_SYNTH];
+       int err;
+       unsigned int i;
+       struct clk_si5341_output_config config[SI5341_MAX_NUM_OUTPUTS];
+       bool initialization_required;
+
+       data = devm_kzalloc(&client->dev, sizeof(*data), GFP_KERNEL);
+       if (!data)
+               return -ENOMEM;
+
+       data->i2c_client = client;
+
+       data->pxtal = devm_clk_get(&client->dev, "xtal");
+       if (IS_ERR(data->pxtal)) {
+               if (PTR_ERR(data->pxtal) == -EPROBE_DEFER)
+                       return -EPROBE_DEFER;
+
+               dev_err(&client->dev, "Missing xtal clock input\n");
+       }
+
+       err = si5341_dt_parse_dt(client, config);
+       if (err)
+               return err;
+
+       if (of_property_read_string(client->dev.of_node, "clock-output-names",
+                       &init.name))
+               init.name = client->dev.of_node->name;
+       root_clock_name = init.name;
+
+       data->regmap = devm_regmap_init_i2c(client, &si5341_regmap_config);
+       if (IS_ERR(data->regmap))
+               return PTR_ERR(data->regmap);
+
+       i2c_set_clientdata(client, data);
+
+       err = si5341_probe_chip_id(data);
+       if (err < 0)
+               return err;
+
+       /* "Activate" the xtal (usually a fixed clock) */
+       clk_prepare_enable(data->pxtal);
+
+       if (of_property_read_bool(client->dev.of_node, "silabs,reprogram")) {
+               initialization_required = true;
+       } else {
+               err = si5341_is_programmed_already(data);
+               if (err < 0)
+                       return err;
+
+               initialization_required = !err;
+       }
+
+       if (initialization_required) {
+               /* Populate the regmap cache in preparation for "cache only" */
+               err = si5341_read_settings(data);
+               if (err < 0)
+                       return err;
+
+               err = si5341_send_preamble(data);
+               if (err < 0)
+                       return err;
+
+               /*
+                * We intend to send all 'final' register values in a single
+                * transaction. So cache all register writes until we're done
+                * configuring.
+                */
+               regcache_cache_only(data->regmap, true);
+
+               /* Write the configuration pairs from the firmware blob */
+               err = si5341_write_multiple(data, si5341_reg_defaults,
+                                       ARRAY_SIZE(si5341_reg_defaults));
+               if (err < 0)
+                       return err;
+
+               /* PLL configuration is required */
+               err = si5341_initialize_pll(data);
+               if (err < 0)
+                       return err;
+       }
+
+       /* Register the PLL */
+       data->pxtal_name = __clk_get_name(data->pxtal);
+       init.parent_names = &data->pxtal_name;
+       init.num_parents = 1; /* For now, only XTAL input supported */
+       init.ops = &si5341_clk_ops;
+       init.flags = 0;
+       data->hw.init = &init;
+
+       err = devm_clk_hw_register(&client->dev, &data->hw);
+       if (err) {
+               dev_err(&client->dev, "clock registration failed\n");
+               return err;
+       }
+
+       init.num_parents = 1;
+       init.parent_names = &root_clock_name;
+       init.ops = &si5341_synth_clk_ops;
+       for (i = 0; i < data->num_synth; ++i) {
+               synth_clock_names[i] = devm_kasprintf(&client->dev, GFP_KERNEL,
+                               "%s.N%u", client->dev.of_node->name, i);
+               init.name = synth_clock_names[i];
+               data->synth[i].index = i;
+               data->synth[i].data = data;
+               data->synth[i].hw.init = &init;
+               err = devm_clk_hw_register(&client->dev, &data->synth[i].hw);
+               if (err) {
+                       dev_err(&client->dev,
+                               "synth N%u registration failed\n", i);
+               }
+       }
+
+       init.num_parents = data->num_synth;
+       init.parent_names = synth_clock_names;
+       init.ops = &si5341_output_clk_ops;
+       for (i = 0; i < data->num_outputs; ++i) {
+               init.name = kasprintf(GFP_KERNEL, "%s.%d",
+                       client->dev.of_node->name, i);
+               init.flags = config[i].synth_master ? CLK_SET_RATE_PARENT : 0;
+               data->clk[i].index = i;
+               data->clk[i].data = data;
+               data->clk[i].hw.init = &init;
+               if (config[i].out_format_drv_bits & 0x07) {
+                       regmap_write(data->regmap,
+                               SI5341_OUT_FORMAT(&data->clk[i]),
+                               config[i].out_format_drv_bits);
+                       regmap_write(data->regmap,
+                               SI5341_OUT_CM(&data->clk[i]),
+                               config[i].out_cm_ampl_bits);
+               }
+               err = devm_clk_hw_register(&client->dev, &data->clk[i].hw);
+               kfree(init.name); /* clock framework made a copy of the name */
+               if (err) {
+                       dev_err(&client->dev,
+                               "output %u registration failed\n", i);
+                       return err;
+               }
+               if (config[i].always_on)
+                       clk_prepare(data->clk[i].hw.clk);
+       }
+
+       err = of_clk_add_hw_provider(client->dev.of_node, of_clk_si5341_get,
+                       data);
+       if (err) {
+               dev_err(&client->dev, "unable to add clk provider\n");
+               return err;
+       }
+
+       if (initialization_required) {
+               /* Synchronize */
+               regcache_cache_only(data->regmap, false);
+               err = regcache_sync(data->regmap);
+               if (err < 0)
+                       return err;
+
+               err = si5341_finalize_defaults(data);
+               if (err < 0)
+                       return err;
+       }
+
+       /* Free the names, clk framework makes copies */
+       for (i = 0; i < data->num_synth; ++i)
+                devm_kfree(&client->dev, (void *)synth_clock_names[i]);
+
+       return 0;
+}
+
+static const struct i2c_device_id si5341_id[] = {
+       { "si5340", 0 },
+       { "si5341", 1 },
+       { }
+};
+MODULE_DEVICE_TABLE(i2c, si5341_id);
+
+static const struct of_device_id clk_si5341_of_match[] = {
+       { .compatible = "silabs,si5340" },
+       { .compatible = "silabs,si5341" },
+       { }
+};
+MODULE_DEVICE_TABLE(of, clk_si5341_of_match);
+
+static struct i2c_driver si5341_driver = {
+       .driver = {
+               .name = "si5341",
+               .of_match_table = clk_si5341_of_match,
+       },
+       .probe          = si5341_probe,
+       .id_table       = si5341_id,
+};
+module_i2c_driver(si5341_driver);
+
+MODULE_AUTHOR("Mike Looijmans <mike.looijmans@topic.nl>");
+MODULE_DESCRIPTION("Si5341 driver");
+MODULE_LICENSE("GPL");
index 64e607f..d9ec908 100644 (file)
@@ -7,6 +7,7 @@
 
 #include <linux/clk-provider.h>
 #include <linux/delay.h>
+#include <linux/math64.h>
 #include <linux/module.h>
 #include <linux/i2c.h>
 #include <linux/regmap.h>
 /* Lowest frequency synthesizeable using only the HS divider */
 #define MIN_HSDIV_FREQ (FVCO_MIN / HS_DIV_MAX)
 
+/* Range and interpretation of the adjustment value */
+#define DELTA_M_MAX    8161512
+#define DELTA_M_FRAC_NUM       19
+#define DELTA_M_FRAC_DEN       20000
+
 enum si544_speed_grade {
        si544a,
        si544b,
@@ -71,12 +77,14 @@ struct clk_si544 {
  * @hs_div:            1st divider, 5..2046, must be even when >33
  * @ls_div_bits:       2nd divider, as 2^x, range 0..5
  *                      If ls_div_bits is non-zero, hs_div must be even
+ * @delta_m:           Frequency shift for small -950..+950 ppm changes, 24 bit
  */
 struct clk_si544_muldiv {
        u32 fb_div_frac;
        u16 fb_div_int;
        u16 hs_div;
        u8 ls_div_bits;
+       s32 delta_m;
 };
 
 /* Enables or disables the output driver */
@@ -134,9 +142,30 @@ static int si544_get_muldiv(struct clk_si544 *data,
        settings->fb_div_int = reg[4] | (reg[5] & 0x07) << 8;
        settings->fb_div_frac = reg[0] | reg[1] << 8 | reg[2] << 16 |
                                reg[3] << 24;
+
+       err = regmap_bulk_read(data->regmap, SI544_REG_ADPLL_DELTA_M0, reg, 3);
+       if (err)
+               return err;
+
+       /* Interpret as 24-bit signed number */
+       settings->delta_m = reg[0] << 8 | reg[1] << 16 | reg[2] << 24;
+       settings->delta_m >>= 8;
+
        return 0;
 }
 
+static int si544_set_delta_m(struct clk_si544 *data, s32 delta_m)
+{
+       u8 reg[3];
+
+       reg[0] = delta_m;
+       reg[1] = delta_m >> 8;
+       reg[2] = delta_m >> 16;
+
+       return regmap_bulk_write(data->regmap, SI544_REG_ADPLL_DELTA_M0,
+                                reg, 3);
+}
+
 static int si544_set_muldiv(struct clk_si544 *data,
        struct clk_si544_muldiv *settings)
 {
@@ -238,11 +267,15 @@ static int si544_calc_muldiv(struct clk_si544_muldiv *settings,
        do_div(vco, FXO);
        settings->fb_div_frac = vco;
 
+       /* Reset the frequency adjustment */
+       settings->delta_m = 0;
+
        return 0;
 }
 
 /* Calculate resulting frequency given the register settings */
-static unsigned long si544_calc_rate(struct clk_si544_muldiv *settings)
+static unsigned long si544_calc_center_rate(
+               const struct clk_si544_muldiv *settings)
 {
        u32 d = settings->hs_div * BIT(settings->ls_div_bits);
        u64 vco;
@@ -261,6 +294,25 @@ static unsigned long si544_calc_rate(struct clk_si544_muldiv *settings)
        return vco;
 }
 
+static unsigned long si544_calc_rate(const struct clk_si544_muldiv *settings)
+{
+       unsigned long rate = si544_calc_center_rate(settings);
+       s64 delta = (s64)rate * (DELTA_M_FRAC_NUM * settings->delta_m);
+
+       /*
+        * The clock adjustment is much smaller than 1 Hz, round to the
+        * nearest multiple. Apparently div64_s64 rounds towards zero, hence
+        * check the sign and adjust into the proper direction.
+        */
+       if (settings->delta_m < 0)
+               delta -= ((s64)DELTA_M_MAX * DELTA_M_FRAC_DEN) / 2;
+       else
+               delta += ((s64)DELTA_M_MAX * DELTA_M_FRAC_DEN) / 2;
+       delta = div64_s64(delta, ((s64)DELTA_M_MAX * DELTA_M_FRAC_DEN));
+
+       return rate + delta;
+}
+
 static unsigned long si544_recalc_rate(struct clk_hw *hw,
                unsigned long parent_rate)
 {
@@ -279,33 +331,60 @@ static long si544_round_rate(struct clk_hw *hw, unsigned long rate,
                unsigned long *parent_rate)
 {
        struct clk_si544 *data = to_clk_si544(hw);
-       struct clk_si544_muldiv settings;
-       int err;
 
        if (!is_valid_frequency(data, rate))
                return -EINVAL;
 
-       err = si544_calc_muldiv(&settings, rate);
-       if (err)
-               return err;
+       /* The accuracy is less than 1 Hz, so any rate is possible */
+       return rate;
+}
 
-       return si544_calc_rate(&settings);
+/* Calculates the maximum "small" change, 950 * rate / 1000000 */
+static unsigned long si544_max_delta(unsigned long rate)
+{
+       u64 num = rate;
+
+       num *= DELTA_M_FRAC_NUM;
+       do_div(num, DELTA_M_FRAC_DEN);
+
+       return num;
+}
+
+static s32 si544_calc_delta(s32 delta, s32 max_delta)
+{
+       s64 n = (s64)delta * DELTA_M_MAX;
+
+       return div_s64(n, max_delta);
 }
 
-/*
- * Update output frequency for "big" frequency changes
- */
 static int si544_set_rate(struct clk_hw *hw, unsigned long rate,
                unsigned long parent_rate)
 {
        struct clk_si544 *data = to_clk_si544(hw);
        struct clk_si544_muldiv settings;
+       unsigned long center;
+       long max_delta;
+       long delta;
        unsigned int old_oe_state;
        int err;
 
        if (!is_valid_frequency(data, rate))
                return -EINVAL;
 
+       /* Try using the frequency adjustment feature for a <= 950ppm change */
+       err = si544_get_muldiv(data, &settings);
+       if (err)
+               return err;
+
+       center = si544_calc_center_rate(&settings);
+       max_delta = si544_max_delta(center);
+       delta = rate - center;
+
+       if (abs(delta) <= max_delta)
+               return si544_set_delta_m(data,
+                                        si544_calc_delta(delta, max_delta));
+
+       /* Too big for the delta adjustment, need to reprogram */
        err = si544_calc_muldiv(&settings, rate);
        if (err)
                return err;
@@ -321,6 +400,9 @@ static int si544_set_rate(struct clk_hw *hw, unsigned long rate,
        if (err < 0)
                return err;
 
+       err = si544_set_delta_m(data, settings.delta_m);
+       if (err < 0)
+               return err;
 
        err = si544_set_muldiv(data, &settings);
        if (err < 0)
index 87b410d..c099070 100644 (file)
@@ -1324,10 +1324,7 @@ static void clk_core_init_rate_req(struct clk_core * const core,
 
 static bool clk_core_can_round(struct clk_core * const core)
 {
-       if (core->ops->determine_rate || core->ops->round_rate)
-               return true;
-
-       return false;
+       return core->ops->determine_rate || core->ops->round_rate;
 }
 
 static int clk_core_round_rate_nolock(struct clk_core *core,
@@ -2194,7 +2191,7 @@ int clk_set_rate(struct clk *clk, unsigned long rate)
 EXPORT_SYMBOL_GPL(clk_set_rate);
 
 /**
- * clk_set_rate_exclusive - specify a new rate get exclusive control
+ * clk_set_rate_exclusive - specify a new rate and get exclusive control
  * @clk: the clk whose rate is being changed
  * @rate: the new rate for clk
  *
@@ -2202,7 +2199,7 @@ EXPORT_SYMBOL_GPL(clk_set_rate);
  * within a critical section
  *
  * This can be used initially to ensure that at least 1 consumer is
- * statisfied when several consumers are competing for exclusivity over the
+ * satisfied when several consumers are competing for exclusivity over the
  * same clock provider.
  *
  * The exclusivity is not applied if setting the rate failed.
@@ -2997,20 +2994,65 @@ static int clk_flags_show(struct seq_file *s, void *data)
 }
 DEFINE_SHOW_ATTRIBUTE(clk_flags);
 
+static void possible_parent_show(struct seq_file *s, struct clk_core *core,
+                                unsigned int i, char terminator)
+{
+       struct clk_core *parent;
+
+       /*
+        * Go through the following options to fetch a parent's name.
+        *
+        * 1. Fetch the registered parent clock and use its name
+        * 2. Use the global (fallback) name if specified
+        * 3. Use the local fw_name if provided
+        * 4. Fetch parent clock's clock-output-name if DT index was set
+        *
+        * This may still fail in some cases, such as when the parent is
+        * specified directly via a struct clk_hw pointer, but it isn't
+        * registered (yet).
+        */
+       parent = clk_core_get_parent_by_index(core, i);
+       if (parent)
+               seq_printf(s, "%s", parent->name);
+       else if (core->parents[i].name)
+               seq_printf(s, "%s", core->parents[i].name);
+       else if (core->parents[i].fw_name)
+               seq_printf(s, "<%s>(fw)", core->parents[i].fw_name);
+       else if (core->parents[i].index >= 0)
+               seq_printf(s, "%s",
+                          of_clk_get_parent_name(core->of_node,
+                                                 core->parents[i].index));
+       else
+               seq_puts(s, "(missing)");
+
+       seq_putc(s, terminator);
+}
+
 static int possible_parents_show(struct seq_file *s, void *data)
 {
        struct clk_core *core = s->private;
        int i;
 
        for (i = 0; i < core->num_parents - 1; i++)
-               seq_printf(s, "%s ", core->parents[i].name);
+               possible_parent_show(s, core, i, ' ');
 
-       seq_printf(s, "%s\n", core->parents[i].name);
+       possible_parent_show(s, core, i, '\n');
 
        return 0;
 }
 DEFINE_SHOW_ATTRIBUTE(possible_parents);
 
+static int current_parent_show(struct seq_file *s, void *data)
+{
+       struct clk_core *core = s->private;
+
+       if (core->parent)
+               seq_printf(s, "%s\n", core->parent->name);
+
+       return 0;
+}
+DEFINE_SHOW_ATTRIBUTE(current_parent);
+
 static int clk_duty_cycle_show(struct seq_file *s, void *data)
 {
        struct clk_core *core = s->private;
@@ -3043,6 +3085,10 @@ static void clk_debug_create_one(struct clk_core *core, struct dentry *pdentry)
        debugfs_create_file("clk_duty_cycle", 0444, root, core,
                            &clk_duty_cycle_fops);
 
+       if (core->num_parents > 0)
+               debugfs_create_file("clk_parent", 0444, root, core,
+                                   &current_parent_fops);
+
        if (core->num_parents > 1)
                debugfs_create_file("clk_possible_parents", 0444, root, core,
                                    &possible_parents_fops);
@@ -4038,6 +4084,7 @@ struct of_clk_provider {
        void *data;
 };
 
+extern struct of_device_id __clk_of_table;
 static const struct of_device_id __clk_of_table_sentinel
        __used __section(__clk_of_table_end);
 
index d8400d6..2d80190 100644 (file)
@@ -33,10 +33,6 @@ clk_hw_create_clk(struct device *dev, struct clk_hw *hw, const char *dev_id,
 {
        return (struct clk *)hw;
 }
-static struct clk_hw *__clk_get_hw(struct clk *clk)
-{
-       return (struct clk_hw *)clk;
-}
 static inline void __clk_put(struct clk *clk) { }
 
 #endif
index 7b35a11..25c863d 100644 (file)
@@ -72,13 +72,14 @@ static const struct clk_ops clk_busy_divider_ops = {
        .set_rate = clk_busy_divider_set_rate,
 };
 
-struct clk *imx_clk_busy_divider(const char *name, const char *parent_name,
+struct clk_hw *imx_clk_hw_busy_divider(const char *name, const char *parent_name,
                                 void __iomem *reg, u8 shift, u8 width,
                                 void __iomem *busy_reg, u8 busy_shift)
 {
        struct clk_busy_divider *busy;
-       struct clk *clk;
+       struct clk_hw *hw;
        struct clk_init_data init;
+       int ret;
 
        busy = kzalloc(sizeof(*busy), GFP_KERNEL);
        if (!busy)
@@ -101,11 +102,15 @@ struct clk *imx_clk_busy_divider(const char *name, const char *parent_name,
 
        busy->div.hw.init = &init;
 
-       clk = clk_register(NULL, &busy->div.hw);
-       if (IS_ERR(clk))
+       hw = &busy->div.hw;
+
+       ret = clk_hw_register(NULL, hw);
+       if (ret) {
                kfree(busy);
+               return ERR_PTR(ret);
+       }
 
-       return clk;
+       return hw;
 }
 
 struct clk_busy_mux {
@@ -146,13 +151,14 @@ static const struct clk_ops clk_busy_mux_ops = {
        .set_parent = clk_busy_mux_set_parent,
 };
 
-struct clk *imx_clk_busy_mux(const char *name, void __iomem *reg, u8 shift,
+struct clk_hw *imx_clk_hw_busy_mux(const char *name, void __iomem *reg, u8 shift,
                             u8 width, void __iomem *busy_reg, u8 busy_shift,
                             const char * const *parent_names, int num_parents)
 {
        struct clk_busy_mux *busy;
-       struct clk *clk;
+       struct clk_hw *hw;
        struct clk_init_data init;
+       int ret;
 
        busy = kzalloc(sizeof(*busy), GFP_KERNEL);
        if (!busy)
@@ -175,9 +181,13 @@ struct clk *imx_clk_busy_mux(const char *name, void __iomem *reg, u8 shift,
 
        busy->mux.hw.init = &init;
 
-       clk = clk_register(NULL, &busy->mux.hw);
-       if (IS_ERR(clk))
+       hw = &busy->mux.hw;
+
+       ret = clk_hw_register(NULL, hw);
+       if (ret) {
                kfree(busy);
+               return ERR_PTR(ret);
+       }
 
-       return clk;
+       return hw;
 }
index 00d026e..cb182be 100644 (file)
@@ -69,13 +69,14 @@ static const struct clk_ops clk_cpu_ops = {
        .set_rate       = clk_cpu_set_rate,
 };
 
-struct clk *imx_clk_cpu(const char *name, const char *parent_name,
+struct clk_hw *imx_clk_hw_cpu(const char *name, const char *parent_name,
                struct clk *div, struct clk *mux, struct clk *pll,
                struct clk *step)
 {
        struct clk_cpu *cpu;
-       struct clk *clk;
+       struct clk_hw *hw;
        struct clk_init_data init;
+       int ret;
 
        cpu = kzalloc(sizeof(*cpu), GFP_KERNEL);
        if (!cpu)
@@ -93,10 +94,13 @@ struct clk *imx_clk_cpu(const char *name, const char *parent_name,
        init.num_parents = 1;
 
        cpu->hw.init = &init;
+       hw = &cpu->hw;
 
-       clk = clk_register(NULL, &cpu->hw);
-       if (IS_ERR(clk))
+       ret = clk_hw_register(NULL, hw);
+       if (ret) {
                kfree(cpu);
+               return ERR_PTR(ret);
+       }
 
-       return clk;
+       return hw;
 }
index bab46c6..4b17b91 100644 (file)
@@ -85,13 +85,14 @@ static const struct clk_ops clk_fixup_div_ops = {
        .set_rate = clk_fixup_div_set_rate,
 };
 
-struct clk *imx_clk_fixup_divider(const char *name, const char *parent,
+struct clk_hw *imx_clk_hw_fixup_divider(const char *name, const char *parent,
                                  void __iomem *reg, u8 shift, u8 width,
                                  void (*fixup)(u32 *val))
 {
        struct clk_fixup_div *fixup_div;
-       struct clk *clk;
+       struct clk_hw *hw;
        struct clk_init_data init;
+       int ret;
 
        if (!fixup)
                return ERR_PTR(-EINVAL);
@@ -114,9 +115,13 @@ struct clk *imx_clk_fixup_divider(const char *name, const char *parent,
        fixup_div->ops = &clk_divider_ops;
        fixup_div->fixup = fixup;
 
-       clk = clk_register(NULL, &fixup_div->divider.hw);
-       if (IS_ERR(clk))
+       hw = &fixup_div->divider.hw;
+
+       ret = clk_hw_register(NULL, hw);
+       if (ret) {
                kfree(fixup_div);
+               return ERR_PTR(ret);
+       }
 
-       return clk;
+       return hw;
 }
index 1aa3e8d..b569d91 100644 (file)
@@ -63,13 +63,14 @@ static const struct clk_ops clk_fixup_mux_ops = {
        .set_parent = clk_fixup_mux_set_parent,
 };
 
-struct clk *imx_clk_fixup_mux(const char *name, void __iomem *reg,
+struct clk_hw *imx_clk_hw_fixup_mux(const char *name, void __iomem *reg,
                              u8 shift, u8 width, const char * const *parents,
                              int num_parents, void (*fixup)(u32 *val))
 {
        struct clk_fixup_mux *fixup_mux;
-       struct clk *clk;
+       struct clk_hw *hw;
        struct clk_init_data init;
+       int ret;
 
        if (!fixup)
                return ERR_PTR(-EINVAL);
@@ -92,9 +93,13 @@ struct clk *imx_clk_fixup_mux(const char *name, void __iomem *reg,
        fixup_mux->ops = &clk_mux_ops;
        fixup_mux->fixup = fixup;
 
-       clk = clk_register(NULL, &fixup_mux->mux.hw);
-       if (IS_ERR(clk))
+       hw = &fixup_mux->mux.hw;
+
+       ret = clk_hw_register(NULL, hw);
+       if (ret) {
                kfree(fixup_mux);
+               return ERR_PTR(ret);
+       }
 
-       return clk;
+       return hw;
 }
index cffa496..7734289 100644 (file)
@@ -55,13 +55,14 @@ static const struct clk_ops clk_gate_exclusive_ops = {
        .is_enabled = clk_gate_exclusive_is_enabled,
 };
 
-struct clk *imx_clk_gate_exclusive(const char *name, const char *parent,
+struct clk_hw *imx_clk_hw_gate_exclusive(const char *name, const char *parent,
         void __iomem *reg, u8 shift, u32 exclusive_mask)
 {
        struct clk_gate_exclusive *exgate;
        struct clk_gate *gate;
-       struct clk *clk;
+       struct clk_hw *hw;
        struct clk_init_data init;
+       int ret;
 
        if (exclusive_mask == 0)
                return ERR_PTR(-EINVAL);
@@ -83,9 +84,13 @@ struct clk *imx_clk_gate_exclusive(const char *name, const char *parent,
        gate->hw.init = &init;
        exgate->exclusive_mask = exclusive_mask;
 
-       clk = clk_register(NULL, &gate->hw);
-       if (IS_ERR(clk))
-               kfree(exgate);
+       hw = &gate->hw;
 
-       return clk;
+       ret = clk_hw_register(NULL, hw);
+       if (ret) {
+               kfree(gate);
+               return ERR_PTR(ret);
+       }
+
+       return hw;
 }
index ec08fda..7d44ce8 100644 (file)
@@ -122,15 +122,16 @@ static const struct clk_ops clk_gate2_ops = {
        .is_enabled = clk_gate2_is_enabled,
 };
 
-struct clk *clk_register_gate2(struct device *dev, const char *name,
+struct clk_hw *clk_hw_register_gate2(struct device *dev, const char *name,
                const char *parent_name, unsigned long flags,
                void __iomem *reg, u8 bit_idx, u8 cgr_val,
                u8 clk_gate2_flags, spinlock_t *lock,
                unsigned int *share_count)
 {
        struct clk_gate2 *gate;
-       struct clk *clk;
+       struct clk_hw *hw;
        struct clk_init_data init;
+       int ret;
 
        gate = kzalloc(sizeof(struct clk_gate2), GFP_KERNEL);
        if (!gate)
@@ -151,10 +152,13 @@ struct clk *clk_register_gate2(struct device *dev, const char *name,
        init.num_parents = parent_name ? 1 : 0;
 
        gate->hw.init = &init;
+       hw = &gate->hw;
 
-       clk = clk_register(dev, &gate->hw);
-       if (IS_ERR(clk))
+       ret = clk_hw_register(NULL, hw);
+       if (ret) {
                kfree(gate);
+               return ERR_PTR(ret);
+       }
 
-       return clk;
+       return hw;
 }
index d5de733..60f2de8 100644 (file)
@@ -8,6 +8,7 @@
 #include <linux/types.h>
 #include <linux/clk.h>
 #include <linux/clkdev.h>
+#include <linux/clk-provider.h>
 #include <linux/err.h>
 #include <linux/io.h>
 #include <linux/of.h>
@@ -87,8 +88,8 @@ static const char *pll5_bypass_sels[] = { "pll5", "pll5_bypass_src", };
 static const char *pll6_bypass_sels[] = { "pll6", "pll6_bypass_src", };
 static const char *pll7_bypass_sels[] = { "pll7", "pll7_bypass_src", };
 
-static struct clk *clk[IMX6QDL_CLK_END];
-static struct clk_onecell_data clk_data;
+static struct clk_hw **hws;
+static struct clk_hw_onecell_data *clk_hw_data;
 
 static struct clk_div_table clk_enet_ref_table[] = {
        { .val = 0, .div = 20, },
@@ -138,12 +139,13 @@ static inline int clk_on_imx6dl(void)
        return of_machine_is_compatible("fsl,imx6dl");
 }
 
-static struct clk ** const uart_clks[] __initconst = {
-       &clk[IMX6QDL_CLK_UART_IPG],
-       &clk[IMX6QDL_CLK_UART_SERIAL],
-       NULL
+static const int uart_clk_ids[] __initconst = {
+       IMX6QDL_CLK_UART_IPG,
+       IMX6QDL_CLK_UART_SERIAL,
 };
 
+static struct clk **uart_clks[ARRAY_SIZE(uart_clk_ids) + 1] __initdata;
+
 static int ldb_di_sel_by_clock_id(int clock_id)
 {
        switch (clock_id) {
@@ -254,25 +256,14 @@ static bool pll6_bypassed(struct device_node *node)
        return false;
 }
 
-#define CCM_CCDR               0x04
 #define CCM_CCSR               0x0c
 #define CCM_CS2CDR             0x2c
 
-#define CCDR_MMDC_CH1_MASK             BIT(16)
 #define CCSR_PLL3_SW_CLK_SEL           BIT(0)
 
 #define CS2CDR_LDB_DI0_CLK_SEL_SHIFT   9
 #define CS2CDR_LDB_DI1_CLK_SEL_SHIFT   12
 
-static void __init imx6q_mmdc_ch1_mask_handshake(void __iomem *ccm_base)
-{
-       unsigned int reg;
-
-       reg = readl_relaxed(ccm_base + CCM_CCDR);
-       reg |= CCDR_MMDC_CH1_MASK;
-       writel_relaxed(reg, ccm_base + CCM_CCDR);
-}
-
 /*
  * The only way to disable the MMDC_CH1 clock is to move it to pll3_sw_clk
  * via periph2_clk2_sel and then to disable pll3_sw_clk by selecting the
@@ -282,14 +273,8 @@ static void mmdc_ch1_disable(void __iomem *ccm_base)
 {
        unsigned int reg;
 
-       clk_set_parent(clk[IMX6QDL_CLK_PERIPH2_CLK2_SEL],
-                      clk[IMX6QDL_CLK_PLL3_USB_OTG]);
-
-       /*
-        * Handshake with mmdc_ch1 module must be masked when changing
-        * periph2_clk_sel.
-        */
-       clk_set_parent(clk[IMX6QDL_CLK_PERIPH2], clk[IMX6QDL_CLK_PERIPH2_CLK2]);
+       clk_set_parent(hws[IMX6QDL_CLK_PERIPH2_CLK2_SEL]->clk,
+                      hws[IMX6QDL_CLK_PLL3_USB_OTG]->clk);
 
        /* Disable pll3_sw_clk by selecting the bypass clock source */
        reg = readl_relaxed(ccm_base + CCM_CCSR);
@@ -305,8 +290,6 @@ static void mmdc_ch1_reenable(void __iomem *ccm_base)
        reg = readl_relaxed(ccm_base + CCM_CCSR);
        reg &= ~CCSR_PLL3_SW_CLK_SEL;
        writel_relaxed(reg, ccm_base + CCM_CCSR);
-
-       clk_set_parent(clk[IMX6QDL_CLK_PERIPH2], clk[IMX6QDL_CLK_PERIPH2_PRE]);
 }
 
 /*
@@ -365,8 +348,8 @@ static void init_ldb_clks(struct device_node *np, void __iomem *ccm_base)
 
                /* Only switch to or from pll2_pfd2_396m if it is disabled */
                if ((sel[i][0] == 2 || sel[i][3] == 2) &&
-                   (clk_get_parent(clk[IMX6QDL_CLK_PERIPH_PRE]) ==
-                    clk[IMX6QDL_CLK_PLL2_PFD2_396M])) {
+                   (clk_get_parent(hws[IMX6QDL_CLK_PERIPH_PRE]->clk) ==
+                    hws[IMX6QDL_CLK_PLL2_PFD2_396M]->clk)) {
                        pr_err("ccm: ldb_di%d_sel: couldn't disable pll2_pfd2_396m\n",
                               i);
                        sel[i][3] = sel[i][2] = sel[i][1] = sel[i][0];
@@ -418,8 +401,8 @@ static void disable_anatop_clocks(void __iomem *anatop_base)
        /* Make sure PLL2 PFDs 0-2 are gated */
        reg = readl_relaxed(anatop_base + CCM_ANALOG_PFD_528);
        /* Cannot gate PFD2 if pll2_pfd2_396m is the parent of MMDC clock */
-       if (clk_get_parent(clk[IMX6QDL_CLK_PERIPH_PRE]) ==
-           clk[IMX6QDL_CLK_PLL2_PFD2_396M])
+       if (clk_get_parent(hws[IMX6QDL_CLK_PERIPH_PRE]->clk) ==
+           hws[IMX6QDL_CLK_PLL2_PFD2_396M]->clk)
                reg |= PFD0_CLKGATE | PFD1_CLKGATE;
        else
                reg |= PFD0_CLKGATE | PFD1_CLKGATE | PFD2_CLKGATE;
@@ -436,31 +419,45 @@ static void disable_anatop_clocks(void __iomem *anatop_base)
        writel_relaxed(reg, anatop_base + CCM_ANALOG_PLL_VIDEO);
 }
 
+static struct clk_hw * __init imx6q_obtain_fixed_clk_hw(struct device_node *np,
+                                                       const char *name,
+                                                       unsigned long rate)
+{
+       struct clk *clk = of_clk_get_by_name(np, name);
+       struct clk_hw *hw;
+
+       if (IS_ERR(clk))
+               hw = imx_obtain_fixed_clock_hw(name, rate);
+       else
+               hw = __clk_get_hw(clk);
+
+       return hw;
+}
+
 static void __init imx6q_clocks_init(struct device_node *ccm_node)
 {
        struct device_node *np;
        void __iomem *anatop_base, *base;
        int ret;
+       int i;
+
+       clk_hw_data = kzalloc(struct_size(clk_hw_data, hws,
+                                         IMX6QDL_CLK_END), GFP_KERNEL);
+       if (WARN_ON(!clk_hw_data))
+               return;
 
-       clk[IMX6QDL_CLK_DUMMY] = imx_clk_fixed("dummy", 0);
-       clk[IMX6QDL_CLK_CKIL] = of_clk_get_by_name(ccm_node, "ckil");
-       if (IS_ERR(clk[IMX6QDL_CLK_CKIL]))
-               clk[IMX6QDL_CLK_CKIL] = imx_obtain_fixed_clock("ckil", 0);
-       clk[IMX6QDL_CLK_CKIH] = of_clk_get_by_name(ccm_node, "ckih1");
-       if (IS_ERR(clk[IMX6QDL_CLK_CKIH]))
-               clk[IMX6QDL_CLK_CKIH] = imx_obtain_fixed_clock("ckih1", 0);
-       clk[IMX6QDL_CLK_OSC] = of_clk_get_by_name(ccm_node, "osc");
-       if (IS_ERR(clk[IMX6QDL_CLK_OSC]))
-               clk[IMX6QDL_CLK_OSC] = imx_obtain_fixed_clock("osc", 0);
+       clk_hw_data->num = IMX6QDL_CLK_END;
+       hws = clk_hw_data->hws;
 
-       /* Clock source from external clock via CLK1/2 PADs */
-       clk[IMX6QDL_CLK_ANACLK1] = of_clk_get_by_name(ccm_node, "anaclk1");
-       if (IS_ERR(clk[IMX6QDL_CLK_ANACLK1]))
-               clk[IMX6QDL_CLK_ANACLK1] = imx_obtain_fixed_clock("anaclk1", 0);
+       hws[IMX6QDL_CLK_DUMMY] = imx_clk_hw_fixed("dummy", 0);
 
-       clk[IMX6QDL_CLK_ANACLK2] = of_clk_get_by_name(ccm_node, "anaclk2");
-       if (IS_ERR(clk[IMX6QDL_CLK_ANACLK2]))
-               clk[IMX6QDL_CLK_ANACLK2] = imx_obtain_fixed_clock("anaclk2", 0);
+       hws[IMX6QDL_CLK_CKIL] = imx6q_obtain_fixed_clk_hw(ccm_node, "ckil", 0);
+       hws[IMX6QDL_CLK_CKIH] = imx6q_obtain_fixed_clk_hw(ccm_node, "ckih1", 0);
+       hws[IMX6QDL_CLK_OSC] = imx6q_obtain_fixed_clk_hw(ccm_node, "osc", 0);
+
+       /* Clock source from external clock via CLK1/2 PADs */
+       hws[IMX6QDL_CLK_ANACLK1] = imx6q_obtain_fixed_clk_hw(ccm_node, "anaclk1", 0);
+       hws[IMX6QDL_CLK_ANACLK2] = imx6q_obtain_fixed_clk_hw(ccm_node, "anaclk2", 0);
 
        np = of_find_compatible_node(NULL, NULL, "fsl,imx6q-anatop");
        anatop_base = base = of_iomap(np, 0);
@@ -475,47 +472,47 @@ static void __init imx6q_clocks_init(struct device_node *ccm_node)
                video_div_table[3].div = 1;
        }
 
-       clk[IMX6QDL_PLL1_BYPASS_SRC] = imx_clk_mux("pll1_bypass_src", base + 0x00, 14, 2, pll_bypass_src_sels, ARRAY_SIZE(pll_bypass_src_sels));
-       clk[IMX6QDL_PLL2_BYPASS_SRC] = imx_clk_mux("pll2_bypass_src", base + 0x30, 14, 2, pll_bypass_src_sels, ARRAY_SIZE(pll_bypass_src_sels));
-       clk[IMX6QDL_PLL3_BYPASS_SRC] = imx_clk_mux("pll3_bypass_src", base + 0x10, 14, 2, pll_bypass_src_sels, ARRAY_SIZE(pll_bypass_src_sels));
-       clk[IMX6QDL_PLL4_BYPASS_SRC] = imx_clk_mux("pll4_bypass_src", base + 0x70, 14, 2, pll_bypass_src_sels, ARRAY_SIZE(pll_bypass_src_sels));
-       clk[IMX6QDL_PLL5_BYPASS_SRC] = imx_clk_mux("pll5_bypass_src", base + 0xa0, 14, 2, pll_bypass_src_sels, ARRAY_SIZE(pll_bypass_src_sels));
-       clk[IMX6QDL_PLL6_BYPASS_SRC] = imx_clk_mux("pll6_bypass_src", base + 0xe0, 14, 2, pll_bypass_src_sels, ARRAY_SIZE(pll_bypass_src_sels));
-       clk[IMX6QDL_PLL7_BYPASS_SRC] = imx_clk_mux("pll7_bypass_src", base + 0x20, 14, 2, pll_bypass_src_sels, ARRAY_SIZE(pll_bypass_src_sels));
+       hws[IMX6QDL_PLL1_BYPASS_SRC] = imx_clk_hw_mux("pll1_bypass_src", base + 0x00, 14, 2, pll_bypass_src_sels, ARRAY_SIZE(pll_bypass_src_sels));
+       hws[IMX6QDL_PLL2_BYPASS_SRC] = imx_clk_hw_mux("pll2_bypass_src", base + 0x30, 14, 2, pll_bypass_src_sels, ARRAY_SIZE(pll_bypass_src_sels));
+       hws[IMX6QDL_PLL3_BYPASS_SRC] = imx_clk_hw_mux("pll3_bypass_src", base + 0x10, 14, 2, pll_bypass_src_sels, ARRAY_SIZE(pll_bypass_src_sels));
+       hws[IMX6QDL_PLL4_BYPASS_SRC] = imx_clk_hw_mux("pll4_bypass_src", base + 0x70, 14, 2, pll_bypass_src_sels, ARRAY_SIZE(pll_bypass_src_sels));
+       hws[IMX6QDL_PLL5_BYPASS_SRC] = imx_clk_hw_mux("pll5_bypass_src", base + 0xa0, 14, 2, pll_bypass_src_sels, ARRAY_SIZE(pll_bypass_src_sels));
+       hws[IMX6QDL_PLL6_BYPASS_SRC] = imx_clk_hw_mux("pll6_bypass_src", base + 0xe0, 14, 2, pll_bypass_src_sels, ARRAY_SIZE(pll_bypass_src_sels));
+       hws[IMX6QDL_PLL7_BYPASS_SRC] = imx_clk_hw_mux("pll7_bypass_src", base + 0x20, 14, 2, pll_bypass_src_sels, ARRAY_SIZE(pll_bypass_src_sels));
 
        /*                                    type               name    parent_name        base         div_mask */
-       clk[IMX6QDL_CLK_PLL1] = imx_clk_pllv3(IMX_PLLV3_SYS,     "pll1", "osc", base + 0x00, 0x7f);
-       clk[IMX6QDL_CLK_PLL2] = imx_clk_pllv3(IMX_PLLV3_GENERIC, "pll2", "osc", base + 0x30, 0x1);
-       clk[IMX6QDL_CLK_PLL3] = imx_clk_pllv3(IMX_PLLV3_USB,     "pll3", "osc", base + 0x10, 0x3);
-       clk[IMX6QDL_CLK_PLL4] = imx_clk_pllv3(IMX_PLLV3_AV,      "pll4", "osc", base + 0x70, 0x7f);
-       clk[IMX6QDL_CLK_PLL5] = imx_clk_pllv3(IMX_PLLV3_AV,      "pll5", "osc", base + 0xa0, 0x7f);
-       clk[IMX6QDL_CLK_PLL6] = imx_clk_pllv3(IMX_PLLV3_ENET,    "pll6", "osc", base + 0xe0, 0x3);
-       clk[IMX6QDL_CLK_PLL7] = imx_clk_pllv3(IMX_PLLV3_USB,     "pll7", "osc", base + 0x20, 0x3);
-
-       clk[IMX6QDL_PLL1_BYPASS] = imx_clk_mux_flags("pll1_bypass", base + 0x00, 16, 1, pll1_bypass_sels, ARRAY_SIZE(pll1_bypass_sels), CLK_SET_RATE_PARENT);
-       clk[IMX6QDL_PLL2_BYPASS] = imx_clk_mux_flags("pll2_bypass", base + 0x30, 16, 1, pll2_bypass_sels, ARRAY_SIZE(pll2_bypass_sels), CLK_SET_RATE_PARENT);
-       clk[IMX6QDL_PLL3_BYPASS] = imx_clk_mux_flags("pll3_bypass", base + 0x10, 16, 1, pll3_bypass_sels, ARRAY_SIZE(pll3_bypass_sels), CLK_SET_RATE_PARENT);
-       clk[IMX6QDL_PLL4_BYPASS] = imx_clk_mux_flags("pll4_bypass", base + 0x70, 16, 1, pll4_bypass_sels, ARRAY_SIZE(pll4_bypass_sels), CLK_SET_RATE_PARENT);
-       clk[IMX6QDL_PLL5_BYPASS] = imx_clk_mux_flags("pll5_bypass", base + 0xa0, 16, 1, pll5_bypass_sels, ARRAY_SIZE(pll5_bypass_sels), CLK_SET_RATE_PARENT);
-       clk[IMX6QDL_PLL6_BYPASS] = imx_clk_mux_flags("pll6_bypass", base + 0xe0, 16, 1, pll6_bypass_sels, ARRAY_SIZE(pll6_bypass_sels), CLK_SET_RATE_PARENT);
-       clk[IMX6QDL_PLL7_BYPASS] = imx_clk_mux_flags("pll7_bypass", base + 0x20, 16, 1, pll7_bypass_sels, ARRAY_SIZE(pll7_bypass_sels), CLK_SET_RATE_PARENT);
+       hws[IMX6QDL_CLK_PLL1] = imx_clk_hw_pllv3(IMX_PLLV3_SYS,     "pll1", "osc", base + 0x00, 0x7f);
+       hws[IMX6QDL_CLK_PLL2] = imx_clk_hw_pllv3(IMX_PLLV3_GENERIC, "pll2", "osc", base + 0x30, 0x1);
+       hws[IMX6QDL_CLK_PLL3] = imx_clk_hw_pllv3(IMX_PLLV3_USB,     "pll3", "osc", base + 0x10, 0x3);
+       hws[IMX6QDL_CLK_PLL4] = imx_clk_hw_pllv3(IMX_PLLV3_AV,      "pll4", "osc", base + 0x70, 0x7f);
+       hws[IMX6QDL_CLK_PLL5] = imx_clk_hw_pllv3(IMX_PLLV3_AV,      "pll5", "osc", base + 0xa0, 0x7f);
+       hws[IMX6QDL_CLK_PLL6] = imx_clk_hw_pllv3(IMX_PLLV3_ENET,    "pll6", "osc", base + 0xe0, 0x3);
+       hws[IMX6QDL_CLK_PLL7] = imx_clk_hw_pllv3(IMX_PLLV3_USB,     "pll7", "osc", base + 0x20, 0x3);
+
+       hws[IMX6QDL_PLL1_BYPASS] = imx_clk_hw_mux_flags("pll1_bypass", base + 0x00, 16, 1, pll1_bypass_sels, ARRAY_SIZE(pll1_bypass_sels), CLK_SET_RATE_PARENT);
+       hws[IMX6QDL_PLL2_BYPASS] = imx_clk_hw_mux_flags("pll2_bypass", base + 0x30, 16, 1, pll2_bypass_sels, ARRAY_SIZE(pll2_bypass_sels), CLK_SET_RATE_PARENT);
+       hws[IMX6QDL_PLL3_BYPASS] = imx_clk_hw_mux_flags("pll3_bypass", base + 0x10, 16, 1, pll3_bypass_sels, ARRAY_SIZE(pll3_bypass_sels), CLK_SET_RATE_PARENT);
+       hws[IMX6QDL_PLL4_BYPASS] = imx_clk_hw_mux_flags("pll4_bypass", base + 0x70, 16, 1, pll4_bypass_sels, ARRAY_SIZE(pll4_bypass_sels), CLK_SET_RATE_PARENT);
+       hws[IMX6QDL_PLL5_BYPASS] = imx_clk_hw_mux_flags("pll5_bypass", base + 0xa0, 16, 1, pll5_bypass_sels, ARRAY_SIZE(pll5_bypass_sels), CLK_SET_RATE_PARENT);
+       hws[IMX6QDL_PLL6_BYPASS] = imx_clk_hw_mux_flags("pll6_bypass", base + 0xe0, 16, 1, pll6_bypass_sels, ARRAY_SIZE(pll6_bypass_sels), CLK_SET_RATE_PARENT);
+       hws[IMX6QDL_PLL7_BYPASS] = imx_clk_hw_mux_flags("pll7_bypass", base + 0x20, 16, 1, pll7_bypass_sels, ARRAY_SIZE(pll7_bypass_sels), CLK_SET_RATE_PARENT);
 
        /* Do not bypass PLLs initially */
-       clk_set_parent(clk[IMX6QDL_PLL1_BYPASS], clk[IMX6QDL_CLK_PLL1]);
-       clk_set_parent(clk[IMX6QDL_PLL2_BYPASS], clk[IMX6QDL_CLK_PLL2]);
-       clk_set_parent(clk[IMX6QDL_PLL3_BYPASS], clk[IMX6QDL_CLK_PLL3]);
-       clk_set_parent(clk[IMX6QDL_PLL4_BYPASS], clk[IMX6QDL_CLK_PLL4]);
-       clk_set_parent(clk[IMX6QDL_PLL5_BYPASS], clk[IMX6QDL_CLK_PLL5]);
-       clk_set_parent(clk[IMX6QDL_PLL6_BYPASS], clk[IMX6QDL_CLK_PLL6]);
-       clk_set_parent(clk[IMX6QDL_PLL7_BYPASS], clk[IMX6QDL_CLK_PLL7]);
-
-       clk[IMX6QDL_CLK_PLL1_SYS]      = imx_clk_gate("pll1_sys",      "pll1_bypass", base + 0x00, 13);
-       clk[IMX6QDL_CLK_PLL2_BUS]      = imx_clk_gate("pll2_bus",      "pll2_bypass", base + 0x30, 13);
-       clk[IMX6QDL_CLK_PLL3_USB_OTG]  = imx_clk_gate("pll3_usb_otg",  "pll3_bypass", base + 0x10, 13);
-       clk[IMX6QDL_CLK_PLL4_AUDIO]    = imx_clk_gate("pll4_audio",    "pll4_bypass", base + 0x70, 13);
-       clk[IMX6QDL_CLK_PLL5_VIDEO]    = imx_clk_gate("pll5_video",    "pll5_bypass", base + 0xa0, 13);
-       clk[IMX6QDL_CLK_PLL6_ENET]     = imx_clk_gate("pll6_enet",     "pll6_bypass", base + 0xe0, 13);
-       clk[IMX6QDL_CLK_PLL7_USB_HOST] = imx_clk_gate("pll7_usb_host", "pll7_bypass", base + 0x20, 13);
+       clk_set_parent(hws[IMX6QDL_PLL1_BYPASS]->clk, hws[IMX6QDL_CLK_PLL1]->clk);
+       clk_set_parent(hws[IMX6QDL_PLL2_BYPASS]->clk, hws[IMX6QDL_CLK_PLL2]->clk);
+       clk_set_parent(hws[IMX6QDL_PLL3_BYPASS]->clk, hws[IMX6QDL_CLK_PLL3]->clk);
+       clk_set_parent(hws[IMX6QDL_PLL4_BYPASS]->clk, hws[IMX6QDL_CLK_PLL4]->clk);
+       clk_set_parent(hws[IMX6QDL_PLL5_BYPASS]->clk, hws[IMX6QDL_CLK_PLL5]->clk);
+       clk_set_parent(hws[IMX6QDL_PLL6_BYPASS]->clk, hws[IMX6QDL_CLK_PLL6]->clk);
+       clk_set_parent(hws[IMX6QDL_PLL7_BYPASS]->clk, hws[IMX6QDL_CLK_PLL7]->clk);
+
+       hws[IMX6QDL_CLK_PLL1_SYS]      = imx_clk_hw_gate("pll1_sys",      "pll1_bypass", base + 0x00, 13);
+       hws[IMX6QDL_CLK_PLL2_BUS]      = imx_clk_hw_gate("pll2_bus",      "pll2_bypass", base + 0x30, 13);
+       hws[IMX6QDL_CLK_PLL3_USB_OTG]  = imx_clk_hw_gate("pll3_usb_otg",  "pll3_bypass", base + 0x10, 13);
+       hws[IMX6QDL_CLK_PLL4_AUDIO]    = imx_clk_hw_gate("pll4_audio",    "pll4_bypass", base + 0x70, 13);
+       hws[IMX6QDL_CLK_PLL5_VIDEO]    = imx_clk_hw_gate("pll5_video",    "pll5_bypass", base + 0xa0, 13);
+       hws[IMX6QDL_CLK_PLL6_ENET]     = imx_clk_hw_gate("pll6_enet",     "pll6_bypass", base + 0xe0, 13);
+       hws[IMX6QDL_CLK_PLL7_USB_HOST] = imx_clk_hw_gate("pll7_usb_host", "pll7_bypass", base + 0x20, 13);
 
        /*
         * Bit 20 is the reserved and read-only bit, we do this only for:
@@ -523,15 +520,15 @@ static void __init imx6q_clocks_init(struct device_node *ccm_node)
         * - Keep refcount when do usbphy clk_enable/disable, in that case,
         * the clk framework may need to enable/disable usbphy's parent
         */
-       clk[IMX6QDL_CLK_USBPHY1] = imx_clk_gate("usbphy1", "pll3_usb_otg", base + 0x10, 20);
-       clk[IMX6QDL_CLK_USBPHY2] = imx_clk_gate("usbphy2", "pll7_usb_host", base + 0x20, 20);
+       hws[IMX6QDL_CLK_USBPHY1] = imx_clk_hw_gate("usbphy1", "pll3_usb_otg", base + 0x10, 20);
+       hws[IMX6QDL_CLK_USBPHY2] = imx_clk_hw_gate("usbphy2", "pll7_usb_host", base + 0x20, 20);
 
        /*
         * usbphy*_gate needs to be on after system boots up, and software
         * never needs to control it anymore.
         */
-       clk[IMX6QDL_CLK_USBPHY1_GATE] = imx_clk_gate("usbphy1_gate", "dummy", base + 0x10, 6);
-       clk[IMX6QDL_CLK_USBPHY2_GATE] = imx_clk_gate("usbphy2_gate", "dummy", base + 0x20, 6);
+       hws[IMX6QDL_CLK_USBPHY1_GATE] = imx_clk_hw_gate("usbphy1_gate", "dummy", base + 0x10, 6);
+       hws[IMX6QDL_CLK_USBPHY2_GATE] = imx_clk_hw_gate("usbphy2_gate", "dummy", base + 0x20, 6);
 
        /*
         * The ENET PLL is special in that is has multiple outputs with
@@ -545,22 +542,22 @@ static void __init imx6q_clocks_init(struct device_node *ccm_node)
         *
         */
        if (!pll6_bypassed(ccm_node)) {
-               clk[IMX6QDL_CLK_SATA_REF] = imx_clk_fixed_factor("sata_ref", "pll6_enet", 1, 5);
-               clk[IMX6QDL_CLK_PCIE_REF] = imx_clk_fixed_factor("pcie_ref", "pll6_enet", 1, 4);
-               clk[IMX6QDL_CLK_ENET_REF] = clk_register_divider_table(NULL, "enet_ref", "pll6_enet", 0,
+               hws[IMX6QDL_CLK_SATA_REF] = imx_clk_hw_fixed_factor("sata_ref", "pll6_enet", 1, 5);
+               hws[IMX6QDL_CLK_PCIE_REF] = imx_clk_hw_fixed_factor("pcie_ref", "pll6_enet", 1, 4);
+               hws[IMX6QDL_CLK_ENET_REF] = clk_hw_register_divider_table(NULL, "enet_ref", "pll6_enet", 0,
                                                base + 0xe0, 0, 2, 0, clk_enet_ref_table,
                                                &imx_ccm_lock);
        } else {
-               clk[IMX6QDL_CLK_SATA_REF] = imx_clk_fixed_factor("sata_ref", "pll6_enet", 1, 1);
-               clk[IMX6QDL_CLK_PCIE_REF] = imx_clk_fixed_factor("pcie_ref", "pll6_enet", 1, 1);
-               clk[IMX6QDL_CLK_ENET_REF] = imx_clk_fixed_factor("enet_ref", "pll6_enet", 1, 1);
+               hws[IMX6QDL_CLK_SATA_REF] = imx_clk_hw_fixed_factor("sata_ref", "pll6_enet", 1, 1);
+               hws[IMX6QDL_CLK_PCIE_REF] = imx_clk_hw_fixed_factor("pcie_ref", "pll6_enet", 1, 1);
+               hws[IMX6QDL_CLK_ENET_REF] = imx_clk_hw_fixed_factor("enet_ref", "pll6_enet", 1, 1);
        }
 
-       clk[IMX6QDL_CLK_SATA_REF_100M] = imx_clk_gate("sata_ref_100m", "sata_ref", base + 0xe0, 20);
-       clk[IMX6QDL_CLK_PCIE_REF_125M] = imx_clk_gate("pcie_ref_125m", "pcie_ref", base + 0xe0, 19);
+       hws[IMX6QDL_CLK_SATA_REF_100M] = imx_clk_hw_gate("sata_ref_100m", "sata_ref", base + 0xe0, 20);
+       hws[IMX6QDL_CLK_PCIE_REF_125M] = imx_clk_hw_gate("pcie_ref_125m", "pcie_ref", base + 0xe0, 19);
 
-       clk[IMX6QDL_CLK_LVDS1_SEL] = imx_clk_mux("lvds1_sel", base + 0x160, 0, 5, lvds_sels, ARRAY_SIZE(lvds_sels));
-       clk[IMX6QDL_CLK_LVDS2_SEL] = imx_clk_mux("lvds2_sel", base + 0x160, 5, 5, lvds_sels, ARRAY_SIZE(lvds_sels));
+       hws[IMX6QDL_CLK_LVDS1_SEL] = imx_clk_hw_mux("lvds1_sel", base + 0x160, 0, 5, lvds_sels, ARRAY_SIZE(lvds_sels));
+       hws[IMX6QDL_CLK_LVDS2_SEL] = imx_clk_hw_mux("lvds2_sel", base + 0x160, 5, 5, lvds_sels, ARRAY_SIZE(lvds_sels));
 
        /*
         * lvds1_gate and lvds2_gate are pseudo-gates.  Both can be
@@ -572,84 +569,84 @@ static void __init imx6q_clocks_init(struct device_node *ccm_node)
         * it.
         */
        writel(readl(base + 0x160) & ~0x3c00, base + 0x160);
-       clk[IMX6QDL_CLK_LVDS1_GATE] = imx_clk_gate_exclusive("lvds1_gate", "lvds1_sel", base + 0x160, 10, BIT(12));
-       clk[IMX6QDL_CLK_LVDS2_GATE] = imx_clk_gate_exclusive("lvds2_gate", "lvds2_sel", base + 0x160, 11, BIT(13));
+       hws[IMX6QDL_CLK_LVDS1_GATE] = imx_clk_hw_gate_exclusive("lvds1_gate", "lvds1_sel", base + 0x160, 10, BIT(12));
+       hws[IMX6QDL_CLK_LVDS2_GATE] = imx_clk_hw_gate_exclusive("lvds2_gate", "lvds2_sel", base + 0x160, 11, BIT(13));
 
-       clk[IMX6QDL_CLK_LVDS1_IN] = imx_clk_gate_exclusive("lvds1_in", "anaclk1", base + 0x160, 12, BIT(10));
-       clk[IMX6QDL_CLK_LVDS2_IN] = imx_clk_gate_exclusive("lvds2_in", "anaclk2", base + 0x160, 13, BIT(11));
+       hws[IMX6QDL_CLK_LVDS1_IN] = imx_clk_hw_gate_exclusive("lvds1_in", "anaclk1", base + 0x160, 12, BIT(10));
+       hws[IMX6QDL_CLK_LVDS2_IN] = imx_clk_hw_gate_exclusive("lvds2_in", "anaclk2", base + 0x160, 13, BIT(11));
 
        /*                                            name              parent_name        reg       idx */
-       clk[IMX6QDL_CLK_PLL2_PFD0_352M] = imx_clk_pfd("pll2_pfd0_352m", "pll2_bus",     base + 0x100, 0);
-       clk[IMX6QDL_CLK_PLL2_PFD1_594M] = imx_clk_pfd("pll2_pfd1_594m", "pll2_bus",     base + 0x100, 1);
-       clk[IMX6QDL_CLK_PLL2_PFD2_396M] = imx_clk_pfd("pll2_pfd2_396m", "pll2_bus",     base + 0x100, 2);
-       clk[IMX6QDL_CLK_PLL3_PFD0_720M] = imx_clk_pfd("pll3_pfd0_720m", "pll3_usb_otg", base + 0xf0,  0);
-       clk[IMX6QDL_CLK_PLL3_PFD1_540M] = imx_clk_pfd("pll3_pfd1_540m", "pll3_usb_otg", base + 0xf0,  1);
-       clk[IMX6QDL_CLK_PLL3_PFD2_508M] = imx_clk_pfd("pll3_pfd2_508m", "pll3_usb_otg", base + 0xf0,  2);
-       clk[IMX6QDL_CLK_PLL3_PFD3_454M] = imx_clk_pfd("pll3_pfd3_454m", "pll3_usb_otg", base + 0xf0,  3);
+       hws[IMX6QDL_CLK_PLL2_PFD0_352M] = imx_clk_hw_pfd("pll2_pfd0_352m", "pll2_bus",     base + 0x100, 0);
+       hws[IMX6QDL_CLK_PLL2_PFD1_594M] = imx_clk_hw_pfd("pll2_pfd1_594m", "pll2_bus",     base + 0x100, 1);
+       hws[IMX6QDL_CLK_PLL2_PFD2_396M] = imx_clk_hw_pfd("pll2_pfd2_396m", "pll2_bus",     base + 0x100, 2);
+       hws[IMX6QDL_CLK_PLL3_PFD0_720M] = imx_clk_hw_pfd("pll3_pfd0_720m", "pll3_usb_otg", base + 0xf0,  0);
+       hws[IMX6QDL_CLK_PLL3_PFD1_540M] = imx_clk_hw_pfd("pll3_pfd1_540m", "pll3_usb_otg", base + 0xf0,  1);
+       hws[IMX6QDL_CLK_PLL3_PFD2_508M] = imx_clk_hw_pfd("pll3_pfd2_508m", "pll3_usb_otg", base + 0xf0,  2);
+       hws[IMX6QDL_CLK_PLL3_PFD3_454M] = imx_clk_hw_pfd("pll3_pfd3_454m", "pll3_usb_otg", base + 0xf0,  3);
 
        /*                                                name         parent_name     mult div */
-       clk[IMX6QDL_CLK_PLL2_198M] = imx_clk_fixed_factor("pll2_198m", "pll2_pfd2_396m", 1, 2);
-       clk[IMX6QDL_CLK_PLL3_120M] = imx_clk_fixed_factor("pll3_120m", "pll3_usb_otg",   1, 4);
-       clk[IMX6QDL_CLK_PLL3_80M]  = imx_clk_fixed_factor("pll3_80m",  "pll3_usb_otg",   1, 6);
-       clk[IMX6QDL_CLK_PLL3_60M]  = imx_clk_fixed_factor("pll3_60m",  "pll3_usb_otg",   1, 8);
-       clk[IMX6QDL_CLK_TWD]       = imx_clk_fixed_factor("twd",       "arm",            1, 2);
-       clk[IMX6QDL_CLK_GPT_3M]    = imx_clk_fixed_factor("gpt_3m",    "osc",            1, 8);
-       clk[IMX6QDL_CLK_VIDEO_27M] = imx_clk_fixed_factor("video_27m", "pll3_pfd1_540m", 1, 20);
+       hws[IMX6QDL_CLK_PLL2_198M] = imx_clk_hw_fixed_factor("pll2_198m", "pll2_pfd2_396m", 1, 2);
+       hws[IMX6QDL_CLK_PLL3_120M] = imx_clk_hw_fixed_factor("pll3_120m", "pll3_usb_otg",   1, 4);
+       hws[IMX6QDL_CLK_PLL3_80M]  = imx_clk_hw_fixed_factor("pll3_80m",  "pll3_usb_otg",   1, 6);
+       hws[IMX6QDL_CLK_PLL3_60M]  = imx_clk_hw_fixed_factor("pll3_60m",  "pll3_usb_otg",   1, 8);
+       hws[IMX6QDL_CLK_TWD]       = imx_clk_hw_fixed_factor("twd",       "arm",            1, 2);
+       hws[IMX6QDL_CLK_GPT_3M]    = imx_clk_hw_fixed_factor("gpt_3m",    "osc",            1, 8);
+       hws[IMX6QDL_CLK_VIDEO_27M] = imx_clk_hw_fixed_factor("video_27m", "pll3_pfd1_540m", 1, 20);
        if (clk_on_imx6dl() || clk_on_imx6qp()) {
-               clk[IMX6QDL_CLK_GPU2D_AXI] = imx_clk_fixed_factor("gpu2d_axi", "mmdc_ch0_axi_podf", 1, 1);
-               clk[IMX6QDL_CLK_GPU3D_AXI] = imx_clk_fixed_factor("gpu3d_axi", "mmdc_ch0_axi_podf", 1, 1);
+               hws[IMX6QDL_CLK_GPU2D_AXI] = imx_clk_hw_fixed_factor("gpu2d_axi", "mmdc_ch0_axi_podf", 1, 1);
+               hws[IMX6QDL_CLK_GPU3D_AXI] = imx_clk_hw_fixed_factor("gpu3d_axi", "mmdc_ch0_axi_podf", 1, 1);
        }
 
-       clk[IMX6QDL_CLK_PLL4_POST_DIV] = clk_register_divider_table(NULL, "pll4_post_div", "pll4_audio", CLK_SET_RATE_PARENT, base + 0x70, 19, 2, 0, post_div_table, &imx_ccm_lock);
-       clk[IMX6QDL_CLK_PLL4_AUDIO_DIV] = clk_register_divider(NULL, "pll4_audio_div", "pll4_post_div", CLK_SET_RATE_PARENT, base + 0x170, 15, 1, 0, &imx_ccm_lock);
-       clk[IMX6QDL_CLK_PLL5_POST_DIV] = clk_register_divider_table(NULL, "pll5_post_div", "pll5_video", CLK_SET_RATE_PARENT, base + 0xa0, 19, 2, 0, post_div_table, &imx_ccm_lock);
-       clk[IMX6QDL_CLK_PLL5_VIDEO_DIV] = clk_register_divider_table(NULL, "pll5_video_div", "pll5_post_div", CLK_SET_RATE_PARENT, base + 0x170, 30, 2, 0, video_div_table, &imx_ccm_lock);
+       hws[IMX6QDL_CLK_PLL4_POST_DIV] = clk_hw_register_divider_table(NULL, "pll4_post_div", "pll4_audio", CLK_SET_RATE_PARENT, base + 0x70, 19, 2, 0, post_div_table, &imx_ccm_lock);
+       hws[IMX6QDL_CLK_PLL4_AUDIO_DIV] = clk_hw_register_divider(NULL, "pll4_audio_div", "pll4_post_div", CLK_SET_RATE_PARENT, base + 0x170, 15, 1, 0, &imx_ccm_lock);
+       hws[IMX6QDL_CLK_PLL5_POST_DIV] = clk_hw_register_divider_table(NULL, "pll5_post_div", "pll5_video", CLK_SET_RATE_PARENT, base + 0xa0, 19, 2, 0, post_div_table, &imx_ccm_lock);
+       hws[IMX6QDL_CLK_PLL5_VIDEO_DIV] = clk_hw_register_divider_table(NULL, "pll5_video_div", "pll5_post_div", CLK_SET_RATE_PARENT, base + 0x170, 30, 2, 0, video_div_table, &imx_ccm_lock);
 
        np = ccm_node;
        base = of_iomap(np, 0);
        WARN_ON(!base);
 
        /*                                              name                reg       shift width parent_names     num_parents */
-       clk[IMX6QDL_CLK_STEP]             = imx_clk_mux("step",             base + 0xc,  8,  1, step_sels,         ARRAY_SIZE(step_sels));
-       clk[IMX6QDL_CLK_PLL1_SW]          = imx_clk_mux("pll1_sw",          base + 0xc,  2,  1, pll1_sw_sels,      ARRAY_SIZE(pll1_sw_sels));
-       clk[IMX6QDL_CLK_PERIPH_PRE]       = imx_clk_mux("periph_pre",       base + 0x18, 18, 2, periph_pre_sels,   ARRAY_SIZE(periph_pre_sels));
-       clk[IMX6QDL_CLK_PERIPH2_PRE]      = imx_clk_mux("periph2_pre",      base + 0x18, 21, 2, periph_pre_sels,   ARRAY_SIZE(periph_pre_sels));
-       clk[IMX6QDL_CLK_PERIPH_CLK2_SEL]  = imx_clk_mux("periph_clk2_sel",  base + 0x18, 12, 2, periph_clk2_sels,  ARRAY_SIZE(periph_clk2_sels));
-       clk[IMX6QDL_CLK_PERIPH2_CLK2_SEL] = imx_clk_mux("periph2_clk2_sel", base + 0x18, 20, 1, periph2_clk2_sels, ARRAY_SIZE(periph2_clk2_sels));
-       clk[IMX6QDL_CLK_AXI_SEL]          = imx_clk_mux("axi_sel",          base + 0x14, 6,  2, axi_sels,          ARRAY_SIZE(axi_sels));
-       clk[IMX6QDL_CLK_ESAI_SEL]         = imx_clk_mux("esai_sel",         base + 0x20, 19, 2, audio_sels,        ARRAY_SIZE(audio_sels));
-       clk[IMX6QDL_CLK_ASRC_SEL]         = imx_clk_mux("asrc_sel",         base + 0x30, 7,  2, audio_sels,        ARRAY_SIZE(audio_sels));
-       clk[IMX6QDL_CLK_SPDIF_SEL]        = imx_clk_mux("spdif_sel",        base + 0x30, 20, 2, audio_sels,        ARRAY_SIZE(audio_sels));
+       hws[IMX6QDL_CLK_STEP]             = imx_clk_hw_mux("step",                  base + 0xc,  8,  1, step_sels,         ARRAY_SIZE(step_sels));
+       hws[IMX6QDL_CLK_PLL1_SW]          = imx_clk_hw_mux("pll1_sw",       base + 0xc,  2,  1, pll1_sw_sels,      ARRAY_SIZE(pll1_sw_sels));
+       hws[IMX6QDL_CLK_PERIPH_PRE]       = imx_clk_hw_mux("periph_pre",       base + 0x18, 18, 2, periph_pre_sels,   ARRAY_SIZE(periph_pre_sels));
+       hws[IMX6QDL_CLK_PERIPH2_PRE]      = imx_clk_hw_mux("periph2_pre",      base + 0x18, 21, 2, periph_pre_sels,   ARRAY_SIZE(periph_pre_sels));
+       hws[IMX6QDL_CLK_PERIPH_CLK2_SEL]  = imx_clk_hw_mux("periph_clk2_sel",  base + 0x18, 12, 2, periph_clk2_sels,  ARRAY_SIZE(periph_clk2_sels));
+       hws[IMX6QDL_CLK_PERIPH2_CLK2_SEL] = imx_clk_hw_mux("periph2_clk2_sel", base + 0x18, 20, 1, periph2_clk2_sels, ARRAY_SIZE(periph2_clk2_sels));
+       hws[IMX6QDL_CLK_AXI_SEL]          = imx_clk_hw_mux("axi_sel",          base + 0x14, 6,  2, axi_sels,          ARRAY_SIZE(axi_sels));
+       hws[IMX6QDL_CLK_ESAI_SEL]         = imx_clk_hw_mux("esai_sel",         base + 0x20, 19, 2, audio_sels,        ARRAY_SIZE(audio_sels));
+       hws[IMX6QDL_CLK_ASRC_SEL]         = imx_clk_hw_mux("asrc_sel",         base + 0x30, 7,  2, audio_sels,        ARRAY_SIZE(audio_sels));
+       hws[IMX6QDL_CLK_SPDIF_SEL]        = imx_clk_hw_mux("spdif_sel",        base + 0x30, 20, 2, audio_sels,        ARRAY_SIZE(audio_sels));
        if (clk_on_imx6q()) {
-               clk[IMX6QDL_CLK_GPU2D_AXI]        = imx_clk_mux("gpu2d_axi",        base + 0x18, 0,  1, gpu_axi_sels,      ARRAY_SIZE(gpu_axi_sels));
-               clk[IMX6QDL_CLK_GPU3D_AXI]        = imx_clk_mux("gpu3d_axi",        base + 0x18, 1,  1, gpu_axi_sels,      ARRAY_SIZE(gpu_axi_sels));
+               hws[IMX6QDL_CLK_GPU2D_AXI]        = imx_clk_hw_mux("gpu2d_axi",        base + 0x18, 0,  1, gpu_axi_sels,      ARRAY_SIZE(gpu_axi_sels));
+               hws[IMX6QDL_CLK_GPU3D_AXI]        = imx_clk_hw_mux("gpu3d_axi",        base + 0x18, 1,  1, gpu_axi_sels,      ARRAY_SIZE(gpu_axi_sels));
        }
        if (clk_on_imx6qp()) {
-               clk[IMX6QDL_CLK_CAN_SEL]   = imx_clk_mux("can_sel",     base + 0x20, 8,  2, can_sels, ARRAY_SIZE(can_sels));
-               clk[IMX6QDL_CLK_ECSPI_SEL] = imx_clk_mux("ecspi_sel",   base + 0x38, 18, 1, ecspi_sels,  ARRAY_SIZE(ecspi_sels));
-               clk[IMX6QDL_CLK_IPG_PER_SEL] = imx_clk_mux("ipg_per_sel", base + 0x1c, 6, 1, ipg_per_sels, ARRAY_SIZE(ipg_per_sels));
-               clk[IMX6QDL_CLK_UART_SEL] = imx_clk_mux("uart_sel", base + 0x24, 6, 1, uart_sels, ARRAY_SIZE(uart_sels));
-               clk[IMX6QDL_CLK_GPU2D_CORE_SEL] = imx_clk_mux("gpu2d_core_sel", base + 0x18, 16, 2, gpu2d_core_sels_2, ARRAY_SIZE(gpu2d_core_sels_2));
+               hws[IMX6QDL_CLK_CAN_SEL]   = imx_clk_hw_mux("can_sel",  base + 0x20, 8,  2, can_sels, ARRAY_SIZE(can_sels));
+               hws[IMX6QDL_CLK_ECSPI_SEL] = imx_clk_hw_mux("ecspi_sel",        base + 0x38, 18, 1, ecspi_sels,  ARRAY_SIZE(ecspi_sels));
+               hws[IMX6QDL_CLK_IPG_PER_SEL] = imx_clk_hw_mux("ipg_per_sel", base + 0x1c, 6, 1, ipg_per_sels, ARRAY_SIZE(ipg_per_sels));
+               hws[IMX6QDL_CLK_UART_SEL] = imx_clk_hw_mux("uart_sel", base + 0x24, 6, 1, uart_sels, ARRAY_SIZE(uart_sels));
+               hws[IMX6QDL_CLK_GPU2D_CORE_SEL] = imx_clk_hw_mux("gpu2d_core_sel", base + 0x18, 16, 2, gpu2d_core_sels_2, ARRAY_SIZE(gpu2d_core_sels_2));
        } else if (clk_on_imx6dl()) {
-               clk[IMX6QDL_CLK_MLB_SEL] = imx_clk_mux("mlb_sel",   base + 0x18, 16, 2, gpu2d_core_sels,   ARRAY_SIZE(gpu2d_core_sels));
+               hws[IMX6QDL_CLK_MLB_SEL] = imx_clk_hw_mux("mlb_sel",   base + 0x18, 16, 2, gpu2d_core_sels,   ARRAY_SIZE(gpu2d_core_sels));
        } else {
-               clk[IMX6QDL_CLK_GPU2D_CORE_SEL] = imx_clk_mux("gpu2d_core_sel",   base + 0x18, 16, 2, gpu2d_core_sels,   ARRAY_SIZE(gpu2d_core_sels));
+               hws[IMX6QDL_CLK_GPU2D_CORE_SEL] = imx_clk_hw_mux("gpu2d_core_sel",   base + 0x18, 16, 2, gpu2d_core_sels,   ARRAY_SIZE(gpu2d_core_sels));
        }
-       clk[IMX6QDL_CLK_GPU3D_CORE_SEL]   = imx_clk_mux("gpu3d_core_sel",   base + 0x18, 4,  2, gpu3d_core_sels,   ARRAY_SIZE(gpu3d_core_sels));
+       hws[IMX6QDL_CLK_GPU3D_CORE_SEL]   = imx_clk_hw_mux("gpu3d_core_sel",   base + 0x18, 4,  2, gpu3d_core_sels,   ARRAY_SIZE(gpu3d_core_sels));
        if (clk_on_imx6dl())
-               clk[IMX6QDL_CLK_GPU2D_CORE_SEL] = imx_clk_mux("gpu2d_core_sel", base + 0x18, 8,  2, gpu3d_shader_sels, ARRAY_SIZE(gpu3d_shader_sels));
+               hws[IMX6QDL_CLK_GPU2D_CORE_SEL] = imx_clk_hw_mux("gpu2d_core_sel", base + 0x18, 8,  2, gpu3d_shader_sels, ARRAY_SIZE(gpu3d_shader_sels));
        else
-               clk[IMX6QDL_CLK_GPU3D_SHADER_SEL] = imx_clk_mux("gpu3d_shader_sel", base + 0x18, 8,  2, gpu3d_shader_sels, ARRAY_SIZE(gpu3d_shader_sels));
-       clk[IMX6QDL_CLK_IPU1_SEL]         = imx_clk_mux("ipu1_sel",         base + 0x3c, 9,  2, ipu_sels,          ARRAY_SIZE(ipu_sels));
-       clk[IMX6QDL_CLK_IPU2_SEL]         = imx_clk_mux("ipu2_sel",         base + 0x3c, 14, 2, ipu_sels,          ARRAY_SIZE(ipu_sels));
+               hws[IMX6QDL_CLK_GPU3D_SHADER_SEL] = imx_clk_hw_mux("gpu3d_shader_sel", base + 0x18, 8,  2, gpu3d_shader_sels, ARRAY_SIZE(gpu3d_shader_sels));
+       hws[IMX6QDL_CLK_IPU1_SEL]         = imx_clk_hw_mux("ipu1_sel",         base + 0x3c, 9,  2, ipu_sels,          ARRAY_SIZE(ipu_sels));
+       hws[IMX6QDL_CLK_IPU2_SEL]         = imx_clk_hw_mux("ipu2_sel",         base + 0x3c, 14, 2, ipu_sels,          ARRAY_SIZE(ipu_sels));
 
        disable_anatop_clocks(anatop_base);
 
-       imx6q_mmdc_ch1_mask_handshake(base);
+       imx_mmdc_mask_handshake(base, 1);
 
        if (clk_on_imx6qp()) {
-               clk[IMX6QDL_CLK_LDB_DI0_SEL]      = imx_clk_mux_flags("ldb_di0_sel", base + 0x2c, 9,  3, ldb_di_sels,      ARRAY_SIZE(ldb_di_sels), CLK_SET_RATE_PARENT);
-               clk[IMX6QDL_CLK_LDB_DI1_SEL]      = imx_clk_mux_flags("ldb_di1_sel", base + 0x2c, 12, 3, ldb_di_sels,      ARRAY_SIZE(ldb_di_sels), CLK_SET_RATE_PARENT);
+               hws[IMX6QDL_CLK_LDB_DI0_SEL]      = imx_clk_hw_mux_flags("ldb_di0_sel", base + 0x2c, 9,  3, ldb_di_sels,      ARRAY_SIZE(ldb_di_sels), CLK_SET_RATE_PARENT);
+               hws[IMX6QDL_CLK_LDB_DI1_SEL]      = imx_clk_hw_mux_flags("ldb_di1_sel", base + 0x2c, 12, 3, ldb_di_sels,      ARRAY_SIZE(ldb_di_sels), CLK_SET_RATE_PARENT);
        } else {
                /*
                 * The LDB_DI0/1_SEL muxes are registered read-only due to a hardware
@@ -658,322 +655,333 @@ static void __init imx6q_clocks_init(struct device_node *ccm_node)
                 */
                init_ldb_clks(np, base);
 
-               clk[IMX6QDL_CLK_LDB_DI0_SEL]      = imx_clk_mux_ldb("ldb_di0_sel", base + 0x2c, 9,  3, ldb_di_sels,      ARRAY_SIZE(ldb_di_sels));
-               clk[IMX6QDL_CLK_LDB_DI1_SEL]      = imx_clk_mux_ldb("ldb_di1_sel", base + 0x2c, 12, 3, ldb_di_sels,      ARRAY_SIZE(ldb_di_sels));
+               hws[IMX6QDL_CLK_LDB_DI0_SEL]      = imx_clk_hw_mux_ldb("ldb_di0_sel", base + 0x2c, 9,  3, ldb_di_sels,      ARRAY_SIZE(ldb_di_sels));
+               hws[IMX6QDL_CLK_LDB_DI1_SEL]      = imx_clk_hw_mux_ldb("ldb_di1_sel", base + 0x2c, 12, 3, ldb_di_sels,      ARRAY_SIZE(ldb_di_sels));
        }
-       clk[IMX6QDL_CLK_IPU1_DI0_PRE_SEL] = imx_clk_mux_flags("ipu1_di0_pre_sel", base + 0x34, 6,  3, ipu_di_pre_sels,   ARRAY_SIZE(ipu_di_pre_sels), CLK_SET_RATE_PARENT);
-       clk[IMX6QDL_CLK_IPU1_DI1_PRE_SEL] = imx_clk_mux_flags("ipu1_di1_pre_sel", base + 0x34, 15, 3, ipu_di_pre_sels,   ARRAY_SIZE(ipu_di_pre_sels), CLK_SET_RATE_PARENT);
-       clk[IMX6QDL_CLK_IPU2_DI0_PRE_SEL] = imx_clk_mux_flags("ipu2_di0_pre_sel", base + 0x38, 6,  3, ipu_di_pre_sels,   ARRAY_SIZE(ipu_di_pre_sels), CLK_SET_RATE_PARENT);
-       clk[IMX6QDL_CLK_IPU2_DI1_PRE_SEL] = imx_clk_mux_flags("ipu2_di1_pre_sel", base + 0x38, 15, 3, ipu_di_pre_sels,   ARRAY_SIZE(ipu_di_pre_sels), CLK_SET_RATE_PARENT);
-       clk[IMX6QDL_CLK_HSI_TX_SEL]       = imx_clk_mux("hsi_tx_sel",       base + 0x30, 28, 1, hsi_tx_sels,       ARRAY_SIZE(hsi_tx_sels));
-       clk[IMX6QDL_CLK_PCIE_AXI_SEL]     = imx_clk_mux("pcie_axi_sel",     base + 0x18, 10, 1, pcie_axi_sels,     ARRAY_SIZE(pcie_axi_sels));
+
+       hws[IMX6QDL_CLK_IPU1_DI0_PRE_SEL] = imx_clk_hw_mux_flags("ipu1_di0_pre_sel", base + 0x34, 6,  3, ipu_di_pre_sels,   ARRAY_SIZE(ipu_di_pre_sels), CLK_SET_RATE_PARENT);
+       hws[IMX6QDL_CLK_IPU1_DI1_PRE_SEL] = imx_clk_hw_mux_flags("ipu1_di1_pre_sel", base + 0x34, 15, 3, ipu_di_pre_sels,   ARRAY_SIZE(ipu_di_pre_sels), CLK_SET_RATE_PARENT);
+       hws[IMX6QDL_CLK_IPU2_DI0_PRE_SEL] = imx_clk_hw_mux_flags("ipu2_di0_pre_sel", base + 0x38, 6,  3, ipu_di_pre_sels,   ARRAY_SIZE(ipu_di_pre_sels), CLK_SET_RATE_PARENT);
+       hws[IMX6QDL_CLK_IPU2_DI1_PRE_SEL] = imx_clk_hw_mux_flags("ipu2_di1_pre_sel", base + 0x38, 15, 3, ipu_di_pre_sels,   ARRAY_SIZE(ipu_di_pre_sels), CLK_SET_RATE_PARENT);
+       hws[IMX6QDL_CLK_HSI_TX_SEL]       = imx_clk_hw_mux("hsi_tx_sel",       base + 0x30, 28, 1, hsi_tx_sels,       ARRAY_SIZE(hsi_tx_sels));
+       hws[IMX6QDL_CLK_PCIE_AXI_SEL]     = imx_clk_hw_mux("pcie_axi_sel",     base + 0x18, 10, 1, pcie_axi_sels,     ARRAY_SIZE(pcie_axi_sels));
+
        if (clk_on_imx6qp()) {
-               clk[IMX6QDL_CLK_IPU1_DI0_SEL]     = imx_clk_mux_flags("ipu1_di0_sel",     base + 0x34, 0,  3, ipu1_di0_sels_2,     ARRAY_SIZE(ipu1_di0_sels_2), CLK_SET_RATE_PARENT);
-               clk[IMX6QDL_CLK_IPU1_DI1_SEL]     = imx_clk_mux_flags("ipu1_di1_sel",     base + 0x34, 9,  3, ipu1_di1_sels_2,     ARRAY_SIZE(ipu1_di1_sels_2), CLK_SET_RATE_PARENT);
-               clk[IMX6QDL_CLK_IPU2_DI0_SEL]     = imx_clk_mux_flags("ipu2_di0_sel",     base + 0x38, 0,  3, ipu2_di0_sels_2,     ARRAY_SIZE(ipu2_di0_sels_2), CLK_SET_RATE_PARENT);
-               clk[IMX6QDL_CLK_IPU2_DI1_SEL]     = imx_clk_mux_flags("ipu2_di1_sel",     base + 0x38, 9,  3, ipu2_di1_sels_2,     ARRAY_SIZE(ipu2_di1_sels_2), CLK_SET_RATE_PARENT);
-               clk[IMX6QDL_CLK_SSI1_SEL]         = imx_clk_mux("ssi1_sel",   base + 0x1c, 10, 2, ssi_sels,          ARRAY_SIZE(ssi_sels));
-               clk[IMX6QDL_CLK_SSI2_SEL]         = imx_clk_mux("ssi2_sel",   base + 0x1c, 12, 2, ssi_sels,          ARRAY_SIZE(ssi_sels));
-               clk[IMX6QDL_CLK_SSI3_SEL]         = imx_clk_mux("ssi3_sel",   base + 0x1c, 14, 2, ssi_sels,          ARRAY_SIZE(ssi_sels));
-               clk[IMX6QDL_CLK_USDHC1_SEL]       = imx_clk_mux("usdhc1_sel", base + 0x1c, 16, 1, usdhc_sels,        ARRAY_SIZE(usdhc_sels));
-               clk[IMX6QDL_CLK_USDHC2_SEL]       = imx_clk_mux("usdhc2_sel", base + 0x1c, 17, 1, usdhc_sels,        ARRAY_SIZE(usdhc_sels));
-               clk[IMX6QDL_CLK_USDHC3_SEL]       = imx_clk_mux("usdhc3_sel", base + 0x1c, 18, 1, usdhc_sels,        ARRAY_SIZE(usdhc_sels));
-               clk[IMX6QDL_CLK_USDHC4_SEL]       = imx_clk_mux("usdhc4_sel", base + 0x1c, 19, 1, usdhc_sels,        ARRAY_SIZE(usdhc_sels));
-               clk[IMX6QDL_CLK_ENFC_SEL]         = imx_clk_mux("enfc_sel",         base + 0x2c, 15, 3, enfc_sels_2,         ARRAY_SIZE(enfc_sels_2));
-               clk[IMX6QDL_CLK_EIM_SEL]          = imx_clk_mux("eim_sel",      base + 0x1c, 27, 2, eim_sels,        ARRAY_SIZE(eim_sels));
-               clk[IMX6QDL_CLK_EIM_SLOW_SEL]     = imx_clk_mux("eim_slow_sel", base + 0x1c, 29, 2, eim_slow_sels,   ARRAY_SIZE(eim_slow_sels));
-               clk[IMX6QDL_CLK_PRE_AXI]          = imx_clk_mux("pre_axi",      base + 0x18, 1,  1, pre_axi_sels,    ARRAY_SIZE(pre_axi_sels));
+               hws[IMX6QDL_CLK_IPU1_DI0_SEL]     = imx_clk_hw_mux_flags("ipu1_di0_sel",     base + 0x34, 0,  3, ipu1_di0_sels_2,     ARRAY_SIZE(ipu1_di0_sels_2), CLK_SET_RATE_PARENT);
+               hws[IMX6QDL_CLK_IPU1_DI1_SEL]     = imx_clk_hw_mux_flags("ipu1_di1_sel",     base + 0x34, 9,  3, ipu1_di1_sels_2,     ARRAY_SIZE(ipu1_di1_sels_2), CLK_SET_RATE_PARENT);
+               hws[IMX6QDL_CLK_IPU2_DI0_SEL]     = imx_clk_hw_mux_flags("ipu2_di0_sel",     base + 0x38, 0,  3, ipu2_di0_sels_2,     ARRAY_SIZE(ipu2_di0_sels_2), CLK_SET_RATE_PARENT);
+               hws[IMX6QDL_CLK_IPU2_DI1_SEL]     = imx_clk_hw_mux_flags("ipu2_di1_sel",     base + 0x38, 9,  3, ipu2_di1_sels_2,     ARRAY_SIZE(ipu2_di1_sels_2), CLK_SET_RATE_PARENT);
+               hws[IMX6QDL_CLK_SSI1_SEL]         = imx_clk_hw_mux("ssi1_sel",   base + 0x1c, 10, 2, ssi_sels,          ARRAY_SIZE(ssi_sels));
+               hws[IMX6QDL_CLK_SSI2_SEL]         = imx_clk_hw_mux("ssi2_sel",   base + 0x1c, 12, 2, ssi_sels,          ARRAY_SIZE(ssi_sels));
+               hws[IMX6QDL_CLK_SSI3_SEL]         = imx_clk_hw_mux("ssi3_sel",   base + 0x1c, 14, 2, ssi_sels,          ARRAY_SIZE(ssi_sels));
+               hws[IMX6QDL_CLK_USDHC1_SEL]       = imx_clk_hw_mux("usdhc1_sel", base + 0x1c, 16, 1, usdhc_sels,        ARRAY_SIZE(usdhc_sels));
+               hws[IMX6QDL_CLK_USDHC2_SEL]       = imx_clk_hw_mux("usdhc2_sel", base + 0x1c, 17, 1, usdhc_sels,        ARRAY_SIZE(usdhc_sels));
+               hws[IMX6QDL_CLK_USDHC3_SEL]       = imx_clk_hw_mux("usdhc3_sel", base + 0x1c, 18, 1, usdhc_sels,        ARRAY_SIZE(usdhc_sels));
+               hws[IMX6QDL_CLK_USDHC4_SEL]       = imx_clk_hw_mux("usdhc4_sel", base + 0x1c, 19, 1, usdhc_sels,        ARRAY_SIZE(usdhc_sels));
+               hws[IMX6QDL_CLK_ENFC_SEL]         = imx_clk_hw_mux("enfc_sel",         base + 0x2c, 15, 3, enfc_sels_2,         ARRAY_SIZE(enfc_sels_2));
+               hws[IMX6QDL_CLK_EIM_SEL]          = imx_clk_hw_mux("eim_sel",      base + 0x1c, 27, 2, eim_sels,        ARRAY_SIZE(eim_sels));
+               hws[IMX6QDL_CLK_EIM_SLOW_SEL]     = imx_clk_hw_mux("eim_slow_sel", base + 0x1c, 29, 2, eim_slow_sels,   ARRAY_SIZE(eim_slow_sels));
+               hws[IMX6QDL_CLK_PRE_AXI]          = imx_clk_hw_mux("pre_axi",   base + 0x18, 1,  1, pre_axi_sels,    ARRAY_SIZE(pre_axi_sels));
        } else {
-               clk[IMX6QDL_CLK_IPU1_DI0_SEL]     = imx_clk_mux_flags("ipu1_di0_sel",     base + 0x34, 0,  3, ipu1_di0_sels,     ARRAY_SIZE(ipu1_di0_sels), CLK_SET_RATE_PARENT);
-               clk[IMX6QDL_CLK_IPU1_DI1_SEL]     = imx_clk_mux_flags("ipu1_di1_sel",     base + 0x34, 9,  3, ipu1_di1_sels,     ARRAY_SIZE(ipu1_di1_sels), CLK_SET_RATE_PARENT);
-               clk[IMX6QDL_CLK_IPU2_DI0_SEL]     = imx_clk_mux_flags("ipu2_di0_sel",     base + 0x38, 0,  3, ipu2_di0_sels,     ARRAY_SIZE(ipu2_di0_sels), CLK_SET_RATE_PARENT);
-               clk[IMX6QDL_CLK_IPU2_DI1_SEL]     = imx_clk_mux_flags("ipu2_di1_sel",     base + 0x38, 9,  3, ipu2_di1_sels,     ARRAY_SIZE(ipu2_di1_sels), CLK_SET_RATE_PARENT);
-               clk[IMX6QDL_CLK_SSI1_SEL]         = imx_clk_fixup_mux("ssi1_sel",   base + 0x1c, 10, 2, ssi_sels,          ARRAY_SIZE(ssi_sels), imx_cscmr1_fixup);
-               clk[IMX6QDL_CLK_SSI2_SEL]         = imx_clk_fixup_mux("ssi2_sel",   base + 0x1c, 12, 2, ssi_sels,          ARRAY_SIZE(ssi_sels), imx_cscmr1_fixup);
-               clk[IMX6QDL_CLK_SSI3_SEL]         = imx_clk_fixup_mux("ssi3_sel",   base + 0x1c, 14, 2, ssi_sels,          ARRAY_SIZE(ssi_sels), imx_cscmr1_fixup);
-               clk[IMX6QDL_CLK_USDHC1_SEL]       = imx_clk_fixup_mux("usdhc1_sel", base + 0x1c, 16, 1, usdhc_sels,        ARRAY_SIZE(usdhc_sels), imx_cscmr1_fixup);
-               clk[IMX6QDL_CLK_USDHC2_SEL]       = imx_clk_fixup_mux("usdhc2_sel", base + 0x1c, 17, 1, usdhc_sels,        ARRAY_SIZE(usdhc_sels), imx_cscmr1_fixup);
-               clk[IMX6QDL_CLK_USDHC3_SEL]       = imx_clk_fixup_mux("usdhc3_sel", base + 0x1c, 18, 1, usdhc_sels,        ARRAY_SIZE(usdhc_sels), imx_cscmr1_fixup);
-               clk[IMX6QDL_CLK_USDHC4_SEL]       = imx_clk_fixup_mux("usdhc4_sel", base + 0x1c, 19, 1, usdhc_sels,        ARRAY_SIZE(usdhc_sels), imx_cscmr1_fixup);
-               clk[IMX6QDL_CLK_ENFC_SEL]         = imx_clk_mux("enfc_sel",         base + 0x2c, 16, 2, enfc_sels,         ARRAY_SIZE(enfc_sels));
-               clk[IMX6QDL_CLK_EIM_SEL]          = imx_clk_fixup_mux("eim_sel",      base + 0x1c, 27, 2, eim_sels,        ARRAY_SIZE(eim_sels), imx_cscmr1_fixup);
-               clk[IMX6QDL_CLK_EIM_SLOW_SEL]     = imx_clk_fixup_mux("eim_slow_sel", base + 0x1c, 29, 2, eim_slow_sels,   ARRAY_SIZE(eim_slow_sels), imx_cscmr1_fixup);
+               hws[IMX6QDL_CLK_IPU1_DI0_SEL]     = imx_clk_hw_mux_flags("ipu1_di0_sel",     base + 0x34, 0,  3, ipu1_di0_sels,     ARRAY_SIZE(ipu1_di0_sels), CLK_SET_RATE_PARENT);
+               hws[IMX6QDL_CLK_IPU1_DI1_SEL]     = imx_clk_hw_mux_flags("ipu1_di1_sel",     base + 0x34, 9,  3, ipu1_di1_sels,     ARRAY_SIZE(ipu1_di1_sels), CLK_SET_RATE_PARENT);
+               hws[IMX6QDL_CLK_IPU2_DI0_SEL]     = imx_clk_hw_mux_flags("ipu2_di0_sel",     base + 0x38, 0,  3, ipu2_di0_sels,     ARRAY_SIZE(ipu2_di0_sels), CLK_SET_RATE_PARENT);
+               hws[IMX6QDL_CLK_IPU2_DI1_SEL]     = imx_clk_hw_mux_flags("ipu2_di1_sel",     base + 0x38, 9,  3, ipu2_di1_sels,     ARRAY_SIZE(ipu2_di1_sels), CLK_SET_RATE_PARENT);
+               hws[IMX6QDL_CLK_SSI1_SEL]         = imx_clk_hw_fixup_mux("ssi1_sel",   base + 0x1c, 10, 2, ssi_sels,          ARRAY_SIZE(ssi_sels), imx_cscmr1_fixup);
+               hws[IMX6QDL_CLK_SSI2_SEL]         = imx_clk_hw_fixup_mux("ssi2_sel",   base + 0x1c, 12, 2, ssi_sels,          ARRAY_SIZE(ssi_sels), imx_cscmr1_fixup);
+               hws[IMX6QDL_CLK_SSI3_SEL]         = imx_clk_hw_fixup_mux("ssi3_sel",   base + 0x1c, 14, 2, ssi_sels,          ARRAY_SIZE(ssi_sels), imx_cscmr1_fixup);
+               hws[IMX6QDL_CLK_USDHC1_SEL]       = imx_clk_hw_fixup_mux("usdhc1_sel", base + 0x1c, 16, 1, usdhc_sels,        ARRAY_SIZE(usdhc_sels), imx_cscmr1_fixup);
+               hws[IMX6QDL_CLK_USDHC2_SEL]       = imx_clk_hw_fixup_mux("usdhc2_sel", base + 0x1c, 17, 1, usdhc_sels,        ARRAY_SIZE(usdhc_sels), imx_cscmr1_fixup);
+               hws[IMX6QDL_CLK_USDHC3_SEL]       = imx_clk_hw_fixup_mux("usdhc3_sel", base + 0x1c, 18, 1, usdhc_sels,        ARRAY_SIZE(usdhc_sels), imx_cscmr1_fixup);
+               hws[IMX6QDL_CLK_USDHC4_SEL]       = imx_clk_hw_fixup_mux("usdhc4_sel", base + 0x1c, 19, 1, usdhc_sels,        ARRAY_SIZE(usdhc_sels), imx_cscmr1_fixup);
+               hws[IMX6QDL_CLK_ENFC_SEL]         = imx_clk_hw_mux("enfc_sel",         base + 0x2c, 16, 2, enfc_sels,         ARRAY_SIZE(enfc_sels));
+               hws[IMX6QDL_CLK_EIM_SEL]          = imx_clk_hw_fixup_mux("eim_sel",      base + 0x1c, 27, 2, eim_sels,        ARRAY_SIZE(eim_sels), imx_cscmr1_fixup);
+               hws[IMX6QDL_CLK_EIM_SLOW_SEL]     = imx_clk_hw_fixup_mux("eim_slow_sel", base + 0x1c, 29, 2, eim_slow_sels,   ARRAY_SIZE(eim_slow_sels), imx_cscmr1_fixup);
        }
-       clk[IMX6QDL_CLK_VDO_AXI_SEL]      = imx_clk_mux("vdo_axi_sel",      base + 0x18, 11, 1, vdo_axi_sels,      ARRAY_SIZE(vdo_axi_sels));
-       clk[IMX6QDL_CLK_VPU_AXI_SEL]      = imx_clk_mux("vpu_axi_sel",      base + 0x18, 14, 2, vpu_axi_sels,      ARRAY_SIZE(vpu_axi_sels));
-       clk[IMX6QDL_CLK_CKO1_SEL]         = imx_clk_mux("cko1_sel",         base + 0x60, 0,  4, cko1_sels,         ARRAY_SIZE(cko1_sels));
-       clk[IMX6QDL_CLK_CKO2_SEL]         = imx_clk_mux("cko2_sel",         base + 0x60, 16, 5, cko2_sels,         ARRAY_SIZE(cko2_sels));
-       clk[IMX6QDL_CLK_CKO]              = imx_clk_mux("cko",              base + 0x60, 8, 1,  cko_sels,          ARRAY_SIZE(cko_sels));
+
+       hws[IMX6QDL_CLK_VDO_AXI_SEL]      = imx_clk_hw_mux("vdo_axi_sel",      base + 0x18, 11, 1, vdo_axi_sels,      ARRAY_SIZE(vdo_axi_sels));
+       hws[IMX6QDL_CLK_VPU_AXI_SEL]      = imx_clk_hw_mux("vpu_axi_sel",      base + 0x18, 14, 2, vpu_axi_sels,      ARRAY_SIZE(vpu_axi_sels));
+       hws[IMX6QDL_CLK_CKO1_SEL]         = imx_clk_hw_mux("cko1_sel",         base + 0x60, 0,  4, cko1_sels,         ARRAY_SIZE(cko1_sels));
+       hws[IMX6QDL_CLK_CKO2_SEL]         = imx_clk_hw_mux("cko2_sel",         base + 0x60, 16, 5, cko2_sels,         ARRAY_SIZE(cko2_sels));
+       hws[IMX6QDL_CLK_CKO]              = imx_clk_hw_mux("cko",              base + 0x60, 8, 1,  cko_sels,          ARRAY_SIZE(cko_sels));
 
        /*                                          name         reg      shift width busy: reg, shift parent_names  num_parents */
-       clk[IMX6QDL_CLK_PERIPH]  = imx_clk_busy_mux("periph",  base + 0x14, 25,  1,   base + 0x48, 5,  periph_sels,  ARRAY_SIZE(periph_sels));
-       clk[IMX6QDL_CLK_PERIPH2] = imx_clk_busy_mux("periph2", base + 0x14, 26,  1,   base + 0x48, 3,  periph2_sels, ARRAY_SIZE(periph2_sels));
+       hws[IMX6QDL_CLK_PERIPH]  = imx_clk_hw_busy_mux("periph",  base + 0x14, 25,  1,   base + 0x48, 5,  periph_sels,  ARRAY_SIZE(periph_sels));
+       hws[IMX6QDL_CLK_PERIPH2] = imx_clk_hw_busy_mux("periph2", base + 0x14, 26,  1,   base + 0x48, 3,  periph2_sels, ARRAY_SIZE(periph2_sels));
 
        /*                                                  name                parent_name          reg       shift width */
-       clk[IMX6QDL_CLK_PERIPH_CLK2]      = imx_clk_divider("periph_clk2",      "periph_clk2_sel",   base + 0x14, 27, 3);
-       clk[IMX6QDL_CLK_PERIPH2_CLK2]     = imx_clk_divider("periph2_clk2",     "periph2_clk2_sel",  base + 0x14, 0,  3);
-       clk[IMX6QDL_CLK_IPG]              = imx_clk_divider("ipg",              "ahb",               base + 0x14, 8,  2);
-       clk[IMX6QDL_CLK_ESAI_PRED]        = imx_clk_divider("esai_pred",        "esai_sel",          base + 0x28, 9,  3);
-       clk[IMX6QDL_CLK_ESAI_PODF]        = imx_clk_divider("esai_podf",        "esai_pred",         base + 0x28, 25, 3);
-       clk[IMX6QDL_CLK_ASRC_PRED]        = imx_clk_divider("asrc_pred",        "asrc_sel",          base + 0x30, 12, 3);
-       clk[IMX6QDL_CLK_ASRC_PODF]        = imx_clk_divider("asrc_podf",        "asrc_pred",         base + 0x30, 9,  3);
-       clk[IMX6QDL_CLK_SPDIF_PRED]       = imx_clk_divider("spdif_pred",       "spdif_sel",         base + 0x30, 25, 3);
-       clk[IMX6QDL_CLK_SPDIF_PODF]       = imx_clk_divider("spdif_podf",       "spdif_pred",        base + 0x30, 22, 3);
+       hws[IMX6QDL_CLK_PERIPH_CLK2]      = imx_clk_hw_divider("periph_clk2",      "periph_clk2_sel",   base + 0x14, 27, 3);
+       hws[IMX6QDL_CLK_PERIPH2_CLK2]     = imx_clk_hw_divider("periph2_clk2",     "periph2_clk2_sel",  base + 0x14, 0,  3);
+       hws[IMX6QDL_CLK_IPG]              = imx_clk_hw_divider("ipg",              "ahb",               base + 0x14, 8,  2);
+       hws[IMX6QDL_CLK_ESAI_PRED]        = imx_clk_hw_divider("esai_pred",        "esai_sel",          base + 0x28, 9,  3);
+       hws[IMX6QDL_CLK_ESAI_PODF]        = imx_clk_hw_divider("esai_podf",        "esai_pred",         base + 0x28, 25, 3);
+       hws[IMX6QDL_CLK_ASRC_PRED]        = imx_clk_hw_divider("asrc_pred",        "asrc_sel",          base + 0x30, 12, 3);
+       hws[IMX6QDL_CLK_ASRC_PODF]        = imx_clk_hw_divider("asrc_podf",        "asrc_pred",         base + 0x30, 9,  3);
+       hws[IMX6QDL_CLK_SPDIF_PRED]       = imx_clk_hw_divider("spdif_pred",       "spdif_sel",         base + 0x30, 25, 3);
+       hws[IMX6QDL_CLK_SPDIF_PODF]       = imx_clk_hw_divider("spdif_podf",       "spdif_pred",        base + 0x30, 22, 3);
+
        if (clk_on_imx6qp()) {
-               clk[IMX6QDL_CLK_IPG_PER] = imx_clk_divider("ipg_per", "ipg_per_sel", base + 0x1c, 0, 6);
-               clk[IMX6QDL_CLK_ECSPI_ROOT] = imx_clk_divider("ecspi_root", "ecspi_sel", base + 0x38, 19, 6);
-               clk[IMX6QDL_CLK_CAN_ROOT] = imx_clk_divider("can_root", "can_sel", base + 0x20, 2, 6);
-               clk[IMX6QDL_CLK_UART_SERIAL_PODF] = imx_clk_divider("uart_serial_podf", "uart_sel", base + 0x24, 0, 6);
-               clk[IMX6QDL_CLK_LDB_DI0_DIV_3_5] = imx_clk_fixed_factor("ldb_di0_div_3_5", "ldb_di0", 2, 7);
-               clk[IMX6QDL_CLK_LDB_DI1_DIV_3_5] = imx_clk_fixed_factor("ldb_di1_div_3_5", "ldb_di1", 2, 7);
+               hws[IMX6QDL_CLK_IPG_PER] = imx_clk_hw_divider("ipg_per", "ipg_per_sel", base + 0x1c, 0, 6);
+               hws[IMX6QDL_CLK_ECSPI_ROOT] = imx_clk_hw_divider("ecspi_root", "ecspi_sel", base + 0x38, 19, 6);
+               hws[IMX6QDL_CLK_CAN_ROOT] = imx_clk_hw_divider("can_root", "can_sel", base + 0x20, 2, 6);
+               hws[IMX6QDL_CLK_UART_SERIAL_PODF] = imx_clk_hw_divider("uart_serial_podf", "uart_sel", base + 0x24, 0, 6);
+               hws[IMX6QDL_CLK_LDB_DI0_DIV_3_5] = imx_clk_hw_fixed_factor("ldb_di0_div_3_5", "ldb_di0", 2, 7);
+               hws[IMX6QDL_CLK_LDB_DI1_DIV_3_5] = imx_clk_hw_fixed_factor("ldb_di1_div_3_5", "ldb_di1", 2, 7);
        } else {
-               clk[IMX6QDL_CLK_ECSPI_ROOT] = imx_clk_divider("ecspi_root", "pll3_60m", base + 0x38, 19, 6);
-               clk[IMX6QDL_CLK_CAN_ROOT] = imx_clk_divider("can_root", "pll3_60m", base + 0x20, 2, 6);
-               clk[IMX6QDL_CLK_IPG_PER] = imx_clk_fixup_divider("ipg_per", "ipg", base + 0x1c, 0, 6, imx_cscmr1_fixup);
-               clk[IMX6QDL_CLK_UART_SERIAL_PODF] = imx_clk_divider("uart_serial_podf", "pll3_80m",          base + 0x24, 0,  6);
-               clk[IMX6QDL_CLK_LDB_DI0_DIV_3_5] = imx_clk_fixed_factor("ldb_di0_div_3_5", "ldb_di0_sel", 2, 7);
-               clk[IMX6QDL_CLK_LDB_DI1_DIV_3_5] = imx_clk_fixed_factor("ldb_di1_div_3_5", "ldb_di1_sel", 2, 7);
+               hws[IMX6QDL_CLK_ECSPI_ROOT] = imx_clk_hw_divider("ecspi_root", "pll3_60m", base + 0x38, 19, 6);
+               hws[IMX6QDL_CLK_CAN_ROOT] = imx_clk_hw_divider("can_root", "pll3_60m", base + 0x20, 2, 6);
+               hws[IMX6QDL_CLK_IPG_PER] = imx_clk_hw_fixup_divider("ipg_per", "ipg", base + 0x1c, 0, 6, imx_cscmr1_fixup);
+               hws[IMX6QDL_CLK_UART_SERIAL_PODF] = imx_clk_hw_divider("uart_serial_podf", "pll3_80m",          base + 0x24, 0,  6);
+               hws[IMX6QDL_CLK_LDB_DI0_DIV_3_5] = imx_clk_hw_fixed_factor("ldb_di0_div_3_5", "ldb_di0_sel", 2, 7);
+               hws[IMX6QDL_CLK_LDB_DI1_DIV_3_5] = imx_clk_hw_fixed_factor("ldb_di1_div_3_5", "ldb_di1_sel", 2, 7);
        }
+
        if (clk_on_imx6dl())
-               clk[IMX6QDL_CLK_MLB_PODF]  = imx_clk_divider("mlb_podf",  "mlb_sel",    base + 0x18, 23, 3);
+               hws[IMX6QDL_CLK_MLB_PODF]  = imx_clk_hw_divider("mlb_podf",  "mlb_sel",    base + 0x18, 23, 3);
        else
-               clk[IMX6QDL_CLK_GPU2D_CORE_PODF]  = imx_clk_divider("gpu2d_core_podf",  "gpu2d_core_sel",    base + 0x18, 23, 3);
-       clk[IMX6QDL_CLK_GPU3D_CORE_PODF]  = imx_clk_divider("gpu3d_core_podf",  "gpu3d_core_sel",    base + 0x18, 26, 3);
+               hws[IMX6QDL_CLK_GPU2D_CORE_PODF]  = imx_clk_hw_divider("gpu2d_core_podf",  "gpu2d_core_sel",    base + 0x18, 23, 3);
+       hws[IMX6QDL_CLK_GPU3D_CORE_PODF]  = imx_clk_hw_divider("gpu3d_core_podf",  "gpu3d_core_sel",    base + 0x18, 26, 3);
        if (clk_on_imx6dl())
-               clk[IMX6QDL_CLK_GPU2D_CORE_PODF]  = imx_clk_divider("gpu2d_core_podf",     "gpu2d_core_sel",  base + 0x18, 29, 3);
+               hws[IMX6QDL_CLK_GPU2D_CORE_PODF]  = imx_clk_hw_divider("gpu2d_core_podf",     "gpu2d_core_sel",  base + 0x18, 29, 3);
        else
-               clk[IMX6QDL_CLK_GPU3D_SHADER]     = imx_clk_divider("gpu3d_shader",     "gpu3d_shader_sel",  base + 0x18, 29, 3);
-       clk[IMX6QDL_CLK_IPU1_PODF]        = imx_clk_divider("ipu1_podf",        "ipu1_sel",          base + 0x3c, 11, 3);
-       clk[IMX6QDL_CLK_IPU2_PODF]        = imx_clk_divider("ipu2_podf",        "ipu2_sel",          base + 0x3c, 16, 3);
-       clk[IMX6QDL_CLK_LDB_DI0_PODF]     = imx_clk_divider_flags("ldb_di0_podf", "ldb_di0_div_3_5", base + 0x20, 10, 1, 0);
-       clk[IMX6QDL_CLK_LDB_DI1_PODF]     = imx_clk_divider_flags("ldb_di1_podf", "ldb_di1_div_3_5", base + 0x20, 11, 1, 0);
-       clk[IMX6QDL_CLK_IPU1_DI0_PRE]     = imx_clk_divider("ipu1_di0_pre",     "ipu1_di0_pre_sel",  base + 0x34, 3,  3);
-       clk[IMX6QDL_CLK_IPU1_DI1_PRE]     = imx_clk_divider("ipu1_di1_pre",     "ipu1_di1_pre_sel",  base + 0x34, 12, 3);
-       clk[IMX6QDL_CLK_IPU2_DI0_PRE]     = imx_clk_divider("ipu2_di0_pre",     "ipu2_di0_pre_sel",  base + 0x38, 3,  3);
-       clk[IMX6QDL_CLK_IPU2_DI1_PRE]     = imx_clk_divider("ipu2_di1_pre",     "ipu2_di1_pre_sel",  base + 0x38, 12, 3);
-       clk[IMX6QDL_CLK_HSI_TX_PODF]      = imx_clk_divider("hsi_tx_podf",      "hsi_tx_sel",        base + 0x30, 29, 3);
-       clk[IMX6QDL_CLK_SSI1_PRED]        = imx_clk_divider("ssi1_pred",        "ssi1_sel",          base + 0x28, 6,  3);
-       clk[IMX6QDL_CLK_SSI1_PODF]        = imx_clk_divider("ssi1_podf",        "ssi1_pred",         base + 0x28, 0,  6);
-       clk[IMX6QDL_CLK_SSI2_PRED]        = imx_clk_divider("ssi2_pred",        "ssi2_sel",          base + 0x2c, 6,  3);
-       clk[IMX6QDL_CLK_SSI2_PODF]        = imx_clk_divider("ssi2_podf",        "ssi2_pred",         base + 0x2c, 0,  6);
-       clk[IMX6QDL_CLK_SSI3_PRED]        = imx_clk_divider("ssi3_pred",        "ssi3_sel",          base + 0x28, 22, 3);
-       clk[IMX6QDL_CLK_SSI3_PODF]        = imx_clk_divider("ssi3_podf",        "ssi3_pred",         base + 0x28, 16, 6);
-       clk[IMX6QDL_CLK_USDHC1_PODF]      = imx_clk_divider("usdhc1_podf",      "usdhc1_sel",        base + 0x24, 11, 3);
-       clk[IMX6QDL_CLK_USDHC2_PODF]      = imx_clk_divider("usdhc2_podf",      "usdhc2_sel",        base + 0x24, 16, 3);
-       clk[IMX6QDL_CLK_USDHC3_PODF]      = imx_clk_divider("usdhc3_podf",      "usdhc3_sel",        base + 0x24, 19, 3);
-       clk[IMX6QDL_CLK_USDHC4_PODF]      = imx_clk_divider("usdhc4_podf",      "usdhc4_sel",        base + 0x24, 22, 3);
-       clk[IMX6QDL_CLK_ENFC_PRED]        = imx_clk_divider("enfc_pred",        "enfc_sel",          base + 0x2c, 18, 3);
-       clk[IMX6QDL_CLK_ENFC_PODF]        = imx_clk_divider("enfc_podf",        "enfc_pred",         base + 0x2c, 21, 6);
+               hws[IMX6QDL_CLK_GPU3D_SHADER]     = imx_clk_hw_divider("gpu3d_shader",     "gpu3d_shader_sel",  base + 0x18, 29, 3);
+       hws[IMX6QDL_CLK_IPU1_PODF]        = imx_clk_hw_divider("ipu1_podf",        "ipu1_sel",          base + 0x3c, 11, 3);
+       hws[IMX6QDL_CLK_IPU2_PODF]        = imx_clk_hw_divider("ipu2_podf",        "ipu2_sel",          base + 0x3c, 16, 3);
+       hws[IMX6QDL_CLK_LDB_DI0_PODF]     = imx_clk_hw_divider_flags("ldb_di0_podf", "ldb_di0_div_3_5", base + 0x20, 10, 1, 0);
+       hws[IMX6QDL_CLK_LDB_DI1_PODF]     = imx_clk_hw_divider_flags("ldb_di1_podf", "ldb_di1_div_3_5", base + 0x20, 11, 1, 0);
+       hws[IMX6QDL_CLK_IPU1_DI0_PRE]     = imx_clk_hw_divider("ipu1_di0_pre",     "ipu1_di0_pre_sel",  base + 0x34, 3,  3);
+       hws[IMX6QDL_CLK_IPU1_DI1_PRE]     = imx_clk_hw_divider("ipu1_di1_pre",     "ipu1_di1_pre_sel",  base + 0x34, 12, 3);
+       hws[IMX6QDL_CLK_IPU2_DI0_PRE]     = imx_clk_hw_divider("ipu2_di0_pre",     "ipu2_di0_pre_sel",  base + 0x38, 3,  3);
+       hws[IMX6QDL_CLK_IPU2_DI1_PRE]     = imx_clk_hw_divider("ipu2_di1_pre",     "ipu2_di1_pre_sel",  base + 0x38, 12, 3);
+       hws[IMX6QDL_CLK_HSI_TX_PODF]      = imx_clk_hw_divider("hsi_tx_podf",      "hsi_tx_sel",        base + 0x30, 29, 3);
+       hws[IMX6QDL_CLK_SSI1_PRED]        = imx_clk_hw_divider("ssi1_pred",        "ssi1_sel",          base + 0x28, 6,  3);
+       hws[IMX6QDL_CLK_SSI1_PODF]        = imx_clk_hw_divider("ssi1_podf",        "ssi1_pred",         base + 0x28, 0,  6);
+       hws[IMX6QDL_CLK_SSI2_PRED]        = imx_clk_hw_divider("ssi2_pred",        "ssi2_sel",          base + 0x2c, 6,  3);
+       hws[IMX6QDL_CLK_SSI2_PODF]        = imx_clk_hw_divider("ssi2_podf",        "ssi2_pred",         base + 0x2c, 0,  6);
+       hws[IMX6QDL_CLK_SSI3_PRED]        = imx_clk_hw_divider("ssi3_pred",        "ssi3_sel",          base + 0x28, 22, 3);
+       hws[IMX6QDL_CLK_SSI3_PODF]        = imx_clk_hw_divider("ssi3_podf",        "ssi3_pred",         base + 0x28, 16, 6);
+       hws[IMX6QDL_CLK_USDHC1_PODF]      = imx_clk_hw_divider("usdhc1_podf",      "usdhc1_sel",        base + 0x24, 11, 3);
+       hws[IMX6QDL_CLK_USDHC2_PODF]      = imx_clk_hw_divider("usdhc2_podf",      "usdhc2_sel",        base + 0x24, 16, 3);
+       hws[IMX6QDL_CLK_USDHC3_PODF]      = imx_clk_hw_divider("usdhc3_podf",      "usdhc3_sel",        base + 0x24, 19, 3);
+       hws[IMX6QDL_CLK_USDHC4_PODF]      = imx_clk_hw_divider("usdhc4_podf",      "usdhc4_sel",        base + 0x24, 22, 3);
+       hws[IMX6QDL_CLK_ENFC_PRED]        = imx_clk_hw_divider("enfc_pred",        "enfc_sel",          base + 0x2c, 18, 3);
+       hws[IMX6QDL_CLK_ENFC_PODF]        = imx_clk_hw_divider("enfc_podf",        "enfc_pred",         base + 0x2c, 21, 6);
        if (clk_on_imx6qp()) {
-               clk[IMX6QDL_CLK_EIM_PODF]         = imx_clk_divider("eim_podf",   "eim_sel",           base + 0x1c, 20, 3);
-               clk[IMX6QDL_CLK_EIM_SLOW_PODF]    = imx_clk_divider("eim_slow_podf", "eim_slow_sel",   base + 0x1c, 23, 3);
+               hws[IMX6QDL_CLK_EIM_PODF]         = imx_clk_hw_divider("eim_podf",   "eim_sel",           base + 0x1c, 20, 3);
+               hws[IMX6QDL_CLK_EIM_SLOW_PODF]    = imx_clk_hw_divider("eim_slow_podf", "eim_slow_sel",   base + 0x1c, 23, 3);
        } else {
-               clk[IMX6QDL_CLK_EIM_PODF]         = imx_clk_fixup_divider("eim_podf",   "eim_sel",           base + 0x1c, 20, 3, imx_cscmr1_fixup);
-               clk[IMX6QDL_CLK_EIM_SLOW_PODF]    = imx_clk_fixup_divider("eim_slow_podf", "eim_slow_sel",   base + 0x1c, 23, 3, imx_cscmr1_fixup);
+               hws[IMX6QDL_CLK_EIM_PODF]         = imx_clk_hw_fixup_divider("eim_podf",   "eim_sel",           base + 0x1c, 20, 3, imx_cscmr1_fixup);
+               hws[IMX6QDL_CLK_EIM_SLOW_PODF]    = imx_clk_hw_fixup_divider("eim_slow_podf", "eim_slow_sel",   base + 0x1c, 23, 3, imx_cscmr1_fixup);
        }
-       clk[IMX6QDL_CLK_VPU_AXI_PODF]     = imx_clk_divider("vpu_axi_podf",     "vpu_axi_sel",       base + 0x24, 25, 3);
-       clk[IMX6QDL_CLK_CKO1_PODF]        = imx_clk_divider("cko1_podf",        "cko1_sel",          base + 0x60, 4,  3);
-       clk[IMX6QDL_CLK_CKO2_PODF]        = imx_clk_divider("cko2_podf",        "cko2_sel",          base + 0x60, 21, 3);
+
+       hws[IMX6QDL_CLK_VPU_AXI_PODF]     = imx_clk_hw_divider("vpu_axi_podf",     "vpu_axi_sel",       base + 0x24, 25, 3);
+       hws[IMX6QDL_CLK_CKO1_PODF]        = imx_clk_hw_divider("cko1_podf",        "cko1_sel",          base + 0x60, 4,  3);
+       hws[IMX6QDL_CLK_CKO2_PODF]        = imx_clk_hw_divider("cko2_podf",        "cko2_sel",          base + 0x60, 21, 3);
 
        /*                                                        name                 parent_name    reg        shift width busy: reg, shift */
-       clk[IMX6QDL_CLK_AXI]               = imx_clk_busy_divider("axi",               "axi_sel",     base + 0x14, 16,  3,   base + 0x48, 0);
-       clk[IMX6QDL_CLK_MMDC_CH0_AXI_PODF] = imx_clk_busy_divider("mmdc_ch0_axi_podf", "periph",      base + 0x14, 19,  3,   base + 0x48, 4);
+       hws[IMX6QDL_CLK_AXI]               = imx_clk_hw_busy_divider("axi",               "axi_sel",     base + 0x14, 16,  3,   base + 0x48, 0);
+       hws[IMX6QDL_CLK_MMDC_CH0_AXI_PODF] = imx_clk_hw_busy_divider("mmdc_ch0_axi_podf", "periph",      base + 0x14, 19,  3,   base + 0x48, 4);
        if (clk_on_imx6qp()) {
-               clk[IMX6QDL_CLK_MMDC_CH1_AXI_CG] = imx_clk_gate("mmdc_ch1_axi_cg", "periph2", base + 0x4, 18);
-               clk[IMX6QDL_CLK_MMDC_CH1_AXI_PODF] = imx_clk_busy_divider("mmdc_ch1_axi_podf", "mmdc_ch1_axi_cg", base + 0x14, 3, 3, base + 0x48, 2);
+               hws[IMX6QDL_CLK_MMDC_CH1_AXI_CG] = imx_clk_hw_gate("mmdc_ch1_axi_cg", "periph2", base + 0x4, 18);
+               hws[IMX6QDL_CLK_MMDC_CH1_AXI_PODF] = imx_clk_hw_busy_divider("mmdc_ch1_axi_podf", "mmdc_ch1_axi_cg", base + 0x14, 3, 3, base + 0x48, 2);
        } else {
-               clk[IMX6QDL_CLK_MMDC_CH1_AXI_PODF] = imx_clk_busy_divider("mmdc_ch1_axi_podf", "periph2",     base + 0x14, 3,   3,   base + 0x48, 2);
+               hws[IMX6QDL_CLK_MMDC_CH1_AXI_PODF] = imx_clk_hw_busy_divider("mmdc_ch1_axi_podf", "periph2",     base + 0x14, 3,   3,   base + 0x48, 2);
        }
-       clk[IMX6QDL_CLK_ARM]               = imx_clk_busy_divider("arm",               "pll1_sw",     base + 0x10, 0,   3,   base + 0x48, 16);
-       clk[IMX6QDL_CLK_AHB]               = imx_clk_busy_divider("ahb",               "periph",      base + 0x14, 10,  3,   base + 0x48, 1);
+       hws[IMX6QDL_CLK_ARM]               = imx_clk_hw_busy_divider("arm",               "pll1_sw",     base + 0x10, 0,   3,   base + 0x48, 16);
+       hws[IMX6QDL_CLK_AHB]               = imx_clk_hw_busy_divider("ahb",               "periph",      base + 0x14, 10,  3,   base + 0x48, 1);
 
        /*                                            name             parent_name          reg         shift */
-       clk[IMX6QDL_CLK_APBH_DMA]     = imx_clk_gate2("apbh_dma",      "usdhc3",            base + 0x68, 4);
-       clk[IMX6QDL_CLK_ASRC]         = imx_clk_gate2_shared("asrc",         "asrc_podf",   base + 0x68, 6, &share_count_asrc);
-       clk[IMX6QDL_CLK_ASRC_IPG]     = imx_clk_gate2_shared("asrc_ipg",     "ahb",         base + 0x68, 6, &share_count_asrc);
-       clk[IMX6QDL_CLK_ASRC_MEM]     = imx_clk_gate2_shared("asrc_mem",     "ahb",         base + 0x68, 6, &share_count_asrc);
-       clk[IMX6QDL_CLK_CAAM_MEM]     = imx_clk_gate2("caam_mem",      "ahb",               base + 0x68, 8);
-       clk[IMX6QDL_CLK_CAAM_ACLK]    = imx_clk_gate2("caam_aclk",     "ahb",               base + 0x68, 10);
-       clk[IMX6QDL_CLK_CAAM_IPG]     = imx_clk_gate2("caam_ipg",      "ipg",               base + 0x68, 12);
-       clk[IMX6QDL_CLK_CAN1_IPG]     = imx_clk_gate2("can1_ipg",      "ipg",               base + 0x68, 14);
-       clk[IMX6QDL_CLK_CAN1_SERIAL]  = imx_clk_gate2("can1_serial",   "can_root",          base + 0x68, 16);
-       clk[IMX6QDL_CLK_CAN2_IPG]     = imx_clk_gate2("can2_ipg",      "ipg",               base + 0x68, 18);
-       clk[IMX6QDL_CLK_CAN2_SERIAL]  = imx_clk_gate2("can2_serial",   "can_root",          base + 0x68, 20);
-       clk[IMX6QDL_CLK_DCIC1]        = imx_clk_gate2("dcic1",         "ipu1_podf",         base + 0x68, 24);
-       clk[IMX6QDL_CLK_DCIC2]        = imx_clk_gate2("dcic2",         "ipu2_podf",         base + 0x68, 26);
-       clk[IMX6QDL_CLK_ECSPI1]       = imx_clk_gate2("ecspi1",        "ecspi_root",        base + 0x6c, 0);
-       clk[IMX6QDL_CLK_ECSPI2]       = imx_clk_gate2("ecspi2",        "ecspi_root",        base + 0x6c, 2);
-       clk[IMX6QDL_CLK_ECSPI3]       = imx_clk_gate2("ecspi3",        "ecspi_root",        base + 0x6c, 4);
-       clk[IMX6QDL_CLK_ECSPI4]       = imx_clk_gate2("ecspi4",        "ecspi_root",        base + 0x6c, 6);
+       hws[IMX6QDL_CLK_APBH_DMA]     = imx_clk_hw_gate2("apbh_dma",      "usdhc3",            base + 0x68, 4);
+       hws[IMX6QDL_CLK_ASRC]         = imx_clk_hw_gate2_shared("asrc",         "asrc_podf",   base + 0x68, 6, &share_count_asrc);
+       hws[IMX6QDL_CLK_ASRC_IPG]     = imx_clk_hw_gate2_shared("asrc_ipg",     "ahb",         base + 0x68, 6, &share_count_asrc);
+       hws[IMX6QDL_CLK_ASRC_MEM]     = imx_clk_hw_gate2_shared("asrc_mem",     "ahb",         base + 0x68, 6, &share_count_asrc);
+       hws[IMX6QDL_CLK_CAAM_MEM]     = imx_clk_hw_gate2("caam_mem",      "ahb",               base + 0x68, 8);
+       hws[IMX6QDL_CLK_CAAM_ACLK]    = imx_clk_hw_gate2("caam_aclk",     "ahb",               base + 0x68, 10);
+       hws[IMX6QDL_CLK_CAAM_IPG]     = imx_clk_hw_gate2("caam_ipg",      "ipg",               base + 0x68, 12);
+       hws[IMX6QDL_CLK_CAN1_IPG]     = imx_clk_hw_gate2("can1_ipg",      "ipg",               base + 0x68, 14);
+       hws[IMX6QDL_CLK_CAN1_SERIAL]  = imx_clk_hw_gate2("can1_serial",   "can_root",          base + 0x68, 16);
+       hws[IMX6QDL_CLK_CAN2_IPG]     = imx_clk_hw_gate2("can2_ipg",      "ipg",               base + 0x68, 18);
+       hws[IMX6QDL_CLK_CAN2_SERIAL]  = imx_clk_hw_gate2("can2_serial",   "can_root",          base + 0x68, 20);
+       hws[IMX6QDL_CLK_DCIC1]        = imx_clk_hw_gate2("dcic1",         "ipu1_podf",         base + 0x68, 24);
+       hws[IMX6QDL_CLK_DCIC2]        = imx_clk_hw_gate2("dcic2",         "ipu2_podf",         base + 0x68, 26);
+       hws[IMX6QDL_CLK_ECSPI1]       = imx_clk_hw_gate2("ecspi1",        "ecspi_root",        base + 0x6c, 0);
+       hws[IMX6QDL_CLK_ECSPI2]       = imx_clk_hw_gate2("ecspi2",        "ecspi_root",        base + 0x6c, 2);
+       hws[IMX6QDL_CLK_ECSPI3]       = imx_clk_hw_gate2("ecspi3",        "ecspi_root",        base + 0x6c, 4);
+       hws[IMX6QDL_CLK_ECSPI4]       = imx_clk_hw_gate2("ecspi4",        "ecspi_root",        base + 0x6c, 6);
        if (clk_on_imx6dl())
-               clk[IMX6DL_CLK_I2C4]  = imx_clk_gate2("i2c4",          "ipg_per",           base + 0x6c, 8);
+               hws[IMX6DL_CLK_I2C4]  = imx_clk_hw_gate2("i2c4",          "ipg_per",           base + 0x6c, 8);
        else
-               clk[IMX6Q_CLK_ECSPI5] = imx_clk_gate2("ecspi5",        "ecspi_root",        base + 0x6c, 8);
-       clk[IMX6QDL_CLK_ENET]         = imx_clk_gate2("enet",          "ipg",               base + 0x6c, 10);
-       clk[IMX6QDL_CLK_EPIT1]        = imx_clk_gate2("epit1",         "ipg",               base + 0x6c, 12);
-       clk[IMX6QDL_CLK_EPIT2]        = imx_clk_gate2("epit2",         "ipg",               base + 0x6c, 14);
-       clk[IMX6QDL_CLK_ESAI_EXTAL]   = imx_clk_gate2_shared("esai_extal",   "esai_podf",   base + 0x6c, 16, &share_count_esai);
-       clk[IMX6QDL_CLK_ESAI_IPG]     = imx_clk_gate2_shared("esai_ipg",   "ahb",           base + 0x6c, 16, &share_count_esai);
-       clk[IMX6QDL_CLK_ESAI_MEM]     = imx_clk_gate2_shared("esai_mem", "ahb",             base + 0x6c, 16, &share_count_esai);
-       clk[IMX6QDL_CLK_GPT_IPG]      = imx_clk_gate2("gpt_ipg",       "ipg",               base + 0x6c, 20);
-       clk[IMX6QDL_CLK_GPT_IPG_PER]  = imx_clk_gate2("gpt_ipg_per",   "ipg_per",           base + 0x6c, 22);
-       clk[IMX6QDL_CLK_GPU2D_CORE] = imx_clk_gate2("gpu2d_core", "gpu2d_core_podf", base + 0x6c, 24);
-       clk[IMX6QDL_CLK_GPU3D_CORE]   = imx_clk_gate2("gpu3d_core",    "gpu3d_core_podf",   base + 0x6c, 26);
-       clk[IMX6QDL_CLK_HDMI_IAHB]    = imx_clk_gate2("hdmi_iahb",     "ahb",               base + 0x70, 0);
-       clk[IMX6QDL_CLK_HDMI_ISFR]    = imx_clk_gate2("hdmi_isfr",     "mipi_core_cfg",     base + 0x70, 4);
-       clk[IMX6QDL_CLK_I2C1]         = imx_clk_gate2("i2c1",          "ipg_per",           base + 0x70, 6);
-       clk[IMX6QDL_CLK_I2C2]         = imx_clk_gate2("i2c2",          "ipg_per",           base + 0x70, 8);
-       clk[IMX6QDL_CLK_I2C3]         = imx_clk_gate2("i2c3",          "ipg_per",           base + 0x70, 10);
-       clk[IMX6QDL_CLK_IIM]          = imx_clk_gate2("iim",           "ipg",               base + 0x70, 12);
-       clk[IMX6QDL_CLK_ENFC]         = imx_clk_gate2("enfc",          "enfc_podf",         base + 0x70, 14);
-       clk[IMX6QDL_CLK_VDOA]         = imx_clk_gate2("vdoa",          "vdo_axi",           base + 0x70, 26);
-       clk[IMX6QDL_CLK_IPU1]         = imx_clk_gate2("ipu1",          "ipu1_podf",         base + 0x74, 0);
-       clk[IMX6QDL_CLK_IPU1_DI0]     = imx_clk_gate2("ipu1_di0",      "ipu1_di0_sel",      base + 0x74, 2);
-       clk[IMX6QDL_CLK_IPU1_DI1]     = imx_clk_gate2("ipu1_di1",      "ipu1_di1_sel",      base + 0x74, 4);
-       clk[IMX6QDL_CLK_IPU2]         = imx_clk_gate2("ipu2",          "ipu2_podf",         base + 0x74, 6);
-       clk[IMX6QDL_CLK_IPU2_DI0]     = imx_clk_gate2("ipu2_di0",      "ipu2_di0_sel",      base + 0x74, 8);
+               hws[IMX6Q_CLK_ECSPI5] = imx_clk_hw_gate2("ecspi5",        "ecspi_root",        base + 0x6c, 8);
+       hws[IMX6QDL_CLK_ENET]         = imx_clk_hw_gate2("enet",          "ipg",               base + 0x6c, 10);
+       hws[IMX6QDL_CLK_EPIT1]        = imx_clk_hw_gate2("epit1",         "ipg",               base + 0x6c, 12);
+       hws[IMX6QDL_CLK_EPIT2]        = imx_clk_hw_gate2("epit2",         "ipg",               base + 0x6c, 14);
+       hws[IMX6QDL_CLK_ESAI_EXTAL]   = imx_clk_hw_gate2_shared("esai_extal",   "esai_podf",   base + 0x6c, 16, &share_count_esai);
+       hws[IMX6QDL_CLK_ESAI_IPG]     = imx_clk_hw_gate2_shared("esai_ipg",   "ahb",           base + 0x6c, 16, &share_count_esai);
+       hws[IMX6QDL_CLK_ESAI_MEM]     = imx_clk_hw_gate2_shared("esai_mem", "ahb",             base + 0x6c, 16, &share_count_esai);
+       hws[IMX6QDL_CLK_GPT_IPG]      = imx_clk_hw_gate2("gpt_ipg",       "ipg",               base + 0x6c, 20);
+       hws[IMX6QDL_CLK_GPT_IPG_PER]  = imx_clk_hw_gate2("gpt_ipg_per",   "ipg_per",           base + 0x6c, 22);
+       hws[IMX6QDL_CLK_GPU2D_CORE] = imx_clk_hw_gate2("gpu2d_core", "gpu2d_core_podf", base + 0x6c, 24);
+       hws[IMX6QDL_CLK_GPU3D_CORE]   = imx_clk_hw_gate2("gpu3d_core",    "gpu3d_core_podf",   base + 0x6c, 26);
+       hws[IMX6QDL_CLK_HDMI_IAHB]    = imx_clk_hw_gate2("hdmi_iahb",     "ahb",               base + 0x70, 0);
+       hws[IMX6QDL_CLK_HDMI_ISFR]    = imx_clk_hw_gate2("hdmi_isfr",     "mipi_core_cfg",     base + 0x70, 4);
+       hws[IMX6QDL_CLK_I2C1]         = imx_clk_hw_gate2("i2c1",          "ipg_per",           base + 0x70, 6);
+       hws[IMX6QDL_CLK_I2C2]         = imx_clk_hw_gate2("i2c2",          "ipg_per",           base + 0x70, 8);
+       hws[IMX6QDL_CLK_I2C3]         = imx_clk_hw_gate2("i2c3",          "ipg_per",           base + 0x70, 10);
+       hws[IMX6QDL_CLK_IIM]          = imx_clk_hw_gate2("iim",           "ipg",               base + 0x70, 12);
+       hws[IMX6QDL_CLK_ENFC]         = imx_clk_hw_gate2("enfc",          "enfc_podf",         base + 0x70, 14);
+       hws[IMX6QDL_CLK_VDOA]         = imx_clk_hw_gate2("vdoa",          "vdo_axi",           base + 0x70, 26);
+       hws[IMX6QDL_CLK_IPU1]         = imx_clk_hw_gate2("ipu1",          "ipu1_podf",         base + 0x74, 0);
+       hws[IMX6QDL_CLK_IPU1_DI0]     = imx_clk_hw_gate2("ipu1_di0",      "ipu1_di0_sel",      base + 0x74, 2);
+       hws[IMX6QDL_CLK_IPU1_DI1]     = imx_clk_hw_gate2("ipu1_di1",      "ipu1_di1_sel",      base + 0x74, 4);
+       hws[IMX6QDL_CLK_IPU2]         = imx_clk_hw_gate2("ipu2",          "ipu2_podf",         base + 0x74, 6);
+       hws[IMX6QDL_CLK_IPU2_DI0]     = imx_clk_hw_gate2("ipu2_di0",      "ipu2_di0_sel",      base + 0x74, 8);
        if (clk_on_imx6qp()) {
-               clk[IMX6QDL_CLK_LDB_DI0]      = imx_clk_gate2("ldb_di0",       "ldb_di0_sel",      base + 0x74, 12);
-               clk[IMX6QDL_CLK_LDB_DI1]      = imx_clk_gate2("ldb_di1",       "ldb_di1_sel",      base + 0x74, 14);
+               hws[IMX6QDL_CLK_LDB_DI0]      = imx_clk_hw_gate2("ldb_di0",       "ldb_di0_sel",      base + 0x74, 12);
+               hws[IMX6QDL_CLK_LDB_DI1]      = imx_clk_hw_gate2("ldb_di1",       "ldb_di1_sel",      base + 0x74, 14);
        } else {
-               clk[IMX6QDL_CLK_LDB_DI0]      = imx_clk_gate2("ldb_di0",       "ldb_di0_podf",      base + 0x74, 12);
-               clk[IMX6QDL_CLK_LDB_DI1]      = imx_clk_gate2("ldb_di1",       "ldb_di1_podf",      base + 0x74, 14);
+               hws[IMX6QDL_CLK_LDB_DI0]      = imx_clk_hw_gate2("ldb_di0",       "ldb_di0_podf",      base + 0x74, 12);
+               hws[IMX6QDL_CLK_LDB_DI1]      = imx_clk_hw_gate2("ldb_di1",       "ldb_di1_podf",      base + 0x74, 14);
        }
-       clk[IMX6QDL_CLK_IPU2_DI1]     = imx_clk_gate2("ipu2_di1",      "ipu2_di1_sel",      base + 0x74, 10);
-       clk[IMX6QDL_CLK_HSI_TX]       = imx_clk_gate2_shared("hsi_tx", "hsi_tx_podf",       base + 0x74, 16, &share_count_mipi_core_cfg);
-       clk[IMX6QDL_CLK_MIPI_CORE_CFG] = imx_clk_gate2_shared("mipi_core_cfg", "video_27m", base + 0x74, 16, &share_count_mipi_core_cfg);
-       clk[IMX6QDL_CLK_MIPI_IPG]     = imx_clk_gate2_shared("mipi_ipg", "ipg",             base + 0x74, 16, &share_count_mipi_core_cfg);
+       hws[IMX6QDL_CLK_IPU2_DI1]     = imx_clk_hw_gate2("ipu2_di1",      "ipu2_di1_sel",      base + 0x74, 10);
+       hws[IMX6QDL_CLK_HSI_TX]       = imx_clk_hw_gate2_shared("hsi_tx", "hsi_tx_podf",       base + 0x74, 16, &share_count_mipi_core_cfg);
+       hws[IMX6QDL_CLK_MIPI_CORE_CFG] = imx_clk_hw_gate2_shared("mipi_core_cfg", "video_27m", base + 0x74, 16, &share_count_mipi_core_cfg);
+       hws[IMX6QDL_CLK_MIPI_IPG]     = imx_clk_hw_gate2_shared("mipi_ipg", "ipg",             base + 0x74, 16, &share_count_mipi_core_cfg);
+
        if (clk_on_imx6dl())
                /*
                 * The multiplexer and divider of the imx6q clock gpu2d get
                 * redefined/reused as mlb_sys_sel and mlb_sys_clk_podf on imx6dl.
                 */
-               clk[IMX6QDL_CLK_MLB] = imx_clk_gate2("mlb",            "mlb_podf",   base + 0x74, 18);
+               hws[IMX6QDL_CLK_MLB] = imx_clk_hw_gate2("mlb",            "mlb_podf",   base + 0x74, 18);
        else
-               clk[IMX6QDL_CLK_MLB] = imx_clk_gate2("mlb",            "axi",               base + 0x74, 18);
-       clk[IMX6QDL_CLK_MMDC_CH0_AXI] = imx_clk_gate2_flags("mmdc_ch0_axi",  "mmdc_ch0_axi_podf", base + 0x74, 20, CLK_IS_CRITICAL);
-       clk[IMX6QDL_CLK_MMDC_CH1_AXI] = imx_clk_gate2("mmdc_ch1_axi",  "mmdc_ch1_axi_podf", base + 0x74, 22);
-       clk[IMX6QDL_CLK_MMDC_P0_IPG]  = imx_clk_gate2_flags("mmdc_p0_ipg",   "ipg",         base + 0x74, 24, CLK_IS_CRITICAL);
-       clk[IMX6QDL_CLK_OCRAM]        = imx_clk_gate2("ocram",         "ahb",               base + 0x74, 28);
-       clk[IMX6QDL_CLK_OPENVG_AXI]   = imx_clk_gate2("openvg_axi",    "axi",               base + 0x74, 30);
-       clk[IMX6QDL_CLK_PCIE_AXI]     = imx_clk_gate2("pcie_axi",      "pcie_axi_sel",      base + 0x78, 0);
-       clk[IMX6QDL_CLK_PER1_BCH]     = imx_clk_gate2("per1_bch",      "usdhc3",            base + 0x78, 12);
-       clk[IMX6QDL_CLK_PWM1]         = imx_clk_gate2("pwm1",          "ipg_per",           base + 0x78, 16);
-       clk[IMX6QDL_CLK_PWM2]         = imx_clk_gate2("pwm2",          "ipg_per",           base + 0x78, 18);
-       clk[IMX6QDL_CLK_PWM3]         = imx_clk_gate2("pwm3",          "ipg_per",           base + 0x78, 20);
-       clk[IMX6QDL_CLK_PWM4]         = imx_clk_gate2("pwm4",          "ipg_per",           base + 0x78, 22);
-       clk[IMX6QDL_CLK_GPMI_BCH_APB] = imx_clk_gate2("gpmi_bch_apb",  "usdhc3",            base + 0x78, 24);
-       clk[IMX6QDL_CLK_GPMI_BCH]     = imx_clk_gate2("gpmi_bch",      "usdhc4",            base + 0x78, 26);
-       clk[IMX6QDL_CLK_GPMI_IO]      = imx_clk_gate2("gpmi_io",       "enfc",              base + 0x78, 28);
-       clk[IMX6QDL_CLK_GPMI_APB]     = imx_clk_gate2("gpmi_apb",      "usdhc3",            base + 0x78, 30);
-       clk[IMX6QDL_CLK_ROM]          = imx_clk_gate2_flags("rom",     "ahb",               base + 0x7c, 0, CLK_IS_CRITICAL);
-       clk[IMX6QDL_CLK_SATA]         = imx_clk_gate2("sata",          "ahb",               base + 0x7c, 4);
-       clk[IMX6QDL_CLK_SDMA]         = imx_clk_gate2("sdma",          "ahb",               base + 0x7c, 6);
-       clk[IMX6QDL_CLK_SPBA]         = imx_clk_gate2("spba",          "ipg",               base + 0x7c, 12);
-       clk[IMX6QDL_CLK_SPDIF]        = imx_clk_gate2_shared("spdif",     "spdif_podf",     base + 0x7c, 14, &share_count_spdif);
-       clk[IMX6QDL_CLK_SPDIF_GCLK]   = imx_clk_gate2_shared("spdif_gclk", "ipg",           base + 0x7c, 14, &share_count_spdif);
-       clk[IMX6QDL_CLK_SSI1_IPG]     = imx_clk_gate2_shared("ssi1_ipg",      "ipg",        base + 0x7c, 18, &share_count_ssi1);
-       clk[IMX6QDL_CLK_SSI2_IPG]     = imx_clk_gate2_shared("ssi2_ipg",      "ipg",        base + 0x7c, 20, &share_count_ssi2);
-       clk[IMX6QDL_CLK_SSI3_IPG]     = imx_clk_gate2_shared("ssi3_ipg",      "ipg",        base + 0x7c, 22, &share_count_ssi3);
-       clk[IMX6QDL_CLK_SSI1]         = imx_clk_gate2_shared("ssi1",          "ssi1_podf",  base + 0x7c, 18, &share_count_ssi1);
-       clk[IMX6QDL_CLK_SSI2]         = imx_clk_gate2_shared("ssi2",          "ssi2_podf",  base + 0x7c, 20, &share_count_ssi2);
-       clk[IMX6QDL_CLK_SSI3]         = imx_clk_gate2_shared("ssi3",          "ssi3_podf",  base + 0x7c, 22, &share_count_ssi3);
-       clk[IMX6QDL_CLK_UART_IPG]     = imx_clk_gate2("uart_ipg",      "ipg",               base + 0x7c, 24);
-       clk[IMX6QDL_CLK_UART_SERIAL]  = imx_clk_gate2("uart_serial",   "uart_serial_podf",  base + 0x7c, 26);
-       clk[IMX6QDL_CLK_USBOH3]       = imx_clk_gate2("usboh3",        "ipg",               base + 0x80, 0);
-       clk[IMX6QDL_CLK_USDHC1]       = imx_clk_gate2("usdhc1",        "usdhc1_podf",       base + 0x80, 2);
-       clk[IMX6QDL_CLK_USDHC2]       = imx_clk_gate2("usdhc2",        "usdhc2_podf",       base + 0x80, 4);
-       clk[IMX6QDL_CLK_USDHC3]       = imx_clk_gate2("usdhc3",        "usdhc3_podf",       base + 0x80, 6);
-       clk[IMX6QDL_CLK_USDHC4]       = imx_clk_gate2("usdhc4",        "usdhc4_podf",       base + 0x80, 8);
-       clk[IMX6QDL_CLK_EIM_SLOW]     = imx_clk_gate2("eim_slow",      "eim_slow_podf",     base + 0x80, 10);
-       clk[IMX6QDL_CLK_VDO_AXI]      = imx_clk_gate2("vdo_axi",       "vdo_axi_sel",       base + 0x80, 12);
-       clk[IMX6QDL_CLK_VPU_AXI]      = imx_clk_gate2("vpu_axi",       "vpu_axi_podf",      base + 0x80, 14);
+               hws[IMX6QDL_CLK_MLB] = imx_clk_hw_gate2("mlb",            "axi",               base + 0x74, 18);
+       hws[IMX6QDL_CLK_MMDC_CH0_AXI] = imx_clk_hw_gate2_flags("mmdc_ch0_axi",  "mmdc_ch0_axi_podf", base + 0x74, 20, CLK_IS_CRITICAL);
+       hws[IMX6QDL_CLK_MMDC_CH1_AXI] = imx_clk_hw_gate2("mmdc_ch1_axi",  "mmdc_ch1_axi_podf", base + 0x74, 22);
+       hws[IMX6QDL_CLK_MMDC_P0_IPG]  = imx_clk_hw_gate2_flags("mmdc_p0_ipg",   "ipg",         base + 0x74, 24, CLK_IS_CRITICAL);
+       hws[IMX6QDL_CLK_OCRAM]        = imx_clk_hw_gate2("ocram",         "ahb",               base + 0x74, 28);
+       hws[IMX6QDL_CLK_OPENVG_AXI]   = imx_clk_hw_gate2("openvg_axi",    "axi",               base + 0x74, 30);
+       hws[IMX6QDL_CLK_PCIE_AXI]     = imx_clk_hw_gate2("pcie_axi",      "pcie_axi_sel",      base + 0x78, 0);
+       hws[IMX6QDL_CLK_PER1_BCH]     = imx_clk_hw_gate2("per1_bch",      "usdhc3",            base + 0x78, 12);
+       hws[IMX6QDL_CLK_PWM1]         = imx_clk_hw_gate2("pwm1",          "ipg_per",           base + 0x78, 16);
+       hws[IMX6QDL_CLK_PWM2]         = imx_clk_hw_gate2("pwm2",          "ipg_per",           base + 0x78, 18);
+       hws[IMX6QDL_CLK_PWM3]         = imx_clk_hw_gate2("pwm3",          "ipg_per",           base + 0x78, 20);
+       hws[IMX6QDL_CLK_PWM4]         = imx_clk_hw_gate2("pwm4",          "ipg_per",           base + 0x78, 22);
+       hws[IMX6QDL_CLK_GPMI_BCH_APB] = imx_clk_hw_gate2("gpmi_bch_apb",  "usdhc3",            base + 0x78, 24);
+       hws[IMX6QDL_CLK_GPMI_BCH]     = imx_clk_hw_gate2("gpmi_bch",      "usdhc4",            base + 0x78, 26);
+       hws[IMX6QDL_CLK_GPMI_IO]      = imx_clk_hw_gate2("gpmi_io",       "enfc",              base + 0x78, 28);
+       hws[IMX6QDL_CLK_GPMI_APB]     = imx_clk_hw_gate2("gpmi_apb",      "usdhc3",            base + 0x78, 30);
+       hws[IMX6QDL_CLK_ROM]          = imx_clk_hw_gate2_flags("rom",     "ahb",               base + 0x7c, 0, CLK_IS_CRITICAL);
+       hws[IMX6QDL_CLK_SATA]         = imx_clk_hw_gate2("sata",          "ahb",               base + 0x7c, 4);
+       hws[IMX6QDL_CLK_SDMA]         = imx_clk_hw_gate2("sdma",          "ahb",               base + 0x7c, 6);
+       hws[IMX6QDL_CLK_SPBA]         = imx_clk_hw_gate2("spba",          "ipg",               base + 0x7c, 12);
+       hws[IMX6QDL_CLK_SPDIF]        = imx_clk_hw_gate2_shared("spdif",     "spdif_podf",     base + 0x7c, 14, &share_count_spdif);
+       hws[IMX6QDL_CLK_SPDIF_GCLK]   = imx_clk_hw_gate2_shared("spdif_gclk", "ipg",           base + 0x7c, 14, &share_count_spdif);
+       hws[IMX6QDL_CLK_SSI1_IPG]     = imx_clk_hw_gate2_shared("ssi1_ipg",      "ipg",        base + 0x7c, 18, &share_count_ssi1);
+       hws[IMX6QDL_CLK_SSI2_IPG]     = imx_clk_hw_gate2_shared("ssi2_ipg",      "ipg",        base + 0x7c, 20, &share_count_ssi2);
+       hws[IMX6QDL_CLK_SSI3_IPG]     = imx_clk_hw_gate2_shared("ssi3_ipg",      "ipg",        base + 0x7c, 22, &share_count_ssi3);
+       hws[IMX6QDL_CLK_SSI1]         = imx_clk_hw_gate2_shared("ssi1",          "ssi1_podf",  base + 0x7c, 18, &share_count_ssi1);
+       hws[IMX6QDL_CLK_SSI2]         = imx_clk_hw_gate2_shared("ssi2",          "ssi2_podf",  base + 0x7c, 20, &share_count_ssi2);
+       hws[IMX6QDL_CLK_SSI3]         = imx_clk_hw_gate2_shared("ssi3",          "ssi3_podf",  base + 0x7c, 22, &share_count_ssi3);
+       hws[IMX6QDL_CLK_UART_IPG]     = imx_clk_hw_gate2("uart_ipg",      "ipg",               base + 0x7c, 24);
+       hws[IMX6QDL_CLK_UART_SERIAL]  = imx_clk_hw_gate2("uart_serial",   "uart_serial_podf",  base + 0x7c, 26);
+       hws[IMX6QDL_CLK_USBOH3]       = imx_clk_hw_gate2("usboh3",        "ipg",               base + 0x80, 0);
+       hws[IMX6QDL_CLK_USDHC1]       = imx_clk_hw_gate2("usdhc1",        "usdhc1_podf",       base + 0x80, 2);
+       hws[IMX6QDL_CLK_USDHC2]       = imx_clk_hw_gate2("usdhc2",        "usdhc2_podf",       base + 0x80, 4);
+       hws[IMX6QDL_CLK_USDHC3]       = imx_clk_hw_gate2("usdhc3",        "usdhc3_podf",       base + 0x80, 6);
+       hws[IMX6QDL_CLK_USDHC4]       = imx_clk_hw_gate2("usdhc4",        "usdhc4_podf",       base + 0x80, 8);
+       hws[IMX6QDL_CLK_EIM_SLOW]     = imx_clk_hw_gate2("eim_slow",      "eim_slow_podf",     base + 0x80, 10);
+       hws[IMX6QDL_CLK_VDO_AXI]      = imx_clk_hw_gate2("vdo_axi",       "vdo_axi_sel",       base + 0x80, 12);
+       hws[IMX6QDL_CLK_VPU_AXI]      = imx_clk_hw_gate2("vpu_axi",       "vpu_axi_podf",      base + 0x80, 14);
        if (clk_on_imx6qp()) {
-               clk[IMX6QDL_CLK_PRE0] = imx_clk_gate2("pre0",          "pre_axi",           base + 0x80, 16);
-               clk[IMX6QDL_CLK_PRE1] = imx_clk_gate2("pre1",          "pre_axi",           base + 0x80, 18);
-               clk[IMX6QDL_CLK_PRE2] = imx_clk_gate2("pre2",          "pre_axi",         base + 0x80, 20);
-               clk[IMX6QDL_CLK_PRE3] = imx_clk_gate2("pre3",          "pre_axi",           base + 0x80, 22);
-               clk[IMX6QDL_CLK_PRG0_AXI] = imx_clk_gate2_shared("prg0_axi",  "ipu1_podf",  base + 0x80, 24, &share_count_prg0);
-               clk[IMX6QDL_CLK_PRG1_AXI] = imx_clk_gate2_shared("prg1_axi",  "ipu2_podf",  base + 0x80, 26, &share_count_prg1);
-               clk[IMX6QDL_CLK_PRG0_APB] = imx_clk_gate2_shared("prg0_apb",  "ipg",        base + 0x80, 24, &share_count_prg0);
-               clk[IMX6QDL_CLK_PRG1_APB] = imx_clk_gate2_shared("prg1_apb",  "ipg",        base + 0x80, 26, &share_count_prg1);
+               hws[IMX6QDL_CLK_PRE0] = imx_clk_hw_gate2("pre0",               "pre_axi",           base + 0x80, 16);
+               hws[IMX6QDL_CLK_PRE1] = imx_clk_hw_gate2("pre1",               "pre_axi",           base + 0x80, 18);
+               hws[IMX6QDL_CLK_PRE2] = imx_clk_hw_gate2("pre2",               "pre_axi",         base + 0x80, 20);
+               hws[IMX6QDL_CLK_PRE3] = imx_clk_hw_gate2("pre3",               "pre_axi",           base + 0x80, 22);
+               hws[IMX6QDL_CLK_PRG0_AXI] = imx_clk_hw_gate2_shared("prg0_axi",  "ipu1_podf",  base + 0x80, 24, &share_count_prg0);
+               hws[IMX6QDL_CLK_PRG1_AXI] = imx_clk_hw_gate2_shared("prg1_axi",  "ipu2_podf",  base + 0x80, 26, &share_count_prg1);
+               hws[IMX6QDL_CLK_PRG0_APB] = imx_clk_hw_gate2_shared("prg0_apb",  "ipg",     base + 0x80, 24, &share_count_prg0);
+               hws[IMX6QDL_CLK_PRG1_APB] = imx_clk_hw_gate2_shared("prg1_apb",  "ipg",     base + 0x80, 26, &share_count_prg1);
        }
-       clk[IMX6QDL_CLK_CKO1]         = imx_clk_gate("cko1",           "cko1_podf",         base + 0x60, 7);
-       clk[IMX6QDL_CLK_CKO2]         = imx_clk_gate("cko2",           "cko2_podf",         base + 0x60, 24);
+       hws[IMX6QDL_CLK_CKO1]         = imx_clk_hw_gate("cko1",           "cko1_podf",         base + 0x60, 7);
+       hws[IMX6QDL_CLK_CKO2]         = imx_clk_hw_gate("cko2",           "cko2_podf",         base + 0x60, 24);
 
        /*
         * The gpt_3m clock is not available on i.MX6Q TO1.0.  Let's point it
         * to clock gpt_ipg_per to ease the gpt driver code.
         */
        if (clk_on_imx6q() && imx_get_soc_revision() == IMX_CHIP_REVISION_1_0)
-               clk[IMX6QDL_CLK_GPT_3M] = clk[IMX6QDL_CLK_GPT_IPG_PER];
+               hws[IMX6QDL_CLK_GPT_3M] = hws[IMX6QDL_CLK_GPT_IPG_PER];
 
-       imx_check_clocks(clk, ARRAY_SIZE(clk));
+       imx_check_clk_hws(hws, IMX6QDL_CLK_END);
 
-       clk_data.clks = clk;
-       clk_data.clk_num = ARRAY_SIZE(clk);
-       of_clk_add_provider(np, of_clk_src_onecell_get, &clk_data);
+       of_clk_add_hw_provider(np, of_clk_hw_onecell_get, clk_hw_data);
 
-       clk_register_clkdev(clk[IMX6QDL_CLK_ENET_REF], "enet_ref", NULL);
+       clk_hw_register_clkdev(hws[IMX6QDL_CLK_ENET_REF], "enet_ref", NULL);
 
-       clk_set_rate(clk[IMX6QDL_CLK_PLL3_PFD1_540M], 540000000);
+       clk_set_rate(hws[IMX6QDL_CLK_PLL3_PFD1_540M]->clk, 540000000);
        if (clk_on_imx6dl())
-               clk_set_parent(clk[IMX6QDL_CLK_IPU1_SEL], clk[IMX6QDL_CLK_PLL3_PFD1_540M]);
+               clk_set_parent(hws[IMX6QDL_CLK_IPU1_SEL]->clk, hws[IMX6QDL_CLK_PLL3_PFD1_540M]->clk);
 
-       clk_set_parent(clk[IMX6QDL_CLK_IPU1_DI0_PRE_SEL], clk[IMX6QDL_CLK_PLL5_VIDEO_DIV]);
-       clk_set_parent(clk[IMX6QDL_CLK_IPU1_DI1_PRE_SEL], clk[IMX6QDL_CLK_PLL5_VIDEO_DIV]);
-       clk_set_parent(clk[IMX6QDL_CLK_IPU2_DI0_PRE_SEL], clk[IMX6QDL_CLK_PLL5_VIDEO_DIV]);
-       clk_set_parent(clk[IMX6QDL_CLK_IPU2_DI1_PRE_SEL], clk[IMX6QDL_CLK_PLL5_VIDEO_DIV]);
-       clk_set_parent(clk[IMX6QDL_CLK_IPU1_DI0_SEL], clk[IMX6QDL_CLK_IPU1_DI0_PRE]);
-       clk_set_parent(clk[IMX6QDL_CLK_IPU1_DI1_SEL], clk[IMX6QDL_CLK_IPU1_DI1_PRE]);
-       clk_set_parent(clk[IMX6QDL_CLK_IPU2_DI0_SEL], clk[IMX6QDL_CLK_IPU2_DI0_PRE]);
-       clk_set_parent(clk[IMX6QDL_CLK_IPU2_DI1_SEL], clk[IMX6QDL_CLK_IPU2_DI1_PRE]);
+       clk_set_parent(hws[IMX6QDL_CLK_IPU1_DI0_PRE_SEL]->clk, hws[IMX6QDL_CLK_PLL5_VIDEO_DIV]->clk);
+       clk_set_parent(hws[IMX6QDL_CLK_IPU1_DI1_PRE_SEL]->clk, hws[IMX6QDL_CLK_PLL5_VIDEO_DIV]->clk);
+       clk_set_parent(hws[IMX6QDL_CLK_IPU2_DI0_PRE_SEL]->clk, hws[IMX6QDL_CLK_PLL5_VIDEO_DIV]->clk);
+       clk_set_parent(hws[IMX6QDL_CLK_IPU2_DI1_PRE_SEL]->clk, hws[IMX6QDL_CLK_PLL5_VIDEO_DIV]->clk);
+       clk_set_parent(hws[IMX6QDL_CLK_IPU1_DI0_SEL]->clk, hws[IMX6QDL_CLK_IPU1_DI0_PRE]->clk);
+       clk_set_parent(hws[IMX6QDL_CLK_IPU1_DI1_SEL]->clk, hws[IMX6QDL_CLK_IPU1_DI1_PRE]->clk);
+       clk_set_parent(hws[IMX6QDL_CLK_IPU2_DI0_SEL]->clk, hws[IMX6QDL_CLK_IPU2_DI0_PRE]->clk);
+       clk_set_parent(hws[IMX6QDL_CLK_IPU2_DI1_SEL]->clk, hws[IMX6QDL_CLK_IPU2_DI1_PRE]->clk);
 
        /*
         * The gpmi needs 100MHz frequency in the EDO/Sync mode,
         * We can not get the 100MHz from the pll2_pfd0_352m.
         * So choose pll2_pfd2_396m as enfc_sel's parent.
         */
-       clk_set_parent(clk[IMX6QDL_CLK_ENFC_SEL], clk[IMX6QDL_CLK_PLL2_PFD2_396M]);
+       clk_set_parent(hws[IMX6QDL_CLK_ENFC_SEL]->clk, hws[IMX6QDL_CLK_PLL2_PFD2_396M]->clk);
 
        if (IS_ENABLED(CONFIG_USB_MXS_PHY)) {
-               clk_prepare_enable(clk[IMX6QDL_CLK_USBPHY1_GATE]);
-               clk_prepare_enable(clk[IMX6QDL_CLK_USBPHY2_GATE]);
+               clk_prepare_enable(hws[IMX6QDL_CLK_USBPHY1_GATE]->clk);
+               clk_prepare_enable(hws[IMX6QDL_CLK_USBPHY2_GATE]->clk);
        }
 
        /*
         * Let's initially set up CLKO with OSC24M, since this configuration
         * is widely used by imx6q board designs to clock audio codec.
         */
-       ret = clk_set_parent(clk[IMX6QDL_CLK_CKO2_SEL], clk[IMX6QDL_CLK_OSC]);
+       ret = clk_set_parent(hws[IMX6QDL_CLK_CKO2_SEL]->clk, hws[IMX6QDL_CLK_OSC]->clk);
        if (!ret)
-               ret = clk_set_parent(clk[IMX6QDL_CLK_CKO], clk[IMX6QDL_CLK_CKO2]);
+               ret = clk_set_parent(hws[IMX6QDL_CLK_CKO]->clk, hws[IMX6QDL_CLK_CKO2]->clk);
        if (ret)
                pr_warn("failed to set up CLKO: %d\n", ret);
 
        /* Audio-related clocks configuration */
-       clk_set_parent(clk[IMX6QDL_CLK_SPDIF_SEL], clk[IMX6QDL_CLK_PLL3_PFD3_454M]);
+       clk_set_parent(hws[IMX6QDL_CLK_SPDIF_SEL]->clk, hws[IMX6QDL_CLK_PLL3_PFD3_454M]->clk);
 
        /* All existing boards with PCIe use LVDS1 */
        if (IS_ENABLED(CONFIG_PCI_IMX6))
-               clk_set_parent(clk[IMX6QDL_CLK_LVDS1_SEL], clk[IMX6QDL_CLK_SATA_REF_100M]);
+               clk_set_parent(hws[IMX6QDL_CLK_LVDS1_SEL]->clk, hws[IMX6QDL_CLK_SATA_REF_100M]->clk);
 
        /*
         * Initialize the GPU clock muxes, so that the maximum specified clock
         * rates for the respective SoC are not exceeded.
         */
        if (clk_on_imx6dl()) {
-               clk_set_parent(clk[IMX6QDL_CLK_GPU3D_CORE_SEL],
-                              clk[IMX6QDL_CLK_PLL2_PFD1_594M]);
-               clk_set_parent(clk[IMX6QDL_CLK_GPU2D_CORE_SEL],
-                              clk[IMX6QDL_CLK_PLL2_PFD1_594M]);
+               clk_set_parent(hws[IMX6QDL_CLK_GPU3D_CORE_SEL]->clk,
+                              hws[IMX6QDL_CLK_PLL2_PFD1_594M]->clk);
+               clk_set_parent(hws[IMX6QDL_CLK_GPU2D_CORE_SEL]->clk,
+                              hws[IMX6QDL_CLK_PLL2_PFD1_594M]->clk);
        } else if (clk_on_imx6q()) {
-               clk_set_parent(clk[IMX6QDL_CLK_GPU3D_CORE_SEL],
-                              clk[IMX6QDL_CLK_MMDC_CH0_AXI]);
-               clk_set_parent(clk[IMX6QDL_CLK_GPU3D_SHADER_SEL],
-                              clk[IMX6QDL_CLK_PLL2_PFD1_594M]);
-               clk_set_parent(clk[IMX6QDL_CLK_GPU2D_CORE_SEL],
-                              clk[IMX6QDL_CLK_PLL3_USB_OTG]);
+               clk_set_parent(hws[IMX6QDL_CLK_GPU3D_CORE_SEL]->clk,
+                              hws[IMX6QDL_CLK_MMDC_CH0_AXI]->clk);
+               clk_set_parent(hws[IMX6QDL_CLK_GPU3D_SHADER_SEL]->clk,
+                              hws[IMX6QDL_CLK_PLL2_PFD1_594M]->clk);
+               clk_set_parent(hws[IMX6QDL_CLK_GPU2D_CORE_SEL]->clk,
+                              hws[IMX6QDL_CLK_PLL3_USB_OTG]->clk);
+       }
+
+       for (i = 0; i < ARRAY_SIZE(uart_clk_ids); i++) {
+               int index = uart_clk_ids[i];
+
+               uart_clks[i] = &hws[index]->clk;
        }
 
        imx_register_uart_clocks(uart_clks);
index f9f1f8a..4bd44d8 100644 (file)
@@ -13,8 +13,6 @@
 
 #include "clk.h"
 
-#define CCDR                           0x4
-#define BM_CCM_CCDR_MMDC_CH0_MASK      (1 << 17)
 #define CCSR                   0xc
 #define BM_CCSR_PLL1_SW_CLK_SEL        (1 << 2)
 #define CACRR                  0x10
@@ -97,8 +95,8 @@ static unsigned int share_count_ssi2;
 static unsigned int share_count_ssi3;
 static unsigned int share_count_spdif;
 
-static struct clk *clks[IMX6SL_CLK_END];
-static struct clk_onecell_data clk_data;
+static struct clk_hw **hws;
+static struct clk_hw_onecell_data *clk_hw_data;
 static void __iomem *ccm_base;
 static void __iomem *anatop_base;
 
@@ -179,74 +177,84 @@ void imx6sl_set_wait_clk(bool enter)
                imx6sl_enable_pll_arm(false);
 }
 
-static struct clk ** const uart_clks[] __initconst = {
-       &clks[IMX6SL_CLK_UART],
-       &clks[IMX6SL_CLK_UART_SERIAL],
-       NULL
+static const int uart_clk_ids[] __initconst = {
+       IMX6SL_CLK_UART,
+       IMX6SL_CLK_UART_SERIAL,
 };
 
+static struct clk **uart_clks[ARRAY_SIZE(uart_clk_ids) + 1] __initdata;
+
 static void __init imx6sl_clocks_init(struct device_node *ccm_node)
 {
        struct device_node *np;
        void __iomem *base;
        int ret;
+       int i;
+
+       clk_hw_data = kzalloc(struct_size(clk_hw_data, hws,
+                                         IMX6SL_CLK_END), GFP_KERNEL);
+       if (WARN_ON(!clk_hw_data))
+               return;
+
+       clk_hw_data->num = IMX6SL_CLK_END;
+       hws = clk_hw_data->hws;
 
-       clks[IMX6SL_CLK_DUMMY] = imx_clk_fixed("dummy", 0);
-       clks[IMX6SL_CLK_CKIL] = imx_obtain_fixed_clock("ckil", 0);
-       clks[IMX6SL_CLK_OSC] = imx_obtain_fixed_clock("osc", 0);
+       hws[IMX6SL_CLK_DUMMY] = imx_clk_hw_fixed("dummy", 0);
+       hws[IMX6SL_CLK_CKIL] = imx_obtain_fixed_clock_hw("ckil", 0);
+       hws[IMX6SL_CLK_OSC] = imx_obtain_fixed_clock_hw("osc", 0);
        /* Clock source from external clock via CLK1 PAD */
-       clks[IMX6SL_CLK_ANACLK1] = imx_obtain_fixed_clock("anaclk1", 0);
+       hws[IMX6SL_CLK_ANACLK1] = imx_obtain_fixed_clock_hw("anaclk1", 0);
 
        np = of_find_compatible_node(NULL, NULL, "fsl,imx6sl-anatop");
        base = of_iomap(np, 0);
        WARN_ON(!base);
        anatop_base = base;
 
-       clks[IMX6SL_PLL1_BYPASS_SRC] = imx_clk_mux("pll1_bypass_src", base + 0x00, 14, 1, pll_bypass_src_sels, ARRAY_SIZE(pll_bypass_src_sels));
-       clks[IMX6SL_PLL2_BYPASS_SRC] = imx_clk_mux("pll2_bypass_src", base + 0x30, 14, 1, pll_bypass_src_sels, ARRAY_SIZE(pll_bypass_src_sels));
-       clks[IMX6SL_PLL3_BYPASS_SRC] = imx_clk_mux("pll3_bypass_src", base + 0x10, 14, 1, pll_bypass_src_sels, ARRAY_SIZE(pll_bypass_src_sels));
-       clks[IMX6SL_PLL4_BYPASS_SRC] = imx_clk_mux("pll4_bypass_src", base + 0x70, 14, 1, pll_bypass_src_sels, ARRAY_SIZE(pll_bypass_src_sels));
-       clks[IMX6SL_PLL5_BYPASS_SRC] = imx_clk_mux("pll5_bypass_src", base + 0xa0, 14, 1, pll_bypass_src_sels, ARRAY_SIZE(pll_bypass_src_sels));
-       clks[IMX6SL_PLL6_BYPASS_SRC] = imx_clk_mux("pll6_bypass_src", base + 0xe0, 14, 1, pll_bypass_src_sels, ARRAY_SIZE(pll_bypass_src_sels));
-       clks[IMX6SL_PLL7_BYPASS_SRC] = imx_clk_mux("pll7_bypass_src", base + 0x20, 14, 1, pll_bypass_src_sels, ARRAY_SIZE(pll_bypass_src_sels));
+       hws[IMX6SL_PLL1_BYPASS_SRC] = imx_clk_hw_mux("pll1_bypass_src", base + 0x00, 14, 1, pll_bypass_src_sels, ARRAY_SIZE(pll_bypass_src_sels));
+       hws[IMX6SL_PLL2_BYPASS_SRC] = imx_clk_hw_mux("pll2_bypass_src", base + 0x30, 14, 1, pll_bypass_src_sels, ARRAY_SIZE(pll_bypass_src_sels));
+       hws[IMX6SL_PLL3_BYPASS_SRC] = imx_clk_hw_mux("pll3_bypass_src", base + 0x10, 14, 1, pll_bypass_src_sels, ARRAY_SIZE(pll_bypass_src_sels));
+       hws[IMX6SL_PLL4_BYPASS_SRC] = imx_clk_hw_mux("pll4_bypass_src", base + 0x70, 14, 1, pll_bypass_src_sels, ARRAY_SIZE(pll_bypass_src_sels));
+       hws[IMX6SL_PLL5_BYPASS_SRC] = imx_clk_hw_mux("pll5_bypass_src", base + 0xa0, 14, 1, pll_bypass_src_sels, ARRAY_SIZE(pll_bypass_src_sels));
+       hws[IMX6SL_PLL6_BYPASS_SRC] = imx_clk_hw_mux("pll6_bypass_src", base + 0xe0, 14, 1, pll_bypass_src_sels, ARRAY_SIZE(pll_bypass_src_sels));
+       hws[IMX6SL_PLL7_BYPASS_SRC] = imx_clk_hw_mux("pll7_bypass_src", base + 0x20, 14, 1, pll_bypass_src_sels, ARRAY_SIZE(pll_bypass_src_sels));
 
        /*                                    type               name    parent_name        base         div_mask */
-       clks[IMX6SL_CLK_PLL1] = imx_clk_pllv3(IMX_PLLV3_SYS,     "pll1", "osc", base + 0x00, 0x7f);
-       clks[IMX6SL_CLK_PLL2] = imx_clk_pllv3(IMX_PLLV3_GENERIC, "pll2", "osc", base + 0x30, 0x1);
-       clks[IMX6SL_CLK_PLL3] = imx_clk_pllv3(IMX_PLLV3_USB,     "pll3", "osc", base + 0x10, 0x3);
-       clks[IMX6SL_CLK_PLL4] = imx_clk_pllv3(IMX_PLLV3_AV,      "pll4", "osc", base + 0x70, 0x7f);
-       clks[IMX6SL_CLK_PLL5] = imx_clk_pllv3(IMX_PLLV3_AV,      "pll5", "osc", base + 0xa0, 0x7f);
-       clks[IMX6SL_CLK_PLL6] = imx_clk_pllv3(IMX_PLLV3_ENET,    "pll6", "osc", base + 0xe0, 0x3);
-       clks[IMX6SL_CLK_PLL7] = imx_clk_pllv3(IMX_PLLV3_USB,     "pll7", "osc", base + 0x20, 0x3);
-
-       clks[IMX6SL_PLL1_BYPASS] = imx_clk_mux_flags("pll1_bypass", base + 0x00, 16, 1, pll1_bypass_sels, ARRAY_SIZE(pll1_bypass_sels), CLK_SET_RATE_PARENT);
-       clks[IMX6SL_PLL2_BYPASS] = imx_clk_mux_flags("pll2_bypass", base + 0x30, 16, 1, pll2_bypass_sels, ARRAY_SIZE(pll2_bypass_sels), CLK_SET_RATE_PARENT);
-       clks[IMX6SL_PLL3_BYPASS] = imx_clk_mux_flags("pll3_bypass", base + 0x10, 16, 1, pll3_bypass_sels, ARRAY_SIZE(pll3_bypass_sels), CLK_SET_RATE_PARENT);
-       clks[IMX6SL_PLL4_BYPASS] = imx_clk_mux_flags("pll4_bypass", base + 0x70, 16, 1, pll4_bypass_sels, ARRAY_SIZE(pll4_bypass_sels), CLK_SET_RATE_PARENT);
-       clks[IMX6SL_PLL5_BYPASS] = imx_clk_mux_flags("pll5_bypass", base + 0xa0, 16, 1, pll5_bypass_sels, ARRAY_SIZE(pll5_bypass_sels), CLK_SET_RATE_PARENT);
-       clks[IMX6SL_PLL6_BYPASS] = imx_clk_mux_flags("pll6_bypass", base + 0xe0, 16, 1, pll6_bypass_sels, ARRAY_SIZE(pll6_bypass_sels), CLK_SET_RATE_PARENT);
-       clks[IMX6SL_PLL7_BYPASS] = imx_clk_mux_flags("pll7_bypass", base + 0x20, 16, 1, pll7_bypass_sels, ARRAY_SIZE(pll7_bypass_sels), CLK_SET_RATE_PARENT);
+       hws[IMX6SL_CLK_PLL1] = imx_clk_hw_pllv3(IMX_PLLV3_SYS,     "pll1", "osc", base + 0x00, 0x7f);
+       hws[IMX6SL_CLK_PLL2] = imx_clk_hw_pllv3(IMX_PLLV3_GENERIC, "pll2", "osc", base + 0x30, 0x1);
+       hws[IMX6SL_CLK_PLL3] = imx_clk_hw_pllv3(IMX_PLLV3_USB,     "pll3", "osc", base + 0x10, 0x3);
+       hws[IMX6SL_CLK_PLL4] = imx_clk_hw_pllv3(IMX_PLLV3_AV,      "pll4", "osc", base + 0x70, 0x7f);
+       hws[IMX6SL_CLK_PLL5] = imx_clk_hw_pllv3(IMX_PLLV3_AV,      "pll5", "osc", base + 0xa0, 0x7f);
+       hws[IMX6SL_CLK_PLL6] = imx_clk_hw_pllv3(IMX_PLLV3_ENET,    "pll6", "osc", base + 0xe0, 0x3);
+       hws[IMX6SL_CLK_PLL7] = imx_clk_hw_pllv3(IMX_PLLV3_USB,     "pll7", "osc", base + 0x20, 0x3);
+
+       hws[IMX6SL_PLL1_BYPASS] = imx_clk_hw_mux_flags("pll1_bypass", base + 0x00, 16, 1, pll1_bypass_sels, ARRAY_SIZE(pll1_bypass_sels), CLK_SET_RATE_PARENT);
+       hws[IMX6SL_PLL2_BYPASS] = imx_clk_hw_mux_flags("pll2_bypass", base + 0x30, 16, 1, pll2_bypass_sels, ARRAY_SIZE(pll2_bypass_sels), CLK_SET_RATE_PARENT);
+       hws[IMX6SL_PLL3_BYPASS] = imx_clk_hw_mux_flags("pll3_bypass", base + 0x10, 16, 1, pll3_bypass_sels, ARRAY_SIZE(pll3_bypass_sels), CLK_SET_RATE_PARENT);
+       hws[IMX6SL_PLL4_BYPASS] = imx_clk_hw_mux_flags("pll4_bypass", base + 0x70, 16, 1, pll4_bypass_sels, ARRAY_SIZE(pll4_bypass_sels), CLK_SET_RATE_PARENT);
+       hws[IMX6SL_PLL5_BYPASS] = imx_clk_hw_mux_flags("pll5_bypass", base + 0xa0, 16, 1, pll5_bypass_sels, ARRAY_SIZE(pll5_bypass_sels), CLK_SET_RATE_PARENT);
+       hws[IMX6SL_PLL6_BYPASS] = imx_clk_hw_mux_flags("pll6_bypass", base + 0xe0, 16, 1, pll6_bypass_sels, ARRAY_SIZE(pll6_bypass_sels), CLK_SET_RATE_PARENT);
+       hws[IMX6SL_PLL7_BYPASS] = imx_clk_hw_mux_flags("pll7_bypass", base + 0x20, 16, 1, pll7_bypass_sels, ARRAY_SIZE(pll7_bypass_sels), CLK_SET_RATE_PARENT);
 
        /* Do not bypass PLLs initially */
-       clk_set_parent(clks[IMX6SL_PLL1_BYPASS], clks[IMX6SL_CLK_PLL1]);
-       clk_set_parent(clks[IMX6SL_PLL2_BYPASS], clks[IMX6SL_CLK_PLL2]);
-       clk_set_parent(clks[IMX6SL_PLL3_BYPASS], clks[IMX6SL_CLK_PLL3]);
-       clk_set_parent(clks[IMX6SL_PLL4_BYPASS], clks[IMX6SL_CLK_PLL4]);
-       clk_set_parent(clks[IMX6SL_PLL5_BYPASS], clks[IMX6SL_CLK_PLL5]);
-       clk_set_parent(clks[IMX6SL_PLL6_BYPASS], clks[IMX6SL_CLK_PLL6]);
-       clk_set_parent(clks[IMX6SL_PLL7_BYPASS], clks[IMX6SL_CLK_PLL7]);
-
-       clks[IMX6SL_CLK_PLL1_SYS]      = imx_clk_gate("pll1_sys",      "pll1_bypass", base + 0x00, 13);
-       clks[IMX6SL_CLK_PLL2_BUS]      = imx_clk_gate("pll2_bus",      "pll2_bypass", base + 0x30, 13);
-       clks[IMX6SL_CLK_PLL3_USB_OTG]  = imx_clk_gate("pll3_usb_otg",  "pll3_bypass", base + 0x10, 13);
-       clks[IMX6SL_CLK_PLL4_AUDIO]    = imx_clk_gate("pll4_audio",    "pll4_bypass", base + 0x70, 13);
-       clks[IMX6SL_CLK_PLL5_VIDEO]    = imx_clk_gate("pll5_video",    "pll5_bypass", base + 0xa0, 13);
-       clks[IMX6SL_CLK_PLL6_ENET]     = imx_clk_gate("pll6_enet",     "pll6_bypass", base + 0xe0, 13);
-       clks[IMX6SL_CLK_PLL7_USB_HOST] = imx_clk_gate("pll7_usb_host", "pll7_bypass", base + 0x20, 13);
-
-       clks[IMX6SL_CLK_LVDS1_SEL] = imx_clk_mux("lvds1_sel", base + 0x160, 0, 5, lvds_sels, ARRAY_SIZE(lvds_sels));
-       clks[IMX6SL_CLK_LVDS1_OUT] = imx_clk_gate_exclusive("lvds1_out", "lvds1_sel", base + 0x160, 10, BIT(12));
-       clks[IMX6SL_CLK_LVDS1_IN] = imx_clk_gate_exclusive("lvds1_in", "anaclk1", base + 0x160, 12, BIT(10));
+       clk_set_parent(hws[IMX6SL_PLL1_BYPASS]->clk, hws[IMX6SL_CLK_PLL1]->clk);
+       clk_set_parent(hws[IMX6SL_PLL2_BYPASS]->clk, hws[IMX6SL_CLK_PLL2]->clk);
+       clk_set_parent(hws[IMX6SL_PLL3_BYPASS]->clk, hws[IMX6SL_CLK_PLL3]->clk);
+       clk_set_parent(hws[IMX6SL_PLL4_BYPASS]->clk, hws[IMX6SL_CLK_PLL4]->clk);
+       clk_set_parent(hws[IMX6SL_PLL5_BYPASS]->clk, hws[IMX6SL_CLK_PLL5]->clk);
+       clk_set_parent(hws[IMX6SL_PLL6_BYPASS]->clk, hws[IMX6SL_CLK_PLL6]->clk);
+       clk_set_parent(hws[IMX6SL_PLL7_BYPASS]->clk, hws[IMX6SL_CLK_PLL7]->clk);
+
+       hws[IMX6SL_CLK_PLL1_SYS]      = imx_clk_hw_gate("pll1_sys",      "pll1_bypass", base + 0x00, 13);
+       hws[IMX6SL_CLK_PLL2_BUS]      = imx_clk_hw_gate("pll2_bus",      "pll2_bypass", base + 0x30, 13);
+       hws[IMX6SL_CLK_PLL3_USB_OTG]  = imx_clk_hw_gate("pll3_usb_otg",  "pll3_bypass", base + 0x10, 13);
+       hws[IMX6SL_CLK_PLL4_AUDIO]    = imx_clk_hw_gate("pll4_audio",    "pll4_bypass", base + 0x70, 13);
+       hws[IMX6SL_CLK_PLL5_VIDEO]    = imx_clk_hw_gate("pll5_video",    "pll5_bypass", base + 0xa0, 13);
+       hws[IMX6SL_CLK_PLL6_ENET]     = imx_clk_hw_gate("pll6_enet",     "pll6_bypass", base + 0xe0, 13);
+       hws[IMX6SL_CLK_PLL7_USB_HOST] = imx_clk_hw_gate("pll7_usb_host", "pll7_bypass", base + 0x20, 13);
+
+       hws[IMX6SL_CLK_LVDS1_SEL] = imx_clk_hw_mux("lvds1_sel", base + 0x160, 0, 5, lvds_sels, ARRAY_SIZE(lvds_sels));
+       hws[IMX6SL_CLK_LVDS1_OUT] = imx_clk_hw_gate_exclusive("lvds1_out", "lvds1_sel", base + 0x160, 10, BIT(12));
+       hws[IMX6SL_CLK_LVDS1_IN] = imx_clk_hw_gate_exclusive("lvds1_in", "anaclk1", base + 0x160, 12, BIT(10));
 
        /*
         * usbphy1 and usbphy2 are implemented as dummy gates using reserve
@@ -255,32 +263,32 @@ static void __init imx6sl_clocks_init(struct device_node *ccm_node)
         * turned on during boot, and software will not need to control it
         * anymore after that.
         */
-       clks[IMX6SL_CLK_USBPHY1]      = imx_clk_gate("usbphy1",      "pll3_usb_otg",  base + 0x10, 20);
-       clks[IMX6SL_CLK_USBPHY2]      = imx_clk_gate("usbphy2",      "pll7_usb_host", base + 0x20, 20);
-       clks[IMX6SL_CLK_USBPHY1_GATE] = imx_clk_gate("usbphy1_gate", "dummy",         base + 0x10, 6);
-       clks[IMX6SL_CLK_USBPHY2_GATE] = imx_clk_gate("usbphy2_gate", "dummy",         base + 0x20, 6);
+       hws[IMX6SL_CLK_USBPHY1]      = imx_clk_hw_gate("usbphy1",      "pll3_usb_otg",  base + 0x10, 20);
+       hws[IMX6SL_CLK_USBPHY2]      = imx_clk_hw_gate("usbphy2",      "pll7_usb_host", base + 0x20, 20);
+       hws[IMX6SL_CLK_USBPHY1_GATE] = imx_clk_hw_gate("usbphy1_gate", "dummy",         base + 0x10, 6);
+       hws[IMX6SL_CLK_USBPHY2_GATE] = imx_clk_hw_gate("usbphy2_gate", "dummy",         base + 0x20, 6);
 
        /*                                                           dev   name              parent_name      flags                reg        shift width div: flags, div_table lock */
-       clks[IMX6SL_CLK_PLL4_POST_DIV]  = clk_register_divider_table(NULL, "pll4_post_div",  "pll4_audio",    CLK_SET_RATE_PARENT, base + 0x70,  19, 2,   0, post_div_table, &imx_ccm_lock);
-       clks[IMX6SL_CLK_PLL4_AUDIO_DIV] =       clk_register_divider(NULL, "pll4_audio_div", "pll4_post_div", CLK_SET_RATE_PARENT, base + 0x170, 15, 1,   0, &imx_ccm_lock);
-       clks[IMX6SL_CLK_PLL5_POST_DIV]  = clk_register_divider_table(NULL, "pll5_post_div",  "pll5_video",    CLK_SET_RATE_PARENT, base + 0xa0,  19, 2,   0, post_div_table, &imx_ccm_lock);
-       clks[IMX6SL_CLK_PLL5_VIDEO_DIV] = clk_register_divider_table(NULL, "pll5_video_div", "pll5_post_div", CLK_SET_RATE_PARENT, base + 0x170, 30, 2,   0, video_div_table, &imx_ccm_lock);
-       clks[IMX6SL_CLK_ENET_REF]       = clk_register_divider_table(NULL, "enet_ref",       "pll6_enet",     0,                   base + 0xe0,  0,  2,   0, clk_enet_ref_table, &imx_ccm_lock);
+       hws[IMX6SL_CLK_PLL4_POST_DIV]  = clk_hw_register_divider_table(NULL, "pll4_post_div",  "pll4_audio",    CLK_SET_RATE_PARENT, base + 0x70,  19, 2,   0, post_div_table, &imx_ccm_lock);
+       hws[IMX6SL_CLK_PLL4_AUDIO_DIV] =       clk_hw_register_divider(NULL, "pll4_audio_div", "pll4_post_div", CLK_SET_RATE_PARENT, base + 0x170, 15, 1,   0, &imx_ccm_lock);
+       hws[IMX6SL_CLK_PLL5_POST_DIV]  = clk_hw_register_divider_table(NULL, "pll5_post_div",  "pll5_video",    CLK_SET_RATE_PARENT, base + 0xa0,  19, 2,   0, post_div_table, &imx_ccm_lock);
+       hws[IMX6SL_CLK_PLL5_VIDEO_DIV] = clk_hw_register_divider_table(NULL, "pll5_video_div", "pll5_post_div", CLK_SET_RATE_PARENT, base + 0x170, 30, 2,   0, video_div_table, &imx_ccm_lock);
+       hws[IMX6SL_CLK_ENET_REF]       = clk_hw_register_divider_table(NULL, "enet_ref",       "pll6_enet",     0,                   base + 0xe0,  0,  2,   0, clk_enet_ref_table, &imx_ccm_lock);
 
        /*                                       name         parent_name     reg           idx */
-       clks[IMX6SL_CLK_PLL2_PFD0] = imx_clk_pfd("pll2_pfd0", "pll2_bus",     base + 0x100, 0);
-       clks[IMX6SL_CLK_PLL2_PFD1] = imx_clk_pfd("pll2_pfd1", "pll2_bus",     base + 0x100, 1);
-       clks[IMX6SL_CLK_PLL2_PFD2] = imx_clk_pfd("pll2_pfd2", "pll2_bus",     base + 0x100, 2);
-       clks[IMX6SL_CLK_PLL3_PFD0] = imx_clk_pfd("pll3_pfd0", "pll3_usb_otg", base + 0xf0,  0);
-       clks[IMX6SL_CLK_PLL3_PFD1] = imx_clk_pfd("pll3_pfd1", "pll3_usb_otg", base + 0xf0,  1);
-       clks[IMX6SL_CLK_PLL3_PFD2] = imx_clk_pfd("pll3_pfd2", "pll3_usb_otg", base + 0xf0,  2);
-       clks[IMX6SL_CLK_PLL3_PFD3] = imx_clk_pfd("pll3_pfd3", "pll3_usb_otg", base + 0xf0,  3);
+       hws[IMX6SL_CLK_PLL2_PFD0] = imx_clk_hw_pfd("pll2_pfd0", "pll2_bus",     base + 0x100, 0);
+       hws[IMX6SL_CLK_PLL2_PFD1] = imx_clk_hw_pfd("pll2_pfd1", "pll2_bus",     base + 0x100, 1);
+       hws[IMX6SL_CLK_PLL2_PFD2] = imx_clk_hw_pfd("pll2_pfd2", "pll2_bus",     base + 0x100, 2);
+       hws[IMX6SL_CLK_PLL3_PFD0] = imx_clk_hw_pfd("pll3_pfd0", "pll3_usb_otg", base + 0xf0,  0);
+       hws[IMX6SL_CLK_PLL3_PFD1] = imx_clk_hw_pfd("pll3_pfd1", "pll3_usb_otg", base + 0xf0,  1);
+       hws[IMX6SL_CLK_PLL3_PFD2] = imx_clk_hw_pfd("pll3_pfd2", "pll3_usb_otg", base + 0xf0,  2);
+       hws[IMX6SL_CLK_PLL3_PFD3] = imx_clk_hw_pfd("pll3_pfd3", "pll3_usb_otg", base + 0xf0,  3);
 
        /*                                                name         parent_name     mult div */
-       clks[IMX6SL_CLK_PLL2_198M] = imx_clk_fixed_factor("pll2_198m", "pll2_pfd2",      1, 2);
-       clks[IMX6SL_CLK_PLL3_120M] = imx_clk_fixed_factor("pll3_120m", "pll3_usb_otg",   1, 4);
-       clks[IMX6SL_CLK_PLL3_80M]  = imx_clk_fixed_factor("pll3_80m",  "pll3_usb_otg",   1, 6);
-       clks[IMX6SL_CLK_PLL3_60M]  = imx_clk_fixed_factor("pll3_60m",  "pll3_usb_otg",   1, 8);
+       hws[IMX6SL_CLK_PLL2_198M] = imx_clk_hw_fixed_factor("pll2_198m", "pll2_pfd2",      1, 2);
+       hws[IMX6SL_CLK_PLL3_120M] = imx_clk_hw_fixed_factor("pll3_120m", "pll3_usb_otg",   1, 4);
+       hws[IMX6SL_CLK_PLL3_80M]  = imx_clk_hw_fixed_factor("pll3_80m",  "pll3_usb_otg",   1, 6);
+       hws[IMX6SL_CLK_PLL3_60M]  = imx_clk_hw_fixed_factor("pll3_60m",  "pll3_usb_otg",   1, 8);
 
        np = ccm_node;
        base = of_iomap(np, 0);
@@ -288,157 +296,160 @@ static void __init imx6sl_clocks_init(struct device_node *ccm_node)
        ccm_base = base;
 
        /*                                              name                reg       shift width parent_names     num_parents */
-       clks[IMX6SL_CLK_STEP]             = imx_clk_mux("step",             base + 0xc,  8,  1, step_sels,         ARRAY_SIZE(step_sels));
-       clks[IMX6SL_CLK_PLL1_SW]          = imx_clk_mux("pll1_sw",          base + 0xc,  2,  1, pll1_sw_sels,      ARRAY_SIZE(pll1_sw_sels));
-       clks[IMX6SL_CLK_OCRAM_ALT_SEL]    = imx_clk_mux("ocram_alt_sel",    base + 0x14, 7,  1, ocram_alt_sels,    ARRAY_SIZE(ocram_alt_sels));
-       clks[IMX6SL_CLK_OCRAM_SEL]        = imx_clk_mux("ocram_sel",        base + 0x14, 6,  1, ocram_sels,        ARRAY_SIZE(ocram_sels));
-       clks[IMX6SL_CLK_PRE_PERIPH2_SEL]  = imx_clk_mux("pre_periph2_sel",  base + 0x18, 21, 2, pre_periph_sels,   ARRAY_SIZE(pre_periph_sels));
-       clks[IMX6SL_CLK_PRE_PERIPH_SEL]   = imx_clk_mux("pre_periph_sel",   base + 0x18, 18, 2, pre_periph_sels,   ARRAY_SIZE(pre_periph_sels));
-       clks[IMX6SL_CLK_PERIPH2_CLK2_SEL] = imx_clk_mux("periph2_clk2_sel", base + 0x18, 20, 1, periph2_clk2_sels, ARRAY_SIZE(periph2_clk2_sels));
-       clks[IMX6SL_CLK_PERIPH_CLK2_SEL]  = imx_clk_mux("periph_clk2_sel",  base + 0x18, 12, 2, periph_clk2_sels,  ARRAY_SIZE(periph_clk2_sels));
-       clks[IMX6SL_CLK_CSI_SEL]          = imx_clk_mux("csi_sel",          base + 0x3c, 9,  2, csi_sels,          ARRAY_SIZE(csi_sels));
-       clks[IMX6SL_CLK_LCDIF_AXI_SEL]    = imx_clk_mux("lcdif_axi_sel",    base + 0x3c, 14, 2, lcdif_axi_sels,    ARRAY_SIZE(lcdif_axi_sels));
-       clks[IMX6SL_CLK_USDHC1_SEL]       = imx_clk_fixup_mux("usdhc1_sel", base + 0x1c, 16, 1, usdhc_sels,        ARRAY_SIZE(usdhc_sels),  imx_cscmr1_fixup);
-       clks[IMX6SL_CLK_USDHC2_SEL]       = imx_clk_fixup_mux("usdhc2_sel", base + 0x1c, 17, 1, usdhc_sels,        ARRAY_SIZE(usdhc_sels),  imx_cscmr1_fixup);
-       clks[IMX6SL_CLK_USDHC3_SEL]       = imx_clk_fixup_mux("usdhc3_sel", base + 0x1c, 18, 1, usdhc_sels,        ARRAY_SIZE(usdhc_sels),  imx_cscmr1_fixup);
-       clks[IMX6SL_CLK_USDHC4_SEL]       = imx_clk_fixup_mux("usdhc4_sel", base + 0x1c, 19, 1, usdhc_sels,        ARRAY_SIZE(usdhc_sels),  imx_cscmr1_fixup);
-       clks[IMX6SL_CLK_SSI1_SEL]         = imx_clk_fixup_mux("ssi1_sel",   base + 0x1c, 10, 2, ssi_sels,          ARRAY_SIZE(ssi_sels),    imx_cscmr1_fixup);
-       clks[IMX6SL_CLK_SSI2_SEL]         = imx_clk_fixup_mux("ssi2_sel",   base + 0x1c, 12, 2, ssi_sels,          ARRAY_SIZE(ssi_sels),    imx_cscmr1_fixup);
-       clks[IMX6SL_CLK_SSI3_SEL]         = imx_clk_fixup_mux("ssi3_sel",   base + 0x1c, 14, 2, ssi_sels,          ARRAY_SIZE(ssi_sels),    imx_cscmr1_fixup);
-       clks[IMX6SL_CLK_PERCLK_SEL]       = imx_clk_fixup_mux("perclk_sel", base + 0x1c, 6,  1, perclk_sels,       ARRAY_SIZE(perclk_sels), imx_cscmr1_fixup);
-       clks[IMX6SL_CLK_PXP_AXI_SEL]      = imx_clk_mux("pxp_axi_sel",      base + 0x34, 6,  3, pxp_axi_sels,      ARRAY_SIZE(pxp_axi_sels));
-       clks[IMX6SL_CLK_EPDC_AXI_SEL]     = imx_clk_mux("epdc_axi_sel",     base + 0x34, 15, 3, epdc_axi_sels,     ARRAY_SIZE(epdc_axi_sels));
-       clks[IMX6SL_CLK_GPU2D_OVG_SEL]    = imx_clk_mux("gpu2d_ovg_sel",    base + 0x18, 4,  2, gpu2d_ovg_sels,    ARRAY_SIZE(gpu2d_ovg_sels));
-       clks[IMX6SL_CLK_GPU2D_SEL]        = imx_clk_mux("gpu2d_sel",        base + 0x18, 8,  2, gpu2d_sels,        ARRAY_SIZE(gpu2d_sels));
-       clks[IMX6SL_CLK_LCDIF_PIX_SEL]    = imx_clk_mux("lcdif_pix_sel",    base + 0x38, 6,  3, lcdif_pix_sels,    ARRAY_SIZE(lcdif_pix_sels));
-       clks[IMX6SL_CLK_EPDC_PIX_SEL]     = imx_clk_mux("epdc_pix_sel",     base + 0x38, 15, 3, epdc_pix_sels,     ARRAY_SIZE(epdc_pix_sels));
-       clks[IMX6SL_CLK_SPDIF0_SEL]       = imx_clk_mux("spdif0_sel",       base + 0x30, 20, 2, audio_sels,        ARRAY_SIZE(audio_sels));
-       clks[IMX6SL_CLK_SPDIF1_SEL]       = imx_clk_mux("spdif1_sel",       base + 0x30, 7,  2, audio_sels,        ARRAY_SIZE(audio_sels));
-       clks[IMX6SL_CLK_EXTERN_AUDIO_SEL] = imx_clk_mux("extern_audio_sel", base + 0x20, 19, 2, audio_sels,        ARRAY_SIZE(audio_sels));
-       clks[IMX6SL_CLK_ECSPI_SEL]        = imx_clk_mux("ecspi_sel",        base + 0x38, 18, 1, ecspi_sels,        ARRAY_SIZE(ecspi_sels));
-       clks[IMX6SL_CLK_UART_SEL]         = imx_clk_mux("uart_sel",         base + 0x24, 6,  1, uart_sels,         ARRAY_SIZE(uart_sels));
+       hws[IMX6SL_CLK_STEP]             = imx_clk_hw_mux("step",             base + 0xc,  8,  1, step_sels,         ARRAY_SIZE(step_sels));
+       hws[IMX6SL_CLK_PLL1_SW]          = imx_clk_hw_mux("pll1_sw",          base + 0xc,  2,  1, pll1_sw_sels,      ARRAY_SIZE(pll1_sw_sels));
+       hws[IMX6SL_CLK_OCRAM_ALT_SEL]    = imx_clk_hw_mux("ocram_alt_sel",    base + 0x14, 7,  1, ocram_alt_sels,    ARRAY_SIZE(ocram_alt_sels));
+       hws[IMX6SL_CLK_OCRAM_SEL]        = imx_clk_hw_mux("ocram_sel",        base + 0x14, 6,  1, ocram_sels,        ARRAY_SIZE(ocram_sels));
+       hws[IMX6SL_CLK_PRE_PERIPH2_SEL]  = imx_clk_hw_mux("pre_periph2_sel",  base + 0x18, 21, 2, pre_periph_sels,   ARRAY_SIZE(pre_periph_sels));
+       hws[IMX6SL_CLK_PRE_PERIPH_SEL]   = imx_clk_hw_mux("pre_periph_sel",   base + 0x18, 18, 2, pre_periph_sels,   ARRAY_SIZE(pre_periph_sels));
+       hws[IMX6SL_CLK_PERIPH2_CLK2_SEL] = imx_clk_hw_mux("periph2_clk2_sel", base + 0x18, 20, 1, periph2_clk2_sels, ARRAY_SIZE(periph2_clk2_sels));
+       hws[IMX6SL_CLK_PERIPH_CLK2_SEL]  = imx_clk_hw_mux("periph_clk2_sel",  base + 0x18, 12, 2, periph_clk2_sels,  ARRAY_SIZE(periph_clk2_sels));
+       hws[IMX6SL_CLK_CSI_SEL]          = imx_clk_hw_mux("csi_sel",          base + 0x3c, 9,  2, csi_sels,          ARRAY_SIZE(csi_sels));
+       hws[IMX6SL_CLK_LCDIF_AXI_SEL]    = imx_clk_hw_mux("lcdif_axi_sel",    base + 0x3c, 14, 2, lcdif_axi_sels,    ARRAY_SIZE(lcdif_axi_sels));
+       hws[IMX6SL_CLK_USDHC1_SEL]       = imx_clk_hw_fixup_mux("usdhc1_sel", base + 0x1c, 16, 1, usdhc_sels,        ARRAY_SIZE(usdhc_sels),  imx_cscmr1_fixup);
+       hws[IMX6SL_CLK_USDHC2_SEL]       = imx_clk_hw_fixup_mux("usdhc2_sel", base + 0x1c, 17, 1, usdhc_sels,        ARRAY_SIZE(usdhc_sels),  imx_cscmr1_fixup);
+       hws[IMX6SL_CLK_USDHC3_SEL]       = imx_clk_hw_fixup_mux("usdhc3_sel", base + 0x1c, 18, 1, usdhc_sels,        ARRAY_SIZE(usdhc_sels),  imx_cscmr1_fixup);
+       hws[IMX6SL_CLK_USDHC4_SEL]       = imx_clk_hw_fixup_mux("usdhc4_sel", base + 0x1c, 19, 1, usdhc_sels,        ARRAY_SIZE(usdhc_sels),  imx_cscmr1_fixup);
+       hws[IMX6SL_CLK_SSI1_SEL]         = imx_clk_hw_fixup_mux("ssi1_sel",   base + 0x1c, 10, 2, ssi_sels,          ARRAY_SIZE(ssi_sels),    imx_cscmr1_fixup);
+       hws[IMX6SL_CLK_SSI2_SEL]         = imx_clk_hw_fixup_mux("ssi2_sel",   base + 0x1c, 12, 2, ssi_sels,          ARRAY_SIZE(ssi_sels),    imx_cscmr1_fixup);
+       hws[IMX6SL_CLK_SSI3_SEL]         = imx_clk_hw_fixup_mux("ssi3_sel",   base + 0x1c, 14, 2, ssi_sels,          ARRAY_SIZE(ssi_sels),    imx_cscmr1_fixup);
+       hws[IMX6SL_CLK_PERCLK_SEL]       = imx_clk_hw_fixup_mux("perclk_sel", base + 0x1c, 6,  1, perclk_sels,       ARRAY_SIZE(perclk_sels), imx_cscmr1_fixup);
+       hws[IMX6SL_CLK_PXP_AXI_SEL]      = imx_clk_hw_mux("pxp_axi_sel",      base + 0x34, 6,  3, pxp_axi_sels,      ARRAY_SIZE(pxp_axi_sels));
+       hws[IMX6SL_CLK_EPDC_AXI_SEL]     = imx_clk_hw_mux("epdc_axi_sel",     base + 0x34, 15, 3, epdc_axi_sels,     ARRAY_SIZE(epdc_axi_sels));
+       hws[IMX6SL_CLK_GPU2D_OVG_SEL]    = imx_clk_hw_mux("gpu2d_ovg_sel",    base + 0x18, 4,  2, gpu2d_ovg_sels,    ARRAY_SIZE(gpu2d_ovg_sels));
+       hws[IMX6SL_CLK_GPU2D_SEL]        = imx_clk_hw_mux("gpu2d_sel",        base + 0x18, 8,  2, gpu2d_sels,        ARRAY_SIZE(gpu2d_sels));
+       hws[IMX6SL_CLK_LCDIF_PIX_SEL]    = imx_clk_hw_mux("lcdif_pix_sel",    base + 0x38, 6,  3, lcdif_pix_sels,    ARRAY_SIZE(lcdif_pix_sels));
+       hws[IMX6SL_CLK_EPDC_PIX_SEL]     = imx_clk_hw_mux("epdc_pix_sel",     base + 0x38, 15, 3, epdc_pix_sels,     ARRAY_SIZE(epdc_pix_sels));
+       hws[IMX6SL_CLK_SPDIF0_SEL]       = imx_clk_hw_mux("spdif0_sel",       base + 0x30, 20, 2, audio_sels,        ARRAY_SIZE(audio_sels));
+       hws[IMX6SL_CLK_SPDIF1_SEL]       = imx_clk_hw_mux("spdif1_sel",       base + 0x30, 7,  2, audio_sels,        ARRAY_SIZE(audio_sels));
+       hws[IMX6SL_CLK_EXTERN_AUDIO_SEL] = imx_clk_hw_mux("extern_audio_sel", base + 0x20, 19, 2, audio_sels,        ARRAY_SIZE(audio_sels));
+       hws[IMX6SL_CLK_ECSPI_SEL]        = imx_clk_hw_mux("ecspi_sel",        base + 0x38, 18, 1, ecspi_sels,        ARRAY_SIZE(ecspi_sels));
+       hws[IMX6SL_CLK_UART_SEL]         = imx_clk_hw_mux("uart_sel",         base + 0x24, 6,  1, uart_sels,         ARRAY_SIZE(uart_sels));
 
        /*                                          name       reg        shift width busy: reg, shift parent_names  num_parents */
-       clks[IMX6SL_CLK_PERIPH]  = imx_clk_busy_mux("periph",  base + 0x14, 25,  1,   base + 0x48, 5,  periph_sels,  ARRAY_SIZE(periph_sels));
-       clks[IMX6SL_CLK_PERIPH2] = imx_clk_busy_mux("periph2", base + 0x14, 26,  1,   base + 0x48, 3,  periph2_sels, ARRAY_SIZE(periph2_sels));
+       hws[IMX6SL_CLK_PERIPH]  = imx_clk_hw_busy_mux("periph",  base + 0x14, 25,  1,   base + 0x48, 5,  periph_sels,  ARRAY_SIZE(periph_sels));
+       hws[IMX6SL_CLK_PERIPH2] = imx_clk_hw_busy_mux("periph2", base + 0x14, 26,  1,   base + 0x48, 3,  periph2_sels, ARRAY_SIZE(periph2_sels));
 
        /*                                                   name                 parent_name          reg       shift width */
-       clks[IMX6SL_CLK_OCRAM_PODF]        = imx_clk_busy_divider("ocram_podf",   "ocram_sel",         base + 0x14, 16, 3, base + 0x48, 0);
-       clks[IMX6SL_CLK_PERIPH_CLK2_PODF]  = imx_clk_divider("periph_clk2_podf",  "periph_clk2_sel",   base + 0x14, 27, 3);
-       clks[IMX6SL_CLK_PERIPH2_CLK2_PODF] = imx_clk_divider("periph2_clk2_podf", "periph2_clk2_sel",  base + 0x14, 0,  3);
-       clks[IMX6SL_CLK_IPG]               = imx_clk_divider("ipg",               "ahb",               base + 0x14, 8,  2);
-       clks[IMX6SL_CLK_CSI_PODF]          = imx_clk_divider("csi_podf",          "csi_sel",           base + 0x3c, 11, 3);
-       clks[IMX6SL_CLK_LCDIF_AXI_PODF]    = imx_clk_divider("lcdif_axi_podf",    "lcdif_axi_sel",     base + 0x3c, 16, 3);
-       clks[IMX6SL_CLK_USDHC1_PODF]       = imx_clk_divider("usdhc1_podf",       "usdhc1_sel",        base + 0x24, 11, 3);
-       clks[IMX6SL_CLK_USDHC2_PODF]       = imx_clk_divider("usdhc2_podf",       "usdhc2_sel",        base + 0x24, 16, 3);
-       clks[IMX6SL_CLK_USDHC3_PODF]       = imx_clk_divider("usdhc3_podf",       "usdhc3_sel",        base + 0x24, 19, 3);
-       clks[IMX6SL_CLK_USDHC4_PODF]       = imx_clk_divider("usdhc4_podf",       "usdhc4_sel",        base + 0x24, 22, 3);
-       clks[IMX6SL_CLK_SSI1_PRED]         = imx_clk_divider("ssi1_pred",         "ssi1_sel",          base + 0x28, 6,  3);
-       clks[IMX6SL_CLK_SSI1_PODF]         = imx_clk_divider("ssi1_podf",         "ssi1_pred",         base + 0x28, 0,  6);
-       clks[IMX6SL_CLK_SSI2_PRED]         = imx_clk_divider("ssi2_pred",         "ssi2_sel",          base + 0x2c, 6,  3);
-       clks[IMX6SL_CLK_SSI2_PODF]         = imx_clk_divider("ssi2_podf",         "ssi2_pred",         base + 0x2c, 0,  6);
-       clks[IMX6SL_CLK_SSI3_PRED]         = imx_clk_divider("ssi3_pred",         "ssi3_sel",          base + 0x28, 22, 3);
-       clks[IMX6SL_CLK_SSI3_PODF]         = imx_clk_divider("ssi3_podf",         "ssi3_pred",         base + 0x28, 16, 6);
-       clks[IMX6SL_CLK_PERCLK]            = imx_clk_fixup_divider("perclk",      "perclk_sel",        base + 0x1c, 0,  6, imx_cscmr1_fixup);
-       clks[IMX6SL_CLK_PXP_AXI_PODF]      = imx_clk_divider("pxp_axi_podf",      "pxp_axi_sel",       base + 0x34, 3,  3);
-       clks[IMX6SL_CLK_EPDC_AXI_PODF]     = imx_clk_divider("epdc_axi_podf",     "epdc_axi_sel",      base + 0x34, 12, 3);
-       clks[IMX6SL_CLK_GPU2D_OVG_PODF]    = imx_clk_divider("gpu2d_ovg_podf",    "gpu2d_ovg_sel",     base + 0x18, 26, 3);
-       clks[IMX6SL_CLK_GPU2D_PODF]        = imx_clk_divider("gpu2d_podf",        "gpu2d_sel",         base + 0x18, 29, 3);
-       clks[IMX6SL_CLK_LCDIF_PIX_PRED]    = imx_clk_divider("lcdif_pix_pred",    "lcdif_pix_sel",     base + 0x38, 3,  3);
-       clks[IMX6SL_CLK_EPDC_PIX_PRED]     = imx_clk_divider("epdc_pix_pred",     "epdc_pix_sel",      base + 0x38, 12, 3);
-       clks[IMX6SL_CLK_LCDIF_PIX_PODF]    = imx_clk_fixup_divider("lcdif_pix_podf", "lcdif_pix_pred", base + 0x1c, 20, 3, imx_cscmr1_fixup);
-       clks[IMX6SL_CLK_EPDC_PIX_PODF]     = imx_clk_divider("epdc_pix_podf",     "epdc_pix_pred",     base + 0x18, 23, 3);
-       clks[IMX6SL_CLK_SPDIF0_PRED]       = imx_clk_divider("spdif0_pred",       "spdif0_sel",        base + 0x30, 25, 3);
-       clks[IMX6SL_CLK_SPDIF0_PODF]       = imx_clk_divider("spdif0_podf",       "spdif0_pred",       base + 0x30, 22, 3);
-       clks[IMX6SL_CLK_SPDIF1_PRED]       = imx_clk_divider("spdif1_pred",       "spdif1_sel",        base + 0x30, 12, 3);
-       clks[IMX6SL_CLK_SPDIF1_PODF]       = imx_clk_divider("spdif1_podf",       "spdif1_pred",       base + 0x30, 9,  3);
-       clks[IMX6SL_CLK_EXTERN_AUDIO_PRED] = imx_clk_divider("extern_audio_pred", "extern_audio_sel",  base + 0x28, 9,  3);
-       clks[IMX6SL_CLK_EXTERN_AUDIO_PODF] = imx_clk_divider("extern_audio_podf", "extern_audio_pred", base + 0x28, 25, 3);
-       clks[IMX6SL_CLK_ECSPI_ROOT]        = imx_clk_divider("ecspi_root",        "ecspi_sel",         base + 0x38, 19, 6);
-       clks[IMX6SL_CLK_UART_ROOT]         = imx_clk_divider("uart_root",         "uart_sel",          base + 0x24, 0,  6);
+       hws[IMX6SL_CLK_OCRAM_PODF]        = imx_clk_hw_busy_divider("ocram_podf",   "ocram_sel",         base + 0x14, 16, 3, base + 0x48, 0);
+       hws[IMX6SL_CLK_PERIPH_CLK2_PODF]  = imx_clk_hw_divider("periph_clk2_podf",  "periph_clk2_sel",   base + 0x14, 27, 3);
+       hws[IMX6SL_CLK_PERIPH2_CLK2_PODF] = imx_clk_hw_divider("periph2_clk2_podf", "periph2_clk2_sel",  base + 0x14, 0,  3);
+       hws[IMX6SL_CLK_IPG]               = imx_clk_hw_divider("ipg",               "ahb",               base + 0x14, 8,  2);
+       hws[IMX6SL_CLK_CSI_PODF]          = imx_clk_hw_divider("csi_podf",          "csi_sel",           base + 0x3c, 11, 3);
+       hws[IMX6SL_CLK_LCDIF_AXI_PODF]    = imx_clk_hw_divider("lcdif_axi_podf",    "lcdif_axi_sel",     base + 0x3c, 16, 3);
+       hws[IMX6SL_CLK_USDHC1_PODF]       = imx_clk_hw_divider("usdhc1_podf",       "usdhc1_sel",        base + 0x24, 11, 3);
+       hws[IMX6SL_CLK_USDHC2_PODF]       = imx_clk_hw_divider("usdhc2_podf",       "usdhc2_sel",        base + 0x24, 16, 3);
+       hws[IMX6SL_CLK_USDHC3_PODF]       = imx_clk_hw_divider("usdhc3_podf",       "usdhc3_sel",        base + 0x24, 19, 3);
+       hws[IMX6SL_CLK_USDHC4_PODF]       = imx_clk_hw_divider("usdhc4_podf",       "usdhc4_sel",        base + 0x24, 22, 3);
+       hws[IMX6SL_CLK_SSI1_PRED]         = imx_clk_hw_divider("ssi1_pred",         "ssi1_sel",          base + 0x28, 6,  3);
+       hws[IMX6SL_CLK_SSI1_PODF]         = imx_clk_hw_divider("ssi1_podf",         "ssi1_pred",         base + 0x28, 0,  6);
+       hws[IMX6SL_CLK_SSI2_PRED]         = imx_clk_hw_divider("ssi2_pred",         "ssi2_sel",          base + 0x2c, 6,  3);
+       hws[IMX6SL_CLK_SSI2_PODF]         = imx_clk_hw_divider("ssi2_podf",         "ssi2_pred",         base + 0x2c, 0,  6);
+       hws[IMX6SL_CLK_SSI3_PRED]         = imx_clk_hw_divider("ssi3_pred",         "ssi3_sel",          base + 0x28, 22, 3);
+       hws[IMX6SL_CLK_SSI3_PODF]         = imx_clk_hw_divider("ssi3_podf",         "ssi3_pred",         base + 0x28, 16, 6);
+       hws[IMX6SL_CLK_PERCLK]            = imx_clk_hw_fixup_divider("perclk",      "perclk_sel",        base + 0x1c, 0,  6, imx_cscmr1_fixup);
+       hws[IMX6SL_CLK_PXP_AXI_PODF]      = imx_clk_hw_divider("pxp_axi_podf",      "pxp_axi_sel",       base + 0x34, 3,  3);
+       hws[IMX6SL_CLK_EPDC_AXI_PODF]     = imx_clk_hw_divider("epdc_axi_podf",     "epdc_axi_sel",      base + 0x34, 12, 3);
+       hws[IMX6SL_CLK_GPU2D_OVG_PODF]    = imx_clk_hw_divider("gpu2d_ovg_podf",    "gpu2d_ovg_sel",     base + 0x18, 26, 3);
+       hws[IMX6SL_CLK_GPU2D_PODF]        = imx_clk_hw_divider("gpu2d_podf",        "gpu2d_sel",         base + 0x18, 29, 3);
+       hws[IMX6SL_CLK_LCDIF_PIX_PRED]    = imx_clk_hw_divider("lcdif_pix_pred",    "lcdif_pix_sel",     base + 0x38, 3,  3);
+       hws[IMX6SL_CLK_EPDC_PIX_PRED]     = imx_clk_hw_divider("epdc_pix_pred",     "epdc_pix_sel",      base + 0x38, 12, 3);
+       hws[IMX6SL_CLK_LCDIF_PIX_PODF]    = imx_clk_hw_fixup_divider("lcdif_pix_podf", "lcdif_pix_pred", base + 0x1c, 20, 3, imx_cscmr1_fixup);
+       hws[IMX6SL_CLK_EPDC_PIX_PODF]     = imx_clk_hw_divider("epdc_pix_podf",     "epdc_pix_pred",     base + 0x18, 23, 3);
+       hws[IMX6SL_CLK_SPDIF0_PRED]       = imx_clk_hw_divider("spdif0_pred",       "spdif0_sel",        base + 0x30, 25, 3);
+       hws[IMX6SL_CLK_SPDIF0_PODF]       = imx_clk_hw_divider("spdif0_podf",       "spdif0_pred",       base + 0x30, 22, 3);
+       hws[IMX6SL_CLK_SPDIF1_PRED]       = imx_clk_hw_divider("spdif1_pred",       "spdif1_sel",        base + 0x30, 12, 3);
+       hws[IMX6SL_CLK_SPDIF1_PODF]       = imx_clk_hw_divider("spdif1_podf",       "spdif1_pred",       base + 0x30, 9,  3);
+       hws[IMX6SL_CLK_EXTERN_AUDIO_PRED] = imx_clk_hw_divider("extern_audio_pred", "extern_audio_sel",  base + 0x28, 9,  3);
+       hws[IMX6SL_CLK_EXTERN_AUDIO_PODF] = imx_clk_hw_divider("extern_audio_podf", "extern_audio_pred", base + 0x28, 25, 3);
+       hws[IMX6SL_CLK_ECSPI_ROOT]        = imx_clk_hw_divider("ecspi_root",        "ecspi_sel",         base + 0x38, 19, 6);
+       hws[IMX6SL_CLK_UART_ROOT]         = imx_clk_hw_divider("uart_root",         "uart_sel",          base + 0x24, 0,  6);
 
        /*                                                name         parent_name reg       shift width busy: reg, shift */
-       clks[IMX6SL_CLK_AHB]       = imx_clk_busy_divider("ahb",       "periph",  base + 0x14, 10, 3,    base + 0x48, 1);
-       clks[IMX6SL_CLK_MMDC_ROOT] = imx_clk_busy_divider("mmdc",      "periph2", base + 0x14, 3,  3,    base + 0x48, 2);
-       clks[IMX6SL_CLK_ARM]       = imx_clk_busy_divider("arm",       "pll1_sw", base + 0x10, 0,  3,    base + 0x48, 16);
+       hws[IMX6SL_CLK_AHB]       = imx_clk_hw_busy_divider("ahb",       "periph",  base + 0x14, 10, 3,    base + 0x48, 1);
+       hws[IMX6SL_CLK_MMDC_ROOT] = imx_clk_hw_busy_divider("mmdc",      "periph2", base + 0x14, 3,  3,    base + 0x48, 2);
+       hws[IMX6SL_CLK_ARM]       = imx_clk_hw_busy_divider("arm",       "pll1_sw", base + 0x10, 0,  3,    base + 0x48, 16);
 
        /*                                            name            parent_name          reg         shift */
-       clks[IMX6SL_CLK_ECSPI1]       = imx_clk_gate2("ecspi1",       "ecspi_root",        base + 0x6c, 0);
-       clks[IMX6SL_CLK_ECSPI2]       = imx_clk_gate2("ecspi2",       "ecspi_root",        base + 0x6c, 2);
-       clks[IMX6SL_CLK_ECSPI3]       = imx_clk_gate2("ecspi3",       "ecspi_root",        base + 0x6c, 4);
-       clks[IMX6SL_CLK_ECSPI4]       = imx_clk_gate2("ecspi4",       "ecspi_root",        base + 0x6c, 6);
-       clks[IMX6SL_CLK_ENET]         = imx_clk_gate2("enet",         "ipg",               base + 0x6c, 10);
-       clks[IMX6SL_CLK_EPIT1]        = imx_clk_gate2("epit1",        "perclk",            base + 0x6c, 12);
-       clks[IMX6SL_CLK_EPIT2]        = imx_clk_gate2("epit2",        "perclk",            base + 0x6c, 14);
-       clks[IMX6SL_CLK_EXTERN_AUDIO] = imx_clk_gate2("extern_audio", "extern_audio_podf", base + 0x6c, 16);
-       clks[IMX6SL_CLK_GPT]          = imx_clk_gate2("gpt",          "perclk",            base + 0x6c, 20);
-       clks[IMX6SL_CLK_GPT_SERIAL]   = imx_clk_gate2("gpt_serial",   "perclk",            base + 0x6c, 22);
-       clks[IMX6SL_CLK_GPU2D_OVG]    = imx_clk_gate2("gpu2d_ovg",    "gpu2d_ovg_podf",    base + 0x6c, 26);
-       clks[IMX6SL_CLK_I2C1]         = imx_clk_gate2("i2c1",         "perclk",            base + 0x70, 6);
-       clks[IMX6SL_CLK_I2C2]         = imx_clk_gate2("i2c2",         "perclk",            base + 0x70, 8);
-       clks[IMX6SL_CLK_I2C3]         = imx_clk_gate2("i2c3",         "perclk",            base + 0x70, 10);
-       clks[IMX6SL_CLK_OCOTP]        = imx_clk_gate2("ocotp",        "ipg",               base + 0x70, 12);
-       clks[IMX6SL_CLK_CSI]          = imx_clk_gate2("csi",          "csi_podf",          base + 0x74, 0);
-       clks[IMX6SL_CLK_PXP_AXI]      = imx_clk_gate2("pxp_axi",      "pxp_axi_podf",      base + 0x74, 2);
-       clks[IMX6SL_CLK_EPDC_AXI]     = imx_clk_gate2("epdc_axi",     "epdc_axi_podf",     base + 0x74, 4);
-       clks[IMX6SL_CLK_LCDIF_AXI]    = imx_clk_gate2("lcdif_axi",    "lcdif_axi_podf",    base + 0x74, 6);
-       clks[IMX6SL_CLK_LCDIF_PIX]    = imx_clk_gate2("lcdif_pix",    "lcdif_pix_podf",    base + 0x74, 8);
-       clks[IMX6SL_CLK_EPDC_PIX]     = imx_clk_gate2("epdc_pix",     "epdc_pix_podf",     base + 0x74, 10);
-       clks[IMX6SL_CLK_MMDC_P0_IPG]  = imx_clk_gate2_flags("mmdc_p0_ipg",  "ipg",         base + 0x74, 24, CLK_IS_CRITICAL);
-       clks[IMX6SL_CLK_MMDC_P1_IPG]  = imx_clk_gate2("mmdc_p1_ipg",  "ipg",               base + 0x74, 26);
-       clks[IMX6SL_CLK_OCRAM]        = imx_clk_gate2("ocram",        "ocram_podf",        base + 0x74, 28);
-       clks[IMX6SL_CLK_PWM1]         = imx_clk_gate2("pwm1",         "perclk",            base + 0x78, 16);
-       clks[IMX6SL_CLK_PWM2]         = imx_clk_gate2("pwm2",         "perclk",            base + 0x78, 18);
-       clks[IMX6SL_CLK_PWM3]         = imx_clk_gate2("pwm3",         "perclk",            base + 0x78, 20);
-       clks[IMX6SL_CLK_PWM4]         = imx_clk_gate2("pwm4",         "perclk",            base + 0x78, 22);
-       clks[IMX6SL_CLK_SDMA]         = imx_clk_gate2("sdma",         "ipg",               base + 0x7c, 6);
-       clks[IMX6SL_CLK_SPBA]         = imx_clk_gate2("spba",         "ipg",               base + 0x7c, 12);
-       clks[IMX6SL_CLK_SPDIF]        = imx_clk_gate2_shared("spdif",     "spdif0_podf",   base + 0x7c, 14, &share_count_spdif);
-       clks[IMX6SL_CLK_SPDIF_GCLK]   = imx_clk_gate2_shared("spdif_gclk",  "ipg",         base + 0x7c, 14, &share_count_spdif);
-       clks[IMX6SL_CLK_SSI1_IPG]     = imx_clk_gate2_shared("ssi1_ipg",     "ipg",        base + 0x7c, 18, &share_count_ssi1);
-       clks[IMX6SL_CLK_SSI2_IPG]     = imx_clk_gate2_shared("ssi2_ipg",     "ipg",        base + 0x7c, 20, &share_count_ssi2);
-       clks[IMX6SL_CLK_SSI3_IPG]     = imx_clk_gate2_shared("ssi3_ipg",     "ipg",        base + 0x7c, 22, &share_count_ssi3);
-       clks[IMX6SL_CLK_SSI1]         = imx_clk_gate2_shared("ssi1",         "ssi1_podf",  base + 0x7c, 18, &share_count_ssi1);
-       clks[IMX6SL_CLK_SSI2]         = imx_clk_gate2_shared("ssi2",         "ssi2_podf",  base + 0x7c, 20, &share_count_ssi2);
-       clks[IMX6SL_CLK_SSI3]         = imx_clk_gate2_shared("ssi3",         "ssi3_podf",  base + 0x7c, 22, &share_count_ssi3);
-       clks[IMX6SL_CLK_UART]         = imx_clk_gate2("uart",         "ipg",               base + 0x7c, 24);
-       clks[IMX6SL_CLK_UART_SERIAL]  = imx_clk_gate2("uart_serial",  "uart_root",         base + 0x7c, 26);
-       clks[IMX6SL_CLK_USBOH3]       = imx_clk_gate2("usboh3",       "ipg",               base + 0x80, 0);
-       clks[IMX6SL_CLK_USDHC1]       = imx_clk_gate2("usdhc1",       "usdhc1_podf",       base + 0x80, 2);
-       clks[IMX6SL_CLK_USDHC2]       = imx_clk_gate2("usdhc2",       "usdhc2_podf",       base + 0x80, 4);
-       clks[IMX6SL_CLK_USDHC3]       = imx_clk_gate2("usdhc3",       "usdhc3_podf",       base + 0x80, 6);
-       clks[IMX6SL_CLK_USDHC4]       = imx_clk_gate2("usdhc4",       "usdhc4_podf",       base + 0x80, 8);
+       hws[IMX6SL_CLK_ECSPI1]       = imx_clk_hw_gate2("ecspi1",       "ecspi_root",        base + 0x6c, 0);
+       hws[IMX6SL_CLK_ECSPI2]       = imx_clk_hw_gate2("ecspi2",       "ecspi_root",        base + 0x6c, 2);
+       hws[IMX6SL_CLK_ECSPI3]       = imx_clk_hw_gate2("ecspi3",       "ecspi_root",        base + 0x6c, 4);
+       hws[IMX6SL_CLK_ECSPI4]       = imx_clk_hw_gate2("ecspi4",       "ecspi_root",        base + 0x6c, 6);
+       hws[IMX6SL_CLK_ENET]         = imx_clk_hw_gate2("enet",         "ipg",               base + 0x6c, 10);
+       hws[IMX6SL_CLK_EPIT1]        = imx_clk_hw_gate2("epit1",        "perclk",            base + 0x6c, 12);
+       hws[IMX6SL_CLK_EPIT2]        = imx_clk_hw_gate2("epit2",        "perclk",            base + 0x6c, 14);
+       hws[IMX6SL_CLK_EXTERN_AUDIO] = imx_clk_hw_gate2("extern_audio", "extern_audio_podf", base + 0x6c, 16);
+       hws[IMX6SL_CLK_GPT]          = imx_clk_hw_gate2("gpt",          "perclk",            base + 0x6c, 20);
+       hws[IMX6SL_CLK_GPT_SERIAL]   = imx_clk_hw_gate2("gpt_serial",   "perclk",            base + 0x6c, 22);
+       hws[IMX6SL_CLK_GPU2D_OVG]    = imx_clk_hw_gate2("gpu2d_ovg",    "gpu2d_ovg_podf",    base + 0x6c, 26);
+       hws[IMX6SL_CLK_I2C1]         = imx_clk_hw_gate2("i2c1",         "perclk",            base + 0x70, 6);
+       hws[IMX6SL_CLK_I2C2]         = imx_clk_hw_gate2("i2c2",         "perclk",            base + 0x70, 8);
+       hws[IMX6SL_CLK_I2C3]         = imx_clk_hw_gate2("i2c3",         "perclk",            base + 0x70, 10);
+       hws[IMX6SL_CLK_OCOTP]        = imx_clk_hw_gate2("ocotp",        "ipg",               base + 0x70, 12);
+       hws[IMX6SL_CLK_CSI]          = imx_clk_hw_gate2("csi",          "csi_podf",          base + 0x74, 0);
+       hws[IMX6SL_CLK_PXP_AXI]      = imx_clk_hw_gate2("pxp_axi",      "pxp_axi_podf",      base + 0x74, 2);
+       hws[IMX6SL_CLK_EPDC_AXI]     = imx_clk_hw_gate2("epdc_axi",     "epdc_axi_podf",     base + 0x74, 4);
+       hws[IMX6SL_CLK_LCDIF_AXI]    = imx_clk_hw_gate2("lcdif_axi",    "lcdif_axi_podf",    base + 0x74, 6);
+       hws[IMX6SL_CLK_LCDIF_PIX]    = imx_clk_hw_gate2("lcdif_pix",    "lcdif_pix_podf",    base + 0x74, 8);
+       hws[IMX6SL_CLK_EPDC_PIX]     = imx_clk_hw_gate2("epdc_pix",     "epdc_pix_podf",     base + 0x74, 10);
+       hws[IMX6SL_CLK_MMDC_P0_IPG]  = imx_clk_hw_gate2_flags("mmdc_p0_ipg",  "ipg",         base + 0x74, 24, CLK_IS_CRITICAL);
+       hws[IMX6SL_CLK_MMDC_P1_IPG]  = imx_clk_hw_gate2("mmdc_p1_ipg",  "ipg",               base + 0x74, 26);
+       hws[IMX6SL_CLK_OCRAM]        = imx_clk_hw_gate2("ocram",        "ocram_podf",        base + 0x74, 28);
+       hws[IMX6SL_CLK_PWM1]         = imx_clk_hw_gate2("pwm1",         "perclk",            base + 0x78, 16);
+       hws[IMX6SL_CLK_PWM2]         = imx_clk_hw_gate2("pwm2",         "perclk",            base + 0x78, 18);
+       hws[IMX6SL_CLK_PWM3]         = imx_clk_hw_gate2("pwm3",         "perclk",            base + 0x78, 20);
+       hws[IMX6SL_CLK_PWM4]         = imx_clk_hw_gate2("pwm4",         "perclk",            base + 0x78, 22);
+       hws[IMX6SL_CLK_SDMA]         = imx_clk_hw_gate2("sdma",         "ipg",               base + 0x7c, 6);
+       hws[IMX6SL_CLK_SPBA]         = imx_clk_hw_gate2("spba",         "ipg",               base + 0x7c, 12);
+       hws[IMX6SL_CLK_SPDIF]        = imx_clk_hw_gate2_shared("spdif",     "spdif0_podf",   base + 0x7c, 14, &share_count_spdif);
+       hws[IMX6SL_CLK_SPDIF_GCLK]   = imx_clk_hw_gate2_shared("spdif_gclk",  "ipg",         base + 0x7c, 14, &share_count_spdif);
+       hws[IMX6SL_CLK_SSI1_IPG]     = imx_clk_hw_gate2_shared("ssi1_ipg",     "ipg",        base + 0x7c, 18, &share_count_ssi1);
+       hws[IMX6SL_CLK_SSI2_IPG]     = imx_clk_hw_gate2_shared("ssi2_ipg",     "ipg",        base + 0x7c, 20, &share_count_ssi2);
+       hws[IMX6SL_CLK_SSI3_IPG]     = imx_clk_hw_gate2_shared("ssi3_ipg",     "ipg",        base + 0x7c, 22, &share_count_ssi3);
+       hws[IMX6SL_CLK_SSI1]         = imx_clk_hw_gate2_shared("ssi1",         "ssi1_podf",  base + 0x7c, 18, &share_count_ssi1);
+       hws[IMX6SL_CLK_SSI2]         = imx_clk_hw_gate2_shared("ssi2",         "ssi2_podf",  base + 0x7c, 20, &share_count_ssi2);
+       hws[IMX6SL_CLK_SSI3]         = imx_clk_hw_gate2_shared("ssi3",         "ssi3_podf",  base + 0x7c, 22, &share_count_ssi3);
+       hws[IMX6SL_CLK_UART]         = imx_clk_hw_gate2("uart",         "ipg",               base + 0x7c, 24);
+       hws[IMX6SL_CLK_UART_SERIAL]  = imx_clk_hw_gate2("uart_serial",  "uart_root",         base + 0x7c, 26);
+       hws[IMX6SL_CLK_USBOH3]       = imx_clk_hw_gate2("usboh3",       "ipg",               base + 0x80, 0);
+       hws[IMX6SL_CLK_USDHC1]       = imx_clk_hw_gate2("usdhc1",       "usdhc1_podf",       base + 0x80, 2);
+       hws[IMX6SL_CLK_USDHC2]       = imx_clk_hw_gate2("usdhc2",       "usdhc2_podf",       base + 0x80, 4);
+       hws[IMX6SL_CLK_USDHC3]       = imx_clk_hw_gate2("usdhc3",       "usdhc3_podf",       base + 0x80, 6);
+       hws[IMX6SL_CLK_USDHC4]       = imx_clk_hw_gate2("usdhc4",       "usdhc4_podf",       base + 0x80, 8);
 
        /* Ensure the MMDC CH0 handshake is bypassed */
-       writel_relaxed(readl_relaxed(base + CCDR) |
-               BM_CCM_CCDR_MMDC_CH0_MASK, base + CCDR);
+       imx_mmdc_mask_handshake(base, 0);
 
-       imx_check_clocks(clks, ARRAY_SIZE(clks));
+       imx_check_clk_hws(hws, IMX6SL_CLK_END);
 
-       clk_data.clks = clks;
-       clk_data.clk_num = ARRAY_SIZE(clks);
-       of_clk_add_provider(np, of_clk_src_onecell_get, &clk_data);
+       of_clk_add_hw_provider(np, of_clk_hw_onecell_get, clk_hw_data);
 
        /* Ensure the AHB clk is at 132MHz. */
-       ret = clk_set_rate(clks[IMX6SL_CLK_AHB], 132000000);
+       ret = clk_set_rate(hws[IMX6SL_CLK_AHB]->clk, 132000000);
        if (ret)
                pr_warn("%s: failed to set AHB clock rate %d!\n",
                        __func__, ret);
 
        if (IS_ENABLED(CONFIG_USB_MXS_PHY)) {
-               clk_prepare_enable(clks[IMX6SL_CLK_USBPHY1_GATE]);
-               clk_prepare_enable(clks[IMX6SL_CLK_USBPHY2_GATE]);
+               clk_prepare_enable(hws[IMX6SL_CLK_USBPHY1_GATE]->clk);
+               clk_prepare_enable(hws[IMX6SL_CLK_USBPHY2_GATE]->clk);
        }
 
        /* Audio-related clocks configuration */
-       clk_set_parent(clks[IMX6SL_CLK_SPDIF0_SEL], clks[IMX6SL_CLK_PLL3_PFD3]);
+       clk_set_parent(hws[IMX6SL_CLK_SPDIF0_SEL]->clk, hws[IMX6SL_CLK_PLL3_PFD3]->clk);
 
        /* set PLL5 video as lcdif pix parent clock */
-       clk_set_parent(clks[IMX6SL_CLK_LCDIF_PIX_SEL],
-                       clks[IMX6SL_CLK_PLL5_VIDEO_DIV]);
+       clk_set_parent(hws[IMX6SL_CLK_LCDIF_PIX_SEL]->clk,
+                       hws[IMX6SL_CLK_PLL5_VIDEO_DIV]->clk);
 
-       clk_set_parent(clks[IMX6SL_CLK_LCDIF_AXI_SEL],
-                      clks[IMX6SL_CLK_PLL2_PFD2]);
+       clk_set_parent(hws[IMX6SL_CLK_LCDIF_AXI_SEL]->clk,
+                      hws[IMX6SL_CLK_PLL2_PFD2]->clk);
+
+       for (i = 0; i < ARRAY_SIZE(uart_clk_ids); i++) {
+               int index = uart_clk_ids[i];
+
+               uart_clks[i] = &hws[index]->clk;
+       }
 
        imx_register_uart_clocks(uart_clks);
 }
index 7eea448..5f3e92c 100644 (file)
@@ -7,6 +7,7 @@
 #include <dt-bindings/clock/imx6sll-clock.h>
 #include <linux/clk.h>
 #include <linux/clkdev.h>
+#include <linux/clk-provider.h>
 #include <linux/err.h>
 #include <linux/init.h>
 #include <linux/io.h>
@@ -16,7 +17,6 @@
 #include "clk.h"
 
 #define CCM_ANALOG_PLL_BYPASS          (0x1 << 16)
-#define BM_CCM_CCDR_MMDC_CH0_MASK      (0x2 << 16)
 #define xPLL_CLR(offset)               (offset + 0x8)
 
 static const char *pll_bypass_src_sels[] = { "osc", "dummy", };
@@ -53,8 +53,8 @@ static const char *lcdif_sels[] = { "lcdif_podf", "ipp_di0", "ipp_di1", "ldb_di0
 static const char *epdc_pre_sels[] = { "pll2_bus", "pll3_usb_otg", "pll5_video_div", "pll2_pfd0_352m", "pll2_pfd2_396m", "pll3_pfd2_508m", };
 static const char *epdc_sels[] = { "epdc_podf", "ipp_di0", "ipp_di1", "ldb_di0", "ldb_di1", };
 
-static struct clk *clks[IMX6SLL_CLK_END];
-static struct clk_onecell_data clk_data;
+static struct clk_hw **hws;
+static struct clk_hw_onecell_data *clk_hw_data;
 
 static const struct clk_div_table post_div_table[] = {
        { .val = 2, .div = 1, },
@@ -76,33 +76,43 @@ static u32 share_count_ssi1;
 static u32 share_count_ssi2;
 static u32 share_count_ssi3;
 
-static struct clk ** const uart_clks[] __initconst = {
-       &clks[IMX6SLL_CLK_UART1_IPG],
-       &clks[IMX6SLL_CLK_UART1_SERIAL],
-       &clks[IMX6SLL_CLK_UART2_IPG],
-       &clks[IMX6SLL_CLK_UART2_SERIAL],
-       &clks[IMX6SLL_CLK_UART3_IPG],
-       &clks[IMX6SLL_CLK_UART3_SERIAL],
-       &clks[IMX6SLL_CLK_UART4_IPG],
-       &clks[IMX6SLL_CLK_UART4_SERIAL],
-       &clks[IMX6SLL_CLK_UART5_IPG],
-       &clks[IMX6SLL_CLK_UART5_SERIAL],
-       NULL
+static const int uart_clk_ids[] __initconst = {
+       IMX6SLL_CLK_UART1_IPG,
+       IMX6SLL_CLK_UART1_SERIAL,
+       IMX6SLL_CLK_UART2_IPG,
+       IMX6SLL_CLK_UART2_SERIAL,
+       IMX6SLL_CLK_UART3_IPG,
+       IMX6SLL_CLK_UART3_SERIAL,
+       IMX6SLL_CLK_UART4_IPG,
+       IMX6SLL_CLK_UART4_SERIAL,
+       IMX6SLL_CLK_UART5_IPG,
+       IMX6SLL_CLK_UART5_SERIAL,
 };
 
+static struct clk **uart_clks[ARRAY_SIZE(uart_clk_ids) + 1] __initdata;
+
 static void __init imx6sll_clocks_init(struct device_node *ccm_node)
 {
        struct device_node *np;
        void __iomem *base;
+       int i;
+
+       clk_hw_data = kzalloc(struct_size(clk_hw_data, hws,
+                                         IMX6SLL_CLK_END), GFP_KERNEL);
+       if (WARN_ON(!clk_hw_data))
+               return;
+
+       clk_hw_data->num = IMX6SLL_CLK_END;
+       hws = clk_hw_data->hws;
 
-       clks[IMX6SLL_CLK_DUMMY] = imx_clk_fixed("dummy", 0);
+       hws[IMX6SLL_CLK_DUMMY] = imx_clk_hw_fixed("dummy", 0);
 
-       clks[IMX6SLL_CLK_CKIL] = of_clk_get_by_name(ccm_node, "ckil");
-       clks[IMX6SLL_CLK_OSC] = of_clk_get_by_name(ccm_node, "osc");
+       hws[IMX6SLL_CLK_CKIL] = __clk_get_hw(of_clk_get_by_name(ccm_node, "ckil"));
+       hws[IMX6SLL_CLK_OSC] = __clk_get_hw(of_clk_get_by_name(ccm_node, "osc"));
 
        /* ipp_di clock is external input */
-       clks[IMX6SLL_CLK_IPP_DI0] = of_clk_get_by_name(ccm_node, "ipp_di0");
-       clks[IMX6SLL_CLK_IPP_DI1] = of_clk_get_by_name(ccm_node, "ipp_di1");
+       hws[IMX6SLL_CLK_IPP_DI0] = __clk_get_hw(of_clk_get_by_name(ccm_node, "ipp_di0"));
+       hws[IMX6SLL_CLK_IPP_DI1] = __clk_get_hw(of_clk_get_by_name(ccm_node, "ipp_di1"));
 
        np = of_find_compatible_node(NULL, NULL, "fsl,imx6sll-anatop");
        base = of_iomap(np, 0);
@@ -118,37 +128,37 @@ static void __init imx6sll_clocks_init(struct device_node *ccm_node)
        writel_relaxed(CCM_ANALOG_PLL_BYPASS, base + xPLL_CLR(0xa0));
        writel_relaxed(CCM_ANALOG_PLL_BYPASS, base + xPLL_CLR(0xe0));
 
-       clks[IMX6SLL_PLL1_BYPASS_SRC] = imx_clk_mux("pll1_bypass_src", base + 0x00, 14, 1, pll_bypass_src_sels, ARRAY_SIZE(pll_bypass_src_sels));
-       clks[IMX6SLL_PLL2_BYPASS_SRC] = imx_clk_mux("pll2_bypass_src", base + 0x30, 14, 1, pll_bypass_src_sels, ARRAY_SIZE(pll_bypass_src_sels));
-       clks[IMX6SLL_PLL3_BYPASS_SRC] = imx_clk_mux("pll3_bypass_src", base + 0x10, 14, 1, pll_bypass_src_sels, ARRAY_SIZE(pll_bypass_src_sels));
-       clks[IMX6SLL_PLL4_BYPASS_SRC] = imx_clk_mux("pll4_bypass_src", base + 0x70, 14, 1, pll_bypass_src_sels, ARRAY_SIZE(pll_bypass_src_sels));
-       clks[IMX6SLL_PLL5_BYPASS_SRC] = imx_clk_mux("pll5_bypass_src", base + 0xa0, 14, 1, pll_bypass_src_sels, ARRAY_SIZE(pll_bypass_src_sels));
-       clks[IMX6SLL_PLL6_BYPASS_SRC] = imx_clk_mux("pll6_bypass_src", base + 0xe0, 14, 1, pll_bypass_src_sels, ARRAY_SIZE(pll_bypass_src_sels));
-       clks[IMX6SLL_PLL7_BYPASS_SRC] = imx_clk_mux("pll7_bypass_src", base + 0x20, 14, 1, pll_bypass_src_sels, ARRAY_SIZE(pll_bypass_src_sels));
-
-       clks[IMX6SLL_CLK_PLL1] = imx_clk_pllv3(IMX_PLLV3_SYS,    "pll1", "pll1_bypass_src", base + 0x00, 0x7f);
-       clks[IMX6SLL_CLK_PLL2] = imx_clk_pllv3(IMX_PLLV3_GENERIC, "pll2", "pll2_bypass_src", base + 0x30, 0x1);
-       clks[IMX6SLL_CLK_PLL3] = imx_clk_pllv3(IMX_PLLV3_USB,    "pll3", "pll3_bypass_src", base + 0x10, 0x3);
-       clks[IMX6SLL_CLK_PLL4] = imx_clk_pllv3(IMX_PLLV3_AV,     "pll4", "pll4_bypass_src", base + 0x70, 0x7f);
-       clks[IMX6SLL_CLK_PLL5] = imx_clk_pllv3(IMX_PLLV3_AV,     "pll5", "pll5_bypass_src", base + 0xa0, 0x7f);
-       clks[IMX6SLL_CLK_PLL6] = imx_clk_pllv3(IMX_PLLV3_ENET,   "pll6", "pll6_bypass_src", base + 0xe0, 0x3);
-       clks[IMX6SLL_CLK_PLL7] = imx_clk_pllv3(IMX_PLLV3_USB,    "pll7", "pll7_bypass_src", base + 0x20, 0x3);
-
-       clks[IMX6SLL_PLL1_BYPASS] = imx_clk_mux_flags("pll1_bypass", base + 0x00, 16, 1, pll1_bypass_sels, ARRAY_SIZE(pll1_bypass_sels), CLK_SET_RATE_PARENT);
-       clks[IMX6SLL_PLL2_BYPASS] = imx_clk_mux_flags("pll2_bypass", base + 0x30, 16, 1, pll2_bypass_sels, ARRAY_SIZE(pll2_bypass_sels), CLK_SET_RATE_PARENT);
-       clks[IMX6SLL_PLL3_BYPASS] = imx_clk_mux_flags("pll3_bypass", base + 0x10, 16, 1, pll3_bypass_sels, ARRAY_SIZE(pll3_bypass_sels), CLK_SET_RATE_PARENT);
-       clks[IMX6SLL_PLL4_BYPASS] = imx_clk_mux_flags("pll4_bypass", base + 0x70, 16, 1, pll4_bypass_sels, ARRAY_SIZE(pll4_bypass_sels), CLK_SET_RATE_PARENT);
-       clks[IMX6SLL_PLL5_BYPASS] = imx_clk_mux_flags("pll5_bypass", base + 0xa0, 16, 1, pll5_bypass_sels, ARRAY_SIZE(pll5_bypass_sels), CLK_SET_RATE_PARENT);
-       clks[IMX6SLL_PLL6_BYPASS] = imx_clk_mux_flags("pll6_bypass", base + 0xe0, 16, 1, pll6_bypass_sels, ARRAY_SIZE(pll6_bypass_sels), CLK_SET_RATE_PARENT);
-       clks[IMX6SLL_PLL7_BYPASS] = imx_clk_mux_flags("pll7_bypass", base + 0x20, 16, 1, pll7_bypass_sels, ARRAY_SIZE(pll7_bypass_sels), CLK_SET_RATE_PARENT);
-
-       clks[IMX6SLL_CLK_PLL1_SYS]      = imx_clk_fixed_factor("pll1_sys", "pll1_bypass", 1, 1);
-       clks[IMX6SLL_CLK_PLL2_BUS]      = imx_clk_gate("pll2_bus",         "pll2_bypass", base + 0x30, 13);
-       clks[IMX6SLL_CLK_PLL3_USB_OTG]  = imx_clk_gate("pll3_usb_otg",     "pll3_bypass", base + 0x10, 13);
-       clks[IMX6SLL_CLK_PLL4_AUDIO]    = imx_clk_gate("pll4_audio",       "pll4_bypass", base + 0x70, 13);
-       clks[IMX6SLL_CLK_PLL5_VIDEO]    = imx_clk_gate("pll5_video",       "pll5_bypass", base + 0xa0, 13);
-       clks[IMX6SLL_CLK_PLL6_ENET]     = imx_clk_gate("pll6_enet",        "pll6_bypass", base + 0xe0, 13);
-       clks[IMX6SLL_CLK_PLL7_USB_HOST] = imx_clk_gate("pll7_usb_host",    "pll7_bypass", base + 0x20, 13);
+       hws[IMX6SLL_PLL1_BYPASS_SRC] = imx_clk_hw_mux("pll1_bypass_src", base + 0x00, 14, 1, pll_bypass_src_sels, ARRAY_SIZE(pll_bypass_src_sels));
+       hws[IMX6SLL_PLL2_BYPASS_SRC] = imx_clk_hw_mux("pll2_bypass_src", base + 0x30, 14, 1, pll_bypass_src_sels, ARRAY_SIZE(pll_bypass_src_sels));
+       hws[IMX6SLL_PLL3_BYPASS_SRC] = imx_clk_hw_mux("pll3_bypass_src", base + 0x10, 14, 1, pll_bypass_src_sels, ARRAY_SIZE(pll_bypass_src_sels));
+       hws[IMX6SLL_PLL4_BYPASS_SRC] = imx_clk_hw_mux("pll4_bypass_src", base + 0x70, 14, 1, pll_bypass_src_sels, ARRAY_SIZE(pll_bypass_src_sels));
+       hws[IMX6SLL_PLL5_BYPASS_SRC] = imx_clk_hw_mux("pll5_bypass_src", base + 0xa0, 14, 1, pll_bypass_src_sels, ARRAY_SIZE(pll_bypass_src_sels));
+       hws[IMX6SLL_PLL6_BYPASS_SRC] = imx_clk_hw_mux("pll6_bypass_src", base + 0xe0, 14, 1, pll_bypass_src_sels, ARRAY_SIZE(pll_bypass_src_sels));
+       hws[IMX6SLL_PLL7_BYPASS_SRC] = imx_clk_hw_mux("pll7_bypass_src", base + 0x20, 14, 1, pll_bypass_src_sels, ARRAY_SIZE(pll_bypass_src_sels));
+
+       hws[IMX6SLL_CLK_PLL1] = imx_clk_hw_pllv3(IMX_PLLV3_SYS,  "pll1", "pll1_bypass_src", base + 0x00, 0x7f);
+       hws[IMX6SLL_CLK_PLL2] = imx_clk_hw_pllv3(IMX_PLLV3_GENERIC, "pll2", "pll2_bypass_src", base + 0x30, 0x1);
+       hws[IMX6SLL_CLK_PLL3] = imx_clk_hw_pllv3(IMX_PLLV3_USB,  "pll3", "pll3_bypass_src", base + 0x10, 0x3);
+       hws[IMX6SLL_CLK_PLL4] = imx_clk_hw_pllv3(IMX_PLLV3_AV,   "pll4", "pll4_bypass_src", base + 0x70, 0x7f);
+       hws[IMX6SLL_CLK_PLL5] = imx_clk_hw_pllv3(IMX_PLLV3_AV,   "pll5", "pll5_bypass_src", base + 0xa0, 0x7f);
+       hws[IMX6SLL_CLK_PLL6] = imx_clk_hw_pllv3(IMX_PLLV3_ENET,         "pll6", "pll6_bypass_src", base + 0xe0, 0x3);
+       hws[IMX6SLL_CLK_PLL7] = imx_clk_hw_pllv3(IMX_PLLV3_USB,  "pll7", "pll7_bypass_src", base + 0x20, 0x3);
+
+       hws[IMX6SLL_PLL1_BYPASS] = imx_clk_hw_mux_flags("pll1_bypass", base + 0x00, 16, 1, pll1_bypass_sels, ARRAY_SIZE(pll1_bypass_sels), CLK_SET_RATE_PARENT);
+       hws[IMX6SLL_PLL2_BYPASS] = imx_clk_hw_mux_flags("pll2_bypass", base + 0x30, 16, 1, pll2_bypass_sels, ARRAY_SIZE(pll2_bypass_sels), CLK_SET_RATE_PARENT);
+       hws[IMX6SLL_PLL3_BYPASS] = imx_clk_hw_mux_flags("pll3_bypass", base + 0x10, 16, 1, pll3_bypass_sels, ARRAY_SIZE(pll3_bypass_sels), CLK_SET_RATE_PARENT);
+       hws[IMX6SLL_PLL4_BYPASS] = imx_clk_hw_mux_flags("pll4_bypass", base + 0x70, 16, 1, pll4_bypass_sels, ARRAY_SIZE(pll4_bypass_sels), CLK_SET_RATE_PARENT);
+       hws[IMX6SLL_PLL5_BYPASS] = imx_clk_hw_mux_flags("pll5_bypass", base + 0xa0, 16, 1, pll5_bypass_sels, ARRAY_SIZE(pll5_bypass_sels), CLK_SET_RATE_PARENT);
+       hws[IMX6SLL_PLL6_BYPASS] = imx_clk_hw_mux_flags("pll6_bypass", base + 0xe0, 16, 1, pll6_bypass_sels, ARRAY_SIZE(pll6_bypass_sels), CLK_SET_RATE_PARENT);
+       hws[IMX6SLL_PLL7_BYPASS] = imx_clk_hw_mux_flags("pll7_bypass", base + 0x20, 16, 1, pll7_bypass_sels, ARRAY_SIZE(pll7_bypass_sels), CLK_SET_RATE_PARENT);
+
+       hws[IMX6SLL_CLK_PLL1_SYS]       = imx_clk_hw_fixed_factor("pll1_sys", "pll1_bypass", 1, 1);
+       hws[IMX6SLL_CLK_PLL2_BUS]       = imx_clk_hw_gate("pll2_bus",      "pll2_bypass", base + 0x30, 13);
+       hws[IMX6SLL_CLK_PLL3_USB_OTG]   = imx_clk_hw_gate("pll3_usb_otg",          "pll3_bypass", base + 0x10, 13);
+       hws[IMX6SLL_CLK_PLL4_AUDIO]     = imx_clk_hw_gate("pll4_audio",    "pll4_bypass", base + 0x70, 13);
+       hws[IMX6SLL_CLK_PLL5_VIDEO]     = imx_clk_hw_gate("pll5_video",    "pll5_bypass", base + 0xa0, 13);
+       hws[IMX6SLL_CLK_PLL6_ENET]      = imx_clk_hw_gate("pll6_enet",     "pll6_bypass", base + 0xe0, 13);
+       hws[IMX6SLL_CLK_PLL7_USB_HOST]  = imx_clk_hw_gate("pll7_usb_host",         "pll7_bypass", base + 0x20, 13);
 
        /*
         * Bit 20 is the reserved and read-only bit, we do this only for:
@@ -156,209 +166,213 @@ static void __init imx6sll_clocks_init(struct device_node *ccm_node)
         * - Keep refcount when do usbphy clk_enable/disable, in that case,
         * the clk framework many need to enable/disable usbphy's parent
         */
-       clks[IMX6SLL_CLK_USBPHY1] = imx_clk_gate("usbphy1", "pll3_usb_otg",  base + 0x10, 20);
-       clks[IMX6SLL_CLK_USBPHY2] = imx_clk_gate("usbphy2", "pll7_usb_host", base + 0x20, 20);
+       hws[IMX6SLL_CLK_USBPHY1] = imx_clk_hw_gate("usbphy1", "pll3_usb_otg",  base + 0x10, 20);
+       hws[IMX6SLL_CLK_USBPHY2] = imx_clk_hw_gate("usbphy2", "pll7_usb_host", base + 0x20, 20);
 
        /*
         * usbphy*_gate needs to be on after system boots up, and software
         * never needs to control it anymore.
         */
        if (IS_ENABLED(CONFIG_USB_MXS_PHY)) {
-               clks[IMX6SLL_CLK_USBPHY1_GATE] = imx_clk_gate_flags("usbphy1_gate", "dummy", base + 0x10, 6, CLK_IS_CRITICAL);
-               clks[IMX6SLL_CLK_USBPHY2_GATE] = imx_clk_gate_flags("usbphy2_gate", "dummy", base + 0x20, 6, CLK_IS_CRITICAL);
+               hws[IMX6SLL_CLK_USBPHY1_GATE] = imx_clk_hw_gate_flags("usbphy1_gate", "dummy", base + 0x10, 6, CLK_IS_CRITICAL);
+               hws[IMX6SLL_CLK_USBPHY2_GATE] = imx_clk_hw_gate_flags("usbphy2_gate", "dummy", base + 0x20, 6, CLK_IS_CRITICAL);
        }
 
        /*                                      name               parent_name     reg          idx */
-       clks[IMX6SLL_CLK_PLL2_PFD0] = imx_clk_pfd("pll2_pfd0_352m", "pll2_bus", base + 0x100, 0);
-       clks[IMX6SLL_CLK_PLL2_PFD1] = imx_clk_pfd("pll2_pfd1_594m", "pll2_bus", base + 0x100, 1);
-       clks[IMX6SLL_CLK_PLL2_PFD2] = imx_clk_pfd("pll2_pfd2_396m", "pll2_bus", base + 0x100, 2);
-       clks[IMX6SLL_CLK_PLL2_PFD3] = imx_clk_pfd("pll2_pfd3_594m", "pll2_bus", base + 0x100, 3);
-       clks[IMX6SLL_CLK_PLL3_PFD0] = imx_clk_pfd("pll3_pfd0_720m", "pll3_usb_otg", base + 0xf0, 0);
-       clks[IMX6SLL_CLK_PLL3_PFD1] = imx_clk_pfd("pll3_pfd1_540m", "pll3_usb_otg", base + 0xf0, 1);
-       clks[IMX6SLL_CLK_PLL3_PFD2] = imx_clk_pfd("pll3_pfd2_508m", "pll3_usb_otg", base + 0xf0, 2);
-       clks[IMX6SLL_CLK_PLL3_PFD3] = imx_clk_pfd("pll3_pfd3_454m", "pll3_usb_otg", base + 0xf0, 3);
-
-       clks[IMX6SLL_CLK_PLL4_POST_DIV]  = clk_register_divider_table(NULL, "pll4_post_div", "pll4_audio",
+       hws[IMX6SLL_CLK_PLL2_PFD0] = imx_clk_hw_pfd("pll2_pfd0_352m", "pll2_bus", base + 0x100, 0);
+       hws[IMX6SLL_CLK_PLL2_PFD1] = imx_clk_hw_pfd("pll2_pfd1_594m", "pll2_bus", base + 0x100, 1);
+       hws[IMX6SLL_CLK_PLL2_PFD2] = imx_clk_hw_pfd("pll2_pfd2_396m", "pll2_bus", base + 0x100, 2);
+       hws[IMX6SLL_CLK_PLL2_PFD3] = imx_clk_hw_pfd("pll2_pfd3_594m", "pll2_bus",       base + 0x100, 3);
+       hws[IMX6SLL_CLK_PLL3_PFD0] = imx_clk_hw_pfd("pll3_pfd0_720m", "pll3_usb_otg", base + 0xf0, 0);
+       hws[IMX6SLL_CLK_PLL3_PFD1] = imx_clk_hw_pfd("pll3_pfd1_540m", "pll3_usb_otg", base + 0xf0, 1);
+       hws[IMX6SLL_CLK_PLL3_PFD2] = imx_clk_hw_pfd("pll3_pfd2_508m", "pll3_usb_otg", base + 0xf0, 2);
+       hws[IMX6SLL_CLK_PLL3_PFD3] = imx_clk_hw_pfd("pll3_pfd3_454m", "pll3_usb_otg", base + 0xf0, 3);
+
+       hws[IMX6SLL_CLK_PLL4_POST_DIV]  = clk_hw_register_divider_table(NULL, "pll4_post_div", "pll4_audio",
                 CLK_SET_RATE_PARENT | CLK_SET_RATE_GATE, base + 0x70, 19, 2, 0, post_div_table, &imx_ccm_lock);
-       clks[IMX6SLL_CLK_PLL4_AUDIO_DIV] = clk_register_divider(NULL, "pll4_audio_div", "pll4_post_div",
+       hws[IMX6SLL_CLK_PLL4_AUDIO_DIV] = clk_hw_register_divider(NULL, "pll4_audio_div", "pll4_post_div",
                 CLK_SET_RATE_PARENT | CLK_SET_RATE_GATE, base + 0x170, 15, 1, 0, &imx_ccm_lock);
-       clks[IMX6SLL_CLK_PLL5_POST_DIV]  = clk_register_divider_table(NULL, "pll5_post_div", "pll5_video",
+       hws[IMX6SLL_CLK_PLL5_POST_DIV]  = clk_hw_register_divider_table(NULL, "pll5_post_div", "pll5_video",
                 CLK_SET_RATE_PARENT | CLK_SET_RATE_GATE, base + 0xa0, 19, 2, 0, post_div_table, &imx_ccm_lock);
-       clks[IMX6SLL_CLK_PLL5_VIDEO_DIV] = clk_register_divider_table(NULL, "pll5_video_div", "pll5_post_div",
+       hws[IMX6SLL_CLK_PLL5_VIDEO_DIV] = clk_hw_register_divider_table(NULL, "pll5_video_div", "pll5_post_div",
                 CLK_SET_RATE_PARENT | CLK_SET_RATE_GATE, base + 0x170, 30, 2, 0, video_div_table, &imx_ccm_lock);
 
        /*                                                 name         parent_name      mult  div */
-       clks[IMX6SLL_CLK_PLL2_198M] = imx_clk_fixed_factor("pll2_198m", "pll2_pfd2_396m", 1, 2);
-       clks[IMX6SLL_CLK_PLL3_120M] = imx_clk_fixed_factor("pll3_120m", "pll3_usb_otg",   1, 4);
-       clks[IMX6SLL_CLK_PLL3_80M]  = imx_clk_fixed_factor("pll3_80m",  "pll3_usb_otg",   1, 6);
-       clks[IMX6SLL_CLK_PLL3_60M]  = imx_clk_fixed_factor("pll3_60m",  "pll3_usb_otg",   1, 8);
+       hws[IMX6SLL_CLK_PLL2_198M] = imx_clk_hw_fixed_factor("pll2_198m", "pll2_pfd2_396m", 1, 2);
+       hws[IMX6SLL_CLK_PLL3_120M] = imx_clk_hw_fixed_factor("pll3_120m", "pll3_usb_otg",   1, 4);
+       hws[IMX6SLL_CLK_PLL3_80M]  = imx_clk_hw_fixed_factor("pll3_80m",  "pll3_usb_otg",   1, 6);
+       hws[IMX6SLL_CLK_PLL3_60M]  = imx_clk_hw_fixed_factor("pll3_60m",  "pll3_usb_otg",   1, 8);
 
        np = ccm_node;
        base = of_iomap(np, 0);
        WARN_ON(!base);
 
-       clks[IMX6SLL_CLK_STEP]            = imx_clk_mux("step", base + 0x0c, 8, 1, step_sels, ARRAY_SIZE(step_sels));
-       clks[IMX6SLL_CLK_PLL1_SW]         = imx_clk_mux_flags("pll1_sw",   base + 0x0c, 2,  1, pll1_sw_sels, ARRAY_SIZE(pll1_sw_sels), 0);
-       clks[IMX6SLL_CLK_AXI_ALT_SEL]     = imx_clk_mux("axi_alt_sel",     base + 0x14, 7,  1, axi_alt_sels, ARRAY_SIZE(axi_alt_sels));
-       clks[IMX6SLL_CLK_AXI_SEL]         = imx_clk_mux_flags("axi_sel",   base + 0x14, 6,  1, axi_sels, ARRAY_SIZE(axi_sels), 0);
-       clks[IMX6SLL_CLK_PERIPH_PRE]      = imx_clk_mux("periph_pre",      base + 0x18, 18, 2, periph_pre_sels, ARRAY_SIZE(periph_pre_sels));
-       clks[IMX6SLL_CLK_PERIPH2_PRE]     = imx_clk_mux("periph2_pre",     base + 0x18, 21, 2, periph2_pre_sels, ARRAY_SIZE(periph2_pre_sels));
-       clks[IMX6SLL_CLK_PERIPH_CLK2_SEL]  = imx_clk_mux("periph_clk2_sel",  base + 0x18, 12, 2, periph_clk2_sels, ARRAY_SIZE(periph_clk2_sels));
-       clks[IMX6SLL_CLK_PERIPH2_CLK2_SEL] = imx_clk_mux("periph2_clk2_sel", base + 0x18, 20, 1, periph2_clk2_sels, ARRAY_SIZE(periph2_clk2_sels));
-       clks[IMX6SLL_CLK_USDHC1_SEL]      = imx_clk_mux("usdhc1_sel",   base + 0x1c, 16, 1, usdhc_sels, ARRAY_SIZE(usdhc_sels));
-       clks[IMX6SLL_CLK_USDHC2_SEL]      = imx_clk_mux("usdhc2_sel",   base + 0x1c, 17, 1, usdhc_sels, ARRAY_SIZE(usdhc_sels));
-       clks[IMX6SLL_CLK_USDHC3_SEL]      = imx_clk_mux("usdhc3_sel",   base + 0x1c, 18, 1, usdhc_sels, ARRAY_SIZE(usdhc_sels));
-       clks[IMX6SLL_CLK_SSI1_SEL]        = imx_clk_mux("ssi1_sel",     base + 0x1c, 10, 2, ssi_sels, ARRAY_SIZE(ssi_sels));
-       clks[IMX6SLL_CLK_SSI2_SEL]        = imx_clk_mux("ssi2_sel",     base + 0x1c, 12, 2, ssi_sels, ARRAY_SIZE(ssi_sels));
-       clks[IMX6SLL_CLK_SSI3_SEL]        = imx_clk_mux("ssi3_sel",     base + 0x1c, 14, 2, ssi_sels, ARRAY_SIZE(ssi_sels));
-       clks[IMX6SLL_CLK_PERCLK_SEL]      = imx_clk_mux("perclk_sel",   base + 0x1c, 6,  1, perclk_sels, ARRAY_SIZE(perclk_sels));
-       clks[IMX6SLL_CLK_UART_SEL]        = imx_clk_mux("uart_sel",     base + 0x24, 6,  1, uart_sels, ARRAY_SIZE(uart_sels));
-       clks[IMX6SLL_CLK_SPDIF_SEL]       = imx_clk_mux("spdif_sel",    base + 0x30, 20, 2, spdif_sels, ARRAY_SIZE(spdif_sels));
-       clks[IMX6SLL_CLK_EXTERN_AUDIO_SEL] = imx_clk_mux("extern_audio_sel", base + 0x30, 7,  2, spdif_sels, ARRAY_SIZE(spdif_sels));
-       clks[IMX6SLL_CLK_EPDC_PRE_SEL]    = imx_clk_mux("epdc_pre_sel", base + 0x34, 15, 3, epdc_pre_sels, ARRAY_SIZE(epdc_pre_sels));
-       clks[IMX6SLL_CLK_EPDC_SEL]        = imx_clk_mux("epdc_sel",     base + 0x34, 9, 3, epdc_sels, ARRAY_SIZE(epdc_sels));
-       clks[IMX6SLL_CLK_ECSPI_SEL]       = imx_clk_mux("ecspi_sel",    base + 0x38, 18, 1, ecspi_sels, ARRAY_SIZE(ecspi_sels));
-       clks[IMX6SLL_CLK_LCDIF_PRE_SEL]   = imx_clk_mux("lcdif_pre_sel", base + 0x38, 15, 3, lcdif_pre_sels, ARRAY_SIZE(lcdif_pre_sels));
-       clks[IMX6SLL_CLK_LCDIF_SEL]       = imx_clk_mux("lcdif_sel",     base + 0x38, 9, 3, lcdif_sels, ARRAY_SIZE(lcdif_sels));
-
-       clks[IMX6SLL_CLK_PERIPH]  = imx_clk_busy_mux("periph",  base + 0x14, 25, 1, base + 0x48, 5, periph_sels, ARRAY_SIZE(periph_sels));
-       clks[IMX6SLL_CLK_PERIPH2] = imx_clk_busy_mux("periph2", base + 0x14, 26, 1, base + 0x48, 3, periph2_sels, ARRAY_SIZE(periph2_sels));
-
-       clks[IMX6SLL_CLK_PERIPH_CLK2]   = imx_clk_divider("periph_clk2",   "periph_clk2_sel",   base + 0x14, 27, 3);
-       clks[IMX6SLL_CLK_PERIPH2_CLK2]  = imx_clk_divider("periph2_clk2",  "periph2_clk2_sel",  base + 0x14, 0,  3);
-       clks[IMX6SLL_CLK_IPG]           = imx_clk_divider("ipg",           "ahb",               base + 0x14, 8,  2);
-       clks[IMX6SLL_CLK_LCDIF_PODF]    = imx_clk_divider("lcdif_podf",    "lcdif_pred",        base + 0x18, 23, 3);
-       clks[IMX6SLL_CLK_PERCLK]        = imx_clk_divider("perclk",        "perclk_sel",        base + 0x1c, 0,  6);
-       clks[IMX6SLL_CLK_USDHC3_PODF]   = imx_clk_divider("usdhc3_podf",   "usdhc3_sel",        base + 0x24, 19, 3);
-       clks[IMX6SLL_CLK_USDHC2_PODF]   = imx_clk_divider("usdhc2_podf",   "usdhc2_sel",        base + 0x24, 16, 3);
-       clks[IMX6SLL_CLK_USDHC1_PODF]   = imx_clk_divider("usdhc1_podf",   "usdhc1_sel",        base + 0x24, 11, 3);
-       clks[IMX6SLL_CLK_UART_PODF]     = imx_clk_divider("uart_podf",     "uart_sel",          base + 0x24, 0,  6);
-       clks[IMX6SLL_CLK_SSI3_PRED]     = imx_clk_divider("ssi3_pred",     "ssi3_sel",          base + 0x28, 22, 3);
-       clks[IMX6SLL_CLK_SSI3_PODF]     = imx_clk_divider("ssi3_podf",     "ssi3_pred",         base + 0x28, 16, 6);
-       clks[IMX6SLL_CLK_SSI1_PRED]     = imx_clk_divider("ssi1_pred",     "ssi1_sel",          base + 0x28, 6,  3);
-       clks[IMX6SLL_CLK_SSI1_PODF]     = imx_clk_divider("ssi1_podf",     "ssi1_pred",         base + 0x28, 0,  6);
-       clks[IMX6SLL_CLK_SSI2_PRED]     = imx_clk_divider("ssi2_pred",     "ssi2_sel",          base + 0x2c, 6,  3);
-       clks[IMX6SLL_CLK_SSI2_PODF]     = imx_clk_divider("ssi2_podf",     "ssi2_pred",         base + 0x2c, 0,  6);
-       clks[IMX6SLL_CLK_SPDIF_PRED]    = imx_clk_divider("spdif_pred",    "spdif_sel",         base + 0x30, 25, 3);
-       clks[IMX6SLL_CLK_SPDIF_PODF]    = imx_clk_divider("spdif_podf",    "spdif_pred",        base + 0x30, 22, 3);
-       clks[IMX6SLL_CLK_EXTERN_AUDIO_PRED] = imx_clk_divider("extern_audio_pred", "extern_audio_sel",  base + 0x30, 12, 3);
-       clks[IMX6SLL_CLK_EXTERN_AUDIO_PODF] = imx_clk_divider("extern_audio_podf", "extern_audio_pred", base + 0x30, 9,  3);
-       clks[IMX6SLL_CLK_EPDC_PODF]  = imx_clk_divider("epdc_podf",  "epdc_pre_sel",  base + 0x34, 12, 3);
-       clks[IMX6SLL_CLK_ECSPI_PODF] = imx_clk_divider("ecspi_podf", "ecspi_sel",     base + 0x38, 19, 6);
-       clks[IMX6SLL_CLK_LCDIF_PRED] = imx_clk_divider("lcdif_pred", "lcdif_pre_sel", base + 0x38, 12, 3);
-
-       clks[IMX6SLL_CLK_ARM]           = imx_clk_busy_divider("arm",       "pll1_sw",  base +  0x10, 0,  3,  base + 0x48, 16);
-       clks[IMX6SLL_CLK_MMDC_PODF]     = imx_clk_busy_divider("mmdc_podf", "periph2",  base +  0x14, 3,  3,  base + 0x48, 2);
-       clks[IMX6SLL_CLK_AXI_PODF]      = imx_clk_busy_divider("axi",       "axi_sel",  base +  0x14, 16, 3,  base + 0x48, 0);
-       clks[IMX6SLL_CLK_AHB]           = imx_clk_busy_divider("ahb",       "periph",   base +  0x14, 10, 3,  base + 0x48, 1);
-
-       clks[IMX6SLL_CLK_LDB_DI0_DIV_3_5] = imx_clk_fixed_factor("ldb_di0_div_3_5", "ldb_di0_sel", 2, 7);
-       clks[IMX6SLL_CLK_LDB_DI0_DIV_7]   = imx_clk_fixed_factor("ldb_di0_div_7",   "ldb_di0_sel", 1, 7);
-       clks[IMX6SLL_CLK_LDB_DI1_DIV_3_5] = imx_clk_fixed_factor("ldb_di1_div_3_5", "ldb_di1_sel", 2, 7);
-       clks[IMX6SLL_CLK_LDB_DI1_DIV_7]   = imx_clk_fixed_factor("ldb_di1_div_7",   "ldb_di1_sel", 1, 7);
-
-       clks[IMX6SLL_CLK_LDB_DI0_SEL]   = imx_clk_mux("ldb_di0_sel", base + 0x2c, 9, 3, ldb_di0_sels, ARRAY_SIZE(ldb_di0_sels));
-       clks[IMX6SLL_CLK_LDB_DI1_SEL]   = imx_clk_mux("ldb_di1_sel", base + 0x1c, 7, 3, ldb_di1_sels, ARRAY_SIZE(ldb_di1_sels));
-       clks[IMX6SLL_CLK_LDB_DI0_DIV_SEL] = imx_clk_mux("ldb_di0_div_sel", base + 0x20, 10, 1, ldb_di0_div_sels, ARRAY_SIZE(ldb_di0_div_sels));
-       clks[IMX6SLL_CLK_LDB_DI1_DIV_SEL] = imx_clk_mux("ldb_di1_div_sel", base + 0x20, 10, 1, ldb_di1_div_sels, ARRAY_SIZE(ldb_di1_div_sels));
+       hws[IMX6SLL_CLK_STEP]             = imx_clk_hw_mux("step", base + 0x0c, 8, 1, step_sels, ARRAY_SIZE(step_sels));
+       hws[IMX6SLL_CLK_PLL1_SW]          = imx_clk_hw_mux_flags("pll1_sw",   base + 0x0c, 2,  1, pll1_sw_sels, ARRAY_SIZE(pll1_sw_sels), 0);
+       hws[IMX6SLL_CLK_AXI_ALT_SEL]      = imx_clk_hw_mux("axi_alt_sel",          base + 0x14, 7,  1, axi_alt_sels, ARRAY_SIZE(axi_alt_sels));
+       hws[IMX6SLL_CLK_AXI_SEL]          = imx_clk_hw_mux_flags("axi_sel",   base + 0x14, 6,  1, axi_sels, ARRAY_SIZE(axi_sels), 0);
+       hws[IMX6SLL_CLK_PERIPH_PRE]       = imx_clk_hw_mux("periph_pre",      base + 0x18, 18, 2, periph_pre_sels, ARRAY_SIZE(periph_pre_sels));
+       hws[IMX6SLL_CLK_PERIPH2_PRE]      = imx_clk_hw_mux("periph2_pre",     base + 0x18, 21, 2, periph2_pre_sels, ARRAY_SIZE(periph2_pre_sels));
+       hws[IMX6SLL_CLK_PERIPH_CLK2_SEL]  = imx_clk_hw_mux("periph_clk2_sel",  base + 0x18, 12, 2, periph_clk2_sels, ARRAY_SIZE(periph_clk2_sels));
+       hws[IMX6SLL_CLK_PERIPH2_CLK2_SEL] = imx_clk_hw_mux("periph2_clk2_sel", base + 0x18, 20, 1, periph2_clk2_sels, ARRAY_SIZE(periph2_clk2_sels));
+       hws[IMX6SLL_CLK_USDHC1_SEL]       = imx_clk_hw_mux("usdhc1_sel",   base + 0x1c, 16, 1, usdhc_sels, ARRAY_SIZE(usdhc_sels));
+       hws[IMX6SLL_CLK_USDHC2_SEL]       = imx_clk_hw_mux("usdhc2_sel",   base + 0x1c, 17, 1, usdhc_sels, ARRAY_SIZE(usdhc_sels));
+       hws[IMX6SLL_CLK_USDHC3_SEL]       = imx_clk_hw_mux("usdhc3_sel",   base + 0x1c, 18, 1, usdhc_sels, ARRAY_SIZE(usdhc_sels));
+       hws[IMX6SLL_CLK_SSI1_SEL]         = imx_clk_hw_mux("ssi1_sel",     base + 0x1c, 10, 2, ssi_sels, ARRAY_SIZE(ssi_sels));
+       hws[IMX6SLL_CLK_SSI2_SEL]         = imx_clk_hw_mux("ssi2_sel",     base + 0x1c, 12, 2, ssi_sels, ARRAY_SIZE(ssi_sels));
+       hws[IMX6SLL_CLK_SSI3_SEL]         = imx_clk_hw_mux("ssi3_sel",     base + 0x1c, 14, 2, ssi_sels, ARRAY_SIZE(ssi_sels));
+       hws[IMX6SLL_CLK_PERCLK_SEL]       = imx_clk_hw_mux("perclk_sel",   base + 0x1c, 6,  1, perclk_sels, ARRAY_SIZE(perclk_sels));
+       hws[IMX6SLL_CLK_UART_SEL]         = imx_clk_hw_mux("uart_sel",  base + 0x24, 6,  1, uart_sels, ARRAY_SIZE(uart_sels));
+       hws[IMX6SLL_CLK_SPDIF_SEL]        = imx_clk_hw_mux("spdif_sel", base + 0x30, 20, 2, spdif_sels, ARRAY_SIZE(spdif_sels));
+       hws[IMX6SLL_CLK_EXTERN_AUDIO_SEL] = imx_clk_hw_mux("extern_audio_sel", base + 0x30, 7,  2, spdif_sels, ARRAY_SIZE(spdif_sels));
+       hws[IMX6SLL_CLK_EPDC_PRE_SEL]     = imx_clk_hw_mux("epdc_pre_sel",      base + 0x34, 15, 3, epdc_pre_sels, ARRAY_SIZE(epdc_pre_sels));
+       hws[IMX6SLL_CLK_EPDC_SEL]         = imx_clk_hw_mux("epdc_sel",  base + 0x34, 9, 3, epdc_sels, ARRAY_SIZE(epdc_sels));
+       hws[IMX6SLL_CLK_ECSPI_SEL]        = imx_clk_hw_mux("ecspi_sel", base + 0x38, 18, 1, ecspi_sels, ARRAY_SIZE(ecspi_sels));
+       hws[IMX6SLL_CLK_LCDIF_PRE_SEL]    = imx_clk_hw_mux("lcdif_pre_sel", base + 0x38, 15, 3, lcdif_pre_sels, ARRAY_SIZE(lcdif_pre_sels));
+       hws[IMX6SLL_CLK_LCDIF_SEL]        = imx_clk_hw_mux("lcdif_sel",     base + 0x38, 9, 3, lcdif_sels, ARRAY_SIZE(lcdif_sels));
+
+       hws[IMX6SLL_CLK_PERIPH]  = imx_clk_hw_busy_mux("periph",  base + 0x14, 25, 1, base + 0x48, 5, periph_sels, ARRAY_SIZE(periph_sels));
+       hws[IMX6SLL_CLK_PERIPH2] = imx_clk_hw_busy_mux("periph2", base + 0x14, 26, 1, base + 0x48, 3, periph2_sels, ARRAY_SIZE(periph2_sels));
+
+       hws[IMX6SLL_CLK_PERIPH_CLK2]    = imx_clk_hw_divider("periph_clk2",   "periph_clk2_sel",        base + 0x14, 27, 3);
+       hws[IMX6SLL_CLK_PERIPH2_CLK2]   = imx_clk_hw_divider("periph2_clk2",  "periph2_clk2_sel",       base + 0x14, 0,  3);
+       hws[IMX6SLL_CLK_IPG]            = imx_clk_hw_divider("ipg",        "ahb",       base + 0x14, 8, 2);
+       hws[IMX6SLL_CLK_LCDIF_PODF]     = imx_clk_hw_divider("lcdif_podf",         "lcdif_pred",        base + 0x18, 23, 3);
+       hws[IMX6SLL_CLK_PERCLK] = imx_clk_hw_divider("perclk",     "perclk_sel",        base + 0x1c, 0,  6);
+       hws[IMX6SLL_CLK_USDHC3_PODF]   = imx_clk_hw_divider("usdhc3_podf",   "usdhc3_sel",      base + 0x24, 19, 3);
+       hws[IMX6SLL_CLK_USDHC2_PODF]    = imx_clk_hw_divider("usdhc2_podf",   "usdhc2_sel",     base + 0x24, 16, 3);
+       hws[IMX6SLL_CLK_USDHC1_PODF]    = imx_clk_hw_divider("usdhc1_podf",   "usdhc1_sel",     base + 0x24, 11, 3);
+       hws[IMX6SLL_CLK_UART_PODF]      = imx_clk_hw_divider("uart_podf",          "uart_sel",          base + 0x24, 0,  6);
+       hws[IMX6SLL_CLK_SSI3_PRED]      = imx_clk_hw_divider("ssi3_pred",          "ssi3_sel",          base + 0x28, 22, 3);
+       hws[IMX6SLL_CLK_SSI3_PODF]      = imx_clk_hw_divider("ssi3_podf",          "ssi3_pred",         base + 0x28, 16, 6);
+       hws[IMX6SLL_CLK_SSI1_PRED]      = imx_clk_hw_divider("ssi1_pred",          "ssi1_sel",          base + 0x28, 6,  3);
+       hws[IMX6SLL_CLK_SSI1_PODF]      = imx_clk_hw_divider("ssi1_podf",          "ssi1_pred",         base + 0x28, 0,  6);
+       hws[IMX6SLL_CLK_SSI2_PRED]      = imx_clk_hw_divider("ssi2_pred",          "ssi2_sel",          base + 0x2c, 6,  3);
+       hws[IMX6SLL_CLK_SSI2_PODF]      = imx_clk_hw_divider("ssi2_podf",          "ssi2_pred",         base + 0x2c, 0,  6);
+       hws[IMX6SLL_CLK_SPDIF_PRED]     = imx_clk_hw_divider("spdif_pred",         "spdif_sel",         base + 0x30, 25, 3);
+       hws[IMX6SLL_CLK_SPDIF_PODF]     = imx_clk_hw_divider("spdif_podf",         "spdif_pred",        base + 0x30, 22, 3);
+       hws[IMX6SLL_CLK_EXTERN_AUDIO_PRED] = imx_clk_hw_divider("extern_audio_pred", "extern_audio_sel",  base + 0x30, 12, 3);
+       hws[IMX6SLL_CLK_EXTERN_AUDIO_PODF] = imx_clk_hw_divider("extern_audio_podf", "extern_audio_pred", base + 0x30, 9,  3);
+       hws[IMX6SLL_CLK_EPDC_PODF]  = imx_clk_hw_divider("epdc_podf",  "epdc_pre_sel",  base + 0x34, 12, 3);
+       hws[IMX6SLL_CLK_ECSPI_PODF] = imx_clk_hw_divider("ecspi_podf", "ecspi_sel",     base + 0x38, 19, 6);
+       hws[IMX6SLL_CLK_LCDIF_PRED] = imx_clk_hw_divider("lcdif_pred", "lcdif_pre_sel", base + 0x38, 12, 3);
+
+       hws[IMX6SLL_CLK_ARM]            = imx_clk_hw_busy_divider("arm",        "pll1_sw",      base +  0x10, 0,  3,  base + 0x48, 16);
+       hws[IMX6SLL_CLK_MMDC_PODF]      = imx_clk_hw_busy_divider("mmdc_podf",  "periph2",      base +  0x14, 3,  3,  base + 0x48, 2);
+       hws[IMX6SLL_CLK_AXI_PODF]       = imx_clk_hw_busy_divider("axi",        "axi_sel",      base +  0x14, 16, 3,  base + 0x48, 0);
+       hws[IMX6SLL_CLK_AHB]            = imx_clk_hw_busy_divider("ahb",        "periph",       base +  0x14, 10, 3,  base + 0x48, 1);
+
+       hws[IMX6SLL_CLK_LDB_DI0_DIV_3_5] = imx_clk_hw_fixed_factor("ldb_di0_div_3_5", "ldb_di0_sel", 2, 7);
+       hws[IMX6SLL_CLK_LDB_DI0_DIV_7]    = imx_clk_hw_fixed_factor("ldb_di0_div_7",   "ldb_di0_sel", 1, 7);
+       hws[IMX6SLL_CLK_LDB_DI1_DIV_3_5] = imx_clk_hw_fixed_factor("ldb_di1_div_3_5", "ldb_di1_sel", 2, 7);
+       hws[IMX6SLL_CLK_LDB_DI1_DIV_7]    = imx_clk_hw_fixed_factor("ldb_di1_div_7",   "ldb_di1_sel", 1, 7);
+
+       hws[IMX6SLL_CLK_LDB_DI0_SEL]    = imx_clk_hw_mux("ldb_di0_sel", base + 0x2c, 9, 3, ldb_di0_sels, ARRAY_SIZE(ldb_di0_sels));
+       hws[IMX6SLL_CLK_LDB_DI1_SEL]   = imx_clk_hw_mux("ldb_di1_sel", base + 0x1c, 7, 3, ldb_di1_sels, ARRAY_SIZE(ldb_di1_sels));
+       hws[IMX6SLL_CLK_LDB_DI0_DIV_SEL] = imx_clk_hw_mux("ldb_di0_div_sel", base + 0x20, 10, 1, ldb_di0_div_sels, ARRAY_SIZE(ldb_di0_div_sels));
+       hws[IMX6SLL_CLK_LDB_DI1_DIV_SEL] = imx_clk_hw_mux("ldb_di1_div_sel", base + 0x20, 10, 1, ldb_di1_div_sels, ARRAY_SIZE(ldb_di1_div_sels));
 
        /* CCGR0 */
-       clks[IMX6SLL_CLK_AIPSTZ1]       = imx_clk_gate2_flags("aips_tz1", "ahb", base + 0x68, 0, CLK_IS_CRITICAL);
-       clks[IMX6SLL_CLK_AIPSTZ2]       = imx_clk_gate2_flags("aips_tz2", "ahb", base + 0x68, 2, CLK_IS_CRITICAL);
-       clks[IMX6SLL_CLK_DCP]           = imx_clk_gate2("dcp", "ahb", base + 0x68, 10);
-       clks[IMX6SLL_CLK_UART2_IPG]     = imx_clk_gate2("uart2_ipg", "ipg", base + 0x68, 28);
-       clks[IMX6SLL_CLK_UART2_SERIAL]  = imx_clk_gate2("uart2_serial", "uart_podf", base + 0x68, 28);
-       clks[IMX6SLL_CLK_GPIO2]         = imx_clk_gate2("gpio2", "ipg", base + 0x68, 30);
+       hws[IMX6SLL_CLK_AIPSTZ1]        = imx_clk_hw_gate2_flags("aips_tz1", "ahb", base + 0x68, 0, CLK_IS_CRITICAL);
+       hws[IMX6SLL_CLK_AIPSTZ2]        = imx_clk_hw_gate2_flags("aips_tz2", "ahb", base + 0x68, 2, CLK_IS_CRITICAL);
+       hws[IMX6SLL_CLK_DCP]            = imx_clk_hw_gate2("dcp", "ahb", base + 0x68, 10);
+       hws[IMX6SLL_CLK_UART2_IPG]      = imx_clk_hw_gate2("uart2_ipg", "ipg", base + 0x68, 28);
+       hws[IMX6SLL_CLK_UART2_SERIAL]   = imx_clk_hw_gate2("uart2_serial",      "uart_podf", base + 0x68, 28);
+       hws[IMX6SLL_CLK_GPIO2]          = imx_clk_hw_gate2("gpio2", "ipg", base + 0x68, 30);
 
        /* CCGR1 */
-       clks[IMX6SLL_CLK_ECSPI1]        = imx_clk_gate2("ecspi1",       "ecspi_podf", base + 0x6c, 0);
-       clks[IMX6SLL_CLK_ECSPI2]        = imx_clk_gate2("ecspi2",       "ecspi_podf", base + 0x6c, 2);
-       clks[IMX6SLL_CLK_ECSPI3]        = imx_clk_gate2("ecspi3",       "ecspi_podf", base + 0x6c, 4);
-       clks[IMX6SLL_CLK_ECSPI4]        = imx_clk_gate2("ecspi4",       "ecspi_podf", base + 0x6c, 6);
-       clks[IMX6SLL_CLK_UART3_IPG]     = imx_clk_gate2("uart3_ipg",    "ipg", base + 0x6c, 10);
-       clks[IMX6SLL_CLK_UART3_SERIAL]  = imx_clk_gate2("uart3_serial", "uart_podf", base + 0x6c, 10);
-       clks[IMX6SLL_CLK_EPIT1]         = imx_clk_gate2("epit1",        "perclk", base + 0x6c, 12);
-       clks[IMX6SLL_CLK_EPIT2]         = imx_clk_gate2("epit2",        "perclk", base + 0x6c, 14);
-       clks[IMX6SLL_CLK_GPT_BUS]       = imx_clk_gate2("gpt1_bus",     "perclk", base + 0x6c, 20);
-       clks[IMX6SLL_CLK_GPT_SERIAL]    = imx_clk_gate2("gpt1_serial",  "perclk", base + 0x6c, 22);
-       clks[IMX6SLL_CLK_UART4_IPG]     = imx_clk_gate2("uart4_ipg",    "ipg", base + 0x6c, 24);
-       clks[IMX6SLL_CLK_UART4_SERIAL]  = imx_clk_gate2("uart4_serial", "uart_podf", base + 0x6c, 24);
-       clks[IMX6SLL_CLK_GPIO1]         = imx_clk_gate2("gpio1",        "ipg", base + 0x6c, 26);
-       clks[IMX6SLL_CLK_GPIO5]         = imx_clk_gate2("gpio5",        "ipg", base + 0x6c, 30);
+       hws[IMX6SLL_CLK_ECSPI1] = imx_clk_hw_gate2("ecspi1",    "ecspi_podf", base + 0x6c, 0);
+       hws[IMX6SLL_CLK_ECSPI2] = imx_clk_hw_gate2("ecspi2",    "ecspi_podf", base + 0x6c, 2);
+       hws[IMX6SLL_CLK_ECSPI3] = imx_clk_hw_gate2("ecspi3",    "ecspi_podf", base + 0x6c, 4);
+       hws[IMX6SLL_CLK_ECSPI4] = imx_clk_hw_gate2("ecspi4",    "ecspi_podf", base + 0x6c, 6);
+       hws[IMX6SLL_CLK_UART3_IPG]      = imx_clk_hw_gate2("uart3_ipg", "ipg", base + 0x6c, 10);
+       hws[IMX6SLL_CLK_UART3_SERIAL]   = imx_clk_hw_gate2("uart3_serial",      "uart_podf", base + 0x6c, 10);
+       hws[IMX6SLL_CLK_EPIT1]          = imx_clk_hw_gate2("epit1",     "perclk", base + 0x6c, 12);
+       hws[IMX6SLL_CLK_EPIT2]          = imx_clk_hw_gate2("epit2",     "perclk", base + 0x6c, 14);
+       hws[IMX6SLL_CLK_GPT_BUS]        = imx_clk_hw_gate2("gpt1_bus",  "perclk", base + 0x6c, 20);
+       hws[IMX6SLL_CLK_GPT_SERIAL]     = imx_clk_hw_gate2("gpt1_serial",       "perclk", base + 0x6c, 22);
+       hws[IMX6SLL_CLK_UART4_IPG]      = imx_clk_hw_gate2("uart4_ipg", "ipg", base + 0x6c, 24);
+       hws[IMX6SLL_CLK_UART4_SERIAL]   = imx_clk_hw_gate2("uart4_serial",      "uart_podf", base + 0x6c, 24);
+       hws[IMX6SLL_CLK_GPIO1]          = imx_clk_hw_gate2("gpio1",     "ipg", base + 0x6c, 26);
+       hws[IMX6SLL_CLK_GPIO5]          = imx_clk_hw_gate2("gpio5",     "ipg", base + 0x6c, 30);
 
        /* CCGR2 */
-       clks[IMX6SLL_CLK_GPIO6]         = imx_clk_gate2("gpio6",        "ipg",    base + 0x70, 0);
-       clks[IMX6SLL_CLK_CSI]           = imx_clk_gate2("csi",          "axi",    base + 0x70,  2);
-       clks[IMX6SLL_CLK_I2C1]          = imx_clk_gate2("i2c1",         "perclk", base + 0x70,  6);
-       clks[IMX6SLL_CLK_I2C2]          = imx_clk_gate2("i2c2",         "perclk", base + 0x70,  8);
-       clks[IMX6SLL_CLK_I2C3]          = imx_clk_gate2("i2c3",         "perclk", base + 0x70,  10);
-       clks[IMX6SLL_CLK_OCOTP]         = imx_clk_gate2("ocotp",        "ipg",    base + 0x70,  12);
-       clks[IMX6SLL_CLK_GPIO3]         = imx_clk_gate2("gpio3",        "ipg",    base + 0x70,  26);
-       clks[IMX6SLL_CLK_LCDIF_APB]     = imx_clk_gate2("lcdif_apb",    "axi",    base + 0x70,  28);
-       clks[IMX6SLL_CLK_PXP]           = imx_clk_gate2("pxp",          "axi",    base + 0x70,  30);
+       hws[IMX6SLL_CLK_GPIO6]          = imx_clk_hw_gate2("gpio6",     "ipg",    base + 0x70, 0);
+       hws[IMX6SLL_CLK_CSI]            = imx_clk_hw_gate2("csi",               "axi",    base + 0x70,  2);
+       hws[IMX6SLL_CLK_I2C1]           = imx_clk_hw_gate2("i2c1",              "perclk", base + 0x70,  6);
+       hws[IMX6SLL_CLK_I2C2]           = imx_clk_hw_gate2("i2c2",              "perclk", base + 0x70,  8);
+       hws[IMX6SLL_CLK_I2C3]           = imx_clk_hw_gate2("i2c3",              "perclk", base + 0x70,  10);
+       hws[IMX6SLL_CLK_OCOTP]          = imx_clk_hw_gate2("ocotp",     "ipg",    base + 0x70,  12);
+       hws[IMX6SLL_CLK_GPIO3]          = imx_clk_hw_gate2("gpio3",     "ipg",    base + 0x70,  26);
+       hws[IMX6SLL_CLK_LCDIF_APB]      = imx_clk_hw_gate2("lcdif_apb", "axi",    base + 0x70,  28);
+       hws[IMX6SLL_CLK_PXP]            = imx_clk_hw_gate2("pxp",               "axi",    base + 0x70,  30);
 
        /* CCGR3 */
-       clks[IMX6SLL_CLK_UART5_IPG]     = imx_clk_gate2("uart5_ipg",    "ipg",          base + 0x74, 2);
-       clks[IMX6SLL_CLK_UART5_SERIAL]  = imx_clk_gate2("uart5_serial", "uart_podf",    base + 0x74, 2);
-       clks[IMX6SLL_CLK_EPDC_AXI]      = imx_clk_gate2("epdc_aclk",    "axi",          base + 0x74, 4);
-       clks[IMX6SLL_CLK_EPDC_PIX]      = imx_clk_gate2("epdc_pix",     "epdc_podf",    base + 0x74, 4);
-       clks[IMX6SLL_CLK_LCDIF_PIX]     = imx_clk_gate2("lcdif_pix",    "lcdif_podf",   base + 0x74, 10);
-       clks[IMX6SLL_CLK_GPIO4]         = imx_clk_gate2("gpio4",        "ipg",          base + 0x74, 12);
-       clks[IMX6SLL_CLK_WDOG1]         = imx_clk_gate2("wdog1",        "ipg",          base + 0x74, 16);
-       clks[IMX6SLL_CLK_MMDC_P0_FAST]  = imx_clk_gate_flags("mmdc_p0_fast", "mmdc_podf",  base + 0x74, 20, CLK_IS_CRITICAL);
-       clks[IMX6SLL_CLK_MMDC_P0_IPG]   = imx_clk_gate2_flags("mmdc_p0_ipg", "ipg",        base + 0x74, 24, CLK_IS_CRITICAL);
-       clks[IMX6SLL_CLK_MMDC_P1_IPG]   = imx_clk_gate2("mmdc_p1_ipg", "ipg",      base + 0x74, 26);
-       clks[IMX6SLL_CLK_OCRAM]         = imx_clk_gate_flags("ocram","ahb",                base + 0x74, 28, CLK_IS_CRITICAL);
+       hws[IMX6SLL_CLK_UART5_IPG]      = imx_clk_hw_gate2("uart5_ipg", "ipg",          base + 0x74, 2);
+       hws[IMX6SLL_CLK_UART5_SERIAL]   = imx_clk_hw_gate2("uart5_serial",      "uart_podf",    base + 0x74, 2);
+       hws[IMX6SLL_CLK_EPDC_AXI]       = imx_clk_hw_gate2("epdc_aclk", "axi",          base + 0x74, 4);
+       hws[IMX6SLL_CLK_EPDC_PIX]       = imx_clk_hw_gate2("epdc_pix",  "epdc_podf",    base + 0x74, 4);
+       hws[IMX6SLL_CLK_LCDIF_PIX]      = imx_clk_hw_gate2("lcdif_pix", "lcdif_podf",   base + 0x74, 10);
+       hws[IMX6SLL_CLK_GPIO4]          = imx_clk_hw_gate2("gpio4",     "ipg",          base + 0x74, 12);
+       hws[IMX6SLL_CLK_WDOG1]          = imx_clk_hw_gate2("wdog1",     "ipg",          base + 0x74, 16);
+       hws[IMX6SLL_CLK_MMDC_P0_FAST]   = imx_clk_hw_gate_flags("mmdc_p0_fast", "mmdc_podf",  base + 0x74,      20, CLK_IS_CRITICAL);
+       hws[IMX6SLL_CLK_MMDC_P0_IPG]    = imx_clk_hw_gate2_flags("mmdc_p0_ipg", "ipg",     base + 0x74, 24, CLK_IS_CRITICAL);
+       hws[IMX6SLL_CLK_MMDC_P1_IPG]    = imx_clk_hw_gate2_flags("mmdc_p1_ipg", "ipg",     base + 0x74, 26, CLK_IS_CRITICAL);
+       hws[IMX6SLL_CLK_OCRAM]          = imx_clk_hw_gate_flags("ocram", "ahb",            base + 0x74, 28, CLK_IS_CRITICAL);
 
        /* CCGR4 */
-       clks[IMX6SLL_CLK_PWM1]          = imx_clk_gate2("pwm1", "perclk", base + 0x78, 16);
-       clks[IMX6SLL_CLK_PWM2]          = imx_clk_gate2("pwm2", "perclk", base + 0x78, 18);
-       clks[IMX6SLL_CLK_PWM3]          = imx_clk_gate2("pwm3", "perclk", base + 0x78, 20);
-       clks[IMX6SLL_CLK_PWM4]          = imx_clk_gate2("pwm4", "perclk", base + 0x78, 22);
+       hws[IMX6SLL_CLK_PWM1]           = imx_clk_hw_gate2("pwm1", "perclk", base + 0x78, 16);
+       hws[IMX6SLL_CLK_PWM2]           = imx_clk_hw_gate2("pwm2", "perclk", base + 0x78, 18);
+       hws[IMX6SLL_CLK_PWM3]           = imx_clk_hw_gate2("pwm3", "perclk", base + 0x78, 20);
+       hws[IMX6SLL_CLK_PWM4]           = imx_clk_hw_gate2("pwm4", "perclk", base + 0x78, 22);
 
        /* CCGR5 */
-       clks[IMX6SLL_CLK_ROM]           = imx_clk_gate2_flags("rom", "ahb", base + 0x7c, 0, CLK_IS_CRITICAL);
-       clks[IMX6SLL_CLK_SDMA]          = imx_clk_gate2("sdma",  "ahb", base + 0x7c, 6);
-       clks[IMX6SLL_CLK_WDOG2]         = imx_clk_gate2("wdog2", "ipg", base + 0x7c, 10);
-       clks[IMX6SLL_CLK_SPBA]          = imx_clk_gate2("spba",  "ipg", base + 0x7c, 12);
-       clks[IMX6SLL_CLK_EXTERN_AUDIO]  = imx_clk_gate2_shared("extern_audio",  "extern_audio_podf", base + 0x7c, 14, &share_count_audio);
-       clks[IMX6SLL_CLK_SPDIF]         = imx_clk_gate2_shared("spdif",         "spdif_podf",   base + 0x7c, 14, &share_count_audio);
-       clks[IMX6SLL_CLK_SPDIF_GCLK]    = imx_clk_gate2_shared("spdif_gclk",    "ipg",          base + 0x7c, 14, &share_count_audio);
-       clks[IMX6SLL_CLK_SSI1]          = imx_clk_gate2_shared("ssi1",          "ssi1_podf",    base + 0x7c, 18, &share_count_ssi1);
-       clks[IMX6SLL_CLK_SSI1_IPG]      = imx_clk_gate2_shared("ssi1_ipg",      "ipg",          base + 0x7c, 18, &share_count_ssi1);
-       clks[IMX6SLL_CLK_SSI2]          = imx_clk_gate2_shared("ssi2",          "ssi2_podf",    base + 0x7c, 20, &share_count_ssi2);
-       clks[IMX6SLL_CLK_SSI2_IPG]      = imx_clk_gate2_shared("ssi2_ipg",      "ipg",          base + 0x7c, 20, &share_count_ssi2);
-       clks[IMX6SLL_CLK_SSI3]          = imx_clk_gate2_shared("ssi3",          "ssi3_podf",    base + 0x7c, 22, &share_count_ssi3);
-       clks[IMX6SLL_CLK_SSI3_IPG]      = imx_clk_gate2_shared("ssi3_ipg",      "ipg",          base + 0x7c, 22, &share_count_ssi3);
-       clks[IMX6SLL_CLK_UART1_IPG]     = imx_clk_gate2("uart1_ipg",    "ipg",          base + 0x7c, 24);
-       clks[IMX6SLL_CLK_UART1_SERIAL]  = imx_clk_gate2("uart1_serial", "uart_podf",    base + 0x7c, 24);
+       hws[IMX6SLL_CLK_ROM]            = imx_clk_hw_gate2_flags("rom", "ahb", base + 0x7c, 0, CLK_IS_CRITICAL);
+       hws[IMX6SLL_CLK_SDMA]           = imx_clk_hw_gate2("sdma",       "ahb", base + 0x7c, 6);
+       hws[IMX6SLL_CLK_WDOG2]          = imx_clk_hw_gate2("wdog2", "ipg",      base + 0x7c, 10);
+       hws[IMX6SLL_CLK_SPBA]           = imx_clk_hw_gate2("spba",       "ipg", base + 0x7c, 12);
+       hws[IMX6SLL_CLK_EXTERN_AUDIO]   = imx_clk_hw_gate2_shared("extern_audio",  "extern_audio_podf", base + 0x7c, 14, &share_count_audio);
+       hws[IMX6SLL_CLK_SPDIF]          = imx_clk_hw_gate2_shared("spdif",              "spdif_podf",   base + 0x7c, 14, &share_count_audio);
+       hws[IMX6SLL_CLK_SPDIF_GCLK]     = imx_clk_hw_gate2_shared("spdif_gclk", "ipg",          base + 0x7c, 14, &share_count_audio);
+       hws[IMX6SLL_CLK_SSI1]           = imx_clk_hw_gate2_shared("ssi1",               "ssi1_podf",    base + 0x7c, 18, &share_count_ssi1);
+       hws[IMX6SLL_CLK_SSI1_IPG]       = imx_clk_hw_gate2_shared("ssi1_ipg",   "ipg",          base + 0x7c, 18, &share_count_ssi1);
+       hws[IMX6SLL_CLK_SSI2]           = imx_clk_hw_gate2_shared("ssi2",               "ssi2_podf",    base + 0x7c, 20, &share_count_ssi2);
+       hws[IMX6SLL_CLK_SSI2_IPG]       = imx_clk_hw_gate2_shared("ssi2_ipg",   "ipg",          base + 0x7c, 20, &share_count_ssi2);
+       hws[IMX6SLL_CLK_SSI3]           = imx_clk_hw_gate2_shared("ssi3",               "ssi3_podf",    base + 0x7c, 22, &share_count_ssi3);
+       hws[IMX6SLL_CLK_SSI3_IPG]       = imx_clk_hw_gate2_shared("ssi3_ipg",   "ipg",          base + 0x7c, 22, &share_count_ssi3);
+       hws[IMX6SLL_CLK_UART1_IPG]      = imx_clk_hw_gate2("uart1_ipg", "ipg",          base + 0x7c, 24);
+       hws[IMX6SLL_CLK_UART1_SERIAL]   = imx_clk_hw_gate2("uart1_serial",      "uart_podf",    base + 0x7c, 24);
 
        /* CCGR6 */
-       clks[IMX6SLL_CLK_USBOH3]        = imx_clk_gate2("usboh3", "ipg",          base + 0x80,  0);
-       clks[IMX6SLL_CLK_USDHC1]        = imx_clk_gate2("usdhc1", "usdhc1_podf",  base + 0x80,  2);
-       clks[IMX6SLL_CLK_USDHC2]        = imx_clk_gate2("usdhc2", "usdhc2_podf",  base + 0x80,  4);
-       clks[IMX6SLL_CLK_USDHC3]        = imx_clk_gate2("usdhc3", "usdhc3_podf",  base + 0x80,  6);
+       hws[IMX6SLL_CLK_USBOH3] = imx_clk_hw_gate2("usboh3", "ipg",       base + 0x80,  0);
+       hws[IMX6SLL_CLK_USDHC1] = imx_clk_hw_gate2("usdhc1", "usdhc1_podf",  base + 0x80,       2);
+       hws[IMX6SLL_CLK_USDHC2] = imx_clk_hw_gate2("usdhc2", "usdhc2_podf",  base + 0x80,       4);
+       hws[IMX6SLL_CLK_USDHC3] = imx_clk_hw_gate2("usdhc3", "usdhc3_podf",  base + 0x80,       6);
 
        /* mask handshake of mmdc */
-       writel_relaxed(BM_CCM_CCDR_MMDC_CH0_MASK, base + 0x4);
+       imx_mmdc_mask_handshake(base, 0);
 
-       imx_check_clocks(clks, ARRAY_SIZE(clks));
+       imx_check_clk_hws(hws, IMX6SLL_CLK_END);
 
-       clk_data.clks = clks;
-       clk_data.clk_num = ARRAY_SIZE(clks);
-       of_clk_add_provider(np, of_clk_src_onecell_get, &clk_data);
+       of_clk_add_hw_provider(np, of_clk_hw_onecell_get, clk_hw_data);
+
+       for (i = 0; i < ARRAY_SIZE(uart_clk_ids); i++) {
+               int index = uart_clk_ids[i];
+
+               uart_clks[i] = &hws[index]->clk;
+       }
 
        imx_register_uart_clocks(uart_clks);
 
        /* Lower the AHB clock rate before changing the clock source. */
-       clk_set_rate(clks[IMX6SLL_CLK_AHB], 99000000);
+       clk_set_rate(hws[IMX6SLL_CLK_AHB]->clk, 99000000);
 
        /* Change periph_pre clock to pll2_bus to adjust AXI rate to 264MHz */
-       clk_set_parent(clks[IMX6SLL_CLK_PERIPH_CLK2_SEL], clks[IMX6SLL_CLK_PLL3_USB_OTG]);
-       clk_set_parent(clks[IMX6SLL_CLK_PERIPH], clks[IMX6SLL_CLK_PERIPH_CLK2]);
-       clk_set_parent(clks[IMX6SLL_CLK_PERIPH_PRE], clks[IMX6SLL_CLK_PLL2_BUS]);
-       clk_set_parent(clks[IMX6SLL_CLK_PERIPH], clks[IMX6SLL_CLK_PERIPH_PRE]);
+       clk_set_parent(hws[IMX6SLL_CLK_PERIPH_CLK2_SEL]->clk, hws[IMX6SLL_CLK_PLL3_USB_OTG]->clk);
+       clk_set_parent(hws[IMX6SLL_CLK_PERIPH]->clk, hws[IMX6SLL_CLK_PERIPH_CLK2]->clk);
+       clk_set_parent(hws[IMX6SLL_CLK_PERIPH_PRE]->clk, hws[IMX6SLL_CLK_PLL2_BUS]->clk);
+       clk_set_parent(hws[IMX6SLL_CLK_PERIPH]->clk, hws[IMX6SLL_CLK_PERIPH_PRE]->clk);
 
-       clk_set_rate(clks[IMX6SLL_CLK_AHB], 132000000);
+       clk_set_rate(hws[IMX6SLL_CLK_AHB]->clk, 132000000);
 }
 CLK_OF_DECLARE_DRIVER(imx6sll, "fsl,imx6sll-ccm", imx6sll_clocks_init);
index d243e34..c4685c0 100644 (file)
@@ -6,6 +6,7 @@
 #include <dt-bindings/clock/imx6sx-clock.h>
 #include <linux/clk.h>
 #include <linux/clkdev.h>
+#include <linux/clk-provider.h>
 #include <linux/err.h>
 #include <linux/init.h>
 #include <linux/io.h>
@@ -16,9 +17,6 @@
 
 #include "clk.h"
 
-#define CCDR    0x4
-#define BM_CCM_CCDR_MMDC_CH0_MASK       (0x2 << 16)
-
 static const char *step_sels[]         = { "osc", "pll2_pfd2_396m", };
 static const char *pll1_sw_sels[]      = { "pll1_sys", "step", };
 static const char *periph_pre_sels[]   = { "pll2_bus", "pll2_pfd2_396m", "pll2_pfd0_352m", "pll2_198m", };
@@ -83,8 +81,8 @@ static const char *pll5_bypass_sels[] = { "pll5", "pll5_bypass_src", };
 static const char *pll6_bypass_sels[] = { "pll6", "pll6_bypass_src", };
 static const char *pll7_bypass_sels[] = { "pll7", "pll7_bypass_src", };
 
-static struct clk *clks[IMX6SX_CLK_CLK_END];
-static struct clk_onecell_data clk_data;
+static struct clk_hw **hws;
+static struct clk_hw_onecell_data *clk_hw_data;
 
 static const struct clk_div_table clk_enet_ref_table[] = {
        { .val = 0, .div = 20, },
@@ -118,76 +116,86 @@ static u32 share_count_ssi3;
 static u32 share_count_sai1;
 static u32 share_count_sai2;
 
-static struct clk ** const uart_clks[] __initconst = {
-       &clks[IMX6SX_CLK_UART_IPG],
-       &clks[IMX6SX_CLK_UART_SERIAL],
-       NULL
+static const int uart_clk_ids[] __initconst = {
+       IMX6SX_CLK_UART_IPG,
+       IMX6SX_CLK_UART_SERIAL,
 };
 
+static struct clk **uart_clks[ARRAY_SIZE(uart_clk_ids) + 1] __initdata;
+
 static void __init imx6sx_clocks_init(struct device_node *ccm_node)
 {
        struct device_node *np;
        void __iomem *base;
+       int i;
+
+       clk_hw_data = kzalloc(struct_size(clk_hw_data, hws,
+                                         IMX6SX_CLK_CLK_END), GFP_KERNEL);
+       if (WARN_ON(!clk_hw_data))
+               return;
+
+       clk_hw_data->num = IMX6SX_CLK_CLK_END;
+       hws = clk_hw_data->hws;
 
-       clks[IMX6SX_CLK_DUMMY] = imx_clk_fixed("dummy", 0);
+       hws[IMX6SX_CLK_DUMMY] = imx_clk_hw_fixed("dummy", 0);
 
-       clks[IMX6SX_CLK_CKIL] = of_clk_get_by_name(ccm_node, "ckil");
-       clks[IMX6SX_CLK_OSC] = of_clk_get_by_name(ccm_node, "osc");
+       hws[IMX6SX_CLK_CKIL] = __clk_get_hw(of_clk_get_by_name(ccm_node, "ckil"));
+       hws[IMX6SX_CLK_OSC] = __clk_get_hw(of_clk_get_by_name(ccm_node, "osc"));
 
        /* ipp_di clock is external input */
-       clks[IMX6SX_CLK_IPP_DI0] = of_clk_get_by_name(ccm_node, "ipp_di0");
-       clks[IMX6SX_CLK_IPP_DI1] = of_clk_get_by_name(ccm_node, "ipp_di1");
+       hws[IMX6SX_CLK_IPP_DI0] = __clk_get_hw(of_clk_get_by_name(ccm_node, "ipp_di0"));
+       hws[IMX6SX_CLK_IPP_DI1] = __clk_get_hw(of_clk_get_by_name(ccm_node, "ipp_di1"));
 
        /* Clock source from external clock via CLK1/2 PAD */
-       clks[IMX6SX_CLK_ANACLK1] = of_clk_get_by_name(ccm_node, "anaclk1");
-       clks[IMX6SX_CLK_ANACLK2] = of_clk_get_by_name(ccm_node, "anaclk2");
+       hws[IMX6SX_CLK_ANACLK1] = __clk_get_hw(of_clk_get_by_name(ccm_node, "anaclk1"));
+       hws[IMX6SX_CLK_ANACLK2] = __clk_get_hw(of_clk_get_by_name(ccm_node, "anaclk2"));
 
        np = of_find_compatible_node(NULL, NULL, "fsl,imx6sx-anatop");
        base = of_iomap(np, 0);
        WARN_ON(!base);
        of_node_put(np);
 
-       clks[IMX6SX_PLL1_BYPASS_SRC] = imx_clk_mux("pll1_bypass_src", base + 0x00, 14, 1, pll_bypass_src_sels, ARRAY_SIZE(pll_bypass_src_sels));
-       clks[IMX6SX_PLL2_BYPASS_SRC] = imx_clk_mux("pll2_bypass_src", base + 0x30, 14, 1, pll_bypass_src_sels, ARRAY_SIZE(pll_bypass_src_sels));
-       clks[IMX6SX_PLL3_BYPASS_SRC] = imx_clk_mux("pll3_bypass_src", base + 0x10, 14, 1, pll_bypass_src_sels, ARRAY_SIZE(pll_bypass_src_sels));
-       clks[IMX6SX_PLL4_BYPASS_SRC] = imx_clk_mux("pll4_bypass_src", base + 0x70, 14, 1, pll_bypass_src_sels, ARRAY_SIZE(pll_bypass_src_sels));
-       clks[IMX6SX_PLL5_BYPASS_SRC] = imx_clk_mux("pll5_bypass_src", base + 0xa0, 14, 1, pll_bypass_src_sels, ARRAY_SIZE(pll_bypass_src_sels));
-       clks[IMX6SX_PLL6_BYPASS_SRC] = imx_clk_mux("pll6_bypass_src", base + 0xe0, 14, 1, pll_bypass_src_sels, ARRAY_SIZE(pll_bypass_src_sels));
-       clks[IMX6SX_PLL7_BYPASS_SRC] = imx_clk_mux("pll7_bypass_src", base + 0x20, 14, 1, pll_bypass_src_sels, ARRAY_SIZE(pll_bypass_src_sels));
+       hws[IMX6SX_PLL1_BYPASS_SRC] = imx_clk_hw_mux("pll1_bypass_src", base + 0x00, 14, 1, pll_bypass_src_sels, ARRAY_SIZE(pll_bypass_src_sels));
+       hws[IMX6SX_PLL2_BYPASS_SRC] = imx_clk_hw_mux("pll2_bypass_src", base + 0x30, 14, 1, pll_bypass_src_sels, ARRAY_SIZE(pll_bypass_src_sels));
+       hws[IMX6SX_PLL3_BYPASS_SRC] = imx_clk_hw_mux("pll3_bypass_src", base + 0x10, 14, 1, pll_bypass_src_sels, ARRAY_SIZE(pll_bypass_src_sels));
+       hws[IMX6SX_PLL4_BYPASS_SRC] = imx_clk_hw_mux("pll4_bypass_src", base + 0x70, 14, 1, pll_bypass_src_sels, ARRAY_SIZE(pll_bypass_src_sels));
+       hws[IMX6SX_PLL5_BYPASS_SRC] = imx_clk_hw_mux("pll5_bypass_src", base + 0xa0, 14, 1, pll_bypass_src_sels, ARRAY_SIZE(pll_bypass_src_sels));
+       hws[IMX6SX_PLL6_BYPASS_SRC] = imx_clk_hw_mux("pll6_bypass_src", base + 0xe0, 14, 1, pll_bypass_src_sels, ARRAY_SIZE(pll_bypass_src_sels));
+       hws[IMX6SX_PLL7_BYPASS_SRC] = imx_clk_hw_mux("pll7_bypass_src", base + 0x20, 14, 1, pll_bypass_src_sels, ARRAY_SIZE(pll_bypass_src_sels));
 
        /*                                    type               name    parent_name        base         div_mask */
-       clks[IMX6SX_CLK_PLL1] = imx_clk_pllv3(IMX_PLLV3_SYS,     "pll1", "osc", base + 0x00, 0x7f);
-       clks[IMX6SX_CLK_PLL2] = imx_clk_pllv3(IMX_PLLV3_GENERIC, "pll2", "osc", base + 0x30, 0x1);
-       clks[IMX6SX_CLK_PLL3] = imx_clk_pllv3(IMX_PLLV3_USB,     "pll3", "osc", base + 0x10, 0x3);
-       clks[IMX6SX_CLK_PLL4] = imx_clk_pllv3(IMX_PLLV3_AV,      "pll4", "osc", base + 0x70, 0x7f);
-       clks[IMX6SX_CLK_PLL5] = imx_clk_pllv3(IMX_PLLV3_AV,      "pll5", "osc", base + 0xa0, 0x7f);
-       clks[IMX6SX_CLK_PLL6] = imx_clk_pllv3(IMX_PLLV3_ENET,    "pll6", "osc", base + 0xe0, 0x3);
-       clks[IMX6SX_CLK_PLL7] = imx_clk_pllv3(IMX_PLLV3_USB,     "pll7", "osc", base + 0x20, 0x3);
-
-       clks[IMX6SX_PLL1_BYPASS] = imx_clk_mux_flags("pll1_bypass", base + 0x00, 16, 1, pll1_bypass_sels, ARRAY_SIZE(pll1_bypass_sels), CLK_SET_RATE_PARENT);
-       clks[IMX6SX_PLL2_BYPASS] = imx_clk_mux_flags("pll2_bypass", base + 0x30, 16, 1, pll2_bypass_sels, ARRAY_SIZE(pll2_bypass_sels), CLK_SET_RATE_PARENT);
-       clks[IMX6SX_PLL3_BYPASS] = imx_clk_mux_flags("pll3_bypass", base + 0x10, 16, 1, pll3_bypass_sels, ARRAY_SIZE(pll3_bypass_sels), CLK_SET_RATE_PARENT);
-       clks[IMX6SX_PLL4_BYPASS] = imx_clk_mux_flags("pll4_bypass", base + 0x70, 16, 1, pll4_bypass_sels, ARRAY_SIZE(pll4_bypass_sels), CLK_SET_RATE_PARENT);
-       clks[IMX6SX_PLL5_BYPASS] = imx_clk_mux_flags("pll5_bypass", base + 0xa0, 16, 1, pll5_bypass_sels, ARRAY_SIZE(pll5_bypass_sels), CLK_SET_RATE_PARENT);
-       clks[IMX6SX_PLL6_BYPASS] = imx_clk_mux_flags("pll6_bypass", base + 0xe0, 16, 1, pll6_bypass_sels, ARRAY_SIZE(pll6_bypass_sels), CLK_SET_RATE_PARENT);
-       clks[IMX6SX_PLL7_BYPASS] = imx_clk_mux_flags("pll7_bypass", base + 0x20, 16, 1, pll7_bypass_sels, ARRAY_SIZE(pll7_bypass_sels), CLK_SET_RATE_PARENT);
+       hws[IMX6SX_CLK_PLL1] = imx_clk_hw_pllv3(IMX_PLLV3_SYS,     "pll1", "osc", base + 0x00, 0x7f);
+       hws[IMX6SX_CLK_PLL2] = imx_clk_hw_pllv3(IMX_PLLV3_GENERIC, "pll2", "osc", base + 0x30, 0x1);
+       hws[IMX6SX_CLK_PLL3] = imx_clk_hw_pllv3(IMX_PLLV3_USB,     "pll3", "osc", base + 0x10, 0x3);
+       hws[IMX6SX_CLK_PLL4] = imx_clk_hw_pllv3(IMX_PLLV3_AV,      "pll4", "osc", base + 0x70, 0x7f);
+       hws[IMX6SX_CLK_PLL5] = imx_clk_hw_pllv3(IMX_PLLV3_AV,      "pll5", "osc", base + 0xa0, 0x7f);
+       hws[IMX6SX_CLK_PLL6] = imx_clk_hw_pllv3(IMX_PLLV3_ENET,    "pll6", "osc", base + 0xe0, 0x3);
+       hws[IMX6SX_CLK_PLL7] = imx_clk_hw_pllv3(IMX_PLLV3_USB,     "pll7", "osc", base + 0x20, 0x3);
+
+       hws[IMX6SX_PLL1_BYPASS] = imx_clk_hw_mux_flags("pll1_bypass", base + 0x00, 16, 1, pll1_bypass_sels, ARRAY_SIZE(pll1_bypass_sels), CLK_SET_RATE_PARENT);
+       hws[IMX6SX_PLL2_BYPASS] = imx_clk_hw_mux_flags("pll2_bypass", base + 0x30, 16, 1, pll2_bypass_sels, ARRAY_SIZE(pll2_bypass_sels), CLK_SET_RATE_PARENT);
+       hws[IMX6SX_PLL3_BYPASS] = imx_clk_hw_mux_flags("pll3_bypass", base + 0x10, 16, 1, pll3_bypass_sels, ARRAY_SIZE(pll3_bypass_sels), CLK_SET_RATE_PARENT);
+       hws[IMX6SX_PLL4_BYPASS] = imx_clk_hw_mux_flags("pll4_bypass", base + 0x70, 16, 1, pll4_bypass_sels, ARRAY_SIZE(pll4_bypass_sels), CLK_SET_RATE_PARENT);
+       hws[IMX6SX_PLL5_BYPASS] = imx_clk_hw_mux_flags("pll5_bypass", base + 0xa0, 16, 1, pll5_bypass_sels, ARRAY_SIZE(pll5_bypass_sels), CLK_SET_RATE_PARENT);
+       hws[IMX6SX_PLL6_BYPASS] = imx_clk_hw_mux_flags("pll6_bypass", base + 0xe0, 16, 1, pll6_bypass_sels, ARRAY_SIZE(pll6_bypass_sels), CLK_SET_RATE_PARENT);
+       hws[IMX6SX_PLL7_BYPASS] = imx_clk_hw_mux_flags("pll7_bypass", base + 0x20, 16, 1, pll7_bypass_sels, ARRAY_SIZE(pll7_bypass_sels), CLK_SET_RATE_PARENT);
 
        /* Do not bypass PLLs initially */
-       clk_set_parent(clks[IMX6SX_PLL1_BYPASS], clks[IMX6SX_CLK_PLL1]);
-       clk_set_parent(clks[IMX6SX_PLL2_BYPASS], clks[IMX6SX_CLK_PLL2]);
-       clk_set_parent(clks[IMX6SX_PLL3_BYPASS], clks[IMX6SX_CLK_PLL3]);
-       clk_set_parent(clks[IMX6SX_PLL4_BYPASS], clks[IMX6SX_CLK_PLL4]);
-       clk_set_parent(clks[IMX6SX_PLL5_BYPASS], clks[IMX6SX_CLK_PLL5]);
-       clk_set_parent(clks[IMX6SX_PLL6_BYPASS], clks[IMX6SX_CLK_PLL6]);
-       clk_set_parent(clks[IMX6SX_PLL7_BYPASS], clks[IMX6SX_CLK_PLL7]);
-
-       clks[IMX6SX_CLK_PLL1_SYS]      = imx_clk_gate("pll1_sys",      "pll1_bypass", base + 0x00, 13);
-       clks[IMX6SX_CLK_PLL2_BUS]      = imx_clk_gate("pll2_bus",      "pll2_bypass", base + 0x30, 13);
-       clks[IMX6SX_CLK_PLL3_USB_OTG]  = imx_clk_gate("pll3_usb_otg",  "pll3_bypass", base + 0x10, 13);
-       clks[IMX6SX_CLK_PLL4_AUDIO]    = imx_clk_gate("pll4_audio",    "pll4_bypass", base + 0x70, 13);
-       clks[IMX6SX_CLK_PLL5_VIDEO]    = imx_clk_gate("pll5_video",    "pll5_bypass", base + 0xa0, 13);
-       clks[IMX6SX_CLK_PLL6_ENET]     = imx_clk_gate("pll6_enet",     "pll6_bypass", base + 0xe0, 13);
-       clks[IMX6SX_CLK_PLL7_USB_HOST] = imx_clk_gate("pll7_usb_host", "pll7_bypass", base + 0x20, 13);
+       clk_set_parent(hws[IMX6SX_PLL1_BYPASS]->clk, hws[IMX6SX_CLK_PLL1]->clk);
+       clk_set_parent(hws[IMX6SX_PLL2_BYPASS]->clk, hws[IMX6SX_CLK_PLL2]->clk);
+       clk_set_parent(hws[IMX6SX_PLL3_BYPASS]->clk, hws[IMX6SX_CLK_PLL3]->clk);
+       clk_set_parent(hws[IMX6SX_PLL4_BYPASS]->clk, hws[IMX6SX_CLK_PLL4]->clk);
+       clk_set_parent(hws[IMX6SX_PLL5_BYPASS]->clk, hws[IMX6SX_CLK_PLL5]->clk);
+       clk_set_parent(hws[IMX6SX_PLL6_BYPASS]->clk, hws[IMX6SX_CLK_PLL6]->clk);
+       clk_set_parent(hws[IMX6SX_PLL7_BYPASS]->clk, hws[IMX6SX_CLK_PLL7]->clk);
+
+       hws[IMX6SX_CLK_PLL1_SYS]      = imx_clk_hw_gate("pll1_sys",      "pll1_bypass", base + 0x00, 13);
+       hws[IMX6SX_CLK_PLL2_BUS]      = imx_clk_hw_gate("pll2_bus",      "pll2_bypass", base + 0x30, 13);
+       hws[IMX6SX_CLK_PLL3_USB_OTG]  = imx_clk_hw_gate("pll3_usb_otg",  "pll3_bypass", base + 0x10, 13);
+       hws[IMX6SX_CLK_PLL4_AUDIO]    = imx_clk_hw_gate("pll4_audio",    "pll4_bypass", base + 0x70, 13);
+       hws[IMX6SX_CLK_PLL5_VIDEO]    = imx_clk_hw_gate("pll5_video",    "pll5_bypass", base + 0xa0, 13);
+       hws[IMX6SX_CLK_PLL6_ENET]     = imx_clk_hw_gate("pll6_enet",     "pll6_bypass", base + 0xe0, 13);
+       hws[IMX6SX_CLK_PLL7_USB_HOST] = imx_clk_hw_gate("pll7_usb_host", "pll7_bypass", base + 0x20, 13);
 
        /*
         * Bit 20 is the reserved and read-only bit, we do this only for:
@@ -195,361 +203,363 @@ static void __init imx6sx_clocks_init(struct device_node *ccm_node)
         * - Keep refcount when do usbphy clk_enable/disable, in that case,
         * the clk framework may need to enable/disable usbphy's parent
         */
-       clks[IMX6SX_CLK_USBPHY1] = imx_clk_gate("usbphy1", "pll3_usb_otg",  base + 0x10, 20);
-       clks[IMX6SX_CLK_USBPHY2] = imx_clk_gate("usbphy2", "pll7_usb_host", base + 0x20, 20);
+       hws[IMX6SX_CLK_USBPHY1] = imx_clk_hw_gate("usbphy1", "pll3_usb_otg",  base + 0x10, 20);
+       hws[IMX6SX_CLK_USBPHY2] = imx_clk_hw_gate("usbphy2", "pll7_usb_host", base + 0x20, 20);
 
        /*
         * usbphy*_gate needs to be on after system boots up, and software
         * never needs to control it anymore.
         */
-       clks[IMX6SX_CLK_USBPHY1_GATE] = imx_clk_gate("usbphy1_gate", "dummy", base + 0x10, 6);
-       clks[IMX6SX_CLK_USBPHY2_GATE] = imx_clk_gate("usbphy2_gate", "dummy", base + 0x20, 6);
+       hws[IMX6SX_CLK_USBPHY1_GATE] = imx_clk_hw_gate("usbphy1_gate", "dummy", base + 0x10, 6);
+       hws[IMX6SX_CLK_USBPHY2_GATE] = imx_clk_hw_gate("usbphy2_gate", "dummy", base + 0x20, 6);
 
        /* FIXME 100MHz is used for pcie ref for all imx6 pcie, excepted imx6q */
-       clks[IMX6SX_CLK_PCIE_REF] = imx_clk_fixed_factor("pcie_ref", "pll6_enet", 1, 5);
-       clks[IMX6SX_CLK_PCIE_REF_125M] = imx_clk_gate("pcie_ref_125m", "pcie_ref", base + 0xe0, 19);
+       hws[IMX6SX_CLK_PCIE_REF] = imx_clk_hw_fixed_factor("pcie_ref", "pll6_enet", 1, 5);
+       hws[IMX6SX_CLK_PCIE_REF_125M] = imx_clk_hw_gate("pcie_ref_125m", "pcie_ref", base + 0xe0, 19);
 
-       clks[IMX6SX_CLK_LVDS1_OUT] = imx_clk_gate_exclusive("lvds1_out", "lvds1_sel", base + 0x160, 10, BIT(12));
-       clks[IMX6SX_CLK_LVDS2_OUT] = imx_clk_gate_exclusive("lvds2_out", "lvds2_sel", base + 0x160, 11, BIT(13));
-       clks[IMX6SX_CLK_LVDS1_IN]  = imx_clk_gate_exclusive("lvds1_in",  "anaclk1",   base + 0x160, 12, BIT(10));
-       clks[IMX6SX_CLK_LVDS2_IN]  = imx_clk_gate_exclusive("lvds2_in",  "anaclk2",   base + 0x160, 13, BIT(11));
+       hws[IMX6SX_CLK_LVDS1_OUT] = imx_clk_hw_gate_exclusive("lvds1_out", "lvds1_sel", base + 0x160, 10, BIT(12));
+       hws[IMX6SX_CLK_LVDS2_OUT] = imx_clk_hw_gate_exclusive("lvds2_out", "lvds2_sel", base + 0x160, 11, BIT(13));
+       hws[IMX6SX_CLK_LVDS1_IN]  = imx_clk_hw_gate_exclusive("lvds1_in",  "anaclk1",   base + 0x160, 12, BIT(10));
+       hws[IMX6SX_CLK_LVDS2_IN]  = imx_clk_hw_gate_exclusive("lvds2_in",  "anaclk2",   base + 0x160, 13, BIT(11));
 
-       clks[IMX6SX_CLK_ENET_REF] = clk_register_divider_table(NULL, "enet_ref", "pll6_enet", 0,
+       hws[IMX6SX_CLK_ENET_REF] = clk_hw_register_divider_table(NULL, "enet_ref", "pll6_enet", 0,
                        base + 0xe0, 0, 2, 0, clk_enet_ref_table,
                        &imx_ccm_lock);
-       clks[IMX6SX_CLK_ENET2_REF] = clk_register_divider_table(NULL, "enet2_ref", "pll6_enet", 0,
+       hws[IMX6SX_CLK_ENET2_REF] = clk_hw_register_divider_table(NULL, "enet2_ref", "pll6_enet", 0,
                        base + 0xe0, 2, 2, 0, clk_enet_ref_table,
                        &imx_ccm_lock);
-       clks[IMX6SX_CLK_ENET2_REF_125M] = imx_clk_gate("enet2_ref_125m", "enet2_ref", base + 0xe0, 20);
+       hws[IMX6SX_CLK_ENET2_REF_125M] = imx_clk_hw_gate("enet2_ref_125m", "enet2_ref", base + 0xe0, 20);
 
-       clks[IMX6SX_CLK_ENET_PTP_REF] = imx_clk_fixed_factor("enet_ptp_ref", "pll6_enet", 1, 20);
-       clks[IMX6SX_CLK_ENET_PTP] = imx_clk_gate("enet_ptp_25m", "enet_ptp_ref", base + 0xe0, 21);
+       hws[IMX6SX_CLK_ENET_PTP_REF] = imx_clk_hw_fixed_factor("enet_ptp_ref", "pll6_enet", 1, 20);
+       hws[IMX6SX_CLK_ENET_PTP] = imx_clk_hw_gate("enet_ptp_25m", "enet_ptp_ref", base + 0xe0, 21);
 
        /*                                       name              parent_name     reg           idx */
-       clks[IMX6SX_CLK_PLL2_PFD0] = imx_clk_pfd("pll2_pfd0_352m", "pll2_bus",     base + 0x100, 0);
-       clks[IMX6SX_CLK_PLL2_PFD1] = imx_clk_pfd("pll2_pfd1_594m", "pll2_bus",     base + 0x100, 1);
-       clks[IMX6SX_CLK_PLL2_PFD2] = imx_clk_pfd("pll2_pfd2_396m", "pll2_bus",     base + 0x100, 2);
-       clks[IMX6SX_CLK_PLL2_PFD3] = imx_clk_pfd("pll2_pfd3_594m", "pll2_bus",     base + 0x100, 3);
-       clks[IMX6SX_CLK_PLL3_PFD0] = imx_clk_pfd("pll3_pfd0_720m", "pll3_usb_otg", base + 0xf0,  0);
-       clks[IMX6SX_CLK_PLL3_PFD1] = imx_clk_pfd("pll3_pfd1_540m", "pll3_usb_otg", base + 0xf0,  1);
-       clks[IMX6SX_CLK_PLL3_PFD2] = imx_clk_pfd("pll3_pfd2_508m", "pll3_usb_otg", base + 0xf0,  2);
-       clks[IMX6SX_CLK_PLL3_PFD3] = imx_clk_pfd("pll3_pfd3_454m", "pll3_usb_otg", base + 0xf0,  3);
+       hws[IMX6SX_CLK_PLL2_PFD0] = imx_clk_hw_pfd("pll2_pfd0_352m", "pll2_bus",     base + 0x100, 0);
+       hws[IMX6SX_CLK_PLL2_PFD1] = imx_clk_hw_pfd("pll2_pfd1_594m", "pll2_bus",     base + 0x100, 1);
+       hws[IMX6SX_CLK_PLL2_PFD2] = imx_clk_hw_pfd("pll2_pfd2_396m", "pll2_bus",     base + 0x100, 2);
+       hws[IMX6SX_CLK_PLL2_PFD3] = imx_clk_hw_pfd("pll2_pfd3_594m", "pll2_bus",     base + 0x100, 3);
+       hws[IMX6SX_CLK_PLL3_PFD0] = imx_clk_hw_pfd("pll3_pfd0_720m", "pll3_usb_otg", base + 0xf0,  0);
+       hws[IMX6SX_CLK_PLL3_PFD1] = imx_clk_hw_pfd("pll3_pfd1_540m", "pll3_usb_otg", base + 0xf0,  1);
+       hws[IMX6SX_CLK_PLL3_PFD2] = imx_clk_hw_pfd("pll3_pfd2_508m", "pll3_usb_otg", base + 0xf0,  2);
+       hws[IMX6SX_CLK_PLL3_PFD3] = imx_clk_hw_pfd("pll3_pfd3_454m", "pll3_usb_otg", base + 0xf0,  3);
 
        /*                                                name         parent_name       mult div */
-       clks[IMX6SX_CLK_PLL2_198M] = imx_clk_fixed_factor("pll2_198m", "pll2_pfd2_396m", 1,   2);
-       clks[IMX6SX_CLK_PLL3_120M] = imx_clk_fixed_factor("pll3_120m", "pll3_usb_otg",   1,   4);
-       clks[IMX6SX_CLK_PLL3_80M]  = imx_clk_fixed_factor("pll3_80m",  "pll3_usb_otg",   1,   6);
-       clks[IMX6SX_CLK_PLL3_60M]  = imx_clk_fixed_factor("pll3_60m",  "pll3_usb_otg",   1,   8);
-       clks[IMX6SX_CLK_TWD]       = imx_clk_fixed_factor("twd",       "arm",            1,   2);
-       clks[IMX6SX_CLK_GPT_3M]    = imx_clk_fixed_factor("gpt_3m",    "osc",            1,   8);
-
-       clks[IMX6SX_CLK_PLL4_POST_DIV]  = clk_register_divider_table(NULL, "pll4_post_div", "pll4_audio",
+       hws[IMX6SX_CLK_PLL2_198M] = imx_clk_hw_fixed_factor("pll2_198m", "pll2_pfd2_396m", 1,   2);
+       hws[IMX6SX_CLK_PLL3_120M] = imx_clk_hw_fixed_factor("pll3_120m", "pll3_usb_otg",   1,   4);
+       hws[IMX6SX_CLK_PLL3_80M]  = imx_clk_hw_fixed_factor("pll3_80m",  "pll3_usb_otg",   1,   6);
+       hws[IMX6SX_CLK_PLL3_60M]  = imx_clk_hw_fixed_factor("pll3_60m",  "pll3_usb_otg",   1,   8);
+       hws[IMX6SX_CLK_TWD]       = imx_clk_hw_fixed_factor("twd",       "arm",            1,   2);
+       hws[IMX6SX_CLK_GPT_3M]    = imx_clk_hw_fixed_factor("gpt_3m",    "osc",            1,   8);
+
+       hws[IMX6SX_CLK_PLL4_POST_DIV]  = clk_hw_register_divider_table(NULL, "pll4_post_div", "pll4_audio",
                                CLK_SET_RATE_PARENT, base + 0x70, 19, 2, 0, post_div_table, &imx_ccm_lock);
-       clks[IMX6SX_CLK_PLL4_AUDIO_DIV] = clk_register_divider(NULL, "pll4_audio_div", "pll4_post_div",
+       hws[IMX6SX_CLK_PLL4_AUDIO_DIV] = clk_hw_register_divider(NULL, "pll4_audio_div", "pll4_post_div",
                                CLK_SET_RATE_PARENT, base + 0x170, 15, 1, 0, &imx_ccm_lock);
-       clks[IMX6SX_CLK_PLL5_POST_DIV]  = clk_register_divider_table(NULL, "pll5_post_div", "pll5_video",
+       hws[IMX6SX_CLK_PLL5_POST_DIV]  = clk_hw_register_divider_table(NULL, "pll5_post_div", "pll5_video",
                                CLK_SET_RATE_PARENT, base + 0xa0, 19, 2, 0, post_div_table, &imx_ccm_lock);
-       clks[IMX6SX_CLK_PLL5_VIDEO_DIV] = clk_register_divider_table(NULL, "pll5_video_div", "pll5_post_div",
+       hws[IMX6SX_CLK_PLL5_VIDEO_DIV] = clk_hw_register_divider_table(NULL, "pll5_video_div", "pll5_post_div",
                                CLK_SET_RATE_PARENT, base + 0x170, 30, 2, 0, video_div_table, &imx_ccm_lock);
 
        /*                                                name                reg           shift   width   parent_names       num_parents */
-       clks[IMX6SX_CLK_LVDS1_SEL]          = imx_clk_mux("lvds1_sel",        base + 0x160, 0,      5,      lvds_sels,         ARRAY_SIZE(lvds_sels));
-       clks[IMX6SX_CLK_LVDS2_SEL]          = imx_clk_mux("lvds2_sel",        base + 0x160, 5,      5,      lvds_sels,         ARRAY_SIZE(lvds_sels));
+       hws[IMX6SX_CLK_LVDS1_SEL]          = imx_clk_hw_mux("lvds1_sel",        base + 0x160, 0,      5,      lvds_sels,         ARRAY_SIZE(lvds_sels));
+       hws[IMX6SX_CLK_LVDS2_SEL]          = imx_clk_hw_mux("lvds2_sel",        base + 0x160, 5,      5,      lvds_sels,         ARRAY_SIZE(lvds_sels));
 
        np = ccm_node;
        base = of_iomap(np, 0);
        WARN_ON(!base);
 
        /*                                                name                reg           shift   width   parent_names       num_parents */
-       clks[IMX6SX_CLK_STEP]               = imx_clk_mux("step",             base + 0xc,   8,      1,      step_sels,         ARRAY_SIZE(step_sels));
-       clks[IMX6SX_CLK_PLL1_SW]            = imx_clk_mux("pll1_sw",          base + 0xc,   2,      1,      pll1_sw_sels,      ARRAY_SIZE(pll1_sw_sels));
-       clks[IMX6SX_CLK_OCRAM_SEL]          = imx_clk_mux("ocram_sel",        base + 0x14,  6,      2,      ocram_sels,        ARRAY_SIZE(ocram_sels));
-       clks[IMX6SX_CLK_PERIPH_PRE]         = imx_clk_mux("periph_pre",       base + 0x18,  18,     2,      periph_pre_sels,   ARRAY_SIZE(periph_pre_sels));
-       clks[IMX6SX_CLK_PERIPH2_PRE]        = imx_clk_mux("periph2_pre",      base + 0x18,  21,     2,      periph2_pre_sels,   ARRAY_SIZE(periph2_pre_sels));
-       clks[IMX6SX_CLK_PERIPH_CLK2_SEL]    = imx_clk_mux("periph_clk2_sel",  base + 0x18,  12,     2,      periph_clk2_sels,  ARRAY_SIZE(periph_clk2_sels));
-       clks[IMX6SX_CLK_PERIPH2_CLK2_SEL]   = imx_clk_mux("periph2_clk2_sel", base + 0x18,  20,     1,      periph2_clk2_sels, ARRAY_SIZE(periph2_clk2_sels));
-       clks[IMX6SX_CLK_PCIE_AXI_SEL]       = imx_clk_mux("pcie_axi_sel",     base + 0x18,  10,     1,      pcie_axi_sels,     ARRAY_SIZE(pcie_axi_sels));
-       clks[IMX6SX_CLK_GPU_AXI_SEL]        = imx_clk_mux("gpu_axi_sel",      base + 0x18,  8,      2,      gpu_axi_sels,      ARRAY_SIZE(gpu_axi_sels));
-       clks[IMX6SX_CLK_GPU_CORE_SEL]       = imx_clk_mux("gpu_core_sel",     base + 0x18,  4,      2,      gpu_core_sels,     ARRAY_SIZE(gpu_core_sels));
-       clks[IMX6SX_CLK_EIM_SLOW_SEL]       = imx_clk_mux("eim_slow_sel",     base + 0x1c,  29,     2,      eim_slow_sels,     ARRAY_SIZE(eim_slow_sels));
-       clks[IMX6SX_CLK_USDHC1_SEL]         = imx_clk_mux("usdhc1_sel",       base + 0x1c,  16,     1,      usdhc_sels,        ARRAY_SIZE(usdhc_sels));
-       clks[IMX6SX_CLK_USDHC2_SEL]         = imx_clk_mux("usdhc2_sel",       base + 0x1c,  17,     1,      usdhc_sels,        ARRAY_SIZE(usdhc_sels));
-       clks[IMX6SX_CLK_USDHC3_SEL]         = imx_clk_mux("usdhc3_sel",       base + 0x1c,  18,     1,      usdhc_sels,        ARRAY_SIZE(usdhc_sels));
-       clks[IMX6SX_CLK_USDHC4_SEL]         = imx_clk_mux("usdhc4_sel",       base + 0x1c,  19,     1,      usdhc_sels,        ARRAY_SIZE(usdhc_sels));
-       clks[IMX6SX_CLK_SSI3_SEL]           = imx_clk_mux("ssi3_sel",         base + 0x1c,  14,     2,      ssi_sels,          ARRAY_SIZE(ssi_sels));
-       clks[IMX6SX_CLK_SSI2_SEL]           = imx_clk_mux("ssi2_sel",         base + 0x1c,  12,     2,      ssi_sels,          ARRAY_SIZE(ssi_sels));
-       clks[IMX6SX_CLK_SSI1_SEL]           = imx_clk_mux("ssi1_sel",         base + 0x1c,  10,     2,      ssi_sels,          ARRAY_SIZE(ssi_sels));
-       clks[IMX6SX_CLK_QSPI1_SEL]          = imx_clk_mux_flags("qspi1_sel", base + 0x1c,  7, 3, qspi1_sels, ARRAY_SIZE(qspi1_sels), CLK_SET_RATE_PARENT);
-       clks[IMX6SX_CLK_PERCLK_SEL]         = imx_clk_mux("perclk_sel",       base + 0x1c,  6,      1,      perclk_sels,       ARRAY_SIZE(perclk_sels));
-       clks[IMX6SX_CLK_VID_SEL]            = imx_clk_mux("vid_sel",          base + 0x20,  21,     3,      vid_sels,          ARRAY_SIZE(vid_sels));
-       clks[IMX6SX_CLK_ESAI_SEL]           = imx_clk_mux("esai_sel",         base + 0x20,  19,     2,      audio_sels,        ARRAY_SIZE(audio_sels));
-       clks[IMX6SX_CLK_CAN_SEL]            = imx_clk_mux("can_sel",          base + 0x20,  8,      2,      can_sels,          ARRAY_SIZE(can_sels));
-       clks[IMX6SX_CLK_UART_SEL]           = imx_clk_mux("uart_sel",         base + 0x24,  6,      1,      uart_sels,         ARRAY_SIZE(uart_sels));
-       clks[IMX6SX_CLK_QSPI2_SEL]          = imx_clk_mux_flags("qspi2_sel", base + 0x2c, 15, 3, qspi2_sels, ARRAY_SIZE(qspi2_sels), CLK_SET_RATE_PARENT);
-       clks[IMX6SX_CLK_SPDIF_SEL]          = imx_clk_mux("spdif_sel",        base + 0x30,  20,     2,      audio_sels,        ARRAY_SIZE(audio_sels));
-       clks[IMX6SX_CLK_AUDIO_SEL]          = imx_clk_mux("audio_sel",        base + 0x30,  7,      2,      audio_sels,        ARRAY_SIZE(audio_sels));
-       clks[IMX6SX_CLK_ENET_PRE_SEL]       = imx_clk_mux("enet_pre_sel",     base + 0x34,  15,     3,      enet_pre_sels,     ARRAY_SIZE(enet_pre_sels));
-       clks[IMX6SX_CLK_ENET_SEL]           = imx_clk_mux("enet_sel",         base + 0x34,  9,      3,      enet_sels,         ARRAY_SIZE(enet_sels));
-       clks[IMX6SX_CLK_M4_PRE_SEL]         = imx_clk_mux("m4_pre_sel",       base + 0x34,  6,      3,      m4_pre_sels,       ARRAY_SIZE(m4_pre_sels));
-       clks[IMX6SX_CLK_M4_SEL]             = imx_clk_mux("m4_sel",           base + 0x34,  0,      3,      m4_sels,           ARRAY_SIZE(m4_sels));
-       clks[IMX6SX_CLK_ECSPI_SEL]          = imx_clk_mux("ecspi_sel",        base + 0x38,  18,     1,      ecspi_sels,        ARRAY_SIZE(ecspi_sels));
-       clks[IMX6SX_CLK_LCDIF2_PRE_SEL]     = imx_clk_mux("lcdif2_pre_sel",   base + 0x38,  6,      3,      lcdif2_pre_sels,   ARRAY_SIZE(lcdif2_pre_sels));
-       clks[IMX6SX_CLK_LCDIF2_SEL]         = imx_clk_mux("lcdif2_sel",       base + 0x38,  0,      3,      lcdif2_sels,       ARRAY_SIZE(lcdif2_sels));
-       clks[IMX6SX_CLK_DISPLAY_SEL]        = imx_clk_mux("display_sel",      base + 0x3c,  14,     2,      display_sels,      ARRAY_SIZE(display_sels));
-       clks[IMX6SX_CLK_CSI_SEL]            = imx_clk_mux("csi_sel",          base + 0x3c,  9,      2,      csi_sels,          ARRAY_SIZE(csi_sels));
-       clks[IMX6SX_CLK_CKO1_SEL]           = imx_clk_mux("cko1_sel",         base + 0x60,  0,      4,      cko1_sels,         ARRAY_SIZE(cko1_sels));
-       clks[IMX6SX_CLK_CKO2_SEL]           = imx_clk_mux("cko2_sel",         base + 0x60,  16,     5,      cko2_sels,         ARRAY_SIZE(cko2_sels));
-       clks[IMX6SX_CLK_CKO]                = imx_clk_mux("cko",              base + 0x60,  8,      1,      cko_sels,          ARRAY_SIZE(cko_sels));
-
-       clks[IMX6SX_CLK_LDB_DI1_DIV_SEL]    = imx_clk_mux_flags("ldb_di1_div_sel", base + 0x20, 11, 1, ldb_di1_div_sels, ARRAY_SIZE(ldb_di1_div_sels), CLK_SET_RATE_PARENT);
-       clks[IMX6SX_CLK_LDB_DI0_DIV_SEL]    = imx_clk_mux_flags("ldb_di0_div_sel", base + 0x20, 10, 1, ldb_di0_div_sels, ARRAY_SIZE(ldb_di0_div_sels), CLK_SET_RATE_PARENT);
-       clks[IMX6SX_CLK_LDB_DI1_SEL]        = imx_clk_mux_flags("ldb_di1_sel",     base + 0x2c, 12, 3, ldb_di1_sels,      ARRAY_SIZE(ldb_di1_sels),    CLK_SET_RATE_PARENT);
-       clks[IMX6SX_CLK_LDB_DI0_SEL]        = imx_clk_mux_flags("ldb_di0_sel",     base + 0x2c, 9,  3, ldb_di0_sels,      ARRAY_SIZE(ldb_di0_sels),    CLK_SET_RATE_PARENT);
-       clks[IMX6SX_CLK_LCDIF1_PRE_SEL]     = imx_clk_mux_flags("lcdif1_pre_sel",  base + 0x38, 15, 3, lcdif1_pre_sels,   ARRAY_SIZE(lcdif1_pre_sels), CLK_SET_RATE_PARENT);
-       clks[IMX6SX_CLK_LCDIF1_SEL]         = imx_clk_mux_flags("lcdif1_sel",      base + 0x38, 9,  3, lcdif1_sels,       ARRAY_SIZE(lcdif1_sels),     CLK_SET_RATE_PARENT);
+       hws[IMX6SX_CLK_STEP]               = imx_clk_hw_mux("step",             base + 0xc,   8,      1,      step_sels,         ARRAY_SIZE(step_sels));
+       hws[IMX6SX_CLK_PLL1_SW]            = imx_clk_hw_mux("pll1_sw",          base + 0xc,   2,      1,      pll1_sw_sels,      ARRAY_SIZE(pll1_sw_sels));
+       hws[IMX6SX_CLK_OCRAM_SEL]          = imx_clk_hw_mux("ocram_sel",        base + 0x14,  6,      2,      ocram_sels,        ARRAY_SIZE(ocram_sels));
+       hws[IMX6SX_CLK_PERIPH_PRE]         = imx_clk_hw_mux("periph_pre",       base + 0x18,  18,     2,      periph_pre_sels,   ARRAY_SIZE(periph_pre_sels));
+       hws[IMX6SX_CLK_PERIPH2_PRE]        = imx_clk_hw_mux("periph2_pre",      base + 0x18,  21,     2,      periph2_pre_sels,   ARRAY_SIZE(periph2_pre_sels));
+       hws[IMX6SX_CLK_PERIPH_CLK2_SEL]    = imx_clk_hw_mux("periph_clk2_sel",  base + 0x18,  12,     2,      periph_clk2_sels,  ARRAY_SIZE(periph_clk2_sels));
+       hws[IMX6SX_CLK_PERIPH2_CLK2_SEL]   = imx_clk_hw_mux("periph2_clk2_sel", base + 0x18,  20,     1,      periph2_clk2_sels, ARRAY_SIZE(periph2_clk2_sels));
+       hws[IMX6SX_CLK_PCIE_AXI_SEL]       = imx_clk_hw_mux("pcie_axi_sel",     base + 0x18,  10,     1,      pcie_axi_sels,     ARRAY_SIZE(pcie_axi_sels));
+       hws[IMX6SX_CLK_GPU_AXI_SEL]        = imx_clk_hw_mux("gpu_axi_sel",      base + 0x18,  8,      2,      gpu_axi_sels,      ARRAY_SIZE(gpu_axi_sels));
+       hws[IMX6SX_CLK_GPU_CORE_SEL]       = imx_clk_hw_mux("gpu_core_sel",     base + 0x18,  4,      2,      gpu_core_sels,     ARRAY_SIZE(gpu_core_sels));
+       hws[IMX6SX_CLK_EIM_SLOW_SEL]       = imx_clk_hw_mux("eim_slow_sel",     base + 0x1c,  29,     2,      eim_slow_sels,     ARRAY_SIZE(eim_slow_sels));
+       hws[IMX6SX_CLK_USDHC1_SEL]         = imx_clk_hw_mux("usdhc1_sel",       base + 0x1c,  16,     1,      usdhc_sels,        ARRAY_SIZE(usdhc_sels));
+       hws[IMX6SX_CLK_USDHC2_SEL]         = imx_clk_hw_mux("usdhc2_sel",       base + 0x1c,  17,     1,      usdhc_sels,        ARRAY_SIZE(usdhc_sels));
+       hws[IMX6SX_CLK_USDHC3_SEL]         = imx_clk_hw_mux("usdhc3_sel",       base + 0x1c,  18,     1,      usdhc_sels,        ARRAY_SIZE(usdhc_sels));
+       hws[IMX6SX_CLK_USDHC4_SEL]         = imx_clk_hw_mux("usdhc4_sel",       base + 0x1c,  19,     1,      usdhc_sels,        ARRAY_SIZE(usdhc_sels));
+       hws[IMX6SX_CLK_SSI3_SEL]           = imx_clk_hw_mux("ssi3_sel",         base + 0x1c,  14,     2,      ssi_sels,          ARRAY_SIZE(ssi_sels));
+       hws[IMX6SX_CLK_SSI2_SEL]           = imx_clk_hw_mux("ssi2_sel",         base + 0x1c,  12,     2,      ssi_sels,          ARRAY_SIZE(ssi_sels));
+       hws[IMX6SX_CLK_SSI1_SEL]           = imx_clk_hw_mux("ssi1_sel",         base + 0x1c,  10,     2,      ssi_sels,          ARRAY_SIZE(ssi_sels));
+       hws[IMX6SX_CLK_QSPI1_SEL]          = imx_clk_hw_mux_flags("qspi1_sel", base + 0x1c,  7, 3, qspi1_sels, ARRAY_SIZE(qspi1_sels), CLK_SET_RATE_PARENT);
+       hws[IMX6SX_CLK_PERCLK_SEL]         = imx_clk_hw_mux("perclk_sel",       base + 0x1c,  6,      1,      perclk_sels,       ARRAY_SIZE(perclk_sels));
+       hws[IMX6SX_CLK_VID_SEL]            = imx_clk_hw_mux("vid_sel",          base + 0x20,  21,     3,      vid_sels,          ARRAY_SIZE(vid_sels));
+       hws[IMX6SX_CLK_ESAI_SEL]           = imx_clk_hw_mux("esai_sel",         base + 0x20,  19,     2,      audio_sels,        ARRAY_SIZE(audio_sels));
+       hws[IMX6SX_CLK_CAN_SEL]            = imx_clk_hw_mux("can_sel",          base + 0x20,  8,      2,      can_sels,          ARRAY_SIZE(can_sels));
+       hws[IMX6SX_CLK_UART_SEL]           = imx_clk_hw_mux("uart_sel",         base + 0x24,  6,      1,      uart_sels,         ARRAY_SIZE(uart_sels));
+       hws[IMX6SX_CLK_QSPI2_SEL]          = imx_clk_hw_mux_flags("qspi2_sel", base + 0x2c, 15, 3, qspi2_sels, ARRAY_SIZE(qspi2_sels), CLK_SET_RATE_PARENT);
+       hws[IMX6SX_CLK_SPDIF_SEL]          = imx_clk_hw_mux("spdif_sel",        base + 0x30,  20,     2,      audio_sels,        ARRAY_SIZE(audio_sels));
+       hws[IMX6SX_CLK_AUDIO_SEL]          = imx_clk_hw_mux("audio_sel",        base + 0x30,  7,      2,      audio_sels,        ARRAY_SIZE(audio_sels));
+       hws[IMX6SX_CLK_ENET_PRE_SEL]       = imx_clk_hw_mux("enet_pre_sel",     base + 0x34,  15,     3,      enet_pre_sels,     ARRAY_SIZE(enet_pre_sels));
+       hws[IMX6SX_CLK_ENET_SEL]           = imx_clk_hw_mux("enet_sel",         base + 0x34,  9,      3,      enet_sels,         ARRAY_SIZE(enet_sels));
+       hws[IMX6SX_CLK_M4_PRE_SEL]         = imx_clk_hw_mux("m4_pre_sel",       base + 0x34,  6,      3,      m4_pre_sels,       ARRAY_SIZE(m4_pre_sels));
+       hws[IMX6SX_CLK_M4_SEL]             = imx_clk_hw_mux("m4_sel",           base + 0x34,  0,      3,      m4_sels,           ARRAY_SIZE(m4_sels));
+       hws[IMX6SX_CLK_ECSPI_SEL]          = imx_clk_hw_mux("ecspi_sel",        base + 0x38,  18,     1,      ecspi_sels,        ARRAY_SIZE(ecspi_sels));
+       hws[IMX6SX_CLK_LCDIF2_PRE_SEL]     = imx_clk_hw_mux("lcdif2_pre_sel",   base + 0x38,  6,      3,      lcdif2_pre_sels,   ARRAY_SIZE(lcdif2_pre_sels));
+       hws[IMX6SX_CLK_LCDIF2_SEL]         = imx_clk_hw_mux("lcdif2_sel",       base + 0x38,  0,      3,      lcdif2_sels,       ARRAY_SIZE(lcdif2_sels));
+       hws[IMX6SX_CLK_DISPLAY_SEL]        = imx_clk_hw_mux("display_sel",      base + 0x3c,  14,     2,      display_sels,      ARRAY_SIZE(display_sels));
+       hws[IMX6SX_CLK_CSI_SEL]            = imx_clk_hw_mux("csi_sel",          base + 0x3c,  9,      2,      csi_sels,          ARRAY_SIZE(csi_sels));
+       hws[IMX6SX_CLK_CKO1_SEL]           = imx_clk_hw_mux("cko1_sel",         base + 0x60,  0,      4,      cko1_sels,         ARRAY_SIZE(cko1_sels));
+       hws[IMX6SX_CLK_CKO2_SEL]           = imx_clk_hw_mux("cko2_sel",         base + 0x60,  16,     5,      cko2_sels,         ARRAY_SIZE(cko2_sels));
+       hws[IMX6SX_CLK_CKO]                = imx_clk_hw_mux("cko",              base + 0x60,  8,      1,      cko_sels,          ARRAY_SIZE(cko_sels));
+
+       hws[IMX6SX_CLK_LDB_DI1_DIV_SEL]    = imx_clk_hw_mux_flags("ldb_di1_div_sel", base + 0x20, 11, 1, ldb_di1_div_sels, ARRAY_SIZE(ldb_di1_div_sels), CLK_SET_RATE_PARENT);
+       hws[IMX6SX_CLK_LDB_DI0_DIV_SEL]    = imx_clk_hw_mux_flags("ldb_di0_div_sel", base + 0x20, 10, 1, ldb_di0_div_sels, ARRAY_SIZE(ldb_di0_div_sels), CLK_SET_RATE_PARENT);
+       hws[IMX6SX_CLK_LDB_DI1_SEL]        = imx_clk_hw_mux_flags("ldb_di1_sel",     base + 0x2c, 12, 3, ldb_di1_sels,      ARRAY_SIZE(ldb_di1_sels),    CLK_SET_RATE_PARENT);
+       hws[IMX6SX_CLK_LDB_DI0_SEL]        = imx_clk_hw_mux_flags("ldb_di0_sel",     base + 0x2c, 9,  3, ldb_di0_sels,      ARRAY_SIZE(ldb_di0_sels),    CLK_SET_RATE_PARENT);
+       hws[IMX6SX_CLK_LCDIF1_PRE_SEL]     = imx_clk_hw_mux_flags("lcdif1_pre_sel",  base + 0x38, 15, 3, lcdif1_pre_sels,   ARRAY_SIZE(lcdif1_pre_sels), CLK_SET_RATE_PARENT);
+       hws[IMX6SX_CLK_LCDIF1_SEL]         = imx_clk_hw_mux_flags("lcdif1_sel",      base + 0x38, 9,  3, lcdif1_sels,       ARRAY_SIZE(lcdif1_sels),     CLK_SET_RATE_PARENT);
 
        /*                                                    name              parent_name          reg          shift width */
-       clks[IMX6SX_CLK_PERIPH_CLK2]        = imx_clk_divider("periph_clk2",    "periph_clk2_sel",   base + 0x14, 27,   3);
-       clks[IMX6SX_CLK_PERIPH2_CLK2]       = imx_clk_divider("periph2_clk2",   "periph2_clk2_sel",  base + 0x14, 0,    3);
-       clks[IMX6SX_CLK_IPG]                = imx_clk_divider("ipg",            "ahb",               base + 0x14, 8,    2);
-       clks[IMX6SX_CLK_GPU_CORE_PODF]      = imx_clk_divider("gpu_core_podf",  "gpu_core_sel",      base + 0x18, 29,   3);
-       clks[IMX6SX_CLK_GPU_AXI_PODF]       = imx_clk_divider("gpu_axi_podf",   "gpu_axi_sel",       base + 0x18, 26,   3);
-       clks[IMX6SX_CLK_LCDIF1_PODF]        = imx_clk_divider("lcdif1_podf",    "lcdif1_pred",       base + 0x18, 23,   3);
-       clks[IMX6SX_CLK_QSPI1_PODF]         = imx_clk_divider("qspi1_podf",     "qspi1_sel",         base + 0x1c, 26,   3);
-       clks[IMX6SX_CLK_EIM_SLOW_PODF]      = imx_clk_divider("eim_slow_podf",  "eim_slow_sel",      base + 0x1c, 23,   3);
-       clks[IMX6SX_CLK_LCDIF2_PODF]        = imx_clk_divider("lcdif2_podf",    "lcdif2_pred",       base + 0x1c, 20,   3);
-       clks[IMX6SX_CLK_PERCLK]             = imx_clk_divider_flags("perclk", "perclk_sel", base + 0x1c, 0, 6, CLK_IS_CRITICAL);
-       clks[IMX6SX_CLK_VID_PODF]           = imx_clk_divider("vid_podf",       "vid_sel",           base + 0x20, 24,   2);
-       clks[IMX6SX_CLK_CAN_PODF]           = imx_clk_divider("can_podf",       "can_sel",           base + 0x20, 2,    6);
-       clks[IMX6SX_CLK_USDHC4_PODF]        = imx_clk_divider("usdhc4_podf",    "usdhc4_sel",        base + 0x24, 22,   3);
-       clks[IMX6SX_CLK_USDHC3_PODF]        = imx_clk_divider("usdhc3_podf",    "usdhc3_sel",        base + 0x24, 19,   3);
-       clks[IMX6SX_CLK_USDHC2_PODF]        = imx_clk_divider("usdhc2_podf",    "usdhc2_sel",        base + 0x24, 16,   3);
-       clks[IMX6SX_CLK_USDHC1_PODF]        = imx_clk_divider("usdhc1_podf",    "usdhc1_sel",        base + 0x24, 11,   3);
-       clks[IMX6SX_CLK_UART_PODF]          = imx_clk_divider("uart_podf",      "uart_sel",          base + 0x24, 0,    6);
-       clks[IMX6SX_CLK_ESAI_PRED]          = imx_clk_divider("esai_pred",      "esai_sel",          base + 0x28, 9,    3);
-       clks[IMX6SX_CLK_ESAI_PODF]          = imx_clk_divider("esai_podf",      "esai_pred",         base + 0x28, 25,   3);
-       clks[IMX6SX_CLK_SSI3_PRED]          = imx_clk_divider("ssi3_pred",      "ssi3_sel",          base + 0x28, 22,   3);
-       clks[IMX6SX_CLK_SSI3_PODF]          = imx_clk_divider("ssi3_podf",      "ssi3_pred",         base + 0x28, 16,   6);
-       clks[IMX6SX_CLK_SSI1_PRED]          = imx_clk_divider("ssi1_pred",      "ssi1_sel",          base + 0x28, 6,    3);
-       clks[IMX6SX_CLK_SSI1_PODF]          = imx_clk_divider("ssi1_podf",      "ssi1_pred",         base + 0x28, 0,    6);
-       clks[IMX6SX_CLK_QSPI2_PRED]         = imx_clk_divider("qspi2_pred",     "qspi2_sel",         base + 0x2c, 18,   3);
-       clks[IMX6SX_CLK_QSPI2_PODF]         = imx_clk_divider("qspi2_podf",     "qspi2_pred",        base + 0x2c, 21,   6);
-       clks[IMX6SX_CLK_SSI2_PRED]          = imx_clk_divider("ssi2_pred",      "ssi2_sel",          base + 0x2c, 6,    3);
-       clks[IMX6SX_CLK_SSI2_PODF]          = imx_clk_divider("ssi2_podf",      "ssi2_pred",         base + 0x2c, 0,    6);
-       clks[IMX6SX_CLK_SPDIF_PRED]         = imx_clk_divider("spdif_pred",     "spdif_sel",         base + 0x30, 25,   3);
-       clks[IMX6SX_CLK_SPDIF_PODF]         = imx_clk_divider("spdif_podf",     "spdif_pred",        base + 0x30, 22,   3);
-       clks[IMX6SX_CLK_AUDIO_PRED]         = imx_clk_divider("audio_pred",     "audio_sel",         base + 0x30, 12,   3);
-       clks[IMX6SX_CLK_AUDIO_PODF]         = imx_clk_divider("audio_podf",     "audio_pred",        base + 0x30, 9,    3);
-       clks[IMX6SX_CLK_ENET_PODF]          = imx_clk_divider("enet_podf",      "enet_pre_sel",      base + 0x34, 12,   3);
-       clks[IMX6SX_CLK_M4_PODF]            = imx_clk_divider("m4_podf",        "m4_sel",            base + 0x34, 3,    3);
-       clks[IMX6SX_CLK_ECSPI_PODF]         = imx_clk_divider("ecspi_podf",     "ecspi_sel",         base + 0x38, 19,   6);
-       clks[IMX6SX_CLK_LCDIF1_PRED]        = imx_clk_divider("lcdif1_pred",    "lcdif1_pre_sel",    base + 0x38, 12,   3);
-       clks[IMX6SX_CLK_LCDIF2_PRED]        = imx_clk_divider("lcdif2_pred",    "lcdif2_pre_sel",    base + 0x38, 3,    3);
-       clks[IMX6SX_CLK_DISPLAY_PODF]       = imx_clk_divider("display_podf",   "display_sel",       base + 0x3c, 16,   3);
-       clks[IMX6SX_CLK_CSI_PODF]           = imx_clk_divider("csi_podf",       "csi_sel",           base + 0x3c, 11,   3);
-       clks[IMX6SX_CLK_CKO1_PODF]          = imx_clk_divider("cko1_podf",      "cko1_sel",          base + 0x60, 4,    3);
-       clks[IMX6SX_CLK_CKO2_PODF]          = imx_clk_divider("cko2_podf",      "cko2_sel",          base + 0x60, 21,   3);
-
-       clks[IMX6SX_CLK_LDB_DI0_DIV_3_5]    = imx_clk_fixed_factor("ldb_di0_div_3_5", "ldb_di0_sel", 2, 7);
-       clks[IMX6SX_CLK_LDB_DI0_DIV_7]      = imx_clk_fixed_factor("ldb_di0_div_7",   "ldb_di0_sel", 1, 7);
-       clks[IMX6SX_CLK_LDB_DI1_DIV_3_5]    = imx_clk_fixed_factor("ldb_di1_div_3_5", "ldb_di1_sel", 2, 7);
-       clks[IMX6SX_CLK_LDB_DI1_DIV_7]      = imx_clk_fixed_factor("ldb_di1_div_7",   "ldb_di1_sel", 1, 7);
+       hws[IMX6SX_CLK_PERIPH_CLK2]        = imx_clk_hw_divider("periph_clk2",    "periph_clk2_sel",   base + 0x14, 27,   3);
+       hws[IMX6SX_CLK_PERIPH2_CLK2]       = imx_clk_hw_divider("periph2_clk2",   "periph2_clk2_sel",  base + 0x14, 0,    3);
+       hws[IMX6SX_CLK_IPG]                = imx_clk_hw_divider("ipg",            "ahb",               base + 0x14, 8,    2);
+       hws[IMX6SX_CLK_GPU_CORE_PODF]      = imx_clk_hw_divider("gpu_core_podf",  "gpu_core_sel",      base + 0x18, 29,   3);
+       hws[IMX6SX_CLK_GPU_AXI_PODF]       = imx_clk_hw_divider("gpu_axi_podf",   "gpu_axi_sel",       base + 0x18, 26,   3);
+       hws[IMX6SX_CLK_LCDIF1_PODF]        = imx_clk_hw_divider("lcdif1_podf",    "lcdif1_pred",       base + 0x18, 23,   3);
+       hws[IMX6SX_CLK_QSPI1_PODF]         = imx_clk_hw_divider("qspi1_podf",     "qspi1_sel",         base + 0x1c, 26,   3);
+       hws[IMX6SX_CLK_EIM_SLOW_PODF]      = imx_clk_hw_divider("eim_slow_podf",  "eim_slow_sel",      base + 0x1c, 23,   3);
+       hws[IMX6SX_CLK_LCDIF2_PODF]        = imx_clk_hw_divider("lcdif2_podf",    "lcdif2_pred",       base + 0x1c, 20,   3);
+       hws[IMX6SX_CLK_PERCLK]             = imx_clk_hw_divider_flags("perclk", "perclk_sel", base + 0x1c, 0, 6, CLK_IS_CRITICAL);
+       hws[IMX6SX_CLK_VID_PODF]           = imx_clk_hw_divider("vid_podf",       "vid_sel",           base + 0x20, 24,   2);
+       hws[IMX6SX_CLK_CAN_PODF]           = imx_clk_hw_divider("can_podf",       "can_sel",           base + 0x20, 2,    6);
+       hws[IMX6SX_CLK_USDHC4_PODF]        = imx_clk_hw_divider("usdhc4_podf",    "usdhc4_sel",        base + 0x24, 22,   3);
+       hws[IMX6SX_CLK_USDHC3_PODF]        = imx_clk_hw_divider("usdhc3_podf",    "usdhc3_sel",        base + 0x24, 19,   3);
+       hws[IMX6SX_CLK_USDHC2_PODF]        = imx_clk_hw_divider("usdhc2_podf",    "usdhc2_sel",        base + 0x24, 16,   3);
+       hws[IMX6SX_CLK_USDHC1_PODF]        = imx_clk_hw_divider("usdhc1_podf",    "usdhc1_sel",        base + 0x24, 11,   3);
+       hws[IMX6SX_CLK_UART_PODF]          = imx_clk_hw_divider("uart_podf",      "uart_sel",          base + 0x24, 0,    6);
+       hws[IMX6SX_CLK_ESAI_PRED]          = imx_clk_hw_divider("esai_pred",      "esai_sel",          base + 0x28, 9,    3);
+       hws[IMX6SX_CLK_ESAI_PODF]          = imx_clk_hw_divider("esai_podf",      "esai_pred",         base + 0x28, 25,   3);
+       hws[IMX6SX_CLK_SSI3_PRED]          = imx_clk_hw_divider("ssi3_pred",      "ssi3_sel",          base + 0x28, 22,   3);
+       hws[IMX6SX_CLK_SSI3_PODF]          = imx_clk_hw_divider("ssi3_podf",      "ssi3_pred",         base + 0x28, 16,   6);
+       hws[IMX6SX_CLK_SSI1_PRED]          = imx_clk_hw_divider("ssi1_pred",      "ssi1_sel",          base + 0x28, 6,    3);
+       hws[IMX6SX_CLK_SSI1_PODF]          = imx_clk_hw_divider("ssi1_podf",      "ssi1_pred",         base + 0x28, 0,    6);
+       hws[IMX6SX_CLK_QSPI2_PRED]         = imx_clk_hw_divider("qspi2_pred",     "qspi2_sel",         base + 0x2c, 18,   3);
+       hws[IMX6SX_CLK_QSPI2_PODF]         = imx_clk_hw_divider("qspi2_podf",     "qspi2_pred",        base + 0x2c, 21,   6);
+       hws[IMX6SX_CLK_SSI2_PRED]          = imx_clk_hw_divider("ssi2_pred",      "ssi2_sel",          base + 0x2c, 6,    3);
+       hws[IMX6SX_CLK_SSI2_PODF]          = imx_clk_hw_divider("ssi2_podf",      "ssi2_pred",         base + 0x2c, 0,    6);
+       hws[IMX6SX_CLK_SPDIF_PRED]         = imx_clk_hw_divider("spdif_pred",     "spdif_sel",         base + 0x30, 25,   3);
+       hws[IMX6SX_CLK_SPDIF_PODF]         = imx_clk_hw_divider("spdif_podf",     "spdif_pred",        base + 0x30, 22,   3);
+       hws[IMX6SX_CLK_AUDIO_PRED]         = imx_clk_hw_divider("audio_pred",     "audio_sel",         base + 0x30, 12,   3);
+       hws[IMX6SX_CLK_AUDIO_PODF]         = imx_clk_hw_divider("audio_podf",     "audio_pred",        base + 0x30, 9,    3);
+       hws[IMX6SX_CLK_ENET_PODF]          = imx_clk_hw_divider("enet_podf",      "enet_pre_sel",      base + 0x34, 12,   3);
+       hws[IMX6SX_CLK_M4_PODF]            = imx_clk_hw_divider("m4_podf",        "m4_sel",            base + 0x34, 3,    3);
+       hws[IMX6SX_CLK_ECSPI_PODF]         = imx_clk_hw_divider("ecspi_podf",     "ecspi_sel",         base + 0x38, 19,   6);
+       hws[IMX6SX_CLK_LCDIF1_PRED]        = imx_clk_hw_divider("lcdif1_pred",    "lcdif1_pre_sel",    base + 0x38, 12,   3);
+       hws[IMX6SX_CLK_LCDIF2_PRED]        = imx_clk_hw_divider("lcdif2_pred",    "lcdif2_pre_sel",    base + 0x38, 3,    3);
+       hws[IMX6SX_CLK_DISPLAY_PODF]       = imx_clk_hw_divider("display_podf",   "display_sel",       base + 0x3c, 16,   3);
+       hws[IMX6SX_CLK_CSI_PODF]           = imx_clk_hw_divider("csi_podf",       "csi_sel",           base + 0x3c, 11,   3);
+       hws[IMX6SX_CLK_CKO1_PODF]          = imx_clk_hw_divider("cko1_podf",      "cko1_sel",          base + 0x60, 4,    3);
+       hws[IMX6SX_CLK_CKO2_PODF]          = imx_clk_hw_divider("cko2_podf",      "cko2_sel",          base + 0x60, 21,   3);
+
+       hws[IMX6SX_CLK_LDB_DI0_DIV_3_5]    = imx_clk_hw_fixed_factor("ldb_di0_div_3_5", "ldb_di0_sel", 2, 7);
+       hws[IMX6SX_CLK_LDB_DI0_DIV_7]      = imx_clk_hw_fixed_factor("ldb_di0_div_7",   "ldb_di0_sel", 1, 7);
+       hws[IMX6SX_CLK_LDB_DI1_DIV_3_5]    = imx_clk_hw_fixed_factor("ldb_di1_div_3_5", "ldb_di1_sel", 2, 7);
+       hws[IMX6SX_CLK_LDB_DI1_DIV_7]      = imx_clk_hw_fixed_factor("ldb_di1_div_7",   "ldb_di1_sel", 1, 7);
 
        /*                                               name        reg          shift width busy: reg,   shift parent_names       num_parents */
-       clks[IMX6SX_CLK_PERIPH]       = imx_clk_busy_mux("periph",   base + 0x14, 25,   1,    base + 0x48, 5,    periph_sels,       ARRAY_SIZE(periph_sels));
-       clks[IMX6SX_CLK_PERIPH2]      = imx_clk_busy_mux("periph2",  base + 0x14, 26,   1,    base + 0x48, 3,    periph2_sels,      ARRAY_SIZE(periph2_sels));
+       hws[IMX6SX_CLK_PERIPH]       = imx_clk_hw_busy_mux("periph",   base + 0x14, 25,   1,    base + 0x48, 5,    periph_sels,       ARRAY_SIZE(periph_sels));
+       hws[IMX6SX_CLK_PERIPH2]      = imx_clk_hw_busy_mux("periph2",  base + 0x14, 26,   1,    base + 0x48, 3,    periph2_sels,      ARRAY_SIZE(periph2_sels));
        /*                                                   name             parent_name    reg          shift width busy: reg,   shift */
-       clks[IMX6SX_CLK_OCRAM_PODF]   = imx_clk_busy_divider("ocram_podf",    "ocram_sel",   base + 0x14, 16,   3,    base + 0x48, 0);
-       clks[IMX6SX_CLK_AHB]          = imx_clk_busy_divider("ahb",           "periph",      base + 0x14, 10,   3,    base + 0x48, 1);
-       clks[IMX6SX_CLK_MMDC_PODF]    = imx_clk_busy_divider("mmdc_podf",     "periph2",     base + 0x14, 3,    3,    base + 0x48, 2);
-       clks[IMX6SX_CLK_ARM]          = imx_clk_busy_divider("arm",           "pll1_sw",     base + 0x10, 0,    3,    base + 0x48, 16);
+       hws[IMX6SX_CLK_OCRAM_PODF]   = imx_clk_hw_busy_divider("ocram_podf",    "ocram_sel",   base + 0x14, 16,   3,    base + 0x48, 0);
+       hws[IMX6SX_CLK_AHB]          = imx_clk_hw_busy_divider("ahb",           "periph",      base + 0x14, 10,   3,    base + 0x48, 1);
+       hws[IMX6SX_CLK_MMDC_PODF]    = imx_clk_hw_busy_divider("mmdc_podf",     "periph2",     base + 0x14, 3,    3,    base + 0x48, 2);
+       hws[IMX6SX_CLK_ARM]          = imx_clk_hw_busy_divider("arm",           "pll1_sw",     base + 0x10, 0,    3,    base + 0x48, 16);
 
        /*                                            name             parent_name          reg         shift */
        /* CCGR0 */
-       clks[IMX6SX_CLK_AIPS_TZ1]     = imx_clk_gate2_flags("aips_tz1", "ahb", base + 0x68, 0, CLK_IS_CRITICAL);
-       clks[IMX6SX_CLK_AIPS_TZ2]     = imx_clk_gate2_flags("aips_tz2", "ahb", base + 0x68, 2, CLK_IS_CRITICAL);
-       clks[IMX6SX_CLK_APBH_DMA]     = imx_clk_gate2("apbh_dma",      "usdhc3",            base + 0x68, 4);
-       clks[IMX6SX_CLK_ASRC_MEM]     = imx_clk_gate2_shared("asrc_mem", "ahb",             base + 0x68, 6, &share_count_asrc);
-       clks[IMX6SX_CLK_ASRC_IPG]     = imx_clk_gate2_shared("asrc_ipg", "ahb",             base + 0x68, 6, &share_count_asrc);
-       clks[IMX6SX_CLK_CAAM_MEM]     = imx_clk_gate2("caam_mem",      "ahb",               base + 0x68, 8);
-       clks[IMX6SX_CLK_CAAM_ACLK]    = imx_clk_gate2("caam_aclk",     "ahb",               base + 0x68, 10);
-       clks[IMX6SX_CLK_CAAM_IPG]     = imx_clk_gate2("caam_ipg",      "ipg",               base + 0x68, 12);
-       clks[IMX6SX_CLK_CAN1_IPG]     = imx_clk_gate2("can1_ipg",      "ipg",               base + 0x68, 14);
-       clks[IMX6SX_CLK_CAN1_SERIAL]  = imx_clk_gate2("can1_serial",   "can_podf",          base + 0x68, 16);
-       clks[IMX6SX_CLK_CAN2_IPG]     = imx_clk_gate2("can2_ipg",      "ipg",               base + 0x68, 18);
-       clks[IMX6SX_CLK_CAN2_SERIAL]  = imx_clk_gate2("can2_serial",   "can_podf",          base + 0x68, 20);
-       clks[IMX6SX_CLK_DCIC1]        = imx_clk_gate2("dcic1",         "display_podf",      base + 0x68, 24);
-       clks[IMX6SX_CLK_DCIC2]        = imx_clk_gate2("dcic2",         "display_podf",      base + 0x68, 26);
-       clks[IMX6SX_CLK_AIPS_TZ3]     = imx_clk_gate2_flags("aips_tz3", "ahb", base + 0x68, 30, CLK_IS_CRITICAL);
+       hws[IMX6SX_CLK_AIPS_TZ1]     = imx_clk_hw_gate2_flags("aips_tz1", "ahb", base + 0x68, 0, CLK_IS_CRITICAL);
+       hws[IMX6SX_CLK_AIPS_TZ2]     = imx_clk_hw_gate2_flags("aips_tz2", "ahb", base + 0x68, 2, CLK_IS_CRITICAL);
+       hws[IMX6SX_CLK_APBH_DMA]     = imx_clk_hw_gate2("apbh_dma",      "usdhc3",            base + 0x68, 4);
+       hws[IMX6SX_CLK_ASRC_MEM]     = imx_clk_hw_gate2_shared("asrc_mem", "ahb",             base + 0x68, 6, &share_count_asrc);
+       hws[IMX6SX_CLK_ASRC_IPG]     = imx_clk_hw_gate2_shared("asrc_ipg", "ahb",             base + 0x68, 6, &share_count_asrc);
+       hws[IMX6SX_CLK_CAAM_MEM]     = imx_clk_hw_gate2("caam_mem",      "ahb",               base + 0x68, 8);
+       hws[IMX6SX_CLK_CAAM_ACLK]    = imx_clk_hw_gate2("caam_aclk",     "ahb",               base + 0x68, 10);
+       hws[IMX6SX_CLK_CAAM_IPG]     = imx_clk_hw_gate2("caam_ipg",      "ipg",               base + 0x68, 12);
+       hws[IMX6SX_CLK_CAN1_IPG]     = imx_clk_hw_gate2("can1_ipg",      "ipg",               base + 0x68, 14);
+       hws[IMX6SX_CLK_CAN1_SERIAL]  = imx_clk_hw_gate2("can1_serial",   "can_podf",          base + 0x68, 16);
+       hws[IMX6SX_CLK_CAN2_IPG]     = imx_clk_hw_gate2("can2_ipg",      "ipg",               base + 0x68, 18);
+       hws[IMX6SX_CLK_CAN2_SERIAL]  = imx_clk_hw_gate2("can2_serial",   "can_podf",          base + 0x68, 20);
+       hws[IMX6SX_CLK_DCIC1]        = imx_clk_hw_gate2("dcic1",         "display_podf",      base + 0x68, 24);
+       hws[IMX6SX_CLK_DCIC2]        = imx_clk_hw_gate2("dcic2",         "display_podf",      base + 0x68, 26);
+       hws[IMX6SX_CLK_AIPS_TZ3]     = imx_clk_hw_gate2_flags("aips_tz3", "ahb", base + 0x68, 30, CLK_IS_CRITICAL);
 
        /* CCGR1 */
-       clks[IMX6SX_CLK_ECSPI1]       = imx_clk_gate2("ecspi1",        "ecspi_podf",        base + 0x6c, 0);
-       clks[IMX6SX_CLK_ECSPI2]       = imx_clk_gate2("ecspi2",        "ecspi_podf",        base + 0x6c, 2);
-       clks[IMX6SX_CLK_ECSPI3]       = imx_clk_gate2("ecspi3",        "ecspi_podf",        base + 0x6c, 4);
-       clks[IMX6SX_CLK_ECSPI4]       = imx_clk_gate2("ecspi4",        "ecspi_podf",        base + 0x6c, 6);
-       clks[IMX6SX_CLK_ECSPI5]       = imx_clk_gate2("ecspi5",        "ecspi_podf",        base + 0x6c, 8);
-       clks[IMX6SX_CLK_EPIT1]        = imx_clk_gate2("epit1",         "perclk",            base + 0x6c, 12);
-       clks[IMX6SX_CLK_EPIT2]        = imx_clk_gate2("epit2",         "perclk",            base + 0x6c, 14);
-       clks[IMX6SX_CLK_ESAI_EXTAL]   = imx_clk_gate2_shared("esai_extal", "esai_podf",     base + 0x6c, 16, &share_count_esai);
-       clks[IMX6SX_CLK_ESAI_IPG]     = imx_clk_gate2_shared("esai_ipg",   "ahb",           base + 0x6c, 16, &share_count_esai);
-       clks[IMX6SX_CLK_ESAI_MEM]     = imx_clk_gate2_shared("esai_mem",   "ahb",           base + 0x6c, 16, &share_count_esai);
-       clks[IMX6SX_CLK_WAKEUP]       = imx_clk_gate2_flags("wakeup", "ipg", base + 0x6c, 18, CLK_IS_CRITICAL);
-       clks[IMX6SX_CLK_GPT_BUS]      = imx_clk_gate2("gpt_bus",       "perclk",            base + 0x6c, 20);
-       clks[IMX6SX_CLK_GPT_SERIAL]   = imx_clk_gate2("gpt_serial",    "perclk",            base + 0x6c, 22);
-       clks[IMX6SX_CLK_GPU]          = imx_clk_gate2("gpu",           "gpu_core_podf",     base + 0x6c, 26);
-       clks[IMX6SX_CLK_OCRAM_S]      = imx_clk_gate2("ocram_s",       "ahb",               base + 0x6c, 28);
-       clks[IMX6SX_CLK_CANFD]        = imx_clk_gate2("canfd",         "can_podf",          base + 0x6c, 30);
+       hws[IMX6SX_CLK_ECSPI1]       = imx_clk_hw_gate2("ecspi1",        "ecspi_podf",        base + 0x6c, 0);
+       hws[IMX6SX_CLK_ECSPI2]       = imx_clk_hw_gate2("ecspi2",        "ecspi_podf",        base + 0x6c, 2);
+       hws[IMX6SX_CLK_ECSPI3]       = imx_clk_hw_gate2("ecspi3",        "ecspi_podf",        base + 0x6c, 4);
+       hws[IMX6SX_CLK_ECSPI4]       = imx_clk_hw_gate2("ecspi4",        "ecspi_podf",        base + 0x6c, 6);
+       hws[IMX6SX_CLK_ECSPI5]       = imx_clk_hw_gate2("ecspi5",        "ecspi_podf",        base + 0x6c, 8);
+       hws[IMX6SX_CLK_EPIT1]        = imx_clk_hw_gate2("epit1",         "perclk",            base + 0x6c, 12);
+       hws[IMX6SX_CLK_EPIT2]        = imx_clk_hw_gate2("epit2",         "perclk",            base + 0x6c, 14);
+       hws[IMX6SX_CLK_ESAI_EXTAL]   = imx_clk_hw_gate2_shared("esai_extal", "esai_podf",     base + 0x6c, 16, &share_count_esai);
+       hws[IMX6SX_CLK_ESAI_IPG]     = imx_clk_hw_gate2_shared("esai_ipg",   "ahb",           base + 0x6c, 16, &share_count_esai);
+       hws[IMX6SX_CLK_ESAI_MEM]     = imx_clk_hw_gate2_shared("esai_mem",   "ahb",           base + 0x6c, 16, &share_count_esai);
+       hws[IMX6SX_CLK_WAKEUP]       = imx_clk_hw_gate2_flags("wakeup", "ipg", base + 0x6c, 18, CLK_IS_CRITICAL);
+       hws[IMX6SX_CLK_GPT_BUS]      = imx_clk_hw_gate2("gpt_bus",       "perclk",            base + 0x6c, 20);
+       hws[IMX6SX_CLK_GPT_SERIAL]   = imx_clk_hw_gate2("gpt_serial",    "perclk",            base + 0x6c, 22);
+       hws[IMX6SX_CLK_GPU]          = imx_clk_hw_gate2("gpu",           "gpu_core_podf",     base + 0x6c, 26);
+       hws[IMX6SX_CLK_OCRAM_S]      = imx_clk_hw_gate2("ocram_s",       "ahb",               base + 0x6c, 28);
+       hws[IMX6SX_CLK_CANFD]        = imx_clk_hw_gate2("canfd",         "can_podf",          base + 0x6c, 30);
 
        /* CCGR2 */
-       clks[IMX6SX_CLK_CSI]          = imx_clk_gate2("csi",           "csi_podf",          base + 0x70, 2);
-       clks[IMX6SX_CLK_I2C1]         = imx_clk_gate2("i2c1",          "perclk",            base + 0x70, 6);
-       clks[IMX6SX_CLK_I2C2]         = imx_clk_gate2("i2c2",          "perclk",            base + 0x70, 8);
-       clks[IMX6SX_CLK_I2C3]         = imx_clk_gate2("i2c3",          "perclk",            base + 0x70, 10);
-       clks[IMX6SX_CLK_OCOTP]        = imx_clk_gate2("ocotp",         "ipg",               base + 0x70, 12);
-       clks[IMX6SX_CLK_IOMUXC]       = imx_clk_gate2("iomuxc",        "lcdif1_podf",       base + 0x70, 14);
-       clks[IMX6SX_CLK_IPMUX1]       = imx_clk_gate2_flags("ipmux1", "ahb", base + 0x70, 16, CLK_IS_CRITICAL);
-       clks[IMX6SX_CLK_IPMUX2]       = imx_clk_gate2_flags("ipmux2", "ahb", base + 0x70, 18, CLK_IS_CRITICAL);
-       clks[IMX6SX_CLK_IPMUX3]       = imx_clk_gate2_flags("ipmux3", "ahb", base + 0x70, 20, CLK_IS_CRITICAL);
-       clks[IMX6SX_CLK_TZASC1]       = imx_clk_gate2_flags("tzasc1", "mmdc_podf", base + 0x70, 22, CLK_IS_CRITICAL);
-       clks[IMX6SX_CLK_LCDIF_APB]    = imx_clk_gate2("lcdif_apb",     "display_podf",      base + 0x70, 28);
-       clks[IMX6SX_CLK_PXP_AXI]      = imx_clk_gate2("pxp_axi",       "display_podf",      base + 0x70, 30);
+       hws[IMX6SX_CLK_CSI]          = imx_clk_hw_gate2("csi",           "csi_podf",          base + 0x70, 2);
+       hws[IMX6SX_CLK_I2C1]         = imx_clk_hw_gate2("i2c1",          "perclk",            base + 0x70, 6);
+       hws[IMX6SX_CLK_I2C2]         = imx_clk_hw_gate2("i2c2",          "perclk",            base + 0x70, 8);
+       hws[IMX6SX_CLK_I2C3]         = imx_clk_hw_gate2("i2c3",          "perclk",            base + 0x70, 10);
+       hws[IMX6SX_CLK_OCOTP]        = imx_clk_hw_gate2("ocotp",         "ipg",               base + 0x70, 12);
+       hws[IMX6SX_CLK_IOMUXC]       = imx_clk_hw_gate2("iomuxc",        "lcdif1_podf",       base + 0x70, 14);
+       hws[IMX6SX_CLK_IPMUX1]       = imx_clk_hw_gate2_flags("ipmux1", "ahb", base + 0x70, 16, CLK_IS_CRITICAL);
+       hws[IMX6SX_CLK_IPMUX2]       = imx_clk_hw_gate2_flags("ipmux2", "ahb", base + 0x70, 18, CLK_IS_CRITICAL);
+       hws[IMX6SX_CLK_IPMUX3]       = imx_clk_hw_gate2_flags("ipmux3", "ahb", base + 0x70, 20, CLK_IS_CRITICAL);
+       hws[IMX6SX_CLK_TZASC1]       = imx_clk_hw_gate2_flags("tzasc1", "mmdc_podf", base + 0x70, 22, CLK_IS_CRITICAL);
+       hws[IMX6SX_CLK_LCDIF_APB]    = imx_clk_hw_gate2("lcdif_apb",     "display_podf",      base + 0x70, 28);
+       hws[IMX6SX_CLK_PXP_AXI]      = imx_clk_hw_gate2("pxp_axi",       "display_podf",      base + 0x70, 30);
 
        /* CCGR3 */
-       clks[IMX6SX_CLK_M4]           = imx_clk_gate2("m4",            "m4_podf",           base + 0x74, 2);
-       clks[IMX6SX_CLK_ENET]         = imx_clk_gate2("enet",          "ipg",               base + 0x74, 4);
-       clks[IMX6SX_CLK_ENET_AHB]     = imx_clk_gate2("enet_ahb",      "enet_sel",          base + 0x74, 4);
-       clks[IMX6SX_CLK_DISPLAY_AXI]  = imx_clk_gate2("display_axi",   "display_podf",      base + 0x74, 6);
-       clks[IMX6SX_CLK_LCDIF2_PIX]   = imx_clk_gate2("lcdif2_pix",    "lcdif2_sel",        base + 0x74, 8);
-       clks[IMX6SX_CLK_LCDIF1_PIX]   = imx_clk_gate2("lcdif1_pix",    "lcdif1_sel",        base + 0x74, 10);
-       clks[IMX6SX_CLK_LDB_DI0]      = imx_clk_gate2("ldb_di0",       "ldb_di0_div_sel",   base + 0x74, 12);
-       clks[IMX6SX_CLK_QSPI1]        = imx_clk_gate2("qspi1",         "qspi1_podf",        base + 0x74, 14);
-       clks[IMX6SX_CLK_MLB]          = imx_clk_gate2("mlb",           "ahb",               base + 0x74, 18);
-       clks[IMX6SX_CLK_MMDC_P0_FAST] = imx_clk_gate2_flags("mmdc_p0_fast", "mmdc_podf", base + 0x74, 20, CLK_IS_CRITICAL);
-       clks[IMX6SX_CLK_MMDC_P0_IPG]  = imx_clk_gate2_flags("mmdc_p0_ipg", "ipg", base + 0x74, 24, CLK_IS_CRITICAL);
-       clks[IMX6SX_CLK_MMDC_P1_IPG]  = imx_clk_gate2("mmdc_p1_ipg", "ipg", base + 0x74, 26);
-       clks[IMX6SX_CLK_OCRAM]        = imx_clk_gate2_flags("ocram", "ocram_podf", base + 0x74, 28, CLK_IS_CRITICAL);
+       hws[IMX6SX_CLK_M4]           = imx_clk_hw_gate2("m4",            "m4_podf",           base + 0x74, 2);
+       hws[IMX6SX_CLK_ENET]         = imx_clk_hw_gate2("enet",          "ipg",               base + 0x74, 4);
+       hws[IMX6SX_CLK_ENET_AHB]     = imx_clk_hw_gate2("enet_ahb",      "enet_sel",          base + 0x74, 4);
+       hws[IMX6SX_CLK_DISPLAY_AXI]  = imx_clk_hw_gate2("display_axi",   "display_podf",      base + 0x74, 6);
+       hws[IMX6SX_CLK_LCDIF2_PIX]   = imx_clk_hw_gate2("lcdif2_pix",    "lcdif2_sel",        base + 0x74, 8);
+       hws[IMX6SX_CLK_LCDIF1_PIX]   = imx_clk_hw_gate2("lcdif1_pix",    "lcdif1_sel",        base + 0x74, 10);
+       hws[IMX6SX_CLK_LDB_DI0]      = imx_clk_hw_gate2("ldb_di0",       "ldb_di0_div_sel",   base + 0x74, 12);
+       hws[IMX6SX_CLK_QSPI1]        = imx_clk_hw_gate2("qspi1",         "qspi1_podf",        base + 0x74, 14);
+       hws[IMX6SX_CLK_MLB]          = imx_clk_hw_gate2("mlb",           "ahb",               base + 0x74, 18);
+       hws[IMX6SX_CLK_MMDC_P0_FAST] = imx_clk_hw_gate2_flags("mmdc_p0_fast", "mmdc_podf", base + 0x74, 20, CLK_IS_CRITICAL);
+       hws[IMX6SX_CLK_MMDC_P0_IPG]  = imx_clk_hw_gate2_flags("mmdc_p0_ipg", "ipg", base + 0x74, 24, CLK_IS_CRITICAL);
+       hws[IMX6SX_CLK_MMDC_P1_IPG]  = imx_clk_hw_gate2_flags("mmdc_p1_ipg", "ipg", base + 0x74, 26, CLK_IS_CRITICAL);
+       hws[IMX6SX_CLK_OCRAM]        = imx_clk_hw_gate2_flags("ocram", "ocram_podf", base + 0x74, 28, CLK_IS_CRITICAL);
 
        /* CCGR4 */
-       clks[IMX6SX_CLK_PCIE_AXI]     = imx_clk_gate2("pcie_axi",      "display_podf",      base + 0x78, 0);
-       clks[IMX6SX_CLK_QSPI2]        = imx_clk_gate2("qspi2",         "qspi2_podf",        base + 0x78, 10);
-       clks[IMX6SX_CLK_PER1_BCH]     = imx_clk_gate2("per1_bch",      "usdhc3",            base + 0x78, 12);
-       clks[IMX6SX_CLK_PER2_MAIN]    = imx_clk_gate2_flags("per2_main", "ahb", base + 0x78, 14, CLK_IS_CRITICAL);
-       clks[IMX6SX_CLK_PWM1]         = imx_clk_gate2("pwm1",          "perclk",            base + 0x78, 16);
-       clks[IMX6SX_CLK_PWM2]         = imx_clk_gate2("pwm2",          "perclk",            base + 0x78, 18);
-       clks[IMX6SX_CLK_PWM3]         = imx_clk_gate2("pwm3",          "perclk",            base + 0x78, 20);
-       clks[IMX6SX_CLK_PWM4]         = imx_clk_gate2("pwm4",          "perclk",            base + 0x78, 22);
-       clks[IMX6SX_CLK_GPMI_BCH_APB] = imx_clk_gate2("gpmi_bch_apb",  "usdhc3",            base + 0x78, 24);
-       clks[IMX6SX_CLK_GPMI_BCH]     = imx_clk_gate2("gpmi_bch",      "usdhc4",            base + 0x78, 26);
-       clks[IMX6SX_CLK_GPMI_IO]      = imx_clk_gate2("gpmi_io",       "qspi2_podf",        base + 0x78, 28);
-       clks[IMX6SX_CLK_GPMI_APB]     = imx_clk_gate2("gpmi_apb",      "usdhc3",            base + 0x78, 30);
+       hws[IMX6SX_CLK_PCIE_AXI]     = imx_clk_hw_gate2("pcie_axi",      "display_podf",      base + 0x78, 0);
+       hws[IMX6SX_CLK_QSPI2]        = imx_clk_hw_gate2("qspi2",         "qspi2_podf",        base + 0x78, 10);
+       hws[IMX6SX_CLK_PER1_BCH]     = imx_clk_hw_gate2("per1_bch",      "usdhc3",            base + 0x78, 12);
+       hws[IMX6SX_CLK_PER2_MAIN]    = imx_clk_hw_gate2_flags("per2_main", "ahb", base + 0x78, 14, CLK_IS_CRITICAL);
+       hws[IMX6SX_CLK_PWM1]         = imx_clk_hw_gate2("pwm1",          "perclk",            base + 0x78, 16);
+       hws[IMX6SX_CLK_PWM2]         = imx_clk_hw_gate2("pwm2",          "perclk",            base + 0x78, 18);
+       hws[IMX6SX_CLK_PWM3]         = imx_clk_hw_gate2("pwm3",          "perclk",            base + 0x78, 20);
+       hws[IMX6SX_CLK_PWM4]         = imx_clk_hw_gate2("pwm4",          "perclk",            base + 0x78, 22);
+       hws[IMX6SX_CLK_GPMI_BCH_APB] = imx_clk_hw_gate2("gpmi_bch_apb",  "usdhc3",            base + 0x78, 24);
+       hws[IMX6SX_CLK_GPMI_BCH]     = imx_clk_hw_gate2("gpmi_bch",      "usdhc4",            base + 0x78, 26);
+       hws[IMX6SX_CLK_GPMI_IO]      = imx_clk_hw_gate2("gpmi_io",       "qspi2_podf",        base + 0x78, 28);
+       hws[IMX6SX_CLK_GPMI_APB]     = imx_clk_hw_gate2("gpmi_apb",      "usdhc3",            base + 0x78, 30);
 
        /* CCGR5 */
-       clks[IMX6SX_CLK_ROM]          = imx_clk_gate2_flags("rom", "ahb", base + 0x7c, 0, CLK_IS_CRITICAL);
-       clks[IMX6SX_CLK_SDMA]         = imx_clk_gate2("sdma",          "ahb",               base + 0x7c, 6);
-       clks[IMX6SX_CLK_SPBA]         = imx_clk_gate2("spba",          "ipg",               base + 0x7c, 12);
-       clks[IMX6SX_CLK_AUDIO]        = imx_clk_gate2_shared("audio",  "audio_podf",        base + 0x7c, 14, &share_count_audio);
-       clks[IMX6SX_CLK_SPDIF]        = imx_clk_gate2_shared("spdif",  "spdif_podf",        base + 0x7c, 14, &share_count_audio);
-       clks[IMX6SX_CLK_SPDIF_GCLK]   = imx_clk_gate2_shared("spdif_gclk",    "ipg",        base + 0x7c, 14, &share_count_audio);
-       clks[IMX6SX_CLK_SSI1_IPG]     = imx_clk_gate2_shared("ssi1_ipg",      "ipg",        base + 0x7c, 18, &share_count_ssi1);
-       clks[IMX6SX_CLK_SSI2_IPG]     = imx_clk_gate2_shared("ssi2_ipg",      "ipg",        base + 0x7c, 20, &share_count_ssi2);
-       clks[IMX6SX_CLK_SSI3_IPG]     = imx_clk_gate2_shared("ssi3_ipg",      "ipg",        base + 0x7c, 22, &share_count_ssi3);
-       clks[IMX6SX_CLK_SSI1]         = imx_clk_gate2_shared("ssi1",          "ssi1_podf",  base + 0x7c, 18, &share_count_ssi1);
-       clks[IMX6SX_CLK_SSI2]         = imx_clk_gate2_shared("ssi2",          "ssi2_podf",  base + 0x7c, 20, &share_count_ssi2);
-       clks[IMX6SX_CLK_SSI3]         = imx_clk_gate2_shared("ssi3",          "ssi3_podf",  base + 0x7c, 22, &share_count_ssi3);
-       clks[IMX6SX_CLK_UART_IPG]     = imx_clk_gate2("uart_ipg",      "ipg",               base + 0x7c, 24);
-       clks[IMX6SX_CLK_UART_SERIAL]  = imx_clk_gate2("uart_serial",   "uart_podf",         base + 0x7c, 26);
-       clks[IMX6SX_CLK_SAI1_IPG]     = imx_clk_gate2_shared("sai1_ipg", "ipg",             base + 0x7c, 28, &share_count_sai1);
-       clks[IMX6SX_CLK_SAI2_IPG]     = imx_clk_gate2_shared("sai2_ipg", "ipg",             base + 0x7c, 30, &share_count_sai2);
-       clks[IMX6SX_CLK_SAI1]         = imx_clk_gate2_shared("sai1",    "ssi1_podf",        base + 0x7c, 28, &share_count_sai1);
-       clks[IMX6SX_CLK_SAI2]         = imx_clk_gate2_shared("sai2",    "ssi2_podf",        base + 0x7c, 30, &share_count_sai2);
+       hws[IMX6SX_CLK_ROM]          = imx_clk_hw_gate2_flags("rom", "ahb", base + 0x7c, 0, CLK_IS_CRITICAL);
+       hws[IMX6SX_CLK_SDMA]         = imx_clk_hw_gate2("sdma",          "ahb",               base + 0x7c, 6);
+       hws[IMX6SX_CLK_SPBA]         = imx_clk_hw_gate2("spba",          "ipg",               base + 0x7c, 12);
+       hws[IMX6SX_CLK_AUDIO]        = imx_clk_hw_gate2_shared("audio",  "audio_podf",        base + 0x7c, 14, &share_count_audio);
+       hws[IMX6SX_CLK_SPDIF]        = imx_clk_hw_gate2_shared("spdif",  "spdif_podf",        base + 0x7c, 14, &share_count_audio);
+       hws[IMX6SX_CLK_SPDIF_GCLK]   = imx_clk_hw_gate2_shared("spdif_gclk",    "ipg",        base + 0x7c, 14, &share_count_audio);
+       hws[IMX6SX_CLK_SSI1_IPG]     = imx_clk_hw_gate2_shared("ssi1_ipg",      "ipg",        base + 0x7c, 18, &share_count_ssi1);
+       hws[IMX6SX_CLK_SSI2_IPG]     = imx_clk_hw_gate2_shared("ssi2_ipg",      "ipg",        base + 0x7c, 20, &share_count_ssi2);
+       hws[IMX6SX_CLK_SSI3_IPG]     = imx_clk_hw_gate2_shared("ssi3_ipg",      "ipg",        base + 0x7c, 22, &share_count_ssi3);
+       hws[IMX6SX_CLK_SSI1]         = imx_clk_hw_gate2_shared("ssi1",          "ssi1_podf",  base + 0x7c, 18, &share_count_ssi1);
+       hws[IMX6SX_CLK_SSI2]         = imx_clk_hw_gate2_shared("ssi2",          "ssi2_podf",  base + 0x7c, 20, &share_count_ssi2);
+       hws[IMX6SX_CLK_SSI3]         = imx_clk_hw_gate2_shared("ssi3",          "ssi3_podf",  base + 0x7c, 22, &share_count_ssi3);
+       hws[IMX6SX_CLK_UART_IPG]     = imx_clk_hw_gate2("uart_ipg",      "ipg",               base + 0x7c, 24);
+       hws[IMX6SX_CLK_UART_SERIAL]  = imx_clk_hw_gate2("uart_serial",   "uart_podf",         base + 0x7c, 26);
+       hws[IMX6SX_CLK_SAI1_IPG]     = imx_clk_hw_gate2_shared("sai1_ipg", "ipg",             base + 0x7c, 28, &share_count_sai1);
+       hws[IMX6SX_CLK_SAI2_IPG]     = imx_clk_hw_gate2_shared("sai2_ipg", "ipg",             base + 0x7c, 30, &share_count_sai2);
+       hws[IMX6SX_CLK_SAI1]         = imx_clk_hw_gate2_shared("sai1",  "ssi1_podf",        base + 0x7c, 28, &share_count_sai1);
+       hws[IMX6SX_CLK_SAI2]         = imx_clk_hw_gate2_shared("sai2",  "ssi2_podf",        base + 0x7c, 30, &share_count_sai2);
 
        /* CCGR6 */
-       clks[IMX6SX_CLK_USBOH3]       = imx_clk_gate2("usboh3",        "ipg",               base + 0x80, 0);
-       clks[IMX6SX_CLK_USDHC1]       = imx_clk_gate2("usdhc1",        "usdhc1_podf",       base + 0x80, 2);
-       clks[IMX6SX_CLK_USDHC2]       = imx_clk_gate2("usdhc2",        "usdhc2_podf",       base + 0x80, 4);
-       clks[IMX6SX_CLK_USDHC3]       = imx_clk_gate2("usdhc3",        "usdhc3_podf",       base + 0x80, 6);
-       clks[IMX6SX_CLK_USDHC4]       = imx_clk_gate2("usdhc4",        "usdhc4_podf",       base + 0x80, 8);
-       clks[IMX6SX_CLK_EIM_SLOW]     = imx_clk_gate2("eim_slow",      "eim_slow_podf",     base + 0x80, 10);
-       clks[IMX6SX_CLK_PWM8]         = imx_clk_gate2("pwm8",          "perclk",            base + 0x80, 16);
-       clks[IMX6SX_CLK_VADC]         = imx_clk_gate2("vadc",          "vid_podf",          base + 0x80, 20);
-       clks[IMX6SX_CLK_GIS]          = imx_clk_gate2("gis",           "display_podf",      base + 0x80, 22);
-       clks[IMX6SX_CLK_I2C4]         = imx_clk_gate2("i2c4",          "perclk",            base + 0x80, 24);
-       clks[IMX6SX_CLK_PWM5]         = imx_clk_gate2("pwm5",          "perclk",            base + 0x80, 26);
-       clks[IMX6SX_CLK_PWM6]         = imx_clk_gate2("pwm6",          "perclk",            base + 0x80, 28);
-       clks[IMX6SX_CLK_PWM7]         = imx_clk_gate2("pwm7",          "perclk",            base + 0x80, 30);
-
-       clks[IMX6SX_CLK_CKO1]         = imx_clk_gate("cko1",           "cko1_podf",         base + 0x60, 7);
-       clks[IMX6SX_CLK_CKO2]         = imx_clk_gate("cko2",           "cko2_podf",         base + 0x60, 24);
+       hws[IMX6SX_CLK_USBOH3]       = imx_clk_hw_gate2("usboh3",        "ipg",               base + 0x80, 0);
+       hws[IMX6SX_CLK_USDHC1]       = imx_clk_hw_gate2("usdhc1",        "usdhc1_podf",       base + 0x80, 2);
+       hws[IMX6SX_CLK_USDHC2]       = imx_clk_hw_gate2("usdhc2",        "usdhc2_podf",       base + 0x80, 4);
+       hws[IMX6SX_CLK_USDHC3]       = imx_clk_hw_gate2("usdhc3",        "usdhc3_podf",       base + 0x80, 6);
+       hws[IMX6SX_CLK_USDHC4]       = imx_clk_hw_gate2("usdhc4",        "usdhc4_podf",       base + 0x80, 8);
+       hws[IMX6SX_CLK_EIM_SLOW]     = imx_clk_hw_gate2("eim_slow",      "eim_slow_podf",     base + 0x80, 10);
+       hws[IMX6SX_CLK_PWM8]         = imx_clk_hw_gate2("pwm8",          "perclk",            base + 0x80, 16);
+       hws[IMX6SX_CLK_VADC]         = imx_clk_hw_gate2("vadc",          "vid_podf",          base + 0x80, 20);
+       hws[IMX6SX_CLK_GIS]          = imx_clk_hw_gate2("gis",           "display_podf",      base + 0x80, 22);
+       hws[IMX6SX_CLK_I2C4]         = imx_clk_hw_gate2("i2c4",          "perclk",            base + 0x80, 24);
+       hws[IMX6SX_CLK_PWM5]         = imx_clk_hw_gate2("pwm5",          "perclk",            base + 0x80, 26);
+       hws[IMX6SX_CLK_PWM6]         = imx_clk_hw_gate2("pwm6",          "perclk",            base + 0x80, 28);
+       hws[IMX6SX_CLK_PWM7]         = imx_clk_hw_gate2("pwm7",          "perclk",            base + 0x80, 30);
+
+       hws[IMX6SX_CLK_CKO1]         = imx_clk_hw_gate("cko1",           "cko1_podf",         base + 0x60, 7);
+       hws[IMX6SX_CLK_CKO2]         = imx_clk_hw_gate("cko2",           "cko2_podf",         base + 0x60, 24);
 
        /* mask handshake of mmdc */
-       writel_relaxed(BM_CCM_CCDR_MMDC_CH0_MASK, base + CCDR);
+       imx_mmdc_mask_handshake(base, 0);
 
-       imx_check_clocks(clks, ARRAY_SIZE(clks));
+       imx_check_clk_hws(hws, IMX6SX_CLK_CLK_END);
 
-       clk_data.clks = clks;
-       clk_data.clk_num = ARRAY_SIZE(clks);
-       of_clk_add_provider(np, of_clk_src_onecell_get, &clk_data);
+       of_clk_add_hw_provider(np, of_clk_hw_onecell_get, clk_hw_data);
 
        if (IS_ENABLED(CONFIG_USB_MXS_PHY)) {
-               clk_prepare_enable(clks[IMX6SX_CLK_USBPHY1_GATE]);
-               clk_prepare_enable(clks[IMX6SX_CLK_USBPHY2_GATE]);
+               clk_prepare_enable(hws[IMX6SX_CLK_USBPHY1_GATE]->clk);
+               clk_prepare_enable(hws[IMX6SX_CLK_USBPHY2_GATE]->clk);
        }
 
        /* Set the default 132MHz for EIM module */
-       clk_set_parent(clks[IMX6SX_CLK_EIM_SLOW_SEL], clks[IMX6SX_CLK_PLL2_PFD2]);
-       clk_set_rate(clks[IMX6SX_CLK_EIM_SLOW], 132000000);
+       clk_set_parent(hws[IMX6SX_CLK_EIM_SLOW_SEL]->clk, hws[IMX6SX_CLK_PLL2_PFD2]->clk);
+       clk_set_rate(hws[IMX6SX_CLK_EIM_SLOW]->clk, 132000000);
 
        /* set parent clock for LCDIF1 pixel clock */
-       clk_set_parent(clks[IMX6SX_CLK_LCDIF1_PRE_SEL], clks[IMX6SX_CLK_PLL5_VIDEO_DIV]);
-       clk_set_parent(clks[IMX6SX_CLK_LCDIF1_SEL], clks[IMX6SX_CLK_LCDIF1_PODF]);
+       clk_set_parent(hws[IMX6SX_CLK_LCDIF1_PRE_SEL]->clk, hws[IMX6SX_CLK_PLL5_VIDEO_DIV]->clk);
+       clk_set_parent(hws[IMX6SX_CLK_LCDIF1_SEL]->clk, hws[IMX6SX_CLK_LCDIF1_PODF]->clk);
 
        /* Set the parent clks of PCIe lvds1 and pcie_axi to be pcie ref, axi */
-       if (clk_set_parent(clks[IMX6SX_CLK_LVDS1_SEL], clks[IMX6SX_CLK_PCIE_REF_125M]))
+       if (clk_set_parent(hws[IMX6SX_CLK_LVDS1_SEL]->clk, hws[IMX6SX_CLK_PCIE_REF_125M]->clk))
                pr_err("Failed to set pcie bus parent clk.\n");
-       if (clk_set_parent(clks[IMX6SX_CLK_PCIE_AXI_SEL], clks[IMX6SX_CLK_AXI]))
-               pr_err("Failed to set pcie parent clk.\n");
 
        /*
         * Init enet system AHB clock, set to 200MHz
         * pll2_pfd2_396m-> ENET_PODF-> ENET_AHB
         */
-       clk_set_parent(clks[IMX6SX_CLK_ENET_PRE_SEL], clks[IMX6SX_CLK_PLL2_PFD2]);
-       clk_set_parent(clks[IMX6SX_CLK_ENET_SEL], clks[IMX6SX_CLK_ENET_PODF]);
-       clk_set_rate(clks[IMX6SX_CLK_ENET_PODF], 200000000);
-       clk_set_rate(clks[IMX6SX_CLK_ENET_REF], 125000000);
-       clk_set_rate(clks[IMX6SX_CLK_ENET2_REF], 125000000);
+       clk_set_parent(hws[IMX6SX_CLK_ENET_PRE_SEL]->clk, hws[IMX6SX_CLK_PLL2_PFD2]->clk);
+       clk_set_parent(hws[IMX6SX_CLK_ENET_SEL]->clk, hws[IMX6SX_CLK_ENET_PODF]->clk);
+       clk_set_rate(hws[IMX6SX_CLK_ENET_PODF]->clk, 200000000);
+       clk_set_rate(hws[IMX6SX_CLK_ENET_REF]->clk, 125000000);
+       clk_set_rate(hws[IMX6SX_CLK_ENET2_REF]->clk, 125000000);
 
        /* Audio clocks */
-       clk_set_rate(clks[IMX6SX_CLK_PLL4_AUDIO_DIV], 393216000);
+       clk_set_rate(hws[IMX6SX_CLK_PLL4_AUDIO_DIV]->clk, 393216000);
 
-       clk_set_parent(clks[IMX6SX_CLK_SPDIF_SEL], clks[IMX6SX_CLK_PLL4_AUDIO_DIV]);
-       clk_set_rate(clks[IMX6SX_CLK_SPDIF_PODF], 98304000);
+       clk_set_parent(hws[IMX6SX_CLK_SPDIF_SEL]->clk, hws[IMX6SX_CLK_PLL4_AUDIO_DIV]->clk);
+       clk_set_rate(hws[IMX6SX_CLK_SPDIF_PODF]->clk, 98304000);
 
-       clk_set_parent(clks[IMX6SX_CLK_AUDIO_SEL], clks[IMX6SX_CLK_PLL3_USB_OTG]);
-       clk_set_rate(clks[IMX6SX_CLK_AUDIO_PODF], 24000000);
+       clk_set_parent(hws[IMX6SX_CLK_AUDIO_SEL]->clk, hws[IMX6SX_CLK_PLL3_USB_OTG]->clk);
+       clk_set_rate(hws[IMX6SX_CLK_AUDIO_PODF]->clk, 24000000);
 
-       clk_set_parent(clks[IMX6SX_CLK_SSI1_SEL], clks[IMX6SX_CLK_PLL4_AUDIO_DIV]);
-       clk_set_parent(clks[IMX6SX_CLK_SSI2_SEL], clks[IMX6SX_CLK_PLL4_AUDIO_DIV]);
-       clk_set_parent(clks[IMX6SX_CLK_SSI3_SEL], clks[IMX6SX_CLK_PLL4_AUDIO_DIV]);
-       clk_set_rate(clks[IMX6SX_CLK_SSI1_PODF], 24576000);
-       clk_set_rate(clks[IMX6SX_CLK_SSI2_PODF], 24576000);
-       clk_set_rate(clks[IMX6SX_CLK_SSI3_PODF], 24576000);
+       clk_set_parent(hws[IMX6SX_CLK_SSI1_SEL]->clk, hws[IMX6SX_CLK_PLL4_AUDIO_DIV]->clk);
+       clk_set_parent(hws[IMX6SX_CLK_SSI2_SEL]->clk, hws[IMX6SX_CLK_PLL4_AUDIO_DIV]->clk);
+       clk_set_parent(hws[IMX6SX_CLK_SSI3_SEL]->clk, hws[IMX6SX_CLK_PLL4_AUDIO_DIV]->clk);
+       clk_set_rate(hws[IMX6SX_CLK_SSI1_PODF]->clk, 24576000);
+       clk_set_rate(hws[IMX6SX_CLK_SSI2_PODF]->clk, 24576000);
+       clk_set_rate(hws[IMX6SX_CLK_SSI3_PODF]->clk, 24576000);
 
-       clk_set_parent(clks[IMX6SX_CLK_ESAI_SEL], clks[IMX6SX_CLK_PLL4_AUDIO_DIV]);
-       clk_set_rate(clks[IMX6SX_CLK_ESAI_PODF], 24576000);
+       clk_set_parent(hws[IMX6SX_CLK_ESAI_SEL]->clk, hws[IMX6SX_CLK_PLL4_AUDIO_DIV]->clk);
+       clk_set_rate(hws[IMX6SX_CLK_ESAI_PODF]->clk, 24576000);
 
        /* Set parent clock for vadc */
-       clk_set_parent(clks[IMX6SX_CLK_VID_SEL], clks[IMX6SX_CLK_PLL3_USB_OTG]);
+       clk_set_parent(hws[IMX6SX_CLK_VID_SEL]->clk, hws[IMX6SX_CLK_PLL3_USB_OTG]->clk);
 
        /* default parent of can_sel clock is invalid, manually set it here */
-       clk_set_parent(clks[IMX6SX_CLK_CAN_SEL], clks[IMX6SX_CLK_PLL3_60M]);
+       clk_set_parent(hws[IMX6SX_CLK_CAN_SEL]->clk, hws[IMX6SX_CLK_PLL3_60M]->clk);
 
        /* Update gpu clock from default 528M to 720M */
-       clk_set_parent(clks[IMX6SX_CLK_GPU_CORE_SEL], clks[IMX6SX_CLK_PLL3_PFD0]);
-       clk_set_parent(clks[IMX6SX_CLK_GPU_AXI_SEL], clks[IMX6SX_CLK_PLL3_PFD0]);
+       clk_set_parent(hws[IMX6SX_CLK_GPU_CORE_SEL]->clk, hws[IMX6SX_CLK_PLL3_PFD0]->clk);
+       clk_set_parent(hws[IMX6SX_CLK_GPU_AXI_SEL]->clk, hws[IMX6SX_CLK_PLL3_PFD0]->clk);
 
-       clk_set_parent(clks[IMX6SX_CLK_QSPI1_SEL], clks[IMX6SX_CLK_PLL2_BUS]);
-       clk_set_parent(clks[IMX6SX_CLK_QSPI2_SEL], clks[IMX6SX_CLK_PLL2_BUS]);
+       clk_set_parent(hws[IMX6SX_CLK_QSPI1_SEL]->clk, hws[IMX6SX_CLK_PLL2_BUS]->clk);
+       clk_set_parent(hws[IMX6SX_CLK_QSPI2_SEL]->clk, hws[IMX6SX_CLK_PLL2_BUS]->clk);
+
+       for (i = 0; i < ARRAY_SIZE(uart_clk_ids); i++) {
+               int index = uart_clk_ids[i];
+
+               uart_clks[i] = &hws[index]->clk;
+       }
 
        imx_register_uart_clocks(uart_clks);
 }
index 8fd52e1..bc93198 100644 (file)
@@ -6,6 +6,7 @@
 #include <dt-bindings/clock/imx6ul-clock.h>
 #include <linux/clk.h>
 #include <linux/clkdev.h>
+#include <linux/clk-provider.h>
 #include <linux/err.h>
 #include <linux/init.h>
 #include <linux/io.h>
@@ -16,9 +17,6 @@
 
 #include "clk.h"
 
-#define BM_CCM_CCDR_MMDC_CH0_MASK      (0x2 << 16)
-#define CCDR   0x4
-
 static const char *pll_bypass_src_sels[] = { "osc", "dummy", };
 static const char *pll1_bypass_sels[] = { "pll1", "pll1_bypass_src", };
 static const char *pll2_bypass_sels[] = { "pll2", "pll2_bypass_src", };
@@ -70,8 +68,8 @@ static const char *cko2_sels[] = { "dummy", "dummy", "dummy", "usdhc1", "dummy",
                                   "dummy", "dummy", "dummy", "dummy", "uart_serial", "spdif", "dummy", "dummy", };
 static const char *cko_sels[] = { "cko1", "cko2", };
 
-static struct clk *clks[IMX6UL_CLK_END];
-static struct clk_onecell_data clk_data;
+static struct clk_hw **hws;
+static struct clk_hw_onecell_data *clk_hw_data;
 
 static const struct clk_div_table clk_enet_ref_table[] = {
        { .val = 0, .div = 20, },
@@ -118,61 +116,69 @@ static void __init imx6ul_clocks_init(struct device_node *ccm_node)
        struct device_node *np;
        void __iomem *base;
 
-       clks[IMX6UL_CLK_DUMMY] = imx_clk_fixed("dummy", 0);
+       clk_hw_data = kzalloc(struct_size(clk_hw_data, hws,
+                                         IMX6UL_CLK_END), GFP_KERNEL);
+       if (WARN_ON(!clk_hw_data))
+               return;
+
+       clk_hw_data->num = IMX6UL_CLK_END;
+       hws = clk_hw_data->hws;
+
+       hws[IMX6UL_CLK_DUMMY] = imx_clk_hw_fixed("dummy", 0);
 
-       clks[IMX6UL_CLK_CKIL] = of_clk_get_by_name(ccm_node, "ckil");
-       clks[IMX6UL_CLK_OSC] = of_clk_get_by_name(ccm_node, "osc");
+       hws[IMX6UL_CLK_CKIL] = __clk_get_hw(of_clk_get_by_name(ccm_node, "ckil"));
+       hws[IMX6UL_CLK_OSC] = __clk_get_hw(of_clk_get_by_name(ccm_node, "osc"));
 
        /* ipp_di clock is external input */
-       clks[IMX6UL_CLK_IPP_DI0] = of_clk_get_by_name(ccm_node, "ipp_di0");
-       clks[IMX6UL_CLK_IPP_DI1] = of_clk_get_by_name(ccm_node, "ipp_di1");
+       hws[IMX6UL_CLK_IPP_DI0] = __clk_get_hw(of_clk_get_by_name(ccm_node, "ipp_di0"));
+       hws[IMX6UL_CLK_IPP_DI1] = __clk_get_hw(of_clk_get_by_name(ccm_node, "ipp_di1"));
 
        np = of_find_compatible_node(NULL, NULL, "fsl,imx6ul-anatop");
        base = of_iomap(np, 0);
        of_node_put(np);
        WARN_ON(!base);
 
-       clks[IMX6UL_PLL1_BYPASS_SRC] = imx_clk_mux("pll1_bypass_src", base + 0x00, 14, 1, pll_bypass_src_sels, ARRAY_SIZE(pll_bypass_src_sels));
-       clks[IMX6UL_PLL2_BYPASS_SRC] = imx_clk_mux("pll2_bypass_src", base + 0x30, 14, 1, pll_bypass_src_sels, ARRAY_SIZE(pll_bypass_src_sels));
-       clks[IMX6UL_PLL3_BYPASS_SRC] = imx_clk_mux("pll3_bypass_src", base + 0x10, 14, 1, pll_bypass_src_sels, ARRAY_SIZE(pll_bypass_src_sels));
-       clks[IMX6UL_PLL4_BYPASS_SRC] = imx_clk_mux("pll4_bypass_src", base + 0x70, 14, 1, pll_bypass_src_sels, ARRAY_SIZE(pll_bypass_src_sels));
-       clks[IMX6UL_PLL5_BYPASS_SRC] = imx_clk_mux("pll5_bypass_src", base + 0xa0, 14, 1, pll_bypass_src_sels, ARRAY_SIZE(pll_bypass_src_sels));
-       clks[IMX6UL_PLL6_BYPASS_SRC] = imx_clk_mux("pll6_bypass_src", base + 0xe0, 14, 1, pll_bypass_src_sels, ARRAY_SIZE(pll_bypass_src_sels));
-       clks[IMX6UL_PLL7_BYPASS_SRC] = imx_clk_mux("pll7_bypass_src", base + 0x20, 14, 1, pll_bypass_src_sels, ARRAY_SIZE(pll_bypass_src_sels));
-
-       clks[IMX6UL_CLK_PLL1] = imx_clk_pllv3(IMX_PLLV3_SYS,     "pll1", "osc", base + 0x00, 0x7f);
-       clks[IMX6UL_CLK_PLL2] = imx_clk_pllv3(IMX_PLLV3_GENERIC, "pll2", "osc", base + 0x30, 0x1);
-       clks[IMX6UL_CLK_PLL3] = imx_clk_pllv3(IMX_PLLV3_USB,     "pll3", "osc", base + 0x10, 0x3);
-       clks[IMX6UL_CLK_PLL4] = imx_clk_pllv3(IMX_PLLV3_AV,      "pll4", "osc", base + 0x70, 0x7f);
-       clks[IMX6UL_CLK_PLL5] = imx_clk_pllv3(IMX_PLLV3_AV,      "pll5", "osc", base + 0xa0, 0x7f);
-       clks[IMX6UL_CLK_PLL6] = imx_clk_pllv3(IMX_PLLV3_ENET,    "pll6", "osc", base + 0xe0, 0x3);
-       clks[IMX6UL_CLK_PLL7] = imx_clk_pllv3(IMX_PLLV3_USB,     "pll7", "osc", base + 0x20, 0x3);
-
-       clks[IMX6UL_PLL1_BYPASS] = imx_clk_mux_flags("pll1_bypass", base + 0x00, 16, 1, pll1_bypass_sels, ARRAY_SIZE(pll1_bypass_sels), CLK_SET_RATE_PARENT);
-       clks[IMX6UL_PLL2_BYPASS] = imx_clk_mux_flags("pll2_bypass", base + 0x30, 16, 1, pll2_bypass_sels, ARRAY_SIZE(pll2_bypass_sels), CLK_SET_RATE_PARENT);
-       clks[IMX6UL_PLL3_BYPASS] = imx_clk_mux_flags("pll3_bypass", base + 0x10, 16, 1, pll3_bypass_sels, ARRAY_SIZE(pll3_bypass_sels), CLK_SET_RATE_PARENT);
-       clks[IMX6UL_PLL4_BYPASS] = imx_clk_mux_flags("pll4_bypass", base + 0x70, 16, 1, pll4_bypass_sels, ARRAY_SIZE(pll4_bypass_sels), CLK_SET_RATE_PARENT);
-       clks[IMX6UL_PLL5_BYPASS] = imx_clk_mux_flags("pll5_bypass", base + 0xa0, 16, 1, pll5_bypass_sels, ARRAY_SIZE(pll5_bypass_sels), CLK_SET_RATE_PARENT);
-       clks[IMX6UL_PLL6_BYPASS] = imx_clk_mux_flags("pll6_bypass", base + 0xe0, 16, 1, pll6_bypass_sels, ARRAY_SIZE(pll6_bypass_sels), CLK_SET_RATE_PARENT);
-       clks[IMX6UL_PLL7_BYPASS] = imx_clk_mux_flags("pll7_bypass", base + 0x20, 16, 1, pll7_bypass_sels, ARRAY_SIZE(pll7_bypass_sels), CLK_SET_RATE_PARENT);
-       clks[IMX6UL_CLK_CSI_SEL] = imx_clk_mux_flags("csi_sel", base + 0x3c, 9, 2, csi_sels, ARRAY_SIZE(csi_sels), CLK_SET_RATE_PARENT);
+       hws[IMX6UL_PLL1_BYPASS_SRC] = imx_clk_hw_mux("pll1_bypass_src", base + 0x00, 14, 1, pll_bypass_src_sels, ARRAY_SIZE(pll_bypass_src_sels));
+       hws[IMX6UL_PLL2_BYPASS_SRC] = imx_clk_hw_mux("pll2_bypass_src", base + 0x30, 14, 1, pll_bypass_src_sels, ARRAY_SIZE(pll_bypass_src_sels));
+       hws[IMX6UL_PLL3_BYPASS_SRC] = imx_clk_hw_mux("pll3_bypass_src", base + 0x10, 14, 1, pll_bypass_src_sels, ARRAY_SIZE(pll_bypass_src_sels));
+       hws[IMX6UL_PLL4_BYPASS_SRC] = imx_clk_hw_mux("pll4_bypass_src", base + 0x70, 14, 1, pll_bypass_src_sels, ARRAY_SIZE(pll_bypass_src_sels));
+       hws[IMX6UL_PLL5_BYPASS_SRC] = imx_clk_hw_mux("pll5_bypass_src", base + 0xa0, 14, 1, pll_bypass_src_sels, ARRAY_SIZE(pll_bypass_src_sels));
+       hws[IMX6UL_PLL6_BYPASS_SRC] = imx_clk_hw_mux("pll6_bypass_src", base + 0xe0, 14, 1, pll_bypass_src_sels, ARRAY_SIZE(pll_bypass_src_sels));
+       hws[IMX6UL_PLL7_BYPASS_SRC] = imx_clk_hw_mux("pll7_bypass_src", base + 0x20, 14, 1, pll_bypass_src_sels, ARRAY_SIZE(pll_bypass_src_sels));
+
+       hws[IMX6UL_CLK_PLL1] = imx_clk_hw_pllv3(IMX_PLLV3_SYS,   "pll1", "osc", base + 0x00, 0x7f);
+       hws[IMX6UL_CLK_PLL2] = imx_clk_hw_pllv3(IMX_PLLV3_GENERIC, "pll2", "osc", base + 0x30, 0x1);
+       hws[IMX6UL_CLK_PLL3] = imx_clk_hw_pllv3(IMX_PLLV3_USB,   "pll3", "osc", base + 0x10, 0x3);
+       hws[IMX6UL_CLK_PLL4] = imx_clk_hw_pllv3(IMX_PLLV3_AV,    "pll4", "osc", base + 0x70, 0x7f);
+       hws[IMX6UL_CLK_PLL5] = imx_clk_hw_pllv3(IMX_PLLV3_AV,    "pll5", "osc", base + 0xa0, 0x7f);
+       hws[IMX6UL_CLK_PLL6] = imx_clk_hw_pllv3(IMX_PLLV3_ENET,  "pll6", "osc", base + 0xe0, 0x3);
+       hws[IMX6UL_CLK_PLL7] = imx_clk_hw_pllv3(IMX_PLLV3_USB,   "pll7", "osc", base + 0x20, 0x3);
+
+       hws[IMX6UL_PLL1_BYPASS] = imx_clk_hw_mux_flags("pll1_bypass", base + 0x00, 16, 1, pll1_bypass_sels, ARRAY_SIZE(pll1_bypass_sels), CLK_SET_RATE_PARENT);
+       hws[IMX6UL_PLL2_BYPASS] = imx_clk_hw_mux_flags("pll2_bypass", base + 0x30, 16, 1, pll2_bypass_sels, ARRAY_SIZE(pll2_bypass_sels), CLK_SET_RATE_PARENT);
+       hws[IMX6UL_PLL3_BYPASS] = imx_clk_hw_mux_flags("pll3_bypass", base + 0x10, 16, 1, pll3_bypass_sels, ARRAY_SIZE(pll3_bypass_sels), CLK_SET_RATE_PARENT);
+       hws[IMX6UL_PLL4_BYPASS] = imx_clk_hw_mux_flags("pll4_bypass", base + 0x70, 16, 1, pll4_bypass_sels, ARRAY_SIZE(pll4_bypass_sels), CLK_SET_RATE_PARENT);
+       hws[IMX6UL_PLL5_BYPASS] = imx_clk_hw_mux_flags("pll5_bypass", base + 0xa0, 16, 1, pll5_bypass_sels, ARRAY_SIZE(pll5_bypass_sels), CLK_SET_RATE_PARENT);
+       hws[IMX6UL_PLL6_BYPASS] = imx_clk_hw_mux_flags("pll6_bypass", base + 0xe0, 16, 1, pll6_bypass_sels, ARRAY_SIZE(pll6_bypass_sels), CLK_SET_RATE_PARENT);
+       hws[IMX6UL_PLL7_BYPASS] = imx_clk_hw_mux_flags("pll7_bypass", base + 0x20, 16, 1, pll7_bypass_sels, ARRAY_SIZE(pll7_bypass_sels), CLK_SET_RATE_PARENT);
+       hws[IMX6UL_CLK_CSI_SEL] = imx_clk_hw_mux_flags("csi_sel", base + 0x3c, 9, 2, csi_sels, ARRAY_SIZE(csi_sels), CLK_SET_RATE_PARENT);
 
        /* Do not bypass PLLs initially */
-       clk_set_parent(clks[IMX6UL_PLL1_BYPASS], clks[IMX6UL_CLK_PLL1]);
-       clk_set_parent(clks[IMX6UL_PLL2_BYPASS], clks[IMX6UL_CLK_PLL2]);
-       clk_set_parent(clks[IMX6UL_PLL3_BYPASS], clks[IMX6UL_CLK_PLL3]);
-       clk_set_parent(clks[IMX6UL_PLL4_BYPASS], clks[IMX6UL_CLK_PLL4]);
-       clk_set_parent(clks[IMX6UL_PLL5_BYPASS], clks[IMX6UL_CLK_PLL5]);
-       clk_set_parent(clks[IMX6UL_PLL6_BYPASS], clks[IMX6UL_CLK_PLL6]);
-       clk_set_parent(clks[IMX6UL_PLL7_BYPASS], clks[IMX6UL_CLK_PLL7]);
-
-       clks[IMX6UL_CLK_PLL1_SYS]       = imx_clk_fixed_factor("pll1_sys",      "pll1_bypass", 1, 1);
-       clks[IMX6UL_CLK_PLL2_BUS]       = imx_clk_gate("pll2_bus",      "pll2_bypass", base + 0x30, 13);
-       clks[IMX6UL_CLK_PLL3_USB_OTG]   = imx_clk_gate("pll3_usb_otg",  "pll3_bypass", base + 0x10, 13);
-       clks[IMX6UL_CLK_PLL4_AUDIO]     = imx_clk_gate("pll4_audio",    "pll4_bypass", base + 0x70, 13);
-       clks[IMX6UL_CLK_PLL5_VIDEO]     = imx_clk_gate("pll5_video",    "pll5_bypass", base + 0xa0, 13);
-       clks[IMX6UL_CLK_PLL6_ENET]      = imx_clk_gate("pll6_enet",     "pll6_bypass", base + 0xe0, 13);
-       clks[IMX6UL_CLK_PLL7_USB_HOST]  = imx_clk_gate("pll7_usb_host", "pll7_bypass", base + 0x20, 13);
+       clk_set_parent(hws[IMX6UL_PLL1_BYPASS]->clk, hws[IMX6UL_CLK_PLL1]->clk);
+       clk_set_parent(hws[IMX6UL_PLL2_BYPASS]->clk, hws[IMX6UL_CLK_PLL2]->clk);
+       clk_set_parent(hws[IMX6UL_PLL3_BYPASS]->clk, hws[IMX6UL_CLK_PLL3]->clk);
+       clk_set_parent(hws[IMX6UL_PLL4_BYPASS]->clk, hws[IMX6UL_CLK_PLL4]->clk);
+       clk_set_parent(hws[IMX6UL_PLL5_BYPASS]->clk, hws[IMX6UL_CLK_PLL5]->clk);
+       clk_set_parent(hws[IMX6UL_PLL6_BYPASS]->clk, hws[IMX6UL_CLK_PLL6]->clk);
+       clk_set_parent(hws[IMX6UL_PLL7_BYPASS]->clk, hws[IMX6UL_CLK_PLL7]->clk);
+
+       hws[IMX6UL_CLK_PLL1_SYS]        = imx_clk_hw_fixed_factor("pll1_sys",   "pll1_bypass", 1, 1);
+       hws[IMX6UL_CLK_PLL2_BUS]        = imx_clk_hw_gate("pll2_bus",   "pll2_bypass", base + 0x30, 13);
+       hws[IMX6UL_CLK_PLL3_USB_OTG]    = imx_clk_hw_gate("pll3_usb_otg",       "pll3_bypass", base + 0x10, 13);
+       hws[IMX6UL_CLK_PLL4_AUDIO]      = imx_clk_hw_gate("pll4_audio", "pll4_bypass", base + 0x70, 13);
+       hws[IMX6UL_CLK_PLL5_VIDEO]      = imx_clk_hw_gate("pll5_video", "pll5_bypass", base + 0xa0, 13);
+       hws[IMX6UL_CLK_PLL6_ENET]       = imx_clk_hw_gate("pll6_enet",  "pll6_bypass", base + 0xe0, 13);
+       hws[IMX6UL_CLK_PLL7_USB_HOST]   = imx_clk_hw_gate("pll7_usb_host",      "pll7_bypass", base + 0x20, 13);
 
        /*
         * Bit 20 is the reserved and read-only bit, we do this only for:
@@ -180,291 +186,289 @@ static void __init imx6ul_clocks_init(struct device_node *ccm_node)
         * - Keep refcount when do usbphy clk_enable/disable, in that case,
         * the clk framework many need to enable/disable usbphy's parent
         */
-       clks[IMX6UL_CLK_USBPHY1] = imx_clk_gate("usbphy1", "pll3_usb_otg",  base + 0x10, 20);
-       clks[IMX6UL_CLK_USBPHY2] = imx_clk_gate("usbphy2", "pll7_usb_host", base + 0x20, 20);
+       hws[IMX6UL_CLK_USBPHY1] = imx_clk_hw_gate("usbphy1", "pll3_usb_otg",  base + 0x10, 20);
+       hws[IMX6UL_CLK_USBPHY2] = imx_clk_hw_gate("usbphy2", "pll7_usb_host", base + 0x20, 20);
 
        /*
         * usbphy*_gate needs to be on after system boots up, and software
         * never needs to control it anymore.
         */
-       clks[IMX6UL_CLK_USBPHY1_GATE] = imx_clk_gate("usbphy1_gate", "dummy", base + 0x10, 6);
-       clks[IMX6UL_CLK_USBPHY2_GATE] = imx_clk_gate("usbphy2_gate", "dummy", base + 0x20, 6);
+       hws[IMX6UL_CLK_USBPHY1_GATE] = imx_clk_hw_gate("usbphy1_gate", "dummy", base + 0x10, 6);
+       hws[IMX6UL_CLK_USBPHY2_GATE] = imx_clk_hw_gate("usbphy2_gate", "dummy", base + 0x20, 6);
 
        /*                                      name               parent_name     reg          idx */
-       clks[IMX6UL_CLK_PLL2_PFD0] = imx_clk_pfd("pll2_pfd0_352m", "pll2_bus",     base + 0x100, 0);
-       clks[IMX6UL_CLK_PLL2_PFD1] = imx_clk_pfd("pll2_pfd1_594m", "pll2_bus",     base + 0x100, 1);
-       clks[IMX6UL_CLK_PLL2_PFD2] = imx_clk_pfd("pll2_pfd2_396m", "pll2_bus",     base + 0x100, 2);
-       clks[IMX6UL_CLK_PLL2_PFD3] = imx_clk_pfd("pll2_pfd3_594m", "pll2_bus",     base + 0x100, 3);
-       clks[IMX6UL_CLK_PLL3_PFD0] = imx_clk_pfd("pll3_pfd0_720m", "pll3_usb_otg", base + 0xf0,  0);
-       clks[IMX6UL_CLK_PLL3_PFD1] = imx_clk_pfd("pll3_pfd1_540m", "pll3_usb_otg", base + 0xf0,  1);
-       clks[IMX6UL_CLK_PLL3_PFD2] = imx_clk_pfd("pll3_pfd2_508m", "pll3_usb_otg", base + 0xf0,  2);
-       clks[IMX6UL_CLK_PLL3_PFD3] = imx_clk_pfd("pll3_pfd3_454m", "pll3_usb_otg", base + 0xf0,  3);
-
-       clks[IMX6UL_CLK_ENET_REF] = clk_register_divider_table(NULL, "enet_ref", "pll6_enet", 0,
+       hws[IMX6UL_CLK_PLL2_PFD0] = imx_clk_hw_pfd("pll2_pfd0_352m", "pll2_bus",           base + 0x100, 0);
+       hws[IMX6UL_CLK_PLL2_PFD1] = imx_clk_hw_pfd("pll2_pfd1_594m", "pll2_bus",           base + 0x100, 1);
+       hws[IMX6UL_CLK_PLL2_PFD2] = imx_clk_hw_pfd("pll2_pfd2_396m", "pll2_bus",           base + 0x100, 2);
+       hws[IMX6UL_CLK_PLL2_PFD3] = imx_clk_hw_pfd("pll2_pfd3_594m", "pll2_bus",           base + 0x100, 3);
+       hws[IMX6UL_CLK_PLL3_PFD0] = imx_clk_hw_pfd("pll3_pfd0_720m", "pll3_usb_otg", base + 0xf0,  0);
+       hws[IMX6UL_CLK_PLL3_PFD1] = imx_clk_hw_pfd("pll3_pfd1_540m", "pll3_usb_otg", base + 0xf0,  1);
+       hws[IMX6UL_CLK_PLL3_PFD2] = imx_clk_hw_pfd("pll3_pfd2_508m", "pll3_usb_otg", base + 0xf0,        2);
+       hws[IMX6UL_CLK_PLL3_PFD3] = imx_clk_hw_pfd("pll3_pfd3_454m", "pll3_usb_otg", base + 0xf0,        3);
+
+       hws[IMX6UL_CLK_ENET_REF] = clk_hw_register_divider_table(NULL, "enet_ref", "pll6_enet", 0,
                        base + 0xe0, 0, 2, 0, clk_enet_ref_table, &imx_ccm_lock);
-       clks[IMX6UL_CLK_ENET2_REF] = clk_register_divider_table(NULL, "enet2_ref", "pll6_enet", 0,
+       hws[IMX6UL_CLK_ENET2_REF] = clk_hw_register_divider_table(NULL, "enet2_ref", "pll6_enet", 0,
                        base + 0xe0, 2, 2, 0, clk_enet_ref_table, &imx_ccm_lock);
 
-       clks[IMX6UL_CLK_ENET2_REF_125M] = imx_clk_gate("enet_ref_125m", "enet2_ref", base + 0xe0, 20);
-       clks[IMX6UL_CLK_ENET_PTP_REF]   = imx_clk_fixed_factor("enet_ptp_ref", "pll6_enet", 1, 20);
-       clks[IMX6UL_CLK_ENET_PTP]       = imx_clk_gate("enet_ptp", "enet_ptp_ref", base + 0xe0, 21);
+       hws[IMX6UL_CLK_ENET2_REF_125M] = imx_clk_hw_gate("enet_ref_125m", "enet2_ref", base + 0xe0, 20);
+       hws[IMX6UL_CLK_ENET_PTP_REF]    = imx_clk_hw_fixed_factor("enet_ptp_ref", "pll6_enet", 1, 20);
+       hws[IMX6UL_CLK_ENET_PTP]        = imx_clk_hw_gate("enet_ptp", "enet_ptp_ref", base + 0xe0, 21);
 
-       clks[IMX6UL_CLK_PLL4_POST_DIV]  = clk_register_divider_table(NULL, "pll4_post_div", "pll4_audio",
+       hws[IMX6UL_CLK_PLL4_POST_DIV]  = clk_hw_register_divider_table(NULL, "pll4_post_div", "pll4_audio",
                 CLK_SET_RATE_PARENT | CLK_SET_RATE_GATE, base + 0x70, 19, 2, 0, post_div_table, &imx_ccm_lock);
-       clks[IMX6UL_CLK_PLL4_AUDIO_DIV] = clk_register_divider(NULL, "pll4_audio_div", "pll4_post_div",
+       hws[IMX6UL_CLK_PLL4_AUDIO_DIV] = clk_hw_register_divider(NULL, "pll4_audio_div", "pll4_post_div",
                 CLK_SET_RATE_PARENT | CLK_SET_RATE_GATE, base + 0x170, 15, 1, 0, &imx_ccm_lock);
-       clks[IMX6UL_CLK_PLL5_POST_DIV]  = clk_register_divider_table(NULL, "pll5_post_div", "pll5_video",
+       hws[IMX6UL_CLK_PLL5_POST_DIV]  = clk_hw_register_divider_table(NULL, "pll5_post_div", "pll5_video",
                 CLK_SET_RATE_PARENT | CLK_SET_RATE_GATE, base + 0xa0, 19, 2, 0, post_div_table, &imx_ccm_lock);
-       clks[IMX6UL_CLK_PLL5_VIDEO_DIV] = clk_register_divider_table(NULL, "pll5_video_div", "pll5_post_div",
+       hws[IMX6UL_CLK_PLL5_VIDEO_DIV] = clk_hw_register_divider_table(NULL, "pll5_video_div", "pll5_post_div",
                 CLK_SET_RATE_PARENT | CLK_SET_RATE_GATE, base + 0x170, 30, 2, 0, video_div_table, &imx_ccm_lock);
 
        /*                                                 name         parent_name      mult  div */
-       clks[IMX6UL_CLK_PLL2_198M] = imx_clk_fixed_factor("pll2_198m", "pll2_pfd2_396m", 1,     2);
-       clks[IMX6UL_CLK_PLL3_80M]  = imx_clk_fixed_factor("pll3_80m",  "pll3_usb_otg",   1,     6);
-       clks[IMX6UL_CLK_PLL3_60M]  = imx_clk_fixed_factor("pll3_60m",  "pll3_usb_otg",   1,     8);
-       clks[IMX6UL_CLK_GPT_3M]    = imx_clk_fixed_factor("gpt_3m",     "osc",           1,     8);
+       hws[IMX6UL_CLK_PLL2_198M] = imx_clk_hw_fixed_factor("pll2_198m", "pll2_pfd2_396m", 1,   2);
+       hws[IMX6UL_CLK_PLL3_80M]  = imx_clk_hw_fixed_factor("pll3_80m",  "pll3_usb_otg",   1,   6);
+       hws[IMX6UL_CLK_PLL3_60M]  = imx_clk_hw_fixed_factor("pll3_60m",  "pll3_usb_otg",   1,   8);
+       hws[IMX6UL_CLK_GPT_3M]     = imx_clk_hw_fixed_factor("gpt_3m",  "osc",           1,     8);
 
        np = ccm_node;
        base = of_iomap(np, 0);
        WARN_ON(!base);
 
-       clks[IMX6UL_CA7_SECONDARY_SEL]    = imx_clk_mux("ca7_secondary_sel", base + 0xc, 3, 1, ca7_secondary_sels, ARRAY_SIZE(ca7_secondary_sels));
-       clks[IMX6UL_CLK_STEP]             = imx_clk_mux("step", base + 0x0c, 8, 1, step_sels, ARRAY_SIZE(step_sels));
-       clks[IMX6UL_CLK_PLL1_SW]          = imx_clk_mux_flags("pll1_sw",   base + 0x0c, 2,  1, pll1_sw_sels, ARRAY_SIZE(pll1_sw_sels), 0);
-       clks[IMX6UL_CLK_AXI_ALT_SEL]      = imx_clk_mux("axi_alt_sel",          base + 0x14, 7,  1, axi_alt_sels, ARRAY_SIZE(axi_alt_sels));
-       clks[IMX6UL_CLK_AXI_SEL]          = imx_clk_mux_flags("axi_sel",        base + 0x14, 6,  1, axi_sels, ARRAY_SIZE(axi_sels), 0);
-       clks[IMX6UL_CLK_PERIPH_PRE]       = imx_clk_mux("periph_pre",       base + 0x18, 18, 2, periph_pre_sels, ARRAY_SIZE(periph_pre_sels));
-       clks[IMX6UL_CLK_PERIPH2_PRE]      = imx_clk_mux("periph2_pre",      base + 0x18, 21, 2, periph2_pre_sels, ARRAY_SIZE(periph2_pre_sels));
-       clks[IMX6UL_CLK_PERIPH_CLK2_SEL]  = imx_clk_mux("periph_clk2_sel",  base + 0x18, 12, 2, periph_clk2_sels, ARRAY_SIZE(periph_clk2_sels));
-       clks[IMX6UL_CLK_PERIPH2_CLK2_SEL] = imx_clk_mux("periph2_clk2_sel", base + 0x18, 20, 1, periph2_clk2_sels, ARRAY_SIZE(periph2_clk2_sels));
-       clks[IMX6UL_CLK_EIM_SLOW_SEL]     = imx_clk_mux("eim_slow_sel", base + 0x1c, 29, 2, eim_slow_sels, ARRAY_SIZE(eim_slow_sels));
-       clks[IMX6UL_CLK_GPMI_SEL]         = imx_clk_mux("gpmi_sel",     base + 0x1c, 19, 1, gpmi_sels, ARRAY_SIZE(gpmi_sels));
-       clks[IMX6UL_CLK_BCH_SEL]          = imx_clk_mux("bch_sel",      base + 0x1c, 18, 1, bch_sels, ARRAY_SIZE(bch_sels));
-       clks[IMX6UL_CLK_USDHC2_SEL]       = imx_clk_mux("usdhc2_sel",   base + 0x1c, 17, 1, usdhc_sels, ARRAY_SIZE(usdhc_sels));
-       clks[IMX6UL_CLK_USDHC1_SEL]       = imx_clk_mux("usdhc1_sel",   base + 0x1c, 16, 1, usdhc_sels, ARRAY_SIZE(usdhc_sels));
-       clks[IMX6UL_CLK_SAI3_SEL]         = imx_clk_mux("sai3_sel",     base + 0x1c, 14, 2, sai_sels, ARRAY_SIZE(sai_sels));
-       clks[IMX6UL_CLK_SAI2_SEL]         = imx_clk_mux("sai2_sel",     base + 0x1c, 12, 2, sai_sels, ARRAY_SIZE(sai_sels));
-       clks[IMX6UL_CLK_SAI1_SEL]         = imx_clk_mux("sai1_sel",     base + 0x1c, 10, 2, sai_sels, ARRAY_SIZE(sai_sels));
-       clks[IMX6UL_CLK_QSPI1_SEL]        = imx_clk_mux("qspi1_sel",    base + 0x1c, 7,  3, qspi1_sels, ARRAY_SIZE(qspi1_sels));
-       clks[IMX6UL_CLK_PERCLK_SEL]       = imx_clk_mux("perclk_sel",   base + 0x1c, 6,  1, perclk_sels, ARRAY_SIZE(perclk_sels));
-       clks[IMX6UL_CLK_CAN_SEL]          = imx_clk_mux("can_sel",      base + 0x20, 8,  2, can_sels, ARRAY_SIZE(can_sels));
+       hws[IMX6UL_CA7_SECONDARY_SEL]     = imx_clk_hw_mux("ca7_secondary_sel", base + 0xc, 3, 1, ca7_secondary_sels, ARRAY_SIZE(ca7_secondary_sels));
+       hws[IMX6UL_CLK_STEP]              = imx_clk_hw_mux("step", base + 0x0c, 8, 1, step_sels, ARRAY_SIZE(step_sels));
+       hws[IMX6UL_CLK_PLL1_SW]   = imx_clk_hw_mux_flags("pll1_sw",   base + 0x0c, 2,  1, pll1_sw_sels, ARRAY_SIZE(pll1_sw_sels), 0);
+       hws[IMX6UL_CLK_AXI_ALT_SEL]       = imx_clk_hw_mux("axi_alt_sel",               base + 0x14, 7,  1, axi_alt_sels, ARRAY_SIZE(axi_alt_sels));
+       hws[IMX6UL_CLK_AXI_SEL]   = imx_clk_hw_mux_flags("axi_sel",     base + 0x14, 6,  1, axi_sels, ARRAY_SIZE(axi_sels), 0);
+       hws[IMX6UL_CLK_PERIPH_PRE]        = imx_clk_hw_mux("periph_pre",       base + 0x18, 18, 2, periph_pre_sels, ARRAY_SIZE(periph_pre_sels));
+       hws[IMX6UL_CLK_PERIPH2_PRE]       = imx_clk_hw_mux("periph2_pre",      base + 0x18, 21, 2, periph2_pre_sels, ARRAY_SIZE(periph2_pre_sels));
+       hws[IMX6UL_CLK_PERIPH_CLK2_SEL]  = imx_clk_hw_mux("periph_clk2_sel",  base + 0x18, 12, 2, periph_clk2_sels, ARRAY_SIZE(periph_clk2_sels));
+       hws[IMX6UL_CLK_PERIPH2_CLK2_SEL] = imx_clk_hw_mux("periph2_clk2_sel", base + 0x18, 20, 1, periph2_clk2_sels, ARRAY_SIZE(periph2_clk2_sels));
+       hws[IMX6UL_CLK_EIM_SLOW_SEL]      = imx_clk_hw_mux("eim_slow_sel", base + 0x1c, 29, 2, eim_slow_sels, ARRAY_SIZE(eim_slow_sels));
+       hws[IMX6UL_CLK_GPMI_SEL]          = imx_clk_hw_mux("gpmi_sel",     base + 0x1c, 19, 1, gpmi_sels, ARRAY_SIZE(gpmi_sels));
+       hws[IMX6UL_CLK_BCH_SEL]   = imx_clk_hw_mux("bch_sel",   base + 0x1c, 18, 1, bch_sels, ARRAY_SIZE(bch_sels));
+       hws[IMX6UL_CLK_USDHC2_SEL]        = imx_clk_hw_mux("usdhc2_sel",   base + 0x1c, 17, 1, usdhc_sels, ARRAY_SIZE(usdhc_sels));
+       hws[IMX6UL_CLK_USDHC1_SEL]        = imx_clk_hw_mux("usdhc1_sel",   base + 0x1c, 16, 1, usdhc_sels, ARRAY_SIZE(usdhc_sels));
+       hws[IMX6UL_CLK_SAI3_SEL]          = imx_clk_hw_mux("sai3_sel",     base + 0x1c, 14, 2, sai_sels, ARRAY_SIZE(sai_sels));
+       hws[IMX6UL_CLK_SAI2_SEL]         = imx_clk_hw_mux("sai2_sel",     base + 0x1c, 12, 2, sai_sels, ARRAY_SIZE(sai_sels));
+       hws[IMX6UL_CLK_SAI1_SEL]          = imx_clk_hw_mux("sai1_sel",     base + 0x1c, 10, 2, sai_sels, ARRAY_SIZE(sai_sels));
+       hws[IMX6UL_CLK_QSPI1_SEL]         = imx_clk_hw_mux("qspi1_sel",    base + 0x1c, 7,  3, qspi1_sels, ARRAY_SIZE(qspi1_sels));
+       hws[IMX6UL_CLK_PERCLK_SEL]        = imx_clk_hw_mux("perclk_sel",        base + 0x1c, 6,  1, perclk_sels, ARRAY_SIZE(perclk_sels));
+       hws[IMX6UL_CLK_CAN_SEL]   = imx_clk_hw_mux("can_sel",   base + 0x20, 8,  2, can_sels, ARRAY_SIZE(can_sels));
        if (clk_on_imx6ull())
-               clks[IMX6ULL_CLK_ESAI_SEL]        = imx_clk_mux("esai_sel",     base + 0x20, 19, 2, esai_sels, ARRAY_SIZE(esai_sels));
-       clks[IMX6UL_CLK_UART_SEL]         = imx_clk_mux("uart_sel",     base + 0x24, 6,  1, uart_sels, ARRAY_SIZE(uart_sels));
-       clks[IMX6UL_CLK_ENFC_SEL]         = imx_clk_mux("enfc_sel",     base + 0x2c, 15, 3, enfc_sels, ARRAY_SIZE(enfc_sels));
-       clks[IMX6UL_CLK_LDB_DI0_SEL]      = imx_clk_mux("ldb_di0_sel",  base + 0x2c, 9,  3, ldb_di0_sels, ARRAY_SIZE(ldb_di0_sels));
-       clks[IMX6UL_CLK_SPDIF_SEL]        = imx_clk_mux("spdif_sel",    base + 0x30, 20, 2, spdif_sels, ARRAY_SIZE(spdif_sels));
+               hws[IMX6ULL_CLK_ESAI_SEL]         = imx_clk_hw_mux("esai_sel",  base + 0x20, 19, 2, esai_sels, ARRAY_SIZE(esai_sels));
+       hws[IMX6UL_CLK_UART_SEL]          = imx_clk_hw_mux("uart_sel",  base + 0x24, 6,  1, uart_sels, ARRAY_SIZE(uart_sels));
+       hws[IMX6UL_CLK_ENFC_SEL]          = imx_clk_hw_mux("enfc_sel",  base + 0x2c, 15, 3, enfc_sels, ARRAY_SIZE(enfc_sels));
+       hws[IMX6UL_CLK_LDB_DI0_SEL]       = imx_clk_hw_mux("ldb_di0_sel",       base + 0x2c, 9,  3, ldb_di0_sels, ARRAY_SIZE(ldb_di0_sels));
+       hws[IMX6UL_CLK_SPDIF_SEL]         = imx_clk_hw_mux("spdif_sel", base + 0x30, 20, 2, spdif_sels, ARRAY_SIZE(spdif_sels));
        if (clk_on_imx6ul()) {
-               clks[IMX6UL_CLK_SIM_PRE_SEL]      = imx_clk_mux("sim_pre_sel",  base + 0x34, 15, 3, sim_pre_sels, ARRAY_SIZE(sim_pre_sels));
-               clks[IMX6UL_CLK_SIM_SEL]          = imx_clk_mux("sim_sel",      base + 0x34, 9, 3, sim_sels, ARRAY_SIZE(sim_sels));
+               hws[IMX6UL_CLK_SIM_PRE_SEL]     = imx_clk_hw_mux("sim_pre_sel", base + 0x34, 15, 3, sim_pre_sels, ARRAY_SIZE(sim_pre_sels));
+               hws[IMX6UL_CLK_SIM_SEL]         = imx_clk_hw_mux("sim_sel",     base + 0x34, 9, 3, sim_sels, ARRAY_SIZE(sim_sels));
        } else if (clk_on_imx6ull()) {
-               clks[IMX6ULL_CLK_EPDC_PRE_SEL]    = imx_clk_mux("epdc_pre_sel", base + 0x34, 15, 3, epdc_pre_sels, ARRAY_SIZE(epdc_pre_sels));
-               clks[IMX6ULL_CLK_EPDC_SEL]        = imx_clk_mux("epdc_sel",     base + 0x34, 9, 3, epdc_sels, ARRAY_SIZE(epdc_sels));
+               hws[IMX6ULL_CLK_EPDC_PRE_SEL]   = imx_clk_hw_mux("epdc_pre_sel",        base + 0x34, 15, 3, epdc_pre_sels, ARRAY_SIZE(epdc_pre_sels));
+               hws[IMX6ULL_CLK_EPDC_SEL]       = imx_clk_hw_mux("epdc_sel",    base + 0x34, 9, 3, epdc_sels, ARRAY_SIZE(epdc_sels));
        }
-       clks[IMX6UL_CLK_ECSPI_SEL]        = imx_clk_mux("ecspi_sel",    base + 0x38, 18, 1, ecspi_sels, ARRAY_SIZE(ecspi_sels));
-       clks[IMX6UL_CLK_LCDIF_PRE_SEL]    = imx_clk_mux_flags("lcdif_pre_sel", base + 0x38, 15, 3, lcdif_pre_sels, ARRAY_SIZE(lcdif_pre_sels), CLK_SET_RATE_PARENT);
-       clks[IMX6UL_CLK_LCDIF_SEL]        = imx_clk_mux("lcdif_sel",    base + 0x38, 9, 3, lcdif_sels, ARRAY_SIZE(lcdif_sels));
-
-       clks[IMX6UL_CLK_LDB_DI0_DIV_SEL]  = imx_clk_mux("ldb_di0", base + 0x20, 10, 1, ldb_di0_div_sels, ARRAY_SIZE(ldb_di0_div_sels));
-       clks[IMX6UL_CLK_LDB_DI1_DIV_SEL]  = imx_clk_mux("ldb_di1", base + 0x20, 11, 1, ldb_di1_div_sels, ARRAY_SIZE(ldb_di1_div_sels));
-
-       clks[IMX6UL_CLK_CKO1_SEL]         = imx_clk_mux("cko1_sel", base + 0x60, 0,  4, cko1_sels, ARRAY_SIZE(cko1_sels));
-       clks[IMX6UL_CLK_CKO2_SEL]         = imx_clk_mux("cko2_sel", base + 0x60, 16, 5, cko2_sels, ARRAY_SIZE(cko2_sels));
-       clks[IMX6UL_CLK_CKO]              = imx_clk_mux("cko", base + 0x60, 8, 1, cko_sels, ARRAY_SIZE(cko_sels));
-
-       clks[IMX6UL_CLK_LDB_DI0_DIV_3_5] = imx_clk_fixed_factor("ldb_di0_div_3_5", "ldb_di0_sel", 2, 7);
-       clks[IMX6UL_CLK_LDB_DI0_DIV_7]   = imx_clk_fixed_factor("ldb_di0_div_7",   "ldb_di0_sel", 1, 7);
-       clks[IMX6UL_CLK_LDB_DI1_DIV_3_5] = imx_clk_fixed_factor("ldb_di1_div_3_5", "qspi1_sel", 2, 7);
-       clks[IMX6UL_CLK_LDB_DI1_DIV_7]   = imx_clk_fixed_factor("ldb_di1_div_7",   "qspi1_sel", 1, 7);
-
-       clks[IMX6UL_CLK_PERIPH]  = imx_clk_busy_mux("periph",  base + 0x14, 25, 1, base + 0x48, 5, periph_sels, ARRAY_SIZE(periph_sels));
-       clks[IMX6UL_CLK_PERIPH2] = imx_clk_busy_mux("periph2", base + 0x14, 26, 1, base + 0x48, 3, periph2_sels, ARRAY_SIZE(periph2_sels));
-
-       clks[IMX6UL_CLK_PERIPH_CLK2]    = imx_clk_divider("periph_clk2",   "periph_clk2_sel",   base + 0x14, 27, 3);
-       clks[IMX6UL_CLK_PERIPH2_CLK2]   = imx_clk_divider("periph2_clk2",  "periph2_clk2_sel",  base + 0x14, 0,  3);
-       clks[IMX6UL_CLK_IPG]            = imx_clk_divider("ipg",           "ahb",               base + 0x14, 8,  2);
-       clks[IMX6UL_CLK_LCDIF_PODF]     = imx_clk_divider("lcdif_podf",    "lcdif_pred",        base + 0x18, 23, 3);
-       clks[IMX6UL_CLK_QSPI1_PDOF]     = imx_clk_divider("qspi1_podf",    "qspi1_sel",         base + 0x1c, 26, 3);
-       clks[IMX6UL_CLK_EIM_SLOW_PODF]  = imx_clk_divider("eim_slow_podf", "eim_slow_sel",      base + 0x1c, 23, 3);
-       clks[IMX6UL_CLK_PERCLK]         = imx_clk_divider("perclk",        "perclk_sel",        base + 0x1c, 0,  6);
-       clks[IMX6UL_CLK_CAN_PODF]       = imx_clk_divider("can_podf",      "can_sel",           base + 0x20, 2,  6);
-       clks[IMX6UL_CLK_GPMI_PODF]      = imx_clk_divider("gpmi_podf",     "gpmi_sel",          base + 0x24, 22, 3);
-       clks[IMX6UL_CLK_BCH_PODF]       = imx_clk_divider("bch_podf",      "bch_sel",           base + 0x24, 19, 3);
-       clks[IMX6UL_CLK_USDHC2_PODF]    = imx_clk_divider("usdhc2_podf",   "usdhc2_sel",        base + 0x24, 16, 3);
-       clks[IMX6UL_CLK_USDHC1_PODF]    = imx_clk_divider("usdhc1_podf",   "usdhc1_sel",        base + 0x24, 11, 3);
-       clks[IMX6UL_CLK_UART_PODF]      = imx_clk_divider("uart_podf",     "uart_sel",          base + 0x24, 0,  6);
-       clks[IMX6UL_CLK_SAI3_PRED]      = imx_clk_divider("sai3_pred",     "sai3_sel",          base + 0x28, 22, 3);
-       clks[IMX6UL_CLK_SAI3_PODF]      = imx_clk_divider("sai3_podf",     "sai3_pred",         base + 0x28, 16, 6);
-       clks[IMX6UL_CLK_SAI1_PRED]      = imx_clk_divider("sai1_pred",     "sai1_sel",          base + 0x28, 6,  3);
-       clks[IMX6UL_CLK_SAI1_PODF]      = imx_clk_divider("sai1_podf",     "sai1_pred",         base + 0x28, 0,  6);
+       hws[IMX6UL_CLK_ECSPI_SEL]         = imx_clk_hw_mux("ecspi_sel", base + 0x38, 18, 1, ecspi_sels, ARRAY_SIZE(ecspi_sels));
+       hws[IMX6UL_CLK_LCDIF_PRE_SEL]     = imx_clk_hw_mux_flags("lcdif_pre_sel", base + 0x38, 15, 3, lcdif_pre_sels, ARRAY_SIZE(lcdif_pre_sels), CLK_SET_RATE_PARENT);
+       hws[IMX6UL_CLK_LCDIF_SEL]         = imx_clk_hw_mux("lcdif_sel", base + 0x38, 9, 3, lcdif_sels, ARRAY_SIZE(lcdif_sels));
+
+       hws[IMX6UL_CLK_LDB_DI0_DIV_SEL]  = imx_clk_hw_mux("ldb_di0", base + 0x20, 10, 1, ldb_di0_div_sels, ARRAY_SIZE(ldb_di0_div_sels));
+       hws[IMX6UL_CLK_LDB_DI1_DIV_SEL]  = imx_clk_hw_mux("ldb_di1", base + 0x20, 11, 1, ldb_di1_div_sels, ARRAY_SIZE(ldb_di1_div_sels));
+
+       hws[IMX6UL_CLK_CKO1_SEL]          = imx_clk_hw_mux("cko1_sel", base + 0x60, 0,  4, cko1_sels, ARRAY_SIZE(cko1_sels));
+       hws[IMX6UL_CLK_CKO2_SEL]          = imx_clk_hw_mux("cko2_sel", base + 0x60, 16, 5, cko2_sels, ARRAY_SIZE(cko2_sels));
+       hws[IMX6UL_CLK_CKO]               = imx_clk_hw_mux("cko", base + 0x60, 8, 1, cko_sels, ARRAY_SIZE(cko_sels));
+
+       hws[IMX6UL_CLK_LDB_DI0_DIV_3_5] = imx_clk_hw_fixed_factor("ldb_di0_div_3_5", "ldb_di0_sel", 2, 7);
+       hws[IMX6UL_CLK_LDB_DI0_DIV_7]    = imx_clk_hw_fixed_factor("ldb_di0_div_7",   "ldb_di0_sel", 1, 7);
+       hws[IMX6UL_CLK_LDB_DI1_DIV_3_5] = imx_clk_hw_fixed_factor("ldb_di1_div_3_5", "qspi1_sel", 2, 7);
+       hws[IMX6UL_CLK_LDB_DI1_DIV_7]    = imx_clk_hw_fixed_factor("ldb_di1_div_7",   "qspi1_sel", 1, 7);
+
+       hws[IMX6UL_CLK_PERIPH]  = imx_clk_hw_busy_mux("periph",  base + 0x14, 25, 1, base + 0x48, 5, periph_sels, ARRAY_SIZE(periph_sels));
+       hws[IMX6UL_CLK_PERIPH2] = imx_clk_hw_busy_mux("periph2", base + 0x14, 26, 1, base + 0x48, 3, periph2_sels, ARRAY_SIZE(periph2_sels));
+
+       hws[IMX6UL_CLK_PERIPH_CLK2]     = imx_clk_hw_divider("periph_clk2",   "periph_clk2_sel",        base + 0x14, 27, 3);
+       hws[IMX6UL_CLK_PERIPH2_CLK2]    = imx_clk_hw_divider("periph2_clk2",  "periph2_clk2_sel",       base + 0x14, 0,  3);
+       hws[IMX6UL_CLK_IPG]             = imx_clk_hw_divider("ipg",        "ahb",               base + 0x14, 8,  2);
+       hws[IMX6UL_CLK_LCDIF_PODF]      = imx_clk_hw_divider("lcdif_podf",         "lcdif_pred",        base + 0x18, 23, 3);
+       hws[IMX6UL_CLK_QSPI1_PDOF]      = imx_clk_hw_divider("qspi1_podf",         "qspi1_sel",         base + 0x1c, 26, 3);
+       hws[IMX6UL_CLK_EIM_SLOW_PODF]   = imx_clk_hw_divider("eim_slow_podf", "eim_slow_sel",   base + 0x1c, 23, 3);
+       hws[IMX6UL_CLK_PERCLK]          = imx_clk_hw_divider("perclk",     "perclk_sel",        base + 0x1c, 0,  6);
+       hws[IMX6UL_CLK_CAN_PODF]        = imx_clk_hw_divider("can_podf",           "can_sel",           base + 0x20, 2,  6);
+       hws[IMX6UL_CLK_GPMI_PODF]       = imx_clk_hw_divider("gpmi_podf",          "gpmi_sel",          base + 0x24, 22, 3);
+       hws[IMX6UL_CLK_BCH_PODF]        = imx_clk_hw_divider("bch_podf",           "bch_sel",           base + 0x24, 19, 3);
+       hws[IMX6UL_CLK_USDHC2_PODF]     = imx_clk_hw_divider("usdhc2_podf",   "usdhc2_sel",     base + 0x24, 16, 3);
+       hws[IMX6UL_CLK_USDHC1_PODF]     = imx_clk_hw_divider("usdhc1_podf",   "usdhc1_sel",     base + 0x24, 11, 3);
+       hws[IMX6UL_CLK_UART_PODF]       = imx_clk_hw_divider("uart_podf",          "uart_sel",          base + 0x24, 0,  6);
+       hws[IMX6UL_CLK_SAI3_PRED]       = imx_clk_hw_divider("sai3_pred",          "sai3_sel",          base + 0x28, 22, 3);
+       hws[IMX6UL_CLK_SAI3_PODF]       = imx_clk_hw_divider("sai3_podf",          "sai3_pred",         base + 0x28, 16, 6);
+       hws[IMX6UL_CLK_SAI1_PRED]       = imx_clk_hw_divider("sai1_pred",          "sai1_sel",          base + 0x28, 6,  3);
+       hws[IMX6UL_CLK_SAI1_PODF]       = imx_clk_hw_divider("sai1_podf",          "sai1_pred",         base + 0x28, 0,  6);
        if (clk_on_imx6ull()) {
-               clks[IMX6ULL_CLK_ESAI_PRED]     = imx_clk_divider("esai_pred",     "esai_sel",          base + 0x28, 9,  3);
-               clks[IMX6ULL_CLK_ESAI_PODF]     = imx_clk_divider("esai_podf",     "esai_pred",         base + 0x28, 25, 3);
+               hws[IMX6ULL_CLK_ESAI_PRED]      = imx_clk_hw_divider("esai_pred",     "esai_sel",               base + 0x28, 9,  3);
+               hws[IMX6ULL_CLK_ESAI_PODF]      = imx_clk_hw_divider("esai_podf",     "esai_pred",              base + 0x28, 25, 3);
        }
-       clks[IMX6UL_CLK_ENFC_PRED]      = imx_clk_divider("enfc_pred",     "enfc_sel",          base + 0x2c, 18, 3);
-       clks[IMX6UL_CLK_ENFC_PODF]      = imx_clk_divider("enfc_podf",     "enfc_pred",         base + 0x2c, 21, 6);
-       clks[IMX6UL_CLK_SAI2_PRED]      = imx_clk_divider("sai2_pred",     "sai2_sel",          base + 0x2c, 6,  3);
-       clks[IMX6UL_CLK_SAI2_PODF]      = imx_clk_divider("sai2_podf",     "sai2_pred",         base + 0x2c, 0,  6);
-       clks[IMX6UL_CLK_SPDIF_PRED]     = imx_clk_divider("spdif_pred",    "spdif_sel",         base + 0x30, 25, 3);
-       clks[IMX6UL_CLK_SPDIF_PODF]     = imx_clk_divider("spdif_podf",    "spdif_pred",        base + 0x30, 22, 3);
+       hws[IMX6UL_CLK_ENFC_PRED]       = imx_clk_hw_divider("enfc_pred",          "enfc_sel",          base + 0x2c, 18, 3);
+       hws[IMX6UL_CLK_ENFC_PODF]       = imx_clk_hw_divider("enfc_podf",          "enfc_pred",         base + 0x2c, 21, 6);
+       hws[IMX6UL_CLK_SAI2_PRED]       = imx_clk_hw_divider("sai2_pred",          "sai2_sel",          base + 0x2c, 6,  3);
+       hws[IMX6UL_CLK_SAI2_PODF]       = imx_clk_hw_divider("sai2_podf",          "sai2_pred",         base + 0x2c, 0,  6);
+       hws[IMX6UL_CLK_SPDIF_PRED]      = imx_clk_hw_divider("spdif_pred",         "spdif_sel",         base + 0x30, 25, 3);
+       hws[IMX6UL_CLK_SPDIF_PODF]      = imx_clk_hw_divider("spdif_podf",         "spdif_pred",        base + 0x30, 22, 3);
        if (clk_on_imx6ul())
-               clks[IMX6UL_CLK_SIM_PODF]       = imx_clk_divider("sim_podf",      "sim_pre_sel",       base + 0x34, 12, 3);
+               hws[IMX6UL_CLK_SIM_PODF]        = imx_clk_hw_divider("sim_podf",           "sim_pre_sel",       base + 0x34, 12, 3);
        else if (clk_on_imx6ull())
-               clks[IMX6ULL_CLK_EPDC_PODF]     = imx_clk_divider("epdc_podf",     "epdc_pre_sel",      base + 0x34, 12, 3);
-       clks[IMX6UL_CLK_ECSPI_PODF]     = imx_clk_divider("ecspi_podf",    "ecspi_sel",         base + 0x38, 19, 6);
-       clks[IMX6UL_CLK_LCDIF_PRED]     = imx_clk_divider("lcdif_pred",    "lcdif_pre_sel",     base + 0x38, 12, 3);
-       clks[IMX6UL_CLK_CSI_PODF]       = imx_clk_divider("csi_podf",      "csi_sel",           base + 0x3c, 11, 3);
+               hws[IMX6ULL_CLK_EPDC_PODF]      = imx_clk_hw_divider("epdc_podf",          "epdc_pre_sel",      base + 0x34, 12, 3);
+       hws[IMX6UL_CLK_ECSPI_PODF]      = imx_clk_hw_divider("ecspi_podf",         "ecspi_sel",         base + 0x38, 19, 6);
+       hws[IMX6UL_CLK_LCDIF_PRED]      = imx_clk_hw_divider("lcdif_pred",         "lcdif_pre_sel",     base + 0x38, 12, 3);
+       hws[IMX6UL_CLK_CSI_PODF]       = imx_clk_hw_divider("csi_podf",      "csi_sel",           base + 0x3c, 11, 3);
 
-       clks[IMX6UL_CLK_CKO1_PODF]      = imx_clk_divider("cko1_podf",     "cko1_sel",          base + 0x60, 4,  3);
-       clks[IMX6UL_CLK_CKO2_PODF]      = imx_clk_divider("cko2_podf",     "cko2_sel",          base + 0x60, 21, 3);
+       hws[IMX6UL_CLK_CKO1_PODF]       = imx_clk_hw_divider("cko1_podf",     "cko1_sel",          base + 0x60, 4,  3);
+       hws[IMX6UL_CLK_CKO2_PODF]       = imx_clk_hw_divider("cko2_podf",     "cko2_sel",          base + 0x60, 21, 3);
 
-       clks[IMX6UL_CLK_ARM]            = imx_clk_busy_divider("arm",       "pll1_sw",  base +  0x10, 0,  3,  base + 0x48, 16);
-       clks[IMX6UL_CLK_MMDC_PODF]      = imx_clk_busy_divider("mmdc_podf", "periph2",  base +  0x14, 3,  3,  base + 0x48, 2);
-       clks[IMX6UL_CLK_AXI_PODF]       = imx_clk_busy_divider("axi_podf",  "axi_sel",  base +  0x14, 16, 3,  base + 0x48, 0);
-       clks[IMX6UL_CLK_AHB]            = imx_clk_busy_divider("ahb",       "periph",   base +  0x14, 10, 3,  base + 0x48, 1);
+       hws[IMX6UL_CLK_ARM]             = imx_clk_hw_busy_divider("arm",            "pll1_sw",  base +  0x10, 0,  3,  base + 0x48, 16);
+       hws[IMX6UL_CLK_MMDC_PODF]       = imx_clk_hw_busy_divider("mmdc_podf", "periph2",       base +  0x14, 3,  3,  base + 0x48, 2);
+       hws[IMX6UL_CLK_AXI_PODF]        = imx_clk_hw_busy_divider("axi_podf",  "axi_sel",       base +  0x14, 16, 3,  base + 0x48, 0);
+       hws[IMX6UL_CLK_AHB]             = imx_clk_hw_busy_divider("ahb",            "periph",   base +  0x14, 10, 3,  base + 0x48, 1);
 
        /* CCGR0 */
-       clks[IMX6UL_CLK_AIPSTZ1]        = imx_clk_gate2_flags("aips_tz1", "ahb", base + 0x68, 0, CLK_IS_CRITICAL);
-       clks[IMX6UL_CLK_AIPSTZ2]        = imx_clk_gate2_flags("aips_tz2", "ahb", base + 0x68, 2, CLK_IS_CRITICAL);
-       clks[IMX6UL_CLK_APBHDMA]        = imx_clk_gate2("apbh_dma",     "bch_podf",     base + 0x68,    4);
-       clks[IMX6UL_CLK_ASRC_IPG]       = imx_clk_gate2_shared("asrc_ipg",      "ahb",  base + 0x68,    6, &share_count_asrc);
-       clks[IMX6UL_CLK_ASRC_MEM]       = imx_clk_gate2_shared("asrc_mem",      "ahb",  base + 0x68,    6, &share_count_asrc);
+       hws[IMX6UL_CLK_AIPSTZ1] = imx_clk_hw_gate2_flags("aips_tz1", "ahb", base + 0x68, 0, CLK_IS_CRITICAL);
+       hws[IMX6UL_CLK_AIPSTZ2] = imx_clk_hw_gate2_flags("aips_tz2", "ahb", base + 0x68, 2, CLK_IS_CRITICAL);
+       hws[IMX6UL_CLK_APBHDMA] = imx_clk_hw_gate2("apbh_dma",  "bch_podf",     base + 0x68,    4);
+       hws[IMX6UL_CLK_ASRC_IPG]        = imx_clk_hw_gate2_shared("asrc_ipg",   "ahb",  base + 0x68,    6, &share_count_asrc);
+       hws[IMX6UL_CLK_ASRC_MEM]        = imx_clk_hw_gate2_shared("asrc_mem",   "ahb",  base + 0x68,    6, &share_count_asrc);
        if (clk_on_imx6ul()) {
-               clks[IMX6UL_CLK_CAAM_MEM]       = imx_clk_gate2("caam_mem",     "ahb",          base + 0x68,    8);
-               clks[IMX6UL_CLK_CAAM_ACLK]      = imx_clk_gate2("caam_aclk",    "ahb",          base + 0x68,    10);
-               clks[IMX6UL_CLK_CAAM_IPG]       = imx_clk_gate2("caam_ipg",     "ipg",          base + 0x68,    12);
+               hws[IMX6UL_CLK_CAAM_MEM]        = imx_clk_hw_gate2("caam_mem",  "ahb",          base + 0x68,    8);
+               hws[IMX6UL_CLK_CAAM_ACLK]       = imx_clk_hw_gate2("caam_aclk", "ahb",          base + 0x68,    10);
+               hws[IMX6UL_CLK_CAAM_IPG]        = imx_clk_hw_gate2("caam_ipg",  "ipg",          base + 0x68,    12);
        } else if (clk_on_imx6ull()) {
-               clks[IMX6ULL_CLK_DCP_CLK]       = imx_clk_gate2("dcp",          "ahb",          base + 0x68,    10);
-               clks[IMX6UL_CLK_ENET]           = imx_clk_gate2("enet",         "ipg",          base + 0x68,    12);
-               clks[IMX6UL_CLK_ENET_AHB]       = imx_clk_gate2("enet_ahb",     "ahb",          base + 0x68,    12);
+               hws[IMX6ULL_CLK_DCP_CLK]        = imx_clk_hw_gate2("dcp",               "ahb",          base + 0x68,    10);
+               hws[IMX6UL_CLK_ENET]            = imx_clk_hw_gate2("enet",              "ipg",          base + 0x68,    12);
+               hws[IMX6UL_CLK_ENET_AHB]        = imx_clk_hw_gate2("enet_ahb",  "ahb",          base + 0x68,    12);
        }
-       clks[IMX6UL_CLK_CAN1_IPG]       = imx_clk_gate2("can1_ipg",     "ipg",          base + 0x68,    14);
-       clks[IMX6UL_CLK_CAN1_SERIAL]    = imx_clk_gate2("can1_serial",  "can_podf",     base + 0x68,    16);
-       clks[IMX6UL_CLK_CAN2_IPG]       = imx_clk_gate2("can2_ipg",     "ipg",          base + 0x68,    18);
-       clks[IMX6UL_CLK_CAN2_SERIAL]    = imx_clk_gate2("can2_serial",  "can_podf",     base + 0x68,    20);
-       clks[IMX6UL_CLK_GPT2_BUS]       = imx_clk_gate2("gpt2_bus",     "perclk",       base + 0x68,    24);
-       clks[IMX6UL_CLK_GPT2_SERIAL]    = imx_clk_gate2("gpt2_serial",  "perclk",       base + 0x68,    26);
-       clks[IMX6UL_CLK_UART2_IPG]      = imx_clk_gate2("uart2_ipg",    "ipg",          base + 0x68,    28);
-       clks[IMX6UL_CLK_UART2_SERIAL]   = imx_clk_gate2("uart2_serial", "uart_podf",    base + 0x68,    28);
+       hws[IMX6UL_CLK_CAN1_IPG]        = imx_clk_hw_gate2("can1_ipg",  "ipg",          base + 0x68,    14);
+       hws[IMX6UL_CLK_CAN1_SERIAL]     = imx_clk_hw_gate2("can1_serial",       "can_podf",     base + 0x68,    16);
+       hws[IMX6UL_CLK_CAN2_IPG]        = imx_clk_hw_gate2("can2_ipg",  "ipg",          base + 0x68,    18);
+       hws[IMX6UL_CLK_CAN2_SERIAL]     = imx_clk_hw_gate2("can2_serial",       "can_podf",     base + 0x68,    20);
+       hws[IMX6UL_CLK_GPT2_BUS]        = imx_clk_hw_gate2("gpt2_bus",  "perclk",       base + 0x68,    24);
+       hws[IMX6UL_CLK_GPT2_SERIAL]     = imx_clk_hw_gate2("gpt2_serial",       "perclk",       base + 0x68,    26);
+       hws[IMX6UL_CLK_UART2_IPG]       = imx_clk_hw_gate2("uart2_ipg", "ipg",          base + 0x68,    28);
+       hws[IMX6UL_CLK_UART2_SERIAL]    = imx_clk_hw_gate2("uart2_serial",      "uart_podf",    base + 0x68,    28);
        if (clk_on_imx6ull())
-               clks[IMX6UL_CLK_AIPSTZ3]        = imx_clk_gate2("aips_tz3",     "ahb",           base + 0x80,   18);
-       clks[IMX6UL_CLK_GPIO2]          = imx_clk_gate2("gpio2",        "ipg",          base + 0x68,    30);
+               hws[IMX6UL_CLK_AIPSTZ3] = imx_clk_hw_gate2("aips_tz3",  "ahb",           base + 0x80,   18);
+       hws[IMX6UL_CLK_GPIO2]           = imx_clk_hw_gate2("gpio2",     "ipg",          base + 0x68,    30);
 
        /* CCGR1 */
-       clks[IMX6UL_CLK_ECSPI1]         = imx_clk_gate2("ecspi1",       "ecspi_podf",   base + 0x6c,    0);
-       clks[IMX6UL_CLK_ECSPI2]         = imx_clk_gate2("ecspi2",       "ecspi_podf",   base + 0x6c,    2);
-       clks[IMX6UL_CLK_ECSPI3]         = imx_clk_gate2("ecspi3",       "ecspi_podf",   base + 0x6c,    4);
-       clks[IMX6UL_CLK_ECSPI4]         = imx_clk_gate2("ecspi4",       "ecspi_podf",   base + 0x6c,    6);
-       clks[IMX6UL_CLK_ADC2]           = imx_clk_gate2("adc2",         "ipg",          base + 0x6c,    8);
-       clks[IMX6UL_CLK_UART3_IPG]      = imx_clk_gate2("uart3_ipg",    "ipg",          base + 0x6c,    10);
-       clks[IMX6UL_CLK_UART3_SERIAL]   = imx_clk_gate2("uart3_serial", "uart_podf",    base + 0x6c,    10);
-       clks[IMX6UL_CLK_EPIT1]          = imx_clk_gate2("epit1",        "perclk",       base + 0x6c,    12);
-       clks[IMX6UL_CLK_EPIT2]          = imx_clk_gate2("epit2",        "perclk",       base + 0x6c,    14);
-       clks[IMX6UL_CLK_ADC1]           = imx_clk_gate2("adc1",         "ipg",          base + 0x6c,    16);
-       clks[IMX6UL_CLK_GPT1_BUS]       = imx_clk_gate2("gpt1_bus",     "perclk",       base + 0x6c,    20);
-       clks[IMX6UL_CLK_GPT1_SERIAL]    = imx_clk_gate2("gpt1_serial",  "perclk",       base + 0x6c,    22);
-       clks[IMX6UL_CLK_UART4_IPG]      = imx_clk_gate2("uart4_ipg",    "ipg",          base + 0x6c,    24);
-       clks[IMX6UL_CLK_UART4_SERIAL]   = imx_clk_gate2("uart4_serial", "uart_podf",    base + 0x6c,    24);
-       clks[IMX6UL_CLK_GPIO1]          = imx_clk_gate2("gpio1",        "ipg",          base + 0x6c,    26);
-       clks[IMX6UL_CLK_GPIO5]          = imx_clk_gate2("gpio5",        "ipg",          base + 0x6c,    30);
+       hws[IMX6UL_CLK_ECSPI1]          = imx_clk_hw_gate2("ecspi1",    "ecspi_podf",   base + 0x6c,    0);
+       hws[IMX6UL_CLK_ECSPI2]          = imx_clk_hw_gate2("ecspi2",    "ecspi_podf",   base + 0x6c,    2);
+       hws[IMX6UL_CLK_ECSPI3]          = imx_clk_hw_gate2("ecspi3",    "ecspi_podf",   base + 0x6c,    4);
+       hws[IMX6UL_CLK_ECSPI4]          = imx_clk_hw_gate2("ecspi4",    "ecspi_podf",   base + 0x6c,    6);
+       hws[IMX6UL_CLK_ADC2]            = imx_clk_hw_gate2("adc2",              "ipg",          base + 0x6c,    8);
+       hws[IMX6UL_CLK_UART3_IPG]       = imx_clk_hw_gate2("uart3_ipg", "ipg",          base + 0x6c,    10);
+       hws[IMX6UL_CLK_UART3_SERIAL]    = imx_clk_hw_gate2("uart3_serial",      "uart_podf",    base + 0x6c,    10);
+       hws[IMX6UL_CLK_EPIT1]           = imx_clk_hw_gate2("epit1",     "perclk",       base + 0x6c,    12);
+       hws[IMX6UL_CLK_EPIT2]           = imx_clk_hw_gate2("epit2",     "perclk",       base + 0x6c,    14);
+       hws[IMX6UL_CLK_ADC1]            = imx_clk_hw_gate2("adc1",              "ipg",          base + 0x6c,    16);
+       hws[IMX6UL_CLK_GPT1_BUS]        = imx_clk_hw_gate2("gpt1_bus",  "perclk",       base + 0x6c,    20);
+       hws[IMX6UL_CLK_GPT1_SERIAL]     = imx_clk_hw_gate2("gpt1_serial",       "perclk",       base + 0x6c,    22);
+       hws[IMX6UL_CLK_UART4_IPG]       = imx_clk_hw_gate2("uart4_ipg", "ipg",          base + 0x6c,    24);
+       hws[IMX6UL_CLK_UART4_SERIAL]    = imx_clk_hw_gate2("uart4_serial",      "uart_podf",    base + 0x6c,    24);
+       hws[IMX6UL_CLK_GPIO1]           = imx_clk_hw_gate2("gpio1",     "ipg",          base + 0x6c,    26);
+       hws[IMX6UL_CLK_GPIO5]           = imx_clk_hw_gate2("gpio5",     "ipg",          base + 0x6c,    30);
 
        /* CCGR2 */
        if (clk_on_imx6ull()) {
-               clks[IMX6ULL_CLK_ESAI_EXTAL]    = imx_clk_gate2_shared("esai_extal",    "esai_podf",    base + 0x70,    0, &share_count_esai);
-               clks[IMX6ULL_CLK_ESAI_IPG]      = imx_clk_gate2_shared("esai_ipg",      "ahb",          base + 0x70,    0, &share_count_esai);
-               clks[IMX6ULL_CLK_ESAI_MEM]      = imx_clk_gate2_shared("esai_mem",      "ahb",          base + 0x70,    0, &share_count_esai);
+               hws[IMX6ULL_CLK_ESAI_EXTAL]     = imx_clk_hw_gate2_shared("esai_extal", "esai_podf",    base + 0x70,    0, &share_count_esai);
+               hws[IMX6ULL_CLK_ESAI_IPG]       = imx_clk_hw_gate2_shared("esai_ipg",   "ahb",          base + 0x70,    0, &share_count_esai);
+               hws[IMX6ULL_CLK_ESAI_MEM]       = imx_clk_hw_gate2_shared("esai_mem",   "ahb",          base + 0x70,    0, &share_count_esai);
        }
-       clks[IMX6UL_CLK_CSI]            = imx_clk_gate2("csi",          "csi_podf",             base + 0x70,    2);
-       clks[IMX6UL_CLK_I2C1]           = imx_clk_gate2("i2c1",         "perclk",       base + 0x70,    6);
-       clks[IMX6UL_CLK_I2C2]           = imx_clk_gate2("i2c2",         "perclk",       base + 0x70,    8);
-       clks[IMX6UL_CLK_I2C3]           = imx_clk_gate2("i2c3",         "perclk",       base + 0x70,    10);
-       clks[IMX6UL_CLK_OCOTP]          = imx_clk_gate2("ocotp",        "ipg",          base + 0x70,    12);
-       clks[IMX6UL_CLK_IOMUXC]         = imx_clk_gate2("iomuxc",       "lcdif_podf",   base + 0x70,    14);
-       clks[IMX6UL_CLK_GPIO3]          = imx_clk_gate2("gpio3",        "ipg",          base + 0x70,    26);
-       clks[IMX6UL_CLK_LCDIF_APB]      = imx_clk_gate2("lcdif_apb",    "axi",          base + 0x70,    28);
-       clks[IMX6UL_CLK_PXP]            = imx_clk_gate2("pxp",          "axi",          base + 0x70,    30);
+       hws[IMX6UL_CLK_CSI]             = imx_clk_hw_gate2("csi",               "csi_podf",             base + 0x70,    2);
+       hws[IMX6UL_CLK_I2C1]            = imx_clk_hw_gate2("i2c1",              "perclk",       base + 0x70,    6);
+       hws[IMX6UL_CLK_I2C2]            = imx_clk_hw_gate2("i2c2",              "perclk",       base + 0x70,    8);
+       hws[IMX6UL_CLK_I2C3]            = imx_clk_hw_gate2("i2c3",              "perclk",       base + 0x70,    10);
+       hws[IMX6UL_CLK_OCOTP]           = imx_clk_hw_gate2("ocotp",     "ipg",          base + 0x70,    12);
+       hws[IMX6UL_CLK_IOMUXC]          = imx_clk_hw_gate2("iomuxc",    "lcdif_podf",   base + 0x70,    14);
+       hws[IMX6UL_CLK_GPIO3]           = imx_clk_hw_gate2("gpio3",     "ipg",          base + 0x70,    26);
+       hws[IMX6UL_CLK_LCDIF_APB]       = imx_clk_hw_gate2("lcdif_apb", "axi",          base + 0x70,    28);
+       hws[IMX6UL_CLK_PXP]             = imx_clk_hw_gate2("pxp",               "axi",          base + 0x70,    30);
 
        /* CCGR3 */
-       clks[IMX6UL_CLK_UART5_IPG]      = imx_clk_gate2("uart5_ipg",    "ipg",          base + 0x74,    2);
-       clks[IMX6UL_CLK_UART5_SERIAL]   = imx_clk_gate2("uart5_serial", "uart_podf",    base + 0x74,    2);
+       hws[IMX6UL_CLK_UART5_IPG]       = imx_clk_hw_gate2("uart5_ipg", "ipg",          base + 0x74,    2);
+       hws[IMX6UL_CLK_UART5_SERIAL]    = imx_clk_hw_gate2("uart5_serial",      "uart_podf",    base + 0x74,    2);
        if (clk_on_imx6ul()) {
-               clks[IMX6UL_CLK_ENET]           = imx_clk_gate2("enet",         "ipg",          base + 0x74,    4);
-               clks[IMX6UL_CLK_ENET_AHB]       = imx_clk_gate2("enet_ahb",     "ahb",          base + 0x74,    4);
+               hws[IMX6UL_CLK_ENET]            = imx_clk_hw_gate2("enet",              "ipg",          base + 0x74,    4);
+               hws[IMX6UL_CLK_ENET_AHB]        = imx_clk_hw_gate2("enet_ahb",  "ahb",          base + 0x74,    4);
        } else if (clk_on_imx6ull()) {
-               clks[IMX6ULL_CLK_EPDC_ACLK]     = imx_clk_gate2("epdc_aclk",    "axi",          base + 0x74,    4);
-               clks[IMX6ULL_CLK_EPDC_PIX]      = imx_clk_gate2("epdc_pix",     "epdc_podf",    base + 0x74,    4);
+               hws[IMX6ULL_CLK_EPDC_ACLK]      = imx_clk_hw_gate2("epdc_aclk", "axi",          base + 0x74,    4);
+               hws[IMX6ULL_CLK_EPDC_PIX]       = imx_clk_hw_gate2("epdc_pix",  "epdc_podf",    base + 0x74,    4);
        }
-       clks[IMX6UL_CLK_UART6_IPG]      = imx_clk_gate2("uart6_ipg",    "ipg",          base + 0x74,    6);
-       clks[IMX6UL_CLK_UART6_SERIAL]   = imx_clk_gate2("uart6_serial", "uart_podf",    base + 0x74,    6);
-       clks[IMX6UL_CLK_LCDIF_PIX]      = imx_clk_gate2("lcdif_pix",    "lcdif_podf",   base + 0x74,    10);
-       clks[IMX6UL_CLK_GPIO4]          = imx_clk_gate2("gpio4",        "ipg",          base + 0x74,    12);
-       clks[IMX6UL_CLK_QSPI]           = imx_clk_gate2("qspi1",        "qspi1_podf",   base + 0x74,    14);
-       clks[IMX6UL_CLK_WDOG1]          = imx_clk_gate2("wdog1",        "ipg",          base + 0x74,    16);
-       clks[IMX6UL_CLK_MMDC_P0_FAST]   = imx_clk_gate_flags("mmdc_p0_fast", "mmdc_podf", base + 0x74,  20, CLK_IS_CRITICAL);
-       clks[IMX6UL_CLK_MMDC_P0_IPG]    = imx_clk_gate2_flags("mmdc_p0_ipg",    "ipg",          base + 0x74,    24, CLK_IS_CRITICAL);
-       clks[IMX6UL_CLK_MMDC_P1_IPG]    = imx_clk_gate2("mmdc_p1_ipg",  "ipg",          base + 0x74,    26);
-       clks[IMX6UL_CLK_AXI]            = imx_clk_gate_flags("axi",     "axi_podf",     base + 0x74,    28, CLK_IS_CRITICAL);
+       hws[IMX6UL_CLK_UART6_IPG]       = imx_clk_hw_gate2("uart6_ipg", "ipg",          base + 0x74,    6);
+       hws[IMX6UL_CLK_UART6_SERIAL]    = imx_clk_hw_gate2("uart6_serial",      "uart_podf",    base + 0x74,    6);
+       hws[IMX6UL_CLK_LCDIF_PIX]       = imx_clk_hw_gate2("lcdif_pix", "lcdif_podf",   base + 0x74,    10);
+       hws[IMX6UL_CLK_GPIO4]           = imx_clk_hw_gate2("gpio4",     "ipg",          base + 0x74,    12);
+       hws[IMX6UL_CLK_QSPI]            = imx_clk_hw_gate2("qspi1",     "qspi1_podf",   base + 0x74,    14);
+       hws[IMX6UL_CLK_WDOG1]           = imx_clk_hw_gate2("wdog1",     "ipg",          base + 0x74,    16);
+       hws[IMX6UL_CLK_MMDC_P0_FAST]    = imx_clk_hw_gate_flags("mmdc_p0_fast", "mmdc_podf", base + 0x74,       20, CLK_IS_CRITICAL);
+       hws[IMX6UL_CLK_MMDC_P0_IPG]     = imx_clk_hw_gate2_flags("mmdc_p0_ipg", "ipg",          base + 0x74,    24, CLK_IS_CRITICAL);
+       hws[IMX6UL_CLK_MMDC_P1_IPG]     = imx_clk_hw_gate2_flags("mmdc_p1_ipg", "ipg",          base + 0x74,    26, CLK_IS_CRITICAL);
+       hws[IMX6UL_CLK_AXI]             = imx_clk_hw_gate_flags("axi",  "axi_podf",     base + 0x74,    28, CLK_IS_CRITICAL);
 
        /* CCGR4 */
-       clks[IMX6UL_CLK_PER_BCH]        = imx_clk_gate2("per_bch",      "bch_podf",     base + 0x78,    12);
-       clks[IMX6UL_CLK_PWM1]           = imx_clk_gate2("pwm1",         "perclk",       base + 0x78,    16);
-       clks[IMX6UL_CLK_PWM2]           = imx_clk_gate2("pwm2",         "perclk",       base + 0x78,    18);
-       clks[IMX6UL_CLK_PWM3]           = imx_clk_gate2("pwm3",         "perclk",       base + 0x78,    20);
-       clks[IMX6UL_CLK_PWM4]           = imx_clk_gate2("pwm4",         "perclk",       base + 0x78,    22);
-       clks[IMX6UL_CLK_GPMI_BCH_APB]   = imx_clk_gate2("gpmi_bch_apb", "bch_podf",     base + 0x78,    24);
-       clks[IMX6UL_CLK_GPMI_BCH]       = imx_clk_gate2("gpmi_bch",     "gpmi_podf",    base + 0x78,    26);
-       clks[IMX6UL_CLK_GPMI_IO]        = imx_clk_gate2("gpmi_io",      "enfc_podf",    base + 0x78,    28);
-       clks[IMX6UL_CLK_GPMI_APB]       = imx_clk_gate2("gpmi_apb",     "bch_podf",     base + 0x78,    30);
+       hws[IMX6UL_CLK_PER_BCH] = imx_clk_hw_gate2("per_bch",   "bch_podf",     base + 0x78,    12);
+       hws[IMX6UL_CLK_PWM1]            = imx_clk_hw_gate2("pwm1",              "perclk",       base + 0x78,    16);
+       hws[IMX6UL_CLK_PWM2]            = imx_clk_hw_gate2("pwm2",              "perclk",       base + 0x78,    18);
+       hws[IMX6UL_CLK_PWM3]            = imx_clk_hw_gate2("pwm3",              "perclk",       base + 0x78,    20);
+       hws[IMX6UL_CLK_PWM4]            = imx_clk_hw_gate2("pwm4",              "perclk",       base + 0x78,    22);
+       hws[IMX6UL_CLK_GPMI_BCH_APB]    = imx_clk_hw_gate2("gpmi_bch_apb",      "bch_podf",     base + 0x78,    24);
+       hws[IMX6UL_CLK_GPMI_BCH]        = imx_clk_hw_gate2("gpmi_bch",  "gpmi_podf",    base + 0x78,    26);
+       hws[IMX6UL_CLK_GPMI_IO] = imx_clk_hw_gate2("gpmi_io",   "enfc_podf",    base + 0x78,    28);
+       hws[IMX6UL_CLK_GPMI_APB]        = imx_clk_hw_gate2("gpmi_apb",  "bch_podf",     base + 0x78,    30);
 
        /* CCGR5 */
-       clks[IMX6UL_CLK_ROM]            = imx_clk_gate2_flags("rom",    "ahb",          base + 0x7c,    0,      CLK_IS_CRITICAL);
-       clks[IMX6UL_CLK_SDMA]           = imx_clk_gate2("sdma",         "ahb",          base + 0x7c,    6);
-       clks[IMX6UL_CLK_KPP]            = imx_clk_gate2("kpp",          "ipg",          base + 0x7c,    8);
-       clks[IMX6UL_CLK_WDOG2]          = imx_clk_gate2("wdog2",        "ipg",          base + 0x7c,    10);
-       clks[IMX6UL_CLK_SPBA]           = imx_clk_gate2("spba",         "ipg",          base + 0x7c,    12);
-       clks[IMX6UL_CLK_SPDIF]          = imx_clk_gate2_shared("spdif",         "spdif_podf",   base + 0x7c,    14, &share_count_audio);
-       clks[IMX6UL_CLK_SPDIF_GCLK]     = imx_clk_gate2_shared("spdif_gclk",    "ipg",          base + 0x7c,    14, &share_count_audio);
-       clks[IMX6UL_CLK_SAI3]           = imx_clk_gate2_shared("sai3",          "sai3_podf",    base + 0x7c,    22, &share_count_sai3);
-       clks[IMX6UL_CLK_SAI3_IPG]       = imx_clk_gate2_shared("sai3_ipg",      "ipg",          base + 0x7c,    22, &share_count_sai3);
-       clks[IMX6UL_CLK_UART1_IPG]      = imx_clk_gate2("uart1_ipg",    "ipg",          base + 0x7c,    24);
-       clks[IMX6UL_CLK_UART1_SERIAL]   = imx_clk_gate2("uart1_serial", "uart_podf",    base + 0x7c,    24);
-       clks[IMX6UL_CLK_UART7_IPG]      = imx_clk_gate2("uart7_ipg",    "ipg",          base + 0x7c,    26);
-       clks[IMX6UL_CLK_UART7_SERIAL]   = imx_clk_gate2("uart7_serial", "uart_podf",    base + 0x7c,    26);
-       clks[IMX6UL_CLK_SAI1]           = imx_clk_gate2_shared("sai1",          "sai1_podf",    base + 0x7c,    28, &share_count_sai1);
-       clks[IMX6UL_CLK_SAI1_IPG]       = imx_clk_gate2_shared("sai1_ipg",      "ipg",          base + 0x7c,    28, &share_count_sai1);
-       clks[IMX6UL_CLK_SAI2]           = imx_clk_gate2_shared("sai2",          "sai2_podf",    base + 0x7c,    30, &share_count_sai2);
-       clks[IMX6UL_CLK_SAI2_IPG]       = imx_clk_gate2_shared("sai2_ipg",      "ipg",          base + 0x7c,    30, &share_count_sai2);
+       hws[IMX6UL_CLK_ROM]             = imx_clk_hw_gate2_flags("rom", "ahb",          base + 0x7c,    0,      CLK_IS_CRITICAL);
+       hws[IMX6UL_CLK_SDMA]            = imx_clk_hw_gate2("sdma",              "ahb",          base + 0x7c,    6);
+       hws[IMX6UL_CLK_KPP]             = imx_clk_hw_gate2("kpp",               "ipg",          base + 0x7c,    8);
+       hws[IMX6UL_CLK_WDOG2]           = imx_clk_hw_gate2("wdog2",     "ipg",          base + 0x7c,    10);
+       hws[IMX6UL_CLK_SPBA]            = imx_clk_hw_gate2("spba",              "ipg",          base + 0x7c,    12);
+       hws[IMX6UL_CLK_SPDIF]           = imx_clk_hw_gate2_shared("spdif",              "spdif_podf",   base + 0x7c,    14, &share_count_audio);
+       hws[IMX6UL_CLK_SPDIF_GCLK]      = imx_clk_hw_gate2_shared("spdif_gclk", "ipg",          base + 0x7c,    14, &share_count_audio);
+       hws[IMX6UL_CLK_SAI3]            = imx_clk_hw_gate2_shared("sai3",               "sai3_podf",    base + 0x7c,    22, &share_count_sai3);
+       hws[IMX6UL_CLK_SAI3_IPG]        = imx_clk_hw_gate2_shared("sai3_ipg",   "ipg",          base + 0x7c,    22, &share_count_sai3);
+       hws[IMX6UL_CLK_UART1_IPG]       = imx_clk_hw_gate2("uart1_ipg", "ipg",          base + 0x7c,    24);
+       hws[IMX6UL_CLK_UART1_SERIAL]    = imx_clk_hw_gate2("uart1_serial",      "uart_podf",    base + 0x7c,    24);
+       hws[IMX6UL_CLK_UART7_IPG]       = imx_clk_hw_gate2("uart7_ipg", "ipg",          base + 0x7c,    26);
+       hws[IMX6UL_CLK_UART7_SERIAL]    = imx_clk_hw_gate2("uart7_serial",      "uart_podf",    base + 0x7c,    26);
+       hws[IMX6UL_CLK_SAI1]            = imx_clk_hw_gate2_shared("sai1",               "sai1_podf",    base + 0x7c,    28, &share_count_sai1);
+       hws[IMX6UL_CLK_SAI1_IPG]        = imx_clk_hw_gate2_shared("sai1_ipg",   "ipg",          base + 0x7c,    28, &share_count_sai1);
+       hws[IMX6UL_CLK_SAI2]            = imx_clk_hw_gate2_shared("sai2",               "sai2_podf",    base + 0x7c,    30, &share_count_sai2);
+       hws[IMX6UL_CLK_SAI2_IPG]        = imx_clk_hw_gate2_shared("sai2_ipg",   "ipg",          base + 0x7c,    30, &share_count_sai2);
 
        /* CCGR6 */
-       clks[IMX6UL_CLK_USBOH3]         = imx_clk_gate2("usboh3",       "ipg",           base + 0x80,   0);
-       clks[IMX6UL_CLK_USDHC1]         = imx_clk_gate2("usdhc1",       "usdhc1_podf",   base + 0x80,   2);
-       clks[IMX6UL_CLK_USDHC2]         = imx_clk_gate2("usdhc2",       "usdhc2_podf",   base + 0x80,   4);
+       hws[IMX6UL_CLK_USBOH3]          = imx_clk_hw_gate2("usboh3",    "ipg",           base + 0x80,   0);
+       hws[IMX6UL_CLK_USDHC1]          = imx_clk_hw_gate2("usdhc1",    "usdhc1_podf",   base + 0x80,   2);
+       hws[IMX6UL_CLK_USDHC2]          = imx_clk_hw_gate2("usdhc2",    "usdhc2_podf",   base + 0x80,   4);
        if (clk_on_imx6ul()) {
-               clks[IMX6UL_CLK_SIM1]           = imx_clk_gate2("sim1",         "sim_sel",       base + 0x80,   6);
-               clks[IMX6UL_CLK_SIM2]           = imx_clk_gate2("sim2",         "sim_sel",       base + 0x80,   8);
+               hws[IMX6UL_CLK_SIM1]            = imx_clk_hw_gate2("sim1",              "sim_sel",       base + 0x80,   6);
+               hws[IMX6UL_CLK_SIM2]            = imx_clk_hw_gate2("sim2",              "sim_sel",       base + 0x80,   8);
        }
-       clks[IMX6UL_CLK_EIM]            = imx_clk_gate2("eim",          "eim_slow_podf", base + 0x80,   10);
-       clks[IMX6UL_CLK_PWM8]           = imx_clk_gate2("pwm8",         "perclk",        base + 0x80,   16);
-       clks[IMX6UL_CLK_UART8_IPG]      = imx_clk_gate2("uart8_ipg",    "ipg",           base + 0x80,   14);
-       clks[IMX6UL_CLK_UART8_SERIAL]   = imx_clk_gate2("uart8_serial", "uart_podf",     base + 0x80,   14);
-       clks[IMX6UL_CLK_WDOG3]          = imx_clk_gate2("wdog3",        "ipg",           base + 0x80,   20);
-       clks[IMX6UL_CLK_I2C4]           = imx_clk_gate2("i2c4",         "perclk",        base + 0x80,   24);
-       clks[IMX6UL_CLK_PWM5]           = imx_clk_gate2("pwm5",         "perclk",        base + 0x80,   26);
-       clks[IMX6UL_CLK_PWM6]           = imx_clk_gate2("pwm6",         "perclk",        base + 0x80,   28);
-       clks[IMX6UL_CLK_PWM7]           = imx_clk_gate2("pwm7",         "perclk",        base + 0x80,   30);
+       hws[IMX6UL_CLK_EIM]             = imx_clk_hw_gate2("eim",               "eim_slow_podf", base + 0x80,   10);
+       hws[IMX6UL_CLK_PWM8]            = imx_clk_hw_gate2("pwm8",              "perclk",        base + 0x80,   16);
+       hws[IMX6UL_CLK_UART8_IPG]       = imx_clk_hw_gate2("uart8_ipg", "ipg",           base + 0x80,   14);
+       hws[IMX6UL_CLK_UART8_SERIAL]    = imx_clk_hw_gate2("uart8_serial", "uart_podf",  base + 0x80,   14);
+       hws[IMX6UL_CLK_WDOG3]           = imx_clk_hw_gate2("wdog3",     "ipg",           base + 0x80,   20);
+       hws[IMX6UL_CLK_I2C4]            = imx_clk_hw_gate2("i2c4",              "perclk",        base + 0x80,   24);
+       hws[IMX6UL_CLK_PWM5]            = imx_clk_hw_gate2("pwm5",              "perclk",        base + 0x80,   26);
+       hws[IMX6UL_CLK_PWM6]            = imx_clk_hw_gate2("pwm6",              "perclk",        base + 0x80,   28);
+       hws[IMX6UL_CLK_PWM7]            = imx_clk_hw_gate2("pwm7",              "perclk",        base + 0x80,   30);
 
        /* CCOSR */
-       clks[IMX6UL_CLK_CKO1]           = imx_clk_gate("cko1",          "cko1_podf",     base + 0x60,   7);
-       clks[IMX6UL_CLK_CKO2]           = imx_clk_gate("cko2",          "cko2_podf",     base + 0x60,   24);
+       hws[IMX6UL_CLK_CKO1]            = imx_clk_hw_gate("cko1",               "cko1_podf",     base + 0x60,   7);
+       hws[IMX6UL_CLK_CKO2]            = imx_clk_hw_gate("cko2",               "cko2_podf",     base + 0x60,   24);
 
        /* mask handshake of mmdc */
-       writel_relaxed(BM_CCM_CCDR_MMDC_CH0_MASK, base + CCDR);
+       imx_mmdc_mask_handshake(base, 0);
 
-       imx_check_clocks(clks, ARRAY_SIZE(clks));
+       imx_check_clk_hws(hws, IMX6UL_CLK_END);
 
-       clk_data.clks = clks;
-       clk_data.clk_num = ARRAY_SIZE(clks);
-       of_clk_add_provider(np, of_clk_src_onecell_get, &clk_data);
+       of_clk_add_hw_provider(np, of_clk_hw_onecell_get, clk_hw_data);
 
        /*
         * Lower the AHB clock rate before changing the parent clock source,
@@ -473,39 +477,39 @@ static void __init imx6ul_clocks_init(struct device_node *ccm_node)
         * AXI clock rate, so we need to lower AHB rate first to make sure at
         * any time, AHB rate is <= 133MHz.
         */
-       clk_set_rate(clks[IMX6UL_CLK_AHB], 99000000);
+       clk_set_rate(hws[IMX6UL_CLK_AHB]->clk, 99000000);
 
        /* Change periph_pre clock to pll2_bus to adjust AXI rate to 264MHz */
-       clk_set_parent(clks[IMX6UL_CLK_PERIPH_CLK2_SEL], clks[IMX6UL_CLK_OSC]);
-       clk_set_parent(clks[IMX6UL_CLK_PERIPH], clks[IMX6UL_CLK_PERIPH_CLK2]);
-       clk_set_parent(clks[IMX6UL_CLK_PERIPH_PRE], clks[IMX6UL_CLK_PLL2_BUS]);
-       clk_set_parent(clks[IMX6UL_CLK_PERIPH], clks[IMX6UL_CLK_PERIPH_PRE]);
+       clk_set_parent(hws[IMX6UL_CLK_PERIPH_CLK2_SEL]->clk, hws[IMX6UL_CLK_OSC]->clk);
+       clk_set_parent(hws[IMX6UL_CLK_PERIPH]->clk, hws[IMX6UL_CLK_PERIPH_CLK2]->clk);
+       clk_set_parent(hws[IMX6UL_CLK_PERIPH_PRE]->clk, hws[IMX6UL_CLK_PLL2_BUS]->clk);
+       clk_set_parent(hws[IMX6UL_CLK_PERIPH]->clk, hws[IMX6UL_CLK_PERIPH_PRE]->clk);
 
        /* Make sure AHB rate is 132MHz  */
-       clk_set_rate(clks[IMX6UL_CLK_AHB], 132000000);
+       clk_set_rate(hws[IMX6UL_CLK_AHB]->clk, 132000000);
 
        /* set perclk to from OSC */
-       clk_set_parent(clks[IMX6UL_CLK_PERCLK_SEL], clks[IMX6UL_CLK_OSC]);
+       clk_set_parent(hws[IMX6UL_CLK_PERCLK_SEL]->clk, hws[IMX6UL_CLK_OSC]->clk);
 
-       clk_set_rate(clks[IMX6UL_CLK_ENET_REF], 50000000);
-       clk_set_rate(clks[IMX6UL_CLK_ENET2_REF], 50000000);
-       clk_set_rate(clks[IMX6UL_CLK_CSI], 24000000);
+       clk_set_rate(hws[IMX6UL_CLK_ENET_REF]->clk, 50000000);
+       clk_set_rate(hws[IMX6UL_CLK_ENET2_REF]->clk, 50000000);
+       clk_set_rate(hws[IMX6UL_CLK_CSI]->clk, 24000000);
 
        if (clk_on_imx6ull())
-               clk_prepare_enable(clks[IMX6UL_CLK_AIPSTZ3]);
+               clk_prepare_enable(hws[IMX6UL_CLK_AIPSTZ3]->clk);
 
        if (IS_ENABLED(CONFIG_USB_MXS_PHY)) {
-               clk_prepare_enable(clks[IMX6UL_CLK_USBPHY1_GATE]);
-               clk_prepare_enable(clks[IMX6UL_CLK_USBPHY2_GATE]);
+               clk_prepare_enable(hws[IMX6UL_CLK_USBPHY1_GATE]->clk);
+               clk_prepare_enable(hws[IMX6UL_CLK_USBPHY2_GATE]->clk);
        }
 
-       clk_set_parent(clks[IMX6UL_CLK_CAN_SEL], clks[IMX6UL_CLK_PLL3_60M]);
+       clk_set_parent(hws[IMX6UL_CLK_CAN_SEL]->clk, hws[IMX6UL_CLK_PLL3_60M]->clk);
        if (clk_on_imx6ul())
-               clk_set_parent(clks[IMX6UL_CLK_SIM_PRE_SEL], clks[IMX6UL_CLK_PLL3_USB_OTG]);
+               clk_set_parent(hws[IMX6UL_CLK_SIM_PRE_SEL]->clk, hws[IMX6UL_CLK_PLL3_USB_OTG]->clk);
        else if (clk_on_imx6ull())
-               clk_set_parent(clks[IMX6ULL_CLK_EPDC_PRE_SEL], clks[IMX6UL_CLK_PLL3_PFD2]);
+               clk_set_parent(hws[IMX6ULL_CLK_EPDC_PRE_SEL]->clk, hws[IMX6UL_CLK_PLL3_PFD2]->clk);
 
-       clk_set_parent(clks[IMX6UL_CLK_ENFC_SEL], clks[IMX6UL_CLK_PLL2_PFD2]);
+       clk_set_parent(hws[IMX6UL_CLK_ENFC_SEL]->clk, hws[IMX6UL_CLK_PLL2_PFD2]->clk);
 }
 
 CLK_OF_DECLARE(imx6ul, "fsl,imx6ul-ccm", imx6ul_clocks_init);
index 8f3aa99..fbea774 100644 (file)
@@ -6,6 +6,7 @@
 #include <dt-bindings/clock/imx7d-clock.h>
 #include <linux/clk.h>
 #include <linux/clkdev.h>
+#include <linux/clk-provider.h>
 #include <linux/err.h>
 #include <linux/init.h>
 #include <linux/io.h>
@@ -39,7 +40,6 @@ static const struct clk_div_table post_div_table[] = {
        { }
 };
 
-static struct clk *clks[IMX7D_CLK_END];
 static const char *arm_a7_sel[] = { "osc", "pll_arm_main_clk",
        "pll_enet_500m_clk", "pll_dram_main_clk",
        "pll_sys_main_clk", "pll_sys_pfd0_392m_clk", "pll_audio_post_div",
@@ -373,517 +373,533 @@ static const char *pll_enet_bypass_sel[] = { "pll_enet_main", "pll_enet_main_src
 static const char *pll_audio_bypass_sel[] = { "pll_audio_main", "pll_audio_main_src", };
 static const char *pll_video_bypass_sel[] = { "pll_video_main", "pll_video_main_src", };
 
-static struct clk_onecell_data clk_data;
-
-static struct clk ** const uart_clks[] __initconst = {
-       &clks[IMX7D_UART1_ROOT_CLK],
-       &clks[IMX7D_UART2_ROOT_CLK],
-       &clks[IMX7D_UART3_ROOT_CLK],
-       &clks[IMX7D_UART4_ROOT_CLK],
-       &clks[IMX7D_UART5_ROOT_CLK],
-       &clks[IMX7D_UART6_ROOT_CLK],
-       &clks[IMX7D_UART7_ROOT_CLK],
-       NULL
+static struct clk_hw **hws;
+static struct clk_hw_onecell_data *clk_hw_data;
+
+static const int uart_clk_ids[] __initconst = {
+       IMX7D_UART1_ROOT_CLK,
+       IMX7D_UART2_ROOT_CLK,
+       IMX7D_UART3_ROOT_CLK,
+       IMX7D_UART4_ROOT_CLK,
+       IMX7D_UART5_ROOT_CLK,
+       IMX7D_UART6_ROOT_CLK,
+       IMX7D_UART7_ROOT_CLK,
 };
 
+static struct clk **uart_clks[ARRAY_SIZE(uart_clk_ids) + 1] __initdata;
+
 static void __init imx7d_clocks_init(struct device_node *ccm_node)
 {
        struct device_node *np;
        void __iomem *base;
+       int i;
+
+       clk_hw_data = kzalloc(struct_size(clk_hw_data, hws,
+                                         IMX7D_CLK_END), GFP_KERNEL);
+       if (WARN_ON(!clk_hw_data))
+               return;
+
+       clk_hw_data->num = IMX7D_CLK_END;
+       hws = clk_hw_data->hws;
 
-       clks[IMX7D_CLK_DUMMY] = imx_clk_fixed("dummy", 0);
-       clks[IMX7D_OSC_24M_CLK] = of_clk_get_by_name(ccm_node, "osc");
-       clks[IMX7D_CKIL] = of_clk_get_by_name(ccm_node, "ckil");
+       hws[IMX7D_CLK_DUMMY] = imx_clk_hw_fixed("dummy", 0);
+       hws[IMX7D_OSC_24M_CLK] = __clk_get_hw(of_clk_get_by_name(ccm_node, "osc"));
+       hws[IMX7D_CKIL] = __clk_get_hw(of_clk_get_by_name(ccm_node, "ckil"));
 
        np = of_find_compatible_node(NULL, NULL, "fsl,imx7d-anatop");
        base = of_iomap(np, 0);
        WARN_ON(!base);
        of_node_put(np);
 
-       clks[IMX7D_PLL_ARM_MAIN_SRC]  = imx_clk_mux("pll_arm_main_src", base + 0x60, 14, 2, pll_bypass_src_sel, ARRAY_SIZE(pll_bypass_src_sel));
-       clks[IMX7D_PLL_DRAM_MAIN_SRC] = imx_clk_mux("pll_dram_main_src", base + 0x70, 14, 2, pll_bypass_src_sel, ARRAY_SIZE(pll_bypass_src_sel));
-       clks[IMX7D_PLL_SYS_MAIN_SRC]  = imx_clk_mux("pll_sys_main_src", base + 0xb0, 14, 2, pll_bypass_src_sel, ARRAY_SIZE(pll_bypass_src_sel));
-       clks[IMX7D_PLL_ENET_MAIN_SRC] = imx_clk_mux("pll_enet_main_src", base + 0xe0, 14, 2, pll_bypass_src_sel, ARRAY_SIZE(pll_bypass_src_sel));
-       clks[IMX7D_PLL_AUDIO_MAIN_SRC] = imx_clk_mux("pll_audio_main_src", base + 0xf0, 14, 2, pll_bypass_src_sel, ARRAY_SIZE(pll_bypass_src_sel));
-       clks[IMX7D_PLL_VIDEO_MAIN_SRC] = imx_clk_mux("pll_video_main_src", base + 0x130, 14, 2, pll_bypass_src_sel, ARRAY_SIZE(pll_bypass_src_sel));
-
-       clks[IMX7D_PLL_ARM_MAIN]  = imx_clk_pllv3(IMX_PLLV3_SYS, "pll_arm_main", "osc", base + 0x60, 0x7f);
-       clks[IMX7D_PLL_DRAM_MAIN] = imx_clk_pllv3(IMX_PLLV3_DDR_IMX7, "pll_dram_main", "osc", base + 0x70, 0x7f);
-       clks[IMX7D_PLL_SYS_MAIN]  = imx_clk_pllv3(IMX_PLLV3_GENERIC, "pll_sys_main", "osc", base + 0xb0, 0x1);
-       clks[IMX7D_PLL_ENET_MAIN] = imx_clk_pllv3(IMX_PLLV3_ENET_IMX7, "pll_enet_main", "osc", base + 0xe0, 0x0);
-       clks[IMX7D_PLL_AUDIO_MAIN] = imx_clk_pllv3(IMX_PLLV3_AV_IMX7, "pll_audio_main", "osc", base + 0xf0, 0x7f);
-       clks[IMX7D_PLL_VIDEO_MAIN] = imx_clk_pllv3(IMX_PLLV3_AV_IMX7, "pll_video_main", "osc", base + 0x130, 0x7f);
-
-       clks[IMX7D_PLL_ARM_MAIN_BYPASS]  = imx_clk_mux_flags("pll_arm_main_bypass", base + 0x60, 16, 1, pll_arm_bypass_sel, ARRAY_SIZE(pll_arm_bypass_sel), CLK_SET_RATE_PARENT);
-       clks[IMX7D_PLL_DRAM_MAIN_BYPASS] = imx_clk_mux_flags("pll_dram_main_bypass", base + 0x70, 16, 1, pll_dram_bypass_sel, ARRAY_SIZE(pll_dram_bypass_sel), CLK_SET_RATE_PARENT);
-       clks[IMX7D_PLL_SYS_MAIN_BYPASS]  = imx_clk_mux_flags("pll_sys_main_bypass", base + 0xb0, 16, 1, pll_sys_bypass_sel, ARRAY_SIZE(pll_sys_bypass_sel), CLK_SET_RATE_PARENT);
-       clks[IMX7D_PLL_ENET_MAIN_BYPASS] = imx_clk_mux_flags("pll_enet_main_bypass", base + 0xe0, 16, 1, pll_enet_bypass_sel, ARRAY_SIZE(pll_enet_bypass_sel), CLK_SET_RATE_PARENT);
-       clks[IMX7D_PLL_AUDIO_MAIN_BYPASS] = imx_clk_mux_flags("pll_audio_main_bypass", base + 0xf0, 16, 1, pll_audio_bypass_sel, ARRAY_SIZE(pll_audio_bypass_sel), CLK_SET_RATE_PARENT);
-       clks[IMX7D_PLL_VIDEO_MAIN_BYPASS] = imx_clk_mux_flags("pll_video_main_bypass", base + 0x130, 16, 1, pll_video_bypass_sel, ARRAY_SIZE(pll_video_bypass_sel), CLK_SET_RATE_PARENT);
-
-       clks[IMX7D_PLL_ARM_MAIN_CLK] = imx_clk_gate("pll_arm_main_clk", "pll_arm_main_bypass", base + 0x60, 13);
-       clks[IMX7D_PLL_DRAM_MAIN_CLK] = imx_clk_gate("pll_dram_main_clk", "pll_dram_test_div", base + 0x70, 13);
-       clks[IMX7D_PLL_SYS_MAIN_CLK] = imx_clk_gate("pll_sys_main_clk", "pll_sys_main_bypass", base + 0xb0, 13);
-       clks[IMX7D_PLL_AUDIO_MAIN_CLK] = imx_clk_gate("pll_audio_main_clk", "pll_audio_main_bypass", base + 0xf0, 13);
-       clks[IMX7D_PLL_VIDEO_MAIN_CLK] = imx_clk_gate("pll_video_main_clk", "pll_video_main_bypass", base + 0x130, 13);
-
-       clks[IMX7D_PLL_DRAM_TEST_DIV]  = clk_register_divider_table(NULL, "pll_dram_test_div", "pll_dram_main_bypass",
+       hws[IMX7D_PLL_ARM_MAIN_SRC]  = imx_clk_hw_mux("pll_arm_main_src", base + 0x60, 14, 2, pll_bypass_src_sel, ARRAY_SIZE(pll_bypass_src_sel));
+       hws[IMX7D_PLL_DRAM_MAIN_SRC] = imx_clk_hw_mux("pll_dram_main_src", base + 0x70, 14, 2, pll_bypass_src_sel, ARRAY_SIZE(pll_bypass_src_sel));
+       hws[IMX7D_PLL_SYS_MAIN_SRC]  = imx_clk_hw_mux("pll_sys_main_src", base + 0xb0, 14, 2, pll_bypass_src_sel, ARRAY_SIZE(pll_bypass_src_sel));
+       hws[IMX7D_PLL_ENET_MAIN_SRC] = imx_clk_hw_mux("pll_enet_main_src", base + 0xe0, 14, 2, pll_bypass_src_sel, ARRAY_SIZE(pll_bypass_src_sel));
+       hws[IMX7D_PLL_AUDIO_MAIN_SRC] = imx_clk_hw_mux("pll_audio_main_src", base + 0xf0, 14, 2, pll_bypass_src_sel, ARRAY_SIZE(pll_bypass_src_sel));
+       hws[IMX7D_PLL_VIDEO_MAIN_SRC] = imx_clk_hw_mux("pll_video_main_src", base + 0x130, 14, 2, pll_bypass_src_sel, ARRAY_SIZE(pll_bypass_src_sel));
+
+       hws[IMX7D_PLL_ARM_MAIN]  = imx_clk_hw_pllv3(IMX_PLLV3_SYS, "pll_arm_main", "osc", base + 0x60, 0x7f);
+       hws[IMX7D_PLL_DRAM_MAIN] = imx_clk_hw_pllv3(IMX_PLLV3_DDR_IMX7, "pll_dram_main", "osc", base + 0x70, 0x7f);
+       hws[IMX7D_PLL_SYS_MAIN]  = imx_clk_hw_pllv3(IMX_PLLV3_GENERIC, "pll_sys_main", "osc", base + 0xb0, 0x1);
+       hws[IMX7D_PLL_ENET_MAIN] = imx_clk_hw_pllv3(IMX_PLLV3_ENET_IMX7, "pll_enet_main", "osc", base + 0xe0, 0x0);
+       hws[IMX7D_PLL_AUDIO_MAIN] = imx_clk_hw_pllv3(IMX_PLLV3_AV_IMX7, "pll_audio_main", "osc", base + 0xf0, 0x7f);
+       hws[IMX7D_PLL_VIDEO_MAIN] = imx_clk_hw_pllv3(IMX_PLLV3_AV_IMX7, "pll_video_main", "osc", base + 0x130, 0x7f);
+
+       hws[IMX7D_PLL_ARM_MAIN_BYPASS]  = imx_clk_hw_mux_flags("pll_arm_main_bypass", base + 0x60, 16, 1, pll_arm_bypass_sel, ARRAY_SIZE(pll_arm_bypass_sel), CLK_SET_RATE_PARENT);
+       hws[IMX7D_PLL_DRAM_MAIN_BYPASS] = imx_clk_hw_mux_flags("pll_dram_main_bypass", base + 0x70, 16, 1, pll_dram_bypass_sel, ARRAY_SIZE(pll_dram_bypass_sel), CLK_SET_RATE_PARENT);
+       hws[IMX7D_PLL_SYS_MAIN_BYPASS]  = imx_clk_hw_mux_flags("pll_sys_main_bypass", base + 0xb0, 16, 1, pll_sys_bypass_sel, ARRAY_SIZE(pll_sys_bypass_sel), CLK_SET_RATE_PARENT);
+       hws[IMX7D_PLL_ENET_MAIN_BYPASS] = imx_clk_hw_mux_flags("pll_enet_main_bypass", base + 0xe0, 16, 1, pll_enet_bypass_sel, ARRAY_SIZE(pll_enet_bypass_sel), CLK_SET_RATE_PARENT);
+       hws[IMX7D_PLL_AUDIO_MAIN_BYPASS] = imx_clk_hw_mux_flags("pll_audio_main_bypass", base + 0xf0, 16, 1, pll_audio_bypass_sel, ARRAY_SIZE(pll_audio_bypass_sel), CLK_SET_RATE_PARENT);
+       hws[IMX7D_PLL_VIDEO_MAIN_BYPASS] = imx_clk_hw_mux_flags("pll_video_main_bypass", base + 0x130, 16, 1, pll_video_bypass_sel, ARRAY_SIZE(pll_video_bypass_sel), CLK_SET_RATE_PARENT);
+
+       hws[IMX7D_PLL_ARM_MAIN_CLK] = imx_clk_hw_gate("pll_arm_main_clk", "pll_arm_main_bypass", base + 0x60, 13);
+       hws[IMX7D_PLL_DRAM_MAIN_CLK] = imx_clk_hw_gate("pll_dram_main_clk", "pll_dram_test_div", base + 0x70, 13);
+       hws[IMX7D_PLL_SYS_MAIN_CLK] = imx_clk_hw_gate("pll_sys_main_clk", "pll_sys_main_bypass", base + 0xb0, 13);
+       hws[IMX7D_PLL_AUDIO_MAIN_CLK] = imx_clk_hw_gate("pll_audio_main_clk", "pll_audio_main_bypass", base + 0xf0, 13);
+       hws[IMX7D_PLL_VIDEO_MAIN_CLK] = imx_clk_hw_gate("pll_video_main_clk", "pll_video_main_bypass", base + 0x130, 13);
+
+       hws[IMX7D_PLL_DRAM_TEST_DIV]  = clk_hw_register_divider_table(NULL, "pll_dram_test_div", "pll_dram_main_bypass",
                                CLK_SET_RATE_PARENT | CLK_SET_RATE_GATE, base + 0x70, 21, 2, 0, test_div_table, &imx_ccm_lock);
-       clks[IMX7D_PLL_AUDIO_TEST_DIV]  = clk_register_divider_table(NULL, "pll_audio_test_div", "pll_audio_main_clk",
+       hws[IMX7D_PLL_AUDIO_TEST_DIV]  = clk_hw_register_divider_table(NULL, "pll_audio_test_div", "pll_audio_main_clk",
                                CLK_SET_RATE_PARENT | CLK_SET_RATE_GATE, base + 0xf0, 19, 2, 0, test_div_table, &imx_ccm_lock);
-       clks[IMX7D_PLL_AUDIO_POST_DIV] = clk_register_divider_table(NULL, "pll_audio_post_div", "pll_audio_test_div",
+       hws[IMX7D_PLL_AUDIO_POST_DIV] = clk_hw_register_divider_table(NULL, "pll_audio_post_div", "pll_audio_test_div",
                                CLK_SET_RATE_PARENT | CLK_SET_RATE_GATE, base + 0xf0, 22, 2, 0, post_div_table, &imx_ccm_lock);
-       clks[IMX7D_PLL_VIDEO_TEST_DIV]  = clk_register_divider_table(NULL, "pll_video_test_div", "pll_video_main_clk",
+       hws[IMX7D_PLL_VIDEO_TEST_DIV]  = clk_hw_register_divider_table(NULL, "pll_video_test_div", "pll_video_main_clk",
                                CLK_SET_RATE_PARENT | CLK_SET_RATE_GATE, base + 0x130, 19, 2, 0, test_div_table, &imx_ccm_lock);
-       clks[IMX7D_PLL_VIDEO_POST_DIV] = clk_register_divider_table(NULL, "pll_video_post_div", "pll_video_test_div",
+       hws[IMX7D_PLL_VIDEO_POST_DIV] = clk_hw_register_divider_table(NULL, "pll_video_post_div", "pll_video_test_div",
                                CLK_SET_RATE_PARENT | CLK_SET_RATE_GATE, base + 0x130, 22, 2, 0, post_div_table, &imx_ccm_lock);
 
-       clks[IMX7D_PLL_SYS_PFD0_392M_CLK] = imx_clk_pfd("pll_sys_pfd0_392m_clk", "pll_sys_main_clk", base + 0xc0, 0);
-       clks[IMX7D_PLL_SYS_PFD1_332M_CLK] = imx_clk_pfd("pll_sys_pfd1_332m_clk", "pll_sys_main_clk", base + 0xc0, 1);
-       clks[IMX7D_PLL_SYS_PFD2_270M_CLK] = imx_clk_pfd("pll_sys_pfd2_270m_clk", "pll_sys_main_clk", base + 0xc0, 2);
-
-       clks[IMX7D_PLL_SYS_PFD3_CLK] = imx_clk_pfd("pll_sys_pfd3_clk", "pll_sys_main_clk", base + 0xc0, 3);
-       clks[IMX7D_PLL_SYS_PFD4_CLK] = imx_clk_pfd("pll_sys_pfd4_clk", "pll_sys_main_clk", base + 0xd0, 0);
-       clks[IMX7D_PLL_SYS_PFD5_CLK] = imx_clk_pfd("pll_sys_pfd5_clk", "pll_sys_main_clk", base + 0xd0, 1);
-       clks[IMX7D_PLL_SYS_PFD6_CLK] = imx_clk_pfd("pll_sys_pfd6_clk", "pll_sys_main_clk", base + 0xd0, 2);
-       clks[IMX7D_PLL_SYS_PFD7_CLK] = imx_clk_pfd("pll_sys_pfd7_clk", "pll_sys_main_clk", base + 0xd0, 3);
-
-       clks[IMX7D_PLL_SYS_MAIN_480M] = imx_clk_fixed_factor("pll_sys_main_480m", "pll_sys_main_clk", 1, 1);
-       clks[IMX7D_PLL_SYS_MAIN_240M] = imx_clk_fixed_factor("pll_sys_main_240m", "pll_sys_main_clk", 1, 2);
-       clks[IMX7D_PLL_SYS_MAIN_120M] = imx_clk_fixed_factor("pll_sys_main_120m", "pll_sys_main_clk", 1, 4);
-       clks[IMX7D_PLL_DRAM_MAIN_533M] = imx_clk_fixed_factor("pll_dram_533m", "pll_dram_main_clk", 1, 2);
-
-       clks[IMX7D_PLL_SYS_MAIN_480M_CLK] = imx_clk_gate_dis_flags("pll_sys_main_480m_clk", "pll_sys_main_480m", base + 0xb0, 4, CLK_IS_CRITICAL);
-       clks[IMX7D_PLL_SYS_MAIN_240M_CLK] = imx_clk_gate_dis("pll_sys_main_240m_clk", "pll_sys_main_240m", base + 0xb0, 5);
-       clks[IMX7D_PLL_SYS_MAIN_120M_CLK] = imx_clk_gate_dis("pll_sys_main_120m_clk", "pll_sys_main_120m", base + 0xb0, 6);
-       clks[IMX7D_PLL_DRAM_MAIN_533M_CLK] = imx_clk_gate("pll_dram_533m_clk", "pll_dram_533m", base + 0x70, 12);
-
-       clks[IMX7D_PLL_SYS_PFD0_196M] = imx_clk_fixed_factor("pll_sys_pfd0_196m", "pll_sys_pfd0_392m_clk", 1, 2);
-       clks[IMX7D_PLL_SYS_PFD1_166M] = imx_clk_fixed_factor("pll_sys_pfd1_166m", "pll_sys_pfd1_332m_clk", 1, 2);
-       clks[IMX7D_PLL_SYS_PFD2_135M] = imx_clk_fixed_factor("pll_sys_pfd2_135m", "pll_sys_pfd2_270m_clk", 1, 2);
-
-       clks[IMX7D_PLL_SYS_PFD0_196M_CLK] = imx_clk_gate_dis("pll_sys_pfd0_196m_clk", "pll_sys_pfd0_196m", base + 0xb0, 26);
-       clks[IMX7D_PLL_SYS_PFD1_166M_CLK] = imx_clk_gate_dis("pll_sys_pfd1_166m_clk", "pll_sys_pfd1_166m", base + 0xb0, 27);
-       clks[IMX7D_PLL_SYS_PFD2_135M_CLK] = imx_clk_gate_dis("pll_sys_pfd2_135m_clk", "pll_sys_pfd2_135m", base + 0xb0, 28);
-
-       clks[IMX7D_PLL_ENET_MAIN_CLK] = imx_clk_fixed_factor("pll_enet_main_clk", "pll_enet_main_bypass", 1, 1);
-       clks[IMX7D_PLL_ENET_MAIN_500M] = imx_clk_fixed_factor("pll_enet_500m", "pll_enet_main_clk", 1, 2);
-       clks[IMX7D_PLL_ENET_MAIN_250M] = imx_clk_fixed_factor("pll_enet_250m", "pll_enet_main_clk", 1, 4);
-       clks[IMX7D_PLL_ENET_MAIN_125M] = imx_clk_fixed_factor("pll_enet_125m", "pll_enet_main_clk", 1, 8);
-       clks[IMX7D_PLL_ENET_MAIN_100M] = imx_clk_fixed_factor("pll_enet_100m", "pll_enet_main_clk", 1, 10);
-       clks[IMX7D_PLL_ENET_MAIN_50M] = imx_clk_fixed_factor("pll_enet_50m", "pll_enet_main_clk", 1, 20);
-       clks[IMX7D_PLL_ENET_MAIN_40M] = imx_clk_fixed_factor("pll_enet_40m", "pll_enet_main_clk", 1, 25);
-       clks[IMX7D_PLL_ENET_MAIN_25M] = imx_clk_fixed_factor("pll_enet_25m", "pll_enet_main_clk", 1, 40);
-
-       clks[IMX7D_PLL_ENET_MAIN_500M_CLK] = imx_clk_gate("pll_enet_500m_clk", "pll_enet_500m", base + 0xe0, 12);
-       clks[IMX7D_PLL_ENET_MAIN_250M_CLK] = imx_clk_gate("pll_enet_250m_clk", "pll_enet_250m", base + 0xe0, 11);
-       clks[IMX7D_PLL_ENET_MAIN_125M_CLK] = imx_clk_gate("pll_enet_125m_clk", "pll_enet_125m", base + 0xe0, 10);
-       clks[IMX7D_PLL_ENET_MAIN_100M_CLK] = imx_clk_gate("pll_enet_100m_clk", "pll_enet_100m", base + 0xe0, 9);
-       clks[IMX7D_PLL_ENET_MAIN_50M_CLK]  = imx_clk_gate("pll_enet_50m_clk", "pll_enet_50m", base + 0xe0, 8);
-       clks[IMX7D_PLL_ENET_MAIN_40M_CLK]  = imx_clk_gate("pll_enet_40m_clk", "pll_enet_40m", base + 0xe0, 7);
-       clks[IMX7D_PLL_ENET_MAIN_25M_CLK]  = imx_clk_gate("pll_enet_25m_clk", "pll_enet_25m", base + 0xe0, 6);
-
-       clks[IMX7D_LVDS1_OUT_SEL] = imx_clk_mux("lvds1_sel", base + 0x170, 0, 5, lvds1_sel, ARRAY_SIZE(lvds1_sel));
-       clks[IMX7D_LVDS1_OUT_CLK] = imx_clk_gate_exclusive("lvds1_out", "lvds1_sel", base + 0x170, 5, BIT(6));
+       hws[IMX7D_PLL_SYS_PFD0_392M_CLK] = imx_clk_hw_pfd("pll_sys_pfd0_392m_clk", "pll_sys_main_clk", base + 0xc0, 0);
+       hws[IMX7D_PLL_SYS_PFD1_332M_CLK] = imx_clk_hw_pfd("pll_sys_pfd1_332m_clk", "pll_sys_main_clk", base + 0xc0, 1);
+       hws[IMX7D_PLL_SYS_PFD2_270M_CLK] = imx_clk_hw_pfd("pll_sys_pfd2_270m_clk", "pll_sys_main_clk", base + 0xc0, 2);
+
+       hws[IMX7D_PLL_SYS_PFD3_CLK] = imx_clk_hw_pfd("pll_sys_pfd3_clk", "pll_sys_main_clk", base + 0xc0, 3);
+       hws[IMX7D_PLL_SYS_PFD4_CLK] = imx_clk_hw_pfd("pll_sys_pfd4_clk", "pll_sys_main_clk", base + 0xd0, 0);
+       hws[IMX7D_PLL_SYS_PFD5_CLK] = imx_clk_hw_pfd("pll_sys_pfd5_clk", "pll_sys_main_clk", base + 0xd0, 1);
+       hws[IMX7D_PLL_SYS_PFD6_CLK] = imx_clk_hw_pfd("pll_sys_pfd6_clk", "pll_sys_main_clk", base + 0xd0, 2);
+       hws[IMX7D_PLL_SYS_PFD7_CLK] = imx_clk_hw_pfd("pll_sys_pfd7_clk", "pll_sys_main_clk", base + 0xd0, 3);
+
+       hws[IMX7D_PLL_SYS_MAIN_480M] = imx_clk_hw_fixed_factor("pll_sys_main_480m", "pll_sys_main_clk", 1, 1);
+       hws[IMX7D_PLL_SYS_MAIN_240M] = imx_clk_hw_fixed_factor("pll_sys_main_240m", "pll_sys_main_clk", 1, 2);
+       hws[IMX7D_PLL_SYS_MAIN_120M] = imx_clk_hw_fixed_factor("pll_sys_main_120m", "pll_sys_main_clk", 1, 4);
+       hws[IMX7D_PLL_DRAM_MAIN_533M] = imx_clk_hw_fixed_factor("pll_dram_533m", "pll_dram_main_clk", 1, 2);
+
+       hws[IMX7D_PLL_SYS_MAIN_480M_CLK] = imx_clk_hw_gate_dis_flags("pll_sys_main_480m_clk", "pll_sys_main_480m", base + 0xb0, 4, CLK_IS_CRITICAL);
+       hws[IMX7D_PLL_SYS_MAIN_240M_CLK] = imx_clk_hw_gate_dis("pll_sys_main_240m_clk", "pll_sys_main_240m", base + 0xb0, 5);
+       hws[IMX7D_PLL_SYS_MAIN_120M_CLK] = imx_clk_hw_gate_dis("pll_sys_main_120m_clk", "pll_sys_main_120m", base + 0xb0, 6);
+       hws[IMX7D_PLL_DRAM_MAIN_533M_CLK] = imx_clk_hw_gate("pll_dram_533m_clk", "pll_dram_533m", base + 0x70, 12);
+
+       hws[IMX7D_PLL_SYS_PFD0_196M] = imx_clk_hw_fixed_factor("pll_sys_pfd0_196m", "pll_sys_pfd0_392m_clk", 1, 2);
+       hws[IMX7D_PLL_SYS_PFD1_166M] = imx_clk_hw_fixed_factor("pll_sys_pfd1_166m", "pll_sys_pfd1_332m_clk", 1, 2);
+       hws[IMX7D_PLL_SYS_PFD2_135M] = imx_clk_hw_fixed_factor("pll_sys_pfd2_135m", "pll_sys_pfd2_270m_clk", 1, 2);
+
+       hws[IMX7D_PLL_SYS_PFD0_196M_CLK] = imx_clk_hw_gate_dis("pll_sys_pfd0_196m_clk", "pll_sys_pfd0_196m", base + 0xb0, 26);
+       hws[IMX7D_PLL_SYS_PFD1_166M_CLK] = imx_clk_hw_gate_dis("pll_sys_pfd1_166m_clk", "pll_sys_pfd1_166m", base + 0xb0, 27);
+       hws[IMX7D_PLL_SYS_PFD2_135M_CLK] = imx_clk_hw_gate_dis("pll_sys_pfd2_135m_clk", "pll_sys_pfd2_135m", base + 0xb0, 28);
+
+       hws[IMX7D_PLL_ENET_MAIN_CLK] = imx_clk_hw_fixed_factor("pll_enet_main_clk", "pll_enet_main_bypass", 1, 1);
+       hws[IMX7D_PLL_ENET_MAIN_500M] = imx_clk_hw_fixed_factor("pll_enet_500m", "pll_enet_main_clk", 1, 2);
+       hws[IMX7D_PLL_ENET_MAIN_250M] = imx_clk_hw_fixed_factor("pll_enet_250m", "pll_enet_main_clk", 1, 4);
+       hws[IMX7D_PLL_ENET_MAIN_125M] = imx_clk_hw_fixed_factor("pll_enet_125m", "pll_enet_main_clk", 1, 8);
+       hws[IMX7D_PLL_ENET_MAIN_100M] = imx_clk_hw_fixed_factor("pll_enet_100m", "pll_enet_main_clk", 1, 10);
+       hws[IMX7D_PLL_ENET_MAIN_50M] = imx_clk_hw_fixed_factor("pll_enet_50m", "pll_enet_main_clk", 1, 20);
+       hws[IMX7D_PLL_ENET_MAIN_40M] = imx_clk_hw_fixed_factor("pll_enet_40m", "pll_enet_main_clk", 1, 25);
+       hws[IMX7D_PLL_ENET_MAIN_25M] = imx_clk_hw_fixed_factor("pll_enet_25m", "pll_enet_main_clk", 1, 40);
+
+       hws[IMX7D_PLL_ENET_MAIN_500M_CLK] = imx_clk_hw_gate("pll_enet_500m_clk", "pll_enet_500m", base + 0xe0, 12);
+       hws[IMX7D_PLL_ENET_MAIN_250M_CLK] = imx_clk_hw_gate("pll_enet_250m_clk", "pll_enet_250m", base + 0xe0, 11);
+       hws[IMX7D_PLL_ENET_MAIN_125M_CLK] = imx_clk_hw_gate("pll_enet_125m_clk", "pll_enet_125m", base + 0xe0, 10);
+       hws[IMX7D_PLL_ENET_MAIN_100M_CLK] = imx_clk_hw_gate("pll_enet_100m_clk", "pll_enet_100m", base + 0xe0, 9);
+       hws[IMX7D_PLL_ENET_MAIN_50M_CLK]  = imx_clk_hw_gate("pll_enet_50m_clk", "pll_enet_50m", base + 0xe0, 8);
+       hws[IMX7D_PLL_ENET_MAIN_40M_CLK]  = imx_clk_hw_gate("pll_enet_40m_clk", "pll_enet_40m", base + 0xe0, 7);
+       hws[IMX7D_PLL_ENET_MAIN_25M_CLK]  = imx_clk_hw_gate("pll_enet_25m_clk", "pll_enet_25m", base + 0xe0, 6);
+
+       hws[IMX7D_LVDS1_OUT_SEL] = imx_clk_hw_mux("lvds1_sel", base + 0x170, 0, 5, lvds1_sel, ARRAY_SIZE(lvds1_sel));
+       hws[IMX7D_LVDS1_OUT_CLK] = imx_clk_hw_gate_exclusive("lvds1_out", "lvds1_sel", base + 0x170, 5, BIT(6));
 
        np = ccm_node;
        base = of_iomap(np, 0);
        WARN_ON(!base);
 
-       clks[IMX7D_ARM_A7_ROOT_SRC] = imx_clk_mux2("arm_a7_src", base + 0x8000, 24, 3, arm_a7_sel, ARRAY_SIZE(arm_a7_sel));
-       clks[IMX7D_ARM_M4_ROOT_SRC] = imx_clk_mux2("arm_m4_src", base + 0x8080, 24, 3, arm_m4_sel, ARRAY_SIZE(arm_m4_sel));
-       clks[IMX7D_MAIN_AXI_ROOT_SRC] = imx_clk_mux2("axi_src", base + 0x8800, 24, 3, axi_sel, ARRAY_SIZE(axi_sel));
-       clks[IMX7D_DISP_AXI_ROOT_SRC] = imx_clk_mux2("disp_axi_src", base + 0x8880, 24, 3, disp_axi_sel, ARRAY_SIZE(disp_axi_sel));
-       clks[IMX7D_ENET_AXI_ROOT_SRC] = imx_clk_mux2("enet_axi_src", base + 0x8900, 24, 3, enet_axi_sel, ARRAY_SIZE(enet_axi_sel));
-       clks[IMX7D_NAND_USDHC_BUS_ROOT_SRC] = imx_clk_mux2("nand_usdhc_src", base + 0x8980, 24, 3, nand_usdhc_bus_sel, ARRAY_SIZE(nand_usdhc_bus_sel));
-       clks[IMX7D_AHB_CHANNEL_ROOT_SRC] = imx_clk_mux2("ahb_src", base + 0x9000, 24, 3, ahb_channel_sel, ARRAY_SIZE(ahb_channel_sel));
-       clks[IMX7D_DRAM_PHYM_ROOT_SRC] = imx_clk_mux2("dram_phym_src", base + 0x9800, 24, 1, dram_phym_sel, ARRAY_SIZE(dram_phym_sel));
-       clks[IMX7D_DRAM_ROOT_SRC] = imx_clk_mux2("dram_src", base + 0x9880, 24, 1, dram_sel, ARRAY_SIZE(dram_sel));
-       clks[IMX7D_DRAM_PHYM_ALT_ROOT_SRC] = imx_clk_mux2("dram_phym_alt_src", base + 0xa000, 24, 3, dram_phym_alt_sel, ARRAY_SIZE(dram_phym_alt_sel));
-       clks[IMX7D_DRAM_ALT_ROOT_SRC]  = imx_clk_mux2("dram_alt_src", base + 0xa080, 24, 3, dram_alt_sel, ARRAY_SIZE(dram_alt_sel));
-       clks[IMX7D_USB_HSIC_ROOT_SRC] = imx_clk_mux2("usb_hsic_src", base + 0xa100, 24, 3, usb_hsic_sel, ARRAY_SIZE(usb_hsic_sel));
-       clks[IMX7D_PCIE_CTRL_ROOT_SRC] = imx_clk_mux2("pcie_ctrl_src", base + 0xa180, 24, 3, pcie_ctrl_sel, ARRAY_SIZE(pcie_ctrl_sel));
-       clks[IMX7D_PCIE_PHY_ROOT_SRC] = imx_clk_mux2("pcie_phy_src", base + 0xa200, 24, 3, pcie_phy_sel, ARRAY_SIZE(pcie_phy_sel));
-       clks[IMX7D_EPDC_PIXEL_ROOT_SRC] = imx_clk_mux2("epdc_pixel_src", base + 0xa280, 24, 3, epdc_pixel_sel, ARRAY_SIZE(epdc_pixel_sel));
-       clks[IMX7D_LCDIF_PIXEL_ROOT_SRC] = imx_clk_mux2("lcdif_pixel_src", base + 0xa300, 24, 3, lcdif_pixel_sel, ARRAY_SIZE(lcdif_pixel_sel));
-       clks[IMX7D_MIPI_DSI_ROOT_SRC] = imx_clk_mux2("mipi_dsi_src", base + 0xa380, 24, 3,  mipi_dsi_sel, ARRAY_SIZE(mipi_dsi_sel));
-       clks[IMX7D_MIPI_CSI_ROOT_SRC] = imx_clk_mux2("mipi_csi_src", base + 0xa400, 24, 3, mipi_csi_sel, ARRAY_SIZE(mipi_csi_sel));
-       clks[IMX7D_MIPI_DPHY_ROOT_SRC] = imx_clk_mux2("mipi_dphy_src", base + 0xa480, 24, 3, mipi_dphy_sel, ARRAY_SIZE(mipi_dphy_sel));
-       clks[IMX7D_SAI1_ROOT_SRC] = imx_clk_mux2("sai1_src", base + 0xa500, 24, 3, sai1_sel, ARRAY_SIZE(sai1_sel));
-       clks[IMX7D_SAI2_ROOT_SRC] = imx_clk_mux2("sai2_src", base + 0xa580, 24, 3, sai2_sel, ARRAY_SIZE(sai2_sel));
-       clks[IMX7D_SAI3_ROOT_SRC] = imx_clk_mux2("sai3_src", base + 0xa600, 24, 3, sai3_sel, ARRAY_SIZE(sai3_sel));
-       clks[IMX7D_SPDIF_ROOT_SRC] = imx_clk_mux2("spdif_src", base + 0xa680, 24, 3, spdif_sel, ARRAY_SIZE(spdif_sel));
-       clks[IMX7D_ENET1_REF_ROOT_SRC] = imx_clk_mux2("enet1_ref_src", base + 0xa700, 24, 3, enet1_ref_sel, ARRAY_SIZE(enet1_ref_sel));
-       clks[IMX7D_ENET1_TIME_ROOT_SRC] = imx_clk_mux2("enet1_time_src", base + 0xa780, 24, 3, enet1_time_sel, ARRAY_SIZE(enet1_time_sel));
-       clks[IMX7D_ENET2_REF_ROOT_SRC] = imx_clk_mux2("enet2_ref_src", base + 0xa800, 24, 3, enet2_ref_sel, ARRAY_SIZE(enet2_ref_sel));
-       clks[IMX7D_ENET2_TIME_ROOT_SRC] = imx_clk_mux2("enet2_time_src", base + 0xa880, 24, 3, enet2_time_sel, ARRAY_SIZE(enet2_time_sel));
-       clks[IMX7D_ENET_PHY_REF_ROOT_SRC] = imx_clk_mux2("enet_phy_ref_src", base + 0xa900, 24, 3, enet_phy_ref_sel, ARRAY_SIZE(enet_phy_ref_sel));
-       clks[IMX7D_EIM_ROOT_SRC] = imx_clk_mux2("eim_src", base + 0xa980, 24, 3, eim_sel, ARRAY_SIZE(eim_sel));
-       clks[IMX7D_NAND_ROOT_SRC] = imx_clk_mux2("nand_src", base + 0xaa00, 24, 3, nand_sel, ARRAY_SIZE(nand_sel));
-       clks[IMX7D_QSPI_ROOT_SRC] = imx_clk_mux2("qspi_src", base + 0xaa80, 24, 3, qspi_sel, ARRAY_SIZE(qspi_sel));
-       clks[IMX7D_USDHC1_ROOT_SRC] = imx_clk_mux2("usdhc1_src", base + 0xab00, 24, 3, usdhc1_sel, ARRAY_SIZE(usdhc1_sel));
-       clks[IMX7D_USDHC2_ROOT_SRC] = imx_clk_mux2("usdhc2_src", base + 0xab80, 24, 3, usdhc2_sel, ARRAY_SIZE(usdhc2_sel));
-       clks[IMX7D_USDHC3_ROOT_SRC] = imx_clk_mux2("usdhc3_src", base + 0xac00, 24, 3, usdhc3_sel, ARRAY_SIZE(usdhc3_sel));
-       clks[IMX7D_CAN1_ROOT_SRC] = imx_clk_mux2("can1_src", base + 0xac80, 24, 3, can1_sel, ARRAY_SIZE(can1_sel));
-       clks[IMX7D_CAN2_ROOT_SRC] = imx_clk_mux2("can2_src", base + 0xad00, 24, 3, can2_sel, ARRAY_SIZE(can2_sel));
-       clks[IMX7D_I2C1_ROOT_SRC] = imx_clk_mux2("i2c1_src", base + 0xad80, 24, 3, i2c1_sel, ARRAY_SIZE(i2c1_sel));
-       clks[IMX7D_I2C2_ROOT_SRC] = imx_clk_mux2("i2c2_src", base + 0xae00, 24, 3, i2c2_sel, ARRAY_SIZE(i2c2_sel));
-       clks[IMX7D_I2C3_ROOT_SRC] = imx_clk_mux2("i2c3_src", base + 0xae80, 24, 3, i2c3_sel, ARRAY_SIZE(i2c3_sel));
-       clks[IMX7D_I2C4_ROOT_SRC] = imx_clk_mux2("i2c4_src", base + 0xaf00, 24, 3, i2c4_sel, ARRAY_SIZE(i2c4_sel));
-       clks[IMX7D_UART1_ROOT_SRC] = imx_clk_mux2("uart1_src", base + 0xaf80, 24, 3, uart1_sel, ARRAY_SIZE(uart1_sel));
-       clks[IMX7D_UART2_ROOT_SRC] = imx_clk_mux2("uart2_src", base + 0xb000, 24, 3, uart2_sel, ARRAY_SIZE(uart2_sel));
-       clks[IMX7D_UART3_ROOT_SRC] = imx_clk_mux2("uart3_src", base + 0xb080, 24, 3, uart3_sel, ARRAY_SIZE(uart3_sel));
-       clks[IMX7D_UART4_ROOT_SRC] = imx_clk_mux2("uart4_src", base + 0xb100, 24, 3, uart4_sel, ARRAY_SIZE(uart4_sel));
-       clks[IMX7D_UART5_ROOT_SRC] = imx_clk_mux2("uart5_src", base + 0xb180, 24, 3, uart5_sel, ARRAY_SIZE(uart5_sel));
-       clks[IMX7D_UART6_ROOT_SRC] = imx_clk_mux2("uart6_src", base + 0xb200, 24, 3, uart6_sel, ARRAY_SIZE(uart6_sel));
-       clks[IMX7D_UART7_ROOT_SRC] = imx_clk_mux2("uart7_src", base + 0xb280, 24, 3, uart7_sel, ARRAY_SIZE(uart7_sel));
-       clks[IMX7D_ECSPI1_ROOT_SRC] = imx_clk_mux2("ecspi1_src", base + 0xb300, 24, 3, ecspi1_sel, ARRAY_SIZE(ecspi1_sel));
-       clks[IMX7D_ECSPI2_ROOT_SRC] = imx_clk_mux2("ecspi2_src", base + 0xb380, 24, 3, ecspi2_sel, ARRAY_SIZE(ecspi2_sel));
-       clks[IMX7D_ECSPI3_ROOT_SRC] = imx_clk_mux2("ecspi3_src", base + 0xb400, 24, 3, ecspi3_sel, ARRAY_SIZE(ecspi3_sel));
-       clks[IMX7D_ECSPI4_ROOT_SRC] = imx_clk_mux2("ecspi4_src", base + 0xb480, 24, 3, ecspi4_sel, ARRAY_SIZE(ecspi4_sel));
-       clks[IMX7D_PWM1_ROOT_SRC] = imx_clk_mux2("pwm1_src", base + 0xb500, 24, 3, pwm1_sel, ARRAY_SIZE(pwm1_sel));
-       clks[IMX7D_PWM2_ROOT_SRC] = imx_clk_mux2("pwm2_src", base + 0xb580, 24, 3, pwm2_sel, ARRAY_SIZE(pwm2_sel));
-       clks[IMX7D_PWM3_ROOT_SRC] = imx_clk_mux2("pwm3_src", base + 0xb600, 24, 3, pwm3_sel, ARRAY_SIZE(pwm3_sel));
-       clks[IMX7D_PWM4_ROOT_SRC] = imx_clk_mux2("pwm4_src", base + 0xb680, 24, 3, pwm4_sel, ARRAY_SIZE(pwm4_sel));
-       clks[IMX7D_FLEXTIMER1_ROOT_SRC] = imx_clk_mux2("flextimer1_src", base + 0xb700, 24, 3, flextimer1_sel, ARRAY_SIZE(flextimer1_sel));
-       clks[IMX7D_FLEXTIMER2_ROOT_SRC] = imx_clk_mux2("flextimer2_src", base + 0xb780, 24, 3, flextimer2_sel, ARRAY_SIZE(flextimer2_sel));
-       clks[IMX7D_SIM1_ROOT_SRC] = imx_clk_mux2("sim1_src", base + 0xb800, 24, 3, sim1_sel, ARRAY_SIZE(sim1_sel));
-       clks[IMX7D_SIM2_ROOT_SRC] = imx_clk_mux2("sim2_src", base + 0xb880, 24, 3, sim2_sel, ARRAY_SIZE(sim2_sel));
-       clks[IMX7D_GPT1_ROOT_SRC] = imx_clk_mux2("gpt1_src", base + 0xb900, 24, 3, gpt1_sel, ARRAY_SIZE(gpt1_sel));
-       clks[IMX7D_GPT2_ROOT_SRC] = imx_clk_mux2("gpt2_src", base + 0xb980, 24, 3, gpt2_sel, ARRAY_SIZE(gpt2_sel));
-       clks[IMX7D_GPT3_ROOT_SRC] = imx_clk_mux2("gpt3_src", base + 0xba00, 24, 3, gpt3_sel, ARRAY_SIZE(gpt3_sel));
-       clks[IMX7D_GPT4_ROOT_SRC] = imx_clk_mux2("gpt4_src", base + 0xba80, 24, 3, gpt4_sel, ARRAY_SIZE(gpt4_sel));
-       clks[IMX7D_TRACE_ROOT_SRC] = imx_clk_mux2("trace_src", base + 0xbb00, 24, 3, trace_sel, ARRAY_SIZE(trace_sel));
-       clks[IMX7D_WDOG_ROOT_SRC] = imx_clk_mux2("wdog_src", base + 0xbb80, 24, 3, wdog_sel, ARRAY_SIZE(wdog_sel));
-       clks[IMX7D_CSI_MCLK_ROOT_SRC] = imx_clk_mux2("csi_mclk_src", base + 0xbc00, 24, 3, csi_mclk_sel, ARRAY_SIZE(csi_mclk_sel));
-       clks[IMX7D_AUDIO_MCLK_ROOT_SRC] = imx_clk_mux2("audio_mclk_src", base + 0xbc80, 24, 3, audio_mclk_sel, ARRAY_SIZE(audio_mclk_sel));
-       clks[IMX7D_WRCLK_ROOT_SRC] = imx_clk_mux2("wrclk_src", base + 0xbd00, 24, 3, wrclk_sel, ARRAY_SIZE(wrclk_sel));
-       clks[IMX7D_CLKO1_ROOT_SRC] = imx_clk_mux2("clko1_src", base + 0xbd80, 24, 3, clko1_sel, ARRAY_SIZE(clko1_sel));
-       clks[IMX7D_CLKO2_ROOT_SRC] = imx_clk_mux2("clko2_src", base + 0xbe00, 24, 3, clko2_sel, ARRAY_SIZE(clko2_sel));
-
-       clks[IMX7D_ARM_A7_ROOT_CG] = imx_clk_gate3("arm_a7_cg", "arm_a7_src", base + 0x8000, 28);
-       clks[IMX7D_ARM_M4_ROOT_CG] = imx_clk_gate3("arm_m4_cg", "arm_m4_src", base + 0x8080, 28);
-       clks[IMX7D_MAIN_AXI_ROOT_CG] = imx_clk_gate3("axi_cg", "axi_src", base + 0x8800, 28);
-       clks[IMX7D_DISP_AXI_ROOT_CG] = imx_clk_gate3("disp_axi_cg", "disp_axi_src", base + 0x8880, 28);
-       clks[IMX7D_ENET_AXI_ROOT_CG] = imx_clk_gate3("enet_axi_cg", "enet_axi_src", base + 0x8900, 28);
-       clks[IMX7D_NAND_USDHC_BUS_ROOT_CG] = imx_clk_gate3("nand_usdhc_cg", "nand_usdhc_src", base + 0x8980, 28);
-       clks[IMX7D_AHB_CHANNEL_ROOT_CG] = imx_clk_gate3("ahb_cg", "ahb_src", base + 0x9000, 28);
-       clks[IMX7D_DRAM_PHYM_ROOT_CG] = imx_clk_gate3("dram_phym_cg", "dram_phym_src", base + 0x9800, 28);
-       clks[IMX7D_DRAM_ROOT_CG] = imx_clk_gate3("dram_cg", "dram_src", base + 0x9880, 28);
-       clks[IMX7D_DRAM_PHYM_ALT_ROOT_CG] = imx_clk_gate3("dram_phym_alt_cg", "dram_phym_alt_src", base + 0xa000, 28);
-       clks[IMX7D_DRAM_ALT_ROOT_CG] = imx_clk_gate3("dram_alt_cg", "dram_alt_src", base + 0xa080, 28);
-       clks[IMX7D_USB_HSIC_ROOT_CG] = imx_clk_gate3("usb_hsic_cg", "usb_hsic_src", base + 0xa100, 28);
-       clks[IMX7D_PCIE_CTRL_ROOT_CG] = imx_clk_gate3("pcie_ctrl_cg", "pcie_ctrl_src", base + 0xa180, 28);
-       clks[IMX7D_PCIE_PHY_ROOT_CG] = imx_clk_gate3("pcie_phy_cg", "pcie_phy_src", base + 0xa200, 28);
-       clks[IMX7D_EPDC_PIXEL_ROOT_CG] = imx_clk_gate3("epdc_pixel_cg", "epdc_pixel_src", base + 0xa280, 28);
-       clks[IMX7D_LCDIF_PIXEL_ROOT_CG] = imx_clk_gate3("lcdif_pixel_cg", "lcdif_pixel_src", base + 0xa300, 28);
-       clks[IMX7D_MIPI_DSI_ROOT_CG] = imx_clk_gate3("mipi_dsi_cg", "mipi_dsi_src", base + 0xa380, 28);
-       clks[IMX7D_MIPI_CSI_ROOT_CG] = imx_clk_gate3("mipi_csi_cg", "mipi_csi_src", base + 0xa400, 28);
-       clks[IMX7D_MIPI_DPHY_ROOT_CG] = imx_clk_gate3("mipi_dphy_cg", "mipi_dphy_src", base + 0xa480, 28);
-       clks[IMX7D_SAI1_ROOT_CG] = imx_clk_gate3("sai1_cg", "sai1_src", base + 0xa500, 28);
-       clks[IMX7D_SAI2_ROOT_CG] = imx_clk_gate3("sai2_cg", "sai2_src", base + 0xa580, 28);
-       clks[IMX7D_SAI3_ROOT_CG] = imx_clk_gate3("sai3_cg", "sai3_src", base + 0xa600, 28);
-       clks[IMX7D_SPDIF_ROOT_CG] = imx_clk_gate3("spdif_cg", "spdif_src", base + 0xa680, 28);
-       clks[IMX7D_ENET1_REF_ROOT_CG] = imx_clk_gate3("enet1_ref_cg", "enet1_ref_src", base + 0xa700, 28);
-       clks[IMX7D_ENET1_TIME_ROOT_CG] = imx_clk_gate3("enet1_time_cg", "enet1_time_src", base + 0xa780, 28);
-       clks[IMX7D_ENET2_REF_ROOT_CG] = imx_clk_gate3("enet2_ref_cg", "enet2_ref_src", base + 0xa800, 28);
-       clks[IMX7D_ENET2_TIME_ROOT_CG] = imx_clk_gate3("enet2_time_cg", "enet2_time_src", base + 0xa880, 28);
-       clks[IMX7D_ENET_PHY_REF_ROOT_CG] = imx_clk_gate3("enet_phy_ref_cg", "enet_phy_ref_src", base + 0xa900, 28);
-       clks[IMX7D_EIM_ROOT_CG] = imx_clk_gate3("eim_cg", "eim_src", base + 0xa980, 28);
-       clks[IMX7D_NAND_ROOT_CG] = imx_clk_gate3("nand_cg", "nand_src", base + 0xaa00, 28);
-       clks[IMX7D_QSPI_ROOT_CG] = imx_clk_gate3("qspi_cg", "qspi_src", base + 0xaa80, 28);
-       clks[IMX7D_USDHC1_ROOT_CG] = imx_clk_gate3("usdhc1_cg", "usdhc1_src", base + 0xab00, 28);
-       clks[IMX7D_USDHC2_ROOT_CG] = imx_clk_gate3("usdhc2_cg", "usdhc2_src", base + 0xab80, 28);
-       clks[IMX7D_USDHC3_ROOT_CG] = imx_clk_gate3("usdhc3_cg", "usdhc3_src", base + 0xac00, 28);
-       clks[IMX7D_CAN1_ROOT_CG] = imx_clk_gate3("can1_cg", "can1_src", base + 0xac80, 28);
-       clks[IMX7D_CAN2_ROOT_CG] = imx_clk_gate3("can2_cg", "can2_src", base + 0xad00, 28);
-       clks[IMX7D_I2C1_ROOT_CG] = imx_clk_gate3("i2c1_cg", "i2c1_src", base + 0xad80, 28);
-       clks[IMX7D_I2C2_ROOT_CG] = imx_clk_gate3("i2c2_cg", "i2c2_src", base + 0xae00, 28);
-       clks[IMX7D_I2C3_ROOT_CG] = imx_clk_gate3("i2c3_cg", "i2c3_src", base + 0xae80, 28);
-       clks[IMX7D_I2C4_ROOT_CG] = imx_clk_gate3("i2c4_cg", "i2c4_src", base + 0xaf00, 28);
-       clks[IMX7D_UART1_ROOT_CG] = imx_clk_gate3("uart1_cg", "uart1_src", base + 0xaf80, 28);
-       clks[IMX7D_UART2_ROOT_CG] = imx_clk_gate3("uart2_cg", "uart2_src", base + 0xb000, 28);
-       clks[IMX7D_UART3_ROOT_CG] = imx_clk_gate3("uart3_cg", "uart3_src", base + 0xb080, 28);
-       clks[IMX7D_UART4_ROOT_CG] = imx_clk_gate3("uart4_cg", "uart4_src", base + 0xb100, 28);
-       clks[IMX7D_UART5_ROOT_CG] = imx_clk_gate3("uart5_cg", "uart5_src", base + 0xb180, 28);
-       clks[IMX7D_UART6_ROOT_CG] = imx_clk_gate3("uart6_cg", "uart6_src", base + 0xb200, 28);
-       clks[IMX7D_UART7_ROOT_CG] = imx_clk_gate3("uart7_cg", "uart7_src", base + 0xb280, 28);
-       clks[IMX7D_ECSPI1_ROOT_CG] = imx_clk_gate3("ecspi1_cg", "ecspi1_src", base + 0xb300, 28);
-       clks[IMX7D_ECSPI2_ROOT_CG] = imx_clk_gate3("ecspi2_cg", "ecspi2_src", base + 0xb380, 28);
-       clks[IMX7D_ECSPI3_ROOT_CG] = imx_clk_gate3("ecspi3_cg", "ecspi3_src", base + 0xb400, 28);
-       clks[IMX7D_ECSPI4_ROOT_CG] = imx_clk_gate3("ecspi4_cg", "ecspi4_src", base + 0xb480, 28);
-       clks[IMX7D_PWM1_ROOT_CG] = imx_clk_gate3("pwm1_cg", "pwm1_src", base + 0xb500, 28);
-       clks[IMX7D_PWM2_ROOT_CG] = imx_clk_gate3("pwm2_cg", "pwm2_src", base + 0xb580, 28);
-       clks[IMX7D_PWM3_ROOT_CG] = imx_clk_gate3("pwm3_cg", "pwm3_src", base + 0xb600, 28);
-       clks[IMX7D_PWM4_ROOT_CG] = imx_clk_gate3("pwm4_cg", "pwm4_src", base + 0xb680, 28);
-       clks[IMX7D_FLEXTIMER1_ROOT_CG] = imx_clk_gate3("flextimer1_cg", "flextimer1_src", base + 0xb700, 28);
-       clks[IMX7D_FLEXTIMER2_ROOT_CG] = imx_clk_gate3("flextimer2_cg", "flextimer2_src", base + 0xb780, 28);
-       clks[IMX7D_SIM1_ROOT_CG] = imx_clk_gate3("sim1_cg", "sim1_src", base + 0xb800, 28);
-       clks[IMX7D_SIM2_ROOT_CG] = imx_clk_gate3("sim2_cg", "sim2_src", base + 0xb880, 28);
-       clks[IMX7D_GPT1_ROOT_CG] = imx_clk_gate3("gpt1_cg", "gpt1_src", base + 0xb900, 28);
-       clks[IMX7D_GPT2_ROOT_CG] = imx_clk_gate3("gpt2_cg", "gpt2_src", base + 0xb980, 28);
-       clks[IMX7D_GPT3_ROOT_CG] = imx_clk_gate3("gpt3_cg", "gpt3_src", base + 0xbA00, 28);
-       clks[IMX7D_GPT4_ROOT_CG] = imx_clk_gate3("gpt4_cg", "gpt4_src", base + 0xbA80, 28);
-       clks[IMX7D_TRACE_ROOT_CG] = imx_clk_gate3("trace_cg", "trace_src", base + 0xbb00, 28);
-       clks[IMX7D_WDOG_ROOT_CG] = imx_clk_gate3("wdog_cg", "wdog_src", base + 0xbb80, 28);
-       clks[IMX7D_CSI_MCLK_ROOT_CG] = imx_clk_gate3("csi_mclk_cg", "csi_mclk_src", base + 0xbc00, 28);
-       clks[IMX7D_AUDIO_MCLK_ROOT_CG] = imx_clk_gate3("audio_mclk_cg", "audio_mclk_src", base + 0xbc80, 28);
-       clks[IMX7D_WRCLK_ROOT_CG] = imx_clk_gate3("wrclk_cg", "wrclk_src", base + 0xbd00, 28);
-       clks[IMX7D_CLKO1_ROOT_CG] = imx_clk_gate3("clko1_cg", "clko1_src", base + 0xbd80, 28);
-       clks[IMX7D_CLKO2_ROOT_CG] = imx_clk_gate3("clko2_cg", "clko2_src", base + 0xbe00, 28);
-
-       clks[IMX7D_MAIN_AXI_ROOT_PRE_DIV] = imx_clk_divider2("axi_pre_div", "axi_cg", base + 0x8800, 16, 3);
-       clks[IMX7D_DISP_AXI_ROOT_PRE_DIV] = imx_clk_divider2("disp_axi_pre_div", "disp_axi_cg", base + 0x8880, 16, 3);
-       clks[IMX7D_ENET_AXI_ROOT_PRE_DIV] = imx_clk_divider2("enet_axi_pre_div", "enet_axi_cg", base + 0x8900, 16, 3);
-       clks[IMX7D_NAND_USDHC_BUS_ROOT_PRE_DIV] = imx_clk_divider2("nand_usdhc_pre_div", "nand_usdhc_cg", base + 0x8980, 16, 3);
-       clks[IMX7D_AHB_CHANNEL_ROOT_PRE_DIV] = imx_clk_divider2("ahb_pre_div", "ahb_cg", base + 0x9000, 16, 3);
-       clks[IMX7D_DRAM_PHYM_ALT_ROOT_PRE_DIV] = imx_clk_divider2("dram_phym_alt_pre_div", "dram_phym_alt_cg", base + 0xa000, 16, 3);
-       clks[IMX7D_DRAM_ALT_ROOT_PRE_DIV] = imx_clk_divider2("dram_alt_pre_div", "dram_alt_cg", base + 0xa080, 16, 3);
-       clks[IMX7D_USB_HSIC_ROOT_PRE_DIV] = imx_clk_divider2("usb_hsic_pre_div", "usb_hsic_cg", base + 0xa100, 16, 3);
-       clks[IMX7D_PCIE_CTRL_ROOT_PRE_DIV] = imx_clk_divider2("pcie_ctrl_pre_div", "pcie_ctrl_cg", base + 0xa180, 16, 3);
-       clks[IMX7D_PCIE_PHY_ROOT_PRE_DIV] = imx_clk_divider2("pcie_phy_pre_div", "pcie_phy_cg", base + 0xa200, 16, 3);
-       clks[IMX7D_EPDC_PIXEL_ROOT_PRE_DIV] = imx_clk_divider2("epdc_pixel_pre_div", "epdc_pixel_cg", base + 0xa280, 16, 3);
-       clks[IMX7D_LCDIF_PIXEL_ROOT_PRE_DIV] = imx_clk_divider2("lcdif_pixel_pre_div", "lcdif_pixel_cg", base + 0xa300, 16, 3);
-       clks[IMX7D_MIPI_DSI_ROOT_PRE_DIV] = imx_clk_divider2("mipi_dsi_pre_div", "mipi_dsi_cg", base + 0xa380, 16, 3);
-       clks[IMX7D_MIPI_CSI_ROOT_PRE_DIV] = imx_clk_divider2("mipi_csi_pre_div", "mipi_csi_cg", base + 0xa400, 16, 3);
-       clks[IMX7D_MIPI_DPHY_ROOT_PRE_DIV] = imx_clk_divider2("mipi_dphy_pre_div", "mipi_dphy_cg", base + 0xa480, 16, 3);
-       clks[IMX7D_SAI1_ROOT_PRE_DIV] = imx_clk_divider2("sai1_pre_div", "sai1_cg", base + 0xa500, 16, 3);
-       clks[IMX7D_SAI2_ROOT_PRE_DIV] = imx_clk_divider2("sai2_pre_div", "sai2_cg", base + 0xa580, 16, 3);
-       clks[IMX7D_SAI3_ROOT_PRE_DIV] = imx_clk_divider2("sai3_pre_div", "sai3_cg", base + 0xa600, 16, 3);
-       clks[IMX7D_SPDIF_ROOT_PRE_DIV] = imx_clk_divider2("spdif_pre_div", "spdif_cg", base + 0xa680, 16, 3);
-       clks[IMX7D_ENET1_REF_ROOT_PRE_DIV] = imx_clk_divider2("enet1_ref_pre_div", "enet1_ref_cg", base + 0xa700, 16, 3);
-       clks[IMX7D_ENET1_TIME_ROOT_PRE_DIV] = imx_clk_divider2("enet1_time_pre_div", "enet1_time_cg", base + 0xa780, 16, 3);
-       clks[IMX7D_ENET2_REF_ROOT_PRE_DIV] = imx_clk_divider2("enet2_ref_pre_div", "enet2_ref_cg", base + 0xa800, 16, 3);
-       clks[IMX7D_ENET2_TIME_ROOT_PRE_DIV] = imx_clk_divider2("enet2_time_pre_div", "enet2_time_cg", base + 0xa880, 16, 3);
-       clks[IMX7D_ENET_PHY_REF_ROOT_PRE_DIV] = imx_clk_divider2("enet_phy_ref_pre_div", "enet_phy_ref_cg", base + 0xa900, 16, 3);
-       clks[IMX7D_EIM_ROOT_PRE_DIV] = imx_clk_divider2("eim_pre_div", "eim_cg", base + 0xa980, 16, 3);
-       clks[IMX7D_NAND_ROOT_PRE_DIV] = imx_clk_divider2("nand_pre_div", "nand_cg", base + 0xaa00, 16, 3);
-       clks[IMX7D_QSPI_ROOT_PRE_DIV] = imx_clk_divider2("qspi_pre_div", "qspi_cg", base + 0xaa80, 16, 3);
-       clks[IMX7D_USDHC1_ROOT_PRE_DIV] = imx_clk_divider2("usdhc1_pre_div", "usdhc1_cg", base + 0xab00, 16, 3);
-       clks[IMX7D_USDHC2_ROOT_PRE_DIV] = imx_clk_divider2("usdhc2_pre_div", "usdhc2_cg", base + 0xab80, 16, 3);
-       clks[IMX7D_USDHC3_ROOT_PRE_DIV] = imx_clk_divider2("usdhc3_pre_div", "usdhc3_cg", base + 0xac00, 16, 3);
-       clks[IMX7D_CAN1_ROOT_PRE_DIV] = imx_clk_divider2("can1_pre_div", "can1_cg", base + 0xac80, 16, 3);
-       clks[IMX7D_CAN2_ROOT_PRE_DIV] = imx_clk_divider2("can2_pre_div", "can2_cg", base + 0xad00, 16, 3);
-       clks[IMX7D_I2C1_ROOT_PRE_DIV] = imx_clk_divider2("i2c1_pre_div", "i2c1_cg", base + 0xad80, 16, 3);
-       clks[IMX7D_I2C2_ROOT_PRE_DIV] = imx_clk_divider2("i2c2_pre_div", "i2c2_cg", base + 0xae00, 16, 3);
-       clks[IMX7D_I2C3_ROOT_PRE_DIV] = imx_clk_divider2("i2c3_pre_div", "i2c3_cg", base + 0xae80, 16, 3);
-       clks[IMX7D_I2C4_ROOT_PRE_DIV] = imx_clk_divider2("i2c4_pre_div", "i2c4_cg", base + 0xaf00, 16, 3);
-       clks[IMX7D_UART1_ROOT_PRE_DIV] = imx_clk_divider2("uart1_pre_div", "uart1_cg", base + 0xaf80, 16, 3);
-       clks[IMX7D_UART2_ROOT_PRE_DIV] = imx_clk_divider2("uart2_pre_div", "uart2_cg", base + 0xb000, 16, 3);
-       clks[IMX7D_UART3_ROOT_PRE_DIV] = imx_clk_divider2("uart3_pre_div", "uart3_cg", base + 0xb080, 16, 3);
-       clks[IMX7D_UART4_ROOT_PRE_DIV] = imx_clk_divider2("uart4_pre_div", "uart4_cg", base + 0xb100, 16, 3);
-       clks[IMX7D_UART5_ROOT_PRE_DIV] = imx_clk_divider2("uart5_pre_div", "uart5_cg", base + 0xb180, 16, 3);
-       clks[IMX7D_UART6_ROOT_PRE_DIV] = imx_clk_divider2("uart6_pre_div", "uart6_cg", base + 0xb200, 16, 3);
-       clks[IMX7D_UART7_ROOT_PRE_DIV] = imx_clk_divider2("uart7_pre_div", "uart7_cg", base + 0xb280, 16, 3);
-       clks[IMX7D_ECSPI1_ROOT_PRE_DIV] = imx_clk_divider2("ecspi1_pre_div", "ecspi1_cg", base + 0xb300, 16, 3);
-       clks[IMX7D_ECSPI2_ROOT_PRE_DIV] = imx_clk_divider2("ecspi2_pre_div", "ecspi2_cg", base + 0xb380, 16, 3);
-       clks[IMX7D_ECSPI3_ROOT_PRE_DIV] = imx_clk_divider2("ecspi3_pre_div", "ecspi3_cg", base + 0xb400, 16, 3);
-       clks[IMX7D_ECSPI4_ROOT_PRE_DIV] = imx_clk_divider2("ecspi4_pre_div", "ecspi4_cg", base + 0xb480, 16, 3);
-       clks[IMX7D_PWM1_ROOT_PRE_DIV] = imx_clk_divider2("pwm1_pre_div", "pwm1_cg", base + 0xb500, 16, 3);
-       clks[IMX7D_PWM2_ROOT_PRE_DIV] = imx_clk_divider2("pwm2_pre_div", "pwm2_cg", base + 0xb580, 16, 3);
-       clks[IMX7D_PWM3_ROOT_PRE_DIV] = imx_clk_divider2("pwm3_pre_div", "pwm3_cg", base + 0xb600, 16, 3);
-       clks[IMX7D_PWM4_ROOT_PRE_DIV] = imx_clk_divider2("pwm4_pre_div", "pwm4_cg", base + 0xb680, 16, 3);
-       clks[IMX7D_FLEXTIMER1_ROOT_PRE_DIV] = imx_clk_divider2("flextimer1_pre_div", "flextimer1_cg", base + 0xb700, 16, 3);
-       clks[IMX7D_FLEXTIMER2_ROOT_PRE_DIV] = imx_clk_divider2("flextimer2_pre_div", "flextimer2_cg", base + 0xb780, 16, 3);
-       clks[IMX7D_SIM1_ROOT_PRE_DIV] = imx_clk_divider2("sim1_pre_div", "sim1_cg", base + 0xb800, 16, 3);
-       clks[IMX7D_SIM2_ROOT_PRE_DIV] = imx_clk_divider2("sim2_pre_div", "sim2_cg", base + 0xb880, 16, 3);
-       clks[IMX7D_GPT1_ROOT_PRE_DIV] = imx_clk_divider2("gpt1_pre_div", "gpt1_cg", base + 0xb900, 16, 3);
-       clks[IMX7D_GPT2_ROOT_PRE_DIV] = imx_clk_divider2("gpt2_pre_div", "gpt2_cg", base + 0xb980, 16, 3);
-       clks[IMX7D_GPT3_ROOT_PRE_DIV] = imx_clk_divider2("gpt3_pre_div", "gpt3_cg", base + 0xba00, 16, 3);
-       clks[IMX7D_GPT4_ROOT_PRE_DIV] = imx_clk_divider2("gpt4_pre_div", "gpt4_cg", base + 0xba80, 16, 3);
-       clks[IMX7D_TRACE_ROOT_PRE_DIV] = imx_clk_divider2("trace_pre_div", "trace_cg", base + 0xbb00, 16, 3);
-       clks[IMX7D_WDOG_ROOT_PRE_DIV] = imx_clk_divider2("wdog_pre_div", "wdog_cg", base + 0xbb80, 16, 3);
-       clks[IMX7D_CSI_MCLK_ROOT_PRE_DIV] = imx_clk_divider2("csi_mclk_pre_div", "csi_mclk_cg", base + 0xbc00, 16, 3);
-       clks[IMX7D_AUDIO_MCLK_ROOT_PRE_DIV] = imx_clk_divider2("audio_mclk_pre_div", "audio_mclk_cg", base + 0xbc80, 16, 3);
-       clks[IMX7D_WRCLK_ROOT_PRE_DIV] = imx_clk_divider2("wrclk_pre_div", "wrclk_cg", base + 0xbd00, 16, 3);
-       clks[IMX7D_CLKO1_ROOT_PRE_DIV] = imx_clk_divider2("clko1_pre_div", "clko1_cg", base + 0xbd80, 16, 3);
-       clks[IMX7D_CLKO2_ROOT_PRE_DIV] = imx_clk_divider2("clko2_pre_div", "clko2_cg", base + 0xbe00, 16, 3);
-
-       clks[IMX7D_ARM_A7_ROOT_DIV] = imx_clk_divider2("arm_a7_div", "arm_a7_cg", base + 0x8000, 0, 3);
-       clks[IMX7D_ARM_M4_ROOT_DIV] = imx_clk_divider2("arm_m4_div", "arm_m4_cg", base + 0x8080, 0, 3);
-       clks[IMX7D_MAIN_AXI_ROOT_DIV] = imx_clk_divider2("axi_post_div", "axi_pre_div", base + 0x8800, 0, 6);
-       clks[IMX7D_DISP_AXI_ROOT_DIV] = imx_clk_divider2("disp_axi_post_div", "disp_axi_pre_div", base + 0x8880, 0, 6);
-       clks[IMX7D_ENET_AXI_ROOT_DIV] = imx_clk_divider2("enet_axi_post_div", "enet_axi_pre_div", base + 0x8900, 0, 6);
-       clks[IMX7D_NAND_USDHC_BUS_ROOT_CLK] = imx_clk_divider2("nand_usdhc_root_clk", "nand_usdhc_pre_div", base + 0x8980, 0, 6);
-       clks[IMX7D_AHB_CHANNEL_ROOT_DIV] = imx_clk_divider2("ahb_root_clk", "ahb_pre_div", base + 0x9000, 0, 6);
-       clks[IMX7D_IPG_ROOT_CLK] = imx_clk_divider_flags("ipg_root_clk", "ahb_root_clk", base + 0x9080, 0, 2, CLK_IS_CRITICAL | CLK_OPS_PARENT_ENABLE | CLK_SET_RATE_PARENT);
-       clks[IMX7D_DRAM_ROOT_DIV] = imx_clk_divider2("dram_post_div", "dram_cg", base + 0x9880, 0, 3);
-       clks[IMX7D_DRAM_PHYM_ALT_ROOT_DIV] = imx_clk_divider2("dram_phym_alt_post_div", "dram_phym_alt_pre_div", base + 0xa000, 0, 3);
-       clks[IMX7D_DRAM_ALT_ROOT_DIV] = imx_clk_divider2("dram_alt_post_div", "dram_alt_pre_div", base + 0xa080, 0, 3);
-       clks[IMX7D_USB_HSIC_ROOT_DIV] = imx_clk_divider2("usb_hsic_post_div", "usb_hsic_pre_div", base + 0xa100, 0, 6);
-       clks[IMX7D_PCIE_CTRL_ROOT_DIV] = imx_clk_divider2("pcie_ctrl_post_div", "pcie_ctrl_pre_div", base + 0xa180, 0, 6);
-       clks[IMX7D_PCIE_PHY_ROOT_DIV] = imx_clk_divider2("pcie_phy_post_div", "pcie_phy_pre_div", base + 0xa200, 0, 6);
-       clks[IMX7D_EPDC_PIXEL_ROOT_DIV] = imx_clk_divider2("epdc_pixel_post_div", "epdc_pixel_pre_div", base + 0xa280, 0, 6);
-       clks[IMX7D_LCDIF_PIXEL_ROOT_DIV] = imx_clk_divider2("lcdif_pixel_post_div", "lcdif_pixel_pre_div", base + 0xa300, 0, 6);
-       clks[IMX7D_MIPI_DSI_ROOT_DIV] = imx_clk_divider2("mipi_dsi_post_div", "mipi_dsi_pre_div", base + 0xa380, 0, 6);
-       clks[IMX7D_MIPI_CSI_ROOT_DIV] = imx_clk_divider2("mipi_csi_post_div", "mipi_csi_pre_div", base + 0xa400, 0, 6);
-       clks[IMX7D_MIPI_DPHY_ROOT_DIV] = imx_clk_divider2("mipi_dphy_post_div", "mipi_dphy_pre_div", base + 0xa480, 0, 6);
-       clks[IMX7D_SAI1_ROOT_DIV] = imx_clk_divider2("sai1_post_div", "sai1_pre_div", base + 0xa500, 0, 6);
-       clks[IMX7D_SAI2_ROOT_DIV] = imx_clk_divider2("sai2_post_div", "sai2_pre_div", base + 0xa580, 0, 6);
-       clks[IMX7D_SAI3_ROOT_DIV] = imx_clk_divider2("sai3_post_div", "sai3_pre_div", base + 0xa600, 0, 6);
-       clks[IMX7D_SPDIF_ROOT_DIV] = imx_clk_divider2("spdif_post_div", "spdif_pre_div", base + 0xa680, 0, 6);
-       clks[IMX7D_ENET1_REF_ROOT_DIV] = imx_clk_divider2("enet1_ref_post_div", "enet1_ref_pre_div", base + 0xa700, 0, 6);
-       clks[IMX7D_ENET1_TIME_ROOT_DIV] = imx_clk_divider2("enet1_time_post_div", "enet1_time_pre_div", base + 0xa780, 0, 6);
-       clks[IMX7D_ENET2_REF_ROOT_DIV] = imx_clk_divider2("enet2_ref_post_div", "enet2_ref_pre_div", base + 0xa800, 0, 6);
-       clks[IMX7D_ENET2_TIME_ROOT_DIV] = imx_clk_divider2("enet2_time_post_div", "enet2_time_pre_div", base + 0xa880, 0, 6);
-       clks[IMX7D_ENET_PHY_REF_ROOT_CLK] = imx_clk_divider2("enet_phy_ref_root_clk", "enet_phy_ref_pre_div", base + 0xa900, 0, 6);
-       clks[IMX7D_EIM_ROOT_DIV] = imx_clk_divider2("eim_post_div", "eim_pre_div", base + 0xa980, 0, 6);
-       clks[IMX7D_NAND_ROOT_CLK] = imx_clk_divider2("nand_root_clk", "nand_pre_div", base + 0xaa00, 0, 6);
-       clks[IMX7D_QSPI_ROOT_DIV] = imx_clk_divider2("qspi_post_div", "qspi_pre_div", base + 0xaa80, 0, 6);
-       clks[IMX7D_USDHC1_ROOT_DIV] = imx_clk_divider2("usdhc1_post_div", "usdhc1_pre_div", base + 0xab00, 0, 6);
-       clks[IMX7D_USDHC2_ROOT_DIV] = imx_clk_divider2("usdhc2_post_div", "usdhc2_pre_div", base + 0xab80, 0, 6);
-       clks[IMX7D_USDHC3_ROOT_DIV] = imx_clk_divider2("usdhc3_post_div", "usdhc3_pre_div", base + 0xac00, 0, 6);
-       clks[IMX7D_CAN1_ROOT_DIV] = imx_clk_divider2("can1_post_div", "can1_pre_div", base + 0xac80, 0, 6);
-       clks[IMX7D_CAN2_ROOT_DIV] = imx_clk_divider2("can2_post_div", "can2_pre_div", base + 0xad00, 0, 6);
-       clks[IMX7D_I2C1_ROOT_DIV] = imx_clk_divider2("i2c1_post_div", "i2c1_pre_div", base + 0xad80, 0, 6);
-       clks[IMX7D_I2C2_ROOT_DIV] = imx_clk_divider2("i2c2_post_div", "i2c2_pre_div", base + 0xae00, 0, 6);
-       clks[IMX7D_I2C3_ROOT_DIV] = imx_clk_divider2("i2c3_post_div", "i2c3_pre_div", base + 0xae80, 0, 6);
-       clks[IMX7D_I2C4_ROOT_DIV] = imx_clk_divider2("i2c4_post_div", "i2c4_pre_div", base + 0xaf00, 0, 6);
-       clks[IMX7D_UART1_ROOT_DIV] = imx_clk_divider2("uart1_post_div", "uart1_pre_div", base + 0xaf80, 0, 6);
-       clks[IMX7D_UART2_ROOT_DIV] = imx_clk_divider2("uart2_post_div", "uart2_pre_div", base + 0xb000, 0, 6);
-       clks[IMX7D_UART3_ROOT_DIV] = imx_clk_divider2("uart3_post_div", "uart3_pre_div", base + 0xb080, 0, 6);
-       clks[IMX7D_UART4_ROOT_DIV] = imx_clk_divider2("uart4_post_div", "uart4_pre_div", base + 0xb100, 0, 6);
-       clks[IMX7D_UART5_ROOT_DIV] = imx_clk_divider2("uart5_post_div", "uart5_pre_div", base + 0xb180, 0, 6);
-       clks[IMX7D_UART6_ROOT_DIV] = imx_clk_divider2("uart6_post_div", "uart6_pre_div", base + 0xb200, 0, 6);
-       clks[IMX7D_UART7_ROOT_DIV] = imx_clk_divider2("uart7_post_div", "uart7_pre_div", base + 0xb280, 0, 6);
-       clks[IMX7D_ECSPI1_ROOT_DIV] = imx_clk_divider2("ecspi1_post_div", "ecspi1_pre_div", base + 0xb300, 0, 6);
-       clks[IMX7D_ECSPI2_ROOT_DIV] = imx_clk_divider2("ecspi2_post_div", "ecspi2_pre_div", base + 0xb380, 0, 6);
-       clks[IMX7D_ECSPI3_ROOT_DIV] = imx_clk_divider2("ecspi3_post_div", "ecspi3_pre_div", base + 0xb400, 0, 6);
-       clks[IMX7D_ECSPI4_ROOT_DIV] = imx_clk_divider2("ecspi4_post_div", "ecspi4_pre_div", base + 0xb480, 0, 6);
-       clks[IMX7D_PWM1_ROOT_DIV] = imx_clk_divider2("pwm1_post_div", "pwm1_pre_div", base + 0xb500, 0, 6);
-       clks[IMX7D_PWM2_ROOT_DIV] = imx_clk_divider2("pwm2_post_div", "pwm2_pre_div", base + 0xb580, 0, 6);
-       clks[IMX7D_PWM3_ROOT_DIV] = imx_clk_divider2("pwm3_post_div", "pwm3_pre_div", base + 0xb600, 0, 6);
-       clks[IMX7D_PWM4_ROOT_DIV] = imx_clk_divider2("pwm4_post_div", "pwm4_pre_div", base + 0xb680, 0, 6);
-       clks[IMX7D_FLEXTIMER1_ROOT_DIV] = imx_clk_divider2("flextimer1_post_div", "flextimer1_pre_div", base + 0xb700, 0, 6);
-       clks[IMX7D_FLEXTIMER2_ROOT_DIV] = imx_clk_divider2("flextimer2_post_div", "flextimer2_pre_div", base + 0xb780, 0, 6);
-       clks[IMX7D_SIM1_ROOT_DIV] = imx_clk_divider2("sim1_post_div", "sim1_pre_div", base + 0xb800, 0, 6);
-       clks[IMX7D_SIM2_ROOT_DIV] = imx_clk_divider2("sim2_post_div", "sim2_pre_div", base + 0xb880, 0, 6);
-       clks[IMX7D_GPT1_ROOT_DIV] = imx_clk_divider2("gpt1_post_div", "gpt1_pre_div", base + 0xb900, 0, 6);
-       clks[IMX7D_GPT2_ROOT_DIV] = imx_clk_divider2("gpt2_post_div", "gpt2_pre_div", base + 0xb980, 0, 6);
-       clks[IMX7D_GPT3_ROOT_DIV] = imx_clk_divider2("gpt3_post_div", "gpt3_pre_div", base + 0xba00, 0, 6);
-       clks[IMX7D_GPT4_ROOT_DIV] = imx_clk_divider2("gpt4_post_div", "gpt4_pre_div", base + 0xba80, 0, 6);
-       clks[IMX7D_TRACE_ROOT_DIV] = imx_clk_divider2("trace_post_div", "trace_pre_div", base + 0xbb00, 0, 6);
-       clks[IMX7D_WDOG_ROOT_DIV] = imx_clk_divider2("wdog_post_div", "wdog_pre_div", base + 0xbb80, 0, 6);
-       clks[IMX7D_CSI_MCLK_ROOT_DIV] = imx_clk_divider2("csi_mclk_post_div", "csi_mclk_pre_div", base + 0xbc00, 0, 6);
-       clks[IMX7D_AUDIO_MCLK_ROOT_DIV] = imx_clk_divider2("audio_mclk_post_div", "audio_mclk_pre_div", base + 0xbc80, 0, 6);
-       clks[IMX7D_WRCLK_ROOT_DIV] = imx_clk_divider2("wrclk_post_div", "wrclk_pre_div", base + 0xbd00, 0, 6);
-       clks[IMX7D_CLKO1_ROOT_DIV] = imx_clk_divider2("clko1_post_div", "clko1_pre_div", base + 0xbd80, 0, 6);
-       clks[IMX7D_CLKO2_ROOT_DIV] = imx_clk_divider2("clko2_post_div", "clko2_pre_div", base + 0xbe00, 0, 6);
-
-       clks[IMX7D_ARM_A7_ROOT_CLK] = imx_clk_gate2_flags("arm_a7_root_clk", "arm_a7_div", base + 0x4000, 0, CLK_OPS_PARENT_ENABLE);
-       clks[IMX7D_ARM_M4_ROOT_CLK] = imx_clk_gate4("arm_m4_root_clk", "arm_m4_div", base + 0x4010, 0);
-       clks[IMX7D_MAIN_AXI_ROOT_CLK] = imx_clk_gate2_flags("main_axi_root_clk", "axi_post_div", base + 0x4040, 0, CLK_IS_CRITICAL | CLK_OPS_PARENT_ENABLE);
-       clks[IMX7D_DISP_AXI_ROOT_CLK] = imx_clk_gate4("disp_axi_root_clk", "disp_axi_post_div", base + 0x4050, 0);
-       clks[IMX7D_ENET_AXI_ROOT_CLK] = imx_clk_gate4("enet_axi_root_clk", "enet_axi_post_div", base + 0x4060, 0);
-       clks[IMX7D_OCRAM_CLK] = imx_clk_gate4("ocram_clk", "main_axi_root_clk", base + 0x4110, 0);
-       clks[IMX7D_OCRAM_S_CLK] = imx_clk_gate4("ocram_s_clk", "ahb_root_clk", base + 0x4120, 0);
-       clks[IMX7D_DRAM_ROOT_CLK] = imx_clk_gate2_flags("dram_root_clk", "dram_post_div", base + 0x4130, 0, CLK_IS_CRITICAL | CLK_OPS_PARENT_ENABLE);
-       clks[IMX7D_DRAM_PHYM_ROOT_CLK] = imx_clk_gate2_flags("dram_phym_root_clk", "dram_phym_cg", base + 0x4130, 0, CLK_IS_CRITICAL | CLK_OPS_PARENT_ENABLE);
-       clks[IMX7D_DRAM_PHYM_ALT_ROOT_CLK] = imx_clk_gate2_flags("dram_phym_alt_root_clk", "dram_phym_alt_post_div", base + 0x4130, 0, CLK_IS_CRITICAL | CLK_OPS_PARENT_ENABLE);
-       clks[IMX7D_DRAM_ALT_ROOT_CLK] = imx_clk_gate2_flags("dram_alt_root_clk", "dram_alt_post_div", base + 0x4130, 0, CLK_IS_CRITICAL | CLK_OPS_PARENT_ENABLE);
-       clks[IMX7D_OCOTP_CLK] = imx_clk_gate4("ocotp_clk", "ipg_root_clk", base + 0x4230, 0);
-       clks[IMX7D_SNVS_CLK] = imx_clk_gate4("snvs_clk", "ipg_root_clk", base + 0x4250, 0);
-       clks[IMX7D_MU_ROOT_CLK] = imx_clk_gate4("mu_root_clk", "ipg_root_clk", base + 0x4270, 0);
-       clks[IMX7D_CAAM_CLK] = imx_clk_gate4("caam_clk", "ipg_root_clk", base + 0x4240, 0);
-       clks[IMX7D_USB_HSIC_ROOT_CLK] = imx_clk_gate4("usb_hsic_root_clk", "usb_hsic_post_div", base + 0x4690, 0);
-       clks[IMX7D_SDMA_CORE_CLK] = imx_clk_gate4("sdma_root_clk", "ahb_root_clk", base + 0x4480, 0);
-       clks[IMX7D_PCIE_CTRL_ROOT_CLK] = imx_clk_gate4("pcie_ctrl_root_clk", "pcie_ctrl_post_div", base + 0x4600, 0);
-       clks[IMX7D_PCIE_PHY_ROOT_CLK] = imx_clk_gate4("pcie_phy_root_clk", "pcie_phy_post_div", base + 0x4600, 0);
-       clks[IMX7D_EPDC_PIXEL_ROOT_CLK] = imx_clk_gate4("epdc_pixel_root_clk", "epdc_pixel_post_div", base + 0x44a0, 0);
-       clks[IMX7D_LCDIF_PIXEL_ROOT_CLK] = imx_clk_gate4("lcdif_pixel_root_clk", "lcdif_pixel_post_div", base + 0x44b0, 0);
-       clks[IMX7D_MIPI_DSI_ROOT_CLK] = imx_clk_gate4("mipi_dsi_root_clk", "mipi_dsi_post_div", base + 0x4650, 0);
-       clks[IMX7D_MIPI_CSI_ROOT_CLK] = imx_clk_gate4("mipi_csi_root_clk", "mipi_csi_post_div", base + 0x4640, 0);
-       clks[IMX7D_MIPI_DPHY_ROOT_CLK] = imx_clk_gate4("mipi_dphy_root_clk", "mipi_dphy_post_div", base + 0x4660, 0);
-       clks[IMX7D_ENET1_IPG_ROOT_CLK] = imx_clk_gate2_shared2("enet1_ipg_root_clk", "enet_axi_post_div", base + 0x4700, 0, &share_count_enet1);
-       clks[IMX7D_ENET1_TIME_ROOT_CLK] = imx_clk_gate2_shared2("enet1_time_root_clk", "enet1_time_post_div", base + 0x4700, 0, &share_count_enet1);
-       clks[IMX7D_ENET2_IPG_ROOT_CLK] = imx_clk_gate2_shared2("enet2_ipg_root_clk", "enet_axi_post_div", base + 0x4710, 0, &share_count_enet2);
-       clks[IMX7D_ENET2_TIME_ROOT_CLK] = imx_clk_gate2_shared2("enet2_time_root_clk", "enet2_time_post_div", base + 0x4710, 0, &share_count_enet2);
-       clks[IMX7D_SAI1_ROOT_CLK] = imx_clk_gate2_shared2("sai1_root_clk", "sai1_post_div", base + 0x48c0, 0, &share_count_sai1);
-       clks[IMX7D_SAI1_IPG_CLK]  = imx_clk_gate2_shared2("sai1_ipg_clk",  "ipg_root_clk",  base + 0x48c0, 0, &share_count_sai1);
-       clks[IMX7D_SAI2_ROOT_CLK] = imx_clk_gate2_shared2("sai2_root_clk", "sai2_post_div", base + 0x48d0, 0, &share_count_sai2);
-       clks[IMX7D_SAI2_IPG_CLK]  = imx_clk_gate2_shared2("sai2_ipg_clk",  "ipg_root_clk",  base + 0x48d0, 0, &share_count_sai2);
-       clks[IMX7D_SAI3_ROOT_CLK] = imx_clk_gate2_shared2("sai3_root_clk", "sai3_post_div", base + 0x48e0, 0, &share_count_sai3);
-       clks[IMX7D_SAI3_IPG_CLK]  = imx_clk_gate2_shared2("sai3_ipg_clk",  "ipg_root_clk",  base + 0x48e0, 0, &share_count_sai3);
-       clks[IMX7D_SPDIF_ROOT_CLK] = imx_clk_gate4("spdif_root_clk", "spdif_post_div", base + 0x44d0, 0);
-       clks[IMX7D_EIM_ROOT_CLK] = imx_clk_gate4("eim_root_clk", "eim_post_div", base + 0x4160, 0);
-       clks[IMX7D_NAND_RAWNAND_CLK] = imx_clk_gate2_shared2("nand_rawnand_clk", "nand_root_clk", base + 0x4140, 0, &share_count_nand);
-       clks[IMX7D_NAND_USDHC_BUS_RAWNAND_CLK] = imx_clk_gate2_shared2("nand_usdhc_rawnand_clk", "nand_usdhc_root_clk", base + 0x4140, 0, &share_count_nand);
-       clks[IMX7D_QSPI_ROOT_CLK] = imx_clk_gate4("qspi_root_clk", "qspi_post_div", base + 0x4150, 0);
-       clks[IMX7D_USDHC1_ROOT_CLK] = imx_clk_gate4("usdhc1_root_clk", "usdhc1_post_div", base + 0x46c0, 0);
-       clks[IMX7D_USDHC2_ROOT_CLK] = imx_clk_gate4("usdhc2_root_clk", "usdhc2_post_div", base + 0x46d0, 0);
-       clks[IMX7D_USDHC3_ROOT_CLK] = imx_clk_gate4("usdhc3_root_clk", "usdhc3_post_div", base + 0x46e0, 0);
-       clks[IMX7D_CAN1_ROOT_CLK] = imx_clk_gate4("can1_root_clk", "can1_post_div", base + 0x4740, 0);
-       clks[IMX7D_CAN2_ROOT_CLK] = imx_clk_gate4("can2_root_clk", "can2_post_div", base + 0x4750, 0);
-       clks[IMX7D_I2C1_ROOT_CLK] = imx_clk_gate4("i2c1_root_clk", "i2c1_post_div", base + 0x4880, 0);
-       clks[IMX7D_I2C2_ROOT_CLK] = imx_clk_gate4("i2c2_root_clk", "i2c2_post_div", base + 0x4890, 0);
-       clks[IMX7D_I2C3_ROOT_CLK] = imx_clk_gate4("i2c3_root_clk", "i2c3_post_div", base + 0x48a0, 0);
-       clks[IMX7D_I2C4_ROOT_CLK] = imx_clk_gate4("i2c4_root_clk", "i2c4_post_div", base + 0x48b0, 0);
-       clks[IMX7D_UART1_ROOT_CLK] = imx_clk_gate4("uart1_root_clk", "uart1_post_div", base + 0x4940, 0);
-       clks[IMX7D_UART2_ROOT_CLK] = imx_clk_gate4("uart2_root_clk", "uart2_post_div", base + 0x4950, 0);
-       clks[IMX7D_UART3_ROOT_CLK] = imx_clk_gate4("uart3_root_clk", "uart3_post_div", base + 0x4960, 0);
-       clks[IMX7D_UART4_ROOT_CLK] = imx_clk_gate4("uart4_root_clk", "uart4_post_div", base + 0x4970, 0);
-       clks[IMX7D_UART5_ROOT_CLK] = imx_clk_gate4("uart5_root_clk", "uart5_post_div", base + 0x4980, 0);
-       clks[IMX7D_UART6_ROOT_CLK] = imx_clk_gate4("uart6_root_clk", "uart6_post_div", base + 0x4990, 0);
-       clks[IMX7D_UART7_ROOT_CLK] = imx_clk_gate4("uart7_root_clk", "uart7_post_div", base + 0x49a0, 0);
-       clks[IMX7D_ECSPI1_ROOT_CLK] = imx_clk_gate4("ecspi1_root_clk", "ecspi1_post_div", base + 0x4780, 0);
-       clks[IMX7D_ECSPI2_ROOT_CLK] = imx_clk_gate4("ecspi2_root_clk", "ecspi2_post_div", base + 0x4790, 0);
-       clks[IMX7D_ECSPI3_ROOT_CLK] = imx_clk_gate4("ecspi3_root_clk", "ecspi3_post_div", base + 0x47a0, 0);
-       clks[IMX7D_ECSPI4_ROOT_CLK] = imx_clk_gate4("ecspi4_root_clk", "ecspi4_post_div", base + 0x47b0, 0);
-       clks[IMX7D_PWM1_ROOT_CLK] = imx_clk_gate4("pwm1_root_clk", "pwm1_post_div", base + 0x4840, 0);
-       clks[IMX7D_PWM2_ROOT_CLK] = imx_clk_gate4("pwm2_root_clk", "pwm2_post_div", base + 0x4850, 0);
-       clks[IMX7D_PWM3_ROOT_CLK] = imx_clk_gate4("pwm3_root_clk", "pwm3_post_div", base + 0x4860, 0);
-       clks[IMX7D_PWM4_ROOT_CLK] = imx_clk_gate4("pwm4_root_clk", "pwm4_post_div", base + 0x4870, 0);
-       clks[IMX7D_FLEXTIMER1_ROOT_CLK] = imx_clk_gate4("flextimer1_root_clk", "flextimer1_post_div", base + 0x4800, 0);
-       clks[IMX7D_FLEXTIMER2_ROOT_CLK] = imx_clk_gate4("flextimer2_root_clk", "flextimer2_post_div", base + 0x4810, 0);
-       clks[IMX7D_SIM1_ROOT_CLK] = imx_clk_gate4("sim1_root_clk", "sim1_post_div", base + 0x4900, 0);
-       clks[IMX7D_SIM2_ROOT_CLK] = imx_clk_gate4("sim2_root_clk", "sim2_post_div", base + 0x4910, 0);
-       clks[IMX7D_GPT1_ROOT_CLK] = imx_clk_gate4("gpt1_root_clk", "gpt1_post_div", base + 0x47c0, 0);
-       clks[IMX7D_GPT2_ROOT_CLK] = imx_clk_gate4("gpt2_root_clk", "gpt2_post_div", base + 0x47d0, 0);
-       clks[IMX7D_GPT3_ROOT_CLK] = imx_clk_gate4("gpt3_root_clk", "gpt3_post_div", base + 0x47e0, 0);
-       clks[IMX7D_GPT4_ROOT_CLK] = imx_clk_gate4("gpt4_root_clk", "gpt4_post_div", base + 0x47f0, 0);
-       clks[IMX7D_TRACE_ROOT_CLK] = imx_clk_gate4("trace_root_clk", "trace_post_div", base + 0x4300, 0);
-       clks[IMX7D_WDOG1_ROOT_CLK] = imx_clk_gate4("wdog1_root_clk", "wdog_post_div", base + 0x49c0, 0);
-       clks[IMX7D_WDOG2_ROOT_CLK] = imx_clk_gate4("wdog2_root_clk", "wdog_post_div", base + 0x49d0, 0);
-       clks[IMX7D_WDOG3_ROOT_CLK] = imx_clk_gate4("wdog3_root_clk", "wdog_post_div", base + 0x49e0, 0);
-       clks[IMX7D_WDOG4_ROOT_CLK] = imx_clk_gate4("wdog4_root_clk", "wdog_post_div", base + 0x49f0, 0);
-       clks[IMX7D_KPP_ROOT_CLK] = imx_clk_gate4("kpp_root_clk", "ipg_root_clk", base + 0x4aa0, 0);
-       clks[IMX7D_CSI_MCLK_ROOT_CLK] = imx_clk_gate4("csi_mclk_root_clk", "csi_mclk_post_div", base + 0x4490, 0);
-       clks[IMX7D_AUDIO_MCLK_ROOT_CLK] = imx_clk_gate4("audio_mclk_root_clk", "audio_mclk_post_div", base + 0x4790, 0);
-       clks[IMX7D_WRCLK_ROOT_CLK] = imx_clk_gate4("wrclk_root_clk", "wrclk_post_div", base + 0x47a0, 0);
-       clks[IMX7D_USB_CTRL_CLK] = imx_clk_gate4("usb_ctrl_clk", "ahb_root_clk", base + 0x4680, 0);
-       clks[IMX7D_USB_PHY1_CLK] = imx_clk_gate4("usb_phy1_clk", "pll_usb1_main_clk", base + 0x46a0, 0);
-       clks[IMX7D_USB_PHY2_CLK] = imx_clk_gate4("usb_phy2_clk", "pll_usb_main_clk", base + 0x46b0, 0);
-       clks[IMX7D_ADC_ROOT_CLK] = imx_clk_gate4("adc_root_clk", "ipg_root_clk", base + 0x4200, 0);
-
-       clks[IMX7D_GPT_3M_CLK] = imx_clk_fixed_factor("gpt_3m", "osc", 1, 8);
-
-       clks[IMX7D_CLK_ARM] = imx_clk_cpu("arm", "arm_a7_root_clk",
-                                        clks[IMX7D_ARM_A7_ROOT_CLK],
-                                        clks[IMX7D_ARM_A7_ROOT_SRC],
-                                        clks[IMX7D_PLL_ARM_MAIN_CLK],
-                                        clks[IMX7D_PLL_SYS_MAIN_CLK]);
-
-       imx_check_clocks(clks, ARRAY_SIZE(clks));
-
-       clk_data.clks = clks;
-       clk_data.clk_num = ARRAY_SIZE(clks);
-       of_clk_add_provider(np, of_clk_src_onecell_get, &clk_data);
-
-       clk_set_parent(clks[IMX7D_PLL_ARM_MAIN_BYPASS], clks[IMX7D_PLL_ARM_MAIN]);
-       clk_set_parent(clks[IMX7D_PLL_DRAM_MAIN_BYPASS], clks[IMX7D_PLL_DRAM_MAIN]);
-       clk_set_parent(clks[IMX7D_PLL_SYS_MAIN_BYPASS], clks[IMX7D_PLL_SYS_MAIN]);
-       clk_set_parent(clks[IMX7D_PLL_ENET_MAIN_BYPASS], clks[IMX7D_PLL_ENET_MAIN]);
-       clk_set_parent(clks[IMX7D_PLL_AUDIO_MAIN_BYPASS], clks[IMX7D_PLL_AUDIO_MAIN]);
-       clk_set_parent(clks[IMX7D_PLL_VIDEO_MAIN_BYPASS], clks[IMX7D_PLL_VIDEO_MAIN]);
-
-       clk_set_parent(clks[IMX7D_MIPI_CSI_ROOT_SRC], clks[IMX7D_PLL_SYS_PFD3_CLK]);
+       hws[IMX7D_ARM_A7_ROOT_SRC] = imx_clk_hw_mux2("arm_a7_src", base + 0x8000, 24, 3, arm_a7_sel, ARRAY_SIZE(arm_a7_sel));
+       hws[IMX7D_ARM_M4_ROOT_SRC] = imx_clk_hw_mux2("arm_m4_src", base + 0x8080, 24, 3, arm_m4_sel, ARRAY_SIZE(arm_m4_sel));
+       hws[IMX7D_MAIN_AXI_ROOT_SRC] = imx_clk_hw_mux2("axi_src", base + 0x8800, 24, 3, axi_sel, ARRAY_SIZE(axi_sel));
+       hws[IMX7D_DISP_AXI_ROOT_SRC] = imx_clk_hw_mux2("disp_axi_src", base + 0x8880, 24, 3, disp_axi_sel, ARRAY_SIZE(disp_axi_sel));
+       hws[IMX7D_ENET_AXI_ROOT_SRC] = imx_clk_hw_mux2("enet_axi_src", base + 0x8900, 24, 3, enet_axi_sel, ARRAY_SIZE(enet_axi_sel));
+       hws[IMX7D_NAND_USDHC_BUS_ROOT_SRC] = imx_clk_hw_mux2("nand_usdhc_src", base + 0x8980, 24, 3, nand_usdhc_bus_sel, ARRAY_SIZE(nand_usdhc_bus_sel));
+       hws[IMX7D_AHB_CHANNEL_ROOT_SRC] = imx_clk_hw_mux2("ahb_src", base + 0x9000, 24, 3, ahb_channel_sel, ARRAY_SIZE(ahb_channel_sel));
+       hws[IMX7D_DRAM_PHYM_ROOT_SRC] = imx_clk_hw_mux2("dram_phym_src", base + 0x9800, 24, 1, dram_phym_sel, ARRAY_SIZE(dram_phym_sel));
+       hws[IMX7D_DRAM_ROOT_SRC] = imx_clk_hw_mux2("dram_src", base + 0x9880, 24, 1, dram_sel, ARRAY_SIZE(dram_sel));
+       hws[IMX7D_DRAM_PHYM_ALT_ROOT_SRC] = imx_clk_hw_mux2("dram_phym_alt_src", base + 0xa000, 24, 3, dram_phym_alt_sel, ARRAY_SIZE(dram_phym_alt_sel));
+       hws[IMX7D_DRAM_ALT_ROOT_SRC]  = imx_clk_hw_mux2("dram_alt_src", base + 0xa080, 24, 3, dram_alt_sel, ARRAY_SIZE(dram_alt_sel));
+       hws[IMX7D_USB_HSIC_ROOT_SRC] = imx_clk_hw_mux2("usb_hsic_src", base + 0xa100, 24, 3, usb_hsic_sel, ARRAY_SIZE(usb_hsic_sel));
+       hws[IMX7D_PCIE_CTRL_ROOT_SRC] = imx_clk_hw_mux2("pcie_ctrl_src", base + 0xa180, 24, 3, pcie_ctrl_sel, ARRAY_SIZE(pcie_ctrl_sel));
+       hws[IMX7D_PCIE_PHY_ROOT_SRC] = imx_clk_hw_mux2("pcie_phy_src", base + 0xa200, 24, 3, pcie_phy_sel, ARRAY_SIZE(pcie_phy_sel));
+       hws[IMX7D_EPDC_PIXEL_ROOT_SRC] = imx_clk_hw_mux2("epdc_pixel_src", base + 0xa280, 24, 3, epdc_pixel_sel, ARRAY_SIZE(epdc_pixel_sel));
+       hws[IMX7D_LCDIF_PIXEL_ROOT_SRC] = imx_clk_hw_mux2("lcdif_pixel_src", base + 0xa300, 24, 3, lcdif_pixel_sel, ARRAY_SIZE(lcdif_pixel_sel));
+       hws[IMX7D_MIPI_DSI_ROOT_SRC] = imx_clk_hw_mux2("mipi_dsi_src", base + 0xa380, 24, 3,  mipi_dsi_sel, ARRAY_SIZE(mipi_dsi_sel));
+       hws[IMX7D_MIPI_CSI_ROOT_SRC] = imx_clk_hw_mux2("mipi_csi_src", base + 0xa400, 24, 3, mipi_csi_sel, ARRAY_SIZE(mipi_csi_sel));
+       hws[IMX7D_MIPI_DPHY_ROOT_SRC] = imx_clk_hw_mux2("mipi_dphy_src", base + 0xa480, 24, 3, mipi_dphy_sel, ARRAY_SIZE(mipi_dphy_sel));
+       hws[IMX7D_SAI1_ROOT_SRC] = imx_clk_hw_mux2("sai1_src", base + 0xa500, 24, 3, sai1_sel, ARRAY_SIZE(sai1_sel));
+       hws[IMX7D_SAI2_ROOT_SRC] = imx_clk_hw_mux2("sai2_src", base + 0xa580, 24, 3, sai2_sel, ARRAY_SIZE(sai2_sel));
+       hws[IMX7D_SAI3_ROOT_SRC] = imx_clk_hw_mux2("sai3_src", base + 0xa600, 24, 3, sai3_sel, ARRAY_SIZE(sai3_sel));
+       hws[IMX7D_SPDIF_ROOT_SRC] = imx_clk_hw_mux2("spdif_src", base + 0xa680, 24, 3, spdif_sel, ARRAY_SIZE(spdif_sel));
+       hws[IMX7D_ENET1_REF_ROOT_SRC] = imx_clk_hw_mux2("enet1_ref_src", base + 0xa700, 24, 3, enet1_ref_sel, ARRAY_SIZE(enet1_ref_sel));
+       hws[IMX7D_ENET1_TIME_ROOT_SRC] = imx_clk_hw_mux2("enet1_time_src", base + 0xa780, 24, 3, enet1_time_sel, ARRAY_SIZE(enet1_time_sel));
+       hws[IMX7D_ENET2_REF_ROOT_SRC] = imx_clk_hw_mux2("enet2_ref_src", base + 0xa800, 24, 3, enet2_ref_sel, ARRAY_SIZE(enet2_ref_sel));
+       hws[IMX7D_ENET2_TIME_ROOT_SRC] = imx_clk_hw_mux2("enet2_time_src", base + 0xa880, 24, 3, enet2_time_sel, ARRAY_SIZE(enet2_time_sel));
+       hws[IMX7D_ENET_PHY_REF_ROOT_SRC] = imx_clk_hw_mux2("enet_phy_ref_src", base + 0xa900, 24, 3, enet_phy_ref_sel, ARRAY_SIZE(enet_phy_ref_sel));
+       hws[IMX7D_EIM_ROOT_SRC] = imx_clk_hw_mux2("eim_src", base + 0xa980, 24, 3, eim_sel, ARRAY_SIZE(eim_sel));
+       hws[IMX7D_NAND_ROOT_SRC] = imx_clk_hw_mux2("nand_src", base + 0xaa00, 24, 3, nand_sel, ARRAY_SIZE(nand_sel));
+       hws[IMX7D_QSPI_ROOT_SRC] = imx_clk_hw_mux2("qspi_src", base + 0xaa80, 24, 3, qspi_sel, ARRAY_SIZE(qspi_sel));
+       hws[IMX7D_USDHC1_ROOT_SRC] = imx_clk_hw_mux2("usdhc1_src", base + 0xab00, 24, 3, usdhc1_sel, ARRAY_SIZE(usdhc1_sel));
+       hws[IMX7D_USDHC2_ROOT_SRC] = imx_clk_hw_mux2("usdhc2_src", base + 0xab80, 24, 3, usdhc2_sel, ARRAY_SIZE(usdhc2_sel));
+       hws[IMX7D_USDHC3_ROOT_SRC] = imx_clk_hw_mux2("usdhc3_src", base + 0xac00, 24, 3, usdhc3_sel, ARRAY_SIZE(usdhc3_sel));
+       hws[IMX7D_CAN1_ROOT_SRC] = imx_clk_hw_mux2("can1_src", base + 0xac80, 24, 3, can1_sel, ARRAY_SIZE(can1_sel));
+       hws[IMX7D_CAN2_ROOT_SRC] = imx_clk_hw_mux2("can2_src", base + 0xad00, 24, 3, can2_sel, ARRAY_SIZE(can2_sel));
+       hws[IMX7D_I2C1_ROOT_SRC] = imx_clk_hw_mux2("i2c1_src", base + 0xad80, 24, 3, i2c1_sel, ARRAY_SIZE(i2c1_sel));
+       hws[IMX7D_I2C2_ROOT_SRC] = imx_clk_hw_mux2("i2c2_src", base + 0xae00, 24, 3, i2c2_sel, ARRAY_SIZE(i2c2_sel));
+       hws[IMX7D_I2C3_ROOT_SRC] = imx_clk_hw_mux2("i2c3_src", base + 0xae80, 24, 3, i2c3_sel, ARRAY_SIZE(i2c3_sel));
+       hws[IMX7D_I2C4_ROOT_SRC] = imx_clk_hw_mux2("i2c4_src", base + 0xaf00, 24, 3, i2c4_sel, ARRAY_SIZE(i2c4_sel));
+       hws[IMX7D_UART1_ROOT_SRC] = imx_clk_hw_mux2("uart1_src", base + 0xaf80, 24, 3, uart1_sel, ARRAY_SIZE(uart1_sel));
+       hws[IMX7D_UART2_ROOT_SRC] = imx_clk_hw_mux2("uart2_src", base + 0xb000, 24, 3, uart2_sel, ARRAY_SIZE(uart2_sel));
+       hws[IMX7D_UART3_ROOT_SRC] = imx_clk_hw_mux2("uart3_src", base + 0xb080, 24, 3, uart3_sel, ARRAY_SIZE(uart3_sel));
+       hws[IMX7D_UART4_ROOT_SRC] = imx_clk_hw_mux2("uart4_src", base + 0xb100, 24, 3, uart4_sel, ARRAY_SIZE(uart4_sel));
+       hws[IMX7D_UART5_ROOT_SRC] = imx_clk_hw_mux2("uart5_src", base + 0xb180, 24, 3, uart5_sel, ARRAY_SIZE(uart5_sel));
+       hws[IMX7D_UART6_ROOT_SRC] = imx_clk_hw_mux2("uart6_src", base + 0xb200, 24, 3, uart6_sel, ARRAY_SIZE(uart6_sel));
+       hws[IMX7D_UART7_ROOT_SRC] = imx_clk_hw_mux2("uart7_src", base + 0xb280, 24, 3, uart7_sel, ARRAY_SIZE(uart7_sel));
+       hws[IMX7D_ECSPI1_ROOT_SRC] = imx_clk_hw_mux2("ecspi1_src", base + 0xb300, 24, 3, ecspi1_sel, ARRAY_SIZE(ecspi1_sel));
+       hws[IMX7D_ECSPI2_ROOT_SRC] = imx_clk_hw_mux2("ecspi2_src", base + 0xb380, 24, 3, ecspi2_sel, ARRAY_SIZE(ecspi2_sel));
+       hws[IMX7D_ECSPI3_ROOT_SRC] = imx_clk_hw_mux2("ecspi3_src", base + 0xb400, 24, 3, ecspi3_sel, ARRAY_SIZE(ecspi3_sel));
+       hws[IMX7D_ECSPI4_ROOT_SRC] = imx_clk_hw_mux2("ecspi4_src", base + 0xb480, 24, 3, ecspi4_sel, ARRAY_SIZE(ecspi4_sel));
+       hws[IMX7D_PWM1_ROOT_SRC] = imx_clk_hw_mux2("pwm1_src", base + 0xb500, 24, 3, pwm1_sel, ARRAY_SIZE(pwm1_sel));
+       hws[IMX7D_PWM2_ROOT_SRC] = imx_clk_hw_mux2("pwm2_src", base + 0xb580, 24, 3, pwm2_sel, ARRAY_SIZE(pwm2_sel));
+       hws[IMX7D_PWM3_ROOT_SRC] = imx_clk_hw_mux2("pwm3_src", base + 0xb600, 24, 3, pwm3_sel, ARRAY_SIZE(pwm3_sel));
+       hws[IMX7D_PWM4_ROOT_SRC] = imx_clk_hw_mux2("pwm4_src", base + 0xb680, 24, 3, pwm4_sel, ARRAY_SIZE(pwm4_sel));
+       hws[IMX7D_FLEXTIMER1_ROOT_SRC] = imx_clk_hw_mux2("flextimer1_src", base + 0xb700, 24, 3, flextimer1_sel, ARRAY_SIZE(flextimer1_sel));
+       hws[IMX7D_FLEXTIMER2_ROOT_SRC] = imx_clk_hw_mux2("flextimer2_src", base + 0xb780, 24, 3, flextimer2_sel, ARRAY_SIZE(flextimer2_sel));
+       hws[IMX7D_SIM1_ROOT_SRC] = imx_clk_hw_mux2("sim1_src", base + 0xb800, 24, 3, sim1_sel, ARRAY_SIZE(sim1_sel));
+       hws[IMX7D_SIM2_ROOT_SRC] = imx_clk_hw_mux2("sim2_src", base + 0xb880, 24, 3, sim2_sel, ARRAY_SIZE(sim2_sel));
+       hws[IMX7D_GPT1_ROOT_SRC] = imx_clk_hw_mux2("gpt1_src", base + 0xb900, 24, 3, gpt1_sel, ARRAY_SIZE(gpt1_sel));
+       hws[IMX7D_GPT2_ROOT_SRC] = imx_clk_hw_mux2("gpt2_src", base + 0xb980, 24, 3, gpt2_sel, ARRAY_SIZE(gpt2_sel));
+       hws[IMX7D_GPT3_ROOT_SRC] = imx_clk_hw_mux2("gpt3_src", base + 0xba00, 24, 3, gpt3_sel, ARRAY_SIZE(gpt3_sel));
+       hws[IMX7D_GPT4_ROOT_SRC] = imx_clk_hw_mux2("gpt4_src", base + 0xba80, 24, 3, gpt4_sel, ARRAY_SIZE(gpt4_sel));
+       hws[IMX7D_TRACE_ROOT_SRC] = imx_clk_hw_mux2("trace_src", base + 0xbb00, 24, 3, trace_sel, ARRAY_SIZE(trace_sel));
+       hws[IMX7D_WDOG_ROOT_SRC] = imx_clk_hw_mux2("wdog_src", base + 0xbb80, 24, 3, wdog_sel, ARRAY_SIZE(wdog_sel));
+       hws[IMX7D_CSI_MCLK_ROOT_SRC] = imx_clk_hw_mux2("csi_mclk_src", base + 0xbc00, 24, 3, csi_mclk_sel, ARRAY_SIZE(csi_mclk_sel));
+       hws[IMX7D_AUDIO_MCLK_ROOT_SRC] = imx_clk_hw_mux2("audio_mclk_src", base + 0xbc80, 24, 3, audio_mclk_sel, ARRAY_SIZE(audio_mclk_sel));
+       hws[IMX7D_WRCLK_ROOT_SRC] = imx_clk_hw_mux2("wrclk_src", base + 0xbd00, 24, 3, wrclk_sel, ARRAY_SIZE(wrclk_sel));
+       hws[IMX7D_CLKO1_ROOT_SRC] = imx_clk_hw_mux2("clko1_src", base + 0xbd80, 24, 3, clko1_sel, ARRAY_SIZE(clko1_sel));
+       hws[IMX7D_CLKO2_ROOT_SRC] = imx_clk_hw_mux2("clko2_src", base + 0xbe00, 24, 3, clko2_sel, ARRAY_SIZE(clko2_sel));
+
+       hws[IMX7D_ARM_A7_ROOT_CG] = imx_clk_hw_gate3("arm_a7_cg", "arm_a7_src", base + 0x8000, 28);
+       hws[IMX7D_ARM_M4_ROOT_CG] = imx_clk_hw_gate3("arm_m4_cg", "arm_m4_src", base + 0x8080, 28);
+       hws[IMX7D_MAIN_AXI_ROOT_CG] = imx_clk_hw_gate3("axi_cg", "axi_src", base + 0x8800, 28);
+       hws[IMX7D_DISP_AXI_ROOT_CG] = imx_clk_hw_gate3("disp_axi_cg", "disp_axi_src", base + 0x8880, 28);
+       hws[IMX7D_ENET_AXI_ROOT_CG] = imx_clk_hw_gate3("enet_axi_cg", "enet_axi_src", base + 0x8900, 28);
+       hws[IMX7D_NAND_USDHC_BUS_ROOT_CG] = imx_clk_hw_gate3("nand_usdhc_cg", "nand_usdhc_src", base + 0x8980, 28);
+       hws[IMX7D_AHB_CHANNEL_ROOT_CG] = imx_clk_hw_gate3("ahb_cg", "ahb_src", base + 0x9000, 28);
+       hws[IMX7D_DRAM_PHYM_ROOT_CG] = imx_clk_hw_gate3("dram_phym_cg", "dram_phym_src", base + 0x9800, 28);
+       hws[IMX7D_DRAM_ROOT_CG] = imx_clk_hw_gate3("dram_cg", "dram_src", base + 0x9880, 28);
+       hws[IMX7D_DRAM_PHYM_ALT_ROOT_CG] = imx_clk_hw_gate3("dram_phym_alt_cg", "dram_phym_alt_src", base + 0xa000, 28);
+       hws[IMX7D_DRAM_ALT_ROOT_CG] = imx_clk_hw_gate3("dram_alt_cg", "dram_alt_src", base + 0xa080, 28);
+       hws[IMX7D_USB_HSIC_ROOT_CG] = imx_clk_hw_gate3("usb_hsic_cg", "usb_hsic_src", base + 0xa100, 28);
+       hws[IMX7D_PCIE_CTRL_ROOT_CG] = imx_clk_hw_gate3("pcie_ctrl_cg", "pcie_ctrl_src", base + 0xa180, 28);
+       hws[IMX7D_PCIE_PHY_ROOT_CG] = imx_clk_hw_gate3("pcie_phy_cg", "pcie_phy_src", base + 0xa200, 28);
+       hws[IMX7D_EPDC_PIXEL_ROOT_CG] = imx_clk_hw_gate3("epdc_pixel_cg", "epdc_pixel_src", base + 0xa280, 28);
+       hws[IMX7D_LCDIF_PIXEL_ROOT_CG] = imx_clk_hw_gate3("lcdif_pixel_cg", "lcdif_pixel_src", base + 0xa300, 28);
+       hws[IMX7D_MIPI_DSI_ROOT_CG] = imx_clk_hw_gate3("mipi_dsi_cg", "mipi_dsi_src", base + 0xa380, 28);
+       hws[IMX7D_MIPI_CSI_ROOT_CG] = imx_clk_hw_gate3("mipi_csi_cg", "mipi_csi_src", base + 0xa400, 28);
+       hws[IMX7D_MIPI_DPHY_ROOT_CG] = imx_clk_hw_gate3("mipi_dphy_cg", "mipi_dphy_src", base + 0xa480, 28);
+       hws[IMX7D_SAI1_ROOT_CG] = imx_clk_hw_gate3("sai1_cg", "sai1_src", base + 0xa500, 28);
+       hws[IMX7D_SAI2_ROOT_CG] = imx_clk_hw_gate3("sai2_cg", "sai2_src", base + 0xa580, 28);
+       hws[IMX7D_SAI3_ROOT_CG] = imx_clk_hw_gate3("sai3_cg", "sai3_src", base + 0xa600, 28);
+       hws[IMX7D_SPDIF_ROOT_CG] = imx_clk_hw_gate3("spdif_cg", "spdif_src", base + 0xa680, 28);
+       hws[IMX7D_ENET1_REF_ROOT_CG] = imx_clk_hw_gate3("enet1_ref_cg", "enet1_ref_src", base + 0xa700, 28);
+       hws[IMX7D_ENET1_TIME_ROOT_CG] = imx_clk_hw_gate3("enet1_time_cg", "enet1_time_src", base + 0xa780, 28);
+       hws[IMX7D_ENET2_REF_ROOT_CG] = imx_clk_hw_gate3("enet2_ref_cg", "enet2_ref_src", base + 0xa800, 28);
+       hws[IMX7D_ENET2_TIME_ROOT_CG] = imx_clk_hw_gate3("enet2_time_cg", "enet2_time_src", base + 0xa880, 28);
+       hws[IMX7D_ENET_PHY_REF_ROOT_CG] = imx_clk_hw_gate3("enet_phy_ref_cg", "enet_phy_ref_src", base + 0xa900, 28);
+       hws[IMX7D_EIM_ROOT_CG] = imx_clk_hw_gate3("eim_cg", "eim_src", base + 0xa980, 28);
+       hws[IMX7D_NAND_ROOT_CG] = imx_clk_hw_gate3("nand_cg", "nand_src", base + 0xaa00, 28);
+       hws[IMX7D_QSPI_ROOT_CG] = imx_clk_hw_gate3("qspi_cg", "qspi_src", base + 0xaa80, 28);
+       hws[IMX7D_USDHC1_ROOT_CG] = imx_clk_hw_gate3("usdhc1_cg", "usdhc1_src", base + 0xab00, 28);
+       hws[IMX7D_USDHC2_ROOT_CG] = imx_clk_hw_gate3("usdhc2_cg", "usdhc2_src", base + 0xab80, 28);
+       hws[IMX7D_USDHC3_ROOT_CG] = imx_clk_hw_gate3("usdhc3_cg", "usdhc3_src", base + 0xac00, 28);
+       hws[IMX7D_CAN1_ROOT_CG] = imx_clk_hw_gate3("can1_cg", "can1_src", base + 0xac80, 28);
+       hws[IMX7D_CAN2_ROOT_CG] = imx_clk_hw_gate3("can2_cg", "can2_src", base + 0xad00, 28);
+       hws[IMX7D_I2C1_ROOT_CG] = imx_clk_hw_gate3("i2c1_cg", "i2c1_src", base + 0xad80, 28);
+       hws[IMX7D_I2C2_ROOT_CG] = imx_clk_hw_gate3("i2c2_cg", "i2c2_src", base + 0xae00, 28);
+       hws[IMX7D_I2C3_ROOT_CG] = imx_clk_hw_gate3("i2c3_cg", "i2c3_src", base + 0xae80, 28);
+       hws[IMX7D_I2C4_ROOT_CG] = imx_clk_hw_gate3("i2c4_cg", "i2c4_src", base + 0xaf00, 28);
+       hws[IMX7D_UART1_ROOT_CG] = imx_clk_hw_gate3("uart1_cg", "uart1_src", base + 0xaf80, 28);
+       hws[IMX7D_UART2_ROOT_CG] = imx_clk_hw_gate3("uart2_cg", "uart2_src", base + 0xb000, 28);
+       hws[IMX7D_UART3_ROOT_CG] = imx_clk_hw_gate3("uart3_cg", "uart3_src", base + 0xb080, 28);
+       hws[IMX7D_UART4_ROOT_CG] = imx_clk_hw_gate3("uart4_cg", "uart4_src", base + 0xb100, 28);
+       hws[IMX7D_UART5_ROOT_CG] = imx_clk_hw_gate3("uart5_cg", "uart5_src", base + 0xb180, 28);
+       hws[IMX7D_UART6_ROOT_CG] = imx_clk_hw_gate3("uart6_cg", "uart6_src", base + 0xb200, 28);
+       hws[IMX7D_UART7_ROOT_CG] = imx_clk_hw_gate3("uart7_cg", "uart7_src", base + 0xb280, 28);
+       hws[IMX7D_ECSPI1_ROOT_CG] = imx_clk_hw_gate3("ecspi1_cg", "ecspi1_src", base + 0xb300, 28);
+       hws[IMX7D_ECSPI2_ROOT_CG] = imx_clk_hw_gate3("ecspi2_cg", "ecspi2_src", base + 0xb380, 28);
+       hws[IMX7D_ECSPI3_ROOT_CG] = imx_clk_hw_gate3("ecspi3_cg", "ecspi3_src", base + 0xb400, 28);
+       hws[IMX7D_ECSPI4_ROOT_CG] = imx_clk_hw_gate3("ecspi4_cg", "ecspi4_src", base + 0xb480, 28);
+       hws[IMX7D_PWM1_ROOT_CG] = imx_clk_hw_gate3("pwm1_cg", "pwm1_src", base + 0xb500, 28);
+       hws[IMX7D_PWM2_ROOT_CG] = imx_clk_hw_gate3("pwm2_cg", "pwm2_src", base + 0xb580, 28);
+       hws[IMX7D_PWM3_ROOT_CG] = imx_clk_hw_gate3("pwm3_cg", "pwm3_src", base + 0xb600, 28);
+       hws[IMX7D_PWM4_ROOT_CG] = imx_clk_hw_gate3("pwm4_cg", "pwm4_src", base + 0xb680, 28);
+       hws[IMX7D_FLEXTIMER1_ROOT_CG] = imx_clk_hw_gate3("flextimer1_cg", "flextimer1_src", base + 0xb700, 28);
+       hws[IMX7D_FLEXTIMER2_ROOT_CG] = imx_clk_hw_gate3("flextimer2_cg", "flextimer2_src", base + 0xb780, 28);
+       hws[IMX7D_SIM1_ROOT_CG] = imx_clk_hw_gate3("sim1_cg", "sim1_src", base + 0xb800, 28);
+       hws[IMX7D_SIM2_ROOT_CG] = imx_clk_hw_gate3("sim2_cg", "sim2_src", base + 0xb880, 28);
+       hws[IMX7D_GPT1_ROOT_CG] = imx_clk_hw_gate3("gpt1_cg", "gpt1_src", base + 0xb900, 28);
+       hws[IMX7D_GPT2_ROOT_CG] = imx_clk_hw_gate3("gpt2_cg", "gpt2_src", base + 0xb980, 28);
+       hws[IMX7D_GPT3_ROOT_CG] = imx_clk_hw_gate3("gpt3_cg", "gpt3_src", base + 0xbA00, 28);
+       hws[IMX7D_GPT4_ROOT_CG] = imx_clk_hw_gate3("gpt4_cg", "gpt4_src", base + 0xbA80, 28);
+       hws[IMX7D_TRACE_ROOT_CG] = imx_clk_hw_gate3("trace_cg", "trace_src", base + 0xbb00, 28);
+       hws[IMX7D_WDOG_ROOT_CG] = imx_clk_hw_gate3("wdog_cg", "wdog_src", base + 0xbb80, 28);
+       hws[IMX7D_CSI_MCLK_ROOT_CG] = imx_clk_hw_gate3("csi_mclk_cg", "csi_mclk_src", base + 0xbc00, 28);
+       hws[IMX7D_AUDIO_MCLK_ROOT_CG] = imx_clk_hw_gate3("audio_mclk_cg", "audio_mclk_src", base + 0xbc80, 28);
+       hws[IMX7D_WRCLK_ROOT_CG] = imx_clk_hw_gate3("wrclk_cg", "wrclk_src", base + 0xbd00, 28);
+       hws[IMX7D_CLKO1_ROOT_CG] = imx_clk_hw_gate3("clko1_cg", "clko1_src", base + 0xbd80, 28);
+       hws[IMX7D_CLKO2_ROOT_CG] = imx_clk_hw_gate3("clko2_cg", "clko2_src", base + 0xbe00, 28);
+
+       hws[IMX7D_MAIN_AXI_ROOT_PRE_DIV] = imx_clk_hw_divider2("axi_pre_div", "axi_cg", base + 0x8800, 16, 3);
+       hws[IMX7D_DISP_AXI_ROOT_PRE_DIV] = imx_clk_hw_divider2("disp_axi_pre_div", "disp_axi_cg", base + 0x8880, 16, 3);
+       hws[IMX7D_ENET_AXI_ROOT_PRE_DIV] = imx_clk_hw_divider2("enet_axi_pre_div", "enet_axi_cg", base + 0x8900, 16, 3);
+       hws[IMX7D_NAND_USDHC_BUS_ROOT_PRE_DIV] = imx_clk_hw_divider2("nand_usdhc_pre_div", "nand_usdhc_cg", base + 0x8980, 16, 3);
+       hws[IMX7D_AHB_CHANNEL_ROOT_PRE_DIV] = imx_clk_hw_divider2("ahb_pre_div", "ahb_cg", base + 0x9000, 16, 3);
+       hws[IMX7D_DRAM_PHYM_ALT_ROOT_PRE_DIV] = imx_clk_hw_divider2("dram_phym_alt_pre_div", "dram_phym_alt_cg", base + 0xa000, 16, 3);
+       hws[IMX7D_DRAM_ALT_ROOT_PRE_DIV] = imx_clk_hw_divider2("dram_alt_pre_div", "dram_alt_cg", base + 0xa080, 16, 3);
+       hws[IMX7D_USB_HSIC_ROOT_PRE_DIV] = imx_clk_hw_divider2("usb_hsic_pre_div", "usb_hsic_cg", base + 0xa100, 16, 3);
+       hws[IMX7D_PCIE_CTRL_ROOT_PRE_DIV] = imx_clk_hw_divider2("pcie_ctrl_pre_div", "pcie_ctrl_cg", base + 0xa180, 16, 3);
+       hws[IMX7D_PCIE_PHY_ROOT_PRE_DIV] = imx_clk_hw_divider2("pcie_phy_pre_div", "pcie_phy_cg", base + 0xa200, 16, 3);
+       hws[IMX7D_EPDC_PIXEL_ROOT_PRE_DIV] = imx_clk_hw_divider2("epdc_pixel_pre_div", "epdc_pixel_cg", base + 0xa280, 16, 3);
+       hws[IMX7D_LCDIF_PIXEL_ROOT_PRE_DIV] = imx_clk_hw_divider2("lcdif_pixel_pre_div", "lcdif_pixel_cg", base + 0xa300, 16, 3);
+       hws[IMX7D_MIPI_DSI_ROOT_PRE_DIV] = imx_clk_hw_divider2("mipi_dsi_pre_div", "mipi_dsi_cg", base + 0xa380, 16, 3);
+       hws[IMX7D_MIPI_CSI_ROOT_PRE_DIV] = imx_clk_hw_divider2("mipi_csi_pre_div", "mipi_csi_cg", base + 0xa400, 16, 3);
+       hws[IMX7D_MIPI_DPHY_ROOT_PRE_DIV] = imx_clk_hw_divider2("mipi_dphy_pre_div", "mipi_dphy_cg", base + 0xa480, 16, 3);
+       hws[IMX7D_SAI1_ROOT_PRE_DIV] = imx_clk_hw_divider2("sai1_pre_div", "sai1_cg", base + 0xa500, 16, 3);
+       hws[IMX7D_SAI2_ROOT_PRE_DIV] = imx_clk_hw_divider2("sai2_pre_div", "sai2_cg", base + 0xa580, 16, 3);
+       hws[IMX7D_SAI3_ROOT_PRE_DIV] = imx_clk_hw_divider2("sai3_pre_div", "sai3_cg", base + 0xa600, 16, 3);
+       hws[IMX7D_SPDIF_ROOT_PRE_DIV] = imx_clk_hw_divider2("spdif_pre_div", "spdif_cg", base + 0xa680, 16, 3);
+       hws[IMX7D_ENET1_REF_ROOT_PRE_DIV] = imx_clk_hw_divider2("enet1_ref_pre_div", "enet1_ref_cg", base + 0xa700, 16, 3);
+       hws[IMX7D_ENET1_TIME_ROOT_PRE_DIV] = imx_clk_hw_divider2("enet1_time_pre_div", "enet1_time_cg", base + 0xa780, 16, 3);
+       hws[IMX7D_ENET2_REF_ROOT_PRE_DIV] = imx_clk_hw_divider2("enet2_ref_pre_div", "enet2_ref_cg", base + 0xa800, 16, 3);
+       hws[IMX7D_ENET2_TIME_ROOT_PRE_DIV] = imx_clk_hw_divider2("enet2_time_pre_div", "enet2_time_cg", base + 0xa880, 16, 3);
+       hws[IMX7D_ENET_PHY_REF_ROOT_PRE_DIV] = imx_clk_hw_divider2("enet_phy_ref_pre_div", "enet_phy_ref_cg", base + 0xa900, 16, 3);
+       hws[IMX7D_EIM_ROOT_PRE_DIV] = imx_clk_hw_divider2("eim_pre_div", "eim_cg", base + 0xa980, 16, 3);
+       hws[IMX7D_NAND_ROOT_PRE_DIV] = imx_clk_hw_divider2("nand_pre_div", "nand_cg", base + 0xaa00, 16, 3);
+       hws[IMX7D_QSPI_ROOT_PRE_DIV] = imx_clk_hw_divider2("qspi_pre_div", "qspi_cg", base + 0xaa80, 16, 3);
+       hws[IMX7D_USDHC1_ROOT_PRE_DIV] = imx_clk_hw_divider2("usdhc1_pre_div", "usdhc1_cg", base + 0xab00, 16, 3);
+       hws[IMX7D_USDHC2_ROOT_PRE_DIV] = imx_clk_hw_divider2("usdhc2_pre_div", "usdhc2_cg", base + 0xab80, 16, 3);
+       hws[IMX7D_USDHC3_ROOT_PRE_DIV] = imx_clk_hw_divider2("usdhc3_pre_div", "usdhc3_cg", base + 0xac00, 16, 3);
+       hws[IMX7D_CAN1_ROOT_PRE_DIV] = imx_clk_hw_divider2("can1_pre_div", "can1_cg", base + 0xac80, 16, 3);
+       hws[IMX7D_CAN2_ROOT_PRE_DIV] = imx_clk_hw_divider2("can2_pre_div", "can2_cg", base + 0xad00, 16, 3);
+       hws[IMX7D_I2C1_ROOT_PRE_DIV] = imx_clk_hw_divider2("i2c1_pre_div", "i2c1_cg", base + 0xad80, 16, 3);
+       hws[IMX7D_I2C2_ROOT_PRE_DIV] = imx_clk_hw_divider2("i2c2_pre_div", "i2c2_cg", base + 0xae00, 16, 3);
+       hws[IMX7D_I2C3_ROOT_PRE_DIV] = imx_clk_hw_divider2("i2c3_pre_div", "i2c3_cg", base + 0xae80, 16, 3);
+       hws[IMX7D_I2C4_ROOT_PRE_DIV] = imx_clk_hw_divider2("i2c4_pre_div", "i2c4_cg", base + 0xaf00, 16, 3);
+       hws[IMX7D_UART1_ROOT_PRE_DIV] = imx_clk_hw_divider2("uart1_pre_div", "uart1_cg", base + 0xaf80, 16, 3);
+       hws[IMX7D_UART2_ROOT_PRE_DIV] = imx_clk_hw_divider2("uart2_pre_div", "uart2_cg", base + 0xb000, 16, 3);
+       hws[IMX7D_UART3_ROOT_PRE_DIV] = imx_clk_hw_divider2("uart3_pre_div", "uart3_cg", base + 0xb080, 16, 3);
+       hws[IMX7D_UART4_ROOT_PRE_DIV] = imx_clk_hw_divider2("uart4_pre_div", "uart4_cg", base + 0xb100, 16, 3);
+       hws[IMX7D_UART5_ROOT_PRE_DIV] = imx_clk_hw_divider2("uart5_pre_div", "uart5_cg", base + 0xb180, 16, 3);
+       hws[IMX7D_UART6_ROOT_PRE_DIV] = imx_clk_hw_divider2("uart6_pre_div", "uart6_cg", base + 0xb200, 16, 3);
+       hws[IMX7D_UART7_ROOT_PRE_DIV] = imx_clk_hw_divider2("uart7_pre_div", "uart7_cg", base + 0xb280, 16, 3);
+       hws[IMX7D_ECSPI1_ROOT_PRE_DIV] = imx_clk_hw_divider2("ecspi1_pre_div", "ecspi1_cg", base + 0xb300, 16, 3);
+       hws[IMX7D_ECSPI2_ROOT_PRE_DIV] = imx_clk_hw_divider2("ecspi2_pre_div", "ecspi2_cg", base + 0xb380, 16, 3);
+       hws[IMX7D_ECSPI3_ROOT_PRE_DIV] = imx_clk_hw_divider2("ecspi3_pre_div", "ecspi3_cg", base + 0xb400, 16, 3);
+       hws[IMX7D_ECSPI4_ROOT_PRE_DIV] = imx_clk_hw_divider2("ecspi4_pre_div", "ecspi4_cg", base + 0xb480, 16, 3);
+       hws[IMX7D_PWM1_ROOT_PRE_DIV] = imx_clk_hw_divider2("pwm1_pre_div", "pwm1_cg", base + 0xb500, 16, 3);
+       hws[IMX7D_PWM2_ROOT_PRE_DIV] = imx_clk_hw_divider2("pwm2_pre_div", "pwm2_cg", base + 0xb580, 16, 3);
+       hws[IMX7D_PWM3_ROOT_PRE_DIV] = imx_clk_hw_divider2("pwm3_pre_div", "pwm3_cg", base + 0xb600, 16, 3);
+       hws[IMX7D_PWM4_ROOT_PRE_DIV] = imx_clk_hw_divider2("pwm4_pre_div", "pwm4_cg", base + 0xb680, 16, 3);
+       hws[IMX7D_FLEXTIMER1_ROOT_PRE_DIV] = imx_clk_hw_divider2("flextimer1_pre_div", "flextimer1_cg", base + 0xb700, 16, 3);
+       hws[IMX7D_FLEXTIMER2_ROOT_PRE_DIV] = imx_clk_hw_divider2("flextimer2_pre_div", "flextimer2_cg", base + 0xb780, 16, 3);
+       hws[IMX7D_SIM1_ROOT_PRE_DIV] = imx_clk_hw_divider2("sim1_pre_div", "sim1_cg", base + 0xb800, 16, 3);
+       hws[IMX7D_SIM2_ROOT_PRE_DIV] = imx_clk_hw_divider2("sim2_pre_div", "sim2_cg", base + 0xb880, 16, 3);
+       hws[IMX7D_GPT1_ROOT_PRE_DIV] = imx_clk_hw_divider2("gpt1_pre_div", "gpt1_cg", base + 0xb900, 16, 3);
+       hws[IMX7D_GPT2_ROOT_PRE_DIV] = imx_clk_hw_divider2("gpt2_pre_div", "gpt2_cg", base + 0xb980, 16, 3);
+       hws[IMX7D_GPT3_ROOT_PRE_DIV] = imx_clk_hw_divider2("gpt3_pre_div", "gpt3_cg", base + 0xba00, 16, 3);
+       hws[IMX7D_GPT4_ROOT_PRE_DIV] = imx_clk_hw_divider2("gpt4_pre_div", "gpt4_cg", base + 0xba80, 16, 3);
+       hws[IMX7D_TRACE_ROOT_PRE_DIV] = imx_clk_hw_divider2("trace_pre_div", "trace_cg", base + 0xbb00, 16, 3);
+       hws[IMX7D_WDOG_ROOT_PRE_DIV] = imx_clk_hw_divider2("wdog_pre_div", "wdog_cg", base + 0xbb80, 16, 3);
+       hws[IMX7D_CSI_MCLK_ROOT_PRE_DIV] = imx_clk_hw_divider2("csi_mclk_pre_div", "csi_mclk_cg", base + 0xbc00, 16, 3);
+       hws[IMX7D_AUDIO_MCLK_ROOT_PRE_DIV] = imx_clk_hw_divider2("audio_mclk_pre_div", "audio_mclk_cg", base + 0xbc80, 16, 3);
+       hws[IMX7D_WRCLK_ROOT_PRE_DIV] = imx_clk_hw_divider2("wrclk_pre_div", "wrclk_cg", base + 0xbd00, 16, 3);
+       hws[IMX7D_CLKO1_ROOT_PRE_DIV] = imx_clk_hw_divider2("clko1_pre_div", "clko1_cg", base + 0xbd80, 16, 3);
+       hws[IMX7D_CLKO2_ROOT_PRE_DIV] = imx_clk_hw_divider2("clko2_pre_div", "clko2_cg", base + 0xbe00, 16, 3);
+
+       hws[IMX7D_ARM_A7_ROOT_DIV] = imx_clk_hw_divider2("arm_a7_div", "arm_a7_cg", base + 0x8000, 0, 3);
+       hws[IMX7D_ARM_M4_ROOT_DIV] = imx_clk_hw_divider2("arm_m4_div", "arm_m4_cg", base + 0x8080, 0, 3);
+       hws[IMX7D_MAIN_AXI_ROOT_DIV] = imx_clk_hw_divider2("axi_post_div", "axi_pre_div", base + 0x8800, 0, 6);
+       hws[IMX7D_DISP_AXI_ROOT_DIV] = imx_clk_hw_divider2("disp_axi_post_div", "disp_axi_pre_div", base + 0x8880, 0, 6);
+       hws[IMX7D_ENET_AXI_ROOT_DIV] = imx_clk_hw_divider2("enet_axi_post_div", "enet_axi_pre_div", base + 0x8900, 0, 6);
+       hws[IMX7D_NAND_USDHC_BUS_ROOT_CLK] = imx_clk_hw_divider2("nand_usdhc_root_clk", "nand_usdhc_pre_div", base + 0x8980, 0, 6);
+       hws[IMX7D_AHB_CHANNEL_ROOT_DIV] = imx_clk_hw_divider2("ahb_root_clk", "ahb_pre_div", base + 0x9000, 0, 6);
+       hws[IMX7D_IPG_ROOT_CLK] = imx_clk_hw_divider_flags("ipg_root_clk", "ahb_root_clk", base + 0x9080, 0, 2, CLK_IS_CRITICAL | CLK_OPS_PARENT_ENABLE | CLK_SET_RATE_PARENT);
+       hws[IMX7D_DRAM_ROOT_DIV] = imx_clk_hw_divider2("dram_post_div", "dram_cg", base + 0x9880, 0, 3);
+       hws[IMX7D_DRAM_PHYM_ALT_ROOT_DIV] = imx_clk_hw_divider2("dram_phym_alt_post_div", "dram_phym_alt_pre_div", base + 0xa000, 0, 3);
+       hws[IMX7D_DRAM_ALT_ROOT_DIV] = imx_clk_hw_divider2("dram_alt_post_div", "dram_alt_pre_div", base + 0xa080, 0, 3);
+       hws[IMX7D_USB_HSIC_ROOT_DIV] = imx_clk_hw_divider2("usb_hsic_post_div", "usb_hsic_pre_div", base + 0xa100, 0, 6);
+       hws[IMX7D_PCIE_CTRL_ROOT_DIV] = imx_clk_hw_divider2("pcie_ctrl_post_div", "pcie_ctrl_pre_div", base + 0xa180, 0, 6);
+       hws[IMX7D_PCIE_PHY_ROOT_DIV] = imx_clk_hw_divider2("pcie_phy_post_div", "pcie_phy_pre_div", base + 0xa200, 0, 6);
+       hws[IMX7D_EPDC_PIXEL_ROOT_DIV] = imx_clk_hw_divider2("epdc_pixel_post_div", "epdc_pixel_pre_div", base + 0xa280, 0, 6);
+       hws[IMX7D_LCDIF_PIXEL_ROOT_DIV] = imx_clk_hw_divider2("lcdif_pixel_post_div", "lcdif_pixel_pre_div", base + 0xa300, 0, 6);
+       hws[IMX7D_MIPI_DSI_ROOT_DIV] = imx_clk_hw_divider2("mipi_dsi_post_div", "mipi_dsi_pre_div", base + 0xa380, 0, 6);
+       hws[IMX7D_MIPI_CSI_ROOT_DIV] = imx_clk_hw_divider2("mipi_csi_post_div", "mipi_csi_pre_div", base + 0xa400, 0, 6);
+       hws[IMX7D_MIPI_DPHY_ROOT_DIV] = imx_clk_hw_divider2("mipi_dphy_post_div", "mipi_dphy_pre_div", base + 0xa480, 0, 6);
+       hws[IMX7D_SAI1_ROOT_DIV] = imx_clk_hw_divider2("sai1_post_div", "sai1_pre_div", base + 0xa500, 0, 6);
+       hws[IMX7D_SAI2_ROOT_DIV] = imx_clk_hw_divider2("sai2_post_div", "sai2_pre_div", base + 0xa580, 0, 6);
+       hws[IMX7D_SAI3_ROOT_DIV] = imx_clk_hw_divider2("sai3_post_div", "sai3_pre_div", base + 0xa600, 0, 6);
+       hws[IMX7D_SPDIF_ROOT_DIV] = imx_clk_hw_divider2("spdif_post_div", "spdif_pre_div", base + 0xa680, 0, 6);
+       hws[IMX7D_ENET1_REF_ROOT_DIV] = imx_clk_hw_divider2("enet1_ref_post_div", "enet1_ref_pre_div", base + 0xa700, 0, 6);
+       hws[IMX7D_ENET1_TIME_ROOT_DIV] = imx_clk_hw_divider2("enet1_time_post_div", "enet1_time_pre_div", base + 0xa780, 0, 6);
+       hws[IMX7D_ENET2_REF_ROOT_DIV] = imx_clk_hw_divider2("enet2_ref_post_div", "enet2_ref_pre_div", base + 0xa800, 0, 6);
+       hws[IMX7D_ENET2_TIME_ROOT_DIV] = imx_clk_hw_divider2("enet2_time_post_div", "enet2_time_pre_div", base + 0xa880, 0, 6);
+       hws[IMX7D_ENET_PHY_REF_ROOT_CLK] = imx_clk_hw_divider2("enet_phy_ref_root_clk", "enet_phy_ref_pre_div", base + 0xa900, 0, 6);
+       hws[IMX7D_EIM_ROOT_DIV] = imx_clk_hw_divider2("eim_post_div", "eim_pre_div", base + 0xa980, 0, 6);
+       hws[IMX7D_NAND_ROOT_CLK] = imx_clk_hw_divider2("nand_root_clk", "nand_pre_div", base + 0xaa00, 0, 6);
+       hws[IMX7D_QSPI_ROOT_DIV] = imx_clk_hw_divider2("qspi_post_div", "qspi_pre_div", base + 0xaa80, 0, 6);
+       hws[IMX7D_USDHC1_ROOT_DIV] = imx_clk_hw_divider2("usdhc1_post_div", "usdhc1_pre_div", base + 0xab00, 0, 6);
+       hws[IMX7D_USDHC2_ROOT_DIV] = imx_clk_hw_divider2("usdhc2_post_div", "usdhc2_pre_div", base + 0xab80, 0, 6);
+       hws[IMX7D_USDHC3_ROOT_DIV] = imx_clk_hw_divider2("usdhc3_post_div", "usdhc3_pre_div", base + 0xac00, 0, 6);
+       hws[IMX7D_CAN1_ROOT_DIV] = imx_clk_hw_divider2("can1_post_div", "can1_pre_div", base + 0xac80, 0, 6);
+       hws[IMX7D_CAN2_ROOT_DIV] = imx_clk_hw_divider2("can2_post_div", "can2_pre_div", base + 0xad00, 0, 6);
+       hws[IMX7D_I2C1_ROOT_DIV] = imx_clk_hw_divider2("i2c1_post_div", "i2c1_pre_div", base + 0xad80, 0, 6);
+       hws[IMX7D_I2C2_ROOT_DIV] = imx_clk_hw_divider2("i2c2_post_div", "i2c2_pre_div", base + 0xae00, 0, 6);
+       hws[IMX7D_I2C3_ROOT_DIV] = imx_clk_hw_divider2("i2c3_post_div", "i2c3_pre_div", base + 0xae80, 0, 6);
+       hws[IMX7D_I2C4_ROOT_DIV] = imx_clk_hw_divider2("i2c4_post_div", "i2c4_pre_div", base + 0xaf00, 0, 6);
+       hws[IMX7D_UART1_ROOT_DIV] = imx_clk_hw_divider2("uart1_post_div", "uart1_pre_div", base + 0xaf80, 0, 6);
+       hws[IMX7D_UART2_ROOT_DIV] = imx_clk_hw_divider2("uart2_post_div", "uart2_pre_div", base + 0xb000, 0, 6);
+       hws[IMX7D_UART3_ROOT_DIV] = imx_clk_hw_divider2("uart3_post_div", "uart3_pre_div", base + 0xb080, 0, 6);
+       hws[IMX7D_UART4_ROOT_DIV] = imx_clk_hw_divider2("uart4_post_div", "uart4_pre_div", base + 0xb100, 0, 6);
+       hws[IMX7D_UART5_ROOT_DIV] = imx_clk_hw_divider2("uart5_post_div", "uart5_pre_div", base + 0xb180, 0, 6);
+       hws[IMX7D_UART6_ROOT_DIV] = imx_clk_hw_divider2("uart6_post_div", "uart6_pre_div", base + 0xb200, 0, 6);
+       hws[IMX7D_UART7_ROOT_DIV] = imx_clk_hw_divider2("uart7_post_div", "uart7_pre_div", base + 0xb280, 0, 6);
+       hws[IMX7D_ECSPI1_ROOT_DIV] = imx_clk_hw_divider2("ecspi1_post_div", "ecspi1_pre_div", base + 0xb300, 0, 6);
+       hws[IMX7D_ECSPI2_ROOT_DIV] = imx_clk_hw_divider2("ecspi2_post_div", "ecspi2_pre_div", base + 0xb380, 0, 6);
+       hws[IMX7D_ECSPI3_ROOT_DIV] = imx_clk_hw_divider2("ecspi3_post_div", "ecspi3_pre_div", base + 0xb400, 0, 6);
+       hws[IMX7D_ECSPI4_ROOT_DIV] = imx_clk_hw_divider2("ecspi4_post_div", "ecspi4_pre_div", base + 0xb480, 0, 6);
+       hws[IMX7D_PWM1_ROOT_DIV] = imx_clk_hw_divider2("pwm1_post_div", "pwm1_pre_div", base + 0xb500, 0, 6);
+       hws[IMX7D_PWM2_ROOT_DIV] = imx_clk_hw_divider2("pwm2_post_div", "pwm2_pre_div", base + 0xb580, 0, 6);
+       hws[IMX7D_PWM3_ROOT_DIV] = imx_clk_hw_divider2("pwm3_post_div", "pwm3_pre_div", base + 0xb600, 0, 6);
+       hws[IMX7D_PWM4_ROOT_DIV] = imx_clk_hw_divider2("pwm4_post_div", "pwm4_pre_div", base + 0xb680, 0, 6);
+       hws[IMX7D_FLEXTIMER1_ROOT_DIV] = imx_clk_hw_divider2("flextimer1_post_div", "flextimer1_pre_div", base + 0xb700, 0, 6);
+       hws[IMX7D_FLEXTIMER2_ROOT_DIV] = imx_clk_hw_divider2("flextimer2_post_div", "flextimer2_pre_div", base + 0xb780, 0, 6);
+       hws[IMX7D_SIM1_ROOT_DIV] = imx_clk_hw_divider2("sim1_post_div", "sim1_pre_div", base + 0xb800, 0, 6);
+       hws[IMX7D_SIM2_ROOT_DIV] = imx_clk_hw_divider2("sim2_post_div", "sim2_pre_div", base + 0xb880, 0, 6);
+       hws[IMX7D_GPT1_ROOT_DIV] = imx_clk_hw_divider2("gpt1_post_div", "gpt1_pre_div", base + 0xb900, 0, 6);
+       hws[IMX7D_GPT2_ROOT_DIV] = imx_clk_hw_divider2("gpt2_post_div", "gpt2_pre_div", base + 0xb980, 0, 6);
+       hws[IMX7D_GPT3_ROOT_DIV] = imx_clk_hw_divider2("gpt3_post_div", "gpt3_pre_div", base + 0xba00, 0, 6);
+       hws[IMX7D_GPT4_ROOT_DIV] = imx_clk_hw_divider2("gpt4_post_div", "gpt4_pre_div", base + 0xba80, 0, 6);
+       hws[IMX7D_TRACE_ROOT_DIV] = imx_clk_hw_divider2("trace_post_div", "trace_pre_div", base + 0xbb00, 0, 6);
+       hws[IMX7D_WDOG_ROOT_DIV] = imx_clk_hw_divider2("wdog_post_div", "wdog_pre_div", base + 0xbb80, 0, 6);
+       hws[IMX7D_CSI_MCLK_ROOT_DIV] = imx_clk_hw_divider2("csi_mclk_post_div", "csi_mclk_pre_div", base + 0xbc00, 0, 6);
+       hws[IMX7D_AUDIO_MCLK_ROOT_DIV] = imx_clk_hw_divider2("audio_mclk_post_div", "audio_mclk_pre_div", base + 0xbc80, 0, 6);
+       hws[IMX7D_WRCLK_ROOT_DIV] = imx_clk_hw_divider2("wrclk_post_div", "wrclk_pre_div", base + 0xbd00, 0, 6);
+       hws[IMX7D_CLKO1_ROOT_DIV] = imx_clk_hw_divider2("clko1_post_div", "clko1_pre_div", base + 0xbd80, 0, 6);
+       hws[IMX7D_CLKO2_ROOT_DIV] = imx_clk_hw_divider2("clko2_post_div", "clko2_pre_div", base + 0xbe00, 0, 6);
+
+       hws[IMX7D_ARM_A7_ROOT_CLK] = imx_clk_hw_gate2_flags("arm_a7_root_clk", "arm_a7_div", base + 0x4000, 0, CLK_OPS_PARENT_ENABLE);
+       hws[IMX7D_ARM_M4_ROOT_CLK] = imx_clk_hw_gate4("arm_m4_root_clk", "arm_m4_div", base + 0x4010, 0);
+       hws[IMX7D_MAIN_AXI_ROOT_CLK] = imx_clk_hw_gate2_flags("main_axi_root_clk", "axi_post_div", base + 0x4040, 0, CLK_IS_CRITICAL | CLK_OPS_PARENT_ENABLE);
+       hws[IMX7D_DISP_AXI_ROOT_CLK] = imx_clk_hw_gate4("disp_axi_root_clk", "disp_axi_post_div", base + 0x4050, 0);
+       hws[IMX7D_ENET_AXI_ROOT_CLK] = imx_clk_hw_gate4("enet_axi_root_clk", "enet_axi_post_div", base + 0x4060, 0);
+       hws[IMX7D_OCRAM_CLK] = imx_clk_hw_gate4("ocram_clk", "main_axi_root_clk", base + 0x4110, 0);
+       hws[IMX7D_OCRAM_S_CLK] = imx_clk_hw_gate4("ocram_s_clk", "ahb_root_clk", base + 0x4120, 0);
+       hws[IMX7D_DRAM_ROOT_CLK] = imx_clk_hw_gate2_flags("dram_root_clk", "dram_post_div", base + 0x4130, 0, CLK_IS_CRITICAL | CLK_OPS_PARENT_ENABLE);
+       hws[IMX7D_DRAM_PHYM_ROOT_CLK] = imx_clk_hw_gate2_flags("dram_phym_root_clk", "dram_phym_cg", base + 0x4130, 0, CLK_IS_CRITICAL | CLK_OPS_PARENT_ENABLE);
+       hws[IMX7D_DRAM_PHYM_ALT_ROOT_CLK] = imx_clk_hw_gate2_flags("dram_phym_alt_root_clk", "dram_phym_alt_post_div", base + 0x4130, 0, CLK_IS_CRITICAL | CLK_OPS_PARENT_ENABLE);
+       hws[IMX7D_DRAM_ALT_ROOT_CLK] = imx_clk_hw_gate2_flags("dram_alt_root_clk", "dram_alt_post_div", base + 0x4130, 0, CLK_IS_CRITICAL | CLK_OPS_PARENT_ENABLE);
+       hws[IMX7D_OCOTP_CLK] = imx_clk_hw_gate4("ocotp_clk", "ipg_root_clk", base + 0x4230, 0);
+       hws[IMX7D_SNVS_CLK] = imx_clk_hw_gate4("snvs_clk", "ipg_root_clk", base + 0x4250, 0);
+       hws[IMX7D_MU_ROOT_CLK] = imx_clk_hw_gate4("mu_root_clk", "ipg_root_clk", base + 0x4270, 0);
+       hws[IMX7D_CAAM_CLK] = imx_clk_hw_gate4("caam_clk", "ipg_root_clk", base + 0x4240, 0);
+       hws[IMX7D_USB_HSIC_ROOT_CLK] = imx_clk_hw_gate4("usb_hsic_root_clk", "usb_hsic_post_div", base + 0x4690, 0);
+       hws[IMX7D_SDMA_CORE_CLK] = imx_clk_hw_gate4("sdma_root_clk", "ahb_root_clk", base + 0x4480, 0);
+       hws[IMX7D_PCIE_CTRL_ROOT_CLK] = imx_clk_hw_gate4("pcie_ctrl_root_clk", "pcie_ctrl_post_div", base + 0x4600, 0);
+       hws[IMX7D_PCIE_PHY_ROOT_CLK] = imx_clk_hw_gate4("pcie_phy_root_clk", "pcie_phy_post_div", base + 0x4600, 0);
+       hws[IMX7D_EPDC_PIXEL_ROOT_CLK] = imx_clk_hw_gate4("epdc_pixel_root_clk", "epdc_pixel_post_div", base + 0x44a0, 0);
+       hws[IMX7D_LCDIF_PIXEL_ROOT_CLK] = imx_clk_hw_gate4("lcdif_pixel_root_clk", "lcdif_pixel_post_div", base + 0x44b0, 0);
+       hws[IMX7D_MIPI_DSI_ROOT_CLK] = imx_clk_hw_gate4("mipi_dsi_root_clk", "mipi_dsi_post_div", base + 0x4650, 0);
+       hws[IMX7D_MIPI_CSI_ROOT_CLK] = imx_clk_hw_gate4("mipi_csi_root_clk", "mipi_csi_post_div", base + 0x4640, 0);
+       hws[IMX7D_MIPI_DPHY_ROOT_CLK] = imx_clk_hw_gate4("mipi_dphy_root_clk", "mipi_dphy_post_div", base + 0x4660, 0);
+       hws[IMX7D_ENET1_IPG_ROOT_CLK] = imx_clk_hw_gate2_shared2("enet1_ipg_root_clk", "enet_axi_post_div", base + 0x4700, 0, &share_count_enet1);
+       hws[IMX7D_ENET1_TIME_ROOT_CLK] = imx_clk_hw_gate2_shared2("enet1_time_root_clk", "enet1_time_post_div", base + 0x4700, 0, &share_count_enet1);
+       hws[IMX7D_ENET2_IPG_ROOT_CLK] = imx_clk_hw_gate2_shared2("enet2_ipg_root_clk", "enet_axi_post_div", base + 0x4710, 0, &share_count_enet2);
+       hws[IMX7D_ENET2_TIME_ROOT_CLK] = imx_clk_hw_gate2_shared2("enet2_time_root_clk", "enet2_time_post_div", base + 0x4710, 0, &share_count_enet2);
+       hws[IMX7D_SAI1_ROOT_CLK] = imx_clk_hw_gate2_shared2("sai1_root_clk", "sai1_post_div", base + 0x48c0, 0, &share_count_sai1);
+       hws[IMX7D_SAI1_IPG_CLK]  = imx_clk_hw_gate2_shared2("sai1_ipg_clk",  "ipg_root_clk",  base + 0x48c0, 0, &share_count_sai1);
+       hws[IMX7D_SAI2_ROOT_CLK] = imx_clk_hw_gate2_shared2("sai2_root_clk", "sai2_post_div", base + 0x48d0, 0, &share_count_sai2);
+       hws[IMX7D_SAI2_IPG_CLK]  = imx_clk_hw_gate2_shared2("sai2_ipg_clk",  "ipg_root_clk",  base + 0x48d0, 0, &share_count_sai2);
+       hws[IMX7D_SAI3_ROOT_CLK] = imx_clk_hw_gate2_shared2("sai3_root_clk", "sai3_post_div", base + 0x48e0, 0, &share_count_sai3);
+       hws[IMX7D_SAI3_IPG_CLK]  = imx_clk_hw_gate2_shared2("sai3_ipg_clk",  "ipg_root_clk",  base + 0x48e0, 0, &share_count_sai3);
+       hws[IMX7D_SPDIF_ROOT_CLK] = imx_clk_hw_gate4("spdif_root_clk", "spdif_post_div", base + 0x44d0, 0);
+       hws[IMX7D_EIM_ROOT_CLK] = imx_clk_hw_gate4("eim_root_clk", "eim_post_div", base + 0x4160, 0);
+       hws[IMX7D_NAND_RAWNAND_CLK] = imx_clk_hw_gate2_shared2("nand_rawnand_clk", "nand_root_clk", base + 0x4140, 0, &share_count_nand);
+       hws[IMX7D_NAND_USDHC_BUS_RAWNAND_CLK] = imx_clk_hw_gate2_shared2("nand_usdhc_rawnand_clk", "nand_usdhc_root_clk", base + 0x4140, 0, &share_count_nand);
+       hws[IMX7D_QSPI_ROOT_CLK] = imx_clk_hw_gate4("qspi_root_clk", "qspi_post_div", base + 0x4150, 0);
+       hws[IMX7D_USDHC1_ROOT_CLK] = imx_clk_hw_gate4("usdhc1_root_clk", "usdhc1_post_div", base + 0x46c0, 0);
+       hws[IMX7D_USDHC2_ROOT_CLK] = imx_clk_hw_gate4("usdhc2_root_clk", "usdhc2_post_div", base + 0x46d0, 0);
+       hws[IMX7D_USDHC3_ROOT_CLK] = imx_clk_hw_gate4("usdhc3_root_clk", "usdhc3_post_div", base + 0x46e0, 0);
+       hws[IMX7D_CAN1_ROOT_CLK] = imx_clk_hw_gate4("can1_root_clk", "can1_post_div", base + 0x4740, 0);
+       hws[IMX7D_CAN2_ROOT_CLK] = imx_clk_hw_gate4("can2_root_clk", "can2_post_div", base + 0x4750, 0);
+       hws[IMX7D_I2C1_ROOT_CLK] = imx_clk_hw_gate4("i2c1_root_clk", "i2c1_post_div", base + 0x4880, 0);
+       hws[IMX7D_I2C2_ROOT_CLK] = imx_clk_hw_gate4("i2c2_root_clk", "i2c2_post_div", base + 0x4890, 0);
+       hws[IMX7D_I2C3_ROOT_CLK] = imx_clk_hw_gate4("i2c3_root_clk", "i2c3_post_div", base + 0x48a0, 0);
+       hws[IMX7D_I2C4_ROOT_CLK] = imx_clk_hw_gate4("i2c4_root_clk", "i2c4_post_div", base + 0x48b0, 0);
+       hws[IMX7D_UART1_ROOT_CLK] = imx_clk_hw_gate4("uart1_root_clk", "uart1_post_div", base + 0x4940, 0);
+       hws[IMX7D_UART2_ROOT_CLK] = imx_clk_hw_gate4("uart2_root_clk", "uart2_post_div", base + 0x4950, 0);
+       hws[IMX7D_UART3_ROOT_CLK] = imx_clk_hw_gate4("uart3_root_clk", "uart3_post_div", base + 0x4960, 0);
+       hws[IMX7D_UART4_ROOT_CLK] = imx_clk_hw_gate4("uart4_root_clk", "uart4_post_div", base + 0x4970, 0);
+       hws[IMX7D_UART5_ROOT_CLK] = imx_clk_hw_gate4("uart5_root_clk", "uart5_post_div", base + 0x4980, 0);
+       hws[IMX7D_UART6_ROOT_CLK] = imx_clk_hw_gate4("uart6_root_clk", "uart6_post_div", base + 0x4990, 0);
+       hws[IMX7D_UART7_ROOT_CLK] = imx_clk_hw_gate4("uart7_root_clk", "uart7_post_div", base + 0x49a0, 0);
+       hws[IMX7D_ECSPI1_ROOT_CLK] = imx_clk_hw_gate4("ecspi1_root_clk", "ecspi1_post_div", base + 0x4780, 0);
+       hws[IMX7D_ECSPI2_ROOT_CLK] = imx_clk_hw_gate4("ecspi2_root_clk", "ecspi2_post_div", base + 0x4790, 0);
+       hws[IMX7D_ECSPI3_ROOT_CLK] = imx_clk_hw_gate4("ecspi3_root_clk", "ecspi3_post_div", base + 0x47a0, 0);
+       hws[IMX7D_ECSPI4_ROOT_CLK] = imx_clk_hw_gate4("ecspi4_root_clk", "ecspi4_post_div", base + 0x47b0, 0);
+       hws[IMX7D_PWM1_ROOT_CLK] = imx_clk_hw_gate4("pwm1_root_clk", "pwm1_post_div", base + 0x4840, 0);
+       hws[IMX7D_PWM2_ROOT_CLK] = imx_clk_hw_gate4("pwm2_root_clk", "pwm2_post_div", base + 0x4850, 0);
+       hws[IMX7D_PWM3_ROOT_CLK] = imx_clk_hw_gate4("pwm3_root_clk", "pwm3_post_div", base + 0x4860, 0);
+       hws[IMX7D_PWM4_ROOT_CLK] = imx_clk_hw_gate4("pwm4_root_clk", "pwm4_post_div", base + 0x4870, 0);
+       hws[IMX7D_FLEXTIMER1_ROOT_CLK] = imx_clk_hw_gate4("flextimer1_root_clk", "flextimer1_post_div", base + 0x4800, 0);
+       hws[IMX7D_FLEXTIMER2_ROOT_CLK] = imx_clk_hw_gate4("flextimer2_root_clk", "flextimer2_post_div", base + 0x4810, 0);
+       hws[IMX7D_SIM1_ROOT_CLK] = imx_clk_hw_gate4("sim1_root_clk", "sim1_post_div", base + 0x4900, 0);
+       hws[IMX7D_SIM2_ROOT_CLK] = imx_clk_hw_gate4("sim2_root_clk", "sim2_post_div", base + 0x4910, 0);
+       hws[IMX7D_GPT1_ROOT_CLK] = imx_clk_hw_gate4("gpt1_root_clk", "gpt1_post_div", base + 0x47c0, 0);
+       hws[IMX7D_GPT2_ROOT_CLK] = imx_clk_hw_gate4("gpt2_root_clk", "gpt2_post_div", base + 0x47d0, 0);
+       hws[IMX7D_GPT3_ROOT_CLK] = imx_clk_hw_gate4("gpt3_root_clk", "gpt3_post_div", base + 0x47e0, 0);
+       hws[IMX7D_GPT4_ROOT_CLK] = imx_clk_hw_gate4("gpt4_root_clk", "gpt4_post_div", base + 0x47f0, 0);
+       hws[IMX7D_TRACE_ROOT_CLK] = imx_clk_hw_gate4("trace_root_clk", "trace_post_div", base + 0x4300, 0);
+       hws[IMX7D_WDOG1_ROOT_CLK] = imx_clk_hw_gate4("wdog1_root_clk", "wdog_post_div", base + 0x49c0, 0);
+       hws[IMX7D_WDOG2_ROOT_CLK] = imx_clk_hw_gate4("wdog2_root_clk", "wdog_post_div", base + 0x49d0, 0);
+       hws[IMX7D_WDOG3_ROOT_CLK] = imx_clk_hw_gate4("wdog3_root_clk", "wdog_post_div", base + 0x49e0, 0);
+       hws[IMX7D_WDOG4_ROOT_CLK] = imx_clk_hw_gate4("wdog4_root_clk", "wdog_post_div", base + 0x49f0, 0);
+       hws[IMX7D_KPP_ROOT_CLK] = imx_clk_hw_gate4("kpp_root_clk", "ipg_root_clk", base + 0x4aa0, 0);
+       hws[IMX7D_CSI_MCLK_ROOT_CLK] = imx_clk_hw_gate4("csi_mclk_root_clk", "csi_mclk_post_div", base + 0x4490, 0);
+       hws[IMX7D_AUDIO_MCLK_ROOT_CLK] = imx_clk_hw_gate4("audio_mclk_root_clk", "audio_mclk_post_div", base + 0x4790, 0);
+       hws[IMX7D_WRCLK_ROOT_CLK] = imx_clk_hw_gate4("wrclk_root_clk", "wrclk_post_div", base + 0x47a0, 0);
+       hws[IMX7D_USB_CTRL_CLK] = imx_clk_hw_gate4("usb_ctrl_clk", "ahb_root_clk", base + 0x4680, 0);
+       hws[IMX7D_USB_PHY1_CLK] = imx_clk_hw_gate4("usb_phy1_clk", "pll_usb1_main_clk", base + 0x46a0, 0);
+       hws[IMX7D_USB_PHY2_CLK] = imx_clk_hw_gate4("usb_phy2_clk", "pll_usb_main_clk", base + 0x46b0, 0);
+       hws[IMX7D_ADC_ROOT_CLK] = imx_clk_hw_gate4("adc_root_clk", "ipg_root_clk", base + 0x4200, 0);
+
+       hws[IMX7D_GPT_3M_CLK] = imx_clk_hw_fixed_factor("gpt_3m", "osc", 1, 8);
+
+       hws[IMX7D_CLK_ARM] = imx_clk_hw_cpu("arm", "arm_a7_root_clk",
+                                        hws[IMX7D_ARM_A7_ROOT_CLK]->clk,
+                                        hws[IMX7D_ARM_A7_ROOT_SRC]->clk,
+                                        hws[IMX7D_PLL_ARM_MAIN_CLK]->clk,
+                                        hws[IMX7D_PLL_SYS_MAIN_CLK]->clk);
+
+       imx_check_clk_hws(hws, IMX7D_CLK_END);
+
+       of_clk_add_hw_provider(np, of_clk_hw_onecell_get, clk_hw_data);
+
+       clk_set_parent(hws[IMX7D_PLL_ARM_MAIN_BYPASS]->clk, hws[IMX7D_PLL_ARM_MAIN]->clk);
+       clk_set_parent(hws[IMX7D_PLL_DRAM_MAIN_BYPASS]->clk, hws[IMX7D_PLL_DRAM_MAIN]->clk);
+       clk_set_parent(hws[IMX7D_PLL_SYS_MAIN_BYPASS]->clk, hws[IMX7D_PLL_SYS_MAIN]->clk);
+       clk_set_parent(hws[IMX7D_PLL_ENET_MAIN_BYPASS]->clk, hws[IMX7D_PLL_ENET_MAIN]->clk);
+       clk_set_parent(hws[IMX7D_PLL_AUDIO_MAIN_BYPASS]->clk, hws[IMX7D_PLL_AUDIO_MAIN]->clk);
+       clk_set_parent(hws[IMX7D_PLL_VIDEO_MAIN_BYPASS]->clk, hws[IMX7D_PLL_VIDEO_MAIN]->clk);
+
+       clk_set_parent(hws[IMX7D_MIPI_CSI_ROOT_SRC]->clk, hws[IMX7D_PLL_SYS_PFD3_CLK]->clk);
 
        /* use old gpt clk setting, gpt1 root clk must be twice as gpt counter freq */
-       clk_set_parent(clks[IMX7D_GPT1_ROOT_SRC], clks[IMX7D_OSC_24M_CLK]);
+       clk_set_parent(hws[IMX7D_GPT1_ROOT_SRC]->clk, hws[IMX7D_OSC_24M_CLK]->clk);
 
        /* Set clock rate for USBPHY, the USB_PLL at CCM is from USBOTG2 */
-       clks[IMX7D_USB1_MAIN_480M_CLK] = imx_clk_fixed_factor("pll_usb1_main_clk", "osc", 20, 1);
-       clks[IMX7D_USB_MAIN_480M_CLK] = imx_clk_fixed_factor("pll_usb_main_clk", "osc", 20, 1);
+       hws[IMX7D_USB1_MAIN_480M_CLK] = imx_clk_hw_fixed_factor("pll_usb1_main_clk", "osc", 20, 1);
+       hws[IMX7D_USB_MAIN_480M_CLK] = imx_clk_hw_fixed_factor("pll_usb_main_clk", "osc", 20, 1);
+
+       for (i = 0; i < ARRAY_SIZE(uart_clk_ids); i++) {
+               int index = uart_clk_ids[i];
+
+               uart_clks[i] = &hws[index]->clk;
+       }
+
 
        imx_register_uart_clocks(uart_clks);
 
index 6668210..42e4667 100644 (file)
@@ -115,7 +115,7 @@ static void __init imx7ulp_clk_scg1_init(struct device_node *np)
 
        clks[IMX7ULP_CLK_NIC0_DIV]      = imx_clk_hw_divider_flags("nic0_clk",          "nic_sel",  base + 0x40, 24, 4, CLK_SET_RATE_PARENT | CLK_IS_CRITICAL);
        clks[IMX7ULP_CLK_NIC1_DIV]      = imx_clk_hw_divider_flags("nic1_clk",          "nic0_clk", base + 0x40, 16, 4, CLK_SET_RATE_PARENT | CLK_IS_CRITICAL);
-       clks[IMX7ULP_CLK_NIC1_BUS_DIV]  = imx_clk_hw_divider_flags("nic1_bus_clk",      "nic1_clk", base + 0x40, 4,  4, CLK_SET_RATE_PARENT | CLK_IS_CRITICAL);
+       clks[IMX7ULP_CLK_NIC1_BUS_DIV]  = imx_clk_hw_divider_flags("nic1_bus_clk",      "nic0_clk", base + 0x40, 4,  4, CLK_SET_RATE_PARENT | CLK_IS_CRITICAL);
 
        clks[IMX7ULP_CLK_GPU_DIV]       = imx_clk_hw_divider("gpu_clk", "nic0_clk", base + 0x40, 20, 4);
 
index 122a81a..6b8e75d 100644 (file)
@@ -288,6 +288,9 @@ static const char *imx8mm_usb_core_sels[] = {"osc_24m", "sys_pll1_100m", "sys_pl
 static const char *imx8mm_usb_phy_sels[] = {"osc_24m", "sys_pll1_100m", "sys_pll1_40m", "sys_pll2_100m",
                                             "sys_pll2_200m", "clk_ext2", "clk_ext3", "audio_pll2_out", };
 
+static const char *imx8mm_gic_sels[] = {"osc_24m", "sys_pll2_200m", "sys_pll1_40m", "sys_pll2_100m",
+                                       "sys_pll1_800m", "clk_ext2", "clk_ext4", "audio_pll2_out" };
+
 static const char *imx8mm_ecspi1_sels[] = {"osc_24m", "sys_pll2_200m", "sys_pll1_40m", "sys_pll1_160m",
                                           "sys_pll1_800m", "sys_pll3_out", "sys_pll2_250m", "audio_pll2_out", };
 
@@ -325,7 +328,7 @@ static const char *imx8mm_dsi_dbi_sels[] = {"osc_24m", "sys_pll1_266m", "sys_pll
                                            "sys_pll2_1000m", "sys_pll3_out", "audio_pll2_out", "video_pll1_out", };
 
 static const char *imx8mm_usdhc3_sels[] = {"osc_24m", "sys_pll1_400m", "sys_pll1_800m", "sys_pll2_500m",
-                                          "sys_pll3_out", "sys_pll1_266m", "audio_pll2_clk", "sys_pll1_100m", };
+                                          "sys_pll3_out", "sys_pll1_266m", "audio_pll2_out", "sys_pll1_100m", };
 
 static const char *imx8mm_csi1_core_sels[] = {"osc_24m", "sys_pll1_266m", "sys_pll2_250m", "sys_pll1_800m",
                                              "sys_pll2_1000m", "sys_pll3_out", "audio_pll2_out", "video_pll1_out", };
@@ -361,11 +364,11 @@ static const char *imx8mm_pdm_sels[] = {"osc_24m", "sys_pll2_100m", "audio_pll1_
                                        "sys_pll2_1000m", "sys_pll3_out", "clk_ext3", "audio_pll2_out", };
 
 static const char *imx8mm_vpu_h1_sels[] = {"osc_24m", "vpu_pll_out", "sys_pll1_800m", "sys_pll2_1000m",
-                                          "audio_pll2_clk", "sys_pll2_125m", "sys_pll3_clk", "audio_pll1_out", };
+                                          "audio_pll2_out", "sys_pll2_125m", "sys_pll3_clk", "audio_pll1_out", };
 
 static const char *imx8mm_dram_core_sels[] = {"dram_pll_out", "dram_alt_root", };
 
-static const char *imx8mm_clko1_sels[] = {"osc_24m", "sys_pll1_800m", "osc_27m", "sys_pll1_200m", "audio_pll2_clk",
+static const char *imx8mm_clko1_sels[] = {"osc_24m", "sys_pll1_800m", "osc_27m", "sys_pll1_200m", "audio_pll2_out",
                                         "vpu_pll", "sys_pll1_80m", };
 
 static struct clk *clks[IMX8MM_CLK_END];
@@ -523,7 +526,7 @@ static int __init imx8mm_clocks_init(struct device_node *ccm_node)
 
        /* IP */
        clks[IMX8MM_CLK_DRAM_ALT] = imx8m_clk_composite("dram_alt", imx8mm_dram_alt_sels, base + 0xa000);
-       clks[IMX8MM_CLK_DRAM_APB] = imx8m_clk_composite("dram_apb", imx8mm_dram_apb_sels, base + 0xa080);
+       clks[IMX8MM_CLK_DRAM_APB] = imx8m_clk_composite_critical("dram_apb", imx8mm_dram_apb_sels, base + 0xa080);
        clks[IMX8MM_CLK_VPU_G1] = imx8m_clk_composite("vpu_g1", imx8mm_vpu_g1_sels, base + 0xa100);
        clks[IMX8MM_CLK_VPU_G2] = imx8m_clk_composite("vpu_g2", imx8mm_vpu_g2_sels, base + 0xa180);
        clks[IMX8MM_CLK_DISP_DTRC] = imx8m_clk_composite("disp_dtrc", imx8mm_disp_dtrc_sels, base + 0xa200);
@@ -558,6 +561,7 @@ static int __init imx8mm_clocks_init(struct device_node *ccm_node)
        clks[IMX8MM_CLK_UART4] = imx8m_clk_composite("uart4", imx8mm_uart4_sels, base + 0xb080);
        clks[IMX8MM_CLK_USB_CORE_REF] = imx8m_clk_composite("usb_core_ref", imx8mm_usb_core_sels, base + 0xb100);
        clks[IMX8MM_CLK_USB_PHY_REF] = imx8m_clk_composite("usb_phy_ref", imx8mm_usb_phy_sels, base + 0xb180);
+       clks[IMX8MM_CLK_GIC] = imx8m_clk_composite_critical("gic", imx8mm_gic_sels, base + 0xb200);
        clks[IMX8MM_CLK_ECSPI1] = imx8m_clk_composite("ecspi1", imx8mm_ecspi1_sels, base + 0xb280);
        clks[IMX8MM_CLK_ECSPI2] = imx8m_clk_composite("ecspi2", imx8mm_ecspi2_sels, base + 0xb300);
        clks[IMX8MM_CLK_PWM1] = imx8m_clk_composite("pwm1", imx8mm_pwm1_sels, base + 0xb380);
@@ -590,6 +594,11 @@ static int __init imx8mm_clocks_init(struct device_node *ccm_node)
        clks[IMX8MM_CLK_ECSPI2_ROOT] = imx_clk_gate4("ecspi2_root_clk", "ecspi2", base + 0x4080, 0);
        clks[IMX8MM_CLK_ECSPI3_ROOT] = imx_clk_gate4("ecspi3_root_clk", "ecspi3", base + 0x4090, 0);
        clks[IMX8MM_CLK_ENET1_ROOT] = imx_clk_gate4("enet1_root_clk", "enet_axi", base + 0x40a0, 0);
+       clks[IMX8MM_CLK_GPIO1_ROOT] = imx_clk_gate4("gpio1_root_clk", "ipg_root", base + 0x40b0, 0);
+       clks[IMX8MM_CLK_GPIO2_ROOT] = imx_clk_gate4("gpio2_root_clk", "ipg_root", base + 0x40c0, 0);
+       clks[IMX8MM_CLK_GPIO3_ROOT] = imx_clk_gate4("gpio3_root_clk", "ipg_root", base + 0x40d0, 0);
+       clks[IMX8MM_CLK_GPIO4_ROOT] = imx_clk_gate4("gpio4_root_clk", "ipg_root", base + 0x40e0, 0);
+       clks[IMX8MM_CLK_GPIO5_ROOT] = imx_clk_gate4("gpio5_root_clk", "ipg_root", base + 0x40f0, 0);
        clks[IMX8MM_CLK_GPT1_ROOT] = imx_clk_gate4("gpt1_root_clk", "gpt1", base + 0x4100, 0);
        clks[IMX8MM_CLK_I2C1_ROOT] = imx_clk_gate4("i2c1_root_clk", "i2c1", base + 0x4170, 0);
        clks[IMX8MM_CLK_I2C2_ROOT] = imx_clk_gate4("i2c2_root_clk", "i2c2", base + 0x4180, 0);
@@ -617,6 +626,7 @@ static int __init imx8mm_clocks_init(struct device_node *ccm_node)
        clks[IMX8MM_CLK_SAI5_IPG] = imx_clk_gate2_shared2("sai5_ipg_clk", "ipg_audio_root", base + 0x4370, 0, &share_count_sai5);
        clks[IMX8MM_CLK_SAI6_ROOT] = imx_clk_gate2_shared2("sai6_root_clk", "sai6", base + 0x4380, 0, &share_count_sai6);
        clks[IMX8MM_CLK_SAI6_IPG] = imx_clk_gate2_shared2("sai6_ipg_clk", "ipg_audio_root", base + 0x4380, 0, &share_count_sai6);
+       clks[IMX8MM_CLK_SNVS_ROOT] = imx_clk_gate4("snvs_root_clk", "ipg_root", base + 0x4470, 0);
        clks[IMX8MM_CLK_UART1_ROOT] = imx_clk_gate4("uart1_root_clk", "uart1", base + 0x4490, 0);
        clks[IMX8MM_CLK_UART2_ROOT] = imx_clk_gate4("uart2_root_clk", "uart2", base + 0x44a0, 0);
        clks[IMX8MM_CLK_UART3_ROOT] = imx_clk_gate4("uart3_root_clk", "uart3", base + 0x44b0, 0);
index daf1841..d407a07 100644 (file)
@@ -192,6 +192,9 @@ static const char * const imx8mq_usb_core_sels[] = {"osc_25m", "sys1_pll_100m",
 static const char * const imx8mq_usb_phy_sels[] = {"osc_25m", "sys1_pll_100m", "sys1_pll_40m", "sys2_pll_100m",
                                             "sys2_pll_200m", "clk_ext2", "clk_ext3", "audio_pll2_out", };
 
+static const char * const imx8mq_gic_sels[] = {"osc_25m", "sys2_pll_200m", "sys1_pll_40m", "sys2_pll_100m",
+                                              "sys2_pll_200m", "clk_ext2", "clk_ext3", "audio_pll2_out" };
+
 static const char * const imx8mq_ecspi1_sels[] = {"osc_25m", "sys2_pll_200m", "sys1_pll_40m", "sys1_pll_160m",
                                           "sys1_pll_800m", "sys3_pll2_out", "sys2_pll_250m", "audio_pll2_out", };
 
@@ -269,13 +272,20 @@ static const char * const imx8mq_clko2_sels[] = {"osc_25m", "sys2_pll_200m", "sy
 
 static struct clk_onecell_data clk_data;
 
+static struct clk ** const uart_clks[] = {
+       &clks[IMX8MQ_CLK_UART1_ROOT],
+       &clks[IMX8MQ_CLK_UART2_ROOT],
+       &clks[IMX8MQ_CLK_UART3_ROOT],
+       &clks[IMX8MQ_CLK_UART4_ROOT],
+       NULL
+};
+
 static int imx8mq_clocks_probe(struct platform_device *pdev)
 {
        struct device *dev = &pdev->dev;
        struct device_node *np = dev->of_node;
        void __iomem *base;
        int err;
-       int i;
 
        clks[IMX8MQ_CLK_DUMMY] = imx_clk_fixed("dummy", 0);
        clks[IMX8MQ_CLK_32K] = of_clk_get_by_name(np, "ckil");
@@ -358,9 +368,9 @@ static int imx8mq_clocks_probe(struct platform_device *pdev)
        clks[IMX8MQ_SYS2_PLL_1000M] = imx_clk_fixed_factor("sys2_pll_1000m", "sys2_pll_out", 1, 1);
 
        np = dev->of_node;
-       base = of_iomap(np, 0);
-       if (WARN_ON(!base))
-               return -ENOMEM;
+       base = devm_platform_ioremap_resource(pdev, 0);
+       if (WARN_ON(IS_ERR(base)))
+               return PTR_ERR(base);
 
        /* CORE */
        clks[IMX8MQ_CLK_A53_SRC] = imx_clk_mux2("arm_a53_src", base + 0x8000, 24, 3, imx8mq_a53_sels, ARRAY_SIZE(imx8mq_a53_sels));
@@ -442,6 +452,7 @@ static int imx8mq_clocks_probe(struct platform_device *pdev)
        clks[IMX8MQ_CLK_UART4] = imx8m_clk_composite("uart4", imx8mq_uart4_sels, base + 0xb080);
        clks[IMX8MQ_CLK_USB_CORE_REF] = imx8m_clk_composite("usb_core_ref", imx8mq_usb_core_sels, base + 0xb100);
        clks[IMX8MQ_CLK_USB_PHY_REF] = imx8m_clk_composite("usb_phy_ref", imx8mq_usb_phy_sels, base + 0xb180);
+       clks[IMX8MQ_CLK_GIC] = imx8m_clk_composite_critical("gic", imx8mq_gic_sels, base + 0xb200);
        clks[IMX8MQ_CLK_ECSPI1] = imx8m_clk_composite("ecspi1", imx8mq_ecspi1_sels, base + 0xb280);
        clks[IMX8MQ_CLK_ECSPI2] = imx8m_clk_composite("ecspi2", imx8mq_ecspi2_sels, base + 0xb300);
        clks[IMX8MQ_CLK_PWM1] = imx8m_clk_composite("pwm1", imx8mq_pwm1_sels, base + 0xb380);
@@ -507,6 +518,7 @@ static int imx8mq_clocks_probe(struct platform_device *pdev)
        clks[IMX8MQ_CLK_SAI5_IPG] = imx_clk_gate2_shared2("sai5_ipg_clk", "ipg_audio_root", base + 0x4370, 0, &share_count_sai5);
        clks[IMX8MQ_CLK_SAI6_ROOT] = imx_clk_gate2_shared2("sai6_root_clk", "sai6", base + 0x4380, 0, &share_count_sai6);
        clks[IMX8MQ_CLK_SAI6_IPG] = imx_clk_gate2_shared2("sai6_ipg_clk", "ipg_audio_root", base + 0x4380, 0, &share_count_sai6);
+       clks[IMX8MQ_CLK_SNVS_ROOT] = imx_clk_gate4("snvs_root_clk", "ipg_root", base + 0x4470, 0);
        clks[IMX8MQ_CLK_UART1_ROOT] = imx_clk_gate4("uart1_root_clk", "uart1", base + 0x4490, 0);
        clks[IMX8MQ_CLK_UART2_ROOT] = imx_clk_gate4("uart2_root_clk", "uart2", base + 0x44a0, 0);
        clks[IMX8MQ_CLK_UART3_ROOT] = imx_clk_gate4("uart3_root_clk", "uart3", base + 0x44b0, 0);
@@ -543,10 +555,7 @@ static int imx8mq_clocks_probe(struct platform_device *pdev)
                                           clks[IMX8MQ_ARM_PLL_OUT],
                                           clks[IMX8MQ_SYS1_PLL_800M]);
 
-       for (i = 0; i < IMX8MQ_CLK_END; i++)
-               if (IS_ERR(clks[i]))
-                       pr_err("i.MX8mq clk %u register failed with %ld\n",
-                              i, PTR_ERR(clks[i]));
+       imx_check_clocks(clks, ARRAY_SIZE(clks));
 
        clk_data.clks = clks;
        clk_data.clk_num = ARRAY_SIZE(clks);
@@ -554,6 +563,8 @@ static int imx8mq_clocks_probe(struct platform_device *pdev)
        err = of_clk_add_provider(np, of_clk_src_onecell_get, &clk_data);
        WARN_ON(err);
 
+       imx_register_uart_clocks(uart_clks);
+
        return err;
 }
 
index fa82dde..50b7c30 100644 (file)
@@ -121,12 +121,13 @@ static const struct clk_ops clk_pfd_ops = {
        .is_enabled     = clk_pfd_is_enabled,
 };
 
-struct clk *imx_clk_pfd(const char *name, const char *parent_name,
+struct clk_hw *imx_clk_hw_pfd(const char *name, const char *parent_name,
                        void __iomem *reg, u8 idx)
 {
        struct clk_pfd *pfd;
-       struct clk *clk;
+       struct clk_hw *hw;
        struct clk_init_data init;
+       int ret;
 
        pfd = kzalloc(sizeof(*pfd), GFP_KERNEL);
        if (!pfd)
@@ -142,10 +143,13 @@ struct clk *imx_clk_pfd(const char *name, const char *parent_name,
        init.num_parents = 1;
 
        pfd->hw.init = &init;
+       hw = &pfd->hw;
 
-       clk = clk_register(NULL, &pfd->hw);
-       if (IS_ERR(clk))
+       ret = clk_hw_register(NULL, hw);
+       if (ret) {
                kfree(pfd);
+               return ERR_PTR(ret);
+       }
 
-       return clk;
+       return hw;
 }
index 93b0596..df91a82 100644 (file)
@@ -410,14 +410,15 @@ static const struct clk_ops clk_pllv3_enet_ops = {
        .recalc_rate    = clk_pllv3_enet_recalc_rate,
 };
 
-struct clk *imx_clk_pllv3(enum imx_pllv3_type type, const char *name,
+struct clk_hw *imx_clk_hw_pllv3(enum imx_pllv3_type type, const char *name,
                          const char *parent_name, void __iomem *base,
                          u32 div_mask)
 {
        struct clk_pllv3 *pll;
        const struct clk_ops *ops;
-       struct clk *clk;
+       struct clk_hw *hw;
        struct clk_init_data init;
+       int ret;
 
        pll = kzalloc(sizeof(*pll), GFP_KERNEL);
        if (!pll)
@@ -478,10 +479,13 @@ struct clk *imx_clk_pllv3(enum imx_pllv3_type type, const char *name,
        init.num_parents = 1;
 
        pll->hw.init = &init;
+       hw = &pll->hw;
 
-       clk = clk_register(NULL, &pll->hw);
-       if (IS_ERR(clk))
+       ret = clk_hw_register(NULL, hw);
+       if (ret) {
                kfree(pll);
+               return ERR_PTR(ret);
+       }
 
-       return clk;
+       return hw;
 }
index 1efed86..f628071 100644 (file)
@@ -1,14 +1,30 @@
 // SPDX-License-Identifier: GPL-2.0
 #include <linux/clk.h>
+#include <linux/clk-provider.h>
 #include <linux/err.h>
+#include <linux/io.h>
 #include <linux/of.h>
 #include <linux/slab.h>
 #include <linux/spinlock.h>
 #include "clk.h"
 
+#define CCM_CCDR                       0x4
+#define CCDR_MMDC_CH0_MASK             BIT(17)
+#define CCDR_MMDC_CH1_MASK             BIT(16)
+
 DEFINE_SPINLOCK(imx_ccm_lock);
 
-void __init imx_check_clocks(struct clk *clks[], unsigned int count)
+void __init imx_mmdc_mask_handshake(void __iomem *ccm_base,
+                                   unsigned int chn)
+{
+       unsigned int reg;
+
+       reg = readl_relaxed(ccm_base + CCM_CCDR);
+       reg |= chn == 0 ? CCDR_MMDC_CH0_MASK : CCDR_MMDC_CH1_MASK;
+       writel_relaxed(reg, ccm_base + CCM_CCDR);
+}
+
+void imx_check_clocks(struct clk *clks[], unsigned int count)
 {
        unsigned i;
 
@@ -59,6 +75,17 @@ struct clk * __init imx_obtain_fixed_clock(
        return clk;
 }
 
+struct clk_hw * __init imx_obtain_fixed_clock_hw(
+                       const char *name, unsigned long rate)
+{
+       struct clk *clk;
+
+       clk = imx_obtain_fixed_clock_from_dt(name);
+       if (IS_ERR(clk))
+               clk = imx_clk_fixed(name, rate);
+       return __clk_get_hw(clk);
+}
+
 struct clk_hw * __init imx_obtain_fixed_clk_hw(struct device_node *np,
                                               const char *name)
 {
@@ -97,8 +124,8 @@ void imx_cscmr1_fixup(u32 *val)
        return;
 }
 
-static int imx_keep_uart_clocks __initdata;
-static struct clk ** const *imx_uart_clocks __initdata;
+static int imx_keep_uart_clocks;
+static struct clk ** const *imx_uart_clocks;
 
 static int __init imx_keep_uart_clocks_param(char *str)
 {
@@ -111,7 +138,7 @@ __setup_param("earlycon", imx_keep_uart_earlycon,
 __setup_param("earlyprintk", imx_keep_uart_earlyprintk,
              imx_keep_uart_clocks_param, 0);
 
-void __init imx_register_uart_clocks(struct clk ** const clks[])
+void imx_register_uart_clocks(struct clk ** const clks[])
 {
        if (imx_keep_uart_clocks) {
                int i;
index 8639a8f..d94d9cb 100644 (file)
@@ -10,6 +10,8 @@ extern spinlock_t imx_ccm_lock;
 void imx_check_clocks(struct clk *clks[], unsigned int count);
 void imx_check_clk_hws(struct clk_hw *clks[], unsigned int count);
 void imx_register_uart_clocks(struct clk ** const clks[]);
+void imx_register_uart_clocks_hws(struct clk_hw ** const hws[]);
+void imx_mmdc_mask_handshake(void __iomem *ccm_base, unsigned int chn);
 
 extern void imx_cscmr1_fixup(u32 *val);
 
@@ -48,6 +50,74 @@ struct imx_pll14xx_clk {
        int flags;
 };
 
+#define imx_clk_busy_divider(name, parent_name, reg, shift, width, busy_reg, busy_shift) \
+       imx_clk_hw_busy_divider(name, parent_name, reg, shift, width, busy_reg, busy_shift)->clk
+
+#define imx_clk_busy_mux(name, reg, shift, width, busy_reg, busy_shift, parent_names, num_parents) \
+       imx_clk_hw_busy_mux(name, reg, shift, width, busy_reg, busy_shift, parent_names, num_parents)->clk
+
+#define imx_clk_cpu(name, parent_name, div, mux, pll, step) \
+       imx_clk_hw_cpu(name, parent_name, div, mux, pll, step)->clk
+
+#define clk_register_gate2(dev, name, parent_name, flags, reg, bit_idx, \
+                               cgr_val, clk_gate_flags, lock, share_count) \
+       clk_hw_register_gate2(dev, name, parent_name, flags, reg, bit_idx, \
+                               cgr_val, clk_gate_flags, lock, share_count)->clk
+
+#define imx_clk_pllv3(type, name, parent_name, base, div_mask) \
+       imx_clk_hw_pllv3(type, name, parent_name, base, div_mask)->clk
+
+#define imx_clk_pfd(name, parent_name, reg, idx) \
+       imx_clk_hw_pfd(name, parent_name, reg, idx)->clk
+
+#define imx_clk_gate_exclusive(name, parent, reg, shift, exclusive_mask) \
+       imx_clk_hw_gate_exclusive(name, parent, reg, shift, exclusive_mask)->clk
+
+#define imx_clk_fixup_divider(name, parent, reg, shift, width, fixup) \
+       imx_clk_hw_fixup_divider(name, parent, reg, shift, width, fixup)->clk
+
+#define imx_clk_fixup_mux(name, reg, shift, width, parents, num_parents, fixup) \
+       imx_clk_hw_fixup_mux(name, reg, shift, width, parents, num_parents, fixup)->clk
+
+#define imx_clk_mux_ldb(name, reg, shift, width, parents, num_parents) \
+       imx_clk_hw_mux_ldb(name, reg, shift, width, parents, num_parents)->clk
+
+#define imx_clk_fixed_factor(name, parent, mult, div) \
+       imx_clk_hw_fixed_factor(name, parent, mult, div)->clk
+
+#define imx_clk_divider2(name, parent, reg, shift, width) \
+       imx_clk_hw_divider2(name, parent, reg, shift, width)->clk
+
+#define imx_clk_gate_dis(name, parent, reg, shift) \
+       imx_clk_hw_gate_dis(name, parent, reg, shift)->clk
+
+#define imx_clk_gate_dis_flags(name, parent, reg, shift, flags) \
+       imx_clk_hw_gate_dis_flags(name, parent, reg, shift, flags)->clk
+
+#define imx_clk_gate_flags(name, parent, reg, shift, flags) \
+       imx_clk_hw_gate_flags(name, parent, reg, shift, flags)->clk
+
+#define imx_clk_gate2(name, parent, reg, shift) \
+       imx_clk_hw_gate2(name, parent, reg, shift)->clk
+
+#define imx_clk_gate2_flags(name, parent, reg, shift, flags) \
+       imx_clk_hw_gate2_flags(name, parent, reg, shift, flags)->clk
+
+#define imx_clk_gate2_shared(name, parent, reg, shift, share_count) \
+       imx_clk_hw_gate2_shared(name, parent, reg, shift, share_count)->clk
+
+#define imx_clk_gate2_shared2(name, parent, reg, shift, share_count) \
+       imx_clk_hw_gate2_shared2(name, parent, reg, shift, share_count)->clk
+
+#define imx_clk_gate3(name, parent, reg, shift) \
+       imx_clk_hw_gate3(name, parent, reg, shift)->clk
+
+#define imx_clk_gate4(name, parent, reg, shift) \
+       imx_clk_hw_gate4(name, parent, reg, shift)->clk
+
+#define imx_clk_mux(name, reg, shift, width, parents, num_parents) \
+       imx_clk_hw_mux(name, reg, shift, width, parents, num_parents)->clk
+
 struct clk *imx_clk_pll14xx(const char *name, const char *parent_name,
                 void __iomem *base, const struct imx_pll14xx_clk *pll_clk);
 
@@ -80,13 +150,13 @@ enum imx_pllv3_type {
        IMX_PLLV3_AV_IMX7,
 };
 
-struct clk *imx_clk_pllv3(enum imx_pllv3_type type, const char *name,
+struct clk_hw *imx_clk_hw_pllv3(enum imx_pllv3_type type, const char *name,
                const char *parent_name, void __iomem *base, u32 div_mask);
 
 struct clk_hw *imx_clk_pllv4(const char *name, const char *parent_name,
                             void __iomem *base);
 
-struct clk *clk_register_gate2(struct device *dev, const char *name,
+struct clk_hw *clk_hw_register_gate2(struct device *dev, const char *name,
                const char *parent_name, unsigned long flags,
                void __iomem *reg, u8 bit_idx, u8 cgr_val,
                u8 clk_gate_flags, spinlock_t *lock,
@@ -95,23 +165,26 @@ struct clk *clk_register_gate2(struct device *dev, const char *name,
 struct clk * imx_obtain_fixed_clock(
                        const char *name, unsigned long rate);
 
+struct clk_hw *imx_obtain_fixed_clock_hw(
+                       const char *name, unsigned long rate);
+
 struct clk_hw *imx_obtain_fixed_clk_hw(struct device_node *np,
                                       const char *name);
 
-struct clk *imx_clk_gate_exclusive(const char *name, const char *parent,
+struct clk_hw *imx_clk_hw_gate_exclusive(const char *name, const char *parent,
         void __iomem *reg, u8 shift, u32 exclusive_mask);
 
-struct clk *imx_clk_pfd(const char *name, const char *parent_name,
+struct clk_hw *imx_clk_hw_pfd(const char *name, const char *parent_name,
                void __iomem *reg, u8 idx);
 
 struct clk_hw *imx_clk_pfdv2(const char *name, const char *parent_name,
                             void __iomem *reg, u8 idx);
 
-struct clk *imx_clk_busy_divider(const char *name, const char *parent_name,
+struct clk_hw *imx_clk_hw_busy_divider(const char *name, const char *parent_name,
                                 void __iomem *reg, u8 shift, u8 width,
                                 void __iomem *busy_reg, u8 busy_shift);
 
-struct clk *imx_clk_busy_mux(const char *name, void __iomem *reg, u8 shift,
+struct clk_hw *imx_clk_hw_busy_mux(const char *name, void __iomem *reg, u8 shift,
                             u8 width, void __iomem *busy_reg, u8 busy_shift,
                             const char * const *parent_names, int num_parents);
 
@@ -121,11 +194,11 @@ struct clk_hw *imx7ulp_clk_composite(const char *name,
                                     bool rate_present, bool gate_present,
                                     void __iomem *reg);
 
-struct clk *imx_clk_fixup_divider(const char *name, const char *parent,
+struct clk_hw *imx_clk_hw_fixup_divider(const char *name, const char *parent,
                                  void __iomem *reg, u8 shift, u8 width,
                                  void (*fixup)(u32 *val));
 
-struct clk *imx_clk_fixup_mux(const char *name, void __iomem *reg,
+struct clk_hw *imx_clk_hw_fixup_mux(const char *name, void __iomem *reg,
                              u8 shift, u8 width, const char * const *parents,
                              int num_parents, void (*fixup)(u32 *val));
 
@@ -139,19 +212,19 @@ static inline struct clk_hw *imx_clk_hw_fixed(const char *name, int rate)
        return clk_hw_register_fixed_rate(NULL, name, NULL, 0, rate);
 }
 
-static inline struct clk *imx_clk_mux_ldb(const char *name, void __iomem *reg,
+static inline struct clk_hw *imx_clk_hw_mux_ldb(const char *name, void __iomem *reg,
                        u8 shift, u8 width, const char * const *parents,
                        int num_parents)
 {
-       return clk_register_mux(NULL, name, parents, num_parents,
+       return clk_hw_register_mux(NULL, name, parents, num_parents,
                        CLK_SET_RATE_NO_REPARENT | CLK_SET_RATE_PARENT, reg,
                        shift, width, CLK_MUX_READ_ONLY, &imx_ccm_lock);
 }
 
-static inline struct clk *imx_clk_fixed_factor(const char *name,
+static inline struct clk_hw *imx_clk_hw_fixed_factor(const char *name,
                const char *parent, unsigned int mult, unsigned int div)
 {
-       return clk_register_fixed_factor(NULL, name, parent,
+       return clk_hw_register_fixed_factor(NULL, name, parent,
                        CLK_SET_RATE_PARENT, mult, div);
 }
 
@@ -188,10 +261,10 @@ static inline struct clk_hw *imx_clk_hw_divider_flags(const char *name,
                                       reg, shift, width, 0, &imx_ccm_lock);
 }
 
-static inline struct clk *imx_clk_divider2(const char *name, const char *parent,
+static inline struct clk_hw *imx_clk_hw_divider2(const char *name, const char *parent,
                void __iomem *reg, u8 shift, u8 width)
 {
-       return clk_register_divider(NULL, name, parent,
+       return clk_hw_register_divider(NULL, name, parent,
                        CLK_SET_RATE_PARENT | CLK_OPS_PARENT_ENABLE,
                        reg, shift, width, 0, &imx_ccm_lock);
 }
@@ -212,10 +285,10 @@ static inline struct clk *imx_clk_gate(const char *name, const char *parent,
                        shift, 0, &imx_ccm_lock);
 }
 
-static inline struct clk *imx_clk_gate_flags(const char *name, const char *parent,
+static inline struct clk_hw *imx_clk_hw_gate_flags(const char *name, const char *parent,
                void __iomem *reg, u8 shift, unsigned long flags)
 {
-       return clk_register_gate(NULL, name, parent, flags | CLK_SET_RATE_PARENT, reg,
+       return clk_hw_register_gate(NULL, name, parent, flags | CLK_SET_RATE_PARENT, reg,
                        shift, 0, &imx_ccm_lock);
 }
 
@@ -226,47 +299,47 @@ static inline struct clk_hw *imx_clk_hw_gate(const char *name, const char *paren
                                    shift, 0, &imx_ccm_lock);
 }
 
-static inline struct clk *imx_clk_gate_dis(const char *name, const char *parent,
+static inline struct clk_hw *imx_clk_hw_gate_dis(const char *name, const char *parent,
                void __iomem *reg, u8 shift)
 {
-       return clk_register_gate(NULL, name, parent, CLK_SET_RATE_PARENT, reg,
+       return clk_hw_register_gate(NULL, name, parent, CLK_SET_RATE_PARENT, reg,
                        shift, CLK_GATE_SET_TO_DISABLE, &imx_ccm_lock);
 }
 
-static inline struct clk *imx_clk_gate_dis_flags(const char *name, const char *parent,
+static inline struct clk_hw *imx_clk_hw_gate_dis_flags(const char *name, const char *parent,
                void __iomem *reg, u8 shift, unsigned long flags)
 {
-       return clk_register_gate(NULL, name, parent, flags | CLK_SET_RATE_PARENT, reg,
+       return clk_hw_register_gate(NULL, name, parent, flags | CLK_SET_RATE_PARENT, reg,
                        shift, CLK_GATE_SET_TO_DISABLE, &imx_ccm_lock);
 }
 
-static inline struct clk *imx_clk_gate2(const char *name, const char *parent,
+static inline struct clk_hw *imx_clk_hw_gate2(const char *name, const char *parent,
                void __iomem *reg, u8 shift)
 {
-       return clk_register_gate2(NULL, name, parent, CLK_SET_RATE_PARENT, reg,
+       return clk_hw_register_gate2(NULL, name, parent, CLK_SET_RATE_PARENT, reg,
                        shift, 0x3, 0, &imx_ccm_lock, NULL);
 }
 
-static inline struct clk *imx_clk_gate2_flags(const char *name, const char *parent,
+static inline struct clk_hw *imx_clk_hw_gate2_flags(const char *name, const char *parent,
                void __iomem *reg, u8 shift, unsigned long flags)
 {
-       return clk_register_gate2(NULL, name, parent, flags | CLK_SET_RATE_PARENT, reg,
+       return clk_hw_register_gate2(NULL, name, parent, flags | CLK_SET_RATE_PARENT, reg,
                        shift, 0x3, 0, &imx_ccm_lock, NULL);
 }
 
-static inline struct clk *imx_clk_gate2_shared(const char *name,
+static inline struct clk_hw *imx_clk_hw_gate2_shared(const char *name,
                const char *parent, void __iomem *reg, u8 shift,
                unsigned int *share_count)
 {
-       return clk_register_gate2(NULL, name, parent, CLK_SET_RATE_PARENT, reg,
+       return clk_hw_register_gate2(NULL, name, parent, CLK_SET_RATE_PARENT, reg,
                        shift, 0x3, 0, &imx_ccm_lock, share_count);
 }
 
-static inline struct clk *imx_clk_gate2_shared2(const char *name,
+static inline struct clk_hw *imx_clk_hw_gate2_shared2(const char *name,
                const char *parent, void __iomem *reg, u8 shift,
                unsigned int *share_count)
 {
-       return clk_register_gate2(NULL, name, parent, CLK_SET_RATE_PARENT |
+       return clk_hw_register_gate2(NULL, name, parent, CLK_SET_RATE_PARENT |
                                  CLK_OPS_PARENT_ENABLE, reg, shift, 0x3, 0,
                                  &imx_ccm_lock, share_count);
 }
@@ -278,10 +351,10 @@ static inline struct clk *imx_clk_gate2_cgr(const char *name,
                        shift, cgr_val, 0, &imx_ccm_lock, NULL);
 }
 
-static inline struct clk *imx_clk_gate3(const char *name, const char *parent,
+static inline struct clk_hw *imx_clk_hw_gate3(const char *name, const char *parent,
                void __iomem *reg, u8 shift)
 {
-       return clk_register_gate(NULL, name, parent,
+       return clk_hw_register_gate(NULL, name, parent,
                        CLK_SET_RATE_PARENT | CLK_OPS_PARENT_ENABLE,
                        reg, shift, 0, &imx_ccm_lock);
 }
@@ -295,10 +368,10 @@ static inline struct clk *imx_clk_gate3_flags(const char *name,
                        reg, shift, 0, &imx_ccm_lock);
 }
 
-static inline struct clk *imx_clk_gate4(const char *name, const char *parent,
+static inline struct clk_hw *imx_clk_hw_gate4(const char *name, const char *parent,
                void __iomem *reg, u8 shift)
 {
-       return clk_register_gate2(NULL, name, parent,
+       return clk_hw_register_gate2(NULL, name, parent,
                        CLK_SET_RATE_PARENT | CLK_OPS_PARENT_ENABLE,
                        reg, shift, 0x3, 0, &imx_ccm_lock, NULL);
 }
@@ -312,11 +385,11 @@ static inline struct clk *imx_clk_gate4_flags(const char *name,
                        reg, shift, 0x3, 0, &imx_ccm_lock, NULL);
 }
 
-static inline struct clk *imx_clk_mux(const char *name, void __iomem *reg,
+static inline struct clk_hw *imx_clk_hw_mux(const char *name, void __iomem *reg,
                        u8 shift, u8 width, const char * const *parents,
                        int num_parents)
 {
-       return clk_register_mux(NULL, name, parents, num_parents,
+       return clk_hw_register_mux(NULL, name, parents, num_parents,
                        CLK_SET_RATE_NO_REPARENT, reg, shift,
                        width, 0, &imx_ccm_lock);
 }
@@ -373,7 +446,7 @@ static inline struct clk_hw *imx_clk_hw_mux_flags(const char *name,
                                   reg, shift, width, 0, &imx_ccm_lock);
 }
 
-struct clk *imx_clk_cpu(const char *name, const char *parent_name,
+struct clk_hw *imx_clk_hw_cpu(const char *name, const char *parent_name,
                struct clk *div, struct clk *mux, struct clk *pll,
                struct clk *step);
 
index ab58a6a..250570a 100644 (file)
@@ -1,5 +1,5 @@
 # SPDX-License-Identifier: GPL-2.0-only
-obj-$(CONFIG_INGENIC_CGU_COMMON)       += cgu.o
+obj-$(CONFIG_INGENIC_CGU_COMMON)       += cgu.o pm.o
 obj-$(CONFIG_INGENIC_CGU_JZ4740)       += jz4740-cgu.o
 obj-$(CONFIG_INGENIC_CGU_JZ4725B)      += jz4725b-cgu.o
 obj-$(CONFIG_INGENIC_CGU_JZ4770)       += jz4770-cgu.o
index 92c3314..6e96303 100644 (file)
@@ -375,8 +375,11 @@ ingenic_clk_recalc_rate(struct clk_hw *hw, unsigned long parent_rate)
                div_reg = readl(cgu->base + clk_info->div.reg);
                div = (div_reg >> clk_info->div.shift) &
                      GENMASK(clk_info->div.bits - 1, 0);
-               div += 1;
-               div *= clk_info->div.div;
+
+               if (clk_info->div.div_table)
+                       div = clk_info->div.div_table[div];
+               else
+                       div = (div + 1) * clk_info->div.div;
 
                rate /= div;
        } else if (clk_info->type & CGU_CLK_FIXDIV) {
@@ -386,16 +389,37 @@ ingenic_clk_recalc_rate(struct clk_hw *hw, unsigned long parent_rate)
        return rate;
 }
 
+static unsigned int
+ingenic_clk_calc_hw_div(const struct ingenic_cgu_clk_info *clk_info,
+                       unsigned int div)
+{
+       unsigned int i;
+
+       for (i = 0; i < (1 << clk_info->div.bits)
+                               && clk_info->div.div_table[i]; i++) {
+               if (clk_info->div.div_table[i] >= div)
+                       return i;
+       }
+
+       return i - 1;
+}
+
 static unsigned
 ingenic_clk_calc_div(const struct ingenic_cgu_clk_info *clk_info,
                     unsigned long parent_rate, unsigned long req_rate)
 {
-       unsigned div;
+       unsigned int div, hw_div;
 
        /* calculate the divide */
        div = DIV_ROUND_UP(parent_rate, req_rate);
 
-       /* and impose hardware constraints */
+       if (clk_info->div.div_table) {
+               hw_div = ingenic_clk_calc_hw_div(clk_info, div);
+
+               return clk_info->div.div_table[hw_div];
+       }
+
+       /* Impose hardware constraints */
        div = min_t(unsigned, div, 1 << clk_info->div.bits);
        div = max_t(unsigned, div, 1);
 
@@ -438,7 +462,7 @@ ingenic_clk_set_rate(struct clk_hw *hw, unsigned long req_rate,
        const struct ingenic_cgu_clk_info *clk_info;
        const unsigned timeout = 100;
        unsigned long rate, flags;
-       unsigned div, i;
+       unsigned int hw_div, div, i;
        u32 reg, mask;
        int ret = 0;
 
@@ -451,13 +475,18 @@ ingenic_clk_set_rate(struct clk_hw *hw, unsigned long req_rate,
                if (rate != req_rate)
                        return -EINVAL;
 
+               if (clk_info->div.div_table)
+                       hw_div = ingenic_clk_calc_hw_div(clk_info, div);
+               else
+                       hw_div = ((div / clk_info->div.div) - 1);
+
                spin_lock_irqsave(&cgu->lock, flags);
                reg = readl(cgu->base + clk_info->div.reg);
 
                /* update the divide */
                mask = GENMASK(clk_info->div.bits - 1, 0);
                reg &= ~(mask << clk_info->div.shift);
-               reg |= ((div / clk_info->div.div) - 1) << clk_info->div.shift;
+               reg |= hw_div << clk_info->div.shift;
 
                /* clear the stop bit */
                if (clk_info->div.stop_bit != -1)
index bfbcf6d..0dc8004 100644 (file)
@@ -10,6 +10,7 @@
 #define __DRIVERS_CLK_INGENIC_CGU_H__
 
 #include <linux/bitops.h>
+#include <linux/clk-provider.h>
 #include <linux/of.h>
 #include <linux/spinlock.h>
 
@@ -79,6 +80,8 @@ struct ingenic_cgu_mux_info {
  *          isn't one
  * @busy_bit: the index of the busy bit within reg, or -1 if there isn't one
  * @stop_bit: the index of the stop bit within reg, or -1 if there isn't one
+ * @div_table: optional table to map the value read from the register to the
+ *             actual divider value
  */
 struct ingenic_cgu_div_info {
        unsigned reg;
@@ -88,6 +91,7 @@ struct ingenic_cgu_div_info {
        s8 ce_bit;
        s8 busy_bit;
        s8 stop_bit;
+       const u8 *div_table;
 };
 
 /**
index 8901ea0..2642d36 100644 (file)
@@ -11,6 +11,7 @@
 #include <linux/of.h>
 #include <dt-bindings/clock/jz4725b-cgu.h>
 #include "cgu.h"
+#include "pm.h"
 
 /* CGU register offsets */
 #define CGU_REG_CPCCR          0x00
@@ -33,6 +34,14 @@ static const s8 pll_od_encoding[4] = {
        0x0, 0x1, -1, 0x3,
 };
 
+static const u8 jz4725b_cgu_cpccr_div_table[] = {
+       1, 2, 3, 4, 6, 8,
+};
+
+static const u8 jz4725b_cgu_pll_half_div_table[] = {
+       2, 1,
+};
+
 static const struct ingenic_cgu_clk_info jz4725b_cgu_clocks[] = {
 
        /* External clocks */
@@ -66,37 +75,55 @@ static const struct ingenic_cgu_clk_info jz4725b_cgu_clocks[] = {
        [JZ4725B_CLK_PLL_HALF] = {
                "pll half", CGU_CLK_DIV,
                .parents = { JZ4725B_CLK_PLL, -1, -1, -1 },
-               .div = { CGU_REG_CPCCR, 21, 1, 1, -1, -1, -1 },
+               .div = {
+                       CGU_REG_CPCCR, 21, 1, 1, -1, -1, -1,
+                       jz4725b_cgu_pll_half_div_table,
+               },
        },
 
        [JZ4725B_CLK_CCLK] = {
                "cclk", CGU_CLK_DIV,
                .parents = { JZ4725B_CLK_PLL, -1, -1, -1 },
-               .div = { CGU_REG_CPCCR, 0, 1, 4, 22, -1, -1 },
+               .div = {
+                       CGU_REG_CPCCR, 0, 1, 4, 22, -1, -1,
+                       jz4725b_cgu_cpccr_div_table,
+               },
        },
 
        [JZ4725B_CLK_HCLK] = {
                "hclk", CGU_CLK_DIV,
                .parents = { JZ4725B_CLK_PLL, -1, -1, -1 },
-               .div = { CGU_REG_CPCCR, 4, 1, 4, 22, -1, -1 },
+               .div = {
+                       CGU_REG_CPCCR, 4, 1, 4, 22, -1, -1,
+                       jz4725b_cgu_cpccr_div_table,
+               },
        },
 
        [JZ4725B_CLK_PCLK] = {
                "pclk", CGU_CLK_DIV,
                .parents = { JZ4725B_CLK_PLL, -1, -1, -1 },
-               .div = { CGU_REG_CPCCR, 8, 1, 4, 22, -1, -1 },
+               .div = {
+                       CGU_REG_CPCCR, 8, 1, 4, 22, -1, -1,
+                       jz4725b_cgu_cpccr_div_table,
+               },
        },
 
        [JZ4725B_CLK_MCLK] = {
                "mclk", CGU_CLK_DIV,
                .parents = { JZ4725B_CLK_PLL, -1, -1, -1 },
-               .div = { CGU_REG_CPCCR, 12, 1, 4, 22, -1, -1 },
+               .div = {
+                       CGU_REG_CPCCR, 12, 1, 4, 22, -1, -1,
+                       jz4725b_cgu_cpccr_div_table,
+               },
        },
 
        [JZ4725B_CLK_IPU] = {
                "ipu", CGU_CLK_DIV | CGU_CLK_GATE,
                .parents = { JZ4725B_CLK_PLL, -1, -1, -1 },
-               .div = { CGU_REG_CPCCR, 16, 1, 4, 22, -1, -1 },
+               .div = {
+                       CGU_REG_CPCCR, 16, 1, 4, 22, -1, -1,
+                       jz4725b_cgu_cpccr_div_table,
+               },
                .gate = { CGU_REG_CLKGR, 13 },
        },
 
@@ -227,5 +254,7 @@ static void __init jz4725b_cgu_init(struct device_node *np)
        retval = ingenic_cgu_register_clocks(cgu);
        if (retval)
                pr_err("%s: failed to register CGU Clocks\n", __func__);
+
+       ingenic_cgu_register_syscore_ops(cgu);
 }
 CLK_OF_DECLARE(jz4725b_cgu, "ingenic,jz4725b-cgu", jz4725b_cgu_init);
index c77f4e1..4c0a209 100644 (file)
@@ -11,8 +11,8 @@
 #include <linux/io.h>
 #include <linux/of.h>
 #include <dt-bindings/clock/jz4740-cgu.h>
-#include <asm/mach-jz4740/clock.h>
 #include "cgu.h"
+#include "pm.h"
 
 /* CGU register offsets */
 #define CGU_REG_CPCCR          0x00
@@ -49,6 +49,10 @@ static const s8 pll_od_encoding[4] = {
        0x0, 0x1, -1, 0x3,
 };
 
+static const u8 jz4740_cgu_cpccr_div_table[] = {
+       1, 2, 3, 4, 6, 8, 12, 16, 24, 32,
+};
+
 static const struct ingenic_cgu_clk_info jz4740_cgu_clocks[] = {
 
        /* External clocks */
@@ -88,31 +92,46 @@ static const struct ingenic_cgu_clk_info jz4740_cgu_clocks[] = {
        [JZ4740_CLK_CCLK] = {
                "cclk", CGU_CLK_DIV,
                .parents = { JZ4740_CLK_PLL, -1, -1, -1 },
-               .div = { CGU_REG_CPCCR, 0, 1, 4, 22, -1, -1 },
+               .div = {
+                       CGU_REG_CPCCR, 0, 1, 4, 22, -1, -1,
+                       jz4740_cgu_cpccr_div_table,
+               },
        },
 
        [JZ4740_CLK_HCLK] = {
                "hclk", CGU_CLK_DIV,
                .parents = { JZ4740_CLK_PLL, -1, -1, -1 },
-               .div = { CGU_REG_CPCCR, 4, 1, 4, 22, -1, -1 },
+               .div = {
+                       CGU_REG_CPCCR, 4, 1, 4, 22, -1, -1,
+                       jz4740_cgu_cpccr_div_table,
+               },
        },
 
        [JZ4740_CLK_PCLK] = {
                "pclk", CGU_CLK_DIV,
                .parents = { JZ4740_CLK_PLL, -1, -1, -1 },
-               .div = { CGU_REG_CPCCR, 8, 1, 4, 22, -1, -1 },
+               .div = {
+                       CGU_REG_CPCCR, 8, 1, 4, 22, -1, -1,
+                       jz4740_cgu_cpccr_div_table,
+               },
        },
 
        [JZ4740_CLK_MCLK] = {
                "mclk", CGU_CLK_DIV,
                .parents = { JZ4740_CLK_PLL, -1, -1, -1 },
-               .div = { CGU_REG_CPCCR, 12, 1, 4, 22, -1, -1 },
+               .div = {
+                       CGU_REG_CPCCR, 12, 1, 4, 22, -1, -1,
+                       jz4740_cgu_cpccr_div_table,
+               },
        },
 
        [JZ4740_CLK_LCD] = {
                "lcd", CGU_CLK_DIV | CGU_CLK_GATE,
                .parents = { JZ4740_CLK_PLL_HALF, -1, -1, -1 },
-               .div = { CGU_REG_CPCCR, 16, 1, 5, 22, -1, -1 },
+               .div = {
+                       CGU_REG_CPCCR, 16, 1, 5, 22, -1, -1,
+                       jz4740_cgu_cpccr_div_table,
+               },
                .gate = { CGU_REG_CLKGR, 10 },
        },
 
@@ -219,77 +238,7 @@ static void __init jz4740_cgu_init(struct device_node *np)
        retval = ingenic_cgu_register_clocks(cgu);
        if (retval)
                pr_err("%s: failed to register CGU Clocks\n", __func__);
-}
-CLK_OF_DECLARE(jz4740_cgu, "ingenic,jz4740-cgu", jz4740_cgu_init);
-
-void jz4740_clock_set_wait_mode(enum jz4740_wait_mode mode)
-{
-       uint32_t lcr = readl(cgu->base + CGU_REG_LCR);
-
-       switch (mode) {
-       case JZ4740_WAIT_MODE_IDLE:
-               lcr &= ~LCR_SLEEP;
-               break;
-
-       case JZ4740_WAIT_MODE_SLEEP:
-               lcr |= LCR_SLEEP;
-               break;
-       }
-
-       writel(lcr, cgu->base + CGU_REG_LCR);
-}
 
-void jz4740_clock_udc_disable_auto_suspend(void)
-{
-       uint32_t clkgr = readl(cgu->base + CGU_REG_CLKGR);
-
-       clkgr &= ~CLKGR_UDC;
-       writel(clkgr, cgu->base + CGU_REG_CLKGR);
-}
-EXPORT_SYMBOL_GPL(jz4740_clock_udc_disable_auto_suspend);
-
-void jz4740_clock_udc_enable_auto_suspend(void)
-{
-       uint32_t clkgr = readl(cgu->base + CGU_REG_CLKGR);
-
-       clkgr |= CLKGR_UDC;
-       writel(clkgr, cgu->base + CGU_REG_CLKGR);
-}
-EXPORT_SYMBOL_GPL(jz4740_clock_udc_enable_auto_suspend);
-
-#define JZ_CLOCK_GATE_UART0    BIT(0)
-#define JZ_CLOCK_GATE_TCU      BIT(1)
-#define JZ_CLOCK_GATE_DMAC     BIT(12)
-
-void jz4740_clock_suspend(void)
-{
-       uint32_t clkgr, cppcr;
-
-       clkgr = readl(cgu->base + CGU_REG_CLKGR);
-       clkgr |= JZ_CLOCK_GATE_TCU | JZ_CLOCK_GATE_DMAC | JZ_CLOCK_GATE_UART0;
-       writel(clkgr, cgu->base + CGU_REG_CLKGR);
-
-       cppcr = readl(cgu->base + CGU_REG_CPPCR);
-       cppcr &= ~BIT(jz4740_cgu_clocks[JZ4740_CLK_PLL].pll.enable_bit);
-       writel(cppcr, cgu->base + CGU_REG_CPPCR);
-}
-
-void jz4740_clock_resume(void)
-{
-       uint32_t clkgr, cppcr, stable;
-
-       cppcr = readl(cgu->base + CGU_REG_CPPCR);
-       cppcr |= BIT(jz4740_cgu_clocks[JZ4740_CLK_PLL].pll.enable_bit);
-       writel(cppcr, cgu->base + CGU_REG_CPPCR);
-
-       stable = BIT(jz4740_cgu_clocks[JZ4740_CLK_PLL].pll.stable_bit);
-       do {
-               cppcr = readl(cgu->base + CGU_REG_CPPCR);
-       } while (!(cppcr & stable));
-
-       clkgr = readl(cgu->base + CGU_REG_CLKGR);
-       clkgr &= ~JZ_CLOCK_GATE_TCU;
-       clkgr &= ~JZ_CLOCK_GATE_DMAC;
-       clkgr &= ~JZ_CLOCK_GATE_UART0;
-       writel(clkgr, cgu->base + CGU_REG_CLKGR);
+       ingenic_cgu_register_syscore_ops(cgu);
 }
+CLK_OF_DECLARE(jz4740_cgu, "ingenic,jz4740-cgu", jz4740_cgu_init);
index dfce740..eebc1be 100644 (file)
@@ -9,9 +9,9 @@
 #include <linux/delay.h>
 #include <linux/io.h>
 #include <linux/of.h>
-#include <linux/syscore_ops.h>
 #include <dt-bindings/clock/jz4770-cgu.h>
 #include "cgu.h"
+#include "pm.h"
 
 /*
  * CPM registers offset address definition
@@ -38,9 +38,6 @@
 #define CGU_REG_MSC2CDR                0xA8
 #define CGU_REG_BCHCDR         0xAC
 
-/* bits within the LCR register */
-#define LCR_LPM                        BIT(0)          /* Low Power Mode */
-
 /* bits within the OPCR register */
 #define OPCR_SPENDH            BIT(5)          /* UHC PHY suspend */
 
@@ -87,6 +84,10 @@ static const s8 pll_od_encoding[8] = {
        0x0, 0x1, -1, 0x2, -1, -1, -1, 0x3,
 };
 
+static const u8 jz4770_cgu_cpccr_div_table[] = {
+       1, 2, 3, 4, 6, 8, 12,
+};
+
 static const struct ingenic_cgu_clk_info jz4770_cgu_clocks[] = {
 
        /* External clocks */
@@ -144,34 +145,52 @@ static const struct ingenic_cgu_clk_info jz4770_cgu_clocks[] = {
        [JZ4770_CLK_CCLK] = {
                "cclk", CGU_CLK_DIV,
                .parents = { JZ4770_CLK_PLL0, },
-               .div = { CGU_REG_CPCCR, 0, 1, 4, 22, -1, -1 },
+               .div = {
+                       CGU_REG_CPCCR, 0, 1, 4, 22, -1, -1,
+                       jz4770_cgu_cpccr_div_table,
+               },
        },
        [JZ4770_CLK_H0CLK] = {
                "h0clk", CGU_CLK_DIV,
                .parents = { JZ4770_CLK_PLL0, },
-               .div = { CGU_REG_CPCCR, 4, 1, 4, 22, -1, -1 },
+               .div = {
+                       CGU_REG_CPCCR, 4, 1, 4, 22, -1, -1,
+                       jz4770_cgu_cpccr_div_table,
+               },
        },
        [JZ4770_CLK_H1CLK] = {
                "h1clk", CGU_CLK_DIV | CGU_CLK_GATE,
                .parents = { JZ4770_CLK_PLL0, },
-               .div = { CGU_REG_CPCCR, 24, 1, 4, 22, -1, -1 },
+               .div = {
+                       CGU_REG_CPCCR, 24, 1, 4, 22, -1, -1,
+                       jz4770_cgu_cpccr_div_table,
+               },
                .gate = { CGU_REG_CLKGR1, 7 },
        },
        [JZ4770_CLK_H2CLK] = {
                "h2clk", CGU_CLK_DIV,
                .parents = { JZ4770_CLK_PLL0, },
-               .div = { CGU_REG_CPCCR, 16, 1, 4, 22, -1, -1 },
+               .div = {
+                       CGU_REG_CPCCR, 16, 1, 4, 22, -1, -1,
+                       jz4770_cgu_cpccr_div_table,
+               },
        },
        [JZ4770_CLK_C1CLK] = {
                "c1clk", CGU_CLK_DIV | CGU_CLK_GATE,
                .parents = { JZ4770_CLK_PLL0, },
-               .div = { CGU_REG_CPCCR, 12, 1, 4, 22, -1, -1 },
+               .div = {
+                       CGU_REG_CPCCR, 12, 1, 4, 22, -1, -1,
+                       jz4770_cgu_cpccr_div_table,
+               },
                .gate = { CGU_REG_OPCR, 31, true }, // disable CCLK stop on idle
        },
        [JZ4770_CLK_PCLK] = {
                "pclk", CGU_CLK_DIV,
                .parents = { JZ4770_CLK_PLL0, },
-               .div = { CGU_REG_CPCCR, 8, 1, 4, 22, -1, -1 },
+               .div = {
+                       CGU_REG_CPCCR, 8, 1, 4, 22, -1, -1,
+                       jz4770_cgu_cpccr_div_table,
+               },
        },
 
        /* Those divided clocks can connect to PLL0 or PLL1 */
@@ -407,30 +426,6 @@ static const struct ingenic_cgu_clk_info jz4770_cgu_clocks[] = {
        },
 };
 
-#if IS_ENABLED(CONFIG_PM_SLEEP)
-static int jz4770_cgu_pm_suspend(void)
-{
-       u32 val;
-
-       val = readl(cgu->base + CGU_REG_LCR);
-       writel(val | LCR_LPM, cgu->base + CGU_REG_LCR);
-       return 0;
-}
-
-static void jz4770_cgu_pm_resume(void)
-{
-       u32 val;
-
-       val = readl(cgu->base + CGU_REG_LCR);
-       writel(val & ~LCR_LPM, cgu->base + CGU_REG_LCR);
-}
-
-static struct syscore_ops jz4770_cgu_pm_ops = {
-       .suspend = jz4770_cgu_pm_suspend,
-       .resume = jz4770_cgu_pm_resume,
-};
-#endif /* CONFIG_PM_SLEEP */
-
 static void __init jz4770_cgu_init(struct device_node *np)
 {
        int retval;
@@ -444,9 +439,7 @@ static void __init jz4770_cgu_init(struct device_node *np)
        if (retval)
                pr_err("%s: failed to register CGU Clocks\n", __func__);
 
-#if IS_ENABLED(CONFIG_PM_SLEEP)
-       register_syscore_ops(&jz4770_cgu_pm_ops);
-#endif
+       ingenic_cgu_register_syscore_ops(cgu);
 }
 
 /* We only probe via devicetree, no need for a platform driver */
index 2464fc4..8c67f89 100644 (file)
@@ -12,6 +12,7 @@
 #include <linux/of.h>
 #include <dt-bindings/clock/jz4780-cgu.h>
 #include "cgu.h"
+#include "pm.h"
 
 /* CGU register offsets */
 #define CGU_REG_CLOCKCONTROL   0x00
@@ -721,5 +722,7 @@ static void __init jz4780_cgu_init(struct device_node *np)
                pr_err("%s: failed to register CGU Clocks\n", __func__);
                return;
        }
+
+       ingenic_cgu_register_syscore_ops(cgu);
 }
 CLK_OF_DECLARE(jz4780_cgu, "ingenic,jz4780-cgu", jz4780_cgu_init);
diff --git a/drivers/clk/ingenic/pm.c b/drivers/clk/ingenic/pm.c
new file mode 100644 (file)
index 0000000..341752b
--- /dev/null
@@ -0,0 +1,45 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (C) 2019 Paul Cercueil <paul@crapouillou.net>
+ */
+
+#include "cgu.h"
+#include "pm.h"
+
+#include <linux/io.h>
+#include <linux/syscore_ops.h>
+
+#define CGU_REG_LCR            0x04
+
+#define LCR_LOW_POWER_MODE     BIT(0)
+
+static void __iomem * __maybe_unused ingenic_cgu_base;
+
+static int __maybe_unused ingenic_cgu_pm_suspend(void)
+{
+       u32 val = readl(ingenic_cgu_base + CGU_REG_LCR);
+
+       writel(val | LCR_LOW_POWER_MODE, ingenic_cgu_base + CGU_REG_LCR);
+
+       return 0;
+}
+
+static void __maybe_unused ingenic_cgu_pm_resume(void)
+{
+       u32 val = readl(ingenic_cgu_base + CGU_REG_LCR);
+
+       writel(val & ~LCR_LOW_POWER_MODE, ingenic_cgu_base + CGU_REG_LCR);
+}
+
+static struct syscore_ops __maybe_unused ingenic_cgu_pm_ops = {
+       .suspend = ingenic_cgu_pm_suspend,
+       .resume = ingenic_cgu_pm_resume,
+};
+
+void ingenic_cgu_register_syscore_ops(struct ingenic_cgu *cgu)
+{
+       if (IS_ENABLED(CONFIG_PM_SLEEP)) {
+               ingenic_cgu_base = cgu->base;
+               register_syscore_ops(&ingenic_cgu_pm_ops);
+       }
+}
diff --git a/drivers/clk/ingenic/pm.h b/drivers/clk/ingenic/pm.h
new file mode 100644 (file)
index 0000000..fa75404
--- /dev/null
@@ -0,0 +1,12 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * Copyright (C) 2019 Paul Cercueil <paul@crapouillou.net>
+ */
+#ifndef DRIVERS_CLK_INGENIC_PM_H
+#define DRIVERS_CLK_INGENIC_PM_H
+
+struct ingenic_cgu;
+
+void ingenic_cgu_register_syscore_ops(struct ingenic_cgu *cgu);
+
+#endif /* DRIVERS_CLK_INGENIC_PM_H */
index 0ca6301..38aeefb 100644 (file)
@@ -15,3 +15,14 @@ config TI_SCI_CLK
          This adds the clock driver support over TI System Control Interface.
          If you wish to use clock resources from the PMMC firmware, say Y.
          Otherwise, say N.
+
+config TI_SCI_CLK_PROBE_FROM_FW
+       bool "Probe available clocks from firmware"
+       depends on TI_SCI_CLK
+       default n
+       help
+         Forces the TI SCI clock driver to probe available clocks from the
+         firmware. By default, only the used clocks are probed from DT.
+         This is mostly only useful for debugging purposes, and will
+         increase the boot time of the device. If you want the clocks probed
+         from firmware, say Y. Otherwise, say N.
index 4cb70be..7edf8c8 100644 (file)
@@ -23,6 +23,7 @@
 #include <linux/slab.h>
 #include <linux/soc/ti/ti_sci_protocol.h>
 #include <linux/bsearch.h>
+#include <linux/list_sort.h>
 
 #define SCI_CLK_SSC_ENABLE             BIT(0)
 #define SCI_CLK_ALLOW_FREQ_CHANGE      BIT(1)
@@ -52,14 +53,16 @@ struct sci_clk_provider {
  * @num_parents: Number of parents for this clock
  * @provider:   Master clock provider
  * @flags:      Flags for the clock
+ * @node:       Link for handling clocks probed via DT
  */
 struct sci_clk {
        struct clk_hw hw;
        u16 dev_id;
-       u8 clk_id;
-       u8 num_parents;
+       u32 clk_id;
+       u32 num_parents;
        struct sci_clk_provider *provider;
        u8 flags;
+       struct list_head node;
 };
 
 #define to_sci_clk(_hw) container_of(_hw, struct sci_clk, hw)
@@ -218,11 +221,11 @@ static int sci_clk_set_rate(struct clk_hw *hw, unsigned long rate,
 static u8 sci_clk_get_parent(struct clk_hw *hw)
 {
        struct sci_clk *clk = to_sci_clk(hw);
-       u8 parent_id;
+       u32 parent_id = 0;
        int ret;
 
        ret = clk->provider->ops->get_parent(clk->provider->sci, clk->dev_id,
-                                            clk->clk_id, &parent_id);
+                                            clk->clk_id, (void *)&parent_id);
        if (ret) {
                dev_err(clk->provider->dev,
                        "get-parent failed for dev=%d, clk=%d, ret=%d\n",
@@ -230,7 +233,9 @@ static u8 sci_clk_get_parent(struct clk_hw *hw)
                return 0;
        }
 
-       return parent_id - clk->clk_id - 1;
+       parent_id = parent_id - clk->clk_id - 1;
+
+       return (u8)parent_id;
 }
 
 /**
@@ -280,8 +285,8 @@ static int _sci_clk_build(struct sci_clk_provider *provider,
        int i;
        int ret = 0;
 
-       name = kasprintf(GFP_KERNEL, "%s:%d:%d", dev_name(provider->dev),
-                        sci_clk->dev_id, sci_clk->clk_id);
+       name = kasprintf(GFP_KERNEL, "clk:%d:%d", sci_clk->dev_id,
+                        sci_clk->clk_id);
 
        init.name = name;
 
@@ -306,8 +311,7 @@ static int _sci_clk_build(struct sci_clk_provider *provider,
                for (i = 0; i < sci_clk->num_parents; i++) {
                        char *parent_name;
 
-                       parent_name = kasprintf(GFP_KERNEL, "%s:%d:%d",
-                                               dev_name(provider->dev),
+                       parent_name = kasprintf(GFP_KERNEL, "clk:%d:%d",
                                                sci_clk->dev_id,
                                                sci_clk->clk_id + 1 + i);
                        if (!parent_name) {
@@ -404,22 +408,9 @@ static const struct of_device_id ti_sci_clk_of_match[] = {
 };
 MODULE_DEVICE_TABLE(of, ti_sci_clk_of_match);
 
-/**
- * ti_sci_clk_probe - Probe function for the TI SCI clock driver
- * @pdev: platform device pointer to be probed
- *
- * Probes the TI SCI clock device. Allocates a new clock provider
- * and registers this to the common clock framework. Also applies
- * any required flags to the identified clocks via clock lists
- * supplied from DT. Returns 0 for success, negative error value
- * for failure.
- */
-static int ti_sci_clk_probe(struct platform_device *pdev)
+#ifdef CONFIG_TI_SCI_CLK_PROBE_FROM_FW
+static int ti_sci_scan_clocks_from_fw(struct sci_clk_provider *provider)
 {
-       struct device *dev = &pdev->dev;
-       struct device_node *np = dev->of_node;
-       struct sci_clk_provider *provider;
-       const struct ti_sci_handle *handle;
        int ret;
        int num_clks = 0;
        struct sci_clk **clks = NULL;
@@ -428,24 +419,14 @@ static int ti_sci_clk_probe(struct platform_device *pdev)
        int max_clks = 0;
        int clk_id = 0;
        int dev_id = 0;
-       u8 num_parents;
+       u32 num_parents = 0;
        int gap_size = 0;
-
-       handle = devm_ti_sci_get_handle(dev);
-       if (IS_ERR(handle))
-               return PTR_ERR(handle);
-
-       provider = devm_kzalloc(dev, sizeof(*provider), GFP_KERNEL);
-       if (!provider)
-               return -ENOMEM;
-
-       provider->sci = handle;
-       provider->ops = &handle->ops.clk_ops;
-       provider->dev = dev;
+       struct device *dev = provider->dev;
 
        while (1) {
                ret = provider->ops->get_num_parents(provider->sci, dev_id,
-                                                    clk_id, &num_parents);
+                                                    clk_id,
+                                                    (void *)&num_parents);
                if (ret) {
                        gap_size++;
                        if (!clk_id) {
@@ -502,6 +483,188 @@ static int ti_sci_clk_probe(struct platform_device *pdev)
 
        devm_kfree(dev, clks);
 
+       return 0;
+}
+
+#else
+
+static int _cmp_sci_clk_list(void *priv, struct list_head *a,
+                            struct list_head *b)
+{
+       struct sci_clk *ca = container_of(a, struct sci_clk, node);
+       struct sci_clk *cb = container_of(b, struct sci_clk, node);
+
+       return _cmp_sci_clk(ca, &cb);
+}
+
+static int ti_sci_scan_clocks_from_dt(struct sci_clk_provider *provider)
+{
+       struct device *dev = provider->dev;
+       struct device_node *np = NULL;
+       int ret;
+       int index;
+       struct of_phandle_args args;
+       struct list_head clks;
+       struct sci_clk *sci_clk, *prev;
+       int num_clks = 0;
+       int num_parents;
+       int clk_id;
+       const char * const clk_names[] = {
+               "clocks", "assigned-clocks", "assigned-clock-parents", NULL
+       };
+       const char * const *clk_name;
+
+       INIT_LIST_HEAD(&clks);
+
+       clk_name = clk_names;
+
+       while (*clk_name) {
+               np = of_find_node_with_property(np, *clk_name);
+               if (!np) {
+                       clk_name++;
+                       break;
+               }
+
+               if (!of_device_is_available(np))
+                       continue;
+
+               index = 0;
+
+               do {
+                       ret = of_parse_phandle_with_args(np, *clk_name,
+                                                        "#clock-cells", index,
+                                                        &args);
+                       if (ret)
+                               break;
+
+                       if (args.args_count == 2 && args.np == dev->of_node) {
+                               sci_clk = devm_kzalloc(dev, sizeof(*sci_clk),
+                                                      GFP_KERNEL);
+                               if (!sci_clk)
+                                       return -ENOMEM;
+
+                               sci_clk->dev_id = args.args[0];
+                               sci_clk->clk_id = args.args[1];
+                               sci_clk->provider = provider;
+                               provider->ops->get_num_parents(provider->sci,
+                                                              sci_clk->dev_id,
+                                                              sci_clk->clk_id,
+                                                              (void *)&sci_clk->num_parents);
+                               list_add_tail(&sci_clk->node, &clks);
+
+                               num_clks++;
+
+                               num_parents = sci_clk->num_parents;
+                               if (num_parents == 1)
+                                       num_parents = 0;
+
+                               /*
+                                * Linux kernel has inherent limitation
+                                * of 255 clock parents at the moment.
+                                * Right now, it is not expected that
+                                * any mux clock from sci-clk driver
+                                * would exceed that limit either, but
+                                * the ABI basically provides that
+                                * possibility. Print out a warning if
+                                * this happens for any clock.
+                                */
+                               if (num_parents >= 255) {
+                                       dev_warn(dev, "too many parents for dev=%d, clk=%d (%d), cropping to 255.\n",
+                                                sci_clk->dev_id,
+                                                sci_clk->clk_id, num_parents);
+                                       num_parents = 255;
+                               }
+
+                               clk_id = args.args[1] + 1;
+
+                               while (num_parents--) {
+                                       sci_clk = devm_kzalloc(dev,
+                                                              sizeof(*sci_clk),
+                                                              GFP_KERNEL);
+                                       if (!sci_clk)
+                                               return -ENOMEM;
+                                       sci_clk->dev_id = args.args[0];
+                                       sci_clk->clk_id = clk_id++;
+                                       sci_clk->provider = provider;
+                                       list_add_tail(&sci_clk->node, &clks);
+
+                                       num_clks++;
+                               }
+                       }
+
+                       index++;
+               } while (args.np);
+       }
+
+       list_sort(NULL, &clks, _cmp_sci_clk_list);
+
+       provider->clocks = devm_kmalloc_array(dev, num_clks, sizeof(sci_clk),
+                                             GFP_KERNEL);
+       if (!provider->clocks)
+               return -ENOMEM;
+
+       num_clks = 0;
+       prev = NULL;
+
+       list_for_each_entry(sci_clk, &clks, node) {
+               if (prev && prev->dev_id == sci_clk->dev_id &&
+                   prev->clk_id == sci_clk->clk_id)
+                       continue;
+
+               provider->clocks[num_clks++] = sci_clk;
+               prev = sci_clk;
+       }
+
+       provider->num_clocks = num_clks;
+
+       return 0;
+}
+#endif
+
+/**
+ * ti_sci_clk_probe - Probe function for the TI SCI clock driver
+ * @pdev: platform device pointer to be probed
+ *
+ * Probes the TI SCI clock device. Allocates a new clock provider
+ * and registers this to the common clock framework. Also applies
+ * any required flags to the identified clocks via clock lists
+ * supplied from DT. Returns 0 for success, negative error value
+ * for failure.
+ */
+static int ti_sci_clk_probe(struct platform_device *pdev)
+{
+       struct device *dev = &pdev->dev;
+       struct device_node *np = dev->of_node;
+       struct sci_clk_provider *provider;
+       const struct ti_sci_handle *handle;
+       int ret;
+
+       handle = devm_ti_sci_get_handle(dev);
+       if (IS_ERR(handle))
+               return PTR_ERR(handle);
+
+       provider = devm_kzalloc(dev, sizeof(*provider), GFP_KERNEL);
+       if (!provider)
+               return -ENOMEM;
+
+       provider->sci = handle;
+       provider->ops = &handle->ops.clk_ops;
+       provider->dev = dev;
+
+#ifdef CONFIG_TI_SCI_CLK_PROBE_FROM_FW
+       ret = ti_sci_scan_clocks_from_fw(provider);
+       if (ret) {
+               dev_err(dev, "scan clocks from FW failed: %d\n", ret);
+               return ret;
+       }
+#else
+       ret = ti_sci_scan_clocks_from_dt(provider);
+       if (ret) {
+               dev_err(dev, "scan clocks from DT failed: %d\n", ret);
+               return ret;
+       }
+#endif
+
        ret = ti_sci_init_clocks(provider);
        if (ret) {
                pr_err("ti-sci-init-clocks failed.\n");
index f797f09..ce3d9b3 100644 (file)
@@ -300,4 +300,10 @@ config COMMON_CLK_MT8516
        help
          This driver supports MediaTek MT8516 clocks.
 
+config COMMON_CLK_MT8516_AUDSYS
+       bool "Clock driver for MediaTek MT8516 audsys"
+       depends on COMMON_CLK_MT8516
+       help
+         This driver supports MediaTek MT8516 audsys clocks.
+
 endmenu
index f74937b..672de00 100644 (file)
@@ -45,3 +45,4 @@ obj-$(CONFIG_COMMON_CLK_MT8183_MMSYS) += clk-mt8183-mm.o
 obj-$(CONFIG_COMMON_CLK_MT8183_VDECSYS) += clk-mt8183-vdec.o
 obj-$(CONFIG_COMMON_CLK_MT8183_VENCSYS) += clk-mt8183-venc.o
 obj-$(CONFIG_COMMON_CLK_MT8516) += clk-mt8516.o
+obj-$(CONFIG_COMMON_CLK_MT8516_AUDSYS) += clk-mt8516-aud.o
index 9d86510..1aa5f40 100644 (file)
@@ -395,14 +395,6 @@ static const char * const atb_parents[] = {
        "syspll_d5"
 };
 
-static const char * const sspm_parents[] = {
-       "clk26m",
-       "univpll_d2_d4",
-       "syspll_d2_d2",
-       "univpll_d2_d2",
-       "syspll_d3"
-};
-
 static const char * const dpi0_parents[] = {
        "clk26m",
        "tvdpll_d2",
@@ -606,9 +598,6 @@ static const struct mtk_mux top_muxes[] = {
        MUX_GATE_CLR_SET_UPD(CLK_TOP_MUX_ATB, "atb_sel",
                atb_parents, 0xa0,
                0xa4, 0xa8, 0, 2, 7, 0x004, 24),
-       MUX_GATE_CLR_SET_UPD(CLK_TOP_MUX_SSPM, "sspm_sel",
-               sspm_parents, 0xa0,
-               0xa4, 0xa8, 8, 3, 15, 0x004, 25),
        MUX_GATE_CLR_SET_UPD(CLK_TOP_MUX_DPI0, "dpi0_sel",
                dpi0_parents, 0xa0,
                0xa4, 0xa8, 16, 4, 23, 0x004, 26),
@@ -947,12 +936,8 @@ static const struct mtk_gate infra_clks[] = {
                "fufs_sel", 13),
        GATE_INFRA2(CLK_INFRA_MD32_BCLK, "infra_md32_bclk",
                "axi_sel", 14),
-       GATE_INFRA2(CLK_INFRA_SSPM, "infra_sspm",
-               "sspm_sel", 15),
        GATE_INFRA2(CLK_INFRA_UNIPRO_MBIST, "infra_unipro_mbist",
                "axi_sel", 16),
-       GATE_INFRA2(CLK_INFRA_SSPM_BUS_HCLK, "infra_sspm_bus_hclk",
-               "axi_sel", 17),
        GATE_INFRA2(CLK_INFRA_I2C5, "infra_i2c5",
                "i2c_sel", 18),
        GATE_INFRA2(CLK_INFRA_I2C5_ARBITER, "infra_i2c5_arbiter",
@@ -986,10 +971,6 @@ static const struct mtk_gate infra_clks[] = {
                "msdc50_0_sel", 1),
        GATE_INFRA3(CLK_INFRA_MSDC2_SELF, "infra_msdc2_self",
                "msdc50_0_sel", 2),
-       GATE_INFRA3(CLK_INFRA_SSPM_26M_SELF, "infra_sspm_26m_self",
-               "f_f26m_ck", 3),
-       GATE_INFRA3(CLK_INFRA_SSPM_32K_SELF, "infra_sspm_32k_self",
-               "f_f26m_ck", 4),
        GATE_INFRA3(CLK_INFRA_UFS_AXI, "infra_ufs_axi",
                "axi_sel", 5),
        GATE_INFRA3(CLK_INFRA_I2C6, "infra_i2c6",
diff --git a/drivers/clk/mediatek/clk-mt8516-aud.c b/drivers/clk/mediatek/clk-mt8516-aud.c
new file mode 100644 (file)
index 0000000..6ab3a06
--- /dev/null
@@ -0,0 +1,65 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (c) 2019 MediaTek Inc.
+ * Author: James Liao <jamesjj.liao@mediatek.com>
+ *         Fabien Parent <fparent@baylibre.com>
+ */
+
+#include <linux/clk-provider.h>
+#include <linux/of.h>
+#include <linux/of_address.h>
+#include <linux/of_device.h>
+#include <linux/platform_device.h>
+
+#include "clk-mtk.h"
+#include "clk-gate.h"
+
+#include <dt-bindings/clock/mt8516-clk.h>
+
+static const struct mtk_gate_regs aud_cg_regs = {
+       .set_ofs = 0x0,
+       .clr_ofs = 0x0,
+       .sta_ofs = 0x0,
+};
+
+#define GATE_AUD(_id, _name, _parent, _shift) {        \
+               .id = _id,                      \
+               .name = _name,                  \
+               .parent_name = _parent,         \
+               .regs = &aud_cg_regs,           \
+               .shift = _shift,                \
+               .ops = &mtk_clk_gate_ops_no_setclr,             \
+       }
+
+static const struct mtk_gate aud_clks[] __initconst = {
+       GATE_AUD(CLK_AUD_AFE, "aud_afe", "clk26m_ck", 2),
+       GATE_AUD(CLK_AUD_I2S, "aud_i2s", "i2s_infra_bck", 6),
+       GATE_AUD(CLK_AUD_22M, "aud_22m", "rg_aud_engen1", 8),
+       GATE_AUD(CLK_AUD_24M, "aud_24m", "rg_aud_engen2", 9),
+       GATE_AUD(CLK_AUD_INTDIR, "aud_intdir", "rg_aud_spdif_in", 15),
+       GATE_AUD(CLK_AUD_APLL2_TUNER, "aud_apll2_tuner", "rg_aud_engen2", 18),
+       GATE_AUD(CLK_AUD_APLL_TUNER, "aud_apll_tuner", "rg_aud_engen1", 19),
+       GATE_AUD(CLK_AUD_HDMI, "aud_hdmi", "apll12_div4", 20),
+       GATE_AUD(CLK_AUD_SPDF, "aud_spdf", "apll12_div6", 21),
+       GATE_AUD(CLK_AUD_ADC, "aud_adc", "aud_afe", 24),
+       GATE_AUD(CLK_AUD_DAC, "aud_dac", "aud_afe", 25),
+       GATE_AUD(CLK_AUD_DAC_PREDIS, "aud_dac_predis", "aud_afe", 26),
+       GATE_AUD(CLK_AUD_TML, "aud_tml", "aud_afe", 27),
+};
+
+static void __init mtk_audsys_init(struct device_node *node)
+{
+       struct clk_onecell_data *clk_data;
+       int r;
+
+       clk_data = mtk_alloc_clk_data(CLK_AUD_NR_CLK);
+
+       mtk_clk_register_gates(node, aud_clks, ARRAY_SIZE(aud_clks), clk_data);
+
+       r = of_clk_add_provider(node, of_clk_src_onecell_get, clk_data);
+       if (r)
+               pr_err("%s(): could not register clock provider: %d\n",
+                       __func__, r);
+
+}
+CLK_OF_DECLARE(mtk_audsys, "mediatek,mt8516-audsys", mtk_audsys_init);
index 26fe43c..9d4261e 100644 (file)
@@ -231,11 +231,6 @@ static const char * const nfi1x_pad_parents[] __initconst = {
        "nfi1x_ck"
 };
 
-static const char * const ddrphycfg_parents[] __initconst = {
-       "clk26m_ck",
-       "mainpll_d16"
-};
-
 static const char * const usb_78m_parents[] __initconst = {
        "clk_null",
        "clk26m_ck",
index 7a8ef80..3ddd0ef 100644 (file)
@@ -469,11 +469,6 @@ static struct clk_regmap axg_mpll0_div = {
                        .shift   = 16,
                        .width   = 9,
                },
-               .ssen = {
-                       .reg_off = HHI_MPLL_CNTL,
-                       .shift   = 25,
-                       .width   = 1,
-               },
                .misc = {
                        .reg_off = HHI_PLL_TOP_MISC,
                        .shift   = 0,
@@ -568,6 +563,11 @@ static struct clk_regmap axg_mpll2_div = {
                        .shift   = 16,
                        .width   = 9,
                },
+               .ssen = {
+                       .reg_off = HHI_MPLL_CNTL,
+                       .shift   = 25,
+                       .width   = 1,
+               },
                .misc = {
                        .reg_off = HHI_PLL_TOP_MISC,
                        .shift   = 2,
index f76850d..2d39a8b 100644 (file)
@@ -115,21 +115,12 @@ static int mpll_set_rate(struct clk_hw *hw,
        else
                __acquire(mpll->lock);
 
-       /* Enable and set the fractional part */
+       /* Set the fractional part */
        meson_parm_write(clk->map, &mpll->sdm, sdm);
-       meson_parm_write(clk->map, &mpll->sdm_en, 1);
-
-       /* Set additional fractional part enable if required */
-       if (MESON_PARM_APPLICABLE(&mpll->ssen))
-               meson_parm_write(clk->map, &mpll->ssen, 1);
 
        /* Set the integer divider part */
        meson_parm_write(clk->map, &mpll->n2, n2);
 
-       /* Set the magic misc bit if required */
-       if (MESON_PARM_APPLICABLE(&mpll->misc))
-               meson_parm_write(clk->map, &mpll->misc, 1);
-
        if (mpll->lock)
                spin_unlock_irqrestore(mpll->lock, flags);
        else
@@ -138,6 +129,30 @@ static int mpll_set_rate(struct clk_hw *hw,
        return 0;
 }
 
+static void mpll_init(struct clk_hw *hw)
+{
+       struct clk_regmap *clk = to_clk_regmap(hw);
+       struct meson_clk_mpll_data *mpll = meson_clk_mpll_data(clk);
+
+       if (mpll->init_count)
+               regmap_multi_reg_write(clk->map, mpll->init_regs,
+                                      mpll->init_count);
+
+       /* Enable the fractional part */
+       meson_parm_write(clk->map, &mpll->sdm_en, 1);
+
+       /* Set spread spectrum if possible */
+       if (MESON_PARM_APPLICABLE(&mpll->ssen)) {
+               unsigned int ss =
+                       mpll->flags & CLK_MESON_MPLL_SPREAD_SPECTRUM ? 1 : 0;
+               meson_parm_write(clk->map, &mpll->ssen, ss);
+       }
+
+       /* Set the magic misc bit if required */
+       if (MESON_PARM_APPLICABLE(&mpll->misc))
+               meson_parm_write(clk->map, &mpll->misc, 1);
+}
+
 const struct clk_ops meson_clk_mpll_ro_ops = {
        .recalc_rate    = mpll_recalc_rate,
        .round_rate     = mpll_round_rate,
@@ -148,6 +163,7 @@ const struct clk_ops meson_clk_mpll_ops = {
        .recalc_rate    = mpll_recalc_rate,
        .round_rate     = mpll_round_rate,
        .set_rate       = mpll_set_rate,
+       .init           = mpll_init,
 };
 EXPORT_SYMBOL_GPL(meson_clk_mpll_ops);
 
index cf79340..a991d56 100644 (file)
@@ -18,11 +18,14 @@ struct meson_clk_mpll_data {
        struct parm n2;
        struct parm ssen;
        struct parm misc;
+       const struct reg_sequence *init_regs;
+       unsigned int init_count;
        spinlock_t *lock;
        u8 flags;
 };
 
 #define CLK_MESON_MPLL_ROUND_CLOSEST   BIT(0)
+#define CLK_MESON_MPLL_SPREAD_SPECTRUM BIT(1)
 
 extern const struct clk_ops meson_clk_mpll_ro_ops;
 extern const struct clk_ops meson_clk_mpll_ops;
index 206fafd..db1c4ed 100644 (file)
@@ -150,6 +150,57 @@ static struct clk_regmap g12a_sys_pll = {
        },
 };
 
+static struct clk_regmap g12b_sys1_pll_dco = {
+       .data = &(struct meson_clk_pll_data){
+               .en = {
+                       .reg_off = HHI_SYS1_PLL_CNTL0,
+                       .shift   = 28,
+                       .width   = 1,
+               },
+               .m = {
+                       .reg_off = HHI_SYS1_PLL_CNTL0,
+                       .shift   = 0,
+                       .width   = 8,
+               },
+               .n = {
+                       .reg_off = HHI_SYS1_PLL_CNTL0,
+                       .shift   = 10,
+                       .width   = 5,
+               },
+               .l = {
+                       .reg_off = HHI_SYS1_PLL_CNTL0,
+                       .shift   = 31,
+                       .width   = 1,
+               },
+               .rst = {
+                       .reg_off = HHI_SYS1_PLL_CNTL0,
+                       .shift   = 29,
+                       .width   = 1,
+               },
+       },
+       .hw.init = &(struct clk_init_data){
+               .name = "sys1_pll_dco",
+               .ops = &meson_clk_pll_ro_ops,
+               .parent_names = (const char *[]){ IN_PREFIX "xtal" },
+               .num_parents = 1,
+       },
+};
+
+static struct clk_regmap g12b_sys1_pll = {
+       .data = &(struct clk_regmap_div_data){
+               .offset = HHI_SYS1_PLL_CNTL0,
+               .shift = 16,
+               .width = 3,
+               .flags = CLK_DIVIDER_POWER_OF_TWO,
+       },
+       .hw.init = &(struct clk_init_data){
+               .name = "sys1_pll",
+               .ops = &clk_regmap_divider_ro_ops,
+               .parent_names = (const char *[]){ "sys1_pll_dco" },
+               .num_parents = 1,
+       },
+};
+
 static struct clk_regmap g12a_sys_pll_div16_en = {
        .data = &(struct clk_regmap_gate_data){
                .offset = HHI_SYS_CPU_CLK_CNTL1,
@@ -167,6 +218,23 @@ static struct clk_regmap g12a_sys_pll_div16_en = {
        },
 };
 
+static struct clk_regmap g12b_sys1_pll_div16_en = {
+       .data = &(struct clk_regmap_gate_data){
+               .offset = HHI_SYS_CPUB_CLK_CNTL1,
+               .bit_idx = 24,
+       },
+       .hw.init = &(struct clk_init_data) {
+               .name = "sys1_pll_div16_en",
+               .ops = &clk_regmap_gate_ro_ops,
+               .parent_names = (const char *[]){ "sys1_pll" },
+               .num_parents = 1,
+               /*
+                * This clock is used to debug the sys_pll range
+                * Linux should not change it at runtime
+                */
+       },
+};
+
 static struct clk_fixed_factor g12a_sys_pll_div16 = {
        .mult = 1,
        .div = 16,
@@ -178,6 +246,17 @@ static struct clk_fixed_factor g12a_sys_pll_div16 = {
        },
 };
 
+static struct clk_fixed_factor g12b_sys1_pll_div16 = {
+       .mult = 1,
+       .div = 16,
+       .hw.init = &(struct clk_init_data){
+               .name = "sys1_pll_div16",
+               .ops = &clk_fixed_factor_ops,
+               .parent_names = (const char *[]){ "sys1_pll_div16_en" },
+               .num_parents = 1,
+       },
+};
+
 /* Datasheet names this field as "premux0" */
 static struct clk_regmap g12a_cpu_clk_premux0 = {
        .data = &(struct clk_regmap_mux_data){
@@ -306,6 +385,150 @@ static struct clk_regmap g12a_cpu_clk = {
        },
 };
 
+/* Datasheet names this field as "Final_mux_sel" */
+static struct clk_regmap g12b_cpu_clk = {
+       .data = &(struct clk_regmap_mux_data){
+               .offset = HHI_SYS_CPU_CLK_CNTL0,
+               .mask = 0x1,
+               .shift = 11,
+       },
+       .hw.init = &(struct clk_init_data){
+               .name = "cpu_clk",
+               .ops = &clk_regmap_mux_ro_ops,
+               .parent_names = (const char *[]){ "cpu_clk_dyn",
+                                                 "sys1_pll" },
+               .num_parents = 2,
+       },
+};
+
+/* Datasheet names this field as "premux0" */
+static struct clk_regmap g12b_cpub_clk_premux0 = {
+       .data = &(struct clk_regmap_mux_data){
+               .offset = HHI_SYS_CPUB_CLK_CNTL,
+               .mask = 0x3,
+               .shift = 0,
+       },
+       .hw.init = &(struct clk_init_data){
+               .name = "cpub_clk_dyn0_sel",
+               .ops = &clk_regmap_mux_ro_ops,
+               .parent_names = (const char *[]){ IN_PREFIX "xtal",
+                                                 "fclk_div2",
+                                                 "fclk_div3" },
+               .num_parents = 3,
+       },
+};
+
+/* Datasheet names this field as "mux0_divn_tcnt" */
+static struct clk_regmap g12b_cpub_clk_mux0_div = {
+       .data = &(struct clk_regmap_div_data){
+               .offset = HHI_SYS_CPUB_CLK_CNTL,
+               .shift = 4,
+               .width = 6,
+       },
+       .hw.init = &(struct clk_init_data){
+               .name = "cpub_clk_dyn0_div",
+               .ops = &clk_regmap_divider_ro_ops,
+               .parent_names = (const char *[]){ "cpub_clk_dyn0_sel" },
+               .num_parents = 1,
+       },
+};
+
+/* Datasheet names this field as "postmux0" */
+static struct clk_regmap g12b_cpub_clk_postmux0 = {
+       .data = &(struct clk_regmap_mux_data){
+               .offset = HHI_SYS_CPUB_CLK_CNTL,
+               .mask = 0x1,
+               .shift = 2,
+       },
+       .hw.init = &(struct clk_init_data){
+               .name = "cpub_clk_dyn0",
+               .ops = &clk_regmap_mux_ro_ops,
+               .parent_names = (const char *[]){ "cpub_clk_dyn0_sel",
+                                                 "cpub_clk_dyn0_div" },
+               .num_parents = 2,
+       },
+};
+
+/* Datasheet names this field as "premux1" */
+static struct clk_regmap g12b_cpub_clk_premux1 = {
+       .data = &(struct clk_regmap_mux_data){
+               .offset = HHI_SYS_CPUB_CLK_CNTL,
+               .mask = 0x3,
+               .shift = 16,
+       },
+       .hw.init = &(struct clk_init_data){
+               .name = "cpub_clk_dyn1_sel",
+               .ops = &clk_regmap_mux_ro_ops,
+               .parent_names = (const char *[]){ IN_PREFIX "xtal",
+                                                 "fclk_div2",
+                                                 "fclk_div3" },
+               .num_parents = 3,
+       },
+};
+
+/* Datasheet names this field as "Mux1_divn_tcnt" */
+static struct clk_regmap g12b_cpub_clk_mux1_div = {
+       .data = &(struct clk_regmap_div_data){
+               .offset = HHI_SYS_CPUB_CLK_CNTL,
+               .shift = 20,
+               .width = 6,
+       },
+       .hw.init = &(struct clk_init_data){
+               .name = "cpub_clk_dyn1_div",
+               .ops = &clk_regmap_divider_ro_ops,
+               .parent_names = (const char *[]){ "cpub_clk_dyn1_sel" },
+               .num_parents = 1,
+       },
+};
+
+/* Datasheet names this field as "postmux1" */
+static struct clk_regmap g12b_cpub_clk_postmux1 = {
+       .data = &(struct clk_regmap_mux_data){
+               .offset = HHI_SYS_CPUB_CLK_CNTL,
+               .mask = 0x1,
+               .shift = 18,
+       },
+       .hw.init = &(struct clk_init_data){
+               .name = "cpub_clk_dyn1",
+               .ops = &clk_regmap_mux_ro_ops,
+               .parent_names = (const char *[]){ "cpub_clk_dyn1_sel",
+                                                 "cpub_clk_dyn1_div" },
+               .num_parents = 2,
+       },
+};
+
+/* Datasheet names this field as "Final_dyn_mux_sel" */
+static struct clk_regmap g12b_cpub_clk_dyn = {
+       .data = &(struct clk_regmap_mux_data){
+               .offset = HHI_SYS_CPUB_CLK_CNTL,
+               .mask = 0x1,
+               .shift = 10,
+       },
+       .hw.init = &(struct clk_init_data){
+               .name = "cpub_clk_dyn",
+               .ops = &clk_regmap_mux_ro_ops,
+               .parent_names = (const char *[]){ "cpub_clk_dyn0",
+                                                 "cpub_clk_dyn1" },
+               .num_parents = 2,
+       },
+};
+
+/* Datasheet names this field as "Final_mux_sel" */
+static struct clk_regmap g12b_cpub_clk = {
+       .data = &(struct clk_regmap_mux_data){
+               .offset = HHI_SYS_CPUB_CLK_CNTL,
+               .mask = 0x1,
+               .shift = 11,
+       },
+       .hw.init = &(struct clk_init_data){
+               .name = "cpub_clk",
+               .ops = &clk_regmap_mux_ro_ops,
+               .parent_names = (const char *[]){ "cpub_clk_dyn",
+                                                 "sys_pll" },
+               .num_parents = 2,
+       },
+};
+
 static struct clk_regmap g12a_cpu_clk_div16_en = {
        .data = &(struct clk_regmap_gate_data){
                .offset = HHI_SYS_CPU_CLK_CNTL1,
@@ -323,6 +546,23 @@ static struct clk_regmap g12a_cpu_clk_div16_en = {
        },
 };
 
+static struct clk_regmap g12b_cpub_clk_div16_en = {
+       .data = &(struct clk_regmap_gate_data){
+               .offset = HHI_SYS_CPUB_CLK_CNTL1,
+               .bit_idx = 1,
+       },
+       .hw.init = &(struct clk_init_data) {
+               .name = "cpub_clk_div16_en",
+               .ops = &clk_regmap_gate_ro_ops,
+               .parent_names = (const char *[]){ "cpub_clk" },
+               .num_parents = 1,
+               /*
+                * This clock is used to debug the cpu_clk range
+                * Linux should not change it at runtime
+                */
+       },
+};
+
 static struct clk_fixed_factor g12a_cpu_clk_div16 = {
        .mult = 1,
        .div = 16,
@@ -334,6 +574,17 @@ static struct clk_fixed_factor g12a_cpu_clk_div16 = {
        },
 };
 
+static struct clk_fixed_factor g12b_cpub_clk_div16 = {
+       .mult = 1,
+       .div = 16,
+       .hw.init = &(struct clk_init_data){
+               .name = "cpub_clk_div16",
+               .ops = &clk_fixed_factor_ops,
+               .parent_names = (const char *[]){ "cpub_clk_div16_en" },
+               .num_parents = 1,
+       },
+};
+
 static struct clk_regmap g12a_cpu_clk_apb_div = {
        .data = &(struct clk_regmap_div_data){
                .offset = HHI_SYS_CPU_CLK_CNTL1,
@@ -445,15 +696,249 @@ static struct clk_regmap g12a_cpu_clk_trace_div = {
        },
 };
 
-static struct clk_regmap g12a_cpu_clk_trace = {
+static struct clk_regmap g12a_cpu_clk_trace = {
+       .data = &(struct clk_regmap_gate_data){
+               .offset = HHI_SYS_CPU_CLK_CNTL1,
+               .bit_idx = 23,
+       },
+       .hw.init = &(struct clk_init_data) {
+               .name = "cpu_clk_trace",
+               .ops = &clk_regmap_gate_ro_ops,
+               .parent_names = (const char *[]){ "cpu_clk_trace_div" },
+               .num_parents = 1,
+               /*
+                * This clock is set by the ROM monitor code,
+                * Linux should not change it at runtime
+                */
+       },
+};
+
+static struct clk_fixed_factor g12b_cpub_clk_div2 = {
+       .mult = 1,
+       .div = 2,
+       .hw.init = &(struct clk_init_data){
+               .name = "cpub_clk_div2",
+               .ops = &clk_fixed_factor_ops,
+               .parent_names = (const char *[]){ "cpub_clk" },
+               .num_parents = 1,
+       },
+};
+
+static struct clk_fixed_factor g12b_cpub_clk_div3 = {
+       .mult = 1,
+       .div = 3,
+       .hw.init = &(struct clk_init_data){
+               .name = "cpub_clk_div3",
+               .ops = &clk_fixed_factor_ops,
+               .parent_names = (const char *[]){ "cpub_clk" },
+               .num_parents = 1,
+       },
+};
+
+static struct clk_fixed_factor g12b_cpub_clk_div4 = {
+       .mult = 1,
+       .div = 4,
+       .hw.init = &(struct clk_init_data){
+               .name = "cpub_clk_div4",
+               .ops = &clk_fixed_factor_ops,
+               .parent_names = (const char *[]){ "cpub_clk" },
+               .num_parents = 1,
+       },
+};
+
+static struct clk_fixed_factor g12b_cpub_clk_div5 = {
+       .mult = 1,
+       .div = 5,
+       .hw.init = &(struct clk_init_data){
+               .name = "cpub_clk_div5",
+               .ops = &clk_fixed_factor_ops,
+               .parent_names = (const char *[]){ "cpub_clk" },
+               .num_parents = 1,
+       },
+};
+
+static struct clk_fixed_factor g12b_cpub_clk_div6 = {
+       .mult = 1,
+       .div = 6,
+       .hw.init = &(struct clk_init_data){
+               .name = "cpub_clk_div6",
+               .ops = &clk_fixed_factor_ops,
+               .parent_names = (const char *[]){ "cpub_clk" },
+               .num_parents = 1,
+       },
+};
+
+static struct clk_fixed_factor g12b_cpub_clk_div7 = {
+       .mult = 1,
+       .div = 7,
+       .hw.init = &(struct clk_init_data){
+               .name = "cpub_clk_div7",
+               .ops = &clk_fixed_factor_ops,
+               .parent_names = (const char *[]){ "cpub_clk" },
+               .num_parents = 1,
+       },
+};
+
+static struct clk_fixed_factor g12b_cpub_clk_div8 = {
+       .mult = 1,
+       .div = 8,
+       .hw.init = &(struct clk_init_data){
+               .name = "cpub_clk_div8",
+               .ops = &clk_fixed_factor_ops,
+               .parent_names = (const char *[]){ "cpub_clk" },
+               .num_parents = 1,
+       },
+};
+
+static u32 mux_table_cpub[] = { 1, 2, 3, 4, 5, 6, 7 };
+static struct clk_regmap g12b_cpub_clk_apb_sel = {
+       .data = &(struct clk_regmap_mux_data){
+               .offset = HHI_SYS_CPUB_CLK_CNTL1,
+               .mask = 7,
+               .shift = 3,
+               .table = mux_table_cpub,
+       },
+       .hw.init = &(struct clk_init_data){
+               .name = "cpub_clk_apb_sel",
+               .ops = &clk_regmap_mux_ro_ops,
+               .parent_names = (const char *[]){ "cpub_clk_div2",
+                                                 "cpub_clk_div3",
+                                                 "cpub_clk_div4",
+                                                 "cpub_clk_div5",
+                                                 "cpub_clk_div6",
+                                                 "cpub_clk_div7",
+                                                 "cpub_clk_div8" },
+               .num_parents = 7,
+       },
+};
+
+static struct clk_regmap g12b_cpub_clk_apb = {
+       .data = &(struct clk_regmap_gate_data){
+               .offset = HHI_SYS_CPUB_CLK_CNTL1,
+               .bit_idx = 16,
+               .flags = CLK_GATE_SET_TO_DISABLE,
+       },
+       .hw.init = &(struct clk_init_data) {
+               .name = "cpub_clk_apb",
+               .ops = &clk_regmap_gate_ro_ops,
+               .parent_names = (const char *[]){ "cpub_clk_apb_sel" },
+               .num_parents = 1,
+               /*
+                * This clock is set by the ROM monitor code,
+                * Linux should not change it at runtime
+                */
+       },
+};
+
+static struct clk_regmap g12b_cpub_clk_atb_sel = {
+       .data = &(struct clk_regmap_mux_data){
+               .offset = HHI_SYS_CPUB_CLK_CNTL1,
+               .mask = 7,
+               .shift = 6,
+               .table = mux_table_cpub,
+       },
+       .hw.init = &(struct clk_init_data){
+               .name = "cpub_clk_atb_sel",
+               .ops = &clk_regmap_mux_ro_ops,
+               .parent_names = (const char *[]){ "cpub_clk_div2",
+                                                 "cpub_clk_div3",
+                                                 "cpub_clk_div4",
+                                                 "cpub_clk_div5",
+                                                 "cpub_clk_div6",
+                                                 "cpub_clk_div7",
+                                                 "cpub_clk_div8" },
+               .num_parents = 7,
+       },
+};
+
+static struct clk_regmap g12b_cpub_clk_atb = {
+       .data = &(struct clk_regmap_gate_data){
+               .offset = HHI_SYS_CPUB_CLK_CNTL1,
+               .bit_idx = 17,
+               .flags = CLK_GATE_SET_TO_DISABLE,
+       },
+       .hw.init = &(struct clk_init_data) {
+               .name = "cpub_clk_atb",
+               .ops = &clk_regmap_gate_ro_ops,
+               .parent_names = (const char *[]){ "cpub_clk_atb_sel" },
+               .num_parents = 1,
+               /*
+                * This clock is set by the ROM monitor code,
+                * Linux should not change it at runtime
+                */
+       },
+};
+
+static struct clk_regmap g12b_cpub_clk_axi_sel = {
+       .data = &(struct clk_regmap_mux_data){
+               .offset = HHI_SYS_CPUB_CLK_CNTL1,
+               .mask = 7,
+               .shift = 9,
+               .table = mux_table_cpub,
+       },
+       .hw.init = &(struct clk_init_data){
+               .name = "cpub_clk_axi_sel",
+               .ops = &clk_regmap_mux_ro_ops,
+               .parent_names = (const char *[]){ "cpub_clk_div2",
+                                                 "cpub_clk_div3",
+                                                 "cpub_clk_div4",
+                                                 "cpub_clk_div5",
+                                                 "cpub_clk_div6",
+                                                 "cpub_clk_div7",
+                                                 "cpub_clk_div8" },
+               .num_parents = 7,
+       },
+};
+
+static struct clk_regmap g12b_cpub_clk_axi = {
+       .data = &(struct clk_regmap_gate_data){
+               .offset = HHI_SYS_CPUB_CLK_CNTL1,
+               .bit_idx = 18,
+               .flags = CLK_GATE_SET_TO_DISABLE,
+       },
+       .hw.init = &(struct clk_init_data) {
+               .name = "cpub_clk_axi",
+               .ops = &clk_regmap_gate_ro_ops,
+               .parent_names = (const char *[]){ "cpub_clk_axi_sel" },
+               .num_parents = 1,
+               /*
+                * This clock is set by the ROM monitor code,
+                * Linux should not change it at runtime
+                */
+       },
+};
+
+static struct clk_regmap g12b_cpub_clk_trace_sel = {
+       .data = &(struct clk_regmap_mux_data){
+               .offset = HHI_SYS_CPUB_CLK_CNTL1,
+               .mask = 7,
+               .shift = 20,
+               .table = mux_table_cpub,
+       },
+       .hw.init = &(struct clk_init_data){
+               .name = "cpub_clk_trace_sel",
+               .ops = &clk_regmap_mux_ro_ops,
+               .parent_names = (const char *[]){ "cpub_clk_div2",
+                                                 "cpub_clk_div3",
+                                                 "cpub_clk_div4",
+                                                 "cpub_clk_div5",
+                                                 "cpub_clk_div6",
+                                                 "cpub_clk_div7",
+                                                 "cpub_clk_div8" },
+               .num_parents = 7,
+       },
+};
+
+static struct clk_regmap g12b_cpub_clk_trace = {
        .data = &(struct clk_regmap_gate_data){
-               .offset = HHI_SYS_CPU_CLK_CNTL1,
+               .offset = HHI_SYS_CPUB_CLK_CNTL1,
                .bit_idx = 23,
+               .flags = CLK_GATE_SET_TO_DISABLE,
        },
        .hw.init = &(struct clk_init_data) {
-               .name = "cpu_clk_trace",
+               .name = "cpub_clk_trace",
                .ops = &clk_regmap_gate_ro_ops,
-               .parent_names = (const char *[]){ "cpu_clk_trace_div" },
+               .parent_names = (const char *[]){ "cpub_clk_trace_sel" },
                .num_parents = 1,
                /*
                 * This clock is set by the ROM monitor code,
@@ -865,6 +1350,16 @@ static struct clk_regmap g12a_fclk_div3 = {
                .ops = &clk_regmap_gate_ops,
                .parent_names = (const char *[]){ "fclk_div3_div" },
                .num_parents = 1,
+               /*
+                * This clock is used by the resident firmware and is required
+                * by the platform to operate correctly.
+                * Until the following condition are met, we need this clock to
+                * be marked as critical:
+                * a) Mark the clock used by a firmware resource, if possible
+                * b) CCF has a clock hand-off mechanism to make the sure the
+                *    clock stays on until the proper driver comes along
+                */
+               .flags = CLK_IS_CRITICAL,
        },
 };
 
@@ -1001,6 +1496,10 @@ static struct clk_fixed_factor g12a_mpll_prediv = {
        },
 };
 
+static const struct reg_sequence g12a_mpll0_init_regs[] = {
+       { .reg = HHI_MPLL_CNTL2,        .def = 0x40000033 },
+};
+
 static struct clk_regmap g12a_mpll0_div = {
        .data = &(struct meson_clk_mpll_data){
                .sdm = {
@@ -1024,6 +1523,8 @@ static struct clk_regmap g12a_mpll0_div = {
                        .width   = 1,
                },
                .lock = &meson_clk_lock,
+               .init_regs = g12a_mpll0_init_regs,
+               .init_count = ARRAY_SIZE(g12a_mpll0_init_regs),
        },
        .hw.init = &(struct clk_init_data){
                .name = "mpll0_div",
@@ -1047,6 +1548,10 @@ static struct clk_regmap g12a_mpll0 = {
        },
 };
 
+static const struct reg_sequence g12a_mpll1_init_regs[] = {
+       { .reg = HHI_MPLL_CNTL4,        .def = 0x40000033 },
+};
+
 static struct clk_regmap g12a_mpll1_div = {
        .data = &(struct meson_clk_mpll_data){
                .sdm = {
@@ -1070,6 +1575,8 @@ static struct clk_regmap g12a_mpll1_div = {
                        .width   = 1,
                },
                .lock = &meson_clk_lock,
+               .init_regs = g12a_mpll1_init_regs,
+               .init_count = ARRAY_SIZE(g12a_mpll1_init_regs),
        },
        .hw.init = &(struct clk_init_data){
                .name = "mpll1_div",
@@ -1093,6 +1600,10 @@ static struct clk_regmap g12a_mpll1 = {
        },
 };
 
+static const struct reg_sequence g12a_mpll2_init_regs[] = {
+       { .reg = HHI_MPLL_CNTL6,        .def = 0x40000033 },
+};
+
 static struct clk_regmap g12a_mpll2_div = {
        .data = &(struct meson_clk_mpll_data){
                .sdm = {
@@ -1116,6 +1627,8 @@ static struct clk_regmap g12a_mpll2_div = {
                        .width   = 1,
                },
                .lock = &meson_clk_lock,
+               .init_regs = g12a_mpll2_init_regs,
+               .init_count = ARRAY_SIZE(g12a_mpll2_init_regs),
        },
        .hw.init = &(struct clk_init_data){
                .name = "mpll2_div",
@@ -1139,6 +1652,10 @@ static struct clk_regmap g12a_mpll2 = {
        },
 };
 
+static const struct reg_sequence g12a_mpll3_init_regs[] = {
+       { .reg = HHI_MPLL_CNTL8,        .def = 0x40000033 },
+};
+
 static struct clk_regmap g12a_mpll3_div = {
        .data = &(struct meson_clk_mpll_data){
                .sdm = {
@@ -1162,6 +1679,8 @@ static struct clk_regmap g12a_mpll3_div = {
                        .width   = 1,
                },
                .lock = &meson_clk_lock,
+               .init_regs = g12a_mpll3_init_regs,
+               .init_count = ARRAY_SIZE(g12a_mpll3_init_regs),
        },
        .hw.init = &(struct clk_init_data){
                .name = "mpll3_div",
@@ -2480,6 +2999,33 @@ static struct clk_regmap g12a_mali = {
        },
 };
 
+static struct clk_regmap g12a_ts_div = {
+       .data = &(struct clk_regmap_div_data){
+               .offset = HHI_TS_CLK_CNTL,
+               .shift = 0,
+               .width = 8,
+       },
+       .hw.init = &(struct clk_init_data){
+               .name = "ts_div",
+               .ops = &clk_regmap_divider_ro_ops,
+               .parent_names = (const char *[]){ "xtal" },
+               .num_parents = 1,
+       },
+};
+
+static struct clk_regmap g12a_ts = {
+       .data = &(struct clk_regmap_gate_data){
+               .offset = HHI_TS_CLK_CNTL,
+               .bit_idx = 8,
+       },
+       .hw.init = &(struct clk_init_data){
+               .name = "ts",
+               .ops = &clk_regmap_gate_ops,
+               .parent_names = (const char *[]){ "ts_div" },
+               .num_parents = 1,
+       },
+};
+
 /* Everything Else (EE) domain gates */
 static MESON_GATE(g12a_ddr,                    HHI_GCLK_MPEG0, 0);
 static MESON_GATE(g12a_dos,                    HHI_GCLK_MPEG0, 1);
@@ -2769,6 +3315,257 @@ static struct clk_hw_onecell_data g12a_hw_onecell_data = {
                [CLKID_VDEC_HEVCF_SEL]          = &g12a_vdec_hevcf_sel.hw,
                [CLKID_VDEC_HEVCF_DIV]          = &g12a_vdec_hevcf_div.hw,
                [CLKID_VDEC_HEVCF]              = &g12a_vdec_hevcf.hw,
+               [CLKID_TS_DIV]                  = &g12a_ts_div.hw,
+               [CLKID_TS]                      = &g12a_ts.hw,
+               [NR_CLKS]                       = NULL,
+       },
+       .num = NR_CLKS,
+};
+
+static struct clk_hw_onecell_data g12b_hw_onecell_data = {
+       .hws = {
+               [CLKID_SYS_PLL]                 = &g12a_sys_pll.hw,
+               [CLKID_FIXED_PLL]               = &g12a_fixed_pll.hw,
+               [CLKID_FCLK_DIV2]               = &g12a_fclk_div2.hw,
+               [CLKID_FCLK_DIV3]               = &g12a_fclk_div3.hw,
+               [CLKID_FCLK_DIV4]               = &g12a_fclk_div4.hw,
+               [CLKID_FCLK_DIV5]               = &g12a_fclk_div5.hw,
+               [CLKID_FCLK_DIV7]               = &g12a_fclk_div7.hw,
+               [CLKID_FCLK_DIV2P5]             = &g12a_fclk_div2p5.hw,
+               [CLKID_GP0_PLL]                 = &g12a_gp0_pll.hw,
+               [CLKID_MPEG_SEL]                = &g12a_mpeg_clk_sel.hw,
+               [CLKID_MPEG_DIV]                = &g12a_mpeg_clk_div.hw,
+               [CLKID_CLK81]                   = &g12a_clk81.hw,
+               [CLKID_MPLL0]                   = &g12a_mpll0.hw,
+               [CLKID_MPLL1]                   = &g12a_mpll1.hw,
+               [CLKID_MPLL2]                   = &g12a_mpll2.hw,
+               [CLKID_MPLL3]                   = &g12a_mpll3.hw,
+               [CLKID_DDR]                     = &g12a_ddr.hw,
+               [CLKID_DOS]                     = &g12a_dos.hw,
+               [CLKID_AUDIO_LOCKER]            = &g12a_audio_locker.hw,
+               [CLKID_MIPI_DSI_HOST]           = &g12a_mipi_dsi_host.hw,
+               [CLKID_ETH_PHY]                 = &g12a_eth_phy.hw,
+               [CLKID_ISA]                     = &g12a_isa.hw,
+               [CLKID_PL301]                   = &g12a_pl301.hw,
+               [CLKID_PERIPHS]                 = &g12a_periphs.hw,
+               [CLKID_SPICC0]                  = &g12a_spicc_0.hw,
+               [CLKID_I2C]                     = &g12a_i2c.hw,
+               [CLKID_SANA]                    = &g12a_sana.hw,
+               [CLKID_SD]                      = &g12a_sd.hw,
+               [CLKID_RNG0]                    = &g12a_rng0.hw,
+               [CLKID_UART0]                   = &g12a_uart0.hw,
+               [CLKID_SPICC1]                  = &g12a_spicc_1.hw,
+               [CLKID_HIU_IFACE]               = &g12a_hiu_reg.hw,
+               [CLKID_MIPI_DSI_PHY]            = &g12a_mipi_dsi_phy.hw,
+               [CLKID_ASSIST_MISC]             = &g12a_assist_misc.hw,
+               [CLKID_SD_EMMC_A]               = &g12a_emmc_a.hw,
+               [CLKID_SD_EMMC_B]               = &g12a_emmc_b.hw,
+               [CLKID_SD_EMMC_C]               = &g12a_emmc_c.hw,
+               [CLKID_AUDIO_CODEC]             = &g12a_audio_codec.hw,
+               [CLKID_AUDIO]                   = &g12a_audio.hw,
+               [CLKID_ETH]                     = &g12a_eth_core.hw,
+               [CLKID_DEMUX]                   = &g12a_demux.hw,
+               [CLKID_AUDIO_IFIFO]             = &g12a_audio_ififo.hw,
+               [CLKID_ADC]                     = &g12a_adc.hw,
+               [CLKID_UART1]                   = &g12a_uart1.hw,
+               [CLKID_G2D]                     = &g12a_g2d.hw,
+               [CLKID_RESET]                   = &g12a_reset.hw,
+               [CLKID_PCIE_COMB]               = &g12a_pcie_comb.hw,
+               [CLKID_PARSER]                  = &g12a_parser.hw,
+               [CLKID_USB]                     = &g12a_usb_general.hw,
+               [CLKID_PCIE_PHY]                = &g12a_pcie_phy.hw,
+               [CLKID_AHB_ARB0]                = &g12a_ahb_arb0.hw,
+               [CLKID_AHB_DATA_BUS]            = &g12a_ahb_data_bus.hw,
+               [CLKID_AHB_CTRL_BUS]            = &g12a_ahb_ctrl_bus.hw,
+               [CLKID_HTX_HDCP22]              = &g12a_htx_hdcp22.hw,
+               [CLKID_HTX_PCLK]                = &g12a_htx_pclk.hw,
+               [CLKID_BT656]                   = &g12a_bt656.hw,
+               [CLKID_USB1_DDR_BRIDGE]         = &g12a_usb1_to_ddr.hw,
+               [CLKID_MMC_PCLK]                = &g12a_mmc_pclk.hw,
+               [CLKID_UART2]                   = &g12a_uart2.hw,
+               [CLKID_VPU_INTR]                = &g12a_vpu_intr.hw,
+               [CLKID_GIC]                     = &g12a_gic.hw,
+               [CLKID_SD_EMMC_A_CLK0_SEL]      = &g12a_sd_emmc_a_clk0_sel.hw,
+               [CLKID_SD_EMMC_A_CLK0_DIV]      = &g12a_sd_emmc_a_clk0_div.hw,
+               [CLKID_SD_EMMC_A_CLK0]          = &g12a_sd_emmc_a_clk0.hw,
+               [CLKID_SD_EMMC_B_CLK0_SEL]      = &g12a_sd_emmc_b_clk0_sel.hw,
+               [CLKID_SD_EMMC_B_CLK0_DIV]      = &g12a_sd_emmc_b_clk0_div.hw,
+               [CLKID_SD_EMMC_B_CLK0]          = &g12a_sd_emmc_b_clk0.hw,
+               [CLKID_SD_EMMC_C_CLK0_SEL]      = &g12a_sd_emmc_c_clk0_sel.hw,
+               [CLKID_SD_EMMC_C_CLK0_DIV]      = &g12a_sd_emmc_c_clk0_div.hw,
+               [CLKID_SD_EMMC_C_CLK0]          = &g12a_sd_emmc_c_clk0.hw,
+               [CLKID_MPLL0_DIV]               = &g12a_mpll0_div.hw,
+               [CLKID_MPLL1_DIV]               = &g12a_mpll1_div.hw,
+               [CLKID_MPLL2_DIV]               = &g12a_mpll2_div.hw,
+               [CLKID_MPLL3_DIV]               = &g12a_mpll3_div.hw,
+               [CLKID_FCLK_DIV2_DIV]           = &g12a_fclk_div2_div.hw,
+               [CLKID_FCLK_DIV3_DIV]           = &g12a_fclk_div3_div.hw,
+               [CLKID_FCLK_DIV4_DIV]           = &g12a_fclk_div4_div.hw,
+               [CLKID_FCLK_DIV5_DIV]           = &g12a_fclk_div5_div.hw,
+               [CLKID_FCLK_DIV7_DIV]           = &g12a_fclk_div7_div.hw,
+               [CLKID_FCLK_DIV2P5_DIV]         = &g12a_fclk_div2p5_div.hw,
+               [CLKID_HIFI_PLL]                = &g12a_hifi_pll.hw,
+               [CLKID_VCLK2_VENCI0]            = &g12a_vclk2_venci0.hw,
+               [CLKID_VCLK2_VENCI1]            = &g12a_vclk2_venci1.hw,
+               [CLKID_VCLK2_VENCP0]            = &g12a_vclk2_vencp0.hw,
+               [CLKID_VCLK2_VENCP1]            = &g12a_vclk2_vencp1.hw,
+               [CLKID_VCLK2_VENCT0]            = &g12a_vclk2_venct0.hw,
+               [CLKID_VCLK2_VENCT1]            = &g12a_vclk2_venct1.hw,
+               [CLKID_VCLK2_OTHER]             = &g12a_vclk2_other.hw,
+               [CLKID_VCLK2_ENCI]              = &g12a_vclk2_enci.hw,
+               [CLKID_VCLK2_ENCP]              = &g12a_vclk2_encp.hw,
+               [CLKID_DAC_CLK]                 = &g12a_dac_clk.hw,
+               [CLKID_AOCLK]                   = &g12a_aoclk_gate.hw,
+               [CLKID_IEC958]                  = &g12a_iec958_gate.hw,
+               [CLKID_ENC480P]                 = &g12a_enc480p.hw,
+               [CLKID_RNG1]                    = &g12a_rng1.hw,
+               [CLKID_VCLK2_ENCT]              = &g12a_vclk2_enct.hw,
+               [CLKID_VCLK2_ENCL]              = &g12a_vclk2_encl.hw,
+               [CLKID_VCLK2_VENCLMMC]          = &g12a_vclk2_venclmmc.hw,
+               [CLKID_VCLK2_VENCL]             = &g12a_vclk2_vencl.hw,
+               [CLKID_VCLK2_OTHER1]            = &g12a_vclk2_other1.hw,
+               [CLKID_FIXED_PLL_DCO]           = &g12a_fixed_pll_dco.hw,
+               [CLKID_SYS_PLL_DCO]             = &g12a_sys_pll_dco.hw,
+               [CLKID_GP0_PLL_DCO]             = &g12a_gp0_pll_dco.hw,
+               [CLKID_HIFI_PLL_DCO]            = &g12a_hifi_pll_dco.hw,
+               [CLKID_DMA]                     = &g12a_dma.hw,
+               [CLKID_EFUSE]                   = &g12a_efuse.hw,
+               [CLKID_ROM_BOOT]                = &g12a_rom_boot.hw,
+               [CLKID_RESET_SEC]               = &g12a_reset_sec.hw,
+               [CLKID_SEC_AHB_APB3]            = &g12a_sec_ahb_apb3.hw,
+               [CLKID_MPLL_PREDIV]             = &g12a_mpll_prediv.hw,
+               [CLKID_VPU_0_SEL]               = &g12a_vpu_0_sel.hw,
+               [CLKID_VPU_0_DIV]               = &g12a_vpu_0_div.hw,
+               [CLKID_VPU_0]                   = &g12a_vpu_0.hw,
+               [CLKID_VPU_1_SEL]               = &g12a_vpu_1_sel.hw,
+               [CLKID_VPU_1_DIV]               = &g12a_vpu_1_div.hw,
+               [CLKID_VPU_1]                   = &g12a_vpu_1.hw,
+               [CLKID_VPU]                     = &g12a_vpu.hw,
+               [CLKID_VAPB_0_SEL]              = &g12a_vapb_0_sel.hw,
+               [CLKID_VAPB_0_DIV]              = &g12a_vapb_0_div.hw,
+               [CLKID_VAPB_0]                  = &g12a_vapb_0.hw,
+               [CLKID_VAPB_1_SEL]              = &g12a_vapb_1_sel.hw,
+               [CLKID_VAPB_1_DIV]              = &g12a_vapb_1_div.hw,
+               [CLKID_VAPB_1]                  = &g12a_vapb_1.hw,
+               [CLKID_VAPB_SEL]                = &g12a_vapb_sel.hw,
+               [CLKID_VAPB]                    = &g12a_vapb.hw,
+               [CLKID_HDMI_PLL_DCO]            = &g12a_hdmi_pll_dco.hw,
+               [CLKID_HDMI_PLL_OD]             = &g12a_hdmi_pll_od.hw,
+               [CLKID_HDMI_PLL_OD2]            = &g12a_hdmi_pll_od2.hw,
+               [CLKID_HDMI_PLL]                = &g12a_hdmi_pll.hw,
+               [CLKID_VID_PLL]                 = &g12a_vid_pll_div.hw,
+               [CLKID_VID_PLL_SEL]             = &g12a_vid_pll_sel.hw,
+               [CLKID_VID_PLL_DIV]             = &g12a_vid_pll.hw,
+               [CLKID_VCLK_SEL]                = &g12a_vclk_sel.hw,
+               [CLKID_VCLK2_SEL]               = &g12a_vclk2_sel.hw,
+               [CLKID_VCLK_INPUT]              = &g12a_vclk_input.hw,
+               [CLKID_VCLK2_INPUT]             = &g12a_vclk2_input.hw,
+               [CLKID_VCLK_DIV]                = &g12a_vclk_div.hw,
+               [CLKID_VCLK2_DIV]               = &g12a_vclk2_div.hw,
+               [CLKID_VCLK]                    = &g12a_vclk.hw,
+               [CLKID_VCLK2]                   = &g12a_vclk2.hw,
+               [CLKID_VCLK_DIV1]               = &g12a_vclk_div1.hw,
+               [CLKID_VCLK_DIV2_EN]            = &g12a_vclk_div2_en.hw,
+               [CLKID_VCLK_DIV4_EN]            = &g12a_vclk_div4_en.hw,
+               [CLKID_VCLK_DIV6_EN]            = &g12a_vclk_div6_en.hw,
+               [CLKID_VCLK_DIV12_EN]           = &g12a_vclk_div12_en.hw,
+               [CLKID_VCLK2_DIV1]              = &g12a_vclk2_div1.hw,
+               [CLKID_VCLK2_DIV2_EN]           = &g12a_vclk2_div2_en.hw,
+               [CLKID_VCLK2_DIV4_EN]           = &g12a_vclk2_div4_en.hw,
+               [CLKID_VCLK2_DIV6_EN]           = &g12a_vclk2_div6_en.hw,
+               [CLKID_VCLK2_DIV12_EN]          = &g12a_vclk2_div12_en.hw,
+               [CLKID_VCLK_DIV2]               = &g12a_vclk_div2.hw,
+               [CLKID_VCLK_DIV4]               = &g12a_vclk_div4.hw,
+               [CLKID_VCLK_DIV6]               = &g12a_vclk_div6.hw,
+               [CLKID_VCLK_DIV12]              = &g12a_vclk_div12.hw,
+               [CLKID_VCLK2_DIV2]              = &g12a_vclk2_div2.hw,
+               [CLKID_VCLK2_DIV4]              = &g12a_vclk2_div4.hw,
+               [CLKID_VCLK2_DIV6]              = &g12a_vclk2_div6.hw,
+               [CLKID_VCLK2_DIV12]             = &g12a_vclk2_div12.hw,
+               [CLKID_CTS_ENCI_SEL]            = &g12a_cts_enci_sel.hw,
+               [CLKID_CTS_ENCP_SEL]            = &g12a_cts_encp_sel.hw,
+               [CLKID_CTS_VDAC_SEL]            = &g12a_cts_vdac_sel.hw,
+               [CLKID_HDMI_TX_SEL]             = &g12a_hdmi_tx_sel.hw,
+               [CLKID_CTS_ENCI]                = &g12a_cts_enci.hw,
+               [CLKID_CTS_ENCP]                = &g12a_cts_encp.hw,
+               [CLKID_CTS_VDAC]                = &g12a_cts_vdac.hw,
+               [CLKID_HDMI_TX]                 = &g12a_hdmi_tx.hw,
+               [CLKID_HDMI_SEL]                = &g12a_hdmi_sel.hw,
+               [CLKID_HDMI_DIV]                = &g12a_hdmi_div.hw,
+               [CLKID_HDMI]                    = &g12a_hdmi.hw,
+               [CLKID_MALI_0_SEL]              = &g12a_mali_0_sel.hw,
+               [CLKID_MALI_0_DIV]              = &g12a_mali_0_div.hw,
+               [CLKID_MALI_0]                  = &g12a_mali_0.hw,
+               [CLKID_MALI_1_SEL]              = &g12a_mali_1_sel.hw,
+               [CLKID_MALI_1_DIV]              = &g12a_mali_1_div.hw,
+               [CLKID_MALI_1]                  = &g12a_mali_1.hw,
+               [CLKID_MALI]                    = &g12a_mali.hw,
+               [CLKID_MPLL_50M_DIV]            = &g12a_mpll_50m_div.hw,
+               [CLKID_MPLL_50M]                = &g12a_mpll_50m.hw,
+               [CLKID_SYS_PLL_DIV16_EN]        = &g12a_sys_pll_div16_en.hw,
+               [CLKID_SYS_PLL_DIV16]           = &g12a_sys_pll_div16.hw,
+               [CLKID_CPU_CLK_DYN0_SEL]        = &g12a_cpu_clk_premux0.hw,
+               [CLKID_CPU_CLK_DYN0_DIV]        = &g12a_cpu_clk_mux0_div.hw,
+               [CLKID_CPU_CLK_DYN0]            = &g12a_cpu_clk_postmux0.hw,
+               [CLKID_CPU_CLK_DYN1_SEL]        = &g12a_cpu_clk_premux1.hw,
+               [CLKID_CPU_CLK_DYN1_DIV]        = &g12a_cpu_clk_mux1_div.hw,
+               [CLKID_CPU_CLK_DYN1]            = &g12a_cpu_clk_postmux1.hw,
+               [CLKID_CPU_CLK_DYN]             = &g12a_cpu_clk_dyn.hw,
+               [CLKID_CPU_CLK]                 = &g12b_cpu_clk.hw,
+               [CLKID_CPU_CLK_DIV16_EN]        = &g12a_cpu_clk_div16_en.hw,
+               [CLKID_CPU_CLK_DIV16]           = &g12a_cpu_clk_div16.hw,
+               [CLKID_CPU_CLK_APB_DIV]         = &g12a_cpu_clk_apb_div.hw,
+               [CLKID_CPU_CLK_APB]             = &g12a_cpu_clk_apb.hw,
+               [CLKID_CPU_CLK_ATB_DIV]         = &g12a_cpu_clk_atb_div.hw,
+               [CLKID_CPU_CLK_ATB]             = &g12a_cpu_clk_atb.hw,
+               [CLKID_CPU_CLK_AXI_DIV]         = &g12a_cpu_clk_axi_div.hw,
+               [CLKID_CPU_CLK_AXI]             = &g12a_cpu_clk_axi.hw,
+               [CLKID_CPU_CLK_TRACE_DIV]       = &g12a_cpu_clk_trace_div.hw,
+               [CLKID_CPU_CLK_TRACE]           = &g12a_cpu_clk_trace.hw,
+               [CLKID_PCIE_PLL_DCO]            = &g12a_pcie_pll_dco.hw,
+               [CLKID_PCIE_PLL_DCO_DIV2]       = &g12a_pcie_pll_dco_div2.hw,
+               [CLKID_PCIE_PLL_OD]             = &g12a_pcie_pll_od.hw,
+               [CLKID_PCIE_PLL]                = &g12a_pcie_pll.hw,
+               [CLKID_VDEC_1_SEL]              = &g12a_vdec_1_sel.hw,
+               [CLKID_VDEC_1_DIV]              = &g12a_vdec_1_div.hw,
+               [CLKID_VDEC_1]                  = &g12a_vdec_1.hw,
+               [CLKID_VDEC_HEVC_SEL]           = &g12a_vdec_hevc_sel.hw,
+               [CLKID_VDEC_HEVC_DIV]           = &g12a_vdec_hevc_div.hw,
+               [CLKID_VDEC_HEVC]               = &g12a_vdec_hevc.hw,
+               [CLKID_VDEC_HEVCF_SEL]          = &g12a_vdec_hevcf_sel.hw,
+               [CLKID_VDEC_HEVCF_DIV]          = &g12a_vdec_hevcf_div.hw,
+               [CLKID_VDEC_HEVCF]              = &g12a_vdec_hevcf.hw,
+               [CLKID_TS_DIV]                  = &g12a_ts_div.hw,
+               [CLKID_TS]                      = &g12a_ts.hw,
+               [CLKID_SYS1_PLL_DCO]            = &g12b_sys1_pll_dco.hw,
+               [CLKID_SYS1_PLL]                = &g12b_sys1_pll.hw,
+               [CLKID_SYS1_PLL_DIV16_EN]       = &g12b_sys1_pll_div16_en.hw,
+               [CLKID_SYS1_PLL_DIV16]          = &g12b_sys1_pll_div16.hw,
+               [CLKID_CPUB_CLK_DYN0_SEL]       = &g12b_cpub_clk_premux0.hw,
+               [CLKID_CPUB_CLK_DYN0_DIV]       = &g12b_cpub_clk_mux0_div.hw,
+               [CLKID_CPUB_CLK_DYN0]           = &g12b_cpub_clk_postmux0.hw,
+               [CLKID_CPUB_CLK_DYN1_SEL]       = &g12b_cpub_clk_premux1.hw,
+               [CLKID_CPUB_CLK_DYN1_DIV]       = &g12b_cpub_clk_mux1_div.hw,
+               [CLKID_CPUB_CLK_DYN1]           = &g12b_cpub_clk_postmux1.hw,
+               [CLKID_CPUB_CLK_DYN]            = &g12b_cpub_clk_dyn.hw,
+               [CLKID_CPUB_CLK]                = &g12b_cpub_clk.hw,
+               [CLKID_CPUB_CLK_DIV16_EN]       = &g12b_cpub_clk_div16_en.hw,
+               [CLKID_CPUB_CLK_DIV16]          = &g12b_cpub_clk_div16.hw,
+               [CLKID_CPUB_CLK_DIV2]           = &g12b_cpub_clk_div2.hw,
+               [CLKID_CPUB_CLK_DIV3]           = &g12b_cpub_clk_div3.hw,
+               [CLKID_CPUB_CLK_DIV4]           = &g12b_cpub_clk_div4.hw,
+               [CLKID_CPUB_CLK_DIV5]           = &g12b_cpub_clk_div5.hw,
+               [CLKID_CPUB_CLK_DIV6]           = &g12b_cpub_clk_div6.hw,
+               [CLKID_CPUB_CLK_DIV7]           = &g12b_cpub_clk_div7.hw,
+               [CLKID_CPUB_CLK_DIV8]           = &g12b_cpub_clk_div8.hw,
+               [CLKID_CPUB_CLK_APB_SEL]        = &g12b_cpub_clk_apb_sel.hw,
+               [CLKID_CPUB_CLK_APB]            = &g12b_cpub_clk_apb.hw,
+               [CLKID_CPUB_CLK_ATB_SEL]        = &g12b_cpub_clk_atb_sel.hw,
+               [CLKID_CPUB_CLK_ATB]            = &g12b_cpub_clk_atb.hw,
+               [CLKID_CPUB_CLK_AXI_SEL]        = &g12b_cpub_clk_axi_sel.hw,
+               [CLKID_CPUB_CLK_AXI]            = &g12b_cpub_clk_axi.hw,
+               [CLKID_CPUB_CLK_TRACE_SEL]      = &g12b_cpub_clk_trace_sel.hw,
+               [CLKID_CPUB_CLK_TRACE]          = &g12b_cpub_clk_trace.hw,
                [NR_CLKS]                       = NULL,
        },
        .num = NR_CLKS,
@@ -2966,16 +3763,52 @@ static struct clk_regmap *const g12a_clk_regmaps[] = {
        &g12a_vdec_hevcf_sel,
        &g12a_vdec_hevcf_div,
        &g12a_vdec_hevcf,
+       &g12a_ts_div,
+       &g12a_ts,
+       &g12b_cpu_clk,
+       &g12b_sys1_pll_dco,
+       &g12b_sys1_pll,
+       &g12b_sys1_pll_div16_en,
+       &g12b_cpub_clk_premux0,
+       &g12b_cpub_clk_mux0_div,
+       &g12b_cpub_clk_postmux0,
+       &g12b_cpub_clk_premux1,
+       &g12b_cpub_clk_mux1_div,
+       &g12b_cpub_clk_postmux1,
+       &g12b_cpub_clk_dyn,
+       &g12b_cpub_clk,
+       &g12b_cpub_clk_div16_en,
+       &g12b_cpub_clk_apb_sel,
+       &g12b_cpub_clk_apb,
+       &g12b_cpub_clk_atb_sel,
+       &g12b_cpub_clk_atb,
+       &g12b_cpub_clk_axi_sel,
+       &g12b_cpub_clk_axi,
+       &g12b_cpub_clk_trace_sel,
+       &g12b_cpub_clk_trace,
+};
+
+static const struct reg_sequence g12a_init_regs[] = {
+       { .reg = HHI_MPLL_CNTL0,        .def = 0x00000543 },
 };
 
 static const struct meson_eeclkc_data g12a_clkc_data = {
        .regmap_clks = g12a_clk_regmaps,
        .regmap_clk_num = ARRAY_SIZE(g12a_clk_regmaps),
-       .hw_onecell_data = &g12a_hw_onecell_data
+       .hw_onecell_data = &g12a_hw_onecell_data,
+       .init_regs = g12a_init_regs,
+       .init_count = ARRAY_SIZE(g12a_init_regs),
+};
+
+static const struct meson_eeclkc_data g12b_clkc_data = {
+       .regmap_clks = g12a_clk_regmaps,
+       .regmap_clk_num = ARRAY_SIZE(g12a_clk_regmaps),
+       .hw_onecell_data = &g12b_hw_onecell_data
 };
 
 static const struct of_device_id clkc_match_table[] = {
        { .compatible = "amlogic,g12a-clkc", .data = &g12a_clkc_data },
+       { .compatible = "amlogic,g12b-clkc", .data = &g12b_clkc_data },
        {}
 };
 
index bcc05cd..c8aed31 100644 (file)
@@ -69,6 +69,8 @@
 #define HHI_VDEC4_CLK_CNTL             0x1EC
 #define HHI_HDCP22_CLK_CNTL            0x1F0
 #define HHI_VAPBCLK_CNTL               0x1F4
+#define HHI_SYS_CPUB_CLK_CNTL1         0x200
+#define HHI_SYS_CPUB_CLK_CNTL          0x208
 #define HHI_VPU_CLKB_CNTL              0x20C
 #define HHI_GEN_CLK_CNTL               0x228
 #define HHI_VDIN_MEAS_CLK_CNTL         0x250
 #define HHI_HDMI_PLL_CNTL5             0x334
 #define HHI_HDMI_PLL_CNTL6             0x338
 #define HHI_SPICC_CLK_CNTL             0x3dc
+#define HHI_SYS1_PLL_CNTL0             0x380
+#define HHI_SYS1_PLL_CNTL1             0x384
+#define HHI_SYS1_PLL_CNTL2             0x388
+#define HHI_SYS1_PLL_CNTL3             0x38c
+#define HHI_SYS1_PLL_CNTL4             0x390
+#define HHI_SYS1_PLL_CNTL5             0x394
+#define HHI_SYS1_PLL_CNTL6             0x398
 
 /*
  * CLKID index values
 #define CLKID_VDEC_HEVC_DIV                    206
 #define CLKID_VDEC_HEVCF_SEL                   208
 #define CLKID_VDEC_HEVCF_DIV                   209
+#define CLKID_TS_DIV                           211
+#define CLKID_SYS1_PLL_DCO                     213
+#define CLKID_SYS1_PLL                         214
+#define CLKID_SYS1_PLL_DIV16_EN                        215
+#define CLKID_SYS1_PLL_DIV16                   216
+#define CLKID_CPUB_CLK_DYN0_SEL                        217
+#define CLKID_CPUB_CLK_DYN0_DIV                        218
+#define CLKID_CPUB_CLK_DYN0                    219
+#define CLKID_CPUB_CLK_DYN1_SEL                        220
+#define CLKID_CPUB_CLK_DYN1_DIV                        221
+#define CLKID_CPUB_CLK_DYN1                    222
+#define CLKID_CPUB_CLK_DYN                     223
+#define CLKID_CPUB_CLK                         224
+#define CLKID_CPUB_CLK_DIV16_EN                        225
+#define CLKID_CPUB_CLK_DIV16                   226
+#define CLKID_CPUB_CLK_DIV2                    227
+#define CLKID_CPUB_CLK_DIV3                    228
+#define CLKID_CPUB_CLK_DIV4                    229
+#define CLKID_CPUB_CLK_DIV5                    230
+#define CLKID_CPUB_CLK_DIV6                    231
+#define CLKID_CPUB_CLK_DIV7                    232
+#define CLKID_CPUB_CLK_DIV8                    233
+#define CLKID_CPUB_CLK_APB_SEL                 234
+#define CLKID_CPUB_CLK_APB                     235
+#define CLKID_CPUB_CLK_ATB_SEL                 236
+#define CLKID_CPUB_CLK_ATB                     237
+#define CLKID_CPUB_CLK_AXI_SEL                 238
+#define CLKID_CPUB_CLK_AXI                     239
+#define CLKID_CPUB_CLK_TRACE_SEL               240
+#define CLKID_CPUB_CLK_TRACE                   241
 
-#define NR_CLKS                                        211
+#define NR_CLKS                                        242
 
 /* include the CLKIDs that have been made part of the DT binding */
 #include <dt-bindings/clock/g12a-clkc.h>
index 29ffb4f..dab16d9 100644 (file)
@@ -679,11 +679,6 @@ static struct clk_regmap gxbb_mpll0_div = {
                        .shift   = 16,
                        .width   = 9,
                },
-               .ssen = {
-                       .reg_off = HHI_MPLL_CNTL,
-                       .shift   = 25,
-                       .width   = 1,
-               },
                .lock = &meson_clk_lock,
        },
        .hw.init = &(struct clk_init_data){
index 37a34c9..6ba2094 100644 (file)
@@ -34,6 +34,9 @@ int meson_eeclkc_probe(struct platform_device *pdev)
                return PTR_ERR(map);
        }
 
+       if (data->init_count)
+               regmap_multi_reg_write(map, data->init_regs, data->init_count);
+
        input = meson_clk_hw_register_input(dev, "xtal", IN_PREFIX "xtal", 0);
        if (IS_ERR(input)) {
                ret = PTR_ERR(input);
index 1b809b1..9ab5d6f 100644 (file)
@@ -17,6 +17,8 @@ struct platform_device;
 struct meson_eeclkc_data {
        struct clk_regmap *const        *regmap_clks;
        unsigned int                    regmap_clk_num;
+       const struct reg_sequence       *init_regs;
+       unsigned int                    init_count;
        struct clk_hw_onecell_data      *hw_onecell_data;
 };
 
index 62cd3a7..537219f 100644 (file)
@@ -2153,6 +2153,132 @@ static struct clk_regmap meson8b_vdec_hevc = {
        },
 };
 
+/* TODO: the clock at index 0 is "DDR_PLL" which we don't support yet */
+static const char * const meson8b_cts_amclk_parent_names[] = {
+       "mpll0", "mpll1", "mpll2"
+};
+
+static u32 meson8b_cts_amclk_mux_table[] = { 1, 2, 3 };
+
+static struct clk_regmap meson8b_cts_amclk_sel = {
+       .data = &(struct clk_regmap_mux_data){
+               .offset = HHI_AUD_CLK_CNTL,
+               .mask = 0x3,
+               .shift = 9,
+               .table = meson8b_cts_amclk_mux_table,
+               .flags = CLK_MUX_ROUND_CLOSEST,
+       },
+       .hw.init = &(struct clk_init_data){
+               .name = "cts_amclk_sel",
+               .ops = &clk_regmap_mux_ops,
+               .parent_names = meson8b_cts_amclk_parent_names,
+               .num_parents = ARRAY_SIZE(meson8b_cts_amclk_parent_names),
+       },
+};
+
+static struct clk_regmap meson8b_cts_amclk_div = {
+       .data = &(struct clk_regmap_div_data) {
+               .offset = HHI_AUD_CLK_CNTL,
+               .shift = 0,
+               .width = 8,
+               .flags = CLK_DIVIDER_ROUND_CLOSEST,
+       },
+       .hw.init = &(struct clk_init_data){
+               .name = "cts_amclk_div",
+               .ops = &clk_regmap_divider_ops,
+               .parent_names = (const char *[]){ "cts_amclk_sel" },
+               .num_parents = 1,
+               .flags = CLK_SET_RATE_PARENT,
+       },
+};
+
+static struct clk_regmap meson8b_cts_amclk = {
+       .data = &(struct clk_regmap_gate_data){
+               .offset = HHI_AUD_CLK_CNTL,
+               .bit_idx = 8,
+       },
+       .hw.init = &(struct clk_init_data){
+               .name = "cts_amclk",
+               .ops = &clk_regmap_gate_ops,
+               .parent_names = (const char *[]){ "cts_amclk_div" },
+               .num_parents = 1,
+               .flags = CLK_SET_RATE_PARENT,
+       },
+};
+
+/* TODO: the clock at index 0 is "DDR_PLL" which we don't support yet */
+static const char * const meson8b_cts_mclk_i958_parent_names[] = {
+       "mpll0", "mpll1", "mpll2"
+};
+
+static u32 meson8b_cts_mclk_i958_mux_table[] = { 1, 2, 3 };
+
+static struct clk_regmap meson8b_cts_mclk_i958_sel = {
+       .data = &(struct clk_regmap_mux_data){
+               .offset = HHI_AUD_CLK_CNTL2,
+               .mask = 0x3,
+               .shift = 25,
+               .table = meson8b_cts_mclk_i958_mux_table,
+               .flags = CLK_MUX_ROUND_CLOSEST,
+       },
+       .hw.init = &(struct clk_init_data) {
+               .name = "cts_mclk_i958_sel",
+               .ops = &clk_regmap_mux_ops,
+               .parent_names = meson8b_cts_mclk_i958_parent_names,
+               .num_parents = ARRAY_SIZE(meson8b_cts_mclk_i958_parent_names),
+       },
+};
+
+static struct clk_regmap meson8b_cts_mclk_i958_div = {
+       .data = &(struct clk_regmap_div_data){
+               .offset = HHI_AUD_CLK_CNTL2,
+               .shift = 16,
+               .width = 8,
+               .flags = CLK_DIVIDER_ROUND_CLOSEST,
+       },
+       .hw.init = &(struct clk_init_data) {
+               .name = "cts_mclk_i958_div",
+               .ops = &clk_regmap_divider_ops,
+               .parent_names = (const char *[]){ "cts_mclk_i958_sel" },
+               .num_parents = 1,
+               .flags = CLK_SET_RATE_PARENT,
+       },
+};
+
+static struct clk_regmap meson8b_cts_mclk_i958 = {
+       .data = &(struct clk_regmap_gate_data){
+               .offset = HHI_AUD_CLK_CNTL2,
+               .bit_idx = 24,
+       },
+       .hw.init = &(struct clk_init_data){
+               .name = "cts_mclk_i958",
+               .ops = &clk_regmap_gate_ops,
+               .parent_names = (const char *[]){ "cts_mclk_i958_div" },
+               .num_parents = 1,
+               .flags = CLK_SET_RATE_PARENT,
+       },
+};
+
+static struct clk_regmap meson8b_cts_i958 = {
+       .data = &(struct clk_regmap_mux_data){
+               .offset = HHI_AUD_CLK_CNTL2,
+               .mask = 0x1,
+               .shift = 27,
+               },
+       .hw.init = &(struct clk_init_data){
+               .name = "cts_i958",
+               .ops = &clk_regmap_mux_ops,
+               .parent_names = (const char *[]){ "cts_amclk",
+                                                 "cts_mclk_i958" },
+               .num_parents = 2,
+               /*
+                * The parent is specific to origin of the audio data. Let the
+                * consumer choose the appropriate parent.
+                */
+               .flags = CLK_SET_RATE_PARENT | CLK_SET_RATE_NO_REPARENT,
+       },
+};
+
 /* Everything Else (EE) domain gates */
 
 static MESON_GATE(meson8b_ddr, HHI_GCLK_MPEG0, 0);
@@ -2432,6 +2558,13 @@ static struct clk_hw_onecell_data meson8_hw_onecell_data = {
                [CLKID_VDEC_HEVC_DIV]       = &meson8b_vdec_hevc_div.hw,
                [CLKID_VDEC_HEVC_EN]        = &meson8b_vdec_hevc_en.hw,
                [CLKID_VDEC_HEVC]           = &meson8b_vdec_hevc.hw,
+               [CLKID_CTS_AMCLK_SEL]       = &meson8b_cts_amclk_sel.hw,
+               [CLKID_CTS_AMCLK_DIV]       = &meson8b_cts_amclk_div.hw,
+               [CLKID_CTS_AMCLK]           = &meson8b_cts_amclk.hw,
+               [CLKID_CTS_MCLK_I958_SEL]   = &meson8b_cts_mclk_i958_sel.hw,
+               [CLKID_CTS_MCLK_I958_DIV]   = &meson8b_cts_mclk_i958_div.hw,
+               [CLKID_CTS_MCLK_I958]       = &meson8b_cts_mclk_i958.hw,
+               [CLKID_CTS_I958]            = &meson8b_cts_i958.hw,
                [CLK_NR_CLKS]               = NULL,
        },
        .num = CLK_NR_CLKS,
@@ -2641,6 +2774,13 @@ static struct clk_hw_onecell_data meson8b_hw_onecell_data = {
                [CLKID_VDEC_HEVC_DIV]       = &meson8b_vdec_hevc_div.hw,
                [CLKID_VDEC_HEVC_EN]        = &meson8b_vdec_hevc_en.hw,
                [CLKID_VDEC_HEVC]           = &meson8b_vdec_hevc.hw,
+               [CLKID_CTS_AMCLK_SEL]       = &meson8b_cts_amclk_sel.hw,
+               [CLKID_CTS_AMCLK_DIV]       = &meson8b_cts_amclk_div.hw,
+               [CLKID_CTS_AMCLK]           = &meson8b_cts_amclk.hw,
+               [CLKID_CTS_MCLK_I958_SEL]   = &meson8b_cts_mclk_i958_sel.hw,
+               [CLKID_CTS_MCLK_I958_DIV]   = &meson8b_cts_mclk_i958_div.hw,
+               [CLKID_CTS_MCLK_I958]       = &meson8b_cts_mclk_i958.hw,
+               [CLKID_CTS_I958]            = &meson8b_cts_i958.hw,
                [CLK_NR_CLKS]               = NULL,
        },
        .num = CLK_NR_CLKS,
@@ -2852,6 +2992,13 @@ static struct clk_hw_onecell_data meson8m2_hw_onecell_data = {
                [CLKID_VDEC_HEVC_DIV]       = &meson8b_vdec_hevc_div.hw,
                [CLKID_VDEC_HEVC_EN]        = &meson8b_vdec_hevc_en.hw,
                [CLKID_VDEC_HEVC]           = &meson8b_vdec_hevc.hw,
+               [CLKID_CTS_AMCLK_SEL]       = &meson8b_cts_amclk_sel.hw,
+               [CLKID_CTS_AMCLK_DIV]       = &meson8b_cts_amclk_div.hw,
+               [CLKID_CTS_AMCLK]           = &meson8b_cts_amclk.hw,
+               [CLKID_CTS_MCLK_I958_SEL]   = &meson8b_cts_mclk_i958_sel.hw,
+               [CLKID_CTS_MCLK_I958_DIV]   = &meson8b_cts_mclk_i958_div.hw,
+               [CLKID_CTS_MCLK_I958]       = &meson8b_cts_mclk_i958.hw,
+               [CLKID_CTS_I958]            = &meson8b_cts_i958.hw,
                [CLK_NR_CLKS]               = NULL,
        },
        .num = CLK_NR_CLKS,
@@ -3041,6 +3188,13 @@ static struct clk_regmap *const meson8b_clk_regmaps[] = {
        &meson8b_vdec_hevc_div,
        &meson8b_vdec_hevc_en,
        &meson8b_vdec_hevc,
+       &meson8b_cts_amclk,
+       &meson8b_cts_amclk_sel,
+       &meson8b_cts_amclk_div,
+       &meson8b_cts_mclk_i958_sel,
+       &meson8b_cts_mclk_i958_div,
+       &meson8b_cts_mclk_i958,
+       &meson8b_cts_i958,
 };
 
 static const struct meson8b_clk_reset_line {
index ed37196..c889fbe 100644 (file)
@@ -30,7 +30,9 @@
 #define HHI_SYS_CPU_CLK_CNTL1          0x15c /* 0x57 offset in data sheet */
 #define HHI_VID_CLK_DIV                        0x164 /* 0x59 offset in data sheet */
 #define HHI_MPEG_CLK_CNTL              0x174 /* 0x5d offset in data sheet */
+#define HHI_AUD_CLK_CNTL               0x178 /* 0x5e offset in data sheet */
 #define HHI_VID_CLK_CNTL               0x17c /* 0x5f offset in data sheet */
+#define HHI_AUD_CLK_CNTL2              0x190 /* 0x64 offset in data sheet */
 #define HHI_VID_CLK_CNTL2              0x194 /* 0x65 offset in data sheet */
 #define HHI_VID_DIVIDER_CNTL           0x198 /* 0x66 offset in data sheet */
 #define HHI_SYS_CPU_CLK_CNTL0          0x19c /* 0x67 offset in data sheet */
 #define CLKID_VDEC_HEVC_SEL    203
 #define CLKID_VDEC_HEVC_DIV    204
 #define CLKID_VDEC_HEVC_EN     205
+#define CLKID_CTS_AMCLK_SEL    207
+#define CLKID_CTS_AMCLK_DIV    208
+#define CLKID_CTS_MCLK_I958_SEL        210
+#define CLKID_CTS_MCLK_I958_DIV        211
 
-#define CLK_NR_CLKS            207
+#define CLK_NR_CLKS            214
 
 /*
  * include the CLKID and RESETID that have
index cb43d54..90bf181 100644 (file)
@@ -78,11 +78,10 @@ static int clk_factor_set_rate(struct clk_hw *hw, unsigned long drate,
        struct mmp_clk_factor_masks *masks = factor->masks;
        int i;
        unsigned long val;
-       unsigned long prev_rate, rate = 0;
+       unsigned long rate = 0;
        unsigned long flags = 0;
 
        for (i = 0; i < factor->ftbl_cnt; i++) {
-               prev_rate = rate;
                rate = (((prate / 10000) * factor->ftbl[i].den) /
                        (factor->ftbl[i].num * factor->masks->factor)) * 10000;
                if (rate > drate)
index 35af3aa..4768023 100644 (file)
@@ -185,6 +185,11 @@ static void __init mv88f6180_get_clk_ratio(
        }
 }
 
+static u32 __init mv98dx1135_get_tclk_freq(void __iomem *sar)
+{
+       return 166666667;
+}
+
 static const struct coreclk_soc_desc kirkwood_coreclks = {
        .get_tclk_freq = kirkwood_get_tclk_freq,
        .get_cpu_freq = kirkwood_get_cpu_freq,
@@ -201,6 +206,14 @@ static const struct coreclk_soc_desc mv88f6180_coreclks = {
        .num_ratios = ARRAY_SIZE(kirkwood_coreclk_ratios),
 };
 
+static const struct coreclk_soc_desc mv98dx1135_coreclks = {
+       .get_tclk_freq = mv98dx1135_get_tclk_freq,
+       .get_cpu_freq = kirkwood_get_cpu_freq,
+       .get_clk_ratio = kirkwood_get_clk_ratio,
+       .ratios = kirkwood_coreclk_ratios,
+       .num_ratios = ARRAY_SIZE(kirkwood_coreclk_ratios),
+};
+
 /*
  * Clock Gating Control
  */
@@ -325,6 +338,8 @@ static void __init kirkwood_clk_init(struct device_node *np)
 
        if (of_device_is_compatible(np, "marvell,mv88f6180-core-clock"))
                mvebu_coreclk_setup(np, &mv88f6180_coreclks);
+       else if (of_device_is_compatible(np, "marvell,mv98dx1135-core-clock"))
+               mvebu_coreclk_setup(np, &mv98dx1135_coreclks);
        else
                mvebu_coreclk_setup(np, &kirkwood_coreclks);
 
@@ -339,3 +354,5 @@ CLK_OF_DECLARE(kirkwood_clk, "marvell,kirkwood-core-clock",
               kirkwood_clk_init);
 CLK_OF_DECLARE(mv88f6180_clk, "marvell,mv88f6180-core-clock",
               kirkwood_clk_init);
+CLK_OF_DECLARE(98dx1135_clk, "marvell,mv98dx1135-core-clock",
+              kirkwood_clk_init);
index d2f39a9..d004cda 100644 (file)
@@ -130,22 +130,6 @@ static const char * const gcc_xo_gpll0_gpll4_gpll0_early_div[] = {
        "gpll0_early_div"
 };
 
-static const struct parent_map gcc_xo_gpll0_gpll2_gpll3_gpll0_early_div_map[] = {
-       { P_XO, 0 },
-       { P_GPLL0, 1 },
-       { P_GPLL2, 2 },
-       { P_GPLL3, 3 },
-       { P_GPLL0_EARLY_DIV, 6 }
-};
-
-static const char * const gcc_xo_gpll0_gpll2_gpll3_gpll0_early_div[] = {
-       "xo",
-       "gpll0",
-       "gpll2",
-       "gpll3",
-       "gpll0_early_div"
-};
-
 static const struct parent_map gcc_xo_gpll0_gpll1_early_div_gpll1_gpll4_gpll0_early_div_map[] = {
        { P_XO, 0 },
        { P_GPLL0, 1 },
@@ -184,26 +168,6 @@ static const char * const gcc_xo_gpll0_gpll2_gpll3_gpll1_gpll2_early_gpll0_early
        "gpll0_early_div"
 };
 
-static const struct parent_map gcc_xo_gpll0_gpll2_gpll3_gpll1_gpll4_gpll0_early_div_map[] = {
-       { P_XO, 0 },
-       { P_GPLL0, 1 },
-       { P_GPLL2, 2 },
-       { P_GPLL3, 3 },
-       { P_GPLL1, 4 },
-       { P_GPLL4, 5 },
-       { P_GPLL0_EARLY_DIV, 6 }
-};
-
-static const char * const gcc_xo_gpll0_gpll2_gpll3_gpll1_gpll4_gpll0_early_div[] = {
-       "xo",
-       "gpll0",
-       "gpll2",
-       "gpll3",
-       "gpll1",
-       "gpll4",
-       "gpll0_early_div"
-};
-
 static struct clk_fixed_factor xo = {
        .mult = 1,
        .div = 1,
index a54807e..29cf464 100644 (file)
@@ -2766,6 +2766,13 @@ static const struct qcom_reset_map gcc_qcs404_resets[] = {
        [GCC_PCIE_0_PHY_BCR] = { 0x3e004 },
        [GCC_PCIE_0_LINK_DOWN_BCR] = { 0x3e038 },
        [GCC_PCIEPHY_0_PHY_BCR] = { 0x3e03c },
+       [GCC_PCIE_0_AXI_MASTER_STICKY_ARES] = { 0x3e040, 6},
+       [GCC_PCIE_0_AHB_ARES] = { 0x3e040, 5 },
+       [GCC_PCIE_0_AXI_SLAVE_ARES] = { 0x3e040, 4 },
+       [GCC_PCIE_0_AXI_MASTER_ARES] = { 0x3e040, 3 },
+       [GCC_PCIE_0_CORE_STICKY_ARES] = { 0x3e040, 2 },
+       [GCC_PCIE_0_SLEEP_ARES] = { 0x3e040, 1 },
+       [GCC_PCIE_0_PIPE_ARES] = { 0x3e040, 0 },
        [GCC_EMAC_BCR] = { 0x4e000 },
 };
 
index 679bc7d..a250f59 100644 (file)
@@ -141,7 +141,9 @@ static int gdsc_toggle_logic(struct gdsc *sc, enum gdsc_status status)
                udelay(1);
        }
 
-       return gdsc_poll_status(sc, status);
+       ret = gdsc_poll_status(sc, status);
+       WARN(ret, "%s status stuck at 'o%s'", sc->pd.name, status ? "ff" : "n");
+       return ret;
 }
 
 static inline int gdsc_deassert_reset(struct gdsc *sc)
index e98a9f5..5ca183e 100644 (file)
@@ -30,8 +30,8 @@
  * @div: divisor value (1-64)
  * @src_shift: Shift to access the register bits to select the parent clock
  * @src_width: Number of register bits to select the parent clock (may be 0)
- * @parents: Array to map from valid parent clocks indices to hardware indices
  * @nb: Notifier block to save/restore clock state for system resume
+ * @parents: Array to map from valid parent clocks indices to hardware indices
  */
 struct div6_clock {
        struct clk_hw hw;
@@ -39,8 +39,8 @@ struct div6_clock {
        unsigned int div;
        u32 src_shift;
        u32 src_width;
-       u8 *parents;
        struct notifier_block nb;
+       u8 parents[];
 };
 
 #define to_div6_clock(_hw) container_of(_hw, struct div6_clock, hw)
@@ -221,17 +221,10 @@ struct clk * __init cpg_div6_register(const char *name,
        struct clk *clk;
        unsigned int i;
 
-       clock = kzalloc(sizeof(*clock), GFP_KERNEL);
+       clock = kzalloc(struct_size(clock, parents, num_parents), GFP_KERNEL);
        if (!clock)
                return ERR_PTR(-ENOMEM);
 
-       clock->parents = kmalloc_array(num_parents, sizeof(*clock->parents),
-                                      GFP_KERNEL);
-       if (!clock->parents) {
-               clk = ERR_PTR(-ENOMEM);
-               goto free_clock;
-       }
-
        clock->reg = reg;
 
        /*
@@ -259,7 +252,7 @@ struct clk * __init cpg_div6_register(const char *name,
                pr_err("%s: invalid number of parents for DIV6 clock %s\n",
                       __func__, name);
                clk = ERR_PTR(-EINVAL);
-               goto free_parents;
+               goto free_clock;
        }
 
        /* Filter out invalid parents */
@@ -282,7 +275,7 @@ struct clk * __init cpg_div6_register(const char *name,
 
        clk = clk_register(NULL, &clock->hw);
        if (IS_ERR(clk))
-               goto free_parents;
+               goto free_clock;
 
        if (notifiers) {
                clock->nb.notifier_call = cpg_div6_clock_notifier_call;
@@ -291,8 +284,6 @@ struct clk * __init cpg_div6_register(const char *name,
 
        return clk;
 
-free_parents:
-       kfree(clock->parents);
 free_clock:
        kfree(clock);
        return clk;
index 92ece22..2db9093 100644 (file)
 /**
  * struct mstp_clock_group - MSTP gating clocks group
  *
- * @data: clocks in this group
+ * @data: clock specifier translation for clocks in this group
  * @smstpcr: module stop control register
  * @mstpsr: module stop status register (optional)
  * @lock: protects writes to SMSTPCR
  * @width_8bit: registers are 8-bit, not 32-bit
+ * @clks: clocks in this group
  */
 struct mstp_clock_group {
        struct clk_onecell_data data;
@@ -42,6 +43,7 @@ struct mstp_clock_group {
        void __iomem *mstpsr;
        spinlock_t lock;
        bool width_8bit;
+       struct clk *clks[];
 };
 
 /**
@@ -186,14 +188,13 @@ static void __init cpg_mstp_clocks_init(struct device_node *np)
        struct clk **clks;
        unsigned int i;
 
-       group = kzalloc(sizeof(*group), GFP_KERNEL);
-       clks = kmalloc_array(MSTP_MAX_CLOCKS, sizeof(*clks), GFP_KERNEL);
-       if (group == NULL || clks == NULL) {
+       group = kzalloc(struct_size(group, clks, MSTP_MAX_CLOCKS), GFP_KERNEL);
+       if (group == NULL) {
                kfree(group);
-               kfree(clks);
                return;
        }
 
+       clks = group->clks;
        spin_lock_init(&group->lock);
        group->data.clks = clks;
 
@@ -203,7 +204,6 @@ static void __init cpg_mstp_clocks_init(struct device_node *np)
        if (group->smstpcr == NULL) {
                pr_err("%s: failed to remap SMSTPCR\n", __func__);
                kfree(group);
-               kfree(clks);
                return;
        }
 
@@ -297,16 +297,12 @@ found:
                return PTR_ERR(clk);
 
        error = pm_clk_create(dev);
-       if (error) {
-               dev_err(dev, "pm_clk_create failed %d\n", error);
+       if (error)
                goto fail_put;
-       }
 
        error = pm_clk_add_clk(dev, clk);
-       if (error) {
-               dev_err(dev, "pm_clk_add_clk %pC failed %d\n", clk, error);
+       if (error)
                goto fail_destroy;
-       }
 
        return 0;
 
index 76ed7d1..e05bfa2 100644 (file)
@@ -113,6 +113,11 @@ static const struct cpg_core_clk r8a774a1_core_clks[] __initconst = {
 };
 
 static const struct mssr_mod_clk r8a774a1_mod_clks[] __initconst = {
+       DEF_MOD("tmu4",                  121,   R8A774A1_CLK_S0D6),
+       DEF_MOD("tmu3",                  122,   R8A774A1_CLK_S3D2),
+       DEF_MOD("tmu2",                  123,   R8A774A1_CLK_S3D2),
+       DEF_MOD("tmu1",                  124,   R8A774A1_CLK_S3D2),
+       DEF_MOD("tmu0",                  125,   R8A774A1_CLK_CP),
        DEF_MOD("fdp1-0",                119,   R8A774A1_CLK_S0D1),
        DEF_MOD("scif5",                 202,   R8A774A1_CLK_S3D4),
        DEF_MOD("scif4",                 203,   R8A774A1_CLK_S3D4),
index 9e9a6f2..fbc8c75 100644 (file)
@@ -138,6 +138,7 @@ static struct mssr_mod_clk r8a7795_mod_clks[] __initdata = {
        DEF_MOD("cmt2",                  301,   R8A7795_CLK_R),
        DEF_MOD("cmt1",                  302,   R8A7795_CLK_R),
        DEF_MOD("cmt0",                  303,   R8A7795_CLK_R),
+       DEF_MOD("tpu0",                  304,   R8A7795_CLK_S3D4),
        DEF_MOD("scif2",                 310,   R8A7795_CLK_S3D4),
        DEF_MOD("sdif3",                 311,   R8A7795_CLK_SD3),
        DEF_MOD("sdif2",                 312,   R8A7795_CLK_SD2),
@@ -201,6 +202,10 @@ static struct mssr_mod_clk r8a7795_mod_clks[] __initdata = {
        DEF_MOD("ehci0",                 703,   R8A7795_CLK_S3D2),
        DEF_MOD("hsusb",                 704,   R8A7795_CLK_S3D2),
        DEF_MOD("hsusb3",                705,   R8A7795_CLK_S3D2),
+       DEF_MOD("cmm3",                  708,   R8A7795_CLK_S2D1),
+       DEF_MOD("cmm2",                  709,   R8A7795_CLK_S2D1),
+       DEF_MOD("cmm1",                  710,   R8A7795_CLK_S2D1),
+       DEF_MOD("cmm0",                  711,   R8A7795_CLK_S2D1),
        DEF_MOD("csi21",                 713,   R8A7795_CLK_CSI0), /* ES1.x */
        DEF_MOD("csi20",                 714,   R8A7795_CLK_CSI0),
        DEF_MOD("csi41",                 715,   R8A7795_CLK_CSI0),
index d8e9af5..90cc6a1 100644 (file)
@@ -134,6 +134,7 @@ static const struct mssr_mod_clk r8a7796_mod_clks[] __initconst = {
        DEF_MOD("cmt2",                  301,   R8A7796_CLK_R),
        DEF_MOD("cmt1",                  302,   R8A7796_CLK_R),
        DEF_MOD("cmt0",                  303,   R8A7796_CLK_R),
+       DEF_MOD("tpu0",                  304,   R8A7796_CLK_S3D4),
        DEF_MOD("scif2",                 310,   R8A7796_CLK_S3D4),
        DEF_MOD("sdif3",                 311,   R8A7796_CLK_SD3),
        DEF_MOD("sdif2",                 312,   R8A7796_CLK_SD2),
@@ -180,6 +181,9 @@ static const struct mssr_mod_clk r8a7796_mod_clks[] __initconst = {
        DEF_MOD("ehci1",                 702,   R8A7796_CLK_S3D2),
        DEF_MOD("ehci0",                 703,   R8A7796_CLK_S3D2),
        DEF_MOD("hsusb",                 704,   R8A7796_CLK_S3D2),
+       DEF_MOD("cmm2",                  709,   R8A7796_CLK_S2D1),
+       DEF_MOD("cmm1",                  710,   R8A7796_CLK_S2D1),
+       DEF_MOD("cmm0",                  711,   R8A7796_CLK_S2D1),
        DEF_MOD("csi20",                 714,   R8A7796_CLK_CSI0),
        DEF_MOD("csi40",                 716,   R8A7796_CLK_CSI0),
        DEF_MOD("du2",                   722,   R8A7796_CLK_S2D1),
index 8f87e31..b4e8c5b 100644 (file)
@@ -132,6 +132,7 @@ static const struct mssr_mod_clk r8a77965_mod_clks[] __initconst = {
        DEF_MOD("cmt2",                 301,    R8A77965_CLK_R),
        DEF_MOD("cmt1",                 302,    R8A77965_CLK_R),
        DEF_MOD("cmt0",                 303,    R8A77965_CLK_R),
+       DEF_MOD("tpu0",                 304,    R8A77965_CLK_S3D4),
        DEF_MOD("scif2",                310,    R8A77965_CLK_S3D4),
        DEF_MOD("sdif3",                311,    R8A77965_CLK_SD3),
        DEF_MOD("sdif2",                312,    R8A77965_CLK_SD2),
@@ -179,6 +180,9 @@ static const struct mssr_mod_clk r8a77965_mod_clks[] __initconst = {
        DEF_MOD("ehci1",                702,    R8A77965_CLK_S3D2),
        DEF_MOD("ehci0",                703,    R8A77965_CLK_S3D2),
        DEF_MOD("hsusb",                704,    R8A77965_CLK_S3D2),
+       DEF_MOD("cmm3",                 708,    R8A77965_CLK_S2D1),
+       DEF_MOD("cmm1",                 710,    R8A77965_CLK_S2D1),
+       DEF_MOD("cmm0",                 711,    R8A77965_CLK_S2D1),
        DEF_MOD("csi20",                714,    R8A77965_CLK_CSI0),
        DEF_MOD("csi40",                716,    R8A77965_CLK_CSI0),
        DEF_MOD("du3",                  721,    R8A77965_CLK_S2D1),
index 9570404..ceabf55 100644 (file)
@@ -183,6 +183,8 @@ static const struct mssr_mod_clk r8a77990_mod_clks[] __initconst = {
 
        DEF_MOD("ehci0",                 703,   R8A77990_CLK_S3D2),
        DEF_MOD("hsusb",                 704,   R8A77990_CLK_S3D2),
+       DEF_MOD("cmm1",                  710,   R8A77990_CLK_S1D1),
+       DEF_MOD("cmm0",                  711,   R8A77990_CLK_S1D1),
        DEF_MOD("csi40",                 716,   R8A77990_CLK_CSI0),
        DEF_MOD("du1",                   723,   R8A77990_CLK_S1D1),
        DEF_MOD("du0",                   724,   R8A77990_CLK_S1D1),
index 6870727..962bb33 100644 (file)
@@ -146,6 +146,8 @@ static const struct mssr_mod_clk r8a77995_mod_clks[] __initconst = {
        DEF_MOD("vspbs",                 627,   R8A77995_CLK_S0D1),
        DEF_MOD("ehci0",                 703,   R8A77995_CLK_S3D2),
        DEF_MOD("hsusb",                 704,   R8A77995_CLK_S3D2),
+       DEF_MOD("cmm1",                  710,   R8A77995_CLK_S1D1),
+       DEF_MOD("cmm0",                  711,   R8A77995_CLK_S1D1),
        DEF_MOD("du1",                   723,   R8A77995_CLK_S1D1),
        DEF_MOD("du0",                   724,   R8A77995_CLK_S1D1),
        DEF_MOD("lvds",                  727,   R8A77995_CLK_S2D1),
index 7d04218..b33e138 100644 (file)
@@ -17,6 +17,8 @@
 #include <linux/of.h>
 #include <linux/of_address.h>
 #include <linux/platform_device.h>
+#include <linux/pm_clock.h>
+#include <linux/pm_domain.h>
 #include <linux/slab.h>
 #include <linux/spinlock.h>
 #include <dt-bindings/clock/r9a06g032-sysctrl.h>
@@ -29,6 +31,7 @@ struct r9a06g032_gate {
 /* This is used to describe a clock for instantiation */
 struct r9a06g032_clkdesc {
        const char *name;
+       uint32_t managed: 1;
        uint32_t type: 3;
        uint32_t index: 8;
        uint32_t source : 8; /* source index + 1 (0 == none) */
@@ -61,7 +64,11 @@ struct r9a06g032_clkdesc {
 #define D_GATE(_idx, _n, _src, ...) \
        { .type = K_GATE, .index = R9A06G032_##_idx, \
                .source = 1 + R9A06G032_##_src, .name = _n, \
-               .gate = I_GATE(__VA_ARGS__), }
+               .gate = I_GATE(__VA_ARGS__) }
+#define D_MODULE(_idx, _n, _src, ...) \
+       { .type = K_GATE, .index = R9A06G032_##_idx, \
+               .source = 1 + R9A06G032_##_src, .name = _n, \
+               .managed = 1, .gate = I_GATE(__VA_ARGS__) }
 #define D_ROOT(_idx, _n, _mul, _div) \
        { .type = K_FFC, .index = R9A06G032_##_idx, .name = _n, \
                .div = _div, .mul = _mul }
@@ -122,7 +129,7 @@ enum { K_GATE = 0, K_FFC, K_DIV, K_BITSEL, K_DUALGATE };
 
 #define R9A06G032_CLOCK_COUNT          (R9A06G032_UART_GROUP_34567 + 1)
 
-static const struct r9a06g032_clkdesc r9a06g032_clocks[] __initconst = {
+static const struct r9a06g032_clkdesc r9a06g032_clocks[] = {
        D_ROOT(CLKOUT, "clkout", 25, 1),
        D_ROOT(CLK_PLL_USB, "clk_pll_usb", 12, 10),
        D_FFC(CLKOUT_D10, "clkout_d10", CLKOUT, 10),
@@ -171,7 +178,7 @@ static const struct r9a06g032_clkdesc r9a06g032_clocks[] __initconst = {
        D_GATE(CLK_P6_PG2, "clk_p6_pg2", DIV_P6_PG, 0x8a3, 0x8a4, 0x8a5, 0, 0xb61, 0, 0),
        D_GATE(CLK_P6_PG3, "clk_p6_pg3", DIV_P6_PG, 0x8a6, 0x8a7, 0x8a8, 0, 0xb62, 0, 0),
        D_GATE(CLK_P6_PG4, "clk_p6_pg4", DIV_P6_PG, 0x8a9, 0x8aa, 0x8ab, 0, 0xb63, 0, 0),
-       D_GATE(CLK_PCI_USB, "clk_pci_usb", CLKOUT_D40, 0xe6, 0, 0, 0, 0, 0, 0),
+       D_MODULE(CLK_PCI_USB, "clk_pci_usb", CLKOUT_D40, 0xe6, 0, 0, 0, 0, 0, 0),
        D_GATE(CLK_QSPI0, "clk_qspi0", DIV_QSPI0, 0x2a4, 0x2a5, 0, 0, 0, 0, 0),
        D_GATE(CLK_QSPI1, "clk_qspi1", DIV_QSPI1, 0x484, 0x485, 0, 0, 0, 0, 0),
        D_GATE(CLK_RGMII_REF, "clk_rgmii_ref", CLKOUT_D8, 0x340, 0, 0, 0, 0, 0, 0),
@@ -188,17 +195,17 @@ static const struct r9a06g032_clkdesc r9a06g032_clocks[] __initconst = {
        D_GATE(CLK_SPI5, "clk_spi5", DIV_P4_PG, 0x822, 0x823, 0, 0, 0, 0, 0),
        D_GATE(CLK_SWITCH, "clk_switch", DIV_SWITCH, 0x982, 0x983, 0, 0, 0, 0, 0),
        D_DIV(DIV_MOTOR, "div_motor", CLKOUT_D5, 84, 2, 8),
-       D_GATE(HCLK_ECAT125, "hclk_ecat125", CLKOUT_D8, 0x400, 0x401, 0, 0x402, 0, 0x440, 0x441),
-       D_GATE(HCLK_PINCONFIG, "hclk_pinconfig", CLKOUT_D40, 0x740, 0x741, 0x742, 0, 0xae0, 0, 0),
-       D_GATE(HCLK_SERCOS, "hclk_sercos", CLKOUT_D10, 0x420, 0x422, 0, 0x421, 0, 0x460, 0x461),
-       D_GATE(HCLK_SGPIO2, "hclk_sgpio2", DIV_P5_PG, 0x8c3, 0x8c4, 0x8c5, 0, 0xb41, 0, 0),
-       D_GATE(HCLK_SGPIO3, "hclk_sgpio3", DIV_P5_PG, 0x8c6, 0x8c7, 0x8c8, 0, 0xb42, 0, 0),
-       D_GATE(HCLK_SGPIO4, "hclk_sgpio4", DIV_P5_PG, 0x8c9, 0x8ca, 0x8cb, 0, 0xb43, 0, 0),
-       D_GATE(HCLK_TIMER0, "hclk_timer0", CLKOUT_D40, 0x743, 0x744, 0x745, 0, 0xae1, 0, 0),
-       D_GATE(HCLK_TIMER1, "hclk_timer1", CLKOUT_D40, 0x746, 0x747, 0x748, 0, 0xae2, 0, 0),
-       D_GATE(HCLK_USBF, "hclk_usbf", CLKOUT_D8, 0xe3, 0, 0, 0xe4, 0, 0x102, 0x103),
-       D_GATE(HCLK_USBH, "hclk_usbh", CLKOUT_D8, 0xe0, 0xe1, 0, 0xe2, 0, 0x100, 0x101),
-       D_GATE(HCLK_USBPM, "hclk_usbpm", CLKOUT_D8, 0xe5, 0, 0, 0, 0, 0, 0),
+       D_MODULE(HCLK_ECAT125, "hclk_ecat125", CLKOUT_D8, 0x400, 0x401, 0, 0x402, 0, 0x440, 0x441),
+       D_MODULE(HCLK_PINCONFIG, "hclk_pinconfig", CLKOUT_D40, 0x740, 0x741, 0x742, 0, 0xae0, 0, 0),
+       D_MODULE(HCLK_SERCOS, "hclk_sercos", CLKOUT_D10, 0x420, 0x422, 0, 0x421, 0, 0x460, 0x461),
+       D_MODULE(HCLK_SGPIO2, "hclk_sgpio2", DIV_P5_PG, 0x8c3, 0x8c4, 0x8c5, 0, 0xb41, 0, 0),
+       D_MODULE(HCLK_SGPIO3, "hclk_sgpio3", DIV_P5_PG, 0x8c6, 0x8c7, 0x8c8, 0, 0xb42, 0, 0),
+       D_MODULE(HCLK_SGPIO4, "hclk_sgpio4", DIV_P5_PG, 0x8c9, 0x8ca, 0x8cb, 0, 0xb43, 0, 0),
+       D_MODULE(HCLK_TIMER0, "hclk_timer0", CLKOUT_D40, 0x743, 0x744, 0x745, 0, 0xae1, 0, 0),
+       D_MODULE(HCLK_TIMER1, "hclk_timer1", CLKOUT_D40, 0x746, 0x747, 0x748, 0, 0xae2, 0, 0),
+       D_MODULE(HCLK_USBF, "hclk_usbf", CLKOUT_D8, 0xe3, 0, 0, 0xe4, 0, 0x102, 0x103),
+       D_MODULE(HCLK_USBH, "hclk_usbh", CLKOUT_D8, 0xe0, 0xe1, 0, 0xe2, 0, 0x100, 0x101),
+       D_MODULE(HCLK_USBPM, "hclk_usbpm", CLKOUT_D8, 0xe5, 0, 0, 0, 0, 0, 0),
        D_GATE(CLK_48_PG_F, "clk_48_pg_f", CLK_48, 0x78c, 0x78d, 0, 0x78e, 0, 0xb04, 0xb05),
        D_GATE(CLK_48_PG4, "clk_48_pg4", CLK_48, 0x789, 0x78a, 0x78b, 0, 0xb03, 0, 0),
        D_FFC(CLK_DDRPHY_PLLCLK_D4, "clk_ddrphy_pllclk_d4", CLK_DDRPHY_PLLCLK, 4),
@@ -208,13 +215,13 @@ static const struct r9a06g032_clkdesc r9a06g032_clocks[] __initconst = {
        D_FFC(CLK_REF_SYNC_D8, "clk_ref_sync_d8", CLK_REF_SYNC, 8),
        D_FFC(CLK_SERCOS100_D2, "clk_sercos100_d2", CLK_SERCOS100, 2),
        D_DIV(DIV_CA7, "div_ca7", CLK_REF_SYNC, 57, 1, 4, 1, 2, 4),
-       D_GATE(HCLK_CAN0, "hclk_can0", CLK_48, 0x783, 0x784, 0x785, 0, 0xb01, 0, 0),
-       D_GATE(HCLK_CAN1, "hclk_can1", CLK_48, 0x786, 0x787, 0x788, 0, 0xb02, 0, 0),
-       D_GATE(HCLK_DELTASIGMA, "hclk_deltasigma", DIV_MOTOR, 0x1ef, 0x1f0, 0x1f1, 0, 0, 0, 0),
-       D_GATE(HCLK_PWMPTO, "hclk_pwmpto", DIV_MOTOR, 0x1ec, 0x1ed, 0x1ee, 0, 0, 0, 0),
-       D_GATE(HCLK_RSV, "hclk_rsv", CLK_48, 0x780, 0x781, 0x782, 0, 0xb00, 0, 0),
-       D_GATE(HCLK_SGPIO0, "hclk_sgpio0", DIV_MOTOR, 0x1e0, 0x1e1, 0x1e2, 0, 0, 0, 0),
-       D_GATE(HCLK_SGPIO1, "hclk_sgpio1", DIV_MOTOR, 0x1e3, 0x1e4, 0x1e5, 0, 0, 0, 0),
+       D_MODULE(HCLK_CAN0, "hclk_can0", CLK_48, 0x783, 0x784, 0x785, 0, 0xb01, 0, 0),
+       D_MODULE(HCLK_CAN1, "hclk_can1", CLK_48, 0x786, 0x787, 0x788, 0, 0xb02, 0, 0),
+       D_MODULE(HCLK_DELTASIGMA, "hclk_deltasigma", DIV_MOTOR, 0x1ef, 0x1f0, 0x1f1, 0, 0, 0, 0),
+       D_MODULE(HCLK_PWMPTO, "hclk_pwmpto", DIV_MOTOR, 0x1ec, 0x1ed, 0x1ee, 0, 0, 0, 0),
+       D_MODULE(HCLK_RSV, "hclk_rsv", CLK_48, 0x780, 0x781, 0x782, 0, 0xb00, 0, 0),
+       D_MODULE(HCLK_SGPIO0, "hclk_sgpio0", DIV_MOTOR, 0x1e0, 0x1e1, 0x1e2, 0, 0, 0, 0),
+       D_MODULE(HCLK_SGPIO1, "hclk_sgpio1", DIV_MOTOR, 0x1e3, 0x1e4, 0x1e5, 0, 0, 0, 0),
        D_DIV(RTOS_MDC, "rtos_mdc", CLK_REF_SYNC, 100, 80, 640, 80, 160, 320, 640),
        D_GATE(CLK_CM3, "clk_cm3", CLK_REF_SYNC_D4, 0xba0, 0xba1, 0, 0xba2, 0, 0xbc0, 0xbc1),
        D_GATE(CLK_DDRC, "clk_ddrc", CLK_DDRPHY_PLLCLK_D4, 0x323, 0x324, 0, 0, 0, 0, 0),
@@ -222,53 +229,53 @@ static const struct r9a06g032_clkdesc r9a06g032_clocks[] __initconst = {
        D_GATE(CLK_HSR50, "clk_hsr50", CLK_HSR100_D2, 0x484, 0x485, 0, 0, 0, 0, 0),
        D_GATE(CLK_HW_RTOS, "clk_hw_rtos", CLK_REF_SYNC_D4, 0xc60, 0xc61, 0, 0, 0, 0, 0),
        D_GATE(CLK_SERCOS50, "clk_sercos50", CLK_SERCOS100_D2, 0x424, 0x423, 0, 0, 0, 0, 0),
-       D_GATE(HCLK_ADC, "hclk_adc", CLK_REF_SYNC_D8, 0x1af, 0x1b0, 0x1b1, 0, 0, 0, 0),
-       D_GATE(HCLK_CM3, "hclk_cm3", CLK_REF_SYNC_D4, 0xc20, 0xc21, 0xc22, 0, 0, 0, 0),
-       D_GATE(HCLK_CRYPTO_EIP150, "hclk_crypto_eip150", CLK_REF_SYNC_D4, 0x123, 0x124, 0x125, 0, 0x142, 0, 0),
-       D_GATE(HCLK_CRYPTO_EIP93, "hclk_crypto_eip93", CLK_REF_SYNC_D4, 0x120, 0x121, 0, 0x122, 0, 0x140, 0x141),
-       D_GATE(HCLK_DDRC, "hclk_ddrc", CLK_REF_SYNC_D4, 0x320, 0x322, 0, 0x321, 0, 0x3a0, 0x3a1),
-       D_GATE(HCLK_DMA0, "hclk_dma0", CLK_REF_SYNC_D4, 0x260, 0x261, 0x262, 0x263, 0x2c0, 0x2c1, 0x2c2),
-       D_GATE(HCLK_DMA1, "hclk_dma1", CLK_REF_SYNC_D4, 0x264, 0x265, 0x266, 0x267, 0x2c3, 0x2c4, 0x2c5),
-       D_GATE(HCLK_GMAC0, "hclk_gmac0", CLK_REF_SYNC_D4, 0x360, 0x361, 0x362, 0x363, 0x3c0, 0x3c1, 0x3c2),
-       D_GATE(HCLK_GMAC1, "hclk_gmac1", CLK_REF_SYNC_D4, 0x380, 0x381, 0x382, 0x383, 0x3e0, 0x3e1, 0x3e2),
-       D_GATE(HCLK_GPIO0, "hclk_gpio0", CLK_REF_SYNC_D4, 0x212, 0x213, 0x214, 0, 0, 0, 0),
-       D_GATE(HCLK_GPIO1, "hclk_gpio1", CLK_REF_SYNC_D4, 0x215, 0x216, 0x217, 0, 0, 0, 0),
-       D_GATE(HCLK_GPIO2, "hclk_gpio2", CLK_REF_SYNC_D4, 0x229, 0x22a, 0x22b, 0, 0, 0, 0),
-       D_GATE(HCLK_HSR, "hclk_hsr", CLK_HSR100_D2, 0x480, 0x482, 0, 0x481, 0, 0x4c0, 0x4c1),
-       D_GATE(HCLK_I2C0, "hclk_i2c0", CLK_REF_SYNC_D8, 0x1a9, 0x1aa, 0x1ab, 0, 0, 0, 0),
-       D_GATE(HCLK_I2C1, "hclk_i2c1", CLK_REF_SYNC_D8, 0x1ac, 0x1ad, 0x1ae, 0, 0, 0, 0),
-       D_GATE(HCLK_LCD, "hclk_lcd", CLK_REF_SYNC_D4, 0x7a0, 0x7a1, 0x7a2, 0, 0xb20, 0, 0),
-       D_GATE(HCLK_MSEBI_M, "hclk_msebi_m", CLK_REF_SYNC_D4, 0x164, 0x165, 0x166, 0, 0x183, 0, 0),
-       D_GATE(HCLK_MSEBI_S, "hclk_msebi_s", CLK_REF_SYNC_D4, 0x160, 0x161, 0x162, 0x163, 0x180, 0x181, 0x182),
-       D_GATE(HCLK_NAND, "hclk_nand", CLK_REF_SYNC_D4, 0x280, 0x281, 0x282, 0x283, 0x2e0, 0x2e1, 0x2e2),
-       D_GATE(HCLK_PG_I, "hclk_pg_i", CLK_REF_SYNC_D4, 0x7ac, 0x7ad, 0, 0x7ae, 0, 0xb24, 0xb25),
-       D_GATE(HCLK_PG19, "hclk_pg19", CLK_REF_SYNC_D4, 0x22c, 0x22d, 0x22e, 0, 0, 0, 0),
-       D_GATE(HCLK_PG20, "hclk_pg20", CLK_REF_SYNC_D4, 0x22f, 0x230, 0x231, 0, 0, 0, 0),
-       D_GATE(HCLK_PG3, "hclk_pg3", CLK_REF_SYNC_D4, 0x7a6, 0x7a7, 0x7a8, 0, 0xb22, 0, 0),
-       D_GATE(HCLK_PG4, "hclk_pg4", CLK_REF_SYNC_D4, 0x7a9, 0x7aa, 0x7ab, 0, 0xb23, 0, 0),
-       D_GATE(HCLK_QSPI0, "hclk_qspi0", CLK_REF_SYNC_D4, 0x2a0, 0x2a1, 0x2a2, 0x2a3, 0x300, 0x301, 0x302),
-       D_GATE(HCLK_QSPI1, "hclk_qspi1", CLK_REF_SYNC_D4, 0x480, 0x481, 0x482, 0x483, 0x4c0, 0x4c1, 0x4c2),
-       D_GATE(HCLK_ROM, "hclk_rom", CLK_REF_SYNC_D4, 0xaa0, 0xaa1, 0xaa2, 0, 0xb80, 0, 0),
-       D_GATE(HCLK_RTC, "hclk_rtc", CLK_REF_SYNC_D8, 0xa00, 0, 0, 0, 0, 0, 0),
-       D_GATE(HCLK_SDIO0, "hclk_sdio0", CLK_REF_SYNC_D4, 0x60, 0x61, 0x62, 0x63, 0x80, 0x81, 0x82),
-       D_GATE(HCLK_SDIO1, "hclk_sdio1", CLK_REF_SYNC_D4, 0x640, 0x641, 0x642, 0x643, 0x660, 0x661, 0x662),
-       D_GATE(HCLK_SEMAP, "hclk_semap", CLK_REF_SYNC_D4, 0x7a3, 0x7a4, 0x7a5, 0, 0xb21, 0, 0),
-       D_GATE(HCLK_SPI0, "hclk_spi0", CLK_REF_SYNC_D4, 0x200, 0x201, 0x202, 0, 0, 0, 0),
-       D_GATE(HCLK_SPI1, "hclk_spi1", CLK_REF_SYNC_D4, 0x203, 0x204, 0x205, 0, 0, 0, 0),
-       D_GATE(HCLK_SPI2, "hclk_spi2", CLK_REF_SYNC_D4, 0x206, 0x207, 0x208, 0, 0, 0, 0),
-       D_GATE(HCLK_SPI3, "hclk_spi3", CLK_REF_SYNC_D4, 0x209, 0x20a, 0x20b, 0, 0, 0, 0),
-       D_GATE(HCLK_SPI4, "hclk_spi4", CLK_REF_SYNC_D4, 0x20c, 0x20d, 0x20e, 0, 0, 0, 0),
-       D_GATE(HCLK_SPI5, "hclk_spi5", CLK_REF_SYNC_D4, 0x20f, 0x210, 0x211, 0, 0, 0, 0),
-       D_GATE(HCLK_SWITCH, "hclk_switch", CLK_REF_SYNC_D4, 0x980, 0, 0x981, 0, 0, 0, 0),
-       D_GATE(HCLK_SWITCH_RG, "hclk_switch_rg", CLK_REF_SYNC_D4, 0xc40, 0xc41, 0xc42, 0, 0, 0, 0),
-       D_GATE(HCLK_UART0, "hclk_uart0", CLK_REF_SYNC_D8, 0x1a0, 0x1a1, 0x1a2, 0, 0, 0, 0),
-       D_GATE(HCLK_UART1, "hclk_uart1", CLK_REF_SYNC_D8, 0x1a3, 0x1a4, 0x1a5, 0, 0, 0, 0),
-       D_GATE(HCLK_UART2, "hclk_uart2", CLK_REF_SYNC_D8, 0x1a6, 0x1a7, 0x1a8, 0, 0, 0, 0),
-       D_GATE(HCLK_UART3, "hclk_uart3", CLK_REF_SYNC_D4, 0x218, 0x219, 0x21a, 0, 0, 0, 0),
-       D_GATE(HCLK_UART4, "hclk_uart4", CLK_REF_SYNC_D4, 0x21b, 0x21c, 0x21d, 0, 0, 0, 0),
-       D_GATE(HCLK_UART5, "hclk_uart5", CLK_REF_SYNC_D4, 0x220, 0x221, 0x222, 0, 0, 0, 0),
-       D_GATE(HCLK_UART6, "hclk_uart6", CLK_REF_SYNC_D4, 0x223, 0x224, 0x225, 0, 0, 0, 0),
-       D_GATE(HCLK_UART7, "hclk_uart7", CLK_REF_SYNC_D4, 0x226, 0x227, 0x228, 0, 0, 0, 0),
+       D_MODULE(HCLK_ADC, "hclk_adc", CLK_REF_SYNC_D8, 0x1af, 0x1b0, 0x1b1, 0, 0, 0, 0),
+       D_MODULE(HCLK_CM3, "hclk_cm3", CLK_REF_SYNC_D4, 0xc20, 0xc21, 0xc22, 0, 0, 0, 0),
+       D_MODULE(HCLK_CRYPTO_EIP150, "hclk_crypto_eip150", CLK_REF_SYNC_D4, 0x123, 0x124, 0x125, 0, 0x142, 0, 0),
+       D_MODULE(HCLK_CRYPTO_EIP93, "hclk_crypto_eip93", CLK_REF_SYNC_D4, 0x120, 0x121, 0, 0x122, 0, 0x140, 0x141),
+       D_MODULE(HCLK_DDRC, "hclk_ddrc", CLK_REF_SYNC_D4, 0x320, 0x322, 0, 0x321, 0, 0x3a0, 0x3a1),
+       D_MODULE(HCLK_DMA0, "hclk_dma0", CLK_REF_SYNC_D4, 0x260, 0x261, 0x262, 0x263, 0x2c0, 0x2c1, 0x2c2),
+       D_MODULE(HCLK_DMA1, "hclk_dma1", CLK_REF_SYNC_D4, 0x264, 0x265, 0x266, 0x267, 0x2c3, 0x2c4, 0x2c5),
+       D_MODULE(HCLK_GMAC0, "hclk_gmac0", CLK_REF_SYNC_D4, 0x360, 0x361, 0x362, 0x363, 0x3c0, 0x3c1, 0x3c2),
+       D_MODULE(HCLK_GMAC1, "hclk_gmac1", CLK_REF_SYNC_D4, 0x380, 0x381, 0x382, 0x383, 0x3e0, 0x3e1, 0x3e2),
+       D_MODULE(HCLK_GPIO0, "hclk_gpio0", CLK_REF_SYNC_D4, 0x212, 0x213, 0x214, 0, 0, 0, 0),
+       D_MODULE(HCLK_GPIO1, "hclk_gpio1", CLK_REF_SYNC_D4, 0x215, 0x216, 0x217, 0, 0, 0, 0),
+       D_MODULE(HCLK_GPIO2, "hclk_gpio2", CLK_REF_SYNC_D4, 0x229, 0x22a, 0x22b, 0, 0, 0, 0),
+       D_MODULE(HCLK_HSR, "hclk_hsr", CLK_HSR100_D2, 0x480, 0x482, 0, 0x481, 0, 0x4c0, 0x4c1),
+       D_MODULE(HCLK_I2C0, "hclk_i2c0", CLK_REF_SYNC_D8, 0x1a9, 0x1aa, 0x1ab, 0, 0, 0, 0),
+       D_MODULE(HCLK_I2C1, "hclk_i2c1", CLK_REF_SYNC_D8, 0x1ac, 0x1ad, 0x1ae, 0, 0, 0, 0),
+       D_MODULE(HCLK_LCD, "hclk_lcd", CLK_REF_SYNC_D4, 0x7a0, 0x7a1, 0x7a2, 0, 0xb20, 0, 0),
+       D_MODULE(HCLK_MSEBI_M, "hclk_msebi_m", CLK_REF_SYNC_D4, 0x164, 0x165, 0x166, 0, 0x183, 0, 0),
+       D_MODULE(HCLK_MSEBI_S, "hclk_msebi_s", CLK_REF_SYNC_D4, 0x160, 0x161, 0x162, 0x163, 0x180, 0x181, 0x182),
+       D_MODULE(HCLK_NAND, "hclk_nand", CLK_REF_SYNC_D4, 0x280, 0x281, 0x282, 0x283, 0x2e0, 0x2e1, 0x2e2),
+       D_MODULE(HCLK_PG_I, "hclk_pg_i", CLK_REF_SYNC_D4, 0x7ac, 0x7ad, 0, 0x7ae, 0, 0xb24, 0xb25),
+       D_MODULE(HCLK_PG19, "hclk_pg19", CLK_REF_SYNC_D4, 0x22c, 0x22d, 0x22e, 0, 0, 0, 0),
+       D_MODULE(HCLK_PG20, "hclk_pg20", CLK_REF_SYNC_D4, 0x22f, 0x230, 0x231, 0, 0, 0, 0),
+       D_MODULE(HCLK_PG3, "hclk_pg3", CLK_REF_SYNC_D4, 0x7a6, 0x7a7, 0x7a8, 0, 0xb22, 0, 0),
+       D_MODULE(HCLK_PG4, "hclk_pg4", CLK_REF_SYNC_D4, 0x7a9, 0x7aa, 0x7ab, 0, 0xb23, 0, 0),
+       D_MODULE(HCLK_QSPI0, "hclk_qspi0", CLK_REF_SYNC_D4, 0x2a0, 0x2a1, 0x2a2, 0x2a3, 0x300, 0x301, 0x302),
+       D_MODULE(HCLK_QSPI1, "hclk_qspi1", CLK_REF_SYNC_D4, 0x480, 0x481, 0x482, 0x483, 0x4c0, 0x4c1, 0x4c2),
+       D_MODULE(HCLK_ROM, "hclk_rom", CLK_REF_SYNC_D4, 0xaa0, 0xaa1, 0xaa2, 0, 0xb80, 0, 0),
+       D_MODULE(HCLK_RTC, "hclk_rtc", CLK_REF_SYNC_D8, 0xa00, 0, 0, 0, 0, 0, 0),
+       D_MODULE(HCLK_SDIO0, "hclk_sdio0", CLK_REF_SYNC_D4, 0x60, 0x61, 0x62, 0x63, 0x80, 0x81, 0x82),
+       D_MODULE(HCLK_SDIO1, "hclk_sdio1", CLK_REF_SYNC_D4, 0x640, 0x641, 0x642, 0x643, 0x660, 0x661, 0x662),
+       D_MODULE(HCLK_SEMAP, "hclk_semap", CLK_REF_SYNC_D4, 0x7a3, 0x7a4, 0x7a5, 0, 0xb21, 0, 0),
+       D_MODULE(HCLK_SPI0, "hclk_spi0", CLK_REF_SYNC_D4, 0x200, 0x201, 0x202, 0, 0, 0, 0),
+       D_MODULE(HCLK_SPI1, "hclk_spi1", CLK_REF_SYNC_D4, 0x203, 0x204, 0x205, 0, 0, 0, 0),
+       D_MODULE(HCLK_SPI2, "hclk_spi2", CLK_REF_SYNC_D4, 0x206, 0x207, 0x208, 0, 0, 0, 0),
+       D_MODULE(HCLK_SPI3, "hclk_spi3", CLK_REF_SYNC_D4, 0x209, 0x20a, 0x20b, 0, 0, 0, 0),
+       D_MODULE(HCLK_SPI4, "hclk_spi4", CLK_REF_SYNC_D4, 0x20c, 0x20d, 0x20e, 0, 0, 0, 0),
+       D_MODULE(HCLK_SPI5, "hclk_spi5", CLK_REF_SYNC_D4, 0x20f, 0x210, 0x211, 0, 0, 0, 0),
+       D_MODULE(HCLK_SWITCH, "hclk_switch", CLK_REF_SYNC_D4, 0x980, 0, 0x981, 0, 0, 0, 0),
+       D_MODULE(HCLK_SWITCH_RG, "hclk_switch_rg", CLK_REF_SYNC_D4, 0xc40, 0xc41, 0xc42, 0, 0, 0, 0),
+       D_MODULE(HCLK_UART0, "hclk_uart0", CLK_REF_SYNC_D8, 0x1a0, 0x1a1, 0x1a2, 0, 0, 0, 0),
+       D_MODULE(HCLK_UART1, "hclk_uart1", CLK_REF_SYNC_D8, 0x1a3, 0x1a4, 0x1a5, 0, 0, 0, 0),
+       D_MODULE(HCLK_UART2, "hclk_uart2", CLK_REF_SYNC_D8, 0x1a6, 0x1a7, 0x1a8, 0, 0, 0, 0),
+       D_MODULE(HCLK_UART3, "hclk_uart3", CLK_REF_SYNC_D4, 0x218, 0x219, 0x21a, 0, 0, 0, 0),
+       D_MODULE(HCLK_UART4, "hclk_uart4", CLK_REF_SYNC_D4, 0x21b, 0x21c, 0x21d, 0, 0, 0, 0),
+       D_MODULE(HCLK_UART5, "hclk_uart5", CLK_REF_SYNC_D4, 0x220, 0x221, 0x222, 0, 0, 0, 0),
+       D_MODULE(HCLK_UART6, "hclk_uart6", CLK_REF_SYNC_D4, 0x223, 0x224, 0x225, 0, 0, 0, 0),
+       D_MODULE(HCLK_UART7, "hclk_uart7", CLK_REF_SYNC_D4, 0x226, 0x227, 0x228, 0, 0, 0, 0),
        /*
         * These are not hardware clocks, but are needed to handle the special
         * case where we have a 'selector bit' that doesn't just change the
@@ -345,6 +352,84 @@ struct r9a06g032_clk_gate {
 
 #define to_r9a06g032_gate(_hw) container_of(_hw, struct r9a06g032_clk_gate, hw)
 
+static int create_add_module_clock(struct of_phandle_args *clkspec,
+                                  struct device *dev)
+{
+       struct clk *clk;
+       int error;
+
+       clk = of_clk_get_from_provider(clkspec);
+       if (IS_ERR(clk))
+               return PTR_ERR(clk);
+
+       error = pm_clk_create(dev);
+       if (error) {
+               clk_put(clk);
+               return error;
+       }
+
+       error = pm_clk_add_clk(dev, clk);
+       if (error) {
+               pm_clk_destroy(dev);
+               clk_put(clk);
+       }
+
+       return error;
+}
+
+static int r9a06g032_attach_dev(struct generic_pm_domain *pd,
+                               struct device *dev)
+{
+       struct device_node *np = dev->of_node;
+       struct of_phandle_args clkspec;
+       int i = 0;
+       int error;
+       int index;
+
+       while (!of_parse_phandle_with_args(np, "clocks", "#clock-cells", i,
+                                          &clkspec)) {
+               if (clkspec.np != pd->dev.of_node)
+                       continue;
+
+               index = clkspec.args[0];
+               if (index < R9A06G032_CLOCK_COUNT &&
+                   r9a06g032_clocks[index].managed) {
+                       error = create_add_module_clock(&clkspec, dev);
+                       of_node_put(clkspec.np);
+                       if (error)
+                               return error;
+               }
+               i++;
+       }
+
+       return 0;
+}
+
+static void r9a06g032_detach_dev(struct generic_pm_domain *unused, struct device *dev)
+{
+       if (!pm_clk_no_clocks(dev))
+               pm_clk_destroy(dev);
+}
+
+static int r9a06g032_add_clk_domain(struct device *dev)
+{
+       struct device_node *np = dev->of_node;
+       struct generic_pm_domain *pd;
+
+       pd = devm_kzalloc(dev, sizeof(*pd), GFP_KERNEL);
+       if (!pd)
+               return -ENOMEM;
+
+       pd->name = np->name;
+       pd->flags = GENPD_FLAG_PM_CLK | GENPD_FLAG_ACTIVE_WAKEUP;
+       pd->attach_dev = r9a06g032_attach_dev;
+       pd->detach_dev = r9a06g032_detach_dev;
+       pm_genpd_init(pd, &pm_domain_always_on_gov, false);
+
+       of_genpd_add_provider_simple(np, pd);
+       return 0;
+}
+
 static void
 r9a06g032_clk_gate_set(struct r9a06g032_priv *clocks,
                       struct r9a06g032_gate *g, int on)
@@ -871,8 +956,12 @@ static int __init r9a06g032_clocks_probe(struct platform_device *pdev)
        if (error)
                return error;
 
-       return devm_add_action_or_reset(dev,
+       error = devm_add_action_or_reset(dev,
                                        r9a06g032_clocks_del_clk_provider, np);
+       if (error)
+               return error;
+
+       return r9a06g032_add_clk_domain(dev);
 }
 
 static const struct of_device_id r9a06g032_match[] = {
index 0201809..52bbb9c 100644 (file)
@@ -112,14 +112,15 @@ static const u16 srcr[] = {
  * @dev: CPG/MSSR device
  * @base: CPG/MSSR register block base address
  * @rmw_lock: protects RMW register accesses
- * @clks: Array containing all Core and Module Clocks
+ * @np: Device node in DT for this CPG/MSSR module
  * @num_core_clks: Number of Core Clocks in clks[]
  * @num_mod_clks: Number of Module Clocks in clks[]
  * @last_dt_core_clk: ID of the last Core Clock exported to DT
+ * @stbyctrl: This device has Standby Control Registers
  * @notifiers: Notifier chain to save/restore clock state for system resume
  * @smstpcr_saved[].mask: Mask of SMSTPCR[] bits under our control
  * @smstpcr_saved[].val: Saved values of SMSTPCR[]
- * @stbyctrl: This device has Standby Control Registers
+ * @clks: Array containing all Core and Module Clocks
  */
 struct cpg_mssr_priv {
 #ifdef CONFIG_RESET_CONTROLLER
@@ -130,7 +131,6 @@ struct cpg_mssr_priv {
        spinlock_t rmw_lock;
        struct device_node *np;
 
-       struct clk **clks;
        unsigned int num_core_clks;
        unsigned int num_mod_clks;
        unsigned int last_dt_core_clk;
@@ -141,6 +141,8 @@ struct cpg_mssr_priv {
                u32 mask;
                u32 val;
        } smstpcr_saved[ARRAY_SIZE(smstpcr)];
+
+       struct clk *clks[];
 };
 
 static struct cpg_mssr_priv *cpg_mssr_priv;
@@ -447,9 +449,8 @@ fail:
 
 struct cpg_mssr_clk_domain {
        struct generic_pm_domain genpd;
-       struct device_node *np;
        unsigned int num_core_pm_clks;
-       unsigned int core_pm_clks[0];
+       unsigned int core_pm_clks[];
 };
 
 static struct cpg_mssr_clk_domain *cpg_mssr_clk_domain;
@@ -459,7 +460,7 @@ static bool cpg_mssr_is_pm_clk(const struct of_phandle_args *clkspec,
 {
        unsigned int i;
 
-       if (clkspec->np != pd->np || clkspec->args_count != 2)
+       if (clkspec->np != pd->genpd.dev.of_node || clkspec->args_count != 2)
                return false;
 
        switch (clkspec->args[0]) {
@@ -510,16 +511,12 @@ found:
                return PTR_ERR(clk);
 
        error = pm_clk_create(dev);
-       if (error) {
-               dev_err(dev, "pm_clk_create failed %d\n", error);
+       if (error)
                goto fail_put;
-       }
 
        error = pm_clk_add_clk(dev, clk);
-       if (error) {
-               dev_err(dev, "pm_clk_add_clk %pC failed %d\n", clk, error);
+       if (error)
                goto fail_destroy;
-       }
 
        return 0;
 
@@ -549,7 +546,6 @@ static int __init cpg_mssr_add_clk_domain(struct device *dev,
        if (!pd)
                return -ENOMEM;
 
-       pd->np = np;
        pd->num_core_pm_clks = num_core_pm_clks;
        memcpy(pd->core_pm_clks, core_pm_clks, pm_size);
 
@@ -896,7 +892,6 @@ static int __init cpg_mssr_common_init(struct device *dev,
                                       const struct cpg_mssr_info *info)
 {
        struct cpg_mssr_priv *priv;
-       struct clk **clks = NULL;
        unsigned int nclks, i;
        int error;
 
@@ -906,7 +901,8 @@ static int __init cpg_mssr_common_init(struct device *dev,
                        return error;
        }
 
-       priv = kzalloc(sizeof(*priv), GFP_KERNEL);
+       nclks = info->num_total_core_clks + info->num_hw_mod_clks;
+       priv = kzalloc(struct_size(priv, clks, nclks), GFP_KERNEL);
        if (!priv)
                return -ENOMEM;
 
@@ -920,15 +916,7 @@ static int __init cpg_mssr_common_init(struct device *dev,
                goto out_err;
        }
 
-       nclks = info->num_total_core_clks + info->num_hw_mod_clks;
-       clks = kmalloc_array(nclks, sizeof(*clks), GFP_KERNEL);
-       if (!clks) {
-               error = -ENOMEM;
-               goto out_err;
-       }
-
        cpg_mssr_priv = priv;
-       priv->clks = clks;
        priv->num_core_clks = info->num_total_core_clks;
        priv->num_mod_clks = info->num_hw_mod_clks;
        priv->last_dt_core_clk = info->last_dt_core_clk;
@@ -936,7 +924,7 @@ static int __init cpg_mssr_common_init(struct device *dev,
        priv->stbyctrl = info->stbyctrl;
 
        for (i = 0; i < nclks; i++)
-               clks[i] = ERR_PTR(-ENOENT);
+               priv->clks[i] = ERR_PTR(-ENOENT);
 
        error = of_clk_add_provider(np, cpg_mssr_clk_src_twocell_get, priv);
        if (error)
@@ -945,7 +933,6 @@ static int __init cpg_mssr_common_init(struct device *dev,
        return 0;
 
 out_err:
-       kfree(clks);
        if (priv->base)
                iounmap(priv->base);
        kfree(priv);
index c61f4d3..4abe7ff 100644 (file)
@@ -46,29 +46,27 @@ static unsigned long rockchip_mmc_recalc(struct clk_hw *hw,
 static int rockchip_mmc_get_phase(struct clk_hw *hw)
 {
        struct rockchip_mmc_clock *mmc_clock = to_mmc_clock(hw);
-       unsigned long rate = clk_get_rate(hw->clk);
+       unsigned long rate = clk_hw_get_rate(hw);
        u32 raw_value;
        u16 degrees;
        u32 delay_num = 0;
 
        /* See the comment for rockchip_mmc_set_phase below */
-       if (!rate) {
-               pr_err("%s: invalid clk rate\n", __func__);
+       if (!rate)
                return -EINVAL;
-       }
 
        raw_value = readl(mmc_clock->reg) >> (mmc_clock->shift);
 
        degrees = (raw_value & ROCKCHIP_MMC_DEGREE_MASK) * 90;
 
        if (raw_value & ROCKCHIP_MMC_DELAY_SEL) {
-               /* degrees/delaynum * 10000 */
+               /* degrees/delaynum * 1000000 */
                unsigned long factor = (ROCKCHIP_MMC_DELAY_ELEMENT_PSEC / 10) *
-                                       36 * (rate / 1000000);
+                                       36 * (rate / 10000);
 
                delay_num = (raw_value & ROCKCHIP_MMC_DELAYNUM_MASK);
                delay_num >>= ROCKCHIP_MMC_DELAYNUM_OFFSET;
-               degrees += DIV_ROUND_CLOSEST(delay_num * factor, 10000);
+               degrees += DIV_ROUND_CLOSEST(delay_num * factor, 1000000);
        }
 
        return degrees % 360;
@@ -77,7 +75,7 @@ static int rockchip_mmc_get_phase(struct clk_hw *hw)
 static int rockchip_mmc_set_phase(struct clk_hw *hw, int degrees)
 {
        struct rockchip_mmc_clock *mmc_clock = to_mmc_clock(hw);
-       unsigned long rate = clk_get_rate(hw->clk);
+       unsigned long rate = clk_hw_get_rate(hw);
        u8 nineties, remainder;
        u8 delay_num;
        u32 raw_value;
index bb39a79..3a50189 100644 (file)
@@ -794,6 +794,9 @@ static struct rockchip_clk_branch px30_clk_branches[] __initdata = {
        GATE(ACLK_GIC, "aclk_gic", "aclk_bus_pre", CLK_IGNORE_UNUSED, PX30_CLKGATE_CON(13), 12, GFLAGS),
        GATE(ACLK_DCF, "aclk_dcf", "aclk_bus_pre", 0, PX30_CLKGATE_CON(13), 15, GFLAGS),
 
+       /* aclk_dmac is controlled by sgrf_soc_con1[11]. */
+       SGRF_GATE(ACLK_DMAC, "aclk_dmac", "aclk_bus_pre"),
+
        GATE(0, "hclk_bus_niu", "hclk_bus_pre", CLK_IGNORE_UNUSED, PX30_CLKGATE_CON(13), 9, GFLAGS),
        GATE(0, "hclk_rom", "hclk_bus_pre", CLK_IGNORE_UNUSED, PX30_CLKGATE_CON(13), 14, GFLAGS),
        GATE(HCLK_PDM, "hclk_pdm", "hclk_bus_pre", 0, PX30_CLKGATE_CON(14), 1, GFLAGS),
@@ -957,7 +960,6 @@ static void __init px30_clk_init(struct device_node *np)
 {
        struct rockchip_clk_provider *ctx;
        void __iomem *reg_base;
-       struct clk *clk;
 
        reg_base = of_iomap(np, 0);
        if (!reg_base) {
@@ -972,14 +974,6 @@ static void __init px30_clk_init(struct device_node *np)
                return;
        }
 
-       /* aclk_dmac is controlled by sgrf_soc_con1[11]. */
-       clk = clk_register_fixed_factor(NULL, "aclk_dmac", "aclk_bus_pre", 0, 1, 1);
-       if (IS_ERR(clk))
-               pr_warn("%s: could not register clock aclk_dmac: %ld\n",
-                       __func__, PTR_ERR(clk));
-       else
-               rockchip_clk_add_lookup(ctx, clk, ACLK_DMAC);
-
        rockchip_clk_register_plls(ctx, px30_pll_clks,
                                   ARRAY_SIZE(px30_pll_clks),
                                   PX30_GRF_SOC_STATUS0);
index bdb1263..d17cfb7 100644 (file)
@@ -101,6 +101,7 @@ static struct rockchip_cpuclk_rate_table rk3228_cpuclk_rates[] __initdata = {
        RK3228_CPUCLK_RATE(1608000000, 1, 7),
        RK3228_CPUCLK_RATE(1512000000, 1, 7),
        RK3228_CPUCLK_RATE(1488000000, 1, 5),
+       RK3228_CPUCLK_RATE(1464000000, 1, 5),
        RK3228_CPUCLK_RATE(1416000000, 1, 5),
        RK3228_CPUCLK_RATE(1392000000, 1, 5),
        RK3228_CPUCLK_RATE(1296000000, 1, 5),
@@ -246,7 +247,7 @@ static struct rockchip_clk_branch rk3228_clk_branches[] __initdata = {
                        RK2928_CLKGATE_CON(4), 0, GFLAGS),
 
        /* PD_MISC */
-       MUX(0, "hdmiphy", mux_hdmiphy_p, CLK_SET_RATE_PARENT,
+       MUX(SCLK_HDMI_PHY, "hdmiphy", mux_hdmiphy_p, CLK_SET_RATE_PARENT,
                        RK2928_MISC_CON, 13, 1, MFLAGS),
        MUX(0, "usb480m_phy", mux_usb480m_phy_p, CLK_SET_RATE_PARENT,
                        RK2928_MISC_CON, 14, 1, MFLAGS),
index 0576296..cc2a177 100644 (file)
@@ -113,7 +113,6 @@ static struct rockchip_pll_rate_table rk3288_pll_rates[] = {
        RK3066_PLL_RATE( 160000000, 1, 80, 12),
        RK3066_PLL_RATE( 157500000, 1, 105, 16),
        RK3066_PLL_RATE( 126000000, 1, 84, 16),
-       RK3066_PLL_RATE(  48000000, 1, 64, 32),
        { /* sentinel */ },
 };
 
@@ -767,6 +766,9 @@ static struct rockchip_clk_branch rk3288_clk_branches[] __initdata = {
        GATE(PCLK_GRF, "pclk_grf", "pclk_pd_alive", CLK_IGNORE_UNUSED, RK3288_CLKGATE_CON(14), 11, GFLAGS),
        GATE(0, "pclk_alive_niu", "pclk_pd_alive", 0, RK3288_CLKGATE_CON(14), 12, GFLAGS),
 
+       /* Watchdog pclk is controlled by RK3288_SGRF_SOC_CON0[1]. */
+       SGRF_GATE(PCLK_WDT, "pclk_wdt", "pclk_pd_alive"),
+
        /* pclk_pd_pmu gates */
        GATE(PCLK_PMU, "pclk_pmu", "pclk_pd_pmu", CLK_IGNORE_UNUSED, RK3288_CLKGATE_CON(17), 0, GFLAGS),
        GATE(0, "pclk_intmem1", "pclk_pd_pmu", CLK_IGNORE_UNUSED, RK3288_CLKGATE_CON(17), 1, GFLAGS),
@@ -915,7 +917,6 @@ static struct syscore_ops rk3288_clk_syscore_ops = {
 static void __init rk3288_clk_init(struct device_node *np)
 {
        struct rockchip_clk_provider *ctx;
-       struct clk *clk;
 
        rk3288_cru_base = of_iomap(np, 0);
        if (!rk3288_cru_base) {
@@ -930,14 +931,6 @@ static void __init rk3288_clk_init(struct device_node *np)
                return;
        }
 
-       /* Watchdog pclk is controlled by RK3288_SGRF_SOC_CON0[1]. */
-       clk = clk_register_fixed_factor(NULL, "pclk_wdt", "pclk_pd_alive", 0, 1, 1);
-       if (IS_ERR(clk))
-               pr_warn("%s: could not register clock pclk_wdt: %ld\n",
-                       __func__, PTR_ERR(clk));
-       else
-               rockchip_clk_add_lookup(ctx, clk, PCLK_WDT);
-
        rockchip_clk_register_plls(ctx, rk3288_pll_clks,
                                   ARRAY_SIZE(rk3288_pll_clks),
                                   RK3288_GRF_SOC_STATUS1);
index 076b977..c186a19 100644 (file)
@@ -791,6 +791,9 @@ static struct rockchip_clk_branch rk3328_clk_branches[] __initdata = {
        GATE(PCLK_SARADC, "pclk_saradc", "pclk_bus", 0, RK3328_CLKGATE_CON(17), 15, GFLAGS),
        GATE(0, "pclk_pmu", "pclk_bus", CLK_IGNORE_UNUSED, RK3328_CLKGATE_CON(28), 3, GFLAGS),
 
+       /* Watchdog pclk is controlled from the secure GRF */
+       SGRF_GATE(PCLK_WDT, "pclk_wdt", "pclk_bus"),
+
        GATE(PCLK_USB3PHY_OTG, "pclk_usb3phy_otg", "pclk_phy_pre", 0, RK3328_CLKGATE_CON(28), 1, GFLAGS),
        GATE(PCLK_USB3PHY_PIPE, "pclk_usb3phy_pipe", "pclk_phy_pre", 0, RK3328_CLKGATE_CON(28), 2, GFLAGS),
        GATE(PCLK_USB3_GRF, "pclk_usb3_grf", "pclk_phy_pre", CLK_IGNORE_UNUSED, RK3328_CLKGATE_CON(17), 2, GFLAGS),
index 43b022d..5544334 100644 (file)
@@ -811,6 +811,9 @@ static struct rockchip_clk_branch rk3368_clk_branches[] __initdata = {
        GATE(PCLK_GPIO2, "pclk_gpio2", "pclk_pd_alive", 0, RK3368_CLKGATE_CON(22), 2, GFLAGS),
        GATE(PCLK_GPIO1, "pclk_gpio1", "pclk_pd_alive", 0, RK3368_CLKGATE_CON(22), 1, GFLAGS),
 
+       /* Watchdog pclk is controlled by sgrf_soc_con3[7]. */
+       SGRF_GATE(PCLK_WDT, "pclk_wdt", "pclk_pd_alive"),
+
        /*
         * pclk_vio gates
         * pclk_vio comes from the exactly same source as hclk_vio
@@ -862,7 +865,6 @@ static void __init rk3368_clk_init(struct device_node *np)
 {
        struct rockchip_clk_provider *ctx;
        void __iomem *reg_base;
-       struct clk *clk;
 
        reg_base = of_iomap(np, 0);
        if (!reg_base) {
@@ -877,14 +879,6 @@ static void __init rk3368_clk_init(struct device_node *np)
                return;
        }
 
-       /* Watchdog pclk is controlled by sgrf_soc_con3[7]. */
-       clk = clk_register_fixed_factor(NULL, "pclk_wdt", "pclk_pd_alive", 0, 1, 1);
-       if (IS_ERR(clk))
-               pr_warn("%s: could not register clock pclk_wdt: %ld\n",
-                       __func__, PTR_ERR(clk));
-       else
-               rockchip_clk_add_lookup(ctx, clk, PCLK_WDT);
-
        rockchip_clk_register_plls(ctx, rk3368_pll_clks,
                                   ARRAY_SIZE(rk3368_pll_clks),
                                   RK3368_GRF_SOC_STATUS0);
index a7ff713..ce1d244 100644 (file)
@@ -1295,6 +1295,9 @@ static struct rockchip_clk_branch rk3399_clk_branches[] __initdata = {
        GATE(PCLK_PMU_INTR_ARB, "pclk_pmu_intr_arb", "pclk_alive", CLK_IGNORE_UNUSED, RK3399_CLKGATE_CON(31), 9, GFLAGS),
        GATE(PCLK_SGRF, "pclk_sgrf", "pclk_alive", CLK_IGNORE_UNUSED, RK3399_CLKGATE_CON(31), 10, GFLAGS),
 
+       /* Watchdog pclk is controlled by RK3399 SECURE_GRF_SOC_CON3[8]. */
+       SGRF_GATE(PCLK_WDT, "pclk_wdt", "pclk_alive"),
+
        GATE(SCLK_MIPIDPHY_REF, "clk_mipidphy_ref", "xin24m", 0, RK3399_CLKGATE_CON(11), 14, GFLAGS),
        GATE(SCLK_DPHY_PLL, "clk_dphy_pll", "clk_mipidphy_ref", CLK_IGNORE_UNUSED, RK3399_CLKGATE_CON(21), 0, GFLAGS),
 
@@ -1522,7 +1525,6 @@ static void __init rk3399_clk_init(struct device_node *np)
 {
        struct rockchip_clk_provider *ctx;
        void __iomem *reg_base;
-       struct clk *clk;
 
        reg_base = of_iomap(np, 0);
        if (!reg_base) {
@@ -1537,14 +1539,6 @@ static void __init rk3399_clk_init(struct device_node *np)
                return;
        }
 
-       /* Watchdog pclk is controlled by RK3399 SECURE_GRF_SOC_CON3[8]. */
-       clk = clk_register_fixed_factor(NULL, "pclk_wdt", "pclk_alive", 0, 1, 1);
-       if (IS_ERR(clk))
-               pr_warn("%s: could not register clock pclk_wdt: %ld\n",
-                       __func__, PTR_ERR(clk));
-       else
-               rockchip_clk_add_lookup(ctx, clk, PCLK_WDT);
-
        rockchip_clk_register_plls(ctx, rk3399_pll_clks,
                                   ARRAY_SIZE(rk3399_pll_clks), -1);
 
index adb66cc..b811597 100644 (file)
@@ -811,6 +811,10 @@ struct rockchip_clk_branch {
                .gate_offset    = -1,                           \
        }
 
+/* SGRF clocks are only accessible from secure mode, so not controllable */
+#define SGRF_GATE(_id, cname, pname)                           \
+               FACTOR(_id, cname, pname, 0, 1, 1)
+
 struct rockchip_clk_provider *rockchip_clk_init(struct device_node *np,
                        void __iomem *base, unsigned long nr_clks);
 void rockchip_clk_of_add_provider(struct device_node *np,
index 982eb02..51564fc 100644 (file)
@@ -958,6 +958,7 @@ static const struct samsung_gate_clock exynos4210_gate_clks[] __initconst = {
 
 /* list of gate clocks supported in exynos4x12 soc */
 static const struct samsung_gate_clock exynos4x12_gate_clks[] __initconst = {
+       GATE(CLK_ASYNC_G3D, "async_g3d", "aclk200", GATE_IP_LEFTBUS, 6, 0, 0),
        GATE(CLK_AUDSS, "audss", "sclk_epll", E4X12_GATE_IP_MAUDIO, 0, 0, 0),
        GATE(CLK_MDNIE0, "mdnie0", "aclk160", GATE_IP_LCD0, 2, 0, 0),
        GATE(CLK_ROTATOR, "rotator", "aclk200", E4X12_GATE_IP_IMAGE, 1, 0, 0),
index 12d800f..01bca5a 100644 (file)
 #define SRC_CDREX              0x20200
 #define DIV_CDREX0             0x20500
 #define DIV_CDREX1             0x20504
+#define GATE_BUS_CDREX0                0x20700
+#define GATE_BUS_CDREX1                0x20704
 #define KPLL_LOCK              0x28000
 #define KPLL_CON0              0x28100
 #define SRC_KFC                        0x28200
@@ -245,6 +247,8 @@ static const unsigned long exynos5x_clk_regs[] __initconst = {
        DIV_CDREX1,
        SRC_KFC,
        DIV_KFC0,
+       GATE_BUS_CDREX0,
+       GATE_BUS_CDREX1,
 };
 
 static const unsigned long exynos5800_clk_regs[] __initconst = {
@@ -422,6 +426,9 @@ PNAME(mout_group13_5800_p)  = { "dout_osc_div", "mout_sw_aclkfl1_550_cam" };
 PNAME(mout_group14_5800_p)     = { "dout_aclk550_cam", "dout_sclk_sw" };
 PNAME(mout_group15_5800_p)     = { "dout_osc_div", "mout_sw_aclk550_cam" };
 PNAME(mout_group16_5800_p)     = { "dout_osc_div", "mout_mau_epll_clk" };
+PNAME(mout_mx_mspll_ccore_phy_p) = { "sclk_bpll", "mout_sclk_dpll",
+                                       "mout_sclk_mpll", "ff_dout_spll2",
+                                       "mout_sclk_spll", "mout_sclk_epll"};
 
 /* fixed rate clocks generated outside the soc */
 static struct samsung_fixed_rate_clock
@@ -447,7 +454,7 @@ static const struct samsung_fixed_factor_clock
 static const struct samsung_fixed_factor_clock
                exynos5800_fixed_factor_clks[] __initconst = {
        FFACTOR(0, "ff_dout_epll2", "mout_sclk_epll", 1, 2, 0),
-       FFACTOR(0, "ff_dout_spll2", "mout_sclk_spll", 1, 2, 0),
+       FFACTOR(CLK_FF_DOUT_SPLL2, "ff_dout_spll2", "mout_sclk_spll", 1, 2, 0),
 };
 
 static const struct samsung_mux_clock exynos5800_mux_clks[] __initconst = {
@@ -469,11 +476,14 @@ static const struct samsung_mux_clock exynos5800_mux_clks[] __initconst = {
        MUX(0, "mout_aclk300_disp1", mout_group5_5800_p, SRC_TOP2, 24, 2),
        MUX(0, "mout_aclk300_gscl", mout_group5_5800_p, SRC_TOP2, 28, 2),
 
+       MUX(CLK_MOUT_MX_MSPLL_CCORE_PHY, "mout_mx_mspll_ccore_phy",
+               mout_mx_mspll_ccore_phy_p, SRC_TOP7, 0, 3),
+
        MUX(CLK_MOUT_MX_MSPLL_CCORE, "mout_mx_mspll_ccore",
-                       mout_mx_mspll_ccore_p, SRC_TOP7, 16, 2),
+                       mout_mx_mspll_ccore_p, SRC_TOP7, 16, 3),
        MUX_F(CLK_MOUT_MAU_EPLL, "mout_mau_epll_clk", mout_mau_epll_clk_5800_p,
                        SRC_TOP7, 20, 2, CLK_SET_RATE_PARENT, 0),
-       MUX(0, "sclk_bpll", mout_bpll_p, SRC_TOP7, 24, 1),
+       MUX(CLK_SCLK_BPLL, "sclk_bpll", mout_bpll_p, SRC_TOP7, 24, 1),
        MUX(0, "mout_epll2", mout_epll2_5800_p, SRC_TOP7, 28, 1),
 
        MUX(0, "mout_aclk550_cam", mout_group3_5800_p, SRC_TOP8, 16, 3),
@@ -645,7 +655,7 @@ static const struct samsung_mux_clock exynos5x_mux_clks[] __initconst = {
 
        MUX(0, "mout_sclk_mpll", mout_mpll_p, SRC_TOP6, 0, 1),
        MUX(CLK_MOUT_VPLL, "mout_sclk_vpll", mout_vpll_p, SRC_TOP6, 4, 1),
-       MUX(0, "mout_sclk_spll", mout_spll_p, SRC_TOP6, 8, 1),
+       MUX(CLK_MOUT_SCLK_SPLL, "mout_sclk_spll", mout_spll_p, SRC_TOP6, 8, 1),
        MUX(0, "mout_sclk_ipll", mout_ipll_p, SRC_TOP6, 12, 1),
        MUX(0, "mout_sclk_rpll", mout_rpll_p, SRC_TOP6, 16, 1),
        MUX_F(CLK_MOUT_EPLL, "mout_sclk_epll", mout_epll_p, SRC_TOP6, 20, 1,
@@ -803,8 +813,21 @@ static const struct samsung_div_clock exynos5x_div_clks[] __initconst = {
                        "mout_aclk400_disp1", DIV_TOP2, 4, 3),
 
        /* CDREX Block */
-       DIV(CLK_DOUT_PCLK_CDREX, "dout_pclk_cdrex", "dout_aclk_cdrex1",
-                       DIV_CDREX0, 28, 3),
+       /*
+        * The three clocks below are controlled using the same register and
+        * bits. They are put into one because there is a need of
+        * synchronization between the BUS and DREXs (two external memory
+        * interfaces).
+        * They are put here to show this HW assumption and for clock
+        * information summary completeness.
+        */
+       DIV_F(CLK_DOUT_PCLK_CDREX, "dout_pclk_cdrex", "dout_aclk_cdrex1",
+                       DIV_CDREX0, 28, 3, CLK_GET_RATE_NOCACHE, 0),
+       DIV_F(CLK_DOUT_PCLK_DREX0, "dout_pclk_drex0", "dout_cclk_drex0",
+                       DIV_CDREX0, 28, 3, CLK_GET_RATE_NOCACHE, 0),
+       DIV_F(CLK_DOUT_PCLK_DREX1, "dout_pclk_drex1", "dout_cclk_drex0",
+                       DIV_CDREX0, 28, 3, CLK_GET_RATE_NOCACHE, 0),
+
        DIV_F(CLK_DOUT_SCLK_CDREX, "dout_sclk_cdrex", "mout_mclk_cdrex",
                        DIV_CDREX0, 24, 3, CLK_SET_RATE_PARENT, 0),
        DIV(CLK_DOUT_ACLK_CDREX1, "dout_aclk_cdrex1", "dout_clk2x_phy0",
@@ -1167,6 +1190,32 @@ static const struct samsung_gate_clock exynos5x_gate_clks[] __initconst = {
                        GATE_TOP_SCLK_ISP, 12, CLK_SET_RATE_PARENT, 0),
 
        GATE(CLK_G3D, "g3d", "mout_user_aclk_g3d", GATE_IP_G3D, 9, 0, 0),
+
+       /* CDREX */
+       GATE(CLK_CLKM_PHY0, "clkm_phy0", "dout_sclk_cdrex",
+                       GATE_BUS_CDREX0, 0, 0, 0),
+       GATE(CLK_CLKM_PHY1, "clkm_phy1", "dout_sclk_cdrex",
+                       GATE_BUS_CDREX0, 1, 0, 0),
+       GATE(0, "mx_mspll_ccore_phy", "mout_mx_mspll_ccore_phy",
+                       SRC_MASK_TOP7, 0, CLK_IGNORE_UNUSED, 0),
+
+       GATE(CLK_ACLK_PPMU_DREX1_1, "aclk_ppmu_drex1_1", "dout_aclk_cdrex1",
+                       GATE_BUS_CDREX1, 12, CLK_IGNORE_UNUSED, 0),
+       GATE(CLK_ACLK_PPMU_DREX1_0, "aclk_ppmu_drex1_0", "dout_aclk_cdrex1",
+                       GATE_BUS_CDREX1, 13, CLK_IGNORE_UNUSED, 0),
+       GATE(CLK_ACLK_PPMU_DREX0_1, "aclk_ppmu_drex0_1", "dout_aclk_cdrex1",
+                       GATE_BUS_CDREX1, 14, CLK_IGNORE_UNUSED, 0),
+       GATE(CLK_ACLK_PPMU_DREX0_0, "aclk_ppmu_drex0_0", "dout_aclk_cdrex1",
+                       GATE_BUS_CDREX1, 15, CLK_IGNORE_UNUSED, 0),
+
+       GATE(CLK_PCLK_PPMU_DREX1_1, "pclk_ppmu_drex1_1", "dout_pclk_cdrex",
+                       GATE_BUS_CDREX1, 26, CLK_IGNORE_UNUSED, 0),
+       GATE(CLK_PCLK_PPMU_DREX1_0, "pclk_ppmu_drex1_0", "dout_pclk_cdrex",
+                       GATE_BUS_CDREX1, 27, CLK_IGNORE_UNUSED, 0),
+       GATE(CLK_PCLK_PPMU_DREX0_1, "pclk_ppmu_drex0_1", "dout_pclk_cdrex",
+                       GATE_BUS_CDREX1, 28, CLK_IGNORE_UNUSED, 0),
+       GATE(CLK_PCLK_PPMU_DREX0_0, "pclk_ppmu_drex0_0", "dout_pclk_cdrex",
+                       GATE_BUS_CDREX1, 29, CLK_IGNORE_UNUSED, 0),
 };
 
 static const struct samsung_div_clock exynos5x_disp_div_clks[] __initconst = {
@@ -1282,6 +1331,17 @@ static const struct samsung_pll_rate_table exynos5420_pll2550x_24mhz_tbl[] __ini
        PLL_35XX_RATE(24 * MHZ, 200000000,  200, 3, 3),
 };
 
+static const struct samsung_pll_rate_table exynos5422_bpll_rate_table[] = {
+       PLL_35XX_RATE(24 * MHZ, 825000000, 275, 4, 1),
+       PLL_35XX_RATE(24 * MHZ, 728000000, 182, 3, 1),
+       PLL_35XX_RATE(24 * MHZ, 633000000, 211, 4, 1),
+       PLL_35XX_RATE(24 * MHZ, 543000000, 181, 2, 2),
+       PLL_35XX_RATE(24 * MHZ, 413000000, 413, 6, 2),
+       PLL_35XX_RATE(24 * MHZ, 275000000, 275, 3, 3),
+       PLL_35XX_RATE(24 * MHZ, 206000000, 206, 3, 3),
+       PLL_35XX_RATE(24 * MHZ, 165000000, 110, 2, 3),
+};
+
 static const struct samsung_pll_rate_table exynos5420_epll_24mhz_tbl[] = {
        PLL_36XX_RATE(24 * MHZ, 600000000U, 100, 2, 1, 0),
        PLL_36XX_RATE(24 * MHZ, 400000000U, 200, 3, 2, 0),
@@ -1424,9 +1484,13 @@ static void __init exynos5x_clk_init(struct device_node *np,
                exynos5x_plls[apll].rate_table = exynos5420_pll2550x_24mhz_tbl;
                exynos5x_plls[epll].rate_table = exynos5420_epll_24mhz_tbl;
                exynos5x_plls[kpll].rate_table = exynos5420_pll2550x_24mhz_tbl;
-               exynos5x_plls[bpll].rate_table = exynos5420_pll2550x_24mhz_tbl;
        }
 
+       if (soc == EXYNOS5420)
+               exynos5x_plls[bpll].rate_table = exynos5420_pll2550x_24mhz_tbl;
+       else
+               exynos5x_plls[bpll].rate_table = exynos5422_bpll_rate_table;
+
        samsung_clk_register_pll(ctx, exynos5x_plls, ARRAY_SIZE(exynos5x_plls),
                                        reg_base);
        samsung_clk_register_fixed_rate(ctx, exynos5x_fixed_rate_clks,
index 945d5f2..7824c2b 100644 (file)
@@ -5587,8 +5587,8 @@ static int __init exynos5433_cmu_probe(struct platform_device *pdev)
        data->nr_clk_save = info->nr_clk_regs;
        data->clk_suspend = info->suspend_regs;
        data->nr_clk_suspend = info->nr_suspend_regs;
-       data->nr_pclks = of_count_phandle_with_args(dev->of_node, "clocks",
-                                                   "#clock-cells");
+       data->nr_pclks = of_clk_get_parent_count(dev->of_node);
+
        if (data->nr_pclks > 0) {
                data->pclks = devm_kcalloc(dev, sizeof(struct clk *),
                                           data->nr_pclks, GFP_KERNEL);
index 5bed36e..993f3a7 100644 (file)
@@ -161,8 +161,12 @@ static const struct stratix10_gate_clock s10_gate_clks[] = {
          8, 0, 0, 0, 0, 0, 0},
        { STRATIX10_SPI_M_CLK, "spi_m_clk", "l4_mp_clk", NULL, 1, 0, 0xA4,
          9, 0, 0, 0, 0, 0, 0},
-       { STRATIX10_NAND_CLK, "nand_clk", "l4_main_clk", NULL, 1, 0, 0xA4,
+       { STRATIX10_NAND_X_CLK, "nand_x_clk", "l4_mp_clk", NULL, 1, 0, 0xA4,
          10, 0, 0, 0, 0, 0, 0},
+       { STRATIX10_NAND_CLK, "nand_clk", "nand_x_clk", NULL, 1, 0, 0xA4,
+         10, 0, 0, 0, 0, 0, 4},
+       { STRATIX10_NAND_ECC_CLK, "nand_ecc_clk", "nand_x_clk", NULL, 1, 0, 0xA4,
+         10, 0, 0, 0, 0, 0, 4},
 };
 
 static int s10_clk_register_c_perip(const struct stratix10_perip_c_clock *clks,
index e038b04..a5bdca1 100644 (file)
@@ -42,6 +42,7 @@ int sprd_clk_regmap_init(struct platform_device *pdev,
        void __iomem *base;
        struct device_node *node = pdev->dev.of_node;
        struct regmap *regmap;
+       struct resource *res;
 
        if (of_find_property(node, "sprd,syscon", NULL)) {
                regmap = syscon_regmap_lookup_by_phandle(node, "sprd,syscon");
@@ -50,10 +51,14 @@ int sprd_clk_regmap_init(struct platform_device *pdev,
                        return PTR_ERR(regmap);
                }
        } else {
-               base = of_iomap(node, 0);
+               res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+               base = devm_ioremap_resource(&pdev->dev, res);
+               if (IS_ERR(base))
+                       return PTR_ERR(base);
+
                regmap = devm_regmap_init_mmio(&pdev->dev, base,
                                               &sprdclk_regmap_config);
-               if (IS_ERR_OR_NULL(regmap)) {
+               if (IS_ERR(regmap)) {
                        pr_err("failed to init regmap\n");
                        return PTR_ERR(regmap);
                }
index 9980ab5..f76305b 100644 (file)
@@ -2023,6 +2023,7 @@ static int sc9860_clk_probe(struct platform_device *pdev)
 {
        const struct of_device_id *match;
        const struct sprd_clk_desc *desc;
+       int ret;
 
        match = of_match_node(sprd_sc9860_clk_ids, pdev->dev.of_node);
        if (!match) {
@@ -2031,7 +2032,9 @@ static int sc9860_clk_probe(struct platform_device *pdev)
        }
 
        desc = match->data;
-       sprd_clk_regmap_init(pdev, desc);
+       ret = sprd_clk_regmap_init(pdev, desc);
+       if (ret)
+               return ret;
 
        return sprd_clk_probe(&pdev->dev, desc->hw_clks);
 }
index df43952..f32366d 100644 (file)
@@ -160,8 +160,9 @@ static struct ccu_nk pll_periph_base_clk = {
        },
 };
 
-static CLK_FIXED_FACTOR(pll_periph_clk, "pll-periph", "pll-periph-base",
-                       2, 1, CLK_SET_RATE_PARENT);
+static CLK_FIXED_FACTOR_HW(pll_periph_clk, "pll-periph",
+                          &pll_periph_base_clk.common.hw,
+                          2, 1, CLK_SET_RATE_PARENT);
 
 /* Not documented on A10 */
 static struct ccu_div pll_periph_sata_clk = {
@@ -1028,19 +1029,29 @@ static struct ccu_common *sun4i_sun7i_ccu_clks[] = {
        &out_b_clk.common
 };
 
+static const struct clk_hw *clk_parent_pll_audio[] = {
+       &pll_audio_base_clk.common.hw
+};
+
 /* Post-divider for pll-audio is hardcoded to 1 */
-static CLK_FIXED_FACTOR(pll_audio_clk, "pll-audio",
-                       "pll-audio-base", 1, 1, CLK_SET_RATE_PARENT);
-static CLK_FIXED_FACTOR(pll_audio_2x_clk, "pll-audio-2x",
-                       "pll-audio-base", 2, 1, CLK_SET_RATE_PARENT);
-static CLK_FIXED_FACTOR(pll_audio_4x_clk, "pll-audio-4x",
-                       "pll-audio-base", 1, 1, CLK_SET_RATE_PARENT);
-static CLK_FIXED_FACTOR(pll_audio_8x_clk, "pll-audio-8x",
-                       "pll-audio-base", 1, 2, CLK_SET_RATE_PARENT);
-static CLK_FIXED_FACTOR(pll_video0_2x_clk, "pll-video0-2x",
-                       "pll-video0", 1, 2, CLK_SET_RATE_PARENT);
-static CLK_FIXED_FACTOR(pll_video1_2x_clk, "pll-video1-2x",
-                       "pll-video1", 1, 2, CLK_SET_RATE_PARENT);
+static CLK_FIXED_FACTOR_HWS(pll_audio_clk, "pll-audio",
+                           clk_parent_pll_audio,
+                           1, 1, CLK_SET_RATE_PARENT);
+static CLK_FIXED_FACTOR_HWS(pll_audio_2x_clk, "pll-audio-2x",
+                           clk_parent_pll_audio,
+                           2, 1, CLK_SET_RATE_PARENT);
+static CLK_FIXED_FACTOR_HWS(pll_audio_4x_clk, "pll-audio-4x",
+                           clk_parent_pll_audio,
+                           1, 1, CLK_SET_RATE_PARENT);
+static CLK_FIXED_FACTOR_HWS(pll_audio_8x_clk, "pll-audio-8x",
+                           clk_parent_pll_audio,
+                           1, 2, CLK_SET_RATE_PARENT);
+static CLK_FIXED_FACTOR_HW(pll_video0_2x_clk, "pll-video0-2x",
+                          &pll_video0_clk.common.hw,
+                          1, 2, CLK_SET_RATE_PARENT);
+static CLK_FIXED_FACTOR_HW(pll_video1_2x_clk, "pll-video1-2x",
+                          &pll_video1_clk.common.hw,
+                          1, 2, CLK_SET_RATE_PARENT);
 
 
 static struct clk_hw_onecell_data sun4i_a10_hw_clks = {
index 1786ee8..49bd7a4 100644 (file)
@@ -597,23 +597,34 @@ static SUNXI_CCU_M_WITH_GATE(gpu_clk, "gpu", "pll-gpu",
                             0x1a0, 0, 3, BIT(31), CLK_SET_RATE_PARENT);
 
 /* Fixed Factor clocks */
-static CLK_FIXED_FACTOR(osc12M_clk, "osc12M", "osc24M", 2, 1, 0);
+static CLK_FIXED_FACTOR_FW_NAME(osc12M_clk, "osc12M", "hosc", 2, 1, 0);
+
+static const struct clk_hw *clk_parent_pll_audio[] = {
+       &pll_audio_base_clk.common.hw
+};
 
 /* We hardcode the divider to 1 for now */
-static CLK_FIXED_FACTOR(pll_audio_clk, "pll-audio",
-                       "pll-audio-base", 1, 1, CLK_SET_RATE_PARENT);
-static CLK_FIXED_FACTOR(pll_audio_2x_clk, "pll-audio-2x",
-                       "pll-audio-base", 2, 1, CLK_SET_RATE_PARENT);
-static CLK_FIXED_FACTOR(pll_audio_4x_clk, "pll-audio-4x",
-                       "pll-audio-base", 1, 1, CLK_SET_RATE_PARENT);
-static CLK_FIXED_FACTOR(pll_audio_8x_clk, "pll-audio-8x",
-                       "pll-audio-base", 1, 2, CLK_SET_RATE_PARENT);
-static CLK_FIXED_FACTOR(pll_periph0_2x_clk, "pll-periph0-2x",
-                       "pll-periph0", 1, 2, 0);
-static CLK_FIXED_FACTOR(pll_periph1_2x_clk, "pll-periph1-2x",
-                       "pll-periph1", 1, 2, 0);
-static CLK_FIXED_FACTOR(pll_video0_2x_clk, "pll-video0-2x",
-                       "pll-video0", 1, 2, CLK_SET_RATE_PARENT);
+static CLK_FIXED_FACTOR_HWS(pll_audio_clk, "pll-audio",
+                           clk_parent_pll_audio,
+                           1, 1, CLK_SET_RATE_PARENT);
+static CLK_FIXED_FACTOR_HWS(pll_audio_2x_clk, "pll-audio-2x",
+                           clk_parent_pll_audio,
+                           2, 1, CLK_SET_RATE_PARENT);
+static CLK_FIXED_FACTOR_HWS(pll_audio_4x_clk, "pll-audio-4x",
+                           clk_parent_pll_audio,
+                           1, 1, CLK_SET_RATE_PARENT);
+static CLK_FIXED_FACTOR_HWS(pll_audio_8x_clk, "pll-audio-8x",
+                           clk_parent_pll_audio,
+                           1, 2, CLK_SET_RATE_PARENT);
+static CLK_FIXED_FACTOR_HW(pll_periph0_2x_clk, "pll-periph0-2x",
+                          &pll_periph0_clk.common.hw,
+                          1, 2, 0);
+static CLK_FIXED_FACTOR_HW(pll_periph1_2x_clk, "pll-periph1-2x",
+                          &pll_periph1_clk.common.hw,
+                          1, 2, 0);
+static CLK_FIXED_FACTOR_HW(pll_video0_2x_clk, "pll-video0-2x",
+                          &pll_video0_clk.common.hw,
+                          1, 2, CLK_SET_RATE_PARENT);
 
 static struct ccu_common *sun50i_a64_ccu_clks[] = {
        &pll_cpux_clk.common,
index 27554ea..45a1ed3 100644 (file)
@@ -49,7 +49,7 @@ static struct ccu_div ar100_clk = {
        },
 };
 
-static CLK_FIXED_FACTOR(r_ahb_clk, "r-ahb", "ar100", 1, 1, 0);
+static CLK_FIXED_FACTOR_HW(r_ahb_clk, "r-ahb", &ar100_clk.common.hw, 1, 1, 0);
 
 static struct ccu_div r_apb1_clk = {
        .div            = _SUNXI_CCU_DIV(0, 2),
@@ -104,7 +104,7 @@ static SUNXI_CCU_GATE(r_apb2_i2c_clk,       "r-apb2-i2c",   "r-apb2",
 static SUNXI_CCU_GATE(r_apb1_ir_clk,   "r-apb1-ir",    "r-apb1",
                      0x1cc, BIT(0), 0);
 static SUNXI_CCU_GATE(r_apb1_w1_clk,   "r-apb1-w1",    "r-apb1",
-                     0x1cc, BIT(0), 0);
+                     0x1ec, BIT(0), 0);
 
 /* Information of IR(RX) mod clock is gathered from BSP source code */
 static const char * const r_mod0_default_parents[] = { "osc32k", "osc24M" };
index 9d3f989..aebef4a 100644 (file)
@@ -622,8 +622,9 @@ static SUNXI_CCU_GATE(bus_xhci_clk, "bus-xhci", "ahb3", 0xa8c, BIT(5), 0);
 static SUNXI_CCU_GATE(bus_ehci3_clk, "bus-ehci3", "ahb3", 0xa8c, BIT(7), 0);
 static SUNXI_CCU_GATE(bus_otg_clk, "bus-otg", "ahb3", 0xa8c, BIT(8), 0);
 
-static CLK_FIXED_FACTOR(pcie_ref_100m_clk, "pcie-ref-100M",
-                       "pll-periph0-4x", 24, 1, 0);
+static struct clk_fixed_factor pll_periph0_4x_clk;
+static CLK_FIXED_FACTOR_HW(pcie_ref_100m_clk, "pcie-ref-100M",
+                          &pll_periph0_4x_clk.hw, 24, 1, 0);
 static SUNXI_CCU_GATE(pcie_ref_clk, "pcie-ref", "pcie-ref-100M",
                      0xab0, BIT(31), 0);
 static SUNXI_CCU_GATE(pcie_ref_out_clk, "pcie-ref-out", "pcie-ref",
@@ -745,34 +746,52 @@ static SUNXI_CCU_M_WITH_MUX_GATE(hdcp_clk, "hdcp", hdcp_parents, 0xc40,
 static SUNXI_CCU_GATE(bus_hdcp_clk, "bus-hdcp", "ahb3", 0xc4c, BIT(0), 0);
 
 /* Fixed factor clocks */
-static CLK_FIXED_FACTOR(osc12M_clk, "osc12M", "osc24M", 2, 1, 0);
+static CLK_FIXED_FACTOR_FW_NAME(osc12M_clk, "osc12M", "hosc", 2, 1, 0);
+
+static const struct clk_hw *clk_parent_pll_audio[] = {
+       &pll_audio_base_clk.common.hw
+};
 
 /*
  * The divider of pll-audio is fixed to 8 now, as pll-audio-4x has a
  * fixed post-divider 2.
  */
-static CLK_FIXED_FACTOR(pll_audio_clk, "pll-audio",
-                       "pll-audio-base", 8, 1, CLK_SET_RATE_PARENT);
-static CLK_FIXED_FACTOR(pll_audio_2x_clk, "pll-audio-2x",
-                       "pll-audio-base", 4, 1, CLK_SET_RATE_PARENT);
-static CLK_FIXED_FACTOR(pll_audio_4x_clk, "pll-audio-4x",
-                       "pll-audio-base", 2, 1, CLK_SET_RATE_PARENT);
-
-static CLK_FIXED_FACTOR(pll_periph0_4x_clk, "pll-periph0-4x",
-                       "pll-periph0", 1, 4, 0);
-static CLK_FIXED_FACTOR(pll_periph0_2x_clk, "pll-periph0-2x",
-                       "pll-periph0", 1, 2, 0);
-
-static CLK_FIXED_FACTOR(pll_periph1_4x_clk, "pll-periph1-4x",
-                       "pll-periph1", 1, 4, 0);
-static CLK_FIXED_FACTOR(pll_periph1_2x_clk, "pll-periph1-2x",
-                       "pll-periph1", 1, 2, 0);
-
-static CLK_FIXED_FACTOR(pll_video0_4x_clk, "pll-video0-4x",
-                       "pll-video0", 1, 4, CLK_SET_RATE_PARENT);
-
-static CLK_FIXED_FACTOR(pll_video1_4x_clk, "pll-video1-4x",
-                       "pll-video1", 1, 4, CLK_SET_RATE_PARENT);
+static CLK_FIXED_FACTOR_HWS(pll_audio_clk, "pll-audio",
+                           clk_parent_pll_audio,
+                           8, 1, CLK_SET_RATE_PARENT);
+static CLK_FIXED_FACTOR_HWS(pll_audio_2x_clk, "pll-audio-2x",
+                           clk_parent_pll_audio,
+                           4, 1, CLK_SET_RATE_PARENT);
+static CLK_FIXED_FACTOR_HWS(pll_audio_4x_clk, "pll-audio-4x",
+                           clk_parent_pll_audio,
+                           2, 1, CLK_SET_RATE_PARENT);
+
+static const struct clk_hw *pll_periph0_parents[] = {
+       &pll_periph0_clk.common.hw
+};
+static CLK_FIXED_FACTOR_HWS(pll_periph0_4x_clk, "pll-periph0-4x",
+                           pll_periph0_parents,
+                           1, 4, 0);
+static CLK_FIXED_FACTOR_HWS(pll_periph0_2x_clk, "pll-periph0-2x",
+                           pll_periph0_parents,
+                           1, 2, 0);
+
+static const struct clk_hw *pll_periph1_parents[] = {
+       &pll_periph1_clk.common.hw
+};
+static CLK_FIXED_FACTOR_HWS(pll_periph1_4x_clk, "pll-periph1-4x",
+                           pll_periph1_parents,
+                           1, 4, 0);
+static CLK_FIXED_FACTOR_HWS(pll_periph1_2x_clk, "pll-periph1-2x",
+                           pll_periph1_parents,
+                           1, 2, 0);
+
+static CLK_FIXED_FACTOR_HW(pll_video0_4x_clk, "pll-video0-4x",
+                          &pll_video0_clk.common.hw,
+                          1, 4, CLK_SET_RATE_PARENT);
+static CLK_FIXED_FACTOR_HW(pll_video1_4x_clk, "pll-video1-4x",
+                          &pll_video1_clk.common.hw,
+                          1, 4, CLK_SET_RATE_PARENT);
 
 static struct ccu_common *sun50i_h6_ccu_clks[] = {
        &pll_cpux_clk.common,
index b71ed0f..b78e9b5 100644 (file)
@@ -603,19 +603,29 @@ static struct ccu_common *sun5i_a10s_ccu_clks[] = {
        &iep_clk.common,
 };
 
+static const struct clk_hw *clk_parent_pll_audio[] = {
+       &pll_audio_base_clk.common.hw
+};
+
 /* We hardcode the divider to 1 for now */
-static CLK_FIXED_FACTOR(pll_audio_clk, "pll-audio",
-                       "pll-audio-base", 1, 1, CLK_SET_RATE_PARENT);
-static CLK_FIXED_FACTOR(pll_audio_2x_clk, "pll-audio-2x",
-                       "pll-audio-base", 2, 1, CLK_SET_RATE_PARENT);
-static CLK_FIXED_FACTOR(pll_audio_4x_clk, "pll-audio-4x",
-                       "pll-audio-base", 1, 1, CLK_SET_RATE_PARENT);
-static CLK_FIXED_FACTOR(pll_audio_8x_clk, "pll-audio-8x",
-                       "pll-audio-base", 1, 2, CLK_SET_RATE_PARENT);
-static CLK_FIXED_FACTOR(pll_video0_2x_clk, "pll-video0-2x",
-                       "pll-video0", 1, 2, CLK_SET_RATE_PARENT);
-static CLK_FIXED_FACTOR(pll_video1_2x_clk, "pll-video1-2x",
-                       "pll-video1", 1, 2, CLK_SET_RATE_PARENT);
+static CLK_FIXED_FACTOR_HWS(pll_audio_clk, "pll-audio",
+                           clk_parent_pll_audio,
+                           1, 1, CLK_SET_RATE_PARENT);
+static CLK_FIXED_FACTOR_HWS(pll_audio_2x_clk, "pll-audio-2x",
+                           clk_parent_pll_audio,
+                           2, 1, CLK_SET_RATE_PARENT);
+static CLK_FIXED_FACTOR_HWS(pll_audio_4x_clk, "pll-audio-4x",
+                           clk_parent_pll_audio,
+                           1, 1, CLK_SET_RATE_PARENT);
+static CLK_FIXED_FACTOR_HWS(pll_audio_8x_clk, "pll-audio-8x",
+                           clk_parent_pll_audio,
+                           1, 2, CLK_SET_RATE_PARENT);
+static CLK_FIXED_FACTOR_HW(pll_video0_2x_clk, "pll-video0-2x",
+                          &pll_video0_clk.common.hw,
+                          1, 2, CLK_SET_RATE_PARENT);
+static CLK_FIXED_FACTOR_HW(pll_video1_2x_clk, "pll-video1-2x",
+                          &pll_video1_clk.common.hw,
+                          1, 2, CLK_SET_RATE_PARENT);
 
 static struct clk_hw_onecell_data sun5i_a10s_hw_clks = {
        .hws    = {
index 2ff7b08..9b40d53 100644 (file)
@@ -955,21 +955,32 @@ static struct ccu_common *sun6i_a31_ccu_clks[] = {
        &out_c_clk.common,
 };
 
+static const struct clk_hw *clk_parent_pll_audio[] = {
+       &pll_audio_base_clk.common.hw
+};
+
 /* We hardcode the divider to 1 for now */
-static CLK_FIXED_FACTOR(pll_audio_clk, "pll-audio",
-                       "pll-audio-base", 1, 1, CLK_SET_RATE_PARENT);
-static CLK_FIXED_FACTOR(pll_audio_2x_clk, "pll-audio-2x",
-                       "pll-audio-base", 2, 1, CLK_SET_RATE_PARENT);
-static CLK_FIXED_FACTOR(pll_audio_4x_clk, "pll-audio-4x",
-                       "pll-audio-base", 1, 1, CLK_SET_RATE_PARENT);
-static CLK_FIXED_FACTOR(pll_audio_8x_clk, "pll-audio-8x",
-                       "pll-audio-base", 1, 2, CLK_SET_RATE_PARENT);
-static CLK_FIXED_FACTOR(pll_periph_2x_clk, "pll-periph-2x",
-                       "pll-periph", 1, 2, 0);
-static CLK_FIXED_FACTOR(pll_video0_2x_clk, "pll-video0-2x",
-                       "pll-video0", 1, 2, CLK_SET_RATE_PARENT);
-static CLK_FIXED_FACTOR(pll_video1_2x_clk, "pll-video1-2x",
-                       "pll-video1", 1, 2, CLK_SET_RATE_PARENT);
+static CLK_FIXED_FACTOR_HWS(pll_audio_clk, "pll-audio",
+                           clk_parent_pll_audio,
+                           1, 1, CLK_SET_RATE_PARENT);
+static CLK_FIXED_FACTOR_HWS(pll_audio_2x_clk, "pll-audio-2x",
+                           clk_parent_pll_audio,
+                           2, 1, CLK_SET_RATE_PARENT);
+static CLK_FIXED_FACTOR_HWS(pll_audio_4x_clk, "pll-audio-4x",
+                           clk_parent_pll_audio,
+                           1, 1, CLK_SET_RATE_PARENT);
+static CLK_FIXED_FACTOR_HWS(pll_audio_8x_clk, "pll-audio-8x",
+                           clk_parent_pll_audio,
+                           1, 2, CLK_SET_RATE_PARENT);
+static CLK_FIXED_FACTOR_HW(pll_periph_2x_clk, "pll-periph-2x",
+                          &pll_periph_clk.common.hw,
+                          1, 2, 0);
+static CLK_FIXED_FACTOR_HW(pll_video0_2x_clk, "pll-video0-2x",
+                          &pll_video0_clk.common.hw,
+                          1, 2, CLK_SET_RATE_PARENT);
+static CLK_FIXED_FACTOR_HW(pll_video1_2x_clk, "pll-video1-2x",
+                          &pll_video1_clk.common.hw,
+                          1, 2, CLK_SET_RATE_PARENT);
 
 static struct clk_hw_onecell_data sun6i_a31_hw_clks = {
        .hws    = {
index 14ced50..103aa50 100644 (file)
@@ -543,19 +543,29 @@ static struct ccu_common *sun8i_a23_ccu_clks[] = {
        &ats_clk.common,
 };
 
+static const struct clk_hw *clk_parent_pll_audio[] = {
+       &pll_audio_base_clk.common.hw
+};
+
 /* We hardcode the divider to 1 for now */
-static CLK_FIXED_FACTOR(pll_audio_clk, "pll-audio",
-                       "pll-audio-base", 1, 1, CLK_SET_RATE_PARENT);
-static CLK_FIXED_FACTOR(pll_audio_2x_clk, "pll-audio-2x",
-                       "pll-audio-base", 2, 1, CLK_SET_RATE_PARENT);
-static CLK_FIXED_FACTOR(pll_audio_4x_clk, "pll-audio-4x",
-                       "pll-audio-base", 1, 1, CLK_SET_RATE_PARENT);
-static CLK_FIXED_FACTOR(pll_audio_8x_clk, "pll-audio-8x",
-                       "pll-audio-base", 1, 2, CLK_SET_RATE_PARENT);
-static CLK_FIXED_FACTOR(pll_periph_2x_clk, "pll-periph-2x",
-                       "pll-periph", 1, 2, 0);
-static CLK_FIXED_FACTOR(pll_video_2x_clk, "pll-video-2x",
-                       "pll-video", 1, 2, 0);
+static CLK_FIXED_FACTOR_HWS(pll_audio_clk, "pll-audio",
+                           clk_parent_pll_audio,
+                           1, 1, CLK_SET_RATE_PARENT);
+static CLK_FIXED_FACTOR_HWS(pll_audio_2x_clk, "pll-audio-2x",
+                           clk_parent_pll_audio,
+                           2, 1, CLK_SET_RATE_PARENT);
+static CLK_FIXED_FACTOR_HWS(pll_audio_4x_clk, "pll-audio-4x",
+                           clk_parent_pll_audio,
+                           1, 1, CLK_SET_RATE_PARENT);
+static CLK_FIXED_FACTOR_HWS(pll_audio_8x_clk, "pll-audio-8x",
+                           clk_parent_pll_audio,
+                           1, 2, CLK_SET_RATE_PARENT);
+static CLK_FIXED_FACTOR_HW(pll_periph_2x_clk, "pll-periph-2x",
+                          &pll_periph_clk.common.hw,
+                          1, 2, 0);
+static CLK_FIXED_FACTOR_HW(pll_video_2x_clk, "pll-video-2x",
+                          &pll_video_clk.common.hw,
+                          1, 2, 0);
 
 static struct clk_hw_onecell_data sun8i_a23_hw_clks = {
        .hws    = {
index 61fb41f..91838cd 100644 (file)
@@ -580,19 +580,29 @@ static struct ccu_common *sun8i_a33_ccu_clks[] = {
        &ats_clk.common,
 };
 
+static const struct clk_hw *clk_parent_pll_audio[] = {
+       &pll_audio_base_clk.common.hw
+};
+
 /* We hardcode the divider to 1 for now */
-static CLK_FIXED_FACTOR(pll_audio_clk, "pll-audio",
-                       "pll-audio-base", 1, 1, CLK_SET_RATE_PARENT);
-static CLK_FIXED_FACTOR(pll_audio_2x_clk, "pll-audio-2x",
-                       "pll-audio-base", 2, 1, CLK_SET_RATE_PARENT);
-static CLK_FIXED_FACTOR(pll_audio_4x_clk, "pll-audio-4x",
-                       "pll-audio-base", 1, 1, CLK_SET_RATE_PARENT);
-static CLK_FIXED_FACTOR(pll_audio_8x_clk, "pll-audio-8x",
-                       "pll-audio-base", 1, 2, CLK_SET_RATE_PARENT);
-static CLK_FIXED_FACTOR(pll_periph_2x_clk, "pll-periph-2x",
-                       "pll-periph", 1, 2, 0);
-static CLK_FIXED_FACTOR(pll_video_2x_clk, "pll-video-2x",
-                       "pll-video", 1, 2, 0);
+static CLK_FIXED_FACTOR_HWS(pll_audio_clk, "pll-audio",
+                           clk_parent_pll_audio,
+                           1, 1, CLK_SET_RATE_PARENT);
+static CLK_FIXED_FACTOR_HWS(pll_audio_2x_clk, "pll-audio-2x",
+                           clk_parent_pll_audio,
+                           2, 1, CLK_SET_RATE_PARENT);
+static CLK_FIXED_FACTOR_HWS(pll_audio_4x_clk, "pll-audio-4x",
+                           clk_parent_pll_audio,
+                           1, 1, CLK_SET_RATE_PARENT);
+static CLK_FIXED_FACTOR_HWS(pll_audio_8x_clk, "pll-audio-8x",
+                           clk_parent_pll_audio,
+                           1, 2, CLK_SET_RATE_PARENT);
+static CLK_FIXED_FACTOR_HW(pll_periph_2x_clk, "pll-periph-2x",
+                          &pll_periph_clk.common.hw,
+                          1, 2, 0);
+static CLK_FIXED_FACTOR_HW(pll_video_2x_clk, "pll-video-2x",
+                          &pll_video_clk.common.hw,
+                          1, 2, 0);
 
 static struct clk_hw_onecell_data sun8i_a33_hw_clks = {
        .hws    = {
index 9601504..6b63636 100644 (file)
@@ -717,17 +717,26 @@ static struct ccu_common *sun50i_h5_ccu_clks[] = {
        &gpu_clk.common,
 };
 
+static const struct clk_hw *clk_parent_pll_audio[] = {
+       &pll_audio_base_clk.common.hw
+};
+
 /* We hardcode the divider to 1 for now */
-static CLK_FIXED_FACTOR(pll_audio_clk, "pll-audio",
-                       "pll-audio-base", 1, 1, CLK_SET_RATE_PARENT);
-static CLK_FIXED_FACTOR(pll_audio_2x_clk, "pll-audio-2x",
-                       "pll-audio-base", 2, 1, CLK_SET_RATE_PARENT);
-static CLK_FIXED_FACTOR(pll_audio_4x_clk, "pll-audio-4x",
-                       "pll-audio-base", 1, 1, CLK_SET_RATE_PARENT);
-static CLK_FIXED_FACTOR(pll_audio_8x_clk, "pll-audio-8x",
-                       "pll-audio-base", 1, 2, CLK_SET_RATE_PARENT);
-static CLK_FIXED_FACTOR(pll_periph0_2x_clk, "pll-periph0-2x",
-                       "pll-periph0", 1, 2, 0);
+static CLK_FIXED_FACTOR_HWS(pll_audio_clk, "pll-audio",
+                           clk_parent_pll_audio,
+                           1, 1, CLK_SET_RATE_PARENT);
+static CLK_FIXED_FACTOR_HWS(pll_audio_2x_clk, "pll-audio-2x",
+                           clk_parent_pll_audio,
+                           2, 1, CLK_SET_RATE_PARENT);
+static CLK_FIXED_FACTOR_HWS(pll_audio_4x_clk, "pll-audio-4x",
+                           clk_parent_pll_audio,
+                           1, 1, CLK_SET_RATE_PARENT);
+static CLK_FIXED_FACTOR_HWS(pll_audio_8x_clk, "pll-audio-8x",
+                           clk_parent_pll_audio,
+                           1, 2, CLK_SET_RATE_PARENT);
+static CLK_FIXED_FACTOR_HW(pll_periph0_2x_clk, "pll-periph0-2x",
+                          &pll_periph0_clk.common.hw,
+                          1, 2, 0);
 
 static struct clk_hw_onecell_data sun8i_h3_hw_clks = {
        .hws    = {
index b5be11e..4646fdc 100644 (file)
 
 #include "ccu-sun8i-r.h"
 
-static const char * const ar100_parents[] = { "osc32k", "osc24M",
-                                            "pll-periph0", "iosc" };
-static const char * const a83t_ar100_parents[] = { "osc16M-d512", "osc24M",
-                                                  "pll-periph0", "iosc" };
+static const struct clk_parent_data ar100_parents[] = {
+       { .fw_name = "losc" },
+       { .fw_name = "hosc" },
+       { .fw_name = "pll-periph" },
+       { .fw_name = "iosc" },
+};
+
 static const struct ccu_mux_var_prediv ar100_predivs[] = {
        { .index = 2, .shift = 8, .width = 5 },
 };
@@ -39,64 +42,49 @@ static struct ccu_div ar100_clk = {
        .common         = {
                .reg            = 0x00,
                .features       = CCU_FEATURE_VARIABLE_PREDIV,
-               .hw.init        = CLK_HW_INIT_PARENTS("ar100",
-                                                     ar100_parents,
-                                                     &ccu_div_ops,
-                                                     0),
-       },
-};
-
-static struct ccu_div a83t_ar100_clk = {
-       .div            = _SUNXI_CCU_DIV_FLAGS(4, 2, CLK_DIVIDER_POWER_OF_TWO),
-
-       .mux            = {
-               .shift  = 16,
-               .width  = 2,
-
-               .var_predivs    = ar100_predivs,
-               .n_var_predivs  = ARRAY_SIZE(ar100_predivs),
-       },
-
-       .common         = {
-               .reg            = 0x00,
-               .features       = CCU_FEATURE_VARIABLE_PREDIV,
-               .hw.init        = CLK_HW_INIT_PARENTS("ar100",
-                                                     a83t_ar100_parents,
-                                                     &ccu_div_ops,
-                                                     0),
+               .hw.init        = CLK_HW_INIT_PARENTS_DATA("ar100",
+                                                          ar100_parents,
+                                                          &ccu_div_ops,
+                                                          0),
        },
 };
 
-static CLK_FIXED_FACTOR(ahb0_clk, "ahb0", "ar100", 1, 1, 0);
+static CLK_FIXED_FACTOR_HW(ahb0_clk, "ahb0", &ar100_clk.common.hw, 1, 1, 0);
 
 static struct ccu_div apb0_clk = {
        .div            = _SUNXI_CCU_DIV_FLAGS(0, 2, CLK_DIVIDER_POWER_OF_TWO),
 
        .common         = {
                .reg            = 0x0c,
-               .hw.init        = CLK_HW_INIT("apb0",
-                                             "ahb0",
-                                             &ccu_div_ops,
-                                             0),
+               .hw.init        = CLK_HW_INIT_HW("apb0",
+                                                &ahb0_clk.hw,
+                                                &ccu_div_ops,
+                                                0),
        },
 };
 
 static SUNXI_CCU_M(a83t_apb0_clk, "apb0", "ahb0", 0x0c, 0, 2, 0);
 
-static SUNXI_CCU_GATE(apb0_pio_clk,    "apb0-pio",     "apb0",
-                     0x28, BIT(0), 0);
-static SUNXI_CCU_GATE(apb0_ir_clk,     "apb0-ir",      "apb0",
-                     0x28, BIT(1), 0);
-static SUNXI_CCU_GATE(apb0_timer_clk,  "apb0-timer",   "apb0",
-                     0x28, BIT(2), 0);
-static SUNXI_CCU_GATE(apb0_rsb_clk,    "apb0-rsb",     "apb0",
-                     0x28, BIT(3), 0);
-static SUNXI_CCU_GATE(apb0_uart_clk,   "apb0-uart",    "apb0",
-                     0x28, BIT(4), 0);
-static SUNXI_CCU_GATE(apb0_i2c_clk,    "apb0-i2c",     "apb0",
-                     0x28, BIT(6), 0);
-static SUNXI_CCU_GATE(apb0_twd_clk,    "apb0-twd",     "apb0",
-                     0x28, BIT(7), 0);
+/*
+ * Define the parent as an array that can be reused to save space
+ * instead of having compound literals for each gate. Also have it
+ * non-const so we can change it on the A83T.
+ */
+static const struct clk_hw *apb0_gate_parent[] = { &apb0_clk.common.hw };
+static SUNXI_CCU_GATE_HWS(apb0_pio_clk,                "apb0-pio",
+                         apb0_gate_parent, 0x28, BIT(0), 0);
+static SUNXI_CCU_GATE_HWS(apb0_ir_clk,         "apb0-ir",
+                         apb0_gate_parent, 0x28, BIT(1), 0);
+static SUNXI_CCU_GATE_HWS(apb0_timer_clk,      "apb0-timer",
+                         apb0_gate_parent, 0x28, BIT(2), 0);
+static SUNXI_CCU_GATE_HWS(apb0_rsb_clk,                "apb0-rsb",
+                         apb0_gate_parent, 0x28, BIT(3), 0);
+static SUNXI_CCU_GATE_HWS(apb0_uart_clk,       "apb0-uart",
+                         apb0_gate_parent, 0x28, BIT(4), 0);
+static SUNXI_CCU_GATE_HWS(apb0_i2c_clk,                "apb0-i2c",
+                         apb0_gate_parent, 0x28, BIT(6), 0);
+static SUNXI_CCU_GATE_HWS(apb0_twd_clk,                "apb0-twd",
+                         apb0_gate_parent, 0x28, BIT(7), 0);
 
 static const char * const r_mod0_default_parents[] = { "osc32k", "osc24M" };
 static SUNXI_CCU_MP_WITH_MUX_GATE(ir_clk, "ir",
@@ -107,7 +95,10 @@ static SUNXI_CCU_MP_WITH_MUX_GATE(ir_clk, "ir",
                                  BIT(31),      /* gate */
                                  0);
 
-static const char *const a83t_r_mod0_parents[] = { "osc16M", "osc24M" };
+static const struct clk_parent_data a83t_r_mod0_parents[] = {
+       { .fw_name = "iosc" },
+       { .fw_name = "hosc" },
+};
 static const struct ccu_mux_fixed_prediv a83t_ir_predivs[] = {
        { .index = 0, .div = 16 },
 };
@@ -127,15 +118,15 @@ static struct ccu_mp a83t_ir_clk = {
        .common         = {
                .reg            = 0x54,
                .features       = CCU_FEATURE_VARIABLE_PREDIV,
-               .hw.init        = CLK_HW_INIT_PARENTS("ir",
-                                                     a83t_r_mod0_parents,
-                                                     &ccu_mp_ops,
-                                                     0),
+               .hw.init        = CLK_HW_INIT_PARENTS_DATA("ir",
+                                                          a83t_r_mod0_parents,
+                                                          &ccu_mp_ops,
+                                                          0),
        },
 };
 
 static struct ccu_common *sun8i_a83t_r_ccu_clks[] = {
-       &a83t_ar100_clk.common,
+       &ar100_clk.common,
        &a83t_apb0_clk.common,
        &apb0_pio_clk.common,
        &apb0_ir_clk.common,
@@ -174,7 +165,7 @@ static struct ccu_common *sun50i_a64_r_ccu_clks[] = {
 
 static struct clk_hw_onecell_data sun8i_a83t_r_hw_clks = {
        .hws    = {
-               [CLK_AR100]             = &a83t_ar100_clk.common.hw,
+               [CLK_AR100]             = &ar100_clk.common.hw,
                [CLK_AHB0]              = &ahb0_clk.hw,
                [CLK_APB0]              = &a83t_apb0_clk.common.hw,
                [CLK_APB0_PIO]          = &apb0_pio_clk.common.hw,
@@ -291,6 +282,9 @@ static void __init sunxi_r_ccu_init(struct device_node *node,
 
 static void __init sun8i_a83t_r_ccu_setup(struct device_node *node)
 {
+       /* Fix apb0 bus gate parents here */
+       apb0_gate_parent[0] = &a83t_apb0_clk.common.hw;
+
        sunxi_r_ccu_init(node, &sun8i_a83t_r_ccu_desc);
 }
 CLK_OF_DECLARE(sun8i_a83t_r_ccu, "allwinner,sun8i-a83t-r-ccu",
index 540f5f7..8974908 100644 (file)
@@ -944,25 +944,37 @@ static struct ccu_common *sun8i_r40_ccu_clks[] = {
 };
 
 /* Fixed Factor clocks */
-static CLK_FIXED_FACTOR(osc12M_clk, "osc12M", "osc24M", 2, 1, 0);
+static CLK_FIXED_FACTOR_FW_NAME(osc12M_clk, "osc12M", "hosc", 2, 1, 0);
+
+static const struct clk_hw *clk_parent_pll_audio[] = {
+       &pll_audio_base_clk.common.hw
+};
 
 /* We hardcode the divider to 4 for now */
-static CLK_FIXED_FACTOR(pll_audio_clk, "pll-audio",
-                       "pll-audio-base", 4, 1, CLK_SET_RATE_PARENT);
-static CLK_FIXED_FACTOR(pll_audio_2x_clk, "pll-audio-2x",
-                       "pll-audio-base", 2, 1, CLK_SET_RATE_PARENT);
-static CLK_FIXED_FACTOR(pll_audio_4x_clk, "pll-audio-4x",
-                       "pll-audio-base", 1, 1, CLK_SET_RATE_PARENT);
-static CLK_FIXED_FACTOR(pll_audio_8x_clk, "pll-audio-8x",
-                       "pll-audio-base", 1, 2, CLK_SET_RATE_PARENT);
-static CLK_FIXED_FACTOR(pll_periph0_2x_clk, "pll-periph0-2x",
-                       "pll-periph0", 1, 2, 0);
-static CLK_FIXED_FACTOR(pll_periph1_2x_clk, "pll-periph1-2x",
-                       "pll-periph1", 1, 2, 0);
-static CLK_FIXED_FACTOR(pll_video0_2x_clk, "pll-video0-2x",
-                       "pll-video0", 1, 2, 0);
-static CLK_FIXED_FACTOR(pll_video1_2x_clk, "pll-video1-2x",
-                       "pll-video1", 1, 2, 0);
+static CLK_FIXED_FACTOR_HWS(pll_audio_clk, "pll-audio",
+                           clk_parent_pll_audio,
+                           4, 1, CLK_SET_RATE_PARENT);
+static CLK_FIXED_FACTOR_HWS(pll_audio_2x_clk, "pll-audio-2x",
+                           clk_parent_pll_audio,
+                           2, 1, CLK_SET_RATE_PARENT);
+static CLK_FIXED_FACTOR_HWS(pll_audio_4x_clk, "pll-audio-4x",
+                           clk_parent_pll_audio,
+                           1, 1, CLK_SET_RATE_PARENT);
+static CLK_FIXED_FACTOR_HWS(pll_audio_8x_clk, "pll-audio-8x",
+                           clk_parent_pll_audio,
+                           1, 2, CLK_SET_RATE_PARENT);
+static CLK_FIXED_FACTOR_HW(pll_periph0_2x_clk, "pll-periph0-2x",
+                          &pll_periph0_clk.common.hw,
+                          1, 2, 0);
+static CLK_FIXED_FACTOR_HW(pll_periph1_2x_clk, "pll-periph1-2x",
+                          &pll_periph1_clk.common.hw,
+                          1, 2, 0);
+static CLK_FIXED_FACTOR_HW(pll_video0_2x_clk, "pll-video0-2x",
+                          &pll_video0_clk.common.hw,
+                          1, 2, 0);
+static CLK_FIXED_FACTOR_HW(pll_video1_2x_clk, "pll-video1-2x",
+                          &pll_video1_clk.common.hw,
+                          1, 2, 0);
 
 static struct clk_hw_onecell_data sun8i_r40_hw_clks = {
        .hws    = {
index cbbf06d..9b3939f 100644 (file)
@@ -429,17 +429,26 @@ static struct ccu_common *sun8i_v3s_ccu_clks[] = {
        &mipi_csi_clk.common,
 };
 
+static const struct clk_hw *clk_parent_pll_audio[] = {
+       &pll_audio_base_clk.common.hw
+};
+
 /* We hardcode the divider to 4 for now */
-static CLK_FIXED_FACTOR(pll_audio_clk, "pll-audio",
-                       "pll-audio-base", 4, 1, CLK_SET_RATE_PARENT);
-static CLK_FIXED_FACTOR(pll_audio_2x_clk, "pll-audio-2x",
-                       "pll-audio-base", 2, 1, CLK_SET_RATE_PARENT);
-static CLK_FIXED_FACTOR(pll_audio_4x_clk, "pll-audio-4x",
-                       "pll-audio-base", 1, 1, CLK_SET_RATE_PARENT);
-static CLK_FIXED_FACTOR(pll_audio_8x_clk, "pll-audio-8x",
-                       "pll-audio-base", 1, 2, CLK_SET_RATE_PARENT);
-static CLK_FIXED_FACTOR(pll_periph0_2x_clk, "pll-periph0-2x",
-                       "pll-periph0", 1, 2, 0);
+static CLK_FIXED_FACTOR_HWS(pll_audio_clk, "pll-audio",
+                           clk_parent_pll_audio,
+                           4, 1, CLK_SET_RATE_PARENT);
+static CLK_FIXED_FACTOR_HWS(pll_audio_2x_clk, "pll-audio-2x",
+                           clk_parent_pll_audio,
+                           2, 1, CLK_SET_RATE_PARENT);
+static CLK_FIXED_FACTOR_HWS(pll_audio_4x_clk, "pll-audio-4x",
+                           clk_parent_pll_audio,
+                           1, 1, CLK_SET_RATE_PARENT);
+static CLK_FIXED_FACTOR_HWS(pll_audio_8x_clk, "pll-audio-8x",
+                           clk_parent_pll_audio,
+                           1, 2, CLK_SET_RATE_PARENT);
+static CLK_FIXED_FACTOR_HW(pll_periph0_2x_clk, "pll-periph0-2x",
+                          &pll_periph0_clk.common.hw,
+                          1, 2, 0);
 
 static struct clk_hw_onecell_data sun8i_v3s_hw_clks = {
        .hws    = {
index 2f82cd8..4b4a507 100644 (file)
 
 #include "ccu-sun9i-a80-usb.h"
 
-static SUNXI_CCU_GATE(bus_hci0_clk, "bus-hci0", "bus-usb", 0x0, BIT(1), 0);
-static SUNXI_CCU_GATE(usb_ohci0_clk, "usb-ohci0", "osc24M", 0x0, BIT(2), 0);
-static SUNXI_CCU_GATE(bus_hci1_clk, "bus-hci1", "bus-usb", 0x0, BIT(3), 0);
-static SUNXI_CCU_GATE(bus_hci2_clk, "bus-hci2", "bus-usb", 0x0, BIT(5), 0);
-static SUNXI_CCU_GATE(usb_ohci2_clk, "usb-ohci2", "osc24M", 0x0, BIT(6), 0);
-
-static SUNXI_CCU_GATE(usb0_phy_clk, "usb0-phy", "osc24M", 0x4, BIT(1), 0);
-static SUNXI_CCU_GATE(usb1_hsic_clk, "usb1-hsic", "osc24M", 0x4, BIT(2), 0);
-static SUNXI_CCU_GATE(usb1_phy_clk, "usb1-phy", "osc24M", 0x4, BIT(3), 0);
-static SUNXI_CCU_GATE(usb2_hsic_clk, "usb2-hsic", "osc24M", 0x4, BIT(4), 0);
-static SUNXI_CCU_GATE(usb2_phy_clk, "usb2-phy", "osc24M", 0x4, BIT(5), 0);
-static SUNXI_CCU_GATE(usb_hsic_clk, "usb-hsic", "osc24M", 0x4, BIT(10), 0);
+static const struct clk_parent_data clk_parent_hosc[] = {
+       { .fw_name = "hosc" },
+};
+
+static const struct clk_parent_data clk_parent_bus[] = {
+       { .fw_name = "bus" },
+};
+
+static SUNXI_CCU_GATE_DATA(bus_hci0_clk, "bus-hci0", clk_parent_bus, 0x0, BIT(1), 0);
+static SUNXI_CCU_GATE_DATA(usb_ohci0_clk, "usb-ohci0", clk_parent_hosc, 0x0, BIT(2), 0);
+static SUNXI_CCU_GATE_DATA(bus_hci1_clk, "bus-hci1", clk_parent_bus, 0x0, BIT(3), 0);
+static SUNXI_CCU_GATE_DATA(bus_hci2_clk, "bus-hci2", clk_parent_bus, 0x0, BIT(5), 0);
+static SUNXI_CCU_GATE_DATA(usb_ohci2_clk, "usb-ohci2", clk_parent_hosc, 0x0, BIT(6), 0);
+
+static SUNXI_CCU_GATE_DATA(usb0_phy_clk, "usb0-phy", clk_parent_hosc, 0x4, BIT(1), 0);
+static SUNXI_CCU_GATE_DATA(usb1_hsic_clk, "usb1-hsic", clk_parent_hosc, 0x4, BIT(2), 0);
+static SUNXI_CCU_GATE_DATA(usb1_phy_clk, "usb1-phy", clk_parent_hosc, 0x4, BIT(3), 0);
+static SUNXI_CCU_GATE_DATA(usb2_hsic_clk, "usb2-hsic", clk_parent_hosc, 0x4, BIT(4), 0);
+static SUNXI_CCU_GATE_DATA(usb2_phy_clk, "usb2-phy", clk_parent_hosc, 0x4, BIT(5), 0);
+static SUNXI_CCU_GATE_DATA(usb_hsic_clk, "usb-hsic", clk_parent_hosc, 0x4, BIT(10), 0);
 
 static struct ccu_common *sun9i_a80_usb_clks[] = {
        &bus_hci0_clk.common,
index e748b8a..7ecc3a5 100644 (file)
@@ -374,16 +374,25 @@ static struct ccu_common *suniv_ccu_clks[] = {
        &avs_clk.common,
 };
 
-static CLK_FIXED_FACTOR(pll_audio_clk, "pll-audio",
-                       "pll-audio-base", 4, 1, CLK_SET_RATE_PARENT);
-static CLK_FIXED_FACTOR(pll_audio_2x_clk, "pll-audio-2x",
-                       "pll-audio-base", 2, 1, CLK_SET_RATE_PARENT);
-static CLK_FIXED_FACTOR(pll_audio_4x_clk, "pll-audio-4x",
-                       "pll-audio-base", 1, 1, CLK_SET_RATE_PARENT);
-static CLK_FIXED_FACTOR(pll_audio_8x_clk, "pll-audio-8x",
-                       "pll-audio-base", 1, 2, CLK_SET_RATE_PARENT);
-static CLK_FIXED_FACTOR(pll_video_2x_clk, "pll-video-2x",
-                       "pll-video", 1, 2, 0);
+static const struct clk_hw *clk_parent_pll_audio[] = {
+       &pll_audio_base_clk.common.hw
+};
+
+static CLK_FIXED_FACTOR_HWS(pll_audio_clk, "pll-audio",
+                           clk_parent_pll_audio,
+                           4, 1, CLK_SET_RATE_PARENT);
+static CLK_FIXED_FACTOR_HWS(pll_audio_2x_clk, "pll-audio-2x",
+                           clk_parent_pll_audio,
+                           2, 1, CLK_SET_RATE_PARENT);
+static CLK_FIXED_FACTOR_HWS(pll_audio_4x_clk, "pll-audio-4x",
+                           clk_parent_pll_audio,
+                           1, 1, CLK_SET_RATE_PARENT);
+static CLK_FIXED_FACTOR_HWS(pll_audio_8x_clk, "pll-audio-8x",
+                           clk_parent_pll_audio,
+                           1, 2, CLK_SET_RATE_PARENT);
+static CLK_FIXED_FACTOR_HW(pll_video_2x_clk, "pll-video-2x",
+                           &pll_video_clk.common.hw,
+                           1, 2, 0);
 
 static struct clk_hw_onecell_data suniv_hw_clks = {
        .hws    = {
index c173778..7fe3ac9 100644 (file)
@@ -101,7 +101,7 @@ int sunxi_ccu_probe(struct device_node *node, void __iomem *reg,
                if (!hw)
                        continue;
 
-               ret = clk_hw_register(NULL, hw);
+               ret = of_clk_hw_register(node, hw);
                if (ret) {
                        pr_err("Couldn't register clock %d - %s\n",
                               i, clk_hw_get_name(hw));
index da8100e..c386689 100644 (file)
@@ -28,6 +28,59 @@ struct ccu_gate {
                }                                                       \
        }
 
+#define SUNXI_CCU_GATE_HW(_struct, _name, _parent, _reg, _gate, _flags)        \
+       struct ccu_gate _struct = {                                     \
+               .enable = _gate,                                        \
+               .common = {                                             \
+                       .reg            = _reg,                         \
+                       .hw.init        = CLK_HW_INIT_HW(_name,         \
+                                                        _parent,       \
+                                                        &ccu_gate_ops, \
+                                                        _flags),       \
+               }                                                       \
+       }
+
+#define SUNXI_CCU_GATE_FW(_struct, _name, _parent, _reg, _gate, _flags)        \
+       struct ccu_gate _struct = {                                     \
+               .enable = _gate,                                        \
+               .common = {                                             \
+                       .reg            = _reg,                         \
+                       .hw.init        = CLK_HW_INIT_FW_NAME(_name,    \
+                                                             _parent,  \
+                                                             &ccu_gate_ops, \
+                                                             _flags),  \
+               }                                                       \
+       }
+
+/*
+ * The following two macros allow the re-use of the data structure
+ * holding the parent info.
+ */
+#define SUNXI_CCU_GATE_HWS(_struct, _name, _parent, _reg, _gate, _flags) \
+       struct ccu_gate _struct = {                                     \
+               .enable = _gate,                                        \
+               .common = {                                             \
+                       .reg            = _reg,                         \
+                       .hw.init        = CLK_HW_INIT_HWS(_name,        \
+                                                         _parent,      \
+                                                         &ccu_gate_ops, \
+                                                         _flags),      \
+               }                                                       \
+       }
+
+#define SUNXI_CCU_GATE_DATA(_struct, _name, _data, _reg, _gate, _flags)        \
+       struct ccu_gate _struct = {                                     \
+               .enable = _gate,                                        \
+               .common = {                                             \
+                       .reg            = _reg,                         \
+                       .hw.init        =                               \
+                               CLK_HW_INIT_PARENTS_DATA(_name,         \
+                                                        _data,         \
+                                                        &ccu_gate_ops, \
+                                                        _flags),       \
+               }                                                       \
+       }
+
 static inline struct ccu_gate *hw_to_ccu_gate(struct clk_hw *hw)
 {
        struct ccu_common *common = hw_to_ccu_common(hw);
index 623fda5..d3a4338 100644 (file)
@@ -980,6 +980,8 @@ static struct clk ** __init sunxi_divs_clk_setup(struct device_node *node,
                if (endp) {
                        derived_name = kstrndup(clk_name, endp - clk_name,
                                                GFP_KERNEL);
+                       if (!derived_name)
+                               return NULL;
                        factors.name = derived_name;
                } else {
                        factors.name = clk_name;
index ac1d27a..df172d5 100644 (file)
@@ -984,8 +984,6 @@ static void tegra210_pllre_set_defaults(struct tegra_clk_pll *pllre)
        pllre->params->defaults_set = true;
 
        if (val & PLL_ENABLE) {
-               pr_warn("PLL_RE already enabled. Postponing set full defaults\n");
-
                /*
                 * PLL is ON: check if defaults already set, then set those
                 * that can be updated in flight.
@@ -1005,13 +1003,20 @@ static void tegra210_pllre_set_defaults(struct tegra_clk_pll *pllre)
                _pll_misc_chk_default(clk_base, pllre->params, 0, val,
                                ~mask & PLLRE_MISC0_WRITE_MASK);
 
-               /* Enable lock detect */
+               /* The PLL doesn't work if it's in IDDQ. */
                val = readl_relaxed(clk_base + pllre->params->ext_misc_reg[0]);
+               if (val & PLLRE_MISC0_IDDQ)
+                       pr_warn("unexpected IDDQ bit set for enabled clock\n");
+
+               /* Enable lock detect */
                val &= ~mask;
                val |= PLLRE_MISC0_DEFAULT_VALUE & mask;
                writel_relaxed(val, clk_base + pllre->params->ext_misc_reg[0]);
                udelay(1);
 
+               if (!pllre->params->defaults_set)
+                       pr_warn("PLL_RE already enabled. Postponing set full defaults\n");
+
                return;
        }
 
@@ -2204,9 +2209,9 @@ static struct div_nmp pllu_nmp = {
 };
 
 static struct tegra_clk_pll_freq_table pll_u_freq_table[] = {
-       { 12000000, 480000000, 40, 1, 0, 0 },
-       { 13000000, 480000000, 36, 1, 0, 0 }, /* actual: 468.0 MHz */
-       { 38400000, 480000000, 25, 2, 0, 0 },
+       { 12000000, 480000000, 40, 1, 1, 0 },
+       { 13000000, 480000000, 36, 1, 1, 0 }, /* actual: 468.0 MHz */
+       { 38400000, 480000000, 25, 2, 1, 0 },
        {        0,         0,  0, 0, 0, 0 },
 };
 
@@ -3332,7 +3337,7 @@ static struct tegra_clk_init_table init_table[] __initdata = {
        { TEGRA210_CLK_DFLL_SOC, TEGRA210_CLK_PLL_P, 51000000, 1 },
        { TEGRA210_CLK_DFLL_REF, TEGRA210_CLK_PLL_P, 51000000, 1 },
        { TEGRA210_CLK_SBC4, TEGRA210_CLK_PLL_P, 12000000, 1 },
-       { TEGRA210_CLK_PLL_RE_VCO, TEGRA210_CLK_CLK_MAX, 672000000, 1 },
+       { TEGRA210_CLK_PLL_U_OUT1, TEGRA210_CLK_CLK_MAX, 48000000, 1 },
        { TEGRA210_CLK_XUSB_GATE, TEGRA210_CLK_CLK_MAX, 0, 1 },
        { TEGRA210_CLK_XUSB_SS_SRC, TEGRA210_CLK_PLL_U_480M, 120000000, 0 },
        { TEGRA210_CLK_XUSB_FS_SRC, TEGRA210_CLK_PLL_U_48M, 48000000, 0 },
@@ -3357,7 +3362,6 @@ static struct tegra_clk_init_table init_table[] __initdata = {
        { TEGRA210_CLK_PLL_DP, TEGRA210_CLK_CLK_MAX, 270000000, 0 },
        { TEGRA210_CLK_SOC_THERM, TEGRA210_CLK_PLL_P, 51000000, 0 },
        { TEGRA210_CLK_CCLK_G, TEGRA210_CLK_CLK_MAX, 0, 1 },
-       { TEGRA210_CLK_PLL_U_OUT1, TEGRA210_CLK_CLK_MAX, 48000000, 1 },
        { TEGRA210_CLK_PLL_U_OUT2, TEGRA210_CLK_CLK_MAX, 60000000, 1 },
        { TEGRA210_CLK_SPDIF_IN_SYNC, TEGRA210_CLK_CLK_MAX, 24576000, 0 },
        { TEGRA210_CLK_I2S0_SYNC, TEGRA210_CLK_CLK_MAX, 24576000, 0 },
index 4786e0e..6cb863c 100644 (file)
@@ -425,91 +425,6 @@ int ti_clk_parse_divider_data(int *div_table, int num_dividers, int max_div,
        return 0;
 }
 
-static const struct clk_div_table *
-_get_div_table_from_setup(struct ti_clk_divider *setup, u8 *width)
-{
-       const struct clk_div_table *table = NULL;
-
-       ti_clk_parse_divider_data(setup->dividers, setup->num_dividers,
-                                 setup->max_div, setup->flags, width,
-                                 &table);
-
-       return table;
-}
-
-struct clk_hw *ti_clk_build_component_div(struct ti_clk_divider *setup)
-{
-       struct clk_omap_divider *div;
-       struct clk_omap_reg *reg;
-       int ret;
-
-       if (!setup)
-               return NULL;
-
-       div = kzalloc(sizeof(*div), GFP_KERNEL);
-       if (!div)
-               return ERR_PTR(-ENOMEM);
-
-       reg = (struct clk_omap_reg *)&div->reg;
-       reg->index = setup->module;
-       reg->offset = setup->reg;
-
-       if (setup->flags & CLKF_INDEX_STARTS_AT_ONE)
-               div->flags |= CLK_DIVIDER_ONE_BASED;
-
-       if (setup->flags & CLKF_INDEX_POWER_OF_TWO)
-               div->flags |= CLK_DIVIDER_POWER_OF_TWO;
-
-       div->table = _get_div_table_from_setup(setup, &div->width);
-       if (IS_ERR(div->table)) {
-               ret = PTR_ERR(div->table);
-               kfree(div);
-               return ERR_PTR(ret);
-       }
-
-
-       div->shift = setup->bit_shift;
-       div->latch = -EINVAL;
-
-       return &div->hw;
-}
-
-struct clk *ti_clk_register_divider(struct ti_clk *setup)
-{
-       struct ti_clk_divider *div = setup->data;
-       struct clk_omap_reg reg = {
-               .index = div->module,
-               .offset = div->reg,
-       };
-       u8 width;
-       u32 flags = 0;
-       u8 div_flags = 0;
-       const struct clk_div_table *table;
-       struct clk *clk;
-
-       if (div->flags & CLKF_INDEX_STARTS_AT_ONE)
-               div_flags |= CLK_DIVIDER_ONE_BASED;
-
-       if (div->flags & CLKF_INDEX_POWER_OF_TWO)
-               div_flags |= CLK_DIVIDER_POWER_OF_TWO;
-
-       if (div->flags & CLKF_SET_RATE_PARENT)
-               flags |= CLK_SET_RATE_PARENT;
-
-       table = _get_div_table_from_setup(div, &width);
-       if (IS_ERR(table))
-               return (struct clk *)table;
-
-       clk = _register_divider(NULL, setup->name, div->parent,
-                               flags, &reg, div->bit_shift,
-                               width, -EINVAL, div_flags, table);
-
-       if (IS_ERR(clk))
-               kfree(table);
-
-       return clk;
-}
-
 static struct clk_div_table *
 __init ti_clk_get_div_table(struct device_node *node)
 {
index 504c0e9..4238955 100644 (file)
@@ -131,36 +131,6 @@ static struct clk *_register_gate(struct device *dev, const char *name,
        return clk;
 }
 
-struct clk_hw *ti_clk_build_component_gate(struct ti_clk_gate *setup)
-{
-       struct clk_hw_omap *gate;
-       struct clk_omap_reg *reg;
-       const struct clk_hw_omap_ops *ops = &clkhwops_wait;
-
-       if (!setup)
-               return NULL;
-
-       gate = kzalloc(sizeof(*gate), GFP_KERNEL);
-       if (!gate)
-               return ERR_PTR(-ENOMEM);
-
-       reg = (struct clk_omap_reg *)&gate->enable_reg;
-       reg->index = setup->module;
-       reg->offset = setup->reg;
-
-       gate->enable_bit = setup->bit_shift;
-
-       if (setup->flags & CLKF_NO_WAIT)
-               ops = NULL;
-
-       if (setup->flags & CLKF_INTERFACE)
-               ops = &clkhwops_iclk_wait;
-
-       gate->ops = ops;
-
-       return &gate->hw;
-}
-
 static void __init _of_ti_gate_clk_setup(struct device_node *node,
                                         const struct clk_ops *ops,
                                         const struct clk_hw_omap_ops *hw_ops)
index b7f9a4f..0069e7c 100644 (file)
@@ -164,37 +164,6 @@ static struct clk *_register_mux(struct device *dev, const char *name,
        return clk;
 }
 
-struct clk *ti_clk_register_mux(struct ti_clk *setup)
-{
-       struct ti_clk_mux *mux;
-       u32 flags;
-       u8 mux_flags = 0;
-       struct clk_omap_reg reg;
-       u32 mask;
-
-       mux = setup->data;
-       flags = CLK_SET_RATE_NO_REPARENT;
-
-       mask = mux->num_parents;
-       if (!(mux->flags & CLKF_INDEX_STARTS_AT_ONE))
-               mask--;
-
-       mask = (1 << fls(mask)) - 1;
-       reg.index = mux->module;
-       reg.offset = mux->reg;
-       reg.ptr = NULL;
-
-       if (mux->flags & CLKF_INDEX_STARTS_AT_ONE)
-               mux_flags |= CLK_MUX_INDEX_ONE;
-
-       if (mux->flags & CLKF_SET_RATE_PARENT)
-               flags |= CLK_SET_RATE_PARENT;
-
-       return _register_mux(NULL, setup->name, mux->parents, mux->num_parents,
-                            flags, &reg, mux->bit_shift, mask, -EINVAL,
-                            mux_flags, NULL);
-}
-
 /**
  * of_mux_clk_setup - Setup function for simple mux rate clock
  * @node: DT node for the clock
index 61be15d..da26a58 100644 (file)
@@ -20,6 +20,7 @@
 #define MBOX_CHAN_PROPERTY             8
 
 static struct platform_device *rpi_hwmon;
+static struct platform_device *rpi_clk;
 
 struct rpi_firmware {
        struct mbox_client cl;
@@ -207,6 +208,12 @@ rpi_register_hwmon_driver(struct device *dev, struct rpi_firmware *fw)
                                                  -1, NULL, 0);
 }
 
+static void rpi_register_clk_driver(struct device *dev)
+{
+       rpi_clk = platform_device_register_data(dev, "raspberrypi-clk",
+                                               -1, NULL, 0);
+}
+
 static int rpi_firmware_probe(struct platform_device *pdev)
 {
        struct device *dev = &pdev->dev;
@@ -234,6 +241,7 @@ static int rpi_firmware_probe(struct platform_device *pdev)
 
        rpi_firmware_print_firmware_revision(fw);
        rpi_register_hwmon_driver(dev, fw);
+       rpi_register_clk_driver(dev);
 
        return 0;
 }
@@ -254,6 +262,8 @@ static int rpi_firmware_remove(struct platform_device *pdev)
 
        platform_device_unregister(rpi_hwmon);
        rpi_hwmon = NULL;
+       platform_device_unregister(rpi_clk);
+       rpi_clk = NULL;
        mbox_free_channel(fw->chan);
 
        return 0;
index ef93406..7696c69 100644 (file)
@@ -916,7 +916,7 @@ static int ti_sci_cmd_get_device_resets(const struct ti_sci_handle *handle,
  * Return: 0 if all went well, else returns appropriate error value.
  */
 static int ti_sci_set_clock_state(const struct ti_sci_handle *handle,
-                                 u32 dev_id, u8 clk_id,
+                                 u32 dev_id, u32 clk_id,
                                  u32 flags, u8 state)
 {
        struct ti_sci_info *info;
@@ -944,7 +944,12 @@ static int ti_sci_set_clock_state(const struct ti_sci_handle *handle,
        }
        req = (struct ti_sci_msg_req_set_clock_state *)xfer->xfer_buf;
        req->dev_id = dev_id;
-       req->clk_id = clk_id;
+       if (clk_id < 255) {
+               req->clk_id = clk_id;
+       } else {
+               req->clk_id = 255;
+               req->clk_id_32 = clk_id;
+       }
        req->request_state = state;
 
        ret = ti_sci_do_xfer(info, xfer);
@@ -976,7 +981,7 @@ fail:
  * Return: 0 if all went well, else returns appropriate error value.
  */
 static int ti_sci_cmd_get_clock_state(const struct ti_sci_handle *handle,
-                                     u32 dev_id, u8 clk_id,
+                                     u32 dev_id, u32 clk_id,
                                      u8 *programmed_state, u8 *current_state)
 {
        struct ti_sci_info *info;
@@ -1007,7 +1012,12 @@ static int ti_sci_cmd_get_clock_state(const struct ti_sci_handle *handle,
        }
        req = (struct ti_sci_msg_req_get_clock_state *)xfer->xfer_buf;
        req->dev_id = dev_id;
-       req->clk_id = clk_id;
+       if (clk_id < 255) {
+               req->clk_id = clk_id;
+       } else {
+               req->clk_id = 255;
+               req->clk_id_32 = clk_id;
+       }
 
        ret = ti_sci_do_xfer(info, xfer);
        if (ret) {
@@ -1047,8 +1057,8 @@ fail:
  * Return: 0 if all went well, else returns appropriate error value.
  */
 static int ti_sci_cmd_get_clock(const struct ti_sci_handle *handle, u32 dev_id,
-                               u8 clk_id, bool needs_ssc, bool can_change_freq,
-                               bool enable_input_term)
+                               u32 clk_id, bool needs_ssc,
+                               bool can_change_freq, bool enable_input_term)
 {
        u32 flags = 0;
 
@@ -1073,7 +1083,7 @@ static int ti_sci_cmd_get_clock(const struct ti_sci_handle *handle, u32 dev_id,
  * Return: 0 if all went well, else returns appropriate error value.
  */
 static int ti_sci_cmd_idle_clock(const struct ti_sci_handle *handle,
-                                u32 dev_id, u8 clk_id)
+                                u32 dev_id, u32 clk_id)
 {
        return ti_sci_set_clock_state(handle, dev_id, clk_id, 0,
                                      MSG_CLOCK_SW_STATE_UNREQ);
@@ -1092,7 +1102,7 @@ static int ti_sci_cmd_idle_clock(const struct ti_sci_handle *handle,
  * Return: 0 if all went well, else returns appropriate error value.
  */
 static int ti_sci_cmd_put_clock(const struct ti_sci_handle *handle,
-                               u32 dev_id, u8 clk_id)
+                               u32 dev_id, u32 clk_id)
 {
        return ti_sci_set_clock_state(handle, dev_id, clk_id, 0,
                                      MSG_CLOCK_SW_STATE_AUTO);
@@ -1110,7 +1120,7 @@ static int ti_sci_cmd_put_clock(const struct ti_sci_handle *handle,
  * Return: 0 if all went well, else returns appropriate error value.
  */
 static int ti_sci_cmd_clk_is_auto(const struct ti_sci_handle *handle,
-                                 u32 dev_id, u8 clk_id, bool *req_state)
+                                 u32 dev_id, u32 clk_id, bool *req_state)
 {
        u8 state = 0;
        int ret;
@@ -1139,7 +1149,7 @@ static int ti_sci_cmd_clk_is_auto(const struct ti_sci_handle *handle,
  * Return: 0 if all went well, else returns appropriate error value.
  */
 static int ti_sci_cmd_clk_is_on(const struct ti_sci_handle *handle, u32 dev_id,
-                               u8 clk_id, bool *req_state, bool *curr_state)
+                               u32 clk_id, bool *req_state, bool *curr_state)
 {
        u8 c_state = 0, r_state = 0;
        int ret;
@@ -1172,7 +1182,7 @@ static int ti_sci_cmd_clk_is_on(const struct ti_sci_handle *handle, u32 dev_id,
  * Return: 0 if all went well, else returns appropriate error value.
  */
 static int ti_sci_cmd_clk_is_off(const struct ti_sci_handle *handle, u32 dev_id,
-                                u8 clk_id, bool *req_state, bool *curr_state)
+                                u32 clk_id, bool *req_state, bool *curr_state)
 {
        u8 c_state = 0, r_state = 0;
        int ret;
@@ -1204,7 +1214,7 @@ static int ti_sci_cmd_clk_is_off(const struct ti_sci_handle *handle, u32 dev_id,
  * Return: 0 if all went well, else returns appropriate error value.
  */
 static int ti_sci_cmd_clk_set_parent(const struct ti_sci_handle *handle,
-                                    u32 dev_id, u8 clk_id, u8 parent_id)
+                                    u32 dev_id, u32 clk_id, u32 parent_id)
 {
        struct ti_sci_info *info;
        struct ti_sci_msg_req_set_clock_parent *req;
@@ -1231,8 +1241,18 @@ static int ti_sci_cmd_clk_set_parent(const struct ti_sci_handle *handle,
        }
        req = (struct ti_sci_msg_req_set_clock_parent *)xfer->xfer_buf;
        req->dev_id = dev_id;
-       req->clk_id = clk_id;
-       req->parent_id = parent_id;
+       if (clk_id < 255) {
+               req->clk_id = clk_id;
+       } else {
+               req->clk_id = 255;
+               req->clk_id_32 = clk_id;
+       }
+       if (parent_id < 255) {
+               req->parent_id = parent_id;
+       } else {
+               req->parent_id = 255;
+               req->parent_id_32 = parent_id;
+       }
 
        ret = ti_sci_do_xfer(info, xfer);
        if (ret) {
@@ -1262,7 +1282,7 @@ fail:
  * Return: 0 if all went well, else returns appropriate error value.
  */
 static int ti_sci_cmd_clk_get_parent(const struct ti_sci_handle *handle,
-                                    u32 dev_id, u8 clk_id, u8 *parent_id)
+                                    u32 dev_id, u32 clk_id, u32 *parent_id)
 {
        struct ti_sci_info *info;
        struct ti_sci_msg_req_get_clock_parent *req;
@@ -1289,7 +1309,12 @@ static int ti_sci_cmd_clk_get_parent(const struct ti_sci_handle *handle,
        }
        req = (struct ti_sci_msg_req_get_clock_parent *)xfer->xfer_buf;
        req->dev_id = dev_id;
-       req->clk_id = clk_id;
+       if (clk_id < 255) {
+               req->clk_id = clk_id;
+       } else {
+               req->clk_id = 255;
+               req->clk_id_32 = clk_id;
+       }
 
        ret = ti_sci_do_xfer(info, xfer);
        if (ret) {
@@ -1299,10 +1324,14 @@ static int ti_sci_cmd_clk_get_parent(const struct ti_sci_handle *handle,
 
        resp = (struct ti_sci_msg_resp_get_clock_parent *)xfer->xfer_buf;
 
-       if (!ti_sci_is_response_ack(resp))
+       if (!ti_sci_is_response_ack(resp)) {
                ret = -ENODEV;
-       else
-               *parent_id = resp->parent_id;
+       } else {
+               if (resp->parent_id < 255)
+                       *parent_id = resp->parent_id;
+               else
+                       *parent_id = resp->parent_id_32;
+       }
 
 fail:
        ti_sci_put_one_xfer(&info->minfo, xfer);
@@ -1322,8 +1351,8 @@ fail:
  * Return: 0 if all went well, else returns appropriate error value.
  */
 static int ti_sci_cmd_clk_get_num_parents(const struct ti_sci_handle *handle,
-                                         u32 dev_id, u8 clk_id,
-                                         u8 *num_parents)
+                                         u32 dev_id, u32 clk_id,
+                                         u32 *num_parents)
 {
        struct ti_sci_info *info;
        struct ti_sci_msg_req_get_clock_num_parents *req;
@@ -1350,7 +1379,12 @@ static int ti_sci_cmd_clk_get_num_parents(const struct ti_sci_handle *handle,
        }
        req = (struct ti_sci_msg_req_get_clock_num_parents *)xfer->xfer_buf;
        req->dev_id = dev_id;
-       req->clk_id = clk_id;
+       if (clk_id < 255) {
+               req->clk_id = clk_id;
+       } else {
+               req->clk_id = 255;
+               req->clk_id_32 = clk_id;
+       }
 
        ret = ti_sci_do_xfer(info, xfer);
        if (ret) {
@@ -1360,10 +1394,14 @@ static int ti_sci_cmd_clk_get_num_parents(const struct ti_sci_handle *handle,
 
        resp = (struct ti_sci_msg_resp_get_clock_num_parents *)xfer->xfer_buf;
 
-       if (!ti_sci_is_response_ack(resp))
+       if (!ti_sci_is_response_ack(resp)) {
                ret = -ENODEV;
-       else
-               *num_parents = resp->num_parents;
+       } else {
+               if (resp->num_parents < 255)
+                       *num_parents = resp->num_parents;
+               else
+                       *num_parents = resp->num_parents_32;
+       }
 
 fail:
        ti_sci_put_one_xfer(&info->minfo, xfer);
@@ -1391,7 +1429,7 @@ fail:
  * Return: 0 if all went well, else returns appropriate error value.
  */
 static int ti_sci_cmd_clk_get_match_freq(const struct ti_sci_handle *handle,
-                                        u32 dev_id, u8 clk_id, u64 min_freq,
+                                        u32 dev_id, u32 clk_id, u64 min_freq,
                                         u64 target_freq, u64 max_freq,
                                         u64 *match_freq)
 {
@@ -1420,7 +1458,12 @@ static int ti_sci_cmd_clk_get_match_freq(const struct ti_sci_handle *handle,
        }
        req = (struct ti_sci_msg_req_query_clock_freq *)xfer->xfer_buf;
        req->dev_id = dev_id;
-       req->clk_id = clk_id;
+       if (clk_id < 255) {
+               req->clk_id = clk_id;
+       } else {
+               req->clk_id = 255;
+               req->clk_id_32 = clk_id;
+       }
        req->min_freq_hz = min_freq;
        req->target_freq_hz = target_freq;
        req->max_freq_hz = max_freq;
@@ -1463,7 +1506,7 @@ fail:
  * Return: 0 if all went well, else returns appropriate error value.
  */
 static int ti_sci_cmd_clk_set_freq(const struct ti_sci_handle *handle,
-                                  u32 dev_id, u8 clk_id, u64 min_freq,
+                                  u32 dev_id, u32 clk_id, u64 min_freq,
                                   u64 target_freq, u64 max_freq)
 {
        struct ti_sci_info *info;
@@ -1491,7 +1534,12 @@ static int ti_sci_cmd_clk_set_freq(const struct ti_sci_handle *handle,
        }
        req = (struct ti_sci_msg_req_set_clock_freq *)xfer->xfer_buf;
        req->dev_id = dev_id;
-       req->clk_id = clk_id;
+       if (clk_id < 255) {
+               req->clk_id = clk_id;
+       } else {
+               req->clk_id = 255;
+               req->clk_id_32 = clk_id;
+       }
        req->min_freq_hz = min_freq;
        req->target_freq_hz = target_freq;
        req->max_freq_hz = max_freq;
@@ -1524,7 +1572,7 @@ fail:
  * Return: 0 if all went well, else returns appropriate error value.
  */
 static int ti_sci_cmd_clk_get_freq(const struct ti_sci_handle *handle,
-                                  u32 dev_id, u8 clk_id, u64 *freq)
+                                  u32 dev_id, u32 clk_id, u64 *freq)
 {
        struct ti_sci_info *info;
        struct ti_sci_msg_req_get_clock_freq *req;
@@ -1551,7 +1599,12 @@ static int ti_sci_cmd_clk_get_freq(const struct ti_sci_handle *handle,
        }
        req = (struct ti_sci_msg_req_get_clock_freq *)xfer->xfer_buf;
        req->dev_id = dev_id;
-       req->clk_id = clk_id;
+       if (clk_id < 255) {
+               req->clk_id = clk_id;
+       } else {
+               req->clk_id = 255;
+               req->clk_id_32 = clk_id;
+       }
 
        ret = ti_sci_do_xfer(info, xfer);
        if (ret) {
@@ -2349,12 +2402,13 @@ devm_ti_sci_get_of_resource(const struct ti_sci_handle *handle,
        if (!res)
                return ERR_PTR(-ENOMEM);
 
-       res->sets = of_property_count_elems_of_size(dev_of_node(dev), of_prop,
-                                                   sizeof(u32));
-       if (res->sets < 0) {
+       ret = of_property_count_elems_of_size(dev_of_node(dev), of_prop,
+                                             sizeof(u32));
+       if (ret < 0) {
                dev_err(dev, "%s resource type ids not available\n", of_prop);
-               return ERR_PTR(res->sets);
+               return ERR_PTR(ret);
        }
+       res->sets = ret;
 
        res->desc = devm_kcalloc(dev, res->sets, sizeof(*res->desc),
                                 GFP_KERNEL);
index adbeeef..414e0ce 100644 (file)
@@ -202,7 +202,8 @@ struct ti_sci_msg_req_set_device_resets {
  * @dev_id:    Device identifier this request is for
  * @clk_id:    Clock identifier for the device for this request.
  *             Each device has it's own set of clock inputs. This indexes
- *             which clock input to modify.
+ *             which clock input to modify. Set to 255 if clock ID is
+ *             greater than or equal to 255.
  * @request_state: Request the state for the clock to be set to.
  *             MSG_CLOCK_SW_STATE_UNREQ: The IP does not require this clock,
  *             it can be disabled, regardless of the state of the device
@@ -213,6 +214,9 @@ struct ti_sci_msg_req_set_device_resets {
  *             being required by the device.(default)
  *             MSG_CLOCK_SW_STATE_REQ:  Configure the clock to be enabled,
  *             regardless of the state of the device.
+ * @clk_id_32: Clock identifier for the device for this request.
+ *             Only to be used if the clock ID is greater than or equal to
+ *             255.
  *
  * Normally, all required clocks are managed by TISCI entity, this is used
  * only for specific control *IF* required. Auto managed state is
@@ -234,6 +238,7 @@ struct ti_sci_msg_req_set_clock_state {
 #define MSG_CLOCK_SW_STATE_AUTO                1
 #define MSG_CLOCK_SW_STATE_REQ         2
        u8 request_state;
+       u32 clk_id_32;
 } __packed;
 
 /**
@@ -242,7 +247,11 @@ struct ti_sci_msg_req_set_clock_state {
  * @dev_id:    Device identifier this request is for
  * @clk_id:    Clock identifier for the device for this request.
  *             Each device has it's own set of clock inputs. This indexes
- *             which clock input to get state of.
+ *             which clock input to get state of. Set to 255 if the clock
+ *             ID is greater than or equal to 255.
+ * @clk_id_32: Clock identifier for the device for the request.
+ *             Only to be used if the clock ID is greater than or equal to
+ *             255.
  *
  * Request type is TI_SCI_MSG_GET_CLOCK_STATE, response is state
  * of the clock
@@ -251,6 +260,7 @@ struct ti_sci_msg_req_get_clock_state {
        struct ti_sci_msg_hdr hdr;
        u32 dev_id;
        u8 clk_id;
+       u32 clk_id_32;
 } __packed;
 
 /**
@@ -278,9 +288,13 @@ struct ti_sci_msg_resp_get_clock_state {
  * @dev_id:    Device identifier this request is for
  * @clk_id:    Clock identifier for the device for this request.
  *             Each device has it's own set of clock inputs. This indexes
- *             which clock input to modify.
+ *             which clock input to modify. Set to 255 if clock ID is
+ *             greater than or equal to 255.
  * @parent_id: The new clock parent is selectable by an index via this
- *             parameter.
+ *             parameter. Set to 255 if clock ID is greater than or
+ *             equal to 255.
+ * @clk_id_32: Clock identifier if @clk_id field is 255.
+ * @parent_id_32:      Parent identifier if @parent_id is 255.
  *
  * Request type is TI_SCI_MSG_SET_CLOCK_PARENT, response is generic
  * ACK / NACK message.
@@ -290,6 +304,8 @@ struct ti_sci_msg_req_set_clock_parent {
        u32 dev_id;
        u8 clk_id;
        u8 parent_id;
+       u32 clk_id_32;
+       u32 parent_id_32;
 } __packed;
 
 /**
@@ -298,7 +314,10 @@ struct ti_sci_msg_req_set_clock_parent {
  * @dev_id:    Device identifier this request is for
  * @clk_id:    Clock identifier for the device for this request.
  *             Each device has it's own set of clock inputs. This indexes
- *             which clock input to get the parent for.
+ *             which clock input to get the parent for. If this field
+ *             contains 255, the actual clock identifier is stored in
+ *             @clk_id_32.
+ * @clk_id_32: Clock identifier if the @clk_id field contains 255.
  *
  * Request type is TI_SCI_MSG_GET_CLOCK_PARENT, response is parent information
  */
@@ -306,25 +325,32 @@ struct ti_sci_msg_req_get_clock_parent {
        struct ti_sci_msg_hdr hdr;
        u32 dev_id;
        u8 clk_id;
+       u32 clk_id_32;
 } __packed;
 
 /**
  * struct ti_sci_msg_resp_get_clock_parent - Response with clock parent
  * @hdr:       Generic Header
- * @parent_id: The current clock parent
+ * @parent_id: The current clock parent. If set to 255, the current parent
+ *             ID can be found from the @parent_id_32 field.
+ * @parent_id_32:      Current clock parent if @parent_id field is set to
+ *                     255.
  *
  * Response to TI_SCI_MSG_GET_CLOCK_PARENT.
  */
 struct ti_sci_msg_resp_get_clock_parent {
        struct ti_sci_msg_hdr hdr;
        u8 parent_id;
+       u32 parent_id_32;
 } __packed;
 
 /**
  * struct ti_sci_msg_req_get_clock_num_parents - Request to get clock parents
  * @hdr:       Generic header
  * @dev_id:    Device identifier this request is for
- * @clk_id:    Clock identifier for the device for this request.
+ * @clk_id:    Clock identifier for the device for this request. Set to
+ *             255 if clock ID is greater than or equal to 255.
+ * @clk_id_32: Clock identifier if the @clk_id field contains 255.
  *
  * This request provides information about how many clock parent options
  * are available for a given clock to a device. This is typically used
@@ -337,18 +363,24 @@ struct ti_sci_msg_req_get_clock_num_parents {
        struct ti_sci_msg_hdr hdr;
        u32 dev_id;
        u8 clk_id;
+       u32 clk_id_32;
 } __packed;
 
 /**
  * struct ti_sci_msg_resp_get_clock_num_parents - Response for get clk parents
  * @hdr:               Generic header
- * @num_parents:       Number of clock parents
+ * @num_parents:       Number of clock parents. If set to 255, the actual
+ *                     number of parents is stored into @num_parents_32
+ *                     field instead.
+ * @num_parents_32:    Number of clock parents if @num_parents field is
+ *                     set to 255.
  *
  * Response to TI_SCI_MSG_GET_NUM_CLOCK_PARENTS
  */
 struct ti_sci_msg_resp_get_clock_num_parents {
        struct ti_sci_msg_hdr hdr;
        u8 num_parents;
+       u32 num_parents_32;
 } __packed;
 
 /**
@@ -363,7 +395,9 @@ struct ti_sci_msg_resp_get_clock_num_parents {
  * @max_freq_hz: The maximum allowable frequency in Hz. This is the maximum
  *             allowable programmed frequency and does not account for clock
  *             tolerances and jitter.
- * @clk_id:    Clock identifier for the device for this request.
+ * @clk_id:    Clock identifier for the device for this request. Set to
+ *             255 if clock identifier is greater than or equal to 255.
+ * @clk_id_32: Clock identifier if @clk_id is set to 255.
  *
  * NOTE: Normally clock frequency management is automatically done by TISCI
  * entity. In case of specific requests, TISCI evaluates capability to achieve
@@ -380,6 +414,7 @@ struct ti_sci_msg_req_query_clock_freq {
        u64 target_freq_hz;
        u64 max_freq_hz;
        u8 clk_id;
+       u32 clk_id_32;
 } __packed;
 
 /**
@@ -407,7 +442,9 @@ struct ti_sci_msg_resp_query_clock_freq {
  * @max_freq_hz: The maximum allowable frequency in Hz. This is the maximum
  *             allowable programmed frequency and does not account for clock
  *             tolerances and jitter.
- * @clk_id:    Clock identifier for the device for this request.
+ * @clk_id:    Clock identifier for the device for this request. Set to
+ *             255 if clock ID is greater than or equal to 255.
+ * @clk_id_32: Clock identifier if @clk_id field is set to 255.
  *
  * NOTE: Normally clock frequency management is automatically done by TISCI
  * entity. In case of specific requests, TISCI evaluates capability to achieve
@@ -436,13 +473,16 @@ struct ti_sci_msg_req_set_clock_freq {
        u64 target_freq_hz;
        u64 max_freq_hz;
        u8 clk_id;
+       u32 clk_id_32;
 } __packed;
 
 /**
  * struct ti_sci_msg_req_get_clock_freq - Request to get the clock frequency
  * @hdr:       Generic Header
  * @dev_id:    Device identifier this request is for
- * @clk_id:    Clock identifier for the device for this request.
+ * @clk_id:    Clock identifier for the device for this request. Set to
+ *             255 if clock ID is greater than or equal to 255.
+ * @clk_id_32: Clock identifier if @clk_id field is set to 255.
  *
  * NOTE: Normally clock frequency management is automatically done by TISCI
  * entity. In some cases, clock frequencies are configured by host.
@@ -454,6 +494,7 @@ struct ti_sci_msg_req_get_clock_freq {
        struct ti_sci_msg_hdr hdr;
        u32 dev_id;
        u8 clk_id;
+       u32 clk_id_32;
 } __packed;
 
 /**
index a0439ce..88ec396 100644 (file)
 #define CLK_MIPI_HSI           349 /* Exynos4210 only */
 #define CLK_PIXELASYNCM0       351
 #define CLK_PIXELASYNCM1       352
+#define CLK_ASYNC_G3D          353 /* Exynos4x12 only */
 #define CLK_PWM_ISP_SCLK       379 /* Exynos4x12 only */
 #define CLK_SPI0_ISP_SCLK      380 /* Exynos4x12 only */
 #define CLK_SPI1_ISP_SCLK      381 /* Exynos4x12 only */
index 355f469..02d5ac4 100644 (file)
@@ -60,6 +60,7 @@
 #define CLK_MAU_EPLL           159
 #define CLK_SCLK_HSIC_12M      160
 #define CLK_SCLK_MPHY_IXTAL24  161
+#define CLK_SCLK_BPLL          162
 
 /* gate clocks */
 #define CLK_UART0              257
 #define CLK_ACLK432_CAM                518
 #define CLK_ACLK_FL1550_CAM    519
 #define CLK_ACLK550_CAM                520
+#define CLK_CLKM_PHY0          521
+#define CLK_CLKM_PHY1          522
+#define CLK_ACLK_PPMU_DREX0_0  523
+#define CLK_ACLK_PPMU_DREX0_1  524
+#define CLK_ACLK_PPMU_DREX1_0  525
+#define CLK_ACLK_PPMU_DREX1_1  526
+#define CLK_PCLK_PPMU_DREX0_0  527
+#define CLK_PCLK_PPMU_DREX0_1  528
+#define CLK_PCLK_PPMU_DREX1_0  529
+#define CLK_PCLK_PPMU_DREX1_1  530
 
 /* mux clocks */
 #define CLK_MOUT_HDMI          640
 #define CLK_MOUT_EPLL          657
 #define CLK_MOUT_MAU_EPLL      658
 #define CLK_MOUT_USER_MAU_EPLL 659
+#define CLK_MOUT_SCLK_SPLL     660
+#define CLK_MOUT_MX_MSPLL_CCORE_PHY    661
 
 /* divider clocks */
 #define CLK_DOUT_PIXEL         768
 #define CLK_DOUT_CCLK_DREX0    794
 #define CLK_DOUT_CLK2X_PHY0    795
 #define CLK_DOUT_PCLK_CORE_MEM 796
+#define CLK_FF_DOUT_SPLL2      797
+#define CLK_DOUT_PCLK_DREX0    798
+#define CLK_DOUT_PCLK_DREX1    799
 
 /* must be greater than maximal clock id */
-#define CLK_NR_CLKS            797
+#define CLK_NR_CLKS            800
 
 #endif /* _DT_BINDINGS_CLOCK_EXYNOS_5420_H */
index e10470e..b6b127e 100644 (file)
 #define CLKID_VDEC_1                           204
 #define CLKID_VDEC_HEVC                                207
 #define CLKID_VDEC_HEVCF                       210
+#define CLKID_TS                               212
 
 #endif /* __G12A_CLKC_H */
index 1b4353e..07e6c68 100644 (file)
 
 #define IMX8MM_CLK_NAND_USDHC_BUS_RAWNAND_CLK  222
 
-#define IMX8MM_CLK_END                         223
+#define IMX8MM_CLK_GPIO1_ROOT                  223
+#define IMX8MM_CLK_GPIO2_ROOT                  224
+#define IMX8MM_CLK_GPIO3_ROOT                  225
+#define IMX8MM_CLK_GPIO4_ROOT                  226
+#define IMX8MM_CLK_GPIO5_ROOT                  227
+
+#define IMX8MM_CLK_SNVS_ROOT                   228
+#define IMX8MM_CLK_GIC                         229
+
+#define IMX8MM_CLK_END                         230
 
 #endif
index 6677e92..6546367 100644 (file)
 #define IMX8MQ_CLK_GPIO4_ROOT                  262
 #define IMX8MQ_CLK_GPIO5_ROOT                  263
 
-#define IMX8MQ_CLK_END                         264
+#define IMX8MQ_CLK_SNVS_ROOT                   264
+#define IMX8MQ_CLK_GIC                         265
+
+#define IMX8MQ_CLK_END                         266
 #endif /* __DT_BINDINGS_CLOCK_IMX8MQ_H */
index 4755653..68862aa 100644 (file)
 #define CLKID_VDEC_HCODEC      199
 #define CLKID_VDEC_2           202
 #define CLKID_VDEC_HEVC                206
+#define CLKID_CTS_AMCLK                209
+#define CLKID_CTS_MCLK_I958    212
+#define CLKID_CTS_I958         213
 
 #endif /* __MESON8B_CLKC_H */
index 9cfca53..816447b 100644 (file)
 #define CLK_TOP_MSDC2_INFRA            176
 #define CLK_TOP_NR_CLK                 177
 
+/* AUDSYS */
+
+#define CLK_AUD_AFE                    0
+#define CLK_AUD_I2S                    1
+#define CLK_AUD_22M                    2
+#define CLK_AUD_24M                    3
+#define CLK_AUD_INTDIR                 4
+#define CLK_AUD_APLL2_TUNER            5
+#define CLK_AUD_APLL_TUNER             6
+#define CLK_AUD_HDMI                   7
+#define CLK_AUD_SPDF                   8
+#define CLK_AUD_ADC                    9
+#define CLK_AUD_DAC                    10
+#define CLK_AUD_DAC_PREDIS             11
+#define CLK_AUD_TML                    12
+#define CLK_AUD_NR_CLK                 13
+
 #endif /* _DT_BINDINGS_CLK_MT8516_H */
index 454b3f4..2cd62c9 100644 (file)
 #define GCC_PCIEPHY_0_PHY_BCR                          12
 #define GCC_EMAC_BCR                                   13
 #define GCC_CDSP_RESTART                               14
+#define GCC_PCIE_0_AXI_MASTER_STICKY_ARES              15
+#define GCC_PCIE_0_AHB_ARES                            16
+#define GCC_PCIE_0_AXI_SLAVE_ARES                      17
+#define GCC_PCIE_0_AXI_MASTER_ARES                     18
+#define GCC_PCIE_0_CORE_STICKY_ARES                    19
+#define GCC_PCIE_0_SLEEP_ARES                          20
+#define GCC_PCIE_0_PIPE_ARES                           21
 
 #endif
diff --git a/include/dt-bindings/clock/qcom,gpucc-msm8998.h b/include/dt-bindings/clock/qcom,gpucc-msm8998.h
new file mode 100644 (file)
index 0000000..2623570
--- /dev/null
@@ -0,0 +1,29 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * Copyright (c) 2019, Jeffrey Hugo
+ */
+
+#ifndef _DT_BINDINGS_CLK_MSM_GPUCC_8998_H
+#define _DT_BINDINGS_CLK_MSM_GPUCC_8998_H
+
+#define GPUPLL0                                                0
+#define GPUPLL0_OUT_EVEN                               1
+#define RBCPR_CLK_SRC                                  2
+#define GFX3D_CLK_SRC                                  3
+#define RBBMTIMER_CLK_SRC                              4
+#define GFX3D_ISENSE_CLK_SRC                           5
+#define RBCPR_CLK                                      6
+#define GFX3D_CLK                                      7
+#define RBBMTIMER_CLK                                  8
+#define GFX3D_ISENSE_CLK                               9
+#define GPUCC_CXO_CLK                                  10
+
+#define GPU_CX_BCR                                     0
+#define RBCPR_BCR                                      1
+#define GPU_GX_BCR                                     2
+#define GPU_ISENSE_BCR                                 3
+
+#define GPU_CX_GDSC                                    1
+#define GPU_GX_GDSC                                    2
+
+#endif
index 3b245e3..de550ea 100644 (file)
@@ -64,6 +64,7 @@
 #define SCLK_WIFI              141
 #define SCLK_OTGPHY0           142
 #define SCLK_OTGPHY1           143
+#define SCLK_HDMI_PHY          144
 
 /* dclk gates */
 #define DCLK_VOP               190
index afb8113..555b4ff 100644 (file)
 #define PCLK_DCF               233
 #define PCLK_SARADC            234
 #define PCLK_ACODECPHY         235
+#define PCLK_WDT               236
 
 /* hclk gates */
 #define HCLK_PERI              308
index 0ac1c90..08b98e2 100644 (file)
@@ -79,6 +79,8 @@
 #define STRATIX10_USB_CLK              59
 #define STRATIX10_SPI_M_CLK            60
 #define STRATIX10_NAND_CLK             61
-#define STRATIX10_NUM_CLKS             62
+#define STRATIX10_NAND_X_CLK           62
+#define STRATIX10_NAND_ECC_CLK         63
+#define STRATIX10_NUM_CLKS             64
 
 #endif /* __STRATIX10_CLOCK_H */
index bb6118f..2ae7604 100644 (file)
@@ -9,8 +9,6 @@
 #include <linux/of.h>
 #include <linux/of_clk.h>
 
-#ifdef CONFIG_COMMON_CLK
-
 /*
  * flags used across common struct clk.  these flags should only affect the
  * top-level framework.  custom flags for dealing with hardware specifics
@@ -807,7 +805,14 @@ void devm_clk_hw_unregister(struct device *dev, struct clk_hw *hw);
 /* helper functions */
 const char *__clk_get_name(const struct clk *clk);
 const char *clk_hw_get_name(const struct clk_hw *hw);
+#ifdef CONFIG_COMMON_CLK
 struct clk_hw *__clk_get_hw(struct clk *clk);
+#else
+static inline struct clk_hw *__clk_get_hw(struct clk *clk)
+{
+       return (struct clk_hw *)clk;
+}
+#endif
 unsigned int clk_hw_get_num_parents(const struct clk_hw *hw);
 struct clk_hw *clk_hw_get_parent(const struct clk_hw *hw);
 struct clk_hw *clk_hw_get_parent_by_index(const struct clk_hw *hw,
@@ -867,8 +872,6 @@ static inline long divider_ro_round_rate(struct clk_hw *hw, unsigned long rate,
  */
 unsigned long clk_hw_round_rate(struct clk_hw *hw, unsigned long rate);
 
-struct of_device_id;
-
 struct clk_onecell_data {
        struct clk **clks;
        unsigned int clk_num;
@@ -879,8 +882,6 @@ struct clk_hw_onecell_data {
        struct clk_hw *hws[];
 };
 
-extern struct of_device_id __clk_of_table;
-
 #define CLK_OF_DECLARE(name, compat, fn) OF_DECLARE_1(clk, name, compat, fn)
 
 /*
@@ -904,6 +905,40 @@ extern struct of_device_id __clk_of_table;
                .ops            = _ops,                         \
        })
 
+#define CLK_HW_INIT_HW(_name, _parent, _ops, _flags)                   \
+       (&(struct clk_init_data) {                                      \
+               .flags          = _flags,                               \
+               .name           = _name,                                \
+               .parent_hws     = (const struct clk_hw*[]) { _parent }, \
+               .num_parents    = 1,                                    \
+               .ops            = _ops,                                 \
+       })
+
+/*
+ * This macro is intended for drivers to be able to share the otherwise
+ * individual struct clk_hw[] compound literals created by the compiler
+ * when using CLK_HW_INIT_HW. It does NOT support multiple parents.
+ */
+#define CLK_HW_INIT_HWS(_name, _parent, _ops, _flags)                  \
+       (&(struct clk_init_data) {                                      \
+               .flags          = _flags,                               \
+               .name           = _name,                                \
+               .parent_hws     = _parent,                              \
+               .num_parents    = 1,                                    \
+               .ops            = _ops,                                 \
+       })
+
+#define CLK_HW_INIT_FW_NAME(_name, _parent, _ops, _flags)              \
+       (&(struct clk_init_data) {                                      \
+               .flags          = _flags,                               \
+               .name           = _name,                                \
+               .parent_data    = (const struct clk_parent_data[]) {    \
+                                       { .fw_name = _parent },         \
+                                 },                                    \
+               .num_parents    = 1,                                    \
+               .ops            = _ops,                                 \
+       })
+
 #define CLK_HW_INIT_PARENTS(_name, _parents, _ops, _flags)     \
        (&(struct clk_init_data) {                              \
                .flags          = _flags,                       \
@@ -913,6 +948,24 @@ extern struct of_device_id __clk_of_table;
                .ops            = _ops,                         \
        })
 
+#define CLK_HW_INIT_PARENTS_HW(_name, _parents, _ops, _flags)  \
+       (&(struct clk_init_data) {                              \
+               .flags          = _flags,                       \
+               .name           = _name,                        \
+               .parent_hws     = _parents,                     \
+               .num_parents    = ARRAY_SIZE(_parents),         \
+               .ops            = _ops,                         \
+       })
+
+#define CLK_HW_INIT_PARENTS_DATA(_name, _parents, _ops, _flags)        \
+       (&(struct clk_init_data) {                              \
+               .flags          = _flags,                       \
+               .name           = _name,                        \
+               .parent_data    = _parents,                     \
+               .num_parents    = ARRAY_SIZE(_parents),         \
+               .ops            = _ops,                         \
+       })
+
 #define CLK_HW_INIT_NO_PARENT(_name, _ops, _flags)     \
        (&(struct clk_init_data) {                      \
                .flags          = _flags,               \
@@ -933,6 +986,43 @@ extern struct of_device_id __clk_of_table;
                                              _flags),                  \
        }
 
+#define CLK_FIXED_FACTOR_HW(_struct, _name, _parent,                   \
+                           _div, _mult, _flags)                        \
+       struct clk_fixed_factor _struct = {                             \
+               .div            = _div,                                 \
+               .mult           = _mult,                                \
+               .hw.init        = CLK_HW_INIT_HW(_name,                 \
+                                                _parent,               \
+                                                &clk_fixed_factor_ops, \
+                                                _flags),               \
+       }
+
+/*
+ * This macro allows the driver to reuse the _parent array for multiple
+ * fixed factor clk declarations.
+ */
+#define CLK_FIXED_FACTOR_HWS(_struct, _name, _parent,                  \
+                            _div, _mult, _flags)                       \
+       struct clk_fixed_factor _struct = {                             \
+               .div            = _div,                                 \
+               .mult           = _mult,                                \
+               .hw.init        = CLK_HW_INIT_HWS(_name,                \
+                                                 _parent,              \
+                                                 &clk_fixed_factor_ops, \
+                                                 _flags),      \
+       }
+
+#define CLK_FIXED_FACTOR_FW_NAME(_struct, _name, _parent,              \
+                                _div, _mult, _flags)                   \
+       struct clk_fixed_factor _struct = {                             \
+               .div            = _div,                                 \
+               .mult           = _mult,                                \
+               .hw.init        = CLK_HW_INIT_FW_NAME(_name,            \
+                                                     _parent,          \
+                                                     &clk_fixed_factor_ops, \
+                                                     _flags),          \
+       }
+
 #ifdef CONFIG_OF
 int of_clk_add_provider(struct device_node *np,
                        struct clk *(*clk_src_get)(struct of_phandle_args *args,
@@ -1019,5 +1109,4 @@ static inline int of_clk_detect_critical(struct device_node *np, int index,
 
 void clk_gate_restore_context(struct clk_hw *hw);
 
-#endif /* CONFIG_COMMON_CLK */
 #endif /* CLK_PROVIDER_H */
index c8e3325..3c096c7 100644 (file)
@@ -329,6 +329,19 @@ int __must_check clk_bulk_get(struct device *dev, int num_clks,
  */
 int __must_check clk_bulk_get_all(struct device *dev,
                                  struct clk_bulk_data **clks);
+
+/**
+ * clk_bulk_get_optional - lookup and obtain a number of references to clock producer
+ * @dev: device for clock "consumer"
+ * @num_clks: the number of clk_bulk_data
+ * @clks: the clk_bulk_data table of consumer
+ *
+ * Behaves the same as clk_bulk_get() except where there is no clock producer.
+ * In this case, instead of returning -ENOENT, the function returns 0 and
+ * NULL for a clk for which a clock producer could not be determined.
+ */
+int __must_check clk_bulk_get_optional(struct device *dev, int num_clks,
+                                      struct clk_bulk_data *clks);
 /**
  * devm_clk_bulk_get - managed get multiple clk consumers
  * @dev: device for clock "consumer"
@@ -344,6 +357,28 @@ int __must_check clk_bulk_get_all(struct device *dev,
 int __must_check devm_clk_bulk_get(struct device *dev, int num_clks,
                                   struct clk_bulk_data *clks);
 /**
+ * devm_clk_bulk_get_optional - managed get multiple optional consumer clocks
+ * @dev: device for clock "consumer"
+ * @clks: pointer to the clk_bulk_data table of consumer
+ *
+ * Behaves the same as devm_clk_bulk_get() except where there is no clock
+ * producer.  In this case, instead of returning -ENOENT, the function returns
+ * NULL for given clk. It is assumed all clocks in clk_bulk_data are optional.
+ *
+ * Returns 0 if all clocks specified in clk_bulk_data table are obtained
+ * successfully or for any clk there was no clk provider available, otherwise
+ * returns valid IS_ERR() condition containing errno.
+ * The implementation uses @dev and @clk_bulk_data.id to determine the
+ * clock consumer, and thereby the clock producer.
+ * The clock returned is stored in each @clk_bulk_data.clk field.
+ *
+ * Drivers must assume that the clock source is not enabled.
+ *
+ * clk_bulk_get should not be called from within interrupt context.
+ */
+int __must_check devm_clk_bulk_get_optional(struct device *dev, int num_clks,
+                                           struct clk_bulk_data *clks);
+/**
  * devm_clk_bulk_get_all - managed get multiple clk consumers
  * @dev: device for clock "consumer"
  * @clks: pointer to the clk_bulk_data table of consumer
@@ -715,6 +750,12 @@ static inline int __must_check clk_bulk_get(struct device *dev, int num_clks,
        return 0;
 }
 
+static inline int __must_check clk_bulk_get_optional(struct device *dev,
+                               int num_clks, struct clk_bulk_data *clks)
+{
+       return 0;
+}
+
 static inline int __must_check clk_bulk_get_all(struct device *dev,
                                         struct clk_bulk_data **clks)
 {
@@ -738,6 +779,12 @@ static inline int __must_check devm_clk_bulk_get(struct device *dev, int num_clk
        return 0;
 }
 
+static inline int __must_check devm_clk_bulk_get_optional(struct device *dev,
+                               int num_clks, struct clk_bulk_data *clks)
+{
+       return 0;
+}
+
 static inline int __must_check devm_clk_bulk_get_all(struct device *dev,
                                                     struct clk_bulk_data **clks)
 {
index 568722a..406e671 100644 (file)
@@ -166,29 +166,29 @@ struct ti_sci_dev_ops {
  * managed by driver for that purpose.
  */
 struct ti_sci_clk_ops {
-       int (*get_clock)(const struct ti_sci_handle *handle, u32 did, u8 cid,
+       int (*get_clock)(const struct ti_sci_handle *handle, u32 did, u32 cid,
                         bool needs_ssc, bool can_change_freq,
                         bool enable_input_term);
-       int (*idle_clock)(const struct ti_sci_handle *handle, u32 did, u8 cid);
-       int (*put_clock)(const struct ti_sci_handle *handle, u32 did, u8 cid);
-       int (*is_auto)(const struct ti_sci_handle *handle, u32 did, u8 cid,
+       int (*idle_clock)(const struct ti_sci_handle *handle, u32 did, u32 cid);
+       int (*put_clock)(const struct ti_sci_handle *handle, u32 did, u32 cid);
+       int (*is_auto)(const struct ti_sci_handle *handle, u32 did, u32 cid,
                       bool *req_state);
-       int (*is_on)(const struct ti_sci_handle *handle, u32 did, u8 cid,
+       int (*is_on)(const struct ti_sci_handle *handle, u32 did, u32 cid,
                     bool *req_state, bool *current_state);
-       int (*is_off)(const struct ti_sci_handle *handle, u32 did, u8 cid,
+       int (*is_off)(const struct ti_sci_handle *handle, u32 did, u32 cid,
                      bool *req_state, bool *current_state);
-       int (*set_parent)(const struct ti_sci_handle *handle, u32 did, u8 cid,
-                         u8 parent_id);
-       int (*get_parent)(const struct ti_sci_handle *handle, u32 did, u8 cid,
-                         u8 *parent_id);
+       int (*set_parent)(const struct ti_sci_handle *handle, u32 did, u32 cid,
+                         u32 parent_id);
+       int (*get_parent)(const struct ti_sci_handle *handle, u32 did, u32 cid,
+                         u32 *parent_id);
        int (*get_num_parents)(const struct ti_sci_handle *handle, u32 did,
-                              u8 cid, u8 *num_parents);
+                              u32 cid, u32 *num_parents);
        int (*get_best_match_freq)(const struct ti_sci_handle *handle, u32 did,
-                                  u8 cid, u64 min_freq, u64 target_freq,
+                                  u32 cid, u64 min_freq, u64 target_freq,
                                   u64 max_freq, u64 *match_freq);
-       int (*set_freq)(const struct ti_sci_handle *handle, u32 did, u8 cid,
+       int (*set_freq)(const struct ti_sci_handle *handle, u32 did, u32 cid,
                        u64 min_freq, u64 target_freq, u64 max_freq);
-       int (*get_freq)(const struct ti_sci_handle *handle, u32 did, u8 cid,
+       int (*get_freq)(const struct ti_sci_handle *handle, u32 did, u32 cid,
                        u64 *current_freq);
 };