linux-arm-kernel.lists.infradead.org archive mirror
 help / color / mirror / Atom feed
* [PATCH v2 00/11] ARM: sun9i: Enable MMC support on Allwinner A80
@ 2014-12-18  7:00 Chen-Yu Tsai
  2014-12-18  7:00 ` [PATCH v2 01/11] clk: sunxi: Add mod0 and mmc module clock support for A80 Chen-Yu Tsai
                   ` (10 more replies)
  0 siblings, 11 replies; 21+ messages in thread
From: Chen-Yu Tsai @ 2014-12-18  7:00 UTC (permalink / raw)
  To: linux-arm-kernel

Hi Maxime,

This is v2 of the sun9i mmc series. It is based on your v2 of your
sunxi mmc phase clocks series. The clock bits will conflict with
Hans' work on the mod0 clock. The DT bits might conflict with your
header conversion series. Assuming this series is OK, how would
you like to proceed?

This series enables MMC support on the A80 using existing drivers
we have. The A80 has 4 MMC controllers. These controllers share
a common clock gate and reset control, which are then sub-divided
to each controller.

The phase clocks are the same as the older SoCs, so it should be
straight forward to add them with the rest of the sunxi family.
I did find that Allwinner's kernel uses different delay values
for the A80, but so far I've not run into any issues using the
mainline kernel.

Patch 1 adds module 0 type clock support for the A80. These are
essentially the same as mod0 clocks on other Allwinner SoCs, except
for the wider mux bits.

Patch 2 adds mmc mod clocks to the DTSI.

Patch 3 adds support for the mmc config (term from user manual) clocks.
This is the part that breaks out the clock gates and reset controls
for each controller. This is implemented as a platform driver, as
the shared reset control must be de-asserted for any of either this
or the mmc blocks to work.

Patch 4 adds clock-indices properties to the AHB/APB gate clocks.
This is needed for of_clk_get_parent_name to work properly, as we
use bit indices instead of counting the entries.

Patch 5 adds the mmc config clock nodes to the DTSI.

Patch 6 changes sunxi-common-regulators.dtsi to use labels to
reference the pio node.

Patch 7 adds the mmc controller nodes to the DTSI.

Patch 8 and 10 add the pinmux settings for mmc0 and mmc2.

Patch 9 and 11 enable mmc0 and mmc2 on the A80 Optimus Board.

Kudos to Andreas for figuring out all the DT bits. His SoB
is on the relevant patches.

Changes since v1:

  - Use sunxi-common-regulators.dtsi for vmmc regulator
  - Rebased onto sunxi mmc phase clock series v2
  - Use new multi-output mmc module clock style
  - Rename sun9i mmc config clock name and compatible
  - Make mmc2_pins include all pins needed, and change
    name to mmc2_8bit_pins
  - Add spaces between pin names in mmc pins
  - Add clk_prepare_enable()/clk_disable_unprepare() calls to
    reset control ops for the mmc config clock
  - Use DIV_ROUND_UP when calculating number of clocks in sun9i
    mmc config clock probe function
  - Add required properties and outputs section for sun9i mmc
    config clock in bindings doc; also add an example

Cheers
ChenYu Tsai

Chen-Yu Tsai (11):
  clk: sunxi: Add mod0 and mmc module clock support for A80
  ARM: dts: sun9i: Add mmc module clock nodes for A80
  clk: sunxi: Add driver for A80 MMC config clocks/resets
  ARM: dts: sun9i: Add clock-indices property for bus gate clocks
  ARM: dts: sun9i: Add mmc config clock nodes
  ARM: dts: sunxi: Use label to reference pio in sunxi-common-regulators
  ARM: dts: sun9i: Add mmc controller nodes to the A80 dtsi
  ARM: dts: sun9i: Add pinmux setting for mmc0
  ARM: dts: sun9i: Enable mmc0 on A80 Optimus Board
  ARM: dts: sun9i: Add 8 bit mmc pinmux setting for mmc2
  ARM: dts: sun9i: Enable mmc2 on A80 Optimus Board

 Documentation/devicetree/bindings/clock/sunxi.txt |  30 ++-
 arch/arm/boot/dts/sun9i-a80-optimus.dts           |  27 +++
 arch/arm/boot/dts/sun9i-a80.dtsi                  | 124 ++++++++++++
 arch/arm/boot/dts/sunxi-common-regulators.dtsi    |  54 +++---
 drivers/clk/sunxi/Makefile                        |   1 +
 drivers/clk/sunxi/clk-mod0.c                      |  99 ++++++++++
 drivers/clk/sunxi/clk-sun9i-mmc.c                 | 222 ++++++++++++++++++++++
 7 files changed, 527 insertions(+), 30 deletions(-)
 create mode 100644 drivers/clk/sunxi/clk-sun9i-mmc.c

-- 
2.1.3

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

* [PATCH v2 01/11] clk: sunxi: Add mod0 and mmc module clock support for A80
  2014-12-18  7:00 [PATCH v2 00/11] ARM: sun9i: Enable MMC support on Allwinner A80 Chen-Yu Tsai
@ 2014-12-18  7:00 ` Chen-Yu Tsai
  2014-12-19 18:02   ` Maxime Ripard
  2014-12-18  7:00 ` [PATCH v2 02/11] ARM: dts: sun9i: Add mmc module clock nodes " Chen-Yu Tsai
                   ` (9 subsequent siblings)
  10 siblings, 1 reply; 21+ messages in thread
From: Chen-Yu Tsai @ 2014-12-18  7:00 UTC (permalink / raw)
  To: linux-arm-kernel

The module 0 style clocks, or storage module clocks as named in the
official SDK, are almost the same as the module 0 clocks on earlier
Allwinner SoCs. The only difference is wider mux register bits.

As with earlier Allwinner SoCs, mmc module clocks are a special case
of mod0 clocks, with phase controls for 2 child clocks, output and
sample.

This patch adds support for both.

Signed-off-by: Chen-Yu Tsai <wens@csie.org>
---
 Documentation/devicetree/bindings/clock/sunxi.txt |  7 +-
 drivers/clk/sunxi/clk-mod0.c                      | 99 +++++++++++++++++++++++
 2 files changed, 104 insertions(+), 2 deletions(-)

diff --git a/Documentation/devicetree/bindings/clock/sunxi.txt b/Documentation/devicetree/bindings/clock/sunxi.txt
index 8c60433..b660bdb 100644
--- a/Documentation/devicetree/bindings/clock/sunxi.txt
+++ b/Documentation/devicetree/bindings/clock/sunxi.txt
@@ -56,7 +56,9 @@ Required properties:
 	"allwinner,sun8i-a23-apb2-gates-clk" - for the APB2 gates on A23
 	"allwinner,sun5i-a13-mbus-clk" - for the MBUS clock on A13
 	"allwinner,sun4i-a10-mmc-clk" - for the MMC clock
+	"allwinner,sun9i-a80-mmc-clk" - for mmc module clocks on A80
 	"allwinner,sun4i-a10-mod0-clk" - for the module 0 family of clocks
+	"allwinner,sun9i-a80-mod0-clk" - for module 0 (storage) clocks on A80
 	"allwinner,sun8i-a23-mbus-clk" - for the MBUS clock on A23
 	"allwinner,sun7i-a20-out-clk" - for the external output clocks
 	"allwinner,sun7i-a20-gmac-clk" - for the GMAC clock module on A20/A31
@@ -72,7 +74,8 @@ Required properties for all clocks:
 - #clock-cells : from common clock binding; shall be set to 0 except for
 	the following compatibles where it shall be set to 1:
 	"allwinner,*-gates-clk", "allwinner,sun4i-pll5-clk",
-	"allwinner,sun4i-pll6-clk", "allwinner,sun6i-a31-pll6-clk"
+	"allwinner,sun4i-pll6-clk", "allwinner,sun6i-a31-pll6-clk",
+	"allwinner,*-usb-clk", "allwinner,*-mmc-clk"
 - clock-output-names : shall be the corresponding names of the outputs.
 	If the clock module only has one output, the name shall be the
 	module name.
@@ -94,7 +97,7 @@ For "allwinner,sun6i-a31-pll6-clk", there are 2 outputs. The first output
 is the normal PLL6 output, or "pll6". The second output is rate doubled
 PLL6, or "pll6x2".
 
-The "allwinner,sun4i-a10-mmc-clk" has three different outputs: the
+The "allwinner,*-mmc-clk" clocks have three different outputs: the
 main clock, with the ID 0, and the output and sample clocks, with the
 IDs 1 and 2, respectively.
 
diff --git a/drivers/clk/sunxi/clk-mod0.c b/drivers/clk/sunxi/clk-mod0.c
index 4ac52c7..ef36e89 100644
--- a/drivers/clk/sunxi/clk-mod0.c
+++ b/drivers/clk/sunxi/clk-mod0.c
@@ -93,6 +93,30 @@ static void __init sun4i_a10_mod0_setup(struct device_node *node)
 }
 CLK_OF_DECLARE(sun4i_a10_mod0, "allwinner,sun4i-a10-mod0-clk", sun4i_a10_mod0_setup);
 
+static const struct factors_data sun9i_a80_mod0_data __initconst = {
+	.enable = 31,
+	.mux = 24,
+	.muxmask = BIT(3) | BIT(2) | BIT(1) | BIT(0),
+	.table = &sun4i_a10_mod0_config,
+	.getter = sun4i_a10_get_mod0_factors,
+};
+
+static void __init sun9i_a80_mod0_setup(struct device_node *node)
+{
+	void __iomem *reg;
+
+	reg = of_io_request_and_map(node, 0, of_node_full_name(node));
+	if (!reg) {
+		pr_err("Could not get registers for mod0-clk: %s\n",
+		       node->name);
+		return;
+	}
+
+	sunxi_factors_register(node, &sun9i_a80_mod0_data,
+			       &sun4i_a10_mod0_lock, reg);
+}
+CLK_OF_DECLARE(sun9i_a80_mod0, "allwinner,sun9i-a80-mod0-clk", sun9i_a80_mod0_setup);
+
 static DEFINE_SPINLOCK(sun5i_a13_mbus_lock);
 
 static void __init sun5i_a13_mbus_setup(struct device_node *node)
@@ -309,3 +333,78 @@ err_free_data:
 	kfree(clk_data);
 }
 CLK_OF_DECLARE(sun4i_a10_mmc, "allwinner,sun4i-a10-mmc-clk", sun4i_a10_mmc_setup);
+
+static DEFINE_SPINLOCK(sun9i_a80_mmc_lock);
+
+static void __init sun9i_a80_mmc_setup(struct device_node *node)
+{
+	struct clk_onecell_data *clk_data;
+	const char *parent;
+	void __iomem *reg;
+	int i;
+
+	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;
+	}
+
+	clk_data = kmalloc(sizeof(*clk_data), GFP_KERNEL);
+	if (!clk_data)
+		return;
+
+	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,
+						   &sun9i_a80_mod0_data,
+						   &sun9i_a80_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 = &sun9i_a80_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])) {
+			kfree(phase);
+			continue;
+		}
+	}
+
+	of_clk_add_provider(node, of_clk_src_onecell_get, clk_data);
+
+	return;
+
+err_free_clks:
+	kfree(clk_data->clks);
+err_free_data:
+	kfree(clk_data);
+}
+CLK_OF_DECLARE(sun9i_a80_mmc, "allwinner,sun9i-a80-mmc-clk", sun9i_a80_mmc_setup);
-- 
2.1.3

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

