Commit 613a475f authored by Amelie Delaunay's avatar Amelie Delaunay Committed by Vinod Koul

phy: stm32: manage 1v1 and 1v8 supplies at pll activation/deactivation

PLL block requires to be powered with 1v1 and 1v8 supplies to catch
ENABLE signal.
Currently, supplies are managed through phy_ops .power_on/off, and PLL
activation/deactivation is managed through phy_ops .init/exit.
The sequence of phy_ops .power_on/.phy_init, .power_off/.exit is USB
drivers dependent.
To ensure a good behavior of the PLL, supplies have to be managed at PLL
activation/deactivation. That means the supplies need to be put in usbphyc
node and not in phy children nodes.
Signed-off-by: default avatarAmelie Delaunay <amelie.delaunay@foss.st.com>
Link: https://lore.kernel.org/r/20210105090525.23164-3-amelie.delaunay@foss.st.comSigned-off-by: default avatarVinod Koul <vkoul@kernel.org>
parent 00a9f717
...@@ -58,7 +58,6 @@ struct pll_params { ...@@ -58,7 +58,6 @@ struct pll_params {
struct stm32_usbphyc_phy { struct stm32_usbphyc_phy {
struct phy *phy; struct phy *phy;
struct stm32_usbphyc *usbphyc; struct stm32_usbphyc *usbphyc;
struct regulator_bulk_data supplies[NUM_SUPPLIES];
u32 index; u32 index;
bool active; bool active;
}; };
...@@ -70,6 +69,7 @@ struct stm32_usbphyc { ...@@ -70,6 +69,7 @@ struct stm32_usbphyc {
struct reset_control *rst; struct reset_control *rst;
struct stm32_usbphyc_phy **phys; struct stm32_usbphyc_phy **phys;
int nphys; int nphys;
struct regulator_bulk_data supplies[NUM_SUPPLIES];
int switch_setup; int switch_setup;
}; };
...@@ -153,10 +153,30 @@ static bool stm32_usbphyc_has_one_phy_active(struct stm32_usbphyc *usbphyc) ...@@ -153,10 +153,30 @@ static bool stm32_usbphyc_has_one_phy_active(struct stm32_usbphyc *usbphyc)
return false; return false;
} }
static int stm32_usbphyc_pll_disable(struct stm32_usbphyc *usbphyc)
{
void __iomem *pll_reg = usbphyc->base + STM32_USBPHYC_PLL;
/* Check if other phy port active */
if (stm32_usbphyc_has_one_phy_active(usbphyc))
return 0;
stm32_usbphyc_clr_bits(pll_reg, PLLEN);
/* Wait for minimum width of powerdown pulse (ENABLE = Low) */
udelay(PLL_PWR_DOWN_TIME_US);
if (readl_relaxed(pll_reg) & PLLEN) {
dev_err(usbphyc->dev, "PLL not reset\n");
return -EIO;
}
return regulator_bulk_disable(NUM_SUPPLIES, usbphyc->supplies);
}
static int stm32_usbphyc_pll_enable(struct stm32_usbphyc *usbphyc) static int stm32_usbphyc_pll_enable(struct stm32_usbphyc *usbphyc)
{ {
void __iomem *pll_reg = usbphyc->base + STM32_USBPHYC_PLL; void __iomem *pll_reg = usbphyc->base + STM32_USBPHYC_PLL;
bool pllen = (readl_relaxed(pll_reg) & PLLEN); bool pllen = readl_relaxed(pll_reg) & PLLEN;
int ret; int ret;
/* Check if one phy port has already configured the pll */ /* Check if one phy port has already configured the pll */
...@@ -164,46 +184,35 @@ static int stm32_usbphyc_pll_enable(struct stm32_usbphyc *usbphyc) ...@@ -164,46 +184,35 @@ static int stm32_usbphyc_pll_enable(struct stm32_usbphyc *usbphyc)
return 0; return 0;
if (pllen) { if (pllen) {
stm32_usbphyc_clr_bits(pll_reg, PLLEN); ret = stm32_usbphyc_pll_disable(usbphyc);
/* Wait for minimum width of powerdown pulse (ENABLE = Low) */ if (ret)
udelay(PLL_PWR_DOWN_TIME_US); return ret;
} }
ret = stm32_usbphyc_pll_init(usbphyc); ret = regulator_bulk_enable(NUM_SUPPLIES, usbphyc->supplies);
if (ret) if (ret)
return ret; return ret;
stm32_usbphyc_set_bits(pll_reg, PLLEN); ret = stm32_usbphyc_pll_init(usbphyc);
if (ret)
goto reg_disable;
stm32_usbphyc_set_bits(pll_reg, PLLEN);
/* Wait for maximum lock time */ /* Wait for maximum lock time */
udelay(PLL_LOCK_TIME_US); udelay(PLL_LOCK_TIME_US);
if (!(readl_relaxed(pll_reg) & PLLEN)) { if (!(readl_relaxed(pll_reg) & PLLEN)) {
dev_err(usbphyc->dev, "PLLEN not set\n"); dev_err(usbphyc->dev, "PLLEN not set\n");
return -EIO; ret = -EIO;
goto reg_disable;
} }
return 0; return 0;
}
static int stm32_usbphyc_pll_disable(struct stm32_usbphyc *usbphyc)
{
void __iomem *pll_reg = usbphyc->base + STM32_USBPHYC_PLL;
/* Check if other phy port active */
if (stm32_usbphyc_has_one_phy_active(usbphyc))
return 0;
stm32_usbphyc_clr_bits(pll_reg, PLLEN); reg_disable:
/* Wait for minimum width of powerdown pulse (ENABLE = Low) */ regulator_bulk_disable(NUM_SUPPLIES, usbphyc->supplies);
udelay(PLL_PWR_DOWN_TIME_US);
if (readl_relaxed(pll_reg) & PLLEN) { return ret;
dev_err(usbphyc->dev, "PLL not reset\n");
return -EIO;
}
return 0;
} }
static int stm32_usbphyc_phy_init(struct phy *phy) static int stm32_usbphyc_phy_init(struct phy *phy)
...@@ -231,25 +240,9 @@ static int stm32_usbphyc_phy_exit(struct phy *phy) ...@@ -231,25 +240,9 @@ static int stm32_usbphyc_phy_exit(struct phy *phy)
return stm32_usbphyc_pll_disable(usbphyc); return stm32_usbphyc_pll_disable(usbphyc);
} }
static int stm32_usbphyc_phy_power_on(struct phy *phy)
{
struct stm32_usbphyc_phy *usbphyc_phy = phy_get_drvdata(phy);
return regulator_bulk_enable(NUM_SUPPLIES, usbphyc_phy->supplies);
}
static int stm32_usbphyc_phy_power_off(struct phy *phy)
{
struct stm32_usbphyc_phy *usbphyc_phy = phy_get_drvdata(phy);
return regulator_bulk_disable(NUM_SUPPLIES, usbphyc_phy->supplies);
}
static const struct phy_ops stm32_usbphyc_phy_ops = { static const struct phy_ops stm32_usbphyc_phy_ops = {
.init = stm32_usbphyc_phy_init, .init = stm32_usbphyc_phy_init,
.exit = stm32_usbphyc_phy_exit, .exit = stm32_usbphyc_phy_exit,
.power_on = stm32_usbphyc_phy_power_on,
.power_off = stm32_usbphyc_phy_power_off,
.owner = THIS_MODULE, .owner = THIS_MODULE,
}; };
...@@ -313,7 +306,7 @@ static int stm32_usbphyc_probe(struct platform_device *pdev) ...@@ -313,7 +306,7 @@ static int stm32_usbphyc_probe(struct platform_device *pdev)
struct device_node *child, *np = dev->of_node; struct device_node *child, *np = dev->of_node;
struct phy_provider *phy_provider; struct phy_provider *phy_provider;
u32 version; u32 version;
int ret, port = 0; int ret, i, port = 0;
usbphyc = devm_kzalloc(dev, sizeof(*usbphyc), GFP_KERNEL); usbphyc = devm_kzalloc(dev, sizeof(*usbphyc), GFP_KERNEL);
if (!usbphyc) if (!usbphyc)
...@@ -355,11 +348,20 @@ static int stm32_usbphyc_probe(struct platform_device *pdev) ...@@ -355,11 +348,20 @@ static int stm32_usbphyc_probe(struct platform_device *pdev)
goto clk_disable; goto clk_disable;
} }
for (i = 0; i < NUM_SUPPLIES; i++)
usbphyc->supplies[i].supply = supplies_names[i];
ret = devm_regulator_bulk_get(dev, NUM_SUPPLIES, usbphyc->supplies);
if (ret) {
if (ret != -EPROBE_DEFER)
dev_err(dev, "failed to get regulators: %d\n", ret);
goto clk_disable;
}
for_each_child_of_node(np, child) { for_each_child_of_node(np, child) {
struct stm32_usbphyc_phy *usbphyc_phy; struct stm32_usbphyc_phy *usbphyc_phy;
struct phy *phy; struct phy *phy;
u32 index; u32 index;
int i;
phy = devm_phy_create(dev, child, &stm32_usbphyc_phy_ops); phy = devm_phy_create(dev, child, &stm32_usbphyc_phy_ops);
if (IS_ERR(phy)) { if (IS_ERR(phy)) {
...@@ -377,18 +379,6 @@ static int stm32_usbphyc_probe(struct platform_device *pdev) ...@@ -377,18 +379,6 @@ static int stm32_usbphyc_probe(struct platform_device *pdev)
goto put_child; goto put_child;
} }
for (i = 0; i < NUM_SUPPLIES; i++)
usbphyc_phy->supplies[i].supply = supplies_names[i];
ret = devm_regulator_bulk_get(&phy->dev, NUM_SUPPLIES,
usbphyc_phy->supplies);
if (ret) {
if (ret != -EPROBE_DEFER)
dev_err(&phy->dev,
"failed to get regulators: %d\n", ret);
goto put_child;
}
ret = of_property_read_u32(child, "reg", &index); ret = of_property_read_u32(child, "reg", &index);
if (ret || index > usbphyc->nphys) { if (ret || index > usbphyc->nphys) {
dev_err(&phy->dev, "invalid reg property: %d\n", ret); dev_err(&phy->dev, "invalid reg property: %d\n", ret);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment