1 // SPDX-License-Identifier: GPL-2.0
3 * Copyright (C) 2016-2018 Broadcom
6 #include <linux/delay.h>
8 #include <linux/module.h>
10 #include <linux/phy/phy.h>
11 #include <linux/platform_device.h>
13 enum bcm_usb_phy_version
{
18 enum bcm_usb_phy_reg
{
26 /* USB PHY registers */
28 static const u8 bcm_usb_combo_phy_ss
[] = {
33 static const u8 bcm_usb_combo_phy_hs
[] = {
34 [PLL_NDIV_FRAC
] = 0x04,
35 [PLL_NDIV_INT
] = 0x08,
40 #define HSPLL_NDIV_INT_VAL 0x13
41 #define HSPLL_NDIV_FRAC_VAL 0x1005
43 static const u8 bcm_usb_hs_phy
[] = {
44 [PLL_NDIV_FRAC
] = 0x0,
58 static const u8 u3pll_ctrl
[] = {
60 [SSPLL_SUSPEND_EN
] = 1,
65 #define HSPLL_PDIV_MASK 0xF
66 #define HSPLL_PDIV_VAL 0x1
68 static const u8 u2pll_ctrl
[] = {
74 enum bcm_usb_phy_ctrl_bits
{
84 #define PHY_PCTL_MASK 0xffff
86 * 0x0806 of PCTL_VAL has below bits set
87 * BIT-8 : refclk divider 1
88 * BIT-3:2: device mode; mode is not effect
89 * BIT-1: soft reset active low
91 #define HSPHY_PCTL_VAL 0x0806
92 #define SSPHY_PCTL_VAL 0x0006
94 static const u8 u3phy_ctrl
[] = {
99 static const u8 u2phy_ctrl
[] = {
101 [AFE_LDO_PWRDWNB
] = 1,
102 [AFE_PLL_PWRDWNB
] = 2,
103 [AFE_BG_PWRDWNB
] = 3,
109 struct bcm_usb_phy_cfg
{
117 #define PLL_LOCK_RETRY_COUNT 1000
119 enum bcm_usb_phy_type
{
124 #define NUM_BCM_SR_USB_COMBO_PHYS 2
126 static inline void bcm_usb_reg32_clrbits(void __iomem
*addr
, uint32_t clear
)
128 writel(readl(addr
) & ~clear
, addr
);
131 static inline void bcm_usb_reg32_setbits(void __iomem
*addr
, uint32_t set
)
133 writel(readl(addr
) | set
, addr
);
136 static int bcm_usb_pll_lock_check(void __iomem
*addr
, u32 bit
)
141 retry
= PLL_LOCK_RETRY_COUNT
;
143 rd_data
= readl(addr
);
147 } while (--retry
> 0);
149 pr_err("%s: FAIL\n", __func__
);
153 static int bcm_usb_ss_phy_init(struct bcm_usb_phy_cfg
*phy_cfg
)
156 void __iomem
*regs
= phy_cfg
->regs
;
160 offset
= phy_cfg
->offset
;
162 /* Set pctl with mode and soft reset */
163 rd_data
= readl(regs
+ offset
[PHY_CTRL
]);
164 rd_data
&= ~(PHY_PCTL_MASK
<< u3phy_ctrl
[PHY_PCTL
]);
165 rd_data
|= (SSPHY_PCTL_VAL
<< u3phy_ctrl
[PHY_PCTL
]);
166 writel(rd_data
, regs
+ offset
[PHY_CTRL
]);
168 bcm_usb_reg32_clrbits(regs
+ offset
[PLL_CTRL
],
169 BIT(u3pll_ctrl
[SSPLL_SUSPEND_EN
]));
170 bcm_usb_reg32_setbits(regs
+ offset
[PLL_CTRL
],
171 BIT(u3pll_ctrl
[PLL_SEQ_START
]));
172 bcm_usb_reg32_setbits(regs
+ offset
[PLL_CTRL
],
173 BIT(u3pll_ctrl
[PLL_RESETB
]));
175 /* Maximum timeout for PLL reset done */
178 ret
= bcm_usb_pll_lock_check(regs
+ offset
[PLL_CTRL
],
179 BIT(u3pll_ctrl
[PLL_LOCK
]));
184 static int bcm_usb_hs_phy_init(struct bcm_usb_phy_cfg
*phy_cfg
)
187 void __iomem
*regs
= phy_cfg
->regs
;
191 offset
= phy_cfg
->offset
;
193 writel(HSPLL_NDIV_INT_VAL
, regs
+ offset
[PLL_NDIV_INT
]);
194 writel(HSPLL_NDIV_FRAC_VAL
, regs
+ offset
[PLL_NDIV_FRAC
]);
196 rd_data
= readl(regs
+ offset
[PLL_CTRL
]);
197 rd_data
&= ~(HSPLL_PDIV_MASK
<< u2pll_ctrl
[PLL_PDIV
]);
198 rd_data
|= (HSPLL_PDIV_VAL
<< u2pll_ctrl
[PLL_PDIV
]);
199 writel(rd_data
, regs
+ offset
[PLL_CTRL
]);
201 /* Set Core Ready high */
202 bcm_usb_reg32_setbits(regs
+ offset
[PHY_CTRL
],
203 BIT(u2phy_ctrl
[CORERDY
]));
205 /* Maximum timeout for Core Ready done */
208 bcm_usb_reg32_setbits(regs
+ offset
[PLL_CTRL
],
209 BIT(u2pll_ctrl
[PLL_RESETB
]));
210 bcm_usb_reg32_setbits(regs
+ offset
[PHY_CTRL
],
211 BIT(u2phy_ctrl
[PHY_RESETB
]));
214 rd_data
= readl(regs
+ offset
[PHY_CTRL
]);
215 rd_data
&= ~(PHY_PCTL_MASK
<< u2phy_ctrl
[PHY_PCTL
]);
216 rd_data
|= (HSPHY_PCTL_VAL
<< u2phy_ctrl
[PHY_PCTL
]);
217 writel(rd_data
, regs
+ offset
[PHY_CTRL
]);
219 /* Maximum timeout for PLL reset done */
222 ret
= bcm_usb_pll_lock_check(regs
+ offset
[PLL_CTRL
],
223 BIT(u2pll_ctrl
[PLL_LOCK
]));
228 static int bcm_usb_phy_reset(struct phy
*phy
)
230 struct bcm_usb_phy_cfg
*phy_cfg
= phy_get_drvdata(phy
);
231 void __iomem
*regs
= phy_cfg
->regs
;
234 offset
= phy_cfg
->offset
;
236 if (phy_cfg
->type
== USB_HS_PHY
) {
237 bcm_usb_reg32_clrbits(regs
+ offset
[PHY_CTRL
],
238 BIT(u2phy_ctrl
[CORERDY
]));
239 bcm_usb_reg32_setbits(regs
+ offset
[PHY_CTRL
],
240 BIT(u2phy_ctrl
[CORERDY
]));
246 static int bcm_usb_phy_init(struct phy
*phy
)
248 struct bcm_usb_phy_cfg
*phy_cfg
= phy_get_drvdata(phy
);
251 if (phy_cfg
->type
== USB_SS_PHY
)
252 ret
= bcm_usb_ss_phy_init(phy_cfg
);
253 else if (phy_cfg
->type
== USB_HS_PHY
)
254 ret
= bcm_usb_hs_phy_init(phy_cfg
);
259 static struct phy_ops sr_phy_ops
= {
260 .init
= bcm_usb_phy_init
,
261 .reset
= bcm_usb_phy_reset
,
262 .owner
= THIS_MODULE
,
265 static struct phy
*bcm_usb_phy_xlate(struct device
*dev
,
266 struct of_phandle_args
*args
)
268 struct bcm_usb_phy_cfg
*phy_cfg
;
271 phy_cfg
= dev_get_drvdata(dev
);
273 return ERR_PTR(-EINVAL
);
275 if (phy_cfg
->version
== BCM_SR_USB_COMBO_PHY
) {
276 phy_idx
= args
->args
[0];
278 if (WARN_ON(phy_idx
> 1))
279 return ERR_PTR(-ENODEV
);
281 return phy_cfg
[phy_idx
].phy
;
286 static int bcm_usb_phy_create(struct device
*dev
, struct device_node
*node
,
287 void __iomem
*regs
, uint32_t version
)
289 struct bcm_usb_phy_cfg
*phy_cfg
;
292 if (version
== BCM_SR_USB_COMBO_PHY
) {
293 phy_cfg
= devm_kzalloc(dev
, NUM_BCM_SR_USB_COMBO_PHYS
*
294 sizeof(struct bcm_usb_phy_cfg
),
299 for (idx
= 0; idx
< NUM_BCM_SR_USB_COMBO_PHYS
; idx
++) {
300 phy_cfg
[idx
].regs
= regs
;
301 phy_cfg
[idx
].version
= version
;
303 phy_cfg
[idx
].offset
= bcm_usb_combo_phy_hs
;
304 phy_cfg
[idx
].type
= USB_HS_PHY
;
306 phy_cfg
[idx
].offset
= bcm_usb_combo_phy_ss
;
307 phy_cfg
[idx
].type
= USB_SS_PHY
;
309 phy_cfg
[idx
].phy
= devm_phy_create(dev
, node
,
311 if (IS_ERR(phy_cfg
[idx
].phy
))
312 return PTR_ERR(phy_cfg
[idx
].phy
);
314 phy_set_drvdata(phy_cfg
[idx
].phy
, &phy_cfg
[idx
]);
316 } else if (version
== BCM_SR_USB_HS_PHY
) {
317 phy_cfg
= devm_kzalloc(dev
, sizeof(struct bcm_usb_phy_cfg
),
322 phy_cfg
->regs
= regs
;
323 phy_cfg
->version
= version
;
324 phy_cfg
->offset
= bcm_usb_hs_phy
;
325 phy_cfg
->type
= USB_HS_PHY
;
326 phy_cfg
->phy
= devm_phy_create(dev
, node
, &sr_phy_ops
);
327 if (IS_ERR(phy_cfg
->phy
))
328 return PTR_ERR(phy_cfg
->phy
);
330 phy_set_drvdata(phy_cfg
->phy
, phy_cfg
);
334 dev_set_drvdata(dev
, phy_cfg
);
339 static const struct of_device_id bcm_usb_phy_of_match
[] = {
341 .compatible
= "brcm,sr-usb-combo-phy",
342 .data
= (void *)BCM_SR_USB_COMBO_PHY
,
345 .compatible
= "brcm,sr-usb-hs-phy",
346 .data
= (void *)BCM_SR_USB_HS_PHY
,
350 MODULE_DEVICE_TABLE(of
, bcm_usb_phy_of_match
);
352 static int bcm_usb_phy_probe(struct platform_device
*pdev
)
354 struct device
*dev
= &pdev
->dev
;
355 struct device_node
*dn
= dev
->of_node
;
356 const struct of_device_id
*of_id
;
357 struct resource
*res
;
360 enum bcm_usb_phy_version version
;
361 struct phy_provider
*phy_provider
;
363 res
= platform_get_resource(pdev
, IORESOURCE_MEM
, 0);
364 regs
= devm_ioremap_resource(dev
, res
);
366 return PTR_ERR(regs
);
368 of_id
= of_match_node(bcm_usb_phy_of_match
, dn
);
370 version
= (enum bcm_usb_phy_version
)of_id
->data
;
374 ret
= bcm_usb_phy_create(dev
, dn
, regs
, version
);
378 phy_provider
= devm_of_phy_provider_register(dev
, bcm_usb_phy_xlate
);
380 return PTR_ERR_OR_ZERO(phy_provider
);
383 static struct platform_driver bcm_usb_phy_driver
= {
385 .name
= "phy-bcm-sr-usb",
386 .of_match_table
= bcm_usb_phy_of_match
,
388 .probe
= bcm_usb_phy_probe
,
390 module_platform_driver(bcm_usb_phy_driver
);
392 MODULE_AUTHOR("Broadcom");
393 MODULE_DESCRIPTION("Broadcom stingray USB Phy driver");
394 MODULE_LICENSE("GPL v2");