linux-arm-kernel.lists.infradead.org archive mirror
 help / color / mirror / Atom feed
* [PATCH 0/4] clk: sunxi: mmc: Last bits of phase handling
@ 2014-12-07 17:21 Maxime Ripard
  2014-12-07 17:21 ` [PATCH 1/4] clk: sunxi: Rework MMC phase clocks Maxime Ripard
                   ` (3 more replies)
  0 siblings, 4 replies; 8+ messages in thread
From: Maxime Ripard @ 2014-12-07 17:21 UTC (permalink / raw)
  To: linux-arm-kernel

Hi,

These are the last patches of the serie converting the custom phase
API to the proper common clock framework API.

These patches have already been discussed in length, only the patch 1
is new and should ease the handling of our MMC clocks.

Thanks,
Maxime

Maxime Ripard (4):
  clk: sunxi: Rework MMC phase clocks
  ARM: sunxi: dt: Add sample and output mmc clocks
  mmc: sunxi: Convert MMC driver to the standard clock phase API
  clk: sunxi: Remove custom phase function

 .../devicetree/bindings/mmc/sunxi-mmc.txt          |   8 +-
 arch/arm/boot/dts/sun4i-a10.dtsi                   |  72 ++++++++----
 arch/arm/boot/dts/sun5i-a10s.dtsi                  |  54 ++++++---
 arch/arm/boot/dts/sun5i-a13.dtsi                   |  44 ++++---
 arch/arm/boot/dts/sun6i-a31.dtsi                   |  72 ++++++++----
 arch/arm/boot/dts/sun7i-a20.dtsi                   |  72 ++++++++----
 arch/arm/boot/dts/sun8i-a23.dtsi                   |  54 ++++++---
 drivers/clk/sunxi/clk-mod0.c                       | 129 +++++++++++----------
 drivers/clk/sunxi/clk-sunxi.c                      |  37 ------
 drivers/mmc/host/sunxi-mmc.c                       |  72 ++++++++----
 include/linux/clk/sunxi.h                          |  22 ----
 11 files changed, 385 insertions(+), 251 deletions(-)
 delete mode 100644 include/linux/clk/sunxi.h

-- 
2.2.0

^ permalink raw reply	[flat|nested] 8+ messages in thread

* [PATCH 1/4] clk: sunxi: Rework MMC phase clocks
  2014-12-07 17:21 [PATCH 0/4] clk: sunxi: mmc: Last bits of phase handling Maxime Ripard
@ 2014-12-07 17:21 ` Maxime Ripard
  2014-12-08 16:53   ` Chen-Yu Tsai
  2014-12-07 17:21 ` [PATCH 2/4] ARM: sunxi: dt: Add sample and output mmc clocks Maxime Ripard
                   ` (2 subsequent siblings)
  3 siblings, 1 reply; 8+ messages in thread
From: Maxime Ripard @ 2014-12-07 17:21 UTC (permalink / raw)
  To: linux-arm-kernel

Instead of having three different clocks for the main MMC clock and the two
phase sub-clocks, which involved having three different drivers sharing the
same register, rework it to have the same single driver registering three
different clocks.

Signed-off-by: Maxime Ripard <maxime.ripard@free-electrons.com>
---
 drivers/clk/sunxi/clk-mod0.c | 129 ++++++++++++++++++++++---------------------
 1 file changed, 67 insertions(+), 62 deletions(-)

diff --git a/drivers/clk/sunxi/clk-mod0.c b/drivers/clk/sunxi/clk-mod0.c
index 658d74f39451..24522c5b94ae 100644
--- a/drivers/clk/sunxi/clk-mod0.c
+++ b/drivers/clk/sunxi/clk-mod0.c
@@ -115,19 +115,17 @@ static void __init sun5i_a13_mbus_setup(struct device_node *node)
 }
 CLK_OF_DECLARE(sun5i_a13_mbus, "allwinner,sun5i-a13-mbus-clk", sun5i_a13_mbus_setup);
 
-struct mmc_phase_data {
-	u8	offset;
-};
-
 struct mmc_phase {
 	struct clk_hw		hw;
+	u8			offset;
 	void __iomem		*reg;
-	struct mmc_phase_data	*data;
 	spinlock_t		*lock;
 };
 
 #define to_mmc_phase(_hw) container_of(_hw, struct mmc_phase, hw)
 
