#define EXYNOS2200_CLKRST_LINK_PCLK_SEL BIT(1)
#define EXYNOS2200_DRD_UTMI 0x10
+
+/* ExynosAutov920 bits */
+#define UTMICTL_FORCE_UTMI_SUSPEND BIT(13)
+#define UTMICTL_FORCE_UTMI_SLEEP BIT(12)
+#define UTMICTL_FORCE_DPPULLDOWN BIT(9)
+#define UTMICTL_FORCE_DMPULLDOWN BIT(8)
+
#define EXYNOS2200_UTMI_FORCE_VBUSVALID BIT(1)
#define EXYNOS2200_UTMI_FORCE_BVALID BIT(0)
#define EXYNOS850_DRD_HSP_TEST 0x5c
#define HSP_TEST_SIDDQ BIT(24)
+#define EXYNOSAUTOV920_DRD_HSP_CLKRST 0x100
+#define HSPCLKRST_PHY20_SW_PORTRESET BIT(3)
+#define HSPCLKRST_PHY20_SW_POR BIT(1)
+#define HSPCLKRST_PHY20_SW_POR_SEL BIT(0)
+
+#define EXYNOSAUTOV920_DRD_HSPCTL 0x104
+#define HSPCTRL_VBUSVLDEXTSEL BIT(13)
+#define HSPCTRL_VBUSVLDEXT BIT(12)
+#define HSPCTRL_EN_UTMISUSPEND BIT(9)
+#define HSPCTRL_COMMONONN BIT(8)
+
+#define EXYNOSAUTOV920_DRD_HSP_TEST 0x10c
+
+#define EXYNOSAUTOV920_DRD_HSPPLLTUNE 0x110
+#define HSPPLLTUNE_FSEL GENMASK(18, 16)
+
/* Exynos9 - GS101 */
#define EXYNOS850_DRD_SECPMACTL 0x48
#define SECPMACTL_PMA_ROPLL_REF_CLK_SEL GENMASK(13, 12)
.n_regulators = ARRAY_SIZE(exynos5_regulator_names),
};
+static void
+exynosautov920_usbdrd_utmi_init(struct exynos5_usbdrd_phy *phy_drd)
+{
+ void __iomem *reg_phy = phy_drd->reg_phy;
+ u32 reg;
+
+ /*
+ * Disable HWACG (hardware auto clock gating control). This
+ * forces QACTIVE signal in Q-Channel interface to HIGH level,
+ * to make sure the PHY clock is not gated by the hardware.
+ */
+ reg = readl(reg_phy + EXYNOS850_DRD_LINKCTRL);
+ reg |= LINKCTRL_FORCE_QACT;
+ writel(reg, reg_phy + EXYNOS850_DRD_LINKCTRL);
+
+ /* De-assert link reset */
+ reg = readl(reg_phy + EXYNOS2200_DRD_CLKRST);
+ reg &= ~CLKRST_LINK_SW_RST;
+ writel(reg, reg_phy + EXYNOS2200_DRD_CLKRST);
+
+ /* Set PHY POR High */
+ reg = readl(reg_phy + EXYNOSAUTOV920_DRD_HSP_CLKRST);
+ reg |= HSPCLKRST_PHY20_SW_POR | HSPCLKRST_PHY20_SW_POR_SEL;
+ writel(reg, reg_phy + EXYNOSAUTOV920_DRD_HSP_CLKRST);
+
+ /* Enable UTMI+ */
+ reg = readl(reg_phy + EXYNOS2200_DRD_UTMI);
+ reg &= ~(UTMICTL_FORCE_UTMI_SUSPEND | UTMICTL_FORCE_UTMI_SLEEP |
+ UTMICTL_FORCE_DPPULLDOWN | UTMICTL_FORCE_DMPULLDOWN);
+ writel(reg, reg_phy + EXYNOS2200_DRD_UTMI);
+
+ /* set phy clock & control HS phy */
+ reg = readl(reg_phy + EXYNOSAUTOV920_DRD_HSPCTL);
+ reg |= HSPCTRL_EN_UTMISUSPEND | HSPCTRL_COMMONONN;
+ writel(reg, reg_phy + EXYNOSAUTOV920_DRD_HSPCTL);
+
+ fsleep(100);
+
+ /* Set VBUS Valid and DP-Pull up control by VBUS pad usage */
+ reg = readl(reg_phy + EXYNOS850_DRD_LINKCTRL);
+ reg |= FIELD_PREP_CONST(LINKCTRL_BUS_FILTER_BYPASS, 0xf);
+ writel(reg, reg_phy + EXYNOS850_DRD_LINKCTRL);
+
+ reg = readl(reg_phy + EXYNOS2200_DRD_UTMI);
+ reg |= EXYNOS2200_UTMI_FORCE_VBUSVALID | EXYNOS2200_UTMI_FORCE_BVALID;
+ writel(reg, reg_phy + EXYNOS2200_DRD_UTMI);
+
+ reg = readl(reg_phy + EXYNOSAUTOV920_DRD_HSPCTL);
+ reg |= HSPCTRL_VBUSVLDEXTSEL | HSPCTRL_VBUSVLDEXT;
+ writel(reg, reg_phy + EXYNOSAUTOV920_DRD_HSPCTL);
+
+ /* Setting FSEL for refference clock */
+ reg = readl(reg_phy + EXYNOSAUTOV920_DRD_HSPPLLTUNE);
+ reg &= ~HSPPLLTUNE_FSEL;
+
+ switch (phy_drd->extrefclk) {
+ case EXYNOS5_FSEL_50MHZ:
+ reg |= FIELD_PREP(HSPPLLTUNE_FSEL, 7);
+ break;
+ case EXYNOS5_FSEL_26MHZ:
+ reg |= FIELD_PREP(HSPPLLTUNE_FSEL, 6);
+ break;
+ case EXYNOS5_FSEL_24MHZ:
+ reg |= FIELD_PREP(HSPPLLTUNE_FSEL, 2);
+ break;
+ case EXYNOS5_FSEL_20MHZ:
+ reg |= FIELD_PREP(HSPPLLTUNE_FSEL, 1);
+ break;
+ case EXYNOS5_FSEL_19MHZ2:
+ reg |= FIELD_PREP(HSPPLLTUNE_FSEL, 0);
+ break;
+ default:
+ dev_warn(phy_drd->dev, "unsupported ref clk: %#.2x\n",
+ phy_drd->extrefclk);
+ break;
+ }
+ writel(reg, reg_phy + EXYNOSAUTOV920_DRD_HSPPLLTUNE);
+
+ /* Enable PHY Power Mode */
+ reg = readl(reg_phy + EXYNOSAUTOV920_DRD_HSP_TEST);
+ reg &= ~HSP_TEST_SIDDQ;
+ writel(reg, reg_phy + EXYNOSAUTOV920_DRD_HSP_TEST);
+
+ /* before POR low, 10us delay is needed to Finish PHY reset */
+ fsleep(10);
+
+ /* Set PHY POR Low */
+ reg = readl(reg_phy + EXYNOSAUTOV920_DRD_HSP_CLKRST);
+ reg |= HSPCLKRST_PHY20_SW_POR_SEL;
+ reg &= ~(HSPCLKRST_PHY20_SW_POR | HSPCLKRST_PHY20_SW_PORTRESET);
+ writel(reg, reg_phy + EXYNOSAUTOV920_DRD_HSP_CLKRST);
+
+ /* after POR low and delay 75us, PHYCLOCK is guaranteed. */
+ fsleep(75);
+
+ /* force pipe3 signal for link */
+ reg = readl(reg_phy + EXYNOS850_DRD_LINKCTRL);
+ reg |= LINKCTRL_FORCE_PIPE_EN;
+ reg &= ~LINKCTRL_FORCE_PHYSTATUS;
+ reg |= LINKCTRL_FORCE_RXELECIDLE;
+ writel(reg, reg_phy + EXYNOS850_DRD_LINKCTRL);
+}
+
+static void
+exynosautov920_usbdrd_hsphy_disable(struct exynos5_usbdrd_phy *phy_drd)
+{
+ u32 reg;
+ void __iomem *reg_phy = phy_drd->reg_phy;
+
+ /* set phy clock & control HS phy */
+ reg = readl(reg_phy + EXYNOS2200_DRD_UTMI);
+ reg |= UTMICTL_FORCE_UTMI_SUSPEND | UTMICTL_FORCE_UTMI_SLEEP;
+ reg &= ~(UTMICTL_FORCE_DPPULLDOWN | UTMICTL_FORCE_DMPULLDOWN);
+ writel(reg, reg_phy + EXYNOS2200_DRD_UTMI);
+
+ /* Disable PHY Power Mode */
+ reg = readl(reg_phy + EXYNOSAUTOV920_DRD_HSP_TEST);
+ reg |= HSP_TEST_SIDDQ;
+ writel(reg, reg_phy + EXYNOSAUTOV920_DRD_HSP_TEST);
+
+ /* clear force q-channel */
+ reg = readl(reg_phy + EXYNOS850_DRD_LINKCTRL);
+ reg &= ~LINKCTRL_FORCE_QACT;
+ writel(reg, reg_phy + EXYNOS850_DRD_LINKCTRL);
+
+ /* link sw reset is need for USB_DP/DM high-z in host mode */
+ reg = readl(reg_phy + EXYNOS2200_DRD_CLKRST);
+ reg |= CLKRST_LINK_SW_RST;
+ writel(reg, reg_phy + EXYNOS2200_DRD_CLKRST);
+ fsleep(10);
+ reg &= ~CLKRST_LINK_SW_RST;
+ writel(reg, reg_phy + EXYNOS2200_DRD_CLKRST);
+}
+
static int exynosautov920_usbdrd_phy_init(struct phy *phy)
{
struct phy_usb_instance *inst = phy_get_drvdata(phy);
return 0;
}
+static int exynosautov920_usbdrd_combo_phy_exit(struct phy *phy)
+{
+ struct phy_usb_instance *inst = phy_get_drvdata(phy);
+ struct exynos5_usbdrd_phy *phy_drd = to_usbdrd_phy(inst);
+ int ret = 0;
+
+ ret = clk_bulk_prepare_enable(phy_drd->drv_data->n_clks, phy_drd->clks);
+ if (ret)
+ return ret;
+
+ if (inst->phy_cfg->id == EXYNOS5_DRDPHY_UTMI)
+ exynosautov920_usbdrd_hsphy_disable(phy_drd);
+
+ /* enable PHY isol */
+ inst->phy_cfg->phy_isol(inst, true);
+
+ clk_bulk_disable_unprepare(phy_drd->drv_data->n_clks, phy_drd->clks);
+
+ return 0;
+}
+
static int exynosautov920_usbdrd_phy_power_on(struct phy *phy)
{
struct phy_usb_instance *inst = phy_get_drvdata(phy);
"dvdd", "vdd18", "vdd33",
};
+static const struct phy_ops exynosautov920_usbdrd_combo_hsphy_ops = {
+ .init = exynosautov920_usbdrd_phy_init,
+ .exit = exynosautov920_usbdrd_combo_phy_exit,
+ .power_on = exynosautov920_usbdrd_phy_power_on,
+ .power_off = exynosautov920_usbdrd_phy_power_off,
+ .owner = THIS_MODULE,
+};
+
+static const struct
+exynos5_usbdrd_phy_config usbdrd_hsphy_cfg_exynosautov920[] = {
+ {
+ .id = EXYNOS5_DRDPHY_UTMI,
+ .phy_isol = exynos5_usbdrd_phy_isol,
+ .phy_init = exynosautov920_usbdrd_utmi_init,
+ },
+};
+
+static const
+struct exynos5_usbdrd_phy_drvdata exynosautov920_usbdrd_combo_hsphy = {
+ .phy_cfg = usbdrd_hsphy_cfg_exynosautov920,
+ .phy_ops = &exynosautov920_usbdrd_combo_hsphy_ops,
+ .pmu_offset_usbdrd0_phy = EXYNOSAUTOV920_PHY_CTRL_USB20,
+ .clk_names = exynos5_clk_names,
+ .n_clks = ARRAY_SIZE(exynos5_clk_names),
+ .core_clk_names = exynos5_core_clk_names,
+ .n_core_clks = ARRAY_SIZE(exynos5_core_clk_names),
+ .regulator_names = exynosautov920_usb20_regulators,
+ .n_regulators = ARRAY_SIZE(exynosautov920_usb20_regulators),
+};
+
static const struct phy_ops exynosautov920_usbdrd_phy_ops = {
.init = exynosautov920_usbdrd_phy_init,
.exit = exynosautov920_usbdrd_phy_exit,
}, {
.compatible = "samsung,exynos990-usbdrd-phy",
.data = &exynos990_usbdrd_phy
+ }, {
+ .compatible = "samsung,exynosautov920-usbdrd-combo-hsphy",
+ .data = &exynosautov920_usbdrd_combo_hsphy
}, {
.compatible = "samsung,exynosautov920-usbdrd-phy",
.data = &exynosautov920_usbdrd_phy