Browse Source

Merge branches 'clk-allwinner', 'clk-rockchip', 'clk-tegra', 'clk-berlin' and 'clk-qcom-mmagic' into clk-next

* clk-allwinner:
  clk: sunxi-ng: r40: export a regmap to access the GMAC register
  clk: sunxi-ng: r40: rewrite init code to a platform driver
  clk: sunxi-ng: add support for H6 PRCM CCU

* clk-rockchip:
  clk: rockchip: remove deprecated gate-clk code and dt-binding
  clk: rockchip: use match_string() helper

* clk-tegra:
  clk: tegra: Add quirk for getting CDEV1/2 clocks on Tegra20
  clk: tegra20: Correct parents of CDEV1/2 clocks
  clk: tegra20: Add DEV1/DEV2 OSC dividers

* clk-berlin:
  clk: berlin: switch to SPDX license identifier

* clk-qcom-mmagic:
  clk: qcom: mmcc-msm8996: leave all mmagic gdscs and clocks always enabled
  clk: qcom: Register the gdscs before the clocks
  clk: qcom: gdsc: Add support for ALWAYS_ON gdscs
Stephen Boyd 7 years ago

+ 0 - 77
Documentation/devicetree/bindings/clock/rockchip.txt

@@ -1,77 +0,0 @@
-Device Tree Clock bindings for arch-rockchip
-
-This binding uses the common clock binding[1].
-
-[1] Documentation/devicetree/bindings/clock/clock-bindings.txt
-
-== Gate clocks ==
-
-These bindings are deprecated!
-Please use the soc specific CRU bindings instead.
-
-The gate registers form a continuos block which makes the dt node
-structure a matter of taste, as either all gates can be put into
-one gate clock spanning all registers or they can be divided into
-the 10 individual gates containing 16 clocks each.
-The code supports both approaches.
-
-Required properties:
-- compatible : "rockchip,rk2928-gate-clk"
-- reg : shall be the control register address(es) for the clock.
-- #clock-cells : from common clock binding; shall be set to 1
-- clock-output-names : the corresponding gate names that the clock controls
-- clocks : should contain the parent clock for each individual gate,
-  therefore the number of clocks elements should match the number of
-  clock-output-names
-
-Example using multiple gate clocks:
-
-		clk_gates0: gate-clk@200000d0 {
-			compatible = "rockchip,rk2928-gate-clk";
-			reg = <0x200000d0 0x4>;
-			clocks = <&dummy>, <&dummy>,
-				 <&dummy>, <&dummy>,
-				 <&dummy>, <&dummy>,
-				 <&dummy>, <&dummy>,
-				 <&dummy>, <&dummy>,
-				 <&dummy>, <&dummy>,
-				 <&dummy>, <&dummy>,
-				 <&dummy>, <&dummy>;
-
-			clock-output-names =
-				"gate_core_periph", "gate_cpu_gpll",
-				"gate_ddrphy", "gate_aclk_cpu",
-				"gate_hclk_cpu", "gate_pclk_cpu",
-				"gate_atclk_cpu", "gate_i2s0",
-				"gate_i2s0_frac", "gate_i2s1",
-				"gate_i2s1_frac", "gate_i2s2",
-				"gate_i2s2_frac", "gate_spdif",
-				"gate_spdif_frac", "gate_testclk";
-
-			#clock-cells = <1>;
-		};
-
-		clk_gates1: gate-clk@200000d4 {
-			compatible = "rockchip,rk2928-gate-clk";
-			reg = <0x200000d4 0x4>;
-			clocks = <&xin24m>, <&xin24m>,
-				 <&xin24m>, <&dummy>,
-				 <&dummy>, <&xin24m>,
-				 <&xin24m>, <&dummy>,
-				 <&xin24m>, <&dummy>,
-				 <&xin24m>, <&dummy>,
-				 <&xin24m>, <&dummy>,
-				 <&xin24m>, <&dummy>;
-
-			clock-output-names =
-				"gate_timer0", "gate_timer1",
-				"gate_timer2", "gate_jtag",
-				"gate_aclk_lcdc1_src", "gate_otgphy0",
-				"gate_otgphy1", "gate_ddr_gpll",
-				"gate_uart0", "gate_frac_uart0",
-				"gate_uart1", "gate_frac_uart1",
-				"gate_uart2", "gate_frac_uart2",
-				"gate_uart3", "gate_frac_uart3";
-
-			#clock-cells = <1>;
-		};

+ 2 - 1
Documentation/devicetree/bindings/clock/sunxi-ccu.txt

@@ -21,6 +21,7 @@ Required properties :
 		- "allwinner,sun50i-a64-r-ccu"
 		- "allwinner,sun50i-a64-r-ccu"
 		- "allwinner,sun50i-h5-ccu"
 		- "allwinner,sun50i-h5-ccu"
 		- "allwinner,sun50i-h6-ccu"
 		- "allwinner,sun50i-h6-ccu"
+		- "allwinner,sun50i-h6-r-ccu"
 		- "nextthing,gr8-ccu"
 		- "nextthing,gr8-ccu"
 
 
 - reg: Must contain the registers base address and length
 - reg: Must contain the registers base address and length
@@ -35,7 +36,7 @@ Required properties :
 For the main CCU on H6, one more clock is needed:
 For the main CCU on H6, one more clock is needed:
 - "iosc": the SoC's internal frequency oscillator
 - "iosc": the SoC's internal frequency oscillator
 
 
-For the PRCM CCUs on A83T/H3/A64, two more clocks are needed:
+For the PRCM CCUs on A83T/H3/A64/H6, two more clocks are needed:
 - "pll-periph": the SoC's peripheral PLL from the main CCU
 - "pll-periph": the SoC's peripheral PLL from the main CCU
 - "iosc": the SoC's internal frequency oscillator
 - "iosc": the SoC's internal frequency oscillator
 
 

+ 1 - 12
drivers/clk/berlin/berlin2-avpll.c

@@ -1,20 +1,9 @@
+// SPDX-License-Identifier: GPL-2.0
 /*
 /*
  * Copyright (c) 2014 Marvell Technology Group Ltd.
  * Copyright (c) 2014 Marvell Technology Group Ltd.
  *
  *
  * Sebastian Hesselbarth <sebastian.hesselbarth@gmail.com>
  * Sebastian Hesselbarth <sebastian.hesselbarth@gmail.com>
  * Alexandre Belloni <alexandre.belloni@free-electrons.com>
  * Alexandre Belloni <alexandre.belloni@free-electrons.com>
- *
- * This program is free software; you can redistribute it and/or modify it
- * under the terms and conditions of the GNU General Public License,
- * version 2, as published by the Free Software Foundation.
- *
- * This program is distributed in the hope it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
- * more details.
- *
- * You should have received a copy of the GNU General Public License along with
- * this program.  If not, see <http://www.gnu.org/licenses/>.
  */
  */
 #include <linux/clk-provider.h>
 #include <linux/clk-provider.h>
 #include <linux/io.h>
 #include <linux/io.h>

+ 1 - 12
drivers/clk/berlin/berlin2-avpll.h

@@ -1,20 +1,9 @@
+/* SPDX-License-Identifier: GPL-2.0 */
 /*
 /*
  * Copyright (c) 2014 Marvell Technology Group Ltd.
  * Copyright (c) 2014 Marvell Technology Group Ltd.
  *
  *
  * Sebastian Hesselbarth <sebastian.hesselbarth@gmail.com>
  * Sebastian Hesselbarth <sebastian.hesselbarth@gmail.com>
  * Alexandre Belloni <alexandre.belloni@free-electrons.com>
  * Alexandre Belloni <alexandre.belloni@free-electrons.com>
- *
- * This program is free software; you can redistribute it and/or modify it
- * under the terms and conditions of the GNU General Public License,
- * version 2, as published by the Free Software Foundation.
- *
- * This program is distributed in the hope it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
- * more details.
- *
- * You should have received a copy of the GNU General Public License along with
- * this program.  If not, see <http://www.gnu.org/licenses/>.
  */
  */
 #ifndef __BERLIN2_AVPLL_H
 #ifndef __BERLIN2_AVPLL_H
 #define __BERLIN2_AVPLL_H
 #define __BERLIN2_AVPLL_H