* [PATCH v2 02/11] ARM: dts: sun9i: Add mmc module clock nodes for A80
  2014-12-18  7:00 [PATCH v2 00/11] ARM: sun9i: Enable MMC support on Allwinner A80 Chen-Yu Tsai
  2014-12-18  7:00 ` [PATCH v2 01/11] clk: sunxi: Add mod0 and mmc module clock support for A80 Chen-Yu Tsai
@ 2014-12-18  7:00 ` Chen-Yu Tsai
  2014-12-18  7:00 ` [PATCH v2 03/11] clk: sunxi: Add driver for A80 MMC config clocks/resets Chen-Yu Tsai
                   ` (8 subsequent siblings)
  10 siblings, 0 replies; 21+ messages in thread
From: Chen-Yu Tsai @ 2014-12-18  7:00 UTC (permalink / raw)
  To: linux-arm-kernel

The mmc module clocks are A80 specific module 0 (storage) type clocks.

Signed-off-by: Chen-Yu Tsai <wens@csie.org>
Signed-off-by: Andreas F?rber <afaerber@suse.de>
---
 arch/arm/boot/dts/sun9i-a80.dtsi | 36 ++++++++++++++++++++++++++++++++++++
 1 file changed, 36 insertions(+)

diff --git a/arch/arm/boot/dts/sun9i-a80.dtsi b/arch/arm/boot/dts/sun9i-a80.dtsi
index 494714f..b595d9e 100644
--- a/arch/arm/boot/dts/sun9i-a80.dtsi
+++ b/arch/arm/boot/dts/sun9i-a80.dtsi
@@ -215,6 +215,42 @@
 			clock-output-names = "cci400";
 		};
 
