diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2013-09-03 14:36:27 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2013-09-03 14:36:27 -0400 |
commit | 1d1fdd95df681f0c065d90ffaafa215a0e8825e2 (patch) | |
tree | 19016e131bb5c7eb280a4cc8dff864ba36e53be4 /drivers/usb/dwc3 | |
parent | b3b49114c80e799af8b08c0c6d1ff886ea843f03 (diff) | |
parent | 3cc1f95283a125cf54ccf1e25065321d4385133b (diff) |
Merge tag 'char-misc-3.12-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/char-misc
Pull char/misc patches from Greg KH:
"Here is the big char/misc driver pull request for 3.12-rc1
Lots of driver updates all over the char/misc tree, full details in
the shortlog"
* tag 'char-misc-3.12-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/char-misc: (62 commits)
drivers: uio: Kconfig: add MMU dependancy for UIO
drivers: uio: Add driver for Humusoft MF624 DAQ PCI card
drivers: uio_pdrv_genirq: use dev_get_platdata()
drivers: uio_pruss: use dev_get_platdata()
drivers: uio_dmem_genirq: use dev_get_platdata()
drivers: parport: Kconfig: exclude h8300 for PARPORT_PC
drivers: misc: ti-st: fix potential race if st_kim_start fails
Drivers: hv: vmbus: Do not attempt to negoatiate a new version prematurely
misc: vmw_balloon: Remove braces to fix build for clang.
Drivers: hv: vmbus: Fix a bug in the handling of channel offers
vme: vme_ca91cx42.c: fix to pass correct device identity to free_irq()
VMCI: Add support for virtual IOMMU
VMCI: Remove non-blocking/pinned queuepair support
uio: uio_pruss: remove unnecessary platform_set_drvdata()
parport: amiga: remove unnecessary platform_set_drvdata()
vme: vme_vmivme7805.c: add missing __iomem annotation
vme: vme_ca91cx42.c: add missing __iomem annotation
vme: vme_tsi148.c: add missing __iomem annotation
drivers/misc/hpilo: Correct panic when an AUX iLO is detected
uio: drop unused vma_count member in uio_device struct
...
Diffstat (limited to 'drivers/usb/dwc3')
-rw-r--r-- | drivers/usb/dwc3/Kconfig | 1 | ||||
-rw-r--r-- | drivers/usb/dwc3/dwc3-omap.c | 125 |
2 files changed, 107 insertions, 19 deletions
diff --git a/drivers/usb/dwc3/Kconfig b/drivers/usb/dwc3/Kconfig index 3e225d5846f6..f969ea266acb 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 ecd99451ee90..7f7ea62e961b 100644 --- a/drivers/usb/dwc3/dwc3-omap.c +++ b/drivers/usb/dwc3/dwc3-omap.c | |||
@@ -23,13 +23,15 @@ | |||
23 | #include <linux/spinlock.h> | 23 | #include <linux/spinlock.h> |
24 | #include <linux/platform_device.h> | 24 | #include <linux/platform_device.h> |
25 | #include <linux/platform_data/dwc3-omap.h> | 25 | #include <linux/platform_data/dwc3-omap.h> |
26 | #include <linux/usb/dwc3-omap.h> | ||
27 | #include <linux/pm_runtime.h> | 26 | #include <linux/pm_runtime.h> |
28 | #include <linux/dma-mapping.h> | 27 | #include <linux/dma-mapping.h> |
29 | #include <linux/ioport.h> | 28 | #include <linux/ioport.h> |
30 | #include <linux/io.h> | 29 | #include <linux/io.h> |
31 | #include <linux/of.h> | 30 | #include <linux/of.h> |
32 | #include <linux/of_platform.h> | 31 | #include <linux/of_platform.h> |
32 | #include <linux/extcon.h> | ||
33 | #include <linux/extcon/of_extcon.h> | ||
34 | #include <linux/regulator/consumer.h> | ||
33 | 35 | ||
34 | #include <linux/usb/otg.h> | 36 | #include <linux/usb/otg.h> |
35 | 37 | ||
@@ -135,9 +137,21 @@ struct dwc3_omap { | |||
135 | u32 revision; | 137 | u32 revision; |
136 | 138 | ||
137 | u32 dma_status:1; | 139 | u32 dma_status:1; |
140 | |||
141 | struct extcon_specific_cable_nb extcon_vbus_dev; | ||
142 | struct extcon_specific_cable_nb extcon_id_dev; | ||
143 | struct notifier_block vbus_nb; | ||
144 | struct notifier_block id_nb; | ||
145 | |||
146 | struct regulator *vbus_reg; | ||
138 | }; | 147 | }; |
139 | 148 | ||
140 | static struct dwc3_omap *_omap; | 149 | enum omap_dwc3_vbus_id_status { |
150 | OMAP_DWC3_ID_FLOAT, | ||
151 | OMAP_DWC3_ID_GROUND, | ||
152 | OMAP_DWC3_VBUS_OFF, | ||
153 | OMAP_DWC3_VBUS_VALID, | ||
154 | }; | ||
141 | 155 | ||
142 | static inline u32 dwc3_omap_readl(void __iomem *base, u32 offset) | 156 | static inline u32 dwc3_omap_readl(void __iomem *base, u32 offset) |
143 | { | 157 | { |
@@ -201,18 +215,24 @@ static void dwc3_omap_write_irq0_set(struct dwc3_omap *omap, u32 value) | |||
201 | omap->irq0_offset, value); | 215 | omap->irq0_offset, value); |
202 | } | 216 | } |
203 | 217 | ||
204 | int dwc3_omap_mailbox(enum omap_dwc3_vbus_id_status status) | 218 | static void dwc3_omap_set_mailbox(struct dwc3_omap *omap, |
219 | enum omap_dwc3_vbus_id_status status) | ||
205 | { | 220 | { |
206 | u32 val; | 221 | int ret; |
207 | struct dwc3_omap *omap = _omap; | 222 | u32 val; |
208 | |||
209 | if (!omap) | ||
210 | return -EPROBE_DEFER; | ||
211 | 223 | ||
212 | switch (status) { | 224 | switch (status) { |
213 | case OMAP_DWC3_ID_GROUND: | 225 | case OMAP_DWC3_ID_GROUND: |
214 | dev_dbg(omap->dev, "ID GND\n"); | 226 | dev_dbg(omap->dev, "ID GND\n"); |
215 | 227 | ||
228 | if (omap->vbus_reg) { | ||
229 | ret = regulator_enable(omap->vbus_reg); | ||
230 | if (ret) { | ||
231 | dev_dbg(omap->dev, "regulator enable failed\n"); | ||
232 | return; | ||
233 | } | ||
234 | } | ||
235 | |||
216 | val = dwc3_omap_read_utmi_status(omap); | 236 | val = dwc3_omap_read_utmi_status(omap); |
217 | val &= ~(USBOTGSS_UTMI_OTG_STATUS_IDDIG | 237 | val &= ~(USBOTGSS_UTMI_OTG_STATUS_IDDIG |
218 | | USBOTGSS_UTMI_OTG_STATUS_VBUSVALID | 238 | | USBOTGSS_UTMI_OTG_STATUS_VBUSVALID |
@@ -235,6 +255,9 @@ int dwc3_omap_mailbox(enum omap_dwc3_vbus_id_status status) | |||
235 | break; | 255 | break; |
236 | 256 | ||
237 | case OMAP_DWC3_ID_FLOAT: | 257 | case OMAP_DWC3_ID_FLOAT: |
258 | if (omap->vbus_reg) | ||
259 | regulator_disable(omap->vbus_reg); | ||
260 | |||
238 | case OMAP_DWC3_VBUS_OFF: | 261 | case OMAP_DWC3_VBUS_OFF: |
239 | dev_dbg(omap->dev, "VBUS Disconnect\n"); | 262 | dev_dbg(omap->dev, "VBUS Disconnect\n"); |
240 | 263 | ||
@@ -248,12 +271,9 @@ int dwc3_omap_mailbox(enum omap_dwc3_vbus_id_status status) | |||
248 | break; | 271 | break; |
249 | 272 | ||
250 | default: | 273 | default: |
251 | dev_dbg(omap->dev, "ID float\n"); | 274 | dev_dbg(omap->dev, "invalid state\n"); |
252 | } | 275 | } |
253 | |||
254 | return 0; | ||
255 | } | 276 | } |
256 | EXPORT_SYMBOL_GPL(dwc3_omap_mailbox); | ||
257 | 277 | ||
258 | static irqreturn_t dwc3_omap_interrupt(int irq, void *_omap) | 278 | static irqreturn_t dwc3_omap_interrupt(int irq, void *_omap) |
259 | { | 279 | { |
@@ -346,6 +366,32 @@ static void dwc3_omap_disable_irqs(struct dwc3_omap *omap) | |||
346 | 366 | ||
347 | static u64 dwc3_omap_dma_mask = DMA_BIT_MASK(32); | 367 | static u64 dwc3_omap_dma_mask = DMA_BIT_MASK(32); |
348 | 368 | ||
369 | static int dwc3_omap_id_notifier(struct notifier_block *nb, | ||
370 | unsigned long event, void *ptr) | ||
371 | { | ||
372 | struct dwc3_omap *omap = container_of(nb, struct dwc3_omap, id_nb); | ||
373 | |||
374 | if (event) | ||
375 | dwc3_omap_set_mailbox(omap, OMAP_DWC3_ID_GROUND); | ||
376 | else | ||
377 | dwc3_omap_set_mailbox(omap, OMAP_DWC3_ID_FLOAT); | ||
378 | |||
379 | return NOTIFY_DONE; | ||
380 | } | ||
381 | |||
382 | static int dwc3_omap_vbus_notifier(struct notifier_block *nb, | ||
383 | unsigned long event, void *ptr) | ||
384 | { | ||
385 | struct dwc3_omap *omap = container_of(nb, struct dwc3_omap, vbus_nb); | ||
386 | |||
387 | if (event) | ||
388 | dwc3_omap_set_mailbox(omap, OMAP_DWC3_VBUS_VALID); | ||
389 | else | ||
390 | dwc3_omap_set_mailbox(omap, OMAP_DWC3_VBUS_OFF); | ||
391 | |||
392 | return NOTIFY_DONE; | ||
393 | } | ||
394 | |||
349 | static int dwc3_omap_probe(struct platform_device *pdev) | 395 | static int dwc3_omap_probe(struct platform_device *pdev) |
350 | { | 396 | { |
351 | struct device_node *node = pdev->dev.of_node; | 397 | struct device_node *node = pdev->dev.of_node; |
@@ -353,6 +399,8 @@ static int dwc3_omap_probe(struct platform_device *pdev) | |||
353 | struct dwc3_omap *omap; | 399 | struct dwc3_omap *omap; |
354 | struct resource *res; | 400 | struct resource *res; |
355 | struct device *dev = &pdev->dev; | 401 | struct device *dev = &pdev->dev; |
402 | struct extcon_dev *edev; | ||
403 | struct regulator *vbus_reg = NULL; | ||
356 | 404 | ||
357 | int ret = -ENOMEM; | 405 | int ret = -ENOMEM; |
358 | int irq; | 406 | int irq; |
@@ -393,19 +441,22 @@ static int dwc3_omap_probe(struct platform_device *pdev) | |||
393 | if (IS_ERR(base)) | 441 | if (IS_ERR(base)) |
394 | return PTR_ERR(base); | 442 | return PTR_ERR(base); |
395 | 443 | ||
444 | if (of_property_read_bool(node, "vbus-supply")) { | ||
445 | vbus_reg = devm_regulator_get(dev, "vbus"); | ||
446 | if (IS_ERR(vbus_reg)) { | ||
447 | dev_err(dev, "vbus init failed\n"); | ||
448 | return PTR_ERR(vbus_reg); | ||
449 | } | ||
450 | } | ||
451 | |||
396 | spin_lock_init(&omap->lock); | 452 | spin_lock_init(&omap->lock); |
397 | 453 | ||
398 | omap->dev = dev; | 454 | omap->dev = dev; |
399 | omap->irq = irq; | 455 | omap->irq = irq; |
400 | omap->base = base; | 456 | omap->base = base; |
457 | omap->vbus_reg = vbus_reg; | ||
401 | dev->dma_mask = &dwc3_omap_dma_mask; | 458 | dev->dma_mask = &dwc3_omap_dma_mask; |
402 | 459 | ||
403 | /* | ||
404 | * REVISIT if we ever have two instances of the wrapper, we will be | ||
405 | * in big trouble | ||
406 | */ | ||
407 | _omap = omap; | ||
408 | |||
409 | pm_runtime_enable(dev); | 460 | pm_runtime_enable(dev); |
410 | ret = pm_runtime_get_sync(dev); | 461 | ret = pm_runtime_get_sync(dev); |
411 | if (ret < 0) { | 462 | if (ret < 0) { |
@@ -480,14 +531,46 @@ static int dwc3_omap_probe(struct platform_device *pdev) | |||
480 | 531 | ||
481 | dwc3_omap_enable_irqs(omap); | 532 | dwc3_omap_enable_irqs(omap); |
482 | 533 | ||
534 | if (of_property_read_bool(node, "extcon")) { | ||
535 | edev = of_extcon_get_extcon_dev(dev, 0); | ||
536 | if (IS_ERR(edev)) { | ||
537 | dev_vdbg(dev, "couldn't get extcon device\n"); | ||
538 | ret = PTR_ERR(edev); | ||
539 | goto err2; | ||
540 | } | ||
541 | |||
542 | omap->vbus_nb.notifier_call = dwc3_omap_vbus_notifier; | ||
543 | ret = extcon_register_interest(&omap->extcon_vbus_dev, | ||
544 | edev->name, "USB", &omap->vbus_nb); | ||
545 | if (ret < 0) | ||
546 | dev_vdbg(dev, "failed to register notifier for USB\n"); | ||
547 | omap->id_nb.notifier_call = dwc3_omap_id_notifier; | ||
548 | ret = extcon_register_interest(&omap->extcon_id_dev, edev->name, | ||
549 | "USB-HOST", &omap->id_nb); | ||
550 | if (ret < 0) | ||
551 | dev_vdbg(dev, | ||
552 | "failed to register notifier for USB-HOST\n"); | ||
553 | |||
554 | if (extcon_get_cable_state(edev, "USB") == true) | ||
555 | dwc3_omap_set_mailbox(omap, OMAP_DWC3_VBUS_VALID); | ||
556 | if (extcon_get_cable_state(edev, "USB-HOST") == true) | ||
557 | dwc3_omap_set_mailbox(omap, OMAP_DWC3_ID_GROUND); | ||
558 | } | ||
559 | |||
483 | ret = of_platform_populate(node, NULL, NULL, dev); | 560 | ret = of_platform_populate(node, NULL, NULL, dev); |
484 | if (ret) { | 561 | if (ret) { |
485 | dev_err(&pdev->dev, "failed to create dwc3 core\n"); | 562 | dev_err(&pdev->dev, "failed to create dwc3 core\n"); |
486 | goto err2; | 563 | goto err3; |
487 | } | 564 | } |
488 | 565 | ||
489 | return 0; | 566 | return 0; |
490 | 567 | ||
568 | err3: | ||
569 | if (omap->extcon_vbus_dev.edev) | ||
570 | extcon_unregister_interest(&omap->extcon_vbus_dev); | ||
571 | if (omap->extcon_id_dev.edev) | ||
572 | extcon_unregister_interest(&omap->extcon_id_dev); | ||
573 | |||
491 | err2: | 574 | err2: |
492 | dwc3_omap_disable_irqs(omap); | 575 | dwc3_omap_disable_irqs(omap); |
493 | 576 | ||
@@ -504,6 +587,10 @@ static int dwc3_omap_remove(struct platform_device *pdev) | |||
504 | { | 587 | { |
505 | struct dwc3_omap *omap = platform_get_drvdata(pdev); | 588 | struct dwc3_omap *omap = platform_get_drvdata(pdev); |
506 | 589 | ||
590 | if (omap->extcon_vbus_dev.edev) | ||
591 | extcon_unregister_interest(&omap->extcon_vbus_dev); | ||
592 | if (omap->extcon_id_dev.edev) | ||
593 | extcon_unregister_interest(&omap->extcon_id_dev); | ||
507 | dwc3_omap_disable_irqs(omap); | 594 | dwc3_omap_disable_irqs(omap); |
508 | pm_runtime_put_sync(&pdev->dev); | 595 | pm_runtime_put_sync(&pdev->dev); |
509 | pm_runtime_disable(&pdev->dev); | 596 | pm_runtime_disable(&pdev->dev); |