+ 1 - 12
drivers/clk/berlin/berlin2-div.c

@@ -1,20 +1,9 @@
+// SPDX-License-Identifier: GPL-2.0
 /*
 /*
  * Copyright (c) 2014 Marvell Technology Group Ltd.
  * Copyright (c) 2014 Marvell Technology Group Ltd.
  *
  *
  * Alexandre Belloni <alexandre.belloni@free-electrons.com>
  * Alexandre Belloni <alexandre.belloni@free-electrons.com>
  * Sebastian Hesselbarth <sebastian.hesselbarth@gmail.com>
  * Sebastian Hesselbarth <sebastian.hesselbarth@gmail.com>
- *
- * This program is free software; you can redistribute it and/or modify it
- * under the terms and conditions of the GNU General Public License,
- * version 2, as published by the Free Software Foundation.
- *
- * This program is distributed in the hope it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
- * more details.
- *
- * You should have received a copy of the GNU General Public License along with
- * this program.  If not, see <http://www.gnu.org/licenses/>.
  */
  */
 #include <linux/bitops.h>
 #include <linux/bitops.h>
 #include <linux/clk-provider.h>
 #include <linux/clk-provider.h>

+ 1 - 12
drivers/clk/berlin/berlin2-div.h

@@ -1,20 +1,9 @@
+/* SPDX-License-Identifier: GPL-2.0 */
 /*
 /*
  * Copyright (c) 2014 Marvell Technology Group Ltd.
  * Copyright (c) 2014 Marvell Technology Group Ltd.
  *
  *
  * Alexandre Belloni <alexandre.belloni@free-electrons.com>
  * Alexandre Belloni <alexandre.belloni@free-electrons.com>
  * Sebastian Hesselbarth <sebastian.hesselbarth@gmail.com>
  * Sebastian Hesselbarth <sebastian.hesselbarth@gmail.com>
- *
- * This program is free software; you can redistribute it and/or modify it
- * under the terms and conditions of the GNU General Public License,
- * version 2, as published by the Free Software Foundation.
- *
- * This program is distributed in the hope it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
- * more details.
- *
- * You should have received a copy of the GNU General Public License along with
- * this program.  If not, see <http://www.gnu.org/licenses/>.
  */
  */
 #ifndef __BERLIN2_DIV_H
 #ifndef __BERLIN2_DIV_H
 #define __BERLIN2_DIV_H
 #define __BERLIN2_DIV_H

+ 1 - 12
drivers/clk/berlin/berlin2-pll.c

@@ -1,20 +1,9 @@
+// SPDX-License-Identifier: GPL-2.0
 /*
 /*
  * Copyright (c) 2014 Marvell Technology Group Ltd.
  * Copyright (c) 2014 Marvell Technology Group Ltd.
  *
  *
  * Alexandre Belloni <alexandre.belloni@free-electrons.com>
  * Alexandre Belloni <alexandre.belloni@free-electrons.com>
  * Sebastian Hesselbarth <sebastian.hesselbarth@gmail.com>
  * Sebastian Hesselbarth <sebastian.hesselbarth@gmail.com>
- *
- * This program is free software; you can redistribute it and/or modify it
- * under the terms and conditions of the GNU General Public License,
- * version 2, as published by the Free Software Foundation.
- *
- * This program is distributed in the hope it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
- * more details.
- *
- * You should have received a copy of the GNU General Public License along with
- * this program.  If not, see <http://www.gnu.org/licenses/>.
  */
  */
 #include <linux/clk-provider.h>
 #include <linux/clk-provider.h>
 #include <linux/io.h>
 #include <linux/io.h>

+ 1 - 12
drivers/clk/berlin/berlin2-pll.h

@@ -1,20 +1,9 @@
+/* SPDX-License-Identifier: GPL-2.0 */
 /*
 /*
  * Copyright (c) 2014 Marvell Technology Group Ltd.
  * Copyright (c) 2014 Marvell Technology Group Ltd.
  *
  *
  * Alexandre Belloni <alexandre.belloni@free-electrons.com>
  * Alexandre Belloni <alexandre.belloni@free-electrons.com>
  * Sebastian Hesselbarth <sebastian.hesselbarth@gmail.com>
  * Sebastian Hesselbarth <sebastian.hesselbarth@gmail.com>
- *
- * This program is free software; you can redistribute it and/or modify it
- * under the terms and conditions of the GNU General Public License,
- * version 2, as published by the Free Software Foundation.
- *
- * This program is distributed in the hope it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
- * more details.
- *
- * You should have received a copy of the GNU General Public License along with
- * this program.  If not, see <http://www.gnu.org/licenses/>.
  */
  */
 #ifndef __BERLIN2_PLL_H
 #ifndef __BERLIN2_PLL_H
 #define __BERLIN2_PLL_H
 #define __BERLIN2_PLL_H

+ 1 - 12
drivers/clk/berlin/bg2.c

@@ -1,20 +1,9 @@
+// SPDX-License-Identifier: GPL-2.0
 /*
 /*
  * Copyright (c) 2014 Marvell Technology Group Ltd.
  * Copyright (c) 2014 Marvell Technology Group Ltd.
  *
  *
  * Sebastian Hesselbarth <sebastian.hesselbarth@gmail.com>
  * Sebastian Hesselbarth <sebastian.hesselbarth@gmail.com>
  * Alexandre Belloni <alexandre.belloni@free-electrons.com>
  * Alexandre Belloni <alexandre.belloni@free-electrons.com>
- *
- * This program is free software; you can redistribute it and/or modify it
- * under the terms and conditions of the GNU General Public License,
- * version 2, as published by the Free Software Foundation.
- *
- * This program is distributed in the hope it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
- * more details.
- *
- * You should have received a copy of the GNU General Public License along with
- * this program.  If not, see <http://www.gnu.org/licenses/>.
  */
  */
 
 
 #include <linux/clk.h>
 #include <linux/clk.h>

+ 1 - 12
drivers/clk/berlin/bg2q.c

@@ -1,20 +1,9 @@
+// SPDX-License-Identifier: GPL-2.0
 /*
 /*
  * Copyright (c) 2014 Marvell Technology Group Ltd.
  * Copyright (c) 2014 Marvell Technology Group Ltd.
  *
  *
  * Alexandre Belloni <alexandre.belloni@free-electrons.com>
  * Alexandre Belloni <alexandre.belloni@free-electrons.com>
  * Sebastian Hesselbarth <sebastian.hesselbarth@gmail.com>
  * Sebastian Hesselbarth <sebastian.hesselbarth@gmail.com>
- *
- * This program is free software; you can redistribute it and/or modify it
- * under the terms and conditions of the GNU General Public License,
- * version 2, as published by the Free Software Foundation.
- *
- * This program is distributed in the hope it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
- * more details.
- *
- * You should have received a copy of the GNU General Public License along with
- * this program.  If not, see <http://www.gnu.org/licenses/>.
  */
  */
 
 
 #include <linux/clk.h>
 #include <linux/clk.h>

+ 1 - 12
drivers/clk/berlin/common.h

@@ -1,20 +1,9 @@
+/* SPDX-License-Identifier: GPL-2.0 */
 /*
 /*
  * Copyright (c) 2014 Marvell Technology Group Ltd.
  * Copyright (c) 2014 Marvell Technology Group Ltd.
  *
  *
  * Sebastian Hesselbarth <sebastian.hesselbarth@gmail.com>
  * Sebastian Hesselbarth <sebastian.hesselbarth@gmail.com>
  * Alexandre Belloni <alexandre.belloni@free-electrons.com>
  * Alexandre Belloni <alexandre.belloni@free-electrons.com>
- *
- * This program is free software; you can redistribute it and/or modify it
- * under the terms and conditions of the GNU General Public License,
- * version 2, as published by the Free Software Foundation.
- *
- * This program is distributed in the hope it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
- * more details.
- *
- * You should have received a copy of the GNU General Public License along with
- * this program.  If not, see <http://www.gnu.org/licenses/>.
  */
  */
 #ifndef __BERLIN2_COMMON_H
 #ifndef __BERLIN2_COMMON_H
 #define __BERLIN2_COMMON_H
 #define __BERLIN2_COMMON_H