+		mmc0_clk: clk at 06000410 {
+			#clock-cells = <1>;
+			compatible = "allwinner,sun9i-a80-mmc-clk";
+			reg = <0x06000410 0x4>;
+			clocks = <&osc24M>, <&pll4>;
+			clock-output-names = "mmc0", "mmc0_output",
+					     "mmc0_sample";
+		};
+
+		mmc1_clk: clk at 06000414 {
+			#clock-cells = <1>;
+			compatible = "allwinner,sun9i-a80-mmc-clk";
+			reg = <0x06000414 0x4>;
+			clocks = <&osc24M>, <&pll4>;
+			clock-output-names = "mmc1", "mmc1_output",
+					     "mmc1_sample";
+		};
+
+		mmc2_clk: clk at 06000418 {
+			#clock-cells = <1>;
+			compatible = "allwinner,sun9i-a80-mmc-clk";
+			reg = <0x06000418 0x4>;
+			clocks = <&osc24M>, <&pll4>;
+			clock-output-names = "mmc2", "mmc2_output",
+					     "mmc2_sample";
+		};
+
+		mmc3_clk: clk at 0600041c {
+			#clock-cells = <1>;
+			compatible = "allwinner,sun9i-a80-mmc-clk";
+			reg = <0x0600041c 0x4>;
+			clocks = <&osc24M>, <&pll4>;
+			clock-output-names = "mmc3", "mmc3_output",
+					     "mmc3_sample";
+		};
+
 		ahb0_gates: clk at 06000580 {
 			#clock-cells = <1>;
 			compatible = "allwinner,sun9i-a80-ahb0-gates-clk";
-- 
2.1.3

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

* [PATCH v2 03/11] clk: sunxi: Add driver for A80 MMC config clocks/resets
  2014-12-18  7:00 [PATCH v2 00/11] ARM: sun9i: Enable MMC support on Allwinner A80 Chen-Yu Tsai
  2014-12-18  7:00 ` [PATCH v2 01/11] clk: sunxi: Add mod0 and mmc module clock support for A80 Chen-Yu Tsai
  2014-12-18  7:00 ` [PATCH v2 02/11] ARM: dts: sun9i: Add mmc module clock nodes " Chen-Yu Tsai
@ 2014-12-18  7:00 ` Chen-Yu Tsai
  2014-12-19 18:08   ` Maxime Ripard
  2014-12-18  7:00 ` [PATCH v2 04/11] ARM: dts: sun9i: Add clock-indices property for bus gate clocks Chen-Yu Tsai
                   ` (7 subsequent siblings)
  10 siblings, 1 reply; 21+ messages in thread
From: Chen-Yu Tsai @ 2014-12-18  7:00 UTC (permalink / raw)
  To: linux-arm-kernel

On the A80 SoC, the 4 mmc controllers each have a separate register
controlling their register access clocks and reset controls. These
registers in turn share a ahb clock gate and reset control.

This patch adds a platform device driver for these controls. It
requires both clocks and reset controls to be available, so using
CLK_OF_DECLARE might not be the best way.

Signed-off-by: Chen-Yu Tsai <wens@csie.org>
---
 Documentation/devicetree/bindings/clock/sunxi.txt |  25 ++-
 drivers/clk/sunxi/Makefile                        |   1 +
 drivers/clk/sunxi/clk-sun9i-mmc.c                 | 222 ++++++++++++++++++++++
 3 files changed, 247 insertions(+), 1 deletion(-)
 create mode 100644 drivers/clk/sunxi/clk-sun9i-mmc.c

diff --git a/Documentation/devicetree/bindings/clock/sunxi.txt b/Documentation/devicetree/bindings/clock/sunxi.txt
index b660bdb..727c4cf 100644
--- a/Documentation/devicetree/bindings/clock/sunxi.txt
+++ b/Documentation/devicetree/bindings/clock/sunxi.txt
@@ -57,6 +57,7 @@ Required properties:
 	"allwinner,sun5i-a13-mbus-clk" - for the MBUS clock on A13
 	"allwinner,sun4i-a10-mmc-clk" - for the MMC clock
 	"allwinner,sun9i-a80-mmc-clk" - for mmc module clocks on A80
+	"allwinner,sun9i-a80-mmc-config-clk" - for mmc gates + resets on A80
 	"allwinner,sun4i-a10-mod0-clk" - for the module 0 family of clocks
 	"allwinner,sun9i-a80-mod0-clk" - for module 0 (storage) clocks on A80
 	"allwinner,sun8i-a23-mbus-clk" - for the MBUS clock on A23
@@ -75,7 +76,8 @@ Required properties for all clocks:
 	the following compatibles where it shall be set to 1:
 	"allwinner,*-gates-clk", "allwinner,sun4i-pll5-clk",
 	"allwinner,sun4i-pll6-clk", "allwinner,sun6i-a31-pll6-clk",
-	"allwinner,*-usb-clk", "allwinner,*-mmc-clk"
+	"allwinner,*-usb-clk", "allwinner,*-mmc-clk",
+	"allwinner,*-mmc-config-clk"
 - clock-output-names : shall be the corresponding names of the outputs.
 	If the clock module only has one output, the name shall be the
 	module name.
@@ -83,6 +85,10 @@ Required properties for all clocks:
 And "allwinner,*-usb-clk" clocks also require:
 - reset-cells : shall be set to 1
 
+The "allwinner,sun9i-a80-mmc-config-clk" clock also requires:
+- #reset-cells : shall be set to 1
+- resets : shall be the reset control phandle for the mmc block.
+
 For "allwinner,sun7i-a20-gmac-clk", the parent clocks shall be fixed rate
 dummy clocks at 25 MHz and 125 MHz, respectively. See example.
 
@@ -101,6 +107,10 @@ The "allwinner,*-mmc-clk" clocks have three different outputs: the
 main clock, with the ID 0, and the output and sample clocks, with the
 IDs 1 and 2, respectively.
 
+The "allwinner,sun9i-a80-mmc-config-clk" clock has one clock/reset output
+per mmc controller. The number of outputs is determined by the size of
+the address block, which is related to the overall mmc block.
+
 For example:
 
 osc24M: clk at 01c20050 {
@@ -176,3 +186,16 @@ gmac_clk: clk at 01c20164 {
 	clocks = <&mii_phy_tx_clk>, <&gmac_int_tx_clk>;
 	clock-output-names = "gmac";
 };
+
+mmc_config_clk: clk at 01c13000 {
+	compatible = "allwinner,sun9i-a80-mmc-config-clk";
+	reg = <0x01c13000 0x10>;
+	clocks = <&ahb0_gates 8>;
+	clock-names = "ahb";
+	resets = <&ahb0_resets 8>;
+	reset-names = "ahb";
+	#clock-cells = <1>;
+	#reset-cells = <1>;
+	clock-output-names = "mmc0_config", "mmc1_config",
+			     "mmc2_config", "mmc3_config";
+};
diff --git a/drivers/clk/sunxi/Makefile b/drivers/clk/sunxi/Makefile
index a66953c..3a5292e 100644
--- a/drivers/clk/sunxi/Makefile
+++ b/drivers/clk/sunxi/Makefile
@@ -8,6 +8,7 @@ obj-y += clk-a20-gmac.o
 obj-y += clk-mod0.o
 obj-y += clk-sun8i-mbus.o
 obj-y += clk-sun9i-core.o
+obj-y += clk-sun9i-mmc.o
 
 obj-$(CONFIG_MFD_SUN6I_PRCM) += \
 	clk-sun6i-ar100.o clk-sun6i-apb0.o clk-sun6i-apb0-gates.o \
diff --git a/drivers/clk/sunxi/clk-sun9i-mmc.c b/drivers/clk/sunxi/clk-sun9i-mmc.c
new file mode 100644
index 0000000..aeb3a52
--- /dev/null
+++ b/drivers/clk/sunxi/clk-sun9i-mmc.c
@@ -0,0 +1,222 @@
+/*
+ * Copyright 2013 Chen-Yu Tsai
+ *
+ * Chen-Yu Tsai	<wens@csie.org>
+ *
+ * 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/module.h>
+#include <linux/of.h>
+#include <linux/of_device.h>
+#include <linux/reset.h>
+#include <linux/platform_device.h>
+#include <linux/reset-controller.h>
+#include <linux/spinlock.h>
+
+#define SUN9I_MMC_WIDTH		4
+
+#define SUN9I_MMC_GATE_BIT	16
+#define SUN9I_MMC_RESET_BIT	18
+
+struct sun9i_mmc_clk_data {
+	spinlock_t			lock;
+	void __iomem			*membase;
+	struct clk			*clk;
+	struct reset_control		*reset;
+	struct clk_onecell_data		clk_data;
+	struct reset_controller_dev	rcdev;
+};
+
+static int sun9i_mmc_reset_assert(struct reset_controller_dev *rcdev,
+			      unsigned long id)
+{
+	struct sun9i_mmc_clk_data *data = container_of(rcdev,
+						       struct sun9i_mmc_clk_data,
+						       rcdev);
+	unsigned long flags;
+	void __iomem *reg = data->membase + SUN9I_MMC_WIDTH * id;
+	u32 val;
+
+	clk_prepare_enable(data->clk);
+	spin_lock_irqsave(&data->lock, flags);
+
+	val = readl(reg);
+	writel(val & ~BIT(SUN9I_MMC_RESET_BIT), reg);
+
+	spin_unlock_irqrestore(&data->lock, flags);
+	clk_disable_unprepare(data->clk);
+
+	return 0;
+}
+
+static int sun9i_mmc_reset_deassert(struct reset_controller_dev *rcdev,
+				unsigned long id)
+{
+	struct sun9i_mmc_clk_data *data = container_of(rcdev,
+						       struct sun9i_mmc_clk_data,
+						       rcdev);
+	unsigned long flags;
+	void __iomem *reg = data->membase + SUN9I_MMC_WIDTH * id;
+	u32 val;
+
+	clk_prepare_enable(data->clk);
+	spin_lock_irqsave(&data->lock, flags);
+
+	val = readl(reg);
+	writel(val | BIT(SUN9I_MMC_RESET_BIT), reg);
+
+	spin_unlock_irqrestore(&data->lock, flags);
+	clk_disable_unprepare(data->clk);
+
+	return 0;
+}
+
+static struct reset_control_ops sun9i_mmc_reset_ops = {
+	.assert		= sun9i_mmc_reset_assert,
+	.deassert	= sun9i_mmc_reset_deassert,
+};
+
+static int sun9i_a80_mmc_config_clk_probe(struct platform_device *pdev)
+{
+	struct device_node *np = pdev->dev.of_node;
+	struct sun9i_mmc_clk_data *data;
+	struct clk_onecell_data *clk_data;
+	const char *clk_name = np->name;
+	const char *clk_parent;
+	struct resource *r;
+	int count, i, ret;
+
+	data = devm_kzalloc(&pdev->dev, sizeof(*data), GFP_KERNEL);
+	if (!data)
+		return -ENOMEM;
+
+	spin_lock_init(&data->lock);
+
+	r = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+	/* one clock/reset pair per word */
+	count = DIV_ROUND_UP((r->end - r->start + 1), SUN9I_MMC_WIDTH);
+	data->membase = devm_ioremap_resource(&pdev->dev, r);
+	if (IS_ERR(data->membase))
+		return PTR_ERR(data->membase);
+
+	clk_data = &data->clk_data;
+	clk_data->clk_num = count;
+	clk_data->clks = devm_kcalloc(&pdev->dev, count, sizeof(struct clk *),
+				      GFP_KERNEL);
+	if (!clk_data->clks)
+		return -ENOMEM;
+
+	clk_parent = of_clk_get_parent_name(np, 0);
+	if (!clk_parent)
+		return -EINVAL;
+
+	data->clk = devm_clk_get(&pdev->dev, NULL);
+	if (IS_ERR(data->clk)) {
+		dev_err(&pdev->dev, "Could not get clock\n");
+		return PTR_ERR(data->clk);
+	}
+
+	data->reset = devm_reset_control_get(&pdev->dev, NULL);
+	if (IS_ERR(data->reset)) {
+		dev_err(&pdev->dev, "Could not get reset control\n");
+		return PTR_ERR(data->reset);
+	}
+
+	ret = reset_control_deassert(data->reset);
+	if (ret) {
+		dev_err(&pdev->dev, "Reset deassert err %d\n", ret);
+		return ret;
+	}
+
+	for (i = 0; i < count; i++) {
+		of_property_read_string_index(np, "clock-output-names",
+					      i, &clk_name);
+
+		clk_data->clks[i] = clk_register_gate(&pdev->dev, clk_name,
+						      clk_parent, 0,
+						      data->membase + SUN9I_MMC_WIDTH * i,
+						      SUN9I_MMC_GATE_BIT, 0,
+						      &data->lock);
+
+		if (IS_ERR(clk_data->clks[i])) {
+			ret = PTR_ERR(clk_data->clks[i]);
+			goto err_clk_register;
+		}
+	}
+
+	ret = of_clk_add_provider(np, of_clk_src_onecell_get, clk_data);
+	if (ret)
+		goto err_clk_provider;
+
+	data->rcdev.owner = THIS_MODULE;
+	data->rcdev.nr_resets = count;
+	data->rcdev.ops = &sun9i_mmc_reset_ops;
+	data->rcdev.of_node = pdev->dev.of_node;
+
+	ret = reset_controller_register(&data->rcdev);
+	if (ret)
+		goto err_rc_reg;
+
+	platform_set_drvdata(pdev, data);
+
+	return 0;
+
+err_rc_reg:
+	of_clk_del_provider(np);
+
+err_clk_provider:
+	for (i = 0; i < count; i++)
+		clk_unregister(clk_data->clks[i]);
+
+err_clk_register:
+	reset_control_assert(data->reset);
+
+	return ret;
+}
+
+static int sun9i_a80_mmc_config_clk_remove(struct platform_device *pdev)
+{
+	struct device_node *np = pdev->dev.of_node;
+	struct sun9i_mmc_clk_data *data = platform_get_drvdata(pdev);
+	struct clk_onecell_data *clk_data = &data->clk_data;
+	int i;
+
+	reset_controller_unregister(&data->rcdev);
+	of_clk_del_provider(np);
+	for (i = 0; i < clk_data->clk_num; i++)
+		clk_unregister(clk_data->clks[i]);
+
+	reset_control_assert(data->reset);
+
+	return 0;
+}
+
+static const struct of_device_id sun9i_a80_mmc_config_clk_dt_ids[] = {
+	{ .compatible = "allwinner,sun9i-a80-mmc-config-clk" },
+	{ /* sentinel */ }
+};
+
+static struct platform_driver sun9i_a80_mmc_config_clk_driver = {
+	.driver = {
+		.name = "sun9i-a80-mmc-config-clk",
+		.of_match_table = sun9i_a80_mmc_config_clk_dt_ids,
+	},
+	.probe = sun9i_a80_mmc_config_clk_probe,
+	.remove = sun9i_a80_mmc_config_clk_remove,
+};
+module_platform_driver(sun9i_a80_mmc_config_clk_driver);
+
+MODULE_AUTHOR("Chen-Yu Tsai <wens@csie.org>");
+MODULE_DESCRIPTION("Allwinner A80 MMC clock/reset Driver");
+MODULE_LICENSE("GPL v2");
-- 
2.1.3

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

* [PATCH v2 04/11] ARM: dts: sun9i: Add clock-indices property for bus gate clocks
  2014-12-18  7:00 [PATCH v2 00/11] ARM: sun9i: Enable MMC support on Allwinner A80 Chen-Yu Tsai
                   ` (2 preceding siblings ...)
  2014-12-18  7:00 ` [PATCH v2 03/11] clk: sunxi: Add driver for A80 MMC config clocks/resets Chen-Yu Tsai
@ 2014-12-18  7:00 ` Chen-Yu Tsai
  2014-12-18  7:00 ` [PATCH v2 05/11] ARM: dts: sun9i: Add mmc config clock nodes Chen-Yu Tsai
                   ` (6 subsequent siblings)
  10 siblings, 0 replies; 21+ messages in thread
From: Chen-Yu Tsai @ 2014-12-18  7:00 UTC (permalink / raw)
  To: linux-arm-kernel

of_clk_get_parent_name() uses the clock-indices property to resolve
clock phandle arguments in case that the argument index does not
match the clock-output-names sequence.

This is the case on sunxi, where we use the actual bit index as the
argument to the phandle. Add the clock-indices property so that
of_clk_get_parent_name() resolves the names correctly.

Signed-off-by: Chen-Yu Tsai <wens@csie.org>
---
 arch/arm/boot/dts/sun9i-a80.dtsi | 10 ++++++++++
 1 file changed, 10 insertions(+)

diff --git a/arch/arm/boot/dts/sun9i-a80.dtsi b/arch/arm/boot/dts/sun9i-a80.dtsi
index b595d9e..eb3f91b 100644
--- a/arch/arm/boot/dts/sun9i-a80.dtsi
+++ b/arch/arm/boot/dts/sun9i-a80.dtsi
@@ -256,6 +256,9 @@
 			compatible = "allwinner,sun9i-a80-ahb0-gates-clk";
 			reg = <0x06000580 0x4>;
 			clocks = <&ahb0>;
+			clock-indices = <0>, <1>, <3>, <5>, <8>, <12>, <13>,
+					<14>, <15>, <16>, <18>, <20>, <21>,
+					<22>, <23>;
 			clock-output-names = "ahb0_fd", "ahb0_ve", "ahb0_gpu",
 					"ahb0_ss", "ahb0_sd", "ahb0_nand1",
 					"ahb0_nand0", "ahb0_sdram",
@@ -269,6 +272,7 @@
 			compatible = "allwinner,sun9i-a80-ahb1-gates-clk";
 			reg = <0x06000584 0x4>;
 			clocks = <&ahb1>;
+			clock-indices = <0>, <1>, <17>, <21>, <22>, <23>, <24>;
 			clock-output-names = "ahb1_usbotg", "ahb1_usbhci",
 					"ahb1_gmac", "ahb1_msgbox",
 					"ahb1_spinlock", "ahb1_hstimer",
@@ -280,6 +284,8 @@
 			compatible = "allwinner,sun9i-a80-ahb2-gates-clk";
 			reg = <0x06000588 0x4>;
 			clocks = <&ahb2>;
+			clock-indices = <0>, <1>, <2>, <4>, <5>, <7>, <8>,
+					<11>;
 			clock-output-names = "ahb2_lcd0", "ahb2_lcd1",
 					"ahb2_edp", "ahb2_csi", "ahb2_hdmi",
 					"ahb2_de", "ahb2_mp", "ahb2_mipi_dsi";
@@ -290,6 +296,8 @@
 			compatible = "allwinner,sun9i-a80-apb0-gates-clk";
 			reg = <0x06000590 0x4>;
 			clocks = <&apb0>;
+			clock-indices = <1>, <5>, <11>, <12>, <13>, <15>,
+					<17>, <18>, <19>;
 			clock-output-names = "apb0_spdif", "apb0_pio",
 					"apb0_ac97", "apb0_i2s0", "apb0_i2s1",
 					"apb0_lradc", "apb0_gpadc", "apb0_twd",
@@ -301,6 +309,8 @@
 			compatible = "allwinner,sun9i-a80-apb1-gates-clk";
 			reg = <0x06000594 0x4>;
 			clocks = <&apb1>;
+			clock-indices = <0>, <1>, <2>, <3>, <4>,
+					<16>, <17>, <18>, <19>, <20>, <21>;
 			clock-output-names = "apb1_i2c0", "apb1_i2c1",
 					"apb1_i2c2", "apb1_i2c3", "apb1_i2c4",
 					"apb1_uart0", "apb1_uart1",
-- 
2.1.3

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

* [PATCH v2 05/11] ARM: dts: sun9i: Add mmc config clock nodes
  2014-12-18  7:00 [PATCH v2 00/11] ARM: sun9i: Enable MMC support on Allwinner A80 Chen-Yu Tsai
                   ` (3 preceding siblings ...)
  2014-12-18  7:00 ` [PATCH v2 04/11] ARM: dts: sun9i: Add clock-indices property for bus gate clocks Chen-Yu Tsai
@ 2014-12-18  7:00 ` Chen-Yu Tsai
  2014-12-18  7:00 ` [PATCH v2 06/11] ARM: dts: sunxi: Use label to reference pio in sunxi-common-regulators Chen-Yu Tsai
                   ` (5 subsequent siblings)
  10 siblings, 0 replies; 21+ messages in thread
From: Chen-Yu Tsai @ 2014-12-18  7:00 UTC (permalink / raw)
  To: linux-arm-kernel

Add the device tree nodes for the mmc config clock nodes.

Signed-off-by: Chen-Yu Tsai <wens@csie.org>
---
 arch/arm/boot/dts/sun9i-a80.dtsi | 13 +++++++++++++
 1 file changed, 13 insertions(+)

diff --git a/arch/arm/boot/dts/sun9i-a80.dtsi b/arch/arm/boot/dts/sun9i-a80.dtsi
index eb3f91b..cd09de2 100644
--- a/arch/arm/boot/dts/sun9i-a80.dtsi
+++ b/arch/arm/boot/dts/sun9i-a80.dtsi
@@ -329,6 +329,19 @@
 		 */
 		ranges = <0 0 0 0x20000000>;
 
+		mmc_config_clk: clk at 01c13000 {
+			compatible = "allwinner,sun9i-a80-mmc-config-clk";
+			reg = <0x01c13000 0x10>;
+			clocks = <&ahb0_gates 8>;
+			clock-names = "ahb";
+			resets = <&ahb0_resets 8>;
+			reset-names = "ahb";
+			#clock-cells = <1>;
+			#reset-cells = <1>;
+			clock-output-names = "mmc0_config", "mmc1_config",
+					     "mmc2_config", "mmc3_config";
+		};
+
 		gic: interrupt-controller at 01c41000 {
 			compatible = "arm,cortex-a7-gic", "arm,cortex-a15-gic";
 			reg = <0x01c41000 0x1000>,
-- 
2.1.3

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

* [PATCH v2 06/11] ARM: dts: sunxi: Use label to reference pio in sunxi-common-regulators
  2014-12-18  7:00 [PATCH v2 00/11] ARM: sun9i: Enable MMC support on Allwinner A80 Chen-Yu Tsai
                   ` (4 preceding siblings ...)
  2014-12-18  7:00 ` [PATCH v2 05/11] ARM: dts: sun9i: Add mmc config clock nodes Chen-Yu Tsai
@ 2014-12-18  7:00 ` Chen-Yu Tsai
  2014-12-18  7:00 ` [PATCH v2 07/11] ARM: dts: sun9i: Add mmc controller nodes to the A80 dtsi Chen-Yu Tsai
                   ` (4 subsequent siblings)
  10 siblings, 0 replies; 21+ messages in thread
From: Chen-Yu Tsai @ 2014-12-18  7:00 UTC (permalink / raw)
  To: linux-arm-kernel

Use the label to reference the pin controller node, so that we can use
sunxi-common-regulators with sunxi families that don't share the same
address space mappings, such as sun9i.

This patch is mostly space changes due to the reduction of node parents.

Signed-off-by: Chen-Yu Tsai <wens@csie.org>
---
 arch/arm/boot/dts/sunxi-common-regulators.dtsi | 54 +++++++++++++-------------
 1 file changed, 26 insertions(+), 28 deletions(-)

diff --git a/arch/arm/boot/dts/sunxi-common-regulators.dtsi b/arch/arm/boot/dts/sunxi-common-regulators.dtsi
index d887663..4bfb0c0 100644
--- a/arch/arm/boot/dts/sunxi-common-regulators.dtsi
+++ b/arch/arm/boot/dts/sunxi-common-regulators.dtsi
@@ -47,39 +47,37 @@
  *     OTHER DEALINGS IN THE SOFTWARE.
  */
 
-/ {
-	soc at 01c00000 {
-		pio: pinctrl at 01c20800 {
-			ahci_pwr_pin_a: ahci_pwr_pin at 0 {
-				allwinner,pins = "PB8";
-				allwinner,function = "gpio_out";
-				allwinner,drive = <0>;
-				allwinner,pull = <0>;
-			};
+&pio {
+	ahci_pwr_pin_a: ahci_pwr_pin at 0 {
+		allwinner,pins = "PB8";
+		allwinner,function = "gpio_out";
+		allwinner,drive = <0>;
+		allwinner,pull = <0>;
+	};
 
-			usb0_vbus_pin_a: usb0_vbus_pin at 0 {
-				allwinner,pins = "PB9";
-				allwinner,function = "gpio_out";
-				allwinner,drive = <0>;
-				allwinner,pull = <0>;
-			};
+	usb0_vbus_pin_a: usb0_vbus_pin at 0 {
+		allwinner,pins = "PB9";
+		allwinner,function = "gpio_out";
+		allwinner,drive = <0>;
+		allwinner,pull = <0>;
+	};
 
-			usb1_vbus_pin_a: usb1_vbus_pin at 0 {
-				allwinner,pins = "PH6";
-				allwinner,function = "gpio_out";
-				allwinner,drive = <0>;
-				allwinner,pull = <0>;
-			};
+	usb1_vbus_pin_a: usb1_vbus_pin at 0 {
+		allwinner,pins = "PH6";
+		allwinner,function = "gpio_out";
+		allwinner,drive = <0>;
+		allwinner,pull = <0>;
+	};
 
-			usb2_vbus_pin_a: usb2_vbus_pin at 0 {
-				allwinner,pins = "PH3";
-				allwinner,function = "gpio_out";
-				allwinner,drive = <0>;
-				allwinner,pull = <0>;
-			};
-		};
+	usb2_vbus_pin_a: usb2_vbus_pin at 0 {
+		allwinner,pins = "PH3";
+		allwinner,function = "gpio_out";
+		allwinner,drive = <0>;
+		allwinner,pull = <0>;
 	};
+};
 
+/ {
 	reg_ahci_5v: ahci-5v {
 		compatible = "regulator-fixed";
 		pinctrl-names = "default";
-- 
2.1.3

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

* [PATCH v2 07/11] ARM: dts: sun9i: Add mmc controller nodes to the A80 dtsi
  2014-12-18  7:00 [PATCH v2 00/11] ARM: sun9i: Enable MMC support on Allwinner A80 Chen-Yu Tsai
                   ` (5 preceding siblings ...)
  2014-12-18  7:00 ` [PATCH v2 06/11] ARM: dts: sunxi: Use label to reference pio in sunxi-common-regulators Chen-Yu Tsai
@ 2014-12-18  7:00 ` Chen-Yu Tsai
  2014-12-18  7:00 ` [PATCH v2 08/11] ARM: dts: sun9i: Add pinmux setting for mmc0 Chen-Yu Tsai
                   ` (3 subsequent siblings)
  10 siblings, 0 replies; 21+ messages in thread
From: Chen-Yu Tsai @ 2014-12-18  7:00 UTC (permalink / raw)
  To: linux-arm-kernel

The A80 has 4 mmc controllers.

Signed-off-by: Chen-Yu Tsai <wens@csie.org>
Signed-off-by: Andreas F?rber <afaerber@suse.de>
---
 arch/arm/boot/dts/sun9i-a80.dtsi | 48 ++++++++++++++++++++++++++++++++++++++++
 1 file changed, 48 insertions(+)

diff --git a/arch/arm/boot/dts/sun9i-a80.dtsi b/arch/arm/boot/dts/sun9i-a80.dtsi
index cd09de2..87198b1 100644
--- a/arch/arm/boot/dts/sun9i-a80.dtsi
+++ b/arch/arm/boot/dts/sun9i-a80.dtsi
@@ -329,6 +329,54 @@
 		 */
 		ranges = <0 0 0 0x20000000>;
 
+		mmc0: mmc at 01c0f000 {
+			compatible = "allwinner,sun5i-a13-mmc";
+			reg = <0x01c0f000 0x1000>;
+			clocks = <&mmc_config_clk 0>, <&mmc0_clk 0>,
+				 <&mmc0_clk 1>, <&mmc0_clk 2>;
+			clock-names = "ahb", "mmc", "output", "sample";
+			resets = <&mmc_config_clk 0>;
+			reset-names = "ahb";
+			interrupts = <0 60 4>;
+			status = "disabled";
+		};
+
+		mmc1: mmc at 01c10000 {
+			compatible = "allwinner,sun5i-a13-mmc";
+			reg = <0x01c10000 0x1000>;
+			clocks = <&mmc_config_clk 1>, <&mmc1_clk 0>,
+				 <&mmc1_clk 1>, <&mmc1_clk 2>;
+			clock-names = "ahb", "mmc", "output", "sample";
+			resets = <&mmc_config_clk 1>;
+			reset-names = "ahb";
+			interrupts = <0 61 4>;
+			status = "disabled";
+		};
+
+		mmc2: mmc at 01c11000 {
+			compatible = "allwinner,sun5i-a13-mmc";
+			reg = <0x01c11000 0x1000>;
+			clocks = <&mmc_config_clk 2>, <&mmc2_clk 0>,
+				 <&mmc2_clk 1>, <&mmc2_clk 2>;
+			clock-names = "ahb", "mmc", "output", "sample";
+			resets = <&mmc_config_clk 2>;
+			reset-names = "ahb";
+			interrupts = <0 62 4>;
+			status = "disabled";
+		};
+
+		mmc3: mmc at 01c12000 {
+			compatible = "allwinner,sun5i-a13-mmc";
+			reg = <0x01c12000 0x1000>;
+			clocks = <&mmc_config_clk 3>, <&mmc3_clk 0>,
+				 <&mmc3_clk 1>, <&mmc3_clk 2>;
+			clock-names = "ahb", "mmc", "output", "sample";
+			resets = <&mmc_config_clk 3>;
+			reset-names = "ahb";
+			interrupts = <0 63 4>;
+			status = "disabled";
+		};
+
 		mmc_config_clk: clk at 01c13000 {
 			compatible = "allwinner,sun9i-a80-mmc-config-clk";
 			reg = <0x01c13000 0x10>;
-- 
2.1.3

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

* [PATCH v2 08/11] ARM: dts: sun9i: Add pinmux setting for mmc0
  2014-12-18  7:00 [PATCH v2 00/11] ARM: sun9i: Enable MMC support on Allwinner A80 Chen-Yu Tsai
                   ` (6 preceding siblings ...)
  2014-12-18  7:00 ` [PATCH v2 07/11] ARM: dts: sun9i: Add mmc controller nodes to the A80 dtsi Chen-Yu Tsai
@ 2014-12-18  7:00 ` Chen-Yu Tsai
  2014-12-18  7:00 ` [PATCH v2 09/11] ARM: dts: sun9i: Enable mmc0 on A80 Optimus Board Chen-Yu Tsai
                   ` (2 subsequent siblings)
  10 siblings, 0 replies; 21+ messages in thread
From: Chen-Yu Tsai @ 2014-12-18  7:00 UTC (permalink / raw)
  To: linux-arm-kernel

mmc0 is only available on port F, and is always used with a 4 bit wide
bus for the onboard micro-sd slot.

Signed-off-by: Chen-Yu Tsai <wens@csie.org>
Signed-off-by: Andreas F?rber <afaerber@suse.de>
---
 arch/arm/boot/dts/sun9i-a80.dtsi | 8 ++++++++
 1 file changed, 8 insertions(+)

diff --git a/arch/arm/boot/dts/sun9i-a80.dtsi b/arch/arm/boot/dts/sun9i-a80.dtsi
index 87198b1..b42e2e7 100644
--- a/arch/arm/boot/dts/sun9i-a80.dtsi
+++ b/arch/arm/boot/dts/sun9i-a80.dtsi
@@ -466,6 +466,14 @@
 				allwinner,pull = <0>;
 			};
 
+			mmc0_pins: mmc0 {
+				allwinner,pins = "PF0", "PF1" ,"PF2", "PF3",
+						 "PF4", "PF5";
+				allwinner,function = "mmc0";
+				allwinner,drive = <2>;
+				allwinner,pull = <0>;
+			};
+
 			uart0_pins_a: uart0 at 0 {
 				allwinner,pins = "PH12", "PH13";
 				allwinner,function = "uart0";
-- 
2.1.3

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

* [PATCH v2 09/11] ARM: dts: sun9i: Enable mmc0 on A80 Optimus Board
  2014-12-18  7:00 [PATCH v2 00/11] ARM: sun9i: Enable MMC support on Allwinner A80 Chen-Yu Tsai
                   ` (7 preceding siblings ...)
  2014-12-18  7:00 ` [PATCH v2 08/11] ARM: dts: sun9i: Add pinmux setting for mmc0 Chen-Yu Tsai
@ 2014-12-18  7:00 ` Chen-Yu Tsai
  2014-12-18  7:00 ` [PATCH v2 10/11] ARM: dts: sun9i: Add 8 bit mmc pinmux setting for mmc2 Chen-Yu Tsai
  2014-12-18  7:00 ` [PATCH v2 11/11] ARM: dts: sun9i: Enable mmc2 on A80 Optimus Board Chen-Yu Tsai
  10 siblings, 0 replies; 21+ messages in thread
From: Chen-Yu Tsai @ 2014-12-18  7:00 UTC (permalink / raw)
  To: linux-arm-kernel

Enable the micro-sd slot on the A80 Optimus Board, which is connected to
mmc0. This adds the card-detect gpio and enables mmc0.

This patch also adds a 3V fixed regulator, which is the default I/O
voltage level.

Signed-off-by: Chen-Yu Tsai <wens@csie.org>
Signed-off-by: Andreas F?rber <afaerber@suse.de>
---
 arch/arm/boot/dts/sun9i-a80-optimus.dts | 18 ++++++++++++++++++
 1 file changed, 18 insertions(+)

diff --git a/arch/arm/boot/dts/sun9i-a80-optimus.dts b/arch/arm/boot/dts/sun9i-a80-optimus.dts
index 506948f..4c94aff 100644
--- a/arch/arm/boot/dts/sun9i-a80-optimus.dts
+++ b/arch/arm/boot/dts/sun9i-a80-optimus.dts
@@ -49,6 +49,7 @@
 
 /dts-v1/;
 /include/ "sun9i-a80.dtsi"
+/include/ "sunxi-common-regulators.dtsi"
 
 / {
 	model = "Merrii A80 Optimus Board";
@@ -59,6 +60,16 @@
 	};
 
 	soc {
+		mmc0: mmc at 01c0f000 {
+			pinctrl-names = "default";
+			pinctrl-0 = <&mmc0_pins>, <&mmc0_cd_pin_optimus>;
+			vmmc-supply = <&reg_vcc3v0>;
+			bus-width = <4>;
+			cd-gpios = <&pio 7 18 0>; /* PH8 */
+			cd-inverted;
+			status = "okay";
+		};
+
 		pio: pinctrl at 06000800 {
 			i2c3_pins_a: i2c3 at 0 {
 				/* Enable internal pull-up */
@@ -72,6 +83,13 @@
 				allwinner,pull = <0>;
 			};
 
+			mmc0_cd_pin_optimus: mmc0_cd_pin at 0 {
+				allwinner,pins = "PH18";
+				allwinner,function = "gpio_in";
+				allwinner,drive = <0>;
+				allwinner,pull = <1>;
+			};
+
 			uart4_pins_a: uart4 at 0 {
 				/* Enable internal pull-up */
 				allwinner,pull = <1>;
-- 
2.1.3

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

* [PATCH v2 10/11] ARM: dts: sun9i: Add 8 bit mmc pinmux setting for mmc2
  2014-12-18  7:00 [PATCH v2 00/11] ARM: sun9i: Enable MMC support on Allwinner A80 Chen-Yu Tsai
                   ` (8 preceding siblings ...)
  2014-12-18  7:00 ` [PATCH v2 09/11] ARM: dts: sun9i: Enable mmc0 on A80 Optimus Board Chen-Yu Tsai
@ 2014-12-18  7:00 ` Chen-Yu Tsai
  2014-12-18  7:00 ` [PATCH v2 11/11] ARM: dts: sun9i: Enable mmc2 on A80 Optimus Board Chen-Yu Tsai
  10 siblings, 0 replies; 21+ messages in thread
From: Chen-Yu Tsai @ 2014-12-18  7:00 UTC (permalink / raw)
  To: linux-arm-kernel

mmc2 is available on port C. Add a pinmux setting for 8 bit wide eMMC.

Signed-off-by: Chen-Yu Tsai <wens@csie.org>
Signed-off-by: Andreas F?rber <afaerber@suse.de>
---
 arch/arm/boot/dts/sun9i-a80.dtsi | 9 +++++++++
 1 file changed, 9 insertions(+)

diff --git a/arch/arm/boot/dts/sun9i-a80.dtsi b/arch/arm/boot/dts/sun9i-a80.dtsi
index b42e2e7..7dc09e7 100644
--- a/arch/arm/boot/dts/sun9i-a80.dtsi
+++ b/arch/arm/boot/dts/sun9i-a80.dtsi
@@ -474,6 +474,15 @@
 				allwinner,pull = <0>;
 			};
 
+			mmc2_8bit_pins: mmc2_8bit {
+				allwinner,pins = "PC6", "PC7", "PC8", "PC9",
+						 "PC10", "PC11", "PC12",
+						 "PC13", "PC14", "PC15";
+				allwinner,function = "mmc2";
+				allwinner,drive = <2>;
+				allwinner,pull = <1>;
+			};
+
 			uart0_pins_a: uart0 at 0 {
 				allwinner,pins = "PH12", "PH13";
 				allwinner,function = "uart0";
-- 
2.1.3

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

* [PATCH v2 11/11] ARM: dts: sun9i: Enable mmc2 on A80 Optimus Board
  2014-12-18  7:00 [PATCH v2 00/11] ARM: sun9i: Enable MMC support on Allwinner A80 Chen-Yu Tsai
                   ` (9 preceding siblings ...)
  2014-12-18  7:00 ` [PATCH v2 10/11] ARM: dts: sun9i: Add 8 bit mmc pinmux setting for mmc2 Chen-Yu Tsai
@ 2014-12-18  7:00 ` Chen-Yu Tsai
  10 siblings, 0 replies; 21+ messages in thread
From: Chen-Yu Tsai @ 2014-12-18  7:00 UTC (permalink / raw)
  To: linux-arm-kernel

The A80 Optimus Board has a 16GB eMMC connected to mmc2, with 8 bit
wide data bus.

Signed-off-by: Chen-Yu Tsai <wens@csie.org>
Signed-off-by: Andreas F?rber <afaerber@suse.de>
---
 arch/arm/boot/dts/sun9i-a80-optimus.dts | 9 +++++++++
 1 file changed, 9 insertions(+)

diff --git a/arch/arm/boot/dts/sun9i-a80-optimus.dts b/arch/arm/boot/dts/sun9i-a80-optimus.dts
index 4c94aff..2d0d490 100644
--- a/arch/arm/boot/dts/sun9i-a80-optimus.dts
+++ b/arch/arm/boot/dts/sun9i-a80-optimus.dts
@@ -70,6 +70,15 @@
 			status = "okay";
 		};
 
+		mmc2: mmc at 01c11000 {
+			pinctrl-names = "default";
+			pinctrl-0 = <&mmc2_8bit_pins>;
+			vmmc-supply = <&reg_vcc3v0>;
+			bus-width = <8>;
+			non-removable;
+			status = "okay";
+		};
+
 		pio: pinctrl at 06000800 {
 			i2c3_pins_a: i2c3 at 0 {
 				/* Enable internal pull-up */
-- 
2.1.3

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

* [PATCH v2 01/11] clk: sunxi: Add mod0 and mmc module clock support for A80
  2014-12-18  7:00 ` [PATCH v2 01/11] clk: sunxi: Add mod0 and mmc module clock support for A80 Chen-Yu Tsai
@ 2014-12-19 18:02   ` Maxime Ripard
  2014-12-20 12:43     ` Chen-Yu Tsai
  0 siblings, 1 reply; 21+ messages in thread
From: Maxime Ripard @ 2014-12-19 18:02 UTC (permalink / raw)
  To: linux-arm-kernel

Hi Chen-Yu,

On Thu, Dec 18, 2014 at 03:00:48PM +0800, Chen-Yu Tsai wrote:
> The module 0 style clocks, or storage module clocks as named in the
> official SDK, are almost the same as the module 0 clocks on earlier
> Allwinner SoCs. The only difference is wider mux register bits.
> 
> As with earlier Allwinner SoCs, mmc module clocks are a special case
> of mod0 clocks, with phase controls for 2 child clocks, output and
> sample.
> 
> This patch adds support for both.
> 
> Signed-off-by: Chen-Yu Tsai <wens@csie.org>
> ---
>  Documentation/devicetree/bindings/clock/sunxi.txt |  7 +-
>  drivers/clk/sunxi/clk-mod0.c                      | 99 +++++++++++++++++++++++
>  2 files changed, 104 insertions(+), 2 deletions(-)
> 
> diff --git a/Documentation/devicetree/bindings/clock/sunxi.txt b/Documentation/devicetree/bindings/clock/sunxi.txt
> index 8c60433..b660bdb 100644
> --- a/Documentation/devicetree/bindings/clock/sunxi.txt
> +++ b/Documentation/devicetree/bindings/clock/sunxi.txt
> @@ -56,7 +56,9 @@ Required properties:
>  	"allwinner,sun8i-a23-apb2-gates-clk" - for the APB2 gates on A23
>  	"allwinner,sun5i-a13-mbus-clk" - for the MBUS clock on A13
>  	"allwinner,sun4i-a10-mmc-clk" - for the MMC clock
> +	"allwinner,sun9i-a80-mmc-clk" - for mmc module clocks on A80
>  	"allwinner,sun4i-a10-mod0-clk" - for the module 0 family of clocks
> +	"allwinner,sun9i-a80-mod0-clk" - for module 0 (storage) clocks on A80
>  	"allwinner,sun8i-a23-mbus-clk" - for the MBUS clock on A23
>  	"allwinner,sun7i-a20-out-clk" - for the external output clocks
>  	"allwinner,sun7i-a20-gmac-clk" - for the GMAC clock module on A20/A31
> @@ -72,7 +74,8 @@ Required properties for all clocks:
>  - #clock-cells : from common clock binding; shall be set to 0 except for
>  	the following compatibles where it shall be set to 1:
>  	"allwinner,*-gates-clk", "allwinner,sun4i-pll5-clk",
> -	"allwinner,sun4i-pll6-clk", "allwinner,sun6i-a31-pll6-clk"
> +	"allwinner,sun4i-pll6-clk", "allwinner,sun6i-a31-pll6-clk",
> +	"allwinner,*-usb-clk", "allwinner,*-mmc-clk"
>  - clock-output-names : shall be the corresponding names of the outputs.
>  	If the clock module only has one output, the name shall be the
>  	module name.
> @@ -94,7 +97,7 @@ For "allwinner,sun6i-a31-pll6-clk", there are 2 outputs. The first output
>  is the normal PLL6 output, or "pll6". The second output is rate doubled
>  PLL6, or "pll6x2".
>  
> -The "allwinner,sun4i-a10-mmc-clk" has three different outputs: the
> +The "allwinner,*-mmc-clk" clocks have three different outputs: the
>  main clock, with the ID 0, and the output and sample clocks, with the
>  IDs 1 and 2, respectively.
>  
> diff --git a/drivers/clk/sunxi/clk-mod0.c b/drivers/clk/sunxi/clk-mod0.c
> index 4ac52c7..ef36e89 100644
> --- a/drivers/clk/sunxi/clk-mod0.c
> +++ b/drivers/clk/sunxi/clk-mod0.c
> @@ -93,6 +93,30 @@ static void __init sun4i_a10_mod0_setup(struct device_node *node)
>  }
>  CLK_OF_DECLARE(sun4i_a10_mod0, "allwinner,sun4i-a10-mod0-clk", sun4i_a10_mod0_setup);
>  
> +static const struct factors_data sun9i_a80_mod0_data __initconst = {
> +	.enable = 31,
> +	.mux = 24,
> +	.muxmask = BIT(3) | BIT(2) | BIT(1) | BIT(0),
> +	.table = &sun4i_a10_mod0_config,
> +	.getter = sun4i_a10_get_mod0_factors,
> +};
> +
> +static void __init sun9i_a80_mod0_setup(struct device_node *node)
> +{
> +	void __iomem *reg;
> +
> +	reg = of_io_request_and_map(node, 0, of_node_full_name(node));
> +	if (!reg) {
> +		pr_err("Could not get registers for mod0-clk: %s\n",
> +		       node->name);
> +		return;
> +	}
> +
> +	sunxi_factors_register(node, &sun9i_a80_mod0_data,
> +			       &sun4i_a10_mod0_lock, reg);
> +}
> +CLK_OF_DECLARE(sun9i_a80_mod0, "allwinner,sun9i-a80-mod0-clk", sun9i_a80_mod0_setup);
> +
>  static DEFINE_SPINLOCK(sun5i_a13_mbus_lock);
>  
>  static void __init sun5i_a13_mbus_setup(struct device_node *node)
> @@ -309,3 +333,78 @@ err_free_data:
>  	kfree(clk_data);
>  }
>  CLK_OF_DECLARE(sun4i_a10_mmc, "allwinner,sun4i-a10-mmc-clk", sun4i_a10_mmc_setup);
> +
> +static DEFINE_SPINLOCK(sun9i_a80_mmc_lock);
> +
> +static void __init sun9i_a80_mmc_setup(struct device_node *node)
> +{
> +	struct clk_onecell_data *clk_data;
> +	const char *parent;
> +	void __iomem *reg;
> +	int i;
> +
> +	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;
> +	}
> +
> +	clk_data = kmalloc(sizeof(*clk_data), GFP_KERNEL);
> +	if (!clk_data)
> +		return;
> +
> +	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,
> +						   &sun9i_a80_mod0_data,
> +						   &sun9i_a80_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 = &sun9i_a80_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])) {
> +			kfree(phase);
> +			continue;
> +		}
> +	}
> +
> +	of_clk_add_provider(node, of_clk_src_onecell_get, clk_data);
> +
> +	return;
> +
> +err_free_clks:
> +	kfree(clk_data->clks);
> +err_free_data:
> +	kfree(clk_data);
> +}
> +CLK_OF_DECLARE(sun9i_a80_mmc, "allwinner,sun9i-a80-mmc-clk", sun9i_a80_mmc_setup);

