1 | // SPDX-License-Identifier: GPL-2.0-only |
2 | /* |
3 | * Motorola CPCAP PMIC USB PHY driver |
4 | * Copyright (C) 2017 Tony Lindgren <tony@atomide.com> |
5 | * |
6 | * Some parts based on earlier Motorola Linux kernel tree code in |
7 | * board-mapphone-usb.c and cpcap-usb-det.c: |
8 | * Copyright (C) 2007 - 2011 Motorola, Inc. |
9 | */ |
10 | |
11 | #include <linux/atomic.h> |
12 | #include <linux/clk.h> |
13 | #include <linux/delay.h> |
14 | #include <linux/err.h> |
15 | #include <linux/io.h> |
16 | #include <linux/module.h> |
17 | #include <linux/of.h> |
18 | #include <linux/iio/consumer.h> |
19 | #include <linux/pinctrl/consumer.h> |
20 | #include <linux/platform_device.h> |
21 | #include <linux/regmap.h> |
22 | #include <linux/slab.h> |
23 | |
24 | #include <linux/gpio/consumer.h> |
25 | #include <linux/mfd/motorola-cpcap.h> |
26 | #include <linux/phy/omap_usb.h> |
27 | #include <linux/phy/phy.h> |
28 | #include <linux/regulator/consumer.h> |
29 | #include <linux/usb/musb.h> |
30 | |
31 | /* CPCAP_REG_USBC1 register bits */ |
32 | #define CPCAP_BIT_IDPULSE BIT(15) |
33 | #define CPCAP_BIT_ID100KPU BIT(14) |
34 | #define CPCAP_BIT_IDPUCNTRL BIT(13) |
35 | #define CPCAP_BIT_IDPU BIT(12) |
36 | #define CPCAP_BIT_IDPD BIT(11) |
37 | #define CPCAP_BIT_VBUSCHRGTMR3 BIT(10) |
38 | #define CPCAP_BIT_VBUSCHRGTMR2 BIT(9) |
39 | #define CPCAP_BIT_VBUSCHRGTMR1 BIT(8) |
40 | #define CPCAP_BIT_VBUSCHRGTMR0 BIT(7) |
41 | #define CPCAP_BIT_VBUSPU BIT(6) |
42 | #define CPCAP_BIT_VBUSPD BIT(5) |
43 | #define CPCAP_BIT_DMPD BIT(4) |
44 | #define CPCAP_BIT_DPPD BIT(3) |
45 | #define CPCAP_BIT_DM1K5PU BIT(2) |
46 | #define CPCAP_BIT_DP1K5PU BIT(1) |
47 | #define CPCAP_BIT_DP150KPU BIT(0) |
48 | |
49 | /* CPCAP_REG_USBC2 register bits */ |
50 | #define CPCAP_BIT_ZHSDRV1 BIT(15) |
51 | #define CPCAP_BIT_ZHSDRV0 BIT(14) |
52 | #define CPCAP_BIT_DPLLCLKREQ BIT(13) |
53 | #define CPCAP_BIT_SE0CONN BIT(12) |
54 | #define CPCAP_BIT_UARTTXTRI BIT(11) |
55 | #define CPCAP_BIT_UARTSWAP BIT(10) |
56 | #define CPCAP_BIT_UARTMUX1 BIT(9) |
57 | #define CPCAP_BIT_UARTMUX0 BIT(8) |
58 | #define CPCAP_BIT_ULPISTPLOW BIT(7) |
59 | #define CPCAP_BIT_TXENPOL BIT(6) |
60 | #define CPCAP_BIT_USBXCVREN BIT(5) |
61 | #define CPCAP_BIT_USBCNTRL BIT(4) |
62 | #define CPCAP_BIT_USBSUSPEND BIT(3) |
63 | #define CPCAP_BIT_EMUMODE2 BIT(2) |
64 | #define CPCAP_BIT_EMUMODE1 BIT(1) |
65 | #define CPCAP_BIT_EMUMODE0 BIT(0) |
66 | |
67 | /* CPCAP_REG_USBC3 register bits */ |
68 | #define CPCAP_BIT_SPARE_898_15 BIT(15) |
69 | #define CPCAP_BIT_IHSTX03 BIT(14) |
70 | #define CPCAP_BIT_IHSTX02 BIT(13) |
71 | #define CPCAP_BIT_IHSTX01 BIT(12) |
72 | #define CPCAP_BIT_IHSTX0 BIT(11) |
73 | #define CPCAP_BIT_IDPU_SPI BIT(10) |
74 | #define CPCAP_BIT_UNUSED_898_9 BIT(9) |
75 | #define CPCAP_BIT_VBUSSTBY_EN BIT(8) |
76 | #define CPCAP_BIT_VBUSEN_SPI BIT(7) |
77 | #define CPCAP_BIT_VBUSPU_SPI BIT(6) |
78 | #define CPCAP_BIT_VBUSPD_SPI BIT(5) |
79 | #define CPCAP_BIT_DMPD_SPI BIT(4) |
80 | #define CPCAP_BIT_DPPD_SPI BIT(3) |
81 | #define CPCAP_BIT_SUSPEND_SPI BIT(2) |
82 | #define CPCAP_BIT_PU_SPI BIT(1) |
83 | #define CPCAP_BIT_ULPI_SPI_SEL BIT(0) |
84 | |
85 | struct cpcap_usb_ints_state { |
86 | bool id_ground; |
87 | bool id_float; |
88 | bool chrg_det; |
89 | bool rvrs_chrg; |
90 | bool vbusov; |
91 | |
92 | bool chrg_se1b; |
93 | bool se0conn; |
94 | bool rvrs_mode; |
95 | bool chrgcurr1; |
96 | bool vbusvld; |
97 | bool sessvld; |
98 | bool sessend; |
99 | bool se1; |
100 | |
101 | bool battdetb; |
102 | bool dm; |
103 | bool dp; |
104 | }; |
105 | |
106 | enum cpcap_gpio_mode { |
107 | CPCAP_DM_DP, |
108 | CPCAP_MDM_RX_TX, |
109 | CPCAP_UNKNOWN_DISABLED, /* Seems to disable USB lines */ |
110 | CPCAP_OTG_DM_DP, |
111 | }; |
112 | |
113 | struct cpcap_phy_ddata { |
114 | struct regmap *reg; |
115 | struct device *dev; |
116 | struct usb_phy phy; |
117 | struct delayed_work detect_work; |
118 | struct pinctrl *pins; |
119 | struct pinctrl_state *pins_ulpi; |
120 | struct pinctrl_state *pins_utmi; |
121 | struct pinctrl_state *pins_uart; |
122 | struct gpio_desc *gpio[2]; |
123 | struct iio_channel *vbus; |
124 | struct iio_channel *id; |
125 | struct regulator *vusb; |
126 | atomic_t active; |
127 | unsigned int vbus_provider:1; |
128 | unsigned int docked:1; |
129 | }; |
130 | |
131 | static bool cpcap_usb_vbus_valid(struct cpcap_phy_ddata *ddata) |
132 | { |
133 | int error, value = 0; |
134 | |
135 | error = iio_read_channel_processed(chan: ddata->vbus, val: &value); |
136 | if (error >= 0) |
137 | return value > 3900; |
138 | |
139 | dev_err(ddata->dev, "error reading VBUS: %i\n" , error); |
140 | |
141 | return false; |
142 | } |
143 | |
144 | static int cpcap_usb_phy_set_host(struct usb_otg *otg, struct usb_bus *host) |
145 | { |
146 | otg->host = host; |
147 | if (!host) |
148 | otg->state = OTG_STATE_UNDEFINED; |
149 | |
150 | return 0; |
151 | } |
152 | |
153 | static int cpcap_usb_phy_set_peripheral(struct usb_otg *otg, |
154 | struct usb_gadget *gadget) |
155 | { |
156 | otg->gadget = gadget; |
157 | if (!gadget) |
158 | otg->state = OTG_STATE_UNDEFINED; |
159 | |
160 | return 0; |
161 | } |
162 | |
163 | static const struct phy_ops ops = { |
164 | .owner = THIS_MODULE, |
165 | }; |
166 | |
167 | static int cpcap_phy_get_ints_state(struct cpcap_phy_ddata *ddata, |
168 | struct cpcap_usb_ints_state *s) |
169 | { |
170 | int val, error; |
171 | |
172 | error = regmap_read(map: ddata->reg, CPCAP_REG_INTS1, val: &val); |
173 | if (error) |
174 | return error; |
175 | |
176 | s->id_ground = val & BIT(15); |
177 | s->id_float = val & BIT(14); |
178 | s->vbusov = val & BIT(11); |
179 | |
180 | error = regmap_read(map: ddata->reg, CPCAP_REG_INTS2, val: &val); |
181 | if (error) |
182 | return error; |
183 | |
184 | s->vbusvld = val & BIT(3); |
185 | s->sessvld = val & BIT(2); |
186 | s->sessend = val & BIT(1); |
187 | s->se1 = val & BIT(0); |
188 | |
189 | error = regmap_read(map: ddata->reg, CPCAP_REG_INTS4, val: &val); |
190 | if (error) |
191 | return error; |
192 | |
193 | s->dm = val & BIT(1); |
194 | s->dp = val & BIT(0); |
195 | |
196 | return 0; |
197 | } |
198 | |
199 | static int cpcap_usb_set_uart_mode(struct cpcap_phy_ddata *ddata); |
200 | static int cpcap_usb_set_usb_mode(struct cpcap_phy_ddata *ddata); |
201 | |
202 | static void cpcap_usb_try_musb_mailbox(struct cpcap_phy_ddata *ddata, |
203 | enum musb_vbus_id_status status) |
204 | { |
205 | int error; |
206 | |
207 | error = musb_mailbox(status); |
208 | if (!error) |
209 | return; |
210 | |
211 | dev_dbg(ddata->dev, "%s: musb_mailbox failed: %i\n" , |
212 | __func__, error); |
213 | } |
214 | |
215 | static void cpcap_usb_detect(struct work_struct *work) |
216 | { |
217 | struct cpcap_phy_ddata *ddata; |
218 | struct cpcap_usb_ints_state s; |
219 | bool vbus = false; |
220 | int error; |
221 | |
222 | ddata = container_of(work, struct cpcap_phy_ddata, detect_work.work); |
223 | |
224 | error = cpcap_phy_get_ints_state(ddata, s: &s); |
225 | if (error) |
226 | return; |
227 | |
228 | vbus = cpcap_usb_vbus_valid(ddata); |
229 | |
230 | /* We need to kick the VBUS as USB A-host */ |
231 | if (s.id_ground && ddata->vbus_provider) { |
232 | dev_dbg(ddata->dev, "still in USB A-host mode, kicking VBUS\n" ); |
233 | |
234 | cpcap_usb_try_musb_mailbox(ddata, status: MUSB_ID_GROUND); |
235 | |
236 | error = regmap_update_bits(map: ddata->reg, CPCAP_REG_USBC3, |
237 | CPCAP_BIT_VBUSSTBY_EN | |
238 | CPCAP_BIT_VBUSEN_SPI, |
239 | CPCAP_BIT_VBUSEN_SPI); |
240 | if (error) |
241 | goto out_err; |
242 | |
243 | return; |
244 | } |
245 | |
246 | if (vbus && s.id_ground && ddata->docked) { |
247 | dev_dbg(ddata->dev, "still docked as A-host, signal ID down\n" ); |
248 | |
249 | cpcap_usb_try_musb_mailbox(ddata, status: MUSB_ID_GROUND); |
250 | |
251 | return; |
252 | } |
253 | |
254 | /* No VBUS needed with docks */ |
255 | if (vbus && s.id_ground && !ddata->vbus_provider) { |
256 | dev_dbg(ddata->dev, "connected to a dock\n" ); |
257 | |
258 | ddata->docked = true; |
259 | |
260 | error = cpcap_usb_set_usb_mode(ddata); |
261 | if (error) |
262 | goto out_err; |
263 | |
264 | cpcap_usb_try_musb_mailbox(ddata, status: MUSB_ID_GROUND); |
265 | |
266 | /* |
267 | * Force check state again after musb has reoriented, |
268 | * otherwise devices won't enumerate after loading PHY |
269 | * driver. |
270 | */ |
271 | schedule_delayed_work(dwork: &ddata->detect_work, |
272 | delay: msecs_to_jiffies(m: 1000)); |
273 | |
274 | return; |
275 | } |
276 | |
277 | if (s.id_ground && !ddata->docked) { |
278 | dev_dbg(ddata->dev, "id ground, USB host mode\n" ); |
279 | |
280 | ddata->vbus_provider = true; |
281 | |
282 | error = cpcap_usb_set_usb_mode(ddata); |
283 | if (error) |
284 | goto out_err; |
285 | |
286 | cpcap_usb_try_musb_mailbox(ddata, status: MUSB_ID_GROUND); |
287 | |
288 | error = regmap_update_bits(map: ddata->reg, CPCAP_REG_USBC3, |
289 | CPCAP_BIT_VBUSSTBY_EN | |
290 | CPCAP_BIT_VBUSEN_SPI, |
291 | CPCAP_BIT_VBUSEN_SPI); |
292 | if (error) |
293 | goto out_err; |
294 | |
295 | return; |
296 | } |
297 | |
298 | error = regmap_update_bits(map: ddata->reg, CPCAP_REG_USBC3, |
299 | CPCAP_BIT_VBUSSTBY_EN | |
300 | CPCAP_BIT_VBUSEN_SPI, val: 0); |
301 | if (error) |
302 | goto out_err; |
303 | |
304 | vbus = cpcap_usb_vbus_valid(ddata); |
305 | |
306 | /* Otherwise assume we're connected to a USB host */ |
307 | if (vbus) { |
308 | dev_dbg(ddata->dev, "connected to USB host\n" ); |
309 | error = cpcap_usb_set_usb_mode(ddata); |
310 | if (error) |
311 | goto out_err; |
312 | cpcap_usb_try_musb_mailbox(ddata, status: MUSB_VBUS_VALID); |
313 | |
314 | return; |
315 | } |
316 | |
317 | ddata->vbus_provider = false; |
318 | ddata->docked = false; |
319 | cpcap_usb_try_musb_mailbox(ddata, status: MUSB_VBUS_OFF); |
320 | |
321 | /* Default to debug UART mode */ |
322 | error = cpcap_usb_set_uart_mode(ddata); |
323 | if (error) |
324 | goto out_err; |
325 | |
326 | dev_dbg(ddata->dev, "set UART mode\n" ); |
327 | |
328 | return; |
329 | |
330 | out_err: |
331 | dev_err(ddata->dev, "error setting cable state: %i\n" , error); |
332 | } |
333 | |
334 | static irqreturn_t cpcap_phy_irq_thread(int irq, void *data) |
335 | { |
336 | struct cpcap_phy_ddata *ddata = data; |
337 | |
338 | if (!atomic_read(v: &ddata->active)) |
339 | return IRQ_NONE; |
340 | |
341 | schedule_delayed_work(dwork: &ddata->detect_work, delay: msecs_to_jiffies(m: 1)); |
342 | |
343 | return IRQ_HANDLED; |
344 | } |
345 | |
346 | static int cpcap_usb_init_irq(struct platform_device *pdev, |
347 | struct cpcap_phy_ddata *ddata, |
348 | const char *name) |
349 | { |
350 | int irq, error; |
351 | |
352 | irq = platform_get_irq_byname(pdev, name); |
353 | if (irq < 0) |
354 | return -ENODEV; |
355 | |
356 | error = devm_request_threaded_irq(dev: ddata->dev, irq, NULL, |
357 | thread_fn: cpcap_phy_irq_thread, |
358 | IRQF_SHARED | |
359 | IRQF_ONESHOT, |
360 | devname: name, dev_id: ddata); |
361 | if (error) { |
362 | dev_err(ddata->dev, "could not get irq %s: %i\n" , |
363 | name, error); |
364 | |
365 | return error; |
366 | } |
367 | |
368 | return 0; |
369 | } |
370 | |
371 | static const char * const cpcap_phy_irqs[] = { |
372 | /* REG_INT_0 */ |
373 | "id_ground" , "id_float" , |
374 | |
375 | /* REG_INT1 */ |
376 | "se0conn" , "vbusvld" , "sessvld" , "sessend" , "se1" , |
377 | |
378 | /* REG_INT_3 */ |
379 | "dm" , "dp" , |
380 | }; |
381 | |
382 | static int cpcap_usb_init_interrupts(struct platform_device *pdev, |
383 | struct cpcap_phy_ddata *ddata) |
384 | { |
385 | int i, error; |
386 | |
387 | for (i = 0; i < ARRAY_SIZE(cpcap_phy_irqs); i++) { |
388 | error = cpcap_usb_init_irq(pdev, ddata, name: cpcap_phy_irqs[i]); |
389 | if (error) |
390 | return error; |
391 | } |
392 | |
393 | return 0; |
394 | } |
395 | |
396 | /* |
397 | * Optional pins and modes. At least Motorola mapphone devices |
398 | * are using two GPIOs and dynamic pinctrl to multiplex PHY pins |
399 | * to UART, ULPI or UTMI mode. |
400 | */ |
401 | |
402 | static int cpcap_usb_gpio_set_mode(struct cpcap_phy_ddata *ddata, |
403 | enum cpcap_gpio_mode mode) |
404 | { |
405 | if (!ddata->gpio[0] || !ddata->gpio[1]) |
406 | return 0; |
407 | |
408 | gpiod_set_value(desc: ddata->gpio[0], value: mode & 1); |
409 | gpiod_set_value(desc: ddata->gpio[1], value: mode >> 1); |
410 | |
411 | return 0; |
412 | } |
413 | |
414 | static int cpcap_usb_set_uart_mode(struct cpcap_phy_ddata *ddata) |
415 | { |
416 | int error; |
417 | |
418 | /* Disable lines to prevent glitches from waking up mdm6600 */ |
419 | error = cpcap_usb_gpio_set_mode(ddata, mode: CPCAP_UNKNOWN_DISABLED); |
420 | if (error) |
421 | goto out_err; |
422 | |
423 | if (ddata->pins_uart) { |
424 | error = pinctrl_select_state(p: ddata->pins, s: ddata->pins_uart); |
425 | if (error) |
426 | goto out_err; |
427 | } |
428 | |
429 | error = regmap_update_bits(map: ddata->reg, CPCAP_REG_USBC1, |
430 | CPCAP_BIT_VBUSPD, |
431 | CPCAP_BIT_VBUSPD); |
432 | if (error) |
433 | goto out_err; |
434 | |
435 | error = regmap_update_bits(map: ddata->reg, CPCAP_REG_USBC2, |
436 | mask: 0xffff, CPCAP_BIT_UARTMUX0 | |
437 | CPCAP_BIT_EMUMODE0); |
438 | if (error) |
439 | goto out_err; |
440 | |
441 | error = regmap_update_bits(map: ddata->reg, CPCAP_REG_USBC3, mask: 0x7fff, |
442 | CPCAP_BIT_IDPU_SPI); |
443 | if (error) |
444 | goto out_err; |
445 | |
446 | /* Enable UART mode */ |
447 | error = cpcap_usb_gpio_set_mode(ddata, mode: CPCAP_DM_DP); |
448 | if (error) |
449 | goto out_err; |
450 | |
451 | return 0; |
452 | |
453 | out_err: |
454 | dev_err(ddata->dev, "%s failed with %i\n" , __func__, error); |
455 | |
456 | return error; |
457 | } |
458 | |
459 | static int cpcap_usb_set_usb_mode(struct cpcap_phy_ddata *ddata) |
460 | { |
461 | int error; |
462 | |
463 | /* Disable lines to prevent glitches from waking up mdm6600 */ |
464 | error = cpcap_usb_gpio_set_mode(ddata, mode: CPCAP_UNKNOWN_DISABLED); |
465 | if (error) |
466 | return error; |
467 | |
468 | if (ddata->pins_utmi) { |
469 | error = pinctrl_select_state(p: ddata->pins, s: ddata->pins_utmi); |
470 | if (error) { |
471 | dev_err(ddata->dev, "could not set usb mode: %i\n" , |
472 | error); |
473 | |
474 | return error; |
475 | } |
476 | } |
477 | |
478 | error = regmap_update_bits(map: ddata->reg, CPCAP_REG_USBC1, |
479 | CPCAP_BIT_VBUSPD, val: 0); |
480 | if (error) |
481 | goto out_err; |
482 | |
483 | error = regmap_update_bits(map: ddata->reg, CPCAP_REG_USBC3, |
484 | CPCAP_BIT_PU_SPI | |
485 | CPCAP_BIT_DMPD_SPI | |
486 | CPCAP_BIT_DPPD_SPI | |
487 | CPCAP_BIT_SUSPEND_SPI | |
488 | CPCAP_BIT_ULPI_SPI_SEL, val: 0); |
489 | if (error) |
490 | goto out_err; |
491 | |
492 | error = regmap_update_bits(map: ddata->reg, CPCAP_REG_USBC2, |
493 | CPCAP_BIT_USBXCVREN, |
494 | CPCAP_BIT_USBXCVREN); |
495 | if (error) |
496 | goto out_err; |
497 | |
498 | /* Enable USB mode */ |
499 | error = cpcap_usb_gpio_set_mode(ddata, mode: CPCAP_OTG_DM_DP); |
500 | if (error) |
501 | goto out_err; |
502 | |
503 | return 0; |
504 | |
505 | out_err: |
506 | dev_err(ddata->dev, "%s failed with %i\n" , __func__, error); |
507 | |
508 | return error; |
509 | } |
510 | |
511 | static int cpcap_usb_init_optional_pins(struct cpcap_phy_ddata *ddata) |
512 | { |
513 | ddata->pins = devm_pinctrl_get(dev: ddata->dev); |
514 | if (IS_ERR(ptr: ddata->pins)) { |
515 | dev_info(ddata->dev, "default pins not configured: %ld\n" , |
516 | PTR_ERR(ddata->pins)); |
517 | ddata->pins = NULL; |
518 | |
519 | return 0; |
520 | } |
521 | |
522 | ddata->pins_ulpi = pinctrl_lookup_state(p: ddata->pins, name: "ulpi" ); |
523 | if (IS_ERR(ptr: ddata->pins_ulpi)) { |
524 | dev_info(ddata->dev, "ulpi pins not configured\n" ); |
525 | ddata->pins_ulpi = NULL; |
526 | } |
527 | |
528 | ddata->pins_utmi = pinctrl_lookup_state(p: ddata->pins, name: "utmi" ); |
529 | if (IS_ERR(ptr: ddata->pins_utmi)) { |
530 | dev_info(ddata->dev, "utmi pins not configured\n" ); |
531 | ddata->pins_utmi = NULL; |
532 | } |
533 | |
534 | ddata->pins_uart = pinctrl_lookup_state(p: ddata->pins, name: "uart" ); |
535 | if (IS_ERR(ptr: ddata->pins_uart)) { |
536 | dev_info(ddata->dev, "uart pins not configured\n" ); |
537 | ddata->pins_uart = NULL; |
538 | } |
539 | |
540 | if (ddata->pins_uart) |
541 | return pinctrl_select_state(p: ddata->pins, s: ddata->pins_uart); |
542 | |
543 | return 0; |
544 | } |
545 | |
546 | static void cpcap_usb_init_optional_gpios(struct cpcap_phy_ddata *ddata) |
547 | { |
548 | int i; |
549 | |
550 | for (i = 0; i < 2; i++) { |
551 | ddata->gpio[i] = devm_gpiod_get_index(dev: ddata->dev, con_id: "mode" , |
552 | idx: i, flags: GPIOD_OUT_HIGH); |
553 | if (IS_ERR(ptr: ddata->gpio[i])) { |
554 | dev_info(ddata->dev, "no mode change GPIO%i: %li\n" , |
555 | i, PTR_ERR(ddata->gpio[i])); |
556 | ddata->gpio[i] = NULL; |
557 | } |
558 | } |
559 | } |
560 | |
561 | static int cpcap_usb_init_iio(struct cpcap_phy_ddata *ddata) |
562 | { |
563 | enum iio_chan_type type; |
564 | int error; |
565 | |
566 | ddata->vbus = devm_iio_channel_get(dev: ddata->dev, consumer_channel: "vbus" ); |
567 | if (IS_ERR(ptr: ddata->vbus)) { |
568 | error = PTR_ERR(ptr: ddata->vbus); |
569 | goto out_err; |
570 | } |
571 | |
572 | if (!ddata->vbus->indio_dev) { |
573 | error = -ENXIO; |
574 | goto out_err; |
575 | } |
576 | |
577 | error = iio_get_channel_type(channel: ddata->vbus, type: &type); |
578 | if (error < 0) |
579 | goto out_err; |
580 | |
581 | if (type != IIO_VOLTAGE) { |
582 | error = -EINVAL; |
583 | goto out_err; |
584 | } |
585 | |
586 | return 0; |
587 | |
588 | out_err: |
589 | dev_err(ddata->dev, "could not initialize VBUS or ID IIO: %i\n" , |
590 | error); |
591 | |
592 | return error; |
593 | } |
594 | |
595 | #ifdef CONFIG_OF |
596 | static const struct of_device_id cpcap_usb_phy_id_table[] = { |
597 | { |
598 | .compatible = "motorola,cpcap-usb-phy" , |
599 | }, |
600 | { |
601 | .compatible = "motorola,mapphone-cpcap-usb-phy" , |
602 | }, |
603 | {}, |
604 | }; |
605 | MODULE_DEVICE_TABLE(of, cpcap_usb_phy_id_table); |
606 | #endif |
607 | |
608 | static int cpcap_usb_phy_probe(struct platform_device *pdev) |
609 | { |
610 | struct cpcap_phy_ddata *ddata; |
611 | struct phy *generic_phy; |
612 | struct phy_provider *phy_provider; |
613 | struct usb_otg *otg; |
614 | int error; |
615 | |
616 | ddata = devm_kzalloc(dev: &pdev->dev, size: sizeof(*ddata), GFP_KERNEL); |
617 | if (!ddata) |
618 | return -ENOMEM; |
619 | |
620 | ddata->reg = dev_get_regmap(dev: pdev->dev.parent, NULL); |
621 | if (!ddata->reg) |
622 | return -ENODEV; |
623 | |
624 | otg = devm_kzalloc(dev: &pdev->dev, size: sizeof(*otg), GFP_KERNEL); |
625 | if (!otg) |
626 | return -ENOMEM; |
627 | |
628 | ddata->dev = &pdev->dev; |
629 | ddata->phy.dev = ddata->dev; |
630 | ddata->phy.label = "cpcap_usb_phy" ; |
631 | ddata->phy.otg = otg; |
632 | ddata->phy.type = USB_PHY_TYPE_USB2; |
633 | otg->set_host = cpcap_usb_phy_set_host; |
634 | otg->set_peripheral = cpcap_usb_phy_set_peripheral; |
635 | otg->usb_phy = &ddata->phy; |
636 | INIT_DELAYED_WORK(&ddata->detect_work, cpcap_usb_detect); |
637 | platform_set_drvdata(pdev, data: ddata); |
638 | |
639 | ddata->vusb = devm_regulator_get(dev: &pdev->dev, id: "vusb" ); |
640 | if (IS_ERR(ptr: ddata->vusb)) |
641 | return PTR_ERR(ptr: ddata->vusb); |
642 | |
643 | error = regulator_enable(regulator: ddata->vusb); |
644 | if (error) |
645 | return error; |
646 | |
647 | generic_phy = devm_phy_create(dev: ddata->dev, NULL, ops: &ops); |
648 | if (IS_ERR(ptr: generic_phy)) { |
649 | error = PTR_ERR(ptr: generic_phy); |
650 | goto out_reg_disable; |
651 | } |
652 | |
653 | phy_set_drvdata(phy: generic_phy, data: ddata); |
654 | |
655 | phy_provider = devm_of_phy_provider_register(ddata->dev, |
656 | of_phy_simple_xlate); |
657 | if (IS_ERR(ptr: phy_provider)) { |
658 | error = PTR_ERR(ptr: phy_provider); |
659 | goto out_reg_disable; |
660 | } |
661 | |
662 | error = cpcap_usb_init_optional_pins(ddata); |
663 | if (error) |
664 | goto out_reg_disable; |
665 | |
666 | cpcap_usb_init_optional_gpios(ddata); |
667 | |
668 | error = cpcap_usb_init_iio(ddata); |
669 | if (error) |
670 | goto out_reg_disable; |
671 | |
672 | error = cpcap_usb_init_interrupts(pdev, ddata); |
673 | if (error) |
674 | goto out_reg_disable; |
675 | |
676 | usb_add_phy_dev(&ddata->phy); |
677 | atomic_set(v: &ddata->active, i: 1); |
678 | schedule_delayed_work(dwork: &ddata->detect_work, delay: msecs_to_jiffies(m: 1)); |
679 | |
680 | return 0; |
681 | |
682 | out_reg_disable: |
683 | regulator_disable(regulator: ddata->vusb); |
684 | |
685 | return error; |
686 | } |
687 | |
688 | static void cpcap_usb_phy_remove(struct platform_device *pdev) |
689 | { |
690 | struct cpcap_phy_ddata *ddata = platform_get_drvdata(pdev); |
691 | int error; |
692 | |
693 | atomic_set(v: &ddata->active, i: 0); |
694 | error = cpcap_usb_set_uart_mode(ddata); |
695 | if (error) |
696 | dev_err(ddata->dev, "could not set UART mode\n" ); |
697 | |
698 | cpcap_usb_try_musb_mailbox(ddata, status: MUSB_VBUS_OFF); |
699 | |
700 | usb_remove_phy(&ddata->phy); |
701 | cancel_delayed_work_sync(dwork: &ddata->detect_work); |
702 | regulator_disable(regulator: ddata->vusb); |
703 | } |
704 | |
705 | static struct platform_driver cpcap_usb_phy_driver = { |
706 | .probe = cpcap_usb_phy_probe, |
707 | .remove_new = cpcap_usb_phy_remove, |
708 | .driver = { |
709 | .name = "cpcap-usb-phy" , |
710 | .of_match_table = of_match_ptr(cpcap_usb_phy_id_table), |
711 | }, |
712 | }; |
713 | |
714 | module_platform_driver(cpcap_usb_phy_driver); |
715 | |
716 | MODULE_ALIAS("platform:cpcap_usb" ); |
717 | MODULE_AUTHOR("Tony Lindgren <tony@atomide.com>" ); |
718 | MODULE_DESCRIPTION("CPCAP usb phy driver" ); |
719 | MODULE_LICENSE("GPL v2" ); |
720 | |