1 // SPDX-License-Identifier: GPL-2.0+
2 /* Copyright (c) 2017 NXP. */
6 #include <linux/module.h>
7 #include <linux/phy/phy.h>
8 #include <linux/platform_device.h>
9 #include <linux/regulator/consumer.h>
12 #define PHY_CTRL0_REF_SSP_EN BIT(2)
15 #define PHY_CTRL1_RESET BIT(0)
16 #define PHY_CTRL1_COMMONONN BIT(1)
17 #define PHY_CTRL1_ATERESET BIT(3)
18 #define PHY_CTRL1_VDATSRCENB0 BIT(19)
19 #define PHY_CTRL1_VDATDETENB0 BIT(20)
22 #define PHY_CTRL2_TXENABLEN0 BIT(8)
24 struct imx8mq_usb_phy
{
28 struct regulator
*vbus
;
31 static int imx8mq_usb_phy_init(struct phy
*phy
)
33 struct imx8mq_usb_phy
*imx_phy
= phy_get_drvdata(phy
);
36 value
= readl(imx_phy
->base
+ PHY_CTRL1
);
37 value
&= ~(PHY_CTRL1_VDATSRCENB0
| PHY_CTRL1_VDATDETENB0
|
39 value
|= PHY_CTRL1_RESET
| PHY_CTRL1_ATERESET
;
40 writel(value
, imx_phy
->base
+ PHY_CTRL1
);
42 value
= readl(imx_phy
->base
+ PHY_CTRL0
);
43 value
|= PHY_CTRL0_REF_SSP_EN
;
44 writel(value
, imx_phy
->base
+ PHY_CTRL0
);
46 value
= readl(imx_phy
->base
+ PHY_CTRL2
);
47 value
|= PHY_CTRL2_TXENABLEN0
;
48 writel(value
, imx_phy
->base
+ PHY_CTRL2
);
50 value
= readl(imx_phy
->base
+ PHY_CTRL1
);
51 value
&= ~(PHY_CTRL1_RESET
| PHY_CTRL1_ATERESET
);
52 writel(value
, imx_phy
->base
+ PHY_CTRL1
);
57 static int imx8mq_phy_power_on(struct phy
*phy
)
59 struct imx8mq_usb_phy
*imx_phy
= phy_get_drvdata(phy
);
62 ret
= regulator_enable(imx_phy
->vbus
);
66 return clk_prepare_enable(imx_phy
->clk
);
69 static int imx8mq_phy_power_off(struct phy
*phy
)
71 struct imx8mq_usb_phy
*imx_phy
= phy_get_drvdata(phy
);
73 clk_disable_unprepare(imx_phy
->clk
);
74 regulator_disable(imx_phy
->vbus
);
79 static struct phy_ops imx8mq_usb_phy_ops
= {
80 .init
= imx8mq_usb_phy_init
,
81 .power_on
= imx8mq_phy_power_on
,
82 .power_off
= imx8mq_phy_power_off
,
86 static int imx8mq_usb_phy_probe(struct platform_device
*pdev
)
88 struct phy_provider
*phy_provider
;
89 struct device
*dev
= &pdev
->dev
;
90 struct imx8mq_usb_phy
*imx_phy
;
93 imx_phy
= devm_kzalloc(dev
, sizeof(*imx_phy
), GFP_KERNEL
);
97 imx_phy
->clk
= devm_clk_get(dev
, "phy");
98 if (IS_ERR(imx_phy
->clk
)) {
99 dev_err(dev
, "failed to get imx8mq usb phy clock\n");
100 return PTR_ERR(imx_phy
->clk
);
103 res
= platform_get_resource(pdev
, IORESOURCE_MEM
, 0);
104 imx_phy
->base
= devm_ioremap_resource(dev
, res
);
105 if (IS_ERR(imx_phy
->base
))
106 return PTR_ERR(imx_phy
->base
);
108 imx_phy
->phy
= devm_phy_create(dev
, NULL
, &imx8mq_usb_phy_ops
);
109 if (IS_ERR(imx_phy
->phy
))
110 return PTR_ERR(imx_phy
->phy
);
112 imx_phy
->vbus
= devm_regulator_get(dev
, "vbus");
113 if (IS_ERR(imx_phy
->vbus
))
114 return PTR_ERR(imx_phy
->vbus
);
116 phy_set_drvdata(imx_phy
->phy
, imx_phy
);
118 phy_provider
= devm_of_phy_provider_register(dev
, of_phy_simple_xlate
);
120 return PTR_ERR_OR_ZERO(phy_provider
);
123 static const struct of_device_id imx8mq_usb_phy_of_match
[] = {
124 {.compatible
= "fsl,imx8mq-usb-phy",},
127 MODULE_DEVICE_TABLE(of
, imx8mq_usb_phy_of_match
);
129 static struct platform_driver imx8mq_usb_phy_driver
= {
130 .probe
= imx8mq_usb_phy_probe
,
132 .name
= "imx8mq-usb-phy",
133 .of_match_table
= imx8mq_usb_phy_of_match
,
136 module_platform_driver(imx8mq_usb_phy_driver
);
138 MODULE_DESCRIPTION("FSL IMX8MQ USB PHY driver");
139 MODULE_LICENSE("GPL");