That looks a lot like the A10 MMC clock. What's changing? only the
data to feed to the factors setup code?

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/20141219/310c5257/attachment.sig>

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

* [PATCH v2 03/11] clk: sunxi: Add driver for A80 MMC config clocks/resets
  2014-12-18  7:00 ` [PATCH v2 03/11] clk: sunxi: Add driver for A80 MMC config clocks/resets Chen-Yu Tsai
@ 2014-12-19 18:08   ` Maxime Ripard
  2014-12-22  2:15     ` Chen-Yu Tsai
  0 siblings, 1 reply; 21+ messages in thread
From: Maxime Ripard @ 2014-12-19 18:08 UTC (permalink / raw)
  To: linux-arm-kernel

On Thu, Dec 18, 2014 at 03:00:50PM +0800, Chen-Yu Tsai wrote:
> +static int sun9i_a80_mmc_config_clk_probe(struct platform_device *pdev)
> +{
> +	struct device_node *np = pdev->dev.of_node;
> +	struct sun9i_mmc_clk_data *data;
> +	struct clk_onecell_data *clk_data;
> +	const char *clk_name = np->name;
> +	const char *clk_parent;
> +	struct resource *r;
> +	int count, i, ret;
> +
> +	data = devm_kzalloc(&pdev->dev, sizeof(*data), GFP_KERNEL);
> +	if (!data)
> +		return -ENOMEM;
> +
> +	spin_lock_init(&data->lock);
> +
> +	r = platform_get_resource(pdev, IORESOURCE_MEM, 0);
> +	/* one clock/reset pair per word */
> +	count = DIV_ROUND_UP((r->end - r->start + 1), SUN9I_MMC_WIDTH);
> +	data->membase = devm_ioremap_resource(&pdev->dev, r);
> +	if (IS_ERR(data->membase))
> +		return PTR_ERR(data->membase);
> +
> +	clk_data = &data->clk_data;
> +	clk_data->clk_num = count;
> +	clk_data->clks = devm_kcalloc(&pdev->dev, count, sizeof(struct clk *),

Hmmm, are you sure of that sizeof?

> +				      GFP_KERNEL);
> +	if (!clk_data->clks)
> +		return -ENOMEM;
> +
> +	clk_parent = of_clk_get_parent_name(np, 0);
> +	if (!clk_parent)
> +		return -EINVAL;
> +
> +	data->clk = devm_clk_get(&pdev->dev, NULL);
> +	if (IS_ERR(data->clk)) {
> +		dev_err(&pdev->dev, "Could not get clock\n");
> +		return PTR_ERR(data->clk);
> +	}
> +
> +	data->reset = devm_reset_control_get(&pdev->dev, NULL);
> +	if (IS_ERR(data->reset)) {
> +		dev_err(&pdev->dev, "Could not get reset control\n");
> +		return PTR_ERR(data->reset);
> +	}
> +
> +	ret = reset_control_deassert(data->reset);
> +	if (ret) {
> +		dev_err(&pdev->dev, "Reset deassert err %d\n", ret);
> +		return ret;
> +	}
> +
> +	for (i = 0; i < count; i++) {
> +		of_property_read_string_index(np, "clock-output-names",
> +					      i, &clk_name);
> +
> +		clk_data->clks[i] = clk_register_gate(&pdev->dev, clk_name,
> +						      clk_parent, 0,
> +						      data->membase + SUN9I_MMC_WIDTH * i,
> +						      SUN9I_MMC_GATE_BIT, 0,
> +						      &data->lock);
> +
> +		if (IS_ERR(clk_data->clks[i])) {
> +			ret = PTR_ERR(clk_data->clks[i]);
> +			goto err_clk_register;
> +		}
> +	}
> +
> +	ret = of_clk_add_provider(np, of_clk_src_onecell_get, clk_data);
> +	if (ret)
> +		goto err_clk_provider;
> +
> +	data->rcdev.owner = THIS_MODULE;
> +	data->rcdev.nr_resets = count;
> +	data->rcdev.ops = &sun9i_mmc_reset_ops;
> +	data->rcdev.of_node = pdev->dev.of_node;
> +
> +	ret = reset_controller_register(&data->rcdev);
> +	if (ret)
> +		goto err_rc_reg;
> +
> +	platform_set_drvdata(pdev, data);
> +
> +	return 0;
> +
> +err_rc_reg:
> +	of_clk_del_provider(np);
> +
> +err_clk_provider:
> +	for (i = 0; i < count; i++)
> +		clk_unregister(clk_data->clks[i]);
> +
> +err_clk_register:
> +	reset_control_assert(data->reset);
> +
> +	return ret;
> +}
> +
> +static int sun9i_a80_mmc_config_clk_remove(struct platform_device *pdev)
> +{
> +	struct device_node *np = pdev->dev.of_node;
> +	struct sun9i_mmc_clk_data *data = platform_get_drvdata(pdev);
> +	struct clk_onecell_data *clk_data = &data->clk_data;
> +	int i;
> +
> +	reset_controller_unregister(&data->rcdev);
> +	of_clk_del_provider(np);
> +	for (i = 0; i < clk_data->clk_num; i++)
> +		clk_unregister(clk_data->clks[i]);
> +
> +	reset_control_assert(data->reset);
> +
> +	return 0;
> +}
> +
> +static const struct of_device_id sun9i_a80_mmc_config_clk_dt_ids[] = {
> +	{ .compatible = "allwinner,sun9i-a80-mmc-config-clk" },
> +	{ /* sentinel */ }
> +};
> +
> +static struct platform_driver sun9i_a80_mmc_config_clk_driver = {
> +	.driver = {
> +		.name = "sun9i-a80-mmc-config-clk",
> +		.of_match_table = sun9i_a80_mmc_config_clk_dt_ids,
> +	},
> +	.probe = sun9i_a80_mmc_config_clk_probe,
> +	.remove = sun9i_a80_mmc_config_clk_remove,
> +};
> +module_platform_driver(sun9i_a80_mmc_config_clk_driver);
> +
> +MODULE_AUTHOR("Chen-Yu Tsai <wens@csie.org>");
> +MODULE_DESCRIPTION("Allwinner A80 MMC clock/reset Driver");
> +MODULE_LICENSE("GPL v2");
> -- 
> 2.1.3
> 

It looks fine otherwise. 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/20141219/a4f3ce89/attachment.sig>

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

* [PATCH v2 01/11] clk: sunxi: Add mod0 and mmc module clock support for A80
  2014-12-19 18:02   ` Maxime Ripard
