ohci_sunxi.c 23 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878
  1. #if 0
  2. /*
  3. * drivers/usb/host/ohci_sunxi.c
  4. * (C) Copyright 2010-2015
  5. * Allwinner Technology Co., Ltd. <www.allwinnertech.com>
  6. * yangnaitian, 2011-5-24, create this file
  7. * javen, 2011-6-26, add suspend and resume
  8. * javen, 2011-7-18, move clock and power operations out from driver
  9. *
  10. * OHCI Driver
  11. *
  12. * This program is free software; you can redistribute it and/or
  13. * modify it under the terms of the GNU General Public License as
  14. * published by the Free Software Foundation; either version 2 of
  15. * the License, or (at your option) any later version.
  16. *
  17. */
  18. #include <linux/platform_device.h>
  19. #include <linux/signal.h>
  20. #include <linux/time.h>
  21. #include <linux/timer.h>
  22. #include <linux/clk.h>
  23. #include <linux/notifier.h>
  24. #include <linux/suspend.h>
  25. #include "sunxi_hci.h"
  26. #if defined(CONFIG_ARCH_SUN50IW10)
  27. #include "../../clk/sunxi/clk-sun50iw10.h"
  28. #endif
  29. #define SUNXI_OHCI_NAME "sunxi-ohci"
  30. static const char ohci_name[] = SUNXI_OHCI_NAME;
  31. #if IS_ENABLED(CONFIG_USB_SUNXI_OHCI0)
  32. #define SUNXI_OHCI0_OF_MATCH "allwinner,sunxi-ohci0"
  33. #else
  34. #define SUNXI_OHCI0_OF_MATCH "null"
  35. #endif
  36. #if IS_ENABLED(CONFIG_USB_SUNXI_OHCI1)
  37. #define SUNXI_OHCI1_OF_MATCH "allwinner,sunxi-ohci1"
  38. #else
  39. #define SUNXI_OHCI1_OF_MATCH "null"
  40. #endif
  41. #if IS_ENABLED(CONFIG_USB_SUNXI_OHCI2)
  42. #define SUNXI_OHCI2_OF_MATCH "allwinner,sunxi-ohci2"
  43. #else
  44. #define SUNXI_OHCI2_OF_MATCH "null"
  45. #endif
  46. #if IS_ENABLED(CONFIG_USB_SUNXI_OHCI3)
  47. #define SUNXI_OHCI3_OF_MATCH "allwinner,sunxi-ohci3"
  48. #else
  49. #define SUNXI_OHCI3_OF_MATCH "null"
  50. #endif
  51. static struct sunxi_hci_hcd *g_sunxi_ohci[4];
  52. static u32 ohci_first_probe[4] = {1, 1, 1, 1};
  53. static u32 ohci_enable[4] = {1, 1, 1, 1};
  54. static atomic_t ohci_in_standby;
  55. #ifdef CONFIG_PM
  56. static void sunxi_ohci_resume_work(struct work_struct *work);
  57. #endif
  58. int sunxi_usb_disable_ohci(__u32 usbc_no);
  59. int sunxi_usb_enable_ohci(__u32 usbc_no);
  60. static ssize_t ohci_enable_show(struct device *dev,
  61. struct device_attribute *attr, char *buf)
  62. {
  63. struct sunxi_hci_hcd *sunxi_ohci = NULL;
  64. if (dev == NULL) {
  65. DMSG_PANIC("ERR: Argment is invalid\n");
  66. return 0;
  67. }
  68. sunxi_ohci = dev->platform_data;
  69. if (sunxi_ohci == NULL) {
  70. DMSG_PANIC("ERR: sw_ohci is null\n");
  71. return 0;
  72. }
  73. return sprintf(buf, "ohci:%d,probe:%u\n",
  74. sunxi_ohci->usbc_no, sunxi_ohci->probe);
  75. }
  76. static ssize_t ohci_enable_store(struct device *dev,
  77. struct device_attribute *attr,
  78. const char *buf, size_t count)
  79. {
  80. struct sunxi_hci_hcd *sunxi_ohci = NULL;
  81. int value = 0;
  82. int err;
  83. if (dev == NULL) {
  84. DMSG_PANIC("ERR: Argment is invalid\n");
  85. return 0;
  86. }
  87. sunxi_ohci = dev->platform_data;
  88. if (sunxi_ohci == NULL) {
  89. DMSG_PANIC("ERR: sw_ohci is null\n");
  90. return 0;
  91. }
  92. ohci_first_probe[sunxi_ohci->usbc_no] = 0;
  93. err = kstrtoint(buf, 10, &value);
  94. if (err != 0)
  95. return -EINVAL;
  96. if (value == 1) {
  97. ohci_enable[sunxi_ohci->usbc_no] = 0;
  98. sunxi_usb_enable_ohci(sunxi_ohci->usbc_no);
  99. if (sunxi_ohci->usbc_no == HCI0_USBC_NO)
  100. sunxi_set_host_vbus(sunxi_ohci, 1);
  101. } else if (value == 0) {
  102. ohci_enable[sunxi_ohci->usbc_no] = 1;
  103. sunxi_usb_disable_ohci(sunxi_ohci->usbc_no);
  104. ohci_enable[sunxi_ohci->usbc_no] = 0;
  105. } else {
  106. DMSG_INFO("unknown value (%d)\n", value);
  107. }
  108. return count;
  109. }
  110. static DEVICE_ATTR(ohci_enable, 0644, ohci_enable_show, ohci_enable_store);
  111. static int open_ohci_clock(struct sunxi_hci_hcd *sunxi_ohci)
  112. {
  113. return sunxi_ohci->open_clock(sunxi_ohci, 1);
  114. }
  115. static int close_ohci_clock(struct sunxi_hci_hcd *sunxi_ohci)
  116. {
  117. return sunxi_ohci->close_clock(sunxi_ohci, 1);
  118. }
  119. static void sunxi_ohci_set_vbus(struct sunxi_hci_hcd *sunxi_ohci, int is_on)
  120. {
  121. sunxi_ohci->set_power(sunxi_ohci, is_on);
  122. }
  123. static void sunxi_ohci_set_passby(struct sunxi_hci_hcd *sunxi_ohci, int is_on)
  124. {
  125. sunxi_ohci->usb_passby(sunxi_ohci, is_on);
  126. }
  127. static void sunxi_start_ohci(struct sunxi_hci_hcd *sunxi_ohci)
  128. {
  129. open_ohci_clock(sunxi_ohci);
  130. sunxi_ohci_set_passby(sunxi_ohci, 1);
  131. sunxi_ohci_set_vbus(sunxi_ohci, 1);
  132. }
  133. static void sunxi_stop_ohci(struct sunxi_hci_hcd *sunxi_ohci)
  134. {
  135. sunxi_ohci_set_vbus(sunxi_ohci, 0);
  136. sunxi_ohci_set_passby(sunxi_ohci, 0);
  137. close_ohci_clock(sunxi_ohci);
  138. }
  139. static int sunxi_ohci_start(struct usb_hcd *hcd)
  140. {
  141. struct ohci_hcd *ohci = hcd_to_ohci(hcd);
  142. int ret;
  143. ret = ohci_init(ohci);
  144. if (ret < 0)
  145. return ret;
  146. ret = ohci_run(ohci);
  147. if (ret < 0) {
  148. DMSG_PANIC("can't start %s", hcd->self.bus_name);
  149. ohci_stop(hcd);
  150. return ret;
  151. }
  152. return 0;
  153. }
  154. static int sunxi_ohci_pm_notify(struct notifier_block *nb,
  155. unsigned long mode, void *_unused)
  156. {
  157. switch (mode) {
  158. case PM_HIBERNATION_PREPARE:
  159. case PM_RESTORE_PREPARE:
  160. case PM_SUSPEND_PREPARE:
  161. atomic_set(&ohci_in_standby, 1);
  162. break;
  163. case PM_POST_HIBERNATION:
  164. case PM_POST_RESTORE:
  165. case PM_POST_SUSPEND:
  166. atomic_set(&ohci_in_standby, 0);
  167. sunxi_hci_standby_completion(SUNXI_USB_OHCI);
  168. break;
  169. default:
  170. break;
  171. }
  172. return 0;
  173. }
  174. static struct notifier_block sunxi_ohci_pm_nb = {
  175. .notifier_call = sunxi_ohci_pm_notify,
  176. };
  177. static const struct hc_driver sunxi_ohci_hc_driver = {
  178. .description = hcd_name,
  179. .product_desc = "SW USB2.0 'Open' Host Controller (OHCI) Driver",
  180. .hcd_priv_size = sizeof(struct ohci_hcd),
  181. /*
  182. * generic hardware linkage
  183. */
  184. .irq = ohci_irq,
  185. .flags = HCD_USB11 | HCD_MEMORY,
  186. /*
  187. * basic lifecycle operations
  188. */
  189. .start = sunxi_ohci_start,
  190. .stop = ohci_stop,
  191. .shutdown = ohci_shutdown,
  192. /*
  193. * managing i/o requests and associated device resources
  194. */
  195. .urb_enqueue = ohci_urb_enqueue,
  196. .urb_dequeue = ohci_urb_dequeue,
  197. .endpoint_disable = ohci_endpoint_disable,
  198. /*
  199. * scheduling support
  200. */
  201. .get_frame_number = ohci_get_frame,
  202. /*
  203. * root hub support
  204. */
  205. .hub_status_data = ohci_hub_status_data,
  206. .hub_control = ohci_hub_control,
  207. #ifdef CONFIG_PM
  208. .bus_suspend = ohci_bus_suspend,
  209. .bus_resume = ohci_bus_resume,
  210. #endif
  211. .start_port_reset = ohci_start_port_reset,
  212. };
  213. static int sunxi_insmod_ohci(struct platform_device *pdev)
  214. {
  215. int ret;
  216. struct usb_hcd *hcd = NULL;
  217. struct sunxi_hci_hcd *sunxi_ohci = NULL;
  218. #if defined(CONFIG_SUNXI_REGULATOR_DT)
  219. struct device *dev = NULL;
  220. #endif
  221. if (pdev == NULL) {
  222. DMSG_PANIC("ERR: Argment is invaild\n");
  223. return -1;
  224. }
  225. /* if usb is disabled, can not probe */
  226. if (usb_disabled()) {
  227. DMSG_PANIC("ERR: usb hcd is disabled\n");
  228. return -ENODEV;
  229. }
  230. sunxi_ohci = pdev->dev.platform_data;
  231. if (!sunxi_ohci) {
  232. DMSG_PANIC("ERR: sunxi_ohci is null\n");
  233. ret = -ENOMEM;
  234. goto ERR1;
  235. }
  236. sunxi_ohci->pdev = pdev;
  237. g_sunxi_ohci[sunxi_ohci->usbc_no] = sunxi_ohci;
  238. DMSG_INFO("[%s%d]: probe, pdev->name: %s, sunxi_ohci: 0x%p\n",
  239. ohci_name, sunxi_ohci->usbc_no, pdev->name, sunxi_ohci);
  240. sunxi_ohci->ohci_base = sunxi_ohci->usb_vbase +
  241. SUNXI_USB_OHCI_BASE_OFFSET;
  242. sunxi_ohci->ohci_reg_length = SUNXI_USB_OHCI_LEN;
  243. /* not init ohci, when driver probe */
  244. if (sunxi_ohci->usbc_no == HCI0_USBC_NO) {
  245. if (sunxi_ohci->port_type != USB_PORT_TYPE_HOST) {
  246. if (ohci_first_probe[sunxi_ohci->usbc_no]) {
  247. ohci_first_probe[sunxi_ohci->usbc_no] = 0;
  248. DMSG_INFO("[%s%d]: Not init ohci0\n",
  249. ohci_name, sunxi_ohci->usbc_no);
  250. return 0;
  251. }
  252. }
  253. }
  254. /* creat a usb_hcd for the ohci controller */
  255. hcd = usb_create_hcd(&sunxi_ohci_hc_driver, &pdev->dev, ohci_name);
  256. if (!hcd) {
  257. DMSG_PANIC("ERR: usb_ohci_create_hcd failed\n");
  258. ret = -ENOMEM;
  259. goto ERR2;
  260. }
  261. hcd->rsrc_start = sunxi_ohci->usb_base_res->start;
  262. hcd->rsrc_len = SUNXI_USB_OHCI_LEN;
  263. hcd->regs = sunxi_ohci->ohci_base;
  264. sunxi_ohci->hcd = hcd;
  265. #if defined(CONFIG_SUNXI_REGULATOR_DT)
  266. dev = &pdev->dev;
  267. sunxi_ohci->supply = regulator_get(dev, "drvvbus");
  268. if (IS_ERR(sunxi_ohci->supply)) {
  269. DMSG_PANIC("%s()%d WARN: get supply failed\n", __func__, __LINE__);
  270. sunxi_ohci->supply = NULL;
  271. }
  272. #endif
  273. /* ochi start to work */
  274. sunxi_start_ohci(sunxi_ohci);
  275. ohci_hcd_init(hcd_to_ohci(hcd));
  276. ret = usb_add_hcd(hcd, sunxi_ohci->irq_no, IRQF_SHARED);
  277. if (ret != 0) {
  278. DMSG_PANIC("ERR: usb_add_hcd failed\n");
  279. ret = -ENOMEM;
  280. goto ERR3;
  281. }
  282. device_wakeup_enable(hcd->self.controller);
  283. platform_set_drvdata(pdev, hcd);
  284. #ifndef USB_SYNC_SUSPEND
  285. device_enable_async_suspend(&pdev->dev);
  286. #endif
  287. #ifdef CONFIG_PM
  288. if (!sunxi_ohci->wakeup_suspend)
  289. INIT_WORK(&sunxi_ohci->resume_work, sunxi_ohci_resume_work);
  290. #endif
  291. sunxi_ohci->probe = 1;
  292. return 0;
  293. ERR3:
  294. sunxi_stop_ohci(sunxi_ohci);
  295. usb_put_hcd(hcd);
  296. ERR2:
  297. sunxi_ohci->hcd = NULL;
  298. ERR1:
  299. return ret;
  300. }
  301. static int sunxi_rmmod_ohci(struct platform_device *pdev)
  302. {
  303. struct usb_hcd *hcd = NULL;
  304. struct sunxi_hci_hcd *sunxi_ohci = NULL;
  305. unsigned long time_left;
  306. if (pdev == NULL) {
  307. DMSG_PANIC("ERR: Argment is invalid\n");
  308. return -1;
  309. }
  310. hcd = platform_get_drvdata(pdev);
  311. if (hcd == NULL) {
  312. DMSG_PANIC("ERR: hcd is null\n");
  313. return -1;
  314. }
  315. sunxi_ohci = pdev->dev.platform_data;
  316. if (sunxi_ohci == NULL) {
  317. DMSG_PANIC("ERR: sunxi_ohci is null\n");
  318. return -1;
  319. }
  320. if (atomic_read(&ohci_in_standby)) {
  321. reinit_completion(&sunxi_ohci->standby_complete);
  322. DMSG_INFO("INFO: sunxi_ohci disable, waiting until standby finish\n");
  323. time_left = wait_for_completion_timeout(&sunxi_ohci->standby_complete,
  324. msecs_to_jiffies(STANDBY_TIMEOUT));
  325. if (time_left)
  326. DMSG_INFO("INFO: sunxi_ohci disable time_left = %lu\n", time_left);
  327. else
  328. DMSG_PANIC("ERR: sunxi_ohci waiting standby failed, go on disable\n");
  329. }
  330. sunxi_ohci->probe = 0;
  331. DMSG_INFO("[%s%d]: remove, pdev->name: %s, sunxi_ohci: 0x%p\n",
  332. ohci_name, sunxi_ohci->usbc_no, pdev->name, sunxi_ohci);
  333. usb_remove_hcd(hcd);
  334. sunxi_stop_ohci(sunxi_ohci);
  335. usb_put_hcd(hcd);
  336. #if defined(CONFIG_SUNXI_REGULATOR_DT)
  337. if (sunxi_ohci->supply)
  338. regulator_put(sunxi_ohci->supply);
  339. #endif
  340. sunxi_ohci->hcd = NULL;
  341. return 0;
  342. }
  343. static int sunxi_ohci_hcd_probe(struct platform_device *pdev)
  344. {
  345. int ret = 0;
  346. #if defined(CONFIG_ARCH_SUN50IW10)
  347. int val = 0;
  348. #endif
  349. struct sunxi_hci_hcd *sunxi_ohci = NULL;
  350. if (pdev == NULL) {
  351. DMSG_PANIC("ERR: %s, Argment is invalid\n", __func__);
  352. return -1;
  353. }
  354. /* if usb is disabled, can not probe */
  355. if (usb_disabled()) {
  356. DMSG_PANIC("ERR: usb hcd is disabled\n");
  357. return -ENODEV;
  358. }
  359. ret = init_sunxi_hci(pdev, SUNXI_USB_OHCI);
  360. if (ret != 0) {
  361. dev_err(&pdev->dev, "init_sunxi_hci is fail\n");
  362. return -1;
  363. }
  364. sunxi_insmod_ohci(pdev);
  365. sunxi_ohci = pdev->dev.platform_data;
  366. if (sunxi_ohci == NULL) {
  367. DMSG_PANIC("ERR: %s, sunxi_ohci is null\n", __func__);
  368. return -1;
  369. }
  370. if (sunxi_ohci->usbc_no == HCI0_USBC_NO) {
  371. ret = register_pm_notifier(&sunxi_ohci_pm_nb);
  372. if (ret) {
  373. DMSG_PANIC("ERR: %s, can not register suspend notifier\n", __func__);
  374. return -1;
  375. }
  376. }
  377. init_completion(&sunxi_ohci->standby_complete);
  378. /* keep common circuit configuration when usb0 enable only*/
  379. #if defined(CONFIG_ARCH_SUN50IW10)
  380. if (sunxi_ohci->usbc_no == HCI0_USBC_NO) {
  381. /*phy reg, offset:0x10 bit3 set 0, enable siddq*/
  382. val = USBC_Readl(sunxi_ohci->usb_common_phy_config + SUNXI_HCI_PHY_CTRL);
  383. val &= ~(0x1 << SUNXI_HCI_PHY_CTRL_SIDDQ);
  384. USBC_Writel(val, sunxi_ohci->usb_common_phy_config + SUNXI_HCI_PHY_CTRL);
  385. }
  386. #endif
  387. if (ohci_enable[sunxi_ohci->usbc_no]) {
  388. device_create_file(&pdev->dev, &dev_attr_ohci_enable);
  389. ohci_enable[sunxi_ohci->usbc_no] = 0;
  390. }
  391. return 0;
  392. }
  393. static int sunxi_ohci_hcd_remove(struct platform_device *pdev)
  394. {
  395. struct sunxi_hci_hcd *sunxi_ohci = NULL;
  396. int ret = 0;
  397. if (pdev == NULL) {
  398. DMSG_PANIC("ERR: %s, Argment is invalid\n", __func__);
  399. return -1;
  400. }
  401. sunxi_ohci = pdev->dev.platform_data;
  402. if (sunxi_ohci == NULL) {
  403. DMSG_PANIC("ERR: %s, sunxi_ohci is null\n", __func__);
  404. return -1;
  405. }
  406. if (ohci_enable[sunxi_ohci->usbc_no] == 0)
  407. device_remove_file(&pdev->dev, &dev_attr_ohci_enable);
  408. if (sunxi_ohci->probe == 1) {
  409. ret = sunxi_rmmod_ohci(pdev);
  410. if (ret == 0)
  411. exit_sunxi_hci(sunxi_ohci);
  412. if (sunxi_ohci->usbc_no == HCI0_USBC_NO)
  413. unregister_pm_notifier(&sunxi_ohci_pm_nb);
  414. return ret;
  415. } else
  416. return 0;
  417. }
  418. static void sunxi_ohci_hcd_shutdown(struct platform_device *pdev)
  419. {
  420. struct sunxi_hci_hcd *sunxi_ohci = NULL;
  421. sunxi_ohci = pdev->dev.platform_data;
  422. if (sunxi_ohci == NULL) {
  423. DMSG_PANIC("ERR: %s sunxi_ohci is null\n", __func__);
  424. return;
  425. }
  426. if (sunxi_ohci->probe == 0) {
  427. DMSG_INFO("%s, %s is disable, need not shutdown\n",
  428. __func__, sunxi_ohci->hci_name);
  429. return;
  430. }
  431. pr_debug("[%s]: ohci shutdown start\n", sunxi_ohci->hci_name);
  432. usb_hcd_platform_shutdown(pdev);
  433. /**
  434. * disable usb otg INTUSBE, to solve usb0 device mode
  435. * catch audio udev on reboot system is fail.
  436. */
  437. if (sunxi_ohci->usbc_no == 0)
  438. if (sunxi_ohci->otg_vbase) {
  439. writel(0, (sunxi_ohci->otg_vbase
  440. + SUNXI_USBC_REG_INTUSBE));
  441. }
  442. pr_debug("[%s]: ohci shutdown end\n", sunxi_ohci->hci_name);
  443. }
  444. #ifdef CONFIG_PM
  445. static int sunxi_ohci_hcd_suspend(struct device *dev)
  446. {
  447. struct sunxi_hci_hcd *sunxi_ohci = NULL;
  448. struct usb_hcd *hcd = NULL;
  449. struct ohci_hcd *ohci = NULL;
  450. int val = 0;
  451. if (dev == NULL) {
  452. DMSG_PANIC("ERR: Argment is invalid\n");
  453. return 0;
  454. }
  455. hcd = dev_get_drvdata(dev);
  456. if (hcd == NULL) {
  457. DMSG_PANIC("ERR: hcd is null\n");
  458. return 0;
  459. }
  460. sunxi_ohci = dev->platform_data;
  461. if (sunxi_ohci == NULL) {
  462. DMSG_PANIC("ERR: sunxi_ohci is null\n");
  463. return 0;
  464. }
  465. if (sunxi_ohci->no_suspend) {
  466. DMSG_INFO("[%s]:ohci is being enable, stop system suspend\n",
  467. sunxi_ohci->hci_name);
  468. return -1;
  469. }
  470. if (sunxi_ohci->probe == 0) {
  471. DMSG_INFO("[%s]: is disable, can not suspend\n",
  472. sunxi_ohci->hci_name);
  473. return 0;
  474. }
  475. ohci = hcd_to_ohci(hcd);
  476. if (ohci == NULL) {
  477. DMSG_PANIC("ERR: ohci is null\n");
  478. return 0;
  479. }
  480. if (sunxi_ohci->wakeup_suspend == USB_STANDBY) {
  481. DMSG_INFO("[%s] usb suspend\n", sunxi_ohci->hci_name);
  482. val = ohci_readl(ohci, &ohci->regs->control);
  483. val |= OHCI_CTRL_RWE;
  484. ohci_writel(ohci, val, &ohci->regs->control);
  485. val = ohci_readl(ohci, &ohci->regs->intrenable);
  486. val |= OHCI_INTR_RD;
  487. val |= OHCI_INTR_MIE;
  488. ohci_writel(ohci, val, &ohci->regs->intrenable);
  489. #ifdef SUNXI_USB_STANDBY_LOW_POW_MODE
  490. val = ohci_readl(ohci, &ohci->regs->control);
  491. val |= OHCI_USB_SUSPEND;
  492. ohci_writel(ohci, val, &ohci->regs->control);
  493. #ifdef SUNXI_USB_STANDBY_NEW_MODE
  494. /*phy reg, offset:0x0 bit2, set 1, enable RC16M CLK*/
  495. sunxi_hci_set_rc_clk(sunxi_ohci, 1);
  496. #endif
  497. /*phy reg, offset:0x08 bit3, set 1, remote enable*/
  498. sunxi_hci_set_wakeup_ctrl(sunxi_ohci, 1);
  499. /*phy reg, offset:0x10 bit3 set 1, clean siddq*/
  500. sunxi_hci_set_siddq(sunxi_ohci, 1);
  501. #endif
  502. #if defined(CONFIG_ARCH_SUN50IW10)
  503. /*phy reg, offset:0x0 bit31, set 1*/
  504. val = USBC_Readl(sunxi_ohci->usb_vbase + SUNXI_USB_PMU_IRQ_ENABLE);
  505. val |= (0x1 << 31);
  506. USBC_Writel(val, sunxi_ohci->usb_vbase + SUNXI_USB_PMU_IRQ_ENABLE);
  507. /*phy reg, offset:0x0 bit3, set 1*/
  508. val = USBC_Readl(sunxi_ohci->usb_vbase + SUNXI_USB_PMU_IRQ_ENABLE);
  509. val |= (0x1 << 3);
  510. USBC_Writel(val, sunxi_ohci->usb_vbase + SUNXI_USB_PMU_IRQ_ENABLE);
  511. /*prcm, offset:0x0 bit3, set 1*/
  512. val = USBC_Readl(sunxi_ohci->prcm);
  513. val |= (0x1 << 3);
  514. USBC_Writel(val, sunxi_ohci->prcm);
  515. #endif
  516. if (sunxi_ohci->clk_usbohci12m && sunxi_ohci->clk_losc)
  517. clk_set_parent(sunxi_ohci->clk_usbohci12m,
  518. sunxi_ohci->clk_losc);
  519. } else {
  520. DMSG_INFO("[%s]super suspend\n", sunxi_ohci->hci_name);
  521. atomic_add(1, &g_sunxi_usb_super_standby);
  522. /**
  523. * Root hub was already suspended. Disable irq emission and
  524. * mark HW unaccessible, bail out if RH has been resumed. Use
  525. * the spinlock to properly synchronize with possible pending
  526. * RH suspend or resume activity.
  527. *
  528. * This is still racy as hcd->state is manipulated outside of
  529. * any locks =P But that will be a different fix.
  530. */
  531. ohci_suspend(hcd, device_may_wakeup(dev));
  532. sunxi_stop_ohci(sunxi_ohci);
  533. sunxi_hci_set_siddq(sunxi_ohci, 1);
  534. cancel_work_sync(&sunxi_ohci->resume_work);
  535. }
  536. return 0;
  537. }
  538. static void sunxi_ohci_resume_work(struct work_struct *work)
  539. {
  540. struct sunxi_hci_hcd *sunxi_ohci = NULL;
  541. sunxi_ohci = container_of(work, struct sunxi_hci_hcd, resume_work);
  542. /* Waiting hci to resume. */
  543. msleep(5000);
  544. sunxi_ohci_set_vbus(sunxi_ohci, 1);
  545. atomic_sub(1, &g_sunxi_usb_super_standby);
  546. }
  547. static int sunxi_ohci_hcd_resume(struct device *dev)
  548. {
  549. struct sunxi_hci_hcd *sunxi_ohci = NULL;
  550. struct usb_hcd *hcd = NULL;
  551. struct ohci_hcd *ohci = NULL;
  552. #ifdef SUNXI_USB_STANDBY_LOW_POW_MODE
  553. int val = 0;
  554. #endif
  555. if (dev == NULL) {
  556. DMSG_PANIC("ERR: Argment is invalid\n");
  557. return 0;
  558. }
  559. hcd = dev_get_drvdata(dev);
  560. if (hcd == NULL) {
  561. DMSG_PANIC("ERR: hcd is null\n");
  562. return 0;
  563. }
  564. sunxi_ohci = dev->platform_data;
  565. if (sunxi_ohci == NULL) {
  566. DMSG_PANIC("ERR: sunxi_ohci is null\n");
  567. return 0;
  568. }
  569. if (sunxi_ohci->probe == 0) {
  570. DMSG_INFO("[%s]: is disable, can not resume\n",
  571. sunxi_ohci->hci_name);
  572. return 0;
  573. }
  574. ohci = hcd_to_ohci(hcd);
  575. if (ohci == NULL) {
  576. DMSG_PANIC("ERR: ohci is null\n");
  577. return 0;
  578. }
  579. if (sunxi_ohci->wakeup_suspend == USB_STANDBY) {
  580. DMSG_INFO("[%s]usb resume\n", sunxi_ohci->hci_name);
  581. if (sunxi_ohci->clk_usbohci12m && sunxi_ohci->clk_hoscx2)
  582. clk_set_parent(sunxi_ohci->clk_usbohci12m,
  583. sunxi_ohci->clk_hoscx2);
  584. #if defined(CONFIG_ARCH_SUN50IW10)
  585. /*prcm, offset:0x0 bit3, set 0*/
  586. val = USBC_Readl(sunxi_ohci->prcm);
  587. val &= ~(0x1 << 3);
  588. USBC_Writel(val, sunxi_ohci->prcm);
  589. /*phy reg, offset:0x0 bit3, set 0*/
  590. val = USBC_Readl(sunxi_ohci->usb_vbase + SUNXI_USB_PMU_IRQ_ENABLE);
  591. val &= ~(0x1 << 3);
  592. USBC_Writel(val, sunxi_ohci->usb_vbase + SUNXI_USB_PMU_IRQ_ENABLE);
  593. /*phy reg, offset:0x0 bit31, set 0*/
  594. val = USBC_Readl(sunxi_ohci->usb_vbase + SUNXI_USB_PMU_IRQ_ENABLE);
  595. val &= ~(0x1 << 31);
  596. USBC_Writel(val, sunxi_ohci->usb_vbase + SUNXI_USB_PMU_IRQ_ENABLE);
  597. #endif
  598. #ifdef SUNXI_USB_STANDBY_LOW_POW_MODE
  599. /*phy reg, offset:0x10 bit3 set 0, enable siddq*/
  600. sunxi_hci_set_siddq(sunxi_ohci, 0);
  601. /*phy reg, offset:0x08 bit3, set 0, remote disable*/
  602. sunxi_hci_set_wakeup_ctrl(sunxi_ohci, 0);
  603. #ifdef SUNXI_USB_STANDBY_NEW_MODE
  604. /*disable rc clk*/
  605. /*phy reg, offset:0x0 bit2, set 0, disable rc clk*/
  606. sunxi_hci_set_rc_clk(sunxi_ohci, 0);
  607. #endif
  608. val = ohci_readl(ohci, &ohci->regs->control);
  609. val &= ~(OHCI_USB_SUSPEND);
  610. ohci_writel(ohci, val, &ohci->regs->control);
  611. #endif
  612. } else {
  613. DMSG_INFO("[%s]super resume\n", sunxi_ohci->hci_name);
  614. sunxi_hci_set_siddq(sunxi_ohci, 0);
  615. open_ohci_clock(sunxi_ohci);
  616. sunxi_ohci_set_passby(sunxi_ohci, 1);
  617. set_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags);
  618. ohci_resume(hcd, false);
  619. #if defined(CONFIG_ARCH_SUN50IW10)
  620. if (sunxi_ohci->usbc_no == HCI0_USBC_NO) {
  621. /*phy reg, offset:0x10 bit3 set 0, enable siddq*/
  622. val = USBC_Readl(sunxi_ohci->usb_common_phy_config + SUNXI_HCI_PHY_CTRL);
  623. val &= ~(0x1 << SUNXI_HCI_PHY_CTRL_SIDDQ);
  624. USBC_Writel(val, sunxi_ohci->usb_common_phy_config + SUNXI_HCI_PHY_CTRL);
  625. }
  626. #endif
  627. schedule_work(&sunxi_ohci->resume_work);
  628. }
  629. return 0;
  630. }
  631. static const struct dev_pm_ops sunxi_ohci_pmops = {
  632. .suspend = sunxi_ohci_hcd_suspend,
  633. .resume = sunxi_ohci_hcd_resume,
  634. };
  635. #define SUNXI_OHCI_PMOPS (&sunxi_ohci_pmops)
  636. #else
  637. #define SUNXI_OHCI_PMOPS NULL
  638. #endif
  639. static const struct of_device_id sunxi_ohci_match[] = {
  640. {.compatible = SUNXI_OHCI0_OF_MATCH, },
  641. {.compatible = SUNXI_OHCI1_OF_MATCH, },
  642. {.compatible = SUNXI_OHCI2_OF_MATCH, },
  643. {.compatible = SUNXI_OHCI3_OF_MATCH, },
  644. {},
  645. };
  646. MODULE_DEVICE_TABLE(of, sunxi_ohci_match);
  647. static struct platform_driver sunxi_ohci_hcd_driver = {
  648. .probe = sunxi_ohci_hcd_probe,
  649. .remove = sunxi_ohci_hcd_remove,
  650. .shutdown = sunxi_ohci_hcd_shutdown,
  651. .driver = {
  652. .name = ohci_name,
  653. .owner = THIS_MODULE,
  654. .pm = SUNXI_OHCI_PMOPS,
  655. .of_match_table = sunxi_ohci_match,
  656. },
  657. };
  658. int sunxi_usb_disable_ohci(__u32 usbc_no)
  659. {
  660. struct sunxi_hci_hcd *sunxi_ohci = NULL;
  661. sunxi_ohci = g_sunxi_ohci[usbc_no];
  662. if (sunxi_ohci == NULL) {
  663. DMSG_PANIC("ERR: sunxi_ohci is null\n");
  664. return -1;
  665. }
  666. if (sunxi_ohci->probe == 0) {
  667. DMSG_PANIC("ERR: sunxi_ohci is disable, can not disable again\n");
  668. return -1;
  669. }
  670. sunxi_ohci->probe = 0;
  671. DMSG_INFO("[%s]: sunxi_usb_disable_ohci\n", sunxi_ohci->hci_name);
  672. sunxi_rmmod_ohci(sunxi_ohci->pdev);
  673. return 0;
  674. }
  675. EXPORT_SYMBOL(sunxi_usb_disable_ohci);
  676. int sunxi_usb_enable_ohci(__u32 usbc_no)
  677. {
  678. struct sunxi_hci_hcd *sunxi_ohci = NULL;
  679. #if defined(CONFIG_ARCH_SUN50IW10)
  680. int val;
  681. #endif
  682. sunxi_ohci = g_sunxi_ohci[usbc_no];
  683. if (sunxi_ohci == NULL) {
  684. DMSG_PANIC("ERR: sunxi_ohci is null\n");
  685. return -1;
  686. }
  687. if (sunxi_ohci->probe == 1) {
  688. DMSG_PANIC("ERR: sunxi_ohci is already enable, can not enable again\n");
  689. return -1;
  690. }
  691. sunxi_ohci->no_suspend = 1;
  692. DMSG_INFO("[%s]: sunxi_usb_enable_ohci\n", sunxi_ohci->hci_name);
  693. #if defined(CONFIG_ARCH_SUN50IW10)
  694. if (sunxi_ohci->usbc_no == HCI0_USBC_NO) {
  695. /*phy reg, offset:0x10 bit3 set 0, enable siddq*/
  696. val = USBC_Readl(sunxi_ohci->usb_common_phy_config + SUNXI_HCI_PHY_CTRL);
  697. val &= ~(0x1 << SUNXI_HCI_PHY_CTRL_SIDDQ);
  698. USBC_Writel(val, sunxi_ohci->usb_common_phy_config + SUNXI_HCI_PHY_CTRL);
  699. }
  700. #endif
  701. sunxi_insmod_ohci(sunxi_ohci->pdev);
  702. sunxi_ohci->no_suspend = 0;
  703. return 0;
  704. }
  705. EXPORT_SYMBOL(sunxi_usb_enable_ohci);
  706. #endif