diff options
Diffstat (limited to 'drivers/usb/otg')
-rw-r--r-- | drivers/usb/otg/Kconfig | 10 | ||||
-rw-r--r-- | drivers/usb/otg/Makefile | 1 | ||||
-rw-r--r-- | drivers/usb/otg/gpio_vbus.c | 1 | ||||
-rw-r--r-- | drivers/usb/otg/isp1301_omap.c | 8 | ||||
-rw-r--r-- | drivers/usb/otg/nop-usb-xceiv.c | 1 | ||||
-rw-r--r-- | drivers/usb/otg/twl4030-usb.c | 86 | ||||
-rw-r--r-- | drivers/usb/otg/ulpi.c | 137 |
7 files changed, 190 insertions, 54 deletions
diff --git a/drivers/usb/otg/Kconfig b/drivers/usb/otg/Kconfig index aa884d072f0b..3d2d3e549bd1 100644 --- a/drivers/usb/otg/Kconfig +++ b/drivers/usb/otg/Kconfig | |||
@@ -41,6 +41,16 @@ config ISP1301_OMAP | |||
41 | This driver can also be built as a module. If so, the module | 41 | This driver can also be built as a module. If so, the module |
42 | will be called isp1301_omap. | 42 | will be called isp1301_omap. |
43 | 43 | ||
44 | config USB_ULPI | ||
45 | bool "Generic ULPI Transceiver Driver" | ||
46 | depends on ARM | ||
47 | select USB_OTG_UTILS | ||
48 | help | ||
49 | Enable this to support ULPI connected USB OTG transceivers which | ||
50 | are likely found on embedded boards. | ||
51 | |||
52 | The only chip currently supported is NXP's ISP1504 | ||
53 | |||
44 | config TWL4030_USB | 54 | config TWL4030_USB |
45 | tristate "TWL4030 USB Transceiver Driver" | 55 | tristate "TWL4030 USB Transceiver Driver" |
46 | depends on TWL4030_CORE && REGULATOR_TWL4030 | 56 | depends on TWL4030_CORE && REGULATOR_TWL4030 |
diff --git a/drivers/usb/otg/Makefile b/drivers/usb/otg/Makefile index 208167856529..aeb49a8ec412 100644 --- a/drivers/usb/otg/Makefile +++ b/drivers/usb/otg/Makefile | |||
@@ -10,6 +10,7 @@ obj-$(CONFIG_USB_GPIO_VBUS) += gpio_vbus.o | |||
10 | obj-$(CONFIG_ISP1301_OMAP) += isp1301_omap.o | 10 | obj-$(CONFIG_ISP1301_OMAP) += isp1301_omap.o |
11 | obj-$(CONFIG_TWL4030_USB) += twl4030-usb.o | 11 | obj-$(CONFIG_TWL4030_USB) += twl4030-usb.o |
12 | obj-$(CONFIG_NOP_USB_XCEIV) += nop-usb-xceiv.o | 12 | obj-$(CONFIG_NOP_USB_XCEIV) += nop-usb-xceiv.o |
13 | obj-$(CONFIG_USB_ULPI) += ulpi.o | ||
13 | 14 | ||
14 | ccflags-$(CONFIG_USB_DEBUG) += -DDEBUG | 15 | ccflags-$(CONFIG_USB_DEBUG) += -DDEBUG |
15 | ccflags-$(CONFIG_USB_GADGET_DEBUG) += -DDEBUG | 16 | ccflags-$(CONFIG_USB_GADGET_DEBUG) += -DDEBUG |
diff --git a/drivers/usb/otg/gpio_vbus.c b/drivers/usb/otg/gpio_vbus.c index 1c26c94513e9..221c44444ec6 100644 --- a/drivers/usb/otg/gpio_vbus.c +++ b/drivers/usb/otg/gpio_vbus.c | |||
@@ -11,6 +11,7 @@ | |||
11 | #include <linux/kernel.h> | 11 | #include <linux/kernel.h> |
12 | #include <linux/platform_device.h> | 12 | #include <linux/platform_device.h> |
13 | #include <linux/gpio.h> | 13 | #include <linux/gpio.h> |
14 | #include <linux/slab.h> | ||
14 | #include <linux/interrupt.h> | 15 | #include <linux/interrupt.h> |
15 | #include <linux/usb.h> | 16 | #include <linux/usb.h> |
16 | #include <linux/workqueue.h> | 17 | #include <linux/workqueue.h> |
diff --git a/drivers/usb/otg/isp1301_omap.c b/drivers/usb/otg/isp1301_omap.c index 77a5f4188999..78a209709260 100644 --- a/drivers/usb/otg/isp1301_omap.c +++ b/drivers/usb/otg/isp1301_omap.c | |||
@@ -36,8 +36,8 @@ | |||
36 | #include <asm/irq.h> | 36 | #include <asm/irq.h> |
37 | #include <asm/mach-types.h> | 37 | #include <asm/mach-types.h> |
38 | 38 | ||
39 | #include <mach/usb.h> | 39 | #include <plat/usb.h> |
40 | #include <mach/mux.h> | 40 | #include <plat/mux.h> |
41 | 41 | ||
42 | 42 | ||
43 | #ifndef DEBUG | 43 | #ifndef DEBUG |
@@ -843,7 +843,7 @@ static irqreturn_t omap_otg_irq(int irq, void *_isp) | |||
843 | 843 | ||
844 | static struct platform_device *otg_dev; | 844 | static struct platform_device *otg_dev; |
845 | 845 | ||
846 | static int otg_init(struct isp1301 *isp) | 846 | static int isp1301_otg_init(struct isp1301 *isp) |
847 | { | 847 | { |
848 | u32 l; | 848 | u32 l; |
849 | 849 | ||
@@ -1275,7 +1275,7 @@ static int __exit isp1301_remove(struct i2c_client *i2c) | |||
1275 | static int isp1301_otg_enable(struct isp1301 *isp) | 1275 | static int isp1301_otg_enable(struct isp1301 *isp) |
1276 | { | 1276 | { |
1277 | power_up(isp); | 1277 | power_up(isp); |
1278 | otg_init(isp); | 1278 | isp1301_otg_init(isp); |
1279 | 1279 | ||
1280 | /* NOTE: since we don't change this, this provides | 1280 | /* NOTE: since we don't change this, this provides |
1281 | * a few more interrupts than are strictly needed. | 1281 | * a few more interrupts than are strictly needed. |
diff --git a/drivers/usb/otg/nop-usb-xceiv.c b/drivers/usb/otg/nop-usb-xceiv.c index af456b48985f..e70014ab0976 100644 --- a/drivers/usb/otg/nop-usb-xceiv.c +++ b/drivers/usb/otg/nop-usb-xceiv.c | |||
@@ -30,6 +30,7 @@ | |||
30 | #include <linux/platform_device.h> | 30 | #include <linux/platform_device.h> |
31 | #include <linux/dma-mapping.h> | 31 | #include <linux/dma-mapping.h> |
32 | #include <linux/usb/otg.h> | 32 | #include <linux/usb/otg.h> |
33 | #include <linux/slab.h> | ||
33 | 34 | ||
34 | struct nop_usb_xceiv { | 35 | struct nop_usb_xceiv { |
35 | struct otg_transceiver otg; | 36 | struct otg_transceiver otg; |
diff --git a/drivers/usb/otg/twl4030-usb.c b/drivers/usb/otg/twl4030-usb.c index 9e3e7a5c258b..223cdf46ccb7 100644 --- a/drivers/usb/otg/twl4030-usb.c +++ b/drivers/usb/otg/twl4030-usb.c | |||
@@ -33,10 +33,11 @@ | |||
33 | #include <linux/io.h> | 33 | #include <linux/io.h> |
34 | #include <linux/delay.h> | 34 | #include <linux/delay.h> |
35 | #include <linux/usb/otg.h> | 35 | #include <linux/usb/otg.h> |
36 | #include <linux/i2c/twl4030.h> | 36 | #include <linux/i2c/twl.h> |
37 | #include <linux/regulator/consumer.h> | 37 | #include <linux/regulator/consumer.h> |
38 | #include <linux/err.h> | 38 | #include <linux/err.h> |
39 | 39 | #include <linux/notifier.h> | |
40 | #include <linux/slab.h> | ||
40 | 41 | ||
41 | /* Register defines */ | 42 | /* Register defines */ |
42 | 43 | ||
@@ -236,15 +237,6 @@ | |||
236 | #define PMBR1 0x0D | 237 | #define PMBR1 0x0D |
237 | #define GPIO_USB_4PIN_ULPI_2430C (3 << 0) | 238 | #define GPIO_USB_4PIN_ULPI_2430C (3 << 0) |
238 | 239 | ||
239 | |||
240 | |||
241 | enum linkstat { | ||
242 | USB_LINK_UNKNOWN = 0, | ||
243 | USB_LINK_NONE, | ||
244 | USB_LINK_VBUS, | ||
245 | USB_LINK_ID, | ||
246 | }; | ||
247 | |||
248 | struct twl4030_usb { | 240 | struct twl4030_usb { |
249 | struct otg_transceiver otg; | 241 | struct otg_transceiver otg; |
250 | struct device *dev; | 242 | struct device *dev; |
@@ -276,16 +268,16 @@ static int twl4030_i2c_write_u8_verify(struct twl4030_usb *twl, | |||
276 | { | 268 | { |
277 | u8 check; | 269 | u8 check; |
278 | 270 | ||
279 | if ((twl4030_i2c_write_u8(module, data, address) >= 0) && | 271 | if ((twl_i2c_write_u8(module, data, address) >= 0) && |
280 | (twl4030_i2c_read_u8(module, &check, address) >= 0) && | 272 | (twl_i2c_read_u8(module, &check, address) >= 0) && |
281 | (check == data)) | 273 | (check == data)) |
282 | return 0; | 274 | return 0; |
283 | dev_dbg(twl->dev, "Write%d[%d,0x%x] wrote %02x but read %02x\n", | 275 | dev_dbg(twl->dev, "Write%d[%d,0x%x] wrote %02x but read %02x\n", |
284 | 1, module, address, check, data); | 276 | 1, module, address, check, data); |
285 | 277 | ||
286 | /* Failed once: Try again */ | 278 | /* Failed once: Try again */ |
287 | if ((twl4030_i2c_write_u8(module, data, address) >= 0) && | 279 | if ((twl_i2c_write_u8(module, data, address) >= 0) && |
288 | (twl4030_i2c_read_u8(module, &check, address) >= 0) && | 280 | (twl_i2c_read_u8(module, &check, address) >= 0) && |
289 | (check == data)) | 281 | (check == data)) |
290 | return 0; | 282 | return 0; |
291 | dev_dbg(twl->dev, "Write%d[%d,0x%x] wrote %02x but read %02x\n", | 283 | dev_dbg(twl->dev, "Write%d[%d,0x%x] wrote %02x but read %02x\n", |
@@ -303,7 +295,7 @@ static inline int twl4030_usb_write(struct twl4030_usb *twl, | |||
303 | { | 295 | { |
304 | int ret = 0; | 296 | int ret = 0; |
305 | 297 | ||
306 | ret = twl4030_i2c_write_u8(TWL4030_MODULE_USB, data, address); | 298 | ret = twl_i2c_write_u8(TWL4030_MODULE_USB, data, address); |
307 | if (ret < 0) | 299 | if (ret < 0) |
308 | dev_dbg(twl->dev, | 300 | dev_dbg(twl->dev, |
309 | "TWL4030:USB:Write[0x%x] Error %d\n", address, ret); | 301 | "TWL4030:USB:Write[0x%x] Error %d\n", address, ret); |
@@ -315,7 +307,7 @@ static inline int twl4030_readb(struct twl4030_usb *twl, u8 module, u8 address) | |||
315 | u8 data; | 307 | u8 data; |
316 | int ret = 0; | 308 | int ret = 0; |
317 | 309 | ||
318 | ret = twl4030_i2c_read_u8(module, &data, address); | 310 | ret = twl_i2c_read_u8(module, &data, address); |
319 | if (ret >= 0) | 311 | if (ret >= 0) |
320 | ret = data; | 312 | ret = data; |
321 | else | 313 | else |
@@ -347,10 +339,10 @@ twl4030_usb_clear_bits(struct twl4030_usb *twl, u8 reg, u8 bits) | |||
347 | 339 | ||
348 | /*-------------------------------------------------------------------------*/ | 340 | /*-------------------------------------------------------------------------*/ |
349 | 341 | ||
350 | static enum linkstat twl4030_usb_linkstat(struct twl4030_usb *twl) | 342 | static enum usb_xceiv_events twl4030_usb_linkstat(struct twl4030_usb *twl) |
351 | { | 343 | { |
352 | int status; | 344 | int status; |
353 | int linkstat = USB_LINK_UNKNOWN; | 345 | int linkstat = USB_EVENT_NONE; |
354 | 346 | ||
355 | /* | 347 | /* |
356 | * For ID/VBUS sensing, see manual section 15.4.8 ... | 348 | * For ID/VBUS sensing, see manual section 15.4.8 ... |
@@ -368,11 +360,11 @@ static enum linkstat twl4030_usb_linkstat(struct twl4030_usb *twl) | |||
368 | dev_err(twl->dev, "USB link status err %d\n", status); | 360 | dev_err(twl->dev, "USB link status err %d\n", status); |
369 | else if (status & (BIT(7) | BIT(2))) { | 361 | else if (status & (BIT(7) | BIT(2))) { |
370 | if (status & BIT(2)) | 362 | if (status & BIT(2)) |
371 | linkstat = USB_LINK_ID; | 363 | linkstat = USB_EVENT_ID; |
372 | else | 364 | else |
373 | linkstat = USB_LINK_VBUS; | 365 | linkstat = USB_EVENT_VBUS; |
374 | } else | 366 | } else |
375 | linkstat = USB_LINK_NONE; | 367 | linkstat = USB_EVENT_NONE; |
376 | 368 | ||
377 | dev_dbg(twl->dev, "HW_CONDITIONS 0x%02x/%d; link %d\n", | 369 | dev_dbg(twl->dev, "HW_CONDITIONS 0x%02x/%d; link %d\n", |
378 | status, status, linkstat); | 370 | status, status, linkstat); |
@@ -383,7 +375,7 @@ static enum linkstat twl4030_usb_linkstat(struct twl4030_usb *twl) | |||
383 | 375 | ||
384 | spin_lock_irq(&twl->lock); | 376 | spin_lock_irq(&twl->lock); |
385 | twl->linkstat = linkstat; | 377 | twl->linkstat = linkstat; |
386 | if (linkstat == USB_LINK_ID) { | 378 | if (linkstat == USB_EVENT_ID) { |
387 | twl->otg.default_a = true; | 379 | twl->otg.default_a = true; |
388 | twl->otg.state = OTG_STATE_A_IDLE; | 380 | twl->otg.state = OTG_STATE_A_IDLE; |
389 | } else { | 381 | } else { |
@@ -462,7 +454,7 @@ static void twl4030_phy_power(struct twl4030_usb *twl, int on) | |||
462 | * SLEEP. We work around this by clearing the bit after usv3v1 | 454 | * SLEEP. We work around this by clearing the bit after usv3v1 |
463 | * is re-activated. This ensures that VUSB3V1 is really active. | 455 | * is re-activated. This ensures that VUSB3V1 is really active. |
464 | */ | 456 | */ |
465 | twl4030_i2c_write_u8(TWL4030_MODULE_PM_RECEIVER, 0, | 457 | twl_i2c_write_u8(TWL4030_MODULE_PM_RECEIVER, 0, |
466 | VUSB_DEDICATED2); | 458 | VUSB_DEDICATED2); |
467 | regulator_enable(twl->usb1v5); | 459 | regulator_enable(twl->usb1v5); |
468 | pwr &= ~PHY_PWR_PHYPWD; | 460 | pwr &= ~PHY_PWR_PHYPWD; |
@@ -505,44 +497,44 @@ static void twl4030_phy_resume(struct twl4030_usb *twl) | |||
505 | static int twl4030_usb_ldo_init(struct twl4030_usb *twl) | 497 | static int twl4030_usb_ldo_init(struct twl4030_usb *twl) |
506 | { | 498 | { |
507 | /* Enable writing to power configuration registers */ | 499 | /* Enable writing to power configuration registers */ |
508 | twl4030_i2c_write_u8(TWL4030_MODULE_PM_MASTER, 0xC0, PROTECT_KEY); | 500 | twl_i2c_write_u8(TWL4030_MODULE_PM_MASTER, 0xC0, PROTECT_KEY); |
509 | twl4030_i2c_write_u8(TWL4030_MODULE_PM_MASTER, 0x0C, PROTECT_KEY); | 501 | twl_i2c_write_u8(TWL4030_MODULE_PM_MASTER, 0x0C, PROTECT_KEY); |
510 | 502 | ||
511 | /* put VUSB3V1 LDO in active state */ | 503 | /* put VUSB3V1 LDO in active state */ |
512 | twl4030_i2c_write_u8(TWL4030_MODULE_PM_RECEIVER, 0, VUSB_DEDICATED2); | 504 | twl_i2c_write_u8(TWL4030_MODULE_PM_RECEIVER, 0, VUSB_DEDICATED2); |
513 | 505 | ||
514 | /* input to VUSB3V1 LDO is from VBAT, not VBUS */ | 506 | /* input to VUSB3V1 LDO is from VBAT, not VBUS */ |
515 | twl4030_i2c_write_u8(TWL4030_MODULE_PM_RECEIVER, 0x14, VUSB_DEDICATED1); | 507 | twl_i2c_write_u8(TWL4030_MODULE_PM_RECEIVER, 0x14, VUSB_DEDICATED1); |
516 | 508 | ||
517 | /* Initialize 3.1V regulator */ | 509 | /* Initialize 3.1V regulator */ |
518 | twl4030_i2c_write_u8(TWL4030_MODULE_PM_RECEIVER, 0, VUSB3V1_DEV_GRP); | 510 | twl_i2c_write_u8(TWL4030_MODULE_PM_RECEIVER, 0, VUSB3V1_DEV_GRP); |
519 | 511 | ||
520 | twl->usb3v1 = regulator_get(twl->dev, "usb3v1"); | 512 | twl->usb3v1 = regulator_get(twl->dev, "usb3v1"); |
521 | if (IS_ERR(twl->usb3v1)) | 513 | if (IS_ERR(twl->usb3v1)) |
522 | return -ENODEV; | 514 | return -ENODEV; |
523 | 515 | ||
524 | twl4030_i2c_write_u8(TWL4030_MODULE_PM_RECEIVER, 0, VUSB3V1_TYPE); | 516 | twl_i2c_write_u8(TWL4030_MODULE_PM_RECEIVER, 0, VUSB3V1_TYPE); |
525 | 517 | ||
526 | /* Initialize 1.5V regulator */ | 518 | /* Initialize 1.5V regulator */ |
527 | twl4030_i2c_write_u8(TWL4030_MODULE_PM_RECEIVER, 0, VUSB1V5_DEV_GRP); | 519 | twl_i2c_write_u8(TWL4030_MODULE_PM_RECEIVER, 0, VUSB1V5_DEV_GRP); |
528 | 520 | ||
529 | twl->usb1v5 = regulator_get(twl->dev, "usb1v5"); | 521 | twl->usb1v5 = regulator_get(twl->dev, "usb1v5"); |
530 | if (IS_ERR(twl->usb1v5)) | 522 | if (IS_ERR(twl->usb1v5)) |
531 | goto fail1; | 523 | goto fail1; |
532 | 524 | ||
533 | twl4030_i2c_write_u8(TWL4030_MODULE_PM_RECEIVER, 0, VUSB1V5_TYPE); | 525 | twl_i2c_write_u8(TWL4030_MODULE_PM_RECEIVER, 0, VUSB1V5_TYPE); |
534 | 526 | ||
535 | /* Initialize 1.8V regulator */ | 527 | /* Initialize 1.8V regulator */ |
536 | twl4030_i2c_write_u8(TWL4030_MODULE_PM_RECEIVER, 0, VUSB1V8_DEV_GRP); | 528 | twl_i2c_write_u8(TWL4030_MODULE_PM_RECEIVER, 0, VUSB1V8_DEV_GRP); |
537 | 529 | ||
538 | twl->usb1v8 = regulator_get(twl->dev, "usb1v8"); | 530 | twl->usb1v8 = regulator_get(twl->dev, "usb1v8"); |
539 | if (IS_ERR(twl->usb1v8)) | 531 | if (IS_ERR(twl->usb1v8)) |
540 | goto fail2; | 532 | goto fail2; |
541 | 533 | ||
542 | twl4030_i2c_write_u8(TWL4030_MODULE_PM_RECEIVER, 0, VUSB1V8_TYPE); | 534 | twl_i2c_write_u8(TWL4030_MODULE_PM_RECEIVER, 0, VUSB1V8_TYPE); |
543 | 535 | ||
544 | /* disable access to power configuration registers */ | 536 | /* disable access to power configuration registers */ |
545 | twl4030_i2c_write_u8(TWL4030_MODULE_PM_MASTER, 0, PROTECT_KEY); | 537 | twl_i2c_write_u8(TWL4030_MODULE_PM_MASTER, 0, PROTECT_KEY); |
546 | 538 | ||
547 | return 0; | 539 | return 0; |
548 | 540 | ||
@@ -564,7 +556,7 @@ static ssize_t twl4030_usb_vbus_show(struct device *dev, | |||
564 | 556 | ||
565 | spin_lock_irqsave(&twl->lock, flags); | 557 | spin_lock_irqsave(&twl->lock, flags); |
566 | ret = sprintf(buf, "%s\n", | 558 | ret = sprintf(buf, "%s\n", |
567 | (twl->linkstat == USB_LINK_VBUS) ? "on" : "off"); | 559 | (twl->linkstat == USB_EVENT_VBUS) ? "on" : "off"); |
568 | spin_unlock_irqrestore(&twl->lock, flags); | 560 | spin_unlock_irqrestore(&twl->lock, flags); |
569 | 561 | ||
570 | return ret; | 562 | return ret; |
@@ -576,17 +568,8 @@ static irqreturn_t twl4030_usb_irq(int irq, void *_twl) | |||
576 | struct twl4030_usb *twl = _twl; | 568 | struct twl4030_usb *twl = _twl; |
577 | int status; | 569 | int status; |
578 | 570 | ||
579 | #ifdef CONFIG_LOCKDEP | ||
580 | /* WORKAROUND for lockdep forcing IRQF_DISABLED on us, which | ||
581 | * we don't want and can't tolerate. Although it might be | ||
582 | * friendlier not to borrow this thread context... | ||
583 | */ | ||
584 | local_irq_enable(); | ||
585 | #endif | ||
586 | |||
587 | status = twl4030_usb_linkstat(twl); | 571 | status = twl4030_usb_linkstat(twl); |
588 | if (status != USB_LINK_UNKNOWN) { | 572 | if (status >= 0) { |
589 | |||
590 | /* FIXME add a set_power() method so that B-devices can | 573 | /* FIXME add a set_power() method so that B-devices can |
591 | * configure the charger appropriately. It's not always | 574 | * configure the charger appropriately. It's not always |
592 | * correct to consume VBUS power, and how much current to | 575 | * correct to consume VBUS power, and how much current to |
@@ -598,12 +581,13 @@ static irqreturn_t twl4030_usb_irq(int irq, void *_twl) | |||
598 | * USB_LINK_VBUS state. musb_hdrc won't care until it | 581 | * USB_LINK_VBUS state. musb_hdrc won't care until it |
599 | * starts to handle softconnect right. | 582 | * starts to handle softconnect right. |
600 | */ | 583 | */ |
601 | twl4030charger_usb_en(status == USB_LINK_VBUS); | 584 | if (status == USB_EVENT_NONE) |
602 | |||
603 | if (status == USB_LINK_NONE) | ||
604 | twl4030_phy_suspend(twl, 0); | 585 | twl4030_phy_suspend(twl, 0); |
605 | else | 586 | else |
606 | twl4030_phy_resume(twl); | 587 | twl4030_phy_resume(twl); |
588 | |||
589 | blocking_notifier_call_chain(&twl->otg.notifier, status, | ||
590 | twl->otg.gadget); | ||
607 | } | 591 | } |
608 | sysfs_notify(&twl->dev->kobj, NULL, "vbus"); | 592 | sysfs_notify(&twl->dev->kobj, NULL, "vbus"); |
609 | 593 | ||
@@ -693,6 +677,8 @@ static int __devinit twl4030_usb_probe(struct platform_device *pdev) | |||
693 | if (device_create_file(&pdev->dev, &dev_attr_vbus)) | 677 | if (device_create_file(&pdev->dev, &dev_attr_vbus)) |
694 | dev_warn(&pdev->dev, "could not create sysfs file\n"); | 678 | dev_warn(&pdev->dev, "could not create sysfs file\n"); |
695 | 679 | ||
680 | BLOCKING_INIT_NOTIFIER_HEAD(&twl->otg.notifier); | ||
681 | |||
696 | /* Our job is to use irqs and status from the power module | 682 | /* Our job is to use irqs and status from the power module |
697 | * to keep the transceiver disabled when nothing's connected. | 683 | * to keep the transceiver disabled when nothing's connected. |
698 | * | 684 | * |
@@ -702,7 +688,7 @@ static int __devinit twl4030_usb_probe(struct platform_device *pdev) | |||
702 | * need both handles, otherwise just one suffices. | 688 | * need both handles, otherwise just one suffices. |
703 | */ | 689 | */ |
704 | twl->irq_enabled = true; | 690 | twl->irq_enabled = true; |
705 | status = request_irq(twl->irq, twl4030_usb_irq, | 691 | status = request_threaded_irq(twl->irq, NULL, twl4030_usb_irq, |
706 | IRQF_TRIGGER_FALLING | IRQF_TRIGGER_RISING, | 692 | IRQF_TRIGGER_FALLING | IRQF_TRIGGER_RISING, |
707 | "twl4030_usb", twl); | 693 | "twl4030_usb", twl); |
708 | if (status < 0) { | 694 | if (status < 0) { |
diff --git a/drivers/usb/otg/ulpi.c b/drivers/usb/otg/ulpi.c new file mode 100644 index 000000000000..9010225e0d06 --- /dev/null +++ b/drivers/usb/otg/ulpi.c | |||
@@ -0,0 +1,137 @@ | |||
1 | /* | ||
2 | * Generic ULPI USB transceiver support | ||
3 | * | ||
4 | * Copyright (C) 2009 Daniel Mack <daniel@caiaq.de> | ||
5 | * | ||
6 | * Based on sources from | ||
7 | * | ||
8 | * Sascha Hauer <s.hauer@pengutronix.de> | ||
9 | * Freescale Semiconductors | ||
10 | * | ||
11 | * This program is free software; you can redistribute it and/or modify | ||
12 | * it under the terms of the GNU General Public License as published by | ||
13 | * the Free Software Foundation; either version 2 of the License, or | ||
14 | * (at your option) any later version. | ||
15 | * | ||
16 | * This program is distributed in the hope that it will be useful, | ||
17 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
18 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
19 | * GNU General Public License for more details. | ||
20 | * | ||
21 | * You should have received a copy of the GNU General Public License | ||
22 | * along with this program; if not, write to the Free Software | ||
23 | * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. | ||
24 | */ | ||
25 | |||
26 | #include <linux/kernel.h> | ||
27 | #include <linux/slab.h> | ||
28 | #include <linux/usb.h> | ||
29 | #include <linux/usb/otg.h> | ||
30 | #include <linux/usb/ulpi.h> | ||
31 | |||
32 | /* ULPI register addresses */ | ||
33 | #define ULPI_VID_LOW 0x00 /* Vendor ID low */ | ||
34 | #define ULPI_VID_HIGH 0x01 /* Vendor ID high */ | ||
35 | #define ULPI_PID_LOW 0x02 /* Product ID low */ | ||
36 | #define ULPI_PID_HIGH 0x03 /* Product ID high */ | ||
37 | #define ULPI_ITFCTL 0x07 /* Interface Control */ | ||
38 | #define ULPI_OTGCTL 0x0A /* OTG Control */ | ||
39 | |||
40 | /* add to above register address to access Set/Clear functions */ | ||
41 | #define ULPI_REG_SET 0x01 | ||
42 | #define ULPI_REG_CLEAR 0x02 | ||
43 | |||
44 | /* ULPI OTG Control Register bits */ | ||
45 | #define ID_PULL_UP (1 << 0) /* enable ID Pull Up */ | ||
46 | #define DP_PULL_DOWN (1 << 1) /* enable DP Pull Down */ | ||
47 | #define DM_PULL_DOWN (1 << 2) /* enable DM Pull Down */ | ||
48 | #define DISCHRG_VBUS (1 << 3) /* Discharge Vbus */ | ||
49 | #define CHRG_VBUS (1 << 4) /* Charge Vbus */ | ||
50 | #define DRV_VBUS (1 << 5) /* Drive Vbus */ | ||
51 | #define DRV_VBUS_EXT (1 << 6) /* Drive Vbus external */ | ||
52 | #define USE_EXT_VBUS_IND (1 << 7) /* Use ext. Vbus indicator */ | ||
53 | |||
54 | #define ULPI_ID(vendor, product) (((vendor) << 16) | (product)) | ||
55 | |||
56 | #define TR_FLAG(flags, a, b) (((flags) & a) ? b : 0) | ||
57 | |||
58 | /* ULPI hardcoded IDs, used for probing */ | ||
59 | static unsigned int ulpi_ids[] = { | ||
60 | ULPI_ID(0x04cc, 0x1504), /* NXP ISP1504 */ | ||
61 | }; | ||
62 | |||
63 | static int ulpi_set_flags(struct otg_transceiver *otg) | ||
64 | { | ||
65 | unsigned int flags = 0; | ||
66 | |||
67 | if (otg->flags & USB_OTG_PULLUP_ID) | ||
68 | flags |= ID_PULL_UP; | ||
69 | |||
70 | if (otg->flags & USB_OTG_PULLDOWN_DM) | ||
71 | flags |= DM_PULL_DOWN; | ||
72 | |||
73 | if (otg->flags & USB_OTG_PULLDOWN_DP) | ||
74 | flags |= DP_PULL_DOWN; | ||
75 | |||
76 | if (otg->flags & USB_OTG_EXT_VBUS_INDICATOR) | ||
77 | flags |= USE_EXT_VBUS_IND; | ||
78 | |||
79 | return otg_io_write(otg, flags, ULPI_OTGCTL + ULPI_REG_SET); | ||
80 | } | ||
81 | |||
82 | static int ulpi_init(struct otg_transceiver *otg) | ||
83 | { | ||
84 | int i, vid, pid; | ||
85 | |||
86 | vid = (otg_io_read(otg, ULPI_VID_HIGH) << 8) | | ||
87 | otg_io_read(otg, ULPI_VID_LOW); | ||
88 | pid = (otg_io_read(otg, ULPI_PID_HIGH) << 8) | | ||
89 | otg_io_read(otg, ULPI_PID_LOW); | ||
90 | |||
91 | pr_info("ULPI transceiver vendor/product ID 0x%04x/0x%04x\n", vid, pid); | ||
92 | |||
93 | for (i = 0; i < ARRAY_SIZE(ulpi_ids); i++) | ||
94 | if (ulpi_ids[i] == ULPI_ID(vid, pid)) | ||
95 | return ulpi_set_flags(otg); | ||
96 | |||
97 | pr_err("ULPI ID does not match any known transceiver.\n"); | ||
98 | return -ENODEV; | ||
99 | } | ||
100 | |||
101 | static int ulpi_set_vbus(struct otg_transceiver *otg, bool on) | ||
102 | { | ||
103 | unsigned int flags = otg_io_read(otg, ULPI_OTGCTL); | ||
104 | |||
105 | flags &= ~(DRV_VBUS | DRV_VBUS_EXT); | ||
106 | |||
107 | if (on) { | ||
108 | if (otg->flags & USB_OTG_DRV_VBUS) | ||
109 | flags |= DRV_VBUS; | ||
110 | |||
111 | if (otg->flags & USB_OTG_DRV_VBUS_EXT) | ||
112 | flags |= DRV_VBUS_EXT; | ||
113 | } | ||
114 | |||
115 | return otg_io_write(otg, flags, ULPI_OTGCTL + ULPI_REG_SET); | ||
116 | } | ||
117 | |||
118 | struct otg_transceiver * | ||
119 | otg_ulpi_create(struct otg_io_access_ops *ops, | ||
120 | unsigned int flags) | ||
121 | { | ||
122 | struct otg_transceiver *otg; | ||
123 | |||
124 | otg = kzalloc(sizeof(*otg), GFP_KERNEL); | ||
125 | if (!otg) | ||
126 | return NULL; | ||
127 | |||
128 | otg->label = "ULPI"; | ||
129 | otg->flags = flags; | ||
130 | otg->io_ops = ops; | ||
131 | otg->init = ulpi_init; | ||
132 | otg->set_vbus = ulpi_set_vbus; | ||
133 | |||
134 | return otg; | ||
135 | } | ||
136 | EXPORT_SYMBOL_GPL(otg_ulpi_create); | ||
137 | |||