blob: 4e1895ff0f67fa37eadd3d71bfa9ff6c798b6258 [file] [log] [blame]
Manu Gautam5143b252012-01-05 19:25:23 -08001/* Copyright (c) 2009-2012, Code Aurora Forum. All rights reserved.
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05302 *
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 *
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +053012 */
13
14#include <linux/module.h>
15#include <linux/device.h>
16#include <linux/platform_device.h>
17#include <linux/clk.h>
18#include <linux/slab.h>
19#include <linux/interrupt.h>
20#include <linux/err.h>
21#include <linux/delay.h>
22#include <linux/io.h>
23#include <linux/ioport.h>
24#include <linux/uaccess.h>
25#include <linux/debugfs.h>
26#include <linux/seq_file.h>
Pavankumar Kondeti87c01042010-12-07 17:53:58 +053027#include <linux/pm_runtime.h>
Pavankumar Kondetieaea7fe2011-10-27 14:46:45 +053028#include <linux/of.h>
29#include <linux/dma-mapping.h>
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +053030
31#include <linux/usb.h>
32#include <linux/usb/otg.h>
33#include <linux/usb/ulpi.h>
34#include <linux/usb/gadget.h>
35#include <linux/usb/hcd.h>
36#include <linux/usb/msm_hsusb.h>
37#include <linux/usb/msm_hsusb_hw.h>
Anji jonnala11aa5c42011-05-04 10:19:48 +053038#include <linux/regulator/consumer.h>
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070039#include <linux/mfd/pm8xxx/pm8921-charger.h>
Pavankumar Kondeti446f4542012-02-01 13:57:13 +053040#include <linux/mfd/pm8xxx/misc.h>
Anji jonnalaa7c1c5c2011-12-12 12:20:36 +053041#include <linux/pm_qos_params.h>
Amit Blay0f7edf72012-01-15 10:11:27 +020042#include <linux/power_supply.h>
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +053043
44#include <mach/clk.h>
Anji jonnala7da3f262011-12-02 17:22:14 -080045#include <mach/msm_xo.h>
Manu Gautamcd82e9d2011-12-20 14:17:28 +053046#include <mach/msm_bus.h>
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +053047
48#define MSM_USB_BASE (motg->regs)
49#define DRIVER_NAME "msm_otg"
50
Pavankumar Kondetiaa449e12011-11-04 11:09:26 +053051#define ID_TIMER_FREQ (jiffies + msecs_to_jiffies(2000))
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +053052#define ULPI_IO_TIMEOUT_USEC (10 * 1000)
Anji jonnala11aa5c42011-05-04 10:19:48 +053053
54#define USB_PHY_3P3_VOL_MIN 3050000 /* uV */
55#define USB_PHY_3P3_VOL_MAX 3300000 /* uV */
56#define USB_PHY_3P3_HPM_LOAD 50000 /* uA */
57#define USB_PHY_3P3_LPM_LOAD 4000 /* uA */
58
59#define USB_PHY_1P8_VOL_MIN 1800000 /* uV */
60#define USB_PHY_1P8_VOL_MAX 1800000 /* uV */
61#define USB_PHY_1P8_HPM_LOAD 50000 /* uA */
62#define USB_PHY_1P8_LPM_LOAD 4000 /* uA */
63
Vamsi Krishna132b2762011-11-11 16:09:20 -080064#define USB_PHY_VDD_DIG_VOL_MIN 1045000 /* uV */
Anji jonnala11aa5c42011-05-04 10:19:48 +053065#define USB_PHY_VDD_DIG_VOL_MAX 1320000 /* uV */
66
Pavankumar Kondeti4960f312011-12-06 15:46:14 +053067static DECLARE_COMPLETION(pmic_vbus_init);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070068static struct msm_otg *the_msm_otg;
Pavankumar Kondetiaa449e12011-11-04 11:09:26 +053069static bool debug_aca_enabled;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070070
Anji jonnalaa7c1c5c2011-12-12 12:20:36 +053071/* Prevent idle power collapse(pc) while operating in peripheral mode */
72static void otg_pm_qos_update_latency(struct msm_otg *dev, int vote)
73{
74 struct msm_otg_platform_data *pdata = dev->pdata;
75 u32 swfi_latency = 0;
76
77 if (!pdata || !pdata->swfi_latency)
78 return;
79
80 swfi_latency = pdata->swfi_latency + 1;
81
82 if (vote)
83 pm_qos_update_request(&dev->pm_qos_req_dma,
84 swfi_latency);
85 else
86 pm_qos_update_request(&dev->pm_qos_req_dma,
87 PM_QOS_DEFAULT_VALUE);
88}
89
Anji jonnala11aa5c42011-05-04 10:19:48 +053090static struct regulator *hsusb_3p3;
91static struct regulator *hsusb_1p8;
92static struct regulator *hsusb_vddcx;
Mayank Ranae3926882011-12-26 09:47:54 +053093static struct regulator *vbus_otg;
Anji jonnala11aa5c42011-05-04 10:19:48 +053094
Pavankumar Kondeti4960f312011-12-06 15:46:14 +053095static bool aca_id_turned_on;
Pavankumar Kondetiaa449e12011-11-04 11:09:26 +053096static inline bool aca_enabled(void)
97{
98#ifdef CONFIG_USB_MSM_ACA
99 return true;
100#else
101 return debug_aca_enabled;
102#endif
103}
104
Anji jonnala11aa5c42011-05-04 10:19:48 +0530105static int msm_hsusb_init_vddcx(struct msm_otg *motg, int init)
106{
107 int ret = 0;
108
109 if (init) {
110 hsusb_vddcx = regulator_get(motg->otg.dev, "HSUSB_VDDCX");
111 if (IS_ERR(hsusb_vddcx)) {
112 dev_err(motg->otg.dev, "unable to get hsusb vddcx\n");
113 return PTR_ERR(hsusb_vddcx);
114 }
115
116 ret = regulator_set_voltage(hsusb_vddcx,
117 USB_PHY_VDD_DIG_VOL_MIN,
118 USB_PHY_VDD_DIG_VOL_MAX);
119 if (ret) {
120 dev_err(motg->otg.dev, "unable to set the voltage "
121 "for hsusb vddcx\n");
122 regulator_put(hsusb_vddcx);
123 return ret;
124 }
125
126 ret = regulator_enable(hsusb_vddcx);
127 if (ret) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700128 regulator_set_voltage(hsusb_vddcx, 0,
129 USB_PHY_VDD_DIG_VOL_MIN);
Anji jonnala11aa5c42011-05-04 10:19:48 +0530130 regulator_put(hsusb_vddcx);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700131 dev_err(motg->otg.dev, "unable to enable the hsusb vddcx\n");
132 return ret;
Anji jonnala11aa5c42011-05-04 10:19:48 +0530133 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700134
Anji jonnala11aa5c42011-05-04 10:19:48 +0530135 } else {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700136
Anji jonnala11aa5c42011-05-04 10:19:48 +0530137 ret = regulator_disable(hsusb_vddcx);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700138 if (ret) {
Anji jonnala11aa5c42011-05-04 10:19:48 +0530139 dev_err(motg->otg.dev, "unable to disable hsusb vddcx\n");
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700140 return ret;
141 }
142
143 ret = regulator_set_voltage(hsusb_vddcx, 0,
144 USB_PHY_VDD_DIG_VOL_MIN);
145 if (ret) {
146 dev_err(motg->otg.dev, "unable to set the voltage"
147 "for hsusb vddcx\n");
148 return ret;
149 }
Anji jonnala11aa5c42011-05-04 10:19:48 +0530150
151 regulator_put(hsusb_vddcx);
152 }
153
154 return ret;
155}
156
157static int msm_hsusb_ldo_init(struct msm_otg *motg, int init)
158{
159 int rc = 0;
160
161 if (init) {
162 hsusb_3p3 = regulator_get(motg->otg.dev, "HSUSB_3p3");
163 if (IS_ERR(hsusb_3p3)) {
164 dev_err(motg->otg.dev, "unable to get hsusb 3p3\n");
165 return PTR_ERR(hsusb_3p3);
166 }
167
168 rc = regulator_set_voltage(hsusb_3p3, USB_PHY_3P3_VOL_MIN,
169 USB_PHY_3P3_VOL_MAX);
170 if (rc) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700171 dev_err(motg->otg.dev, "unable to set voltage level for"
172 "hsusb 3p3\n");
Anji jonnala11aa5c42011-05-04 10:19:48 +0530173 goto put_3p3;
174 }
175 hsusb_1p8 = regulator_get(motg->otg.dev, "HSUSB_1p8");
176 if (IS_ERR(hsusb_1p8)) {
177 dev_err(motg->otg.dev, "unable to get hsusb 1p8\n");
178 rc = PTR_ERR(hsusb_1p8);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700179 goto put_3p3_lpm;
Anji jonnala11aa5c42011-05-04 10:19:48 +0530180 }
181 rc = regulator_set_voltage(hsusb_1p8, USB_PHY_1P8_VOL_MIN,
182 USB_PHY_1P8_VOL_MAX);
183 if (rc) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700184 dev_err(motg->otg.dev, "unable to set voltage level for"
185 "hsusb 1p8\n");
Anji jonnala11aa5c42011-05-04 10:19:48 +0530186 goto put_1p8;
187 }
188
189 return 0;
190 }
191
Anji jonnala11aa5c42011-05-04 10:19:48 +0530192put_1p8:
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700193 regulator_set_voltage(hsusb_1p8, 0, USB_PHY_1P8_VOL_MAX);
Anji jonnala11aa5c42011-05-04 10:19:48 +0530194 regulator_put(hsusb_1p8);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700195put_3p3_lpm:
196 regulator_set_voltage(hsusb_3p3, 0, USB_PHY_3P3_VOL_MAX);
Anji jonnala11aa5c42011-05-04 10:19:48 +0530197put_3p3:
198 regulator_put(hsusb_3p3);
199 return rc;
200}
201
Pavankumar Kondeti04aebcb2011-05-04 10:19:49 +0530202#ifdef CONFIG_PM_SLEEP
203#define USB_PHY_SUSP_DIG_VOL 500000
204static int msm_hsusb_config_vddcx(int high)
205{
206 int max_vol = USB_PHY_VDD_DIG_VOL_MAX;
207 int min_vol;
208 int ret;
209
210 if (high)
211 min_vol = USB_PHY_VDD_DIG_VOL_MIN;
212 else
213 min_vol = USB_PHY_SUSP_DIG_VOL;
214
215 ret = regulator_set_voltage(hsusb_vddcx, min_vol, max_vol);
216 if (ret) {
217 pr_err("%s: unable to set the voltage for regulator "
218 "HSUSB_VDDCX\n", __func__);
219 return ret;
220 }
221
222 pr_debug("%s: min_vol:%d max_vol:%d\n", __func__, min_vol, max_vol);
223
224 return ret;
225}
Hemant Kumar8e7bd072011-08-01 14:14:24 -0700226#else
227static int msm_hsusb_config_vddcx(int high)
228{
229 return 0;
230}
Pavankumar Kondeti04aebcb2011-05-04 10:19:49 +0530231#endif
232
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700233static int msm_hsusb_ldo_enable(struct msm_otg *motg, int on)
Anji jonnala11aa5c42011-05-04 10:19:48 +0530234{
235 int ret = 0;
236
Pavankumar Kondeti68964c92011-10-27 14:58:56 +0530237 if (IS_ERR(hsusb_1p8)) {
Anji jonnala11aa5c42011-05-04 10:19:48 +0530238 pr_err("%s: HSUSB_1p8 is not initialized\n", __func__);
239 return -ENODEV;
240 }
241
Pavankumar Kondeti68964c92011-10-27 14:58:56 +0530242 if (IS_ERR(hsusb_3p3)) {
Anji jonnala11aa5c42011-05-04 10:19:48 +0530243 pr_err("%s: HSUSB_3p3 is not initialized\n", __func__);
244 return -ENODEV;
245 }
246
247 if (on) {
248 ret = regulator_set_optimum_mode(hsusb_1p8,
249 USB_PHY_1P8_HPM_LOAD);
250 if (ret < 0) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700251 pr_err("%s: Unable to set HPM of the regulator:"
Anji jonnala11aa5c42011-05-04 10:19:48 +0530252 "HSUSB_1p8\n", __func__);
253 return ret;
254 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700255
256 ret = regulator_enable(hsusb_1p8);
257 if (ret) {
258 dev_err(motg->otg.dev, "%s: unable to enable the hsusb 1p8\n",
259 __func__);
260 regulator_set_optimum_mode(hsusb_1p8, 0);
261 return ret;
262 }
263
Anji jonnala11aa5c42011-05-04 10:19:48 +0530264 ret = regulator_set_optimum_mode(hsusb_3p3,
265 USB_PHY_3P3_HPM_LOAD);
266 if (ret < 0) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700267 pr_err("%s: Unable to set HPM of the regulator:"
Anji jonnala11aa5c42011-05-04 10:19:48 +0530268 "HSUSB_3p3\n", __func__);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700269 regulator_set_optimum_mode(hsusb_1p8, 0);
270 regulator_disable(hsusb_1p8);
Anji jonnala11aa5c42011-05-04 10:19:48 +0530271 return ret;
272 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700273
274 ret = regulator_enable(hsusb_3p3);
275 if (ret) {
276 dev_err(motg->otg.dev, "%s: unable to enable the hsusb 3p3\n",
277 __func__);
278 regulator_set_optimum_mode(hsusb_3p3, 0);
279 regulator_set_optimum_mode(hsusb_1p8, 0);
280 regulator_disable(hsusb_1p8);
281 return ret;
282 }
283
Anji jonnala11aa5c42011-05-04 10:19:48 +0530284 } else {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700285 ret = regulator_disable(hsusb_1p8);
286 if (ret) {
287 dev_err(motg->otg.dev, "%s: unable to disable the hsusb 1p8\n",
288 __func__);
289 return ret;
290 }
291
292 ret = regulator_set_optimum_mode(hsusb_1p8, 0);
Anji jonnala11aa5c42011-05-04 10:19:48 +0530293 if (ret < 0)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700294 pr_err("%s: Unable to set LPM of the regulator:"
Anji jonnala11aa5c42011-05-04 10:19:48 +0530295 "HSUSB_1p8\n", __func__);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700296
297 ret = regulator_disable(hsusb_3p3);
298 if (ret) {
299 dev_err(motg->otg.dev, "%s: unable to disable the hsusb 3p3\n",
300 __func__);
301 return ret;
302 }
303 ret = regulator_set_optimum_mode(hsusb_3p3, 0);
Anji jonnala11aa5c42011-05-04 10:19:48 +0530304 if (ret < 0)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700305 pr_err("%s: Unable to set LPM of the regulator:"
Anji jonnala11aa5c42011-05-04 10:19:48 +0530306 "HSUSB_3p3\n", __func__);
307 }
308
309 pr_debug("reg (%s)\n", on ? "HPM" : "LPM");
310 return ret < 0 ? ret : 0;
311}
312
Vijayavardhan Vennapusafc464f02011-11-04 21:54:00 +0530313static void msm_hsusb_mhl_switch_enable(struct msm_otg *motg, bool on)
314{
315 static struct regulator *mhl_analog_switch;
316 struct msm_otg_platform_data *pdata = motg->pdata;
317
318 if (!pdata->mhl_enable)
319 return;
320
321 if (on) {
322 mhl_analog_switch = regulator_get(motg->otg.dev,
323 "mhl_ext_3p3v");
324 if (IS_ERR(mhl_analog_switch)) {
325 pr_err("Unable to get mhl_analog_switch\n");
326 return;
327 }
328
329 if (regulator_enable(mhl_analog_switch)) {
330 pr_err("unable to enable mhl_analog_switch\n");
331 goto put_analog_switch;
332 }
333 return;
334 }
335
336 regulator_disable(mhl_analog_switch);
337put_analog_switch:
338 regulator_put(mhl_analog_switch);
339}
340
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +0530341static int ulpi_read(struct otg_transceiver *otg, u32 reg)
342{
343 struct msm_otg *motg = container_of(otg, struct msm_otg, otg);
344 int cnt = 0;
345
346 /* initiate read operation */
347 writel(ULPI_RUN | ULPI_READ | ULPI_ADDR(reg),
348 USB_ULPI_VIEWPORT);
349
350 /* wait for completion */
351 while (cnt < ULPI_IO_TIMEOUT_USEC) {
352 if (!(readl(USB_ULPI_VIEWPORT) & ULPI_RUN))
353 break;
354 udelay(1);
355 cnt++;
356 }
357
358 if (cnt >= ULPI_IO_TIMEOUT_USEC) {
359 dev_err(otg->dev, "ulpi_read: timeout %08x\n",
360 readl(USB_ULPI_VIEWPORT));
361 return -ETIMEDOUT;
362 }
363 return ULPI_DATA_READ(readl(USB_ULPI_VIEWPORT));
364}
365
366static int ulpi_write(struct otg_transceiver *otg, u32 val, u32 reg)
367{
368 struct msm_otg *motg = container_of(otg, struct msm_otg, otg);
369 int cnt = 0;
370
371 /* initiate write operation */
372 writel(ULPI_RUN | ULPI_WRITE |
373 ULPI_ADDR(reg) | ULPI_DATA(val),
374 USB_ULPI_VIEWPORT);
375
376 /* wait for completion */
377 while (cnt < ULPI_IO_TIMEOUT_USEC) {
378 if (!(readl(USB_ULPI_VIEWPORT) & ULPI_RUN))
379 break;
380 udelay(1);
381 cnt++;
382 }
383
384 if (cnt >= ULPI_IO_TIMEOUT_USEC) {
385 dev_err(otg->dev, "ulpi_write: timeout\n");
386 return -ETIMEDOUT;
387 }
388 return 0;
389}
390
391static struct otg_io_access_ops msm_otg_io_ops = {
392 .read = ulpi_read,
393 .write = ulpi_write,
394};
395
396static void ulpi_init(struct msm_otg *motg)
397{
398 struct msm_otg_platform_data *pdata = motg->pdata;
399 int *seq = pdata->phy_init_seq;
400
401 if (!seq)
402 return;
403
404 while (seq[0] >= 0) {
405 dev_vdbg(motg->otg.dev, "ulpi: write 0x%02x to 0x%02x\n",
406 seq[0], seq[1]);
407 ulpi_write(&motg->otg, seq[0], seq[1]);
408 seq += 2;
409 }
410}
411
412static int msm_otg_link_clk_reset(struct msm_otg *motg, bool assert)
413{
414 int ret;
415
416 if (assert) {
417 ret = clk_reset(motg->clk, CLK_RESET_ASSERT);
418 if (ret)
419 dev_err(motg->otg.dev, "usb hs_clk assert failed\n");
420 } else {
421 ret = clk_reset(motg->clk, CLK_RESET_DEASSERT);
422 if (ret)
423 dev_err(motg->otg.dev, "usb hs_clk deassert failed\n");
424 }
425 return ret;
426}
427
428static int msm_otg_phy_clk_reset(struct msm_otg *motg)
429{
430 int ret;
431
Amit Blay02eff132011-09-21 16:46:24 +0300432 if (IS_ERR(motg->phy_reset_clk))
433 return 0;
434
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +0530435 ret = clk_reset(motg->phy_reset_clk, CLK_RESET_ASSERT);
436 if (ret) {
437 dev_err(motg->otg.dev, "usb phy clk assert failed\n");
438 return ret;
439 }
440 usleep_range(10000, 12000);
441 ret = clk_reset(motg->phy_reset_clk, CLK_RESET_DEASSERT);
442 if (ret)
443 dev_err(motg->otg.dev, "usb phy clk deassert failed\n");
444 return ret;
445}
446
447static int msm_otg_phy_reset(struct msm_otg *motg)
448{
449 u32 val;
450 int ret;
451 int retries;
452
453 ret = msm_otg_link_clk_reset(motg, 1);
454 if (ret)
455 return ret;
456 ret = msm_otg_phy_clk_reset(motg);
457 if (ret)
458 return ret;
459 ret = msm_otg_link_clk_reset(motg, 0);
460 if (ret)
461 return ret;
462
463 val = readl(USB_PORTSC) & ~PORTSC_PTS_MASK;
464 writel(val | PORTSC_PTS_ULPI, USB_PORTSC);
465
466 for (retries = 3; retries > 0; retries--) {
467 ret = ulpi_write(&motg->otg, ULPI_FUNC_CTRL_SUSPENDM,
468 ULPI_CLR(ULPI_FUNC_CTRL));
469 if (!ret)
470 break;
471 ret = msm_otg_phy_clk_reset(motg);
472 if (ret)
473 return ret;
474 }
475 if (!retries)
476 return -ETIMEDOUT;
477
478 /* This reset calibrates the phy, if the above write succeeded */
479 ret = msm_otg_phy_clk_reset(motg);
480 if (ret)
481 return ret;
482
483 for (retries = 3; retries > 0; retries--) {
484 ret = ulpi_read(&motg->otg, ULPI_DEBUG);
485 if (ret != -ETIMEDOUT)
486 break;
487 ret = msm_otg_phy_clk_reset(motg);
488 if (ret)
489 return ret;
490 }
491 if (!retries)
492 return -ETIMEDOUT;
493
494 dev_info(motg->otg.dev, "phy_reset: success\n");
495 return 0;
496}
497
498#define LINK_RESET_TIMEOUT_USEC (250 * 1000)
Pavankumar Kondetiaa449e12011-11-04 11:09:26 +0530499static int msm_otg_link_reset(struct msm_otg *motg)
500{
501 int cnt = 0;
502
503 writel_relaxed(USBCMD_RESET, USB_USBCMD);
504 while (cnt < LINK_RESET_TIMEOUT_USEC) {
505 if (!(readl_relaxed(USB_USBCMD) & USBCMD_RESET))
506 break;
507 udelay(1);
508 cnt++;
509 }
510 if (cnt >= LINK_RESET_TIMEOUT_USEC)
511 return -ETIMEDOUT;
512
513 /* select ULPI phy */
514 writel_relaxed(0x80000000, USB_PORTSC);
515 writel_relaxed(0x0, USB_AHBBURST);
516 writel_relaxed(0x00, USB_AHBMODE);
517
518 return 0;
519}
520
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +0530521static int msm_otg_reset(struct otg_transceiver *otg)
522{
523 struct msm_otg *motg = container_of(otg, struct msm_otg, otg);
524 struct msm_otg_platform_data *pdata = motg->pdata;
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +0530525 int ret;
526 u32 val = 0;
527 u32 ulpi_val = 0;
528
Ofir Cohen4da266f2012-01-03 10:19:29 +0200529 /*
530 * USB PHY and Link reset also reset the USB BAM.
531 * Thus perform reset operation only once to avoid
532 * USB BAM reset on other cases e.g. USB cable disconnections.
533 */
534 if (pdata->disable_reset_on_disconnect) {
535 if (motg->reset_counter)
536 return 0;
537 else
538 motg->reset_counter++;
539 }
540
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700541 clk_enable(motg->clk);
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +0530542 ret = msm_otg_phy_reset(motg);
543 if (ret) {
544 dev_err(otg->dev, "phy_reset failed\n");
545 return ret;
546 }
547
Pavankumar Kondeti4960f312011-12-06 15:46:14 +0530548 aca_id_turned_on = false;
Pavankumar Kondetiaa449e12011-11-04 11:09:26 +0530549 ret = msm_otg_link_reset(motg);
550 if (ret) {
551 dev_err(otg->dev, "link reset failed\n");
552 return ret;
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +0530553 }
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +0530554 msleep(100);
Anji jonnalaa8b8d732011-12-06 10:03:24 +0530555
556 ulpi_init(motg);
557
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700558 /* Ensure that RESET operation is completed before turning off clock */
559 mb();
Pavankumar Kondetiaa449e12011-11-04 11:09:26 +0530560
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700561 clk_disable(motg->clk);
562
Pavankumar Kondeti4960f312011-12-06 15:46:14 +0530563 if (pdata->otg_control == OTG_PHY_CONTROL) {
564 val = readl_relaxed(USB_OTGSC);
565 if (pdata->mode == USB_OTG) {
566 ulpi_val = ULPI_INT_IDGRD | ULPI_INT_SESS_VALID;
567 val |= OTGSC_IDIE | OTGSC_BSVIE;
568 } else if (pdata->mode == USB_PERIPHERAL) {
569 ulpi_val = ULPI_INT_SESS_VALID;
570 val |= OTGSC_BSVIE;
571 }
572 writel_relaxed(val, USB_OTGSC);
573 ulpi_write(otg, ulpi_val, ULPI_USB_INT_EN_RISE);
574 ulpi_write(otg, ulpi_val, ULPI_USB_INT_EN_FALL);
Pavankumar Kondeti446f4542012-02-01 13:57:13 +0530575 } else if (pdata->otg_control == OTG_PMIC_CONTROL) {
576 /* Enable PMIC pull-up */
577 pm8xxx_usb_id_pullup(1);
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +0530578 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700579
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +0530580 return 0;
581}
582
Pavankumar Kondeti8be99cf2011-08-04 10:48:08 +0530583static int msm_otg_set_suspend(struct otg_transceiver *otg, int suspend)
584{
585 struct msm_otg *motg = container_of(otg, struct msm_otg, otg);
586
587 /*
588 * Allow bus suspend only for host mode. Device mode bus suspend
589 * is not implemented yet.
590 */
591 if (!test_bit(ID, &motg->inputs) || test_bit(ID_A, &motg->inputs)) {
Pavankumar Kondetiaa449e12011-11-04 11:09:26 +0530592 /*
593 * ID_GND --> ID_A transition can not be detected in LPM.
594 * Disallow host bus suspend when ACA is enabled.
595 */
596 if (suspend && !aca_enabled())
Pavankumar Kondeti8be99cf2011-08-04 10:48:08 +0530597 pm_runtime_put(otg->dev);
598 else
599 pm_runtime_resume(otg->dev);
600 }
601
602 return 0;
603}
604
Pavankumar Kondeti87c01042010-12-07 17:53:58 +0530605#define PHY_SUSPEND_TIMEOUT_USEC (500 * 1000)
Pavankumar Kondeti70187732011-02-15 09:42:34 +0530606#define PHY_RESUME_TIMEOUT_USEC (100 * 1000)
607
608#ifdef CONFIG_PM_SLEEP
Pavankumar Kondeti87c01042010-12-07 17:53:58 +0530609static int msm_otg_suspend(struct msm_otg *motg)
610{
611 struct otg_transceiver *otg = &motg->otg;
612 struct usb_bus *bus = otg->host;
613 struct msm_otg_platform_data *pdata = motg->pdata;
614 int cnt = 0;
Pavankumar Kondeti283146f2012-01-12 12:51:19 +0530615 bool host_bus_suspend, dcp;
Pavankumar Kondeti4960f312011-12-06 15:46:14 +0530616 u32 phy_ctrl_val = 0, cmd_val;
Rajkumar Raghupathy242565d2011-12-13 12:10:59 +0530617 u32 portsc;
Pavankumar Kondeti87c01042010-12-07 17:53:58 +0530618
619 if (atomic_read(&motg->in_lpm))
620 return 0;
621
622 disable_irq(motg->irq);
Pavankumar Kondeti4960f312011-12-06 15:46:14 +0530623 host_bus_suspend = otg->host && !test_bit(ID, &motg->inputs);
Pavankumar Kondeti283146f2012-01-12 12:51:19 +0530624 dcp = motg->chg_type == USB_DCP_CHARGER;
Pavankumar Kondeti87c01042010-12-07 17:53:58 +0530625 /*
Pavankumar Kondeti04aebcb2011-05-04 10:19:49 +0530626 * Chipidea 45-nm PHY suspend sequence:
627 *
Pavankumar Kondeti87c01042010-12-07 17:53:58 +0530628 * Interrupt Latch Register auto-clear feature is not present
629 * in all PHY versions. Latch register is clear on read type.
630 * Clear latch register to avoid spurious wakeup from
631 * low power mode (LPM).
Pavankumar Kondeti04aebcb2011-05-04 10:19:49 +0530632 *
Pavankumar Kondeti87c01042010-12-07 17:53:58 +0530633 * PHY comparators are disabled when PHY enters into low power
634 * mode (LPM). Keep PHY comparators ON in LPM only when we expect
635 * VBUS/Id notifications from USB PHY. Otherwise turn off USB
636 * PHY comparators. This save significant amount of power.
Pavankumar Kondeti04aebcb2011-05-04 10:19:49 +0530637 *
Pavankumar Kondeti87c01042010-12-07 17:53:58 +0530638 * PLL is not turned off when PHY enters into low power mode (LPM).
639 * Disable PLL for maximum power savings.
640 */
Pavankumar Kondeti04aebcb2011-05-04 10:19:49 +0530641
642 if (motg->pdata->phy_type == CI_45NM_INTEGRATED_PHY) {
643 ulpi_read(otg, 0x14);
644 if (pdata->otg_control == OTG_PHY_CONTROL)
645 ulpi_write(otg, 0x01, 0x30);
646 ulpi_write(otg, 0x08, 0x09);
647 }
Pavankumar Kondeti87c01042010-12-07 17:53:58 +0530648
649 /*
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700650 * Turn off the OTG comparators, if depends on PMIC for
651 * VBUS and ID notifications.
652 */
Pavankumar Kondeti4960f312011-12-06 15:46:14 +0530653 if ((motg->caps & ALLOW_PHY_COMP_DISABLE) && !host_bus_suspend) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700654 ulpi_write(otg, OTG_COMP_DISABLE,
655 ULPI_SET(ULPI_PWR_CLK_MNG_REG));
656 motg->lpm_flags |= PHY_OTG_COMP_DISABLED;
657 }
658
Rajkumar Raghupathy242565d2011-12-13 12:10:59 +0530659 /* Set the PHCD bit, only if it is not set by the controller.
Pavankumar Kondeti87c01042010-12-07 17:53:58 +0530660 * PHY may take some time or even fail to enter into low power
661 * mode (LPM). Hence poll for 500 msec and reset the PHY and link
662 * in failure case.
663 */
Rajkumar Raghupathy242565d2011-12-13 12:10:59 +0530664 portsc = readl_relaxed(USB_PORTSC);
665 if (!(portsc & PORTSC_PHCD)) {
666 writel_relaxed(portsc | PORTSC_PHCD,
667 USB_PORTSC);
668 while (cnt < PHY_SUSPEND_TIMEOUT_USEC) {
669 if (readl_relaxed(USB_PORTSC) & PORTSC_PHCD)
670 break;
671 udelay(1);
672 cnt++;
673 }
Pavankumar Kondeti87c01042010-12-07 17:53:58 +0530674 }
675
676 if (cnt >= PHY_SUSPEND_TIMEOUT_USEC) {
677 dev_err(otg->dev, "Unable to suspend PHY\n");
678 msm_otg_reset(otg);
679 enable_irq(motg->irq);
680 return -ETIMEDOUT;
681 }
682
683 /*
684 * PHY has capability to generate interrupt asynchronously in low
685 * power mode (LPM). This interrupt is level triggered. So USB IRQ
686 * line must be disabled till async interrupt enable bit is cleared
687 * in USBCMD register. Assert STP (ULPI interface STOP signal) to
688 * block data communication from PHY.
689 */
Pavankumar Kondeti4960f312011-12-06 15:46:14 +0530690 cmd_val = readl_relaxed(USB_USBCMD);
691 if (host_bus_suspend)
692 cmd_val |= ASYNC_INTR_CTRL | ULPI_STP_CTRL;
693 else
694 cmd_val |= ULPI_STP_CTRL;
695 writel_relaxed(cmd_val, USB_USBCMD);
Pavankumar Kondeti87c01042010-12-07 17:53:58 +0530696
Pavankumar Kondeti283146f2012-01-12 12:51:19 +0530697 /*
698 * BC1.2 spec mandates PD to enable VDP_SRC when charging from DCP.
699 * PHY retention and collapse can not happen with VDP_SRC enabled.
700 */
701 if (motg->caps & ALLOW_PHY_RETENTION && !host_bus_suspend && !dcp) {
Amit Blay58b31472011-11-18 09:39:39 +0200702 phy_ctrl_val = readl_relaxed(USB_PHY_CTRL);
703 if (motg->pdata->otg_control == OTG_PHY_CONTROL)
704 /* Enable PHY HV interrupts to wake MPM/Link */
705 phy_ctrl_val |=
706 (PHY_IDHV_INTEN | PHY_OTGSESSVLDHV_INTEN);
707
708 writel_relaxed(phy_ctrl_val & ~PHY_RETEN, USB_PHY_CTRL);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700709 motg->lpm_flags |= PHY_RETENTIONED;
710 }
Pavankumar Kondeti04aebcb2011-05-04 10:19:49 +0530711
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700712 /* Ensure that above operation is completed before turning off clocks */
713 mb();
Pavankumar Kondeti87c01042010-12-07 17:53:58 +0530714 clk_disable(motg->pclk);
Manu Gautam5143b252012-01-05 19:25:23 -0800715 clk_disable(motg->core_clk);
Anji jonnala0f73cac2011-05-04 10:19:46 +0530716
Anji jonnala7da3f262011-12-02 17:22:14 -0800717 /* usb phy no more require TCXO clock, hence vote for TCXO disable */
Stephen Boyd7dd22662012-01-26 16:09:31 -0800718 clk_disable_unprepare(motg->xo_handle);
Anji jonnala7da3f262011-12-02 17:22:14 -0800719
Pavankumar Kondeti283146f2012-01-12 12:51:19 +0530720 if (motg->caps & ALLOW_PHY_POWER_COLLAPSE &&
721 !host_bus_suspend && !dcp) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700722 msm_hsusb_ldo_enable(motg, 0);
723 motg->lpm_flags |= PHY_PWR_COLLAPSED;
Pavankumar Kondeti04aebcb2011-05-04 10:19:49 +0530724 }
725
Vijayavardhan Vennapusafc464f02011-11-04 21:54:00 +0530726 if (motg->lpm_flags & PHY_RETENTIONED) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700727 msm_hsusb_config_vddcx(0);
Vijayavardhan Vennapusafc464f02011-11-04 21:54:00 +0530728 msm_hsusb_mhl_switch_enable(motg, 0);
729 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700730
731 if (device_may_wakeup(otg->dev)) {
Pavankumar Kondeti87c01042010-12-07 17:53:58 +0530732 enable_irq_wake(motg->irq);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700733 if (motg->pdata->pmic_id_irq)
734 enable_irq_wake(motg->pdata->pmic_id_irq);
735 }
Pavankumar Kondeti87c01042010-12-07 17:53:58 +0530736 if (bus)
737 clear_bit(HCD_FLAG_HW_ACCESSIBLE, &(bus_to_hcd(bus))->flags);
738
739 atomic_set(&motg->in_lpm, 1);
740 enable_irq(motg->irq);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700741 wake_unlock(&motg->wlock);
Pavankumar Kondeti87c01042010-12-07 17:53:58 +0530742
743 dev_info(otg->dev, "USB in low power mode\n");
744
745 return 0;
746}
747
Pavankumar Kondeti87c01042010-12-07 17:53:58 +0530748static int msm_otg_resume(struct msm_otg *motg)
749{
750 struct otg_transceiver *otg = &motg->otg;
751 struct usb_bus *bus = otg->host;
752 int cnt = 0;
753 unsigned temp;
Amit Blay58b31472011-11-18 09:39:39 +0200754 u32 phy_ctrl_val = 0;
Anji jonnala7da3f262011-12-02 17:22:14 -0800755 unsigned ret;
Pavankumar Kondeti87c01042010-12-07 17:53:58 +0530756
757 if (!atomic_read(&motg->in_lpm))
758 return 0;
759
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700760 wake_lock(&motg->wlock);
Anji jonnala7da3f262011-12-02 17:22:14 -0800761
762 /* Vote for TCXO when waking up the phy */
Stephen Boyd7dd22662012-01-26 16:09:31 -0800763 ret = clk_prepare_enable(motg->xo_handle);
Anji jonnala7da3f262011-12-02 17:22:14 -0800764 if (ret)
765 dev_err(otg->dev, "%s failed to vote for "
766 "TCXO D0 buffer%d\n", __func__, ret);
767
Manu Gautam5143b252012-01-05 19:25:23 -0800768 clk_enable(motg->core_clk);
Amit Blay137575f2011-11-06 15:20:54 +0200769
Pavankumar Kondeti87c01042010-12-07 17:53:58 +0530770 clk_enable(motg->pclk);
Pavankumar Kondeti87c01042010-12-07 17:53:58 +0530771
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700772 if (motg->lpm_flags & PHY_PWR_COLLAPSED) {
773 msm_hsusb_ldo_enable(motg, 1);
774 motg->lpm_flags &= ~PHY_PWR_COLLAPSED;
775 }
776
777 if (motg->lpm_flags & PHY_RETENTIONED) {
Vijayavardhan Vennapusafc464f02011-11-04 21:54:00 +0530778 msm_hsusb_mhl_switch_enable(motg, 1);
Pavankumar Kondeti04aebcb2011-05-04 10:19:49 +0530779 msm_hsusb_config_vddcx(1);
Amit Blay58b31472011-11-18 09:39:39 +0200780 phy_ctrl_val = readl_relaxed(USB_PHY_CTRL);
781 phy_ctrl_val |= PHY_RETEN;
782 if (motg->pdata->otg_control == OTG_PHY_CONTROL)
783 /* Disable PHY HV interrupts */
784 phy_ctrl_val &=
785 ~(PHY_IDHV_INTEN | PHY_OTGSESSVLDHV_INTEN);
786 writel_relaxed(phy_ctrl_val, USB_PHY_CTRL);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700787 motg->lpm_flags &= ~PHY_RETENTIONED;
Pavankumar Kondeti04aebcb2011-05-04 10:19:49 +0530788 }
789
Pavankumar Kondeti87c01042010-12-07 17:53:58 +0530790 temp = readl(USB_USBCMD);
791 temp &= ~ASYNC_INTR_CTRL;
792 temp &= ~ULPI_STP_CTRL;
793 writel(temp, USB_USBCMD);
794
795 /*
796 * PHY comes out of low power mode (LPM) in case of wakeup
797 * from asynchronous interrupt.
798 */
799 if (!(readl(USB_PORTSC) & PORTSC_PHCD))
800 goto skip_phy_resume;
801
802 writel(readl(USB_PORTSC) & ~PORTSC_PHCD, USB_PORTSC);
803 while (cnt < PHY_RESUME_TIMEOUT_USEC) {
804 if (!(readl(USB_PORTSC) & PORTSC_PHCD))
805 break;
806 udelay(1);
807 cnt++;
808 }
809
810 if (cnt >= PHY_RESUME_TIMEOUT_USEC) {
811 /*
812 * This is a fatal error. Reset the link and
813 * PHY. USB state can not be restored. Re-insertion
814 * of USB cable is the only way to get USB working.
815 */
816 dev_err(otg->dev, "Unable to resume USB."
817 "Re-plugin the cable\n");
818 msm_otg_reset(otg);
819 }
820
821skip_phy_resume:
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700822 /* Turn on the OTG comparators on resume */
823 if (motg->lpm_flags & PHY_OTG_COMP_DISABLED) {
824 ulpi_write(otg, OTG_COMP_DISABLE,
825 ULPI_CLR(ULPI_PWR_CLK_MNG_REG));
826 motg->lpm_flags &= ~PHY_OTG_COMP_DISABLED;
827 }
828 if (device_may_wakeup(otg->dev)) {
Pavankumar Kondeti87c01042010-12-07 17:53:58 +0530829 disable_irq_wake(motg->irq);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700830 if (motg->pdata->pmic_id_irq)
831 disable_irq_wake(motg->pdata->pmic_id_irq);
832 }
Pavankumar Kondeti87c01042010-12-07 17:53:58 +0530833 if (bus)
834 set_bit(HCD_FLAG_HW_ACCESSIBLE, &(bus_to_hcd(bus))->flags);
835
Pavankumar Kondeti2ce2c3a2011-05-02 11:56:33 +0530836 atomic_set(&motg->in_lpm, 0);
837
Pavankumar Kondeti87c01042010-12-07 17:53:58 +0530838 if (motg->async_int) {
839 motg->async_int = 0;
Pavankumar Kondeti87c01042010-12-07 17:53:58 +0530840 enable_irq(motg->irq);
841 }
842
Pavankumar Kondeti87c01042010-12-07 17:53:58 +0530843 dev_info(otg->dev, "USB exited from low power mode\n");
844
845 return 0;
846}
Pavankumar Kondeti70187732011-02-15 09:42:34 +0530847#endif
Pavankumar Kondeti87c01042010-12-07 17:53:58 +0530848
Chiranjeevi Velempati39f9b952012-01-24 10:46:12 +0530849static int msm_otg_notify_chg_type(struct msm_otg *motg)
850{
851 static int charger_type;
852 /*
853 * TODO
854 * Unify OTG driver charger types and power supply charger types
855 */
856 if (charger_type == motg->chg_type)
857 return 0;
858
859 if (motg->chg_type == USB_SDP_CHARGER)
860 charger_type = POWER_SUPPLY_TYPE_USB;
861 else if (motg->chg_type == USB_CDP_CHARGER)
862 charger_type = POWER_SUPPLY_TYPE_USB_CDP;
863 else if (motg->chg_type == USB_DCP_CHARGER)
864 charger_type = POWER_SUPPLY_TYPE_USB_DCP;
865 else if ((motg->chg_type == USB_ACA_DOCK_CHARGER ||
866 motg->chg_type == USB_ACA_A_CHARGER ||
867 motg->chg_type == USB_ACA_B_CHARGER ||
868 motg->chg_type == USB_ACA_C_CHARGER))
869 charger_type = POWER_SUPPLY_TYPE_USB_ACA;
870 else
871 charger_type = POWER_SUPPLY_TYPE_BATTERY;
872
873 return pm8921_set_usb_power_supply_type(charger_type);
874}
875
Amit Blay0f7edf72012-01-15 10:11:27 +0200876static int msm_otg_notify_power_supply(struct msm_otg *motg, unsigned mA)
877{
878 struct power_supply *psy;
879
880 psy = power_supply_get_by_name("usb");
881 if (!psy)
882 goto psy_not_supported;
883
884 if (motg->cur_power == 0 && mA > 0) {
885 /* Enable charging */
886 if (power_supply_set_online(psy, true))
887 goto psy_not_supported;
888 } else if (motg->cur_power > 0 && mA == 0) {
889 /* Disable charging */
890 if (power_supply_set_online(psy, false))
891 goto psy_not_supported;
892 return 0;
893 }
894 /* Set max current limit */
895 if (power_supply_set_current_limit(psy, 1000*mA))
896 goto psy_not_supported;
897
898 return 0;
899
900psy_not_supported:
901 dev_dbg(motg->otg.dev, "Power Supply doesn't support USB charger\n");
902 return -ENXIO;
903}
904
Pavankumar Kondetid8608522011-05-04 10:19:47 +0530905static void msm_otg_notify_charger(struct msm_otg *motg, unsigned mA)
906{
Pavankumar Kondetiaa449e12011-11-04 11:09:26 +0530907 if ((motg->chg_type == USB_ACA_DOCK_CHARGER ||
908 motg->chg_type == USB_ACA_A_CHARGER ||
909 motg->chg_type == USB_ACA_B_CHARGER ||
910 motg->chg_type == USB_ACA_C_CHARGER) &&
911 mA > IDEV_ACA_CHG_LIMIT)
912 mA = IDEV_ACA_CHG_LIMIT;
913
Chiranjeevi Velempati39f9b952012-01-24 10:46:12 +0530914 if (msm_otg_notify_chg_type(motg))
915 dev_err(motg->otg.dev,
916 "Failed notifying %d charger type to PMIC\n",
917 motg->chg_type);
918
Pavankumar Kondetid8608522011-05-04 10:19:47 +0530919 if (motg->cur_power == mA)
920 return;
921
Pavankumar Kondetid8608522011-05-04 10:19:47 +0530922 dev_info(motg->otg.dev, "Avail curr from USB = %u\n", mA);
Amit Blay0f7edf72012-01-15 10:11:27 +0200923
924 /*
925 * Use Power Supply API if supported, otherwise fallback
926 * to legacy pm8921 API.
927 */
928 if (msm_otg_notify_power_supply(motg, mA))
929 pm8921_charger_vbus_draw(mA);
930
Pavankumar Kondetid8608522011-05-04 10:19:47 +0530931 motg->cur_power = mA;
932}
933
934static int msm_otg_set_power(struct otg_transceiver *otg, unsigned mA)
935{
936 struct msm_otg *motg = container_of(otg, struct msm_otg, otg);
937
938 /*
939 * Gadget driver uses set_power method to notify about the
940 * available current based on suspend/configured states.
941 *
942 * IDEV_CHG can be drawn irrespective of suspend/un-configured
943 * states when CDP/ACA is connected.
944 */
945 if (motg->chg_type == USB_SDP_CHARGER)
946 msm_otg_notify_charger(motg, mA);
947
948 return 0;
949}
950
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +0530951static void msm_otg_start_host(struct otg_transceiver *otg, int on)
952{
953 struct msm_otg *motg = container_of(otg, struct msm_otg, otg);
954 struct msm_otg_platform_data *pdata = motg->pdata;
955 struct usb_hcd *hcd;
956
957 if (!otg->host)
958 return;
959
960 hcd = bus_to_hcd(otg->host);
961
962 if (on) {
963 dev_dbg(otg->dev, "host on\n");
964
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +0530965 /*
966 * Some boards have a switch cotrolled by gpio
967 * to enable/disable internal HUB. Enable internal
968 * HUB before kicking the host.
969 */
970 if (pdata->setup_gpio)
971 pdata->setup_gpio(OTG_STATE_A_HOST);
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +0530972 usb_add_hcd(hcd, hcd->irq, IRQF_SHARED);
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +0530973 } else {
974 dev_dbg(otg->dev, "host off\n");
975
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +0530976 usb_remove_hcd(hcd);
Pavankumar Kondetiaa449e12011-11-04 11:09:26 +0530977 /* HCD core reset all bits of PORTSC. select ULPI phy */
978 writel_relaxed(0x80000000, USB_PORTSC);
979
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +0530980 if (pdata->setup_gpio)
981 pdata->setup_gpio(OTG_STATE_UNDEFINED);
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +0530982 }
983}
984
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700985static int msm_otg_usbdev_notify(struct notifier_block *self,
986 unsigned long action, void *priv)
987{
988 struct msm_otg *motg = container_of(self, struct msm_otg, usbdev_nb);
Pavankumar Kondetiaa449e12011-11-04 11:09:26 +0530989 struct usb_device *udev = priv;
990
991 if (!aca_enabled())
992 goto out;
993
994 if (action == USB_BUS_ADD || action == USB_BUS_REMOVE)
995 goto out;
996
997 if (udev->bus != motg->otg.host)
998 goto out;
999 /*
1000 * Interested in devices connected directly to the root hub.
1001 * ACA dock can supply IDEV_CHG irrespective devices connected
1002 * on the accessory port.
1003 */
1004 if (!udev->parent || udev->parent->parent ||
1005 motg->chg_type == USB_ACA_DOCK_CHARGER)
1006 goto out;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001007
1008 switch (action) {
1009 case USB_DEVICE_ADD:
Pavankumar Kondetiaa449e12011-11-04 11:09:26 +05301010 usb_disable_autosuspend(udev);
1011 /* fall through */
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001012 case USB_DEVICE_CONFIG:
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001013 if (udev->actconfig)
1014 motg->mA_port = udev->actconfig->desc.bMaxPower * 2;
1015 else
1016 motg->mA_port = IUNIT;
Pavankumar Kondetiaa449e12011-11-04 11:09:26 +05301017 break;
1018 case USB_DEVICE_REMOVE:
1019 motg->mA_port = IUNIT;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001020 break;
1021 default:
1022 break;
1023 }
Pavankumar Kondetiaa449e12011-11-04 11:09:26 +05301024 if (test_bit(ID_A, &motg->inputs))
1025 msm_otg_notify_charger(motg, IDEV_ACA_CHG_MAX -
1026 motg->mA_port);
1027out:
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001028 return NOTIFY_OK;
1029}
1030
Mayank Ranae3926882011-12-26 09:47:54 +05301031static void msm_hsusb_vbus_power(struct msm_otg *motg, bool on)
1032{
1033 int ret;
1034 static bool vbus_is_on;
1035
1036 if (vbus_is_on == on)
1037 return;
1038
1039 if (motg->pdata->vbus_power) {
Mayank Rana91f597e2012-01-20 10:12:06 +05301040 ret = motg->pdata->vbus_power(on);
1041 if (!ret)
1042 vbus_is_on = on;
Mayank Ranae3926882011-12-26 09:47:54 +05301043 return;
1044 }
1045
1046 if (!vbus_otg) {
1047 pr_err("vbus_otg is NULL.");
1048 return;
1049 }
1050
Abhijeet Dharmapurikarbe054882012-01-03 20:27:07 -08001051 /*
1052 * if entering host mode tell the charger to not draw any current
1053 * from usb - if exiting host mode let the charger draw current
1054 */
1055 pm8921_disable_source_current(on);
Mayank Ranae3926882011-12-26 09:47:54 +05301056 if (on) {
1057 ret = regulator_enable(vbus_otg);
1058 if (ret) {
1059 pr_err("unable to enable vbus_otg\n");
1060 return;
1061 }
1062 vbus_is_on = true;
1063 } else {
1064 ret = regulator_disable(vbus_otg);
1065 if (ret) {
1066 pr_err("unable to disable vbus_otg\n");
1067 return;
1068 }
1069 vbus_is_on = false;
1070 }
1071}
1072
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05301073static int msm_otg_set_host(struct otg_transceiver *otg, struct usb_bus *host)
1074{
1075 struct msm_otg *motg = container_of(otg, struct msm_otg, otg);
1076 struct usb_hcd *hcd;
1077
1078 /*
1079 * Fail host registration if this board can support
1080 * only peripheral configuration.
1081 */
1082 if (motg->pdata->mode == USB_PERIPHERAL) {
1083 dev_info(otg->dev, "Host mode is not supported\n");
1084 return -ENODEV;
1085 }
1086
Mayank Ranae3926882011-12-26 09:47:54 +05301087 if (!motg->pdata->vbus_power && host) {
1088 vbus_otg = regulator_get(motg->otg.dev, "vbus_otg");
1089 if (IS_ERR(vbus_otg)) {
1090 pr_err("Unable to get vbus_otg\n");
1091 return -ENODEV;
1092 }
1093 }
1094
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05301095 if (!host) {
1096 if (otg->state == OTG_STATE_A_HOST) {
Pavankumar Kondeti87c01042010-12-07 17:53:58 +05301097 pm_runtime_get_sync(otg->dev);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001098 usb_unregister_notify(&motg->usbdev_nb);
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05301099 msm_otg_start_host(otg, 0);
Mayank Ranae3926882011-12-26 09:47:54 +05301100 msm_hsusb_vbus_power(motg, 0);
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05301101 otg->host = NULL;
1102 otg->state = OTG_STATE_UNDEFINED;
1103 schedule_work(&motg->sm_work);
1104 } else {
1105 otg->host = NULL;
1106 }
1107
Mayank Ranae3926882011-12-26 09:47:54 +05301108 if (vbus_otg)
1109 regulator_put(vbus_otg);
1110
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05301111 return 0;
1112 }
1113
1114 hcd = bus_to_hcd(host);
1115 hcd->power_budget = motg->pdata->power_budget;
1116
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001117 motg->usbdev_nb.notifier_call = msm_otg_usbdev_notify;
1118 usb_register_notify(&motg->usbdev_nb);
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05301119 otg->host = host;
1120 dev_dbg(otg->dev, "host driver registered w/ tranceiver\n");
1121
1122 /*
1123 * Kick the state machine work, if peripheral is not supported
1124 * or peripheral is already registered with us.
1125 */
Pavankumar Kondeti87c01042010-12-07 17:53:58 +05301126 if (motg->pdata->mode == USB_HOST || otg->gadget) {
1127 pm_runtime_get_sync(otg->dev);
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05301128 schedule_work(&motg->sm_work);
Pavankumar Kondeti87c01042010-12-07 17:53:58 +05301129 }
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05301130
1131 return 0;
1132}
1133
1134static void msm_otg_start_peripheral(struct otg_transceiver *otg, int on)
1135{
Manu Gautamcd82e9d2011-12-20 14:17:28 +05301136 int ret;
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05301137 struct msm_otg *motg = container_of(otg, struct msm_otg, otg);
1138 struct msm_otg_platform_data *pdata = motg->pdata;
1139
1140 if (!otg->gadget)
1141 return;
1142
1143 if (on) {
1144 dev_dbg(otg->dev, "gadget on\n");
1145 /*
1146 * Some boards have a switch cotrolled by gpio
1147 * to enable/disable internal HUB. Disable internal
1148 * HUB before kicking the gadget.
1149 */
1150 if (pdata->setup_gpio)
1151 pdata->setup_gpio(OTG_STATE_B_PERIPHERAL);
Anji jonnalaa7c1c5c2011-12-12 12:20:36 +05301152 /*
1153 * vote for minimum dma_latency to prevent idle
1154 * power collapse(pc) while running in peripheral mode.
1155 */
1156 otg_pm_qos_update_latency(motg, 1);
Manu Gautamcd82e9d2011-12-20 14:17:28 +05301157 /* Configure BUS performance parameters for MAX bandwidth */
1158 if (motg->bus_perf_client) {
1159 ret = msm_bus_scale_client_update_request(
1160 motg->bus_perf_client, 1);
1161 if (ret)
1162 dev_err(motg->otg.dev, "%s: Failed to vote for "
1163 "bus bandwidth %d\n", __func__, ret);
1164 }
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05301165 usb_gadget_vbus_connect(otg->gadget);
1166 } else {
1167 dev_dbg(otg->dev, "gadget off\n");
1168 usb_gadget_vbus_disconnect(otg->gadget);
Anji jonnalaa7c1c5c2011-12-12 12:20:36 +05301169 otg_pm_qos_update_latency(motg, 0);
Manu Gautamcd82e9d2011-12-20 14:17:28 +05301170 /* Configure BUS performance parameters to default */
1171 if (motg->bus_perf_client) {
1172 ret = msm_bus_scale_client_update_request(
1173 motg->bus_perf_client, 0);
1174 if (ret)
1175 dev_err(motg->otg.dev, "%s: Failed to devote "
1176 "for bus bw %d\n", __func__, ret);
1177 }
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05301178 if (pdata->setup_gpio)
1179 pdata->setup_gpio(OTG_STATE_UNDEFINED);
1180 }
1181
1182}
1183
1184static int msm_otg_set_peripheral(struct otg_transceiver *otg,
1185 struct usb_gadget *gadget)
1186{
1187 struct msm_otg *motg = container_of(otg, struct msm_otg, otg);
1188
1189 /*
1190 * Fail peripheral registration if this board can support
1191 * only host configuration.
1192 */
1193 if (motg->pdata->mode == USB_HOST) {
1194 dev_info(otg->dev, "Peripheral mode is not supported\n");
1195 return -ENODEV;
1196 }
1197
1198 if (!gadget) {
1199 if (otg->state == OTG_STATE_B_PERIPHERAL) {
Pavankumar Kondeti87c01042010-12-07 17:53:58 +05301200 pm_runtime_get_sync(otg->dev);
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05301201 msm_otg_start_peripheral(otg, 0);
1202 otg->gadget = NULL;
1203 otg->state = OTG_STATE_UNDEFINED;
1204 schedule_work(&motg->sm_work);
1205 } else {
1206 otg->gadget = NULL;
1207 }
1208
1209 return 0;
1210 }
1211 otg->gadget = gadget;
1212 dev_dbg(otg->dev, "peripheral driver registered w/ tranceiver\n");
1213
1214 /*
1215 * Kick the state machine work, if host is not supported
1216 * or host is already registered with us.
1217 */
Pavankumar Kondeti87c01042010-12-07 17:53:58 +05301218 if (motg->pdata->mode == USB_PERIPHERAL || otg->host) {
1219 pm_runtime_get_sync(otg->dev);
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05301220 schedule_work(&motg->sm_work);
Pavankumar Kondeti87c01042010-12-07 17:53:58 +05301221 }
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05301222
1223 return 0;
1224}
1225
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001226static bool msm_chg_aca_detect(struct msm_otg *motg)
1227{
1228 struct otg_transceiver *otg = &motg->otg;
1229 u32 int_sts;
1230 bool ret = false;
1231
Pavankumar Kondetiaa449e12011-11-04 11:09:26 +05301232 if (!aca_enabled())
1233 goto out;
1234
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001235 if (motg->pdata->phy_type == CI_45NM_INTEGRATED_PHY)
1236 goto out;
1237
1238 int_sts = ulpi_read(otg, 0x87);
1239 switch (int_sts & 0x1C) {
1240 case 0x08:
1241 if (!test_and_set_bit(ID_A, &motg->inputs)) {
1242 dev_dbg(otg->dev, "ID_A\n");
1243 motg->chg_type = USB_ACA_A_CHARGER;
1244 motg->chg_state = USB_CHG_STATE_DETECTED;
1245 clear_bit(ID_B, &motg->inputs);
1246 clear_bit(ID_C, &motg->inputs);
Pavankumar Kondetiaa449e12011-11-04 11:09:26 +05301247 set_bit(ID, &motg->inputs);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001248 ret = true;
1249 }
1250 break;
1251 case 0x0C:
1252 if (!test_and_set_bit(ID_B, &motg->inputs)) {
1253 dev_dbg(otg->dev, "ID_B\n");
1254 motg->chg_type = USB_ACA_B_CHARGER;
1255 motg->chg_state = USB_CHG_STATE_DETECTED;
1256 clear_bit(ID_A, &motg->inputs);
1257 clear_bit(ID_C, &motg->inputs);
Pavankumar Kondetiaa449e12011-11-04 11:09:26 +05301258 set_bit(ID, &motg->inputs);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001259 ret = true;
1260 }
1261 break;
1262 case 0x10:
1263 if (!test_and_set_bit(ID_C, &motg->inputs)) {
1264 dev_dbg(otg->dev, "ID_C\n");
1265 motg->chg_type = USB_ACA_C_CHARGER;
1266 motg->chg_state = USB_CHG_STATE_DETECTED;
1267 clear_bit(ID_A, &motg->inputs);
1268 clear_bit(ID_B, &motg->inputs);
Pavankumar Kondetiaa449e12011-11-04 11:09:26 +05301269 set_bit(ID, &motg->inputs);
1270 ret = true;
1271 }
1272 break;
1273 case 0x04:
1274 if (test_and_clear_bit(ID, &motg->inputs)) {
1275 dev_dbg(otg->dev, "ID_GND\n");
1276 motg->chg_type = USB_INVALID_CHARGER;
1277 motg->chg_state = USB_CHG_STATE_UNDEFINED;
1278 clear_bit(ID_A, &motg->inputs);
1279 clear_bit(ID_B, &motg->inputs);
1280 clear_bit(ID_C, &motg->inputs);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001281 ret = true;
1282 }
1283 break;
1284 default:
1285 ret = test_and_clear_bit(ID_A, &motg->inputs) |
1286 test_and_clear_bit(ID_B, &motg->inputs) |
Pavankumar Kondetiaa449e12011-11-04 11:09:26 +05301287 test_and_clear_bit(ID_C, &motg->inputs) |
1288 !test_and_set_bit(ID, &motg->inputs);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001289 if (ret) {
Pavankumar Kondetiaa449e12011-11-04 11:09:26 +05301290 dev_dbg(otg->dev, "ID A/B/C/GND is no more\n");
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001291 motg->chg_type = USB_INVALID_CHARGER;
1292 motg->chg_state = USB_CHG_STATE_UNDEFINED;
1293 }
1294 }
1295out:
1296 return ret;
1297}
1298
1299static void msm_chg_enable_aca_det(struct msm_otg *motg)
1300{
1301 struct otg_transceiver *otg = &motg->otg;
1302
Pavankumar Kondetiaa449e12011-11-04 11:09:26 +05301303 if (!aca_enabled())
1304 return;
1305
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001306 switch (motg->pdata->phy_type) {
1307 case SNPS_28NM_INTEGRATED_PHY:
Pavankumar Kondetiaa449e12011-11-04 11:09:26 +05301308 /* Disable ID_GND in link and PHY */
1309 writel_relaxed(readl_relaxed(USB_OTGSC) & ~(OTGSC_IDPU |
1310 OTGSC_IDIE), USB_OTGSC);
1311 ulpi_write(otg, 0x01, 0x0C);
1312 ulpi_write(otg, 0x10, 0x0F);
1313 ulpi_write(otg, 0x10, 0x12);
Pavankumar Kondeti446f4542012-02-01 13:57:13 +05301314 /* Disable PMIC ID pull-up */
1315 pm8xxx_usb_id_pullup(0);
Pavankumar Kondetiaa449e12011-11-04 11:09:26 +05301316 /* Enable ACA ID detection */
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001317 ulpi_write(otg, 0x20, 0x85);
Pavankumar Kondeti4960f312011-12-06 15:46:14 +05301318 aca_id_turned_on = true;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001319 break;
1320 default:
1321 break;
1322 }
1323}
1324
1325static void msm_chg_enable_aca_intr(struct msm_otg *motg)
1326{
1327 struct otg_transceiver *otg = &motg->otg;
1328
Pavankumar Kondetiaa449e12011-11-04 11:09:26 +05301329 if (!aca_enabled())
1330 return;
1331
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001332 switch (motg->pdata->phy_type) {
1333 case SNPS_28NM_INTEGRATED_PHY:
Pavankumar Kondetiaa449e12011-11-04 11:09:26 +05301334 /* Enable ACA Detection interrupt (on any RID change) */
1335 ulpi_write(otg, 0x01, 0x94);
1336 break;
1337 default:
1338 break;
1339 }
1340}
1341
1342static void msm_chg_disable_aca_intr(struct msm_otg *motg)
1343{
1344 struct otg_transceiver *otg = &motg->otg;
1345
1346 if (!aca_enabled())
1347 return;
1348
1349 switch (motg->pdata->phy_type) {
1350 case SNPS_28NM_INTEGRATED_PHY:
1351 ulpi_write(otg, 0x01, 0x95);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001352 break;
1353 default:
1354 break;
1355 }
1356}
1357
1358static bool msm_chg_check_aca_intr(struct msm_otg *motg)
1359{
1360 struct otg_transceiver *otg = &motg->otg;
1361 bool ret = false;
1362
Pavankumar Kondetiaa449e12011-11-04 11:09:26 +05301363 if (!aca_enabled())
1364 return ret;
1365
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001366 switch (motg->pdata->phy_type) {
1367 case SNPS_28NM_INTEGRATED_PHY:
1368 if (ulpi_read(otg, 0x91) & 1) {
1369 dev_dbg(otg->dev, "RID change\n");
1370 ulpi_write(otg, 0x01, 0x92);
1371 ret = msm_chg_aca_detect(motg);
1372 }
1373 default:
1374 break;
1375 }
1376 return ret;
1377}
Pavankumar Kondetiaa449e12011-11-04 11:09:26 +05301378
1379static void msm_otg_id_timer_func(unsigned long data)
1380{
1381 struct msm_otg *motg = (struct msm_otg *) data;
1382
1383 if (!aca_enabled())
1384 return;
1385
1386 if (atomic_read(&motg->in_lpm)) {
1387 dev_dbg(motg->otg.dev, "timer: in lpm\n");
1388 return;
1389 }
1390
1391 if (msm_chg_check_aca_intr(motg)) {
1392 dev_dbg(motg->otg.dev, "timer: aca work\n");
1393 schedule_work(&motg->sm_work);
1394 }
1395
1396 if (!test_bit(ID, &motg->inputs) || test_bit(ID_A, &motg->inputs))
1397 mod_timer(&motg->id_timer, ID_TIMER_FREQ);
1398}
1399
Pavankumar Kondetid8608522011-05-04 10:19:47 +05301400static bool msm_chg_check_secondary_det(struct msm_otg *motg)
1401{
1402 struct otg_transceiver *otg = &motg->otg;
1403 u32 chg_det;
1404 bool ret = false;
1405
1406 switch (motg->pdata->phy_type) {
1407 case CI_45NM_INTEGRATED_PHY:
1408 chg_det = ulpi_read(otg, 0x34);
1409 ret = chg_det & (1 << 4);
1410 break;
1411 case SNPS_28NM_INTEGRATED_PHY:
1412 chg_det = ulpi_read(otg, 0x87);
1413 ret = chg_det & 1;
1414 break;
1415 default:
1416 break;
1417 }
1418 return ret;
1419}
1420
1421static void msm_chg_enable_secondary_det(struct msm_otg *motg)
1422{
1423 struct otg_transceiver *otg = &motg->otg;
1424 u32 chg_det;
1425
1426 switch (motg->pdata->phy_type) {
1427 case CI_45NM_INTEGRATED_PHY:
1428 chg_det = ulpi_read(otg, 0x34);
1429 /* Turn off charger block */
1430 chg_det |= ~(1 << 1);
1431 ulpi_write(otg, chg_det, 0x34);
1432 udelay(20);
1433 /* control chg block via ULPI */
1434 chg_det &= ~(1 << 3);
1435 ulpi_write(otg, chg_det, 0x34);
1436 /* put it in host mode for enabling D- source */
1437 chg_det &= ~(1 << 2);
1438 ulpi_write(otg, chg_det, 0x34);
1439 /* Turn on chg detect block */
1440 chg_det &= ~(1 << 1);
1441 ulpi_write(otg, chg_det, 0x34);
1442 udelay(20);
1443 /* enable chg detection */
1444 chg_det &= ~(1 << 0);
1445 ulpi_write(otg, chg_det, 0x34);
1446 break;
1447 case SNPS_28NM_INTEGRATED_PHY:
Pavankumar Kondeti283146f2012-01-12 12:51:19 +05301448 /* Turn off VDP_SRC */
1449 ulpi_write(otg, 0x3, 0x86);
1450 msleep(20);
Pavankumar Kondetid8608522011-05-04 10:19:47 +05301451 /*
1452 * Configure DM as current source, DP as current sink
1453 * and enable battery charging comparators.
1454 */
1455 ulpi_write(otg, 0x8, 0x85);
1456 ulpi_write(otg, 0x2, 0x85);
1457 ulpi_write(otg, 0x1, 0x85);
1458 break;
1459 default:
1460 break;
1461 }
1462}
1463
1464static bool msm_chg_check_primary_det(struct msm_otg *motg)
1465{
1466 struct otg_transceiver *otg = &motg->otg;
1467 u32 chg_det;
1468 bool ret = false;
1469
1470 switch (motg->pdata->phy_type) {
1471 case CI_45NM_INTEGRATED_PHY:
1472 chg_det = ulpi_read(otg, 0x34);
1473 ret = chg_det & (1 << 4);
1474 break;
1475 case SNPS_28NM_INTEGRATED_PHY:
1476 chg_det = ulpi_read(otg, 0x87);
1477 ret = chg_det & 1;
1478 break;
1479 default:
1480 break;
1481 }
1482 return ret;
1483}
1484
1485static void msm_chg_enable_primary_det(struct msm_otg *motg)
1486{
1487 struct otg_transceiver *otg = &motg->otg;
1488 u32 chg_det;
1489
1490 switch (motg->pdata->phy_type) {
1491 case CI_45NM_INTEGRATED_PHY:
1492 chg_det = ulpi_read(otg, 0x34);
1493 /* enable chg detection */
1494 chg_det &= ~(1 << 0);
1495 ulpi_write(otg, chg_det, 0x34);
1496 break;
1497 case SNPS_28NM_INTEGRATED_PHY:
1498 /*
1499 * Configure DP as current source, DM as current sink
1500 * and enable battery charging comparators.
1501 */
1502 ulpi_write(otg, 0x2, 0x85);
1503 ulpi_write(otg, 0x1, 0x85);
1504 break;
1505 default:
1506 break;
1507 }
1508}
1509
1510static bool msm_chg_check_dcd(struct msm_otg *motg)
1511{
1512 struct otg_transceiver *otg = &motg->otg;
1513 u32 line_state;
1514 bool ret = false;
1515
1516 switch (motg->pdata->phy_type) {
1517 case CI_45NM_INTEGRATED_PHY:
1518 line_state = ulpi_read(otg, 0x15);
1519 ret = !(line_state & 1);
1520 break;
1521 case SNPS_28NM_INTEGRATED_PHY:
1522 line_state = ulpi_read(otg, 0x87);
1523 ret = line_state & 2;
1524 break;
1525 default:
1526 break;
1527 }
1528 return ret;
1529}
1530
1531static void msm_chg_disable_dcd(struct msm_otg *motg)
1532{
1533 struct otg_transceiver *otg = &motg->otg;
1534 u32 chg_det;
1535
1536 switch (motg->pdata->phy_type) {
1537 case CI_45NM_INTEGRATED_PHY:
1538 chg_det = ulpi_read(otg, 0x34);
1539 chg_det &= ~(1 << 5);
1540 ulpi_write(otg, chg_det, 0x34);
1541 break;
1542 case SNPS_28NM_INTEGRATED_PHY:
1543 ulpi_write(otg, 0x10, 0x86);
1544 break;
1545 default:
1546 break;
1547 }
1548}
1549
1550static void msm_chg_enable_dcd(struct msm_otg *motg)
1551{
1552 struct otg_transceiver *otg = &motg->otg;
1553 u32 chg_det;
1554
1555 switch (motg->pdata->phy_type) {
1556 case CI_45NM_INTEGRATED_PHY:
1557 chg_det = ulpi_read(otg, 0x34);
1558 /* Turn on D+ current source */
1559 chg_det |= (1 << 5);
1560 ulpi_write(otg, chg_det, 0x34);
1561 break;
1562 case SNPS_28NM_INTEGRATED_PHY:
1563 /* Data contact detection enable */
1564 ulpi_write(otg, 0x10, 0x85);
1565 break;
1566 default:
1567 break;
1568 }
1569}
1570
1571static void msm_chg_block_on(struct msm_otg *motg)
1572{
1573 struct otg_transceiver *otg = &motg->otg;
1574 u32 func_ctrl, chg_det;
1575
1576 /* put the controller in non-driving mode */
1577 func_ctrl = ulpi_read(otg, ULPI_FUNC_CTRL);
1578 func_ctrl &= ~ULPI_FUNC_CTRL_OPMODE_MASK;
1579 func_ctrl |= ULPI_FUNC_CTRL_OPMODE_NONDRIVING;
1580 ulpi_write(otg, func_ctrl, ULPI_FUNC_CTRL);
1581
1582 switch (motg->pdata->phy_type) {
1583 case CI_45NM_INTEGRATED_PHY:
1584 chg_det = ulpi_read(otg, 0x34);
1585 /* control chg block via ULPI */
1586 chg_det &= ~(1 << 3);
1587 ulpi_write(otg, chg_det, 0x34);
1588 /* Turn on chg detect block */
1589 chg_det &= ~(1 << 1);
1590 ulpi_write(otg, chg_det, 0x34);
1591 udelay(20);
1592 break;
1593 case SNPS_28NM_INTEGRATED_PHY:
1594 /* Clear charger detecting control bits */
Pavankumar Kondetiaa449e12011-11-04 11:09:26 +05301595 ulpi_write(otg, 0x1F, 0x86);
Pavankumar Kondetid8608522011-05-04 10:19:47 +05301596 /* Clear alt interrupt latch and enable bits */
1597 ulpi_write(otg, 0x1F, 0x92);
1598 ulpi_write(otg, 0x1F, 0x95);
1599 udelay(100);
1600 break;
1601 default:
1602 break;
1603 }
1604}
1605
1606static void msm_chg_block_off(struct msm_otg *motg)
1607{
1608 struct otg_transceiver *otg = &motg->otg;
1609 u32 func_ctrl, chg_det;
1610
1611 switch (motg->pdata->phy_type) {
1612 case CI_45NM_INTEGRATED_PHY:
1613 chg_det = ulpi_read(otg, 0x34);
1614 /* Turn off charger block */
1615 chg_det |= ~(1 << 1);
1616 ulpi_write(otg, chg_det, 0x34);
1617 break;
1618 case SNPS_28NM_INTEGRATED_PHY:
1619 /* Clear charger detecting control bits */
1620 ulpi_write(otg, 0x3F, 0x86);
1621 /* Clear alt interrupt latch and enable bits */
1622 ulpi_write(otg, 0x1F, 0x92);
1623 ulpi_write(otg, 0x1F, 0x95);
1624 break;
1625 default:
1626 break;
1627 }
1628
1629 /* put the controller in normal mode */
1630 func_ctrl = ulpi_read(otg, ULPI_FUNC_CTRL);
1631 func_ctrl &= ~ULPI_FUNC_CTRL_OPMODE_MASK;
1632 func_ctrl |= ULPI_FUNC_CTRL_OPMODE_NORMAL;
1633 ulpi_write(otg, func_ctrl, ULPI_FUNC_CTRL);
1634}
1635
Anji jonnalad270e2d2011-08-09 11:28:32 +05301636static const char *chg_to_string(enum usb_chg_type chg_type)
1637{
1638 switch (chg_type) {
1639 case USB_SDP_CHARGER: return "USB_SDP_CHARGER";
1640 case USB_DCP_CHARGER: return "USB_DCP_CHARGER";
1641 case USB_CDP_CHARGER: return "USB_CDP_CHARGER";
1642 case USB_ACA_A_CHARGER: return "USB_ACA_A_CHARGER";
1643 case USB_ACA_B_CHARGER: return "USB_ACA_B_CHARGER";
1644 case USB_ACA_C_CHARGER: return "USB_ACA_C_CHARGER";
1645 case USB_ACA_DOCK_CHARGER: return "USB_ACA_DOCK_CHARGER";
1646 default: return "INVALID_CHARGER";
1647 }
1648}
1649
Pavankumar Kondetid8608522011-05-04 10:19:47 +05301650#define MSM_CHG_DCD_POLL_TIME (100 * HZ/1000) /* 100 msec */
1651#define MSM_CHG_DCD_MAX_RETRIES 6 /* Tdcd_tmout = 6 * 100 msec */
Pavankumar Kondeti283146f2012-01-12 12:51:19 +05301652#define MSM_CHG_PRIMARY_DET_TIME (50 * HZ/1000) /* TVDPSRC_ON */
1653#define MSM_CHG_SECONDARY_DET_TIME (50 * HZ/1000) /* TVDMSRC_ON */
Pavankumar Kondetid8608522011-05-04 10:19:47 +05301654static void msm_chg_detect_work(struct work_struct *w)
1655{
1656 struct msm_otg *motg = container_of(w, struct msm_otg, chg_work.work);
1657 struct otg_transceiver *otg = &motg->otg;
Pavankumar Kondeti2d09e5f2012-01-16 08:56:57 +05301658 bool is_dcd = false, tmout, vout, is_aca;
Pavankumar Kondetid8608522011-05-04 10:19:47 +05301659 unsigned long delay;
1660
1661 dev_dbg(otg->dev, "chg detection work\n");
1662 switch (motg->chg_state) {
1663 case USB_CHG_STATE_UNDEFINED:
Pavankumar Kondetid8608522011-05-04 10:19:47 +05301664 msm_chg_block_on(motg);
Pavankumar Kondeti2d09e5f2012-01-16 08:56:57 +05301665 if (motg->pdata->enable_dcd)
1666 msm_chg_enable_dcd(motg);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001667 msm_chg_enable_aca_det(motg);
Pavankumar Kondetid8608522011-05-04 10:19:47 +05301668 motg->chg_state = USB_CHG_STATE_WAIT_FOR_DCD;
1669 motg->dcd_retries = 0;
1670 delay = MSM_CHG_DCD_POLL_TIME;
1671 break;
1672 case USB_CHG_STATE_WAIT_FOR_DCD:
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001673 is_aca = msm_chg_aca_detect(motg);
1674 if (is_aca) {
1675 /*
1676 * ID_A can be ACA dock too. continue
1677 * primary detection after DCD.
1678 */
1679 if (test_bit(ID_A, &motg->inputs)) {
1680 motg->chg_state = USB_CHG_STATE_WAIT_FOR_DCD;
1681 } else {
1682 delay = 0;
1683 break;
1684 }
1685 }
Pavankumar Kondeti2d09e5f2012-01-16 08:56:57 +05301686 if (motg->pdata->enable_dcd)
1687 is_dcd = msm_chg_check_dcd(motg);
Pavankumar Kondetid8608522011-05-04 10:19:47 +05301688 tmout = ++motg->dcd_retries == MSM_CHG_DCD_MAX_RETRIES;
1689 if (is_dcd || tmout) {
Pavankumar Kondeti2d09e5f2012-01-16 08:56:57 +05301690 if (motg->pdata->enable_dcd)
1691 msm_chg_disable_dcd(motg);
Pavankumar Kondetid8608522011-05-04 10:19:47 +05301692 msm_chg_enable_primary_det(motg);
1693 delay = MSM_CHG_PRIMARY_DET_TIME;
1694 motg->chg_state = USB_CHG_STATE_DCD_DONE;
1695 } else {
1696 delay = MSM_CHG_DCD_POLL_TIME;
1697 }
1698 break;
1699 case USB_CHG_STATE_DCD_DONE:
1700 vout = msm_chg_check_primary_det(motg);
1701 if (vout) {
Pavankumar Kondetiaa449e12011-11-04 11:09:26 +05301702 if (test_bit(ID_A, &motg->inputs)) {
1703 motg->chg_type = USB_ACA_DOCK_CHARGER;
1704 motg->chg_state = USB_CHG_STATE_DETECTED;
1705 delay = 0;
1706 break;
1707 }
Pavankumar Kondetid8608522011-05-04 10:19:47 +05301708 msm_chg_enable_secondary_det(motg);
1709 delay = MSM_CHG_SECONDARY_DET_TIME;
1710 motg->chg_state = USB_CHG_STATE_PRIMARY_DONE;
1711 } else {
Pavankumar Kondetiaa449e12011-11-04 11:09:26 +05301712 if (test_bit(ID_A, &motg->inputs)) {
1713 motg->chg_type = USB_ACA_A_CHARGER;
1714 motg->chg_state = USB_CHG_STATE_DETECTED;
1715 delay = 0;
1716 break;
1717 }
Pavankumar Kondetid8608522011-05-04 10:19:47 +05301718 motg->chg_type = USB_SDP_CHARGER;
1719 motg->chg_state = USB_CHG_STATE_DETECTED;
1720 delay = 0;
1721 }
1722 break;
1723 case USB_CHG_STATE_PRIMARY_DONE:
1724 vout = msm_chg_check_secondary_det(motg);
1725 if (vout)
1726 motg->chg_type = USB_DCP_CHARGER;
1727 else
1728 motg->chg_type = USB_CDP_CHARGER;
1729 motg->chg_state = USB_CHG_STATE_SECONDARY_DONE;
1730 /* fall through */
1731 case USB_CHG_STATE_SECONDARY_DONE:
1732 motg->chg_state = USB_CHG_STATE_DETECTED;
1733 case USB_CHG_STATE_DETECTED:
1734 msm_chg_block_off(motg);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001735 msm_chg_enable_aca_det(motg);
1736 msm_chg_enable_aca_intr(motg);
Anji jonnalad270e2d2011-08-09 11:28:32 +05301737 dev_dbg(otg->dev, "chg_type = %s\n",
1738 chg_to_string(motg->chg_type));
Pavankumar Kondetid8608522011-05-04 10:19:47 +05301739 schedule_work(&motg->sm_work);
1740 return;
1741 default:
1742 return;
1743 }
1744
1745 schedule_delayed_work(&motg->chg_work, delay);
1746}
1747
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05301748/*
1749 * We support OTG, Peripheral only and Host only configurations. In case
1750 * of OTG, mode switch (host-->peripheral/peripheral-->host) can happen
1751 * via Id pin status or user request (debugfs). Id/BSV interrupts are not
1752 * enabled when switch is controlled by user and default mode is supplied
1753 * by board file, which can be changed by userspace later.
1754 */
1755static void msm_otg_init_sm(struct msm_otg *motg)
1756{
1757 struct msm_otg_platform_data *pdata = motg->pdata;
1758 u32 otgsc = readl(USB_OTGSC);
1759
1760 switch (pdata->mode) {
1761 case USB_OTG:
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001762 if (pdata->otg_control == OTG_USER_CONTROL) {
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05301763 if (pdata->default_mode == USB_HOST) {
1764 clear_bit(ID, &motg->inputs);
1765 } else if (pdata->default_mode == USB_PERIPHERAL) {
1766 set_bit(ID, &motg->inputs);
1767 set_bit(B_SESS_VLD, &motg->inputs);
1768 } else {
1769 set_bit(ID, &motg->inputs);
1770 clear_bit(B_SESS_VLD, &motg->inputs);
1771 }
Pavankumar Kondeti4960f312011-12-06 15:46:14 +05301772 } else if (pdata->otg_control == OTG_PHY_CONTROL) {
1773 if (otgsc & OTGSC_ID)
1774 set_bit(ID, &motg->inputs);
1775 else
1776 clear_bit(ID, &motg->inputs);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001777 if (otgsc & OTGSC_BSV)
1778 set_bit(B_SESS_VLD, &motg->inputs);
1779 else
1780 clear_bit(B_SESS_VLD, &motg->inputs);
Pavankumar Kondeti4960f312011-12-06 15:46:14 +05301781 } else if (pdata->otg_control == OTG_PMIC_CONTROL) {
Pavankumar Kondeti0d81f312012-01-13 11:34:10 +05301782 if (pdata->pmic_id_irq) {
1783 if (irq_read_line(pdata->pmic_id_irq))
1784 set_bit(ID, &motg->inputs);
1785 else
1786 clear_bit(ID, &motg->inputs);
1787 }
Pavankumar Kondeti4960f312011-12-06 15:46:14 +05301788 /*
1789 * VBUS initial state is reported after PMIC
1790 * driver initialization. Wait for it.
1791 */
1792 wait_for_completion(&pmic_vbus_init);
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05301793 }
1794 break;
1795 case USB_HOST:
1796 clear_bit(ID, &motg->inputs);
1797 break;
1798 case USB_PERIPHERAL:
1799 set_bit(ID, &motg->inputs);
Pavankumar Kondeti0d81f312012-01-13 11:34:10 +05301800 if (pdata->otg_control == OTG_PHY_CONTROL) {
1801 if (otgsc & OTGSC_BSV)
1802 set_bit(B_SESS_VLD, &motg->inputs);
1803 else
1804 clear_bit(B_SESS_VLD, &motg->inputs);
1805 } else if (pdata->otg_control == OTG_PMIC_CONTROL) {
1806 /*
1807 * VBUS initial state is reported after PMIC
1808 * driver initialization. Wait for it.
1809 */
1810 wait_for_completion(&pmic_vbus_init);
1811 }
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05301812 break;
1813 default:
1814 break;
1815 }
1816}
1817
1818static void msm_otg_sm_work(struct work_struct *w)
1819{
1820 struct msm_otg *motg = container_of(w, struct msm_otg, sm_work);
1821 struct otg_transceiver *otg = &motg->otg;
1822
Pavankumar Kondeti8be99cf2011-08-04 10:48:08 +05301823 pm_runtime_resume(otg->dev);
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05301824 switch (otg->state) {
1825 case OTG_STATE_UNDEFINED:
1826 dev_dbg(otg->dev, "OTG_STATE_UNDEFINED state\n");
1827 msm_otg_reset(otg);
1828 msm_otg_init_sm(motg);
1829 otg->state = OTG_STATE_B_IDLE;
Pavankumar Kondeti8a379b42011-12-12 13:07:23 +05301830 if (!test_bit(B_SESS_VLD, &motg->inputs) &&
1831 test_bit(ID, &motg->inputs)) {
1832 pm_runtime_put_noidle(otg->dev);
1833 pm_runtime_suspend(otg->dev);
1834 break;
1835 }
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05301836 /* FALL THROUGH */
1837 case OTG_STATE_B_IDLE:
1838 dev_dbg(otg->dev, "OTG_STATE_B_IDLE state\n");
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001839 if ((!test_bit(ID, &motg->inputs) ||
1840 test_bit(ID_A, &motg->inputs)) && otg->host) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001841 if (motg->chg_type == USB_ACA_DOCK_CHARGER)
1842 msm_otg_notify_charger(motg,
Pavankumar Kondetiaa449e12011-11-04 11:09:26 +05301843 IDEV_ACA_CHG_MAX);
1844 else if (test_bit(ID_A, &motg->inputs))
1845 msm_otg_notify_charger(motg,
1846 IDEV_ACA_CHG_MAX - IUNIT);
Mayank Ranae3926882011-12-26 09:47:54 +05301847 else
1848 msm_hsusb_vbus_power(motg, 1);
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05301849 msm_otg_start_host(otg, 1);
Pavankumar Kondetiaa449e12011-11-04 11:09:26 +05301850 /*
1851 * Link can not generate PHY_ALT interrupt
1852 * in host mode when no device is attached
1853 * to the port. It is also observed PHY_ALT
1854 * interrupt missing upon Micro-A cable disconnect.
1855 * Hence disable PHY_ALT interrupt and perform
1856 * polling to detect RID change.
1857 */
1858 msm_chg_enable_aca_det(motg);
1859 msm_chg_disable_aca_intr(motg);
1860 mod_timer(&motg->id_timer, ID_TIMER_FREQ);
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05301861 otg->state = OTG_STATE_A_HOST;
Pavankumar Kondetid8608522011-05-04 10:19:47 +05301862 } else if (test_bit(B_SESS_VLD, &motg->inputs)) {
1863 switch (motg->chg_state) {
1864 case USB_CHG_STATE_UNDEFINED:
1865 msm_chg_detect_work(&motg->chg_work.work);
1866 break;
1867 case USB_CHG_STATE_DETECTED:
1868 switch (motg->chg_type) {
1869 case USB_DCP_CHARGER:
Pavankumar Kondeti283146f2012-01-12 12:51:19 +05301870 /* Enable VDP_SRC */
1871 ulpi_write(otg, 0x2, 0x85);
Pavankumar Kondetid8608522011-05-04 10:19:47 +05301872 msm_otg_notify_charger(motg,
1873 IDEV_CHG_MAX);
Pavankumar Kondeti8be99cf2011-08-04 10:48:08 +05301874 pm_runtime_put_noidle(otg->dev);
1875 pm_runtime_suspend(otg->dev);
Pavankumar Kondetid8608522011-05-04 10:19:47 +05301876 break;
Pavankumar Kondetiaa449e12011-11-04 11:09:26 +05301877 case USB_ACA_B_CHARGER:
1878 msm_otg_notify_charger(motg,
1879 IDEV_ACA_CHG_MAX);
1880 /*
1881 * (ID_B --> ID_C) PHY_ALT interrupt can
1882 * not be detected in LPM.
1883 */
1884 break;
Pavankumar Kondetid8608522011-05-04 10:19:47 +05301885 case USB_CDP_CHARGER:
1886 msm_otg_notify_charger(motg,
1887 IDEV_CHG_MAX);
1888 msm_otg_start_peripheral(otg, 1);
1889 otg->state = OTG_STATE_B_PERIPHERAL;
1890 break;
Pavankumar Kondetiaa449e12011-11-04 11:09:26 +05301891 case USB_ACA_C_CHARGER:
1892 msm_otg_notify_charger(motg,
1893 IDEV_ACA_CHG_MAX);
1894 msm_otg_start_peripheral(otg, 1);
1895 otg->state = OTG_STATE_B_PERIPHERAL;
1896 break;
Pavankumar Kondetid8608522011-05-04 10:19:47 +05301897 case USB_SDP_CHARGER:
Pavankumar Kondetid8608522011-05-04 10:19:47 +05301898 msm_otg_start_peripheral(otg, 1);
1899 otg->state = OTG_STATE_B_PERIPHERAL;
1900 break;
1901 default:
1902 break;
1903 }
1904 break;
1905 default:
1906 break;
1907 }
1908 } else {
Pavankumar Kondetiaa449e12011-11-04 11:09:26 +05301909 cancel_delayed_work_sync(&motg->chg_work);
Pavankumar Kondetid8608522011-05-04 10:19:47 +05301910 msm_otg_notify_charger(motg, 0);
1911 motg->chg_state = USB_CHG_STATE_UNDEFINED;
1912 motg->chg_type = USB_INVALID_CHARGER;
Pavankumar Kondetiaa449e12011-11-04 11:09:26 +05301913 msm_otg_reset(otg);
Pavankumar Kondeti8be99cf2011-08-04 10:48:08 +05301914 pm_runtime_put_noidle(otg->dev);
1915 pm_runtime_suspend(otg->dev);
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05301916 }
1917 break;
1918 case OTG_STATE_B_PERIPHERAL:
1919 dev_dbg(otg->dev, "OTG_STATE_B_PERIPHERAL state\n");
1920 if (!test_bit(B_SESS_VLD, &motg->inputs) ||
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001921 !test_bit(ID, &motg->inputs) ||
1922 !test_bit(ID_C, &motg->inputs)) {
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05301923 msm_otg_start_peripheral(otg, 0);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001924 otg->state = OTG_STATE_B_IDLE;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001925 schedule_work(w);
1926 } else if (test_bit(ID_C, &motg->inputs)) {
Pavankumar Kondetiaa449e12011-11-04 11:09:26 +05301927 msm_otg_notify_charger(motg, IDEV_ACA_CHG_MAX);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001928 }
1929 break;
1930 case OTG_STATE_A_HOST:
1931 dev_dbg(otg->dev, "OTG_STATE_A_HOST state\n");
1932 if (test_bit(ID, &motg->inputs) &&
1933 !test_bit(ID_A, &motg->inputs)) {
1934 msm_otg_start_host(otg, 0);
Mayank Ranae3926882011-12-26 09:47:54 +05301935 msm_hsusb_vbus_power(motg, 0);
1936 msleep(100); /* TA_WAIT_VFALL */
Pavankumar Kondetiaa449e12011-11-04 11:09:26 +05301937 /*
1938 * Exit point of host mode.
1939 *
1940 * 1. Micro-A cable disconnect: Just schedule
1941 * the work. PHY is reset in B_IDLE and LPM
1942 * is allowed.
1943 * 2. ID_GND --> ID_B: No need to reset the PHY.
1944 * HCD core clears all PORTSC bits and initializes
1945 * the controller to host mode in remove_hcd.
1946 * Restore PORTSC transceiver select bits (ULPI)
1947 * and reset the controller to change MODE bits.
1948 * PHY_ALT interrupt can not occur in host mode.
1949 */
1950 del_timer_sync(&motg->id_timer);
1951 if (motg->chg_state != USB_CHG_STATE_UNDEFINED) {
1952 msm_otg_link_reset(motg);
1953 msm_chg_enable_aca_intr(motg);
1954 }
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05301955 otg->state = OTG_STATE_B_IDLE;
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05301956 schedule_work(w);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001957 } else if (test_bit(ID_A, &motg->inputs)) {
Mayank Ranae3926882011-12-26 09:47:54 +05301958 msm_hsusb_vbus_power(motg, 0);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001959 msm_otg_notify_charger(motg,
Pavankumar Kondetiaa449e12011-11-04 11:09:26 +05301960 IDEV_ACA_CHG_MAX - motg->mA_port);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001961 } else if (!test_bit(ID, &motg->inputs)) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001962 msm_otg_notify_charger(motg, 0);
Mayank Ranae3926882011-12-26 09:47:54 +05301963 msm_hsusb_vbus_power(motg, 1);
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05301964 }
1965 break;
1966 default:
1967 break;
1968 }
1969}
1970
1971static irqreturn_t msm_otg_irq(int irq, void *data)
1972{
1973 struct msm_otg *motg = data;
1974 struct otg_transceiver *otg = &motg->otg;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001975 u32 otgsc = 0, usbsts;
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05301976
Pavankumar Kondeti87c01042010-12-07 17:53:58 +05301977 if (atomic_read(&motg->in_lpm)) {
Pavankumar Kondeti4960f312011-12-06 15:46:14 +05301978 pr_debug("OTG IRQ: in LPM\n");
Pavankumar Kondeti87c01042010-12-07 17:53:58 +05301979 disable_irq_nosync(irq);
1980 motg->async_int = 1;
Pavankumar Kondeti8be99cf2011-08-04 10:48:08 +05301981 pm_request_resume(otg->dev);
Pavankumar Kondeti87c01042010-12-07 17:53:58 +05301982 return IRQ_HANDLED;
1983 }
1984
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001985 usbsts = readl(USB_USBSTS);
1986 if ((usbsts & PHY_ALT_INT)) {
Pavankumar Kondetiaa449e12011-11-04 11:09:26 +05301987 dev_dbg(otg->dev, "PHY_ALT interrupt\n");
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001988 writel(PHY_ALT_INT, USB_USBSTS);
Pavankumar Kondetiaa449e12011-11-04 11:09:26 +05301989 if (msm_chg_check_aca_intr(motg)) {
1990 dev_dbg(otg->dev, "ACA work from IRQ\n");
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001991 schedule_work(&motg->sm_work);
Pavankumar Kondetiaa449e12011-11-04 11:09:26 +05301992 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001993 return IRQ_HANDLED;
1994 }
1995
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05301996 otgsc = readl(USB_OTGSC);
1997 if (!(otgsc & (OTGSC_IDIS | OTGSC_BSVIS)))
1998 return IRQ_NONE;
1999
2000 if ((otgsc & OTGSC_IDIS) && (otgsc & OTGSC_IDIE)) {
Pavankumar Kondetiaa449e12011-11-04 11:09:26 +05302001 if (otgsc & OTGSC_ID) {
2002 dev_dbg(otg->dev, "ID set\n");
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05302003 set_bit(ID, &motg->inputs);
Pavankumar Kondetiaa449e12011-11-04 11:09:26 +05302004 } else {
2005 dev_dbg(otg->dev, "ID clear\n");
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05302006 clear_bit(ID, &motg->inputs);
Pavankumar Kondetiaa449e12011-11-04 11:09:26 +05302007 msm_chg_enable_aca_det(motg);
2008 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002009 schedule_work(&motg->sm_work);
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05302010 } else if ((otgsc & OTGSC_BSVIS) && (otgsc & OTGSC_BSVIE)) {
Pavankumar Kondetiaa449e12011-11-04 11:09:26 +05302011 if (otgsc & OTGSC_BSV) {
2012 dev_dbg(otg->dev, "BSV set\n");
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05302013 set_bit(B_SESS_VLD, &motg->inputs);
Pavankumar Kondetiaa449e12011-11-04 11:09:26 +05302014 } else {
2015 dev_dbg(otg->dev, "BSV clear\n");
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05302016 clear_bit(B_SESS_VLD, &motg->inputs);
Pavankumar Kondetiaa449e12011-11-04 11:09:26 +05302017 msm_chg_check_aca_intr(motg);
2018 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002019 schedule_work(&motg->sm_work);
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05302020 }
2021
2022 writel(otgsc, USB_OTGSC);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002023 return IRQ_HANDLED;
2024}
2025
2026static void msm_otg_set_vbus_state(int online)
2027{
Pavankumar Kondeti4960f312011-12-06 15:46:14 +05302028 static bool init;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002029 struct msm_otg *motg = the_msm_otg;
2030
Pavankumar Kondeti4960f312011-12-06 15:46:14 +05302031 if (online) {
2032 pr_debug("PMIC: BSV set\n");
2033 set_bit(B_SESS_VLD, &motg->inputs);
2034 } else {
2035 pr_debug("PMIC: BSV clear\n");
2036 clear_bit(B_SESS_VLD, &motg->inputs);
2037 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002038
Pavankumar Kondeti4960f312011-12-06 15:46:14 +05302039 if (!init) {
2040 init = true;
2041 complete(&pmic_vbus_init);
2042 pr_debug("PMIC: BSV init complete\n");
2043 return;
2044 }
2045
2046 schedule_work(&motg->sm_work);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002047}
2048
2049static irqreturn_t msm_pmic_id_irq(int irq, void *data)
2050{
2051 struct msm_otg *motg = data;
2052
Pavankumar Kondeti4960f312011-12-06 15:46:14 +05302053 if (aca_id_turned_on)
2054 return IRQ_HANDLED;
2055
2056 if (irq_read_line(motg->pdata->pmic_id_irq)) {
2057 pr_debug("PMIC: ID set\n");
2058 set_bit(ID, &motg->inputs);
2059 } else {
2060 pr_debug("PMIC: ID clear\n");
2061 clear_bit(ID, &motg->inputs);
2062 }
2063
2064 if (motg->otg.state != OTG_STATE_UNDEFINED)
2065 schedule_work(&motg->sm_work);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002066
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05302067 return IRQ_HANDLED;
2068}
2069
2070static int msm_otg_mode_show(struct seq_file *s, void *unused)
2071{
2072 struct msm_otg *motg = s->private;
2073 struct otg_transceiver *otg = &motg->otg;
2074
2075 switch (otg->state) {
2076 case OTG_STATE_A_HOST:
2077 seq_printf(s, "host\n");
2078 break;
2079 case OTG_STATE_B_PERIPHERAL:
2080 seq_printf(s, "peripheral\n");
2081 break;
2082 default:
2083 seq_printf(s, "none\n");
2084 break;
2085 }
2086
2087 return 0;
2088}
2089
2090static int msm_otg_mode_open(struct inode *inode, struct file *file)
2091{
2092 return single_open(file, msm_otg_mode_show, inode->i_private);
2093}
2094
2095static ssize_t msm_otg_mode_write(struct file *file, const char __user *ubuf,
2096 size_t count, loff_t *ppos)
2097{
Pavankumar Kondetie2904ee2011-02-15 09:42:35 +05302098 struct seq_file *s = file->private_data;
2099 struct msm_otg *motg = s->private;
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05302100 char buf[16];
2101 struct otg_transceiver *otg = &motg->otg;
2102 int status = count;
2103 enum usb_mode_type req_mode;
2104
2105 memset(buf, 0x00, sizeof(buf));
2106
2107 if (copy_from_user(&buf, ubuf, min_t(size_t, sizeof(buf) - 1, count))) {
2108 status = -EFAULT;
2109 goto out;
2110 }
2111
2112 if (!strncmp(buf, "host", 4)) {
2113 req_mode = USB_HOST;
2114 } else if (!strncmp(buf, "peripheral", 10)) {
2115 req_mode = USB_PERIPHERAL;
2116 } else if (!strncmp(buf, "none", 4)) {
2117 req_mode = USB_NONE;
2118 } else {
2119 status = -EINVAL;
2120 goto out;
2121 }
2122
2123 switch (req_mode) {
2124 case USB_NONE:
2125 switch (otg->state) {
2126 case OTG_STATE_A_HOST:
2127 case OTG_STATE_B_PERIPHERAL:
2128 set_bit(ID, &motg->inputs);
2129 clear_bit(B_SESS_VLD, &motg->inputs);
2130 break;
2131 default:
2132 goto out;
2133 }
2134 break;
2135 case USB_PERIPHERAL:
2136 switch (otg->state) {
2137 case OTG_STATE_B_IDLE:
2138 case OTG_STATE_A_HOST:
2139 set_bit(ID, &motg->inputs);
2140 set_bit(B_SESS_VLD, &motg->inputs);
2141 break;
2142 default:
2143 goto out;
2144 }
2145 break;
2146 case USB_HOST:
2147 switch (otg->state) {
2148 case OTG_STATE_B_IDLE:
2149 case OTG_STATE_B_PERIPHERAL:
2150 clear_bit(ID, &motg->inputs);
2151 break;
2152 default:
2153 goto out;
2154 }
2155 break;
2156 default:
2157 goto out;
2158 }
2159
Pavankumar Kondeti8be99cf2011-08-04 10:48:08 +05302160 pm_runtime_resume(otg->dev);
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05302161 schedule_work(&motg->sm_work);
2162out:
2163 return status;
2164}
2165
2166const struct file_operations msm_otg_mode_fops = {
2167 .open = msm_otg_mode_open,
2168 .read = seq_read,
2169 .write = msm_otg_mode_write,
2170 .llseek = seq_lseek,
2171 .release = single_release,
2172};
2173
Anji jonnalad270e2d2011-08-09 11:28:32 +05302174static int msm_otg_show_chg_type(struct seq_file *s, void *unused)
2175{
2176 struct msm_otg *motg = s->private;
2177
Pavankumar Kondeti9ef69cb2011-12-12 14:18:22 +05302178 seq_printf(s, "%s\n", chg_to_string(motg->chg_type));
Anji jonnalad270e2d2011-08-09 11:28:32 +05302179 return 0;
2180}
2181
2182static int msm_otg_chg_open(struct inode *inode, struct file *file)
2183{
2184 return single_open(file, msm_otg_show_chg_type, inode->i_private);
2185}
2186
2187const struct file_operations msm_otg_chg_fops = {
2188 .open = msm_otg_chg_open,
2189 .read = seq_read,
2190 .llseek = seq_lseek,
2191 .release = single_release,
2192};
2193
Pavankumar Kondetiaa449e12011-11-04 11:09:26 +05302194static int msm_otg_aca_show(struct seq_file *s, void *unused)
2195{
2196 if (debug_aca_enabled)
2197 seq_printf(s, "enabled\n");
2198 else
2199 seq_printf(s, "disabled\n");
2200
2201 return 0;
2202}
2203
2204static int msm_otg_aca_open(struct inode *inode, struct file *file)
2205{
2206 return single_open(file, msm_otg_aca_show, inode->i_private);
2207}
2208
2209static ssize_t msm_otg_aca_write(struct file *file, const char __user *ubuf,
2210 size_t count, loff_t *ppos)
2211{
2212 char buf[8];
2213
2214 memset(buf, 0x00, sizeof(buf));
2215
2216 if (copy_from_user(&buf, ubuf, min_t(size_t, sizeof(buf) - 1, count)))
2217 return -EFAULT;
2218
2219 if (!strncmp(buf, "enable", 6))
2220 debug_aca_enabled = true;
2221 else
2222 debug_aca_enabled = false;
2223
2224 return count;
2225}
2226
2227const struct file_operations msm_otg_aca_fops = {
2228 .open = msm_otg_aca_open,
2229 .read = seq_read,
2230 .write = msm_otg_aca_write,
2231 .llseek = seq_lseek,
2232 .release = single_release,
2233};
2234
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05302235static struct dentry *msm_otg_dbg_root;
2236static struct dentry *msm_otg_dbg_mode;
Anji jonnalad270e2d2011-08-09 11:28:32 +05302237static struct dentry *msm_otg_chg_type;
Pavankumar Kondetiaa449e12011-11-04 11:09:26 +05302238static struct dentry *msm_otg_dbg_aca;
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05302239
2240static int msm_otg_debugfs_init(struct msm_otg *motg)
2241{
Anji jonnalad270e2d2011-08-09 11:28:32 +05302242
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05302243 msm_otg_dbg_root = debugfs_create_dir("msm_otg", NULL);
2244
2245 if (!msm_otg_dbg_root || IS_ERR(msm_otg_dbg_root))
2246 return -ENODEV;
2247
Anji jonnalad270e2d2011-08-09 11:28:32 +05302248 if (motg->pdata->mode == USB_OTG &&
2249 motg->pdata->otg_control == OTG_USER_CONTROL) {
2250
2251 msm_otg_dbg_mode = debugfs_create_file("mode", S_IRUGO |
2252 S_IWUSR, msm_otg_dbg_root, motg,
2253 &msm_otg_mode_fops);
2254
2255 if (!msm_otg_dbg_mode) {
2256 debugfs_remove(msm_otg_dbg_root);
2257 msm_otg_dbg_root = NULL;
2258 return -ENODEV;
2259 }
2260 }
2261
2262 msm_otg_chg_type = debugfs_create_file("chg_type", S_IRUGO,
2263 msm_otg_dbg_root, motg,
2264 &msm_otg_chg_fops);
2265
2266 if (!msm_otg_chg_type) {
Pavankumar Kondetiaa449e12011-11-04 11:09:26 +05302267 debugfs_remove_recursive(msm_otg_dbg_root);
2268 return -ENODEV;
2269 }
2270
2271 msm_otg_dbg_aca = debugfs_create_file("aca", S_IRUGO | S_IWUSR,
2272 msm_otg_dbg_root, motg,
2273 &msm_otg_aca_fops);
2274
2275 if (!msm_otg_dbg_aca) {
2276 debugfs_remove_recursive(msm_otg_dbg_root);
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05302277 return -ENODEV;
2278 }
2279
2280 return 0;
2281}
2282
2283static void msm_otg_debugfs_cleanup(void)
2284{
Anji jonnalad270e2d2011-08-09 11:28:32 +05302285 debugfs_remove_recursive(msm_otg_dbg_root);
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05302286}
2287
Pavankumar Kondetieaea7fe2011-10-27 14:46:45 +05302288static u64 msm_otg_dma_mask = DMA_BIT_MASK(64);
2289static struct platform_device *msm_otg_add_pdev(
2290 struct platform_device *ofdev, const char *name)
2291{
2292 struct platform_device *pdev;
2293 const struct resource *res = ofdev->resource;
2294 unsigned int num = ofdev->num_resources;
2295 int retval;
2296
2297 pdev = platform_device_alloc(name, -1);
2298 if (!pdev) {
2299 retval = -ENOMEM;
2300 goto error;
2301 }
2302
2303 pdev->dev.coherent_dma_mask = DMA_BIT_MASK(32);
2304 pdev->dev.dma_mask = &msm_otg_dma_mask;
2305
2306 if (num) {
2307 retval = platform_device_add_resources(pdev, res, num);
2308 if (retval)
2309 goto error;
2310 }
2311
2312 retval = platform_device_add(pdev);
2313 if (retval)
2314 goto error;
2315
2316 return pdev;
2317
2318error:
2319 platform_device_put(pdev);
2320 return ERR_PTR(retval);
2321}
2322
2323static int msm_otg_setup_devices(struct platform_device *ofdev,
2324 enum usb_mode_type mode, bool init)
2325{
2326 const char *gadget_name = "msm_hsusb";
2327 const char *host_name = "msm_hsusb_host";
2328 static struct platform_device *gadget_pdev;
2329 static struct platform_device *host_pdev;
2330 int retval = 0;
2331
2332 if (!init) {
2333 if (gadget_pdev)
2334 platform_device_unregister(gadget_pdev);
2335 if (host_pdev)
2336 platform_device_unregister(host_pdev);
2337 return 0;
2338 }
2339
2340 switch (mode) {
2341 case USB_OTG:
2342 /* fall through */
2343 case USB_PERIPHERAL:
2344 gadget_pdev = msm_otg_add_pdev(ofdev, gadget_name);
2345 if (IS_ERR(gadget_pdev)) {
2346 retval = PTR_ERR(gadget_pdev);
2347 break;
2348 }
2349 if (mode == USB_PERIPHERAL)
2350 break;
2351 /* fall through */
2352 case USB_HOST:
2353 host_pdev = msm_otg_add_pdev(ofdev, host_name);
2354 if (IS_ERR(host_pdev)) {
2355 retval = PTR_ERR(host_pdev);
2356 if (mode == USB_OTG)
2357 platform_device_unregister(gadget_pdev);
2358 }
2359 break;
2360 default:
2361 break;
2362 }
2363
2364 return retval;
2365}
2366
2367struct msm_otg_platform_data *msm_otg_dt_to_pdata(struct platform_device *pdev)
2368{
2369 struct device_node *node = pdev->dev.of_node;
2370 struct msm_otg_platform_data *pdata;
2371 int len = 0;
2372
2373 pdata = devm_kzalloc(&pdev->dev, sizeof(*pdata), GFP_KERNEL);
2374 if (!pdata) {
2375 pr_err("unable to allocate platform data\n");
2376 return NULL;
2377 }
2378 of_get_property(node, "qcom,hsusb-otg-phy-init-seq", &len);
2379 if (len) {
2380 pdata->phy_init_seq = devm_kzalloc(&pdev->dev, len, GFP_KERNEL);
2381 if (!pdata->phy_init_seq)
2382 return NULL;
2383 of_property_read_u32_array(node, "qcom,hsusb-otg-phy-init-seq",
2384 pdata->phy_init_seq,
2385 len/sizeof(*pdata->phy_init_seq));
2386 }
2387 of_property_read_u32(node, "qcom,hsusb-otg-power-budget",
2388 &pdata->power_budget);
2389 of_property_read_u32(node, "qcom,hsusb-otg-mode",
2390 &pdata->mode);
2391 of_property_read_u32(node, "qcom,hsusb-otg-otg-control",
2392 &pdata->otg_control);
2393 of_property_read_u32(node, "qcom,hsusb-otg-default-mode",
2394 &pdata->default_mode);
2395 of_property_read_u32(node, "qcom,hsusb-otg-phy-type",
2396 &pdata->phy_type);
2397 of_property_read_u32(node, "qcom,hsusb-otg-pmic-id-irq",
2398 &pdata->pmic_id_irq);
Pavankumar Kondetieaea7fe2011-10-27 14:46:45 +05302399 return pdata;
2400}
2401
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05302402static int __init msm_otg_probe(struct platform_device *pdev)
2403{
2404 int ret = 0;
2405 struct resource *res;
2406 struct msm_otg *motg;
2407 struct otg_transceiver *otg;
Pavankumar Kondetieaea7fe2011-10-27 14:46:45 +05302408 struct msm_otg_platform_data *pdata;
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05302409
2410 dev_info(&pdev->dev, "msm_otg probe\n");
Pavankumar Kondetieaea7fe2011-10-27 14:46:45 +05302411
2412 if (pdev->dev.of_node) {
2413 dev_dbg(&pdev->dev, "device tree enabled\n");
2414 pdata = msm_otg_dt_to_pdata(pdev);
2415 if (!pdata)
2416 return -ENOMEM;
2417 ret = msm_otg_setup_devices(pdev, pdata->mode, true);
2418 if (ret) {
2419 dev_err(&pdev->dev, "devices setup failed\n");
2420 return ret;
2421 }
2422 } else if (!pdev->dev.platform_data) {
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05302423 dev_err(&pdev->dev, "No platform data given. Bailing out\n");
2424 return -ENODEV;
Pavankumar Kondetieaea7fe2011-10-27 14:46:45 +05302425 } else {
2426 pdata = pdev->dev.platform_data;
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05302427 }
2428
2429 motg = kzalloc(sizeof(struct msm_otg), GFP_KERNEL);
2430 if (!motg) {
2431 dev_err(&pdev->dev, "unable to allocate msm_otg\n");
2432 return -ENOMEM;
2433 }
2434
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002435 the_msm_otg = motg;
Pavankumar Kondetieaea7fe2011-10-27 14:46:45 +05302436 motg->pdata = pdata;
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05302437 otg = &motg->otg;
2438 otg->dev = &pdev->dev;
2439
Pavankumar Kondetiaa449e12011-11-04 11:09:26 +05302440 /*
2441 * ACA ID_GND threshold range is overlapped with OTG ID_FLOAT. Hence
2442 * PHY treat ACA ID_GND as float and no interrupt is generated. But
2443 * PMIC can detect ACA ID_GND and generate an interrupt.
2444 */
2445 if (aca_enabled() && motg->pdata->otg_control != OTG_PMIC_CONTROL) {
2446 dev_err(&pdev->dev, "ACA can not be enabled without PMIC\n");
2447 ret = -EINVAL;
2448 goto free_motg;
2449 }
2450
Ofir Cohen4da266f2012-01-03 10:19:29 +02002451 /* initialize reset counter */
2452 motg->reset_counter = 0;
2453
Amit Blay02eff132011-09-21 16:46:24 +03002454 /* Some targets don't support PHY clock. */
Manu Gautam5143b252012-01-05 19:25:23 -08002455 motg->phy_reset_clk = clk_get(&pdev->dev, "phy_clk");
Amit Blay02eff132011-09-21 16:46:24 +03002456 if (IS_ERR(motg->phy_reset_clk))
Manu Gautam5143b252012-01-05 19:25:23 -08002457 dev_err(&pdev->dev, "failed to get phy_clk\n");
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05302458
Manu Gautam5143b252012-01-05 19:25:23 -08002459 motg->clk = clk_get(&pdev->dev, "alt_core_clk");
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05302460 if (IS_ERR(motg->clk)) {
Manu Gautam5143b252012-01-05 19:25:23 -08002461 dev_err(&pdev->dev, "failed to get alt_core_clk\n");
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05302462 ret = PTR_ERR(motg->clk);
2463 goto put_phy_reset_clk;
2464 }
Anji jonnala0f73cac2011-05-04 10:19:46 +05302465 clk_set_rate(motg->clk, 60000000);
2466
Anji jonnalaa7c1c5c2011-12-12 12:20:36 +05302467 /* pm qos request to prevent apps idle power collapse */
2468 if (motg->pdata->swfi_latency)
2469 pm_qos_add_request(&motg->pm_qos_req_dma,
2470 PM_QOS_CPU_DMA_LATENCY, PM_QOS_DEFAULT_VALUE);
Manu Gautam5143b252012-01-05 19:25:23 -08002471
Anji jonnala0f73cac2011-05-04 10:19:46 +05302472 /*
Manu Gautam5143b252012-01-05 19:25:23 -08002473 * USB Core is running its protocol engine based on CORE CLK,
Anji jonnala0f73cac2011-05-04 10:19:46 +05302474 * CORE CLK must be running at >55Mhz for correct HSUSB
2475 * operation and USB core cannot tolerate frequency changes on
2476 * CORE CLK. For such USB cores, vote for maximum clk frequency
2477 * on pclk source
2478 */
Manu Gautam5143b252012-01-05 19:25:23 -08002479 motg->core_clk = clk_get(&pdev->dev, "core_clk");
2480 if (IS_ERR(motg->core_clk)) {
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05302481 motg->core_clk = NULL;
Manu Gautam5143b252012-01-05 19:25:23 -08002482 dev_err(&pdev->dev, "failed to get core_clk\n");
2483 ret = PTR_ERR(motg->clk);
2484 goto put_clk;
2485 }
2486 clk_set_rate(motg->core_clk, INT_MAX);
2487
2488 motg->pclk = clk_get(&pdev->dev, "iface_clk");
2489 if (IS_ERR(motg->pclk)) {
2490 dev_err(&pdev->dev, "failed to get iface_clk\n");
2491 ret = PTR_ERR(motg->pclk);
2492 goto put_core_clk;
2493 }
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05302494
2495 res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
2496 if (!res) {
2497 dev_err(&pdev->dev, "failed to get platform resource mem\n");
2498 ret = -ENODEV;
Manu Gautam5143b252012-01-05 19:25:23 -08002499 goto put_pclk;
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05302500 }
2501
2502 motg->regs = ioremap(res->start, resource_size(res));
2503 if (!motg->regs) {
2504 dev_err(&pdev->dev, "ioremap failed\n");
2505 ret = -ENOMEM;
Manu Gautam5143b252012-01-05 19:25:23 -08002506 goto put_pclk;
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05302507 }
2508 dev_info(&pdev->dev, "OTG regs = %p\n", motg->regs);
2509
2510 motg->irq = platform_get_irq(pdev, 0);
2511 if (!motg->irq) {
2512 dev_err(&pdev->dev, "platform_get_irq failed\n");
2513 ret = -ENODEV;
2514 goto free_regs;
2515 }
2516
Stephen Boyd7dd22662012-01-26 16:09:31 -08002517 motg->xo_handle = clk_get(&pdev->dev, "xo");
Anji jonnala7da3f262011-12-02 17:22:14 -08002518 if (IS_ERR(motg->xo_handle)) {
2519 dev_err(&pdev->dev, "%s not able to get the handle "
2520 "to vote for TCXO D0 buffer\n", __func__);
2521 ret = PTR_ERR(motg->xo_handle);
2522 goto free_regs;
2523 }
2524
Stephen Boyd7dd22662012-01-26 16:09:31 -08002525 ret = clk_prepare_enable(motg->xo_handle);
Anji jonnala7da3f262011-12-02 17:22:14 -08002526 if (ret) {
2527 dev_err(&pdev->dev, "%s failed to vote for TCXO "
2528 "D0 buffer%d\n", __func__, ret);
2529 goto free_xo_handle;
2530 }
2531
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05302532 clk_enable(motg->pclk);
Anji jonnala11aa5c42011-05-04 10:19:48 +05302533
2534 ret = msm_hsusb_init_vddcx(motg, 1);
2535 if (ret) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002536 dev_err(&pdev->dev, "hsusb vddcx init failed\n");
Anji jonnala7da3f262011-12-02 17:22:14 -08002537 goto devote_xo_handle;
Anji jonnala11aa5c42011-05-04 10:19:48 +05302538 }
2539
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002540 ret = msm_hsusb_config_vddcx(1);
2541 if (ret) {
2542 dev_err(&pdev->dev, "hsusb vddcx configuration failed\n");
2543 goto free_init_vddcx;
2544 }
2545
Anji jonnala11aa5c42011-05-04 10:19:48 +05302546 ret = msm_hsusb_ldo_init(motg, 1);
2547 if (ret) {
2548 dev_err(&pdev->dev, "hsusb vreg configuration failed\n");
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002549 goto free_init_vddcx;
Anji jonnala11aa5c42011-05-04 10:19:48 +05302550 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002551
2552 ret = msm_hsusb_ldo_enable(motg, 1);
Anji jonnala11aa5c42011-05-04 10:19:48 +05302553 if (ret) {
2554 dev_err(&pdev->dev, "hsusb vreg enable failed\n");
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002555 goto free_ldo_init;
Anji jonnala11aa5c42011-05-04 10:19:48 +05302556 }
Manu Gautam5143b252012-01-05 19:25:23 -08002557 clk_enable(motg->core_clk);
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05302558
2559 writel(0, USB_USBINTR);
2560 writel(0, USB_OTGSC);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002561 /* Ensure that above STOREs are completed before enabling interrupts */
2562 mb();
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05302563
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002564 wake_lock_init(&motg->wlock, WAKE_LOCK_SUSPEND, "msm_otg");
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05302565 INIT_WORK(&motg->sm_work, msm_otg_sm_work);
Pavankumar Kondetid8608522011-05-04 10:19:47 +05302566 INIT_DELAYED_WORK(&motg->chg_work, msm_chg_detect_work);
Pavankumar Kondetiaa449e12011-11-04 11:09:26 +05302567 setup_timer(&motg->id_timer, msm_otg_id_timer_func,
2568 (unsigned long) motg);
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05302569 ret = request_irq(motg->irq, msm_otg_irq, IRQF_SHARED,
2570 "msm_otg", motg);
2571 if (ret) {
2572 dev_err(&pdev->dev, "request irq failed\n");
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002573 goto destroy_wlock;
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05302574 }
2575
2576 otg->init = msm_otg_reset;
2577 otg->set_host = msm_otg_set_host;
2578 otg->set_peripheral = msm_otg_set_peripheral;
Pavankumar Kondetid8608522011-05-04 10:19:47 +05302579 otg->set_power = msm_otg_set_power;
Pavankumar Kondeti8be99cf2011-08-04 10:48:08 +05302580 otg->set_suspend = msm_otg_set_suspend;
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05302581
2582 otg->io_ops = &msm_otg_io_ops;
2583
2584 ret = otg_set_transceiver(&motg->otg);
2585 if (ret) {
2586 dev_err(&pdev->dev, "otg_set_transceiver failed\n");
2587 goto free_irq;
2588 }
2589
Pavankumar Kondeti0d81f312012-01-13 11:34:10 +05302590 if (motg->pdata->mode == USB_OTG &&
2591 motg->pdata->otg_control == OTG_PMIC_CONTROL) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002592 if (motg->pdata->pmic_id_irq) {
2593 ret = request_irq(motg->pdata->pmic_id_irq,
2594 msm_pmic_id_irq,
2595 IRQF_TRIGGER_RISING |
2596 IRQF_TRIGGER_FALLING,
2597 "msm_otg", motg);
2598 if (ret) {
2599 dev_err(&pdev->dev, "request irq failed for PMIC ID\n");
2600 goto remove_otg;
2601 }
2602 } else {
2603 ret = -ENODEV;
2604 dev_err(&pdev->dev, "PMIC IRQ for ID notifications doesn't exist\n");
2605 goto remove_otg;
2606 }
2607 }
2608
Vijayavardhan Vennapusafc464f02011-11-04 21:54:00 +05302609 msm_hsusb_mhl_switch_enable(motg, 1);
2610
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05302611 platform_set_drvdata(pdev, motg);
2612 device_init_wakeup(&pdev->dev, 1);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002613 motg->mA_port = IUNIT;
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05302614
Anji jonnalad270e2d2011-08-09 11:28:32 +05302615 ret = msm_otg_debugfs_init(motg);
2616 if (ret)
2617 dev_dbg(&pdev->dev, "mode debugfs file is"
2618 "not available\n");
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05302619
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002620 if (motg->pdata->otg_control == OTG_PMIC_CONTROL)
2621 pm8921_charger_register_vbus_sn(&msm_otg_set_vbus_state);
2622
Amit Blay58b31472011-11-18 09:39:39 +02002623 if (motg->pdata->phy_type == SNPS_28NM_INTEGRATED_PHY) {
2624 if (motg->pdata->otg_control == OTG_PMIC_CONTROL &&
Pavankumar Kondeti0d81f312012-01-13 11:34:10 +05302625 (!(motg->pdata->mode == USB_OTG) ||
2626 motg->pdata->pmic_id_irq))
Amit Blay58b31472011-11-18 09:39:39 +02002627 motg->caps = ALLOW_PHY_POWER_COLLAPSE |
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002628 ALLOW_PHY_RETENTION |
2629 ALLOW_PHY_COMP_DISABLE;
2630
Amit Blay58b31472011-11-18 09:39:39 +02002631 if (motg->pdata->otg_control == OTG_PHY_CONTROL)
2632 motg->caps = ALLOW_PHY_RETENTION;
2633 }
2634
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002635 wake_lock(&motg->wlock);
Pavankumar Kondeti87c01042010-12-07 17:53:58 +05302636 pm_runtime_set_active(&pdev->dev);
2637 pm_runtime_enable(&pdev->dev);
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05302638
Manu Gautamcd82e9d2011-12-20 14:17:28 +05302639 if (motg->pdata->bus_scale_table) {
2640 motg->bus_perf_client =
2641 msm_bus_scale_register_client(motg->pdata->bus_scale_table);
2642 if (!motg->bus_perf_client)
2643 dev_err(motg->otg.dev, "%s: Failed to register BUS "
2644 "scaling client!!\n", __func__);
2645 }
2646
Pavankumar Kondeti87c01042010-12-07 17:53:58 +05302647 return 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002648
2649remove_otg:
2650 otg_set_transceiver(NULL);
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05302651free_irq:
2652 free_irq(motg->irq, motg);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002653destroy_wlock:
2654 wake_lock_destroy(&motg->wlock);
Manu Gautam5143b252012-01-05 19:25:23 -08002655 clk_disable(motg->core_clk);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002656 msm_hsusb_ldo_enable(motg, 0);
2657free_ldo_init:
Anji jonnala11aa5c42011-05-04 10:19:48 +05302658 msm_hsusb_ldo_init(motg, 0);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002659free_init_vddcx:
Anji jonnala11aa5c42011-05-04 10:19:48 +05302660 msm_hsusb_init_vddcx(motg, 0);
Anji jonnala7da3f262011-12-02 17:22:14 -08002661devote_xo_handle:
Manu Gautam5143b252012-01-05 19:25:23 -08002662 clk_disable(motg->pclk);
Stephen Boyd7dd22662012-01-26 16:09:31 -08002663 clk_disable_unprepare(motg->xo_handle);
Anji jonnala7da3f262011-12-02 17:22:14 -08002664free_xo_handle:
Stephen Boyd7dd22662012-01-26 16:09:31 -08002665 clk_put(motg->xo_handle);
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05302666free_regs:
2667 iounmap(motg->regs);
Manu Gautam5143b252012-01-05 19:25:23 -08002668put_pclk:
2669 clk_put(motg->pclk);
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05302670put_core_clk:
Manu Gautam5143b252012-01-05 19:25:23 -08002671 clk_put(motg->core_clk);
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05302672put_clk:
2673 clk_put(motg->clk);
2674put_phy_reset_clk:
Amit Blay02eff132011-09-21 16:46:24 +03002675 if (!IS_ERR(motg->phy_reset_clk))
2676 clk_put(motg->phy_reset_clk);
Pavankumar Kondetiaa449e12011-11-04 11:09:26 +05302677free_motg:
Anji jonnalaa7c1c5c2011-12-12 12:20:36 +05302678 if (motg->pdata->swfi_latency)
2679 pm_qos_remove_request(&motg->pm_qos_req_dma);
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05302680 kfree(motg);
2681 return ret;
2682}
2683
2684static int __devexit msm_otg_remove(struct platform_device *pdev)
2685{
2686 struct msm_otg *motg = platform_get_drvdata(pdev);
2687 struct otg_transceiver *otg = &motg->otg;
Pavankumar Kondeti87c01042010-12-07 17:53:58 +05302688 int cnt = 0;
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05302689
2690 if (otg->host || otg->gadget)
2691 return -EBUSY;
2692
Pavankumar Kondetieaea7fe2011-10-27 14:46:45 +05302693 if (pdev->dev.of_node)
2694 msm_otg_setup_devices(pdev, motg->pdata->mode, false);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002695 if (motg->pdata->otg_control == OTG_PMIC_CONTROL)
2696 pm8921_charger_unregister_vbus_sn(0);
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05302697 msm_otg_debugfs_cleanup();
Pavankumar Kondetid8608522011-05-04 10:19:47 +05302698 cancel_delayed_work_sync(&motg->chg_work);
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05302699 cancel_work_sync(&motg->sm_work);
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05302700
Pavankumar Kondeti70187732011-02-15 09:42:34 +05302701 pm_runtime_resume(&pdev->dev);
Pavankumar Kondeti87c01042010-12-07 17:53:58 +05302702
2703 device_init_wakeup(&pdev->dev, 0);
2704 pm_runtime_disable(&pdev->dev);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002705 wake_lock_destroy(&motg->wlock);
Pavankumar Kondeti87c01042010-12-07 17:53:58 +05302706
Vijayavardhan Vennapusafc464f02011-11-04 21:54:00 +05302707 msm_hsusb_mhl_switch_enable(motg, 0);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002708 if (motg->pdata->pmic_id_irq)
2709 free_irq(motg->pdata->pmic_id_irq, motg);
Pavankumar Kondeti87c01042010-12-07 17:53:58 +05302710 otg_set_transceiver(NULL);
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05302711 free_irq(motg->irq, motg);
2712
Pavankumar Kondeti87c01042010-12-07 17:53:58 +05302713 /*
2714 * Put PHY in low power mode.
2715 */
2716 ulpi_read(otg, 0x14);
2717 ulpi_write(otg, 0x08, 0x09);
2718
2719 writel(readl(USB_PORTSC) | PORTSC_PHCD, USB_PORTSC);
2720 while (cnt < PHY_SUSPEND_TIMEOUT_USEC) {
2721 if (readl(USB_PORTSC) & PORTSC_PHCD)
2722 break;
2723 udelay(1);
2724 cnt++;
2725 }
2726 if (cnt >= PHY_SUSPEND_TIMEOUT_USEC)
2727 dev_err(otg->dev, "Unable to suspend PHY\n");
2728
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05302729 clk_disable(motg->pclk);
Manu Gautam5143b252012-01-05 19:25:23 -08002730 clk_disable(motg->core_clk);
Stephen Boyd7dd22662012-01-26 16:09:31 -08002731 clk_put(motg->xo_handle);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002732 msm_hsusb_ldo_enable(motg, 0);
Anji jonnala11aa5c42011-05-04 10:19:48 +05302733 msm_hsusb_ldo_init(motg, 0);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002734 msm_hsusb_init_vddcx(motg, 0);
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05302735
2736 iounmap(motg->regs);
Pavankumar Kondeti87c01042010-12-07 17:53:58 +05302737 pm_runtime_set_suspended(&pdev->dev);
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05302738
Amit Blay02eff132011-09-21 16:46:24 +03002739 if (!IS_ERR(motg->phy_reset_clk))
2740 clk_put(motg->phy_reset_clk);
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05302741 clk_put(motg->pclk);
2742 clk_put(motg->clk);
Manu Gautam5143b252012-01-05 19:25:23 -08002743 clk_put(motg->core_clk);
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05302744
Anji jonnalaa7c1c5c2011-12-12 12:20:36 +05302745 if (motg->pdata->swfi_latency)
2746 pm_qos_remove_request(&motg->pm_qos_req_dma);
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05302747
Manu Gautamcd82e9d2011-12-20 14:17:28 +05302748 if (motg->bus_perf_client)
2749 msm_bus_scale_unregister_client(motg->bus_perf_client);
2750
Anji jonnalaa7c1c5c2011-12-12 12:20:36 +05302751 kfree(motg);
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05302752 return 0;
2753}
2754
Pavankumar Kondeti87c01042010-12-07 17:53:58 +05302755#ifdef CONFIG_PM_RUNTIME
2756static int msm_otg_runtime_idle(struct device *dev)
2757{
2758 struct msm_otg *motg = dev_get_drvdata(dev);
2759 struct otg_transceiver *otg = &motg->otg;
2760
2761 dev_dbg(dev, "OTG runtime idle\n");
2762
Pavankumar Kondeti8be99cf2011-08-04 10:48:08 +05302763 if (otg->state == OTG_STATE_UNDEFINED)
2764 return -EAGAIN;
2765 else
2766 return 0;
Pavankumar Kondeti87c01042010-12-07 17:53:58 +05302767}
2768
2769static int msm_otg_runtime_suspend(struct device *dev)
2770{
2771 struct msm_otg *motg = dev_get_drvdata(dev);
2772
2773 dev_dbg(dev, "OTG runtime suspend\n");
2774 return msm_otg_suspend(motg);
2775}
2776
2777static int msm_otg_runtime_resume(struct device *dev)
2778{
2779 struct msm_otg *motg = dev_get_drvdata(dev);
2780
2781 dev_dbg(dev, "OTG runtime resume\n");
Pavankumar Kondeti8be99cf2011-08-04 10:48:08 +05302782 pm_runtime_get_noresume(dev);
Pavankumar Kondeti87c01042010-12-07 17:53:58 +05302783 return msm_otg_resume(motg);
2784}
Pavankumar Kondeti87c01042010-12-07 17:53:58 +05302785#endif
2786
Pavankumar Kondeti70187732011-02-15 09:42:34 +05302787#ifdef CONFIG_PM_SLEEP
Pavankumar Kondeti87c01042010-12-07 17:53:58 +05302788static int msm_otg_pm_suspend(struct device *dev)
2789{
Pavankumar Kondeti8be99cf2011-08-04 10:48:08 +05302790 int ret;
Pavankumar Kondeti87c01042010-12-07 17:53:58 +05302791
2792 dev_dbg(dev, "OTG PM suspend\n");
Pavankumar Kondeti8be99cf2011-08-04 10:48:08 +05302793
2794#ifdef CONFIG_PM_RUNTIME
2795 ret = pm_runtime_suspend(dev);
2796 if (ret > 0)
2797 ret = 0;
2798#else
2799 ret = msm_otg_suspend(dev_get_drvdata(dev));
2800#endif
2801 return ret;
Pavankumar Kondeti87c01042010-12-07 17:53:58 +05302802}
2803
2804static int msm_otg_pm_resume(struct device *dev)
2805{
2806 struct msm_otg *motg = dev_get_drvdata(dev);
Pavankumar Kondeti87c01042010-12-07 17:53:58 +05302807
2808 dev_dbg(dev, "OTG PM resume\n");
2809
Manu Gautamf284c052011-09-08 16:52:48 +05302810#ifdef CONFIG_PM_RUNTIME
Pavankumar Kondeti87c01042010-12-07 17:53:58 +05302811 /*
Manu Gautamf284c052011-09-08 16:52:48 +05302812 * Do not resume hardware as part of system resume,
2813 * rather, wait for the ASYNC INT from the h/w
Pavankumar Kondeti87c01042010-12-07 17:53:58 +05302814 */
Gregory Beanebd8ca22011-10-11 12:02:35 -07002815 return 0;
Manu Gautamf284c052011-09-08 16:52:48 +05302816#endif
Pavankumar Kondeti87c01042010-12-07 17:53:58 +05302817
Manu Gautamf284c052011-09-08 16:52:48 +05302818 return msm_otg_resume(motg);
Pavankumar Kondeti87c01042010-12-07 17:53:58 +05302819}
Pavankumar Kondeti87c01042010-12-07 17:53:58 +05302820#endif
2821
Pavankumar Kondeti70187732011-02-15 09:42:34 +05302822#ifdef CONFIG_PM
Pavankumar Kondeti87c01042010-12-07 17:53:58 +05302823static const struct dev_pm_ops msm_otg_dev_pm_ops = {
Pavankumar Kondeti70187732011-02-15 09:42:34 +05302824 SET_SYSTEM_SLEEP_PM_OPS(msm_otg_pm_suspend, msm_otg_pm_resume)
2825 SET_RUNTIME_PM_OPS(msm_otg_runtime_suspend, msm_otg_runtime_resume,
2826 msm_otg_runtime_idle)
Pavankumar Kondeti87c01042010-12-07 17:53:58 +05302827};
Pavankumar Kondeti70187732011-02-15 09:42:34 +05302828#endif
Pavankumar Kondeti87c01042010-12-07 17:53:58 +05302829
Pavankumar Kondetieaea7fe2011-10-27 14:46:45 +05302830static struct of_device_id msm_otg_dt_match[] = {
2831 { .compatible = "qcom,hsusb-otg",
2832 },
2833 {}
2834};
2835
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05302836static struct platform_driver msm_otg_driver = {
2837 .remove = __devexit_p(msm_otg_remove),
2838 .driver = {
2839 .name = DRIVER_NAME,
2840 .owner = THIS_MODULE,
Pavankumar Kondeti70187732011-02-15 09:42:34 +05302841#ifdef CONFIG_PM
Pavankumar Kondeti87c01042010-12-07 17:53:58 +05302842 .pm = &msm_otg_dev_pm_ops,
Pavankumar Kondeti70187732011-02-15 09:42:34 +05302843#endif
Pavankumar Kondetieaea7fe2011-10-27 14:46:45 +05302844 .of_match_table = msm_otg_dt_match,
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05302845 },
2846};
2847
2848static int __init msm_otg_init(void)
2849{
2850 return platform_driver_probe(&msm_otg_driver, msm_otg_probe);
2851}
2852
2853static void __exit msm_otg_exit(void)
2854{
2855 platform_driver_unregister(&msm_otg_driver);
2856}
2857
2858module_init(msm_otg_init);
2859module_exit(msm_otg_exit);
2860
2861MODULE_LICENSE("GPL v2");
2862MODULE_DESCRIPTION("MSM USB transceiver driver");