Merge tag 'v3.20-rockchip-clk1' of git://git.kernel.org/pub/scm/linux/kernel/git...
authorMichael Turquette <mturquette@linaro.org>
Wed, 28 Jan 2015 00:26:12 +0000 (16:26 -0800)
committerMichael Turquette <mturquette@linaro.org>
Wed, 28 Jan 2015 00:26:12 +0000 (16:26 -0800)
The two big changes are the additional of the watchdog clock, which
we currently only "fake" as the clock gate control is living in a
very strange place, but the watchdog driver needs to read the clock
rate from it and the setting of rk3288 plls to slow mode upon suspend.

Other than that some more exported clocks and a CLK_SET_RATE_PARENT
flag for the uart clocks.

59 files changed:
Documentation/devicetree/bindings/clock/exynos7-clock.txt
Documentation/devicetree/bindings/clock/qcom,lcc.txt [new file with mode: 0644]
Documentation/devicetree/bindings/clock/qoriq-clock.txt
Documentation/devicetree/bindings/clock/renesas,cpg-mstp-clocks.txt
Documentation/devicetree/bindings/clock/renesas,r8a73a4-cpg-clocks.txt [new file with mode: 0644]
Documentation/devicetree/bindings/clock/renesas,rcar-gen2-cpg-clocks.txt
Documentation/devicetree/bindings/clock/ti,cdce706.txt [new file with mode: 0644]
Documentation/devicetree/bindings/clock/ti/fapll.txt [new file with mode: 0644]
MAINTAINERS
arch/powerpc/kernel/time.c
arch/powerpc/platforms/512x/clock-commonclk.c
drivers/clk/Kconfig
drivers/clk/Makefile
drivers/clk/at91/clk-slow.c
drivers/clk/berlin/bg2q.c
drivers/clk/clk-asm9260.c [new file with mode: 0644]
drivers/clk/clk-cdce706.c [new file with mode: 0644]
drivers/clk/clk-divider.c
drivers/clk/clk-gate.c
drivers/clk/clk-mux.c
drivers/clk/clk-qoriq.c [moved from drivers/clk/clk-ppc-corenet.c with 80% similarity]
drivers/clk/clk.c
drivers/clk/qcom/Kconfig
drivers/clk/qcom/Makefile
drivers/clk/qcom/clk-regmap-divider.c [new file with mode: 0644]
drivers/clk/qcom/clk-regmap-divider.h [new file with mode: 0644]
drivers/clk/qcom/clk-regmap-mux.c [new file with mode: 0644]
drivers/clk/qcom/clk-regmap-mux.h [new file with mode: 0644]
drivers/clk/qcom/gcc-ipq806x.c
drivers/clk/qcom/lcc-ipq806x.c [new file with mode: 0644]
drivers/clk/qcom/lcc-msm8960.c [new file with mode: 0644]
drivers/clk/rockchip/clk-cpu.c
drivers/clk/rockchip/clk-rk3188.c
drivers/clk/rockchip/clk-rk3288.c
drivers/clk/samsung/clk-exynos-audss.c
drivers/clk/samsung/clk-exynos7.c
drivers/clk/shmobile/Makefile
drivers/clk/shmobile/clk-div6.c
drivers/clk/shmobile/clk-r8a73a4.c [new file with mode: 0644]
drivers/clk/shmobile/clk-rcar-gen2.c
drivers/clk/st/clk-flexgen.c
drivers/clk/ti/Makefile
drivers/clk/ti/clk-3xxx.c
drivers/clk/ti/clk-44xx.c
drivers/clk/ti/clk-54xx.c
drivers/clk/ti/clk-7xx.c
drivers/clk/ti/clk-816x.c [new file with mode: 0644]
drivers/clk/ti/fapll.c [new file with mode: 0644]
drivers/clk/ux500/clk-prcc.c
drivers/clk/ux500/clk-prcmu.c
drivers/cpufreq/Kconfig.powerpc
include/dt-bindings/clock/alphascale,asm9260.h [new file with mode: 0644]
include/dt-bindings/clock/exynos7-clk.h
include/dt-bindings/clock/qcom,gcc-ipq806x.h
include/dt-bindings/clock/qcom,lcc-ipq806x.h [new file with mode: 0644]
include/dt-bindings/clock/qcom,lcc-msm8960.h [new file with mode: 0644]
include/linux/clk-provider.h
include/linux/clk.h
include/linux/clk/ti.h

index 6d3d5f80c1c3186ba35a7c28dd950e2f754e3027..6bf1e7493f61febb762a212d6306dcaa03fb00c4 100644 (file)
@@ -34,6 +34,8 @@ Required Properties for Clock Controller:
        - "samsung,exynos7-clock-peris"
        - "samsung,exynos7-clock-fsys0"
        - "samsung,exynos7-clock-fsys1"
+       - "samsung,exynos7-clock-mscl"
+       - "samsung,exynos7-clock-aud"
 
  - reg: physical base address of the controller and the length of
        memory mapped region.
@@ -53,6 +55,7 @@ Input clocks for top0 clock controller:
        - dout_sclk_bus1_pll
        - dout_sclk_cc_pll
        - dout_sclk_mfc_pll
+       - dout_sclk_aud_pll
 
 Input clocks for top1 clock controller:
        - fin_pll
@@ -76,6 +79,14 @@ Input clocks for peric1 clock controller:
        - sclk_uart1
        - sclk_uart2
        - sclk_uart3
+       - sclk_spi0
+       - sclk_spi1
+       - sclk_spi2
+       - sclk_spi3
+       - sclk_spi4
+       - sclk_i2s1
+       - sclk_pcm1
+       - sclk_spdif
 
 Input clocks for peris clock controller:
        - fin_pll
@@ -91,3 +102,7 @@ Input clocks for fsys1 clock controller:
        - dout_aclk_fsys1_200
        - dout_sclk_mmc0
        - dout_sclk_mmc1
+
+Input clocks for aud clock controller:
+       - fin_pll
+       - fout_aud_pll
diff --git a/Documentation/devicetree/bindings/clock/qcom,lcc.txt b/Documentation/devicetree/bindings/clock/qcom,lcc.txt
new file mode 100644 (file)
index 0000000..dd755be
--- /dev/null
@@ -0,0 +1,21 @@
+Qualcomm LPASS Clock & Reset Controller Binding
+------------------------------------------------
+
+Required properties :
+- compatible : shall contain only one of the following:
+
+                       "qcom,lcc-msm8960"
+                       "qcom,lcc-apq8064"
+                       "qcom,lcc-ipq8064"
+
+- reg : shall contain base register location and length
+- #clock-cells : shall contain 1
+- #reset-cells : shall contain 1
+
+Example:
+       clock-controller@28000000 {
+               compatible = "qcom,lcc-ipq8064";
+               reg = <0x28000000 0x1000>;
+               #clock-cells = <1>;
+               #reset-cells = <1>;
+       };
index 266ff9d232293a976de9e6a851e1bd7d1f2de7d0..df4a259a6898c5d7fe62fd5ad7e3ef323b5719b6 100644 (file)
@@ -1,6 +1,6 @@
-* Clock Block on Freescale CoreNet Platforms
+* Clock Block on Freescale QorIQ Platforms
 
-Freescale CoreNet chips take primary clocking input from the external
+Freescale qoriq chips take primary clocking input from the external
 SYSCLK signal. The SYSCLK input (frequency) is multiplied using
 multiple phase locked loops (PLL) to create a variety of frequencies
 which can then be passed to a variety of internal logic, including
@@ -29,6 +29,7 @@ Required properties:
        * "fsl,t4240-clockgen"
        * "fsl,b4420-clockgen"
        * "fsl,b4860-clockgen"
+       * "fsl,ls1021a-clockgen"
        Chassis clock strings include:
        * "fsl,qoriq-clockgen-1.0": for chassis 1.0 clocks
        * "fsl,qoriq-clockgen-2.0": for chassis 2.0 clocks
index 2e18676bd4b56503ce42ec4b4d368c32041fe1d0..0a80fa70ca265c0f2c7b7657d7270f47d6f53a45 100644 (file)
@@ -11,6 +11,7 @@ Required Properties:
 
   - compatible: Must be one of the following
     - "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,r8a7779-mstp-clocks" for R8A7779 (R-Car H1) MSTP gate clocks
     - "renesas,r8a7790-mstp-clocks" for R8A7790 (R-Car H2) MSTP gate clocks
diff --git a/Documentation/devicetree/bindings/clock/renesas,r8a73a4-cpg-clocks.txt b/Documentation/devicetree/bindings/clock/renesas,r8a73a4-cpg-clocks.txt
new file mode 100644 (file)
index 0000000..ece9239
--- /dev/null
@@ -0,0 +1,33 @@
+* Renesas R8A73A4 Clock Pulse Generator (CPG)
+
+The CPG generates core clocks for the R8A73A4 SoC. It includes five PLLs
+and several fixed ratio dividers.
+
+Required Properties:
+
+  - compatible: Must be "renesas,r8a73a4-cpg-clocks"
+
+  - reg: Base address and length of the memory resource used by the CPG
+
+  - clocks: Reference to the parent clocks ("extal1" and "extal2")
+
+  - #clock-cells: Must be 1
+
+  - clock-output-names: The names of the clocks. Supported clocks are "main",
+    "pll0", "pll1", "pll2", "pll2s", "pll2h", "z", "z2", "i", "m3", "b",
+    "m1", "m2", "zx", "zs", and "hp".
+
+
+Example
+-------
+
+        cpg_clocks: cpg_clocks@e6150000 {
+                compatible = "renesas,r8a73a4-cpg-clocks";
+                reg = <0 0xe6150000 0 0x10000>;
+                clocks = <&extal1_clk>, <&extal2_clk>;
+                #clock-cells = <1>;
+                clock-output-names = "main", "pll0", "pll1", "pll2",
+                                     "pll2s", "pll2h", "z", "z2",
+                                     "i", "m3", "b", "m1", "m2",
+                                     "zx", "zs", "hp";
+        };
index e6ad35b894f919f537dbf58cbdea6fffd9cddfc9..b02944fba9de4f8696d9f6ac7845acb96937aeed 100644 (file)
@@ -8,15 +8,18 @@ Required Properties:
   - compatible: Must be one of
     - "renesas,r8a7790-cpg-clocks" for the r8a7790 CPG
     - "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
 
   - reg: Base address and length of the memory resource used by the CPG
 
-  - clocks: Reference to the parent clock
+  - clocks: References to the parent clocks: first to the EXTAL clock, second
+    to the USB_EXTAL clock
   - #clock-cells: Must be 1
   - clock-output-names: The names of the clocks. Supported clocks are "main",
-    "pll0", "pll1", "pll3", "lb", "qspi", "sdh", "sd0", "sd1" and "z"
+    "pll0", "pll1", "pll3", "lb", "qspi", "sdh", "sd0", "sd1", "z", "rcan", and
+    "adsp"
 
 
 Example
@@ -26,8 +29,9 @@ Example
                compatible = "renesas,r8a7790-cpg-clocks",
                             "renesas,rcar-gen2-cpg-clocks";
                reg = <0 0xe6150000 0 0x1000>;
-               clocks = <&extal_clk>;
+               clocks = <&extal_clk &usb_extal_clk>;
                #clock-cells = <1>;
                clock-output-names = "main", "pll0, "pll1", "pll3",
-                                    "lb", "qspi", "sdh", "sd0", "sd1", "z";
+                                    "lb", "qspi", "sdh", "sd0", "sd1", "z",
+                                    "rcan", "adsp";
        };
diff --git a/Documentation/devicetree/bindings/clock/ti,cdce706.txt b/Documentation/devicetree/bindings/clock/ti,cdce706.txt
new file mode 100644 (file)
index 0000000..616836e
--- /dev/null
@@ -0,0 +1,42 @@
+Bindings for Texas Instruments CDCE706 programmable 3-PLL clock
+synthesizer/multiplier/divider.
+
+Reference: http://www.ti.com/lit/ds/symlink/cdce706.pdf
+
+I2C device node required properties:
+- compatible: shall be "ti,cdce706".
+- reg: i2c device address, shall be in range [0x68...0x6b].
+- #clock-cells: from common clock binding; shall be set to 1.
+- clocks: from common clock binding; list of parent clock
+  handles, shall be reference clock(s) connected to CLK_IN0
+  and CLK_IN1 pins.
+- clock-names: shall be clk_in0 and/or clk_in1. Use clk_in0
+  in case of crystal oscillator or differential signal input
+  configuration. Use clk_in0 and clk_in1 in case of independent
+  single-ended LVCMOS inputs configuration.
+
+Example:
+
+       clocks {
+               clk54: clk54 {
+                       #clock-cells = <0>;
+                       compatible = "fixed-clock";
+                       clock-frequency = <54000000>;
+               };
+       };
+       ...
+       i2c0: i2c-master@0d090000 {
+               ...
+               cdce706: clock-synth@69 {
+                       compatible = "ti,cdce706";
+                       #clock-cells = <1>;
+                       reg = <0x69>;
+                       clocks = <&clk54>;
+                       clock-names = "clk_in0";
+               };
+       };
+       ...
+       simple-audio-card,codec {
+               ...
+               clocks = <&cdce706 4>;
+       };
diff --git a/Documentation/devicetree/bindings/clock/ti/fapll.txt b/Documentation/devicetree/bindings/clock/ti/fapll.txt
new file mode 100644 (file)
index 0000000..c19b3f2
--- /dev/null
@@ -0,0 +1,33 @@
+Binding for Texas Instruments FAPLL clock.
+
+Binding status: Unstable - ABI compatibility may be broken in the future
+
+This binding uses the common clock binding[1]. It assumes a
+register-mapped FAPLL with usually two selectable input clocks
+(reference clock and bypass clock), and one or more child
+syntesizers.
+
+[1] Documentation/devicetree/bindings/clock/clock-bindings.txt
+
+Required properties:
+- compatible : shall be "ti,dm816-fapll-clock"
+- #clock-cells : from common clock binding; shall be set to 0.
+- clocks : link phandles of parent clocks (clk-ref and clk-bypass)
+- reg : address and length of the register set for controlling the FAPLL.
+
+Examples:
+       main_fapll: main_fapll {
+               #clock-cells = <1>;
+               compatible = "ti,dm816-fapll-clock";
+               reg = <0x400 0x40>;
+               clocks = <&sys_clkin_ck &sys_clkin_ck>;
+               clock-indices = <1>, <2>, <3>, <4>, <5>,
+                               <6>, <7>;
+               clock-output-names = "main_pll_clk1",
+                                    "main_pll_clk2",
+                                    "main_pll_clk3",
+                                    "main_pll_clk4",
+                                    "main_pll_clk5",
+                                    "main_pll_clk6",
+                                    "main_pll_clk7";
+       };
index ddb9ac8d32b3eddc46d66bd408392ae09b637ea7..2164026b65eef2282a56e4284bf5b4a3d8ff400a 100644 (file)
@@ -9536,6 +9536,11 @@ L:       linux-pm@vger.kernel.org
 S:     Supported
 F:     drivers/thermal/ti-soc-thermal/
 
+TI CDCE706 CLOCK DRIVER
+M:     Max Filippov <jcmvbkbc@gmail.com>
+S:     Maintained
+F:     drivers/clk/clk-cdce706.c
+
 TI CLOCK DRIVER
 M:     Tero Kristo <t-kristo@ti.com>
 L:     linux-omap@vger.kernel.org
index fa7c4f12104fe427f648e9fe23ad67b059d0ccd5..df9fa05b5fd3123cb9c3b4a73205511f274d7ce8 100644 (file)
@@ -54,6 +54,7 @@
 #include <linux/irq.h>
 #include <linux/delay.h>
 #include <linux/irq_work.h>
+#include <linux/clk-provider.h>
 #include <asm/trace.h>
 
 #include <asm/io.h>
@@ -943,6 +944,10 @@ void __init time_init(void)
 
        init_decrementer_clockevent();
        tick_setup_hrtimer_broadcast();
+
+#ifdef CONFIG_COMMON_CLK
+       of_clk_init(NULL);
+#endif
 }
 
 
index 6eb614a271fbe07390271aca65d802e37d3a6481..f691bcabd71013e23a09a07bfec61a592e1cd237 100644 (file)
@@ -1168,6 +1168,11 @@ static void mpc5121_clk_provide_backwards_compat(void)
        }
 }
 