@ 2014-12-20 12:43     ` Chen-Yu Tsai
  2015-01-08  9:38       ` Maxime Ripard
  0 siblings, 1 reply; 21+ messages in thread
From: Chen-Yu Tsai @ 2014-12-20 12:43 UTC (permalink / raw)
  To: linux-arm-kernel

Hi,

On Sat, Dec 20, 2014 at 2:02 AM, Maxime Ripard
<maxime.ripard@free-electrons.com> wrote:
> Hi Chen-Yu,
>
> On Thu, Dec 18, 2014 at 03:00:48PM +0800, Chen-Yu Tsai wrote:
>> The module 0 style clocks, or storage module clocks as named in the
>> official SDK, are almost the same as the module 0 clocks on earlier
>> Allwinner SoCs. The only difference is wider mux register bits.
>>
>> As with earlier Allwinner SoCs, mmc module clocks are a special case
>> of mod0 clocks, with phase controls for 2 child clocks, output and
>> sample.
>>
>> This patch adds support for both.
>>
>> Signed-off-by: Chen-Yu Tsai <wens@csie.org>
>> ---
>>  Documentation/devicetree/bindings/clock/sunxi.txt |  7 +-
>>  drivers/clk/sunxi/clk-mod0.c                      | 99 +++++++++++++++++++++++
>>  2 files changed, 104 insertions(+), 2 deletions(-)
>>
>> diff --git a/Documentation/devicetree/bindings/clock/sunxi.txt b/Documentation/devicetree/bindings/clock/sunxi.txt
>> index 8c60433..b660bdb 100644
>> --- a/Documentation/devicetree/bindings/clock/sunxi.txt
>> +++ b/Documentation/devicetree/bindings/clock/sunxi.txt
>> @@ -56,7 +56,9 @@ Required properties:
>>       "allwinner,sun8i-a23-apb2-gates-clk" - for the APB2 gates on A23
>>       "allwinner,sun5i-a13-mbus-clk" - for the MBUS clock on A13
>>       "allwinner,sun4i-a10-mmc-clk" - for the MMC clock
>> +     "allwinner,sun9i-a80-mmc-clk" - for mmc module clocks on A80
>>       "allwinner,sun4i-a10-mod0-clk" - for the module 0 family of clocks
>> +     "allwinner,sun9i-a80-mod0-clk" - for module 0 (storage) clocks on A80
>>       "allwinner,sun8i-a23-mbus-clk" - for the MBUS clock on A23
>>       "allwinner,sun7i-a20-out-clk" - for the external output clocks
>>       "allwinner,sun7i-a20-gmac-clk" - for the GMAC clock module on A20/A31
>> @@ -72,7 +74,8 @@ Required properties for all clocks:
>>  - #clock-cells : from common clock binding; shall be set to 0 except for
>>       the following compatibles where it shall be set to 1:
>>       "allwinner,*-gates-clk", "allwinner,sun4i-pll5-clk",
>> -     "allwinner,sun4i-pll6-clk", "allwinner,sun6i-a31-pll6-clk"
>> +     "allwinner,sun4i-pll6-clk", "allwinner,sun6i-a31-pll6-clk",
>> +     "allwinner,*-usb-clk", "allwinner,*-mmc-clk"
>>  - clock-output-names : shall be the corresponding names of the outputs.
>>       If the clock module only has one output, the name shall be the
>>       module name.
>> @@ -94,7 +97,7 @@ For "allwinner,sun6i-a31-pll6-clk", there are 2 outputs. The first output
>>  is the normal PLL6 output, or "pll6". The second output is rate doubled
>>  PLL6, or "pll6x2".
>>
>> -The "allwinner,sun4i-a10-mmc-clk" has three different outputs: the
>> +The "allwinner,*-mmc-clk" clocks have three different outputs: the
>>  main clock, with the ID 0, and the output and sample clocks, with the
>>  IDs 1 and 2, respectively.
>>
>> diff --git a/drivers/clk/sunxi/clk-mod0.c b/drivers/clk/sunxi/clk-mod0.c
>> index 4ac52c7..ef36e89 100644
>> --- a/drivers/clk/sunxi/clk-mod0.c
>> +++ b/drivers/clk/sunxi/clk-mod0.c
>> @@ -93,6 +93,30 @@ static void __init sun4i_a10_mod0_setup(struct device_node *node)
>>  }
>>  CLK_OF_DECLARE(sun4i_a10_mod0, "allwinner,sun4i-a10-mod0-clk", sun4i_a10_mod0_setup);
>>
>> +static const struct factors_data sun9i_a80_mod0_data __initconst = {
>> +     .enable = 31,
>> +     .mux = 24,
>> +     .muxmask = BIT(3) | BIT(2) | BIT(1) | BIT(0),
>> +     .table = &sun4i_a10_mod0_config,
>> +     .getter = sun4i_a10_get_mod0_factors,
>> +};
>> +
>> +static void __init sun9i_a80_mod0_setup(struct device_node *node)
>> +{
>> +     void __iomem *reg;
>> +
>> +     reg = of_io_request_and_map(node, 0, of_node_full_name(node));
>> +     if (!reg) {
>> +             pr_err("Could not get registers for mod0-clk: %s\n",
>> +                    node->name);
>> +             return;
>> +     }
>> +
>> +     sunxi_factors_register(node, &sun9i_a80_mod0_data,
>> +                            &sun4i_a10_mod0_lock, reg);
>> +}
>> +CLK_OF_DECLARE(sun9i_a80_mod0, "allwinner,sun9i-a80-mod0-clk", sun9i_a80_mod0_setup);
>> +
>>  static DEFINE_SPINLOCK(sun5i_a13_mbus_lock);
>>
>>  static void __init sun5i_a13_mbus_setup(struct device_node *node)
>> @@ -309,3 +333,78 @@ err_free_data:
>>       kfree(clk_data);
>>  }
>>  CLK_OF_DECLARE(sun4i_a10_mmc, "allwinner,sun4i-a10-mmc-clk", sun4i_a10_mmc_setup);
>> +
>> +static DEFINE_SPINLOCK(sun9i_a80_mmc_lock);
>> +
>> +static void __init sun9i_a80_mmc_setup(struct device_node *node)
>> +{
>> +     struct clk_onecell_data *clk_data;
>> +     const char *parent;
>> +     void __iomem *reg;
>> +     int i;
>> +
>> +     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;
>> +     }
>> +
>> +     clk_data = kmalloc(sizeof(*clk_data), GFP_KERNEL);
>> +     if (!clk_data)
>> +             return;
>> +
>> +     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,
>> +                                                &sun9i_a80_mod0_data,
>> +                                                &sun9i_a80_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 = &sun9i_a80_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])) {
>> +                     kfree(phase);
>> +                     continue;
>> +             }
>> +     }
>> +
>> +     of_clk_add_provider(node, of_clk_src_onecell_get, clk_data);
>> +
>> +     return;
>> +
>> +err_free_clks:
>> +     kfree(clk_data->clks);
>> +err_free_data:
>> +     kfree(clk_data);
>> +}
>> +CLK_OF_DECLARE(sun9i_a80_mmc, "allwinner,sun9i-a80-mmc-clk", sun9i_a80_mmc_setup);
>
> That looks a lot like the A10 MMC clock. What's changing? only the
> data to feed to the factors setup code?

