aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorKishon Vijay Abraham I <kishon@ti.com>2013-07-07 20:54:43 -0400
committerChanwoo Choi <cw00.choi@samsung.com>2013-08-04 19:53:33 -0400
commit8061ad7239f3f97b477984660e95134ca684578c (patch)
tree7e93e773509e957ad84a6fe7ada64e037503daa0
parent6eee5b3b493824731ed34ade0299241f91f04096 (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.txt5
-rw-r--r--drivers/usb/dwc3/Kconfig1
-rw-r--r--drivers/usb/dwc3/dwc3-omap.c125
-rw-r--r--include/linux/usb/dwc3-omap.h30
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
56Optional 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
56Sub-nodes: 61Sub-nodes:
57The dwc3 core should be added as subnode to omap dwc3 glue. 62The 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 @@
1config USB_DWC3 1config 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
160static struct dwc3_omap *_omap; 169enum 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
162static inline u32 dwc3_omap_readl(void __iomem *base, u32 offset) 176static 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
224int dwc3_omap_mailbox(enum omap_dwc3_vbus_id_status status) 238static 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}
276EXPORT_SYMBOL_GPL(dwc3_omap_mailbox);
277 297
278static irqreturn_t dwc3_omap_interrupt(int irq, void *_omap) 298static 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
367static u64 dwc3_omap_dma_mask = DMA_BIT_MASK(32); 387static u64 dwc3_omap_dma_mask = DMA_BIT_MASK(32);
368 388
389static 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
402static 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
369static int dwc3_omap_probe(struct platform_device *pdev) 415static 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
590err3:
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
513err2: 596err2:
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
13enum 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))
22extern int dwc3_omap_mailbox(enum omap_dwc3_vbus_id_status status);
23#else
24static 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__ */