Skip to contentSkip to conversation

ARM: imx6q: clean up board specific CLKO setup

PATCH New Shawn Guo 2 participants 7 messages Jul 18, 2013

Subsystems (6)
lore
Share & tools
lore

Shawn Guo

author
#0 lore raw

cover ARM: imx6q: clean up board specific CLKO setup

The CLKO is widely used by imx6q board designs to clock audio codec. Currently, imx6q-sabrelite and imx6qdl-sabresd set up CLKO in board specific hooks, while imx6qdl-wandboard handles that in U-Boot. Since most audio codecs accept 24 MHz frequency, the series adds missing CLKO pieces into clock driver, and initially sets up CLKO with OSC24M (cko <-- cko2 <-- osc). Then those board specific CLKO setup for audio codec can be removed, while it improves the power efficiency@the same time by saving the use of PLL.

Shawn

Shawn Guo (4):
ARM: imx6q: add spdif gate clock
ARM: imx6q: add cko2 clocks
ARM: imx6q: add the missing cko output selection
ARM: imx6q: remove board specific CLKO setup

 .../devicetree/bindings/clock/imx6q-clock.txt      |    5 ++
 arch/arm/boot/dts/imx6q-sabrelite.dts              |    2 +-
 arch/arm/boot/dts/imx6qdl-sabresd.dtsi             |    2 +-
 arch/arm/boot/dts/imx6qdl-wandboard.dtsi           |    2 +-
 arch/arm/mach-imx/clk-imx6q.c                      |   30 ++++++++-
 arch/arm/mach-imx/mach-imx6q.c                     |   69 --------------------
 6 files changed, 37 insertions(+), 73 deletions(-)
Signature · 1 line
1.7.9.5
author
#1 lore raw

PATCH 1/4 ARM: imx6q: add spdif gate clock

It adds the missing spdif gate clock into imx6q clock driver.

---
 .../devicetree/bindings/clock/imx6q-clock.txt      |    1 +
 arch/arm/mach-imx/clk-imx6q.c                      |    4 +++-
 2 files changed, 4 insertions(+), 1 deletion(-)
Documentation/devicetree/bindings/clock/imx6q-clock.txt +1 -0
index a0e104f..794d089 100644
@@ -209,6 +209,7 @@ clocks and IDs.
 	pll5_post_div		194
 	pll5_video_div		195
 	eim_slow      		196
+	spdif      		197
 
 Examples:
 
arch/arm/mach-imx/clk-imx6q.c +3 -1
index db9f8f5..d739df1 100644
@@ -239,7 +239,8 @@ enum mx6q_clks {
 	pll4_audio, pll5_video, pll8_mlb, pll7_usb_host, pll6_enet, ssi1_ipg,
 	ssi2_ipg, ssi3_ipg, rom, usbphy1, usbphy2, ldb_di0_div_3_5, ldb_di1_div_3_5,
 	sata_ref, sata_ref_100m, pcie_ref, pcie_ref_125m, enet_ref, usbphy1_gate,
-	usbphy2_gate, pll4_post_div, pll5_post_div, pll5_video_div, eim_slow, clk_max
+	usbphy2_gate, pll4_post_div, pll5_post_div, pll5_video_div, eim_slow,
+	spdif, clk_max
 };
 
 static struct clk *clk[clk_max];
@@ -521,6 +522,7 @@ static void __init imx6q_clocks_init(struct device_node *ccm_node)
 	clk[sata]         = imx_clk_gate2("sata",          "ipg",               base + 0x7c, 4);
 	clk[sdma]         = imx_clk_gate2("sdma",          "ahb",               base + 0x7c, 6);
 	clk[spba]         = imx_clk_gate2("spba",          "ipg",               base + 0x7c, 12);
+	clk[spdif]        = imx_clk_gate2("spdif",         "spdif_podf",    	base + 0x7c, 14);
 	clk[ssi1_ipg]     = imx_clk_gate2("ssi1_ipg",      "ipg",               base + 0x7c, 18);
 	clk[ssi2_ipg]     = imx_clk_gate2("ssi2_ipg",      "ipg",               base + 0x7c, 20);
 	clk[ssi3_ipg]     = imx_clk_gate2("ssi3_ipg",      "ipg",               base + 0x7c, 22);
