phy: k1-usb: k3: add USB2 PHY support

Add USB2 PHY support for SpacemiT K3 SoC.

Register layout of handling USB disconnect operation has been changed,
So introducing a platform data to distinguish the different SoCs.

Reviewed-by: Yao Zi <me@ziyao.cc>
Signed-off-by: Yixun Lan <dlan@kernel.org>
Reviewed-by: Neil Armstrong <neil.armstrong@linaro.org>
Link: https://git.kernel.org/pub/scm/linux/kernel/git/gregkh/usb.git/commit/?h=usb-next&id=c05cf9d274daf72dc7e433480cf2e0e888f6bd89 [1]
Link: https://git.kernel.org/pub/scm/linux/kernel/git/gregkh/usb.git/commit/?h=usb-next&id=00b4fe5be06aecd6426930de86b7cffc2330f4b8 [2]
Link: https://patch.msgid.link/20260305-11-k3-usb2-phy-v4-2-15554fb933bc@kernel.org
Signed-off-by: Vinod Koul <vkoul@kernel.org>
This commit is contained in:
Yixun Lan 2026-03-05 01:00:52 +00:00 committed by Vinod Koul
parent ad8fdebd40
commit 056ee8b37b

View File

@ -51,6 +51,9 @@
#define PHY_K1_HS_HOST_DISC 0x40
#define PHY_K1_HS_HOST_DISC_CLR BIT(0)
#define PHY_K3_HS_HOST_DISC 0x20
#define PHY_K3_HS_HOST_DISC_CLR BIT(8)
#define PHY_PLL_DIV_CFG 0x98
#define PHY_FDIV_FRACT_8_15 GENMASK(7, 0)
#define PHY_FDIV_FRACT_16_19 GENMASK(11, 8)
@ -145,7 +148,7 @@ static int spacemit_usb2phy_exit(struct phy *phy)
return 0;
}
static int spacemit_usb2phy_disconnect(struct phy *phy, int port)
static int spacemit_k1_usb2phy_disconnect(struct phy *phy, int port)
{
struct spacemit_usb2phy *sphy = phy_get_drvdata(phy);
@ -155,10 +158,27 @@ static int spacemit_usb2phy_disconnect(struct phy *phy, int port)
return 0;
}
static const struct phy_ops spacemit_usb2phy_ops = {
static int spacemit_k3_usb2phy_disconnect(struct phy *phy, int port)
{
struct spacemit_usb2phy *sphy = phy_get_drvdata(phy);
regmap_update_bits(sphy->regmap_base, PHY_K3_HS_HOST_DISC,
PHY_K3_HS_HOST_DISC_CLR, PHY_K3_HS_HOST_DISC_CLR);
return 0;
}
static const struct phy_ops spacemit_k1_usb2phy_ops = {
.init = spacemit_usb2phy_init,
.exit = spacemit_usb2phy_exit,
.disconnect = spacemit_usb2phy_disconnect,
.disconnect = spacemit_k1_usb2phy_disconnect,
.owner = THIS_MODULE,
};
static const struct phy_ops spacemit_k3_usb2phy_ops = {
.init = spacemit_usb2phy_init,
.exit = spacemit_usb2phy_exit,
.disconnect = spacemit_k3_usb2phy_disconnect,
.owner = THIS_MODULE,
};
@ -167,12 +187,15 @@ static int spacemit_usb2phy_probe(struct platform_device *pdev)
struct phy_provider *phy_provider;
struct device *dev = &pdev->dev;
struct spacemit_usb2phy *sphy;
const struct phy_ops *ops;
void __iomem *base;
sphy = devm_kzalloc(dev, sizeof(*sphy), GFP_KERNEL);
if (!sphy)
return -ENOMEM;
ops = device_get_match_data(dev);
sphy->clk = devm_clk_get_prepared(&pdev->dev, NULL);
if (IS_ERR(sphy->clk))
return dev_err_probe(dev, PTR_ERR(sphy->clk), "Failed to get clock\n");
@ -185,7 +208,7 @@ static int spacemit_usb2phy_probe(struct platform_device *pdev)
if (IS_ERR(sphy->regmap_base))
return dev_err_probe(dev, PTR_ERR(sphy->regmap_base), "Failed to init regmap\n");
sphy->phy = devm_phy_create(dev, NULL, &spacemit_usb2phy_ops);
sphy->phy = devm_phy_create(dev, NULL, ops);
if (IS_ERR(sphy->phy))
return dev_err_probe(dev, PTR_ERR(sphy->phy), "Failed to create phy\n");
@ -196,7 +219,8 @@ static int spacemit_usb2phy_probe(struct platform_device *pdev)
}
static const struct of_device_id spacemit_usb2phy_dt_match[] = {
{ .compatible = "spacemit,k1-usb2-phy", },
{ .compatible = "spacemit,k1-usb2-phy", .data = &spacemit_k1_usb2phy_ops },
{ .compatible = "spacemit,k3-usb2-phy", .data = &spacemit_k3_usb2phy_ops },
{ /* sentinel */ }
};
MODULE_DEVICE_TABLE(of, spacemit_usb2phy_dt_match);