aboutsummaryrefslogtreecommitdiff
path: root/arch
diff options
context:
space:
mode:
authorInderpal Singh <inderpal.singh@linaro.org>2012-11-29 14:49:23 +0530
committerTushar Behera <tushar.behera@linaro.org>2013-03-14 10:46:16 +0530
commit4aef12131a163f31d668b735f6af8edd841fb5e5 (patch)
tree93f44577b55b0b9f73188767c4d2bc983248395e /arch
parent2dfb26e8d01df5da613a52c2db9e7d3622a748a1 (diff)
ARM: EXYNOS: Setup USB HSIC ports for EXYNOS4412
The USB HSIC on exynos4412 is differant than the exynos4210 HSIC. This patch adds all the new registers and initializes the USB HSIC properly. Signed-off-by: Inderpal Singh <inderpal.singh@linaro.org> Signed-off-by: Tushar Behera <tushar.behera@linaro.org>
Diffstat (limited to 'arch')
-rw-r--r--arch/arm/mach-exynos/include/mach/regs-pmu.h5
-rw-r--r--arch/arm/mach-exynos/include/mach/regs-usb-phy.h27
-rw-r--r--arch/arm/mach-exynos/setup-usb-phy.c87
3 files changed, 106 insertions, 13 deletions
diff --git a/arch/arm/mach-exynos/include/mach/regs-pmu.h b/arch/arm/mach-exynos/include/mach/regs-pmu.h
index 3f30aa1ae354..52535b3d0d27 100644
--- a/arch/arm/mach-exynos/include/mach/regs-pmu.h
+++ b/arch/arm/mach-exynos/include/mach/regs-pmu.h
@@ -163,6 +163,11 @@
#define S5P_CHECK_SLEEP 0x00000BAD
+/* Only for EXYNOS4412*/
+#define S5P_PMU_USB_PHY_CONTROL S5P_PMUREG(0x0704)
+#define S5P_PMU_HSIC_1_PHY_CONTROL S5P_PMUREG(0x0708)
+#define S5P_PMU_HSIC_2_PHY_CONTROL S5P_PMUREG(0x070C)
+
/* Only for EXYNOS4210 */
#define S5P_USBDEVICE_PHY_CONTROL S5P_PMUREG(0x0704)
#define S5P_USBDEVICE_PHY_ENABLE (1 << 0)
diff --git a/arch/arm/mach-exynos/include/mach/regs-usb-phy.h b/arch/arm/mach-exynos/include/mach/regs-usb-phy.h
index 07277735252e..0ddf9d9fd51d 100644
--- a/arch/arm/mach-exynos/include/mach/regs-usb-phy.h
+++ b/arch/arm/mach-exynos/include/mach/regs-usb-phy.h
@@ -13,12 +13,15 @@
#define EXYNOS4_HSOTG_PHYREG(x) ((x) + S3C_VA_USB_HSPHY)
+#define EXYNOS4412_USB_CFG (S3C_VA_SYS + 0x21C)
+
#define EXYNOS4_PHYPWR EXYNOS4_HSOTG_PHYREG(0x00)
-#define PHY1_HSIC_NORMAL_MASK (0xf << 9)
-#define PHY1_HSIC1_SLEEP (1 << 12)
-#define PHY1_HSIC1_FORCE_SUSPEND (1 << 11)
-#define PHY1_HSIC0_SLEEP (1 << 10)
-#define PHY1_HSIC0_FORCE_SUSPEND (1 << 9)
+#define PHY1_HSIC_NORMAL_MASK (0xf << 9)
+#define EXYNOS4412_PHY1_HSIC_NORMAL_MASK (0x3f << 9)
+#define PHY1_HSIC1_SLEEP (1 << 12)
+#define PHY1_HSIC1_FORCE_SUSPEND (1 << 11)
+#define PHY1_HSIC0_SLEEP (1 << 10)
+#define PHY1_HSIC0_FORCE_SUSPEND (1 << 9)
#define PHY1_STD_NORMAL_MASK (0x7 << 6)
#define PHY1_STD_SLEEP (1 << 8)
@@ -51,14 +54,16 @@
#define EXYNOS4X12_CLKSEL_20M (0x4 << 0)
#define EXYNOS4X12_CLKSEL_24M (0x5 << 0)
-#define EXYNOS4_RSTCON EXYNOS4_HSOTG_PHYREG(0x08)
-#define HOST_LINK_PORT_SWRST_MASK (0xf << 6)
-#define HOST_LINK_PORT2_SWRST (1 << 9)
-#define HOST_LINK_PORT1_SWRST (1 << 8)
-#define HOST_LINK_PORT0_SWRST (1 << 7)
-#define HOST_LINK_ALL_SWRST (1 << 6)
+#define EXYNOS4_RSTCON EXYNOS4_HSOTG_PHYREG(0x08)
+#define HOST_LINK_PORT_SWRST_MASK (0xf << 6)
+#define EXYNOS4412_HOST_LINK_PORT_SWRST_MASK (0xf << 7)
+#define HOST_LINK_PORT2_SWRST (1 << 9)
+#define HOST_LINK_PORT1_SWRST (1 << 8)
+#define HOST_LINK_PORT0_SWRST (1 << 7)
+#define HOST_LINK_ALL_SWRST (1 << 6)
#define PHY1_SWRST_MASK (0x7 << 3)
+#define EXYNOS4412_PHY1_SWRST_MASK (0xf << 3)
#define PHY1_HSIC_SWRST (1 << 5)
#define PHY1_STD_SWRST (1 << 4)
#define PHY1_ALL_SWRST (1 << 3)
diff --git a/arch/arm/mach-exynos/setup-usb-phy.c b/arch/arm/mach-exynos/setup-usb-phy.c
index b81cc569a8dd..23c0a6d8c721 100644
--- a/arch/arm/mach-exynos/setup-usb-phy.c
+++ b/arch/arm/mach-exynos/setup-usb-phy.c
@@ -202,12 +202,95 @@ static int exynos4210_usb_phy1_exit(struct platform_device *pdev)
return 0;
}
+static void exynos_usb_mux_change(struct platform_device *pdev, int val)
+{
+ u32 is_host;
+
+ is_host = readl(EXYNOS4412_USB_CFG);
+ writel(val, EXYNOS4412_USB_CFG);
+
+ if (is_host != val)
+ dev_dbg(&pdev->dev, "Change USB MUX from %s to %s",
+ is_host ? "Host" : "Device",
+ val ? "Host" : "Device");
+}
+
+static int exynos4412_usb_phy20_init(struct platform_device *pdev)
+{
+ u32 phypwr, rstcon;
+ struct clk *otg_clk;
+ int err;
+
+ atomic_inc(&host_usage);
+
+ otg_clk = clk_get(&pdev->dev, "otg");
+ if (IS_ERR(otg_clk)) {
+ dev_err(&pdev->dev, "Failed to get otg clock\n");
+ return PTR_ERR(otg_clk);
+ }
+
+ err = clk_enable(otg_clk);
+ if (err) {
+ clk_put(otg_clk);
+ return err;
+ }
+
+ if (exynos4_usb_host_phy_is_on()) {
+ dev_err(&pdev->dev, "Already power on PHY\n");
+ return 0;
+ }
+
+ writel(1, S5P_PMU_USB_PHY_CONTROL);
+ writel(1, S5P_PMU_HSIC_1_PHY_CONTROL);
+ writel(1, S5P_PMU_HSIC_2_PHY_CONTROL);
+
+ /* USB MUX change from Device to Host */
+ exynos_usb_mux_change(pdev, 1);
+
+ /* set clock frequency for PLL */
+ exynos4210_usb_phy_clkset(pdev);
+
+ /* set to normal of Device */
+ phypwr = readl(EXYNOS4_PHYPWR) & ~PHY0_NORMAL_MASK;
+ writel(phypwr, EXYNOS4_PHYPWR);
+
+ /* set to normal of Host */
+ phypwr = readl(EXYNOS4_PHYPWR);
+ phypwr &= ~(PHY1_STD_NORMAL_MASK
+ | EXYNOS4412_PHY1_HSIC_NORMAL_MASK);
+ writel(phypwr, EXYNOS4_PHYPWR);
+
+ /* reset both PHY and Link of Device */
+ rstcon = readl(EXYNOS4_RSTCON) | PHY0_SWRST_MASK;
+ writel(rstcon, EXYNOS4_RSTCON);
+ udelay(10);
+ rstcon &= ~PHY0_SWRST_MASK;
+ writel(rstcon, EXYNOS4_RSTCON);
+
+ /* reset both PHY and Link of Host */
+ rstcon = readl(EXYNOS4_RSTCON)
+ | EXYNOS4412_HOST_LINK_PORT_SWRST_MASK
+ | EXYNOS4412_PHY1_SWRST_MASK;
+ writel(rstcon, EXYNOS4_RSTCON);
+ udelay(10);
+
+ rstcon &= ~(EXYNOS4412_HOST_LINK_PORT_SWRST_MASK
+ | EXYNOS4412_PHY1_SWRST_MASK);
+ writel(rstcon, EXYNOS4_RSTCON);
+ udelay(80);
+
+ return 0;
+}
int s5p_usb_phy_init(struct platform_device *pdev, int type)
{
if (type == S5P_USB_PHY_DEVICE)
return exynos4210_usb_phy0_init(pdev);
- else if (type == S5P_USB_PHY_HOST)
- return exynos4210_usb_phy1_init(pdev);
+ else if (type == S5P_USB_PHY_HOST) {
+ if (soc_is_exynos4412())
+ return exynos4412_usb_phy20_init(pdev);
+ else if (soc_is_exynos4210())
+ return exynos4210_usb_phy1_init(pdev);
+ }
return -EINVAL;
}