diff --git a/drivers/phy/mediatek/phy-mtk-tphy.c b/drivers/phy/mediatek/phy-mtk-tphy.c
index cdbcc49..a7dfeec 100644
--- a/drivers/phy/mediatek/phy-mtk-tphy.c
+++ b/drivers/phy/mediatek/phy-mtk-tphy.c
@@ -68,6 +68,7 @@
#define PA6_RG_U2_SQTH_VAL(x) (0xf & (x))
#define U3P_U2PHYACR4 0x020
+#define P2C_RG_USB20_DM_100K_EN BIT(17)
#define P2C_RG_USB20_GPIO_CTL BIT(9)
#define P2C_USB20_GPIO_MODE BIT(8)
#define P2C_U2_GPIO_CTR_MSK (P2C_RG_USB20_GPIO_CTL | P2C_USB20_GPIO_MODE)
@@ -76,6 +77,12 @@
#define P2C_RG_SIF_U2PLL_FORCE_ON BIT(24)
#define U3P_U2PHYDTM0 0x068
+#define P2C_RG_UART_MODE GENMASK(31, 30)
+#define P2C_RG_UART_MODE_VAL(x) ((0x3 & (x)) << 30)
+#define P2C_RG_UART_MODE_OFET (30)
+#define P2C_FORCE_UART_I BIT(29)
+#define P2C_FORCE_UART_BIAS_EN BIT(28)
+#define P2C_FORCE_UART_TX_OE BIT(27)
#define P2C_FORCE_UART_EN BIT(26)
#define P2C_FORCE_DATAIN BIT(23)
#define P2C_FORCE_DM_PULLDOWN BIT(21)
@@ -98,6 +105,8 @@
P2C_RG_DPPULLDOWN | P2C_RG_TERMSEL)
#define U3P_U2PHYDTM1 0x06C
+#define P2C_RG_UART_BIAS_EN BIT(18)
+#define P2C_RG_UART_TX_OE BIT(17)
#define P2C_RG_UART_EN BIT(16)
#define P2C_FORCE_IDDIG BIT(9)
#define P2C_RG_VBUSVALID BIT(5)
@@ -600,6 +609,90 @@ static void u2_phy_instance_exit(struct mtk_tphy *tphy,
}
}
+static void u2_phy_instance_set_mode_2uart(struct u2phy_banks *u2_banks)
+{
+ u32 tmp;
+
+ /* Clear PA6_RG_U2_BC11_SW_EN */
+ tmp = readl(u2_banks->com + U3P_USBPHYACR6);
+ tmp &= ~(PA6_RG_U2_BC11_SW_EN);
+ writel(tmp, u2_banks->com + U3P_USBPHYACR6);
+
+ /* Set P2C_RG_SUSPENDM */
+ tmp = readl(u2_banks->com + U3P_U2PHYDTM0);
+ tmp |= P2C_RG_SUSPENDM;
+ writel(tmp, u2_banks->com + U3P_U2PHYDTM0);
+
+ /* Set P2C_FORCE_SUSPENDM */
+ tmp = readl(u2_banks->com + U3P_U2PHYDTM0);
+ tmp |= P2C_FORCE_SUSPENDM;
+ writel(tmp, u2_banks->com + U3P_U2PHYDTM0);
+
+ /* Clear and Set P2C_RG_UART_MODE to 2'b01 */
+ tmp = readl(u2_banks->com + U3P_U2PHYDTM0);
+ tmp &= ~(P2C_RG_UART_MODE);
+ tmp |= P2C_RG_UART_MODE_VAL(0x1);
+ writel(tmp, u2_banks->com + U3P_U2PHYDTM0);
+
+ /* Clear P2C_FORCE_UART_I */
+ tmp = readl(u2_banks->com + U3P_U2PHYDTM0);
+ tmp &= ~(P2C_FORCE_UART_I);
+ writel(tmp, u2_banks->com + U3P_U2PHYDTM0);
+
+ /* Set P2C_FORCE_UART_BIAS_EN */
+ tmp = readl(u2_banks->com + U3P_U2PHYDTM0);
+ tmp |= P2C_FORCE_UART_BIAS_EN;
+ writel(tmp, u2_banks->com + U3P_U2PHYDTM0);
+
+ /* Set P2C_FORCE_UART_TX_OE */
+ tmp = readl(u2_banks->com + U3P_U2PHYDTM0);
+ tmp |= P2C_FORCE_UART_TX_OE;
+ writel(tmp, u2_banks->com + U3P_U2PHYDTM0);
+
+ /* Set P2C_FORCE_UART_EN */
+ tmp = readl(u2_banks->com + U3P_U2PHYDTM0);
+ tmp |= P2C_FORCE_UART_EN;
+ writel(tmp, u2_banks->com + U3P_U2PHYDTM0);
+
+ /* Set P2C_RG_UART_BIAS_EN */
+ tmp = readl(u2_banks->com + U3P_U2PHYDTM0);
+ tmp |= P2C_RG_UART_BIAS_EN;
+ writel(tmp, u2_banks->com + U3P_U2PHYDTM0);
+
+ /* Set P2C_RG_UART_TX_OE */
+ tmp = readl(u2_banks->com + U3P_U2PHYDTM0);
+ tmp |= P2C_RG_UART_TX_OE;
+ writel(tmp, u2_banks->com + U3P_U2PHYDTM0);
+
+ /* Set P2C_RG_UART_EN */
+ tmp = readl(u2_banks->com + U3P_U2PHYDTM0);
+ tmp |= P2C_RG_UART_EN;
+ writel(tmp, u2_banks->com + U3P_U2PHYDTM0);
+
+ /* Set P2C_RG_USB20_DM_100K_EN */
+ tmp = readl(u2_banks->com + U3P_U2PHYACR4);
+ tmp |= P2C_RG_USB20_DM_100K_EN;
+ writel(tmp, u2_banks->com + U3P_U2PHYACR4);
+
+ /* Clear P2C_RG_DMPULLDOWN, P2C_RG_DPPULLDOWN */
+ tmp = readl(u2_banks->com + U3P_U2PHYDTM0);
+ tmp &= ~(P2C_RG_DPPULLDOWN | P2C_RG_DMPULLDOWN);
+ writel(tmp, u2_banks->com + U3P_U2PHYDTM0);
+}
+
+static int u2_phy_instance_get_mode_ext(struct mtk_tphy *tphy, struct mtk_phy_instance *instance)
+{
+ struct u2phy_banks *u2_banks = &instance->u2_banks;
+ u32 tmp;
+
+ tmp = readl(u2_banks->com + U3P_U2PHYDTM0);
+
+ if ((tmp & P2C_RG_UART_MODE) >> P2C_RG_UART_MODE_OFET)
+ return PHY_MODE_UART;
+ else
+ return PHY_MODE_USB_OTG;
+}
+
static void u2_phy_instance_set_mode(struct mtk_tphy *tphy,
struct mtk_phy_instance *instance,
enum phy_mode mode)@@ -609,6 +702,9 @@ static void u2_phy_instance_set_mode(struct mtk_tphy *tphy,
tmp = readl(u2_banks->com + U3P_U2PHYDTM1);
switch (mode) {
+ case PHY_MODE_UART:
+ u2_phy_instance_set_mode_2uart(u2_banks);
+ return;
case PHY_MODE_USB_DEVICE:
tmp |= P2C_FORCE_IDDIG | P2C_RG_IDDIG;
break;@@ -933,6 +1029,10 @@ static int mtk_phy_init(struct phy *phy)
return ret;
}
+ ret = u2_phy_instance_get_mode_ext(tphy, instance);
+ if (ret == PHY_MODE_UART)
+ return 0;
+
switch (instance->type) {
case PHY_TYPE_USB2:
u2_phy_instance_init(tphy, instance);@@ -996,6 +1096,19 @@ static int mtk_phy_exit(struct phy *phy)
return 0;
}
+static int mtk_phy_get_mode_ext(struct phy *phy)
+{
+ struct mtk_phy_instance *instance = phy_get_drvdata(phy);
+ struct mtk_tphy *tphy = dev_get_drvdata(phy->dev.parent);
+ int ret;
+
+ ret = 0;
+ if (instance->type == PHY_TYPE_USB2)
+ ret = u2_phy_instance_get_mode_ext(tphy, instance);
+
+ return ret;
+}
+
static int mtk_phy_set_mode(struct phy *phy, enum phy_mode mode, int submode)
{
struct mtk_phy_instance *instance = phy_get_drvdata(phy);@@ -1060,6 +1173,7 @@ static struct phy *mtk_phy_xlate(struct device *dev,
.power_on = mtk_phy_power_on,
.power_off = mtk_phy_power_off,
.set_mode = mtk_phy_set_mode,
+ .get_mode_ext = mtk_phy_get_mode_ext,
.owner = THIS_MODULE,
};
--
1.7.9.5
_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel