Merge branch 'clk-meson-gxbb' into clk-next
authorStephen Boyd <sboyd@codeaurora.org>
Mon, 15 Aug 2016 22:47:15 +0000 (15:47 -0700)
committerStephen Boyd <sboyd@codeaurora.org>
Mon, 15 Aug 2016 22:47:15 +0000 (15:47 -0700)
* clk-meson-gxbb:
  clk: gxbb: add MMC gate clocks, and expose for DT

34 files changed:
Documentation/devicetree/bindings/clock/armada3700-periph-clock.txt [new file with mode: 0644]
Documentation/devicetree/bindings/clock/armada3700-tbg-clock.txt [new file with mode: 0644]
Documentation/devicetree/bindings/clock/armada3700-xtal-clock.txt [new file with mode: 0644]
Documentation/devicetree/bindings/clock/maxim,max77686.txt
Documentation/devicetree/bindings/clock/maxim,max77802.txt [deleted file]
Documentation/devicetree/bindings/clock/mvebu-gated-clock.txt
MAINTAINERS
drivers/clk/Kconfig
drivers/clk/Makefile
drivers/clk/axis/clk-artpec6.c
drivers/clk/clk-divider.c
drivers/clk/clk-fixed-factor.c
drivers/clk/clk-fixed-rate.c
drivers/clk/clk-max-gen.c [deleted file]
drivers/clk/clk-max-gen.h [deleted file]
drivers/clk/clk-max77686.c
drivers/clk/clk-max77802.c [deleted file]
drivers/clk/clk-twl6040.c
drivers/clk/clk.c
drivers/clk/imx/clk-imx7d.c
drivers/clk/meson/gxbb.c
drivers/clk/mvebu/Kconfig
drivers/clk/mvebu/Makefile
drivers/clk/mvebu/armada-37xx-periph.c [new file with mode: 0644]
drivers/clk/mvebu/armada-37xx-tbg.c [new file with mode: 0644]
drivers/clk/mvebu/armada-37xx-xtal.c [new file with mode: 0644]
drivers/clk/mvebu/armada-39x.c
drivers/clk/nxp/clk-lpc18xx-creg.c
drivers/clk/renesas/r8a7795-cpg-mssr.c
drivers/clk/sunxi-ng/ccu_common.c
drivers/clk/sunxi/clk-mod0.c
drivers/clk/sunxi/clk-sun8i-apb0.c
include/dt-bindings/clock/maxim,max77620.h [new file with mode: 0644]
include/linux/clk-provider.h

diff --git a/Documentation/devicetree/bindings/clock/armada3700-periph-clock.txt b/Documentation/devicetree/bindings/clock/armada3700-periph-clock.txt
new file mode 100644 (file)
index 0000000..1e3370b
--- /dev/null
@@ -0,0 +1,70 @@
+* Peripheral Clock bindings for Marvell Armada 37xx SoCs
+
+Marvell Armada 37xx SoCs provide peripheral clocks which are
+used as clock source for the peripheral of the SoC.
+
+There are two different blocks associated to north bridge and south
+bridge.
+
+The peripheral clock consumer should specify the desired clock by
+having the clock ID in its "clocks" phandle cell.
+
+The following is a list of provided IDs for Armada 370 North bridge clocks:
+ID     Clock name      Description
+-----------------------------------
+0      mmc             MMC controller
+1      sata_host       Sata Host
+2      sec_at          Security AT
+3      sac_dap         Security DAP
+4      tsecm           Security Engine
+5      setm_tmx        Serial Embedded Trace Module
+6      avs             Adaptive Voltage Scaling
+7      sqf             SPI
+8      pwm             PWM
+9      i2c_2           I2C 2
+10     i2c_1           I2C 1
+11     ddr_phy         DDR PHY
+12     ddr_fclk        DDR F clock
+13     trace           Trace
+14     counter         Counter
+15     eip97           EIP 97
+16     cpu             CPU
+
+The following is a list of provided IDs for Armada 370 South bridge clocks:
+ID     Clock name      Description
+-----------------------------------
+0      gbe-50          50 MHz parent clock for Gigabit Ethernet
+1      gbe-core        parent clock for Gigabit Ethernet core
+2      gbe-125         125 MHz parent clock for Gigabit Ethernet
+3      gbe1-50         50 MHz clock for Gigabit Ethernet port 1
+4      gbe0-50         50 MHz clock for Gigabit Ethernet port 0
+5      gbe1-125        125 MHz clock for Gigabit Ethernet port 1
+6      gbe0-125        125 MHz clock for Gigabit Ethernet port 0
+7      gbe1-core       Gigabit Ethernet core port 1
+8      gbe0-core       Gigabit Ethernet core port 0
+9      gbe-bm          Gigabit Ethernet Buffer Manager
+10     sdio            SDIO
+11     usb32-sub2-sys  USB 2 clock
+12     usb32-ss-sys    USB 3 clock
+
+Required properties:
+
+- compatible : shall be "marvell,armada-3700-periph-clock-nb" for the
+  north bridge block, or
+  "marvell,armada-3700-periph-clock-sb" for the south bridge block
+- reg : must be the register address of North/South Bridge Clock register
+- #clock-cells : from common clock binding; shall be set to 1
+
+- clocks : list of the parent clock phandle in the following order:
+  TBG-A P, TBG-B P, TBG-A S, TBG-B S and finally the xtal clock.
+
+
+Example:
+
+nb_perih_clk: nb-periph-clk@13000{
+       compatible = "marvell,armada-3700-periph-clock-nb";
+       reg = <0x13000 0x1000>;
+       clocks = <&tbg 0>, <&tbg 1>, <&tbg 2>,
+       <&tbg 3>, <&xtalclk>;
+       #clock-cells = <1>;
+};
diff --git a/Documentation/devicetree/bindings/clock/armada3700-tbg-clock.txt b/Documentation/devicetree/bindings/clock/armada3700-tbg-clock.txt
new file mode 100644 (file)
index 0000000..0ba1d83
--- /dev/null
@@ -0,0 +1,27 @@
+* Time Base Generator Clock bindings for Marvell Armada 37xx SoCs
+
+Marvell Armada 37xx SoCs provde Time Base Generator clocks which are
+used as parent clocks for the peripheral clocks.
+
+The TBG clock consumer should specify the desired clock by having the
+clock ID in its "clocks" phandle cell.
+
+The following is a list of provided IDs and clock names on Armada 3700:
+ 0 = TBG A P
+ 1 = TBG B P
+ 2 = TBG A S
+ 3 = TBG B S
+
+Required properties:
+- compatible : shall be "marvell,armada-3700-tbg-clock"
+- reg : must be the register address of North Bridge PLL register
+- #clock-cells : from common clock binding; shall be set to 1
+
+Example:
+
+tbg: tbg@13200 {
+       compatible = "marvell,armada-3700-tbg-clock";
+       reg = <0x13200 0x1000>;
+       clocks = <&xtalclk>;
+       #clock-cells = <1>;
+};
diff --git a/Documentation/devicetree/bindings/clock/armada3700-xtal-clock.txt b/Documentation/devicetree/bindings/clock/armada3700-xtal-clock.txt
new file mode 100644 (file)
index 0000000..a88f1f0
--- /dev/null
@@ -0,0 +1,28 @@
+* Xtal Clock bindings for Marvell Armada 37xx SoCs
+
+Marvell Armada 37xx SoCs allow to determine the xtal clock frequencies by
+reading the gpio latch register.
+
+This node must be a subnode of the node exposing the register address
+of the GPIO block where the gpio latch is located.
+
+Required properties:
+- compatible : shall be one of the following:
+       "marvell,armada-3700-xtal-clock"
+- #clock-cells : from common clock binding; shall be set to 0
+
+Optional properties:
+- clock-output-names : from common clock binding; allows overwrite default clock
+       output names ("xtal")
+
+Example:
+gpio1: gpio@13800 {
+       compatible = "marvell,armada-3700-gpio", "syscon", "simple-mfd";
+       reg = <0x13800 0x1000>;
+
+       xtalclk: xtal-clk {
+               compatible = "marvell,armada-3700-xtal-clock";
+               clock-output-names = "xtal";
+               #clock-cells = <0>;
+       };
+};
index 9c40739..8398a3a 100644 (file)
@@ -1,10 +1,24 @@
-Binding for Maxim MAX77686 32k clock generator block
+Binding for Maxim MAX77686/MAX77802/MAX77620 32k clock generator block
 
-This is a part of device tree bindings of MAX77686 multi-function device.
-More information can be found in bindings/mfd/max77686.txt file.
+This is a part of device tree bindings of MAX77686/MAX77802/MAX77620
+multi-function device. More information can be found in MFD DT binding
+doc as follows:
+       bindings/mfd/max77686.txt for MAX77686 and
+       bindings/mfd/max77802.txt for MAX77802 and
+       bindings/mfd/max77620.txt for MAX77620.
 
 The MAX77686 contains three 32.768khz clock outputs that can be controlled
-(gated/ungated) over I2C.
+(gated/ungated) over I2C. Clocks are defined as preprocessor macros in
+dt-bindings/clock/maxim,max77686.h.
+
+
+The MAX77802 contains two 32.768khz clock outputs that can be controlled
+(gated/ungated) over I2C. Clocks are defined as preprocessor macros in
+dt-bindings/clock/maxim,max77802.h.
+
+The MAX77686 contains one 32.768khz clock outputs that can be controlled
+(gated/ungated) over I2C. Clocks are defined as preprocessor macros in
+dt-bindings/clock/maxim,max77620.h.
 
 Following properties should be presend in main device node of the MFD chip.
 
@@ -17,30 +31,84 @@ Optional properties:
 
 Each clock is assigned an identifier and client nodes can use this identifier
 to specify the clock which they consume. Following indices are allowed:
-    - 0: 32khz_ap clock,
-    - 1: 32khz_cp clock,
-    - 2: 32khz_pmic clock.
+    - 0: 32khz_ap clock (max77686, max77802), 32khz_out0 (max77620)
+    - 1: 32khz_cp clock (max77686, max77802),
+    - 2: 32khz_pmic clock (max77686).
+
+Clocks are defined as preprocessor macros in above dt-binding header for
+respective chips.
+
+Example:
+
+1. With MAX77686:
+
+#include <dt-bindings/clock/maxim,max77686.h>
+/* ... */
+
+       Node of the MFD chip
+               max77686: max77686@09 {
+                       compatible = "maxim,max77686";
+                       interrupt-parent = <&wakeup_eint>;
+                       interrupts = <26 0>;
+                       reg = <0x09>;
+                       #clock-cells = <1>;
+
+                       /* ... */
+               };
+
+       Clock consumer node
+
+               foo@0 {
+                       compatible = "bar,foo";
+                       /* ... */
+                       clock-names = "my-clock";
+                       clocks = <&max77686 MAX77686_CLK_PMIC>;
+               };
+
+2. With MAX77802:
+
+#include <dt-bindings/clock/maxim,max77802.h>
+/* ... */
+
+       Node of the MFD chip
+               max77802: max77802@09 {
+                       compatible = "maxim,max77802";
+                       interrupt-parent = <&wakeup_eint>;
+                       interrupts = <26 0>;
+                       reg = <0x09>;
+                       #clock-cells = <1>;
+
+                       /* ... */
+               };
+
+       Clock consumer node
+
+               foo@0 {
+                       compatible = "bar,foo";
+                       /* ... */
+                       clock-names = "my-clock";
+                       clocks = <&max77802 MAX77802_CLK_32K_AP>;
+               };
 
-Clocks are defined as preprocessor macros in dt-bindings/clock/maxim,max77686.h
-header and can be used in device tree sources.
 
-Example: Node of the MFD chip
+3. With MAX77620:
 
-       max77686: max77686@09 {
-               compatible = "maxim,max77686";
-               interrupt-parent = <&wakeup_eint>;
-               interrupts = <26 0>;
-               reg = <0x09>;
-               #clock-cells = <1>;
+#include <dt-bindings/clock/maxim,max77620.h>
+/* ... */
 
-               /* ... */
-       };
+       Node of the MFD chip
+               max77620: max77620@3c {
+                       compatible = "maxim,max77620";
+                       reg = <0x3c>;
+                       #clock-cells = <1>;
+                       /* ... */
+               };
 