+ 16 - 16
drivers/clk/qcom/common.c

@@ -228,22 +228,6 @@ int qcom_cc_really_probe(struct platform_device *pdev,
 	if (!cc)
 	if (!cc)
 		return -ENOMEM;
 		return -ENOMEM;
 
 
-	cc->rclks = rclks;
-	cc->num_rclks = num_clks;
-
-	for (i = 0; i < num_clks; i++) {
-		if (!rclks[i])
-			continue;
-
-		ret = devm_clk_register_regmap(dev, rclks[i]);
-		if (ret)
-			return ret;
-	}
-
-	ret = devm_of_clk_add_hw_provider(dev, qcom_cc_clk_hw_get, cc);
-	if (ret)
-		return ret;
-
 	reset = &cc->reset;
 	reset = &cc->reset;
 	reset->rcdev.of_node = dev->of_node;
 	reset->rcdev.of_node = dev->of_node;
 	reset->rcdev.ops = &qcom_reset_ops;
 	reset->rcdev.ops = &qcom_reset_ops;
@@ -272,6 +256,22 @@ int qcom_cc_really_probe(struct platform_device *pdev,
 			return ret;
 			return ret;
 	}
 	}
 
 
+	cc->rclks = rclks;
+	cc->num_rclks = num_clks;
+
+	for (i = 0; i < num_clks; i++) {
+		if (!rclks[i])
+			continue;
+
+		ret = devm_clk_register_regmap(dev, rclks[i]);
+		if (ret)
+			return ret;
+	}
+
+	ret = devm_of_clk_add_hw_provider(dev, qcom_cc_clk_hw_get, cc);
+	if (ret)
+		return ret;
+
 	return 0;
 	return 0;
 }
 }
 EXPORT_SYMBOL_GPL(qcom_cc_really_probe);
 EXPORT_SYMBOL_GPL(qcom_cc_really_probe);

+ 1 - 1
drivers/clk/qcom/gcc-msm8996.c

@@ -3105,7 +3105,7 @@ static struct gdsc aggre0_noc_gdsc = {
 		.name = "aggre0_noc",
 		.name = "aggre0_noc",
 	},
 	},
 	.pwrsts = PWRSTS_OFF_ON,
 	.pwrsts = PWRSTS_OFF_ON,
-	.flags = VOTABLE,
+	.flags = VOTABLE | ALWAYS_ON,
 };
 };
 
 
 static struct gdsc hlos1_vote_aggre0_noc_gdsc = {
 static struct gdsc hlos1_vote_aggre0_noc_gdsc = {

+ 8 - 0
drivers/clk/qcom/gdsc.c

@@ -291,6 +291,14 @@ static int gdsc_init(struct gdsc *sc)
 	if ((sc->flags & VOTABLE) && on)
 	if ((sc->flags & VOTABLE) && on)
 		gdsc_enable(&sc->pd);
 		gdsc_enable(&sc->pd);
 
 
+	/* If ALWAYS_ON GDSCs are not ON, turn them ON */
+	if (sc->flags & ALWAYS_ON) {
+		if (!on)
+			gdsc_enable(&sc->pd);
+		on = true;
+		sc->pd.flags |= GENPD_FLAG_ALWAYS_ON;
+	}
+
 	if (on || (sc->pwrsts & PWRSTS_RET))
 	if (on || (sc->pwrsts & PWRSTS_RET))
 		gdsc_force_mem_on(sc);
 		gdsc_force_mem_on(sc);
 	else
 	else

+ 1 - 0
drivers/clk/qcom/gdsc.h

@@ -53,6 +53,7 @@ struct gdsc {
 #define VOTABLE		BIT(0)
 #define VOTABLE		BIT(0)
 #define CLAMP_IO	BIT(1)
 #define CLAMP_IO	BIT(1)
 #define HW_CTRL		BIT(2)
 #define HW_CTRL		BIT(2)
+#define ALWAYS_ON	BIT(3)
 	struct reset_controller_dev	*rcdev;
 	struct reset_controller_dev	*rcdev;
 	unsigned int			*resets;
 	unsigned int			*resets;
 	unsigned int			reset_count;
 	unsigned int			reset_count;

+ 11 - 11
drivers/clk/qcom/mmcc-msm8996.c

@@ -1245,7 +1245,7 @@ static struct clk_branch mmss_mmagic_ahb_clk = {
 			.name = "mmss_mmagic_ahb_clk",
 			.name = "mmss_mmagic_ahb_clk",
 			.parent_names = (const char *[]){ "ahb_clk_src" },
 			.parent_names = (const char *[]){ "ahb_clk_src" },
 			.num_parents = 1,
 			.num_parents = 1,
-			.flags = CLK_SET_RATE_PARENT | CLK_IGNORE_UNUSED,
+			.flags = CLK_SET_RATE_PARENT | CLK_IS_CRITICAL,
 			.ops = &clk_branch2_ops,
 			.ops = &clk_branch2_ops,
 		},
 		},
 	},
 	},
@@ -1260,7 +1260,7 @@ static struct clk_branch mmss_mmagic_cfg_ahb_clk = {
 			.name = "mmss_mmagic_cfg_ahb_clk",
 			.name = "mmss_mmagic_cfg_ahb_clk",
 			.parent_names = (const char *[]){ "ahb_clk_src" },
 			.parent_names = (const char *[]){ "ahb_clk_src" },
 			.num_parents = 1,
 			.num_parents = 1,
-			.flags = CLK_SET_RATE_PARENT,
+			.flags = CLK_SET_RATE_PARENT | CLK_IS_CRITICAL,
 			.ops = &clk_branch2_ops,
 			.ops = &clk_branch2_ops,
 		},
 		},
 	},
 	},
@@ -1319,7 +1319,7 @@ static struct clk_branch mmagic_camss_axi_clk = {
 			.name = "mmagic_camss_axi_clk",
 			.name = "mmagic_camss_axi_clk",
 			.parent_names = (const char *[]){ "axi_clk_src" },
 			.parent_names = (const char *[]){ "axi_clk_src" },
 			.num_parents = 1,
 			.num_parents = 1,
-			.flags = CLK_SET_RATE_PARENT,
+			.flags = CLK_SET_RATE_PARENT | CLK_IS_CRITICAL,
 			.ops = &clk_branch2_ops,
 			.ops = &clk_branch2_ops,
 		},
 		},
 	},
 	},
@@ -1334,7 +1334,7 @@ static struct clk_branch mmagic_camss_noc_cfg_ahb_clk = {
 			.name = "mmagic_camss_noc_cfg_ahb_clk",
 			.name = "mmagic_camss_noc_cfg_ahb_clk",
 			.parent_names = (const char *[]){ "gcc_mmss_noc_cfg_ahb_clk" },
 			.parent_names = (const char *[]){ "gcc_mmss_noc_cfg_ahb_clk" },
 			.num_parents = 1,
 			.num_parents = 1,
-			.flags = CLK_SET_RATE_PARENT,
+			.flags = CLK_SET_RATE_PARENT | CLK_IS_CRITICAL,
 			.ops = &clk_branch2_ops,
 			.ops = &clk_branch2_ops,
 		},
 		},
 	},
 	},
@@ -1439,7 +1439,7 @@ static struct clk_branch mmagic_mdss_axi_clk = {
 			.name = "mmagic_mdss_axi_clk",
 			.name = "mmagic_mdss_axi_clk",
 			.parent_names = (const char *[]){ "axi_clk_src" },
 			.parent_names = (const char *[]){ "axi_clk_src" },
 			.num_parents = 1,
 			.num_parents = 1,
-			.flags = CLK_SET_RATE_PARENT,
+			.flags = CLK_SET_RATE_PARENT | CLK_IS_CRITICAL,
 			.ops = &clk_branch2_ops,
 			.ops = &clk_branch2_ops,
 		},
 		},
 	},
 	},