That's correct. Only the mux width in the data fed to the setup code
and the lock differ.

The hardware can work with the a10 mod0 code, but it won't recover from
cases where someone writes to the upper bits of the mux, since it doesn't
know about them.

ChenYu

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

* [PATCH v2 03/11] clk: sunxi: Add driver for A80 MMC config clocks/resets
  2014-12-19 18:08   ` Maxime Ripard
@ 2014-12-22  2:15     ` Chen-Yu Tsai
  2015-01-08  9:39       ` Maxime Ripard
  0 siblings, 1 reply; 21+ messages in thread
From: Chen-Yu Tsai @ 2014-12-22  2:15 UTC (permalink / raw)
  To: linux-arm-kernel

On Sat, Dec 20, 2014 at 2:08 AM, Maxime Ripard
<maxime.ripard@free-electrons.com> wrote:
> On Thu, Dec 18, 2014 at 03:00:50PM +0800, Chen-Yu Tsai wrote:
>> +static int sun9i_a80_mmc_config_clk_probe(struct platform_device *pdev)
>> +{
>> +     struct device_node *np = pdev->dev.of_node;
>> +     struct sun9i_mmc_clk_data *data;
>> +     struct clk_onecell_data *clk_data;
>> +     const char *clk_name = np->name;
>> +     const char *clk_parent;
>> +     struct resource *r;
>> +     int count, i, ret;
>> +
>> +     data = devm_kzalloc(&pdev->dev, sizeof(*data), GFP_KERNEL);
>> +     if (!data)
>> +             return -ENOMEM;
>> +
>> +     spin_lock_init(&data->lock);
>> +
>> +     r = platform_get_resource(pdev, IORESOURCE_MEM, 0);
>> +     /* one clock/reset pair per word */
>> +     count = DIV_ROUND_UP((r->end - r->start + 1), SUN9I_MMC_WIDTH);
>> +     data->membase = devm_ioremap_resource(&pdev->dev, r);
>> +     if (IS_ERR(data->membase))
>> +             return PTR_ERR(data->membase);
>> +
>> +     clk_data = &data->clk_data;
>> +     clk_data->clk_num = count;
>> +     clk_data->clks = devm_kcalloc(&pdev->dev, count, sizeof(struct clk *),
>
> Hmmm, are you sure of that sizeof?

Quite sure. Code in clk-sunxi.c for gates:

    clk_data->clks = kzalloc((qty+1) * sizeof(struct clk *), GFP_KERNEL);

Note I'm using kcalloc here.

Also definition for clk_data:

    struct clk_onecell_data {
            struct clk **clks;
            unsigned int clk_num;
    };

>
>> +                                   GFP_KERNEL);
>> +     if (!clk_data->clks)
>> +             return -ENOMEM;
>> +
>> +     clk_parent = of_clk_get_parent_name(np, 0);
>> +     if (!clk_parent)
>> +             return -EINVAL;
>> +
>> +     data->clk = devm_clk_get(&pdev->dev, NULL);
>> +     if (IS_ERR(data->clk)) {
>> +             dev_err(&pdev->dev, "Could not get clock\n");
>> +             return PTR_ERR(data->clk);
>> +     }
>> +
>> +     data->reset = devm_reset_control_get(&pdev->dev, NULL);
>> +     if (IS_ERR(data->reset)) {
>> +             dev_err(&pdev->dev, "Could not get reset control\n");
>> +             return PTR_ERR(data->reset);
>> +     }
>> +
>> +     ret = reset_control_deassert(data->reset);
>> +     if (ret) {
>> +             dev_err(&pdev->dev, "Reset deassert err %d\n", ret);
>> +             return ret;
>> +     }
>> +
>> +     for (i = 0; i < count; i++) {
>> +             of_property_read_string_index(np, "clock-output-names",
>> +                                           i, &clk_name);
>> +
>> +             clk_data->clks[i] = clk_register_gate(&pdev->dev, clk_name,
>> +                                                   clk_parent, 0,
>> +                                                   data->membase + SUN9I_MMC_WIDTH * i,
>> +                                                   SUN9I_MMC_GATE_BIT, 0,
>> +                                                   &data->lock);
>> +
>> +             if (IS_ERR(clk_data->clks[i])) {
>> +                     ret = PTR_ERR(clk_data->clks[i]);
>> +                     goto err_clk_register;
>> +             }
>> +     }
>> +
>> +     ret = of_clk_add_provider(np, of_clk_src_onecell_get, clk_data);
>> +     if (ret)
>> +             goto err_clk_provider;
>> +
>> +     data->rcdev.owner = THIS_MODULE;
>> +     data->rcdev.nr_resets = count;
>> +     data->rcdev.ops = &sun9i_mmc_reset_ops;
>> +     data->rcdev.of_node = pdev->dev.of_node;
>> +
>> +     ret = reset_controller_register(&data->rcdev);
>> +     if (ret)
>> +             goto err_rc_reg;
>> +
>> +     platform_set_drvdata(pdev, data);
>> +
>> +     return 0;
>> +
>> +err_rc_reg:
>> +     of_clk_del_provider(np);
>> +
>> +err_clk_provider:
>> +     for (i = 0; i < count; i++)
>> +             clk_unregister(clk_data->clks[i]);
>> +
>> +err_clk_register:
>> +     reset_control_assert(data->reset);
>> +
>> +     return ret;
>> +}
>> +
>> +static int sun9i_a80_mmc_config_clk_remove(struct platform_device *pdev)
>> +{
>> +     struct device_node *np = pdev->dev.of_node;
>> +     struct sun9i_mmc_clk_data *data = platform_get_drvdata(pdev);
>> +     struct clk_onecell_data *clk_data = &data->clk_data;
>> +     int i;
>> +
>> +     reset_controller_unregister(&data->rcdev);
>> +     of_clk_del_provider(np);
>> +     for (i = 0; i < clk_data->clk_num; i++)
>> +             clk_unregister(clk_data->clks[i]);
>> +
>> +     reset_control_assert(data->reset);
>> +
>> +     return 0;
>> +}
>> +
>> +static const struct of_device_id sun9i_a80_mmc_config_clk_dt_ids[] = {
>> +     { .compatible = "allwinner,sun9i-a80-mmc-config-clk" },
>> +     { /* sentinel */ }
>> +};
>> +
>> +static struct platform_driver sun9i_a80_mmc_config_clk_driver = {
>> +     .driver = {
>> +             .name = "sun9i-a80-mmc-config-clk",
>> +             .of_match_table = sun9i_a80_mmc_config_clk_dt_ids,
>> +     },
>> +     .probe = sun9i_a80_mmc_config_clk_probe,
>> +     .remove = sun9i_a80_mmc_config_clk_remove,
>> +};
>> +module_platform_driver(sun9i_a80_mmc_config_clk_driver);
>> +
>> +MODULE_AUTHOR("Chen-Yu Tsai <wens@csie.org>");
>> +MODULE_DESCRIPTION("Allwinner A80 MMC clock/reset Driver");
>> +MODULE_LICENSE("GPL v2");
>> --
>> 2.1.3
>>
>
> It looks fine otherwise. Thanks!

Thanks!

ChenYu

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

* [PATCH v2 01/11] clk: sunxi: Add mod0 and mmc module clock support for A80
  2014-12-20 12:43     ` Chen-Yu Tsai