-Example: Clock consumer node
+       Clock consumer node
 
-       foo@0 {
-               compatible = "bar,foo";
-               /* ... */
-               clock-names = "my-clock";
-               clocks = <&max77686 MAX77686_CLK_PMIC>;
-       };
+               foo@0 {
+                       compatible = "bar,foo";
+                       /* ... */
+                       clock-names = "my-clock";
+                       clocks = <&max77620 MAX77620_CLK_32K_OUT0>;
+               };
diff --git a/Documentation/devicetree/bindings/clock/maxim,max77802.txt b/Documentation/devicetree/bindings/clock/maxim,max77802.txt
deleted file mode 100644 (file)
index c6dc783..0000000
+++ /dev/null
@@ -1,44 +0,0 @@
-Binding for Maxim MAX77802 32k clock generator block
-
-This is a part of device tree bindings of MAX77802 multi-function device.
-More information can be found in bindings/mfd/max77802.txt file.
-
-The MAX77802 contains two 32.768khz clock outputs that can be controlled
-(gated/ungated) over I2C.
-
-Following properties should be present in main device node of the MFD chip.
-
-Required properties:
-- #clock-cells: From common clock binding; shall be set to 1.
-
-Optional properties:
-- clock-output-names: From common clock binding.
-
-Each clock is assigned an identifier and client nodes can use this identifier
-to specify the clock which they consume. Following indices are allowed:
-     - 0: 32khz_ap clock,
-     - 1: 32khz_cp clock.
-
-Clocks are defined as preprocessor macros in dt-bindings/clock/maxim,max77802.h
-header and can be used in device tree sources.
-
-Example: Node of the MFD chip
-
-       max77802: max77802@09 {
-               compatible = "maxim,max77802";
-               interrupt-parent = <&wakeup_eint>;
-               interrupts = <26 0>;
-               reg = <0x09>;
-               #clock-cells = <1>;
-
-               /* ... */
-       };
-
-Example: Clock consumer node
-
-       foo@0 {
-               compatible = "bar,foo";
-               /* ... */
-               clock-names = "my-clock";
-               clocks = <&max77802 MAX77802_CLK_32K_AP>;
-       };
index 660e649..cb8542d 100644 (file)
@@ -86,6 +86,8 @@ ID    Clock           Peripheral
 7      pex3            PCIe 3
 8      pex0            PCIe 0
 9      usb3h0          USB3 Host 0
+10     usb3h1          USB3 Host 1
+15     sata0           SATA 0
 17     sdio            SDIO
 22     xor0            XOR 0
 28     xor1            XOR 1
index 20bb1d0..5436d3a 100644 (file)
@@ -3150,6 +3150,7 @@ COMMON CLK FRAMEWORK
 M:     Michael Turquette <mturquette@baylibre.com>
 M:     Stephen Boyd <sboyd@codeaurora.org>
 L:     linux-clk@vger.kernel.org
+Q:     http://patchwork.kernel.org/project/linux-clk/list/
 T:     git git://git.kernel.org/pub/scm/linux/kernel/git/clk/linux.git
 S:     Maintained
 F:     Documentation/devicetree/bindings/clock/
index e2d9bd7..b3ee99a 100644 (file)
@@ -31,22 +31,12 @@ config COMMON_CLK_WM831X
 
 source "drivers/clk/versatile/Kconfig"
 
-config COMMON_CLK_MAX_GEN
-        bool
-
 config COMMON_CLK_MAX77686
-       tristate "Clock driver for Maxim 77686 MFD"
-       depends on MFD_MAX77686
-       select COMMON_CLK_MAX_GEN
-       ---help---
-         This driver supports Maxim 77686 crystal oscillator clock. 
-
-config COMMON_CLK_MAX77802
-       tristate "Clock driver for Maxim 77802 PMIC"
-       depends on MFD_MAX77686
-       select COMMON_CLK_MAX_GEN
+       tristate "Clock driver for Maxim 77620/77686/77802 MFD"
+       depends on MFD_MAX77686 || MFD_MAX77620
        ---help---
-         This driver supports Maxim 77802 crystal oscillator clock.
+         This driver supports Maxim 77620/77686/77802 crystal oscillator
+         clock.
 
 config COMMON_CLK_RK808
        tristate "Clock driver for RK808/RK818"
index 3b6f9cf..e775a83 100644 (file)
@@ -27,9 +27,7 @@ obj-$(CONFIG_COMMON_CLK_CS2000_CP)    += clk-cs2000-cp.o
 obj-$(CONFIG_ARCH_EFM32)               += clk-efm32gg.o
 obj-$(CONFIG_ARCH_HIGHBANK)            += clk-highbank.o
 obj-$(CONFIG_MACH_LOONGSON32)          += clk-ls1x.o
-obj-$(CONFIG_COMMON_CLK_MAX_GEN)       += clk-max-gen.o
 obj-$(CONFIG_COMMON_CLK_MAX77686)      += clk-max77686.o
-obj-$(CONFIG_COMMON_CLK_MAX77802)      += clk-max77802.o
 obj-$(CONFIG_ARCH_MB86S7X)             += clk-mb86s7x.o
 obj-$(CONFIG_ARCH_MOXART)              += clk-moxart.o
 obj-$(CONFIG_ARCH_NOMADIK)             += clk-nomadik.o
index ffc988b..da1a073 100644 (file)
@@ -113,8 +113,8 @@ static void of_artpec6_clkctrl_setup(struct device_node *np)
        of_clk_add_provider(np, of_clk_src_onecell_get, &clkdata->clk_data);
 }
 
