diff options
Diffstat (limited to 'arch/arm/mach-exynos4')
-rw-r--r-- | arch/arm/mach-exynos4/Makefile | 2 | ||||
-rw-r--r-- | arch/arm/mach-exynos4/cpu.c | 7 | ||||
-rw-r--r-- | arch/arm/mach-exynos4/include/mach/map.h | 1 | ||||
-rw-r--r-- | arch/arm/mach-exynos4/include/mach/regs-pmu.h | 3 | ||||
-rw-r--r-- | arch/arm/mach-exynos4/include/mach/regs-usb-phy.h | 64 | ||||
-rw-r--r-- | arch/arm/mach-exynos4/usb-phy.c | 136 |
6 files changed, 212 insertions, 1 deletions
diff --git a/arch/arm/mach-exynos4/Makefile b/arch/arm/mach-exynos4/Makefile index 9be104f63c0b..777897551e42 100644 --- a/arch/arm/mach-exynos4/Makefile +++ b/arch/arm/mach-exynos4/Makefile @@ -54,3 +54,5 @@ obj-$(CONFIG_EXYNOS4_SETUP_I2C7) += setup-i2c7.o obj-$(CONFIG_EXYNOS4_SETUP_KEYPAD) += setup-keypad.o obj-$(CONFIG_EXYNOS4_SETUP_SDHCI) += setup-sdhci.o obj-$(CONFIG_EXYNOS4_SETUP_SDHCI_GPIO) += setup-sdhci-gpio.o + +obj-$(CONFIG_USB_SUPPORT) += usb-phy.o diff --git a/arch/arm/mach-exynos4/cpu.c b/arch/arm/mach-exynos4/cpu.c index 793011391943..08813a6f66b1 100644 --- a/arch/arm/mach-exynos4/cpu.c +++ b/arch/arm/mach-exynos4/cpu.c @@ -97,7 +97,12 @@ static struct map_desc exynos4_iodesc[] __initdata = { .pfn = __phys_to_pfn(EXYNOS4_PA_SROMC), .length = SZ_4K, .type = MT_DEVICE, - }, + }, { + .virtual = (unsigned long)S5P_VA_USB_HSPHY, + .pfn = __phys_to_pfn(EXYNOS4_PA_HSPHY), + .length = SZ_4K, + .type = MT_DEVICE, + } }; static void exynos4_idle(void) diff --git a/arch/arm/mach-exynos4/include/mach/map.h b/arch/arm/mach-exynos4/include/mach/map.h index 213c2a27d7ca..0009e77a05fc 100644 --- a/arch/arm/mach-exynos4/include/mach/map.h +++ b/arch/arm/mach-exynos4/include/mach/map.h @@ -102,6 +102,7 @@ #define EXYNOS4_PA_SROMC 0x12570000 #define EXYNOS4_PA_EHCI 0x12580000 +#define EXYNOS4_PA_HSPHY 0x125B0000 #define EXYNOS4_PA_UART 0x13800000 diff --git a/arch/arm/mach-exynos4/include/mach/regs-pmu.h b/arch/arm/mach-exynos4/include/mach/regs-pmu.h index 62b0014d05e0..a9643371f8e7 100644 --- a/arch/arm/mach-exynos4/include/mach/regs-pmu.h +++ b/arch/arm/mach-exynos4/include/mach/regs-pmu.h @@ -33,6 +33,9 @@ #define S5P_EINT_WAKEUP_MASK S5P_PMUREG(0x0604) #define S5P_WAKEUP_MASK S5P_PMUREG(0x0608) +#define S5P_USBHOST_PHY_CONTROL S5P_PMUREG(0x0708) +#define S5P_USBHOST_PHY_ENABLE (1 << 0) + #define S5P_MIPI_DPHY_CONTROL(n) S5P_PMUREG(0x0710 + (n) * 4) #define S5P_MIPI_DPHY_ENABLE (1 << 0) #define S5P_MIPI_DPHY_SRESETN (1 << 1) diff --git a/arch/arm/mach-exynos4/include/mach/regs-usb-phy.h b/arch/arm/mach-exynos4/include/mach/regs-usb-phy.h new file mode 100644 index 000000000000..703118d5173c --- /dev/null +++ b/arch/arm/mach-exynos4/include/mach/regs-usb-phy.h @@ -0,0 +1,64 @@ +/* + * Copyright (C) 2011 Samsung Electronics Co.Ltd + * Author: Joonyoung Shim <jy0922.shim@samsung.com> + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + */ + +#ifndef __PLAT_S5P_REGS_USB_PHY_H +#define __PLAT_S5P_REGS_USB_PHY_H + +#define EXYNOS4_HSOTG_PHYREG(x) ((x) + S5P_VA_USB_HSPHY) + +#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_STD_NORMAL_MASK (0x7 << 6) +#define PHY1_STD_SLEEP (1 << 8) +#define PHY1_STD_ANALOG_POWERDOWN (1 << 7) +#define PHY1_STD_FORCE_SUSPEND (1 << 6) + +#define PHY0_NORMAL_MASK (0x39 << 0) +#define PHY0_SLEEP (1 << 5) +#define PHY0_OTG_DISABLE (1 << 4) +#define PHY0_ANALOG_POWERDOWN (1 << 3) +#define PHY0_FORCE_SUSPEND (1 << 0) + +#define EXYNOS4_PHYCLK EXYNOS4_HSOTG_PHYREG(0x04) +#define PHY1_COMMON_ON_N (1 << 7) +#define PHY0_COMMON_ON_N (1 << 4) +#define PHY0_ID_PULLUP (1 << 2) +#define CLKSEL_MASK (0x3 << 0) +#define CLKSEL_SHIFT (0) +#define CLKSEL_48M (0x0 << 0) +#define CLKSEL_12M (0x2 << 0) +#define CLKSEL_24M (0x3 << 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 PHY1_SWRST_MASK (0x7 << 3) +#define PHY1_HSIC_SWRST (1 << 5) +#define PHY1_STD_SWRST (1 << 4) +#define PHY1_ALL_SWRST (1 << 3) + +#define PHY0_SWRST_MASK (0x7 << 0) +#define PHY0_PHYLINK_SWRST (1 << 2) +#define PHY0_HLINK_SWRST (1 << 1) +#define PHY0_SWRST (1 << 0) + +#define EXYNOS4_PHY1CON EXYNOS4_HSOTG_PHYREG(0x34) +#define FPENABLEN (1 << 0) + +#endif /* __PLAT_S5P_REGS_USB_PHY_H */ diff --git a/arch/arm/mach-exynos4/usb-phy.c b/arch/arm/mach-exynos4/usb-phy.c new file mode 100644 index 000000000000..0883c1b824b9 --- /dev/null +++ b/arch/arm/mach-exynos4/usb-phy.c @@ -0,0 +1,136 @@ +/* + * Copyright (C) 2011 Samsung Electronics Co.Ltd + * Author: Joonyoung Shim <jy0922.shim@samsung.com> + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + * + */ + +#include <linux/clk.h> +#include <linux/delay.h> +#include <linux/err.h> +#include <linux/io.h> +#include <linux/platform_device.h> +#include <mach/regs-pmu.h> +#include <mach/regs-usb-phy.h> +#include <plat/cpu.h> +#include <plat/usb-phy.h> + +static int exynos4_usb_phy1_init(struct platform_device *pdev) +{ + struct clk *otg_clk; + struct clk *xusbxti_clk; + u32 phyclk; + u32 rstcon; + int err; + + 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; + } + + writel(readl(S5P_USBHOST_PHY_CONTROL) | S5P_USBHOST_PHY_ENABLE, + S5P_USBHOST_PHY_CONTROL); + + /* set clock frequency for PLL */ + phyclk = readl(EXYNOS4_PHYCLK) & ~CLKSEL_MASK; + + xusbxti_clk = clk_get(&pdev->dev, "xusbxti"); + if (xusbxti_clk && !IS_ERR(xusbxti_clk)) { + switch (clk_get_rate(xusbxti_clk)) { + case 12 * MHZ: + phyclk |= CLKSEL_12M; + break; + case 24 * MHZ: + phyclk |= CLKSEL_24M; + break; + default: + case 48 * MHZ: + /* default reference clock */ + break; + } + clk_put(xusbxti_clk); + } + + writel(phyclk, EXYNOS4_PHYCLK); + + /* floating prevention logic: disable */ + writel((readl(EXYNOS4_PHY1CON) | FPENABLEN), EXYNOS4_PHY1CON); + + /* set to normal HSIC 0 and 1 of PHY1 */ + writel((readl(EXYNOS4_PHYPWR) & ~PHY1_HSIC_NORMAL_MASK), + EXYNOS4_PHYPWR); + + /* set to normal standard USB of PHY1 */ + writel((readl(EXYNOS4_PHYPWR) & ~PHY1_STD_NORMAL_MASK), EXYNOS4_PHYPWR); + + /* reset all ports of both PHY and Link */ + rstcon = readl(EXYNOS4_RSTCON) | HOST_LINK_PORT_SWRST_MASK | + PHY1_SWRST_MASK; + writel(rstcon, EXYNOS4_RSTCON); + udelay(10); + + rstcon &= ~(HOST_LINK_PORT_SWRST_MASK | PHY1_SWRST_MASK); + writel(rstcon, EXYNOS4_RSTCON); + udelay(50); + + clk_disable(otg_clk); + clk_put(otg_clk); + + return 0; +} + +static int exynos4_usb_phy1_exit(struct platform_device *pdev) +{ + struct clk *otg_clk; + int err; + + 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; + } + + writel((readl(EXYNOS4_PHYPWR) | PHY1_STD_ANALOG_POWERDOWN), + EXYNOS4_PHYPWR); + + writel(readl(S5P_USBHOST_PHY_CONTROL) & ~S5P_USBHOST_PHY_ENABLE, + S5P_USBHOST_PHY_CONTROL); + + clk_disable(otg_clk); + clk_put(otg_clk); + + return 0; +} + +int s5p_usb_phy_init(struct platform_device *pdev, int type) +{ + if (type == S5P_USB_PHY_HOST) + return exynos4_usb_phy1_init(pdev); + + return -EINVAL; +} + +int s5p_usb_phy_exit(struct platform_device *pdev, int type) +{ + if (type == S5P_USB_PHY_HOST) + return exynos4_usb_phy1_exit(pdev); + + return -EINVAL; +} |