phy-mapphone-mdm6600.c 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673
  1. // SPDX-License-Identifier: GPL-2.0
  2. /*
  3. * Motorola Mapphone MDM6600 modem GPIO controlled USB PHY driver
  4. * Copyright (C) 2018 Tony Lindgren <[email protected]>
  5. */
  6. #include <linux/delay.h>
  7. #include <linux/err.h>
  8. #include <linux/io.h>
  9. #include <linux/interrupt.h>
  10. #include <linux/module.h>
  11. #include <linux/of.h>
  12. #include <linux/platform_device.h>
  13. #include <linux/slab.h>
  14. #include <linux/gpio/consumer.h>
  15. #include <linux/of_platform.h>
  16. #include <linux/phy/phy.h>
  17. #include <linux/pinctrl/consumer.h>
  18. #define PHY_MDM6600_PHY_DELAY_MS 4000 /* PHY enable 2.2s to 3.5s */
  19. #define PHY_MDM6600_ENABLED_DELAY_MS 8000 /* 8s more total for MDM6600 */
  20. #define PHY_MDM6600_WAKE_KICK_MS 600 /* time on after GPIO toggle */
  21. #define MDM6600_MODEM_IDLE_DELAY_MS 1000 /* modem after USB suspend */
  22. #define MDM6600_MODEM_WAKE_DELAY_MS 200 /* modem response after idle */
  23. enum phy_mdm6600_ctrl_lines {
  24. PHY_MDM6600_ENABLE, /* USB PHY enable */
  25. PHY_MDM6600_POWER, /* Device power */
  26. PHY_MDM6600_RESET, /* Device reset */
  27. PHY_MDM6600_NR_CTRL_LINES,
  28. };
  29. enum phy_mdm6600_bootmode_lines {
  30. PHY_MDM6600_MODE0, /* out USB mode0 and OOB wake */
  31. PHY_MDM6600_MODE1, /* out USB mode1, in OOB wake */
  32. PHY_MDM6600_NR_MODE_LINES,
  33. };
  34. enum phy_mdm6600_cmd_lines {
  35. PHY_MDM6600_CMD0,
  36. PHY_MDM6600_CMD1,
  37. PHY_MDM6600_CMD2,
  38. PHY_MDM6600_NR_CMD_LINES,
  39. };
  40. enum phy_mdm6600_status_lines {
  41. PHY_MDM6600_STATUS0,
  42. PHY_MDM6600_STATUS1,
  43. PHY_MDM6600_STATUS2,
  44. PHY_MDM6600_NR_STATUS_LINES,
  45. };
  46. /*
  47. * MDM6600 command codes. These are based on Motorola Mapphone Linux
  48. * kernel tree.
  49. */
  50. enum phy_mdm6600_cmd {
  51. PHY_MDM6600_CMD_BP_PANIC_ACK,
  52. PHY_MDM6600_CMD_DATA_ONLY_BYPASS, /* Reroute USB to CPCAP PHY */
  53. PHY_MDM6600_CMD_FULL_BYPASS, /* Reroute USB to CPCAP PHY */
  54. PHY_MDM6600_CMD_NO_BYPASS, /* Request normal USB mode */
  55. PHY_MDM6600_CMD_BP_SHUTDOWN_REQ, /* Request device power off */
  56. PHY_MDM6600_CMD_BP_UNKNOWN_5,
  57. PHY_MDM6600_CMD_BP_UNKNOWN_6,
  58. PHY_MDM6600_CMD_UNDEFINED,
  59. };
  60. /*
  61. * MDM6600 status codes. These are based on Motorola Mapphone Linux
  62. * kernel tree.
  63. */
  64. enum phy_mdm6600_status {
  65. PHY_MDM6600_STATUS_PANIC, /* Seems to be really off */
  66. PHY_MDM6600_STATUS_PANIC_BUSY_WAIT,
  67. PHY_MDM6600_STATUS_QC_DLOAD,
  68. PHY_MDM6600_STATUS_RAM_DOWNLOADER, /* MDM6600 USB flashing mode */
  69. PHY_MDM6600_STATUS_PHONE_CODE_AWAKE, /* MDM6600 normal USB mode */
  70. PHY_MDM6600_STATUS_PHONE_CODE_ASLEEP,
  71. PHY_MDM6600_STATUS_SHUTDOWN_ACK,
  72. PHY_MDM6600_STATUS_UNDEFINED,
  73. };
  74. static const char * const
  75. phy_mdm6600_status_name[] = {
  76. "off", "busy", "qc_dl", "ram_dl", "awake",
  77. "asleep", "shutdown", "undefined",
  78. };
  79. struct phy_mdm6600 {
  80. struct device *dev;
  81. struct phy *generic_phy;
  82. struct phy_provider *phy_provider;
  83. struct gpio_desc *ctrl_gpios[PHY_MDM6600_NR_CTRL_LINES];
  84. struct gpio_descs *mode_gpios;
  85. struct gpio_descs *status_gpios;
  86. struct gpio_descs *cmd_gpios;
  87. struct delayed_work bootup_work;
  88. struct delayed_work status_work;
  89. struct delayed_work modem_wake_work;
  90. struct completion ack;
  91. bool enabled; /* mdm6600 phy enabled */
  92. bool running; /* mdm6600 boot done */
  93. bool awake; /* mdm6600 respnds on n_gsm */
  94. int status;
  95. };
  96. static int phy_mdm6600_init(struct phy *x)
  97. {
  98. struct phy_mdm6600 *ddata = phy_get_drvdata(x);
  99. struct gpio_desc *enable_gpio = ddata->ctrl_gpios[PHY_MDM6600_ENABLE];
  100. if (!ddata->enabled)
  101. return -EPROBE_DEFER;
  102. gpiod_set_value_cansleep(enable_gpio, 0);
  103. return 0;
  104. }
  105. static int phy_mdm6600_power_on(struct phy *x)
  106. {
  107. struct phy_mdm6600 *ddata = phy_get_drvdata(x);
  108. struct gpio_desc *enable_gpio = ddata->ctrl_gpios[PHY_MDM6600_ENABLE];
  109. if (!ddata->enabled)
  110. return -ENODEV;
  111. gpiod_set_value_cansleep(enable_gpio, 1);
  112. /* Allow aggressive PM for USB, it's only needed for n_gsm port */
  113. if (pm_runtime_enabled(&x->dev))
  114. phy_pm_runtime_put(x);
  115. return 0;
  116. }
  117. static int phy_mdm6600_power_off(struct phy *x)
  118. {
  119. struct phy_mdm6600 *ddata = phy_get_drvdata(x);
  120. struct gpio_desc *enable_gpio = ddata->ctrl_gpios[PHY_MDM6600_ENABLE];
  121. int error;
  122. if (!ddata->enabled)
  123. return -ENODEV;
  124. /* Paired with phy_pm_runtime_put() in phy_mdm6600_power_on() */
  125. if (pm_runtime_enabled(&x->dev)) {
  126. error = phy_pm_runtime_get(x);
  127. if (error < 0 && error != -EINPROGRESS)
  128. dev_warn(ddata->dev, "%s: phy_pm_runtime_get: %i\n",
  129. __func__, error);
  130. }
  131. gpiod_set_value_cansleep(enable_gpio, 0);
  132. return 0;
  133. }
  134. static const struct phy_ops gpio_usb_ops = {
  135. .init = phy_mdm6600_init,
  136. .power_on = phy_mdm6600_power_on,
  137. .power_off = phy_mdm6600_power_off,
  138. .owner = THIS_MODULE,
  139. };
  140. /**
  141. * phy_mdm6600_cmd() - send a command request to mdm6600
  142. * @ddata: device driver data
  143. * @val: value of cmd to be set
  144. *
  145. * Configures the three command request GPIOs to the specified value.
  146. */
  147. static void phy_mdm6600_cmd(struct phy_mdm6600 *ddata, int val)
  148. {
  149. DECLARE_BITMAP(values, PHY_MDM6600_NR_CMD_LINES);
  150. values[0] = val;
  151. gpiod_set_array_value_cansleep(PHY_MDM6600_NR_CMD_LINES,
  152. ddata->cmd_gpios->desc,
  153. ddata->cmd_gpios->info, values);
  154. }
  155. /**
  156. * phy_mdm6600_status() - read mdm6600 status lines
  157. * @work: work structure
  158. */
  159. static void phy_mdm6600_status(struct work_struct *work)
  160. {
  161. struct phy_mdm6600 *ddata;
  162. struct device *dev;
  163. DECLARE_BITMAP(values, PHY_MDM6600_NR_STATUS_LINES);
  164. int error;
  165. ddata = container_of(work, struct phy_mdm6600, status_work.work);
  166. dev = ddata->dev;
  167. error = gpiod_get_array_value_cansleep(PHY_MDM6600_NR_STATUS_LINES,
  168. ddata->status_gpios->desc,
  169. ddata->status_gpios->info,
  170. values);
  171. if (error)
  172. return;
  173. ddata->status = values[0] & ((1 << PHY_MDM6600_NR_STATUS_LINES) - 1);
  174. dev_info(dev, "modem status: %i %s\n",
  175. ddata->status,
  176. phy_mdm6600_status_name[ddata->status]);
  177. complete(&ddata->ack);
  178. }
  179. static irqreturn_t phy_mdm6600_irq_thread(int irq, void *data)
  180. {
  181. struct phy_mdm6600 *ddata = data;
  182. schedule_delayed_work(&ddata->status_work, msecs_to_jiffies(10));
  183. return IRQ_HANDLED;
  184. }
  185. /**
  186. * phy_mdm6600_wakeirq_thread - handle mode1 line OOB wake after booting
  187. * @irq: interrupt
  188. * @data: interrupt handler data
  189. *
  190. * GPIO mode1 is used initially as output to configure the USB boot
  191. * mode for mdm6600. After booting it is used as input for OOB wake
  192. * signal from mdm6600 to the SoC. Just use it for debug info only
  193. * for now.
  194. */
  195. static irqreturn_t phy_mdm6600_wakeirq_thread(int irq, void *data)
  196. {
  197. struct phy_mdm6600 *ddata = data;
  198. struct gpio_desc *mode_gpio1;
  199. int error, wakeup;
  200. mode_gpio1 = ddata->mode_gpios->desc[PHY_MDM6600_MODE1];
  201. wakeup = gpiod_get_value(mode_gpio1);
  202. if (!wakeup)
  203. return IRQ_NONE;
  204. dev_dbg(ddata->dev, "OOB wake on mode_gpio1: %i\n", wakeup);
  205. error = pm_runtime_get_sync(ddata->dev);
  206. if (error < 0) {
  207. pm_runtime_put_noidle(ddata->dev);
  208. return IRQ_NONE;
  209. }
  210. /* Just wake-up and kick the autosuspend timer */
  211. pm_runtime_mark_last_busy(ddata->dev);
  212. pm_runtime_put_autosuspend(ddata->dev);
  213. return IRQ_HANDLED;
  214. }
  215. /**
  216. * phy_mdm6600_init_irq() - initialize mdm6600 status IRQ lines
  217. * @ddata: device driver data
  218. */
  219. static void phy_mdm6600_init_irq(struct phy_mdm6600 *ddata)
  220. {
  221. struct device *dev = ddata->dev;
  222. int i, error, irq;
  223. for (i = PHY_MDM6600_STATUS0;
  224. i <= PHY_MDM6600_STATUS2; i++) {
  225. struct gpio_desc *gpio = ddata->status_gpios->desc[i];
  226. irq = gpiod_to_irq(gpio);
  227. if (irq <= 0)
  228. continue;
  229. error = devm_request_threaded_irq(dev, irq, NULL,
  230. phy_mdm6600_irq_thread,
  231. IRQF_TRIGGER_RISING |
  232. IRQF_TRIGGER_FALLING |
  233. IRQF_ONESHOT,
  234. "mdm6600",
  235. ddata);
  236. if (error)
  237. dev_warn(dev, "no modem status irq%i: %i\n",
  238. irq, error);
  239. }
  240. }
  241. struct phy_mdm6600_map {
  242. const char *name;
  243. int direction;
  244. };
  245. static const struct phy_mdm6600_map
  246. phy_mdm6600_ctrl_gpio_map[PHY_MDM6600_NR_CTRL_LINES] = {
  247. { "enable", GPIOD_OUT_LOW, }, /* low = phy disabled */
  248. { "power", GPIOD_OUT_LOW, }, /* low = off */
  249. { "reset", GPIOD_OUT_HIGH, }, /* high = reset */
  250. };
  251. /**
  252. * phy_mdm6600_init_lines() - initialize mdm6600 GPIO lines
  253. * @ddata: device driver data
  254. */
  255. static int phy_mdm6600_init_lines(struct phy_mdm6600 *ddata)
  256. {
  257. struct device *dev = ddata->dev;
  258. int i;
  259. /* MDM6600 control lines */
  260. for (i = 0; i < ARRAY_SIZE(phy_mdm6600_ctrl_gpio_map); i++) {
  261. const struct phy_mdm6600_map *map =
  262. &phy_mdm6600_ctrl_gpio_map[i];
  263. struct gpio_desc **gpio = &ddata->ctrl_gpios[i];
  264. *gpio = devm_gpiod_get(dev, map->name, map->direction);
  265. if (IS_ERR(*gpio)) {
  266. dev_info(dev, "gpio %s error %li\n",
  267. map->name, PTR_ERR(*gpio));
  268. return PTR_ERR(*gpio);
  269. }
  270. }
  271. /* MDM6600 USB start-up mode output lines */
  272. ddata->mode_gpios = devm_gpiod_get_array(dev, "motorola,mode",
  273. GPIOD_OUT_LOW);
  274. if (IS_ERR(ddata->mode_gpios))
  275. return PTR_ERR(ddata->mode_gpios);
  276. if (ddata->mode_gpios->ndescs != PHY_MDM6600_NR_MODE_LINES)
  277. return -EINVAL;
  278. /* MDM6600 status input lines */
  279. ddata->status_gpios = devm_gpiod_get_array(dev, "motorola,status",
  280. GPIOD_IN);
  281. if (IS_ERR(ddata->status_gpios))
  282. return PTR_ERR(ddata->status_gpios);
  283. if (ddata->status_gpios->ndescs != PHY_MDM6600_NR_STATUS_LINES)
  284. return -EINVAL;
  285. /* MDM6600 cmd output lines */
  286. ddata->cmd_gpios = devm_gpiod_get_array(dev, "motorola,cmd",
  287. GPIOD_OUT_LOW);
  288. if (IS_ERR(ddata->cmd_gpios))
  289. return PTR_ERR(ddata->cmd_gpios);
  290. if (ddata->cmd_gpios->ndescs != PHY_MDM6600_NR_CMD_LINES)
  291. return -EINVAL;
  292. return 0;
  293. }
  294. /**
  295. * phy_mdm6600_device_power_on() - power on mdm6600 device
  296. * @ddata: device driver data
  297. *
  298. * To get the integrated USB phy in MDM6600 takes some hoops. We must ensure
  299. * the shared USB bootmode GPIOs are configured, then request modem start-up,
  300. * reset and power-up.. And then we need to recycle the shared USB bootmode
  301. * GPIOs as they are also used for Out of Band (OOB) wake for the USB and
  302. * TS 27.010 serial mux.
  303. */
  304. static int phy_mdm6600_device_power_on(struct phy_mdm6600 *ddata)
  305. {
  306. struct gpio_desc *mode_gpio0, *mode_gpio1, *reset_gpio, *power_gpio;
  307. int error = 0, wakeirq;
  308. mode_gpio0 = ddata->mode_gpios->desc[PHY_MDM6600_MODE0];
  309. mode_gpio1 = ddata->mode_gpios->desc[PHY_MDM6600_MODE1];
  310. reset_gpio = ddata->ctrl_gpios[PHY_MDM6600_RESET];
  311. power_gpio = ddata->ctrl_gpios[PHY_MDM6600_POWER];
  312. /*
  313. * Shared GPIOs must be low for normal USB mode. After booting
  314. * they are used for OOB wake signaling. These can be also used
  315. * to configure USB flashing mode later on based on a module
  316. * parameter.
  317. */
  318. gpiod_set_value_cansleep(mode_gpio0, 0);
  319. gpiod_set_value_cansleep(mode_gpio1, 0);
  320. /* Request start-up mode */
  321. phy_mdm6600_cmd(ddata, PHY_MDM6600_CMD_NO_BYPASS);
  322. /* Request a reset first */
  323. gpiod_set_value_cansleep(reset_gpio, 0);
  324. msleep(100);
  325. /* Toggle power GPIO to request mdm6600 to start */
  326. gpiod_set_value_cansleep(power_gpio, 1);
  327. msleep(100);
  328. gpiod_set_value_cansleep(power_gpio, 0);
  329. /*
  330. * Looks like the USB PHY needs between 2.2 to 4 seconds.
  331. * If we try to use it before that, we will get L3 errors
  332. * from omap-usb-host trying to access the PHY. See also
  333. * phy_mdm6600_init() for -EPROBE_DEFER.
  334. */
  335. msleep(PHY_MDM6600_PHY_DELAY_MS);
  336. ddata->enabled = true;
  337. /* Booting up the rest of MDM6600 will take total about 8 seconds */
  338. dev_info(ddata->dev, "Waiting for power up request to complete..\n");
  339. if (wait_for_completion_timeout(&ddata->ack,
  340. msecs_to_jiffies(PHY_MDM6600_ENABLED_DELAY_MS))) {
  341. if (ddata->status > PHY_MDM6600_STATUS_PANIC &&
  342. ddata->status < PHY_MDM6600_STATUS_SHUTDOWN_ACK)
  343. dev_info(ddata->dev, "Powered up OK\n");
  344. } else {
  345. ddata->enabled = false;
  346. error = -ETIMEDOUT;
  347. dev_err(ddata->dev, "Timed out powering up\n");
  348. }
  349. /* Reconfigure mode1 GPIO as input for OOB wake */
  350. gpiod_direction_input(mode_gpio1);
  351. wakeirq = gpiod_to_irq(mode_gpio1);
  352. if (wakeirq <= 0)
  353. return wakeirq;
  354. error = devm_request_threaded_irq(ddata->dev, wakeirq, NULL,
  355. phy_mdm6600_wakeirq_thread,
  356. IRQF_TRIGGER_RISING |
  357. IRQF_TRIGGER_FALLING |
  358. IRQF_ONESHOT,
  359. "mdm6600-wake",
  360. ddata);
  361. if (error)
  362. dev_warn(ddata->dev, "no modem wakeirq irq%i: %i\n",
  363. wakeirq, error);
  364. ddata->running = true;
  365. return error;
  366. }
  367. /**
  368. * phy_mdm6600_device_power_off() - power off mdm6600 device
  369. * @ddata: device driver data
  370. */
  371. static void phy_mdm6600_device_power_off(struct phy_mdm6600 *ddata)
  372. {
  373. struct gpio_desc *reset_gpio =
  374. ddata->ctrl_gpios[PHY_MDM6600_RESET];
  375. int error;
  376. ddata->enabled = false;
  377. phy_mdm6600_cmd(ddata, PHY_MDM6600_CMD_BP_SHUTDOWN_REQ);
  378. msleep(100);
  379. gpiod_set_value_cansleep(reset_gpio, 1);
  380. dev_info(ddata->dev, "Waiting for power down request to complete.. ");
  381. if (wait_for_completion_timeout(&ddata->ack,
  382. msecs_to_jiffies(5000))) {
  383. if (ddata->status == PHY_MDM6600_STATUS_PANIC)
  384. dev_info(ddata->dev, "Powered down OK\n");
  385. } else {
  386. dev_err(ddata->dev, "Timed out powering down\n");
  387. }
  388. /*
  389. * Keep reset gpio high with padconf internal pull-up resistor to
  390. * prevent modem from waking up during deeper SoC idle states. The
  391. * gpio bank lines can have glitches if not in the always-on wkup
  392. * domain.
  393. */
  394. error = pinctrl_pm_select_sleep_state(ddata->dev);
  395. if (error)
  396. dev_warn(ddata->dev, "%s: error with sleep_state: %i\n",
  397. __func__, error);
  398. }
  399. static void phy_mdm6600_deferred_power_on(struct work_struct *work)
  400. {
  401. struct phy_mdm6600 *ddata;
  402. int error;
  403. ddata = container_of(work, struct phy_mdm6600, bootup_work.work);
  404. error = phy_mdm6600_device_power_on(ddata);
  405. if (error)
  406. dev_err(ddata->dev, "Device not functional\n");
  407. }
  408. /*
  409. * USB suspend puts mdm6600 into low power mode. For any n_gsm using apps,
  410. * we need to keep the modem awake by kicking it's mode0 GPIO. This will
  411. * keep the modem awake for about 1.2 seconds. When no n_gsm apps are using
  412. * the modem, runtime PM auto mode can be enabled so modem can enter low
  413. * power mode.
  414. */
  415. static void phy_mdm6600_wake_modem(struct phy_mdm6600 *ddata)
  416. {
  417. struct gpio_desc *mode_gpio0;
  418. mode_gpio0 = ddata->mode_gpios->desc[PHY_MDM6600_MODE0];
  419. gpiod_set_value_cansleep(mode_gpio0, 1);
  420. usleep_range(5, 15);
  421. gpiod_set_value_cansleep(mode_gpio0, 0);
  422. if (ddata->awake)
  423. usleep_range(5, 15);
  424. else
  425. msleep(MDM6600_MODEM_WAKE_DELAY_MS);
  426. }
  427. static void phy_mdm6600_modem_wake(struct work_struct *work)
  428. {
  429. struct phy_mdm6600 *ddata;
  430. ddata = container_of(work, struct phy_mdm6600, modem_wake_work.work);
  431. phy_mdm6600_wake_modem(ddata);
  432. /*
  433. * The modem does not always stay awake 1.2 seconds after toggling
  434. * the wake GPIO, and sometimes it idles after about some 600 ms
  435. * making writes time out.
  436. */
  437. schedule_delayed_work(&ddata->modem_wake_work,
  438. msecs_to_jiffies(PHY_MDM6600_WAKE_KICK_MS));
  439. }
  440. static int __maybe_unused phy_mdm6600_runtime_suspend(struct device *dev)
  441. {
  442. struct phy_mdm6600 *ddata = dev_get_drvdata(dev);
  443. cancel_delayed_work_sync(&ddata->modem_wake_work);
  444. ddata->awake = false;
  445. return 0;
  446. }
  447. static int __maybe_unused phy_mdm6600_runtime_resume(struct device *dev)
  448. {
  449. struct phy_mdm6600 *ddata = dev_get_drvdata(dev);
  450. phy_mdm6600_modem_wake(&ddata->modem_wake_work.work);
  451. ddata->awake = true;
  452. return 0;
  453. }
  454. static const struct dev_pm_ops phy_mdm6600_pm_ops = {
  455. SET_RUNTIME_PM_OPS(phy_mdm6600_runtime_suspend,
  456. phy_mdm6600_runtime_resume, NULL)
  457. };
  458. static const struct of_device_id phy_mdm6600_id_table[] = {
  459. { .compatible = "motorola,mapphone-mdm6600", },
  460. {},
  461. };
  462. MODULE_DEVICE_TABLE(of, phy_mdm6600_id_table);
  463. static int phy_mdm6600_probe(struct platform_device *pdev)
  464. {
  465. struct phy_mdm6600 *ddata;
  466. int error;
  467. ddata = devm_kzalloc(&pdev->dev, sizeof(*ddata), GFP_KERNEL);
  468. if (!ddata)
  469. return -ENOMEM;
  470. INIT_DELAYED_WORK(&ddata->bootup_work,
  471. phy_mdm6600_deferred_power_on);
  472. INIT_DELAYED_WORK(&ddata->status_work, phy_mdm6600_status);
  473. INIT_DELAYED_WORK(&ddata->modem_wake_work, phy_mdm6600_modem_wake);
  474. init_completion(&ddata->ack);
  475. ddata->dev = &pdev->dev;
  476. platform_set_drvdata(pdev, ddata);
  477. error = phy_mdm6600_init_lines(ddata);
  478. if (error)
  479. return error;
  480. phy_mdm6600_init_irq(ddata);
  481. schedule_delayed_work(&ddata->bootup_work, 0);
  482. /*
  483. * See phy_mdm6600_device_power_on(). We should be able
  484. * to remove this eventually when ohci-platform can deal
  485. * with -EPROBE_DEFER.
  486. */
  487. msleep(PHY_MDM6600_PHY_DELAY_MS + 500);
  488. /*
  489. * Enable PM runtime only after PHY has been powered up properly.
  490. * It is currently only needed after USB suspends mdm6600 and n_gsm
  491. * needs to access the device. We don't want to do this earlier as
  492. * gpio mode0 pin doubles as mdm6600 wake-up gpio.
  493. */
  494. pm_runtime_use_autosuspend(ddata->dev);
  495. pm_runtime_set_autosuspend_delay(ddata->dev,
  496. MDM6600_MODEM_IDLE_DELAY_MS);
  497. pm_runtime_enable(ddata->dev);
  498. error = pm_runtime_get_sync(ddata->dev);
  499. if (error < 0) {
  500. dev_warn(ddata->dev, "failed to wake modem: %i\n", error);
  501. pm_runtime_put_noidle(ddata->dev);
  502. goto cleanup;
  503. }
  504. ddata->generic_phy = devm_phy_create(ddata->dev, NULL, &gpio_usb_ops);
  505. if (IS_ERR(ddata->generic_phy)) {
  506. error = PTR_ERR(ddata->generic_phy);
  507. goto idle;
  508. }
  509. phy_set_drvdata(ddata->generic_phy, ddata);
  510. ddata->phy_provider =
  511. devm_of_phy_provider_register(ddata->dev,
  512. of_phy_simple_xlate);
  513. if (IS_ERR(ddata->phy_provider))
  514. error = PTR_ERR(ddata->phy_provider);
  515. idle:
  516. pm_runtime_mark_last_busy(ddata->dev);
  517. pm_runtime_put_autosuspend(ddata->dev);
  518. cleanup:
  519. if (error < 0) {
  520. phy_mdm6600_device_power_off(ddata);
  521. pm_runtime_disable(ddata->dev);
  522. pm_runtime_dont_use_autosuspend(ddata->dev);
  523. }
  524. return error;
  525. }
  526. static int phy_mdm6600_remove(struct platform_device *pdev)
  527. {
  528. struct phy_mdm6600 *ddata = platform_get_drvdata(pdev);
  529. struct gpio_desc *reset_gpio = ddata->ctrl_gpios[PHY_MDM6600_RESET];
  530. pm_runtime_get_noresume(ddata->dev);
  531. pm_runtime_dont_use_autosuspend(ddata->dev);
  532. pm_runtime_put_sync(ddata->dev);
  533. pm_runtime_disable(ddata->dev);
  534. if (!ddata->running)
  535. wait_for_completion_timeout(&ddata->ack,
  536. msecs_to_jiffies(PHY_MDM6600_ENABLED_DELAY_MS));
  537. gpiod_set_value_cansleep(reset_gpio, 1);
  538. phy_mdm6600_device_power_off(ddata);
  539. cancel_delayed_work_sync(&ddata->modem_wake_work);
  540. cancel_delayed_work_sync(&ddata->bootup_work);
  541. cancel_delayed_work_sync(&ddata->status_work);
  542. return 0;
  543. }
  544. static struct platform_driver phy_mdm6600_driver = {
  545. .probe = phy_mdm6600_probe,
  546. .remove = phy_mdm6600_remove,
  547. .driver = {
  548. .name = "phy-mapphone-mdm6600",
  549. .pm = &phy_mdm6600_pm_ops,
  550. .of_match_table = of_match_ptr(phy_mdm6600_id_table),
  551. },
  552. };
  553. module_platform_driver(phy_mdm6600_driver);
  554. MODULE_ALIAS("platform:gpio_usb");
  555. MODULE_AUTHOR("Tony Lindgren <[email protected]>");
  556. MODULE_DESCRIPTION("mdm6600 gpio usb phy driver");
  557. MODULE_LICENSE("GPL v2");