@@ -1454,7 +1454,7 @@ static struct clk_branch mmagic_mdss_noc_cfg_ahb_clk = {
 			.name = "mmagic_mdss_noc_cfg_ahb_clk",
 			.name = "mmagic_mdss_noc_cfg_ahb_clk",
 			.parent_names = (const char *[]){ "gcc_mmss_noc_cfg_ahb_clk" },
 			.parent_names = (const char *[]){ "gcc_mmss_noc_cfg_ahb_clk" },
 			.num_parents = 1,
 			.num_parents = 1,
-			.flags = CLK_SET_RATE_PARENT,
+			.flags = CLK_SET_RATE_PARENT | CLK_IS_CRITICAL,
 			.ops = &clk_branch2_ops,
 			.ops = &clk_branch2_ops,
 		},
 		},
 	},
 	},
@@ -1529,7 +1529,7 @@ static struct clk_branch mmagic_video_axi_clk = {
 			.name = "mmagic_video_axi_clk",
 			.name = "mmagic_video_axi_clk",
 			.parent_names = (const char *[]){ "axi_clk_src" },
 			.parent_names = (const char *[]){ "axi_clk_src" },
 			.num_parents = 1,
 			.num_parents = 1,
-			.flags = CLK_SET_RATE_PARENT,
+			.flags = CLK_SET_RATE_PARENT | CLK_IS_CRITICAL,
 			.ops = &clk_branch2_ops,
 			.ops = &clk_branch2_ops,
 		},
 		},
 	},
 	},
@@ -1544,7 +1544,7 @@ static struct clk_branch mmagic_video_noc_cfg_ahb_clk = {
 			.name = "mmagic_video_noc_cfg_ahb_clk",
 			.name = "mmagic_video_noc_cfg_ahb_clk",
 			.parent_names = (const char *[]){ "gcc_mmss_noc_cfg_ahb_clk" },
 			.parent_names = (const char *[]){ "gcc_mmss_noc_cfg_ahb_clk" },
 			.num_parents = 1,
 			.num_parents = 1,
-			.flags = CLK_SET_RATE_PARENT,
+			.flags = CLK_SET_RATE_PARENT | CLK_IS_CRITICAL,
 			.ops = &clk_branch2_ops,
 			.ops = &clk_branch2_ops,
 		},
 		},
 	},
 	},
@@ -2919,7 +2919,7 @@ static struct gdsc mmagic_video_gdsc = {
 		.name = "mmagic_video",
 		.name = "mmagic_video",
 	},
 	},
 	.pwrsts = PWRSTS_OFF_ON,
 	.pwrsts = PWRSTS_OFF_ON,
