[PATCH RFC/RFT] ARM: S5P: Fix USB and 48M clock enable procedure

Paulius Zaleckas paulius.zaleckas at gmail.com
Tue Oct 12 15:40:21 EDT 2010


Signed-off-by: Paulius Zaleckas <paulius.zaleckas at gmail.com>
---

 arch/arm/mach-s5p6440/clock.c              |   23 -------
 arch/arm/plat-s5p/clock.c                  |   86 ++++++++++++++++++++++++++++
 arch/arm/plat-s5p/include/plat/s5p-clock.h |    1 
 3 files changed, 86 insertions(+), 24 deletions(-)

diff --git a/arch/arm/mach-s5p6440/clock.c b/arch/arm/mach-s5p6440/clock.c
index ca6e48d..5a5b245 100644
--- a/arch/arm/mach-s5p6440/clock.c
+++ b/arch/arm/mach-s5p6440/clock.c
@@ -295,27 +295,6 @@ static struct clksrc_clk clk_pclk_low = {
 	.reg_div = { .reg = S5P_CLK_DIV3, .shift = 12, .size = 4 },
 };
 
-int s5p6440_clk48m_ctrl(struct clk *clk, int enable)
-{
-	unsigned long flags;
-	u32 val;
-
-	/* can't rely on clock lock, this register has other usages */
-	local_irq_save(flags);
-
-	val = __raw_readl(S5P_OTHERS);
-	if (enable)
-		val |= S5P_OTHERS_USB_SIG_MASK;
-	else
-		val &= ~S5P_OTHERS_USB_SIG_MASK;
-
-	__raw_writel(val, S5P_OTHERS);
-
-	local_irq_restore(flags);
-
-	return 0;
-}
-
 static int s5p6440_pclk_ctrl(struct clk *clk, int enable)
 {
 	return s5p_gatectrl(S5P_CLK_GATE_PCLK, clk, enable);
@@ -769,8 +748,6 @@ void __init_or_cpufreq s5p6440_setup_clocks(void)
 	clk_fout_epll.enable = s5p6440_epll_enable;
 	clk_fout_epll.ops = &s5p6440_epll_ops;
 
-	clk_48m.enable = s5p6440_clk48m_ctrl;
-
 	xtal_clk = clk_get(NULL, "ext_xtal");
 	BUG_ON(IS_ERR(xtal_clk));
 
diff --git a/arch/arm/plat-s5p/clock.c b/arch/arm/plat-s5p/clock.c
index b5e2552..337ced6 100644
--- a/arch/arm/plat-s5p/clock.c
+++ b/arch/arm/plat-s5p/clock.c
@@ -19,11 +19,16 @@
 #include <linux/clk.h>
 #include <linux/sysdev.h>
 #include <linux/io.h>
+#include <linux/delay.h>
 #include <asm/div64.h>
 
+#include <mach/map.h>
+#include <mach/regs-clock.h>
+
 #include <plat/clock.h>
 #include <plat/clock-clksrc.h>
 #include <plat/s5p-clock.h>
+#include <plat/regs-usb-hsotg-phy.h>
 
 /* fin_apll, fin_mpll and fin_epll are all the same clock, which we call
  * clk_ext_xtal_mux.
@@ -33,9 +38,89 @@ struct clk clk_ext_xtal_mux = {
 	.id		= -1,
 };
 
+#ifdef S3C_VA_USB_HSPHY
+void __init s5p_clk_xusbxti_is_osc(int is_osc)
+{
+	u32 val;
+
+	/* no need to protect since it will be called from machine init */
+	val = __raw_readl(S3C_PHYCLK);
+	if (is_osc)
+		val |= S3C_PHYCLK_EXT_OSC;
+	else
+		val &= ~S3C_PHYCLK_EXT_OSC;
+	__raw_writel(val, S3C_PHYCLK);
+}
+
+static int clk_xusbxti_ctrl(struct clk *clk, int enable)
+{
+	unsigned long flags;
+	u32 val;
+
+	/* can't rely on clock lock, this register has other usages */
+	local_irq_save(flags);
+
+#if defined(S5P_OTHERS) && defined(S5P_OTHERS_USB_SIG_MASK)
+	val = __raw_readl(S5P_OTHERS);
+	if (enable)
+		val |= S5P_OTHERS_USB_SIG_MASK;
+	else
+		val &= ~S5P_OTHERS_USB_SIG_MASK;
+
+	__raw_writel(val, S5P_OTHERS);
+#endif
+
+	val = __raw_readl(S3C_PHYPWR);
+	if (enable)
+		val &= ~(SRC_PHYPWR_OTG_DISABLE | SRC_PHYPWR_ANALOG_POWERDOWN |
+			 SRC_PHYPWR_FORCE_SUSPEND);
+	else
+		val |= (SRC_PHYPWR_OTG_DISABLE | SRC_PHYPWR_ANALOG_POWERDOWN |
+			SRC_PHYPWR_FORCE_SUSPEND);
+	__raw_writel(val, S3C_PHYPWR);
+	mdelay(1);
+
+	if (enable) {
+		val = __raw_readl(S3C_PHYCLK);
+
+		val &= ~S3C_PHYCLK_CLKSEL_MASK;
+
+		switch (clk->rate) {
+		case 12000000:
+			val |= S3C_PHYCLK_CLKSEL_12M;
+			break;
+		case 24000000:
+			val |= S3C_PHYCLK_CLKSEL_24M;
+			break;
+		default:
+			pr_err("Invalid USB PHY external clock frequency: %lu\n",
+			       clk->rate);
+		case 48000000:
+			/* default reference clock */
+			break;
+		}
+
+		__raw_writel(val | S3C_PHYCLK_CLK_FORCE, S3C_PHYCLK);
+
+		/* issue a full set of resets to the otg and core */
+		__raw_writel(S3C_RSTCON_PHY, S3C_RSTCON);
+		udelay(20);	/* at-least 10uS */
+		__raw_writel(0, S3C_RSTCON);
+	}
+
+	local_irq_restore(flags);
+
+	return 0;
+}
+#else
+#define clk_xusbxti_ctrl NULL
+#endif /* S3C_VA_USB_HSPHY */
+
 struct clk clk_xusbxti = {
 	.name		= "xusbxti",
 	.id		= -1,
+	.rate		= 48000000,
+	.enable		= clk_xusbxti_ctrl,
 };
 
 struct clk s5p_clk_27m = {
@@ -49,6 +134,7 @@ struct clk clk_48m = {
 	.name		= "clk_48m",
 	.id		= -1,
 	.rate		= 48000000,
+	.parent		= &clk_xusbxti,
 };
 
 /* APLL clock output
diff --git a/arch/arm/plat-s5p/include/plat/s5p-clock.h b/arch/arm/plat-s5p/include/plat/s5p-clock.h
index 09418b1..1c9266d 100644
--- a/arch/arm/plat-s5p/include/plat/s5p-clock.h
+++ b/arch/arm/plat-s5p/include/plat/s5p-clock.h
@@ -38,7 +38,6 @@ extern struct clksrc_sources clk_src_apll;
 extern struct clksrc_sources clk_src_mpll;
 extern struct clksrc_sources clk_src_epll;
 
-extern int s5p6440_clk48m_ctrl(struct clk *clk, int enable);
 extern int s5p_gatectrl(void __iomem *reg, struct clk *clk, int enable);
 
 #endif /* __ASM_PLAT_S5P_CLOCK_H */




More information about the linux-arm-kernel mailing list