Commit 7bc057dd authored by Amelie Delaunay's avatar Amelie Delaunay Committed by Vinod Koul

phy: stm32: register usbphyc as clock provider of ck_usbo_48m clock

ck_usbo_48m is generated by usbphyc PLL and used by OTG controller
for Full-Speed use cases with dedicated Full-Speed transceiver.

ck_usbo_48m is available as soon as the PLL is enabled.
Signed-off-by: default avatarAmelie Delaunay <amelie.delaunay@foss.st.com>
Link: https://lore.kernel.org/r/20210208114659.15269-3-amelie.delaunay@foss.st.comSigned-off-by: default avatarVinod Koul <vkoul@kernel.org>
parent 12810cb9
...@@ -36,6 +36,7 @@ config PHY_STIH407_USB ...@@ -36,6 +36,7 @@ config PHY_STIH407_USB
config PHY_STM32_USBPHYC config PHY_STM32_USBPHYC
tristate "STMicroelectronics STM32 USB HS PHY Controller driver" tristate "STMicroelectronics STM32 USB HS PHY Controller driver"
depends on ARCH_STM32 || COMPILE_TEST depends on ARCH_STM32 || COMPILE_TEST
depends on COMMON_CLK
select GENERIC_PHY select GENERIC_PHY
help help
Enable this to support the High-Speed USB transceivers that are part Enable this to support the High-Speed USB transceivers that are part
......
...@@ -7,6 +7,7 @@ ...@@ -7,6 +7,7 @@
*/ */
#include <linux/bitfield.h> #include <linux/bitfield.h>
#include <linux/clk.h> #include <linux/clk.h>
#include <linux/clk-provider.h>
#include <linux/delay.h> #include <linux/delay.h>
#include <linux/iopoll.h> #include <linux/iopoll.h>
#include <linux/kernel.h> #include <linux/kernel.h>
...@@ -70,6 +71,7 @@ struct stm32_usbphyc { ...@@ -70,6 +71,7 @@ struct stm32_usbphyc {
struct regulator *vdda1v1; struct regulator *vdda1v1;
struct regulator *vdda1v8; struct regulator *vdda1v8;
atomic_t n_pll_cons; atomic_t n_pll_cons;
struct clk_hw clk48_hw;
int switch_setup; int switch_setup;
}; };
...@@ -295,6 +297,61 @@ static const struct phy_ops stm32_usbphyc_phy_ops = { ...@@ -295,6 +297,61 @@ static const struct phy_ops stm32_usbphyc_phy_ops = {
.owner = THIS_MODULE, .owner = THIS_MODULE,
}; };
static int stm32_usbphyc_clk48_prepare(struct clk_hw *hw)
{
struct stm32_usbphyc *usbphyc = container_of(hw, struct stm32_usbphyc, clk48_hw);
return stm32_usbphyc_pll_enable(usbphyc);
}
static void stm32_usbphyc_clk48_unprepare(struct clk_hw *hw)
{
struct stm32_usbphyc *usbphyc = container_of(hw, struct stm32_usbphyc, clk48_hw);
stm32_usbphyc_pll_disable(usbphyc);
}
static unsigned long stm32_usbphyc_clk48_recalc_rate(struct clk_hw *hw, unsigned long parent_rate)
{
return 48000000;
}
static const struct clk_ops usbphyc_clk48_ops = {
.prepare = stm32_usbphyc_clk48_prepare,
.unprepare = stm32_usbphyc_clk48_unprepare,
.recalc_rate = stm32_usbphyc_clk48_recalc_rate,
};
static void stm32_usbphyc_clk48_unregister(void *data)
{
struct stm32_usbphyc *usbphyc = data;
of_clk_del_provider(usbphyc->dev->of_node);
clk_hw_unregister(&usbphyc->clk48_hw);
}
static int stm32_usbphyc_clk48_register(struct stm32_usbphyc *usbphyc)
{
struct device_node *node = usbphyc->dev->of_node;
struct clk_init_data init = { };
int ret = 0;
init.name = "ck_usbo_48m";
init.ops = &usbphyc_clk48_ops;
usbphyc->clk48_hw.init = &init;
ret = clk_hw_register(usbphyc->dev, &usbphyc->clk48_hw);
if (ret)
return ret;
ret = of_clk_add_hw_provider(node, of_clk_hw_simple_get, &usbphyc->clk48_hw);
if (ret)
clk_hw_unregister(&usbphyc->clk48_hw);
return ret;
}
static void stm32_usbphyc_switch_setup(struct stm32_usbphyc *usbphyc, static void stm32_usbphyc_switch_setup(struct stm32_usbphyc *usbphyc,
u32 utmi_switch) u32 utmi_switch)
{ {
...@@ -473,6 +530,12 @@ static int stm32_usbphyc_probe(struct platform_device *pdev) ...@@ -473,6 +530,12 @@ static int stm32_usbphyc_probe(struct platform_device *pdev)
goto clk_disable; goto clk_disable;
} }
ret = stm32_usbphyc_clk48_register(usbphyc);
if (ret) {
dev_err(dev, "failed to register ck_usbo_48m clock: %d\n", ret);
goto clk_disable;
}
version = readl_relaxed(usbphyc->base + STM32_USBPHYC_VERSION); version = readl_relaxed(usbphyc->base + STM32_USBPHYC_VERSION);
dev_info(dev, "registered rev:%lu.%lu\n", dev_info(dev, "registered rev:%lu.%lu\n",
FIELD_GET(MAJREV, version), FIELD_GET(MINREV, version)); FIELD_GET(MAJREV, version), FIELD_GET(MINREV, version));
...@@ -497,6 +560,8 @@ static int stm32_usbphyc_remove(struct platform_device *pdev) ...@@ -497,6 +560,8 @@ static int stm32_usbphyc_remove(struct platform_device *pdev)
if (usbphyc->phys[port]->active) if (usbphyc->phys[port]->active)
stm32_usbphyc_phy_exit(usbphyc->phys[port]->phy); stm32_usbphyc_phy_exit(usbphyc->phys[port]->phy);
stm32_usbphyc_clk48_unregister(usbphyc);
clk_disable_unprepare(usbphyc->clk); clk_disable_unprepare(usbphyc->clk);
return 0; return 0;
......
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