-CLK_OF_DECLARE(artpec6_clkctrl, "axis,artpec6-clkctrl",
-              of_artpec6_clkctrl_setup);
+CLK_OF_DECLARE_DRIVER(artpec6_clkctrl, "axis,artpec6-clkctrl",
+                     of_artpec6_clkctrl_setup);
 
 static int artpec6_clkctrl_probe(struct platform_device *pdev)
 {
index a0f55bc..96386ff 100644 (file)
@@ -352,7 +352,7 @@ static long clk_divider_round_rate(struct clk_hw *hw, unsigned long rate,
 
        /* if read only, just return current value */
        if (divider->flags & CLK_DIVIDER_READ_ONLY) {
-               bestdiv = readl(divider->reg) >> divider->shift;
+               bestdiv = clk_readl(divider->reg) >> divider->shift;
                bestdiv &= div_mask(divider->width);
                bestdiv = _get_div(divider->table, bestdiv, divider->flags,
                        divider->width);
index 4db3be2..a5d402d 100644 (file)
@@ -12,6 +12,7 @@
 #include <linux/slab.h>
 #include <linux/err.h>
 #include <linux/of.h>
+#include <linux/platform_device.h>
 
 /*
  * DOC: basic fixed multiplier and divider clock that cannot gate
@@ -147,27 +148,25 @@ static const struct of_device_id set_rate_parent_matches[] = {
        { /* Sentinel */ },
 };
 
-/**
- * of_fixed_factor_clk_setup() - Setup function for simple fixed factor clock
- */
-void __init of_fixed_factor_clk_setup(struct device_node *node)
+static struct clk *_of_fixed_factor_clk_setup(struct device_node *node)
 {
        struct clk *clk;
        const char *clk_name = node->name;
        const char *parent_name;
        unsigned long flags = 0;
        u32 div, mult;
+       int ret;
 
        if (of_property_read_u32(node, "clock-div", &div)) {
                pr_err("%s Fixed factor clock <%s> must have a clock-div property\n",
                        __func__, node->name);
-               return;
+               return ERR_PTR(-EIO);
        }
 
        if (of_property_read_u32(node, "clock-mult", &mult)) {
                pr_err("%s Fixed factor clock <%s> must have a clock-mult property\n",
                        __func__, node->name);
-               return;
+               return ERR_PTR(-EIO);
        }
 
        of_property_read_string(node, "clock-output-names", &clk_name);
@@ -178,10 +177,67 @@ void __init of_fixed_factor_clk_setup(struct device_node *node)
 
        clk = clk_register_fixed_factor(NULL, clk_name, parent_name, flags,
                                        mult, div);
-       if (!IS_ERR(clk))
-               of_clk_add_provider(node, of_clk_src_simple_get, clk);
+       if (IS_ERR(clk))
+               return clk;
+
+       ret = of_clk_add_provider(node, of_clk_src_simple_get, clk);
+       if (ret) {
+               clk_unregister(clk);
+               return ERR_PTR(ret);
+       }
+
+       return clk;
+}
+
+/**
+ * of_fixed_factor_clk_setup() - Setup function for simple fixed factor clock
+ */
+void __init of_fixed_factor_clk_setup(struct device_node *node)
+{
+       _of_fixed_factor_clk_setup(node);
 }
-EXPORT_SYMBOL_GPL(of_fixed_factor_clk_setup);
 CLK_OF_DECLARE(fixed_factor_clk, "fixed-factor-clock",
                of_fixed_factor_clk_setup);
+
+static int of_fixed_factor_clk_remove(struct platform_device *pdev)
+{
+       struct clk *clk = platform_get_drvdata(pdev);
+
+       clk_unregister_fixed_factor(clk);
+
+       return 0;
+}
+
+static int of_fixed_factor_clk_probe(struct platform_device *pdev)
+{
+       struct clk *clk;
+
+       /*
+        * This function is not executed when of_fixed_factor_clk_setup
+        * succeeded.
+        */
+       clk = _of_fixed_factor_clk_setup(pdev->dev.of_node);
+       if (IS_ERR(clk))
+               return PTR_ERR(clk);
+
+       platform_set_drvdata(pdev, clk);
+
+       return 0;
+}
+
+static const struct of_device_id of_fixed_factor_clk_ids[] = {
+       { .compatible = "fixed-factor-clock" },
+       { }
+};
+MODULE_DEVICE_TABLE(of, of_fixed_factor_clk_ids);
+
+static struct platform_driver of_fixed_factor_clk_driver = {
+       .driver = {
+               .name = "of_fixed_factor_clk",
+               .of_match_table = of_fixed_factor_clk_ids,
+       },
+       .probe = of_fixed_factor_clk_probe,
+       .remove = of_fixed_factor_clk_remove,
+};
+builtin_platform_driver(of_fixed_factor_clk_driver);
 #endif
index 2edb393..b5c46b3 100644 (file)
@@ -15,6 +15,7 @@
 #include <linux/io.h>
 #include <linux/err.h>
 #include <linux/of.h>
+#include <linux/platform_device.h>
 
 /*
  * DOC: basic fixed-rate clock that cannot gate
@@ -157,18 +158,16 @@ void clk_hw_unregister_fixed_rate(struct clk_hw *hw)
 EXPORT_SYMBOL_GPL(clk_hw_unregister_fixed_rate);
 
 #ifdef CONFIG_OF
-/**
- * of_fixed_clk_setup() - Setup function for simple fixed rate clock
- */
-void of_fixed_clk_setup(struct device_node *node)
+static struct clk *_of_fixed_clk_setup(struct device_node *node)
 {
        struct clk *clk;
        const char *clk_name = node->name;
        u32 rate;
        u32 accuracy = 0;
+       int ret;
 
        if (of_property_read_u32(node, "clock-frequency", &rate))
-               return;
+               return ERR_PTR(-EIO);
 
        of_property_read_u32(node, "clock-accuracy", &accuracy);
 
@@ -176,9 +175,66 @@ void of_fixed_clk_setup(struct device_node *node)
 
        clk = clk_register_fixed_rate_with_accuracy(NULL, clk_name, NULL,
                                                    0, rate, accuracy);
-       if (!IS_ERR(clk))
-               of_clk_add_provider(node, of_clk_src_simple_get, clk);
+       if (IS_ERR(clk))
+               return clk;
+
+       ret = of_clk_add_provider(node, of_clk_src_simple_get, clk);
+       if (ret) {
+               clk_unregister(clk);
+               return ERR_PTR(ret);
+       }
+
+       return clk;
+}
+
+/**
+ * of_fixed_clk_setup() - Setup function for simple fixed rate clock
+ */
+void __init of_fixed_clk_setup(struct device_node *node)
+{
+       _of_fixed_clk_setup(node);
 }
-EXPORT_SYMBOL_GPL(of_fixed_clk_setup);
 CLK_OF_DECLARE(fixed_clk, "fixed-clock", of_fixed_clk_setup);
+
+static int of_fixed_clk_remove(struct platform_device *pdev)
+{
+       struct clk *clk = platform_get_drvdata(pdev);
+
+       clk_unregister_fixed_rate(clk);
+
+       return 0;
+}
+
+static int of_fixed_clk_probe(struct platform_device *pdev)
+{
+       struct clk *clk;
+
+       /*
+        * This function is not executed when of_fixed_clk_setup
+        * succeeded.
+        */
+       clk = _of_fixed_clk_setup(pdev->dev.of_node);
+       if (IS_ERR(clk))
+               return PTR_ERR(clk);
+
+       platform_set_drvdata(pdev, clk);
+
+       return 0;
+}
+
+static const struct of_device_id of_fixed_clk_ids[] = {
+       { .compatible = "fixed-clock" },
+       { }
+};
+MODULE_DEVICE_TABLE(of, of_fixed_clk_ids);
+
+static struct platform_driver of_fixed_clk_driver = {
+       .driver = {
+               .name = "of_fixed_clk",
+               .of_match_table = of_fixed_clk_ids,
+       },
+       .probe = of_fixed_clk_probe,
+       .remove = of_fixed_clk_remove,
+};
+builtin_platform_driver(of_fixed_clk_driver);
 #endif
diff --git a/drivers/clk/clk-max-gen.c b/drivers/clk/clk-max-gen.c
deleted file mode 100644 (file)
index 35af9cb..0000000
+++ /dev/null
@@ -1,194 +0,0 @@
-/*
- * clk-max-gen.c - Generic clock driver for Maxim PMICs clocks
- *
- * Copyright (C) 2014 Google, Inc
- *
- * Copyright (C) 2012 Samsung Electornics
- * Jonghwa Lee <jonghwa3.lee@samsung.com>
- *
- * 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;  either version 2 of the  License, or (at your
- * option) any later version.
- *
- * 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.
- *
- * This driver is based on clk-max77686.c
- *
- */
-
-#include <linux/kernel.h>
-#include <linux/slab.h>
-#include <linux/err.h>
-#include <linux/regmap.h>
-#include <linux/platform_device.h>
-#include <linux/clk-provider.h>
-#include <linux/mutex.h>
-#include <linux/clkdev.h>
-#include <linux/of.h>
-#include <linux/export.h>
-
-#include "clk-max-gen.h"
-
-struct max_gen_clk {
-       struct regmap *regmap;
-       u32 mask;
-       u32 reg;
-       struct clk_hw hw;
-};
-
-static struct max_gen_clk *to_max_gen_clk(struct clk_hw *hw)
-{
-       return container_of(hw, struct max_gen_clk, hw);
-}
-
-static int max_gen_clk_prepare(struct clk_hw *hw)
-{
-       struct max_gen_clk *max_gen = to_max_gen_clk(hw);
-
-       return regmap_update_bits(max_gen->regmap, max_gen->reg,
-                                 max_gen->mask, max_gen->mask);
-}
-
-static void max_gen_clk_unprepare(struct clk_hw *hw)
-{
-       struct max_gen_clk *max_gen = to_max_gen_clk(hw);
-
-       regmap_update_bits(max_gen->regmap, max_gen->reg,
-                          max_gen->mask, ~max_gen->mask);
-}
-
-static int max_gen_clk_is_prepared(struct clk_hw *hw)
-{
-       struct max_gen_clk *max_gen = to_max_gen_clk(hw);
-       int ret;
-       u32 val;
-
-       ret = regmap_read(max_gen->regmap, max_gen->reg, &val);
-
-       if (ret < 0)
-               return -EINVAL;
-
-       return val & max_gen->mask;
-}
-
-static unsigned long max_gen_recalc_rate(struct clk_hw *hw,
-                                        unsigned long parent_rate)
-{
-       return 32768;
-}
-
-struct clk_ops max_gen_clk_ops = {
-       .prepare        = max_gen_clk_prepare,
-       .unprepare      = max_gen_clk_unprepare,
-       .is_prepared    = max_gen_clk_is_prepared,
-       .recalc_rate    = max_gen_recalc_rate,
-};
-EXPORT_SYMBOL_GPL(max_gen_clk_ops);
-
-static struct clk *max_gen_clk_register(struct device *dev,
-                                       struct max_gen_clk *max_gen)
-{
-       struct clk *clk;
-       struct clk_hw *hw = &max_gen->hw;
-       int ret;
-
-       clk = devm_clk_register(dev, hw);
-       if (IS_ERR(clk))
-               return clk;
-
-       ret = clk_register_clkdev(clk, hw->init->name, NULL);
-
-       if (ret)
-               return ERR_PTR(ret);
-
-       return clk;
-}
-
-int max_gen_clk_probe(struct platform_device *pdev, struct regmap *regmap,
-                     u32 reg, struct clk_init_data *clks_init, int num_init)
-{
-       int i, ret;
-       struct max_gen_clk *max_gen_clks;
-       struct clk **clocks;
-       struct device *dev = pdev->dev.parent;
-       const char *clk_name;
-       struct clk_init_data *init;
-
-       clocks = devm_kzalloc(dev, sizeof(struct clk *) * num_init, GFP_KERNEL);
-       if (!clocks)
-               return -ENOMEM;
-
-       max_gen_clks = devm_kzalloc(dev, sizeof(struct max_gen_clk)
-                                   * num_init, GFP_KERNEL);
-       if (!max_gen_clks)
-               return -ENOMEM;
-
-       for (i = 0; i < num_init; i++) {
-               max_gen_clks[i].regmap = regmap;
-               max_gen_clks[i].mask = 1 << i;
-               max_gen_clks[i].reg = reg;
-
-               init = devm_kzalloc(dev, sizeof(*init), GFP_KERNEL);
-               if (!init)
-                       return -ENOMEM;
-
-               if (dev->of_node &&
-                   !of_property_read_string_index(dev->of_node,
-                                                  "clock-output-names",
-                                                  i, &clk_name))
-                       init->name = clk_name;
-               else
-                       init->name = clks_init[i].name;
-
-               init->ops = clks_init[i].ops;
-               init->flags = clks_init[i].flags;
-
-               max_gen_clks[i].hw.init = init;
-
-               clocks[i] = max_gen_clk_register(dev, &max_gen_clks[i]);
-               if (IS_ERR(clocks[i])) {
-                       ret = PTR_ERR(clocks[i]);
-                       dev_err(dev, "failed to register %s\n",
-                               max_gen_clks[i].hw.init->name);
-                       return ret;
-               }
-       }
-
-       platform_set_drvdata(pdev, clocks);
-
-       if (dev->of_node) {
-               struct clk_onecell_data *of_data;
-
-               of_data = devm_kzalloc(dev, sizeof(*of_data), GFP_KERNEL);
-               if (!of_data)
-                       return -ENOMEM;
-
-               of_data->clks = clocks;
-               of_data->clk_num = num_init;
-               ret = of_clk_add_provider(dev->of_node, of_clk_src_onecell_get,
-                                         of_data);
-
-               if (ret) {
-                       dev_err(dev, "failed to register OF clock provider\n");
-                       return ret;
-               }
-       }
-
-       return 0;
-}
-EXPORT_SYMBOL_GPL(max_gen_clk_probe);
-
-int max_gen_clk_remove(struct platform_device *pdev, int num_init)
-{
-       struct device *dev = pdev->dev.parent;
-
-       if (dev->of_node)
-               of_clk_del_provider(dev->of_node);
-
-       return 0;
-}
-EXPORT_SYMBOL_GPL(max_gen_clk_remove);
diff --git a/drivers/clk/clk-max-gen.h b/drivers/clk/clk-max-gen.h
deleted file mode 100644 (file)
index 997e86f..0000000
+++ /dev/null
@@ -1,32 +0,0 @@
-/*
- * clk-max-gen.h - Generic clock driver for Maxim PMICs clocks
- *
- * Copyright (C) 2014 Google, Inc
- *
- * 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;  either version 2 of the  License, or (at your
- * option) any later version.
- *
- * 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 __CLK_MAX_GEN_H__
-#define __CLK_MAX_GEN_H__
-
-#include <linux/types.h>
-#include <linux/device.h>
-#include <linux/clkdev.h>
-#include <linux/regmap.h>
-#include <linux/platform_device.h>
-
-int max_gen_clk_probe(struct platform_device *pdev, struct regmap *regmap,
-                     u32 reg, struct clk_init_data *clks_init, int num_init);
-int max_gen_clk_remove(struct platform_device *pdev, int num_init);
-extern struct clk_ops max_gen_clk_ops;
-
-#endif /* __CLK_MAX_GEN_H__ */
index 9b6f277..19f6208 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * clk-max77686.c - Clock driver for Maxim 77686
+ * clk-max77686.c - Clock driver for Maxim 77686/MAX77802
  *
  * Copyright (C) 2012 Samsung Electornics
  * Jonghwa Lee <jonghwa3.lee@samsung.com>
 #include <linux/err.h>
 #include <linux/module.h>
 #include <linux/platform_device.h>
+#include <linux/mfd/max77620.h>
 #include <linux/mfd/max77686.h>
 #include <linux/mfd/max77686-private.h>
 #include <linux/clk-provider.h>
 #include <linux/mutex.h>
 #include <linux/clkdev.h>
+#include <linux/of.h>
+#include <linux/regmap.h>
 
 #include <dt-bindings/clock/maxim,max77686.h>
-#include "clk-max-gen.h"
+#include <dt-bindings/clock/maxim,max77802.h>
+#include <dt-bindings/clock/maxim,max77620.h>
 
-static struct clk_init_data max77686_clks_init[MAX77686_CLKS_NUM] = {
+#define MAX77802_CLOCK_LOW_JITTER_SHIFT 0x3
+
+enum max77686_chip_name {
+       CHIP_MAX77686,
+       CHIP_MAX77802,
+       CHIP_MAX77620,
+};
+
+struct max77686_hw_clk_info {
+       const char *name;
+       u32 clk_reg;
+       u32 clk_enable_mask;
+       u32 flags;
+};
+
+struct max77686_clk_init_data {
+       struct regmap *regmap;
+       struct clk_hw hw;
+       struct clk_init_data clk_idata;
+       const struct max77686_hw_clk_info *clk_info;
+};
+
+struct max77686_clk_driver_data {
+       enum max77686_chip_name chip;
+       struct clk **clks;
+       struct max77686_clk_init_data *max_clk_data;
+       struct clk_onecell_data of_data;
+};
+
+static const struct
+max77686_hw_clk_info max77686_hw_clks_info[MAX77686_CLKS_NUM] = {
        [MAX77686_CLK_AP] = {
                .name = "32khz_ap",
-               .ops = &max_gen_clk_ops,
+               .clk_reg = MAX77686_REG_32KHZ,
+               .clk_enable_mask = BIT(MAX77686_CLK_AP),
        },
        [MAX77686_CLK_CP] = {
                .name = "32khz_cp",
-               .ops = &max_gen_clk_ops,
+               .clk_reg = MAX77686_REG_32KHZ,
+               .clk_enable_mask = BIT(MAX77686_CLK_CP),
        },
        [MAX77686_CLK_PMIC] = {
                .name = "32khz_pmic",
-               .ops = &max_gen_clk_ops,
+               .clk_reg = MAX77686_REG_32KHZ,
+               .clk_enable_mask = BIT(MAX77686_CLK_PMIC),
+       },
+};
+
+static const struct
+max77686_hw_clk_info max77802_hw_clks_info[MAX77802_CLKS_NUM] = {
+       [MAX77802_CLK_32K_AP] = {
+               .name = "32khz_ap",
+               .clk_reg = MAX77802_REG_32KHZ,
+               .clk_enable_mask = BIT(MAX77802_CLK_32K_AP),
+       },
+       [MAX77802_CLK_32K_CP] = {
+               .name = "32khz_cp",
+               .clk_reg = MAX77802_REG_32KHZ,
+               .clk_enable_mask = BIT(MAX77802_CLK_32K_CP),
+       },
+};
+
+static const struct
+max77686_hw_clk_info max77620_hw_clks_info[MAX77620_CLKS_NUM] = {
+       [MAX77620_CLK_32K_OUT0] = {
+               .name = "32khz_out0",
+               .clk_reg = MAX77620_REG_CNFG1_32K,
+               .clk_enable_mask = MAX77620_CNFG1_32K_OUT0_EN,
        },
 };
 
+static struct max77686_clk_init_data *to_max77686_clk_init_data(
+                               struct clk_hw *hw)
+{
+       return container_of(hw, struct max77686_clk_init_data, hw);
+}
+
+static int max77686_clk_prepare(struct clk_hw *hw)
+{
+       struct max77686_clk_init_data *max77686 = to_max77686_clk_init_data(hw);
+
+       return regmap_update_bits(max77686->regmap, max77686->clk_info->clk_reg,
+                                 max77686->clk_info->clk_enable_mask,
+                                 max77686->clk_info->clk_enable_mask);
+}
+
+static void max77686_clk_unprepare(struct clk_hw *hw)
+{
+       struct max77686_clk_init_data *max77686 = to_max77686_clk_init_data(hw);
+
+       regmap_update_bits(max77686->regmap, max77686->clk_info->clk_reg,
+                          max77686->clk_info->clk_enable_mask,
+                          ~max77686->clk_info->clk_enable_mask);
+}
+
+static int max77686_clk_is_prepared(struct clk_hw *hw)
+{
+       struct max77686_clk_init_data *max77686 = to_max77686_clk_init_data(hw);
+       int ret;
+       u32 val;
+
+       ret = regmap_read(max77686->regmap, max77686->clk_info->clk_reg, &val);
+
+       if (ret < 0)
+               return -EINVAL;
+
+       return val & max77686->clk_info->clk_enable_mask;
+}
+
+static unsigned long max77686_recalc_rate(struct clk_hw *hw,
+                                         unsigned long parent_rate)
+{
+       return 32768;
+}
+
+static struct clk_ops max77686_clk_ops = {
+       .prepare        = max77686_clk_prepare,
+       .unprepare      = max77686_clk_unprepare,
+       .is_prepared    = max77686_clk_is_prepared,
+       .recalc_rate    = max77686_recalc_rate,
+};
+
 static int max77686_clk_probe(struct platform_device *pdev)
 {
-       struct max77686_dev *iodev = dev_get_drvdata(pdev->dev.parent);
+       struct device *dev = &pdev->dev;
+       struct device *parent = dev->parent;
+       const struct platform_device_id *id = platform_get_device_id(pdev);
+       struct max77686_clk_driver_data *drv_data;
+       const struct max77686_hw_clk_info *hw_clks;
+       struct regmap *regmap;
+       int i, ret, num_clks;
+
+       drv_data = devm_kzalloc(dev, sizeof(*drv_data), GFP_KERNEL);
+       if (!drv_data)
+               return -ENOMEM;
+
+       regmap = dev_get_regmap(parent, NULL);
+       if (!regmap) {
+               dev_err(dev, "Failed to get rtc regmap\n");
+               return -ENODEV;
+       }
+
+       drv_data->chip = id->driver_data;
+
+       switch (drv_data->chip) {
+       case CHIP_MAX77686:
+               num_clks = MAX77686_CLKS_NUM;
+               hw_clks = max77686_hw_clks_info;
+               break;
+
+       case CHIP_MAX77802:
+               num_clks = MAX77802_CLKS_NUM;
+               hw_clks = max77802_hw_clks_info;
+               break;
+
+       case CHIP_MAX77620:
+               num_clks = MAX77620_CLKS_NUM;
+               hw_clks = max77620_hw_clks_info;
+               break;
+
+       default:
+               dev_err(dev, "Unknown Chip ID\n");
+               return -EINVAL;
+       }
+
+       drv_data->max_clk_data = devm_kcalloc(dev, num_clks,
+                                             sizeof(*drv_data->max_clk_data),
+                                             GFP_KERNEL);
+       if (!drv_data->max_clk_data)
+               return -ENOMEM;
 
-       return max_gen_clk_probe(pdev, iodev->regmap, MAX77686_REG_32KHZ,
-                                max77686_clks_init, MAX77686_CLKS_NUM);
+       drv_data->clks = devm_kcalloc(dev, num_clks,
+                                     sizeof(*drv_data->clks), GFP_KERNEL);
+       if (!drv_data->clks)
+               return -ENOMEM;
+
+       for (i = 0; i < num_clks; i++) {
+               struct max77686_clk_init_data *max_clk_data;
+               struct clk *clk;
+               const char *clk_name;
+
+               max_clk_data = &drv_data->max_clk_data[i];
+
+               max_clk_data->regmap = regmap;
+               max_clk_data->clk_info = &hw_clks[i];
+               max_clk_data->clk_idata.flags = hw_clks[i].flags;
+               max_clk_data->clk_idata.ops = &max77686_clk_ops;
+
+               if (parent->of_node &&
+                   !of_property_read_string_index(parent->of_node,
+                                                  "clock-output-names",
+                                                  i, &clk_name))
+                       max_clk_data->clk_idata.name = clk_name;
+               else
+                       max_clk_data->clk_idata.name = hw_clks[i].name;
+
+               max_clk_data->hw.init = &max_clk_data->clk_idata;
+
+               clk = devm_clk_register(dev, &max_clk_data->hw);
+               if (IS_ERR(clk)) {
+                       ret = PTR_ERR(clk);
+                       dev_err(dev, "Failed to clock register: %d\n", ret);
+                       return ret;
+               }
+
+               ret = clk_register_clkdev(clk, max_clk_data->clk_idata.name,
+                                         NULL);
+               if (ret < 0) {
+                       dev_err(dev, "Failed to clkdev register: %d\n", ret);
+                       return ret;
+               }
+               drv_data->clks[i] = clk;
+       }
+
+       platform_set_drvdata(pdev, drv_data);
+
+       if (parent->of_node) {
+               drv_data->of_data.clks = drv_data->clks;
+               drv_data->of_data.clk_num = num_clks;
+               ret = of_clk_add_provider(parent->of_node,
+                                         of_clk_src_onecell_get,
+                                         &drv_data->of_data);
+
+               if (ret < 0) {
+                       dev_err(dev, "Failed to register OF clock provider: %d\n",
+                               ret);
+                       return ret;
+               }
+       }
+
+       /* MAX77802: Enable low-jitter mode on the 32khz clocks. */
+       if (drv_data->chip == CHIP_MAX77802) {
+               ret = regmap_update_bits(regmap, MAX77802_REG_32KHZ,
+                                        1 << MAX77802_CLOCK_LOW_JITTER_SHIFT,
+                                        1 << MAX77802_CLOCK_LOW_JITTER_SHIFT);
+               if (ret < 0) {
+                       dev_err(dev, "Failed to config low-jitter: %d\n", ret);
+                       goto remove_of_clk_provider;
+               }
+       }
+
+       return 0;
+
+remove_of_clk_provider:
+       if (parent->of_node)
+               of_clk_del_provider(parent->of_node);
+
+       return ret;
 }
 
 static int max77686_clk_remove(struct platform_device *pdev)
 {
-       return max_gen_clk_remove(pdev, MAX77686_CLKS_NUM);
+       struct device *parent = pdev->dev.parent;
+
+       if (parent->of_node)
+               of_clk_del_provider(parent->of_node);
+
+       return 0;
 }
 
 static const struct platform_device_id max77686_clk_id[] = {
-       { "max77686-clk", 0},
-       { },
+       { "max77686-clk", .driver_data = CHIP_MAX77686, },
+       { "max77802-clk", .driver_data = CHIP_MAX77802, },
+       { "max77620-clock", .driver_data = CHIP_MAX77620, },
+       {},
 };
 MODULE_DEVICE_TABLE(platform, max77686_clk_id);
 
diff --git a/drivers/clk/clk-max77802.c b/drivers/clk/clk-max77802.c
deleted file mode 100644 (file)
index 355dd2e..0000000
+++ /dev/null
@@ -1,96 +0,0 @@
-/*
- * clk-max77802.c - Clock driver for Maxim 77802
- *
- * Copyright (C) 2014 Google, Inc
- *
- * Copyright (C) 2012 Samsung Electornics
- * Jonghwa Lee <jonghwa3.lee@samsung.com>
- *
- * 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;  either version 2 of the  License, or (at your
- * option) any later version.
- *
- * 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.
- *
- * This driver is based on clk-max77686.c
- */
-
-#include <linux/kernel.h>
-#include <linux/slab.h>
-#include <linux/err.h>
-#include <linux/module.h>
-#include <linux/platform_device.h>
-#include <linux/mfd/max77686-private.h>
-#include <linux/clk-provider.h>
-#include <linux/mutex.h>
-#include <linux/clkdev.h>
-
-#include <dt-bindings/clock/maxim,max77802.h>
-#include "clk-max-gen.h"
-
-#define MAX77802_CLOCK_OPMODE_MASK     0x1
-#define MAX77802_CLOCK_LOW_JITTER_SHIFT 0x3
-
-static struct clk_init_data max77802_clks_init[MAX77802_CLKS_NUM] = {
-       [MAX77802_CLK_32K_AP] = {
-               .name = "32khz_ap",
-               .ops = &max_gen_clk_ops,
-       },
-       [MAX77802_CLK_32K_CP] = {
-               .name = "32khz_cp",
-               .ops = &max_gen_clk_ops,
-       },
-};
-
-static int max77802_clk_probe(struct platform_device *pdev)
-{
-       struct max77686_dev *iodev = dev_get_drvdata(pdev->dev.parent);
-       int ret;
-
-       ret = max_gen_clk_probe(pdev, iodev->regmap, MAX77802_REG_32KHZ,
-                               max77802_clks_init, MAX77802_CLKS_NUM);
-
-       if (ret) {
-               dev_err(&pdev->dev, "generic probe failed %d\n", ret);
-               return ret;
-       }
-
-       /* Enable low-jitter mode on the 32khz clocks. */
-       ret = regmap_update_bits(iodev->regmap, MAX77802_REG_32KHZ,
-                                1 << MAX77802_CLOCK_LOW_JITTER_SHIFT,
-                                1 << MAX77802_CLOCK_LOW_JITTER_SHIFT);
-       if (ret < 0)
-               dev_err(&pdev->dev, "failed to enable low-jitter mode\n");
-
-       return ret;
-}
-
-static int max77802_clk_remove(struct platform_device *pdev)
-{
-       return max_gen_clk_remove(pdev, MAX77802_CLKS_NUM);
-}
-
-static const struct platform_device_id max77802_clk_id[] = {
-       { "max77802-clk", 0},
-       { },
-};
-MODULE_DEVICE_TABLE(platform, max77802_clk_id);
-
-static struct platform_driver max77802_clk_driver = {
-       .driver = {
-               .name  = "max77802-clk",
-       },
-       .probe = max77802_clk_probe,
-       .remove = max77802_clk_remove,
-       .id_table = max77802_clk_id,
-};
-
-module_platform_driver(max77802_clk_driver);
-
-MODULE_DESCRIPTION("MAXIM 77802 Clock Driver");
-MODULE_AUTHOR("Javier Martinez Canillas <javier@osg.samsung.com");
-MODULE_LICENSE("GPL");
index 697c667..c98b1ec 100644 (file)
 #include <linux/mfd/twl6040.h>
 #include <linux/clk-provider.h>
 
-struct twl6040_clk {
+struct twl6040_pdmclk {
        struct twl6040 *twl6040;
        struct device *dev;
-       struct clk_hw mcpdm_fclk;
+       struct clk_hw pdmclk_hw;
        struct clk *clk;
        int enabled;
 };
 
-static int twl6040_bitclk_is_enabled(struct clk_hw *hw)
+static int twl6040_pdmclk_is_prepared(struct clk_hw *hw)
 {
-       struct twl6040_clk *twl6040_clk = container_of(hw, struct twl6040_clk,
-                                                      mcpdm_fclk);
-       return twl6040_clk->enabled;
+       struct twl6040_pdmclk *pdmclk = container_of(hw, struct twl6040_pdmclk,
+                                                    pdmclk_hw);
+
+       return pdmclk->enabled;
 }
 
-static int twl6040_bitclk_prepare(struct clk_hw *hw)
+static int twl6040_pdmclk_prepare(struct clk_hw *hw)
 {
-       struct twl6040_clk *twl6040_clk = container_of(hw, struct twl6040_clk,
-                                                      mcpdm_fclk);
+       struct twl6040_pdmclk *pdmclk = container_of(hw, struct twl6040_pdmclk,
+                                                    pdmclk_hw);
        int ret;
 
-       ret = twl6040_power(twl6040_clk->twl6040, 1);
+       ret = twl6040_power(pdmclk->twl6040, 1);
        if (!ret)
-               twl6040_clk->enabled = 1;
+               pdmclk->enabled = 1;
 
        return ret;
 }
 
-static void twl6040_bitclk_unprepare(struct clk_hw *hw)
+static void twl6040_pdmclk_unprepare(struct clk_hw *hw)
 {
-       struct twl6040_clk *twl6040_clk = container_of(hw, struct twl6040_clk,
-                                                      mcpdm_fclk);
+       struct twl6040_pdmclk *pdmclk = container_of(hw, struct twl6040_pdmclk,
+                                                    pdmclk_hw);
        int ret;
 
-       ret = twl6040_power(twl6040_clk->twl6040, 0);
+       ret = twl6040_power(pdmclk->twl6040, 0);
        if (!ret)
-               twl6040_clk->enabled = 0;
+               pdmclk->enabled = 0;
+
+}
+
+static unsigned long twl6040_pdmclk_recalc_rate(struct clk_hw *hw,
+                                               unsigned long parent_rate)
+{
+       struct twl6040_pdmclk *pdmclk = container_of(hw, struct twl6040_pdmclk,
+                                                    pdmclk_hw);
+
+       return twl6040_get_sysclk(pdmclk->twl6040);
 }
 
-static const struct clk_ops twl6040_mcpdm_ops = {
-       .is_enabled = twl6040_bitclk_is_enabled,
-       .prepare = twl6040_bitclk_prepare,
-       .unprepare = twl6040_bitclk_unprepare,
+static const struct clk_ops twl6040_pdmclk_ops = {
+       .is_prepared = twl6040_pdmclk_is_prepared,
+       .prepare = twl6040_pdmclk_prepare,
+       .unprepare = twl6040_pdmclk_unprepare,
+       .recalc_rate = twl6040_pdmclk_recalc_rate,
 };
 
-static struct clk_init_data wm831x_clkout_init = {
-       .name = "mcpdm_fclk",
-       .ops = &twl6040_mcpdm_ops,
+static struct clk_init_data twl6040_pdmclk_init = {
+       .name = "pdmclk",
+       .ops = &twl6040_pdmclk_ops,
+       .flags = CLK_GET_RATE_NOCACHE,
 };
 
-static int twl6040_clk_probe(struct platform_device *pdev)
+static int twl6040_pdmclk_probe(struct platform_device *pdev)
 {
        struct twl6040 *twl6040 = dev_get_drvdata(pdev->dev.parent);
-       struct twl6040_clk *clkdata;
+       struct twl6040_pdmclk *clkdata;
 
        clkdata = devm_kzalloc(&pdev->dev, sizeof(*clkdata), GFP_KERNEL);
        if (!clkdata)
@@ -88,26 +101,27 @@ static int twl6040_clk_probe(struct platform_device *pdev)
        clkdata->dev = &pdev->dev;
        clkdata->twl6040 = twl6040;
 
-       clkdata->mcpdm_fclk.init = &wm831x_clkout_init;
-       clkdata->clk = devm_clk_register(&pdev->dev, &clkdata->mcpdm_fclk);
+       clkdata->pdmclk_hw.init = &twl6040_pdmclk_init;
+       clkdata->clk = devm_clk_register(&pdev->dev, &clkdata->pdmclk_hw);
        if (IS_ERR(clkdata->clk))
                return PTR_ERR(clkdata->clk);
 
        platform_set_drvdata(pdev, clkdata);
 
-       return 0;
+       return of_clk_add_provider(pdev->dev.parent->of_node,
+                                  of_clk_src_simple_get, clkdata->clk);
 }
 
-static struct platform_driver twl6040_clk_driver = {
+static struct platform_driver twl6040_pdmclk_driver = {
        .driver = {
-               .name = "twl6040-clk",
+               .name = "twl6040-pdmclk",
        },
-       .probe = twl6040_clk_probe,
+       .probe = twl6040_pdmclk_probe,
 };
 
-module_platform_driver(twl6040_clk_driver);
+module_platform_driver(twl6040_pdmclk_driver);
 
 MODULE_DESCRIPTION("TWL6040 clock driver for McPDM functional clock");
 MODULE_AUTHOR("Peter Ujfalusi <peter.ujfalusi@ti.com>");
-MODULE_ALIAS("platform:twl6040-clk");
+MODULE_ALIAS("platform:twl6040-pdmclk");
 MODULE_LICENSE("GPL");
index 820a939..71cc567 100644 (file)
@@ -2449,8 +2449,16 @@ static int __clk_core_init(struct clk_core *core)
        hlist_for_each_entry_safe(orphan, tmp2, &clk_orphan_list, child_node) {
                struct clk_core *parent = __clk_init_parent(orphan);
 
-               if (parent)
-                       clk_core_reparent(orphan, parent);
+               /*
+                * we could call __clk_set_parent, but that would result in a
+                * redundant call to the .set_rate op, if it exists
+                */
+               if (parent) {
+                       __clk_set_parent_before(orphan, parent);
+                       __clk_set_parent_after(orphan, parent, NULL);
+                       __clk_recalc_accuracies(orphan);
+                       __clk_recalc_rates(orphan, 0);
+               }
        }
 
        /*
@@ -2491,7 +2499,7 @@ struct clk *__clk_create_clk(struct clk_hw *hw, const char *dev_id,
 
        /* This is to allow this function to be chained to others */
        if (IS_ERR_OR_NULL(hw))
-               return (struct clk *) hw;
+               return ERR_CAST(hw);
 
        clk = kzalloc(sizeof(*clk), GFP_KERNEL);
        if (!clk)
@@ -3186,7 +3194,7 @@ struct clk *__of_clk_get_from_provider(struct of_phandle_args *clkspec,
 {
        struct of_clk_provider *provider;
        struct clk *clk = ERR_PTR(-EPROBE_DEFER);
-       struct clk_hw *hw = ERR_PTR(-EPROBE_DEFER);
+       struct clk_hw *hw;
 
        if (!clkspec)
                return ERR_PTR(-EINVAL);
@@ -3194,12 +3202,13 @@ struct clk *__of_clk_get_from_provider(struct of_phandle_args *clkspec,
        /* Check if we have such a provider in our array */
        mutex_lock(&of_clk_mutex);
        list_for_each_entry(provider, &of_clk_providers, link) {
-               if (provider->node == clkspec->np)
+               if (provider->node == clkspec->np) {
                        hw = __of_clk_get_hw_from_provider(provider, clkspec);
-               if (!IS_ERR(hw)) {
                        clk = __clk_create_clk(hw, dev_id, con_id);
+               }
 
-                       if (!IS_ERR(clk) && !__clk_get(clk)) {
+               if (!IS_ERR(clk)) {
+                       if (!__clk_get(clk)) {
                                __clk_free_clk(clk);
                                clk = ERR_PTR(-ENOENT);
                        }
@@ -3451,6 +3460,10 @@ void __init of_clk_init(const struct of_device_id *matches)
                                        &clk_provider_list, node) {
                        if (force || parent_ready(clk_provider->np)) {
 
+                               /* Don't populate platform devices */
+                               of_node_set_flag(clk_provider->np,
+                                                OF_POPULATED);
+
                                clk_provider->clk_init_cb(clk_provider->np);
                                of_clk_set_defaults(clk_provider->np, true);
 
index 6ed4f8f..9257972 100644 (file)
@@ -860,8 +860,6 @@ static void __init imx7d_clocks_init(struct device_node *ccm_node)
        /* use old gpt clk setting, gpt1 root clk must be twice as gpt counter freq */
        clk_set_parent(clks[IMX7D_GPT1_ROOT_SRC], clks[IMX7D_OSC_24M_CLK]);
 
-       clk_set_parent(clks[IMX7D_ENET_AXI_ROOT_SRC], clks[IMX7D_PLL_ENET_MAIN_250M_CLK]);
-
        /* set uart module clock's parent clock source that must be great then 80MHz */
        clk_set_parent(clks[IMX7D_UART1_ROOT_SRC], clks[IMX7D_OSC_24M_CLK]);
 
index 8e36d22..b736277 100644 (file)
@@ -946,8 +946,4 @@ static struct platform_driver gxbb_driver = {
        },
 };
 
-static int __init gxbb_clkc_init(void)
-{
-       return platform_driver_register(&gxbb_driver);
-}
-device_initcall(gxbb_clkc_init);
+builtin_platform_driver(gxbb_driver);
index 3165da7..fddc8ac 100644 (file)
@@ -24,6 +24,9 @@ config ARMADA_39X_CLK
        bool
        select MVEBU_CLK_COMMON
 
+config ARMADA_37XX_CLK
+       bool
+
 config ARMADA_XP_CLK
        bool
        select MVEBU_CLK_COMMON
index 7172ef6..d9ae97f 100644 (file)
@@ -6,6 +6,9 @@ obj-$(CONFIG_ARMADA_370_CLK)    += armada-370.o
 obj-$(CONFIG_ARMADA_375_CLK)   += armada-375.o
 obj-$(CONFIG_ARMADA_38X_CLK)   += armada-38x.o
 obj-$(CONFIG_ARMADA_39X_CLK)   += armada-39x.o
+obj-$(CONFIG_ARMADA_37XX_CLK)  += armada-37xx-xtal.o
+obj-$(CONFIG_ARMADA_37XX_CLK)  += armada-37xx-tbg.o
+obj-$(CONFIG_ARMADA_37XX_CLK)  += armada-37xx-periph.o
 obj-$(CONFIG_ARMADA_XP_CLK)    += armada-xp.o
 obj-$(CONFIG_ARMADA_AP806_SYSCON) += ap806-system-controller.o
 obj-$(CONFIG_ARMADA_CP110_SYSCON) += cp110-system-controller.o
diff --git a/drivers/clk/mvebu/armada-37xx-periph.c b/drivers/clk/mvebu/armada-37xx-periph.c
new file mode 100644 (file)
index 0000000..5bb13c9
--- /dev/null
@@ -0,0 +1,449 @@
+/*
+ * Marvell Armada 37xx SoC Peripheral clocks
+ *
+ * Copyright (C) 2016 Marvell
+ *
+ * Gregory CLEMENT <gregory.clement@free-electrons.com>
+ *
+ * This file is licensed under the terms of the GNU General Public
+ * License version 2 or later. This program is licensed "as is"
+ * without any warranty of any kind, whether express or implied.
+ *
+ * Most of the peripheral clocks can be modelled like this:
+ *             _____    _______    _______
+ * TBG-A-P  --|     |  |       |  |       |   ______
+ * TBG-B-P  --| Mux |--| /div1 |--| /div2 |--| Gate |--> perip_clk
+ * TBG-A-S  --|     |  |       |  |       |  |______|
+ * TBG-B-S  --|_____|  |_______|  |_______|
+ *
+ * However some clocks may use only one or two block or and use the
+ * xtal clock as parent.
+ */
+
+#include <linux/clk-provider.h>
+#include <linux/of.h>
+#include <linux/of_device.h>
+#include <linux/platform_device.h>
+#include <linux/slab.h>
+
+#define TBG_SEL                0x0
+#define DIV_SEL0       0x4
+#define DIV_SEL1       0x8
+#define DIV_SEL2       0xC
+#define CLK_SEL                0x10
+#define CLK_DIS                0x14
+
+struct clk_periph_driver_data {
+       struct clk_hw_onecell_data *hw_data;
+       spinlock_t lock;
+};
+
+struct clk_double_div {
+       struct clk_hw hw;
+       void __iomem *reg1;
+       u8 shift1;
+       void __iomem *reg2;
+       u8 shift2;
+};
+
+#define to_clk_double_div(_hw) container_of(_hw, struct clk_double_div, hw)
+
+struct clk_periph_data {
+       const char *name;
+       const char * const *parent_names;
+       int num_parents;
+       struct clk_hw *mux_hw;
+       struct clk_hw *rate_hw;
+       struct clk_hw *gate_hw;
+       bool is_double_div;
+};
+
+static const struct clk_div_table clk_table6[] = {
+       { .val = 1, .div = 1, },
+       { .val = 2, .div = 2, },
+       { .val = 3, .div = 3, },
+       { .val = 4, .div = 4, },
+       { .val = 5, .div = 5, },
+       { .val = 6, .div = 6, },
+       { .val = 0, .div = 0, }, /* last entry */
+};
+
+static const struct clk_div_table clk_table1[] = {
+       { .val = 0, .div = 1, },
+       { .val = 1, .div = 2, },
+       { .val = 0, .div = 0, }, /* last entry */
+};
+
+static const struct clk_div_table clk_table2[] = {
+       { .val = 0, .div = 2, },
+       { .val = 1, .div = 4, },
+       { .val = 0, .div = 0, }, /* last entry */
+};
+static const struct clk_ops clk_double_div_ops;
+
+#define PERIPH_GATE(_name, _bit)               \
+struct clk_gate gate_##_name = {               \
+       .reg = (void *)CLK_DIS,                 \
+       .bit_idx = _bit,                        \
+       .hw.init = &(struct clk_init_data){     \
+               .ops =  &clk_gate_ops,          \
+       }                                       \
+};
+
+#define PERIPH_MUX(_name, _shift)              \
+struct clk_mux mux_##_name = {                 \
+       .reg = (void *)TBG_SEL,                 \
+       .shift = _shift,                        \
+       .mask = 3,                              \
+       .hw.init = &(struct clk_init_data){     \
+               .ops =  &clk_mux_ro_ops,        \
+       }                                       \
+};
+
+#define PERIPH_DOUBLEDIV(_name, _reg1, _reg2, _shift1, _shift2)        \
+struct clk_double_div rate_##_name = {         \
+       .reg1 = (void *)_reg1,                  \
+       .reg2 = (void *)_reg2,                  \
+       .shift1 = _shift1,                      \
+       .shift2 = _shift2,                      \
+       .hw.init = &(struct clk_init_data){     \
+               .ops =  &clk_double_div_ops,    \
+       }                                       \
+};
+
+#define PERIPH_DIV(_name, _reg, _shift, _table)        \
+struct clk_divider rate_##_name = {            \
+       .reg = (void *)_reg,                    \
+       .table = _table,                        \
+       .shift = _shift,                        \
+       .hw.init = &(struct clk_init_data){     \
+               .ops =  &clk_divider_ro_ops,    \
+       }                                       \
+};
+
+#define PERIPH_CLK_FULL_DD(_name, _bit, _shift, _reg1, _reg2, _shift1, _shift2)\
+static PERIPH_GATE(_name, _bit);                           \
+static PERIPH_MUX(_name, _shift);                          \
+static PERIPH_DOUBLEDIV(_name, _reg1, _reg2, _shift1, _shift2);
+
+#define PERIPH_CLK_FULL(_name, _bit, _shift, _reg, _shift1, _table)    \
+static PERIPH_GATE(_name, _bit);                           \
+static PERIPH_MUX(_name, _shift);                          \
+static PERIPH_DIV(_name, _reg, _shift1, _table);
+
+#define PERIPH_CLK_GATE_DIV(_name, _bit,  _reg, _shift, _table)        \
+static PERIPH_GATE(_name, _bit);                       \
+static PERIPH_DIV(_name, _reg, _shift, _table);
+
+#define PERIPH_CLK_MUX_DIV(_name, _shift,  _reg, _shift_div, _table)   \
+static PERIPH_MUX(_name, _shift);                          \
+static PERIPH_DIV(_name, _reg, _shift_div, _table);
+
+#define PERIPH_CLK_MUX_DD(_name, _shift, _reg1, _reg2, _shift1, _shift2)\
+static PERIPH_MUX(_name, _shift);                          \
+static PERIPH_DOUBLEDIV(_name, _reg1, _reg2, _shift1, _shift2);
+
+#define REF_CLK_FULL(_name)                            \
+       { .name = #_name,                               \
+         .parent_names = (const char *[]){ "TBG-A-P",  \
+             "TBG-B-P", "TBG-A-S", "TBG-B-S"},         \
+         .num_parents = 4,                             \
+         .mux_hw = &mux_##_name.hw,                    \
+         .gate_hw = &gate_##_name.hw,                  \
+         .rate_hw = &rate_##_name.hw,                  \
+       }
+
+#define REF_CLK_FULL_DD(_name)                         \
+       { .name = #_name,                               \
+         .parent_names = (const char *[]){ "TBG-A-P",  \
+             "TBG-B-P", "TBG-A-S", "TBG-B-S"},         \
+         .num_parents = 4,                             \
+         .mux_hw = &mux_##_name.hw,                    \
+         .gate_hw = &gate_##_name.hw,                  \
+         .rate_hw = &rate_##_name.hw,                  \
+         .is_double_div = true,                        \
+       }
+
+#define REF_CLK_GATE(_name, _parent_name)                      \
+       { .name = #_name,                                       \
+         .parent_names = (const char *[]){ _parent_name},      \
+         .num_parents = 1,                                     \
+         .gate_hw = &gate_##_name.hw,                          \
+       }
+
+#define REF_CLK_GATE_DIV(_name, _parent_name)                  \
+       { .name = #_name,                                       \
+         .parent_names = (const char *[]){ _parent_name},      \
+         .num_parents = 1,                                     \
+         .gate_hw = &gate_##_name.hw,                          \
+         .rate_hw = &rate_##_name.hw,                          \
+       }
+
+#define REF_CLK_MUX_DIV(_name)                         \
+       { .name = #_name,                               \
+         .parent_names = (const char *[]){ "TBG-A-P",  \
+             "TBG-B-P", "TBG-A-S", "TBG-B-S"},         \
+         .num_parents = 4,                             \
+         .mux_hw = &mux_##_name.hw,                    \
+         .rate_hw = &rate_##_name.hw,                  \
+       }
+
+#define REF_CLK_MUX_DD(_name)                          \
+       { .name = #_name,                               \
+         .parent_names = (const char *[]){ "TBG-A-P",  \
+             "TBG-B-P", "TBG-A-S", "TBG-B-S"},         \
+         .num_parents = 4,                             \
+         .mux_hw = &mux_##_name.hw,                    \
+         .rate_hw = &rate_##_name.hw,                  \
+         .is_double_div = true,                        \
+       }
+
+/* NB periph clocks */
+PERIPH_CLK_FULL_DD(mmc, 2, 0, DIV_SEL2, DIV_SEL2, 16, 13);
+PERIPH_CLK_FULL_DD(sata_host, 3, 2, DIV_SEL2, DIV_SEL2, 10, 7);
+PERIPH_CLK_FULL_DD(sec_at, 6, 4, DIV_SEL1, DIV_SEL1, 3, 0);
+PERIPH_CLK_FULL_DD(sec_dap, 7, 6, DIV_SEL1, DIV_SEL1, 9, 6);
+PERIPH_CLK_FULL_DD(tscem, 8, 8, DIV_SEL1, DIV_SEL1, 15, 12);
+PERIPH_CLK_FULL(tscem_tmx, 10, 10, DIV_SEL1, 18, clk_table6);
+static PERIPH_GATE(avs, 11);
+PERIPH_CLK_FULL_DD(pwm, 13, 14, DIV_SEL0, DIV_SEL0, 3, 0);
+PERIPH_CLK_FULL_DD(sqf, 12, 12, DIV_SEL1, DIV_SEL1, 27, 24);
+static PERIPH_GATE(i2c_2, 16);
+static PERIPH_GATE(i2c_1, 17);
+PERIPH_CLK_GATE_DIV(ddr_phy, 19, DIV_SEL0, 18, clk_table2);
+PERIPH_CLK_FULL_DD(ddr_fclk, 21, 16, DIV_SEL0, DIV_SEL0, 15, 12);
+PERIPH_CLK_FULL(trace, 22, 18, DIV_SEL0, 20, clk_table6);
+PERIPH_CLK_FULL(counter, 23, 20, DIV_SEL0, 23, clk_table6);
+PERIPH_CLK_FULL_DD(eip97, 24, 24, DIV_SEL2, DIV_SEL2, 22, 19);
+PERIPH_CLK_MUX_DIV(cpu, 22, DIV_SEL0, 28, clk_table6);
+
+static struct clk_periph_data data_nb[] ={
+       REF_CLK_FULL_DD(mmc),
+       REF_CLK_FULL_DD(sata_host),
+       REF_CLK_FULL_DD(sec_at),
+       REF_CLK_FULL_DD(sec_dap),
+       REF_CLK_FULL_DD(tscem),
+       REF_CLK_FULL(tscem_tmx),
+       REF_CLK_GATE(avs, "xtal"),
+       REF_CLK_FULL_DD(sqf),
+       REF_CLK_FULL_DD(pwm),
+       REF_CLK_GATE(i2c_2, "xtal"),
+       REF_CLK_GATE(i2c_1, "xtal"),
+       REF_CLK_GATE_DIV(ddr_phy, "TBG-A-S"),
+       REF_CLK_FULL_DD(ddr_fclk),
+       REF_CLK_FULL(trace),
+       REF_CLK_FULL(counter),
+       REF_CLK_FULL_DD(eip97),
+       REF_CLK_MUX_DIV(cpu),
+       { },
+};
+
+/* SB periph clocks */
+PERIPH_CLK_MUX_DD(gbe_50, 6, DIV_SEL2, DIV_SEL2, 6, 9);
+PERIPH_CLK_MUX_DD(gbe_core, 8, DIV_SEL1, DIV_SEL1, 18, 21);
+PERIPH_CLK_MUX_DD(gbe_125, 10, DIV_SEL1, DIV_SEL1, 6, 9);
+static PERIPH_GATE(gbe1_50, 0);
+static PERIPH_GATE(gbe0_50, 1);
+static PERIPH_GATE(gbe1_125, 2);
+static PERIPH_GATE(gbe0_125, 3);
+PERIPH_CLK_GATE_DIV(gbe1_core, 4, DIV_SEL1, 13, clk_table1);
+PERIPH_CLK_GATE_DIV(gbe0_core, 5, DIV_SEL1, 14, clk_table1);
+PERIPH_CLK_GATE_DIV(gbe_bm, 12, DIV_SEL1, 0, clk_table1);
+PERIPH_CLK_FULL_DD(sdio, 11, 14, DIV_SEL0, DIV_SEL0, 3, 6);
+PERIPH_CLK_FULL_DD(usb32_usb2_sys, 16, 16, DIV_SEL0, DIV_SEL0, 9, 12);
+PERIPH_CLK_FULL_DD(usb32_ss_sys, 17, 18, DIV_SEL0, DIV_SEL0, 15, 18);
+
+static struct clk_periph_data data_sb[] = {
+       REF_CLK_MUX_DD(gbe_50),
+       REF_CLK_MUX_DD(gbe_core),
+       REF_CLK_MUX_DD(gbe_125),
+       REF_CLK_GATE(gbe1_50, "gbe_50"),
+       REF_CLK_GATE(gbe0_50, "gbe_50"),
+       REF_CLK_GATE(gbe1_125, "gbe_125"),
+       REF_CLK_GATE(gbe0_125, "gbe_125"),
+       REF_CLK_GATE_DIV(gbe1_core, "gbe_core"),
+       REF_CLK_GATE_DIV(gbe0_core, "gbe_core"),
+       REF_CLK_GATE_DIV(gbe_bm, "gbe_core"),
+       REF_CLK_FULL_DD(sdio),
+       REF_CLK_FULL_DD(usb32_usb2_sys),
+       REF_CLK_FULL_DD(usb32_ss_sys),
+       { },
+};
+
+static unsigned int get_div(void __iomem *reg, int shift)
+{
+       u32 val;
+
+       val = (readl(reg) >> shift) & 0x7;
+       if (val > 6)
+               return 0;
+       return val;
+}
+
+static unsigned long clk_double_div_recalc_rate(struct clk_hw *hw,
+               unsigned long parent_rate)
+{
+       struct clk_double_div *double_div = to_clk_double_div(hw);
+       unsigned int div;
+
+       div = get_div(double_div->reg1, double_div->shift1);
+       div *= get_div(double_div->reg2, double_div->shift2);
+
+       return DIV_ROUND_UP_ULL((u64)parent_rate, div);
+}
+
+static const struct clk_ops clk_double_div_ops = {
+       .recalc_rate = clk_double_div_recalc_rate,
+};
+
+static const struct of_device_id armada_3700_periph_clock_of_match[] = {
+       { .compatible = "marvell,armada-3700-periph-clock-nb",
+         .data = data_nb, },
+       { .compatible = "marvell,armada-3700-periph-clock-sb",
+       .data = data_sb, },
+       { }
+};
+static int armada_3700_add_composite_clk(const struct clk_periph_data *data,
+                                        void __iomem *reg, spinlock_t *lock,
+                                        struct device *dev, struct clk_hw *hw)
+{
+       const struct clk_ops *mux_ops = NULL, *gate_ops = NULL,
+               *rate_ops = NULL;
+       struct clk_hw *mux_hw = NULL, *gate_hw = NULL, *rate_hw = NULL;
+
+       if (data->mux_hw) {
+               struct clk_mux *mux;
+
+               mux_hw = data->mux_hw;
+               mux = to_clk_mux(mux_hw);
+               mux->lock = lock;
+               mux_ops = mux_hw->init->ops;
+               mux->reg = reg + (u64)mux->reg;
+       }
+
+       if (data->gate_hw) {
+               struct clk_gate *gate;
+
+               gate_hw = data->gate_hw;
+               gate = to_clk_gate(gate_hw);
+               gate->lock = lock;
+               gate_ops = gate_hw->init->ops;
+               gate->reg = reg + (u64)gate->reg;
+       }
+
+       if (data->rate_hw) {
+               rate_hw = data->rate_hw;
+               rate_ops = rate_hw->init->ops;
+               if (data->is_double_div) {
+                       struct clk_double_div *rate;
+
+                       rate =  to_clk_double_div(rate_hw);
+                       rate->reg1 = reg + (u64)rate->reg1;
+                       rate->reg2 = reg + (u64)rate->reg2;
+               } else {
+                       struct clk_divider *rate = to_clk_divider(rate_hw);
+                       const struct clk_div_table *clkt;
+                       int table_size = 0;
+
+                       rate->reg = reg + (u64)rate->reg;
+                       for (clkt = rate->table; clkt->div; clkt++)
+                               table_size++;
+                       rate->width = order_base_2(table_size);
+                       rate->lock = lock;
+               }
+       }
+
+       hw = clk_hw_register_composite(dev, data->name, data->parent_names,
+                                      data->num_parents, mux_hw,
+                                      mux_ops, rate_hw, rate_ops,
+                                      gate_hw, gate_ops, CLK_IGNORE_UNUSED);
+
+       if (IS_ERR(hw))
+               return PTR_ERR(hw);
+
+       return 0;
+}
+
+static int armada_3700_periph_clock_probe(struct platform_device *pdev)
+{
+       struct clk_periph_driver_data *driver_data;
+       struct device_node *np = pdev->dev.of_node;
+       const struct clk_periph_data *data;
+       struct device *dev = &pdev->dev;
+       int num_periph = 0, i, ret;
+       struct resource *res;
+       void __iomem *reg;
+
+       data = of_device_get_match_data(dev);
+       if (!data)
+               return -ENODEV;
+
+       while (data[num_periph].name)
+               num_periph++;
+
+       res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+       reg = devm_ioremap_resource(dev, res);
+       if (IS_ERR(reg)) {
+               dev_err(dev, "Could not map the periph clock registers\n");
+               return PTR_ERR(reg);
+       }
+
+       driver_data = devm_kzalloc(dev, sizeof(*driver_data), GFP_KERNEL);
+       if (!driver_data)
+               return -ENOMEM;
+
+       driver_data->hw_data = devm_kzalloc(dev, sizeof(*driver_data->hw_data) +
+                           sizeof(*driver_data->hw_data->hws) * num_periph,
+                           GFP_KERNEL);
+       if (!driver_data->hw_data)
+               return -ENOMEM;
+       driver_data->hw_data->num = num_periph;
+
+       spin_lock_init(&driver_data->lock);
+
+       for (i = 0; i < num_periph; i++) {
+               struct clk_hw *hw = driver_data->hw_data->hws[i];
+
+               if (armada_3700_add_composite_clk(&data[i], reg,
+                                                 &driver_data->lock, dev, hw))
+                       dev_err(dev, "Can't register periph clock %s\n",
+                              data[i].name);
+
+       }
+
+       ret = of_clk_add_hw_provider(np, of_clk_hw_onecell_get,
+                                 driver_data->hw_data);
+       if (ret) {
+               for (i = 0; i < num_periph; i++)
+                       clk_hw_unregister(driver_data->hw_data->hws[i]);
+               return ret;
+       }
+
+       platform_set_drvdata(pdev, driver_data);
+       return 0;
+}
+
+static int armada_3700_periph_clock_remove(struct platform_device *pdev)
+{
+       struct clk_periph_driver_data *data = platform_get_drvdata(pdev);
+       struct clk_hw_onecell_data *hw_data = data->hw_data;
+       int i;
+
+       of_clk_del_provider(pdev->dev.of_node);
+
+       for (i = 0; i < hw_data->num; i++)
+               clk_hw_unregister(hw_data->hws[i]);
+
+       return 0;
+}
+
+static struct platform_driver armada_3700_periph_clock_driver = {
+       .probe = armada_3700_periph_clock_probe,
+       .remove = armada_3700_periph_clock_remove,
+       .driver         = {
+               .name   = "marvell-armada-3700-periph-clock",
+               .of_match_table = armada_3700_periph_clock_of_match,
+       },
+};
+
+builtin_platform_driver(armada_3700_periph_clock_driver);
diff --git a/drivers/clk/mvebu/armada-37xx-tbg.c b/drivers/clk/mvebu/armada-37xx-tbg.c
new file mode 100644 (file)
index 0000000..aa80db1
--- /dev/null
@@ -0,0 +1,158 @@
+/*
+ * Marvell Armada 37xx SoC Time Base Generator clocks
+ *
+ * Copyright (C) 2016 Marvell
+ *
+ * Gregory CLEMENT <gregory.clement@free-electrons.com>
+ *
+ * This file is licensed under the terms of the GNU General Public
+ * License version 2 or later. This program is licensed "as is"
+ * without any warranty of any kind, whether express or implied.
+ */
+
+#include <linux/clk-provider.h>
+#include <linux/clk.h>
+#include <linux/of.h>
+#include <linux/of_address.h>
+#include <linux/platform_device.h>
+#include <linux/slab.h>
+
+#define NUM_TBG            4
+
+#define TBG_CTRL0              0x4
+#define TBG_CTRL1              0x8
+#define TBG_CTRL7              0x20
+#define TBG_CTRL8              0x30
+
+#define TBG_DIV_MASK           0x1FF
+
+#define TBG_A_REFDIV           0
+#define TBG_B_REFDIV           16
+
+#define TBG_A_FBDIV            2
+#define TBG_B_FBDIV            18
+
+#define TBG_A_VCODIV_SE                0
+#define TBG_B_VCODIV_SE                16
+
+#define TBG_A_VCODIV_DIFF      1
+#define TBG_B_VCODIV_DIFF      17
+
+struct tbg_def {
+       char *name;
+       u32 refdiv_offset;
+       u32 fbdiv_offset;
+       u32 vcodiv_reg;
+       u32 vcodiv_offset;
+};
+
+static const struct tbg_def tbg[NUM_TBG] = {
+       {"TBG-A-P", TBG_A_REFDIV, TBG_A_FBDIV, TBG_CTRL8, TBG_A_VCODIV_DIFF},
+       {"TBG-B-P", TBG_B_REFDIV, TBG_B_FBDIV, TBG_CTRL8, TBG_B_VCODIV_DIFF},
+       {"TBG-A-S", TBG_A_REFDIV, TBG_A_FBDIV, TBG_CTRL1, TBG_A_VCODIV_SE},
+       {"TBG-B-S", TBG_B_REFDIV, TBG_B_FBDIV, TBG_CTRL1, TBG_B_VCODIV_SE},
+};
+
+static unsigned int tbg_get_mult(void __iomem *reg, const struct tbg_def *ptbg)
+{
+       u32 val;
+
+       val = readl(reg + TBG_CTRL0);
+
+       return ((val >> ptbg->fbdiv_offset) & TBG_DIV_MASK) << 2;
+}
+
+static unsigned int tbg_get_div(void __iomem *reg, const struct tbg_def *ptbg)
+{
+       u32 val;
+       unsigned int div;
+
+       val = readl(reg + TBG_CTRL7);
+
+       div = (val >> ptbg->refdiv_offset) & TBG_DIV_MASK;
+       if (div == 0)
+               div = 1;
+       val = readl(reg + ptbg->vcodiv_reg);
+
+       div *= 1 << ((val >>  ptbg->vcodiv_offset) & TBG_DIV_MASK);
+
+       return div;
+}
+
+
+static int armada_3700_tbg_clock_probe(struct platform_device *pdev)
+{
+       struct device_node *np = pdev->dev.of_node;
+       struct clk_hw_onecell_data *hw_tbg_data;
+       struct device *dev = &pdev->dev;
+       const char *parent_name;
+       struct resource *res;
+       struct clk *parent;
+       void __iomem *reg;
+       int i, ret;
+
+       hw_tbg_data = devm_kzalloc(&pdev->dev, sizeof(*hw_tbg_data)
+                                  + sizeof(*hw_tbg_data->hws) * NUM_TBG,
+                                  GFP_KERNEL);
+       if (!hw_tbg_data)
+               return -ENOMEM;
+       hw_tbg_data->num = NUM_TBG;
+       platform_set_drvdata(pdev, hw_tbg_data);
+
+       parent = devm_clk_get(dev, NULL);
+       if (IS_ERR(parent)) {
+               dev_err(dev, "Could get the clock parent\n");
+               return -EINVAL;
+       }
+       parent_name = __clk_get_name(parent);
+
+       res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+       reg = devm_ioremap_resource(dev, res);
+       if (IS_ERR(reg))
+               return PTR_ERR(reg);
+
+       for (i = 0; i < NUM_TBG; i++) {
+               const char *name;
+               unsigned int mult, div;
+
+               name = tbg[i].name;
+               mult = tbg_get_mult(reg, &tbg[i]);
+               div = tbg_get_div(reg, &tbg[i]);
+               hw_tbg_data->hws[i] = clk_hw_register_fixed_factor(NULL, name,
+                                               parent_name, 0, mult, div);
+               if (IS_ERR(hw_tbg_data->hws[i]))
+                       dev_err(dev, "Can't register TBG clock %s\n", name);
+       }
+
+       ret = of_clk_add_hw_provider(np, of_clk_hw_onecell_get, hw_tbg_data);
+
+       return ret;
+}
+
+static int armada_3700_tbg_clock_remove(struct platform_device *pdev)
+{
+       int i;
+       struct clk_hw_onecell_data *hw_tbg_data = platform_get_drvdata(pdev);
+
+       of_clk_del_provider(pdev->dev.of_node);
+       for (i = 0; i < hw_tbg_data->num; i++)
+               clk_hw_unregister_fixed_factor(hw_tbg_data->hws[i]);
+
+       return 0;
+}
+
+static const struct of_device_id armada_3700_tbg_clock_of_match[] = {
+       { .compatible = "marvell,armada-3700-tbg-clock", },
+       { }
+};
+
+static struct platform_driver armada_3700_tbg_clock_driver = {
+       .probe = armada_3700_tbg_clock_probe,
+       .remove = armada_3700_tbg_clock_remove,
+       .driver         = {
+               .name   = "marvell-armada-3700-tbg-clock",
+               .of_match_table = armada_3700_tbg_clock_of_match,
+       },
+};
+
+builtin_platform_driver(armada_3700_tbg_clock_driver);
diff --git a/drivers/clk/mvebu/armada-37xx-xtal.c b/drivers/clk/mvebu/armada-37xx-xtal.c
new file mode 100644 (file)
index 0000000..612d65e
--- /dev/null
@@ -0,0 +1,91 @@
+/*
+ * Marvell Armada 37xx SoC xtal clocks
+ *
+ * Copyright (C) 2016 Marvell
+ *
+ * Gregory CLEMENT <gregory.clement@free-electrons.com>
+ *
+ * This file is licensed under the terms of the GNU General Public
+ * License version 2.  This program is licensed "as is" without any
+ * warranty of any kind, whether express or implied.
+ */
+
+#include <linux/clk-provider.h>
+#include <linux/mfd/syscon.h>
+#include <linux/platform_device.h>
+#include <linux/regmap.h>
+
+#define NB_GPIO1_LATCH 0xC
+#define XTAL_MODE          BIT(31)
+
+static int armada_3700_xtal_clock_probe(struct platform_device *pdev)
+{
+       struct device_node *np = pdev->dev.of_node;
+       const char *xtal_name = "xtal";
+       struct device_node *parent;
+       struct regmap *regmap;
+       struct clk_hw *xtal_hw;
+       unsigned int rate;
+       u32 reg;
+       int ret;
+
+       xtal_hw = devm_kzalloc(&pdev->dev, sizeof(*xtal_hw), GFP_KERNEL);
+       if (!xtal_hw)
+               return -ENOMEM;
+
+       platform_set_drvdata(pdev, xtal_hw);
+
+       parent = np->parent;
+       if (!parent) {
+               dev_err(&pdev->dev, "no parent\n");
+               return -ENODEV;
+       }
+
+       regmap = syscon_node_to_regmap(parent);
+       if (IS_ERR(regmap)) {
+               dev_err(&pdev->dev, "cannot get regmap\n");
+               return PTR_ERR(regmap);
+       }
+
+       ret = regmap_read(regmap, NB_GPIO1_LATCH, &reg);
+       if (ret) {
+               dev_err(&pdev->dev, "cannot read from regmap\n");
+               return ret;
+       }
+
+       if (reg & XTAL_MODE)
+               rate = 40000000;
+       else
+               rate = 25000000;
+
+       of_property_read_string_index(np, "clock-output-names", 0, &xtal_name);
+       xtal_hw = clk_hw_register_fixed_rate(NULL, xtal_name, NULL, 0, rate);
+       if (IS_ERR(xtal_hw))
+               return PTR_ERR(xtal_hw);
+       ret = of_clk_add_hw_provider(np, of_clk_hw_simple_get, xtal_hw);
+
+       return ret;
+}
+
+static int armada_3700_xtal_clock_remove(struct platform_device *pdev)
+{
+       of_clk_del_provider(pdev->dev.of_node);
+
+       return 0;
+}
+
+static const struct of_device_id armada_3700_xtal_clock_of_match[] = {
+       { .compatible = "marvell,armada-3700-xtal-clock", },
+       { }
+};
+
+static struct platform_driver armada_3700_xtal_clock_driver = {
+       .probe = armada_3700_xtal_clock_probe,
+       .remove = armada_3700_xtal_clock_remove,
+       .driver         = {
+               .name   = "marvell-armada-3700-xtal-clock",
+               .of_match_table = armada_3700_xtal_clock_of_match,
+       },
+};
+
+builtin_platform_driver(armada_3700_xtal_clock_driver);
index efb974d..4fdfd32 100644 (file)
@@ -142,6 +142,8 @@ static const struct clk_gating_soc_desc armada_39x_gating_desc[] __initconst = {
        { "pex3", NULL, 7 },
        { "pex0", NULL, 8 },
        { "usb3h0", NULL, 9 },
+       { "usb3h1", NULL, 10 },
+       { "sata0", NULL, 15 },
        { "sdio", NULL, 17 },
        { "xor0", NULL, 22 },
        { "xor1", NULL, 28 },
index 9e35749..c6e802e 100644 (file)
@@ -184,7 +184,8 @@ static void __init lpc18xx_creg_clk_init(struct device_node *np)
 
        of_clk_add_provider(np, of_clk_src_onecell_get, &clk_creg_early_data);
 }
-CLK_OF_DECLARE(lpc18xx_creg_clk, "nxp,lpc1850-creg-clk", lpc18xx_creg_clk_init);
+CLK_OF_DECLARE_DRIVER(lpc18xx_creg_clk, "nxp,lpc1850-creg-clk",
+                     lpc18xx_creg_clk_init);
 
 static struct clk *clk_creg[CREG_CLK_MAX];
 static struct clk_onecell_data clk_creg_data = {
index d359c92..e38bf60 100644 (file)
@@ -69,6 +69,7 @@ static const struct cpg_core_clk r8a7795_core_clks[] __initconst = {
        DEF_FIXED(".s1",        CLK_S1,            CLK_PLL1_DIV2,  3, 1),
        DEF_FIXED(".s2",        CLK_S2,            CLK_PLL1_DIV2,  4, 1),
        DEF_FIXED(".s3",        CLK_S3,            CLK_PLL1_DIV2,  6, 1),
+       DEF_FIXED(".sdsrc",     CLK_SDSRC,         CLK_PLL1_DIV2,  2, 1),
 
        /* Core Clock Outputs */
        DEF_FIXED("ztr",        R8A7795_CLK_ZTR,   CLK_PLL1_DIV2,  6, 1),
@@ -87,10 +88,10 @@ static const struct cpg_core_clk r8a7795_core_clks[] __initconst = {
        DEF_FIXED("s3d2",       R8A7795_CLK_S3D2,  CLK_S3,         2, 1),
        DEF_FIXED("s3d4",       R8A7795_CLK_S3D4,  CLK_S3,         4, 1),
 
-       DEF_GEN3_SD("sd0",      R8A7795_CLK_SD0,   CLK_PLL1_DIV2, 0x0074),
-       DEF_GEN3_SD("sd1",      R8A7795_CLK_SD1,   CLK_PLL1_DIV2, 0x0078),
-       DEF_GEN3_SD("sd2",      R8A7795_CLK_SD2,   CLK_PLL1_DIV2, 0x0268),
-       DEF_GEN3_SD("sd3",      R8A7795_CLK_SD3,   CLK_PLL1_DIV2, 0x026c),
+       DEF_GEN3_SD("sd0",      R8A7795_CLK_SD0,   CLK_SDSRC,     0x0074),
+       DEF_GEN3_SD("sd1",      R8A7795_CLK_SD1,   CLK_SDSRC,     0x0078),
+       DEF_GEN3_SD("sd2",      R8A7795_CLK_SD2,   CLK_SDSRC,     0x0268),
+       DEF_GEN3_SD("sd3",      R8A7795_CLK_SD3,   CLK_SDSRC,     0x026c),
 
        DEF_FIXED("cl",         R8A7795_CLK_CL,    CLK_PLL1_DIV2, 48, 1),
        DEF_FIXED("cp",         R8A7795_CLK_CP,    CLK_EXTAL,      2, 1),
index fc17b52..51d4bac 100644 (file)
@@ -31,7 +31,7 @@ void ccu_helper_wait_for_lock(struct ccu_common *common, u32 lock)
                return;
 
        WARN_ON(readl_relaxed_poll_timeout(common->base + common->reg, reg,
-                                          !(reg & lock), 100, 70000));
+                                          reg & lock, 100, 70000));
 }
 
 int sunxi_ccu_probe(struct device_node *node, void __iomem *reg,
index b38d71c..e54266c 100644 (file)
@@ -91,7 +91,8 @@ static void __init sun4i_a10_mod0_setup(struct device_node *node)
        sunxi_factors_register(node, &sun4i_a10_mod0_data,
                               &sun4i_a10_mod0_lock, reg);
 }
-CLK_OF_DECLARE(sun4i_a10_mod0, "allwinner,sun4i-a10-mod0-clk", sun4i_a10_mod0_setup);
+CLK_OF_DECLARE_DRIVER(sun4i_a10_mod0, "allwinner,sun4i-a10-mod0-clk",
+                     sun4i_a10_mod0_setup);
 
 static int sun4i_a10_mod0_clk_probe(struct platform_device *pdev)
 {
index a5666e1..ea1eed2 100644 (file)
@@ -82,8 +82,8 @@ err_unmap:
        of_address_to_resource(node, 0, &res);
        release_mem_region(res.start, resource_size(&res));
 }
-CLK_OF_DECLARE(sun8i_a23_apb0, "allwinner,sun8i-a23-apb0-clk",
-              sun8i_a23_apb0_setup);
+CLK_OF_DECLARE_DRIVER(sun8i_a23_apb0, "allwinner,sun8i-a23-apb0-clk",
+                     sun8i_a23_apb0_setup);
 
 static int sun8i_a23_apb0_clk_probe(struct platform_device *pdev)
 {
diff --git a/include/dt-bindings/clock/maxim,max77620.h b/include/dt-bindings/clock/maxim,max77620.h
new file mode 100644 (file)
index 0000000..82aba28
--- /dev/null
@@ -0,0 +1,21 @@
+/*
+ * Copyright (C) 2016 NVIDIA CORPORATION. All rights reserved.
+ *
+ * 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.
+ *
+ * Device Tree binding constants clocks for the Maxim 77620 PMIC.
+ */
+
+#ifndef _DT_BINDINGS_CLOCK_MAXIM_MAX77620_CLOCK_H
+#define _DT_BINDINGS_CLOCK_MAXIM_MAX77620_CLOCK_H
+
+/* Fixed rate clocks. */
+
+#define MAX77620_CLK_32K_OUT0          0
+
+/* Total number of clocks. */
+#define MAX77620_CLKS_NUM              (MAX77620_CLK_32K_OUT0 + 1)
+
+#endif /* _DT_BINDINGS_CLOCK_MAXIM_MAX77620_CLOCK_H */
index a39c0c5..f403b8a 100644 (file)
@@ -780,6 +780,18 @@ extern struct of_device_id __clk_of_table;
 
 #define CLK_OF_DECLARE(name, compat, fn) OF_DECLARE_1(clk, name, compat, fn)
 
+/*
+ * Use this macro when you have a driver that requires two initialization
+ * routines, one at of_clk_init(), and one at platform device probe
+ */
+#define CLK_OF_DECLARE_DRIVER(name, compat, fn) \
+       static void name##_of_clk_init_driver(struct device_node *np)   \
+       {                                                               \
+               of_node_clear_flag(np, OF_POPULATED);                   \
+               fn(np);                                                 \
+       }                                                               \
+       OF_DECLARE_1(clk, name, compat, name##_of_clk_init_driver)
+
 #ifdef CONFIG_OF
 int of_clk_add_provider(struct device_node *np,
                        struct clk *(*clk_src_get)(struct of_phandle_args *args,