diff options
Diffstat (limited to 'drivers/usb/otg/msm_otg.c')
-rw-r--r-- | drivers/usb/otg/msm_otg.c | 1124 |
1 files changed, 1124 insertions, 0 deletions
diff --git a/drivers/usb/otg/msm_otg.c b/drivers/usb/otg/msm_otg.c new file mode 100644 index 000000000000..296598628b85 --- /dev/null +++ b/drivers/usb/otg/msm_otg.c | |||
@@ -0,0 +1,1124 @@ | |||
1 | /* Copyright (c) 2009-2010, Code Aurora Forum. All rights reserved. | ||
2 | * | ||
3 | * This program is free software; you can redistribute it and/or modify | ||
4 | * it under the terms of the GNU General Public License version 2 and | ||
5 | * only version 2 as published by the Free Software Foundation. | ||
6 | * | ||
7 | * This program is distributed in the hope that it will be useful, | ||
8 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
9 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
10 | * GNU General Public License for more details. | ||
11 | * | ||
12 | * You should have received a copy of the GNU General Public License | ||
13 | * along with this program; if not, write to the Free Software | ||
14 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA | ||
15 | * 02110-1301, USA. | ||
16 | * | ||
17 | */ | ||
18 | |||
19 | #include <linux/module.h> | ||
20 | #include <linux/device.h> | ||
21 | #include <linux/platform_device.h> | ||
22 | #include <linux/clk.h> | ||
23 | #include <linux/slab.h> | ||
24 | #include <linux/interrupt.h> | ||
25 | #include <linux/err.h> | ||
26 | #include <linux/delay.h> | ||
27 | #include <linux/io.h> | ||
28 | #include <linux/ioport.h> | ||
29 | #include <linux/uaccess.h> | ||
30 | #include <linux/debugfs.h> | ||
31 | #include <linux/seq_file.h> | ||
32 | #include <linux/pm_runtime.h> | ||
33 | |||
34 | #include <linux/usb.h> | ||
35 | #include <linux/usb/otg.h> | ||
36 | #include <linux/usb/ulpi.h> | ||
37 | #include <linux/usb/gadget.h> | ||
38 | #include <linux/usb/hcd.h> | ||
39 | #include <linux/usb/msm_hsusb.h> | ||
40 | #include <linux/usb/msm_hsusb_hw.h> | ||
41 | |||
42 | #include <mach/clk.h> | ||
43 | |||
44 | #define MSM_USB_BASE (motg->regs) | ||
45 | #define DRIVER_NAME "msm_otg" | ||
46 | |||
47 | #define ULPI_IO_TIMEOUT_USEC (10 * 1000) | ||
48 | static int ulpi_read(struct otg_transceiver *otg, u32 reg) | ||
49 | { | ||
50 | struct msm_otg *motg = container_of(otg, struct msm_otg, otg); | ||
51 | int cnt = 0; | ||
52 | |||
53 | /* initiate read operation */ | ||
54 | writel(ULPI_RUN | ULPI_READ | ULPI_ADDR(reg), | ||
55 | USB_ULPI_VIEWPORT); | ||
56 | |||
57 | /* wait for completion */ | ||
58 | while (cnt < ULPI_IO_TIMEOUT_USEC) { | ||
59 | if (!(readl(USB_ULPI_VIEWPORT) & ULPI_RUN)) | ||
60 | break; | ||
61 | udelay(1); | ||
62 | cnt++; | ||
63 | } | ||
64 | |||
65 | if (cnt >= ULPI_IO_TIMEOUT_USEC) { | ||
66 | dev_err(otg->dev, "ulpi_read: timeout %08x\n", | ||
67 | readl(USB_ULPI_VIEWPORT)); | ||
68 | return -ETIMEDOUT; | ||
69 | } | ||
70 | return ULPI_DATA_READ(readl(USB_ULPI_VIEWPORT)); | ||
71 | } | ||
72 | |||
73 | static int ulpi_write(struct otg_transceiver *otg, u32 val, u32 reg) | ||
74 | { | ||
75 | struct msm_otg *motg = container_of(otg, struct msm_otg, otg); | ||
76 | int cnt = 0; | ||
77 | |||
78 | /* initiate write operation */ | ||
79 | writel(ULPI_RUN | ULPI_WRITE | | ||
80 | ULPI_ADDR(reg) | ULPI_DATA(val), | ||
81 | USB_ULPI_VIEWPORT); | ||
82 | |||
83 | /* wait for completion */ | ||
84 | while (cnt < ULPI_IO_TIMEOUT_USEC) { | ||
85 | if (!(readl(USB_ULPI_VIEWPORT) & ULPI_RUN)) | ||
86 | break; | ||
87 | udelay(1); | ||
88 | cnt++; | ||
89 | } | ||
90 | |||
91 | if (cnt >= ULPI_IO_TIMEOUT_USEC) { | ||
92 | dev_err(otg->dev, "ulpi_write: timeout\n"); | ||
93 | return -ETIMEDOUT; | ||
94 | } | ||
95 | return 0; | ||
96 | } | ||
97 | |||
98 | static struct otg_io_access_ops msm_otg_io_ops = { | ||
99 | .read = ulpi_read, | ||
100 | .write = ulpi_write, | ||
101 | }; | ||
102 | |||
103 | static void ulpi_init(struct msm_otg *motg) | ||
104 | { | ||
105 | struct msm_otg_platform_data *pdata = motg->pdata; | ||
106 | int *seq = pdata->phy_init_seq; | ||
107 | |||
108 | if (!seq) | ||
109 | return; | ||
110 | |||
111 | while (seq[0] >= 0) { | ||
112 | dev_vdbg(motg->otg.dev, "ulpi: write 0x%02x to 0x%02x\n", | ||
113 | seq[0], seq[1]); | ||
114 | ulpi_write(&motg->otg, seq[0], seq[1]); | ||
115 | seq += 2; | ||
116 | } | ||
117 | } | ||
118 | |||
119 | static int msm_otg_link_clk_reset(struct msm_otg *motg, bool assert) | ||
120 | { | ||
121 | int ret; | ||
122 | |||
123 | if (assert) { | ||
124 | ret = clk_reset(motg->clk, CLK_RESET_ASSERT); | ||
125 | if (ret) | ||
126 | dev_err(motg->otg.dev, "usb hs_clk assert failed\n"); | ||
127 | } else { | ||
128 | ret = clk_reset(motg->clk, CLK_RESET_DEASSERT); | ||
129 | if (ret) | ||
130 | dev_err(motg->otg.dev, "usb hs_clk deassert failed\n"); | ||
131 | } | ||
132 | return ret; | ||
133 | } | ||
134 | |||
135 | static int msm_otg_phy_clk_reset(struct msm_otg *motg) | ||
136 | { | ||
137 | int ret; | ||
138 | |||
139 | ret = clk_reset(motg->phy_reset_clk, CLK_RESET_ASSERT); | ||
140 | if (ret) { | ||
141 | dev_err(motg->otg.dev, "usb phy clk assert failed\n"); | ||
142 | return ret; | ||
143 | } | ||
144 | usleep_range(10000, 12000); | ||
145 | ret = clk_reset(motg->phy_reset_clk, CLK_RESET_DEASSERT); | ||
146 | if (ret) | ||
147 | dev_err(motg->otg.dev, "usb phy clk deassert failed\n"); | ||
148 | return ret; | ||
149 | } | ||
150 | |||
151 | static int msm_otg_phy_reset(struct msm_otg *motg) | ||
152 | { | ||
153 | u32 val; | ||
154 | int ret; | ||
155 | int retries; | ||
156 | |||
157 | ret = msm_otg_link_clk_reset(motg, 1); | ||
158 | if (ret) | ||
159 | return ret; | ||
160 | ret = msm_otg_phy_clk_reset(motg); | ||
161 | if (ret) | ||
162 | return ret; | ||
163 | ret = msm_otg_link_clk_reset(motg, 0); | ||
164 | if (ret) | ||
165 | return ret; | ||
166 | |||
167 | val = readl(USB_PORTSC) & ~PORTSC_PTS_MASK; | ||
168 | writel(val | PORTSC_PTS_ULPI, USB_PORTSC); | ||
169 | |||
170 | for (retries = 3; retries > 0; retries--) { | ||
171 | ret = ulpi_write(&motg->otg, ULPI_FUNC_CTRL_SUSPENDM, | ||
172 | ULPI_CLR(ULPI_FUNC_CTRL)); | ||
173 | if (!ret) | ||
174 | break; | ||
175 | ret = msm_otg_phy_clk_reset(motg); | ||
176 | if (ret) | ||
177 | return ret; | ||
178 | } | ||
179 | if (!retries) | ||
180 | return -ETIMEDOUT; | ||
181 | |||
182 | /* This reset calibrates the phy, if the above write succeeded */ | ||
183 | ret = msm_otg_phy_clk_reset(motg); | ||
184 | if (ret) | ||
185 | return ret; | ||
186 | |||
187 | for (retries = 3; retries > 0; retries--) { | ||
188 | ret = ulpi_read(&motg->otg, ULPI_DEBUG); | ||
189 | if (ret != -ETIMEDOUT) | ||
190 | break; | ||
191 | ret = msm_otg_phy_clk_reset(motg); | ||
192 | if (ret) | ||
193 | return ret; | ||
194 | } | ||
195 | if (!retries) | ||
196 | return -ETIMEDOUT; | ||
197 | |||
198 | dev_info(motg->otg.dev, "phy_reset: success\n"); | ||
199 | return 0; | ||
200 | } | ||
201 | |||
202 | #define LINK_RESET_TIMEOUT_USEC (250 * 1000) | ||
203 | static int msm_otg_reset(struct otg_transceiver *otg) | ||
204 | { | ||
205 | struct msm_otg *motg = container_of(otg, struct msm_otg, otg); | ||
206 | struct msm_otg_platform_data *pdata = motg->pdata; | ||
207 | int cnt = 0; | ||
208 | int ret; | ||
209 | u32 val = 0; | ||
210 | u32 ulpi_val = 0; | ||
211 | |||
212 | ret = msm_otg_phy_reset(motg); | ||
213 | if (ret) { | ||
214 | dev_err(otg->dev, "phy_reset failed\n"); | ||
215 | return ret; | ||
216 | } | ||
217 | |||
218 | ulpi_init(motg); | ||
219 | |||
220 | writel(USBCMD_RESET, USB_USBCMD); | ||
221 | while (cnt < LINK_RESET_TIMEOUT_USEC) { | ||
222 | if (!(readl(USB_USBCMD) & USBCMD_RESET)) | ||
223 | break; | ||
224 | udelay(1); | ||
225 | cnt++; | ||
226 | } | ||
227 | if (cnt >= LINK_RESET_TIMEOUT_USEC) | ||
228 | return -ETIMEDOUT; | ||
229 | |||
230 | /* select ULPI phy */ | ||
231 | writel(0x80000000, USB_PORTSC); | ||
232 | |||
233 | msleep(100); | ||
234 | |||
235 | writel(0x0, USB_AHBBURST); | ||
236 | writel(0x00, USB_AHBMODE); | ||
237 | |||
238 | if (pdata->otg_control == OTG_PHY_CONTROL) { | ||
239 | val = readl(USB_OTGSC); | ||
240 | if (pdata->mode == USB_OTG) { | ||
241 | ulpi_val = ULPI_INT_IDGRD | ULPI_INT_SESS_VALID; | ||
242 | val |= OTGSC_IDIE | OTGSC_BSVIE; | ||
243 | } else if (pdata->mode == USB_PERIPHERAL) { | ||
244 | ulpi_val = ULPI_INT_SESS_VALID; | ||
245 | val |= OTGSC_BSVIE; | ||
246 | } | ||
247 | writel(val, USB_OTGSC); | ||
248 | ulpi_write(otg, ulpi_val, ULPI_USB_INT_EN_RISE); | ||
249 | ulpi_write(otg, ulpi_val, ULPI_USB_INT_EN_FALL); | ||
250 | } | ||
251 | |||
252 | return 0; | ||
253 | } | ||
254 | |||
255 | #define PHY_SUSPEND_TIMEOUT_USEC (500 * 1000) | ||
256 | #define PHY_RESUME_TIMEOUT_USEC (100 * 1000) | ||
257 | |||
258 | #ifdef CONFIG_PM_SLEEP | ||
259 | static int msm_otg_suspend(struct msm_otg *motg) | ||
260 | { | ||
261 | struct otg_transceiver *otg = &motg->otg; | ||
262 | struct usb_bus *bus = otg->host; | ||
263 | struct msm_otg_platform_data *pdata = motg->pdata; | ||
264 | int cnt = 0; | ||
265 | |||
266 | if (atomic_read(&motg->in_lpm)) | ||
267 | return 0; | ||
268 | |||
269 | disable_irq(motg->irq); | ||
270 | /* | ||
271 | * Interrupt Latch Register auto-clear feature is not present | ||
272 | * in all PHY versions. Latch register is clear on read type. | ||
273 | * Clear latch register to avoid spurious wakeup from | ||
274 | * low power mode (LPM). | ||
275 | */ | ||
276 | ulpi_read(otg, 0x14); | ||
277 | |||
278 | /* | ||
279 | * PHY comparators are disabled when PHY enters into low power | ||
280 | * mode (LPM). Keep PHY comparators ON in LPM only when we expect | ||
281 | * VBUS/Id notifications from USB PHY. Otherwise turn off USB | ||
282 | * PHY comparators. This save significant amount of power. | ||
283 | */ | ||
284 | if (pdata->otg_control == OTG_PHY_CONTROL) | ||
285 | ulpi_write(otg, 0x01, 0x30); | ||
286 | |||
287 | /* | ||
288 | * PLL is not turned off when PHY enters into low power mode (LPM). | ||
289 | * Disable PLL for maximum power savings. | ||
290 | */ | ||
291 | ulpi_write(otg, 0x08, 0x09); | ||
292 | |||
293 | /* | ||
294 | * PHY may take some time or even fail to enter into low power | ||
295 | * mode (LPM). Hence poll for 500 msec and reset the PHY and link | ||
296 | * in failure case. | ||
297 | */ | ||
298 | writel(readl(USB_PORTSC) | PORTSC_PHCD, USB_PORTSC); | ||
299 | while (cnt < PHY_SUSPEND_TIMEOUT_USEC) { | ||
300 | if (readl(USB_PORTSC) & PORTSC_PHCD) | ||
301 | break; | ||
302 | udelay(1); | ||
303 | cnt++; | ||
304 | } | ||
305 | |||
306 | if (cnt >= PHY_SUSPEND_TIMEOUT_USEC) { | ||
307 | dev_err(otg->dev, "Unable to suspend PHY\n"); | ||
308 | msm_otg_reset(otg); | ||
309 | enable_irq(motg->irq); | ||
310 | return -ETIMEDOUT; | ||
311 | } | ||
312 | |||
313 | /* | ||
314 | * PHY has capability to generate interrupt asynchronously in low | ||
315 | * power mode (LPM). This interrupt is level triggered. So USB IRQ | ||
316 | * line must be disabled till async interrupt enable bit is cleared | ||
317 | * in USBCMD register. Assert STP (ULPI interface STOP signal) to | ||
318 | * block data communication from PHY. | ||
319 | */ | ||
320 | writel(readl(USB_USBCMD) | ASYNC_INTR_CTRL | ULPI_STP_CTRL, USB_USBCMD); | ||
321 | |||
322 | clk_disable(motg->pclk); | ||
323 | clk_disable(motg->clk); | ||
324 | if (motg->core_clk) | ||
325 | clk_disable(motg->core_clk); | ||
326 | |||
327 | if (device_may_wakeup(otg->dev)) | ||
328 | enable_irq_wake(motg->irq); | ||
329 | if (bus) | ||
330 | clear_bit(HCD_FLAG_HW_ACCESSIBLE, &(bus_to_hcd(bus))->flags); | ||
331 | |||
332 | atomic_set(&motg->in_lpm, 1); | ||
333 | enable_irq(motg->irq); | ||
334 | |||
335 | dev_info(otg->dev, "USB in low power mode\n"); | ||
336 | |||
337 | return 0; | ||
338 | } | ||
339 | |||
340 | static int msm_otg_resume(struct msm_otg *motg) | ||
341 | { | ||
342 | struct otg_transceiver *otg = &motg->otg; | ||
343 | struct usb_bus *bus = otg->host; | ||
344 | int cnt = 0; | ||
345 | unsigned temp; | ||
346 | |||
347 | if (!atomic_read(&motg->in_lpm)) | ||
348 | return 0; | ||
349 | |||
350 | clk_enable(motg->pclk); | ||
351 | clk_enable(motg->clk); | ||
352 | if (motg->core_clk) | ||
353 | clk_enable(motg->core_clk); | ||
354 | |||
355 | temp = readl(USB_USBCMD); | ||
356 | temp &= ~ASYNC_INTR_CTRL; | ||
357 | temp &= ~ULPI_STP_CTRL; | ||
358 | writel(temp, USB_USBCMD); | ||
359 | |||
360 | /* | ||
361 | * PHY comes out of low power mode (LPM) in case of wakeup | ||
362 | * from asynchronous interrupt. | ||
363 | */ | ||
364 | if (!(readl(USB_PORTSC) & PORTSC_PHCD)) | ||
365 | goto skip_phy_resume; | ||
366 | |||
367 | writel(readl(USB_PORTSC) & ~PORTSC_PHCD, USB_PORTSC); | ||
368 | while (cnt < PHY_RESUME_TIMEOUT_USEC) { | ||
369 | if (!(readl(USB_PORTSC) & PORTSC_PHCD)) | ||
370 | break; | ||
371 | udelay(1); | ||
372 | cnt++; | ||
373 | } | ||
374 | |||
375 | if (cnt >= PHY_RESUME_TIMEOUT_USEC) { | ||
376 | /* | ||
377 | * This is a fatal error. Reset the link and | ||
378 | * PHY. USB state can not be restored. Re-insertion | ||
379 | * of USB cable is the only way to get USB working. | ||
380 | */ | ||
381 | dev_err(otg->dev, "Unable to resume USB." | ||
382 | "Re-plugin the cable\n"); | ||
383 | msm_otg_reset(otg); | ||
384 | } | ||
385 | |||
386 | skip_phy_resume: | ||
387 | if (device_may_wakeup(otg->dev)) | ||
388 | disable_irq_wake(motg->irq); | ||
389 | if (bus) | ||
390 | set_bit(HCD_FLAG_HW_ACCESSIBLE, &(bus_to_hcd(bus))->flags); | ||
391 | |||
392 | if (motg->async_int) { | ||
393 | motg->async_int = 0; | ||
394 | pm_runtime_put(otg->dev); | ||
395 | enable_irq(motg->irq); | ||
396 | } | ||
397 | |||
398 | atomic_set(&motg->in_lpm, 0); | ||
399 | |||
400 | dev_info(otg->dev, "USB exited from low power mode\n"); | ||
401 | |||
402 | return 0; | ||
403 | } | ||
404 | #endif | ||
405 | |||
406 | static void msm_otg_start_host(struct otg_transceiver *otg, int on) | ||
407 | { | ||
408 | struct msm_otg *motg = container_of(otg, struct msm_otg, otg); | ||
409 | struct msm_otg_platform_data *pdata = motg->pdata; | ||
410 | struct usb_hcd *hcd; | ||
411 | |||
412 | if (!otg->host) | ||
413 | return; | ||
414 | |||
415 | hcd = bus_to_hcd(otg->host); | ||
416 | |||
417 | if (on) { | ||
418 | dev_dbg(otg->dev, "host on\n"); | ||
419 | |||
420 | if (pdata->vbus_power) | ||
421 | pdata->vbus_power(1); | ||
422 | /* | ||
423 | * Some boards have a switch cotrolled by gpio | ||
424 | * to enable/disable internal HUB. Enable internal | ||
425 | * HUB before kicking the host. | ||
426 | */ | ||
427 | if (pdata->setup_gpio) | ||
428 | pdata->setup_gpio(OTG_STATE_A_HOST); | ||
429 | #ifdef CONFIG_USB | ||
430 | usb_add_hcd(hcd, hcd->irq, IRQF_SHARED); | ||
431 | #endif | ||
432 | } else { | ||
433 | dev_dbg(otg->dev, "host off\n"); | ||
434 | |||
435 | #ifdef CONFIG_USB | ||
436 | usb_remove_hcd(hcd); | ||
437 | #endif | ||
438 | if (pdata->setup_gpio) | ||
439 | pdata->setup_gpio(OTG_STATE_UNDEFINED); | ||
440 | if (pdata->vbus_power) | ||
441 | pdata->vbus_power(0); | ||
442 | } | ||
443 | } | ||
444 | |||
445 | static int msm_otg_set_host(struct otg_transceiver *otg, struct usb_bus *host) | ||
446 | { | ||
447 | struct msm_otg *motg = container_of(otg, struct msm_otg, otg); | ||
448 | struct usb_hcd *hcd; | ||
449 | |||
450 | /* | ||
451 | * Fail host registration if this board can support | ||
452 | * only peripheral configuration. | ||
453 | */ | ||
454 | if (motg->pdata->mode == USB_PERIPHERAL) { | ||
455 | dev_info(otg->dev, "Host mode is not supported\n"); | ||
456 | return -ENODEV; | ||
457 | } | ||
458 | |||
459 | if (!host) { | ||
460 | if (otg->state == OTG_STATE_A_HOST) { | ||
461 | pm_runtime_get_sync(otg->dev); | ||
462 | msm_otg_start_host(otg, 0); | ||
463 | otg->host = NULL; | ||
464 | otg->state = OTG_STATE_UNDEFINED; | ||
465 | schedule_work(&motg->sm_work); | ||
466 | } else { | ||
467 | otg->host = NULL; | ||
468 | } | ||
469 | |||
470 | return 0; | ||
471 | } | ||
472 | |||
473 | hcd = bus_to_hcd(host); | ||
474 | hcd->power_budget = motg->pdata->power_budget; | ||
475 | |||
476 | otg->host = host; | ||
477 | dev_dbg(otg->dev, "host driver registered w/ tranceiver\n"); | ||
478 | |||
479 | /* | ||
480 | * Kick the state machine work, if peripheral is not supported | ||
481 | * or peripheral is already registered with us. | ||
482 | */ | ||
483 | if (motg->pdata->mode == USB_HOST || otg->gadget) { | ||
484 | pm_runtime_get_sync(otg->dev); | ||
485 | schedule_work(&motg->sm_work); | ||
486 | } | ||
487 | |||
488 | return 0; | ||
489 | } | ||
490 | |||
491 | static void msm_otg_start_peripheral(struct otg_transceiver *otg, int on) | ||
492 | { | ||
493 | struct msm_otg *motg = container_of(otg, struct msm_otg, otg); | ||
494 | struct msm_otg_platform_data *pdata = motg->pdata; | ||
495 | |||
496 | if (!otg->gadget) | ||
497 | return; | ||
498 | |||
499 | if (on) { | ||
500 | dev_dbg(otg->dev, "gadget on\n"); | ||
501 | /* | ||
502 | * Some boards have a switch cotrolled by gpio | ||
503 | * to enable/disable internal HUB. Disable internal | ||
504 | * HUB before kicking the gadget. | ||
505 | */ | ||
506 | if (pdata->setup_gpio) | ||
507 | pdata->setup_gpio(OTG_STATE_B_PERIPHERAL); | ||
508 | usb_gadget_vbus_connect(otg->gadget); | ||
509 | } else { | ||
510 | dev_dbg(otg->dev, "gadget off\n"); | ||
511 | usb_gadget_vbus_disconnect(otg->gadget); | ||
512 | if (pdata->setup_gpio) | ||
513 | pdata->setup_gpio(OTG_STATE_UNDEFINED); | ||
514 | } | ||
515 | |||
516 | } | ||
517 | |||
518 | static int msm_otg_set_peripheral(struct otg_transceiver *otg, | ||
519 | struct usb_gadget *gadget) | ||
520 | { | ||
521 | struct msm_otg *motg = container_of(otg, struct msm_otg, otg); | ||
522 | |||
523 | /* | ||
524 | * Fail peripheral registration if this board can support | ||
525 | * only host configuration. | ||
526 | */ | ||
527 | if (motg->pdata->mode == USB_HOST) { | ||
528 | dev_info(otg->dev, "Peripheral mode is not supported\n"); | ||
529 | return -ENODEV; | ||
530 | } | ||
531 | |||
532 | if (!gadget) { | ||
533 | if (otg->state == OTG_STATE_B_PERIPHERAL) { | ||
534 | pm_runtime_get_sync(otg->dev); | ||
535 | msm_otg_start_peripheral(otg, 0); | ||
536 | otg->gadget = NULL; | ||
537 | otg->state = OTG_STATE_UNDEFINED; | ||
538 | schedule_work(&motg->sm_work); | ||
539 | } else { | ||
540 | otg->gadget = NULL; | ||
541 | } | ||
542 | |||
543 | return 0; | ||
544 | } | ||
545 | otg->gadget = gadget; | ||
546 | dev_dbg(otg->dev, "peripheral driver registered w/ tranceiver\n"); | ||
547 | |||
548 | /* | ||
549 | * Kick the state machine work, if host is not supported | ||
550 | * or host is already registered with us. | ||
551 | */ | ||
552 | if (motg->pdata->mode == USB_PERIPHERAL || otg->host) { | ||
553 | pm_runtime_get_sync(otg->dev); | ||
554 | schedule_work(&motg->sm_work); | ||
555 | } | ||
556 | |||
557 | return 0; | ||
558 | } | ||
559 | |||
560 | /* | ||
561 | * We support OTG, Peripheral only and Host only configurations. In case | ||
562 | * of OTG, mode switch (host-->peripheral/peripheral-->host) can happen | ||
563 | * via Id pin status or user request (debugfs). Id/BSV interrupts are not | ||
564 | * enabled when switch is controlled by user and default mode is supplied | ||
565 | * by board file, which can be changed by userspace later. | ||
566 | */ | ||
567 | static void msm_otg_init_sm(struct msm_otg *motg) | ||
568 | { | ||
569 | struct msm_otg_platform_data *pdata = motg->pdata; | ||
570 | u32 otgsc = readl(USB_OTGSC); | ||
571 | |||
572 | switch (pdata->mode) { | ||
573 | case USB_OTG: | ||
574 | if (pdata->otg_control == OTG_PHY_CONTROL) { | ||
575 | if (otgsc & OTGSC_ID) | ||
576 | set_bit(ID, &motg->inputs); | ||
577 | else | ||
578 | clear_bit(ID, &motg->inputs); | ||
579 | |||
580 | if (otgsc & OTGSC_BSV) | ||
581 | set_bit(B_SESS_VLD, &motg->inputs); | ||
582 | else | ||
583 | clear_bit(B_SESS_VLD, &motg->inputs); | ||
584 | } else if (pdata->otg_control == OTG_USER_CONTROL) { | ||
585 | if (pdata->default_mode == USB_HOST) { | ||
586 | clear_bit(ID, &motg->inputs); | ||
587 | } else if (pdata->default_mode == USB_PERIPHERAL) { | ||
588 | set_bit(ID, &motg->inputs); | ||
589 | set_bit(B_SESS_VLD, &motg->inputs); | ||
590 | } else { | ||
591 | set_bit(ID, &motg->inputs); | ||
592 | clear_bit(B_SESS_VLD, &motg->inputs); | ||
593 | } | ||
594 | } | ||
595 | break; | ||
596 | case USB_HOST: | ||
597 | clear_bit(ID, &motg->inputs); | ||
598 | break; | ||
599 | case USB_PERIPHERAL: | ||
600 | set_bit(ID, &motg->inputs); | ||
601 | if (otgsc & OTGSC_BSV) | ||
602 | set_bit(B_SESS_VLD, &motg->inputs); | ||
603 | else | ||
604 | clear_bit(B_SESS_VLD, &motg->inputs); | ||
605 | break; | ||
606 | default: | ||
607 | break; | ||
608 | } | ||
609 | } | ||
610 | |||
611 | static void msm_otg_sm_work(struct work_struct *w) | ||
612 | { | ||
613 | struct msm_otg *motg = container_of(w, struct msm_otg, sm_work); | ||
614 | struct otg_transceiver *otg = &motg->otg; | ||
615 | |||
616 | switch (otg->state) { | ||
617 | case OTG_STATE_UNDEFINED: | ||
618 | dev_dbg(otg->dev, "OTG_STATE_UNDEFINED state\n"); | ||
619 | msm_otg_reset(otg); | ||
620 | msm_otg_init_sm(motg); | ||
621 | otg->state = OTG_STATE_B_IDLE; | ||
622 | /* FALL THROUGH */ | ||
623 | case OTG_STATE_B_IDLE: | ||
624 | dev_dbg(otg->dev, "OTG_STATE_B_IDLE state\n"); | ||
625 | if (!test_bit(ID, &motg->inputs) && otg->host) { | ||
626 | /* disable BSV bit */ | ||
627 | writel(readl(USB_OTGSC) & ~OTGSC_BSVIE, USB_OTGSC); | ||
628 | msm_otg_start_host(otg, 1); | ||
629 | otg->state = OTG_STATE_A_HOST; | ||
630 | } else if (test_bit(B_SESS_VLD, &motg->inputs) && otg->gadget) { | ||
631 | msm_otg_start_peripheral(otg, 1); | ||
632 | otg->state = OTG_STATE_B_PERIPHERAL; | ||
633 | } | ||
634 | pm_runtime_put_sync(otg->dev); | ||
635 | break; | ||
636 | case OTG_STATE_B_PERIPHERAL: | ||
637 | dev_dbg(otg->dev, "OTG_STATE_B_PERIPHERAL state\n"); | ||
638 | if (!test_bit(B_SESS_VLD, &motg->inputs) || | ||
639 | !test_bit(ID, &motg->inputs)) { | ||
640 | msm_otg_start_peripheral(otg, 0); | ||
641 | otg->state = OTG_STATE_B_IDLE; | ||
642 | msm_otg_reset(otg); | ||
643 | schedule_work(w); | ||
644 | } | ||
645 | break; | ||
646 | case OTG_STATE_A_HOST: | ||
647 | dev_dbg(otg->dev, "OTG_STATE_A_HOST state\n"); | ||
648 | if (test_bit(ID, &motg->inputs)) { | ||
649 | msm_otg_start_host(otg, 0); | ||
650 | otg->state = OTG_STATE_B_IDLE; | ||
651 | msm_otg_reset(otg); | ||
652 | schedule_work(w); | ||
653 | } | ||
654 | break; | ||
655 | default: | ||
656 | break; | ||
657 | } | ||
658 | } | ||
659 | |||
660 | static irqreturn_t msm_otg_irq(int irq, void *data) | ||
661 | { | ||
662 | struct msm_otg *motg = data; | ||
663 | struct otg_transceiver *otg = &motg->otg; | ||
664 | u32 otgsc = 0; | ||
665 | |||
666 | if (atomic_read(&motg->in_lpm)) { | ||
667 | disable_irq_nosync(irq); | ||
668 | motg->async_int = 1; | ||
669 | pm_runtime_get(otg->dev); | ||
670 | return IRQ_HANDLED; | ||
671 | } | ||
672 | |||
673 | otgsc = readl(USB_OTGSC); | ||
674 | if (!(otgsc & (OTGSC_IDIS | OTGSC_BSVIS))) | ||
675 | return IRQ_NONE; | ||
676 | |||
677 | if ((otgsc & OTGSC_IDIS) && (otgsc & OTGSC_IDIE)) { | ||
678 | if (otgsc & OTGSC_ID) | ||
679 | set_bit(ID, &motg->inputs); | ||
680 | else | ||
681 | clear_bit(ID, &motg->inputs); | ||
682 | dev_dbg(otg->dev, "ID set/clear\n"); | ||
683 | pm_runtime_get_noresume(otg->dev); | ||
684 | } else if ((otgsc & OTGSC_BSVIS) && (otgsc & OTGSC_BSVIE)) { | ||
685 | if (otgsc & OTGSC_BSV) | ||
686 | set_bit(B_SESS_VLD, &motg->inputs); | ||
687 | else | ||
688 | clear_bit(B_SESS_VLD, &motg->inputs); | ||
689 | dev_dbg(otg->dev, "BSV set/clear\n"); | ||
690 | pm_runtime_get_noresume(otg->dev); | ||
691 | } | ||
692 | |||
693 | writel(otgsc, USB_OTGSC); | ||
694 | schedule_work(&motg->sm_work); | ||
695 | return IRQ_HANDLED; | ||
696 | } | ||
697 | |||
698 | static int msm_otg_mode_show(struct seq_file *s, void *unused) | ||
699 | { | ||
700 | struct msm_otg *motg = s->private; | ||
701 | struct otg_transceiver *otg = &motg->otg; | ||
702 | |||
703 | switch (otg->state) { | ||
704 | case OTG_STATE_A_HOST: | ||
705 | seq_printf(s, "host\n"); | ||
706 | break; | ||
707 | case OTG_STATE_B_PERIPHERAL: | ||
708 | seq_printf(s, "peripheral\n"); | ||
709 | break; | ||
710 | default: | ||
711 | seq_printf(s, "none\n"); | ||
712 | break; | ||
713 | } | ||
714 | |||
715 | return 0; | ||
716 | } | ||
717 | |||
718 | static int msm_otg_mode_open(struct inode *inode, struct file *file) | ||
719 | { | ||
720 | return single_open(file, msm_otg_mode_show, inode->i_private); | ||
721 | } | ||
722 | |||
723 | static ssize_t msm_otg_mode_write(struct file *file, const char __user *ubuf, | ||
724 | size_t count, loff_t *ppos) | ||
725 | { | ||
726 | struct seq_file *s = file->private_data; | ||
727 | struct msm_otg *motg = s->private; | ||
728 | char buf[16]; | ||
729 | struct otg_transceiver *otg = &motg->otg; | ||
730 | int status = count; | ||
731 | enum usb_mode_type req_mode; | ||
732 | |||
733 | memset(buf, 0x00, sizeof(buf)); | ||
734 | |||
735 | if (copy_from_user(&buf, ubuf, min_t(size_t, sizeof(buf) - 1, count))) { | ||
736 | status = -EFAULT; | ||
737 | goto out; | ||
738 | } | ||
739 | |||
740 | if (!strncmp(buf, "host", 4)) { | ||
741 | req_mode = USB_HOST; | ||
742 | } else if (!strncmp(buf, "peripheral", 10)) { | ||
743 | req_mode = USB_PERIPHERAL; | ||
744 | } else if (!strncmp(buf, "none", 4)) { | ||
745 | req_mode = USB_NONE; | ||
746 | } else { | ||
747 | status = -EINVAL; | ||
748 | goto out; | ||
749 | } | ||
750 | |||
751 | switch (req_mode) { | ||
752 | case USB_NONE: | ||
753 | switch (otg->state) { | ||
754 | case OTG_STATE_A_HOST: | ||
755 | case OTG_STATE_B_PERIPHERAL: | ||
756 | set_bit(ID, &motg->inputs); | ||
757 | clear_bit(B_SESS_VLD, &motg->inputs); | ||
758 | break; | ||
759 | default: | ||
760 | goto out; | ||
761 | } | ||
762 | break; | ||
763 | case USB_PERIPHERAL: | ||
764 | switch (otg->state) { | ||
765 | case OTG_STATE_B_IDLE: | ||
766 | case OTG_STATE_A_HOST: | ||
767 | set_bit(ID, &motg->inputs); | ||
768 | set_bit(B_SESS_VLD, &motg->inputs); | ||
769 | break; | ||
770 | default: | ||
771 | goto out; | ||
772 | } | ||
773 | break; | ||
774 | case USB_HOST: | ||
775 | switch (otg->state) { | ||
776 | case OTG_STATE_B_IDLE: | ||
777 | case OTG_STATE_B_PERIPHERAL: | ||
778 | clear_bit(ID, &motg->inputs); | ||
779 | break; | ||
780 | default: | ||
781 | goto out; | ||
782 | } | ||
783 | break; | ||
784 | default: | ||
785 | goto out; | ||
786 | } | ||
787 | |||
788 | pm_runtime_get_sync(otg->dev); | ||
789 | schedule_work(&motg->sm_work); | ||
790 | out: | ||
791 | return status; | ||
792 | } | ||
793 | |||
794 | const struct file_operations msm_otg_mode_fops = { | ||
795 | .open = msm_otg_mode_open, | ||
796 | .read = seq_read, | ||
797 | .write = msm_otg_mode_write, | ||
798 | .llseek = seq_lseek, | ||
799 | .release = single_release, | ||
800 | }; | ||
801 | |||
802 | static struct dentry *msm_otg_dbg_root; | ||
803 | static struct dentry *msm_otg_dbg_mode; | ||
804 | |||
805 | static int msm_otg_debugfs_init(struct msm_otg *motg) | ||
806 | { | ||
807 | msm_otg_dbg_root = debugfs_create_dir("msm_otg", NULL); | ||
808 | |||
809 | if (!msm_otg_dbg_root || IS_ERR(msm_otg_dbg_root)) | ||
810 | return -ENODEV; | ||
811 | |||
812 | msm_otg_dbg_mode = debugfs_create_file("mode", S_IRUGO | S_IWUSR, | ||
813 | msm_otg_dbg_root, motg, &msm_otg_mode_fops); | ||
814 | if (!msm_otg_dbg_mode) { | ||
815 | debugfs_remove(msm_otg_dbg_root); | ||
816 | msm_otg_dbg_root = NULL; | ||
817 | return -ENODEV; | ||
818 | } | ||
819 | |||
820 | return 0; | ||
821 | } | ||
822 | |||
823 | static void msm_otg_debugfs_cleanup(void) | ||
824 | { | ||
825 | debugfs_remove(msm_otg_dbg_mode); | ||
826 | debugfs_remove(msm_otg_dbg_root); | ||
827 | } | ||
828 | |||
829 | static int __init msm_otg_probe(struct platform_device *pdev) | ||
830 | { | ||
831 | int ret = 0; | ||
832 | struct resource *res; | ||
833 | struct msm_otg *motg; | ||
834 | struct otg_transceiver *otg; | ||
835 | |||
836 | dev_info(&pdev->dev, "msm_otg probe\n"); | ||
837 | if (!pdev->dev.platform_data) { | ||
838 | dev_err(&pdev->dev, "No platform data given. Bailing out\n"); | ||
839 | return -ENODEV; | ||
840 | } | ||
841 | |||
842 | motg = kzalloc(sizeof(struct msm_otg), GFP_KERNEL); | ||
843 | if (!motg) { | ||
844 | dev_err(&pdev->dev, "unable to allocate msm_otg\n"); | ||
845 | return -ENOMEM; | ||
846 | } | ||
847 | |||
848 | motg->pdata = pdev->dev.platform_data; | ||
849 | otg = &motg->otg; | ||
850 | otg->dev = &pdev->dev; | ||
851 | |||
852 | motg->phy_reset_clk = clk_get(&pdev->dev, "usb_phy_clk"); | ||
853 | if (IS_ERR(motg->phy_reset_clk)) { | ||
854 | dev_err(&pdev->dev, "failed to get usb_phy_clk\n"); | ||
855 | ret = PTR_ERR(motg->phy_reset_clk); | ||
856 | goto free_motg; | ||
857 | } | ||
858 | |||
859 | motg->clk = clk_get(&pdev->dev, "usb_hs_clk"); | ||
860 | if (IS_ERR(motg->clk)) { | ||
861 | dev_err(&pdev->dev, "failed to get usb_hs_clk\n"); | ||
862 | ret = PTR_ERR(motg->clk); | ||
863 | goto put_phy_reset_clk; | ||
864 | } | ||
865 | |||
866 | motg->pclk = clk_get(&pdev->dev, "usb_hs_pclk"); | ||
867 | if (IS_ERR(motg->pclk)) { | ||
868 | dev_err(&pdev->dev, "failed to get usb_hs_pclk\n"); | ||
869 | ret = PTR_ERR(motg->pclk); | ||
870 | goto put_clk; | ||
871 | } | ||
872 | |||
873 | /* | ||
874 | * USB core clock is not present on all MSM chips. This | ||
875 | * clock is introduced to remove the dependency on AXI | ||
876 | * bus frequency. | ||
877 | */ | ||
878 | motg->core_clk = clk_get(&pdev->dev, "usb_hs_core_clk"); | ||
879 | if (IS_ERR(motg->core_clk)) | ||
880 | motg->core_clk = NULL; | ||
881 | |||
882 | res = platform_get_resource(pdev, IORESOURCE_MEM, 0); | ||
883 | if (!res) { | ||
884 | dev_err(&pdev->dev, "failed to get platform resource mem\n"); | ||
885 | ret = -ENODEV; | ||
886 | goto put_core_clk; | ||
887 | } | ||
888 | |||
889 | motg->regs = ioremap(res->start, resource_size(res)); | ||
890 | if (!motg->regs) { | ||
891 | dev_err(&pdev->dev, "ioremap failed\n"); | ||
892 | ret = -ENOMEM; | ||
893 | goto put_core_clk; | ||
894 | } | ||
895 | dev_info(&pdev->dev, "OTG regs = %p\n", motg->regs); | ||
896 | |||
897 | motg->irq = platform_get_irq(pdev, 0); | ||
898 | if (!motg->irq) { | ||
899 | dev_err(&pdev->dev, "platform_get_irq failed\n"); | ||
900 | ret = -ENODEV; | ||
901 | goto free_regs; | ||
902 | } | ||
903 | |||
904 | clk_enable(motg->clk); | ||
905 | clk_enable(motg->pclk); | ||
906 | if (motg->core_clk) | ||
907 | clk_enable(motg->core_clk); | ||
908 | |||
909 | writel(0, USB_USBINTR); | ||
910 | writel(0, USB_OTGSC); | ||
911 | |||
912 | INIT_WORK(&motg->sm_work, msm_otg_sm_work); | ||
913 | ret = request_irq(motg->irq, msm_otg_irq, IRQF_SHARED, | ||
914 | "msm_otg", motg); | ||
915 | if (ret) { | ||
916 | dev_err(&pdev->dev, "request irq failed\n"); | ||
917 | goto disable_clks; | ||
918 | } | ||
919 | |||
920 | otg->init = msm_otg_reset; | ||
921 | otg->set_host = msm_otg_set_host; | ||
922 | otg->set_peripheral = msm_otg_set_peripheral; | ||
923 | |||
924 | otg->io_ops = &msm_otg_io_ops; | ||
925 | |||
926 | ret = otg_set_transceiver(&motg->otg); | ||
927 | if (ret) { | ||
928 | dev_err(&pdev->dev, "otg_set_transceiver failed\n"); | ||
929 | goto free_irq; | ||
930 | } | ||
931 | |||
932 | platform_set_drvdata(pdev, motg); | ||
933 | device_init_wakeup(&pdev->dev, 1); | ||
934 | |||
935 | if (motg->pdata->mode == USB_OTG && | ||
936 | motg->pdata->otg_control == OTG_USER_CONTROL) { | ||
937 | ret = msm_otg_debugfs_init(motg); | ||
938 | if (ret) | ||
939 | dev_dbg(&pdev->dev, "mode debugfs file is" | ||
940 | "not available\n"); | ||
941 | } | ||
942 | |||
943 | pm_runtime_set_active(&pdev->dev); | ||
944 | pm_runtime_enable(&pdev->dev); | ||
945 | |||
946 | return 0; | ||
947 | free_irq: | ||
948 | free_irq(motg->irq, motg); | ||
949 | disable_clks: | ||
950 | clk_disable(motg->pclk); | ||
951 | clk_disable(motg->clk); | ||
952 | free_regs: | ||
953 | iounmap(motg->regs); | ||
954 | put_core_clk: | ||
955 | if (motg->core_clk) | ||
956 | clk_put(motg->core_clk); | ||
957 | clk_put(motg->pclk); | ||
958 | put_clk: | ||
959 | clk_put(motg->clk); | ||
960 | put_phy_reset_clk: | ||
961 | clk_put(motg->phy_reset_clk); | ||
962 | free_motg: | ||
963 | kfree(motg); | ||
964 | return ret; | ||
965 | } | ||
966 | |||
967 | static int __devexit msm_otg_remove(struct platform_device *pdev) | ||
968 | { | ||
969 | struct msm_otg *motg = platform_get_drvdata(pdev); | ||
970 | struct otg_transceiver *otg = &motg->otg; | ||
971 | int cnt = 0; | ||
972 | |||
973 | if (otg->host || otg->gadget) | ||
974 | return -EBUSY; | ||
975 | |||
976 | msm_otg_debugfs_cleanup(); | ||
977 | cancel_work_sync(&motg->sm_work); | ||
978 | |||
979 | pm_runtime_resume(&pdev->dev); | ||
980 | |||
981 | device_init_wakeup(&pdev->dev, 0); | ||
982 | pm_runtime_disable(&pdev->dev); | ||
983 | |||
984 | otg_set_transceiver(NULL); | ||
985 | free_irq(motg->irq, motg); | ||
986 | |||
987 | /* | ||
988 | * Put PHY in low power mode. | ||
989 | */ | ||
990 | ulpi_read(otg, 0x14); | ||
991 | ulpi_write(otg, 0x08, 0x09); | ||
992 | |||
993 | writel(readl(USB_PORTSC) | PORTSC_PHCD, USB_PORTSC); | ||
994 | while (cnt < PHY_SUSPEND_TIMEOUT_USEC) { | ||
995 | if (readl(USB_PORTSC) & PORTSC_PHCD) | ||
996 | break; | ||
997 | udelay(1); | ||
998 | cnt++; | ||
999 | } | ||
1000 | if (cnt >= PHY_SUSPEND_TIMEOUT_USEC) | ||
1001 | dev_err(otg->dev, "Unable to suspend PHY\n"); | ||
1002 | |||
1003 | clk_disable(motg->pclk); | ||
1004 | clk_disable(motg->clk); | ||
1005 | if (motg->core_clk) | ||
1006 | clk_disable(motg->core_clk); | ||
1007 | |||
1008 | iounmap(motg->regs); | ||
1009 | pm_runtime_set_suspended(&pdev->dev); | ||
1010 | |||
1011 | clk_put(motg->phy_reset_clk); | ||
1012 | clk_put(motg->pclk); | ||
1013 | clk_put(motg->clk); | ||
1014 | if (motg->core_clk) | ||
1015 | clk_put(motg->core_clk); | ||
1016 | |||
1017 | kfree(motg); | ||
1018 | |||
1019 | return 0; | ||
1020 | } | ||
1021 | |||
1022 | #ifdef CONFIG_PM_RUNTIME | ||
1023 | static int msm_otg_runtime_idle(struct device *dev) | ||
1024 | { | ||
1025 | struct msm_otg *motg = dev_get_drvdata(dev); | ||
1026 | struct otg_transceiver *otg = &motg->otg; | ||
1027 | |||
1028 | dev_dbg(dev, "OTG runtime idle\n"); | ||
1029 | |||
1030 | /* | ||
1031 | * It is observed some times that a spurious interrupt | ||
1032 | * comes when PHY is put into LPM immediately after PHY reset. | ||
1033 | * This 1 sec delay also prevents entering into LPM immediately | ||
1034 | * after asynchronous interrupt. | ||
1035 | */ | ||
1036 | if (otg->state != OTG_STATE_UNDEFINED) | ||
1037 | pm_schedule_suspend(dev, 1000); | ||
1038 | |||
1039 | return -EAGAIN; | ||
1040 | } | ||
1041 | |||
1042 | static int msm_otg_runtime_suspend(struct device *dev) | ||
1043 | { | ||
1044 | struct msm_otg *motg = dev_get_drvdata(dev); | ||
1045 | |||
1046 | dev_dbg(dev, "OTG runtime suspend\n"); | ||
1047 | return msm_otg_suspend(motg); | ||
1048 | } | ||
1049 | |||
1050 | static int msm_otg_runtime_resume(struct device *dev) | ||
1051 | { | ||
1052 | struct msm_otg *motg = dev_get_drvdata(dev); | ||
1053 | |||
1054 | dev_dbg(dev, "OTG runtime resume\n"); | ||
1055 | return msm_otg_resume(motg); | ||
1056 | } | ||
1057 | #endif | ||
1058 | |||
1059 | #ifdef CONFIG_PM_SLEEP | ||
1060 | static int msm_otg_pm_suspend(struct device *dev) | ||
1061 | { | ||
1062 | struct msm_otg *motg = dev_get_drvdata(dev); | ||
1063 | |||
1064 | dev_dbg(dev, "OTG PM suspend\n"); | ||
1065 | return msm_otg_suspend(motg); | ||
1066 | } | ||
1067 | |||
1068 | static int msm_otg_pm_resume(struct device *dev) | ||
1069 | { | ||
1070 | struct msm_otg *motg = dev_get_drvdata(dev); | ||
1071 | int ret; | ||
1072 | |||
1073 | dev_dbg(dev, "OTG PM resume\n"); | ||
1074 | |||
1075 | ret = msm_otg_resume(motg); | ||
1076 | if (ret) | ||
1077 | return ret; | ||
1078 | |||
1079 | /* | ||
1080 | * Runtime PM Documentation recommends bringing the | ||
1081 | * device to full powered state upon resume. | ||
1082 | */ | ||
1083 | pm_runtime_disable(dev); | ||
1084 | pm_runtime_set_active(dev); | ||
1085 | pm_runtime_enable(dev); | ||
1086 | |||
1087 | return 0; | ||
1088 | } | ||
1089 | #endif | ||
1090 | |||
1091 | #ifdef CONFIG_PM | ||
1092 | static const struct dev_pm_ops msm_otg_dev_pm_ops = { | ||
1093 | SET_SYSTEM_SLEEP_PM_OPS(msm_otg_pm_suspend, msm_otg_pm_resume) | ||
1094 | SET_RUNTIME_PM_OPS(msm_otg_runtime_suspend, msm_otg_runtime_resume, | ||
1095 | msm_otg_runtime_idle) | ||
1096 | }; | ||
1097 | #endif | ||
1098 | |||
1099 | static struct platform_driver msm_otg_driver = { | ||
1100 | .remove = __devexit_p(msm_otg_remove), | ||
1101 | .driver = { | ||
1102 | .name = DRIVER_NAME, | ||
1103 | .owner = THIS_MODULE, | ||
1104 | #ifdef CONFIG_PM | ||
1105 | .pm = &msm_otg_dev_pm_ops, | ||
1106 | #endif | ||
1107 | }, | ||
1108 | }; | ||
1109 | |||
1110 | static int __init msm_otg_init(void) | ||
1111 | { | ||
1112 | return platform_driver_probe(&msm_otg_driver, msm_otg_probe); | ||
1113 | } | ||
1114 | |||
1115 | static void __exit msm_otg_exit(void) | ||
1116 | { | ||
1117 | platform_driver_unregister(&msm_otg_driver); | ||
1118 | } | ||
1119 | |||
1120 | module_init(msm_otg_init); | ||
1121 | module_exit(msm_otg_exit); | ||
1122 | |||
1123 | MODULE_LICENSE("GPL v2"); | ||
1124 | MODULE_DESCRIPTION("MSM USB transceiver driver"); | ||