Merge tag 'clk-for-linus-4.2' of git://git.kernel.org/pub/scm/linux/kernel/git/clk...
authorLinus Torvalds <torvalds@linux-foundation.org>
Thu, 2 Jul 2015 02:22:00 +0000 (19:22 -0700)
committerLinus Torvalds <torvalds@linux-foundation.org>
Thu, 2 Jul 2015 02:22:00 +0000 (19:22 -0700)
Pull clock framework updates from Michael Turquette:
 "The changes to the common clock framework for 4.2 are dominated by new
  drivers and updates to existing ones, as usual.

  There are some fixes to the framework itself and several cleanups for
  sparse warnings, etc"

* tag 'clk-for-linus-4.2' of git://git.kernel.org/pub/scm/linux/kernel/git/clk/linux: (135 commits)
  clk: stm32: Add clock driver for STM32F4[23]xxx devices
  dt-bindings: Document the STM32F4 clock bindings
  cpufreq: exynos: remove Exynos4210 specific cpufreq driver support
  ARM: Exynos: switch to using generic cpufreq driver for Exynos4210
  clk: samsung: exynos4: add cpu clock configuration data and instantiate cpu clock
  clk: samsung: add infrastructure to register cpu clocks
  clk: add CLK_RECALC_NEW_RATES clock flag for Exynos cpu clock support
  doc: dt: add documentation for lpc1850-ccu clk driver
  clk: add lpc18xx ccu clk driver
  doc: dt: add documentation for lpc1850-cgu clk driver
  clk: add lpc18xx cgu clk driver
  clk: keystone: add support for post divider register for main pll
  clk: mvebu: flag the crypto clk as CLK_IGNORE_UNUSED
  clk: cygnus: remove Cygnus dummy clock binding
  clk: cygnus: add clock support for Broadcom Cygnus
  clk: Change bcm clocks build dependency
  clk: iproc: add initial common clock support
  clk: iproc: define Broadcom iProc clock binding
  MAINTAINERS: update email for Michael Turquette
  clk: meson: add some error handling in meson_clk_register_cpu()
  ...

182 files changed:
Documentation/clk.txt
Documentation/devicetree/bindings/arm/mediatek/mediatek,apmixedsys.txt [new file with mode: 0644]
Documentation/devicetree/bindings/arm/mediatek/mediatek,infracfg.txt [new file with mode: 0644]
Documentation/devicetree/bindings/arm/mediatek/mediatek,pericfg.txt [new file with mode: 0644]
Documentation/devicetree/bindings/arm/mediatek/mediatek,topckgen.txt [new file with mode: 0644]
Documentation/devicetree/bindings/clock/amlogic,meson8b-clkc.txt [new file with mode: 0644]
Documentation/devicetree/bindings/clock/bcm-cygnus-clock.txt [deleted file]
Documentation/devicetree/bindings/clock/brcm,iproc-clocks.txt [new file with mode: 0644]
Documentation/devicetree/bindings/clock/clock-bindings.txt
Documentation/devicetree/bindings/clock/csr,atlas7-car.txt [new file with mode: 0644]
Documentation/devicetree/bindings/clock/emev2-clock.txt
Documentation/devicetree/bindings/clock/keystone-pll.txt
Documentation/devicetree/bindings/clock/lpc1850-ccu.txt [new file with mode: 0644]
Documentation/devicetree/bindings/clock/lpc1850-cgu.txt [new file with mode: 0644]
Documentation/devicetree/bindings/clock/marvell,pxa1928.txt [new file with mode: 0644]
Documentation/devicetree/bindings/clock/mvebu-gated-clock.txt
Documentation/devicetree/bindings/clock/nvidia,tegra124-car.txt
Documentation/devicetree/bindings/clock/renesas,cpg-div6-clocks.txt
Documentation/devicetree/bindings/clock/renesas,cpg-mstp-clocks.txt
Documentation/devicetree/bindings/clock/renesas,rcar-gen2-cpg-clocks.txt
Documentation/devicetree/bindings/clock/renesas,rz-cpg-clocks.txt
Documentation/devicetree/bindings/clock/st,stm32-rcc.txt [new file with mode: 0644]
Documentation/devicetree/bindings/clock/sunxi.txt
Documentation/devicetree/bindings/clock/ti,cdce925.txt [new file with mode: 0644]
MAINTAINERS
arch/arm/boot/dts/atlas7.dtsi
arch/arm/mach-exynos/exynos.c
drivers/clk/Kconfig
drivers/clk/Makefile
drivers/clk/at91/clk-main.c
drivers/clk/at91/clk-master.c
drivers/clk/at91/clk-programmable.c
drivers/clk/at91/clk-slow.c
drivers/clk/at91/clk-smd.c
drivers/clk/at91/clk-usb.c
drivers/clk/at91/pmc.c
drivers/clk/bcm/Kconfig
drivers/clk/bcm/Makefile
drivers/clk/bcm/clk-cygnus.c [new file with mode: 0644]
drivers/clk/bcm/clk-iproc-armpll.c [new file with mode: 0644]
drivers/clk/bcm/clk-iproc-asiu.c [new file with mode: 0644]
drivers/clk/bcm/clk-iproc-pll.c [new file with mode: 0644]
drivers/clk/bcm/clk-iproc.h [new file with mode: 0644]
drivers/clk/bcm/clk-kona-setup.c
drivers/clk/bcm/clk-kona.c
drivers/clk/bcm/clk-kona.h
drivers/clk/berlin/berlin2-pll.c
drivers/clk/clk-asm9260.c
drivers/clk/clk-axm5516.c
drivers/clk/clk-cdce706.c
drivers/clk/clk-cdce925.c [new file with mode: 0644]
drivers/clk/clk-composite.c
drivers/clk/clk-conf.c
drivers/clk/clk-divider.c
drivers/clk/clk-fixed-factor.c
drivers/clk/clk-fixed-rate.c
drivers/clk/clk-fractional-divider.c
drivers/clk/clk-gate.c
drivers/clk/clk-gpio-gate.c
drivers/clk/clk-ls1x.c
drivers/clk/clk-max-gen.c
drivers/clk/clk-moxart.c
drivers/clk/clk-mux.c
drivers/clk/clk-si5351.c
drivers/clk/clk-stm32f4.c [new file with mode: 0644]
drivers/clk/clk-u300.c
drivers/clk/clk-xgene.c
drivers/clk/clk.c
drivers/clk/hisilicon/Kconfig [new file with mode: 0644]
drivers/clk/hisilicon/Makefile
drivers/clk/hisilicon/clk-hi3620.c
drivers/clk/hisilicon/clk-hi6220.c [new file with mode: 0644]
drivers/clk/hisilicon/clk-hix5hd2.c
drivers/clk/hisilicon/clk.c
drivers/clk/hisilicon/clk.h
drivers/clk/hisilicon/clkdivider-hi6220.c [new file with mode: 0644]
drivers/clk/keystone/pll.c
drivers/clk/mediatek/Makefile [new file with mode: 0644]
drivers/clk/mediatek/clk-gate.c [new file with mode: 0644]
drivers/clk/mediatek/clk-gate.h [new file with mode: 0644]
drivers/clk/mediatek/clk-mt8135.c [new file with mode: 0644]
drivers/clk/mediatek/clk-mt8173.c [new file with mode: 0644]
drivers/clk/mediatek/clk-mtk.c [new file with mode: 0644]
drivers/clk/mediatek/clk-mtk.h [new file with mode: 0644]
drivers/clk/mediatek/clk-pll.c [new file with mode: 0644]
drivers/clk/mediatek/reset.c [new file with mode: 0644]
drivers/clk/meson/Makefile [new file with mode: 0644]
drivers/clk/meson/clk-cpu.c [new file with mode: 0644]
drivers/clk/meson/clk-pll.c [new file with mode: 0644]
drivers/clk/meson/clkc.c [new file with mode: 0644]
drivers/clk/meson/clkc.h [new file with mode: 0644]
drivers/clk/meson/meson8b-clkc.c [new file with mode: 0644]
drivers/clk/mmp/Makefile
drivers/clk/mmp/clk-apbc.c
drivers/clk/mmp/clk-apmu.c
drivers/clk/mmp/clk-mmp2.c
drivers/clk/mmp/clk-of-mmp2.c
drivers/clk/mmp/clk-of-pxa168.c
drivers/clk/mmp/clk-of-pxa1928.c [new file with mode: 0644]
drivers/clk/mmp/clk-of-pxa910.c
drivers/clk/mvebu/armada-370.c
drivers/clk/mxs/clk-imx23.c
drivers/clk/mxs/clk-imx28.c
drivers/clk/mxs/clk.h
drivers/clk/nxp/Makefile [new file with mode: 0644]
drivers/clk/nxp/clk-lpc18xx-ccu.c [new file with mode: 0644]
drivers/clk/nxp/clk-lpc18xx-cgu.c [new file with mode: 0644]
drivers/clk/pistachio/clk-pll.c
drivers/clk/pxa/clk-pxa.h
drivers/clk/rockchip/clk-cpu.c
drivers/clk/rockchip/clk-mmc-phase.c
drivers/clk/rockchip/clk-pll.c
drivers/clk/rockchip/clk-rk3188.c
drivers/clk/rockchip/clk-rk3288.c
drivers/clk/rockchip/clk.c
drivers/clk/rockchip/clk.h
drivers/clk/samsung/Makefile
drivers/clk/samsung/clk-cpu.c [new file with mode: 0644]
drivers/clk/samsung/clk-cpu.h [new file with mode: 0644]
drivers/clk/samsung/clk-exynos4.c
drivers/clk/samsung/clk-exynos5260.c
drivers/clk/samsung/clk-exynos5420.c
drivers/clk/samsung/clk-exynos5433.c
drivers/clk/samsung/clk-pll.c
drivers/clk/samsung/clk-s3c2410-dclk.c
drivers/clk/samsung/clk-s5pv210.c
drivers/clk/samsung/clk.c
drivers/clk/samsung/clk.h
drivers/clk/shmobile/clk-emev2.c
drivers/clk/sirf/Makefile
drivers/clk/sirf/clk-atlas7.c [new file with mode: 0644]
drivers/clk/sirf/clk-common.c
drivers/clk/socfpga/Makefile
drivers/clk/socfpga/clk-gate-a10.c [new file with mode: 0644]
drivers/clk/socfpga/clk-gate.c
drivers/clk/socfpga/clk-periph-a10.c [new file with mode: 0644]
drivers/clk/socfpga/clk-periph.c
drivers/clk/socfpga/clk-pll-a10.c [new file with mode: 0644]
drivers/clk/socfpga/clk-pll.c
drivers/clk/socfpga/clk.c
drivers/clk/socfpga/clk.h
drivers/clk/st/clk-flexgen.c
drivers/clk/st/clkgen-fsyn.c
drivers/clk/st/clkgen-mux.c
drivers/clk/st/clkgen-pll.c
drivers/clk/sunxi/clk-sun9i-core.c
drivers/clk/sunxi/clk-sunxi.c
drivers/clk/sunxi/clk-usb.c
drivers/clk/tegra/Kconfig [new file with mode: 0644]
drivers/clk/tegra/Makefile
drivers/clk/tegra/clk-emc.c [new file with mode: 0644]
drivers/clk/tegra/clk-tegra124.c
drivers/clk/tegra/clk-tegra30.c
drivers/clk/tegra/clk.h
drivers/clk/ti/clk-dra7-atl.c
drivers/clk/ti/clk.c
drivers/clk/ti/clockdomain.c
drivers/clk/ti/dpll.c
drivers/clk/ti/fapll.c
drivers/clk/ux500/u8500_clk.c
drivers/clk/ux500/u8500_of_clk.c
drivers/clk/versatile/clk-sp810.c
drivers/clk/zynq/clkc.c
drivers/cpufreq/Kconfig.arm
drivers/cpufreq/Makefile
drivers/cpufreq/exynos-cpufreq.c
drivers/cpufreq/exynos-cpufreq.h
drivers/cpufreq/exynos4210-cpufreq.c [deleted file]
include/dt-bindings/clock/bcm-cygnus.h [new file with mode: 0644]
include/dt-bindings/clock/hi6220-clock.h [new file with mode: 0644]
include/dt-bindings/clock/lpc18xx-ccu.h [new file with mode: 0644]
include/dt-bindings/clock/lpc18xx-cgu.h [new file with mode: 0644]
include/dt-bindings/clock/marvell,mmp2.h
include/dt-bindings/clock/marvell,pxa168.h
include/dt-bindings/clock/marvell,pxa1928.h [new file with mode: 0644]
include/dt-bindings/clock/marvell,pxa910.h
include/dt-bindings/clock/meson8b-clkc.h [new file with mode: 0644]
include/dt-bindings/clock/mt8135-clk.h [new file with mode: 0644]
include/dt-bindings/clock/mt8173-clk.h [new file with mode: 0644]
include/dt-bindings/reset-controller/mt8135-resets.h [new file with mode: 0644]
include/dt-bindings/reset-controller/mt8173-resets.h [new file with mode: 0644]
include/linux/clk-provider.h

index 0e4f90aa1c136eaa40c9d93e3586bbffdd180de4..f463bdc37f885c80d4614d6c9ab729c739e298d5 100644 (file)
@@ -230,30 +230,7 @@ clk_register(...)
 
 See the basic clock types in drivers/clk/clk-*.c for examples.
 
-       Part 5 - static initialization of clock data
-
-For platforms with many clocks (often numbering into the hundreds) it
-may be desirable to statically initialize some clock data.  This
-presents a problem since the definition of struct clk should be hidden
-from everyone except for the clock core in drivers/clk/clk.c.
-
-To get around this problem struct clk's definition is exposed in
-include/linux/clk-private.h along with some macros for more easily
-initializing instances of the basic clock types.  These clocks must
-still be initialized with the common clock framework via a call to
-__clk_init.
-
-clk-private.h must NEVER be included by code which implements struct
-clk_ops callbacks, nor must it be included by any logic which pokes
-around inside of struct clk at run-time.  To do so is a layering
-violation.
-
-To better enforce this policy, always follow this simple rule: any
-statically initialized clock data MUST be defined in a separate file
-from the logic that implements its ops.  Basically separate the logic
-from the data and all is well.
-
-       Part 6 - Disabling clock gating of unused clocks
+       Part 5 - Disabling clock gating of unused clocks
 
 Sometimes during development it can be useful to be able to bypass the
 default disabling of unused clocks. For example, if drivers aren't enabling
@@ -264,7 +241,7 @@ are sorted out.
 To bypass this disabling, include "clk_ignore_unused" in the bootargs to the
 kernel.
 
-       Part 7 - Locking
+       Part 6 - Locking
 
 The common clock framework uses two global locks, the prepare lock and the
 enable lock.
diff --git a/Documentation/devicetree/bindings/arm/mediatek/mediatek,apmixedsys.txt b/Documentation/devicetree/bindings/arm/mediatek/mediatek,apmixedsys.txt
new file mode 100644 (file)
index 0000000..936166f
--- /dev/null
@@ -0,0 +1,23 @@
+Mediatek apmixedsys controller
+==============================
+
+The Mediatek apmixedsys controller provides the PLLs to the system.
+
+Required Properties:
+
+- compatible: Should be:
+       - "mediatek,mt8135-apmixedsys"
+       - "mediatek,mt8173-apmixedsys"
+- #clock-cells: Must be 1
+
+The apmixedsys controller uses the common clk binding from
+Documentation/devicetree/bindings/clock/clock-bindings.txt
+The available clocks are defined in dt-bindings/clock/mt*-clk.h.
+
+Example:
+
+apmixedsys: clock-controller@10209000 {
+       compatible = "mediatek,mt8173-apmixedsys";
+       reg = <0 0x10209000 0 0x1000>;
+       #clock-cells = <1>;
+};
diff --git a/Documentation/devicetree/bindings/arm/mediatek/mediatek,infracfg.txt b/Documentation/devicetree/bindings/arm/mediatek/mediatek,infracfg.txt
new file mode 100644 (file)
index 0000000..f6cd3e4
--- /dev/null
@@ -0,0 +1,30 @@
+Mediatek infracfg controller
+============================
+
+The Mediatek infracfg controller provides various clocks and reset
+outputs to the system.
+
+Required Properties:
+
+- compatible: Should be:
+       - "mediatek,mt8135-infracfg", "syscon"
+       - "mediatek,mt8173-infracfg", "syscon"
+- #clock-cells: Must be 1
+- #reset-cells: Must be 1
+
+The infracfg controller uses the common clk binding from
+Documentation/devicetree/bindings/clock/clock-bindings.txt
+The available clocks are defined in dt-bindings/clock/mt*-clk.h.
+Also it uses the common reset controller binding from
+Documentation/devicetree/bindings/reset/reset.txt.
+The available reset outputs are defined in
+dt-bindings/reset-controller/mt*-resets.h
+
+Example:
+
+infracfg: power-controller@10001000 {
+       compatible = "mediatek,mt8173-infracfg", "syscon";
+       reg = <0 0x10001000 0 0x1000>;
+       #clock-cells = <1>;
+       #reset-cells = <1>;
+};
diff --git a/Documentation/devicetree/bindings/arm/mediatek/mediatek,pericfg.txt b/Documentation/devicetree/bindings/arm/mediatek/mediatek,pericfg.txt
new file mode 100644 (file)
index 0000000..f25b854
--- /dev/null
@@ -0,0 +1,30 @@
+Mediatek pericfg controller
+===========================
+
+The Mediatek pericfg controller provides various clocks and reset
+outputs to the system.
+
+Required Properties:
+
+- compatible: Should be:
+       - "mediatek,mt8135-pericfg", "syscon"
+       - "mediatek,mt8173-pericfg", "syscon"
+- #clock-cells: Must be 1
+- #reset-cells: Must be 1
+
+The pericfg controller uses the common clk binding from
+Documentation/devicetree/bindings/clock/clock-bindings.txt
+The available clocks are defined in dt-bindings/clock/mt*-clk.h.
+Also it uses the common reset controller binding from
+Documentation/devicetree/bindings/reset/reset.txt.
+The available reset outputs are defined in
+dt-bindings/reset-controller/mt*-resets.h
+
+Example:
+
+pericfg: power-controller@10003000 {
+       compatible = "mediatek,mt8173-pericfg", "syscon";
+       reg = <0 0x10003000 0 0x1000>;
+       #clock-cells = <1>;
+       #reset-cells = <1>;
+};
diff --git a/Documentation/devicetree/bindings/arm/mediatek/mediatek,topckgen.txt b/Documentation/devicetree/bindings/arm/mediatek/mediatek,topckgen.txt
new file mode 100644 (file)
index 0000000..f9e9179
--- /dev/null
@@ -0,0 +1,23 @@
+Mediatek topckgen controller
+============================
+
+The Mediatek topckgen controller provides various clocks to the system.
+
+Required Properties:
+
+- compatible: Should be:
+       - "mediatek,mt8135-topckgen"
+       - "mediatek,mt8173-topckgen"
+- #clock-cells: Must be 1
+
+The topckgen controller uses the common clk binding from
+Documentation/devicetree/bindings/clock/clock-bindings.txt
+The available clocks are defined in dt-bindings/clock/mt*-clk.h.
+
+Example:
+
+topckgen: power-controller@10000000 {
+       compatible = "mediatek,mt8173-topckgen";
+       reg = <0 0x10000000 0 0x1000>;
+       #clock-cells = <1>;
+};
diff --git a/Documentation/devicetree/bindings/clock/amlogic,meson8b-clkc.txt b/Documentation/devicetree/bindings/clock/amlogic,meson8b-clkc.txt
new file mode 100644 (file)
index 0000000..2b7b3fa
--- /dev/null
@@ -0,0 +1,40 @@
+* Amlogic Meson8b Clock and Reset Unit
+
+The Amlogic Meson8b clock controller generates and supplies clock to various
+controllers within the SoC.
+
+Required Properties:
+
+- compatible: should be "amlogic,meson8b-clkc"
+- reg: it must be composed by two tuples:
+       0) physical base address of the xtal register and length of memory
+          mapped region.
+       1) physical base address of the clock controller and length of memory
+          mapped region.
+
+- #clock-cells: should be 1.
+
+Each clock is assigned an identifier and client nodes can use this identifier
+to specify the clock which they consume. All available clocks are defined as
+preprocessor macros in the dt-bindings/clock/meson8b-clkc.h header and can be
+used in device tree sources.
+
+Example: Clock controller node:
+
+       clkc: clock-controller@c1104000 {
+               #clock-cells = <1>;
+               compatible = "amlogic,meson8b-clkc";
+               reg = <0xc1108000 0x4>, <0xc1104000 0x460>;
+       };
+
+
+Example: UART controller node that consumes the clock generated by the clock
+  controller:
+
+       uart_AO: serial@c81004c0 {
+               compatible = "amlogic,meson-uart";
+               reg = <0xc81004c0 0x14>;
+               interrupts = <0 90 1>;
+               clocks = <&clkc CLKID_CLK81>;
+               status = "disabled";
+       };
diff --git a/Documentation/devicetree/bindings/clock/bcm-cygnus-clock.txt b/Documentation/devicetree/bindings/clock/bcm-cygnus-clock.txt
deleted file mode 100644 (file)
index 00d26ed..0000000
+++ /dev/null
@@ -1,34 +0,0 @@
-Broadcom Cygnus Clocks
-
-This binding uses the common clock binding:
-Documentation/devicetree/bindings/clock/clock-bindings.txt
-
-Currently various "fixed" clocks are declared for peripheral drivers that use
-the common clock framework to reference their core clocks. Proper support of
-these clocks will be added later
-
-Device tree example:
-
-       clocks {
-               #address-cells = <1>;
-               #size-cells = <1>;
-               ranges;
-
-               osc: oscillator {
-                       compatible = "fixed-clock";
-                       #clock-cells = <1>;
-                       clock-frequency = <25000000>;
-               };
-
-               apb_clk: apb_clk {
-                       compatible = "fixed-clock";
-                       #clock-cells = <0>;
-                       clock-frequency = <1000000000>;
-               };
-
-               periph_clk: periph_clk {
-                       compatible = "fixed-clock";
-                       #clock-cells = <0>;
-                       clock-frequency = <500000000>;
-               };
-       };
diff --git a/Documentation/devicetree/bindings/clock/brcm,iproc-clocks.txt b/Documentation/devicetree/bindings/clock/brcm,iproc-clocks.txt
new file mode 100644 (file)
index 0000000..da8d9bb
--- /dev/null
@@ -0,0 +1,132 @@
+Broadcom iProc Family Clocks
+
+This binding uses the common clock binding:
+    Documentation/devicetree/bindings/clock/clock-bindings.txt
+
+The iProc clock controller manages clocks that are common to the iProc family.
+An SoC from the iProc family may have several PPLs, e.g., ARMPLL, GENPLL,
+LCPLL0, MIPIPLL, and etc., all derived from an onboard crystal. Each PLL
+comprises of several leaf clocks
+
+Required properties for a PLL and its leaf clocks:
+
+- compatible:
+    Should have a value of the form "brcm,<soc>-<pll>". For example, GENPLL on
+Cygnus has a compatible string of "brcm,cygnus-genpll"
+
+- #clock-cells:
+    Have a value of <1> since there are more than 1 leaf clock of a given PLL
+
+- reg:
+    Define the base and range of the I/O address space that contain the iProc
+clock control registers required for the PLL
+
+- clocks:
+    The input parent clock phandle for the PLL. For most iProc PLLs, this is an
+onboard crystal with a fixed rate
+
+- clock-output-names:
+    An ordered list of strings defining the names of the clocks
+
+Example:
+
+       osc: oscillator {
+               #clock-cells = <0>;
+               compatible = "fixed-clock";
+               clock-frequency = <25000000>;
+       };
+
+       genpll: genpll {
+               #clock-cells = <1>;
+               compatible = "brcm,cygnus-genpll";
+               reg = <0x0301d000 0x2c>, <0x0301c020 0x4>;
+               clocks = <&osc>;
+               clock-output-names = "genpll", "axi21", "250mhz", "ihost_sys",
+                                    "enet_sw", "audio_125", "can";
+       };
+
+Required properties for ASIU clocks:
+
+ASIU clocks are a special case. These clocks are derived directly from the
+reference clock of the onboard crystal
+
+- compatible:
+    Should have a value of the form "brcm,<soc>-asiu-clk". For example, ASIU
+clocks for Cygnus have a compatible string of "brcm,cygnus-asiu-clk"
+
+- #clock-cells:
+    Have a value of <1> since there are more than 1 ASIU clocks
+
+- reg:
+    Define the base and range of the I/O address space that contain the iProc
+clock control registers required for ASIU clocks
+
+- clocks:
+    The input parent clock phandle for the ASIU clock, i.e., the onboard
+crystal
+
+- clock-output-names:
+    An ordered list of strings defining the names of the ASIU clocks
+
+Example:
+
+       osc: oscillator {
+               #clock-cells = <0>;
+               compatible = "fixed-clock";
+               clock-frequency = <25000000>;
+       };
+
+       asiu_clks: asiu_clks {
+               #clock-cells = <1>;
+               compatible = "brcm,cygnus-asiu-clk";
+               reg = <0x0301d048 0xc>, <0x180aa024 0x4>;
+               clocks = <&osc>;
+               clock-output-names = "keypad", "adc/touch", "pwm";
+       };
+
+Cygnus
+------
+PLL and leaf clock compatible strings for Cygnus are:
+    "brcm,cygnus-armpll"
+    "brcm,cygnus-genpll"
+    "brcm,cygnus-lcpll0"
+    "brcm,cygnus-mipipll"
+    "brcm,cygnus-asiu-clk"
+
+The following table defines the set of PLL/clock index and ID for Cygnus.
+These clock IDs are defined in:
+    "include/dt-bindings/clock/bcm-cygnus.h"
+
+    Clock      Source (Parent)  Index   ID
+    ---        -----            -----   ---------
+    crystal    N/A              N/A     N/A
+
+    armpll     crystal          N/A     N/A
+
+    keypad     crystal (ASIU)   0       BCM_CYGNUS_ASIU_KEYPAD_CLK
+    adc/tsc    crystal (ASIU)   1       BCM_CYGNUS_ASIU_ADC_CLK
+    pwm        crystal (ASIU)   2       BCM_CYGNUS_ASIU_PWM_CLK
+
+    genpll     crystal          0       BCM_CYGNUS_GENPLL
+    axi21      genpll           1       BCM_CYGNUS_GENPLL_AXI21_CLK
+    250mhz     genpll           2       BCM_CYGNUS_GENPLL_250MHZ_CLK
+    ihost_sys  genpll           3       BCM_CYGNUS_GENPLL_IHOST_SYS_CLK
+    enet_sw    genpll           4       BCM_CYGNUS_GENPLL_ENET_SW_CLK
+    audio_125  genpll           5       BCM_CYGNUS_GENPLL_AUDIO_125_CLK
+    can        genpll           6       BCM_CYGNUS_GENPLL_CAN_CLK
+
+    lcpll0     crystal          0       BCM_CYGNUS_LCPLL0
+    pcie_phy   lcpll0           1       BCM_CYGNUS_LCPLL0_PCIE_PHY_REF_CLK
+    ddr_phy    lcpll0           2       BCM_CYGNUS_LCPLL0_DDR_PHY_CLK
+    sdio       lcpll0           3       BCM_CYGNUS_LCPLL0_SDIO_CLK
+    usb_phy    lcpll0           4       BCM_CYGNUS_LCPLL0_USB_PHY_REF_CLK
+    smart_card lcpll0           5       BCM_CYGNUS_LCPLL0_SMART_CARD_CLK
+    ch5_unused lcpll0           6       BCM_CYGNUS_LCPLL0_CH5_UNUSED
+
+    mipipll    crystal          0       BCM_CYGNUS_MIPIPLL
+    ch0_unused mipipll          1       BCM_CYGNUS_MIPIPLL_CH0_UNUSED
+    ch1_lcd    mipipll          2       BCM_CYGNUS_MIPIPLL_CH1_LCD
+    ch2_v3d    mipipll          3       BCM_CYGNUS_MIPIPLL_CH2_V3D
+    ch3_unused mipipll          4       BCM_CYGNUS_MIPIPLL_CH3_UNUSED
+    ch4_unused mipipll          5       BCM_CYGNUS_MIPIPLL_CH4_UNUSED
+    ch5_unused mipipll          6       BCM_CYGNUS_MIPIPLL_CH5_UNUSED
index 06fc6d541c8936c67ea609265ab1b56d3c280a57..2ec489eebe723afb0f6cf1700d7869e9d84f0ac6 100644 (file)
@@ -138,9 +138,10 @@ Some platforms may require initial configuration of default parent clocks
 and clock frequencies. Such a configuration can be specified in a device tree
 node through assigned-clocks, assigned-clock-parents and assigned-clock-rates
 properties. The assigned-clock-parents property should contain a list of parent
-clocks in form of phandle and clock specifier pairs, the assigned-clock-parents
-property the list of assigned clock frequency values - corresponding to clocks
-listed in the assigned-clocks property.
+clocks in the form of a phandle and clock specifier pair and the
+assigned-clock-rates property should contain a list of frequencies in Hz. Both
+these properties should correspond to the clocks listed in the assigned-clocks
+property.
 
 To skip setting parent or rate of a clock its corresponding entry should be
 set to 0, or can be omitted if it is not followed by any non-zero entry.
diff --git a/Documentation/devicetree/bindings/clock/csr,atlas7-car.txt b/Documentation/devicetree/bindings/clock/csr,atlas7-car.txt
new file mode 100644 (file)
index 0000000..54d6d13
--- /dev/null
@@ -0,0 +1,55 @@
+* Clock and reset bindings for CSR atlas7
+
+Required properties:
+- compatible: Should be "sirf,atlas7-car"
+- reg: Address and length of the register set
+- #clock-cells: Should be <1>
+- #reset-cells: Should be <1>
+
+The clock consumer should specify the desired clock by having the clock
+ID in its "clocks" phandle cell.
+The ID list atlas7_clks defined in drivers/clk/sirf/clk-atlas7.c
+
+The reset consumer should specify the desired reset by having the reset
+ID in its "reset" phandle cell.
+The ID list atlas7_reset_unit defined in drivers/clk/sirf/clk-atlas7.c
+
+Examples: Clock and reset controller node:
+
+car: clock-controller@18620000 {
+       compatible = "sirf,atlas7-car";
+       reg = <0x18620000 0x1000>;
+       #clock-cells = <1>;
+       #reset-cells = <1>;
+};
+
+Examples: Consumers using clock or reset:
+
+timer@10dc0000 {
+       compatible = "sirf,macro-tick";
+       reg = <0x10dc0000 0x1000>;
+       clocks = <&car 54>;
+       interrupts = <0 0 0>,
+                  <0 1 0>,
+                  <0 2 0>,
+                  <0 49 0>,
+                  <0 50 0>,
+                  <0 51 0>;
+};
+
+uart1: uart@18020000 {
+       cell-index = <1>;
+       compatible = "sirf,macro-uart";
+       reg = <0x18020000 0x1000>;
+       clocks = <&clks 95>;
+       interrupts = <0 18 0>;
+       fifosize = <32>;
+};
+
+vpp@13110000 {
+       compatible = "sirf,prima2-vpp";
+       reg = <0x13110000 0x10000>;
+       interrupts = <0 31 0>;
+       clocks = <&car 85>;
+       resets = <&car 29>;
+};
index 60bbb1a8c69a385274f2aeaafd8961c0a5dd7984..268ca615459e754900f979bda8542b3c5d2cbac3 100644 (file)
@@ -52,7 +52,7 @@ usia_u0_sclk: usia_u0_sclk {
 
 Example of consumer:
 
-uart@e1020000 {
+serial@e1020000 {
        compatible = "renesas,em-uart";
        reg = <0xe1020000 0x38>;
        interrupts = <0 8 0>;
index 225990f79b7c577f50594cec23e1abb889bc5502..47570d20721599a1c68e950ebf5598e913f0c8a1 100644 (file)
@@ -15,8 +15,8 @@ Required properties:
 - compatible : shall be "ti,keystone,main-pll-clock" or "ti,keystone,pll-clock"
 - clocks : parent clock phandle
 - reg - pll control0 and pll multipler registers
-- reg-names : control and multiplier. The multiplier is applicable only for
-               main pll clock
+- reg-names : control, multiplier and post-divider. The multiplier and
+               post-divider registers are applicable only for main pll clock
 - fixed-postdiv : fixed post divider value. If absent, use clkod register bits
                for postdiv
 
@@ -25,8 +25,8 @@ Example:
                #clock-cells = <0>;
                compatible = "ti,keystone,main-pll-clock";
                clocks = <&refclksys>;
-               reg = <0x02620350 4>, <0x02310110 4>;
-               reg-names = "control", "multiplier";
+               reg = <0x02620350 4>, <0x02310110 4>, <0x02310108 4>;
+               reg-names = "control", "multiplier", "post-divider";
                fixed-postdiv = <2>;
        };
 
diff --git a/Documentation/devicetree/bindings/clock/lpc1850-ccu.txt b/Documentation/devicetree/bindings/clock/lpc1850-ccu.txt
new file mode 100644 (file)
index 0000000..fa97c12
--- /dev/null
@@ -0,0 +1,77 @@
+* NXP LPC1850 Clock Control Unit (CCU)
+
+Each CGU base clock has several clock branches which can be turned on
+or off independently by the Clock Control Units CCU1 or CCU2. The
+branch clocks are distributed between CCU1 and CCU2.
+
+ - Above text taken from NXP LPC1850 User Manual.
+
+This binding uses the common clock binding:
+    Documentation/devicetree/bindings/clock/clock-bindings.txt
+
+Required properties:
+- compatible:
+       Should be "nxp,lpc1850-ccu"
+- reg:
+       Shall define the base and range of the address space
+       containing clock control registers
+- #clock-cells:
+       Shall have value <1>.  The permitted clock-specifier values
+       are the branch clock names defined in table below.
+- clocks:
+       Shall contain a list of phandles for the base clocks routed
+       from the CGU to the specific CCU. See mapping of base clocks
+       and CCU in table below.
+- clock-names:
+       Shall contain a list of names for the base clock routed
+       from the CGU to the specific CCU. Valid CCU clock names:
+       "base_usb0_clk",  "base_periph_clk", "base_usb1_clk",
+       "base_cpu_clk",   "base_spifi_clk",  "base_spi_clk",
+       "base_apb1_clk",  "base_apb3_clk",   "base_adchs_clk",
+       "base_sdio_clk",  "base_ssp0_clk",   "base_ssp1_clk",
+       "base_uart0_clk", "base_uart1_clk",  "base_uart2_clk",
+       "base_uart3_clk", "base_audio_clk"
+
+Which branch clocks that are available on the CCU depends on the
+specific LPC part. Check the user manual for your specific part.
+
+A list of CCU clocks can be found in dt-bindings/clock/lpc18xx-ccu.h.
+
+Example board file:
+
+soc {
+       ccu1: clock-controller@40051000 {
+               compatible = "nxp,lpc1850-ccu";
+               reg = <0x40051000 0x1000>;
+               #clock-cells = <1>;
+               clocks = <&cgu BASE_APB3_CLK>,   <&cgu BASE_APB1_CLK>,
+                        <&cgu BASE_SPIFI_CLK>,  <&cgu BASE_CPU_CLK>,
+                        <&cgu BASE_PERIPH_CLK>, <&cgu BASE_USB0_CLK>,
+                        <&cgu BASE_USB1_CLK>,   <&cgu BASE_SPI_CLK>;
+               clock-names = "base_apb3_clk",   "base_apb1_clk",
+                             "base_spifi_clk",  "base_cpu_clk",
+                             "base_periph_clk", "base_usb0_clk",
+                             "base_usb1_clk",   "base_spi_clk";
+       };
+
+       ccu2: clock-controller@40052000 {
+               compatible = "nxp,lpc1850-ccu";
+               reg = <0x40052000 0x1000>;
+               #clock-cells = <1>;
+               clocks = <&cgu BASE_AUDIO_CLK>, <&cgu BASE_UART3_CLK>,
+                        <&cgu BASE_UART2_CLK>, <&cgu BASE_UART1_CLK>,
+                        <&cgu BASE_UART0_CLK>, <&cgu BASE_SSP1_CLK>,
+                        <&cgu BASE_SSP0_CLK>,  <&cgu BASE_SDIO_CLK>;
+               clock-names = "base_audio_clk", "base_uart3_clk",
+                             "base_uart2_clk", "base_uart1_clk",
+                             "base_uart0_clk", "base_ssp1_clk",
+                             "base_ssp0_clk",  "base_sdio_clk";
+       };
+
+       /* A user of CCU brach clocks */
+       uart1: serial@40082000 {
+               ...
+               clocks = <&ccu2 CLK_APB0_UART1>, <&ccu1 CLK_CPU_UART1>;
+               ...
+       };
+};
diff --git a/Documentation/devicetree/bindings/clock/lpc1850-cgu.txt b/Documentation/devicetree/bindings/clock/lpc1850-cgu.txt
new file mode 100644 (file)
index 0000000..2cc32a9
--- /dev/null
@@ -0,0 +1,131 @@
+* NXP LPC1850 Clock Generation Unit (CGU)
+
+The CGU generates multiple independent clocks for the core and the
+peripheral blocks of the LPC18xx. Each independent clock is called
+a base clock and itself is one of the inputs to the two Clock
+Control Units (CCUs) which control the branch clocks to the
+individual peripherals.
+
+The CGU selects the inputs to the clock generators from multiple
+clock sources, controls the clock generation, and routes the outputs
+of the clock generators through the clock source bus to the output
+stages. Each output stage provides an independent clock source and
+corresponds to one of the base clocks for the LPC18xx.
+
+ - Above text taken from NXP LPC1850 User Manual.
+
+
+This binding uses the common clock binding:
+    Documentation/devicetree/bindings/clock/clock-bindings.txt
+
+Required properties:
+- compatible:
+       Should be "nxp,lpc1850-cgu"
+- reg:
+       Shall define the base and range of the address space
+       containing clock control registers
+- #clock-cells:
+       Shall have value <1>.  The permitted clock-specifier values
+       are the base clock numbers defined below.
+- clocks:
+       Shall contain a list of phandles for the external input
+       sources to the CGU. The list shall be in the following
+       order: xtal, 32khz, enet_rx_clk, enet_tx_clk, gp_clkin.
+- clock-indices:
+       Shall be an ordered list of numbers defining the base clock
+       number provided by the CGU.
+- clock-output-names:
+       Shall be an ordered list of strings defining the names of
+       the clocks provided by the CGU.
+
+Which base clocks that are available on the CGU depends on the
+specific LPC part. Base clocks are numbered from 0 to 27.
+
+Number:                Name:                   Description:
+ 0             BASE_SAFE_CLK           Base safe clock (always on) for WWDT
+ 1             BASE_USB0_CLK           Base clock for USB0
+ 2             BASE_PERIPH_CLK         Base clock for Cortex-M0SUB subsystem,
+                                       SPI, and SGPIO
+ 3             BASE_USB1_CLK           Base clock for USB1
+ 4             BASE_CPU_CLK            System base clock for ARM Cortex-M core
+                                       and APB peripheral blocks #0 and #2
+ 5             BASE_SPIFI_CLK          Base clock for SPIFI
+ 6             BASE_SPI_CLK            Base clock for SPI
+ 7             BASE_PHY_RX_CLK         Base clock for Ethernet PHY Receive clock
+ 8             BASE_PHY_TX_CLK         Base clock for Ethernet PHY Transmit clock
+ 9             BASE_APB1_CLK           Base clock for APB peripheral block # 1
+10             BASE_APB3_CLK           Base clock for APB peripheral block # 3
+11             BASE_LCD_CLK            Base clock for LCD
+12             BASE_ADCHS_CLK          Base clock for ADCHS
+13             BASE_SDIO_CLK           Base clock for SD/MMC
+14             BASE_SSP0_CLK           Base clock for SSP0
+15             BASE_SSP1_CLK           Base clock for SSP1
+16             BASE_UART0_CLK          Base clock for UART0
+17             BASE_UART1_CLK          Base clock for UART1
+18             BASE_UART2_CLK          Base clock for UART2
+19             BASE_UART3_CLK          Base clock for UART3
+20             BASE_OUT_CLK            Base clock for CLKOUT pin
+24-21          -                       Reserved
+25             BASE_AUDIO_CLK          Base clock for audio system (I2S)
+26             BASE_CGU_OUT0_CLK       Base clock for CGU_OUT0 clock output
+27             BASE_CGU_OUT1_CLK       Base clock for CGU_OUT1 clock output
+
+BASE_PERIPH_CLK and BASE_SPI_CLK is only available on LPC43xx.
+BASE_ADCHS_CLK is only available on LPC4370.
+
+
+Example board file:
+
+/ {
+       clocks {
+               xtal: xtal {
+                       compatible = "fixed-clock";
+                       #clock-cells = <0>;
+                       clock-frequency = <12000000>;
+               };
+
+               xtal32: xtal32 {
+                       compatible = "fixed-clock";
+                       #clock-cells = <0>;
+                       clock-frequency = <32768>;
+               };
+
+               enet_rx_clk: enet_rx_clk {
+                       compatible = "fixed-clock";
+                       #clock-cells = <0>;
+                       clock-frequency = <0>;
+                       clock-output-names = "enet_rx_clk";
+               };
+
+               enet_tx_clk: enet_tx_clk {
+                       compatible = "fixed-clock";
+                       #clock-cells = <0>;
+                       clock-frequency = <0>;
+                       clock-output-names = "enet_tx_clk";
+               };
+
+               gp_clkin: gp_clkin {
+                       compatible = "fixed-clock";
+                       #clock-cells = <0>;
+                       clock-frequency = <0>;
+                       clock-output-names = "gp_clkin";
+               };
+       };
+
+       soc {
+               cgu: clock-controller@40050000 {
+                       compatible = "nxp,lpc1850-cgu";
+                       reg = <0x40050000 0x1000>;
+                       #clock-cells = <1>;
+                       clocks = <&xtal>, <&creg_clk 1>, <&enet_rx_clk>, <&enet_tx_clk>, <&gp_clkin>;
+               };
+
+               /* A CGU and CCU clock consumer */
+               lcdc: lcdc@40008000 {
+                       ...
+                       clocks = <&cgu BASE_LCD_CLK>, <&ccu1 CLK_CPU_LCD>;
+                       clock-names = "clcdclk", "apb_pclk";
+                       ...
+               };
+       };
+};
diff --git a/Documentation/devicetree/bindings/clock/marvell,pxa1928.txt b/Documentation/devicetree/bindings/clock/marvell,pxa1928.txt
new file mode 100644 (file)
index 0000000..809c5a2
--- /dev/null
@@ -0,0 +1,21 @@
+* Marvell PXA1928 Clock Controllers
+
+The PXA1928 clock subsystem generates and supplies clock to various
+controllers within the PXA1928 SoC. The PXA1928 contains 3 clock controller
+blocks called APMU, MPMU, and APBC roughly corresponding to internal buses.
+
+Required Properties:
+
+- compatible: should be one of the following.
+  - "marvell,pxa1928-apmu" - APMU controller compatible
+  - "marvell,pxa1928-mpmu" - MPMU controller compatible
+  - "marvell,pxa1928-apbc" - APBC controller compatible
+- reg: physical base address of the clock controller and length of memory mapped
+  region.
+- #clock-cells: should be 1.
+- #reset-cells: should be 1.
+
+Each clock is assigned an identifier and client nodes use the clock controller
+phandle and this identifier to specify the clock which they consume.
+
+All these identifiers can be found in <dt-bindings/clock/marvell,pxa1928.h>.
index 31c7c0c1ce8f6b47a625f8b6f41eafc6a35d402a..660e64912cceb69146f1ea6b4a18e8b533944223 100644 (file)
@@ -19,6 +19,7 @@ ID    Clock   Peripheral
 9      pex1    PCIe Cntrl 1
 15     sata0   SATA Host 0
 17     sdio    SDHCI Host
+23     crypto  CESA (crypto engine)
 25     tdm     Time Division Mplx
 28     ddr     DDR Cntrl
 30     sata1   SATA Host 0
index c6620bc9670364315bcc8687ec81c016e7a89719..7f02fb4ca4adb020a9b7990e6db5532e0fc2abe5 100644 (file)
@@ -20,15 +20,38 @@ Required properties :
 - #reset-cells : Should be 1.
   In clock consumers, this cell represents the bit number in the CAR's
   array of CLK_RST_CONTROLLER_RST_DEVICES_* registers.
+- nvidia,external-memory-controller : phandle of the EMC driver.
+
+The node should contain a "emc-timings" subnode for each supported RAM type (see
+field RAM_CODE in register PMC_STRAPPING_OPT_A).
+
+Required properties for "emc-timings" nodes :
+- nvidia,ram-code : Should contain the value of RAM_CODE this timing set
+  is used for.
+
+Each "emc-timings" node should contain a "timing" subnode for every supported
+EMC clock rate.
+
+Required properties for "timing" nodes :
+- clock-frequency : Should contain the memory clock rate to which this timing
+relates.
+- nvidia,parent-clock-frequency : Should contain the rate at which the current
+parent of the EMC clock should be running at this timing.
+- clocks : Must contain an entry for each entry in clock-names.
+  See ../clocks/clock-bindings.txt for details.
+- clock-names : Must include the following entries:
+  - emc-parent : the clock that should be the parent of the EMC clock at this
+timing.
 
 Example SoC include file:
 
 / {
-       tegra_car: clock {
+       tegra_car: clock@60006000 {
                compatible = "nvidia,tegra124-car";
                reg = <0x60006000 0x1000>;
                #clock-cells = <1>;
                #reset-cells = <1>;
+               nvidia,external-memory-controller = <&emc>;
        };
 
        usb@c5004000 {
@@ -62,4 +85,23 @@ Example board file:
        &tegra_car {
                clocks = <&clk_32k> <&osc>;
        };
+
+       clock@60006000 {
+               emc-timings-3 {
+                       nvidia,ram-code = <3>;
+
+                       timing-12750000 {
+                               clock-frequency = <12750000>;
+                               nvidia,parent-clock-frequency = <408000000>;
+                               clocks = <&tegra_car TEGRA124_CLK_PLL_P>;
+                               clock-names = "emc-parent";
+                       };
+                       timing-20400000 {
+                               clock-frequency = <20400000>;
+                               nvidia,parent-clock-frequency = <408000000>;
+                               clocks = <&tegra_car TEGRA124_CLK_PLL_P>;
+                               clock-names = "emc-parent";
+                       };
+               };
+       };
 };
index 054f65f9319cd71c74936dcab565901559a9d280..5ddb68418655d569e047ec91891d5c6b41bda49e 100644 (file)
@@ -10,9 +10,11 @@ Required Properties:
     - "renesas,r8a73a4-div6-clock" for R8A73A4 (R-Mobile APE6) DIV6 clocks
     - "renesas,r8a7740-div6-clock" for R8A7740 (R-Mobile A1) DIV6 clocks
     - "renesas,r8a7790-div6-clock" for R8A7790 (R-Car H2) DIV6 clocks
-    - "renesas,r8a7791-div6-clock" for R8A7791 (R-Car M2) DIV6 clocks
+    - "renesas,r8a7791-div6-clock" for R8A7791 (R-Car M2-W) DIV6 clocks
+    - "renesas,r8a7793-div6-clock" for R8A7793 (R-Car M2-N) DIV6 clocks
+    - "renesas,r8a7794-div6-clock" for R8A7794 (R-Car E2) DIV6 clocks
     - "renesas,sh73a0-div6-clock" for SH73A0 (SH-Mobile AG5) DIV6 clocks
-    - "renesas,cpg-div6-clock" for generic DIV6 clocks
+    and "renesas,cpg-div6-clock" as a fallback.
   - reg: Base address and length of the memory resource used by the DIV6 clock
   - clocks: Reference to the parent clock(s); either one, four, or eight
     clocks must be specified.  For clocks with multiple parents, invalid
index 0a80fa70ca265c0f2c7b7657d7270f47d6f53a45..16ed18155160f58c9ce17dce42f50f1527261f72 100644 (file)
@@ -13,12 +13,14 @@ Required Properties:
     - "renesas,r7s72100-mstp-clocks" for R7S72100 (RZ) MSTP gate clocks
     - "renesas,r8a73a4-mstp-clocks" for R8A73A4 (R-Mobile APE6) MSTP gate clocks
     - "renesas,r8a7740-mstp-clocks" for R8A7740 (R-Mobile A1) MSTP gate clocks
+    - "renesas,r8a7778-mstp-clocks" for R8A7778 (R-Car M1) MSTP gate clocks
     - "renesas,r8a7779-mstp-clocks" for R8A7779 (R-Car H1) MSTP gate clocks
     - "renesas,r8a7790-mstp-clocks" for R8A7790 (R-Car H2) MSTP gate clocks
-    - "renesas,r8a7791-mstp-clocks" for R8A7791 (R-Car M2) MSTP gate clocks
+    - "renesas,r8a7791-mstp-clocks" for R8A7791 (R-Car M2-W) MSTP gate clocks
+    - "renesas,r8a7793-mstp-clocks" for R8A7793 (R-Car M2-N) MSTP gate clocks
     - "renesas,r8a7794-mstp-clocks" for R8A7794 (R-Car E2) MSTP gate clocks
     - "renesas,sh73a0-mstp-clocks" for SH73A0 (SH-MobileAG5) MSTP gate clocks
-    - "renesas,cpg-mstp-clock" for generic MSTP gate clocks
+    and "renesas,cpg-mstp-clocks" as a fallback.
   - reg: Base address and length of the I/O mapped registers used by the MSTP
     clocks. The first register is the clock control register and is mandatory.
     The second register is the clock status register and is optional when not
index b02944fba9de4f8696d9f6ac7845acb96937aeed..56f111bd3e456619ae872fd49825f48b11604c02 100644 (file)
@@ -10,7 +10,7 @@ Required Properties:
     - "renesas,r8a7791-cpg-clocks" for the r8a7791 CPG
     - "renesas,r8a7793-cpg-clocks" for the r8a7793 CPG
     - "renesas,r8a7794-cpg-clocks" for the r8a7794 CPG
-    - "renesas,rcar-gen2-cpg-clocks" for the generic R-Car Gen2 CPG
+    and "renesas,rcar-gen2-cpg-clocks" as a fallback.
 
   - reg: Base address and length of the memory resource used by the CPG
 
index 98a257492522cd45d967189ef14f0df7dcb60207..b0f7ddb8cdb13750e1673e458fa91d2cfa7e44d5 100644 (file)
@@ -7,7 +7,7 @@ Required Properties:
 
   - compatible: Must be one of
     - "renesas,r7s72100-cpg-clocks" for the r7s72100 CPG
-    - "renesas,rz-cpg-clocks" for the generic RZ CPG
+    and "renesas,rz-cpg-clocks" as a fallback.
   - reg: Base address and length of the memory resource used by the CPG
   - clocks: References to possible parent clocks. Order must match clock modes
     in the datasheet. For the r7s72100, this is extal, usb_x1.
diff --git a/Documentation/devicetree/bindings/clock/st,stm32-rcc.txt b/Documentation/devicetree/bindings/clock/st,stm32-rcc.txt
new file mode 100644 (file)
index 0000000..fee3205
--- /dev/null
@@ -0,0 +1,65 @@
+STMicroelectronics STM32 Reset and Clock Controller
+===================================================
+
+The RCC IP is both a reset and a clock controller. This documentation only
+describes the clock part.
+
+Please also refer to clock-bindings.txt in this directory for common clock
+controller binding usage.
+
+Required properties:
+- compatible: Should be "st,stm32f42xx-rcc"
+- reg: should be register base and length as documented in the
+  datasheet
+- #clock-cells: 2, device nodes should specify the clock in their "clocks"
+  property, containing a phandle to the clock device node, an index selecting
+  between gated clocks and other clocks and an index specifying the clock to
+  use.
+
+Example:
+
+       rcc: rcc@40023800 {
+               #clock-cells = <2>
+               compatible = "st,stm32f42xx-rcc", "st,stm32-rcc";
+               reg = <0x40023800 0x400>;
+       };
+
+Specifying gated clocks
+=======================
+
+The primary index must be set to 0.
+
+The secondary index is the bit number within the RCC register bank, starting
+from the first RCC clock enable register (RCC_AHB1ENR, address offset 0x30).
+
+It is calculated as: index = register_offset / 4 * 32 + bit_offset.
+Where bit_offset is the bit offset within the register (LSB is 0, MSB is 31).
+
+Example:
+
+       /* Gated clock, AHB1 bit 0 (GPIOA) */
+       ... {
+               clocks = <&rcc 0 0>
+       };
+
+       /* Gated clock, AHB2 bit 4 (CRYP) */
+       ... {
+               clocks = <&rcc 0 36>
+       };
+
+Specifying other clocks
+=======================
+
+The primary index must be set to 1.
+
+The secondary index is bound with the following magic numbers:
+
+       0       SYSTICK
+       1       FCLK
+
+Example:
+
+       /* Misc clock, FCLK */
+       ... {
+               clocks = <&rcc 1 1>
+       };
index 4fa11af3d378ef281e43717490c012263b901122..8a47b77abfca677e234fdd618ee029935e0861dc 100644 (file)
@@ -67,6 +67,7 @@ Required properties:
        "allwinner,sun4i-a10-usb-clk" - for usb gates + resets on A10 / A20
        "allwinner,sun5i-a13-usb-clk" - for usb gates + resets on A13
        "allwinner,sun6i-a31-usb-clk" - for usb gates + resets on A31
+       "allwinner,sun8i-a23-usb-clk" - for usb gates + resets on A23
        "allwinner,sun9i-a80-usb-mod-clk" - for usb gates + resets on A80
        "allwinner,sun9i-a80-usb-phy-clk" - for usb phy gates + resets on A80
 
diff --git a/Documentation/devicetree/bindings/clock/ti,cdce925.txt b/Documentation/devicetree/bindings/clock/ti,cdce925.txt
new file mode 100644 (file)
index 0000000..4c7669a
--- /dev/null
@@ -0,0 +1,42 @@
+Binding for TO CDCE925 programmable I2C clock synthesizers.
+
+Reference
+This binding uses the common clock binding[1].
+
+[1] Documentation/devicetree/bindings/clock/clock-bindings.txt
+[2] http://www.ti.com/product/cdce925
+
+The driver provides clock sources for each output Y1 through Y5.
+
+Required properties:
+ - compatible: Shall be "ti,cdce925"
+ - reg: I2C device address.
+ - clocks: Points to a fixed parent clock that provides the input frequency.
+ - #clock-cells: From common clock bindings: Shall be 1.
+
+Optional properties:
+ - xtal-load-pf: Crystal load-capacitor value to fine-tune performance on a
+                 board, or to compensate for external influences.
+
+For both PLL1 and PLL2 an optional child node can be used to specify spread
+spectrum clocking parameters for a board.
+  - spread-spectrum: SSC mode as defined in the data sheet.
+  - spread-spectrum-center: Use "centered" mode instead of "max" mode. When
+    present, the clock runs at the requested frequency on average. Otherwise
+    the requested frequency is the maximum value of the SCC range.
+
+
+Example:
+
+       clockgen: cdce925pw@64 {
+               compatible = "cdce925";
+               reg = <0x64>;
+               clocks = <&xtal_27Mhz>;
+               #clock-cells = <1>;
+               xtal-load-pf = <5>;
+               /* PLL options to get SSC 1% centered */
+               PLL2 {
+                       spread-spectrum = <4>;
+                       spread-spectrum-center;
+               };
+       };
index 7628df31b630338dbdd8db733cb422e179176ddd..993d4cfd5aa01e02e7aa3016a92dc74ec477eff7 100644 (file)
@@ -2763,7 +2763,7 @@ F:        Documentation/devicetree/bindings/media/coda.txt
 F:     drivers/media/platform/coda/
 
 COMMON CLK FRAMEWORK
-M:     Mike Turquette <mturquette@linaro.org>
+M:     Michael Turquette <mturquette@baylibre.com>
 M:     Stephen Boyd <sboyd@codeaurora.org>
 L:     linux-clk@vger.kernel.org
 T:     git git://git.kernel.org/pub/scm/linux/kernel/git/clk/linux.git
index a753178abc854a060a29630535667dcd4f7e7ca8..5dfd3a44bf82b38c614da737cea42c6498ef6a73 100644 (file)
                };
        };
 
+       clocks {
+               xinw {
+                       compatible = "fixed-clock";
+                       #clock-cells = <0>;
+                       clock-frequency = <32768>;
+                       clock-output-names = "xinw";
+               };
+               xin {
+                       compatible = "fixed-clock";
+                       #clock-cells = <0>;
+                       clock-frequency = <26000000>;
+                       clock-output-names = "xin";
+               };
+       };
+
        noc {
                compatible = "simple-bus";
                #address-cells = <1>;
index 4bd8b76538175aa2ba4ab3f58a127b94bda08939..5f8ddcdeeacf1117d92313e6cb34608be136a955 100644 (file)
@@ -224,6 +224,25 @@ static void __init exynos_init_irq(void)
        exynos_map_pmu();
 }
 
+static const struct of_device_id exynos_cpufreq_matches[] = {
+       { .compatible = "samsung,exynos4210", .data = "cpufreq-dt" },
+       { /* sentinel */ }
+};
+
+static void __init exynos_cpufreq_init(void)
+{
+       struct device_node *root = of_find_node_by_path("/");
+       const struct of_device_id *match;
+
+       match = of_match_node(exynos_cpufreq_matches, root);
+       if (!match) {
+               platform_device_register_simple("exynos-cpufreq", -1, NULL, 0);
+               return;
+       }
+
+       platform_device_register_simple(match->data, -1, NULL, 0);
+}
+
 static void __init exynos_dt_machine_init(void)
 {
        /*
@@ -246,7 +265,7 @@ static void __init exynos_dt_machine_init(void)
            of_machine_is_compatible("samsung,exynos5250"))
                platform_device_register(&exynos_cpuidle);
 
-       platform_device_register_simple("exynos-cpufreq", -1, NULL, 0);
+       exynos_cpufreq_init();
 
        of_platform_populate(NULL, of_default_bus_match_table, NULL, NULL);
 }
index 9897f353bf1a63f24a0192aeff7ea9785a7c32bf..42f7120ca9ceaa1b900e737efeeb67f0913ae4e4 100644 (file)
@@ -78,6 +78,23 @@ config COMMON_CLK_SI570
          This driver supports Silicon Labs 570/571/598/599 programmable
          clock generators.
 
+config COMMON_CLK_CDCE925
+       tristate "Clock driver for TI CDCE925 devices"
+       depends on I2C
+       depends on OF
+       select REGMAP_I2C
+       help
+       ---help---
+         This driver supports the TI CDCE925 programmable clock synthesizer.
+         The chip contains two PLLs with spread-spectrum clocking support and
+         five output dividers. The driver only supports the following setup,
+         and uses a fixed setting for the output muxes.
+         Y1 is derived from the input clock
+         Y2 and Y3 derive from PLL1
+         Y4 and Y5 derive from PLL2
+         Given a target output frequency, the driver will set the PLL and
+         divider to best approximate the desired output.
+
 config COMMON_CLK_S2MPS11
        tristate "Clock driver for S2MPS1X/S5M8767 MFD"
        depends on MFD_SEC_CORE
@@ -150,11 +167,13 @@ config COMMON_CLK_CDCE706
        ---help---
          This driver supports TI CDCE706 programmable 3-PLL clock synthesizer.
 
+source "drivers/clk/bcm/Kconfig"
+source "drivers/clk/hisilicon/Kconfig"
 source "drivers/clk/qcom/Kconfig"
 
 endmenu
 
-source "drivers/clk/bcm/Kconfig"
 source "drivers/clk/mvebu/Kconfig"
 
 source "drivers/clk/samsung/Kconfig"
+source "drivers/clk/tegra/Kconfig"
index 8732e4c5bf3c131678ec7ee97f9b6e98c2663a39..c4cf075a2320f7ae33327fd79e9d9525c15921c0 100644 (file)
@@ -38,6 +38,8 @@ obj-$(CONFIG_COMMON_CLK_RK808)                += clk-rk808.o
 obj-$(CONFIG_COMMON_CLK_S2MPS11)       += clk-s2mps11.o
 obj-$(CONFIG_COMMON_CLK_SI5351)                += clk-si5351.o
 obj-$(CONFIG_COMMON_CLK_SI570)         += clk-si570.o
+obj-$(CONFIG_COMMON_CLK_CDCE925)       += clk-cdce925.o
+obj-$(CONFIG_ARCH_STM32)               += clk-stm32f4.o
 obj-$(CONFIG_CLK_TWL6040)              += clk-twl6040.o
 obj-$(CONFIG_ARCH_U300)                        += clk-u300.o
 obj-$(CONFIG_ARCH_VT8500)              += clk-vt8500.o
@@ -45,19 +47,20 @@ obj-$(CONFIG_COMMON_CLK_WM831X)             += clk-wm831x.o
 obj-$(CONFIG_COMMON_CLK_XGENE)         += clk-xgene.o
 obj-$(CONFIG_COMMON_CLK_PWM)           += clk-pwm.o
 obj-$(CONFIG_COMMON_CLK_AT91)          += at91/
-obj-$(CONFIG_ARCH_BCM_MOBILE)          += bcm/
+obj-$(CONFIG_ARCH_BCM)                 += bcm/
 obj-$(CONFIG_ARCH_BERLIN)              += berlin/
-obj-$(CONFIG_ARCH_HI3xxx)              += hisilicon/
-obj-$(CONFIG_ARCH_HIP04)               += hisilicon/
-obj-$(CONFIG_ARCH_HIX5HD2)             += hisilicon/
+obj-$(CONFIG_ARCH_HISI)                        += hisilicon/
 obj-$(CONFIG_ARCH_MXC)                 += imx/
 obj-$(CONFIG_MACH_INGENIC)             += ingenic/
 obj-$(CONFIG_COMMON_CLK_KEYSTONE)      += keystone/
+obj-$(CONFIG_ARCH_MEDIATEK)            += mediatek/
 ifeq ($(CONFIG_COMMON_CLK), y)
 obj-$(CONFIG_ARCH_MMP)                 += mmp/
 endif
 obj-$(CONFIG_PLAT_ORION)               += mvebu/
+obj-$(CONFIG_ARCH_MESON)               += meson/
 obj-$(CONFIG_ARCH_MXS)                 += mxs/
+obj-$(CONFIG_ARCH_LPC18XX)             += nxp/
 obj-$(CONFIG_MACH_PISTACHIO)           += pistachio/
 obj-$(CONFIG_COMMON_CLK_PXA)           += pxa/
 obj-$(CONFIG_COMMON_CLK_QCOM)          += qcom/
index 59fa3cc96c9eb3411691970c63799996613dc8fe..c2400456a04471186ec210d8236951d9e4780901 100644 (file)
@@ -614,7 +614,7 @@ void __init of_at91sam9x5_clk_main_setup(struct device_node *np,
        const char *name = np->name;
        int i;
 
-       num_parents = of_count_phandle_with_args(np, "clocks", "#clock-cells");
+       num_parents = of_clk_get_parent_count(np);
        if (num_parents <= 0 || num_parents > 2)
                return;
 
index c1af80bcdf2082c8d0d7b32e28eb9122c59ac53f..f98eafe9b12dc92d1c68f99cd5d9cc86addfb75f 100644 (file)
@@ -224,7 +224,7 @@ of_at91_clk_master_setup(struct device_node *np, struct at91_pmc *pmc,
        const char *name = np->name;
        struct clk_master_characteristics *characteristics;
 
-       num_parents = of_count_phandle_with_args(np, "clocks", "#clock-cells");
+       num_parents = of_clk_get_parent_count(np);
        if (num_parents <= 0 || num_parents > MASTER_SOURCE_MAX)
                return;
 
index 86c8a073dcc32a20b98f4c862d5622b11ffe1d57..8c86c0f7847a55a0cdc257289c49c67777216d73 100644 (file)
@@ -237,7 +237,7 @@ of_at91_clk_prog_setup(struct device_node *np, struct at91_pmc *pmc,
        const char *name;
        struct device_node *progclknp;
 
-       num_parents = of_count_phandle_with_args(np, "clocks", "#clock-cells");
+       num_parents = of_clk_get_parent_count(np);
        if (num_parents <= 0 || num_parents > PROG_SOURCE_MAX)
                return;
 
index 2f13bd5246b5563ec399058029fcd0740c58c3d2..98a84a865fe1cf1b13a437741631b83804e32bf6 100644 (file)
@@ -373,7 +373,7 @@ void __init of_at91sam9x5_clk_slow_setup(struct device_node *np,
        const char *name = np->name;
        int i;
 
-       num_parents = of_count_phandle_with_args(np, "clocks", "#clock-cells");
+       num_parents = of_clk_get_parent_count(np);
        if (num_parents <= 0 || num_parents > 2)
                return;
 
@@ -451,7 +451,7 @@ void __init of_at91sam9260_clk_slow_setup(struct device_node *np,
        const char *name = np->name;
        int i;
 
-       num_parents = of_count_phandle_with_args(np, "clocks", "#clock-cells");
+       num_parents = of_clk_get_parent_count(np);
        if (num_parents != 2)
                return;
 
index 144d47ecfe63c6eb5dd383e2b396e4c59471244f..3817ea865ca258ecb8675f6e35c39be4f53fd424 100644 (file)
@@ -150,7 +150,7 @@ void __init of_at91sam9x5_clk_smd_setup(struct device_node *np,
        const char *parent_names[SMD_SOURCE_MAX];
        const char *name = np->name;
 
-       num_parents = of_count_phandle_with_args(np, "clocks", "#clock-cells");
+       num_parents = of_clk_get_parent_count(np);
        if (num_parents <= 0 || num_parents > SMD_SOURCE_MAX)
                return;
 
index 0b7c3e8840bae0ebf2c97cf276e44e8ab7116f6e..b0cbd2b1ff5957027a5643963d45038435e8b1ce 100644 (file)
@@ -378,7 +378,7 @@ void __init of_at91sam9x5_clk_usb_setup(struct device_node *np,
        const char *parent_names[USB_SOURCE_MAX];
        const char *name = np->name;
 
-       num_parents = of_count_phandle_with_args(np, "clocks", "#clock-cells");
+       num_parents = of_clk_get_parent_count(np);
        if (num_parents <= 0 || num_parents > USB_SOURCE_MAX)
                return;
 
index 3f27d21fb7297e70494bf35743f027f8c8005d73..39be2be82b0a04b730258b4a7154aa5be103cc73 100644 (file)
@@ -153,7 +153,7 @@ static int pmc_irq_domain_xlate(struct irq_domain *d,
        return 0;
 }
 
-static struct irq_domain_ops pmc_irq_ops = {
+static const struct irq_domain_ops pmc_irq_ops = {
        .map    = pmc_irq_map,
        .xlate  = pmc_irq_domain_xlate,
 };
index 75506e53075b95697727763ae155dcc8d7613402..88febf53b276a9253bfaf4045799197901180687 100644 (file)
@@ -7,3 +7,12 @@ config CLK_BCM_KONA
          Enable common clock framework support for Broadcom SoCs
          using "Kona" style clock control units, including those
          in the BCM281xx and BCM21664 families.
+
+config COMMON_CLK_IPROC
+       bool "Broadcom iProc clock support"
+       depends on ARCH_BCM_IPROC
+       depends on COMMON_CLK
+       default ARCH_BCM_IPROC
+       help
+         Enable common clock framework support for Broadcom SoCs
+         based on the iProc architecture
index 6297d05a9a1040a924fcf58914cf8ee2284c11ec..8a7a477862c7037d4d0ff1e9f3cfe0e736df6e51 100644 (file)
@@ -2,3 +2,5 @@ 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_BCM_CYGNUS)  += clk-cygnus.o
diff --git a/drivers/clk/bcm/clk-cygnus.c b/drivers/clk/bcm/clk-cygnus.c
new file mode 100644 (file)
index 0000000..316c603
--- /dev/null
@@ -0,0 +1,265 @@
+/*
+ * Copyright (C) 2014 Broadcom Corporation
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation version 2.
+ *
+ * This program is distributed "as is" WITHOUT ANY WARRANTY of any
+ * kind, whether express or implied; without even the implied warranty
+ * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/kernel.h>
+#include <linux/err.h>
+#include <linux/clk-provider.h>
+#include <linux/io.h>
+#include <linux/of.h>
+#include <linux/clkdev.h>
+#include <linux/of_address.h>
+#include <linux/delay.h>
+
+#include <dt-bindings/clock/bcm-cygnus.h>
+#include "clk-iproc.h"
+
+#define reg_val(o, s, w) { .offset = o, .shift = s, .width = w, }
+
+#define aon_val(o, pw, ps, is) { .offset = o, .pwr_width = pw, \
+       .pwr_shift = ps, .iso_shift = is }
+
+#define sw_ctrl_val(o, s) { .offset = o, .shift = s, }
+
+#define asiu_div_val(o, es, hs, hw, ls, lw) \
+               { .offset = o, .en_shift = es, .high_shift = hs, \
+               .high_width = hw, .low_shift = ls, .low_width = lw }
+
+#define reset_val(o, rs, prs, kis, kiw, kps, kpw, kas, kaw) { .offset = o, \
+       .reset_shift = rs, .p_reset_shift = prs, .ki_shift = kis, \
+       .ki_width = kiw, .kp_shift = kps, .kp_width = kpw, .ka_shift = kas, \
+       .ka_width = kaw }
+
+#define vco_ctrl_val(uo, lo) { .u_offset = uo, .l_offset = lo }
+
+#define enable_val(o, es, hs, bs) { .offset = o, .enable_shift = es, \
+       .hold_shift = hs, .bypass_shift = bs }
+
+#define asiu_gate_val(o, es) { .offset = o, .en_shift = es }
+
+static void __init cygnus_armpll_init(struct device_node *node)
+{
+       iproc_armpll_setup(node);
+}
+CLK_OF_DECLARE(cygnus_armpll, "brcm,cygnus-armpll", cygnus_armpll_init);
+
+static const struct iproc_pll_ctrl genpll = {
+       .flags = IPROC_CLK_AON | IPROC_CLK_PLL_HAS_NDIV_FRAC |
+               IPROC_CLK_PLL_NEEDS_SW_CFG,
+       .aon = aon_val(0x0, 2, 1, 0),
+       .reset = reset_val(0x0, 11, 10, 4, 3, 0, 4, 7, 3),
+       .sw_ctrl = sw_ctrl_val(0x10, 31),
+       .ndiv_int = reg_val(0x10, 20, 10),
+       .ndiv_frac = reg_val(0x10, 0, 20),
+       .pdiv = reg_val(0x14, 0, 4),
+       .vco_ctrl = vco_ctrl_val(0x18, 0x1c),
+       .status = reg_val(0x28, 12, 1),
+};
+
+static const struct iproc_clk_ctrl genpll_clk[] = {
+       [BCM_CYGNUS_GENPLL_AXI21_CLK] = {
+               .channel = BCM_CYGNUS_GENPLL_AXI21_CLK,
+               .flags = IPROC_CLK_AON,
+               .enable = enable_val(0x4, 6, 0, 12),
+               .mdiv = reg_val(0x20, 0, 8),
+       },
+       [BCM_CYGNUS_GENPLL_250MHZ_CLK] = {
+               .channel = BCM_CYGNUS_GENPLL_250MHZ_CLK,
+               .flags = IPROC_CLK_AON,
+               .enable = enable_val(0x4, 7, 1, 13),
+               .mdiv = reg_val(0x20, 10, 8),
+       },
+       [BCM_CYGNUS_GENPLL_IHOST_SYS_CLK] = {
+               .channel = BCM_CYGNUS_GENPLL_IHOST_SYS_CLK,
+               .flags = IPROC_CLK_AON,
+               .enable = enable_val(0x4, 8, 2, 14),
+               .mdiv = reg_val(0x20, 20, 8),
+       },
+       [BCM_CYGNUS_GENPLL_ENET_SW_CLK] = {
+               .channel = BCM_CYGNUS_GENPLL_ENET_SW_CLK,
+               .flags = IPROC_CLK_AON,
+               .enable = enable_val(0x4, 9, 3, 15),
+               .mdiv = reg_val(0x24, 0, 8),
+       },
+       [BCM_CYGNUS_GENPLL_AUDIO_125_CLK] = {
+               .channel = BCM_CYGNUS_GENPLL_AUDIO_125_CLK,
+               .flags = IPROC_CLK_AON,
+               .enable = enable_val(0x4, 10, 4, 16),
+               .mdiv = reg_val(0x24, 10, 8),
+       },
+       [BCM_CYGNUS_GENPLL_CAN_CLK] = {
+               .channel = BCM_CYGNUS_GENPLL_CAN_CLK,
+               .flags = IPROC_CLK_AON,
+               .enable = enable_val(0x4, 11, 5, 17),
+               .mdiv = reg_val(0x24, 20, 8),
+       },
+};
+
+static void __init cygnus_genpll_clk_init(struct device_node *node)
+{
+       iproc_pll_clk_setup(node, &genpll, NULL, 0, genpll_clk,
+                           ARRAY_SIZE(genpll_clk));
+}
+CLK_OF_DECLARE(cygnus_genpll, "brcm,cygnus-genpll", cygnus_genpll_clk_init);
+
+static const struct iproc_pll_ctrl lcpll0 = {
+       .flags = IPROC_CLK_AON | IPROC_CLK_PLL_NEEDS_SW_CFG,
+       .aon = aon_val(0x0, 2, 5, 4),
+       .reset = reset_val(0x0, 31, 30, 27, 3, 23, 4, 19, 4),
+       .sw_ctrl = sw_ctrl_val(0x4, 31),
+       .ndiv_int = reg_val(0x4, 16, 10),
+       .pdiv = reg_val(0x4, 26, 4),
+       .vco_ctrl = vco_ctrl_val(0x10, 0x14),
+       .status = reg_val(0x18, 12, 1),
+};
+
+static const struct iproc_clk_ctrl lcpll0_clk[] = {
+       [BCM_CYGNUS_LCPLL0_PCIE_PHY_REF_CLK] = {
+               .channel = BCM_CYGNUS_LCPLL0_PCIE_PHY_REF_CLK,
+               .flags = IPROC_CLK_AON,
+               .enable = enable_val(0x0, 7, 1, 13),
+               .mdiv = reg_val(0x8, 0, 8),
+       },
+       [BCM_CYGNUS_LCPLL0_DDR_PHY_CLK] = {
+               .channel = BCM_CYGNUS_LCPLL0_DDR_PHY_CLK,
+               .flags = IPROC_CLK_AON,
+               .enable = enable_val(0x0, 8, 2, 14),
+               .mdiv = reg_val(0x8, 10, 8),
+       },
+       [BCM_CYGNUS_LCPLL0_SDIO_CLK] = {
+               .channel = BCM_CYGNUS_LCPLL0_SDIO_CLK,
+               .flags = IPROC_CLK_AON,
+               .enable = enable_val(0x0, 9, 3, 15),
+               .mdiv = reg_val(0x8, 20, 8),
+       },
+       [BCM_CYGNUS_LCPLL0_USB_PHY_REF_CLK] = {
+               .channel = BCM_CYGNUS_LCPLL0_USB_PHY_REF_CLK,
+               .flags = IPROC_CLK_AON,
+               .enable = enable_val(0x0, 10, 4, 16),
+               .mdiv = reg_val(0xc, 0, 8),
+       },
+       [BCM_CYGNUS_LCPLL0_SMART_CARD_CLK] = {
+               .channel = BCM_CYGNUS_LCPLL0_SMART_CARD_CLK,
+               .flags = IPROC_CLK_AON,
+               .enable = enable_val(0x0, 11, 5, 17),
+               .mdiv = reg_val(0xc, 10, 8),
+       },
+       [BCM_CYGNUS_LCPLL0_CH5_UNUSED] = {
+               .channel = BCM_CYGNUS_LCPLL0_CH5_UNUSED,
+               .flags = IPROC_CLK_AON,
+               .enable = enable_val(0x0, 12, 6, 18),
+               .mdiv = reg_val(0xc, 20, 8),
+       },
+};
+
+static void __init cygnus_lcpll0_clk_init(struct device_node *node)
+{
+       iproc_pll_clk_setup(node, &lcpll0, NULL, 0, lcpll0_clk,
+                           ARRAY_SIZE(lcpll0_clk));
+}
+CLK_OF_DECLARE(cygnus_lcpll0, "brcm,cygnus-lcpll0", cygnus_lcpll0_clk_init);
+
+/*
+ * MIPI PLL VCO frequency parameter table
+ */
+static const struct iproc_pll_vco_param mipipll_vco_params[] = {
+       /* rate (Hz) ndiv_int ndiv_frac pdiv */
+       { 750000000UL,   30,     0,        1 },
+       { 1000000000UL,  40,     0,        1 },
+       { 1350000000ul,  54,     0,        1 },
+       { 2000000000UL,  80,     0,        1 },
+       { 2100000000UL,  84,     0,        1 },
+       { 2250000000UL,  90,     0,        1 },
+       { 2500000000UL,  100,    0,        1 },
+       { 2700000000UL,  54,     0,        0 },
+       { 2975000000UL,  119,    0,        1 },
+       { 3100000000UL,  124,    0,        1 },
+       { 3150000000UL,  126,    0,        1 },
+};
+
+static const struct iproc_pll_ctrl mipipll = {
+       .flags = IPROC_CLK_PLL_ASIU | IPROC_CLK_PLL_HAS_NDIV_FRAC |
+                IPROC_CLK_NEEDS_READ_BACK,
+       .aon = aon_val(0x0, 4, 17, 16),
+       .asiu = asiu_gate_val(0x0, 3),
+       .reset = reset_val(0x0, 11, 10, 4, 3, 0, 4, 7, 4),
+       .ndiv_int = reg_val(0x10, 20, 10),
+       .ndiv_frac = reg_val(0x10, 0, 20),
+       .pdiv = reg_val(0x14, 0, 4),
+       .vco_ctrl = vco_ctrl_val(0x18, 0x1c),
+       .status = reg_val(0x28, 12, 1),
+};
+
+static const struct iproc_clk_ctrl mipipll_clk[] = {
+       [BCM_CYGNUS_MIPIPLL_CH0_UNUSED] = {
+               .channel = BCM_CYGNUS_MIPIPLL_CH0_UNUSED,
+               .flags = IPROC_CLK_NEEDS_READ_BACK,
+               .enable = enable_val(0x4, 12, 6, 18),
+               .mdiv = reg_val(0x20, 0, 8),
+       },
+       [BCM_CYGNUS_MIPIPLL_CH1_LCD] = {
+               .channel = BCM_CYGNUS_MIPIPLL_CH1_LCD,
+               .flags = IPROC_CLK_NEEDS_READ_BACK,
+               .enable = enable_val(0x4, 13, 7, 19),
+               .mdiv = reg_val(0x20, 10, 8),
+       },
+       [BCM_CYGNUS_MIPIPLL_CH2_V3D] = {
+               .channel = BCM_CYGNUS_MIPIPLL_CH2_V3D,
+               .flags = IPROC_CLK_NEEDS_READ_BACK,
+               .enable = enable_val(0x4, 14, 8, 20),
+               .mdiv = reg_val(0x20, 20, 8),
+       },
+       [BCM_CYGNUS_MIPIPLL_CH3_UNUSED] = {
+               .channel = BCM_CYGNUS_MIPIPLL_CH3_UNUSED,
+               .flags = IPROC_CLK_NEEDS_READ_BACK,
+               .enable = enable_val(0x4, 15, 9, 21),
+               .mdiv = reg_val(0x24, 0, 8),
+       },
+       [BCM_CYGNUS_MIPIPLL_CH4_UNUSED] = {
+               .channel = BCM_CYGNUS_MIPIPLL_CH4_UNUSED,
+               .flags = IPROC_CLK_NEEDS_READ_BACK,
+               .enable = enable_val(0x4, 16, 10, 22),
+               .mdiv = reg_val(0x24, 10, 8),
+       },
+       [BCM_CYGNUS_MIPIPLL_CH5_UNUSED] = {
+               .channel = BCM_CYGNUS_MIPIPLL_CH5_UNUSED,
+               .flags = IPROC_CLK_NEEDS_READ_BACK,
+               .enable = enable_val(0x4, 17, 11, 23),
+               .mdiv = reg_val(0x24, 20, 8),
+       },
+};
+
+static void __init cygnus_mipipll_clk_init(struct device_node *node)
+{
+       iproc_pll_clk_setup(node, &mipipll, mipipll_vco_params,
+                           ARRAY_SIZE(mipipll_vco_params), mipipll_clk,
+                           ARRAY_SIZE(mipipll_clk));
+}
+CLK_OF_DECLARE(cygnus_mipipll, "brcm,cygnus-mipipll", cygnus_mipipll_clk_init);
+
+static const struct iproc_asiu_div asiu_div[] = {
+       [BCM_CYGNUS_ASIU_KEYPAD_CLK] = asiu_div_val(0x0, 31, 16, 10, 0, 10),
+       [BCM_CYGNUS_ASIU_ADC_CLK] = asiu_div_val(0x4, 31, 16, 10, 0, 10),
+       [BCM_CYGNUS_ASIU_PWM_CLK] = asiu_div_val(0x8, 31, 16, 10, 0, 10),
+};
+
+static const struct iproc_asiu_gate asiu_gate[] = {
+       [BCM_CYGNUS_ASIU_KEYPAD_CLK] = asiu_gate_val(0x0, 7),
+       [BCM_CYGNUS_ASIU_ADC_CLK] = asiu_gate_val(0x0, 9),
+       [BCM_CYGNUS_ASIU_PWM_CLK] = asiu_gate_val(IPROC_CLK_INVALID_OFFSET, 0),
+};
+
+static void __init cygnus_asiu_init(struct device_node *node)
+{
+       iproc_asiu_setup(node, asiu_div, asiu_gate, ARRAY_SIZE(asiu_div));
+}
+CLK_OF_DECLARE(cygnus_asiu_clk, "brcm,cygnus-asiu-clk", cygnus_asiu_init);
diff --git a/drivers/clk/bcm/clk-iproc-armpll.c b/drivers/clk/bcm/clk-iproc-armpll.c
new file mode 100644 (file)
index 0000000..a196ee2
--- /dev/null
@@ -0,0 +1,282 @@
+/*
+ * Copyright (C) 2014 Broadcom Corporation
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation version 2.
+ *
+ * This program is distributed "as is" WITHOUT ANY WARRANTY of any
+ * kind, whether express or implied; without even the implied warranty
+ * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/kernel.h>
+#include <linux/slab.h>
+#include <linux/err.h>
+#include <linux/clk-provider.h>
+#include <linux/io.h>
+#include <linux/of.h>
+#include <linux/clkdev.h>
+#include <linux/of_address.h>
+
+#define IPROC_CLK_MAX_FREQ_POLICY                    0x3
+#define IPROC_CLK_POLICY_FREQ_OFFSET                 0x008
+#define IPROC_CLK_POLICY_FREQ_POLICY_FREQ_SHIFT      8
+#define IPROC_CLK_POLICY_FREQ_POLICY_FREQ_MASK       0x7
+
+#define IPROC_CLK_PLLARMA_OFFSET                     0xc00
+#define IPROC_CLK_PLLARMA_LOCK_SHIFT                 28
+#define IPROC_CLK_PLLARMA_PDIV_SHIFT                 24
+#define IPROC_CLK_PLLARMA_PDIV_MASK                  0xf
+#define IPROC_CLK_PLLARMA_NDIV_INT_SHIFT             8
+#define IPROC_CLK_PLLARMA_NDIV_INT_MASK              0x3ff
+
+#define IPROC_CLK_PLLARMB_OFFSET                     0xc04
+#define IPROC_CLK_PLLARMB_NDIV_FRAC_MASK             0xfffff
+
+#define IPROC_CLK_PLLARMC_OFFSET                     0xc08
+#define IPROC_CLK_PLLARMC_BYPCLK_EN_SHIFT            8
+#define IPROC_CLK_PLLARMC_MDIV_MASK                  0xff
+
+#define IPROC_CLK_PLLARMCTL5_OFFSET                  0xc20
+#define IPROC_CLK_PLLARMCTL5_H_MDIV_MASK             0xff
+
+#define IPROC_CLK_PLLARM_OFFSET_OFFSET               0xc24
+#define IPROC_CLK_PLLARM_SW_CTL_SHIFT                29
+#define IPROC_CLK_PLLARM_NDIV_INT_OFFSET_SHIFT       20
+#define IPROC_CLK_PLLARM_NDIV_INT_OFFSET_MASK        0xff
+#define IPROC_CLK_PLLARM_NDIV_FRAC_OFFSET_MASK       0xfffff
+
+#define IPROC_CLK_ARM_DIV_OFFSET                     0xe00
+#define IPROC_CLK_ARM_DIV_PLL_SELECT_OVERRIDE_SHIFT  4
+#define IPROC_CLK_ARM_DIV_ARM_PLL_SELECT_MASK        0xf
+
+#define IPROC_CLK_POLICY_DBG_OFFSET                  0xec0
+#define IPROC_CLK_POLICY_DBG_ACT_FREQ_SHIFT          12
+#define IPROC_CLK_POLICY_DBG_ACT_FREQ_MASK           0x7
+
+enum iproc_arm_pll_fid {
+       ARM_PLL_FID_CRYSTAL_CLK   = 0,
+       ARM_PLL_FID_SYS_CLK       = 2,
+       ARM_PLL_FID_CH0_SLOW_CLK  = 6,
+       ARM_PLL_FID_CH1_FAST_CLK  = 7
+};
+
+struct iproc_arm_pll {
+       struct clk_hw hw;
+       void __iomem *base;
+       unsigned long rate;
+};
+
+#define to_iproc_arm_pll(hw) container_of(hw, struct iproc_arm_pll, hw)
+
+static unsigned int __get_fid(struct iproc_arm_pll *pll)
+{
+       u32 val;
+       unsigned int policy, fid, active_fid;
+
+       val = readl(pll->base + IPROC_CLK_ARM_DIV_OFFSET);
+       if (val & (1 << IPROC_CLK_ARM_DIV_PLL_SELECT_OVERRIDE_SHIFT))
+               policy = val & IPROC_CLK_ARM_DIV_ARM_PLL_SELECT_MASK;
+       else
+               policy = 0;
+
+       /* something is seriously wrong */
+       BUG_ON(policy > IPROC_CLK_MAX_FREQ_POLICY);
+
+       val = readl(pll->base + IPROC_CLK_POLICY_FREQ_OFFSET);
+       fid = (val >> (IPROC_CLK_POLICY_FREQ_POLICY_FREQ_SHIFT * policy)) &
+               IPROC_CLK_POLICY_FREQ_POLICY_FREQ_MASK;
+
+       val = readl(pll->base + IPROC_CLK_POLICY_DBG_OFFSET);
+       active_fid = IPROC_CLK_POLICY_DBG_ACT_FREQ_MASK &
+               (val >> IPROC_CLK_POLICY_DBG_ACT_FREQ_SHIFT);
+       if (fid != active_fid) {
+               pr_debug("%s: fid override %u->%u\n", __func__, fid,
+                               active_fid);
+               fid = active_fid;
+       }
+
+       pr_debug("%s: active fid: %u\n", __func__, fid);
+
+       return fid;
+}
+
+/*
+ * Determine the mdiv (post divider) based on the frequency ID being used.
+ * There are 4 sources that can be used to derive the output clock rate:
+ *    - 25 MHz Crystal
+ *    - System clock
+ *    - PLL channel 0 (slow clock)
+ *    - PLL channel 1 (fast clock)
+ */
+static int __get_mdiv(struct iproc_arm_pll *pll)
+{
+       unsigned int fid;
+       int mdiv;
+       u32 val;
+
+       fid = __get_fid(pll);
+
+       switch (fid) {
+       case ARM_PLL_FID_CRYSTAL_CLK:
+       case ARM_PLL_FID_SYS_CLK:
+               mdiv = 1;
+               break;
+
+       case ARM_PLL_FID_CH0_SLOW_CLK:
+               val = readl(pll->base + IPROC_CLK_PLLARMC_OFFSET);
+               mdiv = val & IPROC_CLK_PLLARMC_MDIV_MASK;
+               if (mdiv == 0)
+                       mdiv = 256;
+               break;
+
+       case ARM_PLL_FID_CH1_FAST_CLK:
+               val = readl(pll->base + IPROC_CLK_PLLARMCTL5_OFFSET);
+               mdiv = val & IPROC_CLK_PLLARMCTL5_H_MDIV_MASK;
+               if (mdiv == 0)
+                       mdiv = 256;
+               break;
+
+       default:
+               mdiv = -EFAULT;
+       }
+
+       return mdiv;
+}
+
+static unsigned int __get_ndiv(struct iproc_arm_pll *pll)
+{
+       u32 val;
+       unsigned int ndiv_int, ndiv_frac, ndiv;
+
+       val = readl(pll->base + IPROC_CLK_PLLARM_OFFSET_OFFSET);
+       if (val & (1 << IPROC_CLK_PLLARM_SW_CTL_SHIFT)) {
+               /*
+                * offset mode is active. Read the ndiv from the PLLARM OFFSET
+                * register
+                */
+               ndiv_int = (val >> IPROC_CLK_PLLARM_NDIV_INT_OFFSET_SHIFT) &
+                       IPROC_CLK_PLLARM_NDIV_INT_OFFSET_MASK;
+               if (ndiv_int == 0)
+                       ndiv_int = 256;
+
+               ndiv_frac = val & IPROC_CLK_PLLARM_NDIV_FRAC_OFFSET_MASK;
+       } else {
+               /* offset mode not active */
+               val = readl(pll->base + IPROC_CLK_PLLARMA_OFFSET);
+               ndiv_int = (val >> IPROC_CLK_PLLARMA_NDIV_INT_SHIFT) &
+                       IPROC_CLK_PLLARMA_NDIV_INT_MASK;
+               if (ndiv_int == 0)
+                       ndiv_int = 1024;
+
+               val = readl(pll->base + IPROC_CLK_PLLARMB_OFFSET);
+               ndiv_frac = val & IPROC_CLK_PLLARMB_NDIV_FRAC_MASK;
+       }
+
+       ndiv = (ndiv_int << 20) | ndiv_frac;
+
+       return ndiv;
+}
+
+/*
+ * The output frequency of the ARM PLL is calculated based on the ARM PLL
+ * divider values:
+ *   pdiv = ARM PLL pre-divider
+ *   ndiv = ARM PLL multiplier
+ *   mdiv = ARM PLL post divider
+ *
+ * The frequency is calculated by:
+ *   ((ndiv * parent clock rate) / pdiv) / mdiv
+ */
+static unsigned long iproc_arm_pll_recalc_rate(struct clk_hw *hw,
+               unsigned long parent_rate)
+{
+       struct iproc_arm_pll *pll = to_iproc_arm_pll(hw);
+       u32 val;
+       int mdiv;
+       u64 ndiv;
+       unsigned int pdiv;
+
+       /* in bypass mode, use parent rate */
+       val = readl(pll->base + IPROC_CLK_PLLARMC_OFFSET);
+       if (val & (1 << IPROC_CLK_PLLARMC_BYPCLK_EN_SHIFT)) {
+               pll->rate = parent_rate;
+               return pll->rate;
+       }
+
+       /* PLL needs to be locked */
+       val = readl(pll->base + IPROC_CLK_PLLARMA_OFFSET);
+       if (!(val & (1 << IPROC_CLK_PLLARMA_LOCK_SHIFT))) {
+               pll->rate = 0;
+               return 0;
+       }
+
+       pdiv = (val >> IPROC_CLK_PLLARMA_PDIV_SHIFT) &
+               IPROC_CLK_PLLARMA_PDIV_MASK;
+       if (pdiv == 0)
+               pdiv = 16;
+
+       ndiv = __get_ndiv(pll);
+       mdiv = __get_mdiv(pll);
+       if (mdiv <= 0) {
+               pll->rate = 0;
+               return 0;
+       }
+       pll->rate = (ndiv * parent_rate) >> 20;
+       pll->rate = (pll->rate / pdiv) / mdiv;
+
+       pr_debug("%s: ARM PLL rate: %lu. parent rate: %lu\n", __func__,
+                pll->rate, parent_rate);
+       pr_debug("%s: ndiv_int: %u, pdiv: %u, mdiv: %d\n", __func__,
+                (unsigned int)(ndiv >> 20), pdiv, mdiv);
+
+       return pll->rate;
+}
+
+static const struct clk_ops iproc_arm_pll_ops = {
+       .recalc_rate = iproc_arm_pll_recalc_rate,
+};
+
+void __init iproc_armpll_setup(struct device_node *node)
+{
+       int ret;
+       struct clk *clk;
+       struct iproc_arm_pll *pll;
+       struct clk_init_data init;
+       const char *parent_name;
+
+       pll = kzalloc(sizeof(*pll), GFP_KERNEL);
+       if (WARN_ON(!pll))
+               return;
+
+       pll->base = of_iomap(node, 0);
+       if (WARN_ON(!pll->base))
+               goto err_free_pll;
+
+       init.name = node->name;
+       init.ops = &iproc_arm_pll_ops;
+       init.flags = 0;
+       parent_name = of_clk_get_parent_name(node, 0);
+       init.parent_names = (parent_name ? &parent_name : NULL);
+       init.num_parents = (parent_name ? 1 : 0);
+       pll->hw.init = &init;
+
+       clk = clk_register(NULL, &pll->hw);
+       if (WARN_ON(IS_ERR(clk)))
+               goto err_iounmap;
+
+       ret = of_clk_add_provider(node, of_clk_src_simple_get, clk);
+       if (WARN_ON(ret))
+               goto err_clk_unregister;
+
+       return;
+
+err_clk_unregister:
+       clk_unregister(clk);
+err_iounmap:
+       iounmap(pll->base);
+err_free_pll:
+       kfree(pll);
+}
diff --git a/drivers/clk/bcm/clk-iproc-asiu.c b/drivers/clk/bcm/clk-iproc-asiu.c
new file mode 100644 (file)
index 0000000..e19c09c
--- /dev/null
@@ -0,0 +1,276 @@
+/*
+ * Copyright (C) 2014 Broadcom Corporation
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation version 2.
+ *
+ * This program is distributed "as is" WITHOUT ANY WARRANTY of any
+ * kind, whether express or implied; without even the implied warranty
+ * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/kernel.h>
+#include <linux/err.h>
+#include <linux/clk-provider.h>
+#include <linux/io.h>
+#include <linux/of.h>
+#include <linux/clkdev.h>
+#include <linux/of_address.h>
+#include <linux/delay.h>
+
+#include "clk-iproc.h"
+
+struct iproc_asiu;
+
+struct iproc_asiu_clk {
+       struct clk_hw hw;
+       const char *name;
+       struct iproc_asiu *asiu;
+       unsigned long rate;
+       struct iproc_asiu_div div;
+       struct iproc_asiu_gate gate;
+};
+
+struct iproc_asiu {
+       void __iomem *div_base;
+       void __iomem *gate_base;
+
+       struct clk_onecell_data clk_data;
+       struct iproc_asiu_clk *clks;
+};
+
+#define to_asiu_clk(hw) container_of(hw, struct iproc_asiu_clk, hw)
+
+static int iproc_asiu_clk_enable(struct clk_hw *hw)
+{
+       struct iproc_asiu_clk *clk = to_asiu_clk(hw);
+       struct iproc_asiu *asiu = clk->asiu;
+       u32 val;
+
+       /* some clocks at the ASIU level are always enabled */
+       if (clk->gate.offset == IPROC_CLK_INVALID_OFFSET)
+               return 0;
+
+       val = readl(asiu->gate_base + clk->gate.offset);
+       val |= (1 << clk->gate.en_shift);
+       writel(val, asiu->gate_base + clk->gate.offset);
+
+       return 0;
+}
+
+static void iproc_asiu_clk_disable(struct clk_hw *hw)
+{
+       struct iproc_asiu_clk *clk = to_asiu_clk(hw);
+       struct iproc_asiu *asiu = clk->asiu;
+       u32 val;
+
+       /* some clocks at the ASIU level are always enabled */
+       if (clk->gate.offset == IPROC_CLK_INVALID_OFFSET)
+               return;
+
+       val = readl(asiu->gate_base + clk->gate.offset);
+       val &= ~(1 << clk->gate.en_shift);
+       writel(val, asiu->gate_base + clk->gate.offset);
+}
+
+static unsigned long iproc_asiu_clk_recalc_rate(struct clk_hw *hw,
+                                               unsigned long parent_rate)
+{
+       struct iproc_asiu_clk *clk = to_asiu_clk(hw);
+       struct iproc_asiu *asiu = clk->asiu;
+       u32 val;
+       unsigned int div_h, div_l;
+
+       if (parent_rate == 0) {
+               clk->rate = 0;
+               return 0;
+       }
+
+       /* if clock divisor is not enabled, simply return parent rate */
+       val = readl(asiu->div_base + clk->div.offset);
+       if ((val & (1 << clk->div.en_shift)) == 0) {
+               clk->rate = parent_rate;
+               return parent_rate;
+       }
+
+       /* clock rate = parent rate / (high_div + 1) + (low_div + 1) */
+       div_h = (val >> clk->div.high_shift) & bit_mask(clk->div.high_width);
+       div_h++;
+       div_l = (val >> clk->div.low_shift) & bit_mask(clk->div.low_width);
+       div_l++;
+
+       clk->rate = parent_rate / (div_h + div_l);
+       pr_debug("%s: rate: %lu. parent rate: %lu div_h: %u div_l: %u\n",
+                __func__, clk->rate, parent_rate, div_h, div_l);
+
+       return clk->rate;
+}
+
+static long iproc_asiu_clk_round_rate(struct clk_hw *hw, unsigned long rate,
+                                     unsigned long *parent_rate)
+{
+       unsigned int div;
+
+       if (rate == 0 || *parent_rate == 0)
+               return -EINVAL;
+
+       if (rate == *parent_rate)
+               return *parent_rate;
+
+       div = DIV_ROUND_UP(*parent_rate, rate);
+       if (div < 2)
+               return *parent_rate;
+
+       return *parent_rate / div;
+}
+
+static int iproc_asiu_clk_set_rate(struct clk_hw *hw, unsigned long rate,
+                                  unsigned long parent_rate)
+{
+       struct iproc_asiu_clk *clk = to_asiu_clk(hw);
+       struct iproc_asiu *asiu = clk->asiu;
+       unsigned int div, div_h, div_l;
+       u32 val;
+
+       if (rate == 0 || parent_rate == 0)
+               return -EINVAL;
+
+       /* simply disable the divisor if one wants the same rate as parent */
+       if (rate == parent_rate) {
+               val = readl(asiu->div_base + clk->div.offset);
+               val &= ~(1 << clk->div.en_shift);
+               writel(val, asiu->div_base + clk->div.offset);
+               return 0;
+       }
+
+       div = DIV_ROUND_UP(parent_rate, rate);
+       if (div < 2)
+               return -EINVAL;
+
+       div_h = div_l = div >> 1;
+       div_h--;
+       div_l--;
+
+       val = readl(asiu->div_base + clk->div.offset);
+       val |= 1 << clk->div.en_shift;
+       if (div_h) {
+               val &= ~(bit_mask(clk->div.high_width)
+                        << clk->div.high_shift);
+               val |= div_h << clk->div.high_shift;
+       } else {
+               val &= ~(bit_mask(clk->div.high_width)
+                        << clk->div.high_shift);
+       }
+       if (div_l) {
+               val &= ~(bit_mask(clk->div.low_width) << clk->div.low_shift);
+               val |= div_l << clk->div.low_shift;
+       } else {
+               val &= ~(bit_mask(clk->div.low_width) << clk->div.low_shift);
+       }
+       writel(val, asiu->div_base + clk->div.offset);
+
+       return 0;
+}
+
+static const struct clk_ops iproc_asiu_ops = {
+       .enable = iproc_asiu_clk_enable,
+       .disable = iproc_asiu_clk_disable,
+       .recalc_rate = iproc_asiu_clk_recalc_rate,
+       .round_rate = iproc_asiu_clk_round_rate,
+       .set_rate = iproc_asiu_clk_set_rate,
+};
+
+void __init iproc_asiu_setup(struct device_node *node,
+                            const struct iproc_asiu_div *div,
+                            const struct iproc_asiu_gate *gate,
+                            unsigned int num_clks)
+{
+       int i, ret;
+       struct iproc_asiu *asiu;
+
+       if (WARN_ON(!gate || !div))
+               return;
+
+       asiu = kzalloc(sizeof(*asiu), GFP_KERNEL);
+       if (WARN_ON(!asiu))
+               return;
+
+       asiu->clk_data.clk_num = num_clks;
+       asiu->clk_data.clks = kcalloc(num_clks, sizeof(*asiu->clk_data.clks),
+                                     GFP_KERNEL);
+       if (WARN_ON(!asiu->clk_data.clks))
+               goto err_clks;
+
+       asiu->clks = kcalloc(num_clks, sizeof(*asiu->clks), GFP_KERNEL);
+       if (WARN_ON(!asiu->clks))
+               goto err_asiu_clks;
+
+       asiu->div_base = of_iomap(node, 0);
+       if (WARN_ON(!asiu->div_base))
+               goto err_iomap_div;
+
+       asiu->gate_base = of_iomap(node, 1);
+       if (WARN_ON(!asiu->gate_base))
+               goto err_iomap_gate;
+
+       for (i = 0; i < num_clks; i++) {
+               struct clk_init_data init;
+               struct clk *clk;
+               const char *parent_name;
+               struct iproc_asiu_clk *asiu_clk;
+               const char *clk_name;
+
+               clk_name = kzalloc(IPROC_CLK_NAME_LEN, GFP_KERNEL);
+               if (WARN_ON(!clk_name))
+                       goto err_clk_register;
+
+               ret = of_property_read_string_index(node, "clock-output-names",
+                                                   i, &clk_name);
+               if (WARN_ON(ret))
+                       goto err_clk_register;
+
+               asiu_clk = &asiu->clks[i];
+               asiu_clk->name = clk_name;
+               asiu_clk->asiu = asiu;
+               asiu_clk->div = div[i];
+               asiu_clk->gate = gate[i];
+               init.name = clk_name;
+               init.ops = &iproc_asiu_ops;
+               init.flags = 0;
+               parent_name = of_clk_get_parent_name(node, 0);
+               init.parent_names = (parent_name ? &parent_name : NULL);
+               init.num_parents = (parent_name ? 1 : 0);
+               asiu_clk->hw.init = &init;
+
+               clk = clk_register(NULL, &asiu_clk->hw);
+               if (WARN_ON(IS_ERR(clk)))
+                       goto err_clk_register;
+               asiu->clk_data.clks[i] = clk;
+       }
+
+       ret = of_clk_add_provider(node, of_clk_src_onecell_get,
+                                 &asiu->clk_data);
+       if (WARN_ON(ret))
+               goto err_clk_register;
+
+       return;
+
+err_clk_register:
+       for (i = 0; i < num_clks; i++)
+               kfree(asiu->clks[i].name);
+       iounmap(asiu->gate_base);
+
+err_iomap_gate:
+       iounmap(asiu->div_base);
+
+err_iomap_div:
+       kfree(asiu->clks);
+
+err_asiu_clks:
+       kfree(asiu->clk_data.clks);
+
+err_clks:
+       kfree(asiu);
+}
diff --git a/drivers/clk/bcm/clk-iproc-pll.c b/drivers/clk/bcm/clk-iproc-pll.c
new file mode 100644 (file)
index 0000000..46fb84b
--- /dev/null
@@ -0,0 +1,716 @@
+/*
+ * Copyright (C) 2014 Broadcom Corporation
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation version 2.
+ *
+ * This program is distributed "as is" WITHOUT ANY WARRANTY of any
+ * kind, whether express or implied; without even the implied warranty
+ * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/kernel.h>
+#include <linux/err.h>
+#include <linux/clk-provider.h>
+#include <linux/io.h>
+#include <linux/of.h>
+#include <linux/clkdev.h>
+#include <linux/of_address.h>
+#include <linux/delay.h>
+
+#include "clk-iproc.h"
+
+#define PLL_VCO_HIGH_SHIFT 19
+#define PLL_VCO_LOW_SHIFT  30
+
+/* number of delay loops waiting for PLL to lock */
+#define LOCK_DELAY 100
+
+/* number of VCO frequency bands */
+#define NUM_FREQ_BANDS 8
+
+#define NUM_KP_BANDS 3
+enum kp_band {
+       KP_BAND_MID = 0,
+       KP_BAND_HIGH,
+       KP_BAND_HIGH_HIGH
+};
+
+static const unsigned int kp_table[NUM_KP_BANDS][NUM_FREQ_BANDS] = {
+       { 5, 6, 6, 7, 7, 8, 9, 10 },
+       { 4, 4, 5, 5, 6, 7, 8, 9  },
+       { 4, 5, 5, 6, 7, 8, 9, 10 },
+};
+
+static const unsigned long ref_freq_table[NUM_FREQ_BANDS][2] = {
+       { 10000000,  12500000  },
+       { 12500000,  15000000  },
+       { 15000000,  20000000  },
+       { 20000000,  25000000  },
+       { 25000000,  50000000  },
+       { 50000000,  75000000  },
+       { 75000000,  100000000 },
+       { 100000000, 125000000 },
+};
+
+enum vco_freq_range {
+       VCO_LOW       = 700000000U,
+       VCO_MID       = 1200000000U,
+       VCO_HIGH      = 2200000000U,
+       VCO_HIGH_HIGH = 3100000000U,
+       VCO_MAX       = 4000000000U,
+};
+
+struct iproc_pll;
+
+struct iproc_clk {
+       struct clk_hw hw;
+       const char *name;
+       struct iproc_pll *pll;
+       unsigned long rate;
+       const struct iproc_clk_ctrl *ctrl;
+};
+
+struct iproc_pll {
+       void __iomem *pll_base;
+       void __iomem *pwr_base;
+       void __iomem *asiu_base;
+
+       const struct iproc_pll_ctrl *ctrl;
+       const struct iproc_pll_vco_param *vco_param;
+       unsigned int num_vco_entries;
+
+       struct clk_onecell_data clk_data;
+       struct iproc_clk *clks;
+};
+
+#define to_iproc_clk(hw) container_of(hw, struct iproc_clk, hw)
+
+/*
+ * Based on the target frequency, find a match from the VCO frequency parameter
+ * table and return its index
+ */
+static int pll_get_rate_index(struct iproc_pll *pll, unsigned int target_rate)
+{
+       int i;
+
+       for (i = 0; i < pll->num_vco_entries; i++)
+               if (target_rate == pll->vco_param[i].rate)
+                       break;
+
+       if (i >= pll->num_vco_entries)
+               return -EINVAL;
+
+       return i;
+}
+
+static int get_kp(unsigned long ref_freq, enum kp_band kp_index)
+{
+       int i;
+
+       if (ref_freq < ref_freq_table[0][0])
+               return -EINVAL;
+
+       for (i = 0; i < NUM_FREQ_BANDS; i++) {
+               if (ref_freq >= ref_freq_table[i][0] &&
+                   ref_freq < ref_freq_table[i][1])
+                       return kp_table[kp_index][i];
+       }
+       return -EINVAL;
+}
+
+static int pll_wait_for_lock(struct iproc_pll *pll)
+{
+       int i;
+       const struct iproc_pll_ctrl *ctrl = pll->ctrl;
+
+       for (i = 0; i < LOCK_DELAY; i++) {
+               u32 val = readl(pll->pll_base + ctrl->status.offset);
+
+               if (val & (1 << ctrl->status.shift))
+                       return 0;
+               udelay(10);
+       }
+
+       return -EIO;
+}
+
+static void __pll_disable(struct iproc_pll *pll)
+{
+       const struct iproc_pll_ctrl *ctrl = pll->ctrl;
+       u32 val;
+
+       if (ctrl->flags & IPROC_CLK_PLL_ASIU) {
+               val = readl(pll->asiu_base + ctrl->asiu.offset);
+               val &= ~(1 << ctrl->asiu.en_shift);
+               writel(val, pll->asiu_base + ctrl->asiu.offset);
+       }
+
+       /* latch input value so core power can be shut down */
+       val = readl(pll->pwr_base + ctrl->aon.offset);
+       val |= (1 << ctrl->aon.iso_shift);
+       writel(val, pll->pwr_base + ctrl->aon.offset);
+
+       /* power down the core */
+       val &= ~(bit_mask(ctrl->aon.pwr_width) << ctrl->aon.pwr_shift);
+       writel(val, pll->pwr_base + ctrl->aon.offset);
+}
+
+static int __pll_enable(struct iproc_pll *pll)
+{
+       const struct iproc_pll_ctrl *ctrl = pll->ctrl;
+       u32 val;
+
+       /* power up the PLL and make sure it's not latched */
+       val = readl(pll->pwr_base + ctrl->aon.offset);
+       val |= bit_mask(ctrl->aon.pwr_width) << ctrl->aon.pwr_shift;
+       val &= ~(1 << ctrl->aon.iso_shift);
+       writel(val, pll->pwr_base + ctrl->aon.offset);
+
+       /* certain PLLs also need to be ungated from the ASIU top level */
+       if (ctrl->flags & IPROC_CLK_PLL_ASIU) {
+               val = readl(pll->asiu_base + ctrl->asiu.offset);
+               val |= (1 << ctrl->asiu.en_shift);
+               writel(val, pll->asiu_base + ctrl->asiu.offset);
+       }
+
+       return 0;
+}
+
+static void __pll_put_in_reset(struct iproc_pll *pll)
+{
+       u32 val;
+       const struct iproc_pll_ctrl *ctrl = pll->ctrl;
+       const struct iproc_pll_reset_ctrl *reset = &ctrl->reset;
+
+       val = readl(pll->pll_base + reset->offset);
+       val &= ~(1 << reset->reset_shift | 1 << reset->p_reset_shift);
+       writel(val, pll->pll_base + reset->offset);
+       if (unlikely(ctrl->flags & IPROC_CLK_NEEDS_READ_BACK))
+               readl(pll->pll_base + reset->offset);
+}
+
+static void __pll_bring_out_reset(struct iproc_pll *pll, unsigned int kp,
+                                 unsigned int ka, unsigned int ki)
+{
+       u32 val;
+       const struct iproc_pll_ctrl *ctrl = pll->ctrl;
+       const struct iproc_pll_reset_ctrl *reset = &ctrl->reset;
+
+       val = readl(pll->pll_base + reset->offset);
+       val &= ~(bit_mask(reset->ki_width) << reset->ki_shift |
+                bit_mask(reset->kp_width) << reset->kp_shift |
+                bit_mask(reset->ka_width) << reset->ka_shift);
+       val |=  ki << reset->ki_shift | kp << reset->kp_shift |
+               ka << reset->ka_shift;
+       val |= 1 << reset->reset_shift | 1 << reset->p_reset_shift;
+       writel(val, pll->pll_base + reset->offset);
+       if (unlikely(ctrl->flags & IPROC_CLK_NEEDS_READ_BACK))
+               readl(pll->pll_base + reset->offset);
+}
+
+static int pll_set_rate(struct iproc_clk *clk, unsigned int rate_index,
+                       unsigned long parent_rate)
+{
+       struct iproc_pll *pll = clk->pll;
+       const struct iproc_pll_vco_param *vco = &pll->vco_param[rate_index];
+       const struct iproc_pll_ctrl *ctrl = pll->ctrl;
+       int ka = 0, ki, kp, ret;
+       unsigned long rate = vco->rate;
+       u32 val;
+       enum kp_band kp_index;
+       unsigned long ref_freq;
+
+       /*
+        * reference frequency = parent frequency / PDIV
+        * If PDIV = 0, then it becomes a multiplier (x2)
+        */
+       if (vco->pdiv == 0)
+               ref_freq = parent_rate * 2;
+       else
+               ref_freq = parent_rate / vco->pdiv;
+
+       /* determine Ki and Kp index based on target VCO frequency */
+       if (rate >= VCO_LOW && rate < VCO_HIGH) {
+               ki = 4;
+               kp_index = KP_BAND_MID;
+       } else if (rate >= VCO_HIGH && rate && rate < VCO_HIGH_HIGH) {
+               ki = 3;
+               kp_index = KP_BAND_HIGH;
+       } else if (rate >= VCO_HIGH_HIGH && rate < VCO_MAX) {
+               ki = 3;
+               kp_index = KP_BAND_HIGH_HIGH;
+       } else {
+               pr_err("%s: pll: %s has invalid rate: %lu\n", __func__,
+                               clk->name, rate);
+               return -EINVAL;
+       }
+
+       kp = get_kp(ref_freq, kp_index);
+       if (kp < 0) {
+               pr_err("%s: pll: %s has invalid kp\n", __func__, clk->name);
+               return kp;
+       }
+
+       ret = __pll_enable(pll);
+       if (ret) {
+               pr_err("%s: pll: %s fails to enable\n", __func__, clk->name);
+               return ret;
+       }
+
+       /* put PLL in reset */
+       __pll_put_in_reset(pll);
+
+       writel(0, pll->pll_base + ctrl->vco_ctrl.u_offset);
+       if (unlikely(ctrl->flags & IPROC_CLK_NEEDS_READ_BACK))
+               readl(pll->pll_base + ctrl->vco_ctrl.u_offset);
+       val = readl(pll->pll_base + ctrl->vco_ctrl.l_offset);
+
+       if (rate >= VCO_LOW && rate < VCO_MID)
+               val |= (1 << PLL_VCO_LOW_SHIFT);
+
+       if (rate < VCO_HIGH)
+               val &= ~(1 << PLL_VCO_HIGH_SHIFT);
+       else
+               val |= (1 << PLL_VCO_HIGH_SHIFT);
+
+       writel(val, pll->pll_base + ctrl->vco_ctrl.l_offset);
+       if (unlikely(ctrl->flags & IPROC_CLK_NEEDS_READ_BACK))
+               readl(pll->pll_base + ctrl->vco_ctrl.l_offset);
+
+       /* program integer part of NDIV */
+       val = readl(pll->pll_base + ctrl->ndiv_int.offset);
+       val &= ~(bit_mask(ctrl->ndiv_int.width) << ctrl->ndiv_int.shift);
+       val |= vco->ndiv_int << ctrl->ndiv_int.shift;
+       writel(val, pll->pll_base + ctrl->ndiv_int.offset);
+       if (unlikely(ctrl->flags & IPROC_CLK_NEEDS_READ_BACK))
+               readl(pll->pll_base + ctrl->ndiv_int.offset);
+
+       /* program fractional part of NDIV */
+       if (ctrl->flags & IPROC_CLK_PLL_HAS_NDIV_FRAC) {
+               val = readl(pll->pll_base + ctrl->ndiv_frac.offset);
+               val &= ~(bit_mask(ctrl->ndiv_frac.width) <<
+                        ctrl->ndiv_frac.shift);
+               val |= vco->ndiv_frac << ctrl->ndiv_frac.shift;
+               writel(val, pll->pll_base + ctrl->ndiv_frac.offset);
+               if (unlikely(ctrl->flags & IPROC_CLK_NEEDS_READ_BACK))
+                       readl(pll->pll_base + ctrl->ndiv_frac.offset);
+       }
+
+       /* program PDIV */
+       val = readl(pll->pll_base + ctrl->pdiv.offset);
+       val &= ~(bit_mask(ctrl->pdiv.width) << ctrl->pdiv.shift);
+       val |= vco->pdiv << ctrl->pdiv.shift;
+       writel(val, pll->pll_base + ctrl->pdiv.offset);
+       if (unlikely(ctrl->flags & IPROC_CLK_NEEDS_READ_BACK))
+               readl(pll->pll_base + ctrl->pdiv.offset);
+
+       __pll_bring_out_reset(pll, kp, ka, ki);
+
+       ret = pll_wait_for_lock(pll);
+       if (ret < 0) {
+               pr_err("%s: pll: %s failed to lock\n", __func__, clk->name);
+               return ret;
+       }
+
+       return 0;
+}
+
+static int iproc_pll_enable(struct clk_hw *hw)
+{
+       struct iproc_clk *clk = to_iproc_clk(hw);
+       struct iproc_pll *pll = clk->pll;
+
+       return __pll_enable(pll);
+}
+
+static void iproc_pll_disable(struct clk_hw *hw)
+{
+       struct iproc_clk *clk = to_iproc_clk(hw);
+       struct iproc_pll *pll = clk->pll;
+       const struct iproc_pll_ctrl *ctrl = pll->ctrl;
+
+       if (ctrl->flags & IPROC_CLK_AON)
+               return;
+
+       __pll_disable(pll);
+}
+
+static unsigned long iproc_pll_recalc_rate(struct clk_hw *hw,
+                                          unsigned long parent_rate)
+{
+       struct iproc_clk *clk = to_iproc_clk(hw);
+       struct iproc_pll *pll = clk->pll;
+       const struct iproc_pll_ctrl *ctrl = pll->ctrl;
+       u32 val;
+       u64 ndiv;
+       unsigned int ndiv_int, ndiv_frac, pdiv;
+
+       if (parent_rate == 0)
+               return 0;
+
+       /* PLL needs to be locked */
+       val = readl(pll->pll_base + ctrl->status.offset);
+       if ((val & (1 << ctrl->status.shift)) == 0) {
+               clk->rate = 0;
+               return 0;
+       }
+
+       /*
+        * PLL output frequency =
+        *
+        * ((ndiv_int + ndiv_frac / 2^20) * (parent clock rate / pdiv)
+        */
+       val = readl(pll->pll_base + ctrl->ndiv_int.offset);
+       ndiv_int = (val >> ctrl->ndiv_int.shift) &
+               bit_mask(ctrl->ndiv_int.width);
+       ndiv = ndiv_int << ctrl->ndiv_int.shift;
+
+       if (ctrl->flags & IPROC_CLK_PLL_HAS_NDIV_FRAC) {
+               val = readl(pll->pll_base + ctrl->ndiv_frac.offset);
+               ndiv_frac = (val >> ctrl->ndiv_frac.shift) &
+                       bit_mask(ctrl->ndiv_frac.width);
+
+               if (ndiv_frac != 0)
+                       ndiv = (ndiv_int << ctrl->ndiv_int.shift) | ndiv_frac;
+       }
+
+       val = readl(pll->pll_base + ctrl->pdiv.offset);
+       pdiv = (val >> ctrl->pdiv.shift) & bit_mask(ctrl->pdiv.width);
+
+       clk->rate = (ndiv * parent_rate) >> ctrl->ndiv_int.shift;
+
+       if (pdiv == 0)
+               clk->rate *= 2;
+       else
+               clk->rate /= pdiv;
+
+       return clk->rate;
+}
+
+static long iproc_pll_round_rate(struct clk_hw *hw, unsigned long rate,
+                                unsigned long *parent_rate)
+{
+       unsigned i;
+       struct iproc_clk *clk = to_iproc_clk(hw);
+       struct iproc_pll *pll = clk->pll;
+
+       if (rate == 0 || *parent_rate == 0 || !pll->vco_param)
+               return -EINVAL;
+
+       for (i = 0; i < pll->num_vco_entries; i++) {
+               if (rate <= pll->vco_param[i].rate)
+                       break;
+       }
+
+       if (i == pll->num_vco_entries)
+               i--;
+
+       return pll->vco_param[i].rate;
+}
+
+static int iproc_pll_set_rate(struct clk_hw *hw, unsigned long rate,
+               unsigned long parent_rate)
+{
+       struct iproc_clk *clk = to_iproc_clk(hw);
+       struct iproc_pll *pll = clk->pll;
+       int rate_index, ret;
+
+       rate_index = pll_get_rate_index(pll, rate);
+       if (rate_index < 0)
+               return rate_index;
+
+       ret = pll_set_rate(clk, rate_index, parent_rate);
+       return ret;
+}
+
+static const struct clk_ops iproc_pll_ops = {
+       .enable = iproc_pll_enable,
+       .disable = iproc_pll_disable,
+       .recalc_rate = iproc_pll_recalc_rate,
+       .round_rate = iproc_pll_round_rate,
+       .set_rate = iproc_pll_set_rate,
+};
+
+static int iproc_clk_enable(struct clk_hw *hw)
+{
+       struct iproc_clk *clk = to_iproc_clk(hw);
+       const struct iproc_clk_ctrl *ctrl = clk->ctrl;
+       struct iproc_pll *pll = clk->pll;
+       u32 val;
+
+       /* channel enable is active low */
+       val = readl(pll->pll_base + ctrl->enable.offset);
+       val &= ~(1 << ctrl->enable.enable_shift);
+       writel(val, pll->pll_base + ctrl->enable.offset);
+
+       /* also make sure channel is not held */
+       val = readl(pll->pll_base + ctrl->enable.offset);
+       val &= ~(1 << ctrl->enable.hold_shift);
+       writel(val, pll->pll_base + ctrl->enable.offset);
+       if (unlikely(ctrl->flags & IPROC_CLK_NEEDS_READ_BACK))
+               readl(pll->pll_base + ctrl->enable.offset);
+
+       return 0;
+}
+
+static void iproc_clk_disable(struct clk_hw *hw)
+{
+       struct iproc_clk *clk = to_iproc_clk(hw);
+       const struct iproc_clk_ctrl *ctrl = clk->ctrl;
+       struct iproc_pll *pll = clk->pll;
+       u32 val;
+
+       if (ctrl->flags & IPROC_CLK_AON)
+               return;
+
+       val = readl(pll->pll_base + ctrl->enable.offset);
+       val |= 1 << ctrl->enable.enable_shift;
+       writel(val, pll->pll_base + ctrl->enable.offset);
+       if (unlikely(ctrl->flags & IPROC_CLK_NEEDS_READ_BACK))
+               readl(pll->pll_base + ctrl->enable.offset);
+}
+
+static unsigned long iproc_clk_recalc_rate(struct clk_hw *hw,
+               unsigned long parent_rate)
+{
+       struct iproc_clk *clk = to_iproc_clk(hw);
+       const struct iproc_clk_ctrl *ctrl = clk->ctrl;
+       struct iproc_pll *pll = clk->pll;
+       u32 val;
+       unsigned int mdiv;
+
+       if (parent_rate == 0)
+               return 0;
+
+       val = readl(pll->pll_base + ctrl->mdiv.offset);
+       mdiv = (val >> ctrl->mdiv.shift) & bit_mask(ctrl->mdiv.width);
+       if (mdiv == 0)
+               mdiv = 256;
+
+       clk->rate = parent_rate / mdiv;
+
+       return clk->rate;
+}
+
+static long iproc_clk_round_rate(struct clk_hw *hw, unsigned long rate,
+               unsigned long *parent_rate)
+{
+       unsigned int div;
+
+       if (rate == 0 || *parent_rate == 0)
+               return -EINVAL;
+
+       if (rate == *parent_rate)
+               return *parent_rate;
+
+       div = DIV_ROUND_UP(*parent_rate, rate);
+       if (div < 2)
+               return *parent_rate;
+
+       if (div > 256)
+               div = 256;
+
+       return *parent_rate / div;
+}
+
+static int iproc_clk_set_rate(struct clk_hw *hw, unsigned long rate,
+               unsigned long parent_rate)
+{
+       struct iproc_clk *clk = to_iproc_clk(hw);
+       const struct iproc_clk_ctrl *ctrl = clk->ctrl;
+       struct iproc_pll *pll = clk->pll;
+       u32 val;
+       unsigned int div;
+
+       if (rate == 0 || parent_rate == 0)
+               return -EINVAL;
+
+       div = DIV_ROUND_UP(parent_rate, rate);
+       if (div > 256)
+               return -EINVAL;
+
+       val = readl(pll->pll_base + ctrl->mdiv.offset);
+       if (div == 256) {
+               val &= ~(bit_mask(ctrl->mdiv.width) << ctrl->mdiv.shift);
+       } else {
+               val &= ~(bit_mask(ctrl->mdiv.width) << ctrl->mdiv.shift);
+               val |= div << ctrl->mdiv.shift;
+       }
+       writel(val, pll->pll_base + ctrl->mdiv.offset);
+       if (unlikely(ctrl->flags & IPROC_CLK_NEEDS_READ_BACK))
+               readl(pll->pll_base + ctrl->mdiv.offset);
+       clk->rate = parent_rate / div;
+
+       return 0;
+}
+
+static const struct clk_ops iproc_clk_ops = {
+       .enable = iproc_clk_enable,
+       .disable = iproc_clk_disable,
+       .recalc_rate = iproc_clk_recalc_rate,
+       .round_rate = iproc_clk_round_rate,
+       .set_rate = iproc_clk_set_rate,
+};
+
+/**
+ * Some PLLs require the PLL SW override bit to be set before changes can be
+ * applied to the PLL
+ */
+static void iproc_pll_sw_cfg(struct iproc_pll *pll)
+{
+       const struct iproc_pll_ctrl *ctrl = pll->ctrl;
+
+       if (ctrl->flags & IPROC_CLK_PLL_NEEDS_SW_CFG) {
+               u32 val;
+
+               val = readl(pll->pll_base + ctrl->sw_ctrl.offset);
+               val |= BIT(ctrl->sw_ctrl.shift);
+               writel(val, pll->pll_base + ctrl->sw_ctrl.offset);
+               if (unlikely(ctrl->flags & IPROC_CLK_NEEDS_READ_BACK))
+                       readl(pll->pll_base + ctrl->sw_ctrl.offset);
+       }
+}
+
+void __init iproc_pll_clk_setup(struct device_node *node,
+                               const struct iproc_pll_ctrl *pll_ctrl,
+                               const struct iproc_pll_vco_param *vco,
+                               unsigned int num_vco_entries,
+                               const struct iproc_clk_ctrl *clk_ctrl,
+                               unsigned int num_clks)
+{
+       int i, ret;
+       struct clk *clk;
+       struct iproc_pll *pll;
+       struct iproc_clk *iclk;
+       struct clk_init_data init;
+       const char *parent_name;
+
+       if (WARN_ON(!pll_ctrl) || WARN_ON(!clk_ctrl))
+               return;
+
+       pll = kzalloc(sizeof(*pll), GFP_KERNEL);
+       if (WARN_ON(!pll))
+               return;
+
+       pll->clk_data.clk_num = num_clks;
+       pll->clk_data.clks = kcalloc(num_clks, sizeof(*pll->clk_data.clks),
+                                    GFP_KERNEL);
+       if (WARN_ON(!pll->clk_data.clks))
+               goto err_clk_data;
+
+       pll->clks = kcalloc(num_clks, sizeof(*pll->clks), GFP_KERNEL);
+       if (WARN_ON(!pll->clks))
+               goto err_clks;
+
+       pll->pll_base = of_iomap(node, 0);
+       if (WARN_ON(!pll->pll_base))
+               goto err_pll_iomap;
+
+       pll->pwr_base = of_iomap(node, 1);
+       if (WARN_ON(!pll->pwr_base))
+               goto err_pwr_iomap;
+
+       /* some PLLs require gating control at the top ASIU level */
+       if (pll_ctrl->flags & IPROC_CLK_PLL_ASIU) {
+               pll->asiu_base = of_iomap(node, 2);
+               if (WARN_ON(!pll->asiu_base))
+                       goto err_asiu_iomap;
+       }
+
+       /* initialize and register the PLL itself */
+       pll->ctrl = pll_ctrl;
+
+       iclk = &pll->clks[0];
+       iclk->pll = pll;
+       iclk->name = node->name;
+
+       init.name = node->name;
+       init.ops = &iproc_pll_ops;
+       init.flags = 0;
+       parent_name = of_clk_get_parent_name(node, 0);
+       init.parent_names = (parent_name ? &parent_name : NULL);
+       init.num_parents = (parent_name ? 1 : 0);
+       iclk->hw.init = &init;
+
+       if (vco) {
+               pll->num_vco_entries = num_vco_entries;
+               pll->vco_param = vco;
+       }
+
+       iproc_pll_sw_cfg(pll);
+
+       clk = clk_register(NULL, &iclk->hw);
+       if (WARN_ON(IS_ERR(clk)))
+               goto err_pll_register;
+
+       pll->clk_data.clks[0] = clk;
+
+       /* now initialize and register all leaf clocks */
+       for (i = 1; i < num_clks; i++) {
+               const char *clk_name;
+
+               memset(&init, 0, sizeof(init));
+               parent_name = node->name;
+
+               clk_name = kzalloc(IPROC_CLK_NAME_LEN, GFP_KERNEL);
+               if (WARN_ON(!clk_name))
+                       goto err_clk_register;
+
+               ret = of_property_read_string_index(node, "clock-output-names",
+                                                   i, &clk_name);
+               if (WARN_ON(ret))
+                       goto err_clk_register;
+
+               iclk = &pll->clks[i];
+               iclk->name = clk_name;
+               iclk->pll = pll;
+               iclk->ctrl = &clk_ctrl[i];
+
+               init.name = clk_name;
+               init.ops = &iproc_clk_ops;
+               init.flags = 0;
+               init.parent_names = (parent_name ? &parent_name : NULL);
+               init.num_parents = (parent_name ? 1 : 0);
+               iclk->hw.init = &init;
+
+               clk = clk_register(NULL, &iclk->hw);
+               if (WARN_ON(IS_ERR(clk)))
+                       goto err_clk_register;
+
+               pll->clk_data.clks[i] = clk;
+       }
+
+       ret = of_clk_add_provider(node, of_clk_src_onecell_get, &pll->clk_data);
+       if (WARN_ON(ret))
+               goto err_clk_register;
+
+       return;
+
+err_clk_register:
+       for (i = 0; i < num_clks; i++) {
+               kfree(pll->clks[i].name);
+               clk_unregister(pll->clk_data.clks[i]);
+       }
+
+err_pll_register:
+       if (pll->asiu_base)
+               iounmap(pll->asiu_base);
+
+err_asiu_iomap:
+       iounmap(pll->pwr_base);
+
+err_pwr_iomap:
+       iounmap(pll->pll_base);
+
+err_pll_iomap:
+       kfree(pll->clks);
+
+err_clks:
+       kfree(pll->clk_data.clks);
+
+err_clk_data:
+       kfree(pll);
+}
diff --git a/drivers/clk/bcm/clk-iproc.h b/drivers/clk/bcm/clk-iproc.h
new file mode 100644 (file)
index 0000000..d834b7a
--- /dev/null
@@ -0,0 +1,178 @@
+/*
+ * Copyright (C) 2014 Broadcom Corporation
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation version 2.
+ *
+ * This program is distributed "as is" WITHOUT ANY WARRANTY of any
+ * kind, whether express or implied; without even the implied warranty
+ * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#ifndef _CLK_IPROC_H
+#define _CLK_IPROC_H
+
+#include <linux/kernel.h>
+#include <linux/list.h>
+#include <linux/spinlock.h>
+#include <linux/slab.h>
+#include <linux/device.h>
+#include <linux/of.h>
+#include <linux/clk-provider.h>
+
+#define IPROC_CLK_NAME_LEN 25
+#define IPROC_CLK_INVALID_OFFSET 0xffffffff
+#define bit_mask(width) ((1 << (width)) - 1)
+
+/* clocks that should not be disabled at runtime */
+#define IPROC_CLK_AON BIT(0)
+
+/* PLL that requires gating through ASIU */
+#define IPROC_CLK_PLL_ASIU BIT(1)
+
+/* PLL that has fractional part of the NDIV */
+#define IPROC_CLK_PLL_HAS_NDIV_FRAC BIT(2)
+
+/*
+ * Some of the iProc PLL/clocks may have an ASIC bug that requires read back
+ * of the same register following the write to flush the write transaction into
+ * the intended register
+ */
+#define IPROC_CLK_NEEDS_READ_BACK BIT(3)
+
+/*
+ * Some PLLs require the PLL SW override bit to be set before changes can be
+ * applied to the PLL
+ */
+#define IPROC_CLK_PLL_NEEDS_SW_CFG BIT(4)
+
+/*
+ * Parameters for VCO frequency configuration
+ *
+ * VCO frequency =
+ * ((ndiv_int + ndiv_frac / 2^20) * (ref freqeuncy  / pdiv)
+ */
+struct iproc_pll_vco_param {
+       unsigned long rate;
+       unsigned int ndiv_int;
+       unsigned int ndiv_frac;
+       unsigned int pdiv;
+};
+
+struct iproc_clk_reg_op {
+       unsigned int offset;
+       unsigned int shift;
+       unsigned int width;
+};
+
+/*
+ * Clock gating control at the top ASIU level
+ */
+struct iproc_asiu_gate {
+       unsigned int offset;
+       unsigned int en_shift;
+};
+
+/*
+ * Control of powering on/off of a PLL
+ *
+ * Before powering off a PLL, input isolation (ISO) needs to be enabled
+ */
+struct iproc_pll_aon_pwr_ctrl {
+       unsigned int offset;
+       unsigned int pwr_width;
+       unsigned int pwr_shift;
+       unsigned int iso_shift;
+};
+
+/*
+ * Control of the PLL reset, with Ki, Kp, and Ka parameters
+ */
+struct iproc_pll_reset_ctrl {
+       unsigned int offset;
+       unsigned int reset_shift;
+       unsigned int p_reset_shift;
+       unsigned int ki_shift;
+       unsigned int ki_width;
+       unsigned int kp_shift;
+       unsigned int kp_width;
+       unsigned int ka_shift;
+       unsigned int ka_width;
+};
+
+/*
+ * To enable SW control of the PLL
+ */
+struct iproc_pll_sw_ctrl {
+       unsigned int offset;
+       unsigned int shift;
+};
+
+struct iproc_pll_vco_ctrl {
+       unsigned int u_offset;
+       unsigned int l_offset;
+};
+
+/*
+ * Main PLL control parameters
+ */
+struct iproc_pll_ctrl {
+       unsigned long flags;
+       struct iproc_pll_aon_pwr_ctrl aon;
+       struct iproc_asiu_gate asiu;
+       struct iproc_pll_reset_ctrl reset;
+       struct iproc_pll_sw_ctrl sw_ctrl;
+       struct iproc_clk_reg_op ndiv_int;
+       struct iproc_clk_reg_op ndiv_frac;
+       struct iproc_clk_reg_op pdiv;
+       struct iproc_pll_vco_ctrl vco_ctrl;
+       struct iproc_clk_reg_op status;
+};
+
+/*
+ * Controls enabling/disabling a PLL derived clock
+ */
+struct iproc_clk_enable_ctrl {
+       unsigned int offset;
+       unsigned int enable_shift;
+       unsigned int hold_shift;
+       unsigned int bypass_shift;
+};
+
+/*
+ * Main clock control parameters for clocks derived from the PLLs
+ */
+struct iproc_clk_ctrl {
+       unsigned int channel;
+       unsigned long flags;
+       struct iproc_clk_enable_ctrl enable;
+       struct iproc_clk_reg_op mdiv;
+};
+
+/*
+ * Divisor of the ASIU clocks
+ */
+struct iproc_asiu_div {
+       unsigned int offset;
+       unsigned int en_shift;
+       unsigned int high_shift;
+       unsigned int high_width;
+       unsigned int low_shift;
+       unsigned int low_width;
+};
+
+void __init iproc_armpll_setup(struct device_node *node);
+void __init iproc_pll_clk_setup(struct device_node *node,
+                               const struct iproc_pll_ctrl *pll_ctrl,
+                               const struct iproc_pll_vco_param *vco,
+                               unsigned int num_vco_entries,
+                               const struct iproc_clk_ctrl *clk_ctrl,
+                               unsigned int num_clks);
+void __init iproc_asiu_setup(struct device_node *node,
+                            const struct iproc_asiu_div *div,
+                            const struct iproc_asiu_gate *gate,
+                            unsigned int num_clks);
+
+#endif /* _CLK_IPROC_H */
index e5aededdd3221cf34313228767eb72e755215b72..deaa7f962b84ac814eb2445d698d343d45018aec 100644 (file)
@@ -21,8 +21,6 @@
 #define selector_clear_exists(sel)     ((sel)->width = 0)
 #define trigger_clear_exists(trig)     FLAG_CLEAR(trig, TRIG, EXISTS)
 
-LIST_HEAD(ccu_list);   /* The list of set up CCUs */
-
 /* Validity checking */
 
 static bool ccu_data_offsets_valid(struct ccu_data *ccu)
@@ -773,7 +771,6 @@ static void kona_ccu_teardown(struct ccu_data *ccu)
 
        of_clk_del_provider(ccu->node); /* safe if never added */
        ccu_clks_teardown(ccu);
-       list_del(&ccu->links);
        of_node_put(ccu->node);
        ccu->node = NULL;
        iounmap(ccu->base);
@@ -847,7 +844,6 @@ void __init kona_dt_ccu_setup(struct ccu_data *ccu,
                goto out_err;
        }
        ccu->node = of_node_get(node);
-       list_add_tail(&ccu->links, &ccu_list);
 
        /*
         * Set up each defined kona clock and save the result in
index a0ef4f75d4573b2db17ec1435003c50bdd7ef350..79a98506c433bbbbc12bd50d0f7cf82a029d3b8b 100644 (file)
@@ -1240,7 +1240,7 @@ static bool __kona_clk_init(struct kona_clk *bcm_clk)
        default:
                BUG();
        }
-       return -EINVAL;
+       return false;
 }
 
 /* Set a CCU and all its clocks into their desired initial state */
index 6849a64baf6db9969a94203228fb0240bc7df09d..906576ec97b6f9176fa6e0cfe6390e2856dcfc06 100644 (file)
@@ -480,7 +480,6 @@ struct ccu_data {
        spinlock_t lock;        /* serialization lock */
        bool write_enabled;     /* write access is currently enabled */
        struct ccu_policy policy;
-       struct list_head links; /* for ccu_list */
        struct device_node *node;
        struct clk_onecell_data clk_data;
        const char *name;
@@ -492,7 +491,6 @@ struct ccu_data {
 #define KONA_CCU_COMMON(_prefix, _name, _ccuname)                          \
        .name           = #_name "_ccu",                                    \
        .lock           = __SPIN_LOCK_UNLOCKED(_name ## _ccu_data.lock),    \
-       .links          = LIST_HEAD_INIT(_name ## _ccu_data.links),         \
        .clk_data       = {                                                 \
                .clk_num = _prefix ## _ ## _ccuname ## _CCU_CLOCK_COUNT,    \
        }
index bdc506b03824f4f56c68f864ee1092f4ce648170..f4b8d324b083dfda89d3766cc6958b533b7802d4 100644 (file)
 #include <asm/div64.h>
 
 #include "berlin2-div.h"
-
-struct berlin2_pll_map {
-       const u8 vcodiv[16];
-       u8 mult;
-       u8 fbdiv_shift;
-       u8 rfdiv_shift;
-       u8 divsel_shift;
-};
+#include "berlin2-pll.h"
 
 struct berlin2_pll {
        struct clk_hw hw;
index 88f4ff6916fe72ff840dae2906f7a3082beee722..90897af8d9f74b6eb1ec7b4ee309c04f500aea4c 100644 (file)
@@ -274,7 +274,7 @@ static void __init asm9260_acc_init(struct device_node *np)
        u32 accuracy = 0;
 
        base = of_io_request_and_map(np, 0, np->name);
-       if (!base)
+       if (IS_ERR(base))
                panic("%s: unable to map resource", np->name);
 
        /* register pll */
index 0f6368ceec4c970a670cbe63297dcbfbef125869..c7c91a5ecf8be8a2ceab3b143d762f1daabd8810 100644 (file)
@@ -556,7 +556,7 @@ static int axmclk_probe(struct platform_device *pdev)
                return PTR_ERR(regmap);
 
        num_clks = ARRAY_SIZE(axmclk_clocks);
-       pr_info("axmclk: supporting %u clocks\n", num_clks);
+       pr_info("axmclk: supporting %zu clocks\n", num_clks);
        priv = devm_kzalloc(dev, sizeof(*priv) + sizeof(*priv->clks) * num_clks,
                            GFP_KERNEL);
        if (!priv)
index b8e4f8a822e9f334d6db9071136903e88699a280..f01164fada5dafd4e80d0eac8f5f0242847399dd 100644 (file)
@@ -94,7 +94,7 @@ static const char * const cdce706_source_name[] = {
        "clk_in0", "clk_in1",
 };
 
-static const char *cdce706_clkin_name[] = {
+static const char * const cdce706_clkin_name[] = {
        "clk_in",
 };
 
@@ -102,7 +102,7 @@ static const char * const cdce706_pll_name[] = {
        "pll1", "pll2", "pll3",
 };
 
-static const char *cdce706_divider_parent_name[] = {
+static const char * const cdce706_divider_parent_name[] = {
        "clk_in", "pll1", "pll2", "pll2", "pll3",
 };
 
@@ -666,6 +666,7 @@ static int cdce706_probe(struct i2c_client *client,
 
 static int cdce706_remove(struct i2c_client *client)
 {
+       of_clk_del_provider(client->dev.of_node);
        return 0;
 }
 
diff --git a/drivers/clk/clk-cdce925.c b/drivers/clk/clk-cdce925.c
new file mode 100644 (file)
index 0000000..85fafb4
--- /dev/null
@@ -0,0 +1,749 @@
+/*
+ * Driver for TI Dual PLL CDCE925 clock synthesizer
+ *
+ * This driver always connects the Y1 to the input clock, Y2/Y3 to PLL1
+ * and Y4/Y5 to PLL2. PLL frequency is set on a first-come-first-serve
+ * basis. Clients can directly request any frequency that the chip can
+ * deliver using the standard clk framework. In addition, the device can
+ * be configured and activated via the devicetree.
+ *
+ * Copyright (C) 2014, Topic Embedded Products
+ * Licenced under GPL
+ */
+#include <linux/clk-provider.h>
+#include <linux/delay.h>
+#include <linux/module.h>
+#include <linux/i2c.h>
+#include <linux/regmap.h>
+#include <linux/slab.h>
+#include <linux/gcd.h>
+
+/* The chip has 2 PLLs which can be routed through dividers to 5 outputs.
+ * Model this as 2 PLL clocks which are parents to the outputs.
+ */
+#define NUMBER_OF_PLLS 2
+#define NUMBER_OF_OUTPUTS      5
+
+#define CDCE925_REG_GLOBAL1    0x01
+#define CDCE925_REG_Y1SPIPDIVH 0x02
+#define CDCE925_REG_PDIVL      0x03
+#define CDCE925_REG_XCSEL      0x05
+/* PLL parameters start at 0x10, steps of 0x10 */
+#define CDCE925_OFFSET_PLL     0x10
+/* Add CDCE925_OFFSET_PLL * (pll) to these registers before sending */
+#define CDCE925_PLL_MUX_OUTPUTS        0x14
+#define CDCE925_PLL_MULDIV     0x18
+
+#define CDCE925_PLL_FREQUENCY_MIN       80000000ul
+#define CDCE925_PLL_FREQUENCY_MAX      230000000ul
+struct clk_cdce925_chip;
+
+struct clk_cdce925_output {
+       struct clk_hw hw;
+       struct clk_cdce925_chip *chip;
+       u8 index;
+       u16 pdiv; /* 1..127 for Y2-Y5; 1..1023 for Y1 */
+};
+#define to_clk_cdce925_output(_hw) \
+       container_of(_hw, struct clk_cdce925_output, hw)
+
+struct clk_cdce925_pll {
+       struct clk_hw hw;
+       struct clk_cdce925_chip *chip;
+       u8 index;
+       u16 m;   /* 1..511 */
+       u16 n;   /* 1..4095 */
+};
+#define to_clk_cdce925_pll(_hw)        container_of(_hw, struct clk_cdce925_pll, hw)
+
+struct clk_cdce925_chip {
+       struct regmap *regmap;
+       struct i2c_client *i2c_client;
+       struct clk_cdce925_pll pll[NUMBER_OF_PLLS];
+       struct clk_cdce925_output clk[NUMBER_OF_OUTPUTS];
+       struct clk *dt_clk[NUMBER_OF_OUTPUTS];
+       struct clk_onecell_data onecell;
+};
+
+/* ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** */
+
+static unsigned long cdce925_pll_calculate_rate(unsigned long parent_rate,
+       u16 n, u16 m)
+{
+       if ((!m || !n) || (m == n))
+               return parent_rate; /* In bypass mode runs at same frequency */
+       return mult_frac(parent_rate, (unsigned long)n, (unsigned long)m);
+}
+
+static unsigned long cdce925_pll_recalc_rate(struct clk_hw *hw,
+               unsigned long parent_rate)
+{
+       /* Output frequency of PLL is Fout = (Fin/Pdiv)*(N/M) */
+       struct clk_cdce925_pll *data = to_clk_cdce925_pll(hw);
+
+       return cdce925_pll_calculate_rate(parent_rate, data->n, data->m);
+}
+
+static void cdce925_pll_find_rate(unsigned long rate,
+               unsigned long parent_rate, u16 *n, u16 *m)
+{
+       unsigned long un;
+       unsigned long um;
+       unsigned long g;
+
+       if (rate <= parent_rate) {
+               /* Can always deliver parent_rate in bypass mode */
+               rate = parent_rate;
+               *n = 0;
+               *m = 0;
+       } else {
+               /* In PLL mode, need to apply min/max range */
+               if (rate < CDCE925_PLL_FREQUENCY_MIN)
+                       rate = CDCE925_PLL_FREQUENCY_MIN;
+               else if (rate > CDCE925_PLL_FREQUENCY_MAX)
+                       rate = CDCE925_PLL_FREQUENCY_MAX;
+
+               g = gcd(rate, parent_rate);
+               um = parent_rate / g;
+               un = rate / g;
+               /* When outside hw range, reduce to fit (rounding errors) */
+               while ((un > 4095) || (um > 511)) {
+                       un >>= 1;
+                       um >>= 1;
+               }
+               if (un == 0)
+                       un = 1;
+               if (um == 0)
+                       um = 1;
+
+               *n = un;
+               *m = um;
+       }
+}
+
+static long cdce925_pll_round_rate(struct clk_hw *hw, unsigned long rate,
+               unsigned long *parent_rate)
+{
+       u16 n, m;
+
+       cdce925_pll_find_rate(rate, *parent_rate, &n, &m);
+       return (long)cdce925_pll_calculate_rate(*parent_rate, n, m);
+}
+
+static int cdce925_pll_set_rate(struct clk_hw *hw, unsigned long rate,
+               unsigned long parent_rate)
+{
+       struct clk_cdce925_pll *data = to_clk_cdce925_pll(hw);
+
+       if (!rate || (rate == parent_rate)) {
+               data->m = 0; /* Bypass mode */
+               data->n = 0;
+               return 0;
+       }
+
+       if ((rate < CDCE925_PLL_FREQUENCY_MIN) ||
+               (rate > CDCE925_PLL_FREQUENCY_MAX)) {
+               pr_debug("%s: rate %lu outside PLL range.\n", __func__, rate);
+               return -EINVAL;
+       }
+
+       if (rate < parent_rate) {
+               pr_debug("%s: rate %lu less than parent rate %lu.\n", __func__,
+                       rate, parent_rate);
+               return -EINVAL;
+       }
+
+       cdce925_pll_find_rate(rate, parent_rate, &data->n, &data->m);
+       return 0;
+}
+
+
+/* calculate p = max(0, 4 - int(log2 (n/m))) */
+static u8 cdce925_pll_calc_p(u16 n, u16 m)
+{
+       u8 p;
+       u16 r = n / m;
+
+       if (r >= 16)
+               return 0;
+       p = 4;
+       while (r > 1) {
+               r >>= 1;
+               --p;
+       }
+       return p;
+}
+
+/* Returns VCO range bits for VCO1_0_RANGE */
+static u8 cdce925_pll_calc_range_bits(struct clk_hw *hw, u16 n, u16 m)
+{
+       struct clk *parent = clk_get_parent(hw->clk);
+       unsigned long rate = clk_get_rate(parent);
+
+       rate = mult_frac(rate, (unsigned long)n, (unsigned long)m);
+       if (rate >= 175000000)
+               return 0x3;
+       if (rate >= 150000000)
+               return 0x02;
+       if (rate >= 125000000)
+               return 0x01;
+       return 0x00;
+}
+
+/* I2C clock, hence everything must happen in (un)prepare because this
+ * may sleep */
+static int cdce925_pll_prepare(struct clk_hw *hw)
+{
+       struct clk_cdce925_pll *data = to_clk_cdce925_pll(hw);
+       u16 n = data->n;
+       u16 m = data->m;
+       u16 r;
+       u8 q;
+       u8 p;
+       u16 nn;
+       u8 pll[4]; /* Bits are spread out over 4 byte registers */
+       u8 reg_ofs = data->index * CDCE925_OFFSET_PLL;
+       unsigned i;
+
+       if ((!m || !n) || (m == n)) {
+               /* Set PLL mux to bypass mode, leave the rest as is */
+               regmap_update_bits(data->chip->regmap,
+                       reg_ofs + CDCE925_PLL_MUX_OUTPUTS, 0x80, 0x80);
+       } else {
+               /* According to data sheet: */
+               /* p = max(0, 4 - int(log2 (n/m))) */
+               p = cdce925_pll_calc_p(n, m);
+               /* nn = n * 2^p */
+               nn = n * BIT(p);
+               /* q = int(nn/m) */
+               q = nn / m;
+               if ((q < 16) || (1 > 64)) {
+                       pr_debug("%s invalid q=%d\n", __func__, q);
+                       return -EINVAL;
+               }
+               r = nn - (m*q);
+               if (r > 511) {
+                       pr_debug("%s invalid r=%d\n", __func__, r);
+                       return -EINVAL;
+               }
+               pr_debug("%s n=%d m=%d p=%d q=%d r=%d\n", __func__,
+                       n, m, p, q, r);
+               /* encode into register bits */
+               pll[0] = n >> 4;
+               pll[1] = ((n & 0x0F) << 4) | ((r >> 5) & 0x0F);
+               pll[2] = ((r & 0x1F) << 3) | ((q >> 3) & 0x07);
+               pll[3] = ((q & 0x07) << 5) | (p << 2) |
+                               cdce925_pll_calc_range_bits(hw, n, m);
+               /* Write to registers */
+               for (i = 0; i < ARRAY_SIZE(pll); ++i)
+                       regmap_write(data->chip->regmap,
+                               reg_ofs + CDCE925_PLL_MULDIV + i, pll[i]);
+               /* Enable PLL */
+               regmap_update_bits(data->chip->regmap,
+                       reg_ofs + CDCE925_PLL_MUX_OUTPUTS, 0x80, 0x00);
+       }
+
+       return 0;
+}
+
+static void cdce925_pll_unprepare(struct clk_hw *hw)
+{
+       struct clk_cdce925_pll *data = to_clk_cdce925_pll(hw);
+       u8 reg_ofs = data->index * CDCE925_OFFSET_PLL;
+
+       regmap_update_bits(data->chip->regmap,
+                       reg_ofs + CDCE925_PLL_MUX_OUTPUTS, 0x80, 0x80);
+}
+
+static const struct clk_ops cdce925_pll_ops = {
+       .prepare = cdce925_pll_prepare,
+       .unprepare = cdce925_pll_unprepare,
+       .recalc_rate = cdce925_pll_recalc_rate,
+       .round_rate = cdce925_pll_round_rate,
+       .set_rate = cdce925_pll_set_rate,
+};
+
+
+static void cdce925_clk_set_pdiv(struct clk_cdce925_output *data, u16 pdiv)
+{
+       switch (data->index) {
+       case 0:
+               regmap_update_bits(data->chip->regmap,
+                       CDCE925_REG_Y1SPIPDIVH,
+                       0x03, (pdiv >> 8) & 0x03);
+               regmap_write(data->chip->regmap, 0x03, pdiv & 0xFF);
+               break;
+       case 1:
+               regmap_update_bits(data->chip->regmap, 0x16, 0x7F, pdiv);
+               break;
+       case 2:
+               regmap_update_bits(data->chip->regmap, 0x17, 0x7F, pdiv);
+               break;
+       case 3:
+               regmap_update_bits(data->chip->regmap, 0x26, 0x7F, pdiv);
+               break;
+       case 4:
+               regmap_update_bits(data->chip->regmap, 0x27, 0x7F, pdiv);
+               break;
+       }
+}
+
+static void cdce925_clk_activate(struct clk_cdce925_output *data)
+{
+       switch (data->index) {
+       case 0:
+               regmap_update_bits(data->chip->regmap,
+                       CDCE925_REG_Y1SPIPDIVH, 0x0c, 0x0c);
+               break;
+       case 1:
+       case 2:
+               regmap_update_bits(data->chip->regmap, 0x14, 0x03, 0x03);
+               break;
+       case 3:
+       case 4:
+               regmap_update_bits(data->chip->regmap, 0x24, 0x03, 0x03);
+               break;
+       }
+}
+
+static int cdce925_clk_prepare(struct clk_hw *hw)
+{
+       struct clk_cdce925_output *data = to_clk_cdce925_output(hw);
+
+       cdce925_clk_set_pdiv(data, data->pdiv);
+       cdce925_clk_activate(data);
+       return 0;
+}
+
+static void cdce925_clk_unprepare(struct clk_hw *hw)
+{
+       struct clk_cdce925_output *data = to_clk_cdce925_output(hw);
+
+       /* Disable clock by setting divider to "0" */
+       cdce925_clk_set_pdiv(data, 0);
+}
+
+static unsigned long cdce925_clk_recalc_rate(struct clk_hw *hw,
+               unsigned long parent_rate)
+{
+       struct clk_cdce925_output *data = to_clk_cdce925_output(hw);
+
+       if (data->pdiv)
+               return parent_rate / data->pdiv;
+       return 0;
+}
+
+static u16 cdce925_calc_divider(unsigned long rate,
+               unsigned long parent_rate)
+{
+       unsigned long divider;
+
+       if (!rate)
+               return 0;
+       if (rate >= parent_rate)
+               return 1;
+
+       divider = DIV_ROUND_CLOSEST(parent_rate, rate);
+       if (divider > 0x7F)
+               divider = 0x7F;
+
+       return (u16)divider;
+}
+
+static unsigned long cdce925_clk_best_parent_rate(
+       struct clk_hw *hw, unsigned long rate)
+{
+       struct clk *pll = clk_get_parent(hw->clk);
+       struct clk *root = clk_get_parent(pll);
+       unsigned long root_rate = clk_get_rate(root);
+       unsigned long best_rate_error = rate;
+       u16 pdiv_min;
+       u16 pdiv_max;
+       u16 pdiv_best;
+       u16 pdiv_now;
+
+       if (root_rate % rate == 0)
+               return root_rate; /* Don't need the PLL, use bypass */
+
+       pdiv_min = (u16)max(1ul, DIV_ROUND_UP(CDCE925_PLL_FREQUENCY_MIN, rate));
+       pdiv_max = (u16)min(127ul, CDCE925_PLL_FREQUENCY_MAX / rate);
+
+       if (pdiv_min > pdiv_max)
+               return 0; /* No can do? */
+
+       pdiv_best = pdiv_min;
+       for (pdiv_now = pdiv_min; pdiv_now < pdiv_max; ++pdiv_now) {
+               unsigned long target_rate = rate * pdiv_now;
+               long pll_rate = clk_round_rate(pll, target_rate);
+               unsigned long actual_rate;
+               unsigned long rate_error;
+
+               if (pll_rate <= 0)
+                       continue;
+               actual_rate = pll_rate / pdiv_now;
+               rate_error = abs((long)actual_rate - (long)rate);
+               if (rate_error < best_rate_error) {
+                       pdiv_best = pdiv_now;
+                       best_rate_error = rate_error;
+               }
+               /* TODO: Consider PLL frequency based on smaller n/m values
+                * and pick the better one if the error is equal */
+       }
+
+       return rate * pdiv_best;
+}
+
+static long cdce925_clk_round_rate(struct clk_hw *hw, unsigned long rate,
+               unsigned long *parent_rate)
+{
+       unsigned long l_parent_rate = *parent_rate;
+       u16 divider = cdce925_calc_divider(rate, l_parent_rate);
+
+       if (l_parent_rate / divider != rate) {
+               l_parent_rate = cdce925_clk_best_parent_rate(hw, rate);
+               divider = cdce925_calc_divider(rate, l_parent_rate);
+               *parent_rate = l_parent_rate;
+       }
+
+       if (divider)
+               return (long)(l_parent_rate / divider);
+       return 0;
+}
+
+static int cdce925_clk_set_rate(struct clk_hw *hw, unsigned long rate,
+               unsigned long parent_rate)
+{
+       struct clk_cdce925_output *data = to_clk_cdce925_output(hw);
+
+       data->pdiv = cdce925_calc_divider(rate, parent_rate);
+
+       return 0;
+}
+
+static const struct clk_ops cdce925_clk_ops = {
+       .prepare = cdce925_clk_prepare,
+       .unprepare = cdce925_clk_unprepare,
+       .recalc_rate = cdce925_clk_recalc_rate,
+       .round_rate = cdce925_clk_round_rate,
+       .set_rate = cdce925_clk_set_rate,
+};
+
+
+static u16 cdce925_y1_calc_divider(unsigned long rate,
+               unsigned long parent_rate)
+{
+       unsigned long divider;
+
+       if (!rate)
+               return 0;
+       if (rate >= parent_rate)
+               return 1;
+
+       divider = DIV_ROUND_CLOSEST(parent_rate, rate);
+       if (divider > 0x3FF) /* Y1 has 10-bit divider */
+               divider = 0x3FF;
+
+       return (u16)divider;
+}
+
+static long cdce925_clk_y1_round_rate(struct clk_hw *hw, unsigned long rate,
+               unsigned long *parent_rate)
+{
+       unsigned long l_parent_rate = *parent_rate;
+       u16 divider = cdce925_y1_calc_divider(rate, l_parent_rate);
+
+       if (divider)
+               return (long)(l_parent_rate / divider);
+       return 0;
+}
+
+static int cdce925_clk_y1_set_rate(struct clk_hw *hw, unsigned long rate,
+               unsigned long parent_rate)
+{
+       struct clk_cdce925_output *data = to_clk_cdce925_output(hw);
+
+       data->pdiv = cdce925_y1_calc_divider(rate, parent_rate);
+
+       return 0;
+}
+
+static const struct clk_ops cdce925_clk_y1_ops = {
+       .prepare = cdce925_clk_prepare,
+       .unprepare = cdce925_clk_unprepare,
+       .recalc_rate = cdce925_clk_recalc_rate,
+       .round_rate = cdce925_clk_y1_round_rate,
+       .set_rate = cdce925_clk_y1_set_rate,
+};
+
+
+static struct regmap_config cdce925_regmap_config = {
+       .name = "configuration0",
+       .reg_bits = 8,
+       .val_bits = 8,
+       .cache_type = REGCACHE_RBTREE,
+       .max_register = 0x2F,
+};
+
+#define CDCE925_I2C_COMMAND_BLOCK_TRANSFER     0x00
+#define CDCE925_I2C_COMMAND_BYTE_TRANSFER      0x80
+
+static int cdce925_regmap_i2c_write(
+       void *context, const void *data, size_t count)
+{
+       struct device *dev = context;
+       struct i2c_client *i2c = to_i2c_client(dev);
+       int ret;
+       u8 reg_data[2];
+
+       if (count != 2)
+               return -ENOTSUPP;
+
+       /* First byte is command code */
+       reg_data[0] = CDCE925_I2C_COMMAND_BYTE_TRANSFER | ((u8 *)data)[0];
+       reg_data[1] = ((u8 *)data)[1];
+
+       dev_dbg(&i2c->dev, "%s(%zu) %#x %#x\n", __func__, count,
+                       reg_data[0], reg_data[1]);
+
+       ret = i2c_master_send(i2c, reg_data, count);
+       if (likely(ret == count))
+               return 0;
+       else if (ret < 0)
+               return ret;
+       else
+               return -EIO;
+}
+
+static int cdce925_regmap_i2c_read(void *context,
+          const void *reg, size_t reg_size, void *val, size_t val_size)
+{
+       struct device *dev = context;
+       struct i2c_client *i2c = to_i2c_client(dev);
+       struct i2c_msg xfer[2];
+       int ret;
+       u8 reg_data[2];
+
+       if (reg_size != 1)
+               return -ENOTSUPP;
+
+       xfer[0].addr = i2c->addr;
+       xfer[0].flags = 0;
+       xfer[0].buf = reg_data;
+       if (val_size == 1) {
+               reg_data[0] =
+                       CDCE925_I2C_COMMAND_BYTE_TRANSFER | ((u8 *)reg)[0];
+               xfer[0].len = 1;
+       } else {
+               reg_data[0] =
+                       CDCE925_I2C_COMMAND_BLOCK_TRANSFER | ((u8 *)reg)[0];
+               reg_data[1] = val_size;
+               xfer[0].len = 2;
+       }
+
+       xfer[1].addr = i2c->addr;
+       xfer[1].flags = I2C_M_RD;
+       xfer[1].len = val_size;
+       xfer[1].buf = val;
+
+       ret = i2c_transfer(i2c->adapter, xfer, 2);
+       if (likely(ret == 2)) {
+               dev_dbg(&i2c->dev, "%s(%zu, %zu) %#x %#x\n", __func__,
+                               reg_size, val_size, reg_data[0], *((u8 *)val));
+               return 0;
+       } else if (ret < 0)
+               return ret;
+       else
+               return -EIO;
+}
+
+/* The CDCE925 uses a funky way to read/write registers. Bulk mode is
+ * just weird, so just use the single byte mode exclusively. */
+static struct regmap_bus regmap_cdce925_bus = {
+       .write = cdce925_regmap_i2c_write,
+       .read = cdce925_regmap_i2c_read,
+};
+
+static int cdce925_probe(struct i2c_client *client,
+               const struct i2c_device_id *id)
+{
+       struct clk_cdce925_chip *data;
+       struct device_node *node = client->dev.of_node;
+       const char *parent_name;
+       const char *pll_clk_name[NUMBER_OF_PLLS] = {NULL,};
+       struct clk_init_data init;
+       struct clk *clk;
+       u32 value;
+       int i;
+       int err;
+       struct device_node *np_output;
+       char child_name[6];
+
+       dev_dbg(&client->dev, "%s\n", __func__);
+       data = devm_kzalloc(&client->dev, sizeof(*data), GFP_KERNEL);
+       if (!data)
+               return -ENOMEM;
+
+       data->i2c_client = client;
+       data->regmap = devm_regmap_init(&client->dev, &regmap_cdce925_bus,
+                       &client->dev, &cdce925_regmap_config);
+       if (IS_ERR(data->regmap)) {
+               dev_err(&client->dev, "failed to allocate register map\n");
+               return PTR_ERR(data->regmap);
+       }
+       i2c_set_clientdata(client, data);
+
+       parent_name = of_clk_get_parent_name(node, 0);
+       if (!parent_name) {
+               dev_err(&client->dev, "missing parent clock\n");
+               return -ENODEV;
+       }
+       dev_dbg(&client->dev, "parent is: %s\n", parent_name);
+
+       if (of_property_read_u32(node, "xtal-load-pf", &value) == 0)
+               regmap_write(data->regmap,
+                       CDCE925_REG_XCSEL, (value << 3) & 0xF8);
+       /* PWDN bit */
+       regmap_update_bits(data->regmap, CDCE925_REG_GLOBAL1, BIT(4), 0);
+
+       /* Set input source for Y1 to be the XTAL */
+       regmap_update_bits(data->regmap, 0x02, BIT(7), 0);
+
+       init.ops = &cdce925_pll_ops;
+       init.flags = 0;
+       init.parent_names = &parent_name;
+       init.num_parents = parent_name ? 1 : 0;
+
+       /* Register PLL clocks */
+       for (i = 0; i < NUMBER_OF_PLLS; ++i) {
+               pll_clk_name[i] = kasprintf(GFP_KERNEL, "%s.pll%d",
+                       client->dev.of_node->name, i);
+               init.name = pll_clk_name[i];
+               data->pll[i].chip = data;
+               data->pll[i].hw.init = &init;
+               data->pll[i].index = i;
+               clk = devm_clk_register(&client->dev, &data->pll[i].hw);
+               if (IS_ERR(clk)) {
+                       dev_err(&client->dev, "Failed register PLL %d\n", i);
+                       err = PTR_ERR(clk);
+                       goto error;
+               }
+               sprintf(child_name, "PLL%d", i+1);
+               np_output = of_get_child_by_name(node, child_name);
+               if (!np_output)
+                       continue;
+               if (!of_property_read_u32(np_output,
+                       "clock-frequency", &value)) {
+                       err = clk_set_rate(clk, value);
+                       if (err)
+                               dev_err(&client->dev,
+                                       "unable to set PLL frequency %ud\n",
+                                       value);
+               }
+               if (!of_property_read_u32(np_output,
+                       "spread-spectrum", &value)) {
+                       u8 flag = of_property_read_bool(np_output,
+                               "spread-spectrum-center") ? 0x80 : 0x00;
+                       regmap_update_bits(data->regmap,
+                               0x16 + (i*CDCE925_OFFSET_PLL),
+                               0x80, flag);
+                       regmap_update_bits(data->regmap,
+                               0x12 + (i*CDCE925_OFFSET_PLL),
+                               0x07, value & 0x07);
+               }
+       }
+
+       /* Register output clock Y1 */
+       init.ops = &cdce925_clk_y1_ops;
+       init.flags = 0;
+       init.num_parents = 1;
+       init.parent_names = &parent_name; /* Mux Y1 to input */
+       init.name = kasprintf(GFP_KERNEL, "%s.Y1", client->dev.of_node->name);
+       data->clk[0].chip = data;
+       data->clk[0].hw.init = &init;
+       data->clk[0].index = 0;
+       data->clk[0].pdiv = 1;
+       clk = devm_clk_register(&client->dev, &data->clk[0].hw);
+       kfree(init.name); /* clock framework made a copy of the name */
+       if (IS_ERR(clk)) {
+               dev_err(&client->dev, "clock registration Y1 failed\n");
+               err = PTR_ERR(clk);
+               goto error;
+       }
+       data->dt_clk[0] = clk;
+
+       /* Register output clocks Y2 .. Y5*/
+       init.ops = &cdce925_clk_ops;
+       init.flags = CLK_SET_RATE_PARENT;
+       init.num_parents = 1;
+       for (i = 1; i < NUMBER_OF_OUTPUTS; ++i) {
+               init.name = kasprintf(GFP_KERNEL, "%s.Y%d",
+                       client->dev.of_node->name, i+1);
+               data->clk[i].chip = data;
+               data->clk[i].hw.init = &init;
+               data->clk[i].index = i;
+               data->clk[i].pdiv = 1;
+               switch (i) {
+               case 1:
+               case 2:
+                       /* Mux Y2/3 to PLL1 */
+                       init.parent_names = &pll_clk_name[0];
+                       break;
+               case 3:
+               case 4:
+                       /* Mux Y4/5 to PLL2 */
+                       init.parent_names = &pll_clk_name[1];
+                       break;
+               }
+               clk = devm_clk_register(&client->dev, &data->clk[i].hw);
+               kfree(init.name); /* clock framework made a copy of the name */
+               if (IS_ERR(clk)) {
+                       dev_err(&client->dev, "clock registration failed\n");
+                       err = PTR_ERR(clk);
+                       goto error;
+               }
+               data->dt_clk[i] = clk;
+       }
+
+       /* Register the output clocks */
+       data->onecell.clk_num = NUMBER_OF_OUTPUTS;
+       data->onecell.clks = data->dt_clk;
+       err = of_clk_add_provider(client->dev.of_node, of_clk_src_onecell_get,
+               &data->onecell);
+       if (err)
+               dev_err(&client->dev, "unable to add OF clock provider\n");
+
+       err = 0;
+
+error:
+       for (i = 0; i < NUMBER_OF_PLLS; ++i)
+               /* clock framework made a copy of the name */
+               kfree(pll_clk_name[i]);
+
+       return err;
+}
+
+static const struct i2c_device_id cdce925_id[] = {
+       { "cdce925", 0 },
+       { }
+};
+MODULE_DEVICE_TABLE(i2c, cdce925_id);
+
+static const struct of_device_id clk_cdce925_of_match[] = {
+       { .compatible = "ti,cdce925" },
+       { },
+};
+MODULE_DEVICE_TABLE(of, clk_cdce925_of_match);
+
+static struct i2c_driver cdce925_driver = {
+       .driver = {
+               .name = "cdce925",
+               .of_match_table = of_match_ptr(clk_cdce925_of_match),
+       },
+       .probe          = cdce925_probe,
+       .id_table       = cdce925_id,
+};
+module_i2c_driver(cdce925_driver);
+
+MODULE_AUTHOR("Mike Looijmans <mike.looijmans@topic.nl>");
+MODULE_DESCRIPTION("cdce925 driver");
+MODULE_LICENSE("GPL");
index 956b7e54fa1c5f4f3583ac642c3f3f2ae255fee2..616f5aef3c26c7ad24334b1291d7d8178ef76ede 100644 (file)
@@ -188,7 +188,7 @@ static void clk_composite_disable(struct clk_hw *hw)
 }
 
 struct clk *clk_register_composite(struct device *dev, const char *name,
-                       const char **parent_names, int num_parents,
+                       const char * const *parent_names, int num_parents,
                        struct clk_hw *mux_hw, const struct clk_ops *mux_ops,
                        struct clk_hw *rate_hw, const struct clk_ops *rate_ops,
                        struct clk_hw *gate_hw, const struct clk_ops *gate_ops,
@@ -200,10 +200,8 @@ struct clk *clk_register_composite(struct device *dev, const char *name,
        struct clk_ops *clk_composite_ops;
 
        composite = kzalloc(sizeof(*composite), GFP_KERNEL);
-       if (!composite) {
-               pr_err("%s: could not allocate composite clk\n", __func__);
+       if (!composite)
                return ERR_PTR(-ENOMEM);
-       }
 
        init.name = name;
        init.flags = flags | CLK_IS_BASIC;
index 48a65b2b402785659d25120f6e18d70b478df4fe..43a218f35b190a21e62bc520cdac38f275f5da82 100644 (file)
@@ -106,8 +106,9 @@ static int __set_clk_rates(struct device_node *node, bool clk_supplier)
 
                        rc = clk_set_rate(clk, rate);
                        if (rc < 0)
-                               pr_err("clk: couldn't set %s clock rate: %d\n",
-                                      __clk_get_name(clk), rc);
+                               pr_err("clk: couldn't set %s clk rate to %d (%d), current rate: %ld\n",
+                                      __clk_get_name(clk), rate, rc,
+                                      clk_get_rate(clk));
                        clk_put(clk);
                }
                index++;
@@ -124,7 +125,7 @@ static int __set_clk_rates(struct device_node *node, bool clk_supplier)
  * and sets any specified clock parents and rates. The @clk_supplier argument
  * should be set to true if @node may be also a clock supplier of any clock
  * listed in its 'assigned-clocks' or 'assigned-clock-parents' properties.
- * If @clk_supplier is false the function exits returnning 0 as soon as it
+ * If @clk_supplier is false the function exits returning 0 as soon as it
  * determines the @node is also a supplier of any of the clocks.
  */
 int of_clk_set_defaults(struct device_node *node, bool clk_supplier)
index 25006a8bb8e6d5af8d145472fc76e2ef45281f09..706b5783c360dfc5ba60c6f7054374f5f06ff4f8 100644 (file)
@@ -430,11 +430,9 @@ static struct clk *_register_divider(struct device *dev, const char *name,
        }
 
        /* allocate the divider */
-       div = kzalloc(sizeof(struct clk_divider), GFP_KERNEL);
-       if (!div) {
-               pr_err("%s: could not allocate divider clk\n", __func__);
+       div = kzalloc(sizeof(*div), GFP_KERNEL);
+       if (!div)
                return ERR_PTR(-ENOMEM);
-       }
 
        init.name = name;
        init.ops = &clk_divider_ops;
index d9e3f671c2ea634012982c2228493cba8eb71903..fccabe497f6e5db42f6585acd9ecb1c4440bcb4e 100644 (file)
@@ -55,10 +55,16 @@ static long clk_factor_round_rate(struct clk_hw *hw, unsigned long rate,
 static int clk_factor_set_rate(struct clk_hw *hw, unsigned long rate,
                                unsigned long parent_rate)
 {
+       /*
+        * We must report success but we can do so unconditionally because
+        * clk_factor_round_rate returns values that ensure this call is a
+        * nop.
+        */
+
        return 0;
 }
 
-struct clk_ops clk_fixed_factor_ops = {
+const struct clk_ops clk_fixed_factor_ops = {
        .round_rate = clk_factor_round_rate,
        .set_rate = clk_factor_set_rate,
        .recalc_rate = clk_factor_recalc_rate,
@@ -74,10 +80,8 @@ struct clk *clk_register_fixed_factor(struct device *dev, const char *name,
        struct clk *clk;
 
        fix = kmalloc(sizeof(*fix), GFP_KERNEL);
-       if (!fix) {
-               pr_err("%s: could not allocate fixed factor clk\n", __func__);
+       if (!fix)
                return ERR_PTR(-ENOMEM);
-       }
 
        /* struct clk_fixed_factor assignments */
        fix->mult = mult;
index 0fc56ab6e844c88493e68f86b6a1fed8884a516e..f85ec8d1711fb7f36ac2e724308745dbf7b1ef47 100644 (file)
@@ -65,11 +65,9 @@ struct clk *clk_register_fixed_rate_with_accuracy(struct device *dev,
        struct clk_init_data init;
 
        /* allocate fixed-rate clock */
-       fixed = kzalloc(sizeof(struct clk_fixed_rate), GFP_KERNEL);
-       if (!fixed) {
-               pr_err("%s: could not allocate fixed clk\n", __func__);
+       fixed = kzalloc(sizeof(*fixed), GFP_KERNEL);
+       if (!fixed)
                return ERR_PTR(-ENOMEM);
-       }
 
        init.name = name;
        init.ops = &clk_fixed_rate_ops;
index 6aa72d9d79bad43d5c8f79f47fa30134d710a624..140eb5844dc4b86d1fb6b7034b5c375117dee0f8 100644 (file)
@@ -109,10 +109,8 @@ struct clk *clk_register_fractional_divider(struct device *dev,
        struct clk *clk;
 
        fd = kzalloc(sizeof(*fd), GFP_KERNEL);
-       if (!fd) {
-               dev_err(dev, "could not allocate fractional divider clk\n");
+       if (!fd)
                return ERR_PTR(-ENOMEM);
-       }
 
        init.name = name;
        init.ops = &clk_fractional_divider_ops;
index 3f0e4200cb5d4ca4a680c78479ac86ed116766a5..551dd067279402abbd45685315ee9df1c5f7c5d5 100644 (file)
@@ -135,11 +135,9 @@ struct clk *clk_register_gate(struct device *dev, const char *name,
        }
 
        /* allocate the gate */
-       gate = kzalloc(sizeof(struct clk_gate), GFP_KERNEL);
-       if (!gate) {
-               pr_err("%s: could not allocate gated clk\n", __func__);
+       gate = kzalloc(sizeof(*gate), GFP_KERNEL);
+       if (!gate)
                return ERR_PTR(-ENOMEM);
-       }
 
        init.name = name;
        init.ops = &clk_gate_ops;
index a71cabedda93c88d87230c038398413bb48e9c7b..f564e624fb935f3b2e4b77a768b6fae4b7d19563 100644 (file)
@@ -189,7 +189,7 @@ static struct clk *of_clk_gpio_gate_delayed_register_get(
 /**
  * of_gpio_gate_clk_setup() - Setup function for gpio controlled clock
  */
-void __init of_gpio_gate_clk_setup(struct device_node *node)
+static void __init of_gpio_gate_clk_setup(struct device_node *node)
 {
        struct clk_gpio_gate_delayed_register_data *data;
 
@@ -203,6 +203,5 @@ void __init of_gpio_gate_clk_setup(struct device_node *node)
 
        of_clk_add_provider(node, of_clk_gpio_gate_delayed_register_get, data);
 }
-EXPORT_SYMBOL_GPL(of_gpio_gate_clk_setup);
 CLK_OF_DECLARE(gpio_gate_clk, "gpio-gate-clock", of_gpio_gate_clk_setup);
 #endif
index ca80103ac1888f734fc25de4dd3ee6f3792ea1c9..d4c61985f4488ac1fac3ebc2f6061d98e922d2e3 100644 (file)
@@ -80,9 +80,9 @@ static struct clk *__init clk_register_pll(struct device *dev,
        return clk;
 }
 
-static const char const *cpu_parents[] = { "cpu_clk_div", "osc_33m_clk", };
-static const char const *ahb_parents[] = { "ahb_clk_div", "osc_33m_clk", };
-static const char const *dc_parents[] = { "dc_clk_div", "osc_33m_clk", };
+static const char * const cpu_parents[] = { "cpu_clk_div", "osc_33m_clk", };
+static const char * const ahb_parents[] = { "ahb_clk_div", "osc_33m_clk", };
+static const char * const dc_parents[] = { "dc_clk_div", "osc_33m_clk", };
 
 void __init ls1x_clk_init(void)
 {
index 6505049d50f1e54720864b58694ef0be26e314b9..35af9cb6da4ff3c06601139c7db544a5bf88578f 100644 (file)
@@ -31,6 +31,8 @@
 #include <linux/of.h>
 #include <linux/export.h>
 
+#include "clk-max-gen.h"
+
 struct max_gen_clk {
        struct regmap *regmap;
        u32 mask;
index 30a3b6999e10e16581bdac42911e0d9ca2c24989..5181b89c3cb2f18de2047a70a0bc43c562be4326 100644 (file)
@@ -15,7 +15,7 @@
 #include <linux/of_address.h>
 #include <linux/clkdev.h>
 
-void __init moxart_of_pll_clk_init(struct device_node *node)
+static void __init moxart_of_pll_clk_init(struct device_node *node)
 {
        static void __iomem *base;
        struct clk *clk, *ref_clk;
@@ -53,7 +53,7 @@ void __init moxart_of_pll_clk_init(struct device_node *node)
 CLK_OF_DECLARE(moxart_pll_clock, "moxa,moxart-pll-clock",
               moxart_of_pll_clk_init);
 
-void __init moxart_of_apb_clk_init(struct device_node *node)
+static void __init moxart_of_apb_clk_init(struct device_node *node)
 {
        static void __iomem *base;
        struct clk *clk, *pll_clk;
index 69a094c3783d8eb2a2c0d3624f3a641f97a5d484..6066a01b20ea8d0e304dca2ff27bc34da9e0bf1c 100644 (file)
@@ -114,7 +114,8 @@ const struct clk_ops clk_mux_ro_ops = {
 EXPORT_SYMBOL_GPL(clk_mux_ro_ops);
 
 struct clk *clk_register_mux_table(struct device *dev, const char *name,
-               const char **parent_names, u8 num_parents, unsigned long flags,
+               const char * const *parent_names, u8 num_parents,
+               unsigned long flags,
                void __iomem *reg, u8 shift, u32 mask,
                u8 clk_mux_flags, u32 *table, spinlock_t *lock)
 {
@@ -166,7 +167,8 @@ struct clk *clk_register_mux_table(struct device *dev, const char *name,
 EXPORT_SYMBOL_GPL(clk_register_mux_table);
 
 struct clk *clk_register_mux(struct device *dev, const char *name,
-               const char **parent_names, u8 num_parents, unsigned long flags,
+               const char * const *parent_names, u8 num_parents,
+               unsigned long flags,
                void __iomem *reg, u8 shift, u8 width,
                u8 clk_mux_flags, spinlock_t *lock)
 {
index 30335d3b99afb197332505d5be045f2d5d75be4c..e39e1e680b3c6c09b117e7a32a35b7d1a808bf37 100644 (file)
@@ -552,7 +552,8 @@ static const struct clk_ops si5351_pll_ops = {
  * MSx_P2[19:0] = 128 * b - c * floor(128 * b/c) = (128*b) mod c
  * MSx_P3[19:0] = c
  *
- * MS[6,7] are integer (P1) divide only, P2 = 0, P3 = 0
+ * MS[6,7] are integer (P1) divide only, P1 = divide value,
+ * P2 and P3 are not applicable
  *
  * for 150MHz < fOUT <= 160MHz:
  *
@@ -606,9 +607,6 @@ static unsigned long si5351_msynth_recalc_rate(struct clk_hw *hw,
        if (!hwdata->params.valid)
                si5351_read_parameters(hwdata->drvdata, reg, &hwdata->params);
 
-       if (hwdata->params.p3 == 0)
-               return parent_rate;
-
        /*
         * multisync0-5: fOUT = (128 * P3 * fIN) / (P1*P3 + P2 + 512*P3)
         * multisync6-7: fOUT = fIN / P1
@@ -616,6 +614,8 @@ static unsigned long si5351_msynth_recalc_rate(struct clk_hw *hw,
        rate = parent_rate;
        if (hwdata->num > 5) {
                m = hwdata->params.p1;
+       } else if (hwdata->params.p3 == 0) {
+               return parent_rate;
        } else if ((si5351_reg_read(hwdata->drvdata, reg + 2) &
                    SI5351_OUTPUT_CLK_DIVBY4) == SI5351_OUTPUT_CLK_DIVBY4) {
                m = 4;
@@ -679,6 +679,16 @@ static long si5351_msynth_round_rate(struct clk_hw *hw, unsigned long rate,
                c = 1;
 
                *parent_rate = a * rate;
+       } else if (hwdata->num >= 6) {
+               /* determine the closest integer divider */
+               a = DIV_ROUND_CLOSEST(*parent_rate, rate);
+               if (a < SI5351_MULTISYNTH_A_MIN)
+                       a = SI5351_MULTISYNTH_A_MIN;
+               if (a > SI5351_MULTISYNTH67_A_MAX)
+                       a = SI5351_MULTISYNTH67_A_MAX;
+
+               b = 0;
+               c = 1;
        } else {
                unsigned long rfrac, denom;
 
@@ -692,9 +702,7 @@ static long si5351_msynth_round_rate(struct clk_hw *hw, unsigned long rate,
                a = *parent_rate / rate;
                if (a < SI5351_MULTISYNTH_A_MIN)
                        a = SI5351_MULTISYNTH_A_MIN;
-               if (hwdata->num >= 6 && a > SI5351_MULTISYNTH67_A_MAX)
-                       a = SI5351_MULTISYNTH67_A_MAX;
-               else if (a > SI5351_MULTISYNTH_A_MAX)
+               if (a > SI5351_MULTISYNTH_A_MAX)
                        a = SI5351_MULTISYNTH_A_MAX;
 
                /* find best approximation for b/c = fVCO mod fOUT */
@@ -723,6 +731,10 @@ static long si5351_msynth_round_rate(struct clk_hw *hw, unsigned long rate,
                hwdata->params.p3 = 1;
                hwdata->params.p2 = 0;
                hwdata->params.p1 = 0;
+       } else if (hwdata->num >= 6) {
+               hwdata->params.p3 = 0;
+               hwdata->params.p2 = 0;
+               hwdata->params.p1 = a;
        } else {
                hwdata->params.p3  = c;
                hwdata->params.p2  = (128 * b) % c;
diff --git a/drivers/clk/clk-stm32f4.c b/drivers/clk/clk-stm32f4.c
new file mode 100644 (file)
index 0000000..b9b12a7
--- /dev/null
@@ -0,0 +1,380 @@
+/*
+ * Author: Daniel Thompson <daniel.thompson@linaro.org>
+ *
+ * Inspired by clk-asm9260.c .
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <linux/clk-provider.h>
+#include <linux/err.h>
+#include <linux/io.h>
+#include <linux/slab.h>
+#include <linux/spinlock.h>
+#include <linux/of.h>
+#include <linux/of_address.h>
+
+#define STM32F4_RCC_PLLCFGR            0x04
+#define STM32F4_RCC_CFGR               0x08
+#define STM32F4_RCC_AHB1ENR            0x30
+#define STM32F4_RCC_AHB2ENR            0x34
+#define STM32F4_RCC_AHB3ENR            0x38
+#define STM32F4_RCC_APB1ENR            0x40
+#define STM32F4_RCC_APB2ENR            0x44
+
+struct stm32f4_gate_data {
+       u8      offset;
+       u8      bit_idx;
+       const char *name;
+       const char *parent_name;
+       unsigned long flags;
+};
+
+static const struct stm32f4_gate_data stm32f4_gates[] __initconst = {
+       { STM32F4_RCC_AHB1ENR,  0,      "gpioa",        "ahb_div" },
+       { STM32F4_RCC_AHB1ENR,  1,      "gpiob",        "ahb_div" },
+       { STM32F4_RCC_AHB1ENR,  2,      "gpioc",        "ahb_div" },
+       { STM32F4_RCC_AHB1ENR,  3,      "gpiod",        "ahb_div" },
+       { STM32F4_RCC_AHB1ENR,  4,      "gpioe",        "ahb_div" },
+       { STM32F4_RCC_AHB1ENR,  5,      "gpiof",        "ahb_div" },
+       { STM32F4_RCC_AHB1ENR,  6,      "gpiog",        "ahb_div" },
+       { STM32F4_RCC_AHB1ENR,  7,      "gpioh",        "ahb_div" },
+       { STM32F4_RCC_AHB1ENR,  8,      "gpioi",        "ahb_div" },
+       { STM32F4_RCC_AHB1ENR,  9,      "gpioj",        "ahb_div" },
+       { STM32F4_RCC_AHB1ENR, 10,      "gpiok",        "ahb_div" },
+       { STM32F4_RCC_AHB1ENR, 12,      "crc",          "ahb_div" },
+       { STM32F4_RCC_AHB1ENR, 18,      "bkpsra",       "ahb_div" },
+       { STM32F4_RCC_AHB1ENR, 20,      "ccmdatam",     "ahb_div" },
+       { STM32F4_RCC_AHB1ENR, 21,      "dma1",         "ahb_div" },
+       { STM32F4_RCC_AHB1ENR, 22,      "dma2",         "ahb_div" },
+       { STM32F4_RCC_AHB1ENR, 23,      "dma2d",        "ahb_div" },
+       { STM32F4_RCC_AHB1ENR, 25,      "ethmac",       "ahb_div" },
+       { STM32F4_RCC_AHB1ENR, 26,      "ethmactx",     "ahb_div" },
+       { STM32F4_RCC_AHB1ENR, 27,      "ethmacrx",     "ahb_div" },
+       { STM32F4_RCC_AHB1ENR, 28,      "ethmacptp",    "ahb_div" },
+       { STM32F4_RCC_AHB1ENR, 29,      "otghs",        "ahb_div" },
+       { STM32F4_RCC_AHB1ENR, 30,      "otghsulpi",    "ahb_div" },
+
+       { STM32F4_RCC_AHB2ENR,  0,      "dcmi",         "ahb_div" },
+       { STM32F4_RCC_AHB2ENR,  4,      "cryp",         "ahb_div" },
+       { STM32F4_RCC_AHB2ENR,  5,      "hash",         "ahb_div" },
+       { STM32F4_RCC_AHB2ENR,  6,      "rng",          "pll48" },
+       { STM32F4_RCC_AHB2ENR,  7,      "otgfs",        "pll48" },
+
+       { STM32F4_RCC_AHB3ENR,  0,      "fmc",          "ahb_div",
+               CLK_IGNORE_UNUSED },
+
+       { STM32F4_RCC_APB1ENR,  0,      "tim2",         "apb1_mul" },
+       { STM32F4_RCC_APB1ENR,  1,      "tim3",         "apb1_mul" },
+       { STM32F4_RCC_APB1ENR,  2,      "tim4",         "apb1_mul" },
+       { STM32F4_RCC_APB1ENR,  3,      "tim5",         "apb1_mul" },
+       { STM32F4_RCC_APB1ENR,  4,      "tim6",         "apb1_mul" },
+       { STM32F4_RCC_APB1ENR,  5,      "tim7",         "apb1_mul" },
+       { STM32F4_RCC_APB1ENR,  6,      "tim12",        "apb1_mul" },
+       { STM32F4_RCC_APB1ENR,  7,      "tim13",        "apb1_mul" },
+       { STM32F4_RCC_APB1ENR,  8,      "tim14",        "apb1_mul" },
+       { STM32F4_RCC_APB1ENR, 11,      "wwdg",         "apb1_div" },
+       { STM32F4_RCC_APB1ENR, 14,      "spi2",         "apb1_div" },
+       { STM32F4_RCC_APB1ENR, 15,      "spi3",         "apb1_div" },
+       { STM32F4_RCC_APB1ENR, 17,      "uart2",        "apb1_div" },
+       { STM32F4_RCC_APB1ENR, 18,      "uart3",        "apb1_div" },
+       { STM32F4_RCC_APB1ENR, 19,      "uart4",        "apb1_div" },
+       { STM32F4_RCC_APB1ENR, 20,      "uart5",        "apb1_div" },
+       { STM32F4_RCC_APB1ENR, 21,      "i2c1",         "apb1_div" },
+       { STM32F4_RCC_APB1ENR, 22,      "i2c2",         "apb1_div" },
+       { STM32F4_RCC_APB1ENR, 23,      "i2c3",         "apb1_div" },
+       { STM32F4_RCC_APB1ENR, 25,      "can1",         "apb1_div" },
+       { STM32F4_RCC_APB1ENR, 26,      "can2",         "apb1_div" },
+       { STM32F4_RCC_APB1ENR, 28,      "pwr",          "apb1_div" },
+       { STM32F4_RCC_APB1ENR, 29,      "dac",          "apb1_div" },
+       { STM32F4_RCC_APB1ENR, 30,      "uart7",        "apb1_div" },
+       { STM32F4_RCC_APB1ENR, 31,      "uart8",        "apb1_div" },
+
+       { STM32F4_RCC_APB2ENR,  0,      "tim1",         "apb2_mul" },
+       { STM32F4_RCC_APB2ENR,  1,      "tim8",         "apb2_mul" },
+       { STM32F4_RCC_APB2ENR,  4,      "usart1",       "apb2_div" },
+       { STM32F4_RCC_APB2ENR,  5,      "usart6",       "apb2_div" },
+       { STM32F4_RCC_APB2ENR,  8,      "adc1",         "apb2_div" },
+       { STM32F4_RCC_APB2ENR,  9,      "adc2",         "apb2_div" },
+       { STM32F4_RCC_APB2ENR, 10,      "adc3",         "apb2_div" },
+       { STM32F4_RCC_APB2ENR, 11,      "sdio",         "pll48" },
+       { STM32F4_RCC_APB2ENR, 12,      "spi1",         "apb2_div" },
+       { STM32F4_RCC_APB2ENR, 13,      "spi4",         "apb2_div" },
+       { STM32F4_RCC_APB2ENR, 14,      "syscfg",       "apb2_div" },
+       { STM32F4_RCC_APB2ENR, 16,      "tim9",         "apb2_mul" },
+       { STM32F4_RCC_APB2ENR, 17,      "tim10",        "apb2_mul" },
+       { STM32F4_RCC_APB2ENR, 18,      "tim11",        "apb2_mul" },
+       { STM32F4_RCC_APB2ENR, 20,      "spi5",         "apb2_div" },
+       { STM32F4_RCC_APB2ENR, 21,      "spi6",         "apb2_div" },
+       { STM32F4_RCC_APB2ENR, 22,      "sai1",         "apb2_div" },
+       { STM32F4_RCC_APB2ENR, 26,      "ltdc",         "apb2_div" },
+};
+
+/*
+ * MAX_CLKS is the maximum value in the enumeration below plus the combined
+ * hweight of stm32f42xx_gate_map (plus one).
+ */
+#define MAX_CLKS 74
+
+enum { SYSTICK, FCLK };
+
+/*
+ * This bitmask tells us which bit offsets (0..192) on STM32F4[23]xxx
+ * have gate bits associated with them. Its combined hweight is 71.
+ */
+static const u64 stm32f42xx_gate_map[] = { 0x000000f17ef417ffull,
+                                          0x0000000000000001ull,
+                                          0x04777f33f6fec9ffull };
+
+static struct clk *clks[MAX_CLKS];
+static DEFINE_SPINLOCK(stm32f4_clk_lock);
+static void __iomem *base;
+
+/*
+ * "Multiplier" device for APBx clocks.
+ *
+ * The APBx dividers are power-of-two dividers and, if *not* running in 1:1
+ * mode, they also tap out the one of the low order state bits to run the
+ * timers. ST datasheets represent this feature as a (conditional) clock
+ * multiplier.
+ */
+struct clk_apb_mul {
+       struct clk_hw hw;
+       u8 bit_idx;
+};
+
+#define to_clk_apb_mul(_hw) container_of(_hw, struct clk_apb_mul, hw)
+
+static unsigned long clk_apb_mul_recalc_rate(struct clk_hw *hw,
+                                            unsigned long parent_rate)
+{
+       struct clk_apb_mul *am = to_clk_apb_mul(hw);
+
+       if (readl(base + STM32F4_RCC_CFGR) & BIT(am->bit_idx))
+               return parent_rate * 2;
+
+       return parent_rate;
+}
+
+static long clk_apb_mul_round_rate(struct clk_hw *hw, unsigned long rate,
+                                  unsigned long *prate)
+{
+       struct clk_apb_mul *am = to_clk_apb_mul(hw);
+       unsigned long mult = 1;
+
+       if (readl(base + STM32F4_RCC_CFGR) & BIT(am->bit_idx))
+               mult = 2;
+
+       if (__clk_get_flags(hw->clk) & CLK_SET_RATE_PARENT) {
+               unsigned long best_parent = rate / mult;
+
+               *prate =
+                   __clk_round_rate(__clk_get_parent(hw->clk), best_parent);
+       }
+
+       return *prate * mult;
+}
+
+static int clk_apb_mul_set_rate(struct clk_hw *hw, unsigned long rate,
+                               unsigned long parent_rate)
+{
+       /*
+        * We must report success but we can do so unconditionally because
+        * clk_apb_mul_round_rate returns values that ensure this call is a
+        * nop.
+        */
+
+       return 0;
+}
+
+static const struct clk_ops clk_apb_mul_factor_ops = {
+       .round_rate = clk_apb_mul_round_rate,
+       .set_rate = clk_apb_mul_set_rate,
+       .recalc_rate = clk_apb_mul_recalc_rate,
+};
+
+static struct clk *clk_register_apb_mul(struct device *dev, const char *name,
+                                       const char *parent_name,
+                                       unsigned long flags, u8 bit_idx)
+{
+       struct clk_apb_mul *am;
+       struct clk_init_data init;
+       struct clk *clk;
+
+       am = kzalloc(sizeof(*am), GFP_KERNEL);
+       if (!am)
+               return ERR_PTR(-ENOMEM);
+
+       am->bit_idx = bit_idx;
+       am->hw.init = &init;
+
+       init.name = name;
+       init.ops = &clk_apb_mul_factor_ops;
+       init.flags = flags;
+       init.parent_names = &parent_name;
+       init.num_parents = 1;
+
+       clk = clk_register(dev, &am->hw);
+
+       if (IS_ERR(clk))
+               kfree(am);
+
+       return clk;
+}
+
+/*
+ * Decode current PLL state and (statically) model the state we inherit from
+ * the bootloader.
+ */
+static void stm32f4_rcc_register_pll(const char *hse_clk, const char *hsi_clk)
+{
+       unsigned long pllcfgr = readl(base + STM32F4_RCC_PLLCFGR);
+
+       unsigned long pllm   = pllcfgr & 0x3f;
+       unsigned long plln   = (pllcfgr >> 6) & 0x1ff;
+       unsigned long pllp   = BIT(((pllcfgr >> 16) & 3) + 1);
+       const char   *pllsrc = pllcfgr & BIT(22) ? hse_clk : hsi_clk;
+       unsigned long pllq   = (pllcfgr >> 24) & 0xf;
+
+       clk_register_fixed_factor(NULL, "vco", pllsrc, 0, plln, pllm);
+       clk_register_fixed_factor(NULL, "pll", "vco", 0, 1, pllp);
+       clk_register_fixed_factor(NULL, "pll48", "vco", 0, 1, pllq);
+}
+
+/*
+ * Converts the primary and secondary indices (as they appear in DT) to an
+ * offset into our struct clock array.
+ */
+static int stm32f4_rcc_lookup_clk_idx(u8 primary, u8 secondary)
+{
+       u64 table[ARRAY_SIZE(stm32f42xx_gate_map)];
+
+       if (primary == 1) {
+               if (WARN_ON(secondary > FCLK))
+                       return -EINVAL;
+               return secondary;
+       }
+
+       memcpy(table, stm32f42xx_gate_map, sizeof(table));
+
+       /* only bits set in table can be used as indices */
+       if (WARN_ON(secondary > 8 * sizeof(table) ||
+                   0 == (table[BIT_ULL_WORD(secondary)] &
+                         BIT_ULL_MASK(secondary))))
+               return -EINVAL;
+
+       /* mask out bits above our current index */
+       table[BIT_ULL_WORD(secondary)] &=
+           GENMASK_ULL(secondary % BITS_PER_LONG_LONG, 0);
+
+       return FCLK + hweight64(table[0]) +
+              (BIT_ULL_WORD(secondary) >= 1 ? hweight64(table[1]) : 0) +
+              (BIT_ULL_WORD(secondary) >= 2 ? hweight64(table[2]) : 0);
+}
+
+static struct clk *
+stm32f4_rcc_lookup_clk(struct of_phandle_args *clkspec, void *data)
+{
+       int i = stm32f4_rcc_lookup_clk_idx(clkspec->args[0], clkspec->args[1]);
+
+       if (i < 0)
+               return ERR_PTR(-EINVAL);
+
+       return clks[i];
+}
+
+static const char *sys_parents[] __initdata =   { "hsi", NULL, "pll" };
+
+static const struct clk_div_table ahb_div_table[] = {
+       { 0x0,   1 }, { 0x1,   1 }, { 0x2,   1 }, { 0x3,   1 },
+       { 0x4,   1 }, { 0x5,   1 }, { 0x6,   1 }, { 0x7,   1 },
+       { 0x8,   2 }, { 0x9,   4 }, { 0xa,   8 }, { 0xb,  16 },
+       { 0xc,  64 }, { 0xd, 128 }, { 0xe, 256 }, { 0xf, 512 },
+       { 0 },
+};
+
+static const struct clk_div_table apb_div_table[] = {
+       { 0,  1 }, { 0,  1 }, { 0,  1 }, { 0,  1 },
+       { 4,  2 }, { 5,  4 }, { 6,  8 }, { 7, 16 },
+       { 0 },
+};
+
+static void __init stm32f4_rcc_init(struct device_node *np)
+{
+       const char *hse_clk;
+       int n;
+
+       base = of_iomap(np, 0);
+       if (!base) {
+               pr_err("%s: unable to map resource", np->name);
+               return;
+       }
+
+       hse_clk = of_clk_get_parent_name(np, 0);
+
+       clk_register_fixed_rate_with_accuracy(NULL, "hsi", NULL, 0,
+                       16000000, 160000);
+       stm32f4_rcc_register_pll(hse_clk, "hsi");
+
+       sys_parents[1] = hse_clk;
+       clk_register_mux_table(
+           NULL, "sys", sys_parents, ARRAY_SIZE(sys_parents), 0,
+           base + STM32F4_RCC_CFGR, 0, 3, 0, NULL, &stm32f4_clk_lock);
+
+       clk_register_divider_table(NULL, "ahb_div", "sys",
+                                  CLK_SET_RATE_PARENT, base + STM32F4_RCC_CFGR,
+                                  4, 4, 0, ahb_div_table, &stm32f4_clk_lock);
+
+       clk_register_divider_table(NULL, "apb1_div", "ahb_div",
+                                  CLK_SET_RATE_PARENT, base + STM32F4_RCC_CFGR,
+                                  10, 3, 0, apb_div_table, &stm32f4_clk_lock);
+       clk_register_apb_mul(NULL, "apb1_mul", "apb1_div",
+                            CLK_SET_RATE_PARENT, 12);
+
+       clk_register_divider_table(NULL, "apb2_div", "ahb_div",
+                                  CLK_SET_RATE_PARENT, base + STM32F4_RCC_CFGR,
+                                  13, 3, 0, apb_div_table, &stm32f4_clk_lock);
+       clk_register_apb_mul(NULL, "apb2_mul", "apb2_div",
+                            CLK_SET_RATE_PARENT, 15);
+
+       clks[SYSTICK] = clk_register_fixed_factor(NULL, "systick", "ahb_div",
+                                                 0, 1, 8);
+       clks[FCLK] = clk_register_fixed_factor(NULL, "fclk", "ahb_div",
+                                              0, 1, 1);
+
+       for (n = 0; n < ARRAY_SIZE(stm32f4_gates); n++) {
+               const struct stm32f4_gate_data *gd = &stm32f4_gates[n];
+               unsigned int secondary =
+                   8 * (gd->offset - STM32F4_RCC_AHB1ENR) + gd->bit_idx;
+               int idx = stm32f4_rcc_lookup_clk_idx(0, secondary);
+
+               if (idx < 0)
+                       goto fail;
+
+               clks[idx] = clk_register_gate(
+                   NULL, gd->name, gd->parent_name, gd->flags,
+                   base + gd->offset, gd->bit_idx, 0, &stm32f4_clk_lock);
+
+               if (IS_ERR(clks[n])) {
+                       pr_err("%s: Unable to register leaf clock %s\n",
+                              np->full_name, gd->name);
+                       goto fail;
+               }
+       }
+
+       of_clk_add_provider(np, stm32f4_rcc_lookup_clk, NULL);
+       return;
+fail:
+       iounmap(base);
+}
+CLK_OF_DECLARE(stm32f4_rcc, "st,stm32f42xx-rcc", stm32f4_rcc_init);
index 406bfc1375b2d4a44e9e4993786cca2c48c713f3..18bf5e576b9390c680b4e9a08637104cb07cdde4 100644 (file)
@@ -12,6 +12,7 @@
 #include <linux/clk-provider.h>
 #include <linux/spinlock.h>
 #include <linux/of.h>
+#include <linux/platform_data/clk-u300.h>
 
 /* APP side SYSCON registers */
 /* CLK Control Register 16bit (R/W) */
index dd8a62d8f11f12da7aa51b6bace5287bf4532b7d..f26b3ac36b27a1aa06fd7db2b3352420f96c7768 100644 (file)
 
 static DEFINE_SPINLOCK(clk_lock);
 
-static inline u32 xgene_clk_read(void *csr)
+static inline u32 xgene_clk_read(void __iomem *csr)
 {
        return readl_relaxed(csr);
 }
 
-static inline void xgene_clk_write(u32 data, void *csr)
+static inline void xgene_clk_write(u32 data, void __iomem *csr)
 {
        return writel_relaxed(data, csr);
 }
@@ -119,7 +119,7 @@ static unsigned long xgene_clk_pll_recalc_rate(struct clk_hw *hw,
        return fvco / nout;
 }
 
-const struct clk_ops xgene_clk_pll_ops = {
+static const struct clk_ops xgene_clk_pll_ops = {
        .is_enabled = xgene_clk_pll_is_enabled,
        .recalc_rate = xgene_clk_pll_recalc_rate,
 };
@@ -167,7 +167,7 @@ static void xgene_pllclk_init(struct device_node *np, enum xgene_pll_type pll_ty
 {
         const char *clk_name = np->full_name;
         struct clk *clk;
-        void *reg;
+        void __iomem *reg;
 
         reg = of_iomap(np, 0);
         if (reg == NULL) {
@@ -222,20 +222,22 @@ static int xgene_clk_enable(struct clk_hw *hw)
        struct xgene_clk *pclk = to_xgene_clk(hw);
        unsigned long flags = 0;
        u32 data;
+       phys_addr_t reg;
 
        if (pclk->lock)
                spin_lock_irqsave(pclk->lock, flags);
 
        if (pclk->param.csr_reg != NULL) {
                pr_debug("%s clock enabled\n", pclk->name);
+               reg = __pa(pclk->param.csr_reg);
                /* First enable the clock */
                data = xgene_clk_read(pclk->param.csr_reg +
                                        pclk->param.reg_clk_offset);
                data |= pclk->param.reg_clk_mask;
                xgene_clk_write(data, pclk->param.csr_reg +
                                        pclk->param.reg_clk_offset);
-               pr_debug("%s clock PADDR base 0x%016LX clk offset 0x%08X mask 0x%08X value 0x%08X\n",
-                       pclk->name, __pa(pclk->param.csr_reg),
+               pr_debug("%s clock PADDR base %pa clk offset 0x%08X mask 0x%08X value 0x%08X\n",
+                       pclk->name, &reg,
                        pclk->param.reg_clk_offset, pclk->param.reg_clk_mask,
                        data);
 
@@ -245,8 +247,8 @@ static int xgene_clk_enable(struct clk_hw *hw)
                data &= ~pclk->param.reg_csr_mask;
                xgene_clk_write(data, pclk->param.csr_reg +
                                        pclk->param.reg_csr_offset);
-               pr_debug("%s CSR RESET PADDR base 0x%016LX csr offset 0x%08X mask 0x%08X value 0x%08X\n",
-                       pclk->name, __pa(pclk->param.csr_reg),
+               pr_debug("%s CSR RESET PADDR base %pa csr offset 0x%08X mask 0x%08X value 0x%08X\n",
+                       pclk->name, &reg,
                        pclk->param.reg_csr_offset, pclk->param.reg_csr_mask,
                        data);
        }
@@ -386,7 +388,7 @@ static long xgene_clk_round_rate(struct clk_hw *hw, unsigned long rate,
        return parent_rate / divider;
 }
 
-const struct clk_ops xgene_clk_ops = {
+static const struct clk_ops xgene_clk_ops = {
        .enable = xgene_clk_enable,
        .disable = xgene_clk_disable,
        .is_enabled = xgene_clk_is_enabled,
@@ -456,7 +458,7 @@ static void __init xgene_devclk_init(struct device_node *np)
        parameters.csr_reg = NULL;
        parameters.divider_reg = NULL;
        for (i = 0; i < 2; i++) {
-               void *map_res;
+               void __iomem *map_res;
                rc = of_address_to_resource(np, i, &res);
                if (rc != 0) {
                        if (i == 0) {
index 5b0f41868b425672e6295ac6b30a52e43cf5730c..ddb4b541016fe986860a95a4a482d2f6c6713a3e 100644 (file)
@@ -21,6 +21,7 @@
 #include <linux/device.h>
 #include <linux/init.h>
 #include <linux/sched.h>
+#include <linux/clkdev.h>
 
 #include "clk.h"
 
@@ -37,13 +38,6 @@ static HLIST_HEAD(clk_root_list);
 static HLIST_HEAD(clk_orphan_list);
 static LIST_HEAD(clk_notifier_list);
 
-static long clk_core_get_accuracy(struct clk_core *clk);
-static unsigned long clk_core_get_rate(struct clk_core *clk);
-static int clk_core_get_phase(struct clk_core *clk);
-static bool clk_core_is_prepared(struct clk_core *clk);
-static bool clk_core_is_enabled(struct clk_core *clk);
-static struct clk_core *clk_core_lookup(const char *name);
-
 /***    private data structures    ***/
 
 struct clk_core {
@@ -68,11 +62,11 @@ struct clk_core {
        int                     phase;
        struct hlist_head       children;
        struct hlist_node       child_node;
-       struct hlist_node       debug_node;
        struct hlist_head       clks;
        unsigned int            notifier_count;
 #ifdef CONFIG_DEBUG_FS
        struct dentry           *dentry;
+       struct hlist_node       debug_node;
 #endif
        struct kref             ref;
 };
@@ -145,516 +139,248 @@ static void clk_enable_unlock(unsigned long flags)
        spin_unlock_irqrestore(&enable_lock, flags);
 }
 
-/***        debugfs support        ***/
-
-#ifdef CONFIG_DEBUG_FS
-#include <linux/debugfs.h>
-
-static struct dentry *rootdir;
-static int inited = 0;
-static DEFINE_MUTEX(clk_debug_lock);
-static HLIST_HEAD(clk_debug_list);
-
-static struct hlist_head *all_lists[] = {
-       &clk_root_list,
-       &clk_orphan_list,
-       NULL,
-};
+static bool clk_core_is_prepared(struct clk_core *core)
+{
+       /*
+        * .is_prepared is optional for clocks that can prepare
+        * fall back to software usage counter if it is missing
+        */
+       if (!core->ops->is_prepared)
+               return core->prepare_count;
 
-static struct hlist_head *orphan_list[] = {
-       &clk_orphan_list,
-       NULL,
-};
+       return core->ops->is_prepared(core->hw);
+}
 
-static void clk_summary_show_one(struct seq_file *s, struct clk_core *c,
-                                int level)
+static bool clk_core_is_enabled(struct clk_core *core)
 {
-       if (!c)
-               return;
+       /*
+        * .is_enabled is only mandatory for clocks that gate
+        * fall back to software usage counter if .is_enabled is missing
+        */
+       if (!core->ops->is_enabled)
+               return core->enable_count;
 
-       seq_printf(s, "%*s%-*s %11d %12d %11lu %10lu %-3d\n",
-                  level * 3 + 1, "",
-                  30 - level * 3, c->name,
-                  c->enable_count, c->prepare_count, clk_core_get_rate(c),
-                  clk_core_get_accuracy(c), clk_core_get_phase(c));
+       return core->ops->is_enabled(core->hw);
 }
 
-static void clk_summary_show_subtree(struct seq_file *s, struct clk_core *c,
-                                    int level)
+static void clk_unprepare_unused_subtree(struct clk_core *core)
 {
        struct clk_core *child;
 
-       if (!c)
+       lockdep_assert_held(&prepare_lock);
+
+       hlist_for_each_entry(child, &core->children, child_node)
+               clk_unprepare_unused_subtree(child);
+
+       if (core->prepare_count)
                return;
 
-       clk_summary_show_one(s, c, level);
+       if (core->flags & CLK_IGNORE_UNUSED)
+               return;
 
-       hlist_for_each_entry(child, &c->children, child_node)
-               clk_summary_show_subtree(s, child, level + 1);
+       if (clk_core_is_prepared(core)) {
+               trace_clk_unprepare(core);
+               if (core->ops->unprepare_unused)
+                       core->ops->unprepare_unused(core->hw);
+               else if (core->ops->unprepare)
+                       core->ops->unprepare(core->hw);
+               trace_clk_unprepare_complete(core);
+       }
 }
 
-static int clk_summary_show(struct seq_file *s, void *data)
+static void clk_disable_unused_subtree(struct clk_core *core)
 {
-       struct clk_core *c;
-       struct hlist_head **lists = (struct hlist_head **)s->private;
+       struct clk_core *child;
+       unsigned long flags;
 
-       seq_puts(s, "   clock                         enable_cnt  prepare_cnt        rate   accuracy   phase\n");
-       seq_puts(s, "----------------------------------------------------------------------------------------\n");
+       lockdep_assert_held(&prepare_lock);
 
-       clk_prepare_lock();
+       hlist_for_each_entry(child, &core->children, child_node)
+               clk_disable_unused_subtree(child);
 
-       for (; *lists; lists++)
-               hlist_for_each_entry(c, *lists, child_node)
-                       clk_summary_show_subtree(s, c, 0);
+       flags = clk_enable_lock();
 
-       clk_prepare_unlock();
+       if (core->enable_count)
+               goto unlock_out;
 
-       return 0;
-}
+       if (core->flags & CLK_IGNORE_UNUSED)
+               goto unlock_out;
 
+       /*
+        * some gate clocks have special needs during the disable-unused
+        * sequence.  call .disable_unused if available, otherwise fall
+        * back to .disable
+        */
+       if (clk_core_is_enabled(core)) {
+               trace_clk_disable(core);
+               if (core->ops->disable_unused)
+                       core->ops->disable_unused(core->hw);
+               else if (core->ops->disable)
+                       core->ops->disable(core->hw);
+               trace_clk_disable_complete(core);
+       }
 
-static int clk_summary_open(struct inode *inode, struct file *file)
-{
-       return single_open(file, clk_summary_show, inode->i_private);
+unlock_out:
+       clk_enable_unlock(flags);
 }
 
-static const struct file_operations clk_summary_fops = {
-       .open           = clk_summary_open,
-       .read           = seq_read,
-       .llseek         = seq_lseek,
-       .release        = single_release,
-};
-
-static void clk_dump_one(struct seq_file *s, struct clk_core *c, int level)
+static bool clk_ignore_unused;
+static int __init clk_ignore_unused_setup(char *__unused)
 {
-       if (!c)
-               return;
-
-       seq_printf(s, "\"%s\": { ", c->name);
-       seq_printf(s, "\"enable_count\": %d,", c->enable_count);
-       seq_printf(s, "\"prepare_count\": %d,", c->prepare_count);
-       seq_printf(s, "\"rate\": %lu", clk_core_get_rate(c));
-       seq_printf(s, "\"accuracy\": %lu", clk_core_get_accuracy(c));
-       seq_printf(s, "\"phase\": %d", clk_core_get_phase(c));
+       clk_ignore_unused = true;
+       return 1;
 }
+__setup("clk_ignore_unused", clk_ignore_unused_setup);
 
-static void clk_dump_subtree(struct seq_file *s, struct clk_core *c, int level)
+static int clk_disable_unused(void)
 {
-       struct clk_core *child;
-
-       if (!c)
-               return;
-
-       clk_dump_one(s, c, level);
+       struct clk_core *core;
 
-       hlist_for_each_entry(child, &c->children, child_node) {
-               seq_printf(s, ",");
-               clk_dump_subtree(s, child, level + 1);
+       if (clk_ignore_unused) {
+               pr_warn("clk: Not disabling unused clocks\n");
+               return 0;
        }
 
-       seq_printf(s, "}");
-}
+       clk_prepare_lock();
 
-static int clk_dump(struct seq_file *s, void *data)
-{
-       struct clk_core *c;
-       bool first_node = true;
-       struct hlist_head **lists = (struct hlist_head **)s->private;
+       hlist_for_each_entry(core, &clk_root_list, child_node)
+               clk_disable_unused_subtree(core);
 
-       seq_printf(s, "{");
+       hlist_for_each_entry(core, &clk_orphan_list, child_node)
+               clk_disable_unused_subtree(core);
 
-       clk_prepare_lock();
+       hlist_for_each_entry(core, &clk_root_list, child_node)
+               clk_unprepare_unused_subtree(core);
 
-       for (; *lists; lists++) {
-               hlist_for_each_entry(c, *lists, child_node) {
-                       if (!first_node)
-                               seq_puts(s, ",");
-                       first_node = false;
-                       clk_dump_subtree(s, c, 0);
-               }
-       }
+       hlist_for_each_entry(core, &clk_orphan_list, child_node)
+               clk_unprepare_unused_subtree(core);
 
        clk_prepare_unlock();
 
-       seq_printf(s, "}");
        return 0;
 }
+late_initcall_sync(clk_disable_unused);
 
+/***    helper functions   ***/
 
-static int clk_dump_open(struct inode *inode, struct file *file)
+const char *__clk_get_name(struct clk *clk)
 {
-       return single_open(file, clk_dump, inode->i_private);
+       return !clk ? NULL : clk->core->name;
 }
+EXPORT_SYMBOL_GPL(__clk_get_name);
 
-static const struct file_operations clk_dump_fops = {
-       .open           = clk_dump_open,
-       .read           = seq_read,
-       .llseek         = seq_lseek,
-       .release        = single_release,
-};
-
-static int clk_debug_create_one(struct clk_core *clk, struct dentry *pdentry)
+struct clk_hw *__clk_get_hw(struct clk *clk)
 {
-       struct dentry *d;
-       int ret = -ENOMEM;
-
-       if (!clk || !pdentry) {
-               ret = -EINVAL;
-               goto out;
-       }
+       return !clk ? NULL : clk->core->hw;
+}
+EXPORT_SYMBOL_GPL(__clk_get_hw);
 
-       d = debugfs_create_dir(clk->name, pdentry);
-       if (!d)
-               goto out;
+u8 __clk_get_num_parents(struct clk *clk)
+{
+       return !clk ? 0 : clk->core->num_parents;
+}
+EXPORT_SYMBOL_GPL(__clk_get_num_parents);
 
-       clk->dentry = d;
+struct clk *__clk_get_parent(struct clk *clk)
+{
+       if (!clk)
+               return NULL;
 
-       d = debugfs_create_u32("clk_rate", S_IRUGO, clk->dentry,
-                       (u32 *)&clk->rate);
-       if (!d)
-               goto err_out;
+       /* TODO: Create a per-user clk and change callers to call clk_put */
+       return !clk->core->parent ? NULL : clk->core->parent->hw->clk;
+}
+EXPORT_SYMBOL_GPL(__clk_get_parent);
 
-       d = debugfs_create_u32("clk_accuracy", S_IRUGO, clk->dentry,
-                       (u32 *)&clk->accuracy);
-       if (!d)
-               goto err_out;
+static struct clk_core *__clk_lookup_subtree(const char *name,
+                                            struct clk_core *core)
+{
+       struct clk_core *child;
+       struct clk_core *ret;
 
-       d = debugfs_create_u32("clk_phase", S_IRUGO, clk->dentry,
-                       (u32 *)&clk->phase);
-       if (!d)
-               goto err_out;
+       if (!strcmp(core->name, name))
+               return core;
 
-       d = debugfs_create_x32("clk_flags", S_IRUGO, clk->dentry,
-                       (u32 *)&clk->flags);
-       if (!d)
-               goto err_out;
+       hlist_for_each_entry(child, &core->children, child_node) {
+               ret = __clk_lookup_subtree(name, child);
+               if (ret)
+                       return ret;
+       }
 
-       d = debugfs_create_u32("clk_prepare_count", S_IRUGO, clk->dentry,
-                       (u32 *)&clk->prepare_count);
-       if (!d)
-               goto err_out;
+       return NULL;
+}
 
-       d = debugfs_create_u32("clk_enable_count", S_IRUGO, clk->dentry,
-                       (u32 *)&clk->enable_count);
-       if (!d)
-               goto err_out;
+static struct clk_core *clk_core_lookup(const char *name)
+{
+       struct clk_core *root_clk;
+       struct clk_core *ret;
 
-       d = debugfs_create_u32("clk_notifier_count", S_IRUGO, clk->dentry,
-                       (u32 *)&clk->notifier_count);
-       if (!d)
-               goto err_out;
+       if (!name)
+               return NULL;
 
-       if (clk->ops->debug_init) {
-               ret = clk->ops->debug_init(clk->hw, clk->dentry);
+       /* search the 'proper' clk tree first */
+       hlist_for_each_entry(root_clk, &clk_root_list, child_node) {
+               ret = __clk_lookup_subtree(name, root_clk);
                if (ret)
-                       goto err_out;
+                       return ret;
        }
 
-       ret = 0;
-       goto out;
+       /* if not found, then search the orphan tree */
+       hlist_for_each_entry(root_clk, &clk_orphan_list, child_node) {
+               ret = __clk_lookup_subtree(name, root_clk);
+               if (ret)
+                       return ret;
+       }
 
-err_out:
-       debugfs_remove_recursive(clk->dentry);
-       clk->dentry = NULL;
-out:
-       return ret;
+       return NULL;
 }
 
-/**
- * clk_debug_register - add a clk node to the debugfs clk tree
- * @clk: the clk being added to the debugfs clk tree
- *
- * Dynamically adds a clk to the debugfs clk tree if debugfs has been
- * initialized.  Otherwise it bails out early since the debugfs clk tree
- * will be created lazily by clk_debug_init as part of a late_initcall.
- */
-static int clk_debug_register(struct clk_core *clk)
+static struct clk_core *clk_core_get_parent_by_index(struct clk_core *core,
+                                                        u8 index)
 {
-       int ret = 0;
+       if (!core || index >= core->num_parents)
+               return NULL;
+       else if (!core->parents)
+               return clk_core_lookup(core->parent_names[index]);
+       else if (!core->parents[index])
+               return core->parents[index] =
+                       clk_core_lookup(core->parent_names[index]);
+       else
+               return core->parents[index];
+}
 
-       mutex_lock(&clk_debug_lock);
-       hlist_add_head(&clk->debug_node, &clk_debug_list);
+struct clk *clk_get_parent_by_index(struct clk *clk, u8 index)
+{
+       struct clk_core *parent;
 
-       if (!inited)
-               goto unlock;
+       if (!clk)
+               return NULL;
 
-       ret = clk_debug_create_one(clk, rootdir);
-unlock:
-       mutex_unlock(&clk_debug_lock);
+       parent = clk_core_get_parent_by_index(clk->core, index);
 
-       return ret;
+       return !parent ? NULL : parent->hw->clk;
 }
+EXPORT_SYMBOL_GPL(clk_get_parent_by_index);
 
- /**
- * clk_debug_unregister - remove a clk node from the debugfs clk tree
- * @clk: the clk being removed from the debugfs clk tree
- *
- * Dynamically removes a clk and all it's children clk nodes from the
- * debugfs clk tree if clk->dentry points to debugfs created by
- * clk_debug_register in __clk_init.
- */
-static void clk_debug_unregister(struct clk_core *clk)
+unsigned int __clk_get_enable_count(struct clk *clk)
 {
-       mutex_lock(&clk_debug_lock);
-       hlist_del_init(&clk->debug_node);
-       debugfs_remove_recursive(clk->dentry);
-       clk->dentry = NULL;
-       mutex_unlock(&clk_debug_lock);
+       return !clk ? 0 : clk->core->enable_count;
 }
 
-struct dentry *clk_debugfs_add_file(struct clk_hw *hw, char *name, umode_t mode,
-                               void *data, const struct file_operations *fops)
-{
-       struct dentry *d = NULL;
-
-       if (hw->core->dentry)
-               d = debugfs_create_file(name, mode, hw->core->dentry, data,
-                                       fops);
-
-       return d;
-}
-EXPORT_SYMBOL_GPL(clk_debugfs_add_file);
-
-/**
- * clk_debug_init - lazily create the debugfs clk tree visualization
- *
- * clks are often initialized very early during boot before memory can
- * be dynamically allocated and well before debugfs is setup.
- * clk_debug_init walks the clk tree hierarchy while holding
- * prepare_lock and creates the topology as part of a late_initcall,
- * thus insuring that clks initialized very early will still be
- * represented in the debugfs clk tree.  This function should only be
- * called once at boot-time, and all other clks added dynamically will
- * be done so with clk_debug_register.
- */
-static int __init clk_debug_init(void)
-{
-       struct clk_core *clk;
-       struct dentry *d;
-
-       rootdir = debugfs_create_dir("clk", NULL);
-
-       if (!rootdir)
-               return -ENOMEM;
-
-       d = debugfs_create_file("clk_summary", S_IRUGO, rootdir, &all_lists,
-                               &clk_summary_fops);
-       if (!d)
-               return -ENOMEM;
-
-       d = debugfs_create_file("clk_dump", S_IRUGO, rootdir, &all_lists,
-                               &clk_dump_fops);
-       if (!d)
-               return -ENOMEM;
-
-       d = debugfs_create_file("clk_orphan_summary", S_IRUGO, rootdir,
-                               &orphan_list, &clk_summary_fops);
-       if (!d)
-               return -ENOMEM;
-
-       d = debugfs_create_file("clk_orphan_dump", S_IRUGO, rootdir,
-                               &orphan_list, &clk_dump_fops);
-       if (!d)
-               return -ENOMEM;
-
-       mutex_lock(&clk_debug_lock);
-       hlist_for_each_entry(clk, &clk_debug_list, debug_node)
-               clk_debug_create_one(clk, rootdir);
-
-       inited = 1;
-       mutex_unlock(&clk_debug_lock);
-
-       return 0;
-}
-late_initcall(clk_debug_init);
-#else
-static inline int clk_debug_register(struct clk_core *clk) { return 0; }
-static inline void clk_debug_reparent(struct clk_core *clk,
-                                     struct clk_core *new_parent)
-{
-}
-static inline void clk_debug_unregister(struct clk_core *clk)
-{
-}
-#endif
-
-/* caller must hold prepare_lock */
-static void clk_unprepare_unused_subtree(struct clk_core *clk)
-{
-       struct clk_core *child;
-
-       lockdep_assert_held(&prepare_lock);
-
-       hlist_for_each_entry(child, &clk->children, child_node)
-               clk_unprepare_unused_subtree(child);
-
-       if (clk->prepare_count)
-               return;
-
-       if (clk->flags & CLK_IGNORE_UNUSED)
-               return;
-
-       if (clk_core_is_prepared(clk)) {
-               trace_clk_unprepare(clk);
-               if (clk->ops->unprepare_unused)
-                       clk->ops->unprepare_unused(clk->hw);
-               else if (clk->ops->unprepare)
-                       clk->ops->unprepare(clk->hw);
-               trace_clk_unprepare_complete(clk);
-       }
-}
-
-/* caller must hold prepare_lock */
-static void clk_disable_unused_subtree(struct clk_core *clk)
-{
-       struct clk_core *child;
-       unsigned long flags;
-
-       lockdep_assert_held(&prepare_lock);
-
-       hlist_for_each_entry(child, &clk->children, child_node)
-               clk_disable_unused_subtree(child);
-
-       flags = clk_enable_lock();
-
-       if (clk->enable_count)
-               goto unlock_out;
-
-       if (clk->flags & CLK_IGNORE_UNUSED)
-               goto unlock_out;
-
-       /*
-        * some gate clocks have special needs during the disable-unused
-        * sequence.  call .disable_unused if available, otherwise fall
-        * back to .disable
-        */
-       if (clk_core_is_enabled(clk)) {
-               trace_clk_disable(clk);
-               if (clk->ops->disable_unused)
-                       clk->ops->disable_unused(clk->hw);
-               else if (clk->ops->disable)
-                       clk->ops->disable(clk->hw);
-               trace_clk_disable_complete(clk);
-       }
-
-unlock_out:
-       clk_enable_unlock(flags);
-}
-
-static bool clk_ignore_unused;
-static int __init clk_ignore_unused_setup(char *__unused)
-{
-       clk_ignore_unused = true;
-       return 1;
-}
-__setup("clk_ignore_unused", clk_ignore_unused_setup);
-
-static int clk_disable_unused(void)
-{
-       struct clk_core *clk;
-
-       if (clk_ignore_unused) {
-               pr_warn("clk: Not disabling unused clocks\n");
-               return 0;
-       }
-
-       clk_prepare_lock();
-
-       hlist_for_each_entry(clk, &clk_root_list, child_node)
-               clk_disable_unused_subtree(clk);
-
-       hlist_for_each_entry(clk, &clk_orphan_list, child_node)
-               clk_disable_unused_subtree(clk);
-
-       hlist_for_each_entry(clk, &clk_root_list, child_node)
-               clk_unprepare_unused_subtree(clk);
-
-       hlist_for_each_entry(clk, &clk_orphan_list, child_node)
-               clk_unprepare_unused_subtree(clk);
-
-       clk_prepare_unlock();
-
-       return 0;
-}
-late_initcall_sync(clk_disable_unused);
-
-/***    helper functions   ***/
-
-const char *__clk_get_name(struct clk *clk)
-{
-       return !clk ? NULL : clk->core->name;
-}
-EXPORT_SYMBOL_GPL(__clk_get_name);
-
-struct clk_hw *__clk_get_hw(struct clk *clk)
-{
-       return !clk ? NULL : clk->core->hw;
-}
-EXPORT_SYMBOL_GPL(__clk_get_hw);
-
-u8 __clk_get_num_parents(struct clk *clk)
-{
-       return !clk ? 0 : clk->core->num_parents;
-}
-EXPORT_SYMBOL_GPL(__clk_get_num_parents);
-
-struct clk *__clk_get_parent(struct clk *clk)
-{
-       if (!clk)
-               return NULL;
-
-       /* TODO: Create a per-user clk and change callers to call clk_put */
-       return !clk->core->parent ? NULL : clk->core->parent->hw->clk;
-}
-EXPORT_SYMBOL_GPL(__clk_get_parent);
-
-static struct clk_core *clk_core_get_parent_by_index(struct clk_core *clk,
-                                                        u8 index)
-{
-       if (!clk || index >= clk->num_parents)
-               return NULL;
-       else if (!clk->parents)
-               return clk_core_lookup(clk->parent_names[index]);
-       else if (!clk->parents[index])
-               return clk->parents[index] =
-                       clk_core_lookup(clk->parent_names[index]);
-       else
-               return clk->parents[index];
-}
-
-struct clk *clk_get_parent_by_index(struct clk *clk, u8 index)
-{
-       struct clk_core *parent;
-
-       if (!clk)
-               return NULL;
-
-       parent = clk_core_get_parent_by_index(clk->core, index);
-
-       return !parent ? NULL : parent->hw->clk;
-}
-EXPORT_SYMBOL_GPL(clk_get_parent_by_index);
-
-unsigned int __clk_get_enable_count(struct clk *clk)
-{
-       return !clk ? 0 : clk->core->enable_count;
-}
-
-static unsigned long clk_core_get_rate_nolock(struct clk_core *clk)
+static unsigned long clk_core_get_rate_nolock(struct clk_core *core)
 {
        unsigned long ret;
 
-       if (!clk) {
+       if (!core) {
                ret = 0;
                goto out;
        }
 
-       ret = clk->rate;
+       ret = core->rate;
 
-       if (clk->flags & CLK_IS_ROOT)
+       if (core->flags & CLK_IS_ROOT)
                goto out;
 
-       if (!clk->parent)
+       if (!core->parent)
                ret = 0;
 
 out:
@@ -670,12 +396,12 @@ unsigned long __clk_get_rate(struct clk *clk)
 }
 EXPORT_SYMBOL_GPL(__clk_get_rate);
 
-static unsigned long __clk_get_accuracy(struct clk_core *clk)
+static unsigned long __clk_get_accuracy(struct clk_core *core)
 {
-       if (!clk)
+       if (!core)
                return 0;
 
-       return clk->accuracy;
+       return core->accuracy;
 }
 
 unsigned long __clk_get_flags(struct clk *clk)
@@ -684,27 +410,6 @@ unsigned long __clk_get_flags(struct clk *clk)
 }
 EXPORT_SYMBOL_GPL(__clk_get_flags);
 
-static bool clk_core_is_prepared(struct clk_core *clk)
-{
-       int ret;
-
-       if (!clk)
-               return false;
-
-       /*
-        * .is_prepared is optional for clocks that can prepare
-        * fall back to software usage counter if it is missing
-        */
-       if (!clk->ops->is_prepared) {
-               ret = clk->prepare_count ? 1 : 0;
-               goto out;
-       }
-
-       ret = clk->ops->is_prepared(clk->hw);
-out:
-       return !!ret;
-}
-
 bool __clk_is_prepared(struct clk *clk)
 {
        if (!clk)
@@ -713,27 +418,6 @@ bool __clk_is_prepared(struct clk *clk)
        return clk_core_is_prepared(clk->core);
 }
 
-static bool clk_core_is_enabled(struct clk_core *clk)
-{
-       int ret;
-
-       if (!clk)
-               return false;
-
-       /*
-        * .is_enabled is only mandatory for clocks that gate
-        * fall back to software usage counter if .is_enabled is missing
-        */
-       if (!clk->ops->is_enabled) {
-               ret = clk->enable_count ? 1 : 0;
-               goto out;
-       }
-
-       ret = clk->ops->is_enabled(clk->hw);
-out:
-       return !!ret;
-}
-
 bool __clk_is_enabled(struct clk *clk)
 {
        if (!clk)
@@ -743,49 +427,6 @@ bool __clk_is_enabled(struct clk *clk)
 }
 EXPORT_SYMBOL_GPL(__clk_is_enabled);
 
-static struct clk_core *__clk_lookup_subtree(const char *name,
-                                            struct clk_core *clk)
-{
-       struct clk_core *child;
-       struct clk_core *ret;
-
-       if (!strcmp(clk->name, name))
-               return clk;
-
-       hlist_for_each_entry(child, &clk->children, child_node) {
-               ret = __clk_lookup_subtree(name, child);
-               if (ret)
-                       return ret;
-       }
-
-       return NULL;
-}
-
-static struct clk_core *clk_core_lookup(const char *name)
-{
-       struct clk_core *root_clk;
-       struct clk_core *ret;
-
-       if (!name)
-               return NULL;
-
-       /* search the 'proper' clk tree first */
-       hlist_for_each_entry(root_clk, &clk_root_list, child_node) {
-               ret = __clk_lookup_subtree(name, root_clk);
-               if (ret)
-                       return ret;
-       }
-
-       /* if not found, then search the orphan tree */
-       hlist_for_each_entry(root_clk, &clk_orphan_list, child_node) {
-               ret = __clk_lookup_subtree(name, root_clk);
-               if (ret)
-                       return ret;
-       }
-
-       return NULL;
-}
-
 static bool mux_is_better_rate(unsigned long rate, unsigned long now,
                           unsigned long best, unsigned long flags)
 {
@@ -853,7 +494,7 @@ struct clk *__clk_lookup(const char *name)
        return !core ? NULL : core->hw->clk;
 }
 
-static void clk_core_get_boundaries(struct clk_core *clk,
+static void clk_core_get_boundaries(struct clk_core *core,
                                    unsigned long *min_rate,
                                    unsigned long *max_rate)
 {
@@ -862,10 +503,10 @@ static void clk_core_get_boundaries(struct clk_core *clk,
        *min_rate = 0;
        *max_rate = ULONG_MAX;
 
-       hlist_for_each_entry(clk_user, &clk->clks, clks_node)
+       hlist_for_each_entry(clk_user, &core->clks, clks_node)
                *min_rate = max(*min_rate, clk_user->min_rate);
 
-       hlist_for_each_entry(clk_user, &clk->clks, clks_node)
+       hlist_for_each_entry(clk_user, &core->clks, clks_node)
                *max_rate = min(*max_rate, clk_user->max_rate);
 }
 
@@ -901,26 +542,28 @@ EXPORT_SYMBOL_GPL(__clk_mux_determine_rate_closest);
 
 /***        clk api        ***/
 
-static void clk_core_unprepare(struct clk_core *clk)
+static void clk_core_unprepare(struct clk_core *core)
 {
-       if (!clk)
+       lockdep_assert_held(&prepare_lock);
+
+       if (!core)
                return;
 
-       if (WARN_ON(clk->prepare_count == 0))
+       if (WARN_ON(core->prepare_count == 0))
                return;
 
-       if (--clk->prepare_count > 0)
+       if (--core->prepare_count > 0)
                return;
 
-       WARN_ON(clk->enable_count > 0);
+       WARN_ON(core->enable_count > 0);
 
-       trace_clk_unprepare(clk);
+       trace_clk_unprepare(core);
 
-       if (clk->ops->unprepare)
-               clk->ops->unprepare(clk->hw);
+       if (core->ops->unprepare)
+               core->ops->unprepare(core->hw);
 
-       trace_clk_unprepare_complete(clk);
-       clk_core_unprepare(clk->parent);
+       trace_clk_unprepare_complete(core);
+       clk_core_unprepare(core->parent);
 }
 
 /**
@@ -945,32 +588,34 @@ void clk_unprepare(struct clk *clk)
 }
 EXPORT_SYMBOL_GPL(clk_unprepare);
 
-static int clk_core_prepare(struct clk_core *clk)
+static int clk_core_prepare(struct clk_core *core)
 {
        int ret = 0;
 
-       if (!clk)
-               return 0;
+       lockdep_assert_held(&prepare_lock);
+
+       if (!core)
+               return 0;
 
-       if (clk->prepare_count == 0) {
-               ret = clk_core_prepare(clk->parent);
+       if (core->prepare_count == 0) {
+               ret = clk_core_prepare(core->parent);
                if (ret)
                        return ret;
 
-               trace_clk_prepare(clk);
+               trace_clk_prepare(core);
 
-               if (clk->ops->prepare)
-                       ret = clk->ops->prepare(clk->hw);
+               if (core->ops->prepare)
+                       ret = core->ops->prepare(core->hw);
 
-               trace_clk_prepare_complete(clk);
+               trace_clk_prepare_complete(core);
 
                if (ret) {
-                       clk_core_unprepare(clk->parent);
+                       clk_core_unprepare(core->parent);
                        return ret;
                }
        }
 
-       clk->prepare_count++;
+       core->prepare_count++;
 
        return 0;
 }
@@ -1002,33 +647,27 @@ int clk_prepare(struct clk *clk)
 }
 EXPORT_SYMBOL_GPL(clk_prepare);
 
-static void clk_core_disable(struct clk_core *clk)
+static void clk_core_disable(struct clk_core *core)
 {
-       if (!clk)
-               return;
+       lockdep_assert_held(&enable_lock);
 
-       if (WARN_ON(clk->enable_count == 0))
+       if (!core)
                return;
 
-       if (--clk->enable_count > 0)
+       if (WARN_ON(core->enable_count == 0))
                return;
 
-       trace_clk_disable(clk);
-
-       if (clk->ops->disable)
-               clk->ops->disable(clk->hw);
+       if (--core->enable_count > 0)
+               return;
 
-       trace_clk_disable_complete(clk);
+       trace_clk_disable(core);
 
-       clk_core_disable(clk->parent);
-}
+       if (core->ops->disable)
+               core->ops->disable(core->hw);
 
-static void __clk_disable(struct clk *clk)
-{
-       if (!clk)
-               return;
+       trace_clk_disable_complete(core);
 
-       clk_core_disable(clk->core);
+       clk_core_disable(core->parent);
 }
 
 /**
@@ -1051,52 +690,46 @@ void clk_disable(struct clk *clk)
                return;
 
        flags = clk_enable_lock();
-       __clk_disable(clk);
+       clk_core_disable(clk->core);
        clk_enable_unlock(flags);
 }
 EXPORT_SYMBOL_GPL(clk_disable);
 
-static int clk_core_enable(struct clk_core *clk)
+static int clk_core_enable(struct clk_core *core)
 {
        int ret = 0;
 
-       if (!clk)
+       lockdep_assert_held(&enable_lock);
+
+       if (!core)
                return 0;
 
-       if (WARN_ON(clk->prepare_count == 0))
+       if (WARN_ON(core->prepare_count == 0))
                return -ESHUTDOWN;
 
-       if (clk->enable_count == 0) {
-               ret = clk_core_enable(clk->parent);
+       if (core->enable_count == 0) {
+               ret = clk_core_enable(core->parent);
 
                if (ret)
                        return ret;
 
-               trace_clk_enable(clk);
+               trace_clk_enable(core);
 
-               if (clk->ops->enable)
-                       ret = clk->ops->enable(clk->hw);
+               if (core->ops->enable)
+                       ret = core->ops->enable(core->hw);
 
-               trace_clk_enable_complete(clk);
+               trace_clk_enable_complete(core);
 
                if (ret) {
-                       clk_core_disable(clk->parent);
+                       clk_core_disable(core->parent);
                        return ret;
                }
        }
 
-       clk->enable_count++;
+       core->enable_count++;
        return 0;
 }
 
-static int __clk_enable(struct clk *clk)
-{
-       if (!clk)
-               return 0;
-
-       return clk_core_enable(clk->core);
-}
-
 /**
  * clk_enable - ungate a clock
  * @clk: the clk being ungated
@@ -1115,15 +748,18 @@ int clk_enable(struct clk *clk)
        unsigned long flags;
        int ret;
 
+       if (!clk)
+               return 0;
+
        flags = clk_enable_lock();
-       ret = __clk_enable(clk);
+       ret = clk_core_enable(clk->core);
        clk_enable_unlock(flags);
 
        return ret;
 }
 EXPORT_SYMBOL_GPL(clk_enable);
 
-static unsigned long clk_core_round_rate_nolock(struct clk_core *clk,
+static unsigned long clk_core_round_rate_nolock(struct clk_core *core,
                                                unsigned long rate,
                                                unsigned long min_rate,
                                                unsigned long max_rate)
@@ -1134,25 +770,25 @@ static unsigned long clk_core_round_rate_nolock(struct clk_core *clk,
 
        lockdep_assert_held(&prepare_lock);
 
-       if (!clk)
+       if (!core)
                return 0;
 
-       parent = clk->parent;
+       parent = core->parent;
        if (parent)
                parent_rate = parent->rate;
 
-       if (clk->ops->determine_rate) {
+       if (core->ops->determine_rate) {
                parent_hw = parent ? parent->hw : NULL;
-               return clk->ops->determine_rate(clk->hw, rate,
+               return core->ops->determine_rate(core->hw, rate,
                                                min_rate, max_rate,
                                                &parent_rate, &parent_hw);
-       } else if (clk->ops->round_rate)
-               return clk->ops->round_rate(clk->hw, rate, &parent_rate);
-       else if (clk->flags & CLK_SET_RATE_PARENT)
-               return clk_core_round_rate_nolock(clk->parent, rate, min_rate,
+       } else if (core->ops->round_rate)
+               return core->ops->round_rate(core->hw, rate, &parent_rate);
+       else if (core->flags & CLK_SET_RATE_PARENT)
+               return clk_core_round_rate_nolock(core->parent, rate, min_rate,
                                                  max_rate);
        else
-               return clk->rate;
+               return core->rate;
 }
 
 /**
@@ -1162,8 +798,7 @@ static unsigned long clk_core_round_rate_nolock(struct clk_core *clk,
  * @min_rate: returned rate must be greater than this rate
  * @max_rate: returned rate must be less than this rate
  *
- * Caller must hold prepare_lock.  Useful for clk_ops such as .set_rate and
- * .determine_rate.
+ * Useful for clk_ops such as .set_rate and .determine_rate.
  */
 unsigned long __clk_determine_rate(struct clk_hw *hw,
                                   unsigned long rate,
@@ -1182,7 +817,7 @@ EXPORT_SYMBOL_GPL(__clk_determine_rate);
  * @clk: round the rate of this clock
  * @rate: the rate which is to be rounded
  *
- * Caller must hold prepare_lock.  Useful for clk_ops such as .set_rate
+ * Useful for clk_ops such as .set_rate
  */
 unsigned long __clk_round_rate(struct clk *clk, unsigned long rate)
 {
@@ -1224,7 +859,7 @@ EXPORT_SYMBOL_GPL(clk_round_rate);
 
 /**
  * __clk_notify - call clk notifier chain
- * @clk: struct clk * that is changing rate
+ * @core: clk that is changing rate
  * @msg: clk notifier type (see include/linux/clk.h)
  * @old_rate: old clk rate
  * @new_rate: new clk rate
@@ -1236,7 +871,7 @@ EXPORT_SYMBOL_GPL(clk_round_rate);
  * called if all went well, or NOTIFY_STOP or NOTIFY_BAD immediately if
  * a driver returns that.
  */
-static int __clk_notify(struct clk_core *clk, unsigned long msg,
+static int __clk_notify(struct clk_core *core, unsigned long msg,
                unsigned long old_rate, unsigned long new_rate)
 {
        struct clk_notifier *cn;
@@ -1247,7 +882,7 @@ static int __clk_notify(struct clk_core *clk, unsigned long msg,
        cnd.new_rate = new_rate;
 
        list_for_each_entry(cn, &clk_notifier_list, node) {
-               if (cn->clk->core == clk) {
+               if (cn->clk->core == core) {
                        cnd.clk = cn->clk;
                        ret = srcu_notifier_call_chain(&cn->notifier_head, msg,
                                        &cnd);
@@ -1259,44 +894,42 @@ static int __clk_notify(struct clk_core *clk, unsigned long msg,
 
 /**
  * __clk_recalc_accuracies
- * @clk: first clk in the subtree
+ * @core: first clk in the subtree
  *
  * Walks the subtree of clks starting with clk and recalculates accuracies as
  * it goes.  Note that if a clk does not implement the .recalc_accuracy
- * callback then it is assumed that the clock will take on the accuracy of it's
+ * callback then it is assumed that the clock will take on the accuracy of its
  * parent.
- *
- * Caller must hold prepare_lock.
  */
-static void __clk_recalc_accuracies(struct clk_core *clk)
+static void __clk_recalc_accuracies(struct clk_core *core)
 {
        unsigned long parent_accuracy = 0;
        struct clk_core *child;
 
        lockdep_assert_held(&prepare_lock);
 
-       if (clk->parent)
-               parent_accuracy = clk->parent->accuracy;
+       if (core->parent)
+               parent_accuracy = core->parent->accuracy;
 
-       if (clk->ops->recalc_accuracy)
-               clk->accuracy = clk->ops->recalc_accuracy(clk->hw,
+       if (core->ops->recalc_accuracy)
+               core->accuracy = core->ops->recalc_accuracy(core->hw,
                                                          parent_accuracy);
        else
-               clk->accuracy = parent_accuracy;
+               core->accuracy = parent_accuracy;
 
-       hlist_for_each_entry(child, &clk->children, child_node)
+       hlist_for_each_entry(child, &core->children, child_node)
                __clk_recalc_accuracies(child);
 }
 
-static long clk_core_get_accuracy(struct clk_core *clk)
+static long clk_core_get_accuracy(struct clk_core *core)
 {
        unsigned long accuracy;
 
        clk_prepare_lock();
-       if (clk && (clk->flags & CLK_GET_ACCURACY_NOCACHE))
-               __clk_recalc_accuracies(clk);
+       if (core && (core->flags & CLK_GET_ACCURACY_NOCACHE))
+               __clk_recalc_accuracies(core);
 
-       accuracy = __clk_get_accuracy(clk);
+       accuracy = __clk_get_accuracy(core);
        clk_prepare_unlock();
 
        return accuracy;
@@ -1320,17 +953,17 @@ long clk_get_accuracy(struct clk *clk)
 }
 EXPORT_SYMBOL_GPL(clk_get_accuracy);
 
-static unsigned long clk_recalc(struct clk_core *clk,
+static unsigned long clk_recalc(struct clk_core *core,
                                unsigned long parent_rate)
 {
-       if (clk->ops->recalc_rate)
-               return clk->ops->recalc_rate(clk->hw, parent_rate);
+       if (core->ops->recalc_rate)
+               return core->ops->recalc_rate(core->hw, parent_rate);
        return parent_rate;
 }
 
 /**
  * __clk_recalc_rates
- * @clk: first clk in the subtree
+ * @core: first clk in the subtree
  * @msg: notification type (see include/linux/clk.h)
  *
  * Walks the subtree of clks starting with clk and recalculates rates as it
@@ -1339,10 +972,8 @@ static unsigned long clk_recalc(struct clk_core *clk,
  *
  * clk_recalc_rates also propagates the POST_RATE_CHANGE notification,
  * if necessary.
- *
- * Caller must hold prepare_lock.
  */
-static void __clk_recalc_rates(struct clk_core *clk, unsigned long msg)
+static void __clk_recalc_rates(struct clk_core *core, unsigned long msg)
 {
        unsigned long old_rate;
        unsigned long parent_rate = 0;
@@ -1350,34 +981,34 @@ static void __clk_recalc_rates(struct clk_core *clk, unsigned long msg)
 
        lockdep_assert_held(&prepare_lock);
 
-       old_rate = clk->rate;
+       old_rate = core->rate;
 
-       if (clk->parent)
-               parent_rate = clk->parent->rate;
+       if (core->parent)
+               parent_rate = core->parent->rate;
 
-       clk->rate = clk_recalc(clk, parent_rate);
+       core->rate = clk_recalc(core, parent_rate);
 
        /*
         * ignore NOTIFY_STOP and NOTIFY_BAD return values for POST_RATE_CHANGE
         * & ABORT_RATE_CHANGE notifiers
         */
-       if (clk->notifier_count && msg)
-               __clk_notify(clk, msg, old_rate, clk->rate);
+       if (core->notifier_count && msg)
+               __clk_notify(core, msg, old_rate, core->rate);
 
-       hlist_for_each_entry(child, &clk->children, child_node)
+       hlist_for_each_entry(child, &core->children, child_node)
                __clk_recalc_rates(child, msg);
 }
 
-static unsigned long clk_core_get_rate(struct clk_core *clk)
+static unsigned long clk_core_get_rate(struct clk_core *core)
 {
        unsigned long rate;
 
        clk_prepare_lock();
 
-       if (clk && (clk->flags & CLK_GET_RATE_NOCACHE))
-               __clk_recalc_rates(clk, 0);
+       if (core && (core->flags & CLK_GET_RATE_NOCACHE))
+               __clk_recalc_rates(core, 0);
 
-       rate = clk_core_get_rate_nolock(clk);
+       rate = clk_core_get_rate_nolock(core);
        clk_prepare_unlock();
 
        return rate;
@@ -1400,15 +1031,15 @@ unsigned long clk_get_rate(struct clk *clk)
 }
 EXPORT_SYMBOL_GPL(clk_get_rate);
 
-static int clk_fetch_parent_index(struct clk_core *clk,
+static int clk_fetch_parent_index(struct clk_core *core,
                                  struct clk_core *parent)
 {
        int i;
 
-       if (!clk->parents) {
-               clk->parents = kcalloc(clk->num_parents,
+       if (!core->parents) {
+               core->parents = kcalloc(core->num_parents,
                                        sizeof(struct clk *), GFP_KERNEL);
-               if (!clk->parents)
+               if (!core->parents)
                        return -ENOMEM;
        }
 
@@ -1417,15 +1048,15 @@ static int clk_fetch_parent_index(struct clk_core *clk,
         * or if not yet cached, use string name comparison and cache
         * them now to avoid future calls to clk_core_lookup.
         */
-       for (i = 0; i < clk->num_parents; i++) {
-               if (clk->parents[i] == parent)
+       for (i = 0; i < core->num_parents; i++) {
+               if (core->parents[i] == parent)
                        return i;
 
-               if (clk->parents[i])
+               if (core->parents[i])
                        continue;
 
-               if (!strcmp(clk->parent_names[i], parent->name)) {
-                       clk->parents[i] = clk_core_lookup(parent->name);
+               if (!strcmp(core->parent_names[i], parent->name)) {
+                       core->parents[i] = clk_core_lookup(parent->name);
                        return i;
                }
        }
@@ -1433,28 +1064,28 @@ static int clk_fetch_parent_index(struct clk_core *clk,
        return -EINVAL;
 }
 
-static void clk_reparent(struct clk_core *clk, struct clk_core *new_parent)
+static void clk_reparent(struct clk_core *core, struct clk_core *new_parent)
 {
-       hlist_del(&clk->child_node);
+       hlist_del(&core->child_node);
 
        if (new_parent) {
                /* avoid duplicate POST_RATE_CHANGE notifications */
-               if (new_parent->new_child == clk)
+               if (new_parent->new_child == core)
                        new_parent->new_child = NULL;
 
-               hlist_add_head(&clk->child_node, &new_parent->children);
+               hlist_add_head(&core->child_node, &new_parent->children);
        } else {
-               hlist_add_head(&clk->child_node, &clk_orphan_list);
+               hlist_add_head(&core->child_node, &clk_orphan_list);
        }
 
-       clk->parent = new_parent;
+       core->parent = new_parent;
 }
 
-static struct clk_core *__clk_set_parent_before(struct clk_core *clk,
+static struct clk_core *__clk_set_parent_before(struct clk_core *core,
                                           struct clk_core *parent)
 {
        unsigned long flags;
-       struct clk_core *old_parent = clk->parent;
+       struct clk_core *old_parent = core->parent;
 
        /*
         * Migrate prepare state between parents and prevent race with
@@ -1473,17 +1104,17 @@ static struct clk_core *__clk_set_parent_before(struct clk_core *clk,
         *
         * See also: Comment for clk_set_parent() below.
         */
-       if (clk->prepare_count) {
+       if (core->prepare_count) {
                clk_core_prepare(parent);
                flags = clk_enable_lock();
                clk_core_enable(parent);
-               clk_core_enable(clk);
+               clk_core_enable(core);
                clk_enable_unlock(flags);
        }
 
        /* update the clk tree topology */
        flags = clk_enable_lock();
-       clk_reparent(clk, parent);
+       clk_reparent(core, parent);
        clk_enable_unlock(flags);
 
        return old_parent;
@@ -1508,31 +1139,31 @@ static void __clk_set_parent_after(struct clk_core *core,
        }
 }
 
-static int __clk_set_parent(struct clk_core *clk, struct clk_core *parent,
+static int __clk_set_parent(struct clk_core *core, struct clk_core *parent,
                            u8 p_index)
 {
        unsigned long flags;
        int ret = 0;
        struct clk_core *old_parent;
 
-       old_parent = __clk_set_parent_before(clk, parent);
+       old_parent = __clk_set_parent_before(core, parent);
 
-       trace_clk_set_parent(clk, parent);
+       trace_clk_set_parent(core, parent);
 
        /* change clock input source */
-       if (parent && clk->ops->set_parent)
-               ret = clk->ops->set_parent(clk->hw, p_index);
+       if (parent && core->ops->set_parent)
+               ret = core->ops->set_parent(core->hw, p_index);
 
-       trace_clk_set_parent_complete(clk, parent);
+       trace_clk_set_parent_complete(core, parent);
 
        if (ret) {
                flags = clk_enable_lock();
-               clk_reparent(clk, old_parent);
+               clk_reparent(core, old_parent);
                clk_enable_unlock(flags);
 
-               if (clk->prepare_count) {
+               if (core->prepare_count) {
                        flags = clk_enable_lock();
-                       clk_core_disable(clk);
+                       clk_core_disable(core);
                        clk_core_disable(parent);
                        clk_enable_unlock(flags);
                        clk_core_unprepare(parent);
@@ -1540,14 +1171,14 @@ static int __clk_set_parent(struct clk_core *clk, struct clk_core *parent,
                return ret;
        }
 
-       __clk_set_parent_after(clk, parent, old_parent);
+       __clk_set_parent_after(core, parent, old_parent);
 
        return 0;
 }
 
 /**
  * __clk_speculate_rates
- * @clk: first clk in the subtree
+ * @core: first clk in the subtree
  * @parent_rate: the "future" rate of clk's parent
  *
  * Walks the subtree of clks starting with clk, speculating rates as it
@@ -1558,10 +1189,8 @@ static int __clk_set_parent(struct clk_core *clk, struct clk_core *parent,
  * subtree have subscribed to the notifications.  Note that if a clk does not
  * implement the .recalc_rate callback then it is assumed that the clock will
  * take on the rate of its parent.
- *
- * Caller must hold prepare_lock.
  */
-static int __clk_speculate_rates(struct clk_core *clk,
+static int __clk_speculate_rates(struct clk_core *core,
                                 unsigned long parent_rate)
 {
        struct clk_core *child;
@@ -1570,19 +1199,19 @@ static int __clk_speculate_rates(struct clk_core *clk,
 
        lockdep_assert_held(&prepare_lock);
 
-       new_rate = clk_recalc(clk, parent_rate);
+       new_rate = clk_recalc(core, parent_rate);
 
        /* abort rate change if a driver returns NOTIFY_BAD or NOTIFY_STOP */
-       if (clk->notifier_count)
-               ret = __clk_notify(clk, PRE_RATE_CHANGE, clk->rate, new_rate);
+       if (core->notifier_count)
+               ret = __clk_notify(core, PRE_RATE_CHANGE, core->rate, new_rate);
 
        if (ret & NOTIFY_STOP_MASK) {
                pr_debug("%s: clk notifier callback for clock %s aborted with error %d\n",
-                               __func__, clk->name, ret);
+                               __func__, core->name, ret);
                goto out;
        }
 
-       hlist_for_each_entry(child, &clk->children, child_node) {
+       hlist_for_each_entry(child, &core->children, child_node) {
                ret = __clk_speculate_rates(child, new_rate);
                if (ret & NOTIFY_STOP_MASK)
                        break;
@@ -1592,20 +1221,20 @@ out:
        return ret;
 }
 
-static void clk_calc_subtree(struct clk_core *clk, unsigned long new_rate,
+static void clk_calc_subtree(struct clk_core *core, unsigned long new_rate,
                             struct clk_core *new_parent, u8 p_index)
 {
        struct clk_core *child;
 
-       clk->new_rate = new_rate;
-       clk->new_parent = new_parent;
-       clk->new_parent_index = p_index;
+       core->new_rate = new_rate;
+       core->new_parent = new_parent;
+       core->new_parent_index = p_index;
        /* include clk in new parent's PRE_RATE_CHANGE notifications */
-       clk->new_child = NULL;
-       if (new_parent && new_parent != clk->parent)
-               new_parent->new_child = clk;
+       core->new_child = NULL;
+       if (new_parent && new_parent != core->parent)
+               new_parent->new_child = core;
 
-       hlist_for_each_entry(child, &clk->children, child_node) {
+       hlist_for_each_entry(child, &core->children, child_node) {
                child->new_rate = clk_recalc(child, new_rate);
                clk_calc_subtree(child, child->new_rate, NULL, 0);
        }
@@ -1615,10 +1244,10 @@ static void clk_calc_subtree(struct clk_core *clk, unsigned long new_rate,
  * calculate the new rates returning the topmost clock that has to be
  * changed.
  */
-static struct clk_core *clk_calc_new_rates(struct clk_core *clk,
+static struct clk_core *clk_calc_new_rates(struct clk_core *core,
                                           unsigned long rate)
 {
-       struct clk_core *top = clk;
+       struct clk_core *top = core;
        struct clk_core *old_parent, *parent;
        struct clk_hw *parent_hw;
        unsigned long best_parent_rate = 0;
@@ -1629,20 +1258,20 @@ static struct clk_core *clk_calc_new_rates(struct clk_core *clk,
        long ret;
 
        /* sanity */
-       if (IS_ERR_OR_NULL(clk))
+       if (IS_ERR_OR_NULL(core))
                return NULL;
 
        /* save parent rate, if it exists */
-       parent = old_parent = clk->parent;
+       parent = old_parent = core->parent;
        if (parent)
                best_parent_rate = parent->rate;
 
-       clk_core_get_boundaries(clk, &min_rate, &max_rate);
+       clk_core_get_boundaries(core, &min_rate, &max_rate);
 
        /* find the closest rate and parent clk/rate */
-       if (clk->ops->determine_rate) {
+       if (core->ops->determine_rate) {
                parent_hw = parent ? parent->hw : NULL;
-               ret = clk->ops->determine_rate(clk->hw, rate,
+               ret = core->ops->determine_rate(core->hw, rate,
                                               min_rate,
                                               max_rate,
                                               &best_parent_rate,
@@ -1652,8 +1281,8 @@ static struct clk_core *clk_calc_new_rates(struct clk_core *clk,
 
                new_rate = ret;
                parent = parent_hw ? parent_hw->core : NULL;
-       } else if (clk->ops->round_rate) {
-               ret = clk->ops->round_rate(clk->hw, rate,
+       } else if (core->ops->round_rate) {
+               ret = core->ops->round_rate(core->hw, rate,
                                           &best_parent_rate);
                if (ret < 0)
                        return NULL;
@@ -1661,9 +1290,9 @@ static struct clk_core *clk_calc_new_rates(struct clk_core *clk,
                new_rate = ret;
                if (new_rate < min_rate || new_rate > max_rate)
                        return NULL;
-       } else if (!parent || !(clk->flags & CLK_SET_RATE_PARENT)) {
+       } else if (!parent || !(core->flags & CLK_SET_RATE_PARENT)) {
                /* pass-through clock without adjustable parent */
-               clk->new_rate = clk->rate;
+               core->new_rate = core->rate;
                return NULL;
        } else {
                /* pass-through clock with adjustable parent */
@@ -1674,28 +1303,28 @@ static struct clk_core *clk_calc_new_rates(struct clk_core *clk,
 
        /* some clocks must be gated to change parent */
        if (parent != old_parent &&
-           (clk->flags & CLK_SET_PARENT_GATE) && clk->prepare_count) {
+           (core->flags & CLK_SET_PARENT_GATE) && core->prepare_count) {
                pr_debug("%s: %s not gated but wants to reparent\n",
-                        __func__, clk->name);
+                        __func__, core->name);
                return NULL;
        }
 
        /* try finding the new parent index */
-       if (parent && clk->num_parents > 1) {
-               p_index = clk_fetch_parent_index(clk, parent);
+       if (parent && core->num_parents > 1) {
+               p_index = clk_fetch_parent_index(core, parent);
                if (p_index < 0) {
                        pr_debug("%s: clk %s can not be parent of clk %s\n",
-                                __func__, parent->name, clk->name);
+                                __func__, parent->name, core->name);
                        return NULL;
                }
        }
 
-       if ((clk->flags & CLK_SET_RATE_PARENT) && parent &&
+       if ((core->flags & CLK_SET_RATE_PARENT) && parent &&
            best_parent_rate != parent->rate)
                top = clk_calc_new_rates(parent, best_parent_rate);
 
 out:
-       clk_calc_subtree(clk, new_rate, parent, p_index);
+       clk_calc_subtree(core, new_rate, parent, p_index);
 
        return top;
 }
@@ -1705,33 +1334,33 @@ out:
  * so that in case of an error we can walk down the whole tree again and
  * abort the change.
  */
-static struct clk_core *clk_propagate_rate_change(struct clk_core *clk,
+static struct clk_core *clk_propagate_rate_change(struct clk_core *core,
                                                  unsigned long event)
 {
        struct clk_core *child, *tmp_clk, *fail_clk = NULL;
        int ret = NOTIFY_DONE;
 
-       if (clk->rate == clk->new_rate)
+       if (core->rate == core->new_rate)
                return NULL;
 
-       if (clk->notifier_count) {
-               ret = __clk_notify(clk, event, clk->rate, clk->new_rate);
+       if (core->notifier_count) {
+               ret = __clk_notify(core, event, core->rate, core->new_rate);
                if (ret & NOTIFY_STOP_MASK)
-                       fail_clk = clk;
+                       fail_clk = core;
        }
 
-       hlist_for_each_entry(child, &clk->children, child_node) {
+       hlist_for_each_entry(child, &core->children, child_node) {
                /* Skip children who will be reparented to another clock */
-               if (child->new_parent && child->new_parent != clk)
+               if (child->new_parent && child->new_parent != core)
                        continue;
                tmp_clk = clk_propagate_rate_change(child, event);
                if (tmp_clk)
                        fail_clk = tmp_clk;
        }
 
-       /* handle the new child who might not be in clk->children yet */
-       if (clk->new_child) {
-               tmp_clk = clk_propagate_rate_change(clk->new_child, event);
+       /* handle the new child who might not be in core->children yet */
+       if (core->new_child) {
+               tmp_clk = clk_propagate_rate_change(core->new_child, event);
                if (tmp_clk)
                        fail_clk = tmp_clk;
        }
@@ -1743,7 +1372,7 @@ static struct clk_core *clk_propagate_rate_change(struct clk_core *clk,
  * walk down a subtree and set the new rates notifying the rate
  * change on the way
  */
-static void clk_change_rate(struct clk_core *clk)
+static void clk_change_rate(struct clk_core *core)
 {
        struct clk_core *child;
        struct hlist_node *tmp;
@@ -1752,77 +1381,80 @@ static void clk_change_rate(struct clk_core *clk)
        bool skip_set_rate = false;
        struct clk_core *old_parent;
 
-       old_rate = clk->rate;
+       old_rate = core->rate;
 
-       if (clk->new_parent)
-               best_parent_rate = clk->new_parent->rate;
-       else if (clk->parent)
-               best_parent_rate = clk->parent->rate;
+       if (core->new_parent)
+               best_parent_rate = core->new_parent->rate;
+       else if (core->parent)
+               best_parent_rate = core->parent->rate;
 
-       if (clk->new_parent && clk->new_parent != clk->parent) {
-               old_parent = __clk_set_parent_before(clk, clk->new_parent);
-               trace_clk_set_parent(clk, clk->new_parent);
+       if (core->new_parent && core->new_parent != core->parent) {
+               old_parent = __clk_set_parent_before(core, core->new_parent);
+               trace_clk_set_parent(core, core->new_parent);
 
-               if (clk->ops->set_rate_and_parent) {
+               if (core->ops->set_rate_and_parent) {
                        skip_set_rate = true;
-                       clk->ops->set_rate_and_parent(clk->hw, clk->new_rate,
+                       core->ops->set_rate_and_parent(core->hw, core->new_rate,
                                        best_parent_rate,
-                                       clk->new_parent_index);
-               } else if (clk->ops->set_parent) {
-                       clk->ops->set_parent(clk->hw, clk->new_parent_index);
+                                       core->new_parent_index);
+               } else if (core->ops->set_parent) {
+                       core->ops->set_parent(core->hw, core->new_parent_index);
                }
 
-               trace_clk_set_parent_complete(clk, clk->new_parent);
-               __clk_set_parent_after(clk, clk->new_parent, old_parent);
+               trace_clk_set_parent_complete(core, core->new_parent);
+               __clk_set_parent_after(core, core->new_parent, old_parent);
        }
 
-       trace_clk_set_rate(clk, clk->new_rate);
+       trace_clk_set_rate(core, core->new_rate);
+
+       if (!skip_set_rate && core->ops->set_rate)
+               core->ops->set_rate(core->hw, core->new_rate, best_parent_rate);
 
-       if (!skip_set_rate && clk->ops->set_rate)
-               clk->ops->set_rate(clk->hw, clk->new_rate, best_parent_rate);
+       trace_clk_set_rate_complete(core, core->new_rate);
 
-       trace_clk_set_rate_complete(clk, clk->new_rate);
+       core->rate = clk_recalc(core, best_parent_rate);
 
-       clk->rate = clk_recalc(clk, best_parent_rate);
+       if (core->notifier_count && old_rate != core->rate)
+               __clk_notify(core, POST_RATE_CHANGE, old_rate, core->rate);
 
-       if (clk->notifier_count && old_rate != clk->rate)
-               __clk_notify(clk, POST_RATE_CHANGE, old_rate, clk->rate);
+       if (core->flags & CLK_RECALC_NEW_RATES)
+               (void)clk_calc_new_rates(core, core->new_rate);
 
        /*
         * Use safe iteration, as change_rate can actually swap parents
         * for certain clock types.
         */
-       hlist_for_each_entry_safe(child, tmp, &clk->children, child_node) {
+       hlist_for_each_entry_safe(child, tmp, &core->children, child_node) {
                /* Skip children who will be reparented to another clock */
-               if (child->new_parent && child->new_parent != clk)
+               if (child->new_parent && child->new_parent != core)
                        continue;
                clk_change_rate(child);
        }
 
-       /* handle the new child who might not be in clk->children yet */
-       if (clk->new_child)
-               clk_change_rate(clk->new_child);
+       /* handle the new child who might not be in core->children yet */
+       if (core->new_child)
+               clk_change_rate(core->new_child);
 }
 
-static int clk_core_set_rate_nolock(struct clk_core *clk,
+static int clk_core_set_rate_nolock(struct clk_core *core,
                                    unsigned long req_rate)
 {
        struct clk_core *top, *fail_clk;
        unsigned long rate = req_rate;
        int ret = 0;
 
-       if (!clk)
+       if (!core)
                return 0;
 
        /* bail early if nothing to do */
-       if (rate == clk_core_get_rate_nolock(clk))
+       if (rate == clk_core_get_rate_nolock(core))
                return 0;
 
-       if ((clk->flags & CLK_SET_RATE_GATE) && clk->prepare_count)
+       if ((core->flags & CLK_SET_RATE_GATE) && core->prepare_count)
                return -EBUSY;
 
        /* calculate new rates and get the topmost changed clock */
-       top = clk_calc_new_rates(clk, rate);
+       top = clk_calc_new_rates(core, rate);
        if (!top)
                return -EINVAL;
 
@@ -1838,7 +1470,7 @@ static int clk_core_set_rate_nolock(struct clk_core *clk,
        /* change the rates */
        clk_change_rate(top);
 
-       clk->req_rate = req_rate;
+       core->req_rate = req_rate;
 
        return ret;
 }
@@ -1977,55 +1609,63 @@ EXPORT_SYMBOL_GPL(clk_get_parent);
  * .parents array exists, and if so use it to avoid an expensive tree
  * traversal.  If .parents does not exist then walk the tree.
  */
-static struct clk_core *__clk_init_parent(struct clk_core *clk)
+static struct clk_core *__clk_init_parent(struct clk_core *core)
 {
        struct clk_core *ret = NULL;
        u8 index;
 
        /* handle the trivial cases */
 
-       if (!clk->num_parents)
+       if (!core->num_parents)
                goto out;
 
-       if (clk->num_parents == 1) {
-               if (IS_ERR_OR_NULL(clk->parent))
-                       clk->parent = clk_core_lookup(clk->parent_names[0]);
-               ret = clk->parent;
+       if (core->num_parents == 1) {
+               if (IS_ERR_OR_NULL(core->parent))
+                       core->parent = clk_core_lookup(core->parent_names[0]);
+               ret = core->parent;
                goto out;
        }
 
-       if (!clk->ops->get_parent) {
-               WARN(!clk->ops->get_parent,
+       if (!core->ops->get_parent) {
+               WARN(!core->ops->get_parent,
                        "%s: multi-parent clocks must implement .get_parent\n",
                        __func__);
                goto out;
        };
 
        /*
-        * Do our best to cache parent clocks in clk->parents.  This prevents
-        * unnecessary and expensive lookups.  We don't set clk->parent here;
+        * Do our best to cache parent clocks in core->parents.  This prevents
+        * unnecessary and expensive lookups.  We don't set core->parent here;
         * that is done by the calling function.
         */
 
-       index = clk->ops->get_parent(clk->hw);
+       index = core->ops->get_parent(core->hw);
 
-       if (!clk->parents)
-               clk->parents =
-                       kcalloc(clk->num_parents, sizeof(struct clk *),
+       if (!core->parents)
+               core->parents =
+                       kcalloc(core->num_parents, sizeof(struct clk *),
                                        GFP_KERNEL);
 
-       ret = clk_core_get_parent_by_index(clk, index);
+       ret = clk_core_get_parent_by_index(core, index);
 
 out:
        return ret;
 }
 
-static void clk_core_reparent(struct clk_core *clk,
+static void clk_core_reparent(struct clk_core *core,
                                  struct clk_core *new_parent)
 {
-       clk_reparent(clk, new_parent);
-       __clk_recalc_accuracies(clk);
-       __clk_recalc_rates(clk, POST_RATE_CHANGE);
+       clk_reparent(core, new_parent);
+       __clk_recalc_accuracies(core);
+       __clk_recalc_rates(core, POST_RATE_CHANGE);
+}
+
+void clk_hw_reparent(struct clk_hw *hw, struct clk_hw *new_parent)
+{
+       if (!hw)
+               return;
+
+       clk_core_reparent(hw->core, !new_parent ? NULL : new_parent->core);
 }
 
 /**
@@ -2054,209 +1694,536 @@ bool clk_has_parent(struct clk *clk, struct clk *parent)
        if (core->parent == parent_core)
                return true;
 
-       for (i = 0; i < core->num_parents; i++)
-               if (strcmp(core->parent_names[i], parent_core->name) == 0)
-                       return true;
+       for (i = 0; i < core->num_parents; i++)
+               if (strcmp(core->parent_names[i], parent_core->name) == 0)
+                       return true;
+
+       return false;
+}
+EXPORT_SYMBOL_GPL(clk_has_parent);
+
+static int clk_core_set_parent(struct clk_core *core, struct clk_core *parent)
+{
+       int ret = 0;
+       int p_index = 0;
+       unsigned long p_rate = 0;
+
+       if (!core)
+               return 0;
+
+       /* prevent racing with updates to the clock topology */
+       clk_prepare_lock();
+
+       if (core->parent == parent)
+               goto out;
+
+       /* verify ops for for multi-parent clks */
+       if ((core->num_parents > 1) && (!core->ops->set_parent)) {
+               ret = -ENOSYS;
+               goto out;
+       }
+
+       /* check that we are allowed to re-parent if the clock is in use */
+       if ((core->flags & CLK_SET_PARENT_GATE) && core->prepare_count) {
+               ret = -EBUSY;
+               goto out;
+       }
+
+       /* try finding the new parent index */
+       if (parent) {
+               p_index = clk_fetch_parent_index(core, parent);
+               p_rate = parent->rate;
+               if (p_index < 0) {
+                       pr_debug("%s: clk %s can not be parent of clk %s\n",
+                                       __func__, parent->name, core->name);
+                       ret = p_index;
+                       goto out;
+               }
+       }
+
+       /* propagate PRE_RATE_CHANGE notifications */
+       ret = __clk_speculate_rates(core, p_rate);
+
+       /* abort if a driver objects */
+       if (ret & NOTIFY_STOP_MASK)
+               goto out;
+
+       /* do the re-parent */
+       ret = __clk_set_parent(core, parent, p_index);
+
+       /* propagate rate an accuracy recalculation accordingly */
+       if (ret) {
+               __clk_recalc_rates(core, ABORT_RATE_CHANGE);
+       } else {
+               __clk_recalc_rates(core, POST_RATE_CHANGE);
+               __clk_recalc_accuracies(core);
+       }
+
+out:
+       clk_prepare_unlock();
+
+       return ret;
+}
+
+/**
+ * clk_set_parent - switch the parent of a mux clk
+ * @clk: the mux clk whose input we are switching
+ * @parent: the new input to clk
+ *
+ * Re-parent clk to use parent as its new input source.  If clk is in
+ * prepared state, the clk will get enabled for the duration of this call. If
+ * that's not acceptable for a specific clk (Eg: the consumer can't handle
+ * that, the reparenting is glitchy in hardware, etc), use the
+ * CLK_SET_PARENT_GATE flag to allow reparenting only when clk is unprepared.
+ *
+ * After successfully changing clk's parent clk_set_parent will update the
+ * clk topology, sysfs topology and propagate rate recalculation via
+ * __clk_recalc_rates.
+ *
+ * Returns 0 on success, -EERROR otherwise.
+ */
+int clk_set_parent(struct clk *clk, struct clk *parent)
+{
+       if (!clk)
+               return 0;
+
+       return clk_core_set_parent(clk->core, parent ? parent->core : NULL);
+}
+EXPORT_SYMBOL_GPL(clk_set_parent);
+
+/**
+ * clk_set_phase - adjust the phase shift of a clock signal
+ * @clk: clock signal source
+ * @degrees: number of degrees the signal is shifted
+ *
+ * Shifts the phase of a clock signal by the specified
+ * degrees. Returns 0 on success, -EERROR otherwise.
+ *
+ * This function makes no distinction about the input or reference
+ * signal that we adjust the clock signal phase against. For example
+ * phase locked-loop clock signal generators we may shift phase with
+ * respect to feedback clock signal input, but for other cases the
+ * clock phase may be shifted with respect to some other, unspecified
+ * signal.
+ *
+ * Additionally the concept of phase shift does not propagate through
+ * the clock tree hierarchy, which sets it apart from clock rates and
+ * clock accuracy. A parent clock phase attribute does not have an
+ * impact on the phase attribute of a child clock.
+ */
+int clk_set_phase(struct clk *clk, int degrees)
+{
+       int ret = -EINVAL;
+
+       if (!clk)
+               return 0;
+
+       /* sanity check degrees */
+       degrees %= 360;
+       if (degrees < 0)
+               degrees += 360;
+
+       clk_prepare_lock();
+
+       trace_clk_set_phase(clk->core, degrees);
+
+       if (clk->core->ops->set_phase)
+               ret = clk->core->ops->set_phase(clk->core->hw, degrees);
+
+       trace_clk_set_phase_complete(clk->core, degrees);
+
+       if (!ret)
+               clk->core->phase = degrees;
+
+       clk_prepare_unlock();
+
+       return ret;
+}
+EXPORT_SYMBOL_GPL(clk_set_phase);
+
+static int clk_core_get_phase(struct clk_core *core)
+{
+       int ret;
+
+       clk_prepare_lock();
+       ret = core->phase;
+       clk_prepare_unlock();
+
+       return ret;
+}
+
+/**
+ * clk_get_phase - return the phase shift of a clock signal
+ * @clk: clock signal source
+ *
+ * Returns the phase shift of a clock node in degrees, otherwise returns
+ * -EERROR.
+ */
+int clk_get_phase(struct clk *clk)
+{
+       if (!clk)
+               return 0;
+
+       return clk_core_get_phase(clk->core);
+}
+EXPORT_SYMBOL_GPL(clk_get_phase);
+
+/**
+ * clk_is_match - check if two clk's point to the same hardware clock
+ * @p: clk compared against q
+ * @q: clk compared against p
+ *
+ * Returns true if the two struct clk pointers both point to the same hardware
+ * clock node. Put differently, returns true if struct clk *p and struct clk *q
+ * share the same struct clk_core object.
+ *
+ * Returns false otherwise. Note that two NULL clks are treated as matching.
+ */
+bool clk_is_match(const struct clk *p, const struct clk *q)
+{
+       /* trivial case: identical struct clk's or both NULL */
+       if (p == q)
+               return true;
+
+       /* true if clk->core pointers match. Avoid derefing garbage */
+       if (!IS_ERR_OR_NULL(p) && !IS_ERR_OR_NULL(q))
+               if (p->core == q->core)
+                       return true;
+
+       return false;
+}
+EXPORT_SYMBOL_GPL(clk_is_match);
+
+/***        debugfs support        ***/
+
+#ifdef CONFIG_DEBUG_FS
+#include <linux/debugfs.h>
+
+static struct dentry *rootdir;
+static int inited = 0;
+static DEFINE_MUTEX(clk_debug_lock);
+static HLIST_HEAD(clk_debug_list);
+
+static struct hlist_head *all_lists[] = {
+       &clk_root_list,
+       &clk_orphan_list,
+       NULL,
+};
+
+static struct hlist_head *orphan_list[] = {
+       &clk_orphan_list,
+       NULL,
+};
+
+static void clk_summary_show_one(struct seq_file *s, struct clk_core *c,
+                                int level)
+{
+       if (!c)
+               return;
+
+       seq_printf(s, "%*s%-*s %11d %12d %11lu %10lu %-3d\n",
+                  level * 3 + 1, "",
+                  30 - level * 3, c->name,
+                  c->enable_count, c->prepare_count, clk_core_get_rate(c),
+                  clk_core_get_accuracy(c), clk_core_get_phase(c));
+}
+
+static void clk_summary_show_subtree(struct seq_file *s, struct clk_core *c,
+                                    int level)
+{
+       struct clk_core *child;
+
+       if (!c)
+               return;
+
+       clk_summary_show_one(s, c, level);
+
+       hlist_for_each_entry(child, &c->children, child_node)
+               clk_summary_show_subtree(s, child, level + 1);
+}
+
+static int clk_summary_show(struct seq_file *s, void *data)
+{
+       struct clk_core *c;
+       struct hlist_head **lists = (struct hlist_head **)s->private;
+
+       seq_puts(s, "   clock                         enable_cnt  prepare_cnt        rate   accuracy   phase\n");
+       seq_puts(s, "----------------------------------------------------------------------------------------\n");
+
+       clk_prepare_lock();
+
+       for (; *lists; lists++)
+               hlist_for_each_entry(c, *lists, child_node)
+                       clk_summary_show_subtree(s, c, 0);
+
+       clk_prepare_unlock();
+
+       return 0;
+}
+
+
+static int clk_summary_open(struct inode *inode, struct file *file)
+{
+       return single_open(file, clk_summary_show, inode->i_private);
+}
+
+static const struct file_operations clk_summary_fops = {
+       .open           = clk_summary_open,
+       .read           = seq_read,
+       .llseek         = seq_lseek,
+       .release        = single_release,
+};
+
+static void clk_dump_one(struct seq_file *s, struct clk_core *c, int level)
+{
+       if (!c)
+               return;
+
+       /* This should be JSON format, i.e. elements separated with a comma */
+       seq_printf(s, "\"%s\": { ", c->name);
+       seq_printf(s, "\"enable_count\": %d,", c->enable_count);
+       seq_printf(s, "\"prepare_count\": %d,", c->prepare_count);
+       seq_printf(s, "\"rate\": %lu,", clk_core_get_rate(c));
+       seq_printf(s, "\"accuracy\": %lu,", clk_core_get_accuracy(c));
+       seq_printf(s, "\"phase\": %d", clk_core_get_phase(c));
+}
+
+static void clk_dump_subtree(struct seq_file *s, struct clk_core *c, int level)
+{
+       struct clk_core *child;
+
+       if (!c)
+               return;
+
+       clk_dump_one(s, c, level);
+
+       hlist_for_each_entry(child, &c->children, child_node) {
+               seq_printf(s, ",");
+               clk_dump_subtree(s, child, level + 1);
+       }
+
+       seq_printf(s, "}");
+}
+
+static int clk_dump(struct seq_file *s, void *data)
+{
+       struct clk_core *c;
+       bool first_node = true;
+       struct hlist_head **lists = (struct hlist_head **)s->private;
+
+       seq_printf(s, "{");
+
+       clk_prepare_lock();
+
+       for (; *lists; lists++) {
+               hlist_for_each_entry(c, *lists, child_node) {
+                       if (!first_node)
+                               seq_puts(s, ",");
+                       first_node = false;
+                       clk_dump_subtree(s, c, 0);
+               }
+       }
+
+       clk_prepare_unlock();
 
-       return false;
+       seq_puts(s, "}\n");
+       return 0;
 }
-EXPORT_SYMBOL_GPL(clk_has_parent);
 
-static int clk_core_set_parent(struct clk_core *clk, struct clk_core *parent)
-{
-       int ret = 0;
-       int p_index = 0;
-       unsigned long p_rate = 0;
 
-       if (!clk)
-               return 0;
+static int clk_dump_open(struct inode *inode, struct file *file)
+{
+       return single_open(file, clk_dump, inode->i_private);
+}
 
-       /* prevent racing with updates to the clock topology */
-       clk_prepare_lock();
+static const struct file_operations clk_dump_fops = {
+       .open           = clk_dump_open,
+       .read           = seq_read,
+       .llseek         = seq_lseek,
+       .release        = single_release,
+};
 
-       if (clk->parent == parent)
-               goto out;
+static int clk_debug_create_one(struct clk_core *core, struct dentry *pdentry)
+{
+       struct dentry *d;
+       int ret = -ENOMEM;
 
-       /* verify ops for for multi-parent clks */
-       if ((clk->num_parents > 1) && (!clk->ops->set_parent)) {
-               ret = -ENOSYS;
+       if (!core || !pdentry) {
+               ret = -EINVAL;
                goto out;
        }
 
-       /* check that we are allowed to re-parent if the clock is in use */
-       if ((clk->flags & CLK_SET_PARENT_GATE) && clk->prepare_count) {
-               ret = -EBUSY;
+       d = debugfs_create_dir(core->name, pdentry);
+       if (!d)
                goto out;
-       }
 
-       /* try finding the new parent index */
-       if (parent) {
-               p_index = clk_fetch_parent_index(clk, parent);
-               p_rate = parent->rate;
-               if (p_index < 0) {
-                       pr_debug("%s: clk %s can not be parent of clk %s\n",
-                                       __func__, parent->name, clk->name);
-                       ret = p_index;
-                       goto out;
-               }
-       }
+       core->dentry = d;
 
-       /* propagate PRE_RATE_CHANGE notifications */
-       ret = __clk_speculate_rates(clk, p_rate);
+       d = debugfs_create_u32("clk_rate", S_IRUGO, core->dentry,
+                       (u32 *)&core->rate);
+       if (!d)
+               goto err_out;
 
-       /* abort if a driver objects */
-       if (ret & NOTIFY_STOP_MASK)
-               goto out;
+       d = debugfs_create_u32("clk_accuracy", S_IRUGO, core->dentry,
+                       (u32 *)&core->accuracy);
+       if (!d)
+               goto err_out;
 
-       /* do the re-parent */
-       ret = __clk_set_parent(clk, parent, p_index);
+       d = debugfs_create_u32("clk_phase", S_IRUGO, core->dentry,
+                       (u32 *)&core->phase);
+       if (!d)
+               goto err_out;
 
-       /* propagate rate an accuracy recalculation accordingly */
-       if (ret) {
-               __clk_recalc_rates(clk, ABORT_RATE_CHANGE);
-       } else {
-               __clk_recalc_rates(clk, POST_RATE_CHANGE);
-               __clk_recalc_accuracies(clk);
+       d = debugfs_create_x32("clk_flags", S_IRUGO, core->dentry,
+                       (u32 *)&core->flags);
+       if (!d)
+               goto err_out;
+
+       d = debugfs_create_u32("clk_prepare_count", S_IRUGO, core->dentry,
+                       (u32 *)&core->prepare_count);
+       if (!d)
+               goto err_out;
+
+       d = debugfs_create_u32("clk_enable_count", S_IRUGO, core->dentry,
+                       (u32 *)&core->enable_count);
+       if (!d)
+               goto err_out;
+
+       d = debugfs_create_u32("clk_notifier_count", S_IRUGO, core->dentry,
+                       (u32 *)&core->notifier_count);
+       if (!d)
+               goto err_out;
+
+       if (core->ops->debug_init) {
+               ret = core->ops->debug_init(core->hw, core->dentry);
+               if (ret)
+                       goto err_out;
        }
 
-out:
-       clk_prepare_unlock();
+       ret = 0;
+       goto out;
 
+err_out:
+       debugfs_remove_recursive(core->dentry);
+       core->dentry = NULL;
+out:
        return ret;
 }
 
 /**
- * clk_set_parent - switch the parent of a mux clk
- * @clk: the mux clk whose input we are switching
- * @parent: the new input to clk
- *
- * Re-parent clk to use parent as its new input source.  If clk is in
- * prepared state, the clk will get enabled for the duration of this call. If
- * that's not acceptable for a specific clk (Eg: the consumer can't handle
- * that, the reparenting is glitchy in hardware, etc), use the
- * CLK_SET_PARENT_GATE flag to allow reparenting only when clk is unprepared.
- *
- * After successfully changing clk's parent clk_set_parent will update the
- * clk topology, sysfs topology and propagate rate recalculation via
- * __clk_recalc_rates.
+ * clk_debug_register - add a clk node to the debugfs clk directory
+ * @core: the clk being added to the debugfs clk directory
  *
- * Returns 0 on success, -EERROR otherwise.
+ * Dynamically adds a clk to the debugfs clk directory if debugfs has been
+ * initialized.  Otherwise it bails out early since the debugfs clk directory
+ * will be created lazily by clk_debug_init as part of a late_initcall.
  */
-int clk_set_parent(struct clk *clk, struct clk *parent)
+static int clk_debug_register(struct clk_core *core)
 {
-       if (!clk)
-               return 0;
+       int ret = 0;
 
-       return clk_core_set_parent(clk->core, parent ? parent->core : NULL);
+       mutex_lock(&clk_debug_lock);
+       hlist_add_head(&core->debug_node, &clk_debug_list);
+
+       if (!inited)
+               goto unlock;
+
+       ret = clk_debug_create_one(core, rootdir);
+unlock:
+       mutex_unlock(&clk_debug_lock);
+
+       return ret;
 }
-EXPORT_SYMBOL_GPL(clk_set_parent);
 
-/**
- * clk_set_phase - adjust the phase shift of a clock signal
- * @clk: clock signal source
- * @degrees: number of degrees the signal is shifted
- *
- * Shifts the phase of a clock signal by the specified
- * degrees. Returns 0 on success, -EERROR otherwise.
- *
- * This function makes no distinction about the input or reference
- * signal that we adjust the clock signal phase against. For example
- * phase locked-loop clock signal generators we may shift phase with
- * respect to feedback clock signal input, but for other cases the
- * clock phase may be shifted with respect to some other, unspecified
- * signal.
+ /**
+ * clk_debug_unregister - remove a clk node from the debugfs clk directory
+ * @core: the clk being removed from the debugfs clk directory
  *
- * Additionally the concept of phase shift does not propagate through
- * the clock tree hierarchy, which sets it apart from clock rates and
- * clock accuracy. A parent clock phase attribute does not have an
- * impact on the phase attribute of a child clock.
+ * Dynamically removes a clk and all its child nodes from the
+ * debugfs clk directory if clk->dentry points to debugfs created by
+ * clk_debug_register in __clk_init.
  */
-int clk_set_phase(struct clk *clk, int degrees)
+static void clk_debug_unregister(struct clk_core *core)
 {
-       int ret = -EINVAL;
+       mutex_lock(&clk_debug_lock);
+       hlist_del_init(&core->debug_node);
+       debugfs_remove_recursive(core->dentry);
+       core->dentry = NULL;
+       mutex_unlock(&clk_debug_lock);
+}
 
-       if (!clk)
-               return 0;
+struct dentry *clk_debugfs_add_file(struct clk_hw *hw, char *name, umode_t mode,
+                               void *data, const struct file_operations *fops)
+{
+       struct dentry *d = NULL;
 
-       /* sanity check degrees */
-       degrees %= 360;
-       if (degrees < 0)
-               degrees += 360;
+       if (hw->core->dentry)
+               d = debugfs_create_file(name, mode, hw->core->dentry, data,
+                                       fops);
 
-       clk_prepare_lock();
+       return d;
+}
+EXPORT_SYMBOL_GPL(clk_debugfs_add_file);
 
-       trace_clk_set_phase(clk->core, degrees);
+/**
+ * clk_debug_init - lazily populate the debugfs clk directory
+ *
+ * clks are often initialized very early during boot before memory can be
+ * dynamically allocated and well before debugfs is setup. This function
+ * populates the debugfs clk directory once at boot-time when we know that
+ * debugfs is setup. It should only be called once at boot-time, all other clks
+ * added dynamically will be done so with clk_debug_register.
+ */
+static int __init clk_debug_init(void)
+{
+       struct clk_core *core;
+       struct dentry *d;
 
-       if (clk->core->ops->set_phase)
-               ret = clk->core->ops->set_phase(clk->core->hw, degrees);
+       rootdir = debugfs_create_dir("clk", NULL);
 
-       trace_clk_set_phase_complete(clk->core, degrees);
+       if (!rootdir)
+               return -ENOMEM;
 
-       if (!ret)
-               clk->core->phase = degrees;
+       d = debugfs_create_file("clk_summary", S_IRUGO, rootdir, &all_lists,
+                               &clk_summary_fops);
+       if (!d)
+               return -ENOMEM;
 
-       clk_prepare_unlock();
+       d = debugfs_create_file("clk_dump", S_IRUGO, rootdir, &all_lists,
+                               &clk_dump_fops);
+       if (!d)
+               return -ENOMEM;
 
-       return ret;
-}
-EXPORT_SYMBOL_GPL(clk_set_phase);
+       d = debugfs_create_file("clk_orphan_summary", S_IRUGO, rootdir,
+                               &orphan_list, &clk_summary_fops);
+       if (!d)
+               return -ENOMEM;
 
-static int clk_core_get_phase(struct clk_core *clk)
-{
-       int ret = 0;
+       d = debugfs_create_file("clk_orphan_dump", S_IRUGO, rootdir,
+                               &orphan_list, &clk_dump_fops);
+       if (!d)
+               return -ENOMEM;
 
-       if (!clk)
-               goto out;
+       mutex_lock(&clk_debug_lock);
+       hlist_for_each_entry(core, &clk_debug_list, debug_node)
+               clk_debug_create_one(core, rootdir);
 
-       clk_prepare_lock();
-       ret = clk->phase;
-       clk_prepare_unlock();
+       inited = 1;
+       mutex_unlock(&clk_debug_lock);
 
-out:
-       return ret;
+       return 0;
 }
-EXPORT_SYMBOL_GPL(clk_get_phase);
-
-/**
- * clk_get_phase - return the phase shift of a clock signal
- * @clk: clock signal source
- *
- * Returns the phase shift of a clock node in degrees, otherwise returns
- * -EERROR.
- */
-int clk_get_phase(struct clk *clk)
+late_initcall(clk_debug_init);
+#else
+static inline int clk_debug_register(struct clk_core *core) { return 0; }
+static inline void clk_debug_reparent(struct clk_core *core,
+                                     struct clk_core *new_parent)
 {
-       if (!clk)
-               return 0;
-
-       return clk_core_get_phase(clk->core);
 }
-
-/**
- * clk_is_match - check if two clk's point to the same hardware clock
- * @p: clk compared against q
- * @q: clk compared against p
- *
- * Returns true if the two struct clk pointers both point to the same hardware
- * clock node. Put differently, returns true if struct clk *p and struct clk *q
- * share the same struct clk_core object.
- *
- * Returns false otherwise. Note that two NULL clks are treated as matching.
- */
-bool clk_is_match(const struct clk *p, const struct clk *q)
+static inline void clk_debug_unregister(struct clk_core *core)
 {
-       /* trivial case: identical struct clk's or both NULL */
-       if (p == q)
-               return true;
-
-       /* true if clk->core pointers match. Avoid derefing garbage */
-       if (!IS_ERR_OR_NULL(p) && !IS_ERR_OR_NULL(q))
-               if (p->core == q->core)
-                       return true;
-
-       return false;
 }
-EXPORT_SYMBOL_GPL(clk_is_match);
+#endif
 
 /**
  * __clk_init - initialize the data structures in a struct clk
@@ -2271,67 +2238,67 @@ static int __clk_init(struct device *dev, struct clk *clk_user)
        int i, ret = 0;
        struct clk_core *orphan;
        struct hlist_node *tmp2;
-       struct clk_core *clk;
+       struct clk_core *core;
        unsigned long rate;
 
        if (!clk_user)
                return -EINVAL;
 
-       clk = clk_user->core;
+       core = clk_user->core;
 
        clk_prepare_lock();
 
        /* check to see if a clock with this name is already registered */
-       if (clk_core_lookup(clk->name)) {
+       if (clk_core_lookup(core->name)) {
                pr_debug("%s: clk %s already initialized\n",
-                               __func__, clk->name);
+                               __func__, core->name);
                ret = -EEXIST;
                goto out;
        }
 
        /* check that clk_ops are sane.  See Documentation/clk.txt */
-       if (clk->ops->set_rate &&
-           !((clk->ops->round_rate || clk->ops->determine_rate) &&
-             clk->ops->recalc_rate)) {
+       if (core->ops->set_rate &&
+           !((core->ops->round_rate || core->ops->determine_rate) &&
+             core->ops->recalc_rate)) {
                pr_warning("%s: %s must implement .round_rate or .determine_rate in addition to .recalc_rate\n",
-                               __func__, clk->name);
+                               __func__, core->name);
                ret = -EINVAL;
                goto out;
        }
 
-       if (clk->ops->set_parent && !clk->ops->get_parent) {
+       if (core->ops->set_parent && !core->ops->get_parent) {
                pr_warning("%s: %s must implement .get_parent & .set_parent\n",
-                               __func__, clk->name);
+                               __func__, core->name);
                ret = -EINVAL;
                goto out;
        }
 
-       if (clk->ops->set_rate_and_parent &&
-                       !(clk->ops->set_parent && clk->ops->set_rate)) {
+       if (core->ops->set_rate_and_parent &&
+                       !(core->ops->set_parent && core->ops->set_rate)) {
                pr_warn("%s: %s must implement .set_parent & .set_rate\n",
-                               __func__, clk->name);
+                               __func__, core->name);
                ret = -EINVAL;
                goto out;
        }
 
        /* throw a WARN if any entries in parent_names are NULL */
-       for (i = 0; i < clk->num_parents; i++)
-               WARN(!clk->parent_names[i],
+       for (i = 0; i < core->num_parents; i++)
+               WARN(!core->parent_names[i],
                                "%s: invalid NULL in %s's .parent_names\n",
-                               __func__, clk->name);
+                               __func__, core->name);
 
        /*
         * Allocate an array of struct clk *'s to avoid unnecessary string
         * look-ups of clk's possible parents.  This can fail for clocks passed
-        * in to clk_init during early boot; thus any access to clk->parents[]
+        * in to clk_init during early boot; thus any access to core->parents[]
         * must always check for a NULL pointer and try to populate it if
         * necessary.
         *
-        * If clk->parents is not NULL we skip this entire block.  This allows
-        * for clock drivers to statically initialize clk->parents.
+        * If core->parents is not NULL we skip this entire block.  This allows
+        * for clock drivers to statically initialize core->parents.
         */
-       if (clk->num_parents > 1 && !clk->parents) {
-               clk->parents = kcalloc(clk->num_parents, sizeof(struct clk *),
+       if (core->num_parents > 1 && !core->parents) {
+               core->parents = kcalloc(core->num_parents, sizeof(struct clk *),
                                        GFP_KERNEL);
                /*
                 * clk_core_lookup returns NULL for parents that have not been
@@ -2339,16 +2306,16 @@ static int __clk_init(struct device *dev, struct clk *clk_user)
                 * for a NULL pointer.  We can always perform lazy lookups for
                 * missing parents later on.
                 */
-               if (clk->parents)
-                       for (i = 0; i < clk->num_parents; i++)
-                               clk->parents[i] =
-                                       clk_core_lookup(clk->parent_names[i]);
+               if (core->parents)
+                       for (i = 0; i < core->num_parents; i++)
+                               core->parents[i] =
+                                       clk_core_lookup(core->parent_names[i]);
        }
 
-       clk->parent = __clk_init_parent(clk);
+       core->parent = __clk_init_parent(core);
 
        /*
-        * Populate clk->parent if parent has already been __clk_init'd.  If
+        * Populate core->parent if parent has already been __clk_init'd.  If
         * parent has not yet been __clk_init'd then place clk in the orphan
         * list.  If clk has set the CLK_IS_ROOT flag then place it in the root
         * clk list.
@@ -2357,13 +2324,13 @@ static int __clk_init(struct device *dev, struct clk *clk_user)
         * clocks and re-parent any that are children of the clock currently
         * being clk_init'd.
         */
-       if (clk->parent)
-               hlist_add_head(&clk->child_node,
-                               &clk->parent->children);
-       else if (clk->flags & CLK_IS_ROOT)
-               hlist_add_head(&clk->child_node, &clk_root_list);
+       if (core->parent)
+               hlist_add_head(&core->child_node,
+                               &core->parent->children);
+       else if (core->flags & CLK_IS_ROOT)
+               hlist_add_head(&core->child_node, &clk_root_list);
        else
-               hlist_add_head(&clk->child_node, &clk_orphan_list);
+               hlist_add_head(&core->child_node, &clk_orphan_list);
 
        /*
         * Set clk's accuracy.  The preferred method is to use
@@ -2372,23 +2339,23 @@ static int __clk_init(struct device *dev, struct clk *clk_user)
         * parent (or is orphaned) then accuracy is set to zero (perfect
         * clock).
         */
-       if (clk->ops->recalc_accuracy)
-               clk->accuracy = clk->ops->recalc_accuracy(clk->hw,
-                                       __clk_get_accuracy(clk->parent));
-       else if (clk->parent)
-               clk->accuracy = clk->parent->accuracy;
+       if (core->ops->recalc_accuracy)
+               core->accuracy = core->ops->recalc_accuracy(core->hw,
+                                       __clk_get_accuracy(core->parent));
+       else if (core->parent)
+               core->accuracy = core->parent->accuracy;
        else
-               clk->accuracy = 0;
+               core->accuracy = 0;
 
        /*
         * Set clk's phase.
         * Since a phase is by definition relative to its parent, just
         * query the current clock phase, or just assume it's in phase.
         */
-       if (clk->ops->get_phase)
-               clk->phase = clk->ops->get_phase(clk->hw);
+       if (core->ops->get_phase)
+               core->phase = core->ops->get_phase(core->hw);
        else
-               clk->phase = 0;
+               core->phase = 0;
 
        /*
         * Set clk's rate.  The preferred method is to use .recalc_rate.  For
@@ -2396,14 +2363,14 @@ static int __clk_init(struct device *dev, struct clk *clk_user)
         * parent's rate.  If a clock doesn't have a parent (or is orphaned)
         * then rate is set to zero.
         */
-       if (clk->ops->recalc_rate)
-               rate = clk->ops->recalc_rate(clk->hw,
-                               clk_core_get_rate_nolock(clk->parent));
-       else if (clk->parent)
-               rate = clk->parent->rate;
+       if (core->ops->recalc_rate)
+               rate = core->ops->recalc_rate(core->hw,
+                               clk_core_get_rate_nolock(core->parent));
+       else if (core->parent)
+               rate = core->parent->rate;
        else
                rate = 0;
-       clk->rate = clk->req_rate = rate;
+       core->rate = core->req_rate = rate;
 
        /*
         * walk the list of orphan clocks and reparent any that are children of
@@ -2412,14 +2379,14 @@ static int __clk_init(struct device *dev, struct clk *clk_user)
        hlist_for_each_entry_safe(orphan, tmp2, &clk_orphan_list, child_node) {
                if (orphan->num_parents && orphan->ops->get_parent) {
                        i = orphan->ops->get_parent(orphan->hw);
-                       if (!strcmp(clk->name, orphan->parent_names[i]))
-                               clk_core_reparent(orphan, clk);
+                       if (!strcmp(core->name, orphan->parent_names[i]))
+                               clk_core_reparent(orphan, core);
                        continue;
                }
 
                for (i = 0; i < orphan->num_parents; i++)
-                       if (!strcmp(clk->name, orphan->parent_names[i])) {
-                               clk_core_reparent(orphan, clk);
+                       if (!strcmp(core->name, orphan->parent_names[i])) {
+                               clk_core_reparent(orphan, core);
                                break;
                        }
         }
@@ -2432,15 +2399,15 @@ static int __clk_init(struct device *dev, struct clk *clk_user)
         * Please consider other ways of solving initialization problems before
         * using this callback, as its use is discouraged.
         */
-       if (clk->ops->init)
-               clk->ops->init(clk->hw);
+       if (core->ops->init)
+               core->ops->init(core->hw);
 
-       kref_init(&clk->ref);
+       kref_init(&core->ref);
 out:
        clk_prepare_unlock();
 
        if (!ret)
-               clk_debug_register(clk);
+               clk_debug_register(core);
 
        return ret;
 }
@@ -2486,63 +2453,58 @@ void __clk_free_clk(struct clk *clk)
  *
  * clk_register is the primary interface for populating the clock tree with new
  * clock nodes.  It returns a pointer to the newly allocated struct clk which
- * cannot be dereferenced by driver code but may be used in conjuction with the
+ * cannot be dereferenced by driver code but may be used in conjunction with the
  * rest of the clock API.  In the event of an error clk_register will return an
  * error code; drivers must test for an error code after calling clk_register.
  */
 struct clk *clk_register(struct device *dev, struct clk_hw *hw)
 {
        int i, ret;
-       struct clk_core *clk;
+       struct clk_core *core;
 
-       clk = kzalloc(sizeof(*clk), GFP_KERNEL);
-       if (!clk) {
-               pr_err("%s: could not allocate clk\n", __func__);
+       core = kzalloc(sizeof(*core), GFP_KERNEL);
+       if (!core) {
                ret = -ENOMEM;
                goto fail_out;
        }
 
-       clk->name = kstrdup_const(hw->init->name, GFP_KERNEL);
-       if (!clk->name) {
-               pr_err("%s: could not allocate clk->name\n", __func__);
+       core->name = kstrdup_const(hw->init->name, GFP_KERNEL);
+       if (!core->name) {
                ret = -ENOMEM;
                goto fail_name;
        }
-       clk->ops = hw->init->ops;
+       core->ops = hw->init->ops;
        if (dev && dev->driver)
-               clk->owner = dev->driver->owner;
-       clk->hw = hw;
-       clk->flags = hw->init->flags;
-       clk->num_parents = hw->init->num_parents;
-       hw->core = clk;
+               core->owner = dev->driver->owner;
+       core->hw = hw;
+       core->flags = hw->init->flags;
+       core->num_parents = hw->init->num_parents;
+       hw->core = core;
 
        /* allocate local copy in case parent_names is __initdata */
-       clk->parent_names = kcalloc(clk->num_parents, sizeof(char *),
+       core->parent_names = kcalloc(core->num_parents, sizeof(char *),
                                        GFP_KERNEL);
 
-       if (!clk->parent_names) {
-               pr_err("%s: could not allocate clk->parent_names\n", __func__);
+       if (!core->parent_names) {
                ret = -ENOMEM;
                goto fail_parent_names;
        }
 
 
        /* copy each string name in case parent_names is __initdata */
-       for (i = 0; i < clk->num_parents; i++) {
-               clk->parent_names[i] = kstrdup_const(hw->init->parent_names[i],
+       for (i = 0; i < core->num_parents; i++) {
+               core->parent_names[i] = kstrdup_const(hw->init->parent_names[i],
                                                GFP_KERNEL);
-               if (!clk->parent_names[i]) {
-                       pr_err("%s: could not copy parent_names\n", __func__);
+               if (!core->parent_names[i]) {
                        ret = -ENOMEM;
                        goto fail_parent_names_copy;
                }
        }
 
-       INIT_HLIST_HEAD(&clk->clks);
+       INIT_HLIST_HEAD(&core->clks);
 
        hw->clk = __clk_create_clk(hw, NULL, NULL);
        if (IS_ERR(hw->clk)) {
-               pr_err("%s: could not allocate per-user clk\n", __func__);
                ret = PTR_ERR(hw->clk);
                goto fail_parent_names_copy;
        }
@@ -2556,35 +2518,32 @@ struct clk *clk_register(struct device *dev, struct clk_hw *hw)
 
 fail_parent_names_copy:
        while (--i >= 0)
-               kfree_const(clk->parent_names[i]);
-       kfree(clk->parent_names);
+               kfree_const(core->parent_names[i]);
+       kfree(core->parent_names);
 fail_parent_names:
-       kfree_const(clk->name);
+       kfree_const(core->name);
 fail_name:
-       kfree(clk);
+       kfree(core);
 fail_out:
        return ERR_PTR(ret);
 }
 EXPORT_SYMBOL_GPL(clk_register);
 
-/*
- * Free memory allocated for a clock.
- * Caller must hold prepare_lock.
- */
+/* Free memory allocated for a clock. */
 static void __clk_release(struct kref *ref)
 {
-       struct clk_core *clk = container_of(ref, struct clk_core, ref);
-       int i = clk->num_parents;
+       struct clk_core *core = container_of(ref, struct clk_core, ref);
+       int i = core->num_parents;
 
        lockdep_assert_held(&prepare_lock);
 
-       kfree(clk->parents);
+       kfree(core->parents);
        while (--i >= 0)
-               kfree_const(clk->parent_names[i]);
+               kfree_const(core->parent_names[i]);
 
-       kfree(clk->parent_names);
-       kfree_const(clk->name);
-       kfree(clk);
+       kfree(core->parent_names);
+       kfree_const(core->name);
+       kfree(core);
 }
 
 /*
@@ -3068,6 +3027,27 @@ const char *of_clk_get_parent_name(struct device_node *np, int index)
 }
 EXPORT_SYMBOL_GPL(of_clk_get_parent_name);
 
+/**
+ * of_clk_parent_fill() - Fill @parents with names of @np's parents and return
+ * number of parents
+ * @np: Device node pointer associated with clock provider
+ * @parents: pointer to char array that hold the parents' names
+ * @size: size of the @parents array
+ *
+ * Return: number of parents for the clock node.
+ */
+int of_clk_parent_fill(struct device_node *np, const char **parents,
+                      unsigned int size)
+{
+       unsigned int i = 0;
+
+       while (i < size && (parents[i] = of_clk_get_parent_name(np, i)) != NULL)
+               i++;
+
+       return i;
+}
+EXPORT_SYMBOL_GPL(of_clk_parent_fill);
+
 struct clock_provider {
        of_clk_init_cb_t clk_init_cb;
        struct device_node *np;
diff --git a/drivers/clk/hisilicon/Kconfig b/drivers/clk/hisilicon/Kconfig
new file mode 100644 (file)
index 0000000..b4165ba
--- /dev/null
@@ -0,0 +1,6 @@
+config COMMON_CLK_HI6220
+       bool "Hi6220 Clock Driver"
+       depends on ARCH_HISI || COMPILE_TEST
+       default ARCH_HISI
+       help
+         Build the Hisilicon Hi6220 clock driver based on the common clock framework.
index 038c02f4d0e740df187b769764bfb28c3f891615..48f0116a032a4e0b9606107e4dec92c90ff11bd0 100644 (file)
@@ -2,8 +2,9 @@
 # Hisilicon Clock specific Makefile
 #
 
-obj-y  += clk.o clkgate-separated.o
+obj-y  += clk.o clkgate-separated.o clkdivider-hi6220.o
 
 obj-$(CONFIG_ARCH_HI3xxx)      += clk-hi3620.o
 obj-$(CONFIG_ARCH_HIP04)       += clk-hip04.o
 obj-$(CONFIG_ARCH_HIX5HD2)     += clk-hix5hd2.o
+obj-$(CONFIG_COMMON_CLK_HI6220)        += clk-hi6220.o
index 472dd2cb10b3bfe71a2e811c6e82db75f2d5df66..715d34a5ef9bc766b330726493445ffb02cfbb4d 100644 (file)
 #include "clk.h"
 
 /* clock parent list */
-static const char *timer0_mux_p[] __initdata = { "osc32k", "timerclk01", };
-static const char *timer1_mux_p[] __initdata = { "osc32k", "timerclk01", };
-static const char *timer2_mux_p[] __initdata = { "osc32k", "timerclk23", };
-static const char *timer3_mux_p[] __initdata = { "osc32k", "timerclk23", };
-static const char *timer4_mux_p[] __initdata = { "osc32k", "timerclk45", };
-static const char *timer5_mux_p[] __initdata = { "osc32k", "timerclk45", };
-static const char *timer6_mux_p[] __initdata = { "osc32k", "timerclk67", };
-static const char *timer7_mux_p[] __initdata = { "osc32k", "timerclk67", };
-static const char *timer8_mux_p[] __initdata = { "osc32k", "timerclk89", };
-static const char *timer9_mux_p[] __initdata = { "osc32k", "timerclk89", };
-static const char *uart0_mux_p[] __initdata = { "osc26m", "pclk", };
-static const char *uart1_mux_p[] __initdata = { "osc26m", "pclk", };
-static const char *uart2_mux_p[] __initdata = { "osc26m", "pclk", };
-static const char *uart3_mux_p[] __initdata = { "osc26m", "pclk", };
-static const char *uart4_mux_p[] __initdata = { "osc26m", "pclk", };
-static const char *spi0_mux_p[] __initdata = { "osc26m", "rclk_cfgaxi", };
-static const char *spi1_mux_p[] __initdata = { "osc26m", "rclk_cfgaxi", };
-static const char *spi2_mux_p[] __initdata = { "osc26m", "rclk_cfgaxi", };
+static const char *const timer0_mux_p[] __initconst = { "osc32k", "timerclk01", };
+static const char *const timer1_mux_p[] __initconst = { "osc32k", "timerclk01", };
+static const char *const timer2_mux_p[] __initconst = { "osc32k", "timerclk23", };
+static const char *const timer3_mux_p[] __initconst = { "osc32k", "timerclk23", };
+static const char *const timer4_mux_p[] __initconst = { "osc32k", "timerclk45", };
+static const char *const timer5_mux_p[] __initconst = { "osc32k", "timerclk45", };
+static const char *const timer6_mux_p[] __initconst = { "osc32k", "timerclk67", };
+static const char *const timer7_mux_p[] __initconst = { "osc32k", "timerclk67", };
+static const char *const timer8_mux_p[] __initconst = { "osc32k", "timerclk89", };
+static const char *const timer9_mux_p[] __initconst = { "osc32k", "timerclk89", };
+static const char *const uart0_mux_p[] __initconst = { "osc26m", "pclk", };
+static const char *const uart1_mux_p[] __initconst = { "osc26m", "pclk", };
+static const char *const uart2_mux_p[] __initconst = { "osc26m", "pclk", };
+static const char *const uart3_mux_p[] __initconst = { "osc26m", "pclk", };
+static const char *const uart4_mux_p[] __initconst = { "osc26m", "pclk", };
+static const char *const spi0_mux_p[] __initconst = { "osc26m", "rclk_cfgaxi", };
+static const char *const spi1_mux_p[] __initconst = { "osc26m", "rclk_cfgaxi", };
+static const char *const spi2_mux_p[] __initconst = { "osc26m", "rclk_cfgaxi", };
 /* share axi parent */
-static const char *saxi_mux_p[] __initdata = { "armpll3", "armpll2", };
-static const char *pwm0_mux_p[] __initdata = { "osc32k", "osc26m", };
-static const char *pwm1_mux_p[] __initdata = { "osc32k", "osc26m", };
-static const char *sd_mux_p[] __initdata = { "armpll2", "armpll3", };
-static const char *mmc1_mux_p[] __initdata = { "armpll2", "armpll3", };
-static const char *mmc1_mux2_p[] __initdata = { "osc26m", "mmc1_div", };
-static const char *g2d_mux_p[] __initdata = { "armpll2", "armpll3", };
-static const char *venc_mux_p[] __initdata = { "armpll2", "armpll3", };
-static const char *vdec_mux_p[] __initdata = { "armpll2", "armpll3", };
-static const char *vpp_mux_p[] __initdata = { "armpll2", "armpll3", };
-static const char *edc0_mux_p[] __initdata = { "armpll2", "armpll3", };
-static const char *ldi0_mux_p[] __initdata = { "armpll2", "armpll4",
+static const char *const saxi_mux_p[] __initconst = { "armpll3", "armpll2", };
+static const char *const pwm0_mux_p[] __initconst = { "osc32k", "osc26m", };
+static const char *const pwm1_mux_p[] __initconst = { "osc32k", "osc26m", };
+static const char *const sd_mux_p[] __initconst = { "armpll2", "armpll3", };
+static const char *const mmc1_mux_p[] __initconst = { "armpll2", "armpll3", };
+static const char *const mmc1_mux2_p[] __initconst = { "osc26m", "mmc1_div", };
+static const char *const g2d_mux_p[] __initconst = { "armpll2", "armpll3", };
+static const char *const venc_mux_p[] __initconst = { "armpll2", "armpll3", };
+static const char *const vdec_mux_p[] __initconst = { "armpll2", "armpll3", };
+static const char *const vpp_mux_p[] __initconst = { "armpll2", "armpll3", };
+static const char *const edc0_mux_p[] __initconst = { "armpll2", "armpll3", };
+static const char *const ldi0_mux_p[] __initconst = { "armpll2", "armpll4",
                                             "armpll3", "armpll5", };
-static const char *edc1_mux_p[] __initdata = { "armpll2", "armpll3", };
-static const char *ldi1_mux_p[] __initdata = { "armpll2", "armpll4",
+static const char *const edc1_mux_p[] __initconst = { "armpll2", "armpll3", };
+static const char *const ldi1_mux_p[] __initconst = { "armpll2", "armpll4",
                                             "armpll3", "armpll5", };
-static const char *rclk_hsic_p[] __initdata = { "armpll3", "armpll2", };
-static const char *mmc2_mux_p[] __initdata = { "armpll2", "armpll3", };
-static const char *mmc3_mux_p[] __initdata = { "armpll2", "armpll3", };
+static const char *const rclk_hsic_p[] __initconst = { "armpll3", "armpll2", };
+static const char *const mmc2_mux_p[] __initconst = { "armpll2", "armpll3", };
+static const char *const mmc3_mux_p[] __initconst = { "armpll2", "armpll3", };
 
 
 /* fixed rate clocks */
diff --git a/drivers/clk/hisilicon/clk-hi6220.c b/drivers/clk/hisilicon/clk-hi6220.c
new file mode 100644 (file)
index 0000000..4563343
--- /dev/null
@@ -0,0 +1,284 @@
+/*
+ * Hisilicon Hi6220 clock driver
+ *
+ * Copyright (c) 2015 Hisilicon Limited.
+ *
+ * Author: Bintian Wang <bintian.wang@huawei.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/kernel.h>
+#include <linux/clk-provider.h>
+#include <linux/clkdev.h>
+#include <linux/io.h>
+#include <linux/of.h>
+#include <linux/of_address.h>
+#include <linux/of_device.h>
+#include <linux/slab.h>
+
+#include <dt-bindings/clock/hi6220-clock.h>
+
+#include "clk.h"
+
+
+/* clocks in AO (always on) controller */
+static struct hisi_fixed_rate_clock hi6220_fixed_rate_clks[] __initdata = {
+       { HI6220_REF32K,        "ref32k",       NULL, CLK_IS_ROOT, 32764,     },
+       { HI6220_CLK_TCXO,      "clk_tcxo",     NULL, CLK_IS_ROOT, 19200000,  },
+       { HI6220_MMC1_PAD,      "mmc1_pad",     NULL, CLK_IS_ROOT, 100000000, },
+       { HI6220_MMC2_PAD,      "mmc2_pad",     NULL, CLK_IS_ROOT, 100000000, },
+       { HI6220_MMC0_PAD,      "mmc0_pad",     NULL, CLK_IS_ROOT, 200000000, },
+       { HI6220_PLL_BBP,       "bbppll0",      NULL, CLK_IS_ROOT, 245760000, },
+       { HI6220_PLL_GPU,       "gpupll",       NULL, CLK_IS_ROOT, 1000000000,},
+       { HI6220_PLL1_DDR,      "ddrpll1",      NULL, CLK_IS_ROOT, 1066000000,},
+       { HI6220_PLL_SYS,       "syspll",       NULL, CLK_IS_ROOT, 1200000000,},
+       { HI6220_PLL_SYS_MEDIA, "media_syspll", NULL, CLK_IS_ROOT, 1200000000,},
+       { HI6220_DDR_SRC,       "ddr_sel_src",  NULL, CLK_IS_ROOT, 1200000000,},
+       { HI6220_PLL_MEDIA,     "media_pll",    NULL, CLK_IS_ROOT, 1440000000,},
+       { HI6220_PLL_DDR,       "ddrpll0",      NULL, CLK_IS_ROOT, 1600000000,},
+};
+
+static struct hisi_fixed_factor_clock hi6220_fixed_factor_clks[] __initdata = {
+       { HI6220_300M,         "clk_300m",    "syspll",          1, 4, 0, },
+       { HI6220_150M,         "clk_150m",    "clk_300m",        1, 2, 0, },
+       { HI6220_PICOPHY_SRC,  "picophy_src", "clk_150m",        1, 4, 0, },
+       { HI6220_MMC0_SRC_SEL, "mmc0srcsel",  "mmc0_sel",        1, 8, 0, },
+       { HI6220_MMC1_SRC_SEL, "mmc1srcsel",  "mmc1_sel",        1, 8, 0, },
+       { HI6220_MMC2_SRC_SEL, "mmc2srcsel",  "mmc2_sel",        1, 8, 0, },
+       { HI6220_VPU_CODEC,    "vpucodec",    "codec_jpeg_aclk", 1, 2, 0, },
+       { HI6220_MMC0_SMP,     "mmc0_sample", "mmc0_sel",        1, 8, 0, },
+       { HI6220_MMC1_SMP,     "mmc1_sample", "mmc1_sel",        1, 8, 0, },
+       { HI6220_MMC2_SMP,     "mmc2_sample", "mmc2_sel",        1, 8, 0, },
+};
+
+static struct hisi_gate_clock hi6220_separated_gate_clks_ao[] __initdata = {
+       { HI6220_WDT0_PCLK,   "wdt0_pclk",   "clk_tcxo", CLK_SET_RATE_PARENT|CLK_IGNORE_UNUSED, 0x630, 12, 0, },
+       { HI6220_WDT1_PCLK,   "wdt1_pclk",   "clk_tcxo", CLK_SET_RATE_PARENT|CLK_IGNORE_UNUSED, 0x630, 13, 0, },
+       { HI6220_WDT2_PCLK,   "wdt2_pclk",   "clk_tcxo", CLK_SET_RATE_PARENT|CLK_IGNORE_UNUSED, 0x630, 14, 0, },
+       { HI6220_TIMER0_PCLK, "timer0_pclk", "clk_tcxo", CLK_SET_RATE_PARENT|CLK_IGNORE_UNUSED, 0x630, 15, 0, },
+       { HI6220_TIMER1_PCLK, "timer1_pclk", "clk_tcxo", CLK_SET_RATE_PARENT|CLK_IGNORE_UNUSED, 0x630, 16, 0, },
+       { HI6220_TIMER2_PCLK, "timer2_pclk", "clk_tcxo", CLK_SET_RATE_PARENT|CLK_IGNORE_UNUSED, 0x630, 17, 0, },
+       { HI6220_TIMER3_PCLK, "timer3_pclk", "clk_tcxo", CLK_SET_RATE_PARENT|CLK_IGNORE_UNUSED, 0x630, 18, 0, },
+       { HI6220_TIMER4_PCLK, "timer4_pclk", "clk_tcxo", CLK_SET_RATE_PARENT|CLK_IGNORE_UNUSED, 0x630, 19, 0, },
+       { HI6220_TIMER5_PCLK, "timer5_pclk", "clk_tcxo", CLK_SET_RATE_PARENT|CLK_IGNORE_UNUSED, 0x630, 20, 0, },
+       { HI6220_TIMER6_PCLK, "timer6_pclk", "clk_tcxo", CLK_SET_RATE_PARENT|CLK_IGNORE_UNUSED, 0x630, 21, 0, },
+       { HI6220_TIMER7_PCLK, "timer7_pclk", "clk_tcxo", CLK_SET_RATE_PARENT|CLK_IGNORE_UNUSED, 0x630, 22, 0, },
+       { HI6220_TIMER8_PCLK, "timer8_pclk", "clk_tcxo", CLK_SET_RATE_PARENT|CLK_IGNORE_UNUSED, 0x630, 23, 0, },
+       { HI6220_UART0_PCLK,  "uart0_pclk",  "clk_tcxo", CLK_SET_RATE_PARENT|CLK_IGNORE_UNUSED, 0x630, 24, 0, },
+};
+
+static void __init hi6220_clk_ao_init(struct device_node *np)
+{
+       struct hisi_clock_data *clk_data_ao;
+
+       clk_data_ao = hisi_clk_init(np, HI6220_AO_NR_CLKS);
+       if (!clk_data_ao)
+               return;
+
+       hisi_clk_register_fixed_rate(hi6220_fixed_rate_clks,
+                               ARRAY_SIZE(hi6220_fixed_rate_clks), clk_data_ao);
+
+       hisi_clk_register_fixed_factor(hi6220_fixed_factor_clks,
+                               ARRAY_SIZE(hi6220_fixed_factor_clks), clk_data_ao);
+
+       hisi_clk_register_gate_sep(hi6220_separated_gate_clks_ao,
+                               ARRAY_SIZE(hi6220_separated_gate_clks_ao), clk_data_ao);
+}
+CLK_OF_DECLARE(hi6220_clk_ao, "hisilicon,hi6220-aoctrl", hi6220_clk_ao_init);
+
+
+/* clocks in sysctrl */
+static const char *mmc0_mux0_p[] __initdata = { "pll_ddr_gate", "syspll", };
+static const char *mmc0_mux1_p[] __initdata = { "mmc0_mux0", "pll_media_gate", };
+static const char *mmc0_src_p[] __initdata = { "mmc0srcsel", "mmc0_div", };
+static const char *mmc1_mux0_p[] __initdata = { "pll_ddr_gate", "syspll", };
+static const char *mmc1_mux1_p[] __initdata = { "mmc1_mux0", "pll_media_gate", };
+static const char *mmc1_src_p[]  __initdata = { "mmc1srcsel", "mmc1_div", };
+static const char *mmc2_mux0_p[] __initdata = { "pll_ddr_gate", "syspll", };
+static const char *mmc2_mux1_p[] __initdata = { "mmc2_mux0", "pll_media_gate", };
+static const char *mmc2_src_p[]  __initdata = { "mmc2srcsel", "mmc2_div", };
+static const char *mmc0_sample_in[] __initdata = { "mmc0_sample", "mmc0_pad", };
+static const char *mmc1_sample_in[] __initdata = { "mmc1_sample", "mmc1_pad", };
+static const char *mmc2_sample_in[] __initdata = { "mmc2_sample", "mmc2_pad", };
+static const char *uart1_src[] __initdata = { "clk_tcxo", "clk_150m", };
+static const char *uart2_src[] __initdata = { "clk_tcxo", "clk_150m", };
+static const char *uart3_src[] __initdata = { "clk_tcxo", "clk_150m", };
+static const char *uart4_src[] __initdata = { "clk_tcxo", "clk_150m", };
+static const char *hifi_src[] __initdata = { "syspll", "pll_media_gate", };
+
+static struct hisi_gate_clock hi6220_separated_gate_clks_sys[] __initdata = {
+       { HI6220_MMC0_CLK,      "mmc0_clk",      "mmc0_src",       CLK_SET_RATE_PARENT|CLK_IGNORE_UNUSED, 0x200, 0,  0, },
+       { HI6220_MMC0_CIUCLK,   "mmc0_ciuclk",   "mmc0_smp_in",    CLK_SET_RATE_PARENT|CLK_IGNORE_UNUSED, 0x200, 0,  0, },
+       { HI6220_MMC1_CLK,      "mmc1_clk",      "mmc1_src",       CLK_SET_RATE_PARENT|CLK_IGNORE_UNUSED, 0x200, 1,  0, },
+       { HI6220_MMC1_CIUCLK,   "mmc1_ciuclk",   "mmc1_smp_in",    CLK_SET_RATE_PARENT|CLK_IGNORE_UNUSED, 0x200, 1,  0, },
+       { HI6220_MMC2_CLK,      "mmc2_clk",      "mmc2_src",       CLK_SET_RATE_PARENT|CLK_IGNORE_UNUSED, 0x200, 2,  0, },
+       { HI6220_MMC2_CIUCLK,   "mmc2_ciuclk",   "mmc2_smp_in",    CLK_SET_RATE_PARENT|CLK_IGNORE_UNUSED, 0x200, 2,  0, },
+       { HI6220_USBOTG_HCLK,   "usbotg_hclk",   "clk_bus",        CLK_SET_RATE_PARENT|CLK_IGNORE_UNUSED, 0x200, 4,  0, },
+       { HI6220_CLK_PICOPHY,   "clk_picophy",   "cs_dapb",        CLK_SET_RATE_PARENT|CLK_IGNORE_UNUSED, 0x200, 5,  0, },
+       { HI6220_HIFI,          "hifi_clk",      "hifi_div",       CLK_SET_RATE_PARENT|CLK_IGNORE_UNUSED, 0x210, 0,  0, },
+       { HI6220_DACODEC_PCLK,  "dacodec_pclk",  "clk_bus",        CLK_SET_RATE_PARENT|CLK_IGNORE_UNUSED, 0x210, 5,  0, },
+       { HI6220_EDMAC_ACLK,    "edmac_aclk",    "clk_bus",        CLK_SET_RATE_PARENT|CLK_IGNORE_UNUSED, 0x220, 2,  0, },
+       { HI6220_CS_ATB,        "cs_atb",        "cs_atb_div",     CLK_SET_RATE_PARENT|CLK_IGNORE_UNUSED, 0x230, 0,  0, },
+       { HI6220_I2C0_CLK,      "i2c0_clk",      "clk_150m",       CLK_SET_RATE_PARENT|CLK_IGNORE_UNUSED, 0x230, 1,  0, },
+       { HI6220_I2C1_CLK,      "i2c1_clk",      "clk_150m",       CLK_SET_RATE_PARENT|CLK_IGNORE_UNUSED, 0x230, 2,  0, },
+       { HI6220_I2C2_CLK,      "i2c2_clk",      "clk_150m",       CLK_SET_RATE_PARENT|CLK_IGNORE_UNUSED, 0x230, 3,  0, },
+       { HI6220_I2C3_CLK,      "i2c3_clk",      "clk_150m",       CLK_SET_RATE_PARENT|CLK_IGNORE_UNUSED, 0x230, 4,  0, },
+       { HI6220_UART1_PCLK,    "uart1_pclk",    "uart1_src",      CLK_SET_RATE_PARENT|CLK_IGNORE_UNUSED, 0x230, 5,  0, },
+       { HI6220_UART2_PCLK,    "uart2_pclk",    "uart2_src",      CLK_SET_RATE_PARENT|CLK_IGNORE_UNUSED, 0x230, 6,  0, },
+       { HI6220_UART3_PCLK,    "uart3_pclk",    "uart3_src",      CLK_SET_RATE_PARENT|CLK_IGNORE_UNUSED, 0x230, 7,  0, },
+       { HI6220_UART4_PCLK,    "uart4_pclk",    "uart4_src",      CLK_SET_RATE_PARENT|CLK_IGNORE_UNUSED, 0x230, 8,  0, },
+       { HI6220_SPI_CLK,       "spi_clk",       "clk_150m",       CLK_SET_RATE_PARENT|CLK_IGNORE_UNUSED, 0x230, 9,  0, },
+       { HI6220_TSENSOR_CLK,   "tsensor_clk",   "clk_bus",        CLK_SET_RATE_PARENT|CLK_IGNORE_UNUSED, 0x230, 12, 0, },
+       { HI6220_MMU_CLK,       "mmu_clk",       "ddrc_axi1",      CLK_SET_RATE_PARENT|CLK_IGNORE_UNUSED, 0x240, 11, 0, },
+       { HI6220_HIFI_SEL,      "hifi_sel",      "hifi_src",       CLK_SET_RATE_PARENT|CLK_IGNORE_UNUSED, 0x270, 0,  0, },
+       { HI6220_MMC0_SYSPLL,   "mmc0_syspll",   "syspll",         CLK_SET_RATE_PARENT|CLK_IGNORE_UNUSED, 0x270, 1,  0, },
+       { HI6220_MMC1_SYSPLL,   "mmc1_syspll",   "syspll",         CLK_SET_RATE_PARENT|CLK_IGNORE_UNUSED, 0x270, 2,  0, },
+       { HI6220_MMC2_SYSPLL,   "mmc2_syspll",   "syspll",         CLK_SET_RATE_PARENT|CLK_IGNORE_UNUSED, 0x270, 3,  0, },
+       { HI6220_MMC0_SEL,      "mmc0_sel",      "mmc0_mux1",      CLK_SET_RATE_PARENT|CLK_IGNORE_UNUSED, 0x270, 6,  0, },
+       { HI6220_MMC1_SEL,      "mmc1_sel",      "mmc1_mux1",      CLK_SET_RATE_PARENT|CLK_IGNORE_UNUSED, 0x270, 7,  0, },
+       { HI6220_BBPPLL_SEL,    "bbppll_sel",    "pll0_bbp_gate",  CLK_SET_RATE_PARENT|CLK_IGNORE_UNUSED, 0x270, 9,  0, },
+       { HI6220_MEDIA_PLL_SRC, "media_pll_src", "pll_media_gate", CLK_SET_RATE_PARENT|CLK_IGNORE_UNUSED, 0x270, 10, 0, },
+       { HI6220_MMC2_SEL,      "mmc2_sel",      "mmc2_mux1",      CLK_SET_RATE_PARENT|CLK_IGNORE_UNUSED, 0x270, 11, 0, },
+       { HI6220_CS_ATB_SYSPLL, "cs_atb_syspll", "syspll",         CLK_SET_RATE_PARENT|CLK_IGNORE_UNUSED, 0x270, 12, 0, },
+};
+
+static struct hisi_mux_clock hi6220_mux_clks_sys[] __initdata = {
+       { HI6220_MMC0_SRC,    "mmc0_src",    mmc0_src_p,     ARRAY_SIZE(mmc0_src_p),     CLK_SET_RATE_PARENT, 0x4,   0,  1, 0, },
+       { HI6220_MMC0_SMP_IN, "mmc0_smp_in", mmc0_sample_in, ARRAY_SIZE(mmc0_sample_in), CLK_SET_RATE_PARENT, 0x4,   0,  1, 0, },
+       { HI6220_MMC1_SRC,    "mmc1_src",    mmc1_src_p,     ARRAY_SIZE(mmc1_src_p),     CLK_SET_RATE_PARENT, 0x4,   2,  1, 0, },
+       { HI6220_MMC1_SMP_IN, "mmc1_smp_in", mmc1_sample_in, ARRAY_SIZE(mmc1_sample_in), CLK_SET_RATE_PARENT, 0x4,   2,  1, 0, },
+       { HI6220_MMC2_SRC,    "mmc2_src",    mmc2_src_p,     ARRAY_SIZE(mmc2_src_p),     CLK_SET_RATE_PARENT, 0x4,   4,  1, 0, },
+       { HI6220_MMC2_SMP_IN, "mmc2_smp_in", mmc2_sample_in, ARRAY_SIZE(mmc2_sample_in), CLK_SET_RATE_PARENT, 0x4,   4,  1, 0, },
+       { HI6220_HIFI_SRC,    "hifi_src",    hifi_src,       ARRAY_SIZE(hifi_src),       CLK_SET_RATE_PARENT, 0x400, 0,  1, CLK_MUX_HIWORD_MASK,},
+       { HI6220_UART1_SRC,   "uart1_src",   uart1_src,      ARRAY_SIZE(uart1_src),      CLK_SET_RATE_PARENT, 0x400, 1,  1, CLK_MUX_HIWORD_MASK,},
+       { HI6220_UART2_SRC,   "uart2_src",   uart2_src,      ARRAY_SIZE(uart2_src),      CLK_SET_RATE_PARENT, 0x400, 2,  1, CLK_MUX_HIWORD_MASK,},
+       { HI6220_UART3_SRC,   "uart3_src",   uart3_src,      ARRAY_SIZE(uart3_src),      CLK_SET_RATE_PARENT, 0x400, 3,  1, CLK_MUX_HIWORD_MASK,},
+       { HI6220_UART4_SRC,   "uart4_src",   uart4_src,      ARRAY_SIZE(uart4_src),      CLK_SET_RATE_PARENT, 0x400, 4,  1, CLK_MUX_HIWORD_MASK,},
+       { HI6220_MMC0_MUX0,   "mmc0_mux0",   mmc0_mux0_p,    ARRAY_SIZE(mmc0_mux0_p),    CLK_SET_RATE_PARENT, 0x400, 5,  1, CLK_MUX_HIWORD_MASK,},
+       { HI6220_MMC1_MUX0,   "mmc1_mux0",   mmc1_mux0_p,    ARRAY_SIZE(mmc1_mux0_p),    CLK_SET_RATE_PARENT, 0x400, 11, 1, CLK_MUX_HIWORD_MASK,},
+       { HI6220_MMC2_MUX0,   "mmc2_mux0",   mmc2_mux0_p,    ARRAY_SIZE(mmc2_mux0_p),    CLK_SET_RATE_PARENT, 0x400, 12, 1, CLK_MUX_HIWORD_MASK,},
+       { HI6220_MMC0_MUX1,   "mmc0_mux1",   mmc0_mux1_p,    ARRAY_SIZE(mmc0_mux1_p),    CLK_SET_RATE_PARENT, 0x400, 13, 1, CLK_MUX_HIWORD_MASK,},
+       { HI6220_MMC1_MUX1,   "mmc1_mux1",   mmc1_mux1_p,    ARRAY_SIZE(mmc1_mux1_p),    CLK_SET_RATE_PARENT, 0x400, 14, 1, CLK_MUX_HIWORD_MASK,},
+       { HI6220_MMC2_MUX1,   "mmc2_mux1",   mmc2_mux1_p,    ARRAY_SIZE(mmc2_mux1_p),    CLK_SET_RATE_PARENT, 0x400, 15, 1, CLK_MUX_HIWORD_MASK,},
+};
+
+static struct hi6220_divider_clock hi6220_div_clks_sys[] __initdata = {
+       { HI6220_CLK_BUS,     "clk_bus",     "clk_300m",      CLK_SET_RATE_PARENT, 0x490, 0,  4, 7, },
+       { HI6220_MMC0_DIV,    "mmc0_div",    "mmc0_syspll",   CLK_SET_RATE_PARENT, 0x494, 0,  6, 7, },
+       { HI6220_MMC1_DIV,    "mmc1_div",    "mmc1_syspll",   CLK_SET_RATE_PARENT, 0x498, 0,  6, 7, },
+       { HI6220_MMC2_DIV,    "mmc2_div",    "mmc2_syspll",   CLK_SET_RATE_PARENT, 0x49c, 0,  6, 7, },
+       { HI6220_HIFI_DIV,    "hifi_div",    "hifi_sel",      CLK_SET_RATE_PARENT, 0x4a0, 0,  4, 7, },
+       { HI6220_BBPPLL0_DIV, "bbppll0_div", "bbppll_sel",    CLK_SET_RATE_PARENT, 0x4a0, 8,  6, 15,},
+       { HI6220_CS_DAPB,     "cs_dapb",     "picophy_src",   CLK_SET_RATE_PARENT, 0x4a0, 24, 2, 31,},
+       { HI6220_CS_ATB_DIV,  "cs_atb_div",  "cs_atb_syspll", CLK_SET_RATE_PARENT, 0x4a4, 0,  4, 7, },
+};
+
+static void __init hi6220_clk_sys_init(struct device_node *np)
+{
+       struct hisi_clock_data *clk_data;
+
+       clk_data = hisi_clk_init(np, HI6220_SYS_NR_CLKS);
+       if (!clk_data)
+               return;
+
+       hisi_clk_register_gate_sep(hi6220_separated_gate_clks_sys,
+                       ARRAY_SIZE(hi6220_separated_gate_clks_sys), clk_data);
+
+       hisi_clk_register_mux(hi6220_mux_clks_sys,
+                       ARRAY_SIZE(hi6220_mux_clks_sys), clk_data);
+
+       hi6220_clk_register_divider(hi6220_div_clks_sys,
+                       ARRAY_SIZE(hi6220_div_clks_sys), clk_data);
+}
+CLK_OF_DECLARE(hi6220_clk_sys, "hisilicon,hi6220-sysctrl", hi6220_clk_sys_init);
+
+
+/* clocks in media controller */
+static const char *clk_1000_1200_src[] __initdata = { "pll_gpu_gate", "media_syspll_src", };
+static const char *clk_1440_1200_src[] __initdata = { "media_syspll_src", "media_pll_src", };
+static const char *clk_1000_1440_src[] __initdata = { "pll_gpu_gate", "media_pll_src", };
+
+static struct hisi_gate_clock hi6220_separated_gate_clks_media[] __initdata = {
+       { HI6220_DSI_PCLK,       "dsi_pclk",         "vpucodec",      CLK_SET_RATE_PARENT|CLK_IGNORE_UNUSED, 0x520, 0,  0, },
+       { HI6220_G3D_PCLK,       "g3d_pclk",         "vpucodec",      CLK_SET_RATE_PARENT|CLK_IGNORE_UNUSED, 0x520, 1,  0, },
+       { HI6220_ACLK_CODEC_VPU, "aclk_codec_vpu",   "ade_core_src",  CLK_SET_RATE_PARENT|CLK_IGNORE_UNUSED, 0x520, 3,  0, },
+       { HI6220_ISP_SCLK,       "isp_sclk",         "isp_sclk_src",  CLK_SET_RATE_PARENT|CLK_IGNORE_UNUSED, 0x520, 5,  0, },
+       { HI6220_ADE_CORE,       "ade_core",         "ade_core_src",  CLK_SET_RATE_PARENT|CLK_IGNORE_UNUSED, 0x520, 6,  0, },
+       { HI6220_MED_MMU,        "media_mmu",        "mmu_clk",       CLK_SET_RATE_PARENT|CLK_IGNORE_UNUSED, 0x520, 8,  0, },
+       { HI6220_CFG_CSI4PHY,    "cfg_csi4phy",      "clk_tcxo",      CLK_SET_RATE_PARENT|CLK_IGNORE_UNUSED, 0x520, 9,  0, },
+       { HI6220_CFG_CSI2PHY,    "cfg_csi2phy",      "clk_tcxo",      CLK_SET_RATE_PARENT|CLK_IGNORE_UNUSED, 0x520, 10, 0, },
+       { HI6220_ISP_SCLK_GATE,  "isp_sclk_gate",    "media_pll_src", CLK_SET_RATE_PARENT|CLK_IGNORE_UNUSED, 0x520, 11, 0, },
+       { HI6220_ISP_SCLK_GATE1, "isp_sclk_gate1",   "media_pll_src", CLK_SET_RATE_PARENT|CLK_IGNORE_UNUSED, 0x520, 12, 0, },
+       { HI6220_ADE_CORE_GATE,  "ade_core_gate",    "media_pll_src", CLK_SET_RATE_PARENT|CLK_IGNORE_UNUSED, 0x520, 14, 0, },
+       { HI6220_CODEC_VPU_GATE, "codec_vpu_gate",   "clk_1000_1440", CLK_SET_RATE_PARENT|CLK_IGNORE_UNUSED, 0x520, 15, 0, },
+       { HI6220_MED_SYSPLL,     "media_syspll_src", "media_syspll",  CLK_SET_RATE_PARENT|CLK_IGNORE_UNUSED, 0x520, 17, 0, },
+};
+
+static struct hisi_mux_clock hi6220_mux_clks_media[] __initdata = {
+       { HI6220_1440_1200, "clk_1440_1200", clk_1440_1200_src, ARRAY_SIZE(clk_1440_1200_src), CLK_SET_RATE_PARENT, 0x51c, 0, 1, 0, },
+       { HI6220_1000_1200, "clk_1000_1200", clk_1000_1200_src, ARRAY_SIZE(clk_1000_1200_src), CLK_SET_RATE_PARENT, 0x51c, 1, 1, 0, },
+       { HI6220_1000_1440, "clk_1000_1440", clk_1000_1440_src, ARRAY_SIZE(clk_1000_1440_src), CLK_SET_RATE_PARENT, 0x51c, 6, 1, 0, },
+};
+
+static struct hi6220_divider_clock hi6220_div_clks_media[] __initdata = {
+       { HI6220_CODEC_JPEG,    "codec_jpeg_aclk", "media_pll_src",  CLK_SET_RATE_PARENT, 0xcbc, 0,  4, 23, },
+       { HI6220_ISP_SCLK_SRC,  "isp_sclk_src",    "isp_sclk_gate",  CLK_SET_RATE_PARENT, 0xcbc, 8,  4, 15, },
+       { HI6220_ISP_SCLK1,     "isp_sclk1",       "isp_sclk_gate1", CLK_SET_RATE_PARENT, 0xcbc, 24, 4, 31, },
+       { HI6220_ADE_CORE_SRC,  "ade_core_src",    "ade_core_gate",  CLK_SET_RATE_PARENT, 0xcc0, 16, 3, 23, },
+       { HI6220_ADE_PIX_SRC,   "ade_pix_src",     "clk_1440_1200",  CLK_SET_RATE_PARENT, 0xcc0, 24, 6, 31, },
+       { HI6220_G3D_CLK,       "g3d_clk",         "clk_1000_1200",  CLK_SET_RATE_PARENT, 0xcc4, 8,  4, 15, },
+       { HI6220_CODEC_VPU_SRC, "codec_vpu_src",   "codec_vpu_gate", CLK_SET_RATE_PARENT, 0xcc4, 24, 6, 31, },
+};
+
+static void __init hi6220_clk_media_init(struct device_node *np)
+{
+       struct hisi_clock_data *clk_data;
+
+       clk_data = hisi_clk_init(np, HI6220_MEDIA_NR_CLKS);
+       if (!clk_data)
+               return;
+
+       hisi_clk_register_gate_sep(hi6220_separated_gate_clks_media,
+                               ARRAY_SIZE(hi6220_separated_gate_clks_media), clk_data);
+
+       hisi_clk_register_mux(hi6220_mux_clks_media,
+                               ARRAY_SIZE(hi6220_mux_clks_media), clk_data);
+
+       hi6220_clk_register_divider(hi6220_div_clks_media,
+                               ARRAY_SIZE(hi6220_div_clks_media), clk_data);
+}
+CLK_OF_DECLARE(hi6220_clk_media, "hisilicon,hi6220-mediactrl", hi6220_clk_media_init);
+
+
+/* clocks in pmctrl */
+static struct hisi_gate_clock hi6220_gate_clks_power[] __initdata = {
+       { HI6220_PLL_GPU_GATE,   "pll_gpu_gate",   "gpupll",    CLK_SET_RATE_PARENT|CLK_IGNORE_UNUSED, 0x8,  0,  0, },
+       { HI6220_PLL1_DDR_GATE,  "pll1_ddr_gate",  "ddrpll1",   CLK_SET_RATE_PARENT|CLK_IGNORE_UNUSED, 0x10, 0,  0, },
+       { HI6220_PLL_DDR_GATE,   "pll_ddr_gate",   "ddrpll0",   CLK_SET_RATE_PARENT|CLK_IGNORE_UNUSED, 0x18, 0,  0, },
+       { HI6220_PLL_MEDIA_GATE, "pll_media_gate", "media_pll", CLK_SET_RATE_PARENT|CLK_IGNORE_UNUSED, 0x38, 0,  0, },
+       { HI6220_PLL0_BBP_GATE,  "pll0_bbp_gate",  "bbppll0",   CLK_SET_RATE_PARENT|CLK_IGNORE_UNUSED, 0x48, 0,  0, },
+};
+
+static struct hi6220_divider_clock hi6220_div_clks_power[] __initdata = {
+       { HI6220_DDRC_SRC,  "ddrc_src",  "ddr_sel_src", CLK_SET_RATE_PARENT, 0x5a8, 0, 4, 0, },
+       { HI6220_DDRC_AXI1, "ddrc_axi1", "ddrc_src",    CLK_SET_RATE_PARENT, 0x5a8, 8, 2, 0, },
+};
+
+static void __init hi6220_clk_power_init(struct device_node *np)
+{
+       struct hisi_clock_data *clk_data;
+
+       clk_data = hisi_clk_init(np, HI6220_POWER_NR_CLKS);
+       if (!clk_data)
+               return;
+
+       hisi_clk_register_gate(hi6220_gate_clks_power,
+                               ARRAY_SIZE(hi6220_gate_clks_power), clk_data);
+
+       hi6220_clk_register_divider(hi6220_div_clks_power,
+                               ARRAY_SIZE(hi6220_div_clks_power), clk_data);
+}
+CLK_OF_DECLARE(hi6220_clk_power, "hisilicon,hi6220-pmctrl", hi6220_clk_power_init);
index f1d239435826ca6e7a873d08c9dcaa0c8590e630..0aaf29da84918337bb89dd83c1aec8c5dcb1a75a 100644 (file)
@@ -46,15 +46,15 @@ static struct hisi_fixed_rate_clock hix5hd2_fixed_rate_clks[] __initdata = {
        { HIX5HD2_FIXED_83M, "83m", NULL, CLK_IS_ROOT, 83333333, },
 };
 
-static const char *sfc_mux_p[] __initdata = {
+static const char *const sfc_mux_p[] __initconst = {
                "24m", "150m", "200m", "100m", "75m", };
 static u32 sfc_mux_table[] = {0, 4, 5, 6, 7};
 
-static const char *sdio_mux_p[] __initdata = {
+static const char *const sdio_mux_p[] __initconst = {
                "75m", "100m", "50m", "15m", };
 static u32 sdio_mux_table[] = {0, 1, 2, 3};
 
-static const char *fephy_mux_p[] __initdata = { "25m", "125m"};
+static const char *const fephy_mux_p[] __initconst = { "25m", "125m"};
 static u32 fephy_mux_table[] = {0, 1};
 
 
@@ -252,8 +252,9 @@ static struct clk_ops clk_complex_ops = {
        .disable = clk_complex_disable,
 };
 
-void __init hix5hd2_clk_register_complex(struct hix5hd2_complex_clock *clks,
-                                        int nums, struct hisi_clock_data *data)
+static void __init
+hix5hd2_clk_register_complex(struct hix5hd2_complex_clock *clks, int nums,
+                            struct hisi_clock_data *data)
 {
        void __iomem *base = data->base;
        int i;
index a078e84f7b05629a4d27bb3a6cc5a945a1beac8e..c90a89739b033480253641db138c99afde08be6c 100644 (file)
@@ -232,3 +232,32 @@ void __init hisi_clk_register_gate_sep(struct hisi_gate_clock *clks,
                data->clk_data.clks[clks[i].id] = clk;
        }
 }
+
+void __init hi6220_clk_register_divider(struct hi6220_divider_clock *clks,
+                                       int nums, struct hisi_clock_data *data)
+{
+       struct clk *clk;
+       void __iomem *base = data->base;
+       int i;
+
+       for (i = 0; i < nums; i++) {
+               clk = hi6220_register_clkdiv(NULL, clks[i].name,
+                                               clks[i].parent_name,
+                                               clks[i].flags,
+                                               base + clks[i].offset,
+                                               clks[i].shift,
+                                               clks[i].width,
+                                               clks[i].mask_bit,
+                                               &hisi_clk_lock);
+               if (IS_ERR(clk)) {
+                       pr_err("%s: failed to register clock %s\n",
+                              __func__, clks[i].name);
+                       continue;
+               }
+
+               if (clks[i].alias)
+                       clk_register_clkdev(clk, clks[i].alias, NULL);
+
+               data->clk_data.clks[clks[i].id] = clk;
+       }
+}
index 31083ffc0650b326f2232dead75672b2df6400e8..b56fbc1c5f27c4e0a8886fdeb4721891553113a1 100644 (file)
@@ -55,7 +55,7 @@ struct hisi_fixed_factor_clock {
 struct hisi_mux_clock {
        unsigned int            id;
        const char              *name;
-       const char              **parent_names;
+       const char              *const *parent_names;
        u8                      num_parents;
        unsigned long           flags;
        unsigned long           offset;
@@ -79,6 +79,18 @@ struct hisi_divider_clock {
        const char              *alias;
 };
 
+struct hi6220_divider_clock {
+       unsigned int            id;
+       const char              *name;
+       const char              *parent_name;
+       unsigned long           flags;
+       unsigned long           offset;
+       u8                      shift;
+       u8                      width;
+       u32                     mask_bit;
+       const char              *alias;
+};
+
 struct hisi_gate_clock {
        unsigned int            id;
        const char              *name;
@@ -94,18 +106,23 @@ struct clk *hisi_register_clkgate_sep(struct device *, const char *,
                                const char *, unsigned long,
                                void __iomem *, u8,
                                u8, spinlock_t *);
+struct clk *hi6220_register_clkdiv(struct device *dev, const char *name,
+       const char *parent_name, unsigned long flags, void __iomem *reg,
+       u8 shift, u8 width, u32 mask_bit, spinlock_t *lock);
 
-struct hisi_clock_data __init *hisi_clk_init(struct device_node *, int);
-void __init hisi_clk_register_fixed_rate(struct hisi_fixed_rate_clock *,
-                                       int, struct hisi_clock_data *);
-void __init hisi_clk_register_fixed_factor(struct hisi_fixed_factor_clock *,
-                                       int, struct hisi_clock_data *);
-void __init hisi_clk_register_mux(struct hisi_mux_clock *, int,
+struct hisi_clock_data *hisi_clk_init(struct device_node *, int);
+void hisi_clk_register_fixed_rate(struct hisi_fixed_rate_clock *,
+                               int, struct hisi_clock_data *);
+void hisi_clk_register_fixed_factor(struct hisi_fixed_factor_clock *,
+                               int, struct hisi_clock_data *);
+void hisi_clk_register_mux(struct hisi_mux_clock *, int,
                                struct hisi_clock_data *);
-void __init hisi_clk_register_divider(struct hisi_divider_clock *,
+void hisi_clk_register_divider(struct hisi_divider_clock *,
+                               int, struct hisi_clock_data *);
+void hisi_clk_register_gate(struct hisi_gate_clock *,
+                               int, struct hisi_clock_data *);
+void hisi_clk_register_gate_sep(struct hisi_gate_clock *,
+                               int, struct hisi_clock_data *);
+void hi6220_clk_register_divider(struct hi6220_divider_clock *,
                                int, struct hisi_clock_data *);
-void __init hisi_clk_register_gate(struct hisi_gate_clock *,
-                                       int, struct hisi_clock_data *);
-void __init hisi_clk_register_gate_sep(struct hisi_gate_clock *,
-                                       int, struct hisi_clock_data *);
 #endif /* __HISI_CLK_H */
diff --git a/drivers/clk/hisilicon/clkdivider-hi6220.c b/drivers/clk/hisilicon/clkdivider-hi6220.c
new file mode 100644 (file)
index 0000000..113eee8
--- /dev/null
@@ -0,0 +1,156 @@
+/*
+ * Hisilicon hi6220 SoC divider clock driver
+ *
+ * Copyright (c) 2015 Hisilicon Limited.
+ *
+ * Author: Bintian Wang <bintian.wang@huawei.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ */
+
+#include <linux/kernel.h>
+#include <linux/clk-provider.h>
+#include <linux/slab.h>
+#include <linux/io.h>
+#include <linux/err.h>
+#include <linux/spinlock.h>
+
+#define div_mask(width)        ((1 << (width)) - 1)
+
+/**
+ * struct hi6220_clk_divider - divider clock for hi6220
+ *
+ * @hw:                handle between common and hardware-specific interfaces
+ * @reg:       register containing divider
+ * @shift:     shift to the divider bit field
+ * @width:     width of the divider bit field
+ * @mask:      mask for setting divider rate
+ * @table:     the div table that the divider supports
+ * @lock:      register lock
+ */
+struct hi6220_clk_divider {
+       struct clk_hw   hw;
+       void __iomem    *reg;
+       u8              shift;
+       u8              width;
+       u32             mask;
+       const struct clk_div_table *table;
+       spinlock_t      *lock;
+};
+
+#define to_hi6220_clk_divider(_hw)     \
+       container_of(_hw, struct hi6220_clk_divider, hw)
+
+static unsigned long hi6220_clkdiv_recalc_rate(struct clk_hw *hw,
+                                       unsigned long parent_rate)
+{
+       unsigned int val;
+       struct hi6220_clk_divider *dclk = to_hi6220_clk_divider(hw);
+
+       val = readl_relaxed(dclk->reg) >> dclk->shift;
+       val &= div_mask(dclk->width);
+
+       return divider_recalc_rate(hw, parent_rate, val, dclk->table,
+                                  CLK_DIVIDER_ROUND_CLOSEST);
+}
+
+static long hi6220_clkdiv_round_rate(struct clk_hw *hw, unsigned long rate,
+                                       unsigned long *prate)
+{
+       struct hi6220_clk_divider *dclk = to_hi6220_clk_divider(hw);
+
+       return divider_round_rate(hw, rate, prate, dclk->table,
+                                 dclk->width, CLK_DIVIDER_ROUND_CLOSEST);
+}
+
+static int hi6220_clkdiv_set_rate(struct clk_hw *hw, unsigned long rate,
+                                       unsigned long parent_rate)
+{
+       int value;
+       unsigned long flags = 0;
+       u32 data;
+       struct hi6220_clk_divider *dclk = to_hi6220_clk_divider(hw);
+
+       value = divider_get_val(rate, parent_rate, dclk->table,
+                               dclk->width, CLK_DIVIDER_ROUND_CLOSEST);
+
+       if (dclk->lock)
+               spin_lock_irqsave(dclk->lock, flags);
+
+       data = readl_relaxed(dclk->reg);
+       data &= ~(div_mask(dclk->width) << dclk->shift);
+       data |= value << dclk->shift;
+       data |= dclk->mask;
+
+       writel_relaxed(data, dclk->reg);
+
+       if (dclk->lock)
+               spin_unlock_irqrestore(dclk->lock, flags);
+
+       return 0;
+}
+
+static const struct clk_ops hi6220_clkdiv_ops = {
+       .recalc_rate = hi6220_clkdiv_recalc_rate,
+       .round_rate = hi6220_clkdiv_round_rate,
+       .set_rate = hi6220_clkdiv_set_rate,
+};
+
+struct clk *hi6220_register_clkdiv(struct device *dev, const char *name,
+       const char *parent_name, unsigned long flags, void __iomem *reg,
+       u8 shift, u8 width, u32 mask_bit, spinlock_t *lock)
+{
+       struct hi6220_clk_divider *div;
+       struct clk *clk;
+       struct clk_init_data init;
+       struct clk_div_table *table;
+       u32 max_div, min_div;
+       int i;
+
+       /* allocate the divider */
+       div = kzalloc(sizeof(*div), GFP_KERNEL);
+       if (!div)
+               return ERR_PTR(-ENOMEM);
+
+       /* Init the divider table */
+       max_div = div_mask(width) + 1;
+       min_div = 1;
+
+       table = kcalloc(max_div + 1, sizeof(*table), GFP_KERNEL);
+       if (!table) {
+               kfree(div);
+               return ERR_PTR(-ENOMEM);
+       }
+
+       for (i = 0; i < max_div; i++) {
+               table[i].div = min_div + i;
+               table[i].val = table[i].div - 1;
+       }
+
+       init.name = name;
+       init.ops = &hi6220_clkdiv_ops;
+       init.flags = flags;
+       init.parent_names = parent_name ? &parent_name : NULL;
+       init.num_parents = parent_name ? 1 : 0;
+
+       /* struct hi6220_clk_divider assignments */
+       div->reg = reg;
+       div->shift = shift;
+       div->width = width;
+       div->mask = mask_bit ? BIT(mask_bit) : 0;
+       div->lock = lock;
+       div->hw.init = &init;
+       div->table = table;
+
+       /* register the clock */
+       clk = clk_register(dev, &div->hw);
+       if (IS_ERR(clk)) {
+               kfree(table);
+               kfree(div);
+       }
+
+       return clk;
+}
index 0dd8a4b12747b6df0ce1c88f34aaf28781fe85f8..4a375ead70e9f2c58c1eb6aaced07ea39e579b7b 100644 (file)
@@ -37,7 +37,8 @@
  *     Main PLL or any other PLLs in the device such as ARM PLL, DDR PLL
  *     or PA PLL available on keystone2. These PLLs are controlled by
  *     this register. Main PLL is controlled by a PLL controller.
- * @pllm: PLL register map address
+ * @pllm: PLL register map address for multiplier bits
+ * @pllod: PLL register map address for post divider bits
  * @pll_ctl0: PLL controller map address
  * @pllm_lower_mask: multiplier lower mask
  * @pllm_upper_mask: multiplier upper mask
@@ -53,6 +54,7 @@ struct clk_pll_data {
        u32 phy_pllm;
        u32 phy_pll_ctl0;
        void __iomem *pllm;
+       void __iomem *pllod;
        void __iomem *pll_ctl0;
        u32 pllm_lower_mask;
        u32 pllm_upper_mask;
@@ -102,7 +104,11 @@ static unsigned long clk_pllclk_recalc(struct clk_hw *hw,
                /* read post divider from od bits*/
                postdiv = ((val & pll_data->clkod_mask) >>
                                 pll_data->clkod_shift) + 1;
-       else
+       else if (pll_data->pllod) {
+               postdiv = readl(pll_data->pllod);
+               postdiv = ((postdiv & pll_data->clkod_mask) >>
+                               pll_data->clkod_shift) + 1;
+       } else
                postdiv = pll_data->postdiv;
 
        rate /= (prediv + 1);
@@ -172,12 +178,21 @@ static void __init _of_pll_clk_init(struct device_node *node, bool pllctrl)
                /* assume the PLL has output divider register bits */
                pll_data->clkod_mask = CLKOD_MASK;
                pll_data->clkod_shift = CLKOD_SHIFT;
+
+               /*
+                * Check if there is an post-divider register. If not
+                * assume od bits are part of control register.
+                */
+               i = of_property_match_string(node, "reg-names",
+                                            "post-divider");
+               pll_data->pllod = of_iomap(node, i);
        }
 
        i = of_property_match_string(node, "reg-names", "control");
        pll_data->pll_ctl0 = of_iomap(node, i);
        if (!pll_data->pll_ctl0) {
                pr_err("%s: ioremap failed\n", __func__);
+               iounmap(pll_data->pllod);
                goto out;
        }
 
@@ -193,6 +208,7 @@ static void __init _of_pll_clk_init(struct device_node *node, bool pllctrl)
                pll_data->pllm = of_iomap(node, i);
                if (!pll_data->pllm) {
                        iounmap(pll_data->pll_ctl0);
+                       iounmap(pll_data->pllod);
                        goto out;
                }
        }
diff --git a/drivers/clk/mediatek/Makefile b/drivers/clk/mediatek/Makefile
new file mode 100644 (file)
index 0000000..8e4b2a4
--- /dev/null
@@ -0,0 +1,4 @@
+obj-y += clk-mtk.o clk-pll.o clk-gate.o
+obj-$(CONFIG_RESET_CONTROLLER) += reset.o
+obj-y += clk-mt8135.o
+obj-y += clk-mt8173.o
diff --git a/drivers/clk/mediatek/clk-gate.c b/drivers/clk/mediatek/clk-gate.c
new file mode 100644 (file)
index 0000000..5702036
--- /dev/null
@@ -0,0 +1,137 @@
+/*
+ * Copyright (c) 2014 MediaTek Inc.
+ * Author: James Liao <jamesjj.liao@mediatek.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/of.h>
+#include <linux/of_address.h>
+
+#include <linux/io.h>
+#include <linux/slab.h>
+#include <linux/delay.h>
+#include <linux/clkdev.h>
+
+#include "clk-mtk.h"
+#include "clk-gate.h"
+
+static int mtk_cg_bit_is_cleared(struct clk_hw *hw)
+{
+       struct mtk_clk_gate *cg = to_clk_gate(hw);
+       u32 val;
+
+       regmap_read(cg->regmap, cg->sta_ofs, &val);
+
+       val &= BIT(cg->bit);
+
+       return val == 0;
+}
+
+static int mtk_cg_bit_is_set(struct clk_hw *hw)
+{
+       struct mtk_clk_gate *cg = to_clk_gate(hw);
+       u32 val;
+
+       regmap_read(cg->regmap, cg->sta_ofs, &val);
+
+       val &= BIT(cg->bit);
+
+       return val != 0;
+}
+
+static void mtk_cg_set_bit(struct clk_hw *hw)
+{
+       struct mtk_clk_gate *cg = to_clk_gate(hw);
+
+       regmap_write(cg->regmap, cg->set_ofs, BIT(cg->bit));
+}
+
+static void mtk_cg_clr_bit(struct clk_hw *hw)
+{
+       struct mtk_clk_gate *cg = to_clk_gate(hw);
+
+       regmap_write(cg->regmap, cg->clr_ofs, BIT(cg->bit));
+}
+
+static int mtk_cg_enable(struct clk_hw *hw)
+{
+       mtk_cg_clr_bit(hw);
+
+       return 0;
+}
+
+static void mtk_cg_disable(struct clk_hw *hw)
+{
+       mtk_cg_set_bit(hw);
+}
+
+static int mtk_cg_enable_inv(struct clk_hw *hw)
+{
+       mtk_cg_set_bit(hw);
+
+       return 0;
+}
+
+static void mtk_cg_disable_inv(struct clk_hw *hw)
+{
+       mtk_cg_clr_bit(hw);
+}
+
+const struct clk_ops mtk_clk_gate_ops_setclr = {
+       .is_enabled     = mtk_cg_bit_is_cleared,
+       .enable         = mtk_cg_enable,
+       .disable        = mtk_cg_disable,
+};
+
+const struct clk_ops mtk_clk_gate_ops_setclr_inv = {
+       .is_enabled     = mtk_cg_bit_is_set,
+       .enable         = mtk_cg_enable_inv,
+       .disable        = mtk_cg_disable_inv,
+};
+
+struct clk *mtk_clk_register_gate(
+               const char *name,
+               const char *parent_name,
+               struct regmap *regmap,
+               int set_ofs,
+               int clr_ofs,
+               int sta_ofs,
+               u8 bit,
+               const struct clk_ops *ops)
+{
+       struct mtk_clk_gate *cg;
+       struct clk *clk;
+       struct clk_init_data init = {};
+
+       cg = kzalloc(sizeof(*cg), GFP_KERNEL);
+       if (!cg)
+               return ERR_PTR(-ENOMEM);
+
+       init.name = name;
+       init.flags = CLK_SET_RATE_PARENT;
+       init.parent_names = parent_name ? &parent_name : NULL;
+       init.num_parents = parent_name ? 1 : 0;
+       init.ops = ops;
+
+       cg->regmap = regmap;
+       cg->set_ofs = set_ofs;
+       cg->clr_ofs = clr_ofs;
+       cg->sta_ofs = sta_ofs;
+       cg->bit = bit;
+
+       cg->hw.init = &init;
+
+       clk = clk_register(NULL, &cg->hw);
+       if (IS_ERR(clk))
+               kfree(cg);
+
+       return clk;
+}
diff --git a/drivers/clk/mediatek/clk-gate.h b/drivers/clk/mediatek/clk-gate.h
new file mode 100644 (file)
index 0000000..6b6780b
--- /dev/null
@@ -0,0 +1,49 @@
+/*
+ * Copyright (c) 2014 MediaTek Inc.
+ * Author: James Liao <jamesjj.liao@mediatek.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#ifndef __DRV_CLK_GATE_H
+#define __DRV_CLK_GATE_H
+
+#include <linux/regmap.h>
+#include <linux/clk.h>
+#include <linux/clk-provider.h>
+
+struct mtk_clk_gate {
+       struct clk_hw   hw;
+       struct regmap   *regmap;
+       int             set_ofs;
+       int             clr_ofs;
+       int             sta_ofs;
+       u8              bit;
+};
+
+static inline struct mtk_clk_gate *to_clk_gate(struct clk_hw *hw)
+{
+       return container_of(hw, struct mtk_clk_gate, hw);
+}
+
+extern const struct clk_ops mtk_clk_gate_ops_setclr;
+extern const struct clk_ops mtk_clk_gate_ops_setclr_inv;
+
+struct clk *mtk_clk_register_gate(
+               const char *name,
+               const char *parent_name,
+               struct regmap *regmap,
+               int set_ofs,
+               int clr_ofs,
+               int sta_ofs,
+               u8 bit,
+               const struct clk_ops *ops);
+
+#endif /* __DRV_CLK_GATE_H */
diff --git a/drivers/clk/mediatek/clk-mt8135.c b/drivers/clk/mediatek/clk-mt8135.c
new file mode 100644 (file)
index 0000000..08b4b84
--- /dev/null
@@ -0,0 +1,644 @@
+/*
+ * Copyright (c) 2014 MediaTek Inc.
+ * Author: James Liao <jamesjj.liao@mediatek.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/of.h>
+#include <linux/of_address.h>
+#include <linux/slab.h>
+#include <linux/mfd/syscon.h>
+#include <dt-bindings/clock/mt8135-clk.h>
+
+#include "clk-mtk.h"
+#include "clk-gate.h"
+
+static DEFINE_SPINLOCK(mt8135_clk_lock);
+
+static const struct mtk_fixed_factor root_clk_alias[] __initconst = {
+       FACTOR(CLK_TOP_DSI0_LNTC_DSICLK, "dsi0_lntc_dsiclk", "clk_null", 1, 1),
+       FACTOR(CLK_TOP_HDMITX_CLKDIG_CTS, "hdmitx_clkdig_cts", "clk_null", 1, 1),
+       FACTOR(CLK_TOP_CLKPH_MCK, "clkph_mck", "clk_null", 1, 1),
+       FACTOR(CLK_TOP_CPUM_TCK_IN, "cpum_tck_in", "clk_null", 1, 1),
+};
+
+static const struct mtk_fixed_factor top_divs[] __initconst = {
+       FACTOR(CLK_TOP_MAINPLL_806M, "mainpll_806m", "mainpll", 1, 2),
+       FACTOR(CLK_TOP_MAINPLL_537P3M, "mainpll_537p3m", "mainpll", 1, 3),
+       FACTOR(CLK_TOP_MAINPLL_322P4M, "mainpll_322p4m", "mainpll", 1, 5),
+       FACTOR(CLK_TOP_MAINPLL_230P3M, "mainpll_230p3m", "mainpll", 1, 7),
+
+       FACTOR(CLK_TOP_UNIVPLL_624M, "univpll_624m", "univpll", 1, 2),
+       FACTOR(CLK_TOP_UNIVPLL_416M, "univpll_416m", "univpll", 1, 3),
+       FACTOR(CLK_TOP_UNIVPLL_249P6M, "univpll_249p6m", "univpll", 1, 5),
+       FACTOR(CLK_TOP_UNIVPLL_178P3M, "univpll_178p3m", "univpll", 1, 7),
+       FACTOR(CLK_TOP_UNIVPLL_48M, "univpll_48m", "univpll", 1, 26),
+
+       FACTOR(CLK_TOP_MMPLL_D2, "mmpll_d2", "mmpll", 1, 2),
+       FACTOR(CLK_TOP_MMPLL_D3, "mmpll_d3", "mmpll", 1, 3),
+       FACTOR(CLK_TOP_MMPLL_D5, "mmpll_d5", "mmpll", 1, 5),
+       FACTOR(CLK_TOP_MMPLL_D7, "mmpll_d7", "mmpll", 1, 7),
+       FACTOR(CLK_TOP_MMPLL_D4, "mmpll_d4", "mmpll_d2", 1, 2),
+       FACTOR(CLK_TOP_MMPLL_D6, "mmpll_d6", "mmpll_d3", 1, 2),
+
+       FACTOR(CLK_TOP_SYSPLL_D2, "syspll_d2", "mainpll_806m", 1, 1),
+       FACTOR(CLK_TOP_SYSPLL_D4, "syspll_d4", "mainpll_806m", 1, 2),
+       FACTOR(CLK_TOP_SYSPLL_D6, "syspll_d6", "mainpll_806m", 1, 3),
+       FACTOR(CLK_TOP_SYSPLL_D8, "syspll_d8", "mainpll_806m", 1, 4),
+       FACTOR(CLK_TOP_SYSPLL_D10, "syspll_d10", "mainpll_806m", 1, 5),
+       FACTOR(CLK_TOP_SYSPLL_D12, "syspll_d12", "mainpll_806m", 1, 6),
+       FACTOR(CLK_TOP_SYSPLL_D16, "syspll_d16", "mainpll_806m", 1, 8),
+       FACTOR(CLK_TOP_SYSPLL_D24, "syspll_d24", "mainpll_806m", 1, 12),
+
+       FACTOR(CLK_TOP_SYSPLL_D3, "syspll_d3", "mainpll_537p3m", 1, 1),
+
+       FACTOR(CLK_TOP_SYSPLL_D2P5, "syspll_d2p5", "mainpll_322p4m", 2, 1),
+       FACTOR(CLK_TOP_SYSPLL_D5, "syspll_d5", "mainpll_322p4m", 1, 1),
+
+       FACTOR(CLK_TOP_SYSPLL_D3P5, "syspll_d3p5", "mainpll_230p3m", 2, 1),
+
+       FACTOR(CLK_TOP_UNIVPLL1_D2, "univpll1_d2", "univpll_624m", 1, 2),
+       FACTOR(CLK_TOP_UNIVPLL1_D4, "univpll1_d4", "univpll_624m", 1, 4),
+       FACTOR(CLK_TOP_UNIVPLL1_D6, "univpll1_d6", "univpll_624m", 1, 6),
+       FACTOR(CLK_TOP_UNIVPLL1_D8, "univpll1_d8", "univpll_624m", 1, 8),
+       FACTOR(CLK_TOP_UNIVPLL1_D10, "univpll1_d10", "univpll_624m", 1, 10),
+
+       FACTOR(CLK_TOP_UNIVPLL2_D2, "univpll2_d2", "univpll_416m", 1, 2),
+       FACTOR(CLK_TOP_UNIVPLL2_D4, "univpll2_d4", "univpll_416m", 1, 4),
+       FACTOR(CLK_TOP_UNIVPLL2_D6, "univpll2_d6", "univpll_416m", 1, 6),
+       FACTOR(CLK_TOP_UNIVPLL2_D8, "univpll2_d8", "univpll_416m", 1, 8),
+
+       FACTOR(CLK_TOP_UNIVPLL_D3, "univpll_d3", "univpll_416m", 1, 1),
+       FACTOR(CLK_TOP_UNIVPLL_D5, "univpll_d5", "univpll_249p6m", 1, 1),
+       FACTOR(CLK_TOP_UNIVPLL_D7, "univpll_d7", "univpll_178p3m", 1, 1),
+       FACTOR(CLK_TOP_UNIVPLL_D10, "univpll_d10", "univpll_249p6m", 1, 2),
+       FACTOR(CLK_TOP_UNIVPLL_D26, "univpll_d26", "univpll_48m", 1, 1),
+
+       FACTOR(CLK_TOP_APLL, "apll_ck", "audpll", 1, 1),
+       FACTOR(CLK_TOP_APLL_D4, "apll_d4", "audpll", 1, 4),
+       FACTOR(CLK_TOP_APLL_D8, "apll_d8", "audpll", 1, 8),
+       FACTOR(CLK_TOP_APLL_D16, "apll_d16", "audpll", 1, 16),
+       FACTOR(CLK_TOP_APLL_D24, "apll_d24", "audpll", 1, 24),
+
+       FACTOR(CLK_TOP_LVDSPLL_D2, "lvdspll_d2", "lvdspll", 1, 2),
+       FACTOR(CLK_TOP_LVDSPLL_D4, "lvdspll_d4", "lvdspll", 1, 4),
+       FACTOR(CLK_TOP_LVDSPLL_D8, "lvdspll_d8", "lvdspll", 1, 8),
+
+       FACTOR(CLK_TOP_LVDSTX_CLKDIG_CT, "lvdstx_clkdig_cts", "lvdspll", 1, 1),
+       FACTOR(CLK_TOP_VPLL_DPIX, "vpll_dpix_ck", "lvdspll", 1, 1),
+
+       FACTOR(CLK_TOP_TVHDMI_H, "tvhdmi_h_ck", "tvdpll", 1, 1),
+
+       FACTOR(CLK_TOP_HDMITX_CLKDIG_D2, "hdmitx_clkdig_d2", "hdmitx_clkdig_cts", 1, 2),
+       FACTOR(CLK_TOP_HDMITX_CLKDIG_D3, "hdmitx_clkdig_d3", "hdmitx_clkdig_cts", 1, 3),
+
+       FACTOR(CLK_TOP_TVHDMI_D2, "tvhdmi_d2", "tvhdmi_h_ck", 1, 2),
+       FACTOR(CLK_TOP_TVHDMI_D4, "tvhdmi_d4", "tvhdmi_h_ck", 1, 4),
+
+       FACTOR(CLK_TOP_MEMPLL_MCK_D4, "mempll_mck_d4", "clkph_mck", 1, 4),
+};
+
+static const char * const axi_parents[] __initconst = {
+       "clk26m",
+       "syspll_d3",
+       "syspll_d4",
+       "syspll_d6",
+       "univpll_d5",
+       "univpll2_d2",
+       "syspll_d3p5"
+};
+
+static const char * const smi_parents[] __initconst = {
+       "clk26m",
+       "clkph_mck",
+       "syspll_d2p5",
+       "syspll_d3",
+       "syspll_d8",
+       "univpll_d5",
+       "univpll1_d2",
+       "univpll1_d6",
+       "mmpll_d3",
+       "mmpll_d4",
+       "mmpll_d5",
+       "mmpll_d6",
+       "mmpll_d7",
+       "vdecpll",
+       "lvdspll"
+};
+
+static const char * const mfg_parents[] __initconst = {
+       "clk26m",
+       "univpll1_d4",
+       "syspll_d2",
+       "syspll_d2p5",
+       "syspll_d3",
+       "univpll_d5",
+       "univpll1_d2",
+       "mmpll_d2",
+       "mmpll_d3",
+       "mmpll_d4",
+       "mmpll_d5",
+       "mmpll_d6",
+       "mmpll_d7"
+};
+
+static const char * const irda_parents[] __initconst = {
+       "clk26m",
+       "univpll2_d8",
+       "univpll1_d6"
+};
+
+static const char * const cam_parents[] __initconst = {
+       "clk26m",
+       "syspll_d3",
+       "syspll_d3p5",
+       "syspll_d4",
+       "univpll_d5",
+       "univpll2_d2",
+       "univpll_d7",
+       "univpll1_d4"
+};
+
+static const char * const aud_intbus_parents[] __initconst = {
+       "clk26m",
+       "syspll_d6",
+       "univpll_d10"
+};
+
+static const char * const jpg_parents[] __initconst = {
+       "clk26m",
+       "syspll_d5",
+       "syspll_d4",
+       "syspll_d3",
+       "univpll_d7",
+       "univpll2_d2",
+       "univpll_d5"
+};
+
+static const char * const disp_parents[] __initconst = {
+       "clk26m",
+       "syspll_d3p5",
+       "syspll_d3",
+       "univpll2_d2",
+       "univpll_d5",
+       "univpll1_d2",
+       "lvdspll",
+       "vdecpll"
+};
+
+static const char * const msdc30_parents[] __initconst = {
+       "clk26m",
+       "syspll_d6",
+       "syspll_d5",
+       "univpll1_d4",
+       "univpll2_d4",
+       "msdcpll"
+};
+
+static const char * const usb20_parents[] __initconst = {
+       "clk26m",
+       "univpll2_d6",
+       "univpll1_d10"
+};
+
+static const char * const venc_parents[] __initconst = {
+       "clk26m",
+       "syspll_d3",
+       "syspll_d8",
+       "univpll_d5",
+       "univpll1_d6",
+       "mmpll_d4",
+       "mmpll_d5",
+       "mmpll_d6"
+};
+
+static const char * const spi_parents[] __initconst = {
+       "clk26m",
+       "syspll_d6",
+       "syspll_d8",
+       "syspll_d10",
+       "univpll1_d6",
+       "univpll1_d8"
+};
+
+static const char * const uart_parents[] __initconst = {
+       "clk26m",
+       "univpll2_d8"
+};
+
+static const char * const mem_parents[] __initconst = {
+       "clk26m",
+       "clkph_mck"
+};
+
+static const char * const camtg_parents[] __initconst = {
+       "clk26m",
+       "univpll_d26",
+       "univpll1_d6",
+       "syspll_d16",
+       "syspll_d8"
+};
+
+static const char * const audio_parents[] __initconst = {
+       "clk26m",
+       "syspll_d24"
+};
+
+static const char * const fix_parents[] __initconst = {
+       "rtc32k",
+       "clk26m",
+       "univpll_d5",
+       "univpll_d7",
+       "univpll1_d2",
+       "univpll1_d4",
+       "univpll1_d6",
+       "univpll1_d8"
+};
+
+static const char * const vdec_parents[] __initconst = {
+       "clk26m",
+       "vdecpll",
+       "clkph_mck",
+       "syspll_d2p5",
+       "syspll_d3",
+       "syspll_d3p5",
+       "syspll_d4",
+       "syspll_d5",
+       "syspll_d6",
+       "syspll_d8",
+       "univpll1_d2",
+       "univpll2_d2",
+       "univpll_d7",
+       "univpll_d10",
+       "univpll2_d4",
+       "lvdspll"
+};
+
+static const char * const ddrphycfg_parents[] __initconst = {
+       "clk26m",
+       "axi_sel",
+       "syspll_d12"
+};
+
+static const char * const dpilvds_parents[] __initconst = {
+       "clk26m",
+       "lvdspll",
+       "lvdspll_d2",
+       "lvdspll_d4",
+       "lvdspll_d8"
+};
+
+static const char * const pmicspi_parents[] __initconst = {
+       "clk26m",
+       "univpll2_d6",
+       "syspll_d8",
+       "syspll_d10",
+       "univpll1_d10",
+       "mempll_mck_d4",
+       "univpll_d26",
+       "syspll_d24"
+};
+
+static const char * const smi_mfg_as_parents[] __initconst = {
+       "clk26m",
+       "smi_sel",
+       "mfg_sel",
+       "mem_sel"
+};
+
+static const char * const gcpu_parents[] __initconst = {
+       "clk26m",
+       "syspll_d4",
+       "univpll_d7",
+       "syspll_d5",
+       "syspll_d6"
+};
+
+static const char * const dpi1_parents[] __initconst = {
+       "clk26m",
+       "tvhdmi_h_ck",
+       "tvhdmi_d2",
+       "tvhdmi_d4"
+};
+
+static const char * const cci_parents[] __initconst = {
+       "clk26m",
+       "mainpll_537p3m",
+       "univpll_d3",
+       "syspll_d2p5",
+       "syspll_d3",
+       "syspll_d5"
+};
+
+static const char * const apll_parents[] __initconst = {
+       "clk26m",
+       "apll_ck",
+       "apll_d4",
+       "apll_d8",
+       "apll_d16",
+       "apll_d24"
+};
+
+static const char * const hdmipll_parents[] __initconst = {
+       "clk26m",
+       "hdmitx_clkdig_cts",
+       "hdmitx_clkdig_d2",
+       "hdmitx_clkdig_d3"
+};
+
+static const struct mtk_composite top_muxes[] __initconst = {
+       /* CLK_CFG_0 */
+       MUX_GATE(CLK_TOP_AXI_SEL, "axi_sel", axi_parents,
+               0x0140, 0, 3, INVALID_MUX_GATE_BIT),
+       MUX_GATE(CLK_TOP_SMI_SEL, "smi_sel", smi_parents, 0x0140, 8, 4, 15),
+       MUX_GATE(CLK_TOP_MFG_SEL, "mfg_sel", mfg_parents, 0x0140, 16, 4, 23),
+       MUX_GATE(CLK_TOP_IRDA_SEL, "irda_sel", irda_parents, 0x0140, 24, 2, 31),
+       /* CLK_CFG_1 */
+       MUX_GATE(CLK_TOP_CAM_SEL, "cam_sel", cam_parents, 0x0144, 0, 3, 7),
+       MUX_GATE(CLK_TOP_AUD_INTBUS_SEL, "aud_intbus_sel", aud_intbus_parents,
+               0x0144, 8, 2, 15),
+       MUX_GATE(CLK_TOP_JPG_SEL, "jpg_sel", jpg_parents, 0x0144, 16, 3, 23),
+       MUX_GATE(CLK_TOP_DISP_SEL, "disp_sel", disp_parents, 0x0144, 24, 3, 31),
+       /* CLK_CFG_2 */
+       MUX_GATE(CLK_TOP_MSDC30_1_SEL, "msdc30_1_sel", msdc30_parents, 0x0148, 0, 3, 7),
+       MUX_GATE(CLK_TOP_MSDC30_2_SEL, "msdc30_2_sel", msdc30_parents, 0x0148, 8, 3, 15),
+       MUX_GATE(CLK_TOP_MSDC30_3_SEL, "msdc30_3_sel", msdc30_parents, 0x0148, 16, 3, 23),
+       MUX_GATE(CLK_TOP_MSDC30_4_SEL, "msdc30_4_sel", msdc30_parents, 0x0148, 24, 3, 31),
+       /* CLK_CFG_3 */
+       MUX_GATE(CLK_TOP_USB20_SEL, "usb20_sel", usb20_parents, 0x014c, 0, 2, 7),
+       /* CLK_CFG_4 */
+       MUX_GATE(CLK_TOP_VENC_SEL, "venc_sel", venc_parents, 0x0150, 8, 3, 15),
+       MUX_GATE(CLK_TOP_SPI_SEL, "spi_sel", spi_parents, 0x0150, 16, 3, 23),
+       MUX_GATE(CLK_TOP_UART_SEL, "uart_sel", uart_parents, 0x0150, 24, 2, 31),
+       /* CLK_CFG_6 */
+       MUX_GATE(CLK_TOP_MEM_SEL, "mem_sel", mem_parents, 0x0158, 0, 2, 7),
+       MUX_GATE(CLK_TOP_CAMTG_SEL, "camtg_sel", camtg_parents, 0x0158, 8, 3, 15),
+       MUX_GATE(CLK_TOP_AUDIO_SEL, "audio_sel", audio_parents, 0x0158, 24, 2, 31),
+       /* CLK_CFG_7 */
+       MUX_GATE(CLK_TOP_FIX_SEL, "fix_sel", fix_parents, 0x015c, 0, 3, 7),
+       MUX_GATE(CLK_TOP_VDEC_SEL, "vdec_sel", vdec_parents, 0x015c, 8, 4, 15),
+       MUX_GATE(CLK_TOP_DDRPHYCFG_SEL, "ddrphycfg_sel", ddrphycfg_parents,
+               0x015c, 16, 2, 23),
+       MUX_GATE(CLK_TOP_DPILVDS_SEL, "dpilvds_sel", dpilvds_parents, 0x015c, 24, 3, 31),
+       /* CLK_CFG_8 */
+       MUX_GATE(CLK_TOP_PMICSPI_SEL, "pmicspi_sel", pmicspi_parents, 0x0164, 0, 3, 7),
+       MUX_GATE(CLK_TOP_MSDC30_0_SEL, "msdc30_0_sel", msdc30_parents, 0x0164, 8, 3, 15),
+       MUX_GATE(CLK_TOP_SMI_MFG_AS_SEL, "smi_mfg_as_sel", smi_mfg_as_parents,
+               0x0164, 16, 2, 23),
+       MUX_GATE(CLK_TOP_GCPU_SEL, "gcpu_sel", gcpu_parents, 0x0164, 24, 3, 31),
+       /* CLK_CFG_9 */
+       MUX_GATE(CLK_TOP_DPI1_SEL, "dpi1_sel", dpi1_parents, 0x0168, 0, 2, 7),
+       MUX_GATE(CLK_TOP_CCI_SEL, "cci_sel", cci_parents, 0x0168, 8, 3, 15),
+       MUX_GATE(CLK_TOP_APLL_SEL, "apll_sel", apll_parents, 0x0168, 16, 3, 23),
+       MUX_GATE(CLK_TOP_HDMIPLL_SEL, "hdmipll_sel", hdmipll_parents, 0x0168, 24, 2, 31),
+};
+
+static const struct mtk_gate_regs infra_cg_regs = {
+       .set_ofs = 0x0040,
+       .clr_ofs = 0x0044,
+       .sta_ofs = 0x0048,
+};
+
+#define GATE_ICG(_id, _name, _parent, _shift) {        \
+               .id = _id,                                      \
+               .name = _name,                                  \
+               .parent_name = _parent,                         \
+               .regs = &infra_cg_regs,                         \
+               .shift = _shift,                                \
+               .ops = &mtk_clk_gate_ops_setclr,                \
+       }
+
+static const struct mtk_gate infra_clks[] __initconst = {
+       GATE_ICG(CLK_INFRA_PMIC_WRAP, "pmic_wrap_ck", "axi_sel", 23),
+       GATE_ICG(CLK_INFRA_PMICSPI, "pmicspi_ck", "pmicspi_sel", 22),
+       GATE_ICG(CLK_INFRA_CCIF1_AP_CTRL, "ccif1_ap_ctrl", "axi_sel", 21),
+       GATE_ICG(CLK_INFRA_CCIF0_AP_CTRL, "ccif0_ap_ctrl", "axi_sel", 20),
+       GATE_ICG(CLK_INFRA_KP, "kp_ck", "axi_sel", 16),
+       GATE_ICG(CLK_INFRA_CPUM, "cpum_ck", "cpum_tck_in", 15),
+       GATE_ICG(CLK_INFRA_M4U, "m4u_ck", "mem_sel", 8),
+       GATE_ICG(CLK_INFRA_MFGAXI, "mfgaxi_ck", "axi_sel", 7),
+       GATE_ICG(CLK_INFRA_DEVAPC, "devapc_ck", "axi_sel", 6),
+       GATE_ICG(CLK_INFRA_AUDIO, "audio_ck", "aud_intbus_sel", 5),
+       GATE_ICG(CLK_INFRA_MFG_BUS, "mfg_bus_ck", "axi_sel", 2),
+       GATE_ICG(CLK_INFRA_SMI, "smi_ck", "smi_sel", 1),
+       GATE_ICG(CLK_INFRA_DBGCLK, "dbgclk_ck", "axi_sel", 0),
+};
+
+static const struct mtk_gate_regs peri0_cg_regs = {
+       .set_ofs = 0x0008,
+       .clr_ofs = 0x0010,
+       .sta_ofs = 0x0018,
+};
+
+static const struct mtk_gate_regs peri1_cg_regs = {
+       .set_ofs = 0x000c,
+       .clr_ofs = 0x0014,
+       .sta_ofs = 0x001c,
+};
+
+#define GATE_PERI0(_id, _name, _parent, _shift) {      \
+               .id = _id,                                      \
+               .name = _name,                                  \
+               .parent_name = _parent,                         \
+               .regs = &peri0_cg_regs,                         \
+               .shift = _shift,                                \
+               .ops = &mtk_clk_gate_ops_setclr,                \
+       }
+
+#define GATE_PERI1(_id, _name, _parent, _shift) {      \
+               .id = _id,                                      \
+               .name = _name,                                  \
+               .parent_name = _parent,                         \
+               .regs = &peri1_cg_regs,                         \
+               .shift = _shift,                                \
+               .ops = &mtk_clk_gate_ops_setclr,                \
+       }
+
+static const struct mtk_gate peri_gates[] __initconst = {
+       /* PERI0 */
+       GATE_PERI0(CLK_PERI_I2C5, "i2c5_ck", "axi_sel", 31),
+       GATE_PERI0(CLK_PERI_I2C4, "i2c4_ck", "axi_sel", 30),
+       GATE_PERI0(CLK_PERI_I2C3, "i2c3_ck", "axi_sel", 29),
+       GATE_PERI0(CLK_PERI_I2C2, "i2c2_ck", "axi_sel", 28),
+       GATE_PERI0(CLK_PERI_I2C1, "i2c1_ck", "axi_sel", 27),
+       GATE_PERI0(CLK_PERI_I2C0, "i2c0_ck", "axi_sel", 26),
+       GATE_PERI0(CLK_PERI_UART3, "uart3_ck", "axi_sel", 25),
+       GATE_PERI0(CLK_PERI_UART2, "uart2_ck", "axi_sel", 24),
+       GATE_PERI0(CLK_PERI_UART1, "uart1_ck", "axi_sel", 23),
+       GATE_PERI0(CLK_PERI_UART0, "uart0_ck", "axi_sel", 22),
+       GATE_PERI0(CLK_PERI_IRDA, "irda_ck", "irda_sel", 21),
+       GATE_PERI0(CLK_PERI_NLI, "nli_ck", "axi_sel", 20),
+       GATE_PERI0(CLK_PERI_MD_HIF, "md_hif_ck", "axi_sel", 19),
+       GATE_PERI0(CLK_PERI_AP_HIF, "ap_hif_ck", "axi_sel", 18),
+       GATE_PERI0(CLK_PERI_MSDC30_3, "msdc30_3_ck", "msdc30_4_sel", 17),
+       GATE_PERI0(CLK_PERI_MSDC30_2, "msdc30_2_ck", "msdc30_3_sel", 16),
+       GATE_PERI0(CLK_PERI_MSDC30_1, "msdc30_1_ck", "msdc30_2_sel", 15),
+       GATE_PERI0(CLK_PERI_MSDC20_2, "msdc20_2_ck", "msdc30_1_sel", 14),
+       GATE_PERI0(CLK_PERI_MSDC20_1, "msdc20_1_ck", "msdc30_0_sel", 13),
+       GATE_PERI0(CLK_PERI_AP_DMA, "ap_dma_ck", "axi_sel", 12),
+       GATE_PERI0(CLK_PERI_USB1, "usb1_ck", "usb20_sel", 11),
+       GATE_PERI0(CLK_PERI_USB0, "usb0_ck", "usb20_sel", 10),
+       GATE_PERI0(CLK_PERI_PWM, "pwm_ck", "axi_sel", 9),
+       GATE_PERI0(CLK_PERI_PWM7, "pwm7_ck", "axi_sel", 8),
+       GATE_PERI0(CLK_PERI_PWM6, "pwm6_ck", "axi_sel", 7),
+       GATE_PERI0(CLK_PERI_PWM5, "pwm5_ck", "axi_sel", 6),
+       GATE_PERI0(CLK_PERI_PWM4, "pwm4_ck", "axi_sel", 5),
+       GATE_PERI0(CLK_PERI_PWM3, "pwm3_ck", "axi_sel", 4),
+       GATE_PERI0(CLK_PERI_PWM2, "pwm2_ck", "axi_sel", 3),
+       GATE_PERI0(CLK_PERI_PWM1, "pwm1_ck", "axi_sel", 2),
+       GATE_PERI0(CLK_PERI_THERM, "therm_ck", "axi_sel", 1),
+       GATE_PERI0(CLK_PERI_NFI, "nfi_ck", "axi_sel", 0),
+       /* PERI1 */
+       GATE_PERI1(CLK_PERI_USBSLV, "usbslv_ck", "axi_sel", 8),
+       GATE_PERI1(CLK_PERI_USB1_MCU, "usb1_mcu_ck", "axi_sel", 7),
+       GATE_PERI1(CLK_PERI_USB0_MCU, "usb0_mcu_ck", "axi_sel", 6),
+       GATE_PERI1(CLK_PERI_GCPU, "gcpu_ck", "gcpu_sel", 5),
+       GATE_PERI1(CLK_PERI_FHCTL, "fhctl_ck", "clk26m", 4),
+       GATE_PERI1(CLK_PERI_SPI1, "spi1_ck", "spi_sel", 3),
+       GATE_PERI1(CLK_PERI_AUXADC, "auxadc_ck", "clk26m", 2),
+       GATE_PERI1(CLK_PERI_PERI_PWRAP, "peri_pwrap_ck", "axi_sel", 1),
+       GATE_PERI1(CLK_PERI_I2C6, "i2c6_ck", "axi_sel", 0),
+};
+
+static const char * const uart_ck_sel_parents[] __initconst = {
+       "clk26m",
+       "uart_sel",
+};
+
+static const struct mtk_composite peri_clks[] __initconst = {
+       MUX(CLK_PERI_UART0_SEL, "uart0_ck_sel", uart_ck_sel_parents, 0x40c, 0, 1),
+       MUX(CLK_PERI_UART1_SEL, "uart1_ck_sel", uart_ck_sel_parents, 0x40c, 1, 1),
+       MUX(CLK_PERI_UART2_SEL, "uart2_ck_sel", uart_ck_sel_parents, 0x40c, 2, 1),
+       MUX(CLK_PERI_UART3_SEL, "uart3_ck_sel", uart_ck_sel_parents, 0x40c, 3, 1),
+};
+
+static void __init mtk_topckgen_init(struct device_node *node)
+{
+       struct clk_onecell_data *clk_data;
+       void __iomem *base;
+       int r;
+
+       base = of_iomap(node, 0);
+       if (!base) {
+               pr_err("%s(): ioremap failed\n", __func__);
+               return;
+       }
+
+       clk_data = mtk_alloc_clk_data(CLK_TOP_NR_CLK);
+
+       mtk_clk_register_factors(root_clk_alias, ARRAY_SIZE(root_clk_alias), clk_data);
+       mtk_clk_register_factors(top_divs, ARRAY_SIZE(top_divs), clk_data);
+       mtk_clk_register_composites(top_muxes, ARRAY_SIZE(top_muxes), base,
+                       &mt8135_clk_lock, clk_data);
+
+       clk_prepare_enable(clk_data->clks[CLK_TOP_CCI_SEL]);
+
+       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_topckgen, "mediatek,mt8135-topckgen", mtk_topckgen_init);
+
+static void __init mtk_infrasys_init(struct device_node *node)
+{
+       struct clk_onecell_data *clk_data;
+       int r;
+
+       clk_data = mtk_alloc_clk_data(CLK_INFRA_NR_CLK);
+
+       mtk_clk_register_gates(node, infra_clks, ARRAY_SIZE(infra_clks),
+                                               clk_data);
+
+       clk_prepare_enable(clk_data->clks[CLK_INFRA_M4U]);
+
+       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);
+
+       mtk_register_reset_controller(node, 2, 0x30);
+}
+CLK_OF_DECLARE(mtk_infrasys, "mediatek,mt8135-infracfg", mtk_infrasys_init);
+
+static void __init mtk_pericfg_init(struct device_node *node)
+{
+       struct clk_onecell_data *clk_data;
+       int r;
+       void __iomem *base;
+
+       base = of_iomap(node, 0);
+       if (!base) {
+               pr_err("%s(): ioremap failed\n", __func__);
+               return;
+       }
+
+       clk_data = mtk_alloc_clk_data(CLK_PERI_NR_CLK);
+
+       mtk_clk_register_gates(node, peri_gates, ARRAY_SIZE(peri_gates),
+                                               clk_data);
+       mtk_clk_register_composites(peri_clks, ARRAY_SIZE(peri_clks), base,
+                       &mt8135_clk_lock, 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);
+
+       mtk_register_reset_controller(node, 2, 0);
+}
+CLK_OF_DECLARE(mtk_pericfg, "mediatek,mt8135-pericfg", mtk_pericfg_init);
+
+#define MT8135_PLL_FMAX                (2000 * MHZ)
+#define CON0_MT8135_RST_BAR    BIT(27)
+
+#define PLL(_id, _name, _reg, _pwr_reg, _en_mask, _flags, _pcwbits, _pd_reg, _pd_shift, _tuner_reg, _pcw_reg, _pcw_shift) { \
+               .id = _id,                                              \
+               .name = _name,                                          \
+               .reg = _reg,                                            \
+               .pwr_reg = _pwr_reg,                                    \
+               .en_mask = _en_mask,                                    \
+               .flags = _flags,                                        \
+               .rst_bar_mask = CON0_MT8135_RST_BAR,                    \
+               .fmax = MT8135_PLL_FMAX,                                \
+               .pcwbits = _pcwbits,                                    \
+               .pd_reg = _pd_reg,                                      \
+               .pd_shift = _pd_shift,                                  \
+               .tuner_reg = _tuner_reg,                                \
+               .pcw_reg = _pcw_reg,                                    \
+               .pcw_shift = _pcw_shift,                                \
+       }
+
+static const struct mtk_pll_data plls[] = {
+       PLL(CLK_APMIXED_ARMPLL1, "armpll1", 0x200, 0x218, 0x80000001, 0, 21, 0x204, 24, 0x0, 0x204, 0),
+       PLL(CLK_APMIXED_ARMPLL2, "armpll2", 0x2cc, 0x2e4, 0x80000001, 0, 21, 0x2d0, 24, 0x0, 0x2d0, 0),
+       PLL(CLK_APMIXED_MAINPLL, "mainpll", 0x21c, 0x234, 0xf0000001, HAVE_RST_BAR, 21, 0x21c, 6, 0x0, 0x220, 0),
+       PLL(CLK_APMIXED_UNIVPLL, "univpll", 0x238, 0x250, 0xf3000001, HAVE_RST_BAR, 7, 0x238, 6, 0x0, 0x238, 9),
+       PLL(CLK_APMIXED_MMPLL, "mmpll", 0x254, 0x26c, 0xf0000001, HAVE_RST_BAR, 21, 0x254, 6, 0x0, 0x258, 0),
+       PLL(CLK_APMIXED_MSDCPLL, "msdcpll", 0x278, 0x290, 0x80000001, 0, 21, 0x278, 6, 0x0, 0x27c, 0),
+       PLL(CLK_APMIXED_TVDPLL, "tvdpll", 0x294, 0x2ac, 0x80000001, 0, 31, 0x294, 6, 0x0, 0x298, 0),
+       PLL(CLK_APMIXED_LVDSPLL, "lvdspll", 0x2b0, 0x2c8,       0x80000001, 0, 21, 0x2b0, 6, 0x0, 0x2b4, 0),
+       PLL(CLK_APMIXED_AUDPLL, "audpll", 0x2e8, 0x300, 0x80000001, 0, 31, 0x2e8, 6, 0x2f8, 0x2ec, 0),
+       PLL(CLK_APMIXED_VDECPLL, "vdecpll", 0x304, 0x31c,       0x80000001, 0, 21, 0x2b0, 6, 0x0, 0x308, 0),
+};
+
+static void __init mtk_apmixedsys_init(struct device_node *node)
+{
+       struct clk_onecell_data *clk_data;
+
+       clk_data = mtk_alloc_clk_data(CLK_APMIXED_NR_CLK);
+       if (!clk_data)
+               return;
+
+       mtk_clk_register_plls(node, plls, ARRAY_SIZE(plls), clk_data);
+}
+CLK_OF_DECLARE(mtk_apmixedsys, "mediatek,mt8135-apmixedsys",
+               mtk_apmixedsys_init);
diff --git a/drivers/clk/mediatek/clk-mt8173.c b/drivers/clk/mediatek/clk-mt8173.c
new file mode 100644 (file)
index 0000000..4b9e04c
--- /dev/null
@@ -0,0 +1,830 @@
+/*
+ * Copyright (c) 2014 MediaTek Inc.
+ * Author: James Liao <jamesjj.liao@mediatek.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/of.h>
+#include <linux/of_address.h>
+#include <linux/slab.h>
+#include <linux/mfd/syscon.h>
+
+#include "clk-mtk.h"
+#include "clk-gate.h"
+
+#include <dt-bindings/clock/mt8173-clk.h>
+
+static DEFINE_SPINLOCK(mt8173_clk_lock);
+
+static const struct mtk_fixed_factor root_clk_alias[] __initconst = {
+       FACTOR(CLK_TOP_CLKPH_MCK_O, "clkph_mck_o", "clk_null", 1, 1),
+       FACTOR(CLK_TOP_DPI, "dpi_ck", "clk_null", 1, 1),
+       FACTOR(CLK_TOP_USB_SYSPLL_125M, "usb_syspll_125m", "clk_null", 1, 1),
+       FACTOR(CLK_TOP_HDMITX_DIG_CTS, "hdmitx_dig_cts", "clk_null", 1, 1),
+};
+
+static const struct mtk_fixed_factor top_divs[] __initconst = {
+       FACTOR(CLK_TOP_ARMCA7PLL_754M, "armca7pll_754m", "armca7pll", 1, 2),
+       FACTOR(CLK_TOP_ARMCA7PLL_502M, "armca7pll_502m", "armca7pll", 1, 3),
+
+       FACTOR(CLK_TOP_MAIN_H546M, "main_h546m", "mainpll", 1, 2),
+       FACTOR(CLK_TOP_MAIN_H364M, "main_h364m", "mainpll", 1, 3),
+       FACTOR(CLK_TOP_MAIN_H218P4M, "main_h218p4m", "mainpll", 1, 5),
+       FACTOR(CLK_TOP_MAIN_H156M, "main_h156m", "mainpll", 1, 7),
+
+       FACTOR(CLK_TOP_TVDPLL_445P5M, "tvdpll_445p5m", "tvdpll", 1, 4),
+       FACTOR(CLK_TOP_TVDPLL_594M, "tvdpll_594m", "tvdpll", 1, 3),
+
+       FACTOR(CLK_TOP_UNIV_624M, "univ_624m", "univpll", 1, 2),
+       FACTOR(CLK_TOP_UNIV_416M, "univ_416m", "univpll", 1, 3),
+       FACTOR(CLK_TOP_UNIV_249P6M, "univ_249p6m", "univpll", 1, 5),
+       FACTOR(CLK_TOP_UNIV_178P3M, "univ_178p3m", "univpll", 1, 7),
+       FACTOR(CLK_TOP_UNIV_48M, "univ_48m", "univpll", 1, 26),
+
+       FACTOR(CLK_TOP_CLKRTC_EXT, "clkrtc_ext", "clk32k", 1, 1),
+       FACTOR(CLK_TOP_CLKRTC_INT, "clkrtc_int", "clk26m", 1, 793),
+       FACTOR(CLK_TOP_FPC, "fpc_ck", "clk26m", 1, 1),
+
+       FACTOR(CLK_TOP_HDMITXPLL_D2, "hdmitxpll_d2", "hdmitx_dig_cts", 1, 2),
+       FACTOR(CLK_TOP_HDMITXPLL_D3, "hdmitxpll_d3", "hdmitx_dig_cts", 1, 3),
+
+       FACTOR(CLK_TOP_ARMCA7PLL_D2, "armca7pll_d2", "armca7pll_754m", 1, 1),
+       FACTOR(CLK_TOP_ARMCA7PLL_D3, "armca7pll_d3", "armca7pll_502m", 1, 1),
+
+       FACTOR(CLK_TOP_APLL1, "apll1_ck", "apll1", 1, 1),
+       FACTOR(CLK_TOP_APLL2, "apll2_ck", "apll2", 1, 1),
+
+       FACTOR(CLK_TOP_DMPLL, "dmpll_ck", "clkph_mck_o", 1, 1),
+       FACTOR(CLK_TOP_DMPLL_D2, "dmpll_d2", "clkph_mck_o", 1, 2),
+       FACTOR(CLK_TOP_DMPLL_D4, "dmpll_d4", "clkph_mck_o", 1, 4),
+       FACTOR(CLK_TOP_DMPLL_D8, "dmpll_d8", "clkph_mck_o", 1, 8),
+       FACTOR(CLK_TOP_DMPLL_D16, "dmpll_d16", "clkph_mck_o", 1, 16),
+
+       FACTOR(CLK_TOP_LVDSPLL_D2, "lvdspll_d2", "lvdspll", 1, 2),
+       FACTOR(CLK_TOP_LVDSPLL_D4, "lvdspll_d4", "lvdspll", 1, 4),
+       FACTOR(CLK_TOP_LVDSPLL_D8, "lvdspll_d8", "lvdspll", 1, 8),
+
+       FACTOR(CLK_TOP_MMPLL, "mmpll_ck", "mmpll", 1, 1),
+       FACTOR(CLK_TOP_MMPLL_D2, "mmpll_d2", "mmpll", 1, 2),
+
+       FACTOR(CLK_TOP_MSDCPLL, "msdcpll_ck", "msdcpll", 1, 1),
+       FACTOR(CLK_TOP_MSDCPLL_D2, "msdcpll_d2", "msdcpll", 1, 2),
+       FACTOR(CLK_TOP_MSDCPLL_D4, "msdcpll_d4", "msdcpll", 1, 4),
+       FACTOR(CLK_TOP_MSDCPLL2, "msdcpll2_ck", "msdcpll2", 1, 1),
+       FACTOR(CLK_TOP_MSDCPLL2_D2, "msdcpll2_d2", "msdcpll2", 1, 2),
+       FACTOR(CLK_TOP_MSDCPLL2_D4, "msdcpll2_d4", "msdcpll2", 1, 4),
+
+       FACTOR(CLK_TOP_SYSPLL_D2, "syspll_d2", "main_h546m", 1, 1),
+       FACTOR(CLK_TOP_SYSPLL1_D2, "syspll1_d2", "main_h546m", 1, 2),
+       FACTOR(CLK_TOP_SYSPLL1_D4, "syspll1_d4", "main_h546m", 1, 4),
+       FACTOR(CLK_TOP_SYSPLL1_D8, "syspll1_d8", "main_h546m", 1, 8),
+       FACTOR(CLK_TOP_SYSPLL1_D16, "syspll1_d16", "main_h546m", 1, 16),
+       FACTOR(CLK_TOP_SYSPLL_D3, "syspll_d3", "main_h364m", 1, 1),
+       FACTOR(CLK_TOP_SYSPLL2_D2, "syspll2_d2", "main_h364m", 1, 2),
+       FACTOR(CLK_TOP_SYSPLL2_D4, "syspll2_d4", "main_h364m", 1, 4),
+       FACTOR(CLK_TOP_SYSPLL_D5, "syspll_d5", "main_h218p4m", 1, 1),
+       FACTOR(CLK_TOP_SYSPLL3_D2, "syspll3_d2", "main_h218p4m", 1, 2),
+       FACTOR(CLK_TOP_SYSPLL3_D4, "syspll3_d4", "main_h218p4m", 1, 4),
+       FACTOR(CLK_TOP_SYSPLL_D7, "syspll_d7", "main_h156m", 1, 1),
+       FACTOR(CLK_TOP_SYSPLL4_D2, "syspll4_d2", "main_h156m", 1, 2),
+       FACTOR(CLK_TOP_SYSPLL4_D4, "syspll4_d4", "main_h156m", 1, 4),
+
+       FACTOR(CLK_TOP_TVDPLL, "tvdpll_ck", "tvdpll_594m", 1, 1),
+       FACTOR(CLK_TOP_TVDPLL_D2, "tvdpll_d2", "tvdpll_594m", 1, 2),
+       FACTOR(CLK_TOP_TVDPLL_D4, "tvdpll_d4", "tvdpll_594m", 1, 4),
+       FACTOR(CLK_TOP_TVDPLL_D8, "tvdpll_d8", "tvdpll_594m", 1, 8),
+       FACTOR(CLK_TOP_TVDPLL_D16, "tvdpll_d16", "tvdpll_594m", 1, 16),
+
+       FACTOR(CLK_TOP_UNIVPLL_D2, "univpll_d2", "univ_624m", 1, 1),
+       FACTOR(CLK_TOP_UNIVPLL1_D2, "univpll1_d2", "univ_624m", 1, 2),
+       FACTOR(CLK_TOP_UNIVPLL1_D4, "univpll1_d4", "univ_624m", 1, 4),
+       FACTOR(CLK_TOP_UNIVPLL1_D8, "univpll1_d8", "univ_624m", 1, 8),
+       FACTOR(CLK_TOP_UNIVPLL_D3, "univpll_d3", "univ_416m", 1, 1),
+       FACTOR(CLK_TOP_UNIVPLL2_D2, "univpll2_d2", "univ_416m", 1, 2),
+       FACTOR(CLK_TOP_UNIVPLL2_D4, "univpll2_d4", "univ_416m", 1, 4),
+       FACTOR(CLK_TOP_UNIVPLL2_D8, "univpll2_d8", "univ_416m", 1, 8),
+       FACTOR(CLK_TOP_UNIVPLL_D5, "univpll_d5", "univ_249p6m", 1, 1),
+       FACTOR(CLK_TOP_UNIVPLL3_D2, "univpll3_d2", "univ_249p6m", 1, 2),
+       FACTOR(CLK_TOP_UNIVPLL3_D4, "univpll3_d4", "univ_249p6m", 1, 4),
+       FACTOR(CLK_TOP_UNIVPLL3_D8, "univpll3_d8", "univ_249p6m", 1, 8),
+       FACTOR(CLK_TOP_UNIVPLL_D7, "univpll_d7", "univ_178p3m", 1, 1),
+       FACTOR(CLK_TOP_UNIVPLL_D26, "univpll_d26", "univ_48m", 1, 1),
+       FACTOR(CLK_TOP_UNIVPLL_D52, "univpll_d52", "univ_48m", 1, 2),
+
+       FACTOR(CLK_TOP_VCODECPLL, "vcodecpll_ck", "vcodecpll", 1, 3),
+       FACTOR(CLK_TOP_VCODECPLL_370P5, "vcodecpll_370p5", "vcodecpll", 1, 4),
+
+       FACTOR(CLK_TOP_VENCPLL, "vencpll_ck", "vencpll", 1, 1),
+       FACTOR(CLK_TOP_VENCPLL_D2, "vencpll_d2", "vencpll", 1, 2),
+       FACTOR(CLK_TOP_VENCPLL_D4, "vencpll_d4", "vencpll", 1, 4),
+};
+
+static const char * const axi_parents[] __initconst = {
+       "clk26m",
+       "syspll1_d2",
+       "syspll_d5",
+       "syspll1_d4",
+       "univpll_d5",
+       "univpll2_d2",
+       "dmpll_d2",
+       "dmpll_d4"
+};
+
+static const char * const mem_parents[] __initconst = {
+       "clk26m",
+       "dmpll_ck"
+};
+
+static const char * const ddrphycfg_parents[] __initconst = {
+       "clk26m",
+       "syspll1_d8"
+};
+
+static const char * const mm_parents[] __initconst = {
+       "clk26m",
+       "vencpll_d2",
+       "main_h364m",
+       "syspll1_d2",
+       "syspll_d5",
+       "syspll1_d4",
+       "univpll1_d2",
+       "univpll2_d2",
+       "dmpll_d2"
+};
+
+static const char * const pwm_parents[] __initconst = {
+       "clk26m",
+       "univpll2_d4",
+       "univpll3_d2",
+       "univpll1_d4"
+};
+
+static const char * const vdec_parents[] __initconst = {
+       "clk26m",
+       "vcodecpll_ck",
+       "tvdpll_445p5m",
+       "univpll_d3",
+       "vencpll_d2",
+       "syspll_d3",
+       "univpll1_d2",
+       "mmpll_d2",
+       "dmpll_d2",
+       "dmpll_d4"
+};
+
+static const char * const venc_parents[] __initconst = {
+       "clk26m",
+       "vcodecpll_ck",
+       "tvdpll_445p5m",
+       "univpll_d3",
+       "vencpll_d2",
+       "syspll_d3",
+       "univpll1_d2",
+       "univpll2_d2",
+       "dmpll_d2",
+       "dmpll_d4"
+};
+
+static const char * const mfg_parents[] __initconst = {
+       "clk26m",
+       "mmpll_ck",
+       "dmpll_ck",
+       "clk26m",
+       "clk26m",
+       "clk26m",
+       "clk26m",
+       "clk26m",
+       "clk26m",
+       "syspll_d3",
+       "syspll1_d2",
+       "syspll_d5",
+       "univpll_d3",
+       "univpll1_d2",
+       "univpll_d5",
+       "univpll2_d2"
+};
+
+static const char * const camtg_parents[] __initconst = {
+       "clk26m",
+       "univpll_d26",
+       "univpll2_d2",
+       "syspll3_d2",
+       "syspll3_d4",
+       "univpll1_d4"
+};
+
+static const char * const uart_parents[] __initconst = {
+       "clk26m",
+       "univpll2_d8"
+};
+
+static const char * const spi_parents[] __initconst = {
+       "clk26m",
+       "syspll3_d2",
+       "syspll1_d4",
+       "syspll4_d2",
+       "univpll3_d2",
+       "univpll2_d4",
+       "univpll1_d8"
+};
+
+static const char * const usb20_parents[] __initconst = {
+       "clk26m",
+       "univpll1_d8",
+       "univpll3_d4"
+};
+
+static const char * const usb30_parents[] __initconst = {
+       "clk26m",
+       "univpll3_d2",
+       "usb_syspll_125m",
+       "univpll2_d4"
+};
+
+static const char * const msdc50_0_h_parents[] __initconst = {
+       "clk26m",
+       "syspll1_d2",
+       "syspll2_d2",
+       "syspll4_d2",
+       "univpll_d5",
+       "univpll1_d4"
+};
+
+static const char * const msdc50_0_parents[] __initconst = {
+       "clk26m",
+       "msdcpll_ck",
+       "msdcpll_d2",
+       "univpll1_d4",
+       "syspll2_d2",
+       "syspll_d7",
+       "msdcpll_d4",
+       "vencpll_d4",
+       "tvdpll_ck",
+       "univpll_d2",
+       "univpll1_d2",
+       "mmpll_ck",
+       "msdcpll2_ck",
+       "msdcpll2_d2",
+       "msdcpll2_d4"
+};
+
+static const char * const msdc30_1_parents[] __initconst = {
+       "clk26m",
+       "univpll2_d2",
+       "msdcpll_d4",
+       "univpll1_d4",
+       "syspll2_d2",
+       "syspll_d7",
+       "univpll_d7",
+       "vencpll_d4"
+};
+
+static const char * const msdc30_2_parents[] __initconst = {
+       "clk26m",
+       "univpll2_d2",
+       "msdcpll_d4",
+       "univpll1_d4",
+       "syspll2_d2",
+       "syspll_d7",
+       "univpll_d7",
+       "vencpll_d2"
+};
+
+static const char * const msdc30_3_parents[] __initconst = {
+       "clk26m",
+       "msdcpll2_ck",
+       "msdcpll2_d2",
+       "univpll2_d2",
+       "msdcpll2_d4",
+       "msdcpll_d4",
+       "univpll1_d4",
+       "syspll2_d2",
+       "syspll_d7",
+       "univpll_d7",
+       "vencpll_d4",
+       "msdcpll_ck",
+       "msdcpll_d2",
+       "msdcpll_d4"
+};
+
+static const char * const audio_parents[] __initconst = {
+       "clk26m",
+       "syspll3_d4",
+       "syspll4_d4",
+       "syspll1_d16"
+};
+
+static const char * const aud_intbus_parents[] __initconst = {
+       "clk26m",
+       "syspll1_d4",
+       "syspll4_d2",
+       "univpll3_d2",
+       "univpll2_d8",
+       "dmpll_d4",
+       "dmpll_d8"
+};
+
+static const char * const pmicspi_parents[] __initconst = {
+       "clk26m",
+       "syspll1_d8",
+       "syspll3_d4",
+       "syspll1_d16",
+       "univpll3_d4",
+       "univpll_d26",
+       "dmpll_d8",
+       "dmpll_d16"
+};
+
+static const char * const scp_parents[] __initconst = {
+       "clk26m",
+       "syspll1_d2",
+       "univpll_d5",
+       "syspll_d5",
+       "dmpll_d2",
+       "dmpll_d4"
+};
+
+static const char * const atb_parents[] __initconst = {
+       "clk26m",
+       "syspll1_d2",
+       "univpll_d5",
+       "dmpll_d2"
+};
+
+static const char * const venc_lt_parents[] __initconst = {
+       "clk26m",
+       "univpll_d3",
+       "vcodecpll_ck",
+       "tvdpll_445p5m",
+       "vencpll_d2",
+       "syspll_d3",
+       "univpll1_d2",
+       "univpll2_d2",
+       "syspll1_d2",
+       "univpll_d5",
+       "vcodecpll_370p5",
+       "dmpll_ck"
+};
+
+static const char * const dpi0_parents[] __initconst = {
+       "clk26m",
+       "tvdpll_d2",
+       "tvdpll_d4",
+       "clk26m",
+       "clk26m",
+       "tvdpll_d8",
+       "tvdpll_d16"
+};
+
+static const char * const irda_parents[] __initconst = {
+       "clk26m",
+       "univpll2_d4",
+       "syspll2_d4"
+};
+
+static const char * const cci400_parents[] __initconst = {
+       "clk26m",
+       "vencpll_ck",
+       "armca7pll_754m",
+       "armca7pll_502m",
+       "univpll_d2",
+       "syspll_d2",
+       "msdcpll_ck",
+       "dmpll_ck"
+};
+
+static const char * const aud_1_parents[] __initconst = {
+       "clk26m",
+       "apll1_ck",
+       "univpll2_d4",
+       "univpll2_d8"
+};
+
+static const char * const aud_2_parents[] __initconst = {
+       "clk26m",
+       "apll2_ck",
+       "univpll2_d4",
+       "univpll2_d8"
+};
+
+static const char * const mem_mfg_in_parents[] __initconst = {
+       "clk26m",
+       "mmpll_ck",
+       "dmpll_ck",
+       "clk26m"
+};
+
+static const char * const axi_mfg_in_parents[] __initconst = {
+       "clk26m",
+       "axi_sel",
+       "dmpll_d2"
+};
+
+static const char * const scam_parents[] __initconst = {
+       "clk26m",
+       "syspll3_d2",
+       "univpll2_d4",
+       "dmpll_d4"
+};
+
+static const char * const spinfi_ifr_parents[] __initconst = {
+       "clk26m",
+       "univpll2_d8",
+       "univpll3_d4",
+       "syspll4_d2",
+       "univpll2_d4",
+       "univpll3_d2",
+       "syspll1_d4",
+       "univpll1_d4"
+};
+
+static const char * const hdmi_parents[] __initconst = {
+       "clk26m",
+       "hdmitx_dig_cts",
+       "hdmitxpll_d2",
+       "hdmitxpll_d3"
+};
+
+static const char * const dpilvds_parents[] __initconst = {
+       "clk26m",
+       "lvdspll",
+       "lvdspll_d2",
+       "lvdspll_d4",
+       "lvdspll_d8",
+       "fpc_ck"
+};
+
+static const char * const msdc50_2_h_parents[] __initconst = {
+       "clk26m",
+       "syspll1_d2",
+       "syspll2_d2",
+       "syspll4_d2",
+       "univpll_d5",
+       "univpll1_d4"
+};
+
+static const char * const hdcp_parents[] __initconst = {
+       "clk26m",
+       "syspll4_d2",
+       "syspll3_d4",
+       "univpll2_d4"
+};
+
+static const char * const hdcp_24m_parents[] __initconst = {
+       "clk26m",
+       "univpll_d26",
+       "univpll_d52",
+       "univpll2_d8"
+};
+
+static const char * const rtc_parents[] __initconst = {
+       "clkrtc_int",
+       "clkrtc_ext",
+       "clk26m",
+       "univpll3_d8"
+};
+
+static const char * const i2s0_m_ck_parents[] __initconst = {
+       "apll1_div1",
+       "apll2_div1"
+};
+
+static const char * const i2s1_m_ck_parents[] __initconst = {
+       "apll1_div2",
+       "apll2_div2"
+};
+
+static const char * const i2s2_m_ck_parents[] __initconst = {
+       "apll1_div3",
+       "apll2_div3"
+};
+
+static const char * const i2s3_m_ck_parents[] __initconst = {
+       "apll1_div4",
+       "apll2_div4"
+};
+
+static const char * const i2s3_b_ck_parents[] __initconst = {
+       "apll1_div5",
+       "apll2_div5"
+};
+
+static const struct mtk_composite top_muxes[] __initconst = {
+       /* CLK_CFG_0 */
+       MUX(CLK_TOP_AXI_SEL, "axi_sel", axi_parents, 0x0040, 0, 3),
+       MUX(CLK_TOP_MEM_SEL, "mem_sel", mem_parents, 0x0040, 8, 1),
+       MUX_GATE(CLK_TOP_DDRPHYCFG_SEL, "ddrphycfg_sel", ddrphycfg_parents, 0x0040, 16, 1, 23),
+       MUX_GATE(CLK_TOP_MM_SEL, "mm_sel", mm_parents, 0x0040, 24, 4, 31),
+       /* CLK_CFG_1 */
+       MUX_GATE(CLK_TOP_PWM_SEL, "pwm_sel", pwm_parents, 0x0050, 0, 2, 7),
+       MUX_GATE(CLK_TOP_VDEC_SEL, "vdec_sel", vdec_parents, 0x0050, 8, 4, 15),
+       MUX_GATE(CLK_TOP_VENC_SEL, "venc_sel", venc_parents, 0x0050, 16, 4, 23),
+       MUX_GATE(CLK_TOP_MFG_SEL, "mfg_sel", mfg_parents, 0x0050, 24, 4, 31),
+       /* CLK_CFG_2 */
+       MUX_GATE(CLK_TOP_CAMTG_SEL, "camtg_sel", camtg_parents, 0x0060, 0, 3, 7),
+       MUX_GATE(CLK_TOP_UART_SEL, "uart_sel", uart_parents, 0x0060, 8, 1, 15),
+       MUX_GATE(CLK_TOP_SPI_SEL, "spi_sel", spi_parents, 0x0060, 16, 3, 23),
+       MUX_GATE(CLK_TOP_USB20_SEL, "usb20_sel", usb20_parents, 0x0060, 24, 2, 31),
+       /* CLK_CFG_3 */
+       MUX_GATE(CLK_TOP_USB30_SEL, "usb30_sel", usb30_parents, 0x0070, 0, 2, 7),
+       MUX_GATE(CLK_TOP_MSDC50_0_H_SEL, "msdc50_0_h_sel", msdc50_0_h_parents, 0x0070, 8, 3, 15),
+       MUX_GATE(CLK_TOP_MSDC50_0_SEL, "msdc50_0_sel", msdc50_0_parents, 0x0070, 16, 4, 23),
+       MUX_GATE(CLK_TOP_MSDC30_1_SEL, "msdc30_1_sel", msdc30_1_parents, 0x0070, 24, 3, 31),
+       /* CLK_CFG_4 */
+       MUX_GATE(CLK_TOP_MSDC30_2_SEL, "msdc30_2_sel", msdc30_2_parents, 0x0080, 0, 3, 7),
+       MUX_GATE(CLK_TOP_MSDC30_3_SEL, "msdc30_3_sel", msdc30_3_parents, 0x0080, 8, 4, 15),
+       MUX_GATE(CLK_TOP_AUDIO_SEL, "audio_sel", audio_parents, 0x0080, 16, 2, 23),
+       MUX_GATE(CLK_TOP_AUD_INTBUS_SEL, "aud_intbus_sel", aud_intbus_parents, 0x0080, 24, 3, 31),
+       /* CLK_CFG_5 */
+       MUX_GATE(CLK_TOP_PMICSPI_SEL, "pmicspi_sel", pmicspi_parents, 0x0090, 0, 3, 7 /* 7:5 */),
+       MUX_GATE(CLK_TOP_SCP_SEL, "scp_sel", scp_parents, 0x0090, 8, 3, 15),
+       MUX_GATE(CLK_TOP_ATB_SEL, "atb_sel", atb_parents, 0x0090, 16, 2, 23),
+       MUX_GATE(CLK_TOP_VENC_LT_SEL, "venclt_sel", venc_lt_parents, 0x0090, 24, 4, 31),
+       /* CLK_CFG_6 */
+       MUX_GATE(CLK_TOP_DPI0_SEL, "dpi0_sel", dpi0_parents, 0x00a0, 0, 3, 7),
+       MUX_GATE(CLK_TOP_IRDA_SEL, "irda_sel", irda_parents, 0x00a0, 8, 2, 15),
+       MUX_GATE(CLK_TOP_CCI400_SEL, "cci400_sel", cci400_parents, 0x00a0, 16, 3, 23),
+       MUX_GATE(CLK_TOP_AUD_1_SEL, "aud_1_sel", aud_1_parents, 0x00a0, 24, 2, 31),
+       /* CLK_CFG_7 */
+       MUX_GATE(CLK_TOP_AUD_2_SEL, "aud_2_sel", aud_2_parents, 0x00b0, 0, 2, 7),
+       MUX_GATE(CLK_TOP_MEM_MFG_IN_SEL, "mem_mfg_in_sel", mem_mfg_in_parents, 0x00b0, 8, 2, 15),
+       MUX_GATE(CLK_TOP_AXI_MFG_IN_SEL, "axi_mfg_in_sel", axi_mfg_in_parents, 0x00b0, 16, 2, 23),
+       MUX_GATE(CLK_TOP_SCAM_SEL, "scam_sel", scam_parents, 0x00b0, 24, 2, 31),
+       /* CLK_CFG_12 */
+       MUX_GATE(CLK_TOP_SPINFI_IFR_SEL, "spinfi_ifr_sel", spinfi_ifr_parents, 0x00c0, 0, 3, 7),
+       MUX_GATE(CLK_TOP_HDMI_SEL, "hdmi_sel", hdmi_parents, 0x00c0, 8, 2, 15),
+       MUX_GATE(CLK_TOP_DPILVDS_SEL, "dpilvds_sel", dpilvds_parents, 0x00c0, 24, 3, 31),
+       /* CLK_CFG_13 */
+       MUX_GATE(CLK_TOP_MSDC50_2_H_SEL, "msdc50_2_h_sel", msdc50_2_h_parents, 0x00d0, 0, 3, 7),
+       MUX_GATE(CLK_TOP_HDCP_SEL, "hdcp_sel", hdcp_parents, 0x00d0, 8, 2, 15),
+       MUX_GATE(CLK_TOP_HDCP_24M_SEL, "hdcp_24m_sel", hdcp_24m_parents, 0x00d0, 16, 2, 23),
+       MUX(CLK_TOP_RTC_SEL, "rtc_sel", rtc_parents, 0x00d0, 24, 2),
+
+       DIV_GATE(CLK_TOP_APLL1_DIV0, "apll1_div0", "aud_1_sel", 0x12c, 8, 0x120, 4, 24),
+       DIV_GATE(CLK_TOP_APLL1_DIV1, "apll1_div1", "aud_1_sel", 0x12c, 9, 0x124, 8, 0),
+       DIV_GATE(CLK_TOP_APLL1_DIV2, "apll1_div2", "aud_1_sel", 0x12c, 10, 0x124, 8, 8),
+       DIV_GATE(CLK_TOP_APLL1_DIV3, "apll1_div3", "aud_1_sel", 0x12c, 11, 0x124, 8, 16),
+       DIV_GATE(CLK_TOP_APLL1_DIV4, "apll1_div4", "aud_1_sel", 0x12c, 12, 0x124, 8, 24),
+       DIV_GATE(CLK_TOP_APLL1_DIV5, "apll1_div5", "apll1_div4", 0x12c, 13, 0x12c, 4, 0),
+
+       DIV_GATE(CLK_TOP_APLL2_DIV0, "apll2_div0", "aud_2_sel", 0x12c, 16, 0x120, 4, 28),
+       DIV_GATE(CLK_TOP_APLL2_DIV1, "apll2_div1", "aud_2_sel", 0x12c, 17, 0x128, 8, 0),
+       DIV_GATE(CLK_TOP_APLL2_DIV2, "apll2_div2", "aud_2_sel", 0x12c, 18, 0x128, 8, 8),
+       DIV_GATE(CLK_TOP_APLL2_DIV3, "apll2_div3", "aud_2_sel", 0x12c, 19, 0x128, 8, 16),
+       DIV_GATE(CLK_TOP_APLL2_DIV4, "apll2_div4", "aud_2_sel", 0x12c, 20, 0x128, 8, 24),
+       DIV_GATE(CLK_TOP_APLL2_DIV5, "apll2_div5", "apll2_div4", 0x12c, 21, 0x12c, 4, 4),
+
+       MUX(CLK_TOP_I2S0_M_SEL, "i2s0_m_ck_sel", i2s0_m_ck_parents, 0x120, 4, 1),
+       MUX(CLK_TOP_I2S1_M_SEL, "i2s1_m_ck_sel", i2s1_m_ck_parents, 0x120, 5, 1),
+       MUX(CLK_TOP_I2S2_M_SEL, "i2s2_m_ck_sel", i2s2_m_ck_parents, 0x120, 6, 1),
+       MUX(CLK_TOP_I2S3_M_SEL, "i2s3_m_ck_sel", i2s3_m_ck_parents, 0x120, 7, 1),
+       MUX(CLK_TOP_I2S3_B_SEL, "i2s3_b_ck_sel", i2s3_b_ck_parents, 0x120, 8, 1),
+};
+
+static const struct mtk_gate_regs infra_cg_regs = {
+       .set_ofs = 0x0040,
+       .clr_ofs = 0x0044,
+       .sta_ofs = 0x0048,
+};
+
+#define GATE_ICG(_id, _name, _parent, _shift) {        \
+               .id = _id,                                      \
+               .name = _name,                                  \
+               .parent_name = _parent,                         \
+               .regs = &infra_cg_regs,                         \
+               .shift = _shift,                                \
+               .ops = &mtk_clk_gate_ops_setclr,                \
+       }
+
+static const struct mtk_gate infra_clks[] __initconst = {
+       GATE_ICG(CLK_INFRA_DBGCLK, "infra_dbgclk", "axi_sel", 0),
+       GATE_ICG(CLK_INFRA_SMI, "infra_smi", "mm_sel", 1),
+       GATE_ICG(CLK_INFRA_AUDIO, "infra_audio", "aud_intbus_sel", 5),
+       GATE_ICG(CLK_INFRA_GCE, "infra_gce", "axi_sel", 6),
+       GATE_ICG(CLK_INFRA_L2C_SRAM, "infra_l2c_sram", "axi_sel", 7),
+       GATE_ICG(CLK_INFRA_M4U, "infra_m4u", "mem_sel", 8),
+       GATE_ICG(CLK_INFRA_CPUM, "infra_cpum", "clk_null", 15),
+       GATE_ICG(CLK_INFRA_KP, "infra_kp", "axi_sel", 16),
+       GATE_ICG(CLK_INFRA_CEC, "infra_cec", "clk26m", 18),
+       GATE_ICG(CLK_INFRA_PMICSPI, "infra_pmicspi", "pmicspi_sel", 22),
+       GATE_ICG(CLK_INFRA_PMICWRAP, "infra_pmicwrap", "axi_sel", 23),
+};
+
+static const struct mtk_gate_regs peri0_cg_regs = {
+       .set_ofs = 0x0008,
+       .clr_ofs = 0x0010,
+       .sta_ofs = 0x0018,
+};
+
+static const struct mtk_gate_regs peri1_cg_regs = {
+       .set_ofs = 0x000c,
+       .clr_ofs = 0x0014,
+       .sta_ofs = 0x001c,
+};
+
+#define GATE_PERI0(_id, _name, _parent, _shift) {      \
+               .id = _id,                                      \
+               .name = _name,                                  \
+               .parent_name = _parent,                         \
+               .regs = &peri0_cg_regs,                         \
+               .shift = _shift,                                \
+               .ops = &mtk_clk_gate_ops_setclr,                \
+       }
+
+#define GATE_PERI1(_id, _name, _parent, _shift) {      \
+               .id = _id,                                      \
+               .name = _name,                                  \
+               .parent_name = _parent,                         \
+               .regs = &peri1_cg_regs,                         \
+               .shift = _shift,                                \
+               .ops = &mtk_clk_gate_ops_setclr,                \
+       }
+
+static const struct mtk_gate peri_gates[] __initconst = {
+       /* PERI0 */
+       GATE_PERI0(CLK_PERI_NFI, "peri_nfi", "axi_sel", 0),
+       GATE_PERI0(CLK_PERI_THERM, "peri_therm", "axi_sel", 1),
+       GATE_PERI0(CLK_PERI_PWM1, "peri_pwm1", "axi_sel", 2),
+       GATE_PERI0(CLK_PERI_PWM2, "peri_pwm2", "axi_sel", 3),
+       GATE_PERI0(CLK_PERI_PWM3, "peri_pwm3", "axi_sel", 4),
+       GATE_PERI0(CLK_PERI_PWM4, "peri_pwm4", "axi_sel", 5),
+       GATE_PERI0(CLK_PERI_PWM5, "peri_pwm5", "axi_sel", 6),
+       GATE_PERI0(CLK_PERI_PWM6, "peri_pwm6", "axi_sel", 7),
+       GATE_PERI0(CLK_PERI_PWM7, "peri_pwm7", "axi_sel", 8),
+       GATE_PERI0(CLK_PERI_PWM, "peri_pwm", "axi_sel", 9),
+       GATE_PERI0(CLK_PERI_USB0, "peri_usb0", "usb20_sel", 10),
+       GATE_PERI0(CLK_PERI_USB1, "peri_usb1", "usb20_sel", 11),
+       GATE_PERI0(CLK_PERI_AP_DMA, "peri_ap_dma", "axi_sel", 12),
+       GATE_PERI0(CLK_PERI_MSDC30_0, "peri_msdc30_0", "msdc50_0_sel", 13),
+       GATE_PERI0(CLK_PERI_MSDC30_1, "peri_msdc30_1", "msdc30_1_sel", 14),
+       GATE_PERI0(CLK_PERI_MSDC30_2, "peri_msdc30_2", "msdc30_2_sel", 15),
+       GATE_PERI0(CLK_PERI_MSDC30_3, "peri_msdc30_3", "msdc30_3_sel", 16),
+       GATE_PERI0(CLK_PERI_NLI_ARB, "peri_nli_arb", "axi_sel", 17),
+       GATE_PERI0(CLK_PERI_IRDA, "peri_irda", "irda_sel", 18),
+       GATE_PERI0(CLK_PERI_UART0, "peri_uart0", "axi_sel", 19),
+       GATE_PERI0(CLK_PERI_UART1, "peri_uart1", "axi_sel", 20),
+       GATE_PERI0(CLK_PERI_UART2, "peri_uart2", "axi_sel", 21),
+       GATE_PERI0(CLK_PERI_UART3, "peri_uart3", "axi_sel", 22),
+       GATE_PERI0(CLK_PERI_I2C0, "peri_i2c0", "axi_sel", 23),
+       GATE_PERI0(CLK_PERI_I2C1, "peri_i2c1", "axi_sel", 24),
+       GATE_PERI0(CLK_PERI_I2C2, "peri_i2c2", "axi_sel", 25),
+       GATE_PERI0(CLK_PERI_I2C3, "peri_i2c3", "axi_sel", 26),
+       GATE_PERI0(CLK_PERI_I2C4, "peri_i2c4", "axi_sel", 27),
+       GATE_PERI0(CLK_PERI_AUXADC, "peri_auxadc", "clk26m", 28),
+       GATE_PERI0(CLK_PERI_SPI0, "peri_spi0", "spi_sel", 29),
+       GATE_PERI0(CLK_PERI_I2C5, "peri_i2c5", "axi_sel", 30),
+       GATE_PERI0(CLK_PERI_NFIECC, "peri_nfiecc", "axi_sel", 31),
+       /* PERI1 */
+       GATE_PERI1(CLK_PERI_SPI, "peri_spi", "spi_sel", 0),
+       GATE_PERI1(CLK_PERI_IRRX, "peri_irrx", "spi_sel", 1),
+       GATE_PERI1(CLK_PERI_I2C6, "peri_i2c6", "axi_sel", 2),
+};
+
+static const char * const uart_ck_sel_parents[] __initconst = {
+       "clk26m",
+       "uart_sel",
+};
+
+static const struct mtk_composite peri_clks[] __initconst = {
+       MUX(CLK_PERI_UART0_SEL, "uart0_ck_sel", uart_ck_sel_parents, 0x40c, 0, 1),
+       MUX(CLK_PERI_UART1_SEL, "uart1_ck_sel", uart_ck_sel_parents, 0x40c, 1, 1),
+       MUX(CLK_PERI_UART2_SEL, "uart2_ck_sel", uart_ck_sel_parents, 0x40c, 2, 1),
+       MUX(CLK_PERI_UART3_SEL, "uart3_ck_sel", uart_ck_sel_parents, 0x40c, 3, 1),
+};
+
+static void __init mtk_topckgen_init(struct device_node *node)
+{
+       struct clk_onecell_data *clk_data;
+       void __iomem *base;
+       int r;
+
+       base = of_iomap(node, 0);
+       if (!base) {
+               pr_err("%s(): ioremap failed\n", __func__);
+               return;
+       }
+
+       clk_data = mtk_alloc_clk_data(CLK_TOP_NR_CLK);
+
+       mtk_clk_register_factors(root_clk_alias, ARRAY_SIZE(root_clk_alias), clk_data);
+       mtk_clk_register_factors(top_divs, ARRAY_SIZE(top_divs), clk_data);
+       mtk_clk_register_composites(top_muxes, ARRAY_SIZE(top_muxes), base,
+                       &mt8173_clk_lock, clk_data);
+
+       clk_prepare_enable(clk_data->clks[CLK_TOP_CCI400_SEL]);
+
+       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_topckgen, "mediatek,mt8173-topckgen", mtk_topckgen_init);
+
+static void __init mtk_infrasys_init(struct device_node *node)
+{
+       struct clk_onecell_data *clk_data;
+       int r;
+
+       clk_data = mtk_alloc_clk_data(CLK_INFRA_NR_CLK);
+
+       mtk_clk_register_gates(node, infra_clks, ARRAY_SIZE(infra_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);
+
+       mtk_register_reset_controller(node, 2, 0x30);
+}
+CLK_OF_DECLARE(mtk_infrasys, "mediatek,mt8173-infracfg", mtk_infrasys_init);
+
+static void __init mtk_pericfg_init(struct device_node *node)
+{
+       struct clk_onecell_data *clk_data;
+       int r;
+       void __iomem *base;
+
+       base = of_iomap(node, 0);
+       if (!base) {
+               pr_err("%s(): ioremap failed\n", __func__);
+               return;
+       }
+
+       clk_data = mtk_alloc_clk_data(CLK_PERI_NR_CLK);
+
+       mtk_clk_register_gates(node, peri_gates, ARRAY_SIZE(peri_gates),
+                                               clk_data);
+       mtk_clk_register_composites(peri_clks, ARRAY_SIZE(peri_clks), base,
+                       &mt8173_clk_lock, 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);
+
+       mtk_register_reset_controller(node, 2, 0);
+}
+CLK_OF_DECLARE(mtk_pericfg, "mediatek,mt8173-pericfg", mtk_pericfg_init);
+
+#define MT8173_PLL_FMAX                (3000UL * MHZ)
+
+#define CON0_MT8173_RST_BAR    BIT(24)
+
+#define PLL(_id, _name, _reg, _pwr_reg, _en_mask, _flags, _pcwbits, _pd_reg, _pd_shift, \
+                       _tuner_reg, _pcw_reg, _pcw_shift) { \
+               .id = _id,                                              \
+               .name = _name,                                          \
+               .reg = _reg,                                            \
+               .pwr_reg = _pwr_reg,                                    \
+               .en_mask = _en_mask,                                    \
+               .flags = _flags,                                        \
+               .rst_bar_mask = CON0_MT8173_RST_BAR,                    \
+               .fmax = MT8173_PLL_FMAX,                                \
+               .pcwbits = _pcwbits,                                    \
+               .pd_reg = _pd_reg,                                      \
+               .pd_shift = _pd_shift,                                  \
+               .tuner_reg = _tuner_reg,                                \
+               .pcw_reg = _pcw_reg,                                    \
+               .pcw_shift = _pcw_shift,                                \
+       }
+
+static const struct mtk_pll_data plls[] = {
+       PLL(CLK_APMIXED_ARMCA15PLL, "armca15pll", 0x200, 0x20c, 0x00000001, 0, 21, 0x204, 24, 0x0, 0x204, 0),
+       PLL(CLK_APMIXED_ARMCA7PLL, "armca7pll", 0x210, 0x21c, 0x00000001, 0, 21, 0x214, 24, 0x0, 0x214, 0),
+       PLL(CLK_APMIXED_MAINPLL, "mainpll", 0x220, 0x22c, 0xf0000101, HAVE_RST_BAR, 21, 0x220, 4, 0x0, 0x224, 0),
+       PLL(CLK_APMIXED_UNIVPLL, "univpll", 0x230, 0x23c, 0xfe000001, HAVE_RST_BAR, 7, 0x230, 4, 0x0, 0x234, 14),
+       PLL(CLK_APMIXED_MMPLL, "mmpll", 0x240, 0x24c, 0x00000001, 0, 21, 0x244, 24, 0x0, 0x244, 0),
+       PLL(CLK_APMIXED_MSDCPLL, "msdcpll", 0x250, 0x25c, 0x00000001, 0, 21, 0x250, 4, 0x0, 0x254, 0),
+       PLL(CLK_APMIXED_VENCPLL, "vencpll", 0x260, 0x26c, 0x00000001, 0, 21, 0x260, 4, 0x0, 0x264, 0),
+       PLL(CLK_APMIXED_TVDPLL, "tvdpll", 0x270, 0x27c, 0x00000001, 0, 21, 0x270, 4, 0x0, 0x274, 0),
+       PLL(CLK_APMIXED_MPLL, "mpll", 0x280, 0x28c, 0x00000001, 0, 21, 0x280, 4, 0x0, 0x284, 0),
+       PLL(CLK_APMIXED_VCODECPLL, "vcodecpll", 0x290, 0x29c, 0x00000001, 0, 21, 0x290, 4, 0x0, 0x294, 0),
+       PLL(CLK_APMIXED_APLL1, "apll1", 0x2a0, 0x2b0, 0x00000001, 0, 31, 0x2a0, 4, 0x2a4, 0x2a4, 0),
+       PLL(CLK_APMIXED_APLL2, "apll2", 0x2b4, 0x2c4, 0x00000001, 0, 31, 0x2b4, 4, 0x2b8, 0x2b8, 0),
+       PLL(CLK_APMIXED_LVDSPLL, "lvdspll", 0x2d0, 0x2dc, 0x00000001, 0, 21, 0x2d0, 4, 0x0, 0x2d4, 0),
+       PLL(CLK_APMIXED_MSDCPLL2, "msdcpll2", 0x2f0, 0x2fc, 0x00000001, 0, 21, 0x2f0, 4, 0x0, 0x2f4, 0),
+};
+
+static void __init mtk_apmixedsys_init(struct device_node *node)
+{
+       struct clk_onecell_data *clk_data;
+
+       clk_data = mtk_alloc_clk_data(CLK_APMIXED_NR_CLK);
+       if (!clk_data)
+               return;
+
+       mtk_clk_register_plls(node, plls, ARRAY_SIZE(plls), clk_data);
+
+       clk_prepare_enable(clk_data->clks[CLK_APMIXED_ARMCA15PLL]);
+}
+CLK_OF_DECLARE(mtk_apmixedsys, "mediatek,mt8173-apmixedsys",
+               mtk_apmixedsys_init);
diff --git a/drivers/clk/mediatek/clk-mtk.c b/drivers/clk/mediatek/clk-mtk.c
new file mode 100644 (file)
index 0000000..18444ae
--- /dev/null
@@ -0,0 +1,220 @@
+/*
+ * Copyright (c) 2014 MediaTek Inc.
+ * Author: James Liao <jamesjj.liao@mediatek.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/of.h>
+#include <linux/of_address.h>
+#include <linux/err.h>
+#include <linux/io.h>
+#include <linux/slab.h>
+#include <linux/delay.h>
+#include <linux/clkdev.h>
+#include <linux/mfd/syscon.h>
+
+#include "clk-mtk.h"
+#include "clk-gate.h"
+
+struct clk_onecell_data *mtk_alloc_clk_data(unsigned int clk_num)
+{
+       int i;
+       struct clk_onecell_data *clk_data;
+
+       clk_data = kzalloc(sizeof(*clk_data), GFP_KERNEL);
+       if (!clk_data)
+               return NULL;
+
+       clk_data->clks = kcalloc(clk_num, sizeof(*clk_data->clks), GFP_KERNEL);
+       if (!clk_data->clks)
+               goto err_out;
+
+       clk_data->clk_num = clk_num;
+
+       for (i = 0; i < clk_num; i++)
+               clk_data->clks[i] = ERR_PTR(-ENOENT);
+
+       return clk_data;
+err_out:
+       kfree(clk_data);
+
+       return NULL;
+}
+
+void mtk_clk_register_factors(const struct mtk_fixed_factor *clks, int num,
+               struct clk_onecell_data *clk_data)
+{
+       int i;
+       struct clk *clk;
+
+       for (i = 0; i < num; i++) {
+               const struct mtk_fixed_factor *ff = &clks[i];
+
+               clk = clk_register_fixed_factor(NULL, ff->name, ff->parent_name,
+                               CLK_SET_RATE_PARENT, ff->mult, ff->div);
+
+               if (IS_ERR(clk)) {
+                       pr_err("Failed to register clk %s: %ld\n",
+                                       ff->name, PTR_ERR(clk));
+                       continue;
+               }
+
+               if (clk_data)
+                       clk_data->clks[ff->id] = clk;
+       }
+}
+
+int mtk_clk_register_gates(struct device_node *node, const struct mtk_gate *clks,
+               int num, struct clk_onecell_data *clk_data)
+{
+       int i;
+       struct clk *clk;
+       struct regmap *regmap;
+
+       if (!clk_data)
+               return -ENOMEM;
+
+       regmap = syscon_node_to_regmap(node);
+       if (IS_ERR(regmap)) {
+               pr_err("Cannot find regmap for %s: %ld\n", node->full_name,
+                               PTR_ERR(regmap));
+               return PTR_ERR(regmap);
+       }
+
+       for (i = 0; i < num; i++) {
+               const struct mtk_gate *gate = &clks[i];
+
+               clk = mtk_clk_register_gate(gate->name, gate->parent_name,
+                               regmap,
+                               gate->regs->set_ofs,
+                               gate->regs->clr_ofs,
+                               gate->regs->sta_ofs,
+                               gate->shift, gate->ops);
+
+               if (IS_ERR(clk)) {
+                       pr_err("Failed to register clk %s: %ld\n",
+                                       gate->name, PTR_ERR(clk));
+                       continue;
+               }
+
+               clk_data->clks[gate->id] = clk;
+       }
+
+       return 0;
+}
+
+struct clk *mtk_clk_register_composite(const struct mtk_composite *mc,
+               void __iomem *base, spinlock_t *lock)
+{
+       struct clk *clk;
+       struct clk_mux *mux = NULL;
+       struct clk_gate *gate = NULL;
+       struct clk_divider *div = NULL;
+       struct clk_hw *mux_hw = NULL, *gate_hw = NULL, *div_hw = NULL;
+       const struct clk_ops *mux_ops = NULL, *gate_ops = NULL, *div_ops = NULL;
+       const char * const *parent_names;
+       const char *parent;
+       int num_parents;
+       int ret;
+
+       if (mc->mux_shift >= 0) {
+               mux = kzalloc(sizeof(*mux), GFP_KERNEL);
+               if (!mux)
+                       return ERR_PTR(-ENOMEM);
+
+               mux->reg = base + mc->mux_reg;
+               mux->mask = BIT(mc->mux_width) - 1;
+               mux->shift = mc->mux_shift;
+               mux->lock = lock;
+
+               mux_hw = &mux->hw;
+               mux_ops = &clk_mux_ops;
+
+               parent_names = mc->parent_names;
+               num_parents = mc->num_parents;
+       } else {
+               parent = mc->parent;
+               parent_names = &parent;
+               num_parents = 1;
+       }
+
+       if (mc->gate_shift >= 0) {
+               gate = kzalloc(sizeof(*gate), GFP_KERNEL);
+               if (!gate) {
+                       ret = -ENOMEM;
+                       goto err_out;
+               }
+
+               gate->reg = base + mc->gate_reg;
+               gate->bit_idx = mc->gate_shift;
+               gate->flags = CLK_GATE_SET_TO_DISABLE;
+               gate->lock = lock;
+
+               gate_hw = &gate->hw;
+               gate_ops = &clk_gate_ops;
+       }
+
+       if (mc->divider_shift >= 0) {
+               div = kzalloc(sizeof(*div), GFP_KERNEL);
+               if (!div) {
+                       ret = -ENOMEM;
+                       goto err_out;
+               }
+
+               div->reg = base + mc->divider_reg;
+               div->shift = mc->divider_shift;
+               div->width = mc->divider_width;
+               div->lock = lock;
+
+               div_hw = &div->hw;
+               div_ops = &clk_divider_ops;
+       }
+
+       clk = clk_register_composite(NULL, mc->name, parent_names, num_parents,
+               mux_hw, mux_ops,
+               div_hw, div_ops,
+               gate_hw, gate_ops,
+               mc->flags);
+
+       if (IS_ERR(clk)) {
+               kfree(gate);
+               kfree(mux);
+       }
+
+       return clk;
+err_out:
+       kfree(mux);
+
+       return ERR_PTR(ret);
+}
+
+void mtk_clk_register_composites(const struct mtk_composite *mcs,
+               int num, void __iomem *base, spinlock_t *lock,
+               struct clk_onecell_data *clk_data)
+{
+       struct clk *clk;
+       int i;
+
+       for (i = 0; i < num; i++) {
+               const struct mtk_composite *mc = &mcs[i];
+
+               clk = mtk_clk_register_composite(mc, base, lock);
+
+               if (IS_ERR(clk)) {
+                       pr_err("Failed to register clk %s: %ld\n",
+                                       mc->name, PTR_ERR(clk));
+                       continue;
+               }
+
+               if (clk_data)
+                       clk_data->clks[mc->id] = clk;
+       }
+}
diff --git a/drivers/clk/mediatek/clk-mtk.h b/drivers/clk/mediatek/clk-mtk.h
new file mode 100644 (file)
index 0000000..9dda9d8
--- /dev/null
@@ -0,0 +1,169 @@
+/*
+ * Copyright (c) 2014 MediaTek Inc.
+ * Author: James Liao <jamesjj.liao@mediatek.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#ifndef __DRV_CLK_MTK_H
+#define __DRV_CLK_MTK_H
+
+#include <linux/regmap.h>
+#include <linux/bitops.h>
+#include <linux/clk.h>
+#include <linux/clk-provider.h>
+
+#define MAX_MUX_GATE_BIT       31
+#define INVALID_MUX_GATE_BIT   (MAX_MUX_GATE_BIT + 1)
+
+#define MHZ (1000 * 1000)
+
+struct mtk_fixed_factor {
+       int id;
+       const char *name;
+       const char *parent_name;
+       int mult;
+       int div;
+};
+
+#define FACTOR(_id, _name, _parent, _mult, _div) {     \
+               .id = _id,                              \
+               .name = _name,                          \
+               .parent_name = _parent,                 \
+               .mult = _mult,                          \
+               .div = _div,                            \
+       }
+
+extern void mtk_clk_register_factors(const struct mtk_fixed_factor *clks,
+               int num, struct clk_onecell_data *clk_data);
+
+struct mtk_composite {
+       int id;
+       const char *name;
+       const char * const *parent_names;
+       const char *parent;
+       unsigned flags;
+
+       uint32_t mux_reg;
+       uint32_t divider_reg;
+       uint32_t gate_reg;
+
+       signed char mux_shift;
+       signed char mux_width;
+       signed char gate_shift;
+
+       signed char divider_shift;
+       signed char divider_width;
+
+       signed char num_parents;
+};
+
+#define MUX_GATE(_id, _name, _parents, _reg, _shift, _width, _gate) {  \
+               .id = _id,                                              \
+               .name = _name,                                          \
+               .mux_reg = _reg,                                        \
+               .mux_shift = _shift,                                    \
+               .mux_width = _width,                                    \
+               .gate_reg = _reg,                                       \
+               .gate_shift = _gate,                                    \
+               .divider_shift = -1,                                    \
+               .parent_names = _parents,                               \
+               .num_parents = ARRAY_SIZE(_parents),                    \
+               .flags = CLK_SET_RATE_PARENT,                           \
+       }
+
+#define MUX(_id, _name, _parents, _reg, _shift, _width) {              \
+               .id = _id,                                              \
+               .name = _name,                                          \
+               .mux_reg = _reg,                                        \
+               .mux_shift = _shift,                                    \
+               .mux_width = _width,                                    \
+               .gate_shift = -1,                                       \
+               .divider_shift = -1,                                    \
+               .parent_names = _parents,                               \
+               .num_parents = ARRAY_SIZE(_parents),                    \
+               .flags = CLK_SET_RATE_PARENT,                           \
+       }
+
+#define DIV_GATE(_id, _name, _parent, _gate_reg, _gate_shift, _div_reg, _div_width, _div_shift) {      \
+               .id = _id,                                              \
+               .parent = _parent,                                      \
+               .name = _name,                                          \
+               .divider_reg = _div_reg,                                \
+               .divider_shift = _div_shift,                            \
+               .divider_width = _div_width,                            \
+               .gate_reg = _gate_reg,                                  \
+               .gate_shift = _gate_shift,                              \
+               .mux_shift = -1,                                        \
+               .flags = 0,                                             \
+       }
+
+struct clk *mtk_clk_register_composite(const struct mtk_composite *mc,
+               void __iomem *base, spinlock_t *lock);
+
+void mtk_clk_register_composites(const struct mtk_composite *mcs,
+               int num, void __iomem *base, spinlock_t *lock,
+               struct clk_onecell_data *clk_data);
+
+struct mtk_gate_regs {
+       u32 sta_ofs;
+       u32 clr_ofs;
+       u32 set_ofs;
+};
+
+struct mtk_gate {
+       int id;
+       const char *name;
+       const char *parent_name;
+       const struct mtk_gate_regs *regs;
+       int shift;
+       const struct clk_ops *ops;
+};
+
+int mtk_clk_register_gates(struct device_node *node, const struct mtk_gate *clks,
+               int num, struct clk_onecell_data *clk_data);
+
+struct clk_onecell_data *mtk_alloc_clk_data(unsigned int clk_num);
+
+#define HAVE_RST_BAR   BIT(0)
+
+struct mtk_pll_data {
+       int id;
+       const char *name;
+       uint32_t reg;
+       uint32_t pwr_reg;
+       uint32_t en_mask;
+       uint32_t pd_reg;
+       uint32_t tuner_reg;
+       int pd_shift;
+       unsigned int flags;
+       const struct clk_ops *ops;
+       u32 rst_bar_mask;
+       unsigned long fmax;
+       int pcwbits;
+       uint32_t pcw_reg;
+       int pcw_shift;
+};
+
+void __init mtk_clk_register_plls(struct device_node *node,
+               const struct mtk_pll_data *plls, int num_plls,
+               struct clk_onecell_data *clk_data);
+
+#ifdef CONFIG_RESET_CONTROLLER
+void mtk_register_reset_controller(struct device_node *np,
+                       unsigned int num_regs, int regofs);
+#else
+static inline void mtk_register_reset_controller(struct device_node *np,
+                       unsigned int num_regs, int regofs)
+{
+}
+#endif
+
+#endif /* __DRV_CLK_MTK_H */
diff --git a/drivers/clk/mediatek/clk-pll.c b/drivers/clk/mediatek/clk-pll.c
new file mode 100644 (file)
index 0000000..44409e9
--- /dev/null
@@ -0,0 +1,332 @@
+/*
+ * Copyright (c) 2014 MediaTek Inc.
+ * Author: James Liao <jamesjj.liao@mediatek.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/of.h>
+#include <linux/of_address.h>
+#include <linux/io.h>
+#include <linux/slab.h>
+#include <linux/clkdev.h>
+#include <linux/delay.h>
+
+#include "clk-mtk.h"
+
+#define REG_CON0               0
+#define REG_CON1               4
+
+#define CON0_BASE_EN           BIT(0)
+#define CON0_PWR_ON            BIT(0)
+#define CON0_ISO_EN            BIT(1)
+#define CON0_PCW_CHG           BIT(31)
+
+#define AUDPLL_TUNER_EN                BIT(31)
+
+#define POSTDIV_MASK           0x7
+#define INTEGER_BITS           7
+
+/*
+ * MediaTek PLLs are configured through their pcw value. The pcw value describes
+ * a divider in the PLL feedback loop which consists of 7 bits for the integer
+ * part and the remaining bits (if present) for the fractional part. Also they
+ * have a 3 bit power-of-two post divider.
+ */
+
+struct mtk_clk_pll {
+       struct clk_hw   hw;
+       void __iomem    *base_addr;
+       void __iomem    *pd_addr;
+       void __iomem    *pwr_addr;
+       void __iomem    *tuner_addr;
+       void __iomem    *pcw_addr;
+       const struct mtk_pll_data *data;
+};
+
+static inline struct mtk_clk_pll *to_mtk_clk_pll(struct clk_hw *hw)
+{
+       return container_of(hw, struct mtk_clk_pll, hw);
+}
+
+static int mtk_pll_is_prepared(struct clk_hw *hw)
+{
+       struct mtk_clk_pll *pll = to_mtk_clk_pll(hw);
+
+       return (readl(pll->base_addr + REG_CON0) & CON0_BASE_EN) != 0;
+}
+
+static unsigned long __mtk_pll_recalc_rate(struct mtk_clk_pll *pll, u32 fin,
+               u32 pcw, int postdiv)
+{
+       int pcwbits = pll->data->pcwbits;
+       int pcwfbits;
+       u64 vco;
+       u8 c = 0;
+
+       /* The fractional part of the PLL divider. */
+       pcwfbits = pcwbits > INTEGER_BITS ? pcwbits - INTEGER_BITS : 0;
+
+       vco = (u64)fin * pcw;
+
+       if (pcwfbits && (vco & GENMASK(pcwfbits - 1, 0)))
+               c = 1;
+
+       vco >>= pcwfbits;
+
+       if (c)
+               vco++;
+
+       return ((unsigned long)vco + postdiv - 1) / postdiv;
+}
+
+static void mtk_pll_set_rate_regs(struct mtk_clk_pll *pll, u32 pcw,
+               int postdiv)
+{
+       u32 con1, pd, val;
+       int pll_en;
+
+       /* set postdiv */
+       pd = readl(pll->pd_addr);
+       pd &= ~(POSTDIV_MASK << pll->data->pd_shift);
+       pd |= (ffs(postdiv) - 1) << pll->data->pd_shift;
+       writel(pd, pll->pd_addr);
+
+       pll_en = readl(pll->base_addr + REG_CON0) & CON0_BASE_EN;
+
+       /* set pcw */
+       val = readl(pll->pcw_addr);
+
+       val &= ~GENMASK(pll->data->pcw_shift + pll->data->pcwbits - 1,
+                       pll->data->pcw_shift);
+       val |= pcw << pll->data->pcw_shift;
+       writel(val, pll->pcw_addr);
+
+       con1 = readl(pll->base_addr + REG_CON1);
+
+       if (pll_en)
+               con1 |= CON0_PCW_CHG;
+
+       writel(con1, pll->base_addr + REG_CON1);
+       if (pll->tuner_addr)
+               writel(con1 + 1, pll->tuner_addr);
+
+       if (pll_en)
+               udelay(20);
+}
+
+/*
+ * mtk_pll_calc_values - calculate good values for a given input frequency.
+ * @pll:       The pll
+ * @pcw:       The pcw value (output)
+ * @postdiv:   The post divider (output)
+ * @freq:      The desired target frequency
+ * @fin:       The input frequency
+ *
+ */
+static void mtk_pll_calc_values(struct mtk_clk_pll *pll, u32 *pcw, u32 *postdiv,
+               u32 freq, u32 fin)
+{
+       unsigned long fmin = 1000 * MHZ;
+       u64 _pcw;
+       u32 val;
+
+       if (freq > pll->data->fmax)
+               freq = pll->data->fmax;
+
+       for (val = 0; val < 4; val++) {
+               *postdiv = 1 << val;
+               if (freq * *postdiv >= fmin)
+                       break;
+       }
+
+       /* _pcw = freq * postdiv / fin * 2^pcwfbits */
+       _pcw = ((u64)freq << val) << (pll->data->pcwbits - INTEGER_BITS);
+       do_div(_pcw, fin);
+
+       *pcw = (u32)_pcw;
+}
+
+static int mtk_pll_set_rate(struct clk_hw *hw, unsigned long rate,
+               unsigned long parent_rate)
+{
+       struct mtk_clk_pll *pll = to_mtk_clk_pll(hw);
+       u32 pcw = 0;
+       u32 postdiv;
+
+       mtk_pll_calc_values(pll, &pcw, &postdiv, rate, parent_rate);
+       mtk_pll_set_rate_regs(pll, pcw, postdiv);
+
+       return 0;
+}
+
+static unsigned long mtk_pll_recalc_rate(struct clk_hw *hw,
+               unsigned long parent_rate)
+{
+       struct mtk_clk_pll *pll = to_mtk_clk_pll(hw);
+       u32 postdiv;
+       u32 pcw;
+
+       postdiv = (readl(pll->pd_addr) >> pll->data->pd_shift) & POSTDIV_MASK;
+       postdiv = 1 << postdiv;
+
+       pcw = readl(pll->pcw_addr) >> pll->data->pcw_shift;
+       pcw &= GENMASK(pll->data->pcwbits - 1, 0);
+
+       return __mtk_pll_recalc_rate(pll, parent_rate, pcw, postdiv);
+}
+
+static long mtk_pll_round_rate(struct clk_hw *hw, unsigned long rate,
+               unsigned long *prate)
+{
+       struct mtk_clk_pll *pll = to_mtk_clk_pll(hw);
+       u32 pcw = 0;
+       int postdiv;
+
+       mtk_pll_calc_values(pll, &pcw, &postdiv, rate, *prate);
+
+       return __mtk_pll_recalc_rate(pll, *prate, pcw, postdiv);
+}
+
+static int mtk_pll_prepare(struct clk_hw *hw)
+{
+       struct mtk_clk_pll *pll = to_mtk_clk_pll(hw);
+       u32 r;
+
+       r = readl(pll->pwr_addr) | CON0_PWR_ON;
+       writel(r, pll->pwr_addr);
+       udelay(1);
+
+       r = readl(pll->pwr_addr) & ~CON0_ISO_EN;
+       writel(r, pll->pwr_addr);
+       udelay(1);
+
+       r = readl(pll->base_addr + REG_CON0);
+       r |= pll->data->en_mask;
+       writel(r, pll->base_addr + REG_CON0);
+
+       if (pll->tuner_addr) {
+               r = readl(pll->tuner_addr) | AUDPLL_TUNER_EN;
+               writel(r, pll->tuner_addr);
+       }
+
+       udelay(20);
+
+       if (pll->data->flags & HAVE_RST_BAR) {
+               r = readl(pll->base_addr + REG_CON0);
+               r |= pll->data->rst_bar_mask;
+               writel(r, pll->base_addr + REG_CON0);
+       }
+
+       return 0;
+}
+
+static void mtk_pll_unprepare(struct clk_hw *hw)
+{
+       struct mtk_clk_pll *pll = to_mtk_clk_pll(hw);
+       u32 r;
+
+       if (pll->data->flags & HAVE_RST_BAR) {
+               r = readl(pll->base_addr + REG_CON0);
+               r &= ~pll->data->rst_bar_mask;
+               writel(r, pll->base_addr + REG_CON0);
+       }
+
+       if (pll->tuner_addr) {
+               r = readl(pll->tuner_addr) & ~AUDPLL_TUNER_EN;
+               writel(r, pll->tuner_addr);
+       }
+
+       r = readl(pll->base_addr + REG_CON0);
+       r &= ~CON0_BASE_EN;
+       writel(r, pll->base_addr + REG_CON0);
+
+       r = readl(pll->pwr_addr) | CON0_ISO_EN;
+       writel(r, pll->pwr_addr);
+
+       r = readl(pll->pwr_addr) & ~CON0_PWR_ON;
+       writel(r, pll->pwr_addr);
+}
+
+static const struct clk_ops mtk_pll_ops = {
+       .is_prepared    = mtk_pll_is_prepared,
+       .prepare        = mtk_pll_prepare,
+       .unprepare      = mtk_pll_unprepare,
+       .recalc_rate    = mtk_pll_recalc_rate,
+       .round_rate     = mtk_pll_round_rate,
+       .set_rate       = mtk_pll_set_rate,
+};
+
+static struct clk *mtk_clk_register_pll(const struct mtk_pll_data *data,
+               void __iomem *base)
+{
+       struct mtk_clk_pll *pll;
+       struct clk_init_data init = {};
+       struct clk *clk;
+       const char *parent_name = "clk26m";
+
+       pll = kzalloc(sizeof(*pll), GFP_KERNEL);
+       if (!pll)
+               return ERR_PTR(-ENOMEM);
+
+       pll->base_addr = base + data->reg;
+       pll->pwr_addr = base + data->pwr_reg;
+       pll->pd_addr = base + data->pd_reg;
+       pll->pcw_addr = base + data->pcw_reg;
+       if (data->tuner_reg)
+               pll->tuner_addr = base + data->tuner_reg;
+       pll->hw.init = &init;
+       pll->data = data;
+
+       init.name = data->name;
+       init.ops = &mtk_pll_ops;
+       init.parent_names = &parent_name;
+       init.num_parents = 1;
+
+       clk = clk_register(NULL, &pll->hw);
+
+       if (IS_ERR(clk))
+               kfree(pll);
+
+       return clk;
+}
+
+void __init mtk_clk_register_plls(struct device_node *node,
+               const struct mtk_pll_data *plls, int num_plls, struct clk_onecell_data *clk_data)
+{
+       void __iomem *base;
+       int r, i;
+       struct clk *clk;
+
+       base = of_iomap(node, 0);
+       if (!base) {
+               pr_err("%s(): ioremap failed\n", __func__);
+               return;
+       }
+
+       for (i = 0; i < num_plls; i++) {
+               const struct mtk_pll_data *pll = &plls[i];
+
+               clk = mtk_clk_register_pll(pll, base);
+
+               if (IS_ERR(clk)) {
+                       pr_err("Failed to register clk %s: %ld\n",
+                                       pll->name, PTR_ERR(clk));
+                       continue;
+               }
+
+               clk_data->clks[pll->id] = clk;
+       }
+
+       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);
+}
diff --git a/drivers/clk/mediatek/reset.c b/drivers/clk/mediatek/reset.c
new file mode 100644 (file)
index 0000000..9e9fe4b
--- /dev/null
@@ -0,0 +1,97 @@
+/*
+ * Copyright (c) 2014 MediaTek Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/mfd/syscon.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/platform_device.h>
+#include <linux/regmap.h>
+#include <linux/reset-controller.h>
+#include <linux/slab.h>
+
+#include "clk-mtk.h"
+
+struct mtk_reset {
+       struct regmap *regmap;
+       int regofs;
+       struct reset_controller_dev rcdev;
+};
+
+static int mtk_reset_assert(struct reset_controller_dev *rcdev,
+                             unsigned long id)
+{
+       struct mtk_reset *data = container_of(rcdev, struct mtk_reset, rcdev);
+
+       return regmap_update_bits(data->regmap, data->regofs + ((id / 32) << 2),
+                       BIT(id % 32), ~0);
+}
+
+static int mtk_reset_deassert(struct reset_controller_dev *rcdev,
+                               unsigned long id)
+{
+       struct mtk_reset *data = container_of(rcdev, struct mtk_reset, rcdev);
+
+       return regmap_update_bits(data->regmap, data->regofs + ((id / 32) << 2),
+                       BIT(id % 32), 0);
+}
+
+static int mtk_reset(struct reset_controller_dev *rcdev,
+                             unsigned long id)
+{
+       int ret;
+
+       ret = mtk_reset_assert(rcdev, id);
+       if (ret)
+               return ret;
+
+       return mtk_reset_deassert(rcdev, id);
+}
+
+static struct reset_control_ops mtk_reset_ops = {
+       .assert = mtk_reset_assert,
+       .deassert = mtk_reset_deassert,
+       .reset = mtk_reset,
+};
+
+void mtk_register_reset_controller(struct device_node *np,
+                       unsigned int num_regs, int regofs)
+{
+       struct mtk_reset *data;
+       int ret;
+       struct regmap *regmap;
+
+       regmap = syscon_node_to_regmap(np);
+       if (IS_ERR(regmap)) {
+               pr_err("Cannot find regmap for %s: %ld\n", np->full_name,
+                               PTR_ERR(regmap));
+               return;
+       }
+
+       data = kzalloc(sizeof(*data), GFP_KERNEL);
+       if (!data)
+               return;
+
+       data->regmap = regmap;
+       data->regofs = regofs;
+       data->rcdev.owner = THIS_MODULE;
+       data->rcdev.nr_resets = num_regs * 32;
+       data->rcdev.ops = &mtk_reset_ops;
+       data->rcdev.of_node = np;
+
+       ret = reset_controller_register(&data->rcdev);
+       if (ret) {
+               pr_err("could not register reset controller: %d\n", ret);
+               kfree(data);
+               return;
+       }
+}
diff --git a/drivers/clk/meson/Makefile b/drivers/clk/meson/Makefile
new file mode 100644 (file)
index 0000000..6d45531
--- /dev/null
@@ -0,0 +1,6 @@
+#
+# Makefile for Meson specific clk
+#
+
+obj-y += clkc.o clk-pll.o clk-cpu.o
+obj-y += meson8b-clkc.o
diff --git a/drivers/clk/meson/clk-cpu.c b/drivers/clk/meson/clk-cpu.c
new file mode 100644 (file)
index 0000000..71ad493
--- /dev/null
@@ -0,0 +1,242 @@
+/*
+ * Copyright (c) 2015 Endless Mobile, Inc.
+ * Author: Carlo Caione <carlo@endlessm.com>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+/*
+ * CPU clock path:
+ *
+ *                           +-[/N]-----|3|
+ *             MUX2  +--[/3]-+----------|2| MUX1
+ * [sys_pll]---|1|   |--[/2]------------|1|-|1|
+ *             | |---+------------------|0| | |----- [a5_clk]
+ *          +--|0|                          | |
+ * [xtal]---+-------------------------------|0|
+ *
+ *
+ *
+ */
+
+#include <linux/delay.h>
+#include <linux/err.h>
+#include <linux/io.h>
+#include <linux/module.h>
+#include <linux/of_address.h>
+#include <linux/slab.h>
+#include <linux/clk-provider.h>
+
+#define MESON_CPU_CLK_CNTL1            0x00
+#define MESON_CPU_CLK_CNTL             0x40
+
+#define MESON_CPU_CLK_MUX1             BIT(7)
+#define MESON_CPU_CLK_MUX2             BIT(0)
+
+#define MESON_N_WIDTH                  9
+#define MESON_N_SHIFT                  20
+#define MESON_SEL_WIDTH                        2
+#define MESON_SEL_SHIFT                        2
+
+#include "clkc.h"
+
+struct meson_clk_cpu {
+       struct notifier_block           clk_nb;
+       const struct clk_div_table      *div_table;
+       struct clk_hw                   hw;
+       void __iomem                    *base;
+       u16                             reg_off;
+};
+#define to_meson_clk_cpu_hw(_hw) container_of(_hw, struct meson_clk_cpu, hw)
+#define to_meson_clk_cpu_nb(_nb) container_of(_nb, struct meson_clk_cpu, clk_nb)
+
+static long meson_clk_cpu_round_rate(struct clk_hw *hw, unsigned long rate,
+                                    unsigned long *prate)
+{
+       struct meson_clk_cpu *clk_cpu = to_meson_clk_cpu_hw(hw);
+
+       return divider_round_rate(hw, rate, prate, clk_cpu->div_table,
+                                 MESON_N_WIDTH, CLK_DIVIDER_ROUND_CLOSEST);
+}
+
+static int meson_clk_cpu_set_rate(struct clk_hw *hw, unsigned long rate,
+                                 unsigned long parent_rate)
+{
+       struct meson_clk_cpu *clk_cpu = to_meson_clk_cpu_hw(hw);
+       unsigned int div, sel, N = 0;
+       u32 reg;
+
+       div = DIV_ROUND_UP(parent_rate, rate);
+
+       if (div <= 3) {
+               sel = div - 1;
+       } else {
+               sel = 3;
+               N = div / 2;
+       }
+
+       reg = readl(clk_cpu->base + clk_cpu->reg_off + MESON_CPU_CLK_CNTL1);
+       reg = PARM_SET(MESON_N_WIDTH, MESON_N_SHIFT, reg, N);
+       writel(reg, clk_cpu->base + clk_cpu->reg_off + MESON_CPU_CLK_CNTL1);
+
+       reg = readl(clk_cpu->base + clk_cpu->reg_off + MESON_CPU_CLK_CNTL);
+       reg = PARM_SET(MESON_SEL_WIDTH, MESON_SEL_SHIFT, reg, sel);
+       writel(reg, clk_cpu->base + clk_cpu->reg_off + MESON_CPU_CLK_CNTL);
+
+       return 0;
+}
+
+static unsigned long meson_clk_cpu_recalc_rate(struct clk_hw *hw,
+                                              unsigned long parent_rate)
+{
+       struct meson_clk_cpu *clk_cpu = to_meson_clk_cpu_hw(hw);
+       unsigned int N, sel;
+       unsigned int div = 1;
+       u32 reg;
+
+       reg = readl(clk_cpu->base + clk_cpu->reg_off + MESON_CPU_CLK_CNTL1);
+       N = PARM_GET(MESON_N_WIDTH, MESON_N_SHIFT, reg);
+
+       reg = readl(clk_cpu->base + clk_cpu->reg_off + MESON_CPU_CLK_CNTL);
+       sel = PARM_GET(MESON_SEL_WIDTH, MESON_SEL_SHIFT, reg);
+
+       if (sel < 3)
+               div = sel + 1;
+       else
+               div = 2 * N;
+
+       return parent_rate / div;
+}
+
+static int meson_clk_cpu_pre_rate_change(struct meson_clk_cpu *clk_cpu,
+                                        struct clk_notifier_data *ndata)
+{
+       u32 cpu_clk_cntl;
+
+       /* switch MUX1 to xtal */
+       cpu_clk_cntl = readl(clk_cpu->base + clk_cpu->reg_off
+                               + MESON_CPU_CLK_CNTL);
+       cpu_clk_cntl &= ~MESON_CPU_CLK_MUX1;
+       writel(cpu_clk_cntl, clk_cpu->base + clk_cpu->reg_off
+                               + MESON_CPU_CLK_CNTL);
+       udelay(100);
+
+       /* switch MUX2 to sys-pll */
+       cpu_clk_cntl |= MESON_CPU_CLK_MUX2;
+       writel(cpu_clk_cntl, clk_cpu->base + clk_cpu->reg_off
+                               + MESON_CPU_CLK_CNTL);
+
+       return 0;
+}
+
+static int meson_clk_cpu_post_rate_change(struct meson_clk_cpu *clk_cpu,
+                                         struct clk_notifier_data *ndata)
+{
+       u32 cpu_clk_cntl;
+
+       /* switch MUX1 to divisors' output */
+       cpu_clk_cntl = readl(clk_cpu->base + clk_cpu->reg_off
+                               + MESON_CPU_CLK_CNTL);
+       cpu_clk_cntl |= MESON_CPU_CLK_MUX1;
+       writel(cpu_clk_cntl, clk_cpu->base + clk_cpu->reg_off
+                               + MESON_CPU_CLK_CNTL);
+       udelay(100);
+
+       return 0;
+}
+
+/*
+ * This clock notifier is called when the frequency of the of the parent
+ * PLL clock is to be changed. We use the xtal input as temporary parent
+ * while the PLL frequency is stabilized.
+ */
+static int meson_clk_cpu_notifier_cb(struct notifier_block *nb,
+                                    unsigned long event, void *data)
+{
+       struct clk_notifier_data *ndata = data;
+       struct meson_clk_cpu *clk_cpu = to_meson_clk_cpu_nb(nb);
+       int ret = 0;
+
+       if (event == PRE_RATE_CHANGE)
+               ret = meson_clk_cpu_pre_rate_change(clk_cpu, ndata);
+       else if (event == POST_RATE_CHANGE)
+               ret = meson_clk_cpu_post_rate_change(clk_cpu, ndata);
+
+       return notifier_from_errno(ret);
+}
+
+static const struct clk_ops meson_clk_cpu_ops = {
+       .recalc_rate    = meson_clk_cpu_recalc_rate,
+       .round_rate     = meson_clk_cpu_round_rate,
+       .set_rate       = meson_clk_cpu_set_rate,
+};
+
+struct clk *meson_clk_register_cpu(const struct clk_conf *clk_conf,
+                                  void __iomem *reg_base,
+                                  spinlock_t *lock)
+{
+       struct clk *clk;
+       struct clk *pclk;
+       struct meson_clk_cpu *clk_cpu;
+       struct clk_init_data init;
+       int ret;
+
+       clk_cpu = kzalloc(sizeof(*clk_cpu), GFP_KERNEL);
+       if (!clk_cpu)
+               return ERR_PTR(-ENOMEM);
+
+       clk_cpu->base = reg_base;
+       clk_cpu->reg_off = clk_conf->reg_off;
+       clk_cpu->div_table = clk_conf->conf.div_table;
+       clk_cpu->clk_nb.notifier_call = meson_clk_cpu_notifier_cb;
+
+       init.name = clk_conf->clk_name;
+       init.ops = &meson_clk_cpu_ops;
+       init.flags = clk_conf->flags | CLK_GET_RATE_NOCACHE;
+       init.flags |= CLK_SET_RATE_PARENT;
+       init.parent_names = clk_conf->clks_parent;
+       init.num_parents = 1;
+
+       clk_cpu->hw.init = &init;
+
+       pclk = __clk_lookup(clk_conf->clks_parent[0]);
+       if (!pclk) {
+               pr_err("%s: could not lookup parent clock %s\n",
+                               __func__, clk_conf->clks_parent[0]);
+               ret = -EINVAL;
+               goto free_clk;
+       }
+
+       ret = clk_notifier_register(pclk, &clk_cpu->clk_nb);
+       if (ret) {
+               pr_err("%s: failed to register clock notifier for %s\n",
+                               __func__, clk_conf->clk_name);
+               goto free_clk;
+       }
+
+       clk = clk_register(NULL, &clk_cpu->hw);
+       if (IS_ERR(clk)) {
+               ret = PTR_ERR(clk);
+               goto unregister_clk_nb;
+       }
+
+       return clk;
+
+unregister_clk_nb:
+       clk_notifier_unregister(pclk, &clk_cpu->clk_nb);
+free_clk:
+       kfree(clk_cpu);
+
+       return ERR_PTR(ret);
+}
+
diff --git a/drivers/clk/meson/clk-pll.c b/drivers/clk/meson/clk-pll.c
new file mode 100644 (file)
index 0000000..664edf0
--- /dev/null
@@ -0,0 +1,227 @@
+/*
+ * Copyright (c) 2015 Endless Mobile, Inc.
+ * Author: Carlo Caione <carlo@endlessm.com>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+/*
+ * In the most basic form, a Meson PLL is composed as follows:
+ *
+ *                     PLL
+ *      +------------------------------+
+ *      |                              |
+ * in -----[ /N ]---[ *M ]---[ >>OD ]----->> out
+ *      |         ^        ^           |
+ *      +------------------------------+
+ *                |        |
+ *               FREF     VCO
+ *
+ * out = (in * M / N) >> OD
+ */
+
+#include <linux/clk-provider.h>
+#include <linux/delay.h>
+#include <linux/err.h>
+#include <linux/io.h>
+#include <linux/module.h>
+#include <linux/of_address.h>
+#include <linux/slab.h>
+#include <linux/string.h>
+
+#include "clkc.h"
+
+#define MESON_PLL_RESET                                BIT(29)
+#define MESON_PLL_LOCK                         BIT(31)
+
+struct meson_clk_pll {
+       struct clk_hw   hw;
+       void __iomem    *base;
+       struct pll_conf *conf;
+       unsigned int    rate_count;
+       spinlock_t      *lock;
+};
+#define to_meson_clk_pll(_hw) container_of(_hw, struct meson_clk_pll, hw)
+
+static unsigned long meson_clk_pll_recalc_rate(struct clk_hw *hw,
+                                               unsigned long parent_rate)
+{
+       struct meson_clk_pll *pll = to_meson_clk_pll(hw);
+       struct parm *p;
+       unsigned long parent_rate_mhz = parent_rate / 1000000;
+       unsigned long rate_mhz;
+       u16 n, m, od;
+       u32 reg;
+
+       p = &pll->conf->n;
+       reg = readl(pll->base + p->reg_off);
+       n = PARM_GET(p->width, p->shift, reg);
+
+       p = &pll->conf->m;
+       reg = readl(pll->base + p->reg_off);
+       m = PARM_GET(p->width, p->shift, reg);
+
+       p = &pll->conf->od;
+       reg = readl(pll->base + p->reg_off);
+       od = PARM_GET(p->width, p->shift, reg);
+
+       rate_mhz = (parent_rate_mhz * m / n) >> od;
+
+       return rate_mhz * 1000000;
+}
+
+static long meson_clk_pll_round_rate(struct clk_hw *hw, unsigned long rate,
+                                    unsigned long *parent_rate)
+{
+       struct meson_clk_pll *pll = to_meson_clk_pll(hw);
+       const struct pll_rate_table *rate_table = pll->conf->rate_table;
+       int i;
+
+       for (i = 0; i < pll->rate_count; i++) {
+               if (rate <= rate_table[i].rate)
+                       return rate_table[i].rate;
+       }
+
+       /* else return the smallest value */
+       return rate_table[0].rate;
+}
+
+static const struct pll_rate_table *meson_clk_get_pll_settings(struct meson_clk_pll *pll,
+                                                              unsigned long rate)
+{
+       const struct pll_rate_table *rate_table = pll->conf->rate_table;
+       int i;
+
+       for (i = 0; i < pll->rate_count; i++) {
+               if (rate == rate_table[i].rate)
+                       return &rate_table[i];
+       }
+       return NULL;
+}
+
+static int meson_clk_pll_wait_lock(struct meson_clk_pll *pll,
+                                  struct parm *p_n)
+{
+       int delay = 24000000;
+       u32 reg;
+
+       while (delay > 0) {
+               reg = readl(pll->base + p_n->reg_off);
+
+               if (reg & MESON_PLL_LOCK)
+                       return 0;
+               delay--;
+       }
+       return -ETIMEDOUT;
+}
+
+static int meson_clk_pll_set_rate(struct clk_hw *hw, unsigned long rate,
+                                 unsigned long parent_rate)
+{
+       struct meson_clk_pll *pll = to_meson_clk_pll(hw);
+       struct parm *p;
+       const struct pll_rate_table *rate_set;
+       unsigned long old_rate;
+       int ret = 0;
+       u32 reg;
+
+       if (parent_rate == 0 || rate == 0)
+               return -EINVAL;
+
+       old_rate = rate;
+
+       rate_set = meson_clk_get_pll_settings(pll, rate);
+       if (!rate_set)
+               return -EINVAL;
+
+       /* PLL reset */
+       p = &pll->conf->n;
+       reg = readl(pll->base + p->reg_off);
+       writel(reg | MESON_PLL_RESET, pll->base + p->reg_off);
+
+       reg = PARM_SET(p->width, p->shift, reg, rate_set->n);
+       writel(reg, pll->base + p->reg_off);
+
+       p = &pll->conf->m;
+       reg = readl(pll->base + p->reg_off);
+       reg = PARM_SET(p->width, p->shift, reg, rate_set->m);
+       writel(reg, pll->base + p->reg_off);
+
+       p = &pll->conf->od;
+       reg = readl(pll->base + p->reg_off);
+       reg = PARM_SET(p->width, p->shift, reg, rate_set->od);
+       writel(reg, pll->base + p->reg_off);
+
+       p = &pll->conf->n;
+       ret = meson_clk_pll_wait_lock(pll, p);
+       if (ret) {
+               pr_warn("%s: pll did not lock, trying to restore old rate %lu\n",
+                       __func__, old_rate);
+               meson_clk_pll_set_rate(hw, old_rate, parent_rate);
+       }
+
+       return ret;
+}
+
+static const struct clk_ops meson_clk_pll_ops = {
+       .recalc_rate    = meson_clk_pll_recalc_rate,
+       .round_rate     = meson_clk_pll_round_rate,
+       .set_rate       = meson_clk_pll_set_rate,
+};
+
+static const struct clk_ops meson_clk_pll_ro_ops = {
+       .recalc_rate    = meson_clk_pll_recalc_rate,
+};
+
+struct clk *meson_clk_register_pll(const struct clk_conf *clk_conf,
+                                  void __iomem *reg_base,
+                                  spinlock_t *lock)
+{
+       struct clk *clk;
+       struct meson_clk_pll *clk_pll;
+       struct clk_init_data init;
+
+       clk_pll = kzalloc(sizeof(*clk_pll), GFP_KERNEL);
+       if (!clk_pll)
+               return ERR_PTR(-ENOMEM);
+
+       clk_pll->base = reg_base + clk_conf->reg_off;
+       clk_pll->lock = lock;
+       clk_pll->conf = clk_conf->conf.pll;
+
+       init.name = clk_conf->clk_name;
+       init.flags = clk_conf->flags | CLK_GET_RATE_NOCACHE;
+
+       init.parent_names = &clk_conf->clks_parent[0];
+       init.num_parents = 1;
+       init.ops = &meson_clk_pll_ro_ops;
+
+       /* If no rate_table is specified we assume the PLL is read-only */
+       if (clk_pll->conf->rate_table) {
+               int len;
+
+               for (len = 0; clk_pll->conf->rate_table[len].rate != 0; )
+                       len++;
+
+                clk_pll->rate_count = len;
+                init.ops = &meson_clk_pll_ops;
+       }
+
+       clk_pll->hw.init = &init;
+
+       clk = clk_register(NULL, &clk_pll->hw);
+       if (IS_ERR(clk))
+               kfree(clk_pll);
+
+       return clk;
+}
diff --git a/drivers/clk/meson/clkc.c b/drivers/clk/meson/clkc.c
new file mode 100644 (file)
index 0000000..b8c511c
--- /dev/null
@@ -0,0 +1,250 @@
+/*
+ * Copyright (c) 2015 Endless Mobile, Inc.
+ * Author: Carlo Caione <carlo@endlessm.com>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <linux/clk.h>
+#include <linux/clk-provider.h>
+#include <linux/mfd/syscon.h>
+#include <linux/slab.h>
+
+#include "clkc.h"
+
+static DEFINE_SPINLOCK(clk_lock);
+
+static struct clk **clks;
+static struct clk_onecell_data clk_data;
+
+struct clk ** __init meson_clk_init(struct device_node *np,
+                                  unsigned long nr_clks)
+{
+       clks = kcalloc(nr_clks, sizeof(*clks), GFP_KERNEL);
+       if (!clks)
+               return ERR_PTR(-ENOMEM);
+
+       clk_data.clks = clks;
+       clk_data.clk_num = nr_clks;
+       of_clk_add_provider(np, of_clk_src_onecell_get, &clk_data);
+
+       return clks;
+}
+
+static void meson_clk_add_lookup(struct clk *clk, unsigned int id)
+{
+       if (clks && id)
+               clks[id] = clk;
+}
+
+static struct clk * __init
+meson_clk_register_composite(const struct clk_conf *clk_conf,
+                            void __iomem *clk_base)
+{
+       struct clk *clk;
+       struct clk_mux *mux = NULL;
+       struct clk_divider *div = NULL;
+       struct clk_gate *gate = NULL;
+       const struct clk_ops *mux_ops = NULL;
+       const struct composite_conf *composite_conf;
+
+       composite_conf = clk_conf->conf.composite;
+
+       if (clk_conf->num_parents > 1) {
+               mux = kzalloc(sizeof(*mux), GFP_KERNEL);
+               if (!mux)
+                       return ERR_PTR(-ENOMEM);
+
+               mux->reg = clk_base + clk_conf->reg_off
+                               + composite_conf->mux_parm.reg_off;
+               mux->shift = composite_conf->mux_parm.shift;
+               mux->mask = BIT(composite_conf->mux_parm.width) - 1;
+               mux->flags = composite_conf->mux_flags;
+               mux->lock = &clk_lock;
+               mux->table = composite_conf->mux_table;
+               mux_ops = (composite_conf->mux_flags & CLK_MUX_READ_ONLY) ?
+                         &clk_mux_ro_ops : &clk_mux_ops;
+       }
+
+       if (MESON_PARM_APPLICABLE(&composite_conf->div_parm)) {
+               div = kzalloc(sizeof(*div), GFP_KERNEL);
+               if (!div) {
+                       clk = ERR_PTR(-ENOMEM);
+                       goto error;
+               }
+
+               div->reg = clk_base + clk_conf->reg_off
+                               + composite_conf->div_parm.reg_off;
+               div->shift = composite_conf->div_parm.shift;
+               div->width = composite_conf->div_parm.width;
+               div->lock = &clk_lock;
+               div->flags = composite_conf->div_flags;
+               div->table = composite_conf->div_table;
+       }
+
+       if (MESON_PARM_APPLICABLE(&composite_conf->gate_parm)) {
+               gate = kzalloc(sizeof(*gate), GFP_KERNEL);
+               if (!gate) {
+                       clk = ERR_PTR(-ENOMEM);
+                       goto error;
+               }
+
+               gate->reg = clk_base + clk_conf->reg_off
+                               + composite_conf->div_parm.reg_off;
+               gate->bit_idx = composite_conf->gate_parm.shift;
+               gate->flags = composite_conf->gate_flags;
+               gate->lock = &clk_lock;
+       }
+
+       clk = clk_register_composite(NULL, clk_conf->clk_name,
+                                   clk_conf->clks_parent,
+                                   clk_conf->num_parents,
+                                   mux ? &mux->hw : NULL, mux_ops,
+                                   div ? &div->hw : NULL, &clk_divider_ops,
+                                   gate ? &gate->hw : NULL, &clk_gate_ops,
+                                   clk_conf->flags);
+       if (IS_ERR(clk))
+               goto error;
+
+       return clk;
+
+error:
+       kfree(gate);
+       kfree(div);
+       kfree(mux);
+
+       return clk;
+}
+
+static struct clk * __init
+meson_clk_register_fixed_factor(const struct clk_conf *clk_conf,
+                               void __iomem *clk_base)
+{
+       struct clk *clk;
+       const struct fixed_fact_conf *fixed_fact_conf;
+       const struct parm *p;
+       unsigned int mult, div;
+       u32 reg;
+
+       fixed_fact_conf = &clk_conf->conf.fixed_fact;
+
+       mult = clk_conf->conf.fixed_fact.mult;
+       div = clk_conf->conf.fixed_fact.div;
+
+       if (!mult) {
+               mult = 1;
+               p = &fixed_fact_conf->mult_parm;
+               if (MESON_PARM_APPLICABLE(p)) {
+                       reg = readl(clk_base + clk_conf->reg_off + p->reg_off);
+                       mult = PARM_GET(p->width, p->shift, reg);
+               }
+       }
+
+       if (!div) {
+               div = 1;
+               p = &fixed_fact_conf->div_parm;
+               if (MESON_PARM_APPLICABLE(p)) {
+                       reg = readl(clk_base + clk_conf->reg_off + p->reg_off);
+                       mult = PARM_GET(p->width, p->shift, reg);
+               }
+       }
+
+       clk = clk_register_fixed_factor(NULL,
+                       clk_conf->clk_name,
+                       clk_conf->clks_parent[0],
+                       clk_conf->flags,
+                       mult, div);
+
+       return clk;
+}
+
+static struct clk * __init
+meson_clk_register_fixed_rate(const struct clk_conf *clk_conf,
+                             void __iomem *clk_base)
+{
+       struct clk *clk;
+       const struct fixed_rate_conf *fixed_rate_conf;
+       const struct parm *r;
+       unsigned long rate;
+       u32 reg;
+
+       fixed_rate_conf = &clk_conf->conf.fixed_rate;
+       rate = fixed_rate_conf->rate;
+
+       if (!rate) {
+               r = &fixed_rate_conf->rate_parm;
+               reg = readl(clk_base + clk_conf->reg_off + r->reg_off);
+               rate = PARM_GET(r->width, r->shift, reg);
+       }
+
+       rate *= 1000000;
+
+       clk = clk_register_fixed_rate(NULL,
+                       clk_conf->clk_name,
+                       clk_conf->num_parents
+                               ? clk_conf->clks_parent[0] : NULL,
+                       clk_conf->flags, rate);
+
+       return clk;
+}
+
+void __init meson_clk_register_clks(const struct clk_conf *clk_confs,
+                                   size_t nr_confs,
+                                   void __iomem *clk_base)
+{
+       unsigned int i;
+       struct clk *clk = NULL;
+
+       for (i = 0; i < nr_confs; i++) {
+               const struct clk_conf *clk_conf = &clk_confs[i];
+
+               switch (clk_conf->clk_type) {
+               case CLK_FIXED_RATE:
+                       clk = meson_clk_register_fixed_rate(clk_conf,
+                                                           clk_base);
+                       break;
+               case CLK_FIXED_FACTOR:
+                       clk = meson_clk_register_fixed_factor(clk_conf,
+                                                             clk_base);
+                       break;
+               case CLK_COMPOSITE:
+                       clk = meson_clk_register_composite(clk_conf,
+                                                          clk_base);
+                       break;
+               case CLK_CPU:
+                       clk = meson_clk_register_cpu(clk_conf, clk_base,
+                                                    &clk_lock);
+                       break;
+               case CLK_PLL:
+                       clk = meson_clk_register_pll(clk_conf, clk_base,
+                                                    &clk_lock);
+                       break;
+               default:
+                       clk = NULL;
+               }
+
+               if (!clk) {
+                       pr_err("%s: unknown clock type %d\n", __func__,
+                              clk_conf->clk_type);
+                       continue;
+               }
+
+               if (IS_ERR(clk)) {
+                       pr_warn("%s: Unable to create %s clock\n", __func__,
+                               clk_conf->clk_name);
+                       continue;
+               }
+
+               meson_clk_add_lookup(clk, clk_conf->clk_id);
+       }
+}
diff --git a/drivers/clk/meson/clkc.h b/drivers/clk/meson/clkc.h
new file mode 100644 (file)
index 0000000..609ae92
--- /dev/null
@@ -0,0 +1,187 @@
+/*
+ * Copyright (c) 2015 Endless Mobile, Inc.
+ * Author: Carlo Caione <carlo@endlessm.com>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef __CLKC_H
+#define __CLKC_H
+
+#define PMASK(width)                   GENMASK(width - 1, 0)
+#define SETPMASK(width, shift)         GENMASK(shift + width - 1, shift)
+#define CLRPMASK(width, shift)         (~SETPMASK(width, shift))
+
+#define PARM_GET(width, shift, reg)                                    \
+       (((reg) & SETPMASK(width, shift)) >> (shift))
+#define PARM_SET(width, shift, reg, val)                               \
+       (((reg) & CLRPMASK(width, shift)) | (val << (shift)))
+
+#define MESON_PARM_APPLICABLE(p)               (!!((p)->width))
+
+struct parm {
+       u16     reg_off;
+       u8      shift;
+       u8      width;
+};
+#define PARM(_r, _s, _w)                                               \
+       {                                                               \
+               .reg_off        = (_r),                                 \
+               .shift          = (_s),                                 \
+               .width          = (_w),                                 \
+       }                                                               \
+
+struct pll_rate_table {
+       unsigned long   rate;
+       u16             m;
+       u16             n;
+       u16             od;
+};
+#define PLL_RATE(_r, _m, _n, _od)                                      \
+       {                                                               \
+               .rate           = (_r),                                 \
+               .m              = (_m),                                 \
+               .n              = (_n),                                 \
+               .od             = (_od),                                \
+       }                                                               \
+
+struct pll_conf {
+       const struct pll_rate_table     *rate_table;
+       struct parm                     m;
+       struct parm                     n;
+       struct parm                     od;
+};
+
+struct fixed_fact_conf {
+       unsigned int    div;
+       unsigned int    mult;
+       struct parm     div_parm;
+       struct parm     mult_parm;
+};
+
+struct fixed_rate_conf {
+       unsigned long   rate;
+       struct parm     rate_parm;
+};
+
+struct composite_conf {
+       struct parm             mux_parm;
+       struct parm             div_parm;
+       struct parm             gate_parm;
+       struct clk_div_table    *div_table;
+       u32                     *mux_table;
+       u8                      mux_flags;
+       u8                      div_flags;
+       u8                      gate_flags;
+};
+
+#define PNAME(x) static const char *x[]
+
+enum clk_type {
+       CLK_FIXED_FACTOR,
+       CLK_FIXED_RATE,
+       CLK_COMPOSITE,
+       CLK_CPU,
+       CLK_PLL,
+};
+
+struct clk_conf {
+       u16                             reg_off;
+       enum clk_type                   clk_type;
+       unsigned int                    clk_id;
+       const char                      *clk_name;
+       const char                      **clks_parent;
+       int                             num_parents;
+       unsigned long                   flags;
+       union {
+               struct fixed_fact_conf          fixed_fact;
+               struct fixed_rate_conf          fixed_rate;
+               const struct composite_conf             *composite;
+               struct pll_conf                 *pll;
+               const struct clk_div_table      *div_table;
+       } conf;
+};
+
+#define FIXED_RATE_P(_ro, _ci, _cn, _f, _c)                            \
+       {                                                               \
+               .reg_off                        = (_ro),                \
+               .clk_type                       = CLK_FIXED_RATE,       \
+               .clk_id                         = (_ci),                \
+               .clk_name                       = (_cn),                \
+               .flags                          = (_f),                 \
+               .conf.fixed_rate.rate_parm      = _c,                   \
+       }                                                               \
+
+#define FIXED_RATE(_ci, _cn, _f, _r)                                   \
+       {                                                               \
+               .clk_type                       = CLK_FIXED_RATE,       \
+               .clk_id                         = (_ci),                \
+               .clk_name                       = (_cn),                \
+               .flags                          = (_f),                 \
+               .conf.fixed_rate.rate           = (_r),                 \
+       }                                                               \
+
+#define PLL(_ro, _ci, _cn, _cp, _f, _c)                                        \
+       {                                                               \
+               .reg_off                        = (_ro),                \
+               .clk_type                       = CLK_PLL,              \
+               .clk_id                         = (_ci),                \
+               .clk_name                       = (_cn),                \
+               .clks_parent                    = (_cp),                \
+               .num_parents                    = ARRAY_SIZE(_cp),      \
+               .flags                          = (_f),                 \
+               .conf.pll                       = (_c),                 \
+       }                                                               \
+
+#define FIXED_FACTOR_DIV(_ci, _cn, _cp, _f, _d)                                \
+       {                                                               \
+               .clk_type                       = CLK_FIXED_FACTOR,     \
+               .clk_id                         = (_ci),                \
+               .clk_name                       = (_cn),                \
+               .clks_parent                    = (_cp),                \
+               .num_parents                    = ARRAY_SIZE(_cp),      \
+               .conf.fixed_fact.div            = (_d),                 \
+       }                                                               \
+
+#define CPU(_ro, _ci, _cn, _cp, _dt)                                   \
+       {                                                               \
+               .reg_off                        = (_ro),                \
+               .clk_type                       = CLK_CPU,              \
+               .clk_id                         = (_ci),                \
+               .clk_name                       = (_cn),                \
+               .clks_parent                    = (_cp),                \
+               .num_parents                    = ARRAY_SIZE(_cp),      \
+               .conf.div_table                 = (_dt),                \
+       }                                                               \
+
+#define COMPOSITE(_ro, _ci, _cn, _cp, _f, _c)                          \
+       {                                                               \
+               .reg_off                        = (_ro),                \
+               .clk_type                       = CLK_COMPOSITE,        \
+               .clk_id                         = (_ci),                \
+               .clk_name                       = (_cn),                \
+               .clks_parent                    = (_cp),                \
+               .num_parents                    = ARRAY_SIZE(_cp),      \
+               .flags                          = (_f),                 \
+               .conf.composite                 = (_c),                 \
+       }                                                               \
+
+struct clk **meson_clk_init(struct device_node *np, unsigned long nr_clks);
+void meson_clk_register_clks(const struct clk_conf *clk_confs,
+                            unsigned int nr_confs, void __iomem *clk_base);
+struct clk *meson_clk_register_cpu(const struct clk_conf *clk_conf,
+                                  void __iomem *reg_base, spinlock_t *lock);
+struct clk *meson_clk_register_pll(const struct clk_conf *clk_conf,
+                                  void __iomem *reg_base, spinlock_t *lock);
+
+#endif /* __CLKC_H */
diff --git a/drivers/clk/meson/meson8b-clkc.c b/drivers/clk/meson/meson8b-clkc.c
new file mode 100644 (file)
index 0000000..61f6d55
--- /dev/null
@@ -0,0 +1,196 @@
+/*
+ * Copyright (c) 2015 Endless Mobile, Inc.
+ * Author: Carlo Caione <carlo@endlessm.com>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <linux/clk-provider.h>
+#include <linux/kernel.h>
+#include <linux/of.h>
+#include <linux/of_address.h>
+#include <linux/slab.h>
+#include <dt-bindings/clock/meson8b-clkc.h>
+
+#include "clkc.h"
+
+#define MESON8B_REG_CTL0_ADDR          0x0000
+#define MESON8B_REG_SYS_CPU_CNTL1      0x015c
+#define MESON8B_REG_HHI_MPEG           0x0174
+#define MESON8B_REG_MALI               0x01b0
+#define MESON8B_REG_PLL_FIXED          0x0280
+#define MESON8B_REG_PLL_SYS            0x0300
+#define MESON8B_REG_PLL_VID            0x0320
+
+static const struct pll_rate_table sys_pll_rate_table[] = {
+       PLL_RATE(312000000, 52, 1, 2),
+       PLL_RATE(336000000, 56, 1, 2),
+       PLL_RATE(360000000, 60, 1, 2),
+       PLL_RATE(384000000, 64, 1, 2),
+       PLL_RATE(408000000, 68, 1, 2),
+       PLL_RATE(432000000, 72, 1, 2),
+       PLL_RATE(456000000, 76, 1, 2),
+       PLL_RATE(480000000, 80, 1, 2),
+       PLL_RATE(504000000, 84, 1, 2),
+       PLL_RATE(528000000, 88, 1, 2),
+       PLL_RATE(552000000, 92, 1, 2),
+       PLL_RATE(576000000, 96, 1, 2),
+       PLL_RATE(600000000, 50, 1, 1),
+       PLL_RATE(624000000, 52, 1, 1),
+       PLL_RATE(648000000, 54, 1, 1),
+       PLL_RATE(672000000, 56, 1, 1),
+       PLL_RATE(696000000, 58, 1, 1),
+       PLL_RATE(720000000, 60, 1, 1),
+       PLL_RATE(744000000, 62, 1, 1),
+       PLL_RATE(768000000, 64, 1, 1),
+       PLL_RATE(792000000, 66, 1, 1),
+       PLL_RATE(816000000, 68, 1, 1),
+       PLL_RATE(840000000, 70, 1, 1),
+       PLL_RATE(864000000, 72, 1, 1),
+       PLL_RATE(888000000, 74, 1, 1),
+       PLL_RATE(912000000, 76, 1, 1),
+       PLL_RATE(936000000, 78, 1, 1),
+       PLL_RATE(960000000, 80, 1, 1),
+       PLL_RATE(984000000, 82, 1, 1),
+       PLL_RATE(1008000000, 84, 1, 1),
+       PLL_RATE(1032000000, 86, 1, 1),
+       PLL_RATE(1056000000, 88, 1, 1),
+       PLL_RATE(1080000000, 90, 1, 1),
+       PLL_RATE(1104000000, 92, 1, 1),
+       PLL_RATE(1128000000, 94, 1, 1),
+       PLL_RATE(1152000000, 96, 1, 1),
+       PLL_RATE(1176000000, 98, 1, 1),
+       PLL_RATE(1200000000, 50, 1, 0),
+       PLL_RATE(1224000000, 51, 1, 0),
+       PLL_RATE(1248000000, 52, 1, 0),
+       PLL_RATE(1272000000, 53, 1, 0),
+       PLL_RATE(1296000000, 54, 1, 0),
+       PLL_RATE(1320000000, 55, 1, 0),
+       PLL_RATE(1344000000, 56, 1, 0),
+       PLL_RATE(1368000000, 57, 1, 0),
+       PLL_RATE(1392000000, 58, 1, 0),
+       PLL_RATE(1416000000, 59, 1, 0),
+       PLL_RATE(1440000000, 60, 1, 0),
+       PLL_RATE(1464000000, 61, 1, 0),
+       PLL_RATE(1488000000, 62, 1, 0),
+       PLL_RATE(1512000000, 63, 1, 0),
+       PLL_RATE(1536000000, 64, 1, 0),
+       { /* sentinel */ },
+};
+
+static const struct clk_div_table cpu_div_table[] = {
+       { .val = 1, .div = 1 },
+       { .val = 2, .div = 2 },
+       { .val = 3, .div = 3 },
+       { .val = 2, .div = 4 },
+       { .val = 3, .div = 6 },
+       { .val = 4, .div = 8 },
+       { .val = 5, .div = 10 },
+       { .val = 6, .div = 12 },
+       { .val = 7, .div = 14 },
+       { .val = 8, .div = 16 },
+       { /* sentinel */ },
+};
+
+PNAME(p_xtal)          = { "xtal" };
+PNAME(p_fclk_div)      = { "fixed_pll" };
+PNAME(p_cpu_clk)       = { "sys_pll" };
+PNAME(p_clk81)         = { "fclk_div3", "fclk_div4", "fclk_div5" };
+PNAME(p_mali)          = { "fclk_div3", "fclk_div4", "fclk_div5",
+                           "fclk_div7", "zero" };
+
+static u32 mux_table_clk81[]   = { 6, 5, 7 };
+static u32 mux_table_mali[]    = { 6, 5, 7, 4, 0 };
+
+static struct pll_conf pll_confs = {
+       .m              = PARM(0x00, 0,  9),
+       .n              = PARM(0x00, 9,  5),
+       .od             = PARM(0x00, 16, 2),
+};
+
+static struct pll_conf sys_pll_conf = {
+       .m              = PARM(0x00, 0,  9),
+       .n              = PARM(0x00, 9,  5),
+       .od             = PARM(0x00, 16, 2),
+       .rate_table     = sys_pll_rate_table,
+};
+
+static const struct composite_conf clk81_conf __initconst = {
+       .mux_table              = mux_table_clk81,
+       .mux_flags              = CLK_MUX_READ_ONLY,
+       .mux_parm               = PARM(0x00, 12, 3),
+       .div_parm               = PARM(0x00, 0, 7),
+       .gate_parm              = PARM(0x00, 7, 1),
+};
+
+static const struct composite_conf mali_conf __initconst = {
+       .mux_table              = mux_table_mali,
+       .mux_parm               = PARM(0x00, 9, 3),
+       .div_parm               = PARM(0x00, 0, 7),
+       .gate_parm              = PARM(0x00, 8, 1),
+};
+
+static const struct clk_conf meson8b_xtal_conf __initconst =
+       FIXED_RATE_P(MESON8B_REG_CTL0_ADDR, CLKID_XTAL, "xtal",
+                    CLK_IS_ROOT, PARM(0x00, 4, 7));
+
+static const struct clk_conf meson8b_clk_confs[] __initconst = {
+       FIXED_RATE(CLKID_ZERO, "zero", CLK_IS_ROOT, 0),
+       PLL(MESON8B_REG_PLL_FIXED, CLKID_PLL_FIXED, "fixed_pll",
+           p_xtal, 0, &pll_confs),
+       PLL(MESON8B_REG_PLL_VID, CLKID_PLL_VID, "vid_pll",
+           p_xtal, 0, &pll_confs),
+       PLL(MESON8B_REG_PLL_SYS, CLKID_PLL_SYS, "sys_pll",
+           p_xtal, 0, &sys_pll_conf),
+       FIXED_FACTOR_DIV(CLKID_FCLK_DIV2, "fclk_div2", p_fclk_div, 0, 2),
+       FIXED_FACTOR_DIV(CLKID_FCLK_DIV3, "fclk_div3", p_fclk_div, 0, 3),
+       FIXED_FACTOR_DIV(CLKID_FCLK_DIV4, "fclk_div4", p_fclk_div, 0, 4),
+       FIXED_FACTOR_DIV(CLKID_FCLK_DIV5, "fclk_div5", p_fclk_div, 0, 5),
+       FIXED_FACTOR_DIV(CLKID_FCLK_DIV7, "fclk_div7", p_fclk_div, 0, 7),
+       CPU(MESON8B_REG_SYS_CPU_CNTL1, CLKID_CPUCLK, "a5_clk", p_cpu_clk,
+           cpu_div_table),
+       COMPOSITE(MESON8B_REG_HHI_MPEG, CLKID_CLK81, "clk81", p_clk81,
+                 CLK_SET_RATE_NO_REPARENT | CLK_IGNORE_UNUSED, &clk81_conf),
+       COMPOSITE(MESON8B_REG_MALI, CLKID_MALI, "mali", p_mali,
+                 CLK_IGNORE_UNUSED, &mali_conf),
+};
+
+static void __init meson8b_clkc_init(struct device_node *np)
+{
+       void __iomem *clk_base;
+
+       if (!meson_clk_init(np, CLK_NR_CLKS))
+               return;
+
+       /* XTAL */
+       clk_base = of_iomap(np, 0);
+       if (!clk_base) {
+               pr_err("%s: Unable to map xtal base\n", __func__);
+               return;
+       }
+
+       meson_clk_register_clks(&meson8b_xtal_conf, 1, clk_base);
+       iounmap(clk_base);
+
+       /*  Generic clocks and PLLs */
+       clk_base = of_iomap(np, 1);
+       if (!clk_base) {
+               pr_err("%s: Unable to map clk base\n", __func__);
+               return;
+       }
+
+       meson_clk_register_clks(meson8b_clk_confs,
+                               ARRAY_SIZE(meson8b_clk_confs),
+                               clk_base);
+}
+CLK_OF_DECLARE(meson8b_clock, "amlogic,meson8b-clkc", meson8b_clkc_init);
index 3caaf7cc169c684559973f105317dea76bbd1d54..9d4bc41e4239506b7061fc183d6756cead5b2dad 100644 (file)
@@ -12,3 +12,5 @@ obj-$(CONFIG_MACH_MMP2_DT) += clk-of-mmp2.o
 obj-$(CONFIG_CPU_PXA168) += clk-pxa168.o
 obj-$(CONFIG_CPU_PXA910) += clk-pxa910.o
 obj-$(CONFIG_CPU_MMP2) += clk-mmp2.o
+
+obj-y += clk-of-pxa1928.o
index d14120eaa71f4c5d5498814aeee91a46d9012283..09d41c717c52830efd22849100deb01e9f9252fb 100644 (file)
@@ -115,7 +115,7 @@ static void clk_apbc_unprepare(struct clk_hw *hw)
                spin_unlock_irqrestore(apbc->lock, flags);
 }
 
-struct clk_ops clk_apbc_ops = {
+static struct clk_ops clk_apbc_ops = {
        .prepare = clk_apbc_prepare,
        .unprepare = clk_apbc_unprepare,
 };
index abe182b2377f04889cbfd85f3ca3ef332b786a79..cdcf2d7f321e0d5becfaa90b199d9839bcc9d81a 100644 (file)
@@ -61,7 +61,7 @@ static void clk_apmu_disable(struct clk_hw *hw)
                spin_unlock_irqrestore(apmu->lock, flags);
 }
 
-struct clk_ops clk_apmu_ops = {
+static struct clk_ops clk_apmu_ops = {
        .enable = clk_apmu_enable,
        .disable = clk_apmu_disable,
 };
index 5c90a4230fa3d3f2718c7ed6452c32c51df70b24..09d2832fbd7821a56e53fe8dc22ab16548fa3f1c 100644 (file)
@@ -63,10 +63,8 @@ static struct mmp_clk_factor_masks uart_factor_masks = {
 };
 
 static struct mmp_clk_factor_tbl uart_factor_tbl[] = {
-       {.num = 14634, .den = 2165},    /*14.745MHZ */
+       {.num = 8125, .den = 1536},     /*14.745MHZ */
        {.num = 3521, .den = 689},      /*19.23MHZ */
-       {.num = 9679, .den = 5728},     /*58.9824MHZ */
-       {.num = 15850, .den = 9451},    /*59.429MHZ */
 };
 
 static const char *uart_parent[] = {"uart_pll", "vctcxo"};
index 2cbc2b43ae527265c89f8a9deabfbf26a2f2bd28..251533d87c6538f6ff2cb46bee025a2589a1df2f 100644 (file)
@@ -30,6 +30,7 @@
 #define APBC_TWSI4     0x7c
 #define APBC_TWSI5     0x80
 #define APBC_KPC       0x18
+#define APBC_TIMER     0x24
 #define APBC_UART0     0x2c
 #define APBC_UART1     0x30
 #define APBC_UART2     0x34
@@ -98,10 +99,8 @@ static struct mmp_clk_factor_masks uart_factor_masks = {
 };
 
 static struct mmp_clk_factor_tbl uart_factor_tbl[] = {
-       {.num = 14634, .den = 2165},    /*14.745MHZ */
+       {.num = 8125, .den = 1536},     /*14.745MHZ */
        {.num = 3521, .den = 689},      /*19.23MHZ */
-       {.num = 9679, .den = 5728},     /*58.9824MHZ */
-       {.num = 15850, .den = 9451},    /*59.429MHZ */
 };
 
 static void mmp2_pll_init(struct mmp2_clk_unit *pxa_unit)
@@ -134,6 +133,9 @@ static DEFINE_SPINLOCK(ssp2_lock);
 static DEFINE_SPINLOCK(ssp3_lock);
 static const char *ssp_parent_names[] = {"vctcxo_4", "vctcxo_2", "vctcxo", "pll1_16"};
 
+static DEFINE_SPINLOCK(timer_lock);
+static const char *timer_parent_names[] = {"clk32", "vctcxo_2", "vctcxo_4", "vctcxo"};
+
 static DEFINE_SPINLOCK(reset_lock);
 
 static struct mmp_param_mux_clk apbc_mux_clks[] = {
@@ -145,6 +147,7 @@ static struct mmp_param_mux_clk apbc_mux_clks[] = {
        {0, "ssp1_mux", ssp_parent_names, ARRAY_SIZE(ssp_parent_names), CLK_SET_RATE_PARENT, APBC_SSP1, 4, 3, 0, &ssp1_lock},
        {0, "ssp2_mux", ssp_parent_names, ARRAY_SIZE(ssp_parent_names), CLK_SET_RATE_PARENT, APBC_SSP2, 4, 3, 0, &ssp2_lock},
        {0, "ssp3_mux", ssp_parent_names, ARRAY_SIZE(ssp_parent_names), CLK_SET_RATE_PARENT, APBC_SSP3, 4, 3, 0, &ssp3_lock},
+       {0, "timer_mux", timer_parent_names, ARRAY_SIZE(timer_parent_names), CLK_SET_RATE_PARENT, APBC_TIMER, 4, 3, 0, &timer_lock},
 };
 
 static struct mmp_param_gate_clk apbc_gate_clks[] = {
@@ -170,6 +173,7 @@ static struct mmp_param_gate_clk apbc_gate_clks[] = {
        {MMP2_CLK_SSP1, "ssp1_clk", "ssp1_mux", CLK_SET_RATE_PARENT, APBC_SSP1, 0x7, 0x3, 0x0, 0, &ssp1_lock},
        {MMP2_CLK_SSP2, "ssp2_clk", "ssp2_mux", CLK_SET_RATE_PARENT, APBC_SSP2, 0x7, 0x3, 0x0, 0, &ssp2_lock},
        {MMP2_CLK_SSP3, "ssp3_clk", "ssp3_mux", CLK_SET_RATE_PARENT, APBC_SSP3, 0x7, 0x3, 0x0, 0, &ssp3_lock},
+       {MMP2_CLK_TIMER, "timer_clk", "timer_mux", CLK_SET_RATE_PARENT, APBC_TIMER, 0x7, 0x3, 0x0, 0, &timer_lock},
 };
 
 static void mmp2_apb_periph_clk_init(struct mmp2_clk_unit *pxa_unit)
index 5b1810dc4bd20839d90531c6a47208a7f73a829f..64eaf4141c69842a766f49a79a1b2698b6974e8a 100644 (file)
@@ -32,6 +32,7 @@
 #define APBC_PWM1      0x10
 #define APBC_PWM2      0x14
 #define APBC_PWM3      0x18
+#define APBC_TIMER     0x34
 #define APBC_SSP0      0x81c
 #define APBC_SSP1      0x820
 #define APBC_SSP2      0x84c
@@ -58,6 +59,7 @@ static struct mmp_param_fixed_rate_clk fixed_rate_clks[] = {
        {PXA168_CLK_CLK32, "clk32", NULL, CLK_IS_ROOT, 32768},
        {PXA168_CLK_VCTCXO, "vctcxo", NULL, CLK_IS_ROOT, 26000000},
        {PXA168_CLK_PLL1, "pll1", NULL, CLK_IS_ROOT, 624000000},
+       {PXA168_CLK_USB_PLL, "usb_pll", NULL, CLK_IS_ROOT, 480000000},
 };
 
 static struct mmp_param_fixed_factor_clk fixed_factor_clks[] = {
@@ -70,6 +72,7 @@ static struct mmp_param_fixed_factor_clk fixed_factor_clks[] = {
        {PXA168_CLK_PLL1_24, "pll1_24", "pll1_12", 1, 2, 0},
        {PXA168_CLK_PLL1_48, "pll1_48", "pll1_24", 1, 2, 0},
        {PXA168_CLK_PLL1_96, "pll1_96", "pll1_48", 1, 2, 0},
+       {PXA168_CLK_PLL1_192, "pll1_192", "pll1_96", 1, 2, 0},
        {PXA168_CLK_PLL1_13, "pll1_13", "pll1", 1, 13, 0},
        {PXA168_CLK_PLL1_13_1_5, "pll1_13_1_5", "pll1_13", 2, 3, 0},
        {PXA168_CLK_PLL1_2_1_5, "pll1_2_1_5", "pll1_2", 2, 3, 0},
@@ -119,6 +122,9 @@ static DEFINE_SPINLOCK(ssp3_lock);
 static DEFINE_SPINLOCK(ssp4_lock);
 static const char *ssp_parent_names[] = {"pll1_96", "pll1_48", "pll1_24", "pll1_12"};
 
+static DEFINE_SPINLOCK(timer_lock);
+static const char *timer_parent_names[] = {"pll1_48", "clk32", "pll1_96", "pll1_192"};
+
 static DEFINE_SPINLOCK(reset_lock);
 
 static struct mmp_param_mux_clk apbc_mux_clks[] = {
@@ -130,6 +136,7 @@ static struct mmp_param_mux_clk apbc_mux_clks[] = {
        {0, "ssp2_mux", ssp_parent_names, ARRAY_SIZE(ssp_parent_names), CLK_SET_RATE_PARENT, APBC_SSP2, 4, 3, 0, &ssp2_lock},
        {0, "ssp3_mux", ssp_parent_names, ARRAY_SIZE(ssp_parent_names), CLK_SET_RATE_PARENT, APBC_SSP3, 4, 3, 0, &ssp3_lock},
        {0, "ssp4_mux", ssp_parent_names, ARRAY_SIZE(ssp_parent_names), CLK_SET_RATE_PARENT, APBC_SSP4, 4, 3, 0, &ssp4_lock},
+       {0, "timer_mux", timer_parent_names, ARRAY_SIZE(timer_parent_names), CLK_SET_RATE_PARENT, APBC_TIMER, 4, 3, 0, &timer_lock},
 };
 
 static struct mmp_param_gate_clk apbc_gate_clks[] = {
@@ -151,6 +158,7 @@ static struct mmp_param_gate_clk apbc_gate_clks[] = {
        {PXA168_CLK_SSP2, "ssp2_clk", "ssp2_mux", CLK_SET_RATE_PARENT, APBC_SSP2, 0x3, 0x3, 0x0, 0, &ssp2_lock},
        {PXA168_CLK_SSP3, "ssp3_clk", "ssp3_mux", CLK_SET_RATE_PARENT, APBC_SSP3, 0x3, 0x3, 0x0, 0, &ssp3_lock},
        {PXA168_CLK_SSP4, "ssp4_clk", "ssp4_mux", CLK_SET_RATE_PARENT, APBC_SSP4, 0x3, 0x3, 0x0, 0, &ssp4_lock},
+       {PXA168_CLK_TIMER, "timer_clk", "timer_mux", CLK_SET_RATE_PARENT, APBC_TIMER, 0x3, 0x3, 0x0, 0, &timer_lock},
 };
 
 static void pxa168_apb_periph_clk_init(struct pxa168_clk_unit *pxa_unit)
diff --git a/drivers/clk/mmp/clk-of-pxa1928.c b/drivers/clk/mmp/clk-of-pxa1928.c
new file mode 100644 (file)
index 0000000..433a5ae
--- /dev/null
@@ -0,0 +1,265 @@
+/*
+ * pxa1928 clock framework source file
+ *
+ * Copyright (C) 2015 Linaro, Ltd.
+ * Rob Herring <robh@kernel.org>
+ *
+ * Based on drivers/clk/mmp/clk-of-mmp2.c:
+ * Copyright (C) 2012 Marvell
+ * Chao Xie <xiechao.mail@gmail.com>
+ *
+ * This file is licensed under the terms of the GNU General Public
+ * License version 2. This program is licensed "as is" without any
+ * warranty of any kind, whether express or implied.
+ */
+#include <linux/kernel.h>
+#include <linux/io.h>
+#include <linux/of_address.h>
+#include <linux/slab.h>
+#include <linux/spinlock.h>
+
+#include <dt-bindings/clock/marvell,pxa1928.h>
+
+#include "clk.h"
+#include "reset.h"
+
+#define MPMU_UART_PLL  0x14
+
+struct pxa1928_clk_unit {
+       struct mmp_clk_unit unit;
+       void __iomem *mpmu_base;
+       void __iomem *apmu_base;
+       void __iomem *apbc_base;
+       void __iomem *apbcp_base;
+};
+
+static struct mmp_param_fixed_rate_clk fixed_rate_clks[] = {
+       {0, "clk32", NULL, CLK_IS_ROOT, 32768},
+       {0, "vctcxo", NULL, CLK_IS_ROOT, 26000000},
+       {0, "pll1_624", NULL, CLK_IS_ROOT, 624000000},
+       {0, "pll5p", NULL, CLK_IS_ROOT, 832000000},
+       {0, "pll5", NULL, CLK_IS_ROOT, 1248000000},
+       {0, "usb_pll", NULL, CLK_IS_ROOT, 480000000},
+};
+
+static struct mmp_param_fixed_factor_clk fixed_factor_clks[] = {
+       {0, "pll1_d2", "pll1_624", 1, 2, 0},
+       {0, "pll1_d9", "pll1_624", 1, 9, 0},
+       {0, "pll1_d12", "pll1_624", 1, 12, 0},
+       {0, "pll1_d16", "pll1_624", 1, 16, 0},
+       {0, "pll1_d20", "pll1_624", 1, 20, 0},
+       {0, "pll1_416", "pll1_624", 2, 3, 0},
+       {0, "vctcxo_d2", "vctcxo", 1, 2, 0},
+       {0, "vctcxo_d4", "vctcxo", 1, 4, 0},
+};
+
+static struct mmp_clk_factor_masks uart_factor_masks = {
+       .factor = 2,
+       .num_mask = 0x1fff,
+       .den_mask = 0x1fff,
+       .num_shift = 16,
+       .den_shift = 0,
+};
+
+static struct mmp_clk_factor_tbl uart_factor_tbl[] = {
+       {.num = 832, .den = 234},       /*58.5MHZ */
+       {.num = 1, .den = 1},           /*26MHZ */
+};
+
+static void pxa1928_pll_init(struct pxa1928_clk_unit *pxa_unit)
+{
+       struct clk *clk;
+       struct mmp_clk_unit *unit = &pxa_unit->unit;
+
+       mmp_register_fixed_rate_clks(unit, fixed_rate_clks,
+                                       ARRAY_SIZE(fixed_rate_clks));
+
+       mmp_register_fixed_factor_clks(unit, fixed_factor_clks,
+                                       ARRAY_SIZE(fixed_factor_clks));
+
+       clk = mmp_clk_register_factor("uart_pll", "pll1_416",
+                               CLK_SET_RATE_PARENT,
+                               pxa_unit->mpmu_base + MPMU_UART_PLL,
+                               &uart_factor_masks, uart_factor_tbl,
+                               ARRAY_SIZE(uart_factor_tbl), NULL);
+}
+
+static DEFINE_SPINLOCK(uart0_lock);
+static DEFINE_SPINLOCK(uart1_lock);
+static DEFINE_SPINLOCK(uart2_lock);
+static DEFINE_SPINLOCK(uart3_lock);
+static const char *uart_parent_names[] = {"uart_pll", "vctcxo"};
+
+static DEFINE_SPINLOCK(ssp0_lock);
+static DEFINE_SPINLOCK(ssp1_lock);
+static const char *ssp_parent_names[] = {"vctcxo_d4", "vctcxo_d2", "vctcxo", "pll1_d12"};
+
+static DEFINE_SPINLOCK(reset_lock);
+
+static struct mmp_param_mux_clk apbc_mux_clks[] = {
+       {0, "uart0_mux", uart_parent_names, ARRAY_SIZE(uart_parent_names), CLK_SET_RATE_PARENT, PXA1928_CLK_UART0 * 4, 4, 3, 0, &uart0_lock},
+       {0, "uart1_mux", uart_parent_names, ARRAY_SIZE(uart_parent_names), CLK_SET_RATE_PARENT, PXA1928_CLK_UART1 * 4, 4, 3, 0, &uart1_lock},
+       {0, "uart2_mux", uart_parent_names, ARRAY_SIZE(uart_parent_names), CLK_SET_RATE_PARENT, PXA1928_CLK_UART2 * 4, 4, 3, 0, &uart2_lock},
+       {0, "uart3_mux", uart_parent_names, ARRAY_SIZE(uart_parent_names), CLK_SET_RATE_PARENT, PXA1928_CLK_UART3 * 4, 4, 3, 0, &uart3_lock},
+       {0, "ssp0_mux", ssp_parent_names, ARRAY_SIZE(ssp_parent_names), CLK_SET_RATE_PARENT, PXA1928_CLK_SSP0 * 4, 4, 3, 0, &ssp0_lock},
+       {0, "ssp1_mux", ssp_parent_names, ARRAY_SIZE(ssp_parent_names), CLK_SET_RATE_PARENT, PXA1928_CLK_SSP1 * 4, 4, 3, 0, &ssp1_lock},
+};
+
+static struct mmp_param_gate_clk apbc_gate_clks[] = {
+       {PXA1928_CLK_TWSI0, "twsi0_clk", "vctcxo", CLK_SET_RATE_PARENT, PXA1928_CLK_TWSI0 * 4, 0x3, 0x3, 0x0, 0, &reset_lock},
+       {PXA1928_CLK_TWSI1, "twsi1_clk", "vctcxo", CLK_SET_RATE_PARENT, PXA1928_CLK_TWSI1 * 4, 0x3, 0x3, 0x0, 0, &reset_lock},
+       {PXA1928_CLK_TWSI2, "twsi2_clk", "vctcxo", CLK_SET_RATE_PARENT, PXA1928_CLK_TWSI2 * 4, 0x3, 0x3, 0x0, 0, &reset_lock},
+       {PXA1928_CLK_TWSI3, "twsi3_clk", "vctcxo", CLK_SET_RATE_PARENT, PXA1928_CLK_TWSI3 * 4, 0x3, 0x3, 0x0, 0, &reset_lock},
+       {PXA1928_CLK_TWSI4, "twsi4_clk", "vctcxo", CLK_SET_RATE_PARENT, PXA1928_CLK_TWSI4 * 4, 0x3, 0x3, 0x0, 0, &reset_lock},
+       {PXA1928_CLK_TWSI5, "twsi5_clk", "vctcxo", CLK_SET_RATE_PARENT, PXA1928_CLK_TWSI5 * 4, 0x3, 0x3, 0x0, 0, &reset_lock},
+       {PXA1928_CLK_GPIO, "gpio_clk", "vctcxo", CLK_SET_RATE_PARENT, PXA1928_CLK_GPIO * 4, 0x3, 0x3, 0x0, 0, &reset_lock},
+       {PXA1928_CLK_KPC, "kpc_clk", "clk32", CLK_SET_RATE_PARENT, PXA1928_CLK_KPC * 4, 0x3, 0x3, 0x0, MMP_CLK_GATE_NEED_DELAY, NULL},
+       {PXA1928_CLK_RTC, "rtc_clk", "clk32", CLK_SET_RATE_PARENT, PXA1928_CLK_RTC * 4, 0x83, 0x83, 0x0, MMP_CLK_GATE_NEED_DELAY, NULL},
+       {PXA1928_CLK_PWM0, "pwm0_clk", "vctcxo", CLK_SET_RATE_PARENT, PXA1928_CLK_PWM0 * 4, 0x3, 0x3, 0x0, 0, &reset_lock},
+       {PXA1928_CLK_PWM1, "pwm1_clk", "vctcxo", CLK_SET_RATE_PARENT, PXA1928_CLK_PWM1 * 4, 0x3, 0x3, 0x0, 0, &reset_lock},
+       {PXA1928_CLK_PWM2, "pwm2_clk", "vctcxo", CLK_SET_RATE_PARENT, PXA1928_CLK_PWM2 * 4, 0x3, 0x3, 0x0, 0, &reset_lock},
+       {PXA1928_CLK_PWM3, "pwm3_clk", "vctcxo", CLK_SET_RATE_PARENT, PXA1928_CLK_PWM3 * 4, 0x3, 0x3, 0x0, 0, &reset_lock},
+       /* The gate clocks has mux parent. */
+       {PXA1928_CLK_UART0, "uart0_clk", "uart0_mux", CLK_SET_RATE_PARENT, PXA1928_CLK_UART0 * 4, 0x3, 0x3, 0x0, 0, &uart0_lock},
+       {PXA1928_CLK_UART1, "uart1_clk", "uart1_mux", CLK_SET_RATE_PARENT, PXA1928_CLK_UART1 * 4, 0x3, 0x3, 0x0, 0, &uart1_lock},
+       {PXA1928_CLK_UART2, "uart2_clk", "uart2_mux", CLK_SET_RATE_PARENT, PXA1928_CLK_UART2 * 4, 0x3, 0x3, 0x0, 0, &uart2_lock},
+       {PXA1928_CLK_UART3, "uart3_clk", "uart3_mux", CLK_SET_RATE_PARENT, PXA1928_CLK_UART3 * 4, 0x3, 0x3, 0x0, 0, &uart3_lock},
+       {PXA1928_CLK_SSP0, "ssp0_clk", "ssp0_mux", CLK_SET_RATE_PARENT, PXA1928_CLK_SSP0 * 4, 0x3, 0x3, 0x0, 0, &ssp0_lock},
+       {PXA1928_CLK_SSP1, "ssp1_clk", "ssp1_mux", CLK_SET_RATE_PARENT, PXA1928_CLK_SSP1 * 4, 0x3, 0x3, 0x0, 0, &ssp1_lock},
+};
+
+static void pxa1928_apb_periph_clk_init(struct pxa1928_clk_unit *pxa_unit)
+{
+       struct mmp_clk_unit *unit = &pxa_unit->unit;
+
+       mmp_register_mux_clks(unit, apbc_mux_clks, pxa_unit->apbc_base,
+                               ARRAY_SIZE(apbc_mux_clks));
+
+       mmp_register_gate_clks(unit, apbc_gate_clks, pxa_unit->apbc_base,
+                               ARRAY_SIZE(apbc_gate_clks));
+}
+
+static DEFINE_SPINLOCK(sdh0_lock);
+static DEFINE_SPINLOCK(sdh1_lock);
+static DEFINE_SPINLOCK(sdh2_lock);
+static DEFINE_SPINLOCK(sdh3_lock);
+static DEFINE_SPINLOCK(sdh4_lock);
+static const char *sdh_parent_names[] = {"pll1_624", "pll5p", "pll5", "pll1_416"};
+
+static DEFINE_SPINLOCK(usb_lock);
+
+static struct mmp_param_mux_clk apmu_mux_clks[] = {
+       {0, "sdh_mux", sdh_parent_names, ARRAY_SIZE(sdh_parent_names), CLK_SET_RATE_PARENT, PXA1928_CLK_SDH0 * 4, 8, 2, 0, &sdh0_lock},
+};
+
+static struct mmp_param_div_clk apmu_div_clks[] = {
+       {0, "sdh_div", "sdh_mux", 0, PXA1928_CLK_SDH0 * 4, 10, 4, CLK_DIVIDER_ONE_BASED, &sdh0_lock},
+};
+
+static struct mmp_param_gate_clk apmu_gate_clks[] = {
+       {PXA1928_CLK_USB, "usb_clk", "usb_pll", 0, PXA1928_CLK_USB * 4, 0x9, 0x9, 0x0, 0, &usb_lock},
+       {PXA1928_CLK_HSIC, "hsic_clk", "usb_pll", 0, PXA1928_CLK_HSIC * 4, 0x9, 0x9, 0x0, 0, &usb_lock},
+       /* The gate clocks has mux parent. */
+       {PXA1928_CLK_SDH0, "sdh0_clk", "sdh_div", CLK_SET_RATE_PARENT, PXA1928_CLK_SDH0 * 4, 0x1b, 0x1b, 0x0, 0, &sdh0_lock},
+       {PXA1928_CLK_SDH1, "sdh1_clk", "sdh_div", CLK_SET_RATE_PARENT, PXA1928_CLK_SDH1 * 4, 0x1b, 0x1b, 0x0, 0, &sdh1_lock},
+       {PXA1928_CLK_SDH2, "sdh2_clk", "sdh_div", CLK_SET_RATE_PARENT, PXA1928_CLK_SDH2 * 4, 0x1b, 0x1b, 0x0, 0, &sdh2_lock},
+       {PXA1928_CLK_SDH3, "sdh3_clk", "sdh_div", CLK_SET_RATE_PARENT, PXA1928_CLK_SDH3 * 4, 0x1b, 0x1b, 0x0, 0, &sdh3_lock},
+       {PXA1928_CLK_SDH4, "sdh4_clk", "sdh_div", CLK_SET_RATE_PARENT, PXA1928_CLK_SDH4 * 4, 0x1b, 0x1b, 0x0, 0, &sdh4_lock},
+};
+
+static void pxa1928_axi_periph_clk_init(struct pxa1928_clk_unit *pxa_unit)
+{
+       struct mmp_clk_unit *unit = &pxa_unit->unit;
+
+       mmp_register_mux_clks(unit, apmu_mux_clks, pxa_unit->apmu_base,
+                               ARRAY_SIZE(apmu_mux_clks));
+
+       mmp_register_div_clks(unit, apmu_div_clks, pxa_unit->apmu_base,
+                               ARRAY_SIZE(apmu_div_clks));
+
+       mmp_register_gate_clks(unit, apmu_gate_clks, pxa_unit->apmu_base,
+                               ARRAY_SIZE(apmu_gate_clks));
+}
+
+static void pxa1928_clk_reset_init(struct device_node *np,
+                               struct pxa1928_clk_unit *pxa_unit)
+{
+       struct mmp_clk_reset_cell *cells;
+       int i, base, nr_resets;
+
+       nr_resets = ARRAY_SIZE(apbc_gate_clks);
+       cells = kcalloc(nr_resets, sizeof(*cells), GFP_KERNEL);
+       if (!cells)
+               return;
+
+       base = 0;
+       for (i = 0; i < nr_resets; i++) {
+               cells[base + i].clk_id = apbc_gate_clks[i].id;
+               cells[base + i].reg =
+                       pxa_unit->apbc_base + apbc_gate_clks[i].offset;
+               cells[base + i].flags = 0;
+               cells[base + i].lock = apbc_gate_clks[i].lock;
+               cells[base + i].bits = 0x4;
+       }
+
+       mmp_clk_reset_register(np, cells, nr_resets);
+}
+
+static void __init pxa1928_mpmu_clk_init(struct device_node *np)
+{
+       struct pxa1928_clk_unit *pxa_unit;
+
+       pxa_unit = kzalloc(sizeof(*pxa_unit), GFP_KERNEL);
+       if (!pxa_unit)
+               return;
+
+       pxa_unit->mpmu_base = of_iomap(np, 0);
+       if (!pxa_unit->mpmu_base) {
+               pr_err("failed to map mpmu registers\n");
+               return;
+       }
+
+       pxa1928_pll_init(pxa_unit);
+}
+CLK_OF_DECLARE(pxa1928_mpmu_clk, "marvell,pxa1928-mpmu", pxa1928_mpmu_clk_init);
+
+static void __init pxa1928_apmu_clk_init(struct device_node *np)
+{
+       struct pxa1928_clk_unit *pxa_unit;
+
+       pxa_unit = kzalloc(sizeof(*pxa_unit), GFP_KERNEL);
+       if (!pxa_unit)
+               return;
+
+       pxa_unit->apmu_base = of_iomap(np, 0);
+       if (!pxa_unit->apmu_base) {
+               pr_err("failed to map apmu registers\n");
+               return;
+       }
+
+       mmp_clk_init(np, &pxa_unit->unit, PXA1928_APMU_NR_CLKS);
+
+       pxa1928_axi_periph_clk_init(pxa_unit);
+}
+CLK_OF_DECLARE(pxa1928_apmu_clk, "marvell,pxa1928-apmu", pxa1928_apmu_clk_init);
+
+static void __init pxa1928_apbc_clk_init(struct device_node *np)
+{
+       struct pxa1928_clk_unit *pxa_unit;
+
+       pxa_unit = kzalloc(sizeof(*pxa_unit), GFP_KERNEL);
+       if (!pxa_unit)
+               return;
+
+       pxa_unit->apbc_base = of_iomap(np, 0);
+       if (!pxa_unit->apbc_base) {
+               pr_err("failed to map apbc registers\n");
+               return;
+       }
+
+       mmp_clk_init(np, &pxa_unit->unit, PXA1928_APBC_NR_CLKS);
+
+       pxa1928_apb_periph_clk_init(pxa_unit);
+       pxa1928_clk_reset_init(np, pxa_unit);
+}
+CLK_OF_DECLARE(pxa1928_apbc_clk, "marvell,pxa1928-apbc", pxa1928_apbc_clk_init);
index 5e3c80dad336e0ea1857f39be3ccccadf7b947f8..13d6173326a435ad46af652f27bfc20e32302e04 100644 (file)
@@ -35,6 +35,8 @@
 #define APBC_SSP0      0x1c
 #define APBC_SSP1      0x20
 #define APBC_SSP2      0x4c
+#define APBC_TIMER0    0x30
+#define APBC_TIMER1    0x44
 #define APBCP_TWSI1    0x28
 #define APBCP_UART2    0x1c
 #define APMU_SDH0      0x54
@@ -57,6 +59,7 @@ static struct mmp_param_fixed_rate_clk fixed_rate_clks[] = {
        {PXA910_CLK_CLK32, "clk32", NULL, CLK_IS_ROOT, 32768},
        {PXA910_CLK_VCTCXO, "vctcxo", NULL, CLK_IS_ROOT, 26000000},
        {PXA910_CLK_PLL1, "pll1", NULL, CLK_IS_ROOT, 624000000},
+       {PXA910_CLK_USB_PLL, "usb_pll", NULL, CLK_IS_ROOT, 480000000},
 };
 
 static struct mmp_param_fixed_factor_clk fixed_factor_clks[] = {
@@ -69,6 +72,7 @@ static struct mmp_param_fixed_factor_clk fixed_factor_clks[] = {
        {PXA910_CLK_PLL1_24, "pll1_24", "pll1_12", 1, 2, 0},
        {PXA910_CLK_PLL1_48, "pll1_48", "pll1_24", 1, 2, 0},
        {PXA910_CLK_PLL1_96, "pll1_96", "pll1_48", 1, 2, 0},
+       {PXA910_CLK_PLL1_192, "pll1_192", "pll1_96", 1, 2, 0},
        {PXA910_CLK_PLL1_13, "pll1_13", "pll1", 1, 13, 0},
        {PXA910_CLK_PLL1_13_1_5, "pll1_13_1_5", "pll1_13", 2, 3, 0},
        {PXA910_CLK_PLL1_2_1_5, "pll1_2_1_5", "pll1_2", 2, 3, 0},
@@ -115,6 +119,10 @@ static DEFINE_SPINLOCK(ssp0_lock);
 static DEFINE_SPINLOCK(ssp1_lock);
 static const char *ssp_parent_names[] = {"pll1_96", "pll1_48", "pll1_24", "pll1_12"};
 
+static DEFINE_SPINLOCK(timer0_lock);
+static DEFINE_SPINLOCK(timer1_lock);
+static const char *timer_parent_names[] = {"pll1_48", "clk32", "pll1_96"};
+
 static DEFINE_SPINLOCK(reset_lock);
 
 static struct mmp_param_mux_clk apbc_mux_clks[] = {
@@ -122,6 +130,8 @@ static struct mmp_param_mux_clk apbc_mux_clks[] = {
        {0, "uart1_mux", uart_parent_names, ARRAY_SIZE(uart_parent_names), CLK_SET_RATE_PARENT, APBC_UART1, 4, 3, 0, &uart1_lock},
        {0, "ssp0_mux", ssp_parent_names, ARRAY_SIZE(ssp_parent_names), CLK_SET_RATE_PARENT, APBC_SSP0, 4, 3, 0, &ssp0_lock},
        {0, "ssp1_mux", ssp_parent_names, ARRAY_SIZE(ssp_parent_names), CLK_SET_RATE_PARENT, APBC_SSP1, 4, 3, 0, &ssp1_lock},
+       {0, "timer0_mux", timer_parent_names, ARRAY_SIZE(timer_parent_names), CLK_SET_RATE_PARENT, APBC_TIMER0, 4, 3, 0, &timer0_lock},
+       {0, "timer1_mux", timer_parent_names, ARRAY_SIZE(timer_parent_names), CLK_SET_RATE_PARENT, APBC_TIMER1, 4, 3, 0, &timer1_lock},
 };
 
 static struct mmp_param_mux_clk apbcp_mux_clks[] = {
@@ -142,6 +152,8 @@ static struct mmp_param_gate_clk apbc_gate_clks[] = {
        {PXA910_CLK_UART1, "uart1_clk", "uart1_mux", CLK_SET_RATE_PARENT, APBC_UART1, 0x3, 0x3, 0x0, 0, &uart1_lock},
        {PXA910_CLK_SSP0, "ssp0_clk", "ssp0_mux", CLK_SET_RATE_PARENT, APBC_SSP0, 0x3, 0x3, 0x0, 0, &ssp0_lock},
        {PXA910_CLK_SSP1, "ssp1_clk", "ssp1_mux", CLK_SET_RATE_PARENT, APBC_SSP1, 0x3, 0x3, 0x0, 0, &ssp1_lock},
+       {PXA910_CLK_TIMER0, "timer0_clk", "timer0_mux", CLK_SET_RATE_PARENT, APBC_TIMER0, 0x3, 0x3, 0x0, 0, &timer0_lock},
+       {PXA910_CLK_TIMER1, "timer1_clk", "timer1_mux", CLK_SET_RATE_PARENT, APBC_TIMER1, 0x3, 0x3, 0x0, 0, &timer1_lock},
 };
 
 static struct mmp_param_gate_clk apbcp_gate_clks[] = {
index 756f0f39d6a3d9f4d3ffcd19a9eae6166c7ba3e3..2c7c1085f88300ca84ac529831876af25376a047 100644 (file)
@@ -163,6 +163,7 @@ static const struct clk_gating_soc_desc a370_gating_desc[] __initconst = {
        { "pex1", "pex1_en", 9, 0 },
        { "sata0", NULL, 15, 0 },
        { "sdio", NULL, 17, 0 },
+       { "crypto", NULL, 23, CLK_IGNORE_UNUSED },
        { "tdm", NULL, 25, 0 },
        { "ddr", NULL, 28, CLK_IGNORE_UNUSED },
        { "sata1", NULL, 30, 0 },
index 22d136aa699ff1b15a73247e183d4a81d98726c7..32216f9b7f03e9b5540106d29c842cd68cf9b60a 100644 (file)
@@ -77,12 +77,12 @@ static void __init clk_misc_init(void)
        writel_relaxed(30 << BP_FRAC_IOFRAC, FRAC + SET);
 }
 
-static const char *sel_pll[]  __initdata = { "pll", "ref_xtal", };
-static const char *sel_cpu[]  __initdata = { "ref_cpu", "ref_xtal", };
-static const char *sel_pix[]  __initdata = { "ref_pix", "ref_xtal", };
-static const char *sel_io[]   __initdata = { "ref_io", "ref_xtal", };
-static const char *cpu_sels[] __initdata = { "cpu_pll", "cpu_xtal", };
-static const char *emi_sels[] __initdata = { "emi_pll", "emi_xtal", };
+static const char *const sel_pll[]  __initconst = { "pll", "ref_xtal", };
+static const char *const sel_cpu[]  __initconst = { "ref_cpu", "ref_xtal", };
+static const char *const sel_pix[]  __initconst = { "ref_pix", "ref_xtal", };
+static const char *const sel_io[]   __initconst = { "ref_io", "ref_xtal", };
+static const char *const cpu_sels[] __initconst = { "cpu_pll", "cpu_xtal", };
+static const char *const emi_sels[] __initconst = { "emi_pll", "emi_xtal", };
 
 enum imx23_clk {
        ref_xtal, pll, ref_cpu, ref_emi, ref_pix, ref_io, saif_sel,
index b1be3746ce958dad95fe396c0621b3f4ae248b29..a68670868baacd42686b4ce61471838b02ee4905 100644 (file)
@@ -125,15 +125,15 @@ static void __init clk_misc_init(void)
        writel_relaxed(val, FRAC0);
 }
 
-static const char *sel_cpu[]  __initdata = { "ref_cpu", "ref_xtal", };
-static const char *sel_io0[]  __initdata = { "ref_io0", "ref_xtal", };
-static const char *sel_io1[]  __initdata = { "ref_io1", "ref_xtal", };
-static const char *sel_pix[]  __initdata = { "ref_pix", "ref_xtal", };
-static const char *sel_gpmi[] __initdata = { "ref_gpmi", "ref_xtal", };
-static const char *sel_pll0[] __initdata = { "pll0", "ref_xtal", };
-static const char *cpu_sels[] __initdata = { "cpu_pll", "cpu_xtal", };
-static const char *emi_sels[] __initdata = { "emi_pll", "emi_xtal", };
-static const char *ptp_sels[] __initdata = { "ref_xtal", "pll0", };
+static const char *const sel_cpu[]  __initconst = { "ref_cpu", "ref_xtal", };
+static const char *const sel_io0[]  __initconst = { "ref_io0", "ref_xtal", };
+static const char *const sel_io1[]  __initconst = { "ref_io1", "ref_xtal", };
+static const char *const sel_pix[]  __initconst = { "ref_pix", "ref_xtal", };
+static const char *const sel_gpmi[] __initconst = { "ref_gpmi", "ref_xtal", };
+static const char *const sel_pll0[] __initconst = { "pll0", "ref_xtal", };
+static const char *const cpu_sels[] __initconst = { "cpu_pll", "cpu_xtal", };
+static const char *const emi_sels[] __initconst = { "emi_pll", "emi_xtal", };
+static const char *const ptp_sels[] __initconst = { "ref_xtal", "pll0", };
 
 enum imx28_clk {
        ref_xtal, pll0, pll1, pll2, ref_cpu, ref_emi, ref_io0, ref_io1,
index ef10ad9b5daa0b48601670d0e40fe3d01da60dfa..f07d821dd75d5d4a9318d5976c6c84938e3420f9 100644 (file)
@@ -49,7 +49,7 @@ static inline struct clk *mxs_clk_gate(const char *name,
 }
 
 static inline struct clk *mxs_clk_mux(const char *name, void __iomem *reg,
-               u8 shift, u8 width, const char **parent_names, int num_parents)
+               u8 shift, u8 width, const char *const *parent_names, int num_parents)
 {
        return clk_register_mux(NULL, name, parent_names, num_parents,
                                CLK_SET_RATE_PARENT | CLK_SET_RATE_NO_REPARENT,
diff --git a/drivers/clk/nxp/Makefile b/drivers/clk/nxp/Makefile
new file mode 100644 (file)
index 0000000..7f608b0
--- /dev/null
@@ -0,0 +1,2 @@
+obj-$(CONFIG_ARCH_LPC18XX)     += clk-lpc18xx-cgu.o
+obj-$(CONFIG_ARCH_LPC18XX)     += clk-lpc18xx-ccu.o
diff --git a/drivers/clk/nxp/clk-lpc18xx-ccu.c b/drivers/clk/nxp/clk-lpc18xx-ccu.c
new file mode 100644 (file)
index 0000000..eeaee97
--- /dev/null
@@ -0,0 +1,293 @@
+/*
+ * Clk driver for NXP LPC18xx/LPC43xx Clock Control Unit (CCU)
+ *
+ * Copyright (C) 2015 Joachim Eastwood <manabian@gmail.com>
+ *
+ * This file is licensed under the terms of the GNU General Public
+ * License version 2. This program is licensed "as is" without any
+ * warranty of any kind, whether express or implied.
+ */
+
+#include <linux/clk.h>
+#include <linux/clk-provider.h>
+#include <linux/kernel.h>
+#include <linux/of.h>
+#include <linux/of_address.h>
+#include <linux/slab.h>
+#include <linux/string.h>
+
+#include <dt-bindings/clock/lpc18xx-ccu.h>
+
+/* Bit defines for CCU branch configuration register */
+#define LPC18XX_CCU_RUN                BIT(0)
+#define LPC18XX_CCU_AUTO       BIT(1)
+#define LPC18XX_CCU_DIV                BIT(5)
+#define LPC18XX_CCU_DIVSTAT    BIT(27)
+
+/* CCU branch feature bits */
+#define CCU_BRANCH_IS_BUS      BIT(0)
+#define CCU_BRANCH_HAVE_DIV2   BIT(1)
+
+#define to_clk_gate(_hw) container_of(_hw, struct clk_gate, hw)
+
+struct lpc18xx_branch_clk_data {
+       const char **name;
+       int num;
+};
+
+struct lpc18xx_clk_branch {
+       const char *base_name;
+       const char *name;
+       u16 offset;
+       u16 flags;
+       struct clk *clk;
+       struct clk_gate gate;
+};
+
+static struct lpc18xx_clk_branch clk_branches[] = {
+       {"base_apb3_clk", "apb3_bus",           CLK_APB3_BUS,           CCU_BRANCH_IS_BUS},
+       {"base_apb3_clk", "apb3_i2c1",          CLK_APB3_I2C1,          0},
+       {"base_apb3_clk", "apb3_dac",           CLK_APB3_DAC,           0},
+       {"base_apb3_clk", "apb3_adc0",          CLK_APB3_ADC0,          0},
+       {"base_apb3_clk", "apb3_adc1",          CLK_APB3_ADC1,          0},
+       {"base_apb3_clk", "apb3_can0",          CLK_APB3_CAN0,          0},
+
+       {"base_apb1_clk", "apb1_bus",           CLK_APB1_BUS,           CCU_BRANCH_IS_BUS},
+       {"base_apb1_clk", "apb1_mc_pwm",        CLK_APB1_MOTOCON_PWM,   0},
+       {"base_apb1_clk", "apb1_i2c0",          CLK_APB1_I2C0,          0},
+       {"base_apb1_clk", "apb1_i2s",           CLK_APB1_I2S,           0},
+       {"base_apb1_clk", "apb1_can1",          CLK_APB1_CAN1,          0},
+
+       {"base_spifi_clk", "spifi",             CLK_SPIFI,              0},
+
+       {"base_cpu_clk", "cpu_bus",             CLK_CPU_BUS,            CCU_BRANCH_IS_BUS},
+       {"base_cpu_clk", "cpu_spifi",           CLK_CPU_SPIFI,          0},
+       {"base_cpu_clk", "cpu_gpio",            CLK_CPU_GPIO,           0},
+       {"base_cpu_clk", "cpu_lcd",             CLK_CPU_LCD,            0},
+       {"base_cpu_clk", "cpu_ethernet",        CLK_CPU_ETHERNET,       0},
+       {"base_cpu_clk", "cpu_usb0",            CLK_CPU_USB0,           0},
+       {"base_cpu_clk", "cpu_emc",             CLK_CPU_EMC,            0},
+       {"base_cpu_clk", "cpu_sdio",            CLK_CPU_SDIO,           0},
+       {"base_cpu_clk", "cpu_dma",             CLK_CPU_DMA,            0},
+       {"base_cpu_clk", "cpu_core",            CLK_CPU_CORE,           0},
+       {"base_cpu_clk", "cpu_sct",             CLK_CPU_SCT,            0},
+       {"base_cpu_clk", "cpu_usb1",            CLK_CPU_USB1,           0},
+       {"base_cpu_clk", "cpu_emcdiv",          CLK_CPU_EMCDIV,         CCU_BRANCH_HAVE_DIV2},
+       {"base_cpu_clk", "cpu_flasha",          CLK_CPU_FLASHA,         CCU_BRANCH_HAVE_DIV2},
+       {"base_cpu_clk", "cpu_flashb",          CLK_CPU_FLASHB,         CCU_BRANCH_HAVE_DIV2},
+       {"base_cpu_clk", "cpu_m0app",           CLK_CPU_M0APP,          CCU_BRANCH_HAVE_DIV2},
+       {"base_cpu_clk", "cpu_adchs",           CLK_CPU_ADCHS,          CCU_BRANCH_HAVE_DIV2},
+       {"base_cpu_clk", "cpu_eeprom",          CLK_CPU_EEPROM,         CCU_BRANCH_HAVE_DIV2},
+       {"base_cpu_clk", "cpu_wwdt",            CLK_CPU_WWDT,           0},
+       {"base_cpu_clk", "cpu_uart0",           CLK_CPU_UART0,          0},
+       {"base_cpu_clk", "cpu_uart1",           CLK_CPU_UART1,          0},
+       {"base_cpu_clk", "cpu_ssp0",            CLK_CPU_SSP0,           0},
+       {"base_cpu_clk", "cpu_timer0",          CLK_CPU_TIMER0,         0},
+       {"base_cpu_clk", "cpu_timer1",          CLK_CPU_TIMER1,         0},
+       {"base_cpu_clk", "cpu_scu",             CLK_CPU_SCU,            0},
+       {"base_cpu_clk", "cpu_creg",            CLK_CPU_CREG,           0},
+       {"base_cpu_clk", "cpu_ritimer",         CLK_CPU_RITIMER,        0},
+       {"base_cpu_clk", "cpu_uart2",           CLK_CPU_UART2,          0},
+       {"base_cpu_clk", "cpu_uart3",           CLK_CPU_UART3,          0},
+       {"base_cpu_clk", "cpu_timer2",          CLK_CPU_TIMER2,         0},
+       {"base_cpu_clk", "cpu_timer3",          CLK_CPU_TIMER3,         0},
+       {"base_cpu_clk", "cpu_ssp1",            CLK_CPU_SSP1,           0},
+       {"base_cpu_clk", "cpu_qei",             CLK_CPU_QEI,            0},
+
+       {"base_periph_clk", "periph_bus",       CLK_PERIPH_BUS,         CCU_BRANCH_IS_BUS},
+       {"base_periph_clk", "periph_core",      CLK_PERIPH_CORE,        0},
+       {"base_periph_clk", "periph_sgpio",     CLK_PERIPH_SGPIO,       0},
+
+       {"base_usb0_clk",  "usb0",              CLK_USB0,               0},
+       {"base_usb1_clk",  "usb1",              CLK_USB1,               0},
+       {"base_spi_clk",   "spi",               CLK_SPI,                0},
+       {"base_adchs_clk", "adchs",             CLK_ADCHS,              0},
+
+       {"base_audio_clk", "audio",             CLK_AUDIO,              0},
+       {"base_uart3_clk", "apb2_uart3",        CLK_APB2_UART3,         0},
+       {"base_uart2_clk", "apb2_uart2",        CLK_APB2_UART2,         0},
+       {"base_uart1_clk", "apb0_uart1",        CLK_APB0_UART1,         0},
+       {"base_uart0_clk", "apb0_uart0",        CLK_APB0_UART0,         0},
+       {"base_ssp1_clk",  "apb2_ssp1",         CLK_APB2_SSP1,          0},
+       {"base_ssp0_clk",  "apb0_ssp0",         CLK_APB0_SSP0,          0},
+       {"base_sdio_clk",  "sdio",              CLK_SDIO,               0},
+};
+
+static struct clk *lpc18xx_ccu_branch_clk_get(struct of_phandle_args *clkspec,
+                                             void *data)
+{
+       struct lpc18xx_branch_clk_data *clk_data = data;
+       unsigned int offset = clkspec->args[0];
+       int i, j;
+
+       for (i = 0; i < ARRAY_SIZE(clk_branches); i++) {
+               if (clk_branches[i].offset != offset)
+                       continue;
+
+               for (j = 0; j < clk_data->num; j++) {
+                       if (!strcmp(clk_branches[i].base_name, clk_data->name[j]))
+                               return clk_branches[i].clk;
+               }
+       }
+
+       pr_err("%s: invalid clock offset %d\n", __func__, offset);
+
+       return ERR_PTR(-EINVAL);
+}
+
+static int lpc18xx_ccu_gate_endisable(struct clk_hw *hw, bool enable)
+{
+       struct clk_gate *gate = to_clk_gate(hw);
+       u32 val;
+
+       /*
+        * Divider field is write only, so divider stat field must
+        * be read so divider field can be set accordingly.
+        */
+       val = clk_readl(gate->reg);
+       if (val & LPC18XX_CCU_DIVSTAT)
+               val |= LPC18XX_CCU_DIV;
+
+       if (enable) {
+               val |= LPC18XX_CCU_RUN;
+       } else {
+               /*
+                * To safely disable a branch clock a squence of two separate
+                * writes must be used. First write should set the AUTO bit
+                * and the next write should clear the RUN bit.
+                */
+               val |= LPC18XX_CCU_AUTO;
+               clk_writel(val, gate->reg);
+
+               val &= ~LPC18XX_CCU_RUN;
+       }
+
+       clk_writel(val, gate->reg);
+
+       return 0;
+}
+
+static int lpc18xx_ccu_gate_enable(struct clk_hw *hw)
+{
+       return lpc18xx_ccu_gate_endisable(hw, true);
+}
+
+static void lpc18xx_ccu_gate_disable(struct clk_hw *hw)
+{
+       lpc18xx_ccu_gate_endisable(hw, false);
+}
+
+static int lpc18xx_ccu_gate_is_enabled(struct clk_hw *hw)
+{
+       struct clk_gate *gate = to_clk_gate(hw);
+
+       return clk_readl(gate->reg) & LPC18XX_CCU_RUN;
+}
+
+static const struct clk_ops lpc18xx_ccu_gate_ops = {
+       .enable         = lpc18xx_ccu_gate_enable,
+       .disable        = lpc18xx_ccu_gate_disable,
+       .is_enabled     = lpc18xx_ccu_gate_is_enabled,
+};
+
+static void lpc18xx_ccu_register_branch_gate_div(struct lpc18xx_clk_branch *branch,
+                                                void __iomem *reg_base,
+                                                const char *parent)
+{
+       const struct clk_ops *div_ops = NULL;
+       struct clk_divider *div = NULL;
+       struct clk_hw *div_hw = NULL;
+
+       if (branch->flags & CCU_BRANCH_HAVE_DIV2) {
+               div = kzalloc(sizeof(*div), GFP_KERNEL);
+               if (!div)
+                       return;
+
+               div->reg = branch->offset + reg_base;
+               div->flags = CLK_DIVIDER_READ_ONLY;
+               div->shift = 27;
+               div->width = 1;
+
+               div_hw = &div->hw;
+               div_ops = &clk_divider_ops;
+       }
+
+       branch->gate.reg = branch->offset + reg_base;
+       branch->gate.bit_idx = 0;
+
+       branch->clk = clk_register_composite(NULL, branch->name, &parent, 1,
+                                            NULL, NULL,
+                                            div_hw, div_ops,
+                                            &branch->gate.hw, &lpc18xx_ccu_gate_ops, 0);
+       if (IS_ERR(branch->clk)) {
+               kfree(div);
+               pr_warn("%s: failed to register %s\n", __func__, branch->name);
+               return;
+       }
+
+       /* Grab essential branch clocks for CPU and SDRAM */
+       switch (branch->offset) {
+       case CLK_CPU_EMC:
+       case CLK_CPU_CORE:
+       case CLK_CPU_CREG:
+       case CLK_CPU_EMCDIV:
+               clk_prepare_enable(branch->clk);
+       }
+}
+
+static void lpc18xx_ccu_register_branch_clks(void __iomem *reg_base,
+                                            const char *base_name)
+{
+       const char *parent = base_name;
+       int i;
+
+       for (i = 0; i < ARRAY_SIZE(clk_branches); i++) {
+               if (strcmp(clk_branches[i].base_name, base_name))
+                       continue;
+
+               lpc18xx_ccu_register_branch_gate_div(&clk_branches[i], reg_base,
+                                                    parent);
+
+               if (clk_branches[i].flags & CCU_BRANCH_IS_BUS)
+                       parent = clk_branches[i].name;
+       }
+}
+
+static void __init lpc18xx_ccu_init(struct device_node *np)
+{
+       struct lpc18xx_branch_clk_data *clk_data;
+       void __iomem *reg_base;
+       int i, ret;
+
+       reg_base = of_iomap(np, 0);
+       if (!reg_base) {
+               pr_warn("%s: failed to map address range\n", __func__);
+               return;
+       }
+
+       clk_data = kzalloc(sizeof(*clk_data), GFP_KERNEL);
+       if (!clk_data)
+               return;
+
+       clk_data->num = of_property_count_strings(np, "clock-names");
+       clk_data->name = kcalloc(clk_data->num, sizeof(char *), GFP_KERNEL);
+       if (!clk_data->name) {
+               kfree(clk_data);
+               return;
+       }
+
+       for (i = 0; i < clk_data->num; i++) {
+               ret = of_property_read_string_index(np, "clock-names", i,
+                                                   &clk_data->name[i]);
+               if (ret) {
+                       pr_warn("%s: failed to get clock name at idx %d\n",
+                               __func__, i);
+                       continue;
+               }
+
+               lpc18xx_ccu_register_branch_clks(reg_base, clk_data->name[i]);
+       }
+
+       of_clk_add_provider(np, lpc18xx_ccu_branch_clk_get, clk_data);
+}
+CLK_OF_DECLARE(lpc18xx_ccu, "nxp,lpc1850-ccu", lpc18xx_ccu_init);
diff --git a/drivers/clk/nxp/clk-lpc18xx-cgu.c b/drivers/clk/nxp/clk-lpc18xx-cgu.c
new file mode 100644 (file)
index 0000000..81e9e1c
--- /dev/null
@@ -0,0 +1,635 @@
+/*
+ * Clk driver for NXP LPC18xx/LPC43xx Clock Generation Unit (CGU)
+ *
+ * Copyright (C) 2015 Joachim Eastwood <manabian@gmail.com>
+ *
+ * This file is licensed under the terms of the GNU General Public
+ * License version 2. This program is licensed "as is" without any
+ * warranty of any kind, whether express or implied.
+ */
+
+#include <linux/clk.h>
+#include <linux/clk-provider.h>
+#include <linux/delay.h>
+#include <linux/kernel.h>
+#include <linux/of.h>
+#include <linux/of_address.h>
+
+#include <dt-bindings/clock/lpc18xx-cgu.h>
+
+/* Clock Generation Unit (CGU) registers */
+#define LPC18XX_CGU_XTAL_OSC_CTRL      0x018
+#define LPC18XX_CGU_PLL0USB_STAT       0x01c
+#define LPC18XX_CGU_PLL0USB_CTRL       0x020
+#define LPC18XX_CGU_PLL0USB_MDIV       0x024
+#define LPC18XX_CGU_PLL0USB_NP_DIV     0x028
+#define LPC18XX_CGU_PLL0AUDIO_STAT     0x02c
+#define LPC18XX_CGU_PLL0AUDIO_CTRL     0x030
+#define LPC18XX_CGU_PLL0AUDIO_MDIV     0x034
+#define LPC18XX_CGU_PLL0AUDIO_NP_DIV   0x038
+#define LPC18XX_CGU_PLL0AUDIO_FRAC     0x03c
+#define LPC18XX_CGU_PLL1_STAT          0x040
+#define LPC18XX_CGU_PLL1_CTRL          0x044
+#define  LPC18XX_PLL1_CTRL_FBSEL       BIT(6)
+#define  LPC18XX_PLL1_CTRL_DIRECT      BIT(7)
+#define LPC18XX_CGU_IDIV_CTRL(n)       (0x048 + (n) * sizeof(u32))
+#define LPC18XX_CGU_BASE_CLK(id)       (0x05c + (id) * sizeof(u32))
+#define LPC18XX_CGU_PLL_CTRL_OFFSET    0x4
+
+/* PLL0 bits common to both audio and USB PLL */
+#define LPC18XX_PLL0_STAT_LOCK         BIT(0)
+#define LPC18XX_PLL0_CTRL_PD           BIT(0)
+#define LPC18XX_PLL0_CTRL_BYPASS       BIT(1)
+#define LPC18XX_PLL0_CTRL_DIRECTI      BIT(2)
+#define LPC18XX_PLL0_CTRL_DIRECTO      BIT(3)
+#define LPC18XX_PLL0_CTRL_CLKEN                BIT(4)
+#define LPC18XX_PLL0_MDIV_MDEC_MASK    0x1ffff
+#define LPC18XX_PLL0_MDIV_SELP_SHIFT   17
+#define LPC18XX_PLL0_MDIV_SELI_SHIFT   22
+#define LPC18XX_PLL0_MSEL_MAX          BIT(15)
+
+/* Register value that gives PLL0 post/pre dividers equal to 1 */
+#define LPC18XX_PLL0_NP_DIVS_1         0x00302062
+
+enum {
+       CLK_SRC_OSC32,
+       CLK_SRC_IRC,
+       CLK_SRC_ENET_RX_CLK,
+       CLK_SRC_ENET_TX_CLK,
+       CLK_SRC_GP_CLKIN,
+       CLK_SRC_RESERVED1,
+       CLK_SRC_OSC,
+       CLK_SRC_PLL0USB,
+       CLK_SRC_PLL0AUDIO,
+       CLK_SRC_PLL1,
+       CLK_SRC_RESERVED2,
+       CLK_SRC_RESERVED3,
+       CLK_SRC_IDIVA,
+       CLK_SRC_IDIVB,
+       CLK_SRC_IDIVC,
+       CLK_SRC_IDIVD,
+       CLK_SRC_IDIVE,
+       CLK_SRC_MAX
+};
+
+static const char *clk_src_names[CLK_SRC_MAX] = {
+       [CLK_SRC_OSC32]         = "osc32",
+       [CLK_SRC_IRC]           = "irc",
+       [CLK_SRC_ENET_RX_CLK]   = "enet_rx_clk",
+       [CLK_SRC_ENET_TX_CLK]   = "enet_tx_clk",
+       [CLK_SRC_GP_CLKIN]      = "gp_clkin",
+       [CLK_SRC_OSC]           = "osc",
+       [CLK_SRC_PLL0USB]       = "pll0usb",
+       [CLK_SRC_PLL0AUDIO]     = "pll0audio",
+       [CLK_SRC_PLL1]          = "pll1",
+       [CLK_SRC_IDIVA]         = "idiva",
+       [CLK_SRC_IDIVB]         = "idivb",
+       [CLK_SRC_IDIVC]         = "idivc",
+       [CLK_SRC_IDIVD]         = "idivd",
+       [CLK_SRC_IDIVE]         = "idive",
+};
+
+static const char *clk_base_names[BASE_CLK_MAX] = {
+       [BASE_SAFE_CLK]         = "base_safe_clk",
+       [BASE_USB0_CLK]         = "base_usb0_clk",
+       [BASE_PERIPH_CLK]       = "base_periph_clk",
+       [BASE_USB1_CLK]         = "base_usb1_clk",
+       [BASE_CPU_CLK]          = "base_cpu_clk",
+       [BASE_SPIFI_CLK]        = "base_spifi_clk",
+       [BASE_SPI_CLK]          = "base_spi_clk",
+       [BASE_PHY_RX_CLK]       = "base_phy_rx_clk",
+       [BASE_PHY_TX_CLK]       = "base_phy_tx_clk",
+       [BASE_APB1_CLK]         = "base_apb1_clk",
+       [BASE_APB3_CLK]         = "base_apb3_clk",
+       [BASE_LCD_CLK]          = "base_lcd_clk",
+       [BASE_ADCHS_CLK]        = "base_adchs_clk",
+       [BASE_SDIO_CLK]         = "base_sdio_clk",
+       [BASE_SSP0_CLK]         = "base_ssp0_clk",
+       [BASE_SSP1_CLK]         = "base_ssp1_clk",
+       [BASE_UART0_CLK]        = "base_uart0_clk",
+       [BASE_UART1_CLK]        = "base_uart1_clk",
+       [BASE_UART2_CLK]        = "base_uart2_clk",
+       [BASE_UART3_CLK]        = "base_uart3_clk",
+       [BASE_OUT_CLK]          = "base_out_clk",
+       [BASE_AUDIO_CLK]        = "base_audio_clk",
+       [BASE_CGU_OUT0_CLK]     = "base_cgu_out0_clk",
+       [BASE_CGU_OUT1_CLK]     = "base_cgu_out1_clk",
+};
+
+static u32 lpc18xx_cgu_pll0_src_ids[] = {
+       CLK_SRC_OSC32, CLK_SRC_IRC, CLK_SRC_ENET_RX_CLK,
+       CLK_SRC_ENET_TX_CLK, CLK_SRC_GP_CLKIN, CLK_SRC_OSC,
+       CLK_SRC_PLL1, CLK_SRC_IDIVA, CLK_SRC_IDIVB, CLK_SRC_IDIVC,
+       CLK_SRC_IDIVD, CLK_SRC_IDIVE,
+};
+
+static u32 lpc18xx_cgu_pll1_src_ids[] = {
+       CLK_SRC_OSC32, CLK_SRC_IRC, CLK_SRC_ENET_RX_CLK,
+       CLK_SRC_ENET_TX_CLK, CLK_SRC_GP_CLKIN, CLK_SRC_OSC,
+       CLK_SRC_PLL0USB, CLK_SRC_PLL0AUDIO, CLK_SRC_IDIVA,
+       CLK_SRC_IDIVB, CLK_SRC_IDIVC, CLK_SRC_IDIVD, CLK_SRC_IDIVE,
+};
+
+static u32 lpc18xx_cgu_idiva_src_ids[] = {
+       CLK_SRC_OSC32, CLK_SRC_IRC, CLK_SRC_ENET_RX_CLK,
+       CLK_SRC_ENET_TX_CLK, CLK_SRC_GP_CLKIN, CLK_SRC_OSC,
+       CLK_SRC_PLL0USB, CLK_SRC_PLL0AUDIO, CLK_SRC_PLL1
+};
+
+static u32 lpc18xx_cgu_idivbcde_src_ids[] = {
+       CLK_SRC_OSC32, CLK_SRC_IRC, CLK_SRC_ENET_RX_CLK,
+       CLK_SRC_ENET_TX_CLK, CLK_SRC_GP_CLKIN, CLK_SRC_OSC,
+       CLK_SRC_PLL0AUDIO, CLK_SRC_PLL1, CLK_SRC_IDIVA,
+};
+
+static u32 lpc18xx_cgu_base_irc_src_ids[] = {CLK_SRC_IRC};
+
+static u32 lpc18xx_cgu_base_usb0_src_ids[] = {CLK_SRC_PLL0USB};
+
+static u32 lpc18xx_cgu_base_common_src_ids[] = {
+       CLK_SRC_OSC32, CLK_SRC_IRC, CLK_SRC_ENET_RX_CLK,
+       CLK_SRC_ENET_TX_CLK, CLK_SRC_GP_CLKIN, CLK_SRC_OSC,
+       CLK_SRC_PLL0AUDIO, CLK_SRC_PLL1, CLK_SRC_IDIVA,
+       CLK_SRC_IDIVB, CLK_SRC_IDIVC, CLK_SRC_IDIVD, CLK_SRC_IDIVE,
+};
+
+static u32 lpc18xx_cgu_base_all_src_ids[] = {
+       CLK_SRC_OSC32, CLK_SRC_IRC, CLK_SRC_ENET_RX_CLK,
+       CLK_SRC_ENET_TX_CLK, CLK_SRC_GP_CLKIN, CLK_SRC_OSC,
+       CLK_SRC_PLL0USB, CLK_SRC_PLL0AUDIO, CLK_SRC_PLL1,
+       CLK_SRC_IDIVA, CLK_SRC_IDIVB, CLK_SRC_IDIVC,
+       CLK_SRC_IDIVD, CLK_SRC_IDIVE,
+};
+
+struct lpc18xx_cgu_src_clk_div {
+       u8 clk_id;
+       u8 n_parents;
+       struct clk_divider      div;
+       struct clk_mux          mux;
+       struct clk_gate         gate;
+};
+
+#define LPC1XX_CGU_SRC_CLK_DIV(_id, _width, _table)    \
+{                                                      \
+       .clk_id = CLK_SRC_ ##_id,                       \
+       .n_parents = ARRAY_SIZE(lpc18xx_cgu_ ##_table), \
+       .div = {                                        \
+               .shift = 2,                             \
+               .width = _width,                        \
+       },                                              \
+       .mux = {                                        \
+               .mask = 0x1f,                           \
+               .shift = 24,                            \
+               .table = lpc18xx_cgu_ ##_table,         \
+       },                                              \
+       .gate = {                                       \
+               .bit_idx = 0,                           \
+               .flags = CLK_GATE_SET_TO_DISABLE,       \
+       },                                              \
+}
+
+static struct lpc18xx_cgu_src_clk_div lpc18xx_cgu_src_clk_divs[] = {
+       LPC1XX_CGU_SRC_CLK_DIV(IDIVA, 2, idiva_src_ids),
+       LPC1XX_CGU_SRC_CLK_DIV(IDIVB, 4, idivbcde_src_ids),
+       LPC1XX_CGU_SRC_CLK_DIV(IDIVC, 4, idivbcde_src_ids),
+       LPC1XX_CGU_SRC_CLK_DIV(IDIVD, 4, idivbcde_src_ids),
+       LPC1XX_CGU_SRC_CLK_DIV(IDIVE, 8, idivbcde_src_ids),
+};
+
+struct lpc18xx_cgu_base_clk {
+       u8 clk_id;
+       u8 n_parents;
+       struct clk_mux mux;
+       struct clk_gate gate;
+};
+
+#define LPC1XX_CGU_BASE_CLK(_id, _table, _flags)       \
+{                                                      \
+       .clk_id = BASE_ ##_id ##_CLK,                   \
+       .n_parents = ARRAY_SIZE(lpc18xx_cgu_ ##_table), \
+       .mux = {                                        \
+               .mask = 0x1f,                           \
+               .shift = 24,                            \
+               .table = lpc18xx_cgu_ ##_table,         \
+               .flags = _flags,                        \
+       },                                              \
+       .gate = {                                       \
+               .bit_idx = 0,                           \
+               .flags = CLK_GATE_SET_TO_DISABLE,       \
+       },                                              \
+}
+
+static struct lpc18xx_cgu_base_clk lpc18xx_cgu_base_clks[] = {
+       LPC1XX_CGU_BASE_CLK(SAFE,       base_irc_src_ids, CLK_MUX_READ_ONLY),
+       LPC1XX_CGU_BASE_CLK(USB0,       base_usb0_src_ids,   0),
+       LPC1XX_CGU_BASE_CLK(PERIPH,     base_common_src_ids, 0),
+       LPC1XX_CGU_BASE_CLK(USB1,       base_all_src_ids,    0),
+       LPC1XX_CGU_BASE_CLK(CPU,        base_common_src_ids, 0),
+       LPC1XX_CGU_BASE_CLK(SPIFI,      base_common_src_ids, 0),
+       LPC1XX_CGU_BASE_CLK(SPI,        base_common_src_ids, 0),
+       LPC1XX_CGU_BASE_CLK(PHY_RX,     base_common_src_ids, 0),
+       LPC1XX_CGU_BASE_CLK(PHY_TX,     base_common_src_ids, 0),
+       LPC1XX_CGU_BASE_CLK(APB1,       base_common_src_ids, 0),
+       LPC1XX_CGU_BASE_CLK(APB3,       base_common_src_ids, 0),
+       LPC1XX_CGU_BASE_CLK(LCD,        base_common_src_ids, 0),
+       LPC1XX_CGU_BASE_CLK(ADCHS,      base_common_src_ids, 0),
+       LPC1XX_CGU_BASE_CLK(SDIO,       base_common_src_ids, 0),
+       LPC1XX_CGU_BASE_CLK(SSP0,       base_common_src_ids, 0),
+       LPC1XX_CGU_BASE_CLK(SSP1,       base_common_src_ids, 0),
+       LPC1XX_CGU_BASE_CLK(UART0,      base_common_src_ids, 0),
+       LPC1XX_CGU_BASE_CLK(UART1,      base_common_src_ids, 0),
+       LPC1XX_CGU_BASE_CLK(UART2,      base_common_src_ids, 0),
+       LPC1XX_CGU_BASE_CLK(UART3,      base_common_src_ids, 0),
+       LPC1XX_CGU_BASE_CLK(OUT,        base_all_src_ids,    0),
+       { /* 21 reserved */ },
+       { /* 22 reserved */ },
+       { /* 23 reserved */ },
+       { /* 24 reserved */ },
+       LPC1XX_CGU_BASE_CLK(AUDIO,      base_common_src_ids, 0),
+       LPC1XX_CGU_BASE_CLK(CGU_OUT0,   base_all_src_ids,    0),
+       LPC1XX_CGU_BASE_CLK(CGU_OUT1,   base_all_src_ids,    0),
+};
+
+struct lpc18xx_pll {
+       struct          clk_hw hw;
+       void __iomem    *reg;
+       spinlock_t      *lock;
+       u8              flags;
+};
+
+#define to_lpc_pll(hw) container_of(hw, struct lpc18xx_pll, hw)
+
+struct lpc18xx_cgu_pll_clk {
+       u8 clk_id;
+       u8 n_parents;
+       u8 reg_offset;
+       struct clk_mux mux;
+       struct clk_gate gate;
+       struct lpc18xx_pll pll;
+       const struct clk_ops *pll_ops;
+};
+
+#define LPC1XX_CGU_CLK_PLL(_id, _table, _pll_ops)      \
+{                                                      \
+       .clk_id = CLK_SRC_ ##_id,                       \
+       .n_parents = ARRAY_SIZE(lpc18xx_cgu_ ##_table), \
+       .reg_offset = LPC18XX_CGU_ ##_id ##_STAT,       \
+       .mux = {                                        \
+               .mask = 0x1f,                           \
+               .shift = 24,                            \
+               .table = lpc18xx_cgu_ ##_table,         \
+       },                                              \
+       .gate = {                                       \
+               .bit_idx = 0,                           \
+               .flags = CLK_GATE_SET_TO_DISABLE,       \
+       },                                              \
+       .pll_ops = &lpc18xx_ ##_pll_ops,                \
+}
+
+/*
+ * PLL0 uses a special register value encoding. The compute functions below
+ * are taken or derived from the LPC1850 user manual (section 12.6.3.3).
+ */
+
+/* Compute PLL0 multiplier from decoded version */
+static u32 lpc18xx_pll0_mdec2msel(u32 x)
+{
+       int i;
+
+       switch (x) {
+       case 0x18003: return 1;
+       case 0x10003: return 2;
+       default:
+               for (i = LPC18XX_PLL0_MSEL_MAX + 1; x != 0x4000 && i > 0; i--)
+                       x = ((x ^ x >> 14) & 1) | (x << 1 & 0x7fff);
+               return i;
+       }
+}
+/* Compute PLL0 decoded multiplier from binary version */
+static u32 lpc18xx_pll0_msel2mdec(u32 msel)
+{
+       u32 i, x = 0x4000;
+
+       switch (msel) {
+       case 0: return 0;
+       case 1: return 0x18003;
+       case 2: return 0x10003;
+       default:
+               for (i = msel; i <= LPC18XX_PLL0_MSEL_MAX; i++)
+                       x = ((x ^ x >> 1) & 1) << 14 | (x >> 1 & 0xffff);
+               return x;
+       }
+}
+
+/* Compute PLL0 bandwidth SELI reg from multiplier */
+static u32 lpc18xx_pll0_msel2seli(u32 msel)
+{
+       u32 tmp;
+
+       if (msel > 16384) return 1;
+       if (msel >  8192) return 2;
+       if (msel >  2048) return 4;
+       if (msel >=  501) return 8;
+       if (msel >=   60) {
+               tmp = 1024 / (msel + 9);
+               return ((1024 == (tmp * (msel + 9))) == 0) ? tmp * 4 : (tmp + 1) * 4;
+       }
+
+       return (msel & 0x3c) + 4;
+}
+
+/* Compute PLL0 bandwidth SELP reg from multiplier */
+static u32 lpc18xx_pll0_msel2selp(u32 msel)
+{
+       if (msel < 60)
+               return (msel >> 1) + 1;
+
+       return 31;
+}
+
+static unsigned long lpc18xx_pll0_recalc_rate(struct clk_hw *hw,
+                                             unsigned long parent_rate)
+{
+       struct lpc18xx_pll *pll = to_lpc_pll(hw);
+       u32 ctrl, mdiv, msel, npdiv;
+
+       ctrl = clk_readl(pll->reg + LPC18XX_CGU_PLL0USB_CTRL);
+       mdiv = clk_readl(pll->reg + LPC18XX_CGU_PLL0USB_MDIV);
+       npdiv = clk_readl(pll->reg + LPC18XX_CGU_PLL0USB_NP_DIV);
+
+       if (ctrl & LPC18XX_PLL0_CTRL_BYPASS)
+               return parent_rate;
+
+       if (npdiv != LPC18XX_PLL0_NP_DIVS_1) {
+               pr_warn("%s: pre/post dividers not supported\n", __func__);
+               return 0;
+       }
+
+       msel = lpc18xx_pll0_mdec2msel(mdiv & LPC18XX_PLL0_MDIV_MDEC_MASK);
+       if (msel)
+               return 2 * msel * parent_rate;
+
+       pr_warn("%s: unable to calculate rate\n", __func__);
+
+       return 0;
+}
+
+static long lpc18xx_pll0_round_rate(struct clk_hw *hw, unsigned long rate,
+                                   unsigned long *prate)
+{
+       unsigned long m;
+
+       if (*prate < rate) {
+               pr_warn("%s: pll dividers not supported\n", __func__);
+               return -EINVAL;
+       }
+
+       m = DIV_ROUND_UP_ULL(*prate, rate * 2);
+       if (m <= 0 && m > LPC18XX_PLL0_MSEL_MAX) {
+               pr_warn("%s: unable to support rate %lu\n", __func__, rate);
+               return -EINVAL;
+       }
+
+       return 2 * *prate * m;
+}
+
+static int lpc18xx_pll0_set_rate(struct clk_hw *hw, unsigned long rate,
+                                unsigned long parent_rate)
+{
+       struct lpc18xx_pll *pll = to_lpc_pll(hw);
+       u32 ctrl, stat, m;
+       int retry = 3;
+
+       if (parent_rate < rate) {
+               pr_warn("%s: pll dividers not supported\n", __func__);
+               return -EINVAL;
+       }
+
+       m = DIV_ROUND_UP_ULL(parent_rate, rate * 2);
+       if (m <= 0 && m > LPC18XX_PLL0_MSEL_MAX) {
+               pr_warn("%s: unable to support rate %lu\n", __func__, rate);
+               return -EINVAL;
+       }
+
+       m  = lpc18xx_pll0_msel2mdec(m);
+       m |= lpc18xx_pll0_msel2selp(m) << LPC18XX_PLL0_MDIV_SELP_SHIFT;
+       m |= lpc18xx_pll0_msel2seli(m) << LPC18XX_PLL0_MDIV_SELI_SHIFT;
+
+       /* Power down PLL, disable clk output and dividers */
+       ctrl = clk_readl(pll->reg + LPC18XX_CGU_PLL0USB_CTRL);
+       ctrl |= LPC18XX_PLL0_CTRL_PD;
+       ctrl &= ~(LPC18XX_PLL0_CTRL_BYPASS | LPC18XX_PLL0_CTRL_DIRECTI |
+                 LPC18XX_PLL0_CTRL_DIRECTO | LPC18XX_PLL0_CTRL_CLKEN);
+       clk_writel(ctrl, pll->reg + LPC18XX_CGU_PLL0USB_CTRL);
+
+       /* Configure new PLL settings */
+       clk_writel(m, pll->reg + LPC18XX_CGU_PLL0USB_MDIV);
+       clk_writel(LPC18XX_PLL0_NP_DIVS_1, pll->reg + LPC18XX_CGU_PLL0USB_NP_DIV);
+
+       /* Power up PLL and wait for lock */
+       ctrl &= ~LPC18XX_PLL0_CTRL_PD;
+       clk_writel(ctrl, pll->reg + LPC18XX_CGU_PLL0USB_CTRL);
+       do {
+               udelay(10);
+               stat = clk_readl(pll->reg + LPC18XX_CGU_PLL0USB_STAT);
+               if (stat & LPC18XX_PLL0_STAT_LOCK) {
+                       ctrl |= LPC18XX_PLL0_CTRL_CLKEN;
+                       clk_writel(ctrl, pll->reg + LPC18XX_CGU_PLL0USB_CTRL);
+
+                       return 0;
+               }
+       } while (retry--);
+
+       pr_warn("%s: unable to lock pll\n", __func__);
+
+       return -EINVAL;
+}
+
+static const struct clk_ops lpc18xx_pll0_ops = {
+       .recalc_rate    = lpc18xx_pll0_recalc_rate,
+       .round_rate     = lpc18xx_pll0_round_rate,
+       .set_rate       = lpc18xx_pll0_set_rate,
+};
+
+static unsigned long lpc18xx_pll1_recalc_rate(struct clk_hw *hw,
+                                             unsigned long parent_rate)
+{
+       struct lpc18xx_pll *pll = to_lpc_pll(hw);
+       u16 msel, nsel, psel;
+       bool direct, fbsel;
+       u32 stat, ctrl;
+
+       stat = clk_readl(pll->reg + LPC18XX_CGU_PLL1_STAT);
+       ctrl = clk_readl(pll->reg + LPC18XX_CGU_PLL1_CTRL);
+
+       direct = (ctrl & LPC18XX_PLL1_CTRL_DIRECT) ? true : false;
+       fbsel = (ctrl & LPC18XX_PLL1_CTRL_FBSEL) ? true : false;
+
+       msel = ((ctrl >> 16) & 0xff) + 1;
+       nsel = ((ctrl >> 12) & 0x3) + 1;
+
+       if (direct || fbsel)
+               return msel * (parent_rate / nsel);
+
+       psel = (ctrl >>  8) & 0x3;
+       psel = 1 << psel;
+
+       return (msel / (2 * psel)) * (parent_rate / nsel);
+}
+
+static const struct clk_ops lpc18xx_pll1_ops = {
+       .recalc_rate = lpc18xx_pll1_recalc_rate,
+};
+
+static struct lpc18xx_cgu_pll_clk lpc18xx_cgu_src_clk_plls[] = {
+       LPC1XX_CGU_CLK_PLL(PLL0USB,     pll0_src_ids, pll0_ops),
+       LPC1XX_CGU_CLK_PLL(PLL0AUDIO,   pll0_src_ids, pll0_ops),
+       LPC1XX_CGU_CLK_PLL(PLL1,        pll1_src_ids, pll1_ops),
+};
+
+static void lpc18xx_fill_parent_names(const char **parent, u32 *id, int size)
+{
+       int i;
+
+       for (i = 0; i < size; i++)
+               parent[i] = clk_src_names[id[i]];
+}
+
+static struct clk *lpc18xx_cgu_register_div(struct lpc18xx_cgu_src_clk_div *clk,
+                                           void __iomem *base, int n)
+{
+       void __iomem *reg = base + LPC18XX_CGU_IDIV_CTRL(n);
+       const char *name = clk_src_names[clk->clk_id];
+       const char *parents[CLK_SRC_MAX];
+
+       clk->div.reg = reg;
+       clk->mux.reg = reg;
+       clk->gate.reg = reg;
+
+       lpc18xx_fill_parent_names(parents, clk->mux.table, clk->n_parents);
+
+       return clk_register_composite(NULL, name, parents, clk->n_parents,
+                                     &clk->mux.hw, &clk_mux_ops,
+                                     &clk->div.hw, &clk_divider_ops,
+                                     &clk->gate.hw, &clk_gate_ops, 0);
+}
+
+
+static struct clk *lpc18xx_register_base_clk(struct lpc18xx_cgu_base_clk *clk,
+                                            void __iomem *reg_base, int n)
+{
+       void __iomem *reg = reg_base + LPC18XX_CGU_BASE_CLK(n);
+       const char *name = clk_base_names[clk->clk_id];
+       const char *parents[CLK_SRC_MAX];
+
+       if (clk->n_parents == 0)
+               return ERR_PTR(-ENOENT);
+
+       clk->mux.reg = reg;
+       clk->gate.reg = reg;
+
+       lpc18xx_fill_parent_names(parents, clk->mux.table, clk->n_parents);
+
+       /* SAFE_CLK can not be turned off */
+       if (n == BASE_SAFE_CLK)
+               return clk_register_composite(NULL, name, parents, clk->n_parents,
+                                             &clk->mux.hw, &clk_mux_ops,
+                                             NULL, NULL, NULL, NULL, 0);
+
+       return clk_register_composite(NULL, name, parents, clk->n_parents,
+                                     &clk->mux.hw, &clk_mux_ops,
+                                     NULL,  NULL,
+                                     &clk->gate.hw, &clk_gate_ops, 0);
+}
+
+
+static struct clk *lpc18xx_cgu_register_pll(struct lpc18xx_cgu_pll_clk *clk,
+                                           void __iomem *base)
+{
+       const char *name = clk_src_names[clk->clk_id];
+       const char *parents[CLK_SRC_MAX];
+
+       clk->pll.reg  = base;
+       clk->mux.reg  = base + clk->reg_offset + LPC18XX_CGU_PLL_CTRL_OFFSET;
+       clk->gate.reg = base + clk->reg_offset + LPC18XX_CGU_PLL_CTRL_OFFSET;
+
+       lpc18xx_fill_parent_names(parents, clk->mux.table, clk->n_parents);
+
+       return clk_register_composite(NULL, name, parents, clk->n_parents,
+                                     &clk->mux.hw, &clk_mux_ops,
+                                     &clk->pll.hw, clk->pll_ops,
+                                     &clk->gate.hw, &clk_gate_ops, 0);
+}
+
+static void __init lpc18xx_cgu_register_source_clks(struct device_node *np,
+                                                   void __iomem *base)
+{
+       const char *parents[CLK_SRC_MAX];
+       struct clk *clk;
+       int i;
+
+       /* Register the internal 12 MHz RC oscillator (IRC) */
+       clk = clk_register_fixed_rate(NULL, clk_src_names[CLK_SRC_IRC],
+                                     NULL, CLK_IS_ROOT, 12000000);
+       if (IS_ERR(clk))
+               pr_warn("%s: failed to register irc clk\n", __func__);
+
+       /* Register crystal oscillator controlller */
+       parents[0] = of_clk_get_parent_name(np, 0);
+       clk = clk_register_gate(NULL, clk_src_names[CLK_SRC_OSC], parents[0],
+                               0, base + LPC18XX_CGU_XTAL_OSC_CTRL,
+                               0, CLK_GATE_SET_TO_DISABLE, NULL);
+       if (IS_ERR(clk))
+               pr_warn("%s: failed to register osc clk\n", __func__);
+
+       /* Register all PLLs */
+       for (i = 0; i < ARRAY_SIZE(lpc18xx_cgu_src_clk_plls); i++) {
+               clk = lpc18xx_cgu_register_pll(&lpc18xx_cgu_src_clk_plls[i],
+                                                  base);
+               if (IS_ERR(clk))
+                       pr_warn("%s: failed to register pll (%d)\n", __func__, i);
+       }
+
+       /* Register all clock dividers A-E */
+       for (i = 0; i < ARRAY_SIZE(lpc18xx_cgu_src_clk_divs); i++) {
+               clk = lpc18xx_cgu_register_div(&lpc18xx_cgu_src_clk_divs[i],
+                                              base, i);
+               if (IS_ERR(clk))
+                       pr_warn("%s: failed to register div %d\n", __func__, i);
+       }
+}
+
+static struct clk *clk_base[BASE_CLK_MAX];
+static struct clk_onecell_data clk_base_data = {
+       .clks = clk_base,
+       .clk_num = BASE_CLK_MAX,
+};
+
+static void __init lpc18xx_cgu_register_base_clks(void __iomem *reg_base)
+{
+       int i;
+
+       for (i = BASE_SAFE_CLK; i < BASE_CLK_MAX; i++) {
+               clk_base[i] = lpc18xx_register_base_clk(&lpc18xx_cgu_base_clks[i],
+                                                       reg_base, i);
+               if (IS_ERR(clk_base[i]) && PTR_ERR(clk_base[i]) != -ENOENT)
+                       pr_warn("%s: register base clk %d failed\n", __func__, i);
+       }
+}
+
+static void __init lpc18xx_cgu_init(struct device_node *np)
+{
+       void __iomem *reg_base;
+
+       reg_base = of_iomap(np, 0);
+       if (!reg_base) {
+               pr_warn("%s: failed to map address range\n", __func__);
+               return;
+       }
+
+       lpc18xx_cgu_register_source_clks(np, reg_base);
+       lpc18xx_cgu_register_base_clks(reg_base);
+
+       of_clk_add_provider(np, of_clk_src_onecell_get, &clk_base_data);
+}
+CLK_OF_DECLARE(lpc18xx_cgu, "nxp,lpc1850-cgu", lpc18xx_cgu_init);
index de537560bf709444601405f42650c22b91c4334d..e17dada0dd21ab88fe1282b6dcc662e5e775988a 100644 (file)
@@ -6,9 +6,12 @@
  * version 2, as published by the Free Software Foundation.
  */
 
+#define pr_fmt(fmt) "%s: " fmt, __func__
+
 #include <linux/clk-provider.h>
 #include <linux/io.h>
 #include <linux/kernel.h>
+#include <linux/printk.h>
 #include <linux/slab.h>
 
 #include "clk.h"
 #define PLL_CTRL4                      0x10
 #define PLL_FRAC_CTRL4_BYPASS          BIT(28)
 
+#define MIN_PFD                                9600000UL
+#define MIN_VCO_LA                     400000000UL
+#define MAX_VCO_LA                     1600000000UL
+#define MIN_VCO_FRAC_INT               600000000UL
+#define MAX_VCO_FRAC_INT               1600000000UL
+#define MIN_VCO_FRAC_FRAC              600000000UL
+#define MAX_VCO_FRAC_FRAC              2400000000UL
+#define MIN_OUTPUT_LA                  8000000UL
+#define MAX_OUTPUT_LA                  1600000000UL
+#define MIN_OUTPUT_FRAC                        12000000UL
+#define MAX_OUTPUT_FRAC                        1600000000UL
+
 struct pistachio_clk_pll {
        struct clk_hw hw;
        void __iomem *base;
@@ -67,6 +82,12 @@ static inline void pll_writel(struct pistachio_clk_pll *pll, u32 val, u32 reg)
        writel(val, pll->base + reg);
 }
 
+static inline void pll_lock(struct pistachio_clk_pll *pll)
+{
+       while (!(pll_readl(pll, PLL_STATUS) & PLL_STATUS_LOCK))
+               cpu_relax();
+}
+
 static inline u32 do_div_round_closest(u64 dividend, u32 divisor)
 {
        dividend += divisor / 2;
@@ -124,6 +145,8 @@ static int pll_gf40lp_frac_enable(struct clk_hw *hw)
        val &= ~PLL_FRAC_CTRL4_BYPASS;
        pll_writel(pll, val, PLL_CTRL4);
 
+       pll_lock(pll);
+
        return 0;
 }
 
@@ -149,16 +172,29 @@ static int pll_gf40lp_frac_set_rate(struct clk_hw *hw, unsigned long rate,
 {
        struct pistachio_clk_pll *pll = to_pistachio_pll(hw);
        struct pistachio_pll_rate_table *params;
-       bool was_enabled;
-       u32 val;
+       int enabled = pll_gf40lp_frac_is_enabled(hw);
+       u32 val, vco, old_postdiv1, old_postdiv2;
+       const char *name = __clk_get_name(hw->clk);
+
+       if (rate < MIN_OUTPUT_FRAC || rate > MAX_OUTPUT_FRAC)
+               return -EINVAL;
 
        params = pll_get_params(pll, parent_rate, rate);
-       if (!params)
+       if (!params || !params->refdiv)
                return -EINVAL;
 
-       was_enabled = pll_gf40lp_frac_is_enabled(hw);
-       if (!was_enabled)
-               pll_gf40lp_frac_enable(hw);
+       vco = params->fref * params->fbdiv / params->refdiv;
+       if (vco < MIN_VCO_FRAC_FRAC || vco > MAX_VCO_FRAC_FRAC)
+               pr_warn("%s: VCO %u is out of range %lu..%lu\n", name, vco,
+                       MIN_VCO_FRAC_FRAC, MAX_VCO_FRAC_FRAC);
+
+       val = params->fref / params->refdiv;
+       if (val < MIN_PFD)
+               pr_warn("%s: PFD %u is too low (min %lu)\n",
+                       name, val, MIN_PFD);
+       if (val > vco / 16)
+               pr_warn("%s: PFD %u is too high (max %u)\n",
+                       name, val, vco / 16);
 
        val = pll_readl(pll, PLL_CTRL1);
        val &= ~((PLL_CTRL1_REFDIV_MASK << PLL_CTRL1_REFDIV_SHIFT) |
@@ -168,6 +204,19 @@ static int pll_gf40lp_frac_set_rate(struct clk_hw *hw, unsigned long rate,
        pll_writel(pll, val, PLL_CTRL1);
 
        val = pll_readl(pll, PLL_CTRL2);
+
+       old_postdiv1 = (val >> PLL_FRAC_CTRL2_POSTDIV1_SHIFT) &
+                      PLL_FRAC_CTRL2_POSTDIV1_MASK;
+       old_postdiv2 = (val >> PLL_FRAC_CTRL2_POSTDIV2_SHIFT) &
+                      PLL_FRAC_CTRL2_POSTDIV2_MASK;
+       if (enabled &&
+           (params->postdiv1 != old_postdiv1 ||
+            params->postdiv2 != old_postdiv2))
+               pr_warn("%s: changing postdiv while PLL is enabled\n", name);
+
+       if (params->postdiv2 > params->postdiv1)
+               pr_warn("%s: postdiv2 should not exceed postdiv1\n", name);
+
        val &= ~((PLL_FRAC_CTRL2_FRAC_MASK << PLL_FRAC_CTRL2_FRAC_SHIFT) |
                 (PLL_FRAC_CTRL2_POSTDIV1_MASK <<
                  PLL_FRAC_CTRL2_POSTDIV1_SHIFT) |
@@ -178,11 +227,8 @@ static int pll_gf40lp_frac_set_rate(struct clk_hw *hw, unsigned long rate,
                (params->postdiv2 << PLL_FRAC_CTRL2_POSTDIV2_SHIFT);
        pll_writel(pll, val, PLL_CTRL2);
 
-       while (!(pll_readl(pll, PLL_STATUS) & PLL_STATUS_LOCK))
-               cpu_relax();
-
-       if (!was_enabled)
-               pll_gf40lp_frac_disable(hw);
+       if (enabled)
+               pll_lock(pll);
 
        return 0;
 }
@@ -241,6 +287,8 @@ static int pll_gf40lp_laint_enable(struct clk_hw *hw)
        val &= ~PLL_INT_CTRL2_BYPASS;
        pll_writel(pll, val, PLL_CTRL2);
 
+       pll_lock(pll);
+
        return 0;
 }
 
@@ -266,18 +314,44 @@ static int pll_gf40lp_laint_set_rate(struct clk_hw *hw, unsigned long rate,
 {
        struct pistachio_clk_pll *pll = to_pistachio_pll(hw);
        struct pistachio_pll_rate_table *params;
-       bool was_enabled;
-       u32 val;
+       int enabled = pll_gf40lp_laint_is_enabled(hw);
+       u32 val, vco, old_postdiv1, old_postdiv2;
+       const char *name = __clk_get_name(hw->clk);
+
+       if (rate < MIN_OUTPUT_LA || rate > MAX_OUTPUT_LA)
+               return -EINVAL;
 
        params = pll_get_params(pll, parent_rate, rate);
-       if (!params)
+       if (!params || !params->refdiv)
                return -EINVAL;
 
-       was_enabled = pll_gf40lp_laint_is_enabled(hw);
-       if (!was_enabled)
-               pll_gf40lp_laint_enable(hw);
+       vco = params->fref * params->fbdiv / params->refdiv;
+       if (vco < MIN_VCO_LA || vco > MAX_VCO_LA)
+               pr_warn("%s: VCO %u is out of range %lu..%lu\n", name, vco,
+                       MIN_VCO_LA, MAX_VCO_LA);
+
+       val = params->fref / params->refdiv;
+       if (val < MIN_PFD)
+               pr_warn("%s: PFD %u is too low (min %lu)\n",
+                       name, val, MIN_PFD);
+       if (val > vco / 16)
+               pr_warn("%s: PFD %u is too high (max %u)\n",
+                       name, val, vco / 16);
 
        val = pll_readl(pll, PLL_CTRL1);
+
+       old_postdiv1 = (val >> PLL_INT_CTRL1_POSTDIV1_SHIFT) &
+                      PLL_INT_CTRL1_POSTDIV1_MASK;
+       old_postdiv2 = (val >> PLL_INT_CTRL1_POSTDIV2_SHIFT) &
+                      PLL_INT_CTRL1_POSTDIV2_MASK;
+       if (enabled &&
+           (params->postdiv1 != old_postdiv1 ||
+            params->postdiv2 != old_postdiv2))
+               pr_warn("%s: changing postdiv while PLL is enabled\n", name);
+
+       if (params->postdiv2 > params->postdiv1)
+               pr_warn("%s: postdiv2 should not exceed postdiv1\n", name);
+
        val &= ~((PLL_CTRL1_REFDIV_MASK << PLL_CTRL1_REFDIV_SHIFT) |
                 (PLL_CTRL1_FBDIV_MASK << PLL_CTRL1_FBDIV_SHIFT) |
                 (PLL_INT_CTRL1_POSTDIV1_MASK << PLL_INT_CTRL1_POSTDIV1_SHIFT) |
@@ -288,11 +362,8 @@ static int pll_gf40lp_laint_set_rate(struct clk_hw *hw, unsigned long rate,
                (params->postdiv2 << PLL_INT_CTRL1_POSTDIV2_SHIFT);
        pll_writel(pll, val, PLL_CTRL1);
 
-       while (!(pll_readl(pll, PLL_STATUS) & PLL_STATUS_LOCK))
-               cpu_relax();
-
-       if (!was_enabled)
-               pll_gf40lp_laint_disable(hw);
+       if (enabled)
+               pll_lock(pll);
 
        return 0;
 }
index b04c5b9c0ea816e4e900b83268126cecd051e3f5..d1de805df86733bb2a4b69505f070bae72f23f3f 100644 (file)
@@ -14,7 +14,7 @@
 #define _CLK_PXA_
 
 #define PARENTS(name) \
-       static const char *name ## _parents[] __initdata
+       static const char *const name ## _parents[] __initconst
 #define MUX_RO_RATE_RO_OPS(name, clk_name)                     \
        static struct clk_hw name ## _mux_hw;                   \
        static struct clk_hw name ## _rate_hw;                  \
@@ -72,7 +72,7 @@ struct desc_clk_cken {
        const char *name;
        const char *dev_id;
        const char *con_id;
-       const char **parent_names;
+       const char * const *parent_names;
        struct clk_fixed_factor lp;
        struct clk_fixed_factor hp;
        struct clk_gate gate;
index 8539c4fd34cc37bd28810b93d6ffb815b0bd48d6..fb7721bd37e6a9595f70cbd8125fdab52fd2265e 100644 (file)
@@ -231,7 +231,7 @@ static int rockchip_cpuclk_notifier_cb(struct notifier_block *nb,
 }
 
 struct clk *rockchip_clk_register_cpuclk(const char *name,
-                       const char **parent_names, u8 num_parents,
+                       const char *const *parent_names, u8 num_parents,
                        const struct rockchip_cpuclk_reg_data *reg_data,
                        const struct rockchip_cpuclk_rate_table *rates,
                        int nrates, void __iomem *reg_base, spinlock_t *lock)
index c842e3b60f21af12a80f74ee43e7c65d1172a249..e9f8df324e7ccecad7730998d8210c8ea11a2276 100644 (file)
@@ -120,7 +120,7 @@ static const struct clk_ops rockchip_mmc_clk_ops = {
 };
 
 struct clk *rockchip_clk_register_mmc(const char *name,
-                               const char **parent_names, u8 num_parents,
+                               const char *const *parent_names, u8 num_parents,
                                void __iomem *reg, int shift)
 {
        struct clk_init_data init;
index f8d3baf275b211623efd553d7b7fdf23c609d7f0..76027261f7ed999971f0b46ca10a4b4774d55bc3 100644 (file)
@@ -329,10 +329,10 @@ static const struct clk_ops rockchip_rk3066_pll_clk_ops = {
  */
 
 struct clk *rockchip_clk_register_pll(enum rockchip_pll_type pll_type,
-               const char *name, const char **parent_names, u8 num_parents,
-               void __iomem *base, int con_offset, int grf_lock_offset,
-               int lock_shift, int mode_offset, int mode_shift,
-               struct rockchip_pll_rate_table *rate_table,
+               const char *name, const char *const *parent_names,
+               u8 num_parents, void __iomem *base, int con_offset,
+               int grf_lock_offset, int lock_shift, int mode_offset,
+               int mode_shift, struct rockchip_pll_rate_table *rate_table,
                u8 clk_pll_flags, spinlock_t *lock)
 {
        const char *pll_parents[3];
index 556ce041d371478b43a9549a258f368b57f3468d..e4f9d472f1ffb52f7ffb5f5061b39d56d519fb89 100644 (file)
@@ -26,7 +26,7 @@ enum rk3188_plls {
        apll, cpll, dpll, gpll,
 };
 
-struct rockchip_pll_rate_table rk3188_pll_rates[] = {
+static struct rockchip_pll_rate_table rk3188_pll_rates[] = {
        RK3066_PLL_RATE(2208000000, 1, 92, 1),
        RK3066_PLL_RATE(2184000000, 1, 91, 1),
        RK3066_PLL_RATE(2160000000, 1, 90, 1),
index d17eb4528a283ee089603876ac8daa7da6b66054..4f817ed9e6eedc432d0e6fd05adcb365e03e0f6b 100644 (file)
@@ -27,7 +27,7 @@ enum rk3288_plls {
        apll, dpll, cpll, gpll, npll,
 };
 
-struct rockchip_pll_rate_table rk3288_pll_rates[] = {
+static struct rockchip_pll_rate_table rk3288_pll_rates[] = {
        RK3066_PLL_RATE(2208000000, 1, 92, 1),
        RK3066_PLL_RATE(2184000000, 1, 91, 1),
        RK3066_PLL_RATE(2160000000, 1, 90, 1),
index edb5d489ae61859c5853d2ece634bd5d3e397f73..052b94db0ff93a690dda50339b81ad673c00fadd 100644 (file)
@@ -39,7 +39,7 @@
  * sometimes without one of those components.
  */
 static struct clk *rockchip_clk_register_branch(const char *name,
-               const char **parent_names, u8 num_parents, void __iomem *base,
+               const char *const *parent_names, u8 num_parents, void __iomem *base,
                int muxdiv_offset, u8 mux_shift, u8 mux_width, u8 mux_flags,
                u8 div_shift, u8 div_width, u8 div_flags,
                struct clk_div_table *div_table, int gate_offset,
@@ -103,8 +103,8 @@ static struct clk *rockchip_clk_register_branch(const char *name,
 }
 
 static struct clk *rockchip_clk_register_frac_branch(const char *name,
-               const char **parent_names, u8 num_parents, void __iomem *base,
-               int muxdiv_offset, u8 div_flags,
+               const char *const *parent_names, u8 num_parents,
+               void __iomem *base, int muxdiv_offset, u8 div_flags,
                int gate_offset, u8 gate_shift, u8 gate_flags,
                unsigned long flags, spinlock_t *lock)
 {
@@ -297,7 +297,7 @@ void __init rockchip_clk_register_branches(
 }
 
 void __init rockchip_clk_register_armclk(unsigned int lookup_id,
-                       const char *name, const char **parent_names,
+                       const char *name, const char *const *parent_names,
                        u8 num_parents,
                        const struct rockchip_cpuclk_reg_data *reg_data,
                        const struct rockchip_cpuclk_rate_table *rates,
index e63cafe893e19f82f2d200a6c1a391aff6112a12..6b092673048a2514399bd07cf156aefb081fb56a 100644 (file)
@@ -108,7 +108,7 @@ struct rockchip_pll_rate_table {
 struct rockchip_pll_clock {
        unsigned int            id;
        const char              *name;
-       const char              **parent_names;
+       const char              *const *parent_names;
        u8                      num_parents;
        unsigned long           flags;
        int                     con_offset;
@@ -140,10 +140,10 @@ struct rockchip_pll_clock {
        }
 
 struct clk *rockchip_clk_register_pll(enum rockchip_pll_type pll_type,
-               const char *name, const char **parent_names, u8 num_parents,
-               void __iomem *base, int con_offset, int grf_lock_offset,
-               int lock_shift, int reg_mode, int mode_shift,
-               struct rockchip_pll_rate_table *rate_table,
+               const char *name, const char *const *parent_names,
+               u8 num_parents, void __iomem *base, int con_offset,
+               int grf_lock_offset, int lock_shift, int reg_mode,
+               int mode_shift, struct rockchip_pll_rate_table *rate_table,
                u8 clk_pll_flags, spinlock_t *lock);
 
 struct rockchip_cpuclk_clksel {
@@ -173,16 +173,16 @@ struct rockchip_cpuclk_reg_data {
 };
 
 struct clk *rockchip_clk_register_cpuclk(const char *name,
-                       const char **parent_names, u8 num_parents,
+                       const char *const *parent_names, u8 num_parents,
                        const struct rockchip_cpuclk_reg_data *reg_data,
                        const struct rockchip_cpuclk_rate_table *rates,
                        int nrates, void __iomem *reg_base, spinlock_t *lock);
 
 struct clk *rockchip_clk_register_mmc(const char *name,
-                               const char **parent_names, u8 num_parents,
+                               const char *const *parent_names, u8 num_parents,
                                void __iomem *reg, int shift);
 
-#define PNAME(x) static const char *x[] __initdata
+#define PNAME(x) static const char *const x[] __initconst
 
 enum rockchip_clk_branch_type {
        branch_composite,
@@ -197,7 +197,7 @@ struct rockchip_clk_branch {
        unsigned int                    id;
        enum rockchip_clk_branch_type   branch_type;
        const char                      *name;
-       const char                      **parent_names;
+       const char                      *const *parent_names;
        u8                              num_parents;
        unsigned long                   flags;
        int                             muxdiv_offset;
@@ -403,7 +403,7 @@ void rockchip_clk_register_branches(struct rockchip_clk_branch *clk_list,
 void rockchip_clk_register_plls(struct rockchip_pll_clock *pll_list,
                                unsigned int nr_pll, int grf_lock_offset);
 void rockchip_clk_register_armclk(unsigned int lookup_id, const char *name,
-                       const char **parent_names, u8 num_parents,
+                       const char *const *parent_names, u8 num_parents,
                        const struct rockchip_cpuclk_reg_data *reg_data,
                        const struct rockchip_cpuclk_rate_table *rates,
                        int nrates);
index a17683b2cf276b03e287bd6959f217e7aacb7c5f..5f6833ea355d686a5d1429133715cf1ba1f48795 100644 (file)
@@ -2,7 +2,7 @@
 # Samsung Clock specific Makefile
 #
 
-obj-$(CONFIG_COMMON_CLK)       += clk.o clk-pll.o
+obj-$(CONFIG_COMMON_CLK)       += clk.o clk-pll.o clk-cpu.o
 obj-$(CONFIG_SOC_EXYNOS3250)   += clk-exynos3250.o
 obj-$(CONFIG_ARCH_EXYNOS4)     += clk-exynos4.o
 obj-$(CONFIG_SOC_EXYNOS4415)   += clk-exynos4415.o
diff --git a/drivers/clk/samsung/clk-cpu.c b/drivers/clk/samsung/clk-cpu.c
new file mode 100644 (file)
index 0000000..3a1fe07
--- /dev/null
@@ -0,0 +1,349 @@
+/*
+ * Copyright (c) 2014 Samsung Electronics Co., Ltd.
+ * Author: Thomas Abraham <thomas.ab@samsung.com>
+ *
+ * Copyright (c) 2015 Samsung Electronics Co., Ltd.
+ * Bartlomiej Zolnierkiewicz <b.zolnierkie@samsung.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This file contains the utility function to register CPU clock for Samsung
+ * Exynos platforms. A CPU clock is defined as a clock supplied to a CPU or a
+ * group of CPUs. The CPU clock is typically derived from a hierarchy of clock
+ * blocks which includes mux and divider blocks. There are a number of other
+ * auxiliary clocks supplied to the CPU domain such as the debug blocks and AXI
+ * clock for CPU domain. The rates of these auxiliary clocks are related to the
+ * CPU clock rate and this relation is usually specified in the hardware manual
+ * of the SoC or supplied after the SoC characterization.
+ *
+ * The below implementation of the CPU clock allows the rate changes of the CPU
+ * clock and the corresponding rate changes of the auxillary clocks of the CPU
+ * domain. The platform clock driver provides a clock register configuration
+ * for each configurable rate which is then used to program the clock hardware
+ * registers to acheive a fast co-oridinated rate change for all the CPU domain
+ * clocks.
+ *
+ * On a rate change request for the CPU clock, the rate change is propagated
+ * upto the PLL supplying the clock to the CPU domain clock blocks. While the
+ * CPU domain PLL is reconfigured, the CPU domain clocks are driven using an
+ * alternate clock source. If required, the alternate clock source is divided
+ * down in order to keep the output clock rate within the previous OPP limits.
+*/
+
+#include <linux/errno.h>
+#include "clk-cpu.h"
+
+#define E4210_SRC_CPU          0x0
+#define E4210_STAT_CPU         0x200
+#define E4210_DIV_CPU0         0x300
+#define E4210_DIV_CPU1         0x304
+#define E4210_DIV_STAT_CPU0    0x400
+#define E4210_DIV_STAT_CPU1    0x404
+
+#define E4210_DIV0_RATIO0_MASK 0x7
+#define E4210_DIV1_HPM_MASK    (0x7 << 4)
+#define E4210_DIV1_COPY_MASK   (0x7 << 0)
+#define E4210_MUX_HPM_MASK     (1 << 20)
+#define E4210_DIV0_ATB_SHIFT   16
+#define E4210_DIV0_ATB_MASK    (DIV_MASK << E4210_DIV0_ATB_SHIFT)
+
+#define MAX_DIV                        8
+#define DIV_MASK               7
+#define DIV_MASK_ALL           0xffffffff
+#define MUX_MASK               7
+
+/*
+ * Helper function to wait until divider(s) have stabilized after the divider
+ * value has changed.
+ */
+static void wait_until_divider_stable(void __iomem *div_reg, unsigned long mask)
+{
+       unsigned long timeout = jiffies + msecs_to_jiffies(10);
+
+       do {
+               if (!(readl(div_reg) & mask))
+                       return;
+       } while (time_before(jiffies, timeout));
+
+       if (!(readl(div_reg) & mask))
+               return;
+
+       pr_err("%s: timeout in divider stablization\n", __func__);
+}
+
+/*
+ * Helper function to wait until mux has stabilized after the mux selection
+ * value was changed.
+ */
+static void wait_until_mux_stable(void __iomem *mux_reg, u32 mux_pos,
+                                       unsigned long mux_value)
+{
+       unsigned long timeout = jiffies + msecs_to_jiffies(10);
+
+       do {
+               if (((readl(mux_reg) >> mux_pos) & MUX_MASK) == mux_value)
+                       return;
+       } while (time_before(jiffies, timeout));
+
+       if (((readl(mux_reg) >> mux_pos) & MUX_MASK) == mux_value)
+               return;
+
+       pr_err("%s: re-parenting mux timed-out\n", __func__);
+}
+
+/* common round rate callback useable for all types of CPU clocks */
+static long exynos_cpuclk_round_rate(struct clk_hw *hw,
+                       unsigned long drate, unsigned long *prate)
+{
+       struct clk *parent = __clk_get_parent(hw->clk);
+       *prate = __clk_round_rate(parent, drate);
+       return *prate;
+}
+
+/* common recalc rate callback useable for all types of CPU clocks */
+static unsigned long exynos_cpuclk_recalc_rate(struct clk_hw *hw,
+                       unsigned long parent_rate)
+{
+       /*
+        * The CPU clock output (armclk) rate is the same as its parent
+        * rate. Although there exist certain dividers inside the CPU
+        * clock block that could be used to divide the parent clock,
+        * the driver does not make use of them currently, except during
+        * frequency transitions.
+        */
+       return parent_rate;
+}
+
+static const struct clk_ops exynos_cpuclk_clk_ops = {
+       .recalc_rate = exynos_cpuclk_recalc_rate,
+       .round_rate = exynos_cpuclk_round_rate,
+};
+
+/*
+ * Helper function to set the 'safe' dividers for the CPU clock. The parameters
+ * div and mask contain the divider value and the register bit mask of the
+ * dividers to be programmed.
+ */
+static void exynos_set_safe_div(void __iomem *base, unsigned long div,
+                                       unsigned long mask)
+{
+       unsigned long div0;
+
+       div0 = readl(base + E4210_DIV_CPU0);
+       div0 = (div0 & ~mask) | (div & mask);
+       writel(div0, base + E4210_DIV_CPU0);
+       wait_until_divider_stable(base + E4210_DIV_STAT_CPU0, mask);
+}
+
+/* handler for pre-rate change notification from parent clock */
+static int exynos_cpuclk_pre_rate_change(struct clk_notifier_data *ndata,
+                       struct exynos_cpuclk *cpuclk, void __iomem *base)
+{
+       const struct exynos_cpuclk_cfg_data *cfg_data = cpuclk->cfg;
+       unsigned long alt_prate = clk_get_rate(cpuclk->alt_parent);
+       unsigned long alt_div = 0, alt_div_mask = DIV_MASK;
+       unsigned long div0, div1 = 0, mux_reg;
+
+       /* find out the divider values to use for clock data */
+       while ((cfg_data->prate * 1000) != ndata->new_rate) {
+               if (cfg_data->prate == 0)
+                       return -EINVAL;
+               cfg_data++;
+       }
+
+       spin_lock(cpuclk->lock);
+
+       /*
+        * For the selected PLL clock frequency, get the pre-defined divider
+        * values. If the clock for sclk_hpm is not sourced from apll, then
+        * the values for DIV_COPY and DIV_HPM dividers need not be set.
+        */
+       div0 = cfg_data->div0;
+       if (test_bit(CLK_CPU_HAS_DIV1, &cpuclk->flags)) {
+               div1 = cfg_data->div1;
+               if (readl(base + E4210_SRC_CPU) & E4210_MUX_HPM_MASK)
+                       div1 = readl(base + E4210_DIV_CPU1) &
+                               (E4210_DIV1_HPM_MASK | E4210_DIV1_COPY_MASK);
+       }
+
+       /*
+        * If the old parent clock speed is less than the clock speed of
+        * the alternate parent, then it should be ensured that at no point
+        * the armclk speed is more than the old_prate until the dividers are
+        * set.  Also workaround the issue of the dividers being set to lower
+        * values before the parent clock speed is set to new lower speed
+        * (this can result in too high speed of armclk output clocks).
+        */
+       if (alt_prate > ndata->old_rate || ndata->old_rate > ndata->new_rate) {
+               unsigned long tmp_rate = min(ndata->old_rate, ndata->new_rate);
+
+               alt_div = DIV_ROUND_UP(alt_prate, tmp_rate) - 1;
+               WARN_ON(alt_div >= MAX_DIV);
+
+               if (test_bit(CLK_CPU_NEEDS_DEBUG_ALT_DIV, &cpuclk->flags)) {
+                       /*
+                        * In Exynos4210, ATB clock parent is also mout_core. So
+                        * ATB clock also needs to be mantained at safe speed.
+                        */
+                       alt_div |= E4210_DIV0_ATB_MASK;
+                       alt_div_mask |= E4210_DIV0_ATB_MASK;
+               }
+               exynos_set_safe_div(base, alt_div, alt_div_mask);
+               div0 |= alt_div;
+       }
+
+       /* select sclk_mpll as the alternate parent */
+       mux_reg = readl(base + E4210_SRC_CPU);
+       writel(mux_reg | (1 << 16), base + E4210_SRC_CPU);
+       wait_until_mux_stable(base + E4210_STAT_CPU, 16, 2);
+
+       /* alternate parent is active now. set the dividers */
+       writel(div0, base + E4210_DIV_CPU0);
+       wait_until_divider_stable(base + E4210_DIV_STAT_CPU0, DIV_MASK_ALL);
+
+       if (test_bit(CLK_CPU_HAS_DIV1, &cpuclk->flags)) {
+               writel(div1, base + E4210_DIV_CPU1);
+               wait_until_divider_stable(base + E4210_DIV_STAT_CPU1,
+                               DIV_MASK_ALL);
+       }
+
+       spin_unlock(cpuclk->lock);
+       return 0;
+}
+
+/* handler for post-rate change notification from parent clock */
+static int exynos_cpuclk_post_rate_change(struct clk_notifier_data *ndata,
+                       struct exynos_cpuclk *cpuclk, void __iomem *base)
+{
+       const struct exynos_cpuclk_cfg_data *cfg_data = cpuclk->cfg;
+       unsigned long div = 0, div_mask = DIV_MASK;
+       unsigned long mux_reg;
+
+       /* find out the divider values to use for clock data */
+       if (test_bit(CLK_CPU_NEEDS_DEBUG_ALT_DIV, &cpuclk->flags)) {
+               while ((cfg_data->prate * 1000) != ndata->new_rate) {
+                       if (cfg_data->prate == 0)
+                               return -EINVAL;
+                       cfg_data++;
+               }
+       }
+
+       spin_lock(cpuclk->lock);
+
+       /* select mout_apll as the alternate parent */
+       mux_reg = readl(base + E4210_SRC_CPU);
+       writel(mux_reg & ~(1 << 16), base + E4210_SRC_CPU);
+       wait_until_mux_stable(base + E4210_STAT_CPU, 16, 1);
+
+       if (test_bit(CLK_CPU_NEEDS_DEBUG_ALT_DIV, &cpuclk->flags)) {
+               div |= (cfg_data->div0 & E4210_DIV0_ATB_MASK);
+               div_mask |= E4210_DIV0_ATB_MASK;
+       }
+
+       exynos_set_safe_div(base, div, div_mask);
+       spin_unlock(cpuclk->lock);
+       return 0;
+}
+
+/*
+ * This notifier function is called for the pre-rate and post-rate change
+ * notifications of the parent clock of cpuclk.
+ */
+static int exynos_cpuclk_notifier_cb(struct notifier_block *nb,
+                               unsigned long event, void *data)
+{
+       struct clk_notifier_data *ndata = data;
+       struct exynos_cpuclk *cpuclk;
+       void __iomem *base;
+       int err = 0;
+
+       cpuclk = container_of(nb, struct exynos_cpuclk, clk_nb);
+       base = cpuclk->ctrl_base;
+
+       if (event == PRE_RATE_CHANGE)
+               err = exynos_cpuclk_pre_rate_change(ndata, cpuclk, base);
+       else if (event == POST_RATE_CHANGE)
+               err = exynos_cpuclk_post_rate_change(ndata, cpuclk, base);
+
+       return notifier_from_errno(err);
+}
+
+/* helper function to register a CPU clock */
+int __init exynos_register_cpu_clock(struct samsung_clk_provider *ctx,
+               unsigned int lookup_id, const char *name, const char *parent,
+               const char *alt_parent, unsigned long offset,
+               const struct exynos_cpuclk_cfg_data *cfg,
+               unsigned long num_cfgs, unsigned long flags)
+{
+       struct exynos_cpuclk *cpuclk;
+       struct clk_init_data init;
+       struct clk *clk;
+       int ret = 0;
+
+       cpuclk = kzalloc(sizeof(*cpuclk), GFP_KERNEL);
+       if (!cpuclk)
+               return -ENOMEM;
+
+       init.name = name;
+       init.flags = CLK_SET_RATE_PARENT;
+       init.parent_names = &parent;
+       init.num_parents = 1;
+       init.ops = &exynos_cpuclk_clk_ops;
+
+       cpuclk->hw.init = &init;
+       cpuclk->ctrl_base = ctx->reg_base + offset;
+       cpuclk->lock = &ctx->lock;
+       cpuclk->flags = flags;
+       cpuclk->clk_nb.notifier_call = exynos_cpuclk_notifier_cb;
+
+       cpuclk->alt_parent = __clk_lookup(alt_parent);
+       if (!cpuclk->alt_parent) {
+               pr_err("%s: could not lookup alternate parent %s\n",
+                               __func__, alt_parent);
+               ret = -EINVAL;
+               goto free_cpuclk;
+       }
+
+       clk = __clk_lookup(parent);
+       if (!clk) {
+               pr_err("%s: could not lookup parent clock %s\n",
+                               __func__, parent);
+               ret = -EINVAL;
+               goto free_cpuclk;
+       }
+
+       ret = clk_notifier_register(clk, &cpuclk->clk_nb);
+       if (ret) {
+               pr_err("%s: failed to register clock notifier for %s\n",
+                               __func__, name);
+               goto free_cpuclk;
+       }
+
+       cpuclk->cfg = kmemdup(cfg, sizeof(*cfg) * num_cfgs, GFP_KERNEL);
+       if (!cpuclk->cfg) {
+               pr_err("%s: could not allocate memory for cpuclk data\n",
+                               __func__);
+               ret = -ENOMEM;
+               goto unregister_clk_nb;
+       }
+
+       clk = clk_register(NULL, &cpuclk->hw);
+       if (IS_ERR(clk)) {
+               pr_err("%s: could not register cpuclk %s\n", __func__,  name);
+               ret = PTR_ERR(clk);
+               goto free_cpuclk_data;
+       }
+
+       samsung_clk_add_lookup(ctx, clk, lookup_id);
+       return 0;
+
+free_cpuclk_data:
+       kfree(cpuclk->cfg);
+unregister_clk_nb:
+       clk_notifier_unregister(__clk_lookup(parent), &cpuclk->clk_nb);
+free_cpuclk:
+       kfree(cpuclk);
+       return ret;
+}
diff --git a/drivers/clk/samsung/clk-cpu.h b/drivers/clk/samsung/clk-cpu.h
new file mode 100644 (file)
index 0000000..37874d3
--- /dev/null
@@ -0,0 +1,73 @@
+/*
+ * Copyright (c) 2014 Samsung Electronics Co., Ltd.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * Common Clock Framework support for all PLL's in Samsung platforms
+*/
+
+#ifndef __SAMSUNG_CLK_CPU_H
+#define __SAMSUNG_CLK_CPU_H
+
+#include "clk.h"
+
+/**
+ * struct exynos_cpuclk_data: config data to setup cpu clocks.
+ * @prate: frequency of the primary parent clock (in KHz).
+ * @div0: value to be programmed in the div_cpu0 register.
+ * @div1: value to be programmed in the div_cpu1 register.
+ *
+ * This structure holds the divider configuration data for dividers in the CPU
+ * clock domain. The parent frequency at which these divider values are valid is
+ * specified in @prate. The @prate is the frequency of the primary parent clock.
+ * For CPU clock domains that do not have a DIV1 register, the @div1 member
+ * value is not used.
+ */
+struct exynos_cpuclk_cfg_data {
+       unsigned long   prate;
+       unsigned long   div0;
+       unsigned long   div1;
+};
+
+/**
+ * struct exynos_cpuclk: information about clock supplied to a CPU core.
+ * @hw:        handle between CCF and CPU clock.
+ * @alt_parent: alternate parent clock to use when switching the speed
+ *     of the primary parent clock.
+ * @ctrl_base: base address of the clock controller.
+ * @lock: cpu clock domain register access lock.
+ * @cfg: cpu clock rate configuration data.
+ * @num_cfgs: number of array elements in @cfg array.
+ * @clk_nb: clock notifier registered for changes in clock speed of the
+ *     primary parent clock.
+ * @flags: configuration flags for the CPU clock.
+ *
+ * This structure holds information required for programming the CPU clock for
+ * various clock speeds.
+ */
+struct exynos_cpuclk {
+       struct clk_hw                           hw;
+       struct clk                              *alt_parent;
+       void __iomem                            *ctrl_base;
+       spinlock_t                              *lock;
+       const struct exynos_cpuclk_cfg_data     *cfg;
+       const unsigned long                     num_cfgs;
+       struct notifier_block                   clk_nb;
+       unsigned long                           flags;
+
+/* The CPU clock registers has DIV1 configuration register */
+#define CLK_CPU_HAS_DIV1               (1 << 0)
+/* When ALT parent is active, debug clocks need safe divider values */
+#define CLK_CPU_NEEDS_DEBUG_ALT_DIV    (1 << 1)
+};
+
+extern int __init exynos_register_cpu_clock(struct samsung_clk_provider *ctx,
+                       unsigned int lookup_id, const char *name,
+                       const char *parent, const char *alt_parent,
+                       unsigned long offset,
+                       const struct exynos_cpuclk_cfg_data *cfg,
+                       unsigned long num_cfgs, unsigned long flags);
+
+#endif /* __SAMSUNG_CLK_CPU_H */
index 714d6ba782c81b2420c7770db183a3b6b1ffd785..cae2c048488db3e7a4c3545c81faa50f450797d7 100644 (file)
@@ -19,6 +19,7 @@
 #include <linux/syscore_ops.h>
 
 #include "clk.h"
+#include "clk-cpu.h"
 
 /* Exynos4 clock controller register offsets */
 #define SRC_LEFTBUS            0x4200
@@ -534,7 +535,8 @@ static struct samsung_fixed_factor_clock exynos4x12_fixed_factor_clks[] __initda
 /* list of mux clocks supported in all exynos4 soc's */
 static struct samsung_mux_clock exynos4_mux_clks[] __initdata = {
        MUX_FA(CLK_MOUT_APLL, "mout_apll", mout_apll_p, SRC_CPU, 0, 1,
-                       CLK_SET_RATE_PARENT, 0, "mout_apll"),
+                       CLK_SET_RATE_PARENT | CLK_RECALC_NEW_RATES, 0,
+                       "mout_apll"),
        MUX(CLK_MOUT_HDMI, "mout_hdmi", mout_hdmi_p, SRC_TV, 0, 1),
        MUX(0, "mout_mfc1", sclk_evpll_p, SRC_MFC, 4, 1),
        MUX(0, "mout_mfc", mout_mfc_p, SRC_MFC, 8, 1),
@@ -1378,6 +1380,22 @@ static void __init exynos4x12_core_down_clock(void)
        __raw_writel(0x0, reg_base + E4X12_PWR_CTRL2);
 }
 
+#define E4210_CPU_DIV0(apll, pclk_dbg, atb, periph, corem1, corem0)    \
+               (((apll) << 24) | ((pclk_dbg) << 20) | ((atb) << 16) |  \
+               ((periph) << 12) | ((corem1) << 8) | ((corem0) <<  4))
+#define E4210_CPU_DIV1(hpm, copy)                                      \
+               (((hpm) << 4) | ((copy) << 0))
+
+static const struct exynos_cpuclk_cfg_data e4210_armclk_d[] __initconst = {
+       { 1200000, E4210_CPU_DIV0(7, 1, 4, 3, 7, 3), E4210_CPU_DIV1(0, 5), },
+       { 1000000, E4210_CPU_DIV0(7, 1, 4, 3, 7, 3), E4210_CPU_DIV1(0, 4), },
+       {  800000, E4210_CPU_DIV0(7, 1, 3, 3, 7, 3), E4210_CPU_DIV1(0, 3), },
+       {  500000, E4210_CPU_DIV0(7, 1, 3, 3, 7, 3), E4210_CPU_DIV1(0, 3), },
+       {  400000, E4210_CPU_DIV0(7, 1, 3, 3, 7, 3), E4210_CPU_DIV1(0, 3), },
+       {  200000, E4210_CPU_DIV0(0, 1, 1, 1, 3, 1), E4210_CPU_DIV1(0, 3), },
+       {  0 },
+};
+
 /* register exynos4 clocks */
 static void __init exynos4_clk_init(struct device_node *np,
                                    enum exynos4_soc soc)
@@ -1455,6 +1473,10 @@ static void __init exynos4_clk_init(struct device_node *np,
                samsung_clk_register_fixed_factor(ctx,
                        exynos4210_fixed_factor_clks,
                        ARRAY_SIZE(exynos4210_fixed_factor_clks));
+               exynos_register_cpu_clock(ctx, CLK_ARM_CLK, "armclk",
+                       mout_core_p4210[0], mout_core_p4210[1], 0x14200,
+                       e4210_armclk_d, ARRAY_SIZE(e4210_armclk_d),
+                       CLK_CPU_NEEDS_DEBUG_ALT_DIV | CLK_CPU_HAS_DIV1);
        } else {
                samsung_clk_register_mux(ctx, exynos4x12_mux_clks,
                        ARRAY_SIZE(exynos4x12_mux_clks));
index e2e5193d10490b0295805023c448c1c0b685d02d..06f96eb7cf93c5b4c7d946d41b57b30078042db2 100644 (file)
@@ -94,7 +94,7 @@ PNAME(mout_aud_pll_user_p) = {"fin_pll", "fout_aud_pll"};
 PNAME(mout_sclk_aud_i2s_p) = {"mout_aud_pll_user", "ioclk_i2s_cdclk"};
 PNAME(mout_sclk_aud_pcm_p) = {"mout_aud_pll_user", "ioclk_pcm_extclk"};
 
-struct samsung_mux_clock aud_mux_clks[] __initdata = {
+static struct samsung_mux_clock aud_mux_clks[] __initdata = {
        MUX(AUD_MOUT_AUD_PLL_USER, "mout_aud_pll_user", mout_aud_pll_user_p,
                        MUX_SEL_AUD, 0, 1),
        MUX(AUD_MOUT_SCLK_AUD_I2S, "mout_sclk_aud_i2s", mout_sclk_aud_i2s_p,
@@ -103,7 +103,7 @@ struct samsung_mux_clock aud_mux_clks[] __initdata = {
                        MUX_SEL_AUD, 8, 1),
 };
 
-struct samsung_div_clock aud_div_clks[] __initdata = {
+static struct samsung_div_clock aud_div_clks[] __initdata = {
        DIV(AUD_DOUT_ACLK_AUD_131, "dout_aclk_aud_131", "mout_aud_pll_user",
                        DIV_AUD0, 0, 4),
 
@@ -115,7 +115,7 @@ struct samsung_div_clock aud_div_clks[] __initdata = {
                        DIV_AUD1, 12, 4),
 };
 
-struct samsung_gate_clock aud_gate_clks[] __initdata = {
+static struct samsung_gate_clock aud_gate_clks[] __initdata = {
        GATE(AUD_SCLK_I2S, "sclk_aud_i2s", "dout_sclk_aud_i2s",
                        EN_SCLK_AUD, 0, CLK_SET_RATE_PARENT, 0),
        GATE(AUD_SCLK_PCM, "sclk_aud_pcm", "dout_sclk_aud_pcm",
@@ -135,7 +135,7 @@ struct samsung_gate_clock aud_gate_clks[] __initdata = {
 
 static void __init exynos5260_clk_aud_init(struct device_node *np)
 {
-       struct samsung_cmu_info cmu = {0};
+       struct samsung_cmu_info cmu = { NULL };
 
        cmu.mux_clks = aud_mux_clks;
        cmu.nr_mux_clks = ARRAY_SIZE(aud_mux_clks);
@@ -203,7 +203,7 @@ PNAME(mout_phyclk_mipi_dphy_4lmrxclk_esc0_user_p) = {"fin_pll",
 PNAME(mout_sclk_hdmi_spdif_p) = {"fin_pll", "ioclk_spdif_extclk",
                        "dout_aclk_peri_aud", "phyclk_hdmi_phy_ref_cko"};
 
-struct samsung_mux_clock disp_mux_clks[] __initdata = {
+static struct samsung_mux_clock disp_mux_clks[] __initdata = {
        MUX(DISP_MOUT_ACLK_DISP_333_USER, "mout_aclk_disp_333_user",
                        mout_aclk_disp_333_user_p,
                        MUX_SEL_DISP0, 0, 1),
@@ -272,7 +272,7 @@ struct samsung_mux_clock disp_mux_clks[] __initdata = {
                        MUX_SEL_DISP4, 4, 2),
 };
 
-struct samsung_div_clock disp_div_clks[] __initdata = {
+static struct samsung_div_clock disp_div_clks[] __initdata = {
        DIV(DISP_DOUT_PCLK_DISP_111, "dout_pclk_disp_111",
                        "mout_aclk_disp_222_user",
                        DIV_DISP, 8, 4),
@@ -285,7 +285,7 @@ struct samsung_div_clock disp_div_clks[] __initdata = {
                        DIV_DISP, 16, 4),
 };
 
-struct samsung_gate_clock disp_gate_clks[] __initdata = {
+static struct samsung_gate_clock disp_gate_clks[] __initdata = {
        GATE(DISP_MOUT_HDMI_PHY_PIXEL_USER, "sclk_hdmi_link_i_pixel",
                        "mout_phyclk_hdmi_phy_pixel_clko_user",
                        EN_SCLK_DISP0, 26, CLK_SET_RATE_PARENT, 0),
@@ -325,7 +325,7 @@ struct samsung_gate_clock disp_gate_clks[] __initdata = {
 
 static void __init exynos5260_clk_disp_init(struct device_node *np)
 {
-       struct samsung_cmu_info cmu = {0};
+       struct samsung_cmu_info cmu = { NULL };
 
        cmu.mux_clks = disp_mux_clks;
        cmu.nr_mux_clks = ARRAY_SIZE(disp_mux_clks);
@@ -363,13 +363,13 @@ static unsigned long egl_clk_regs[] __initdata = {
 PNAME(mout_egl_b_p) = {"mout_egl_pll", "dout_bus_pll"};
 PNAME(mout_egl_pll_p) = {"fin_pll", "fout_egl_pll"};
 
-struct samsung_mux_clock egl_mux_clks[] __initdata = {
+static struct samsung_mux_clock egl_mux_clks[] __initdata = {
        MUX(EGL_MOUT_EGL_PLL, "mout_egl_pll", mout_egl_pll_p,
                        MUX_SEL_EGL, 4, 1),
        MUX(EGL_MOUT_EGL_B, "mout_egl_b", mout_egl_b_p, MUX_SEL_EGL, 16, 1),
 };
 
-struct samsung_div_clock egl_div_clks[] __initdata = {
+static struct samsung_div_clock egl_div_clks[] __initdata = {
        DIV(EGL_DOUT_EGL1, "dout_egl1", "mout_egl_b", DIV_EGL, 0, 3),
        DIV(EGL_DOUT_EGL2, "dout_egl2", "dout_egl1", DIV_EGL, 4, 3),
        DIV(EGL_DOUT_ACLK_EGL, "dout_aclk_egl", "dout_egl2", DIV_EGL, 8, 3),
@@ -389,7 +389,7 @@ static struct samsung_pll_clock egl_pll_clks[] __initdata = {
 
 static void __init exynos5260_clk_egl_init(struct device_node *np)
 {
-       struct samsung_cmu_info cmu = {0};
+       struct samsung_cmu_info cmu = { NULL };
 
        cmu.pll_clks = egl_pll_clks;
        cmu.nr_pll_clks =  ARRAY_SIZE(egl_pll_clks);
@@ -433,7 +433,7 @@ PNAME(mout_phyclk_usbdrd30_pipe_pclk_user_p) = {"fin_pll",
 PNAME(mout_phyclk_usbdrd30_phyclock_user_p) = {"fin_pll",
                        "phyclk_usbdrd30_udrd30_phyclock"};
 
-struct samsung_mux_clock fsys_mux_clks[] __initdata = {
+static struct samsung_mux_clock fsys_mux_clks[] __initdata = {
        MUX(FSYS_MOUT_PHYCLK_USBDRD30_PHYCLOCK_USER,
                        "mout_phyclk_usbdrd30_phyclock_user",
                        mout_phyclk_usbdrd30_phyclock_user_p,
@@ -456,7 +456,7 @@ struct samsung_mux_clock fsys_mux_clks[] __initdata = {
                        MUX_SEL_FSYS1, 16, 1),
 };
 
-struct samsung_gate_clock fsys_gate_clks[] __initdata = {
+static struct samsung_gate_clock fsys_gate_clks[] __initdata = {
        GATE(FSYS_PHYCLK_USBHOST20, "phyclk_usbhost20_phyclock",
                        "mout_phyclk_usbdrd30_phyclock_user",
                        EN_SCLK_FSYS, 1, 0, 0),
@@ -491,7 +491,7 @@ struct samsung_gate_clock fsys_gate_clks[] __initdata = {
 
 static void __init exynos5260_clk_fsys_init(struct device_node *np)
 {
-       struct samsung_cmu_info cmu = {0};
+       struct samsung_cmu_info cmu = { NULL };
 
        cmu.mux_clks = fsys_mux_clks;
        cmu.nr_mux_clks = ARRAY_SIZE(fsys_mux_clks);
@@ -537,18 +537,18 @@ static unsigned long g2d_clk_regs[] __initdata = {
 
 PNAME(mout_aclk_g2d_333_user_p) = {"fin_pll", "dout_aclk_g2d_333"};
 
-struct samsung_mux_clock g2d_mux_clks[] __initdata = {
+static struct samsung_mux_clock g2d_mux_clks[] __initdata = {
        MUX(G2D_MOUT_ACLK_G2D_333_USER, "mout_aclk_g2d_333_user",
                        mout_aclk_g2d_333_user_p,
                        MUX_SEL_G2D, 0, 1),
 };
 
-struct samsung_div_clock g2d_div_clks[] __initdata = {
+static struct samsung_div_clock g2d_div_clks[] __initdata = {
        DIV(G2D_DOUT_PCLK_G2D_83, "dout_pclk_g2d_83", "mout_aclk_g2d_333_user",
                        DIV_G2D, 0, 3),
 };
 
-struct samsung_gate_clock g2d_gate_clks[] __initdata = {
+static struct samsung_gate_clock g2d_gate_clks[] __initdata = {
        GATE(G2D_CLK_G2D, "clk_g2d", "mout_aclk_g2d_333_user",
                        EN_IP_G2D, 4, 0, 0),
        GATE(G2D_CLK_JPEG, "clk_jpeg", "mout_aclk_g2d_333_user",
@@ -580,7 +580,7 @@ struct samsung_gate_clock g2d_gate_clks[] __initdata = {
 
 static void __init exynos5260_clk_g2d_init(struct device_node *np)
 {
-       struct samsung_cmu_info cmu = {0};
+       struct samsung_cmu_info cmu = { NULL };
 
        cmu.mux_clks = g2d_mux_clks;
        cmu.nr_mux_clks = ARRAY_SIZE(g2d_mux_clks);
@@ -617,17 +617,17 @@ static unsigned long g3d_clk_regs[] __initdata = {
 
 PNAME(mout_g3d_pll_p) = {"fin_pll", "fout_g3d_pll"};
 
-struct samsung_mux_clock g3d_mux_clks[] __initdata = {
+static struct samsung_mux_clock g3d_mux_clks[] __initdata = {
        MUX(G3D_MOUT_G3D_PLL, "mout_g3d_pll", mout_g3d_pll_p,
                        MUX_SEL_G3D, 0, 1),
 };
 
-struct samsung_div_clock g3d_div_clks[] __initdata = {
+static struct samsung_div_clock g3d_div_clks[] __initdata = {
        DIV(G3D_DOUT_PCLK_G3D, "dout_pclk_g3d", "dout_aclk_g3d", DIV_G3D, 0, 3),
        DIV(G3D_DOUT_ACLK_G3D, "dout_aclk_g3d", "mout_g3d_pll", DIV_G3D, 4, 3),
 };
 
-struct samsung_gate_clock g3d_gate_clks[] __initdata = {
+static struct samsung_gate_clock g3d_gate_clks[] __initdata = {
        GATE(G3D_CLK_G3D, "clk_g3d", "dout_aclk_g3d", EN_IP_G3D, 2, 0, 0),
        GATE(G3D_CLK_G3D_HPM, "clk_g3d_hpm", "dout_aclk_g3d",
                        EN_IP_G3D, 3, 0, 0),
@@ -641,7 +641,7 @@ static struct samsung_pll_clock g3d_pll_clks[] __initdata = {
 
 static void __init exynos5260_clk_g3d_init(struct device_node *np)
 {
-       struct samsung_cmu_info cmu = {0};
+       struct samsung_cmu_info cmu = { NULL };
 
        cmu.pll_clks = g3d_pll_clks;
        cmu.nr_pll_clks =  ARRAY_SIZE(g3d_pll_clks);
@@ -694,7 +694,7 @@ PNAME(mout_aclk_m2m_400_user_p) = {"fin_pll", "dout_aclk_gscl_400"};
 PNAME(mout_aclk_gscl_fimc_user_p) = {"fin_pll", "dout_aclk_gscl_400"};
 PNAME(mout_aclk_csis_p) = {"dout_aclk_csis_200", "mout_aclk_gscl_fimc_user"};
 
-struct samsung_mux_clock gscl_mux_clks[] __initdata = {
+static struct samsung_mux_clock gscl_mux_clks[] __initdata = {
        MUX(GSCL_MOUT_ACLK_GSCL_333_USER, "mout_aclk_gscl_333_user",
                        mout_aclk_gscl_333_user_p,
                        MUX_SEL_GSCL, 0, 1),
@@ -708,7 +708,7 @@ struct samsung_mux_clock gscl_mux_clks[] __initdata = {
                        MUX_SEL_GSCL, 24, 1),
 };
 
-struct samsung_div_clock gscl_div_clks[] __initdata = {
+static struct samsung_div_clock gscl_div_clks[] __initdata = {
        DIV(GSCL_DOUT_PCLK_M2M_100, "dout_pclk_m2m_100",
                        "mout_aclk_m2m_400_user",
                        DIV_GSCL, 0, 3),
@@ -717,7 +717,7 @@ struct samsung_div_clock gscl_div_clks[] __initdata = {
                        DIV_GSCL, 4, 3),
 };
 
-struct samsung_gate_clock gscl_gate_clks[] __initdata = {
+static struct samsung_gate_clock gscl_gate_clks[] __initdata = {
        GATE(GSCL_SCLK_CSIS0_WRAP, "sclk_csis0_wrap", "dout_aclk_csis_200",
                        EN_SCLK_GSCL_FIMC, 0, CLK_SET_RATE_PARENT, 0),
        GATE(GSCL_SCLK_CSIS1_WRAP, "sclk_csis1_wrap", "dout_aclk_csis_200",
@@ -776,7 +776,7 @@ struct samsung_gate_clock gscl_gate_clks[] __initdata = {
 
 static void __init exynos5260_clk_gscl_init(struct device_node *np)
 {
-       struct samsung_cmu_info cmu = {0};
+       struct samsung_cmu_info cmu = { NULL };
 
        cmu.mux_clks = gscl_mux_clks;
        cmu.nr_mux_clks = ARRAY_SIZE(gscl_mux_clks);
@@ -813,14 +813,14 @@ static unsigned long isp_clk_regs[] __initdata = {
 PNAME(mout_isp_400_user_p) = {"fin_pll", "dout_aclk_isp1_400"};
 PNAME(mout_isp_266_user_p)      = {"fin_pll", "dout_aclk_isp1_266"};
 
-struct samsung_mux_clock isp_mux_clks[] __initdata = {
+static struct samsung_mux_clock isp_mux_clks[] __initdata = {
        MUX(ISP_MOUT_ISP_266_USER, "mout_isp_266_user", mout_isp_266_user_p,
                        MUX_SEL_ISP0, 0, 1),
        MUX(ISP_MOUT_ISP_400_USER, "mout_isp_400_user", mout_isp_400_user_p,
                        MUX_SEL_ISP0, 4, 1),
 };
 
-struct samsung_div_clock isp_div_clks[] __initdata = {
+static struct samsung_div_clock isp_div_clks[] __initdata = {
        DIV(ISP_DOUT_PCLK_ISP_66, "dout_pclk_isp_66", "mout_kfc",
                        DIV_ISP, 0, 3),
        DIV(ISP_DOUT_PCLK_ISP_133, "dout_pclk_isp_133", "mout_kfc",
@@ -832,7 +832,7 @@ struct samsung_div_clock isp_div_clks[] __initdata = {
        DIV(ISP_DOUT_SCLK_MPWM, "dout_sclk_mpwm", "mout_kfc", DIV_ISP, 20, 2),
 };
 
-struct samsung_gate_clock isp_gate_clks[] __initdata = {
+static struct samsung_gate_clock isp_gate_clks[] __initdata = {
        GATE(ISP_CLK_GIC, "clk_isp_gic", "mout_aclk_isp1_266",
                        EN_IP_ISP0, 15, 0, 0),
 
@@ -895,7 +895,7 @@ struct samsung_gate_clock isp_gate_clks[] __initdata = {
 
 static void __init exynos5260_clk_isp_init(struct device_node *np)
 {
-       struct samsung_cmu_info cmu = {0};
+       struct samsung_cmu_info cmu = { NULL };
 
        cmu.mux_clks = isp_mux_clks;
        cmu.nr_mux_clks = ARRAY_SIZE(isp_mux_clks);
@@ -934,13 +934,13 @@ static unsigned long kfc_clk_regs[] __initdata = {
 PNAME(mout_kfc_pll_p) = {"fin_pll", "fout_kfc_pll"};
 PNAME(mout_kfc_p)       = {"mout_kfc_pll", "dout_media_pll"};
 
-struct samsung_mux_clock kfc_mux_clks[] __initdata = {
+static struct samsung_mux_clock kfc_mux_clks[] __initdata = {
        MUX(KFC_MOUT_KFC_PLL, "mout_kfc_pll", mout_kfc_pll_p,
                        MUX_SEL_KFC0, 0, 1),
        MUX(KFC_MOUT_KFC, "mout_kfc", mout_kfc_p, MUX_SEL_KFC2, 0, 1),
 };
 
-struct samsung_div_clock kfc_div_clks[] __initdata = {
+static struct samsung_div_clock kfc_div_clks[] __initdata = {
        DIV(KFC_DOUT_KFC1, "dout_kfc1", "mout_kfc", DIV_KFC, 0, 3),
        DIV(KFC_DOUT_KFC2, "dout_kfc2", "dout_kfc1", DIV_KFC, 4, 3),
        DIV(KFC_DOUT_KFC_ATCLK, "dout_kfc_atclk", "dout_kfc2", DIV_KFC, 8, 3),
@@ -959,7 +959,7 @@ static struct samsung_pll_clock kfc_pll_clks[] __initdata = {
 
 static void __init exynos5260_clk_kfc_init(struct device_node *np)
 {
-       struct samsung_cmu_info cmu = {0};
+       struct samsung_cmu_info cmu = { NULL };
 
        cmu.pll_clks = kfc_pll_clks;
        cmu.nr_pll_clks =  ARRAY_SIZE(kfc_pll_clks);
@@ -993,18 +993,18 @@ static unsigned long mfc_clk_regs[] __initdata = {
 
 PNAME(mout_aclk_mfc_333_user_p) = {"fin_pll", "dout_aclk_mfc_333"};
 
-struct samsung_mux_clock mfc_mux_clks[] __initdata = {
+static struct samsung_mux_clock mfc_mux_clks[] __initdata = {
        MUX(MFC_MOUT_ACLK_MFC_333_USER, "mout_aclk_mfc_333_user",
                        mout_aclk_mfc_333_user_p,
                        MUX_SEL_MFC, 0, 1),
 };
 
-struct samsung_div_clock mfc_div_clks[] __initdata = {
+static struct samsung_div_clock mfc_div_clks[] __initdata = {
        DIV(MFC_DOUT_PCLK_MFC_83, "dout_pclk_mfc_83", "mout_aclk_mfc_333_user",
                        DIV_MFC, 0, 3),
 };
 
-struct samsung_gate_clock mfc_gate_clks[] __initdata = {
+static struct samsung_gate_clock mfc_gate_clks[] __initdata = {
        GATE(MFC_CLK_MFC, "clk_mfc", "mout_aclk_mfc_333_user",
                        EN_IP_MFC, 1, 0, 0),
        GATE(MFC_CLK_SMMU2_MFCM0, "clk_smmu2_mfcm0", "mout_aclk_mfc_333_user",
@@ -1015,7 +1015,7 @@ struct samsung_gate_clock mfc_gate_clks[] __initdata = {
 
 static void __init exynos5260_clk_mfc_init(struct device_node *np)
 {
-       struct samsung_cmu_info cmu = {0};
+       struct samsung_cmu_info cmu = { NULL };
 
        cmu.mux_clks = mfc_mux_clks;
        cmu.nr_mux_clks = ARRAY_SIZE(mfc_mux_clks);
@@ -1078,7 +1078,7 @@ PNAME(mout_mif_drex2x_p) = {"dout_mem_pll", "dout_bus_pll"};
 PNAME(mout_clkm_phy_p) = {"mout_mif_drex", "dout_media_pll"};
 PNAME(mout_clk2x_phy_p) = {"mout_mif_drex2x", "dout_media_pll"};
 
-struct samsung_mux_clock mif_mux_clks[] __initdata = {
+static struct samsung_mux_clock mif_mux_clks[] __initdata = {
        MUX(MIF_MOUT_MEM_PLL, "mout_mem_pll", mout_mem_pll_p,
                        MUX_SEL_MIF, 0, 1),
        MUX(MIF_MOUT_BUS_PLL, "mout_bus_pll", mout_bus_pll_p,
@@ -1095,7 +1095,7 @@ struct samsung_mux_clock mif_mux_clks[] __initdata = {
                        MUX_SEL_MIF, 24, 1),
 };
 
-struct samsung_div_clock mif_div_clks[] __initdata = {
+static struct samsung_div_clock mif_div_clks[] __initdata = {
        DIV(MIF_DOUT_MEDIA_PLL, "dout_media_pll", "mout_media_pll",
                        DIV_MIF, 0, 3),
        DIV(MIF_DOUT_MEM_PLL, "dout_mem_pll", "mout_mem_pll",
@@ -1114,7 +1114,7 @@ struct samsung_div_clock mif_div_clks[] __initdata = {
                        DIV_MIF, 28, 4),
 };
 
-struct samsung_gate_clock mif_gate_clks[] __initdata = {
+static struct samsung_gate_clock mif_gate_clks[] __initdata = {
        GATE(MIF_CLK_LPDDR3PHY_WRAP0, "clk_lpddr3phy_wrap0", "dout_clk2x_phy",
                        EN_IP_MIF, 12, CLK_IGNORE_UNUSED, 0),
        GATE(MIF_CLK_LPDDR3PHY_WRAP1, "clk_lpddr3phy_wrap1", "dout_clk2x_phy",
@@ -1162,7 +1162,7 @@ static struct samsung_pll_clock mif_pll_clks[] __initdata = {
 
 static void __init exynos5260_clk_mif_init(struct device_node *np)
 {
-       struct samsung_cmu_info cmu = {0};
+       struct samsung_cmu_info cmu = { NULL };
 
        cmu.pll_clks = mif_pll_clks;
        cmu.nr_pll_clks =  ARRAY_SIZE(mif_pll_clks);
@@ -1221,7 +1221,7 @@ PNAME(mout_sclk_i2scod_p) = {"ioclk_i2s_cdclk", "fin_pll", "dout_aclk_peri_aud",
 PNAME(mout_sclk_spdif_p) = {"ioclk_spdif_extclk", "fin_pll",
                        "dout_aclk_peri_aud", "phyclk_hdmi_phy_ref_cko"};
 
-struct samsung_mux_clock peri_mux_clks[] __initdata = {
+static struct samsung_mux_clock peri_mux_clks[] __initdata = {
        MUX(PERI_MOUT_SCLK_PCM, "mout_sclk_pcm", mout_sclk_pcm_p,
                        MUX_SEL_PERI1, 4, 2),
        MUX(PERI_MOUT_SCLK_I2SCOD, "mout_sclk_i2scod", mout_sclk_i2scod_p,
@@ -1230,12 +1230,12 @@ struct samsung_mux_clock peri_mux_clks[] __initdata = {
                        MUX_SEL_PERI1, 20, 2),
 };
 
-struct samsung_div_clock peri_div_clks[] __initdata = {
+static struct samsung_div_clock peri_div_clks[] __initdata = {
        DIV(PERI_DOUT_PCM, "dout_pcm", "mout_sclk_pcm", DIV_PERI, 0, 8),
        DIV(PERI_DOUT_I2S, "dout_i2s", "mout_sclk_i2scod", DIV_PERI, 8, 6),
 };
 
-struct samsung_gate_clock peri_gate_clks[] __initdata = {
+static struct samsung_gate_clock peri_gate_clks[] __initdata = {
        GATE(PERI_SCLK_PCM1, "sclk_pcm1", "dout_pcm", EN_SCLK_PERI, 0,
                        CLK_SET_RATE_PARENT, 0),
        GATE(PERI_SCLK_I2S, "sclk_i2s", "dout_i2s", EN_SCLK_PERI, 1,
@@ -1370,7 +1370,7 @@ struct samsung_gate_clock peri_gate_clks[] __initdata = {
 
 static void __init exynos5260_clk_peri_init(struct device_node *np)
 {
-       struct samsung_cmu_info cmu = {0};
+       struct samsung_cmu_info cmu = { NULL };
 
        cmu.mux_clks = peri_mux_clks;
        cmu.nr_mux_clks = ARRAY_SIZE(peri_mux_clks);
@@ -1432,7 +1432,7 @@ static unsigned long top_clk_regs[] __initdata = {
 };
 
 /* fixed rate clocks generated inside the soc */
-struct samsung_fixed_rate_clock fixed_rate_clks[] __initdata = {
+static struct samsung_fixed_rate_clock fixed_rate_clks[] __initdata = {
        FRATE(PHYCLK_DPTX_PHY_CH3_TXD_CLK, "phyclk_dptx_phy_ch3_txd_clk", NULL,
                        CLK_IS_ROOT, 270000000),
        FRATE(PHYCLK_DPTX_PHY_CH2_TXD_CLK, "phyclk_dptx_phy_ch2_txd_clk", NULL,
@@ -1519,7 +1519,7 @@ PNAME(mout_sclk_fsys_mmc1_sdclkin_b_p) = {"mout_sclk_fsys_mmc1_sdclkin_a",
 PNAME(mout_sclk_fsys_mmc2_sdclkin_b_p) = {"mout_sclk_fsys_mmc2_sdclkin_a",
                        "mout_mediatop_pll_user"};
 
-struct samsung_mux_clock top_mux_clks[] __initdata = {
+static struct samsung_mux_clock top_mux_clks[] __initdata = {
        MUX(TOP_MOUT_MEDIATOP_PLL_USER, "mout_mediatop_pll_user",
                        mout_mediatop_pll_user_p,
                        MUX_SEL_TOP_PLL0, 0, 1),
@@ -1679,7 +1679,7 @@ struct samsung_mux_clock top_mux_clks[] __initdata = {
                        MUX_SEL_TOP_GSCL, 20, 1),
 };
 
-struct samsung_div_clock top_div_clks[] __initdata = {
+static struct samsung_div_clock top_div_clks[] __initdata = {
        DIV(TOP_DOUT_ACLK_G2D_333, "dout_aclk_g2d_333", "mout_aclk_g2d_333",
                        DIV_TOP_G2D_MFC, 0, 3),
        DIV(TOP_DOUT_ACLK_MFC_333, "dout_aclk_mfc_333", "mout_aclk_mfc_333",
@@ -1800,7 +1800,7 @@ struct samsung_div_clock top_div_clks[] __initdata = {
 
 };
 
-struct samsung_gate_clock top_gate_clks[] __initdata = {
+static struct samsung_gate_clock top_gate_clks[] __initdata = {
        GATE(TOP_SCLK_MMC0, "sclk_fsys_mmc0_sdclkin",
                        "dout_sclk_fsys_mmc0_sdclkin_b",
                        EN_SCLK_TOP, 7, CLK_SET_RATE_PARENT, 0),
@@ -1826,7 +1826,7 @@ static struct samsung_pll_clock top_pll_clks[] __initdata = {
 
 static void __init exynos5260_clk_top_init(struct device_node *np)
 {
-       struct samsung_cmu_info cmu = {0};
+       struct samsung_cmu_info cmu = { NULL };
 
        cmu.pll_clks = top_pll_clks;
        cmu.nr_pll_clks =  ARRAY_SIZE(top_pll_clks);
index bea4a173eef5e40e12a4a05f8f6ccb3310700814..a1d731ca8f48587870753182a1ef76db82072686 100644 (file)
@@ -504,7 +504,7 @@ static struct samsung_fixed_factor_clock
        FFACTOR(0, "ff_dout_spll2", "mout_sclk_spll", 1, 2, 0),
 };
 
-struct samsung_mux_clock exynos5800_mux_clks[] __initdata = {
+static struct samsung_mux_clock exynos5800_mux_clks[] __initdata = {
        MUX(0, "mout_aclk400_isp", mout_group3_5800_p, SRC_TOP0, 0, 3),
        MUX(0, "mout_aclk400_mscl", mout_group3_5800_p, SRC_TOP0, 4, 3),
        MUX(0, "mout_aclk400_wcore", mout_group2_5800_p, SRC_TOP0, 16, 3),
@@ -553,7 +553,7 @@ struct samsung_mux_clock exynos5800_mux_clks[] __initdata = {
        MUX(0, "mout_fimd1", mout_group2_p, SRC_DISP10, 4, 3),
 };
 
-struct samsung_div_clock exynos5800_div_clks[] __initdata = {
+static struct samsung_div_clock exynos5800_div_clks[] __initdata = {
        DIV(0, "dout_aclk400_wcore", "mout_aclk400_wcore", DIV_TOP0, 16, 3),
 
        DIV(0, "dout_aclk550_cam", "mout_aclk550_cam",
@@ -569,14 +569,14 @@ struct samsung_div_clock exynos5800_div_clks[] __initdata = {
        DIV(0, "dout_sclk_sw", "sclk_spll", DIV_TOP9, 24, 6),
 };
 
-struct samsung_gate_clock exynos5800_gate_clks[] __initdata = {
+static struct samsung_gate_clock exynos5800_gate_clks[] __initdata = {
        GATE(CLK_ACLK550_CAM, "aclk550_cam", "mout_user_aclk550_cam",
                                GATE_BUS_TOP, 24, 0, 0),
        GATE(CLK_ACLK432_SCALER, "aclk432_scaler", "mout_user_aclk432_scaler",
                                GATE_BUS_TOP, 27, 0, 0),
 };
 
-struct samsung_mux_clock exynos5420_mux_clks[] __initdata = {
+static struct samsung_mux_clock exynos5420_mux_clks[] __initdata = {
        MUX(0, "sclk_bpll", mout_bpll_p, TOP_SPARE2, 0, 1),
        MUX(0, "mout_aclk400_wcore_bpll", mout_aclk400_wcore_bpll_p,
                                TOP_SPARE2, 4, 1),
@@ -606,7 +606,7 @@ struct samsung_mux_clock exynos5420_mux_clks[] __initdata = {
        MUX(0, "mout_fimd1", mout_group3_p, SRC_DISP10, 4, 1),
 };
 
-struct samsung_div_clock exynos5420_div_clks[] __initdata = {
+static struct samsung_div_clock exynos5420_div_clks[] __initdata = {
        DIV(0, "dout_aclk400_wcore", "mout_aclk400_wcore_bpll",
                        DIV_TOP0, 16, 3),
 };
index 9e04ae2bb4d74912f18976c305a1738756b19837..39c95649d3d016d14da7500e5b5ea188860252c9 100644 (file)
@@ -835,6 +835,7 @@ static unsigned long cpif_clk_regs[] __initdata = {
        MPHY_PLL_CON1,
        MPHY_PLL_FREQ_DET,
        MUX_SEL_CPIF0,
+       DIV_CPIF,
        ENABLE_SCLK_CPIF,
 };
 
@@ -1389,7 +1390,7 @@ static struct samsung_gate_clock mif_gate_clks[] __initdata = {
 
        /* ENABLE_ACLK_MIF2 */
        GATE(CLK_ACLK_MIFND_266, "aclk_mifnd_266", "div_aclk_mif_266",
-                       ENABLE_ACLK_MIF2, 20, 0, 0),
+                       ENABLE_ACLK_MIF2, 20, CLK_IGNORE_UNUSED, 0),
        GATE(CLK_ACLK_PPMU_DREX1S3, "aclk_ppmu_drex1s3", "div_aclk_drex1",
                        ENABLE_ACLK_MIF2, 17, CLK_IGNORE_UNUSED, 0),
        GATE(CLK_ACLK_PPMU_DREX1S1, "aclk_ppmu_drex1s1", "div_aclk_drex1",
@@ -1832,39 +1833,39 @@ static struct samsung_gate_clock peris_gate_clks[] __initdata = {
 
        /* ENABLE_PCLK_PERIS_SECURE_TZPC */
        GATE(CLK_PCLK_TZPC12, "pclk_tzpc12", "aclk_peris_66",
-                       ENABLE_PCLK_PERIS_SECURE_TZPC, 12, 0, 0),
+                       ENABLE_PCLK_PERIS_SECURE_TZPC, 12, CLK_IGNORE_UNUSED, 0),
        GATE(CLK_PCLK_TZPC11, "pclk_tzpc11", "aclk_peris_66",
-                       ENABLE_PCLK_PERIS_SECURE_TZPC, 11, 0, 0),
+                       ENABLE_PCLK_PERIS_SECURE_TZPC, 11, CLK_IGNORE_UNUSED, 0),
        GATE(CLK_PCLK_TZPC10, "pclk_tzpc10", "aclk_peris_66",
-                       ENABLE_PCLK_PERIS_SECURE_TZPC, 10, 0, 0),
+                       ENABLE_PCLK_PERIS_SECURE_TZPC, 10, CLK_IGNORE_UNUSED, 0),
        GATE(CLK_PCLK_TZPC9, "pclk_tzpc9", "aclk_peris_66",
-                       ENABLE_PCLK_PERIS_SECURE_TZPC, 9, 0, 0),
+                       ENABLE_PCLK_PERIS_SECURE_TZPC, 9, CLK_IGNORE_UNUSED, 0),
        GATE(CLK_PCLK_TZPC8, "pclk_tzpc8", "aclk_peris_66",
-                       ENABLE_PCLK_PERIS_SECURE_TZPC, 8, 0, 0),
+                       ENABLE_PCLK_PERIS_SECURE_TZPC, 8, CLK_IGNORE_UNUSED, 0),
        GATE(CLK_PCLK_TZPC7, "pclk_tzpc7", "aclk_peris_66",
-                       ENABLE_PCLK_PERIS_SECURE_TZPC, 7, 0, 0),
+                       ENABLE_PCLK_PERIS_SECURE_TZPC, 7, CLK_IGNORE_UNUSED, 0),
        GATE(CLK_PCLK_TZPC6, "pclk_tzpc6", "aclk_peris_66",
-                       ENABLE_PCLK_PERIS_SECURE_TZPC, 6, 0, 0),
+                       ENABLE_PCLK_PERIS_SECURE_TZPC, 6, CLK_IGNORE_UNUSED, 0),
        GATE(CLK_PCLK_TZPC5, "pclk_tzpc5", "aclk_peris_66",
-                       ENABLE_PCLK_PERIS_SECURE_TZPC, 5, 0, 0),
+                       ENABLE_PCLK_PERIS_SECURE_TZPC, 5, CLK_IGNORE_UNUSED, 0),
        GATE(CLK_PCLK_TZPC4, "pclk_tzpc4", "aclk_peris_66",
-                       ENABLE_PCLK_PERIS_SECURE_TZPC, 4, 0, 0),
+                       ENABLE_PCLK_PERIS_SECURE_TZPC, 4, CLK_IGNORE_UNUSED, 0),
        GATE(CLK_PCLK_TZPC3, "pclk_tzpc3", "aclk_peris_66",
-                       ENABLE_PCLK_PERIS_SECURE_TZPC, 3, 0, 0),
+                       ENABLE_PCLK_PERIS_SECURE_TZPC, 3, CLK_IGNORE_UNUSED, 0),
        GATE(CLK_PCLK_TZPC2, "pclk_tzpc2", "aclk_peris_66",
-                       ENABLE_PCLK_PERIS_SECURE_TZPC, 2, 0, 0),
+                       ENABLE_PCLK_PERIS_SECURE_TZPC, 2, CLK_IGNORE_UNUSED, 0),
        GATE(CLK_PCLK_TZPC1, "pclk_tzpc1", "aclk_peris_66",
-                       ENABLE_PCLK_PERIS_SECURE_TZPC, 1, 0, 0),
+                       ENABLE_PCLK_PERIS_SECURE_TZPC, 1, CLK_IGNORE_UNUSED, 0),
        GATE(CLK_PCLK_TZPC0, "pclk_tzpc0", "aclk_peris_66",
-                       ENABLE_PCLK_PERIS_SECURE_TZPC, 0, 0, 0),
+                       ENABLE_PCLK_PERIS_SECURE_TZPC, 0, CLK_IGNORE_UNUSED, 0),
 
        /* ENABLE_PCLK_PERIS_SECURE_SECKEY_APBIF */
        GATE(CLK_PCLK_SECKEY_APBIF, "pclk_seckey_apbif", "aclk_peris_66",
-                       ENABLE_PCLK_PERIS_SECURE_SECKEY_APBIF, 0, 0, 0),
+                       ENABLE_PCLK_PERIS_SECURE_SECKEY_APBIF, 0, CLK_IGNORE_UNUSED, 0),
 
        /* ENABLE_PCLK_PERIS_SECURE_CHIPID_APBIF */
        GATE(CLK_PCLK_CHIPID_APBIF, "pclk_chipid_apbif", "aclk_peris_66",
-                       ENABLE_PCLK_PERIS_SECURE_CHIPID_APBIF, 0, 0, 0),
+                       ENABLE_PCLK_PERIS_SECURE_CHIPID_APBIF, 0, CLK_IGNORE_UNUSED, 0),
 
        /* ENABLE_PCLK_PERIS_SECURE_TOPRTC */
        GATE(CLK_PCLK_TOPRTC, "pclk_toprtc", "aclk_peris_66",
@@ -1895,11 +1896,11 @@ static struct samsung_gate_clock peris_gate_clks[] __initdata = {
 
        /* ENABLE_SCLK_PERIS_SECURE_SECKEY */
        GATE(CLK_SCLK_SECKEY, "sclk_seckey", "oscclk_efuse_common",
-                       ENABLE_SCLK_PERIS_SECURE_SECKEY, 0, 0, 0),
+                       ENABLE_SCLK_PERIS_SECURE_SECKEY, 0, CLK_IGNORE_UNUSED, 0),
 
        /* ENABLE_SCLK_PERIS_SECURE_CHIPID */
        GATE(CLK_SCLK_CHIPID, "sclk_chipid", "oscclk_efuse_common",
-                       ENABLE_SCLK_PERIS_SECURE_CHIPID, 0, 0, 0),
+                       ENABLE_SCLK_PERIS_SECURE_CHIPID, 0, CLK_IGNORE_UNUSED, 0),
 
        /* ENABLE_SCLK_PERIS_SECURE_TOPRTC */
        GATE(CLK_SCLK_TOPRTC, "sclk_toprtc", "oscclk_efuse_common",
@@ -3286,10 +3287,10 @@ static struct samsung_pll_clock g3d_pll_clks[] __initdata = {
 
 static struct samsung_mux_clock g3d_mux_clks[] __initdata = {
        /* MUX_SEL_G3D */
-       MUX(CLK_MOUT_ACLK_G3D_400, "mout_aclk_g3d_400", mout_aclk_g3d_400_p,
-                       MUX_SEL_G3D, 8, 1),
-       MUX(CLK_MOUT_G3D_PLL, "mout_g3d_pll", mout_g3d_pll_p,
-                       MUX_SEL_G3D, 0, 1),
+       MUX_F(CLK_MOUT_ACLK_G3D_400, "mout_aclk_g3d_400", mout_aclk_g3d_400_p,
+                       MUX_SEL_G3D, 8, 1, CLK_SET_RATE_PARENT, 0),
+       MUX_F(CLK_MOUT_G3D_PLL, "mout_g3d_pll", mout_g3d_pll_p,
+                       MUX_SEL_G3D, 0, 1, CLK_SET_RATE_PARENT, 0),
 };
 
 static struct samsung_div_clock g3d_div_clks[] __initdata = {
@@ -3298,8 +3299,8 @@ static struct samsung_div_clock g3d_div_clks[] __initdata = {
                        8, 2),
        DIV(CLK_DIV_PCLK_G3D, "div_pclk_g3d", "div_aclk_g3d", DIV_G3D,
                        4, 3),
-       DIV(CLK_DIV_ACLK_G3D, "div_aclk_g3d", "mout_aclk_g3d_400", DIV_G3D,
-                       0, 3),
+       DIV_F(CLK_DIV_ACLK_G3D, "div_aclk_g3d", "mout_aclk_g3d_400", DIV_G3D,
+                       0, 3, CLK_SET_RATE_PARENT, 0),
 };
 
 static struct samsung_gate_clock g3d_gate_clks[] __initdata = {
@@ -3309,9 +3310,9 @@ static struct samsung_gate_clock g3d_gate_clks[] __initdata = {
        GATE(CLK_ACLK_BTS_G3D0, "aclk_bts_g3d0", "div_aclk_g3d",
                        ENABLE_ACLK_G3D, 6, 0, 0),
        GATE(CLK_ACLK_ASYNCAPBS_G3D, "aclk_asyncapbs_g3d", "div_pclk_g3d",
-                       ENABLE_ACLK_G3D, 5, 0, 0),
+                       ENABLE_ACLK_G3D, 5, CLK_IGNORE_UNUSED, 0),
        GATE(CLK_ACLK_ASYNCAPBM_G3D, "aclk_asyncapbm_g3d", "div_aclk_g3d",
-                       ENABLE_ACLK_G3D, 4, 0, 0),
+                       ENABLE_ACLK_G3D, 4, CLK_IGNORE_UNUSED, 0),
        GATE(CLK_ACLK_AHB2APB_G3DP, "aclk_ahb2apb_g3dp", "div_pclk_g3d",
                        ENABLE_ACLK_G3D, 3, CLK_IGNORE_UNUSED, 0),
        GATE(CLK_ACLK_G3DNP_150, "aclk_g3dnp_150", "div_pclk_g3d",
@@ -3319,7 +3320,7 @@ static struct samsung_gate_clock g3d_gate_clks[] __initdata = {
        GATE(CLK_ACLK_G3DND_600, "aclk_g3dnd_600", "div_aclk_g3d",
                        ENABLE_ACLK_G3D, 1, CLK_IGNORE_UNUSED, 0),
        GATE(CLK_ACLK_G3D, "aclk_g3d", "div_aclk_g3d",
-                       ENABLE_ACLK_G3D, 0, 0, 0),
+                       ENABLE_ACLK_G3D, 0, CLK_SET_RATE_PARENT, 0),
 
        /* ENABLE_PCLK_G3D */
        GATE(CLK_PCLK_BTS_G3D1, "pclk_bts_g3d1", "div_pclk_g3d",
@@ -3582,7 +3583,7 @@ static struct samsung_pll_clock apollo_pll_clks[] __initdata = {
 static struct samsung_mux_clock apollo_mux_clks[] __initdata = {
        /* MUX_SEL_APOLLO0 */
        MUX_F(CLK_MOUT_APOLLO_PLL, "mout_apollo_pll", mout_apollo_pll_p,
-                       MUX_SEL_APOLLO0, 0, 1, 0, CLK_MUX_READ_ONLY),
+                       MUX_SEL_APOLLO0, 0, 1, CLK_SET_RATE_PARENT, 0),
 
        /* MUX_SEL_APOLLO1 */
        MUX(CLK_MOUT_BUS_PLL_APOLLO_USER, "mout_bus_pll_apollo_user",
@@ -3590,7 +3591,7 @@ static struct samsung_mux_clock apollo_mux_clks[] __initdata = {
 
        /* MUX_SEL_APOLLO2 */
        MUX_F(CLK_MOUT_APOLLO, "mout_apollo", mout_apollo_p, MUX_SEL_APOLLO2,
-                       0, 1, 0, CLK_MUX_READ_ONLY),
+                       0, 1, CLK_SET_RATE_PARENT, 0),
 };
 
 static struct samsung_div_clock apollo_div_clks[] __initdata = {
@@ -3611,11 +3612,9 @@ static struct samsung_div_clock apollo_div_clks[] __initdata = {
                        DIV_APOLLO0, 8, 3, CLK_GET_RATE_NOCACHE,
                        CLK_DIVIDER_READ_ONLY),
        DIV_F(CLK_DIV_APOLLO2, "div_apollo2", "div_apollo1",
-                       DIV_APOLLO0, 4, 3, CLK_GET_RATE_NOCACHE,
-                       CLK_DIVIDER_READ_ONLY),
+                       DIV_APOLLO0, 4, 3, CLK_SET_RATE_PARENT, 0),
        DIV_F(CLK_DIV_APOLLO1, "div_apollo1", "mout_apollo",
-                       DIV_APOLLO0, 0, 3, CLK_GET_RATE_NOCACHE,
-                       CLK_DIVIDER_READ_ONLY),
+                       DIV_APOLLO0, 0, 3, CLK_SET_RATE_PARENT, 0),
 
        /* DIV_APOLLO1 */
        DIV_F(CLK_DIV_SCLK_HPM_APOLLO, "div_sclk_hpm_apollo", "mout_apollo",
@@ -3666,7 +3665,8 @@ static struct samsung_gate_clock apollo_gate_clks[] __initdata = {
        GATE(CLK_SCLK_HPM_APOLLO, "sclk_hpm_apollo", "div_sclk_hpm_apollo",
                        ENABLE_SCLK_APOLLO, 1, CLK_IGNORE_UNUSED, 0),
        GATE(CLK_SCLK_APOLLO, "sclk_apollo", "div_apollo2",
-                       ENABLE_SCLK_APOLLO, 0, CLK_IGNORE_UNUSED, 0),
+                       ENABLE_SCLK_APOLLO, 0,
+                       CLK_IGNORE_UNUSED | CLK_SET_RATE_PARENT, 0),
 };
 
 static struct samsung_cmu_info apollo_cmu_info __initdata = {
@@ -3775,7 +3775,7 @@ static struct samsung_pll_clock atlas_pll_clks[] __initdata = {
 static struct samsung_mux_clock atlas_mux_clks[] __initdata = {
        /* MUX_SEL_ATLAS0 */
        MUX_F(CLK_MOUT_ATLAS_PLL, "mout_atlas_pll", mout_atlas_pll_p,
-                       MUX_SEL_ATLAS0, 0, 1, 0, CLK_MUX_READ_ONLY),
+                       MUX_SEL_ATLAS0, 0, 1, CLK_SET_RATE_PARENT, 0),
 
        /* MUX_SEL_ATLAS1 */
        MUX(CLK_MOUT_BUS_PLL_ATLAS_USER, "mout_bus_pll_atlas_user",
@@ -3783,7 +3783,7 @@ static struct samsung_mux_clock atlas_mux_clks[] __initdata = {
 
        /* MUX_SEL_ATLAS2 */
        MUX_F(CLK_MOUT_ATLAS, "mout_atlas", mout_atlas_p, MUX_SEL_ATLAS2,
-                       0, 1, 0, CLK_MUX_READ_ONLY),
+                       0, 1, CLK_SET_RATE_PARENT, 0),
 };
 
 static struct samsung_div_clock atlas_div_clks[] __initdata = {
@@ -3804,11 +3804,9 @@ static struct samsung_div_clock atlas_div_clks[] __initdata = {
                        DIV_ATLAS0, 8, 3, CLK_GET_RATE_NOCACHE,
                        CLK_DIVIDER_READ_ONLY),
        DIV_F(CLK_DIV_ATLAS2, "div_atlas2", "div_atlas1",
-                       DIV_ATLAS0, 4, 3, CLK_GET_RATE_NOCACHE,
-                       CLK_DIVIDER_READ_ONLY),
+                       DIV_ATLAS0, 4, 3, CLK_SET_RATE_PARENT, 0),
        DIV_F(CLK_DIV_ATLAS1, "div_atlas1", "mout_atlas",
-                       DIV_ATLAS0, 0, 3, CLK_GET_RATE_NOCACHE,
-                       CLK_DIVIDER_READ_ONLY),
+                       DIV_ATLAS0, 0, 3, CLK_SET_RATE_PARENT, 0),
 
        /* DIV_ATLAS1 */
        DIV_F(CLK_DIV_SCLK_HPM_ATLAS, "div_sclk_hpm_atlas", "mout_atlas",
@@ -3885,7 +3883,8 @@ static struct samsung_gate_clock atlas_gate_clks[] __initdata = {
        GATE(CLK_ATCLK, "atclk", "div_atclk_atlas",
                        ENABLE_SCLK_ATLAS, 1, CLK_IGNORE_UNUSED, 0),
        GATE(CLK_SCLK_ATLAS, "sclk_atlas", "div_atlas2",
-                       ENABLE_SCLK_ATLAS, 0, CLK_IGNORE_UNUSED, 0),
+                       ENABLE_SCLK_ATLAS, 0,
+                       CLK_IGNORE_UNUSED | CLK_SET_RATE_PARENT, 0),
 };
 
 static struct samsung_cmu_info atlas_cmu_info __initdata = {
index 9d70e5c03804cee247ee54ff4faed549bbf7ea12..bebc61b5fce1f3741200bf146e6dd059a222f5b9 100644 (file)
@@ -1156,7 +1156,7 @@ static const struct clk_ops samsung_pll2650xx_clk_min_ops = {
 };
 
 static void __init _samsung_clk_register_pll(struct samsung_clk_provider *ctx,
-                               struct samsung_pll_clock *pll_clk,
+                               const struct samsung_pll_clock *pll_clk,
                                void __iomem *base)
 {
        struct samsung_clk_pll *pll;
@@ -1303,7 +1303,7 @@ static void __init _samsung_clk_register_pll(struct samsung_clk_provider *ctx,
 }
 
 void __init samsung_clk_register_pll(struct samsung_clk_provider *ctx,
-                       struct samsung_pll_clock *pll_list,
+                       const struct samsung_pll_clock *pll_list,
                        unsigned int nr_pll, void __iomem *base)
 {
        int cnt;
index f4f29ed6bd25a4d6d4cd0174738aaa93d6541353..e56df5064889e00530ddf8c531e29539debecc76 100644 (file)
@@ -81,13 +81,13 @@ static int s3c24xx_clkout_set_parent(struct clk_hw *hw, u8 index)
        return ret;
 }
 
-const struct clk_ops s3c24xx_clkout_ops = {
+static const struct clk_ops s3c24xx_clkout_ops = {
        .get_parent = s3c24xx_clkout_get_parent,
        .set_parent = s3c24xx_clkout_set_parent,
        .determine_rate = __clk_mux_determine_rate,
 };
 
-struct clk *s3c24xx_register_clkout(struct device *dev, const char *name,
+static struct clk *s3c24xx_register_clkout(struct device *dev, const char *name,
                const char **parent_names, u8 num_parents,
                u8 shift, u32 mask)
 {
@@ -404,7 +404,7 @@ static struct s3c24xx_dclk_drv_data dclk_variants[] = {
        },
 };
 
-static struct platform_device_id s3c24xx_dclk_driver_ids[] = {
+static const struct platform_device_id s3c24xx_dclk_driver_ids[] = {
        {
                .name           = "s3c2410-dclk",
                .driver_data    = (kernel_ulong_t)&dclk_variants[S3C2410],
index e668e479a6970301c9512711bb6b4f044ff670e5..cf7e8fa7b624c701511d7cefadb4c721221ec1bd 100644 (file)
@@ -169,44 +169,44 @@ static inline void s5pv210_clk_sleep_init(void) { }
 #endif
 
 /* Mux parent lists. */
-static const char *fin_pll_p[] __initdata = {
+static const char *const fin_pll_p[] __initconst = {
        "xxti",
        "xusbxti"
 };
 
-static const char *mout_apll_p[] __initdata = {
+static const char *const mout_apll_p[] __initconst = {
        "fin_pll",
        "fout_apll"
 };
 
-static const char *mout_mpll_p[] __initdata = {
+static const char *const mout_mpll_p[] __initconst = {
        "fin_pll",
        "fout_mpll"
 };
 
-static const char *mout_epll_p[] __initdata = {
+static const char *const mout_epll_p[] __initconst = {
        "fin_pll",
        "fout_epll"
 };
 
-static const char *mout_vpllsrc_p[] __initdata = {
+static const char *const mout_vpllsrc_p[] __initconst = {
        "fin_pll",
        "sclk_hdmi27m"
 };
 
-static const char *mout_vpll_p[] __initdata = {
+static const char *const mout_vpll_p[] __initconst = {
        "mout_vpllsrc",
        "fout_vpll"
 };
 
-static const char *mout_group1_p[] __initdata = {
+static const char *const mout_group1_p[] __initconst = {
        "dout_a2m",
        "mout_mpll",
        "mout_epll",
        "mout_vpll"
 };
 
-static const char *mout_group2_p[] __initdata = {
+static const char *const mout_group2_p[] __initconst = {
        "xxti",
        "xusbxti",
        "sclk_hdmi27m",
@@ -218,7 +218,7 @@ static const char *mout_group2_p[] __initdata = {
        "mout_vpll",
 };
 
-static const char *mout_audio0_p[] __initdata = {
+static const char *const mout_audio0_p[] __initconst = {
        "xxti",
        "pcmcdclk0",
        "sclk_hdmi27m",
@@ -230,7 +230,7 @@ static const char *mout_audio0_p[] __initdata = {
        "mout_vpll",
 };
 
-static const char *mout_audio1_p[] __initdata = {
+static const char *const mout_audio1_p[] __initconst = {
        "i2scdclk1",
        "pcmcdclk1",
        "sclk_hdmi27m",
@@ -242,7 +242,7 @@ static const char *mout_audio1_p[] __initdata = {
        "mout_vpll",
 };
 
-static const char *mout_audio2_p[] __initdata = {
+static const char *const mout_audio2_p[] __initconst = {
        "i2scdclk2",
        "pcmcdclk2",
        "sclk_hdmi27m",
@@ -254,63 +254,63 @@ static const char *mout_audio2_p[] __initdata = {
        "mout_vpll",
 };
 
-static const char *mout_spdif_p[] __initdata = {
+static const char *const mout_spdif_p[] __initconst = {
        "dout_audio0",
        "dout_audio1",
        "dout_audio3",
 };
 
-static const char *mout_group3_p[] __initdata = {
+static const char *const mout_group3_p[] __initconst = {
        "mout_apll",
        "mout_mpll"
 };
 
-static const char *mout_group4_p[] __initdata = {
+static const char *const mout_group4_p[] __initconst = {
        "mout_mpll",
        "dout_a2m"
 };
 
-static const char *mout_flash_p[] __initdata = {
+static const char *const mout_flash_p[] __initconst = {
        "dout_hclkd",
        "dout_hclkp"
 };
 
-static const char *mout_dac_p[] __initdata = {
+static const char *const mout_dac_p[] __initconst = {
        "mout_vpll",
        "sclk_hdmiphy"
 };
 
-static const char *mout_hdmi_p[] __initdata = {
+static const char *const mout_hdmi_p[] __initconst = {
        "sclk_hdmiphy",
        "dout_tblk"
 };
 
-static const char *mout_mixer_p[] __initdata = {
+static const char *const mout_mixer_p[] __initconst = {
        "mout_dac",
        "mout_hdmi"
 };
 
-static const char *mout_vpll_6442_p[] __initdata = {
+static const char *const mout_vpll_6442_p[] __initconst = {
        "fin_pll",
        "fout_vpll"
 };
 
-static const char *mout_mixer_6442_p[] __initdata = {
+static const char *const mout_mixer_6442_p[] __initconst = {
        "mout_vpll",
        "dout_mixer"
 };
 
-static const char *mout_d0sync_6442_p[] __initdata = {
+static const char *const mout_d0sync_6442_p[] __initconst = {
        "mout_dsys",
        "div_apll"
 };
 
-static const char *mout_d1sync_6442_p[] __initdata = {
+static const char *const mout_d1sync_6442_p[] __initconst = {
        "mout_psys",
        "div_apll"
 };
 
-static const char *mout_group2_6442_p[] __initdata = {
+static const char *const mout_group2_6442_p[] __initconst = {
        "fin_pll",
        "none",
        "none",
@@ -322,7 +322,7 @@ static const char *mout_group2_6442_p[] __initdata = {
        "mout_vpll",
 };
 
-static const char *mout_audio0_6442_p[] __initdata = {
+static const char *const mout_audio0_6442_p[] __initconst = {
        "fin_pll",
        "pcmcdclk0",
        "none",
@@ -334,7 +334,7 @@ static const char *mout_audio0_6442_p[] __initdata = {
        "mout_vpll",
 };
 
-static const char *mout_audio1_6442_p[] __initdata = {
+static const char *const mout_audio1_6442_p[] __initconst = {
        "i2scdclk1",
        "pcmcdclk1",
        "none",
@@ -347,7 +347,7 @@ static const char *mout_audio1_6442_p[] __initdata = {
        "fin_pll",
 };
 
-static const char *mout_clksel_p[] __initdata = {
+static const char *const mout_clksel_p[] __initconst = {
        "fout_apll_clkout",
        "fout_mpll_clkout",
        "fout_epll",
@@ -370,7 +370,7 @@ static const char *mout_clksel_p[] __initdata = {
        "div_dclk"
 };
 
-static const char *mout_clksel_6442_p[] __initdata = {
+static const char *const mout_clksel_6442_p[] __initconst = {
        "fout_apll_clkout",
        "fout_mpll_clkout",
        "fout_epll",
@@ -393,7 +393,7 @@ static const char *mout_clksel_6442_p[] __initdata = {
        "div_dclk"
 };
 
-static const char *mout_clkout_p[] __initdata = {
+static const char *const mout_clkout_p[] __initconst = {
        "dout_clkout",
        "none",
        "xxti",
@@ -401,20 +401,20 @@ static const char *mout_clkout_p[] __initdata = {
 };
 
 /* Common fixed factor clocks. */
-static struct samsung_fixed_factor_clock ffactor_clks[] __initdata = {
+static const struct samsung_fixed_factor_clock ffactor_clks[] __initconst = {
        FFACTOR(FOUT_APLL_CLKOUT, "fout_apll_clkout", "fout_apll", 1, 4, 0),
        FFACTOR(FOUT_MPLL_CLKOUT, "fout_mpll_clkout", "fout_mpll", 1, 2, 0),
        FFACTOR(DOUT_APLL_CLKOUT, "dout_apll_clkout", "dout_apll", 1, 4, 0),
 };
 
 /* PLL input mux (fin_pll), which needs to be registered before PLLs. */
-static struct samsung_mux_clock early_mux_clks[] __initdata = {
+static const struct samsung_mux_clock early_mux_clks[] __initconst = {
        MUX_F(FIN_PLL, "fin_pll", fin_pll_p, OM_STAT, 0, 1,
                                        CLK_MUX_READ_ONLY, 0),
 };
 
 /* Common clock muxes. */
-static struct samsung_mux_clock mux_clks[] __initdata = {
+static const struct samsung_mux_clock mux_clks[] __initconst = {
        MUX(MOUT_FLASH, "mout_flash", mout_flash_p, CLK_SRC0, 28, 1),
        MUX(MOUT_PSYS, "mout_psys", mout_group4_p, CLK_SRC0, 24, 1),
        MUX(MOUT_DSYS, "mout_dsys", mout_group4_p, CLK_SRC0, 20, 1),
@@ -427,7 +427,7 @@ static struct samsung_mux_clock mux_clks[] __initdata = {
 };
 
 /* S5PV210-specific clock muxes. */
-static struct samsung_mux_clock s5pv210_mux_clks[] __initdata = {
+static const struct samsung_mux_clock s5pv210_mux_clks[] __initconst = {
        MUX(MOUT_VPLL, "mout_vpll", mout_vpll_p, CLK_SRC0, 12, 1),
 
        MUX(MOUT_VPLLSRC, "mout_vpllsrc", mout_vpllsrc_p, CLK_SRC1, 28, 1),
@@ -472,7 +472,7 @@ static struct samsung_mux_clock s5pv210_mux_clks[] __initdata = {
 };
 
 /* S5P6442-specific clock muxes. */
-static struct samsung_mux_clock s5p6442_mux_clks[] __initdata = {
+static const struct samsung_mux_clock s5p6442_mux_clks[] __initconst = {
        MUX(MOUT_VPLL, "mout_vpll", mout_vpll_6442_p, CLK_SRC0, 12, 1),
 
        MUX(MOUT_FIMD, "mout_fimd", mout_group2_6442_p, CLK_SRC1, 20, 4),
@@ -504,7 +504,7 @@ static struct samsung_mux_clock s5p6442_mux_clks[] __initdata = {
 };
 
 /* S5PV210-specific fixed rate clocks generated inside the SoC. */
-static struct samsung_fixed_rate_clock s5pv210_frate_clks[] __initdata = {
+static const struct samsung_fixed_rate_clock s5pv210_frate_clks[] __initconst = {
        FRATE(SCLK_HDMI27M, "sclk_hdmi27m", NULL, CLK_IS_ROOT, 27000000),
        FRATE(SCLK_HDMIPHY, "sclk_hdmiphy", NULL, CLK_IS_ROOT, 27000000),
        FRATE(SCLK_USBPHY0, "sclk_usbphy0", NULL, CLK_IS_ROOT, 48000000),
@@ -512,12 +512,12 @@ static struct samsung_fixed_rate_clock s5pv210_frate_clks[] __initdata = {
 };
 
 /* S5P6442-specific fixed rate clocks generated inside the SoC. */
-static struct samsung_fixed_rate_clock s5p6442_frate_clks[] __initdata = {
+static const struct samsung_fixed_rate_clock s5p6442_frate_clks[] __initconst = {
        FRATE(SCLK_USBPHY0, "sclk_usbphy0", NULL, CLK_IS_ROOT, 30000000),
 };
 
 /* Common clock dividers. */
-static struct samsung_div_clock div_clks[] __initdata = {
+static const struct samsung_div_clock div_clks[] __initconst = {
        DIV(DOUT_PCLKP, "dout_pclkp", "dout_hclkp", CLK_DIV0, 28, 3),
        DIV(DOUT_PCLKD, "dout_pclkd", "dout_hclkd", CLK_DIV0, 20, 3),
        DIV(DOUT_A2M, "dout_a2m", "mout_apll", CLK_DIV0, 4, 3),
@@ -549,7 +549,7 @@ static struct samsung_div_clock div_clks[] __initdata = {
 };
 
 /* S5PV210-specific clock dividers. */
-static struct samsung_div_clock s5pv210_div_clks[] __initdata = {
+static const struct samsung_div_clock s5pv210_div_clks[] __initconst = {
        DIV(DOUT_HCLKP, "dout_hclkp", "mout_psys", CLK_DIV0, 24, 4),
        DIV(DOUT_HCLKD, "dout_hclkd", "mout_dsys", CLK_DIV0, 16, 4),
        DIV(DOUT_PCLKM, "dout_pclkm", "dout_hclkm", CLK_DIV0, 12, 3),
@@ -578,7 +578,7 @@ static struct samsung_div_clock s5pv210_div_clks[] __initdata = {
 };
 
 /* S5P6442-specific clock dividers. */
-static struct samsung_div_clock s5p6442_div_clks[] __initdata = {
+static const struct samsung_div_clock s5p6442_div_clks[] __initconst = {
        DIV(DOUT_HCLKP, "dout_hclkp", "mout_d1sync", CLK_DIV0, 24, 4),
        DIV(DOUT_HCLKD, "dout_hclkd", "mout_d0sync", CLK_DIV0, 16, 4),
 
@@ -586,7 +586,7 @@ static struct samsung_div_clock s5p6442_div_clks[] __initdata = {
 };
 
 /* Common clock gates. */
-static struct samsung_gate_clock gate_clks[] __initdata = {
+static const struct samsung_gate_clock gate_clks[] __initconst = {
        GATE(CLK_ROTATOR, "rotator", "dout_hclkd", CLK_GATE_IP0, 29, 0, 0),
        GATE(CLK_FIMC2, "fimc2", "dout_hclkd", CLK_GATE_IP0, 26, 0, 0),
        GATE(CLK_FIMC1, "fimc1", "dout_hclkd", CLK_GATE_IP0, 25, 0, 0),
@@ -666,7 +666,7 @@ static struct samsung_gate_clock gate_clks[] __initdata = {
 };
 
 /* S5PV210-specific clock gates. */
-static struct samsung_gate_clock s5pv210_gate_clks[] __initdata = {
+static const struct samsung_gate_clock s5pv210_gate_clks[] __initconst = {
        GATE(CLK_CSIS, "clk_csis", "dout_hclkd", CLK_GATE_IP0, 31, 0, 0),
        GATE(CLK_MFC, "mfc", "dout_hclkm", CLK_GATE_IP0, 16, 0, 0),
        GATE(CLK_G2D, "g2d", "dout_hclkd", CLK_GATE_IP0, 12, 0, 0),
@@ -728,7 +728,7 @@ static struct samsung_gate_clock s5pv210_gate_clks[] __initdata = {
 };
 
 /* S5P6442-specific clock gates. */
-static struct samsung_gate_clock s5p6442_gate_clks[] __initdata = {
+static const struct samsung_gate_clock s5p6442_gate_clks[] __initconst = {
        GATE(CLK_JPEG, "jpeg", "dout_hclkd", CLK_GATE_IP0, 28, 0, 0),
        GATE(CLK_MFC, "mfc", "dout_hclkd", CLK_GATE_IP0, 16, 0, 0),
        GATE(CLK_G2D, "g2d", "dout_hclkd", CLK_GATE_IP0, 12, 0, 0),
@@ -748,14 +748,14 @@ static struct samsung_gate_clock s5p6442_gate_clks[] __initdata = {
  * Clock aliases for legacy clkdev look-up.
  * NOTE: Needed only to support legacy board files.
  */
-static struct samsung_clock_alias s5pv210_aliases[] = {
+static const struct samsung_clock_alias s5pv210_aliases[] __initconst = {
        ALIAS(DOUT_APLL, NULL, "armclk"),
        ALIAS(DOUT_HCLKM, NULL, "hclk_msys"),
        ALIAS(MOUT_DMC0, NULL, "sclk_dmc0"),
 };
 
 /* S5PV210-specific PLLs. */
-static struct samsung_pll_clock s5pv210_pll_clks[] __initdata = {
+static const struct samsung_pll_clock s5pv210_pll_clks[] __initconst = {
        [apll] = PLL(pll_4508, FOUT_APLL, "fout_apll", "fin_pll",
                                                APLL_LOCK, APLL_CON0, NULL),
        [mpll] = PLL(pll_4502, FOUT_MPLL, "fout_mpll", "fin_pll",
@@ -767,7 +767,7 @@ static struct samsung_pll_clock s5pv210_pll_clks[] __initdata = {
 };
 
 /* S5P6442-specific PLLs. */
-static struct samsung_pll_clock s5p6442_pll_clks[] __initdata = {
+static const struct samsung_pll_clock s5p6442_pll_clks[] __initconst = {
        [apll] = PLL(pll_4502, FOUT_APLL, "fout_apll", "fin_pll",
                                                APLL_LOCK, APLL_CON0, NULL),
        [mpll] = PLL(pll_4502, FOUT_MPLL, "fout_mpll", "fin_pll",
index 9e1f88c04fd46dd583e1b2ccd90fc96c8cae06e8..0117238391d6532b5b332a0ba09d319b693c03aa 100644 (file)
@@ -98,7 +98,7 @@ void samsung_clk_add_lookup(struct samsung_clk_provider *ctx, struct clk *clk,
 
 /* register a list of aliases */
 void __init samsung_clk_register_alias(struct samsung_clk_provider *ctx,
-                               struct samsung_clock_alias *list,
+                               const struct samsung_clock_alias *list,
                                unsigned int nr_clk)
 {
        struct clk *clk;
@@ -132,7 +132,8 @@ void __init samsung_clk_register_alias(struct samsung_clk_provider *ctx,
 
 /* register a list of fixed clocks */
 void __init samsung_clk_register_fixed_rate(struct samsung_clk_provider *ctx,
-               struct samsung_fixed_rate_clock *list, unsigned int nr_clk)
+               const struct samsung_fixed_rate_clock *list,
+               unsigned int nr_clk)
 {
        struct clk *clk;
        unsigned int idx, ret;
@@ -161,7 +162,7 @@ void __init samsung_clk_register_fixed_rate(struct samsung_clk_provider *ctx,
 
 /* register a list of fixed factor clocks */
 void __init samsung_clk_register_fixed_factor(struct samsung_clk_provider *ctx,
-               struct samsung_fixed_factor_clock *list, unsigned int nr_clk)
+               const struct samsung_fixed_factor_clock *list, unsigned int nr_clk)
 {
        struct clk *clk;
        unsigned int idx;
@@ -181,7 +182,7 @@ void __init samsung_clk_register_fixed_factor(struct samsung_clk_provider *ctx,
 
 /* register a list of mux clocks */
 void __init samsung_clk_register_mux(struct samsung_clk_provider *ctx,
-                               struct samsung_mux_clock *list,
+                               const struct samsung_mux_clock *list,
                                unsigned int nr_clk)
 {
        struct clk *clk;
@@ -213,7 +214,7 @@ void __init samsung_clk_register_mux(struct samsung_clk_provider *ctx,
 
 /* register a list of div clocks */
 void __init samsung_clk_register_div(struct samsung_clk_provider *ctx,
-                               struct samsung_div_clock *list,
+                               const struct samsung_div_clock *list,
                                unsigned int nr_clk)
 {
        struct clk *clk;
@@ -252,7 +253,7 @@ void __init samsung_clk_register_div(struct samsung_clk_provider *ctx,
 
 /* register a list of gate clocks */
 void __init samsung_clk_register_gate(struct samsung_clk_provider *ctx,
-                               struct samsung_gate_clock *list,
+                               const struct samsung_gate_clock *list,
                                unsigned int nr_clk)
 {
        struct clk *clk;
@@ -389,7 +390,7 @@ struct samsung_clk_provider * __init samsung_cmu_register_one(
 
        ctx = samsung_clk_init(np, reg_base, cmu->nr_clk_ids);
        if (!ctx) {
-               panic("%s: unable to alllocate ctx\n", __func__);
+               panic("%s: unable to allocate ctx\n", __func__);
                return ctx;
        }
 
index e4c75383cea718c7fb563db70fbdd8452b1f9bd8..b775fc29caa507dcaccfa1e54d78fef2f7d4a45b 100644 (file)
@@ -121,7 +121,7 @@ struct samsung_mux_clock {
        unsigned int            id;
        const char              *dev_name;
        const char              *name;
-       const char              **parent_names;
+       const char              *const *parent_names;
        u8                      num_parents;
        unsigned long           flags;
        unsigned long           offset;
@@ -368,28 +368,28 @@ extern void __init samsung_clk_of_register_fixed_ext(
 extern void samsung_clk_add_lookup(struct samsung_clk_provider *ctx,
                        struct clk *clk, unsigned int id);
 
-extern void samsung_clk_register_alias(struct samsung_clk_provider *ctx,
-                       struct samsung_clock_alias *list,
+extern void __init samsung_clk_register_alias(struct samsung_clk_provider *ctx,
+                       const struct samsung_clock_alias *list,
                        unsigned int nr_clk);
 extern void __init samsung_clk_register_fixed_rate(
                        struct samsung_clk_provider *ctx,
-                       struct samsung_fixed_rate_clock *clk_list,
+                       const struct samsung_fixed_rate_clock *clk_list,
                        unsigned int nr_clk);
 extern void __init samsung_clk_register_fixed_factor(
                        struct samsung_clk_provider *ctx,
-                       struct samsung_fixed_factor_clock *list,
+                       const struct samsung_fixed_factor_clock *list,
                        unsigned int nr_clk);
 extern void __init samsung_clk_register_mux(struct samsung_clk_provider *ctx,
-                       struct samsung_mux_clock *clk_list,
+                       const struct samsung_mux_clock *clk_list,
                        unsigned int nr_clk);
 extern void __init samsung_clk_register_div(struct samsung_clk_provider *ctx,
-                       struct samsung_div_clock *clk_list,
+                       const struct samsung_div_clock *clk_list,
                        unsigned int nr_clk);
 extern void __init samsung_clk_register_gate(struct samsung_clk_provider *ctx,
-                       struct samsung_gate_clock *clk_list,
+                       const struct samsung_gate_clock *clk_list,
                        unsigned int nr_clk);
 extern void __init samsung_clk_register_pll(struct samsung_clk_provider *ctx,
-                       struct samsung_pll_clock *pll_list,
+                       const struct samsung_pll_clock *pll_list,
                        unsigned int nr_clk, void __iomem *base);
 
 extern struct samsung_clk_provider __init *samsung_cmu_register_one(
index 6c7c929c77655771999c59d0d9c85fc998429944..5b60beb7d0ebce09f7f0f34b97620dd7025ba762 100644 (file)
@@ -34,7 +34,7 @@
 static DEFINE_SPINLOCK(lock);
 
 /* not pretty, but hey */
-void __iomem *smu_base;
+static void __iomem *smu_base;
 
 static void __init emev2_smu_write(unsigned long value, int offs)
 {
index 36b8e203f6e7cdfe92c39ed502e245e736608fee..09b4210d91240b032f5c97a72c2f2da8b59f17f6 100644 (file)
@@ -2,4 +2,4 @@
 # Makefile for sirf specific clk
 #
 
-obj-$(CONFIG_ARCH_SIRF) += clk-prima2.o clk-atlas6.o
+obj-$(CONFIG_ARCH_SIRF) += clk-prima2.o clk-atlas6.o clk-atlas7.o
diff --git a/drivers/clk/sirf/clk-atlas7.c b/drivers/clk/sirf/clk-atlas7.c
new file mode 100644 (file)
index 0000000..db8ab69
--- /dev/null
@@ -0,0 +1,1632 @@
+/*
+ * Clock tree for CSR SiRFAtlas7
+ *
+ * Copyright (c) 2014 Cambridge Silicon Radio Limited, a CSR plc group company.
+ *
+ * Licensed under GPLv2 or later.
+ */
+
+#include <linux/bitops.h>
+#include <linux/io.h>
+#include <linux/clk-provider.h>
+#include <linux/delay.h>
+#include <linux/of_address.h>
+#include <linux/reset-controller.h>
+#include <linux/slab.h>
+
+#define SIRFSOC_CLKC_MEMPLL_AB_FREQ          0x0000
+#define SIRFSOC_CLKC_MEMPLL_AB_SSC           0x0004
+#define SIRFSOC_CLKC_MEMPLL_AB_CTRL0         0x0008
+#define SIRFSOC_CLKC_MEMPLL_AB_CTRL1         0x000c
+#define SIRFSOC_CLKC_MEMPLL_AB_STATUS        0x0010
+#define SIRFSOC_CLKC_MEMPLL_AB_SSRAM_ADDR    0x0014
+#define SIRFSOC_CLKC_MEMPLL_AB_SSRAM_DATA    0x0018
+
+#define SIRFSOC_CLKC_CPUPLL_AB_FREQ          0x001c
+#define SIRFSOC_CLKC_CPUPLL_AB_SSC           0x0020
+#define SIRFSOC_CLKC_CPUPLL_AB_CTRL0         0x0024
+#define SIRFSOC_CLKC_CPUPLL_AB_CTRL1         0x0028
+#define SIRFSOC_CLKC_CPUPLL_AB_STATUS        0x002c
+
+#define SIRFSOC_CLKC_SYS0PLL_AB_FREQ         0x0030
+#define SIRFSOC_CLKC_SYS0PLL_AB_SSC          0x0034
+#define SIRFSOC_CLKC_SYS0PLL_AB_CTRL0        0x0038
+#define SIRFSOC_CLKC_SYS0PLL_AB_CTRL1        0x003c
+#define SIRFSOC_CLKC_SYS0PLL_AB_STATUS       0x0040
+
+#define SIRFSOC_CLKC_SYS1PLL_AB_FREQ         0x0044
+#define SIRFSOC_CLKC_SYS1PLL_AB_SSC          0x0048
+#define SIRFSOC_CLKC_SYS1PLL_AB_CTRL0        0x004c
+#define SIRFSOC_CLKC_SYS1PLL_AB_CTRL1        0x0050
+#define SIRFSOC_CLKC_SYS1PLL_AB_STATUS       0x0054
+
+#define SIRFSOC_CLKC_SYS2PLL_AB_FREQ         0x0058
+#define SIRFSOC_CLKC_SYS2PLL_AB_SSC          0x005c
+#define SIRFSOC_CLKC_SYS2PLL_AB_CTRL0        0x0060
+#define SIRFSOC_CLKC_SYS2PLL_AB_CTRL1        0x0064
+#define SIRFSOC_CLKC_SYS2PLL_AB_STATUS       0x0068
+
+#define SIRFSOC_CLKC_SYS3PLL_AB_FREQ         0x006c
+#define SIRFSOC_CLKC_SYS3PLL_AB_SSC          0x0070
+#define SIRFSOC_CLKC_SYS3PLL_AB_CTRL0        0x0074
+#define SIRFSOC_CLKC_SYS3PLL_AB_CTRL1        0x0078
+#define SIRFSOC_CLKC_SYS3PLL_AB_STATUS       0x007c
+
+#define SIRFSOC_ABPLL_CTRL0_SSEN     0x00001000
+#define SIRFSOC_ABPLL_CTRL0_BYPASS   0x00000010
+#define SIRFSOC_ABPLL_CTRL0_RESET    0x00000001
+
+#define SIRFSOC_CLKC_AUDIO_DTO_INC           0x0088
+#define SIRFSOC_CLKC_DISP0_DTO_INC           0x008c
+#define SIRFSOC_CLKC_DISP1_DTO_INC           0x0090
+
+#define SIRFSOC_CLKC_AUDIO_DTO_SRC           0x0094
+#define SIRFSOC_CLKC_AUDIO_DTO_ENA           0x0098
+#define SIRFSOC_CLKC_AUDIO_DTO_DROFF         0x009c
+
+#define SIRFSOC_CLKC_DISP0_DTO_SRC           0x00a0
+#define SIRFSOC_CLKC_DISP0_DTO_ENA           0x00a4
+#define SIRFSOC_CLKC_DISP0_DTO_DROFF         0x00a8
+
+#define SIRFSOC_CLKC_DISP1_DTO_SRC           0x00ac
+#define SIRFSOC_CLKC_DISP1_DTO_ENA           0x00b0
+#define SIRFSOC_CLKC_DISP1_DTO_DROFF         0x00b4
+
+#define SIRFSOC_CLKC_I2S_CLK_SEL             0x00b8
+#define SIRFSOC_CLKC_I2S_SEL_STAT            0x00bc
+
+#define SIRFSOC_CLKC_USBPHY_CLKDIV_CFG       0x00c0
+#define SIRFSOC_CLKC_USBPHY_CLKDIV_ENA       0x00c4
+#define SIRFSOC_CLKC_USBPHY_CLK_SEL          0x00c8
+#define SIRFSOC_CLKC_USBPHY_CLK_SEL_STAT     0x00cc
+
+#define SIRFSOC_CLKC_BTSS_CLKDIV_CFG         0x00d0
+#define SIRFSOC_CLKC_BTSS_CLKDIV_ENA         0x00d4
+#define SIRFSOC_CLKC_BTSS_CLK_SEL            0x00d8
+#define SIRFSOC_CLKC_BTSS_CLK_SEL_STAT       0x00dc
+
+#define SIRFSOC_CLKC_RGMII_CLKDIV_CFG        0x00e0
+#define SIRFSOC_CLKC_RGMII_CLKDIV_ENA        0x00e4
+#define SIRFSOC_CLKC_RGMII_CLK_SEL           0x00e8
+#define SIRFSOC_CLKC_RGMII_CLK_SEL_STAT      0x00ec
+
+#define SIRFSOC_CLKC_CPU_CLKDIV_CFG          0x00f0
+#define SIRFSOC_CLKC_CPU_CLKDIV_ENA          0x00f4
+#define SIRFSOC_CLKC_CPU_CLK_SEL             0x00f8
+#define SIRFSOC_CLKC_CPU_CLK_SEL_STAT        0x00fc
+
+#define SIRFSOC_CLKC_SDPHY01_CLKDIV_CFG      0x0100
+#define SIRFSOC_CLKC_SDPHY01_CLKDIV_ENA      0x0104
+#define SIRFSOC_CLKC_SDPHY01_CLK_SEL         0x0108
+#define SIRFSOC_CLKC_SDPHY01_CLK_SEL_STAT    0x010c
+
+#define SIRFSOC_CLKC_SDPHY23_CLKDIV_CFG      0x0110
+#define SIRFSOC_CLKC_SDPHY23_CLKDIV_ENA      0x0114
+#define SIRFSOC_CLKC_SDPHY23_CLK_SEL         0x0118
+#define SIRFSOC_CLKC_SDPHY23_CLK_SEL_STAT    0x011c
+
+#define SIRFSOC_CLKC_SDPHY45_CLKDIV_CFG      0x0120
+#define SIRFSOC_CLKC_SDPHY45_CLKDIV_ENA      0x0124
+#define SIRFSOC_CLKC_SDPHY45_CLK_SEL         0x0128
+#define SIRFSOC_CLKC_SDPHY45_CLK_SEL_STAT    0x012c
+
+#define SIRFSOC_CLKC_SDPHY67_CLKDIV_CFG      0x0130
+#define SIRFSOC_CLKC_SDPHY67_CLKDIV_ENA      0x0134
+#define SIRFSOC_CLKC_SDPHY67_CLK_SEL         0x0138
+#define SIRFSOC_CLKC_SDPHY67_CLK_SEL_STAT    0x013c
+
+#define SIRFSOC_CLKC_CAN_CLKDIV_CFG          0x0140
+#define SIRFSOC_CLKC_CAN_CLKDIV_ENA          0x0144
+#define SIRFSOC_CLKC_CAN_CLK_SEL             0x0148
+#define SIRFSOC_CLKC_CAN_CLK_SEL_STAT        0x014c
+
+#define SIRFSOC_CLKC_DEINT_CLKDIV_CFG        0x0150
+#define SIRFSOC_CLKC_DEINT_CLKDIV_ENA        0x0154
+#define SIRFSOC_CLKC_DEINT_CLK_SEL           0x0158
+#define SIRFSOC_CLKC_DEINT_CLK_SEL_STAT      0x015c
+
+#define SIRFSOC_CLKC_NAND_CLKDIV_CFG         0x0160
+#define SIRFSOC_CLKC_NAND_CLKDIV_ENA         0x0164
+#define SIRFSOC_CLKC_NAND_CLK_SEL            0x0168
+#define SIRFSOC_CLKC_NAND_CLK_SEL_STAT       0x016c
+
+#define SIRFSOC_CLKC_DISP0_CLKDIV_CFG        0x0170
+#define SIRFSOC_CLKC_DISP0_CLKDIV_ENA        0x0174
+#define SIRFSOC_CLKC_DISP0_CLK_SEL           0x0178
+#define SIRFSOC_CLKC_DISP0_CLK_SEL_STAT      0x017c
+
+#define SIRFSOC_CLKC_DISP1_CLKDIV_CFG        0x0180
+#define SIRFSOC_CLKC_DISP1_CLKDIV_ENA        0x0184
+#define SIRFSOC_CLKC_DISP1_CLK_SEL           0x0188
+#define SIRFSOC_CLKC_DISP1_CLK_SEL_STAT      0x018c
+
+#define SIRFSOC_CLKC_GPU_CLKDIV_CFG          0x0190
+#define SIRFSOC_CLKC_GPU_CLKDIV_ENA          0x0194
+#define SIRFSOC_CLKC_GPU_CLK_SEL             0x0198
+#define SIRFSOC_CLKC_GPU_CLK_SEL_STAT        0x019c
+
+#define SIRFSOC_CLKC_GNSS_CLKDIV_CFG         0x01a0
+#define SIRFSOC_CLKC_GNSS_CLKDIV_ENA         0x01a4
+#define SIRFSOC_CLKC_GNSS_CLK_SEL            0x01a8
+#define SIRFSOC_CLKC_GNSS_CLK_SEL_STAT       0x01ac
+
+#define SIRFSOC_CLKC_SHARED_DIVIDER_CFG0     0x01b0
+#define SIRFSOC_CLKC_SHARED_DIVIDER_CFG1     0x01b4
+#define SIRFSOC_CLKC_SHARED_DIVIDER_ENA      0x01b8
+
+#define SIRFSOC_CLKC_SYS_CLK_SEL             0x01bc
+#define SIRFSOC_CLKC_SYS_CLK_SEL_STAT        0x01c0
+#define SIRFSOC_CLKC_IO_CLK_SEL              0x01c4
+#define SIRFSOC_CLKC_IO_CLK_SEL_STAT         0x01c8
+#define SIRFSOC_CLKC_G2D_CLK_SEL             0x01cc
+#define SIRFSOC_CLKC_G2D_CLK_SEL_STAT        0x01d0
+#define SIRFSOC_CLKC_JPENC_CLK_SEL           0x01d4
+#define SIRFSOC_CLKC_JPENC_CLK_SEL_STAT      0x01d8
+#define SIRFSOC_CLKC_VDEC_CLK_SEL            0x01dc
+#define SIRFSOC_CLKC_VDEC_CLK_SEL_STAT       0x01e0
+#define SIRFSOC_CLKC_GMAC_CLK_SEL            0x01e4
+#define SIRFSOC_CLKC_GMAC_CLK_SEL_STAT       0x01e8
+#define SIRFSOC_CLKC_USB_CLK_SEL             0x01ec
+#define SIRFSOC_CLKC_USB_CLK_SEL_STAT        0x01f0
+#define SIRFSOC_CLKC_KAS_CLK_SEL             0x01f4
+#define SIRFSOC_CLKC_KAS_CLK_SEL_STAT        0x01f8
+#define SIRFSOC_CLKC_SEC_CLK_SEL             0x01fc
+#define SIRFSOC_CLKC_SEC_CLK_SEL_STAT        0x0200
+#define SIRFSOC_CLKC_SDR_CLK_SEL             0x0204
+#define SIRFSOC_CLKC_SDR_CLK_SEL_STAT        0x0208
+#define SIRFSOC_CLKC_VIP_CLK_SEL             0x020c
+#define SIRFSOC_CLKC_VIP_CLK_SEL_STAT        0x0210
+#define SIRFSOC_CLKC_NOCD_CLK_SEL            0x0214
+#define SIRFSOC_CLKC_NOCD_CLK_SEL_STAT       0x0218
+#define SIRFSOC_CLKC_NOCR_CLK_SEL            0x021c
+#define SIRFSOC_CLKC_NOCR_CLK_SEL_STAT       0x0220
+#define SIRFSOC_CLKC_TPIU_CLK_SEL            0x0224
+#define SIRFSOC_CLKC_TPIU_CLK_SEL_STAT       0x0228
+
+#define SIRFSOC_CLKC_ROOT_CLK_EN0_SET        0x022c
+#define SIRFSOC_CLKC_ROOT_CLK_EN0_CLR        0x0230
+#define SIRFSOC_CLKC_ROOT_CLK_EN0_STAT       0x0234
+#define SIRFSOC_CLKC_ROOT_CLK_EN1_SET        0x0238
+#define SIRFSOC_CLKC_ROOT_CLK_EN1_CLR        0x023c
+#define SIRFSOC_CLKC_ROOT_CLK_EN1_STAT       0x0240
+
+#define SIRFSOC_CLKC_LEAF_CLK_EN0_SET        0x0244
+#define SIRFSOC_CLKC_LEAF_CLK_EN0_CLR        0x0248
+#define SIRFSOC_CLKC_LEAF_CLK_EN0_STAT       0x024c
+
+#define SIRFSOC_CLKC_RSTC_A7_SW_RST          0x0308
+
+#define SIRFSOC_CLKC_LEAF_CLK_EN1_SET        0x04a0
+#define SIRFSOC_CLKC_LEAF_CLK_EN2_SET        0x04b8
+#define SIRFSOC_CLKC_LEAF_CLK_EN3_SET        0x04d0
+#define SIRFSOC_CLKC_LEAF_CLK_EN4_SET        0x04e8
+#define SIRFSOC_CLKC_LEAF_CLK_EN5_SET        0x0500
+#define SIRFSOC_CLKC_LEAF_CLK_EN6_SET        0x0518
+#define SIRFSOC_CLKC_LEAF_CLK_EN7_SET        0x0530
+#define SIRFSOC_CLKC_LEAF_CLK_EN8_SET        0x0548
+
+
+static void __iomem *sirfsoc_clk_vbase;
+static struct clk_onecell_data clk_data;
+
+static const struct clk_div_table pll_div_table[] = {
+       { .val = 0, .div = 1 },
+       { .val = 1, .div = 2 },
+       { .val = 2, .div = 4 },
+       { .val = 3, .div = 8 },
+       { .val = 4, .div = 16 },
+       { .val = 5, .div = 32 },
+};
+
+struct clk_pll {
+       struct clk_hw hw;
+       u16 regofs;  /* register offset */
+};
+#define to_pllclk(_hw) container_of(_hw, struct clk_pll, hw)
+
+struct clk_dto {
+       struct clk_hw hw;
+       u16 inc_offset;  /* dto increment offset */
+       u16 src_offset;  /* dto src offset */
+};
+#define to_dtoclk(_hw) container_of(_hw, struct clk_dto, hw)
+
+struct clk_unit {
+       struct clk_hw hw;
+       u16 regofs;
+       u16 bit;
+       spinlock_t *lock;
+};
+#define to_unitclk(_hw) container_of(_hw, struct clk_unit, hw)
+
+struct atlas7_div_init_data {
+       const char *div_name;
+       const char *parent_name;
+       const char *gate_name;
+       unsigned long flags;
+       u8 divider_flags;
+       u8 gate_flags;
+       u32 div_offset;
+       u8 shift;
+       u8 width;
+       u32 gate_offset;
+       u8 gate_bit;
+       spinlock_t *lock;
+};
+
+struct atlas7_mux_init_data {
+       const char *mux_name;
+       const char * const *parent_names;
+       u8 parent_num;
+       unsigned long flags;
+       u8 mux_flags;
+       u32 mux_offset;
+       u8 shift;
+       u8 width;
+};
+
+struct atlas7_unit_init_data {
+       u32 index;
+       const char *unit_name;
+       const char *parent_name;
+       unsigned long flags;
+       u32 regofs;
+       u8 bit;
+       spinlock_t *lock;
+};
+
+struct atlas7_reset_desc {
+       const char *name;
+       u32 clk_ofs;
+       u8  clk_bit;
+       u32 rst_ofs;
+       u8  rst_bit;
+       spinlock_t *lock;
+};
+
+static DEFINE_SPINLOCK(cpupll_ctrl1_lock);
+static DEFINE_SPINLOCK(mempll_ctrl1_lock);
+static DEFINE_SPINLOCK(sys0pll_ctrl1_lock);
+static DEFINE_SPINLOCK(sys1pll_ctrl1_lock);
+static DEFINE_SPINLOCK(sys2pll_ctrl1_lock);
+static DEFINE_SPINLOCK(sys3pll_ctrl1_lock);
+static DEFINE_SPINLOCK(usbphy_div_lock);
+static DEFINE_SPINLOCK(btss_div_lock);
+static DEFINE_SPINLOCK(rgmii_div_lock);
+static DEFINE_SPINLOCK(cpu_div_lock);
+static DEFINE_SPINLOCK(sdphy01_div_lock);
+static DEFINE_SPINLOCK(sdphy23_div_lock);
+static DEFINE_SPINLOCK(sdphy45_div_lock);
+static DEFINE_SPINLOCK(sdphy67_div_lock);
+static DEFINE_SPINLOCK(can_div_lock);
+static DEFINE_SPINLOCK(deint_div_lock);
+static DEFINE_SPINLOCK(nand_div_lock);
+static DEFINE_SPINLOCK(disp0_div_lock);
+static DEFINE_SPINLOCK(disp1_div_lock);
+static DEFINE_SPINLOCK(gpu_div_lock);
+static DEFINE_SPINLOCK(gnss_div_lock);
+/* gate register shared */
+static DEFINE_SPINLOCK(share_div_lock);
+static DEFINE_SPINLOCK(root0_gate_lock);
+static DEFINE_SPINLOCK(root1_gate_lock);
+static DEFINE_SPINLOCK(leaf0_gate_lock);
+static DEFINE_SPINLOCK(leaf1_gate_lock);
+static DEFINE_SPINLOCK(leaf2_gate_lock);
+static DEFINE_SPINLOCK(leaf3_gate_lock);
+static DEFINE_SPINLOCK(leaf4_gate_lock);
+static DEFINE_SPINLOCK(leaf5_gate_lock);
+static DEFINE_SPINLOCK(leaf6_gate_lock);
+static DEFINE_SPINLOCK(leaf7_gate_lock);
+static DEFINE_SPINLOCK(leaf8_gate_lock);
+
+static inline unsigned long clkc_readl(unsigned reg)
+{
+       return readl(sirfsoc_clk_vbase + reg);
+}
+
+static inline void clkc_writel(u32 val, unsigned reg)
+{
+       writel(val, sirfsoc_clk_vbase + reg);
+}
+
+/*
+*  ABPLL
+*  integer mode: Fvco = Fin * 2 * NF / NR
+*  Spread Spectrum mode: Fvco = Fin * SSN / NR
+*  SSN = 2^24 / (256 * ((ssdiv >> ssdepth) << ssdepth) + (ssmod << ssdepth))
+*/
+static unsigned long pll_clk_recalc_rate(struct clk_hw *hw,
+       unsigned long parent_rate)
+{
+       unsigned long fin = parent_rate;
+       struct clk_pll *clk = to_pllclk(hw);
+       u64 rate;
+       u32 regctrl0 = clkc_readl(clk->regofs + SIRFSOC_CLKC_MEMPLL_AB_CTRL0 -
+                       SIRFSOC_CLKC_MEMPLL_AB_FREQ);
+       u32 regfreq = clkc_readl(clk->regofs);
+       u32 regssc = clkc_readl(clk->regofs + SIRFSOC_CLKC_MEMPLL_AB_SSC -
+                       SIRFSOC_CLKC_MEMPLL_AB_FREQ);
+       u32 nr = (regfreq  >> 16 & (BIT(3) - 1)) + 1;
+       u32 nf = (regfreq & (BIT(9) - 1)) + 1;
+       u32 ssdiv = regssc >> 8 & (BIT(12) - 1);
+       u32 ssdepth = regssc >> 20 & (BIT(2) - 1);
+       u32 ssmod = regssc & (BIT(8) - 1);
+
+       if (regctrl0 & SIRFSOC_ABPLL_CTRL0_BYPASS)
+               return fin;
+
+       if (regctrl0 & SIRFSOC_ABPLL_CTRL0_SSEN) {
+               rate = fin;
+               rate *= 1 << 24;
+               do_div(rate, (256 * ((ssdiv >> ssdepth) << ssdepth)
+                       + (ssmod << ssdepth)));
+       } else {
+               rate = 2 * fin;
+               rate *= nf;
+               do_div(rate, nr);
+       }
+       return rate;
+}
+
+static const struct clk_ops ab_pll_ops = {
+       .recalc_rate = pll_clk_recalc_rate,
+};
+
+static const char * const pll_clk_parents[] = {
+       "xin",
+};
+
+static struct clk_init_data clk_cpupll_init = {
+       .name = "cpupll_vco",
+       .ops = &ab_pll_ops,
+       .parent_names = pll_clk_parents,
+       .num_parents = ARRAY_SIZE(pll_clk_parents),
+};
+
+static struct clk_pll clk_cpupll = {
+       .regofs = SIRFSOC_CLKC_CPUPLL_AB_FREQ,
+       .hw = {
+               .init = &clk_cpupll_init,
+       },
+};
+
+static struct clk_init_data clk_mempll_init = {
+       .name = "mempll_vco",
+       .ops = &ab_pll_ops,
+       .parent_names = pll_clk_parents,
+       .num_parents = ARRAY_SIZE(pll_clk_parents),
+};
+
+static struct clk_pll clk_mempll = {
+       .regofs = SIRFSOC_CLKC_MEMPLL_AB_FREQ,
+       .hw = {
+               .init = &clk_mempll_init,
+       },
+};
+
+static struct clk_init_data clk_sys0pll_init = {
+       .name = "sys0pll_vco",
+       .ops = &ab_pll_ops,
+       .parent_names = pll_clk_parents,
+       .num_parents = ARRAY_SIZE(pll_clk_parents),
+};
+
+static struct clk_pll clk_sys0pll = {
+       .regofs = SIRFSOC_CLKC_SYS0PLL_AB_FREQ,
+       .hw = {
+               .init = &clk_sys0pll_init,
+       },
+};
+
+static struct clk_init_data clk_sys1pll_init = {
+       .name = "sys1pll_vco",
+       .ops = &ab_pll_ops,
+       .parent_names = pll_clk_parents,
+       .num_parents = ARRAY_SIZE(pll_clk_parents),
+};
+
+static struct clk_pll clk_sys1pll = {
+       .regofs = SIRFSOC_CLKC_SYS1PLL_AB_FREQ,
+       .hw = {
+               .init = &clk_sys1pll_init,
+       },
+};
+
+static struct clk_init_data clk_sys2pll_init = {
+       .name = "sys2pll_vco",
+       .ops = &ab_pll_ops,
+       .parent_names = pll_clk_parents,
+       .num_parents = ARRAY_SIZE(pll_clk_parents),
+};
+
+static struct clk_pll clk_sys2pll = {
+       .regofs = SIRFSOC_CLKC_SYS2PLL_AB_FREQ,
+       .hw = {
+               .init = &clk_sys2pll_init,
+       },
+};
+
+static struct clk_init_data clk_sys3pll_init = {
+       .name = "sys3pll_vco",
+       .ops = &ab_pll_ops,
+       .parent_names = pll_clk_parents,
+       .num_parents = ARRAY_SIZE(pll_clk_parents),
+};
+
+static struct clk_pll clk_sys3pll = {
+       .regofs = SIRFSOC_CLKC_SYS3PLL_AB_FREQ,
+       .hw = {
+               .init = &clk_sys3pll_init,
+       },
+};
+
+/*
+ *  DTO in clkc, default enable double resolution mode
+ *  double resolution mode:fout = fin * finc / 2^29
+ *  normal mode:fout = fin * finc / 2^28
+ */
+static int dto_clk_is_enabled(struct clk_hw *hw)
+{
+       struct clk_dto *clk = to_dtoclk(hw);
+       int reg;
+
+       reg = clk->src_offset + SIRFSOC_CLKC_AUDIO_DTO_ENA - SIRFSOC_CLKC_AUDIO_DTO_SRC;
+
+       return !!(clkc_readl(reg) & BIT(0));
+}
+
+static int dto_clk_enable(struct clk_hw *hw)
+{
+       u32 val, reg;
+       struct clk_dto *clk = to_dtoclk(hw);
+
+       reg = clk->src_offset + SIRFSOC_CLKC_AUDIO_DTO_ENA - SIRFSOC_CLKC_AUDIO_DTO_SRC;
+
+       val = clkc_readl(reg) | BIT(0);
+       clkc_writel(val, reg);
+       return 0;
+}
+
+static void dto_clk_disable(struct clk_hw *hw)
+{
+       u32 val, reg;
+       struct clk_dto *clk = to_dtoclk(hw);
+
+       reg = clk->src_offset + SIRFSOC_CLKC_AUDIO_DTO_ENA - SIRFSOC_CLKC_AUDIO_DTO_SRC;
+
+       val = clkc_readl(reg) & ~BIT(0);
+       clkc_writel(val, reg);
+}
+
+static unsigned long dto_clk_recalc_rate(struct clk_hw *hw,
+       unsigned long parent_rate)
+{
+       u64 rate = parent_rate;
+       struct clk_dto *clk = to_dtoclk(hw);
+       u32 finc = clkc_readl(clk->inc_offset);
+       u32 droff = clkc_readl(clk->src_offset + SIRFSOC_CLKC_AUDIO_DTO_DROFF - SIRFSOC_CLKC_AUDIO_DTO_SRC);
+
+       rate *= finc;
+       if (droff & BIT(0))
+               /* Double resolution off */
+               do_div(rate, 1 << 28);
+       else
+               do_div(rate, 1 << 29);
+
+       return rate;
+}
+
+static long dto_clk_round_rate(struct clk_hw *hw, unsigned long rate,
+       unsigned long *parent_rate)
+{
+       u64 dividend = rate * (1 << 29);
+
+       do_div(dividend, *parent_rate);
+       dividend *= *parent_rate;
+       do_div(dividend, 1 << 29);
+
+       return dividend;
+}
+
+static int dto_clk_set_rate(struct clk_hw *hw, unsigned long rate,
+       unsigned long parent_rate)
+{
+       u64 dividend = rate * (1 << 29);
+       struct clk_dto *clk = to_dtoclk(hw);
+
+       do_div(dividend, parent_rate);
+       clkc_writel(0, clk->src_offset + SIRFSOC_CLKC_AUDIO_DTO_DROFF - SIRFSOC_CLKC_AUDIO_DTO_SRC);
+       clkc_writel(dividend, clk->inc_offset);
+
+       return 0;
+}
+
+static u8 dto_clk_get_parent(struct clk_hw *hw)
+{
+       struct clk_dto *clk = to_dtoclk(hw);
+
+       return clkc_readl(clk->src_offset);
+}
+
+/*
+ *   dto need CLK_SET_PARENT_GATE
+ */
+static int dto_clk_set_parent(struct clk_hw *hw, u8 index)
+{
+       struct clk_dto *clk = to_dtoclk(hw);
+
+       clkc_writel(index, clk->src_offset);
+       return 0;
+}
+
+static const struct clk_ops dto_ops = {
+       .is_enabled = dto_clk_is_enabled,
+       .enable = dto_clk_enable,
+       .disable = dto_clk_disable,
+       .recalc_rate = dto_clk_recalc_rate,
+       .round_rate = dto_clk_round_rate,
+       .set_rate = dto_clk_set_rate,
+       .get_parent = dto_clk_get_parent,
+       .set_parent = dto_clk_set_parent,
+};
+
+/* dto parent clock as syspllvco/clk1 */
+static const char * const audiodto_clk_parents[] = {
+       "sys0pll_clk1",
+       "sys1pll_clk1",
+       "sys3pll_clk1",
+};
+
+static struct clk_init_data clk_audiodto_init = {
+       .name = "audio_dto",
+       .ops = &dto_ops,
+       .parent_names = audiodto_clk_parents,
+       .num_parents = ARRAY_SIZE(audiodto_clk_parents),
+};
+
+static struct clk_dto clk_audio_dto = {
+       .inc_offset = SIRFSOC_CLKC_AUDIO_DTO_INC,
+       .src_offset = SIRFSOC_CLKC_AUDIO_DTO_SRC,
+       .hw = {
+               .init = &clk_audiodto_init,
+       },
+};
+
+static const char * const disp0dto_clk_parents[] = {
+       "sys0pll_clk1",
+       "sys1pll_clk1",
+       "sys3pll_clk1",
+};
+
+static struct clk_init_data clk_disp0dto_init = {
+       .name = "disp0_dto",
+       .ops = &dto_ops,
+       .parent_names = disp0dto_clk_parents,
+       .num_parents = ARRAY_SIZE(disp0dto_clk_parents),
+};
+
+static struct clk_dto clk_disp0_dto = {
+       .inc_offset = SIRFSOC_CLKC_DISP0_DTO_INC,
+       .src_offset = SIRFSOC_CLKC_DISP0_DTO_SRC,
+       .hw = {
+               .init = &clk_disp0dto_init,
+       },
+};
+
+static const char * const disp1dto_clk_parents[] = {
+       "sys0pll_clk1",
+       "sys1pll_clk1",
+       "sys3pll_clk1",
+};
+
+static struct clk_init_data clk_disp1dto_init = {
+       .name = "disp1_dto",
+       .ops = &dto_ops,
+       .parent_names = disp1dto_clk_parents,
+       .num_parents = ARRAY_SIZE(disp1dto_clk_parents),
+};
+
+static struct clk_dto clk_disp1_dto = {
+       .inc_offset = SIRFSOC_CLKC_DISP1_DTO_INC,
+       .src_offset = SIRFSOC_CLKC_DISP1_DTO_SRC,
+       .hw = {
+               .init = &clk_disp1dto_init,
+       },
+};
+
+static struct atlas7_div_init_data divider_list[] __initdata = {
+       /* div_name, parent_name, gate_name, clk_flag, divider_flag, gate_flag, div_offset, shift, wdith, gate_offset, bit_enable, lock */
+       { "sys0pll_qa1", "sys0pll_fixdiv", "sys0pll_a1", 0, 0, 0, SIRFSOC_CLKC_USBPHY_CLKDIV_CFG, 0, 6, SIRFSOC_CLKC_USBPHY_CLKDIV_ENA, 0, &usbphy_div_lock },
+       { "sys1pll_qa1", "sys1pll_fixdiv", "sys1pll_a1", 0, 0, 0, SIRFSOC_CLKC_USBPHY_CLKDIV_CFG, 8, 6, SIRFSOC_CLKC_USBPHY_CLKDIV_ENA, 4, &usbphy_div_lock },
+       { "sys2pll_qa1", "sys2pll_fixdiv", "sys2pll_a1", 0, 0, 0, SIRFSOC_CLKC_USBPHY_CLKDIV_CFG, 16, 6, SIRFSOC_CLKC_USBPHY_CLKDIV_ENA, 8, &usbphy_div_lock },
+       { "sys3pll_qa1", "sys3pll_fixdiv", "sys3pll_a1", 0, 0, 0, SIRFSOC_CLKC_USBPHY_CLKDIV_CFG, 24, 6, SIRFSOC_CLKC_USBPHY_CLKDIV_ENA, 12, &usbphy_div_lock },
+       { "sys0pll_qa2", "sys0pll_fixdiv", "sys0pll_a2", 0, 0, 0, SIRFSOC_CLKC_BTSS_CLKDIV_CFG, 0, 6, SIRFSOC_CLKC_BTSS_CLKDIV_ENA, 0, &btss_div_lock },
+       { "sys1pll_qa2", "sys1pll_fixdiv", "sys1pll_a2", 0, 0, 0, SIRFSOC_CLKC_BTSS_CLKDIV_CFG, 8, 6, SIRFSOC_CLKC_BTSS_CLKDIV_ENA, 4, &btss_div_lock },
+       { "sys2pll_qa2", "sys2pll_fixdiv", "sys2pll_a2", 0, 0, 0, SIRFSOC_CLKC_BTSS_CLKDIV_CFG, 16, 6, SIRFSOC_CLKC_BTSS_CLKDIV_ENA, 8, &btss_div_lock },
+       { "sys3pll_qa2", "sys3pll_fixdiv", "sys3pll_a2", 0, 0, 0, SIRFSOC_CLKC_BTSS_CLKDIV_CFG, 24, 6, SIRFSOC_CLKC_BTSS_CLKDIV_ENA, 12, &btss_div_lock },
+       { "sys0pll_qa3", "sys0pll_fixdiv", "sys0pll_a3", 0, 0, 0, SIRFSOC_CLKC_RGMII_CLKDIV_CFG, 0, 6, SIRFSOC_CLKC_RGMII_CLKDIV_ENA, 0, &rgmii_div_lock },
+       { "sys1pll_qa3", "sys1pll_fixdiv", "sys1pll_a3", 0, 0, 0, SIRFSOC_CLKC_RGMII_CLKDIV_CFG, 8, 6, SIRFSOC_CLKC_RGMII_CLKDIV_ENA, 4, &rgmii_div_lock },
+       { "sys2pll_qa3", "sys2pll_fixdiv", "sys2pll_a3", 0, 0, 0, SIRFSOC_CLKC_RGMII_CLKDIV_CFG, 16, 6, SIRFSOC_CLKC_RGMII_CLKDIV_ENA, 8, &rgmii_div_lock },
+       { "sys3pll_qa3", "sys3pll_fixdiv", "sys3pll_a3", 0, 0, 0, SIRFSOC_CLKC_RGMII_CLKDIV_CFG, 24, 6, SIRFSOC_CLKC_RGMII_CLKDIV_ENA, 12, &rgmii_div_lock },
+       { "sys0pll_qa4", "sys0pll_fixdiv", "sys0pll_a4", 0, 0, 0, SIRFSOC_CLKC_CPU_CLKDIV_CFG, 0, 6, SIRFSOC_CLKC_CPU_CLKDIV_ENA, 0, &cpu_div_lock },
+       { "sys1pll_qa4", "sys1pll_fixdiv", "sys1pll_a4", 0, 0, CLK_IGNORE_UNUSED, SIRFSOC_CLKC_CPU_CLKDIV_CFG, 8, 6, SIRFSOC_CLKC_CPU_CLKDIV_ENA, 4, &cpu_div_lock },
+       { "sys0pll_qa5", "sys0pll_fixdiv", "sys0pll_a5", 0, 0, 0, SIRFSOC_CLKC_SDPHY01_CLKDIV_CFG, 0, 6, SIRFSOC_CLKC_SDPHY01_CLKDIV_ENA, 0, &sdphy01_div_lock },
+       { "sys1pll_qa5", "sys1pll_fixdiv", "sys1pll_a5", 0, 0, 0, SIRFSOC_CLKC_SDPHY01_CLKDIV_CFG, 8, 6, SIRFSOC_CLKC_SDPHY01_CLKDIV_ENA, 4, &sdphy01_div_lock },
+       { "sys2pll_qa5", "sys2pll_fixdiv", "sys2pll_a5", 0, 0, 0, SIRFSOC_CLKC_SDPHY01_CLKDIV_CFG, 16, 6, SIRFSOC_CLKC_SDPHY01_CLKDIV_ENA, 8, &sdphy01_div_lock },
+       { "sys3pll_qa5", "sys3pll_fixdiv", "sys3pll_a5", 0, 0, 0, SIRFSOC_CLKC_SDPHY01_CLKDIV_CFG, 24, 6, SIRFSOC_CLKC_SDPHY01_CLKDIV_ENA, 12, &sdphy01_div_lock },
+       { "sys0pll_qa6", "sys0pll_fixdiv", "sys0pll_a6", 0, 0, 0, SIRFSOC_CLKC_SDPHY23_CLKDIV_CFG, 0, 6, SIRFSOC_CLKC_SDPHY23_CLKDIV_ENA, 0, &sdphy23_div_lock },
+       { "sys1pll_qa6", "sys1pll_fixdiv", "sys1pll_a6", 0, 0, 0, SIRFSOC_CLKC_SDPHY23_CLKDIV_CFG, 8, 6, SIRFSOC_CLKC_SDPHY23_CLKDIV_ENA, 4, &sdphy23_div_lock },
+       { "sys2pll_qa6", "sys2pll_fixdiv", "sys2pll_a6", 0, 0, 0, SIRFSOC_CLKC_SDPHY23_CLKDIV_CFG, 16, 6, SIRFSOC_CLKC_SDPHY23_CLKDIV_ENA, 8, &sdphy23_div_lock },
+       { "sys3pll_qa6", "sys3pll_fixdiv", "sys3pll_a6", 0, 0, 0, SIRFSOC_CLKC_SDPHY23_CLKDIV_CFG, 24, 6, SIRFSOC_CLKC_SDPHY23_CLKDIV_ENA, 12, &sdphy23_div_lock },
+       { "sys0pll_qa7", "sys0pll_fixdiv", "sys0pll_a7", 0, 0, 0, SIRFSOC_CLKC_SDPHY45_CLKDIV_CFG, 0, 6, SIRFSOC_CLKC_SDPHY45_CLKDIV_ENA, 0, &sdphy45_div_lock },
+       { "sys1pll_qa7", "sys1pll_fixdiv", "sys1pll_a7", 0, 0, 0, SIRFSOC_CLKC_SDPHY45_CLKDIV_CFG, 8, 6, SIRFSOC_CLKC_SDPHY45_CLKDIV_ENA, 4, &sdphy45_div_lock },
+       { "sys2pll_qa7", "sys2pll_fixdiv", "sys2pll_a7", 0, 0, 0, SIRFSOC_CLKC_SDPHY45_CLKDIV_CFG, 16, 6, SIRFSOC_CLKC_SDPHY45_CLKDIV_ENA, 8, &sdphy45_div_lock },
+       { "sys3pll_qa7", "sys3pll_fixdiv", "sys3pll_a7", 0, 0, 0, SIRFSOC_CLKC_SDPHY45_CLKDIV_CFG, 24, 6, SIRFSOC_CLKC_SDPHY45_CLKDIV_ENA, 12, &sdphy45_div_lock },
+       { "sys0pll_qa8", "sys0pll_fixdiv", "sys0pll_a8", 0, 0, 0, SIRFSOC_CLKC_SDPHY67_CLKDIV_CFG, 0, 6, SIRFSOC_CLKC_SDPHY67_CLKDIV_ENA, 0, &sdphy67_div_lock },
+       { "sys1pll_qa8", "sys1pll_fixdiv", "sys1pll_a8", 0, 0, 0, SIRFSOC_CLKC_SDPHY67_CLKDIV_CFG, 8, 6, SIRFSOC_CLKC_SDPHY67_CLKDIV_ENA, 4, &sdphy67_div_lock },
+       { "sys2pll_qa8", "sys2pll_fixdiv", "sys2pll_a8", 0, 0, 0, SIRFSOC_CLKC_SDPHY67_CLKDIV_CFG, 16, 6, SIRFSOC_CLKC_SDPHY67_CLKDIV_ENA, 8, &sdphy67_div_lock },
+       { "sys3pll_qa8", "sys3pll_fixdiv", "sys3pll_a8", 0, 0, 0, SIRFSOC_CLKC_SDPHY67_CLKDIV_CFG, 24, 6, SIRFSOC_CLKC_SDPHY67_CLKDIV_ENA, 12, &sdphy67_div_lock },
+       { "sys0pll_qa9", "sys0pll_fixdiv", "sys0pll_a9", 0, 0, 0, SIRFSOC_CLKC_CAN_CLKDIV_CFG, 0, 6, SIRFSOC_CLKC_CAN_CLKDIV_ENA, 0, &can_div_lock },
+       { "sys1pll_qa9", "sys1pll_fixdiv", "sys1pll_a9", 0, 0, 0, SIRFSOC_CLKC_CAN_CLKDIV_CFG, 8, 6, SIRFSOC_CLKC_CAN_CLKDIV_ENA, 4, &can_div_lock },
+       { "sys2pll_qa9", "sys2pll_fixdiv", "sys2pll_a9", 0, 0, 0, SIRFSOC_CLKC_CAN_CLKDIV_CFG, 16, 6, SIRFSOC_CLKC_CAN_CLKDIV_ENA, 8, &can_div_lock },
+       { "sys3pll_qa9", "sys3pll_fixdiv", "sys3pll_a9", 0, 0, 0, SIRFSOC_CLKC_CAN_CLKDIV_CFG, 24, 6, SIRFSOC_CLKC_CAN_CLKDIV_ENA, 12, &can_div_lock },
+       { "sys0pll_qa10", "sys0pll_fixdiv", "sys0pll_a10", 0, 0, 0, SIRFSOC_CLKC_DEINT_CLKDIV_CFG, 0, 6, SIRFSOC_CLKC_DEINT_CLKDIV_ENA, 0, &deint_div_lock },
+       { "sys1pll_qa10", "sys1pll_fixdiv", "sys1pll_a10", 0, 0, 0, SIRFSOC_CLKC_DEINT_CLKDIV_CFG, 8, 6, SIRFSOC_CLKC_DEINT_CLKDIV_ENA, 4, &deint_div_lock },
+       { "sys2pll_qa10", "sys2pll_fixdiv", "sys2pll_a10", 0, 0, 0, SIRFSOC_CLKC_DEINT_CLKDIV_CFG, 16, 6, SIRFSOC_CLKC_DEINT_CLKDIV_ENA, 8, &deint_div_lock },
+       { "sys3pll_qa10", "sys3pll_fixdiv", "sys3pll_a10", 0, 0, 0, SIRFSOC_CLKC_DEINT_CLKDIV_CFG, 24, 6, SIRFSOC_CLKC_DEINT_CLKDIV_ENA, 12, &deint_div_lock },
+       { "sys0pll_qa11", "sys0pll_fixdiv", "sys0pll_a11", 0, 0, 0, SIRFSOC_CLKC_NAND_CLKDIV_CFG, 0, 6, SIRFSOC_CLKC_NAND_CLKDIV_ENA, 0, &nand_div_lock },
+       { "sys1pll_qa11", "sys1pll_fixdiv", "sys1pll_a11", 0, 0, 0, SIRFSOC_CLKC_NAND_CLKDIV_CFG, 8, 6, SIRFSOC_CLKC_NAND_CLKDIV_ENA, 4, &nand_div_lock },
+       { "sys2pll_qa11", "sys2pll_fixdiv", "sys2pll_a11", 0, 0, 0, SIRFSOC_CLKC_NAND_CLKDIV_CFG, 16, 6, SIRFSOC_CLKC_NAND_CLKDIV_ENA, 8, &nand_div_lock },
+       { "sys3pll_qa11", "sys3pll_fixdiv", "sys3pll_a11", 0, 0, 0, SIRFSOC_CLKC_NAND_CLKDIV_CFG, 24, 6, SIRFSOC_CLKC_NAND_CLKDIV_ENA, 12, &nand_div_lock },
+       { "sys0pll_qa12", "sys0pll_fixdiv", "sys0pll_a12", 0, 0, 0, SIRFSOC_CLKC_DISP0_CLKDIV_CFG, 0, 6, SIRFSOC_CLKC_DISP0_CLKDIV_ENA, 0, &disp0_div_lock },
+       { "sys1pll_qa12", "sys1pll_fixdiv", "sys1pll_a12", 0, 0, 0, SIRFSOC_CLKC_DISP0_CLKDIV_CFG, 8, 6, SIRFSOC_CLKC_DISP0_CLKDIV_ENA, 4, &disp0_div_lock },
+       { "sys2pll_qa12", "sys2pll_fixdiv", "sys2pll_a12", 0, 0, 0, SIRFSOC_CLKC_DISP0_CLKDIV_CFG, 16, 6, SIRFSOC_CLKC_DISP0_CLKDIV_ENA, 8, &disp0_div_lock },
+       { "sys3pll_qa12", "sys3pll_fixdiv", "sys3pll_a12", 0, 0, 0, SIRFSOC_CLKC_DISP0_CLKDIV_CFG, 24, 6, SIRFSOC_CLKC_DISP0_CLKDIV_ENA, 12, &disp0_div_lock },
+       { "sys0pll_qa13", "sys0pll_fixdiv", "sys0pll_a13", 0, 0, 0, SIRFSOC_CLKC_DISP1_CLKDIV_CFG, 0, 6, SIRFSOC_CLKC_DISP1_CLKDIV_ENA, 0, &disp1_div_lock },
+       { "sys1pll_qa13", "sys1pll_fixdiv", "sys1pll_a13", 0, 0, 0, SIRFSOC_CLKC_DISP1_CLKDIV_CFG, 8, 6, SIRFSOC_CLKC_DISP1_CLKDIV_ENA, 4, &disp1_div_lock },
+       { "sys2pll_qa13", "sys2pll_fixdiv", "sys2pll_a13", 0, 0, 0, SIRFSOC_CLKC_DISP1_CLKDIV_CFG, 16, 6, SIRFSOC_CLKC_DISP1_CLKDIV_ENA, 8, &disp1_div_lock },
+       { "sys3pll_qa13", "sys3pll_fixdiv", "sys3pll_a13", 0, 0, 0, SIRFSOC_CLKC_DISP1_CLKDIV_CFG, 24, 6, SIRFSOC_CLKC_DISP1_CLKDIV_ENA, 12, &disp1_div_lock },
+       { "sys0pll_qa14", "sys0pll_fixdiv", "sys0pll_a14", 0, 0, 0, SIRFSOC_CLKC_GPU_CLKDIV_CFG, 0, 6, SIRFSOC_CLKC_GPU_CLKDIV_ENA, 0, &gpu_div_lock },
+       { "sys1pll_qa14", "sys1pll_fixdiv", "sys1pll_a14", 0, 0, 0, SIRFSOC_CLKC_GPU_CLKDIV_CFG, 8, 6, SIRFSOC_CLKC_GPU_CLKDIV_ENA, 4, &gpu_div_lock },
+       { "sys2pll_qa14", "sys2pll_fixdiv", "sys2pll_a14", 0, 0, 0, SIRFSOC_CLKC_GPU_CLKDIV_CFG, 16, 6, SIRFSOC_CLKC_GPU_CLKDIV_ENA, 8, &gpu_div_lock },
+       { "sys3pll_qa14", "sys3pll_fixdiv", "sys3pll_a14", 0, 0, 0, SIRFSOC_CLKC_GPU_CLKDIV_CFG, 24, 6, SIRFSOC_CLKC_GPU_CLKDIV_ENA, 12, &gpu_div_lock },
+       { "sys0pll_qa15", "sys0pll_fixdiv", "sys0pll_a15", 0, 0, 0, SIRFSOC_CLKC_GNSS_CLKDIV_CFG, 0, 6, SIRFSOC_CLKC_GNSS_CLKDIV_ENA, 0, &gnss_div_lock },
+       { "sys1pll_qa15", "sys1pll_fixdiv", "sys1pll_a15", 0, 0, 0, SIRFSOC_CLKC_GNSS_CLKDIV_CFG, 8, 6, SIRFSOC_CLKC_GNSS_CLKDIV_ENA, 4, &gnss_div_lock },
+       { "sys2pll_qa15", "sys2pll_fixdiv", "sys2pll_a15", 0, 0, 0, SIRFSOC_CLKC_GNSS_CLKDIV_CFG, 16, 6, SIRFSOC_CLKC_GNSS_CLKDIV_ENA, 8, &gnss_div_lock },
+       { "sys3pll_qa15", "sys3pll_fixdiv", "sys3pll_a15", 0, 0, 0, SIRFSOC_CLKC_GNSS_CLKDIV_CFG, 24, 6, SIRFSOC_CLKC_GNSS_CLKDIV_ENA, 12, &gnss_div_lock },
+       { "sys1pll_qa18", "sys1pll_fixdiv", "sys1pll_a18", 0, 0, 0, SIRFSOC_CLKC_SHARED_DIVIDER_CFG0, 24, 6, SIRFSOC_CLKC_SHARED_DIVIDER_ENA, 12, &share_div_lock },
+       { "sys1pll_qa19", "sys1pll_fixdiv", "sys1pll_a19", 0, 0, CLK_IGNORE_UNUSED, SIRFSOC_CLKC_SHARED_DIVIDER_CFG0, 16, 6, SIRFSOC_CLKC_SHARED_DIVIDER_ENA, 8, &share_div_lock },
+       { "sys1pll_qa20", "sys1pll_fixdiv", "sys1pll_a20", 0, 0, 0, SIRFSOC_CLKC_SHARED_DIVIDER_CFG0, 8, 6, SIRFSOC_CLKC_SHARED_DIVIDER_ENA, 4, &share_div_lock },
+       { "sys2pll_qa20", "sys2pll_fixdiv", "sys2pll_a20", 0, 0, 0, SIRFSOC_CLKC_SHARED_DIVIDER_CFG0, 0, 6, SIRFSOC_CLKC_SHARED_DIVIDER_ENA, 0, &share_div_lock },
+       { "sys1pll_qa17", "sys1pll_fixdiv", "sys1pll_a17", 0, 0, CLK_IGNORE_UNUSED, SIRFSOC_CLKC_SHARED_DIVIDER_CFG1, 8, 6, SIRFSOC_CLKC_SHARED_DIVIDER_ENA, 20, &share_div_lock },
+       { "sys0pll_qa20", "sys0pll_fixdiv", "sys0pll_a20", 0, 0, 0, SIRFSOC_CLKC_SHARED_DIVIDER_CFG1, 0, 6, SIRFSOC_CLKC_SHARED_DIVIDER_ENA, 16, &share_div_lock },
+};
+
+static const char * const i2s_clk_parents[] = {
+       "xin",
+       "xinw",
+       "audio_dto",
+       /* "pwm_i2s01" */
+};
+
+static const char * const usbphy_clk_parents[] = {
+       "xin",
+       "xinw",
+       "sys0pll_a1",
+       "sys1pll_a1",
+       "sys2pll_a1",
+       "sys3pll_a1",
+};
+
+static const char * const btss_clk_parents[] = {
+       "xin",
+       "xinw",
+       "sys0pll_a2",
+       "sys1pll_a2",
+       "sys2pll_a2",
+       "sys3pll_a2",
+};
+
+static const char * const rgmii_clk_parents[] = {
+       "xin",
+       "xinw",
+       "sys0pll_a3",
+       "sys1pll_a3",
+       "sys2pll_a3",
+       "sys3pll_a3",
+};
+
+static const char * const cpu_clk_parents[] = {
+       "xin",
+       "xinw",
+       "sys0pll_a4",
+       "sys1pll_a4",
+       "cpupll_clk1",
+};
+
+static const char * const sdphy01_clk_parents[] = {
+       "xin",
+       "xinw",
+       "sys0pll_a5",
+       "sys1pll_a5",
+       "sys2pll_a5",
+       "sys3pll_a5",
+};
+
+static const char * const sdphy23_clk_parents[] = {
+       "xin",
+       "xinw",
+       "sys0pll_a6",
+       "sys1pll_a6",
+       "sys2pll_a6",
+       "sys3pll_a6",
+};
+
+static const char * const sdphy45_clk_parents[] = {
+       "xin",
+       "xinw",
+       "sys0pll_a7",
+       "sys1pll_a7",
+       "sys2pll_a7",
+       "sys3pll_a7",
+};
+
+static const char * const sdphy67_clk_parents[] = {
+       "xin",
+       "xinw",
+       "sys0pll_a8",
+       "sys1pll_a8",
+       "sys2pll_a8",
+       "sys3pll_a8",
+};
+
+static const char * const can_clk_parents[] = {
+       "xin",
+       "xinw",
+       "sys0pll_a9",
+       "sys1pll_a9",
+       "sys2pll_a9",
+       "sys3pll_a9",
+};
+
+static const char * const deint_clk_parents[] = {
+       "xin",
+       "xinw",
+       "sys0pll_a10",
+       "sys1pll_a10",
+       "sys2pll_a10",
+       "sys3pll_a10",
+};
+
+static const char * const nand_clk_parents[] = {
+       "xin",
+       "xinw",
+       "sys0pll_a11",
+       "sys1pll_a11",
+       "sys2pll_a11",
+       "sys3pll_a11",
+};
+
+static const char * const disp0_clk_parents[] = {
+       "xin",
+       "xinw",
+       "sys0pll_a12",
+       "sys1pll_a12",
+       "sys2pll_a12",
+       "sys3pll_a12",
+       "disp0_dto",
+};
+
+static const char * const disp1_clk_parents[] = {
+       "xin",
+       "xinw",
+       "sys0pll_a13",
+       "sys1pll_a13",
+       "sys2pll_a13",
+       "sys3pll_a13",
+       "disp1_dto",
+};
+
+static const char * const gpu_clk_parents[] = {
+       "xin",
+       "xinw",
+       "sys0pll_a14",
+       "sys1pll_a14",
+       "sys2pll_a14",
+       "sys3pll_a14",
+};
+
+static const char * const gnss_clk_parents[] = {
+       "xin",
+       "xinw",
+       "sys0pll_a15",
+       "sys1pll_a15",
+       "sys2pll_a15",
+       "sys3pll_a15",
+};
+
+static const char * const sys_clk_parents[] = {
+       "xin",
+       "xinw",
+       "sys2pll_a20",
+       "sys1pll_a20",
+       "sys1pll_a19",
+       "sys1pll_a18",
+       "sys0pll_a20",
+       "sys1pll_a17",
+};
+
+static const char * const io_clk_parents[] = {
+       "xin",
+       "xinw",
+       "sys2pll_a20",
+       "sys1pll_a20",
+       "sys1pll_a19",
+       "sys1pll_a18",
+       "sys0pll_a20",
+       "sys1pll_a17",
+};
+
+static const char * const g2d_clk_parents[] = {
+       "xin",
+       "xinw",
+       "sys2pll_a20",
+       "sys1pll_a20",
+       "sys1pll_a19",
+       "sys1pll_a18",
+       "sys0pll_a20",
+       "sys1pll_a17",
+};
+
+static const char * const jpenc_clk_parents[] = {
+       "xin",
+       "xinw",
+       "sys2pll_a20",
+       "sys1pll_a20",
+       "sys1pll_a19",
+       "sys1pll_a18",
+       "sys0pll_a20",
+       "sys1pll_a17",
+};
+
+static const char * const vdec_clk_parents[] = {
+       "xin",
+       "xinw",
+       "sys2pll_a20",
+       "sys1pll_a20",
+       "sys1pll_a19",
+       "sys1pll_a18",
+       "sys0pll_a20",
+       "sys1pll_a17",
+};
+
+static const char * const gmac_clk_parents[] = {
+       "xin",
+       "xinw",
+       "sys2pll_a20",
+       "sys1pll_a20",
+       "sys1pll_a19",
+       "sys1pll_a18",
+       "sys0pll_a20",
+       "sys1pll_a17",
+};
+
+static const char * const usb_clk_parents[] = {
+       "xin",
+       "xinw",
+       "sys2pll_a20",
+       "sys1pll_a20",
+       "sys1pll_a19",
+       "sys1pll_a18",
+       "sys0pll_a20",
+       "sys1pll_a17",
+};
+
+static const char * const kas_clk_parents[] = {
+       "xin",
+       "xinw",
+       "sys2pll_a20",
+       "sys1pll_a20",
+       "sys1pll_a19",
+       "sys1pll_a18",
+       "sys0pll_a20",
+       "sys1pll_a17",
+};
+
+static const char * const sec_clk_parents[] = {
+       "xin",
+       "xinw",
+       "sys2pll_a20",
+       "sys1pll_a20",
+       "sys1pll_a19",
+       "sys1pll_a18",
+       "sys0pll_a20",
+       "sys1pll_a17",
+};
+
+static const char * const sdr_clk_parents[] = {
+       "xin",
+       "xinw",
+       "sys2pll_a20",
+       "sys1pll_a20",
+       "sys1pll_a19",
+       "sys1pll_a18",
+       "sys0pll_a20",
+       "sys1pll_a17",
+};
+
+static const char * const vip_clk_parents[] = {
+       "xin",
+       "xinw",
+       "sys2pll_a20",
+       "sys1pll_a20",
+       "sys1pll_a19",
+       "sys1pll_a18",
+       "sys0pll_a20",
+       "sys1pll_a17",
+};
+
+static const char * const nocd_clk_parents[] = {
+       "xin",
+       "xinw",
+       "sys2pll_a20",
+       "sys1pll_a20",
+       "sys1pll_a19",
+       "sys1pll_a18",
+       "sys0pll_a20",
+       "sys1pll_a17",
+};
+
+static const char * const nocr_clk_parents[] = {
+       "xin",
+       "xinw",
+       "sys2pll_a20",
+       "sys1pll_a20",
+       "sys1pll_a19",
+       "sys1pll_a18",
+       "sys0pll_a20",
+       "sys1pll_a17",
+};
+
+static const char * const tpiu_clk_parents[] = {
+       "xin",
+       "xinw",
+       "sys2pll_a20",
+       "sys1pll_a20",
+       "sys1pll_a19",
+       "sys1pll_a18",
+       "sys0pll_a20",
+       "sys1pll_a17",
+};
+
+static struct atlas7_mux_init_data mux_list[] __initdata = {
+       /* mux_name, parent_names, parent_num, flags, mux_flags, mux_offset, shift, width */
+       { "i2s_mux", i2s_clk_parents, ARRAY_SIZE(i2s_clk_parents), 0, 0, SIRFSOC_CLKC_I2S_CLK_SEL, 0, 2 },
+       { "usbphy_mux", usbphy_clk_parents, ARRAY_SIZE(usbphy_clk_parents), 0, 0, SIRFSOC_CLKC_I2S_CLK_SEL, 0, 3 },
+       { "btss_mux", btss_clk_parents, ARRAY_SIZE(btss_clk_parents), 0, 0, SIRFSOC_CLKC_BTSS_CLK_SEL, 0, 3 },
+       { "rgmii_mux", rgmii_clk_parents, ARRAY_SIZE(rgmii_clk_parents), 0, 0, SIRFSOC_CLKC_RGMII_CLK_SEL, 0, 3 },
+       { "cpu_mux", cpu_clk_parents, ARRAY_SIZE(cpu_clk_parents), 0, 0, SIRFSOC_CLKC_CPU_CLK_SEL, 0, 3 },
+       { "sdphy01_mux", sdphy01_clk_parents, ARRAY_SIZE(sdphy01_clk_parents), 0, 0, SIRFSOC_CLKC_SDPHY01_CLK_SEL, 0, 3 },
+       { "sdphy23_mux", sdphy23_clk_parents, ARRAY_SIZE(sdphy23_clk_parents), 0, 0, SIRFSOC_CLKC_SDPHY23_CLK_SEL, 0, 3 },
+       { "sdphy45_mux", sdphy45_clk_parents, ARRAY_SIZE(sdphy45_clk_parents), 0, 0, SIRFSOC_CLKC_SDPHY45_CLK_SEL, 0, 3 },
+       { "sdphy67_mux", sdphy67_clk_parents, ARRAY_SIZE(sdphy67_clk_parents), 0, 0, SIRFSOC_CLKC_SDPHY67_CLK_SEL, 0, 3 },
+       { "can_mux", can_clk_parents, ARRAY_SIZE(can_clk_parents), 0, 0, SIRFSOC_CLKC_CAN_CLK_SEL, 0, 3 },
+       { "deint_mux", deint_clk_parents, ARRAY_SIZE(deint_clk_parents), 0, 0, SIRFSOC_CLKC_DEINT_CLK_SEL, 0, 3 },
+       { "nand_mux", nand_clk_parents, ARRAY_SIZE(nand_clk_parents), 0, 0, SIRFSOC_CLKC_NAND_CLK_SEL, 0, 3 },
+       { "disp0_mux", disp0_clk_parents, ARRAY_SIZE(disp0_clk_parents), 0, 0, SIRFSOC_CLKC_DISP0_CLK_SEL, 0, 3 },
+       { "disp1_mux", disp1_clk_parents, ARRAY_SIZE(disp1_clk_parents), 0, 0, SIRFSOC_CLKC_DISP1_CLK_SEL, 0, 3 },
+       { "gpu_mux", gpu_clk_parents, ARRAY_SIZE(gpu_clk_parents), 0, 0, SIRFSOC_CLKC_GPU_CLK_SEL, 0, 3 },
+       { "gnss_mux", gnss_clk_parents, ARRAY_SIZE(gnss_clk_parents), 0, 0, SIRFSOC_CLKC_GNSS_CLK_SEL, 0, 3 },
+       { "sys_mux", sys_clk_parents, ARRAY_SIZE(sys_clk_parents), 0, 0, SIRFSOC_CLKC_SYS_CLK_SEL, 0, 3 },
+       { "io_mux", io_clk_parents, ARRAY_SIZE(io_clk_parents), 0, 0, SIRFSOC_CLKC_IO_CLK_SEL, 0, 3 },
+       { "g2d_mux", g2d_clk_parents, ARRAY_SIZE(g2d_clk_parents), 0, 0, SIRFSOC_CLKC_G2D_CLK_SEL, 0, 3 },
+       { "jpenc_mux", jpenc_clk_parents, ARRAY_SIZE(jpenc_clk_parents), 0, 0, SIRFSOC_CLKC_JPENC_CLK_SEL, 0, 3 },
+       { "vdec_mux", vdec_clk_parents, ARRAY_SIZE(vdec_clk_parents), 0, 0, SIRFSOC_CLKC_VDEC_CLK_SEL, 0, 3 },
+       { "gmac_mux", gmac_clk_parents, ARRAY_SIZE(gmac_clk_parents), 0, 0, SIRFSOC_CLKC_GMAC_CLK_SEL, 0, 3 },
+       { "usb_mux", usb_clk_parents, ARRAY_SIZE(usb_clk_parents), 0, 0, SIRFSOC_CLKC_USB_CLK_SEL, 0, 3 },
+       { "kas_mux", kas_clk_parents, ARRAY_SIZE(kas_clk_parents), 0, 0, SIRFSOC_CLKC_KAS_CLK_SEL, 0, 3 },
+       { "sec_mux", sec_clk_parents, ARRAY_SIZE(sec_clk_parents), 0, 0, SIRFSOC_CLKC_SEC_CLK_SEL, 0, 3 },
+       { "sdr_mux", sdr_clk_parents, ARRAY_SIZE(sdr_clk_parents), 0, 0, SIRFSOC_CLKC_SDR_CLK_SEL, 0, 3 },
+       { "vip_mux", vip_clk_parents, ARRAY_SIZE(vip_clk_parents), 0, 0, SIRFSOC_CLKC_VIP_CLK_SEL, 0, 3 },
+       { "nocd_mux", nocd_clk_parents, ARRAY_SIZE(nocd_clk_parents), 0, 0, SIRFSOC_CLKC_NOCD_CLK_SEL, 0, 3 },
+       { "nocr_mux", nocr_clk_parents, ARRAY_SIZE(nocr_clk_parents), 0, 0, SIRFSOC_CLKC_NOCR_CLK_SEL, 0, 3 },
+       { "tpiu_mux", tpiu_clk_parents, ARRAY_SIZE(tpiu_clk_parents), 0, 0, SIRFSOC_CLKC_TPIU_CLK_SEL, 0, 3 },
+};
+
+       /* new unit should add start from the tail of list */
+static struct atlas7_unit_init_data unit_list[] __initdata = {
+       /* unit_name, parent_name, flags, regofs, bit, lock */
+       { 0, "audmscm_kas", "kas_mux", 0, SIRFSOC_CLKC_ROOT_CLK_EN0_SET, 0, &root0_gate_lock },
+       { 1, "gnssm_gnss", "gnss_mux", 0, SIRFSOC_CLKC_ROOT_CLK_EN0_SET, 1, &root0_gate_lock },
+       { 2, "gpum_gpu", "gpu_mux", 0, SIRFSOC_CLKC_ROOT_CLK_EN0_SET, 2, &root0_gate_lock },
+       { 3, "mediam_g2d", "g2d_mux", 0, SIRFSOC_CLKC_ROOT_CLK_EN0_SET, 3, &root0_gate_lock },
+       { 4, "mediam_jpenc", "jpenc_mux", 0, SIRFSOC_CLKC_ROOT_CLK_EN0_SET, 4, &root0_gate_lock },
+       { 5, "vdifm_disp0", "disp0_mux", 0, SIRFSOC_CLKC_ROOT_CLK_EN0_SET, 5, &root0_gate_lock },
+       { 6, "vdifm_disp1", "disp1_mux", 0, SIRFSOC_CLKC_ROOT_CLK_EN0_SET, 6, &root0_gate_lock },
+       { 7, "audmscm_i2s", "i2s_mux", 0, SIRFSOC_CLKC_ROOT_CLK_EN0_SET, 8, &root0_gate_lock },
+       { 8, "audmscm_io", "io_mux", 0, SIRFSOC_CLKC_ROOT_CLK_EN0_SET, 11, &root0_gate_lock },
+       { 9, "vdifm_io", "io_mux", 0, SIRFSOC_CLKC_ROOT_CLK_EN0_SET, 12, &root0_gate_lock },
+       { 10, "gnssm_io", "io_mux", 0, SIRFSOC_CLKC_ROOT_CLK_EN0_SET, 13, &root0_gate_lock },
+       { 11, "mediam_io", "io_mux", 0, SIRFSOC_CLKC_ROOT_CLK_EN0_SET, 14, &root0_gate_lock },
+       { 12, "btm_io", "io_mux", 0, SIRFSOC_CLKC_ROOT_CLK_EN0_SET, 17, &root0_gate_lock },
+       { 13, "mediam_sdphy01", "sdphy01_mux", 0, SIRFSOC_CLKC_ROOT_CLK_EN0_SET, 18, &root0_gate_lock },
+       { 14, "vdifm_sdphy23", "sdphy23_mux", 0, SIRFSOC_CLKC_ROOT_CLK_EN0_SET, 19, &root0_gate_lock },
+       { 15, "vdifm_sdphy45", "sdphy45_mux", 0, SIRFSOC_CLKC_ROOT_CLK_EN0_SET, 20, &root0_gate_lock },
+       { 16, "vdifm_sdphy67", "sdphy67_mux", 0, SIRFSOC_CLKC_ROOT_CLK_EN0_SET, 21, &root0_gate_lock },
+       { 17, "audmscm_xin", "xin", 0, SIRFSOC_CLKC_ROOT_CLK_EN0_SET, 22, &root0_gate_lock },
+       { 18, "mediam_nand", "nand_mux", 0, SIRFSOC_CLKC_ROOT_CLK_EN0_SET, 27, &root0_gate_lock },
+       { 19, "gnssm_sec", "sec_mux", 0, SIRFSOC_CLKC_ROOT_CLK_EN0_SET, 28, &root0_gate_lock },
+       { 20, "cpum_cpu", "cpu_mux", 0, SIRFSOC_CLKC_ROOT_CLK_EN0_SET, 29, &root0_gate_lock },
+       { 21, "gnssm_xin", "xin", 0, SIRFSOC_CLKC_ROOT_CLK_EN0_SET, 30, &root0_gate_lock },
+       { 22, "vdifm_vip", "vip_mux", 0, SIRFSOC_CLKC_ROOT_CLK_EN0_SET, 31, &root0_gate_lock },
+       { 23, "btm_btss", "btss_mux", 0, SIRFSOC_CLKC_ROOT_CLK_EN1_SET, 0, &root1_gate_lock },
+       { 24, "mediam_usbphy", "usbphy_mux", 0, SIRFSOC_CLKC_ROOT_CLK_EN1_SET, 1, &root1_gate_lock },
+       { 25, "rtcm_kas", "kas_mux", 0, SIRFSOC_CLKC_ROOT_CLK_EN1_SET, 2, &root1_gate_lock },
+       { 26, "audmscm_nocd", "nocd_mux", 0, SIRFSOC_CLKC_ROOT_CLK_EN1_SET, 3, &root1_gate_lock },
+       { 27, "vdifm_nocd", "nocd_mux", 0, SIRFSOC_CLKC_ROOT_CLK_EN1_SET, 4, &root1_gate_lock },
+       { 28, "gnssm_nocd", "nocd_mux", 0, SIRFSOC_CLKC_ROOT_CLK_EN1_SET, 5, &root1_gate_lock },
+       { 29, "mediam_nocd", "nocd_mux", 0, SIRFSOC_CLKC_ROOT_CLK_EN1_SET, 6, &root1_gate_lock },
+       { 30, "cpum_nocd", "nocd_mux", 0, SIRFSOC_CLKC_ROOT_CLK_EN1_SET, 8, &root1_gate_lock },
+       { 31, "gpum_nocd", "nocd_mux", 0, SIRFSOC_CLKC_ROOT_CLK_EN1_SET, 9, &root1_gate_lock },
+       { 32, "audmscm_nocr", "nocr_mux", 0, SIRFSOC_CLKC_ROOT_CLK_EN1_SET, 11, &root1_gate_lock },
+       { 33, "vdifm_nocr", "nocr_mux", 0, SIRFSOC_CLKC_ROOT_CLK_EN1_SET, 12, &root1_gate_lock },
+       { 34, "gnssm_nocr", "nocr_mux", CLK_IGNORE_UNUSED, SIRFSOC_CLKC_ROOT_CLK_EN1_SET, 13, &root1_gate_lock },
+       { 35, "mediam_nocr", "nocr_mux", CLK_IGNORE_UNUSED, SIRFSOC_CLKC_ROOT_CLK_EN1_SET, 14, &root1_gate_lock },
+       { 36, "ddrm_nocr", "nocr_mux", CLK_IGNORE_UNUSED, SIRFSOC_CLKC_ROOT_CLK_EN1_SET, 15, &root1_gate_lock },
+       { 37, "cpum_tpiu", "tpiu_mux", 0, SIRFSOC_CLKC_ROOT_CLK_EN1_SET, 16, &root1_gate_lock },
+       { 38, "gpum_nocr", "nocr_mux", 0, SIRFSOC_CLKC_ROOT_CLK_EN1_SET, 17, &root1_gate_lock },
+       { 39, "gnssm_rgmii", "rgmii_mux", 0, SIRFSOC_CLKC_ROOT_CLK_EN1_SET, 20, &root1_gate_lock },
+       { 40, "mediam_vdec", "vdec_mux", 0, SIRFSOC_CLKC_ROOT_CLK_EN1_SET, 21, &root1_gate_lock },
+       { 41, "gpum_sdr", "sdr_mux", 0, SIRFSOC_CLKC_ROOT_CLK_EN1_SET, 22, &root1_gate_lock },
+       { 42, "vdifm_deint", "deint_mux", 0, SIRFSOC_CLKC_ROOT_CLK_EN1_SET, 23, &root1_gate_lock },
+       { 43, "gnssm_can", "can_mux", 0, SIRFSOC_CLKC_ROOT_CLK_EN1_SET, 26, &root1_gate_lock },
+       { 44, "mediam_usb", "usb_mux", 0, SIRFSOC_CLKC_ROOT_CLK_EN1_SET, 28, &root1_gate_lock },
+       { 45, "gnssm_gmac", "gmac_mux", 0, SIRFSOC_CLKC_ROOT_CLK_EN1_SET, 29, &root1_gate_lock },
+       { 46, "cvd_io", "audmscm_io", 0, SIRFSOC_CLKC_LEAF_CLK_EN1_SET, 0, &leaf1_gate_lock },
+       { 47, "timer_io", "audmscm_io", 0, SIRFSOC_CLKC_LEAF_CLK_EN1_SET, 1, &leaf1_gate_lock },
+       { 48, "pulse_io", "audmscm_io", 0, SIRFSOC_CLKC_LEAF_CLK_EN1_SET, 2, &leaf1_gate_lock },
+       { 49, "tsc_io", "audmscm_io", 0, SIRFSOC_CLKC_LEAF_CLK_EN1_SET, 3, &leaf1_gate_lock },
+       { 50, "tsc_xin", "audmscm_xin", 0, SIRFSOC_CLKC_LEAF_CLK_EN1_SET, 21, &leaf1_gate_lock },
+       { 51, "ioctop_io", "audmscm_io", 0, SIRFSOC_CLKC_LEAF_CLK_EN1_SET, 4, &leaf1_gate_lock },
+       { 52, "rsc_io", "audmscm_io", 0, SIRFSOC_CLKC_LEAF_CLK_EN1_SET, 5, &leaf1_gate_lock },
+       { 53, "dvm_io", "audmscm_io", 0, SIRFSOC_CLKC_LEAF_CLK_EN1_SET, 6, &leaf1_gate_lock },
+       { 54, "lvds_xin", "audmscm_xin", 0, SIRFSOC_CLKC_LEAF_CLK_EN1_SET, 7, &leaf1_gate_lock },
+       { 55, "kas_kas", "audmscm_kas", 0, SIRFSOC_CLKC_LEAF_CLK_EN1_SET, 8, &leaf1_gate_lock },
+       { 56, "ac97_kas", "audmscm_kas", 0, SIRFSOC_CLKC_LEAF_CLK_EN1_SET, 9, &leaf1_gate_lock },
+       { 57, "usp0_kas", "audmscm_kas", 0, SIRFSOC_CLKC_LEAF_CLK_EN1_SET, 10, &leaf1_gate_lock },
+       { 58, "usp1_kas", "audmscm_kas", 0, SIRFSOC_CLKC_LEAF_CLK_EN1_SET, 11, &leaf1_gate_lock },
+       { 59, "usp2_kas", "audmscm_kas", 0, SIRFSOC_CLKC_LEAF_CLK_EN1_SET, 12, &leaf1_gate_lock },
+       { 60, "dmac2_kas", "audmscm_kas", 0, SIRFSOC_CLKC_LEAF_CLK_EN1_SET, 13, &leaf1_gate_lock },
+       { 61, "dmac3_kas", "audmscm_kas", 0, SIRFSOC_CLKC_LEAF_CLK_EN1_SET, 14, &leaf1_gate_lock },
+       { 62, "audioif_kas", "audmscm_kas", 0, SIRFSOC_CLKC_LEAF_CLK_EN1_SET, 15, &leaf1_gate_lock },
+       { 63, "i2s1_kas", "audmscm_kas", 0, SIRFSOC_CLKC_LEAF_CLK_EN1_SET, 17, &leaf1_gate_lock },
+       { 64, "thaudmscm_io", "audmscm_io", 0, SIRFSOC_CLKC_LEAF_CLK_EN1_SET, 22, &leaf1_gate_lock },
+       { 65, "analogtest_xin", "audmscm_xin", 0, SIRFSOC_CLKC_LEAF_CLK_EN1_SET, 23, &leaf1_gate_lock },
+       { 66, "sys2pci_io", "vdifm_io", 0, SIRFSOC_CLKC_LEAF_CLK_EN2_SET, 0, &leaf2_gate_lock },
+       { 67, "pciarb_io", "vdifm_io", 0, SIRFSOC_CLKC_LEAF_CLK_EN2_SET, 1, &leaf2_gate_lock },
+       { 68, "pcicopy_io", "vdifm_io", 0, SIRFSOC_CLKC_LEAF_CLK_EN2_SET, 2, &leaf2_gate_lock },
+       { 69, "rom_io", "vdifm_io", 0, SIRFSOC_CLKC_LEAF_CLK_EN2_SET, 3, &leaf2_gate_lock },
+       { 70, "sdio23_io", "vdifm_io", 0, SIRFSOC_CLKC_LEAF_CLK_EN2_SET, 4, &leaf2_gate_lock },
+       { 71, "sdio45_io", "vdifm_io", 0, SIRFSOC_CLKC_LEAF_CLK_EN2_SET, 5, &leaf2_gate_lock },
+       { 72, "sdio67_io", "vdifm_io", 0, SIRFSOC_CLKC_LEAF_CLK_EN2_SET, 6, &leaf2_gate_lock },
+       { 73, "vip1_io", "vdifm_io", 0, SIRFSOC_CLKC_LEAF_CLK_EN2_SET, 7, &leaf2_gate_lock },
+       { 74, "vip1_vip", "vdifm_vip", 0, SIRFSOC_CLKC_LEAF_CLK_EN2_SET, 16, &leaf2_gate_lock },
+       { 75, "sdio23_sdphy23", "vdifm_sdphy23", 0, SIRFSOC_CLKC_LEAF_CLK_EN2_SET, 8, &leaf2_gate_lock },
+       { 76, "sdio45_sdphy45", "vdifm_sdphy45", 0, SIRFSOC_CLKC_LEAF_CLK_EN2_SET, 9, &leaf2_gate_lock },
+       { 77, "sdio67_sdphy67", "vdifm_sdphy67", 0, SIRFSOC_CLKC_LEAF_CLK_EN2_SET, 10, &leaf2_gate_lock },
+       { 78, "vpp0_disp0", "vdifm_disp0", 0, SIRFSOC_CLKC_LEAF_CLK_EN2_SET, 11, &leaf2_gate_lock },
+       { 79, "lcd0_disp0", "vdifm_disp0", 0, SIRFSOC_CLKC_LEAF_CLK_EN2_SET, 12, &leaf2_gate_lock },
+       { 80, "vpp1_disp1", "vdifm_disp1", 0, SIRFSOC_CLKC_LEAF_CLK_EN2_SET, 13, &leaf2_gate_lock },
+       { 81, "lcd1_disp1", "vdifm_disp1", 0, SIRFSOC_CLKC_LEAF_CLK_EN2_SET, 14, &leaf2_gate_lock },
+       { 82, "dcu_deint", "vdifm_deint", 0, SIRFSOC_CLKC_LEAF_CLK_EN2_SET, 15, &leaf2_gate_lock },
+       { 83, "vdifm_dapa_r_nocr", "vdifm_nocr", 0, SIRFSOC_CLKC_LEAF_CLK_EN2_SET, 17, &leaf2_gate_lock },
+       { 84, "gpio1_io", "vdifm_io", 0, SIRFSOC_CLKC_LEAF_CLK_EN2_SET, 18, &leaf2_gate_lock },
+       { 85, "thvdifm_io", "vdifm_io", 0, SIRFSOC_CLKC_LEAF_CLK_EN2_SET, 19, &leaf2_gate_lock },
+       { 86, "gmac_rgmii", "gnssm_rgmii", 0, SIRFSOC_CLKC_LEAF_CLK_EN3_SET, 0, &leaf3_gate_lock },
+       { 87, "gmac_gmac", "gnssm_gmac", 0, SIRFSOC_CLKC_LEAF_CLK_EN3_SET, 1, &leaf3_gate_lock },
+       { 88, "uart1_io", "gnssm_io", 0, SIRFSOC_CLKC_LEAF_CLK_EN3_SET, 2, &leaf3_gate_lock },
+       { 89, "dmac0_io", "gnssm_io", 0, SIRFSOC_CLKC_LEAF_CLK_EN3_SET, 3, &leaf3_gate_lock },
+       { 90, "uart0_io", "gnssm_io", 0, SIRFSOC_CLKC_LEAF_CLK_EN3_SET, 4, &leaf3_gate_lock },
+       { 91, "uart2_io", "gnssm_io", 0, SIRFSOC_CLKC_LEAF_CLK_EN3_SET, 5, &leaf3_gate_lock },
+       { 92, "uart3_io", "gnssm_io", 0, SIRFSOC_CLKC_LEAF_CLK_EN3_SET, 6, &leaf3_gate_lock },
+       { 93, "uart4_io", "gnssm_io", 0, SIRFSOC_CLKC_LEAF_CLK_EN3_SET, 7, &leaf3_gate_lock },
+       { 94, "uart5_io", "gnssm_io", 0, SIRFSOC_CLKC_LEAF_CLK_EN3_SET, 8, &leaf3_gate_lock },
+       { 95, "spi1_io", "gnssm_io", 0, SIRFSOC_CLKC_LEAF_CLK_EN3_SET, 9, &leaf3_gate_lock },
+       { 96, "gnss_gnss", "gnssm_gnss", 0, SIRFSOC_CLKC_LEAF_CLK_EN3_SET, 10, &leaf3_gate_lock },
+       { 97, "canbus1_can", "gnssm_can", 0, SIRFSOC_CLKC_LEAF_CLK_EN3_SET, 12, &leaf3_gate_lock },
+       { 98, "ccsec_sec", "gnssm_sec", 0, SIRFSOC_CLKC_LEAF_CLK_EN3_SET, 15, &leaf3_gate_lock },
+       { 99,  "ccpub_sec", "gnssm_sec", 0, SIRFSOC_CLKC_LEAF_CLK_EN3_SET, 16, &leaf3_gate_lock },
+       { 100, "gnssm_dapa_r_nocr", "gnssm_nocr", 0, SIRFSOC_CLKC_LEAF_CLK_EN3_SET, 13, &leaf3_gate_lock },
+       { 101, "thgnssm_io", "gnssm_io", 0, SIRFSOC_CLKC_LEAF_CLK_EN3_SET, 14, &leaf3_gate_lock },
+       { 102, "media_vdec", "mediam_vdec", 0, SIRFSOC_CLKC_LEAF_CLK_EN4_SET, 0, &leaf4_gate_lock },
+       { 103, "media_jpenc", "mediam_jpenc", 0, SIRFSOC_CLKC_LEAF_CLK_EN4_SET, 1, &leaf4_gate_lock },
+       { 104, "g2d_g2d", "mediam_g2d", 0, SIRFSOC_CLKC_LEAF_CLK_EN4_SET, 2, &leaf4_gate_lock },
+       { 105, "i2c0_io", "mediam_io", 0, SIRFSOC_CLKC_LEAF_CLK_EN4_SET, 3, &leaf4_gate_lock },
+       { 106, "i2c1_io", "mediam_io", 0, SIRFSOC_CLKC_LEAF_CLK_EN4_SET, 4, &leaf4_gate_lock },
+       { 107, "gpio0_io", "mediam_io", 0, SIRFSOC_CLKC_LEAF_CLK_EN4_SET, 5, &leaf4_gate_lock },
+       { 108, "nand_io", "mediam_io", 0, SIRFSOC_CLKC_LEAF_CLK_EN4_SET, 6, &leaf4_gate_lock },
+       { 109, "sdio01_io", "mediam_io", 0, SIRFSOC_CLKC_LEAF_CLK_EN4_SET, 7, &leaf4_gate_lock },
+       { 110, "sys2pci2_io", "mediam_io", 0, SIRFSOC_CLKC_LEAF_CLK_EN4_SET, 8, &leaf4_gate_lock },
+       { 111, "sdio01_sdphy01", "mediam_sdphy01", 0, SIRFSOC_CLKC_LEAF_CLK_EN4_SET, 9, &leaf4_gate_lock },
+       { 112, "nand_nand", "mediam_nand", 0, SIRFSOC_CLKC_LEAF_CLK_EN4_SET, 10, &leaf4_gate_lock },
+       { 113, "usb0_usb", "mediam_usb", 0, SIRFSOC_CLKC_LEAF_CLK_EN4_SET, 11, &leaf4_gate_lock },
+       { 114, "usb1_usb", "mediam_usb", 0, SIRFSOC_CLKC_LEAF_CLK_EN4_SET, 12, &leaf4_gate_lock },
+       { 115, "usbphy0_usbphy", "mediam_usbphy", 0, SIRFSOC_CLKC_LEAF_CLK_EN4_SET, 13, &leaf4_gate_lock },
+       { 116, "usbphy1_usbphy", "mediam_usbphy", 0, SIRFSOC_CLKC_LEAF_CLK_EN4_SET, 14, &leaf4_gate_lock },
+       { 117, "thmediam_io", "mediam_io", 0, SIRFSOC_CLKC_LEAF_CLK_EN4_SET, 15, &leaf4_gate_lock },
+       { 118, "memc_mem", "mempll_clk1", CLK_IGNORE_UNUSED, SIRFSOC_CLKC_LEAF_CLK_EN5_SET, 0, &leaf5_gate_lock },
+       { 119, "dapa_mem", "mempll_clk1", 0, SIRFSOC_CLKC_LEAF_CLK_EN5_SET, 1, &leaf5_gate_lock },
+       { 120, "nocddrm_nocr", "ddrm_nocr", 0, SIRFSOC_CLKC_LEAF_CLK_EN5_SET, 2, &leaf5_gate_lock },
+       { 121, "thddrm_nocr", "ddrm_nocr", 0, SIRFSOC_CLKC_LEAF_CLK_EN5_SET, 3, &leaf5_gate_lock },
+       { 122, "spram1_cpudiv2", "cpum_cpu", 0, SIRFSOC_CLKC_LEAF_CLK_EN6_SET, 0, &leaf6_gate_lock },
+       { 123, "spram2_cpudiv2", "cpum_cpu", 0, SIRFSOC_CLKC_LEAF_CLK_EN6_SET, 1, &leaf6_gate_lock },
+       { 124, "coresight_cpudiv2", "cpum_cpu", 0, SIRFSOC_CLKC_LEAF_CLK_EN6_SET, 2, &leaf6_gate_lock },
+       { 125, "thcpum_cpudiv4", "cpum_cpu", 0, SIRFSOC_CLKC_LEAF_CLK_EN6_SET, 3, &leaf6_gate_lock },
+       { 126, "graphic_gpu", "gpum_gpu", 0, SIRFSOC_CLKC_LEAF_CLK_EN7_SET, 0, &leaf7_gate_lock },
+       { 127, "vss_sdr", "gpum_sdr", 0, SIRFSOC_CLKC_LEAF_CLK_EN7_SET, 1, &leaf7_gate_lock },
+       { 128, "thgpum_nocr", "gpum_nocr", 0, SIRFSOC_CLKC_LEAF_CLK_EN7_SET, 2, &leaf7_gate_lock },
+       { 129, "a7ca_btss", "btm_btss", 0, SIRFSOC_CLKC_LEAF_CLK_EN8_SET, 1, &leaf8_gate_lock },
+       { 130, "dmac4_io", "btm_io", 0, SIRFSOC_CLKC_LEAF_CLK_EN8_SET, 2, &leaf8_gate_lock },
+       { 131, "uart6_io", "btm_io", 0, SIRFSOC_CLKC_LEAF_CLK_EN8_SET, 3, &leaf8_gate_lock },
+       { 132, "usp3_io", "btm_io", 0, SIRFSOC_CLKC_LEAF_CLK_EN8_SET, 4, &leaf8_gate_lock },
+       { 133, "a7ca_io", "btm_io", 0, SIRFSOC_CLKC_LEAF_CLK_EN8_SET, 5, &leaf8_gate_lock },
+       { 134, "noc_btm_io", "btm_io", 0, SIRFSOC_CLKC_LEAF_CLK_EN8_SET, 6, &leaf8_gate_lock },
+       { 135, "thbtm_io", "btm_io", 0, SIRFSOC_CLKC_LEAF_CLK_EN8_SET, 7, &leaf8_gate_lock },
+       { 136, "btslow", "xinw_fixdiv_btslow", 0, SIRFSOC_CLKC_ROOT_CLK_EN1_SET, 25, &root1_gate_lock },
+       { 137, "a7ca_btslow", "btslow", 0, SIRFSOC_CLKC_LEAF_CLK_EN8_SET, 0, &leaf8_gate_lock },
+};
+
+static struct clk *atlas7_clks[ARRAY_SIZE(unit_list)];
+
+static int unit_clk_is_enabled(struct clk_hw *hw)
+{
+       struct clk_unit *clk = to_unitclk(hw);
+       u32 reg;
+
+       reg = clk->regofs + SIRFSOC_CLKC_ROOT_CLK_EN0_STAT - SIRFSOC_CLKC_ROOT_CLK_EN0_SET;
+
+       return !!(clkc_readl(reg) & BIT(clk->bit));
+}
+
+static int unit_clk_enable(struct clk_hw *hw)
+{
+       u32 reg;
+       struct clk_unit *clk = to_unitclk(hw);
+       unsigned long flags;
+
+       reg = clk->regofs;
+
+       spin_lock_irqsave(clk->lock, flags);
+       clkc_writel(BIT(clk->bit), reg);
+       spin_unlock_irqrestore(clk->lock, flags);
+       return 0;
+}
+
+static void unit_clk_disable(struct clk_hw *hw)
+{
+       u32  reg;
+       struct clk_unit *clk = to_unitclk(hw);
+       unsigned long flags;
+
+       reg = clk->regofs + SIRFSOC_CLKC_ROOT_CLK_EN0_CLR - SIRFSOC_CLKC_ROOT_CLK_EN0_SET;
+
+       spin_lock_irqsave(clk->lock, flags);
+       clkc_writel(BIT(clk->bit), reg);
+       spin_unlock_irqrestore(clk->lock, flags);
+}
+
+static const struct clk_ops unit_clk_ops = {
+       .is_enabled = unit_clk_is_enabled,
+       .enable = unit_clk_enable,
+       .disable = unit_clk_disable,
+};
+
+static struct clk * __init
+atlas7_unit_clk_register(struct device *dev, const char *name,
+                const char * const parent_name, unsigned long flags,
+                u32 regofs, u8 bit, spinlock_t *lock)
+{
+       struct clk *clk;
+       struct clk_unit *unit;
+       struct clk_init_data init;
+
+       unit = kzalloc(sizeof(*unit), GFP_KERNEL);
+       if (!unit)
+               return ERR_PTR(-ENOMEM);
+
+       init.name = name;
+       init.parent_names = &parent_name;
+       init.num_parents = 1;
+       init.ops = &unit_clk_ops;
+       init.flags = flags;
+
+       unit->hw.init = &init;
+       unit->regofs = regofs;
+       unit->bit = bit;
+       unit->lock = lock;
+
+       clk = clk_register(dev, &unit->hw);
+       if (IS_ERR(clk))
+               kfree(unit);
+
+       return clk;
+}
+
+static struct atlas7_reset_desc atlas7_reset_unit[] = {
+       { "PWM", 0x0244, 0, 0x0320, 0, &leaf0_gate_lock }, /* 0-5 */
+       { "THCGUM", 0x0244, 3, 0x0320, 1, &leaf0_gate_lock },
+       { "CVD", 0x04A0, 0, 0x032C, 0, &leaf1_gate_lock },
+       { "TIMER", 0x04A0, 1, 0x032C, 1, &leaf1_gate_lock },
+       { "PULSEC", 0x04A0, 2, 0x032C, 2, &leaf1_gate_lock },
+       { "TSC", 0x04A0, 3, 0x032C, 3, &leaf1_gate_lock },
+       { "IOCTOP", 0x04A0, 4, 0x032C, 4, &leaf1_gate_lock }, /* 6-10 */
+       { "RSC", 0x04A0, 5, 0x032C, 5, &leaf1_gate_lock },
+       { "DVM", 0x04A0, 6, 0x032C, 6, &leaf1_gate_lock },
+       { "LVDS", 0x04A0, 7, 0x032C, 7, &leaf1_gate_lock },
+       { "KAS", 0x04A0, 8, 0x032C, 8, &leaf1_gate_lock },
+       { "AC97", 0x04A0, 9, 0x032C, 9, &leaf1_gate_lock }, /* 11-15 */
+       { "USP0", 0x04A0, 10, 0x032C, 10, &leaf1_gate_lock },
+       { "USP1", 0x04A0, 11, 0x032C, 11, &leaf1_gate_lock },
+       { "USP2", 0x04A0, 12, 0x032C, 12, &leaf1_gate_lock },
+       { "DMAC2", 0x04A0, 13, 0x032C, 13, &leaf1_gate_lock },
+       { "DMAC3", 0x04A0, 14, 0x032C, 14, &leaf1_gate_lock }, /* 16-20 */
+       { "AUDIO", 0x04A0, 15, 0x032C, 15, &leaf1_gate_lock },
+       { "I2S1", 0x04A0, 17, 0x032C, 16, &leaf1_gate_lock },
+       { "PMU_AUDIO", 0x04A0, 22, 0x032C, 17, &leaf1_gate_lock },
+       { "THAUDMSCM", 0x04A0, 23, 0x032C, 18, &leaf1_gate_lock },
+       { "SYS2PCI", 0x04B8, 0, 0x0338, 0, &leaf2_gate_lock }, /* 21-25 */
+       { "PCIARB", 0x04B8, 1, 0x0338, 1, &leaf2_gate_lock },
+       { "PCICOPY", 0x04B8, 2, 0x0338, 2, &leaf2_gate_lock },
+       { "ROM", 0x04B8, 3, 0x0338, 3, &leaf2_gate_lock },
+       { "SDIO23", 0x04B8, 4, 0x0338, 4, &leaf2_gate_lock },
+       { "SDIO45", 0x04B8, 5, 0x0338, 5, &leaf2_gate_lock }, /* 26-30 */
+       { "SDIO67", 0x04B8, 6, 0x0338, 6, &leaf2_gate_lock },
+       { "VIP1", 0x04B8, 7, 0x0338, 7, &leaf2_gate_lock },
+       { "VPP0", 0x04B8, 11, 0x0338, 8, &leaf2_gate_lock },
+       { "LCD0", 0x04B8, 12, 0x0338, 9, &leaf2_gate_lock },
+       { "VPP1", 0x04B8, 13, 0x0338, 10, &leaf2_gate_lock }, /* 31-35 */
+       { "LCD1", 0x04B8, 14, 0x0338, 11, &leaf2_gate_lock },
+       { "DCU", 0x04B8, 15, 0x0338, 12, &leaf2_gate_lock },
+       { "GPIO", 0x04B8, 18, 0x0338, 13, &leaf2_gate_lock },
+       { "DAPA_VDIFM", 0x04B8, 17, 0x0338, 15, &leaf2_gate_lock },
+       { "THVDIFM", 0x04B8, 19, 0x0338, 16, &leaf2_gate_lock }, /* 36-40 */
+       { "RGMII", 0x04D0, 0, 0x0344, 0, &leaf3_gate_lock },
+       { "GMAC", 0x04D0, 1, 0x0344, 1, &leaf3_gate_lock },
+       { "UART1", 0x04D0, 2, 0x0344, 2, &leaf3_gate_lock },
+       { "DMAC0", 0x04D0, 3, 0x0344, 3, &leaf3_gate_lock },
+       { "UART0", 0x04D0, 4, 0x0344, 4, &leaf3_gate_lock }, /* 41-45 */
+       { "UART2", 0x04D0, 5, 0x0344, 5, &leaf3_gate_lock },
+       { "UART3", 0x04D0, 6, 0x0344, 6, &leaf3_gate_lock },
+       { "UART4", 0x04D0, 7, 0x0344, 7, &leaf3_gate_lock },
+       { "UART5", 0x04D0, 8, 0x0344, 8, &leaf3_gate_lock },
+       { "SPI1", 0x04D0, 9, 0x0344, 9, &leaf3_gate_lock }, /* 46-50 */
+       { "GNSS_SYS_M0", 0x04D0, 10, 0x0344, 10, &leaf3_gate_lock },
+       { "CANBUS1", 0x04D0, 12, 0x0344, 11, &leaf3_gate_lock },
+       { "CCSEC", 0x04D0, 15, 0x0344, 12, &leaf3_gate_lock },
+       { "CCPUB", 0x04D0, 16, 0x0344, 13, &leaf3_gate_lock },
+       { "DAPA_GNSSM", 0x04D0, 13, 0x0344, 14, &leaf3_gate_lock }, /* 51-55 */
+       { "THGNSSM", 0x04D0, 14, 0x0344, 15, &leaf3_gate_lock },
+       { "VDEC", 0x04E8, 0, 0x0350, 0, &leaf4_gate_lock },
+       { "JPENC", 0x04E8, 1, 0x0350, 1, &leaf4_gate_lock },
+       { "G2D", 0x04E8, 2, 0x0350, 2, &leaf4_gate_lock },
+       { "I2C0", 0x04E8, 3, 0x0350, 3, &leaf4_gate_lock }, /* 56-60 */
+       { "I2C1", 0x04E8, 4, 0x0350, 4, &leaf4_gate_lock },
+       { "GPIO0", 0x04E8, 5, 0x0350, 5, &leaf4_gate_lock },
+       { "NAND", 0x04E8, 6, 0x0350, 6, &leaf4_gate_lock },
+       { "SDIO01", 0x04E8, 7, 0x0350, 7, &leaf4_gate_lock },
+       { "SYS2PCI2", 0x04E8, 8, 0x0350, 8, &leaf4_gate_lock }, /* 61-65 */
+       { "USB0", 0x04E8, 11, 0x0350, 9, &leaf4_gate_lock },
+       { "USB1", 0x04E8, 12, 0x0350, 10, &leaf4_gate_lock },
+       { "THMEDIAM", 0x04E8, 15, 0x0350, 11, &leaf4_gate_lock },
+       { "MEMC_DDRPHY", 0x0500, 0, 0x035C, 0, &leaf5_gate_lock },
+       { "MEMC_UPCTL", 0x0500, 0, 0x035C, 1, &leaf5_gate_lock }, /* 66-70 */
+       { "DAPA_MEM", 0x0500, 1, 0x035C, 2, &leaf5_gate_lock },
+       { "MEMC_MEMDIV", 0x0500, 0, 0x035C, 3, &leaf5_gate_lock },
+       { "THDDRM", 0x0500, 3, 0x035C, 4, &leaf5_gate_lock },
+       { "CORESIGHT", 0x0518, 3, 0x0368, 13, &leaf6_gate_lock },
+       { "THCPUM", 0x0518, 4, 0x0368, 17, &leaf6_gate_lock }, /* 71-75 */
+       { "GRAPHIC", 0x0530, 0, 0x0374, 0, &leaf7_gate_lock },
+       { "VSS_SDR", 0x0530, 1, 0x0374, 1, &leaf7_gate_lock },
+       { "THGPUM", 0x0530, 2, 0x0374, 2, &leaf7_gate_lock },
+       { "DMAC4", 0x0548, 2, 0x0380, 1, &leaf8_gate_lock },
+       { "UART6", 0x0548, 3, 0x0380, 2, &leaf8_gate_lock }, /* 76- */
+       { "USP3", 0x0548, 4, 0x0380, 3, &leaf8_gate_lock },
+       { "THBTM", 0x0548, 5, 0x0380, 5, &leaf8_gate_lock },
+       { "A7CA", 0x0548, 1, 0x0380, 0, &leaf8_gate_lock },
+       { "A7CA_APB", 0x0548, 5, 0x0380, 4, &leaf8_gate_lock },
+};
+
+static int atlas7_reset_module(struct reset_controller_dev *rcdev,
+                                       unsigned long reset_idx)
+{
+       struct atlas7_reset_desc *reset = &atlas7_reset_unit[reset_idx];
+       unsigned long flags;
+
+       /*
+        * HW suggest unit reset sequence:
+        * assert sw reset (0)
+        * setting sw clk_en to if the clock was disabled before reset
+        * delay 16 clocks
+        * disable clock (sw clk_en = 0)
+        * de-assert reset (1)
+        * after this sequence, restore clock or not is decided by SW
+        */
+
+       spin_lock_irqsave(reset->lock, flags);
+       /* clock enable or not */
+       if (clkc_readl(reset->clk_ofs + 8) & (1 << reset->clk_bit)) {
+               clkc_writel(1 << reset->rst_bit, reset->rst_ofs + 4);
+               udelay(2);
+               clkc_writel(1 << reset->clk_bit, reset->clk_ofs + 4);
+               clkc_writel(1 << reset->rst_bit, reset->rst_ofs);
+               /* restore clock enable */
+               clkc_writel(1 << reset->clk_bit, reset->clk_ofs);
+       } else {
+               clkc_writel(1 << reset->rst_bit, reset->rst_ofs + 4);
+               clkc_writel(1 << reset->clk_bit, reset->clk_ofs);
+               udelay(2);
+               clkc_writel(1 << reset->clk_bit, reset->clk_ofs + 4);
+               clkc_writel(1 << reset->rst_bit, reset->rst_ofs);
+       }
+       spin_unlock_irqrestore(reset->lock, flags);
+
+       return 0;
+}
+
+static struct reset_control_ops atlas7_rst_ops = {
+       .reset = atlas7_reset_module,
+};
+
+static struct reset_controller_dev atlas7_rst_ctlr = {
+       .ops = &atlas7_rst_ops,
+       .owner = THIS_MODULE,
+       .of_reset_n_cells = 1,
+};
+
+static void __init atlas7_clk_init(struct device_node *np)
+{
+       struct clk *clk;
+       struct atlas7_div_init_data *div;
+       struct atlas7_mux_init_data *mux;
+       struct atlas7_unit_init_data *unit;
+       int i;
+       int ret;
+
+       sirfsoc_clk_vbase = of_iomap(np, 0);
+       if (!sirfsoc_clk_vbase)
+               panic("unable to map clkc registers\n");
+
+       of_node_put(np);
+
+       clk = clk_register(NULL, &clk_cpupll.hw);
+       BUG_ON(!clk);
+       clk = clk_register(NULL, &clk_mempll.hw);
+       BUG_ON(!clk);
+       clk = clk_register(NULL, &clk_sys0pll.hw);
+       BUG_ON(!clk);
+       clk = clk_register(NULL, &clk_sys1pll.hw);
+       BUG_ON(!clk);
+       clk = clk_register(NULL, &clk_sys2pll.hw);
+       BUG_ON(!clk);
+       clk = clk_register(NULL, &clk_sys3pll.hw);
+       BUG_ON(!clk);
+
+       clk = clk_register_divider_table(NULL, "cpupll_div1", "cpupll_vco", 0,
+                        sirfsoc_clk_vbase + SIRFSOC_CLKC_CPUPLL_AB_CTRL1, 0, 3, 0,
+                        pll_div_table, &cpupll_ctrl1_lock);
+       BUG_ON(!clk);
+       clk = clk_register_divider_table(NULL, "cpupll_div2", "cpupll_vco", 0,
+                        sirfsoc_clk_vbase + SIRFSOC_CLKC_CPUPLL_AB_CTRL1, 4, 3, 0,
+                        pll_div_table, &cpupll_ctrl1_lock);
+       BUG_ON(!clk);
+       clk = clk_register_divider_table(NULL, "cpupll_div3", "cpupll_vco", 0,
+                        sirfsoc_clk_vbase + SIRFSOC_CLKC_CPUPLL_AB_CTRL1, 8, 3, 0,
+                        pll_div_table, &cpupll_ctrl1_lock);
+       BUG_ON(!clk);
+
+       clk = clk_register_divider_table(NULL, "mempll_div1", "mempll_vco", 0,
+                        sirfsoc_clk_vbase + SIRFSOC_CLKC_MEMPLL_AB_CTRL1, 0, 3, 0,
+                        pll_div_table, &mempll_ctrl1_lock);
+       BUG_ON(!clk);
+       clk = clk_register_divider_table(NULL, "mempll_div2", "mempll_vco", 0,
+                        sirfsoc_clk_vbase + SIRFSOC_CLKC_MEMPLL_AB_CTRL1, 4, 3, 0,
+                        pll_div_table, &mempll_ctrl1_lock);
+       BUG_ON(!clk);
+       clk = clk_register_divider_table(NULL, "mempll_div3", "mempll_vco", 0,
+                        sirfsoc_clk_vbase + SIRFSOC_CLKC_MEMPLL_AB_CTRL1, 8, 3, 0,
+                        pll_div_table, &mempll_ctrl1_lock);
+       BUG_ON(!clk);
+
+       clk = clk_register_divider_table(NULL, "sys0pll_div1", "sys0pll_vco", 0,
+                        sirfsoc_clk_vbase + SIRFSOC_CLKC_SYS0PLL_AB_CTRL1, 0, 3, 0,
+                        pll_div_table, &sys0pll_ctrl1_lock);
+       BUG_ON(!clk);
+       clk = clk_register_divider_table(NULL, "sys0pll_div2", "sys0pll_vco", 0,
+                        sirfsoc_clk_vbase + SIRFSOC_CLKC_SYS0PLL_AB_CTRL1, 4, 3, 0,
+                        pll_div_table, &sys0pll_ctrl1_lock);
+       BUG_ON(!clk);
+       clk = clk_register_divider_table(NULL, "sys0pll_div3", "sys0pll_vco", 0,
+                        sirfsoc_clk_vbase + SIRFSOC_CLKC_SYS0PLL_AB_CTRL1, 8, 3, 0,
+                        pll_div_table, &sys0pll_ctrl1_lock);
+       BUG_ON(!clk);
+       clk = clk_register_fixed_factor(NULL, "sys0pll_fixdiv", "sys0pll_vco",
+                                       CLK_SET_RATE_PARENT, 1, 2);
+
+       clk = clk_register_divider_table(NULL, "sys1pll_div1", "sys1pll_vco", 0,
+                        sirfsoc_clk_vbase + SIRFSOC_CLKC_SYS1PLL_AB_CTRL1, 0, 3, 0,
+                        pll_div_table, &sys1pll_ctrl1_lock);
+       BUG_ON(!clk);
+       clk = clk_register_divider_table(NULL, "sys1pll_div2", "sys1pll_vco", 0,
+                        sirfsoc_clk_vbase + SIRFSOC_CLKC_SYS1PLL_AB_CTRL1, 4, 3, 0,
+                        pll_div_table, &sys1pll_ctrl1_lock);
+       BUG_ON(!clk);
+       clk = clk_register_divider_table(NULL, "sys1pll_div3", "sys1pll_vco", 0,
+                        sirfsoc_clk_vbase + SIRFSOC_CLKC_SYS1PLL_AB_CTRL1, 8, 3, 0,
+                        pll_div_table, &sys1pll_ctrl1_lock);
+       BUG_ON(!clk);
+       clk = clk_register_fixed_factor(NULL, "sys1pll_fixdiv", "sys1pll_vco",
+                                       CLK_SET_RATE_PARENT, 1, 2);
+
+       clk = clk_register_divider_table(NULL, "sys2pll_div1", "sys2pll_vco", 0,
+                        sirfsoc_clk_vbase + SIRFSOC_CLKC_SYS2PLL_AB_CTRL1, 0, 3, 0,
+                        pll_div_table, &sys2pll_ctrl1_lock);
+       BUG_ON(!clk);
+       clk = clk_register_divider_table(NULL, "sys2pll_div2", "sys2pll_vco", 0,
+                        sirfsoc_clk_vbase + SIRFSOC_CLKC_SYS2PLL_AB_CTRL1, 4, 3, 0,
+                        pll_div_table, &sys2pll_ctrl1_lock);
+       BUG_ON(!clk);
+       clk = clk_register_divider_table(NULL, "sys2pll_div3", "sys2pll_vco", 0,
+                        sirfsoc_clk_vbase + SIRFSOC_CLKC_SYS2PLL_AB_CTRL1, 8, 3, 0,
+                        pll_div_table, &sys2pll_ctrl1_lock);
+       BUG_ON(!clk);
+       clk = clk_register_fixed_factor(NULL, "sys2pll_fixdiv", "sys2pll_vco",
+                                       CLK_SET_RATE_PARENT, 1, 2);
+
+       clk = clk_register_divider_table(NULL, "sys3pll_div1", "sys3pll_vco", 0,
+                        sirfsoc_clk_vbase + SIRFSOC_CLKC_SYS3PLL_AB_CTRL1, 0, 3, 0,
+                        pll_div_table, &sys3pll_ctrl1_lock);
+       BUG_ON(!clk);
+       clk = clk_register_divider_table(NULL, "sys3pll_div2", "sys3pll_vco", 0,
+                        sirfsoc_clk_vbase + SIRFSOC_CLKC_SYS3PLL_AB_CTRL1, 4, 3, 0,
+                        pll_div_table, &sys3pll_ctrl1_lock);
+       BUG_ON(!clk);
+       clk = clk_register_divider_table(NULL, "sys3pll_div3", "sys3pll_vco", 0,
+                        sirfsoc_clk_vbase + SIRFSOC_CLKC_SYS3PLL_AB_CTRL1, 8, 3, 0,
+                        pll_div_table, &sys3pll_ctrl1_lock);
+       BUG_ON(!clk);
+       clk = clk_register_fixed_factor(NULL, "sys3pll_fixdiv", "sys3pll_vco",
+                                       CLK_SET_RATE_PARENT, 1, 2);
+
+       BUG_ON(!clk);
+       clk = clk_register_fixed_factor(NULL, "xinw_fixdiv_btslow", "xinw",
+                                       CLK_SET_RATE_PARENT, 1, 4);
+
+       BUG_ON(!clk);
+       clk = clk_register_gate(NULL, "cpupll_clk1", "cpupll_div1",
+               CLK_SET_RATE_PARENT, sirfsoc_clk_vbase + SIRFSOC_CLKC_CPUPLL_AB_CTRL1,
+                               12, 0, &cpupll_ctrl1_lock);
+       BUG_ON(!clk);
+       clk = clk_register_gate(NULL, "cpupll_clk2", "cpupll_div2",
+               CLK_SET_RATE_PARENT, sirfsoc_clk_vbase + SIRFSOC_CLKC_CPUPLL_AB_CTRL1,
+                               13, 0, &cpupll_ctrl1_lock);
+       BUG_ON(!clk);
+       clk = clk_register_gate(NULL, "cpupll_clk3", "cpupll_div3",
+               CLK_SET_RATE_PARENT, sirfsoc_clk_vbase + SIRFSOC_CLKC_CPUPLL_AB_CTRL1,
+                               14, 0, &cpupll_ctrl1_lock);
+       BUG_ON(!clk);
+
+       clk = clk_register_gate(NULL, "mempll_clk1", "mempll_div1",
+               CLK_SET_RATE_PARENT | CLK_IGNORE_UNUSED,
+               sirfsoc_clk_vbase + SIRFSOC_CLKC_MEMPLL_AB_CTRL1,
+               12, 0, &mempll_ctrl1_lock);
+       BUG_ON(!clk);
+       clk = clk_register_gate(NULL, "mempll_clk2", "mempll_div2",
+               CLK_SET_RATE_PARENT, sirfsoc_clk_vbase + SIRFSOC_CLKC_MEMPLL_AB_CTRL1,
+                               13, 0, &mempll_ctrl1_lock);
+       BUG_ON(!clk);
+       clk = clk_register_gate(NULL, "mempll_clk3", "mempll_div3",
+               CLK_SET_RATE_PARENT, sirfsoc_clk_vbase + SIRFSOC_CLKC_MEMPLL_AB_CTRL1,
+                               14, 0, &mempll_ctrl1_lock);
+       BUG_ON(!clk);
+
+       clk = clk_register_gate(NULL, "sys0pll_clk1", "sys0pll_div1",
+               CLK_SET_RATE_PARENT, sirfsoc_clk_vbase + SIRFSOC_CLKC_SYS0PLL_AB_CTRL1,
+                               12, 0, &sys0pll_ctrl1_lock);
+       BUG_ON(!clk);
+       clk = clk_register_gate(NULL, "sys0pll_clk2", "sys0pll_div2",
+               CLK_SET_RATE_PARENT, sirfsoc_clk_vbase + SIRFSOC_CLKC_SYS0PLL_AB_CTRL1,
+                               13, 0, &sys0pll_ctrl1_lock);
+       BUG_ON(!clk);
+       clk = clk_register_gate(NULL, "sys0pll_clk3", "sys0pll_div3",
+               CLK_SET_RATE_PARENT, sirfsoc_clk_vbase + SIRFSOC_CLKC_SYS0PLL_AB_CTRL1,
+                               14, 0, &sys0pll_ctrl1_lock);
+       BUG_ON(!clk);
+
+       clk = clk_register_gate(NULL, "sys1pll_clk1", "sys1pll_div1",
+               CLK_SET_RATE_PARENT, sirfsoc_clk_vbase + SIRFSOC_CLKC_SYS1PLL_AB_CTRL1,
+                               12, 0, &sys1pll_ctrl1_lock);
+       BUG_ON(!clk);
+       clk = clk_register_gate(NULL, "sys1pll_clk2", "sys1pll_div2",
+               CLK_SET_RATE_PARENT, sirfsoc_clk_vbase + SIRFSOC_CLKC_SYS1PLL_AB_CTRL1,
+                               13, 0, &sys1pll_ctrl1_lock);
+       BUG_ON(!clk);
+       clk = clk_register_gate(NULL, "sys1pll_clk3", "sys1pll_div3",
+               CLK_SET_RATE_PARENT, sirfsoc_clk_vbase + SIRFSOC_CLKC_SYS1PLL_AB_CTRL1,
+                               14, 0, &sys1pll_ctrl1_lock);
+       BUG_ON(!clk);
+
+       clk = clk_register_gate(NULL, "sys2pll_clk1", "sys2pll_div1",
+               CLK_SET_RATE_PARENT, sirfsoc_clk_vbase + SIRFSOC_CLKC_SYS2PLL_AB_CTRL1,
+                               12, 0, &sys2pll_ctrl1_lock);
+       BUG_ON(!clk);
+       clk = clk_register_gate(NULL, "sys2pll_clk2", "sys2pll_div2",
+               CLK_SET_RATE_PARENT, sirfsoc_clk_vbase + SIRFSOC_CLKC_SYS2PLL_AB_CTRL1,
+                               13, 0, &sys2pll_ctrl1_lock);
+       BUG_ON(!clk);
+       clk = clk_register_gate(NULL, "sys2pll_clk3", "sys2pll_div3",
+               CLK_SET_RATE_PARENT, sirfsoc_clk_vbase + SIRFSOC_CLKC_SYS2PLL_AB_CTRL1,
+                               14, 0, &sys2pll_ctrl1_lock);
+       BUG_ON(!clk);
+
+       clk = clk_register_gate(NULL, "sys3pll_clk1", "sys3pll_div1",
+               CLK_SET_RATE_PARENT, sirfsoc_clk_vbase + SIRFSOC_CLKC_SYS3PLL_AB_CTRL1,
+                               12, 0, &sys3pll_ctrl1_lock);
+       BUG_ON(!clk);
+       clk = clk_register_gate(NULL, "sys3pll_clk2", "sys3pll_div2",
+               CLK_SET_RATE_PARENT, sirfsoc_clk_vbase + SIRFSOC_CLKC_SYS3PLL_AB_CTRL1,
+                               13, 0, &sys3pll_ctrl1_lock);
+       BUG_ON(!clk);
+       clk = clk_register_gate(NULL, "sys3pll_clk3", "sys3pll_div3",
+               CLK_SET_RATE_PARENT, sirfsoc_clk_vbase + SIRFSOC_CLKC_SYS3PLL_AB_CTRL1,
+                               14, 0, &sys3pll_ctrl1_lock);
+       BUG_ON(!clk);
+
+       clk = clk_register(NULL, &clk_audio_dto.hw);
+       BUG_ON(!clk);
+
+       clk = clk_register(NULL, &clk_disp0_dto.hw);
+       BUG_ON(!clk);
+
+       clk = clk_register(NULL, &clk_disp1_dto.hw);
+       BUG_ON(!clk);
+
+       for (i = 0; i < ARRAY_SIZE(divider_list); i++) {
+               div = &divider_list[i];
+               clk = clk_register_divider(NULL, div->div_name,
+                       div->parent_name, div->divider_flags, sirfsoc_clk_vbase + div->div_offset,
+                       div->shift, div->width, 0, div->lock);
+               BUG_ON(!clk);
+               clk = clk_register_gate(NULL, div->gate_name, div->div_name,
+                       div->gate_flags, sirfsoc_clk_vbase + div->gate_offset,
+                               div->gate_bit, 0, div->lock);
+               BUG_ON(!clk);
+       }
+       /* ignore selector status register check */
+       for (i = 0; i < ARRAY_SIZE(mux_list); i++) {
+               mux = &mux_list[i];
+               clk = clk_register_mux(NULL, mux->mux_name, mux->parent_names,
+                              mux->parent_num, mux->flags,
+                              sirfsoc_clk_vbase + mux->mux_offset,
+                              mux->shift, mux->width,
+                              mux->mux_flags, NULL);
+               BUG_ON(!clk);
+       }
+
+       for (i = 0; i < ARRAY_SIZE(unit_list); i++) {
+               unit = &unit_list[i];
+               atlas7_clks[i] = atlas7_unit_clk_register(NULL, unit->unit_name, unit->parent_name,
+                               unit->flags, unit->regofs, unit->bit, unit->lock);
+               BUG_ON(!atlas7_clks[i]);
+       }
+
+       clk_data.clks = atlas7_clks;
+       clk_data.clk_num = ARRAY_SIZE(unit_list);
+
+       ret = of_clk_add_provider(np, of_clk_src_onecell_get, &clk_data);
+       BUG_ON(ret);
+
+       atlas7_rst_ctlr.of_node = np;
+       atlas7_rst_ctlr.nr_resets = ARRAY_SIZE(atlas7_reset_unit);
+       reset_controller_register(&atlas7_rst_ctlr);
+}
+CLK_OF_DECLARE(atlas7_clk, "sirf,atlas7-car", atlas7_clk_init);
index 37af51c5f213bb496c2dce74ba975cbc4227a22f..9fc285d784d3faa4b78eac774cc466b989b8d667 100644 (file)
@@ -10,8 +10,8 @@
 #define KHZ     1000
 #define MHZ     (KHZ * KHZ)
 
-static void *sirfsoc_clk_vbase;
-static void *sirfsoc_rsc_vbase;
+static void __iomem *sirfsoc_clk_vbase;
+static void __iomem *sirfsoc_rsc_vbase;
 static struct clk_onecell_data clk_data;
 
 /*
@@ -188,7 +188,7 @@ static struct clk_ops std_pll_ops = {
        .set_rate = pll_clk_set_rate,
 };
 
-static const char *pll_clk_parents[] = {
+static const char * const pll_clk_parents[] = {
        "osc",
 };
 
@@ -284,7 +284,7 @@ static struct clk_hw usb_pll_clk_hw = {
  * clock domains - cpu, mem, sys/io, dsp, gfx
  */
 
-static const char *dmn_clk_parents[] = {
+static const char * const dmn_clk_parents[] = {
        "rtc",
        "osc",
        "pll1",
@@ -673,7 +673,7 @@ static void std_clk_disable(struct clk_hw *hw)
        clkc_writel(val, reg);
 }
 
-static const char *std_clk_io_parents[] = {
+static const char * const std_clk_io_parents[] = {
        "io",
 };
 
@@ -949,7 +949,7 @@ static struct clk_std clk_pulse = {
        },
 };
 
-static const char *std_clk_dsp_parents[] = {
+static const char * const std_clk_dsp_parents[] = {
        "dsp",
 };
 
@@ -981,7 +981,7 @@ static struct clk_std clk_mf = {
        },
 };
 
-static const char *std_clk_sys_parents[] = {
+static const char * const std_clk_sys_parents[] = {
        "sys",
 };
 
@@ -999,7 +999,7 @@ static struct clk_std clk_security = {
        },
 };
 
-static const char *std_clk_usb_parents[] = {
+static const char * const std_clk_usb_parents[] = {
        "usb_pll",
 };
 
index 7e2d15a0c7b8aec7c28e9074727c76406abc6918..d8bb239753a4747261c9ead8f8eb57cf68459e5e 100644 (file)
@@ -2,3 +2,4 @@ obj-y += clk.o
 obj-y += clk-gate.o
 obj-y += clk-pll.o
 obj-y += clk-periph.o
+obj-y += clk-pll-a10.o clk-periph-a10.o clk-gate-a10.o
diff --git a/drivers/clk/socfpga/clk-gate-a10.c b/drivers/clk/socfpga/clk-gate-a10.c
new file mode 100644 (file)
index 0000000..83c6780
--- /dev/null
@@ -0,0 +1,190 @@
+/*
+ * Copyright (C) 2015 Altera Corporation. All rights reserved
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+#include <linux/clk-provider.h>
+#include <linux/io.h>
+#include <linux/mfd/syscon.h>
+#include <linux/of.h>
+#include <linux/regmap.h>
+
+#include "clk.h"
+
+#define streq(a, b) (strcmp((a), (b)) == 0)
+
+#define to_socfpga_gate_clk(p) container_of(p, struct socfpga_gate_clk, hw.hw)
+
+/* SDMMC Group for System Manager defines */
+#define SYSMGR_SDMMCGRP_CTRL_OFFSET    0x28
+
+static unsigned long socfpga_gate_clk_recalc_rate(struct clk_hw *hwclk,
+       unsigned long parent_rate)
+{
+       struct socfpga_gate_clk *socfpgaclk = to_socfpga_gate_clk(hwclk);
+       u32 div = 1, val;
+
+       if (socfpgaclk->fixed_div)
+               div = socfpgaclk->fixed_div;
+       else if (socfpgaclk->div_reg) {
+               val = readl(socfpgaclk->div_reg) >> socfpgaclk->shift;
+               val &= div_mask(socfpgaclk->width);
+               div = (1 << val);
+       }
+
+       return parent_rate / div;
+}
+
+static int socfpga_clk_prepare(struct clk_hw *hwclk)
+{
+       struct socfpga_gate_clk *socfpgaclk = to_socfpga_gate_clk(hwclk);
+       int i;
+       u32 hs_timing;
+       u32 clk_phase[2];
+
+       if (socfpgaclk->clk_phase[0] || socfpgaclk->clk_phase[1]) {
+               for (i = 0; i < ARRAY_SIZE(clk_phase); i++) {
+                       switch (socfpgaclk->clk_phase[i]) {
+                       case 0:
+                               clk_phase[i] = 0;
+                               break;
+                       case 45:
+                               clk_phase[i] = 1;
+                               break;
+                       case 90:
+                               clk_phase[i] = 2;
+                               break;
+                       case 135:
+                               clk_phase[i] = 3;
+                               break;
+                       case 180:
+                               clk_phase[i] = 4;
+                               break;
+                       case 225:
+                               clk_phase[i] = 5;
+                               break;
+                       case 270:
+                               clk_phase[i] = 6;
+                               break;
+                       case 315:
+                               clk_phase[i] = 7;
+                               break;
+                       default:
+                               clk_phase[i] = 0;
+                               break;
+                       }
+               }
+
+               hs_timing = SYSMGR_SDMMC_CTRL_SET(clk_phase[0], clk_phase[1]);
+               if (!IS_ERR(socfpgaclk->sys_mgr_base_addr))
+                       regmap_write(socfpgaclk->sys_mgr_base_addr,
+                                    SYSMGR_SDMMCGRP_CTRL_OFFSET, hs_timing);
+               else
+                       pr_err("%s: cannot set clk_phase because sys_mgr_base_addr is not available!\n",
+                                       __func__);
+       }
+       return 0;
+}
+
+static struct clk_ops gateclk_ops = {
+       .prepare = socfpga_clk_prepare,
+       .recalc_rate = socfpga_gate_clk_recalc_rate,
+};
+
+static void __init __socfpga_gate_init(struct device_node *node,
+       const struct clk_ops *ops)
+{
+       u32 clk_gate[2];
+       u32 div_reg[3];
+       u32 clk_phase[2];
+       u32 fixed_div;
+       struct clk *clk;
+       struct socfpga_gate_clk *socfpga_clk;
+       const char *clk_name = node->name;
+       const char *parent_name[SOCFPGA_MAX_PARENTS];
+       struct clk_init_data init;
+       int rc;
+       int i = 0;
+
+       socfpga_clk = kzalloc(sizeof(*socfpga_clk), GFP_KERNEL);
+       if (WARN_ON(!socfpga_clk))
+               return;
+
+       rc = of_property_read_u32_array(node, "clk-gate", clk_gate, 2);
+       if (rc)
+               clk_gate[0] = 0;
+
+       if (clk_gate[0]) {
+               socfpga_clk->hw.reg = clk_mgr_a10_base_addr + clk_gate[0];
+               socfpga_clk->hw.bit_idx = clk_gate[1];
+
+               gateclk_ops.enable = clk_gate_ops.enable;
+               gateclk_ops.disable = clk_gate_ops.disable;
+       }
+
+       rc = of_property_read_u32(node, "fixed-divider", &fixed_div);
+       if (rc)
+               socfpga_clk->fixed_div = 0;
+       else
+               socfpga_clk->fixed_div = fixed_div;
+
+       rc = of_property_read_u32_array(node, "div-reg", div_reg, 3);
+       if (!rc) {
+               socfpga_clk->div_reg = clk_mgr_a10_base_addr + div_reg[0];
+               socfpga_clk->shift = div_reg[1];
+               socfpga_clk->width = div_reg[2];
+       } else {
+               socfpga_clk->div_reg = NULL;
+       }
+
+       rc = of_property_read_u32_array(node, "clk-phase", clk_phase, 2);
+       if (!rc) {
+               socfpga_clk->clk_phase[0] = clk_phase[0];
+               socfpga_clk->clk_phase[1] = clk_phase[1];
+
+               socfpga_clk->sys_mgr_base_addr =
+                       syscon_regmap_lookup_by_compatible("altr,sys-mgr");
+               if (IS_ERR(socfpga_clk->sys_mgr_base_addr)) {
+                       pr_err("%s: failed to find altr,sys-mgr regmap!\n",
+                                       __func__);
+                       return;
+               }
+       }
+
+       of_property_read_string(node, "clock-output-names", &clk_name);
+
+       init.name = clk_name;
+       init.ops = ops;
+       init.flags = 0;
+       while (i < SOCFPGA_MAX_PARENTS && (parent_name[i] =
+                       of_clk_get_parent_name(node, i)) != NULL)
+               i++;
+
+       init.parent_names = parent_name;
+       init.num_parents = i;
+       socfpga_clk->hw.hw.init = &init;
+
+       clk = clk_register(NULL, &socfpga_clk->hw.hw);
+       if (WARN_ON(IS_ERR(clk))) {
+               kfree(socfpga_clk);
+               return;
+       }
+       rc = of_clk_add_provider(node, of_clk_src_simple_get, clk);
+       if (WARN_ON(rc))
+               return;
+}
+
+void __init socfpga_a10_gate_init(struct device_node *node)
+{
+       __socfpga_gate_init(node, &gateclk_ops);
+}
index dd3a78c64795f27c7e171f004f9bb0462f44579a..82449cd76fd7e3ebb9b98b39ce81682eb1105173 100644 (file)
 #define SOCFPGA_MMC_CLK                        "sdmmc_clk"
 #define SOCFPGA_GPIO_DB_CLK_OFFSET     0xA8
 
-#define streq(a, b) (strcmp((a), (b)) == 0)
-
 #define to_socfpga_gate_clk(p) container_of(p, struct socfpga_gate_clk, hw.hw)
 
 /* SDMMC Group for System Manager defines */
 #define SYSMGR_SDMMCGRP_CTRL_OFFSET    0x108
-#define SYSMGR_SDMMC_CTRL_SET(smplsel, drvsel) \
-       ((((smplsel) & 0x7) << 3) | (((drvsel) & 0x7) << 0))
 
 static u8 socfpga_clk_get_parent(struct clk_hw *hwclk)
 {
@@ -194,7 +190,6 @@ static void __init __socfpga_gate_init(struct device_node *node,
        const char *parent_name[SOCFPGA_MAX_PARENTS];
        struct clk_init_data init;
        int rc;
-       int i = 0;
 
        socfpga_clk = kzalloc(sizeof(*socfpga_clk), GFP_KERNEL);
        if (WARN_ON(!socfpga_clk))
@@ -224,7 +219,7 @@ static void __init __socfpga_gate_init(struct device_node *node,
                socfpga_clk->shift = div_reg[1];
                socfpga_clk->width = div_reg[2];
        } else {
-               socfpga_clk->div_reg = 0;
+               socfpga_clk->div_reg = NULL;
        }
 
        rc = of_property_read_u32_array(node, "clk-phase", clk_phase, 2);
@@ -238,12 +233,9 @@ static void __init __socfpga_gate_init(struct device_node *node,
        init.name = clk_name;
        init.ops = ops;
        init.flags = 0;
-       while (i < SOCFPGA_MAX_PARENTS && (parent_name[i] =
-                       of_clk_get_parent_name(node, i)) != NULL)
-               i++;
 
+       init.num_parents = of_clk_parent_fill(node, parent_name, SOCFPGA_MAX_PARENTS);
        init.parent_names = parent_name;
-       init.num_parents = i;
        socfpga_clk->hw.hw.init = &init;
 
        clk = clk_register(NULL, &socfpga_clk->hw.hw);
diff --git a/drivers/clk/socfpga/clk-periph-a10.c b/drivers/clk/socfpga/clk-periph-a10.c
new file mode 100644 (file)
index 0000000..9d0181b
--- /dev/null
@@ -0,0 +1,138 @@
+/*
+ * Copyright (C) 2015 Altera Corporation. All rights reserved
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+#include <linux/clk-provider.h>
+#include <linux/io.h>
+#include <linux/of.h>
+
+#include "clk.h"
+
+#define CLK_MGR_FREE_SHIFT             16
+#define CLK_MGR_FREE_MASK              0x7
+
+#define SOCFPGA_MPU_FREE_CLK           "mpu_free_clk"
+#define SOCFPGA_NOC_FREE_CLK           "noc_free_clk"
+#define SOCFPGA_SDMMC_FREE_CLK         "sdmmc_free_clk"
+#define to_socfpga_periph_clk(p) container_of(p, struct socfpga_periph_clk, hw.hw)
+
+static unsigned long clk_periclk_recalc_rate(struct clk_hw *hwclk,
+                                            unsigned long parent_rate)
+{
+       struct socfpga_periph_clk *socfpgaclk = to_socfpga_periph_clk(hwclk);
+       u32 div;
+
+       if (socfpgaclk->fixed_div) {
+               div = socfpgaclk->fixed_div;
+       } else if (socfpgaclk->div_reg) {
+               div = readl(socfpgaclk->div_reg) >> socfpgaclk->shift;
+               div &= div_mask(socfpgaclk->width);
+               div += 1;
+       } else {
+               div = ((readl(socfpgaclk->hw.reg) & 0x7ff) + 1);
+       }
+
+       return parent_rate / div;
+}
+
+static u8 clk_periclk_get_parent(struct clk_hw *hwclk)
+{
+       struct socfpga_periph_clk *socfpgaclk = to_socfpga_periph_clk(hwclk);
+       u32 clk_src;
+
+       clk_src = readl(socfpgaclk->hw.reg);
+       if (streq(hwclk->init->name, SOCFPGA_MPU_FREE_CLK) ||
+           streq(hwclk->init->name, SOCFPGA_NOC_FREE_CLK) ||
+           streq(hwclk->init->name, SOCFPGA_SDMMC_FREE_CLK))
+               return (clk_src >> CLK_MGR_FREE_SHIFT) &
+                       CLK_MGR_FREE_MASK;
+       else
+               return 0;
+}
+
+static const struct clk_ops periclk_ops = {
+       .recalc_rate = clk_periclk_recalc_rate,
+       .get_parent = clk_periclk_get_parent,
+};
+
+static __init void __socfpga_periph_init(struct device_node *node,
+       const struct clk_ops *ops)
+{
+       u32 reg;
+       struct clk *clk;
+       struct socfpga_periph_clk *periph_clk;
+       const char *clk_name = node->name;
+       const char *parent_name;
+       struct clk_init_data init;
+       int rc;
+       u32 fixed_div;
+       u32 div_reg[3];
+
+       of_property_read_u32(node, "reg", &reg);
+
+       periph_clk = kzalloc(sizeof(*periph_clk), GFP_KERNEL);
+       if (WARN_ON(!periph_clk))
+               return;
+
+       periph_clk->hw.reg = clk_mgr_a10_base_addr + reg;
+
+       rc = of_property_read_u32_array(node, "div-reg", div_reg, 3);
+       if (!rc) {
+               periph_clk->div_reg = clk_mgr_a10_base_addr + div_reg[0];
+               periph_clk->shift = div_reg[1];
+               periph_clk->width = div_reg[2];
+       } else {
+               periph_clk->div_reg = NULL;
+       }
+
+       rc = of_property_read_u32(node, "fixed-divider", &fixed_div);
+       if (rc)
+               periph_clk->fixed_div = 0;
+       else
+               periph_clk->fixed_div = fixed_div;
+
+       of_property_read_string(node, "clock-output-names", &clk_name);
+
+       init.name = clk_name;
+       init.ops = ops;
+       init.flags = 0;
+
+       parent_name = of_clk_get_parent_name(node, 0);
+       init.num_parents = 1;
+       init.parent_names = &parent_name;
+
+       periph_clk->hw.hw.init = &init;
+
+       clk = clk_register(NULL, &periph_clk->hw.hw);
+       if (WARN_ON(IS_ERR(clk))) {
+               kfree(periph_clk);
+               return;
+       }
+       rc = of_clk_add_provider(node, of_clk_src_simple_get, clk);
+       if (rc < 0) {
+               pr_err("Could not register clock provider for node:%s\n",
+                      clk_name);
+               goto err_clk;
+       }
+
+       return;
+
+err_clk:
+       clk_unregister(clk);
+}
+
+void __init socfpga_a10_periph_init(struct device_node *node)
+{
+       __socfpga_periph_init(node, &periclk_ops);
+}
index 46531c34ec9b5b58799c1c538c3f3ef103158502..83aeaa219d14e82800976e476fc24a72a0f032a9 100644 (file)
@@ -76,7 +76,7 @@ static __init void __socfpga_periph_init(struct device_node *node,
                periph_clk->shift = div_reg[1];
                periph_clk->width = div_reg[2];
        } else {
-               periph_clk->div_reg = 0;
+               periph_clk->div_reg = NULL;
        }
 
        rc = of_property_read_u32(node, "fixed-divider", &fixed_div);
diff --git a/drivers/clk/socfpga/clk-pll-a10.c b/drivers/clk/socfpga/clk-pll-a10.c
new file mode 100644 (file)
index 0000000..1178b11
--- /dev/null
@@ -0,0 +1,129 @@
+/*
+ * Copyright (C) 2015 Altera Corporation. All rights reserved
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+#include <linux/clk-provider.h>
+#include <linux/io.h>
+#include <linux/of.h>
+#include <linux/of_address.h>
+
+#include "clk.h"
+
+/* Clock Manager offsets */
+#define CLK_MGR_PLL_CLK_SRC_SHIFT      8
+#define CLK_MGR_PLL_CLK_SRC_MASK       0x3
+
+/* Clock bypass bits */
+#define SOCFPGA_PLL_BG_PWRDWN          0
+#define SOCFPGA_PLL_PWR_DOWN           1
+#define SOCFPGA_PLL_EXT_ENA            2
+#define SOCFPGA_PLL_DIVF_MASK          0x00001FFF
+#define SOCFPGA_PLL_DIVF_SHIFT 0
+#define SOCFPGA_PLL_DIVQ_MASK          0x003F0000
+#define SOCFPGA_PLL_DIVQ_SHIFT 16
+#define SOCFGPA_MAX_PARENTS    5
+
+#define SOCFPGA_MAIN_PLL_CLK           "main_pll"
+#define SOCFPGA_PERIP_PLL_CLK          "periph_pll"
+
+#define to_socfpga_clk(p) container_of(p, struct socfpga_pll, hw.hw)
+
+void __iomem *clk_mgr_a10_base_addr;
+
+static unsigned long clk_pll_recalc_rate(struct clk_hw *hwclk,
+                                        unsigned long parent_rate)
+{
+       struct socfpga_pll *socfpgaclk = to_socfpga_clk(hwclk);
+       unsigned long divf, divq, reg;
+       unsigned long long vco_freq;
+
+       /* read VCO1 reg for numerator and denominator */
+       reg = readl(socfpgaclk->hw.reg + 0x4);
+       divf = (reg & SOCFPGA_PLL_DIVF_MASK) >> SOCFPGA_PLL_DIVF_SHIFT;
+       divq = (reg & SOCFPGA_PLL_DIVQ_MASK) >> SOCFPGA_PLL_DIVQ_SHIFT;
+       vco_freq = (unsigned long long)parent_rate * (divf + 1);
+       do_div(vco_freq, (1 + divq));
+       return (unsigned long)vco_freq;
+}
+
+static u8 clk_pll_get_parent(struct clk_hw *hwclk)
+{
+       struct socfpga_pll *socfpgaclk = to_socfpga_clk(hwclk);
+       u32 pll_src;
+
+       pll_src = readl(socfpgaclk->hw.reg);
+
+       return (pll_src >> CLK_MGR_PLL_CLK_SRC_SHIFT) &
+               CLK_MGR_PLL_CLK_SRC_MASK;
+}
+
+static struct clk_ops clk_pll_ops = {
+       .recalc_rate = clk_pll_recalc_rate,
+       .get_parent = clk_pll_get_parent,
+};
+
+static struct __init clk * __socfpga_pll_init(struct device_node *node,
+       const struct clk_ops *ops)
+{
+       u32 reg;
+       struct clk *clk;
+       struct socfpga_pll *pll_clk;
+       const char *clk_name = node->name;
+       const char *parent_name[SOCFGPA_MAX_PARENTS];
+       struct clk_init_data init;
+       struct device_node *clkmgr_np;
+       int rc;
+       int i = 0;
+
+       of_property_read_u32(node, "reg", &reg);
+
+       pll_clk = kzalloc(sizeof(*pll_clk), GFP_KERNEL);
+       if (WARN_ON(!pll_clk))
+               return NULL;
+
+       clkmgr_np = of_find_compatible_node(NULL, NULL, "altr,clk-mgr");
+       clk_mgr_a10_base_addr = of_iomap(clkmgr_np, 0);
+       BUG_ON(!clk_mgr_a10_base_addr);
+       pll_clk->hw.reg = clk_mgr_a10_base_addr + reg;
+
+       of_property_read_string(node, "clock-output-names", &clk_name);
+
+       init.name = clk_name;
+       init.ops = ops;
+       init.flags = 0;
+
+       while (i < SOCFGPA_MAX_PARENTS && (parent_name[i] =
+                       of_clk_get_parent_name(node, i)) != NULL)
+               i++;
+       init.num_parents = i;
+       init.parent_names = parent_name;
+       pll_clk->hw.hw.init = &init;
+
+       pll_clk->hw.bit_idx = SOCFPGA_PLL_EXT_ENA;
+       clk_pll_ops.enable = clk_gate_ops.enable;
+       clk_pll_ops.disable = clk_gate_ops.disable;
+
+       clk = clk_register(NULL, &pll_clk->hw.hw);
+       if (WARN_ON(IS_ERR(clk))) {
+               kfree(pll_clk);
+               return NULL;
+       }
+       rc = of_clk_add_provider(node, of_clk_src_simple_get, clk);
+       return clk;
+}
+
+void __init socfpga_a10_pll_init(struct device_node *node)
+{
+       __socfpga_pll_init(node, &clk_pll_ops);
+}
index de6da957a09d6ebe82f416370c84a7dc50acea8e..8f26b5234947eafca2649fdbce3262db4351f8bd 100644 (file)
@@ -92,7 +92,6 @@ static __init struct clk *__socfpga_pll_init(struct device_node *node,
        struct clk_init_data init;
        struct device_node *clkmgr_np;
        int rc;
-       int i = 0;
 
        of_property_read_u32(node, "reg", &reg);
 
@@ -111,11 +110,7 @@ static __init struct clk *__socfpga_pll_init(struct device_node *node,
        init.ops = ops;
        init.flags = 0;
 
-       while (i < SOCFPGA_MAX_PARENTS && (parent_name[i] =
-                       of_clk_get_parent_name(node, i)) != NULL)
-               i++;
-
-       init.num_parents = i;
+       init.num_parents = of_clk_parent_fill(node, parent_name, SOCFPGA_MAX_PARENTS);
        init.parent_names = parent_name;
        pll_clk->hw.hw.init = &init;
 
index 43db947e5f0e51e60c232832d379faca9ca386d3..7564d2e35f3207cf2d9ee399827d461cdae90194 100644 (file)
@@ -24,4 +24,9 @@
 CLK_OF_DECLARE(socfpga_pll_clk, "altr,socfpga-pll-clock", socfpga_pll_init);
 CLK_OF_DECLARE(socfpga_perip_clk, "altr,socfpga-perip-clk", socfpga_periph_init);
 CLK_OF_DECLARE(socfpga_gate_clk, "altr,socfpga-gate-clk", socfpga_gate_init);
-
+CLK_OF_DECLARE(socfpga_a10_pll_clk, "altr,socfpga-a10-pll-clock",
+              socfpga_a10_pll_init);
+CLK_OF_DECLARE(socfpga_a10_perip_clk, "altr,socfpga-a10-perip-clk",
+              socfpga_a10_periph_init);
+CLK_OF_DECLARE(socfpga_a10_gate_clk, "altr,socfpga-a10-gate-clk",
+              socfpga_a10_gate_init);
index d291f60c46e1adbbef48733388f1a1f0d40e31c5..603973ab7e2914d0da3c39e56d7613dd8263ee19 100644 (file)
 #define CLKMGR_L4SRC           0x70
 #define CLKMGR_PERPLL_SRC      0xAC
 
-#define SOCFPGA_MAX_PARENTS            3
+#define SOCFPGA_MAX_PARENTS            5
 #define div_mask(width) ((1 << (width)) - 1)
 
+#define streq(a, b) (strcmp((a), (b)) == 0)
+#define SYSMGR_SDMMC_CTRL_SET(smplsel, drvsel) \
+       ((((smplsel) & 0x7) << 3) | (((drvsel) & 0x7) << 0))
+
 extern void __iomem *clk_mgr_base_addr;
+extern void __iomem *clk_mgr_a10_base_addr;
 
 void __init socfpga_pll_init(struct device_node *node);
 void __init socfpga_periph_init(struct device_node *node);
 void __init socfpga_gate_init(struct device_node *node);
+void socfpga_a10_pll_init(struct device_node *node);
+void socfpga_a10_periph_init(struct device_node *node);
+void socfpga_a10_gate_init(struct device_node *node);
 
 struct socfpga_pll {
        struct clk_gate hw;
@@ -44,6 +52,7 @@ struct socfpga_gate_clk {
        char *parent_name;
        u32 fixed_div;
        void __iomem *div_reg;
+       struct regmap *sys_mgr_base_addr;
        u32 width;      /* only valid if div_reg != 0 */
        u32 shift;      /* only valid if div_reg != 0 */
        u32 clk_phase[2];
index bf12a25eb3a22aab048f04d5280195d21bd7dd01..657ca14ba709a64b97e297e74f15f8f5d751efdf 100644 (file)
@@ -116,7 +116,7 @@ static long flexgen_round_rate(struct clk_hw *hw, unsigned long rate,
        return *prate / div;
 }
 
-unsigned long flexgen_recalc_rate(struct clk_hw *hw,
+static unsigned long flexgen_recalc_rate(struct clk_hw *hw,
                unsigned long parent_rate)
 {
        struct flexgen *flexgen = to_flexgen(hw);
@@ -174,7 +174,7 @@ static const struct clk_ops flexgen_ops = {
        .set_rate = flexgen_set_rate,
 };
 
-struct clk *clk_register_flexgen(const char *name,
+static struct clk *clk_register_flexgen(const char *name,
                                const char **parent_names, u8 num_parents,
                                void __iomem *reg, spinlock_t *lock, u32 idx,
                                unsigned long flexgen_flags) {
@@ -245,7 +245,7 @@ static const char ** __init flexgen_get_parents(struct device_node *np,
        const char **parents;
        int nparents, i;
 
-       nparents = of_count_phandle_with_args(np, "clocks", "#clock-cells");
+       nparents = of_clk_get_parent_count(np);
        if (WARN_ON(nparents <= 0))
                return NULL;
 
@@ -260,7 +260,7 @@ static const char ** __init flexgen_get_parents(struct device_node *np,
        return parents;
 }
 
-void __init st_of_flexgen_setup(struct device_node *np)
+static void __init st_of_flexgen_setup(struct device_node *np)
 {
        struct device_node *pnode;
        void __iomem *reg;
index a917c4c7eaa9c2f6709985c544a4370494e29b38..e94197f04b0b3bae5a811c70e7d91393a2a263c6 100644 (file)
@@ -492,7 +492,7 @@ static int quadfs_pll_is_enabled(struct clk_hw *hw)
        return !!npda;
 }
 
-int clk_fs660c32_vco_get_rate(unsigned long input, struct stm_fs *fs,
+static int clk_fs660c32_vco_get_rate(unsigned long input, struct stm_fs *fs,
                           unsigned long *rate)
 {
        unsigned long nd = fs->ndiv + 16; /* ndiv value */
@@ -519,7 +519,7 @@ static unsigned long quadfs_pll_fs660c32_recalc_rate(struct clk_hw *hw,
        return rate;
 }
 
-int clk_fs660c32_vco_get_params(unsigned long input,
+static int clk_fs660c32_vco_get_params(unsigned long input,
                                unsigned long output, struct stm_fs *fs)
 {
 /* Formula
index fdcff10f6d3089ec389b21522e178db32eaaa911..4fbe6e099587c0541ce9a22783fb2dc4e4becf8c 100644 (file)
@@ -26,7 +26,7 @@ static const char ** __init clkgen_mux_get_parents(struct device_node *np,
        const char **parents;
        int nparents, i;
 
-       nparents = of_count_phandle_with_args(np, "clocks", "#clock-cells");
+       nparents = of_clk_get_parent_count(np);
        if (WARN_ON(nparents <= 0))
                return ERR_PTR(-EINVAL);
 
@@ -131,7 +131,7 @@ static int clkgena_divmux_is_enabled(struct clk_hw *hw)
        return (s8)clk_mux_ops.get_parent(mux_hw) > 0;
 }
 
-u8 clkgena_divmux_get_parent(struct clk_hw *hw)
+static u8 clkgena_divmux_get_parent(struct clk_hw *hw)
 {
        struct clkgena_divmux *genamux = to_clkgena_divmux(hw);
        struct clk_hw *mux_hw = &genamux->mux.hw;
@@ -168,7 +168,7 @@ static int clkgena_divmux_set_parent(struct clk_hw *hw, u8 index)
        return 0;
 }
 
-unsigned long clkgena_divmux_recalc_rate(struct clk_hw *hw,
+static unsigned long clkgena_divmux_recalc_rate(struct clk_hw *hw,
                unsigned long parent_rate)
 {
        struct clkgena_divmux *genamux = to_clkgena_divmux(hw);
@@ -215,7 +215,7 @@ static const struct clk_ops clkgena_divmux_ops = {
 /**
  * clk_register_genamux - register a genamux clock with the clock framework
  */
-struct clk *clk_register_genamux(const char *name,
+static struct clk *clk_register_genamux(const char *name,
                                const char **parent_names, u8 num_parents,
                                void __iomem *reg,
                                const struct clkgena_divmux_data *muxdata,
@@ -385,7 +385,7 @@ static void __iomem * __init clkgen_get_register_base(
        return reg;
 }
 
-void __init st_of_clkgena_divmux_setup(struct device_node *np)
+static void __init st_of_clkgena_divmux_setup(struct device_node *np)
 {
        const struct of_device_id *match;
        const struct clkgena_divmux_data *data;
@@ -485,7 +485,7 @@ static const struct of_device_id clkgena_prediv_of_match[] = {
        {}
 };
 
-void __init st_of_clkgena_prediv_setup(struct device_node *np)
+static void __init st_of_clkgena_prediv_setup(struct device_node *np)
 {
        const struct of_device_id *match;
        void __iomem *reg;
@@ -622,7 +622,7 @@ static const struct of_device_id mux_of_match[] = {
        {}
 };
 
-void __init st_of_clkgen_mux_setup(struct device_node *np)
+static void __init st_of_clkgen_mux_setup(struct device_node *np)
 {
        const struct of_device_id *match;
        struct clk *clk;
@@ -699,7 +699,7 @@ static const struct of_device_id vcc_of_match[] = {
        {}
 };
 
-void __init st_of_clkgen_vcc_setup(struct device_node *np)
+static void __init st_of_clkgen_vcc_setup(struct device_node *np)
 {
        const struct of_device_id *match;
        void __iomem *reg;
index d204ba85db3a423d6b404cb825c873c2815850e2..1065322072136bd90c868f9d6a2fd4c56104f303 100644 (file)
@@ -270,7 +270,7 @@ static int clkgen_pll_is_enabled(struct clk_hw *hw)
        return !poweroff;
 }
 
-unsigned long recalc_stm_pll800c65(struct clk_hw *hw,
+static unsigned long recalc_stm_pll800c65(struct clk_hw *hw,
                unsigned long parent_rate)
 {
        struct clkgen_pll *pll = to_clkgen_pll(hw);
@@ -297,7 +297,7 @@ unsigned long recalc_stm_pll800c65(struct clk_hw *hw,
 
 }
 
-unsigned long recalc_stm_pll1600c65(struct clk_hw *hw,
+static unsigned long recalc_stm_pll1600c65(struct clk_hw *hw,
                unsigned long parent_rate)
 {
        struct clkgen_pll *pll = to_clkgen_pll(hw);
@@ -321,7 +321,7 @@ unsigned long recalc_stm_pll1600c65(struct clk_hw *hw,
        return rate;
 }
 
-unsigned long recalc_stm_pll3200c32(struct clk_hw *hw,
+static unsigned long recalc_stm_pll3200c32(struct clk_hw *hw,
                unsigned long parent_rate)
 {
        struct clkgen_pll *pll = to_clkgen_pll(hw);
@@ -343,7 +343,7 @@ unsigned long recalc_stm_pll3200c32(struct clk_hw *hw,
        return rate;
 }
 
-unsigned long recalc_stm_pll1200c32(struct clk_hw *hw,
+static unsigned long recalc_stm_pll1200c32(struct clk_hw *hw,
                unsigned long parent_rate)
 {
        struct clkgen_pll *pll = to_clkgen_pll(hw);
@@ -544,7 +544,7 @@ CLK_OF_DECLARE(clkgena_c65_plls,
               "st,clkgena-plls-c65", clkgena_c65_pll_setup);
 
 static struct clk * __init clkgen_odf_register(const char *parent_name,
-                                              void * __iomem reg,
+                                              void __iomem *reg,
                                               struct clkgen_pll_data *pll_data,
                                               int odf,
                                               spinlock_t *odf_lock,
index d8da77d72861b29f0867d47b43b7917da31037f7..887f4ea161bb4eb79700c7778aecbec2c977e2b4 100644 (file)
@@ -93,7 +93,7 @@ static void __init sun9i_a80_pll4_setup(struct device_node *node)
        void __iomem *reg;
 
        reg = of_io_request_and_map(node, 0, of_node_full_name(node));
-       if (!reg) {
+       if (IS_ERR(reg)) {
                pr_err("Could not get registers for a80-pll4-clk: %s\n",
                       node->name);
                return;
@@ -154,7 +154,7 @@ static void __init sun9i_a80_gt_setup(struct device_node *node)
        struct clk *gt;
 
        reg = of_io_request_and_map(node, 0, of_node_full_name(node));
-       if (!reg) {
+       if (IS_ERR(reg)) {
                pr_err("Could not get registers for a80-gt-clk: %s\n",
                       node->name);
                return;
@@ -218,7 +218,7 @@ static void __init sun9i_a80_ahb_setup(struct device_node *node)
        void __iomem *reg;
 
        reg = of_io_request_and_map(node, 0, of_node_full_name(node));
-       if (!reg) {
+       if (IS_ERR(reg)) {
                pr_err("Could not get registers for a80-ahb-clk: %s\n",
                       node->name);
                return;
@@ -244,7 +244,7 @@ static void __init sun9i_a80_apb0_setup(struct device_node *node)
        void __iomem *reg;
 
        reg = of_io_request_and_map(node, 0, of_node_full_name(node));
-       if (!reg) {
+       if (IS_ERR(reg)) {
                pr_err("Could not get registers for a80-apb0-clk: %s\n",
                       node->name);
                return;
@@ -310,7 +310,7 @@ static void __init sun9i_a80_apb1_setup(struct device_node *node)
        void __iomem *reg;
 
        reg = of_io_request_and_map(node, 0, of_node_full_name(node));
-       if (!reg) {
+       if (IS_ERR(reg)) {
                pr_err("Could not get registers for a80-apb1-clk: %s\n",
                       node->name);
                return;
index 7e1e2bd189b6a6f6f3c0047d6b3f4d6b5899c3c6..9a82f17d2d73daf611ac5e8651e35c2101ea6245 100644 (file)
@@ -198,6 +198,8 @@ static void __init sun6i_ahb1_clk_setup(struct device_node *node)
        int i = 0;
 
        reg = of_io_request_and_map(node, 0, of_node_full_name(node));
+       if (IS_ERR(reg))
+               return;
 
        /* we have a mux, we will have >1 parents */
        while (i < SUN6I_AHB1_MAX_PARENTS &&
index a86ed2f8d7af85faa09c0363a3d288b2af228fab..3a25f9588e67b58da122a82056854e5add44fd1c 100644 (file)
@@ -204,6 +204,17 @@ static void __init sun6i_a31_usb_setup(struct device_node *node)
 }
 CLK_OF_DECLARE(sun6i_a31_usb, "allwinner,sun6i-a31-usb-clk", sun6i_a31_usb_setup);
 
+static const struct usb_clk_data sun8i_a23_usb_clk_data __initconst = {
+       .clk_mask = BIT(16) | BIT(11) | BIT(10) | BIT(9) | BIT(8),
+       .reset_mask = BIT(2) | BIT(1) | BIT(0),
+};
+
+static void __init sun8i_a23_usb_setup(struct device_node *node)
+{
+       sunxi_usb_clk_setup(node, &sun8i_a23_usb_clk_data, &sun4i_a10_usb_lock);
+}
+CLK_OF_DECLARE(sun8i_a23_usb, "allwinner,sun8i-a23-usb-clk", sun8i_a23_usb_setup);
+
 static const struct usb_clk_data sun9i_a80_usb_mod_data __initconst = {
        .clk_mask = BIT(6) | BIT(5) | BIT(4) | BIT(3) | BIT(2) | BIT(1),
        .reset_mask = BIT(19) | BIT(18) | BIT(17),
diff --git a/drivers/clk/tegra/Kconfig b/drivers/clk/tegra/Kconfig
new file mode 100644 (file)
index 0000000..1ba30d1
--- /dev/null
@@ -0,0 +1,3 @@
+config TEGRA_CLK_EMC
+       def_bool y
+       depends on TEGRA124_EMC
index edb8358fa6cebab596e7f39c022736a4b6c31457..aec862ba7a17547b870a175ef436927b2c7307d3 100644 (file)
@@ -11,6 +11,7 @@ obj-y                                 += clk-tegra-periph.o
 obj-y                                  += clk-tegra-pmc.o
 obj-y                                  += clk-tegra-fixed.o
 obj-y                                  += clk-tegra-super-gen4.o
+obj-$(CONFIG_TEGRA_CLK_EMC)            += clk-emc.o
 obj-$(CONFIG_ARCH_TEGRA_2x_SOC)         += clk-tegra20.o
 obj-$(CONFIG_ARCH_TEGRA_3x_SOC)         += clk-tegra30.o
 obj-$(CONFIG_ARCH_TEGRA_114_SOC)       += clk-tegra114.o
diff --git a/drivers/clk/tegra/clk-emc.c b/drivers/clk/tegra/clk-emc.c
new file mode 100644 (file)
index 0000000..7649685
--- /dev/null
@@ -0,0 +1,538 @@
+/*
+ * drivers/clk/tegra/clk-emc.c
+ *
+ * Copyright (c) 2014, NVIDIA CORPORATION.  All rights reserved.
+ *
+ * Author:
+ *     Mikko Perttunen <mperttunen@nvidia.com>
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/clk-provider.h>
+#include <linux/clk.h>
+#include <linux/clkdev.h>
+#include <linux/delay.h>
+#include <linux/module.h>
+#include <linux/of_address.h>
+#include <linux/of_platform.h>
+#include <linux/platform_device.h>
+#include <linux/sort.h>
+#include <linux/string.h>
+
+#include <soc/tegra/fuse.h>
+#include <soc/tegra/emc.h>
+
+#include "clk.h"
+
+#define CLK_SOURCE_EMC 0x19c
+
+#define CLK_SOURCE_EMC_EMC_2X_CLK_DIVISOR_SHIFT 0
+#define CLK_SOURCE_EMC_EMC_2X_CLK_DIVISOR_MASK 0xff
+#define CLK_SOURCE_EMC_EMC_2X_CLK_DIVISOR(x) (((x) & CLK_SOURCE_EMC_EMC_2X_CLK_DIVISOR_MASK) << \
+                                             CLK_SOURCE_EMC_EMC_2X_CLK_DIVISOR_SHIFT)
+
+#define CLK_SOURCE_EMC_EMC_2X_CLK_SRC_SHIFT 29
+#define CLK_SOURCE_EMC_EMC_2X_CLK_SRC_MASK 0x7
+#define CLK_SOURCE_EMC_EMC_2X_CLK_SRC(x) (((x) & CLK_SOURCE_EMC_EMC_2X_CLK_SRC_MASK) << \
+                                         CLK_SOURCE_EMC_EMC_2X_CLK_SRC_SHIFT)
+
+static const char * const emc_parent_clk_names[] = {
+       "pll_m", "pll_c", "pll_p", "clk_m", "pll_m_ud",
+       "pll_c2", "pll_c3", "pll_c_ud"
+};
+
+/*
+ * List of clock sources for various parents the EMC clock can have.
+ * When we change the timing to a timing with a parent that has the same
+ * clock source as the current parent, we must first change to a backup
+ * timing that has a different clock source.
+ */
+
+#define EMC_SRC_PLL_M 0
+#define EMC_SRC_PLL_C 1
+#define EMC_SRC_PLL_P 2
+#define EMC_SRC_CLK_M 3
+#define EMC_SRC_PLL_C2 4
+#define EMC_SRC_PLL_C3 5
+
+static const char emc_parent_clk_sources[] = {
+       EMC_SRC_PLL_M, EMC_SRC_PLL_C, EMC_SRC_PLL_P, EMC_SRC_CLK_M,
+       EMC_SRC_PLL_M, EMC_SRC_PLL_C2, EMC_SRC_PLL_C3, EMC_SRC_PLL_C
+};
+
+struct emc_timing {
+       unsigned long rate, parent_rate;
+       u8 parent_index;
+       struct clk *parent;
+       u32 ram_code;
+};
+
+struct tegra_clk_emc {
+       struct clk_hw hw;
+       void __iomem *clk_regs;
+       struct clk *prev_parent;
+       bool changing_timing;
+
+       struct device_node *emc_node;
+       struct tegra_emc *emc;
+
+       int num_timings;
+       struct emc_timing *timings;
+       spinlock_t *lock;
+};
+
+/* Common clock framework callback implementations */
+
+static unsigned long emc_recalc_rate(struct clk_hw *hw,
+                                    unsigned long parent_rate)
+{
+       struct tegra_clk_emc *tegra;
+       u32 val, div;
+
+       tegra = container_of(hw, struct tegra_clk_emc, hw);
+
+       /*
+        * CCF wrongly assumes that the parent won't change during set_rate,
+        * so get the parent rate explicitly.
+        */
+       parent_rate = __clk_get_rate(__clk_get_parent(hw->clk));
+
+       val = readl(tegra->clk_regs + CLK_SOURCE_EMC);
+       div = val & CLK_SOURCE_EMC_EMC_2X_CLK_DIVISOR_MASK;
+
+       return parent_rate / (div + 2) * 2;
+}
+
+/*
+ * Rounds up unless no higher rate exists, in which case down. This way is
+ * safer since things have EMC rate floors. Also don't touch parent_rate
+ * since we don't want the CCF to play with our parent clocks.
+ */
+static long emc_determine_rate(struct clk_hw *hw, unsigned long rate,
+                              unsigned long min_rate,
+                              unsigned long max_rate,
+                              unsigned long *best_parent_rate,
+                              struct clk_hw **best_parent_hw)
+{
+       struct tegra_clk_emc *tegra;
+       u8 ram_code = tegra_read_ram_code();
+       struct emc_timing *timing = NULL;
+       int i;
+
+       tegra = container_of(hw, struct tegra_clk_emc, hw);
+
+       for (i = 0; i < tegra->num_timings; i++) {
+               if (tegra->timings[i].ram_code != ram_code)
+                       continue;
+
+               timing = tegra->timings + i;
+
+               if (timing->rate > max_rate) {
+                       i = min(i, 1);
+                       return tegra->timings[i - 1].rate;
+               }
+
+               if (timing->rate < min_rate)
+                       continue;
+
+               if (timing->rate >= rate)
+                       return timing->rate;
+       }
+
+       if (timing)
+               return timing->rate;
+
+       return __clk_get_rate(hw->clk);
+}
+
+static u8 emc_get_parent(struct clk_hw *hw)
+{
+       struct tegra_clk_emc *tegra;
+       u32 val;
+
+       tegra = container_of(hw, struct tegra_clk_emc, hw);
+
+       val = readl(tegra->clk_regs + CLK_SOURCE_EMC);
+
+       return (val >> CLK_SOURCE_EMC_EMC_2X_CLK_SRC_SHIFT)
+               & CLK_SOURCE_EMC_EMC_2X_CLK_SRC_MASK;
+}
+
+static struct tegra_emc *emc_ensure_emc_driver(struct tegra_clk_emc *tegra)
+{
+       struct platform_device *pdev;
+
+       if (tegra->emc)
+               return tegra->emc;
+
+       if (!tegra->emc_node)
+               return NULL;
+
+       pdev = of_find_device_by_node(tegra->emc_node);
+       if (!pdev) {
+               pr_err("%s: could not get external memory controller\n",
+                      __func__);
+               return NULL;
+       }
+
+       of_node_put(tegra->emc_node);
+       tegra->emc_node = NULL;
+
+       tegra->emc = platform_get_drvdata(pdev);
+       if (!tegra->emc) {
+               pr_err("%s: cannot find EMC driver\n", __func__);
+               return NULL;
+       }
+
+       return tegra->emc;
+}
+
+static int emc_set_timing(struct tegra_clk_emc *tegra,
+                         struct emc_timing *timing)
+{
+       int err;
+       u8 div;
+       u32 car_value;
+       unsigned long flags = 0;
+       struct tegra_emc *emc = emc_ensure_emc_driver(tegra);
+
+       if (!emc)
+               return -ENOENT;
+
+       pr_debug("going to rate %ld prate %ld p %s\n", timing->rate,
+                timing->parent_rate, __clk_get_name(timing->parent));
+
+       if (emc_get_parent(&tegra->hw) == timing->parent_index &&
+           clk_get_rate(timing->parent) != timing->parent_rate) {
+               BUG();
+               return -EINVAL;
+       }
+
+       tegra->changing_timing = true;
+
+       err = clk_set_rate(timing->parent, timing->parent_rate);
+       if (err) {
+               pr_err("cannot change parent %s rate to %ld: %d\n",
+                      __clk_get_name(timing->parent), timing->parent_rate,
+                      err);
+
+               return err;
+       }
+
+       err = clk_prepare_enable(timing->parent);
+       if (err) {
+               pr_err("cannot enable parent clock: %d\n", err);
+               return err;
+       }
+
+       div = timing->parent_rate / (timing->rate / 2) - 2;
+
+       err = tegra_emc_prepare_timing_change(emc, timing->rate);
+       if (err)
+               return err;
+
+       spin_lock_irqsave(tegra->lock, flags);
+
+       car_value = readl(tegra->clk_regs + CLK_SOURCE_EMC);
+
+       car_value &= ~CLK_SOURCE_EMC_EMC_2X_CLK_SRC(~0);
+       car_value |= CLK_SOURCE_EMC_EMC_2X_CLK_SRC(timing->parent_index);
+
+       car_value &= ~CLK_SOURCE_EMC_EMC_2X_CLK_DIVISOR(~0);
+       car_value |= CLK_SOURCE_EMC_EMC_2X_CLK_DIVISOR(div);
+
+       writel(car_value, tegra->clk_regs + CLK_SOURCE_EMC);
+
+       spin_unlock_irqrestore(tegra->lock, flags);
+
+       tegra_emc_complete_timing_change(emc, timing->rate);
+
+       clk_hw_reparent(&tegra->hw, __clk_get_hw(timing->parent));
+       clk_disable_unprepare(tegra->prev_parent);
+
+       tegra->prev_parent = timing->parent;
+       tegra->changing_timing = false;
+
+       return 0;
+}
+
+/*
+ * Get backup timing to use as an intermediate step when a change between
+ * two timings with the same clock source has been requested. First try to
+ * find a timing with a higher clock rate to avoid a rate below any set rate
+ * floors. If that is not possible, find a lower rate.
+ */
+static struct emc_timing *get_backup_timing(struct tegra_clk_emc *tegra,
+                                           int timing_index)
+{
+       int i;
+       u32 ram_code = tegra_read_ram_code();
+       struct emc_timing *timing;
+
+       for (i = timing_index+1; i < tegra->num_timings; i++) {
+               timing = tegra->timings + i;
+               if (timing->ram_code != ram_code)
+                       continue;
+
+               if (emc_parent_clk_sources[timing->parent_index] !=
+                   emc_parent_clk_sources[
+                     tegra->timings[timing_index].parent_index])
+                       return timing;
+       }
+
+       for (i = timing_index-1; i >= 0; --i) {
+               timing = tegra->timings + i;
+               if (timing->ram_code != ram_code)
+                       continue;
+
+               if (emc_parent_clk_sources[timing->parent_index] !=
+                   emc_parent_clk_sources[
+                     tegra->timings[timing_index].parent_index])
+                       return timing;
+       }
+
+       return NULL;
+}
+
+static int emc_set_rate(struct clk_hw *hw, unsigned long rate,
+                       unsigned long parent_rate)
+{
+       struct tegra_clk_emc *tegra;
+       struct emc_timing *timing = NULL;
+       int i, err;
+       u32 ram_code = tegra_read_ram_code();
+
+       tegra = container_of(hw, struct tegra_clk_emc, hw);
+
+       if (__clk_get_rate(hw->clk) == rate)
+               return 0;
+
+       /*
+        * When emc_set_timing changes the parent rate, CCF will propagate
+        * that downward to us, so ignore any set_rate calls while a rate
+        * change is already going on.
+        */
+       if (tegra->changing_timing)
+               return 0;
+
+       for (i = 0; i < tegra->num_timings; i++) {
+               if (tegra->timings[i].rate == rate &&
+                   tegra->timings[i].ram_code == ram_code) {
+                       timing = tegra->timings + i;
+                       break;
+               }
+       }
+
+       if (!timing) {
+               pr_err("cannot switch to rate %ld without emc table\n", rate);
+               return -EINVAL;
+       }
+
+       if (emc_parent_clk_sources[emc_get_parent(hw)] ==
+           emc_parent_clk_sources[timing->parent_index] &&
+           clk_get_rate(timing->parent) != timing->parent_rate) {
+               /*
+                * Parent clock source not changed but parent rate has changed,
+                * need to temporarily switch to another parent
+                */
+
+               struct emc_timing *backup_timing;
+
+               backup_timing = get_backup_timing(tegra, i);
+               if (!backup_timing) {
+                       pr_err("cannot find backup timing\n");
+                       return -EINVAL;
+               }
+
+               pr_debug("using %ld as backup rate when going to %ld\n",
+                        backup_timing->rate, rate);
+
+               err = emc_set_timing(tegra, backup_timing);
+               if (err) {
+                       pr_err("cannot set backup timing: %d\n", err);
+                       return err;
+               }
+       }
+
+       return emc_set_timing(tegra, timing);
+}
+
+/* Initialization and deinitialization */
+
+static int load_one_timing_from_dt(struct tegra_clk_emc *tegra,
+                                  struct emc_timing *timing,
+                                  struct device_node *node)
+{
+       int err, i;
+       u32 tmp;
+
+       err = of_property_read_u32(node, "clock-frequency", &tmp);
+       if (err) {
+               pr_err("timing %s: failed to read rate\n", node->full_name);
+               return err;
+       }
+
+       timing->rate = tmp;
+
+       err = of_property_read_u32(node, "nvidia,parent-clock-frequency", &tmp);
+       if (err) {
+               pr_err("timing %s: failed to read parent rate\n",
+                      node->full_name);
+               return err;
+       }
+
+       timing->parent_rate = tmp;
+
+       timing->parent = of_clk_get_by_name(node, "emc-parent");
+       if (IS_ERR(timing->parent)) {
+               pr_err("timing %s: failed to get parent clock\n",
+                      node->full_name);
+               return PTR_ERR(timing->parent);
+       }
+
+       timing->parent_index = 0xff;
+       for (i = 0; i < ARRAY_SIZE(emc_parent_clk_names); i++) {
+               if (!strcmp(emc_parent_clk_names[i],
+                           __clk_get_name(timing->parent))) {
+                       timing->parent_index = i;
+                       break;
+               }
+       }
+       if (timing->parent_index == 0xff) {
+               pr_err("timing %s: %s is not a valid parent\n",
+                      node->full_name, __clk_get_name(timing->parent));
+               clk_put(timing->parent);
+               return -EINVAL;
+       }
+
+       return 0;
+}
+
+static int cmp_timings(const void *_a, const void *_b)
+{
+       const struct emc_timing *a = _a;
+       const struct emc_timing *b = _b;
+
+       if (a->rate < b->rate)
+               return -1;
+       else if (a->rate == b->rate)
+               return 0;
+       else
+               return 1;
+}
+
+static int load_timings_from_dt(struct tegra_clk_emc *tegra,
+                               struct device_node *node,
+                               u32 ram_code)
+{
+       struct device_node *child;
+       int child_count = of_get_child_count(node);
+       int i = 0, err;
+
+       tegra->timings = kcalloc(child_count, sizeof(struct emc_timing),
+                                GFP_KERNEL);
+       if (!tegra->timings)
+               return -ENOMEM;
+
+       tegra->num_timings = child_count;
+
+       for_each_child_of_node(node, child) {
+               struct emc_timing *timing = tegra->timings + (i++);
+
+               err = load_one_timing_from_dt(tegra, timing, child);
+               if (err)
+                       return err;
+
+               timing->ram_code = ram_code;
+       }
+
+       sort(tegra->timings, tegra->num_timings, sizeof(struct emc_timing),
+            cmp_timings, NULL);
+
+       return 0;
+}
+
+static const struct clk_ops tegra_clk_emc_ops = {
+       .recalc_rate = emc_recalc_rate,
+       .determine_rate = emc_determine_rate,
+       .set_rate = emc_set_rate,
+       .get_parent = emc_get_parent,
+};
+
+struct clk *tegra_clk_register_emc(void __iomem *base, struct device_node *np,
+                                  spinlock_t *lock)
+{
+       struct tegra_clk_emc *tegra;
+       struct clk_init_data init;
+       struct device_node *node;
+       u32 node_ram_code;
+       struct clk *clk;
+       int err;
+
+       tegra = kcalloc(1, sizeof(*tegra), GFP_KERNEL);
+       if (!tegra)
+               return ERR_PTR(-ENOMEM);
+
+       tegra->clk_regs = base;
+       tegra->lock = lock;
+
+       tegra->num_timings = 0;
+
+       for_each_child_of_node(np, node) {
+               err = of_property_read_u32(node, "nvidia,ram-code",
+                                          &node_ram_code);
+               if (err) {
+                       of_node_put(node);
+                       continue;
+               }
+
+               /*
+                * Store timings for all ram codes as we cannot read the
+                * fuses until the apbmisc driver is loaded.
+                */
+               err = load_timings_from_dt(tegra, node, node_ram_code);
+               if (err)
+                       return ERR_PTR(err);
+               of_node_put(node);
+               break;
+       }
+
+       if (tegra->num_timings == 0)
+               pr_warn("%s: no memory timings registered\n", __func__);
+
+       tegra->emc_node = of_parse_phandle(np,
+                       "nvidia,external-memory-controller", 0);
+       if (!tegra->emc_node)
+               pr_warn("%s: couldn't find node for EMC driver\n", __func__);
+
+       init.name = "emc";
+       init.ops = &tegra_clk_emc_ops;
+       init.flags = 0;
+       init.parent_names = emc_parent_clk_names;
+       init.num_parents = ARRAY_SIZE(emc_parent_clk_names);
+
+       tegra->hw.init = &init;
+
+       clk = clk_register(NULL, &tegra->hw);
+       if (IS_ERR(clk))
+               return clk;
+
+       tegra->prev_parent = clk_get_parent_by_index(
+               tegra->hw.clk, emc_get_parent(&tegra->hw));
+       tegra->changing_timing = false;
+
+       /* Allow debugging tools to see the EMC clock */
+       clk_register_clkdev(clk, "emc", "tegra-clk-debug");
+
+       clk_prepare_enable(clk);
+
+       return clk;
+};
index 11f857cd5f6a2bf01d86dc2b95497905d971a85e..e8cca3eac00742713cc8fe39f9a63c8fe9b62def 100644 (file)
@@ -152,11 +152,6 @@ static unsigned long tegra124_input_freq[] = {
        [12] = 260000000,
 };
 
-static const char *mux_pllmcp_clkm[] = {
-       "pll_m", "pll_c", "pll_p", "clk_m", "pll_m_ud", "pll_c2", "pll_c3",
-};
-#define mux_pllmcp_clkm_idx NULL
-
 static struct div_nmp pllxc_nmp = {
        .divm_shift = 0,
        .divm_width = 8,
@@ -791,7 +786,6 @@ static struct tegra_clk tegra124_clks[tegra_clk_max] __initdata = {
        [tegra_clk_i2c2] = { .dt_id = TEGRA124_CLK_I2C2, .present = true },
        [tegra_clk_uartc] = { .dt_id = TEGRA124_CLK_UARTC, .present = true },
        [tegra_clk_mipi_cal] = { .dt_id = TEGRA124_CLK_MIPI_CAL, .present = true },
-       [tegra_clk_emc] = { .dt_id = TEGRA124_CLK_EMC, .present = true },
        [tegra_clk_usb2] = { .dt_id = TEGRA124_CLK_USB2, .present = true },
        [tegra_clk_usb3] = { .dt_id = TEGRA124_CLK_USB3, .present = true },
        [tegra_clk_vde_8] = { .dt_id = TEGRA124_CLK_VDE, .present = true },
@@ -1127,13 +1121,7 @@ static __init void tegra124_periph_clk_init(void __iomem *clk_base,
                                             periph_clk_enb_refcnt);
        clks[TEGRA124_CLK_DSIB] = clk;
 
-       /* emc mux */
-       clk = clk_register_mux(NULL, "emc_mux", mux_pllmcp_clkm,
-                              ARRAY_SIZE(mux_pllmcp_clkm), 0,
-                              clk_base + CLK_SOURCE_EMC,
-                              29, 3, 0, &emc_lock);
-
-       clk = tegra_clk_register_mc("mc", "emc_mux", clk_base + CLK_SOURCE_EMC,
+       clk = tegra_clk_register_mc("mc", "emc", clk_base + CLK_SOURCE_EMC,
                                    &emc_lock);
        clks[TEGRA124_CLK_MC] = clk;
 
@@ -1389,7 +1377,6 @@ static struct tegra_clk_init_table common_init_table[] __initdata = {
        {TEGRA124_CLK_XUSB_HOST_SRC, TEGRA124_CLK_PLL_RE_OUT, 112000000, 0},
        {TEGRA124_CLK_SATA, TEGRA124_CLK_PLL_P, 104000000, 0},
        {TEGRA124_CLK_SATA_OOB, TEGRA124_CLK_PLL_P, 204000000, 0},
-       {TEGRA124_CLK_EMC, TEGRA124_CLK_CLK_MAX, 0, 1},
        {TEGRA124_CLK_MSELECT, TEGRA124_CLK_CLK_MAX, 0, 1},
        {TEGRA124_CLK_CSITE, TEGRA124_CLK_CLK_MAX, 0, 1},
        {TEGRA124_CLK_TSENSOR, TEGRA124_CLK_CLK_M, 400000, 0},
@@ -1513,6 +1500,10 @@ static void __init tegra124_132_clock_init_post(struct device_node *np)
        tegra_super_clk_gen4_init(clk_base, pmc_base, tegra124_clks,
                                  &pll_x_params);
        tegra_add_of_provider(np);
+
+       clks[TEGRA124_CLK_EMC] = tegra_clk_register_emc(clk_base, np,
+                                                       &emc_lock);
+
        tegra_register_devclks(devclks, ARRAY_SIZE(devclks));
 
        tegra_cpu_car_ops = &tegra124_cpu_car_ops;
index 4b26509fc21857ede7ea3c41ed79d4fad3175c8f..0af3e834dd24a25d3e3e0cbfa020c596d57bc908 100644 (file)
@@ -679,7 +679,7 @@ static struct tegra_devclk devclks[] __initdata = {
        { .dev_id = "tegra30-dam.1", .dt_id = TEGRA30_CLK_DAM1 },
        { .dev_id = "tegra30-dam.2", .dt_id = TEGRA30_CLK_DAM2 },
        { .con_id = "hda", .dev_id = "tegra30-hda", .dt_id = TEGRA30_CLK_HDA },
-       { .con_id = "hda2codec", .dev_id = "tegra30-hda", .dt_id = TEGRA30_CLK_HDA2CODEC_2X },
+       { .con_id = "hda2codec_2x", .dev_id = "tegra30-hda", .dt_id = TEGRA30_CLK_HDA2CODEC_2X },
        { .dev_id = "spi_tegra.0", .dt_id = TEGRA30_CLK_SBC1 },
        { .dev_id = "spi_tegra.1", .dt_id = TEGRA30_CLK_SBC2 },
        { .dev_id = "spi_tegra.2", .dt_id = TEGRA30_CLK_SBC3 },
index d6ac00647fafb05311b646f208f7175fa0e618a4..75ddc8ff8bd4aff97d61ff9ae27095aa2ba0cf33 100644 (file)
@@ -623,6 +623,18 @@ void tegra_super_clk_gen4_init(void __iomem *clk_base,
                        void __iomem *pmc_base, struct tegra_clk *tegra_clks,
                        struct tegra_clk_pll_params *pll_params);
 
+#ifdef CONFIG_TEGRA_CLK_EMC
+struct clk *tegra_clk_register_emc(void __iomem *base, struct device_node *np,
+                                  spinlock_t *lock);
+#else
+static inline struct clk *tegra_clk_register_emc(void __iomem *base,
+                                                struct device_node *np,
+                                                spinlock_t *lock)
+{
+       return NULL;
+}
+#endif
+
 void tegra114_clock_tune_cpu_trimmers_high(void);
 void tegra114_clock_tune_cpu_trimmers_low(void);
 void tegra114_clock_tune_cpu_trimmers_init(void);
index d86bc46b93bdfeae630f94a55745315a0d8c1ec8..19e543a32e2bad1e4591fb3106258d9f6769551b 100644 (file)
@@ -155,7 +155,7 @@ static int atl_clk_set_rate(struct clk_hw *hw, unsigned long rate,
        return 0;
 }
 
-const struct clk_ops atl_clk_ops = {
+static const struct clk_ops atl_clk_ops = {
        .enable         = atl_clk_enable,
        .disable        = atl_clk_disable,
        .is_enabled     = atl_clk_is_enabled,
@@ -167,7 +167,7 @@ const struct clk_ops atl_clk_ops = {
 static void __init of_dra7_atl_clock_setup(struct device_node *node)
 {
        struct dra7_atl_desc *clk_hw = NULL;
-       struct clk_init_data init = { 0 };
+       struct clk_init_data init = { NULL };
        const char **parent_names = NULL;
        struct clk *clk;
 
@@ -252,6 +252,11 @@ static int of_dra7_atl_clk_probe(struct platform_device *pdev)
                }
 
                clk = of_clk_get_from_provider(&clkspec);
+               if (IS_ERR(clk)) {
+                       pr_err("%s: failed to get atl clock %d from provider\n",
+                              __func__, i);
+                       return PTR_ERR(clk);
+               }
 
                cdesc = to_atl_desc(__clk_get_hw(clk));
                cdesc->cinfo = cinfo;
index 0ebe5c51062b9ee2c2aa8e3fbe5dd84fcb14f753..64bb5e8a3b8cd845952bb4e97ffdead89f366d97 100644 (file)
@@ -122,14 +122,14 @@ void __iomem *ti_clk_get_reg_addr(struct device_node *node, int index)
 
        if (i == CLK_MAX_MEMMAPS) {
                pr_err("clk-provider not found for %s!\n", node->name);
-               return ERR_PTR(-ENOENT);
+               return IOMEM_ERR_PTR(-ENOENT);
        }
 
        reg->index = i;
 
        if (of_property_read_u32_index(node, "reg", index, &val)) {
                pr_err("%s must have reg[%d]!\n", node->name, index);
-               return ERR_PTR(-EINVAL);
+               return IOMEM_ERR_PTR(-EINVAL);
        }
 
        reg->offset = val;
index 35fe1085480cf33da68547e76a7e126d5b95738b..b82ef07f340341052fa8a92ddacd8f65845ba843 100644 (file)
@@ -32,7 +32,7 @@ static void __init of_ti_clockdomain_setup(struct device_node *node)
        int i;
        int num_clks;
 
-       num_clks = of_count_phandle_with_args(node, "clocks", "#clock-cells");
+       num_clks = of_clk_get_parent_count(node);
 
        for (i = 0; i < num_clks; i++) {
                clk = of_clk_get(node, i);
index 11478a501c3074c53071bf9afb206b375fbda14c..2aacf7a3bcaeb137e4e7bb973cea2874ff1aa6a7 100644 (file)
@@ -177,7 +177,7 @@ cleanup:
 }
 
 #if defined(CONFIG_ARCH_OMAP3) && defined(CONFIG_ATAGS)
-void __iomem *_get_reg(u8 module, u16 offset)
+static void __iomem *_get_reg(u8 module, u16 offset)
 {
        u32 reg;
        struct clk_omap_reg *reg_setup;
index ffcd8e09e85b9eae1a1ffea5dda006b976a93fc5..730aa62454a2454f6a5311adbd16bfff57e366d2 100644 (file)
@@ -621,13 +621,13 @@ static void __init ti_fapll_setup(struct device_node *node)
 
                /* Check for hardwired audio_pll_clk1 */
                if (is_audio_pll_clk1(freq)) {
-                       freq = 0;
-                       div = 0;
+                       freq = NULL;
+                       div = NULL;
                } else {
                        /* Does the synthesizer have a FREQ register? */
                        v = readl_relaxed(freq);
                        if (!v)
-                               freq = 0;
+                               freq = NULL;
                }
                synth_clk = ti_fapll_synth_setup(fd, freq, div, output_instance,
                                                 output_name, node->name,
index 80069c370a47a1c560f05929ce7bd2aedb651514..4626b97b7d83295b06d0259a5f55574572dc6a09 100644 (file)
@@ -116,11 +116,12 @@ void u8500_clk_init(u32 clkrst1_base, u32 clkrst2_base, u32 clkrst3_base,
        clk_register_clkdev(clk, NULL, "hdmi");
        clk_register_clkdev(clk, "hdmi", "mcde");
 
-       clk = clk_reg_prcmu_gate("apeatclk", NULL, PRCMU_APEATCLK, CLK_IS_ROOT);
+       clk = clk_reg_prcmu_scalable("apeatclk", NULL, PRCMU_APEATCLK, 0,
+                                    CLK_IS_ROOT|CLK_SET_RATE_GATE);
        clk_register_clkdev(clk, NULL, "apeat");
 
-       clk = clk_reg_prcmu_gate("apetraceclk", NULL, PRCMU_APETRACECLK,
-                               CLK_IS_ROOT);
+       clk = clk_reg_prcmu_scalable("apetraceclk", NULL, PRCMU_APETRACECLK, 0,
+                               CLK_IS_ROOT|CLK_SET_RATE_GATE);
        clk_register_clkdev(clk, NULL, "apetrace");
 
        clk = clk_reg_prcmu_gate("mcdeclk", NULL, PRCMU_MCDECLK, CLK_IS_ROOT);
index 7b55ef89baa53c7ef6d59c19dcf8c9287b773199..e319ef912dc6c27bbaba940a42a4ef97a5bf07a0 100644 (file)
@@ -166,8 +166,8 @@ void u8500_of_clk_init(u32 clkrst1_base, u32 clkrst2_base, u32 clkrst3_base,
        clk = clk_reg_prcmu_gate("apeatclk", NULL, PRCMU_APEATCLK, CLK_IS_ROOT);
        prcmu_clk[PRCMU_APEATCLK] = clk;
 
-       clk = clk_reg_prcmu_gate("apetraceclk", NULL, PRCMU_APETRACECLK,
-                               CLK_IS_ROOT);
+       clk = clk_reg_prcmu_scalable("apetraceclk", NULL, PRCMU_APETRACECLK, 0,
+                               CLK_IS_ROOT|CLK_SET_RATE_GATE);
        prcmu_clk[PRCMU_APETRACECLK] = clk;
 
        clk = clk_reg_prcmu_gate("mcdeclk", NULL, PRCMU_MCDECLK, CLK_IS_ROOT);
index c6e86a9a2aa3da2313711ac0c1bc6a46032cde6c..a96dd8e53fdb2d9537a363c480418db859c8c0b1 100644 (file)
@@ -135,7 +135,7 @@ static struct clk *clk_sp810_timerclken_of_get(struct of_phandle_args *clkspec,
        return sp810->timerclken[clkspec->args[0]].clk;
 }
 
-void __init clk_sp810_of_setup(struct device_node *node)
+static void __init clk_sp810_of_setup(struct device_node *node)
 {
        struct clk_sp810 *sp810 = kzalloc(sizeof(*sp810), GFP_KERNEL);
        const char *parent_names[2];
@@ -156,7 +156,7 @@ void __init clk_sp810_of_setup(struct device_node *node)
                        "timclk");
        parent_names[1] = of_clk_get_parent_name(node, sp810->timclk_index);
 
-       if (parent_names[0] <= 0 || parent_names[1] <= 0) {
+       if (!parent_names[0] || !parent_names[1]) {
                pr_warn("Failed to obtain parent clocks for SP810!\n");
                return;
        }
index 40cb113be6af110139bf533d142b3ea304cb6010..de614384bb447512344e089a9ed56ea657f731f3 100644 (file)
@@ -85,22 +85,29 @@ static DEFINE_SPINLOCK(canmioclk_lock);
 static DEFINE_SPINLOCK(dbgclk_lock);
 static DEFINE_SPINLOCK(aperclk_lock);
 
-static const char *armpll_parents[] __initdata = {"armpll_int", "ps_clk"};
-static const char *ddrpll_parents[] __initdata = {"ddrpll_int", "ps_clk"};
-static const char *iopll_parents[] __initdata = {"iopll_int", "ps_clk"};
+static const char *const armpll_parents[] __initconst = {"armpll_int",
+       "ps_clk"};
+static const char *const ddrpll_parents[] __initconst = {"ddrpll_int",
+       "ps_clk"};
+static const char *const iopll_parents[] __initconst = {"iopll_int",
+       "ps_clk"};
 static const char *gem0_mux_parents[] __initdata = {"gem0_div1", "dummy_name"};
 static const char *gem1_mux_parents[] __initdata = {"gem1_div1", "dummy_name"};
-static const char *can0_mio_mux2_parents[] __initdata = {"can0_gate",
+static const char *const can0_mio_mux2_parents[] __initconst = {"can0_gate",
        "can0_mio_mux"};
-static const char *can1_mio_mux2_parents[] __initdata = {"can1_gate",
+static const char *const can1_mio_mux2_parents[] __initconst = {"can1_gate",
        "can1_mio_mux"};
 static const char *dbg_emio_mux_parents[] __initdata = {"dbg_div",
        "dummy_name"};
 
-static const char *dbgtrc_emio_input_names[] __initdata = {"trace_emio_clk"};
-static const char *gem0_emio_input_names[] __initdata = {"gem0_emio_clk"};
-static const char *gem1_emio_input_names[] __initdata = {"gem1_emio_clk"};
-static const char *swdt_ext_clk_input_names[] __initdata = {"swdt_ext_clk"};
+static const char *const dbgtrc_emio_input_names[] __initconst = {
+       "trace_emio_clk"};
+static const char *const gem0_emio_input_names[] __initconst = {
+       "gem0_emio_clk"};
+static const char *const gem1_emio_input_names[] __initconst = {
+       "gem1_emio_clk"};
+static const char *const swdt_ext_clk_input_names[] __initconst = {
+       "swdt_ext_clk"};
 
 static void __init zynq_clk_register_fclk(enum zynq_clk fclk,
                const char *clk_name, void __iomem *fclk_ctrl_reg,
index 611cb09239ebe1214837c1e5048e479e5c50d71e..cc8a71c267b88132496efc6bc083ed5107a7e46b 100644 (file)
@@ -36,17 +36,6 @@ config ARM_EXYNOS_CPUFREQ
 
          If in doubt, say N.
 
-config ARM_EXYNOS4210_CPUFREQ
-       bool "SAMSUNG EXYNOS4210"
-       depends on CPU_EXYNOS4210
-       depends on ARM_EXYNOS_CPUFREQ
-       default y
-       help
-         This adds the CPUFreq driver for Samsung EXYNOS4210
-         SoC (S5PV310 or S5PC210).
-
-         If in doubt, say N.
-
 config ARM_EXYNOS4X12_CPUFREQ
        bool "SAMSUNG EXYNOS4x12"
        depends on SOC_EXYNOS4212 || SOC_EXYNOS4412
index cdce92ae2e8b7fdb81e4d25e3ab03ced14e63aac..2169bf792db76cbcea69f8b5d57670004853e47b 100644 (file)
@@ -54,7 +54,6 @@ obj-$(CONFIG_ARCH_DAVINCI)            += davinci-cpufreq.o
 obj-$(CONFIG_UX500_SOC_DB8500)         += dbx500-cpufreq.o
 obj-$(CONFIG_ARM_EXYNOS_CPUFREQ)       += arm-exynos-cpufreq.o
 arm-exynos-cpufreq-y                                   := exynos-cpufreq.o
-arm-exynos-cpufreq-$(CONFIG_ARM_EXYNOS4210_CPUFREQ)    += exynos4210-cpufreq.o
 arm-exynos-cpufreq-$(CONFIG_ARM_EXYNOS4X12_CPUFREQ)    += exynos4x12-cpufreq.o
 arm-exynos-cpufreq-$(CONFIG_ARM_EXYNOS5250_CPUFREQ)    += exynos5250-cpufreq.o
 obj-$(CONFIG_ARM_EXYNOS5440_CPUFREQ)   += exynos5440-cpufreq.o
index 82d2fbb20f7eb70d94a9c9c6e1d6ec3708f53ee0..fb24aaf4adcf8099c04a4f2de5eb558a56292707 100644 (file)
@@ -168,10 +168,7 @@ static int exynos_cpufreq_probe(struct platform_device *pdev)
 
        exynos_info->dev = &pdev->dev;
 
-       if (of_machine_is_compatible("samsung,exynos4210")) {
-               exynos_info->type = EXYNOS_SOC_4210;
-               ret = exynos4210_cpufreq_init(exynos_info);
-       } else if (of_machine_is_compatible("samsung,exynos4212")) {
+       if (of_machine_is_compatible("samsung,exynos4212")) {
                exynos_info->type = EXYNOS_SOC_4212;
                ret = exynos4x12_cpufreq_init(exynos_info);
        } else if (of_machine_is_compatible("samsung,exynos4412")) {
index 9f2062a7cc02ea2500be4f1d54218f0b78d6c127..a3855e4d913d6bf34c429c019fa5d9ec07e660cb 100644 (file)
@@ -18,7 +18,6 @@ enum cpufreq_level_index {
 };
 
 enum exynos_soc_type {
-       EXYNOS_SOC_4210,
        EXYNOS_SOC_4212,
        EXYNOS_SOC_4412,
        EXYNOS_SOC_5250,
@@ -53,14 +52,6 @@ struct exynos_dvfs_info {
        void __iomem    *cmu_regs;
 };
 
-#ifdef CONFIG_ARM_EXYNOS4210_CPUFREQ
-extern int exynos4210_cpufreq_init(struct exynos_dvfs_info *);
-#else
-static inline int exynos4210_cpufreq_init(struct exynos_dvfs_info *info)
-{
-       return -EOPNOTSUPP;
-}
-#endif
 #ifdef CONFIG_ARM_EXYNOS4X12_CPUFREQ
 extern int exynos4x12_cpufreq_init(struct exynos_dvfs_info *);
 #else
diff --git a/drivers/cpufreq/exynos4210-cpufreq.c b/drivers/cpufreq/exynos4210-cpufreq.c
deleted file mode 100644 (file)
index 843ec82..0000000
+++ /dev/null
@@ -1,184 +0,0 @@
-/*
- * Copyright (c) 2010-2011 Samsung Electronics Co., Ltd.
- *             http://www.samsung.com
- *
- * EXYNOS4210 - CPU frequency scaling support
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
-*/
-
-#include <linux/module.h>
-#include <linux/kernel.h>
-#include <linux/err.h>
-#include <linux/clk.h>
-#include <linux/io.h>
-#include <linux/slab.h>
-#include <linux/cpufreq.h>
-#include <linux/of.h>
-#include <linux/of_address.h>
-
-#include "exynos-cpufreq.h"
-
-static struct clk *cpu_clk;
-static struct clk *moutcore;
-static struct clk *mout_mpll;
-static struct clk *mout_apll;
-static struct exynos_dvfs_info *cpufreq;
-
-static unsigned int exynos4210_volt_table[] = {
-       1250000, 1150000, 1050000, 975000, 950000,
-};
-
-static struct cpufreq_frequency_table exynos4210_freq_table[] = {
-       {0, L0, 1200 * 1000},
-       {0, L1, 1000 * 1000},
-       {0, L2,  800 * 1000},
-       {0, L3,  500 * 1000},
-       {0, L4,  200 * 1000},
-       {0, 0, CPUFREQ_TABLE_END},
-};
-
-static struct apll_freq apll_freq_4210[] = {
-       /*
-        * values:
-        * freq
-        * clock divider for CORE, COREM0, COREM1, PERIPH, ATB, PCLK_DBG, APLL, RESERVED
-        * clock divider for COPY, HPM, RESERVED
-        * PLL M, P, S
-        */
-       APLL_FREQ(1200, 0, 3, 7, 3, 4, 1, 7, 0, 5, 0, 0, 150, 3, 1),
-       APLL_FREQ(1000, 0, 3, 7, 3, 4, 1, 7, 0, 4, 0, 0, 250, 6, 1),
-       APLL_FREQ(800,  0, 3, 7, 3, 3, 1, 7, 0, 3, 0, 0, 200, 6, 1),
-       APLL_FREQ(500,  0, 3, 7, 3, 3, 1, 7, 0, 3, 0, 0, 250, 6, 2),
-       APLL_FREQ(200,  0, 1, 3, 1, 3, 1, 0, 0, 3, 0, 0, 200, 6, 3),
-};
-
-static void exynos4210_set_clkdiv(unsigned int div_index)
-{
-       unsigned int tmp;
-
-       /* Change Divider - CPU0 */
-
-       tmp = apll_freq_4210[div_index].clk_div_cpu0;
-
-       __raw_writel(tmp, cpufreq->cmu_regs + EXYNOS4_CLKDIV_CPU);
-
-       do {
-               tmp = __raw_readl(cpufreq->cmu_regs + EXYNOS4_CLKDIV_STATCPU);
-       } while (tmp & 0x1111111);
-
-       /* Change Divider - CPU1 */
-
-       tmp = apll_freq_4210[div_index].clk_div_cpu1;
-
-       __raw_writel(tmp, cpufreq->cmu_regs + EXYNOS4_CLKDIV_CPU1);
-
-       do {
-               tmp = __raw_readl(cpufreq->cmu_regs + EXYNOS4_CLKDIV_STATCPU1);
-       } while (tmp & 0x11);
-}
-
-static void exynos4210_set_apll(unsigned int index)
-{
-       unsigned int tmp, freq = apll_freq_4210[index].freq;
-
-       /* MUX_CORE_SEL = MPLL, ARMCLK uses MPLL for lock time */
-       clk_set_parent(moutcore, mout_mpll);
-
-       do {
-               tmp = (__raw_readl(cpufreq->cmu_regs + EXYNOS4_CLKMUX_STATCPU)
-                       >> EXYNOS4_CLKSRC_CPU_MUXCORE_SHIFT);
-               tmp &= 0x7;
-       } while (tmp != 0x2);
-
-       clk_set_rate(mout_apll, freq * 1000);
-
-       /* MUX_CORE_SEL = APLL */
-       clk_set_parent(moutcore, mout_apll);
-
-       do {
-               tmp = __raw_readl(cpufreq->cmu_regs + EXYNOS4_CLKMUX_STATCPU);
-               tmp &= EXYNOS4_CLKMUX_STATCPU_MUXCORE_MASK;
-       } while (tmp != (0x1 << EXYNOS4_CLKSRC_CPU_MUXCORE_SHIFT));
-}
-
-static void exynos4210_set_frequency(unsigned int old_index,
-                                    unsigned int new_index)
-{
-       if (old_index > new_index) {
-               exynos4210_set_clkdiv(new_index);
-               exynos4210_set_apll(new_index);
-       } else if (old_index < new_index) {
-               exynos4210_set_apll(new_index);
-               exynos4210_set_clkdiv(new_index);
-       }
-}
-
-int exynos4210_cpufreq_init(struct exynos_dvfs_info *info)
-{
-       struct device_node *np;
-       unsigned long rate;
-
-       /*
-        * HACK: This is a temporary workaround to get access to clock
-        * controller registers directly and remove static mappings and
-        * dependencies on platform headers. It is necessary to enable
-        * Exynos multi-platform support and will be removed together with
-        * this whole driver as soon as Exynos gets migrated to use
-        * cpufreq-dt driver.
-        */
-       np = of_find_compatible_node(NULL, NULL, "samsung,exynos4210-clock");
-       if (!np) {
-               pr_err("%s: failed to find clock controller DT node\n",
-                       __func__);
-               return -ENODEV;
-       }
-
-       info->cmu_regs = of_iomap(np, 0);
-       if (!info->cmu_regs) {
-               pr_err("%s: failed to map CMU registers\n", __func__);
-               return -EFAULT;
-       }
-
-       cpu_clk = clk_get(NULL, "armclk");
-       if (IS_ERR(cpu_clk))
-               return PTR_ERR(cpu_clk);
-
-       moutcore = clk_get(NULL, "moutcore");
-       if (IS_ERR(moutcore))
-               goto err_moutcore;
-
-       mout_mpll = clk_get(NULL, "mout_mpll");
-       if (IS_ERR(mout_mpll))
-               goto err_mout_mpll;
-
-       rate = clk_get_rate(mout_mpll) / 1000;
-
-       mout_apll = clk_get(NULL, "mout_apll");
-       if (IS_ERR(mout_apll))
-               goto err_mout_apll;
-
-       info->mpll_freq_khz = rate;
-       /* 800Mhz */
-       info->pll_safe_idx = L2;
-       info->cpu_clk = cpu_clk;
-       info->volt_table = exynos4210_volt_table;
-       info->freq_table = exynos4210_freq_table;
-       info->set_freq = exynos4210_set_frequency;
-
-       cpufreq = info;
-
-       return 0;
-
-err_mout_apll:
-       clk_put(mout_mpll);
-err_mout_mpll:
-       clk_put(moutcore);
-err_moutcore:
-       clk_put(cpu_clk);
-
-       pr_debug("%s: failed initialization\n", __func__);
-       return -EINVAL;
-}
diff --git a/include/dt-bindings/clock/bcm-cygnus.h b/include/dt-bindings/clock/bcm-cygnus.h
new file mode 100644 (file)
index 0000000..32fbc47
--- /dev/null
@@ -0,0 +1,68 @@
+/*
+ *  BSD LICENSE
+ *
+ *  Copyright(c) 2014 Broadcom Corporation.  All rights reserved.
+ *
+ *  Redistribution and use in source and binary forms, with or without
+ *  modification, are permitted provided that the following conditions
+ *  are met:
+ *
+ *    * Redistributions of source code must retain the above copyright
+ *      notice, this list of conditions and the following disclaimer.
+ *    * Redistributions in binary form must reproduce the above copyright
+ *      notice, this list of conditions and the following disclaimer in
+ *      the documentation and/or other materials provided with the
+ *      distribution.
+ *    * Neither the name of Broadcom Corporation nor the names of its
+ *      contributors may be used to endorse or promote products derived
+ *      from this software without specific prior written permission.
+ *
+ *  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ *  "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ *  LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ *  A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ *  OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ *  SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ *  LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ *  DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ *  THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ *  (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef _CLOCK_BCM_CYGNUS_H
+#define _CLOCK_BCM_CYGNUS_H
+
+/* GENPLL clock ID */
+#define BCM_CYGNUS_GENPLL                     0
+#define BCM_CYGNUS_GENPLL_AXI21_CLK           1
+#define BCM_CYGNUS_GENPLL_250MHZ_CLK          2
+#define BCM_CYGNUS_GENPLL_IHOST_SYS_CLK       3
+#define BCM_CYGNUS_GENPLL_ENET_SW_CLK         4
+#define BCM_CYGNUS_GENPLL_AUDIO_125_CLK       5
+#define BCM_CYGNUS_GENPLL_CAN_CLK             6
+
+/* LCPLL0 clock ID */
+#define BCM_CYGNUS_LCPLL0                     0
+#define BCM_CYGNUS_LCPLL0_PCIE_PHY_REF_CLK    1
+#define BCM_CYGNUS_LCPLL0_DDR_PHY_CLK         2
+#define BCM_CYGNUS_LCPLL0_SDIO_CLK            3
+#define BCM_CYGNUS_LCPLL0_USB_PHY_REF_CLK     4
+#define BCM_CYGNUS_LCPLL0_SMART_CARD_CLK      5
+#define BCM_CYGNUS_LCPLL0_CH5_UNUSED          6
+
+/* MIPI PLL clock ID */
+#define BCM_CYGNUS_MIPIPLL                    0
+#define BCM_CYGNUS_MIPIPLL_CH0_UNUSED         1
+#define BCM_CYGNUS_MIPIPLL_CH1_LCD            2
+#define BCM_CYGNUS_MIPIPLL_CH2_V3D            3
+#define BCM_CYGNUS_MIPIPLL_CH3_UNUSED         4
+#define BCM_CYGNUS_MIPIPLL_CH4_UNUSED         5
+#define BCM_CYGNUS_MIPIPLL_CH5_UNUSED         6
+
+/* ASIU clock ID */
+#define BCM_CYGNUS_ASIU_KEYPAD_CLK    0
+#define BCM_CYGNUS_ASIU_ADC_CLK       1
+#define BCM_CYGNUS_ASIU_PWM_CLK       2
+
+#endif /* _CLOCK_BCM_CYGNUS_H */
diff --git a/include/dt-bindings/clock/hi6220-clock.h b/include/dt-bindings/clock/hi6220-clock.h
new file mode 100644 (file)
index 0000000..70ee383
--- /dev/null
@@ -0,0 +1,173 @@
+/*
+ * Copyright (c) 2015 Hisilicon Limited.
+ *
+ * Author: Bintian Wang <bintian.wang@huawei.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#ifndef __DT_BINDINGS_CLOCK_HI6220_H
+#define __DT_BINDINGS_CLOCK_HI6220_H
+
+/* clk in Hi6220 AO (always on) controller */
+#define HI6220_NONE_CLOCK      0
+
+/* fixed rate clocks */
+#define HI6220_REF32K          1
+#define HI6220_CLK_TCXO                2
+#define HI6220_MMC1_PAD                3
+#define HI6220_MMC2_PAD                4
+#define HI6220_MMC0_PAD                5
+#define HI6220_PLL_BBP         6
+#define HI6220_PLL_GPU         7
+#define HI6220_PLL1_DDR                8
+#define HI6220_PLL_SYS         9
+#define HI6220_PLL_SYS_MEDIA   10
+#define HI6220_DDR_SRC         11
+#define HI6220_PLL_MEDIA       12
+#define HI6220_PLL_DDR         13
+
+/* fixed factor clocks */
+#define HI6220_300M            14
+#define HI6220_150M            15
+#define HI6220_PICOPHY_SRC     16
+#define HI6220_MMC0_SRC_SEL    17
+#define HI6220_MMC1_SRC_SEL    18
+#define HI6220_MMC2_SRC_SEL    19
+#define HI6220_VPU_CODEC       20
+#define HI6220_MMC0_SMP                21
+#define HI6220_MMC1_SMP                22
+#define HI6220_MMC2_SMP                23
+
+/* gate clocks */
+#define HI6220_WDT0_PCLK       24
+#define HI6220_WDT1_PCLK       25
+#define HI6220_WDT2_PCLK       26
+#define HI6220_TIMER0_PCLK     27
+#define HI6220_TIMER1_PCLK     28
+#define HI6220_TIMER2_PCLK     29
+#define HI6220_TIMER3_PCLK     30
+#define HI6220_TIMER4_PCLK     31
+#define HI6220_TIMER5_PCLK     32
+#define HI6220_TIMER6_PCLK     33
+#define HI6220_TIMER7_PCLK     34
+#define HI6220_TIMER8_PCLK     35
+#define HI6220_UART0_PCLK      36
+
+#define HI6220_AO_NR_CLKS      37
+
+/* clk in Hi6220 systrl */
+/* gate clock */
+#define HI6220_MMC0_CLK                1
+#define HI6220_MMC0_CIUCLK     2
+#define HI6220_MMC1_CLK                3
+#define HI6220_MMC1_CIUCLK     4
+#define HI6220_MMC2_CLK                5
+#define HI6220_MMC2_CIUCLK     6
+#define HI6220_USBOTG_HCLK     7
+#define HI6220_CLK_PICOPHY     8
+#define HI6220_HIFI            9
+#define HI6220_DACODEC_PCLK    10
+#define HI6220_EDMAC_ACLK      11
+#define HI6220_CS_ATB          12
+#define HI6220_I2C0_CLK                13
+#define HI6220_I2C1_CLK                14
+#define HI6220_I2C2_CLK                15
+#define HI6220_I2C3_CLK                16
+#define HI6220_UART1_PCLK      17
+#define HI6220_UART2_PCLK      18
+#define HI6220_UART3_PCLK      19
+#define HI6220_UART4_PCLK      20
+#define HI6220_SPI_CLK         21
+#define HI6220_TSENSOR_CLK     22
+#define HI6220_MMU_CLK         23
+#define HI6220_HIFI_SEL                24
+#define HI6220_MMC0_SYSPLL     25
+#define HI6220_MMC1_SYSPLL     26
+#define HI6220_MMC2_SYSPLL     27
+#define HI6220_MMC0_SEL                28
+#define HI6220_MMC1_SEL                29
+#define HI6220_BBPPLL_SEL      30
+#define HI6220_MEDIA_PLL_SRC   31
+#define HI6220_MMC2_SEL                32
+#define HI6220_CS_ATB_SYSPLL   33
+
+/* mux clocks */
+#define HI6220_MMC0_SRC                34
+#define HI6220_MMC0_SMP_IN     35
+#define HI6220_MMC1_SRC                36
+#define HI6220_MMC1_SMP_IN     37
+#define HI6220_MMC2_SRC                38
+#define HI6220_MMC2_SMP_IN     39
+#define HI6220_HIFI_SRC                40
+#define HI6220_UART1_SRC       41
+#define HI6220_UART2_SRC       42
+#define HI6220_UART3_SRC       43
+#define HI6220_UART4_SRC       44
+#define HI6220_MMC0_MUX0       45
+#define HI6220_MMC1_MUX0       46
+#define HI6220_MMC2_MUX0       47
+#define HI6220_MMC0_MUX1       48
+#define HI6220_MMC1_MUX1       49
+#define HI6220_MMC2_MUX1       50
+
+/* divider clocks */
+#define HI6220_CLK_BUS         51
+#define HI6220_MMC0_DIV                52
+#define HI6220_MMC1_DIV                53
+#define HI6220_MMC2_DIV                54
+#define HI6220_HIFI_DIV                55
+#define HI6220_BBPPLL0_DIV     56
+#define HI6220_CS_DAPB         57
+#define HI6220_CS_ATB_DIV      58
+
+#define HI6220_SYS_NR_CLKS     59
+
+/* clk in Hi6220 media controller */
+/* gate clocks */
+#define HI6220_DSI_PCLK                1
+#define HI6220_G3D_PCLK                2
+#define HI6220_ACLK_CODEC_VPU  3
+#define HI6220_ISP_SCLK                4
+#define HI6220_ADE_CORE                5
+#define HI6220_MED_MMU         6
+#define HI6220_CFG_CSI4PHY     7
+#define HI6220_CFG_CSI2PHY     8
+#define HI6220_ISP_SCLK_GATE   9
+#define HI6220_ISP_SCLK_GATE1  10
+#define HI6220_ADE_CORE_GATE   11
+#define HI6220_CODEC_VPU_GATE  12
+#define HI6220_MED_SYSPLL      13
+
+/* mux clocks */
+#define HI6220_1440_1200       14
+#define HI6220_1000_1200       15
+#define HI6220_1000_1440       16
+
+/* divider clocks */
+#define HI6220_CODEC_JPEG      17
+#define HI6220_ISP_SCLK_SRC    18
+#define HI6220_ISP_SCLK1       19
+#define HI6220_ADE_CORE_SRC    20
+#define HI6220_ADE_PIX_SRC     21
+#define HI6220_G3D_CLK         22
+#define HI6220_CODEC_VPU_SRC   23
+
+#define HI6220_MEDIA_NR_CLKS   24
+
+/* clk in Hi6220 power controller */
+/* gate clocks */
+#define HI6220_PLL_GPU_GATE    1
+#define HI6220_PLL1_DDR_GATE   2
+#define HI6220_PLL_DDR_GATE    3
+#define HI6220_PLL_MEDIA_GATE  4
+#define HI6220_PLL0_BBP_GATE   5
+
+/* divider clocks */
+#define HI6220_DDRC_SRC                6
+#define HI6220_DDRC_AXI1       7
+
+#define HI6220_POWER_NR_CLKS   8
+#endif
diff --git a/include/dt-bindings/clock/lpc18xx-ccu.h b/include/dt-bindings/clock/lpc18xx-ccu.h
new file mode 100644 (file)
index 0000000..bbfe00b
--- /dev/null
@@ -0,0 +1,74 @@
+/*
+ * Copyright (c) 2015 Joachim Eastwood <manabian@gmail.com>
+ *
+ * This code is released using a dual license strategy: BSD/GPL
+ * You can choose the licence that better fits your requirements.
+ *
+ * Released under the terms of 3-clause BSD License
+ * Released under the terms of GNU General Public License Version 2.0
+ *
+ */
+
+/* Clock Control Unit 1 (CCU1) clock offsets */
+#define CLK_APB3_BUS           0x100
+#define CLK_APB3_I2C1          0x108
+#define CLK_APB3_DAC           0x110
+#define CLK_APB3_ADC0          0x118
+#define CLK_APB3_ADC1          0x120
+#define CLK_APB3_CAN0          0x128
+#define CLK_APB1_BUS           0x200
+#define CLK_APB1_MOTOCON_PWM   0x208
+#define CLK_APB1_I2C0          0x210
+#define CLK_APB1_I2S           0x218
+#define CLK_APB1_CAN1          0x220
+#define CLK_SPIFI              0x300
+#define CLK_CPU_BUS            0x400
+#define CLK_CPU_SPIFI          0x408
+#define CLK_CPU_GPIO           0x410
+#define CLK_CPU_LCD            0x418
+#define CLK_CPU_ETHERNET       0x420
+#define CLK_CPU_USB0           0x428
+#define CLK_CPU_EMC            0x430
+#define CLK_CPU_SDIO           0x438
+#define CLK_CPU_DMA            0x440
+#define CLK_CPU_CORE           0x448
+#define CLK_CPU_SCT            0x468
+#define CLK_CPU_USB1           0x470
+#define CLK_CPU_EMCDIV         0x478
+#define CLK_CPU_FLASHA         0x480
+#define CLK_CPU_FLASHB         0x488
+#define CLK_CPU_M0APP          0x490
+#define CLK_CPU_ADCHS          0x498
+#define CLK_CPU_EEPROM         0x4a0
+#define CLK_CPU_WWDT           0x500
+#define CLK_CPU_UART0          0x508
+#define CLK_CPU_UART1          0x510
+#define CLK_CPU_SSP0           0x518
+#define CLK_CPU_TIMER0         0x520
+#define CLK_CPU_TIMER1         0x528
+#define CLK_CPU_SCU            0x530
+#define CLK_CPU_CREG           0x538
+#define CLK_CPU_RITIMER                0x600
+#define CLK_CPU_UART2          0x608
+#define CLK_CPU_UART3          0x610
+#define CLK_CPU_TIMER2         0x618
+#define CLK_CPU_TIMER3         0x620
+#define CLK_CPU_SSP1           0x628
+#define CLK_CPU_QEI            0x630
+#define CLK_PERIPH_BUS         0x700
+#define CLK_PERIPH_CORE                0x710
+#define CLK_PERIPH_SGPIO       0x718
+#define CLK_USB0               0x800
+#define CLK_USB1               0x900
+#define CLK_SPI                        0xA00
+#define CLK_ADCHS              0xB00
+
+/* Clock Control Unit 2 (CCU2) clock offsets */
+#define CLK_AUDIO              0x100
+#define CLK_APB2_UART3         0x200
+#define CLK_APB2_UART2         0x300
+#define CLK_APB0_UART1         0x400
+#define CLK_APB0_UART0         0x500
+#define CLK_APB2_SSP1          0x600
+#define CLK_APB0_SSP0          0x700
+#define CLK_SDIO               0x800
diff --git a/include/dt-bindings/clock/lpc18xx-cgu.h b/include/dt-bindings/clock/lpc18xx-cgu.h
new file mode 100644 (file)
index 0000000..6e57c6d
--- /dev/null
@@ -0,0 +1,41 @@
+/*
+ * Copyright (c) 2015 Joachim Eastwood <manabian@gmail.com>
+ *
+ * This code is released using a dual license strategy: BSD/GPL
+ * You can choose the licence that better fits your requirements.
+ *
+ * Released under the terms of 3-clause BSD License
+ * Released under the terms of GNU General Public License Version 2.0
+ *
+ */
+
+/* LPC18xx/43xx base clock ids */
+#define BASE_SAFE_CLK          0
+#define BASE_USB0_CLK          1
+#define BASE_PERIPH_CLK                2
+#define BASE_USB1_CLK          3
+#define BASE_CPU_CLK           4
+#define BASE_SPIFI_CLK         5
+#define BASE_SPI_CLK           6
+#define BASE_PHY_RX_CLK                7
+#define BASE_PHY_TX_CLK                8
+#define BASE_APB1_CLK          9
+#define BASE_APB3_CLK          10
+#define BASE_LCD_CLK           11
+#define BASE_ADCHS_CLK         12
+#define BASE_SDIO_CLK          13
+#define BASE_SSP0_CLK          14
+#define BASE_SSP1_CLK          15
+#define BASE_UART0_CLK         16
+#define BASE_UART1_CLK         17
+#define BASE_UART2_CLK         18
+#define BASE_UART3_CLK         19
+#define BASE_OUT_CLK           20
+#define BASE_RES1_CLK          21
+#define BASE_RES2_CLK          22
+#define BASE_RES3_CLK          23
+#define BASE_RES4_CLK          24
+#define BASE_AUDIO_CLK         25
+#define BASE_CGU_OUT0_CLK      26
+#define BASE_CGU_OUT1_CLK      27
+#define BASE_CLK_MAX           (BASE_CGU_OUT1_CLK + 1)
index 591f7fba89e2ea89d57c2dd6b02c4aace50d83d8..7a510384a82ae19e1776bfc771b6a6626c987a9e 100644 (file)
@@ -48,6 +48,7 @@
 #define MMP2_CLK_SSP1                  78
 #define MMP2_CLK_SSP2                  79
 #define MMP2_CLK_SSP3                  80
+#define MMP2_CLK_TIMER                 81
 
 /* axi periphrals */
 #define MMP2_CLK_SDH0                  101
index 79630b9d74b81b4c81582d74fd5b74bbe037a455..3e45bdfe1aa45f60a6cb976304053202bda4ab8a 100644 (file)
@@ -18,7 +18,9 @@
 #define PXA168_CLK_PLL1_13_1_5         18
 #define PXA168_CLK_PLL1_2_1_5          19
 #define PXA168_CLK_PLL1_3_16           20
+#define PXA168_CLK_PLL1_192            21
 #define PXA168_CLK_UART_PLL            27
+#define PXA168_CLK_USB_PLL             28
 
 /* apb periphrals */
 #define PXA168_CLK_TWSI0               60
@@ -40,6 +42,7 @@
 #define PXA168_CLK_SSP2                        76
 #define PXA168_CLK_SSP3                        77
 #define PXA168_CLK_SSP4                        78
+#define PXA168_CLK_TIMER               79
 
 /* axi periphrals */
 #define PXA168_CLK_DFC                 100
diff --git a/include/dt-bindings/clock/marvell,pxa1928.h b/include/dt-bindings/clock/marvell,pxa1928.h
new file mode 100644 (file)
index 0000000..d4f2e18
--- /dev/null
@@ -0,0 +1,57 @@
+#ifndef __DTS_MARVELL_PXA1928_CLOCK_H
+#define __DTS_MARVELL_PXA1928_CLOCK_H
+
+/*
+ * Clock ID values here correspond to the control register offset/4.
+ */
+
+/* apb peripherals */
+#define PXA1928_CLK_RTC                        0x00
+#define PXA1928_CLK_TWSI0              0x01
+#define PXA1928_CLK_TWSI1              0x02
+#define PXA1928_CLK_TWSI2              0x03
+#define PXA1928_CLK_TWSI3              0x04
+#define PXA1928_CLK_OWIRE              0x05
+#define PXA1928_CLK_KPC                        0x06
+#define PXA1928_CLK_TB_ROTARY          0x07
+#define PXA1928_CLK_SW_JTAG            0x08
+#define PXA1928_CLK_TIMER1             0x09
+#define PXA1928_CLK_UART0              0x0b
+#define PXA1928_CLK_UART1              0x0c
+#define PXA1928_CLK_UART2              0x0d
+#define PXA1928_CLK_GPIO               0x0e
+#define PXA1928_CLK_PWM0               0x0f
+#define PXA1928_CLK_PWM1               0x10
+#define PXA1928_CLK_PWM2               0x11
+#define PXA1928_CLK_PWM3               0x12
+#define PXA1928_CLK_SSP0               0x13
+#define PXA1928_CLK_SSP1               0x14
+#define PXA1928_CLK_SSP2               0x15
+
+#define PXA1928_CLK_TWSI4              0x1f
+#define PXA1928_CLK_TWSI5              0x20
+#define PXA1928_CLK_UART3              0x22
+#define PXA1928_CLK_THSENS_GLOB                0x24
+#define PXA1928_CLK_THSENS_CPU         0x26
+#define PXA1928_CLK_THSENS_VPU         0x27
+#define PXA1928_CLK_THSENS_GC          0x28
+#define PXA1928_APBC_NR_CLKS           0x30
+
+
+/* axi peripherals */
+#define PXA1928_CLK_SDH0               0x15
+#define PXA1928_CLK_SDH1               0x16
+#define PXA1928_CLK_USB                        0x17
+#define PXA1928_CLK_NAND               0x18
+#define PXA1928_CLK_DMA                        0x19
+
+#define PXA1928_CLK_SDH2               0x3a
+#define PXA1928_CLK_SDH3               0x3b
+#define PXA1928_CLK_HSIC               0x3e
+#define PXA1928_CLK_SDH4               0x57
+#define PXA1928_CLK_GC3D               0x5d
+#define PXA1928_CLK_GC2D               0x5f
+
+#define PXA1928_APMU_NR_CLKS           0x60
+
+#endif
index 719cffb2bea207e43b9fe40498401e14bb7d9151..135082a0b62f6c472421f9dbcb568d9d92de8554 100644 (file)
@@ -18,7 +18,9 @@
 #define PXA910_CLK_PLL1_13_1_5         18
 #define PXA910_CLK_PLL1_2_1_5          19
 #define PXA910_CLK_PLL1_3_16           20
+#define PXA910_CLK_PLL1_192            21
 #define PXA910_CLK_UART_PLL            27
+#define PXA910_CLK_USB_PLL             28
 
 /* apb periphrals */
 #define PXA910_CLK_TWSI0               60
@@ -37,6 +39,8 @@
 #define PXA910_CLK_UART2               73
 #define PXA910_CLK_SSP0                        74
 #define PXA910_CLK_SSP1                        75
+#define PXA910_CLK_TIMER0              76
+#define PXA910_CLK_TIMER1              77
 
 /* axi periphrals */
 #define PXA910_CLK_DFC                 100
diff --git a/include/dt-bindings/clock/meson8b-clkc.h b/include/dt-bindings/clock/meson8b-clkc.h
new file mode 100644 (file)
index 0000000..bd2720d
--- /dev/null
@@ -0,0 +1,25 @@
+/*
+ * Meson8b clock tree IDs
+ */
+
+#ifndef __MESON8B_CLKC_H
+#define __MESON8B_CLKC_H
+
+#define CLKID_UNUSED           0
+#define CLKID_XTAL             1
+#define CLKID_PLL_FIXED                2
+#define CLKID_PLL_VID          3
+#define CLKID_PLL_SYS          4
+#define CLKID_FCLK_DIV2                5
+#define CLKID_FCLK_DIV3                6
+#define CLKID_FCLK_DIV4                7
+#define CLKID_FCLK_DIV5                8
+#define CLKID_FCLK_DIV7                9
+#define CLKID_CLK81            10
+#define CLKID_MALI             11
+#define CLKID_CPUCLK           12
+#define CLKID_ZERO             13
+
+#define CLK_NR_CLKS            (CLKID_ZERO + 1)
+
+#endif /* __MESON8B_CLKC_H */
diff --git a/include/dt-bindings/clock/mt8135-clk.h b/include/dt-bindings/clock/mt8135-clk.h
new file mode 100644 (file)
index 0000000..6dac6c0
--- /dev/null
@@ -0,0 +1,194 @@
+/*
+ * Copyright (c) 2014 MediaTek Inc.
+ * Author: James Liao <jamesjj.liao@mediatek.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#ifndef _DT_BINDINGS_CLK_MT8135_H
+#define _DT_BINDINGS_CLK_MT8135_H
+
+/* TOPCKGEN */
+
+#define CLK_TOP_DSI0_LNTC_DSICLK       1
+#define CLK_TOP_HDMITX_CLKDIG_CTS      2
+#define CLK_TOP_CLKPH_MCK              3
+#define CLK_TOP_CPUM_TCK_IN            4
+#define CLK_TOP_MAINPLL_806M           5
+#define CLK_TOP_MAINPLL_537P3M         6
+#define CLK_TOP_MAINPLL_322P4M         7
+#define CLK_TOP_MAINPLL_230P3M         8
+#define CLK_TOP_UNIVPLL_624M           9
+#define CLK_TOP_UNIVPLL_416M           10
+#define CLK_TOP_UNIVPLL_249P6M         11
+#define CLK_TOP_UNIVPLL_178P3M         12
+#define CLK_TOP_UNIVPLL_48M            13
+#define CLK_TOP_MMPLL_D2               14
+#define CLK_TOP_MMPLL_D3               15
+#define CLK_TOP_MMPLL_D5               16
+#define CLK_TOP_MMPLL_D7               17
+#define CLK_TOP_MMPLL_D4               18
+#define CLK_TOP_MMPLL_D6               19
+#define CLK_TOP_SYSPLL_D2              20
+#define CLK_TOP_SYSPLL_D4              21
+#define CLK_TOP_SYSPLL_D6              22
+#define CLK_TOP_SYSPLL_D8              23
+#define CLK_TOP_SYSPLL_D10             24
+#define CLK_TOP_SYSPLL_D12             25
+#define CLK_TOP_SYSPLL_D16             26
+#define CLK_TOP_SYSPLL_D24             27
+#define CLK_TOP_SYSPLL_D3              28
+#define CLK_TOP_SYSPLL_D2P5            29
+#define CLK_TOP_SYSPLL_D5              30
+#define CLK_TOP_SYSPLL_D3P5            31
+#define CLK_TOP_UNIVPLL1_D2            32
+#define CLK_TOP_UNIVPLL1_D4            33
+#define CLK_TOP_UNIVPLL1_D6            34
+#define CLK_TOP_UNIVPLL1_D8            35
+#define CLK_TOP_UNIVPLL1_D10           36
+#define CLK_TOP_UNIVPLL2_D2            37
+#define CLK_TOP_UNIVPLL2_D4            38
+#define CLK_TOP_UNIVPLL2_D6            39
+#define CLK_TOP_UNIVPLL2_D8            40
+#define CLK_TOP_UNIVPLL_D3             41
+#define CLK_TOP_UNIVPLL_D5             42
+#define CLK_TOP_UNIVPLL_D7             43
+#define CLK_TOP_UNIVPLL_D10            44
+#define CLK_TOP_UNIVPLL_D26            45
+#define CLK_TOP_APLL                   46
+#define CLK_TOP_APLL_D4                        47
+#define CLK_TOP_APLL_D8                        48
+#define CLK_TOP_APLL_D16               49
+#define CLK_TOP_APLL_D24               50
+#define CLK_TOP_LVDSPLL_D2             51
+#define CLK_TOP_LVDSPLL_D4             52
+#define CLK_TOP_LVDSPLL_D8             53
+#define CLK_TOP_LVDSTX_CLKDIG_CT       54
+#define CLK_TOP_VPLL_DPIX              55
+#define CLK_TOP_TVHDMI_H               56
+#define CLK_TOP_HDMITX_CLKDIG_D2       57
+#define CLK_TOP_HDMITX_CLKDIG_D3       58
+#define CLK_TOP_TVHDMI_D2              59
+#define CLK_TOP_TVHDMI_D4              60
+#define CLK_TOP_MEMPLL_MCK_D4          61
+#define CLK_TOP_AXI_SEL                        62
+#define CLK_TOP_SMI_SEL                        63
+#define CLK_TOP_MFG_SEL                        64
+#define CLK_TOP_IRDA_SEL               65
+#define CLK_TOP_CAM_SEL                        66
+#define CLK_TOP_AUD_INTBUS_SEL         67
+#define CLK_TOP_JPG_SEL                        68
+#define CLK_TOP_DISP_SEL               69
+#define CLK_TOP_MSDC30_1_SEL           70
+#define CLK_TOP_MSDC30_2_SEL           71
+#define CLK_TOP_MSDC30_3_SEL           72
+#define CLK_TOP_MSDC30_4_SEL           73
+#define CLK_TOP_USB20_SEL              74
+#define CLK_TOP_VENC_SEL               75
+#define CLK_TOP_SPI_SEL                        76
+#define CLK_TOP_UART_SEL               77
+#define CLK_TOP_MEM_SEL                        78
+#define CLK_TOP_CAMTG_SEL              79
+#define CLK_TOP_AUDIO_SEL              80
+#define CLK_TOP_FIX_SEL                        81
+#define CLK_TOP_VDEC_SEL               82
+#define CLK_TOP_DDRPHYCFG_SEL          83
+#define CLK_TOP_DPILVDS_SEL            84
+#define CLK_TOP_PMICSPI_SEL            85
+#define CLK_TOP_MSDC30_0_SEL           86
+#define CLK_TOP_SMI_MFG_AS_SEL         87
+#define CLK_TOP_GCPU_SEL               88
+#define CLK_TOP_DPI1_SEL               89
+#define CLK_TOP_CCI_SEL                        90
+#define CLK_TOP_APLL_SEL               91
+#define CLK_TOP_HDMIPLL_SEL            92
+#define CLK_TOP_NR_CLK                 93
+
+/* APMIXED_SYS */
+
+#define CLK_APMIXED_ARMPLL1            1
+#define CLK_APMIXED_ARMPLL2            2
+#define CLK_APMIXED_MAINPLL            3
+#define CLK_APMIXED_UNIVPLL            4
+#define CLK_APMIXED_MMPLL              5
+#define CLK_APMIXED_MSDCPLL            6
+#define CLK_APMIXED_TVDPLL             7
+#define CLK_APMIXED_LVDSPLL            8
+#define CLK_APMIXED_AUDPLL             9
+#define CLK_APMIXED_VDECPLL            10
+#define CLK_APMIXED_NR_CLK             11
+
+/* INFRA_SYS */
+
+#define CLK_INFRA_PMIC_WRAP            1
+#define CLK_INFRA_PMICSPI              2
+#define CLK_INFRA_CCIF1_AP_CTRL                3
+#define CLK_INFRA_CCIF0_AP_CTRL                4
+#define CLK_INFRA_KP                   5
+#define CLK_INFRA_CPUM                 6
+#define CLK_INFRA_M4U                  7
+#define CLK_INFRA_MFGAXI               8
+#define CLK_INFRA_DEVAPC               9
+#define CLK_INFRA_AUDIO                        10
+#define CLK_INFRA_MFG_BUS              11
+#define CLK_INFRA_SMI                  12
+#define CLK_INFRA_DBGCLK               13
+#define CLK_INFRA_NR_CLK               14
+
+/* PERI_SYS */
+
+#define CLK_PERI_I2C5                  1
+#define CLK_PERI_I2C4                  2
+#define CLK_PERI_I2C3                  3
+#define CLK_PERI_I2C2                  4
+#define CLK_PERI_I2C1                  5
+#define CLK_PERI_I2C0                  6
+#define CLK_PERI_UART3                 7
+#define CLK_PERI_UART2                 8
+#define CLK_PERI_UART1                 9
+#define CLK_PERI_UART0                 10
+#define CLK_PERI_IRDA                  11
+#define CLK_PERI_NLI                   12
+#define CLK_PERI_MD_HIF                        13
+#define CLK_PERI_AP_HIF                        14
+#define CLK_PERI_MSDC30_3              15
+#define CLK_PERI_MSDC30_2              16
+#define CLK_PERI_MSDC30_1              17
+#define CLK_PERI_MSDC20_2              18
+#define CLK_PERI_MSDC20_1              19
+#define CLK_PERI_AP_DMA                        20
+#define CLK_PERI_USB1                  21
+#define CLK_PERI_USB0                  22
+#define CLK_PERI_PWM                   23
+#define CLK_PERI_PWM7                  24
+#define CLK_PERI_PWM6                  25
+#define CLK_PERI_PWM5                  26
+#define CLK_PERI_PWM4                  27
+#define CLK_PERI_PWM3                  28
+#define CLK_PERI_PWM2                  29
+#define CLK_PERI_PWM1                  30
+#define CLK_PERI_THERM                 31
+#define CLK_PERI_NFI                   32
+#define CLK_PERI_USBSLV                        33
+#define CLK_PERI_USB1_MCU              34
+#define CLK_PERI_USB0_MCU              35
+#define CLK_PERI_GCPU                  36
+#define CLK_PERI_FHCTL                 37
+#define CLK_PERI_SPI1                  38
+#define CLK_PERI_AUXADC                        39
+#define CLK_PERI_PERI_PWRAP            40
+#define CLK_PERI_I2C6                  41
+#define CLK_PERI_UART0_SEL             42
+#define CLK_PERI_UART1_SEL             43
+#define CLK_PERI_UART2_SEL             44
+#define CLK_PERI_UART3_SEL             45
+#define CLK_PERI_NR_CLK                        46
+
+#endif /* _DT_BINDINGS_CLK_MT8135_H */
diff --git a/include/dt-bindings/clock/mt8173-clk.h b/include/dt-bindings/clock/mt8173-clk.h
new file mode 100644 (file)
index 0000000..4ad76ed
--- /dev/null
@@ -0,0 +1,235 @@
+/*
+ * Copyright (c) 2014 MediaTek Inc.
+ * Author: James Liao <jamesjj.liao@mediatek.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#ifndef _DT_BINDINGS_CLK_MT8173_H
+#define _DT_BINDINGS_CLK_MT8173_H
+
+/* TOPCKGEN */
+
+#define CLK_TOP_CLKPH_MCK_O            1
+#define CLK_TOP_DPI                    2
+#define CLK_TOP_USB_SYSPLL_125M                3
+#define CLK_TOP_HDMITX_DIG_CTS         4
+#define CLK_TOP_ARMCA7PLL_754M         5
+#define CLK_TOP_ARMCA7PLL_502M         6
+#define CLK_TOP_MAIN_H546M             7
+#define CLK_TOP_MAIN_H364M             8
+#define CLK_TOP_MAIN_H218P4M           9
+#define CLK_TOP_MAIN_H156M             10
+#define CLK_TOP_TVDPLL_445P5M          11
+#define CLK_TOP_TVDPLL_594M            12
+#define CLK_TOP_UNIV_624M              13
+#define CLK_TOP_UNIV_416M              14
+#define CLK_TOP_UNIV_249P6M            15
+#define CLK_TOP_UNIV_178P3M            16
+#define CLK_TOP_UNIV_48M               17
+#define CLK_TOP_CLKRTC_EXT             18
+#define CLK_TOP_CLKRTC_INT             19
+#define CLK_TOP_FPC                    20
+#define CLK_TOP_HDMITXPLL_D2           21
+#define CLK_TOP_HDMITXPLL_D3           22
+#define CLK_TOP_ARMCA7PLL_D2           23
+#define CLK_TOP_ARMCA7PLL_D3           24
+#define CLK_TOP_APLL1                  25
+#define CLK_TOP_APLL2                  26
+#define CLK_TOP_DMPLL                  27
+#define CLK_TOP_DMPLL_D2               28
+#define CLK_TOP_DMPLL_D4               29
+#define CLK_TOP_DMPLL_D8               30
+#define CLK_TOP_DMPLL_D16              31
+#define CLK_TOP_LVDSPLL_D2             32
+#define CLK_TOP_LVDSPLL_D4             33
+#define CLK_TOP_LVDSPLL_D8             34
+#define CLK_TOP_MMPLL                  35
+#define CLK_TOP_MMPLL_D2               36
+#define CLK_TOP_MSDCPLL                        37
+#define CLK_TOP_MSDCPLL_D2             38
+#define CLK_TOP_MSDCPLL_D4             39
+#define CLK_TOP_MSDCPLL2               40
+#define CLK_TOP_MSDCPLL2_D2            41
+#define CLK_TOP_MSDCPLL2_D4            42
+#define CLK_TOP_SYSPLL_D2              43
+#define CLK_TOP_SYSPLL1_D2             44
+#define CLK_TOP_SYSPLL1_D4             45
+#define CLK_TOP_SYSPLL1_D8             46
+#define CLK_TOP_SYSPLL1_D16            47
+#define CLK_TOP_SYSPLL_D3              48
+#define CLK_TOP_SYSPLL2_D2             49
+#define CLK_TOP_SYSPLL2_D4             50
+#define CLK_TOP_SYSPLL_D5              51
+#define CLK_TOP_SYSPLL3_D2             52
+#define CLK_TOP_SYSPLL3_D4             53
+#define CLK_TOP_SYSPLL_D7              54
+#define CLK_TOP_SYSPLL4_D2             55
+#define CLK_TOP_SYSPLL4_D4             56
+#define CLK_TOP_TVDPLL                 57
+#define CLK_TOP_TVDPLL_D2              58
+#define CLK_TOP_TVDPLL_D4              59
+#define CLK_TOP_TVDPLL_D8              60
+#define CLK_TOP_TVDPLL_D16             61
+#define CLK_TOP_UNIVPLL_D2             62
+#define CLK_TOP_UNIVPLL1_D2            63
+#define CLK_TOP_UNIVPLL1_D4            64
+#define CLK_TOP_UNIVPLL1_D8            65
+#define CLK_TOP_UNIVPLL_D3             66
+#define CLK_TOP_UNIVPLL2_D2            67
+#define CLK_TOP_UNIVPLL2_D4            68
+#define CLK_TOP_UNIVPLL2_D8            69
+#define CLK_TOP_UNIVPLL_D5             70
+#define CLK_TOP_UNIVPLL3_D2            71
+#define CLK_TOP_UNIVPLL3_D4            72
+#define CLK_TOP_UNIVPLL3_D8            73
+#define CLK_TOP_UNIVPLL_D7             74
+#define CLK_TOP_UNIVPLL_D26            75
+#define CLK_TOP_UNIVPLL_D52            76
+#define CLK_TOP_VCODECPLL              77
+#define CLK_TOP_VCODECPLL_370P5                78
+#define CLK_TOP_VENCPLL                        79
+#define CLK_TOP_VENCPLL_D2             80
+#define CLK_TOP_VENCPLL_D4             81
+#define CLK_TOP_AXI_SEL                        82
+#define CLK_TOP_MEM_SEL                        83
+#define CLK_TOP_DDRPHYCFG_SEL          84
+#define CLK_TOP_MM_SEL                 85
+#define CLK_TOP_PWM_SEL                        86
+#define CLK_TOP_VDEC_SEL               87
+#define CLK_TOP_VENC_SEL               88
+#define CLK_TOP_MFG_SEL                        89
+#define CLK_TOP_CAMTG_SEL              90
+#define CLK_TOP_UART_SEL               91
+#define CLK_TOP_SPI_SEL                        92
+#define CLK_TOP_USB20_SEL              93
+#define CLK_TOP_USB30_SEL              94
+#define CLK_TOP_MSDC50_0_H_SEL         95
+#define CLK_TOP_MSDC50_0_SEL           96
+#define CLK_TOP_MSDC30_1_SEL           97
+#define CLK_TOP_MSDC30_2_SEL           98
+#define CLK_TOP_MSDC30_3_SEL           99
+#define CLK_TOP_AUDIO_SEL              100
+#define CLK_TOP_AUD_INTBUS_SEL         101
+#define CLK_TOP_PMICSPI_SEL            102
+#define CLK_TOP_SCP_SEL                        103
+#define CLK_TOP_ATB_SEL                        104
+#define CLK_TOP_VENC_LT_SEL            105
+#define CLK_TOP_DPI0_SEL               106
+#define CLK_TOP_IRDA_SEL               107
+#define CLK_TOP_CCI400_SEL             108
+#define CLK_TOP_AUD_1_SEL              109
+#define CLK_TOP_AUD_2_SEL              110
+#define CLK_TOP_MEM_MFG_IN_SEL         111
+#define CLK_TOP_AXI_MFG_IN_SEL         112
+#define CLK_TOP_SCAM_SEL               113
+#define CLK_TOP_SPINFI_IFR_SEL         114
+#define CLK_TOP_HDMI_SEL               115
+#define CLK_TOP_DPILVDS_SEL            116
+#define CLK_TOP_MSDC50_2_H_SEL         117
+#define CLK_TOP_HDCP_SEL               118
+#define CLK_TOP_HDCP_24M_SEL           119
+#define CLK_TOP_RTC_SEL                        120
+#define CLK_TOP_APLL1_DIV0             121
+#define CLK_TOP_APLL1_DIV1             122
+#define CLK_TOP_APLL1_DIV2             123
+#define CLK_TOP_APLL1_DIV3             124
+#define CLK_TOP_APLL1_DIV4             125
+#define CLK_TOP_APLL1_DIV5             126
+#define CLK_TOP_APLL2_DIV0             127
+#define CLK_TOP_APLL2_DIV1             128
+#define CLK_TOP_APLL2_DIV2             129
+#define CLK_TOP_APLL2_DIV3             130
+#define CLK_TOP_APLL2_DIV4             131
+#define CLK_TOP_APLL2_DIV5             132
+#define CLK_TOP_I2S0_M_SEL             133
+#define CLK_TOP_I2S1_M_SEL             134
+#define CLK_TOP_I2S2_M_SEL             135
+#define CLK_TOP_I2S3_M_SEL             136
+#define CLK_TOP_I2S3_B_SEL             137
+#define CLK_TOP_NR_CLK                 138
+
+/* APMIXED_SYS */
+
+#define CLK_APMIXED_ARMCA15PLL 1
+#define CLK_APMIXED_ARMCA7PLL  2
+#define CLK_APMIXED_MAINPLL            3
+#define CLK_APMIXED_UNIVPLL            4
+#define CLK_APMIXED_MMPLL              5
+#define CLK_APMIXED_MSDCPLL            6
+#define CLK_APMIXED_VENCPLL            7
+#define CLK_APMIXED_TVDPLL             8
+#define CLK_APMIXED_MPLL               9
+#define CLK_APMIXED_VCODECPLL          10
+#define CLK_APMIXED_APLL1              11
+#define CLK_APMIXED_APLL2              12
+#define CLK_APMIXED_LVDSPLL            13
+#define CLK_APMIXED_MSDCPLL2           14
+#define CLK_APMIXED_NR_CLK             15
+
+/* INFRA_SYS */
+
+#define CLK_INFRA_DBGCLK               1
+#define CLK_INFRA_SMI                  2
+#define CLK_INFRA_AUDIO                        3
+#define CLK_INFRA_GCE                  4
+#define CLK_INFRA_L2C_SRAM             5
+#define CLK_INFRA_M4U                  6
+#define CLK_INFRA_CPUM                 7
+#define CLK_INFRA_KP                   8
+#define CLK_INFRA_CEC                  9
+#define CLK_INFRA_PMICSPI              10
+#define CLK_INFRA_PMICWRAP             11
+#define CLK_INFRA_NR_CLK               12
+
+/* PERI_SYS */
+
+#define CLK_PERI_NFI                   1
+#define CLK_PERI_THERM                 2
+#define CLK_PERI_PWM1                  3
+#define CLK_PERI_PWM2                  4
+#define CLK_PERI_PWM3                  5
+#define CLK_PERI_PWM4                  6
+#define CLK_PERI_PWM5                  7
+#define CLK_PERI_PWM6                  8
+#define CLK_PERI_PWM7                  9
+#define CLK_PERI_PWM                   10
+#define CLK_PERI_USB0                  11
+#define CLK_PERI_USB1                  12
+#define CLK_PERI_AP_DMA                        13
+#define CLK_PERI_MSDC30_0              14
+#define CLK_PERI_MSDC30_1              15
+#define CLK_PERI_MSDC30_2              16
+#define CLK_PERI_MSDC30_3              17
+#define CLK_PERI_NLI_ARB               18
+#define CLK_PERI_IRDA                  19
+#define CLK_PERI_UART0                 20
+#define CLK_PERI_UART1                 21
+#define CLK_PERI_UART2                 22
+#define CLK_PERI_UART3                 23
+#define CLK_PERI_I2C0                  24
+#define CLK_PERI_I2C1                  25
+#define CLK_PERI_I2C2                  26
+#define CLK_PERI_I2C3                  27
+#define CLK_PERI_I2C4                  28
+#define CLK_PERI_AUXADC                        29
+#define CLK_PERI_SPI0                  30
+#define CLK_PERI_I2C5                  31
+#define CLK_PERI_NFIECC                        32
+#define CLK_PERI_SPI                   33
+#define CLK_PERI_IRRX                  34
+#define CLK_PERI_I2C6                  35
+#define CLK_PERI_UART0_SEL             36
+#define CLK_PERI_UART1_SEL             37
+#define CLK_PERI_UART2_SEL             38
+#define CLK_PERI_UART3_SEL             39
+#define CLK_PERI_NR_CLK                        40
+
+#endif /* _DT_BINDINGS_CLK_MT8173_H */
diff --git a/include/dt-bindings/reset-controller/mt8135-resets.h b/include/dt-bindings/reset-controller/mt8135-resets.h
new file mode 100644 (file)
index 0000000..1fb6295
--- /dev/null
@@ -0,0 +1,64 @@
+/*
+ * Copyright (c) 2014 MediaTek Inc.
+ * Author: Flora Fu, MediaTek
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#ifndef _DT_BINDINGS_RESET_CONTROLLER_MT8135
+#define _DT_BINDINGS_RESET_CONTROLLER_MT8135
+
+/* INFRACFG resets */
+#define MT8135_INFRA_EMI_REG_RST        0
+#define MT8135_INFRA_DRAMC0_A0_RST      1
+#define MT8135_INFRA_CCIF0_RST          2
+#define MT8135_INFRA_APCIRQ_EINT_RST    3
+#define MT8135_INFRA_APXGPT_RST         4
+#define MT8135_INFRA_SCPSYS_RST         5
+#define MT8135_INFRA_CCIF1_RST          6
+#define MT8135_INFRA_PMIC_WRAP_RST      7
+#define MT8135_INFRA_KP_RST             8
+#define MT8135_INFRA_EMI_RST            32
+#define MT8135_INFRA_DRAMC0_RST         34
+#define MT8135_INFRA_SMI_RST            35
+#define MT8135_INFRA_M4U_RST            36
+
+/*  PERICFG resets */
+#define MT8135_PERI_UART0_SW_RST        0
+#define MT8135_PERI_UART1_SW_RST        1
+#define MT8135_PERI_UART2_SW_RST        2
+#define MT8135_PERI_UART3_SW_RST        3
+#define MT8135_PERI_IRDA_SW_RST         4
+#define MT8135_PERI_PTP_SW_RST          5
+#define MT8135_PERI_AP_HIF_SW_RST       6
+#define MT8135_PERI_GPCU_SW_RST         7
+#define MT8135_PERI_MD_HIF_SW_RST       8
+#define MT8135_PERI_NLI_SW_RST          9
+#define MT8135_PERI_AUXADC_SW_RST       10
+#define MT8135_PERI_DMA_SW_RST          11
+#define MT8135_PERI_NFI_SW_RST          14
+#define MT8135_PERI_PWM_SW_RST          15
+#define MT8135_PERI_THERM_SW_RST        16
+#define MT8135_PERI_MSDC0_SW_RST        17
+#define MT8135_PERI_MSDC1_SW_RST        18
+#define MT8135_PERI_MSDC2_SW_RST        19
+#define MT8135_PERI_MSDC3_SW_RST        20
+#define MT8135_PERI_I2C0_SW_RST         22
+#define MT8135_PERI_I2C1_SW_RST         23
+#define MT8135_PERI_I2C2_SW_RST         24
+#define MT8135_PERI_I2C3_SW_RST         25
+#define MT8135_PERI_I2C4_SW_RST         26
+#define MT8135_PERI_I2C5_SW_RST         27
+#define MT8135_PERI_I2C6_SW_RST         28
+#define MT8135_PERI_USB_SW_RST          29
+#define MT8135_PERI_SPI1_SW_RST         33
+#define MT8135_PERI_PWRAP_BRIDGE_SW_RST 34
+
+#endif  /* _DT_BINDINGS_RESET_CONTROLLER_MT8135 */
diff --git a/include/dt-bindings/reset-controller/mt8173-resets.h b/include/dt-bindings/reset-controller/mt8173-resets.h
new file mode 100644 (file)
index 0000000..9464b37
--- /dev/null
@@ -0,0 +1,63 @@
+/*
+ * Copyright (c) 2014 MediaTek Inc.
+ * Author: Flora Fu, MediaTek
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#ifndef _DT_BINDINGS_RESET_CONTROLLER_MT8173
+#define _DT_BINDINGS_RESET_CONTROLLER_MT8173
+
+/* INFRACFG resets */
+#define MT8173_INFRA_EMI_REG_RST        0
+#define MT8173_INFRA_DRAMC0_A0_RST      1
+#define MT8173_INFRA_APCIRQ_EINT_RST    3
+#define MT8173_INFRA_APXGPT_RST         4
+#define MT8173_INFRA_SCPSYS_RST         5
+#define MT8173_INFRA_KP_RST             6
+#define MT8173_INFRA_PMIC_WRAP_RST      7
+#define MT8173_INFRA_MPIP_RST           8
+#define MT8173_INFRA_CEC_RST            9
+#define MT8173_INFRA_EMI_RST            32
+#define MT8173_INFRA_DRAMC0_RST         34
+#define MT8173_INFRA_APMIXEDSYS_RST     35
+#define MT8173_INFRA_MIPI_DSI_RST       36
+#define MT8173_INFRA_TRNG_RST           37
+#define MT8173_INFRA_SYSIRQ_RST         38
+#define MT8173_INFRA_MIPI_CSI_RST       39
+#define MT8173_INFRA_GCE_FAXI_RST       40
+#define MT8173_INFRA_MMIOMMURST         47
+
+
+/*  PERICFG resets */
+#define MT8173_PERI_UART0_SW_RST        0
+#define MT8173_PERI_UART1_SW_RST        1
+#define MT8173_PERI_UART2_SW_RST        2
+#define MT8173_PERI_UART3_SW_RST        3
+#define MT8173_PERI_IRRX_SW_RST         4
+#define MT8173_PERI_PWM_SW_RST          8
+#define MT8173_PERI_AUXADC_SW_RST       10
+#define MT8173_PERI_DMA_SW_RST          11
+#define MT8173_PERI_I2C6_SW_RST         13
+#define MT8173_PERI_NFI_SW_RST          14
+#define MT8173_PERI_THERM_SW_RST        16
+#define MT8173_PERI_MSDC2_SW_RST        17
+#define MT8173_PERI_MSDC3_SW_RST        18
+#define MT8173_PERI_MSDC0_SW_RST        19
+#define MT8173_PERI_MSDC1_SW_RST        20
+#define MT8173_PERI_I2C0_SW_RST         22
+#define MT8173_PERI_I2C1_SW_RST         23
+#define MT8173_PERI_I2C2_SW_RST         24
+#define MT8173_PERI_I2C3_SW_RST         25
+#define MT8173_PERI_I2C4_SW_RST         26
+#define MT8173_PERI_HDMI_SW_RST         29
+#define MT8173_PERI_SPI0_SW_RST         33
+
+#endif  /* _DT_BINDINGS_RESET_CONTROLLER_MT8173 */
index df695313f975769b6cfc740760cbc8c33b6a8d5c..78842f46f152694906e0b73f99fd2aa93611e2f7 100644 (file)
@@ -31,6 +31,7 @@
 #define CLK_GET_RATE_NOCACHE   BIT(6) /* do not use the cached clk rate */
 #define CLK_SET_RATE_NO_REPARENT BIT(7) /* don't re-parent on rate change */
 #define CLK_GET_ACCURACY_NOCACHE BIT(8) /* do not use the cached clk accuracy */
+#define CLK_RECALC_NEW_RATES   BIT(9) /* recalc rates after notifications */
 
 struct clk_hw;
 struct clk_core;
@@ -209,7 +210,7 @@ struct clk_ops {
 struct clk_init_data {
        const char              *name;
        const struct clk_ops    *ops;
-       const char              **parent_names;
+       const char              * const *parent_names;
        u8                      num_parents;
        unsigned long           flags;
 };
@@ -426,12 +427,14 @@ extern const struct clk_ops clk_mux_ops;
 extern const struct clk_ops clk_mux_ro_ops;
 
 struct clk *clk_register_mux(struct device *dev, const char *name,
-               const char **parent_names, u8 num_parents, unsigned long flags,
+               const char * const *parent_names, u8 num_parents,
+               unsigned long flags,
                void __iomem *reg, u8 shift, u8 width,
                u8 clk_mux_flags, spinlock_t *lock);
 
 struct clk *clk_register_mux_table(struct device *dev, const char *name,
-               const char **parent_names, u8 num_parents, unsigned long flags,
+               const char * const *parent_names, u8 num_parents,
+               unsigned long flags,
                void __iomem *reg, u8 shift, u32 mask,
                u8 clk_mux_flags, u32 *table, spinlock_t *lock);
 
@@ -457,7 +460,7 @@ struct clk_fixed_factor {
        unsigned int    div;
 };
 
-extern struct clk_ops clk_fixed_factor_ops;
+extern const struct clk_ops clk_fixed_factor_ops;
 struct clk *clk_register_fixed_factor(struct device *dev, const char *name,
                const char *parent_name, unsigned long flags,
                unsigned int mult, unsigned int div);
@@ -518,7 +521,7 @@ struct clk_composite {
 };
 
 struct clk *clk_register_composite(struct device *dev, const char *name,
-               const char **parent_names, int num_parents,
+               const char * const *parent_names, int num_parents,
                struct clk_hw *mux_hw, const struct clk_ops *mux_ops,
                struct clk_hw *rate_hw, const struct clk_ops *rate_ops,
                struct clk_hw *gate_hw, const struct clk_ops *gate_ops,
@@ -589,6 +592,7 @@ long __clk_mux_determine_rate_closest(struct clk_hw *hw, unsigned long rate,
                              unsigned long max_rate,
                              unsigned long *best_parent_rate,
                              struct clk_hw **best_parent_p);
+void clk_hw_reparent(struct clk_hw *hw, struct clk_hw *new_parent);
 
 static inline void __clk_hw_set_clk(struct clk_hw *dst, struct clk_hw *src)
 {
@@ -624,6 +628,8 @@ struct clk *of_clk_src_simple_get(struct of_phandle_args *clkspec,
                                  void *data);
 struct clk *of_clk_src_onecell_get(struct of_phandle_args *clkspec, void *data);
 int of_clk_get_parent_count(struct device_node *np);
+int of_clk_parent_fill(struct device_node *np, const char **parents,
+                      unsigned int size);
 const char *of_clk_get_parent_name(struct device_node *np, int index);
 
 void of_clk_init(const struct of_device_id *matches);