1 // SPDX-License-Identifier: GPL-2.0-or-later
3 * BCM6328 USBH PHY Controller Driver
5 * Copyright (C) 2020 Álvaro Fernández Rojas <noltari@gmail.com>
6 * Copyright (C) 2015 Simon Arlott
8 * Derived from bcm963xx_4.12L.06B_consumer/kernel/linux/arch/mips/bcm963xx/setup.c:
9 * Copyright (C) 2002 Broadcom Corporation
11 * Derived from OpenWrt patches:
12 * Copyright (C) 2013 Jonas Gorski <jonas.gorski@gmail.com>
13 * Copyright (C) 2013 Florian Fainelli <f.fainelli@gmail.com>
14 * Copyright (C) 2008 Maxime Bizon <mbizon@freebox.fr>
17 #include <linux/clk.h>
19 #include <linux/module.h>
21 #include <linux/phy/phy.h>
22 #include <linux/platform_device.h>
23 #include <linux/reset.h>
25 /* USBH control register offsets */
27 USBH_BRT_CONTROL1
= 0,
32 #define USBH_UC1_DEV_MODE_SEL BIT(0)
33 USBH_TEST_PORT_CONTROL
,
35 #define USBH_PLLC_REFCLKSEL_SHIFT 0
36 #define USBH_PLLC_REFCLKSEL_MASK (0x3 << USBH_PLLC_REFCLKSEL_SHIFT)
37 #define USBH_PLLC_CLKSEL_SHIFT 2
38 #define USBH_PLLC_CLKSEL_MASK (0x3 << USBH_PLLC_CLKSEL_MASK)
39 #define USBH_PLLC_XTAL_PWRDWNB BIT(4)
40 #define USBH_PLLC_PLL_PWRDWNB BIT(5)
41 #define USBH_PLLC_PLL_CALEN BIT(6)
42 #define USBH_PLLC_PHYPLL_BYP BIT(7)
43 #define USBH_PLLC_PLL_RESET BIT(8)
44 #define USBH_PLLC_PLL_IDDQ_PWRDN BIT(9)
45 #define USBH_PLLC_PLL_PWRDN_DELAY BIT(10)
46 #define USBH_6318_PLLC_PLL_SUSPEND_EN BIT(27)
47 #define USBH_6318_PLLC_PHYPLL_BYP BIT(29)
48 #define USBH_6318_PLLC_PLL_RESET BIT(30)
49 #define USBH_6318_PLLC_PLL_IDDQ_PWRDN BIT(31)
51 #define USBH_SC_OHCI_DATA_SWAP BIT(0)
52 #define USBH_SC_OHCI_ENDIAN_SWAP BIT(1)
53 #define USBH_SC_OHCI_LOGICAL_ADDR_EN BIT(2)
54 #define USBH_SC_EHCI_DATA_SWAP BIT(3)
55 #define USBH_SC_EHCI_ENDIAN_SWAP BIT(4)
56 #define USBH_SC_EHCI_LOGICAL_ADDR_EN BIT(5)
57 #define USBH_SC_USB_DEVICE_SEL BIT(6)
59 #define USBH_GC_PLL_SUSPEND_EN BIT(1)
60 USBH_FRAME_ADJUST_VALUE
,
62 #define USBH_S_IOC BIT(4)
63 #define USBH_S_IPP BIT(5)
67 #define USBH_USC_LADDR_SEL BIT(5)
72 struct bcm63xx_usbh_phy_variant
{
74 long regs
[__USBH_ENUM_SIZE
];
76 /* PLLC bits to set/clear for power on */
80 /* Setup bits to set/clear for power on */
84 /* Swap Control bits to set */
87 /* Test Port Control value to set if non-zero */
90 /* USB Sim Control bits to set */
93 /* UTMI Control 1 bits to set */
97 struct bcm63xx_usbh_phy
{
100 struct clk
*usb_ref_clk
;
101 struct reset_control
*reset
;
102 const struct bcm63xx_usbh_phy_variant
*variant
;
106 static const struct bcm63xx_usbh_phy_variant usbh_bcm6318
= {
108 [USBH_BRT_CONTROL1
] = -1,
109 [USBH_BRT_CONTROL2
] = -1,
110 [USBH_BRT_STATUS1
] = -1,
111 [USBH_BRT_STATUS2
] = -1,
112 [USBH_UTMI_CONTROL1
] = 0x2c,
113 [USBH_TEST_PORT_CONTROL
] = 0x1c,
114 [USBH_PLL_CONTROL1
] = 0x04,
115 [USBH_SWAP_CONTROL
] = 0x0c,
116 [USBH_GENERIC_CONTROL
] = -1,
117 [USBH_FRAME_ADJUST_VALUE
] = 0x08,
120 [USBH_MDIO32
] = 0x18,
121 [USBH_USB_SIM_CONTROL
] = 0x20,
123 .power_pllc_clr
= USBH_6318_PLLC_PLL_IDDQ_PWRDN
,
124 .power_pllc_set
= USBH_6318_PLLC_PLL_SUSPEND_EN
,
125 .setup_set
= USBH_S_IOC
,
126 .swapctl_dev_set
= USBH_SC_USB_DEVICE_SEL
,
127 .usc_set
= USBH_USC_LADDR_SEL
,
128 .utmictl1_dev_set
= USBH_UC1_DEV_MODE_SEL
,
131 static const struct bcm63xx_usbh_phy_variant usbh_bcm6328
= {
133 [USBH_BRT_CONTROL1
] = 0x00,
134 [USBH_BRT_CONTROL2
] = 0x04,
135 [USBH_BRT_STATUS1
] = 0x08,
136 [USBH_BRT_STATUS2
] = 0x0c,
137 [USBH_UTMI_CONTROL1
] = 0x10,
138 [USBH_TEST_PORT_CONTROL
] = 0x14,
139 [USBH_PLL_CONTROL1
] = 0x18,
140 [USBH_SWAP_CONTROL
] = 0x1c,
141 [USBH_GENERIC_CONTROL
] = 0x20,
142 [USBH_FRAME_ADJUST_VALUE
] = 0x24,
145 [USBH_MDIO32
] = 0x30,
146 [USBH_USB_SIM_CONTROL
] = 0x34,
148 .setup_set
= USBH_S_IOC
,
149 .swapctl_dev_set
= USBH_SC_USB_DEVICE_SEL
,
150 .utmictl1_dev_set
= USBH_UC1_DEV_MODE_SEL
,
153 static const struct bcm63xx_usbh_phy_variant usbh_bcm6358
= {
155 [USBH_BRT_CONTROL1
] = -1,
156 [USBH_BRT_CONTROL2
] = -1,
157 [USBH_BRT_STATUS1
] = -1,
158 [USBH_BRT_STATUS2
] = -1,
159 [USBH_UTMI_CONTROL1
] = -1,
160 [USBH_TEST_PORT_CONTROL
] = 0x24,
161 [USBH_PLL_CONTROL1
] = -1,
162 [USBH_SWAP_CONTROL
] = 0x00,
163 [USBH_GENERIC_CONTROL
] = -1,
164 [USBH_FRAME_ADJUST_VALUE
] = -1,
168 [USBH_USB_SIM_CONTROL
] = -1,
171 * The magic value comes for the original vendor BSP
172 * and is needed for USB to work. Datasheet does not
173 * help, so the magic value is used as-is.
178 static const struct bcm63xx_usbh_phy_variant usbh_bcm6368
= {
180 [USBH_BRT_CONTROL1
] = 0x00,
181 [USBH_BRT_CONTROL2
] = 0x04,
182 [USBH_BRT_STATUS1
] = 0x08,
183 [USBH_BRT_STATUS2
] = 0x0c,
184 [USBH_UTMI_CONTROL1
] = 0x10,
185 [USBH_TEST_PORT_CONTROL
] = 0x14,
186 [USBH_PLL_CONTROL1
] = 0x18,
187 [USBH_SWAP_CONTROL
] = 0x1c,
188 [USBH_GENERIC_CONTROL
] = -1,
189 [USBH_FRAME_ADJUST_VALUE
] = 0x24,
192 [USBH_MDIO32
] = 0x30,
193 [USBH_USB_SIM_CONTROL
] = 0x34,
195 .power_pllc_clr
= USBH_PLLC_PLL_IDDQ_PWRDN
| USBH_PLLC_PLL_PWRDN_DELAY
,
196 .setup_set
= USBH_S_IOC
,
197 .swapctl_dev_set
= USBH_SC_USB_DEVICE_SEL
,
198 .utmictl1_dev_set
= USBH_UC1_DEV_MODE_SEL
,
201 static const struct bcm63xx_usbh_phy_variant usbh_bcm63268
= {
203 [USBH_BRT_CONTROL1
] = 0x00,
204 [USBH_BRT_CONTROL2
] = 0x04,
205 [USBH_BRT_STATUS1
] = 0x08,
206 [USBH_BRT_STATUS2
] = 0x0c,
207 [USBH_UTMI_CONTROL1
] = 0x10,
208 [USBH_TEST_PORT_CONTROL
] = 0x14,
209 [USBH_PLL_CONTROL1
] = 0x18,
210 [USBH_SWAP_CONTROL
] = 0x1c,
211 [USBH_GENERIC_CONTROL
] = 0x20,
212 [USBH_FRAME_ADJUST_VALUE
] = 0x24,
215 [USBH_MDIO32
] = 0x30,
216 [USBH_USB_SIM_CONTROL
] = 0x34,
218 .power_pllc_clr
= USBH_PLLC_PLL_IDDQ_PWRDN
| USBH_PLLC_PLL_PWRDN_DELAY
,
219 .setup_clr
= USBH_S_IPP
,
220 .setup_set
= USBH_S_IOC
,
221 .swapctl_dev_set
= USBH_SC_USB_DEVICE_SEL
,
222 .utmictl1_dev_set
= USBH_UC1_DEV_MODE_SEL
,
225 static inline bool usbh_has_reg(struct bcm63xx_usbh_phy
*usbh
, int reg
)
227 return (usbh
->variant
->regs
[reg
] >= 0);
230 static inline u32
usbh_readl(struct bcm63xx_usbh_phy
*usbh
, int reg
)
232 return __raw_readl(usbh
->base
+ usbh
->variant
->regs
[reg
]);
235 static inline void usbh_writel(struct bcm63xx_usbh_phy
*usbh
, int reg
,
238 __raw_writel(value
, usbh
->base
+ usbh
->variant
->regs
[reg
]);
241 static int bcm63xx_usbh_phy_init(struct phy
*phy
)
243 struct bcm63xx_usbh_phy
*usbh
= phy_get_drvdata(phy
);
246 ret
= clk_prepare_enable(usbh
->usbh_clk
);
248 dev_err(&phy
->dev
, "unable to enable usbh clock: %d\n", ret
);
252 ret
= clk_prepare_enable(usbh
->usb_ref_clk
);
254 dev_err(&phy
->dev
, "unable to enable usb_ref clock: %d\n", ret
);
255 clk_disable_unprepare(usbh
->usbh_clk
);
259 ret
= reset_control_reset(usbh
->reset
);
261 dev_err(&phy
->dev
, "unable to reset device: %d\n", ret
);
262 clk_disable_unprepare(usbh
->usb_ref_clk
);
263 clk_disable_unprepare(usbh
->usbh_clk
);
267 /* Configure to work in native CPU endian */
268 if (usbh_has_reg(usbh
, USBH_SWAP_CONTROL
)) {
269 u32 val
= usbh_readl(usbh
, USBH_SWAP_CONTROL
);
271 val
|= USBH_SC_EHCI_DATA_SWAP
;
272 val
&= ~USBH_SC_EHCI_ENDIAN_SWAP
;
274 val
|= USBH_SC_OHCI_DATA_SWAP
;
275 val
&= ~USBH_SC_OHCI_ENDIAN_SWAP
;
277 if (usbh
->device_mode
&& usbh
->variant
->swapctl_dev_set
)
278 val
|= usbh
->variant
->swapctl_dev_set
;
280 usbh_writel(usbh
, USBH_SWAP_CONTROL
, val
);
283 if (usbh_has_reg(usbh
, USBH_SETUP
)) {
284 u32 val
= usbh_readl(usbh
, USBH_SETUP
);
286 val
|= usbh
->variant
->setup_set
;
287 val
&= ~usbh
->variant
->setup_clr
;
289 usbh_writel(usbh
, USBH_SETUP
, val
);
292 if (usbh_has_reg(usbh
, USBH_USB_SIM_CONTROL
)) {
293 u32 val
= usbh_readl(usbh
, USBH_USB_SIM_CONTROL
);
295 val
|= usbh
->variant
->usc_set
;
297 usbh_writel(usbh
, USBH_USB_SIM_CONTROL
, val
);
300 if (usbh
->variant
->tpc_val
&&
301 usbh_has_reg(usbh
, USBH_TEST_PORT_CONTROL
))
302 usbh_writel(usbh
, USBH_TEST_PORT_CONTROL
,
303 usbh
->variant
->tpc_val
);
305 if (usbh
->device_mode
&&
306 usbh_has_reg(usbh
, USBH_UTMI_CONTROL1
) &&
307 usbh
->variant
->utmictl1_dev_set
) {
308 u32 val
= usbh_readl(usbh
, USBH_UTMI_CONTROL1
);
310 val
|= usbh
->variant
->utmictl1_dev_set
;
312 usbh_writel(usbh
, USBH_UTMI_CONTROL1
, val
);
318 static int bcm63xx_usbh_phy_power_on(struct phy
*phy
)
320 struct bcm63xx_usbh_phy
*usbh
= phy_get_drvdata(phy
);
322 if (usbh_has_reg(usbh
, USBH_PLL_CONTROL1
)) {
323 u32 val
= usbh_readl(usbh
, USBH_PLL_CONTROL1
);
325 val
|= usbh
->variant
->power_pllc_set
;
326 val
&= ~usbh
->variant
->power_pllc_clr
;
328 usbh_writel(usbh
, USBH_PLL_CONTROL1
, val
);
334 static int bcm63xx_usbh_phy_power_off(struct phy
*phy
)
336 struct bcm63xx_usbh_phy
*usbh
= phy_get_drvdata(phy
);
338 if (usbh_has_reg(usbh
, USBH_PLL_CONTROL1
)) {
339 u32 val
= usbh_readl(usbh
, USBH_PLL_CONTROL1
);
341 val
&= ~usbh
->variant
->power_pllc_set
;
342 val
|= usbh
->variant
->power_pllc_clr
;
344 usbh_writel(usbh
, USBH_PLL_CONTROL1
, val
);
350 static int bcm63xx_usbh_phy_exit(struct phy
*phy
)
352 struct bcm63xx_usbh_phy
*usbh
= phy_get_drvdata(phy
);
354 clk_disable_unprepare(usbh
->usbh_clk
);
355 clk_disable_unprepare(usbh
->usb_ref_clk
);
360 static const struct phy_ops bcm63xx_usbh_phy_ops
= {
361 .exit
= bcm63xx_usbh_phy_exit
,
362 .init
= bcm63xx_usbh_phy_init
,
363 .power_off
= bcm63xx_usbh_phy_power_off
,
364 .power_on
= bcm63xx_usbh_phy_power_on
,
365 .owner
= THIS_MODULE
,
368 static struct phy
*bcm63xx_usbh_phy_xlate(struct device
*dev
,
369 const struct of_phandle_args
*args
)
371 struct bcm63xx_usbh_phy
*usbh
= dev_get_drvdata(dev
);
373 usbh
->device_mode
= !!args
->args
[0];
375 return of_phy_simple_xlate(dev
, args
);
378 static int __init
bcm63xx_usbh_phy_probe(struct platform_device
*pdev
)
380 struct device
*dev
= &pdev
->dev
;
381 struct bcm63xx_usbh_phy
*usbh
;
382 const struct bcm63xx_usbh_phy_variant
*variant
;
384 struct phy_provider
*phy_provider
;
386 usbh
= devm_kzalloc(dev
, sizeof(*usbh
), GFP_KERNEL
);
390 variant
= device_get_match_data(dev
);
393 usbh
->variant
= variant
;
395 usbh
->base
= devm_platform_ioremap_resource(pdev
, 0);
396 if (IS_ERR(usbh
->base
))
397 return PTR_ERR(usbh
->base
);
399 usbh
->reset
= devm_reset_control_get_exclusive(dev
, NULL
);
400 if (IS_ERR(usbh
->reset
)) {
401 if (PTR_ERR(usbh
->reset
) != -EPROBE_DEFER
)
402 dev_err(dev
, "failed to get reset\n");
403 return PTR_ERR(usbh
->reset
);
406 usbh
->usbh_clk
= devm_clk_get_optional(dev
, "usbh");
407 if (IS_ERR(usbh
->usbh_clk
))
408 return PTR_ERR(usbh
->usbh_clk
);
410 usbh
->usb_ref_clk
= devm_clk_get_optional(dev
, "usb_ref");
411 if (IS_ERR(usbh
->usb_ref_clk
))
412 return PTR_ERR(usbh
->usb_ref_clk
);
414 phy
= devm_phy_create(dev
, NULL
, &bcm63xx_usbh_phy_ops
);
416 dev_err(dev
, "failed to create PHY\n");
420 platform_set_drvdata(pdev
, usbh
);
421 phy_set_drvdata(phy
, usbh
);
423 phy_provider
= devm_of_phy_provider_register(dev
,
424 bcm63xx_usbh_phy_xlate
);
425 if (IS_ERR(phy_provider
)) {
426 dev_err(dev
, "failed to register PHY provider\n");
427 return PTR_ERR(phy_provider
);
430 dev_dbg(dev
, "Registered BCM63xx USB PHY driver\n");
435 static const struct of_device_id bcm63xx_usbh_phy_ids
[] __initconst
= {
436 { .compatible
= "brcm,bcm6318-usbh-phy", .data
= &usbh_bcm6318
},
437 { .compatible
= "brcm,bcm6328-usbh-phy", .data
= &usbh_bcm6328
},
438 { .compatible
= "brcm,bcm6358-usbh-phy", .data
= &usbh_bcm6358
},
439 { .compatible
= "brcm,bcm6362-usbh-phy", .data
= &usbh_bcm6368
},
440 { .compatible
= "brcm,bcm6368-usbh-phy", .data
= &usbh_bcm6368
},
441 { .compatible
= "brcm,bcm63268-usbh-phy", .data
= &usbh_bcm63268
},
444 MODULE_DEVICE_TABLE(of
, bcm63xx_usbh_phy_ids
);
446 static struct platform_driver bcm63xx_usbh_phy_driver __refdata
= {
448 .name
= "bcm63xx-usbh-phy",
449 .of_match_table
= bcm63xx_usbh_phy_ids
,
451 .probe
= bcm63xx_usbh_phy_probe
,
453 module_platform_driver(bcm63xx_usbh_phy_driver
);
455 MODULE_DESCRIPTION("BCM63xx USBH PHY driver");
456 MODULE_AUTHOR("Álvaro Fernández Rojas <noltari@gmail.com>");
457 MODULE_AUTHOR("Simon Arlott");
458 MODULE_LICENSE("GPL");