+/*
+ * The "fixed-clock" nodes (which includes the oscillator node if the board's
+ * DT provides one) has already been scanned by the of_clk_init() in
+ * time_init().
+ */
 int __init mpc5121_clk_init(void)
 {
        struct device_node *clk_np;
@@ -1186,12 +1191,6 @@ int __init mpc5121_clk_init(void)
        /* invalidate all not yet registered clock slots */
        mpc512x_clk_preset_data();
 
-       /*
-        * have the device tree scanned for "fixed-clock" nodes (which
-        * includes the oscillator node if the board's DT provides one)
-        */
-       of_clk_init(NULL);
-
        /*
         * add a dummy clock for those situations where a clock spec is
         * required yet no real clock is involved
index 3f44f292d066f03c2bd3029f4631d3a5183a70de..1c0832d9475a7a1dfb62e05da195505ec1371d8c 100644 (file)
@@ -101,12 +101,12 @@ config COMMON_CLK_AXI_CLKGEN
          Support for the Analog Devices axi-clkgen pcore clock generator for Xilinx
          FPGAs. It is commonly used in Analog Devices' reference designs.
 
-config CLK_PPC_CORENET
-       bool "Clock driver for PowerPC corenet platforms"
-       depends on PPC_E500MC && OF
+config CLK_QORIQ
+       bool "Clock driver for Freescale QorIQ platforms"
+       depends on (PPC_E500MC || ARM) && OF
        ---help---
-         This adds the clock driver support for Freescale PowerPC corenet
-         platforms using common clock framework.
+         This adds the clock driver support for Freescale QorIQ platforms
+         using common clock framework.
 
 config COMMON_CLK_XGENE
        bool "Clock driver for APM XGene SoC"
@@ -134,6 +134,14 @@ config COMMON_CLK_PXA
        ---help---
          Sypport for the Marvell PXA SoC.
 
+config COMMON_CLK_CDCE706
+       tristate "Clock driver for TI CDCE706 clock synthesizer"
+       depends on I2C
+       select REGMAP_I2C
+       select RATIONAL
+       ---help---
+         This driver supports TI CDCE706 programmable 3-PLL clock synthesizer.
+
 source "drivers/clk/qcom/Kconfig"
 
 endmenu
index d5fba5bc6e1bc1f07991be58f367c30a253a58f7..d478ceb69c5fc6b4a1bee49276b37763db36c79d 100644 (file)
@@ -16,9 +16,11 @@ endif
 
 # hardware specific clock types
 # please keep this section sorted lexicographically by file/directory path name
+obj-$(CONFIG_MACH_ASM9260)             += clk-asm9260.o
 obj-$(CONFIG_COMMON_CLK_AXI_CLKGEN)    += clk-axi-clkgen.o
 obj-$(CONFIG_ARCH_AXXIA)               += clk-axm5516.o
 obj-$(CONFIG_ARCH_BCM2835)             += clk-bcm2835.o
+obj-$(CONFIG_COMMON_CLK_CDCE706)       += clk-cdce706.o
 obj-$(CONFIG_ARCH_CLPS711X)            += clk-clps711x.o
 obj-$(CONFIG_ARCH_EFM32)               += clk-efm32gg.o
 obj-$(CONFIG_ARCH_HIGHBANK)            += clk-highbank.o
@@ -30,7 +32,7 @@ obj-$(CONFIG_ARCH_MOXART)             += clk-moxart.o
 obj-$(CONFIG_ARCH_NOMADIK)             += clk-nomadik.o
 obj-$(CONFIG_ARCH_NSPIRE)              += clk-nspire.o
 obj-$(CONFIG_COMMON_CLK_PALMAS)                += clk-palmas.o
-obj-$(CONFIG_CLK_PPC_CORENET)          += clk-ppc-corenet.o
+obj-$(CONFIG_CLK_QORIQ)                        += clk-qoriq.o
 obj-$(CONFIG_COMMON_CLK_RK808)         += clk-rk808.o
 obj-$(CONFIG_COMMON_CLK_S2MPS11)       += clk-s2mps11.o
 obj-$(CONFIG_COMMON_CLK_SI5351)                += clk-si5351.o
index 32f7c1b36204018d0ce151601c6ca5ef6f2cf75f..2f13bd5246b5563ec399058029fcd0740c58c3d2 100644 (file)
@@ -70,6 +70,7 @@ struct clk_sam9x5_slow {
 
 #define to_clk_sam9x5_slow(hw) container_of(hw, struct clk_sam9x5_slow, hw)
 
+static struct clk *slow_clk;
 
 static int clk_slow_osc_prepare(struct clk_hw *hw)
 {
@@ -357,6 +358,8 @@ at91_clk_register_sam9x5_slow(void __iomem *sckcr,
        clk = clk_register(NULL, &slowck->hw);
        if (IS_ERR(clk))
                kfree(slowck);
+       else
+               slow_clk = clk;
 
        return clk;
 }
@@ -433,6 +436,8 @@ at91_clk_register_sam9260_slow(struct at91_pmc *pmc,
        clk = clk_register(NULL, &slowck->hw);
        if (IS_ERR(clk))
                kfree(slowck);
+       else
+               slow_clk = clk;
 
        return clk;
 }
@@ -465,3 +470,25 @@ void __init of_at91sam9260_clk_slow_setup(struct device_node *np,
 
        of_clk_add_provider(np, of_clk_src_simple_get, clk);
 }
+
+/*
+ * FIXME: All slow clk users are not properly claiming it (get + prepare +
+ * enable) before using it.
+ * If all users properly claiming this clock decide that they don't need it
+ * anymore (or are removed), it is disabled while faulty users are still
+ * requiring it, and the system hangs.
+ * Prevent this clock from being disabled until all users are properly
+ * requesting it.
+ * Once this is done we should remove this function and the slow_clk variable.
+ */
+static int __init of_at91_clk_slow_retain(void)
+{
+       if (!slow_clk)
+               return 0;
+
+       __clk_get(slow_clk);
+       clk_prepare_enable(slow_clk);
+
+       return 0;
+}
+arch_initcall(of_at91_clk_slow_retain);
index 21784e4eb3f004af06c1b980938ab4ced9bc2894..440ef81ab15c4ba8d9f70947db7e5a0d144a97a4 100644 (file)
@@ -285,7 +285,6 @@ static const struct berlin2_gate_data bg2q_gates[] __initconst = {
        { "pbridge",    "perif",        15, CLK_IGNORE_UNUSED },
        { "sdio",       "perif",        16, CLK_IGNORE_UNUSED },
        { "nfc",        "perif",        18 },
-       { "smemc",      "perif",        19 },
        { "pcie",       "perif",        22 },
 };
 
diff --git a/drivers/clk/clk-asm9260.c b/drivers/clk/clk-asm9260.c
new file mode 100644 (file)
index 0000000..88f4ff6
--- /dev/null
@@ -0,0 +1,348 @@
+/*
+ * Copyright (c) 2014 Oleksij Rempel <linux@rempel-privat.de>.
+ *
+ * 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/clkdev.h>
+#include <linux/err.h>
+#include <linux/io.h>
+#include <linux/clk-provider.h>
+#include <linux/spinlock.h>
+#include <linux/of.h>
+#include <linux/of_address.h>
+#include <dt-bindings/clock/alphascale,asm9260.h>
+
+#define HW_AHBCLKCTRL0         0x0020
+#define HW_AHBCLKCTRL1         0x0030
+#define HW_SYSPLLCTRL          0x0100
+#define HW_MAINCLKSEL          0x0120
+#define HW_MAINCLKUEN          0x0124
+#define HW_UARTCLKSEL          0x0128
+#define HW_UARTCLKUEN          0x012c
+#define HW_I2S0CLKSEL          0x0130
+#define HW_I2S0CLKUEN          0x0134
+#define HW_I2S1CLKSEL          0x0138
+#define HW_I2S1CLKUEN          0x013c
+#define HW_WDTCLKSEL           0x0160
+#define HW_WDTCLKUEN           0x0164
+#define HW_CLKOUTCLKSEL                0x0170
+#define HW_CLKOUTCLKUEN                0x0174
+#define HW_CPUCLKDIV           0x017c
+#define HW_SYSAHBCLKDIV                0x0180
+#define HW_I2S0MCLKDIV         0x0190
+#define HW_I2S0SCLKDIV         0x0194
+#define HW_I2S1MCLKDIV         0x0188
+#define HW_I2S1SCLKDIV         0x018c
+#define HW_UART0CLKDIV         0x0198
+#define HW_UART1CLKDIV         0x019c
+#define HW_UART2CLKDIV         0x01a0
+#define HW_UART3CLKDIV         0x01a4
+#define HW_UART4CLKDIV         0x01a8
+#define HW_UART5CLKDIV         0x01ac
+#define HW_UART6CLKDIV         0x01b0
+#define HW_UART7CLKDIV         0x01b4
+#define HW_UART8CLKDIV         0x01b8
+#define HW_UART9CLKDIV         0x01bc
+#define HW_SPI0CLKDIV          0x01c0
+#define HW_SPI1CLKDIV          0x01c4
+#define HW_QUADSPICLKDIV       0x01c8
+#define HW_SSP0CLKDIV          0x01d0
+#define HW_NANDCLKDIV          0x01d4
+#define HW_TRACECLKDIV         0x01e0
+#define HW_CAMMCLKDIV          0x01e8
+#define HW_WDTCLKDIV           0x01ec
+#define HW_CLKOUTCLKDIV                0x01f4
+#define HW_MACCLKDIV           0x01f8
+#define HW_LCDCLKDIV           0x01fc
+#define HW_ADCANACLKDIV                0x0200
+
+static struct clk *clks[MAX_CLKS];
+static struct clk_onecell_data clk_data;
+static DEFINE_SPINLOCK(asm9260_clk_lock);
+
+struct asm9260_div_clk {
+       unsigned int idx;
+       const char *name;
+       const char *parent_name;
+       u32 reg;
+};
+
+struct asm9260_gate_data {
+       unsigned int idx;
+       const char *name;
+       const char *parent_name;
+       u32 reg;
+       u8 bit_idx;
+       unsigned long flags;
+};
+
+struct asm9260_mux_clock {
+       u8                      mask;
+       u32                     *table;
+       const char              *name;
+       const char              **parent_names;
+       u8                      num_parents;
+       unsigned long           offset;
+       unsigned long           flags;
+};
+
+static void __iomem *base;
+
+static const struct asm9260_div_clk asm9260_div_clks[] __initconst = {
+       { CLKID_SYS_CPU,        "cpu_div", "main_gate", HW_CPUCLKDIV },
+       { CLKID_SYS_AHB,        "ahb_div", "cpu_div", HW_SYSAHBCLKDIV },
+
+       /* i2s has two deviders: one for only external mclk and internal
+        * devider for all clks. */
+       { CLKID_SYS_I2S0M,      "i2s0m_div", "i2s0_mclk",  HW_I2S0MCLKDIV },
+       { CLKID_SYS_I2S1M,      "i2s1m_div", "i2s1_mclk",  HW_I2S1MCLKDIV },
+       { CLKID_SYS_I2S0S,      "i2s0s_div", "i2s0_gate",  HW_I2S0SCLKDIV },
+       { CLKID_SYS_I2S1S,      "i2s1s_div", "i2s0_gate",  HW_I2S1SCLKDIV },
+
+       { CLKID_SYS_UART0,      "uart0_div", "uart_gate", HW_UART0CLKDIV },
+       { CLKID_SYS_UART1,      "uart1_div", "uart_gate", HW_UART1CLKDIV },
+       { CLKID_SYS_UART2,      "uart2_div", "uart_gate", HW_UART2CLKDIV },
+       { CLKID_SYS_UART3,      "uart3_div", "uart_gate", HW_UART3CLKDIV },
+       { CLKID_SYS_UART4,      "uart4_div", "uart_gate", HW_UART4CLKDIV },
+       { CLKID_SYS_UART5,      "uart5_div", "uart_gate", HW_UART5CLKDIV },
+       { CLKID_SYS_UART6,      "uart6_div", "uart_gate", HW_UART6CLKDIV },
+       { CLKID_SYS_UART7,      "uart7_div", "uart_gate", HW_UART7CLKDIV },
+       { CLKID_SYS_UART8,      "uart8_div", "uart_gate", HW_UART8CLKDIV },
+       { CLKID_SYS_UART9,      "uart9_div", "uart_gate", HW_UART9CLKDIV },
+
+       { CLKID_SYS_SPI0,       "spi0_div",     "main_gate", HW_SPI0CLKDIV },
+       { CLKID_SYS_SPI1,       "spi1_div",     "main_gate", HW_SPI1CLKDIV },
+       { CLKID_SYS_QUADSPI,    "quadspi_div",  "main_gate", HW_QUADSPICLKDIV },
+       { CLKID_SYS_SSP0,       "ssp0_div",     "main_gate", HW_SSP0CLKDIV },
+       { CLKID_SYS_NAND,       "nand_div",     "main_gate", HW_NANDCLKDIV },
+       { CLKID_SYS_TRACE,      "trace_div",    "main_gate", HW_TRACECLKDIV },
+       { CLKID_SYS_CAMM,       "camm_div",     "main_gate", HW_CAMMCLKDIV },
+       { CLKID_SYS_MAC,        "mac_div",      "main_gate", HW_MACCLKDIV },
+       { CLKID_SYS_LCD,        "lcd_div",      "main_gate", HW_LCDCLKDIV },
+       { CLKID_SYS_ADCANA,     "adcana_div",   "main_gate", HW_ADCANACLKDIV },
+
+       { CLKID_SYS_WDT,        "wdt_div",      "wdt_gate",    HW_WDTCLKDIV },
+       { CLKID_SYS_CLKOUT,     "clkout_div",   "clkout_gate", HW_CLKOUTCLKDIV },
+};
+
+static const struct asm9260_gate_data asm9260_mux_gates[] __initconst = {
+       { 0, "main_gate",       "main_mux",     HW_MAINCLKUEN,  0 },
+       { 0, "uart_gate",       "uart_mux",     HW_UARTCLKUEN,  0 },
+       { 0, "i2s0_gate",       "i2s0_mux",     HW_I2S0CLKUEN,  0 },
+       { 0, "i2s1_gate",       "i2s1_mux",     HW_I2S1CLKUEN,  0 },
+       { 0, "wdt_gate",        "wdt_mux",      HW_WDTCLKUEN,   0 },
+       { 0, "clkout_gate",     "clkout_mux",   HW_CLKOUTCLKUEN, 0 },
+};
+static const struct asm9260_gate_data asm9260_ahb_gates[] __initconst = {
+       /* ahb gates */
+       { CLKID_AHB_ROM,        "rom",          "ahb_div",
+               HW_AHBCLKCTRL0, 1, CLK_IGNORE_UNUSED},
+       { CLKID_AHB_RAM,        "ram",          "ahb_div",
+               HW_AHBCLKCTRL0, 2, CLK_IGNORE_UNUSED},
+       { CLKID_AHB_GPIO,       "gpio",         "ahb_div",
+               HW_AHBCLKCTRL0, 4 },
+       { CLKID_AHB_MAC,        "mac",          "ahb_div",
+               HW_AHBCLKCTRL0, 5 },
+       { CLKID_AHB_EMI,        "emi",          "ahb_div",
+               HW_AHBCLKCTRL0, 6, CLK_IGNORE_UNUSED},
+       { CLKID_AHB_USB0,       "usb0",         "ahb_div",
+               HW_AHBCLKCTRL0, 7 },
+       { CLKID_AHB_USB1,       "usb1",         "ahb_div",
+               HW_AHBCLKCTRL0, 8 },
+       { CLKID_AHB_DMA0,       "dma0",         "ahb_div",
+               HW_AHBCLKCTRL0, 9 },
+       { CLKID_AHB_DMA1,       "dma1",         "ahb_div",
+               HW_AHBCLKCTRL0, 10 },
+       { CLKID_AHB_UART0,      "uart0",        "ahb_div",
+               HW_AHBCLKCTRL0, 11 },
+       { CLKID_AHB_UART1,      "uart1",        "ahb_div",
+               HW_AHBCLKCTRL0, 12 },
+       { CLKID_AHB_UART2,      "uart2",        "ahb_div",
+               HW_AHBCLKCTRL0, 13 },
+       { CLKID_AHB_UART3,      "uart3",        "ahb_div",
+               HW_AHBCLKCTRL0, 14 },
+       { CLKID_AHB_UART4,      "uart4",        "ahb_div",
+               HW_AHBCLKCTRL0, 15 },
+       { CLKID_AHB_UART5,      "uart5",        "ahb_div",
+               HW_AHBCLKCTRL0, 16 },
+       { CLKID_AHB_UART6,      "uart6",        "ahb_div",
+               HW_AHBCLKCTRL0, 17 },
+       { CLKID_AHB_UART7,      "uart7",        "ahb_div",
+               HW_AHBCLKCTRL0, 18 },
+       { CLKID_AHB_UART8,      "uart8",        "ahb_div",
+               HW_AHBCLKCTRL0, 19 },
+       { CLKID_AHB_UART9,      "uart9",        "ahb_div",
+               HW_AHBCLKCTRL0, 20 },
+       { CLKID_AHB_I2S0,       "i2s0",         "ahb_div",
+               HW_AHBCLKCTRL0, 21 },
+       { CLKID_AHB_I2C0,       "i2c0",         "ahb_div",
+               HW_AHBCLKCTRL0, 22 },
+       { CLKID_AHB_I2C1,       "i2c1",         "ahb_div",
+               HW_AHBCLKCTRL0, 23 },
+       { CLKID_AHB_SSP0,       "ssp0",         "ahb_div",
+               HW_AHBCLKCTRL0, 24 },
+       { CLKID_AHB_IOCONFIG,   "ioconf",       "ahb_div",
+               HW_AHBCLKCTRL0, 25 },
+       { CLKID_AHB_WDT,        "wdt",          "ahb_div",
+               HW_AHBCLKCTRL0, 26 },
+       { CLKID_AHB_CAN0,       "can0",         "ahb_div",
+               HW_AHBCLKCTRL0, 27 },
+       { CLKID_AHB_CAN1,       "can1",         "ahb_div",
+               HW_AHBCLKCTRL0, 28 },
+       { CLKID_AHB_MPWM,       "mpwm",         "ahb_div",
+               HW_AHBCLKCTRL0, 29 },
+       { CLKID_AHB_SPI0,       "spi0",         "ahb_div",
+               HW_AHBCLKCTRL0, 30 },
+       { CLKID_AHB_SPI1,       "spi1",         "ahb_div",
+               HW_AHBCLKCTRL0, 31 },
+
+       { CLKID_AHB_QEI,        "qei",          "ahb_div",
+               HW_AHBCLKCTRL1, 0 },
+       { CLKID_AHB_QUADSPI0,   "quadspi0",     "ahb_div",
+               HW_AHBCLKCTRL1, 1 },
+       { CLKID_AHB_CAMIF,      "capmif",       "ahb_div",
+               HW_AHBCLKCTRL1, 2 },
+       { CLKID_AHB_LCDIF,      "lcdif",        "ahb_div",
+               HW_AHBCLKCTRL1, 3 },
+       { CLKID_AHB_TIMER0,     "timer0",       "ahb_div",
+               HW_AHBCLKCTRL1, 4 },
+       { CLKID_AHB_TIMER1,     "timer1",       "ahb_div",
+               HW_AHBCLKCTRL1, 5 },
+       { CLKID_AHB_TIMER2,     "timer2",       "ahb_div",
+               HW_AHBCLKCTRL1, 6 },
+       { CLKID_AHB_TIMER3,     "timer3",       "ahb_div",
+               HW_AHBCLKCTRL1, 7 },
+       { CLKID_AHB_IRQ,        "irq",          "ahb_div",
+               HW_AHBCLKCTRL1, 8, CLK_IGNORE_UNUSED},
+       { CLKID_AHB_RTC,        "rtc",          "ahb_div",
+               HW_AHBCLKCTRL1, 9 },
+       { CLKID_AHB_NAND,       "nand",         "ahb_div",
+               HW_AHBCLKCTRL1, 10 },
+       { CLKID_AHB_ADC0,       "adc0",         "ahb_div",
+               HW_AHBCLKCTRL1, 11 },
+       { CLKID_AHB_LED,        "led",          "ahb_div",
+               HW_AHBCLKCTRL1, 12 },
+       { CLKID_AHB_DAC0,       "dac0",         "ahb_div",
+               HW_AHBCLKCTRL1, 13 },
+       { CLKID_AHB_LCD,        "lcd",          "ahb_div",
+               HW_AHBCLKCTRL1, 14 },
+       { CLKID_AHB_I2S1,       "i2s1",         "ahb_div",
+               HW_AHBCLKCTRL1, 15 },
+       { CLKID_AHB_MAC1,       "mac1",         "ahb_div",
+               HW_AHBCLKCTRL1, 16 },
+};
+
+static const char __initdata *main_mux_p[] =   { NULL, NULL };
+static const char __initdata *i2s0_mux_p[] =   { NULL, NULL, "i2s0m_div"};
+static const char __initdata *i2s1_mux_p[] =   { NULL, NULL, "i2s1m_div"};
+static const char __initdata *clkout_mux_p[] = { NULL, NULL, "rtc"};
+static u32 three_mux_table[] = {0, 1, 3};
+
+static struct asm9260_mux_clock asm9260_mux_clks[] __initdata = {
+       { 1, three_mux_table, "main_mux",       main_mux_p,
+               ARRAY_SIZE(main_mux_p), HW_MAINCLKSEL, },
+       { 1, three_mux_table, "uart_mux",       main_mux_p,
+               ARRAY_SIZE(main_mux_p), HW_UARTCLKSEL, },
+       { 1, three_mux_table, "wdt_mux",        main_mux_p,
+               ARRAY_SIZE(main_mux_p), HW_WDTCLKSEL, },
+       { 3, three_mux_table, "i2s0_mux",       i2s0_mux_p,
+               ARRAY_SIZE(i2s0_mux_p), HW_I2S0CLKSEL, },
+       { 3, three_mux_table, "i2s1_mux",       i2s1_mux_p,
+               ARRAY_SIZE(i2s1_mux_p), HW_I2S1CLKSEL, },
+       { 3, three_mux_table, "clkout_mux",     clkout_mux_p,
+               ARRAY_SIZE(clkout_mux_p), HW_CLKOUTCLKSEL, },
+};
+
+static void __init asm9260_acc_init(struct device_node *np)
+{
+       struct clk *clk;
+       const char *ref_clk, *pll_clk = "pll";
+       u32 rate;
+       int n;
+       u32 accuracy = 0;
+
+       base = of_io_request_and_map(np, 0, np->name);
+       if (!base)
+               panic("%s: unable to map resource", np->name);
+
+       /* register pll */
+       rate = (ioread32(base + HW_SYSPLLCTRL) & 0xffff) * 1000000;
+
+       ref_clk = of_clk_get_parent_name(np, 0);
+       accuracy = clk_get_accuracy(__clk_lookup(ref_clk));
+       clk = clk_register_fixed_rate_with_accuracy(NULL, pll_clk,
+                       ref_clk, 0, rate, accuracy);
+
+       if (IS_ERR(clk))
+               panic("%s: can't register REFCLK. Check DT!", np->name);
+
+       for (n = 0; n < ARRAY_SIZE(asm9260_mux_clks); n++) {
+               const struct asm9260_mux_clock *mc = &asm9260_mux_clks[n];
+
+               mc->parent_names[0] = ref_clk;
+               mc->parent_names[1] = pll_clk;
+               clk = clk_register_mux_table(NULL, mc->name, mc->parent_names,
+                               mc->num_parents, mc->flags, base + mc->offset,
+                               0, mc->mask, 0, mc->table, &asm9260_clk_lock);
+       }
+
+       /* clock mux gate cells */
+       for (n = 0; n < ARRAY_SIZE(asm9260_mux_gates); n++) {
+               const struct asm9260_gate_data *gd = &asm9260_mux_gates[n];
+
+               clk = clk_register_gate(NULL, gd->name,
+                       gd->parent_name, gd->flags | CLK_SET_RATE_PARENT,
+                       base + gd->reg, gd->bit_idx, 0, &asm9260_clk_lock);
+       }
+
+       /* clock div cells */
+       for (n = 0; n < ARRAY_SIZE(asm9260_div_clks); n++) {
+               const struct asm9260_div_clk *dc = &asm9260_div_clks[n];
+
+               clks[dc->idx] = clk_register_divider(NULL, dc->name,
+                               dc->parent_name, CLK_SET_RATE_PARENT,
+                               base + dc->reg, 0, 8, CLK_DIVIDER_ONE_BASED,
+                               &asm9260_clk_lock);
+       }
+
+       /* clock ahb gate cells */
+       for (n = 0; n < ARRAY_SIZE(asm9260_ahb_gates); n++) {
+               const struct asm9260_gate_data *gd = &asm9260_ahb_gates[n];
+
+               clks[gd->idx] = clk_register_gate(NULL, gd->name,
+                               gd->parent_name, gd->flags, base + gd->reg,
+                               gd->bit_idx, 0, &asm9260_clk_lock);
+       }
+
+       /* check for errors on leaf clocks */
+       for (n = 0; n < MAX_CLKS; n++) {
+               if (!IS_ERR(clks[n]))
+                       continue;
+
+               pr_err("%s: Unable to register leaf clock %d\n",
+                               np->full_name, n);
+               goto fail;
+       }
+
+       /* register clk-provider */
+       clk_data.clks = clks;
+       clk_data.clk_num = MAX_CLKS;
+       of_clk_add_provider(np, of_clk_src_onecell_get, &clk_data);
+       return;
+fail:
+       iounmap(base);
+}
+CLK_OF_DECLARE(asm9260_acc, "alphascale,asm9260-clock-controller",
+               asm9260_acc_init);
diff --git a/drivers/clk/clk-cdce706.c b/drivers/clk/clk-cdce706.c
new file mode 100644 (file)
index 0000000..c386ad2
--- /dev/null
@@ -0,0 +1,700 @@
+/*
+ * TI CDCE706 programmable 3-PLL clock synthesizer driver
+ *
+ * Copyright (c) 2014 Cadence Design Systems Inc.
+ *
+ * Reference: http://www.ti.com/lit/ds/symlink/cdce706.pdf
+ *
+ * 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/clk-provider.h>
+#include <linux/delay.h>
+#include <linux/i2c.h>
+#include <linux/interrupt.h>
+#include <linux/mod_devicetable.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/rational.h>
+#include <linux/regmap.h>
+#include <linux/slab.h>
+
+#define CDCE706_CLKIN_CLOCK            10
+#define CDCE706_CLKIN_SOURCE           11
+#define CDCE706_PLL_M_LOW(pll)         (1 + 3 * (pll))
+#define CDCE706_PLL_N_LOW(pll)         (2 + 3 * (pll))
+#define CDCE706_PLL_HI(pll)            (3 + 3 * (pll))
+#define CDCE706_PLL_MUX                        3
+#define CDCE706_PLL_FVCO               6
+#define CDCE706_DIVIDER(div)           (13 + (div))
+#define CDCE706_CLKOUT(out)            (19 + (out))
+
+#define CDCE706_CLKIN_CLOCK_MASK       0x10
+#define CDCE706_CLKIN_SOURCE_SHIFT     6
+#define CDCE706_CLKIN_SOURCE_MASK      0xc0
+#define CDCE706_CLKIN_SOURCE_LVCMOS    0x40
+
+#define CDCE706_PLL_MUX_MASK(pll)      (0x80 >> (pll))
+#define CDCE706_PLL_LOW_M_MASK         0xff
+#define CDCE706_PLL_LOW_N_MASK         0xff
+#define CDCE706_PLL_HI_M_MASK          0x1
+#define CDCE706_PLL_HI_N_MASK          0x1e
+#define CDCE706_PLL_HI_N_SHIFT         1
+#define CDCE706_PLL_M_MAX              0x1ff
+#define CDCE706_PLL_N_MAX              0xfff
+#define CDCE706_PLL_FVCO_MASK(pll)     (0x80 >> (pll))
+#define CDCE706_PLL_FREQ_MIN            80000000
+#define CDCE706_PLL_FREQ_MAX           300000000
+#define CDCE706_PLL_FREQ_HI            180000000
+
+#define CDCE706_DIVIDER_PLL(div)       (9 + (div) - ((div) > 2) - ((div) > 4))
+#define CDCE706_DIVIDER_PLL_SHIFT(div) ((div) < 2 ? 5 : 3 * ((div) & 1))
+#define CDCE706_DIVIDER_PLL_MASK(div)  (0x7 << CDCE706_DIVIDER_PLL_SHIFT(div))
+#define CDCE706_DIVIDER_DIVIDER_MASK   0x7f
+#define CDCE706_DIVIDER_DIVIDER_MAX    0x7f
+
+#define CDCE706_CLKOUT_DIVIDER_MASK    0x7
+#define CDCE706_CLKOUT_ENABLE_MASK     0x8
+
+static struct regmap_config cdce706_regmap_config = {
+       .reg_bits = 8,
+       .val_bits = 8,
+       .val_format_endian = REGMAP_ENDIAN_NATIVE,
+};
+
+#define to_hw_data(phw) (container_of((phw), struct cdce706_hw_data, hw))
+
+struct cdce706_hw_data {
+       struct cdce706_dev_data *dev_data;
+       unsigned idx;
+       unsigned parent;
+       struct clk *clk;
+       struct clk_hw hw;
+       unsigned div;
+       unsigned mul;
+       unsigned mux;
+};
+
+struct cdce706_dev_data {
+       struct i2c_client *client;
+       struct regmap *regmap;
+       struct clk_onecell_data onecell;
+       struct clk *clks[6];
+       struct clk *clkin_clk[2];
+       const char *clkin_name[2];
+       struct cdce706_hw_data clkin[1];
+       struct cdce706_hw_data pll[3];
+       struct cdce706_hw_data divider[6];
+       struct cdce706_hw_data clkout[6];
+};
+
+static const char * const cdce706_source_name[] = {
+       "clk_in0", "clk_in1",
+};
+
+static const char *cdce706_clkin_name[] = {
+       "clk_in",
+};
+
+static const char * const cdce706_pll_name[] = {
+       "pll1", "pll2", "pll3",
+};
+
+static const char *cdce706_divider_parent_name[] = {
+       "clk_in", "pll1", "pll2", "pll2", "pll3",
+};
+
+static const char *cdce706_divider_name[] = {
+       "p0", "p1", "p2", "p3", "p4", "p5",
+};
+
+static const char * const cdce706_clkout_name[] = {
+       "clk_out0", "clk_out1", "clk_out2", "clk_out3", "clk_out4", "clk_out5",
+};
+
+static int cdce706_reg_read(struct cdce706_dev_data *dev_data, unsigned reg,
+                           unsigned *val)
+{
+       int rc = regmap_read(dev_data->regmap, reg | 0x80, val);
+
+       if (rc < 0)
+               dev_err(&dev_data->client->dev, "error reading reg %u", reg);
+       return rc;
+}
+
+static int cdce706_reg_write(struct cdce706_dev_data *dev_data, unsigned reg,
+                            unsigned val)
+{
+       int rc = regmap_write(dev_data->regmap, reg | 0x80, val);
+
+       if (rc < 0)
+               dev_err(&dev_data->client->dev, "error writing reg %u", reg);
+       return rc;
+}
+
+static int cdce706_reg_update(struct cdce706_dev_data *dev_data, unsigned reg,
+                             unsigned mask, unsigned val)
+{
+       int rc = regmap_update_bits(dev_data->regmap, reg | 0x80, mask, val);
+
+       if (rc < 0)
+               dev_err(&dev_data->client->dev, "error updating reg %u", reg);
+       return rc;
+}
+
+static int cdce706_clkin_set_parent(struct clk_hw *hw, u8 index)
+{
+       struct cdce706_hw_data *hwd = to_hw_data(hw);
+
+       hwd->parent = index;
+       return 0;
+}
+
+static u8 cdce706_clkin_get_parent(struct clk_hw *hw)
+{
+       struct cdce706_hw_data *hwd = to_hw_data(hw);
+
+       return hwd->parent;
+}
+
+static const struct clk_ops cdce706_clkin_ops = {
+       .set_parent = cdce706_clkin_set_parent,
+       .get_parent = cdce706_clkin_get_parent,
+};
+
+static unsigned long cdce706_pll_recalc_rate(struct clk_hw *hw,
+                                            unsigned long parent_rate)
+{
+       struct cdce706_hw_data *hwd = to_hw_data(hw);
+
+       dev_dbg(&hwd->dev_data->client->dev,
+               "%s, pll: %d, mux: %d, mul: %u, div: %u\n",
+               __func__, hwd->idx, hwd->mux, hwd->mul, hwd->div);
+
+       if (!hwd->mux) {
+               if (hwd->div && hwd->mul) {
+                       u64 res = (u64)parent_rate * hwd->mul;
+
+                       do_div(res, hwd->div);
+                       return res;
+               }
+       } else {
+               if (hwd->div)
+                       return parent_rate / hwd->div;
+       }
+       return 0;
+}
+
+static long cdce706_pll_round_rate(struct clk_hw *hw, unsigned long rate,
+                                  unsigned long *parent_rate)
+{
+       struct cdce706_hw_data *hwd = to_hw_data(hw);
+       unsigned long mul, div;
+       u64 res;
+
+       dev_dbg(&hwd->dev_data->client->dev,
+               "%s, rate: %lu, parent_rate: %lu\n",
+               __func__, rate, *parent_rate);
+
+       rational_best_approximation(rate, *parent_rate,
+                                   CDCE706_PLL_N_MAX, CDCE706_PLL_M_MAX,
+                                   &mul, &div);
+       hwd->mul = mul;
+       hwd->div = div;
+
+       dev_dbg(&hwd->dev_data->client->dev,
+               "%s, pll: %d, mul: %lu, div: %lu\n",
+               __func__, hwd->idx, mul, div);
+
+       res = (u64)*parent_rate * hwd->mul;
+       do_div(res, hwd->div);
+       return res;
+}
+
+static int cdce706_pll_set_rate(struct clk_hw *hw, unsigned long rate,
+                               unsigned long parent_rate)
+{
+       struct cdce706_hw_data *hwd = to_hw_data(hw);
+       unsigned long mul = hwd->mul, div = hwd->div;
+       int err;
+
+       dev_dbg(&hwd->dev_data->client->dev,
+               "%s, pll: %d, mul: %lu, div: %lu\n",
+               __func__, hwd->idx, mul, div);
+
+       err = cdce706_reg_update(hwd->dev_data,
+                                CDCE706_PLL_HI(hwd->idx),
+                                CDCE706_PLL_HI_M_MASK | CDCE706_PLL_HI_N_MASK,
+                                ((div >> 8) & CDCE706_PLL_HI_M_MASK) |
+                                ((mul >> (8 - CDCE706_PLL_HI_N_SHIFT)) &
+                                 CDCE706_PLL_HI_N_MASK));
+       if (err < 0)
+               return err;
+
+       err = cdce706_reg_write(hwd->dev_data,
+                               CDCE706_PLL_M_LOW(hwd->idx),
+                               div & CDCE706_PLL_LOW_M_MASK);
+       if (err < 0)
+               return err;
+
+       err = cdce706_reg_write(hwd->dev_data,
+                               CDCE706_PLL_N_LOW(hwd->idx),
+                               mul & CDCE706_PLL_LOW_N_MASK);
+       if (err < 0)
+               return err;
+
+       err = cdce706_reg_update(hwd->dev_data,
+                                CDCE706_PLL_FVCO,
+                                CDCE706_PLL_FVCO_MASK(hwd->idx),
+                                rate > CDCE706_PLL_FREQ_HI ?
+                                CDCE706_PLL_FVCO_MASK(hwd->idx) : 0);
+       return err;
+}
+
+static const struct clk_ops cdce706_pll_ops = {
+       .recalc_rate = cdce706_pll_recalc_rate,
+       .round_rate = cdce706_pll_round_rate,
+       .set_rate = cdce706_pll_set_rate,
+};
+
+static int cdce706_divider_set_parent(struct clk_hw *hw, u8 index)
+{
+       struct cdce706_hw_data *hwd = to_hw_data(hw);
+
+       if (hwd->parent == index)
+               return 0;
+       hwd->parent = index;
+       return cdce706_reg_update(hwd->dev_data,
+                                 CDCE706_DIVIDER_PLL(hwd->idx),
+                                 CDCE706_DIVIDER_PLL_MASK(hwd->idx),
+                                 index << CDCE706_DIVIDER_PLL_SHIFT(hwd->idx));
+}
+
+static u8 cdce706_divider_get_parent(struct clk_hw *hw)
+{
+       struct cdce706_hw_data *hwd = to_hw_data(hw);
+
+       return hwd->parent;
+}
+
+static unsigned long cdce706_divider_recalc_rate(struct clk_hw *hw,
+                                                unsigned long parent_rate)
+{
+       struct cdce706_hw_data *hwd = to_hw_data(hw);
+
+       dev_dbg(&hwd->dev_data->client->dev,
+               "%s, divider: %d, div: %u\n",
+               __func__, hwd->idx, hwd->div);
+       if (hwd->div)
+               return parent_rate / hwd->div;
+       return 0;
+}
+
+static long cdce706_divider_round_rate(struct clk_hw *hw, unsigned long rate,
+                                      unsigned long *parent_rate)
+{
+       struct cdce706_hw_data *hwd = to_hw_data(hw);
+       struct cdce706_dev_data *cdce = hwd->dev_data;
+       unsigned long mul, div;
+
+       dev_dbg(&hwd->dev_data->client->dev,
+               "%s, rate: %lu, parent_rate: %lu\n",
+               __func__, rate, *parent_rate);
+
+       rational_best_approximation(rate, *parent_rate,
+                                   1, CDCE706_DIVIDER_DIVIDER_MAX,
+                                   &mul, &div);
+       if (!mul)
+               div = CDCE706_DIVIDER_DIVIDER_MAX;
+
+       if (__clk_get_flags(hw->clk) & CLK_SET_RATE_PARENT) {
+               unsigned long best_diff = rate;
+               unsigned long best_div = 0;
+               struct clk *gp_clk = cdce->clkin_clk[cdce->clkin[0].parent];
+               unsigned long gp_rate = gp_clk ? clk_get_rate(gp_clk) : 0;
+
+               for (div = CDCE706_PLL_FREQ_MIN / rate; best_diff &&
+                    div <= CDCE706_PLL_FREQ_MAX / rate; ++div) {
+                       unsigned long n, m;
+                       unsigned long diff;
+                       unsigned long div_rate;
+                       u64 div_rate64;
+
+                       if (rate * div < CDCE706_PLL_FREQ_MIN)
+                               continue;
+
+                       rational_best_approximation(rate * div, gp_rate,
+                                                   CDCE706_PLL_N_MAX,
+                                                   CDCE706_PLL_M_MAX,
+                                                   &n, &m);
+                       div_rate64 = (u64)gp_rate * n;
+                       do_div(div_rate64, m);
+                       do_div(div_rate64, div);
+                       div_rate = div_rate64;
+                       diff = max(div_rate, rate) - min(div_rate, rate);
+
+                       if (diff < best_diff) {
+                               best_diff = diff;
+                               best_div = div;
+                               dev_dbg(&hwd->dev_data->client->dev,
+                                       "%s, %lu * %lu / %lu / %lu = %lu\n",
+                                       __func__, gp_rate, n, m, div, div_rate);
+                       }
+               }
+
+               div = best_div;
+
+               dev_dbg(&hwd->dev_data->client->dev,
+                       "%s, altering parent rate: %lu -> %lu\n",
+                       __func__, *parent_rate, rate * div);
+               *parent_rate = rate * div;
+       }
+       hwd->div = div;
+
+       dev_dbg(&hwd->dev_data->client->dev,
+               "%s, divider: %d, div: %lu\n",
+               __func__, hwd->idx, div);
+
+       return *parent_rate / div;
+}
+
+static int cdce706_divider_set_rate(struct clk_hw *hw, unsigned long rate,
+                                   unsigned long parent_rate)
+{
+       struct cdce706_hw_data *hwd = to_hw_data(hw);
+
+       dev_dbg(&hwd->dev_data->client->dev,
+               "%s, divider: %d, div: %u\n",
+               __func__, hwd->idx, hwd->div);
+
+       return cdce706_reg_update(hwd->dev_data,
+                                 CDCE706_DIVIDER(hwd->idx),
+                                 CDCE706_DIVIDER_DIVIDER_MASK,
+                                 hwd->div);
+}
+
+static const struct clk_ops cdce706_divider_ops = {
+       .set_parent = cdce706_divider_set_parent,
+       .get_parent = cdce706_divider_get_parent,
+       .recalc_rate = cdce706_divider_recalc_rate,
+       .round_rate = cdce706_divider_round_rate,
+       .set_rate = cdce706_divider_set_rate,
+};
+
+static int cdce706_clkout_prepare(struct clk_hw *hw)
+{
+       struct cdce706_hw_data *hwd = to_hw_data(hw);
+
+       return cdce706_reg_update(hwd->dev_data, CDCE706_CLKOUT(hwd->idx),
+                                 CDCE706_CLKOUT_ENABLE_MASK,
+                                 CDCE706_CLKOUT_ENABLE_MASK);
+}
+
+static void cdce706_clkout_unprepare(struct clk_hw *hw)
+{
+       struct cdce706_hw_data *hwd = to_hw_data(hw);
+
+       cdce706_reg_update(hwd->dev_data, CDCE706_CLKOUT(hwd->idx),
+                          CDCE706_CLKOUT_ENABLE_MASK, 0);
+}
+
+static int cdce706_clkout_set_parent(struct clk_hw *hw, u8 index)
+{
+       struct cdce706_hw_data *hwd = to_hw_data(hw);
+
+       if (hwd->parent == index)
+               return 0;
+       hwd->parent = index;
+       return cdce706_reg_update(hwd->dev_data,
+                                 CDCE706_CLKOUT(hwd->idx),
+                                 CDCE706_CLKOUT_ENABLE_MASK, index);
+}
+
+static u8 cdce706_clkout_get_parent(struct clk_hw *hw)
+{
+       struct cdce706_hw_data *hwd = to_hw_data(hw);
+
+       return hwd->parent;
+}
+
+static unsigned long cdce706_clkout_recalc_rate(struct clk_hw *hw,
+                                               unsigned long parent_rate)
+{
+       return parent_rate;
+}
+
+static long cdce706_clkout_round_rate(struct clk_hw *hw, unsigned long rate,
+                                     unsigned long *parent_rate)
+{
+       *parent_rate = rate;
+       return rate;
+}
+
+static int cdce706_clkout_set_rate(struct clk_hw *hw, unsigned long rate,
+                                  unsigned long parent_rate)
+{
+       return 0;
+}
+
+static const struct clk_ops cdce706_clkout_ops = {
+       .prepare = cdce706_clkout_prepare,
+       .unprepare = cdce706_clkout_unprepare,
+       .set_parent = cdce706_clkout_set_parent,
+       .get_parent = cdce706_clkout_get_parent,
+       .recalc_rate = cdce706_clkout_recalc_rate,
+       .round_rate = cdce706_clkout_round_rate,
+       .set_rate = cdce706_clkout_set_rate,
+};
+
+static int cdce706_register_hw(struct cdce706_dev_data *cdce,
+                              struct cdce706_hw_data *hw, unsigned num_hw,
+                              const char * const *clk_names,
+                              struct clk_init_data *init)
+{
+       unsigned i;
+
+       for (i = 0; i < num_hw; ++i, ++hw) {
+               init->name = clk_names[i];
+               hw->dev_data = cdce;
+               hw->idx = i;
+               hw->hw.init = init;
+               hw->clk = devm_clk_register(&cdce->client->dev,
+                                           &hw->hw);
+               if (IS_ERR(hw->clk)) {
+                       dev_err(&cdce->client->dev, "Failed to register %s\n",
+                               clk_names[i]);
+                       return PTR_ERR(hw->clk);
+               }
+       }
+       return 0;
+}
+
+static int cdce706_register_clkin(struct cdce706_dev_data *cdce)
+{
+       struct clk_init_data init = {
+               .ops = &cdce706_clkin_ops,
+               .parent_names = cdce->clkin_name,
+               .num_parents = ARRAY_SIZE(cdce->clkin_name),
+       };
+       unsigned i;
+       int ret;
+       unsigned clock, source;
+
+       for (i = 0; i < ARRAY_SIZE(cdce->clkin_name); ++i) {
+               struct clk *parent = devm_clk_get(&cdce->client->dev,
+                                                 cdce706_source_name[i]);
+
+               if (IS_ERR(parent)) {
+                       cdce->clkin_name[i] = cdce706_source_name[i];
+               } else {
+                       cdce->clkin_name[i] = __clk_get_name(parent);
+                       cdce->clkin_clk[i] = parent;
+               }
+       }
+
+       ret = cdce706_reg_read(cdce, CDCE706_CLKIN_SOURCE, &source);
+       if (ret < 0)
+               return ret;
+       if ((source & CDCE706_CLKIN_SOURCE_MASK) ==
+           CDCE706_CLKIN_SOURCE_LVCMOS) {
+               ret = cdce706_reg_read(cdce, CDCE706_CLKIN_CLOCK, &clock);
+               if (ret < 0)
+                       return ret;
+               cdce->clkin[0].parent = !!(clock & CDCE706_CLKIN_CLOCK_MASK);
+       }
+
+       ret = cdce706_register_hw(cdce, cdce->clkin,
+                                 ARRAY_SIZE(cdce->clkin),
+                                 cdce706_clkin_name, &init);
+       return ret;
+}
+
+static int cdce706_register_plls(struct cdce706_dev_data *cdce)
+{
+       struct clk_init_data init = {
+               .ops = &cdce706_pll_ops,
+               .parent_names = cdce706_clkin_name,
+               .num_parents = ARRAY_SIZE(cdce706_clkin_name),
+       };
+       unsigned i;
+       int ret;
+       unsigned mux;
+
+       ret = cdce706_reg_read(cdce, CDCE706_PLL_MUX, &mux);
+       if (ret < 0)
+               return ret;
+
+       for (i = 0; i < ARRAY_SIZE(cdce->pll); ++i) {
+               unsigned m, n, v;
+
+               ret = cdce706_reg_read(cdce, CDCE706_PLL_M_LOW(i), &m);
+               if (ret < 0)
+                       return ret;
+               ret = cdce706_reg_read(cdce, CDCE706_PLL_N_LOW(i), &n);
+               if (ret < 0)
+                       return ret;
+               ret = cdce706_reg_read(cdce, CDCE706_PLL_HI(i), &v);
+               if (ret < 0)
+                       return ret;
+               cdce->pll[i].div = m | ((v & CDCE706_PLL_HI_M_MASK) << 8);
+               cdce->pll[i].mul = n | ((v & CDCE706_PLL_HI_N_MASK) <<
+                                       (8 - CDCE706_PLL_HI_N_SHIFT));
+               cdce->pll[i].mux = mux & CDCE706_PLL_MUX_MASK(i);
+               dev_dbg(&cdce->client->dev,
+                       "%s: i: %u, div: %u, mul: %u, mux: %d\n", __func__, i,
+                       cdce->pll[i].div, cdce->pll[i].mul, cdce->pll[i].mux);
+       }
+
+       ret = cdce706_register_hw(cdce, cdce->pll,
+                                 ARRAY_SIZE(cdce->pll),
+                                 cdce706_pll_name, &init);
+       return ret;
+}
+
+static int cdce706_register_dividers(struct cdce706_dev_data *cdce)
+{
+       struct clk_init_data init = {
+               .ops = &cdce706_divider_ops,
+               .parent_names = cdce706_divider_parent_name,
+               .num_parents = ARRAY_SIZE(cdce706_divider_parent_name),
+               .flags = CLK_SET_RATE_PARENT,
+       };
+       unsigned i;
+       int ret;
+
+       for (i = 0; i < ARRAY_SIZE(cdce->divider); ++i) {
+               unsigned val;
+
+               ret = cdce706_reg_read(cdce, CDCE706_DIVIDER_PLL(i), &val);
+               if (ret < 0)
+                       return ret;
+               cdce->divider[i].parent =
+                       (val & CDCE706_DIVIDER_PLL_MASK(i)) >>
+                       CDCE706_DIVIDER_PLL_SHIFT(i);
+
+               ret = cdce706_reg_read(cdce, CDCE706_DIVIDER(i), &val);
+               if (ret < 0)
+                       return ret;
+               cdce->divider[i].div = val & CDCE706_DIVIDER_DIVIDER_MASK;
+               dev_dbg(&cdce->client->dev,
+                       "%s: i: %u, parent: %u, div: %u\n", __func__, i,
+                       cdce->divider[i].parent, cdce->divider[i].div);
+       }
+
+       ret = cdce706_register_hw(cdce, cdce->divider,
+                                 ARRAY_SIZE(cdce->divider),
+                                 cdce706_divider_name, &init);
+       return ret;
+}
+
+static int cdce706_register_clkouts(struct cdce706_dev_data *cdce)
+{
+       struct clk_init_data init = {
+               .ops = &cdce706_clkout_ops,
+               .parent_names = cdce706_divider_name,
+               .num_parents = ARRAY_SIZE(cdce706_divider_name),
+               .flags = CLK_SET_RATE_PARENT,
+       };
+       unsigned i;
+       int ret;
+
+       for (i = 0; i < ARRAY_SIZE(cdce->clkout); ++i) {
+               unsigned val;
+
+               ret = cdce706_reg_read(cdce, CDCE706_CLKOUT(i), &val);
+               if (ret < 0)
+                       return ret;
+               cdce->clkout[i].parent = val & CDCE706_CLKOUT_DIVIDER_MASK;
+               dev_dbg(&cdce->client->dev,
+                       "%s: i: %u, parent: %u\n", __func__, i,
+                       cdce->clkout[i].parent);
+       }
+
+       ret = cdce706_register_hw(cdce, cdce->clkout,
+                                 ARRAY_SIZE(cdce->clkout),
+                                 cdce706_clkout_name, &init);
+       for (i = 0; i < ARRAY_SIZE(cdce->clkout); ++i)
+               cdce->clks[i] = cdce->clkout[i].clk;
+
+       return ret;
+}
+
+static int cdce706_probe(struct i2c_client *client,
+                        const struct i2c_device_id *id)
+{
+       struct i2c_adapter *adapter = to_i2c_adapter(client->dev.parent);
+       struct cdce706_dev_data *cdce;
+       int ret;
+
+       if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA))
+               return -EIO;
+
+       cdce = devm_kzalloc(&client->dev, sizeof(*cdce), GFP_KERNEL);
+       if (!cdce)
+               return -ENOMEM;
+
+       cdce->client = client;
+       cdce->regmap = devm_regmap_init_i2c(client, &cdce706_regmap_config);
+       if (IS_ERR(cdce->regmap)) {
+               dev_err(&client->dev, "Failed to initialize regmap\n");
+               return -EINVAL;
+       }
+
+       i2c_set_clientdata(client, cdce);
+
+       ret = cdce706_register_clkin(cdce);
+       if (ret < 0)
+               return ret;
+       ret = cdce706_register_plls(cdce);
+       if (ret < 0)
+               return ret;
+       ret = cdce706_register_dividers(cdce);
+       if (ret < 0)
+               return ret;
+       ret = cdce706_register_clkouts(cdce);
+       if (ret < 0)
+               return ret;
+       cdce->onecell.clks = cdce->clks;
+       cdce->onecell.clk_num = ARRAY_SIZE(cdce->clks);
+       ret = of_clk_add_provider(client->dev.of_node, of_clk_src_onecell_get,
+                                 &cdce->onecell);
+
+       return ret;
+}
+
+static int cdce706_remove(struct i2c_client *client)
+{
+       return 0;
+}
+
+
+#ifdef CONFIG_OF
+static const struct of_device_id cdce706_dt_match[] = {
+       { .compatible = "ti,cdce706" },
+       { },
+};
+MODULE_DEVICE_TABLE(of, cdce706_dt_match);
+#endif
+
+static const struct i2c_device_id cdce706_id[] = {
+       { "cdce706", 0 },
+       { }
+};
+MODULE_DEVICE_TABLE(i2c, cdce706_id);
+
+static struct i2c_driver cdce706_i2c_driver = {
+       .driver = {
+               .name   = "cdce706",
+               .of_match_table = of_match_ptr(cdce706_dt_match),
+       },
+       .probe          = cdce706_probe,
+       .remove         = cdce706_remove,
+       .id_table       = cdce706_id,
+};
+module_i2c_driver(cdce706_i2c_driver);
+
+MODULE_AUTHOR("Max Filippov <jcmvbkbc@gmail.com>");
+MODULE_DESCRIPTION("TI CDCE 706 clock synthesizer driver");
+MODULE_LICENSE("GPL");
index c0a842b335c520c6c28f08308a1b62a743038dd3..db7f8bce7467a2abfd37f6ccb8e22c784a6bce28 100644 (file)
@@ -30,7 +30,7 @@
 
 #define to_clk_divider(_hw) container_of(_hw, struct clk_divider, hw)
 
-#define div_mask(d)    ((1 << ((d)->width)) - 1)
+#define div_mask(width)        ((1 << (width)) - 1)
 
 static unsigned int _get_table_maxdiv(const struct clk_div_table *table)
 {
@@ -54,15 +54,16 @@ static unsigned int _get_table_mindiv(const struct clk_div_table *table)
        return mindiv;
 }
 
-static unsigned int _get_maxdiv(struct clk_divider *divider)
+static unsigned int _get_maxdiv(const struct clk_div_table *table, u8 width,
+                               unsigned long flags)
 {
-       if (divider->flags & CLK_DIVIDER_ONE_BASED)
-               return div_mask(divider);
-       if (divider->flags & CLK_DIVIDER_POWER_OF_TWO)
-               return 1 << div_mask(divider);
-       if (divider->table)
-               return _get_table_maxdiv(divider->table);
-       return div_mask(divider) + 1;
+       if (flags & CLK_DIVIDER_ONE_BASED)
+               return div_mask(width);
+       if (flags & CLK_DIVIDER_POWER_OF_TWO)
+               return 1 << div_mask(width);
+       if (table)
+               return _get_table_maxdiv(table);
+       return div_mask(width) + 1;
 }
 
 static unsigned int _get_table_div(const struct clk_div_table *table,
@@ -76,14 +77,15 @@ static unsigned int _get_table_div(const struct clk_div_table *table,
        return 0;
 }
 
-static unsigned int _get_div(struct clk_divider *divider, unsigned int val)
+static unsigned int _get_div(const struct clk_div_table *table,
+                            unsigned int val, unsigned long flags)
 {
-       if (divider->flags & CLK_DIVIDER_ONE_BASED)
+       if (flags & CLK_DIVIDER_ONE_BASED)
                return val;
-       if (divider->flags & CLK_DIVIDER_POWER_OF_TWO)
+       if (flags & CLK_DIVIDER_POWER_OF_TWO)
                return 1 << val;
-       if (divider->table)
-               return _get_table_div(divider->table, val);
+       if (table)
+               return _get_table_div(table, val);
        return val + 1;
 }
 
@@ -98,29 +100,28 @@ static unsigned int _get_table_val(const struct clk_div_table *table,
        return 0;
 }
 
-static unsigned int _get_val(struct clk_divider *divider, unsigned int div)
+static unsigned int _get_val(const struct clk_div_table *table,
+                            unsigned int div, unsigned long flags)
 {
-       if (divider->flags & CLK_DIVIDER_ONE_BASED)
+       if (flags & CLK_DIVIDER_ONE_BASED)
                return div;
-       if (divider->flags & CLK_DIVIDER_POWER_OF_TWO)
+       if (flags & CLK_DIVIDER_POWER_OF_TWO)
                return __ffs(div);
-       if (divider->table)
-               return  _get_table_val(divider->table, div);
+       if (table)
+               return  _get_table_val(table, div);
        return div - 1;
 }
 
-static unsigned long clk_divider_recalc_rate(struct clk_hw *hw,
-               unsigned long parent_rate)
+unsigned long divider_recalc_rate(struct clk_hw *hw, unsigned long parent_rate,
+                                 unsigned int val,
+                                 const struct clk_div_table *table,
+                                 unsigned long flags)
 {
-       struct clk_divider *divider = to_clk_divider(hw);
-       unsigned int div, val;
+       unsigned int div;
 
-       val = clk_readl(divider->reg) >> divider->shift;
-       val &= div_mask(divider);
-
-       div = _get_div(divider, val);
+       div = _get_div(table, val, flags);
        if (!div) {
-               WARN(!(divider->flags & CLK_DIVIDER_ALLOW_ZERO),
+               WARN(!(flags & CLK_DIVIDER_ALLOW_ZERO),
                        "%s: Zero divisor and CLK_DIVIDER_ALLOW_ZERO not set\n",
                        __clk_get_name(hw->clk));
                return parent_rate;
@@ -128,6 +129,20 @@ static unsigned long clk_divider_recalc_rate(struct clk_hw *hw,
 
        return DIV_ROUND_UP(parent_rate, div);
 }
+EXPORT_SYMBOL_GPL(divider_recalc_rate);
+
+static unsigned long clk_divider_recalc_rate(struct clk_hw *hw,
+               unsigned long parent_rate)
+{
+       struct clk_divider *divider = to_clk_divider(hw);
+       unsigned int val;
+
+       val = clk_readl(divider->reg) >> divider->shift;
+       val &= div_mask(divider->width);
+
+       return divider_recalc_rate(hw, parent_rate, val, divider->table,
+                                  divider->flags);
+}
 
 /*
  * The reverse of DIV_ROUND_UP: The maximum number which
@@ -146,12 +161,13 @@ static bool _is_valid_table_div(const struct clk_div_table *table,
        return false;
 }
 
-static bool _is_valid_div(struct clk_divider *divider, unsigned int div)
+static bool _is_valid_div(const struct clk_div_table *table, unsigned int div,
+                         unsigned long flags)
 {
-       if (divider->flags & CLK_DIVIDER_POWER_OF_TWO)
+       if (flags & CLK_DIVIDER_POWER_OF_TWO)
                return is_power_of_2(div);
-       if (divider->table)
-               return _is_valid_table_div(divider->table, div);
+       if (table)
+               return _is_valid_table_div(table, div);
        return true;
 }
 
@@ -191,71 +207,76 @@ static int _round_down_table(const struct clk_div_table *table, int div)
        return down;
 }
 
-static int _div_round_up(struct clk_divider *divider,
-               unsigned long parent_rate, unsigned long rate)
+static int _div_round_up(const struct clk_div_table *table,
+                        unsigned long parent_rate, unsigned long rate,
+                        unsigned long flags)
 {
        int div = DIV_ROUND_UP(parent_rate, rate);
 
-       if (divider->flags & CLK_DIVIDER_POWER_OF_TWO)
+       if (flags & CLK_DIVIDER_POWER_OF_TWO)
                div = __roundup_pow_of_two(div);
-       if (divider->table)
-               div = _round_up_table(divider->table, div);
+       if (table)
+               div = _round_up_table(table, div);
 
        return div;
 }
 
-static int _div_round_closest(struct clk_divider *divider,
-               unsigned long parent_rate, unsigned long rate)
+static int _div_round_closest(const struct clk_div_table *table,
+                             unsigned long parent_rate, unsigned long rate,
+                             unsigned long flags)
 {
        int up, down, div;
 
        up = down = div = DIV_ROUND_CLOSEST(parent_rate, rate);
 
-       if (divider->flags & CLK_DIVIDER_POWER_OF_TWO) {
+       if (flags & CLK_DIVIDER_POWER_OF_TWO) {
                up = __roundup_pow_of_two(div);
                down = __rounddown_pow_of_two(div);
-       } else if (divider->table) {
-               up = _round_up_table(divider->table, div);
-               down = _round_down_table(divider->table, div);
+       } else if (table) {
+               up = _round_up_table(table, div);
+               down = _round_down_table(table, div);
        }
 
        return (up - div) <= (div - down) ? up : down;
 }
 
-static int _div_round(struct clk_divider *divider, unsigned long parent_rate,
-               unsigned long rate)
+static int _div_round(const struct clk_div_table *table,
+                     unsigned long parent_rate, unsigned long rate,
+                     unsigned long flags)
 {
-       if (divider->flags & CLK_DIVIDER_ROUND_CLOSEST)
-               return _div_round_closest(divider, parent_rate, rate);
+       if (flags & CLK_DIVIDER_ROUND_CLOSEST)
+               return _div_round_closest(table, parent_rate, rate, flags);
 
-       return _div_round_up(divider, parent_rate, rate);
+       return _div_round_up(table, parent_rate, rate, flags);
 }
 
-static bool _is_best_div(struct clk_divider *divider,
-               unsigned long rate, unsigned long now, unsigned long best)
+static bool _is_best_div(unsigned long rate, unsigned long now,
+                        unsigned long best, unsigned long flags)
 {
-       if (divider->flags & CLK_DIVIDER_ROUND_CLOSEST)
+       if (flags & CLK_DIVIDER_ROUND_CLOSEST)
                return abs(rate - now) < abs(rate - best);
 
        return now <= rate && now > best;
 }
 
-static int _next_div(struct clk_divider *divider, int div)
+static int _next_div(const struct clk_div_table *table, int div,
+                    unsigned long flags)
 {
        div++;
 
-       if (divider->flags & CLK_DIVIDER_POWER_OF_TWO)
+       if (flags & CLK_DIVIDER_POWER_OF_TWO)
                return __roundup_pow_of_two(div);
-       if (divider->table)
-               return _round_up_table(divider->table, div);
+       if (table)
+               return _round_up_table(table, div);
 
        return div;
 }
 
 static int clk_divider_bestdiv(struct clk_hw *hw, unsigned long rate,
-               unsigned long *best_parent_rate)
+                              unsigned long *best_parent_rate,
+                              const struct clk_div_table *table, u8 width,
+                              unsigned long flags)
 {
-       struct clk_divider *divider = to_clk_divider(hw);
        int i, bestdiv = 0;
        unsigned long parent_rate, best = 0, now, maxdiv;
        unsigned long parent_rate_saved = *best_parent_rate;
@@ -263,19 +284,11 @@ static int clk_divider_bestdiv(struct clk_hw *hw, unsigned long rate,
        if (!rate)
                rate = 1;
 
-       /* if read only, just return current value */
-       if (divider->flags & CLK_DIVIDER_READ_ONLY) {
-               bestdiv = readl(divider->reg) >> divider->shift;
-               bestdiv &= div_mask(divider);
-               bestdiv = _get_div(divider, bestdiv);
-               return bestdiv;
-       }
-
-       maxdiv = _get_maxdiv(divider);
+       maxdiv = _get_maxdiv(table, width, flags);
 
        if (!(__clk_get_flags(hw->clk) & CLK_SET_RATE_PARENT)) {
                parent_rate = *best_parent_rate;
-               bestdiv = _div_round(divider, parent_rate, rate);
+               bestdiv = _div_round(table, parent_rate, rate, flags);
                bestdiv = bestdiv == 0 ? 1 : bestdiv;
                bestdiv = bestdiv > maxdiv ? maxdiv : bestdiv;
                return bestdiv;
@@ -287,8 +300,8 @@ static int clk_divider_bestdiv(struct clk_hw *hw, unsigned long rate,
         */
        maxdiv = min(ULONG_MAX / rate, maxdiv);
 
-       for (i = 1; i <= maxdiv; i = _next_div(divider, i)) {
-               if (!_is_valid_div(divider, i))
+       for (i = 1; i <= maxdiv; i = _next_div(table, i, flags)) {
+               if (!_is_valid_div(table, i, flags))
                        continue;
                if (rate * i == parent_rate_saved) {
                        /*
@@ -302,7 +315,7 @@ static int clk_divider_bestdiv(struct clk_hw *hw, unsigned long rate,
                parent_rate = __clk_round_rate(__clk_get_parent(hw->clk),
                                MULT_ROUND_UP(rate, i));
                now = DIV_ROUND_UP(parent_rate, i);
-               if (_is_best_div(divider, rate, now, best)) {
+               if (_is_best_div(rate, now, best, flags)) {
                        bestdiv = i;
                        best = now;
                        *best_parent_rate = parent_rate;
@@ -310,48 +323,79 @@ static int clk_divider_bestdiv(struct clk_hw *hw, unsigned long rate,
        }
 
        if (!bestdiv) {
-               bestdiv = _get_maxdiv(divider);
+               bestdiv = _get_maxdiv(table, width, flags);
                *best_parent_rate = __clk_round_rate(__clk_get_parent(hw->clk), 1);
        }
 
        return bestdiv;
 }
 
-static long clk_divider_round_rate(struct clk_hw *hw, unsigned long rate,
-                               unsigned long *prate)
+long divider_round_rate(struct clk_hw *hw, unsigned long rate,
+                       unsigned long *prate, const struct clk_div_table *table,
+                       u8 width, unsigned long flags)
 {
        int div;
-       div = clk_divider_bestdiv(hw, rate, prate);
+
+       div = clk_divider_bestdiv(hw, rate, prate, table, width, flags);
 
        return DIV_ROUND_UP(*prate, div);
 }
+EXPORT_SYMBOL_GPL(divider_round_rate);
 
-static int clk_divider_set_rate(struct clk_hw *hw, unsigned long rate,
-                               unsigned long parent_rate)
+static long clk_divider_round_rate(struct clk_hw *hw, unsigned long rate,
+                               unsigned long *prate)
 {
        struct clk_divider *divider = to_clk_divider(hw);
+       int bestdiv;
+
+       /* if read only, just return current value */
+       if (divider->flags & CLK_DIVIDER_READ_ONLY) {
+               bestdiv = readl(divider->reg) >> divider->shift;
+               bestdiv &= div_mask(divider->width);
+               bestdiv = _get_div(divider->table, bestdiv, divider->flags);
+               return bestdiv;
+       }
+
+       return divider_round_rate(hw, rate, prate, divider->table,
+                                 divider->width, divider->flags);
+}
+
+int divider_get_val(unsigned long rate, unsigned long parent_rate,
+                   const struct clk_div_table *table, u8 width,
+                   unsigned long flags)
+{
        unsigned int div, value;
-       unsigned long flags = 0;
-       u32 val;
 
        div = DIV_ROUND_UP(parent_rate, rate);
 
-       if (!_is_valid_div(divider, div))
+       if (!_is_valid_div(table, div, flags))
                return -EINVAL;
 
-       value = _get_val(divider, div);
+       value = _get_val(table, div, flags);
+
+       return min_t(unsigned int, value, div_mask(width));
+}
+EXPORT_SYMBOL_GPL(divider_get_val);
+
+static int clk_divider_set_rate(struct clk_hw *hw, unsigned long rate,
+                               unsigned long parent_rate)
+{
+       struct clk_divider *divider = to_clk_divider(hw);
+       unsigned int value;
+       unsigned long flags = 0;
+       u32 val;
 
-       if (value > div_mask(divider))
-               value = div_mask(divider);
+       value = divider_get_val(rate, parent_rate, divider->table,
+                               divider->width, divider->flags);
 
        if (divider->lock)
                spin_lock_irqsave(divider->lock, flags);
 
        if (divider->flags & CLK_DIVIDER_HIWORD_MASK) {
-               val = div_mask(divider) << (divider->shift + 16);
+               val = div_mask(divider->width) << (divider->shift + 16);
        } else {
                val = clk_readl(divider->reg);
-               val &= ~(div_mask(divider) << divider->shift);
+               val &= ~(div_mask(divider->width) << divider->shift);
        }
        val |= value << divider->shift;
        clk_writel(val, divider->reg);
@@ -463,3 +507,19 @@ struct clk *clk_register_divider_table(struct device *dev, const char *name,
                        width, clk_divider_flags, table, lock);
 }
 EXPORT_SYMBOL_GPL(clk_register_divider_table);
+
+void clk_unregister_divider(struct clk *clk)
+{
+       struct clk_divider *div;
+       struct clk_hw *hw;
+
+       hw = __clk_get_hw(clk);
+       if (!hw)
+               return;
+
+       div = to_clk_divider(hw);
+
+       clk_unregister(clk);
+       kfree(div);
+}
+EXPORT_SYMBOL_GPL(clk_unregister_divider);
index 51fd87fb7ba691e8a52e40ddc1ee4524ecd3e781..3f0e4200cb5d4ca4a680c78479ac86ed116766a5 100644 (file)
@@ -128,7 +128,7 @@ struct clk *clk_register_gate(struct device *dev, const char *name,
        struct clk_init_data init;
 
        if (clk_gate_flags & CLK_GATE_HIWORD_MASK) {
-               if (bit_idx > 16) {
+               if (bit_idx > 15) {
                        pr_err("gate bit exceeds LOWORD field\n");
                        return ERR_PTR(-EINVAL);
                }
@@ -162,3 +162,19 @@ struct clk *clk_register_gate(struct device *dev, const char *name,
        return clk;
 }
 EXPORT_SYMBOL_GPL(clk_register_gate);
+
+void clk_unregister_gate(struct clk *clk)
+{
+       struct clk_gate *gate;
+       struct clk_hw *hw;
+
+       hw = __clk_get_hw(clk);
+       if (!hw)
+               return;
+
+       gate = to_clk_gate(hw);
+
+       clk_unregister(clk);
+       kfree(gate);
+}
+EXPORT_SYMBOL_GPL(clk_unregister_gate);
index 6e1ecf94bf58daa279cb47e42065da9a9db3c581..69a094c3783d8eb2a2c0d3624f3a641f97a5d484 100644 (file)
@@ -177,3 +177,19 @@ struct clk *clk_register_mux(struct device *dev, const char *name,
                                      NULL, lock);
 }
 EXPORT_SYMBOL_GPL(clk_register_mux);
+
+void clk_unregister_mux(struct clk *clk)
+{
+       struct clk_mux *mux;
+       struct clk_hw *hw;
+
+       hw = __clk_get_hw(clk);
+       if (!hw)
+               return;
+
+       mux = to_clk_mux(hw);
+
+       clk_unregister(clk);
+       kfree(mux);
+}
+EXPORT_SYMBOL_GPL(clk_unregister_mux);
similarity index 80%
rename from drivers/clk/clk-ppc-corenet.c
rename to drivers/clk/clk-qoriq.c
index b6e6c85507a5a7706c8c69f2c6611d908ade8611..f9b7eb43ac695fe7c3b4a34469a416e78335f95a 100644 (file)
@@ -5,7 +5,7 @@
  * it under the terms of the GNU General Public License version 2 as
  * published by the Free Software Foundation.
  *
- * clock driver for Freescale PowerPC corenet SoCs.
+ * clock driver for Freescale QorIQ SoCs.
  */
 #include <linux/clk-provider.h>
 #include <linux/io.h>
@@ -19,6 +19,7 @@
 struct cmux_clk {
        struct clk_hw hw;
        void __iomem *reg;
+       unsigned int clk_per_pll;
        u32 flags;
 };
 
@@ -27,14 +28,12 @@ struct cmux_clk {
 #define CLKSEL_ADJUST          BIT(0)
 #define to_cmux_clk(p)         container_of(p, struct cmux_clk, hw)
 
-static unsigned int clocks_per_pll;
-
 static int cmux_set_parent(struct clk_hw *hw, u8 idx)
 {
        struct cmux_clk *clk = to_cmux_clk(hw);
        u32 clksel;
 
-       clksel = ((idx / clocks_per_pll) << 2) + idx % clocks_per_pll;
+       clksel = ((idx / clk->clk_per_pll) << 2) + idx % clk->clk_per_pll;
        if (clk->flags & CLKSEL_ADJUST)
                clksel += 8;
        clksel = (clksel & 0xf) << CLKSEL_SHIFT;
@@ -52,7 +51,7 @@ static u8 cmux_get_parent(struct clk_hw *hw)
        clksel = (clksel >> CLKSEL_SHIFT) & 0xf;
        if (clk->flags & CLKSEL_ADJUST)
                clksel -= 8;
-       clksel = (clksel >> 2) * clocks_per_pll + clksel % 4;
+       clksel = (clksel >> 2) * clk->clk_per_pll + clksel % 4;
 
        return clksel;
 }
@@ -72,6 +71,7 @@ static void __init core_mux_init(struct device_node *np)
        u32     offset;
        const char *clk_name;
        const char **parent_names;
+       struct of_phandle_args clkspec;
 
        rc = of_property_read_u32(np, "reg", &offset);
        if (rc) {
@@ -105,6 +105,17 @@ static void __init core_mux_init(struct device_node *np)
                goto err_clk;
        }
 
+       rc = of_parse_phandle_with_args(np, "clocks", "#clock-cells", 0,
+                                       &clkspec);
+       if (rc) {
+               pr_err("%s: parse clock node error\n", __func__);
+               goto err_clk;
+       }
+
+       cmux_clk->clk_per_pll = of_property_count_strings(clkspec.np,
+                       "clock-output-names");
+       of_node_put(clkspec.np);
+
        node = of_find_compatible_node(NULL, NULL, "fsl,p4080-clockgen");
        if (node && (offset >= 0x80))
                cmux_clk->flags = CLKSEL_ADJUST;
@@ -155,7 +166,7 @@ static void __init core_pll_init(struct device_node *np)
 
        base = of_iomap(np, 0);
        if (!base) {
-               pr_err("clk-ppc: iomap error\n");
+               pr_err("clk-qoriq: iomap error\n");
                return;
        }
 
@@ -181,9 +192,6 @@ static void __init core_pll_init(struct device_node *np)
                goto err_map;
        }
 
-       /* output clock number per PLL */
-       clocks_per_pll = count;
-
        subclks = kzalloc(sizeof(struct clk *) * count, GFP_KERNEL);
        if (!subclks) {
                pr_err("%s: could not allocate subclks\n", __func__);
@@ -252,7 +260,7 @@ static void __init sysclk_init(struct device_node *node)
        u32 rate;
 
        if (!np) {
-               pr_err("ppc-clk: could not get parent node\n");
+               pr_err("qoriq-clk: could not get parent node\n");
                return;
        }
 
@@ -267,40 +275,9 @@ static void __init sysclk_init(struct device_node *node)
        if (!IS_ERR(clk))
                of_clk_add_provider(np, of_clk_src_simple_get, clk);
 }
-
-static const struct of_device_id clk_match[] __initconst = {
-       { .compatible = "fsl,qoriq-sysclk-1.0", .data = sysclk_init, },
-       { .compatible = "fsl,qoriq-sysclk-2.0", .data = sysclk_init, },
-       { .compatible = "fsl,qoriq-core-pll-1.0", .data = core_pll_init, },
-       { .compatible = "fsl,qoriq-core-pll-2.0", .data = core_pll_init, },
-       { .compatible = "fsl,qoriq-core-mux-1.0", .data = core_mux_init, },
-       { .compatible = "fsl,qoriq-core-mux-2.0", .data = core_mux_init, },
-       {}
-};
-
-static int __init ppc_corenet_clk_probe(struct platform_device *pdev)
-{
-       of_clk_init(clk_match);
-
-       return 0;
-}
-
-static const struct of_device_id ppc_clk_ids[] __initconst = {
-       { .compatible = "fsl,qoriq-clockgen-1.0", },
-       { .compatible = "fsl,qoriq-clockgen-2.0", },
-       {}
-};
-
-static struct platform_driver ppc_corenet_clk_driver __initdata = {
-       .driver = {
-               .name = "ppc_corenet_clock",
-               .of_match_table = ppc_clk_ids,
-       },
-       .probe = ppc_corenet_clk_probe,
-};
-
-static int __init ppc_corenet_clk_init(void)
-{
-       return platform_driver_register(&ppc_corenet_clk_driver);
-}
-subsys_initcall(ppc_corenet_clk_init);
+CLK_OF_DECLARE(qoriq_sysclk_1, "fsl,qoriq-sysclk-1.0", sysclk_init);
+CLK_OF_DECLARE(qoriq_sysclk_2, "fsl,qoriq-sysclk-2.0", sysclk_init);
+CLK_OF_DECLARE(qoriq_core_pll_1, "fsl,qoriq-core-pll-1.0", core_pll_init);
+CLK_OF_DECLARE(qoriq_core_pll_2, "fsl,qoriq-core-pll-2.0", core_pll_init);
+CLK_OF_DECLARE(qoriq_core_mux_1, "fsl,qoriq-core-mux-1.0", core_mux_init);
+CLK_OF_DECLARE(qoriq_core_mux_2, "fsl,qoriq-core-mux-2.0", core_mux_init);
index f4963b7d4e17d41b6a6553854c5250a7e90bfdef..aa8a9d2d0b73efb62ec1a4ecad23de93a8e42a0d 100644 (file)
@@ -343,13 +343,9 @@ unlock:
 static void clk_debug_unregister(struct clk *clk)
 {
        mutex_lock(&clk_debug_lock);
-       if (!clk->dentry)
-               goto out;
-
        hlist_del_init(&clk->debug_node);
        debugfs_remove_recursive(clk->dentry);
        clk->dentry = NULL;
-out:
        mutex_unlock(&clk_debug_lock);
 }
 
@@ -694,14 +690,20 @@ struct clk *__clk_lookup(const char *name)
        return NULL;
 }
 
-/*
- * Helper for finding best parent to provide a given frequency. This can be used
- * directly as a determine_rate callback (e.g. for a mux), or from a more
- * complex clock that may combine a mux with other operations.
- */
-long __clk_mux_determine_rate(struct clk_hw *hw, unsigned long rate,
-                             unsigned long *best_parent_rate,
-                             struct clk_hw **best_parent_p)
+static bool mux_is_better_rate(unsigned long rate, unsigned long now,
+                          unsigned long best, unsigned long flags)
+{
+       if (flags & CLK_MUX_ROUND_CLOSEST)
+               return abs(now - rate) < abs(best - rate);
+
+       return now <= rate && now > best;
+}
+
+static long
+clk_mux_determine_rate_flags(struct clk_hw *hw, unsigned long rate,
+                            unsigned long *best_parent_rate,
+                            struct clk_hw **best_parent_p,
+                            unsigned long flags)
 {
        struct clk *clk = hw->clk, *parent, *best_parent = NULL;
        int i, num_parents;
@@ -729,7 +731,7 @@ long __clk_mux_determine_rate(struct clk_hw *hw, unsigned long rate,
                        parent_rate = __clk_round_rate(parent, rate);
                else
                        parent_rate = __clk_get_rate(parent);
-               if (parent_rate <= rate && parent_rate > best) {
+               if (mux_is_better_rate(rate, parent_rate, best, flags)) {
                        best_parent = parent;
                        best = parent_rate;
                }
@@ -742,8 +744,31 @@ out:
 
        return best;
 }
+
+/*
+ * Helper for finding best parent to provide a given frequency. This can be used
+ * directly as a determine_rate callback (e.g. for a mux), or from a more
+ * complex clock that may combine a mux with other operations.
+ */
+long __clk_mux_determine_rate(struct clk_hw *hw, unsigned long rate,
+                             unsigned long *best_parent_rate,
+                             struct clk_hw **best_parent_p)
+{
+       return clk_mux_determine_rate_flags(hw, rate, best_parent_rate,
+                                           best_parent_p, 0);
+}
 EXPORT_SYMBOL_GPL(__clk_mux_determine_rate);
 
+long __clk_mux_determine_rate_closest(struct clk_hw *hw, unsigned long rate,
+                             unsigned long *best_parent_rate,
+                             struct clk_hw **best_parent_p)
+{
+       return clk_mux_determine_rate_flags(hw, rate, best_parent_rate,
+                                           best_parent_p,
+                                           CLK_MUX_ROUND_CLOSEST);
+}
+EXPORT_SYMBOL_GPL(__clk_mux_determine_rate_closest);
+
 /***        clk api        ***/
 
 void __clk_unprepare(struct clk *clk)
@@ -1366,7 +1391,7 @@ static struct clk *clk_calc_new_rates(struct clk *clk, unsigned long rate)
                new_rate = clk->ops->determine_rate(clk->hw, rate,
                                                    &best_parent_rate,
                                                    &parent_hw);
-               parent = parent_hw->clk;
+               parent = parent_hw ? parent_hw->clk : NULL;
        } else if (clk->ops->round_rate) {
                new_rate = clk->ops->round_rate(clk->hw, rate,
                                                &best_parent_rate);
@@ -1390,7 +1415,7 @@ static struct clk *clk_calc_new_rates(struct clk *clk, unsigned long rate)
        }
 
        /* try finding the new parent index */
-       if (parent) {
+       if (parent && clk->num_parents > 1) {
                p_index = clk_fetch_parent_index(clk, parent);
                if (p_index < 0) {
                        pr_debug("%s: clk %s can not be parent of clk %s\n",
@@ -1651,6 +1676,36 @@ void __clk_reparent(struct clk *clk, struct clk *new_parent)
        __clk_recalc_rates(clk, POST_RATE_CHANGE);
 }
 
+/**
+ * clk_has_parent - check if a clock is a possible parent for another
+ * @clk: clock source
+ * @parent: parent clock source
+ *
+ * This function can be used in drivers that need to check that a clock can be
+ * the parent of another without actually changing the parent.
+ *
+ * Returns true if @parent is a possible parent for @clk, false otherwise.
+ */
+bool clk_has_parent(struct clk *clk, struct clk *parent)
+{
+       unsigned int i;
+
+       /* NULL clocks should be nops, so return success if either is NULL. */
+       if (!clk || !parent)
+               return true;
+
+       /* Optimize for the case where the parent is already the parent. */
+       if (clk->parent == parent)
+               return true;
+
+       for (i = 0; i < clk->num_parents; i++)
+               if (strcmp(clk->parent_names[i], parent->name) == 0)
+                       return true;
+
+       return false;
+}
+EXPORT_SYMBOL_GPL(clk_has_parent);
+
 /**
  * clk_set_parent - switch the parent of a mux clk
  * @clk: the mux clk whose input we are switching
@@ -1778,6 +1833,7 @@ out_unlock:
 out:
        return ret;
 }
+EXPORT_SYMBOL_GPL(clk_set_phase);
 
 /**
  * clk_get_phase - return the phase shift of a clock signal
@@ -1800,6 +1856,7 @@ int clk_get_phase(struct clk *clk)
 out:
        return ret;
 }
+EXPORT_SYMBOL_GPL(clk_get_phase);
 
 /**
  * __clk_init - initialize the data structures in a struct clk
index 1107351ed34682e7cd8fa04ffcd61c0e4bc146f9..0d7ab52b7ab0076fec09340410c09bca0efe3b4f 100644 (file)
@@ -29,6 +29,15 @@ config IPQ_GCC_806X
          Say Y if you want to use peripheral devices such as UART, SPI,
          i2c, USB, SD/eMMC, etc.
 
+config IPQ_LCC_806X
+       tristate "IPQ806x LPASS Clock Controller"
+       select IPQ_GCC_806X
+       depends on COMMON_CLK_QCOM
+       help
+         Support for the LPASS clock controller on ipq806x devices.
+         Say Y if you want to use audio devices such as i2s, pcm,
+         S/PDIF, etc.
+
 config MSM_GCC_8660
        tristate "MSM8660 Global Clock Controller"
        depends on COMMON_CLK_QCOM
@@ -45,6 +54,15 @@ config MSM_GCC_8960
          Say Y if you want to use peripheral devices such as UART, SPI,
          i2c, USB, SD/eMMC, SATA, PCIe, etc.
 
+config MSM_LCC_8960
+       tristate "APQ8064/MSM8960 LPASS Clock Controller"
+       select MSM_GCC_8960
+       depends on COMMON_CLK_QCOM
+       help
+         Support for the LPASS clock controller on apq8064/msm8960 devices.
+         Say Y if you want to use audio devices such as i2s, pcm,
+         SLIMBus, etc.
+
 config MSM_MMCC_8960
        tristate "MSM8960 Multimedia Clock Controller"
        select MSM_GCC_8960
index 783cfb24faa41cbbac81e676d5ed129733529aac..61782646959534bec2b19d445762abbec7fb1591 100644 (file)
@@ -6,13 +6,17 @@ clk-qcom-y += clk-pll.o
 clk-qcom-y += clk-rcg.o
 clk-qcom-y += clk-rcg2.o
 clk-qcom-y += clk-branch.o
+clk-qcom-y += clk-regmap-divider.o
+clk-qcom-y += clk-regmap-mux.o
 clk-qcom-y += reset.o
 
 obj-$(CONFIG_APQ_GCC_8084) += gcc-apq8084.o
 obj-$(CONFIG_APQ_MMCC_8084) += mmcc-apq8084.o
 obj-$(CONFIG_IPQ_GCC_806X) += gcc-ipq806x.o
+obj-$(CONFIG_IPQ_LCC_806X) += lcc-ipq806x.o
 obj-$(CONFIG_MSM_GCC_8660) += gcc-msm8660.o
 obj-$(CONFIG_MSM_GCC_8960) += gcc-msm8960.o
+obj-$(CONFIG_MSM_LCC_8960) += lcc-msm8960.o
 obj-$(CONFIG_MSM_GCC_8974) += gcc-msm8974.o
 obj-$(CONFIG_MSM_MMCC_8960) += mmcc-msm8960.o
 obj-$(CONFIG_MSM_MMCC_8974) += mmcc-msm8974.o
diff --git a/drivers/clk/qcom/clk-regmap-divider.c b/drivers/clk/qcom/clk-regmap-divider.c
new file mode 100644 (file)
index 0000000..5348491
--- /dev/null
@@ -0,0 +1,70 @@
+/*
+ * Copyright (c) 2014, The Linux Foundation. All rights reserved.
+ *
+ * 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/kernel.h>
+#include <linux/bitops.h>
+#include <linux/regmap.h>
+#include <linux/export.h>
+
+#include "clk-regmap-divider.h"
+
+static inline struct clk_regmap_div *to_clk_regmap_div(struct clk_hw *hw)
+{
+       return container_of(to_clk_regmap(hw), struct clk_regmap_div, clkr);
+}
+
+static long div_round_rate(struct clk_hw *hw, unsigned long rate,
+                          unsigned long *prate)
+{
+       struct clk_regmap_div *divider = to_clk_regmap_div(hw);
+
+       return divider_round_rate(hw, rate, prate, NULL, divider->width,
+                                 CLK_DIVIDER_ROUND_CLOSEST);
+}
+
+static int div_set_rate(struct clk_hw *hw, unsigned long rate,
+                       unsigned long parent_rate)
+{
+       struct clk_regmap_div *divider = to_clk_regmap_div(hw);
+       struct clk_regmap *clkr = &divider->clkr;
+       u32 div;
+
+       div = divider_get_val(rate, parent_rate, NULL, divider->width,
+                             CLK_DIVIDER_ROUND_CLOSEST);
+
+       return regmap_update_bits(clkr->regmap, divider->reg,
+                                 (BIT(divider->width) - 1) << divider->shift,
+                                 div << divider->shift);
+}
+
+static unsigned long div_recalc_rate(struct clk_hw *hw,
+                                    unsigned long parent_rate)
+{
+       struct clk_regmap_div *divider = to_clk_regmap_div(hw);
+       struct clk_regmap *clkr = &divider->clkr;
+       u32 div;
+
+       regmap_read(clkr->regmap, divider->reg, &div);
+       div >>= divider->shift;
+       div &= BIT(divider->width) - 1;
+
+       return divider_recalc_rate(hw, parent_rate, div, NULL,
+                                  CLK_DIVIDER_ROUND_CLOSEST);
+}
+
+const struct clk_ops clk_regmap_div_ops = {
+       .round_rate = div_round_rate,
+       .set_rate = div_set_rate,
+       .recalc_rate = div_recalc_rate,
+};
+EXPORT_SYMBOL_GPL(clk_regmap_div_ops);
diff --git a/drivers/clk/qcom/clk-regmap-divider.h b/drivers/clk/qcom/clk-regmap-divider.h
new file mode 100644 (file)
index 0000000..fc4492e
--- /dev/null
@@ -0,0 +1,29 @@
+/*
+ * Copyright (c) 2014, The Linux Foundation. All rights reserved.
+ *
+ * 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.
+ */
+
+#ifndef __QCOM_CLK_REGMAP_DIVIDER_H__
+#define __QCOM_CLK_REGMAP_DIVIDER_H__
+
+#include <linux/clk-provider.h>
+#include "clk-regmap.h"
+
+struct clk_regmap_div {
+       u32                     reg;
+       u32                     shift;
+       u32                     width;
+       struct clk_regmap       clkr;
+};
+
+extern const struct clk_ops clk_regmap_div_ops;
+
+#endif
diff --git a/drivers/clk/qcom/clk-regmap-mux.c b/drivers/clk/qcom/clk-regmap-mux.c
new file mode 100644 (file)
index 0000000..cae3071
--- /dev/null
@@ -0,0 +1,59 @@
+/*
+ * Copyright (c) 2014, The Linux Foundation. All rights reserved.
+ *
+ * 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/kernel.h>
+#include <linux/bitops.h>
+#include <linux/regmap.h>
+#include <linux/export.h>
+
+#include "clk-regmap-mux.h"
+
+static inline struct clk_regmap_mux *to_clk_regmap_mux(struct clk_hw *hw)
+{
+       return container_of(to_clk_regmap(hw), struct clk_regmap_mux, clkr);
+}
+
+static u8 mux_get_parent(struct clk_hw *hw)
+{
+       struct clk_regmap_mux *mux = to_clk_regmap_mux(hw);
+       struct clk_regmap *clkr = to_clk_regmap(hw);
+       unsigned int mask = GENMASK(mux->width - 1, 0);
+       unsigned int val;
+
+       regmap_read(clkr->regmap, mux->reg, &val);
+
+       val >>= mux->shift;
+       val &= mask;
+
+       return val;
+}
+
+static int mux_set_parent(struct clk_hw *hw, u8 index)
+{
+       struct clk_regmap_mux *mux = to_clk_regmap_mux(hw);
+       struct clk_regmap *clkr = to_clk_regmap(hw);
+       unsigned int mask = GENMASK(mux->width + mux->shift - 1, mux->shift);
+       unsigned int val;
+
+       val = index;
+       val <<= mux->shift;
+
+       return regmap_update_bits(clkr->regmap, mux->reg, mask, val);
+}
+
+const struct clk_ops clk_regmap_mux_closest_ops = {
+       .get_parent = mux_get_parent,
+       .set_parent = mux_set_parent,
+       .determine_rate = __clk_mux_determine_rate_closest,
+};
+EXPORT_SYMBOL_GPL(clk_regmap_mux_closest_ops);
diff --git a/drivers/clk/qcom/clk-regmap-mux.h b/drivers/clk/qcom/clk-regmap-mux.h
new file mode 100644 (file)
index 0000000..5cec761
--- /dev/null
@@ -0,0 +1,29 @@
+/*
+ * Copyright (c) 2014, The Linux Foundation. All rights reserved.
+ *
+ * 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.
+ */
+
+#ifndef __QCOM_CLK_REGMAP_MUX_H__
+#define __QCOM_CLK_REGMAP_MUX_H__
+
+#include <linux/clk-provider.h>
+#include "clk-regmap.h"
+
+struct clk_regmap_mux {
+       u32                     reg;
+       u32                     shift;
+       u32                     width;
+       struct clk_regmap       clkr;
+};
+
+extern const struct clk_ops clk_regmap_mux_closest_ops;
+
+#endif
index afed5eb0691e101c246275b1b6a80d44de9d1eed..cbdc31dea7f4311d091b938959179b3dd97e0fbe 100644 (file)
@@ -75,6 +75,17 @@ static struct clk_pll pll3 = {
        },
 };
 
+static struct clk_regmap pll4_vote = {
+       .enable_reg = 0x34c0,
+       .enable_mask = BIT(4),
+       .hw.init = &(struct clk_init_data){
+               .name = "pll4_vote",
+               .parent_names = (const char *[]){ "pll4" },
+               .num_parents = 1,
+               .ops = &clk_pll_vote_ops,
+       },
+};
+
 static struct clk_pll pll8 = {
        .l_reg = 0x3144,
        .m_reg = 0x3148,
@@ -2163,6 +2174,7 @@ static struct clk_regmap *gcc_ipq806x_clks[] = {
        [PLL0] = &pll0.clkr,
        [PLL0_VOTE] = &pll0_vote,
        [PLL3] = &pll3.clkr,
+       [PLL4_VOTE] = &pll4_vote,
        [PLL8] = &pll8.clkr,
        [PLL8_VOTE] = &pll8_vote,
        [PLL14] = &pll14.clkr,
diff --git a/drivers/clk/qcom/lcc-ipq806x.c b/drivers/clk/qcom/lcc-ipq806x.c
new file mode 100644 (file)
index 0000000..121ffde
--- /dev/null
@@ -0,0 +1,473 @@
+/*
+ * Copyright (c) 2014, The Linux Foundation. All rights reserved.
+ *
+ * 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/kernel.h>
+#include <linux/bitops.h>
+#include <linux/err.h>
+#include <linux/platform_device.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/of_device.h>
+#include <linux/clk-provider.h>
+#include <linux/regmap.h>
+
+#include <dt-bindings/clock/qcom,lcc-ipq806x.h>
+
+#include "common.h"
+#include "clk-regmap.h"
+#include "clk-pll.h"
+#include "clk-rcg.h"
+#include "clk-branch.h"
+#include "clk-regmap-divider.h"
+#include "clk-regmap-mux.h"
+
+static struct clk_pll pll4 = {
+       .l_reg = 0x4,
+       .m_reg = 0x8,
+       .n_reg = 0xc,
+       .config_reg = 0x14,
+       .mode_reg = 0x0,
+       .status_reg = 0x18,
+       .status_bit = 16,
+       .clkr.hw.init = &(struct clk_init_data){
+               .name = "pll4",
+               .parent_names = (const char *[]){ "pxo" },
+               .num_parents = 1,
+               .ops = &clk_pll_ops,
+       },
+};
+
+static const struct pll_config pll4_config = {
+       .l = 0xf,
+       .m = 0x91,
+       .n = 0xc7,
+       .vco_val = 0x0,
+       .vco_mask = BIT(17) | BIT(16),
+       .pre_div_val = 0x0,
+       .pre_div_mask = BIT(19),
+       .post_div_val = 0x0,
+       .post_div_mask = BIT(21) | BIT(20),
+       .mn_ena_mask = BIT(22),
+       .main_output_mask = BIT(23),
+};
+
+#define P_PXO  0
+#define P_PLL4 1
+
+static const u8 lcc_pxo_pll4_map[] = {
+       [P_PXO]         = 0,
+       [P_PLL4]        = 2,
+};
+
+static const char *lcc_pxo_pll4[] = {
+       "pxo",
+       "pll4_vote",
+};
+
+static struct freq_tbl clk_tbl_aif_mi2s[] = {
+       {  1024000, P_PLL4, 4,  1,  96 },
+       {  1411200, P_PLL4, 4,  2, 139 },
+       {  1536000, P_PLL4, 4,  1,  64 },
+       {  2048000, P_PLL4, 4,  1,  48 },
+       {  2116800, P_PLL4, 4,  2,  93 },
+       {  2304000, P_PLL4, 4,  2,  85 },
+       {  2822400, P_PLL4, 4,  6, 209 },
+       {  3072000, P_PLL4, 4,  1,  32 },
+       {  3175200, P_PLL4, 4,  1,  31 },
+       {  4096000, P_PLL4, 4,  1,  24 },
+       {  4233600, P_PLL4, 4,  9, 209 },
+       {  4608000, P_PLL4, 4,  3,  64 },
+       {  5644800, P_PLL4, 4, 12, 209 },
+       {  6144000, P_PLL4, 4,  1,  16 },
+       {  6350400, P_PLL4, 4,  2,  31 },
+       {  8192000, P_PLL4, 4,  1,  12 },
+       {  8467200, P_PLL4, 4, 18, 209 },
+       {  9216000, P_PLL4, 4,  3,  32 },
+       { 11289600, P_PLL4, 4, 24, 209 },
+       { 12288000, P_PLL4, 4,  1,   8 },
+       { 12700800, P_PLL4, 4, 27, 209 },
+       { 13824000, P_PLL4, 4,  9,  64 },
+       { 16384000, P_PLL4, 4,  1,   6 },
+       { 16934400, P_PLL4, 4, 41, 238 },
+       { 18432000, P_PLL4, 4,  3,  16 },
+       { 22579200, P_PLL4, 2, 24, 209 },
+       { 24576000, P_PLL4, 4,  1,   4 },
+       { 27648000, P_PLL4, 4,  9,  32 },
+       { 33868800, P_PLL4, 4, 41, 119 },
+       { 36864000, P_PLL4, 4,  3,   8 },
+       { 45158400, P_PLL4, 1, 24, 209 },
+       { 49152000, P_PLL4, 4,  1,   2 },
+       { 50803200, P_PLL4, 1, 27, 209 },
+       { }
+};
+
+static struct clk_rcg mi2s_osr_src = {
+       .ns_reg = 0x48,
+       .md_reg = 0x4c,
+       .mn = {
+               .mnctr_en_bit = 8,
+               .mnctr_reset_bit = 7,
+               .mnctr_mode_shift = 5,
+               .n_val_shift = 24,
+               .m_val_shift = 8,
+               .width = 8,
+       },
+       .p = {
+               .pre_div_shift = 3,
+               .pre_div_width = 2,
+       },
+       .s = {
+               .src_sel_shift = 0,
+               .parent_map = lcc_pxo_pll4_map,
+       },
+       .freq_tbl = clk_tbl_aif_mi2s,
+       .clkr = {
+               .enable_reg = 0x48,
+               .enable_mask = BIT(9),
+               .hw.init = &(struct clk_init_data){
+                       .name = "mi2s_osr_src",
+                       .parent_names = lcc_pxo_pll4,
+                       .num_parents = 2,
+                       .ops = &clk_rcg_ops,
+                       .flags = CLK_SET_RATE_GATE,
+               },
+       },
+};
+
+static const char *lcc_mi2s_parents[] = {
+       "mi2s_osr_src",
+};
+
+static struct clk_branch mi2s_osr_clk = {
+       .halt_reg = 0x50,
+       .halt_bit = 1,
+       .halt_check = BRANCH_HALT_ENABLE,
+       .clkr = {
+               .enable_reg = 0x48,
+               .enable_mask = BIT(17),
+               .hw.init = &(struct clk_init_data){
+                       .name = "mi2s_osr_clk",
+                       .parent_names = lcc_mi2s_parents,
+                       .num_parents = 1,
+                       .ops = &clk_branch_ops,
+                       .flags = CLK_SET_RATE_PARENT,
+               },
+       },
+};
+
+static struct clk_regmap_div mi2s_div_clk = {
+       .reg = 0x48,
+       .shift = 10,
+       .width = 4,
+       .clkr = {
+               .hw.init = &(struct clk_init_data){
+                       .name = "mi2s_div_clk",
+                       .parent_names = lcc_mi2s_parents,
+                       .num_parents = 1,
+                       .ops = &clk_regmap_div_ops,
+               },
+       },
+};
+
+static struct clk_branch mi2s_bit_div_clk = {
+       .halt_reg = 0x50,
+       .halt_bit = 0,
+       .halt_check = BRANCH_HALT_ENABLE,
+       .clkr = {
+               .enable_reg = 0x48,
+               .enable_mask = BIT(15),
+               .hw.init = &(struct clk_init_data){
+                       .name = "mi2s_bit_div_clk",
+                       .parent_names = (const char *[]){ "mi2s_div_clk" },
+                       .num_parents = 1,
+                       .ops = &clk_branch_ops,
+                       .flags = CLK_SET_RATE_PARENT,
+               },
+       },
+};
+
+
+static struct clk_regmap_mux mi2s_bit_clk = {
+       .reg = 0x48,
+       .shift = 14,
+       .width = 1,
+       .clkr = {
+               .hw.init = &(struct clk_init_data){
+                       .name = "mi2s_bit_clk",
+                       .parent_names = (const char *[]){
+                               "mi2s_bit_div_clk",
+                               "mi2s_codec_clk",
+                       },
+                       .num_parents = 2,
+                       .ops = &clk_regmap_mux_closest_ops,
+                       .flags = CLK_SET_RATE_PARENT,
+               },
+       },
+};
+
+static struct freq_tbl clk_tbl_pcm[] = {
+       {   64000, P_PLL4, 4, 1, 1536 },
+       {  128000, P_PLL4, 4, 1,  768 },
+       {  256000, P_PLL4, 4, 1,  384 },
+       {  512000, P_PLL4, 4, 1,  192 },
+       { 1024000, P_PLL4, 4, 1,   96 },
+       { 2048000, P_PLL4, 4, 1,   48 },
+       { },
+};
+
+static struct clk_rcg pcm_src = {
+       .ns_reg = 0x54,
+       .md_reg = 0x58,
+       .mn = {
+               .mnctr_en_bit = 8,
+               .mnctr_reset_bit = 7,
+               .mnctr_mode_shift = 5,
+               .n_val_shift = 16,
+               .m_val_shift = 16,
+               .width = 16,
+       },
+       .p = {
+               .pre_div_shift = 3,
+               .pre_div_width = 2,
+       },
+       .s = {
+               .src_sel_shift = 0,
+               .parent_map = lcc_pxo_pll4_map,
+       },
+       .freq_tbl = clk_tbl_pcm,
+       .clkr = {
+               .enable_reg = 0x54,
+               .enable_mask = BIT(9),
+               .hw.init = &(struct clk_init_data){
+                       .name = "pcm_src",
+                       .parent_names = lcc_pxo_pll4,
+                       .num_parents = 2,
+                       .ops = &clk_rcg_ops,
+                       .flags = CLK_SET_RATE_GATE,
+               },
+       },
+};
+
+static struct clk_branch pcm_clk_out = {
+       .halt_reg = 0x5c,
+       .halt_bit = 0,
+       .halt_check = BRANCH_HALT_ENABLE,
+       .clkr = {
+               .enable_reg = 0x54,
+               .enable_mask = BIT(11),
+               .hw.init = &(struct clk_init_data){
+                       .name = "pcm_clk_out",
+                       .parent_names = (const char *[]){ "pcm_src" },
+                       .num_parents = 1,
+                       .ops = &clk_branch_ops,
+                       .flags = CLK_SET_RATE_PARENT,
+               },
+       },
+};
+
+static struct clk_regmap_mux pcm_clk = {
+       .reg = 0x54,
+       .shift = 10,
+       .width = 1,
+       .clkr = {
+               .hw.init = &(struct clk_init_data){
+                       .name = "pcm_clk",
+                       .parent_names = (const char *[]){
+                               "pcm_clk_out",
+                               "pcm_codec_clk",
+                       },
+                       .num_parents = 2,
+                       .ops = &clk_regmap_mux_closest_ops,
+                       .flags = CLK_SET_RATE_PARENT,
+               },
+       },
+};
+
+static struct freq_tbl clk_tbl_aif_osr[] = {
+       {  22050, P_PLL4, 1, 147, 20480 },
+       {  32000, P_PLL4, 1,   1,    96 },
+       {  44100, P_PLL4, 1, 147, 10240 },
+       {  48000, P_PLL4, 1,   1,    64 },
+       {  88200, P_PLL4, 1, 147,  5120 },
+       {  96000, P_PLL4, 1,   1,    32 },
+       { 176400, P_PLL4, 1, 147,  2560 },
+       { 192000, P_PLL4, 1,   1,    16 },
+       { },
+};
+
+static struct clk_rcg spdif_src = {
+       .ns_reg = 0xcc,
+       .md_reg = 0xd0,
+       .mn = {
+               .mnctr_en_bit = 8,
+               .mnctr_reset_bit = 7,
+               .mnctr_mode_shift = 5,
+               .n_val_shift = 16,
+               .m_val_shift = 16,
+               .width = 8,
+       },
+       .p = {
+               .pre_div_shift = 3,
+               .pre_div_width = 2,
+       },
+       .s = {
+               .src_sel_shift = 0,
+               .parent_map = lcc_pxo_pll4_map,
+       },
+       .freq_tbl = clk_tbl_aif_osr,
+       .clkr = {
+               .enable_reg = 0xcc,
+               .enable_mask = BIT(9),
+               .hw.init = &(struct clk_init_data){
+                       .name = "spdif_src",
+                       .parent_names = lcc_pxo_pll4,
+                       .num_parents = 2,
+                       .ops = &clk_rcg_ops,
+                       .flags = CLK_SET_RATE_GATE,
+               },
+       },
+};
+
+static const char *lcc_spdif_parents[] = {
+       "spdif_src",
+};
+
+static struct clk_branch spdif_clk = {
+       .halt_reg = 0xd4,
+       .halt_bit = 1,
+       .halt_check = BRANCH_HALT_ENABLE,
+       .clkr = {
+               .enable_reg = 0xcc,
+               .enable_mask = BIT(12),
+               .hw.init = &(struct clk_init_data){
+                       .name = "spdif_clk",
+                       .parent_names = lcc_spdif_parents,
+                       .num_parents = 1,
+                       .ops = &clk_branch_ops,
+                       .flags = CLK_SET_RATE_PARENT,
+               },
+       },
+};
+
+static struct freq_tbl clk_tbl_ahbix[] = {
+       { 131072, P_PLL4, 1, 1, 3 },
+       { },
+};
+
+static struct clk_rcg ahbix_clk = {
+       .ns_reg = 0x38,
+       .md_reg = 0x3c,
+       .mn = {
+               .mnctr_en_bit = 8,
+               .mnctr_reset_bit = 7,
+               .mnctr_mode_shift = 5,
+               .n_val_shift = 24,
+               .m_val_shift = 8,
+               .width = 8,
+       },
+       .p = {
+               .pre_div_shift = 3,
+               .pre_div_width = 2,
+       },
+       .s = {
+               .src_sel_shift = 0,
+               .parent_map = lcc_pxo_pll4_map,
+       },
+       .freq_tbl = clk_tbl_ahbix,
+       .clkr = {
+               .enable_reg = 0x38,
+               .enable_mask = BIT(10), /* toggle the gfmux to select mn/pxo */
+               .hw.init = &(struct clk_init_data){
+                       .name = "ahbix",
+                       .parent_names = lcc_pxo_pll4,
+                       .num_parents = 2,
+                       .ops = &clk_rcg_ops,
+                       .flags = CLK_SET_RATE_GATE,
+               },
+       },
+};
+
+static struct clk_regmap *lcc_ipq806x_clks[] = {
+       [PLL4] = &pll4.clkr,
+       [MI2S_OSR_SRC] = &mi2s_osr_src.clkr,
+       [MI2S_OSR_CLK] = &mi2s_osr_clk.clkr,
+       [MI2S_DIV_CLK] = &mi2s_div_clk.clkr,
+       [MI2S_BIT_DIV_CLK] = &mi2s_bit_div_clk.clkr,
+       [MI2S_BIT_CLK] = &mi2s_bit_clk.clkr,
+       [PCM_SRC] = &pcm_src.clkr,
+       [PCM_CLK_OUT] = &pcm_clk_out.clkr,
+       [PCM_CLK] = &pcm_clk.clkr,
+       [SPDIF_SRC] = &spdif_src.clkr,
+       [SPDIF_CLK] = &spdif_clk.clkr,
+       [AHBIX_CLK] = &ahbix_clk.clkr,
+};
+
+static const struct regmap_config lcc_ipq806x_regmap_config = {
+       .reg_bits       = 32,
+       .reg_stride     = 4,
+       .val_bits       = 32,
+       .max_register   = 0xfc,
+       .fast_io        = true,
+};
+
+static const struct qcom_cc_desc lcc_ipq806x_desc = {
+       .config = &lcc_ipq806x_regmap_config,
+       .clks = lcc_ipq806x_clks,
+       .num_clks = ARRAY_SIZE(lcc_ipq806x_clks),
+};
+
+static const struct of_device_id lcc_ipq806x_match_table[] = {
+       { .compatible = "qcom,lcc-ipq8064" },
+       { }
+};
+MODULE_DEVICE_TABLE(of, lcc_ipq806x_match_table);
+
+static int lcc_ipq806x_probe(struct platform_device *pdev)
+{
+       u32 val;
+       struct regmap *regmap;
+
+       regmap = qcom_cc_map(pdev, &lcc_ipq806x_desc);
+       if (IS_ERR(regmap))
+               return PTR_ERR(regmap);
+
+       /* Configure the rate of PLL4 if the bootloader hasn't already */
+       val = regmap_read(regmap, 0x0, &val);
+       if (!val)
+               clk_pll_configure_sr(&pll4, regmap, &pll4_config, true);
+       /* Enable PLL4 source on the LPASS Primary PLL Mux */
+       regmap_write(regmap, 0xc4, 0x1);
+
+       return qcom_cc_really_probe(pdev, &lcc_ipq806x_desc, regmap);
+}
+
+static int lcc_ipq806x_remove(struct platform_device *pdev)
+{
+       qcom_cc_remove(pdev);
+       return 0;
+}
+
+static struct platform_driver lcc_ipq806x_driver = {
+       .probe          = lcc_ipq806x_probe,
+       .remove         = lcc_ipq806x_remove,
+       .driver         = {
+               .name   = "lcc-ipq806x",
+               .owner  = THIS_MODULE,
+               .of_match_table = lcc_ipq806x_match_table,
+       },
+};
+module_platform_driver(lcc_ipq806x_driver);
+
+MODULE_DESCRIPTION("QCOM LCC IPQ806x Driver");
+MODULE_LICENSE("GPL v2");
+MODULE_ALIAS("platform:lcc-ipq806x");
diff --git a/drivers/clk/qcom/lcc-msm8960.c b/drivers/clk/qcom/lcc-msm8960.c
new file mode 100644 (file)
index 0000000..a75a408
--- /dev/null
@@ -0,0 +1,585 @@
+/*
+ * Copyright (c) 2014, The Linux Foundation. All rights reserved.
+ *
+ * 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/kernel.h>
+#include <linux/bitops.h>
+#include <linux/err.h>
+#include <linux/platform_device.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/of_device.h>
+#include <linux/clk-provider.h>
+#include <linux/regmap.h>
+
+#include <dt-bindings/clock/qcom,lcc-msm8960.h>
+
+#include "common.h"
+#include "clk-regmap.h"
+#include "clk-pll.h"
+#include "clk-rcg.h"
+#include "clk-branch.h"
+#include "clk-regmap-divider.h"
+#include "clk-regmap-mux.h"
+
+static struct clk_pll pll4 = {
+       .l_reg = 0x4,
+       .m_reg = 0x8,
+       .n_reg = 0xc,
+       .config_reg = 0x14,
+       .mode_reg = 0x0,
+       .status_reg = 0x18,
+       .status_bit = 16,
+       .clkr.hw.init = &(struct clk_init_data){
+               .name = "pll4",
+               .parent_names = (const char *[]){ "pxo" },
+               .num_parents = 1,
+               .ops = &clk_pll_ops,
+       },
+};
+
+#define P_PXO  0
+#define P_PLL4 1
+
+static const u8 lcc_pxo_pll4_map[] = {
+       [P_PXO]         = 0,
+       [P_PLL4]        = 2,
+};
+
+static const char *lcc_pxo_pll4[] = {
+       "pxo",
+       "pll4_vote",
+};
+
+static struct freq_tbl clk_tbl_aif_osr_492[] = {
+       {   512000, P_PLL4, 4, 1, 240 },
+       {   768000, P_PLL4, 4, 1, 160 },
+       {  1024000, P_PLL4, 4, 1, 120 },
+       {  1536000, P_PLL4, 4, 1,  80 },
+       {  2048000, P_PLL4, 4, 1,  60 },
+       {  3072000, P_PLL4, 4, 1,  40 },
+       {  4096000, P_PLL4, 4, 1,  30 },
+       {  6144000, P_PLL4, 4, 1,  20 },
+       {  8192000, P_PLL4, 4, 1,  15 },
+       { 12288000, P_PLL4, 4, 1,  10 },
+       { 24576000, P_PLL4, 4, 1,   5 },
+       { 27000000, P_PXO,  1, 0,   0 },
+       { }
+};
+
+static struct freq_tbl clk_tbl_aif_osr_393[] = {
+       {   512000, P_PLL4, 4, 1, 192 },
+       {   768000, P_PLL4, 4, 1, 128 },
+       {  1024000, P_PLL4, 4, 1,  96 },
+       {  1536000, P_PLL4, 4, 1,  64 },
+       {  2048000, P_PLL4, 4, 1,  48 },
+       {  3072000, P_PLL4, 4, 1,  32 },
+       {  4096000, P_PLL4, 4, 1,  24 },
+       {  6144000, P_PLL4, 4, 1,  16 },
+       {  8192000, P_PLL4, 4, 1,  12 },
+       { 12288000, P_PLL4, 4, 1,   8 },
+       { 24576000, P_PLL4, 4, 1,   4 },
+       { 27000000, P_PXO,  1, 0,   0 },
+       { }
+};
+
+static struct clk_rcg mi2s_osr_src = {
+       .ns_reg = 0x48,
+       .md_reg = 0x4c,
+       .mn = {
+               .mnctr_en_bit = 8,
+               .mnctr_reset_bit = 7,
+               .mnctr_mode_shift = 5,
+               .n_val_shift = 24,
+               .m_val_shift = 8,
+               .width = 8,
+       },
+       .p = {
+               .pre_div_shift = 3,
+               .pre_div_width = 2,
+       },
+       .s = {
+               .src_sel_shift = 0,
+               .parent_map = lcc_pxo_pll4_map,
+       },
+       .freq_tbl = clk_tbl_aif_osr_393,
+       .clkr = {
+               .enable_reg = 0x48,
+               .enable_mask = BIT(9),
+               .hw.init = &(struct clk_init_data){
+                       .name = "mi2s_osr_src",
+                       .parent_names = lcc_pxo_pll4,
+                       .num_parents = 2,
+                       .ops = &clk_rcg_ops,
+                       .flags = CLK_SET_RATE_GATE,
+               },
+       },
+};
+
+static const char *lcc_mi2s_parents[] = {
+       "mi2s_osr_src",
+};
+
+static struct clk_branch mi2s_osr_clk = {
+       .halt_reg = 0x50,
+       .halt_bit = 1,
+       .halt_check = BRANCH_HALT_ENABLE,
+       .clkr = {
+               .enable_reg = 0x48,
+               .enable_mask = BIT(17),
+               .hw.init = &(struct clk_init_data){
+                       .name = "mi2s_osr_clk",
+                       .parent_names = lcc_mi2s_parents,
+                       .num_parents = 1,
+                       .ops = &clk_branch_ops,
+                       .flags = CLK_SET_RATE_PARENT,
+               },
+       },
+};
+
+static struct clk_regmap_div mi2s_div_clk = {
+       .reg = 0x48,
+       .shift = 10,
+       .width = 4,
+       .clkr = {
+               .enable_reg = 0x48,
+               .enable_mask = BIT(15),
+               .hw.init = &(struct clk_init_data){
+                       .name = "mi2s_div_clk",
+                       .parent_names = lcc_mi2s_parents,
+                       .num_parents = 1,
+                       .ops = &clk_regmap_div_ops,
+               },
+       },
+};
+
+static struct clk_branch mi2s_bit_div_clk = {
+       .halt_reg = 0x50,
+       .halt_bit = 0,
+       .halt_check = BRANCH_HALT_ENABLE,
+       .clkr = {
+               .enable_reg = 0x48,
+               .enable_mask = BIT(15),
+               .hw.init = &(struct clk_init_data){
+                       .name = "mi2s_bit_div_clk",
+                       .parent_names = (const char *[]){ "mi2s_div_clk" },
+                       .num_parents = 1,
+                       .ops = &clk_branch_ops,
+                       .flags = CLK_SET_RATE_PARENT,
+               },
+       },
+};
+
+static struct clk_regmap_mux mi2s_bit_clk = {
+       .reg = 0x48,
+       .shift = 14,
+       .width = 1,
+       .clkr = {
+               .hw.init = &(struct clk_init_data){
+                       .name = "mi2s_bit_clk",
+                       .parent_names = (const char *[]){
+                               "mi2s_bit_div_clk",
+                               "mi2s_codec_clk",
+                       },
+                       .num_parents = 2,
+                       .ops = &clk_regmap_mux_closest_ops,
+                       .flags = CLK_SET_RATE_PARENT,
+               },
+       },
+};
+
+#define CLK_AIF_OSR_DIV(prefix, _ns, _md, hr)                  \
+static struct clk_rcg prefix##_osr_src = {                     \
+       .ns_reg = _ns,                                          \
+       .md_reg = _md,                                          \
+       .mn = {                                                 \
+               .mnctr_en_bit = 8,                              \
+               .mnctr_reset_bit = 7,                           \
+               .mnctr_mode_shift = 5,                          \
+               .n_val_shift = 24,                              \
+               .m_val_shift = 8,                               \
+               .width = 8,                                     \
+       },                                                      \
+       .p = {                                                  \
+               .pre_div_shift = 3,                             \
+               .pre_div_width = 2,                             \
+       },                                                      \
+       .s = {                                                  \
+               .src_sel_shift = 0,                             \
+               .parent_map = lcc_pxo_pll4_map,                 \
+       },                                                      \
+       .freq_tbl = clk_tbl_aif_osr_393,                        \
+       .clkr = {                                               \
+               .enable_reg = _ns,                              \
+               .enable_mask = BIT(9),                          \
+               .hw.init = &(struct clk_init_data){             \
+                       .name = #prefix "_osr_src",             \
+                       .parent_names = lcc_pxo_pll4,           \
+                       .num_parents = 2,                       \
+                       .ops = &clk_rcg_ops,                    \
+                       .flags = CLK_SET_RATE_GATE,             \
+               },                                              \
+       },                                                      \
+};                                                             \
+                                                               \
+static const char *lcc_##prefix##_parents[] = {                        \
+       #prefix "_osr_src",                                     \
+};                                                             \
+                                                               \
+static struct clk_branch prefix##_osr_clk = {                  \
+       .halt_reg = hr,                                         \
+       .halt_bit = 1,                                          \
+       .halt_check = BRANCH_HALT_ENABLE,                       \
+       .clkr = {                                               \
+               .enable_reg = _ns,                              \
+               .enable_mask = BIT(21),                         \
+               .hw.init = &(struct clk_init_data){             \
+                       .name = #prefix "_osr_clk",             \
+                       .parent_names = lcc_##prefix##_parents, \
+                       .num_parents = 1,                       \
+                       .ops = &clk_branch_ops,                 \
+                       .flags = CLK_SET_RATE_PARENT,           \
+               },                                              \
+       },                                                      \
+};                                                             \
+                                                               \
+static struct clk_regmap_div prefix##_div_clk = {              \
+       .reg = _ns,                                             \
+       .shift = 10,                                            \
+       .width = 8,                                             \
+       .clkr = {                                               \
+               .hw.init = &(struct clk_init_data){             \
+                       .name = #prefix "_div_clk",             \
+                       .parent_names = lcc_##prefix##_parents, \
+                       .num_parents = 1,                       \
+                       .ops = &clk_regmap_div_ops,             \
+               },                                              \
+       },                                                      \
+};                                                             \
+                                                               \
+static struct clk_branch prefix##_bit_div_clk = {              \
+       .halt_reg = hr,                                         \
+       .halt_bit = 0,                                          \
+       .halt_check = BRANCH_HALT_ENABLE,                       \
+       .clkr = {                                               \
+               .enable_reg = _ns,                              \
+               .enable_mask = BIT(19),                         \
+               .hw.init = &(struct clk_init_data){             \
+                       .name = #prefix "_bit_div_clk",         \
+                       .parent_names = (const char *[]){       \
+                               #prefix "_div_clk"              \
+                       },                                      \
+                       .num_parents = 1,                       \
+                       .ops = &clk_branch_ops,                 \
+                       .flags = CLK_SET_RATE_PARENT,           \
+               },                                              \
+       },                                                      \
+};                                                             \
+                                                               \
+static struct clk_regmap_mux prefix##_bit_clk = {              \
+       .reg = _ns,                                             \
+       .shift = 18,                                            \
+       .width = 1,                                             \
+       .clkr = {                                               \
+               .hw.init = &(struct clk_init_data){             \
+                       .name = #prefix "_bit_clk",             \
+                       .parent_names = (const char *[]){       \
+                               #prefix "_bit_div_clk",         \
+                               #prefix "_codec_clk",           \
+                       },                                      \
+                       .num_parents = 2,                       \
+                       .ops = &clk_regmap_mux_closest_ops,     \
+                       .flags = CLK_SET_RATE_PARENT,           \
+               },                                              \
+       },                                                      \
+}
+
+CLK_AIF_OSR_DIV(codec_i2s_mic, 0x60, 0x64, 0x68);
+CLK_AIF_OSR_DIV(spare_i2s_mic, 0x78, 0x7c, 0x80);
+CLK_AIF_OSR_DIV(codec_i2s_spkr, 0x6c, 0x70, 0x74);
+CLK_AIF_OSR_DIV(spare_i2s_spkr, 0x84, 0x88, 0x8c);
+
+static struct freq_tbl clk_tbl_pcm_492[] = {
+       {   256000, P_PLL4, 4, 1, 480 },
+       {   512000, P_PLL4, 4, 1, 240 },
+       {   768000, P_PLL4, 4, 1, 160 },
+       {  1024000, P_PLL4, 4, 1, 120 },
+       {  1536000, P_PLL4, 4, 1,  80 },
+       {  2048000, P_PLL4, 4, 1,  60 },
+       {  3072000, P_PLL4, 4, 1,  40 },
+       {  4096000, P_PLL4, 4, 1,  30 },
+       {  6144000, P_PLL4, 4, 1,  20 },
+       {  8192000, P_PLL4, 4, 1,  15 },
+       { 12288000, P_PLL4, 4, 1,  10 },
+       { 24576000, P_PLL4, 4, 1,   5 },
+       { 27000000, P_PXO,  1, 0,   0 },
+       { }
+};
+
+static struct freq_tbl clk_tbl_pcm_393[] = {
+       {   256000, P_PLL4, 4, 1, 384 },
+       {   512000, P_PLL4, 4, 1, 192 },
+       {   768000, P_PLL4, 4, 1, 128 },
+       {  1024000, P_PLL4, 4, 1,  96 },
+       {  1536000, P_PLL4, 4, 1,  64 },
+       {  2048000, P_PLL4, 4, 1,  48 },
+       {  3072000, P_PLL4, 4, 1,  32 },
+       {  4096000, P_PLL4, 4, 1,  24 },
+       {  6144000, P_PLL4, 4, 1,  16 },
+       {  8192000, P_PLL4, 4, 1,  12 },
+       { 12288000, P_PLL4, 4, 1,   8 },
+       { 24576000, P_PLL4, 4, 1,   4 },
+       { 27000000, P_PXO,  1, 0,   0 },
+       { }
+};
+
+static struct clk_rcg pcm_src = {
+       .ns_reg = 0x54,
+       .md_reg = 0x58,
+       .mn = {
+               .mnctr_en_bit = 8,
+               .mnctr_reset_bit = 7,
+               .mnctr_mode_shift = 5,
+               .n_val_shift = 16,
+               .m_val_shift = 16,
+               .width = 16,
+       },
+       .p = {
+               .pre_div_shift = 3,
+               .pre_div_width = 2,
+       },
+       .s = {
+               .src_sel_shift = 0,
+               .parent_map = lcc_pxo_pll4_map,
+       },
+       .freq_tbl = clk_tbl_pcm_393,
+       .clkr = {
+               .enable_reg = 0x54,
+               .enable_mask = BIT(9),
+               .hw.init = &(struct clk_init_data){
+                       .name = "pcm_src",
+                       .parent_names = lcc_pxo_pll4,
+                       .num_parents = 2,
+                       .ops = &clk_rcg_ops,
+                       .flags = CLK_SET_RATE_GATE,
+               },
+       },
+};
+
+static struct clk_branch pcm_clk_out = {
+       .halt_reg = 0x5c,
+       .halt_bit = 0,
+       .halt_check = BRANCH_HALT_ENABLE,
+       .clkr = {
+               .enable_reg = 0x54,
+               .enable_mask = BIT(11),
+               .hw.init = &(struct clk_init_data){
+                       .name = "pcm_clk_out",
+                       .parent_names = (const char *[]){ "pcm_src" },
+                       .num_parents = 1,
+                       .ops = &clk_branch_ops,
+                       .flags = CLK_SET_RATE_PARENT,
+               },
+       },
+};
+
+static struct clk_regmap_mux pcm_clk = {
+       .reg = 0x54,
+       .shift = 10,
+       .width = 1,
+       .clkr = {
+               .hw.init = &(struct clk_init_data){
+                       .name = "pcm_clk",
+                       .parent_names = (const char *[]){
+                               "pcm_clk_out",
+                               "pcm_codec_clk",
+                       },
+                       .num_parents = 2,
+                       .ops = &clk_regmap_mux_closest_ops,
+                       .flags = CLK_SET_RATE_PARENT,
+               },
+       },
+};
+
+static struct clk_rcg slimbus_src = {
+       .ns_reg = 0xcc,
+       .md_reg = 0xd0,
+       .mn = {
+               .mnctr_en_bit = 8,
+               .mnctr_reset_bit = 7,
+               .mnctr_mode_shift = 5,
+               .n_val_shift = 16,
+               .m_val_shift = 16,
+               .width = 8,
+       },
+       .p = {
+               .pre_div_shift = 3,
+               .pre_div_width = 2,
+       },
+       .s = {
+               .src_sel_shift = 0,
+               .parent_map = lcc_pxo_pll4_map,
+       },
+       .freq_tbl = clk_tbl_aif_osr_393,
+       .clkr = {
+               .enable_reg = 0xcc,
+               .enable_mask = BIT(9),
+               .hw.init = &(struct clk_init_data){
+                       .name = "slimbus_src",
+                       .parent_names = lcc_pxo_pll4,
+                       .num_parents = 2,
+                       .ops = &clk_rcg_ops,
+                       .flags = CLK_SET_RATE_GATE,
+               },
+       },
+};
+
+static const char *lcc_slimbus_parents[] = {
+       "slimbus_src",
+};
+
+static struct clk_branch audio_slimbus_clk = {
+       .halt_reg = 0xd4,
+       .halt_bit = 0,
+       .halt_check = BRANCH_HALT_ENABLE,
+       .clkr = {
+               .enable_reg = 0xcc,
+               .enable_mask = BIT(10),
+               .hw.init = &(struct clk_init_data){
+                       .name = "audio_slimbus_clk",
+                       .parent_names = lcc_slimbus_parents,
+                       .num_parents = 1,
+                       .ops = &clk_branch_ops,
+                       .flags = CLK_SET_RATE_PARENT,
+               },
+       },
+};
+
+static struct clk_branch sps_slimbus_clk = {
+       .halt_reg = 0xd4,
+       .halt_bit = 1,
+       .halt_check = BRANCH_HALT_ENABLE,
+       .clkr = {
+               .enable_reg = 0xcc,
+               .enable_mask = BIT(12),
+               .hw.init = &(struct clk_init_data){
+                       .name = "sps_slimbus_clk",
+                       .parent_names = lcc_slimbus_parents,
+                       .num_parents = 1,
+                       .ops = &clk_branch_ops,
+                       .flags = CLK_SET_RATE_PARENT,
+               },
+       },
+};
+
+static struct clk_regmap *lcc_msm8960_clks[] = {
+       [PLL4] = &pll4.clkr,
+       [MI2S_OSR_SRC] = &mi2s_osr_src.clkr,
+       [MI2S_OSR_CLK] = &mi2s_osr_clk.clkr,
+       [MI2S_DIV_CLK] = &mi2s_div_clk.clkr,
+       [MI2S_BIT_DIV_CLK] = &mi2s_bit_div_clk.clkr,
+       [MI2S_BIT_CLK] = &mi2s_bit_clk.clkr,
+       [PCM_SRC] = &pcm_src.clkr,
+       [PCM_CLK_OUT] = &pcm_clk_out.clkr,
+       [PCM_CLK] = &pcm_clk.clkr,
+       [SLIMBUS_SRC] = &slimbus_src.clkr,
+       [AUDIO_SLIMBUS_CLK] = &audio_slimbus_clk.clkr,
+       [SPS_SLIMBUS_CLK] = &sps_slimbus_clk.clkr,
+       [CODEC_I2S_MIC_OSR_SRC] = &codec_i2s_mic_osr_src.clkr,
+       [CODEC_I2S_MIC_OSR_CLK] = &codec_i2s_mic_osr_clk.clkr,
+       [CODEC_I2S_MIC_DIV_CLK] = &codec_i2s_mic_div_clk.clkr,
+       [CODEC_I2S_MIC_BIT_DIV_CLK] = &codec_i2s_mic_bit_div_clk.clkr,
+       [CODEC_I2S_MIC_BIT_CLK] = &codec_i2s_mic_bit_clk.clkr,
+       [SPARE_I2S_MIC_OSR_SRC] = &spare_i2s_mic_osr_src.clkr,
+       [SPARE_I2S_MIC_OSR_CLK] = &spare_i2s_mic_osr_clk.clkr,
+       [SPARE_I2S_MIC_DIV_CLK] = &spare_i2s_mic_div_clk.clkr,
+       [SPARE_I2S_MIC_BIT_DIV_CLK] = &spare_i2s_mic_bit_div_clk.clkr,
+       [SPARE_I2S_MIC_BIT_CLK] = &spare_i2s_mic_bit_clk.clkr,
+       [CODEC_I2S_SPKR_OSR_SRC] = &codec_i2s_spkr_osr_src.clkr,
+       [CODEC_I2S_SPKR_OSR_CLK] = &codec_i2s_spkr_osr_clk.clkr,
+       [CODEC_I2S_SPKR_DIV_CLK] = &codec_i2s_spkr_div_clk.clkr,
+       [CODEC_I2S_SPKR_BIT_DIV_CLK] = &codec_i2s_spkr_bit_div_clk.clkr,
+       [CODEC_I2S_SPKR_BIT_CLK] = &codec_i2s_spkr_bit_clk.clkr,
+       [SPARE_I2S_SPKR_OSR_SRC] = &spare_i2s_spkr_osr_src.clkr,
+       [SPARE_I2S_SPKR_OSR_CLK] = &spare_i2s_spkr_osr_clk.clkr,
+       [SPARE_I2S_SPKR_DIV_CLK] = &spare_i2s_spkr_div_clk.clkr,
+       [SPARE_I2S_SPKR_BIT_DIV_CLK] = &spare_i2s_spkr_bit_div_clk.clkr,
+       [SPARE_I2S_SPKR_BIT_CLK] = &spare_i2s_spkr_bit_clk.clkr,
+};
+
+static const struct regmap_config lcc_msm8960_regmap_config = {
+       .reg_bits       = 32,
+       .reg_stride     = 4,
+       .val_bits       = 32,
+       .max_register   = 0xfc,
+       .fast_io        = true,
+};
+
+static const struct qcom_cc_desc lcc_msm8960_desc = {
+       .config = &lcc_msm8960_regmap_config,
+       .clks = lcc_msm8960_clks,
+       .num_clks = ARRAY_SIZE(lcc_msm8960_clks),
+};
+
+static const struct of_device_id lcc_msm8960_match_table[] = {
+       { .compatible = "qcom,lcc-msm8960" },
+       { .compatible = "qcom,lcc-apq8064" },
+       { }
+};
+MODULE_DEVICE_TABLE(of, lcc_msm8960_match_table);
+
+static int lcc_msm8960_probe(struct platform_device *pdev)
+{
+       u32 val;
+       struct regmap *regmap;
+
+       regmap = qcom_cc_map(pdev, &lcc_msm8960_desc);
+       if (IS_ERR(regmap))
+               return PTR_ERR(regmap);
+
+       /* Use the correct frequency plan depending on speed of PLL4 */
+       val = regmap_read(regmap, 0x4, &val);
+       if (val == 0x12) {
+               slimbus_src.freq_tbl = clk_tbl_aif_osr_492;
+               mi2s_osr_src.freq_tbl = clk_tbl_aif_osr_492;
+               codec_i2s_mic_osr_src.freq_tbl = clk_tbl_aif_osr_492;
+               spare_i2s_mic_osr_src.freq_tbl = clk_tbl_aif_osr_492;
+               codec_i2s_spkr_osr_src.freq_tbl = clk_tbl_aif_osr_492;
+               spare_i2s_spkr_osr_src.freq_tbl = clk_tbl_aif_osr_492;
+               pcm_src.freq_tbl = clk_tbl_pcm_492;
+       }
+       /* Enable PLL4 source on the LPASS Primary PLL Mux */
+       regmap_write(regmap, 0xc4, 0x1);
+
+       return qcom_cc_really_probe(pdev, &lcc_msm8960_desc, regmap);
+}
+
+static int lcc_msm8960_remove(struct platform_device *pdev)
+{
+       qcom_cc_remove(pdev);
+       return 0;
+}
+
+static struct platform_driver lcc_msm8960_driver = {
+       .probe          = lcc_msm8960_probe,
+       .remove         = lcc_msm8960_remove,
+       .driver         = {
+               .name   = "lcc-msm8960",
+               .owner  = THIS_MODULE,
+               .of_match_table = lcc_msm8960_match_table,
+       },
+};
+module_platform_driver(lcc_msm8960_driver);
+
+MODULE_DESCRIPTION("QCOM LCC MSM8960 Driver");
+MODULE_LICENSE("GPL v2");
+MODULE_ALIAS("platform:lcc-msm8960");
index 75c8c45ef72849358e4b7bf2c3bbff7927761ae0..8539c4fd34cc37bd28810b93d6ffb815b0bd48d6 100644 (file)
@@ -124,10 +124,11 @@ static int rockchip_cpuclk_pre_rate_change(struct rockchip_cpuclk *cpuclk,
 {
        const struct rockchip_cpuclk_reg_data *reg_data = cpuclk->reg_data;
        unsigned long alt_prate, alt_div;
+       unsigned long flags;
 
        alt_prate = clk_get_rate(cpuclk->alt_parent);
 
-       spin_lock(cpuclk->lock);
+       spin_lock_irqsave(cpuclk->lock, flags);
 
        /*
         * If the old parent clock speed is less than the clock speed
@@ -164,7 +165,7 @@ static int rockchip_cpuclk_pre_rate_change(struct rockchip_cpuclk *cpuclk,
                        cpuclk->reg_base + reg_data->core_reg);
        }
 
-       spin_unlock(cpuclk->lock);
+       spin_unlock_irqrestore(cpuclk->lock, flags);
        return 0;
 }
 
@@ -173,6 +174,7 @@ static int rockchip_cpuclk_post_rate_change(struct rockchip_cpuclk *cpuclk,
 {
        const struct rockchip_cpuclk_reg_data *reg_data = cpuclk->reg_data;
        const struct rockchip_cpuclk_rate_table *rate;
+       unsigned long flags;
 
        rate = rockchip_get_cpuclk_settings(cpuclk, ndata->new_rate);
        if (!rate) {
@@ -181,7 +183,7 @@ static int rockchip_cpuclk_post_rate_change(struct rockchip_cpuclk *cpuclk,
                return -EINVAL;
        }
 
-       spin_lock(cpuclk->lock);
+       spin_lock_irqsave(cpuclk->lock, flags);
 
        if (ndata->old_rate < ndata->new_rate)
                rockchip_cpuclk_set_dividers(cpuclk, rate);
@@ -201,7 +203,7 @@ static int rockchip_cpuclk_post_rate_change(struct rockchip_cpuclk *cpuclk,
        if (ndata->old_rate > ndata->new_rate)
                rockchip_cpuclk_set_dividers(cpuclk, rate);
 
-       spin_unlock(cpuclk->lock);
+       spin_unlock_irqrestore(cpuclk->lock, flags);
        return 0;
 }
 
index c54078960847c91f6f499ecb8f26924338bb2ab4..7eb684c50d42ce9f0d06ffa4de1ecef4270808b7 100644 (file)
@@ -210,6 +210,17 @@ PNAME(mux_sclk_hsadc_p)            = { "hsadc_src", "hsadc_frac", "ext_hsadc" };
 PNAME(mux_mac_p)               = { "gpll", "dpll" };
 PNAME(mux_sclk_macref_p)       = { "mac_src", "ext_rmii" };
 
+static struct rockchip_pll_clock rk3066_pll_clks[] __initdata = {
+       [apll] = PLL(pll_rk3066, PLL_APLL, "apll", mux_pll_p, 0, RK2928_PLL_CON(0),
+                    RK2928_MODE_CON, 0, 5, 0, rk3188_pll_rates),
+       [dpll] = PLL(pll_rk3066, PLL_DPLL, "dpll", mux_pll_p, 0, RK2928_PLL_CON(4),
+                    RK2928_MODE_CON, 4, 4, 0, NULL),
+       [cpll] = PLL(pll_rk3066, PLL_CPLL, "cpll", mux_pll_p, 0, RK2928_PLL_CON(8),
+                    RK2928_MODE_CON, 8, 6, ROCKCHIP_PLL_SYNC_RATE, rk3188_pll_rates),
+       [gpll] = PLL(pll_rk3066, PLL_GPLL, "gpll", mux_pll_p, 0, RK2928_PLL_CON(12),
+                    RK2928_MODE_CON, 12, 7, ROCKCHIP_PLL_SYNC_RATE, rk3188_pll_rates),
+};
+
 static struct rockchip_pll_clock rk3188_pll_clks[] __initdata = {
        [apll] = PLL(pll_rk3066, PLL_APLL, "apll", mux_pll_p, 0, RK2928_PLL_CON(0),
                     RK2928_MODE_CON, 0, 6, 0, rk3188_pll_rates),
@@ -427,11 +438,11 @@ static struct rockchip_clk_branch common_clk_branches[] __initdata = {
        /* hclk_peri gates */
        GATE(0, "hclk_peri_axi_matrix", "hclk_peri", CLK_IGNORE_UNUSED, RK2928_CLKGATE_CON(4), 0, GFLAGS),
        GATE(0, "hclk_peri_ahb_arbi", "hclk_peri", CLK_IGNORE_UNUSED, RK2928_CLKGATE_CON(4), 6, GFLAGS),
-       GATE(0, "hclk_emem_peri", "hclk_peri", 0, RK2928_CLKGATE_CON(4), 7, GFLAGS),
+       GATE(0, "hclk_emem_peri", "hclk_peri", CLK_IGNORE_UNUSED, RK2928_CLKGATE_CON(4), 7, GFLAGS),
        GATE(HCLK_EMAC, "hclk_emac", "hclk_peri", 0, RK2928_CLKGATE_CON(7), 0, GFLAGS),
        GATE(HCLK_NANDC0, "hclk_nandc0", "hclk_peri", 0, RK2928_CLKGATE_CON(5), 9, GFLAGS),
-       GATE(0, "hclk_usb_peri", "hclk_peri", 0, RK2928_CLKGATE_CON(4), 5, GFLAGS),
-       GATE(HCLK_OTG0, "hclk_usbotg0", "hclk_peri", 0, RK2928_CLKGATE_CON(5), 13, GFLAGS),
+       GATE(0, "hclk_usb_peri", "hclk_peri", CLK_IGNORE_UNUSED, RK2928_CLKGATE_CON(4), 5, GFLAGS),
+       GATE(HCLK_OTG0, "hclk_usbotg0", "hclk_peri", CLK_IGNORE_UNUSED, RK2928_CLKGATE_CON(5), 13, GFLAGS),
        GATE(HCLK_HSADC, "hclk_hsadc", "hclk_peri", 0, RK2928_CLKGATE_CON(7), 5, GFLAGS),
        GATE(HCLK_PIDF, "hclk_pidfilter", "hclk_peri", 0, RK2928_CLKGATE_CON(7), 6, GFLAGS),
        GATE(HCLK_SDMMC, "hclk_sdmmc", "hclk_peri", 0, RK2928_CLKGATE_CON(5), 10, GFLAGS),
@@ -592,7 +603,8 @@ static struct rockchip_clk_branch rk3066a_clk_branches[] __initdata = {
        GATE(0, "hclk_cif1", "hclk_cpu", 0, RK2928_CLKGATE_CON(6), 6, GFLAGS),
        GATE(0, "hclk_hdmi", "hclk_cpu", 0, RK2928_CLKGATE_CON(4), 14, GFLAGS),
 
-       GATE(HCLK_OTG1, "hclk_usbotg1", "hclk_peri", 0, RK2928_CLKGATE_CON(5), 14, GFLAGS),
+       GATE(HCLK_OTG1, "hclk_usbotg1", "hclk_peri", CLK_IGNORE_UNUSED,
+                       RK2928_CLKGATE_CON(5), 14, GFLAGS),
 
        GATE(0, "aclk_cif1", "aclk_vio1", 0, RK2928_CLKGATE_CON(6), 7, GFLAGS),
 
@@ -680,7 +692,8 @@ static struct rockchip_clk_branch rk3188_clk_branches[] __initdata = {
        GATE(0, "hclk_imem0", "hclk_cpu", 0, RK2928_CLKGATE_CON(4), 14, GFLAGS),
        GATE(0, "hclk_imem1", "hclk_cpu", 0, RK2928_CLKGATE_CON(4), 15, GFLAGS),
 
-       GATE(HCLK_OTG1, "hclk_usbotg1", "hclk_peri", 0, RK2928_CLKGATE_CON(7), 3, GFLAGS),
+       GATE(HCLK_OTG1, "hclk_usbotg1", "hclk_peri", CLK_IGNORE_UNUSED,
+                       RK2928_CLKGATE_CON(7), 3, GFLAGS),
        GATE(HCLK_HSIC, "hclk_hsic", "hclk_peri", 0, RK2928_CLKGATE_CON(7), 4, GFLAGS),
 
        GATE(PCLK_TIMER3, "pclk_timer3", "pclk_cpu", 0, RK2928_CLKGATE_CON(7), 9, GFLAGS),
@@ -735,8 +748,8 @@ static void __init rk3188_common_clk_init(struct device_node *np)
 static void __init rk3066a_clk_init(struct device_node *np)
 {
        rk3188_common_clk_init(np);
-       rockchip_clk_register_plls(rk3188_pll_clks,
-                                  ARRAY_SIZE(rk3188_pll_clks),
+       rockchip_clk_register_plls(rk3066_pll_clks,
+                                  ARRAY_SIZE(rk3066_pll_clks),
                                   RK3066_GRF_SOC_STATUS);
        rockchip_clk_register_branches(rk3066a_clk_branches,
                                  ARRAY_SIZE(rk3066a_clk_branches));
index 320b8f0607512c04757e7bb9ec9b10c178b6e602..eeadbb6b52061f83058343ff0439337a683be093 100644 (file)
@@ -145,20 +145,20 @@ struct rockchip_pll_rate_table rk3288_pll_rates[] = {
        }
 
 static struct rockchip_cpuclk_rate_table rk3288_cpuclk_rates[] __initdata = {
-       RK3288_CPUCLK_RATE(1800000000, 2, 4, 2, 4, 4),
-       RK3288_CPUCLK_RATE(1704000000, 2, 4, 2, 4, 4),
-       RK3288_CPUCLK_RATE(1608000000, 2, 4, 2, 4, 4),
-       RK3288_CPUCLK_RATE(1512000000, 2, 4, 2, 4, 4),
-       RK3288_CPUCLK_RATE(1416000000, 2, 4, 2, 4, 4),
-       RK3288_CPUCLK_RATE(1200000000, 2, 4, 2, 4, 4),
-       RK3288_CPUCLK_RATE(1008000000, 2, 4, 2, 4, 4),
-       RK3288_CPUCLK_RATE( 816000000, 2, 4, 2, 4, 4),
-       RK3288_CPUCLK_RATE( 696000000, 2, 4, 2, 4, 4),
-       RK3288_CPUCLK_RATE( 600000000, 2, 4, 2, 4, 4),
-       RK3288_CPUCLK_RATE( 408000000, 2, 4, 2, 4, 4),
-       RK3288_CPUCLK_RATE( 312000000, 2, 4, 2, 4, 4),
-       RK3288_CPUCLK_RATE( 216000000, 2, 4, 2, 4, 4),
-       RK3288_CPUCLK_RATE( 126000000, 2, 4, 2, 4, 4),
+       RK3288_CPUCLK_RATE(1800000000, 1, 3, 1, 3, 3),
+       RK3288_CPUCLK_RATE(1704000000, 1, 3, 1, 3, 3),
+       RK3288_CPUCLK_RATE(1608000000, 1, 3, 1, 3, 3),
+       RK3288_CPUCLK_RATE(1512000000, 1, 3, 1, 3, 3),
+       RK3288_CPUCLK_RATE(1416000000, 1, 3, 1, 3, 3),
+       RK3288_CPUCLK_RATE(1200000000, 1, 3, 1, 3, 3),
+       RK3288_CPUCLK_RATE(1008000000, 1, 3, 1, 3, 3),
+       RK3288_CPUCLK_RATE( 816000000, 1, 3, 1, 3, 3),
+       RK3288_CPUCLK_RATE( 696000000, 1, 3, 1, 3, 3),
+       RK3288_CPUCLK_RATE( 600000000, 1, 3, 1, 3, 3),
+       RK3288_CPUCLK_RATE( 408000000, 1, 3, 1, 3, 3),
+       RK3288_CPUCLK_RATE( 312000000, 1, 3, 1, 3, 3),
+       RK3288_CPUCLK_RATE( 216000000, 1, 3, 1, 3, 3),
+       RK3288_CPUCLK_RATE( 126000000, 1, 3, 1, 3, 3),
 };
 
 static const struct rockchip_cpuclk_reg_data rk3288_cpuclk_data = {
index f2c2ccce49bb1ad00f7502e9d4e4236fc6bcbe54..454b02ae486a86917f31614c2c4b016841deefaa 100644 (file)
@@ -82,6 +82,26 @@ static const struct of_device_id exynos_audss_clk_of_match[] = {
        {},
 };
 
+static void exynos_audss_clk_teardown(void)
+{
+       int i;
+
+       for (i = EXYNOS_MOUT_AUDSS; i < EXYNOS_DOUT_SRP; i++) {
+               if (!IS_ERR(clk_table[i]))
+                       clk_unregister_mux(clk_table[i]);
+       }
+
+       for (; i < EXYNOS_SRP_CLK; i++) {
+               if (!IS_ERR(clk_table[i]))
+                       clk_unregister_divider(clk_table[i]);
+       }
+
+       for (; i < clk_data.clk_num; i++) {
+               if (!IS_ERR(clk_table[i]))
+                       clk_unregister_gate(clk_table[i]);
+       }
+}
+
 /* register exynos_audss clocks */
 static int exynos_audss_clk_probe(struct platform_device *pdev)
 {
@@ -219,10 +239,7 @@ static int exynos_audss_clk_probe(struct platform_device *pdev)
        return 0;
 
 unregister:
-       for (i = 0; i < clk_data.clk_num; i++) {
-               if (!IS_ERR(clk_table[i]))
-                       clk_unregister(clk_table[i]);
-       }
+       exynos_audss_clk_teardown();
 
        if (!IS_ERR(epll))
                clk_disable_unprepare(epll);
@@ -232,18 +249,13 @@ unregister:
 
 static int exynos_audss_clk_remove(struct platform_device *pdev)
 {
-       int i;
-
 #ifdef CONFIG_PM_SLEEP
        unregister_syscore_ops(&exynos_audss_clk_syscore_ops);
 #endif
 
        of_clk_del_provider(pdev->dev.of_node);
 
-       for (i = 0; i < clk_data.clk_num; i++) {
-               if (!IS_ERR(clk_table[i]))
-                       clk_unregister(clk_table[i]);
-       }
+       exynos_audss_clk_teardown();
 
        if (!IS_ERR(epll))
                clk_disable_unprepare(epll);
index ea4483b8d62e8a89ea2ef1c1d37b1e720c5d9f68..03d36e847b78e067d16bdfe1758df10560c4a2b4 100644 (file)
@@ -34,6 +34,7 @@
 #define DIV_TOPC0              0x0600
 #define DIV_TOPC1              0x0604
 #define DIV_TOPC3              0x060C
+#define ENABLE_ACLK_TOPC1      0x0804
 
 static struct samsung_fixed_factor_clock topc_fixed_factor_clks[] __initdata = {
        FFACTOR(0, "ffac_topc_bus0_pll_div2", "mout_bus0_pll_ctrl", 1, 2, 0),
@@ -45,6 +46,7 @@ static struct samsung_fixed_factor_clock topc_fixed_factor_clks[] __initdata = {
 };
 
 /* List of parent clocks for Muxes in CMU_TOPC */
+PNAME(mout_aud_pll_ctrl_p)     = { "fin_pll", "fout_aud_pll" };
 PNAME(mout_bus0_pll_ctrl_p)    = { "fin_pll", "fout_bus0_pll" };
 PNAME(mout_bus1_pll_ctrl_p)    = { "fin_pll", "fout_bus1_pll" };
 PNAME(mout_cc_pll_ctrl_p)      = { "fin_pll", "fout_cc_pll" };
@@ -104,9 +106,11 @@ static struct samsung_mux_clock topc_mux_clks[] __initdata = {
 
        MUX(0, "mout_sclk_bus0_pll_out", mout_sclk_bus0_pll_out_p,
                MUX_SEL_TOPC1, 16, 1),
+       MUX(0, "mout_aud_pll_ctrl", mout_aud_pll_ctrl_p, MUX_SEL_TOPC1, 0, 1),
 
        MUX(0, "mout_aclk_ccore_133", mout_topc_group2, MUX_SEL_TOPC2, 4, 2),
 
+       MUX(0, "mout_aclk_mscl_532", mout_topc_group2, MUX_SEL_TOPC3, 20, 2),
        MUX(0, "mout_aclk_peris_66", mout_topc_group2, MUX_SEL_TOPC3, 24, 2),
 };
 
@@ -114,6 +118,8 @@ static struct samsung_div_clock topc_div_clks[] __initdata = {
        DIV(DOUT_ACLK_CCORE_133, "dout_aclk_ccore_133", "mout_aclk_ccore_133",
                DIV_TOPC0, 4, 4),
 
+       DIV(DOUT_ACLK_MSCL_532, "dout_aclk_mscl_532", "mout_aclk_mscl_532",
+               DIV_TOPC1, 20, 4),
        DIV(DOUT_ACLK_PERIS, "dout_aclk_peris_66", "mout_aclk_peris_66",
                DIV_TOPC1, 24, 4),
 
@@ -125,6 +131,18 @@ static struct samsung_div_clock topc_div_clks[] __initdata = {
                DIV_TOPC3, 12, 3),
        DIV(DOUT_SCLK_MFC_PLL, "dout_sclk_mfc_pll", "mout_mfc_pll_ctrl",
                DIV_TOPC3, 16, 3),
+       DIV(DOUT_SCLK_AUD_PLL, "dout_sclk_aud_pll", "mout_aud_pll_ctrl",
+               DIV_TOPC3, 28, 3),
+};
+
+static struct samsung_pll_rate_table pll1460x_24mhz_tbl[] __initdata = {
+       PLL_36XX_RATE(491520000, 20, 1, 0, 31457),
+       {},
+};
+
+static struct samsung_gate_clock topc_gate_clks[] __initdata = {
+       GATE(ACLK_MSCL_532, "aclk_mscl_532", "dout_aclk_mscl_532",
+               ENABLE_ACLK_TOPC1, 20, 0, 0),
 };
 
 static struct samsung_pll_clock topc_pll_clks[] __initdata = {
@@ -136,8 +154,8 @@ static struct samsung_pll_clock topc_pll_clks[] __initdata = {
                BUS1_DPLL_CON0, NULL),
        PLL(pll_1452x, 0, "fout_mfc_pll", "fin_pll", MFC_PLL_LOCK,
                MFC_PLL_CON0, NULL),
-       PLL(pll_1460x, 0, "fout_aud_pll", "fin_pll", AUD_PLL_LOCK,
-               AUD_PLL_CON0, NULL),
+       PLL(pll_1460x, FOUT_AUD_PLL, "fout_aud_pll", "fin_pll", AUD_PLL_LOCK,
+               AUD_PLL_CON0, pll1460x_24mhz_tbl),
 };
 
 static struct samsung_cmu_info topc_cmu_info __initdata = {
@@ -147,6 +165,8 @@ static struct samsung_cmu_info topc_cmu_info __initdata = {
        .nr_mux_clks            = ARRAY_SIZE(topc_mux_clks),
        .div_clks               = topc_div_clks,
        .nr_div_clks            = ARRAY_SIZE(topc_div_clks),
+       .gate_clks              = topc_gate_clks,
+       .nr_gate_clks           = ARRAY_SIZE(topc_gate_clks),
        .fixed_factor_clks      = topc_fixed_factor_clks,
        .nr_fixed_factor_clks   = ARRAY_SIZE(topc_fixed_factor_clks),
        .nr_clk_ids             = TOPC_NR_CLK,
@@ -166,9 +186,18 @@ CLK_OF_DECLARE(exynos7_clk_topc, "samsung,exynos7-clock-topc",
 #define MUX_SEL_TOP00                  0x0200
 #define MUX_SEL_TOP01                  0x0204
 #define MUX_SEL_TOP03                  0x020C
+#define MUX_SEL_TOP0_PERIC0            0x0230
+#define MUX_SEL_TOP0_PERIC1            0x0234
+#define MUX_SEL_TOP0_PERIC2            0x0238
 #define MUX_SEL_TOP0_PERIC3            0x023C
 #define DIV_TOP03                      0x060C
+#define DIV_TOP0_PERIC0                        0x0630
+#define DIV_TOP0_PERIC1                        0x0634
+#define DIV_TOP0_PERIC2                        0x0638
 #define DIV_TOP0_PERIC3                        0x063C
+#define ENABLE_SCLK_TOP0_PERIC0                0x0A30
+#define ENABLE_SCLK_TOP0_PERIC1                0x0A34
+#define ENABLE_SCLK_TOP0_PERIC2                0x0A38
 #define ENABLE_SCLK_TOP0_PERIC3                0x0A3C
 
 /* List of parent clocks for Muxes in CMU_TOP0 */
@@ -176,6 +205,7 @@ PNAME(mout_bus0_pll_p)      = { "fin_pll", "dout_sclk_bus0_pll" };
 PNAME(mout_bus1_pll_p) = { "fin_pll", "dout_sclk_bus1_pll" };
 PNAME(mout_cc_pll_p)   = { "fin_pll", "dout_sclk_cc_pll" };
 PNAME(mout_mfc_pll_p)  = { "fin_pll", "dout_sclk_mfc_pll" };
+PNAME(mout_aud_pll_p)  = { "fin_pll", "dout_sclk_aud_pll" };
 
 PNAME(mout_top0_half_bus0_pll_p) = {"mout_top0_bus0_pll",
        "ffac_top0_bus0_pll_div2"};
@@ -189,18 +219,34 @@ PNAME(mout_top0_half_mfc_pll_p) = {"mout_top0_mfc_pll",
 PNAME(mout_top0_group1) = {"mout_top0_half_bus0_pll",
        "mout_top0_half_bus1_pll", "mout_top0_half_cc_pll",
        "mout_top0_half_mfc_pll"};
+PNAME(mout_top0_group3) = {"ioclk_audiocdclk0",
+       "ioclk_audiocdclk1", "ioclk_spdif_extclk",
+       "mout_top0_aud_pll", "mout_top0_half_bus0_pll",
+       "mout_top0_half_bus1_pll"};
+PNAME(mout_top0_group4) = {"ioclk_audiocdclk1", "mout_top0_aud_pll",
+       "mout_top0_half_bus0_pll", "mout_top0_half_bus1_pll"};
 
 static unsigned long top0_clk_regs[] __initdata = {
        MUX_SEL_TOP00,
        MUX_SEL_TOP01,
        MUX_SEL_TOP03,
+       MUX_SEL_TOP0_PERIC0,
+       MUX_SEL_TOP0_PERIC1,
+       MUX_SEL_TOP0_PERIC2,
        MUX_SEL_TOP0_PERIC3,
        DIV_TOP03,
+       DIV_TOP0_PERIC0,
+       DIV_TOP0_PERIC1,
+       DIV_TOP0_PERIC2,
        DIV_TOP0_PERIC3,
+       ENABLE_SCLK_TOP0_PERIC0,
+       ENABLE_SCLK_TOP0_PERIC1,
+       ENABLE_SCLK_TOP0_PERIC2,
        ENABLE_SCLK_TOP0_PERIC3,
 };
 
 static struct samsung_mux_clock top0_mux_clks[] __initdata = {
+       MUX(0, "mout_top0_aud_pll", mout_aud_pll_p, MUX_SEL_TOP00, 0, 1),
        MUX(0, "mout_top0_mfc_pll", mout_mfc_pll_p, MUX_SEL_TOP00, 4, 1),
        MUX(0, "mout_top0_cc_pll", mout_cc_pll_p, MUX_SEL_TOP00, 8, 1),
        MUX(0, "mout_top0_bus1_pll", mout_bus1_pll_p, MUX_SEL_TOP00, 12, 1),
@@ -218,10 +264,20 @@ static struct samsung_mux_clock top0_mux_clks[] __initdata = {
        MUX(0, "mout_aclk_peric1_66", mout_top0_group1, MUX_SEL_TOP03, 12, 2),
        MUX(0, "mout_aclk_peric0_66", mout_top0_group1, MUX_SEL_TOP03, 20, 2),
 
+       MUX(0, "mout_sclk_spdif", mout_top0_group3, MUX_SEL_TOP0_PERIC0, 4, 3),
+       MUX(0, "mout_sclk_pcm1", mout_top0_group4, MUX_SEL_TOP0_PERIC0, 8, 2),
+       MUX(0, "mout_sclk_i2s1", mout_top0_group4, MUX_SEL_TOP0_PERIC0, 20, 2),
+
+       MUX(0, "mout_sclk_spi1", mout_top0_group1, MUX_SEL_TOP0_PERIC1, 8, 2),
+       MUX(0, "mout_sclk_spi0", mout_top0_group1, MUX_SEL_TOP0_PERIC1, 20, 2),
+
+       MUX(0, "mout_sclk_spi3", mout_top0_group1, MUX_SEL_TOP0_PERIC2, 8, 2),
+       MUX(0, "mout_sclk_spi2", mout_top0_group1, MUX_SEL_TOP0_PERIC2, 20, 2),
        MUX(0, "mout_sclk_uart3", mout_top0_group1, MUX_SEL_TOP0_PERIC3, 4, 2),
        MUX(0, "mout_sclk_uart2", mout_top0_group1, MUX_SEL_TOP0_PERIC3, 8, 2),
        MUX(0, "mout_sclk_uart1", mout_top0_group1, MUX_SEL_TOP0_PERIC3, 12, 2),
        MUX(0, "mout_sclk_uart0", mout_top0_group1, MUX_SEL_TOP0_PERIC3, 16, 2),
+       MUX(0, "mout_sclk_spi4", mout_top0_group1, MUX_SEL_TOP0_PERIC3, 20, 2),
 };
 
 static struct samsung_div_clock top0_div_clks[] __initdata = {
@@ -230,13 +286,40 @@ static struct samsung_div_clock top0_div_clks[] __initdata = {
        DIV(DOUT_ACLK_PERIC0, "dout_aclk_peric0_66", "mout_aclk_peric0_66",
                DIV_TOP03, 20, 6),
 
+       DIV(0, "dout_sclk_spdif", "mout_sclk_spdif", DIV_TOP0_PERIC0, 4, 4),
+       DIV(0, "dout_sclk_pcm1", "mout_sclk_pcm1", DIV_TOP0_PERIC0, 8, 12),
+       DIV(0, "dout_sclk_i2s1", "mout_sclk_i2s1", DIV_TOP0_PERIC0, 20, 10),
+
+       DIV(0, "dout_sclk_spi1", "mout_sclk_spi1", DIV_TOP0_PERIC1, 8, 12),
+       DIV(0, "dout_sclk_spi0", "mout_sclk_spi0", DIV_TOP0_PERIC1, 20, 12),
+
+       DIV(0, "dout_sclk_spi3", "mout_sclk_spi3", DIV_TOP0_PERIC2, 8, 12),
+       DIV(0, "dout_sclk_spi2", "mout_sclk_spi2", DIV_TOP0_PERIC2, 20, 12),
+
        DIV(0, "dout_sclk_uart3", "mout_sclk_uart3", DIV_TOP0_PERIC3, 4, 4),
        DIV(0, "dout_sclk_uart2", "mout_sclk_uart2", DIV_TOP0_PERIC3, 8, 4),
        DIV(0, "dout_sclk_uart1", "mout_sclk_uart1", DIV_TOP0_PERIC3, 12, 4),
        DIV(0, "dout_sclk_uart0", "mout_sclk_uart0", DIV_TOP0_PERIC3, 16, 4),
+       DIV(0, "dout_sclk_spi4", "mout_sclk_spi4", DIV_TOP0_PERIC3, 20, 12),
 };
 
 static struct samsung_gate_clock top0_gate_clks[] __initdata = {
+       GATE(CLK_SCLK_SPDIF, "sclk_spdif", "dout_sclk_spdif",
+               ENABLE_SCLK_TOP0_PERIC0, 4, CLK_SET_RATE_PARENT, 0),
+       GATE(CLK_SCLK_PCM1, "sclk_pcm1", "dout_sclk_pcm1",
+               ENABLE_SCLK_TOP0_PERIC0, 8, CLK_SET_RATE_PARENT, 0),
+       GATE(CLK_SCLK_I2S1, "sclk_i2s1", "dout_sclk_i2s1",
+               ENABLE_SCLK_TOP0_PERIC0, 20, CLK_SET_RATE_PARENT, 0),
+
+       GATE(CLK_SCLK_SPI1, "sclk_spi1", "dout_sclk_spi1",
+               ENABLE_SCLK_TOP0_PERIC1, 8, CLK_SET_RATE_PARENT, 0),
+       GATE(CLK_SCLK_SPI0, "sclk_spi0", "dout_sclk_spi0",
+               ENABLE_SCLK_TOP0_PERIC1, 20, CLK_SET_RATE_PARENT, 0),
+
+       GATE(CLK_SCLK_SPI3, "sclk_spi3", "dout_sclk_spi3",
+               ENABLE_SCLK_TOP0_PERIC2, 8, CLK_SET_RATE_PARENT, 0),
+       GATE(CLK_SCLK_SPI2, "sclk_spi2", "dout_sclk_spi2",
+               ENABLE_SCLK_TOP0_PERIC2, 20, CLK_SET_RATE_PARENT, 0),
        GATE(CLK_SCLK_UART3, "sclk_uart3", "dout_sclk_uart3",
                ENABLE_SCLK_TOP0_PERIC3, 4, 0, 0),
        GATE(CLK_SCLK_UART2, "sclk_uart2", "dout_sclk_uart2",
@@ -245,6 +328,8 @@ static struct samsung_gate_clock top0_gate_clks[] __initdata = {
                ENABLE_SCLK_TOP0_PERIC3, 12, 0, 0),
        GATE(CLK_SCLK_UART0, "sclk_uart0", "dout_sclk_uart0",
                ENABLE_SCLK_TOP0_PERIC3, 16, 0, 0),
+       GATE(CLK_SCLK_SPI4, "sclk_spi4", "dout_sclk_spi4",
+               ENABLE_SCLK_TOP0_PERIC3, 20, CLK_SET_RATE_PARENT, 0),
 };
 
 static struct samsung_fixed_factor_clock top0_fixed_factor_clks[] __initdata = {
@@ -343,6 +428,8 @@ static struct samsung_mux_clock top1_mux_clks[] __initdata = {
        MUX(0, "mout_aclk_fsys0_200", mout_top1_group1, MUX_SEL_TOP13, 28, 2),
 
        MUX(0, "mout_sclk_mmc2", mout_top1_group1, MUX_SEL_TOP1_FSYS0, 24, 2),
+       MUX(0, "mout_sclk_usbdrd300", mout_top1_group1,
+               MUX_SEL_TOP1_FSYS0, 28, 2),
 
        MUX(0, "mout_sclk_mmc1", mout_top1_group1, MUX_SEL_TOP1_FSYS1, 24, 2),
        MUX(0, "mout_sclk_mmc0", mout_top1_group1, MUX_SEL_TOP1_FSYS1, 28, 2),
@@ -356,6 +443,8 @@ static struct samsung_div_clock top1_div_clks[] __initdata = {
 
        DIV(DOUT_SCLK_MMC2, "dout_sclk_mmc2", "mout_sclk_mmc2",
                DIV_TOP1_FSYS0, 24, 4),
+       DIV(0, "dout_sclk_usbdrd300", "mout_sclk_usbdrd300",
+               DIV_TOP1_FSYS0, 28, 4),
 
        DIV(DOUT_SCLK_MMC1, "dout_sclk_mmc1", "mout_sclk_mmc1",
                DIV_TOP1_FSYS1, 24, 4),
@@ -366,6 +455,8 @@ static struct samsung_div_clock top1_div_clks[] __initdata = {
 static struct samsung_gate_clock top1_gate_clks[] __initdata = {
        GATE(CLK_SCLK_MMC2, "sclk_mmc2", "dout_sclk_mmc2",
                ENABLE_SCLK_TOP1_FSYS0, 24, CLK_SET_RATE_PARENT, 0),
+       GATE(0, "sclk_usbdrd300", "dout_sclk_usbdrd300",
+               ENABLE_SCLK_TOP1_FSYS0, 28, 0, 0),
 
        GATE(CLK_SCLK_MMC1, "sclk_mmc1", "dout_sclk_mmc1",
                ENABLE_SCLK_TOP1_FSYS1, 24, CLK_SET_RATE_PARENT, 0),
@@ -514,6 +605,7 @@ static void __init exynos7_clk_peric0_init(struct device_node *np)
 /* Register Offset definitions for CMU_PERIC1 (0x14C80000) */
 #define MUX_SEL_PERIC10                        0x0200
 #define MUX_SEL_PERIC11                        0x0204
+#define MUX_SEL_PERIC12                        0x0208
 #define ENABLE_PCLK_PERIC1             0x0900
 #define ENABLE_SCLK_PERIC10            0x0A00
 
@@ -525,10 +617,16 @@ PNAME(mout_aclk_peric1_66_p)      = { "fin_pll", "dout_aclk_peric1_66" };
 PNAME(mout_sclk_uart1_p)       = { "fin_pll", "sclk_uart1" };
 PNAME(mout_sclk_uart2_p)       = { "fin_pll", "sclk_uart2" };
 PNAME(mout_sclk_uart3_p)       = { "fin_pll", "sclk_uart3" };
+PNAME(mout_sclk_spi0_p)                = { "fin_pll", "sclk_spi0" };
+PNAME(mout_sclk_spi1_p)                = { "fin_pll", "sclk_spi1" };
+PNAME(mout_sclk_spi2_p)                = { "fin_pll", "sclk_spi2" };
+PNAME(mout_sclk_spi3_p)                = { "fin_pll", "sclk_spi3" };
+PNAME(mout_sclk_spi4_p)                = { "fin_pll", "sclk_spi4" };
 
 static unsigned long peric1_clk_regs[] __initdata = {
        MUX_SEL_PERIC10,
        MUX_SEL_PERIC11,
+       MUX_SEL_PERIC12,
        ENABLE_PCLK_PERIC1,
        ENABLE_SCLK_PERIC10,
 };
@@ -537,6 +635,16 @@ static struct samsung_mux_clock peric1_mux_clks[] __initdata = {
        MUX(0, "mout_aclk_peric1_66_user", mout_aclk_peric1_66_p,
                MUX_SEL_PERIC10, 0, 1),
 
+       MUX_F(0, "mout_sclk_spi0_user", mout_sclk_spi0_p,
+               MUX_SEL_PERIC11, 0, 1, CLK_SET_RATE_PARENT, 0),
+       MUX_F(0, "mout_sclk_spi1_user", mout_sclk_spi1_p,
+               MUX_SEL_PERIC11, 4, 1, CLK_SET_RATE_PARENT, 0),
+       MUX_F(0, "mout_sclk_spi2_user", mout_sclk_spi2_p,
+               MUX_SEL_PERIC11, 8, 1, CLK_SET_RATE_PARENT, 0),
+       MUX_F(0, "mout_sclk_spi3_user", mout_sclk_spi3_p,
+               MUX_SEL_PERIC11, 12, 1, CLK_SET_RATE_PARENT, 0),
+       MUX_F(0, "mout_sclk_spi4_user", mout_sclk_spi4_p,
+               MUX_SEL_PERIC11, 16, 1, CLK_SET_RATE_PARENT, 0),
        MUX(0, "mout_sclk_uart1_user", mout_sclk_uart1_p,
                MUX_SEL_PERIC11, 20, 1),
        MUX(0, "mout_sclk_uart2_user", mout_sclk_uart2_p,
@@ -562,6 +670,22 @@ static struct samsung_gate_clock peric1_gate_clks[] __initdata = {
                ENABLE_PCLK_PERIC1, 10, 0, 0),
        GATE(PCLK_UART3, "pclk_uart3", "mout_aclk_peric1_66_user",
                ENABLE_PCLK_PERIC1, 11, 0, 0),
+       GATE(PCLK_SPI0, "pclk_spi0", "mout_aclk_peric1_66_user",
+               ENABLE_PCLK_PERIC1, 12, 0, 0),
+       GATE(PCLK_SPI1, "pclk_spi1", "mout_aclk_peric1_66_user",
+               ENABLE_PCLK_PERIC1, 13, 0, 0),
+       GATE(PCLK_SPI2, "pclk_spi2", "mout_aclk_peric1_66_user",
+               ENABLE_PCLK_PERIC1, 14, 0, 0),
+       GATE(PCLK_SPI3, "pclk_spi3", "mout_aclk_peric1_66_user",
+               ENABLE_PCLK_PERIC1, 15, 0, 0),
+       GATE(PCLK_SPI4, "pclk_spi4", "mout_aclk_peric1_66_user",
+               ENABLE_PCLK_PERIC1, 16, 0, 0),
+       GATE(PCLK_I2S1, "pclk_i2s1", "mout_aclk_peric1_66_user",
+               ENABLE_PCLK_PERIC1, 17, CLK_SET_RATE_PARENT, 0),
+       GATE(PCLK_PCM1, "pclk_pcm1", "mout_aclk_peric1_66_user",
+               ENABLE_PCLK_PERIC1, 18, 0, 0),
+       GATE(PCLK_SPDIF, "pclk_spdif", "mout_aclk_peric1_66_user",
+               ENABLE_PCLK_PERIC1, 19, 0, 0),
 
        GATE(SCLK_UART1, "sclk_uart1_user", "mout_sclk_uart1_user",
                ENABLE_SCLK_PERIC10, 9, 0, 0),
@@ -569,6 +693,22 @@ static struct samsung_gate_clock peric1_gate_clks[] __initdata = {
                ENABLE_SCLK_PERIC10, 10, 0, 0),
        GATE(SCLK_UART3, "sclk_uart3_user", "mout_sclk_uart3_user",
                ENABLE_SCLK_PERIC10, 11, 0, 0),
+       GATE(SCLK_SPI0, "sclk_spi0_user", "mout_sclk_spi0_user",
+               ENABLE_SCLK_PERIC10, 12, CLK_SET_RATE_PARENT, 0),
+       GATE(SCLK_SPI1, "sclk_spi1_user", "mout_sclk_spi1_user",
+               ENABLE_SCLK_PERIC10, 13, CLK_SET_RATE_PARENT, 0),
+       GATE(SCLK_SPI2, "sclk_spi2_user", "mout_sclk_spi2_user",
+               ENABLE_SCLK_PERIC10, 14, CLK_SET_RATE_PARENT, 0),
+       GATE(SCLK_SPI3, "sclk_spi3_user", "mout_sclk_spi3_user",
+               ENABLE_SCLK_PERIC10, 15, CLK_SET_RATE_PARENT, 0),
+       GATE(SCLK_SPI4, "sclk_spi4_user", "mout_sclk_spi4_user",
+               ENABLE_SCLK_PERIC10, 16, CLK_SET_RATE_PARENT, 0),
+       GATE(SCLK_I2S1, "sclk_i2s1_user", "sclk_i2s1",
+               ENABLE_SCLK_PERIC10, 17, CLK_SET_RATE_PARENT, 0),
+       GATE(SCLK_PCM1, "sclk_pcm1_user", "sclk_pcm1",
+               ENABLE_SCLK_PERIC10, 18, CLK_SET_RATE_PARENT, 0),
+       GATE(SCLK_SPDIF, "sclk_spdif_user", "sclk_spdif",
+               ENABLE_SCLK_PERIC10, 19, CLK_SET_RATE_PARENT, 0),
 };
 
 static struct samsung_cmu_info peric1_cmu_info __initdata = {
@@ -647,7 +787,12 @@ CLK_OF_DECLARE(exynos7_clk_peris, "samsung,exynos7-clock-peris",
 /* Register Offset definitions for CMU_FSYS0 (0x10E90000) */
 #define MUX_SEL_FSYS00                 0x0200
 #define MUX_SEL_FSYS01                 0x0204
+#define MUX_SEL_FSYS02                 0x0208
+#define ENABLE_ACLK_FSYS00             0x0800
 #define ENABLE_ACLK_FSYS01             0x0804
+#define ENABLE_SCLK_FSYS01             0x0A04
+#define ENABLE_SCLK_FSYS02             0x0A08
+#define ENABLE_SCLK_FSYS04             0x0A10
 
 /*
  * List of parent clocks for Muxes in CMU_FSYS0
@@ -655,10 +800,29 @@ CLK_OF_DECLARE(exynos7_clk_peris, "samsung,exynos7-clock-peris",
 PNAME(mout_aclk_fsys0_200_p)   = { "fin_pll", "dout_aclk_fsys0_200" };
 PNAME(mout_sclk_mmc2_p)                = { "fin_pll", "sclk_mmc2" };
 
+PNAME(mout_sclk_usbdrd300_p)   = { "fin_pll", "sclk_usbdrd300" };
+PNAME(mout_phyclk_usbdrd300_udrd30_phyclk_p)   = { "fin_pll",
+                               "phyclk_usbdrd300_udrd30_phyclock" };
+PNAME(mout_phyclk_usbdrd300_udrd30_pipe_pclk_p)        = { "fin_pll",
+                               "phyclk_usbdrd300_udrd30_pipe_pclk" };
+
+/* fixed rate clocks used in the FSYS0 block */
+struct samsung_fixed_rate_clock fixed_rate_clks_fsys0[] __initdata = {
+       FRATE(0, "phyclk_usbdrd300_udrd30_phyclock", NULL,
+               CLK_IS_ROOT, 60000000),
+       FRATE(0, "phyclk_usbdrd300_udrd30_pipe_pclk", NULL,
+               CLK_IS_ROOT, 125000000),
+};
+
 static unsigned long fsys0_clk_regs[] __initdata = {
        MUX_SEL_FSYS00,
        MUX_SEL_FSYS01,
+       MUX_SEL_FSYS02,
+       ENABLE_ACLK_FSYS00,
        ENABLE_ACLK_FSYS01,
+       ENABLE_SCLK_FSYS01,
+       ENABLE_SCLK_FSYS02,
+       ENABLE_SCLK_FSYS04,
 };
 
 static struct samsung_mux_clock fsys0_mux_clks[] __initdata = {
@@ -666,11 +830,49 @@ static struct samsung_mux_clock fsys0_mux_clks[] __initdata = {
                MUX_SEL_FSYS00, 24, 1),
 
        MUX(0, "mout_sclk_mmc2_user", mout_sclk_mmc2_p, MUX_SEL_FSYS01, 24, 1),
+       MUX(0, "mout_sclk_usbdrd300_user", mout_sclk_usbdrd300_p,
+               MUX_SEL_FSYS01, 28, 1),
+
+       MUX(0, "mout_phyclk_usbdrd300_udrd30_pipe_pclk_user",
+               mout_phyclk_usbdrd300_udrd30_pipe_pclk_p,
+               MUX_SEL_FSYS02, 24, 1),
+       MUX(0, "mout_phyclk_usbdrd300_udrd30_phyclk_user",
+               mout_phyclk_usbdrd300_udrd30_phyclk_p,
+               MUX_SEL_FSYS02, 28, 1),
 };
 
 static struct samsung_gate_clock fsys0_gate_clks[] __initdata = {
+       GATE(ACLK_AXIUS_USBDRD30X_FSYS0X, "aclk_axius_usbdrd30x_fsys0x",
+               "mout_aclk_fsys0_200_user",
+               ENABLE_ACLK_FSYS00, 19, 0, 0),
+       GATE(ACLK_PDMA1, "aclk_pdma1", "mout_aclk_fsys0_200_user",
+                       ENABLE_ACLK_FSYS00, 3, 0, 0),
+       GATE(ACLK_PDMA0, "aclk_pdma0", "mout_aclk_fsys0_200_user",
+                       ENABLE_ACLK_FSYS00, 4, 0, 0),
+
+       GATE(ACLK_USBDRD300, "aclk_usbdrd300", "mout_aclk_fsys0_200_user",
+               ENABLE_ACLK_FSYS01, 29, 0, 0),
        GATE(ACLK_MMC2, "aclk_mmc2", "mout_aclk_fsys0_200_user",
                ENABLE_ACLK_FSYS01, 31, 0, 0),
+
+       GATE(SCLK_USBDRD300_SUSPENDCLK, "sclk_usbdrd300_suspendclk",
+               "mout_sclk_usbdrd300_user",
+               ENABLE_SCLK_FSYS01, 4, 0, 0),
+       GATE(SCLK_USBDRD300_REFCLK, "sclk_usbdrd300_refclk", "fin_pll",
+               ENABLE_SCLK_FSYS01, 8, 0, 0),
+
+       GATE(PHYCLK_USBDRD300_UDRD30_PIPE_PCLK_USER,
+               "phyclk_usbdrd300_udrd30_pipe_pclk_user",
+               "mout_phyclk_usbdrd300_udrd30_pipe_pclk_user",
+               ENABLE_SCLK_FSYS02, 24, 0, 0),
+       GATE(PHYCLK_USBDRD300_UDRD30_PHYCLK_USER,
+               "phyclk_usbdrd300_udrd30_phyclk_user",
+               "mout_phyclk_usbdrd300_udrd30_phyclk_user",
+               ENABLE_SCLK_FSYS02, 28, 0, 0),
+
+       GATE(OSCCLK_PHY_CLKOUT_USB30_PHY, "oscclk_phy_clkout_usb30_phy",
+               "fin_pll",
+               ENABLE_SCLK_FSYS04, 28, 0, 0),
 };
 
 static struct samsung_cmu_info fsys0_cmu_info __initdata = {
@@ -741,3 +943,205 @@ static void __init exynos7_clk_fsys1_init(struct device_node *np)
 
 CLK_OF_DECLARE(exynos7_clk_fsys1, "samsung,exynos7-clock-fsys1",
        exynos7_clk_fsys1_init);
+
+#define MUX_SEL_MSCL                   0x0200
+#define DIV_MSCL                       0x0600
+#define ENABLE_ACLK_MSCL               0x0800
+#define ENABLE_PCLK_MSCL               0x0900
+
+/* List of parent clocks for Muxes in CMU_MSCL */
+PNAME(mout_aclk_mscl_532_user_p)       = { "fin_pll", "aclk_mscl_532" };
+
+static unsigned long mscl_clk_regs[] __initdata = {
+       MUX_SEL_MSCL,
+       DIV_MSCL,
+       ENABLE_ACLK_MSCL,
+       ENABLE_PCLK_MSCL,
+};
+
+static struct samsung_mux_clock mscl_mux_clks[] __initdata = {
+       MUX(USERMUX_ACLK_MSCL_532, "usermux_aclk_mscl_532",
+               mout_aclk_mscl_532_user_p, MUX_SEL_MSCL, 0, 1),
+};
+static struct samsung_div_clock mscl_div_clks[] __initdata = {
+       DIV(DOUT_PCLK_MSCL, "dout_pclk_mscl", "usermux_aclk_mscl_532",
+                       DIV_MSCL, 0, 3),
+};
+static struct samsung_gate_clock mscl_gate_clks[] __initdata = {
+
+       GATE(ACLK_MSCL_0, "aclk_mscl_0", "usermux_aclk_mscl_532",
+                       ENABLE_ACLK_MSCL, 31, 0, 0),
+       GATE(ACLK_MSCL_1, "aclk_mscl_1", "usermux_aclk_mscl_532",
+                       ENABLE_ACLK_MSCL, 30, 0, 0),
+       GATE(ACLK_JPEG, "aclk_jpeg", "usermux_aclk_mscl_532",
+                       ENABLE_ACLK_MSCL, 29, 0, 0),
+       GATE(ACLK_G2D, "aclk_g2d", "usermux_aclk_mscl_532",
+                       ENABLE_ACLK_MSCL, 28, 0, 0),
+       GATE(ACLK_LH_ASYNC_SI_MSCL_0, "aclk_lh_async_si_mscl_0",
+                       "usermux_aclk_mscl_532",
+                       ENABLE_ACLK_MSCL, 27, 0, 0),
+       GATE(ACLK_LH_ASYNC_SI_MSCL_1, "aclk_lh_async_si_mscl_1",
+                       "usermux_aclk_mscl_532",
+                       ENABLE_ACLK_MSCL, 26, 0, 0),
+       GATE(ACLK_XIU_MSCLX_0, "aclk_xiu_msclx_0", "usermux_aclk_mscl_532",
+                       ENABLE_ACLK_MSCL, 25, 0, 0),
+       GATE(ACLK_XIU_MSCLX_1, "aclk_xiu_msclx_1", "usermux_aclk_mscl_532",
+                       ENABLE_ACLK_MSCL, 24, 0, 0),
+       GATE(ACLK_AXI2ACEL_BRIDGE, "aclk_axi2acel_bridge",
+                       "usermux_aclk_mscl_532",
+                       ENABLE_ACLK_MSCL, 23, 0, 0),
+       GATE(ACLK_QE_MSCL_0, "aclk_qe_mscl_0", "usermux_aclk_mscl_532",
+                       ENABLE_ACLK_MSCL, 22, 0, 0),
+       GATE(ACLK_QE_MSCL_1, "aclk_qe_mscl_1", "usermux_aclk_mscl_532",
+                       ENABLE_ACLK_MSCL, 21, 0, 0),
+       GATE(ACLK_QE_JPEG, "aclk_qe_jpeg", "usermux_aclk_mscl_532",
+                       ENABLE_ACLK_MSCL, 20, 0, 0),
+       GATE(ACLK_QE_G2D, "aclk_qe_g2d", "usermux_aclk_mscl_532",
+                       ENABLE_ACLK_MSCL, 19, 0, 0),
+       GATE(ACLK_PPMU_MSCL_0, "aclk_ppmu_mscl_0", "usermux_aclk_mscl_532",
+                       ENABLE_ACLK_MSCL, 18, 0, 0),
+       GATE(ACLK_PPMU_MSCL_1, "aclk_ppmu_mscl_1", "usermux_aclk_mscl_532",
+                       ENABLE_ACLK_MSCL, 17, 0, 0),
+       GATE(ACLK_MSCLNP_133, "aclk_msclnp_133", "usermux_aclk_mscl_532",
+                       ENABLE_ACLK_MSCL, 16, 0, 0),
+       GATE(ACLK_AHB2APB_MSCL0P, "aclk_ahb2apb_mscl0p",
+                       "usermux_aclk_mscl_532",
+                       ENABLE_ACLK_MSCL, 15, 0, 0),
+       GATE(ACLK_AHB2APB_MSCL1P, "aclk_ahb2apb_mscl1p",
+                       "usermux_aclk_mscl_532",
+                       ENABLE_ACLK_MSCL, 14, 0, 0),
+
+       GATE(PCLK_MSCL_0, "pclk_mscl_0", "dout_pclk_mscl",
+                       ENABLE_PCLK_MSCL, 31, 0, 0),
+       GATE(PCLK_MSCL_1, "pclk_mscl_1", "dout_pclk_mscl",
+                       ENABLE_PCLK_MSCL, 30, 0, 0),
+       GATE(PCLK_JPEG, "pclk_jpeg", "dout_pclk_mscl",
+                       ENABLE_PCLK_MSCL, 29, 0, 0),
+       GATE(PCLK_G2D, "pclk_g2d", "dout_pclk_mscl",
+                       ENABLE_PCLK_MSCL, 28, 0, 0),
+       GATE(PCLK_QE_MSCL_0, "pclk_qe_mscl_0", "dout_pclk_mscl",
+                       ENABLE_PCLK_MSCL, 27, 0, 0),
+       GATE(PCLK_QE_MSCL_1, "pclk_qe_mscl_1", "dout_pclk_mscl",
+                       ENABLE_PCLK_MSCL, 26, 0, 0),
+       GATE(PCLK_QE_JPEG, "pclk_qe_jpeg", "dout_pclk_mscl",
+                       ENABLE_PCLK_MSCL, 25, 0, 0),
+       GATE(PCLK_QE_G2D, "pclk_qe_g2d", "dout_pclk_mscl",
+                       ENABLE_PCLK_MSCL, 24, 0, 0),
+       GATE(PCLK_PPMU_MSCL_0, "pclk_ppmu_mscl_0", "dout_pclk_mscl",
+                       ENABLE_PCLK_MSCL, 23, 0, 0),
+       GATE(PCLK_PPMU_MSCL_1, "pclk_ppmu_mscl_1", "dout_pclk_mscl",
+                       ENABLE_PCLK_MSCL, 22, 0, 0),
+       GATE(PCLK_AXI2ACEL_BRIDGE, "pclk_axi2acel_bridge", "dout_pclk_mscl",
+                       ENABLE_PCLK_MSCL, 21, 0, 0),
+       GATE(PCLK_PMU_MSCL, "pclk_pmu_mscl", "dout_pclk_mscl",
+                       ENABLE_PCLK_MSCL, 20, 0, 0),
+};
+
+static struct samsung_cmu_info mscl_cmu_info __initdata = {
+       .mux_clks               = mscl_mux_clks,
+       .nr_mux_clks            = ARRAY_SIZE(mscl_mux_clks),
+       .div_clks               = mscl_div_clks,
+       .nr_div_clks            = ARRAY_SIZE(mscl_div_clks),
+       .gate_clks              = mscl_gate_clks,
+       .nr_gate_clks           = ARRAY_SIZE(mscl_gate_clks),
+       .nr_clk_ids             = MSCL_NR_CLK,
+       .clk_regs               = mscl_clk_regs,
+       .nr_clk_regs            = ARRAY_SIZE(mscl_clk_regs),
+};
+
+static void __init exynos7_clk_mscl_init(struct device_node *np)
+{
+       samsung_cmu_register_one(np, &mscl_cmu_info);
+}
+
+CLK_OF_DECLARE(exynos7_clk_mscl, "samsung,exynos7-clock-mscl",
+               exynos7_clk_mscl_init);
+
+/* Register Offset definitions for CMU_AUD (0x114C0000) */
+#define        MUX_SEL_AUD                     0x0200
+#define        DIV_AUD0                        0x0600
+#define        DIV_AUD1                        0x0604
+#define        ENABLE_ACLK_AUD                 0x0800
+#define        ENABLE_PCLK_AUD                 0x0900
+#define        ENABLE_SCLK_AUD                 0x0A00
+
+/*
+ * List of parent clocks for Muxes in CMU_AUD
+ */
+PNAME(mout_aud_pll_user_p) = { "fin_pll", "fout_aud_pll" };
+PNAME(mout_aud_group_p) = { "dout_aud_cdclk", "ioclk_audiocdclk0" };
+
+static unsigned long aud_clk_regs[] __initdata = {
+       MUX_SEL_AUD,
+       DIV_AUD0,
+       DIV_AUD1,
+       ENABLE_ACLK_AUD,
+       ENABLE_PCLK_AUD,
+       ENABLE_SCLK_AUD,
+};
+
+static struct samsung_mux_clock aud_mux_clks[] __initdata = {
+       MUX(0, "mout_sclk_i2s", mout_aud_group_p, MUX_SEL_AUD, 12, 1),
+       MUX(0, "mout_sclk_pcm", mout_aud_group_p, MUX_SEL_AUD, 16, 1),
+       MUX(0, "mout_aud_pll_user", mout_aud_pll_user_p, MUX_SEL_AUD, 20, 1),
+};
+
+static struct samsung_div_clock aud_div_clks[] __initdata = {
+       DIV(0, "dout_aud_ca5", "mout_aud_pll_user", DIV_AUD0, 0, 4),
+       DIV(0, "dout_aclk_aud", "dout_aud_ca5", DIV_AUD0, 4, 4),
+       DIV(0, "dout_aud_pclk_dbg", "dout_aud_ca5", DIV_AUD0, 8, 4),
+
+       DIV(0, "dout_sclk_i2s", "mout_sclk_i2s", DIV_AUD1, 0, 4),
+       DIV(0, "dout_sclk_pcm", "mout_sclk_pcm", DIV_AUD1, 4, 8),
+       DIV(0, "dout_sclk_uart", "dout_aud_cdclk", DIV_AUD1, 12, 4),
+       DIV(0, "dout_sclk_slimbus", "dout_aud_cdclk", DIV_AUD1, 16, 5),
+       DIV(0, "dout_aud_cdclk", "mout_aud_pll_user", DIV_AUD1, 24, 4),
+};
+
+static struct samsung_gate_clock aud_gate_clks[] __initdata = {
+       GATE(SCLK_PCM, "sclk_pcm", "dout_sclk_pcm",
+                       ENABLE_SCLK_AUD, 27, CLK_SET_RATE_PARENT, 0),
+       GATE(SCLK_I2S, "sclk_i2s", "dout_sclk_i2s",
+                       ENABLE_SCLK_AUD, 28, CLK_SET_RATE_PARENT, 0),
+       GATE(0, "sclk_uart", "dout_sclk_uart", ENABLE_SCLK_AUD, 29, 0, 0),
+       GATE(0, "sclk_slimbus", "dout_sclk_slimbus",
+                       ENABLE_SCLK_AUD, 30, 0, 0),
+
+       GATE(0, "pclk_dbg_aud", "dout_aud_pclk_dbg", ENABLE_PCLK_AUD, 19, 0, 0),
+       GATE(0, "pclk_gpio_aud", "dout_aclk_aud", ENABLE_PCLK_AUD, 20, 0, 0),
+       GATE(0, "pclk_wdt1", "dout_aclk_aud", ENABLE_PCLK_AUD, 22, 0, 0),
+       GATE(0, "pclk_wdt0", "dout_aclk_aud", ENABLE_PCLK_AUD, 23, 0, 0),
+       GATE(0, "pclk_slimbus", "dout_aclk_aud", ENABLE_PCLK_AUD, 24, 0, 0),
+       GATE(0, "pclk_uart", "dout_aclk_aud", ENABLE_PCLK_AUD, 25, 0, 0),
+       GATE(PCLK_PCM, "pclk_pcm", "dout_aclk_aud",
+                       ENABLE_PCLK_AUD, 26, CLK_SET_RATE_PARENT, 0),
+       GATE(PCLK_I2S, "pclk_i2s", "dout_aclk_aud",
+                       ENABLE_PCLK_AUD, 27, CLK_SET_RATE_PARENT, 0),
+       GATE(0, "pclk_timer", "dout_aclk_aud", ENABLE_PCLK_AUD, 28, 0, 0),
+       GATE(0, "pclk_smmu_aud", "dout_aclk_aud", ENABLE_PCLK_AUD, 31, 0, 0),
+
+       GATE(0, "aclk_smmu_aud", "dout_aclk_aud", ENABLE_ACLK_AUD, 27, 0, 0),
+       GATE(0, "aclk_acel_lh_async_si_top", "dout_aclk_aud",
+                        ENABLE_ACLK_AUD, 28, 0, 0),
+       GATE(ACLK_ADMA, "aclk_dmac", "dout_aclk_aud", ENABLE_ACLK_AUD, 31, 0, 0),
+};
+
+static struct samsung_cmu_info aud_cmu_info __initdata = {
+       .mux_clks               = aud_mux_clks,
+       .nr_mux_clks            = ARRAY_SIZE(aud_mux_clks),
+       .div_clks               = aud_div_clks,
+       .nr_div_clks            = ARRAY_SIZE(aud_div_clks),
+       .gate_clks              = aud_gate_clks,
+       .nr_gate_clks           = ARRAY_SIZE(aud_gate_clks),
+       .nr_clk_ids             = AUD_NR_CLK,
+       .clk_regs               = aud_clk_regs,
+       .nr_clk_regs            = ARRAY_SIZE(aud_clk_regs),
+};
+
+static void __init exynos7_clk_aud_init(struct device_node *np)
+{
+       samsung_cmu_register_one(np, &aud_cmu_info);
+}
+
+CLK_OF_DECLARE(exynos7_clk_aud, "samsung,exynos7-clock-aud",
+               exynos7_clk_aud_init);
index 960bf22d42ae156bda33c375ccfcbbb42bed8712..bef4e4fa6688d31bca7f2343bdad3ff30a868fde 100644 (file)
@@ -1,9 +1,11 @@
 obj-$(CONFIG_ARCH_EMEV2)               += clk-emev2.o
 obj-$(CONFIG_ARCH_R7S72100)            += clk-rz.o
+obj-$(CONFIG_ARCH_R8A73A4)             += clk-r8a73a4.o
 obj-$(CONFIG_ARCH_R8A7740)             += clk-r8a7740.o
 obj-$(CONFIG_ARCH_R8A7779)             += clk-r8a7779.o
 obj-$(CONFIG_ARCH_R8A7790)             += clk-rcar-gen2.o
 obj-$(CONFIG_ARCH_R8A7791)             += clk-rcar-gen2.o
+obj-$(CONFIG_ARCH_R8A7793)             += clk-rcar-gen2.o
 obj-$(CONFIG_ARCH_R8A7794)             += clk-rcar-gen2.o
 obj-$(CONFIG_ARCH_SHMOBILE_MULTI)      += clk-div6.o
 obj-$(CONFIG_ARCH_SHMOBILE_MULTI)      += clk-mstp.o
index 639241e31e03ec244907761ef430ed95bc53adde..efbaf6c81b7530b89b52967e087f6e4aa689122b 100644 (file)
@@ -54,12 +54,19 @@ static int cpg_div6_clock_enable(struct clk_hw *hw)
 static void cpg_div6_clock_disable(struct clk_hw *hw)
 {
        struct div6_clock *clock = to_div6_clock(hw);
+       u32 val;
 
-       /* DIV6 clocks require the divisor field to be non-zero when stopping
-        * the clock.
+       val = clk_readl(clock->reg);
+       val |= CPG_DIV6_CKSTP;
+       /*
+        * DIV6 clocks require the divisor field to be non-zero when stopping
+        * the clock. However, some clocks (e.g. ZB on sh73a0) fail to be
+        * re-enabled later if the divisor field is changed when stopping the
+        * clock
         */
-       clk_writel(clk_readl(clock->reg) | CPG_DIV6_CKSTP | CPG_DIV6_DIV_MASK,
-                  clock->reg);
+       if (!(val & CPG_DIV6_DIV_MASK))
+               val |= CPG_DIV6_DIV_MASK;
+       clk_writel(val, clock->reg);
 }
 
 static int cpg_div6_clock_is_enabled(struct clk_hw *hw)
diff --git a/drivers/clk/shmobile/clk-r8a73a4.c b/drivers/clk/shmobile/clk-r8a73a4.c
new file mode 100644 (file)
index 0000000..29b9a0b
--- /dev/null
@@ -0,0 +1,241 @@
+/*
+ * r8a73a4 Core CPG Clocks
+ *
+ * Copyright (C) 2014  Ulrich Hecht
+ *
+ * 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 of the License.
+ */
+
+#include <linux/clk-provider.h>
+#include <linux/clkdev.h>
+#include <linux/clk/shmobile.h>
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/of.h>
+#include <linux/of_address.h>
+#include <linux/spinlock.h>
+
+struct r8a73a4_cpg {
+       struct clk_onecell_data data;
+       spinlock_t lock;
+       void __iomem *reg;
+};
+
+#define CPG_CKSCR      0xc0
+#define CPG_FRQCRA     0x00
+#define CPG_FRQCRB     0x04
+#define CPG_FRQCRC     0xe0
+#define CPG_PLL0CR     0xd8
+#define CPG_PLL1CR     0x28
+#define CPG_PLL2CR     0x2c
+#define CPG_PLL2HCR    0xe4
+#define CPG_PLL2SCR    0xf4
+
+#define CLK_ENABLE_ON_INIT BIT(0)
+
+struct div4_clk {
+       const char *name;
+       unsigned int reg;
+       unsigned int shift;
+};
+
+static struct div4_clk div4_clks[] = {
+       { "i",  CPG_FRQCRA, 20 },
+       { "m3", CPG_FRQCRA, 12 },
+       { "b",  CPG_FRQCRA,  8 },
+       { "m1", CPG_FRQCRA,  4 },
+       { "m2", CPG_FRQCRA,  0 },
+       { "zx", CPG_FRQCRB, 12 },
+       { "zs", CPG_FRQCRB,  8 },
+       { "hp", CPG_FRQCRB,  4 },
+       { NULL, 0, 0 },
+};
+
+static const struct clk_div_table div4_div_table[] = {
+       { 0, 2 }, { 1, 3 }, { 2, 4 }, { 3, 6 }, { 4, 8 }, { 5, 12 },
+       { 6, 16 }, { 7, 18 }, { 8, 24 }, { 10, 36 }, { 11, 48 },
+       { 12, 10 }, { 0, 0 }
+};
+
+static struct clk * __init
+r8a73a4_cpg_register_clock(struct device_node *np, struct r8a73a4_cpg *cpg,
+                            const char *name)
+{
+       const struct clk_div_table *table = NULL;
+       const char *parent_name;
+       unsigned int shift, reg;
+       unsigned int mult = 1;
+       unsigned int div = 1;
+
+
+       if (!strcmp(name, "main")) {
+               u32 ckscr = clk_readl(cpg->reg + CPG_CKSCR);
+
+               switch ((ckscr >> 28) & 3) {
+               case 0: /* extal1 */
+                       parent_name = of_clk_get_parent_name(np, 0);
+                       break;
+               case 1: /* extal1 / 2 */
+                       parent_name = of_clk_get_parent_name(np, 0);
+                       div = 2;
+                       break;
+               case 2: /* extal2 */
+                       parent_name = of_clk_get_parent_name(np, 1);
+                       break;
+               case 3: /* extal2 / 2 */
+                       parent_name = of_clk_get_parent_name(np, 1);
+                       div = 2;
+                       break;
+               }
+       } else if (!strcmp(name, "pll0")) {
+               /* PLL0/1 are configurable multiplier clocks. Register them as
+                * fixed factor clocks for now as there's no generic multiplier
+                * clock implementation and we currently have no need to change
+                * the multiplier value.
+                */
+               u32 value = clk_readl(cpg->reg + CPG_PLL0CR);
+
+               parent_name = "main";
+               mult = ((value >> 24) & 0x7f) + 1;
+               if (value & BIT(20))
+                       div = 2;
+       } else if (!strcmp(name, "pll1")) {
+               u32 value = clk_readl(cpg->reg + CPG_PLL1CR);
+
+               parent_name = "main";
+               /* XXX: enable bit? */
+               mult = ((value >> 24) & 0x7f) + 1;
+               if (value & BIT(7))
+                       div = 2;
+       } else if (!strncmp(name, "pll2", 4)) {
+               u32 value, cr;
+
+               switch (name[4]) {
+               case 0:
+                       cr = CPG_PLL2CR;
+                       break;
+               case 's':
+                       cr = CPG_PLL2SCR;
+                       break;
+               case 'h':
+                       cr = CPG_PLL2HCR;
+                       break;
+               default:
+                       return ERR_PTR(-EINVAL);
+               }
+               value = clk_readl(cpg->reg + cr);
+               switch ((value >> 5) & 7) {
+               case 0:
+                       parent_name = "main";
+                       div = 2;
+                       break;
+               case 1:
+                       parent_name = "extal2";
+                       div = 2;
+                       break;
+               case 3:
+                       parent_name = "extal2";
+                       div = 4;
+                       break;
+               case 4:
+                       parent_name = "main";
+                       break;
+               case 5:
+                       parent_name = "extal2";
+                       break;
+               default:
+                       pr_warn("%s: unexpected parent of %s\n", __func__,
+                               name);
+                       return ERR_PTR(-EINVAL);
+               }
+               /* XXX: enable bit? */
+               mult = ((value >> 24) & 0x7f) + 1;
+       } else if (!strcmp(name, "z") || !strcmp(name, "z2")) {
+               u32 shift = 8;
+
+               parent_name = "pll0";
+               if (name[1] == '2') {
+                       div = 2;
+                       shift = 0;
+               }
+               div *= 32;
+               mult = 0x20 - ((clk_readl(cpg->reg + CPG_FRQCRC) >> shift)
+                      & 0x1f);
+       } else {
+               struct div4_clk *c;
+
+               for (c = div4_clks; c->name; c++) {
+                       if (!strcmp(name, c->name))
+                               break;
+               }
+               if (!c->name)
+                       return ERR_PTR(-EINVAL);
+
+               parent_name = "pll1";
+               table = div4_div_table;
+               reg = c->reg;
+               shift = c->shift;
+       }
+
+       if (!table) {
+               return clk_register_fixed_factor(NULL, name, parent_name, 0,
+                                                mult, div);
+       } else {
+               return clk_register_divider_table(NULL, name, parent_name, 0,
+                                                 cpg->reg + reg, shift, 4, 0,
+                                                 table, &cpg->lock);
+       }
+}
+
+static void __init r8a73a4_cpg_clocks_init(struct device_node *np)
+{
+       struct r8a73a4_cpg *cpg;
+       struct clk **clks;
+       unsigned int i;
+       int num_clks;
+
+       num_clks = of_property_count_strings(np, "clock-output-names");
+       if (num_clks < 0) {
+               pr_err("%s: failed to count clocks\n", __func__);
+               return;
+       }
+
+       cpg = kzalloc(sizeof(*cpg), GFP_KERNEL);
+       clks = kcalloc(num_clks, sizeof(*clks), GFP_KERNEL);
+       if (cpg == NULL || clks == NULL) {
+               /* We're leaking memory on purpose, there's no point in cleaning
+                * up as the system won't boot anyway.
+                */
+               return;
+       }
+
+       spin_lock_init(&cpg->lock);
+
+       cpg->data.clks = clks;
+       cpg->data.clk_num = num_clks;
+
+       cpg->reg = of_iomap(np, 0);
+       if (WARN_ON(cpg->reg == NULL))
+               return;
+
+       for (i = 0; i < num_clks; ++i) {
+               const char *name;
+               struct clk *clk;
+
+               of_property_read_string_index(np, "clock-output-names", i,
+                                             &name);
+
+               clk = r8a73a4_cpg_register_clock(np, cpg, name);
+               if (IS_ERR(clk))
+                       pr_err("%s: failed to register %s %s clock (%ld)\n",
+                              __func__, np->name, name, PTR_ERR(clk));
+               else
+                       cpg->data.clks[i] = clk;
+       }
+
+       of_clk_add_provider(np, of_clk_src_onecell_get, &cpg->data);
+}
+CLK_OF_DECLARE(r8a73a4_cpg_clks, "renesas,r8a73a4-cpg-clocks",
+              r8a73a4_cpg_clocks_init);
index e996425d06a920728cd4f32448c19d08efb5a776..acfb6d7dbd6bc049fe39213d675d5a2602e65d9e 100644 (file)
@@ -33,6 +33,8 @@ struct rcar_gen2_cpg {
 #define CPG_FRQCRC                     0x000000e0
 #define CPG_FRQCRC_ZFC_MASK            (0x1f << 8)
 #define CPG_FRQCRC_ZFC_SHIFT           8
+#define CPG_ADSPCKCR                   0x0000025c
+#define CPG_RCANCKCR                   0x00000270
 
 /* -----------------------------------------------------------------------------
  * Z Clock
@@ -161,6 +163,88 @@ static struct clk * __init cpg_z_clk_register(struct rcar_gen2_cpg *cpg)
        return clk;
 }
 
+static struct clk * __init cpg_rcan_clk_register(struct rcar_gen2_cpg *cpg,
+                                                struct device_node *np)
+{
+       const char *parent_name = of_clk_get_parent_name(np, 1);
+       struct clk_fixed_factor *fixed;
+       struct clk_gate *gate;
+       struct clk *clk;
+
+       fixed = kzalloc(sizeof(*fixed), GFP_KERNEL);
+       if (!fixed)
+               return ERR_PTR(-ENOMEM);
+
+       fixed->mult = 1;
+       fixed->div = 6;
+
+       gate = kzalloc(sizeof(*gate), GFP_KERNEL);
+       if (!gate) {
+               kfree(fixed);
+               return ERR_PTR(-ENOMEM);
+       }
+
+       gate->reg = cpg->reg + CPG_RCANCKCR;
+       gate->bit_idx = 8;
+       gate->flags = CLK_GATE_SET_TO_DISABLE;
+       gate->lock = &cpg->lock;
+
+       clk = clk_register_composite(NULL, "rcan", &parent_name, 1, NULL, NULL,
+                                    &fixed->hw, &clk_fixed_factor_ops,
+                                    &gate->hw, &clk_gate_ops, 0);
+       if (IS_ERR(clk)) {
+               kfree(gate);
+               kfree(fixed);
+       }
+
+       return clk;
+}
+
+/* ADSP divisors */
+static const struct clk_div_table cpg_adsp_div_table[] = {
+       {  1,  3 }, {  2,  4 }, {  3,  6 }, {  4,  8 },
+       {  5, 12 }, {  6, 16 }, {  7, 18 }, {  8, 24 },
+       { 10, 36 }, { 11, 48 }, {  0,  0 },
+};
+
+static struct clk * __init cpg_adsp_clk_register(struct rcar_gen2_cpg *cpg)
+{
+       const char *parent_name = "pll1";
+       struct clk_divider *div;
+       struct clk_gate *gate;
+       struct clk *clk;
+
+       div = kzalloc(sizeof(*div), GFP_KERNEL);
+       if (!div)
+               return ERR_PTR(-ENOMEM);
+
+       div->reg = cpg->reg + CPG_ADSPCKCR;
+       div->width = 4;
+       div->table = cpg_adsp_div_table;
+       div->lock = &cpg->lock;
+
+       gate = kzalloc(sizeof(*gate), GFP_KERNEL);
+       if (!gate) {
+               kfree(div);
+               return ERR_PTR(-ENOMEM);
+       }
+
+       gate->reg = cpg->reg + CPG_ADSPCKCR;
+       gate->bit_idx = 8;
+       gate->flags = CLK_GATE_SET_TO_DISABLE;
+       gate->lock = &cpg->lock;
+
+       clk = clk_register_composite(NULL, "adsp", &parent_name, 1, NULL, NULL,
+                                    &div->hw, &clk_divider_ops,
+                                    &gate->hw, &clk_gate_ops, 0);
+       if (IS_ERR(clk)) {
+               kfree(gate);
+               kfree(div);
+       }
+
+       return clk;
+}
+
 /* -----------------------------------------------------------------------------
  * CPG Clock Data
  */
@@ -263,6 +347,10 @@ rcar_gen2_cpg_register_clock(struct device_node *np, struct rcar_gen2_cpg *cpg,
                shift = 0;
        } else if (!strcmp(name, "z")) {
                return cpg_z_clk_register(cpg);
+       } else if (!strcmp(name, "rcan")) {
+               return cpg_rcan_clk_register(cpg, np);
+       } else if (!strcmp(name, "adsp")) {
+               return cpg_adsp_clk_register(cpg);
        } else {
                return ERR_PTR(-EINVAL);
        }
index 2282cef9f2ffb0d834b84be7b2b00c32190bde15..3a484b3cb448616f10578f7e6e2d064a8bf67cbd 100644 (file)
@@ -138,16 +138,27 @@ static int flexgen_set_rate(struct clk_hw *hw, unsigned long rate,
        struct flexgen *flexgen = to_flexgen(hw);
        struct clk_hw *pdiv_hw = &flexgen->pdiv.hw;
        struct clk_hw *fdiv_hw = &flexgen->fdiv.hw;
-       unsigned long primary_div = 0;
+       unsigned long div = 0;
        int ret = 0;
 
        pdiv_hw->clk = hw->clk;
        fdiv_hw->clk = hw->clk;
 
-       primary_div = clk_best_div(parent_rate, rate);
+       div = clk_best_div(parent_rate, rate);
 
-       clk_divider_ops.set_rate(fdiv_hw, parent_rate, parent_rate);
-       ret = clk_divider_ops.set_rate(pdiv_hw, rate, rate * primary_div);
+       /*
+       * pdiv is mainly targeted for low freq results, while fdiv
+       * should be used for div <= 64. The other way round can
+       * lead to 'duty cycle' issues.
+       */
+
+       if (div <= 64) {
+               clk_divider_ops.set_rate(pdiv_hw, parent_rate, parent_rate);
+               ret = clk_divider_ops.set_rate(fdiv_hw, rate, rate * div);
+       } else {
+               clk_divider_ops.set_rate(fdiv_hw, parent_rate, parent_rate);
+               ret = clk_divider_ops.set_rate(pdiv_hw, rate, rate * div);
+       }
 
        return ret;
 }
index ed4d0aaf891639585825344d7460bbfcbc1c81e2..36acc7d0d91cd841366e745841714bcbc09e5388 100644 (file)
@@ -3,6 +3,7 @@ obj-y                                   += clk.o autoidle.o clockdomain.o
 clk-common                             = dpll.o composite.o divider.o gate.o \
                                          fixed-factor.o mux.o apll.o
 obj-$(CONFIG_SOC_AM33XX)               += $(clk-common) clk-33xx.o
+obj-$(CONFIG_SOC_TI81XX)               += $(clk-common) fapll.o clk-816x.o
 obj-$(CONFIG_ARCH_OMAP2)               += $(clk-common) interface.o clk-2xxx.o
 obj-$(CONFIG_ARCH_OMAP3)               += $(clk-common) interface.o clk-3xxx.o
 obj-$(CONFIG_ARCH_OMAP4)               += $(clk-common) clk-44xx.o
index 0d1750a8aea40db16a470c697418d1dbd8b6bb45..383a06e49b09db95e465260369fe307afebb92e2 100644 (file)
@@ -327,7 +327,6 @@ enum {
        OMAP3_SOC_OMAP3430_ES1,
        OMAP3_SOC_OMAP3430_ES2_PLUS,
        OMAP3_SOC_OMAP3630,
-       OMAP3_SOC_TI81XX,
 };
 
 static int __init omap3xxx_dt_clk_init(int soc_type)
@@ -370,7 +369,7 @@ static int __init omap3xxx_dt_clk_init(int soc_type)
                (clk_get_rate(clk_get_sys(NULL, "core_ck")) / 1000000),
                (clk_get_rate(clk_get_sys(NULL, "arm_fck")) / 1000000));
 
-       if (soc_type != OMAP3_SOC_TI81XX && soc_type != OMAP3_SOC_OMAP3430_ES1)
+       if (soc_type != OMAP3_SOC_OMAP3430_ES1)
                omap3_clk_lock_dpll5();
 
        return 0;
@@ -390,8 +389,3 @@ int __init am35xx_dt_clk_init(void)
 {
        return omap3xxx_dt_clk_init(OMAP3_SOC_AM35XX);
 }
-
-int __init ti81xx_dt_clk_init(void)
-{
-       return omap3xxx_dt_clk_init(OMAP3_SOC_TI81XX);
-}
index 02517a8206bda8eda55ef32aac17f8163dc2d064..4f4c87751db521d0ce05dcd82e2a62e81408f9d9 100644 (file)
@@ -12,7 +12,7 @@
 
 #include <linux/kernel.h>
 #include <linux/list.h>
-#include <linux/clk-private.h>
+#include <linux/clk.h>
 #include <linux/clkdev.h>
 #include <linux/clk/ti.h>
 
index 5e183993e3ec56b926fffd252325000d02566d03..14160b2235480f1b2855a5c1f3d16865321ce18a 100644 (file)
@@ -12,7 +12,7 @@
 
 #include <linux/kernel.h>
 #include <linux/list.h>
-#include <linux/clk-private.h>
+#include <linux/clk.h>
 #include <linux/clkdev.h>
 #include <linux/io.h>
 #include <linux/clk/ti.h>
index 62ac8f6e480c61abf1760aeec2ebc980fd716cc3..ee32f4deebf40280be8e4d4e6e454e815c53cd67 100644 (file)
@@ -12,7 +12,7 @@
 
 #include <linux/kernel.h>
 #include <linux/list.h>
-#include <linux/clk-private.h>
+#include <linux/clk.h>
 #include <linux/clkdev.h>
 #include <linux/clk/ti.h>
 
diff --git a/drivers/clk/ti/clk-816x.c b/drivers/clk/ti/clk-816x.c
new file mode 100644 (file)
index 0000000..9451e65
--- /dev/null
@@ -0,0 +1,53 @@
+/*
+ * 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/list.h>
+#include <linux/clk-provider.h>
+#include <linux/clk/ti.h>
+
+static struct ti_dt_clk dm816x_clks[] = {
+       DT_CLK(NULL, "sys_clkin", "sys_clkin_ck"),
+       DT_CLK(NULL, "timer_sys_ck", "sys_clkin_ck"),
+       DT_CLK(NULL, "sys_32k_ck", "sys_32k_ck"),
+       DT_CLK(NULL, "mpu_ck", "mpu_ck"),
+       DT_CLK(NULL, "timer1_fck", "timer1_fck"),
+       DT_CLK(NULL, "timer2_fck", "timer2_fck"),
+       DT_CLK(NULL, "timer3_fck", "timer3_fck"),
+       DT_CLK(NULL, "timer4_fck", "timer4_fck"),
+       DT_CLK(NULL, "timer5_fck", "timer5_fck"),
+       DT_CLK(NULL, "timer6_fck", "timer6_fck"),
+       DT_CLK(NULL, "timer7_fck", "timer7_fck"),
+       DT_CLK(NULL, "sysclk4_ck", "sysclk4_ck"),
+       DT_CLK(NULL, "sysclk5_ck", "sysclk5_ck"),
+       DT_CLK(NULL, "sysclk6_ck", "sysclk6_ck"),
+       DT_CLK(NULL, "sysclk10_ck", "sysclk10_ck"),
+       DT_CLK(NULL, "sysclk18_ck", "sysclk18_ck"),
+       DT_CLK(NULL, "sysclk24_ck", "sysclk24_ck"),
+       DT_CLK("4a100000.ethernet", "sysclk24_ck", "sysclk24_ck"),
+       { .node_name = NULL },
+};
+
+static const char *enable_init_clks[] = {
+       "ddr_pll_clk1",
+       "ddr_pll_clk2",
+       "ddr_pll_clk3",
+};
+
+int __init ti81xx_dt_clk_init(void)
+{
+       ti_dt_clocks_register(dm816x_clks);
+       omap2_clk_disable_autoidle_all();
+       omap2_clk_enable_init_clocks(enable_init_clks,
+                                    ARRAY_SIZE(enable_init_clks));
+
+       return 0;
+}
diff --git a/drivers/clk/ti/fapll.c b/drivers/clk/ti/fapll.c
new file mode 100644 (file)
index 0000000..6ef8963
--- /dev/null
@@ -0,0 +1,410 @@
+/*
+ * 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/clk-provider.h>
+#include <linux/delay.h>
+#include <linux/slab.h>
+#include <linux/err.h>
+#include <linux/of.h>
+#include <linux/of_address.h>
+#include <linux/clk/ti.h>
+#include <asm/div64.h>
+
+/* FAPLL Control Register PLL_CTRL */
+#define FAPLL_MAIN_LOCK                BIT(7)
+#define FAPLL_MAIN_PLLEN       BIT(3)
+#define FAPLL_MAIN_BP          BIT(2)
+#define FAPLL_MAIN_LOC_CTL     BIT(0)
+
+/* FAPLL powerdown register PWD */
+#define FAPLL_PWD_OFFSET       4
+
+#define MAX_FAPLL_OUTPUTS      7
+#define FAPLL_MAX_RETRIES      1000
+
+#define to_fapll(_hw)          container_of(_hw, struct fapll_data, hw)
+#define to_synth(_hw)          container_of(_hw, struct fapll_synth, hw)
+
+/* The bypass bit is inverted on the ddr_pll.. */
+#define fapll_is_ddr_pll(va)   (((u32)(va) & 0xffff) == 0x0440)
+
+/*
+ * The audio_pll_clk1 input is hard wired to the 27MHz bypass clock,
+ * and the audio_pll_clk1 synthesizer is hardwared to 32KiHz output.
+ */
+#define is_ddr_pll_clk1(va)    (((u32)(va) & 0xffff) == 0x044c)
+#define is_audio_pll_clk1(va)  (((u32)(va) & 0xffff) == 0x04a8)
+
+/* Synthesizer divider register */
+#define SYNTH_LDMDIV1          BIT(8)
+
+/* Synthesizer frequency register */
+#define SYNTH_LDFREQ           BIT(31)
+
+struct fapll_data {
+       struct clk_hw hw;
+       void __iomem *base;
+       const char *name;
+       struct clk *clk_ref;
+       struct clk *clk_bypass;
+       struct clk_onecell_data outputs;
+       bool bypass_bit_inverted;
+};
+
+struct fapll_synth {
+       struct clk_hw hw;
+       struct fapll_data *fd;
+       int index;
+       void __iomem *freq;
+       void __iomem *div;
+       const char *name;
+       struct clk *clk_pll;
+};
+
+static bool ti_fapll_clock_is_bypass(struct fapll_data *fd)
+{
+       u32 v = readl_relaxed(fd->base);
+
+       if (fd->bypass_bit_inverted)
+               return !(v & FAPLL_MAIN_BP);
+       else
+               return !!(v & FAPLL_MAIN_BP);
+}
+
+static int ti_fapll_enable(struct clk_hw *hw)
+{
+       struct fapll_data *fd = to_fapll(hw);
+       u32 v = readl_relaxed(fd->base);
+
+       v |= (1 << FAPLL_MAIN_PLLEN);
+       writel_relaxed(v, fd->base);
+
+       return 0;
+}
+
+static void ti_fapll_disable(struct clk_hw *hw)
+{
+       struct fapll_data *fd = to_fapll(hw);
+       u32 v = readl_relaxed(fd->base);
+
+       v &= ~(1 << FAPLL_MAIN_PLLEN);
+       writel_relaxed(v, fd->base);
+}
+
+static int ti_fapll_is_enabled(struct clk_hw *hw)
+{
+       struct fapll_data *fd = to_fapll(hw);
+       u32 v = readl_relaxed(fd->base);
+
+       return v & (1 << FAPLL_MAIN_PLLEN);
+}
+
+static unsigned long ti_fapll_recalc_rate(struct clk_hw *hw,
+                                         unsigned long parent_rate)
+{
+       struct fapll_data *fd = to_fapll(hw);
+       u32 fapll_n, fapll_p, v;
+       long long rate;
+
+       if (ti_fapll_clock_is_bypass(fd))
+               return parent_rate;
+
+       rate = parent_rate;
+
+       /* PLL pre-divider is P and multiplier is N */
+       v = readl_relaxed(fd->base);
+       fapll_p = (v >> 8) & 0xff;
+       if (fapll_p)
+               do_div(rate, fapll_p);
+       fapll_n = v >> 16;
+       if (fapll_n)
+               rate *= fapll_n;
+
+       return rate;
+}
+
+static u8 ti_fapll_get_parent(struct clk_hw *hw)
+{
+       struct fapll_data *fd = to_fapll(hw);
+
+       if (ti_fapll_clock_is_bypass(fd))
+               return 1;
+
+       return 0;
+}
+
+static struct clk_ops ti_fapll_ops = {
+       .enable = ti_fapll_enable,
+       .disable = ti_fapll_disable,
+       .is_enabled = ti_fapll_is_enabled,
+       .recalc_rate = ti_fapll_recalc_rate,
+       .get_parent = ti_fapll_get_parent,
+};
+
+static int ti_fapll_synth_enable(struct clk_hw *hw)
+{
+       struct fapll_synth *synth = to_synth(hw);
+       u32 v = readl_relaxed(synth->fd->base + FAPLL_PWD_OFFSET);
+
+       v &= ~(1 << synth->index);
+       writel_relaxed(v, synth->fd->base + FAPLL_PWD_OFFSET);
+
+       return 0;
+}
+
+static void ti_fapll_synth_disable(struct clk_hw *hw)
+{
+       struct fapll_synth *synth = to_synth(hw);
+       u32 v = readl_relaxed(synth->fd->base + FAPLL_PWD_OFFSET);
+
+       v |= 1 << synth->index;
+       writel_relaxed(v, synth->fd->base + FAPLL_PWD_OFFSET);
+}
+
+static int ti_fapll_synth_is_enabled(struct clk_hw *hw)
+{
+       struct fapll_synth *synth = to_synth(hw);
+       u32 v = readl_relaxed(synth->fd->base + FAPLL_PWD_OFFSET);
+
+       return !(v & (1 << synth->index));
+}
+
+/*
+ * See dm816x TRM chapter 1.10.3 Flying Adder PLL fore more info
+ */
+static unsigned long ti_fapll_synth_recalc_rate(struct clk_hw *hw,
+                                               unsigned long parent_rate)
+{
+       struct fapll_synth *synth = to_synth(hw);
+       u32 synth_div_m;
+       long long rate;
+
+       /* The audio_pll_clk1 is hardwired to produce 32.768KiHz clock */
+       if (!synth->div)
+               return 32768;
+
+       /*
+        * PLL in bypass sets the synths in bypass mode too. The PLL rate
+        * can be also be set to 27MHz, so we can't use parent_rate to
+        * check for bypass mode.
+        */
+       if (ti_fapll_clock_is_bypass(synth->fd))
+               return parent_rate;
+
+       rate = parent_rate;
+
+       /*
+        * Synth frequency integer and fractional divider.
+        * Note that the phase output K is 8, so the result needs
+        * to be multiplied by 8.
+        */
+       if (synth->freq) {
+               u32 v, synth_int_div, synth_frac_div, synth_div_freq;
+
+               v = readl_relaxed(synth->freq);
+               synth_int_div = (v >> 24) & 0xf;
+               synth_frac_div = v & 0xffffff;
+               synth_div_freq = (synth_int_div * 10000000) + synth_frac_div;
+               rate *= 10000000;
+               do_div(rate, synth_div_freq);
+               rate *= 8;
+       }
+
+       /* Synth ost-divider M */
+       synth_div_m = readl_relaxed(synth->div) & 0xff;
+       do_div(rate, synth_div_m);
+
+       return rate;
+}
+
+static struct clk_ops ti_fapll_synt_ops = {
+       .enable = ti_fapll_synth_enable,
+       .disable = ti_fapll_synth_disable,
+       .is_enabled = ti_fapll_synth_is_enabled,
+       .recalc_rate = ti_fapll_synth_recalc_rate,
+};
+
+static struct clk * __init ti_fapll_synth_setup(struct fapll_data *fd,
+                                               void __iomem *freq,
+                                               void __iomem *div,
+                                               int index,
+                                               const char *name,
+                                               const char *parent,
+                                               struct clk *pll_clk)
+{
+       struct clk_init_data *init;
+       struct fapll_synth *synth;
+
+       init = kzalloc(sizeof(*init), GFP_KERNEL);
+       if (!init)
+               return ERR_PTR(-ENOMEM);
+
+       init->ops = &ti_fapll_synt_ops;
+       init->name = name;
+       init->parent_names = &parent;
+       init->num_parents = 1;
+
+       synth = kzalloc(sizeof(*synth), GFP_KERNEL);
+       if (!synth)
+               goto free;
+
+       synth->fd = fd;
+       synth->index = index;
+       synth->freq = freq;
+       synth->div = div;
+       synth->name = name;
+       synth->hw.init = init;
+       synth->clk_pll = pll_clk;
+
+       return clk_register(NULL, &synth->hw);
+
+free:
+       kfree(synth);
+       kfree(init);
+
+       return ERR_PTR(-ENOMEM);
+}
+
+static void __init ti_fapll_setup(struct device_node *node)
+{
+       struct fapll_data *fd;
+       struct clk_init_data *init = NULL;
+       const char *parent_name[2];
+       struct clk *pll_clk;
+       int i;
+
+       fd = kzalloc(sizeof(*fd), GFP_KERNEL);
+       if (!fd)
+               return;
+
+       fd->outputs.clks = kzalloc(sizeof(struct clk *) *
+                                  MAX_FAPLL_OUTPUTS + 1,
+                                  GFP_KERNEL);
+       if (!fd->outputs.clks)
+               goto free;
+
+       init = kzalloc(sizeof(*init), GFP_KERNEL);
+       if (!init)
+               goto free;
+
+       init->ops = &ti_fapll_ops;
+       init->name = node->name;
+
+       init->num_parents = of_clk_get_parent_count(node);
+       if (init->num_parents != 2) {
+               pr_err("%s must have two parents\n", node->name);
+               goto free;
+       }
+
+       parent_name[0] = of_clk_get_parent_name(node, 0);
+       parent_name[1] = of_clk_get_parent_name(node, 1);
+       init->parent_names = parent_name;
+
+       fd->clk_ref = of_clk_get(node, 0);
+       if (IS_ERR(fd->clk_ref)) {
+               pr_err("%s could not get clk_ref\n", node->name);
+               goto free;
+       }
+
+       fd->clk_bypass = of_clk_get(node, 1);
+       if (IS_ERR(fd->clk_bypass)) {
+               pr_err("%s could not get clk_bypass\n", node->name);
+               goto free;
+       }
+
+       fd->base = of_iomap(node, 0);
+       if (!fd->base) {
+               pr_err("%s could not get IO base\n", node->name);
+               goto free;
+       }
+
+       if (fapll_is_ddr_pll(fd->base))
+               fd->bypass_bit_inverted = true;
+
+       fd->name = node->name;
+       fd->hw.init = init;
+
+       /* Register the parent PLL */
+       pll_clk = clk_register(NULL, &fd->hw);
+       if (IS_ERR(pll_clk))
+               goto unmap;
+
+       fd->outputs.clks[0] = pll_clk;
+       fd->outputs.clk_num++;
+
+       /*
+        * Set up the child synthesizers starting at index 1 as the
+        * PLL output is at index 0. We need to check the clock-indices
+        * for numbering in case there are holes in the synth mapping,
+        * and then probe the synth register to see if it has a FREQ
+        * register available.
+        */
+       for (i = 0; i < MAX_FAPLL_OUTPUTS; i++) {
+               const char *output_name;
+               void __iomem *freq, *div;
+               struct clk *synth_clk;
+               int output_instance;
+               u32 v;
+
+               if (of_property_read_string_index(node, "clock-output-names",
+                                                 i, &output_name))
+                       continue;
+
+               if (of_property_read_u32_index(node, "clock-indices", i,
+                                              &output_instance))
+                       output_instance = i;
+
+               freq = fd->base + (output_instance * 8);
+               div = freq + 4;
+
+               /* Check for hardwired audio_pll_clk1 */
+               if (is_audio_pll_clk1(freq)) {
+                       freq = 0;
+                       div = 0;
+               } else {
+                       /* Does the synthesizer have a FREQ register? */
+                       v = readl_relaxed(freq);
+                       if (!v)
+                               freq = 0;
+               }
+               synth_clk = ti_fapll_synth_setup(fd, freq, div, output_instance,
+                                                output_name, node->name,
+                                                pll_clk);
+               if (IS_ERR(synth_clk))
+                       continue;
+
+               fd->outputs.clks[output_instance] = synth_clk;
+               fd->outputs.clk_num++;
+
+               clk_register_clkdev(synth_clk, output_name, NULL);
+       }
+
+       /* Register the child synthesizers as the FAPLL outputs */
+       of_clk_add_provider(node, of_clk_src_onecell_get, &fd->outputs);
+       /* Add clock alias for the outputs */
+
+       kfree(init);
+
+       return;
+
+unmap:
+       iounmap(fd->base);
+free:
+       if (fd->clk_bypass)
+               clk_put(fd->clk_bypass);
+       if (fd->clk_ref)
+               clk_put(fd->clk_ref);
+       kfree(fd->outputs.clks);
+       kfree(fd);
+       kfree(init);
+}
+
+CLK_OF_DECLARE(ti_fapll_clock, "ti,dm816-fapll-clock", ti_fapll_setup);
index bd4769a8448582284b2734b0a77cfa6484306e17..0e950769ed033185cf2ad95587958de586ad1246 100644 (file)
@@ -8,7 +8,6 @@
  */
 
 #include <linux/clk-provider.h>
-#include <linux/clk-private.h>
 #include <linux/slab.h>
 #include <linux/io.h>
 #include <linux/err.h>
index e2d63bc47436d1ee51014a24dc21ebcc1131ca51..bf63c96acb1a2947ce7e274f2869b51ab8e95550 100644 (file)
@@ -8,7 +8,6 @@
  */
 
 #include <linux/clk-provider.h>
-#include <linux/clk-private.h>
 #include <linux/mfd/dbx500-prcmu.h>
 #include <linux/slab.h>
 #include <linux/io.h>
index 72564b701b4a7018643c77de03f58a9092ff5f71..7ea24413cee6855c65daa7954bc4843622402e75 100644 (file)
@@ -26,7 +26,7 @@ config CPU_FREQ_MAPLE
 config PPC_CORENET_CPUFREQ
        tristate "CPU frequency scaling driver for Freescale E500MC SoCs"
        depends on PPC_E500MC && OF && COMMON_CLK
-       select CLK_PPC_CORENET
+       select CLK_QORIQ
        help
          This adds the CPUFreq driver support for Freescale e500mc,
          e5500 and e6500 series SoCs which are capable of changing
diff --git a/include/dt-bindings/clock/alphascale,asm9260.h b/include/dt-bindings/clock/alphascale,asm9260.h
new file mode 100644 (file)
index 0000000..04e8db2
--- /dev/null
@@ -0,0 +1,97 @@
+/*
+ * Copyright 2014 Oleksij Rempel <linux@rempel-privat.de>
+ *
+ * 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.
+ */
+
+#ifndef _DT_BINDINGS_CLK_ASM9260_H
+#define _DT_BINDINGS_CLK_ASM9260_H
+
+/* ahb gate */
+#define CLKID_AHB_ROM          0
+#define CLKID_AHB_RAM          1
+#define CLKID_AHB_GPIO         2
+#define CLKID_AHB_MAC          3
+#define CLKID_AHB_EMI          4
+#define CLKID_AHB_USB0         5
+#define CLKID_AHB_USB1         6
+#define CLKID_AHB_DMA0         7
+#define CLKID_AHB_DMA1         8
+#define CLKID_AHB_UART0                9
+#define CLKID_AHB_UART1                10
+#define CLKID_AHB_UART2                11
+#define CLKID_AHB_UART3                12
+#define CLKID_AHB_UART4                13
+#define CLKID_AHB_UART5                14
+#define CLKID_AHB_UART6                15
+#define CLKID_AHB_UART7                16
+#define CLKID_AHB_UART8                17
+#define CLKID_AHB_UART9                18
+#define CLKID_AHB_I2S0         19
+#define CLKID_AHB_I2C0         20
+#define CLKID_AHB_I2C1         21
+#define CLKID_AHB_SSP0         22
+#define CLKID_AHB_IOCONFIG     23
+#define CLKID_AHB_WDT          24
+#define CLKID_AHB_CAN0         25
+#define CLKID_AHB_CAN1         26
+#define CLKID_AHB_MPWM         27
+#define CLKID_AHB_SPI0         28
+#define CLKID_AHB_SPI1         29
+#define CLKID_AHB_QEI          30
+#define CLKID_AHB_QUADSPI0     31
+#define CLKID_AHB_CAMIF                32
+#define CLKID_AHB_LCDIF                33
+#define CLKID_AHB_TIMER0       34
+#define CLKID_AHB_TIMER1       35
+#define CLKID_AHB_TIMER2       36
+#define CLKID_AHB_TIMER3       37
+#define CLKID_AHB_IRQ          38
+#define CLKID_AHB_RTC          39
+#define CLKID_AHB_NAND         40
+#define CLKID_AHB_ADC0         41
+#define CLKID_AHB_LED          42
+#define CLKID_AHB_DAC0         43
+#define CLKID_AHB_LCD          44
+#define CLKID_AHB_I2S1         45
+#define CLKID_AHB_MAC1         46
+
+/* devider */
+#define CLKID_SYS_CPU          47
+#define CLKID_SYS_AHB          48
+#define CLKID_SYS_I2S0M                49
+#define CLKID_SYS_I2S0S                50
+#define CLKID_SYS_I2S1M                51
+#define CLKID_SYS_I2S1S                52
+#define CLKID_SYS_UART0                53
+#define CLKID_SYS_UART1                54
+#define CLKID_SYS_UART2                55
+#define CLKID_SYS_UART3                56
+#define CLKID_SYS_UART4                56
+#define CLKID_SYS_UART5                57
+#define CLKID_SYS_UART6                58
+#define CLKID_SYS_UART7                59
+#define CLKID_SYS_UART8                60
+#define CLKID_SYS_UART9                61
+#define CLKID_SYS_SPI0         62
+#define CLKID_SYS_SPI1         63
+#define CLKID_SYS_QUADSPI      64
+#define CLKID_SYS_SSP0         65
+#define CLKID_SYS_NAND         66
+#define CLKID_SYS_TRACE                67
+#define CLKID_SYS_CAMM         68
+#define CLKID_SYS_WDT          69
+#define CLKID_SYS_CLKOUT       70
+#define CLKID_SYS_MAC          71
+#define CLKID_SYS_LCD          72
+#define CLKID_SYS_ADCANA       73
+
+#define MAX_CLKS               74
+#endif
index 8e4681b07ae79fcaaf6b9e563ac360da6ac198d0..e33c75a3c09dc7caf26575a7e3469788aa6cc234 100644 (file)
 #define DOUT_SCLK_CC_PLL               4
 #define DOUT_SCLK_MFC_PLL              5
 #define DOUT_ACLK_CCORE_133            6
-#define TOPC_NR_CLK                    7
+#define DOUT_ACLK_MSCL_532             7
+#define ACLK_MSCL_532                  8
+#define DOUT_SCLK_AUD_PLL              9
+#define FOUT_AUD_PLL                   10
+#define TOPC_NR_CLK                    11
 
 /* TOP0 */
 #define DOUT_ACLK_PERIC1               1
 #define CLK_SCLK_UART1                 4
 #define CLK_SCLK_UART2                 5
 #define CLK_SCLK_UART3                 6
-#define TOP0_NR_CLK                    7
+#define CLK_SCLK_SPI0                  7
+#define CLK_SCLK_SPI1                  8
+#define CLK_SCLK_SPI2                  9
+#define CLK_SCLK_SPI3                  10
+#define CLK_SCLK_SPI4                  11
+#define CLK_SCLK_SPDIF                 12
+#define CLK_SCLK_PCM1                  13
+#define CLK_SCLK_I2S1                  14
+#define TOP0_NR_CLK                    15
 
 /* TOP1 */
 #define DOUT_ACLK_FSYS1_200            1
 #define PCLK_HSI2C6                    9
 #define PCLK_HSI2C7                    10
 #define PCLK_HSI2C8                    11
-#define PERIC1_NR_CLK                  12
+#define PCLK_SPI0                      12
+#define PCLK_SPI1                      13
+#define PCLK_SPI2                      14
+#define PCLK_SPI3                      15
+#define PCLK_SPI4                      16
+#define SCLK_SPI0                      17
+#define SCLK_SPI1                      18
+#define SCLK_SPI2                      19
+#define SCLK_SPI3                      20
+#define SCLK_SPI4                      21
+#define PCLK_I2S1                      22
+#define PCLK_PCM1                      23
+#define PCLK_SPDIF                     24
+#define SCLK_I2S1                      25
+#define SCLK_PCM1                      26
+#define SCLK_SPDIF                     27
+#define PERIC1_NR_CLK                  28
 
 /* PERIS */
 #define PCLK_CHIPID                    1
 
 /* FSYS0 */
 #define ACLK_MMC2                      1
-#define FSYS0_NR_CLK                   2
+#define ACLK_AXIUS_USBDRD30X_FSYS0X    2
+#define ACLK_USBDRD300                 3
+#define SCLK_USBDRD300_SUSPENDCLK      4
+#define SCLK_USBDRD300_REFCLK          5
+#define PHYCLK_USBDRD300_UDRD30_PIPE_PCLK_USER         6
+#define PHYCLK_USBDRD300_UDRD30_PHYCLK_USER            7
+#define OSCCLK_PHY_CLKOUT_USB30_PHY            8
+#define ACLK_PDMA0                     9
+#define ACLK_PDMA1                     10
+#define FSYS0_NR_CLK                   11
 
 /* FSYS1 */
 #define ACLK_MMC1                      1
 #define ACLK_MMC0                      2
 #define FSYS1_NR_CLK                   3
 
+/* MSCL */
+#define USERMUX_ACLK_MSCL_532          1
+#define DOUT_PCLK_MSCL                 2
+#define ACLK_MSCL_0                    3
+#define ACLK_MSCL_1                    4
+#define ACLK_JPEG                      5
+#define ACLK_G2D                       6
+#define ACLK_LH_ASYNC_SI_MSCL_0                7
+#define ACLK_LH_ASYNC_SI_MSCL_1                8
+#define ACLK_AXI2ACEL_BRIDGE           9
+#define ACLK_XIU_MSCLX_0               10
+#define ACLK_XIU_MSCLX_1               11
+#define ACLK_QE_MSCL_0                 12
+#define ACLK_QE_MSCL_1                 13
+#define ACLK_QE_JPEG                   14
+#define ACLK_QE_G2D                    15
+#define ACLK_PPMU_MSCL_0               16
+#define ACLK_PPMU_MSCL_1               17
+#define ACLK_MSCLNP_133                        18
+#define ACLK_AHB2APB_MSCL0P            19
+#define ACLK_AHB2APB_MSCL1P            20
+
+#define PCLK_MSCL_0                    21
+#define PCLK_MSCL_1                    22
+#define PCLK_JPEG                      23
+#define PCLK_G2D                       24
+#define PCLK_QE_MSCL_0                 25
+#define PCLK_QE_MSCL_1                 26
+#define PCLK_QE_JPEG                   27
+#define PCLK_QE_G2D                    28
+#define PCLK_PPMU_MSCL_0               29
+#define PCLK_PPMU_MSCL_1               30
+#define PCLK_AXI2ACEL_BRIDGE           31
+#define PCLK_PMU_MSCL                  32
+#define MSCL_NR_CLK                    33
+
+/* AUD */
+#define SCLK_I2S                       1
+#define SCLK_PCM                       2
+#define PCLK_I2S                       3
+#define PCLK_PCM                       4
+#define ACLK_ADMA                      5
+#define AUD_NR_CLK                     6
 #endif /* _DT_BINDINGS_CLOCK_EXYNOS7_H */
index b857cadb0bd40ef8c2843693b6fa8c9f7bb11528..04fb29ae30e69801f37713f1284d165396f8525a 100644 (file)
 #define PLL0_VOTE                              221
 #define PLL3                                   222
 #define PLL3_VOTE                              223
-#define PLL4                                   224
 #define PLL4_VOTE                              225
 #define PLL8                                   226
 #define PLL8_VOTE                              227
diff --git a/include/dt-bindings/clock/qcom,lcc-ipq806x.h b/include/dt-bindings/clock/qcom,lcc-ipq806x.h
new file mode 100644 (file)
index 0000000..4e944b8
--- /dev/null
@@ -0,0 +1,30 @@
+/*
+ * Copyright (c) 2014, The Linux Foundation. All rights reserved.
+ *
+ * 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.
+ */
+
+#ifndef _DT_BINDINGS_CLK_LCC_IPQ806X_H
+#define _DT_BINDINGS_CLK_LCC_IPQ806X_H
+
+#define PLL4                           0
+#define MI2S_OSR_SRC                   1
+#define MI2S_OSR_CLK                   2
+#define MI2S_DIV_CLK                   3
+#define MI2S_BIT_DIV_CLK               4
+#define MI2S_BIT_CLK                   5
+#define PCM_SRC                                6
+#define PCM_CLK_OUT                    7
+#define PCM_CLK                                8
+#define SPDIF_SRC                      9
+#define SPDIF_CLK                      10
+#define AHBIX_CLK                      11
+
+#endif
diff --git a/include/dt-bindings/clock/qcom,lcc-msm8960.h b/include/dt-bindings/clock/qcom,lcc-msm8960.h
new file mode 100644 (file)
index 0000000..4fb2aa6
--- /dev/null
@@ -0,0 +1,50 @@
+/*
+ * Copyright (c) 2014, The Linux Foundation. All rights reserved.
+ *
+ * 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.
+ */
+
+#ifndef _DT_BINDINGS_CLK_LCC_MSM8960_H
+#define _DT_BINDINGS_CLK_LCC_MSM8960_H
+
+#define PLL4                           0
+#define MI2S_OSR_SRC                   1
+#define MI2S_OSR_CLK                   2
+#define MI2S_DIV_CLK                   3
+#define MI2S_BIT_DIV_CLK               4
+#define MI2S_BIT_CLK                   5
+#define PCM_SRC                                6
+#define PCM_CLK_OUT                    7
+#define PCM_CLK                                8
+#define SLIMBUS_SRC                    9
+#define AUDIO_SLIMBUS_CLK              10
+#define SPS_SLIMBUS_CLK                        11
+#define CODEC_I2S_MIC_OSR_SRC          12
+#define CODEC_I2S_MIC_OSR_CLK          13
+#define CODEC_I2S_MIC_DIV_CLK          14
+#define CODEC_I2S_MIC_BIT_DIV_CLK      15
+#define CODEC_I2S_MIC_BIT_CLK          16
+#define SPARE_I2S_MIC_OSR_SRC          17
+#define SPARE_I2S_MIC_OSR_CLK          18
+#define SPARE_I2S_MIC_DIV_CLK          19
+#define SPARE_I2S_MIC_BIT_DIV_CLK      20
+#define SPARE_I2S_MIC_BIT_CLK          21
+#define CODEC_I2S_SPKR_OSR_SRC         22
+#define CODEC_I2S_SPKR_OSR_CLK         23
+#define CODEC_I2S_SPKR_DIV_CLK         24
+#define CODEC_I2S_SPKR_BIT_DIV_CLK     25
+#define CODEC_I2S_SPKR_BIT_CLK         26
+#define SPARE_I2S_SPKR_OSR_SRC         27
+#define SPARE_I2S_SPKR_OSR_CLK         28
+#define SPARE_I2S_SPKR_DIV_CLK         29
+#define SPARE_I2S_SPKR_BIT_DIV_CLK     30
+#define SPARE_I2S_SPKR_BIT_CLK         31
+
+#endif
index d936409520f8db609994f7ddab629a99981883dc..0ed5bf2209adf8122f05ceb9ef4ed8b099a07a9e 100644 (file)
@@ -294,6 +294,7 @@ struct clk *clk_register_gate(struct device *dev, const char *name,
                const char *parent_name, unsigned long flags,
                void __iomem *reg, u8 bit_idx,
                u8 clk_gate_flags, spinlock_t *lock);
+void clk_unregister_gate(struct clk *clk);
 
 struct clk_div_table {
        unsigned int    val;
@@ -352,6 +353,17 @@ struct clk_divider {
 #define CLK_DIVIDER_READ_ONLY          BIT(5)
 
 extern const struct clk_ops clk_divider_ops;
+
+unsigned long divider_recalc_rate(struct clk_hw *hw, unsigned long parent_rate,
+               unsigned int val, const struct clk_div_table *table,
+               unsigned long flags);
+long divider_round_rate(struct clk_hw *hw, unsigned long rate,
+               unsigned long *prate, const struct clk_div_table *table,
+               u8 width, unsigned long flags);
+int divider_get_val(unsigned long rate, unsigned long parent_rate,
+               const struct clk_div_table *table, u8 width,
+               unsigned long flags);
+
 struct clk *clk_register_divider(struct device *dev, const char *name,
                const char *parent_name, unsigned long flags,
                void __iomem *reg, u8 shift, u8 width,
@@ -361,6 +373,7 @@ struct clk *clk_register_divider_table(struct device *dev, const char *name,
                void __iomem *reg, u8 shift, u8 width,
                u8 clk_divider_flags, const struct clk_div_table *table,
                spinlock_t *lock);
+void clk_unregister_divider(struct clk *clk);
 
 /**
  * struct clk_mux - multiplexer clock
@@ -382,6 +395,8 @@ struct clk *clk_register_divider_table(struct device *dev, const char *name,
  *     register, and mask of mux bits are in higher 16-bit of this register.
  *     While setting the mux bits, higher 16-bit should also be updated to
  *     indicate changing mux bits.
+ * CLK_MUX_ROUND_CLOSEST - Use the parent rate that is closest to the desired
+ *     frequency.
  */
 struct clk_mux {
        struct clk_hw   hw;
@@ -396,7 +411,8 @@ struct clk_mux {
 #define CLK_MUX_INDEX_ONE              BIT(0)
 #define CLK_MUX_INDEX_BIT              BIT(1)
 #define CLK_MUX_HIWORD_MASK            BIT(2)
-#define CLK_MUX_READ_ONLY      BIT(3) /* mux setting cannot be changed */
+#define CLK_MUX_READ_ONLY              BIT(3) /* mux can't be changed */
+#define CLK_MUX_ROUND_CLOSEST          BIT(4)
 
 extern const struct clk_ops clk_mux_ops;
 extern const struct clk_ops clk_mux_ro_ops;
@@ -411,6 +427,8 @@ struct clk *clk_register_mux_table(struct device *dev, const char *name,
                void __iomem *reg, u8 shift, u32 mask,
                u8 clk_mux_flags, u32 *table, spinlock_t *lock);
 
+void clk_unregister_mux(struct clk *clk);
+
 void of_fixed_factor_clk_setup(struct device_node *node);
 
 /**
@@ -552,6 +570,9 @@ struct clk *__clk_lookup(const char *name);
 long __clk_mux_determine_rate(struct clk_hw *hw, unsigned long rate,
                              unsigned long *best_parent_rate,
                              struct clk_hw **best_parent_p);
+long __clk_mux_determine_rate_closest(struct clk_hw *hw, unsigned long rate,
+                             unsigned long *best_parent_rate,
+                             struct clk_hw **best_parent_p);
 
 /*
  * FIXME clock api without lock protection
index c7f258a81761d22b1b204654d3582af55044915a..ba7e9eda434721f6d39dcce14229fd903e364c1b 100644 (file)
@@ -301,6 +301,18 @@ long clk_round_rate(struct clk *clk, unsigned long rate);
  */
 int clk_set_rate(struct clk *clk, unsigned long rate);
 
+/**
+ * clk_has_parent - check if a clock is a possible parent for another
+ * @clk: clock source
+ * @parent: parent clock source
+ *
+ * This function can be used in drivers that need to check that a clock can be
+ * the parent of another without actually changing the parent.
+ *
+ * Returns true if @parent is a possible parent for @clk, false otherwise.
+ */
+bool clk_has_parent(struct clk *clk, struct clk *parent);
+
 /**
  * clk_set_parent - set the parent clock source for this clock
  * @clk: clock source
@@ -374,6 +386,11 @@ static inline long clk_round_rate(struct clk *clk, unsigned long rate)
        return 0;
 }
 
+static inline bool clk_has_parent(struct clk *clk, struct clk *parent)
+{
+       return true;
+}
+
 static inline int clk_set_parent(struct clk *clk, struct clk *parent)
 {
        return 0;
index 55ef529a0dbf905995781bd051bf926396b837c5..172d13fd8bea87ce6b06c83fc7c0d6019661a0b4 100644 (file)
@@ -15,6 +15,7 @@
 #ifndef __LINUX_CLK_TI_H__
 #define __LINUX_CLK_TI_H__
 
+#include <linux/clk-provider.h>
 #include <linux/clkdev.h>
 
 /**