Signature · 1 line
1.7.9.5
author
#2 lore raw

PATCH 2/4 ARM: imx6q: add cko2 clocks

In reply to Shawn Guo

It adds the missing cko2 clocks, including multiplexer, divider and gate.

---
 .../devicetree/bindings/clock/imx6q-clock.txt      |    3 +++
 arch/arm/mach-imx/clk-imx6q.c                      |   15 ++++++++++++++-
 2 files changed, 17 insertions(+), 1 deletion(-)
Documentation/devicetree/bindings/clock/imx6q-clock.txt +3 -0
index 794d089..c6d7e16 100644
@@ -210,6 +210,9 @@ clocks and IDs.
 	pll5_video_div		195
 	eim_slow      		196
 	spdif      		197
+	cko2_sel      		198
+	cko2_podf      		199
+	cko2      		200
 
 Examples:
 
arch/arm/mach-imx/clk-imx6q.c +14 -1
index d739df1..924ed84 100644
@@ -206,6 +206,16 @@ static const char *vpu_axi_sels[]	= { "axi", "pll2_pfd2_396m", "pll2_pfd0_352m",
 static const char *cko1_sels[]	= { "pll3_usb_otg", "pll2_bus", "pll1_sys", "pll5_video_div",
 				    "dummy", "axi", "enfc", "ipu1_di0", "ipu1_di1", "ipu2_di0",
 				    "ipu2_di1", "ahb", "ipg", "ipg_per", "ckil", "pll4_post_div", };
+static const char *cko2_sels[] = {
+	"mmdc_ch0_axi", "mmdc_ch1_axi", "usdhc4", "usdhc1",
+	"gpu2d_axi", "dummy", "ecspi_root", "gpu3d_axi",
+	"usdhc3", "dummy", "arm", "ipu1",
+	"ipu2", "vdo_axi", "osc", "gpu2d_core",
+	"gpu3d_core", "usdhc2", "ssi1", "ssi2",
+	"ssi3", "gpu3d_shader", "vpu_axi", "can_root",
+	"ldb_di0", "ldb_di1", "esai", "eim_slow",
+	"uart_serial", "spdif", "asrc", "hsi_tx",
+};
 
 enum mx6q_clks {
 	dummy, ckil, ckih, osc, pll2_pfd0_352m, pll2_pfd1_594m, pll2_pfd2_396m,
@@ -240,7 +250,7 @@ enum mx6q_clks {
 	ssi2_ipg, ssi3_ipg, rom, usbphy1, usbphy2, ldb_di0_div_3_5, ldb_di1_div_3_5,
 	sata_ref, sata_ref_100m, pcie_ref, pcie_ref_125m, enet_ref, usbphy1_gate,
 	usbphy2_gate, pll4_post_div, pll5_post_div, pll5_video_div, eim_slow,
-	spdif, clk_max
+	spdif, cko2_sel, cko2_podf, cko2, clk_max
 };
 
 static struct clk *clk[clk_max];
@@ -398,6 +408,7 @@ static void __init imx6q_clocks_init(struct device_node *ccm_node)
 	clk[vdo_axi_sel]      = imx_clk_mux("vdo_axi_sel",      base + 0x18, 11, 1, vdo_axi_sels,      ARRAY_SIZE(vdo_axi_sels));
 	clk[vpu_axi_sel]      = imx_clk_mux("vpu_axi_sel",      base + 0x18, 14, 2, vpu_axi_sels,      ARRAY_SIZE(vpu_axi_sels));
 	clk[cko1_sel]         = imx_clk_mux("cko1_sel",         base + 0x60, 0,  4, cko1_sels,         ARRAY_SIZE(cko1_sels));
+	clk[cko2_sel]         = imx_clk_mux("cko2_sel",         base + 0x60, 16, 5, cko2_sels,         ARRAY_SIZE(cko2_sels));
 
 	/*                              name         reg      shift width busy: reg, shift parent_names  num_parents */
 	clk[periph]  = imx_clk_busy_mux("periph",  base + 0x14, 25,  1,   base + 0x48, 5,  periph_sels,  ARRAY_SIZE(periph_sels));
@@ -447,6 +458,7 @@ static void __init imx6q_clocks_init(struct device_node *ccm_node)
 	clk[emi_slow_podf]    = imx_clk_fixup_divider("emi_slow_podf", "emi_slow_sel",   base + 0x1c, 23, 3, imx_cscmr1_fixup);
 	clk[vpu_axi_podf]     = imx_clk_divider("vpu_axi_podf",     "vpu_axi_sel",       base + 0x24, 25, 3);
 	clk[cko1_podf]        = imx_clk_divider("cko1_podf",        "cko1_sel",          base + 0x60, 4,  3);
+	clk[cko2_podf]        = imx_clk_divider("cko2_podf",        "cko2_sel",          base + 0x60, 21, 3);
 
 	/*                                            name                 parent_name    reg        shift width busy: reg, shift */
 	clk[axi]               = imx_clk_busy_divider("axi",               "axi_sel",     base + 0x14, 16,  3,   base + 0x48, 0);
@@ -537,6 +549,7 @@ static void __init imx6q_clocks_init(struct device_node *ccm_node)
 	clk[vdo_axi]      = imx_clk_gate2("vdo_axi",       "vdo_axi_sel",       base + 0x80, 12);
 	clk[vpu_axi]      = imx_clk_gate2("vpu_axi",       "vpu_axi_podf",      base + 0x80, 14);
 	clk[cko1]         = imx_clk_gate("cko1",           "cko1_podf",         base + 0x60, 7);
+	clk[cko2]         = imx_clk_gate("cko2",           "cko2_podf",         base + 0x60, 24);
 
 	for (i = 0; i < ARRAY_SIZE(clk); i++)
 		if (IS_ERR(clk[i]))
Signature · 1 line
1.7.9.5
author
#3 lore raw

PATCH 3/4 ARM: imx6q: add the missing cko output selection

In reply to Shawn Guo

The clock output on imx6q CCM_CLKO1 pad is not always cko1 clock, and there is a multiplexer to select between cko1 and cko2. Add this missing selection as the clock cko.

---
 .../devicetree/bindings/clock/imx6q-clock.txt      |    1 +
 arch/arm/mach-imx/clk-imx6q.c                      |    4 +++-
 2 files changed, 4 insertions(+), 1 deletion(-)
Documentation/devicetree/bindings/clock/imx6q-clock.txt +1 -0
index c6d7e16..3066f181 100644
@@ -213,6 +213,7 @@ clocks and IDs.
 	cko2_sel      		198
 	cko2_podf      		199
 	cko2      		200
+	cko      		201
 
 Examples:
 
arch/arm/mach-imx/clk-imx6q.c +3 -1
index 924ed84..ed19b33 100644
@@ -216,6 +216,7 @@ static const char *cko2_sels[] = {
 	"ldb_di0", "ldb_di1", "esai", "eim_slow",
 	"uart_serial", "spdif", "asrc", "hsi_tx",
 };
+static const char *cko_sels[] = { "cko1", "cko2", };
 
 enum mx6q_clks {
 	dummy, ckil, ckih, osc, pll2_pfd0_352m, pll2_pfd1_594m, pll2_pfd2_396m,
@@ -250,7 +251,7 @@ enum mx6q_clks {
 	ssi2_ipg, ssi3_ipg, rom, usbphy1, usbphy2, ldb_di0_div_3_5, ldb_di1_div_3_5,
 	sata_ref, sata_ref_100m, pcie_ref, pcie_ref_125m, enet_ref, usbphy1_gate,
 	usbphy2_gate, pll4_post_div, pll5_post_div, pll5_video_div, eim_slow,
-	spdif, cko2_sel, cko2_podf, cko2, clk_max
+	spdif, cko2_sel, cko2_podf, cko2, cko, clk_max
 };
 
 static struct clk *clk[clk_max];
@@ -409,6 +410,7 @@ static void __init imx6q_clocks_init(struct device_node *ccm_node)
 	clk[vpu_axi_sel]      = imx_clk_mux("vpu_axi_sel",      base + 0x18, 14, 2, vpu_axi_sels,      ARRAY_SIZE(vpu_axi_sels));
 	clk[cko1_sel]         = imx_clk_mux("cko1_sel",         base + 0x60, 0,  4, cko1_sels,         ARRAY_SIZE(cko1_sels));
 	clk[cko2_sel]         = imx_clk_mux("cko2_sel",         base + 0x60, 16, 5, cko2_sels,         ARRAY_SIZE(cko2_sels));
+	clk[cko]              = imx_clk_mux("cko",              base + 0x60, 8, 1,  cko_sels,          ARRAY_SIZE(cko_sels));
 
 	/*                              name         reg      shift width busy: reg, shift parent_names  num_parents */
 	clk[periph]  = imx_clk_busy_mux("periph",  base + 0x14, 25,  1,   base + 0x48, 5,  periph_sels,  ARRAY_SIZE(periph_sels));
Signature · 1 line
1.7.9.5
author
#4 lore raw

PATCH 4/4 ARM: imx6q: remove board specific CLKO setup

In reply to Shawn Guo

The CLKO is widely used by imx6q board designs to clock audio codec. Since most codecs accept 24 MHz frequency, let's initially set up CLKO with OSC24M (cko <-- cko2 <-- osc). Then those board specific CLKO setup for audio codec can be removed.

The board dts files also need an update on cko reference in codec node.

---
 arch/arm/boot/dts/imx6q-sabrelite.dts    |    2 +-
 arch/arm/boot/dts/imx6qdl-sabresd.dtsi   |    2 +-
 arch/arm/boot/dts/imx6qdl-wandboard.dtsi |    2 +-
 arch/arm/mach-imx/clk-imx6q.c            |   11 +++++
 arch/arm/mach-imx/mach-imx6q.c           |   69 ------------------------------
 5 files changed, 14 insertions(+), 72 deletions(-)
arch/arm/boot/dts/imx6q-sabrelite.dts +1 -1
index e0f4cd0..3530280 100644
@@ -167,7 +167,7 @@
 	codec: sgtl5000 at 0a {
 		compatible = "fsl,sgtl5000";
 		reg = <0x0a>;
-		clocks = <&clks 169>;
+		clocks = <&clks 201>;
 		VDDA-supply = <&reg_2p5v>;
 		VDDIO-supply = <&reg_3p3v>;
 	};
arch/arm/boot/dts/imx6qdl-sabresd.dtsi +1 -1
index 166b9ae..75b36b2 100644
@@ -109,7 +109,7 @@
 	codec: wm8962 at 1a {
 		compatible = "wlf,wm8962";
 		reg = <0x1a>;
-		clocks = <&clks 169>;
+		clocks = <&clks 201>;
 		DCVDD-supply = <&reg_audio>;
 		DBVDD-supply = <&reg_audio>;
 		AVDD-supply = <&reg_audio>;
arch/arm/boot/dts/imx6qdl-wandboard.dtsi +1 -1
index 7a46f64..77188cb 100644
@@ -60,7 +60,7 @@
 	codec: sgtl5000 at 0a {
 		compatible = "fsl,sgtl5000";
 		reg = <0x0a>;
-		clocks = <&clks 169>;
+		clocks = <&clks 201>;
 		VDDA-supply = <&reg_2p5v>;
 		VDDIO-supply = <&reg_3p3v>;
 	};
arch/arm/mach-imx/clk-imx6q.c +11 -0
index ed19b33..97f2702 100644
@@ -288,6 +288,7 @@ static void __init imx6q_clocks_init(struct device_node *ccm_node)
 	struct device_node *np;
 	void __iomem *base;
 	int i, irq;
+	int ret;
 
 	clk[dummy] = imx_clk_fixed("dummy", 0);
 	clk[ckil] = imx_obtain_fixed_clock("ckil", 0);
@@ -591,6 +592,16 @@ static void __init imx6q_clocks_init(struct device_node *ccm_node)
 		clk_prepare_enable(clk[usbphy2_gate]);
 	}
 
+	/*
+	 * Let's initially set up CLKO with OSC24M, since this configuration
+	 * is widely used by imx6q board designs to clock audio codec.
+	 */
+	ret = clk_set_parent(clk[cko2_sel], clk[osc]);
+	if (!ret)
+		ret = clk_set_parent(clk[cko], clk[cko2]);
+	if (ret)
+		pr_warn("failed to set up CLKO: %d\n", ret);
+
 	/* Set initial power mode */
 	imx6q_set_lpm(WAIT_CLOCKED);
 
arch/arm/mach-imx/mach-imx6q.c +0 -69

87 lines not on this page · raw message

Signature · 1 line
1.7.9.5
maintainer
#5 lore raw

PATCH 4/4 ARM: imx6q: remove board specific CLKO setup

Quoted 7 lines · Shawn Guo

The CLKO is widely used by imx6q board designs to clock audio codec. Since most codecs accept 24 MHz frequency, let's initially set up CLKO with OSC24M (cko <-- cko2 <-- osc). Then those board specific CLKO setup for audio codec can be removed.

The board dts files also need an update on cko reference in codec node.

arch/arm/mach-imx/clk-imx6q.c static void __init imx6q_clocks_init(struct device_node *ccm_node) · line 603

Quoted 9 lines
arch/arm/mach-imx/clk-imx6q.c +9 -0
+	/*
+	 * Let's initially set up CLKO with OSC24M, since this configuration
+	 * is widely used by imx6q board designs to clock audio codec.
+	 */
+	ret = clk_set_parent(clk[cko2_sel], clk[osc]);
+	if (!ret)
+		ret = clk_set_parent(clk[cko], clk[cko2]);
+	if (ret)
+		pr_warn("failed to set up CLKO: %d\n", ret);

I don't really like that the clock setup code fiddles with clocks it has no knowledge about just because it happens to be correct for several boards.

I currently have no example where this bites me, so I think I can live with it for now. I just wonder what I should do when this clock is used for something vital to the system (clocking an FPGA for example?).

Sascha

Signature · 4 lines
Pengutronix e.K.                           |                             |
Industrial Linux Solutions                 | http://www.pengutronix.de/  |
Peiner Str. 6-8, 31137 Hildesheim, Germany | Phone: +49-5121-206917-0    |
Amtsgericht Hildesheim, HRA 2686           | Fax:   +49-5121-206917-5555 |
author
#6 lore raw

PATCH 4/4 ARM: imx6q: remove board specific CLKO setup

Quoted 8 lines · Sascha Hauer
Quoted 7 lines · Shawn Guo

The CLKO is widely used by imx6q board designs to clock audio codec. Since most codecs accept 24 MHz frequency, let's initially set up CLKO with OSC24M (cko <-- cko2 <-- osc). Then those board specific CLKO setup for audio codec can be removed.

The board dts files also need an update on cko reference in codec node.

Quoted 14 lines

arch/arm/mach-imx/clk-imx6q.c static void __init imx6q_clocks_init(struct device_node *ccm_node) · line 603

Quoted 9 lines
arch/arm/mach-imx/clk-imx6q.c +9 -0
+	/*
+	 * Let's initially set up CLKO with OSC24M, since this configuration
+	 * is widely used by imx6q board designs to clock audio codec.
+	 */
+	ret = clk_set_parent(clk[cko2_sel], clk[osc]);
+	if (!ret)
+		ret = clk_set_parent(clk[cko], clk[cko2]);
+	if (ret)
+		pr_warn("failed to set up CLKO: %d\n", ret);

I don't really like that the clock setup code fiddles with clocks it has no knowledge about just because it happens to be correct for several boards.

I have to admit it's not the best way to handle it, and I can understand your concern. What I like about it is we can remove those board specific hooks from mach-imx6q.c at least for now.

Quoted 4 lines

I currently have no example where this bites me, so I think I can live with it for now. I just wonder what I should do when this clock is used for something vital to the system (clocking an FPGA for example?).

Go back to set up CLKO in mach-imx6q.c with board specific hook for the system?

I think I chose to change the default CLKO setup for audio use case, as all the users we've seen so far is audio codec. I can still have this setup done in mach-imx6q.c with of_machine_is_compatible() check on all those board. But that also means we need to register lookups for those CLKO clocks and call clk_get_sys() to get them.

Shawn