From bf011cb7527ae05169c1b82cc52c6ff9530b0580 Mon Sep 17 00:00:00 2001 From: Frank Wang Date: Fri, 11 Mar 2016 09:20:26 +0800 Subject: [PATCH] phy: rockchip-usb: support InnoSilicon usb2.0 phy 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 --- drivers/phy/phy-rockchip-usb.c | 77 ++++++++++++++++++++++++++++------ 1 file changed, 65 insertions(+), 12 deletions(-) diff --git a/drivers/phy/phy-rockchip-usb.c b/drivers/phy/phy-rockchip-usb.c index 33a80eba1cb4..4b407d385c91 100644 --- a/drivers/phy/phy-rockchip-usb.c +++ b/drivers/phy/phy-rockchip-usb.c @@ -38,6 +38,10 @@ #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 }, {} }; -- 2.34.1