phy-tahvo.c 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457
  1. /*
  2. * Tahvo USB transceiver driver
  3. *
  4. * Copyright (C) 2005-2006 Nokia Corporation
  5. *
  6. * Parts copied from isp1301_omap.c.
  7. * Copyright (C) 2004 Texas Instruments
  8. * Copyright (C) 2004 David Brownell
  9. *
  10. * Original driver written by Juha Yrjölä, Tony Lindgren and Timo Teräs.
  11. * Modified for Retu/Tahvo MFD by Aaro Koskinen.
  12. *
  13. * This file is subject to the terms and conditions of the GNU General
  14. * Public License. See the file "COPYING" in the main directory of this
  15. * archive for more details.
  16. *
  17. * This program is distributed in the hope that it will be useful,
  18. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  19. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  20. * GNU General Public License for more details.
  21. */
  22. #include <linux/io.h>
  23. #include <linux/clk.h>
  24. #include <linux/usb.h>
  25. #include <linux/extcon.h>
  26. #include <linux/kernel.h>
  27. #include <linux/module.h>
  28. #include <linux/usb/otg.h>
  29. #include <linux/mfd/retu.h>
  30. #include <linux/usb/gadget.h>
  31. #include <linux/platform_device.h>
  32. #define DRIVER_NAME "tahvo-usb"
  33. #define TAHVO_REG_IDSR 0x02
  34. #define TAHVO_REG_USBR 0x06
  35. #define USBR_SLAVE_CONTROL (1 << 8)
  36. #define USBR_VPPVIO_SW (1 << 7)
  37. #define USBR_SPEED (1 << 6)
  38. #define USBR_REGOUT (1 << 5)
  39. #define USBR_MASTER_SW2 (1 << 4)
  40. #define USBR_MASTER_SW1 (1 << 3)
  41. #define USBR_SLAVE_SW (1 << 2)
  42. #define USBR_NSUSPEND (1 << 1)
  43. #define USBR_SEMODE (1 << 0)
  44. #define TAHVO_MODE_HOST 0
  45. #define TAHVO_MODE_PERIPHERAL 1
  46. struct tahvo_usb {
  47. struct platform_device *pt_dev;
  48. struct usb_phy phy;
  49. int vbus_state;
  50. struct mutex serialize;
  51. struct clk *ick;
  52. int irq;
  53. int tahvo_mode;
  54. struct extcon_dev extcon;
  55. };
  56. static const char *tahvo_cable[] = {
  57. "USB-HOST",
  58. "USB",
  59. NULL,
  60. };
  61. static ssize_t vbus_state_show(struct device *device,
  62. struct device_attribute *attr, char *buf)
  63. {
  64. struct tahvo_usb *tu = dev_get_drvdata(device);
  65. return sprintf(buf, "%s\n", tu->vbus_state ? "on" : "off");
  66. }
  67. static DEVICE_ATTR(vbus, 0444, vbus_state_show, NULL);
  68. static void check_vbus_state(struct tahvo_usb *tu)
  69. {
  70. struct retu_dev *rdev = dev_get_drvdata(tu->pt_dev->dev.parent);
  71. int reg, prev_state;
  72. reg = retu_read(rdev, TAHVO_REG_IDSR);
  73. if (reg & TAHVO_STAT_VBUS) {
  74. switch (tu->phy.state) {
  75. case OTG_STATE_B_IDLE:
  76. /* Enable the gadget driver */
  77. if (tu->phy.otg->gadget)
  78. usb_gadget_vbus_connect(tu->phy.otg->gadget);
  79. tu->phy.state = OTG_STATE_B_PERIPHERAL;
  80. break;
  81. case OTG_STATE_A_IDLE:
  82. /*
  83. * Session is now valid assuming the USB hub is driving
  84. * Vbus.
  85. */
  86. tu->phy.state = OTG_STATE_A_HOST;
  87. break;
  88. default:
  89. break;
  90. }
  91. dev_info(&tu->pt_dev->dev, "USB cable connected\n");
  92. } else {
  93. switch (tu->phy.state) {
  94. case OTG_STATE_B_PERIPHERAL:
  95. if (tu->phy.otg->gadget)
  96. usb_gadget_vbus_disconnect(tu->phy.otg->gadget);
  97. tu->phy.state = OTG_STATE_B_IDLE;
  98. break;
  99. case OTG_STATE_A_HOST:
  100. tu->phy.state = OTG_STATE_A_IDLE;
  101. break;
  102. default:
  103. break;
  104. }
  105. dev_info(&tu->pt_dev->dev, "USB cable disconnected\n");
  106. }
  107. prev_state = tu->vbus_state;
  108. tu->vbus_state = reg & TAHVO_STAT_VBUS;
  109. if (prev_state != tu->vbus_state) {
  110. extcon_set_cable_state(&tu->extcon, "USB", tu->vbus_state);
  111. sysfs_notify(&tu->pt_dev->dev.kobj, NULL, "vbus_state");
  112. }
  113. }
  114. static void tahvo_usb_become_host(struct tahvo_usb *tu)
  115. {
  116. struct retu_dev *rdev = dev_get_drvdata(tu->pt_dev->dev.parent);
  117. extcon_set_cable_state(&tu->extcon, "USB-HOST", true);
  118. /* Power up the transceiver in USB host mode */
  119. retu_write(rdev, TAHVO_REG_USBR, USBR_REGOUT | USBR_NSUSPEND |
  120. USBR_MASTER_SW2 | USBR_MASTER_SW1);
  121. tu->phy.state = OTG_STATE_A_IDLE;
  122. check_vbus_state(tu);
  123. }
  124. static void tahvo_usb_stop_host(struct tahvo_usb *tu)
  125. {
  126. tu->phy.state = OTG_STATE_A_IDLE;
  127. }
  128. static void tahvo_usb_become_peripheral(struct tahvo_usb *tu)
  129. {
  130. struct retu_dev *rdev = dev_get_drvdata(tu->pt_dev->dev.parent);
  131. extcon_set_cable_state(&tu->extcon, "USB-HOST", false);
  132. /* Power up transceiver and set it in USB peripheral mode */
  133. retu_write(rdev, TAHVO_REG_USBR, USBR_SLAVE_CONTROL | USBR_REGOUT |
  134. USBR_NSUSPEND | USBR_SLAVE_SW);
  135. tu->phy.state = OTG_STATE_B_IDLE;
  136. check_vbus_state(tu);
  137. }
  138. static void tahvo_usb_stop_peripheral(struct tahvo_usb *tu)
  139. {
  140. if (tu->phy.otg->gadget)
  141. usb_gadget_vbus_disconnect(tu->phy.otg->gadget);
  142. tu->phy.state = OTG_STATE_B_IDLE;
  143. }
  144. static void tahvo_usb_power_off(struct tahvo_usb *tu)
  145. {
  146. struct retu_dev *rdev = dev_get_drvdata(tu->pt_dev->dev.parent);
  147. /* Disable gadget controller if any */
  148. if (tu->phy.otg->gadget)
  149. usb_gadget_vbus_disconnect(tu->phy.otg->gadget);
  150. /* Power off transceiver */
  151. retu_write(rdev, TAHVO_REG_USBR, 0);
  152. tu->phy.state = OTG_STATE_UNDEFINED;
  153. }
  154. static int tahvo_usb_set_suspend(struct usb_phy *dev, int suspend)
  155. {
  156. struct tahvo_usb *tu = container_of(dev, struct tahvo_usb, phy);
  157. struct retu_dev *rdev = dev_get_drvdata(tu->pt_dev->dev.parent);
  158. u16 w;
  159. dev_dbg(&tu->pt_dev->dev, "%s\n", __func__);
  160. w = retu_read(rdev, TAHVO_REG_USBR);
  161. if (suspend)
  162. w &= ~USBR_NSUSPEND;
  163. else
  164. w |= USBR_NSUSPEND;
  165. retu_write(rdev, TAHVO_REG_USBR, w);
  166. return 0;
  167. }
  168. static int tahvo_usb_set_host(struct usb_otg *otg, struct usb_bus *host)
  169. {
  170. struct tahvo_usb *tu = container_of(otg->phy, struct tahvo_usb, phy);
  171. dev_dbg(&tu->pt_dev->dev, "%s %p\n", __func__, host);
  172. mutex_lock(&tu->serialize);
  173. if (host == NULL) {
  174. if (tu->tahvo_mode == TAHVO_MODE_HOST)
  175. tahvo_usb_power_off(tu);
  176. otg->host = NULL;
  177. mutex_unlock(&tu->serialize);
  178. return 0;
  179. }
  180. if (tu->tahvo_mode == TAHVO_MODE_HOST) {
  181. otg->host = NULL;
  182. tahvo_usb_become_host(tu);
  183. }
  184. otg->host = host;
  185. mutex_unlock(&tu->serialize);
  186. return 0;
  187. }
  188. static int tahvo_usb_set_peripheral(struct usb_otg *otg,
  189. struct usb_gadget *gadget)
  190. {
  191. struct tahvo_usb *tu = container_of(otg->phy, struct tahvo_usb, phy);
  192. dev_dbg(&tu->pt_dev->dev, "%s %p\n", __func__, gadget);
  193. mutex_lock(&tu->serialize);
  194. if (!gadget) {
  195. if (tu->tahvo_mode == TAHVO_MODE_PERIPHERAL)
  196. tahvo_usb_power_off(tu);
  197. tu->phy.otg->gadget = NULL;
  198. mutex_unlock(&tu->serialize);
  199. return 0;
  200. }
  201. tu->phy.otg->gadget = gadget;
  202. if (tu->tahvo_mode == TAHVO_MODE_PERIPHERAL)
  203. tahvo_usb_become_peripheral(tu);
  204. mutex_unlock(&tu->serialize);
  205. return 0;
  206. }
  207. static irqreturn_t tahvo_usb_vbus_interrupt(int irq, void *_tu)
  208. {
  209. struct tahvo_usb *tu = _tu;
  210. mutex_lock(&tu->serialize);
  211. check_vbus_state(tu);
  212. mutex_unlock(&tu->serialize);
  213. return IRQ_HANDLED;
  214. }
  215. static ssize_t otg_mode_show(struct device *device,
  216. struct device_attribute *attr, char *buf)
  217. {
  218. struct tahvo_usb *tu = dev_get_drvdata(device);
  219. switch (tu->tahvo_mode) {
  220. case TAHVO_MODE_HOST:
  221. return sprintf(buf, "host\n");
  222. case TAHVO_MODE_PERIPHERAL:
  223. return sprintf(buf, "peripheral\n");
  224. }
  225. return -EINVAL;
  226. }
  227. static ssize_t otg_mode_store(struct device *device,
  228. struct device_attribute *attr,
  229. const char *buf, size_t count)
  230. {
  231. struct tahvo_usb *tu = dev_get_drvdata(device);
  232. int r;
  233. mutex_lock(&tu->serialize);
  234. if (count >= 4 && strncmp(buf, "host", 4) == 0) {
  235. if (tu->tahvo_mode == TAHVO_MODE_PERIPHERAL)
  236. tahvo_usb_stop_peripheral(tu);
  237. tu->tahvo_mode = TAHVO_MODE_HOST;
  238. if (tu->phy.otg->host) {
  239. dev_info(device, "HOST mode: host controller present\n");
  240. tahvo_usb_become_host(tu);
  241. } else {
  242. dev_info(device, "HOST mode: no host controller, powering off\n");
  243. tahvo_usb_power_off(tu);
  244. }
  245. r = strlen(buf);
  246. } else if (count >= 10 && strncmp(buf, "peripheral", 10) == 0) {
  247. if (tu->tahvo_mode == TAHVO_MODE_HOST)
  248. tahvo_usb_stop_host(tu);
  249. tu->tahvo_mode = TAHVO_MODE_PERIPHERAL;
  250. if (tu->phy.otg->gadget) {
  251. dev_info(device, "PERIPHERAL mode: gadget driver present\n");
  252. tahvo_usb_become_peripheral(tu);
  253. } else {
  254. dev_info(device, "PERIPHERAL mode: no gadget driver, powering off\n");
  255. tahvo_usb_power_off(tu);
  256. }
  257. r = strlen(buf);
  258. } else {
  259. r = -EINVAL;
  260. }
  261. mutex_unlock(&tu->serialize);
  262. return r;
  263. }
  264. static DEVICE_ATTR(otg_mode, 0644, otg_mode_show, otg_mode_store);
  265. static struct attribute *tahvo_attributes[] = {
  266. &dev_attr_vbus.attr,
  267. &dev_attr_otg_mode.attr,
  268. NULL
  269. };
  270. static struct attribute_group tahvo_attr_group = {
  271. .attrs = tahvo_attributes,
  272. };
  273. static int tahvo_usb_probe(struct platform_device *pdev)
  274. {
  275. struct retu_dev *rdev = dev_get_drvdata(pdev->dev.parent);
  276. struct tahvo_usb *tu;
  277. int ret;
  278. tu = devm_kzalloc(&pdev->dev, sizeof(*tu), GFP_KERNEL);
  279. if (!tu)
  280. return -ENOMEM;
  281. tu->phy.otg = devm_kzalloc(&pdev->dev, sizeof(*tu->phy.otg),
  282. GFP_KERNEL);
  283. if (!tu->phy.otg)
  284. return -ENOMEM;
  285. tu->pt_dev = pdev;
  286. /* Default mode */
  287. #ifdef CONFIG_TAHVO_USB_HOST_BY_DEFAULT
  288. tu->tahvo_mode = TAHVO_MODE_HOST;
  289. #else
  290. tu->tahvo_mode = TAHVO_MODE_PERIPHERAL;
  291. #endif
  292. mutex_init(&tu->serialize);
  293. tu->ick = devm_clk_get(&pdev->dev, "usb_l4_ick");
  294. if (!IS_ERR(tu->ick))
  295. clk_enable(tu->ick);
  296. /*
  297. * Set initial state, so that we generate kevents only on state changes.
  298. */
  299. tu->vbus_state = retu_read(rdev, TAHVO_REG_IDSR) & TAHVO_STAT_VBUS;
  300. tu->extcon.name = DRIVER_NAME;
  301. tu->extcon.supported_cable = tahvo_cable;
  302. tu->extcon.dev.parent = &pdev->dev;
  303. ret = extcon_dev_register(&tu->extcon);
  304. if (ret) {
  305. dev_err(&pdev->dev, "could not register extcon device: %d\n",
  306. ret);
  307. goto err_disable_clk;
  308. }
  309. /* Set the initial cable state. */
  310. extcon_set_cable_state(&tu->extcon, "USB-HOST",
  311. tu->tahvo_mode == TAHVO_MODE_HOST);
  312. extcon_set_cable_state(&tu->extcon, "USB", tu->vbus_state);
  313. /* Create OTG interface */
  314. tahvo_usb_power_off(tu);
  315. tu->phy.dev = &pdev->dev;
  316. tu->phy.state = OTG_STATE_UNDEFINED;
  317. tu->phy.label = DRIVER_NAME;
  318. tu->phy.set_suspend = tahvo_usb_set_suspend;
  319. tu->phy.otg->phy = &tu->phy;
  320. tu->phy.otg->set_host = tahvo_usb_set_host;
  321. tu->phy.otg->set_peripheral = tahvo_usb_set_peripheral;
  322. ret = usb_add_phy(&tu->phy, USB_PHY_TYPE_USB2);
  323. if (ret < 0) {
  324. dev_err(&pdev->dev, "cannot register USB transceiver: %d\n",
  325. ret);
  326. goto err_extcon_unreg;
  327. }
  328. dev_set_drvdata(&pdev->dev, tu);
  329. tu->irq = platform_get_irq(pdev, 0);
  330. ret = request_threaded_irq(tu->irq, NULL, tahvo_usb_vbus_interrupt, 0,
  331. "tahvo-vbus", tu);
  332. if (ret) {
  333. dev_err(&pdev->dev, "could not register tahvo-vbus irq: %d\n",
  334. ret);
  335. goto err_remove_phy;
  336. }
  337. /* Attributes */
  338. ret = sysfs_create_group(&pdev->dev.kobj, &tahvo_attr_group);
  339. if (ret) {
  340. dev_err(&pdev->dev, "cannot create sysfs group: %d\n", ret);
  341. goto err_free_irq;
  342. }
  343. return 0;
  344. err_free_irq:
  345. free_irq(tu->irq, tu);
  346. err_remove_phy:
  347. usb_remove_phy(&tu->phy);
  348. err_extcon_unreg:
  349. extcon_dev_unregister(&tu->extcon);
  350. err_disable_clk:
  351. if (!IS_ERR(tu->ick))
  352. clk_disable(tu->ick);
  353. return ret;
  354. }
  355. static int tahvo_usb_remove(struct platform_device *pdev)
  356. {
  357. struct tahvo_usb *tu = platform_get_drvdata(pdev);
  358. sysfs_remove_group(&pdev->dev.kobj, &tahvo_attr_group);
  359. free_irq(tu->irq, tu);
  360. usb_remove_phy(&tu->phy);
  361. extcon_dev_unregister(&tu->extcon);
  362. if (!IS_ERR(tu->ick))
  363. clk_disable(tu->ick);
  364. return 0;
  365. }
  366. static struct platform_driver tahvo_usb_driver = {
  367. .probe = tahvo_usb_probe,
  368. .remove = tahvo_usb_remove,
  369. .driver = {
  370. .name = "tahvo-usb",
  371. .owner = THIS_MODULE,
  372. },
  373. };
  374. module_platform_driver(tahvo_usb_driver);
  375. MODULE_DESCRIPTION("Tahvo USB transceiver driver");
  376. MODULE_LICENSE("GPL");
  377. MODULE_AUTHOR("Juha Yrjölä, Tony Lindgren, and Timo Teräs");
  378. MODULE_AUTHOR("Aaro Koskinen <aaro.koskinen@iki.fi>");