phy-omap-otg.c 4.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168
  1. /*
  2. * OMAP OTG controller driver
  3. *
  4. * Based on code from tahvo-usb.c and isp1301_omap.c drivers.
  5. *
  6. * Copyright (C) 2005-2006 Nokia Corporation
  7. * Copyright (C) 2004 Texas Instruments
  8. * Copyright (C) 2004 David Brownell
  9. *
  10. * This file is subject to the terms and conditions of the GNU General
  11. * Public License. See the file "COPYING" in the main directory of this
  12. * archive for more details.
  13. *
  14. * This program is distributed in the hope that it will be useful,
  15. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  16. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  17. * GNU General Public License for more details.
  18. */
  19. #include <linux/io.h>
  20. #include <linux/err.h>
  21. #include <linux/extcon.h>
  22. #include <linux/kernel.h>
  23. #include <linux/module.h>
  24. #include <linux/interrupt.h>
  25. #include <linux/platform_device.h>
  26. #include <linux/platform_data/usb-omap1.h>
  27. struct otg_device {
  28. void __iomem *base;
  29. bool id;
  30. bool vbus;
  31. struct extcon_dev *extcon;
  32. struct notifier_block vbus_nb;
  33. struct notifier_block id_nb;
  34. };
  35. #define OMAP_OTG_CTRL 0x0c
  36. #define OMAP_OTG_ASESSVLD (1 << 20)
  37. #define OMAP_OTG_BSESSEND (1 << 19)
  38. #define OMAP_OTG_BSESSVLD (1 << 18)
  39. #define OMAP_OTG_VBUSVLD (1 << 17)
  40. #define OMAP_OTG_ID (1 << 16)
  41. #define OMAP_OTG_XCEIV_OUTPUTS \
  42. (OMAP_OTG_ASESSVLD | OMAP_OTG_BSESSEND | OMAP_OTG_BSESSVLD | \
  43. OMAP_OTG_VBUSVLD | OMAP_OTG_ID)
  44. static void omap_otg_ctrl(struct otg_device *otg_dev, u32 outputs)
  45. {
  46. u32 l;
  47. l = readl(otg_dev->base + OMAP_OTG_CTRL);
  48. l &= ~OMAP_OTG_XCEIV_OUTPUTS;
  49. l |= outputs;
  50. writel(l, otg_dev->base + OMAP_OTG_CTRL);
  51. }
  52. static void omap_otg_set_mode(struct otg_device *otg_dev)
  53. {
  54. if (!otg_dev->id && otg_dev->vbus)
  55. /* Set B-session valid. */
  56. omap_otg_ctrl(otg_dev, OMAP_OTG_ID | OMAP_OTG_BSESSVLD);
  57. else if (otg_dev->vbus)
  58. /* Set A-session valid. */
  59. omap_otg_ctrl(otg_dev, OMAP_OTG_ASESSVLD);
  60. else if (!otg_dev->id)
  61. /* Set B-session end to indicate no VBUS. */
  62. omap_otg_ctrl(otg_dev, OMAP_OTG_ID | OMAP_OTG_BSESSEND);
  63. }
  64. static int omap_otg_id_notifier(struct notifier_block *nb,
  65. unsigned long event, void *ptr)
  66. {
  67. struct otg_device *otg_dev = container_of(nb, struct otg_device, id_nb);
  68. otg_dev->id = event;
  69. omap_otg_set_mode(otg_dev);
  70. return NOTIFY_DONE;
  71. }
  72. static int omap_otg_vbus_notifier(struct notifier_block *nb,
  73. unsigned long event, void *ptr)
  74. {
  75. struct otg_device *otg_dev = container_of(nb, struct otg_device,
  76. vbus_nb);
  77. otg_dev->vbus = event;
  78. omap_otg_set_mode(otg_dev);
  79. return NOTIFY_DONE;
  80. }
  81. static int omap_otg_probe(struct platform_device *pdev)
  82. {
  83. const struct omap_usb_config *config = pdev->dev.platform_data;
  84. struct otg_device *otg_dev;
  85. struct extcon_dev *extcon;
  86. int ret;
  87. u32 rev;
  88. if (!config || !config->extcon)
  89. return -ENODEV;
  90. extcon = extcon_get_extcon_dev(config->extcon);
  91. if (!extcon)
  92. return -EPROBE_DEFER;
  93. otg_dev = devm_kzalloc(&pdev->dev, sizeof(*otg_dev), GFP_KERNEL);
  94. if (!otg_dev)
  95. return -ENOMEM;
  96. otg_dev->base = devm_ioremap_resource(&pdev->dev, &pdev->resource[0]);
  97. if (IS_ERR(otg_dev->base))
  98. return PTR_ERR(otg_dev->base);
  99. otg_dev->extcon = extcon;
  100. otg_dev->id_nb.notifier_call = omap_otg_id_notifier;
  101. otg_dev->vbus_nb.notifier_call = omap_otg_vbus_notifier;
  102. ret = extcon_register_notifier(extcon, EXTCON_USB_HOST, &otg_dev->id_nb);
  103. if (ret)
  104. return ret;
  105. ret = extcon_register_notifier(extcon, EXTCON_USB, &otg_dev->vbus_nb);
  106. if (ret) {
  107. extcon_unregister_notifier(extcon, EXTCON_USB_HOST,
  108. &otg_dev->id_nb);
  109. return ret;
  110. }
  111. otg_dev->id = extcon_get_cable_state_(extcon, EXTCON_USB_HOST);
  112. otg_dev->vbus = extcon_get_cable_state_(extcon, EXTCON_USB);
  113. omap_otg_set_mode(otg_dev);
  114. rev = readl(otg_dev->base);
  115. dev_info(&pdev->dev,
  116. "OMAP USB OTG controller rev %d.%d (%s, id=%d, vbus=%d)\n",
  117. (rev >> 4) & 0xf, rev & 0xf, config->extcon, otg_dev->id,
  118. otg_dev->vbus);
  119. return 0;
  120. }
  121. static int omap_otg_remove(struct platform_device *pdev)
  122. {
  123. struct otg_device *otg_dev = platform_get_drvdata(pdev);
  124. struct extcon_dev *edev = otg_dev->extcon;
  125. extcon_unregister_notifier(edev, EXTCON_USB_HOST,&otg_dev->id_nb);
  126. extcon_unregister_notifier(edev, EXTCON_USB, &otg_dev->vbus_nb);
  127. return 0;
  128. }
  129. static struct platform_driver omap_otg_driver = {
  130. .probe = omap_otg_probe,
  131. .remove = omap_otg_remove,
  132. .driver = {
  133. .name = "omap_otg",
  134. },
  135. };
  136. module_platform_driver(omap_otg_driver);
  137. MODULE_DESCRIPTION("OMAP USB OTG controller driver");
  138. MODULE_LICENSE("GPL");
  139. MODULE_AUTHOR("Aaro Koskinen <aaro.koskinen@iki.fi>");