phy: rockchip-usb: support InnoSilicon usb2.0 phy
authorFrank Wang <frank.wang@rock-chips.com>
Fri, 11 Mar 2016 01:20:26 +0000 (09:20 +0800)
committerKever Yang <kever.yang@rock-chips.com>
Tue, 15 Mar 2016 08:59:43 +0000 (16:59 +0800)
For InnoSilicon usb2.0 phy, there is no siddq bit for operating,
what is more, when we control usb phy to suspend, its Plls will
not be affected. So we can operate resume/suspend bits directly
when it is going to power on/off.

Change-Id: I6bfe6b1a90b1bdcb0b0d5b670d579a625b22c0ba
Signed-off-by: Frank Wang <frank.wang@rock-chips.com>
drivers/phy/phy-rockchip-usb.c

index 33a80eba1cb44836ebc74e6ddeefb5269b76dd30..4b407d385c9126dfb57b16b753e451ec1e103f19 100644 (file)
 #define SIDDQ_ON               BIT(13)
 #define SIDDQ_OFF              (0 << 13)
 
+#define USB2_PHY_WRITE_ENA     (0xffff << 16)
+#define USB2_PHY_SUSPEND       (0x5 << 0 | 0xd << 4 | 0x1 << 8)
+#define USB2_PHY_RESUME        (0)
+
 struct rockchip_usb_phys {
        int reg;
        const char *pll_name;
@@ -45,6 +49,9 @@ struct rockchip_usb_phys {
 
 struct rockchip_usb_phy_pdata {
        struct rockchip_usb_phys *phys;
+       unsigned int phy_pw_on;
+       unsigned int phy_pw_off;
+       bool siddq_ctl;
 };
 
 struct rockchip_usb_phy_base {
@@ -64,10 +71,12 @@ struct rockchip_usb_phy {
 };
 
 static int rockchip_usb_phy_power(struct rockchip_usb_phy *phy,
-                                          bool siddq)
+                                          bool off)
 {
-       return regmap_write(phy->base->reg_base, phy->reg_offset,
-                           SIDDQ_WRITE_ENA | (siddq ? SIDDQ_ON : SIDDQ_OFF));
+       unsigned int val;
+
+       val = !off ? phy->base->pdata->phy_pw_on : phy->base->pdata->phy_pw_off;
+       return regmap_write(phy->base->reg_base, phy->reg_offset, val);
 }
 
 static unsigned long rockchip_usb_phy480m_recalc_rate(struct clk_hw *hw,
@@ -83,17 +92,22 @@ static void rockchip_usb_phy480m_disable(struct clk_hw *hw)
                                                    clk480m_hw);
 
        /* Power down usb phy analog blocks by set siddq 1 */
-       rockchip_usb_phy_power(phy, 1);
+       if (phy->base->pdata->siddq_ctl)
+               rockchip_usb_phy_power(phy, 1);
 }
 
 static int rockchip_usb_phy480m_enable(struct clk_hw *hw)
 {
+       int ret = 0;
        struct rockchip_usb_phy *phy = container_of(hw,
                                                    struct rockchip_usb_phy,
                                                    clk480m_hw);
 
        /* Power up usb phy analog blocks by set siddq 0 */
-       return rockchip_usb_phy_power(phy, 0);
+       if (phy->base->pdata->siddq_ctl)
+               ret = rockchip_usb_phy_power(phy, 0);
+
+       return ret;
 }
 
 static int rockchip_usb_phy480m_is_enabled(struct clk_hw *hw)
@@ -101,14 +115,18 @@ static int rockchip_usb_phy480m_is_enabled(struct clk_hw *hw)
        struct rockchip_usb_phy *phy = container_of(hw,
                                                    struct rockchip_usb_phy,
                                                    clk480m_hw);
-       int ret;
+       int ret = 1;
        u32 val;
 
-       ret = regmap_read(phy->base->reg_base, phy->reg_offset, &val);
-       if (ret < 0)
-               return ret;
+       if (phy->base->pdata->siddq_ctl) {
+               ret = regmap_read(phy->base->reg_base, phy->reg_offset, &val);
+               if (ret < 0)
+                       return ret;
 
-       return (val & SIDDQ_ON) ? 0 : 1;
+               ret = (val & SIDDQ_ON) ? 0 : 1;
+       }
+
+       return ret;
 }
 
 static const struct clk_ops rockchip_usb_phy480m_ops = {
@@ -120,18 +138,32 @@ static const struct clk_ops rockchip_usb_phy480m_ops = {
 
 static int rockchip_usb_phy_power_off(struct phy *_phy)
 {
+       int ret = 0;
        struct rockchip_usb_phy *phy = phy_get_drvdata(_phy);
 
-       clk_disable_unprepare(phy->clk480m);
+       if (!phy->base->pdata->siddq_ctl) {
+               ret = rockchip_usb_phy_power(phy, 1);
+               if (ret)
+                       return ret;
+       }
 
+       clk_disable_unprepare(phy->clk480m);
        return 0;
 }
 
 static int rockchip_usb_phy_power_on(struct phy *_phy)
 {
+       int ret = 0;
        struct rockchip_usb_phy *phy = phy_get_drvdata(_phy);
 
-       return clk_prepare_enable(phy->clk480m);
+       ret = clk_prepare_enable(phy->clk480m);
+       if (ret)
+               return ret;
+
+       if (!phy->base->pdata->siddq_ctl)
+               ret = rockchip_usb_phy_power(phy, 0);
+
+       return ret;
 }
 
 static const struct phy_ops ops = {
@@ -249,6 +281,9 @@ static const struct rockchip_usb_phy_pdata rk3066a_pdata = {
                { .reg = 0x188, .pll_name = "sclk_otgphy1_480m" },
                { /* sentinel */ }
        },
+       .phy_pw_on  = SIDDQ_WRITE_ENA | SIDDQ_OFF,
+       .phy_pw_off = SIDDQ_WRITE_ENA | SIDDQ_ON,
+       .siddq_ctl  = true,
 };
 
 static const struct rockchip_usb_phy_pdata rk3188_pdata = {
@@ -257,6 +292,9 @@ static const struct rockchip_usb_phy_pdata rk3188_pdata = {
                { .reg = 0x11c, .pll_name = "sclk_otgphy1_480m" },
                { /* sentinel */ }
        },
+       .phy_pw_on  = SIDDQ_WRITE_ENA | SIDDQ_OFF,
+       .phy_pw_off = SIDDQ_WRITE_ENA | SIDDQ_ON,
+       .siddq_ctl  = true,
 };
 
 static const struct rockchip_usb_phy_pdata rk3288_pdata = {
@@ -266,6 +304,20 @@ static const struct rockchip_usb_phy_pdata rk3288_pdata = {
                { .reg = 0x348, .pll_name = "sclk_otgphy2_480m" },
                { /* sentinel */ }
        },
+       .phy_pw_on  = SIDDQ_WRITE_ENA | SIDDQ_OFF,
+       .phy_pw_off = SIDDQ_WRITE_ENA | SIDDQ_ON,
+       .siddq_ctl  = true,
+};
+
+static const struct rockchip_usb_phy_pdata rk336x_pdata = {
+       .phys = (struct rockchip_usb_phys[]){
+               { .reg = 0x700, .pll_name = "sclk_otgphy0_480m" },
+               { .reg = 0x728, .pll_name = "sclk_otgphy1_480m" },
+               { /* sentinel */ }
+       },
+       .phy_pw_on  = USB2_PHY_WRITE_ENA | USB2_PHY_RESUME,
+       .phy_pw_off = USB2_PHY_WRITE_ENA | USB2_PHY_SUSPEND,
+       .siddq_ctl  = false,
 };
 
 static int rockchip_usb_phy_probe(struct platform_device *pdev)
@@ -313,6 +365,7 @@ static const struct of_device_id rockchip_usb_phy_dt_ids[] = {
        { .compatible = "rockchip,rk3066a-usb-phy", .data = &rk3066a_pdata },
        { .compatible = "rockchip,rk3188-usb-phy", .data = &rk3188_pdata },
        { .compatible = "rockchip,rk3288-usb-phy", .data = &rk3288_pdata },
+       { .compatible = "rockchip,rk336x-usb-phy", .data = &rk336x_pdata },
        {}
 };