Message ID | 1344261462-14183-3-git-send-email-dongjin.kim@agreeyamobility.net (mailing list archive) |
---|---|
State | New, archived |
Headers | show |
Hi, Now another person try to use drivers/usb/phy for it. "usb: phy: samsung: Introducing usb phy driver for hsotg" Can you use it instead of previous one? Thank you, Kyungmin Park On 8/6/12, Dongjin Kim <tobetter@gmail.com> wrote: > This patch support to control USB HSIC of EXYNOS4, > edited based on Samsung's GT-i9100 ICS Opensource Update7. > > Change-Id: Ifba33c6a5166abf3644794eee6abe528bd71f521 > Signed-off-by: Dongjin Kim <dongjin.kim@agreeyamobility.net> > --- > arch/arm/mach-exynos/common.c | 5 + > arch/arm/mach-exynos/include/mach/regs-pmu.h | 12 + > arch/arm/mach-exynos/include/mach/regs-usb-phy.h | 97 +++++ > arch/arm/mach-exynos/setup-usb-phy.c | 493 > ++++++++++++++++------ > drivers/usb/host/Kconfig | 14 + > 5 files changed, 501 insertions(+), 120 deletions(-) > > diff --git a/arch/arm/mach-exynos/common.c b/arch/arm/mach-exynos/common.c > index 4eb39cd..94d58af 100644 > --- a/arch/arm/mach-exynos/common.c > +++ b/arch/arm/mach-exynos/common.c > @@ -179,6 +179,11 @@ static struct map_desc exynos4_iodesc[] __initdata = { > .length = SZ_4K, > .type = MT_DEVICE, > }, { > + .virtual = (unsigned long)S5P_VA_GPIO2, > + .pfn = __phys_to_pfn(EXYNOS4_PA_GPIO2), > + .length = SZ_4K, > + .type = MT_DEVICE, > + }, { > .virtual = (unsigned long)S5P_VA_DMC0, > .pfn = __phys_to_pfn(EXYNOS4_PA_DMC0), > .length = SZ_64K, > diff --git a/arch/arm/mach-exynos/include/mach/regs-pmu.h > b/arch/arm/mach-exynos/include/mach/regs-pmu.h > index 0bb21e2..d98c2fe 100644 > --- a/arch/arm/mach-exynos/include/mach/regs-pmu.h > +++ b/arch/arm/mach-exynos/include/mach/regs-pmu.h > @@ -185,6 +185,15 @@ > #define S5P_PMU_LCD1_CONF S5P_PMUREG(0x3CA0) > > /* Only for EXYNOS4x12 */ > +#define S5P_USB_PHY_CONTROL S5P_PMUREG(0x0704) > +#define S5P_USB_PHY_ENABLE (0x1 << 0) > + > +#define S5P_HSIC_1_PHY_CONTROL S5P_PMUREG(0x0708) > +#define S5P_HSIC_1_PHY_ENABLE (0x1 << 0) > + > +#define S5P_HSIC_2_PHY_CONTROL S5P_PMUREG(0x070C) > +#define S5P_HSIC_2_PHY_ENABLE (0x1 << 0) > + > #define S5P_ISP_ARM_LOWPWR S5P_PMUREG(0x1050) > #define S5P_DIS_IRQ_ISP_ARM_LOCAL_LOWPWR S5P_PMUREG(0x1054) > #define S5P_DIS_IRQ_ISP_ARM_CENTRAL_LOWPWR S5P_PMUREG(0x1058) > @@ -242,6 +251,9 @@ > > #define EXYNOS5_SYS_WDTRESET (1 << 20) > > +#define EXYNOS5_USBDEV_PHY_CONTROL S5P_PMUREG(0x0704) > +#define EXYNOS5_USBHOST_PHY_CONTROL S5P_PMUREG(0x0708) > + > #define EXYNOS5_ARM_CORE0_SYS_PWR_REG S5P_PMUREG(0x1000) > #define EXYNOS5_DIS_IRQ_ARM_CORE0_LOCAL_SYS_PWR_REG S5P_PMUREG(0x1004) > #define EXYNOS5_DIS_IRQ_ARM_CORE0_CENTRAL_SYS_PWR_REG S5P_PMUREG(0x1008) > 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 0727773..79021a0 100644 > --- a/arch/arm/mach-exynos/include/mach/regs-usb-phy.h > +++ b/arch/arm/mach-exynos/include/mach/regs-usb-phy.h > @@ -43,6 +43,43 @@ > #define EXYNOS4210_CLKSEL_12M (0x2 << 0) > #define EXYNOS4210_CLKSEL_24M (0x3 << 0) > > +#define EXYNOS4210_HSIC1_NORMAL_MASK (0x3 << 11) > +#define EXYNOS4210_HSIC1_SLEEP (1 << 12) > +#define EXYNOS4210_HSIC1_FORCE_SUSPEND (1 << 11) > +#define EXYNOS4210_HSIC0_NORMAL_MASK (0x3 << 9) > +#define EXYNOS4210_HSIC0_SLEEP (1 << 10) > +#define EXYNOS4210_HSIC0_FORCE_SUSPEND (1 << 9) > + > +#define EXYNOS4210_HOST_LINK_PORT_SWRST_MASK (0xf << 6) > +#define EXYNOS4210_HOST_LINK_PORT2_SWRST (1 << 9) > +#define EXYNOS4210_HOST_LINK_PORT1_SWRST (1 << 8) > +#define EXYNOS4210_HOST_LINK_PORT0_SWRST (1 << 7) > +#define EXYNOS4210_HOST_LINK_ALL_SWRST (1 << 6) > +#define EXYNOS4210_PHY1_SWRST_MASK (0x7 << 3) > +#define EXYNOS4210_PHY1_HSIC_SWRST (1 << 5) > +#define EXYNOS4210_PHY1_STD_SWRST (1 << 4) > +#define EXYNOS4210_PHY1_ALL_SWRST (1 << 3) > + > +#define EXYNOS4X12_HSIC1_NORMAL_MASK (0x7 << 12) > +#define EXYNOS4X12_HSIC1_SLEEP (1 << 14) > +#define EXYNOS4X12_HSIC1_ANALOG_POWERDOWN (1 << 13) > +#define EXYNOS4X12_HSIC1_FORCE_SUSPEND (1 << 12) > +#define EXYNOS4X12_HSIC0_NORMAL_MASK (0x7 << 9) > +#define EXYNOS4X12_HSIC0_SLEEP (1 << 11) > +#define EXYNOS4X12_HSIC0_ANALOG_POWERDOWN (1 << 10) > +#define EXYNOS4X12_HSIC0_FORCE_SUSPEND (1 << 9) > + > +#define EXYNOS4X12_HOST_LINK_PORT_SWRST_MASK (0xf << 7) > +#define EXYNOS4X12_HOST_LINK_PORT2_SWRST (1 << 10) > +#define EXYNOS4X12_HOST_LINK_PORT1_SWRST (1 << 9) > +#define EXYNOS4X12_HOST_LINK_PORT0_SWRST (1 << 8) > +#define EXYNOS4X12_HOST_LINK_ALL_SWRST (1 << 7) > +#define EXYNOS4X12_PHY1_SWRST_MASK (0xf << 3) > +#define EXYNOS4X12_PHY1_HSIC1_SWRST (1 << 6) > +#define EXYNOS4X12_PHY1_HSIC0_SWRST (1 << 5) > +#define EXYNOS4X12_PHY1_SWRST (1 << 4) > +#define EXYNOS4X12_HOST_PHY_SWRST (1 << 3) > + > #define EXYNOS4X12_CLKSEL_MASK (0x7 << 0) > #define EXYNOS4X12_CLKSEL_9600K (0x0 << 0) > #define EXYNOS4X12_CLKSEL_10M (0x1 << 0) > @@ -71,4 +108,64 @@ > #define EXYNOS4_PHY1CON EXYNOS4_HSOTG_PHYREG(0x34) > #define FPENABLEN (1 << 0) > > +/* For Exynos5 */ > +#define EXYNOS5_PHY_HOST_CTRL0 EXYNOS4_HSOTG_PHYREG(0x00) > +#define HOST_CTRL0_PHYSWRSTALL (0x1 << 31) > +#define HOST_CTRL0_REFCLKSEL(val) (val << 19) > +#define EXYNOS5_CLKSEL_50M (0x7) > +#define EXYNOS5_CLKSEL_24M (0x5) > +#define EXYNOS5_CLKSEL_20M (0x4) > +#define EXYNOS5_CLKSEL_19200K (0x3) > +#define EXYNOS5_CLKSEL_12M (0x2) > +#define EXYNOS5_CLKSEL_10M (0x1) > +#define EXYNOS5_CLKSEL_9600K (0x0) > +#define HOST_CTRL0_CLKSEL_SHIFT (16) > +#define HOST_CTRL0_FSEL_MASK (0x7 << 16) > + > +#define HOST_CTRL0_COMMONON_N (0x1 << 9) > +#define HOST_CTRL0_SIDDQ (0x1 << 6) > +#define HOST_CTRL0_FORCESLEEP (0x1 << 5) > +#define HOST_CTRL0_FORCESUSPEND (0x1 << 4) > +#define HOST_CTRL0_WORDINTERFACE (0x1 << 3) > +#define HOST_CTRL0_UTMISWRST (0x1 << 2) > +#define HOST_CTRL0_LINKSWRST (0x1 << 1) > +#define HOST_CTRL0_PHYSWRST (0x1 << 0) > + > +#define EXYNOS5_PHY_HOST_TUNE0 EXYNOS4_HSOTG_PHYREG(0x04) > +#define EXYNOS5_PHY_HOST_TEST0 EXYNOS4_HSOTG_PHYREG(0x08) > + > +#define EXYNOS5_PHY_HSIC_CTRL1 EXYNOS4_HSOTG_PHYREG(0x10) > +#define EXYNOS5_PHY_HSIC_CTRL2 EXYNOS4_HSOTG_PHYREG(0x20) > +#define HSIC_CTRL_REFCLKSEL(val) ((val&0x3) << 23) > +#define HSIC_CTRL_REFCLKDIV(val) ((val&0x7f) << 16) > +#define HSIC_CTRL_SIDDQ (0x1 << 6) > +#define HSIC_CTRL_FORCESLEEP (0x1 << 5) > +#define HSIC_CTRL_FORCESUSPEND (0x1 << 4) > +#define HSIC_CTRL_WORDINTERFACE (0x1 << 3) > +#define HSIC_CTRL_UTMISWRST (0x1 << 2) > +#define HSIC_CTRL_PHYSWRST (0x1 << 0) > + > +#define EXYNOS5_PHY_HOST_EHCICTRL EXYNOS4_HSOTG_PHYREG(0x30) > +#define EHCICTRL_ENAINCRXALIGN (0x1 << 29) > +#define EHCICTRL_ENAINCR4 (0x1 << 28) > +#define EHCICTRL_ENAINCR8 (0x1 << 27) > +#define EHCICTRL_ENAINCR16 (0x1 << 26) > + > +#define EXYNOS5_PHY_HOST_OHCICTRL EXYNOS4_HSOTG_PHYREG(0x34) > + > +#define EXYNOS5_PHY_OTG_SYS EXYNOS4_HSOTG_PHYREG(0x38) > +#define OTG_SYS_PHYLINK_SW_RESET (0x1 << 14) > +#define OTG_SYS_LINK_SW_RST_UOTG (0x1 << 13) > +#define OTG_SYS_PHY0_SW_RST (0x1 << 12) > +#define OTG_SYS_REF_CLK_SEL(val) ((val&0x3) << 9) > +#define OTG_SYS_REF_CLK_SEL_MASK (0x3 << 9) > +#define OTG_SYS_IP_PULLUP_UOTG (0x1 << 8) > +#define OTG_SYS_COMMON_ON (0x1 << 7) > +#define OTG_SYS_CLKSEL_SHIFT (4) > +#define OTG_SYS_CTRL0_FSEL_MASK (0x7 << 4) > +#define OTG_SYS_FORCE_SLEEP (0x1 << 3) > +#define OTG_SYS_OTGDISABLE (0x1 << 2) > +#define OTG_SYS_SIDDQ_UOTG (0x1 << 1) > +#define OTG_SYS_FORCE_SUSPEND (0x1 << 0) > + > #endif /* __PLAT_S5P_REGS_USB_PHY_H */ > diff --git a/arch/arm/mach-exynos/setup-usb-phy.c > b/arch/arm/mach-exynos/setup-usb-phy.c > index b81cc56..c725745 100644 > --- a/arch/arm/mach-exynos/setup-usb-phy.c > +++ b/arch/arm/mach-exynos/setup-usb-phy.c > @@ -1,5 +1,6 @@ > /* > * Copyright (C) 2011 Samsung Electronics Co.Ltd > + * Author: Yulgon Kim <yulgon.kim@samsung.com> > * Author: Joonyoung Shim <jy0922.shim@samsung.com> > * > * This program is free software; you can redistribute it and/or modify > it > @@ -19,205 +20,457 @@ > #include <plat/cpu.h> > #include <plat/usb-phy.h> > > +#define ETC6PUD (S5P_VA_GPIO2 + 0x228) > +#define EXYNOS4_USB_CFG (S3C_VA_SYS + 0x21C) > + > +#define PHY_ENABLE (1 << 0) > +#define PHY_DISABLE (0) > + > +enum usb_host_type { > + HOST_PHY_EHCI = (0x1 << 0), > + HOST_PHY_OHCI = (0x1 << 1), > +}; > + > +enum usb_phy_type { > + USB_PHY = (0x1 << 0), > + USB_PHY0 = (0x1 << 0), > + USB_PHY1 = (0x1 << 1), > + USB_PHY_HSIC0 = (0x1 << 1), > + USB_PHY_HSIC1 = (0x1 << 2), > +}; > + > static atomic_t host_usage; > +static DEFINE_MUTEX(phy_lock); > +static struct clk *phy_clk; > > static int exynos4_usb_host_phy_is_on(void) > { > return (readl(EXYNOS4_PHYPWR) & PHY1_STD_ANALOG_POWERDOWN) ? 0 : 1; > } > > -static void exynos4210_usb_phy_clkset(struct platform_device *pdev) > +static int exynos4_usb_phy20_is_on(void) > { > - struct clk *xusbxti_clk; > - u32 phyclk; > + return exynos4_usb_host_phy_is_on(); > +} > + > +static int exynos_usb_phy_clock_enable(struct platform_device *pdev) > +{ > + int err; > + > + if (!phy_clk) { > + if (soc_is_exynos4210() || > + soc_is_exynos4212() || soc_is_exynos4412()) > + phy_clk = clk_get(&pdev->dev, "otg"); > + else > + phy_clk = clk_get(&pdev->dev, "usbhost"); > + > + if (IS_ERR(phy_clk)) { > + dev_err(&pdev->dev, "Failed to get phy clock\n"); > + return PTR_ERR(phy_clk); > + } > + } > + > + err = clk_enable(phy_clk); > + > + return err; > +} > > - xusbxti_clk = clk_get(&pdev->dev, "xusbxti"); > - if (xusbxti_clk && !IS_ERR(xusbxti_clk)) { > - if (soc_is_exynos4210()) { > - /* set clock frequency for PLL */ > - phyclk = readl(EXYNOS4_PHYCLK) & ~EXYNOS4210_CLKSEL_MASK; > - > - switch (clk_get_rate(xusbxti_clk)) { > - case 12 * MHZ: > - phyclk |= EXYNOS4210_CLKSEL_12M; > - break; > - case 48 * MHZ: > - phyclk |= EXYNOS4210_CLKSEL_48M; > - break; > - default: > - case 24 * MHZ: > - phyclk |= EXYNOS4210_CLKSEL_24M; > - break; > - } > - writel(phyclk, EXYNOS4_PHYCLK); > - } else if (soc_is_exynos4212() || soc_is_exynos4412()) { > - /* set clock frequency for PLL */ > - phyclk = readl(EXYNOS4_PHYCLK) & ~EXYNOS4X12_CLKSEL_MASK; > - > - switch (clk_get_rate(xusbxti_clk)) { > - case 9600 * KHZ: > - phyclk |= EXYNOS4X12_CLKSEL_9600K; > - break; > - case 10 * MHZ: > - phyclk |= EXYNOS4X12_CLKSEL_10M; > - break; > - case 12 * MHZ: > - phyclk |= EXYNOS4X12_CLKSEL_12M; > - break; > - case 19200 * KHZ: > - phyclk |= EXYNOS4X12_CLKSEL_19200K; > - break; > - case 20 * MHZ: > - phyclk |= EXYNOS4X12_CLKSEL_20M; > - break; > - default: > - case 24 * MHZ: > - /* default reference clock */ > - phyclk |= EXYNOS4X12_CLKSEL_24M; > - break; > - } > - writel(phyclk, EXYNOS4_PHYCLK); > +static int exynos_usb_phy_clock_disable(struct platform_device *pdev) > +{ > + if (!phy_clk) { > + if (soc_is_exynos4210() || > + soc_is_exynos4212() || soc_is_exynos4412()) > + phy_clk = clk_get(&pdev->dev, "otg"); > + else > + phy_clk = clk_get(&pdev->dev, "usbhost"); > + if (IS_ERR(phy_clk)) { > + dev_err(&pdev->dev, "Failed to get phy clock\n"); > + return PTR_ERR(phy_clk); > } > - clk_put(xusbxti_clk); > } > + > + clk_disable(phy_clk); > + > + return 0; > } > > -static int exynos4210_usb_phy0_init(struct platform_device *pdev) > +static u32 exynos_usb_phy_set_clock(struct platform_device *pdev) > { > + struct clk *ref_clk; > + u32 refclk_freq = 0; > + > + if (soc_is_exynos4210() || soc_is_exynos4212() || soc_is_exynos4412()) > + ref_clk = clk_get(&pdev->dev, "xusbxti"); > + else > + ref_clk = clk_get(&pdev->dev, "ext_xtal"); > + > + if (IS_ERR(ref_clk)) { > + dev_err(&pdev->dev, "Failed to get reference clock\n"); > + return PTR_ERR(ref_clk); > + } > + > + if (soc_is_exynos4210()) { > + switch (clk_get_rate(ref_clk)) { > + case 12 * MHZ: > + refclk_freq = EXYNOS4210_CLKSEL_12M; > + break; > + case 48 * MHZ: > + refclk_freq = EXYNOS4210_CLKSEL_48M; > + break; > + case 24 * MHZ: > + default: > + /* default reference clock */ > + refclk_freq = EXYNOS4210_CLKSEL_24M; > + break; > + } > + } else if (soc_is_exynos4212() | soc_is_exynos4412()) { > + switch (clk_get_rate(ref_clk)) { > + case 96 * 100000: > + refclk_freq = EXYNOS4X12_CLKSEL_9600K; > + break; > + case 10 * MHZ: > + refclk_freq = EXYNOS4X12_CLKSEL_10M; > + break; > + case 12 * MHZ: > + refclk_freq = EXYNOS4X12_CLKSEL_12M; > + break; > + case 192 * 100000: > + refclk_freq = EXYNOS4X12_CLKSEL_19200K; > + break; > + case 20 * MHZ: > + refclk_freq = EXYNOS4X12_CLKSEL_20M; > + break; > + case 24 * MHZ: > + default: > + /* default reference clock */ > + refclk_freq = EXYNOS4X12_CLKSEL_24M; > + break; > + } > + } else { > + switch (clk_get_rate(ref_clk)) { > + case 96 * 100000: > + refclk_freq = EXYNOS5_CLKSEL_9600K; > + break; > + case 10 * MHZ: > + refclk_freq = EXYNOS5_CLKSEL_10M; > + break; > + case 12 * MHZ: > + refclk_freq = EXYNOS5_CLKSEL_12M; > + break; > + case 192 * 100000: > + refclk_freq = EXYNOS5_CLKSEL_19200K; > + break; > + case 20 * MHZ: > + refclk_freq = EXYNOS5_CLKSEL_20M; > + break; > + case 50 * MHZ: > + refclk_freq = EXYNOS5_CLKSEL_50M; > + break; > + case 24 * MHZ: > + default: > + /* default reference clock */ > + refclk_freq = EXYNOS5_CLKSEL_24M; > + break; > + } > + } > + clk_put(ref_clk); > + > + return refclk_freq; > +} > + > +static void exynos_usb_phy_control(enum usb_phy_type phy_type , int on) > +{ > + if (soc_is_exynos4210()) { > + if (phy_type & USB_PHY0) > + writel(on, S5P_USBDEVICE_PHY_CONTROL); > + if (phy_type & USB_PHY1) > + writel(on, S5P_USBHOST_PHY_CONTROL); > + } else if (soc_is_exynos4212() | soc_is_exynos4412()) { > + if (phy_type & USB_PHY) > + writel(on, S5P_USB_PHY_CONTROL); > +#ifdef CONFIG_USB_S5P_HSIC0 > + if (phy_type & USB_PHY_HSIC0) > + writel(on, S5P_HSIC_1_PHY_CONTROL); > +#endif > +#ifdef CONFIG_USB_S5P_HSIC1 > + if (phy_type & USB_PHY_HSIC1) > + writel(on, S5P_HSIC_2_PHY_CONTROL); > +#endif > + } else { > + if (phy_type & USB_PHY0) > + writel(on, EXYNOS5_USBDEV_PHY_CONTROL); > + if (phy_type & USB_PHY1) > + writel(on, EXYNOS5_USBHOST_PHY_CONTROL); > + } > +} > + > +static int exynos4_usb_phy0_init(struct platform_device *pdev) > +{ > + u32 phypwr; > + u32 phyclk; > u32 rstcon; > > - writel(readl(S5P_USBDEVICE_PHY_CONTROL) | S5P_USBDEVICE_PHY_ENABLE, > - S5P_USBDEVICE_PHY_CONTROL); > + exynos_usb_phy_control(USB_PHY0, PHY_ENABLE); > > - exynos4210_usb_phy_clkset(pdev); > + /* set clock frequency for PLL */ > + phyclk = exynos_usb_phy_set_clock(pdev); > + phyclk &= ~(PHY0_COMMON_ON_N); > + writel(phyclk, EXYNOS4_PHYCLK); > > - /* set to normal PHY0 */ > - writel((readl(EXYNOS4_PHYPWR) & ~PHY0_NORMAL_MASK), EXYNOS4_PHYPWR); > + /* set to normal of PHY0 */ > + phypwr = readl(EXYNOS4_PHYPWR) & ~PHY0_NORMAL_MASK; > + writel(phypwr, EXYNOS4_PHYPWR); > > - /* reset PHY0 and Link */ > + /* reset all ports of both PHY and Link */ > rstcon = readl(EXYNOS4_RSTCON) | PHY0_SWRST_MASK; > writel(rstcon, EXYNOS4_RSTCON); > udelay(10); > - > rstcon &= ~PHY0_SWRST_MASK; > writel(rstcon, EXYNOS4_RSTCON); > > return 0; > } > > -static int exynos4210_usb_phy0_exit(struct platform_device *pdev) > +static int exynos4_usb_phy0_exit(struct platform_device *pdev) > { > - writel((readl(EXYNOS4_PHYPWR) | PHY0_ANALOG_POWERDOWN | > - PHY0_OTG_DISABLE), EXYNOS4_PHYPWR); > + /* unset to normal of PHY0 */ > + writel((readl(EXYNOS4_PHYPWR) | PHY0_NORMAL_MASK), > + EXYNOS4_PHYPWR); > > - writel(readl(S5P_USBDEVICE_PHY_CONTROL) & ~S5P_USBDEVICE_PHY_ENABLE, > - S5P_USBDEVICE_PHY_CONTROL); > + exynos_usb_phy_control(USB_PHY0, PHY_DISABLE); > > return 0; > } > > -static int exynos4210_usb_phy1_init(struct platform_device *pdev) > +static int exynos4_usb_phy1_init(struct platform_device *pdev) > { > - struct clk *otg_clk; > + u32 phypwr; > + u32 phyclk; > u32 rstcon; > - 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); > + if (exynos4_usb_host_phy_is_on()) { > + dev_err(&pdev->dev, "Already power on PHY\n"); > + return 0; > } > > - err = clk_enable(otg_clk); > - if (err) { > - clk_put(otg_clk); > - return err; > - } > + /* > + * set XuhostOVERCUR to in-active by controlling ET6PUD[15:14] > + * 0x0 : pull-up/down disabled > + * 0x1 : pull-down enabled > + * 0x2 : reserved > + * 0x3 : pull-up enabled > + */ > + writel((__raw_readl(ETC6PUD) & ~(0x3 << 14)) | (0x3 << 14), > + ETC6PUD); > > - if (exynos4_usb_host_phy_is_on()) > - return 0; > + exynos_usb_phy_control(USB_PHY1, PHY_ENABLE); > > - writel(readl(S5P_USBHOST_PHY_CONTROL) | S5P_USBHOST_PHY_ENABLE, > - S5P_USBHOST_PHY_CONTROL); > + /* set clock frequency for PLL */ > + phyclk = exynos_usb_phy_set_clock(pdev); > + phyclk &= ~(PHY1_COMMON_ON_N); > + writel(phyclk, EXYNOS4_PHYCLK); > > - exynos4210_usb_phy_clkset(pdev); > + /* set to normal HSIC 0 and 1 of PHY1 */ > + phypwr = readl(EXYNOS4_PHYPWR); > + phypwr &= ~(PHY1_STD_NORMAL_MASK > + | EXYNOS4210_HSIC0_NORMAL_MASK); > + writel(phypwr, EXYNOS4_PHYPWR); > > /* 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; > + rstcon = readl(EXYNOS4_RSTCON) > + | EXYNOS4210_HOST_LINK_PORT_SWRST_MASK > + | EXYNOS4210_PHY1_SWRST_MASK; > writel(rstcon, EXYNOS4_RSTCON); > udelay(10); > > - rstcon &= ~(HOST_LINK_PORT_SWRST_MASK | PHY1_SWRST_MASK); > + rstcon &= ~(EXYNOS4210_HOST_LINK_PORT_SWRST_MASK > + | EXYNOS4210_PHY1_SWRST_MASK); > writel(rstcon, EXYNOS4_RSTCON); > udelay(80); > > - clk_disable(otg_clk); > - clk_put(otg_clk); > + return 0; > +} > + > +static int exynos4_usb_phy1_exit(struct platform_device *pdev) > +{ > + u32 phypwr; > + > + if (atomic_dec_return(&host_usage) > 0) { > + dev_info(&pdev->dev, "still being used\n"); > + return -EBUSY; > + } > + > + phypwr = readl(EXYNOS4_PHYPWR) > + | PHY1_STD_NORMAL_MASK > + | EXYNOS4210_HSIC0_NORMAL_MASK; > + writel(phypwr, EXYNOS4_PHYPWR); > + > + exynos_usb_phy_control(USB_PHY1, PHY_DISABLE); > > return 0; > } > > -static int exynos4210_usb_phy1_exit(struct platform_device *pdev) > +static int exynos4_usb_phy20_init(struct platform_device *pdev) > { > - struct clk *otg_clk; > - int err; > + u32 phypwr, phyclk, rstcon; > > - if (atomic_dec_return(&host_usage) > 0) > - return 0; > + 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); > + if (exynos4_usb_phy20_is_on()) { > + dev_err(&pdev->dev, "Already power on PHY\n"); > + return 0; > } > > - err = clk_enable(otg_clk); > - if (err) { > - clk_put(otg_clk); > - return err; > + /* > + * set XuhostOVERCUR to in-active by controlling ET6PUD[15:14] > + * 0x0 : pull-up/down disabled > + * 0x1 : pull-down enabled > + * 0x2 : reserved > + * 0x3 : pull-up enabled > + */ > + writel((__raw_readl(ETC6PUD) & ~(0x3 << 14)) | (0x3 << 14), > + ETC6PUD); > + > + exynos_usb_phy_control(USB_PHY > + | USB_PHY_HSIC0, > + PHY_ENABLE); > + > + /* set clock frequency for PLL */ > + phyclk = exynos_usb_phy_set_clock(pdev); > + /* COMMON Block configuration during suspend */ > + phyclk &= ~(PHY0_COMMON_ON_N | PHY1_COMMON_ON_N); > + writel(phyclk, EXYNOS4_PHYCLK); > + > + /* 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 > + | EXYNOS4X12_HSIC0_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) > + | EXYNOS4X12_HOST_LINK_PORT_SWRST_MASK > + | EXYNOS4X12_PHY1_SWRST_MASK; > + writel(rstcon, EXYNOS4_RSTCON); > + udelay(10); > + > + rstcon &= ~(EXYNOS4X12_HOST_LINK_PORT_SWRST_MASK > + | EXYNOS4X12_PHY1_SWRST_MASK); > + writel(rstcon, EXYNOS4_RSTCON); > + udelay(80); > + > + return 0; > +} > + > +static int exynos4_usb_phy20_exit(struct platform_device *pdev) > +{ > + u32 phypwr; > + > + if (atomic_dec_return(&host_usage) > 0) { > + dev_info(&pdev->dev, "still being used\n"); > + return -EBUSY; > } > > - writel((readl(EXYNOS4_PHYPWR) | PHY1_STD_ANALOG_POWERDOWN), > + /* unset to normal of Device */ > + writel((readl(EXYNOS4_PHYPWR) | PHY0_NORMAL_MASK), > EXYNOS4_PHYPWR); > > - writel(readl(S5P_USBHOST_PHY_CONTROL) & ~S5P_USBHOST_PHY_ENABLE, > - S5P_USBHOST_PHY_CONTROL); > + /* unset to normal of Host */ > + phypwr = readl(EXYNOS4_PHYPWR) > + | PHY1_STD_NORMAL_MASK > + | EXYNOS4X12_HSIC0_NORMAL_MASK; > + writel(phypwr, EXYNOS4_PHYPWR); > > - clk_disable(otg_clk); > - clk_put(otg_clk); > + exynos_usb_phy_control(USB_PHY > + | USB_PHY_HSIC0, > + PHY_DISABLE); > + > + return 0; > +} > + > +static int exynos_usb_dev_phy20_init(struct platform_device *pdev) > +{ > + if (soc_is_exynos4212() || soc_is_exynos4412()) > + exynos4_usb_phy20_init(pdev); > + > + writel(0, EXYNOS4_USB_CFG); > + > + return 0; > +} > + > +static int exynos_usb_dev_phy20_exit(struct platform_device *pdev) > +{ > + if (soc_is_exynos4212() || soc_is_exynos4412()) > + exynos4_usb_phy20_exit(pdev); > > 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); > + int ret = -EINVAL; > + > + if (exynos_usb_phy_clock_enable(pdev)) > + return ret; > + > + mutex_lock(&phy_lock); > + if (type == S5P_USB_PHY_HOST) { > + if (soc_is_exynos4210()) > + ret = exynos4_usb_phy1_init(pdev); > + else if (soc_is_exynos4212() || soc_is_exynos4412()) > + ret = exynos4_usb_phy20_init(pdev); > + } else if (type == S5P_USB_PHY_DEVICE) { > + if (soc_is_exynos4210()) > + ret = exynos4_usb_phy0_init(pdev); > + else > + ret = exynos_usb_dev_phy20_init(pdev); > + } > + > + mutex_unlock(&phy_lock); > + exynos_usb_phy_clock_disable(pdev); > > - return -EINVAL; > + return ret; > } > > int s5p_usb_phy_exit(struct platform_device *pdev, int type) > { > - if (type == S5P_USB_PHY_DEVICE) > - return exynos4210_usb_phy0_exit(pdev); > - else if (type == S5P_USB_PHY_HOST) > - return exynos4210_usb_phy1_exit(pdev); > + int ret = -EINVAL; > + > + if (exynos_usb_phy_clock_enable(pdev)) > + return ret; > + > + mutex_lock(&phy_lock); > + > + if (type == S5P_USB_PHY_HOST) { > + if (soc_is_exynos4210()) > + ret = exynos4_usb_phy1_exit(pdev); > + else if (soc_is_exynos4212() || soc_is_exynos4412()) > + ret = exynos4_usb_phy20_exit(pdev); > + } else if (type == S5P_USB_PHY_DEVICE) { > + if (soc_is_exynos4210()) > + ret = exynos4_usb_phy0_exit(pdev); > + else > + ret = exynos_usb_dev_phy20_exit(pdev); > + } > + > + mutex_unlock(&phy_lock); > + exynos_usb_phy_clock_disable(pdev); > > - return -EINVAL; > + return ret; > } > diff --git a/drivers/usb/host/Kconfig b/drivers/usb/host/Kconfig > index 075d2ec..5f69041 100644 > --- a/drivers/usb/host/Kconfig > +++ b/drivers/usb/host/Kconfig > @@ -199,6 +199,20 @@ config USB_EHCI_S5P > help > Enable support for the S5P SOC's on-chip EHCI controller. > > +config USB_S5P_HSIC0 > + boolean "S5P HSIC0 support" > + depends on USB_EHCI_HCD && PLAT_S5P && USB_EHCI_S5P > + default n > + help > + Enable support for the S5P SOC's on-chip HSIC PHY. > + > +config USB_S5P_HSIC1 > + boolean "S5P HSIC1 support" > + depends on USB_EHCI_HCD && PLAT_S5P && USB_EHCI_S5P > + default n > + help > + Enable support for the S5P SOC's on-chip HSIC PHY. > + > config USB_EHCI_MV > bool "EHCI support for Marvell on-chip controller" > depends on USB_EHCI_HCD && (ARCH_PXA || ARCH_MMP) > -- > 1.7.9.5 > > > _______________________________________________ > linux-arm-kernel mailing list > linux-arm-kernel@lists.infradead.org > http://lists.infradead.org/mailman/listinfo/linux-arm-kernel >
diff --git a/arch/arm/mach-exynos/common.c b/arch/arm/mach-exynos/common.c index 4eb39cd..94d58af 100644 --- a/arch/arm/mach-exynos/common.c +++ b/arch/arm/mach-exynos/common.c @@ -179,6 +179,11 @@ static struct map_desc exynos4_iodesc[] __initdata = { .length = SZ_4K, .type = MT_DEVICE, }, { + .virtual = (unsigned long)S5P_VA_GPIO2, + .pfn = __phys_to_pfn(EXYNOS4_PA_GPIO2), + .length = SZ_4K, + .type = MT_DEVICE, + }, { .virtual = (unsigned long)S5P_VA_DMC0, .pfn = __phys_to_pfn(EXYNOS4_PA_DMC0), .length = SZ_64K, diff --git a/arch/arm/mach-exynos/include/mach/regs-pmu.h b/arch/arm/mach-exynos/include/mach/regs-pmu.h index 0bb21e2..d98c2fe 100644 --- a/arch/arm/mach-exynos/include/mach/regs-pmu.h +++ b/arch/arm/mach-exynos/include/mach/regs-pmu.h @@ -185,6 +185,15 @@ #define S5P_PMU_LCD1_CONF S5P_PMUREG(0x3CA0) /* Only for EXYNOS4x12 */ +#define S5P_USB_PHY_CONTROL S5P_PMUREG(0x0704) +#define S5P_USB_PHY_ENABLE (0x1 << 0) + +#define S5P_HSIC_1_PHY_CONTROL S5P_PMUREG(0x0708) +#define S5P_HSIC_1_PHY_ENABLE (0x1 << 0) + +#define S5P_HSIC_2_PHY_CONTROL S5P_PMUREG(0x070C) +#define S5P_HSIC_2_PHY_ENABLE (0x1 << 0) + #define S5P_ISP_ARM_LOWPWR S5P_PMUREG(0x1050) #define S5P_DIS_IRQ_ISP_ARM_LOCAL_LOWPWR S5P_PMUREG(0x1054) #define S5P_DIS_IRQ_ISP_ARM_CENTRAL_LOWPWR S5P_PMUREG(0x1058) @@ -242,6 +251,9 @@ #define EXYNOS5_SYS_WDTRESET (1 << 20) +#define EXYNOS5_USBDEV_PHY_CONTROL S5P_PMUREG(0x0704) +#define EXYNOS5_USBHOST_PHY_CONTROL S5P_PMUREG(0x0708) + #define EXYNOS5_ARM_CORE0_SYS_PWR_REG S5P_PMUREG(0x1000) #define EXYNOS5_DIS_IRQ_ARM_CORE0_LOCAL_SYS_PWR_REG S5P_PMUREG(0x1004) #define EXYNOS5_DIS_IRQ_ARM_CORE0_CENTRAL_SYS_PWR_REG S5P_PMUREG(0x1008) 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 0727773..79021a0 100644 --- a/arch/arm/mach-exynos/include/mach/regs-usb-phy.h +++ b/arch/arm/mach-exynos/include/mach/regs-usb-phy.h @@ -43,6 +43,43 @@ #define EXYNOS4210_CLKSEL_12M (0x2 << 0) #define EXYNOS4210_CLKSEL_24M (0x3 << 0) +#define EXYNOS4210_HSIC1_NORMAL_MASK (0x3 << 11) +#define EXYNOS4210_HSIC1_SLEEP (1 << 12) +#define EXYNOS4210_HSIC1_FORCE_SUSPEND (1 << 11) +#define EXYNOS4210_HSIC0_NORMAL_MASK (0x3 << 9) +#define EXYNOS4210_HSIC0_SLEEP (1 << 10) +#define EXYNOS4210_HSIC0_FORCE_SUSPEND (1 << 9) + +#define EXYNOS4210_HOST_LINK_PORT_SWRST_MASK (0xf << 6) +#define EXYNOS4210_HOST_LINK_PORT2_SWRST (1 << 9) +#define EXYNOS4210_HOST_LINK_PORT1_SWRST (1 << 8) +#define EXYNOS4210_HOST_LINK_PORT0_SWRST (1 << 7) +#define EXYNOS4210_HOST_LINK_ALL_SWRST (1 << 6) +#define EXYNOS4210_PHY1_SWRST_MASK (0x7 << 3) +#define EXYNOS4210_PHY1_HSIC_SWRST (1 << 5) +#define EXYNOS4210_PHY1_STD_SWRST (1 << 4) +#define EXYNOS4210_PHY1_ALL_SWRST (1 << 3) + +#define EXYNOS4X12_HSIC1_NORMAL_MASK (0x7 << 12) +#define EXYNOS4X12_HSIC1_SLEEP (1 << 14) +#define EXYNOS4X12_HSIC1_ANALOG_POWERDOWN (1 << 13) +#define EXYNOS4X12_HSIC1_FORCE_SUSPEND (1 << 12) +#define EXYNOS4X12_HSIC0_NORMAL_MASK (0x7 << 9) +#define EXYNOS4X12_HSIC0_SLEEP (1 << 11) +#define EXYNOS4X12_HSIC0_ANALOG_POWERDOWN (1 << 10) +#define EXYNOS4X12_HSIC0_FORCE_SUSPEND (1 << 9) + +#define EXYNOS4X12_HOST_LINK_PORT_SWRST_MASK (0xf << 7) +#define EXYNOS4X12_HOST_LINK_PORT2_SWRST (1 << 10) +#define EXYNOS4X12_HOST_LINK_PORT1_SWRST (1 << 9) +#define EXYNOS4X12_HOST_LINK_PORT0_SWRST (1 << 8) +#define EXYNOS4X12_HOST_LINK_ALL_SWRST (1 << 7) +#define EXYNOS4X12_PHY1_SWRST_MASK (0xf << 3) +#define EXYNOS4X12_PHY1_HSIC1_SWRST (1 << 6) +#define EXYNOS4X12_PHY1_HSIC0_SWRST (1 << 5) +#define EXYNOS4X12_PHY1_SWRST (1 << 4) +#define EXYNOS4X12_HOST_PHY_SWRST (1 << 3) + #define EXYNOS4X12_CLKSEL_MASK (0x7 << 0) #define EXYNOS4X12_CLKSEL_9600K (0x0 << 0) #define EXYNOS4X12_CLKSEL_10M (0x1 << 0) @@ -71,4 +108,64 @@ #define EXYNOS4_PHY1CON EXYNOS4_HSOTG_PHYREG(0x34) #define FPENABLEN (1 << 0) +/* For Exynos5 */ +#define EXYNOS5_PHY_HOST_CTRL0 EXYNOS4_HSOTG_PHYREG(0x00) +#define HOST_CTRL0_PHYSWRSTALL (0x1 << 31) +#define HOST_CTRL0_REFCLKSEL(val) (val << 19) +#define EXYNOS5_CLKSEL_50M (0x7) +#define EXYNOS5_CLKSEL_24M (0x5) +#define EXYNOS5_CLKSEL_20M (0x4) +#define EXYNOS5_CLKSEL_19200K (0x3) +#define EXYNOS5_CLKSEL_12M (0x2) +#define EXYNOS5_CLKSEL_10M (0x1) +#define EXYNOS5_CLKSEL_9600K (0x0) +#define HOST_CTRL0_CLKSEL_SHIFT (16) +#define HOST_CTRL0_FSEL_MASK (0x7 << 16) + +#define HOST_CTRL0_COMMONON_N (0x1 << 9) +#define HOST_CTRL0_SIDDQ (0x1 << 6) +#define HOST_CTRL0_FORCESLEEP (0x1 << 5) +#define HOST_CTRL0_FORCESUSPEND (0x1 << 4) +#define HOST_CTRL0_WORDINTERFACE (0x1 << 3) +#define HOST_CTRL0_UTMISWRST (0x1 << 2) +#define HOST_CTRL0_LINKSWRST (0x1 << 1) +#define HOST_CTRL0_PHYSWRST (0x1 << 0) + +#define EXYNOS5_PHY_HOST_TUNE0 EXYNOS4_HSOTG_PHYREG(0x04) +#define EXYNOS5_PHY_HOST_TEST0 EXYNOS4_HSOTG_PHYREG(0x08) + +#define EXYNOS5_PHY_HSIC_CTRL1 EXYNOS4_HSOTG_PHYREG(0x10) +#define EXYNOS5_PHY_HSIC_CTRL2 EXYNOS4_HSOTG_PHYREG(0x20) +#define HSIC_CTRL_REFCLKSEL(val) ((val&0x3) << 23) +#define HSIC_CTRL_REFCLKDIV(val) ((val&0x7f) << 16) +#define HSIC_CTRL_SIDDQ (0x1 << 6) +#define HSIC_CTRL_FORCESLEEP (0x1 << 5) +#define HSIC_CTRL_FORCESUSPEND (0x1 << 4) +#define HSIC_CTRL_WORDINTERFACE (0x1 << 3) +#define HSIC_CTRL_UTMISWRST (0x1 << 2) +#define HSIC_CTRL_PHYSWRST (0x1 << 0) + +#define EXYNOS5_PHY_HOST_EHCICTRL EXYNOS4_HSOTG_PHYREG(0x30) +#define EHCICTRL_ENAINCRXALIGN (0x1 << 29) +#define EHCICTRL_ENAINCR4 (0x1 << 28) +#define EHCICTRL_ENAINCR8 (0x1 << 27) +#define EHCICTRL_ENAINCR16 (0x1 << 26) + +#define EXYNOS5_PHY_HOST_OHCICTRL EXYNOS4_HSOTG_PHYREG(0x34) + +#define EXYNOS5_PHY_OTG_SYS EXYNOS4_HSOTG_PHYREG(0x38) +#define OTG_SYS_PHYLINK_SW_RESET (0x1 << 14) +#define OTG_SYS_LINK_SW_RST_UOTG (0x1 << 13) +#define OTG_SYS_PHY0_SW_RST (0x1 << 12) +#define OTG_SYS_REF_CLK_SEL(val) ((val&0x3) << 9) +#define OTG_SYS_REF_CLK_SEL_MASK (0x3 << 9) +#define OTG_SYS_IP_PULLUP_UOTG (0x1 << 8) +#define OTG_SYS_COMMON_ON (0x1 << 7) +#define OTG_SYS_CLKSEL_SHIFT (4) +#define OTG_SYS_CTRL0_FSEL_MASK (0x7 << 4) +#define OTG_SYS_FORCE_SLEEP (0x1 << 3) +#define OTG_SYS_OTGDISABLE (0x1 << 2) +#define OTG_SYS_SIDDQ_UOTG (0x1 << 1) +#define OTG_SYS_FORCE_SUSPEND (0x1 << 0) + #endif /* __PLAT_S5P_REGS_USB_PHY_H */ diff --git a/arch/arm/mach-exynos/setup-usb-phy.c b/arch/arm/mach-exynos/setup-usb-phy.c index b81cc56..c725745 100644 --- a/arch/arm/mach-exynos/setup-usb-phy.c +++ b/arch/arm/mach-exynos/setup-usb-phy.c @@ -1,5 +1,6 @@ /* * Copyright (C) 2011 Samsung Electronics Co.Ltd + * Author: Yulgon Kim <yulgon.kim@samsung.com> * Author: Joonyoung Shim <jy0922.shim@samsung.com> * * This program is free software; you can redistribute it and/or modify it @@ -19,205 +20,457 @@ #include <plat/cpu.h> #include <plat/usb-phy.h> +#define ETC6PUD (S5P_VA_GPIO2 + 0x228) +#define EXYNOS4_USB_CFG (S3C_VA_SYS + 0x21C) + +#define PHY_ENABLE (1 << 0) +#define PHY_DISABLE (0) + +enum usb_host_type { + HOST_PHY_EHCI = (0x1 << 0), + HOST_PHY_OHCI = (0x1 << 1), +}; + +enum usb_phy_type { + USB_PHY = (0x1 << 0), + USB_PHY0 = (0x1 << 0), + USB_PHY1 = (0x1 << 1), + USB_PHY_HSIC0 = (0x1 << 1), + USB_PHY_HSIC1 = (0x1 << 2), +}; + static atomic_t host_usage; +static DEFINE_MUTEX(phy_lock); +static struct clk *phy_clk; static int exynos4_usb_host_phy_is_on(void) { return (readl(EXYNOS4_PHYPWR) & PHY1_STD_ANALOG_POWERDOWN) ? 0 : 1; } -static void exynos4210_usb_phy_clkset(struct platform_device *pdev) +static int exynos4_usb_phy20_is_on(void) { - struct clk *xusbxti_clk; - u32 phyclk; + return exynos4_usb_host_phy_is_on(); +} + +static int exynos_usb_phy_clock_enable(struct platform_device *pdev) +{ + int err; + + if (!phy_clk) { + if (soc_is_exynos4210() || + soc_is_exynos4212() || soc_is_exynos4412()) + phy_clk = clk_get(&pdev->dev, "otg"); + else + phy_clk = clk_get(&pdev->dev, "usbhost"); + + if (IS_ERR(phy_clk)) { + dev_err(&pdev->dev, "Failed to get phy clock\n"); + return PTR_ERR(phy_clk); + } + } + + err = clk_enable(phy_clk); + + return err; +} - xusbxti_clk = clk_get(&pdev->dev, "xusbxti"); - if (xusbxti_clk && !IS_ERR(xusbxti_clk)) { - if (soc_is_exynos4210()) { - /* set clock frequency for PLL */ - phyclk = readl(EXYNOS4_PHYCLK) & ~EXYNOS4210_CLKSEL_MASK; - - switch (clk_get_rate(xusbxti_clk)) { - case 12 * MHZ: - phyclk |= EXYNOS4210_CLKSEL_12M; - break; - case 48 * MHZ: - phyclk |= EXYNOS4210_CLKSEL_48M; - break; - default: - case 24 * MHZ: - phyclk |= EXYNOS4210_CLKSEL_24M; - break; - } - writel(phyclk, EXYNOS4_PHYCLK); - } else if (soc_is_exynos4212() || soc_is_exynos4412()) { - /* set clock frequency for PLL */ - phyclk = readl(EXYNOS4_PHYCLK) & ~EXYNOS4X12_CLKSEL_MASK; - - switch (clk_get_rate(xusbxti_clk)) { - case 9600 * KHZ: - phyclk |= EXYNOS4X12_CLKSEL_9600K; - break; - case 10 * MHZ: - phyclk |= EXYNOS4X12_CLKSEL_10M; - break; - case 12 * MHZ: - phyclk |= EXYNOS4X12_CLKSEL_12M; - break; - case 19200 * KHZ: - phyclk |= EXYNOS4X12_CLKSEL_19200K; - break; - case 20 * MHZ: - phyclk |= EXYNOS4X12_CLKSEL_20M; - break; - default: - case 24 * MHZ: - /* default reference clock */ - phyclk |= EXYNOS4X12_CLKSEL_24M; - break; - } - writel(phyclk, EXYNOS4_PHYCLK); +static int exynos_usb_phy_clock_disable(struct platform_device *pdev) +{ + if (!phy_clk) { + if (soc_is_exynos4210() || + soc_is_exynos4212() || soc_is_exynos4412()) + phy_clk = clk_get(&pdev->dev, "otg"); + else + phy_clk = clk_get(&pdev->dev, "usbhost"); + if (IS_ERR(phy_clk)) { + dev_err(&pdev->dev, "Failed to get phy clock\n"); + return PTR_ERR(phy_clk); } - clk_put(xusbxti_clk); } + + clk_disable(phy_clk); + + return 0; } -static int exynos4210_usb_phy0_init(struct platform_device *pdev) +static u32 exynos_usb_phy_set_clock(struct platform_device *pdev) { + struct clk *ref_clk; + u32 refclk_freq = 0; + + if (soc_is_exynos4210() || soc_is_exynos4212() || soc_is_exynos4412()) + ref_clk = clk_get(&pdev->dev, "xusbxti"); + else + ref_clk = clk_get(&pdev->dev, "ext_xtal"); + + if (IS_ERR(ref_clk)) { + dev_err(&pdev->dev, "Failed to get reference clock\n"); + return PTR_ERR(ref_clk); + } + + if (soc_is_exynos4210()) { + switch (clk_get_rate(ref_clk)) { + case 12 * MHZ: + refclk_freq = EXYNOS4210_CLKSEL_12M; + break; + case 48 * MHZ: + refclk_freq = EXYNOS4210_CLKSEL_48M; + break; + case 24 * MHZ: + default: + /* default reference clock */ + refclk_freq = EXYNOS4210_CLKSEL_24M; + break; + } + } else if (soc_is_exynos4212() | soc_is_exynos4412()) { + switch (clk_get_rate(ref_clk)) { + case 96 * 100000: + refclk_freq = EXYNOS4X12_CLKSEL_9600K; + break; + case 10 * MHZ: + refclk_freq = EXYNOS4X12_CLKSEL_10M; + break; + case 12 * MHZ: + refclk_freq = EXYNOS4X12_CLKSEL_12M; + break; + case 192 * 100000: + refclk_freq = EXYNOS4X12_CLKSEL_19200K; + break; + case 20 * MHZ: + refclk_freq = EXYNOS4X12_CLKSEL_20M; + break; + case 24 * MHZ: + default: + /* default reference clock */ + refclk_freq = EXYNOS4X12_CLKSEL_24M; + break; + } + } else { + switch (clk_get_rate(ref_clk)) { + case 96 * 100000: + refclk_freq = EXYNOS5_CLKSEL_9600K; + break; + case 10 * MHZ: + refclk_freq = EXYNOS5_CLKSEL_10M; + break; + case 12 * MHZ: + refclk_freq = EXYNOS5_CLKSEL_12M; + break; + case 192 * 100000: + refclk_freq = EXYNOS5_CLKSEL_19200K; + break; + case 20 * MHZ: + refclk_freq = EXYNOS5_CLKSEL_20M; + break; + case 50 * MHZ: + refclk_freq = EXYNOS5_CLKSEL_50M; + break; + case 24 * MHZ: + default: + /* default reference clock */ + refclk_freq = EXYNOS5_CLKSEL_24M; + break; + } + } + clk_put(ref_clk); + + return refclk_freq; +} + +static void exynos_usb_phy_control(enum usb_phy_type phy_type , int on) +{ + if (soc_is_exynos4210()) { + if (phy_type & USB_PHY0) + writel(on, S5P_USBDEVICE_PHY_CONTROL); + if (phy_type & USB_PHY1) + writel(on, S5P_USBHOST_PHY_CONTROL); + } else if (soc_is_exynos4212() | soc_is_exynos4412()) { + if (phy_type & USB_PHY) + writel(on, S5P_USB_PHY_CONTROL); +#ifdef CONFIG_USB_S5P_HSIC0 + if (phy_type & USB_PHY_HSIC0) + writel(on, S5P_HSIC_1_PHY_CONTROL); +#endif +#ifdef CONFIG_USB_S5P_HSIC1 + if (phy_type & USB_PHY_HSIC1) + writel(on, S5P_HSIC_2_PHY_CONTROL); +#endif + } else { + if (phy_type & USB_PHY0) + writel(on, EXYNOS5_USBDEV_PHY_CONTROL); + if (phy_type & USB_PHY1) + writel(on, EXYNOS5_USBHOST_PHY_CONTROL); + } +} + +static int exynos4_usb_phy0_init(struct platform_device *pdev) +{ + u32 phypwr; + u32 phyclk; u32 rstcon; - writel(readl(S5P_USBDEVICE_PHY_CONTROL) | S5P_USBDEVICE_PHY_ENABLE, - S5P_USBDEVICE_PHY_CONTROL); + exynos_usb_phy_control(USB_PHY0, PHY_ENABLE); - exynos4210_usb_phy_clkset(pdev); + /* set clock frequency for PLL */ + phyclk = exynos_usb_phy_set_clock(pdev); + phyclk &= ~(PHY0_COMMON_ON_N); + writel(phyclk, EXYNOS4_PHYCLK); - /* set to normal PHY0 */ - writel((readl(EXYNOS4_PHYPWR) & ~PHY0_NORMAL_MASK), EXYNOS4_PHYPWR); + /* set to normal of PHY0 */ + phypwr = readl(EXYNOS4_PHYPWR) & ~PHY0_NORMAL_MASK; + writel(phypwr, EXYNOS4_PHYPWR); - /* reset PHY0 and Link */ + /* reset all ports of both PHY and Link */ rstcon = readl(EXYNOS4_RSTCON) | PHY0_SWRST_MASK; writel(rstcon, EXYNOS4_RSTCON); udelay(10); - rstcon &= ~PHY0_SWRST_MASK; writel(rstcon, EXYNOS4_RSTCON); return 0; } -static int exynos4210_usb_phy0_exit(struct platform_device *pdev) +static int exynos4_usb_phy0_exit(struct platform_device *pdev) { - writel((readl(EXYNOS4_PHYPWR) | PHY0_ANALOG_POWERDOWN | - PHY0_OTG_DISABLE), EXYNOS4_PHYPWR); + /* unset to normal of PHY0 */ + writel((readl(EXYNOS4_PHYPWR) | PHY0_NORMAL_MASK), + EXYNOS4_PHYPWR); - writel(readl(S5P_USBDEVICE_PHY_CONTROL) & ~S5P_USBDEVICE_PHY_ENABLE, - S5P_USBDEVICE_PHY_CONTROL); + exynos_usb_phy_control(USB_PHY0, PHY_DISABLE); return 0; } -static int exynos4210_usb_phy1_init(struct platform_device *pdev) +static int exynos4_usb_phy1_init(struct platform_device *pdev) { - struct clk *otg_clk; + u32 phypwr; + u32 phyclk; u32 rstcon; - 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); + if (exynos4_usb_host_phy_is_on()) { + dev_err(&pdev->dev, "Already power on PHY\n"); + return 0; } - err = clk_enable(otg_clk); - if (err) { - clk_put(otg_clk); - return err; - } + /* + * set XuhostOVERCUR to in-active by controlling ET6PUD[15:14] + * 0x0 : pull-up/down disabled + * 0x1 : pull-down enabled + * 0x2 : reserved + * 0x3 : pull-up enabled + */ + writel((__raw_readl(ETC6PUD) & ~(0x3 << 14)) | (0x3 << 14), + ETC6PUD); - if (exynos4_usb_host_phy_is_on()) - return 0; + exynos_usb_phy_control(USB_PHY1, PHY_ENABLE); - writel(readl(S5P_USBHOST_PHY_CONTROL) | S5P_USBHOST_PHY_ENABLE, - S5P_USBHOST_PHY_CONTROL); + /* set clock frequency for PLL */ + phyclk = exynos_usb_phy_set_clock(pdev); + phyclk &= ~(PHY1_COMMON_ON_N); + writel(phyclk, EXYNOS4_PHYCLK); - exynos4210_usb_phy_clkset(pdev); + /* set to normal HSIC 0 and 1 of PHY1 */ + phypwr = readl(EXYNOS4_PHYPWR); + phypwr &= ~(PHY1_STD_NORMAL_MASK + | EXYNOS4210_HSIC0_NORMAL_MASK); + writel(phypwr, EXYNOS4_PHYPWR); /* 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; + rstcon = readl(EXYNOS4_RSTCON) + | EXYNOS4210_HOST_LINK_PORT_SWRST_MASK + | EXYNOS4210_PHY1_SWRST_MASK; writel(rstcon, EXYNOS4_RSTCON); udelay(10); - rstcon &= ~(HOST_LINK_PORT_SWRST_MASK | PHY1_SWRST_MASK); + rstcon &= ~(EXYNOS4210_HOST_LINK_PORT_SWRST_MASK + | EXYNOS4210_PHY1_SWRST_MASK); writel(rstcon, EXYNOS4_RSTCON); udelay(80); - clk_disable(otg_clk); - clk_put(otg_clk); + return 0; +} + +static int exynos4_usb_phy1_exit(struct platform_device *pdev) +{ + u32 phypwr; + + if (atomic_dec_return(&host_usage) > 0) { + dev_info(&pdev->dev, "still being used\n"); + return -EBUSY; + } + + phypwr = readl(EXYNOS4_PHYPWR) + | PHY1_STD_NORMAL_MASK + | EXYNOS4210_HSIC0_NORMAL_MASK; + writel(phypwr, EXYNOS4_PHYPWR); + + exynos_usb_phy_control(USB_PHY1, PHY_DISABLE); return 0; } -static int exynos4210_usb_phy1_exit(struct platform_device *pdev) +static int exynos4_usb_phy20_init(struct platform_device *pdev) { - struct clk *otg_clk; - int err; + u32 phypwr, phyclk, rstcon; - if (atomic_dec_return(&host_usage) > 0) - return 0; + 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); + if (exynos4_usb_phy20_is_on()) { + dev_err(&pdev->dev, "Already power on PHY\n"); + return 0; } - err = clk_enable(otg_clk); - if (err) { - clk_put(otg_clk); - return err; + /* + * set XuhostOVERCUR to in-active by controlling ET6PUD[15:14] + * 0x0 : pull-up/down disabled + * 0x1 : pull-down enabled + * 0x2 : reserved + * 0x3 : pull-up enabled + */ + writel((__raw_readl(ETC6PUD) & ~(0x3 << 14)) | (0x3 << 14), + ETC6PUD); + + exynos_usb_phy_control(USB_PHY + | USB_PHY_HSIC0, + PHY_ENABLE); + + /* set clock frequency for PLL */ + phyclk = exynos_usb_phy_set_clock(pdev); + /* COMMON Block configuration during suspend */ + phyclk &= ~(PHY0_COMMON_ON_N | PHY1_COMMON_ON_N); + writel(phyclk, EXYNOS4_PHYCLK); + + /* 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 + | EXYNOS4X12_HSIC0_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) + | EXYNOS4X12_HOST_LINK_PORT_SWRST_MASK + | EXYNOS4X12_PHY1_SWRST_MASK; + writel(rstcon, EXYNOS4_RSTCON); + udelay(10); + + rstcon &= ~(EXYNOS4X12_HOST_LINK_PORT_SWRST_MASK + | EXYNOS4X12_PHY1_SWRST_MASK); + writel(rstcon, EXYNOS4_RSTCON); + udelay(80); + + return 0; +} + +static int exynos4_usb_phy20_exit(struct platform_device *pdev) +{ + u32 phypwr; + + if (atomic_dec_return(&host_usage) > 0) { + dev_info(&pdev->dev, "still being used\n"); + return -EBUSY; } - writel((readl(EXYNOS4_PHYPWR) | PHY1_STD_ANALOG_POWERDOWN), + /* unset to normal of Device */ + writel((readl(EXYNOS4_PHYPWR) | PHY0_NORMAL_MASK), EXYNOS4_PHYPWR); - writel(readl(S5P_USBHOST_PHY_CONTROL) & ~S5P_USBHOST_PHY_ENABLE, - S5P_USBHOST_PHY_CONTROL); + /* unset to normal of Host */ + phypwr = readl(EXYNOS4_PHYPWR) + | PHY1_STD_NORMAL_MASK + | EXYNOS4X12_HSIC0_NORMAL_MASK; + writel(phypwr, EXYNOS4_PHYPWR); - clk_disable(otg_clk); - clk_put(otg_clk); + exynos_usb_phy_control(USB_PHY + | USB_PHY_HSIC0, + PHY_DISABLE); + + return 0; +} + +static int exynos_usb_dev_phy20_init(struct platform_device *pdev) +{ + if (soc_is_exynos4212() || soc_is_exynos4412()) + exynos4_usb_phy20_init(pdev); + + writel(0, EXYNOS4_USB_CFG); + + return 0; +} + +static int exynos_usb_dev_phy20_exit(struct platform_device *pdev) +{ + if (soc_is_exynos4212() || soc_is_exynos4412()) + exynos4_usb_phy20_exit(pdev); 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); + int ret = -EINVAL; + + if (exynos_usb_phy_clock_enable(pdev)) + return ret; + + mutex_lock(&phy_lock); + if (type == S5P_USB_PHY_HOST) { + if (soc_is_exynos4210()) + ret = exynos4_usb_phy1_init(pdev); + else if (soc_is_exynos4212() || soc_is_exynos4412()) + ret = exynos4_usb_phy20_init(pdev); + } else if (type == S5P_USB_PHY_DEVICE) { + if (soc_is_exynos4210()) + ret = exynos4_usb_phy0_init(pdev); + else + ret = exynos_usb_dev_phy20_init(pdev); + } + + mutex_unlock(&phy_lock); + exynos_usb_phy_clock_disable(pdev); - return -EINVAL; + return ret; } int s5p_usb_phy_exit(struct platform_device *pdev, int type) { - if (type == S5P_USB_PHY_DEVICE) - return exynos4210_usb_phy0_exit(pdev); - else if (type == S5P_USB_PHY_HOST) - return exynos4210_usb_phy1_exit(pdev); + int ret = -EINVAL; + + if (exynos_usb_phy_clock_enable(pdev)) + return ret; + + mutex_lock(&phy_lock); + + if (type == S5P_USB_PHY_HOST) { + if (soc_is_exynos4210()) + ret = exynos4_usb_phy1_exit(pdev); + else if (soc_is_exynos4212() || soc_is_exynos4412()) + ret = exynos4_usb_phy20_exit(pdev); + } else if (type == S5P_USB_PHY_DEVICE) { + if (soc_is_exynos4210()) + ret = exynos4_usb_phy0_exit(pdev); + else + ret = exynos_usb_dev_phy20_exit(pdev); + } + + mutex_unlock(&phy_lock); + exynos_usb_phy_clock_disable(pdev); - return -EINVAL; + return ret; } diff --git a/drivers/usb/host/Kconfig b/drivers/usb/host/Kconfig index 075d2ec..5f69041 100644 --- a/drivers/usb/host/Kconfig +++ b/drivers/usb/host/Kconfig @@ -199,6 +199,20 @@ config USB_EHCI_S5P help Enable support for the S5P SOC's on-chip EHCI controller. +config USB_S5P_HSIC0 + boolean "S5P HSIC0 support" + depends on USB_EHCI_HCD && PLAT_S5P && USB_EHCI_S5P + default n + help + Enable support for the S5P SOC's on-chip HSIC PHY. + +config USB_S5P_HSIC1 + boolean "S5P HSIC1 support" + depends on USB_EHCI_HCD && PLAT_S5P && USB_EHCI_S5P + default n + help + Enable support for the S5P SOC's on-chip HSIC PHY. + config USB_EHCI_MV bool "EHCI support for Marvell on-chip controller" depends on USB_EHCI_HCD && (ARCH_PXA || ARCH_MMP)
This patch support to control USB HSIC of EXYNOS4, edited based on Samsung's GT-i9100 ICS Opensource Update7. Change-Id: Ifba33c6a5166abf3644794eee6abe528bd71f521 Signed-off-by: Dongjin Kim <dongjin.kim@agreeyamobility.net> --- arch/arm/mach-exynos/common.c | 5 + arch/arm/mach-exynos/include/mach/regs-pmu.h | 12 + arch/arm/mach-exynos/include/mach/regs-usb-phy.h | 97 +++++ arch/arm/mach-exynos/setup-usb-phy.c | 493 ++++++++++++++++------ drivers/usb/host/Kconfig | 14 + 5 files changed, 501 insertions(+), 120 deletions(-)