diff options
author | Kishon Vijay Abraham I <kishon@ti.com> | 2013-07-07 20:54:43 -0400 |
---|---|---|
committer | Chanwoo Choi <cw00.choi@samsung.com> | 2013-08-04 19:53:33 -0400 |
commit | 8061ad7239f3f97b477984660e95134ca684578c (patch) | |
tree | 7e93e773509e957ad84a6fe7ada64e037503daa0 | |
parent | 6eee5b3b493824731ed34ade0299241f91f04096 (diff) |
usb: dwc3: use extcon fwrk to receive connect/disconnect
Modified dwc3-omap to receive connect and disconnect notification using
extcon framework. Also did the necessary cleanups required after
adapting to extcon framework.
Signed-off-by: Kishon Vijay Abraham I <kishon@ti.com>
Acked-by: Felipe Balbi <balbi@ti.com>
Signed-off-by: Chanwoo Choi <cw00.choi@samsung.com>
-rw-r--r-- | Documentation/devicetree/bindings/usb/omap-usb.txt | 5 | ||||
-rw-r--r-- | drivers/usb/dwc3/Kconfig | 1 | ||||
-rw-r--r-- | drivers/usb/dwc3/dwc3-omap.c | 125 | ||||
-rw-r--r-- | include/linux/usb/dwc3-omap.h | 30 |
4 files changed, 112 insertions, 49 deletions
diff --git a/Documentation/devicetree/bindings/usb/omap-usb.txt b/Documentation/devicetree/bindings/usb/omap-usb.txt index 57e71f6817d0..9088ab09e200 100644 --- a/Documentation/devicetree/bindings/usb/omap-usb.txt +++ b/Documentation/devicetree/bindings/usb/omap-usb.txt | |||
@@ -53,6 +53,11 @@ OMAP DWC3 GLUE | |||
53 | It should be set to "1" for HW mode and "2" for SW mode. | 53 | It should be set to "1" for HW mode and "2" for SW mode. |
54 | - ranges: the child address space are mapped 1:1 onto the parent address space | 54 | - ranges: the child address space are mapped 1:1 onto the parent address space |
55 | 55 | ||
56 | Optional Properties: | ||
57 | - extcon : phandle for the extcon device omap dwc3 uses to detect | ||
58 | connect/disconnect events. | ||
59 | - vbus-supply : phandle to the regulator device tree node if needed. | ||
60 | |||
56 | Sub-nodes: | 61 | Sub-nodes: |
57 | The dwc3 core should be added as subnode to omap dwc3 glue. | 62 | The dwc3 core should be added as subnode to omap dwc3 glue. |
58 | - dwc3 : | 63 | - dwc3 : |
diff --git a/drivers/usb/dwc3/Kconfig b/drivers/usb/dwc3/Kconfig index 2378958ea63e..4c855e598c84 100644 --- a/drivers/usb/dwc3/Kconfig +++ b/drivers/usb/dwc3/Kconfig | |||
@@ -1,6 +1,7 @@ | |||
1 | config USB_DWC3 | 1 | config USB_DWC3 |
2 | tristate "DesignWare USB3 DRD Core Support" | 2 | tristate "DesignWare USB3 DRD Core Support" |
3 | depends on (USB || USB_GADGET) && GENERIC_HARDIRQS && HAS_DMA | 3 | depends on (USB || USB_GADGET) && GENERIC_HARDIRQS && HAS_DMA |
4 | depends on EXTCON | ||
4 | select USB_XHCI_PLATFORM if USB_SUPPORT && USB_XHCI_HCD | 5 | select USB_XHCI_PLATFORM if USB_SUPPORT && USB_XHCI_HCD |
5 | help | 6 | help |
6 | Say Y or M here if your system has a Dual Role SuperSpeed | 7 | Say Y or M here if your system has a Dual Role SuperSpeed |
diff --git a/drivers/usb/dwc3/dwc3-omap.c b/drivers/usb/dwc3/dwc3-omap.c index 077f110bd746..b26c2a4b4fb5 100644 --- a/drivers/usb/dwc3/dwc3-omap.c +++ b/drivers/usb/dwc3/dwc3-omap.c | |||
@@ -43,13 +43,15 @@ | |||
43 | #include <linux/spinlock.h> | 43 | #include <linux/spinlock.h> |
44 | #include <linux/platform_device.h> | 44 | #include <linux/platform_device.h> |
45 | #include <linux/platform_data/dwc3-omap.h> | 45 | #include <linux/platform_data/dwc3-omap.h> |
46 | #include <linux/usb/dwc3-omap.h> | ||
47 | #include <linux/pm_runtime.h> | 46 | #include <linux/pm_runtime.h> |
48 | #include <linux/dma-mapping.h> | 47 | #include <linux/dma-mapping.h> |
49 | #include <linux/ioport.h> | 48 | #include <linux/ioport.h> |
50 | #include <linux/io.h> | 49 | #include <linux/io.h> |
51 | #include <linux/of.h> | 50 | #include <linux/of.h> |
52 | #include <linux/of_platform.h> | 51 | #include <linux/of_platform.h> |
52 | #include <linux/extcon.h> | ||
53 | #include <linux/extcon/of_extcon.h> | ||
54 | #include <linux/regulator/consumer.h> | ||
53 | 55 | ||
54 | #include <linux/usb/otg.h> | 56 | #include <linux/usb/otg.h> |
55 | 57 | ||
@@ -155,9 +157,21 @@ struct dwc3_omap { | |||
155 | u32 revision; | 157 | u32 revision; |
156 | 158 | ||
157 | u32 dma_status:1; | 159 | u32 dma_status:1; |
160 | |||
161 | struct extcon_specific_cable_nb extcon_vbus_dev; | ||
162 | struct extcon_specific_cable_nb extcon_id_dev; | ||
163 | struct notifier_block vbus_nb; | ||
164 | struct notifier_block id_nb; | ||
165 | |||
166 | struct regulator *vbus_reg; | ||
158 | }; | 167 | }; |
159 | 168 | ||
160 | static struct dwc3_omap *_omap; | 169 | enum omap_dwc3_vbus_id_status { |
170 | OMAP_DWC3_ID_FLOAT, | ||
171 | OMAP_DWC3_ID_GROUND, | ||
172 | OMAP_DWC3_VBUS_OFF, | ||
173 | OMAP_DWC3_VBUS_VALID, | ||
174 | }; | ||
161 | 175 | ||
162 | static inline u32 dwc3_omap_readl(void __iomem *base, u32 offset) | 176 | static inline u32 dwc3_omap_readl(void __iomem *base, u32 offset) |
163 | { | 177 | { |
@@ -221,18 +235,24 @@ static void dwc3_omap_write_irq0_set(struct dwc3_omap *omap, u32 value) | |||
221 | omap->irq0_offset, value); | 235 | omap->irq0_offset, value); |
222 | } | 236 | } |
223 | 237 | ||
224 | int dwc3_omap_mailbox(enum omap_dwc3_vbus_id_status status) | 238 | static void dwc3_omap_set_mailbox(struct dwc3_omap *omap, |
239 | enum omap_dwc3_vbus_id_status status) | ||
225 | { | 240 | { |
226 | u32 val; | 241 | int ret; |
227 | struct dwc3_omap *omap = _omap; | 242 | u32 val; |
228 | |||
229 | if (!omap) | ||
230 | return -EPROBE_DEFER; | ||
231 | 243 | ||
232 | switch (status) { | 244 | switch (status) { |
233 | case OMAP_DWC3_ID_GROUND: | 245 | case OMAP_DWC3_ID_GROUND: |
234 | dev_dbg(omap->dev, "ID GND\n"); | 246 | dev_dbg(omap->dev, "ID GND\n"); |
235 | 247 | ||
248 | if (omap->vbus_reg) { | ||
249 | ret = regulator_enable(omap->vbus_reg); | ||
250 | if (ret) { | ||
251 | dev_dbg(omap->dev, "regulator enable failed\n"); | ||
252 | return; | ||
253 | } | ||
254 | } | ||
255 | |||
236 | val = dwc3_omap_read_utmi_status(omap); | 256 | val = dwc3_omap_read_utmi_status(omap); |
237 | val &= ~(USBOTGSS_UTMI_OTG_STATUS_IDDIG | 257 | val &= ~(USBOTGSS_UTMI_OTG_STATUS_IDDIG |
238 | | USBOTGSS_UTMI_OTG_STATUS_VBUSVALID | 258 | | USBOTGSS_UTMI_OTG_STATUS_VBUSVALID |
@@ -255,6 +275,9 @@ int dwc3_omap_mailbox(enum omap_dwc3_vbus_id_status status) | |||
255 | break; | 275 | break; |
256 | 276 | ||
257 | case OMAP_DWC3_ID_FLOAT: | 277 | case OMAP_DWC3_ID_FLOAT: |
278 | if (omap->vbus_reg) | ||
279 | regulator_disable(omap->vbus_reg); | ||
280 | |||
258 | case OMAP_DWC3_VBUS_OFF: | 281 | case OMAP_DWC3_VBUS_OFF: |
259 | dev_dbg(omap->dev, "VBUS Disconnect\n"); | 282 | dev_dbg(omap->dev, "VBUS Disconnect\n"); |
260 | 283 | ||
@@ -268,12 +291,9 @@ int dwc3_omap_mailbox(enum omap_dwc3_vbus_id_status status) | |||
268 | break; | 291 | break; |
269 | 292 | ||
270 | default: | 293 | default: |
271 | dev_dbg(omap->dev, "ID float\n"); | 294 | dev_dbg(omap->dev, "invalid state\n"); |
272 | } | 295 | } |
273 | |||
274 | return 0; | ||
275 | } | 296 | } |
276 | EXPORT_SYMBOL_GPL(dwc3_omap_mailbox); | ||
277 | 297 | ||
278 | static irqreturn_t dwc3_omap_interrupt(int irq, void *_omap) | 298 | static irqreturn_t dwc3_omap_interrupt(int irq, void *_omap) |
279 | { | 299 | { |
@@ -366,6 +386,32 @@ static void dwc3_omap_disable_irqs(struct dwc3_omap *omap) | |||
366 | 386 | ||
367 | static u64 dwc3_omap_dma_mask = DMA_BIT_MASK(32); | 387 | static u64 dwc3_omap_dma_mask = DMA_BIT_MASK(32); |
368 | 388 | ||
389 | static int dwc3_omap_id_notifier(struct notifier_block *nb, | ||
390 | unsigned long event, void *ptr) | ||
391 | { | ||
392 | struct dwc3_omap *omap = container_of(nb, struct dwc3_omap, id_nb); | ||
393 | |||
394 | if (event) | ||
395 | dwc3_omap_set_mailbox(omap, OMAP_DWC3_ID_GROUND); | ||
396 | else | ||
397 | dwc3_omap_set_mailbox(omap, OMAP_DWC3_ID_FLOAT); | ||
398 | |||
399 | return NOTIFY_DONE; | ||
400 | } | ||
401 | |||
402 | static int dwc3_omap_vbus_notifier(struct notifier_block *nb, | ||
403 | unsigned long event, void *ptr) | ||
404 | { | ||
405 | struct dwc3_omap *omap = container_of(nb, struct dwc3_omap, vbus_nb); | ||
406 | |||
407 | if (event) | ||
408 | dwc3_omap_set_mailbox(omap, OMAP_DWC3_VBUS_VALID); | ||
409 | else | ||
410 | dwc3_omap_set_mailbox(omap, OMAP_DWC3_VBUS_OFF); | ||
411 | |||
412 | return NOTIFY_DONE; | ||
413 | } | ||
414 | |||
369 | static int dwc3_omap_probe(struct platform_device *pdev) | 415 | static int dwc3_omap_probe(struct platform_device *pdev) |
370 | { | 416 | { |
371 | struct device_node *node = pdev->dev.of_node; | 417 | struct device_node *node = pdev->dev.of_node; |
@@ -373,6 +419,8 @@ static int dwc3_omap_probe(struct platform_device *pdev) | |||
373 | struct dwc3_omap *omap; | 419 | struct dwc3_omap *omap; |
374 | struct resource *res; | 420 | struct resource *res; |
375 | struct device *dev = &pdev->dev; | 421 | struct device *dev = &pdev->dev; |
422 | struct extcon_dev *edev; | ||
423 | struct regulator *vbus_reg = NULL; | ||
376 | 424 | ||
377 | int ret = -ENOMEM; | 425 | int ret = -ENOMEM; |
378 | int irq; | 426 | int irq; |
@@ -415,19 +463,22 @@ static int dwc3_omap_probe(struct platform_device *pdev) | |||
415 | return -ENOMEM; | 463 | return -ENOMEM; |
416 | } | 464 | } |
417 | 465 | ||
466 | if (of_property_read_bool(node, "vbus-supply")) { | ||
467 | vbus_reg = devm_regulator_get(dev, "vbus"); | ||
468 | if (IS_ERR(vbus_reg)) { | ||
469 | dev_err(dev, "vbus init failed\n"); | ||
470 | return PTR_ERR(vbus_reg); | ||
471 | } | ||
472 | } | ||
473 | |||
418 | spin_lock_init(&omap->lock); | 474 | spin_lock_init(&omap->lock); |
419 | 475 | ||
420 | omap->dev = dev; | 476 | omap->dev = dev; |
421 | omap->irq = irq; | 477 | omap->irq = irq; |
422 | omap->base = base; | 478 | omap->base = base; |
479 | omap->vbus_reg = vbus_reg; | ||
423 | dev->dma_mask = &dwc3_omap_dma_mask; | 480 | dev->dma_mask = &dwc3_omap_dma_mask; |
424 | 481 | ||
425 | /* | ||
426 | * REVISIT if we ever have two instances of the wrapper, we will be | ||
427 | * in big trouble | ||
428 | */ | ||
429 | _omap = omap; | ||
430 | |||
431 | pm_runtime_enable(dev); | 482 | pm_runtime_enable(dev); |
432 | ret = pm_runtime_get_sync(dev); | 483 | ret = pm_runtime_get_sync(dev); |
433 | if (ret < 0) { | 484 | if (ret < 0) { |
@@ -502,14 +553,46 @@ static int dwc3_omap_probe(struct platform_device *pdev) | |||
502 | 553 | ||
503 | dwc3_omap_enable_irqs(omap); | 554 | dwc3_omap_enable_irqs(omap); |
504 | 555 | ||
556 | if (of_property_read_bool(node, "extcon")) { | ||
557 | edev = of_extcon_get_extcon_dev(dev, 0); | ||
558 | if (IS_ERR(edev)) { | ||
559 | dev_vdbg(dev, "couldn't get extcon device\n"); | ||
560 | ret = PTR_ERR(edev); | ||
561 | goto err2; | ||
562 | } | ||
563 | |||
564 | omap->vbus_nb.notifier_call = dwc3_omap_vbus_notifier; | ||
565 | ret = extcon_register_interest(&omap->extcon_vbus_dev, | ||
566 | edev->name, "USB", &omap->vbus_nb); | ||
567 | if (ret < 0) | ||
568 | dev_vdbg(dev, "failed to register notifier for USB\n"); | ||
569 | omap->id_nb.notifier_call = dwc3_omap_id_notifier; | ||
570 | ret = extcon_register_interest(&omap->extcon_id_dev, edev->name, | ||
571 | "USB-HOST", &omap->id_nb); | ||
572 | if (ret < 0) | ||
573 | dev_vdbg(dev, | ||
574 | "failed to register notifier for USB-HOST\n"); | ||
575 | |||
576 | if (extcon_get_cable_state(edev, "USB") == true) | ||
577 | dwc3_omap_set_mailbox(omap, OMAP_DWC3_VBUS_VALID); | ||
578 | if (extcon_get_cable_state(edev, "USB-HOST") == true) | ||
579 | dwc3_omap_set_mailbox(omap, OMAP_DWC3_ID_GROUND); | ||
580 | } | ||
581 | |||
505 | ret = of_platform_populate(node, NULL, NULL, dev); | 582 | ret = of_platform_populate(node, NULL, NULL, dev); |
506 | if (ret) { | 583 | if (ret) { |
507 | dev_err(&pdev->dev, "failed to create dwc3 core\n"); | 584 | dev_err(&pdev->dev, "failed to create dwc3 core\n"); |
508 | goto err2; | 585 | goto err3; |
509 | } | 586 | } |
510 | 587 | ||
511 | return 0; | 588 | return 0; |
512 | 589 | ||
590 | err3: | ||
591 | if (omap->extcon_vbus_dev.edev) | ||
592 | extcon_unregister_interest(&omap->extcon_vbus_dev); | ||
593 | if (omap->extcon_id_dev.edev) | ||
594 | extcon_unregister_interest(&omap->extcon_id_dev); | ||
595 | |||
513 | err2: | 596 | err2: |
514 | dwc3_omap_disable_irqs(omap); | 597 | dwc3_omap_disable_irqs(omap); |
515 | 598 | ||
@@ -526,6 +609,10 @@ static int dwc3_omap_remove(struct platform_device *pdev) | |||
526 | { | 609 | { |
527 | struct dwc3_omap *omap = platform_get_drvdata(pdev); | 610 | struct dwc3_omap *omap = platform_get_drvdata(pdev); |
528 | 611 | ||
612 | if (omap->extcon_vbus_dev.edev) | ||
613 | extcon_unregister_interest(&omap->extcon_vbus_dev); | ||
614 | if (omap->extcon_id_dev.edev) | ||
615 | extcon_unregister_interest(&omap->extcon_id_dev); | ||
529 | dwc3_omap_disable_irqs(omap); | 616 | dwc3_omap_disable_irqs(omap); |
530 | pm_runtime_put_sync(&pdev->dev); | 617 | pm_runtime_put_sync(&pdev->dev); |
531 | pm_runtime_disable(&pdev->dev); | 618 | pm_runtime_disable(&pdev->dev); |
diff --git a/include/linux/usb/dwc3-omap.h b/include/linux/usb/dwc3-omap.h deleted file mode 100644 index 5615f4d82724..000000000000 --- a/include/linux/usb/dwc3-omap.h +++ /dev/null | |||
@@ -1,30 +0,0 @@ | |||
1 | /* | ||
2 | * Copyright (C) 2013 by Texas Instruments | ||
3 | * | ||
4 | * The Inventra Controller Driver for Linux is free software; you | ||
5 | * can redistribute it and/or modify it under the terms of the GNU | ||
6 | * General Public License version 2 as published by the Free Software | ||
7 | * Foundation. | ||
8 | */ | ||
9 | |||
10 | #ifndef __DWC3_OMAP_H__ | ||
11 | #define __DWC3_OMAP_H__ | ||
12 | |||
13 | enum omap_dwc3_vbus_id_status { | ||
14 | OMAP_DWC3_UNKNOWN = 0, | ||
15 | OMAP_DWC3_ID_GROUND, | ||
16 | OMAP_DWC3_ID_FLOAT, | ||
17 | OMAP_DWC3_VBUS_VALID, | ||
18 | OMAP_DWC3_VBUS_OFF, | ||
19 | }; | ||
20 | |||
21 | #if (defined(CONFIG_USB_DWC3) || defined(CONFIG_USB_DWC3_MODULE)) | ||
22 | extern int dwc3_omap_mailbox(enum omap_dwc3_vbus_id_status status); | ||
23 | #else | ||
24 | static inline int dwc3_omap_mailbox(enum omap_dwc3_vbus_id_status status) | ||
25 | { | ||
26 | return -ENODEV; | ||
27 | } | ||
28 | #endif | ||
29 | |||
30 | #endif /* __DWC3_OMAP_H__ */ | ||