@ 2015-01-08  9:38       ` Maxime Ripard
  2015-01-12  2:39         ` [linux-sunxi] " Chen-Yu Tsai
  0 siblings, 1 reply; 21+ messages in thread
From: Maxime Ripard @ 2015-01-08  9:38 UTC (permalink / raw)
  To: linux-arm-kernel

On Sat, Dec 20, 2014 at 08:43:27PM +0800, Chen-Yu Tsai wrote:
> > That looks a lot like the A10 MMC clock. What's changing? only the
> > data to feed to the factors setup code?
> 
> That's correct. Only the mux width in the data fed to the setup code
> and the lock differ.
> 
> The hardware can work with the a10 mod0 code, but it won't recover from
> cases where someone writes to the upper bits of the mux, since it doesn't
> know about them.

I'd very much prefer if we could factorise that code then.

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/20150108/80c7f14b/attachment.sig>

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

* [PATCH v2 03/11] clk: sunxi: Add driver for A80 MMC config clocks/resets
  2014-12-22  2:15     ` Chen-Yu Tsai
@ 2015-01-08  9:39       ` Maxime Ripard
  0 siblings, 0 replies; 21+ messages in thread
From: Maxime Ripard @ 2015-01-08  9:39 UTC (permalink / raw)
  To: linux-arm-kernel

