blob: 748edf0dc8f3bd2b7d74484443f4c9194c59afad [file] [log] [blame]
Pavankumar Kondetid8608522011-05-04 10:19:47 +05301/* Copyright (c) 2009-2011, 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>
Anji jonnalaa7c1c5c2011-12-12 12:20:36 +053040#include <linux/pm_qos_params.h>
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +053041
42#include <mach/clk.h>
Anji jonnala7da3f262011-12-02 17:22:14 -080043#include <mach/msm_xo.h>
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +053044
45#define MSM_USB_BASE (motg->regs)
46#define DRIVER_NAME "msm_otg"
47
Pavankumar Kondetiaa449e12011-11-04 11:09:26 +053048#define ID_TIMER_FREQ (jiffies + msecs_to_jiffies(2000))
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +053049#define ULPI_IO_TIMEOUT_USEC (10 * 1000)
Anji jonnala11aa5c42011-05-04 10:19:48 +053050
51#define USB_PHY_3P3_VOL_MIN 3050000 /* uV */
52#define USB_PHY_3P3_VOL_MAX 3300000 /* uV */
53#define USB_PHY_3P3_HPM_LOAD 50000 /* uA */
54#define USB_PHY_3P3_LPM_LOAD 4000 /* uA */
55
56#define USB_PHY_1P8_VOL_MIN 1800000 /* uV */
57#define USB_PHY_1P8_VOL_MAX 1800000 /* uV */
58#define USB_PHY_1P8_HPM_LOAD 50000 /* uA */
59#define USB_PHY_1P8_LPM_LOAD 4000 /* uA */
60
Vamsi Krishna132b2762011-11-11 16:09:20 -080061#define USB_PHY_VDD_DIG_VOL_MIN 1045000 /* uV */
Anji jonnala11aa5c42011-05-04 10:19:48 +053062#define USB_PHY_VDD_DIG_VOL_MAX 1320000 /* uV */
63
Pavankumar Kondeti4960f312011-12-06 15:46:14 +053064static DECLARE_COMPLETION(pmic_vbus_init);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070065static struct msm_otg *the_msm_otg;
Pavankumar Kondetiaa449e12011-11-04 11:09:26 +053066static bool debug_aca_enabled;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070067
Anji jonnalaa7c1c5c2011-12-12 12:20:36 +053068/* Prevent idle power collapse(pc) while operating in peripheral mode */
69static void otg_pm_qos_update_latency(struct msm_otg *dev, int vote)
70{
71 struct msm_otg_platform_data *pdata = dev->pdata;
72 u32 swfi_latency = 0;
73
74 if (!pdata || !pdata->swfi_latency)
75 return;
76
77 swfi_latency = pdata->swfi_latency + 1;
78
79 if (vote)
80 pm_qos_update_request(&dev->pm_qos_req_dma,
81 swfi_latency);
82 else
83 pm_qos_update_request(&dev->pm_qos_req_dma,
84 PM_QOS_DEFAULT_VALUE);
85}
86
Anji jonnala11aa5c42011-05-04 10:19:48 +053087static struct regulator *hsusb_3p3;
88static struct regulator *hsusb_1p8;
89static struct regulator *hsusb_vddcx;
90
Pavankumar Kondeti4960f312011-12-06 15:46:14 +053091static bool aca_id_turned_on;
Pavankumar Kondetiaa449e12011-11-04 11:09:26 +053092static inline bool aca_enabled(void)
93{
94#ifdef CONFIG_USB_MSM_ACA
95 return true;
96#else
97 return debug_aca_enabled;
98#endif
99}
100
Anji jonnala11aa5c42011-05-04 10:19:48 +0530101static int msm_hsusb_init_vddcx(struct msm_otg *motg, int init)
102{
103 int ret = 0;
104
105 if (init) {
106 hsusb_vddcx = regulator_get(motg->otg.dev, "HSUSB_VDDCX");
107 if (IS_ERR(hsusb_vddcx)) {
108 dev_err(motg->otg.dev, "unable to get hsusb vddcx\n");
109 return PTR_ERR(hsusb_vddcx);
110 }
111
112 ret = regulator_set_voltage(hsusb_vddcx,
113 USB_PHY_VDD_DIG_VOL_MIN,
114 USB_PHY_VDD_DIG_VOL_MAX);
115 if (ret) {
116 dev_err(motg->otg.dev, "unable to set the voltage "
117 "for hsusb vddcx\n");
118 regulator_put(hsusb_vddcx);
119 return ret;
120 }
121
122 ret = regulator_enable(hsusb_vddcx);
123 if (ret) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700124 regulator_set_voltage(hsusb_vddcx, 0,
125 USB_PHY_VDD_DIG_VOL_MIN);
Anji jonnala11aa5c42011-05-04 10:19:48 +0530126 regulator_put(hsusb_vddcx);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700127 dev_err(motg->otg.dev, "unable to enable the hsusb vddcx\n");
128 return ret;
Anji jonnala11aa5c42011-05-04 10:19:48 +0530129 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700130
Anji jonnala11aa5c42011-05-04 10:19:48 +0530131 } else {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700132
Anji jonnala11aa5c42011-05-04 10:19:48 +0530133 ret = regulator_disable(hsusb_vddcx);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700134 if (ret) {
Anji jonnala11aa5c42011-05-04 10:19:48 +0530135 dev_err(motg->otg.dev, "unable to disable hsusb vddcx\n");
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700136 return ret;
137 }
138
139 ret = regulator_set_voltage(hsusb_vddcx, 0,
140 USB_PHY_VDD_DIG_VOL_MIN);
141 if (ret) {
142 dev_err(motg->otg.dev, "unable to set the voltage"
143 "for hsusb vddcx\n");
144 return ret;
145 }
Anji jonnala11aa5c42011-05-04 10:19:48 +0530146
147 regulator_put(hsusb_vddcx);
148 }
149
150 return ret;
151}
152
153static int msm_hsusb_ldo_init(struct msm_otg *motg, int init)
154{
155 int rc = 0;
156
157 if (init) {
158 hsusb_3p3 = regulator_get(motg->otg.dev, "HSUSB_3p3");
159 if (IS_ERR(hsusb_3p3)) {
160 dev_err(motg->otg.dev, "unable to get hsusb 3p3\n");
161 return PTR_ERR(hsusb_3p3);
162 }
163
164 rc = regulator_set_voltage(hsusb_3p3, USB_PHY_3P3_VOL_MIN,
165 USB_PHY_3P3_VOL_MAX);
166 if (rc) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700167 dev_err(motg->otg.dev, "unable to set voltage level for"
168 "hsusb 3p3\n");
Anji jonnala11aa5c42011-05-04 10:19:48 +0530169 goto put_3p3;
170 }
171 hsusb_1p8 = regulator_get(motg->otg.dev, "HSUSB_1p8");
172 if (IS_ERR(hsusb_1p8)) {
173 dev_err(motg->otg.dev, "unable to get hsusb 1p8\n");
174 rc = PTR_ERR(hsusb_1p8);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700175 goto put_3p3_lpm;
Anji jonnala11aa5c42011-05-04 10:19:48 +0530176 }
177 rc = regulator_set_voltage(hsusb_1p8, USB_PHY_1P8_VOL_MIN,
178 USB_PHY_1P8_VOL_MAX);
179 if (rc) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700180 dev_err(motg->otg.dev, "unable to set voltage level for"
181 "hsusb 1p8\n");
Anji jonnala11aa5c42011-05-04 10:19:48 +0530182 goto put_1p8;
183 }
184
185 return 0;
186 }
187
Anji jonnala11aa5c42011-05-04 10:19:48 +0530188put_1p8:
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700189 regulator_set_voltage(hsusb_1p8, 0, USB_PHY_1P8_VOL_MAX);
Anji jonnala11aa5c42011-05-04 10:19:48 +0530190 regulator_put(hsusb_1p8);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700191put_3p3_lpm:
192 regulator_set_voltage(hsusb_3p3, 0, USB_PHY_3P3_VOL_MAX);
Anji jonnala11aa5c42011-05-04 10:19:48 +0530193put_3p3:
194 regulator_put(hsusb_3p3);
195 return rc;
196}
197
Pavankumar Kondeti04aebcb2011-05-04 10:19:49 +0530198#ifdef CONFIG_PM_SLEEP
199#define USB_PHY_SUSP_DIG_VOL 500000
200static int msm_hsusb_config_vddcx(int high)
201{
202 int max_vol = USB_PHY_VDD_DIG_VOL_MAX;
203 int min_vol;
204 int ret;
205
206 if (high)
207 min_vol = USB_PHY_VDD_DIG_VOL_MIN;
208 else
209 min_vol = USB_PHY_SUSP_DIG_VOL;
210
211 ret = regulator_set_voltage(hsusb_vddcx, min_vol, max_vol);
212 if (ret) {
213 pr_err("%s: unable to set the voltage for regulator "
214 "HSUSB_VDDCX\n", __func__);
215 return ret;
216 }
217
218 pr_debug("%s: min_vol:%d max_vol:%d\n", __func__, min_vol, max_vol);
219
220 return ret;
221}
Hemant Kumar8e7bd072011-08-01 14:14:24 -0700222#else
223static int msm_hsusb_config_vddcx(int high)
224{
225 return 0;
226}
Pavankumar Kondeti04aebcb2011-05-04 10:19:49 +0530227#endif
228
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700229static int msm_hsusb_ldo_enable(struct msm_otg *motg, int on)
Anji jonnala11aa5c42011-05-04 10:19:48 +0530230{
231 int ret = 0;
232
Pavankumar Kondeti68964c92011-10-27 14:58:56 +0530233 if (IS_ERR(hsusb_1p8)) {
Anji jonnala11aa5c42011-05-04 10:19:48 +0530234 pr_err("%s: HSUSB_1p8 is not initialized\n", __func__);
235 return -ENODEV;
236 }
237
Pavankumar Kondeti68964c92011-10-27 14:58:56 +0530238 if (IS_ERR(hsusb_3p3)) {
Anji jonnala11aa5c42011-05-04 10:19:48 +0530239 pr_err("%s: HSUSB_3p3 is not initialized\n", __func__);
240 return -ENODEV;
241 }
242
243 if (on) {
244 ret = regulator_set_optimum_mode(hsusb_1p8,
245 USB_PHY_1P8_HPM_LOAD);
246 if (ret < 0) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700247 pr_err("%s: Unable to set HPM of the regulator:"
Anji jonnala11aa5c42011-05-04 10:19:48 +0530248 "HSUSB_1p8\n", __func__);
249 return ret;
250 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700251
252 ret = regulator_enable(hsusb_1p8);
253 if (ret) {
254 dev_err(motg->otg.dev, "%s: unable to enable the hsusb 1p8\n",
255 __func__);
256 regulator_set_optimum_mode(hsusb_1p8, 0);
257 return ret;
258 }
259
Anji jonnala11aa5c42011-05-04 10:19:48 +0530260 ret = regulator_set_optimum_mode(hsusb_3p3,
261 USB_PHY_3P3_HPM_LOAD);
262 if (ret < 0) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700263 pr_err("%s: Unable to set HPM of the regulator:"
Anji jonnala11aa5c42011-05-04 10:19:48 +0530264 "HSUSB_3p3\n", __func__);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700265 regulator_set_optimum_mode(hsusb_1p8, 0);
266 regulator_disable(hsusb_1p8);
Anji jonnala11aa5c42011-05-04 10:19:48 +0530267 return ret;
268 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700269
270 ret = regulator_enable(hsusb_3p3);
271 if (ret) {
272 dev_err(motg->otg.dev, "%s: unable to enable the hsusb 3p3\n",
273 __func__);
274 regulator_set_optimum_mode(hsusb_3p3, 0);
275 regulator_set_optimum_mode(hsusb_1p8, 0);
276 regulator_disable(hsusb_1p8);
277 return ret;
278 }
279
Anji jonnala11aa5c42011-05-04 10:19:48 +0530280 } else {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700281 ret = regulator_disable(hsusb_1p8);
282 if (ret) {
283 dev_err(motg->otg.dev, "%s: unable to disable the hsusb 1p8\n",
284 __func__);
285 return ret;
286 }
287
288 ret = regulator_set_optimum_mode(hsusb_1p8, 0);
Anji jonnala11aa5c42011-05-04 10:19:48 +0530289 if (ret < 0)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700290 pr_err("%s: Unable to set LPM of the regulator:"
Anji jonnala11aa5c42011-05-04 10:19:48 +0530291 "HSUSB_1p8\n", __func__);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700292
293 ret = regulator_disable(hsusb_3p3);
294 if (ret) {
295 dev_err(motg->otg.dev, "%s: unable to disable the hsusb 3p3\n",
296 __func__);
297 return ret;
298 }
299 ret = regulator_set_optimum_mode(hsusb_3p3, 0);
Anji jonnala11aa5c42011-05-04 10:19:48 +0530300 if (ret < 0)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700301 pr_err("%s: Unable to set LPM of the regulator:"
Anji jonnala11aa5c42011-05-04 10:19:48 +0530302 "HSUSB_3p3\n", __func__);
303 }
304
305 pr_debug("reg (%s)\n", on ? "HPM" : "LPM");
306 return ret < 0 ? ret : 0;
307}
308
Vijayavardhan Vennapusafc464f02011-11-04 21:54:00 +0530309static void msm_hsusb_mhl_switch_enable(struct msm_otg *motg, bool on)
310{
311 static struct regulator *mhl_analog_switch;
312 struct msm_otg_platform_data *pdata = motg->pdata;
313
314 if (!pdata->mhl_enable)
315 return;
316
317 if (on) {
318 mhl_analog_switch = regulator_get(motg->otg.dev,
319 "mhl_ext_3p3v");
320 if (IS_ERR(mhl_analog_switch)) {
321 pr_err("Unable to get mhl_analog_switch\n");
322 return;
323 }
324
325 if (regulator_enable(mhl_analog_switch)) {
326 pr_err("unable to enable mhl_analog_switch\n");
327 goto put_analog_switch;
328 }
329 return;
330 }
331
332 regulator_disable(mhl_analog_switch);
333put_analog_switch:
334 regulator_put(mhl_analog_switch);
335}
336
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +0530337static int ulpi_read(struct otg_transceiver *otg, u32 reg)
338{
339 struct msm_otg *motg = container_of(otg, struct msm_otg, otg);
340 int cnt = 0;
341
342 /* initiate read operation */
343 writel(ULPI_RUN | ULPI_READ | ULPI_ADDR(reg),
344 USB_ULPI_VIEWPORT);
345
346 /* wait for completion */
347 while (cnt < ULPI_IO_TIMEOUT_USEC) {
348 if (!(readl(USB_ULPI_VIEWPORT) & ULPI_RUN))
349 break;
350 udelay(1);
351 cnt++;
352 }
353
354 if (cnt >= ULPI_IO_TIMEOUT_USEC) {
355 dev_err(otg->dev, "ulpi_read: timeout %08x\n",
356 readl(USB_ULPI_VIEWPORT));
357 return -ETIMEDOUT;
358 }
359 return ULPI_DATA_READ(readl(USB_ULPI_VIEWPORT));
360}
361
362static int ulpi_write(struct otg_transceiver *otg, u32 val, u32 reg)
363{
364 struct msm_otg *motg = container_of(otg, struct msm_otg, otg);
365 int cnt = 0;
366
367 /* initiate write operation */
368 writel(ULPI_RUN | ULPI_WRITE |
369 ULPI_ADDR(reg) | ULPI_DATA(val),
370 USB_ULPI_VIEWPORT);
371
372 /* wait for completion */
373 while (cnt < ULPI_IO_TIMEOUT_USEC) {
374 if (!(readl(USB_ULPI_VIEWPORT) & ULPI_RUN))
375 break;
376 udelay(1);
377 cnt++;
378 }
379
380 if (cnt >= ULPI_IO_TIMEOUT_USEC) {
381 dev_err(otg->dev, "ulpi_write: timeout\n");
382 return -ETIMEDOUT;
383 }
384 return 0;
385}
386
387static struct otg_io_access_ops msm_otg_io_ops = {
388 .read = ulpi_read,
389 .write = ulpi_write,
390};
391
392static void ulpi_init(struct msm_otg *motg)
393{
394 struct msm_otg_platform_data *pdata = motg->pdata;
395 int *seq = pdata->phy_init_seq;
396
397 if (!seq)
398 return;
399
400 while (seq[0] >= 0) {
401 dev_vdbg(motg->otg.dev, "ulpi: write 0x%02x to 0x%02x\n",
402 seq[0], seq[1]);
403 ulpi_write(&motg->otg, seq[0], seq[1]);
404 seq += 2;
405 }
406}
407
408static int msm_otg_link_clk_reset(struct msm_otg *motg, bool assert)
409{
410 int ret;
411
412 if (assert) {
413 ret = clk_reset(motg->clk, CLK_RESET_ASSERT);
414 if (ret)
415 dev_err(motg->otg.dev, "usb hs_clk assert failed\n");
416 } else {
417 ret = clk_reset(motg->clk, CLK_RESET_DEASSERT);
418 if (ret)
419 dev_err(motg->otg.dev, "usb hs_clk deassert failed\n");
420 }
421 return ret;
422}
423
424static int msm_otg_phy_clk_reset(struct msm_otg *motg)
425{
426 int ret;
427
Amit Blay02eff132011-09-21 16:46:24 +0300428 if (IS_ERR(motg->phy_reset_clk))
429 return 0;
430
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +0530431 ret = clk_reset(motg->phy_reset_clk, CLK_RESET_ASSERT);
432 if (ret) {
433 dev_err(motg->otg.dev, "usb phy clk assert failed\n");
434 return ret;
435 }
436 usleep_range(10000, 12000);
437 ret = clk_reset(motg->phy_reset_clk, CLK_RESET_DEASSERT);
438 if (ret)
439 dev_err(motg->otg.dev, "usb phy clk deassert failed\n");
440 return ret;
441}
442
443static int msm_otg_phy_reset(struct msm_otg *motg)
444{
445 u32 val;
446 int ret;
447 int retries;
448
449 ret = msm_otg_link_clk_reset(motg, 1);
450 if (ret)
451 return ret;
452 ret = msm_otg_phy_clk_reset(motg);
453 if (ret)
454 return ret;
455 ret = msm_otg_link_clk_reset(motg, 0);
456 if (ret)
457 return ret;
458
459 val = readl(USB_PORTSC) & ~PORTSC_PTS_MASK;
460 writel(val | PORTSC_PTS_ULPI, USB_PORTSC);
461
462 for (retries = 3; retries > 0; retries--) {
463 ret = ulpi_write(&motg->otg, ULPI_FUNC_CTRL_SUSPENDM,
464 ULPI_CLR(ULPI_FUNC_CTRL));
465 if (!ret)
466 break;
467 ret = msm_otg_phy_clk_reset(motg);
468 if (ret)
469 return ret;
470 }
471 if (!retries)
472 return -ETIMEDOUT;
473
474 /* This reset calibrates the phy, if the above write succeeded */
475 ret = msm_otg_phy_clk_reset(motg);
476 if (ret)
477 return ret;
478
479 for (retries = 3; retries > 0; retries--) {
480 ret = ulpi_read(&motg->otg, ULPI_DEBUG);
481 if (ret != -ETIMEDOUT)
482 break;
483 ret = msm_otg_phy_clk_reset(motg);
484 if (ret)
485 return ret;
486 }
487 if (!retries)
488 return -ETIMEDOUT;
489
490 dev_info(motg->otg.dev, "phy_reset: success\n");
491 return 0;
492}
493
494#define LINK_RESET_TIMEOUT_USEC (250 * 1000)
Pavankumar Kondetiaa449e12011-11-04 11:09:26 +0530495static int msm_otg_link_reset(struct msm_otg *motg)
496{
497 int cnt = 0;
498
499 writel_relaxed(USBCMD_RESET, USB_USBCMD);
500 while (cnt < LINK_RESET_TIMEOUT_USEC) {
501 if (!(readl_relaxed(USB_USBCMD) & USBCMD_RESET))
502 break;
503 udelay(1);
504 cnt++;
505 }
506 if (cnt >= LINK_RESET_TIMEOUT_USEC)
507 return -ETIMEDOUT;
508
509 /* select ULPI phy */
510 writel_relaxed(0x80000000, USB_PORTSC);
511 writel_relaxed(0x0, USB_AHBBURST);
512 writel_relaxed(0x00, USB_AHBMODE);
513
514 return 0;
515}
516
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +0530517static int msm_otg_reset(struct otg_transceiver *otg)
518{
519 struct msm_otg *motg = container_of(otg, struct msm_otg, otg);
520 struct msm_otg_platform_data *pdata = motg->pdata;
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +0530521 int ret;
522 u32 val = 0;
523 u32 ulpi_val = 0;
524
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700525 clk_enable(motg->clk);
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +0530526 ret = msm_otg_phy_reset(motg);
527 if (ret) {
528 dev_err(otg->dev, "phy_reset failed\n");
529 return ret;
530 }
531
Pavankumar Kondeti4960f312011-12-06 15:46:14 +0530532 aca_id_turned_on = false;
Pavankumar Kondetiaa449e12011-11-04 11:09:26 +0530533 ret = msm_otg_link_reset(motg);
534 if (ret) {
535 dev_err(otg->dev, "link reset failed\n");
536 return ret;
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +0530537 }
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +0530538 msleep(100);
Anji jonnalaa8b8d732011-12-06 10:03:24 +0530539
540 ulpi_init(motg);
541
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700542 /* Ensure that RESET operation is completed before turning off clock */
543 mb();
Pavankumar Kondetiaa449e12011-11-04 11:09:26 +0530544
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700545 clk_disable(motg->clk);
546
Pavankumar Kondeti4960f312011-12-06 15:46:14 +0530547 if (pdata->otg_control == OTG_PHY_CONTROL) {
548 val = readl_relaxed(USB_OTGSC);
549 if (pdata->mode == USB_OTG) {
550 ulpi_val = ULPI_INT_IDGRD | ULPI_INT_SESS_VALID;
551 val |= OTGSC_IDIE | OTGSC_BSVIE;
552 } else if (pdata->mode == USB_PERIPHERAL) {
553 ulpi_val = ULPI_INT_SESS_VALID;
554 val |= OTGSC_BSVIE;
555 }
556 writel_relaxed(val, USB_OTGSC);
557 ulpi_write(otg, ulpi_val, ULPI_USB_INT_EN_RISE);
558 ulpi_write(otg, ulpi_val, ULPI_USB_INT_EN_FALL);
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +0530559 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700560
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +0530561 return 0;
562}
563
Pavankumar Kondeti8be99cf2011-08-04 10:48:08 +0530564static int msm_otg_set_suspend(struct otg_transceiver *otg, int suspend)
565{
566 struct msm_otg *motg = container_of(otg, struct msm_otg, otg);
567
568 /*
569 * Allow bus suspend only for host mode. Device mode bus suspend
570 * is not implemented yet.
571 */
572 if (!test_bit(ID, &motg->inputs) || test_bit(ID_A, &motg->inputs)) {
Pavankumar Kondetiaa449e12011-11-04 11:09:26 +0530573 /*
574 * ID_GND --> ID_A transition can not be detected in LPM.
575 * Disallow host bus suspend when ACA is enabled.
576 */
577 if (suspend && !aca_enabled())
Pavankumar Kondeti8be99cf2011-08-04 10:48:08 +0530578 pm_runtime_put(otg->dev);
579 else
580 pm_runtime_resume(otg->dev);
581 }
582
583 return 0;
584}
585
Pavankumar Kondeti87c01042010-12-07 17:53:58 +0530586#define PHY_SUSPEND_TIMEOUT_USEC (500 * 1000)
Pavankumar Kondeti70187732011-02-15 09:42:34 +0530587#define PHY_RESUME_TIMEOUT_USEC (100 * 1000)
588
589#ifdef CONFIG_PM_SLEEP
Pavankumar Kondeti87c01042010-12-07 17:53:58 +0530590static int msm_otg_suspend(struct msm_otg *motg)
591{
592 struct otg_transceiver *otg = &motg->otg;
593 struct usb_bus *bus = otg->host;
594 struct msm_otg_platform_data *pdata = motg->pdata;
595 int cnt = 0;
Pavankumar Kondeti4960f312011-12-06 15:46:14 +0530596 bool host_bus_suspend;
597 u32 phy_ctrl_val = 0, cmd_val;
Anji jonnala7da3f262011-12-02 17:22:14 -0800598 unsigned ret;
Rajkumar Raghupathy242565d2011-12-13 12:10:59 +0530599 u32 portsc;
Pavankumar Kondeti87c01042010-12-07 17:53:58 +0530600
601 if (atomic_read(&motg->in_lpm))
602 return 0;
603
604 disable_irq(motg->irq);
Pavankumar Kondeti4960f312011-12-06 15:46:14 +0530605 host_bus_suspend = otg->host && !test_bit(ID, &motg->inputs);
Pavankumar Kondeti87c01042010-12-07 17:53:58 +0530606 /*
Pavankumar Kondeti04aebcb2011-05-04 10:19:49 +0530607 * Chipidea 45-nm PHY suspend sequence:
608 *
Pavankumar Kondeti87c01042010-12-07 17:53:58 +0530609 * Interrupt Latch Register auto-clear feature is not present
610 * in all PHY versions. Latch register is clear on read type.
611 * Clear latch register to avoid spurious wakeup from
612 * low power mode (LPM).
Pavankumar Kondeti04aebcb2011-05-04 10:19:49 +0530613 *
Pavankumar Kondeti87c01042010-12-07 17:53:58 +0530614 * PHY comparators are disabled when PHY enters into low power
615 * mode (LPM). Keep PHY comparators ON in LPM only when we expect
616 * VBUS/Id notifications from USB PHY. Otherwise turn off USB
617 * PHY comparators. This save significant amount of power.
Pavankumar Kondeti04aebcb2011-05-04 10:19:49 +0530618 *
Pavankumar Kondeti87c01042010-12-07 17:53:58 +0530619 * PLL is not turned off when PHY enters into low power mode (LPM).
620 * Disable PLL for maximum power savings.
621 */
Pavankumar Kondeti04aebcb2011-05-04 10:19:49 +0530622
623 if (motg->pdata->phy_type == CI_45NM_INTEGRATED_PHY) {
624 ulpi_read(otg, 0x14);
625 if (pdata->otg_control == OTG_PHY_CONTROL)
626 ulpi_write(otg, 0x01, 0x30);
627 ulpi_write(otg, 0x08, 0x09);
628 }
Pavankumar Kondeti87c01042010-12-07 17:53:58 +0530629
630 /*
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700631 * Turn off the OTG comparators, if depends on PMIC for
632 * VBUS and ID notifications.
633 */
Pavankumar Kondeti4960f312011-12-06 15:46:14 +0530634 if ((motg->caps & ALLOW_PHY_COMP_DISABLE) && !host_bus_suspend) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700635 ulpi_write(otg, OTG_COMP_DISABLE,
636 ULPI_SET(ULPI_PWR_CLK_MNG_REG));
637 motg->lpm_flags |= PHY_OTG_COMP_DISABLED;
638 }
639
Rajkumar Raghupathy242565d2011-12-13 12:10:59 +0530640 /* Set the PHCD bit, only if it is not set by the controller.
Pavankumar Kondeti87c01042010-12-07 17:53:58 +0530641 * PHY may take some time or even fail to enter into low power
642 * mode (LPM). Hence poll for 500 msec and reset the PHY and link
643 * in failure case.
644 */
Rajkumar Raghupathy242565d2011-12-13 12:10:59 +0530645 portsc = readl_relaxed(USB_PORTSC);
646 if (!(portsc & PORTSC_PHCD)) {
647 writel_relaxed(portsc | PORTSC_PHCD,
648 USB_PORTSC);
649 while (cnt < PHY_SUSPEND_TIMEOUT_USEC) {
650 if (readl_relaxed(USB_PORTSC) & PORTSC_PHCD)
651 break;
652 udelay(1);
653 cnt++;
654 }
Pavankumar Kondeti87c01042010-12-07 17:53:58 +0530655 }
656
657 if (cnt >= PHY_SUSPEND_TIMEOUT_USEC) {
658 dev_err(otg->dev, "Unable to suspend PHY\n");
659 msm_otg_reset(otg);
660 enable_irq(motg->irq);
661 return -ETIMEDOUT;
662 }
663
664 /*
665 * PHY has capability to generate interrupt asynchronously in low
666 * power mode (LPM). This interrupt is level triggered. So USB IRQ
667 * line must be disabled till async interrupt enable bit is cleared
668 * in USBCMD register. Assert STP (ULPI interface STOP signal) to
669 * block data communication from PHY.
670 */
Pavankumar Kondeti4960f312011-12-06 15:46:14 +0530671 cmd_val = readl_relaxed(USB_USBCMD);
672 if (host_bus_suspend)
673 cmd_val |= ASYNC_INTR_CTRL | ULPI_STP_CTRL;
674 else
675 cmd_val |= ULPI_STP_CTRL;
676 writel_relaxed(cmd_val, USB_USBCMD);
Pavankumar Kondeti87c01042010-12-07 17:53:58 +0530677
Pavankumar Kondeti4960f312011-12-06 15:46:14 +0530678 if (motg->caps & ALLOW_PHY_RETENTION && !host_bus_suspend) {
Amit Blay58b31472011-11-18 09:39:39 +0200679 phy_ctrl_val = readl_relaxed(USB_PHY_CTRL);
680 if (motg->pdata->otg_control == OTG_PHY_CONTROL)
681 /* Enable PHY HV interrupts to wake MPM/Link */
682 phy_ctrl_val |=
683 (PHY_IDHV_INTEN | PHY_OTGSESSVLDHV_INTEN);
684
685 writel_relaxed(phy_ctrl_val & ~PHY_RETEN, USB_PHY_CTRL);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700686 motg->lpm_flags |= PHY_RETENTIONED;
687 }
Pavankumar Kondeti04aebcb2011-05-04 10:19:49 +0530688
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700689 /* Ensure that above operation is completed before turning off clocks */
690 mb();
Pavankumar Kondeti87c01042010-12-07 17:53:58 +0530691 clk_disable(motg->pclk);
Pavankumar Kondeti87c01042010-12-07 17:53:58 +0530692 if (motg->core_clk)
693 clk_disable(motg->core_clk);
694
Amit Blay137575f2011-11-06 15:20:54 +0200695 if (!IS_ERR(motg->system_clk))
696 clk_disable(motg->system_clk);
697
Anji jonnala0f73cac2011-05-04 10:19:46 +0530698 if (!IS_ERR(motg->pclk_src))
699 clk_disable(motg->pclk_src);
700
Anji jonnala7da3f262011-12-02 17:22:14 -0800701 /* usb phy no more require TCXO clock, hence vote for TCXO disable */
702 ret = msm_xo_mode_vote(motg->xo_handle, MSM_XO_MODE_OFF);
703 if (ret)
704 dev_err(otg->dev, "%s failed to devote for "
705 "TCXO D0 buffer%d\n", __func__, ret);
706
Pavankumar Kondeti4960f312011-12-06 15:46:14 +0530707 if (motg->caps & ALLOW_PHY_POWER_COLLAPSE && !host_bus_suspend) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700708 msm_hsusb_ldo_enable(motg, 0);
709 motg->lpm_flags |= PHY_PWR_COLLAPSED;
Pavankumar Kondeti04aebcb2011-05-04 10:19:49 +0530710 }
711
Vijayavardhan Vennapusafc464f02011-11-04 21:54:00 +0530712 if (motg->lpm_flags & PHY_RETENTIONED) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700713 msm_hsusb_config_vddcx(0);
Vijayavardhan Vennapusafc464f02011-11-04 21:54:00 +0530714 msm_hsusb_mhl_switch_enable(motg, 0);
715 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700716
717 if (device_may_wakeup(otg->dev)) {
Pavankumar Kondeti87c01042010-12-07 17:53:58 +0530718 enable_irq_wake(motg->irq);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700719 if (motg->pdata->pmic_id_irq)
720 enable_irq_wake(motg->pdata->pmic_id_irq);
721 }
Pavankumar Kondeti87c01042010-12-07 17:53:58 +0530722 if (bus)
723 clear_bit(HCD_FLAG_HW_ACCESSIBLE, &(bus_to_hcd(bus))->flags);
724
725 atomic_set(&motg->in_lpm, 1);
726 enable_irq(motg->irq);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700727 wake_unlock(&motg->wlock);
Pavankumar Kondeti87c01042010-12-07 17:53:58 +0530728
729 dev_info(otg->dev, "USB in low power mode\n");
730
731 return 0;
732}
733
Pavankumar Kondeti87c01042010-12-07 17:53:58 +0530734static int msm_otg_resume(struct msm_otg *motg)
735{
736 struct otg_transceiver *otg = &motg->otg;
737 struct usb_bus *bus = otg->host;
738 int cnt = 0;
739 unsigned temp;
Amit Blay58b31472011-11-18 09:39:39 +0200740 u32 phy_ctrl_val = 0;
Anji jonnala7da3f262011-12-02 17:22:14 -0800741 unsigned ret;
Pavankumar Kondeti87c01042010-12-07 17:53:58 +0530742
743 if (!atomic_read(&motg->in_lpm))
744 return 0;
745
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700746 wake_lock(&motg->wlock);
Anji jonnala7da3f262011-12-02 17:22:14 -0800747
748 /* Vote for TCXO when waking up the phy */
749 ret = msm_xo_mode_vote(motg->xo_handle, MSM_XO_MODE_ON);
750 if (ret)
751 dev_err(otg->dev, "%s failed to vote for "
752 "TCXO D0 buffer%d\n", __func__, ret);
753
Anji jonnala0f73cac2011-05-04 10:19:46 +0530754 if (!IS_ERR(motg->pclk_src))
755 clk_enable(motg->pclk_src);
756
Amit Blay137575f2011-11-06 15:20:54 +0200757 if (!IS_ERR(motg->system_clk))
758 clk_enable(motg->system_clk);
759
Pavankumar Kondeti87c01042010-12-07 17:53:58 +0530760 clk_enable(motg->pclk);
Pavankumar Kondeti87c01042010-12-07 17:53:58 +0530761 if (motg->core_clk)
762 clk_enable(motg->core_clk);
763
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700764 if (motg->lpm_flags & PHY_PWR_COLLAPSED) {
765 msm_hsusb_ldo_enable(motg, 1);
766 motg->lpm_flags &= ~PHY_PWR_COLLAPSED;
767 }
768
769 if (motg->lpm_flags & PHY_RETENTIONED) {
Vijayavardhan Vennapusafc464f02011-11-04 21:54:00 +0530770 msm_hsusb_mhl_switch_enable(motg, 1);
Pavankumar Kondeti04aebcb2011-05-04 10:19:49 +0530771 msm_hsusb_config_vddcx(1);
Amit Blay58b31472011-11-18 09:39:39 +0200772 phy_ctrl_val = readl_relaxed(USB_PHY_CTRL);
773 phy_ctrl_val |= PHY_RETEN;
774 if (motg->pdata->otg_control == OTG_PHY_CONTROL)
775 /* Disable PHY HV interrupts */
776 phy_ctrl_val &=
777 ~(PHY_IDHV_INTEN | PHY_OTGSESSVLDHV_INTEN);
778 writel_relaxed(phy_ctrl_val, USB_PHY_CTRL);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700779 motg->lpm_flags &= ~PHY_RETENTIONED;
Pavankumar Kondeti04aebcb2011-05-04 10:19:49 +0530780 }
781
Pavankumar Kondeti87c01042010-12-07 17:53:58 +0530782 temp = readl(USB_USBCMD);
783 temp &= ~ASYNC_INTR_CTRL;
784 temp &= ~ULPI_STP_CTRL;
785 writel(temp, USB_USBCMD);
786
787 /*
788 * PHY comes out of low power mode (LPM) in case of wakeup
789 * from asynchronous interrupt.
790 */
791 if (!(readl(USB_PORTSC) & PORTSC_PHCD))
792 goto skip_phy_resume;
793
794 writel(readl(USB_PORTSC) & ~PORTSC_PHCD, USB_PORTSC);
795 while (cnt < PHY_RESUME_TIMEOUT_USEC) {
796 if (!(readl(USB_PORTSC) & PORTSC_PHCD))
797 break;
798 udelay(1);
799 cnt++;
800 }
801
802 if (cnt >= PHY_RESUME_TIMEOUT_USEC) {
803 /*
804 * This is a fatal error. Reset the link and
805 * PHY. USB state can not be restored. Re-insertion
806 * of USB cable is the only way to get USB working.
807 */
808 dev_err(otg->dev, "Unable to resume USB."
809 "Re-plugin the cable\n");
810 msm_otg_reset(otg);
811 }
812
813skip_phy_resume:
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700814 /* Turn on the OTG comparators on resume */
815 if (motg->lpm_flags & PHY_OTG_COMP_DISABLED) {
816 ulpi_write(otg, OTG_COMP_DISABLE,
817 ULPI_CLR(ULPI_PWR_CLK_MNG_REG));
818 motg->lpm_flags &= ~PHY_OTG_COMP_DISABLED;
819 }
820 if (device_may_wakeup(otg->dev)) {
Pavankumar Kondeti87c01042010-12-07 17:53:58 +0530821 disable_irq_wake(motg->irq);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700822 if (motg->pdata->pmic_id_irq)
823 disable_irq_wake(motg->pdata->pmic_id_irq);
824 }
Pavankumar Kondeti87c01042010-12-07 17:53:58 +0530825 if (bus)
826 set_bit(HCD_FLAG_HW_ACCESSIBLE, &(bus_to_hcd(bus))->flags);
827
Pavankumar Kondeti2ce2c3a2011-05-02 11:56:33 +0530828 atomic_set(&motg->in_lpm, 0);
829
Pavankumar Kondeti87c01042010-12-07 17:53:58 +0530830 if (motg->async_int) {
831 motg->async_int = 0;
Pavankumar Kondeti87c01042010-12-07 17:53:58 +0530832 enable_irq(motg->irq);
833 }
834
Pavankumar Kondeti87c01042010-12-07 17:53:58 +0530835 dev_info(otg->dev, "USB exited from low power mode\n");
836
837 return 0;
838}
Pavankumar Kondeti70187732011-02-15 09:42:34 +0530839#endif
Pavankumar Kondeti87c01042010-12-07 17:53:58 +0530840
Pavankumar Kondetid8608522011-05-04 10:19:47 +0530841static void msm_otg_notify_charger(struct msm_otg *motg, unsigned mA)
842{
Pavankumar Kondetiaa449e12011-11-04 11:09:26 +0530843 if ((motg->chg_type == USB_ACA_DOCK_CHARGER ||
844 motg->chg_type == USB_ACA_A_CHARGER ||
845 motg->chg_type == USB_ACA_B_CHARGER ||
846 motg->chg_type == USB_ACA_C_CHARGER) &&
847 mA > IDEV_ACA_CHG_LIMIT)
848 mA = IDEV_ACA_CHG_LIMIT;
849
Pavankumar Kondetid8608522011-05-04 10:19:47 +0530850 if (motg->cur_power == mA)
851 return;
852
Pavankumar Kondetid8608522011-05-04 10:19:47 +0530853 dev_info(motg->otg.dev, "Avail curr from USB = %u\n", mA);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700854 pm8921_charger_vbus_draw(mA);
Pavankumar Kondetid8608522011-05-04 10:19:47 +0530855 motg->cur_power = mA;
856}
857
858static int msm_otg_set_power(struct otg_transceiver *otg, unsigned mA)
859{
860 struct msm_otg *motg = container_of(otg, struct msm_otg, otg);
861
862 /*
863 * Gadget driver uses set_power method to notify about the
864 * available current based on suspend/configured states.
865 *
866 * IDEV_CHG can be drawn irrespective of suspend/un-configured
867 * states when CDP/ACA is connected.
868 */
869 if (motg->chg_type == USB_SDP_CHARGER)
870 msm_otg_notify_charger(motg, mA);
871
872 return 0;
873}
874
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +0530875static void msm_otg_start_host(struct otg_transceiver *otg, int on)
876{
877 struct msm_otg *motg = container_of(otg, struct msm_otg, otg);
878 struct msm_otg_platform_data *pdata = motg->pdata;
879 struct usb_hcd *hcd;
880
881 if (!otg->host)
882 return;
883
884 hcd = bus_to_hcd(otg->host);
885
886 if (on) {
887 dev_dbg(otg->dev, "host on\n");
888
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +0530889 /*
890 * Some boards have a switch cotrolled by gpio
891 * to enable/disable internal HUB. Enable internal
892 * HUB before kicking the host.
893 */
894 if (pdata->setup_gpio)
895 pdata->setup_gpio(OTG_STATE_A_HOST);
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +0530896 usb_add_hcd(hcd, hcd->irq, IRQF_SHARED);
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +0530897 } else {
898 dev_dbg(otg->dev, "host off\n");
899
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +0530900 usb_remove_hcd(hcd);
Pavankumar Kondetiaa449e12011-11-04 11:09:26 +0530901 /* HCD core reset all bits of PORTSC. select ULPI phy */
902 writel_relaxed(0x80000000, USB_PORTSC);
903
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +0530904 if (pdata->setup_gpio)
905 pdata->setup_gpio(OTG_STATE_UNDEFINED);
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +0530906 }
907}
908
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700909static int msm_otg_usbdev_notify(struct notifier_block *self,
910 unsigned long action, void *priv)
911{
912 struct msm_otg *motg = container_of(self, struct msm_otg, usbdev_nb);
Pavankumar Kondetiaa449e12011-11-04 11:09:26 +0530913 struct usb_device *udev = priv;
914
915 if (!aca_enabled())
916 goto out;
917
918 if (action == USB_BUS_ADD || action == USB_BUS_REMOVE)
919 goto out;
920
921 if (udev->bus != motg->otg.host)
922 goto out;
923 /*
924 * Interested in devices connected directly to the root hub.
925 * ACA dock can supply IDEV_CHG irrespective devices connected
926 * on the accessory port.
927 */
928 if (!udev->parent || udev->parent->parent ||
929 motg->chg_type == USB_ACA_DOCK_CHARGER)
930 goto out;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700931
932 switch (action) {
933 case USB_DEVICE_ADD:
Pavankumar Kondetiaa449e12011-11-04 11:09:26 +0530934 usb_disable_autosuspend(udev);
935 /* fall through */
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700936 case USB_DEVICE_CONFIG:
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700937 if (udev->actconfig)
938 motg->mA_port = udev->actconfig->desc.bMaxPower * 2;
939 else
940 motg->mA_port = IUNIT;
Pavankumar Kondetiaa449e12011-11-04 11:09:26 +0530941 break;
942 case USB_DEVICE_REMOVE:
943 motg->mA_port = IUNIT;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700944 break;
945 default:
946 break;
947 }
Pavankumar Kondetiaa449e12011-11-04 11:09:26 +0530948 if (test_bit(ID_A, &motg->inputs))
949 msm_otg_notify_charger(motg, IDEV_ACA_CHG_MAX -
950 motg->mA_port);
951out:
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700952 return NOTIFY_OK;
953}
954
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +0530955static int msm_otg_set_host(struct otg_transceiver *otg, struct usb_bus *host)
956{
957 struct msm_otg *motg = container_of(otg, struct msm_otg, otg);
958 struct usb_hcd *hcd;
959
960 /*
961 * Fail host registration if this board can support
962 * only peripheral configuration.
963 */
964 if (motg->pdata->mode == USB_PERIPHERAL) {
965 dev_info(otg->dev, "Host mode is not supported\n");
966 return -ENODEV;
967 }
968
969 if (!host) {
970 if (otg->state == OTG_STATE_A_HOST) {
Pavankumar Kondeti87c01042010-12-07 17:53:58 +0530971 pm_runtime_get_sync(otg->dev);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700972 usb_unregister_notify(&motg->usbdev_nb);
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +0530973 msm_otg_start_host(otg, 0);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700974 if (motg->pdata->vbus_power)
975 motg->pdata->vbus_power(0);
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +0530976 otg->host = NULL;
977 otg->state = OTG_STATE_UNDEFINED;
978 schedule_work(&motg->sm_work);
979 } else {
980 otg->host = NULL;
981 }
982
983 return 0;
984 }
985
986 hcd = bus_to_hcd(host);
987 hcd->power_budget = motg->pdata->power_budget;
988
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700989 motg->usbdev_nb.notifier_call = msm_otg_usbdev_notify;
990 usb_register_notify(&motg->usbdev_nb);
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +0530991 otg->host = host;
992 dev_dbg(otg->dev, "host driver registered w/ tranceiver\n");
993
994 /*
995 * Kick the state machine work, if peripheral is not supported
996 * or peripheral is already registered with us.
997 */
Pavankumar Kondeti87c01042010-12-07 17:53:58 +0530998 if (motg->pdata->mode == USB_HOST || otg->gadget) {
999 pm_runtime_get_sync(otg->dev);
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05301000 schedule_work(&motg->sm_work);
Pavankumar Kondeti87c01042010-12-07 17:53:58 +05301001 }
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05301002
1003 return 0;
1004}
1005
1006static void msm_otg_start_peripheral(struct otg_transceiver *otg, int on)
1007{
1008 struct msm_otg *motg = container_of(otg, struct msm_otg, otg);
1009 struct msm_otg_platform_data *pdata = motg->pdata;
1010
1011 if (!otg->gadget)
1012 return;
1013
1014 if (on) {
1015 dev_dbg(otg->dev, "gadget on\n");
1016 /*
1017 * Some boards have a switch cotrolled by gpio
1018 * to enable/disable internal HUB. Disable internal
1019 * HUB before kicking the gadget.
1020 */
1021 if (pdata->setup_gpio)
1022 pdata->setup_gpio(OTG_STATE_B_PERIPHERAL);
Anji jonnalaa7c1c5c2011-12-12 12:20:36 +05301023 /*
1024 * vote for minimum dma_latency to prevent idle
1025 * power collapse(pc) while running in peripheral mode.
1026 */
1027 otg_pm_qos_update_latency(motg, 1);
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05301028 usb_gadget_vbus_connect(otg->gadget);
1029 } else {
1030 dev_dbg(otg->dev, "gadget off\n");
1031 usb_gadget_vbus_disconnect(otg->gadget);
Anji jonnalaa7c1c5c2011-12-12 12:20:36 +05301032 otg_pm_qos_update_latency(motg, 0);
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05301033 if (pdata->setup_gpio)
1034 pdata->setup_gpio(OTG_STATE_UNDEFINED);
1035 }
1036
1037}
1038
1039static int msm_otg_set_peripheral(struct otg_transceiver *otg,
1040 struct usb_gadget *gadget)
1041{
1042 struct msm_otg *motg = container_of(otg, struct msm_otg, otg);
1043
1044 /*
1045 * Fail peripheral registration if this board can support
1046 * only host configuration.
1047 */
1048 if (motg->pdata->mode == USB_HOST) {
1049 dev_info(otg->dev, "Peripheral mode is not supported\n");
1050 return -ENODEV;
1051 }
1052
1053 if (!gadget) {
1054 if (otg->state == OTG_STATE_B_PERIPHERAL) {
Pavankumar Kondeti87c01042010-12-07 17:53:58 +05301055 pm_runtime_get_sync(otg->dev);
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05301056 msm_otg_start_peripheral(otg, 0);
1057 otg->gadget = NULL;
1058 otg->state = OTG_STATE_UNDEFINED;
1059 schedule_work(&motg->sm_work);
1060 } else {
1061 otg->gadget = NULL;
1062 }
1063
1064 return 0;
1065 }
1066 otg->gadget = gadget;
1067 dev_dbg(otg->dev, "peripheral driver registered w/ tranceiver\n");
1068
1069 /*
1070 * Kick the state machine work, if host is not supported
1071 * or host is already registered with us.
1072 */
Pavankumar Kondeti87c01042010-12-07 17:53:58 +05301073 if (motg->pdata->mode == USB_PERIPHERAL || otg->host) {
1074 pm_runtime_get_sync(otg->dev);
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05301075 schedule_work(&motg->sm_work);
Pavankumar Kondeti87c01042010-12-07 17:53:58 +05301076 }
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05301077
1078 return 0;
1079}
1080
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001081static bool msm_chg_aca_detect(struct msm_otg *motg)
1082{
1083 struct otg_transceiver *otg = &motg->otg;
1084 u32 int_sts;
1085 bool ret = false;
1086
Pavankumar Kondetiaa449e12011-11-04 11:09:26 +05301087 if (!aca_enabled())
1088 goto out;
1089
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001090 if (motg->pdata->phy_type == CI_45NM_INTEGRATED_PHY)
1091 goto out;
1092
1093 int_sts = ulpi_read(otg, 0x87);
1094 switch (int_sts & 0x1C) {
1095 case 0x08:
1096 if (!test_and_set_bit(ID_A, &motg->inputs)) {
1097 dev_dbg(otg->dev, "ID_A\n");
1098 motg->chg_type = USB_ACA_A_CHARGER;
1099 motg->chg_state = USB_CHG_STATE_DETECTED;
1100 clear_bit(ID_B, &motg->inputs);
1101 clear_bit(ID_C, &motg->inputs);
Pavankumar Kondetiaa449e12011-11-04 11:09:26 +05301102 set_bit(ID, &motg->inputs);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001103 ret = true;
1104 }
1105 break;
1106 case 0x0C:
1107 if (!test_and_set_bit(ID_B, &motg->inputs)) {
1108 dev_dbg(otg->dev, "ID_B\n");
1109 motg->chg_type = USB_ACA_B_CHARGER;
1110 motg->chg_state = USB_CHG_STATE_DETECTED;
1111 clear_bit(ID_A, &motg->inputs);
1112 clear_bit(ID_C, &motg->inputs);
Pavankumar Kondetiaa449e12011-11-04 11:09:26 +05301113 set_bit(ID, &motg->inputs);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001114 ret = true;
1115 }
1116 break;
1117 case 0x10:
1118 if (!test_and_set_bit(ID_C, &motg->inputs)) {
1119 dev_dbg(otg->dev, "ID_C\n");
1120 motg->chg_type = USB_ACA_C_CHARGER;
1121 motg->chg_state = USB_CHG_STATE_DETECTED;
1122 clear_bit(ID_A, &motg->inputs);
1123 clear_bit(ID_B, &motg->inputs);
Pavankumar Kondetiaa449e12011-11-04 11:09:26 +05301124 set_bit(ID, &motg->inputs);
1125 ret = true;
1126 }
1127 break;
1128 case 0x04:
1129 if (test_and_clear_bit(ID, &motg->inputs)) {
1130 dev_dbg(otg->dev, "ID_GND\n");
1131 motg->chg_type = USB_INVALID_CHARGER;
1132 motg->chg_state = USB_CHG_STATE_UNDEFINED;
1133 clear_bit(ID_A, &motg->inputs);
1134 clear_bit(ID_B, &motg->inputs);
1135 clear_bit(ID_C, &motg->inputs);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001136 ret = true;
1137 }
1138 break;
1139 default:
1140 ret = test_and_clear_bit(ID_A, &motg->inputs) |
1141 test_and_clear_bit(ID_B, &motg->inputs) |
Pavankumar Kondetiaa449e12011-11-04 11:09:26 +05301142 test_and_clear_bit(ID_C, &motg->inputs) |
1143 !test_and_set_bit(ID, &motg->inputs);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001144 if (ret) {
Pavankumar Kondetiaa449e12011-11-04 11:09:26 +05301145 dev_dbg(otg->dev, "ID A/B/C/GND is no more\n");
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001146 motg->chg_type = USB_INVALID_CHARGER;
1147 motg->chg_state = USB_CHG_STATE_UNDEFINED;
1148 }
1149 }
1150out:
1151 return ret;
1152}
1153
1154static void msm_chg_enable_aca_det(struct msm_otg *motg)
1155{
1156 struct otg_transceiver *otg = &motg->otg;
1157
Pavankumar Kondetiaa449e12011-11-04 11:09:26 +05301158 if (!aca_enabled())
1159 return;
1160
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001161 switch (motg->pdata->phy_type) {
1162 case SNPS_28NM_INTEGRATED_PHY:
Pavankumar Kondetiaa449e12011-11-04 11:09:26 +05301163 /* Disable ID_GND in link and PHY */
1164 writel_relaxed(readl_relaxed(USB_OTGSC) & ~(OTGSC_IDPU |
1165 OTGSC_IDIE), USB_OTGSC);
1166 ulpi_write(otg, 0x01, 0x0C);
1167 ulpi_write(otg, 0x10, 0x0F);
1168 ulpi_write(otg, 0x10, 0x12);
1169 /* Enable ACA ID detection */
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001170 ulpi_write(otg, 0x20, 0x85);
Pavankumar Kondeti4960f312011-12-06 15:46:14 +05301171 aca_id_turned_on = true;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001172 break;
1173 default:
1174 break;
1175 }
1176}
1177
1178static void msm_chg_enable_aca_intr(struct msm_otg *motg)
1179{
1180 struct otg_transceiver *otg = &motg->otg;
1181
Pavankumar Kondetiaa449e12011-11-04 11:09:26 +05301182 if (!aca_enabled())
1183 return;
1184
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001185 switch (motg->pdata->phy_type) {
1186 case SNPS_28NM_INTEGRATED_PHY:
Pavankumar Kondetiaa449e12011-11-04 11:09:26 +05301187 /* Enable ACA Detection interrupt (on any RID change) */
1188 ulpi_write(otg, 0x01, 0x94);
1189 break;
1190 default:
1191 break;
1192 }
1193}
1194
1195static void msm_chg_disable_aca_intr(struct msm_otg *motg)
1196{
1197 struct otg_transceiver *otg = &motg->otg;
1198
1199 if (!aca_enabled())
1200 return;
1201
1202 switch (motg->pdata->phy_type) {
1203 case SNPS_28NM_INTEGRATED_PHY:
1204 ulpi_write(otg, 0x01, 0x95);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001205 break;
1206 default:
1207 break;
1208 }
1209}
1210
1211static bool msm_chg_check_aca_intr(struct msm_otg *motg)
1212{
1213 struct otg_transceiver *otg = &motg->otg;
1214 bool ret = false;
1215
Pavankumar Kondetiaa449e12011-11-04 11:09:26 +05301216 if (!aca_enabled())
1217 return ret;
1218
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001219 switch (motg->pdata->phy_type) {
1220 case SNPS_28NM_INTEGRATED_PHY:
1221 if (ulpi_read(otg, 0x91) & 1) {
1222 dev_dbg(otg->dev, "RID change\n");
1223 ulpi_write(otg, 0x01, 0x92);
1224 ret = msm_chg_aca_detect(motg);
1225 }
1226 default:
1227 break;
1228 }
1229 return ret;
1230}
Pavankumar Kondetiaa449e12011-11-04 11:09:26 +05301231
1232static void msm_otg_id_timer_func(unsigned long data)
1233{
1234 struct msm_otg *motg = (struct msm_otg *) data;
1235
1236 if (!aca_enabled())
1237 return;
1238
1239 if (atomic_read(&motg->in_lpm)) {
1240 dev_dbg(motg->otg.dev, "timer: in lpm\n");
1241 return;
1242 }
1243
1244 if (msm_chg_check_aca_intr(motg)) {
1245 dev_dbg(motg->otg.dev, "timer: aca work\n");
1246 schedule_work(&motg->sm_work);
1247 }
1248
1249 if (!test_bit(ID, &motg->inputs) || test_bit(ID_A, &motg->inputs))
1250 mod_timer(&motg->id_timer, ID_TIMER_FREQ);
1251}
1252
Pavankumar Kondetid8608522011-05-04 10:19:47 +05301253static bool msm_chg_check_secondary_det(struct msm_otg *motg)
1254{
1255 struct otg_transceiver *otg = &motg->otg;
1256 u32 chg_det;
1257 bool ret = false;
1258
1259 switch (motg->pdata->phy_type) {
1260 case CI_45NM_INTEGRATED_PHY:
1261 chg_det = ulpi_read(otg, 0x34);
1262 ret = chg_det & (1 << 4);
1263 break;
1264 case SNPS_28NM_INTEGRATED_PHY:
1265 chg_det = ulpi_read(otg, 0x87);
1266 ret = chg_det & 1;
1267 break;
1268 default:
1269 break;
1270 }
1271 return ret;
1272}
1273
1274static void msm_chg_enable_secondary_det(struct msm_otg *motg)
1275{
1276 struct otg_transceiver *otg = &motg->otg;
1277 u32 chg_det;
1278
1279 switch (motg->pdata->phy_type) {
1280 case CI_45NM_INTEGRATED_PHY:
1281 chg_det = ulpi_read(otg, 0x34);
1282 /* Turn off charger block */
1283 chg_det |= ~(1 << 1);
1284 ulpi_write(otg, chg_det, 0x34);
1285 udelay(20);
1286 /* control chg block via ULPI */
1287 chg_det &= ~(1 << 3);
1288 ulpi_write(otg, chg_det, 0x34);
1289 /* put it in host mode for enabling D- source */
1290 chg_det &= ~(1 << 2);
1291 ulpi_write(otg, chg_det, 0x34);
1292 /* Turn on chg detect block */
1293 chg_det &= ~(1 << 1);
1294 ulpi_write(otg, chg_det, 0x34);
1295 udelay(20);
1296 /* enable chg detection */
1297 chg_det &= ~(1 << 0);
1298 ulpi_write(otg, chg_det, 0x34);
1299 break;
1300 case SNPS_28NM_INTEGRATED_PHY:
1301 /*
1302 * Configure DM as current source, DP as current sink
1303 * and enable battery charging comparators.
1304 */
1305 ulpi_write(otg, 0x8, 0x85);
1306 ulpi_write(otg, 0x2, 0x85);
1307 ulpi_write(otg, 0x1, 0x85);
1308 break;
1309 default:
1310 break;
1311 }
1312}
1313
1314static bool msm_chg_check_primary_det(struct msm_otg *motg)
1315{
1316 struct otg_transceiver *otg = &motg->otg;
1317 u32 chg_det;
1318 bool ret = false;
1319
1320 switch (motg->pdata->phy_type) {
1321 case CI_45NM_INTEGRATED_PHY:
1322 chg_det = ulpi_read(otg, 0x34);
1323 ret = chg_det & (1 << 4);
1324 break;
1325 case SNPS_28NM_INTEGRATED_PHY:
1326 chg_det = ulpi_read(otg, 0x87);
1327 ret = chg_det & 1;
1328 break;
1329 default:
1330 break;
1331 }
1332 return ret;
1333}
1334
1335static void msm_chg_enable_primary_det(struct msm_otg *motg)
1336{
1337 struct otg_transceiver *otg = &motg->otg;
1338 u32 chg_det;
1339
1340 switch (motg->pdata->phy_type) {
1341 case CI_45NM_INTEGRATED_PHY:
1342 chg_det = ulpi_read(otg, 0x34);
1343 /* enable chg detection */
1344 chg_det &= ~(1 << 0);
1345 ulpi_write(otg, chg_det, 0x34);
1346 break;
1347 case SNPS_28NM_INTEGRATED_PHY:
1348 /*
1349 * Configure DP as current source, DM as current sink
1350 * and enable battery charging comparators.
1351 */
1352 ulpi_write(otg, 0x2, 0x85);
1353 ulpi_write(otg, 0x1, 0x85);
1354 break;
1355 default:
1356 break;
1357 }
1358}
1359
1360static bool msm_chg_check_dcd(struct msm_otg *motg)
1361{
1362 struct otg_transceiver *otg = &motg->otg;
1363 u32 line_state;
1364 bool ret = false;
1365
1366 switch (motg->pdata->phy_type) {
1367 case CI_45NM_INTEGRATED_PHY:
1368 line_state = ulpi_read(otg, 0x15);
1369 ret = !(line_state & 1);
1370 break;
1371 case SNPS_28NM_INTEGRATED_PHY:
1372 line_state = ulpi_read(otg, 0x87);
1373 ret = line_state & 2;
1374 break;
1375 default:
1376 break;
1377 }
1378 return ret;
1379}
1380
1381static void msm_chg_disable_dcd(struct msm_otg *motg)
1382{
1383 struct otg_transceiver *otg = &motg->otg;
1384 u32 chg_det;
1385
1386 switch (motg->pdata->phy_type) {
1387 case CI_45NM_INTEGRATED_PHY:
1388 chg_det = ulpi_read(otg, 0x34);
1389 chg_det &= ~(1 << 5);
1390 ulpi_write(otg, chg_det, 0x34);
1391 break;
1392 case SNPS_28NM_INTEGRATED_PHY:
1393 ulpi_write(otg, 0x10, 0x86);
1394 break;
1395 default:
1396 break;
1397 }
1398}
1399
1400static void msm_chg_enable_dcd(struct msm_otg *motg)
1401{
1402 struct otg_transceiver *otg = &motg->otg;
1403 u32 chg_det;
1404
1405 switch (motg->pdata->phy_type) {
1406 case CI_45NM_INTEGRATED_PHY:
1407 chg_det = ulpi_read(otg, 0x34);
1408 /* Turn on D+ current source */
1409 chg_det |= (1 << 5);
1410 ulpi_write(otg, chg_det, 0x34);
1411 break;
1412 case SNPS_28NM_INTEGRATED_PHY:
1413 /* Data contact detection enable */
1414 ulpi_write(otg, 0x10, 0x85);
1415 break;
1416 default:
1417 break;
1418 }
1419}
1420
1421static void msm_chg_block_on(struct msm_otg *motg)
1422{
1423 struct otg_transceiver *otg = &motg->otg;
1424 u32 func_ctrl, chg_det;
1425
1426 /* put the controller in non-driving mode */
1427 func_ctrl = ulpi_read(otg, ULPI_FUNC_CTRL);
1428 func_ctrl &= ~ULPI_FUNC_CTRL_OPMODE_MASK;
1429 func_ctrl |= ULPI_FUNC_CTRL_OPMODE_NONDRIVING;
1430 ulpi_write(otg, func_ctrl, ULPI_FUNC_CTRL);
1431
1432 switch (motg->pdata->phy_type) {
1433 case CI_45NM_INTEGRATED_PHY:
1434 chg_det = ulpi_read(otg, 0x34);
1435 /* control chg block via ULPI */
1436 chg_det &= ~(1 << 3);
1437 ulpi_write(otg, chg_det, 0x34);
1438 /* Turn on chg detect block */
1439 chg_det &= ~(1 << 1);
1440 ulpi_write(otg, chg_det, 0x34);
1441 udelay(20);
1442 break;
1443 case SNPS_28NM_INTEGRATED_PHY:
1444 /* Clear charger detecting control bits */
Pavankumar Kondetiaa449e12011-11-04 11:09:26 +05301445 ulpi_write(otg, 0x1F, 0x86);
Pavankumar Kondetid8608522011-05-04 10:19:47 +05301446 /* Clear alt interrupt latch and enable bits */
1447 ulpi_write(otg, 0x1F, 0x92);
1448 ulpi_write(otg, 0x1F, 0x95);
1449 udelay(100);
1450 break;
1451 default:
1452 break;
1453 }
1454}
1455
1456static void msm_chg_block_off(struct msm_otg *motg)
1457{
1458 struct otg_transceiver *otg = &motg->otg;
1459 u32 func_ctrl, chg_det;
1460
1461 switch (motg->pdata->phy_type) {
1462 case CI_45NM_INTEGRATED_PHY:
1463 chg_det = ulpi_read(otg, 0x34);
1464 /* Turn off charger block */
1465 chg_det |= ~(1 << 1);
1466 ulpi_write(otg, chg_det, 0x34);
1467 break;
1468 case SNPS_28NM_INTEGRATED_PHY:
1469 /* Clear charger detecting control bits */
1470 ulpi_write(otg, 0x3F, 0x86);
1471 /* Clear alt interrupt latch and enable bits */
1472 ulpi_write(otg, 0x1F, 0x92);
1473 ulpi_write(otg, 0x1F, 0x95);
1474 break;
1475 default:
1476 break;
1477 }
1478
1479 /* put the controller in normal mode */
1480 func_ctrl = ulpi_read(otg, ULPI_FUNC_CTRL);
1481 func_ctrl &= ~ULPI_FUNC_CTRL_OPMODE_MASK;
1482 func_ctrl |= ULPI_FUNC_CTRL_OPMODE_NORMAL;
1483 ulpi_write(otg, func_ctrl, ULPI_FUNC_CTRL);
1484}
1485
Anji jonnalad270e2d2011-08-09 11:28:32 +05301486static const char *chg_to_string(enum usb_chg_type chg_type)
1487{
1488 switch (chg_type) {
1489 case USB_SDP_CHARGER: return "USB_SDP_CHARGER";
1490 case USB_DCP_CHARGER: return "USB_DCP_CHARGER";
1491 case USB_CDP_CHARGER: return "USB_CDP_CHARGER";
1492 case USB_ACA_A_CHARGER: return "USB_ACA_A_CHARGER";
1493 case USB_ACA_B_CHARGER: return "USB_ACA_B_CHARGER";
1494 case USB_ACA_C_CHARGER: return "USB_ACA_C_CHARGER";
1495 case USB_ACA_DOCK_CHARGER: return "USB_ACA_DOCK_CHARGER";
1496 default: return "INVALID_CHARGER";
1497 }
1498}
1499
Pavankumar Kondetid8608522011-05-04 10:19:47 +05301500#define MSM_CHG_DCD_POLL_TIME (100 * HZ/1000) /* 100 msec */
1501#define MSM_CHG_DCD_MAX_RETRIES 6 /* Tdcd_tmout = 6 * 100 msec */
1502#define MSM_CHG_PRIMARY_DET_TIME (40 * HZ/1000) /* TVDPSRC_ON */
1503#define MSM_CHG_SECONDARY_DET_TIME (40 * HZ/1000) /* TVDMSRC_ON */
1504static void msm_chg_detect_work(struct work_struct *w)
1505{
1506 struct msm_otg *motg = container_of(w, struct msm_otg, chg_work.work);
1507 struct otg_transceiver *otg = &motg->otg;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001508 bool is_dcd, tmout, vout, is_aca;
Pavankumar Kondetid8608522011-05-04 10:19:47 +05301509 unsigned long delay;
1510
1511 dev_dbg(otg->dev, "chg detection work\n");
1512 switch (motg->chg_state) {
1513 case USB_CHG_STATE_UNDEFINED:
Pavankumar Kondetid8608522011-05-04 10:19:47 +05301514 msm_chg_block_on(motg);
1515 msm_chg_enable_dcd(motg);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001516 msm_chg_enable_aca_det(motg);
Pavankumar Kondetid8608522011-05-04 10:19:47 +05301517 motg->chg_state = USB_CHG_STATE_WAIT_FOR_DCD;
1518 motg->dcd_retries = 0;
1519 delay = MSM_CHG_DCD_POLL_TIME;
1520 break;
1521 case USB_CHG_STATE_WAIT_FOR_DCD:
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001522 is_aca = msm_chg_aca_detect(motg);
1523 if (is_aca) {
1524 /*
1525 * ID_A can be ACA dock too. continue
1526 * primary detection after DCD.
1527 */
1528 if (test_bit(ID_A, &motg->inputs)) {
1529 motg->chg_state = USB_CHG_STATE_WAIT_FOR_DCD;
1530 } else {
1531 delay = 0;
1532 break;
1533 }
1534 }
Pavankumar Kondetid8608522011-05-04 10:19:47 +05301535 is_dcd = msm_chg_check_dcd(motg);
1536 tmout = ++motg->dcd_retries == MSM_CHG_DCD_MAX_RETRIES;
1537 if (is_dcd || tmout) {
1538 msm_chg_disable_dcd(motg);
1539 msm_chg_enable_primary_det(motg);
1540 delay = MSM_CHG_PRIMARY_DET_TIME;
1541 motg->chg_state = USB_CHG_STATE_DCD_DONE;
1542 } else {
1543 delay = MSM_CHG_DCD_POLL_TIME;
1544 }
1545 break;
1546 case USB_CHG_STATE_DCD_DONE:
1547 vout = msm_chg_check_primary_det(motg);
1548 if (vout) {
Pavankumar Kondetiaa449e12011-11-04 11:09:26 +05301549 if (test_bit(ID_A, &motg->inputs)) {
1550 motg->chg_type = USB_ACA_DOCK_CHARGER;
1551 motg->chg_state = USB_CHG_STATE_DETECTED;
1552 delay = 0;
1553 break;
1554 }
Pavankumar Kondetid8608522011-05-04 10:19:47 +05301555 msm_chg_enable_secondary_det(motg);
1556 delay = MSM_CHG_SECONDARY_DET_TIME;
1557 motg->chg_state = USB_CHG_STATE_PRIMARY_DONE;
1558 } else {
Pavankumar Kondetiaa449e12011-11-04 11:09:26 +05301559 if (test_bit(ID_A, &motg->inputs)) {
1560 motg->chg_type = USB_ACA_A_CHARGER;
1561 motg->chg_state = USB_CHG_STATE_DETECTED;
1562 delay = 0;
1563 break;
1564 }
Pavankumar Kondetid8608522011-05-04 10:19:47 +05301565 motg->chg_type = USB_SDP_CHARGER;
1566 motg->chg_state = USB_CHG_STATE_DETECTED;
1567 delay = 0;
1568 }
1569 break;
1570 case USB_CHG_STATE_PRIMARY_DONE:
1571 vout = msm_chg_check_secondary_det(motg);
1572 if (vout)
1573 motg->chg_type = USB_DCP_CHARGER;
1574 else
1575 motg->chg_type = USB_CDP_CHARGER;
1576 motg->chg_state = USB_CHG_STATE_SECONDARY_DONE;
1577 /* fall through */
1578 case USB_CHG_STATE_SECONDARY_DONE:
1579 motg->chg_state = USB_CHG_STATE_DETECTED;
1580 case USB_CHG_STATE_DETECTED:
1581 msm_chg_block_off(motg);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001582 msm_chg_enable_aca_det(motg);
1583 msm_chg_enable_aca_intr(motg);
Anji jonnalad270e2d2011-08-09 11:28:32 +05301584 dev_dbg(otg->dev, "chg_type = %s\n",
1585 chg_to_string(motg->chg_type));
Pavankumar Kondetid8608522011-05-04 10:19:47 +05301586 schedule_work(&motg->sm_work);
1587 return;
1588 default:
1589 return;
1590 }
1591
1592 schedule_delayed_work(&motg->chg_work, delay);
1593}
1594
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05301595/*
1596 * We support OTG, Peripheral only and Host only configurations. In case
1597 * of OTG, mode switch (host-->peripheral/peripheral-->host) can happen
1598 * via Id pin status or user request (debugfs). Id/BSV interrupts are not
1599 * enabled when switch is controlled by user and default mode is supplied
1600 * by board file, which can be changed by userspace later.
1601 */
1602static void msm_otg_init_sm(struct msm_otg *motg)
1603{
1604 struct msm_otg_platform_data *pdata = motg->pdata;
1605 u32 otgsc = readl(USB_OTGSC);
1606
1607 switch (pdata->mode) {
1608 case USB_OTG:
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001609 if (pdata->otg_control == OTG_USER_CONTROL) {
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05301610 if (pdata->default_mode == USB_HOST) {
1611 clear_bit(ID, &motg->inputs);
1612 } else if (pdata->default_mode == USB_PERIPHERAL) {
1613 set_bit(ID, &motg->inputs);
1614 set_bit(B_SESS_VLD, &motg->inputs);
1615 } else {
1616 set_bit(ID, &motg->inputs);
1617 clear_bit(B_SESS_VLD, &motg->inputs);
1618 }
Pavankumar Kondeti4960f312011-12-06 15:46:14 +05301619 } else if (pdata->otg_control == OTG_PHY_CONTROL) {
1620 if (otgsc & OTGSC_ID)
1621 set_bit(ID, &motg->inputs);
1622 else
1623 clear_bit(ID, &motg->inputs);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001624 if (otgsc & OTGSC_BSV)
1625 set_bit(B_SESS_VLD, &motg->inputs);
1626 else
1627 clear_bit(B_SESS_VLD, &motg->inputs);
Pavankumar Kondeti4960f312011-12-06 15:46:14 +05301628 } else if (pdata->otg_control == OTG_PMIC_CONTROL) {
1629 if (irq_read_line(motg->pdata->pmic_id_irq))
1630 set_bit(ID, &motg->inputs);
1631 else
1632 clear_bit(ID, &motg->inputs);
1633
1634 /*
1635 * VBUS initial state is reported after PMIC
1636 * driver initialization. Wait for it.
1637 */
1638 wait_for_completion(&pmic_vbus_init);
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05301639 }
1640 break;
1641 case USB_HOST:
1642 clear_bit(ID, &motg->inputs);
1643 break;
1644 case USB_PERIPHERAL:
1645 set_bit(ID, &motg->inputs);
1646 if (otgsc & OTGSC_BSV)
1647 set_bit(B_SESS_VLD, &motg->inputs);
1648 else
1649 clear_bit(B_SESS_VLD, &motg->inputs);
1650 break;
1651 default:
1652 break;
1653 }
1654}
1655
1656static void msm_otg_sm_work(struct work_struct *w)
1657{
1658 struct msm_otg *motg = container_of(w, struct msm_otg, sm_work);
1659 struct otg_transceiver *otg = &motg->otg;
1660
Pavankumar Kondeti8be99cf2011-08-04 10:48:08 +05301661 pm_runtime_resume(otg->dev);
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05301662 switch (otg->state) {
1663 case OTG_STATE_UNDEFINED:
1664 dev_dbg(otg->dev, "OTG_STATE_UNDEFINED state\n");
1665 msm_otg_reset(otg);
1666 msm_otg_init_sm(motg);
1667 otg->state = OTG_STATE_B_IDLE;
Pavankumar Kondeti8a379b42011-12-12 13:07:23 +05301668 if (!test_bit(B_SESS_VLD, &motg->inputs) &&
1669 test_bit(ID, &motg->inputs)) {
1670 pm_runtime_put_noidle(otg->dev);
1671 pm_runtime_suspend(otg->dev);
1672 break;
1673 }
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05301674 /* FALL THROUGH */
1675 case OTG_STATE_B_IDLE:
1676 dev_dbg(otg->dev, "OTG_STATE_B_IDLE state\n");
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001677 if ((!test_bit(ID, &motg->inputs) ||
1678 test_bit(ID_A, &motg->inputs)) && otg->host) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001679 if (motg->chg_type == USB_ACA_DOCK_CHARGER)
1680 msm_otg_notify_charger(motg,
Pavankumar Kondetiaa449e12011-11-04 11:09:26 +05301681 IDEV_ACA_CHG_MAX);
1682 else if (test_bit(ID_A, &motg->inputs))
1683 msm_otg_notify_charger(motg,
1684 IDEV_ACA_CHG_MAX - IUNIT);
1685 else if (motg->pdata->vbus_power)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001686 motg->pdata->vbus_power(1);
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05301687 msm_otg_start_host(otg, 1);
Pavankumar Kondetiaa449e12011-11-04 11:09:26 +05301688 /*
1689 * Link can not generate PHY_ALT interrupt
1690 * in host mode when no device is attached
1691 * to the port. It is also observed PHY_ALT
1692 * interrupt missing upon Micro-A cable disconnect.
1693 * Hence disable PHY_ALT interrupt and perform
1694 * polling to detect RID change.
1695 */
1696 msm_chg_enable_aca_det(motg);
1697 msm_chg_disable_aca_intr(motg);
1698 mod_timer(&motg->id_timer, ID_TIMER_FREQ);
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05301699 otg->state = OTG_STATE_A_HOST;
Pavankumar Kondetid8608522011-05-04 10:19:47 +05301700 } else if (test_bit(B_SESS_VLD, &motg->inputs)) {
1701 switch (motg->chg_state) {
1702 case USB_CHG_STATE_UNDEFINED:
1703 msm_chg_detect_work(&motg->chg_work.work);
1704 break;
1705 case USB_CHG_STATE_DETECTED:
1706 switch (motg->chg_type) {
1707 case USB_DCP_CHARGER:
1708 msm_otg_notify_charger(motg,
1709 IDEV_CHG_MAX);
Pavankumar Kondeti8be99cf2011-08-04 10:48:08 +05301710 pm_runtime_put_noidle(otg->dev);
1711 pm_runtime_suspend(otg->dev);
Pavankumar Kondetid8608522011-05-04 10:19:47 +05301712 break;
Pavankumar Kondetiaa449e12011-11-04 11:09:26 +05301713 case USB_ACA_B_CHARGER:
1714 msm_otg_notify_charger(motg,
1715 IDEV_ACA_CHG_MAX);
1716 /*
1717 * (ID_B --> ID_C) PHY_ALT interrupt can
1718 * not be detected in LPM.
1719 */
1720 break;
Pavankumar Kondetid8608522011-05-04 10:19:47 +05301721 case USB_CDP_CHARGER:
1722 msm_otg_notify_charger(motg,
1723 IDEV_CHG_MAX);
1724 msm_otg_start_peripheral(otg, 1);
1725 otg->state = OTG_STATE_B_PERIPHERAL;
1726 break;
Pavankumar Kondetiaa449e12011-11-04 11:09:26 +05301727 case USB_ACA_C_CHARGER:
1728 msm_otg_notify_charger(motg,
1729 IDEV_ACA_CHG_MAX);
1730 msm_otg_start_peripheral(otg, 1);
1731 otg->state = OTG_STATE_B_PERIPHERAL;
1732 break;
Pavankumar Kondetid8608522011-05-04 10:19:47 +05301733 case USB_SDP_CHARGER:
1734 msm_otg_notify_charger(motg, IUNIT);
1735 msm_otg_start_peripheral(otg, 1);
1736 otg->state = OTG_STATE_B_PERIPHERAL;
1737 break;
1738 default:
1739 break;
1740 }
1741 break;
1742 default:
1743 break;
1744 }
1745 } else {
Pavankumar Kondetiaa449e12011-11-04 11:09:26 +05301746 cancel_delayed_work_sync(&motg->chg_work);
Pavankumar Kondetid8608522011-05-04 10:19:47 +05301747 msm_otg_notify_charger(motg, 0);
1748 motg->chg_state = USB_CHG_STATE_UNDEFINED;
1749 motg->chg_type = USB_INVALID_CHARGER;
Pavankumar Kondetiaa449e12011-11-04 11:09:26 +05301750 msm_otg_reset(otg);
Pavankumar Kondeti8be99cf2011-08-04 10:48:08 +05301751 pm_runtime_put_noidle(otg->dev);
1752 pm_runtime_suspend(otg->dev);
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05301753 }
1754 break;
1755 case OTG_STATE_B_PERIPHERAL:
1756 dev_dbg(otg->dev, "OTG_STATE_B_PERIPHERAL state\n");
1757 if (!test_bit(B_SESS_VLD, &motg->inputs) ||
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001758 !test_bit(ID, &motg->inputs) ||
1759 !test_bit(ID_C, &motg->inputs)) {
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05301760 msm_otg_start_peripheral(otg, 0);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001761 otg->state = OTG_STATE_B_IDLE;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001762 schedule_work(w);
1763 } else if (test_bit(ID_C, &motg->inputs)) {
Pavankumar Kondetiaa449e12011-11-04 11:09:26 +05301764 msm_otg_notify_charger(motg, IDEV_ACA_CHG_MAX);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001765 }
1766 break;
1767 case OTG_STATE_A_HOST:
1768 dev_dbg(otg->dev, "OTG_STATE_A_HOST state\n");
1769 if (test_bit(ID, &motg->inputs) &&
1770 !test_bit(ID_A, &motg->inputs)) {
1771 msm_otg_start_host(otg, 0);
Pavankumar Kondetiaa449e12011-11-04 11:09:26 +05301772 if (motg->pdata->vbus_power) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001773 motg->pdata->vbus_power(0);
Pavankumar Kondetiaa449e12011-11-04 11:09:26 +05301774 msleep(100); /* TA_WAIT_VFALL */
1775 }
1776 /*
1777 * Exit point of host mode.
1778 *
1779 * 1. Micro-A cable disconnect: Just schedule
1780 * the work. PHY is reset in B_IDLE and LPM
1781 * is allowed.
1782 * 2. ID_GND --> ID_B: No need to reset the PHY.
1783 * HCD core clears all PORTSC bits and initializes
1784 * the controller to host mode in remove_hcd.
1785 * Restore PORTSC transceiver select bits (ULPI)
1786 * and reset the controller to change MODE bits.
1787 * PHY_ALT interrupt can not occur in host mode.
1788 */
1789 del_timer_sync(&motg->id_timer);
1790 if (motg->chg_state != USB_CHG_STATE_UNDEFINED) {
1791 msm_otg_link_reset(motg);
1792 msm_chg_enable_aca_intr(motg);
1793 }
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05301794 otg->state = OTG_STATE_B_IDLE;
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05301795 schedule_work(w);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001796 } else if (test_bit(ID_A, &motg->inputs)) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001797 if (motg->pdata->vbus_power)
1798 motg->pdata->vbus_power(0);
1799 msm_otg_notify_charger(motg,
Pavankumar Kondetiaa449e12011-11-04 11:09:26 +05301800 IDEV_ACA_CHG_MAX - motg->mA_port);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001801 } else if (!test_bit(ID, &motg->inputs)) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001802 msm_otg_notify_charger(motg, 0);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001803 if (motg->pdata->vbus_power)
1804 motg->pdata->vbus_power(1);
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05301805 }
1806 break;
1807 default:
1808 break;
1809 }
1810}
1811
1812static irqreturn_t msm_otg_irq(int irq, void *data)
1813{
1814 struct msm_otg *motg = data;
1815 struct otg_transceiver *otg = &motg->otg;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001816 u32 otgsc = 0, usbsts;
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05301817
Pavankumar Kondeti87c01042010-12-07 17:53:58 +05301818 if (atomic_read(&motg->in_lpm)) {
Pavankumar Kondeti4960f312011-12-06 15:46:14 +05301819 pr_debug("OTG IRQ: in LPM\n");
Pavankumar Kondeti87c01042010-12-07 17:53:58 +05301820 disable_irq_nosync(irq);
1821 motg->async_int = 1;
Pavankumar Kondeti8be99cf2011-08-04 10:48:08 +05301822 pm_request_resume(otg->dev);
Pavankumar Kondeti87c01042010-12-07 17:53:58 +05301823 return IRQ_HANDLED;
1824 }
1825
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001826 usbsts = readl(USB_USBSTS);
1827 if ((usbsts & PHY_ALT_INT)) {
Pavankumar Kondetiaa449e12011-11-04 11:09:26 +05301828 dev_dbg(otg->dev, "PHY_ALT interrupt\n");
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001829 writel(PHY_ALT_INT, USB_USBSTS);
Pavankumar Kondetiaa449e12011-11-04 11:09:26 +05301830 if (msm_chg_check_aca_intr(motg)) {
1831 dev_dbg(otg->dev, "ACA work from IRQ\n");
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001832 schedule_work(&motg->sm_work);
Pavankumar Kondetiaa449e12011-11-04 11:09:26 +05301833 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001834 return IRQ_HANDLED;
1835 }
1836
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05301837 otgsc = readl(USB_OTGSC);
1838 if (!(otgsc & (OTGSC_IDIS | OTGSC_BSVIS)))
1839 return IRQ_NONE;
1840
1841 if ((otgsc & OTGSC_IDIS) && (otgsc & OTGSC_IDIE)) {
Pavankumar Kondetiaa449e12011-11-04 11:09:26 +05301842 if (otgsc & OTGSC_ID) {
1843 dev_dbg(otg->dev, "ID set\n");
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05301844 set_bit(ID, &motg->inputs);
Pavankumar Kondetiaa449e12011-11-04 11:09:26 +05301845 } else {
1846 dev_dbg(otg->dev, "ID clear\n");
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05301847 clear_bit(ID, &motg->inputs);
Pavankumar Kondetiaa449e12011-11-04 11:09:26 +05301848 msm_chg_enable_aca_det(motg);
1849 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001850 schedule_work(&motg->sm_work);
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05301851 } else if ((otgsc & OTGSC_BSVIS) && (otgsc & OTGSC_BSVIE)) {
Pavankumar Kondetiaa449e12011-11-04 11:09:26 +05301852 if (otgsc & OTGSC_BSV) {
1853 dev_dbg(otg->dev, "BSV set\n");
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05301854 set_bit(B_SESS_VLD, &motg->inputs);
Pavankumar Kondetiaa449e12011-11-04 11:09:26 +05301855 } else {
1856 dev_dbg(otg->dev, "BSV clear\n");
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05301857 clear_bit(B_SESS_VLD, &motg->inputs);
Pavankumar Kondetiaa449e12011-11-04 11:09:26 +05301858 msm_chg_check_aca_intr(motg);
1859 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001860 schedule_work(&motg->sm_work);
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05301861 }
1862
1863 writel(otgsc, USB_OTGSC);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001864 return IRQ_HANDLED;
1865}
1866
1867static void msm_otg_set_vbus_state(int online)
1868{
Pavankumar Kondeti4960f312011-12-06 15:46:14 +05301869 static bool init;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001870 struct msm_otg *motg = the_msm_otg;
1871
Pavankumar Kondeti4960f312011-12-06 15:46:14 +05301872 if (online) {
1873 pr_debug("PMIC: BSV set\n");
1874 set_bit(B_SESS_VLD, &motg->inputs);
1875 } else {
1876 pr_debug("PMIC: BSV clear\n");
1877 clear_bit(B_SESS_VLD, &motg->inputs);
1878 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001879
Pavankumar Kondeti4960f312011-12-06 15:46:14 +05301880 if (!init) {
1881 init = true;
1882 complete(&pmic_vbus_init);
1883 pr_debug("PMIC: BSV init complete\n");
1884 return;
1885 }
1886
1887 schedule_work(&motg->sm_work);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001888}
1889
1890static irqreturn_t msm_pmic_id_irq(int irq, void *data)
1891{
1892 struct msm_otg *motg = data;
1893
Pavankumar Kondeti4960f312011-12-06 15:46:14 +05301894 if (aca_id_turned_on)
1895 return IRQ_HANDLED;
1896
1897 if (irq_read_line(motg->pdata->pmic_id_irq)) {
1898 pr_debug("PMIC: ID set\n");
1899 set_bit(ID, &motg->inputs);
1900 } else {
1901 pr_debug("PMIC: ID clear\n");
1902 clear_bit(ID, &motg->inputs);
1903 }
1904
1905 if (motg->otg.state != OTG_STATE_UNDEFINED)
1906 schedule_work(&motg->sm_work);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001907
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05301908 return IRQ_HANDLED;
1909}
1910
1911static int msm_otg_mode_show(struct seq_file *s, void *unused)
1912{
1913 struct msm_otg *motg = s->private;
1914 struct otg_transceiver *otg = &motg->otg;
1915
1916 switch (otg->state) {
1917 case OTG_STATE_A_HOST:
1918 seq_printf(s, "host\n");
1919 break;
1920 case OTG_STATE_B_PERIPHERAL:
1921 seq_printf(s, "peripheral\n");
1922 break;
1923 default:
1924 seq_printf(s, "none\n");
1925 break;
1926 }
1927
1928 return 0;
1929}
1930
1931static int msm_otg_mode_open(struct inode *inode, struct file *file)
1932{
1933 return single_open(file, msm_otg_mode_show, inode->i_private);
1934}
1935
1936static ssize_t msm_otg_mode_write(struct file *file, const char __user *ubuf,
1937 size_t count, loff_t *ppos)
1938{
Pavankumar Kondetie2904ee2011-02-15 09:42:35 +05301939 struct seq_file *s = file->private_data;
1940 struct msm_otg *motg = s->private;
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05301941 char buf[16];
1942 struct otg_transceiver *otg = &motg->otg;
1943 int status = count;
1944 enum usb_mode_type req_mode;
1945
1946 memset(buf, 0x00, sizeof(buf));
1947
1948 if (copy_from_user(&buf, ubuf, min_t(size_t, sizeof(buf) - 1, count))) {
1949 status = -EFAULT;
1950 goto out;
1951 }
1952
1953 if (!strncmp(buf, "host", 4)) {
1954 req_mode = USB_HOST;
1955 } else if (!strncmp(buf, "peripheral", 10)) {
1956 req_mode = USB_PERIPHERAL;
1957 } else if (!strncmp(buf, "none", 4)) {
1958 req_mode = USB_NONE;
1959 } else {
1960 status = -EINVAL;
1961 goto out;
1962 }
1963
1964 switch (req_mode) {
1965 case USB_NONE:
1966 switch (otg->state) {
1967 case OTG_STATE_A_HOST:
1968 case OTG_STATE_B_PERIPHERAL:
1969 set_bit(ID, &motg->inputs);
1970 clear_bit(B_SESS_VLD, &motg->inputs);
1971 break;
1972 default:
1973 goto out;
1974 }
1975 break;
1976 case USB_PERIPHERAL:
1977 switch (otg->state) {
1978 case OTG_STATE_B_IDLE:
1979 case OTG_STATE_A_HOST:
1980 set_bit(ID, &motg->inputs);
1981 set_bit(B_SESS_VLD, &motg->inputs);
1982 break;
1983 default:
1984 goto out;
1985 }
1986 break;
1987 case USB_HOST:
1988 switch (otg->state) {
1989 case OTG_STATE_B_IDLE:
1990 case OTG_STATE_B_PERIPHERAL:
1991 clear_bit(ID, &motg->inputs);
1992 break;
1993 default:
1994 goto out;
1995 }
1996 break;
1997 default:
1998 goto out;
1999 }
2000
Pavankumar Kondeti8be99cf2011-08-04 10:48:08 +05302001 pm_runtime_resume(otg->dev);
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05302002 schedule_work(&motg->sm_work);
2003out:
2004 return status;
2005}
2006
2007const struct file_operations msm_otg_mode_fops = {
2008 .open = msm_otg_mode_open,
2009 .read = seq_read,
2010 .write = msm_otg_mode_write,
2011 .llseek = seq_lseek,
2012 .release = single_release,
2013};
2014
Anji jonnalad270e2d2011-08-09 11:28:32 +05302015static int msm_otg_show_chg_type(struct seq_file *s, void *unused)
2016{
2017 struct msm_otg *motg = s->private;
2018
Pavankumar Kondeti9ef69cb2011-12-12 14:18:22 +05302019 seq_printf(s, "%s\n", chg_to_string(motg->chg_type));
Anji jonnalad270e2d2011-08-09 11:28:32 +05302020 return 0;
2021}
2022
2023static int msm_otg_chg_open(struct inode *inode, struct file *file)
2024{
2025 return single_open(file, msm_otg_show_chg_type, inode->i_private);
2026}
2027
2028const struct file_operations msm_otg_chg_fops = {
2029 .open = msm_otg_chg_open,
2030 .read = seq_read,
2031 .llseek = seq_lseek,
2032 .release = single_release,
2033};
2034
Pavankumar Kondetiaa449e12011-11-04 11:09:26 +05302035static int msm_otg_aca_show(struct seq_file *s, void *unused)
2036{
2037 if (debug_aca_enabled)
2038 seq_printf(s, "enabled\n");
2039 else
2040 seq_printf(s, "disabled\n");
2041
2042 return 0;
2043}
2044
2045static int msm_otg_aca_open(struct inode *inode, struct file *file)
2046{
2047 return single_open(file, msm_otg_aca_show, inode->i_private);
2048}
2049
2050static ssize_t msm_otg_aca_write(struct file *file, const char __user *ubuf,
2051 size_t count, loff_t *ppos)
2052{
2053 char buf[8];
2054
2055 memset(buf, 0x00, sizeof(buf));
2056
2057 if (copy_from_user(&buf, ubuf, min_t(size_t, sizeof(buf) - 1, count)))
2058 return -EFAULT;
2059
2060 if (!strncmp(buf, "enable", 6))
2061 debug_aca_enabled = true;
2062 else
2063 debug_aca_enabled = false;
2064
2065 return count;
2066}
2067
2068const struct file_operations msm_otg_aca_fops = {
2069 .open = msm_otg_aca_open,
2070 .read = seq_read,
2071 .write = msm_otg_aca_write,
2072 .llseek = seq_lseek,
2073 .release = single_release,
2074};
2075
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05302076static struct dentry *msm_otg_dbg_root;
2077static struct dentry *msm_otg_dbg_mode;
Anji jonnalad270e2d2011-08-09 11:28:32 +05302078static struct dentry *msm_otg_chg_type;
Pavankumar Kondetiaa449e12011-11-04 11:09:26 +05302079static struct dentry *msm_otg_dbg_aca;
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05302080
2081static int msm_otg_debugfs_init(struct msm_otg *motg)
2082{
Anji jonnalad270e2d2011-08-09 11:28:32 +05302083
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05302084 msm_otg_dbg_root = debugfs_create_dir("msm_otg", NULL);
2085
2086 if (!msm_otg_dbg_root || IS_ERR(msm_otg_dbg_root))
2087 return -ENODEV;
2088
Anji jonnalad270e2d2011-08-09 11:28:32 +05302089 if (motg->pdata->mode == USB_OTG &&
2090 motg->pdata->otg_control == OTG_USER_CONTROL) {
2091
2092 msm_otg_dbg_mode = debugfs_create_file("mode", S_IRUGO |
2093 S_IWUSR, msm_otg_dbg_root, motg,
2094 &msm_otg_mode_fops);
2095
2096 if (!msm_otg_dbg_mode) {
2097 debugfs_remove(msm_otg_dbg_root);
2098 msm_otg_dbg_root = NULL;
2099 return -ENODEV;
2100 }
2101 }
2102
2103 msm_otg_chg_type = debugfs_create_file("chg_type", S_IRUGO,
2104 msm_otg_dbg_root, motg,
2105 &msm_otg_chg_fops);
2106
2107 if (!msm_otg_chg_type) {
Pavankumar Kondetiaa449e12011-11-04 11:09:26 +05302108 debugfs_remove_recursive(msm_otg_dbg_root);
2109 return -ENODEV;
2110 }
2111
2112 msm_otg_dbg_aca = debugfs_create_file("aca", S_IRUGO | S_IWUSR,
2113 msm_otg_dbg_root, motg,
2114 &msm_otg_aca_fops);
2115
2116 if (!msm_otg_dbg_aca) {
2117 debugfs_remove_recursive(msm_otg_dbg_root);
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05302118 return -ENODEV;
2119 }
2120
2121 return 0;
2122}
2123
2124static void msm_otg_debugfs_cleanup(void)
2125{
Anji jonnalad270e2d2011-08-09 11:28:32 +05302126 debugfs_remove_recursive(msm_otg_dbg_root);
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05302127}
2128
Pavankumar Kondetieaea7fe2011-10-27 14:46:45 +05302129static u64 msm_otg_dma_mask = DMA_BIT_MASK(64);
2130static struct platform_device *msm_otg_add_pdev(
2131 struct platform_device *ofdev, const char *name)
2132{
2133 struct platform_device *pdev;
2134 const struct resource *res = ofdev->resource;
2135 unsigned int num = ofdev->num_resources;
2136 int retval;
2137
2138 pdev = platform_device_alloc(name, -1);
2139 if (!pdev) {
2140 retval = -ENOMEM;
2141 goto error;
2142 }
2143
2144 pdev->dev.coherent_dma_mask = DMA_BIT_MASK(32);
2145 pdev->dev.dma_mask = &msm_otg_dma_mask;
2146
2147 if (num) {
2148 retval = platform_device_add_resources(pdev, res, num);
2149 if (retval)
2150 goto error;
2151 }
2152
2153 retval = platform_device_add(pdev);
2154 if (retval)
2155 goto error;
2156
2157 return pdev;
2158
2159error:
2160 platform_device_put(pdev);
2161 return ERR_PTR(retval);
2162}
2163
2164static int msm_otg_setup_devices(struct platform_device *ofdev,
2165 enum usb_mode_type mode, bool init)
2166{
2167 const char *gadget_name = "msm_hsusb";
2168 const char *host_name = "msm_hsusb_host";
2169 static struct platform_device *gadget_pdev;
2170 static struct platform_device *host_pdev;
2171 int retval = 0;
2172
2173 if (!init) {
2174 if (gadget_pdev)
2175 platform_device_unregister(gadget_pdev);
2176 if (host_pdev)
2177 platform_device_unregister(host_pdev);
2178 return 0;
2179 }
2180
2181 switch (mode) {
2182 case USB_OTG:
2183 /* fall through */
2184 case USB_PERIPHERAL:
2185 gadget_pdev = msm_otg_add_pdev(ofdev, gadget_name);
2186 if (IS_ERR(gadget_pdev)) {
2187 retval = PTR_ERR(gadget_pdev);
2188 break;
2189 }
2190 if (mode == USB_PERIPHERAL)
2191 break;
2192 /* fall through */
2193 case USB_HOST:
2194 host_pdev = msm_otg_add_pdev(ofdev, host_name);
2195 if (IS_ERR(host_pdev)) {
2196 retval = PTR_ERR(host_pdev);
2197 if (mode == USB_OTG)
2198 platform_device_unregister(gadget_pdev);
2199 }
2200 break;
2201 default:
2202 break;
2203 }
2204
2205 return retval;
2206}
2207
2208struct msm_otg_platform_data *msm_otg_dt_to_pdata(struct platform_device *pdev)
2209{
2210 struct device_node *node = pdev->dev.of_node;
2211 struct msm_otg_platform_data *pdata;
2212 int len = 0;
2213
2214 pdata = devm_kzalloc(&pdev->dev, sizeof(*pdata), GFP_KERNEL);
2215 if (!pdata) {
2216 pr_err("unable to allocate platform data\n");
2217 return NULL;
2218 }
2219 of_get_property(node, "qcom,hsusb-otg-phy-init-seq", &len);
2220 if (len) {
2221 pdata->phy_init_seq = devm_kzalloc(&pdev->dev, len, GFP_KERNEL);
2222 if (!pdata->phy_init_seq)
2223 return NULL;
2224 of_property_read_u32_array(node, "qcom,hsusb-otg-phy-init-seq",
2225 pdata->phy_init_seq,
2226 len/sizeof(*pdata->phy_init_seq));
2227 }
2228 of_property_read_u32(node, "qcom,hsusb-otg-power-budget",
2229 &pdata->power_budget);
2230 of_property_read_u32(node, "qcom,hsusb-otg-mode",
2231 &pdata->mode);
2232 of_property_read_u32(node, "qcom,hsusb-otg-otg-control",
2233 &pdata->otg_control);
2234 of_property_read_u32(node, "qcom,hsusb-otg-default-mode",
2235 &pdata->default_mode);
2236 of_property_read_u32(node, "qcom,hsusb-otg-phy-type",
2237 &pdata->phy_type);
2238 of_property_read_u32(node, "qcom,hsusb-otg-pmic-id-irq",
2239 &pdata->pmic_id_irq);
2240 of_property_read_string(node, "qcom,hsusb-otg-pclk-src-name",
2241 &pdata->pclk_src_name);
2242 return pdata;
2243}
2244
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05302245static int __init msm_otg_probe(struct platform_device *pdev)
2246{
2247 int ret = 0;
2248 struct resource *res;
2249 struct msm_otg *motg;
2250 struct otg_transceiver *otg;
Pavankumar Kondetieaea7fe2011-10-27 14:46:45 +05302251 struct msm_otg_platform_data *pdata;
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05302252
2253 dev_info(&pdev->dev, "msm_otg probe\n");
Pavankumar Kondetieaea7fe2011-10-27 14:46:45 +05302254
2255 if (pdev->dev.of_node) {
2256 dev_dbg(&pdev->dev, "device tree enabled\n");
2257 pdata = msm_otg_dt_to_pdata(pdev);
2258 if (!pdata)
2259 return -ENOMEM;
2260 ret = msm_otg_setup_devices(pdev, pdata->mode, true);
2261 if (ret) {
2262 dev_err(&pdev->dev, "devices setup failed\n");
2263 return ret;
2264 }
2265 } else if (!pdev->dev.platform_data) {
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05302266 dev_err(&pdev->dev, "No platform data given. Bailing out\n");
2267 return -ENODEV;
Pavankumar Kondetieaea7fe2011-10-27 14:46:45 +05302268 } else {
2269 pdata = pdev->dev.platform_data;
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05302270 }
2271
2272 motg = kzalloc(sizeof(struct msm_otg), GFP_KERNEL);
2273 if (!motg) {
2274 dev_err(&pdev->dev, "unable to allocate msm_otg\n");
2275 return -ENOMEM;
2276 }
2277
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002278 the_msm_otg = motg;
Pavankumar Kondetieaea7fe2011-10-27 14:46:45 +05302279 motg->pdata = pdata;
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05302280 otg = &motg->otg;
2281 otg->dev = &pdev->dev;
2282
Pavankumar Kondetiaa449e12011-11-04 11:09:26 +05302283 /*
2284 * ACA ID_GND threshold range is overlapped with OTG ID_FLOAT. Hence
2285 * PHY treat ACA ID_GND as float and no interrupt is generated. But
2286 * PMIC can detect ACA ID_GND and generate an interrupt.
2287 */
2288 if (aca_enabled() && motg->pdata->otg_control != OTG_PMIC_CONTROL) {
2289 dev_err(&pdev->dev, "ACA can not be enabled without PMIC\n");
2290 ret = -EINVAL;
2291 goto free_motg;
2292 }
2293
Amit Blay02eff132011-09-21 16:46:24 +03002294 /* Some targets don't support PHY clock. */
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05302295 motg->phy_reset_clk = clk_get(&pdev->dev, "usb_phy_clk");
Amit Blay02eff132011-09-21 16:46:24 +03002296 if (IS_ERR(motg->phy_reset_clk))
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05302297 dev_err(&pdev->dev, "failed to get usb_phy_clk\n");
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05302298
2299 motg->clk = clk_get(&pdev->dev, "usb_hs_clk");
2300 if (IS_ERR(motg->clk)) {
2301 dev_err(&pdev->dev, "failed to get usb_hs_clk\n");
2302 ret = PTR_ERR(motg->clk);
2303 goto put_phy_reset_clk;
2304 }
Anji jonnala0f73cac2011-05-04 10:19:46 +05302305 clk_set_rate(motg->clk, 60000000);
2306
Anji jonnalaa7c1c5c2011-12-12 12:20:36 +05302307 /* pm qos request to prevent apps idle power collapse */
2308 if (motg->pdata->swfi_latency)
2309 pm_qos_add_request(&motg->pm_qos_req_dma,
2310 PM_QOS_CPU_DMA_LATENCY, PM_QOS_DEFAULT_VALUE);
Anji jonnala0f73cac2011-05-04 10:19:46 +05302311 /*
2312 * If USB Core is running its protocol engine based on CORE CLK,
2313 * CORE CLK must be running at >55Mhz for correct HSUSB
2314 * operation and USB core cannot tolerate frequency changes on
2315 * CORE CLK. For such USB cores, vote for maximum clk frequency
2316 * on pclk source
2317 */
2318 if (motg->pdata->pclk_src_name) {
2319 motg->pclk_src = clk_get(&pdev->dev,
2320 motg->pdata->pclk_src_name);
2321 if (IS_ERR(motg->pclk_src))
2322 goto put_clk;
2323 clk_set_rate(motg->pclk_src, INT_MAX);
2324 clk_enable(motg->pclk_src);
2325 } else
2326 motg->pclk_src = ERR_PTR(-ENOENT);
2327
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05302328 motg->pclk = clk_get(&pdev->dev, "usb_hs_pclk");
2329 if (IS_ERR(motg->pclk)) {
2330 dev_err(&pdev->dev, "failed to get usb_hs_pclk\n");
2331 ret = PTR_ERR(motg->pclk);
Anji jonnala0f73cac2011-05-04 10:19:46 +05302332 goto put_pclk_src;
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05302333 }
2334
Amit Blay02eff132011-09-21 16:46:24 +03002335 motg->system_clk = clk_get(&pdev->dev, "usb_hs_system_clk");
2336 if (!IS_ERR(motg->system_clk))
2337 clk_enable(motg->system_clk);
2338
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05302339 /*
2340 * USB core clock is not present on all MSM chips. This
2341 * clock is introduced to remove the dependency on AXI
2342 * bus frequency.
2343 */
2344 motg->core_clk = clk_get(&pdev->dev, "usb_hs_core_clk");
2345 if (IS_ERR(motg->core_clk))
2346 motg->core_clk = NULL;
2347
2348 res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
2349 if (!res) {
2350 dev_err(&pdev->dev, "failed to get platform resource mem\n");
2351 ret = -ENODEV;
2352 goto put_core_clk;
2353 }
2354
2355 motg->regs = ioremap(res->start, resource_size(res));
2356 if (!motg->regs) {
2357 dev_err(&pdev->dev, "ioremap failed\n");
2358 ret = -ENOMEM;
2359 goto put_core_clk;
2360 }
2361 dev_info(&pdev->dev, "OTG regs = %p\n", motg->regs);
2362
2363 motg->irq = platform_get_irq(pdev, 0);
2364 if (!motg->irq) {
2365 dev_err(&pdev->dev, "platform_get_irq failed\n");
2366 ret = -ENODEV;
2367 goto free_regs;
2368 }
2369
Anji jonnala7da3f262011-12-02 17:22:14 -08002370 motg->xo_handle = msm_xo_get(MSM_XO_TCXO_D0, "usb");
2371 if (IS_ERR(motg->xo_handle)) {
2372 dev_err(&pdev->dev, "%s not able to get the handle "
2373 "to vote for TCXO D0 buffer\n", __func__);
2374 ret = PTR_ERR(motg->xo_handle);
2375 goto free_regs;
2376 }
2377
2378 ret = msm_xo_mode_vote(motg->xo_handle, MSM_XO_MODE_ON);
2379 if (ret) {
2380 dev_err(&pdev->dev, "%s failed to vote for TCXO "
2381 "D0 buffer%d\n", __func__, ret);
2382 goto free_xo_handle;
2383 }
2384
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05302385 clk_enable(motg->pclk);
Anji jonnala11aa5c42011-05-04 10:19:48 +05302386
2387 ret = msm_hsusb_init_vddcx(motg, 1);
2388 if (ret) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002389 dev_err(&pdev->dev, "hsusb vddcx init failed\n");
Anji jonnala7da3f262011-12-02 17:22:14 -08002390 goto devote_xo_handle;
Anji jonnala11aa5c42011-05-04 10:19:48 +05302391 }
2392
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002393 ret = msm_hsusb_config_vddcx(1);
2394 if (ret) {
2395 dev_err(&pdev->dev, "hsusb vddcx configuration failed\n");
2396 goto free_init_vddcx;
2397 }
2398
Anji jonnala11aa5c42011-05-04 10:19:48 +05302399 ret = msm_hsusb_ldo_init(motg, 1);
2400 if (ret) {
2401 dev_err(&pdev->dev, "hsusb vreg configuration failed\n");
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002402 goto free_init_vddcx;
Anji jonnala11aa5c42011-05-04 10:19:48 +05302403 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002404
2405 ret = msm_hsusb_ldo_enable(motg, 1);
Anji jonnala11aa5c42011-05-04 10:19:48 +05302406 if (ret) {
2407 dev_err(&pdev->dev, "hsusb vreg enable failed\n");
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002408 goto free_ldo_init;
Anji jonnala11aa5c42011-05-04 10:19:48 +05302409 }
2410
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05302411 if (motg->core_clk)
2412 clk_enable(motg->core_clk);
2413
2414 writel(0, USB_USBINTR);
2415 writel(0, USB_OTGSC);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002416 /* Ensure that above STOREs are completed before enabling interrupts */
2417 mb();
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05302418
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002419 wake_lock_init(&motg->wlock, WAKE_LOCK_SUSPEND, "msm_otg");
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05302420 INIT_WORK(&motg->sm_work, msm_otg_sm_work);
Pavankumar Kondetid8608522011-05-04 10:19:47 +05302421 INIT_DELAYED_WORK(&motg->chg_work, msm_chg_detect_work);
Pavankumar Kondetiaa449e12011-11-04 11:09:26 +05302422 setup_timer(&motg->id_timer, msm_otg_id_timer_func,
2423 (unsigned long) motg);
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05302424 ret = request_irq(motg->irq, msm_otg_irq, IRQF_SHARED,
2425 "msm_otg", motg);
2426 if (ret) {
2427 dev_err(&pdev->dev, "request irq failed\n");
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002428 goto destroy_wlock;
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05302429 }
2430
2431 otg->init = msm_otg_reset;
2432 otg->set_host = msm_otg_set_host;
2433 otg->set_peripheral = msm_otg_set_peripheral;
Pavankumar Kondetid8608522011-05-04 10:19:47 +05302434 otg->set_power = msm_otg_set_power;
Pavankumar Kondeti8be99cf2011-08-04 10:48:08 +05302435 otg->set_suspend = msm_otg_set_suspend;
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05302436
2437 otg->io_ops = &msm_otg_io_ops;
2438
2439 ret = otg_set_transceiver(&motg->otg);
2440 if (ret) {
2441 dev_err(&pdev->dev, "otg_set_transceiver failed\n");
2442 goto free_irq;
2443 }
2444
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002445 if (motg->pdata->otg_control == OTG_PMIC_CONTROL) {
2446 if (motg->pdata->pmic_id_irq) {
2447 ret = request_irq(motg->pdata->pmic_id_irq,
2448 msm_pmic_id_irq,
2449 IRQF_TRIGGER_RISING |
2450 IRQF_TRIGGER_FALLING,
2451 "msm_otg", motg);
2452 if (ret) {
2453 dev_err(&pdev->dev, "request irq failed for PMIC ID\n");
2454 goto remove_otg;
2455 }
2456 } else {
2457 ret = -ENODEV;
2458 dev_err(&pdev->dev, "PMIC IRQ for ID notifications doesn't exist\n");
2459 goto remove_otg;
2460 }
2461 }
2462
Vijayavardhan Vennapusafc464f02011-11-04 21:54:00 +05302463 msm_hsusb_mhl_switch_enable(motg, 1);
2464
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05302465 platform_set_drvdata(pdev, motg);
2466 device_init_wakeup(&pdev->dev, 1);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002467 motg->mA_port = IUNIT;
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05302468
Anji jonnalad270e2d2011-08-09 11:28:32 +05302469 ret = msm_otg_debugfs_init(motg);
2470 if (ret)
2471 dev_dbg(&pdev->dev, "mode debugfs file is"
2472 "not available\n");
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05302473
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002474 if (motg->pdata->otg_control == OTG_PMIC_CONTROL)
2475 pm8921_charger_register_vbus_sn(&msm_otg_set_vbus_state);
2476
Amit Blay58b31472011-11-18 09:39:39 +02002477 if (motg->pdata->phy_type == SNPS_28NM_INTEGRATED_PHY) {
2478 if (motg->pdata->otg_control == OTG_PMIC_CONTROL &&
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002479 motg->pdata->pmic_id_irq)
Amit Blay58b31472011-11-18 09:39:39 +02002480 motg->caps = ALLOW_PHY_POWER_COLLAPSE |
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002481 ALLOW_PHY_RETENTION |
2482 ALLOW_PHY_COMP_DISABLE;
2483
Amit Blay58b31472011-11-18 09:39:39 +02002484 if (motg->pdata->otg_control == OTG_PHY_CONTROL)
2485 motg->caps = ALLOW_PHY_RETENTION;
2486 }
2487
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002488 wake_lock(&motg->wlock);
Pavankumar Kondeti87c01042010-12-07 17:53:58 +05302489 pm_runtime_set_active(&pdev->dev);
2490 pm_runtime_enable(&pdev->dev);
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05302491
Pavankumar Kondeti87c01042010-12-07 17:53:58 +05302492 return 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002493
2494remove_otg:
2495 otg_set_transceiver(NULL);
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05302496free_irq:
2497 free_irq(motg->irq, motg);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002498destroy_wlock:
2499 wake_lock_destroy(&motg->wlock);
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05302500 clk_disable(motg->pclk);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002501 msm_hsusb_ldo_enable(motg, 0);
2502free_ldo_init:
Anji jonnala11aa5c42011-05-04 10:19:48 +05302503 msm_hsusb_ldo_init(motg, 0);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002504free_init_vddcx:
Anji jonnala11aa5c42011-05-04 10:19:48 +05302505 msm_hsusb_init_vddcx(motg, 0);
Anji jonnala7da3f262011-12-02 17:22:14 -08002506devote_xo_handle:
2507 msm_xo_mode_vote(motg->xo_handle, MSM_XO_MODE_OFF);
2508free_xo_handle:
2509 msm_xo_put(motg->xo_handle);
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05302510free_regs:
2511 iounmap(motg->regs);
2512put_core_clk:
2513 if (motg->core_clk)
2514 clk_put(motg->core_clk);
Amit Blay02eff132011-09-21 16:46:24 +03002515
2516 if (!IS_ERR(motg->system_clk)) {
2517 clk_disable(motg->system_clk);
2518 clk_put(motg->system_clk);
2519 }
Anji jonnala0f73cac2011-05-04 10:19:46 +05302520put_pclk_src:
2521 if (!IS_ERR(motg->pclk_src)) {
2522 clk_disable(motg->pclk_src);
2523 clk_put(motg->pclk_src);
2524 }
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05302525put_clk:
2526 clk_put(motg->clk);
2527put_phy_reset_clk:
Amit Blay02eff132011-09-21 16:46:24 +03002528 if (!IS_ERR(motg->phy_reset_clk))
2529 clk_put(motg->phy_reset_clk);
Pavankumar Kondetiaa449e12011-11-04 11:09:26 +05302530free_motg:
Anji jonnalaa7c1c5c2011-12-12 12:20:36 +05302531 if (motg->pdata->swfi_latency)
2532 pm_qos_remove_request(&motg->pm_qos_req_dma);
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05302533 kfree(motg);
2534 return ret;
2535}
2536
2537static int __devexit msm_otg_remove(struct platform_device *pdev)
2538{
2539 struct msm_otg *motg = platform_get_drvdata(pdev);
2540 struct otg_transceiver *otg = &motg->otg;
Pavankumar Kondeti87c01042010-12-07 17:53:58 +05302541 int cnt = 0;
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05302542
2543 if (otg->host || otg->gadget)
2544 return -EBUSY;
2545
Pavankumar Kondetieaea7fe2011-10-27 14:46:45 +05302546 if (pdev->dev.of_node)
2547 msm_otg_setup_devices(pdev, motg->pdata->mode, false);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002548 if (motg->pdata->otg_control == OTG_PMIC_CONTROL)
2549 pm8921_charger_unregister_vbus_sn(0);
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05302550 msm_otg_debugfs_cleanup();
Pavankumar Kondetid8608522011-05-04 10:19:47 +05302551 cancel_delayed_work_sync(&motg->chg_work);
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05302552 cancel_work_sync(&motg->sm_work);
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05302553
Pavankumar Kondeti70187732011-02-15 09:42:34 +05302554 pm_runtime_resume(&pdev->dev);
Pavankumar Kondeti87c01042010-12-07 17:53:58 +05302555
2556 device_init_wakeup(&pdev->dev, 0);
2557 pm_runtime_disable(&pdev->dev);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002558 wake_lock_destroy(&motg->wlock);
Pavankumar Kondeti87c01042010-12-07 17:53:58 +05302559
Vijayavardhan Vennapusafc464f02011-11-04 21:54:00 +05302560 msm_hsusb_mhl_switch_enable(motg, 0);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002561 if (motg->pdata->pmic_id_irq)
2562 free_irq(motg->pdata->pmic_id_irq, motg);
Pavankumar Kondeti87c01042010-12-07 17:53:58 +05302563 otg_set_transceiver(NULL);
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05302564 free_irq(motg->irq, motg);
2565
Pavankumar Kondeti87c01042010-12-07 17:53:58 +05302566 /*
2567 * Put PHY in low power mode.
2568 */
2569 ulpi_read(otg, 0x14);
2570 ulpi_write(otg, 0x08, 0x09);
2571
2572 writel(readl(USB_PORTSC) | PORTSC_PHCD, USB_PORTSC);
2573 while (cnt < PHY_SUSPEND_TIMEOUT_USEC) {
2574 if (readl(USB_PORTSC) & PORTSC_PHCD)
2575 break;
2576 udelay(1);
2577 cnt++;
2578 }
2579 if (cnt >= PHY_SUSPEND_TIMEOUT_USEC)
2580 dev_err(otg->dev, "Unable to suspend PHY\n");
2581
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05302582 clk_disable(motg->pclk);
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05302583 if (motg->core_clk)
2584 clk_disable(motg->core_clk);
Amit Blay137575f2011-11-06 15:20:54 +02002585 if (!IS_ERR(motg->system_clk))
2586 clk_disable(motg->system_clk);
Anji jonnala0f73cac2011-05-04 10:19:46 +05302587 if (!IS_ERR(motg->pclk_src)) {
2588 clk_disable(motg->pclk_src);
2589 clk_put(motg->pclk_src);
2590 }
Anji jonnala7da3f262011-12-02 17:22:14 -08002591 msm_xo_put(motg->xo_handle);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002592 msm_hsusb_ldo_enable(motg, 0);
Anji jonnala11aa5c42011-05-04 10:19:48 +05302593 msm_hsusb_ldo_init(motg, 0);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002594 msm_hsusb_init_vddcx(motg, 0);
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05302595
2596 iounmap(motg->regs);
Pavankumar Kondeti87c01042010-12-07 17:53:58 +05302597 pm_runtime_set_suspended(&pdev->dev);
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05302598
Amit Blay02eff132011-09-21 16:46:24 +03002599 if (!IS_ERR(motg->phy_reset_clk))
2600 clk_put(motg->phy_reset_clk);
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05302601 clk_put(motg->pclk);
2602 clk_put(motg->clk);
2603 if (motg->core_clk)
2604 clk_put(motg->core_clk);
Amit Blay02eff132011-09-21 16:46:24 +03002605 if (!IS_ERR(motg->system_clk))
2606 clk_put(motg->system_clk);
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05302607
Anji jonnalaa7c1c5c2011-12-12 12:20:36 +05302608 if (motg->pdata->swfi_latency)
2609 pm_qos_remove_request(&motg->pm_qos_req_dma);
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05302610
Anji jonnalaa7c1c5c2011-12-12 12:20:36 +05302611 kfree(motg);
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05302612 return 0;
2613}
2614
Pavankumar Kondeti87c01042010-12-07 17:53:58 +05302615#ifdef CONFIG_PM_RUNTIME
2616static int msm_otg_runtime_idle(struct device *dev)
2617{
2618 struct msm_otg *motg = dev_get_drvdata(dev);
2619 struct otg_transceiver *otg = &motg->otg;
2620
2621 dev_dbg(dev, "OTG runtime idle\n");
2622
Pavankumar Kondeti8be99cf2011-08-04 10:48:08 +05302623 if (otg->state == OTG_STATE_UNDEFINED)
2624 return -EAGAIN;
2625 else
2626 return 0;
Pavankumar Kondeti87c01042010-12-07 17:53:58 +05302627}
2628
2629static int msm_otg_runtime_suspend(struct device *dev)
2630{
2631 struct msm_otg *motg = dev_get_drvdata(dev);
2632
2633 dev_dbg(dev, "OTG runtime suspend\n");
2634 return msm_otg_suspend(motg);
2635}
2636
2637static int msm_otg_runtime_resume(struct device *dev)
2638{
2639 struct msm_otg *motg = dev_get_drvdata(dev);
2640
2641 dev_dbg(dev, "OTG runtime resume\n");
Pavankumar Kondeti8be99cf2011-08-04 10:48:08 +05302642 pm_runtime_get_noresume(dev);
Pavankumar Kondeti87c01042010-12-07 17:53:58 +05302643 return msm_otg_resume(motg);
2644}
Pavankumar Kondeti87c01042010-12-07 17:53:58 +05302645#endif
2646
Pavankumar Kondeti70187732011-02-15 09:42:34 +05302647#ifdef CONFIG_PM_SLEEP
Pavankumar Kondeti87c01042010-12-07 17:53:58 +05302648static int msm_otg_pm_suspend(struct device *dev)
2649{
Pavankumar Kondeti8be99cf2011-08-04 10:48:08 +05302650 int ret;
Pavankumar Kondeti87c01042010-12-07 17:53:58 +05302651
2652 dev_dbg(dev, "OTG PM suspend\n");
Pavankumar Kondeti8be99cf2011-08-04 10:48:08 +05302653
2654#ifdef CONFIG_PM_RUNTIME
2655 ret = pm_runtime_suspend(dev);
2656 if (ret > 0)
2657 ret = 0;
2658#else
2659 ret = msm_otg_suspend(dev_get_drvdata(dev));
2660#endif
2661 return ret;
Pavankumar Kondeti87c01042010-12-07 17:53:58 +05302662}
2663
2664static int msm_otg_pm_resume(struct device *dev)
2665{
2666 struct msm_otg *motg = dev_get_drvdata(dev);
Pavankumar Kondeti87c01042010-12-07 17:53:58 +05302667
2668 dev_dbg(dev, "OTG PM resume\n");
2669
Manu Gautamf284c052011-09-08 16:52:48 +05302670#ifdef CONFIG_PM_RUNTIME
Pavankumar Kondeti87c01042010-12-07 17:53:58 +05302671 /*
Manu Gautamf284c052011-09-08 16:52:48 +05302672 * Do not resume hardware as part of system resume,
2673 * rather, wait for the ASYNC INT from the h/w
Pavankumar Kondeti87c01042010-12-07 17:53:58 +05302674 */
Gregory Beanebd8ca22011-10-11 12:02:35 -07002675 return 0;
Manu Gautamf284c052011-09-08 16:52:48 +05302676#endif
Pavankumar Kondeti87c01042010-12-07 17:53:58 +05302677
Manu Gautamf284c052011-09-08 16:52:48 +05302678 return msm_otg_resume(motg);
Pavankumar Kondeti87c01042010-12-07 17:53:58 +05302679}
Pavankumar Kondeti87c01042010-12-07 17:53:58 +05302680#endif
2681
Pavankumar Kondeti70187732011-02-15 09:42:34 +05302682#ifdef CONFIG_PM
Pavankumar Kondeti87c01042010-12-07 17:53:58 +05302683static const struct dev_pm_ops msm_otg_dev_pm_ops = {
Pavankumar Kondeti70187732011-02-15 09:42:34 +05302684 SET_SYSTEM_SLEEP_PM_OPS(msm_otg_pm_suspend, msm_otg_pm_resume)
2685 SET_RUNTIME_PM_OPS(msm_otg_runtime_suspend, msm_otg_runtime_resume,
2686 msm_otg_runtime_idle)
Pavankumar Kondeti87c01042010-12-07 17:53:58 +05302687};
Pavankumar Kondeti70187732011-02-15 09:42:34 +05302688#endif
Pavankumar Kondeti87c01042010-12-07 17:53:58 +05302689
Pavankumar Kondetieaea7fe2011-10-27 14:46:45 +05302690static struct of_device_id msm_otg_dt_match[] = {
2691 { .compatible = "qcom,hsusb-otg",
2692 },
2693 {}
2694};
2695
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05302696static struct platform_driver msm_otg_driver = {
2697 .remove = __devexit_p(msm_otg_remove),
2698 .driver = {
2699 .name = DRIVER_NAME,
2700 .owner = THIS_MODULE,
Pavankumar Kondeti70187732011-02-15 09:42:34 +05302701#ifdef CONFIG_PM
Pavankumar Kondeti87c01042010-12-07 17:53:58 +05302702 .pm = &msm_otg_dev_pm_ops,
Pavankumar Kondeti70187732011-02-15 09:42:34 +05302703#endif
Pavankumar Kondetieaea7fe2011-10-27 14:46:45 +05302704 .of_match_table = msm_otg_dt_match,
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05302705 },
2706};
2707
2708static int __init msm_otg_init(void)
2709{
2710 return platform_driver_probe(&msm_otg_driver, msm_otg_probe);
2711}
2712
2713static void __exit msm_otg_exit(void)
2714{
2715 platform_driver_unregister(&msm_otg_driver);
2716}
2717
2718module_init(msm_otg_init);
2719module_exit(msm_otg_exit);
2720
2721MODULE_LICENSE("GPL v2");
2722MODULE_DESCRIPTION("MSM USB transceiver driver");