-	.flags = VOTABLE,
+	.flags = VOTABLE | ALWAYS_ON,
 };
 };
 
 
 static struct gdsc mmagic_mdss_gdsc = {
 static struct gdsc mmagic_mdss_gdsc = {
@@ -2929,7 +2929,7 @@ static struct gdsc mmagic_mdss_gdsc = {
 		.name = "mmagic_mdss",
 		.name = "mmagic_mdss",
 	},
 	},
 	.pwrsts = PWRSTS_OFF_ON,
 	.pwrsts = PWRSTS_OFF_ON,
-	.flags = VOTABLE,
+	.flags = VOTABLE | ALWAYS_ON,
 };
 };
 
 
 static struct gdsc mmagic_camss_gdsc = {
 static struct gdsc mmagic_camss_gdsc = {
@@ -2939,7 +2939,7 @@ static struct gdsc mmagic_camss_gdsc = {
 		.name = "mmagic_camss",
 		.name = "mmagic_camss",
 	},
 	},
 	.pwrsts = PWRSTS_OFF_ON,
 	.pwrsts = PWRSTS_OFF_ON,
-	.flags = VOTABLE,
+	.flags = VOTABLE | ALWAYS_ON,
 };
 };
 
 
 static struct gdsc venus_gdsc = {
 static struct gdsc venus_gdsc = {

+ 0 - 1
drivers/clk/rockchip/Makefile

@@ -3,7 +3,6 @@
 # Rockchip Clock specific Makefile
 # Rockchip Clock specific Makefile
 #
 #
 
 
-obj-y	+= clk-rockchip.o
 obj-y	+= clk.o
 obj-y	+= clk.o
 obj-y	+= clk-pll.o
 obj-y	+= clk-pll.o
 obj-y	+= clk-cpu.o
 obj-y	+= clk-cpu.o

+ 0 - 98
drivers/clk/rockchip/clk-rockchip.c

@@ -1,98 +0,0 @@
-/*
- * Copyright (c) 2013 MundoReader S.L.
- * Author: Heiko Stuebner <heiko@sntech.de>
- *
- * 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.
- */
-
-#include <linux/clk-provider.h>
-#include <linux/clkdev.h>
-#include <linux/of.h>
-#include <linux/of_address.h>
-
-static DEFINE_SPINLOCK(clk_lock);
-
-/*
- * Gate clocks
- */
-
-static void __init rk2928_gate_clk_init(struct device_node *node)
-{
-	struct clk_onecell_data *clk_data;
-	const char *clk_parent;
-	const char *clk_name;
-	void __iomem *reg;
-	void __iomem *reg_idx;
-	int flags;
-	int qty;
-	int reg_bit;
-	int clkflags = CLK_SET_RATE_PARENT;
-	int i;
-
-	qty = of_property_count_strings(node, "clock-output-names");
-	if (qty < 0) {
-		pr_err("%s: error in clock-output-names %d\n", __func__, qty);
-		return;
-	}
-
-	if (qty == 0) {
-		pr_info("%s: nothing to do\n", __func__);
-		return;
-	}
-
-	reg = of_iomap(node, 0);
-	if (!reg)
-		return;
-
-	clk_data = kzalloc(sizeof(struct clk_onecell_data), GFP_KERNEL);
-	if (!clk_data) {
-		iounmap(reg);
-		return;
-	}
-
-	clk_data->clks = kzalloc(qty * sizeof(struct clk *), GFP_KERNEL);
-	if (!clk_data->clks) {
-		kfree(clk_data);
-		iounmap(reg);
-		return;
-	}
-
-	flags = CLK_GATE_HIWORD_MASK | CLK_GATE_SET_TO_DISABLE;
-
-	for (i = 0; i < qty; i++) {
-		of_property_read_string_index(node, "clock-output-names",
-					      i, &clk_name);
-
-		/* ignore empty slots */
-		if (!strcmp("reserved", clk_name))
-			continue;
-
-		clk_parent = of_clk_get_parent_name(node, i);
-
-		/* keep all gates untouched for now */
-		clkflags |= CLK_IGNORE_UNUSED;
-
-		reg_idx = reg + (4 * (i / 16));
-		reg_bit = (i % 16);
-
-		clk_data->clks[i] = clk_register_gate(NULL, clk_name,
-						      clk_parent, clkflags,
-						      reg_idx, reg_bit,
-						      flags,
-						      &clk_lock);
-		WARN_ON(IS_ERR(clk_data->clks[i]));
-	}
-
-	clk_data->clk_num = qty;
-
-	of_clk_add_provider(node, of_clk_src_onecell_get, clk_data);
-}
-CLK_OF_DECLARE(rk2928_gate, "rockchip,rk2928-gate-clk", rk2928_gate_clk_init);

+ 5 - 11
drivers/clk/rockchip/clk.c

@@ -274,18 +274,10 @@ static struct clk *rockchip_clk_register_frac_branch(
 		struct clk_mux *frac_mux = &frac->mux;
 		struct clk_mux *frac_mux = &frac->mux;
 		struct clk_init_data init;
 		struct clk_init_data init;
 		struct clk *mux_clk;
 		struct clk *mux_clk;
-		int i, ret;
-
-		frac->mux_frac_idx = -1;
-		for (i = 0; i < child->num_parents; i++) {
-			if (!strcmp(name, child->parent_names[i])) {
-				pr_debug("%s: found fractional parent in mux at pos %d\n",
-					 __func__, i);
-				frac->mux_frac_idx = i;
-				break;
-			}
-		}
+		int ret;
 
 
+		frac->mux_frac_idx = match_string(child->parent_names,
+						  child->num_parents, name);
 		frac->mux_ops = &clk_mux_ops;
 		frac->mux_ops = &clk_mux_ops;
 		frac->clk_nb.notifier_call = rockchip_clk_frac_notifier_cb;
 		frac->clk_nb.notifier_call = rockchip_clk_frac_notifier_cb;
 
 
@@ -312,6 +304,8 @@ static struct clk *rockchip_clk_register_frac_branch(
 
 
 		/* notifier on the fraction divider to catch rate changes */
 		/* notifier on the fraction divider to catch rate changes */
 		if (frac->mux_frac_idx >= 0) {
 		if (frac->mux_frac_idx >= 0) {
+			pr_debug("%s: found fractional parent in mux at pos %d\n",
+				 __func__, frac->mux_frac_idx);
 			ret = clk_notifier_register(clk, &frac->clk_nb);
 			ret = clk_notifier_register(clk, &frac->clk_nb);
 			if (ret)
 			if (ret)
 				pr_err("%s: failed to register clock notifier for %s\n",
 				pr_err("%s: failed to register clock notifier for %s\n",

+ 5 - 0
drivers/clk/sunxi-ng/Kconfig

@@ -16,6 +16,11 @@ config SUN50I_H6_CCU
 	default ARM64 && ARCH_SUNXI
 	default ARM64 && ARCH_SUNXI
 	depends on (ARM64 && ARCH_SUNXI) || COMPILE_TEST
 	depends on (ARM64 && ARCH_SUNXI) || COMPILE_TEST
 
 
+config SUN50I_H6_R_CCU
+	bool "Support for the Allwinner H6 PRCM CCU"
+	default ARM64 && ARCH_SUNXI
+	depends on (ARM64 && ARCH_SUNXI) || COMPILE_TEST
+
 config SUN4I_A10_CCU
 config SUN4I_A10_CCU
 	bool "Support for the Allwinner A10/A20 CCU"
 	bool "Support for the Allwinner A10/A20 CCU"
 	default MACH_SUN4I
 	default MACH_SUN4I

+ 1 - 0
drivers/clk/sunxi-ng/Makefile

@@ -23,6 +23,7 @@ lib-$(CONFIG_SUNXI_CCU)		+= ccu_mp.o
 # SoC support
 # SoC support
 obj-$(CONFIG_SUN50I_A64_CCU)	+= ccu-sun50i-a64.o
 obj-$(CONFIG_SUN50I_A64_CCU)	+= ccu-sun50i-a64.o
 obj-$(CONFIG_SUN50I_H6_CCU)	+= ccu-sun50i-h6.o
 obj-$(CONFIG_SUN50I_H6_CCU)	+= ccu-sun50i-h6.o
+obj-$(CONFIG_SUN50I_H6_R_CCU)	+= ccu-sun50i-h6-r.o
 obj-$(CONFIG_SUN4I_A10_CCU)	+= ccu-sun4i-a10.o
 obj-$(CONFIG_SUN4I_A10_CCU)	+= ccu-sun4i-a10.o
 obj-$(CONFIG_SUN5I_CCU)		+= ccu-sun5i.o
 obj-$(CONFIG_SUN5I_CCU)		+= ccu-sun5i.o
 obj-$(CONFIG_SUN6I_A31_CCU)	+= ccu-sun6i-a31.o
 obj-$(CONFIG_SUN6I_A31_CCU)	+= ccu-sun6i-a31.o

+ 207 - 0
drivers/clk/sunxi-ng/ccu-sun50i-h6-r.c

@@ -0,0 +1,207 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (c) 2017 Icenowy Zheng <icenowy@aosc.xyz>
+ */
+
+#include <linux/clk-provider.h>
+#include <linux/of_address.h>
+#include <linux/platform_device.h>
+
+#include "ccu_common.h"
+#include "ccu_reset.h"
+
+#include "ccu_div.h"
+#include "ccu_gate.h"
+#include "ccu_mp.h"
+#include "ccu_nm.h"
+
+#include "ccu-sun50i-h6-r.h"
+
+/*
+ * Information about AR100 and AHB/APB clocks in R_CCU are gathered from
+ * clock definitions in the BSP source code.
+ */
+
+static const char * const ar100_r_apb2_parents[] = { "osc24M", "osc32k",
+					     "pll-periph0", "iosc" };
+static const struct ccu_mux_var_prediv ar100_r_apb2_predivs[] = {
+	{ .index = 2, .shift = 0, .width = 5 },
+};
+
+static struct ccu_div ar100_clk = {
+	.div		= _SUNXI_CCU_DIV_FLAGS(8, 2, CLK_DIVIDER_POWER_OF_TWO),
+
+	.mux		= {
+		.shift	= 24,
+		.width	= 2,
+
+		.var_predivs	= ar100_r_apb2_predivs,
+		.n_var_predivs	= ARRAY_SIZE(ar100_r_apb2_predivs),
+	},
+
+	.common		= {
+		.reg		= 0x000,
+		.features	= CCU_FEATURE_VARIABLE_PREDIV,
+		.hw.init	= CLK_HW_INIT_PARENTS("ar100",
+						      ar100_r_apb2_parents,
+						      &ccu_div_ops,
+						      0),
+	},
+};
+
+static CLK_FIXED_FACTOR(r_ahb_clk, "r-ahb", "ar100", 1, 1, 0);
+
+static struct ccu_div r_apb1_clk = {
+	.div		= _SUNXI_CCU_DIV(0, 2),
+
+	.common		= {
+		.reg		= 0x00c,
+		.hw.init	= CLK_HW_INIT("r-apb1",
+					      "r-ahb",
+					      &ccu_div_ops,
+					      0),
+	},
+};
+
+static struct ccu_div r_apb2_clk = {
+	.div		= _SUNXI_CCU_DIV_FLAGS(8, 2, CLK_DIVIDER_POWER_OF_TWO),
+
+	.mux		= {
+		.shift	= 24,
+		.width	= 2,
+
+		.var_predivs	= ar100_r_apb2_predivs,
+		.n_var_predivs	= ARRAY_SIZE(ar100_r_apb2_predivs),
+	},
+
+	.common		= {
+		.reg		= 0x010,
+		.features	= CCU_FEATURE_VARIABLE_PREDIV,
+		.hw.init	= CLK_HW_INIT_PARENTS("r-apb2",
+						      ar100_r_apb2_parents,
+						      &ccu_div_ops,
+						      0),
+	},
+};
+
+/*
+ * Information about the gate/resets are gathered from the clock header file
+ * in the BSP source code, although most of them are unused. The existence
+ * of the hardware block is verified with "3.1 Memory Mapping" chapter in
+ * "Allwinner H6 V200 User Manual V1.1"; and the parent APB buses are verified
+ * with "3.3.2.1 System Bus Tree" chapter inthe same document.
+ */
+static SUNXI_CCU_GATE(r_apb1_timer_clk,	"r-apb1-timer",	"r-apb1",
+		      0x11c, BIT(0), 0);
+static SUNXI_CCU_GATE(r_apb1_twd_clk,	"r-apb1-twd",	"r-apb1",
+		      0x12c, BIT(0), 0);
+static SUNXI_CCU_GATE(r_apb1_pwm_clk,	"r-apb1-pwm",	"r-apb1",
+		      0x13c, BIT(0), 0);
+static SUNXI_CCU_GATE(r_apb2_uart_clk,	"r-apb2-uart",	"r-apb2",
+		      0x18c, BIT(0), 0);
+static SUNXI_CCU_GATE(r_apb2_i2c_clk,	"r-apb2-i2c",	"r-apb2",
+		      0x19c, BIT(0), 0);
+static SUNXI_CCU_GATE(r_apb1_ir_clk,	"r-apb1-ir",	"r-apb1",
+		      0x1cc, BIT(0), 0);
+static SUNXI_CCU_GATE(r_apb1_w1_clk,	"r-apb1-w1",	"r-apb1",
+		      0x1cc, BIT(0), 0);
+
+/* Information of IR(RX) mod clock is gathered from BSP source code */
+static const char * const r_mod0_default_parents[] = { "osc32k", "osc24M" };
+static SUNXI_CCU_MP_WITH_MUX_GATE(ir_clk, "ir",
+				  r_mod0_default_parents, 0x1c0,
+				  0, 5,		/* M */
+				  8, 2,		/* P */
+				  24, 1,	/* mux */
+				  BIT(31),	/* gate */
+				  0);
+
+/*
+ * BSP didn't use the 1-wire function at all now, and the information about
+ * this mod clock is guessed from the IR mod clock above. The existence of
+ * this mod clock is proven by BSP clock header, and the dividers are verified
+ * by contents in the 1-wire related chapter of the User Manual.
+ */
+
+static SUNXI_CCU_MP_WITH_MUX_GATE(w1_clk, "w1",
+				  r_mod0_default_parents, 0x1e0,
+				  0, 5,		/* M */
+				  8, 2,		/* P */
+				  24, 1,	/* mux */
+				  BIT(31),	/* gate */
+				  0);
+
+static struct ccu_common *sun50i_h6_r_ccu_clks[] = {
+	&ar100_clk.common,
+	&r_apb1_clk.common,
+	&r_apb2_clk.common,
+	&r_apb1_timer_clk.common,
+	&r_apb1_twd_clk.common,
+	&r_apb1_pwm_clk.common,
+	&r_apb2_uart_clk.common,
+	&r_apb2_i2c_clk.common,
+	&r_apb1_ir_clk.common,
+	&r_apb1_w1_clk.common,
+	&ir_clk.common,
+	&w1_clk.common,
+};
+
+static struct clk_hw_onecell_data sun50i_h6_r_hw_clks = {
+	.hws	= {
+		[CLK_AR100]		= &ar100_clk.common.hw,
+		[CLK_R_AHB]		= &r_ahb_clk.hw,
+		[CLK_R_APB1]		= &r_apb1_clk.common.hw,
+		[CLK_R_APB2]		= &r_apb2_clk.common.hw,
+		[CLK_R_APB1_TIMER]	= &r_apb1_timer_clk.common.hw,
+		[CLK_R_APB1_TWD]	= &r_apb1_twd_clk.common.hw,
+		[CLK_R_APB1_PWM]	= &r_apb1_pwm_clk.common.hw,
+		[CLK_R_APB2_UART]	= &r_apb2_uart_clk.common.hw,
+		[CLK_R_APB2_I2C]	= &r_apb2_i2c_clk.common.hw,
+		[CLK_R_APB1_IR]		= &r_apb1_ir_clk.common.hw,
+		[CLK_R_APB1_W1]		= &r_apb1_w1_clk.common.hw,
+		[CLK_IR]		= &ir_clk.common.hw,
+		[CLK_W1]		= &w1_clk.common.hw,
+	},
+	.num	= CLK_NUMBER,
+};
+
+static struct ccu_reset_map sun50i_h6_r_ccu_resets[] = {
+	[RST_R_APB1_TIMER]	=  { 0x11c, BIT(16) },
+	[RST_R_APB1_TWD]	=  { 0x12c, BIT(16) },
+	[RST_R_APB1_PWM]	=  { 0x13c, BIT(16) },
+	[RST_R_APB2_UART]	=  { 0x18c, BIT(16) },
+	[RST_R_APB2_I2C]	=  { 0x19c, BIT(16) },
+	[RST_R_APB1_IR]		=  { 0x1cc, BIT(16) },
+	[RST_R_APB1_W1]		=  { 0x1ec, BIT(16) },
+};
+
+static const struct sunxi_ccu_desc sun50i_h6_r_ccu_desc = {
+	.ccu_clks	= sun50i_h6_r_ccu_clks,
+	.num_ccu_clks	= ARRAY_SIZE(sun50i_h6_r_ccu_clks),
+
+	.hw_clks	= &sun50i_h6_r_hw_clks,
+
+	.resets		= sun50i_h6_r_ccu_resets,
+	.num_resets	= ARRAY_SIZE(sun50i_h6_r_ccu_resets),
+};
+
+static void __init sunxi_r_ccu_init(struct device_node *node,
+				    const struct sunxi_ccu_desc *desc)
+{
+	void __iomem *reg;
+
+	reg = of_io_request_and_map(node, 0, of_node_full_name(node));
+	if (IS_ERR(reg)) {
+		pr_err("%pOF: Could not map the clock registers\n", node);
+		return;
+	}
+
+	sunxi_ccu_probe(node, reg, desc);
+}
+
+static void __init sun50i_h6_r_ccu_setup(struct device_node *node)
+{
+	sunxi_r_ccu_init(node, &sun50i_h6_r_ccu_desc);
+}
+CLK_OF_DECLARE(sun50i_h6_r_ccu, "allwinner,sun50i-h6-r-ccu",
+	       sun50i_h6_r_ccu_setup);

+ 19 - 0
drivers/clk/sunxi-ng/ccu-sun50i-h6-r.h

@@ -0,0 +1,19 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * Copyright 2017 Icenowy Zheng <icenowy@aosc.xyz>
+ */
+
+#ifndef _CCU_SUN50I_H6_R_H
+#define _CCU_SUN50I_H6_R_H
+
+#include <dt-bindings/clock/sun50i-h6-r-ccu.h>
+#include <dt-bindings/reset/sun50i-h6-r-ccu.h>
+
+/* AHB/APB bus clocks are not exported except APB1 for R_PIO */
+#define CLK_R_AHB	1
+
+#define CLK_R_APB2	3
+
+#define CLK_NUMBER	(CLK_W1 + 1)
+
+#endif /* _CCU_SUN50I_H6_R_H */

+ 61 - 11
drivers/clk/sunxi-ng/ccu-sun8i-r40.c

@@ -12,7 +12,8 @@
  */
  */
 
 
 #include <linux/clk-provider.h>
 #include <linux/clk-provider.h>
-#include <linux/of_address.h>
+#include <linux/platform_device.h>
+#include <linux/regmap.h>
 
 
 #include "ccu_common.h"
 #include "ccu_common.h"
 #include "ccu_reset.h"
 #include "ccu_reset.h"
@@ -1250,17 +1251,45 @@ static struct ccu_mux_nb sun8i_r40_cpu_nb = {
 	.bypass_index	= 1, /* index of 24 MHz oscillator */
 	.bypass_index	= 1, /* index of 24 MHz oscillator */
 };
 };
 
 
-static void __init sun8i_r40_ccu_setup(struct device_node *node)
+/*
+ * Add a regmap for the GMAC driver (dwmac-sun8i) to access the
+ * GMAC configuration register.
+ * Only this register is allowed to be written, in order to
+ * prevent overriding critical clock configuration.
+ */
+
+#define SUN8I_R40_GMAC_CFG_REG 0x164
+static bool sun8i_r40_ccu_regmap_accessible_reg(struct device *dev,
+						unsigned int reg)
+{
+	if (reg == SUN8I_R40_GMAC_CFG_REG)
+		return true;
+	return false;
+}
+
+static struct regmap_config sun8i_r40_ccu_regmap_config = {
+	.reg_bits	= 32,
+	.val_bits	= 32,
+	.reg_stride	= 4,
+	.max_register	= 0x320, /* PLL_LOCK_CTRL_REG */
+
+	/* other devices have no business accessing other registers */
+	.readable_reg	= sun8i_r40_ccu_regmap_accessible_reg,
+	.writeable_reg	= sun8i_r40_ccu_regmap_accessible_reg,
+};
+
+static int sun8i_r40_ccu_probe(struct platform_device *pdev)
 {
 {
+	struct resource *res;
+	struct regmap *regmap;
 	void __iomem *reg;
 	void __iomem *reg;
 	u32 val;
 	u32 val;
+	int ret;
 
 
-	reg = of_io_request_and_map(node, 0, of_node_full_name(node));
-	if (IS_ERR(reg)) {
-		pr_err("%s: Could not map the clock registers\n",
-		       of_node_full_name(node));
-		return;
-	}
+	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+	reg = devm_ioremap_resource(&pdev->dev, res);
+	if (IS_ERR(reg))
+		return PTR_ERR(reg);
 
 
 	/* Force the PLL-Audio-1x divider to 4 */
 	/* Force the PLL-Audio-1x divider to 4 */
 	val = readl(reg + SUN8I_R40_PLL_AUDIO_REG);
 	val = readl(reg + SUN8I_R40_PLL_AUDIO_REG);
@@ -1277,7 +1306,14 @@ static void __init sun8i_r40_ccu_setup(struct device_node *node)
 	val &= ~GENMASK(25, 20);
 	val &= ~GENMASK(25, 20);
 	writel(val, reg + SUN8I_R40_USB_CLK_REG);
 	writel(val, reg + SUN8I_R40_USB_CLK_REG);
 
 
-	sunxi_ccu_probe(node, reg, &sun8i_r40_ccu_desc);
+	regmap = devm_regmap_init_mmio(&pdev->dev, reg,
+				       &sun8i_r40_ccu_regmap_config);
+	if (IS_ERR(regmap))
+		return PTR_ERR(regmap);
+
+	ret = sunxi_ccu_probe(pdev->dev.of_node, reg, &sun8i_r40_ccu_desc);
+	if (ret)
+		return ret;
 
 
 	/* Gate then ungate PLL CPU after any rate changes */
 	/* Gate then ungate PLL CPU after any rate changes */
 	ccu_pll_notifier_register(&sun8i_r40_pll_cpu_nb);
 	ccu_pll_notifier_register(&sun8i_r40_pll_cpu_nb);
@@ -1285,6 +1321,20 @@ static void __init sun8i_r40_ccu_setup(struct device_node *node)
 	/* Reparent CPU during PLL CPU rate changes */
 	/* Reparent CPU during PLL CPU rate changes */
 	ccu_mux_notifier_register(pll_cpu_clk.common.hw.clk,
 	ccu_mux_notifier_register(pll_cpu_clk.common.hw.clk,
 				  &sun8i_r40_cpu_nb);
 				  &sun8i_r40_cpu_nb);
+
+	return 0;
 }
 }
-CLK_OF_DECLARE(sun8i_r40_ccu, "allwinner,sun8i-r40-ccu",
-	       sun8i_r40_ccu_setup);
+
+static const struct of_device_id sun8i_r40_ccu_ids[] = {
+	{ .compatible = "allwinner,sun8i-r40-ccu" },
+	{ }
+};
+
+static struct platform_driver sun8i_r40_ccu_driver = {
+	.probe	= sun8i_r40_ccu_probe,
+	.driver	= {
+		.name	= "sun8i-r40-ccu",
+		.of_match_table	= sun8i_r40_ccu_ids,
+	},
+};
+builtin_platform_driver(sun8i_r40_ccu_driver);

+ 1 - 1
drivers/clk/tegra/clk-tegra114.c

@@ -1367,7 +1367,7 @@ static void __init tegra114_clock_init(struct device_node *np)
 	tegra_super_clk_gen4_init(clk_base, pmc_base, tegra114_clks,
 	tegra_super_clk_gen4_init(clk_base, pmc_base, tegra114_clks,
 					&pll_x_params);
 					&pll_x_params);
 
 
-	tegra_add_of_provider(np);
+	tegra_add_of_provider(np, of_clk_src_onecell_get);
 	tegra_register_devclks(devclks, ARRAY_SIZE(devclks));
 	tegra_register_devclks(devclks, ARRAY_SIZE(devclks));
 
 
 	tegra_clk_apply_init_table = tegra114_clock_apply_init_table;
 	tegra_clk_apply_init_table = tegra114_clock_apply_init_table;

+ 1 - 1
drivers/clk/tegra/clk-tegra124.c

@@ -1479,7 +1479,7 @@ static void __init tegra124_132_clock_init_post(struct device_node *np)
 				  &pll_x_params);
 				  &pll_x_params);
 	tegra_init_special_resets(1, tegra124_reset_assert,
 	tegra_init_special_resets(1, tegra124_reset_assert,
 				  tegra124_reset_deassert);
 				  tegra124_reset_deassert);
-	tegra_add_of_provider(np);
+	tegra_add_of_provider(np, of_clk_src_onecell_get);
 
 
 	clks[TEGRA124_CLK_EMC] = tegra_clk_register_emc(clk_base, np,
 	clks[TEGRA124_CLK_EMC] = tegra_clk_register_emc(clk_base, np,
 							&emc_lock);
 							&emc_lock);

+ 47 - 5
drivers/clk/tegra/clk-tegra20.c

@@ -26,6 +26,8 @@
 #include "clk.h"
 #include "clk.h"
 #include "clk-id.h"
 #include "clk-id.h"
 
 
+#define MISC_CLK_ENB 0x48
+
 #define OSC_CTRL 0x50
 #define OSC_CTRL 0x50
 #define OSC_CTRL_OSC_FREQ_MASK (3<<30)
 #define OSC_CTRL_OSC_FREQ_MASK (3<<30)
 #define OSC_CTRL_OSC_FREQ_13MHZ (0<<30)
 #define OSC_CTRL_OSC_FREQ_13MHZ (0<<30)
@@ -831,15 +833,25 @@ static void __init tegra20_periph_clk_init(void)
 				    periph_clk_enb_refcnt);
 				    periph_clk_enb_refcnt);
 	clks[TEGRA20_CLK_PEX] = clk;
 	clks[TEGRA20_CLK_PEX] = clk;
 
 
+	/* dev1 OSC divider */
+	clk_register_divider(NULL, "dev1_osc_div", "clk_m",
+			     0, clk_base + MISC_CLK_ENB, 22, 2,
+			     CLK_DIVIDER_POWER_OF_TWO | CLK_DIVIDER_READ_ONLY,
+			     NULL);
+
+	/* dev2 OSC divider */
+	clk_register_divider(NULL, "dev2_osc_div", "clk_m",
+			     0, clk_base + MISC_CLK_ENB, 20, 2,
+			     CLK_DIVIDER_POWER_OF_TWO | CLK_DIVIDER_READ_ONLY,
+			     NULL);
+
 	/* cdev1 */
 	/* cdev1 */
-	clk = clk_register_fixed_rate(NULL, "cdev1_fixed", NULL, 0, 26000000);
-	clk = tegra_clk_register_periph_gate("cdev1", "cdev1_fixed", 0,
+	clk = tegra_clk_register_periph_gate("cdev1", "cdev1_mux", 0,
 				    clk_base, 0, 94, periph_clk_enb_refcnt);
 				    clk_base, 0, 94, periph_clk_enb_refcnt);
 	clks[TEGRA20_CLK_CDEV1] = clk;
 	clks[TEGRA20_CLK_CDEV1] = clk;
 
 
 	/* cdev2 */
 	/* cdev2 */
-	clk = clk_register_fixed_rate(NULL, "cdev2_fixed", NULL, 0, 26000000);
-	clk = tegra_clk_register_periph_gate("cdev2", "cdev2_fixed", 0,
+	clk = tegra_clk_register_periph_gate("cdev2", "cdev2_mux", 0,
 				    clk_base, 0, 93, periph_clk_enb_refcnt);
 				    clk_base, 0, 93, periph_clk_enb_refcnt);
 	clks[TEGRA20_CLK_CDEV2] = clk;
 	clks[TEGRA20_CLK_CDEV2] = clk;
 
 
@@ -1077,6 +1089,36 @@ static const struct of_device_id pmc_match[] __initconst = {
 	{ },
 	{ },
 };
 };
 
 
+static struct clk *tegra20_clk_src_onecell_get(struct of_phandle_args *clkspec,
+					       void *data)
+{
+	struct clk_hw *parent_hw;
+	struct clk_hw *hw;
+	struct clk *clk;
+
+	clk = of_clk_src_onecell_get(clkspec, data);
+	if (IS_ERR(clk))
+		return clk;
+
+	/*
+	 * Tegra20 CDEV1 and CDEV2 clocks are a bit special case, their parent
+	 * clock is created by the pinctrl driver. It is possible for clk user
+	 * to request these clocks before pinctrl driver got probed and hence
+	 * user will get an orphaned clock. That might be undesirable because
+	 * user may expect parent clock to be enabled by the child.
+	 */
+	if (clkspec->args[0] == TEGRA20_CLK_CDEV1 ||
+	    clkspec->args[0] == TEGRA20_CLK_CDEV2) {
+		hw = __clk_get_hw(clk);
+
+		parent_hw = clk_hw_get_parent(hw);
+		if (!parent_hw)
+			return ERR_PTR(-EPROBE_DEFER);
+	}
+
+	return clk;
+}
+
 static void __init tegra20_clock_init(struct device_node *np)
 static void __init tegra20_clock_init(struct device_node *np)
 {
 {
 	struct device_node *node;
 	struct device_node *node;
@@ -1115,7 +1157,7 @@ static void __init tegra20_clock_init(struct device_node *np)
 
 
 	tegra_init_dup_clks(tegra_clk_duplicates, clks, TEGRA20_CLK_CLK_MAX);
 	tegra_init_dup_clks(tegra_clk_duplicates, clks, TEGRA20_CLK_CLK_MAX);
 
 
-	tegra_add_of_provider(np);
+	tegra_add_of_provider(np, tegra20_clk_src_onecell_get);
 	tegra_register_devclks(devclks, ARRAY_SIZE(devclks));
 	tegra_register_devclks(devclks, ARRAY_SIZE(devclks));
 
 
 	tegra_clk_apply_init_table = tegra20_clock_apply_init_table;
 	tegra_clk_apply_init_table = tegra20_clock_apply_init_table;

+ 1 - 1
drivers/clk/tegra/clk-tegra210.c

@@ -3567,7 +3567,7 @@ static void __init tegra210_clock_init(struct device_node *np)
 	tegra_init_special_resets(2, tegra210_reset_assert,
 	tegra_init_special_resets(2, tegra210_reset_assert,
 				  tegra210_reset_deassert);
 				  tegra210_reset_deassert);
 
 
-	tegra_add_of_provider(np);
+	tegra_add_of_provider(np, of_clk_src_onecell_get);
 	tegra_register_devclks(devclks, ARRAY_SIZE(devclks));
 	tegra_register_devclks(devclks, ARRAY_SIZE(devclks));
 
 
 	tegra210_mbist_clk_init();
 	tegra210_mbist_clk_init();

+ 1 - 1
drivers/clk/tegra/clk-tegra30.c

@@ -1349,7 +1349,7 @@ static void __init tegra30_clock_init(struct device_node *np)
 
 
 	tegra_init_dup_clks(tegra_clk_duplicates, clks, TEGRA30_CLK_CLK_MAX);
 	tegra_init_dup_clks(tegra_clk_duplicates, clks, TEGRA30_CLK_CLK_MAX);
 
 
-	tegra_add_of_provider(np);
+	tegra_add_of_provider(np, of_clk_src_onecell_get);
 	tegra_register_devclks(devclks, ARRAY_SIZE(devclks));
 	tegra_register_devclks(devclks, ARRAY_SIZE(devclks));
 
 
 	tegra_clk_apply_init_table = tegra30_clock_apply_init_table;
 	tegra_clk_apply_init_table = tegra30_clock_apply_init_table;

+ 3 - 2
drivers/clk/tegra/clk.c

@@ -298,7 +298,8 @@ static struct reset_controller_dev rst_ctlr = {
 	.of_reset_n_cells = 1,
 	.of_reset_n_cells = 1,
 };
 };
 
 
-void __init tegra_add_of_provider(struct device_node *np)
+void __init tegra_add_of_provider(struct device_node *np,
+				  void *clk_src_onecell_get)
 {
 {
 	int i;
 	int i;
 
 
@@ -314,7 +315,7 @@ void __init tegra_add_of_provider(struct device_node *np)
 
 
 	clk_data.clks = clks;
 	clk_data.clks = clks;
 	clk_data.clk_num = clk_num;
 	clk_data.clk_num = clk_num;
-	of_clk_add_provider(np, of_clk_src_onecell_get, &clk_data);
+	of_clk_add_provider(np, clk_src_onecell_get, &clk_data);
 
 
 	rst_ctlr.of_node = np;
 	rst_ctlr.of_node = np;
 	rst_ctlr.nr_resets = periph_banks * 32 + num_special_reset;
 	rst_ctlr.nr_resets = periph_banks * 32 + num_special_reset;

+ 1 - 1
drivers/clk/tegra/clk.h

@@ -763,7 +763,7 @@ struct clk **tegra_clk_init(void __iomem *clk_base, int num, int periph_banks);
 
 
 struct clk **tegra_lookup_dt_id(int clk_id, struct tegra_clk *tegra_clk);
 struct clk **tegra_lookup_dt_id(int clk_id, struct tegra_clk *tegra_clk);
 
 
-void tegra_add_of_provider(struct device_node *np);
+void tegra_add_of_provider(struct device_node *np, void *clk_src_onecell_get);
 void tegra_register_devclks(struct tegra_devclk *dev_clks, int num);
 void tegra_register_devclks(struct tegra_devclk *dev_clks, int num);
 
 
 void tegra_audio_clk_init(void __iomem *clk_base,
 void tegra_audio_clk_init(void __iomem *clk_base,

+ 24 - 0
include/dt-bindings/clock/sun50i-h6-r-ccu.h

@@ -0,0 +1,24 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * Copyright (c) 2017 Icenowy Zheng <icenowy@aosc.xyz>
+ */
+
+#ifndef _DT_BINDINGS_CLK_SUN50I_H6_R_CCU_H_
+#define _DT_BINDINGS_CLK_SUN50I_H6_R_CCU_H_
+
+#define CLK_AR100		0
+
+#define CLK_R_APB1		2
+
+#define CLK_R_APB1_TIMER	4
+#define CLK_R_APB1_TWD		5
+#define CLK_R_APB1_PWM		6
+#define CLK_R_APB2_UART		7
+#define CLK_R_APB2_I2C		8
+#define CLK_R_APB1_IR		9
+#define CLK_R_APB1_W1		10
+
+#define CLK_IR			11
+#define CLK_W1			12
+
+#endif /* _DT_BINDINGS_CLK_SUN50I_H6_R_CCU_H_ */

+ 17 - 0
include/dt-bindings/reset/sun50i-h6-r-ccu.h

@@ -0,0 +1,17 @@
+/* SPDX-License-Identifier: (GPL-2.0+ or MIT) */
+/*
+ * Copyright (C) 2016 Icenowy Zheng <icenowy@aosc.xyz>
+ */
+
+#ifndef _DT_BINDINGS_RST_SUN50I_H6_R_CCU_H_
+#define _DT_BINDINGS_RST_SUN50I_H6_R_CCU_H_
+
+#define RST_R_APB1_TIMER	0
+#define RST_R_APB1_TWD		1
+#define RST_R_APB1_PWM		2
+#define RST_R_APB2_UART		3
+#define RST_R_APB2_I2C		4
+#define RST_R_APB1_IR		5
+#define RST_R_APB1_W1		6
+
+#endif /* _DT_BINDINGS_RST_SUN50I_H6_R_CCU_H_ */