On Mon, Dec 22, 2014 at 10:15:19AM +0800, Chen-Yu Tsai wrote:
> >> +     clk_data->clks = devm_kcalloc(&pdev->dev, count, sizeof(struct clk *),
> >
> > Hmmm, are you sure of that sizeof?
> 
> Quite sure. Code in clk-sunxi.c for gates:
> 
>     clk_data->clks = kzalloc((qty+1) * sizeof(struct clk *), GFP_KERNEL);
> 
> Note I'm using kcalloc here.
> 
> Also definition for clk_data:
> 
>     struct clk_onecell_data {
>             struct clk **clks;
>             unsigned int clk_num;
>     };

Ah, right, my bad :)

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/20150108/2153110c/attachment.sig>

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

* [linux-sunxi] Re: [PATCH v2 01/11] clk: sunxi: Add mod0 and mmc module clock support for A80
  2015-01-08  9:38       ` Maxime Ripard
@ 2015-01-12  2:39         ` Chen-Yu Tsai
  2015-01-12  2:54           ` Chen-Yu Tsai
  2015-01-12 15:19           ` Maxime Ripard
  0 siblings, 2 replies; 21+ messages in thread
From: Chen-Yu Tsai @ 2015-01-12  2:39 UTC (permalink / raw)
  To: linux-arm-kernel

On Thu, Jan 8, 2015 at 5:38 PM, Maxime Ripard
<maxime.ripard@free-electrons.com> wrote:
> On Sat, Dec 20, 2014 at 08:43:27PM +0800, Chen-Yu Tsai wrote:
>> > That looks a lot like the A10 MMC clock. What's changing? only the
>> > data to feed to the factors setup code?
>>
>> That's correct. Only the mux width in the data fed to the setup code
>> and the lock differ.
>>
>> The hardware can work with the a10 mod0 code, but it won't recover from
>> cases where someone writes to the upper bits of the mux, since it doesn't
>> know about them.
>
> I'd very much prefer if we could factorise that code then.

I was hoping to not have to extend sunxi-factors-clk any more. But yes,
I can add mux_width and mux_table fields to factors_data.


ChenYu

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

* [linux-sunxi] Re: [PATCH v2 01/11] clk: sunxi: Add mod0 and mmc module clock support for A80
  2015-01-12  2:39         ` [linux-sunxi] " Chen-Yu Tsai
@ 2015-01-12  2:54           ` Chen-Yu Tsai
  2015-01-12 15:19           ` Maxime Ripard
  1 sibling, 0 replies; 21+ messages in thread
From: Chen-Yu Tsai @ 2015-01-12  2:54 UTC (permalink / raw)
  To: linux-arm-kernel

On Mon, Jan 12, 2015 at 10:39 AM, Chen-Yu Tsai <wens@csie.org> wrote:
> On Thu, Jan 8, 2015 at 5:38 PM, Maxime Ripard
> <maxime.ripard@free-electrons.com> wrote:
>> On Sat, Dec 20, 2014 at 08:43:27PM +0800, Chen-Yu Tsai wrote:
>>> > That looks a lot like the A10 MMC clock. What's changing? only the
>>> > data to feed to the factors setup code?
>>>
>>> That's correct. Only the mux width in the data fed to the setup code
>>> and the lock differ.
>>>
>>> The hardware can work with the a10 mod0 code, but it won't recover from
>>> cases where someone writes to the upper bits of the mux, since it doesn't
>>> know about them.
>>
>> I'd very much prefer if we could factorise that code then.
>
> I was hoping to not have to extend sunxi-factors-clk any more. But yes,
> I can add mux_width and mux_table fields to factors_data.

OK. This was not what I meant to say at all. I've generalized
sun4i_a10_mmc_setup() in the next version.

ChenYu

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

* [linux-sunxi] Re: [PATCH v2 01/11] clk: sunxi: Add mod0 and mmc module clock support for A80
  2015-01-12  2:39         ` [linux-sunxi] " Chen-Yu Tsai
  2015-01-12  2:54           ` Chen-Yu Tsai
@ 2015-01-12 15:19           ` Maxime Ripard
  1 sibling, 0 replies; 21+ messages in thread
From: Maxime Ripard @ 2015-01-12 15:19 UTC (permalink / raw)
  To: linux-arm-kernel

On Mon, Jan 12, 2015 at 10:39:38AM +0800, Chen-Yu Tsai wrote:
> On Thu, Jan 8, 2015 at 5:38 PM, Maxime Ripard
> <maxime.ripard@free-electrons.com> wrote:
> > On Sat, Dec 20, 2014 at 08:43:27PM +0800, Chen-Yu Tsai wrote:
> >> > That looks a lot like the A10 MMC clock. What's changing? only the
> >> > data to feed to the factors setup code?
> >>
> >> That's correct. Only the mux width in the data fed to the setup code
> >> and the lock differ.
> >>
> >> The hardware can work with the a10 mod0 code, but it won't recover from
> >> cases where someone writes to the upper bits of the mux, since it doesn't
> >> know about them.
> >
> > I'd very much prefer if we could factorise that code then.
> 
> I was hoping to not have to extend sunxi-factors-clk any more. But yes,
> I can add mux_width and mux_table fields to factors_data.

I didn't really thought of putting it into sunxi-factors, just have a
common probe for the two, with for example the code checking which
compatible is used, and put one value or another.

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/20150112/66668de5/attachment.sig>

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

end of thread, other threads:[~2015-01-12 15:19 UTC | newest]

Thread overview: 21+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2014-12-18  7:00 [PATCH v2 00/11] ARM: sun9i: Enable MMC support on Allwinner A80 Chen-Yu Tsai
2014-12-18  7:00 ` [PATCH v2 01/11] clk: sunxi: Add mod0 and mmc module clock support for A80 Chen-Yu Tsai
2014-12-19 18:02   ` Maxime Ripard
2014-12-20 12:43     ` Chen-Yu Tsai
2015-01-08  9:38       ` Maxime Ripard
2015-01-12  2:39         ` [linux-sunxi] " Chen-Yu Tsai
2015-01-12  2:54           ` Chen-Yu Tsai
2015-01-12 15:19           ` Maxime Ripard
2014-12-18  7:00 ` [PATCH v2 02/11] ARM: dts: sun9i: Add mmc module clock nodes " Chen-Yu Tsai
2014-12-18  7:00 ` [PATCH v2 03/11] clk: sunxi: Add driver for A80 MMC config clocks/resets Chen-Yu Tsai
2014-12-19 18:08   ` Maxime Ripard
2014-12-22  2:15     ` Chen-Yu Tsai
2015-01-08  9:39       ` Maxime Ripard
2014-12-18  7:00 ` [PATCH v2 04/11] ARM: dts: sun9i: Add clock-indices property for bus gate clocks Chen-Yu Tsai
2014-12-18  7:00 ` [PATCH v2 05/11] ARM: dts: sun9i: Add mmc config clock nodes Chen-Yu Tsai
2014-12-18  7:00 ` [PATCH v2 06/11] ARM: dts: sunxi: Use label to reference pio in sunxi-common-regulators Chen-Yu Tsai
2014-12-18  7:00 ` [PATCH v2 07/11] ARM: dts: sun9i: Add mmc controller nodes to the A80 dtsi Chen-Yu Tsai
2014-12-18  7:00 ` [PATCH v2 08/11] ARM: dts: sun9i: Add pinmux setting for mmc0 Chen-Yu Tsai
2014-12-18  7:00 ` [PATCH v2 09/11] ARM: dts: sun9i: Enable mmc0 on A80 Optimus Board Chen-Yu Tsai
2014-12-18  7:00 ` [PATCH v2 10/11] ARM: dts: sun9i: Add 8 bit mmc pinmux setting for mmc2 Chen-Yu Tsai
2014-12-18  7:00 ` [PATCH v2 11/11] ARM: dts: sun9i: Enable mmc2 on A80 Optimus Board Chen-Yu Tsai

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).