blob: 4217ba0b99aa4813c8c8e9bb3ce09e1dd35e7df3 [file] [log] [blame]
Manu Gautam5143b252012-01-05 19:25:23 -08001/* Copyright (c) 2009-2012, Code Aurora Forum. All rights reserved.
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05302 *
3 * This program is free software; you can redistribute it and/or modify
4 * it under the terms of the GNU General Public License version 2 and
5 * only version 2 as published by the Free Software Foundation.
6 *
7 * This program is distributed in the hope that it will be useful,
8 * but WITHOUT ANY WARRANTY; without even the implied warranty of
9 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10 * GNU General Public License for more details.
11 *
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +053012 */
13
14#include <linux/module.h>
15#include <linux/device.h>
16#include <linux/platform_device.h>
17#include <linux/clk.h>
18#include <linux/slab.h>
19#include <linux/interrupt.h>
20#include <linux/err.h>
21#include <linux/delay.h>
22#include <linux/io.h>
23#include <linux/ioport.h>
24#include <linux/uaccess.h>
25#include <linux/debugfs.h>
26#include <linux/seq_file.h>
Pavankumar Kondeti87c01042010-12-07 17:53:58 +053027#include <linux/pm_runtime.h>
Pavankumar Kondetieaea7fe2011-10-27 14:46:45 +053028#include <linux/of.h>
29#include <linux/dma-mapping.h>
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +053030
31#include <linux/usb.h>
32#include <linux/usb/otg.h>
33#include <linux/usb/ulpi.h>
34#include <linux/usb/gadget.h>
35#include <linux/usb/hcd.h>
Vijayavardhan Vennapusaa3152032012-03-05 16:29:30 +053036#include <linux/usb/quirks.h>
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +053037#include <linux/usb/msm_hsusb.h>
38#include <linux/usb/msm_hsusb_hw.h>
Anji jonnala11aa5c42011-05-04 10:19:48 +053039#include <linux/regulator/consumer.h>
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070040#include <linux/mfd/pm8xxx/pm8921-charger.h>
Pavankumar Kondeti446f4542012-02-01 13:57:13 +053041#include <linux/mfd/pm8xxx/misc.h>
Amit Blay0f7edf72012-01-15 10:11:27 +020042#include <linux/power_supply.h>
Pavankumar Kondeti2aec9f32012-06-13 09:06:03 +053043#include <linux/mhl_8334.h>
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +053044
45#include <mach/clk.h>
Jack Pham87f202f2012-08-06 00:24:22 -070046#include <mach/mpm.h>
Anji jonnala7da3f262011-12-02 17:22:14 -080047#include <mach/msm_xo.h>
Manu Gautamcd82e9d2011-12-20 14:17:28 +053048#include <mach/msm_bus.h>
Mayank Rana248698c2012-04-19 00:03:16 +053049#include <mach/rpm-regulator.h>
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +053050
51#define MSM_USB_BASE (motg->regs)
52#define DRIVER_NAME "msm_otg"
53
Chiranjeevi Velempati489a27c2012-03-29 09:47:17 +053054#define ID_TIMER_FREQ (jiffies + msecs_to_jiffies(500))
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +053055#define ULPI_IO_TIMEOUT_USEC (10 * 1000)
Anji jonnala11aa5c42011-05-04 10:19:48 +053056#define USB_PHY_3P3_VOL_MIN 3050000 /* uV */
57#define USB_PHY_3P3_VOL_MAX 3300000 /* uV */
58#define USB_PHY_3P3_HPM_LOAD 50000 /* uA */
59#define USB_PHY_3P3_LPM_LOAD 4000 /* uA */
60
61#define USB_PHY_1P8_VOL_MIN 1800000 /* uV */
62#define USB_PHY_1P8_VOL_MAX 1800000 /* uV */
63#define USB_PHY_1P8_HPM_LOAD 50000 /* uA */
64#define USB_PHY_1P8_LPM_LOAD 4000 /* uA */
65
Mayank Rana248698c2012-04-19 00:03:16 +053066#define USB_PHY_VDD_DIG_VOL_NONE 0 /*uV */
Vamsi Krishna132b2762011-11-11 16:09:20 -080067#define USB_PHY_VDD_DIG_VOL_MIN 1045000 /* uV */
Anji jonnala11aa5c42011-05-04 10:19:48 +053068#define USB_PHY_VDD_DIG_VOL_MAX 1320000 /* uV */
69
Pavankumar Kondeti4960f312011-12-06 15:46:14 +053070static DECLARE_COMPLETION(pmic_vbus_init);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070071static struct msm_otg *the_msm_otg;
Pavankumar Kondetiaa449e12011-11-04 11:09:26 +053072static bool debug_aca_enabled;
Manu Gautam8bdcc592012-03-06 11:26:06 +053073static bool debug_bus_voting_enabled;
Pavankumar Kondeti2aec9f32012-06-13 09:06:03 +053074static bool mhl_det_in_progress;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070075
Anji jonnala11aa5c42011-05-04 10:19:48 +053076static struct regulator *hsusb_3p3;
77static struct regulator *hsusb_1p8;
78static struct regulator *hsusb_vddcx;
Mayank Ranae3926882011-12-26 09:47:54 +053079static struct regulator *vbus_otg;
Pavankumar Kondeti56dc7422012-07-02 12:45:19 +053080static struct regulator *mhl_usb_hs_switch;
Vijayavardhan Vennapusa05c437c2012-05-25 16:20:46 +053081static struct power_supply *psy;
Anji jonnala11aa5c42011-05-04 10:19:48 +053082
Pavankumar Kondeti4960f312011-12-06 15:46:14 +053083static bool aca_id_turned_on;
Pavankumar Kondetiaa449e12011-11-04 11:09:26 +053084static inline bool aca_enabled(void)
Anji jonnala11aa5c42011-05-04 10:19:48 +053085{
Pavankumar Kondetiaa449e12011-11-04 11:09:26 +053086#ifdef CONFIG_USB_MSM_ACA
87 return true;
88#else
89 return debug_aca_enabled;
90#endif
Anji jonnala11aa5c42011-05-04 10:19:48 +053091}
92
Mayank Rana248698c2012-04-19 00:03:16 +053093static const int vdd_val[VDD_TYPE_MAX][VDD_VAL_MAX] = {
94 { /* VDD_CX CORNER Voting */
95 [VDD_NONE] = RPM_VREG_CORNER_NONE,
96 [VDD_MIN] = RPM_VREG_CORNER_NOMINAL,
97 [VDD_MAX] = RPM_VREG_CORNER_HIGH,
98 },
99 { /* VDD_CX Voltage Voting */
100 [VDD_NONE] = USB_PHY_VDD_DIG_VOL_NONE,
101 [VDD_MIN] = USB_PHY_VDD_DIG_VOL_MIN,
102 [VDD_MAX] = USB_PHY_VDD_DIG_VOL_MAX,
103 },
104};
Anji jonnala11aa5c42011-05-04 10:19:48 +0530105
106static int msm_hsusb_ldo_init(struct msm_otg *motg, int init)
107{
108 int rc = 0;
109
110 if (init) {
Steve Mucklef132c6c2012-06-06 18:30:57 -0700111 hsusb_3p3 = devm_regulator_get(motg->phy.dev, "HSUSB_3p3");
Anji jonnala11aa5c42011-05-04 10:19:48 +0530112 if (IS_ERR(hsusb_3p3)) {
Heikki Krogerus1d4c9292012-02-13 13:24:09 +0200113 dev_err(motg->phy.dev, "unable to get hsusb 3p3\n");
Anji jonnala11aa5c42011-05-04 10:19:48 +0530114 return PTR_ERR(hsusb_3p3);
115 }
116
117 rc = regulator_set_voltage(hsusb_3p3, USB_PHY_3P3_VOL_MIN,
118 USB_PHY_3P3_VOL_MAX);
119 if (rc) {
Steve Mucklef132c6c2012-06-06 18:30:57 -0700120 dev_err(motg->phy.dev, "unable to set voltage level for"
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700121 "hsusb 3p3\n");
Mayank Rana9e9a2ac2012-03-24 04:05:28 +0530122 return rc;
Anji jonnala11aa5c42011-05-04 10:19:48 +0530123 }
Steve Mucklef132c6c2012-06-06 18:30:57 -0700124 hsusb_1p8 = devm_regulator_get(motg->phy.dev, "HSUSB_1p8");
Anji jonnala11aa5c42011-05-04 10:19:48 +0530125 if (IS_ERR(hsusb_1p8)) {
Heikki Krogerus1d4c9292012-02-13 13:24:09 +0200126 dev_err(motg->phy.dev, "unable to get hsusb 1p8\n");
Anji jonnala11aa5c42011-05-04 10:19:48 +0530127 rc = PTR_ERR(hsusb_1p8);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700128 goto put_3p3_lpm;
Anji jonnala11aa5c42011-05-04 10:19:48 +0530129 }
130 rc = regulator_set_voltage(hsusb_1p8, USB_PHY_1P8_VOL_MIN,
131 USB_PHY_1P8_VOL_MAX);
132 if (rc) {
Steve Mucklef132c6c2012-06-06 18:30:57 -0700133 dev_err(motg->phy.dev, "unable to set voltage level for"
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700134 "hsusb 1p8\n");
Anji jonnala11aa5c42011-05-04 10:19:48 +0530135 goto put_1p8;
136 }
137
138 return 0;
139 }
140
Anji jonnala11aa5c42011-05-04 10:19:48 +0530141put_1p8:
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700142 regulator_set_voltage(hsusb_1p8, 0, USB_PHY_1P8_VOL_MAX);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700143put_3p3_lpm:
144 regulator_set_voltage(hsusb_3p3, 0, USB_PHY_3P3_VOL_MAX);
Anji jonnala11aa5c42011-05-04 10:19:48 +0530145 return rc;
146}
147
Pavankumar Kondeti04aebcb2011-05-04 10:19:49 +0530148static int msm_hsusb_config_vddcx(int high)
149{
Mayank Rana248698c2012-04-19 00:03:16 +0530150 struct msm_otg *motg = the_msm_otg;
151 enum usb_vdd_type vdd_type = motg->vdd_type;
152 int max_vol = vdd_val[vdd_type][VDD_MAX];
Pavankumar Kondeti04aebcb2011-05-04 10:19:49 +0530153 int min_vol;
154 int ret;
155
Mayank Rana248698c2012-04-19 00:03:16 +0530156 min_vol = vdd_val[vdd_type][!!high];
Pavankumar Kondeti04aebcb2011-05-04 10:19:49 +0530157 ret = regulator_set_voltage(hsusb_vddcx, min_vol, max_vol);
158 if (ret) {
159 pr_err("%s: unable to set the voltage for regulator "
160 "HSUSB_VDDCX\n", __func__);
161 return ret;
162 }
163
164 pr_debug("%s: min_vol:%d max_vol:%d\n", __func__, min_vol, max_vol);
165
166 return ret;
167}
Pavankumar Kondeti04aebcb2011-05-04 10:19:49 +0530168
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700169static int msm_hsusb_ldo_enable(struct msm_otg *motg, int on)
Anji jonnala11aa5c42011-05-04 10:19:48 +0530170{
171 int ret = 0;
172
Pavankumar Kondeti68964c92011-10-27 14:58:56 +0530173 if (IS_ERR(hsusb_1p8)) {
Anji jonnala11aa5c42011-05-04 10:19:48 +0530174 pr_err("%s: HSUSB_1p8 is not initialized\n", __func__);
175 return -ENODEV;
176 }
177
Pavankumar Kondeti68964c92011-10-27 14:58:56 +0530178 if (IS_ERR(hsusb_3p3)) {
Anji jonnala11aa5c42011-05-04 10:19:48 +0530179 pr_err("%s: HSUSB_3p3 is not initialized\n", __func__);
180 return -ENODEV;
181 }
182
183 if (on) {
184 ret = regulator_set_optimum_mode(hsusb_1p8,
185 USB_PHY_1P8_HPM_LOAD);
186 if (ret < 0) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700187 pr_err("%s: Unable to set HPM of the regulator:"
Anji jonnala11aa5c42011-05-04 10:19:48 +0530188 "HSUSB_1p8\n", __func__);
189 return ret;
190 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700191
192 ret = regulator_enable(hsusb_1p8);
193 if (ret) {
Steve Mucklef132c6c2012-06-06 18:30:57 -0700194 dev_err(motg->phy.dev, "%s: unable to enable the hsusb 1p8\n",
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700195 __func__);
196 regulator_set_optimum_mode(hsusb_1p8, 0);
197 return ret;
198 }
199
Anji jonnala11aa5c42011-05-04 10:19:48 +0530200 ret = regulator_set_optimum_mode(hsusb_3p3,
201 USB_PHY_3P3_HPM_LOAD);
202 if (ret < 0) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700203 pr_err("%s: Unable to set HPM of the regulator:"
Anji jonnala11aa5c42011-05-04 10:19:48 +0530204 "HSUSB_3p3\n", __func__);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700205 regulator_set_optimum_mode(hsusb_1p8, 0);
206 regulator_disable(hsusb_1p8);
Anji jonnala11aa5c42011-05-04 10:19:48 +0530207 return ret;
208 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700209
210 ret = regulator_enable(hsusb_3p3);
211 if (ret) {
Steve Mucklef132c6c2012-06-06 18:30:57 -0700212 dev_err(motg->phy.dev, "%s: unable to enable the hsusb 3p3\n",
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700213 __func__);
214 regulator_set_optimum_mode(hsusb_3p3, 0);
215 regulator_set_optimum_mode(hsusb_1p8, 0);
216 regulator_disable(hsusb_1p8);
217 return ret;
218 }
219
Anji jonnala11aa5c42011-05-04 10:19:48 +0530220 } else {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700221 ret = regulator_disable(hsusb_1p8);
222 if (ret) {
Steve Mucklef132c6c2012-06-06 18:30:57 -0700223 dev_err(motg->phy.dev, "%s: unable to disable the hsusb 1p8\n",
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700224 __func__);
225 return ret;
226 }
227
228 ret = regulator_set_optimum_mode(hsusb_1p8, 0);
Anji jonnala11aa5c42011-05-04 10:19:48 +0530229 if (ret < 0)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700230 pr_err("%s: Unable to set LPM of the regulator:"
Anji jonnala11aa5c42011-05-04 10:19:48 +0530231 "HSUSB_1p8\n", __func__);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700232
233 ret = regulator_disable(hsusb_3p3);
234 if (ret) {
Steve Mucklef132c6c2012-06-06 18:30:57 -0700235 dev_err(motg->phy.dev, "%s: unable to disable the hsusb 3p3\n",
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700236 __func__);
237 return ret;
238 }
239 ret = regulator_set_optimum_mode(hsusb_3p3, 0);
Anji jonnala11aa5c42011-05-04 10:19:48 +0530240 if (ret < 0)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700241 pr_err("%s: Unable to set LPM of the regulator:"
Anji jonnala11aa5c42011-05-04 10:19:48 +0530242 "HSUSB_3p3\n", __func__);
243 }
244
245 pr_debug("reg (%s)\n", on ? "HPM" : "LPM");
246 return ret < 0 ? ret : 0;
247}
248
Vijayavardhan Vennapusafc464f02011-11-04 21:54:00 +0530249static void msm_hsusb_mhl_switch_enable(struct msm_otg *motg, bool on)
250{
Vijayavardhan Vennapusafc464f02011-11-04 21:54:00 +0530251 struct msm_otg_platform_data *pdata = motg->pdata;
252
253 if (!pdata->mhl_enable)
254 return;
255
Pavankumar Kondeti56dc7422012-07-02 12:45:19 +0530256 if (!mhl_usb_hs_switch) {
257 pr_err("%s: mhl_usb_hs_switch is NULL.\n", __func__);
Vijayavardhan Vennapusafc464f02011-11-04 21:54:00 +0530258 return;
259 }
260
Mayank Rana9e9a2ac2012-03-24 04:05:28 +0530261 if (on) {
Pavankumar Kondeti56dc7422012-07-02 12:45:19 +0530262 if (regulator_enable(mhl_usb_hs_switch))
263 pr_err("unable to enable mhl_usb_hs_switch\n");
Mayank Rana9e9a2ac2012-03-24 04:05:28 +0530264 } else {
Pavankumar Kondeti56dc7422012-07-02 12:45:19 +0530265 regulator_disable(mhl_usb_hs_switch);
Mayank Rana9e9a2ac2012-03-24 04:05:28 +0530266 }
Vijayavardhan Vennapusafc464f02011-11-04 21:54:00 +0530267}
268
Heikki Krogerus1d4c9292012-02-13 13:24:09 +0200269static int ulpi_read(struct usb_phy *phy, u32 reg)
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +0530270{
Heikki Krogerus1d4c9292012-02-13 13:24:09 +0200271 struct msm_otg *motg = container_of(phy, struct msm_otg, phy);
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +0530272 int cnt = 0;
273
274 /* initiate read operation */
275 writel(ULPI_RUN | ULPI_READ | ULPI_ADDR(reg),
276 USB_ULPI_VIEWPORT);
277
278 /* wait for completion */
279 while (cnt < ULPI_IO_TIMEOUT_USEC) {
280 if (!(readl(USB_ULPI_VIEWPORT) & ULPI_RUN))
281 break;
282 udelay(1);
283 cnt++;
284 }
285
286 if (cnt >= ULPI_IO_TIMEOUT_USEC) {
Heikki Krogerus1d4c9292012-02-13 13:24:09 +0200287 dev_err(phy->dev, "ulpi_read: timeout %08x\n",
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +0530288 readl(USB_ULPI_VIEWPORT));
289 return -ETIMEDOUT;
290 }
291 return ULPI_DATA_READ(readl(USB_ULPI_VIEWPORT));
292}
293
Heikki Krogerus1d4c9292012-02-13 13:24:09 +0200294static int ulpi_write(struct usb_phy *phy, u32 val, u32 reg)
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +0530295{
Heikki Krogerus1d4c9292012-02-13 13:24:09 +0200296 struct msm_otg *motg = container_of(phy, struct msm_otg, phy);
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +0530297 int cnt = 0;
298
299 /* initiate write operation */
300 writel(ULPI_RUN | ULPI_WRITE |
301 ULPI_ADDR(reg) | ULPI_DATA(val),
302 USB_ULPI_VIEWPORT);
303
304 /* wait for completion */
305 while (cnt < ULPI_IO_TIMEOUT_USEC) {
306 if (!(readl(USB_ULPI_VIEWPORT) & ULPI_RUN))
307 break;
308 udelay(1);
309 cnt++;
310 }
311
312 if (cnt >= ULPI_IO_TIMEOUT_USEC) {
Heikki Krogerus1d4c9292012-02-13 13:24:09 +0200313 dev_err(phy->dev, "ulpi_write: timeout\n");
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +0530314 return -ETIMEDOUT;
315 }
316 return 0;
317}
318
Heikki Krogerus1d4c9292012-02-13 13:24:09 +0200319static struct usb_phy_io_ops msm_otg_io_ops = {
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +0530320 .read = ulpi_read,
321 .write = ulpi_write,
322};
323
324static void ulpi_init(struct msm_otg *motg)
325{
326 struct msm_otg_platform_data *pdata = motg->pdata;
327 int *seq = pdata->phy_init_seq;
328
329 if (!seq)
330 return;
331
332 while (seq[0] >= 0) {
Heikki Krogerus1d4c9292012-02-13 13:24:09 +0200333 dev_vdbg(motg->phy.dev, "ulpi: write 0x%02x to 0x%02x\n",
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +0530334 seq[0], seq[1]);
Heikki Krogerus1d4c9292012-02-13 13:24:09 +0200335 ulpi_write(&motg->phy, seq[0], seq[1]);
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +0530336 seq += 2;
337 }
338}
339
340static int msm_otg_link_clk_reset(struct msm_otg *motg, bool assert)
341{
342 int ret;
343
344 if (assert) {
Manu Gautam5025ff12012-07-20 10:56:50 +0530345 if (!IS_ERR(motg->clk)) {
346 ret = clk_reset(motg->clk, CLK_RESET_ASSERT);
347 } else {
348 /* Using asynchronous block reset to the hardware */
349 dev_dbg(motg->phy.dev, "block_reset ASSERT\n");
350 clk_disable_unprepare(motg->pclk);
351 clk_disable_unprepare(motg->core_clk);
352 ret = clk_reset(motg->core_clk, CLK_RESET_ASSERT);
353 }
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +0530354 if (ret)
Heikki Krogerus1d4c9292012-02-13 13:24:09 +0200355 dev_err(motg->phy.dev, "usb hs_clk assert failed\n");
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +0530356 } else {
Manu Gautam5025ff12012-07-20 10:56:50 +0530357 if (!IS_ERR(motg->clk)) {
358 ret = clk_reset(motg->clk, CLK_RESET_DEASSERT);
359 } else {
360 dev_dbg(motg->phy.dev, "block_reset DEASSERT\n");
361 ret = clk_reset(motg->core_clk, CLK_RESET_DEASSERT);
362 ndelay(200);
363 clk_prepare_enable(motg->core_clk);
364 clk_prepare_enable(motg->pclk);
365 }
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +0530366 if (ret)
Heikki Krogerus1d4c9292012-02-13 13:24:09 +0200367 dev_err(motg->phy.dev, "usb hs_clk deassert failed\n");
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +0530368 }
369 return ret;
370}
371
372static int msm_otg_phy_clk_reset(struct msm_otg *motg)
373{
374 int ret;
375
Amit Blay02eff132011-09-21 16:46:24 +0300376 if (IS_ERR(motg->phy_reset_clk))
377 return 0;
378
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +0530379 ret = clk_reset(motg->phy_reset_clk, CLK_RESET_ASSERT);
380 if (ret) {
Heikki Krogerus1d4c9292012-02-13 13:24:09 +0200381 dev_err(motg->phy.dev, "usb phy clk assert failed\n");
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +0530382 return ret;
383 }
384 usleep_range(10000, 12000);
385 ret = clk_reset(motg->phy_reset_clk, CLK_RESET_DEASSERT);
386 if (ret)
Heikki Krogerus1d4c9292012-02-13 13:24:09 +0200387 dev_err(motg->phy.dev, "usb phy clk deassert failed\n");
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +0530388 return ret;
389}
390
391static int msm_otg_phy_reset(struct msm_otg *motg)
392{
393 u32 val;
394 int ret;
395 int retries;
396
397 ret = msm_otg_link_clk_reset(motg, 1);
398 if (ret)
399 return ret;
400 ret = msm_otg_phy_clk_reset(motg);
401 if (ret)
402 return ret;
403 ret = msm_otg_link_clk_reset(motg, 0);
404 if (ret)
405 return ret;
406
407 val = readl(USB_PORTSC) & ~PORTSC_PTS_MASK;
408 writel(val | PORTSC_PTS_ULPI, USB_PORTSC);
409
410 for (retries = 3; retries > 0; retries--) {
Heikki Krogerus1d4c9292012-02-13 13:24:09 +0200411 ret = ulpi_write(&motg->phy, ULPI_FUNC_CTRL_SUSPENDM,
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +0530412 ULPI_CLR(ULPI_FUNC_CTRL));
413 if (!ret)
414 break;
415 ret = msm_otg_phy_clk_reset(motg);
416 if (ret)
417 return ret;
418 }
419 if (!retries)
420 return -ETIMEDOUT;
421
422 /* This reset calibrates the phy, if the above write succeeded */
423 ret = msm_otg_phy_clk_reset(motg);
424 if (ret)
425 return ret;
426
427 for (retries = 3; retries > 0; retries--) {
Heikki Krogerus1d4c9292012-02-13 13:24:09 +0200428 ret = ulpi_read(&motg->phy, ULPI_DEBUG);
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +0530429 if (ret != -ETIMEDOUT)
430 break;
431 ret = msm_otg_phy_clk_reset(motg);
432 if (ret)
433 return ret;
434 }
435 if (!retries)
436 return -ETIMEDOUT;
437
Heikki Krogerus1d4c9292012-02-13 13:24:09 +0200438 dev_info(motg->phy.dev, "phy_reset: success\n");
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +0530439 return 0;
440}
441
442#define LINK_RESET_TIMEOUT_USEC (250 * 1000)
Pavankumar Kondetiaa449e12011-11-04 11:09:26 +0530443static int msm_otg_link_reset(struct msm_otg *motg)
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +0530444{
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +0530445 int cnt = 0;
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +0530446
Pavankumar Kondetiaa449e12011-11-04 11:09:26 +0530447 writel_relaxed(USBCMD_RESET, USB_USBCMD);
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +0530448 while (cnt < LINK_RESET_TIMEOUT_USEC) {
Pavankumar Kondetiaa449e12011-11-04 11:09:26 +0530449 if (!(readl_relaxed(USB_USBCMD) & USBCMD_RESET))
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +0530450 break;
451 udelay(1);
452 cnt++;
453 }
454 if (cnt >= LINK_RESET_TIMEOUT_USEC)
455 return -ETIMEDOUT;
456
457 /* select ULPI phy */
Pavankumar Kondetiaa449e12011-11-04 11:09:26 +0530458 writel_relaxed(0x80000000, USB_PORTSC);
459 writel_relaxed(0x0, USB_AHBBURST);
Vijayavardhan Vennapusa5f32d7a2012-03-14 16:30:26 +0530460 writel_relaxed(0x08, USB_AHBMODE);
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +0530461
Pavankumar Kondetiaa449e12011-11-04 11:09:26 +0530462 return 0;
463}
464
Steve Mucklef132c6c2012-06-06 18:30:57 -0700465static int msm_otg_reset(struct usb_phy *phy)
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +0530466{
Steve Mucklef132c6c2012-06-06 18:30:57 -0700467 struct msm_otg *motg = container_of(phy, struct msm_otg, phy);
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +0530468 struct msm_otg_platform_data *pdata = motg->pdata;
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +0530469 int ret;
470 u32 val = 0;
471 u32 ulpi_val = 0;
472
Ofir Cohen4da266f2012-01-03 10:19:29 +0200473 /*
474 * USB PHY and Link reset also reset the USB BAM.
475 * Thus perform reset operation only once to avoid
476 * USB BAM reset on other cases e.g. USB cable disconnections.
477 */
478 if (pdata->disable_reset_on_disconnect) {
479 if (motg->reset_counter)
480 return 0;
481 else
482 motg->reset_counter++;
483 }
484
Pavankumar Kondeti923262e2012-04-20 15:34:24 +0530485 if (!IS_ERR(motg->clk))
486 clk_prepare_enable(motg->clk);
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +0530487 ret = msm_otg_phy_reset(motg);
488 if (ret) {
Steve Mucklef132c6c2012-06-06 18:30:57 -0700489 dev_err(phy->dev, "phy_reset failed\n");
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +0530490 return ret;
491 }
492
Pavankumar Kondeti4960f312011-12-06 15:46:14 +0530493 aca_id_turned_on = false;
Pavankumar Kondetiaa449e12011-11-04 11:09:26 +0530494 ret = msm_otg_link_reset(motg);
495 if (ret) {
Steve Mucklef132c6c2012-06-06 18:30:57 -0700496 dev_err(phy->dev, "link reset failed\n");
Pavankumar Kondetiaa449e12011-11-04 11:09:26 +0530497 return ret;
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +0530498 }
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +0530499 msleep(100);
500
Anji jonnalaa8b8d732011-12-06 10:03:24 +0530501 ulpi_init(motg);
502
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700503 /* Ensure that RESET operation is completed before turning off clock */
504 mb();
Pavankumar Kondetiaa449e12011-11-04 11:09:26 +0530505
Pavankumar Kondeti923262e2012-04-20 15:34:24 +0530506 if (!IS_ERR(motg->clk))
507 clk_disable_unprepare(motg->clk);
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +0530508
509 if (pdata->otg_control == OTG_PHY_CONTROL) {
Pavankumar Kondeti4960f312011-12-06 15:46:14 +0530510 val = readl_relaxed(USB_OTGSC);
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +0530511 if (pdata->mode == USB_OTG) {
512 ulpi_val = ULPI_INT_IDGRD | ULPI_INT_SESS_VALID;
513 val |= OTGSC_IDIE | OTGSC_BSVIE;
514 } else if (pdata->mode == USB_PERIPHERAL) {
515 ulpi_val = ULPI_INT_SESS_VALID;
516 val |= OTGSC_BSVIE;
517 }
Pavankumar Kondeti4960f312011-12-06 15:46:14 +0530518 writel_relaxed(val, USB_OTGSC);
Heikki Krogerus1d4c9292012-02-13 13:24:09 +0200519 ulpi_write(phy, ulpi_val, ULPI_USB_INT_EN_RISE);
520 ulpi_write(phy, ulpi_val, ULPI_USB_INT_EN_FALL);
Pavankumar Kondeti446f4542012-02-01 13:57:13 +0530521 } else if (pdata->otg_control == OTG_PMIC_CONTROL) {
Steve Mucklef132c6c2012-06-06 18:30:57 -0700522 ulpi_write(phy, OTG_COMP_DISABLE,
Vijayavardhan Vennapusa03171c72012-04-26 14:44:48 +0530523 ULPI_SET(ULPI_PWR_CLK_MNG_REG));
Pavankumar Kondeti446f4542012-02-01 13:57:13 +0530524 /* Enable PMIC pull-up */
525 pm8xxx_usb_id_pullup(1);
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +0530526 }
527
528 return 0;
529}
530
Vijayavardhan Vennapusaa3152032012-03-05 16:29:30 +0530531static const char *timer_string(int bit)
532{
533 switch (bit) {
534 case A_WAIT_VRISE: return "a_wait_vrise";
535 case A_WAIT_VFALL: return "a_wait_vfall";
536 case B_SRP_FAIL: return "b_srp_fail";
537 case A_WAIT_BCON: return "a_wait_bcon";
538 case A_AIDL_BDIS: return "a_aidl_bdis";
539 case A_BIDL_ADIS: return "a_bidl_adis";
540 case B_ASE0_BRST: return "b_ase0_brst";
541 case A_TST_MAINT: return "a_tst_maint";
542 case B_TST_SRP: return "b_tst_srp";
543 case B_TST_CONFIG: return "b_tst_config";
544 default: return "UNDEFINED";
545 }
546}
547
548static enum hrtimer_restart msm_otg_timer_func(struct hrtimer *hrtimer)
549{
550 struct msm_otg *motg = container_of(hrtimer, struct msm_otg, timer);
551
552 switch (motg->active_tmout) {
553 case A_WAIT_VRISE:
554 /* TODO: use vbus_vld interrupt */
555 set_bit(A_VBUS_VLD, &motg->inputs);
556 break;
557 case A_TST_MAINT:
558 /* OTG PET: End session after TA_TST_MAINT */
559 set_bit(A_BUS_DROP, &motg->inputs);
560 break;
561 case B_TST_SRP:
562 /*
563 * OTG PET: Initiate SRP after TB_TST_SRP of
564 * previous session end.
565 */
566 set_bit(B_BUS_REQ, &motg->inputs);
567 break;
568 case B_TST_CONFIG:
569 clear_bit(A_CONN, &motg->inputs);
570 break;
571 default:
572 set_bit(motg->active_tmout, &motg->tmouts);
573 }
574
575 pr_debug("expired %s timer\n", timer_string(motg->active_tmout));
576 queue_work(system_nrt_wq, &motg->sm_work);
577 return HRTIMER_NORESTART;
578}
579
580static void msm_otg_del_timer(struct msm_otg *motg)
581{
582 int bit = motg->active_tmout;
583
584 pr_debug("deleting %s timer. remaining %lld msec\n", timer_string(bit),
585 div_s64(ktime_to_us(hrtimer_get_remaining(
586 &motg->timer)), 1000));
587 hrtimer_cancel(&motg->timer);
588 clear_bit(bit, &motg->tmouts);
589}
590
591static void msm_otg_start_timer(struct msm_otg *motg, int time, int bit)
592{
593 clear_bit(bit, &motg->tmouts);
594 motg->active_tmout = bit;
595 pr_debug("starting %s timer\n", timer_string(bit));
596 hrtimer_start(&motg->timer,
597 ktime_set(time / 1000, (time % 1000) * 1000000),
598 HRTIMER_MODE_REL);
599}
600
601static void msm_otg_init_timer(struct msm_otg *motg)
602{
603 hrtimer_init(&motg->timer, CLOCK_MONOTONIC, HRTIMER_MODE_REL);
604 motg->timer.function = msm_otg_timer_func;
605}
606
Steve Mucklef132c6c2012-06-06 18:30:57 -0700607static int msm_otg_start_hnp(struct usb_otg *otg)
Vijayavardhan Vennapusaa3152032012-03-05 16:29:30 +0530608{
Steve Mucklef132c6c2012-06-06 18:30:57 -0700609 struct msm_otg *motg = container_of(otg->phy, struct msm_otg, phy);
Vijayavardhan Vennapusaa3152032012-03-05 16:29:30 +0530610
Steve Mucklef132c6c2012-06-06 18:30:57 -0700611 if (otg->phy->state != OTG_STATE_A_HOST) {
Vijayavardhan Vennapusaa3152032012-03-05 16:29:30 +0530612 pr_err("HNP can not be initiated in %s state\n",
Steve Mucklef132c6c2012-06-06 18:30:57 -0700613 otg_state_string(otg->phy->state));
Vijayavardhan Vennapusaa3152032012-03-05 16:29:30 +0530614 return -EINVAL;
615 }
616
617 pr_debug("A-Host: HNP initiated\n");
618 clear_bit(A_BUS_REQ, &motg->inputs);
619 queue_work(system_nrt_wq, &motg->sm_work);
620 return 0;
621}
622
Steve Mucklef132c6c2012-06-06 18:30:57 -0700623static int msm_otg_start_srp(struct usb_otg *otg)
Vijayavardhan Vennapusaa3152032012-03-05 16:29:30 +0530624{
Steve Mucklef132c6c2012-06-06 18:30:57 -0700625 struct msm_otg *motg = container_of(otg->phy, struct msm_otg, phy);
Vijayavardhan Vennapusaa3152032012-03-05 16:29:30 +0530626 u32 val;
627 int ret = 0;
628
Steve Mucklef132c6c2012-06-06 18:30:57 -0700629 if (otg->phy->state != OTG_STATE_B_IDLE) {
Vijayavardhan Vennapusaa3152032012-03-05 16:29:30 +0530630 pr_err("SRP can not be initiated in %s state\n",
Steve Mucklef132c6c2012-06-06 18:30:57 -0700631 otg_state_string(otg->phy->state));
Vijayavardhan Vennapusaa3152032012-03-05 16:29:30 +0530632 ret = -EINVAL;
633 goto out;
634 }
635
636 if ((jiffies - motg->b_last_se0_sess) < msecs_to_jiffies(TB_SRP_INIT)) {
637 pr_debug("initial conditions of SRP are not met. Try again"
638 "after some time\n");
639 ret = -EAGAIN;
640 goto out;
641 }
642
643 pr_debug("B-Device SRP started\n");
644
645 /*
646 * PHY won't pull D+ high unless it detects Vbus valid.
647 * Since by definition, SRP is only done when Vbus is not valid,
648 * software work-around needs to be used to spoof the PHY into
649 * thinking it is valid. This can be done using the VBUSVLDEXTSEL and
650 * VBUSVLDEXT register bits.
651 */
Steve Mucklef132c6c2012-06-06 18:30:57 -0700652 ulpi_write(otg->phy, 0x03, 0x97);
Vijayavardhan Vennapusaa3152032012-03-05 16:29:30 +0530653 /*
654 * Harware auto assist data pulsing: Data pulse is given
655 * for 7msec; wait for vbus
656 */
657 val = readl_relaxed(USB_OTGSC);
658 writel_relaxed((val & ~OTGSC_INTSTS_MASK) | OTGSC_HADP, USB_OTGSC);
659
660 /* VBUS plusing is obsoleted in OTG 2.0 supplement */
661out:
662 return ret;
663}
664
Steve Mucklef132c6c2012-06-06 18:30:57 -0700665static void msm_otg_host_hnp_enable(struct usb_otg *otg, bool enable)
Vijayavardhan Vennapusaa3152032012-03-05 16:29:30 +0530666{
667 struct usb_hcd *hcd = bus_to_hcd(otg->host);
668 struct usb_device *rhub = otg->host->root_hub;
669
670 if (enable) {
671 pm_runtime_disable(&rhub->dev);
672 rhub->state = USB_STATE_NOTATTACHED;
673 hcd->driver->bus_suspend(hcd);
674 clear_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags);
675 } else {
676 usb_remove_hcd(hcd);
Steve Mucklef132c6c2012-06-06 18:30:57 -0700677 msm_otg_reset(otg->phy);
Vijayavardhan Vennapusaa3152032012-03-05 16:29:30 +0530678 usb_add_hcd(hcd, hcd->irq, IRQF_SHARED);
679 }
680}
681
Steve Mucklef132c6c2012-06-06 18:30:57 -0700682static int msm_otg_set_suspend(struct usb_phy *phy, int suspend)
Pavankumar Kondeti8be99cf2011-08-04 10:48:08 +0530683{
Steve Mucklef132c6c2012-06-06 18:30:57 -0700684 struct msm_otg *motg = container_of(phy, struct msm_otg, phy);
Pavankumar Kondeti8be99cf2011-08-04 10:48:08 +0530685
Amit Blay6fa647a2012-05-24 14:12:08 +0300686 if (aca_enabled())
Vijayavardhan Vennapusaa3152032012-03-05 16:29:30 +0530687 return 0;
Pavankumar Kondeti8be99cf2011-08-04 10:48:08 +0530688
Jack Pham69e621d2012-06-25 18:48:07 -0700689 if (atomic_read(&motg->in_lpm) == suspend)
690 return 0;
691
Vijayavardhan Vennapusaa3152032012-03-05 16:29:30 +0530692 if (suspend) {
Steve Mucklef132c6c2012-06-06 18:30:57 -0700693 switch (phy->state) {
Vijayavardhan Vennapusaa3152032012-03-05 16:29:30 +0530694 case OTG_STATE_A_WAIT_BCON:
695 if (TA_WAIT_BCON > 0)
696 break;
697 /* fall through */
698 case OTG_STATE_A_HOST:
699 pr_debug("host bus suspend\n");
700 clear_bit(A_BUS_REQ, &motg->inputs);
701 queue_work(system_nrt_wq, &motg->sm_work);
702 break;
Amit Blay6fa647a2012-05-24 14:12:08 +0300703 case OTG_STATE_B_PERIPHERAL:
704 pr_debug("peripheral bus suspend\n");
705 if (!(motg->caps & ALLOW_LPM_ON_DEV_SUSPEND))
706 break;
707 set_bit(A_BUS_SUSPEND, &motg->inputs);
708 queue_work(system_nrt_wq, &motg->sm_work);
709 break;
710
Vijayavardhan Vennapusaa3152032012-03-05 16:29:30 +0530711 default:
712 break;
713 }
714 } else {
Steve Mucklef132c6c2012-06-06 18:30:57 -0700715 switch (phy->state) {
Vijayavardhan Vennapusaa3152032012-03-05 16:29:30 +0530716 case OTG_STATE_A_SUSPEND:
717 /* Remote wakeup or resume */
718 set_bit(A_BUS_REQ, &motg->inputs);
Steve Mucklef132c6c2012-06-06 18:30:57 -0700719 phy->state = OTG_STATE_A_HOST;
Jack Pham5ca279b2012-05-14 18:42:54 -0700720
721 /* ensure hardware is not in low power mode */
Steve Mucklef132c6c2012-06-06 18:30:57 -0700722 pm_runtime_resume(phy->dev);
Vijayavardhan Vennapusaa3152032012-03-05 16:29:30 +0530723 break;
Amit Blay6fa647a2012-05-24 14:12:08 +0300724 case OTG_STATE_B_PERIPHERAL:
725 pr_debug("peripheral bus resume\n");
726 if (!(motg->caps & ALLOW_LPM_ON_DEV_SUSPEND))
727 break;
728 clear_bit(A_BUS_SUSPEND, &motg->inputs);
729 queue_work(system_nrt_wq, &motg->sm_work);
730 break;
Vijayavardhan Vennapusaa3152032012-03-05 16:29:30 +0530731 default:
732 break;
733 }
734 }
Pavankumar Kondeti8be99cf2011-08-04 10:48:08 +0530735 return 0;
736}
737
Pavankumar Kondeti87c01042010-12-07 17:53:58 +0530738#define PHY_SUSPEND_TIMEOUT_USEC (500 * 1000)
Pavankumar Kondeti70187732011-02-15 09:42:34 +0530739#define PHY_RESUME_TIMEOUT_USEC (100 * 1000)
740
741#ifdef CONFIG_PM_SLEEP
Pavankumar Kondeti87c01042010-12-07 17:53:58 +0530742static int msm_otg_suspend(struct msm_otg *motg)
743{
Heikki Krogerus1d4c9292012-02-13 13:24:09 +0200744 struct usb_phy *phy = &motg->phy;
745 struct usb_bus *bus = phy->otg->host;
Pavankumar Kondeti87c01042010-12-07 17:53:58 +0530746 struct msm_otg_platform_data *pdata = motg->pdata;
747 int cnt = 0;
Amit Blay6fa647a2012-05-24 14:12:08 +0300748 bool host_bus_suspend, device_bus_suspend, dcp;
Pavankumar Kondeti4960f312011-12-06 15:46:14 +0530749 u32 phy_ctrl_val = 0, cmd_val;
Stephen Boyd30ad10b2012-03-01 14:51:04 -0800750 unsigned ret;
Rajkumar Raghupathy242565d2011-12-13 12:10:59 +0530751 u32 portsc;
Pavankumar Kondeti87c01042010-12-07 17:53:58 +0530752
753 if (atomic_read(&motg->in_lpm))
754 return 0;
755
756 disable_irq(motg->irq);
Pavankumar Kondeti2aec9f32012-06-13 09:06:03 +0530757 host_bus_suspend = !test_bit(MHL, &motg->inputs) && phy->otg->host &&
758 !test_bit(ID, &motg->inputs);
Steve Mucklef132c6c2012-06-06 18:30:57 -0700759 device_bus_suspend = phy->otg->gadget && test_bit(ID, &motg->inputs) &&
Amit Blay6fa647a2012-05-24 14:12:08 +0300760 test_bit(A_BUS_SUSPEND, &motg->inputs) &&
761 motg->caps & ALLOW_LPM_ON_DEV_SUSPEND;
Pavankumar Kondeti283146f2012-01-12 12:51:19 +0530762 dcp = motg->chg_type == USB_DCP_CHARGER;
Pavankumar Kondeti87c01042010-12-07 17:53:58 +0530763 /*
Pavankumar Kondeti04aebcb2011-05-04 10:19:49 +0530764 * Chipidea 45-nm PHY suspend sequence:
765 *
Pavankumar Kondeti87c01042010-12-07 17:53:58 +0530766 * Interrupt Latch Register auto-clear feature is not present
767 * in all PHY versions. Latch register is clear on read type.
768 * Clear latch register to avoid spurious wakeup from
769 * low power mode (LPM).
Pavankumar Kondeti04aebcb2011-05-04 10:19:49 +0530770 *
Pavankumar Kondeti87c01042010-12-07 17:53:58 +0530771 * PHY comparators are disabled when PHY enters into low power
772 * mode (LPM). Keep PHY comparators ON in LPM only when we expect
773 * VBUS/Id notifications from USB PHY. Otherwise turn off USB
774 * PHY comparators. This save significant amount of power.
Pavankumar Kondeti04aebcb2011-05-04 10:19:49 +0530775 *
Pavankumar Kondeti87c01042010-12-07 17:53:58 +0530776 * PLL is not turned off when PHY enters into low power mode (LPM).
777 * Disable PLL for maximum power savings.
778 */
Pavankumar Kondeti04aebcb2011-05-04 10:19:49 +0530779
780 if (motg->pdata->phy_type == CI_45NM_INTEGRATED_PHY) {
Heikki Krogerus1d4c9292012-02-13 13:24:09 +0200781 ulpi_read(phy, 0x14);
Pavankumar Kondeti04aebcb2011-05-04 10:19:49 +0530782 if (pdata->otg_control == OTG_PHY_CONTROL)
Heikki Krogerus1d4c9292012-02-13 13:24:09 +0200783 ulpi_write(phy, 0x01, 0x30);
784 ulpi_write(phy, 0x08, 0x09);
Pavankumar Kondeti04aebcb2011-05-04 10:19:49 +0530785 }
Pavankumar Kondeti87c01042010-12-07 17:53:58 +0530786
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700787
Rajkumar Raghupathy242565d2011-12-13 12:10:59 +0530788 /* Set the PHCD bit, only if it is not set by the controller.
Pavankumar Kondeti87c01042010-12-07 17:53:58 +0530789 * PHY may take some time or even fail to enter into low power
790 * mode (LPM). Hence poll for 500 msec and reset the PHY and link
791 * in failure case.
792 */
Rajkumar Raghupathy242565d2011-12-13 12:10:59 +0530793 portsc = readl_relaxed(USB_PORTSC);
794 if (!(portsc & PORTSC_PHCD)) {
795 writel_relaxed(portsc | PORTSC_PHCD,
796 USB_PORTSC);
797 while (cnt < PHY_SUSPEND_TIMEOUT_USEC) {
798 if (readl_relaxed(USB_PORTSC) & PORTSC_PHCD)
799 break;
800 udelay(1);
801 cnt++;
802 }
Pavankumar Kondeti87c01042010-12-07 17:53:58 +0530803 }
804
805 if (cnt >= PHY_SUSPEND_TIMEOUT_USEC) {
Heikki Krogerus1d4c9292012-02-13 13:24:09 +0200806 dev_err(phy->dev, "Unable to suspend PHY\n");
807 msm_otg_reset(phy);
Pavankumar Kondeti87c01042010-12-07 17:53:58 +0530808 enable_irq(motg->irq);
809 return -ETIMEDOUT;
810 }
811
812 /*
813 * PHY has capability to generate interrupt asynchronously in low
814 * power mode (LPM). This interrupt is level triggered. So USB IRQ
815 * line must be disabled till async interrupt enable bit is cleared
816 * in USBCMD register. Assert STP (ULPI interface STOP signal) to
817 * block data communication from PHY.
Pavankumar Kondeti6be675f2012-04-16 13:29:24 +0530818 *
819 * PHY retention mode is disallowed while entering to LPM with wall
820 * charger connected. But PHY is put into suspend mode. Hence
821 * enable asynchronous interrupt to detect charger disconnection when
822 * PMIC notifications are unavailable.
Pavankumar Kondeti87c01042010-12-07 17:53:58 +0530823 */
Pavankumar Kondeti4960f312011-12-06 15:46:14 +0530824 cmd_val = readl_relaxed(USB_USBCMD);
Amit Blay6fa647a2012-05-24 14:12:08 +0300825 if (host_bus_suspend || device_bus_suspend ||
826 (motg->pdata->otg_control == OTG_PHY_CONTROL && dcp))
Pavankumar Kondeti4960f312011-12-06 15:46:14 +0530827 cmd_val |= ASYNC_INTR_CTRL | ULPI_STP_CTRL;
828 else
829 cmd_val |= ULPI_STP_CTRL;
830 writel_relaxed(cmd_val, USB_USBCMD);
Pavankumar Kondeti87c01042010-12-07 17:53:58 +0530831
Pavankumar Kondeti283146f2012-01-12 12:51:19 +0530832 /*
833 * BC1.2 spec mandates PD to enable VDP_SRC when charging from DCP.
834 * PHY retention and collapse can not happen with VDP_SRC enabled.
835 */
Amit Blay6fa647a2012-05-24 14:12:08 +0300836 if (motg->caps & ALLOW_PHY_RETENTION && !host_bus_suspend &&
837 !device_bus_suspend && !dcp) {
Amit Blay58b31472011-11-18 09:39:39 +0200838 phy_ctrl_val = readl_relaxed(USB_PHY_CTRL);
839 if (motg->pdata->otg_control == OTG_PHY_CONTROL)
840 /* Enable PHY HV interrupts to wake MPM/Link */
841 phy_ctrl_val |=
842 (PHY_IDHV_INTEN | PHY_OTGSESSVLDHV_INTEN);
Pavankumar Kondeti04aebcb2011-05-04 10:19:49 +0530843
Amit Blay58b31472011-11-18 09:39:39 +0200844 writel_relaxed(phy_ctrl_val & ~PHY_RETEN, USB_PHY_CTRL);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700845 motg->lpm_flags |= PHY_RETENTIONED;
Pavankumar Kondeti04aebcb2011-05-04 10:19:49 +0530846 }
847
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700848 /* Ensure that above operation is completed before turning off clocks */
849 mb();
Ido Shayevitzc5c0f572012-07-31 13:58:45 +0300850 /* Consider clocks on workaround flag only in case of bus suspend */
851 if (!(phy->state == OTG_STATE_B_PERIPHERAL &&
852 test_bit(A_BUS_SUSPEND, &motg->inputs)) ||
853 !motg->pdata->core_clk_always_on_workaround) {
Amit Blay9b6e58b2012-06-18 13:12:49 +0300854 clk_disable_unprepare(motg->pclk);
855 clk_disable_unprepare(motg->core_clk);
Ido Shayevitzc5c0f572012-07-31 13:58:45 +0300856 motg->lpm_flags |= CLOCKS_DOWN;
Amit Blay9b6e58b2012-06-18 13:12:49 +0300857 }
Pavankumar Kondeti87c01042010-12-07 17:53:58 +0530858
Anji jonnala7da3f262011-12-02 17:22:14 -0800859 /* usb phy no more require TCXO clock, hence vote for TCXO disable */
Vijayavardhan Vennapusabbdd6082012-06-06 14:14:25 +0530860 if (!host_bus_suspend) {
861 ret = msm_xo_mode_vote(motg->xo_handle, MSM_XO_MODE_OFF);
862 if (ret)
Steve Muckle75c34ca2012-06-12 14:27:40 -0700863 dev_err(phy->dev, "%s failed to devote for "
Vijayavardhan Vennapusabbdd6082012-06-06 14:14:25 +0530864 "TCXO D0 buffer%d\n", __func__, ret);
865 else
866 motg->lpm_flags |= XO_SHUTDOWN;
867 }
Anji jonnala7da3f262011-12-02 17:22:14 -0800868
Pavankumar Kondeti283146f2012-01-12 12:51:19 +0530869 if (motg->caps & ALLOW_PHY_POWER_COLLAPSE &&
870 !host_bus_suspend && !dcp) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700871 msm_hsusb_ldo_enable(motg, 0);
872 motg->lpm_flags |= PHY_PWR_COLLAPSED;
Anji jonnala0f73cac2011-05-04 10:19:46 +0530873 }
874
Vijayavardhan Vennapusafc464f02011-11-04 21:54:00 +0530875 if (motg->lpm_flags & PHY_RETENTIONED) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700876 msm_hsusb_config_vddcx(0);
Vijayavardhan Vennapusafc464f02011-11-04 21:54:00 +0530877 msm_hsusb_mhl_switch_enable(motg, 0);
878 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700879
Steve Mucklef132c6c2012-06-06 18:30:57 -0700880 if (device_may_wakeup(phy->dev)) {
Pavankumar Kondeti87c01042010-12-07 17:53:58 +0530881 enable_irq_wake(motg->irq);
Manu Gautamf8c45642012-08-10 10:20:56 -0700882 if (motg->async_irq)
883 enable_irq_wake(motg->async_irq);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700884 if (motg->pdata->pmic_id_irq)
885 enable_irq_wake(motg->pdata->pmic_id_irq);
Jack Pham87f202f2012-08-06 00:24:22 -0700886 if (pdata->otg_control == OTG_PHY_CONTROL &&
887 pdata->mpm_otgsessvld_int)
888 msm_mpm_set_pin_wake(pdata->mpm_otgsessvld_int, 1);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700889 }
Pavankumar Kondeti87c01042010-12-07 17:53:58 +0530890 if (bus)
891 clear_bit(HCD_FLAG_HW_ACCESSIBLE, &(bus_to_hcd(bus))->flags);
892
893 atomic_set(&motg->in_lpm, 1);
Manu Gautamf8c45642012-08-10 10:20:56 -0700894 /* Enable ASYNC IRQ (if present) during LPM */
895 if (motg->async_irq)
896 enable_irq(motg->async_irq);
Pavankumar Kondeti87c01042010-12-07 17:53:58 +0530897 enable_irq(motg->irq);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700898 wake_unlock(&motg->wlock);
Pavankumar Kondeti87c01042010-12-07 17:53:58 +0530899
Heikki Krogerus1d4c9292012-02-13 13:24:09 +0200900 dev_info(phy->dev, "USB in low power mode\n");
Pavankumar Kondeti87c01042010-12-07 17:53:58 +0530901
902 return 0;
903}
904
Pavankumar Kondeti87c01042010-12-07 17:53:58 +0530905static int msm_otg_resume(struct msm_otg *motg)
906{
Heikki Krogerus1d4c9292012-02-13 13:24:09 +0200907 struct usb_phy *phy = &motg->phy;
908 struct usb_bus *bus = phy->otg->host;
Jack Pham87f202f2012-08-06 00:24:22 -0700909 struct msm_otg_platform_data *pdata = motg->pdata;
Pavankumar Kondeti87c01042010-12-07 17:53:58 +0530910 int cnt = 0;
911 unsigned temp;
Amit Blay58b31472011-11-18 09:39:39 +0200912 u32 phy_ctrl_val = 0;
Anji jonnala7da3f262011-12-02 17:22:14 -0800913 unsigned ret;
Pavankumar Kondeti87c01042010-12-07 17:53:58 +0530914
915 if (!atomic_read(&motg->in_lpm))
916 return 0;
917
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700918 wake_lock(&motg->wlock);
Anji jonnala0f73cac2011-05-04 10:19:46 +0530919
Anji jonnala7da3f262011-12-02 17:22:14 -0800920 /* Vote for TCXO when waking up the phy */
Vijayavardhan Vennapusabbdd6082012-06-06 14:14:25 +0530921 if (motg->lpm_flags & XO_SHUTDOWN) {
922 ret = msm_xo_mode_vote(motg->xo_handle, MSM_XO_MODE_ON);
923 if (ret)
Steve Muckle75c34ca2012-06-12 14:27:40 -0700924 dev_err(phy->dev, "%s failed to vote for "
Vijayavardhan Vennapusabbdd6082012-06-06 14:14:25 +0530925 "TCXO D0 buffer%d\n", __func__, ret);
926 motg->lpm_flags &= ~XO_SHUTDOWN;
927 }
Pavankumar Kondeti87c01042010-12-07 17:53:58 +0530928
Ido Shayevitzc5c0f572012-07-31 13:58:45 +0300929 if (motg->lpm_flags & CLOCKS_DOWN) {
Amit Blay9b6e58b2012-06-18 13:12:49 +0300930 clk_prepare_enable(motg->core_clk);
931 clk_prepare_enable(motg->pclk);
Ido Shayevitzc5c0f572012-07-31 13:58:45 +0300932 motg->lpm_flags &= ~CLOCKS_DOWN;
Amit Blay9b6e58b2012-06-18 13:12:49 +0300933 }
Pavankumar Kondeti87c01042010-12-07 17:53:58 +0530934
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700935 if (motg->lpm_flags & PHY_PWR_COLLAPSED) {
936 msm_hsusb_ldo_enable(motg, 1);
937 motg->lpm_flags &= ~PHY_PWR_COLLAPSED;
938 }
939
940 if (motg->lpm_flags & PHY_RETENTIONED) {
Vijayavardhan Vennapusafc464f02011-11-04 21:54:00 +0530941 msm_hsusb_mhl_switch_enable(motg, 1);
Pavankumar Kondeti04aebcb2011-05-04 10:19:49 +0530942 msm_hsusb_config_vddcx(1);
Amit Blay58b31472011-11-18 09:39:39 +0200943 phy_ctrl_val = readl_relaxed(USB_PHY_CTRL);
944 phy_ctrl_val |= PHY_RETEN;
945 if (motg->pdata->otg_control == OTG_PHY_CONTROL)
946 /* Disable PHY HV interrupts */
947 phy_ctrl_val &=
948 ~(PHY_IDHV_INTEN | PHY_OTGSESSVLDHV_INTEN);
949 writel_relaxed(phy_ctrl_val, USB_PHY_CTRL);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700950 motg->lpm_flags &= ~PHY_RETENTIONED;
Pavankumar Kondeti04aebcb2011-05-04 10:19:49 +0530951 }
952
Pavankumar Kondeti87c01042010-12-07 17:53:58 +0530953 temp = readl(USB_USBCMD);
954 temp &= ~ASYNC_INTR_CTRL;
955 temp &= ~ULPI_STP_CTRL;
956 writel(temp, USB_USBCMD);
957
958 /*
959 * PHY comes out of low power mode (LPM) in case of wakeup
960 * from asynchronous interrupt.
961 */
962 if (!(readl(USB_PORTSC) & PORTSC_PHCD))
963 goto skip_phy_resume;
964
965 writel(readl(USB_PORTSC) & ~PORTSC_PHCD, USB_PORTSC);
966 while (cnt < PHY_RESUME_TIMEOUT_USEC) {
967 if (!(readl(USB_PORTSC) & PORTSC_PHCD))
968 break;
969 udelay(1);
970 cnt++;
971 }
972
973 if (cnt >= PHY_RESUME_TIMEOUT_USEC) {
974 /*
975 * This is a fatal error. Reset the link and
976 * PHY. USB state can not be restored. Re-insertion
977 * of USB cable is the only way to get USB working.
978 */
Heikki Krogerus1d4c9292012-02-13 13:24:09 +0200979 dev_err(phy->dev, "Unable to resume USB."
Pavankumar Kondeti87c01042010-12-07 17:53:58 +0530980 "Re-plugin the cable\n");
Heikki Krogerus1d4c9292012-02-13 13:24:09 +0200981 msm_otg_reset(phy);
Pavankumar Kondeti87c01042010-12-07 17:53:58 +0530982 }
983
984skip_phy_resume:
Steve Mucklef132c6c2012-06-06 18:30:57 -0700985 if (device_may_wakeup(phy->dev)) {
Pavankumar Kondeti87c01042010-12-07 17:53:58 +0530986 disable_irq_wake(motg->irq);
Manu Gautamf8c45642012-08-10 10:20:56 -0700987 if (motg->async_irq)
988 disable_irq_wake(motg->async_irq);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700989 if (motg->pdata->pmic_id_irq)
990 disable_irq_wake(motg->pdata->pmic_id_irq);
Jack Pham87f202f2012-08-06 00:24:22 -0700991 if (pdata->otg_control == OTG_PHY_CONTROL &&
992 pdata->mpm_otgsessvld_int)
993 msm_mpm_set_pin_wake(pdata->mpm_otgsessvld_int, 0);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700994 }
Pavankumar Kondeti87c01042010-12-07 17:53:58 +0530995 if (bus)
996 set_bit(HCD_FLAG_HW_ACCESSIBLE, &(bus_to_hcd(bus))->flags);
997
Pavankumar Kondeti2ce2c3a2011-05-02 11:56:33 +0530998 atomic_set(&motg->in_lpm, 0);
999
Pavankumar Kondeti87c01042010-12-07 17:53:58 +05301000 if (motg->async_int) {
Manu Gautamf8c45642012-08-10 10:20:56 -07001001 /* Match the disable_irq call from ISR */
1002 enable_irq(motg->async_int);
Pavankumar Kondeti87c01042010-12-07 17:53:58 +05301003 motg->async_int = 0;
Pavankumar Kondeti87c01042010-12-07 17:53:58 +05301004 }
1005
Manu Gautamf8c45642012-08-10 10:20:56 -07001006 /* If ASYNC IRQ is present then keep it enabled only during LPM */
1007 if (motg->async_irq)
1008 disable_irq(motg->async_irq);
1009
Heikki Krogerus1d4c9292012-02-13 13:24:09 +02001010 dev_info(phy->dev, "USB exited from low power mode\n");
Pavankumar Kondeti87c01042010-12-07 17:53:58 +05301011
1012 return 0;
1013}
Pavankumar Kondeti70187732011-02-15 09:42:34 +05301014#endif
Pavankumar Kondeti87c01042010-12-07 17:53:58 +05301015
Abhijeet Dharmapurikar5e96aaa2012-06-26 11:21:03 -07001016static int msm_otg_notify_host_mode(struct msm_otg *motg, bool host_mode)
1017{
1018 if (!psy)
1019 goto psy_not_supported;
1020
1021 if (host_mode)
1022 power_supply_set_scope(psy, POWER_SUPPLY_SCOPE_SYSTEM);
1023 else
1024 power_supply_set_scope(psy, POWER_SUPPLY_SCOPE_DEVICE);
1025
1026psy_not_supported:
1027 dev_dbg(motg->phy.dev, "Power Supply doesn't support USB charger\n");
1028 return -ENXIO;
1029}
1030
David Keitel081a3e22012-04-18 12:37:07 -07001031static int msm_otg_notify_chg_type(struct msm_otg *motg)
1032{
1033 static int charger_type;
1034 /*
1035 * TODO
1036 * Unify OTG driver charger types and power supply charger types
1037 */
1038 if (charger_type == motg->chg_type)
1039 return 0;
1040
1041 if (motg->chg_type == USB_SDP_CHARGER)
1042 charger_type = POWER_SUPPLY_TYPE_USB;
1043 else if (motg->chg_type == USB_CDP_CHARGER)
1044 charger_type = POWER_SUPPLY_TYPE_USB_CDP;
Pavankumar Kondeti9ec21d32012-05-07 15:50:23 +05301045 else if (motg->chg_type == USB_DCP_CHARGER ||
1046 motg->chg_type == USB_PROPRIETARY_CHARGER)
David Keitel081a3e22012-04-18 12:37:07 -07001047 charger_type = POWER_SUPPLY_TYPE_USB_DCP;
1048 else if ((motg->chg_type == USB_ACA_DOCK_CHARGER ||
1049 motg->chg_type == USB_ACA_A_CHARGER ||
1050 motg->chg_type == USB_ACA_B_CHARGER ||
1051 motg->chg_type == USB_ACA_C_CHARGER))
1052 charger_type = POWER_SUPPLY_TYPE_USB_ACA;
1053 else
1054 charger_type = POWER_SUPPLY_TYPE_BATTERY;
1055
1056 return pm8921_set_usb_power_supply_type(charger_type);
1057}
1058
Amit Blay0f7edf72012-01-15 10:11:27 +02001059static int msm_otg_notify_power_supply(struct msm_otg *motg, unsigned mA)
1060{
Amit Blay0f7edf72012-01-15 10:11:27 +02001061
Amit Blay0f7edf72012-01-15 10:11:27 +02001062 if (!psy)
1063 goto psy_not_supported;
1064
1065 if (motg->cur_power == 0 && mA > 0) {
1066 /* Enable charging */
1067 if (power_supply_set_online(psy, true))
1068 goto psy_not_supported;
1069 } else if (motg->cur_power > 0 && mA == 0) {
1070 /* Disable charging */
1071 if (power_supply_set_online(psy, false))
1072 goto psy_not_supported;
1073 return 0;
1074 }
1075 /* Set max current limit */
1076 if (power_supply_set_current_limit(psy, 1000*mA))
1077 goto psy_not_supported;
1078
1079 return 0;
1080
1081psy_not_supported:
Steve Mucklef132c6c2012-06-06 18:30:57 -07001082 dev_dbg(motg->phy.dev, "Power Supply doesn't support USB charger\n");
Amit Blay0f7edf72012-01-15 10:11:27 +02001083 return -ENXIO;
1084}
1085
Pavankumar Kondetid8608522011-05-04 10:19:47 +05301086static void msm_otg_notify_charger(struct msm_otg *motg, unsigned mA)
1087{
Steve Mucklef132c6c2012-06-06 18:30:57 -07001088 struct usb_gadget *g = motg->phy.otg->gadget;
Vijayavardhan Vennapusaa3152032012-03-05 16:29:30 +05301089
1090 if (g && g->is_a_peripheral)
1091 return;
1092
Pavankumar Kondetiaa449e12011-11-04 11:09:26 +05301093 if ((motg->chg_type == USB_ACA_DOCK_CHARGER ||
1094 motg->chg_type == USB_ACA_A_CHARGER ||
1095 motg->chg_type == USB_ACA_B_CHARGER ||
1096 motg->chg_type == USB_ACA_C_CHARGER) &&
1097 mA > IDEV_ACA_CHG_LIMIT)
1098 mA = IDEV_ACA_CHG_LIMIT;
1099
David Keitel081a3e22012-04-18 12:37:07 -07001100 if (msm_otg_notify_chg_type(motg))
Steve Mucklef132c6c2012-06-06 18:30:57 -07001101 dev_err(motg->phy.dev,
David Keitel081a3e22012-04-18 12:37:07 -07001102 "Failed notifying %d charger type to PMIC\n",
1103 motg->chg_type);
1104
Pavankumar Kondetid8608522011-05-04 10:19:47 +05301105 if (motg->cur_power == mA)
1106 return;
1107
Heikki Krogerus1d4c9292012-02-13 13:24:09 +02001108 dev_info(motg->phy.dev, "Avail curr from USB = %u\n", mA);
Amit Blay0f7edf72012-01-15 10:11:27 +02001109
1110 /*
1111 * Use Power Supply API if supported, otherwise fallback
1112 * to legacy pm8921 API.
1113 */
1114 if (msm_otg_notify_power_supply(motg, mA))
1115 pm8921_charger_vbus_draw(mA);
1116
Pavankumar Kondetid8608522011-05-04 10:19:47 +05301117 motg->cur_power = mA;
1118}
1119
Heikki Krogerus1d4c9292012-02-13 13:24:09 +02001120static int msm_otg_set_power(struct usb_phy *phy, unsigned mA)
Pavankumar Kondetid8608522011-05-04 10:19:47 +05301121{
Heikki Krogerus1d4c9292012-02-13 13:24:09 +02001122 struct msm_otg *motg = container_of(phy, struct msm_otg, phy);
Pavankumar Kondetid8608522011-05-04 10:19:47 +05301123
1124 /*
1125 * Gadget driver uses set_power method to notify about the
1126 * available current based on suspend/configured states.
1127 *
1128 * IDEV_CHG can be drawn irrespective of suspend/un-configured
1129 * states when CDP/ACA is connected.
1130 */
1131 if (motg->chg_type == USB_SDP_CHARGER)
1132 msm_otg_notify_charger(motg, mA);
1133
1134 return 0;
1135}
1136
Steve Mucklef132c6c2012-06-06 18:30:57 -07001137static void msm_otg_start_host(struct usb_otg *otg, int on)
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05301138{
Steve Mucklef132c6c2012-06-06 18:30:57 -07001139 struct msm_otg *motg = container_of(otg->phy, struct msm_otg, phy);
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05301140 struct msm_otg_platform_data *pdata = motg->pdata;
1141 struct usb_hcd *hcd;
1142
1143 if (!otg->host)
1144 return;
1145
1146 hcd = bus_to_hcd(otg->host);
1147
1148 if (on) {
Steve Mucklef132c6c2012-06-06 18:30:57 -07001149 dev_dbg(otg->phy->dev, "host on\n");
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05301150
Vijayavardhan Vennapusa03171c72012-04-26 14:44:48 +05301151 if (pdata->otg_control == OTG_PHY_CONTROL)
Steve Mucklef132c6c2012-06-06 18:30:57 -07001152 ulpi_write(otg->phy, OTG_COMP_DISABLE,
Vijayavardhan Vennapusa03171c72012-04-26 14:44:48 +05301153 ULPI_SET(ULPI_PWR_CLK_MNG_REG));
1154
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05301155 /*
1156 * Some boards have a switch cotrolled by gpio
1157 * to enable/disable internal HUB. Enable internal
1158 * HUB before kicking the host.
1159 */
1160 if (pdata->setup_gpio)
1161 pdata->setup_gpio(OTG_STATE_A_HOST);
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05301162 usb_add_hcd(hcd, hcd->irq, IRQF_SHARED);
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05301163 } else {
Steve Mucklef132c6c2012-06-06 18:30:57 -07001164 dev_dbg(otg->phy->dev, "host off\n");
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05301165
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05301166 usb_remove_hcd(hcd);
Pavankumar Kondetiaa449e12011-11-04 11:09:26 +05301167 /* HCD core reset all bits of PORTSC. select ULPI phy */
1168 writel_relaxed(0x80000000, USB_PORTSC);
1169
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05301170 if (pdata->setup_gpio)
1171 pdata->setup_gpio(OTG_STATE_UNDEFINED);
Vijayavardhan Vennapusa03171c72012-04-26 14:44:48 +05301172
1173 if (pdata->otg_control == OTG_PHY_CONTROL)
Steve Mucklef132c6c2012-06-06 18:30:57 -07001174 ulpi_write(otg->phy, OTG_COMP_DISABLE,
Vijayavardhan Vennapusa03171c72012-04-26 14:44:48 +05301175 ULPI_CLR(ULPI_PWR_CLK_MNG_REG));
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05301176 }
1177}
1178
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001179static int msm_otg_usbdev_notify(struct notifier_block *self,
1180 unsigned long action, void *priv)
1181{
1182 struct msm_otg *motg = container_of(self, struct msm_otg, usbdev_nb);
Steve Mucklef132c6c2012-06-06 18:30:57 -07001183 struct usb_otg *otg = motg->phy.otg;
Pavankumar Kondetiaa449e12011-11-04 11:09:26 +05301184 struct usb_device *udev = priv;
1185
Pavankumar Kondetiaa449e12011-11-04 11:09:26 +05301186 if (action == USB_BUS_ADD || action == USB_BUS_REMOVE)
1187 goto out;
1188
Steve Mucklef132c6c2012-06-06 18:30:57 -07001189 if (udev->bus != otg->host)
Pavankumar Kondetiaa449e12011-11-04 11:09:26 +05301190 goto out;
1191 /*
1192 * Interested in devices connected directly to the root hub.
1193 * ACA dock can supply IDEV_CHG irrespective devices connected
1194 * on the accessory port.
1195 */
1196 if (!udev->parent || udev->parent->parent ||
1197 motg->chg_type == USB_ACA_DOCK_CHARGER)
1198 goto out;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001199
1200 switch (action) {
1201 case USB_DEVICE_ADD:
Vijayavardhan Vennapusaa3152032012-03-05 16:29:30 +05301202 if (aca_enabled())
1203 usb_disable_autosuspend(udev);
Steve Mucklef132c6c2012-06-06 18:30:57 -07001204 if (otg->phy->state == OTG_STATE_A_WAIT_BCON) {
Vijayavardhan Vennapusaa3152032012-03-05 16:29:30 +05301205 pr_debug("B_CONN set\n");
1206 set_bit(B_CONN, &motg->inputs);
1207 msm_otg_del_timer(motg);
Steve Mucklef132c6c2012-06-06 18:30:57 -07001208 otg->phy->state = OTG_STATE_A_HOST;
Vijayavardhan Vennapusaa3152032012-03-05 16:29:30 +05301209 /*
1210 * OTG PET: A-device must end session within
1211 * 10 sec after PET enumeration.
1212 */
1213 if (udev->quirks & USB_QUIRK_OTG_PET)
1214 msm_otg_start_timer(motg, TA_TST_MAINT,
1215 A_TST_MAINT);
1216 }
Pavankumar Kondetiaa449e12011-11-04 11:09:26 +05301217 /* fall through */
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001218 case USB_DEVICE_CONFIG:
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001219 if (udev->actconfig)
1220 motg->mA_port = udev->actconfig->desc.bMaxPower * 2;
1221 else
1222 motg->mA_port = IUNIT;
Steve Mucklef132c6c2012-06-06 18:30:57 -07001223 if (otg->phy->state == OTG_STATE_B_HOST)
Vijayavardhan Vennapusaa3152032012-03-05 16:29:30 +05301224 msm_otg_del_timer(motg);
Pavankumar Kondetiaa449e12011-11-04 11:09:26 +05301225 break;
1226 case USB_DEVICE_REMOVE:
Steve Mucklef132c6c2012-06-06 18:30:57 -07001227 if ((otg->phy->state == OTG_STATE_A_HOST) ||
1228 (otg->phy->state == OTG_STATE_A_SUSPEND)) {
Vijayavardhan Vennapusaa3152032012-03-05 16:29:30 +05301229 pr_debug("B_CONN clear\n");
1230 clear_bit(B_CONN, &motg->inputs);
1231 /*
1232 * OTG PET: A-device must end session after
1233 * PET disconnection if it is enumerated
1234 * with bcdDevice[0] = 1. USB core sets
1235 * bus->otg_vbus_off for us. clear it here.
1236 */
1237 if (udev->bus->otg_vbus_off) {
1238 udev->bus->otg_vbus_off = 0;
1239 set_bit(A_BUS_DROP, &motg->inputs);
1240 }
1241 queue_work(system_nrt_wq, &motg->sm_work);
1242 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001243 default:
1244 break;
1245 }
Pavankumar Kondetiaa449e12011-11-04 11:09:26 +05301246 if (test_bit(ID_A, &motg->inputs))
1247 msm_otg_notify_charger(motg, IDEV_ACA_CHG_MAX -
1248 motg->mA_port);
1249out:
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001250 return NOTIFY_OK;
1251}
1252
Mayank Ranae3926882011-12-26 09:47:54 +05301253static void msm_hsusb_vbus_power(struct msm_otg *motg, bool on)
1254{
1255 int ret;
1256 static bool vbus_is_on;
1257
1258 if (vbus_is_on == on)
1259 return;
1260
1261 if (motg->pdata->vbus_power) {
Mayank Rana91f597e2012-01-20 10:12:06 +05301262 ret = motg->pdata->vbus_power(on);
1263 if (!ret)
1264 vbus_is_on = on;
Mayank Ranae3926882011-12-26 09:47:54 +05301265 return;
1266 }
1267
1268 if (!vbus_otg) {
1269 pr_err("vbus_otg is NULL.");
1270 return;
1271 }
1272
Abhijeet Dharmapurikarbe054882012-01-03 20:27:07 -08001273 /*
1274 * if entering host mode tell the charger to not draw any current
Abhijeet Dharmapurikar6d941212012-03-05 10:30:56 -08001275 * from usb before turning on the boost.
1276 * if exiting host mode disable the boost before enabling to draw
1277 * current from the source.
Abhijeet Dharmapurikarbe054882012-01-03 20:27:07 -08001278 */
Mayank Ranae3926882011-12-26 09:47:54 +05301279 if (on) {
Abhijeet Dharmapurikar5e96aaa2012-06-26 11:21:03 -07001280 msm_otg_notify_host_mode(motg, on);
Mayank Ranae3926882011-12-26 09:47:54 +05301281 ret = regulator_enable(vbus_otg);
1282 if (ret) {
1283 pr_err("unable to enable vbus_otg\n");
1284 return;
1285 }
1286 vbus_is_on = true;
1287 } else {
1288 ret = regulator_disable(vbus_otg);
1289 if (ret) {
1290 pr_err("unable to disable vbus_otg\n");
1291 return;
1292 }
Abhijeet Dharmapurikar5e96aaa2012-06-26 11:21:03 -07001293 msm_otg_notify_host_mode(motg, on);
Mayank Ranae3926882011-12-26 09:47:54 +05301294 vbus_is_on = false;
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05301295 }
1296}
1297
Heikki Krogerus1d4c9292012-02-13 13:24:09 +02001298static int msm_otg_set_host(struct usb_otg *otg, struct usb_bus *host)
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05301299{
Heikki Krogerus1d4c9292012-02-13 13:24:09 +02001300 struct msm_otg *motg = container_of(otg->phy, struct msm_otg, phy);
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05301301 struct usb_hcd *hcd;
1302
1303 /*
1304 * Fail host registration if this board can support
1305 * only peripheral configuration.
1306 */
1307 if (motg->pdata->mode == USB_PERIPHERAL) {
Heikki Krogerus1d4c9292012-02-13 13:24:09 +02001308 dev_info(otg->phy->dev, "Host mode is not supported\n");
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05301309 return -ENODEV;
1310 }
1311
Mayank Ranae3926882011-12-26 09:47:54 +05301312 if (!motg->pdata->vbus_power && host) {
Steve Mucklef132c6c2012-06-06 18:30:57 -07001313 vbus_otg = devm_regulator_get(motg->phy.dev, "vbus_otg");
Mayank Ranae3926882011-12-26 09:47:54 +05301314 if (IS_ERR(vbus_otg)) {
1315 pr_err("Unable to get vbus_otg\n");
1316 return -ENODEV;
1317 }
1318 }
1319
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05301320 if (!host) {
Heikki Krogerus1d4c9292012-02-13 13:24:09 +02001321 if (otg->phy->state == OTG_STATE_A_HOST) {
1322 pm_runtime_get_sync(otg->phy->dev);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001323 usb_unregister_notify(&motg->usbdev_nb);
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05301324 msm_otg_start_host(otg, 0);
Mayank Ranae3926882011-12-26 09:47:54 +05301325 msm_hsusb_vbus_power(motg, 0);
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05301326 otg->host = NULL;
Heikki Krogerus1d4c9292012-02-13 13:24:09 +02001327 otg->phy->state = OTG_STATE_UNDEFINED;
Vijayavardhan Vennapusaa3152032012-03-05 16:29:30 +05301328 queue_work(system_nrt_wq, &motg->sm_work);
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05301329 } else {
1330 otg->host = NULL;
1331 }
1332
1333 return 0;
1334 }
1335
1336 hcd = bus_to_hcd(host);
1337 hcd->power_budget = motg->pdata->power_budget;
1338
Vijayavardhan Vennapusaa3152032012-03-05 16:29:30 +05301339#ifdef CONFIG_USB_OTG
1340 host->otg_port = 1;
1341#endif
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001342 motg->usbdev_nb.notifier_call = msm_otg_usbdev_notify;
1343 usb_register_notify(&motg->usbdev_nb);
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05301344 otg->host = host;
Heikki Krogerus1d4c9292012-02-13 13:24:09 +02001345 dev_dbg(otg->phy->dev, "host driver registered w/ tranceiver\n");
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05301346
1347 /*
1348 * Kick the state machine work, if peripheral is not supported
1349 * or peripheral is already registered with us.
1350 */
Pavankumar Kondeti87c01042010-12-07 17:53:58 +05301351 if (motg->pdata->mode == USB_HOST || otg->gadget) {
Heikki Krogerus1d4c9292012-02-13 13:24:09 +02001352 pm_runtime_get_sync(otg->phy->dev);
Vijayavardhan Vennapusaa3152032012-03-05 16:29:30 +05301353 queue_work(system_nrt_wq, &motg->sm_work);
Pavankumar Kondeti87c01042010-12-07 17:53:58 +05301354 }
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05301355
1356 return 0;
1357}
1358
Steve Mucklef132c6c2012-06-06 18:30:57 -07001359static void msm_otg_start_peripheral(struct usb_otg *otg, int on)
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05301360{
Manu Gautamcd82e9d2011-12-20 14:17:28 +05301361 int ret;
Steve Mucklef132c6c2012-06-06 18:30:57 -07001362 struct msm_otg *motg = container_of(otg->phy, struct msm_otg, phy);
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05301363 struct msm_otg_platform_data *pdata = motg->pdata;
1364
1365 if (!otg->gadget)
1366 return;
1367
1368 if (on) {
Steve Mucklef132c6c2012-06-06 18:30:57 -07001369 dev_dbg(otg->phy->dev, "gadget on\n");
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05301370 /*
1371 * Some boards have a switch cotrolled by gpio
1372 * to enable/disable internal HUB. Disable internal
1373 * HUB before kicking the gadget.
1374 */
1375 if (pdata->setup_gpio)
1376 pdata->setup_gpio(OTG_STATE_B_PERIPHERAL);
Ofir Cohen94213a72012-05-03 14:26:32 +03001377
Manu Gautamcd82e9d2011-12-20 14:17:28 +05301378 /* Configure BUS performance parameters for MAX bandwidth */
Manu Gautam8bdcc592012-03-06 11:26:06 +05301379 if (motg->bus_perf_client && debug_bus_voting_enabled) {
Manu Gautamcd82e9d2011-12-20 14:17:28 +05301380 ret = msm_bus_scale_client_update_request(
1381 motg->bus_perf_client, 1);
1382 if (ret)
Steve Mucklef132c6c2012-06-06 18:30:57 -07001383 dev_err(motg->phy.dev, "%s: Failed to vote for "
Manu Gautamcd82e9d2011-12-20 14:17:28 +05301384 "bus bandwidth %d\n", __func__, ret);
1385 }
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05301386 usb_gadget_vbus_connect(otg->gadget);
1387 } else {
Steve Mucklef132c6c2012-06-06 18:30:57 -07001388 dev_dbg(otg->phy->dev, "gadget off\n");
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05301389 usb_gadget_vbus_disconnect(otg->gadget);
Manu Gautamcd82e9d2011-12-20 14:17:28 +05301390 /* Configure BUS performance parameters to default */
1391 if (motg->bus_perf_client) {
1392 ret = msm_bus_scale_client_update_request(
1393 motg->bus_perf_client, 0);
1394 if (ret)
Steve Mucklef132c6c2012-06-06 18:30:57 -07001395 dev_err(motg->phy.dev, "%s: Failed to devote "
Manu Gautamcd82e9d2011-12-20 14:17:28 +05301396 "for bus bw %d\n", __func__, ret);
1397 }
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05301398 if (pdata->setup_gpio)
1399 pdata->setup_gpio(OTG_STATE_UNDEFINED);
1400 }
1401
1402}
1403
Heikki Krogerus1d4c9292012-02-13 13:24:09 +02001404static int msm_otg_set_peripheral(struct usb_otg *otg,
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05301405 struct usb_gadget *gadget)
1406{
Heikki Krogerus1d4c9292012-02-13 13:24:09 +02001407 struct msm_otg *motg = container_of(otg->phy, struct msm_otg, phy);
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05301408
1409 /*
1410 * Fail peripheral registration if this board can support
1411 * only host configuration.
1412 */
1413 if (motg->pdata->mode == USB_HOST) {
Heikki Krogerus1d4c9292012-02-13 13:24:09 +02001414 dev_info(otg->phy->dev, "Peripheral mode is not supported\n");
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05301415 return -ENODEV;
1416 }
1417
1418 if (!gadget) {
Heikki Krogerus1d4c9292012-02-13 13:24:09 +02001419 if (otg->phy->state == OTG_STATE_B_PERIPHERAL) {
1420 pm_runtime_get_sync(otg->phy->dev);
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05301421 msm_otg_start_peripheral(otg, 0);
1422 otg->gadget = NULL;
Heikki Krogerus1d4c9292012-02-13 13:24:09 +02001423 otg->phy->state = OTG_STATE_UNDEFINED;
Vijayavardhan Vennapusaa3152032012-03-05 16:29:30 +05301424 queue_work(system_nrt_wq, &motg->sm_work);
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05301425 } else {
1426 otg->gadget = NULL;
1427 }
1428
1429 return 0;
1430 }
1431 otg->gadget = gadget;
Heikki Krogerus1d4c9292012-02-13 13:24:09 +02001432 dev_dbg(otg->phy->dev, "peripheral driver registered w/ tranceiver\n");
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05301433
1434 /*
1435 * Kick the state machine work, if host is not supported
1436 * or host is already registered with us.
1437 */
Pavankumar Kondeti87c01042010-12-07 17:53:58 +05301438 if (motg->pdata->mode == USB_PERIPHERAL || otg->host) {
Heikki Krogerus1d4c9292012-02-13 13:24:09 +02001439 pm_runtime_get_sync(otg->phy->dev);
Vijayavardhan Vennapusaa3152032012-03-05 16:29:30 +05301440 queue_work(system_nrt_wq, &motg->sm_work);
Pavankumar Kondeti87c01042010-12-07 17:53:58 +05301441 }
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05301442
1443 return 0;
1444}
1445
Pavankumar Kondeti2aec9f32012-06-13 09:06:03 +05301446static int msm_otg_mhl_register_callback(struct msm_otg *motg,
1447 void (*callback)(int on))
1448{
1449 struct usb_phy *phy = &motg->phy;
1450 int ret;
1451
1452 if (motg->pdata->otg_control != OTG_PMIC_CONTROL ||
1453 !motg->pdata->pmic_id_irq) {
1454 dev_dbg(phy->dev, "MHL can not be supported without PMIC Id\n");
1455 return -ENODEV;
1456 }
1457
1458 if (!motg->pdata->mhl_dev_name) {
1459 dev_dbg(phy->dev, "MHL device name does not exist.\n");
1460 return -ENODEV;
1461 }
1462
1463 if (callback)
1464 ret = mhl_register_callback(motg->pdata->mhl_dev_name,
1465 callback);
1466 else
1467 ret = mhl_unregister_callback(motg->pdata->mhl_dev_name);
1468
1469 if (ret)
1470 dev_dbg(phy->dev, "mhl_register_callback(%s) return error=%d\n",
1471 motg->pdata->mhl_dev_name, ret);
1472 else
1473 motg->mhl_enabled = true;
1474
1475 return ret;
1476}
1477
1478static void msm_otg_mhl_notify_online(int on)
1479{
1480 struct msm_otg *motg = the_msm_otg;
1481 struct usb_phy *phy = &motg->phy;
1482 bool queue = false;
1483
1484 dev_dbg(phy->dev, "notify MHL %s%s\n", on ? "" : "dis", "connected");
1485
1486 if (on) {
1487 set_bit(MHL, &motg->inputs);
1488 } else {
1489 clear_bit(MHL, &motg->inputs);
1490 queue = true;
1491 }
1492
1493 if (queue && phy->state != OTG_STATE_UNDEFINED)
1494 schedule_work(&motg->sm_work);
1495}
1496
1497static bool msm_otg_is_mhl(struct msm_otg *motg)
1498{
1499 struct usb_phy *phy = &motg->phy;
1500 int is_mhl, ret;
1501
1502 ret = mhl_device_discovery(motg->pdata->mhl_dev_name, &is_mhl);
1503 if (ret || is_mhl != MHL_DISCOVERY_RESULT_MHL) {
1504 /*
1505 * MHL driver calls our callback saying that MHL connected
1506 * if RID_GND is detected. But at later part of discovery
1507 * it may figure out MHL is not connected and returns
1508 * false. Hence clear MHL input here.
1509 */
1510 clear_bit(MHL, &motg->inputs);
1511 dev_dbg(phy->dev, "MHL device not found\n");
1512 return false;
1513 }
1514
1515 set_bit(MHL, &motg->inputs);
1516 dev_dbg(phy->dev, "MHL device found\n");
1517 return true;
1518}
1519
1520static bool msm_chg_mhl_detect(struct msm_otg *motg)
1521{
1522 bool ret, id;
1523 unsigned long flags;
1524
1525 if (!motg->mhl_enabled)
1526 return false;
1527
1528 local_irq_save(flags);
1529 id = irq_read_line(motg->pdata->pmic_id_irq);
1530 local_irq_restore(flags);
1531
1532 if (id)
1533 return false;
1534
1535 mhl_det_in_progress = true;
1536 ret = msm_otg_is_mhl(motg);
1537 mhl_det_in_progress = false;
1538
1539 return ret;
1540}
1541
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001542static bool msm_chg_aca_detect(struct msm_otg *motg)
1543{
Steve Mucklef132c6c2012-06-06 18:30:57 -07001544 struct usb_phy *phy = &motg->phy;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001545 u32 int_sts;
1546 bool ret = false;
1547
Pavankumar Kondetiaa449e12011-11-04 11:09:26 +05301548 if (!aca_enabled())
1549 goto out;
1550
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001551 if (motg->pdata->phy_type == CI_45NM_INTEGRATED_PHY)
1552 goto out;
1553
Steve Mucklef132c6c2012-06-06 18:30:57 -07001554 int_sts = ulpi_read(phy, 0x87);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001555 switch (int_sts & 0x1C) {
1556 case 0x08:
1557 if (!test_and_set_bit(ID_A, &motg->inputs)) {
Steve Mucklef132c6c2012-06-06 18:30:57 -07001558 dev_dbg(phy->dev, "ID_A\n");
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001559 motg->chg_type = USB_ACA_A_CHARGER;
1560 motg->chg_state = USB_CHG_STATE_DETECTED;
1561 clear_bit(ID_B, &motg->inputs);
1562 clear_bit(ID_C, &motg->inputs);
Pavankumar Kondetiaa449e12011-11-04 11:09:26 +05301563 set_bit(ID, &motg->inputs);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001564 ret = true;
1565 }
1566 break;
1567 case 0x0C:
1568 if (!test_and_set_bit(ID_B, &motg->inputs)) {
Steve Mucklef132c6c2012-06-06 18:30:57 -07001569 dev_dbg(phy->dev, "ID_B\n");
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001570 motg->chg_type = USB_ACA_B_CHARGER;
1571 motg->chg_state = USB_CHG_STATE_DETECTED;
1572 clear_bit(ID_A, &motg->inputs);
1573 clear_bit(ID_C, &motg->inputs);
Pavankumar Kondetiaa449e12011-11-04 11:09:26 +05301574 set_bit(ID, &motg->inputs);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001575 ret = true;
1576 }
1577 break;
1578 case 0x10:
1579 if (!test_and_set_bit(ID_C, &motg->inputs)) {
Steve Mucklef132c6c2012-06-06 18:30:57 -07001580 dev_dbg(phy->dev, "ID_C\n");
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001581 motg->chg_type = USB_ACA_C_CHARGER;
1582 motg->chg_state = USB_CHG_STATE_DETECTED;
1583 clear_bit(ID_A, &motg->inputs);
1584 clear_bit(ID_B, &motg->inputs);
Pavankumar Kondetiaa449e12011-11-04 11:09:26 +05301585 set_bit(ID, &motg->inputs);
1586 ret = true;
1587 }
1588 break;
1589 case 0x04:
1590 if (test_and_clear_bit(ID, &motg->inputs)) {
Steve Mucklef132c6c2012-06-06 18:30:57 -07001591 dev_dbg(phy->dev, "ID_GND\n");
Pavankumar Kondetiaa449e12011-11-04 11:09:26 +05301592 motg->chg_type = USB_INVALID_CHARGER;
1593 motg->chg_state = USB_CHG_STATE_UNDEFINED;
1594 clear_bit(ID_A, &motg->inputs);
1595 clear_bit(ID_B, &motg->inputs);
1596 clear_bit(ID_C, &motg->inputs);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001597 ret = true;
1598 }
1599 break;
1600 default:
1601 ret = test_and_clear_bit(ID_A, &motg->inputs) |
1602 test_and_clear_bit(ID_B, &motg->inputs) |
Pavankumar Kondetiaa449e12011-11-04 11:09:26 +05301603 test_and_clear_bit(ID_C, &motg->inputs) |
1604 !test_and_set_bit(ID, &motg->inputs);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001605 if (ret) {
Steve Mucklef132c6c2012-06-06 18:30:57 -07001606 dev_dbg(phy->dev, "ID A/B/C/GND is no more\n");
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001607 motg->chg_type = USB_INVALID_CHARGER;
1608 motg->chg_state = USB_CHG_STATE_UNDEFINED;
1609 }
1610 }
1611out:
1612 return ret;
1613}
1614
1615static void msm_chg_enable_aca_det(struct msm_otg *motg)
1616{
Steve Mucklef132c6c2012-06-06 18:30:57 -07001617 struct usb_phy *phy = &motg->phy;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001618
Pavankumar Kondetiaa449e12011-11-04 11:09:26 +05301619 if (!aca_enabled())
1620 return;
1621
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001622 switch (motg->pdata->phy_type) {
1623 case SNPS_28NM_INTEGRATED_PHY:
Pavankumar Kondetiaa449e12011-11-04 11:09:26 +05301624 /* Disable ID_GND in link and PHY */
1625 writel_relaxed(readl_relaxed(USB_OTGSC) & ~(OTGSC_IDPU |
1626 OTGSC_IDIE), USB_OTGSC);
Steve Mucklef132c6c2012-06-06 18:30:57 -07001627 ulpi_write(phy, 0x01, 0x0C);
1628 ulpi_write(phy, 0x10, 0x0F);
1629 ulpi_write(phy, 0x10, 0x12);
Pavankumar Kondeti446f4542012-02-01 13:57:13 +05301630 /* Disable PMIC ID pull-up */
1631 pm8xxx_usb_id_pullup(0);
Pavankumar Kondetiaa449e12011-11-04 11:09:26 +05301632 /* Enable ACA ID detection */
Steve Mucklef132c6c2012-06-06 18:30:57 -07001633 ulpi_write(phy, 0x20, 0x85);
Pavankumar Kondeti4960f312011-12-06 15:46:14 +05301634 aca_id_turned_on = true;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001635 break;
1636 default:
1637 break;
1638 }
1639}
1640
1641static void msm_chg_enable_aca_intr(struct msm_otg *motg)
1642{
Steve Mucklef132c6c2012-06-06 18:30:57 -07001643 struct usb_phy *phy = &motg->phy;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001644
Pavankumar Kondetiaa449e12011-11-04 11:09:26 +05301645 if (!aca_enabled())
1646 return;
1647
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001648 switch (motg->pdata->phy_type) {
1649 case SNPS_28NM_INTEGRATED_PHY:
Pavankumar Kondetiaa449e12011-11-04 11:09:26 +05301650 /* Enable ACA Detection interrupt (on any RID change) */
Steve Mucklef132c6c2012-06-06 18:30:57 -07001651 ulpi_write(phy, 0x01, 0x94);
Pavankumar Kondetiaa449e12011-11-04 11:09:26 +05301652 break;
1653 default:
1654 break;
1655 }
1656}
1657
1658static void msm_chg_disable_aca_intr(struct msm_otg *motg)
1659{
Steve Mucklef132c6c2012-06-06 18:30:57 -07001660 struct usb_phy *phy = &motg->phy;
Pavankumar Kondetiaa449e12011-11-04 11:09:26 +05301661
1662 if (!aca_enabled())
1663 return;
1664
1665 switch (motg->pdata->phy_type) {
1666 case SNPS_28NM_INTEGRATED_PHY:
Steve Mucklef132c6c2012-06-06 18:30:57 -07001667 ulpi_write(phy, 0x01, 0x95);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001668 break;
1669 default:
1670 break;
1671 }
1672}
1673
1674static bool msm_chg_check_aca_intr(struct msm_otg *motg)
1675{
Steve Mucklef132c6c2012-06-06 18:30:57 -07001676 struct usb_phy *phy = &motg->phy;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001677 bool ret = false;
1678
Pavankumar Kondetiaa449e12011-11-04 11:09:26 +05301679 if (!aca_enabled())
1680 return ret;
1681
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001682 switch (motg->pdata->phy_type) {
1683 case SNPS_28NM_INTEGRATED_PHY:
Steve Mucklef132c6c2012-06-06 18:30:57 -07001684 if (ulpi_read(phy, 0x91) & 1) {
1685 dev_dbg(phy->dev, "RID change\n");
1686 ulpi_write(phy, 0x01, 0x92);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001687 ret = msm_chg_aca_detect(motg);
1688 }
1689 default:
1690 break;
1691 }
1692 return ret;
1693}
Pavankumar Kondetiaa449e12011-11-04 11:09:26 +05301694
1695static void msm_otg_id_timer_func(unsigned long data)
1696{
1697 struct msm_otg *motg = (struct msm_otg *) data;
1698
1699 if (!aca_enabled())
1700 return;
1701
1702 if (atomic_read(&motg->in_lpm)) {
Steve Mucklef132c6c2012-06-06 18:30:57 -07001703 dev_dbg(motg->phy.dev, "timer: in lpm\n");
Pavankumar Kondetiaa449e12011-11-04 11:09:26 +05301704 return;
1705 }
1706
Steve Mucklef132c6c2012-06-06 18:30:57 -07001707 if (motg->phy.state == OTG_STATE_A_SUSPEND)
Vijayavardhan Vennapusaa3152032012-03-05 16:29:30 +05301708 goto out;
1709
Pavankumar Kondetiaa449e12011-11-04 11:09:26 +05301710 if (msm_chg_check_aca_intr(motg)) {
Steve Mucklef132c6c2012-06-06 18:30:57 -07001711 dev_dbg(motg->phy.dev, "timer: aca work\n");
Vijayavardhan Vennapusaa3152032012-03-05 16:29:30 +05301712 queue_work(system_nrt_wq, &motg->sm_work);
Pavankumar Kondetiaa449e12011-11-04 11:09:26 +05301713 }
1714
Vijayavardhan Vennapusaa3152032012-03-05 16:29:30 +05301715out:
Pavankumar Kondetiaa449e12011-11-04 11:09:26 +05301716 if (!test_bit(ID, &motg->inputs) || test_bit(ID_A, &motg->inputs))
1717 mod_timer(&motg->id_timer, ID_TIMER_FREQ);
1718}
1719
Pavankumar Kondetid8608522011-05-04 10:19:47 +05301720static bool msm_chg_check_secondary_det(struct msm_otg *motg)
1721{
Heikki Krogerus1d4c9292012-02-13 13:24:09 +02001722 struct usb_phy *phy = &motg->phy;
Pavankumar Kondetid8608522011-05-04 10:19:47 +05301723 u32 chg_det;
1724 bool ret = false;
1725
1726 switch (motg->pdata->phy_type) {
1727 case CI_45NM_INTEGRATED_PHY:
Heikki Krogerus1d4c9292012-02-13 13:24:09 +02001728 chg_det = ulpi_read(phy, 0x34);
Pavankumar Kondetid8608522011-05-04 10:19:47 +05301729 ret = chg_det & (1 << 4);
1730 break;
1731 case SNPS_28NM_INTEGRATED_PHY:
Heikki Krogerus1d4c9292012-02-13 13:24:09 +02001732 chg_det = ulpi_read(phy, 0x87);
Pavankumar Kondetid8608522011-05-04 10:19:47 +05301733 ret = chg_det & 1;
1734 break;
1735 default:
1736 break;
1737 }
1738 return ret;
1739}
1740
1741static void msm_chg_enable_secondary_det(struct msm_otg *motg)
1742{
Heikki Krogerus1d4c9292012-02-13 13:24:09 +02001743 struct usb_phy *phy = &motg->phy;
Pavankumar Kondetid8608522011-05-04 10:19:47 +05301744 u32 chg_det;
1745
1746 switch (motg->pdata->phy_type) {
1747 case CI_45NM_INTEGRATED_PHY:
Heikki Krogerus1d4c9292012-02-13 13:24:09 +02001748 chg_det = ulpi_read(phy, 0x34);
Pavankumar Kondetid8608522011-05-04 10:19:47 +05301749 /* Turn off charger block */
1750 chg_det |= ~(1 << 1);
Heikki Krogerus1d4c9292012-02-13 13:24:09 +02001751 ulpi_write(phy, chg_det, 0x34);
Pavankumar Kondetid8608522011-05-04 10:19:47 +05301752 udelay(20);
1753 /* control chg block via ULPI */
1754 chg_det &= ~(1 << 3);
Heikki Krogerus1d4c9292012-02-13 13:24:09 +02001755 ulpi_write(phy, chg_det, 0x34);
Pavankumar Kondetid8608522011-05-04 10:19:47 +05301756 /* put it in host mode for enabling D- source */
1757 chg_det &= ~(1 << 2);
Heikki Krogerus1d4c9292012-02-13 13:24:09 +02001758 ulpi_write(phy, chg_det, 0x34);
Pavankumar Kondetid8608522011-05-04 10:19:47 +05301759 /* Turn on chg detect block */
1760 chg_det &= ~(1 << 1);
Heikki Krogerus1d4c9292012-02-13 13:24:09 +02001761 ulpi_write(phy, chg_det, 0x34);
Pavankumar Kondetid8608522011-05-04 10:19:47 +05301762 udelay(20);
1763 /* enable chg detection */
1764 chg_det &= ~(1 << 0);
Heikki Krogerus1d4c9292012-02-13 13:24:09 +02001765 ulpi_write(phy, chg_det, 0x34);
Pavankumar Kondetid8608522011-05-04 10:19:47 +05301766 break;
1767 case SNPS_28NM_INTEGRATED_PHY:
1768 /*
1769 * Configure DM as current source, DP as current sink
1770 * and enable battery charging comparators.
1771 */
Heikki Krogerus1d4c9292012-02-13 13:24:09 +02001772 ulpi_write(phy, 0x8, 0x85);
1773 ulpi_write(phy, 0x2, 0x85);
1774 ulpi_write(phy, 0x1, 0x85);
Pavankumar Kondetid8608522011-05-04 10:19:47 +05301775 break;
1776 default:
1777 break;
1778 }
1779}
1780
1781static bool msm_chg_check_primary_det(struct msm_otg *motg)
1782{
Heikki Krogerus1d4c9292012-02-13 13:24:09 +02001783 struct usb_phy *phy = &motg->phy;
Pavankumar Kondetid8608522011-05-04 10:19:47 +05301784 u32 chg_det;
1785 bool ret = false;
1786
1787 switch (motg->pdata->phy_type) {
1788 case CI_45NM_INTEGRATED_PHY:
Heikki Krogerus1d4c9292012-02-13 13:24:09 +02001789 chg_det = ulpi_read(phy, 0x34);
Pavankumar Kondetid8608522011-05-04 10:19:47 +05301790 ret = chg_det & (1 << 4);
1791 break;
1792 case SNPS_28NM_INTEGRATED_PHY:
Heikki Krogerus1d4c9292012-02-13 13:24:09 +02001793 chg_det = ulpi_read(phy, 0x87);
Pavankumar Kondetid8608522011-05-04 10:19:47 +05301794 ret = chg_det & 1;
Pavankumar Kondeti9ec21d32012-05-07 15:50:23 +05301795 /* Turn off VDP_SRC */
1796 ulpi_write(phy, 0x3, 0x86);
1797 msleep(20);
Pavankumar Kondetid8608522011-05-04 10:19:47 +05301798 break;
1799 default:
1800 break;
1801 }
1802 return ret;
1803}
1804
1805static void msm_chg_enable_primary_det(struct msm_otg *motg)
1806{
Heikki Krogerus1d4c9292012-02-13 13:24:09 +02001807 struct usb_phy *phy = &motg->phy;
Pavankumar Kondetid8608522011-05-04 10:19:47 +05301808 u32 chg_det;
1809
1810 switch (motg->pdata->phy_type) {
1811 case CI_45NM_INTEGRATED_PHY:
Heikki Krogerus1d4c9292012-02-13 13:24:09 +02001812 chg_det = ulpi_read(phy, 0x34);
Pavankumar Kondetid8608522011-05-04 10:19:47 +05301813 /* enable chg detection */
1814 chg_det &= ~(1 << 0);
Heikki Krogerus1d4c9292012-02-13 13:24:09 +02001815 ulpi_write(phy, chg_det, 0x34);
Pavankumar Kondetid8608522011-05-04 10:19:47 +05301816 break;
1817 case SNPS_28NM_INTEGRATED_PHY:
1818 /*
1819 * Configure DP as current source, DM as current sink
1820 * and enable battery charging comparators.
1821 */
Heikki Krogerus1d4c9292012-02-13 13:24:09 +02001822 ulpi_write(phy, 0x2, 0x85);
1823 ulpi_write(phy, 0x1, 0x85);
Pavankumar Kondetid8608522011-05-04 10:19:47 +05301824 break;
1825 default:
1826 break;
1827 }
1828}
1829
1830static bool msm_chg_check_dcd(struct msm_otg *motg)
1831{
Heikki Krogerus1d4c9292012-02-13 13:24:09 +02001832 struct usb_phy *phy = &motg->phy;
Pavankumar Kondetid8608522011-05-04 10:19:47 +05301833 u32 line_state;
1834 bool ret = false;
1835
1836 switch (motg->pdata->phy_type) {
1837 case CI_45NM_INTEGRATED_PHY:
Heikki Krogerus1d4c9292012-02-13 13:24:09 +02001838 line_state = ulpi_read(phy, 0x15);
Pavankumar Kondetid8608522011-05-04 10:19:47 +05301839 ret = !(line_state & 1);
1840 break;
1841 case SNPS_28NM_INTEGRATED_PHY:
Heikki Krogerus1d4c9292012-02-13 13:24:09 +02001842 line_state = ulpi_read(phy, 0x87);
Pavankumar Kondetid8608522011-05-04 10:19:47 +05301843 ret = line_state & 2;
1844 break;
1845 default:
1846 break;
1847 }
1848 return ret;
1849}
1850
1851static void msm_chg_disable_dcd(struct msm_otg *motg)
1852{
Heikki Krogerus1d4c9292012-02-13 13:24:09 +02001853 struct usb_phy *phy = &motg->phy;
Pavankumar Kondetid8608522011-05-04 10:19:47 +05301854 u32 chg_det;
1855
1856 switch (motg->pdata->phy_type) {
1857 case CI_45NM_INTEGRATED_PHY:
Heikki Krogerus1d4c9292012-02-13 13:24:09 +02001858 chg_det = ulpi_read(phy, 0x34);
Pavankumar Kondetid8608522011-05-04 10:19:47 +05301859 chg_det &= ~(1 << 5);
Heikki Krogerus1d4c9292012-02-13 13:24:09 +02001860 ulpi_write(phy, chg_det, 0x34);
Pavankumar Kondetid8608522011-05-04 10:19:47 +05301861 break;
1862 case SNPS_28NM_INTEGRATED_PHY:
Heikki Krogerus1d4c9292012-02-13 13:24:09 +02001863 ulpi_write(phy, 0x10, 0x86);
Pavankumar Kondetid8608522011-05-04 10:19:47 +05301864 break;
1865 default:
1866 break;
1867 }
1868}
1869
1870static void msm_chg_enable_dcd(struct msm_otg *motg)
1871{
Heikki Krogerus1d4c9292012-02-13 13:24:09 +02001872 struct usb_phy *phy = &motg->phy;
Pavankumar Kondetid8608522011-05-04 10:19:47 +05301873 u32 chg_det;
1874
1875 switch (motg->pdata->phy_type) {
1876 case CI_45NM_INTEGRATED_PHY:
Heikki Krogerus1d4c9292012-02-13 13:24:09 +02001877 chg_det = ulpi_read(phy, 0x34);
Pavankumar Kondetid8608522011-05-04 10:19:47 +05301878 /* Turn on D+ current source */
1879 chg_det |= (1 << 5);
Heikki Krogerus1d4c9292012-02-13 13:24:09 +02001880 ulpi_write(phy, chg_det, 0x34);
Pavankumar Kondetid8608522011-05-04 10:19:47 +05301881 break;
1882 case SNPS_28NM_INTEGRATED_PHY:
1883 /* Data contact detection enable */
Heikki Krogerus1d4c9292012-02-13 13:24:09 +02001884 ulpi_write(phy, 0x10, 0x85);
Pavankumar Kondetid8608522011-05-04 10:19:47 +05301885 break;
1886 default:
1887 break;
1888 }
1889}
1890
1891static void msm_chg_block_on(struct msm_otg *motg)
1892{
Heikki Krogerus1d4c9292012-02-13 13:24:09 +02001893 struct usb_phy *phy = &motg->phy;
Pavankumar Kondetid8608522011-05-04 10:19:47 +05301894 u32 func_ctrl, chg_det;
1895
1896 /* put the controller in non-driving mode */
Heikki Krogerus1d4c9292012-02-13 13:24:09 +02001897 func_ctrl = ulpi_read(phy, ULPI_FUNC_CTRL);
Pavankumar Kondetid8608522011-05-04 10:19:47 +05301898 func_ctrl &= ~ULPI_FUNC_CTRL_OPMODE_MASK;
1899 func_ctrl |= ULPI_FUNC_CTRL_OPMODE_NONDRIVING;
Heikki Krogerus1d4c9292012-02-13 13:24:09 +02001900 ulpi_write(phy, func_ctrl, ULPI_FUNC_CTRL);
Pavankumar Kondetid8608522011-05-04 10:19:47 +05301901
1902 switch (motg->pdata->phy_type) {
1903 case CI_45NM_INTEGRATED_PHY:
Heikki Krogerus1d4c9292012-02-13 13:24:09 +02001904 chg_det = ulpi_read(phy, 0x34);
Pavankumar Kondetid8608522011-05-04 10:19:47 +05301905 /* control chg block via ULPI */
1906 chg_det &= ~(1 << 3);
Heikki Krogerus1d4c9292012-02-13 13:24:09 +02001907 ulpi_write(phy, chg_det, 0x34);
Pavankumar Kondetid8608522011-05-04 10:19:47 +05301908 /* Turn on chg detect block */
1909 chg_det &= ~(1 << 1);
Heikki Krogerus1d4c9292012-02-13 13:24:09 +02001910 ulpi_write(phy, chg_det, 0x34);
Pavankumar Kondetid8608522011-05-04 10:19:47 +05301911 udelay(20);
1912 break;
1913 case SNPS_28NM_INTEGRATED_PHY:
1914 /* Clear charger detecting control bits */
Steve Mucklef132c6c2012-06-06 18:30:57 -07001915 ulpi_write(phy, 0x1F, 0x86);
Pavankumar Kondetid8608522011-05-04 10:19:47 +05301916 /* Clear alt interrupt latch and enable bits */
Heikki Krogerus1d4c9292012-02-13 13:24:09 +02001917 ulpi_write(phy, 0x1F, 0x92);
1918 ulpi_write(phy, 0x1F, 0x95);
Pavankumar Kondetid8608522011-05-04 10:19:47 +05301919 udelay(100);
1920 break;
1921 default:
1922 break;
1923 }
1924}
1925
1926static void msm_chg_block_off(struct msm_otg *motg)
1927{
Heikki Krogerus1d4c9292012-02-13 13:24:09 +02001928 struct usb_phy *phy = &motg->phy;
Pavankumar Kondetid8608522011-05-04 10:19:47 +05301929 u32 func_ctrl, chg_det;
1930
1931 switch (motg->pdata->phy_type) {
1932 case CI_45NM_INTEGRATED_PHY:
Heikki Krogerus1d4c9292012-02-13 13:24:09 +02001933 chg_det = ulpi_read(phy, 0x34);
Pavankumar Kondetid8608522011-05-04 10:19:47 +05301934 /* Turn off charger block */
1935 chg_det |= ~(1 << 1);
Heikki Krogerus1d4c9292012-02-13 13:24:09 +02001936 ulpi_write(phy, chg_det, 0x34);
Pavankumar Kondetid8608522011-05-04 10:19:47 +05301937 break;
1938 case SNPS_28NM_INTEGRATED_PHY:
1939 /* Clear charger detecting control bits */
Heikki Krogerus1d4c9292012-02-13 13:24:09 +02001940 ulpi_write(phy, 0x3F, 0x86);
Pavankumar Kondetid8608522011-05-04 10:19:47 +05301941 /* Clear alt interrupt latch and enable bits */
Heikki Krogerus1d4c9292012-02-13 13:24:09 +02001942 ulpi_write(phy, 0x1F, 0x92);
1943 ulpi_write(phy, 0x1F, 0x95);
Pavankumar Kondetid8608522011-05-04 10:19:47 +05301944 break;
1945 default:
1946 break;
1947 }
1948
1949 /* put the controller in normal mode */
Heikki Krogerus1d4c9292012-02-13 13:24:09 +02001950 func_ctrl = ulpi_read(phy, ULPI_FUNC_CTRL);
Pavankumar Kondetid8608522011-05-04 10:19:47 +05301951 func_ctrl &= ~ULPI_FUNC_CTRL_OPMODE_MASK;
1952 func_ctrl |= ULPI_FUNC_CTRL_OPMODE_NORMAL;
Heikki Krogerus1d4c9292012-02-13 13:24:09 +02001953 ulpi_write(phy, func_ctrl, ULPI_FUNC_CTRL);
Pavankumar Kondetid8608522011-05-04 10:19:47 +05301954}
1955
Anji jonnalad270e2d2011-08-09 11:28:32 +05301956static const char *chg_to_string(enum usb_chg_type chg_type)
1957{
1958 switch (chg_type) {
1959 case USB_SDP_CHARGER: return "USB_SDP_CHARGER";
1960 case USB_DCP_CHARGER: return "USB_DCP_CHARGER";
1961 case USB_CDP_CHARGER: return "USB_CDP_CHARGER";
1962 case USB_ACA_A_CHARGER: return "USB_ACA_A_CHARGER";
1963 case USB_ACA_B_CHARGER: return "USB_ACA_B_CHARGER";
1964 case USB_ACA_C_CHARGER: return "USB_ACA_C_CHARGER";
1965 case USB_ACA_DOCK_CHARGER: return "USB_ACA_DOCK_CHARGER";
Pavankumar Kondeti9ec21d32012-05-07 15:50:23 +05301966 case USB_PROPRIETARY_CHARGER: return "USB_PROPRIETARY_CHARGER";
Anji jonnalad270e2d2011-08-09 11:28:32 +05301967 default: return "INVALID_CHARGER";
1968 }
1969}
1970
Pavankumar Kondetid8608522011-05-04 10:19:47 +05301971#define MSM_CHG_DCD_POLL_TIME (100 * HZ/1000) /* 100 msec */
1972#define MSM_CHG_DCD_MAX_RETRIES 6 /* Tdcd_tmout = 6 * 100 msec */
Pavankumar Kondeti283146f2012-01-12 12:51:19 +05301973#define MSM_CHG_PRIMARY_DET_TIME (50 * HZ/1000) /* TVDPSRC_ON */
1974#define MSM_CHG_SECONDARY_DET_TIME (50 * HZ/1000) /* TVDMSRC_ON */
Pavankumar Kondetid8608522011-05-04 10:19:47 +05301975static void msm_chg_detect_work(struct work_struct *w)
1976{
1977 struct msm_otg *motg = container_of(w, struct msm_otg, chg_work.work);
Heikki Krogerus1d4c9292012-02-13 13:24:09 +02001978 struct usb_phy *phy = &motg->phy;
Pavankumar Kondeti2d09e5f2012-01-16 08:56:57 +05301979 bool is_dcd = false, tmout, vout, is_aca;
Pavankumar Kondeti9ec21d32012-05-07 15:50:23 +05301980 u32 line_state, dm_vlgc;
Pavankumar Kondetid8608522011-05-04 10:19:47 +05301981 unsigned long delay;
1982
Heikki Krogerus1d4c9292012-02-13 13:24:09 +02001983 dev_dbg(phy->dev, "chg detection work\n");
Pavankumar Kondeti2aec9f32012-06-13 09:06:03 +05301984
1985 if (test_bit(MHL, &motg->inputs)) {
1986 dev_dbg(phy->dev, "detected MHL, escape chg detection work\n");
1987 return;
1988 }
1989
Pavankumar Kondetid8608522011-05-04 10:19:47 +05301990 switch (motg->chg_state) {
1991 case USB_CHG_STATE_UNDEFINED:
Pavankumar Kondetid8608522011-05-04 10:19:47 +05301992 msm_chg_block_on(motg);
Pavankumar Kondeti2d09e5f2012-01-16 08:56:57 +05301993 if (motg->pdata->enable_dcd)
1994 msm_chg_enable_dcd(motg);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001995 msm_chg_enable_aca_det(motg);
Pavankumar Kondetid8608522011-05-04 10:19:47 +05301996 motg->chg_state = USB_CHG_STATE_WAIT_FOR_DCD;
1997 motg->dcd_retries = 0;
1998 delay = MSM_CHG_DCD_POLL_TIME;
1999 break;
2000 case USB_CHG_STATE_WAIT_FOR_DCD:
Pavankumar Kondeti2aec9f32012-06-13 09:06:03 +05302001 if (msm_chg_mhl_detect(motg)) {
2002 msm_chg_block_off(motg);
2003 motg->chg_state = USB_CHG_STATE_DETECTED;
2004 motg->chg_type = USB_INVALID_CHARGER;
2005 queue_work(system_nrt_wq, &motg->sm_work);
2006 return;
2007 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002008 is_aca = msm_chg_aca_detect(motg);
2009 if (is_aca) {
2010 /*
2011 * ID_A can be ACA dock too. continue
2012 * primary detection after DCD.
2013 */
2014 if (test_bit(ID_A, &motg->inputs)) {
2015 motg->chg_state = USB_CHG_STATE_WAIT_FOR_DCD;
2016 } else {
2017 delay = 0;
2018 break;
2019 }
2020 }
Pavankumar Kondeti2d09e5f2012-01-16 08:56:57 +05302021 if (motg->pdata->enable_dcd)
2022 is_dcd = msm_chg_check_dcd(motg);
Pavankumar Kondetid8608522011-05-04 10:19:47 +05302023 tmout = ++motg->dcd_retries == MSM_CHG_DCD_MAX_RETRIES;
2024 if (is_dcd || tmout) {
Pavankumar Kondeti2d09e5f2012-01-16 08:56:57 +05302025 if (motg->pdata->enable_dcd)
2026 msm_chg_disable_dcd(motg);
Pavankumar Kondetid8608522011-05-04 10:19:47 +05302027 msm_chg_enable_primary_det(motg);
2028 delay = MSM_CHG_PRIMARY_DET_TIME;
2029 motg->chg_state = USB_CHG_STATE_DCD_DONE;
2030 } else {
2031 delay = MSM_CHG_DCD_POLL_TIME;
2032 }
2033 break;
2034 case USB_CHG_STATE_DCD_DONE:
2035 vout = msm_chg_check_primary_det(motg);
Pavankumar Kondeti9ec21d32012-05-07 15:50:23 +05302036 line_state = readl_relaxed(USB_PORTSC) & PORTSC_LS;
2037 dm_vlgc = line_state & PORTSC_LS_DM;
2038 if (vout && !dm_vlgc) { /* VDAT_REF < DM < VLGC */
Pavankumar Kondetiaa449e12011-11-04 11:09:26 +05302039 if (test_bit(ID_A, &motg->inputs)) {
2040 motg->chg_type = USB_ACA_DOCK_CHARGER;
2041 motg->chg_state = USB_CHG_STATE_DETECTED;
2042 delay = 0;
2043 break;
2044 }
Pavankumar Kondeti9ec21d32012-05-07 15:50:23 +05302045 if (line_state) { /* DP > VLGC */
2046 motg->chg_type = USB_PROPRIETARY_CHARGER;
2047 motg->chg_state = USB_CHG_STATE_DETECTED;
2048 delay = 0;
2049 } else {
2050 msm_chg_enable_secondary_det(motg);
2051 delay = MSM_CHG_SECONDARY_DET_TIME;
2052 motg->chg_state = USB_CHG_STATE_PRIMARY_DONE;
2053 }
2054 } else { /* DM < VDAT_REF || DM > VLGC */
Pavankumar Kondetiaa449e12011-11-04 11:09:26 +05302055 if (test_bit(ID_A, &motg->inputs)) {
2056 motg->chg_type = USB_ACA_A_CHARGER;
2057 motg->chg_state = USB_CHG_STATE_DETECTED;
2058 delay = 0;
2059 break;
2060 }
Pavankumar Kondeti9ec21d32012-05-07 15:50:23 +05302061
2062 if (line_state) /* DP > VLGC or/and DM > VLGC */
2063 motg->chg_type = USB_PROPRIETARY_CHARGER;
2064 else
2065 motg->chg_type = USB_SDP_CHARGER;
2066
Pavankumar Kondetid8608522011-05-04 10:19:47 +05302067 motg->chg_state = USB_CHG_STATE_DETECTED;
2068 delay = 0;
2069 }
2070 break;
2071 case USB_CHG_STATE_PRIMARY_DONE:
2072 vout = msm_chg_check_secondary_det(motg);
2073 if (vout)
2074 motg->chg_type = USB_DCP_CHARGER;
2075 else
2076 motg->chg_type = USB_CDP_CHARGER;
2077 motg->chg_state = USB_CHG_STATE_SECONDARY_DONE;
2078 /* fall through */
2079 case USB_CHG_STATE_SECONDARY_DONE:
2080 motg->chg_state = USB_CHG_STATE_DETECTED;
2081 case USB_CHG_STATE_DETECTED:
2082 msm_chg_block_off(motg);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002083 msm_chg_enable_aca_det(motg);
Vijayavardhan Vennapusaa3152032012-03-05 16:29:30 +05302084 /*
2085 * Spurious interrupt is seen after enabling ACA detection
2086 * due to which charger detection fails in case of PET.
2087 * Add delay of 100 microsec to avoid that.
2088 */
2089 udelay(100);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002090 msm_chg_enable_aca_intr(motg);
Steve Mucklef132c6c2012-06-06 18:30:57 -07002091 dev_dbg(phy->dev, "chg_type = %s\n",
Anji jonnalad270e2d2011-08-09 11:28:32 +05302092 chg_to_string(motg->chg_type));
Vijayavardhan Vennapusaa3152032012-03-05 16:29:30 +05302093 queue_work(system_nrt_wq, &motg->sm_work);
Pavankumar Kondetid8608522011-05-04 10:19:47 +05302094 return;
2095 default:
2096 return;
2097 }
2098
Vijayavardhan Vennapusaa3152032012-03-05 16:29:30 +05302099 queue_delayed_work(system_nrt_wq, &motg->chg_work, delay);
Pavankumar Kondetid8608522011-05-04 10:19:47 +05302100}
2101
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05302102/*
2103 * We support OTG, Peripheral only and Host only configurations. In case
2104 * of OTG, mode switch (host-->peripheral/peripheral-->host) can happen
2105 * via Id pin status or user request (debugfs). Id/BSV interrupts are not
2106 * enabled when switch is controlled by user and default mode is supplied
2107 * by board file, which can be changed by userspace later.
2108 */
2109static void msm_otg_init_sm(struct msm_otg *motg)
2110{
2111 struct msm_otg_platform_data *pdata = motg->pdata;
2112 u32 otgsc = readl(USB_OTGSC);
2113
2114 switch (pdata->mode) {
2115 case USB_OTG:
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002116 if (pdata->otg_control == OTG_USER_CONTROL) {
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05302117 if (pdata->default_mode == USB_HOST) {
2118 clear_bit(ID, &motg->inputs);
2119 } else if (pdata->default_mode == USB_PERIPHERAL) {
2120 set_bit(ID, &motg->inputs);
2121 set_bit(B_SESS_VLD, &motg->inputs);
2122 } else {
2123 set_bit(ID, &motg->inputs);
2124 clear_bit(B_SESS_VLD, &motg->inputs);
2125 }
Pavankumar Kondeti4960f312011-12-06 15:46:14 +05302126 } else if (pdata->otg_control == OTG_PHY_CONTROL) {
Vijayavardhan Vennapusaa3152032012-03-05 16:29:30 +05302127 if (otgsc & OTGSC_ID) {
Pavankumar Kondeti4960f312011-12-06 15:46:14 +05302128 set_bit(ID, &motg->inputs);
Vijayavardhan Vennapusaa3152032012-03-05 16:29:30 +05302129 } else {
Pavankumar Kondeti4960f312011-12-06 15:46:14 +05302130 clear_bit(ID, &motg->inputs);
Vijayavardhan Vennapusaa3152032012-03-05 16:29:30 +05302131 set_bit(A_BUS_REQ, &motg->inputs);
2132 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002133 if (otgsc & OTGSC_BSV)
2134 set_bit(B_SESS_VLD, &motg->inputs);
2135 else
2136 clear_bit(B_SESS_VLD, &motg->inputs);
Pavankumar Kondeti4960f312011-12-06 15:46:14 +05302137 } else if (pdata->otg_control == OTG_PMIC_CONTROL) {
Pavankumar Kondeti0d81f312012-01-13 11:34:10 +05302138 if (pdata->pmic_id_irq) {
Stephen Boyd431771e2012-04-18 20:00:23 -07002139 unsigned long flags;
2140 local_irq_save(flags);
Pavankumar Kondeti0d81f312012-01-13 11:34:10 +05302141 if (irq_read_line(pdata->pmic_id_irq))
2142 set_bit(ID, &motg->inputs);
2143 else
2144 clear_bit(ID, &motg->inputs);
Stephen Boyd431771e2012-04-18 20:00:23 -07002145 local_irq_restore(flags);
Pavankumar Kondeti0d81f312012-01-13 11:34:10 +05302146 }
Pavankumar Kondeti4960f312011-12-06 15:46:14 +05302147 /*
2148 * VBUS initial state is reported after PMIC
2149 * driver initialization. Wait for it.
2150 */
2151 wait_for_completion(&pmic_vbus_init);
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05302152 }
2153 break;
2154 case USB_HOST:
2155 clear_bit(ID, &motg->inputs);
2156 break;
2157 case USB_PERIPHERAL:
2158 set_bit(ID, &motg->inputs);
Pavankumar Kondeti0d81f312012-01-13 11:34:10 +05302159 if (pdata->otg_control == OTG_PHY_CONTROL) {
2160 if (otgsc & OTGSC_BSV)
2161 set_bit(B_SESS_VLD, &motg->inputs);
2162 else
2163 clear_bit(B_SESS_VLD, &motg->inputs);
2164 } else if (pdata->otg_control == OTG_PMIC_CONTROL) {
2165 /*
2166 * VBUS initial state is reported after PMIC
2167 * driver initialization. Wait for it.
2168 */
2169 wait_for_completion(&pmic_vbus_init);
2170 }
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05302171 break;
2172 default:
2173 break;
2174 }
2175}
2176
2177static void msm_otg_sm_work(struct work_struct *w)
2178{
2179 struct msm_otg *motg = container_of(w, struct msm_otg, sm_work);
Heikki Krogerus1d4c9292012-02-13 13:24:09 +02002180 struct usb_otg *otg = motg->phy.otg;
Vijayavardhan Vennapusaa3152032012-03-05 16:29:30 +05302181 bool work = 0, srp_reqd;
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05302182
Steve Mucklef132c6c2012-06-06 18:30:57 -07002183 pm_runtime_resume(otg->phy->dev);
2184 pr_debug("%s work\n", otg_state_string(otg->phy->state));
Heikki Krogerus1d4c9292012-02-13 13:24:09 +02002185 switch (otg->phy->state) {
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05302186 case OTG_STATE_UNDEFINED:
Heikki Krogerus1d4c9292012-02-13 13:24:09 +02002187 msm_otg_reset(otg->phy);
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05302188 msm_otg_init_sm(motg);
Vijayavardhan Vennapusa05c437c2012-05-25 16:20:46 +05302189 psy = power_supply_get_by_name("usb");
2190 if (!psy)
2191 pr_err("couldn't get usb power supply\n");
Heikki Krogerus1d4c9292012-02-13 13:24:09 +02002192 otg->phy->state = OTG_STATE_B_IDLE;
Pavankumar Kondeti8a379b42011-12-12 13:07:23 +05302193 if (!test_bit(B_SESS_VLD, &motg->inputs) &&
2194 test_bit(ID, &motg->inputs)) {
Steve Mucklef132c6c2012-06-06 18:30:57 -07002195 pm_runtime_put_noidle(otg->phy->dev);
2196 pm_runtime_suspend(otg->phy->dev);
Pavankumar Kondeti8a379b42011-12-12 13:07:23 +05302197 break;
2198 }
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05302199 /* FALL THROUGH */
2200 case OTG_STATE_B_IDLE:
Pavankumar Kondeti2aec9f32012-06-13 09:06:03 +05302201 if (test_bit(MHL, &motg->inputs)) {
2202 /* allow LPM */
2203 pm_runtime_put_noidle(otg->phy->dev);
2204 pm_runtime_suspend(otg->phy->dev);
2205 } else if ((!test_bit(ID, &motg->inputs) ||
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002206 test_bit(ID_A, &motg->inputs)) && otg->host) {
Vijayavardhan Vennapusaa3152032012-03-05 16:29:30 +05302207 pr_debug("!id || id_A\n");
Pavankumar Kondeti2aec9f32012-06-13 09:06:03 +05302208 if (msm_chg_mhl_detect(motg)) {
2209 work = 1;
2210 break;
2211 }
Vijayavardhan Vennapusaa3152032012-03-05 16:29:30 +05302212 clear_bit(B_BUS_REQ, &motg->inputs);
2213 set_bit(A_BUS_REQ, &motg->inputs);
Steve Mucklef132c6c2012-06-06 18:30:57 -07002214 otg->phy->state = OTG_STATE_A_IDLE;
Vijayavardhan Vennapusaa3152032012-03-05 16:29:30 +05302215 work = 1;
Pavankumar Kondetid8608522011-05-04 10:19:47 +05302216 } else if (test_bit(B_SESS_VLD, &motg->inputs)) {
Vijayavardhan Vennapusaa3152032012-03-05 16:29:30 +05302217 pr_debug("b_sess_vld\n");
Pavankumar Kondetid8608522011-05-04 10:19:47 +05302218 switch (motg->chg_state) {
2219 case USB_CHG_STATE_UNDEFINED:
2220 msm_chg_detect_work(&motg->chg_work.work);
2221 break;
2222 case USB_CHG_STATE_DETECTED:
2223 switch (motg->chg_type) {
2224 case USB_DCP_CHARGER:
Pavankumar Kondeti283146f2012-01-12 12:51:19 +05302225 /* Enable VDP_SRC */
Steve Mucklef132c6c2012-06-06 18:30:57 -07002226 ulpi_write(otg->phy, 0x2, 0x85);
Pavankumar Kondeti9ec21d32012-05-07 15:50:23 +05302227 /* fall through */
2228 case USB_PROPRIETARY_CHARGER:
Pavankumar Kondetid8608522011-05-04 10:19:47 +05302229 msm_otg_notify_charger(motg,
2230 IDEV_CHG_MAX);
Steve Mucklef132c6c2012-06-06 18:30:57 -07002231 pm_runtime_put_noidle(otg->phy->dev);
2232 pm_runtime_suspend(otg->phy->dev);
Pavankumar Kondetid8608522011-05-04 10:19:47 +05302233 break;
Pavankumar Kondetiaa449e12011-11-04 11:09:26 +05302234 case USB_ACA_B_CHARGER:
2235 msm_otg_notify_charger(motg,
2236 IDEV_ACA_CHG_MAX);
2237 /*
2238 * (ID_B --> ID_C) PHY_ALT interrupt can
2239 * not be detected in LPM.
2240 */
Pavankumar Kondetid8608522011-05-04 10:19:47 +05302241 break;
2242 case USB_CDP_CHARGER:
2243 msm_otg_notify_charger(motg,
2244 IDEV_CHG_MAX);
2245 msm_otg_start_peripheral(otg, 1);
Steve Mucklef132c6c2012-06-06 18:30:57 -07002246 otg->phy->state =
2247 OTG_STATE_B_PERIPHERAL;
Pavankumar Kondetid8608522011-05-04 10:19:47 +05302248 break;
Pavankumar Kondetiaa449e12011-11-04 11:09:26 +05302249 case USB_ACA_C_CHARGER:
2250 msm_otg_notify_charger(motg,
2251 IDEV_ACA_CHG_MAX);
2252 msm_otg_start_peripheral(otg, 1);
Steve Mucklef132c6c2012-06-06 18:30:57 -07002253 otg->phy->state =
2254 OTG_STATE_B_PERIPHERAL;
Pavankumar Kondetid8608522011-05-04 10:19:47 +05302255 break;
2256 case USB_SDP_CHARGER:
Pavankumar Kondetid8608522011-05-04 10:19:47 +05302257 msm_otg_start_peripheral(otg, 1);
Steve Mucklef132c6c2012-06-06 18:30:57 -07002258 otg->phy->state =
2259 OTG_STATE_B_PERIPHERAL;
Pavankumar Kondetid8608522011-05-04 10:19:47 +05302260 break;
2261 default:
2262 break;
2263 }
2264 break;
2265 default:
2266 break;
2267 }
Vijayavardhan Vennapusaa3152032012-03-05 16:29:30 +05302268 } else if (test_bit(B_BUS_REQ, &motg->inputs)) {
2269 pr_debug("b_sess_end && b_bus_req\n");
2270 if (msm_otg_start_srp(otg) < 0) {
2271 clear_bit(B_BUS_REQ, &motg->inputs);
2272 work = 1;
2273 break;
Pavankumar Kondetid8608522011-05-04 10:19:47 +05302274 }
Steve Mucklef132c6c2012-06-06 18:30:57 -07002275 otg->phy->state = OTG_STATE_B_SRP_INIT;
Vijayavardhan Vennapusaa3152032012-03-05 16:29:30 +05302276 msm_otg_start_timer(motg, TB_SRP_FAIL, B_SRP_FAIL);
2277 break;
Pavankumar Kondetid8608522011-05-04 10:19:47 +05302278 } else {
Vijayavardhan Vennapusaa3152032012-03-05 16:29:30 +05302279 pr_debug("chg_work cancel");
Pavankumar Kondetiaa449e12011-11-04 11:09:26 +05302280 cancel_delayed_work_sync(&motg->chg_work);
Pavankumar Kondetid8608522011-05-04 10:19:47 +05302281 motg->chg_state = USB_CHG_STATE_UNDEFINED;
2282 motg->chg_type = USB_INVALID_CHARGER;
Rajkumar Raghupathy18fd7132012-04-20 11:28:13 +05302283 msm_otg_notify_charger(motg, 0);
Steve Mucklef132c6c2012-06-06 18:30:57 -07002284 msm_otg_reset(otg->phy);
2285 pm_runtime_put_noidle(otg->phy->dev);
2286 pm_runtime_suspend(otg->phy->dev);
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05302287 }
2288 break;
Vijayavardhan Vennapusaa3152032012-03-05 16:29:30 +05302289 case OTG_STATE_B_SRP_INIT:
2290 if (!test_bit(ID, &motg->inputs) ||
2291 test_bit(ID_A, &motg->inputs) ||
2292 test_bit(ID_C, &motg->inputs) ||
2293 (test_bit(B_SESS_VLD, &motg->inputs) &&
2294 !test_bit(ID_B, &motg->inputs))) {
2295 pr_debug("!id || id_a/c || b_sess_vld+!id_b\n");
2296 msm_otg_del_timer(motg);
Steve Mucklef132c6c2012-06-06 18:30:57 -07002297 otg->phy->state = OTG_STATE_B_IDLE;
Vijayavardhan Vennapusaa3152032012-03-05 16:29:30 +05302298 /*
2299 * clear VBUSVLDEXTSEL and VBUSVLDEXT register
2300 * bits after SRP initiation.
2301 */
Steve Mucklef132c6c2012-06-06 18:30:57 -07002302 ulpi_write(otg->phy, 0x0, 0x98);
Vijayavardhan Vennapusaa3152032012-03-05 16:29:30 +05302303 work = 1;
2304 } else if (test_bit(B_SRP_FAIL, &motg->tmouts)) {
2305 pr_debug("b_srp_fail\n");
2306 pr_info("A-device did not respond to SRP\n");
2307 clear_bit(B_BUS_REQ, &motg->inputs);
2308 clear_bit(B_SRP_FAIL, &motg->tmouts);
2309 otg_send_event(OTG_EVENT_NO_RESP_FOR_SRP);
Steve Mucklef132c6c2012-06-06 18:30:57 -07002310 ulpi_write(otg->phy, 0x0, 0x98);
2311 otg->phy->state = OTG_STATE_B_IDLE;
Vijayavardhan Vennapusaa3152032012-03-05 16:29:30 +05302312 motg->b_last_se0_sess = jiffies;
2313 work = 1;
2314 }
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05302315 break;
2316 case OTG_STATE_B_PERIPHERAL:
Vijayavardhan Vennapusaa3152032012-03-05 16:29:30 +05302317 if (!test_bit(ID, &motg->inputs) ||
2318 test_bit(ID_A, &motg->inputs) ||
2319 test_bit(ID_B, &motg->inputs) ||
2320 !test_bit(B_SESS_VLD, &motg->inputs)) {
2321 pr_debug("!id || id_a/b || !b_sess_vld\n");
Pavankumar Kondetid8608522011-05-04 10:19:47 +05302322 motg->chg_state = USB_CHG_STATE_UNDEFINED;
2323 motg->chg_type = USB_INVALID_CHARGER;
Vijayavardhan Vennapusaa3152032012-03-05 16:29:30 +05302324 msm_otg_notify_charger(motg, 0);
2325 srp_reqd = otg->gadget->otg_srp_reqd;
2326 msm_otg_start_peripheral(otg, 0);
Vijayavardhan Vennapusaa3152032012-03-05 16:29:30 +05302327 if (test_bit(ID_B, &motg->inputs))
2328 clear_bit(ID_B, &motg->inputs);
2329 clear_bit(B_BUS_REQ, &motg->inputs);
Steve Mucklef132c6c2012-06-06 18:30:57 -07002330 otg->phy->state = OTG_STATE_B_IDLE;
Vijayavardhan Vennapusaa3152032012-03-05 16:29:30 +05302331 motg->b_last_se0_sess = jiffies;
2332 if (srp_reqd)
2333 msm_otg_start_timer(motg,
2334 TB_TST_SRP, B_TST_SRP);
2335 else
2336 work = 1;
2337 } else if (test_bit(B_BUS_REQ, &motg->inputs) &&
2338 otg->gadget->b_hnp_enable &&
2339 test_bit(A_BUS_SUSPEND, &motg->inputs)) {
2340 pr_debug("b_bus_req && b_hnp_en && a_bus_suspend\n");
2341 msm_otg_start_timer(motg, TB_ASE0_BRST, B_ASE0_BRST);
2342 /* D+ pullup should not be disconnected within 4msec
2343 * after A device suspends the bus. Otherwise PET will
2344 * fail the compliance test.
2345 */
2346 udelay(1000);
2347 msm_otg_start_peripheral(otg, 0);
Steve Mucklef132c6c2012-06-06 18:30:57 -07002348 otg->phy->state = OTG_STATE_B_WAIT_ACON;
Vijayavardhan Vennapusaa3152032012-03-05 16:29:30 +05302349 /*
2350 * start HCD even before A-device enable
2351 * pull-up to meet HNP timings.
2352 */
2353 otg->host->is_b_host = 1;
2354 msm_otg_start_host(otg, 1);
Amit Blay6fa647a2012-05-24 14:12:08 +03002355 } else if (test_bit(A_BUS_SUSPEND, &motg->inputs) &&
2356 test_bit(B_SESS_VLD, &motg->inputs)) {
2357 pr_debug("a_bus_suspend && b_sess_vld\n");
2358 if (motg->caps & ALLOW_LPM_ON_DEV_SUSPEND) {
Steve Mucklef132c6c2012-06-06 18:30:57 -07002359 pm_runtime_put_noidle(otg->phy->dev);
2360 pm_runtime_suspend(otg->phy->dev);
Amit Blay6fa647a2012-05-24 14:12:08 +03002361 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002362 } else if (test_bit(ID_C, &motg->inputs)) {
Pavankumar Kondetiaa449e12011-11-04 11:09:26 +05302363 msm_otg_notify_charger(motg, IDEV_ACA_CHG_MAX);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002364 }
2365 break;
Vijayavardhan Vennapusaa3152032012-03-05 16:29:30 +05302366 case OTG_STATE_B_WAIT_ACON:
2367 if (!test_bit(ID, &motg->inputs) ||
2368 test_bit(ID_A, &motg->inputs) ||
2369 test_bit(ID_B, &motg->inputs) ||
2370 !test_bit(B_SESS_VLD, &motg->inputs)) {
2371 pr_debug("!id || id_a/b || !b_sess_vld\n");
2372 msm_otg_del_timer(motg);
Pavankumar Kondetiaa449e12011-11-04 11:09:26 +05302373 /*
Vijayavardhan Vennapusaa3152032012-03-05 16:29:30 +05302374 * A-device is physically disconnected during
2375 * HNP. Remove HCD.
Pavankumar Kondetiaa449e12011-11-04 11:09:26 +05302376 */
Vijayavardhan Vennapusaa3152032012-03-05 16:29:30 +05302377 msm_otg_start_host(otg, 0);
2378 otg->host->is_b_host = 0;
2379
2380 clear_bit(B_BUS_REQ, &motg->inputs);
2381 clear_bit(A_BUS_SUSPEND, &motg->inputs);
2382 motg->b_last_se0_sess = jiffies;
Heikki Krogerus1d4c9292012-02-13 13:24:09 +02002383 otg->phy->state = OTG_STATE_B_IDLE;
2384 msm_otg_reset(otg->phy);
Vijayavardhan Vennapusaa3152032012-03-05 16:29:30 +05302385 work = 1;
2386 } else if (test_bit(A_CONN, &motg->inputs)) {
2387 pr_debug("a_conn\n");
2388 clear_bit(A_BUS_SUSPEND, &motg->inputs);
Steve Mucklef132c6c2012-06-06 18:30:57 -07002389 otg->phy->state = OTG_STATE_B_HOST;
Vijayavardhan Vennapusaa3152032012-03-05 16:29:30 +05302390 /*
2391 * PET disconnects D+ pullup after reset is generated
2392 * by B device in B_HOST role which is not detected by
2393 * B device. As workaorund , start timer of 300msec
2394 * and stop timer if A device is enumerated else clear
2395 * A_CONN.
2396 */
2397 msm_otg_start_timer(motg, TB_TST_CONFIG,
2398 B_TST_CONFIG);
2399 } else if (test_bit(B_ASE0_BRST, &motg->tmouts)) {
2400 pr_debug("b_ase0_brst_tmout\n");
2401 pr_info("B HNP fail:No response from A device\n");
2402 msm_otg_start_host(otg, 0);
Steve Mucklef132c6c2012-06-06 18:30:57 -07002403 msm_otg_reset(otg->phy);
Vijayavardhan Vennapusaa3152032012-03-05 16:29:30 +05302404 otg->host->is_b_host = 0;
2405 clear_bit(B_ASE0_BRST, &motg->tmouts);
2406 clear_bit(A_BUS_SUSPEND, &motg->inputs);
2407 clear_bit(B_BUS_REQ, &motg->inputs);
2408 otg_send_event(OTG_EVENT_HNP_FAILED);
Steve Mucklef132c6c2012-06-06 18:30:57 -07002409 otg->phy->state = OTG_STATE_B_IDLE;
Vijayavardhan Vennapusaa3152032012-03-05 16:29:30 +05302410 work = 1;
2411 } else if (test_bit(ID_C, &motg->inputs)) {
2412 msm_otg_notify_charger(motg, IDEV_ACA_CHG_MAX);
2413 }
2414 break;
2415 case OTG_STATE_B_HOST:
2416 if (!test_bit(B_BUS_REQ, &motg->inputs) ||
2417 !test_bit(A_CONN, &motg->inputs) ||
2418 !test_bit(B_SESS_VLD, &motg->inputs)) {
2419 pr_debug("!b_bus_req || !a_conn || !b_sess_vld\n");
2420 clear_bit(A_CONN, &motg->inputs);
2421 clear_bit(B_BUS_REQ, &motg->inputs);
2422 msm_otg_start_host(otg, 0);
2423 otg->host->is_b_host = 0;
Steve Mucklef132c6c2012-06-06 18:30:57 -07002424 otg->phy->state = OTG_STATE_B_IDLE;
2425 msm_otg_reset(otg->phy);
Vijayavardhan Vennapusaa3152032012-03-05 16:29:30 +05302426 work = 1;
2427 } else if (test_bit(ID_C, &motg->inputs)) {
2428 msm_otg_notify_charger(motg, IDEV_ACA_CHG_MAX);
2429 }
2430 break;
2431 case OTG_STATE_A_IDLE:
2432 otg->default_a = 1;
2433 if (test_bit(ID, &motg->inputs) &&
2434 !test_bit(ID_A, &motg->inputs)) {
2435 pr_debug("id && !id_a\n");
2436 otg->default_a = 0;
2437 clear_bit(A_BUS_DROP, &motg->inputs);
Steve Mucklef132c6c2012-06-06 18:30:57 -07002438 otg->phy->state = OTG_STATE_B_IDLE;
Vijayavardhan Vennapusaa3152032012-03-05 16:29:30 +05302439 del_timer_sync(&motg->id_timer);
2440 msm_otg_link_reset(motg);
2441 msm_chg_enable_aca_intr(motg);
2442 msm_otg_notify_charger(motg, 0);
2443 work = 1;
2444 } else if (!test_bit(A_BUS_DROP, &motg->inputs) &&
2445 (test_bit(A_SRP_DET, &motg->inputs) ||
2446 test_bit(A_BUS_REQ, &motg->inputs))) {
2447 pr_debug("!a_bus_drop && (a_srp_det || a_bus_req)\n");
2448
2449 clear_bit(A_SRP_DET, &motg->inputs);
2450 /* Disable SRP detection */
2451 writel_relaxed((readl_relaxed(USB_OTGSC) &
2452 ~OTGSC_INTSTS_MASK) &
2453 ~OTGSC_DPIE, USB_OTGSC);
2454
Steve Mucklef132c6c2012-06-06 18:30:57 -07002455 otg->phy->state = OTG_STATE_A_WAIT_VRISE;
Vijayavardhan Vennapusaa3152032012-03-05 16:29:30 +05302456 /* VBUS should not be supplied before end of SRP pulse
2457 * generated by PET, if not complaince test fail.
2458 */
2459 usleep_range(10000, 12000);
2460 /* ACA: ID_A: Stop charging untill enumeration */
2461 if (test_bit(ID_A, &motg->inputs))
2462 msm_otg_notify_charger(motg, 0);
2463 else
2464 msm_hsusb_vbus_power(motg, 1);
2465 msm_otg_start_timer(motg, TA_WAIT_VRISE, A_WAIT_VRISE);
2466 } else {
2467 pr_debug("No session requested\n");
2468 clear_bit(A_BUS_DROP, &motg->inputs);
2469 if (test_bit(ID_A, &motg->inputs)) {
2470 msm_otg_notify_charger(motg,
2471 IDEV_ACA_CHG_MAX);
2472 } else if (!test_bit(ID, &motg->inputs)) {
2473 msm_otg_notify_charger(motg, 0);
2474 /*
2475 * A-device is not providing power on VBUS.
2476 * Enable SRP detection.
2477 */
2478 writel_relaxed(0x13, USB_USBMODE);
2479 writel_relaxed((readl_relaxed(USB_OTGSC) &
2480 ~OTGSC_INTSTS_MASK) |
2481 OTGSC_DPIE, USB_OTGSC);
2482 mb();
2483 }
2484 }
2485 break;
2486 case OTG_STATE_A_WAIT_VRISE:
2487 if ((test_bit(ID, &motg->inputs) &&
2488 !test_bit(ID_A, &motg->inputs)) ||
2489 test_bit(A_BUS_DROP, &motg->inputs) ||
2490 test_bit(A_WAIT_VRISE, &motg->tmouts)) {
2491 pr_debug("id || a_bus_drop || a_wait_vrise_tmout\n");
2492 clear_bit(A_BUS_REQ, &motg->inputs);
2493 msm_otg_del_timer(motg);
2494 msm_hsusb_vbus_power(motg, 0);
Steve Mucklef132c6c2012-06-06 18:30:57 -07002495 otg->phy->state = OTG_STATE_A_WAIT_VFALL;
Vijayavardhan Vennapusaa3152032012-03-05 16:29:30 +05302496 msm_otg_start_timer(motg, TA_WAIT_VFALL, A_WAIT_VFALL);
2497 } else if (test_bit(A_VBUS_VLD, &motg->inputs)) {
2498 pr_debug("a_vbus_vld\n");
Steve Mucklef132c6c2012-06-06 18:30:57 -07002499 otg->phy->state = OTG_STATE_A_WAIT_BCON;
Vijayavardhan Vennapusaa3152032012-03-05 16:29:30 +05302500 if (TA_WAIT_BCON > 0)
2501 msm_otg_start_timer(motg, TA_WAIT_BCON,
2502 A_WAIT_BCON);
2503 msm_otg_start_host(otg, 1);
2504 msm_chg_enable_aca_det(motg);
2505 msm_chg_disable_aca_intr(motg);
Chiranjeevi Velempati489a27c2012-03-29 09:47:17 +05302506 mod_timer(&motg->id_timer, ID_TIMER_FREQ);
Vijayavardhan Vennapusaa3152032012-03-05 16:29:30 +05302507 if (msm_chg_check_aca_intr(motg))
2508 work = 1;
2509 }
2510 break;
2511 case OTG_STATE_A_WAIT_BCON:
2512 if ((test_bit(ID, &motg->inputs) &&
2513 !test_bit(ID_A, &motg->inputs)) ||
2514 test_bit(A_BUS_DROP, &motg->inputs) ||
2515 test_bit(A_WAIT_BCON, &motg->tmouts)) {
2516 pr_debug("(id && id_a/b/c) || a_bus_drop ||"
2517 "a_wait_bcon_tmout\n");
2518 if (test_bit(A_WAIT_BCON, &motg->tmouts)) {
2519 pr_info("Device No Response\n");
2520 otg_send_event(OTG_EVENT_DEV_CONN_TMOUT);
2521 }
2522 msm_otg_del_timer(motg);
2523 clear_bit(A_BUS_REQ, &motg->inputs);
2524 clear_bit(B_CONN, &motg->inputs);
2525 msm_otg_start_host(otg, 0);
2526 /*
2527 * ACA: ID_A with NO accessory, just the A plug is
2528 * attached to ACA: Use IDCHG_MAX for charging
2529 */
2530 if (test_bit(ID_A, &motg->inputs))
2531 msm_otg_notify_charger(motg, IDEV_CHG_MIN);
2532 else
2533 msm_hsusb_vbus_power(motg, 0);
Steve Mucklef132c6c2012-06-06 18:30:57 -07002534 otg->phy->state = OTG_STATE_A_WAIT_VFALL;
Vijayavardhan Vennapusaa3152032012-03-05 16:29:30 +05302535 msm_otg_start_timer(motg, TA_WAIT_VFALL, A_WAIT_VFALL);
2536 } else if (!test_bit(A_VBUS_VLD, &motg->inputs)) {
2537 pr_debug("!a_vbus_vld\n");
2538 clear_bit(B_CONN, &motg->inputs);
2539 msm_otg_del_timer(motg);
2540 msm_otg_start_host(otg, 0);
Steve Mucklef132c6c2012-06-06 18:30:57 -07002541 otg->phy->state = OTG_STATE_A_VBUS_ERR;
2542 msm_otg_reset(otg->phy);
Vijayavardhan Vennapusaa3152032012-03-05 16:29:30 +05302543 } else if (test_bit(ID_A, &motg->inputs)) {
2544 msm_hsusb_vbus_power(motg, 0);
2545 } else if (!test_bit(A_BUS_REQ, &motg->inputs)) {
2546 /*
2547 * If TA_WAIT_BCON is infinite, we don;t
2548 * turn off VBUS. Enter low power mode.
2549 */
2550 if (TA_WAIT_BCON < 0)
Steve Mucklef132c6c2012-06-06 18:30:57 -07002551 pm_runtime_put_sync(otg->phy->dev);
Vijayavardhan Vennapusaa3152032012-03-05 16:29:30 +05302552 } else if (!test_bit(ID, &motg->inputs)) {
2553 msm_hsusb_vbus_power(motg, 1);
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05302554 }
2555 break;
2556 case OTG_STATE_A_HOST:
Vijayavardhan Vennapusaa3152032012-03-05 16:29:30 +05302557 if ((test_bit(ID, &motg->inputs) &&
2558 !test_bit(ID_A, &motg->inputs)) ||
2559 test_bit(A_BUS_DROP, &motg->inputs)) {
2560 pr_debug("id_a/b/c || a_bus_drop\n");
2561 clear_bit(B_CONN, &motg->inputs);
2562 clear_bit(A_BUS_REQ, &motg->inputs);
2563 msm_otg_del_timer(motg);
Steve Mucklef132c6c2012-06-06 18:30:57 -07002564 otg->phy->state = OTG_STATE_A_WAIT_VFALL;
Vijayavardhan Vennapusaa3152032012-03-05 16:29:30 +05302565 msm_otg_start_host(otg, 0);
2566 if (!test_bit(ID_A, &motg->inputs))
2567 msm_hsusb_vbus_power(motg, 0);
2568 msm_otg_start_timer(motg, TA_WAIT_VFALL, A_WAIT_VFALL);
2569 } else if (!test_bit(A_VBUS_VLD, &motg->inputs)) {
2570 pr_debug("!a_vbus_vld\n");
2571 clear_bit(B_CONN, &motg->inputs);
2572 msm_otg_del_timer(motg);
Steve Mucklef132c6c2012-06-06 18:30:57 -07002573 otg->phy->state = OTG_STATE_A_VBUS_ERR;
Vijayavardhan Vennapusaa3152032012-03-05 16:29:30 +05302574 msm_otg_start_host(otg, 0);
Heikki Krogerus1d4c9292012-02-13 13:24:09 +02002575 msm_otg_reset(otg->phy);
Vijayavardhan Vennapusaa3152032012-03-05 16:29:30 +05302576 } else if (!test_bit(A_BUS_REQ, &motg->inputs)) {
2577 /*
2578 * a_bus_req is de-asserted when root hub is
2579 * suspended or HNP is in progress.
2580 */
2581 pr_debug("!a_bus_req\n");
2582 msm_otg_del_timer(motg);
Steve Mucklef132c6c2012-06-06 18:30:57 -07002583 otg->phy->state = OTG_STATE_A_SUSPEND;
Vijayavardhan Vennapusaa3152032012-03-05 16:29:30 +05302584 if (otg->host->b_hnp_enable)
2585 msm_otg_start_timer(motg, TA_AIDL_BDIS,
2586 A_AIDL_BDIS);
2587 else
Steve Mucklef132c6c2012-06-06 18:30:57 -07002588 pm_runtime_put_sync(otg->phy->dev);
Vijayavardhan Vennapusaa3152032012-03-05 16:29:30 +05302589 } else if (!test_bit(B_CONN, &motg->inputs)) {
2590 pr_debug("!b_conn\n");
2591 msm_otg_del_timer(motg);
Steve Mucklef132c6c2012-06-06 18:30:57 -07002592 otg->phy->state = OTG_STATE_A_WAIT_BCON;
Vijayavardhan Vennapusaa3152032012-03-05 16:29:30 +05302593 if (TA_WAIT_BCON > 0)
2594 msm_otg_start_timer(motg, TA_WAIT_BCON,
2595 A_WAIT_BCON);
2596 if (msm_chg_check_aca_intr(motg))
2597 work = 1;
2598 } else if (test_bit(ID_A, &motg->inputs)) {
2599 msm_otg_del_timer(motg);
2600 msm_hsusb_vbus_power(motg, 0);
2601 if (motg->chg_type == USB_ACA_DOCK_CHARGER)
2602 msm_otg_notify_charger(motg,
2603 IDEV_ACA_CHG_MAX);
2604 else
2605 msm_otg_notify_charger(motg,
2606 IDEV_CHG_MIN - motg->mA_port);
2607 } else if (!test_bit(ID, &motg->inputs)) {
2608 motg->chg_state = USB_CHG_STATE_UNDEFINED;
2609 motg->chg_type = USB_INVALID_CHARGER;
2610 msm_otg_notify_charger(motg, 0);
2611 msm_hsusb_vbus_power(motg, 1);
2612 }
2613 break;
2614 case OTG_STATE_A_SUSPEND:
2615 if ((test_bit(ID, &motg->inputs) &&
2616 !test_bit(ID_A, &motg->inputs)) ||
2617 test_bit(A_BUS_DROP, &motg->inputs) ||
2618 test_bit(A_AIDL_BDIS, &motg->tmouts)) {
2619 pr_debug("id_a/b/c || a_bus_drop ||"
2620 "a_aidl_bdis_tmout\n");
2621 msm_otg_del_timer(motg);
2622 clear_bit(B_CONN, &motg->inputs);
Steve Mucklef132c6c2012-06-06 18:30:57 -07002623 otg->phy->state = OTG_STATE_A_WAIT_VFALL;
Vijayavardhan Vennapusaa3152032012-03-05 16:29:30 +05302624 msm_otg_start_host(otg, 0);
Steve Mucklef132c6c2012-06-06 18:30:57 -07002625 msm_otg_reset(otg->phy);
Vijayavardhan Vennapusaa3152032012-03-05 16:29:30 +05302626 if (!test_bit(ID_A, &motg->inputs))
2627 msm_hsusb_vbus_power(motg, 0);
2628 msm_otg_start_timer(motg, TA_WAIT_VFALL, A_WAIT_VFALL);
2629 } else if (!test_bit(A_VBUS_VLD, &motg->inputs)) {
2630 pr_debug("!a_vbus_vld\n");
2631 msm_otg_del_timer(motg);
2632 clear_bit(B_CONN, &motg->inputs);
Steve Mucklef132c6c2012-06-06 18:30:57 -07002633 otg->phy->state = OTG_STATE_A_VBUS_ERR;
Vijayavardhan Vennapusaa3152032012-03-05 16:29:30 +05302634 msm_otg_start_host(otg, 0);
Steve Mucklef132c6c2012-06-06 18:30:57 -07002635 msm_otg_reset(otg->phy);
Vijayavardhan Vennapusaa3152032012-03-05 16:29:30 +05302636 } else if (!test_bit(B_CONN, &motg->inputs) &&
2637 otg->host->b_hnp_enable) {
2638 pr_debug("!b_conn && b_hnp_enable");
Steve Mucklef132c6c2012-06-06 18:30:57 -07002639 otg->phy->state = OTG_STATE_A_PERIPHERAL;
Vijayavardhan Vennapusaa3152032012-03-05 16:29:30 +05302640 msm_otg_host_hnp_enable(otg, 1);
2641 otg->gadget->is_a_peripheral = 1;
2642 msm_otg_start_peripheral(otg, 1);
2643 } else if (!test_bit(B_CONN, &motg->inputs) &&
2644 !otg->host->b_hnp_enable) {
2645 pr_debug("!b_conn && !b_hnp_enable");
2646 /*
2647 * bus request is dropped during suspend.
2648 * acquire again for next device.
2649 */
2650 set_bit(A_BUS_REQ, &motg->inputs);
Steve Mucklef132c6c2012-06-06 18:30:57 -07002651 otg->phy->state = OTG_STATE_A_WAIT_BCON;
Vijayavardhan Vennapusaa3152032012-03-05 16:29:30 +05302652 if (TA_WAIT_BCON > 0)
2653 msm_otg_start_timer(motg, TA_WAIT_BCON,
2654 A_WAIT_BCON);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002655 } else if (test_bit(ID_A, &motg->inputs)) {
Mayank Ranae3926882011-12-26 09:47:54 +05302656 msm_hsusb_vbus_power(motg, 0);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002657 msm_otg_notify_charger(motg,
Vijayavardhan Vennapusaa3152032012-03-05 16:29:30 +05302658 IDEV_CHG_MIN - motg->mA_port);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002659 } else if (!test_bit(ID, &motg->inputs)) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002660 msm_otg_notify_charger(motg, 0);
Mayank Ranae3926882011-12-26 09:47:54 +05302661 msm_hsusb_vbus_power(motg, 1);
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05302662 }
2663 break;
Vijayavardhan Vennapusaa3152032012-03-05 16:29:30 +05302664 case OTG_STATE_A_PERIPHERAL:
2665 if ((test_bit(ID, &motg->inputs) &&
2666 !test_bit(ID_A, &motg->inputs)) ||
2667 test_bit(A_BUS_DROP, &motg->inputs)) {
2668 pr_debug("id _f/b/c || a_bus_drop\n");
2669 /* Clear BIDL_ADIS timer */
2670 msm_otg_del_timer(motg);
Steve Mucklef132c6c2012-06-06 18:30:57 -07002671 otg->phy->state = OTG_STATE_A_WAIT_VFALL;
Vijayavardhan Vennapusaa3152032012-03-05 16:29:30 +05302672 msm_otg_start_peripheral(otg, 0);
2673 otg->gadget->is_a_peripheral = 0;
2674 msm_otg_start_host(otg, 0);
Steve Mucklef132c6c2012-06-06 18:30:57 -07002675 msm_otg_reset(otg->phy);
Vijayavardhan Vennapusaa3152032012-03-05 16:29:30 +05302676 if (!test_bit(ID_A, &motg->inputs))
2677 msm_hsusb_vbus_power(motg, 0);
2678 msm_otg_start_timer(motg, TA_WAIT_VFALL, A_WAIT_VFALL);
2679 } else if (!test_bit(A_VBUS_VLD, &motg->inputs)) {
2680 pr_debug("!a_vbus_vld\n");
2681 /* Clear BIDL_ADIS timer */
2682 msm_otg_del_timer(motg);
Steve Mucklef132c6c2012-06-06 18:30:57 -07002683 otg->phy->state = OTG_STATE_A_VBUS_ERR;
Vijayavardhan Vennapusaa3152032012-03-05 16:29:30 +05302684 msm_otg_start_peripheral(otg, 0);
2685 otg->gadget->is_a_peripheral = 0;
2686 msm_otg_start_host(otg, 0);
2687 } else if (test_bit(A_BIDL_ADIS, &motg->tmouts)) {
2688 pr_debug("a_bidl_adis_tmout\n");
2689 msm_otg_start_peripheral(otg, 0);
2690 otg->gadget->is_a_peripheral = 0;
Steve Mucklef132c6c2012-06-06 18:30:57 -07002691 otg->phy->state = OTG_STATE_A_WAIT_BCON;
Vijayavardhan Vennapusaa3152032012-03-05 16:29:30 +05302692 set_bit(A_BUS_REQ, &motg->inputs);
2693 msm_otg_host_hnp_enable(otg, 0);
2694 if (TA_WAIT_BCON > 0)
2695 msm_otg_start_timer(motg, TA_WAIT_BCON,
2696 A_WAIT_BCON);
2697 } else if (test_bit(ID_A, &motg->inputs)) {
2698 msm_hsusb_vbus_power(motg, 0);
2699 msm_otg_notify_charger(motg,
2700 IDEV_CHG_MIN - motg->mA_port);
2701 } else if (!test_bit(ID, &motg->inputs)) {
2702 msm_otg_notify_charger(motg, 0);
2703 msm_hsusb_vbus_power(motg, 1);
2704 }
2705 break;
2706 case OTG_STATE_A_WAIT_VFALL:
2707 if (test_bit(A_WAIT_VFALL, &motg->tmouts)) {
2708 clear_bit(A_VBUS_VLD, &motg->inputs);
Steve Mucklef132c6c2012-06-06 18:30:57 -07002709 otg->phy->state = OTG_STATE_A_IDLE;
Vijayavardhan Vennapusaa3152032012-03-05 16:29:30 +05302710 work = 1;
2711 }
2712 break;
2713 case OTG_STATE_A_VBUS_ERR:
2714 if ((test_bit(ID, &motg->inputs) &&
2715 !test_bit(ID_A, &motg->inputs)) ||
2716 test_bit(A_BUS_DROP, &motg->inputs) ||
2717 test_bit(A_CLR_ERR, &motg->inputs)) {
Steve Mucklef132c6c2012-06-06 18:30:57 -07002718 otg->phy->state = OTG_STATE_A_WAIT_VFALL;
Vijayavardhan Vennapusaa3152032012-03-05 16:29:30 +05302719 if (!test_bit(ID_A, &motg->inputs))
2720 msm_hsusb_vbus_power(motg, 0);
2721 msm_otg_start_timer(motg, TA_WAIT_VFALL, A_WAIT_VFALL);
2722 motg->chg_state = USB_CHG_STATE_UNDEFINED;
2723 motg->chg_type = USB_INVALID_CHARGER;
2724 msm_otg_notify_charger(motg, 0);
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05302725 }
2726 break;
2727 default:
2728 break;
2729 }
Vijayavardhan Vennapusaa3152032012-03-05 16:29:30 +05302730 if (work)
2731 queue_work(system_nrt_wq, &motg->sm_work);
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05302732}
2733
2734static irqreturn_t msm_otg_irq(int irq, void *data)
2735{
2736 struct msm_otg *motg = data;
Steve Mucklef132c6c2012-06-06 18:30:57 -07002737 struct usb_otg *otg = motg->phy.otg;
Vijayavardhan Vennapusaa3152032012-03-05 16:29:30 +05302738 u32 otgsc = 0, usbsts, pc;
2739 bool work = 0;
2740 irqreturn_t ret = IRQ_HANDLED;
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05302741
Pavankumar Kondeti87c01042010-12-07 17:53:58 +05302742 if (atomic_read(&motg->in_lpm)) {
Manu Gautamf8c45642012-08-10 10:20:56 -07002743 pr_debug("OTG IRQ: %d in LPM\n", irq);
Pavankumar Kondeti87c01042010-12-07 17:53:58 +05302744 disable_irq_nosync(irq);
Manu Gautamf8c45642012-08-10 10:20:56 -07002745 motg->async_int = irq;
Vijayavardhan Vennapusa6d783712012-08-06 17:18:56 +05302746 if (atomic_read(&motg->pm_suspended)) {
Jack Pham5ca279b2012-05-14 18:42:54 -07002747 motg->sm_work_pending = true;
Vijayavardhan Vennapusa6d783712012-08-06 17:18:56 +05302748 if ((otg->phy->state == OTG_STATE_A_SUSPEND) ||
2749 (otg->phy->state == OTG_STATE_A_WAIT_BCON))
2750 set_bit(A_BUS_REQ, &motg->inputs);
2751 } else {
Steve Mucklef132c6c2012-06-06 18:30:57 -07002752 pm_request_resume(otg->phy->dev);
Vijayavardhan Vennapusa6d783712012-08-06 17:18:56 +05302753 }
Pavankumar Kondeti87c01042010-12-07 17:53:58 +05302754 return IRQ_HANDLED;
2755 }
2756
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002757 usbsts = readl(USB_USBSTS);
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05302758 otgsc = readl(USB_OTGSC);
Vijayavardhan Vennapusaa3152032012-03-05 16:29:30 +05302759
2760 if (!(otgsc & OTG_OTGSTS_MASK) && !(usbsts & OTG_USBSTS_MASK))
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05302761 return IRQ_NONE;
2762
2763 if ((otgsc & OTGSC_IDIS) && (otgsc & OTGSC_IDIE)) {
Pavankumar Kondetiaa449e12011-11-04 11:09:26 +05302764 if (otgsc & OTGSC_ID) {
Vijayavardhan Vennapusaa3152032012-03-05 16:29:30 +05302765 pr_debug("Id set\n");
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05302766 set_bit(ID, &motg->inputs);
Pavankumar Kondetiaa449e12011-11-04 11:09:26 +05302767 } else {
Vijayavardhan Vennapusaa3152032012-03-05 16:29:30 +05302768 pr_debug("Id clear\n");
2769 /*
2770 * Assert a_bus_req to supply power on
2771 * VBUS when Micro/Mini-A cable is connected
2772 * with out user intervention.
2773 */
2774 set_bit(A_BUS_REQ, &motg->inputs);
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05302775 clear_bit(ID, &motg->inputs);
Pavankumar Kondetiaa449e12011-11-04 11:09:26 +05302776 msm_chg_enable_aca_det(motg);
2777 }
Vijayavardhan Vennapusaa3152032012-03-05 16:29:30 +05302778 writel_relaxed(otgsc, USB_OTGSC);
2779 work = 1;
2780 } else if (otgsc & OTGSC_DPIS) {
2781 pr_debug("DPIS detected\n");
2782 writel_relaxed(otgsc, USB_OTGSC);
2783 set_bit(A_SRP_DET, &motg->inputs);
2784 set_bit(A_BUS_REQ, &motg->inputs);
2785 work = 1;
2786 } else if (otgsc & OTGSC_BSVIS) {
2787 writel_relaxed(otgsc, USB_OTGSC);
2788 /*
2789 * BSV interrupt comes when operating as an A-device
2790 * (VBUS on/off).
2791 * But, handle BSV when charger is removed from ACA in ID_A
2792 */
Steve Mucklef132c6c2012-06-06 18:30:57 -07002793 if ((otg->phy->state >= OTG_STATE_A_IDLE) &&
Vijayavardhan Vennapusaa3152032012-03-05 16:29:30 +05302794 !test_bit(ID_A, &motg->inputs))
2795 return IRQ_HANDLED;
Pavankumar Kondetiaa449e12011-11-04 11:09:26 +05302796 if (otgsc & OTGSC_BSV) {
Vijayavardhan Vennapusaa3152032012-03-05 16:29:30 +05302797 pr_debug("BSV set\n");
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05302798 set_bit(B_SESS_VLD, &motg->inputs);
Pavankumar Kondetiaa449e12011-11-04 11:09:26 +05302799 } else {
Vijayavardhan Vennapusaa3152032012-03-05 16:29:30 +05302800 pr_debug("BSV clear\n");
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05302801 clear_bit(B_SESS_VLD, &motg->inputs);
Amit Blay6fa647a2012-05-24 14:12:08 +03002802 clear_bit(A_BUS_SUSPEND, &motg->inputs);
2803
Pavankumar Kondetiaa449e12011-11-04 11:09:26 +05302804 msm_chg_check_aca_intr(motg);
2805 }
Vijayavardhan Vennapusaa3152032012-03-05 16:29:30 +05302806 work = 1;
2807 } else if (usbsts & STS_PCI) {
2808 pc = readl_relaxed(USB_PORTSC);
2809 pr_debug("portsc = %x\n", pc);
2810 ret = IRQ_NONE;
2811 /*
2812 * HCD Acks PCI interrupt. We use this to switch
2813 * between different OTG states.
2814 */
2815 work = 1;
Steve Mucklef132c6c2012-06-06 18:30:57 -07002816 switch (otg->phy->state) {
Vijayavardhan Vennapusaa3152032012-03-05 16:29:30 +05302817 case OTG_STATE_A_SUSPEND:
2818 if (otg->host->b_hnp_enable && (pc & PORTSC_CSC) &&
2819 !(pc & PORTSC_CCS)) {
2820 pr_debug("B_CONN clear\n");
2821 clear_bit(B_CONN, &motg->inputs);
2822 msm_otg_del_timer(motg);
2823 }
2824 break;
2825 case OTG_STATE_A_PERIPHERAL:
2826 /*
2827 * A-peripheral observed activity on bus.
2828 * clear A_BIDL_ADIS timer.
2829 */
2830 msm_otg_del_timer(motg);
2831 work = 0;
2832 break;
2833 case OTG_STATE_B_WAIT_ACON:
2834 if ((pc & PORTSC_CSC) && (pc & PORTSC_CCS)) {
2835 pr_debug("A_CONN set\n");
2836 set_bit(A_CONN, &motg->inputs);
2837 /* Clear ASE0_BRST timer */
2838 msm_otg_del_timer(motg);
2839 }
2840 break;
2841 case OTG_STATE_B_HOST:
2842 if ((pc & PORTSC_CSC) && !(pc & PORTSC_CCS)) {
2843 pr_debug("A_CONN clear\n");
2844 clear_bit(A_CONN, &motg->inputs);
2845 msm_otg_del_timer(motg);
2846 }
2847 break;
2848 case OTG_STATE_A_WAIT_BCON:
2849 if (TA_WAIT_BCON < 0)
2850 set_bit(A_BUS_REQ, &motg->inputs);
2851 default:
2852 work = 0;
2853 break;
2854 }
2855 } else if (usbsts & STS_URI) {
2856 ret = IRQ_NONE;
Steve Mucklef132c6c2012-06-06 18:30:57 -07002857 switch (otg->phy->state) {
Vijayavardhan Vennapusaa3152032012-03-05 16:29:30 +05302858 case OTG_STATE_A_PERIPHERAL:
2859 /*
2860 * A-peripheral observed activity on bus.
2861 * clear A_BIDL_ADIS timer.
2862 */
2863 msm_otg_del_timer(motg);
2864 work = 0;
2865 break;
2866 default:
2867 work = 0;
2868 break;
2869 }
2870 } else if (usbsts & STS_SLI) {
2871 ret = IRQ_NONE;
2872 work = 0;
Steve Mucklef132c6c2012-06-06 18:30:57 -07002873 switch (otg->phy->state) {
Vijayavardhan Vennapusaa3152032012-03-05 16:29:30 +05302874 case OTG_STATE_B_PERIPHERAL:
2875 if (otg->gadget->b_hnp_enable) {
2876 set_bit(A_BUS_SUSPEND, &motg->inputs);
2877 set_bit(B_BUS_REQ, &motg->inputs);
2878 work = 1;
2879 }
2880 break;
2881 case OTG_STATE_A_PERIPHERAL:
2882 msm_otg_start_timer(motg, TA_BIDL_ADIS,
2883 A_BIDL_ADIS);
2884 break;
2885 default:
2886 break;
2887 }
2888 } else if ((usbsts & PHY_ALT_INT)) {
2889 writel_relaxed(PHY_ALT_INT, USB_USBSTS);
2890 if (msm_chg_check_aca_intr(motg))
2891 work = 1;
2892 ret = IRQ_HANDLED;
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05302893 }
Vijayavardhan Vennapusaa3152032012-03-05 16:29:30 +05302894 if (work)
2895 queue_work(system_nrt_wq, &motg->sm_work);
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05302896
Vijayavardhan Vennapusaa3152032012-03-05 16:29:30 +05302897 return ret;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002898}
2899
2900static void msm_otg_set_vbus_state(int online)
2901{
Pavankumar Kondeti4960f312011-12-06 15:46:14 +05302902 static bool init;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002903 struct msm_otg *motg = the_msm_otg;
Mayank Ranabaf31f42012-07-05 09:43:54 +05302904 struct usb_otg *otg = motg->phy.otg;
2905
2906 /* In A Host Mode, ignore received BSV interrupts */
2907 if (otg->phy->state >= OTG_STATE_A_IDLE)
2908 return;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002909
Pavankumar Kondeti4960f312011-12-06 15:46:14 +05302910 if (online) {
2911 pr_debug("PMIC: BSV set\n");
2912 set_bit(B_SESS_VLD, &motg->inputs);
2913 } else {
2914 pr_debug("PMIC: BSV clear\n");
2915 clear_bit(B_SESS_VLD, &motg->inputs);
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05302916 }
2917
Pavankumar Kondeti4960f312011-12-06 15:46:14 +05302918 if (!init) {
2919 init = true;
2920 complete(&pmic_vbus_init);
2921 pr_debug("PMIC: BSV init complete\n");
2922 return;
2923 }
2924
Pavankumar Kondeti2aec9f32012-06-13 09:06:03 +05302925 if (test_bit(MHL, &motg->inputs) ||
2926 mhl_det_in_progress) {
2927 pr_debug("PMIC: BSV interrupt ignored in MHL\n");
2928 return;
2929 }
2930
Jack Pham5ca279b2012-05-14 18:42:54 -07002931 if (atomic_read(&motg->pm_suspended))
2932 motg->sm_work_pending = true;
2933 else
2934 queue_work(system_nrt_wq, &motg->sm_work);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002935}
2936
Vijayavardhan Vennapusa68d55cf2012-06-27 20:06:12 +05302937static void msm_pmic_id_status_w(struct work_struct *w)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002938{
Vijayavardhan Vennapusa68d55cf2012-06-27 20:06:12 +05302939 struct msm_otg *motg = container_of(w, struct msm_otg,
2940 pmic_id_status_work.work);
2941 int work = 0;
2942 unsigned long flags;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002943
Vijayavardhan Vennapusa68d55cf2012-06-27 20:06:12 +05302944 local_irq_save(flags);
Pavankumar Kondeti4960f312011-12-06 15:46:14 +05302945 if (irq_read_line(motg->pdata->pmic_id_irq)) {
Vijayavardhan Vennapusa68d55cf2012-06-27 20:06:12 +05302946 if (!test_and_set_bit(ID, &motg->inputs)) {
2947 pr_debug("PMIC: ID set\n");
2948 work = 1;
2949 }
Pavankumar Kondeti4960f312011-12-06 15:46:14 +05302950 } else {
Vijayavardhan Vennapusa68d55cf2012-06-27 20:06:12 +05302951 if (test_and_clear_bit(ID, &motg->inputs)) {
2952 pr_debug("PMIC: ID clear\n");
2953 set_bit(A_BUS_REQ, &motg->inputs);
2954 work = 1;
2955 }
Pavankumar Kondeti4960f312011-12-06 15:46:14 +05302956 }
2957
Vijayavardhan Vennapusa68d55cf2012-06-27 20:06:12 +05302958 if (work && (motg->phy.state != OTG_STATE_UNDEFINED)) {
Jack Pham5ca279b2012-05-14 18:42:54 -07002959 if (atomic_read(&motg->pm_suspended))
2960 motg->sm_work_pending = true;
2961 else
2962 queue_work(system_nrt_wq, &motg->sm_work);
2963 }
Vijayavardhan Vennapusa68d55cf2012-06-27 20:06:12 +05302964 local_irq_restore(flags);
2965
2966}
2967
2968#define MSM_PMIC_ID_STATUS_DELAY 5 /* 5msec */
2969static irqreturn_t msm_pmic_id_irq(int irq, void *data)
2970{
2971 struct msm_otg *motg = data;
2972
Pavankumar Kondeti2aec9f32012-06-13 09:06:03 +05302973 if (test_bit(MHL, &motg->inputs) ||
2974 mhl_det_in_progress) {
2975 pr_debug("PMIC: Id interrupt ignored in MHL\n");
2976 return IRQ_HANDLED;
2977 }
2978
Vijayavardhan Vennapusa68d55cf2012-06-27 20:06:12 +05302979 if (!aca_id_turned_on)
2980 /*schedule delayed work for 5msec for ID line state to settle*/
2981 queue_delayed_work(system_nrt_wq, &motg->pmic_id_status_work,
2982 msecs_to_jiffies(MSM_PMIC_ID_STATUS_DELAY));
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002983
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05302984 return IRQ_HANDLED;
2985}
2986
2987static int msm_otg_mode_show(struct seq_file *s, void *unused)
2988{
2989 struct msm_otg *motg = s->private;
Steve Mucklef132c6c2012-06-06 18:30:57 -07002990 struct usb_phy *phy = &motg->phy;
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05302991
Steve Mucklef132c6c2012-06-06 18:30:57 -07002992 switch (phy->state) {
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05302993 case OTG_STATE_A_HOST:
2994 seq_printf(s, "host\n");
2995 break;
2996 case OTG_STATE_B_PERIPHERAL:
2997 seq_printf(s, "peripheral\n");
2998 break;
2999 default:
3000 seq_printf(s, "none\n");
3001 break;
3002 }
3003
3004 return 0;
3005}
3006
3007static int msm_otg_mode_open(struct inode *inode, struct file *file)
3008{
3009 return single_open(file, msm_otg_mode_show, inode->i_private);
3010}
3011
3012static ssize_t msm_otg_mode_write(struct file *file, const char __user *ubuf,
3013 size_t count, loff_t *ppos)
3014{
Pavankumar Kondetie2904ee2011-02-15 09:42:35 +05303015 struct seq_file *s = file->private_data;
3016 struct msm_otg *motg = s->private;
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05303017 char buf[16];
Steve Mucklef132c6c2012-06-06 18:30:57 -07003018 struct usb_phy *phy = &motg->phy;
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05303019 int status = count;
3020 enum usb_mode_type req_mode;
3021
3022 memset(buf, 0x00, sizeof(buf));
3023
3024 if (copy_from_user(&buf, ubuf, min_t(size_t, sizeof(buf) - 1, count))) {
3025 status = -EFAULT;
3026 goto out;
3027 }
3028
3029 if (!strncmp(buf, "host", 4)) {
3030 req_mode = USB_HOST;
3031 } else if (!strncmp(buf, "peripheral", 10)) {
3032 req_mode = USB_PERIPHERAL;
3033 } else if (!strncmp(buf, "none", 4)) {
3034 req_mode = USB_NONE;
3035 } else {
3036 status = -EINVAL;
3037 goto out;
3038 }
3039
3040 switch (req_mode) {
3041 case USB_NONE:
Steve Mucklef132c6c2012-06-06 18:30:57 -07003042 switch (phy->state) {
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05303043 case OTG_STATE_A_HOST:
3044 case OTG_STATE_B_PERIPHERAL:
3045 set_bit(ID, &motg->inputs);
3046 clear_bit(B_SESS_VLD, &motg->inputs);
3047 break;
3048 default:
3049 goto out;
3050 }
3051 break;
3052 case USB_PERIPHERAL:
Steve Mucklef132c6c2012-06-06 18:30:57 -07003053 switch (phy->state) {
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05303054 case OTG_STATE_B_IDLE:
3055 case OTG_STATE_A_HOST:
3056 set_bit(ID, &motg->inputs);
3057 set_bit(B_SESS_VLD, &motg->inputs);
3058 break;
3059 default:
3060 goto out;
3061 }
3062 break;
3063 case USB_HOST:
Steve Mucklef132c6c2012-06-06 18:30:57 -07003064 switch (phy->state) {
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05303065 case OTG_STATE_B_IDLE:
3066 case OTG_STATE_B_PERIPHERAL:
3067 clear_bit(ID, &motg->inputs);
3068 break;
3069 default:
3070 goto out;
3071 }
3072 break;
3073 default:
3074 goto out;
3075 }
3076
Steve Mucklef132c6c2012-06-06 18:30:57 -07003077 pm_runtime_resume(phy->dev);
Vijayavardhan Vennapusaa3152032012-03-05 16:29:30 +05303078 queue_work(system_nrt_wq, &motg->sm_work);
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05303079out:
3080 return status;
3081}
3082
3083const struct file_operations msm_otg_mode_fops = {
3084 .open = msm_otg_mode_open,
3085 .read = seq_read,
3086 .write = msm_otg_mode_write,
3087 .llseek = seq_lseek,
3088 .release = single_release,
3089};
3090
Chiranjeevi Velempatif9a11542012-03-28 18:18:34 +05303091static int msm_otg_show_otg_state(struct seq_file *s, void *unused)
3092{
3093 struct msm_otg *motg = s->private;
Steve Mucklef132c6c2012-06-06 18:30:57 -07003094 struct usb_phy *phy = &motg->phy;
Chiranjeevi Velempatif9a11542012-03-28 18:18:34 +05303095
Steve Mucklef132c6c2012-06-06 18:30:57 -07003096 seq_printf(s, "%s\n", otg_state_string(phy->state));
Chiranjeevi Velempatif9a11542012-03-28 18:18:34 +05303097 return 0;
3098}
3099
3100static int msm_otg_otg_state_open(struct inode *inode, struct file *file)
3101{
3102 return single_open(file, msm_otg_show_otg_state, inode->i_private);
3103}
3104
3105const struct file_operations msm_otg_state_fops = {
3106 .open = msm_otg_otg_state_open,
3107 .read = seq_read,
3108 .llseek = seq_lseek,
3109 .release = single_release,
3110};
3111
Anji jonnalad270e2d2011-08-09 11:28:32 +05303112static int msm_otg_show_chg_type(struct seq_file *s, void *unused)
3113{
3114 struct msm_otg *motg = s->private;
3115
Pavankumar Kondeti9ef69cb2011-12-12 14:18:22 +05303116 seq_printf(s, "%s\n", chg_to_string(motg->chg_type));
Anji jonnalad270e2d2011-08-09 11:28:32 +05303117 return 0;
3118}
3119
3120static int msm_otg_chg_open(struct inode *inode, struct file *file)
3121{
3122 return single_open(file, msm_otg_show_chg_type, inode->i_private);
3123}
3124
3125const struct file_operations msm_otg_chg_fops = {
3126 .open = msm_otg_chg_open,
3127 .read = seq_read,
3128 .llseek = seq_lseek,
3129 .release = single_release,
3130};
3131
Pavankumar Kondetiaa449e12011-11-04 11:09:26 +05303132static int msm_otg_aca_show(struct seq_file *s, void *unused)
3133{
3134 if (debug_aca_enabled)
3135 seq_printf(s, "enabled\n");
3136 else
3137 seq_printf(s, "disabled\n");
3138
3139 return 0;
3140}
3141
3142static int msm_otg_aca_open(struct inode *inode, struct file *file)
3143{
3144 return single_open(file, msm_otg_aca_show, inode->i_private);
3145}
3146
3147static ssize_t msm_otg_aca_write(struct file *file, const char __user *ubuf,
3148 size_t count, loff_t *ppos)
3149{
3150 char buf[8];
3151
3152 memset(buf, 0x00, sizeof(buf));
3153
3154 if (copy_from_user(&buf, ubuf, min_t(size_t, sizeof(buf) - 1, count)))
3155 return -EFAULT;
3156
3157 if (!strncmp(buf, "enable", 6))
3158 debug_aca_enabled = true;
3159 else
3160 debug_aca_enabled = false;
3161
3162 return count;
3163}
3164
3165const struct file_operations msm_otg_aca_fops = {
3166 .open = msm_otg_aca_open,
3167 .read = seq_read,
3168 .write = msm_otg_aca_write,
3169 .llseek = seq_lseek,
3170 .release = single_release,
3171};
3172
Manu Gautam8bdcc592012-03-06 11:26:06 +05303173static int msm_otg_bus_show(struct seq_file *s, void *unused)
3174{
3175 if (debug_bus_voting_enabled)
3176 seq_printf(s, "enabled\n");
3177 else
3178 seq_printf(s, "disabled\n");
3179
3180 return 0;
3181}
3182
3183static int msm_otg_bus_open(struct inode *inode, struct file *file)
3184{
3185 return single_open(file, msm_otg_bus_show, inode->i_private);
3186}
3187
3188static ssize_t msm_otg_bus_write(struct file *file, const char __user *ubuf,
3189 size_t count, loff_t *ppos)
3190{
3191 char buf[8];
3192 int ret;
3193 struct seq_file *s = file->private_data;
3194 struct msm_otg *motg = s->private;
3195
3196 memset(buf, 0x00, sizeof(buf));
3197
3198 if (copy_from_user(&buf, ubuf, min_t(size_t, sizeof(buf) - 1, count)))
3199 return -EFAULT;
3200
3201 if (!strncmp(buf, "enable", 6)) {
3202 /* Do not vote here. Let OTG statemachine decide when to vote */
3203 debug_bus_voting_enabled = true;
3204 } else {
3205 debug_bus_voting_enabled = false;
3206 if (motg->bus_perf_client) {
3207 ret = msm_bus_scale_client_update_request(
3208 motg->bus_perf_client, 0);
3209 if (ret)
Steve Mucklef132c6c2012-06-06 18:30:57 -07003210 dev_err(motg->phy.dev, "%s: Failed to devote "
Manu Gautam8bdcc592012-03-06 11:26:06 +05303211 "for bus bw %d\n", __func__, ret);
3212 }
3213 }
3214
3215 return count;
3216}
3217
3218const struct file_operations msm_otg_bus_fops = {
3219 .open = msm_otg_bus_open,
3220 .read = seq_read,
3221 .write = msm_otg_bus_write,
3222 .llseek = seq_lseek,
3223 .release = single_release,
3224};
3225
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05303226static struct dentry *msm_otg_dbg_root;
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05303227
3228static int msm_otg_debugfs_init(struct msm_otg *motg)
3229{
Manu Gautam8bdcc592012-03-06 11:26:06 +05303230 struct dentry *msm_otg_dentry;
Anji jonnalad270e2d2011-08-09 11:28:32 +05303231
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05303232 msm_otg_dbg_root = debugfs_create_dir("msm_otg", NULL);
3233
3234 if (!msm_otg_dbg_root || IS_ERR(msm_otg_dbg_root))
3235 return -ENODEV;
3236
Anji jonnalad270e2d2011-08-09 11:28:32 +05303237 if (motg->pdata->mode == USB_OTG &&
3238 motg->pdata->otg_control == OTG_USER_CONTROL) {
3239
Manu Gautam8bdcc592012-03-06 11:26:06 +05303240 msm_otg_dentry = debugfs_create_file("mode", S_IRUGO |
Anji jonnalad270e2d2011-08-09 11:28:32 +05303241 S_IWUSR, msm_otg_dbg_root, motg,
3242 &msm_otg_mode_fops);
3243
Manu Gautam8bdcc592012-03-06 11:26:06 +05303244 if (!msm_otg_dentry) {
Anji jonnalad270e2d2011-08-09 11:28:32 +05303245 debugfs_remove(msm_otg_dbg_root);
3246 msm_otg_dbg_root = NULL;
3247 return -ENODEV;
3248 }
3249 }
3250
Manu Gautam8bdcc592012-03-06 11:26:06 +05303251 msm_otg_dentry = debugfs_create_file("chg_type", S_IRUGO,
Anji jonnalad270e2d2011-08-09 11:28:32 +05303252 msm_otg_dbg_root, motg,
3253 &msm_otg_chg_fops);
3254
Manu Gautam8bdcc592012-03-06 11:26:06 +05303255 if (!msm_otg_dentry) {
Pavankumar Kondetiaa449e12011-11-04 11:09:26 +05303256 debugfs_remove_recursive(msm_otg_dbg_root);
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05303257 return -ENODEV;
3258 }
3259
Manu Gautam8bdcc592012-03-06 11:26:06 +05303260 msm_otg_dentry = debugfs_create_file("aca", S_IRUGO | S_IWUSR,
Pavankumar Kondetiaa449e12011-11-04 11:09:26 +05303261 msm_otg_dbg_root, motg,
3262 &msm_otg_aca_fops);
3263
Manu Gautam8bdcc592012-03-06 11:26:06 +05303264 if (!msm_otg_dentry) {
Pavankumar Kondetiaa449e12011-11-04 11:09:26 +05303265 debugfs_remove_recursive(msm_otg_dbg_root);
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05303266 return -ENODEV;
3267 }
3268
Manu Gautam8bdcc592012-03-06 11:26:06 +05303269 msm_otg_dentry = debugfs_create_file("bus_voting", S_IRUGO | S_IWUSR,
3270 msm_otg_dbg_root, motg,
3271 &msm_otg_bus_fops);
3272
3273 if (!msm_otg_dentry) {
3274 debugfs_remove_recursive(msm_otg_dbg_root);
3275 return -ENODEV;
3276 }
Chiranjeevi Velempatif9a11542012-03-28 18:18:34 +05303277
3278 msm_otg_dentry = debugfs_create_file("otg_state", S_IRUGO,
3279 msm_otg_dbg_root, motg, &msm_otg_state_fops);
3280
3281 if (!msm_otg_dentry) {
3282 debugfs_remove_recursive(msm_otg_dbg_root);
3283 return -ENODEV;
3284 }
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05303285 return 0;
3286}
3287
3288static void msm_otg_debugfs_cleanup(void)
3289{
Anji jonnalad270e2d2011-08-09 11:28:32 +05303290 debugfs_remove_recursive(msm_otg_dbg_root);
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05303291}
3292
Pavankumar Kondetieaea7fe2011-10-27 14:46:45 +05303293static u64 msm_otg_dma_mask = DMA_BIT_MASK(64);
3294static struct platform_device *msm_otg_add_pdev(
3295 struct platform_device *ofdev, const char *name)
3296{
3297 struct platform_device *pdev;
3298 const struct resource *res = ofdev->resource;
3299 unsigned int num = ofdev->num_resources;
3300 int retval;
3301
3302 pdev = platform_device_alloc(name, -1);
3303 if (!pdev) {
3304 retval = -ENOMEM;
3305 goto error;
3306 }
3307
3308 pdev->dev.coherent_dma_mask = DMA_BIT_MASK(32);
3309 pdev->dev.dma_mask = &msm_otg_dma_mask;
3310
3311 if (num) {
3312 retval = platform_device_add_resources(pdev, res, num);
3313 if (retval)
3314 goto error;
3315 }
3316
3317 retval = platform_device_add(pdev);
3318 if (retval)
3319 goto error;
3320
3321 return pdev;
3322
3323error:
3324 platform_device_put(pdev);
3325 return ERR_PTR(retval);
3326}
3327
3328static int msm_otg_setup_devices(struct platform_device *ofdev,
3329 enum usb_mode_type mode, bool init)
3330{
3331 const char *gadget_name = "msm_hsusb";
3332 const char *host_name = "msm_hsusb_host";
3333 static struct platform_device *gadget_pdev;
3334 static struct platform_device *host_pdev;
3335 int retval = 0;
3336
3337 if (!init) {
3338 if (gadget_pdev)
3339 platform_device_unregister(gadget_pdev);
3340 if (host_pdev)
3341 platform_device_unregister(host_pdev);
3342 return 0;
3343 }
3344
3345 switch (mode) {
3346 case USB_OTG:
3347 /* fall through */
3348 case USB_PERIPHERAL:
3349 gadget_pdev = msm_otg_add_pdev(ofdev, gadget_name);
3350 if (IS_ERR(gadget_pdev)) {
3351 retval = PTR_ERR(gadget_pdev);
3352 break;
3353 }
3354 if (mode == USB_PERIPHERAL)
3355 break;
3356 /* fall through */
3357 case USB_HOST:
3358 host_pdev = msm_otg_add_pdev(ofdev, host_name);
3359 if (IS_ERR(host_pdev)) {
3360 retval = PTR_ERR(host_pdev);
3361 if (mode == USB_OTG)
3362 platform_device_unregister(gadget_pdev);
3363 }
3364 break;
3365 default:
3366 break;
3367 }
3368
3369 return retval;
3370}
3371
3372struct msm_otg_platform_data *msm_otg_dt_to_pdata(struct platform_device *pdev)
3373{
3374 struct device_node *node = pdev->dev.of_node;
3375 struct msm_otg_platform_data *pdata;
3376 int len = 0;
3377
3378 pdata = devm_kzalloc(&pdev->dev, sizeof(*pdata), GFP_KERNEL);
3379 if (!pdata) {
3380 pr_err("unable to allocate platform data\n");
3381 return NULL;
3382 }
3383 of_get_property(node, "qcom,hsusb-otg-phy-init-seq", &len);
3384 if (len) {
3385 pdata->phy_init_seq = devm_kzalloc(&pdev->dev, len, GFP_KERNEL);
3386 if (!pdata->phy_init_seq)
3387 return NULL;
3388 of_property_read_u32_array(node, "qcom,hsusb-otg-phy-init-seq",
3389 pdata->phy_init_seq,
3390 len/sizeof(*pdata->phy_init_seq));
3391 }
3392 of_property_read_u32(node, "qcom,hsusb-otg-power-budget",
3393 &pdata->power_budget);
3394 of_property_read_u32(node, "qcom,hsusb-otg-mode",
3395 &pdata->mode);
3396 of_property_read_u32(node, "qcom,hsusb-otg-otg-control",
3397 &pdata->otg_control);
3398 of_property_read_u32(node, "qcom,hsusb-otg-default-mode",
3399 &pdata->default_mode);
3400 of_property_read_u32(node, "qcom,hsusb-otg-phy-type",
3401 &pdata->phy_type);
3402 of_property_read_u32(node, "qcom,hsusb-otg-pmic-id-irq",
3403 &pdata->pmic_id_irq);
Manu Gautambd53fba2012-07-31 16:13:06 +05303404 pdata->disable_reset_on_disconnect = of_property_read_bool(node,
3405 "qcom,hsusb-otg-disable-reset");
3406
Pavankumar Kondetieaea7fe2011-10-27 14:46:45 +05303407 return pdata;
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05303408}
3409
3410static int __init msm_otg_probe(struct platform_device *pdev)
3411{
Manu Gautamf8c45642012-08-10 10:20:56 -07003412 int ret = 0;
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05303413 struct resource *res;
3414 struct msm_otg *motg;
Heikki Krogerus1d4c9292012-02-13 13:24:09 +02003415 struct usb_phy *phy;
Pavankumar Kondetieaea7fe2011-10-27 14:46:45 +05303416 struct msm_otg_platform_data *pdata;
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05303417
3418 dev_info(&pdev->dev, "msm_otg probe\n");
Pavankumar Kondetieaea7fe2011-10-27 14:46:45 +05303419
3420 if (pdev->dev.of_node) {
3421 dev_dbg(&pdev->dev, "device tree enabled\n");
3422 pdata = msm_otg_dt_to_pdata(pdev);
3423 if (!pdata)
3424 return -ENOMEM;
3425 ret = msm_otg_setup_devices(pdev, pdata->mode, true);
3426 if (ret) {
3427 dev_err(&pdev->dev, "devices setup failed\n");
3428 return ret;
3429 }
3430 } else if (!pdev->dev.platform_data) {
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05303431 dev_err(&pdev->dev, "No platform data given. Bailing out\n");
3432 return -ENODEV;
Pavankumar Kondetieaea7fe2011-10-27 14:46:45 +05303433 } else {
3434 pdata = pdev->dev.platform_data;
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05303435 }
3436
3437 motg = kzalloc(sizeof(struct msm_otg), GFP_KERNEL);
3438 if (!motg) {
3439 dev_err(&pdev->dev, "unable to allocate msm_otg\n");
3440 return -ENOMEM;
3441 }
3442
Heikki Krogerus1d4c9292012-02-13 13:24:09 +02003443 motg->phy.otg = kzalloc(sizeof(struct usb_otg), GFP_KERNEL);
3444 if (!motg->phy.otg) {
Steve Mucklef132c6c2012-06-06 18:30:57 -07003445 dev_err(&pdev->dev, "unable to allocate usb_otg\n");
3446 ret = -ENOMEM;
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05303447 goto free_motg;
3448 }
3449
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003450 the_msm_otg = motg;
Pavankumar Kondetieaea7fe2011-10-27 14:46:45 +05303451 motg->pdata = pdata;
Steve Mucklef132c6c2012-06-06 18:30:57 -07003452 phy = &motg->phy;
3453 phy->dev = &pdev->dev;
Anji jonnala0f73cac2011-05-04 10:19:46 +05303454
3455 /*
Pavankumar Kondetiaa449e12011-11-04 11:09:26 +05303456 * ACA ID_GND threshold range is overlapped with OTG ID_FLOAT. Hence
3457 * PHY treat ACA ID_GND as float and no interrupt is generated. But
3458 * PMIC can detect ACA ID_GND and generate an interrupt.
3459 */
3460 if (aca_enabled() && motg->pdata->otg_control != OTG_PMIC_CONTROL) {
3461 dev_err(&pdev->dev, "ACA can not be enabled without PMIC\n");
3462 ret = -EINVAL;
Steve Mucklef132c6c2012-06-06 18:30:57 -07003463 goto free_otg;
Pavankumar Kondetiaa449e12011-11-04 11:09:26 +05303464 }
3465
Ofir Cohen4da266f2012-01-03 10:19:29 +02003466 /* initialize reset counter */
3467 motg->reset_counter = 0;
3468
Amit Blay02eff132011-09-21 16:46:24 +03003469 /* Some targets don't support PHY clock. */
Manu Gautam5143b252012-01-05 19:25:23 -08003470 motg->phy_reset_clk = clk_get(&pdev->dev, "phy_clk");
Amit Blay02eff132011-09-21 16:46:24 +03003471 if (IS_ERR(motg->phy_reset_clk))
Manu Gautam5143b252012-01-05 19:25:23 -08003472 dev_err(&pdev->dev, "failed to get phy_clk\n");
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05303473
Pavankumar Kondeti923262e2012-04-20 15:34:24 +05303474 /*
3475 * Targets on which link uses asynchronous reset methodology,
3476 * free running clock is not required during the reset.
3477 */
Manu Gautam5143b252012-01-05 19:25:23 -08003478 motg->clk = clk_get(&pdev->dev, "alt_core_clk");
Pavankumar Kondeti923262e2012-04-20 15:34:24 +05303479 if (IS_ERR(motg->clk))
3480 dev_dbg(&pdev->dev, "alt_core_clk is not present\n");
3481 else
3482 clk_set_rate(motg->clk, 60000000);
Anji jonnala0f73cac2011-05-04 10:19:46 +05303483
3484 /*
Manu Gautam5143b252012-01-05 19:25:23 -08003485 * USB Core is running its protocol engine based on CORE CLK,
Anji jonnala0f73cac2011-05-04 10:19:46 +05303486 * CORE CLK must be running at >55Mhz for correct HSUSB
3487 * operation and USB core cannot tolerate frequency changes on
3488 * CORE CLK. For such USB cores, vote for maximum clk frequency
3489 * on pclk source
3490 */
Manu Gautam5143b252012-01-05 19:25:23 -08003491 motg->core_clk = clk_get(&pdev->dev, "core_clk");
3492 if (IS_ERR(motg->core_clk)) {
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05303493 motg->core_clk = NULL;
Manu Gautam5143b252012-01-05 19:25:23 -08003494 dev_err(&pdev->dev, "failed to get core_clk\n");
Pavankumar Kondetibc541332012-04-20 15:32:04 +05303495 ret = PTR_ERR(motg->core_clk);
Manu Gautam5143b252012-01-05 19:25:23 -08003496 goto put_clk;
3497 }
3498 clk_set_rate(motg->core_clk, INT_MAX);
3499
3500 motg->pclk = clk_get(&pdev->dev, "iface_clk");
3501 if (IS_ERR(motg->pclk)) {
3502 dev_err(&pdev->dev, "failed to get iface_clk\n");
3503 ret = PTR_ERR(motg->pclk);
3504 goto put_core_clk;
3505 }
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05303506
3507 res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
3508 if (!res) {
3509 dev_err(&pdev->dev, "failed to get platform resource mem\n");
3510 ret = -ENODEV;
Manu Gautam5143b252012-01-05 19:25:23 -08003511 goto put_pclk;
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05303512 }
3513
3514 motg->regs = ioremap(res->start, resource_size(res));
3515 if (!motg->regs) {
3516 dev_err(&pdev->dev, "ioremap failed\n");
3517 ret = -ENOMEM;
Manu Gautam5143b252012-01-05 19:25:23 -08003518 goto put_pclk;
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05303519 }
3520 dev_info(&pdev->dev, "OTG regs = %p\n", motg->regs);
3521
3522 motg->irq = platform_get_irq(pdev, 0);
3523 if (!motg->irq) {
3524 dev_err(&pdev->dev, "platform_get_irq failed\n");
3525 ret = -ENODEV;
3526 goto free_regs;
3527 }
3528
Manu Gautamf8c45642012-08-10 10:20:56 -07003529 motg->async_irq = platform_get_irq_byname(pdev, "async_irq");
3530 if (motg->async_irq < 0) {
3531 dev_dbg(&pdev->dev, "platform_get_irq for async_int failed\n");
3532 motg->async_irq = 0;
3533 }
3534
Stephen Boyd30ad10b2012-03-01 14:51:04 -08003535 motg->xo_handle = msm_xo_get(MSM_XO_TCXO_D0, "usb");
Anji jonnala7da3f262011-12-02 17:22:14 -08003536 if (IS_ERR(motg->xo_handle)) {
3537 dev_err(&pdev->dev, "%s not able to get the handle "
3538 "to vote for TCXO D0 buffer\n", __func__);
3539 ret = PTR_ERR(motg->xo_handle);
3540 goto free_regs;
3541 }
Anji jonnala11aa5c42011-05-04 10:19:48 +05303542
Stephen Boyd30ad10b2012-03-01 14:51:04 -08003543 ret = msm_xo_mode_vote(motg->xo_handle, MSM_XO_MODE_ON);
Anji jonnala7da3f262011-12-02 17:22:14 -08003544 if (ret) {
3545 dev_err(&pdev->dev, "%s failed to vote for TCXO "
3546 "D0 buffer%d\n", __func__, ret);
3547 goto free_xo_handle;
3548 }
3549
Manu Gautam28b1bac2012-01-30 16:43:06 +05303550 clk_prepare_enable(motg->pclk);
Anji jonnala11aa5c42011-05-04 10:19:48 +05303551
Mayank Rana248698c2012-04-19 00:03:16 +05303552 motg->vdd_type = VDDCX_CORNER;
Steve Mucklef132c6c2012-06-06 18:30:57 -07003553 hsusb_vddcx = devm_regulator_get(motg->phy.dev, "hsusb_vdd_dig");
Mayank Rana248698c2012-04-19 00:03:16 +05303554 if (IS_ERR(hsusb_vddcx)) {
Steve Mucklef132c6c2012-06-06 18:30:57 -07003555 hsusb_vddcx = devm_regulator_get(motg->phy.dev, "HSUSB_VDDCX");
Mayank Rana248698c2012-04-19 00:03:16 +05303556 if (IS_ERR(hsusb_vddcx)) {
Steve Mucklef132c6c2012-06-06 18:30:57 -07003557 dev_err(motg->phy.dev, "unable to get hsusb vddcx\n");
Hemant Kumar41812392012-07-13 15:26:20 -07003558 ret = PTR_ERR(hsusb_vddcx);
Mayank Rana248698c2012-04-19 00:03:16 +05303559 goto devote_xo_handle;
3560 }
3561 motg->vdd_type = VDDCX;
Anji jonnala11aa5c42011-05-04 10:19:48 +05303562 }
3563
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003564 ret = msm_hsusb_config_vddcx(1);
Anji jonnala11aa5c42011-05-04 10:19:48 +05303565 if (ret) {
3566 dev_err(&pdev->dev, "hsusb vddcx configuration failed\n");
Mayank Rana248698c2012-04-19 00:03:16 +05303567 goto devote_xo_handle;
3568 }
3569
3570 ret = regulator_enable(hsusb_vddcx);
3571 if (ret) {
3572 dev_err(&pdev->dev, "unable to enable the hsusb vddcx\n");
3573 goto free_config_vddcx;
Anji jonnala11aa5c42011-05-04 10:19:48 +05303574 }
3575
3576 ret = msm_hsusb_ldo_init(motg, 1);
3577 if (ret) {
3578 dev_err(&pdev->dev, "hsusb vreg configuration failed\n");
Mayank Rana248698c2012-04-19 00:03:16 +05303579 goto free_hsusb_vddcx;
Anji jonnala11aa5c42011-05-04 10:19:48 +05303580 }
3581
Mayank Rana9e9a2ac2012-03-24 04:05:28 +05303582 if (pdata->mhl_enable) {
Pavankumar Kondeti56dc7422012-07-02 12:45:19 +05303583 mhl_usb_hs_switch = devm_regulator_get(motg->phy.dev,
3584 "mhl_usb_hs_switch");
3585 if (IS_ERR(mhl_usb_hs_switch)) {
3586 dev_err(&pdev->dev, "Unable to get mhl_usb_hs_switch\n");
Hemant Kumar41812392012-07-13 15:26:20 -07003587 ret = PTR_ERR(mhl_usb_hs_switch);
Mayank Rana9e9a2ac2012-03-24 04:05:28 +05303588 goto free_ldo_init;
3589 }
3590 }
3591
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003592 ret = msm_hsusb_ldo_enable(motg, 1);
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05303593 if (ret) {
3594 dev_err(&pdev->dev, "hsusb vreg enable failed\n");
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003595 goto free_ldo_init;
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05303596 }
Manu Gautam28b1bac2012-01-30 16:43:06 +05303597 clk_prepare_enable(motg->core_clk);
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05303598
3599 writel(0, USB_USBINTR);
3600 writel(0, USB_OTGSC);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003601 /* Ensure that above STOREs are completed before enabling interrupts */
3602 mb();
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05303603
Pavankumar Kondeti2aec9f32012-06-13 09:06:03 +05303604 ret = msm_otg_mhl_register_callback(motg, msm_otg_mhl_notify_online);
3605 if (ret)
3606 dev_dbg(&pdev->dev, "MHL can not be supported\n");
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003607 wake_lock_init(&motg->wlock, WAKE_LOCK_SUSPEND, "msm_otg");
Vijayavardhan Vennapusaa3152032012-03-05 16:29:30 +05303608 msm_otg_init_timer(motg);
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05303609 INIT_WORK(&motg->sm_work, msm_otg_sm_work);
Pavankumar Kondetid8608522011-05-04 10:19:47 +05303610 INIT_DELAYED_WORK(&motg->chg_work, msm_chg_detect_work);
Vijayavardhan Vennapusa68d55cf2012-06-27 20:06:12 +05303611 INIT_DELAYED_WORK(&motg->pmic_id_status_work, msm_pmic_id_status_w);
Pavankumar Kondetiaa449e12011-11-04 11:09:26 +05303612 setup_timer(&motg->id_timer, msm_otg_id_timer_func,
3613 (unsigned long) motg);
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05303614 ret = request_irq(motg->irq, msm_otg_irq, IRQF_SHARED,
3615 "msm_otg", motg);
3616 if (ret) {
3617 dev_err(&pdev->dev, "request irq failed\n");
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003618 goto destroy_wlock;
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05303619 }
3620
Manu Gautamf8c45642012-08-10 10:20:56 -07003621 if (motg->async_irq) {
3622 ret = request_irq(motg->async_irq, msm_otg_irq, IRQF_SHARED,
3623 "msm_otg", motg);
3624 if (ret) {
3625 dev_err(&pdev->dev, "request irq failed (ASYNC INT)\n");
3626 goto free_irq;
3627 }
3628 disable_irq(motg->async_irq);
3629 }
3630
Jack Pham87f202f2012-08-06 00:24:22 -07003631 if (pdata->otg_control == OTG_PHY_CONTROL && pdata->mpm_otgsessvld_int)
3632 msm_mpm_enable_pin(pdata->mpm_otgsessvld_int, 1);
3633
Heikki Krogerus1d4c9292012-02-13 13:24:09 +02003634 phy->init = msm_otg_reset;
3635 phy->set_power = msm_otg_set_power;
Steve Mucklef132c6c2012-06-06 18:30:57 -07003636 phy->set_suspend = msm_otg_set_suspend;
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05303637
Heikki Krogerus1d4c9292012-02-13 13:24:09 +02003638 phy->io_ops = &msm_otg_io_ops;
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05303639
Heikki Krogerus1d4c9292012-02-13 13:24:09 +02003640 phy->otg->phy = &motg->phy;
3641 phy->otg->set_host = msm_otg_set_host;
3642 phy->otg->set_peripheral = msm_otg_set_peripheral;
Steve Mucklef132c6c2012-06-06 18:30:57 -07003643 phy->otg->start_hnp = msm_otg_start_hnp;
3644 phy->otg->start_srp = msm_otg_start_srp;
Heikki Krogerus1d4c9292012-02-13 13:24:09 +02003645
3646 ret = usb_set_transceiver(&motg->phy);
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05303647 if (ret) {
Heikki Krogerus1d4c9292012-02-13 13:24:09 +02003648 dev_err(&pdev->dev, "usb_set_transceiver failed\n");
Manu Gautamf8c45642012-08-10 10:20:56 -07003649 goto free_async_irq;
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05303650 }
3651
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05303652 if (motg->pdata->mode == USB_OTG &&
Pavankumar Kondeti0d81f312012-01-13 11:34:10 +05303653 motg->pdata->otg_control == OTG_PMIC_CONTROL) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003654 if (motg->pdata->pmic_id_irq) {
3655 ret = request_irq(motg->pdata->pmic_id_irq,
3656 msm_pmic_id_irq,
3657 IRQF_TRIGGER_RISING |
3658 IRQF_TRIGGER_FALLING,
3659 "msm_otg", motg);
3660 if (ret) {
3661 dev_err(&pdev->dev, "request irq failed for PMIC ID\n");
Steve Mucklef132c6c2012-06-06 18:30:57 -07003662 goto remove_phy;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003663 }
3664 } else {
3665 ret = -ENODEV;
3666 dev_err(&pdev->dev, "PMIC IRQ for ID notifications doesn't exist\n");
Steve Mucklef132c6c2012-06-06 18:30:57 -07003667 goto remove_phy;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003668 }
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05303669 }
3670
Vijayavardhan Vennapusafc464f02011-11-04 21:54:00 +05303671 msm_hsusb_mhl_switch_enable(motg, 1);
3672
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05303673 platform_set_drvdata(pdev, motg);
3674 device_init_wakeup(&pdev->dev, 1);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003675 motg->mA_port = IUNIT;
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05303676
Anji jonnalad270e2d2011-08-09 11:28:32 +05303677 ret = msm_otg_debugfs_init(motg);
3678 if (ret)
3679 dev_dbg(&pdev->dev, "mode debugfs file is"
3680 "not available\n");
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05303681
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003682 if (motg->pdata->otg_control == OTG_PMIC_CONTROL)
3683 pm8921_charger_register_vbus_sn(&msm_otg_set_vbus_state);
3684
Amit Blay58b31472011-11-18 09:39:39 +02003685 if (motg->pdata->phy_type == SNPS_28NM_INTEGRATED_PHY) {
3686 if (motg->pdata->otg_control == OTG_PMIC_CONTROL &&
Pavankumar Kondeti0d81f312012-01-13 11:34:10 +05303687 (!(motg->pdata->mode == USB_OTG) ||
3688 motg->pdata->pmic_id_irq))
Amit Blay58b31472011-11-18 09:39:39 +02003689 motg->caps = ALLOW_PHY_POWER_COLLAPSE |
Vijayavardhan Vennapusa03171c72012-04-26 14:44:48 +05303690 ALLOW_PHY_RETENTION;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003691
Amit Blay58b31472011-11-18 09:39:39 +02003692 if (motg->pdata->otg_control == OTG_PHY_CONTROL)
3693 motg->caps = ALLOW_PHY_RETENTION;
3694 }
3695
Amit Blay6fa647a2012-05-24 14:12:08 +03003696 if (motg->pdata->enable_lpm_on_dev_suspend)
3697 motg->caps |= ALLOW_LPM_ON_DEV_SUSPEND;
3698
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003699 wake_lock(&motg->wlock);
Pavankumar Kondeti87c01042010-12-07 17:53:58 +05303700 pm_runtime_set_active(&pdev->dev);
Manu Gautamf8c45642012-08-10 10:20:56 -07003701 pm_runtime_enable(&pdev->dev);
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05303702
Manu Gautamcd82e9d2011-12-20 14:17:28 +05303703 if (motg->pdata->bus_scale_table) {
3704 motg->bus_perf_client =
3705 msm_bus_scale_register_client(motg->pdata->bus_scale_table);
3706 if (!motg->bus_perf_client)
Steve Mucklef132c6c2012-06-06 18:30:57 -07003707 dev_err(motg->phy.dev, "%s: Failed to register BUS "
Manu Gautamcd82e9d2011-12-20 14:17:28 +05303708 "scaling client!!\n", __func__);
Manu Gautam8bdcc592012-03-06 11:26:06 +05303709 else
3710 debug_bus_voting_enabled = true;
Manu Gautamcd82e9d2011-12-20 14:17:28 +05303711 }
3712
Pavankumar Kondeti87c01042010-12-07 17:53:58 +05303713 return 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003714
Steve Mucklef132c6c2012-06-06 18:30:57 -07003715remove_phy:
3716 usb_set_transceiver(NULL);
Manu Gautamf8c45642012-08-10 10:20:56 -07003717free_async_irq:
3718 if (motg->async_irq)
3719 free_irq(motg->async_irq, motg);
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05303720free_irq:
3721 free_irq(motg->irq, motg);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003722destroy_wlock:
3723 wake_lock_destroy(&motg->wlock);
Manu Gautam28b1bac2012-01-30 16:43:06 +05303724 clk_disable_unprepare(motg->core_clk);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003725 msm_hsusb_ldo_enable(motg, 0);
3726free_ldo_init:
Anji jonnala11aa5c42011-05-04 10:19:48 +05303727 msm_hsusb_ldo_init(motg, 0);
Mayank Rana248698c2012-04-19 00:03:16 +05303728free_hsusb_vddcx:
3729 regulator_disable(hsusb_vddcx);
3730free_config_vddcx:
3731 regulator_set_voltage(hsusb_vddcx,
3732 vdd_val[motg->vdd_type][VDD_NONE],
3733 vdd_val[motg->vdd_type][VDD_MAX]);
Anji jonnala7da3f262011-12-02 17:22:14 -08003734devote_xo_handle:
Manu Gautam28b1bac2012-01-30 16:43:06 +05303735 clk_disable_unprepare(motg->pclk);
Stephen Boyd30ad10b2012-03-01 14:51:04 -08003736 msm_xo_mode_vote(motg->xo_handle, MSM_XO_MODE_OFF);
Anji jonnala7da3f262011-12-02 17:22:14 -08003737free_xo_handle:
Stephen Boyd30ad10b2012-03-01 14:51:04 -08003738 msm_xo_put(motg->xo_handle);
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05303739free_regs:
3740 iounmap(motg->regs);
Manu Gautam5143b252012-01-05 19:25:23 -08003741put_pclk:
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05303742 clk_put(motg->pclk);
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05303743put_core_clk:
Manu Gautam5143b252012-01-05 19:25:23 -08003744 clk_put(motg->core_clk);
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05303745put_clk:
Pavankumar Kondeti923262e2012-04-20 15:34:24 +05303746 if (!IS_ERR(motg->clk))
3747 clk_put(motg->clk);
Amit Blay02eff132011-09-21 16:46:24 +03003748 if (!IS_ERR(motg->phy_reset_clk))
3749 clk_put(motg->phy_reset_clk);
Steve Mucklef132c6c2012-06-06 18:30:57 -07003750free_otg:
Heikki Krogerus1d4c9292012-02-13 13:24:09 +02003751 kfree(motg->phy.otg);
Pavankumar Kondetiaa449e12011-11-04 11:09:26 +05303752free_motg:
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05303753 kfree(motg);
3754 return ret;
3755}
3756
3757static int __devexit msm_otg_remove(struct platform_device *pdev)
3758{
3759 struct msm_otg *motg = platform_get_drvdata(pdev);
Steve Mucklef132c6c2012-06-06 18:30:57 -07003760 struct usb_otg *otg = motg->phy.otg;
Pavankumar Kondeti87c01042010-12-07 17:53:58 +05303761 int cnt = 0;
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05303762
3763 if (otg->host || otg->gadget)
3764 return -EBUSY;
3765
Pavankumar Kondetieaea7fe2011-10-27 14:46:45 +05303766 if (pdev->dev.of_node)
3767 msm_otg_setup_devices(pdev, motg->pdata->mode, false);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003768 if (motg->pdata->otg_control == OTG_PMIC_CONTROL)
3769 pm8921_charger_unregister_vbus_sn(0);
Pavankumar Kondeti2aec9f32012-06-13 09:06:03 +05303770 msm_otg_mhl_register_callback(motg, NULL);
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05303771 msm_otg_debugfs_cleanup();
Pavankumar Kondetid8608522011-05-04 10:19:47 +05303772 cancel_delayed_work_sync(&motg->chg_work);
Vijayavardhan Vennapusa68d55cf2012-06-27 20:06:12 +05303773 cancel_delayed_work_sync(&motg->pmic_id_status_work);
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05303774 cancel_work_sync(&motg->sm_work);
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05303775
Pavankumar Kondeti70187732011-02-15 09:42:34 +05303776 pm_runtime_resume(&pdev->dev);
Pavankumar Kondeti87c01042010-12-07 17:53:58 +05303777
3778 device_init_wakeup(&pdev->dev, 0);
3779 pm_runtime_disable(&pdev->dev);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003780 wake_lock_destroy(&motg->wlock);
Pavankumar Kondeti87c01042010-12-07 17:53:58 +05303781
Vijayavardhan Vennapusafc464f02011-11-04 21:54:00 +05303782 msm_hsusb_mhl_switch_enable(motg, 0);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003783 if (motg->pdata->pmic_id_irq)
3784 free_irq(motg->pdata->pmic_id_irq, motg);
Heikki Krogerus1d4c9292012-02-13 13:24:09 +02003785 usb_set_transceiver(NULL);
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05303786 free_irq(motg->irq, motg);
3787
Jack Pham87f202f2012-08-06 00:24:22 -07003788 if (motg->pdata->otg_control == OTG_PHY_CONTROL &&
3789 motg->pdata->mpm_otgsessvld_int)
3790 msm_mpm_enable_pin(motg->pdata->mpm_otgsessvld_int, 0);
3791
Pavankumar Kondeti87c01042010-12-07 17:53:58 +05303792 /*
3793 * Put PHY in low power mode.
3794 */
Steve Mucklef132c6c2012-06-06 18:30:57 -07003795 ulpi_read(otg->phy, 0x14);
3796 ulpi_write(otg->phy, 0x08, 0x09);
Pavankumar Kondeti87c01042010-12-07 17:53:58 +05303797
3798 writel(readl(USB_PORTSC) | PORTSC_PHCD, USB_PORTSC);
3799 while (cnt < PHY_SUSPEND_TIMEOUT_USEC) {
3800 if (readl(USB_PORTSC) & PORTSC_PHCD)
3801 break;
3802 udelay(1);
3803 cnt++;
3804 }
3805 if (cnt >= PHY_SUSPEND_TIMEOUT_USEC)
Steve Mucklef132c6c2012-06-06 18:30:57 -07003806 dev_err(otg->phy->dev, "Unable to suspend PHY\n");
Pavankumar Kondeti87c01042010-12-07 17:53:58 +05303807
Manu Gautam28b1bac2012-01-30 16:43:06 +05303808 clk_disable_unprepare(motg->pclk);
3809 clk_disable_unprepare(motg->core_clk);
Stephen Boyd30ad10b2012-03-01 14:51:04 -08003810 msm_xo_put(motg->xo_handle);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003811 msm_hsusb_ldo_enable(motg, 0);
Anji jonnala11aa5c42011-05-04 10:19:48 +05303812 msm_hsusb_ldo_init(motg, 0);
Mayank Rana248698c2012-04-19 00:03:16 +05303813 regulator_disable(hsusb_vddcx);
3814 regulator_set_voltage(hsusb_vddcx,
3815 vdd_val[motg->vdd_type][VDD_NONE],
3816 vdd_val[motg->vdd_type][VDD_MAX]);
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05303817
3818 iounmap(motg->regs);
Pavankumar Kondeti87c01042010-12-07 17:53:58 +05303819 pm_runtime_set_suspended(&pdev->dev);
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05303820
Amit Blay02eff132011-09-21 16:46:24 +03003821 if (!IS_ERR(motg->phy_reset_clk))
3822 clk_put(motg->phy_reset_clk);
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05303823 clk_put(motg->pclk);
Pavankumar Kondeti923262e2012-04-20 15:34:24 +05303824 if (!IS_ERR(motg->clk))
3825 clk_put(motg->clk);
Manu Gautam5143b252012-01-05 19:25:23 -08003826 clk_put(motg->core_clk);
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05303827
Manu Gautamcd82e9d2011-12-20 14:17:28 +05303828 if (motg->bus_perf_client)
3829 msm_bus_scale_unregister_client(motg->bus_perf_client);
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05303830
Heikki Krogerus1d4c9292012-02-13 13:24:09 +02003831 kfree(motg->phy.otg);
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05303832 kfree(motg);
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05303833 return 0;
3834}
3835
Pavankumar Kondeti87c01042010-12-07 17:53:58 +05303836#ifdef CONFIG_PM_RUNTIME
3837static int msm_otg_runtime_idle(struct device *dev)
3838{
3839 struct msm_otg *motg = dev_get_drvdata(dev);
Steve Mucklef132c6c2012-06-06 18:30:57 -07003840 struct usb_phy *phy = &motg->phy;
Pavankumar Kondeti87c01042010-12-07 17:53:58 +05303841
3842 dev_dbg(dev, "OTG runtime idle\n");
3843
Steve Mucklef132c6c2012-06-06 18:30:57 -07003844 if (phy->state == OTG_STATE_UNDEFINED)
Pavankumar Kondeti8be99cf2011-08-04 10:48:08 +05303845 return -EAGAIN;
3846 else
3847 return 0;
Pavankumar Kondeti87c01042010-12-07 17:53:58 +05303848}
3849
3850static int msm_otg_runtime_suspend(struct device *dev)
3851{
3852 struct msm_otg *motg = dev_get_drvdata(dev);
3853
3854 dev_dbg(dev, "OTG runtime suspend\n");
3855 return msm_otg_suspend(motg);
3856}
3857
3858static int msm_otg_runtime_resume(struct device *dev)
3859{
3860 struct msm_otg *motg = dev_get_drvdata(dev);
3861
3862 dev_dbg(dev, "OTG runtime resume\n");
Pavankumar Kondeti8be99cf2011-08-04 10:48:08 +05303863 pm_runtime_get_noresume(dev);
Pavankumar Kondeti87c01042010-12-07 17:53:58 +05303864 return msm_otg_resume(motg);
3865}
Pavankumar Kondeti87c01042010-12-07 17:53:58 +05303866#endif
3867
Pavankumar Kondeti70187732011-02-15 09:42:34 +05303868#ifdef CONFIG_PM_SLEEP
Pavankumar Kondeti87c01042010-12-07 17:53:58 +05303869static int msm_otg_pm_suspend(struct device *dev)
3870{
Jack Pham5ca279b2012-05-14 18:42:54 -07003871 int ret = 0;
Pavankumar Kondeti87c01042010-12-07 17:53:58 +05303872 struct msm_otg *motg = dev_get_drvdata(dev);
3873
3874 dev_dbg(dev, "OTG PM suspend\n");
Jack Pham5ca279b2012-05-14 18:42:54 -07003875
3876 atomic_set(&motg->pm_suspended, 1);
3877 ret = msm_otg_suspend(motg);
3878 if (ret)
3879 atomic_set(&motg->pm_suspended, 0);
3880
3881 return ret;
Pavankumar Kondeti87c01042010-12-07 17:53:58 +05303882}
3883
3884static int msm_otg_pm_resume(struct device *dev)
3885{
Jack Pham5ca279b2012-05-14 18:42:54 -07003886 int ret = 0;
Pavankumar Kondeti87c01042010-12-07 17:53:58 +05303887 struct msm_otg *motg = dev_get_drvdata(dev);
Pavankumar Kondeti87c01042010-12-07 17:53:58 +05303888
3889 dev_dbg(dev, "OTG PM resume\n");
3890
Jack Pham5ca279b2012-05-14 18:42:54 -07003891 atomic_set(&motg->pm_suspended, 0);
3892 if (motg->sm_work_pending) {
3893 motg->sm_work_pending = false;
Pavankumar Kondeti87c01042010-12-07 17:53:58 +05303894
Jack Pham5ca279b2012-05-14 18:42:54 -07003895 pm_runtime_get_noresume(dev);
3896 ret = msm_otg_resume(motg);
Pavankumar Kondeti87c01042010-12-07 17:53:58 +05303897
Jack Pham5ca279b2012-05-14 18:42:54 -07003898 /* Update runtime PM status */
3899 pm_runtime_disable(dev);
3900 pm_runtime_set_active(dev);
3901 pm_runtime_enable(dev);
3902
3903 queue_work(system_nrt_wq, &motg->sm_work);
3904 }
3905
3906 return ret;
Pavankumar Kondeti87c01042010-12-07 17:53:58 +05303907}
Pavankumar Kondeti87c01042010-12-07 17:53:58 +05303908#endif
3909
Pavankumar Kondeti70187732011-02-15 09:42:34 +05303910#ifdef CONFIG_PM
Pavankumar Kondeti87c01042010-12-07 17:53:58 +05303911static const struct dev_pm_ops msm_otg_dev_pm_ops = {
Pavankumar Kondeti70187732011-02-15 09:42:34 +05303912 SET_SYSTEM_SLEEP_PM_OPS(msm_otg_pm_suspend, msm_otg_pm_resume)
3913 SET_RUNTIME_PM_OPS(msm_otg_runtime_suspend, msm_otg_runtime_resume,
3914 msm_otg_runtime_idle)
Pavankumar Kondeti87c01042010-12-07 17:53:58 +05303915};
Pavankumar Kondeti70187732011-02-15 09:42:34 +05303916#endif
Pavankumar Kondeti87c01042010-12-07 17:53:58 +05303917
Pavankumar Kondetieaea7fe2011-10-27 14:46:45 +05303918static struct of_device_id msm_otg_dt_match[] = {
3919 { .compatible = "qcom,hsusb-otg",
3920 },
3921 {}
3922};
3923
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05303924static struct platform_driver msm_otg_driver = {
3925 .remove = __devexit_p(msm_otg_remove),
3926 .driver = {
3927 .name = DRIVER_NAME,
3928 .owner = THIS_MODULE,
Pavankumar Kondeti70187732011-02-15 09:42:34 +05303929#ifdef CONFIG_PM
Pavankumar Kondeti87c01042010-12-07 17:53:58 +05303930 .pm = &msm_otg_dev_pm_ops,
Pavankumar Kondeti70187732011-02-15 09:42:34 +05303931#endif
Pavankumar Kondetieaea7fe2011-10-27 14:46:45 +05303932 .of_match_table = msm_otg_dt_match,
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05303933 },
3934};
3935
3936static int __init msm_otg_init(void)
3937{
3938 return platform_driver_probe(&msm_otg_driver, msm_otg_probe);
3939}
3940
3941static void __exit msm_otg_exit(void)
3942{
3943 platform_driver_unregister(&msm_otg_driver);
3944}
3945
3946module_init(msm_otg_init);
3947module_exit(msm_otg_exit);
3948
3949MODULE_LICENSE("GPL v2");
3950MODULE_DESCRIPTION("MSM USB transceiver driver");