+static DEFINE_SPINLOCK(sun4i_a10_mmc_lock);
+
 static int mmc_get_phase(struct clk_hw *hw)
 {
 	struct clk *mmc, *mmc_parent, *clk = hw->clk;
@@ -138,7 +136,7 @@ static int mmc_get_phase(struct clk_hw *hw)
 	u8 delay;
 
 	value = readl(phase->reg);
-	delay = (value >> phase->data->offset) & 0x3;
+	delay = (value >> phase->offset) & 0x3;
 
 	if (!delay)
 		return 180;
@@ -226,8 +224,8 @@ static int mmc_set_phase(struct clk_hw *hw, int degrees)
 
 	spin_lock_irqsave(phase->lock, flags);
 	value = readl(phase->reg);
-	value &= ~GENMASK(phase->data->offset + 3, phase->data->offset);
-	value |= delay << phase->data->offset;
+	value &= ~GENMASK(phase->offset + 3, phase->offset);
+	value |= delay << phase->offset;
 	writel(value, phase->reg);
 	spin_unlock_irqrestore(phase->lock, flags);
 
@@ -239,66 +237,73 @@ static const struct clk_ops mmc_clk_ops = {
 	.set_phase	= mmc_set_phase,
 };
 
-static void __init sun4i_a10_mmc_phase_setup(struct device_node *node,
-					     struct mmc_phase_data *data)
+static void __init sun4i_a10_mmc_setup(struct device_node *node)
 {
-	const char *parent_names[1] = { of_clk_get_parent_name(node, 0) };
-	struct clk_init_data init = {
-		.num_parents	= 1,
-		.parent_names	= parent_names,
-		.ops		= &mmc_clk_ops,
-	};
-
-	struct mmc_phase *phase;
-	struct clk *clk;
-
-	phase = kmalloc(sizeof(*phase), GFP_KERNEL);
-	if (!phase)
-		return;
-
-	phase->hw.init = &init;
-
-	phase->reg = of_iomap(node, 0);
-	if (!phase->reg)
-		goto err_free;
+	struct clk_onecell_data *clk_data;
+	const char *parent;
+	void __iomem *reg;
+	int i;
 
-	phase->data = data;
-	phase->lock = &sun4i_a10_mod0_lock;
+	reg = of_io_request_and_map(node, 0, of_node_full_name(node));
+	if (IS_ERR(reg)) {
+		pr_err("Couldn't map the %s clock registers\n", node->name);
+		return;
+	}
 
-	if (of_property_read_string(node, "clock-output-names", &init.name))
-		init.name = node->name;
+	clk_data = kmalloc(sizeof(*clk_data), GFP_KERNEL);
+	if (!clk_data)
+		return;
 
-	clk = clk_register(NULL, &phase->hw);
-	if (IS_ERR(clk))
-		goto err_unmap;
+	clk_data->clks = kcalloc(3, sizeof(*clk_data->clks), GFP_KERNEL);
+	if (!clk_data->clks)
+		goto err_free_data;
+
+	clk_data->clk_num = 3;
+	clk_data->clks[0] = sunxi_factors_register(node,
+						   &sun4i_a10_mod0_data,
+						   &sun4i_a10_mmc_lock, reg);
+	if (!clk_data->clks[0])
+		goto err_free_clks;
+
+	parent = __clk_get_name(clk_data->clks[0]);
+
+	for (i = 1; i < 3; i++) {
+		struct clk_init_data init = {
+			.num_parents	= 1,
+			.parent_names	= &parent,
+			.ops		= &mmc_clk_ops,
+		};
+		struct mmc_phase *phase;
+
+		phase = kmalloc(sizeof(*phase), GFP_KERNEL);
+		if (!phase)
+			continue;
+
+		phase->hw.init = &init;
+		phase->reg = reg;
+		phase->lock = &sun4i_a10_mmc_lock;
+
+		if (i == 1)
+			phase->offset = 8;
+		else
+			phase->offset = 20;
+
+		if (of_property_read_string_index(node, "clock-output-names",
+						  i, &init.name))
+			init.name = node->name;
+
+		clk_data->clks[i] = clk_register(NULL, &phase->hw);
+		if (IS_ERR(clk_data->clks[i]))
+			continue;
+	}
 
-	of_clk_add_provider(node, of_clk_src_simple_get, clk);
+	of_clk_add_provider(node, of_clk_src_onecell_get, clk_data);
 
 	return;
 
-err_unmap:
-	iounmap(phase->reg);
-err_free:
-	kfree(phase);
-}
-
-
-static struct mmc_phase_data mmc_output_clk = {
-	.offset	= 8,
-};
-
-static struct mmc_phase_data mmc_sample_clk = {
-	.offset	= 20,
-};
-
-static void __init sun4i_a10_mmc_output_setup(struct device_node *node)
-{
-	sun4i_a10_mmc_phase_setup(node, &mmc_output_clk);
-}
-CLK_OF_DECLARE(sun4i_a10_mmc_output, "allwinner,sun4i-a10-mmc-output-clk", sun4i_a10_mmc_output_setup);
-
-static void __init sun4i_a10_mmc_sample_setup(struct device_node *node)
-{
-	sun4i_a10_mmc_phase_setup(node, &mmc_sample_clk);
+err_free_clks:
+	kfree(clk_data->clks);
+err_free_data:
+	kfree(clk_data);
 }
-CLK_OF_DECLARE(sun4i_a10_mmc_sample, "allwinner,sun4i-a10-mmc-sample-clk", sun4i_a10_mmc_sample_setup);
+CLK_OF_DECLARE(sun4i_a10_mmc, "allwinner,sun4i-a10-mmc-clk", sun4i_a10_mmc_setup);
-- 
2.2.0

^ permalink raw reply related	[flat|nested] 8+ messages in thread

* [PATCH 2/4] ARM: sunxi: dt: Add sample and output mmc clocks
  2014-12-07 17:21 [PATCH 0/4] clk: sunxi: mmc: Last bits of phase handling Maxime Ripard
  2014-12-07 17:21 ` [PATCH 1/4] clk: sunxi: Rework MMC phase clocks Maxime Ripard
@ 2014-12-07 17:21 ` Maxime Ripard
  2014-12-07 17:21 ` [PATCH 3/4] mmc: sunxi: Convert MMC driver to the standard clock phase API Maxime Ripard
  2014-12-07 17:21 ` [PATCH 4/4] clk: sunxi: Remove custom phase function Maxime Ripard
  3 siblings, 0 replies; 8+ messages in thread
From: Maxime Ripard @ 2014-12-07 17:21 UTC (permalink / raw)
  To: linux-arm-kernel

Add the sample and output clocks for the MMC phase support.

Signed-off-by: Maxime Ripard <maxime.ripard@free-electrons.com>
---
 arch/arm/boot/dts/sun4i-a10.dtsi  | 72 ++++++++++++++++++++++++++++-----------
 arch/arm/boot/dts/sun5i-a10s.dtsi | 54 +++++++++++++++++++++--------
 arch/arm/boot/dts/sun5i-a13.dtsi  | 44 +++++++++++++++++-------
 arch/arm/boot/dts/sun6i-a31.dtsi  | 72 ++++++++++++++++++++++++++++-----------
 arch/arm/boot/dts/sun7i-a20.dtsi  | 72 ++++++++++++++++++++++++++++-----------
 arch/arm/boot/dts/sun8i-a23.dtsi  | 54 +++++++++++++++++++++--------
 6 files changed, 265 insertions(+), 103 deletions(-)

diff --git a/arch/arm/boot/dts/sun4i-a10.dtsi b/arch/arm/boot/dts/sun4i-a10.dtsi
index 7b4099fcf817..bb6b6ae95d82 100644
--- a/arch/arm/boot/dts/sun4i-a10.dtsi
+++ b/arch/arm/boot/dts/sun4i-a10.dtsi
@@ -226,35 +226,43 @@
 		};
 
 		mmc0_clk: clk at 01c20088 {
-			#clock-cells = <0>;
-			compatible = "allwinner,sun4i-a10-mod0-clk";
+			#clock-cells = <1>;
+			compatible = "allwinner,sun4i-a10-mmc-clk";
 			reg = <0x01c20088 0x4>;
 			clocks = <&osc24M>, <&pll6 1>, <&pll5 1>;
-			clock-output-names = "mmc0";
+			clock-output-names = "mmc0",
+					     "mmc0_output",
+					     "mmc0_sample";
 		};
 
 		mmc1_clk: clk at 01c2008c {
-			#clock-cells = <0>;
-			compatible = "allwinner,sun4i-a10-mod0-clk";
+			#clock-cells = <1>;
+			compatible = "allwinner,sun4i-a10-mmc-clk";
 			reg = <0x01c2008c 0x4>;
 			clocks = <&osc24M>, <&pll6 1>, <&pll5 1>;
-			clock-output-names = "mmc1";
+			clock-output-names = "mmc1",
+					     "mmc1_output",
+					     "mmc1_sample";
 		};
 
 		mmc2_clk: clk at 01c20090 {
-			#clock-cells = <0>;
-			compatible = "allwinner,sun4i-a10-mod0-clk";
+			#clock-cells = <1>;
+			compatible = "allwinner,sun4i-a10-mmc-clk";
 			reg = <0x01c20090 0x4>;
 			clocks = <&osc24M>, <&pll6 1>, <&pll5 1>;
-			clock-output-names = "mmc2";
+			clock-output-names = "mmc2",
+					     "mmc2_output",
+					     "mmc2_sample";
 		};
 
 		mmc3_clk: clk at 01c20094 {
-			#clock-cells = <0>;
-			compatible = "allwinner,sun4i-a10-mod0-clk";
+			#clock-cells = <1>;
+			compatible = "allwinner,sun4i-a10-mmc-clk";
 			reg = <0x01c20094 0x4>;
 			clocks = <&osc24M>, <&pll6 1>, <&pll5 1>;
-			clock-output-names = "mmc3";
+			clock-output-names = "mmc3",
+					     "mmc3_output",
+					     "mmc3_sample";
 		};
 
 		ts_clk: clk at 01c20098 {
@@ -398,8 +406,14 @@
 		mmc0: mmc at 01c0f000 {
 			compatible = "allwinner,sun4i-a10-mmc";
 			reg = <0x01c0f000 0x1000>;
-			clocks = <&ahb_gates 8>, <&mmc0_clk>;
-			clock-names = "ahb", "mmc";
+			clocks = <&ahb_gates 8>,
+				 <&mmc0_clk 0>,
+				 <&mmc0_clk 1>,
+				 <&mmc0_clk 2>;
+			clock-names = "ahb",
+				      "mmc",
+				      "output",
+				      "sample";
 			interrupts = <32>;
 			status = "disabled";
 		};
@@ -407,8 +421,14 @@
 		mmc1: mmc at 01c10000 {
 			compatible = "allwinner,sun4i-a10-mmc";
 			reg = <0x01c10000 0x1000>;
-			clocks = <&ahb_gates 9>, <&mmc1_clk>;
-			clock-names = "ahb", "mmc";
+			clocks = <&ahb_gates 9>,
+				 <&mmc1_clk 0>,
+				 <&mmc1_clk 1>,
+				 <&mmc1_clk 2>;
+			clock-names = "ahb",
+				      "mmc",
+				      "output",
+				      "sample";
 			interrupts = <33>;
 			status = "disabled";
 		};
@@ -416,8 +436,14 @@
 		mmc2: mmc at 01c11000 {
 			compatible = "allwinner,sun4i-a10-mmc";
 			reg = <0x01c11000 0x1000>;
-			clocks = <&ahb_gates 10>, <&mmc2_clk>;
-			clock-names = "ahb", "mmc";
+			clocks = <&ahb_gates 10>,
+				 <&mmc2_clk 0>,
+				 <&mmc2_clk 1>,
+				 <&mmc2_clk 2>;
+			clock-names = "ahb",
+				      "mmc",
+				      "output",
+				      "sample";
 			interrupts = <34>;
 			status = "disabled";
 		};
@@ -425,8 +451,14 @@
 		mmc3: mmc at 01c12000 {
 			compatible = "allwinner,sun4i-a10-mmc";
 			reg = <0x01c12000 0x1000>;
-			clocks = <&ahb_gates 11>, <&mmc3_clk>;
-			clock-names = "ahb", "mmc";
+			clocks = <&ahb_gates 11>,
+				 <&mmc3_clk 0>,
+				 <&mmc3_clk 1>,
+				 <&mmc3_clk 2>;
+			clock-names = "ahb",
+				      "mmc",
+				      "output",
+				      "sample";
 			interrupts = <35>;
 			status = "disabled";
 		};
diff --git a/arch/arm/boot/dts/sun5i-a10s.dtsi b/arch/arm/boot/dts/sun5i-a10s.dtsi
index 1b76667f3182..0e011427615f 100644
--- a/arch/arm/boot/dts/sun5i-a10s.dtsi
+++ b/arch/arm/boot/dts/sun5i-a10s.dtsi
@@ -211,27 +211,33 @@
 		};
 
 		mmc0_clk: clk at 01c20088 {
-			#clock-cells = <0>;
-			compatible = "allwinner,sun4i-a10-mod0-clk";
+			#clock-cells = <1>;
+			compatible = "allwinner,sun4i-a10-mmc-clk";
 			reg = <0x01c20088 0x4>;
 			clocks = <&osc24M>, <&pll6 1>, <&pll5 1>;
-			clock-output-names = "mmc0";
+			clock-output-names = "mmc0",
+					     "mmc0_output",
+					     "mmc0_sample";
 		};
 
 		mmc1_clk: clk at 01c2008c {
-			#clock-cells = <0>;
-			compatible = "allwinner,sun4i-a10-mod0-clk";
+			#clock-cells = <1>;
+			compatible = "allwinner,sun4i-a10-mmc-clk";
 			reg = <0x01c2008c 0x4>;
 			clocks = <&osc24M>, <&pll6 1>, <&pll5 1>;
-			clock-output-names = "mmc1";
+			clock-output-names = "mmc1",
+					     "mmc1_output",
+					     "mmc1_sample";
 		};
 
 		mmc2_clk: clk at 01c20090 {
-			#clock-cells = <0>;
-			compatible = "allwinner,sun4i-a10-mod0-clk";
+			#clock-cells = <1>;
+			compatible = "allwinner,sun4i-a10-mmc-clk";
 			reg = <0x01c20090 0x4>;
 			clocks = <&osc24M>, <&pll6 1>, <&pll5 1>;
-			clock-output-names = "mmc2";
+			clock-output-names = "mmc2",
+					     "mmc2_output",
+					     "mmc2_sample";
 		};
 
 		ts_clk: clk at 01c20098 {
@@ -359,8 +365,14 @@
 		mmc0: mmc at 01c0f000 {
 			compatible = "allwinner,sun5i-a13-mmc";
 			reg = <0x01c0f000 0x1000>;
-			clocks = <&ahb_gates 8>, <&mmc0_clk>;
-			clock-names = "ahb", "mmc";
+			clocks = <&ahb_gates 8>,
+				 <&mmc0_clk 0>,
+				 <&mmc0_clk 1>,
+				 <&mmc0_clk 2>;
+			clock-names = "ahb",
+				      "mmc",
+				      "output",
+				      "sample";
 			interrupts = <32>;
 			status = "disabled";
 		};
@@ -368,8 +380,14 @@
 		mmc1: mmc at 01c10000 {
 			compatible = "allwinner,sun5i-a13-mmc";
 			reg = <0x01c10000 0x1000>;
-			clocks = <&ahb_gates 9>, <&mmc1_clk>;
-			clock-names = "ahb", "mmc";
+			clocks = <&ahb_gates 9>,
+				 <&mmc1_clk 0>,
+				 <&mmc1_clk 1>,
+				 <&mmc1_clk 2>;
+			clock-names = "ahb",
+				      "mmc",
+				      "output",
+				      "sample";
 			interrupts = <33>;
 			status = "disabled";
 		};
@@ -377,8 +395,14 @@
 		mmc2: mmc at 01c11000 {
 			compatible = "allwinner,sun5i-a13-mmc";
 			reg = <0x01c11000 0x1000>;
-			clocks = <&ahb_gates 10>, <&mmc2_clk>;
-			clock-names = "ahb", "mmc";
+			clocks = <&ahb_gates 10>,
+				 <&mmc2_clk 0>,
+				 <&mmc2_clk 1>,
+				 <&mmc2_clk 2>;
+			clock-names = "ahb",
+				      "mmc",
+				      "output",
+				      "sample";
 			interrupts = <34>;
 			status = "disabled";
 		};
diff --git a/arch/arm/boot/dts/sun5i-a13.dtsi b/arch/arm/boot/dts/sun5i-a13.dtsi
index c35217ea1f64..cbb63b750e08 100644
--- a/arch/arm/boot/dts/sun5i-a13.dtsi
+++ b/arch/arm/boot/dts/sun5i-a13.dtsi
@@ -195,27 +195,33 @@
 		};
 
 		mmc0_clk: clk at 01c20088 {
-			#clock-cells = <0>;
-			compatible = "allwinner,sun4i-a10-mod0-clk";
+			#clock-cells = <1>;
+			compatible = "allwinner,sun4i-a10-mmc-clk";
 			reg = <0x01c20088 0x4>;
 			clocks = <&osc24M>, <&pll6 1>, <&pll5 1>;
-			clock-output-names = "mmc0";
+			clock-output-names = "mmc0",
+					     "mmc0_output",
+					     "mmc0_sample";
 		};
 
 		mmc1_clk: clk at 01c2008c {
-			#clock-cells = <0>;
-			compatible = "allwinner,sun4i-a10-mod0-clk";
+			#clock-cells = <1>;
+			compatible = "allwinner,sun4i-a10-mmc-clk";
 			reg = <0x01c2008c 0x4>;
 			clocks = <&osc24M>, <&pll6 1>, <&pll5 1>;
-			clock-output-names = "mmc1";
+			clock-output-names = "mmc1",
+					     "mmc1_output",
+					     "mmc1_sample";
 		};
 
 		mmc2_clk: clk at 01c20090 {
-			#clock-cells = <0>;
-			compatible = "allwinner,sun4i-a10-mod0-clk";
+			#clock-cells = <1>;
+			compatible = "allwinner,sun4i-a10-mmc-clk";
 			reg = <0x01c20090 0x4>;
 			clocks = <&osc24M>, <&pll6 1>, <&pll5 1>;
-			clock-output-names = "mmc2";
+			clock-output-names = "mmc2",
+					     "mmc2_output",
+					     "mmc2_sample";
 		};
 
 		ts_clk: clk at 01c20098 {
@@ -327,8 +333,14 @@
 		mmc0: mmc at 01c0f000 {
 			compatible = "allwinner,sun5i-a13-mmc";
 			reg = <0x01c0f000 0x1000>;
-			clocks = <&ahb_gates 8>, <&mmc0_clk>;
-			clock-names = "ahb", "mmc";
+			clocks = <&ahb_gates 8>,
+				 <&mmc0_clk 0>,
+				 <&mmc0_clk 1>,
+				 <&mmc0_clk 2>;
+			clock-names = "ahb",
+				      "mmc",
+				      "output",
+				      "sample";
 			interrupts = <32>;
 			status = "disabled";
 		};
@@ -336,8 +348,14 @@
 		mmc2: mmc at 01c11000 {
 			compatible = "allwinner,sun5i-a13-mmc";
 			reg = <0x01c11000 0x1000>;
-			clocks = <&ahb_gates 10>, <&mmc2_clk>;
-			clock-names = "ahb", "mmc";
+			clocks = <&ahb_gates 10>,
+				 <&mmc2_clk 0>,
+				 <&mmc2_clk 1>,
+				 <&mmc2_clk 2>;
+			clock-names = "ahb",
+				      "mmc",
+				      "output",
+				      "sample";
 			interrupts = <34>;
 			status = "disabled";
 		};
diff --git a/arch/arm/boot/dts/sun6i-a31.dtsi b/arch/arm/boot/dts/sun6i-a31.dtsi
index 62d932e9b7d1..3e7db5191516 100644
--- a/arch/arm/boot/dts/sun6i-a31.dtsi
+++ b/arch/arm/boot/dts/sun6i-a31.dtsi
@@ -241,35 +241,43 @@
 		};
 
 		mmc0_clk: clk at 01c20088 {
-			#clock-cells = <0>;
-			compatible = "allwinner,sun4i-a10-mod0-clk";
+			#clock-cells = <1>;
+			compatible = "allwinner,sun4i-a10-mmc-clk";
 			reg = <0x01c20088 0x4>;
 			clocks = <&osc24M>, <&pll6 0>;
-			clock-output-names = "mmc0";
+			clock-output-names = "mmc0",
+					     "mmc0_output",
+					     "mmc0_sample";
 		};
 
 		mmc1_clk: clk at 01c2008c {
-			#clock-cells = <0>;
-			compatible = "allwinner,sun4i-a10-mod0-clk";
+			#clock-cells = <1>;
+			compatible = "allwinner,sun4i-a10-mmc-clk";
 			reg = <0x01c2008c 0x4>;
 			clocks = <&osc24M>, <&pll6 0>;
-			clock-output-names = "mmc1";
+			clock-output-names = "mmc1",
+					     "mmc1_output",
+					     "mmc1_sample";
 		};
 
 		mmc2_clk: clk at 01c20090 {
-			#clock-cells = <0>;
-			compatible = "allwinner,sun4i-a10-mod0-clk";
+			#clock-cells = <1>;
+			compatible = "allwinner,sun4i-a10-mmc-clk";
 			reg = <0x01c20090 0x4>;
 			clocks = <&osc24M>, <&pll6 0>;
-			clock-output-names = "mmc2";
+			clock-output-names = "mmc2",
+					     "mmc2_output",
+					     "mmc2_sample";
 		};
 
 		mmc3_clk: clk at 01c20094 {
-			#clock-cells = <0>;
-			compatible = "allwinner,sun4i-a10-mod0-clk";
+			#clock-cells = <1>;
+			compatible = "allwinner,sun4i-a10-mmc-clk";
 			reg = <0x01c20094 0x4>;
 			clocks = <&osc24M>, <&pll6 0>;
-			clock-output-names = "mmc3";
+			clock-output-names = "mmc3",
+					     "mmc3_output",
+					     "mmc3_sample";
 		};
 
 		spi0_clk: clk at 01c200a0 {
@@ -366,8 +374,14 @@
 		mmc0: mmc at 01c0f000 {
 			compatible = "allwinner,sun5i-a13-mmc";
 			reg = <0x01c0f000 0x1000>;
-			clocks = <&ahb1_gates 8>, <&mmc0_clk>;
-			clock-names = "ahb", "mmc";
+			clocks = <&ahb1_gates 8>,
+				 <&mmc0_clk 0>,
+				 <&mmc0_clk 1>,
+				 <&mmc0_clk 2>;
+			clock-names = "ahb",
+				      "mmc",
+				      "output",
+				      "sample";
 			resets = <&ahb1_rst 8>;
 			reset-names = "ahb";
 			interrupts = <0 60 4>;
@@ -377,8 +391,14 @@
 		mmc1: mmc at 01c10000 {
 			compatible = "allwinner,sun5i-a13-mmc";
 			reg = <0x01c10000 0x1000>;
-			clocks = <&ahb1_gates 9>, <&mmc1_clk>;
-			clock-names = "ahb", "mmc";
+			clocks = <&ahb1_gates 9>,
+				 <&mmc1_clk 0>,
+				 <&mmc1_clk 1>,
+				 <&mmc1_clk 2>;
+			clock-names = "ahb",
+				      "mmc",
+				      "output",
+				      "sample";
 			resets = <&ahb1_rst 9>;
 			reset-names = "ahb";
 			interrupts = <0 61 4>;
@@ -388,8 +408,14 @@
 		mmc2: mmc at 01c11000 {
 			compatible = "allwinner,sun5i-a13-mmc";
 			reg = <0x01c11000 0x1000>;
-			clocks = <&ahb1_gates 10>, <&mmc2_clk>;
-			clock-names = "ahb", "mmc";
+			clocks = <&ahb1_gates 10>,
+				 <&mmc2_clk 0>,
+				 <&mmc2_clk 1>,
+				 <&mmc2_clk 2>;
+			clock-names = "ahb",
+				      "mmc",
+				      "output",
+				      "sample";
 			resets = <&ahb1_rst 10>;
 			reset-names = "ahb";
 			interrupts = <0 62 4>;
@@ -399,8 +425,14 @@
 		mmc3: mmc at 01c12000 {
 			compatible = "allwinner,sun5i-a13-mmc";
 			reg = <0x01c12000 0x1000>;
-			clocks = <&ahb1_gates 11>, <&mmc3_clk>;
-			clock-names = "ahb", "mmc";
+			clocks = <&ahb1_gates 11>,
+				 <&mmc3_clk 0>,
+				 <&mmc3_clk 1>,
+				 <&mmc3_clk 2>;
+			clock-names = "ahb",
+				      "mmc",
+				      "output",
+				      "sample";
 			resets = <&ahb1_rst 11>;
 			reset-names = "ahb";
 			interrupts = <0 63 4>;
diff --git a/arch/arm/boot/dts/sun7i-a20.dtsi b/arch/arm/boot/dts/sun7i-a20.dtsi
index e21ce5992d56..fa51bffcaf1d 100644
--- a/arch/arm/boot/dts/sun7i-a20.dtsi
+++ b/arch/arm/boot/dts/sun7i-a20.dtsi
@@ -274,35 +274,43 @@
 		};
 
 		mmc0_clk: clk at 01c20088 {
-			#clock-cells = <0>;
-			compatible = "allwinner,sun4i-a10-mod0-clk";
+			#clock-cells = <1>;
+			compatible = "allwinner,sun4i-a10-mmc-clk";
 			reg = <0x01c20088 0x4>;
 			clocks = <&osc24M>, <&pll6 1>, <&pll5 1>;
-			clock-output-names = "mmc0";
+			clock-output-names = "mmc0",
+					     "mmc0_output",
+					     "mmc0_sample";
 		};
 
 		mmc1_clk: clk at 01c2008c {
-			#clock-cells = <0>;
-			compatible = "allwinner,sun4i-a10-mod0-clk";
+			#clock-cells = <1>;
+			compatible = "allwinner,sun4i-a10-mmc-clk";
 			reg = <0x01c2008c 0x4>;
 			clocks = <&osc24M>, <&pll6 1>, <&pll5 1>;
-			clock-output-names = "mmc1";
+			clock-output-names = "mmc1",
+					     "mmc1_output",
+					     "mmc1_sample";
 		};
 
 		mmc2_clk: clk at 01c20090 {
-			#clock-cells = <0>;
-			compatible = "allwinner,sun4i-a10-mod0-clk";
+			#clock-cells = <1>;
+			compatible = "allwinner,sun4i-a10-mmc-clk";
 			reg = <0x01c20090 0x4>;
 			clocks = <&osc24M>, <&pll6 1>, <&pll5 1>;
-			clock-output-names = "mmc2";
+			clock-output-names = "mmc2",
+					     "mmc2_output",
+					     "mmc2_sample";
 		};
 
 		mmc3_clk: clk at 01c20094 {
-			#clock-cells = <0>;
-			compatible = "allwinner,sun4i-a10-mod0-clk";
+			#clock-cells = <1>;
+			compatible = "allwinner,sun4i-a10-mmc-clk";
 			reg = <0x01c20094 0x4>;
 			clocks = <&osc24M>, <&pll6 1>, <&pll5 1>;
-			clock-output-names = "mmc3";
+			clock-output-names = "mmc3",
+					     "mmc3_output",
+					     "mmc3_sample";
 		};
 
 		ts_clk: clk at 01c20098 {
@@ -518,8 +526,14 @@
 		mmc0: mmc at 01c0f000 {
 			compatible = "allwinner,sun5i-a13-mmc";
 			reg = <0x01c0f000 0x1000>;
-			clocks = <&ahb_gates 8>, <&mmc0_clk>;
-			clock-names = "ahb", "mmc";
+			clocks = <&ahb_gates 8>,
+				 <&mmc0_clk 0>,
+				 <&mmc0_clk 1>,
+				 <&mmc0_clk 2>;
+			clock-names = "ahb",
+				      "mmc",
+				      "output",
+				      "sample";
 			interrupts = <0 32 4>;
 			status = "disabled";
 		};
@@ -527,8 +541,14 @@
 		mmc1: mmc at 01c10000 {
 			compatible = "allwinner,sun5i-a13-mmc";
 			reg = <0x01c10000 0x1000>;
-			clocks = <&ahb_gates 9>, <&mmc1_clk>;
-			clock-names = "ahb", "mmc";
+			clocks = <&ahb_gates 9>,
+				 <&mmc1_clk 0>,
+				 <&mmc1_clk 1>,
+				 <&mmc1_clk 2>;
+			clock-names = "ahb",
+				      "mmc",
+				      "output",
+				      "sample";
 			interrupts = <0 33 4>;
 			status = "disabled";
 		};
@@ -536,8 +556,14 @@
 		mmc2: mmc at 01c11000 {
 			compatible = "allwinner,sun5i-a13-mmc";
 			reg = <0x01c11000 0x1000>;
-			clocks = <&ahb_gates 10>, <&mmc2_clk>;
-			clock-names = "ahb", "mmc";
+			clocks = <&ahb_gates 10>,
+				 <&mmc2_clk 0>,
+				 <&mmc2_clk 1>,
+				 <&mmc2_clk 2>;
+			clock-names = "ahb",
+				      "mmc",
+				      "output",
+				      "sample";
 			interrupts = <0 34 4>;
 			status = "disabled";
 		};
@@ -545,8 +571,14 @@
 		mmc3: mmc at 01c12000 {
 			compatible = "allwinner,sun5i-a13-mmc";
 			reg = <0x01c12000 0x1000>;
-			clocks = <&ahb_gates 11>, <&mmc3_clk>;
-			clock-names = "ahb", "mmc";
+			clocks = <&ahb_gates 11>,
+				 <&mmc3_clk 0>,
+				 <&mmc3_clk 1>,
+				 <&mmc3_clk 2>;
+			clock-names = "ahb",
+				      "mmc",
+				      "output",
+				      "sample";
 			interrupts = <0 35 4>;
 			status = "disabled";
 		};
diff --git a/arch/arm/boot/dts/sun8i-a23.dtsi b/arch/arm/boot/dts/sun8i-a23.dtsi
index 2fcccf0cbcee..79dc07d0d596 100644
--- a/arch/arm/boot/dts/sun8i-a23.dtsi
+++ b/arch/arm/boot/dts/sun8i-a23.dtsi
@@ -209,27 +209,33 @@
 		};
 
 		mmc0_clk: clk at 01c20088 {
-			#clock-cells = <0>;
-			compatible = "allwinner,sun4i-a10-mod0-clk";
+			#clock-cells = <1>;
+			compatible = "allwinner,sun4i-a10-mmc-clk";
 			reg = <0x01c20088 0x4>;
 			clocks = <&osc24M>, <&pll6 0>;
-			clock-output-names = "mmc0";
+			clock-output-names = "mmc0",
+					     "mmc0_output",
+					     "mmc0_sample";
 		};
 
 		mmc1_clk: clk at 01c2008c {
-			#clock-cells = <0>;
-			compatible = "allwinner,sun4i-a10-mod0-clk";
+			#clock-cells = <1>;
+			compatible = "allwinner,sun4i-a10-mmc-clk";
 			reg = <0x01c2008c 0x4>;
 			clocks = <&osc24M>, <&pll6 0>;
-			clock-output-names = "mmc1";
+			clock-output-names = "mmc1",
+					     "mmc1_output",
+					     "mmc1_sample";
 		};
 
 		mmc2_clk: clk at 01c20090 {
-			#clock-cells = <0>;
-			compatible = "allwinner,sun4i-a10-mod0-clk";
+			#clock-cells = <1>;
+			compatible = "allwinner,sun4i-a10-mmc-clk";
 			reg = <0x01c20090 0x4>;
 			clocks = <&osc24M>, <&pll6 0>;
-			clock-output-names = "mmc2";
+			clock-output-names = "mmc2",
+					     "mmc2_output",
+					     "mmc2_sample";
 		};
 
 		mbus_clk: clk at 01c2015c {
@@ -259,8 +265,14 @@
 		mmc0: mmc at 01c0f000 {
 			compatible = "allwinner,sun5i-a13-mmc";
 			reg = <0x01c0f000 0x1000>;
-			clocks = <&ahb1_gates 8>, <&mmc0_clk>;
-			clock-names = "ahb", "mmc";
+			clocks = <&ahb_gates 8>,
+				 <&mmc0_clk 0>,
+				 <&mmc0_clk 1>,
+				 <&mmc0_clk 2>;
+			clock-names = "ahb",
+				      "mmc",
+				      "output",
+				      "sample";
 			resets = <&ahb1_rst 8>;
 			reset-names = "ahb";
 			interrupts = <0 60 4>;
@@ -270,8 +282,14 @@
 		mmc1: mmc at 01c10000 {
 			compatible = "allwinner,sun5i-a13-mmc";
 			reg = <0x01c10000 0x1000>;
-			clocks = <&ahb1_gates 9>, <&mmc1_clk>;
-			clock-names = "ahb", "mmc";
+			clocks = <&ahb_gates 9>,
+				 <&mmc1_clk 0>,
+				 <&mmc1_clk 1>,
+				 <&mmc1_clk 2>;
+			clock-names = "ahb",
+				      "mmc",
+				      "output",
+				      "sample";
 			resets = <&ahb1_rst 9>;
 			reset-names = "ahb";
 			interrupts = <0 61 4>;
@@ -281,8 +299,14 @@
 		mmc2: mmc at 01c11000 {
 			compatible = "allwinner,sun5i-a13-mmc";
 			reg = <0x01c11000 0x1000>;
-			clocks = <&ahb1_gates 10>, <&mmc2_clk>;
-			clock-names = "ahb", "mmc";
+			clocks = <&ahb_gates 10>,
+				 <&mmc2_clk 0>,
+				 <&mmc2_clk 1>,
+				 <&mmc2_clk 2>;
+			clock-names = "ahb",
+				      "mmc",
+				      "output",
+				      "sample";
 			resets = <&ahb1_rst 10>;
 			reset-names = "ahb";
 			interrupts = <0 62 4>;
-- 
2.2.0

^ permalink raw reply related	[flat|nested] 8+ messages in thread

* [PATCH 3/4] mmc: sunxi: Convert MMC driver to the standard clock phase API
  2014-12-07 17:21 [PATCH 0/4] clk: sunxi: mmc: Last bits of phase handling Maxime Ripard
  2014-12-07 17:21 ` [PATCH 1/4] clk: sunxi: Rework MMC phase clocks Maxime Ripard
  2014-12-07 17:21 ` [PATCH 2/4] ARM: sunxi: dt: Add sample and output mmc clocks Maxime Ripard
@ 2014-12-07 17:21 ` Maxime Ripard
  2014-12-07 17:21 ` [PATCH 4/4] clk: sunxi: Remove custom phase function Maxime Ripard
  3 siblings, 0 replies; 8+ messages in thread
From: Maxime Ripard @ 2014-12-07 17:21 UTC (permalink / raw)
  To: linux-arm-kernel

Now that we have proper support to use the generic phase API in our clock
driver, switch the MMC driver to use it.

Signed-off-by: Maxime Ripard <maxime.ripard@free-electrons.com>
Acked-by: Ulf Hansson <ulf.hansson@linaro.org>
Acked-by: David Lanzend?rfer <david.lanzendoerfer@o2s.ch>
---
 .../devicetree/bindings/mmc/sunxi-mmc.txt          |  8 +--
 drivers/mmc/host/sunxi-mmc.c                       | 72 +++++++++++++++-------
 2 files changed, 53 insertions(+), 27 deletions(-)

diff --git a/Documentation/devicetree/bindings/mmc/sunxi-mmc.txt b/Documentation/devicetree/bindings/mmc/sunxi-mmc.txt
index 91b3a3467150..4bf41d833804 100644
--- a/Documentation/devicetree/bindings/mmc/sunxi-mmc.txt
+++ b/Documentation/devicetree/bindings/mmc/sunxi-mmc.txt
@@ -10,8 +10,8 @@ Absolute maximum transfer rate is 200MB/s
 Required properties:
  - compatible : "allwinner,sun4i-a10-mmc" or "allwinner,sun5i-a13-mmc"
  - reg : mmc controller base registers
- - clocks : a list with 2 phandle + clock specifier pairs
- - clock-names : must contain "ahb" and "mmc"
+ - clocks : a list with 4 phandle + clock specifier pairs
+ - clock-names : must contain "ahb", "mmc", "output" and "sample"
  - interrupts : mmc controller interrupt
 
 Optional properties:
@@ -25,8 +25,8 @@ Examples:
 	mmc0: mmc at 01c0f000 {
 		compatible = "allwinner,sun5i-a13-mmc";
 		reg = <0x01c0f000 0x1000>;
-		clocks = <&ahb_gates 8>, <&mmc0_clk>;
-		clock-names = "ahb", "mod";
+		clocks = <&ahb_gates 8>, <&mmc0_clk>, <&mmc0_output_clk>, <&mmc0_sample_clk>;
+		clock-names = "ahb", "mod", "output", "sample";
 		interrupts = <0 32 4>;
 		status = "disabled";
 	};
diff --git a/drivers/mmc/host/sunxi-mmc.c b/drivers/mmc/host/sunxi-mmc.c
index d1663b3c4143..afe20c322e55 100644
--- a/drivers/mmc/host/sunxi-mmc.c
+++ b/drivers/mmc/host/sunxi-mmc.c
@@ -22,7 +22,6 @@
 
 #include <linux/clk.h>
 #include <linux/clk-private.h>
-#include <linux/clk/sunxi.h>
 
 #include <linux/gpio.h>
 #include <linux/platform_device.h>
@@ -230,6 +229,8 @@ struct sunxi_mmc_host {
 	/* clock management */
 	struct clk	*clk_ahb;
 	struct clk	*clk_mmc;
+	struct clk	*clk_sample;
+	struct clk	*clk_output;
 
 	/* irq */
 	spinlock_t	lock;
@@ -617,7 +618,7 @@ static int sunxi_mmc_oclk_onoff(struct sunxi_mmc_host *host, u32 oclk_en)
 static int sunxi_mmc_clk_set_rate(struct sunxi_mmc_host *host,
 				  struct mmc_ios *ios)
 {
-	u32 rate, oclk_dly, rval, sclk_dly, src_clk;
+	u32 rate, oclk_dly, rval, sclk_dly;
 	int ret;
 
 	rate = clk_round_rate(host->clk_mmc, ios->clock);
@@ -643,34 +644,31 @@ static int sunxi_mmc_clk_set_rate(struct sunxi_mmc_host *host,
 
 	/* determine delays */
 	if (rate <= 400000) {
-		oclk_dly = 0;
-		sclk_dly = 7;
+		oclk_dly = 180;
+		sclk_dly = 42;
 	} else if (rate <= 25000000) {
-		oclk_dly = 0;
-		sclk_dly = 5;
+		oclk_dly = 180;
+		sclk_dly = 75;
 	} else if (rate <= 50000000) {
 		if (ios->timing == MMC_TIMING_UHS_DDR50) {
-			oclk_dly = 2;
-			sclk_dly = 4;
+			oclk_dly = 60;
+			sclk_dly = 120;
 		} else {
-			oclk_dly = 3;
-			sclk_dly = 5;
+			oclk_dly = 90;
+			sclk_dly = 150;
 		}
+	} else if (rate <= 100000000) {
+		oclk_dly = 6;
+		sclk_dly = 24;
+	} else if (rate <= 200000000) {
+		oclk_dly = 3;
+		sclk_dly = 12;
 	} else {
-		/* rate > 50000000 */
-		oclk_dly = 2;
-		sclk_dly = 4;
+		return -EINVAL;
 	}
 
-	src_clk = clk_get_rate(clk_get_parent(host->clk_mmc));
-	if (src_clk >= 300000000 && src_clk <= 400000000) {
-		if (oclk_dly)
-			oclk_dly--;
-		if (sclk_dly)
-			sclk_dly--;
-	}
-
-	clk_sunxi_mmc_phase_control(host->clk_mmc, sclk_dly, oclk_dly);
+	clk_set_phase(host->clk_sample, sclk_dly);
+	clk_set_phase(host->clk_output, oclk_dly);
 
 	return sunxi_mmc_oclk_onoff(host, 1);
 }
@@ -909,6 +907,18 @@ static int sunxi_mmc_resource_request(struct sunxi_mmc_host *host,
 		return PTR_ERR(host->clk_mmc);
 	}
 
+	host->clk_output = devm_clk_get(&pdev->dev, "output");
+	if (IS_ERR(host->clk_output)) {
+		dev_err(&pdev->dev, "Could not get output clock\n");
+		return PTR_ERR(host->clk_output);
+	}
+
+	host->clk_sample = devm_clk_get(&pdev->dev, "sample");
+	if (IS_ERR(host->clk_sample)) {
+		dev_err(&pdev->dev, "Could not get sample clock\n");
+		return PTR_ERR(host->clk_sample);
+	}
+
 	host->reset = devm_reset_control_get(&pdev->dev, "ahb");
 
 	ret = clk_prepare_enable(host->clk_ahb);
@@ -923,11 +933,23 @@ static int sunxi_mmc_resource_request(struct sunxi_mmc_host *host,
 		goto error_disable_clk_ahb;
 	}
 
+	ret = clk_prepare_enable(host->clk_output);
+	if (ret) {
+		dev_err(&pdev->dev, "Enable output clk err %d\n", ret);
+		goto error_disable_clk_mmc;
+	}
+
+	ret = clk_prepare_enable(host->clk_sample);
+	if (ret) {
+		dev_err(&pdev->dev, "Enable sample clk err %d\n", ret);
+		goto error_disable_clk_output;
+	}
+
 	if (!IS_ERR(host->reset)) {
 		ret = reset_control_deassert(host->reset);
 		if (ret) {
 			dev_err(&pdev->dev, "reset err %d\n", ret);
-			goto error_disable_clk_mmc;
+			goto error_disable_clk_sample;
 		}
 	}
 
@@ -946,6 +968,10 @@ static int sunxi_mmc_resource_request(struct sunxi_mmc_host *host,
 error_assert_reset:
 	if (!IS_ERR(host->reset))
 		reset_control_assert(host->reset);
+error_disable_clk_sample:
+	clk_disable_unprepare(host->clk_sample);
+error_disable_clk_output:
+	clk_disable_unprepare(host->clk_output);
 error_disable_clk_mmc:
 	clk_disable_unprepare(host->clk_mmc);
 error_disable_clk_ahb:
-- 
2.2.0

^ permalink raw reply related	[flat|nested] 8+ messages in thread

* [PATCH 4/4] clk: sunxi: Remove custom phase function
  2014-12-07 17:21 [PATCH 0/4] clk: sunxi: mmc: Last bits of phase handling Maxime Ripard
                   ` (2 preceding siblings ...)
  2014-12-07 17:21 ` [PATCH 3/4] mmc: sunxi: Convert MMC driver to the standard clock phase API Maxime Ripard
@ 2014-12-07 17:21 ` Maxime Ripard
  3 siblings, 0 replies; 8+ messages in thread
From: Maxime Ripard @ 2014-12-07 17:21 UTC (permalink / raw)
  To: linux-arm-kernel

Now that we don't have any user left for our custom phase function, we can
safely remove this hack from the code.

Signed-off-by: Maxime Ripard <maxime.ripard@free-electrons.com>
---
 drivers/clk/sunxi/clk-sunxi.c | 37 -------------------------------------
 include/linux/clk/sunxi.h     | 22 ----------------------
 2 files changed, 59 deletions(-)
 delete mode 100644 include/linux/clk/sunxi.h

diff --git a/drivers/clk/sunxi/clk-sunxi.c b/drivers/clk/sunxi/clk-sunxi.c
index 68ac9f068c4b..fab22c68d05e 100644
--- a/drivers/clk/sunxi/clk-sunxi.c
+++ b/drivers/clk/sunxi/clk-sunxi.c
@@ -563,43 +563,6 @@ static void sun7i_a20_get_out_factors(u32 *freq, u32 parent_rate,
 }
 
 /**
- * clk_sunxi_mmc_phase_control() - configures MMC clock phase control
- */
-
-void clk_sunxi_mmc_phase_control(struct clk *clk, u8 sample, u8 output)
-{
-	#define to_clk_composite(_hw) container_of(_hw, struct clk_composite, hw)
-	#define to_clk_factors(_hw) container_of(_hw, struct clk_factors, hw)
-
-	struct clk_hw *hw = __clk_get_hw(clk);
-	struct clk_composite *composite = to_clk_composite(hw);
-	struct clk_hw *rate_hw = composite->rate_hw;
-	struct clk_factors *factors = to_clk_factors(rate_hw);
-	unsigned long flags = 0;
-	u32 reg;
-
-	if (factors->lock)
-		spin_lock_irqsave(factors->lock, flags);
-
-	reg = readl(factors->reg);
-
-	/* set sample clock phase control */
-	reg &= ~(0x7 << 20);
-	reg |= ((sample & 0x7) << 20);
-
-	/* set output clock phase control */
-	reg &= ~(0x7 << 8);
-	reg |= ((output & 0x7) << 8);
-
-	writel(reg, factors->reg);
-
-	if (factors->lock)
-		spin_unlock_irqrestore(factors->lock, flags);
-}
-EXPORT_SYMBOL(clk_sunxi_mmc_phase_control);
-
-
-/**
  * sunxi_factors_clk_setup() - Setup function for factor clocks
  */
 
diff --git a/include/linux/clk/sunxi.h b/include/linux/clk/sunxi.h
deleted file mode 100644
index aed28c4451d9..000000000000
--- a/include/linux/clk/sunxi.h
+++ /dev/null
@@ -1,22 +0,0 @@
-/*
- * Copyright 2013 - Hans de Goede <hdegoede@redhat.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.
- */
-
-#ifndef __LINUX_CLK_SUNXI_H_
-#define __LINUX_CLK_SUNXI_H_
-
-#include <linux/clk.h>
-
-void clk_sunxi_mmc_phase_control(struct clk *clk, u8 sample, u8 output);
-
-#endif
-- 
2.2.0

^ permalink raw reply related	[flat|nested] 8+ messages in thread

* [PATCH 1/4] clk: sunxi: Rework MMC phase clocks
  2014-12-07 17:21 ` [PATCH 1/4] clk: sunxi: Rework MMC phase clocks Maxime Ripard
@ 2014-12-08 16:53   ` Chen-Yu Tsai
  2014-12-09  3:26     ` Chen-Yu Tsai
  2014-12-09 10:53     ` Maxime Ripard
  0 siblings, 2 replies; 8+ messages in thread
From: Chen-Yu Tsai @ 2014-12-08 16:53 UTC (permalink / raw)
  To: linux-arm-kernel

On Mon, Dec 8, 2014 at 1:21 AM, Maxime Ripard
<maxime.ripard@free-electrons.com> wrote:
> Instead of having three different clocks for the main MMC clock and the two
> phase sub-clocks, which involved having three different drivers sharing the
> same register, rework it to have the same single driver registering three
> different clocks.
>
> Signed-off-by: Maxime Ripard <maxime.ripard@free-electrons.com>
> ---
>  drivers/clk/sunxi/clk-mod0.c | 129 ++++++++++++++++++++++---------------------
>  1 file changed, 67 insertions(+), 62 deletions(-)
>
> diff --git a/drivers/clk/sunxi/clk-mod0.c b/drivers/clk/sunxi/clk-mod0.c
> index 658d74f39451..24522c5b94ae 100644
> --- a/drivers/clk/sunxi/clk-mod0.c
> +++ b/drivers/clk/sunxi/clk-mod0.c
> @@ -115,19 +115,17 @@ static void __init sun5i_a13_mbus_setup(struct device_node *node)
>  }
>  CLK_OF_DECLARE(sun5i_a13_mbus, "allwinner,sun5i-a13-mbus-clk", sun5i_a13_mbus_setup);
>
> -struct mmc_phase_data {
> -       u8      offset;
> -};
> -
>  struct mmc_phase {
>         struct clk_hw           hw;
> +       u8                      offset;
>         void __iomem            *reg;
> -       struct mmc_phase_data   *data;
>         spinlock_t              *lock;
>  };
>
>  #define to_mmc_phase(_hw) container_of(_hw, struct mmc_phase, hw)
>
> +static DEFINE_SPINLOCK(sun4i_a10_mmc_lock);
> +

I'd move this to just above the setup function.
The get/set_phase callbacks don't need it.

>  static int mmc_get_phase(struct clk_hw *hw)
>  {
>         struct clk *mmc, *mmc_parent, *clk = hw->clk;
> @@ -138,7 +136,7 @@ static int mmc_get_phase(struct clk_hw *hw)
>         u8 delay;
>
>         value = readl(phase->reg);
> -       delay = (value >> phase->data->offset) & 0x3;
> +       delay = (value >> phase->offset) & 0x3;
>
>         if (!delay)
>                 return 180;
> @@ -226,8 +224,8 @@ static int mmc_set_phase(struct clk_hw *hw, int degrees)
>
>         spin_lock_irqsave(phase->lock, flags);
>         value = readl(phase->reg);
> -       value &= ~GENMASK(phase->data->offset + 3, phase->data->offset);
> -       value |= delay << phase->data->offset;
> +       value &= ~GENMASK(phase->offset + 3, phase->offset);
> +       value |= delay << phase->offset;
>         writel(value, phase->reg);
>         spin_unlock_irqrestore(phase->lock, flags);
>
> @@ -239,66 +237,73 @@ static const struct clk_ops mmc_clk_ops = {
>         .set_phase      = mmc_set_phase,
>  };
>
> -static void __init sun4i_a10_mmc_phase_setup(struct device_node *node,
> -                                            struct mmc_phase_data *data)
> +static void __init sun4i_a10_mmc_setup(struct device_node *node)
>  {
> -       const char *parent_names[1] = { of_clk_get_parent_name(node, 0) };
> -       struct clk_init_data init = {
> -               .num_parents    = 1,
> -               .parent_names   = parent_names,
> -               .ops            = &mmc_clk_ops,
> -       };
> -
> -       struct mmc_phase *phase;
> -       struct clk *clk;
> -
> -       phase = kmalloc(sizeof(*phase), GFP_KERNEL);
> -       if (!phase)
> -               return;
> -
> -       phase->hw.init = &init;
> -
> -       phase->reg = of_iomap(node, 0);
> -       if (!phase->reg)
> -               goto err_free;
> +       struct clk_onecell_data *clk_data;
> +       const char *parent;
> +       void __iomem *reg;
> +       int i;
>
> -       phase->data = data;
> -       phase->lock = &sun4i_a10_mod0_lock;
> +       reg = of_io_request_and_map(node, 0, of_node_full_name(node));
> +       if (IS_ERR(reg)) {
> +               pr_err("Couldn't map the %s clock registers\n", node->name);
> +               return;
> +       }
>
> -       if (of_property_read_string(node, "clock-output-names", &init.name))
> -               init.name = node->name;
> +       clk_data = kmalloc(sizeof(*clk_data), GFP_KERNEL);
> +       if (!clk_data)
> +               return;
>
> -       clk = clk_register(NULL, &phase->hw);
> -       if (IS_ERR(clk))
> -               goto err_unmap;
> +       clk_data->clks = kcalloc(3, sizeof(*clk_data->clks), GFP_KERNEL);
> +       if (!clk_data->clks)
> +               goto err_free_data;
> +
> +       clk_data->clk_num = 3;
> +       clk_data->clks[0] = sunxi_factors_register(node,
> +                                                  &sun4i_a10_mod0_data,
> +                                                  &sun4i_a10_mmc_lock, reg);
> +       if (!clk_data->clks[0])
> +               goto err_free_clks;
> +
> +       parent = __clk_get_name(clk_data->clks[0]);
> +
> +       for (i = 1; i < 3; i++) {
> +               struct clk_init_data init = {
> +                       .num_parents    = 1,
> +                       .parent_names   = &parent,
> +                       .ops            = &mmc_clk_ops,
> +               };
> +               struct mmc_phase *phase;
> +
> +               phase = kmalloc(sizeof(*phase), GFP_KERNEL);
> +               if (!phase)
> +                       continue;
> +
> +               phase->hw.init = &init;
> +               phase->reg = reg;
> +               phase->lock = &sun4i_a10_mmc_lock;
> +
> +               if (i == 1)
> +                       phase->offset = 8;
> +               else
> +                       phase->offset = 20;
> +
> +               if (of_property_read_string_index(node, "clock-output-names",
> +                                                 i, &init.name))
> +                       init.name = node->name;

You could assign first, then call of_property_read_string_index.
It won't touch the string unless a valid string is found.

> +
> +               clk_data->clks[i] = clk_register(NULL, &phase->hw);
> +               if (IS_ERR(clk_data->clks[i]))
> +                       continue;

I'm a bit skeptical about partial success/failure, though I don't
have a strong argument for or against it yet.

ChenYu

> +       }
>
> -       of_clk_add_provider(node, of_clk_src_simple_get, clk);
> +       of_clk_add_provider(node, of_clk_src_onecell_get, clk_data);
>
>         return;
>
> -err_unmap:
> -       iounmap(phase->reg);
> -err_free:
> -       kfree(phase);
> -}
> -
> -
> -static struct mmc_phase_data mmc_output_clk = {
> -       .offset = 8,
> -};
> -
> -static struct mmc_phase_data mmc_sample_clk = {
> -       .offset = 20,
> -};
> -
> -static void __init sun4i_a10_mmc_output_setup(struct device_node *node)
> -{
> -       sun4i_a10_mmc_phase_setup(node, &mmc_output_clk);
> -}
> -CLK_OF_DECLARE(sun4i_a10_mmc_output, "allwinner,sun4i-a10-mmc-output-clk", sun4i_a10_mmc_output_setup);
> -
> -static void __init sun4i_a10_mmc_sample_setup(struct device_node *node)
> -{
> -       sun4i_a10_mmc_phase_setup(node, &mmc_sample_clk);
> +err_free_clks:
> +       kfree(clk_data->clks);
> +err_free_data:
> +       kfree(clk_data);
>  }
> -CLK_OF_DECLARE(sun4i_a10_mmc_sample, "allwinner,sun4i-a10-mmc-sample-clk", sun4i_a10_mmc_sample_setup);
> +CLK_OF_DECLARE(sun4i_a10_mmc, "allwinner,sun4i-a10-mmc-clk", sun4i_a10_mmc_setup);
> --
> 2.2.0

^ permalink raw reply	[flat|nested] 8+ messages in thread

* [PATCH 1/4] clk: sunxi: Rework MMC phase clocks
  2014-12-08 16:53   ` Chen-Yu Tsai
@ 2014-12-09  3:26     ` Chen-Yu Tsai
  2014-12-09 10:53     ` Maxime Ripard
  1 sibling, 0 replies; 8+ messages in thread
From: Chen-Yu Tsai @ 2014-12-09  3:26 UTC (permalink / raw)
  To: linux-arm-kernel

On Tue, Dec 9, 2014 at 12:53 AM, Chen-Yu Tsai <wens@csie.org> wrote:
> On Mon, Dec 8, 2014 at 1:21 AM, Maxime Ripard
> <maxime.ripard@free-electrons.com> wrote:
>> Instead of having three different clocks for the main MMC clock and the two
>> phase sub-clocks, which involved having three different drivers sharing the
>> same register, rework it to have the same single driver registering three
>> different clocks.
>>
>> Signed-off-by: Maxime Ripard <maxime.ripard@free-electrons.com>
>> ---
>>  drivers/clk/sunxi/clk-mod0.c | 129 ++++++++++++++++++++++---------------------
>>  1 file changed, 67 insertions(+), 62 deletions(-)
>>
>> diff --git a/drivers/clk/sunxi/clk-mod0.c b/drivers/clk/sunxi/clk-mod0.c
>> index 658d74f39451..24522c5b94ae 100644
>> --- a/drivers/clk/sunxi/clk-mod0.c
>> +++ b/drivers/clk/sunxi/clk-mod0.c
>> @@ -115,19 +115,17 @@ static void __init sun5i_a13_mbus_setup(struct device_node *node)
>>  }
>>  CLK_OF_DECLARE(sun5i_a13_mbus, "allwinner,sun5i-a13-mbus-clk", sun5i_a13_mbus_setup);
>>
>> -struct mmc_phase_data {
>> -       u8      offset;
>> -};
>> -
>>  struct mmc_phase {
>>         struct clk_hw           hw;
>> +       u8                      offset;
>>         void __iomem            *reg;
>> -       struct mmc_phase_data   *data;
>>         spinlock_t              *lock;
>>  };
>>
>>  #define to_mmc_phase(_hw) container_of(_hw, struct mmc_phase, hw)
>>
>> +static DEFINE_SPINLOCK(sun4i_a10_mmc_lock);
>> +
>
> I'd move this to just above the setup function.
> The get/set_phase callbacks don't need it.
>
>>  static int mmc_get_phase(struct clk_hw *hw)
>>  {
>>         struct clk *mmc, *mmc_parent, *clk = hw->clk;
>> @@ -138,7 +136,7 @@ static int mmc_get_phase(struct clk_hw *hw)
>>         u8 delay;
>>
>>         value = readl(phase->reg);
>> -       delay = (value >> phase->data->offset) & 0x3;
>> +       delay = (value >> phase->offset) & 0x3;
>>
>>         if (!delay)
>>                 return 180;
>> @@ -226,8 +224,8 @@ static int mmc_set_phase(struct clk_hw *hw, int degrees)
>>
>>         spin_lock_irqsave(phase->lock, flags);
>>         value = readl(phase->reg);
>> -       value &= ~GENMASK(phase->data->offset + 3, phase->data->offset);
>> -       value |= delay << phase->data->offset;
>> +       value &= ~GENMASK(phase->offset + 3, phase->offset);
>> +       value |= delay << phase->offset;
>>         writel(value, phase->reg);
>>         spin_unlock_irqrestore(phase->lock, flags);
>>
>> @@ -239,66 +237,73 @@ static const struct clk_ops mmc_clk_ops = {
>>         .set_phase      = mmc_set_phase,
>>  };
>>
>> -static void __init sun4i_a10_mmc_phase_setup(struct device_node *node,
>> -                                            struct mmc_phase_data *data)
>> +static void __init sun4i_a10_mmc_setup(struct device_node *node)
>>  {
>> -       const char *parent_names[1] = { of_clk_get_parent_name(node, 0) };
>> -       struct clk_init_data init = {
>> -               .num_parents    = 1,
>> -               .parent_names   = parent_names,
>> -               .ops            = &mmc_clk_ops,
>> -       };
>> -
>> -       struct mmc_phase *phase;
>> -       struct clk *clk;
>> -
>> -       phase = kmalloc(sizeof(*phase), GFP_KERNEL);
>> -       if (!phase)
>> -               return;
>> -
>> -       phase->hw.init = &init;
>> -
>> -       phase->reg = of_iomap(node, 0);
>> -       if (!phase->reg)
>> -               goto err_free;
>> +       struct clk_onecell_data *clk_data;
>> +       const char *parent;
>> +       void __iomem *reg;
>> +       int i;
>>
>> -       phase->data = data;
>> -       phase->lock = &sun4i_a10_mod0_lock;
>> +       reg = of_io_request_and_map(node, 0, of_node_full_name(node));
>> +       if (IS_ERR(reg)) {
>> +               pr_err("Couldn't map the %s clock registers\n", node->name);
>> +               return;
>> +       }
>>
>> -       if (of_property_read_string(node, "clock-output-names", &init.name))
>> -               init.name = node->name;
>> +       clk_data = kmalloc(sizeof(*clk_data), GFP_KERNEL);
>> +       if (!clk_data)
>> +               return;
>>
>> -       clk = clk_register(NULL, &phase->hw);
>> -       if (IS_ERR(clk))
>> -               goto err_unmap;
>> +       clk_data->clks = kcalloc(3, sizeof(*clk_data->clks), GFP_KERNEL);
>> +       if (!clk_data->clks)
>> +               goto err_free_data;
>> +
>> +       clk_data->clk_num = 3;
>> +       clk_data->clks[0] = sunxi_factors_register(node,
>> +                                                  &sun4i_a10_mod0_data,
>> +                                                  &sun4i_a10_mmc_lock, reg);
>> +       if (!clk_data->clks[0])
>> +               goto err_free_clks;
>> +
>> +       parent = __clk_get_name(clk_data->clks[0]);
>> +
>> +       for (i = 1; i < 3; i++) {
>> +               struct clk_init_data init = {
>> +                       .num_parents    = 1,
>> +                       .parent_names   = &parent,
>> +                       .ops            = &mmc_clk_ops,
>> +               };
>> +               struct mmc_phase *phase;
>> +
>> +               phase = kmalloc(sizeof(*phase), GFP_KERNEL);
>> +               if (!phase)
>> +                       continue;
>> +
>> +               phase->hw.init = &init;
>> +               phase->reg = reg;
>> +               phase->lock = &sun4i_a10_mmc_lock;
>> +
>> +               if (i == 1)
>> +                       phase->offset = 8;
>> +               else
>> +                       phase->offset = 20;
>> +
>> +               if (of_property_read_string_index(node, "clock-output-names",
>> +                                                 i, &init.name))
>> +                       init.name = node->name;
>
> You could assign first, then call of_property_read_string_index.
> It won't touch the string unless a valid string is found.
>
>> +
>> +               clk_data->clks[i] = clk_register(NULL, &phase->hw);
>> +               if (IS_ERR(clk_data->clks[i]))
>> +                       continue;
>
> I'm a bit skeptical about partial success/failure, though I don't
> have a strong argument for or against it yet.
>
> ChenYu
>
>> +       }
>>
>> -       of_clk_add_provider(node, of_clk_src_simple_get, clk);
>> +       of_clk_add_provider(node, of_clk_src_onecell_get, clk_data);
>>
>>         return;
>>
>> -err_unmap:
>> -       iounmap(phase->reg);
>> -err_free:
>> -       kfree(phase);
>> -}
>> -
>> -
>> -static struct mmc_phase_data mmc_output_clk = {
>> -       .offset = 8,
>> -};
>> -
>> -static struct mmc_phase_data mmc_sample_clk = {
>> -       .offset = 20,
>> -};
>> -
>> -static void __init sun4i_a10_mmc_output_setup(struct device_node *node)
>> -{
>> -       sun4i_a10_mmc_phase_setup(node, &mmc_output_clk);
>> -}
>> -CLK_OF_DECLARE(sun4i_a10_mmc_output, "allwinner,sun4i-a10-mmc-output-clk", sun4i_a10_mmc_output_setup);
>> -
>> -static void __init sun4i_a10_mmc_sample_setup(struct device_node *node)
>> -{
>> -       sun4i_a10_mmc_phase_setup(node, &mmc_sample_clk);
>> +err_free_clks:
>> +       kfree(clk_data->clks);
>> +err_free_data:
>> +       kfree(clk_data);
>>  }
>> -CLK_OF_DECLARE(sun4i_a10_mmc_sample, "allwinner,sun4i-a10-mmc-sample-clk", sun4i_a10_mmc_sample_setup);
>> +CLK_OF_DECLARE(sun4i_a10_mmc, "allwinner,sun4i-a10-mmc-clk", sun4i_a10_mmc_setup);

You should also update the DT bindings. :)

^ permalink raw reply	[flat|nested] 8+ messages in thread

* [PATCH 1/4] clk: sunxi: Rework MMC phase clocks
  2014-12-08 16:53   ` Chen-Yu Tsai
  2014-12-09  3:26     ` Chen-Yu Tsai
@ 2014-12-09 10:53     ` Maxime Ripard
  1 sibling, 0 replies; 8+ messages in thread
From: Maxime Ripard @ 2014-12-09 10:53 UTC (permalink / raw)
  To: linux-arm-kernel

Hi,

On Tue, Dec 09, 2014 at 12:53:35AM +0800, Chen-Yu Tsai wrote:
> On Mon, Dec 8, 2014 at 1:21 AM, Maxime Ripard
> <maxime.ripard@free-electrons.com> wrote:
> > Instead of having three different clocks for the main MMC clock and the two
> > phase sub-clocks, which involved having three different drivers sharing the
> > same register, rework it to have the same single driver registering three
> > different clocks.
> >
> > Signed-off-by: Maxime Ripard <maxime.ripard@free-electrons.com>
> > ---
> >  drivers/clk/sunxi/clk-mod0.c | 129 ++++++++++++++++++++++---------------------
> >  1 file changed, 67 insertions(+), 62 deletions(-)
> >
> > diff --git a/drivers/clk/sunxi/clk-mod0.c b/drivers/clk/sunxi/clk-mod0.c
> > index 658d74f39451..24522c5b94ae 100644
> > --- a/drivers/clk/sunxi/clk-mod0.c
> > +++ b/drivers/clk/sunxi/clk-mod0.c
> > @@ -115,19 +115,17 @@ static void __init sun5i_a13_mbus_setup(struct device_node *node)
> >  }
> >  CLK_OF_DECLARE(sun5i_a13_mbus, "allwinner,sun5i-a13-mbus-clk", sun5i_a13_mbus_setup);
> >
> > -struct mmc_phase_data {
> > -       u8      offset;
> > -};
> > -
> >  struct mmc_phase {
> >         struct clk_hw           hw;
> > +       u8                      offset;
> >         void __iomem            *reg;
> > -       struct mmc_phase_data   *data;
> >         spinlock_t              *lock;
> >  };
> >
> >  #define to_mmc_phase(_hw) container_of(_hw, struct mmc_phase, hw)
> >
> > +static DEFINE_SPINLOCK(sun4i_a10_mmc_lock);
> > +
> 
> I'd move this to just above the setup function.
> The get/set_phase callbacks don't need it.

Indeed.

> > +               if (of_property_read_string_index(node, "clock-output-names",
> > +                                                 i, &init.name))
> > +                       init.name = node->name;
> 
> You could assign first, then call of_property_read_string_index.
> It won't touch the string unless a valid string is found.

Well then, in the most likely case (where you have the property), you
would have two consecutive assignments, instead of a single one like
what's done here.

It seems more natural to do it that way.

> 
> > +
> > +               clk_data->clks[i] = clk_register(NULL, &phase->hw);
> > +               if (IS_ERR(clk_data->clks[i]))
> > +                       continue;
> 
> I'm a bit skeptical about partial success/failure, though I don't
> have a strong argument for or against it yet.

Yeah, I was also a bit skeptical about that part to be honest :)

I'll rework it to cleanup the clocks if it fails.

Thanks!
Maxime

-- 
Maxime Ripard, Free Electrons
Embedded Linux, Kernel and Android engineering
http://free-electrons.com
-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 819 bytes
Desc: Digital signature
URL: <http://lists.infradead.org/pipermail/linux-arm-kernel/attachments/20141209/96392eac/attachment.sig>

^ permalink raw reply	[flat|nested] 8+ messages in thread

end of thread, other threads:[~2014-12-09 10:53 UTC | newest]

Thread overview: 8+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2014-12-07 17:21 [PATCH 0/4] clk: sunxi: mmc: Last bits of phase handling Maxime Ripard
2014-12-07 17:21 ` [PATCH 1/4] clk: sunxi: Rework MMC phase clocks Maxime Ripard
2014-12-08 16:53   ` Chen-Yu Tsai
2014-12-09  3:26     ` Chen-Yu Tsai
2014-12-09 10:53     ` Maxime Ripard
2014-12-07 17:21 ` [PATCH 2/4] ARM: sunxi: dt: Add sample and output mmc clocks Maxime Ripard
2014-12-07 17:21 ` [PATCH 3/4] mmc: sunxi: Convert MMC driver to the standard clock phase API Maxime Ripard
2014-12-07 17:21 ` [PATCH 4/4] clk: sunxi: Remove custom phase function Maxime Ripard

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).