1 // SPDX-License-Identifier: GPL-2.0-only
2 // Copyright (C) 2017 Broadcom
4 #include <linux/delay.h>
5 #include <linux/extcon-provider.h>
6 #include <linux/gpio.h>
7 #include <linux/gpio/consumer.h>
8 #include <linux/init.h>
9 #include <linux/interrupt.h>
11 #include <linux/iopoll.h>
12 #include <linux/irq.h>
13 #include <linux/mfd/syscon.h>
14 #include <linux/module.h>
16 #include <linux/of_address.h>
17 #include <linux/phy/phy.h>
18 #include <linux/platform_device.h>
19 #include <linux/regmap.h>
20 #include <linux/slab.h>
21 #include <linux/workqueue.h>
23 #define ICFG_DRD_AFE 0x0
24 #define ICFG_MISC_STAT 0x18
25 #define ICFG_DRD_P0CTL 0x1C
26 #define ICFG_STRAP_CTRL 0x20
27 #define ICFG_FSM_CTRL 0x24
29 #define ICFG_DEV_BIT BIT(2)
30 #define IDM_RST_BIT BIT(0)
31 #define AFE_CORERDY_VDDC BIT(18)
32 #define PHY_PLL_RESETB BIT(15)
33 #define PHY_RESETB BIT(14)
34 #define PHY_PLL_LOCK BIT(0)
36 #define DRD_DEV_MODE BIT(20)
37 #define OHCI_OVRCUR_POL BIT(11)
38 #define ICFG_OFF_MODE BIT(6)
39 #define PLL_LOCK_RETRY 1000
44 #define DRD_HOST_MODE (BIT(2) | BIT(3))
45 #define DRD_DEVICE_MODE (BIT(4) | BIT(5))
46 #define DRD_HOST_VAL 0x803
47 #define DRD_DEV_VAL 0x807
51 struct ns2_phy_driver
{
52 void __iomem
*icfgdrd_regs
;
53 void __iomem
*idmdrd_rst_ctrl
;
54 void __iomem
*crmu_usb2_ctrl
;
55 void __iomem
*usb2h_strap_reg
;
56 struct ns2_phy_data
*data
;
57 struct extcon_dev
*edev
;
58 struct gpio_desc
*vbus_gpiod
;
59 struct gpio_desc
*id_gpiod
;
62 unsigned long debounce_jiffies
;
63 struct delayed_work wq_extcon
;
67 struct ns2_phy_driver
*driver
;
72 static const unsigned int usb_extcon_cable
[] = {
78 static inline int pll_lock_stat(u32 usb_reg
, int reg_mask
,
79 struct ns2_phy_driver
*driver
)
83 return readl_poll_timeout_atomic(driver
->icfgdrd_regs
+ usb_reg
,
84 val
, (val
& reg_mask
), 1,
88 static int ns2_drd_phy_init(struct phy
*phy
)
90 struct ns2_phy_data
*data
= phy_get_drvdata(phy
);
91 struct ns2_phy_driver
*driver
= data
->driver
;
94 val
= readl(driver
->icfgdrd_regs
+ ICFG_FSM_CTRL
);
96 if (data
->new_state
== EVT_HOST
) {
97 val
&= ~DRD_DEVICE_MODE
;
100 val
&= ~DRD_HOST_MODE
;
101 val
|= DRD_DEVICE_MODE
;
103 writel(val
, driver
->icfgdrd_regs
+ ICFG_FSM_CTRL
);
108 static int ns2_drd_phy_poweroff(struct phy
*phy
)
110 struct ns2_phy_data
*data
= phy_get_drvdata(phy
);
111 struct ns2_phy_driver
*driver
= data
->driver
;
114 val
= readl(driver
->crmu_usb2_ctrl
);
115 val
&= ~AFE_CORERDY_VDDC
;
116 writel(val
, driver
->crmu_usb2_ctrl
);
118 val
= readl(driver
->crmu_usb2_ctrl
);
119 val
&= ~DRD_DEV_MODE
;
120 writel(val
, driver
->crmu_usb2_ctrl
);
122 /* Disable Host and Device Mode */
123 val
= readl(driver
->icfgdrd_regs
+ ICFG_FSM_CTRL
);
124 val
&= ~(DRD_HOST_MODE
| DRD_DEVICE_MODE
| ICFG_OFF_MODE
);
125 writel(val
, driver
->icfgdrd_regs
+ ICFG_FSM_CTRL
);
130 static int ns2_drd_phy_poweron(struct phy
*phy
)
132 struct ns2_phy_data
*data
= phy_get_drvdata(phy
);
133 struct ns2_phy_driver
*driver
= data
->driver
;
134 u32 extcon_event
= data
->new_state
;
138 if (extcon_event
== EVT_DEVICE
) {
139 writel(DRD_DEV_VAL
, driver
->icfgdrd_regs
+ ICFG_DRD_P0CTL
);
141 val
= readl(driver
->idmdrd_rst_ctrl
);
143 writel(val
, driver
->idmdrd_rst_ctrl
);
145 val
= readl(driver
->crmu_usb2_ctrl
);
146 val
|= (AFE_CORERDY_VDDC
| DRD_DEV_MODE
);
147 writel(val
, driver
->crmu_usb2_ctrl
);
149 /* Bring PHY and PHY_PLL out of Reset */
150 val
= readl(driver
->crmu_usb2_ctrl
);
151 val
|= (PHY_PLL_RESETB
| PHY_RESETB
);
152 writel(val
, driver
->crmu_usb2_ctrl
);
154 ret
= pll_lock_stat(ICFG_MISC_STAT
, PHY_PLL_LOCK
, driver
);
156 dev_err(&phy
->dev
, "Phy PLL lock failed\n");
160 writel(DRD_HOST_VAL
, driver
->icfgdrd_regs
+ ICFG_DRD_P0CTL
);
162 val
= readl(driver
->crmu_usb2_ctrl
);
163 val
|= AFE_CORERDY_VDDC
;
164 writel(val
, driver
->crmu_usb2_ctrl
);
166 ret
= pll_lock_stat(ICFG_MISC_STAT
, PHY_PLL_LOCK
, driver
);
168 dev_err(&phy
->dev
, "Phy PLL lock failed\n");
172 val
= readl(driver
->idmdrd_rst_ctrl
);
174 writel(val
, driver
->idmdrd_rst_ctrl
);
176 /* port over current Polarity */
177 val
= readl(driver
->usb2h_strap_reg
);
178 val
|= OHCI_OVRCUR_POL
;
179 writel(val
, driver
->usb2h_strap_reg
);
185 static void connect_change(struct ns2_phy_driver
*driver
)
190 extcon_event
= driver
->data
->new_state
;
191 val
= readl(driver
->icfgdrd_regs
+ ICFG_FSM_CTRL
);
193 switch (extcon_event
) {
195 val
&= ~(DRD_HOST_MODE
| DRD_DEVICE_MODE
);
196 writel(val
, driver
->icfgdrd_regs
+ ICFG_FSM_CTRL
);
198 val
= (val
& ~DRD_HOST_MODE
) | DRD_DEVICE_MODE
;
199 writel(val
, driver
->icfgdrd_regs
+ ICFG_FSM_CTRL
);
201 val
= readl(driver
->icfgdrd_regs
+ ICFG_DRD_P0CTL
);
203 writel(val
, driver
->icfgdrd_regs
+ ICFG_DRD_P0CTL
);
207 val
&= ~(DRD_HOST_MODE
| DRD_DEVICE_MODE
);
208 writel(val
, driver
->icfgdrd_regs
+ ICFG_FSM_CTRL
);
210 val
= (val
& ~DRD_DEVICE_MODE
) | DRD_HOST_MODE
;
211 writel(val
, driver
->icfgdrd_regs
+ ICFG_FSM_CTRL
);
213 val
= readl(driver
->usb2h_strap_reg
);
214 val
|= OHCI_OVRCUR_POL
;
215 writel(val
, driver
->usb2h_strap_reg
);
217 val
= readl(driver
->icfgdrd_regs
+ ICFG_DRD_P0CTL
);
218 val
&= ~ICFG_DEV_BIT
;
219 writel(val
, driver
->icfgdrd_regs
+ ICFG_DRD_P0CTL
);
223 pr_err("Invalid extcon event\n");
228 static void extcon_work(struct work_struct
*work
)
230 struct ns2_phy_driver
*driver
;
234 driver
= container_of(to_delayed_work(work
),
235 struct ns2_phy_driver
, wq_extcon
);
237 id
= gpiod_get_value_cansleep(driver
->id_gpiod
);
238 vbus
= gpiod_get_value_cansleep(driver
->vbus_gpiod
);
240 if (!id
&& vbus
) { /* Host connected */
241 extcon_set_state_sync(driver
->edev
, EXTCON_USB_HOST
, true);
242 pr_debug("Host cable connected\n");
243 driver
->data
->new_state
= EVT_HOST
;
244 connect_change(driver
);
245 } else if (id
&& !vbus
) { /* Disconnected */
246 extcon_set_state_sync(driver
->edev
, EXTCON_USB_HOST
, false);
247 extcon_set_state_sync(driver
->edev
, EXTCON_USB
, false);
248 pr_debug("Cable disconnected\n");
249 } else if (id
&& vbus
) { /* Device connected */
250 extcon_set_state_sync(driver
->edev
, EXTCON_USB
, true);
251 pr_debug("Device cable connected\n");
252 driver
->data
->new_state
= EVT_DEVICE
;
253 connect_change(driver
);
257 static irqreturn_t
gpio_irq_handler(int irq
, void *dev_id
)
259 struct ns2_phy_driver
*driver
= dev_id
;
261 queue_delayed_work(system_power_efficient_wq
, &driver
->wq_extcon
,
262 driver
->debounce_jiffies
);
267 static const struct phy_ops ops
= {
268 .init
= ns2_drd_phy_init
,
269 .power_on
= ns2_drd_phy_poweron
,
270 .power_off
= ns2_drd_phy_poweroff
,
271 .owner
= THIS_MODULE
,
274 static const struct of_device_id ns2_drd_phy_dt_ids
[] = {
275 { .compatible
= "brcm,ns2-drd-phy", },
278 MODULE_DEVICE_TABLE(of
, ns2_drd_phy_dt_ids
);
280 static int ns2_drd_phy_probe(struct platform_device
*pdev
)
282 struct phy_provider
*phy_provider
;
283 struct device
*dev
= &pdev
->dev
;
284 struct ns2_phy_driver
*driver
;
285 struct ns2_phy_data
*data
;
289 driver
= devm_kzalloc(dev
, sizeof(struct ns2_phy_driver
),
294 driver
->data
= devm_kzalloc(dev
, sizeof(struct ns2_phy_data
),
299 driver
->icfgdrd_regs
= devm_platform_ioremap_resource_byname(pdev
, "icfg");
300 if (IS_ERR(driver
->icfgdrd_regs
))
301 return PTR_ERR(driver
->icfgdrd_regs
);
303 driver
->idmdrd_rst_ctrl
= devm_platform_ioremap_resource_byname(pdev
, "rst-ctrl");
304 if (IS_ERR(driver
->idmdrd_rst_ctrl
))
305 return PTR_ERR(driver
->idmdrd_rst_ctrl
);
307 driver
->crmu_usb2_ctrl
= devm_platform_ioremap_resource_byname(pdev
, "crmu-ctrl");
308 if (IS_ERR(driver
->crmu_usb2_ctrl
))
309 return PTR_ERR(driver
->crmu_usb2_ctrl
);
311 driver
->usb2h_strap_reg
= devm_platform_ioremap_resource_byname(pdev
, "usb2-strap");
312 if (IS_ERR(driver
->usb2h_strap_reg
))
313 return PTR_ERR(driver
->usb2h_strap_reg
);
316 driver
->id_gpiod
= devm_gpiod_get(&pdev
->dev
, "id", GPIOD_IN
);
317 if (IS_ERR(driver
->id_gpiod
)) {
318 dev_err(dev
, "failed to get ID GPIO\n");
319 return PTR_ERR(driver
->id_gpiod
);
321 driver
->vbus_gpiod
= devm_gpiod_get(&pdev
->dev
, "vbus", GPIOD_IN
);
322 if (IS_ERR(driver
->vbus_gpiod
)) {
323 dev_err(dev
, "failed to get VBUS GPIO\n");
324 return PTR_ERR(driver
->vbus_gpiod
);
327 driver
->edev
= devm_extcon_dev_allocate(dev
, usb_extcon_cable
);
328 if (IS_ERR(driver
->edev
)) {
329 dev_err(dev
, "failed to allocate extcon device\n");
333 ret
= devm_extcon_dev_register(dev
, driver
->edev
);
335 dev_err(dev
, "failed to register extcon device\n");
339 ret
= gpiod_set_debounce(driver
->id_gpiod
, GPIO_DELAY
* 1000);
341 driver
->debounce_jiffies
= msecs_to_jiffies(GPIO_DELAY
);
343 INIT_DELAYED_WORK(&driver
->wq_extcon
, extcon_work
);
345 driver
->id_irq
= gpiod_to_irq(driver
->id_gpiod
);
346 if (driver
->id_irq
< 0) {
347 dev_err(dev
, "failed to get ID IRQ\n");
348 return driver
->id_irq
;
351 driver
->vbus_irq
= gpiod_to_irq(driver
->vbus_gpiod
);
352 if (driver
->vbus_irq
< 0) {
353 dev_err(dev
, "failed to get ID IRQ\n");
354 return driver
->vbus_irq
;
357 ret
= devm_request_irq(dev
, driver
->id_irq
, gpio_irq_handler
,
358 IRQF_TRIGGER_RISING
| IRQF_TRIGGER_FALLING
,
361 dev_err(dev
, "failed to request handler for ID IRQ\n");
365 ret
= devm_request_irq(dev
, driver
->vbus_irq
, gpio_irq_handler
,
366 IRQF_TRIGGER_RISING
| IRQF_TRIGGER_FALLING
,
369 dev_err(dev
, "failed to request handler for VBUS IRQ\n");
373 dev_set_drvdata(dev
, driver
);
375 /* Shutdown all ports. They can be powered up as required */
376 val
= readl(driver
->crmu_usb2_ctrl
);
377 val
&= ~(AFE_CORERDY_VDDC
| PHY_RESETB
);
378 writel(val
, driver
->crmu_usb2_ctrl
);
381 data
->phy
= devm_phy_create(dev
, dev
->of_node
, &ops
);
382 if (IS_ERR(data
->phy
)) {
383 dev_err(dev
, "Failed to create usb drd phy\n");
384 return PTR_ERR(data
->phy
);
387 data
->driver
= driver
;
388 phy_set_drvdata(data
->phy
, data
);
390 phy_provider
= devm_of_phy_provider_register(dev
, of_phy_simple_xlate
);
391 if (IS_ERR(phy_provider
)) {
392 dev_err(dev
, "Failed to register as phy provider\n");
393 return PTR_ERR(phy_provider
);
396 platform_set_drvdata(pdev
, driver
);
398 dev_info(dev
, "Registered NS2 DRD Phy device\n");
399 queue_delayed_work(system_power_efficient_wq
, &driver
->wq_extcon
,
400 driver
->debounce_jiffies
);
405 static struct platform_driver ns2_drd_phy_driver
= {
406 .probe
= ns2_drd_phy_probe
,
408 .name
= "bcm-ns2-usbphy",
409 .of_match_table
= of_match_ptr(ns2_drd_phy_dt_ids
),
412 module_platform_driver(ns2_drd_phy_driver
);
414 MODULE_ALIAS("platform:bcm-ns2-drd-phy");
415 MODULE_AUTHOR("Broadcom");
416 MODULE_DESCRIPTION("Broadcom NS2 USB2 PHY driver");
417 MODULE_LICENSE("GPL v2");