1 // SPDX-License-Identifier: GPL-2.0
3 * Copyright (C) 2018 Marvell
6 * Igal Liberman <igall@marvell.com>
7 * Miquèl Raynal <miquel.raynal@bootlin.com>
9 * Marvell A3700 UTMI PHY driver
13 #include <linux/iopoll.h>
14 #include <linux/mfd/syscon.h>
15 #include <linux/module.h>
16 #include <linux/of_device.h>
17 #include <linux/phy/phy.h>
18 #include <linux/platform_device.h>
19 #include <linux/regmap.h>
21 /* Armada 3700 UTMI PHY registers */
22 #define USB2_PHY_PLL_CTRL_REG0 0x0
23 #define PLL_REF_DIV_OFF 0
24 #define PLL_REF_DIV_MASK GENMASK(6, 0)
25 #define PLL_REF_DIV_5 5
26 #define PLL_FB_DIV_OFF 16
27 #define PLL_FB_DIV_MASK GENMASK(24, 16)
28 #define PLL_FB_DIV_96 96
29 #define PLL_SEL_LPFR_OFF 28
30 #define PLL_SEL_LPFR_MASK GENMASK(29, 28)
31 #define PLL_READY BIT(31)
32 #define USB2_PHY_CAL_CTRL 0x8
33 #define PHY_PLLCAL_DONE BIT(31)
34 #define PHY_IMPCAL_DONE BIT(23)
35 #define USB2_RX_CHAN_CTRL1 0x18
36 #define USB2PHY_SQCAL_DONE BIT(31)
37 #define USB2_PHY_OTG_CTRL 0x34
38 #define PHY_PU_OTG BIT(4)
39 #define USB2_PHY_CHRGR_DETECT 0x38
40 #define PHY_CDP_EN BIT(2)
41 #define PHY_DCP_EN BIT(3)
42 #define PHY_PD_EN BIT(4)
43 #define PHY_PU_CHRG_DTC BIT(5)
44 #define PHY_CDP_DM_AUTO BIT(7)
45 #define PHY_ENSWITCH_DP BIT(12)
46 #define PHY_ENSWITCH_DM BIT(13)
48 /* Armada 3700 USB miscellaneous registers */
49 #define USB2_PHY_CTRL(usb32) (usb32 ? 0x20 : 0x4)
50 #define RB_USB2PHY_PU BIT(0)
51 #define USB2_DP_PULLDN_DEV_MODE BIT(5)
52 #define USB2_DM_PULLDN_DEV_MODE BIT(6)
53 #define RB_USB2PHY_SUSPM(usb32) (usb32 ? BIT(14) : BIT(7))
55 #define PLL_LOCK_DELAY_US 10000
56 #define PLL_LOCK_TIMEOUT_US 1000000
59 * struct mvebu_a3700_utmi_caps - PHY capabilities
61 * @usb32: Flag indicating which PHY is in use (impacts the register map):
62 * - The UTMI PHY wired to the USB3/USB2 controller (otg)
63 * - The UTMI PHY wired to the USB2 controller (host only)
64 * @ops: PHY operations
66 struct mvebu_a3700_utmi_caps
{
68 const struct phy_ops
*ops
;
72 * struct mvebu_a3700_utmi - PHY driver data
74 * @regs: PHY registers
75 * @usb_misc: Regmap with USB miscellaneous registers including PHY ones
76 * @caps: PHY capabilities
79 struct mvebu_a3700_utmi
{
81 struct regmap
*usb_misc
;
82 const struct mvebu_a3700_utmi_caps
*caps
;
86 static int mvebu_a3700_utmi_phy_power_on(struct phy
*phy
)
88 struct mvebu_a3700_utmi
*utmi
= phy_get_drvdata(phy
);
89 struct device
*dev
= &phy
->dev
;
90 int usb32
= utmi
->caps
->usb32
;
95 * Setup PLL. 40MHz clock used to be the default, being 25MHz now.
96 * See "PLL Settings for Typical REFCLK" table.
98 reg
= readl(utmi
->regs
+ USB2_PHY_PLL_CTRL_REG0
);
99 reg
&= ~(PLL_REF_DIV_MASK
| PLL_FB_DIV_MASK
| PLL_SEL_LPFR_MASK
);
100 reg
|= (PLL_REF_DIV_5
<< PLL_REF_DIV_OFF
) |
101 (PLL_FB_DIV_96
<< PLL_FB_DIV_OFF
);
102 writel(reg
, utmi
->regs
+ USB2_PHY_PLL_CTRL_REG0
);
104 /* Enable PHY pull up and disable USB2 suspend */
105 regmap_update_bits(utmi
->usb_misc
, USB2_PHY_CTRL(usb32
),
106 RB_USB2PHY_SUSPM(usb32
) | RB_USB2PHY_PU
,
107 RB_USB2PHY_SUSPM(usb32
) | RB_USB2PHY_PU
);
110 /* Power up OTG module */
111 reg
= readl(utmi
->regs
+ USB2_PHY_OTG_CTRL
);
113 writel(reg
, utmi
->regs
+ USB2_PHY_OTG_CTRL
);
115 /* Disable PHY charger detection */
116 reg
= readl(utmi
->regs
+ USB2_PHY_CHRGR_DETECT
);
117 reg
&= ~(PHY_CDP_EN
| PHY_DCP_EN
| PHY_PD_EN
| PHY_PU_CHRG_DTC
|
118 PHY_CDP_DM_AUTO
| PHY_ENSWITCH_DP
| PHY_ENSWITCH_DM
);
119 writel(reg
, utmi
->regs
+ USB2_PHY_CHRGR_DETECT
);
121 /* Disable PHY DP/DM pull-down (used for device mode) */
122 regmap_update_bits(utmi
->usb_misc
, USB2_PHY_CTRL(usb32
),
123 USB2_DP_PULLDN_DEV_MODE
|
124 USB2_DM_PULLDN_DEV_MODE
, 0);
127 /* Wait for PLL calibration */
128 ret
= readl_poll_timeout(utmi
->regs
+ USB2_PHY_CAL_CTRL
, reg
,
129 reg
& PHY_PLLCAL_DONE
,
130 PLL_LOCK_DELAY_US
, PLL_LOCK_TIMEOUT_US
);
132 dev_err(dev
, "Failed to end USB2 PLL calibration\n");
136 /* Wait for impedance calibration */
137 ret
= readl_poll_timeout(utmi
->regs
+ USB2_PHY_CAL_CTRL
, reg
,
138 reg
& PHY_IMPCAL_DONE
,
139 PLL_LOCK_DELAY_US
, PLL_LOCK_TIMEOUT_US
);
141 dev_err(dev
, "Failed to end USB2 impedance calibration\n");
145 /* Wait for squelch calibration */
146 ret
= readl_poll_timeout(utmi
->regs
+ USB2_RX_CHAN_CTRL1
, reg
,
147 reg
& USB2PHY_SQCAL_DONE
,
148 PLL_LOCK_DELAY_US
, PLL_LOCK_TIMEOUT_US
);
150 dev_err(dev
, "Failed to end USB2 unknown calibration\n");
154 /* Wait for PLL to be locked */
155 ret
= readl_poll_timeout(utmi
->regs
+ USB2_PHY_PLL_CTRL_REG0
, reg
,
157 PLL_LOCK_DELAY_US
, PLL_LOCK_TIMEOUT_US
);
159 dev_err(dev
, "Failed to lock USB2 PLL\n");
164 static int mvebu_a3700_utmi_phy_power_off(struct phy
*phy
)
166 struct mvebu_a3700_utmi
*utmi
= phy_get_drvdata(phy
);
167 int usb32
= utmi
->caps
->usb32
;
170 /* Disable PHY pull-up and enable USB2 suspend */
171 reg
= readl(utmi
->regs
+ USB2_PHY_CTRL(usb32
));
172 reg
&= ~(RB_USB2PHY_PU
| RB_USB2PHY_SUSPM(usb32
));
173 writel(reg
, utmi
->regs
+ USB2_PHY_CTRL(usb32
));
175 /* Power down OTG module */
177 reg
= readl(utmi
->regs
+ USB2_PHY_OTG_CTRL
);
179 writel(reg
, utmi
->regs
+ USB2_PHY_OTG_CTRL
);
185 static const struct phy_ops mvebu_a3700_utmi_phy_ops
= {
186 .power_on
= mvebu_a3700_utmi_phy_power_on
,
187 .power_off
= mvebu_a3700_utmi_phy_power_off
,
188 .owner
= THIS_MODULE
,
191 static const struct mvebu_a3700_utmi_caps mvebu_a3700_utmi_otg_phy_caps
= {
193 .ops
= &mvebu_a3700_utmi_phy_ops
,
196 static const struct mvebu_a3700_utmi_caps mvebu_a3700_utmi_host_phy_caps
= {
198 .ops
= &mvebu_a3700_utmi_phy_ops
,
201 static const struct of_device_id mvebu_a3700_utmi_of_match
[] = {
203 .compatible
= "marvell,a3700-utmi-otg-phy",
204 .data
= &mvebu_a3700_utmi_otg_phy_caps
,
207 .compatible
= "marvell,a3700-utmi-host-phy",
208 .data
= &mvebu_a3700_utmi_host_phy_caps
,
212 MODULE_DEVICE_TABLE(of
, mvebu_a3700_utmi_of_match
);
214 static int mvebu_a3700_utmi_phy_probe(struct platform_device
*pdev
)
216 struct device
*dev
= &pdev
->dev
;
217 struct mvebu_a3700_utmi
*utmi
;
218 struct phy_provider
*provider
;
220 utmi
= devm_kzalloc(dev
, sizeof(*utmi
), GFP_KERNEL
);
224 /* Get UTMI memory region */
225 utmi
->regs
= devm_platform_ioremap_resource(pdev
, 0);
226 if (IS_ERR(utmi
->regs
))
227 return PTR_ERR(utmi
->regs
);
229 /* Get miscellaneous Host/PHY region */
230 utmi
->usb_misc
= syscon_regmap_lookup_by_phandle(dev
->of_node
,
231 "marvell,usb-misc-reg");
232 if (IS_ERR(utmi
->usb_misc
)) {
234 "Missing USB misc purpose system controller\n");
235 return PTR_ERR(utmi
->usb_misc
);
238 /* Retrieve PHY capabilities */
239 utmi
->caps
= of_device_get_match_data(dev
);
241 /* Instantiate the PHY */
242 utmi
->phy
= devm_phy_create(dev
, NULL
, utmi
->caps
->ops
);
243 if (IS_ERR(utmi
->phy
)) {
244 dev_err(dev
, "Failed to create the UTMI PHY\n");
245 return PTR_ERR(utmi
->phy
);
248 phy_set_drvdata(utmi
->phy
, utmi
);
250 /* Ensure the PHY is powered off */
251 utmi
->caps
->ops
->power_off(utmi
->phy
);
253 provider
= devm_of_phy_provider_register(dev
, of_phy_simple_xlate
);
255 return PTR_ERR_OR_ZERO(provider
);
258 static struct platform_driver mvebu_a3700_utmi_driver
= {
259 .probe
= mvebu_a3700_utmi_phy_probe
,
261 .name
= "mvebu-a3700-utmi-phy",
262 .of_match_table
= mvebu_a3700_utmi_of_match
,
265 module_platform_driver(mvebu_a3700_utmi_driver
);
267 MODULE_AUTHOR("Igal Liberman <igall@marvell.com>");
268 MODULE_AUTHOR("Miquel Raynal <miquel.raynal@bootlin.com>");
269 MODULE_DESCRIPTION("Marvell EBU A3700 UTMI PHY driver");
270 MODULE_LICENSE("GPL v2");