#define PHYPWR_FORCE_SUSPEND (0x1 << 1)
/* For Exynos4 */
#define PHYPWR_NORMAL_MASK_PHY0 (0x39 << 0)
+#define PHYPWR_NORMAL_MASK_PHY1 (0x7 << 6)
+#define PHYPWR_NORMAL_MASK_HSIC0_4210 (0x3 << 9)
+#define PHYPWR_NORMAL_MASK_HSIC1_4210 (0x3 << 11)
+#define PHYPWR_NORMAL_MASK_HSIC0_4X12 (0x7 << 9)
+#define PHYPWR_NORMAL_MASK_HSIC1_4X12 (0x7 << 12)
#define PHYPWR_SLEEP_PHY0 (0x1 << 5)
#define SAMSUNG_PHYCLK (0x04)
#define RSTCON_PHYLINK_SWRST (0x1 << 2)
#define RSTCON_HLINK_SWRST (0x1 << 1)
#define RSTCON_SWRST (0x1 << 0)
+/* This following values will also reset some fields marked as "reserved"
+ The question is... was it intentional? */
+#define RSTCON_SWRST_HOST_4X12 (0xff << 3)
+#define RSTCON_SWRST_HOST_4210 (0x7f << 3)
+
+#define EXYNOS4_PHY1CON (0x34)
+#define PHY1CON_FPENABLEN (0x1 << 0)
/* EXYNOS5 */
#define EXYNOS5_PHY_HOST_CTRL0 (0x00)
#define KHZ (1000)
#endif
-#define EXYNOS_USBHOST_PHY_CTRL_OFFSET (0x4)
+#define EXYNOS5_USBHOST_PHY_CTRL_OFFSET (0x4)
+#define EXYNOS4x12_HSIC1_PHY_CTRL_OFFSET (0x4)
+#define EXYNOS4x12_HSIC2_PHY_CTRL_OFFSET (0x8)
#define S3C64XX_USBPHY_ENABLE (0x1 << 16)
#define EXYNOS_USBPHY_ENABLE (0x1 << 0)
#define EXYNOS_USB20PHY_CFG_HOST_LINK (0x1 << 0)
* the last consumer to disable it.
*/
+
atomic_inc(&sphy->phy_usage);
if (exynos5_phyhost_is_on(regs)) {
u32 phypwr;
u32 phyclk;
u32 rstcon;
+ u32 rstbits;
/* set clock frequency for PLL */
phyclk = sphy->ref_clk_freq;
phypwr = readl(regs + SAMSUNG_PHYPWR);
rstcon = readl(regs + SAMSUNG_RSTCON);
+ rstbits = 0;
switch (sphy->drv_data->cpu_type) {
case TYPE_S3C64XX:
phyclk &= ~PHYCLK_COMMON_ON_N;
phypwr &= ~PHYPWR_NORMAL_MASK;
- rstcon |= RSTCON_SWRST;
+ rstbits = RSTCON_SWRST;
break;
case TYPE_EXYNOS4210:
- case TYPE_EXYNOS4X12:
phypwr &= ~PHYPWR_NORMAL_MASK_PHY0;
- rstcon |= RSTCON_SWRST;
+ rstbits = RSTCON_SWRST;
+ break;
+ case TYPE_EXYNOS4X12:
+ if (sphy->phy_type == USB_PHY_TYPE_HOST) {
+ phypwr &= ~PHYPWR_NORMAL_MASK_PHY1;
+ phypwr &= ~PHYPWR_NORMAL_MASK_HSIC0_4X12;
+ phypwr &= ~PHYPWR_NORMAL_MASK_HSIC1_4X12;
+ rstbits = RSTCON_SWRST_HOST_4X12;
+ /* The following register (0x125b0034) is not documented
+ * for Exynos4412, however it is documented for S5PC210.
+ * There is means that is should not be used, but hey,
+ * who knows? */
+ writel(PHY1CON_FPENABLEN, regs + EXYNOS4_PHY1CON);
+ } else {
+ phypwr &= ~PHYPWR_NORMAL_MASK_PHY0;
+ rstbits |= RSTCON_SWRST;
+ }
+ break;
+
default:
break;
}
/* Configure PHY0 for normal operation*/
writel(phypwr, regs + SAMSUNG_PHYPWR);
/* reset all ports of PHY and Link */
+ /* Keep track of which bits are reset with rstbits. */
+ rstcon |= rstbits;
writel(rstcon, regs + SAMSUNG_RSTCON);
udelay(10);
- rstcon &= ~RSTCON_SWRST;
+ rstcon &= ~rstbits;
writel(rstcon, regs + SAMSUNG_RSTCON);
}
phypwr |= PHYPWR_NORMAL_MASK;
break;
case TYPE_EXYNOS4210:
- case TYPE_EXYNOS4X12:
phypwr |= PHYPWR_NORMAL_MASK_PHY0;
+ break;
+ case TYPE_EXYNOS4X12:
+ if (sphy->phy_type == USB_PHY_TYPE_HOST) {
+ phypwr |= PHYPWR_NORMAL_MASK_PHY1;
+ phypwr |= PHYPWR_NORMAL_MASK_HSIC0_4X12;
+ phypwr |= PHYPWR_NORMAL_MASK_HSIC1_4X12;
+ } else {
+ phypwr |= PHYPWR_NORMAL_MASK_PHY0;
+ }
+ break;
default:
break;
}
.cpu_type = TYPE_EXYNOS4X12,
.devphy_en_mask = EXYNOS_USBPHY_ENABLE,
.hostphy_en_mask = EXYNOS_USBPHY_ENABLE,
+ .hostphy_reg_offset = EXYNOS4x12_HSIC1_PHY_CTRL_OFFSET,
.rate_to_clksel = samsung_usbphy_rate_to_clksel_4x12,
.set_isolation = samsung_usbphy_set_isolation_4210,
.phy_enable = samsung_usb2phy_enable,
static struct samsung_usbphy_drvdata usb2phy_exynos5 = {
.cpu_type = TYPE_EXYNOS5250,
.hostphy_en_mask = EXYNOS_USBPHY_ENABLE,
- .hostphy_reg_offset = EXYNOS_USBHOST_PHY_CTRL_OFFSET,
+ .hostphy_reg_offset = EXYNOS5_USBHOST_PHY_CTRL_OFFSET,
.rate_to_clksel = samsung_usbphy_rate_to_clksel_4x12,
.set_isolation = samsung_usbphy_set_isolation_4210,
.phy_enable = samsung_exynos5_usb2phy_enable,