blob: bc6580be65c8d7e55ab3bd3de5c27b9708d9dacb [file] [log] [blame]
Pavankumar Kondetiebb4a2d2013-01-04 12:28:10 +05301/* Copyright (c) 2009-2013, Linux Foundation. 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>
Pavankumar Kondeti2aec9f32012-06-13 09:06:03 +053042#include <linux/mhl_8334.h>
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +053043
Manu Gautam0ddbd922012-09-21 17:17:38 +053044#include <mach/scm.h>
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +053045#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 Kondeti458d8792012-09-28 14:45:18 +053055#define CHG_RECHECK_DELAY (jiffies + msecs_to_jiffies(2000))
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +053056#define ULPI_IO_TIMEOUT_USEC (10 * 1000)
Anji jonnala11aa5c42011-05-04 10:19:48 +053057#define USB_PHY_3P3_VOL_MIN 3050000 /* uV */
58#define USB_PHY_3P3_VOL_MAX 3300000 /* uV */
59#define USB_PHY_3P3_HPM_LOAD 50000 /* uA */
60#define USB_PHY_3P3_LPM_LOAD 4000 /* uA */
61
62#define USB_PHY_1P8_VOL_MIN 1800000 /* uV */
63#define USB_PHY_1P8_VOL_MAX 1800000 /* uV */
64#define USB_PHY_1P8_HPM_LOAD 50000 /* uA */
65#define USB_PHY_1P8_LPM_LOAD 4000 /* uA */
66
Mayank Rana248698c2012-04-19 00:03:16 +053067#define USB_PHY_VDD_DIG_VOL_NONE 0 /*uV */
Vamsi Krishna132b2762011-11-11 16:09:20 -080068#define USB_PHY_VDD_DIG_VOL_MIN 1045000 /* uV */
Anji jonnala11aa5c42011-05-04 10:19:48 +053069#define USB_PHY_VDD_DIG_VOL_MAX 1320000 /* uV */
70
Amit Blayd0fe07b2012-09-05 16:42:09 +030071#define USB_SUSPEND_DELAY_TIME (500 * HZ/1000) /* 500 msec */
72
Amit Blay81801aa2012-09-19 12:08:12 +020073enum msm_otg_phy_reg_mode {
74 USB_PHY_REG_OFF,
75 USB_PHY_REG_ON,
76 USB_PHY_REG_LPM_ON,
77 USB_PHY_REG_LPM_OFF,
78};
79
Mayank Rana443f9e42012-09-21 18:32:39 +053080static char *override_phy_init;
81module_param(override_phy_init, charp, S_IRUGO|S_IWUSR);
82MODULE_PARM_DESC(override_phy_init,
83 "Override HSUSB PHY Init Settings");
84
Amit Blayd6f38282012-10-29 13:13:46 +020085unsigned int lpm_disconnect_thresh = 1000;
86module_param(lpm_disconnect_thresh , uint, S_IRUGO | S_IWUSR);
87MODULE_PARM_DESC(lpm_disconnect_thresh,
88 "Delay before entering LPM on USB disconnect");
89
Pavankumar Kondeti4960f312011-12-06 15:46:14 +053090static DECLARE_COMPLETION(pmic_vbus_init);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070091static struct msm_otg *the_msm_otg;
Pavankumar Kondetiaa449e12011-11-04 11:09:26 +053092static bool debug_aca_enabled;
Manu Gautam8bdcc592012-03-06 11:26:06 +053093static bool debug_bus_voting_enabled;
Pavankumar Kondeti2aec9f32012-06-13 09:06:03 +053094static bool mhl_det_in_progress;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070095
Anji jonnala11aa5c42011-05-04 10:19:48 +053096static struct regulator *hsusb_3p3;
97static struct regulator *hsusb_1p8;
Mayank Rana0f286cf2013-02-27 11:43:27 +053098static struct regulator *hsusb_vdd;
Mayank Ranae3926882011-12-26 09:47:54 +053099static struct regulator *vbus_otg;
Pavankumar Kondeti56dc7422012-07-02 12:45:19 +0530100static struct regulator *mhl_usb_hs_switch;
Vijayavardhan Vennapusa05c437c2012-05-25 16:20:46 +0530101static struct power_supply *psy;
Anji jonnala11aa5c42011-05-04 10:19:48 +0530102
Pavankumar Kondeti4960f312011-12-06 15:46:14 +0530103static bool aca_id_turned_on;
David Keitel272ce522012-08-17 16:25:24 -0700104static bool legacy_power_supply;
Pavankumar Kondetiaa449e12011-11-04 11:09:26 +0530105static inline bool aca_enabled(void)
Anji jonnala11aa5c42011-05-04 10:19:48 +0530106{
Pavankumar Kondetiaa449e12011-11-04 11:09:26 +0530107#ifdef CONFIG_USB_MSM_ACA
108 return true;
109#else
110 return debug_aca_enabled;
111#endif
Anji jonnala11aa5c42011-05-04 10:19:48 +0530112}
113
Mayank Rana0f286cf2013-02-27 11:43:27 +0530114static int vdd_val[VDD_TYPE_MAX][VDD_VAL_MAX] = {
Mayank Rana248698c2012-04-19 00:03:16 +0530115 { /* VDD_CX CORNER Voting */
116 [VDD_NONE] = RPM_VREG_CORNER_NONE,
117 [VDD_MIN] = RPM_VREG_CORNER_NOMINAL,
118 [VDD_MAX] = RPM_VREG_CORNER_HIGH,
119 },
120 { /* VDD_CX Voltage Voting */
121 [VDD_NONE] = USB_PHY_VDD_DIG_VOL_NONE,
122 [VDD_MIN] = USB_PHY_VDD_DIG_VOL_MIN,
123 [VDD_MAX] = USB_PHY_VDD_DIG_VOL_MAX,
124 },
125};
Anji jonnala11aa5c42011-05-04 10:19:48 +0530126
127static int msm_hsusb_ldo_init(struct msm_otg *motg, int init)
128{
129 int rc = 0;
130
131 if (init) {
Steve Mucklef132c6c2012-06-06 18:30:57 -0700132 hsusb_3p3 = devm_regulator_get(motg->phy.dev, "HSUSB_3p3");
Anji jonnala11aa5c42011-05-04 10:19:48 +0530133 if (IS_ERR(hsusb_3p3)) {
Heikki Krogerus1d4c9292012-02-13 13:24:09 +0200134 dev_err(motg->phy.dev, "unable to get hsusb 3p3\n");
Anji jonnala11aa5c42011-05-04 10:19:48 +0530135 return PTR_ERR(hsusb_3p3);
136 }
137
138 rc = regulator_set_voltage(hsusb_3p3, USB_PHY_3P3_VOL_MIN,
139 USB_PHY_3P3_VOL_MAX);
140 if (rc) {
Steve Mucklef132c6c2012-06-06 18:30:57 -0700141 dev_err(motg->phy.dev, "unable to set voltage level for"
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700142 "hsusb 3p3\n");
Mayank Rana9e9a2ac2012-03-24 04:05:28 +0530143 return rc;
Anji jonnala11aa5c42011-05-04 10:19:48 +0530144 }
Steve Mucklef132c6c2012-06-06 18:30:57 -0700145 hsusb_1p8 = devm_regulator_get(motg->phy.dev, "HSUSB_1p8");
Anji jonnala11aa5c42011-05-04 10:19:48 +0530146 if (IS_ERR(hsusb_1p8)) {
Heikki Krogerus1d4c9292012-02-13 13:24:09 +0200147 dev_err(motg->phy.dev, "unable to get hsusb 1p8\n");
Anji jonnala11aa5c42011-05-04 10:19:48 +0530148 rc = PTR_ERR(hsusb_1p8);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700149 goto put_3p3_lpm;
Anji jonnala11aa5c42011-05-04 10:19:48 +0530150 }
151 rc = regulator_set_voltage(hsusb_1p8, USB_PHY_1P8_VOL_MIN,
152 USB_PHY_1P8_VOL_MAX);
153 if (rc) {
Stephen Boyd9850acb2013-01-28 14:11:20 -0800154 dev_err(motg->phy.dev, "unable to set voltage level "
155 "for hsusb 1p8\n");
Anji jonnala11aa5c42011-05-04 10:19:48 +0530156 goto put_1p8;
157 }
158
159 return 0;
160 }
161
Anji jonnala11aa5c42011-05-04 10:19:48 +0530162put_1p8:
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700163 regulator_set_voltage(hsusb_1p8, 0, USB_PHY_1P8_VOL_MAX);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700164put_3p3_lpm:
165 regulator_set_voltage(hsusb_3p3, 0, USB_PHY_3P3_VOL_MAX);
Anji jonnala11aa5c42011-05-04 10:19:48 +0530166 return rc;
167}
168
Pavankumar Kondeti04aebcb2011-05-04 10:19:49 +0530169static int msm_hsusb_config_vddcx(int high)
170{
Mayank Rana248698c2012-04-19 00:03:16 +0530171 struct msm_otg *motg = the_msm_otg;
172 enum usb_vdd_type vdd_type = motg->vdd_type;
173 int max_vol = vdd_val[vdd_type][VDD_MAX];
Pavankumar Kondeti04aebcb2011-05-04 10:19:49 +0530174 int min_vol;
175 int ret;
176
Mayank Rana248698c2012-04-19 00:03:16 +0530177 min_vol = vdd_val[vdd_type][!!high];
Mayank Rana0f286cf2013-02-27 11:43:27 +0530178 ret = regulator_set_voltage(hsusb_vdd, min_vol, max_vol);
Pavankumar Kondeti04aebcb2011-05-04 10:19:49 +0530179 if (ret) {
180 pr_err("%s: unable to set the voltage for regulator "
181 "HSUSB_VDDCX\n", __func__);
182 return ret;
183 }
184
185 pr_debug("%s: min_vol:%d max_vol:%d\n", __func__, min_vol, max_vol);
186
187 return ret;
188}
Pavankumar Kondeti04aebcb2011-05-04 10:19:49 +0530189
Amit Blay81801aa2012-09-19 12:08:12 +0200190static int msm_hsusb_ldo_enable(struct msm_otg *motg,
191 enum msm_otg_phy_reg_mode mode)
Anji jonnala11aa5c42011-05-04 10:19:48 +0530192{
193 int ret = 0;
194
Pavankumar Kondeti68964c92011-10-27 14:58:56 +0530195 if (IS_ERR(hsusb_1p8)) {
Anji jonnala11aa5c42011-05-04 10:19:48 +0530196 pr_err("%s: HSUSB_1p8 is not initialized\n", __func__);
197 return -ENODEV;
198 }
199
Pavankumar Kondeti68964c92011-10-27 14:58:56 +0530200 if (IS_ERR(hsusb_3p3)) {
Anji jonnala11aa5c42011-05-04 10:19:48 +0530201 pr_err("%s: HSUSB_3p3 is not initialized\n", __func__);
202 return -ENODEV;
203 }
204
Amit Blay81801aa2012-09-19 12:08:12 +0200205 switch (mode) {
206 case USB_PHY_REG_ON:
Anji jonnala11aa5c42011-05-04 10:19:48 +0530207 ret = regulator_set_optimum_mode(hsusb_1p8,
208 USB_PHY_1P8_HPM_LOAD);
209 if (ret < 0) {
Stephen Boyd9850acb2013-01-28 14:11:20 -0800210 pr_err("%s: Unable to set HPM of the regulator "
Anji jonnala11aa5c42011-05-04 10:19:48 +0530211 "HSUSB_1p8\n", __func__);
212 return ret;
213 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700214
215 ret = regulator_enable(hsusb_1p8);
216 if (ret) {
Steve Mucklef132c6c2012-06-06 18:30:57 -0700217 dev_err(motg->phy.dev, "%s: unable to enable the hsusb 1p8\n",
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700218 __func__);
219 regulator_set_optimum_mode(hsusb_1p8, 0);
220 return ret;
221 }
222
Anji jonnala11aa5c42011-05-04 10:19:48 +0530223 ret = regulator_set_optimum_mode(hsusb_3p3,
224 USB_PHY_3P3_HPM_LOAD);
225 if (ret < 0) {
Stephen Boyd9850acb2013-01-28 14:11:20 -0800226 pr_err("%s: Unable to set HPM of the regulator "
Anji jonnala11aa5c42011-05-04 10:19:48 +0530227 "HSUSB_3p3\n", __func__);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700228 regulator_set_optimum_mode(hsusb_1p8, 0);
229 regulator_disable(hsusb_1p8);
Anji jonnala11aa5c42011-05-04 10:19:48 +0530230 return ret;
231 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700232
233 ret = regulator_enable(hsusb_3p3);
234 if (ret) {
Steve Mucklef132c6c2012-06-06 18:30:57 -0700235 dev_err(motg->phy.dev, "%s: unable to enable the hsusb 3p3\n",
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700236 __func__);
237 regulator_set_optimum_mode(hsusb_3p3, 0);
238 regulator_set_optimum_mode(hsusb_1p8, 0);
239 regulator_disable(hsusb_1p8);
240 return ret;
241 }
242
Amit Blay81801aa2012-09-19 12:08:12 +0200243 break;
244
245 case USB_PHY_REG_OFF:
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700246 ret = regulator_disable(hsusb_1p8);
247 if (ret) {
Steve Mucklef132c6c2012-06-06 18:30:57 -0700248 dev_err(motg->phy.dev, "%s: unable to disable the hsusb 1p8\n",
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700249 __func__);
250 return ret;
251 }
252
253 ret = regulator_set_optimum_mode(hsusb_1p8, 0);
Anji jonnala11aa5c42011-05-04 10:19:48 +0530254 if (ret < 0)
Stephen Boyd9850acb2013-01-28 14:11:20 -0800255 pr_err("%s: Unable to set LPM of the regulator "
Anji jonnala11aa5c42011-05-04 10:19:48 +0530256 "HSUSB_1p8\n", __func__);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700257
258 ret = regulator_disable(hsusb_3p3);
259 if (ret) {
Steve Mucklef132c6c2012-06-06 18:30:57 -0700260 dev_err(motg->phy.dev, "%s: unable to disable the hsusb 3p3\n",
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700261 __func__);
262 return ret;
263 }
264 ret = regulator_set_optimum_mode(hsusb_3p3, 0);
Anji jonnala11aa5c42011-05-04 10:19:48 +0530265 if (ret < 0)
Stephen Boyd9850acb2013-01-28 14:11:20 -0800266 pr_err("%s: Unable to set LPM of the regulator "
Anji jonnala11aa5c42011-05-04 10:19:48 +0530267 "HSUSB_3p3\n", __func__);
Amit Blay81801aa2012-09-19 12:08:12 +0200268
269 break;
270
271 case USB_PHY_REG_LPM_ON:
272 ret = regulator_set_optimum_mode(hsusb_1p8,
273 USB_PHY_1P8_LPM_LOAD);
274 if (ret < 0) {
275 pr_err("%s: Unable to set LPM of the regulator: HSUSB_1p8\n",
276 __func__);
277 return ret;
278 }
279
280 ret = regulator_set_optimum_mode(hsusb_3p3,
281 USB_PHY_3P3_LPM_LOAD);
282 if (ret < 0) {
283 pr_err("%s: Unable to set LPM of the regulator: HSUSB_3p3\n",
284 __func__);
285 regulator_set_optimum_mode(hsusb_1p8, USB_PHY_REG_ON);
286 return ret;
287 }
288
289 break;
290
291 case USB_PHY_REG_LPM_OFF:
292 ret = regulator_set_optimum_mode(hsusb_1p8,
293 USB_PHY_1P8_HPM_LOAD);
294 if (ret < 0) {
295 pr_err("%s: Unable to set HPM of the regulator: HSUSB_1p8\n",
296 __func__);
297 return ret;
298 }
299
300 ret = regulator_set_optimum_mode(hsusb_3p3,
301 USB_PHY_3P3_HPM_LOAD);
302 if (ret < 0) {
303 pr_err("%s: Unable to set HPM of the regulator: HSUSB_3p3\n",
304 __func__);
305 regulator_set_optimum_mode(hsusb_1p8, USB_PHY_REG_ON);
306 return ret;
307 }
308
309 break;
310
311 default:
312 pr_err("%s: Unsupported mode (%d).", __func__, mode);
313 return -ENOTSUPP;
Anji jonnala11aa5c42011-05-04 10:19:48 +0530314 }
315
Amit Blay81801aa2012-09-19 12:08:12 +0200316 pr_debug("%s: USB reg mode (%d) (OFF/HPM/LPM)\n", __func__, mode);
Anji jonnala11aa5c42011-05-04 10:19:48 +0530317 return ret < 0 ? ret : 0;
318}
319
Vijayavardhan Vennapusafc464f02011-11-04 21:54:00 +0530320static void msm_hsusb_mhl_switch_enable(struct msm_otg *motg, bool on)
321{
Vijayavardhan Vennapusafc464f02011-11-04 21:54:00 +0530322 struct msm_otg_platform_data *pdata = motg->pdata;
323
324 if (!pdata->mhl_enable)
325 return;
326
Pavankumar Kondeti56dc7422012-07-02 12:45:19 +0530327 if (!mhl_usb_hs_switch) {
328 pr_err("%s: mhl_usb_hs_switch is NULL.\n", __func__);
Vijayavardhan Vennapusafc464f02011-11-04 21:54:00 +0530329 return;
330 }
331
Mayank Rana9e9a2ac2012-03-24 04:05:28 +0530332 if (on) {
Pavankumar Kondeti56dc7422012-07-02 12:45:19 +0530333 if (regulator_enable(mhl_usb_hs_switch))
334 pr_err("unable to enable mhl_usb_hs_switch\n");
Mayank Rana9e9a2ac2012-03-24 04:05:28 +0530335 } else {
Pavankumar Kondeti56dc7422012-07-02 12:45:19 +0530336 regulator_disable(mhl_usb_hs_switch);
Mayank Rana9e9a2ac2012-03-24 04:05:28 +0530337 }
Vijayavardhan Vennapusafc464f02011-11-04 21:54:00 +0530338}
339
Heikki Krogerus1d4c9292012-02-13 13:24:09 +0200340static int ulpi_read(struct usb_phy *phy, u32 reg)
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +0530341{
Heikki Krogerus1d4c9292012-02-13 13:24:09 +0200342 struct msm_otg *motg = container_of(phy, struct msm_otg, phy);
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +0530343 int cnt = 0;
344
345 /* initiate read operation */
346 writel(ULPI_RUN | ULPI_READ | ULPI_ADDR(reg),
347 USB_ULPI_VIEWPORT);
348
349 /* wait for completion */
350 while (cnt < ULPI_IO_TIMEOUT_USEC) {
351 if (!(readl(USB_ULPI_VIEWPORT) & ULPI_RUN))
352 break;
353 udelay(1);
354 cnt++;
355 }
356
357 if (cnt >= ULPI_IO_TIMEOUT_USEC) {
Heikki Krogerus1d4c9292012-02-13 13:24:09 +0200358 dev_err(phy->dev, "ulpi_read: timeout %08x\n",
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +0530359 readl(USB_ULPI_VIEWPORT));
360 return -ETIMEDOUT;
361 }
362 return ULPI_DATA_READ(readl(USB_ULPI_VIEWPORT));
363}
364
Heikki Krogerus1d4c9292012-02-13 13:24:09 +0200365static int ulpi_write(struct usb_phy *phy, u32 val, u32 reg)
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +0530366{
Heikki Krogerus1d4c9292012-02-13 13:24:09 +0200367 struct msm_otg *motg = container_of(phy, struct msm_otg, phy);
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +0530368 int cnt = 0;
369
370 /* initiate write operation */
371 writel(ULPI_RUN | ULPI_WRITE |
372 ULPI_ADDR(reg) | ULPI_DATA(val),
373 USB_ULPI_VIEWPORT);
374
375 /* wait for completion */
376 while (cnt < ULPI_IO_TIMEOUT_USEC) {
377 if (!(readl(USB_ULPI_VIEWPORT) & ULPI_RUN))
378 break;
379 udelay(1);
380 cnt++;
381 }
382
383 if (cnt >= ULPI_IO_TIMEOUT_USEC) {
Heikki Krogerus1d4c9292012-02-13 13:24:09 +0200384 dev_err(phy->dev, "ulpi_write: timeout\n");
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +0530385 return -ETIMEDOUT;
386 }
387 return 0;
388}
389
Heikki Krogerus1d4c9292012-02-13 13:24:09 +0200390static struct usb_phy_io_ops msm_otg_io_ops = {
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +0530391 .read = ulpi_read,
392 .write = ulpi_write,
393};
394
395static void ulpi_init(struct msm_otg *motg)
396{
397 struct msm_otg_platform_data *pdata = motg->pdata;
Mayank Rana443f9e42012-09-21 18:32:39 +0530398 int aseq[10];
399 int *seq = NULL;
400
401 if (override_phy_init) {
402 pr_debug("%s(): HUSB PHY Init:%s\n", __func__,
403 override_phy_init);
404 get_options(override_phy_init, ARRAY_SIZE(aseq), aseq);
405 seq = &aseq[1];
406 } else {
407 seq = pdata->phy_init_seq;
408 }
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +0530409
410 if (!seq)
411 return;
412
413 while (seq[0] >= 0) {
Mayank Rana443f9e42012-09-21 18:32:39 +0530414 if (override_phy_init)
415 pr_debug("ulpi: write 0x%02x to 0x%02x\n",
416 seq[0], seq[1]);
417
Heikki Krogerus1d4c9292012-02-13 13:24:09 +0200418 dev_vdbg(motg->phy.dev, "ulpi: write 0x%02x to 0x%02x\n",
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +0530419 seq[0], seq[1]);
Heikki Krogerus1d4c9292012-02-13 13:24:09 +0200420 ulpi_write(&motg->phy, seq[0], seq[1]);
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +0530421 seq += 2;
422 }
423}
424
425static int msm_otg_link_clk_reset(struct msm_otg *motg, bool assert)
426{
427 int ret;
428
429 if (assert) {
Manu Gautam5025ff12012-07-20 10:56:50 +0530430 if (!IS_ERR(motg->clk)) {
431 ret = clk_reset(motg->clk, CLK_RESET_ASSERT);
432 } else {
433 /* Using asynchronous block reset to the hardware */
434 dev_dbg(motg->phy.dev, "block_reset ASSERT\n");
435 clk_disable_unprepare(motg->pclk);
436 clk_disable_unprepare(motg->core_clk);
437 ret = clk_reset(motg->core_clk, CLK_RESET_ASSERT);
438 }
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +0530439 if (ret)
Heikki Krogerus1d4c9292012-02-13 13:24:09 +0200440 dev_err(motg->phy.dev, "usb hs_clk assert failed\n");
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +0530441 } else {
Manu Gautam5025ff12012-07-20 10:56:50 +0530442 if (!IS_ERR(motg->clk)) {
443 ret = clk_reset(motg->clk, CLK_RESET_DEASSERT);
444 } else {
445 dev_dbg(motg->phy.dev, "block_reset DEASSERT\n");
446 ret = clk_reset(motg->core_clk, CLK_RESET_DEASSERT);
447 ndelay(200);
448 clk_prepare_enable(motg->core_clk);
449 clk_prepare_enable(motg->pclk);
450 }
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +0530451 if (ret)
Heikki Krogerus1d4c9292012-02-13 13:24:09 +0200452 dev_err(motg->phy.dev, "usb hs_clk deassert failed\n");
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +0530453 }
454 return ret;
455}
456
457static int msm_otg_phy_clk_reset(struct msm_otg *motg)
458{
459 int ret;
460
Amit Blay02eff132011-09-21 16:46:24 +0300461 if (IS_ERR(motg->phy_reset_clk))
462 return 0;
463
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +0530464 ret = clk_reset(motg->phy_reset_clk, CLK_RESET_ASSERT);
465 if (ret) {
Heikki Krogerus1d4c9292012-02-13 13:24:09 +0200466 dev_err(motg->phy.dev, "usb phy clk assert failed\n");
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +0530467 return ret;
468 }
469 usleep_range(10000, 12000);
470 ret = clk_reset(motg->phy_reset_clk, CLK_RESET_DEASSERT);
471 if (ret)
Heikki Krogerus1d4c9292012-02-13 13:24:09 +0200472 dev_err(motg->phy.dev, "usb phy clk deassert failed\n");
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +0530473 return ret;
474}
475
476static int msm_otg_phy_reset(struct msm_otg *motg)
477{
478 u32 val;
479 int ret;
480 int retries;
481
482 ret = msm_otg_link_clk_reset(motg, 1);
483 if (ret)
484 return ret;
485 ret = msm_otg_phy_clk_reset(motg);
486 if (ret)
487 return ret;
Amit Blay58dc2bc2013-01-24 12:28:03 +0200488
489 /*
490 * 10 usec delay is required according to spec. Using larger value
491 * since the exact value proved to not work 100% of the time.
492 */
Bar Weinere7129cb2012-11-28 08:44:14 +0200493 if (IS_ERR(motg->phy_reset_clk))
Amit Blay58dc2bc2013-01-24 12:28:03 +0200494 usleep_range(100, 120);
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +0530495 ret = msm_otg_link_clk_reset(motg, 0);
496 if (ret)
497 return ret;
498
499 val = readl(USB_PORTSC) & ~PORTSC_PTS_MASK;
500 writel(val | PORTSC_PTS_ULPI, USB_PORTSC);
501
502 for (retries = 3; retries > 0; retries--) {
Heikki Krogerus1d4c9292012-02-13 13:24:09 +0200503 ret = ulpi_write(&motg->phy, ULPI_FUNC_CTRL_SUSPENDM,
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +0530504 ULPI_CLR(ULPI_FUNC_CTRL));
505 if (!ret)
506 break;
507 ret = msm_otg_phy_clk_reset(motg);
508 if (ret)
509 return ret;
510 }
511 if (!retries)
512 return -ETIMEDOUT;
513
514 /* This reset calibrates the phy, if the above write succeeded */
515 ret = msm_otg_phy_clk_reset(motg);
516 if (ret)
517 return ret;
518
519 for (retries = 3; retries > 0; retries--) {
Heikki Krogerus1d4c9292012-02-13 13:24:09 +0200520 ret = ulpi_read(&motg->phy, ULPI_DEBUG);
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +0530521 if (ret != -ETIMEDOUT)
522 break;
523 ret = msm_otg_phy_clk_reset(motg);
524 if (ret)
525 return ret;
526 }
527 if (!retries)
528 return -ETIMEDOUT;
529
Heikki Krogerus1d4c9292012-02-13 13:24:09 +0200530 dev_info(motg->phy.dev, "phy_reset: success\n");
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +0530531 return 0;
532}
533
534#define LINK_RESET_TIMEOUT_USEC (250 * 1000)
Pavankumar Kondetiaa449e12011-11-04 11:09:26 +0530535static int msm_otg_link_reset(struct msm_otg *motg)
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +0530536{
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +0530537 int cnt = 0;
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +0530538
Pavankumar Kondetiaa449e12011-11-04 11:09:26 +0530539 writel_relaxed(USBCMD_RESET, USB_USBCMD);
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +0530540 while (cnt < LINK_RESET_TIMEOUT_USEC) {
Pavankumar Kondetiaa449e12011-11-04 11:09:26 +0530541 if (!(readl_relaxed(USB_USBCMD) & USBCMD_RESET))
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +0530542 break;
543 udelay(1);
544 cnt++;
545 }
546 if (cnt >= LINK_RESET_TIMEOUT_USEC)
547 return -ETIMEDOUT;
548
549 /* select ULPI phy */
Pavankumar Kondetiaa449e12011-11-04 11:09:26 +0530550 writel_relaxed(0x80000000, USB_PORTSC);
551 writel_relaxed(0x0, USB_AHBBURST);
Vijayavardhan Vennapusa5f32d7a2012-03-14 16:30:26 +0530552 writel_relaxed(0x08, USB_AHBMODE);
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +0530553
Pavankumar Kondetiaa449e12011-11-04 11:09:26 +0530554 return 0;
555}
556
Steve Mucklef132c6c2012-06-06 18:30:57 -0700557static int msm_otg_reset(struct usb_phy *phy)
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +0530558{
Steve Mucklef132c6c2012-06-06 18:30:57 -0700559 struct msm_otg *motg = container_of(phy, struct msm_otg, phy);
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +0530560 struct msm_otg_platform_data *pdata = motg->pdata;
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +0530561 int ret;
562 u32 val = 0;
563 u32 ulpi_val = 0;
564
Ofir Cohen4da266f2012-01-03 10:19:29 +0200565 /*
566 * USB PHY and Link reset also reset the USB BAM.
567 * Thus perform reset operation only once to avoid
568 * USB BAM reset on other cases e.g. USB cable disconnections.
569 */
570 if (pdata->disable_reset_on_disconnect) {
571 if (motg->reset_counter)
572 return 0;
573 else
574 motg->reset_counter++;
575 }
576
Pavankumar Kondeti923262e2012-04-20 15:34:24 +0530577 if (!IS_ERR(motg->clk))
578 clk_prepare_enable(motg->clk);
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +0530579 ret = msm_otg_phy_reset(motg);
580 if (ret) {
Steve Mucklef132c6c2012-06-06 18:30:57 -0700581 dev_err(phy->dev, "phy_reset failed\n");
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +0530582 return ret;
583 }
584
Pavankumar Kondeti4960f312011-12-06 15:46:14 +0530585 aca_id_turned_on = false;
Pavankumar Kondetiaa449e12011-11-04 11:09:26 +0530586 ret = msm_otg_link_reset(motg);
587 if (ret) {
Steve Mucklef132c6c2012-06-06 18:30:57 -0700588 dev_err(phy->dev, "link reset failed\n");
Pavankumar Kondetiaa449e12011-11-04 11:09:26 +0530589 return ret;
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +0530590 }
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +0530591 msleep(100);
592
Anji jonnalaa8b8d732011-12-06 10:03:24 +0530593 ulpi_init(motg);
594
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700595 /* Ensure that RESET operation is completed before turning off clock */
596 mb();
Pavankumar Kondetiaa449e12011-11-04 11:09:26 +0530597
Pavankumar Kondeti923262e2012-04-20 15:34:24 +0530598 if (!IS_ERR(motg->clk))
599 clk_disable_unprepare(motg->clk);
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +0530600
601 if (pdata->otg_control == OTG_PHY_CONTROL) {
Pavankumar Kondeti4960f312011-12-06 15:46:14 +0530602 val = readl_relaxed(USB_OTGSC);
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +0530603 if (pdata->mode == USB_OTG) {
604 ulpi_val = ULPI_INT_IDGRD | ULPI_INT_SESS_VALID;
605 val |= OTGSC_IDIE | OTGSC_BSVIE;
606 } else if (pdata->mode == USB_PERIPHERAL) {
607 ulpi_val = ULPI_INT_SESS_VALID;
608 val |= OTGSC_BSVIE;
609 }
Pavankumar Kondeti4960f312011-12-06 15:46:14 +0530610 writel_relaxed(val, USB_OTGSC);
Heikki Krogerus1d4c9292012-02-13 13:24:09 +0200611 ulpi_write(phy, ulpi_val, ULPI_USB_INT_EN_RISE);
612 ulpi_write(phy, ulpi_val, ULPI_USB_INT_EN_FALL);
Pavankumar Kondeti446f4542012-02-01 13:57:13 +0530613 } else if (pdata->otg_control == OTG_PMIC_CONTROL) {
Steve Mucklef132c6c2012-06-06 18:30:57 -0700614 ulpi_write(phy, OTG_COMP_DISABLE,
Vijayavardhan Vennapusa03171c72012-04-26 14:44:48 +0530615 ULPI_SET(ULPI_PWR_CLK_MNG_REG));
Pavankumar Kondeti446f4542012-02-01 13:57:13 +0530616 /* Enable PMIC pull-up */
617 pm8xxx_usb_id_pullup(1);
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +0530618 }
619
620 return 0;
621}
622
Vijayavardhan Vennapusaa3152032012-03-05 16:29:30 +0530623static const char *timer_string(int bit)
624{
625 switch (bit) {
626 case A_WAIT_VRISE: return "a_wait_vrise";
627 case A_WAIT_VFALL: return "a_wait_vfall";
628 case B_SRP_FAIL: return "b_srp_fail";
629 case A_WAIT_BCON: return "a_wait_bcon";
630 case A_AIDL_BDIS: return "a_aidl_bdis";
631 case A_BIDL_ADIS: return "a_bidl_adis";
632 case B_ASE0_BRST: return "b_ase0_brst";
633 case A_TST_MAINT: return "a_tst_maint";
634 case B_TST_SRP: return "b_tst_srp";
635 case B_TST_CONFIG: return "b_tst_config";
636 default: return "UNDEFINED";
637 }
638}
639
640static enum hrtimer_restart msm_otg_timer_func(struct hrtimer *hrtimer)
641{
642 struct msm_otg *motg = container_of(hrtimer, struct msm_otg, timer);
643
644 switch (motg->active_tmout) {
645 case A_WAIT_VRISE:
646 /* TODO: use vbus_vld interrupt */
647 set_bit(A_VBUS_VLD, &motg->inputs);
648 break;
649 case A_TST_MAINT:
650 /* OTG PET: End session after TA_TST_MAINT */
651 set_bit(A_BUS_DROP, &motg->inputs);
652 break;
653 case B_TST_SRP:
654 /*
655 * OTG PET: Initiate SRP after TB_TST_SRP of
656 * previous session end.
657 */
658 set_bit(B_BUS_REQ, &motg->inputs);
659 break;
660 case B_TST_CONFIG:
661 clear_bit(A_CONN, &motg->inputs);
662 break;
663 default:
664 set_bit(motg->active_tmout, &motg->tmouts);
665 }
666
667 pr_debug("expired %s timer\n", timer_string(motg->active_tmout));
668 queue_work(system_nrt_wq, &motg->sm_work);
669 return HRTIMER_NORESTART;
670}
671
672static void msm_otg_del_timer(struct msm_otg *motg)
673{
674 int bit = motg->active_tmout;
675
676 pr_debug("deleting %s timer. remaining %lld msec\n", timer_string(bit),
677 div_s64(ktime_to_us(hrtimer_get_remaining(
678 &motg->timer)), 1000));
679 hrtimer_cancel(&motg->timer);
680 clear_bit(bit, &motg->tmouts);
681}
682
683static void msm_otg_start_timer(struct msm_otg *motg, int time, int bit)
684{
685 clear_bit(bit, &motg->tmouts);
686 motg->active_tmout = bit;
687 pr_debug("starting %s timer\n", timer_string(bit));
688 hrtimer_start(&motg->timer,
689 ktime_set(time / 1000, (time % 1000) * 1000000),
690 HRTIMER_MODE_REL);
691}
692
693static void msm_otg_init_timer(struct msm_otg *motg)
694{
695 hrtimer_init(&motg->timer, CLOCK_MONOTONIC, HRTIMER_MODE_REL);
696 motg->timer.function = msm_otg_timer_func;
697}
698
Steve Mucklef132c6c2012-06-06 18:30:57 -0700699static int msm_otg_start_hnp(struct usb_otg *otg)
Vijayavardhan Vennapusaa3152032012-03-05 16:29:30 +0530700{
Steve Mucklef132c6c2012-06-06 18:30:57 -0700701 struct msm_otg *motg = container_of(otg->phy, struct msm_otg, phy);
Vijayavardhan Vennapusaa3152032012-03-05 16:29:30 +0530702
Steve Mucklef132c6c2012-06-06 18:30:57 -0700703 if (otg->phy->state != OTG_STATE_A_HOST) {
Vijayavardhan Vennapusaa3152032012-03-05 16:29:30 +0530704 pr_err("HNP can not be initiated in %s state\n",
Steve Mucklef132c6c2012-06-06 18:30:57 -0700705 otg_state_string(otg->phy->state));
Vijayavardhan Vennapusaa3152032012-03-05 16:29:30 +0530706 return -EINVAL;
707 }
708
709 pr_debug("A-Host: HNP initiated\n");
710 clear_bit(A_BUS_REQ, &motg->inputs);
711 queue_work(system_nrt_wq, &motg->sm_work);
712 return 0;
713}
714
Steve Mucklef132c6c2012-06-06 18:30:57 -0700715static int msm_otg_start_srp(struct usb_otg *otg)
Vijayavardhan Vennapusaa3152032012-03-05 16:29:30 +0530716{
Steve Mucklef132c6c2012-06-06 18:30:57 -0700717 struct msm_otg *motg = container_of(otg->phy, struct msm_otg, phy);
Vijayavardhan Vennapusaa3152032012-03-05 16:29:30 +0530718 u32 val;
719 int ret = 0;
720
Steve Mucklef132c6c2012-06-06 18:30:57 -0700721 if (otg->phy->state != OTG_STATE_B_IDLE) {
Vijayavardhan Vennapusaa3152032012-03-05 16:29:30 +0530722 pr_err("SRP can not be initiated in %s state\n",
Steve Mucklef132c6c2012-06-06 18:30:57 -0700723 otg_state_string(otg->phy->state));
Vijayavardhan Vennapusaa3152032012-03-05 16:29:30 +0530724 ret = -EINVAL;
725 goto out;
726 }
727
728 if ((jiffies - motg->b_last_se0_sess) < msecs_to_jiffies(TB_SRP_INIT)) {
729 pr_debug("initial conditions of SRP are not met. Try again"
730 "after some time\n");
731 ret = -EAGAIN;
732 goto out;
733 }
734
735 pr_debug("B-Device SRP started\n");
736
737 /*
738 * PHY won't pull D+ high unless it detects Vbus valid.
739 * Since by definition, SRP is only done when Vbus is not valid,
740 * software work-around needs to be used to spoof the PHY into
741 * thinking it is valid. This can be done using the VBUSVLDEXTSEL and
742 * VBUSVLDEXT register bits.
743 */
Steve Mucklef132c6c2012-06-06 18:30:57 -0700744 ulpi_write(otg->phy, 0x03, 0x97);
Vijayavardhan Vennapusaa3152032012-03-05 16:29:30 +0530745 /*
746 * Harware auto assist data pulsing: Data pulse is given
747 * for 7msec; wait for vbus
748 */
749 val = readl_relaxed(USB_OTGSC);
750 writel_relaxed((val & ~OTGSC_INTSTS_MASK) | OTGSC_HADP, USB_OTGSC);
751
752 /* VBUS plusing is obsoleted in OTG 2.0 supplement */
753out:
754 return ret;
755}
756
Steve Mucklef132c6c2012-06-06 18:30:57 -0700757static void msm_otg_host_hnp_enable(struct usb_otg *otg, bool enable)
Vijayavardhan Vennapusaa3152032012-03-05 16:29:30 +0530758{
759 struct usb_hcd *hcd = bus_to_hcd(otg->host);
760 struct usb_device *rhub = otg->host->root_hub;
761
762 if (enable) {
763 pm_runtime_disable(&rhub->dev);
764 rhub->state = USB_STATE_NOTATTACHED;
765 hcd->driver->bus_suspend(hcd);
766 clear_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags);
767 } else {
768 usb_remove_hcd(hcd);
Steve Mucklef132c6c2012-06-06 18:30:57 -0700769 msm_otg_reset(otg->phy);
Vijayavardhan Vennapusaa3152032012-03-05 16:29:30 +0530770 usb_add_hcd(hcd, hcd->irq, IRQF_SHARED);
771 }
772}
773
Steve Mucklef132c6c2012-06-06 18:30:57 -0700774static int msm_otg_set_suspend(struct usb_phy *phy, int suspend)
Pavankumar Kondeti8be99cf2011-08-04 10:48:08 +0530775{
Steve Mucklef132c6c2012-06-06 18:30:57 -0700776 struct msm_otg *motg = container_of(phy, struct msm_otg, phy);
Pavankumar Kondeti8be99cf2011-08-04 10:48:08 +0530777
Amit Blay6fa647a2012-05-24 14:12:08 +0300778 if (aca_enabled())
Vijayavardhan Vennapusaa3152032012-03-05 16:29:30 +0530779 return 0;
Pavankumar Kondeti8be99cf2011-08-04 10:48:08 +0530780
Pavankumar Kondetie618bf82012-11-28 21:12:44 +0530781 /*
782 * UDC and HCD call usb_phy_set_suspend() to enter/exit LPM
783 * during bus suspend/resume. Update the relevant state
784 * machine inputs and trigger LPM entry/exit. Checking
785 * in_lpm flag would avoid unnecessary work scheduling.
786 */
Vijayavardhan Vennapusaa3152032012-03-05 16:29:30 +0530787 if (suspend) {
Steve Mucklef132c6c2012-06-06 18:30:57 -0700788 switch (phy->state) {
Vijayavardhan Vennapusaa3152032012-03-05 16:29:30 +0530789 case OTG_STATE_A_WAIT_BCON:
790 if (TA_WAIT_BCON > 0)
791 break;
792 /* fall through */
793 case OTG_STATE_A_HOST:
794 pr_debug("host bus suspend\n");
795 clear_bit(A_BUS_REQ, &motg->inputs);
Pavankumar Kondetie618bf82012-11-28 21:12:44 +0530796 if (!atomic_read(&motg->in_lpm))
797 queue_work(system_nrt_wq, &motg->sm_work);
Vijayavardhan Vennapusaa3152032012-03-05 16:29:30 +0530798 break;
Amit Blay6fa647a2012-05-24 14:12:08 +0300799 case OTG_STATE_B_PERIPHERAL:
800 pr_debug("peripheral bus suspend\n");
801 if (!(motg->caps & ALLOW_LPM_ON_DEV_SUSPEND))
802 break;
803 set_bit(A_BUS_SUSPEND, &motg->inputs);
Pavankumar Kondetie618bf82012-11-28 21:12:44 +0530804 if (!atomic_read(&motg->in_lpm))
805 queue_delayed_work(system_nrt_wq,
806 &motg->suspend_work,
807 USB_SUSPEND_DELAY_TIME);
Amit Blay6fa647a2012-05-24 14:12:08 +0300808 break;
809
Vijayavardhan Vennapusaa3152032012-03-05 16:29:30 +0530810 default:
811 break;
812 }
813 } else {
Steve Mucklef132c6c2012-06-06 18:30:57 -0700814 switch (phy->state) {
Pavankumar Kondetie618bf82012-11-28 21:12:44 +0530815 case OTG_STATE_A_WAIT_BCON:
816 /* Remote wakeup or resume */
817 set_bit(A_BUS_REQ, &motg->inputs);
818 /* ensure hardware is not in low power mode */
819 if (atomic_read(&motg->in_lpm))
820 pm_runtime_resume(phy->dev);
821 break;
Vijayavardhan Vennapusaa3152032012-03-05 16:29:30 +0530822 case OTG_STATE_A_SUSPEND:
823 /* Remote wakeup or resume */
824 set_bit(A_BUS_REQ, &motg->inputs);
Steve Mucklef132c6c2012-06-06 18:30:57 -0700825 phy->state = OTG_STATE_A_HOST;
Jack Pham5ca279b2012-05-14 18:42:54 -0700826
827 /* ensure hardware is not in low power mode */
Pavankumar Kondetie618bf82012-11-28 21:12:44 +0530828 if (atomic_read(&motg->in_lpm))
829 pm_runtime_resume(phy->dev);
Vijayavardhan Vennapusaa3152032012-03-05 16:29:30 +0530830 break;
Amit Blay6fa647a2012-05-24 14:12:08 +0300831 case OTG_STATE_B_PERIPHERAL:
832 pr_debug("peripheral bus resume\n");
833 if (!(motg->caps & ALLOW_LPM_ON_DEV_SUSPEND))
834 break;
835 clear_bit(A_BUS_SUSPEND, &motg->inputs);
Pavankumar Kondetie618bf82012-11-28 21:12:44 +0530836 if (atomic_read(&motg->in_lpm))
837 queue_work(system_nrt_wq, &motg->sm_work);
Amit Blay6fa647a2012-05-24 14:12:08 +0300838 break;
Vijayavardhan Vennapusaa3152032012-03-05 16:29:30 +0530839 default:
840 break;
841 }
842 }
Pavankumar Kondeti8be99cf2011-08-04 10:48:08 +0530843 return 0;
844}
845
Pavankumar Kondeti87c01042010-12-07 17:53:58 +0530846#define PHY_SUSPEND_TIMEOUT_USEC (500 * 1000)
Pavankumar Kondeti70187732011-02-15 09:42:34 +0530847#define PHY_RESUME_TIMEOUT_USEC (100 * 1000)
848
849#ifdef CONFIG_PM_SLEEP
Pavankumar Kondeti87c01042010-12-07 17:53:58 +0530850static int msm_otg_suspend(struct msm_otg *motg)
851{
Heikki Krogerus1d4c9292012-02-13 13:24:09 +0200852 struct usb_phy *phy = &motg->phy;
853 struct usb_bus *bus = phy->otg->host;
Pavankumar Kondeti87c01042010-12-07 17:53:58 +0530854 struct msm_otg_platform_data *pdata = motg->pdata;
855 int cnt = 0;
Amit Blay6fa647a2012-05-24 14:12:08 +0300856 bool host_bus_suspend, device_bus_suspend, dcp;
Pavankumar Kondeti4960f312011-12-06 15:46:14 +0530857 u32 phy_ctrl_val = 0, cmd_val;
Stephen Boyd30ad10b2012-03-01 14:51:04 -0800858 unsigned ret;
Rajkumar Raghupathy242565d2011-12-13 12:10:59 +0530859 u32 portsc;
Pavankumar Kondeti87c01042010-12-07 17:53:58 +0530860
861 if (atomic_read(&motg->in_lpm))
862 return 0;
863
864 disable_irq(motg->irq);
Pavankumar Kondeti2aec9f32012-06-13 09:06:03 +0530865 host_bus_suspend = !test_bit(MHL, &motg->inputs) && phy->otg->host &&
866 !test_bit(ID, &motg->inputs);
Steve Mucklef132c6c2012-06-06 18:30:57 -0700867 device_bus_suspend = phy->otg->gadget && test_bit(ID, &motg->inputs) &&
Amit Blay6fa647a2012-05-24 14:12:08 +0300868 test_bit(A_BUS_SUSPEND, &motg->inputs) &&
869 motg->caps & ALLOW_LPM_ON_DEV_SUSPEND;
Pavankumar Kondeti283146f2012-01-12 12:51:19 +0530870 dcp = motg->chg_type == USB_DCP_CHARGER;
Jack Pham502bea32012-08-13 15:34:20 -0700871
Pavankumar Kondeticfe05392012-10-22 13:21:19 +0530872 /*
873 * Abort suspend when,
874 * 1. charging detection in progress due to cable plug-in
875 * 2. host mode activation in progress due to Micro-A cable insertion
876 */
877
878 if ((test_bit(B_SESS_VLD, &motg->inputs) && !device_bus_suspend &&
879 !dcp) || test_bit(A_BUS_REQ, &motg->inputs)) {
Jack Pham502bea32012-08-13 15:34:20 -0700880 enable_irq(motg->irq);
881 return -EBUSY;
882 }
883
Pavankumar Kondeti87c01042010-12-07 17:53:58 +0530884 /*
Pavankumar Kondeti04aebcb2011-05-04 10:19:49 +0530885 * Chipidea 45-nm PHY suspend sequence:
886 *
Pavankumar Kondeti87c01042010-12-07 17:53:58 +0530887 * Interrupt Latch Register auto-clear feature is not present
888 * in all PHY versions. Latch register is clear on read type.
889 * Clear latch register to avoid spurious wakeup from
890 * low power mode (LPM).
Pavankumar Kondeti04aebcb2011-05-04 10:19:49 +0530891 *
Pavankumar Kondeti87c01042010-12-07 17:53:58 +0530892 * PHY comparators are disabled when PHY enters into low power
893 * mode (LPM). Keep PHY comparators ON in LPM only when we expect
894 * VBUS/Id notifications from USB PHY. Otherwise turn off USB
895 * PHY comparators. This save significant amount of power.
Pavankumar Kondeti04aebcb2011-05-04 10:19:49 +0530896 *
Pavankumar Kondeti87c01042010-12-07 17:53:58 +0530897 * PLL is not turned off when PHY enters into low power mode (LPM).
898 * Disable PLL for maximum power savings.
899 */
Pavankumar Kondeti04aebcb2011-05-04 10:19:49 +0530900
901 if (motg->pdata->phy_type == CI_45NM_INTEGRATED_PHY) {
Heikki Krogerus1d4c9292012-02-13 13:24:09 +0200902 ulpi_read(phy, 0x14);
Pavankumar Kondeti04aebcb2011-05-04 10:19:49 +0530903 if (pdata->otg_control == OTG_PHY_CONTROL)
Heikki Krogerus1d4c9292012-02-13 13:24:09 +0200904 ulpi_write(phy, 0x01, 0x30);
905 ulpi_write(phy, 0x08, 0x09);
Pavankumar Kondeti04aebcb2011-05-04 10:19:49 +0530906 }
Pavankumar Kondeti87c01042010-12-07 17:53:58 +0530907
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700908
Rajkumar Raghupathy242565d2011-12-13 12:10:59 +0530909 /* Set the PHCD bit, only if it is not set by the controller.
Pavankumar Kondeti87c01042010-12-07 17:53:58 +0530910 * PHY may take some time or even fail to enter into low power
911 * mode (LPM). Hence poll for 500 msec and reset the PHY and link
912 * in failure case.
913 */
Rajkumar Raghupathy242565d2011-12-13 12:10:59 +0530914 portsc = readl_relaxed(USB_PORTSC);
915 if (!(portsc & PORTSC_PHCD)) {
916 writel_relaxed(portsc | PORTSC_PHCD,
917 USB_PORTSC);
918 while (cnt < PHY_SUSPEND_TIMEOUT_USEC) {
919 if (readl_relaxed(USB_PORTSC) & PORTSC_PHCD)
920 break;
921 udelay(1);
922 cnt++;
923 }
Pavankumar Kondeti87c01042010-12-07 17:53:58 +0530924 }
925
926 if (cnt >= PHY_SUSPEND_TIMEOUT_USEC) {
Heikki Krogerus1d4c9292012-02-13 13:24:09 +0200927 dev_err(phy->dev, "Unable to suspend PHY\n");
928 msm_otg_reset(phy);
Pavankumar Kondeti87c01042010-12-07 17:53:58 +0530929 enable_irq(motg->irq);
930 return -ETIMEDOUT;
931 }
932
933 /*
934 * PHY has capability to generate interrupt asynchronously in low
935 * power mode (LPM). This interrupt is level triggered. So USB IRQ
936 * line must be disabled till async interrupt enable bit is cleared
937 * in USBCMD register. Assert STP (ULPI interface STOP signal) to
938 * block data communication from PHY.
Pavankumar Kondeti6be675f2012-04-16 13:29:24 +0530939 *
940 * PHY retention mode is disallowed while entering to LPM with wall
941 * charger connected. But PHY is put into suspend mode. Hence
942 * enable asynchronous interrupt to detect charger disconnection when
943 * PMIC notifications are unavailable.
Pavankumar Kondeti87c01042010-12-07 17:53:58 +0530944 */
Pavankumar Kondeti4960f312011-12-06 15:46:14 +0530945 cmd_val = readl_relaxed(USB_USBCMD);
Amit Blay6fa647a2012-05-24 14:12:08 +0300946 if (host_bus_suspend || device_bus_suspend ||
947 (motg->pdata->otg_control == OTG_PHY_CONTROL && dcp))
Pavankumar Kondeti4960f312011-12-06 15:46:14 +0530948 cmd_val |= ASYNC_INTR_CTRL | ULPI_STP_CTRL;
949 else
950 cmd_val |= ULPI_STP_CTRL;
951 writel_relaxed(cmd_val, USB_USBCMD);
Pavankumar Kondeti87c01042010-12-07 17:53:58 +0530952
Pavankumar Kondeti283146f2012-01-12 12:51:19 +0530953 /*
954 * BC1.2 spec mandates PD to enable VDP_SRC when charging from DCP.
955 * PHY retention and collapse can not happen with VDP_SRC enabled.
956 */
Amit Blay6fa647a2012-05-24 14:12:08 +0300957 if (motg->caps & ALLOW_PHY_RETENTION && !host_bus_suspend &&
958 !device_bus_suspend && !dcp) {
Amit Blay58b31472011-11-18 09:39:39 +0200959 phy_ctrl_val = readl_relaxed(USB_PHY_CTRL);
Vijayavardhan Vennapusa9ab6f972012-10-11 19:18:55 +0530960 if (motg->pdata->otg_control == OTG_PHY_CONTROL) {
Amit Blay58b31472011-11-18 09:39:39 +0200961 /* Enable PHY HV interrupts to wake MPM/Link */
Vijayavardhan Vennapusa9ab6f972012-10-11 19:18:55 +0530962 if ((motg->pdata->mode == USB_OTG) ||
963 (motg->pdata->mode == USB_HOST))
964 phy_ctrl_val |= (PHY_IDHV_INTEN |
965 PHY_OTGSESSVLDHV_INTEN);
966 else
967 phy_ctrl_val |= PHY_OTGSESSVLDHV_INTEN;
968 }
Pavankumar Kondeti04aebcb2011-05-04 10:19:49 +0530969
Amit Blay58b31472011-11-18 09:39:39 +0200970 writel_relaxed(phy_ctrl_val & ~PHY_RETEN, USB_PHY_CTRL);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700971 motg->lpm_flags |= PHY_RETENTIONED;
Pavankumar Kondeti04aebcb2011-05-04 10:19:49 +0530972 }
973
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700974 /* Ensure that above operation is completed before turning off clocks */
975 mb();
Ido Shayevitzc5c0f572012-07-31 13:58:45 +0300976 /* Consider clocks on workaround flag only in case of bus suspend */
977 if (!(phy->state == OTG_STATE_B_PERIPHERAL &&
978 test_bit(A_BUS_SUSPEND, &motg->inputs)) ||
979 !motg->pdata->core_clk_always_on_workaround) {
Amit Blay9b6e58b2012-06-18 13:12:49 +0300980 clk_disable_unprepare(motg->pclk);
981 clk_disable_unprepare(motg->core_clk);
Ido Shayevitzc5c0f572012-07-31 13:58:45 +0300982 motg->lpm_flags |= CLOCKS_DOWN;
Amit Blay9b6e58b2012-06-18 13:12:49 +0300983 }
Pavankumar Kondeti87c01042010-12-07 17:53:58 +0530984
Anji jonnala7da3f262011-12-02 17:22:14 -0800985 /* usb phy no more require TCXO clock, hence vote for TCXO disable */
Vijayavardhan Vennapusabbdd6082012-06-06 14:14:25 +0530986 if (!host_bus_suspend) {
Vijayavardhan Vennapusa0cab6172013-02-20 19:51:15 +0530987 if (!IS_ERR(motg->xo_clk)) {
988 clk_disable_unprepare(motg->xo_clk);
Vijayavardhan Vennapusabbdd6082012-06-06 14:14:25 +0530989 motg->lpm_flags |= XO_SHUTDOWN;
Vijayavardhan Vennapusa0cab6172013-02-20 19:51:15 +0530990 } else {
991 ret = msm_xo_mode_vote(motg->xo_handle,
992 MSM_XO_MODE_OFF);
993 if (ret)
994 dev_err(phy->dev, "%s fail to devote XO %d\n",
995 __func__, ret);
996 else
997 motg->lpm_flags |= XO_SHUTDOWN;
998 }
Vijayavardhan Vennapusabbdd6082012-06-06 14:14:25 +0530999 }
Anji jonnala7da3f262011-12-02 17:22:14 -08001000
Pavankumar Kondeti283146f2012-01-12 12:51:19 +05301001 if (motg->caps & ALLOW_PHY_POWER_COLLAPSE &&
1002 !host_bus_suspend && !dcp) {
Amit Blay81801aa2012-09-19 12:08:12 +02001003 msm_hsusb_ldo_enable(motg, USB_PHY_REG_OFF);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001004 motg->lpm_flags |= PHY_PWR_COLLAPSED;
Amit Blay81801aa2012-09-19 12:08:12 +02001005 } else if (motg->caps & ALLOW_PHY_REGULATORS_LPM &&
1006 !host_bus_suspend && !device_bus_suspend && !dcp) {
1007 msm_hsusb_ldo_enable(motg, USB_PHY_REG_LPM_ON);
1008 motg->lpm_flags |= PHY_REGULATORS_LPM;
Anji jonnala0f73cac2011-05-04 10:19:46 +05301009 }
1010
Vijayavardhan Vennapusafc464f02011-11-04 21:54:00 +05301011 if (motg->lpm_flags & PHY_RETENTIONED) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001012 msm_hsusb_config_vddcx(0);
Vijayavardhan Vennapusafc464f02011-11-04 21:54:00 +05301013 msm_hsusb_mhl_switch_enable(motg, 0);
1014 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001015
Steve Mucklef132c6c2012-06-06 18:30:57 -07001016 if (device_may_wakeup(phy->dev)) {
Manu Gautamf8c45642012-08-10 10:20:56 -07001017 if (motg->async_irq)
1018 enable_irq_wake(motg->async_irq);
Jack Phamd110a5a2013-02-21 13:34:48 -08001019 else
1020 enable_irq_wake(motg->irq);
1021
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001022 if (motg->pdata->pmic_id_irq)
1023 enable_irq_wake(motg->pdata->pmic_id_irq);
Jack Pham87f202f2012-08-06 00:24:22 -07001024 if (pdata->otg_control == OTG_PHY_CONTROL &&
1025 pdata->mpm_otgsessvld_int)
1026 msm_mpm_set_pin_wake(pdata->mpm_otgsessvld_int, 1);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001027 }
Pavankumar Kondeti87c01042010-12-07 17:53:58 +05301028 if (bus)
1029 clear_bit(HCD_FLAG_HW_ACCESSIBLE, &(bus_to_hcd(bus))->flags);
1030
1031 atomic_set(&motg->in_lpm, 1);
Manu Gautamf8c45642012-08-10 10:20:56 -07001032 /* Enable ASYNC IRQ (if present) during LPM */
1033 if (motg->async_irq)
1034 enable_irq(motg->async_irq);
Pavankumar Kondeti87c01042010-12-07 17:53:58 +05301035 enable_irq(motg->irq);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001036 wake_unlock(&motg->wlock);
Pavankumar Kondeti87c01042010-12-07 17:53:58 +05301037
Heikki Krogerus1d4c9292012-02-13 13:24:09 +02001038 dev_info(phy->dev, "USB in low power mode\n");
Pavankumar Kondeti87c01042010-12-07 17:53:58 +05301039
1040 return 0;
1041}
1042
Pavankumar Kondeti87c01042010-12-07 17:53:58 +05301043static int msm_otg_resume(struct msm_otg *motg)
1044{
Heikki Krogerus1d4c9292012-02-13 13:24:09 +02001045 struct usb_phy *phy = &motg->phy;
1046 struct usb_bus *bus = phy->otg->host;
Jack Pham87f202f2012-08-06 00:24:22 -07001047 struct msm_otg_platform_data *pdata = motg->pdata;
Pavankumar Kondeti87c01042010-12-07 17:53:58 +05301048 int cnt = 0;
1049 unsigned temp;
Amit Blay58b31472011-11-18 09:39:39 +02001050 u32 phy_ctrl_val = 0;
Anji jonnala7da3f262011-12-02 17:22:14 -08001051 unsigned ret;
Pavankumar Kondeti87c01042010-12-07 17:53:58 +05301052
1053 if (!atomic_read(&motg->in_lpm))
1054 return 0;
1055
Jack Pham8978b892012-10-17 16:31:39 -07001056 disable_irq(motg->irq);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001057 wake_lock(&motg->wlock);
Anji jonnala0f73cac2011-05-04 10:19:46 +05301058
Anji jonnala7da3f262011-12-02 17:22:14 -08001059 /* Vote for TCXO when waking up the phy */
Vijayavardhan Vennapusabbdd6082012-06-06 14:14:25 +05301060 if (motg->lpm_flags & XO_SHUTDOWN) {
Vijayavardhan Vennapusa0cab6172013-02-20 19:51:15 +05301061 if (!IS_ERR(motg->xo_clk)) {
1062 clk_prepare_enable(motg->xo_clk);
1063 } else {
1064 ret = msm_xo_mode_vote(motg->xo_handle, MSM_XO_MODE_ON);
1065 if (ret)
1066 dev_err(phy->dev, "%s fail to vote for XO %d\n",
1067 __func__, ret);
1068 }
Vijayavardhan Vennapusabbdd6082012-06-06 14:14:25 +05301069 motg->lpm_flags &= ~XO_SHUTDOWN;
1070 }
Pavankumar Kondeti87c01042010-12-07 17:53:58 +05301071
Ido Shayevitzc5c0f572012-07-31 13:58:45 +03001072 if (motg->lpm_flags & CLOCKS_DOWN) {
Amit Blay9b6e58b2012-06-18 13:12:49 +03001073 clk_prepare_enable(motg->core_clk);
1074 clk_prepare_enable(motg->pclk);
Ido Shayevitzc5c0f572012-07-31 13:58:45 +03001075 motg->lpm_flags &= ~CLOCKS_DOWN;
Amit Blay9b6e58b2012-06-18 13:12:49 +03001076 }
Pavankumar Kondeti87c01042010-12-07 17:53:58 +05301077
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001078 if (motg->lpm_flags & PHY_PWR_COLLAPSED) {
Amit Blay81801aa2012-09-19 12:08:12 +02001079 msm_hsusb_ldo_enable(motg, USB_PHY_REG_ON);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001080 motg->lpm_flags &= ~PHY_PWR_COLLAPSED;
Amit Blay81801aa2012-09-19 12:08:12 +02001081 } else if (motg->lpm_flags & PHY_REGULATORS_LPM) {
1082 msm_hsusb_ldo_enable(motg, USB_PHY_REG_LPM_OFF);
1083 motg->lpm_flags &= ~PHY_REGULATORS_LPM;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001084 }
1085
1086 if (motg->lpm_flags & PHY_RETENTIONED) {
Vijayavardhan Vennapusafc464f02011-11-04 21:54:00 +05301087 msm_hsusb_mhl_switch_enable(motg, 1);
Pavankumar Kondeti04aebcb2011-05-04 10:19:49 +05301088 msm_hsusb_config_vddcx(1);
Amit Blay58b31472011-11-18 09:39:39 +02001089 phy_ctrl_val = readl_relaxed(USB_PHY_CTRL);
1090 phy_ctrl_val |= PHY_RETEN;
1091 if (motg->pdata->otg_control == OTG_PHY_CONTROL)
1092 /* Disable PHY HV interrupts */
1093 phy_ctrl_val &=
1094 ~(PHY_IDHV_INTEN | PHY_OTGSESSVLDHV_INTEN);
1095 writel_relaxed(phy_ctrl_val, USB_PHY_CTRL);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001096 motg->lpm_flags &= ~PHY_RETENTIONED;
Pavankumar Kondeti04aebcb2011-05-04 10:19:49 +05301097 }
1098
Pavankumar Kondeti87c01042010-12-07 17:53:58 +05301099 temp = readl(USB_USBCMD);
1100 temp &= ~ASYNC_INTR_CTRL;
1101 temp &= ~ULPI_STP_CTRL;
1102 writel(temp, USB_USBCMD);
1103
1104 /*
1105 * PHY comes out of low power mode (LPM) in case of wakeup
1106 * from asynchronous interrupt.
1107 */
1108 if (!(readl(USB_PORTSC) & PORTSC_PHCD))
1109 goto skip_phy_resume;
1110
1111 writel(readl(USB_PORTSC) & ~PORTSC_PHCD, USB_PORTSC);
1112 while (cnt < PHY_RESUME_TIMEOUT_USEC) {
1113 if (!(readl(USB_PORTSC) & PORTSC_PHCD))
1114 break;
1115 udelay(1);
1116 cnt++;
1117 }
1118
1119 if (cnt >= PHY_RESUME_TIMEOUT_USEC) {
1120 /*
1121 * This is a fatal error. Reset the link and
1122 * PHY. USB state can not be restored. Re-insertion
1123 * of USB cable is the only way to get USB working.
1124 */
Heikki Krogerus1d4c9292012-02-13 13:24:09 +02001125 dev_err(phy->dev, "Unable to resume USB."
Pavankumar Kondeti87c01042010-12-07 17:53:58 +05301126 "Re-plugin the cable\n");
Heikki Krogerus1d4c9292012-02-13 13:24:09 +02001127 msm_otg_reset(phy);
Pavankumar Kondeti87c01042010-12-07 17:53:58 +05301128 }
1129
1130skip_phy_resume:
Steve Mucklef132c6c2012-06-06 18:30:57 -07001131 if (device_may_wakeup(phy->dev)) {
Manu Gautamf8c45642012-08-10 10:20:56 -07001132 if (motg->async_irq)
1133 disable_irq_wake(motg->async_irq);
Jack Phamd110a5a2013-02-21 13:34:48 -08001134 else
1135 disable_irq_wake(motg->irq);
1136
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001137 if (motg->pdata->pmic_id_irq)
1138 disable_irq_wake(motg->pdata->pmic_id_irq);
Jack Pham87f202f2012-08-06 00:24:22 -07001139 if (pdata->otg_control == OTG_PHY_CONTROL &&
1140 pdata->mpm_otgsessvld_int)
1141 msm_mpm_set_pin_wake(pdata->mpm_otgsessvld_int, 0);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001142 }
Pavankumar Kondeti87c01042010-12-07 17:53:58 +05301143 if (bus)
1144 set_bit(HCD_FLAG_HW_ACCESSIBLE, &(bus_to_hcd(bus))->flags);
1145
Pavankumar Kondeti2ce2c3a2011-05-02 11:56:33 +05301146 atomic_set(&motg->in_lpm, 0);
1147
Pavankumar Kondeti87c01042010-12-07 17:53:58 +05301148 if (motg->async_int) {
Manu Gautamf8c45642012-08-10 10:20:56 -07001149 /* Match the disable_irq call from ISR */
1150 enable_irq(motg->async_int);
Pavankumar Kondeti87c01042010-12-07 17:53:58 +05301151 motg->async_int = 0;
Pavankumar Kondeti87c01042010-12-07 17:53:58 +05301152 }
Jack Pham8978b892012-10-17 16:31:39 -07001153 enable_irq(motg->irq);
Pavankumar Kondeti87c01042010-12-07 17:53:58 +05301154
Manu Gautamf8c45642012-08-10 10:20:56 -07001155 /* If ASYNC IRQ is present then keep it enabled only during LPM */
1156 if (motg->async_irq)
1157 disable_irq(motg->async_irq);
1158
Heikki Krogerus1d4c9292012-02-13 13:24:09 +02001159 dev_info(phy->dev, "USB exited from low power mode\n");
Pavankumar Kondeti87c01042010-12-07 17:53:58 +05301160
1161 return 0;
1162}
Pavankumar Kondeti70187732011-02-15 09:42:34 +05301163#endif
Pavankumar Kondeti87c01042010-12-07 17:53:58 +05301164
David Keitel272ce522012-08-17 16:25:24 -07001165static void msm_otg_notify_host_mode(struct msm_otg *motg, bool host_mode)
Abhijeet Dharmapurikar5e96aaa2012-06-26 11:21:03 -07001166{
Jack Pham0c695282012-10-19 18:13:03 -07001167 if (!psy) {
David Keitel272ce522012-08-17 16:25:24 -07001168 pr_err("No USB power supply registered!\n");
1169 return;
1170 }
Sridhar Parasuram3c67a412012-09-26 09:36:22 -07001171
Jack Pham0c695282012-10-19 18:13:03 -07001172 if (legacy_power_supply) {
David Keitel272ce522012-08-17 16:25:24 -07001173 /* legacy support */
Pavankumar Kondeti811cab32012-11-09 20:51:36 +05301174 if (host_mode) {
David Keitel272ce522012-08-17 16:25:24 -07001175 power_supply_set_scope(psy, POWER_SUPPLY_SCOPE_SYSTEM);
Pavankumar Kondeti811cab32012-11-09 20:51:36 +05301176 } else {
David Keitel272ce522012-08-17 16:25:24 -07001177 power_supply_set_scope(psy, POWER_SUPPLY_SCOPE_DEVICE);
Pavankumar Kondeti811cab32012-11-09 20:51:36 +05301178 /*
1179 * VBUS comparator is disabled by PMIC charging driver
1180 * when SYSTEM scope is selected. For ID_GND->ID_A
1181 * transition, give 50 msec delay so that PMIC charger
1182 * driver detect the VBUS and ready for accepting
1183 * charging current value from USB.
1184 */
1185 if (test_bit(ID_A, &motg->inputs))
1186 msleep(50);
1187 }
David Keitel272ce522012-08-17 16:25:24 -07001188 } else {
1189 motg->host_mode = host_mode;
Jack Pham0c695282012-10-19 18:13:03 -07001190 power_supply_changed(psy);
David Keitel272ce522012-08-17 16:25:24 -07001191 }
Abhijeet Dharmapurikar5e96aaa2012-06-26 11:21:03 -07001192}
1193
David Keitel081a3e22012-04-18 12:37:07 -07001194static int msm_otg_notify_chg_type(struct msm_otg *motg)
1195{
1196 static int charger_type;
David Keitelba8f8322012-06-01 17:14:10 -07001197
David Keitel081a3e22012-04-18 12:37:07 -07001198 /*
1199 * TODO
1200 * Unify OTG driver charger types and power supply charger types
1201 */
1202 if (charger_type == motg->chg_type)
1203 return 0;
1204
1205 if (motg->chg_type == USB_SDP_CHARGER)
1206 charger_type = POWER_SUPPLY_TYPE_USB;
1207 else if (motg->chg_type == USB_CDP_CHARGER)
1208 charger_type = POWER_SUPPLY_TYPE_USB_CDP;
Pavankumar Kondeti9ec21d32012-05-07 15:50:23 +05301209 else if (motg->chg_type == USB_DCP_CHARGER ||
1210 motg->chg_type == USB_PROPRIETARY_CHARGER)
David Keitel081a3e22012-04-18 12:37:07 -07001211 charger_type = POWER_SUPPLY_TYPE_USB_DCP;
1212 else if ((motg->chg_type == USB_ACA_DOCK_CHARGER ||
1213 motg->chg_type == USB_ACA_A_CHARGER ||
1214 motg->chg_type == USB_ACA_B_CHARGER ||
1215 motg->chg_type == USB_ACA_C_CHARGER))
1216 charger_type = POWER_SUPPLY_TYPE_USB_ACA;
1217 else
Anirudh Ghayal685a6a52013-01-08 18:28:55 +05301218 charger_type = POWER_SUPPLY_TYPE_UNKNOWN;
David Keitel081a3e22012-04-18 12:37:07 -07001219
Jack Pham0c695282012-10-19 18:13:03 -07001220 if (!psy) {
David Keitelba8f8322012-06-01 17:14:10 -07001221 pr_err("No USB power supply registered!\n");
1222 return -EINVAL;
1223 }
1224
1225 pr_debug("setting usb power supply type %d\n", charger_type);
Jack Pham0c695282012-10-19 18:13:03 -07001226 power_supply_set_supply_type(psy, charger_type);
David Keitelba8f8322012-06-01 17:14:10 -07001227 return 0;
David Keitel081a3e22012-04-18 12:37:07 -07001228}
1229
Amit Blay0f7edf72012-01-15 10:11:27 +02001230static int msm_otg_notify_power_supply(struct msm_otg *motg, unsigned mA)
1231{
Jack Pham0c695282012-10-19 18:13:03 -07001232 if (!psy) {
David Keitel272ce522012-08-17 16:25:24 -07001233 dev_dbg(motg->phy.dev, "no usb power supply registered\n");
1234 goto psy_error;
David Keitelf5c5d602012-08-17 16:25:24 -07001235 }
1236
David Keitel272ce522012-08-17 16:25:24 -07001237 if (motg->cur_power == 0 && mA > 2) {
1238 /* Enable charging */
Jack Pham0c695282012-10-19 18:13:03 -07001239 if (power_supply_set_online(psy, true))
David Keitel272ce522012-08-17 16:25:24 -07001240 goto psy_error;
Jack Pham0c695282012-10-19 18:13:03 -07001241 if (power_supply_set_current_limit(psy, 1000*mA))
David Keitel272ce522012-08-17 16:25:24 -07001242 goto psy_error;
1243 } else if (motg->cur_power > 0 && (mA == 0 || mA == 2)) {
1244 /* Disable charging */
Jack Pham0c695282012-10-19 18:13:03 -07001245 if (power_supply_set_online(psy, false))
David Keitel272ce522012-08-17 16:25:24 -07001246 goto psy_error;
1247 /* Set max current limit */
Jack Pham0c695282012-10-19 18:13:03 -07001248 if (power_supply_set_current_limit(psy, 0))
David Keitel272ce522012-08-17 16:25:24 -07001249 goto psy_error;
1250 }
Jack Pham0c695282012-10-19 18:13:03 -07001251 power_supply_changed(psy);
Amit Blay0f7edf72012-01-15 10:11:27 +02001252 return 0;
1253
David Keitel272ce522012-08-17 16:25:24 -07001254psy_error:
1255 dev_dbg(motg->phy.dev, "power supply error when setting property\n");
Amit Blay0f7edf72012-01-15 10:11:27 +02001256 return -ENXIO;
1257}
1258
Pavankumar Kondetid8608522011-05-04 10:19:47 +05301259static void msm_otg_notify_charger(struct msm_otg *motg, unsigned mA)
1260{
Steve Mucklef132c6c2012-06-06 18:30:57 -07001261 struct usb_gadget *g = motg->phy.otg->gadget;
Vijayavardhan Vennapusaa3152032012-03-05 16:29:30 +05301262
1263 if (g && g->is_a_peripheral)
1264 return;
1265
Pavankumar Kondetiaa449e12011-11-04 11:09:26 +05301266 if ((motg->chg_type == USB_ACA_DOCK_CHARGER ||
1267 motg->chg_type == USB_ACA_A_CHARGER ||
1268 motg->chg_type == USB_ACA_B_CHARGER ||
1269 motg->chg_type == USB_ACA_C_CHARGER) &&
1270 mA > IDEV_ACA_CHG_LIMIT)
1271 mA = IDEV_ACA_CHG_LIMIT;
1272
David Keitel081a3e22012-04-18 12:37:07 -07001273 if (msm_otg_notify_chg_type(motg))
Steve Mucklef132c6c2012-06-06 18:30:57 -07001274 dev_err(motg->phy.dev,
David Keitel081a3e22012-04-18 12:37:07 -07001275 "Failed notifying %d charger type to PMIC\n",
1276 motg->chg_type);
1277
Pavankumar Kondetid8608522011-05-04 10:19:47 +05301278 if (motg->cur_power == mA)
1279 return;
1280
Heikki Krogerus1d4c9292012-02-13 13:24:09 +02001281 dev_info(motg->phy.dev, "Avail curr from USB = %u\n", mA);
Amit Blay0f7edf72012-01-15 10:11:27 +02001282
1283 /*
1284 * Use Power Supply API if supported, otherwise fallback
1285 * to legacy pm8921 API.
1286 */
1287 if (msm_otg_notify_power_supply(motg, mA))
1288 pm8921_charger_vbus_draw(mA);
1289
Pavankumar Kondetid8608522011-05-04 10:19:47 +05301290 motg->cur_power = mA;
1291}
1292
Heikki Krogerus1d4c9292012-02-13 13:24:09 +02001293static int msm_otg_set_power(struct usb_phy *phy, unsigned mA)
Pavankumar Kondetid8608522011-05-04 10:19:47 +05301294{
Heikki Krogerus1d4c9292012-02-13 13:24:09 +02001295 struct msm_otg *motg = container_of(phy, struct msm_otg, phy);
Pavankumar Kondetid8608522011-05-04 10:19:47 +05301296
1297 /*
1298 * Gadget driver uses set_power method to notify about the
1299 * available current based on suspend/configured states.
1300 *
1301 * IDEV_CHG can be drawn irrespective of suspend/un-configured
1302 * states when CDP/ACA is connected.
1303 */
1304 if (motg->chg_type == USB_SDP_CHARGER)
1305 msm_otg_notify_charger(motg, mA);
1306
1307 return 0;
1308}
1309
Steve Mucklef132c6c2012-06-06 18:30:57 -07001310static void msm_otg_start_host(struct usb_otg *otg, int on)
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05301311{
Steve Mucklef132c6c2012-06-06 18:30:57 -07001312 struct msm_otg *motg = container_of(otg->phy, struct msm_otg, phy);
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05301313 struct msm_otg_platform_data *pdata = motg->pdata;
1314 struct usb_hcd *hcd;
1315
1316 if (!otg->host)
1317 return;
1318
1319 hcd = bus_to_hcd(otg->host);
1320
1321 if (on) {
Steve Mucklef132c6c2012-06-06 18:30:57 -07001322 dev_dbg(otg->phy->dev, "host on\n");
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05301323
Vijayavardhan Vennapusa03171c72012-04-26 14:44:48 +05301324 if (pdata->otg_control == OTG_PHY_CONTROL)
Steve Mucklef132c6c2012-06-06 18:30:57 -07001325 ulpi_write(otg->phy, OTG_COMP_DISABLE,
Vijayavardhan Vennapusa03171c72012-04-26 14:44:48 +05301326 ULPI_SET(ULPI_PWR_CLK_MNG_REG));
1327
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05301328 /*
1329 * Some boards have a switch cotrolled by gpio
1330 * to enable/disable internal HUB. Enable internal
1331 * HUB before kicking the host.
1332 */
1333 if (pdata->setup_gpio)
1334 pdata->setup_gpio(OTG_STATE_A_HOST);
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05301335 usb_add_hcd(hcd, hcd->irq, IRQF_SHARED);
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05301336 } else {
Steve Mucklef132c6c2012-06-06 18:30:57 -07001337 dev_dbg(otg->phy->dev, "host off\n");
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05301338
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05301339 usb_remove_hcd(hcd);
Pavankumar Kondetiaa449e12011-11-04 11:09:26 +05301340 /* HCD core reset all bits of PORTSC. select ULPI phy */
1341 writel_relaxed(0x80000000, USB_PORTSC);
1342
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05301343 if (pdata->setup_gpio)
1344 pdata->setup_gpio(OTG_STATE_UNDEFINED);
Vijayavardhan Vennapusa03171c72012-04-26 14:44:48 +05301345
1346 if (pdata->otg_control == OTG_PHY_CONTROL)
Steve Mucklef132c6c2012-06-06 18:30:57 -07001347 ulpi_write(otg->phy, OTG_COMP_DISABLE,
Vijayavardhan Vennapusa03171c72012-04-26 14:44:48 +05301348 ULPI_CLR(ULPI_PWR_CLK_MNG_REG));
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05301349 }
1350}
1351
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001352static int msm_otg_usbdev_notify(struct notifier_block *self,
1353 unsigned long action, void *priv)
1354{
1355 struct msm_otg *motg = container_of(self, struct msm_otg, usbdev_nb);
Steve Mucklef132c6c2012-06-06 18:30:57 -07001356 struct usb_otg *otg = motg->phy.otg;
Pavankumar Kondetiaa449e12011-11-04 11:09:26 +05301357 struct usb_device *udev = priv;
1358
Pavankumar Kondetiaa449e12011-11-04 11:09:26 +05301359 if (action == USB_BUS_ADD || action == USB_BUS_REMOVE)
1360 goto out;
1361
Steve Mucklef132c6c2012-06-06 18:30:57 -07001362 if (udev->bus != otg->host)
Pavankumar Kondetiaa449e12011-11-04 11:09:26 +05301363 goto out;
1364 /*
1365 * Interested in devices connected directly to the root hub.
1366 * ACA dock can supply IDEV_CHG irrespective devices connected
1367 * on the accessory port.
1368 */
1369 if (!udev->parent || udev->parent->parent ||
1370 motg->chg_type == USB_ACA_DOCK_CHARGER)
1371 goto out;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001372
1373 switch (action) {
1374 case USB_DEVICE_ADD:
Vijayavardhan Vennapusaa3152032012-03-05 16:29:30 +05301375 if (aca_enabled())
1376 usb_disable_autosuspend(udev);
Steve Mucklef132c6c2012-06-06 18:30:57 -07001377 if (otg->phy->state == OTG_STATE_A_WAIT_BCON) {
Vijayavardhan Vennapusaa3152032012-03-05 16:29:30 +05301378 pr_debug("B_CONN set\n");
1379 set_bit(B_CONN, &motg->inputs);
1380 msm_otg_del_timer(motg);
Steve Mucklef132c6c2012-06-06 18:30:57 -07001381 otg->phy->state = OTG_STATE_A_HOST;
Vijayavardhan Vennapusaa3152032012-03-05 16:29:30 +05301382 /*
1383 * OTG PET: A-device must end session within
1384 * 10 sec after PET enumeration.
1385 */
1386 if (udev->quirks & USB_QUIRK_OTG_PET)
1387 msm_otg_start_timer(motg, TA_TST_MAINT,
1388 A_TST_MAINT);
1389 }
Pavankumar Kondetiaa449e12011-11-04 11:09:26 +05301390 /* fall through */
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001391 case USB_DEVICE_CONFIG:
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001392 if (udev->actconfig)
1393 motg->mA_port = udev->actconfig->desc.bMaxPower * 2;
1394 else
1395 motg->mA_port = IUNIT;
Steve Mucklef132c6c2012-06-06 18:30:57 -07001396 if (otg->phy->state == OTG_STATE_B_HOST)
Vijayavardhan Vennapusaa3152032012-03-05 16:29:30 +05301397 msm_otg_del_timer(motg);
Pavankumar Kondetiaa449e12011-11-04 11:09:26 +05301398 break;
1399 case USB_DEVICE_REMOVE:
Steve Mucklef132c6c2012-06-06 18:30:57 -07001400 if ((otg->phy->state == OTG_STATE_A_HOST) ||
1401 (otg->phy->state == OTG_STATE_A_SUSPEND)) {
Vijayavardhan Vennapusaa3152032012-03-05 16:29:30 +05301402 pr_debug("B_CONN clear\n");
1403 clear_bit(B_CONN, &motg->inputs);
1404 /*
1405 * OTG PET: A-device must end session after
1406 * PET disconnection if it is enumerated
1407 * with bcdDevice[0] = 1. USB core sets
1408 * bus->otg_vbus_off for us. clear it here.
1409 */
1410 if (udev->bus->otg_vbus_off) {
1411 udev->bus->otg_vbus_off = 0;
1412 set_bit(A_BUS_DROP, &motg->inputs);
1413 }
1414 queue_work(system_nrt_wq, &motg->sm_work);
1415 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001416 default:
1417 break;
1418 }
Pavankumar Kondetiaa449e12011-11-04 11:09:26 +05301419 if (test_bit(ID_A, &motg->inputs))
1420 msm_otg_notify_charger(motg, IDEV_ACA_CHG_MAX -
1421 motg->mA_port);
1422out:
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001423 return NOTIFY_OK;
1424}
1425
Mayank Ranae3926882011-12-26 09:47:54 +05301426static void msm_hsusb_vbus_power(struct msm_otg *motg, bool on)
1427{
1428 int ret;
1429 static bool vbus_is_on;
1430
1431 if (vbus_is_on == on)
1432 return;
1433
1434 if (motg->pdata->vbus_power) {
Mayank Rana91f597e2012-01-20 10:12:06 +05301435 ret = motg->pdata->vbus_power(on);
1436 if (!ret)
1437 vbus_is_on = on;
Mayank Ranae3926882011-12-26 09:47:54 +05301438 return;
1439 }
1440
1441 if (!vbus_otg) {
1442 pr_err("vbus_otg is NULL.");
1443 return;
1444 }
1445
Abhijeet Dharmapurikarbe054882012-01-03 20:27:07 -08001446 /*
1447 * if entering host mode tell the charger to not draw any current
Abhijeet Dharmapurikar6d941212012-03-05 10:30:56 -08001448 * from usb before turning on the boost.
1449 * if exiting host mode disable the boost before enabling to draw
1450 * current from the source.
Abhijeet Dharmapurikarbe054882012-01-03 20:27:07 -08001451 */
Mayank Ranae3926882011-12-26 09:47:54 +05301452 if (on) {
Abhijeet Dharmapurikar5e96aaa2012-06-26 11:21:03 -07001453 msm_otg_notify_host_mode(motg, on);
Mayank Ranae3926882011-12-26 09:47:54 +05301454 ret = regulator_enable(vbus_otg);
1455 if (ret) {
1456 pr_err("unable to enable vbus_otg\n");
1457 return;
1458 }
1459 vbus_is_on = true;
1460 } else {
1461 ret = regulator_disable(vbus_otg);
1462 if (ret) {
1463 pr_err("unable to disable vbus_otg\n");
1464 return;
1465 }
Abhijeet Dharmapurikar5e96aaa2012-06-26 11:21:03 -07001466 msm_otg_notify_host_mode(motg, on);
Mayank Ranae3926882011-12-26 09:47:54 +05301467 vbus_is_on = false;
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05301468 }
1469}
1470
Heikki Krogerus1d4c9292012-02-13 13:24:09 +02001471static int msm_otg_set_host(struct usb_otg *otg, struct usb_bus *host)
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05301472{
Heikki Krogerus1d4c9292012-02-13 13:24:09 +02001473 struct msm_otg *motg = container_of(otg->phy, struct msm_otg, phy);
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05301474 struct usb_hcd *hcd;
1475
1476 /*
1477 * Fail host registration if this board can support
1478 * only peripheral configuration.
1479 */
1480 if (motg->pdata->mode == USB_PERIPHERAL) {
Heikki Krogerus1d4c9292012-02-13 13:24:09 +02001481 dev_info(otg->phy->dev, "Host mode is not supported\n");
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05301482 return -ENODEV;
1483 }
1484
Mayank Ranae3926882011-12-26 09:47:54 +05301485 if (!motg->pdata->vbus_power && host) {
Steve Mucklef132c6c2012-06-06 18:30:57 -07001486 vbus_otg = devm_regulator_get(motg->phy.dev, "vbus_otg");
Mayank Ranae3926882011-12-26 09:47:54 +05301487 if (IS_ERR(vbus_otg)) {
1488 pr_err("Unable to get vbus_otg\n");
1489 return -ENODEV;
1490 }
1491 }
1492
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05301493 if (!host) {
Heikki Krogerus1d4c9292012-02-13 13:24:09 +02001494 if (otg->phy->state == OTG_STATE_A_HOST) {
1495 pm_runtime_get_sync(otg->phy->dev);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001496 usb_unregister_notify(&motg->usbdev_nb);
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05301497 msm_otg_start_host(otg, 0);
Mayank Ranae3926882011-12-26 09:47:54 +05301498 msm_hsusb_vbus_power(motg, 0);
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05301499 otg->host = NULL;
Heikki Krogerus1d4c9292012-02-13 13:24:09 +02001500 otg->phy->state = OTG_STATE_UNDEFINED;
Vijayavardhan Vennapusaa3152032012-03-05 16:29:30 +05301501 queue_work(system_nrt_wq, &motg->sm_work);
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05301502 } else {
1503 otg->host = NULL;
1504 }
1505
1506 return 0;
1507 }
1508
1509 hcd = bus_to_hcd(host);
1510 hcd->power_budget = motg->pdata->power_budget;
1511
Vijayavardhan Vennapusaa3152032012-03-05 16:29:30 +05301512#ifdef CONFIG_USB_OTG
1513 host->otg_port = 1;
1514#endif
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001515 motg->usbdev_nb.notifier_call = msm_otg_usbdev_notify;
1516 usb_register_notify(&motg->usbdev_nb);
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05301517 otg->host = host;
Heikki Krogerus1d4c9292012-02-13 13:24:09 +02001518 dev_dbg(otg->phy->dev, "host driver registered w/ tranceiver\n");
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05301519
1520 /*
1521 * Kick the state machine work, if peripheral is not supported
1522 * or peripheral is already registered with us.
1523 */
Pavankumar Kondeti87c01042010-12-07 17:53:58 +05301524 if (motg->pdata->mode == USB_HOST || otg->gadget) {
Heikki Krogerus1d4c9292012-02-13 13:24:09 +02001525 pm_runtime_get_sync(otg->phy->dev);
Vijayavardhan Vennapusaa3152032012-03-05 16:29:30 +05301526 queue_work(system_nrt_wq, &motg->sm_work);
Pavankumar Kondeti87c01042010-12-07 17:53:58 +05301527 }
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05301528
1529 return 0;
1530}
1531
Steve Mucklef132c6c2012-06-06 18:30:57 -07001532static void msm_otg_start_peripheral(struct usb_otg *otg, int on)
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05301533{
Manu Gautamcd82e9d2011-12-20 14:17:28 +05301534 int ret;
Steve Mucklef132c6c2012-06-06 18:30:57 -07001535 struct msm_otg *motg = container_of(otg->phy, struct msm_otg, phy);
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05301536 struct msm_otg_platform_data *pdata = motg->pdata;
1537
1538 if (!otg->gadget)
1539 return;
1540
1541 if (on) {
Steve Mucklef132c6c2012-06-06 18:30:57 -07001542 dev_dbg(otg->phy->dev, "gadget on\n");
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05301543 /*
1544 * Some boards have a switch cotrolled by gpio
1545 * to enable/disable internal HUB. Disable internal
1546 * HUB before kicking the gadget.
1547 */
1548 if (pdata->setup_gpio)
1549 pdata->setup_gpio(OTG_STATE_B_PERIPHERAL);
Ofir Cohen94213a72012-05-03 14:26:32 +03001550
Manu Gautamcd82e9d2011-12-20 14:17:28 +05301551 /* Configure BUS performance parameters for MAX bandwidth */
Manu Gautam8bdcc592012-03-06 11:26:06 +05301552 if (motg->bus_perf_client && debug_bus_voting_enabled) {
Manu Gautamcd82e9d2011-12-20 14:17:28 +05301553 ret = msm_bus_scale_client_update_request(
1554 motg->bus_perf_client, 1);
1555 if (ret)
Steve Mucklef132c6c2012-06-06 18:30:57 -07001556 dev_err(motg->phy.dev, "%s: Failed to vote for "
Manu Gautamcd82e9d2011-12-20 14:17:28 +05301557 "bus bandwidth %d\n", __func__, ret);
1558 }
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05301559 usb_gadget_vbus_connect(otg->gadget);
1560 } else {
Steve Mucklef132c6c2012-06-06 18:30:57 -07001561 dev_dbg(otg->phy->dev, "gadget off\n");
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05301562 usb_gadget_vbus_disconnect(otg->gadget);
Manu Gautamcd82e9d2011-12-20 14:17:28 +05301563 /* Configure BUS performance parameters to default */
1564 if (motg->bus_perf_client) {
1565 ret = msm_bus_scale_client_update_request(
1566 motg->bus_perf_client, 0);
1567 if (ret)
Steve Mucklef132c6c2012-06-06 18:30:57 -07001568 dev_err(motg->phy.dev, "%s: Failed to devote "
Manu Gautamcd82e9d2011-12-20 14:17:28 +05301569 "for bus bw %d\n", __func__, ret);
1570 }
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05301571 if (pdata->setup_gpio)
1572 pdata->setup_gpio(OTG_STATE_UNDEFINED);
1573 }
1574
1575}
1576
Heikki Krogerus1d4c9292012-02-13 13:24:09 +02001577static int msm_otg_set_peripheral(struct usb_otg *otg,
Stephen Boyd9850acb2013-01-28 14:11:20 -08001578 struct usb_gadget *gadget)
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05301579{
Heikki Krogerus1d4c9292012-02-13 13:24:09 +02001580 struct msm_otg *motg = container_of(otg->phy, struct msm_otg, phy);
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05301581
1582 /*
1583 * Fail peripheral registration if this board can support
1584 * only host configuration.
1585 */
1586 if (motg->pdata->mode == USB_HOST) {
Heikki Krogerus1d4c9292012-02-13 13:24:09 +02001587 dev_info(otg->phy->dev, "Peripheral mode is not supported\n");
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05301588 return -ENODEV;
1589 }
1590
1591 if (!gadget) {
Heikki Krogerus1d4c9292012-02-13 13:24:09 +02001592 if (otg->phy->state == OTG_STATE_B_PERIPHERAL) {
1593 pm_runtime_get_sync(otg->phy->dev);
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05301594 msm_otg_start_peripheral(otg, 0);
1595 otg->gadget = NULL;
Heikki Krogerus1d4c9292012-02-13 13:24:09 +02001596 otg->phy->state = OTG_STATE_UNDEFINED;
Vijayavardhan Vennapusaa3152032012-03-05 16:29:30 +05301597 queue_work(system_nrt_wq, &motg->sm_work);
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05301598 } else {
1599 otg->gadget = NULL;
1600 }
1601
1602 return 0;
1603 }
1604 otg->gadget = gadget;
Heikki Krogerus1d4c9292012-02-13 13:24:09 +02001605 dev_dbg(otg->phy->dev, "peripheral driver registered w/ tranceiver\n");
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05301606
1607 /*
1608 * Kick the state machine work, if host is not supported
1609 * or host is already registered with us.
1610 */
Pavankumar Kondeti87c01042010-12-07 17:53:58 +05301611 if (motg->pdata->mode == USB_PERIPHERAL || otg->host) {
Heikki Krogerus1d4c9292012-02-13 13:24:09 +02001612 pm_runtime_get_sync(otg->phy->dev);
Vijayavardhan Vennapusaa3152032012-03-05 16:29:30 +05301613 queue_work(system_nrt_wq, &motg->sm_work);
Pavankumar Kondeti87c01042010-12-07 17:53:58 +05301614 }
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05301615
1616 return 0;
1617}
1618
Pavankumar Kondetibecab5b2012-11-06 16:45:10 +05301619static bool msm_otg_read_pmic_id_state(struct msm_otg *motg)
1620{
1621 unsigned long flags;
1622 int id;
1623
1624 if (!motg->pdata->pmic_id_irq)
1625 return -ENODEV;
1626
1627 local_irq_save(flags);
1628 id = irq_read_line(motg->pdata->pmic_id_irq);
1629 local_irq_restore(flags);
1630
1631 /*
1632 * If we can not read ID line state for some reason, treat
1633 * it as float. This would prevent MHL discovery and kicking
1634 * host mode unnecessarily.
1635 */
1636 return !!id;
1637}
1638
Pavankumar Kondeti2aec9f32012-06-13 09:06:03 +05301639static int msm_otg_mhl_register_callback(struct msm_otg *motg,
1640 void (*callback)(int on))
1641{
1642 struct usb_phy *phy = &motg->phy;
1643 int ret;
1644
Manoj Raoa7bddd12012-08-27 20:36:45 -07001645 if (!motg->pdata->mhl_enable) {
1646 dev_dbg(phy->dev, "MHL feature not enabled\n");
1647 return -ENODEV;
1648 }
1649
Pavankumar Kondeti2aec9f32012-06-13 09:06:03 +05301650 if (motg->pdata->otg_control != OTG_PMIC_CONTROL ||
1651 !motg->pdata->pmic_id_irq) {
1652 dev_dbg(phy->dev, "MHL can not be supported without PMIC Id\n");
1653 return -ENODEV;
1654 }
1655
1656 if (!motg->pdata->mhl_dev_name) {
1657 dev_dbg(phy->dev, "MHL device name does not exist.\n");
1658 return -ENODEV;
1659 }
1660
1661 if (callback)
1662 ret = mhl_register_callback(motg->pdata->mhl_dev_name,
1663 callback);
1664 else
1665 ret = mhl_unregister_callback(motg->pdata->mhl_dev_name);
1666
1667 if (ret)
1668 dev_dbg(phy->dev, "mhl_register_callback(%s) return error=%d\n",
1669 motg->pdata->mhl_dev_name, ret);
1670 else
1671 motg->mhl_enabled = true;
1672
1673 return ret;
1674}
1675
1676static void msm_otg_mhl_notify_online(int on)
1677{
1678 struct msm_otg *motg = the_msm_otg;
1679 struct usb_phy *phy = &motg->phy;
1680 bool queue = false;
1681
1682 dev_dbg(phy->dev, "notify MHL %s%s\n", on ? "" : "dis", "connected");
1683
1684 if (on) {
1685 set_bit(MHL, &motg->inputs);
1686 } else {
1687 clear_bit(MHL, &motg->inputs);
1688 queue = true;
1689 }
1690
1691 if (queue && phy->state != OTG_STATE_UNDEFINED)
1692 schedule_work(&motg->sm_work);
1693}
1694
1695static bool msm_otg_is_mhl(struct msm_otg *motg)
1696{
1697 struct usb_phy *phy = &motg->phy;
1698 int is_mhl, ret;
1699
1700 ret = mhl_device_discovery(motg->pdata->mhl_dev_name, &is_mhl);
1701 if (ret || is_mhl != MHL_DISCOVERY_RESULT_MHL) {
1702 /*
1703 * MHL driver calls our callback saying that MHL connected
1704 * if RID_GND is detected. But at later part of discovery
1705 * it may figure out MHL is not connected and returns
1706 * false. Hence clear MHL input here.
1707 */
1708 clear_bit(MHL, &motg->inputs);
1709 dev_dbg(phy->dev, "MHL device not found\n");
1710 return false;
1711 }
1712
1713 set_bit(MHL, &motg->inputs);
1714 dev_dbg(phy->dev, "MHL device found\n");
1715 return true;
1716}
1717
1718static bool msm_chg_mhl_detect(struct msm_otg *motg)
1719{
1720 bool ret, id;
Pavankumar Kondeti2aec9f32012-06-13 09:06:03 +05301721
1722 if (!motg->mhl_enabled)
1723 return false;
1724
Pavankumar Kondetibecab5b2012-11-06 16:45:10 +05301725 id = msm_otg_read_pmic_id_state(motg);
Pavankumar Kondeti2aec9f32012-06-13 09:06:03 +05301726
1727 if (id)
1728 return false;
1729
1730 mhl_det_in_progress = true;
1731 ret = msm_otg_is_mhl(motg);
1732 mhl_det_in_progress = false;
1733
1734 return ret;
1735}
1736
Pavankumar Kondeti458d8792012-09-28 14:45:18 +05301737static void msm_otg_chg_check_timer_func(unsigned long data)
1738{
1739 struct msm_otg *motg = (struct msm_otg *) data;
1740 struct usb_otg *otg = motg->phy.otg;
1741
1742 if (atomic_read(&motg->in_lpm) ||
1743 !test_bit(B_SESS_VLD, &motg->inputs) ||
1744 otg->phy->state != OTG_STATE_B_PERIPHERAL ||
1745 otg->gadget->speed != USB_SPEED_UNKNOWN) {
1746 dev_dbg(otg->phy->dev, "Nothing to do in chg_check_timer\n");
1747 return;
1748 }
1749
1750 if ((readl_relaxed(USB_PORTSC) & PORTSC_LS) == PORTSC_LS) {
1751 dev_dbg(otg->phy->dev, "DCP is detected as SDP\n");
1752 set_bit(B_FALSE_SDP, &motg->inputs);
1753 queue_work(system_nrt_wq, &motg->sm_work);
1754 }
1755}
1756
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001757static bool msm_chg_aca_detect(struct msm_otg *motg)
1758{
Steve Mucklef132c6c2012-06-06 18:30:57 -07001759 struct usb_phy *phy = &motg->phy;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001760 u32 int_sts;
1761 bool ret = false;
1762
Pavankumar Kondetiaa449e12011-11-04 11:09:26 +05301763 if (!aca_enabled())
1764 goto out;
1765
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001766 if (motg->pdata->phy_type == CI_45NM_INTEGRATED_PHY)
1767 goto out;
1768
Steve Mucklef132c6c2012-06-06 18:30:57 -07001769 int_sts = ulpi_read(phy, 0x87);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001770 switch (int_sts & 0x1C) {
1771 case 0x08:
1772 if (!test_and_set_bit(ID_A, &motg->inputs)) {
Steve Mucklef132c6c2012-06-06 18:30:57 -07001773 dev_dbg(phy->dev, "ID_A\n");
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001774 motg->chg_type = USB_ACA_A_CHARGER;
1775 motg->chg_state = USB_CHG_STATE_DETECTED;
1776 clear_bit(ID_B, &motg->inputs);
1777 clear_bit(ID_C, &motg->inputs);
Pavankumar Kondetiaa449e12011-11-04 11:09:26 +05301778 set_bit(ID, &motg->inputs);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001779 ret = true;
1780 }
1781 break;
1782 case 0x0C:
1783 if (!test_and_set_bit(ID_B, &motg->inputs)) {
Steve Mucklef132c6c2012-06-06 18:30:57 -07001784 dev_dbg(phy->dev, "ID_B\n");
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001785 motg->chg_type = USB_ACA_B_CHARGER;
1786 motg->chg_state = USB_CHG_STATE_DETECTED;
1787 clear_bit(ID_A, &motg->inputs);
1788 clear_bit(ID_C, &motg->inputs);
Pavankumar Kondetiaa449e12011-11-04 11:09:26 +05301789 set_bit(ID, &motg->inputs);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001790 ret = true;
1791 }
1792 break;
1793 case 0x10:
1794 if (!test_and_set_bit(ID_C, &motg->inputs)) {
Steve Mucklef132c6c2012-06-06 18:30:57 -07001795 dev_dbg(phy->dev, "ID_C\n");
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001796 motg->chg_type = USB_ACA_C_CHARGER;
1797 motg->chg_state = USB_CHG_STATE_DETECTED;
1798 clear_bit(ID_A, &motg->inputs);
1799 clear_bit(ID_B, &motg->inputs);
Pavankumar Kondetiaa449e12011-11-04 11:09:26 +05301800 set_bit(ID, &motg->inputs);
1801 ret = true;
1802 }
1803 break;
1804 case 0x04:
1805 if (test_and_clear_bit(ID, &motg->inputs)) {
Steve Mucklef132c6c2012-06-06 18:30:57 -07001806 dev_dbg(phy->dev, "ID_GND\n");
Pavankumar Kondetiaa449e12011-11-04 11:09:26 +05301807 motg->chg_type = USB_INVALID_CHARGER;
1808 motg->chg_state = USB_CHG_STATE_UNDEFINED;
1809 clear_bit(ID_A, &motg->inputs);
1810 clear_bit(ID_B, &motg->inputs);
1811 clear_bit(ID_C, &motg->inputs);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001812 ret = true;
1813 }
1814 break;
1815 default:
1816 ret = test_and_clear_bit(ID_A, &motg->inputs) |
1817 test_and_clear_bit(ID_B, &motg->inputs) |
Pavankumar Kondetiaa449e12011-11-04 11:09:26 +05301818 test_and_clear_bit(ID_C, &motg->inputs) |
1819 !test_and_set_bit(ID, &motg->inputs);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001820 if (ret) {
Steve Mucklef132c6c2012-06-06 18:30:57 -07001821 dev_dbg(phy->dev, "ID A/B/C/GND is no more\n");
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001822 motg->chg_type = USB_INVALID_CHARGER;
1823 motg->chg_state = USB_CHG_STATE_UNDEFINED;
1824 }
1825 }
1826out:
1827 return ret;
1828}
1829
1830static void msm_chg_enable_aca_det(struct msm_otg *motg)
1831{
Steve Mucklef132c6c2012-06-06 18:30:57 -07001832 struct usb_phy *phy = &motg->phy;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001833
Pavankumar Kondetiaa449e12011-11-04 11:09:26 +05301834 if (!aca_enabled())
1835 return;
1836
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001837 switch (motg->pdata->phy_type) {
1838 case SNPS_28NM_INTEGRATED_PHY:
Pavankumar Kondetiaa449e12011-11-04 11:09:26 +05301839 /* Disable ID_GND in link and PHY */
1840 writel_relaxed(readl_relaxed(USB_OTGSC) & ~(OTGSC_IDPU |
1841 OTGSC_IDIE), USB_OTGSC);
Steve Mucklef132c6c2012-06-06 18:30:57 -07001842 ulpi_write(phy, 0x01, 0x0C);
1843 ulpi_write(phy, 0x10, 0x0F);
1844 ulpi_write(phy, 0x10, 0x12);
Pavankumar Kondeti446f4542012-02-01 13:57:13 +05301845 /* Disable PMIC ID pull-up */
1846 pm8xxx_usb_id_pullup(0);
Pavankumar Kondetiaa449e12011-11-04 11:09:26 +05301847 /* Enable ACA ID detection */
Steve Mucklef132c6c2012-06-06 18:30:57 -07001848 ulpi_write(phy, 0x20, 0x85);
Pavankumar Kondeti4960f312011-12-06 15:46:14 +05301849 aca_id_turned_on = true;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001850 break;
1851 default:
1852 break;
1853 }
1854}
1855
1856static void msm_chg_enable_aca_intr(struct msm_otg *motg)
1857{
Steve Mucklef132c6c2012-06-06 18:30:57 -07001858 struct usb_phy *phy = &motg->phy;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001859
Pavankumar Kondetiaa449e12011-11-04 11:09:26 +05301860 if (!aca_enabled())
1861 return;
1862
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001863 switch (motg->pdata->phy_type) {
1864 case SNPS_28NM_INTEGRATED_PHY:
Pavankumar Kondetiaa449e12011-11-04 11:09:26 +05301865 /* Enable ACA Detection interrupt (on any RID change) */
Steve Mucklef132c6c2012-06-06 18:30:57 -07001866 ulpi_write(phy, 0x01, 0x94);
Pavankumar Kondetiaa449e12011-11-04 11:09:26 +05301867 break;
1868 default:
1869 break;
1870 }
1871}
1872
1873static void msm_chg_disable_aca_intr(struct msm_otg *motg)
1874{
Steve Mucklef132c6c2012-06-06 18:30:57 -07001875 struct usb_phy *phy = &motg->phy;
Pavankumar Kondetiaa449e12011-11-04 11:09:26 +05301876
1877 if (!aca_enabled())
1878 return;
1879
1880 switch (motg->pdata->phy_type) {
1881 case SNPS_28NM_INTEGRATED_PHY:
Steve Mucklef132c6c2012-06-06 18:30:57 -07001882 ulpi_write(phy, 0x01, 0x95);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001883 break;
1884 default:
1885 break;
1886 }
1887}
1888
1889static bool msm_chg_check_aca_intr(struct msm_otg *motg)
1890{
Steve Mucklef132c6c2012-06-06 18:30:57 -07001891 struct usb_phy *phy = &motg->phy;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001892 bool ret = false;
1893
Pavankumar Kondetiaa449e12011-11-04 11:09:26 +05301894 if (!aca_enabled())
1895 return ret;
1896
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001897 switch (motg->pdata->phy_type) {
1898 case SNPS_28NM_INTEGRATED_PHY:
Steve Mucklef132c6c2012-06-06 18:30:57 -07001899 if (ulpi_read(phy, 0x91) & 1) {
1900 dev_dbg(phy->dev, "RID change\n");
1901 ulpi_write(phy, 0x01, 0x92);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001902 ret = msm_chg_aca_detect(motg);
1903 }
1904 default:
1905 break;
1906 }
1907 return ret;
1908}
Pavankumar Kondetiaa449e12011-11-04 11:09:26 +05301909
1910static void msm_otg_id_timer_func(unsigned long data)
1911{
1912 struct msm_otg *motg = (struct msm_otg *) data;
1913
1914 if (!aca_enabled())
1915 return;
1916
1917 if (atomic_read(&motg->in_lpm)) {
Steve Mucklef132c6c2012-06-06 18:30:57 -07001918 dev_dbg(motg->phy.dev, "timer: in lpm\n");
Pavankumar Kondetiaa449e12011-11-04 11:09:26 +05301919 return;
1920 }
1921
Steve Mucklef132c6c2012-06-06 18:30:57 -07001922 if (motg->phy.state == OTG_STATE_A_SUSPEND)
Vijayavardhan Vennapusaa3152032012-03-05 16:29:30 +05301923 goto out;
1924
Pavankumar Kondetiaa449e12011-11-04 11:09:26 +05301925 if (msm_chg_check_aca_intr(motg)) {
Steve Mucklef132c6c2012-06-06 18:30:57 -07001926 dev_dbg(motg->phy.dev, "timer: aca work\n");
Vijayavardhan Vennapusaa3152032012-03-05 16:29:30 +05301927 queue_work(system_nrt_wq, &motg->sm_work);
Pavankumar Kondetiaa449e12011-11-04 11:09:26 +05301928 }
1929
Vijayavardhan Vennapusaa3152032012-03-05 16:29:30 +05301930out:
Pavankumar Kondetiaa449e12011-11-04 11:09:26 +05301931 if (!test_bit(ID, &motg->inputs) || test_bit(ID_A, &motg->inputs))
1932 mod_timer(&motg->id_timer, ID_TIMER_FREQ);
1933}
1934
Pavankumar Kondetid8608522011-05-04 10:19:47 +05301935static bool msm_chg_check_secondary_det(struct msm_otg *motg)
1936{
Heikki Krogerus1d4c9292012-02-13 13:24:09 +02001937 struct usb_phy *phy = &motg->phy;
Pavankumar Kondetid8608522011-05-04 10:19:47 +05301938 u32 chg_det;
1939 bool ret = false;
1940
1941 switch (motg->pdata->phy_type) {
1942 case CI_45NM_INTEGRATED_PHY:
Heikki Krogerus1d4c9292012-02-13 13:24:09 +02001943 chg_det = ulpi_read(phy, 0x34);
Pavankumar Kondetid8608522011-05-04 10:19:47 +05301944 ret = chg_det & (1 << 4);
1945 break;
1946 case SNPS_28NM_INTEGRATED_PHY:
Heikki Krogerus1d4c9292012-02-13 13:24:09 +02001947 chg_det = ulpi_read(phy, 0x87);
Pavankumar Kondetid8608522011-05-04 10:19:47 +05301948 ret = chg_det & 1;
1949 break;
1950 default:
1951 break;
1952 }
1953 return ret;
1954}
1955
1956static void msm_chg_enable_secondary_det(struct msm_otg *motg)
1957{
Heikki Krogerus1d4c9292012-02-13 13:24:09 +02001958 struct usb_phy *phy = &motg->phy;
Pavankumar Kondetid8608522011-05-04 10:19:47 +05301959 u32 chg_det;
1960
1961 switch (motg->pdata->phy_type) {
1962 case CI_45NM_INTEGRATED_PHY:
Heikki Krogerus1d4c9292012-02-13 13:24:09 +02001963 chg_det = ulpi_read(phy, 0x34);
Pavankumar Kondetid8608522011-05-04 10:19:47 +05301964 /* Turn off charger block */
1965 chg_det |= ~(1 << 1);
Heikki Krogerus1d4c9292012-02-13 13:24:09 +02001966 ulpi_write(phy, chg_det, 0x34);
Pavankumar Kondetid8608522011-05-04 10:19:47 +05301967 udelay(20);
1968 /* control chg block via ULPI */
1969 chg_det &= ~(1 << 3);
Heikki Krogerus1d4c9292012-02-13 13:24:09 +02001970 ulpi_write(phy, chg_det, 0x34);
Pavankumar Kondetid8608522011-05-04 10:19:47 +05301971 /* put it in host mode for enabling D- source */
1972 chg_det &= ~(1 << 2);
Heikki Krogerus1d4c9292012-02-13 13:24:09 +02001973 ulpi_write(phy, chg_det, 0x34);
Pavankumar Kondetid8608522011-05-04 10:19:47 +05301974 /* Turn on chg detect block */
1975 chg_det &= ~(1 << 1);
Heikki Krogerus1d4c9292012-02-13 13:24:09 +02001976 ulpi_write(phy, chg_det, 0x34);
Pavankumar Kondetid8608522011-05-04 10:19:47 +05301977 udelay(20);
1978 /* enable chg detection */
1979 chg_det &= ~(1 << 0);
Heikki Krogerus1d4c9292012-02-13 13:24:09 +02001980 ulpi_write(phy, chg_det, 0x34);
Pavankumar Kondetid8608522011-05-04 10:19:47 +05301981 break;
1982 case SNPS_28NM_INTEGRATED_PHY:
1983 /*
1984 * Configure DM as current source, DP as current sink
1985 * and enable battery charging comparators.
1986 */
Heikki Krogerus1d4c9292012-02-13 13:24:09 +02001987 ulpi_write(phy, 0x8, 0x85);
1988 ulpi_write(phy, 0x2, 0x85);
1989 ulpi_write(phy, 0x1, 0x85);
Pavankumar Kondetid8608522011-05-04 10:19:47 +05301990 break;
1991 default:
1992 break;
1993 }
1994}
1995
1996static bool msm_chg_check_primary_det(struct msm_otg *motg)
1997{
Heikki Krogerus1d4c9292012-02-13 13:24:09 +02001998 struct usb_phy *phy = &motg->phy;
Pavankumar Kondetid8608522011-05-04 10:19:47 +05301999 u32 chg_det;
2000 bool ret = false;
2001
2002 switch (motg->pdata->phy_type) {
2003 case CI_45NM_INTEGRATED_PHY:
Heikki Krogerus1d4c9292012-02-13 13:24:09 +02002004 chg_det = ulpi_read(phy, 0x34);
Pavankumar Kondetid8608522011-05-04 10:19:47 +05302005 ret = chg_det & (1 << 4);
2006 break;
2007 case SNPS_28NM_INTEGRATED_PHY:
Heikki Krogerus1d4c9292012-02-13 13:24:09 +02002008 chg_det = ulpi_read(phy, 0x87);
Pavankumar Kondetid8608522011-05-04 10:19:47 +05302009 ret = chg_det & 1;
Pavankumar Kondeti9ec21d32012-05-07 15:50:23 +05302010 /* Turn off VDP_SRC */
2011 ulpi_write(phy, 0x3, 0x86);
2012 msleep(20);
Pavankumar Kondetid8608522011-05-04 10:19:47 +05302013 break;
2014 default:
2015 break;
2016 }
2017 return ret;
2018}
2019
2020static void msm_chg_enable_primary_det(struct msm_otg *motg)
2021{
Heikki Krogerus1d4c9292012-02-13 13:24:09 +02002022 struct usb_phy *phy = &motg->phy;
Pavankumar Kondetid8608522011-05-04 10:19:47 +05302023 u32 chg_det;
2024
2025 switch (motg->pdata->phy_type) {
2026 case CI_45NM_INTEGRATED_PHY:
Heikki Krogerus1d4c9292012-02-13 13:24:09 +02002027 chg_det = ulpi_read(phy, 0x34);
Pavankumar Kondetid8608522011-05-04 10:19:47 +05302028 /* enable chg detection */
2029 chg_det &= ~(1 << 0);
Heikki Krogerus1d4c9292012-02-13 13:24:09 +02002030 ulpi_write(phy, chg_det, 0x34);
Pavankumar Kondetid8608522011-05-04 10:19:47 +05302031 break;
2032 case SNPS_28NM_INTEGRATED_PHY:
2033 /*
2034 * Configure DP as current source, DM as current sink
2035 * and enable battery charging comparators.
2036 */
Heikki Krogerus1d4c9292012-02-13 13:24:09 +02002037 ulpi_write(phy, 0x2, 0x85);
2038 ulpi_write(phy, 0x1, 0x85);
Pavankumar Kondetid8608522011-05-04 10:19:47 +05302039 break;
2040 default:
2041 break;
2042 }
2043}
2044
2045static bool msm_chg_check_dcd(struct msm_otg *motg)
2046{
Heikki Krogerus1d4c9292012-02-13 13:24:09 +02002047 struct usb_phy *phy = &motg->phy;
Pavankumar Kondetid8608522011-05-04 10:19:47 +05302048 u32 line_state;
2049 bool ret = false;
2050
2051 switch (motg->pdata->phy_type) {
2052 case CI_45NM_INTEGRATED_PHY:
Heikki Krogerus1d4c9292012-02-13 13:24:09 +02002053 line_state = ulpi_read(phy, 0x15);
Pavankumar Kondetid8608522011-05-04 10:19:47 +05302054 ret = !(line_state & 1);
2055 break;
2056 case SNPS_28NM_INTEGRATED_PHY:
Heikki Krogerus1d4c9292012-02-13 13:24:09 +02002057 line_state = ulpi_read(phy, 0x87);
Pavankumar Kondetid8608522011-05-04 10:19:47 +05302058 ret = line_state & 2;
2059 break;
2060 default:
2061 break;
2062 }
2063 return ret;
2064}
2065
2066static void msm_chg_disable_dcd(struct msm_otg *motg)
2067{
Heikki Krogerus1d4c9292012-02-13 13:24:09 +02002068 struct usb_phy *phy = &motg->phy;
Pavankumar Kondetid8608522011-05-04 10:19:47 +05302069 u32 chg_det;
2070
2071 switch (motg->pdata->phy_type) {
2072 case CI_45NM_INTEGRATED_PHY:
Heikki Krogerus1d4c9292012-02-13 13:24:09 +02002073 chg_det = ulpi_read(phy, 0x34);
Pavankumar Kondetid8608522011-05-04 10:19:47 +05302074 chg_det &= ~(1 << 5);
Heikki Krogerus1d4c9292012-02-13 13:24:09 +02002075 ulpi_write(phy, chg_det, 0x34);
Pavankumar Kondetid8608522011-05-04 10:19:47 +05302076 break;
2077 case SNPS_28NM_INTEGRATED_PHY:
Heikki Krogerus1d4c9292012-02-13 13:24:09 +02002078 ulpi_write(phy, 0x10, 0x86);
Pavankumar Kondetid8608522011-05-04 10:19:47 +05302079 break;
2080 default:
2081 break;
2082 }
2083}
2084
2085static void msm_chg_enable_dcd(struct msm_otg *motg)
2086{
Heikki Krogerus1d4c9292012-02-13 13:24:09 +02002087 struct usb_phy *phy = &motg->phy;
Pavankumar Kondetid8608522011-05-04 10:19:47 +05302088 u32 chg_det;
2089
2090 switch (motg->pdata->phy_type) {
2091 case CI_45NM_INTEGRATED_PHY:
Heikki Krogerus1d4c9292012-02-13 13:24:09 +02002092 chg_det = ulpi_read(phy, 0x34);
Pavankumar Kondetid8608522011-05-04 10:19:47 +05302093 /* Turn on D+ current source */
2094 chg_det |= (1 << 5);
Heikki Krogerus1d4c9292012-02-13 13:24:09 +02002095 ulpi_write(phy, chg_det, 0x34);
Pavankumar Kondetid8608522011-05-04 10:19:47 +05302096 break;
2097 case SNPS_28NM_INTEGRATED_PHY:
2098 /* Data contact detection enable */
Heikki Krogerus1d4c9292012-02-13 13:24:09 +02002099 ulpi_write(phy, 0x10, 0x85);
Pavankumar Kondetid8608522011-05-04 10:19:47 +05302100 break;
2101 default:
2102 break;
2103 }
2104}
2105
2106static void msm_chg_block_on(struct msm_otg *motg)
2107{
Heikki Krogerus1d4c9292012-02-13 13:24:09 +02002108 struct usb_phy *phy = &motg->phy;
Pavankumar Kondetid8608522011-05-04 10:19:47 +05302109 u32 func_ctrl, chg_det;
2110
2111 /* put the controller in non-driving mode */
Heikki Krogerus1d4c9292012-02-13 13:24:09 +02002112 func_ctrl = ulpi_read(phy, ULPI_FUNC_CTRL);
Pavankumar Kondetid8608522011-05-04 10:19:47 +05302113 func_ctrl &= ~ULPI_FUNC_CTRL_OPMODE_MASK;
2114 func_ctrl |= ULPI_FUNC_CTRL_OPMODE_NONDRIVING;
Heikki Krogerus1d4c9292012-02-13 13:24:09 +02002115 ulpi_write(phy, func_ctrl, ULPI_FUNC_CTRL);
Pavankumar Kondetid8608522011-05-04 10:19:47 +05302116
2117 switch (motg->pdata->phy_type) {
2118 case CI_45NM_INTEGRATED_PHY:
Heikki Krogerus1d4c9292012-02-13 13:24:09 +02002119 chg_det = ulpi_read(phy, 0x34);
Pavankumar Kondetid8608522011-05-04 10:19:47 +05302120 /* control chg block via ULPI */
2121 chg_det &= ~(1 << 3);
Heikki Krogerus1d4c9292012-02-13 13:24:09 +02002122 ulpi_write(phy, chg_det, 0x34);
Pavankumar Kondetid8608522011-05-04 10:19:47 +05302123 /* Turn on chg detect block */
2124 chg_det &= ~(1 << 1);
Heikki Krogerus1d4c9292012-02-13 13:24:09 +02002125 ulpi_write(phy, chg_det, 0x34);
Pavankumar Kondetid8608522011-05-04 10:19:47 +05302126 udelay(20);
2127 break;
2128 case SNPS_28NM_INTEGRATED_PHY:
Pavankumar Kondeti768dcb82012-10-05 13:21:45 +05302129 /* disable DP and DM pull down resistors */
2130 ulpi_write(phy, 0x6, 0xC);
Pavankumar Kondetid8608522011-05-04 10:19:47 +05302131 /* Clear charger detecting control bits */
Steve Mucklef132c6c2012-06-06 18:30:57 -07002132 ulpi_write(phy, 0x1F, 0x86);
Pavankumar Kondetid8608522011-05-04 10:19:47 +05302133 /* Clear alt interrupt latch and enable bits */
Heikki Krogerus1d4c9292012-02-13 13:24:09 +02002134 ulpi_write(phy, 0x1F, 0x92);
2135 ulpi_write(phy, 0x1F, 0x95);
Pavankumar Kondetid8608522011-05-04 10:19:47 +05302136 udelay(100);
2137 break;
2138 default:
2139 break;
2140 }
2141}
2142
2143static void msm_chg_block_off(struct msm_otg *motg)
2144{
Heikki Krogerus1d4c9292012-02-13 13:24:09 +02002145 struct usb_phy *phy = &motg->phy;
Pavankumar Kondetid8608522011-05-04 10:19:47 +05302146 u32 func_ctrl, chg_det;
2147
2148 switch (motg->pdata->phy_type) {
2149 case CI_45NM_INTEGRATED_PHY:
Heikki Krogerus1d4c9292012-02-13 13:24:09 +02002150 chg_det = ulpi_read(phy, 0x34);
Pavankumar Kondetid8608522011-05-04 10:19:47 +05302151 /* Turn off charger block */
2152 chg_det |= ~(1 << 1);
Heikki Krogerus1d4c9292012-02-13 13:24:09 +02002153 ulpi_write(phy, chg_det, 0x34);
Pavankumar Kondetid8608522011-05-04 10:19:47 +05302154 break;
2155 case SNPS_28NM_INTEGRATED_PHY:
2156 /* Clear charger detecting control bits */
Heikki Krogerus1d4c9292012-02-13 13:24:09 +02002157 ulpi_write(phy, 0x3F, 0x86);
Pavankumar Kondetid8608522011-05-04 10:19:47 +05302158 /* Clear alt interrupt latch and enable bits */
Heikki Krogerus1d4c9292012-02-13 13:24:09 +02002159 ulpi_write(phy, 0x1F, 0x92);
2160 ulpi_write(phy, 0x1F, 0x95);
Pavankumar Kondetid8608522011-05-04 10:19:47 +05302161 break;
2162 default:
2163 break;
2164 }
2165
2166 /* put the controller in normal mode */
Heikki Krogerus1d4c9292012-02-13 13:24:09 +02002167 func_ctrl = ulpi_read(phy, ULPI_FUNC_CTRL);
Pavankumar Kondetid8608522011-05-04 10:19:47 +05302168 func_ctrl &= ~ULPI_FUNC_CTRL_OPMODE_MASK;
2169 func_ctrl |= ULPI_FUNC_CTRL_OPMODE_NORMAL;
Heikki Krogerus1d4c9292012-02-13 13:24:09 +02002170 ulpi_write(phy, func_ctrl, ULPI_FUNC_CTRL);
Pavankumar Kondetid8608522011-05-04 10:19:47 +05302171}
2172
Anji jonnalad270e2d2011-08-09 11:28:32 +05302173static const char *chg_to_string(enum usb_chg_type chg_type)
2174{
2175 switch (chg_type) {
2176 case USB_SDP_CHARGER: return "USB_SDP_CHARGER";
2177 case USB_DCP_CHARGER: return "USB_DCP_CHARGER";
2178 case USB_CDP_CHARGER: return "USB_CDP_CHARGER";
2179 case USB_ACA_A_CHARGER: return "USB_ACA_A_CHARGER";
2180 case USB_ACA_B_CHARGER: return "USB_ACA_B_CHARGER";
2181 case USB_ACA_C_CHARGER: return "USB_ACA_C_CHARGER";
2182 case USB_ACA_DOCK_CHARGER: return "USB_ACA_DOCK_CHARGER";
Pavankumar Kondeti9ec21d32012-05-07 15:50:23 +05302183 case USB_PROPRIETARY_CHARGER: return "USB_PROPRIETARY_CHARGER";
Anji jonnalad270e2d2011-08-09 11:28:32 +05302184 default: return "INVALID_CHARGER";
2185 }
2186}
2187
Pavankumar Kondetiebb4a2d2013-01-04 12:28:10 +05302188#define MSM_CHG_DCD_TIMEOUT (750 * HZ/1000) /* 750 msec */
2189#define MSM_CHG_DCD_POLL_TIME (50 * HZ/1000) /* 50 msec */
Pavankumar Kondeti283146f2012-01-12 12:51:19 +05302190#define MSM_CHG_PRIMARY_DET_TIME (50 * HZ/1000) /* TVDPSRC_ON */
2191#define MSM_CHG_SECONDARY_DET_TIME (50 * HZ/1000) /* TVDMSRC_ON */
Pavankumar Kondetid8608522011-05-04 10:19:47 +05302192static void msm_chg_detect_work(struct work_struct *w)
2193{
2194 struct msm_otg *motg = container_of(w, struct msm_otg, chg_work.work);
Heikki Krogerus1d4c9292012-02-13 13:24:09 +02002195 struct usb_phy *phy = &motg->phy;
Pavankumar Kondeti2d09e5f2012-01-16 08:56:57 +05302196 bool is_dcd = false, tmout, vout, is_aca;
Pavankumar Kondeti9ec21d32012-05-07 15:50:23 +05302197 u32 line_state, dm_vlgc;
Pavankumar Kondetid8608522011-05-04 10:19:47 +05302198 unsigned long delay;
2199
Heikki Krogerus1d4c9292012-02-13 13:24:09 +02002200 dev_dbg(phy->dev, "chg detection work\n");
Pavankumar Kondeti2aec9f32012-06-13 09:06:03 +05302201
2202 if (test_bit(MHL, &motg->inputs)) {
2203 dev_dbg(phy->dev, "detected MHL, escape chg detection work\n");
2204 return;
2205 }
2206
Pavankumar Kondetid8608522011-05-04 10:19:47 +05302207 switch (motg->chg_state) {
2208 case USB_CHG_STATE_UNDEFINED:
Pavankumar Kondetid8608522011-05-04 10:19:47 +05302209 msm_chg_block_on(motg);
Pavankumar Kondeti768dcb82012-10-05 13:21:45 +05302210 msm_chg_enable_dcd(motg);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002211 msm_chg_enable_aca_det(motg);
Pavankumar Kondetid8608522011-05-04 10:19:47 +05302212 motg->chg_state = USB_CHG_STATE_WAIT_FOR_DCD;
Pavankumar Kondetiebb4a2d2013-01-04 12:28:10 +05302213 motg->dcd_time = 0;
Pavankumar Kondetid8608522011-05-04 10:19:47 +05302214 delay = MSM_CHG_DCD_POLL_TIME;
2215 break;
2216 case USB_CHG_STATE_WAIT_FOR_DCD:
Pavankumar Kondeti2aec9f32012-06-13 09:06:03 +05302217 if (msm_chg_mhl_detect(motg)) {
2218 msm_chg_block_off(motg);
2219 motg->chg_state = USB_CHG_STATE_DETECTED;
2220 motg->chg_type = USB_INVALID_CHARGER;
2221 queue_work(system_nrt_wq, &motg->sm_work);
2222 return;
2223 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002224 is_aca = msm_chg_aca_detect(motg);
2225 if (is_aca) {
2226 /*
2227 * ID_A can be ACA dock too. continue
2228 * primary detection after DCD.
2229 */
2230 if (test_bit(ID_A, &motg->inputs)) {
2231 motg->chg_state = USB_CHG_STATE_WAIT_FOR_DCD;
2232 } else {
2233 delay = 0;
2234 break;
2235 }
2236 }
Pavankumar Kondeti768dcb82012-10-05 13:21:45 +05302237 is_dcd = msm_chg_check_dcd(motg);
Pavankumar Kondetiebb4a2d2013-01-04 12:28:10 +05302238 motg->dcd_time += MSM_CHG_DCD_POLL_TIME;
2239 tmout = motg->dcd_time >= MSM_CHG_DCD_TIMEOUT;
Pavankumar Kondetid8608522011-05-04 10:19:47 +05302240 if (is_dcd || tmout) {
Pavankumar Kondeti768dcb82012-10-05 13:21:45 +05302241 msm_chg_disable_dcd(motg);
Pavankumar Kondetid8608522011-05-04 10:19:47 +05302242 msm_chg_enable_primary_det(motg);
2243 delay = MSM_CHG_PRIMARY_DET_TIME;
2244 motg->chg_state = USB_CHG_STATE_DCD_DONE;
2245 } else {
2246 delay = MSM_CHG_DCD_POLL_TIME;
2247 }
2248 break;
2249 case USB_CHG_STATE_DCD_DONE:
2250 vout = msm_chg_check_primary_det(motg);
Pavankumar Kondeti9ec21d32012-05-07 15:50:23 +05302251 line_state = readl_relaxed(USB_PORTSC) & PORTSC_LS;
2252 dm_vlgc = line_state & PORTSC_LS_DM;
2253 if (vout && !dm_vlgc) { /* VDAT_REF < DM < VLGC */
Pavankumar Kondetiaa449e12011-11-04 11:09:26 +05302254 if (test_bit(ID_A, &motg->inputs)) {
2255 motg->chg_type = USB_ACA_DOCK_CHARGER;
2256 motg->chg_state = USB_CHG_STATE_DETECTED;
2257 delay = 0;
2258 break;
2259 }
Pavankumar Kondeti9ec21d32012-05-07 15:50:23 +05302260 if (line_state) { /* DP > VLGC */
2261 motg->chg_type = USB_PROPRIETARY_CHARGER;
2262 motg->chg_state = USB_CHG_STATE_DETECTED;
2263 delay = 0;
2264 } else {
2265 msm_chg_enable_secondary_det(motg);
2266 delay = MSM_CHG_SECONDARY_DET_TIME;
2267 motg->chg_state = USB_CHG_STATE_PRIMARY_DONE;
2268 }
2269 } else { /* DM < VDAT_REF || DM > VLGC */
Pavankumar Kondetiaa449e12011-11-04 11:09:26 +05302270 if (test_bit(ID_A, &motg->inputs)) {
2271 motg->chg_type = USB_ACA_A_CHARGER;
2272 motg->chg_state = USB_CHG_STATE_DETECTED;
2273 delay = 0;
2274 break;
2275 }
Pavankumar Kondeti9ec21d32012-05-07 15:50:23 +05302276
2277 if (line_state) /* DP > VLGC or/and DM > VLGC */
2278 motg->chg_type = USB_PROPRIETARY_CHARGER;
2279 else
2280 motg->chg_type = USB_SDP_CHARGER;
2281
Pavankumar Kondetid8608522011-05-04 10:19:47 +05302282 motg->chg_state = USB_CHG_STATE_DETECTED;
2283 delay = 0;
2284 }
2285 break;
2286 case USB_CHG_STATE_PRIMARY_DONE:
2287 vout = msm_chg_check_secondary_det(motg);
2288 if (vout)
2289 motg->chg_type = USB_DCP_CHARGER;
2290 else
2291 motg->chg_type = USB_CDP_CHARGER;
2292 motg->chg_state = USB_CHG_STATE_SECONDARY_DONE;
2293 /* fall through */
2294 case USB_CHG_STATE_SECONDARY_DONE:
2295 motg->chg_state = USB_CHG_STATE_DETECTED;
2296 case USB_CHG_STATE_DETECTED:
Pavankumar Kondetid7b6d1a2013-01-11 15:38:09 +05302297 /*
2298 * Notify the charger type to power supply
2299 * owner as soon as we determine the charger.
2300 */
2301 msm_otg_notify_chg_type(motg);
Pavankumar Kondetid8608522011-05-04 10:19:47 +05302302 msm_chg_block_off(motg);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002303 msm_chg_enable_aca_det(motg);
Vijayavardhan Vennapusaa3152032012-03-05 16:29:30 +05302304 /*
2305 * Spurious interrupt is seen after enabling ACA detection
2306 * due to which charger detection fails in case of PET.
2307 * Add delay of 100 microsec to avoid that.
2308 */
2309 udelay(100);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002310 msm_chg_enable_aca_intr(motg);
Steve Mucklef132c6c2012-06-06 18:30:57 -07002311 dev_dbg(phy->dev, "chg_type = %s\n",
Anji jonnalad270e2d2011-08-09 11:28:32 +05302312 chg_to_string(motg->chg_type));
Vijayavardhan Vennapusaa3152032012-03-05 16:29:30 +05302313 queue_work(system_nrt_wq, &motg->sm_work);
Pavankumar Kondetid8608522011-05-04 10:19:47 +05302314 return;
2315 default:
2316 return;
2317 }
2318
Vijayavardhan Vennapusaa3152032012-03-05 16:29:30 +05302319 queue_delayed_work(system_nrt_wq, &motg->chg_work, delay);
Pavankumar Kondetid8608522011-05-04 10:19:47 +05302320}
2321
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05302322/*
2323 * We support OTG, Peripheral only and Host only configurations. In case
2324 * of OTG, mode switch (host-->peripheral/peripheral-->host) can happen
2325 * via Id pin status or user request (debugfs). Id/BSV interrupts are not
2326 * enabled when switch is controlled by user and default mode is supplied
2327 * by board file, which can be changed by userspace later.
2328 */
2329static void msm_otg_init_sm(struct msm_otg *motg)
2330{
2331 struct msm_otg_platform_data *pdata = motg->pdata;
2332 u32 otgsc = readl(USB_OTGSC);
2333
2334 switch (pdata->mode) {
2335 case USB_OTG:
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002336 if (pdata->otg_control == OTG_USER_CONTROL) {
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05302337 if (pdata->default_mode == USB_HOST) {
2338 clear_bit(ID, &motg->inputs);
2339 } else if (pdata->default_mode == USB_PERIPHERAL) {
2340 set_bit(ID, &motg->inputs);
2341 set_bit(B_SESS_VLD, &motg->inputs);
2342 } else {
2343 set_bit(ID, &motg->inputs);
2344 clear_bit(B_SESS_VLD, &motg->inputs);
2345 }
Pavankumar Kondeti4960f312011-12-06 15:46:14 +05302346 } else if (pdata->otg_control == OTG_PHY_CONTROL) {
Vijayavardhan Vennapusaa3152032012-03-05 16:29:30 +05302347 if (otgsc & OTGSC_ID) {
Pavankumar Kondeti4960f312011-12-06 15:46:14 +05302348 set_bit(ID, &motg->inputs);
Vijayavardhan Vennapusaa3152032012-03-05 16:29:30 +05302349 } else {
Pavankumar Kondeti4960f312011-12-06 15:46:14 +05302350 clear_bit(ID, &motg->inputs);
Vijayavardhan Vennapusaa3152032012-03-05 16:29:30 +05302351 set_bit(A_BUS_REQ, &motg->inputs);
2352 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002353 if (otgsc & OTGSC_BSV)
2354 set_bit(B_SESS_VLD, &motg->inputs);
2355 else
2356 clear_bit(B_SESS_VLD, &motg->inputs);
Pavankumar Kondeti4960f312011-12-06 15:46:14 +05302357 } else if (pdata->otg_control == OTG_PMIC_CONTROL) {
Pavankumar Kondeti0d81f312012-01-13 11:34:10 +05302358 if (pdata->pmic_id_irq) {
Pavankumar Kondetibecab5b2012-11-06 16:45:10 +05302359 if (msm_otg_read_pmic_id_state(motg))
Pavankumar Kondeti0d81f312012-01-13 11:34:10 +05302360 set_bit(ID, &motg->inputs);
2361 else
2362 clear_bit(ID, &motg->inputs);
2363 }
Pavankumar Kondeti4960f312011-12-06 15:46:14 +05302364 /*
2365 * VBUS initial state is reported after PMIC
2366 * driver initialization. Wait for it.
2367 */
2368 wait_for_completion(&pmic_vbus_init);
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05302369 }
2370 break;
2371 case USB_HOST:
2372 clear_bit(ID, &motg->inputs);
2373 break;
2374 case USB_PERIPHERAL:
2375 set_bit(ID, &motg->inputs);
Pavankumar Kondeti0d81f312012-01-13 11:34:10 +05302376 if (pdata->otg_control == OTG_PHY_CONTROL) {
2377 if (otgsc & OTGSC_BSV)
2378 set_bit(B_SESS_VLD, &motg->inputs);
2379 else
2380 clear_bit(B_SESS_VLD, &motg->inputs);
2381 } else if (pdata->otg_control == OTG_PMIC_CONTROL) {
2382 /*
2383 * VBUS initial state is reported after PMIC
2384 * driver initialization. Wait for it.
2385 */
2386 wait_for_completion(&pmic_vbus_init);
2387 }
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05302388 break;
2389 default:
2390 break;
2391 }
2392}
2393
2394static void msm_otg_sm_work(struct work_struct *w)
2395{
2396 struct msm_otg *motg = container_of(w, struct msm_otg, sm_work);
Heikki Krogerus1d4c9292012-02-13 13:24:09 +02002397 struct usb_otg *otg = motg->phy.otg;
Vijayavardhan Vennapusaa3152032012-03-05 16:29:30 +05302398 bool work = 0, srp_reqd;
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05302399
Steve Mucklef132c6c2012-06-06 18:30:57 -07002400 pm_runtime_resume(otg->phy->dev);
2401 pr_debug("%s work\n", otg_state_string(otg->phy->state));
Heikki Krogerus1d4c9292012-02-13 13:24:09 +02002402 switch (otg->phy->state) {
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05302403 case OTG_STATE_UNDEFINED:
Heikki Krogerus1d4c9292012-02-13 13:24:09 +02002404 msm_otg_reset(otg->phy);
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05302405 msm_otg_init_sm(motg);
David Keitel272ce522012-08-17 16:25:24 -07002406 if (!psy && legacy_power_supply) {
2407 psy = power_supply_get_by_name("usb");
2408
2409 if (!psy)
2410 pr_err("couldn't get usb power supply\n");
2411 }
2412
Heikki Krogerus1d4c9292012-02-13 13:24:09 +02002413 otg->phy->state = OTG_STATE_B_IDLE;
Pavankumar Kondeti8a379b42011-12-12 13:07:23 +05302414 if (!test_bit(B_SESS_VLD, &motg->inputs) &&
2415 test_bit(ID, &motg->inputs)) {
Steve Mucklef132c6c2012-06-06 18:30:57 -07002416 pm_runtime_put_noidle(otg->phy->dev);
2417 pm_runtime_suspend(otg->phy->dev);
Pavankumar Kondeti8a379b42011-12-12 13:07:23 +05302418 break;
2419 }
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05302420 /* FALL THROUGH */
2421 case OTG_STATE_B_IDLE:
Pavankumar Kondeti2aec9f32012-06-13 09:06:03 +05302422 if (test_bit(MHL, &motg->inputs)) {
2423 /* allow LPM */
2424 pm_runtime_put_noidle(otg->phy->dev);
2425 pm_runtime_suspend(otg->phy->dev);
2426 } else if ((!test_bit(ID, &motg->inputs) ||
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002427 test_bit(ID_A, &motg->inputs)) && otg->host) {
Vijayavardhan Vennapusaa3152032012-03-05 16:29:30 +05302428 pr_debug("!id || id_A\n");
Pavankumar Kondeti2aec9f32012-06-13 09:06:03 +05302429 if (msm_chg_mhl_detect(motg)) {
2430 work = 1;
2431 break;
2432 }
Vijayavardhan Vennapusaa3152032012-03-05 16:29:30 +05302433 clear_bit(B_BUS_REQ, &motg->inputs);
2434 set_bit(A_BUS_REQ, &motg->inputs);
Steve Mucklef132c6c2012-06-06 18:30:57 -07002435 otg->phy->state = OTG_STATE_A_IDLE;
Vijayavardhan Vennapusaa3152032012-03-05 16:29:30 +05302436 work = 1;
Pavankumar Kondetid8608522011-05-04 10:19:47 +05302437 } else if (test_bit(B_SESS_VLD, &motg->inputs)) {
Vijayavardhan Vennapusaa3152032012-03-05 16:29:30 +05302438 pr_debug("b_sess_vld\n");
Pavankumar Kondetid8608522011-05-04 10:19:47 +05302439 switch (motg->chg_state) {
2440 case USB_CHG_STATE_UNDEFINED:
2441 msm_chg_detect_work(&motg->chg_work.work);
2442 break;
2443 case USB_CHG_STATE_DETECTED:
2444 switch (motg->chg_type) {
2445 case USB_DCP_CHARGER:
Pavankumar Kondeti283146f2012-01-12 12:51:19 +05302446 /* Enable VDP_SRC */
Steve Mucklef132c6c2012-06-06 18:30:57 -07002447 ulpi_write(otg->phy, 0x2, 0x85);
Pavankumar Kondeti9ec21d32012-05-07 15:50:23 +05302448 /* fall through */
2449 case USB_PROPRIETARY_CHARGER:
Pavankumar Kondetid8608522011-05-04 10:19:47 +05302450 msm_otg_notify_charger(motg,
2451 IDEV_CHG_MAX);
Steve Mucklef132c6c2012-06-06 18:30:57 -07002452 pm_runtime_put_noidle(otg->phy->dev);
2453 pm_runtime_suspend(otg->phy->dev);
Pavankumar Kondetid8608522011-05-04 10:19:47 +05302454 break;
Pavankumar Kondetiaa449e12011-11-04 11:09:26 +05302455 case USB_ACA_B_CHARGER:
2456 msm_otg_notify_charger(motg,
2457 IDEV_ACA_CHG_MAX);
2458 /*
2459 * (ID_B --> ID_C) PHY_ALT interrupt can
2460 * not be detected in LPM.
2461 */
Pavankumar Kondetid8608522011-05-04 10:19:47 +05302462 break;
2463 case USB_CDP_CHARGER:
2464 msm_otg_notify_charger(motg,
2465 IDEV_CHG_MAX);
2466 msm_otg_start_peripheral(otg, 1);
Steve Mucklef132c6c2012-06-06 18:30:57 -07002467 otg->phy->state =
2468 OTG_STATE_B_PERIPHERAL;
Pavankumar Kondetid8608522011-05-04 10:19:47 +05302469 break;
Pavankumar Kondetiaa449e12011-11-04 11:09:26 +05302470 case USB_ACA_C_CHARGER:
2471 msm_otg_notify_charger(motg,
2472 IDEV_ACA_CHG_MAX);
2473 msm_otg_start_peripheral(otg, 1);
Steve Mucklef132c6c2012-06-06 18:30:57 -07002474 otg->phy->state =
2475 OTG_STATE_B_PERIPHERAL;
Pavankumar Kondetid8608522011-05-04 10:19:47 +05302476 break;
2477 case USB_SDP_CHARGER:
Pavankumar Kondetid8608522011-05-04 10:19:47 +05302478 msm_otg_start_peripheral(otg, 1);
Steve Mucklef132c6c2012-06-06 18:30:57 -07002479 otg->phy->state =
2480 OTG_STATE_B_PERIPHERAL;
Pavankumar Kondeti458d8792012-09-28 14:45:18 +05302481 mod_timer(&motg->chg_check_timer,
2482 CHG_RECHECK_DELAY);
Pavankumar Kondetid8608522011-05-04 10:19:47 +05302483 break;
2484 default:
2485 break;
2486 }
2487 break;
2488 default:
2489 break;
2490 }
Vijayavardhan Vennapusaa3152032012-03-05 16:29:30 +05302491 } else if (test_bit(B_BUS_REQ, &motg->inputs)) {
2492 pr_debug("b_sess_end && b_bus_req\n");
2493 if (msm_otg_start_srp(otg) < 0) {
2494 clear_bit(B_BUS_REQ, &motg->inputs);
2495 work = 1;
2496 break;
Pavankumar Kondetid8608522011-05-04 10:19:47 +05302497 }
Steve Mucklef132c6c2012-06-06 18:30:57 -07002498 otg->phy->state = OTG_STATE_B_SRP_INIT;
Vijayavardhan Vennapusaa3152032012-03-05 16:29:30 +05302499 msm_otg_start_timer(motg, TB_SRP_FAIL, B_SRP_FAIL);
2500 break;
Pavankumar Kondetid8608522011-05-04 10:19:47 +05302501 } else {
Vijayavardhan Vennapusaa3152032012-03-05 16:29:30 +05302502 pr_debug("chg_work cancel");
Pavankumar Kondeti458d8792012-09-28 14:45:18 +05302503 del_timer_sync(&motg->chg_check_timer);
2504 clear_bit(B_FALSE_SDP, &motg->inputs);
Mayank Rana8ab00352013-01-23 19:26:21 +05302505 clear_bit(A_BUS_REQ, &motg->inputs);
Pavankumar Kondetiaa449e12011-11-04 11:09:26 +05302506 cancel_delayed_work_sync(&motg->chg_work);
Pavankumar Kondetid8608522011-05-04 10:19:47 +05302507 motg->chg_state = USB_CHG_STATE_UNDEFINED;
2508 motg->chg_type = USB_INVALID_CHARGER;
Rajkumar Raghupathy18fd7132012-04-20 11:28:13 +05302509 msm_otg_notify_charger(motg, 0);
Steve Mucklef132c6c2012-06-06 18:30:57 -07002510 msm_otg_reset(otg->phy);
Pavankumar Kondetibecab5b2012-11-06 16:45:10 +05302511 /*
2512 * There is a small window where ID interrupt
2513 * is not monitored during ID detection circuit
2514 * switch from ACA to PMIC. Check ID state
2515 * before entering into low power mode.
2516 */
2517 if (!msm_otg_read_pmic_id_state(motg)) {
2518 pr_debug("process missed ID intr\n");
2519 clear_bit(ID, &motg->inputs);
2520 work = 1;
2521 break;
2522 }
Steve Mucklef132c6c2012-06-06 18:30:57 -07002523 pm_runtime_put_noidle(otg->phy->dev);
Amit Blayd6f38282012-10-29 13:13:46 +02002524 /*
2525 * Only if autosuspend was enabled in probe, it will be
2526 * used here. Otherwise, no delay will be used.
2527 */
2528 pm_runtime_mark_last_busy(otg->phy->dev);
2529 pm_runtime_autosuspend(otg->phy->dev);
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05302530 }
2531 break;
Vijayavardhan Vennapusaa3152032012-03-05 16:29:30 +05302532 case OTG_STATE_B_SRP_INIT:
2533 if (!test_bit(ID, &motg->inputs) ||
2534 test_bit(ID_A, &motg->inputs) ||
2535 test_bit(ID_C, &motg->inputs) ||
2536 (test_bit(B_SESS_VLD, &motg->inputs) &&
2537 !test_bit(ID_B, &motg->inputs))) {
2538 pr_debug("!id || id_a/c || b_sess_vld+!id_b\n");
2539 msm_otg_del_timer(motg);
Steve Mucklef132c6c2012-06-06 18:30:57 -07002540 otg->phy->state = OTG_STATE_B_IDLE;
Vijayavardhan Vennapusaa3152032012-03-05 16:29:30 +05302541 /*
2542 * clear VBUSVLDEXTSEL and VBUSVLDEXT register
2543 * bits after SRP initiation.
2544 */
Steve Mucklef132c6c2012-06-06 18:30:57 -07002545 ulpi_write(otg->phy, 0x0, 0x98);
Vijayavardhan Vennapusaa3152032012-03-05 16:29:30 +05302546 work = 1;
2547 } else if (test_bit(B_SRP_FAIL, &motg->tmouts)) {
2548 pr_debug("b_srp_fail\n");
2549 pr_info("A-device did not respond to SRP\n");
2550 clear_bit(B_BUS_REQ, &motg->inputs);
2551 clear_bit(B_SRP_FAIL, &motg->tmouts);
2552 otg_send_event(OTG_EVENT_NO_RESP_FOR_SRP);
Steve Mucklef132c6c2012-06-06 18:30:57 -07002553 ulpi_write(otg->phy, 0x0, 0x98);
2554 otg->phy->state = OTG_STATE_B_IDLE;
Vijayavardhan Vennapusaa3152032012-03-05 16:29:30 +05302555 motg->b_last_se0_sess = jiffies;
2556 work = 1;
2557 }
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05302558 break;
2559 case OTG_STATE_B_PERIPHERAL:
Pavankumar Kondeti458d8792012-09-28 14:45:18 +05302560 if (test_bit(B_SESS_VLD, &motg->inputs) &&
2561 test_bit(B_FALSE_SDP, &motg->inputs)) {
2562 pr_debug("B_FALSE_SDP\n");
2563 msm_otg_start_peripheral(otg, 0);
2564 motg->chg_type = USB_DCP_CHARGER;
2565 clear_bit(B_FALSE_SDP, &motg->inputs);
2566 otg->phy->state = OTG_STATE_B_IDLE;
2567 work = 1;
2568 } else if (!test_bit(ID, &motg->inputs) ||
Vijayavardhan Vennapusaa3152032012-03-05 16:29:30 +05302569 test_bit(ID_A, &motg->inputs) ||
2570 test_bit(ID_B, &motg->inputs) ||
2571 !test_bit(B_SESS_VLD, &motg->inputs)) {
2572 pr_debug("!id || id_a/b || !b_sess_vld\n");
Pavankumar Kondetid8608522011-05-04 10:19:47 +05302573 motg->chg_state = USB_CHG_STATE_UNDEFINED;
2574 motg->chg_type = USB_INVALID_CHARGER;
Vijayavardhan Vennapusaa3152032012-03-05 16:29:30 +05302575 msm_otg_notify_charger(motg, 0);
2576 srp_reqd = otg->gadget->otg_srp_reqd;
2577 msm_otg_start_peripheral(otg, 0);
Vijayavardhan Vennapusaa3152032012-03-05 16:29:30 +05302578 if (test_bit(ID_B, &motg->inputs))
2579 clear_bit(ID_B, &motg->inputs);
2580 clear_bit(B_BUS_REQ, &motg->inputs);
Steve Mucklef132c6c2012-06-06 18:30:57 -07002581 otg->phy->state = OTG_STATE_B_IDLE;
Vijayavardhan Vennapusaa3152032012-03-05 16:29:30 +05302582 motg->b_last_se0_sess = jiffies;
2583 if (srp_reqd)
2584 msm_otg_start_timer(motg,
2585 TB_TST_SRP, B_TST_SRP);
2586 else
2587 work = 1;
2588 } else if (test_bit(B_BUS_REQ, &motg->inputs) &&
2589 otg->gadget->b_hnp_enable &&
2590 test_bit(A_BUS_SUSPEND, &motg->inputs)) {
2591 pr_debug("b_bus_req && b_hnp_en && a_bus_suspend\n");
2592 msm_otg_start_timer(motg, TB_ASE0_BRST, B_ASE0_BRST);
2593 /* D+ pullup should not be disconnected within 4msec
2594 * after A device suspends the bus. Otherwise PET will
2595 * fail the compliance test.
2596 */
2597 udelay(1000);
2598 msm_otg_start_peripheral(otg, 0);
Steve Mucklef132c6c2012-06-06 18:30:57 -07002599 otg->phy->state = OTG_STATE_B_WAIT_ACON;
Vijayavardhan Vennapusaa3152032012-03-05 16:29:30 +05302600 /*
2601 * start HCD even before A-device enable
2602 * pull-up to meet HNP timings.
2603 */
2604 otg->host->is_b_host = 1;
2605 msm_otg_start_host(otg, 1);
Amit Blay6fa647a2012-05-24 14:12:08 +03002606 } else if (test_bit(A_BUS_SUSPEND, &motg->inputs) &&
2607 test_bit(B_SESS_VLD, &motg->inputs)) {
2608 pr_debug("a_bus_suspend && b_sess_vld\n");
2609 if (motg->caps & ALLOW_LPM_ON_DEV_SUSPEND) {
Steve Mucklef132c6c2012-06-06 18:30:57 -07002610 pm_runtime_put_noidle(otg->phy->dev);
2611 pm_runtime_suspend(otg->phy->dev);
Amit Blay6fa647a2012-05-24 14:12:08 +03002612 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002613 } else if (test_bit(ID_C, &motg->inputs)) {
Pavankumar Kondetiaa449e12011-11-04 11:09:26 +05302614 msm_otg_notify_charger(motg, IDEV_ACA_CHG_MAX);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002615 }
2616 break;
Vijayavardhan Vennapusaa3152032012-03-05 16:29:30 +05302617 case OTG_STATE_B_WAIT_ACON:
2618 if (!test_bit(ID, &motg->inputs) ||
2619 test_bit(ID_A, &motg->inputs) ||
2620 test_bit(ID_B, &motg->inputs) ||
2621 !test_bit(B_SESS_VLD, &motg->inputs)) {
2622 pr_debug("!id || id_a/b || !b_sess_vld\n");
2623 msm_otg_del_timer(motg);
Pavankumar Kondetiaa449e12011-11-04 11:09:26 +05302624 /*
Vijayavardhan Vennapusaa3152032012-03-05 16:29:30 +05302625 * A-device is physically disconnected during
2626 * HNP. Remove HCD.
Pavankumar Kondetiaa449e12011-11-04 11:09:26 +05302627 */
Vijayavardhan Vennapusaa3152032012-03-05 16:29:30 +05302628 msm_otg_start_host(otg, 0);
2629 otg->host->is_b_host = 0;
2630
2631 clear_bit(B_BUS_REQ, &motg->inputs);
2632 clear_bit(A_BUS_SUSPEND, &motg->inputs);
2633 motg->b_last_se0_sess = jiffies;
Heikki Krogerus1d4c9292012-02-13 13:24:09 +02002634 otg->phy->state = OTG_STATE_B_IDLE;
2635 msm_otg_reset(otg->phy);
Vijayavardhan Vennapusaa3152032012-03-05 16:29:30 +05302636 work = 1;
2637 } else if (test_bit(A_CONN, &motg->inputs)) {
2638 pr_debug("a_conn\n");
2639 clear_bit(A_BUS_SUSPEND, &motg->inputs);
Steve Mucklef132c6c2012-06-06 18:30:57 -07002640 otg->phy->state = OTG_STATE_B_HOST;
Vijayavardhan Vennapusaa3152032012-03-05 16:29:30 +05302641 /*
2642 * PET disconnects D+ pullup after reset is generated
2643 * by B device in B_HOST role which is not detected by
2644 * B device. As workaorund , start timer of 300msec
2645 * and stop timer if A device is enumerated else clear
2646 * A_CONN.
2647 */
2648 msm_otg_start_timer(motg, TB_TST_CONFIG,
2649 B_TST_CONFIG);
2650 } else if (test_bit(B_ASE0_BRST, &motg->tmouts)) {
2651 pr_debug("b_ase0_brst_tmout\n");
2652 pr_info("B HNP fail:No response from A device\n");
2653 msm_otg_start_host(otg, 0);
Steve Mucklef132c6c2012-06-06 18:30:57 -07002654 msm_otg_reset(otg->phy);
Vijayavardhan Vennapusaa3152032012-03-05 16:29:30 +05302655 otg->host->is_b_host = 0;
2656 clear_bit(B_ASE0_BRST, &motg->tmouts);
2657 clear_bit(A_BUS_SUSPEND, &motg->inputs);
2658 clear_bit(B_BUS_REQ, &motg->inputs);
2659 otg_send_event(OTG_EVENT_HNP_FAILED);
Steve Mucklef132c6c2012-06-06 18:30:57 -07002660 otg->phy->state = OTG_STATE_B_IDLE;
Vijayavardhan Vennapusaa3152032012-03-05 16:29:30 +05302661 work = 1;
2662 } else if (test_bit(ID_C, &motg->inputs)) {
2663 msm_otg_notify_charger(motg, IDEV_ACA_CHG_MAX);
2664 }
2665 break;
2666 case OTG_STATE_B_HOST:
2667 if (!test_bit(B_BUS_REQ, &motg->inputs) ||
2668 !test_bit(A_CONN, &motg->inputs) ||
2669 !test_bit(B_SESS_VLD, &motg->inputs)) {
2670 pr_debug("!b_bus_req || !a_conn || !b_sess_vld\n");
2671 clear_bit(A_CONN, &motg->inputs);
2672 clear_bit(B_BUS_REQ, &motg->inputs);
2673 msm_otg_start_host(otg, 0);
2674 otg->host->is_b_host = 0;
Steve Mucklef132c6c2012-06-06 18:30:57 -07002675 otg->phy->state = OTG_STATE_B_IDLE;
2676 msm_otg_reset(otg->phy);
Vijayavardhan Vennapusaa3152032012-03-05 16:29:30 +05302677 work = 1;
2678 } else if (test_bit(ID_C, &motg->inputs)) {
2679 msm_otg_notify_charger(motg, IDEV_ACA_CHG_MAX);
2680 }
2681 break;
2682 case OTG_STATE_A_IDLE:
2683 otg->default_a = 1;
2684 if (test_bit(ID, &motg->inputs) &&
2685 !test_bit(ID_A, &motg->inputs)) {
2686 pr_debug("id && !id_a\n");
2687 otg->default_a = 0;
2688 clear_bit(A_BUS_DROP, &motg->inputs);
Steve Mucklef132c6c2012-06-06 18:30:57 -07002689 otg->phy->state = OTG_STATE_B_IDLE;
Vijayavardhan Vennapusaa3152032012-03-05 16:29:30 +05302690 del_timer_sync(&motg->id_timer);
2691 msm_otg_link_reset(motg);
2692 msm_chg_enable_aca_intr(motg);
2693 msm_otg_notify_charger(motg, 0);
2694 work = 1;
2695 } else if (!test_bit(A_BUS_DROP, &motg->inputs) &&
2696 (test_bit(A_SRP_DET, &motg->inputs) ||
2697 test_bit(A_BUS_REQ, &motg->inputs))) {
2698 pr_debug("!a_bus_drop && (a_srp_det || a_bus_req)\n");
2699
2700 clear_bit(A_SRP_DET, &motg->inputs);
2701 /* Disable SRP detection */
2702 writel_relaxed((readl_relaxed(USB_OTGSC) &
2703 ~OTGSC_INTSTS_MASK) &
2704 ~OTGSC_DPIE, USB_OTGSC);
2705
Steve Mucklef132c6c2012-06-06 18:30:57 -07002706 otg->phy->state = OTG_STATE_A_WAIT_VRISE;
Vijayavardhan Vennapusaa3152032012-03-05 16:29:30 +05302707 /* VBUS should not be supplied before end of SRP pulse
2708 * generated by PET, if not complaince test fail.
2709 */
2710 usleep_range(10000, 12000);
2711 /* ACA: ID_A: Stop charging untill enumeration */
2712 if (test_bit(ID_A, &motg->inputs))
2713 msm_otg_notify_charger(motg, 0);
2714 else
2715 msm_hsusb_vbus_power(motg, 1);
2716 msm_otg_start_timer(motg, TA_WAIT_VRISE, A_WAIT_VRISE);
2717 } else {
2718 pr_debug("No session requested\n");
2719 clear_bit(A_BUS_DROP, &motg->inputs);
2720 if (test_bit(ID_A, &motg->inputs)) {
2721 msm_otg_notify_charger(motg,
2722 IDEV_ACA_CHG_MAX);
2723 } else if (!test_bit(ID, &motg->inputs)) {
2724 msm_otg_notify_charger(motg, 0);
2725 /*
2726 * A-device is not providing power on VBUS.
2727 * Enable SRP detection.
2728 */
2729 writel_relaxed(0x13, USB_USBMODE);
2730 writel_relaxed((readl_relaxed(USB_OTGSC) &
2731 ~OTGSC_INTSTS_MASK) |
2732 OTGSC_DPIE, USB_OTGSC);
2733 mb();
2734 }
2735 }
2736 break;
2737 case OTG_STATE_A_WAIT_VRISE:
2738 if ((test_bit(ID, &motg->inputs) &&
2739 !test_bit(ID_A, &motg->inputs)) ||
2740 test_bit(A_BUS_DROP, &motg->inputs) ||
2741 test_bit(A_WAIT_VRISE, &motg->tmouts)) {
2742 pr_debug("id || a_bus_drop || a_wait_vrise_tmout\n");
2743 clear_bit(A_BUS_REQ, &motg->inputs);
2744 msm_otg_del_timer(motg);
2745 msm_hsusb_vbus_power(motg, 0);
Steve Mucklef132c6c2012-06-06 18:30:57 -07002746 otg->phy->state = OTG_STATE_A_WAIT_VFALL;
Vijayavardhan Vennapusaa3152032012-03-05 16:29:30 +05302747 msm_otg_start_timer(motg, TA_WAIT_VFALL, A_WAIT_VFALL);
2748 } else if (test_bit(A_VBUS_VLD, &motg->inputs)) {
2749 pr_debug("a_vbus_vld\n");
Steve Mucklef132c6c2012-06-06 18:30:57 -07002750 otg->phy->state = OTG_STATE_A_WAIT_BCON;
Vijayavardhan Vennapusaa3152032012-03-05 16:29:30 +05302751 if (TA_WAIT_BCON > 0)
2752 msm_otg_start_timer(motg, TA_WAIT_BCON,
2753 A_WAIT_BCON);
2754 msm_otg_start_host(otg, 1);
2755 msm_chg_enable_aca_det(motg);
2756 msm_chg_disable_aca_intr(motg);
Chiranjeevi Velempati489a27c2012-03-29 09:47:17 +05302757 mod_timer(&motg->id_timer, ID_TIMER_FREQ);
Vijayavardhan Vennapusaa3152032012-03-05 16:29:30 +05302758 if (msm_chg_check_aca_intr(motg))
2759 work = 1;
2760 }
2761 break;
2762 case OTG_STATE_A_WAIT_BCON:
2763 if ((test_bit(ID, &motg->inputs) &&
2764 !test_bit(ID_A, &motg->inputs)) ||
2765 test_bit(A_BUS_DROP, &motg->inputs) ||
2766 test_bit(A_WAIT_BCON, &motg->tmouts)) {
2767 pr_debug("(id && id_a/b/c) || a_bus_drop ||"
2768 "a_wait_bcon_tmout\n");
2769 if (test_bit(A_WAIT_BCON, &motg->tmouts)) {
2770 pr_info("Device No Response\n");
2771 otg_send_event(OTG_EVENT_DEV_CONN_TMOUT);
2772 }
2773 msm_otg_del_timer(motg);
2774 clear_bit(A_BUS_REQ, &motg->inputs);
2775 clear_bit(B_CONN, &motg->inputs);
2776 msm_otg_start_host(otg, 0);
2777 /*
2778 * ACA: ID_A with NO accessory, just the A plug is
2779 * attached to ACA: Use IDCHG_MAX for charging
2780 */
2781 if (test_bit(ID_A, &motg->inputs))
2782 msm_otg_notify_charger(motg, IDEV_CHG_MIN);
2783 else
2784 msm_hsusb_vbus_power(motg, 0);
Steve Mucklef132c6c2012-06-06 18:30:57 -07002785 otg->phy->state = OTG_STATE_A_WAIT_VFALL;
Vijayavardhan Vennapusaa3152032012-03-05 16:29:30 +05302786 msm_otg_start_timer(motg, TA_WAIT_VFALL, A_WAIT_VFALL);
2787 } else if (!test_bit(A_VBUS_VLD, &motg->inputs)) {
2788 pr_debug("!a_vbus_vld\n");
2789 clear_bit(B_CONN, &motg->inputs);
2790 msm_otg_del_timer(motg);
2791 msm_otg_start_host(otg, 0);
Steve Mucklef132c6c2012-06-06 18:30:57 -07002792 otg->phy->state = OTG_STATE_A_VBUS_ERR;
2793 msm_otg_reset(otg->phy);
Vijayavardhan Vennapusaa3152032012-03-05 16:29:30 +05302794 } else if (test_bit(ID_A, &motg->inputs)) {
2795 msm_hsusb_vbus_power(motg, 0);
2796 } else if (!test_bit(A_BUS_REQ, &motg->inputs)) {
2797 /*
2798 * If TA_WAIT_BCON is infinite, we don;t
2799 * turn off VBUS. Enter low power mode.
2800 */
2801 if (TA_WAIT_BCON < 0)
Steve Mucklef132c6c2012-06-06 18:30:57 -07002802 pm_runtime_put_sync(otg->phy->dev);
Vijayavardhan Vennapusaa3152032012-03-05 16:29:30 +05302803 } else if (!test_bit(ID, &motg->inputs)) {
2804 msm_hsusb_vbus_power(motg, 1);
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05302805 }
2806 break;
2807 case OTG_STATE_A_HOST:
Vijayavardhan Vennapusaa3152032012-03-05 16:29:30 +05302808 if ((test_bit(ID, &motg->inputs) &&
2809 !test_bit(ID_A, &motg->inputs)) ||
2810 test_bit(A_BUS_DROP, &motg->inputs)) {
2811 pr_debug("id_a/b/c || a_bus_drop\n");
2812 clear_bit(B_CONN, &motg->inputs);
2813 clear_bit(A_BUS_REQ, &motg->inputs);
2814 msm_otg_del_timer(motg);
Steve Mucklef132c6c2012-06-06 18:30:57 -07002815 otg->phy->state = OTG_STATE_A_WAIT_VFALL;
Vijayavardhan Vennapusaa3152032012-03-05 16:29:30 +05302816 msm_otg_start_host(otg, 0);
2817 if (!test_bit(ID_A, &motg->inputs))
2818 msm_hsusb_vbus_power(motg, 0);
2819 msm_otg_start_timer(motg, TA_WAIT_VFALL, A_WAIT_VFALL);
2820 } else if (!test_bit(A_VBUS_VLD, &motg->inputs)) {
2821 pr_debug("!a_vbus_vld\n");
2822 clear_bit(B_CONN, &motg->inputs);
2823 msm_otg_del_timer(motg);
Steve Mucklef132c6c2012-06-06 18:30:57 -07002824 otg->phy->state = OTG_STATE_A_VBUS_ERR;
Vijayavardhan Vennapusaa3152032012-03-05 16:29:30 +05302825 msm_otg_start_host(otg, 0);
Heikki Krogerus1d4c9292012-02-13 13:24:09 +02002826 msm_otg_reset(otg->phy);
Vijayavardhan Vennapusaa3152032012-03-05 16:29:30 +05302827 } else if (!test_bit(A_BUS_REQ, &motg->inputs)) {
2828 /*
2829 * a_bus_req is de-asserted when root hub is
2830 * suspended or HNP is in progress.
2831 */
2832 pr_debug("!a_bus_req\n");
2833 msm_otg_del_timer(motg);
Steve Mucklef132c6c2012-06-06 18:30:57 -07002834 otg->phy->state = OTG_STATE_A_SUSPEND;
Vijayavardhan Vennapusaa3152032012-03-05 16:29:30 +05302835 if (otg->host->b_hnp_enable)
2836 msm_otg_start_timer(motg, TA_AIDL_BDIS,
2837 A_AIDL_BDIS);
2838 else
Steve Mucklef132c6c2012-06-06 18:30:57 -07002839 pm_runtime_put_sync(otg->phy->dev);
Vijayavardhan Vennapusaa3152032012-03-05 16:29:30 +05302840 } else if (!test_bit(B_CONN, &motg->inputs)) {
2841 pr_debug("!b_conn\n");
2842 msm_otg_del_timer(motg);
Steve Mucklef132c6c2012-06-06 18:30:57 -07002843 otg->phy->state = OTG_STATE_A_WAIT_BCON;
Vijayavardhan Vennapusaa3152032012-03-05 16:29:30 +05302844 if (TA_WAIT_BCON > 0)
2845 msm_otg_start_timer(motg, TA_WAIT_BCON,
2846 A_WAIT_BCON);
2847 if (msm_chg_check_aca_intr(motg))
2848 work = 1;
2849 } else if (test_bit(ID_A, &motg->inputs)) {
2850 msm_otg_del_timer(motg);
2851 msm_hsusb_vbus_power(motg, 0);
2852 if (motg->chg_type == USB_ACA_DOCK_CHARGER)
2853 msm_otg_notify_charger(motg,
2854 IDEV_ACA_CHG_MAX);
2855 else
2856 msm_otg_notify_charger(motg,
2857 IDEV_CHG_MIN - motg->mA_port);
2858 } else if (!test_bit(ID, &motg->inputs)) {
2859 motg->chg_state = USB_CHG_STATE_UNDEFINED;
2860 motg->chg_type = USB_INVALID_CHARGER;
2861 msm_otg_notify_charger(motg, 0);
2862 msm_hsusb_vbus_power(motg, 1);
2863 }
2864 break;
2865 case OTG_STATE_A_SUSPEND:
2866 if ((test_bit(ID, &motg->inputs) &&
2867 !test_bit(ID_A, &motg->inputs)) ||
2868 test_bit(A_BUS_DROP, &motg->inputs) ||
2869 test_bit(A_AIDL_BDIS, &motg->tmouts)) {
2870 pr_debug("id_a/b/c || a_bus_drop ||"
2871 "a_aidl_bdis_tmout\n");
2872 msm_otg_del_timer(motg);
2873 clear_bit(B_CONN, &motg->inputs);
Steve Mucklef132c6c2012-06-06 18:30:57 -07002874 otg->phy->state = OTG_STATE_A_WAIT_VFALL;
Vijayavardhan Vennapusaa3152032012-03-05 16:29:30 +05302875 msm_otg_start_host(otg, 0);
Steve Mucklef132c6c2012-06-06 18:30:57 -07002876 msm_otg_reset(otg->phy);
Vijayavardhan Vennapusaa3152032012-03-05 16:29:30 +05302877 if (!test_bit(ID_A, &motg->inputs))
2878 msm_hsusb_vbus_power(motg, 0);
2879 msm_otg_start_timer(motg, TA_WAIT_VFALL, A_WAIT_VFALL);
2880 } else if (!test_bit(A_VBUS_VLD, &motg->inputs)) {
2881 pr_debug("!a_vbus_vld\n");
2882 msm_otg_del_timer(motg);
2883 clear_bit(B_CONN, &motg->inputs);
Steve Mucklef132c6c2012-06-06 18:30:57 -07002884 otg->phy->state = OTG_STATE_A_VBUS_ERR;
Vijayavardhan Vennapusaa3152032012-03-05 16:29:30 +05302885 msm_otg_start_host(otg, 0);
Steve Mucklef132c6c2012-06-06 18:30:57 -07002886 msm_otg_reset(otg->phy);
Vijayavardhan Vennapusaa3152032012-03-05 16:29:30 +05302887 } else if (!test_bit(B_CONN, &motg->inputs) &&
2888 otg->host->b_hnp_enable) {
2889 pr_debug("!b_conn && b_hnp_enable");
Steve Mucklef132c6c2012-06-06 18:30:57 -07002890 otg->phy->state = OTG_STATE_A_PERIPHERAL;
Vijayavardhan Vennapusaa3152032012-03-05 16:29:30 +05302891 msm_otg_host_hnp_enable(otg, 1);
2892 otg->gadget->is_a_peripheral = 1;
2893 msm_otg_start_peripheral(otg, 1);
2894 } else if (!test_bit(B_CONN, &motg->inputs) &&
2895 !otg->host->b_hnp_enable) {
2896 pr_debug("!b_conn && !b_hnp_enable");
2897 /*
2898 * bus request is dropped during suspend.
2899 * acquire again for next device.
2900 */
2901 set_bit(A_BUS_REQ, &motg->inputs);
Steve Mucklef132c6c2012-06-06 18:30:57 -07002902 otg->phy->state = OTG_STATE_A_WAIT_BCON;
Vijayavardhan Vennapusaa3152032012-03-05 16:29:30 +05302903 if (TA_WAIT_BCON > 0)
2904 msm_otg_start_timer(motg, TA_WAIT_BCON,
2905 A_WAIT_BCON);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002906 } else if (test_bit(ID_A, &motg->inputs)) {
Mayank Ranae3926882011-12-26 09:47:54 +05302907 msm_hsusb_vbus_power(motg, 0);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002908 msm_otg_notify_charger(motg,
Vijayavardhan Vennapusaa3152032012-03-05 16:29:30 +05302909 IDEV_CHG_MIN - motg->mA_port);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002910 } else if (!test_bit(ID, &motg->inputs)) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002911 msm_otg_notify_charger(motg, 0);
Mayank Ranae3926882011-12-26 09:47:54 +05302912 msm_hsusb_vbus_power(motg, 1);
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05302913 }
2914 break;
Vijayavardhan Vennapusaa3152032012-03-05 16:29:30 +05302915 case OTG_STATE_A_PERIPHERAL:
2916 if ((test_bit(ID, &motg->inputs) &&
2917 !test_bit(ID_A, &motg->inputs)) ||
2918 test_bit(A_BUS_DROP, &motg->inputs)) {
2919 pr_debug("id _f/b/c || a_bus_drop\n");
2920 /* Clear BIDL_ADIS timer */
2921 msm_otg_del_timer(motg);
Steve Mucklef132c6c2012-06-06 18:30:57 -07002922 otg->phy->state = OTG_STATE_A_WAIT_VFALL;
Vijayavardhan Vennapusaa3152032012-03-05 16:29:30 +05302923 msm_otg_start_peripheral(otg, 0);
2924 otg->gadget->is_a_peripheral = 0;
2925 msm_otg_start_host(otg, 0);
Steve Mucklef132c6c2012-06-06 18:30:57 -07002926 msm_otg_reset(otg->phy);
Vijayavardhan Vennapusaa3152032012-03-05 16:29:30 +05302927 if (!test_bit(ID_A, &motg->inputs))
2928 msm_hsusb_vbus_power(motg, 0);
2929 msm_otg_start_timer(motg, TA_WAIT_VFALL, A_WAIT_VFALL);
2930 } else if (!test_bit(A_VBUS_VLD, &motg->inputs)) {
2931 pr_debug("!a_vbus_vld\n");
2932 /* Clear BIDL_ADIS timer */
2933 msm_otg_del_timer(motg);
Steve Mucklef132c6c2012-06-06 18:30:57 -07002934 otg->phy->state = OTG_STATE_A_VBUS_ERR;
Vijayavardhan Vennapusaa3152032012-03-05 16:29:30 +05302935 msm_otg_start_peripheral(otg, 0);
2936 otg->gadget->is_a_peripheral = 0;
2937 msm_otg_start_host(otg, 0);
2938 } else if (test_bit(A_BIDL_ADIS, &motg->tmouts)) {
2939 pr_debug("a_bidl_adis_tmout\n");
2940 msm_otg_start_peripheral(otg, 0);
2941 otg->gadget->is_a_peripheral = 0;
Steve Mucklef132c6c2012-06-06 18:30:57 -07002942 otg->phy->state = OTG_STATE_A_WAIT_BCON;
Vijayavardhan Vennapusaa3152032012-03-05 16:29:30 +05302943 set_bit(A_BUS_REQ, &motg->inputs);
2944 msm_otg_host_hnp_enable(otg, 0);
2945 if (TA_WAIT_BCON > 0)
2946 msm_otg_start_timer(motg, TA_WAIT_BCON,
2947 A_WAIT_BCON);
2948 } else if (test_bit(ID_A, &motg->inputs)) {
2949 msm_hsusb_vbus_power(motg, 0);
2950 msm_otg_notify_charger(motg,
2951 IDEV_CHG_MIN - motg->mA_port);
2952 } else if (!test_bit(ID, &motg->inputs)) {
2953 msm_otg_notify_charger(motg, 0);
2954 msm_hsusb_vbus_power(motg, 1);
2955 }
2956 break;
2957 case OTG_STATE_A_WAIT_VFALL:
2958 if (test_bit(A_WAIT_VFALL, &motg->tmouts)) {
2959 clear_bit(A_VBUS_VLD, &motg->inputs);
Steve Mucklef132c6c2012-06-06 18:30:57 -07002960 otg->phy->state = OTG_STATE_A_IDLE;
Vijayavardhan Vennapusaa3152032012-03-05 16:29:30 +05302961 work = 1;
2962 }
2963 break;
2964 case OTG_STATE_A_VBUS_ERR:
2965 if ((test_bit(ID, &motg->inputs) &&
2966 !test_bit(ID_A, &motg->inputs)) ||
2967 test_bit(A_BUS_DROP, &motg->inputs) ||
2968 test_bit(A_CLR_ERR, &motg->inputs)) {
Steve Mucklef132c6c2012-06-06 18:30:57 -07002969 otg->phy->state = OTG_STATE_A_WAIT_VFALL;
Vijayavardhan Vennapusaa3152032012-03-05 16:29:30 +05302970 if (!test_bit(ID_A, &motg->inputs))
2971 msm_hsusb_vbus_power(motg, 0);
2972 msm_otg_start_timer(motg, TA_WAIT_VFALL, A_WAIT_VFALL);
2973 motg->chg_state = USB_CHG_STATE_UNDEFINED;
2974 motg->chg_type = USB_INVALID_CHARGER;
2975 msm_otg_notify_charger(motg, 0);
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05302976 }
2977 break;
2978 default:
2979 break;
2980 }
Vijayavardhan Vennapusaa3152032012-03-05 16:29:30 +05302981 if (work)
2982 queue_work(system_nrt_wq, &motg->sm_work);
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05302983}
2984
Amit Blayd0fe07b2012-09-05 16:42:09 +03002985static void msm_otg_suspend_work(struct work_struct *w)
2986{
2987 struct msm_otg *motg =
2988 container_of(w, struct msm_otg, suspend_work.work);
Pavankumar Kondetie618bf82012-11-28 21:12:44 +05302989
2990 /* This work is only for device bus suspend */
2991 if (test_bit(A_BUS_SUSPEND, &motg->inputs))
2992 msm_otg_sm_work(&motg->sm_work);
Amit Blayd0fe07b2012-09-05 16:42:09 +03002993}
2994
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05302995static irqreturn_t msm_otg_irq(int irq, void *data)
2996{
2997 struct msm_otg *motg = data;
Steve Mucklef132c6c2012-06-06 18:30:57 -07002998 struct usb_otg *otg = motg->phy.otg;
Vijayavardhan Vennapusaa3152032012-03-05 16:29:30 +05302999 u32 otgsc = 0, usbsts, pc;
3000 bool work = 0;
3001 irqreturn_t ret = IRQ_HANDLED;
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05303002
Pavankumar Kondeti87c01042010-12-07 17:53:58 +05303003 if (atomic_read(&motg->in_lpm)) {
Manu Gautamf8c45642012-08-10 10:20:56 -07003004 pr_debug("OTG IRQ: %d in LPM\n", irq);
Pavankumar Kondeti87c01042010-12-07 17:53:58 +05303005 disable_irq_nosync(irq);
Manu Gautamf8c45642012-08-10 10:20:56 -07003006 motg->async_int = irq;
Jack Phamc7edb172012-08-13 15:32:39 -07003007 if (!atomic_read(&motg->pm_suspended))
Steve Mucklef132c6c2012-06-06 18:30:57 -07003008 pm_request_resume(otg->phy->dev);
Pavankumar Kondeti87c01042010-12-07 17:53:58 +05303009 return IRQ_HANDLED;
3010 }
3011
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003012 usbsts = readl(USB_USBSTS);
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05303013 otgsc = readl(USB_OTGSC);
Vijayavardhan Vennapusaa3152032012-03-05 16:29:30 +05303014
3015 if (!(otgsc & OTG_OTGSTS_MASK) && !(usbsts & OTG_USBSTS_MASK))
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05303016 return IRQ_NONE;
3017
3018 if ((otgsc & OTGSC_IDIS) && (otgsc & OTGSC_IDIE)) {
Pavankumar Kondetiaa449e12011-11-04 11:09:26 +05303019 if (otgsc & OTGSC_ID) {
Stephen Boyd9850acb2013-01-28 14:11:20 -08003020 dev_dbg(otg->phy->dev, "ID set\n");
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05303021 set_bit(ID, &motg->inputs);
Pavankumar Kondetiaa449e12011-11-04 11:09:26 +05303022 } else {
Stephen Boyd9850acb2013-01-28 14:11:20 -08003023 dev_dbg(otg->phy->dev, "ID clear\n");
Vijayavardhan Vennapusaa3152032012-03-05 16:29:30 +05303024 /*
3025 * Assert a_bus_req to supply power on
3026 * VBUS when Micro/Mini-A cable is connected
3027 * with out user intervention.
3028 */
3029 set_bit(A_BUS_REQ, &motg->inputs);
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05303030 clear_bit(ID, &motg->inputs);
Pavankumar Kondetiaa449e12011-11-04 11:09:26 +05303031 msm_chg_enable_aca_det(motg);
3032 }
Vijayavardhan Vennapusaa3152032012-03-05 16:29:30 +05303033 writel_relaxed(otgsc, USB_OTGSC);
3034 work = 1;
3035 } else if (otgsc & OTGSC_DPIS) {
3036 pr_debug("DPIS detected\n");
3037 writel_relaxed(otgsc, USB_OTGSC);
3038 set_bit(A_SRP_DET, &motg->inputs);
3039 set_bit(A_BUS_REQ, &motg->inputs);
3040 work = 1;
Vamsi Krishnaef6e1bf2013-03-02 15:36:17 -08003041 } else if ((otgsc & OTGSC_BSVIE) && (otgsc & OTGSC_BSVIS)) {
Vijayavardhan Vennapusaa3152032012-03-05 16:29:30 +05303042 writel_relaxed(otgsc, USB_OTGSC);
3043 /*
3044 * BSV interrupt comes when operating as an A-device
3045 * (VBUS on/off).
3046 * But, handle BSV when charger is removed from ACA in ID_A
3047 */
Steve Mucklef132c6c2012-06-06 18:30:57 -07003048 if ((otg->phy->state >= OTG_STATE_A_IDLE) &&
Vijayavardhan Vennapusaa3152032012-03-05 16:29:30 +05303049 !test_bit(ID_A, &motg->inputs))
3050 return IRQ_HANDLED;
Pavankumar Kondetiaa449e12011-11-04 11:09:26 +05303051 if (otgsc & OTGSC_BSV) {
Stephen Boyd9850acb2013-01-28 14:11:20 -08003052 dev_dbg(otg->phy->dev, "BSV set\n");
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05303053 set_bit(B_SESS_VLD, &motg->inputs);
Pavankumar Kondetiaa449e12011-11-04 11:09:26 +05303054 } else {
Stephen Boyd9850acb2013-01-28 14:11:20 -08003055 dev_dbg(otg->phy->dev, "BSV clear\n");
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05303056 clear_bit(B_SESS_VLD, &motg->inputs);
Amit Blay6fa647a2012-05-24 14:12:08 +03003057 clear_bit(A_BUS_SUSPEND, &motg->inputs);
3058
Pavankumar Kondetiaa449e12011-11-04 11:09:26 +05303059 msm_chg_check_aca_intr(motg);
3060 }
Vijayavardhan Vennapusaa3152032012-03-05 16:29:30 +05303061 work = 1;
3062 } else if (usbsts & STS_PCI) {
3063 pc = readl_relaxed(USB_PORTSC);
3064 pr_debug("portsc = %x\n", pc);
3065 ret = IRQ_NONE;
3066 /*
3067 * HCD Acks PCI interrupt. We use this to switch
3068 * between different OTG states.
3069 */
3070 work = 1;
Steve Mucklef132c6c2012-06-06 18:30:57 -07003071 switch (otg->phy->state) {
Vijayavardhan Vennapusaa3152032012-03-05 16:29:30 +05303072 case OTG_STATE_A_SUSPEND:
3073 if (otg->host->b_hnp_enable && (pc & PORTSC_CSC) &&
3074 !(pc & PORTSC_CCS)) {
3075 pr_debug("B_CONN clear\n");
3076 clear_bit(B_CONN, &motg->inputs);
3077 msm_otg_del_timer(motg);
3078 }
3079 break;
3080 case OTG_STATE_A_PERIPHERAL:
3081 /*
3082 * A-peripheral observed activity on bus.
3083 * clear A_BIDL_ADIS timer.
3084 */
3085 msm_otg_del_timer(motg);
3086 work = 0;
3087 break;
3088 case OTG_STATE_B_WAIT_ACON:
3089 if ((pc & PORTSC_CSC) && (pc & PORTSC_CCS)) {
3090 pr_debug("A_CONN set\n");
3091 set_bit(A_CONN, &motg->inputs);
3092 /* Clear ASE0_BRST timer */
3093 msm_otg_del_timer(motg);
3094 }
3095 break;
3096 case OTG_STATE_B_HOST:
3097 if ((pc & PORTSC_CSC) && !(pc & PORTSC_CCS)) {
3098 pr_debug("A_CONN clear\n");
3099 clear_bit(A_CONN, &motg->inputs);
3100 msm_otg_del_timer(motg);
3101 }
3102 break;
3103 case OTG_STATE_A_WAIT_BCON:
3104 if (TA_WAIT_BCON < 0)
3105 set_bit(A_BUS_REQ, &motg->inputs);
3106 default:
3107 work = 0;
3108 break;
3109 }
3110 } else if (usbsts & STS_URI) {
3111 ret = IRQ_NONE;
Steve Mucklef132c6c2012-06-06 18:30:57 -07003112 switch (otg->phy->state) {
Vijayavardhan Vennapusaa3152032012-03-05 16:29:30 +05303113 case OTG_STATE_A_PERIPHERAL:
3114 /*
3115 * A-peripheral observed activity on bus.
3116 * clear A_BIDL_ADIS timer.
3117 */
3118 msm_otg_del_timer(motg);
3119 work = 0;
3120 break;
3121 default:
3122 work = 0;
3123 break;
3124 }
3125 } else if (usbsts & STS_SLI) {
3126 ret = IRQ_NONE;
3127 work = 0;
Steve Mucklef132c6c2012-06-06 18:30:57 -07003128 switch (otg->phy->state) {
Vijayavardhan Vennapusaa3152032012-03-05 16:29:30 +05303129 case OTG_STATE_B_PERIPHERAL:
3130 if (otg->gadget->b_hnp_enable) {
3131 set_bit(A_BUS_SUSPEND, &motg->inputs);
3132 set_bit(B_BUS_REQ, &motg->inputs);
3133 work = 1;
3134 }
3135 break;
3136 case OTG_STATE_A_PERIPHERAL:
3137 msm_otg_start_timer(motg, TA_BIDL_ADIS,
3138 A_BIDL_ADIS);
3139 break;
3140 default:
3141 break;
3142 }
3143 } else if ((usbsts & PHY_ALT_INT)) {
3144 writel_relaxed(PHY_ALT_INT, USB_USBSTS);
3145 if (msm_chg_check_aca_intr(motg))
3146 work = 1;
3147 ret = IRQ_HANDLED;
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05303148 }
Vijayavardhan Vennapusaa3152032012-03-05 16:29:30 +05303149 if (work)
3150 queue_work(system_nrt_wq, &motg->sm_work);
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05303151
Vijayavardhan Vennapusaa3152032012-03-05 16:29:30 +05303152 return ret;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003153}
3154
3155static void msm_otg_set_vbus_state(int online)
3156{
Pavankumar Kondeti4960f312011-12-06 15:46:14 +05303157 static bool init;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003158 struct msm_otg *motg = the_msm_otg;
Mayank Ranabaf31f42012-07-05 09:43:54 +05303159
Vamsi Krishna945b4a92013-03-02 15:31:16 -08003160 if (online) {
3161 pr_debug("PMIC: BSV set\n");
3162 set_bit(B_SESS_VLD, &motg->inputs);
3163 } else {
3164 pr_debug("PMIC: BSV clear\n");
3165 clear_bit(B_SESS_VLD, &motg->inputs);
3166 }
3167
3168 /* do not queue state m/c work if id is grounded */
Pavankumar Kondetibbaa46ff2012-12-09 20:21:02 +05303169 if (!test_bit(ID, &motg->inputs)) {
3170 /*
3171 * state machine work waits for initial VBUS
3172 * completion in UNDEFINED state. Process
3173 * the initial VBUS event in ID_GND state.
3174 */
3175 if (init)
3176 return;
Pavankumar Kondetibbaa46ff2012-12-09 20:21:02 +05303177 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003178
Pavankumar Kondeti4960f312011-12-06 15:46:14 +05303179 if (!init) {
3180 init = true;
3181 complete(&pmic_vbus_init);
3182 pr_debug("PMIC: BSV init complete\n");
3183 return;
3184 }
3185
Pavankumar Kondeti2aec9f32012-06-13 09:06:03 +05303186 if (test_bit(MHL, &motg->inputs) ||
3187 mhl_det_in_progress) {
3188 pr_debug("PMIC: BSV interrupt ignored in MHL\n");
3189 return;
3190 }
3191
Jack Pham5ca279b2012-05-14 18:42:54 -07003192 if (atomic_read(&motg->pm_suspended))
3193 motg->sm_work_pending = true;
3194 else
3195 queue_work(system_nrt_wq, &motg->sm_work);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003196}
3197
Vijayavardhan Vennapusa68d55cf2012-06-27 20:06:12 +05303198static void msm_pmic_id_status_w(struct work_struct *w)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003199{
Vijayavardhan Vennapusa68d55cf2012-06-27 20:06:12 +05303200 struct msm_otg *motg = container_of(w, struct msm_otg,
3201 pmic_id_status_work.work);
3202 int work = 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003203
Pavankumar Kondetibecab5b2012-11-06 16:45:10 +05303204 if (msm_otg_read_pmic_id_state(motg)) {
Vijayavardhan Vennapusa68d55cf2012-06-27 20:06:12 +05303205 if (!test_and_set_bit(ID, &motg->inputs)) {
3206 pr_debug("PMIC: ID set\n");
3207 work = 1;
3208 }
Pavankumar Kondeti4960f312011-12-06 15:46:14 +05303209 } else {
Vijayavardhan Vennapusa68d55cf2012-06-27 20:06:12 +05303210 if (test_and_clear_bit(ID, &motg->inputs)) {
3211 pr_debug("PMIC: ID clear\n");
3212 set_bit(A_BUS_REQ, &motg->inputs);
3213 work = 1;
3214 }
Pavankumar Kondeti4960f312011-12-06 15:46:14 +05303215 }
3216
Vijayavardhan Vennapusa68d55cf2012-06-27 20:06:12 +05303217 if (work && (motg->phy.state != OTG_STATE_UNDEFINED)) {
Jack Pham5ca279b2012-05-14 18:42:54 -07003218 if (atomic_read(&motg->pm_suspended))
3219 motg->sm_work_pending = true;
3220 else
3221 queue_work(system_nrt_wq, &motg->sm_work);
3222 }
Vijayavardhan Vennapusa68d55cf2012-06-27 20:06:12 +05303223
3224}
3225
3226#define MSM_PMIC_ID_STATUS_DELAY 5 /* 5msec */
3227static irqreturn_t msm_pmic_id_irq(int irq, void *data)
3228{
3229 struct msm_otg *motg = data;
3230
Pavankumar Kondeti2aec9f32012-06-13 09:06:03 +05303231 if (test_bit(MHL, &motg->inputs) ||
3232 mhl_det_in_progress) {
3233 pr_debug("PMIC: Id interrupt ignored in MHL\n");
3234 return IRQ_HANDLED;
3235 }
3236
Vijayavardhan Vennapusa68d55cf2012-06-27 20:06:12 +05303237 if (!aca_id_turned_on)
3238 /*schedule delayed work for 5msec for ID line state to settle*/
3239 queue_delayed_work(system_nrt_wq, &motg->pmic_id_status_work,
3240 msecs_to_jiffies(MSM_PMIC_ID_STATUS_DELAY));
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003241
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05303242 return IRQ_HANDLED;
3243}
3244
3245static int msm_otg_mode_show(struct seq_file *s, void *unused)
3246{
3247 struct msm_otg *motg = s->private;
Stephen Boyd9850acb2013-01-28 14:11:20 -08003248 struct usb_otg *otg = motg->phy.otg;
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05303249
Stephen Boyd9850acb2013-01-28 14:11:20 -08003250 switch (otg->phy->state) {
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05303251 case OTG_STATE_A_HOST:
3252 seq_printf(s, "host\n");
3253 break;
3254 case OTG_STATE_B_PERIPHERAL:
3255 seq_printf(s, "peripheral\n");
3256 break;
3257 default:
3258 seq_printf(s, "none\n");
3259 break;
3260 }
3261
3262 return 0;
3263}
3264
3265static int msm_otg_mode_open(struct inode *inode, struct file *file)
3266{
3267 return single_open(file, msm_otg_mode_show, inode->i_private);
3268}
3269
3270static ssize_t msm_otg_mode_write(struct file *file, const char __user *ubuf,
3271 size_t count, loff_t *ppos)
3272{
Pavankumar Kondetie2904ee2011-02-15 09:42:35 +05303273 struct seq_file *s = file->private_data;
3274 struct msm_otg *motg = s->private;
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05303275 char buf[16];
Steve Mucklef132c6c2012-06-06 18:30:57 -07003276 struct usb_phy *phy = &motg->phy;
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05303277 int status = count;
3278 enum usb_mode_type req_mode;
3279
3280 memset(buf, 0x00, sizeof(buf));
3281
3282 if (copy_from_user(&buf, ubuf, min_t(size_t, sizeof(buf) - 1, count))) {
3283 status = -EFAULT;
3284 goto out;
3285 }
3286
3287 if (!strncmp(buf, "host", 4)) {
3288 req_mode = USB_HOST;
3289 } else if (!strncmp(buf, "peripheral", 10)) {
3290 req_mode = USB_PERIPHERAL;
3291 } else if (!strncmp(buf, "none", 4)) {
3292 req_mode = USB_NONE;
3293 } else {
3294 status = -EINVAL;
3295 goto out;
3296 }
3297
3298 switch (req_mode) {
3299 case USB_NONE:
Steve Mucklef132c6c2012-06-06 18:30:57 -07003300 switch (phy->state) {
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05303301 case OTG_STATE_A_HOST:
3302 case OTG_STATE_B_PERIPHERAL:
3303 set_bit(ID, &motg->inputs);
3304 clear_bit(B_SESS_VLD, &motg->inputs);
3305 break;
3306 default:
3307 goto out;
3308 }
3309 break;
3310 case USB_PERIPHERAL:
Steve Mucklef132c6c2012-06-06 18:30:57 -07003311 switch (phy->state) {
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05303312 case OTG_STATE_B_IDLE:
3313 case OTG_STATE_A_HOST:
3314 set_bit(ID, &motg->inputs);
3315 set_bit(B_SESS_VLD, &motg->inputs);
3316 break;
3317 default:
3318 goto out;
3319 }
3320 break;
3321 case USB_HOST:
Steve Mucklef132c6c2012-06-06 18:30:57 -07003322 switch (phy->state) {
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05303323 case OTG_STATE_B_IDLE:
3324 case OTG_STATE_B_PERIPHERAL:
3325 clear_bit(ID, &motg->inputs);
3326 break;
3327 default:
3328 goto out;
3329 }
3330 break;
3331 default:
3332 goto out;
3333 }
3334
Steve Mucklef132c6c2012-06-06 18:30:57 -07003335 pm_runtime_resume(phy->dev);
Vijayavardhan Vennapusaa3152032012-03-05 16:29:30 +05303336 queue_work(system_nrt_wq, &motg->sm_work);
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05303337out:
3338 return status;
3339}
3340
3341const struct file_operations msm_otg_mode_fops = {
3342 .open = msm_otg_mode_open,
3343 .read = seq_read,
3344 .write = msm_otg_mode_write,
3345 .llseek = seq_lseek,
3346 .release = single_release,
3347};
3348
Chiranjeevi Velempatif9a11542012-03-28 18:18:34 +05303349static int msm_otg_show_otg_state(struct seq_file *s, void *unused)
3350{
3351 struct msm_otg *motg = s->private;
Steve Mucklef132c6c2012-06-06 18:30:57 -07003352 struct usb_phy *phy = &motg->phy;
Chiranjeevi Velempatif9a11542012-03-28 18:18:34 +05303353
Steve Mucklef132c6c2012-06-06 18:30:57 -07003354 seq_printf(s, "%s\n", otg_state_string(phy->state));
Chiranjeevi Velempatif9a11542012-03-28 18:18:34 +05303355 return 0;
3356}
3357
3358static int msm_otg_otg_state_open(struct inode *inode, struct file *file)
3359{
3360 return single_open(file, msm_otg_show_otg_state, inode->i_private);
3361}
3362
3363const struct file_operations msm_otg_state_fops = {
3364 .open = msm_otg_otg_state_open,
3365 .read = seq_read,
3366 .llseek = seq_lseek,
3367 .release = single_release,
3368};
3369
Anji jonnalad270e2d2011-08-09 11:28:32 +05303370static int msm_otg_show_chg_type(struct seq_file *s, void *unused)
3371{
3372 struct msm_otg *motg = s->private;
3373
Pavankumar Kondeti9ef69cb2011-12-12 14:18:22 +05303374 seq_printf(s, "%s\n", chg_to_string(motg->chg_type));
Anji jonnalad270e2d2011-08-09 11:28:32 +05303375 return 0;
3376}
3377
3378static int msm_otg_chg_open(struct inode *inode, struct file *file)
3379{
3380 return single_open(file, msm_otg_show_chg_type, inode->i_private);
3381}
3382
3383const struct file_operations msm_otg_chg_fops = {
3384 .open = msm_otg_chg_open,
3385 .read = seq_read,
3386 .llseek = seq_lseek,
3387 .release = single_release,
3388};
3389
Pavankumar Kondetiaa449e12011-11-04 11:09:26 +05303390static int msm_otg_aca_show(struct seq_file *s, void *unused)
3391{
3392 if (debug_aca_enabled)
3393 seq_printf(s, "enabled\n");
3394 else
3395 seq_printf(s, "disabled\n");
3396
3397 return 0;
3398}
3399
3400static int msm_otg_aca_open(struct inode *inode, struct file *file)
3401{
3402 return single_open(file, msm_otg_aca_show, inode->i_private);
3403}
3404
3405static ssize_t msm_otg_aca_write(struct file *file, const char __user *ubuf,
3406 size_t count, loff_t *ppos)
3407{
3408 char buf[8];
3409
3410 memset(buf, 0x00, sizeof(buf));
3411
3412 if (copy_from_user(&buf, ubuf, min_t(size_t, sizeof(buf) - 1, count)))
3413 return -EFAULT;
3414
3415 if (!strncmp(buf, "enable", 6))
3416 debug_aca_enabled = true;
3417 else
3418 debug_aca_enabled = false;
3419
3420 return count;
3421}
3422
3423const struct file_operations msm_otg_aca_fops = {
3424 .open = msm_otg_aca_open,
3425 .read = seq_read,
3426 .write = msm_otg_aca_write,
3427 .llseek = seq_lseek,
3428 .release = single_release,
3429};
3430
Manu Gautam8bdcc592012-03-06 11:26:06 +05303431static int msm_otg_bus_show(struct seq_file *s, void *unused)
3432{
3433 if (debug_bus_voting_enabled)
3434 seq_printf(s, "enabled\n");
3435 else
3436 seq_printf(s, "disabled\n");
3437
3438 return 0;
3439}
3440
3441static int msm_otg_bus_open(struct inode *inode, struct file *file)
3442{
3443 return single_open(file, msm_otg_bus_show, inode->i_private);
3444}
3445
3446static ssize_t msm_otg_bus_write(struct file *file, const char __user *ubuf,
3447 size_t count, loff_t *ppos)
3448{
3449 char buf[8];
3450 int ret;
3451 struct seq_file *s = file->private_data;
3452 struct msm_otg *motg = s->private;
3453
3454 memset(buf, 0x00, sizeof(buf));
3455
3456 if (copy_from_user(&buf, ubuf, min_t(size_t, sizeof(buf) - 1, count)))
3457 return -EFAULT;
3458
3459 if (!strncmp(buf, "enable", 6)) {
3460 /* Do not vote here. Let OTG statemachine decide when to vote */
3461 debug_bus_voting_enabled = true;
3462 } else {
3463 debug_bus_voting_enabled = false;
3464 if (motg->bus_perf_client) {
3465 ret = msm_bus_scale_client_update_request(
3466 motg->bus_perf_client, 0);
3467 if (ret)
Steve Mucklef132c6c2012-06-06 18:30:57 -07003468 dev_err(motg->phy.dev, "%s: Failed to devote "
Manu Gautam8bdcc592012-03-06 11:26:06 +05303469 "for bus bw %d\n", __func__, ret);
3470 }
3471 }
3472
3473 return count;
3474}
3475
David Keitel272ce522012-08-17 16:25:24 -07003476static int otg_power_get_property_usb(struct power_supply *psy,
3477 enum power_supply_property psp,
3478 union power_supply_propval *val)
3479{
Jack Pham0c695282012-10-19 18:13:03 -07003480 struct msm_otg *motg = container_of(psy, struct msm_otg, usb_psy);
David Keitel272ce522012-08-17 16:25:24 -07003481 switch (psp) {
3482 case POWER_SUPPLY_PROP_SCOPE:
3483 if (motg->host_mode)
3484 val->intval = POWER_SUPPLY_SCOPE_SYSTEM;
3485 else
3486 val->intval = POWER_SUPPLY_SCOPE_DEVICE;
3487 break;
3488 case POWER_SUPPLY_PROP_CURRENT_MAX:
3489 val->intval = motg->current_max;
3490 break;
3491 /* Reflect USB enumeration */
3492 case POWER_SUPPLY_PROP_PRESENT:
3493 case POWER_SUPPLY_PROP_ONLINE:
3494 val->intval = motg->online;
3495 break;
3496 default:
3497 return -EINVAL;
3498 }
3499 return 0;
3500}
3501
3502static int otg_power_set_property_usb(struct power_supply *psy,
3503 enum power_supply_property psp,
3504 const union power_supply_propval *val)
3505{
Jack Pham0c695282012-10-19 18:13:03 -07003506 struct msm_otg *motg = container_of(psy, struct msm_otg, usb_psy);
David Keitel272ce522012-08-17 16:25:24 -07003507
3508 switch (psp) {
3509 /* Process PMIC notification in PRESENT prop */
3510 case POWER_SUPPLY_PROP_PRESENT:
3511 msm_otg_set_vbus_state(val->intval);
3512 break;
3513 /* The ONLINE property reflects if usb has enumerated */
3514 case POWER_SUPPLY_PROP_ONLINE:
3515 motg->online = val->intval;
3516 break;
3517 case POWER_SUPPLY_PROP_CURRENT_MAX:
3518 motg->current_max = val->intval;
3519 break;
3520 default:
3521 return -EINVAL;
3522 }
3523
3524 power_supply_changed(&motg->usb_psy);
3525 return 0;
3526}
3527
David Collinsd79acc52012-11-26 14:59:00 -08003528static int otg_power_property_is_writeable_usb(struct power_supply *psy,
3529 enum power_supply_property psp)
3530{
3531 switch (psp) {
3532 case POWER_SUPPLY_PROP_PRESENT:
3533 case POWER_SUPPLY_PROP_ONLINE:
3534 case POWER_SUPPLY_PROP_CURRENT_MAX:
3535 return 1;
3536 default:
3537 break;
3538 }
3539
3540 return 0;
3541}
3542
David Keitel272ce522012-08-17 16:25:24 -07003543static char *otg_pm_power_supplied_to[] = {
3544 "battery",
3545};
3546
3547static enum power_supply_property otg_pm_power_props_usb[] = {
3548 POWER_SUPPLY_PROP_PRESENT,
3549 POWER_SUPPLY_PROP_ONLINE,
3550 POWER_SUPPLY_PROP_CURRENT_MAX,
3551 POWER_SUPPLY_PROP_SCOPE,
3552};
3553
Manu Gautam8bdcc592012-03-06 11:26:06 +05303554const struct file_operations msm_otg_bus_fops = {
3555 .open = msm_otg_bus_open,
3556 .read = seq_read,
3557 .write = msm_otg_bus_write,
3558 .llseek = seq_lseek,
3559 .release = single_release,
3560};
3561
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05303562static struct dentry *msm_otg_dbg_root;
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05303563
3564static int msm_otg_debugfs_init(struct msm_otg *motg)
3565{
Manu Gautam8bdcc592012-03-06 11:26:06 +05303566 struct dentry *msm_otg_dentry;
Anji jonnalad270e2d2011-08-09 11:28:32 +05303567
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05303568 msm_otg_dbg_root = debugfs_create_dir("msm_otg", NULL);
3569
3570 if (!msm_otg_dbg_root || IS_ERR(msm_otg_dbg_root))
3571 return -ENODEV;
3572
Anji jonnalad270e2d2011-08-09 11:28:32 +05303573 if (motg->pdata->mode == USB_OTG &&
3574 motg->pdata->otg_control == OTG_USER_CONTROL) {
3575
Manu Gautam8bdcc592012-03-06 11:26:06 +05303576 msm_otg_dentry = debugfs_create_file("mode", S_IRUGO |
Anji jonnalad270e2d2011-08-09 11:28:32 +05303577 S_IWUSR, msm_otg_dbg_root, motg,
3578 &msm_otg_mode_fops);
3579
Manu Gautam8bdcc592012-03-06 11:26:06 +05303580 if (!msm_otg_dentry) {
Anji jonnalad270e2d2011-08-09 11:28:32 +05303581 debugfs_remove(msm_otg_dbg_root);
3582 msm_otg_dbg_root = NULL;
3583 return -ENODEV;
3584 }
3585 }
3586
Manu Gautam8bdcc592012-03-06 11:26:06 +05303587 msm_otg_dentry = debugfs_create_file("chg_type", S_IRUGO,
Anji jonnalad270e2d2011-08-09 11:28:32 +05303588 msm_otg_dbg_root, motg,
3589 &msm_otg_chg_fops);
3590
Manu Gautam8bdcc592012-03-06 11:26:06 +05303591 if (!msm_otg_dentry) {
Pavankumar Kondetiaa449e12011-11-04 11:09:26 +05303592 debugfs_remove_recursive(msm_otg_dbg_root);
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05303593 return -ENODEV;
3594 }
3595
Manu Gautam8bdcc592012-03-06 11:26:06 +05303596 msm_otg_dentry = debugfs_create_file("aca", S_IRUGO | S_IWUSR,
Pavankumar Kondetiaa449e12011-11-04 11:09:26 +05303597 msm_otg_dbg_root, motg,
3598 &msm_otg_aca_fops);
3599
Manu Gautam8bdcc592012-03-06 11:26:06 +05303600 if (!msm_otg_dentry) {
Pavankumar Kondetiaa449e12011-11-04 11:09:26 +05303601 debugfs_remove_recursive(msm_otg_dbg_root);
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05303602 return -ENODEV;
3603 }
3604
Manu Gautam8bdcc592012-03-06 11:26:06 +05303605 msm_otg_dentry = debugfs_create_file("bus_voting", S_IRUGO | S_IWUSR,
3606 msm_otg_dbg_root, motg,
3607 &msm_otg_bus_fops);
3608
3609 if (!msm_otg_dentry) {
3610 debugfs_remove_recursive(msm_otg_dbg_root);
3611 return -ENODEV;
3612 }
Chiranjeevi Velempatif9a11542012-03-28 18:18:34 +05303613
3614 msm_otg_dentry = debugfs_create_file("otg_state", S_IRUGO,
3615 msm_otg_dbg_root, motg, &msm_otg_state_fops);
3616
3617 if (!msm_otg_dentry) {
3618 debugfs_remove_recursive(msm_otg_dbg_root);
3619 return -ENODEV;
3620 }
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05303621 return 0;
3622}
3623
3624static void msm_otg_debugfs_cleanup(void)
3625{
Anji jonnalad270e2d2011-08-09 11:28:32 +05303626 debugfs_remove_recursive(msm_otg_dbg_root);
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05303627}
3628
Manu Gautam0ddbd922012-09-21 17:17:38 +05303629#define MSM_OTG_CMD_ID 0x09
3630#define MSM_OTG_DEVICE_ID 0x04
3631#define MSM_OTG_VMID_IDX 0xFF
3632#define MSM_OTG_MEM_TYPE 0x02
3633struct msm_otg_scm_cmd_buf {
3634 unsigned int device_id;
3635 unsigned int vmid_idx;
3636 unsigned int mem_type;
3637} __attribute__ ((__packed__));
3638
3639static void msm_otg_pnoc_errata_fix(struct msm_otg *motg)
3640{
3641 int ret;
3642 struct msm_otg_platform_data *pdata = motg->pdata;
3643 struct msm_otg_scm_cmd_buf cmd_buf;
3644
3645 if (!pdata->pnoc_errata_fix)
3646 return;
3647
3648 dev_dbg(motg->phy.dev, "applying fix for pnoc h/w issue\n");
3649
3650 cmd_buf.device_id = MSM_OTG_DEVICE_ID;
3651 cmd_buf.vmid_idx = MSM_OTG_VMID_IDX;
3652 cmd_buf.mem_type = MSM_OTG_MEM_TYPE;
3653
Syed Rameez Mustafa6ab6af32013-03-18 12:53:11 -07003654 ret = scm_call(SCM_SVC_MP, MSM_OTG_CMD_ID, &cmd_buf,
Manu Gautam0ddbd922012-09-21 17:17:38 +05303655 sizeof(cmd_buf), NULL, 0);
3656
3657 if (ret)
3658 dev_err(motg->phy.dev, "scm command failed to update VMIDMT\n");
3659}
3660
Pavankumar Kondetieaea7fe2011-10-27 14:46:45 +05303661static u64 msm_otg_dma_mask = DMA_BIT_MASK(64);
3662static struct platform_device *msm_otg_add_pdev(
3663 struct platform_device *ofdev, const char *name)
3664{
3665 struct platform_device *pdev;
3666 const struct resource *res = ofdev->resource;
3667 unsigned int num = ofdev->num_resources;
3668 int retval;
3669
3670 pdev = platform_device_alloc(name, -1);
3671 if (!pdev) {
3672 retval = -ENOMEM;
3673 goto error;
3674 }
3675
3676 pdev->dev.coherent_dma_mask = DMA_BIT_MASK(32);
3677 pdev->dev.dma_mask = &msm_otg_dma_mask;
3678
3679 if (num) {
3680 retval = platform_device_add_resources(pdev, res, num);
3681 if (retval)
3682 goto error;
3683 }
3684
3685 retval = platform_device_add(pdev);
3686 if (retval)
3687 goto error;
3688
3689 return pdev;
3690
3691error:
3692 platform_device_put(pdev);
3693 return ERR_PTR(retval);
3694}
3695
3696static int msm_otg_setup_devices(struct platform_device *ofdev,
3697 enum usb_mode_type mode, bool init)
3698{
3699 const char *gadget_name = "msm_hsusb";
3700 const char *host_name = "msm_hsusb_host";
3701 static struct platform_device *gadget_pdev;
3702 static struct platform_device *host_pdev;
3703 int retval = 0;
3704
3705 if (!init) {
3706 if (gadget_pdev)
3707 platform_device_unregister(gadget_pdev);
3708 if (host_pdev)
3709 platform_device_unregister(host_pdev);
3710 return 0;
3711 }
3712
3713 switch (mode) {
3714 case USB_OTG:
3715 /* fall through */
3716 case USB_PERIPHERAL:
3717 gadget_pdev = msm_otg_add_pdev(ofdev, gadget_name);
3718 if (IS_ERR(gadget_pdev)) {
3719 retval = PTR_ERR(gadget_pdev);
3720 break;
3721 }
3722 if (mode == USB_PERIPHERAL)
3723 break;
3724 /* fall through */
3725 case USB_HOST:
3726 host_pdev = msm_otg_add_pdev(ofdev, host_name);
3727 if (IS_ERR(host_pdev)) {
3728 retval = PTR_ERR(host_pdev);
3729 if (mode == USB_OTG)
3730 platform_device_unregister(gadget_pdev);
3731 }
3732 break;
3733 default:
3734 break;
3735 }
3736
3737 return retval;
3738}
3739
David Keitel272ce522012-08-17 16:25:24 -07003740static int msm_otg_register_power_supply(struct platform_device *pdev,
3741 struct msm_otg *motg)
3742{
3743 int ret;
3744
3745 ret = power_supply_register(&pdev->dev, &motg->usb_psy);
3746 if (ret < 0) {
3747 dev_err(motg->phy.dev,
3748 "%s:power_supply_register usb failed\n",
3749 __func__);
3750 return ret;
3751 }
3752
3753 legacy_power_supply = false;
3754 return 0;
3755}
3756
Pavankumar Kondetieaea7fe2011-10-27 14:46:45 +05303757struct msm_otg_platform_data *msm_otg_dt_to_pdata(struct platform_device *pdev)
3758{
3759 struct device_node *node = pdev->dev.of_node;
3760 struct msm_otg_platform_data *pdata;
3761 int len = 0;
3762
3763 pdata = devm_kzalloc(&pdev->dev, sizeof(*pdata), GFP_KERNEL);
3764 if (!pdata) {
3765 pr_err("unable to allocate platform data\n");
3766 return NULL;
3767 }
3768 of_get_property(node, "qcom,hsusb-otg-phy-init-seq", &len);
3769 if (len) {
3770 pdata->phy_init_seq = devm_kzalloc(&pdev->dev, len, GFP_KERNEL);
3771 if (!pdata->phy_init_seq)
3772 return NULL;
3773 of_property_read_u32_array(node, "qcom,hsusb-otg-phy-init-seq",
3774 pdata->phy_init_seq,
3775 len/sizeof(*pdata->phy_init_seq));
3776 }
3777 of_property_read_u32(node, "qcom,hsusb-otg-power-budget",
3778 &pdata->power_budget);
3779 of_property_read_u32(node, "qcom,hsusb-otg-mode",
3780 &pdata->mode);
3781 of_property_read_u32(node, "qcom,hsusb-otg-otg-control",
3782 &pdata->otg_control);
3783 of_property_read_u32(node, "qcom,hsusb-otg-default-mode",
3784 &pdata->default_mode);
3785 of_property_read_u32(node, "qcom,hsusb-otg-phy-type",
3786 &pdata->phy_type);
Manu Gautambd53fba2012-07-31 16:13:06 +05303787 pdata->disable_reset_on_disconnect = of_property_read_bool(node,
3788 "qcom,hsusb-otg-disable-reset");
Manu Gautam0ddbd922012-09-21 17:17:38 +05303789 pdata->pnoc_errata_fix = of_property_read_bool(node,
3790 "qcom,hsusb-otg-pnoc-errata-fix");
Ido Shayevitza7114b92013-01-13 13:34:47 +02003791 pdata->enable_lpm_on_dev_suspend = of_property_read_bool(node,
3792 "qcom,hsusb-otg-lpm-on-dev-suspend");
Ido Shayevitz26193352013-01-21 23:16:54 +02003793 pdata->core_clk_always_on_workaround = of_property_read_bool(node,
3794 "qcom,hsusb-otg-clk-always-on-workaround");
Shimrit Malichiffab5b02013-03-10 11:06:16 +02003795 pdata->delay_lpm_on_disconnect = of_property_read_bool(node,
3796 "qcom,hsusb-otg-delay-lpm");
Vamsi Krishna1a1684b2013-03-02 16:14:52 -08003797 pdata->dp_manual_pullup = of_property_read_bool(node,
3798 "qcom,dp-manual-pullup");
Manu Gautambd53fba2012-07-31 16:13:06 +05303799
Manu Gautam0e0c53f2013-04-04 10:55:20 +05303800 pdata->pmic_id_irq = platform_get_irq_byname(pdev, "pmic_id_irq");
3801 if (pdata->pmic_id_irq < 0)
3802 pdata->pmic_id_irq = 0;
3803
Pavankumar Kondetieaea7fe2011-10-27 14:46:45 +05303804 return pdata;
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05303805}
3806
3807static int __init msm_otg_probe(struct platform_device *pdev)
3808{
Manu Gautamf8c45642012-08-10 10:20:56 -07003809 int ret = 0;
Mayank Rana0f286cf2013-02-27 11:43:27 +05303810 int len = 0;
3811 u32 tmp[3];
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05303812 struct resource *res;
3813 struct msm_otg *motg;
Heikki Krogerus1d4c9292012-02-13 13:24:09 +02003814 struct usb_phy *phy;
Pavankumar Kondetieaea7fe2011-10-27 14:46:45 +05303815 struct msm_otg_platform_data *pdata;
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05303816
3817 dev_info(&pdev->dev, "msm_otg probe\n");
Pavankumar Kondetieaea7fe2011-10-27 14:46:45 +05303818
3819 if (pdev->dev.of_node) {
3820 dev_dbg(&pdev->dev, "device tree enabled\n");
3821 pdata = msm_otg_dt_to_pdata(pdev);
3822 if (!pdata)
3823 return -ENOMEM;
Manu Gautam2e8ac102012-08-31 11:41:16 -07003824
3825 pdata->bus_scale_table = msm_bus_cl_get_pdata(pdev);
3826 if (!pdata->bus_scale_table)
3827 dev_dbg(&pdev->dev, "bus scaling is disabled\n");
3828
Pavankumar Kondetieaea7fe2011-10-27 14:46:45 +05303829 ret = msm_otg_setup_devices(pdev, pdata->mode, true);
3830 if (ret) {
3831 dev_err(&pdev->dev, "devices setup failed\n");
3832 return ret;
3833 }
3834 } else if (!pdev->dev.platform_data) {
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05303835 dev_err(&pdev->dev, "No platform data given. Bailing out\n");
3836 return -ENODEV;
Pavankumar Kondetieaea7fe2011-10-27 14:46:45 +05303837 } else {
3838 pdata = pdev->dev.platform_data;
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05303839 }
3840
3841 motg = kzalloc(sizeof(struct msm_otg), GFP_KERNEL);
3842 if (!motg) {
3843 dev_err(&pdev->dev, "unable to allocate msm_otg\n");
3844 return -ENOMEM;
3845 }
3846
Heikki Krogerus1d4c9292012-02-13 13:24:09 +02003847 motg->phy.otg = kzalloc(sizeof(struct usb_otg), GFP_KERNEL);
3848 if (!motg->phy.otg) {
Steve Mucklef132c6c2012-06-06 18:30:57 -07003849 dev_err(&pdev->dev, "unable to allocate usb_otg\n");
3850 ret = -ENOMEM;
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05303851 goto free_motg;
3852 }
3853
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003854 the_msm_otg = motg;
Pavankumar Kondetieaea7fe2011-10-27 14:46:45 +05303855 motg->pdata = pdata;
Steve Mucklef132c6c2012-06-06 18:30:57 -07003856 phy = &motg->phy;
3857 phy->dev = &pdev->dev;
Anji jonnala0f73cac2011-05-04 10:19:46 +05303858
3859 /*
Pavankumar Kondetiaa449e12011-11-04 11:09:26 +05303860 * ACA ID_GND threshold range is overlapped with OTG ID_FLOAT. Hence
3861 * PHY treat ACA ID_GND as float and no interrupt is generated. But
3862 * PMIC can detect ACA ID_GND and generate an interrupt.
3863 */
3864 if (aca_enabled() && motg->pdata->otg_control != OTG_PMIC_CONTROL) {
3865 dev_err(&pdev->dev, "ACA can not be enabled without PMIC\n");
3866 ret = -EINVAL;
Steve Mucklef132c6c2012-06-06 18:30:57 -07003867 goto free_otg;
Pavankumar Kondetiaa449e12011-11-04 11:09:26 +05303868 }
3869
Ofir Cohen4da266f2012-01-03 10:19:29 +02003870 /* initialize reset counter */
3871 motg->reset_counter = 0;
3872
Amit Blay02eff132011-09-21 16:46:24 +03003873 /* Some targets don't support PHY clock. */
Manu Gautam5143b252012-01-05 19:25:23 -08003874 motg->phy_reset_clk = clk_get(&pdev->dev, "phy_clk");
Amit Blay02eff132011-09-21 16:46:24 +03003875 if (IS_ERR(motg->phy_reset_clk))
Manu Gautam5143b252012-01-05 19:25:23 -08003876 dev_err(&pdev->dev, "failed to get phy_clk\n");
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05303877
Pavankumar Kondeti923262e2012-04-20 15:34:24 +05303878 /*
3879 * Targets on which link uses asynchronous reset methodology,
3880 * free running clock is not required during the reset.
3881 */
Manu Gautam5143b252012-01-05 19:25:23 -08003882 motg->clk = clk_get(&pdev->dev, "alt_core_clk");
Pavankumar Kondeti923262e2012-04-20 15:34:24 +05303883 if (IS_ERR(motg->clk))
3884 dev_dbg(&pdev->dev, "alt_core_clk is not present\n");
3885 else
3886 clk_set_rate(motg->clk, 60000000);
Anji jonnala0f73cac2011-05-04 10:19:46 +05303887
3888 /*
Manu Gautam5143b252012-01-05 19:25:23 -08003889 * USB Core is running its protocol engine based on CORE CLK,
Anji jonnala0f73cac2011-05-04 10:19:46 +05303890 * CORE CLK must be running at >55Mhz for correct HSUSB
3891 * operation and USB core cannot tolerate frequency changes on
3892 * CORE CLK. For such USB cores, vote for maximum clk frequency
3893 * on pclk source
3894 */
Manu Gautam5143b252012-01-05 19:25:23 -08003895 motg->core_clk = clk_get(&pdev->dev, "core_clk");
3896 if (IS_ERR(motg->core_clk)) {
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05303897 motg->core_clk = NULL;
Manu Gautam5143b252012-01-05 19:25:23 -08003898 dev_err(&pdev->dev, "failed to get core_clk\n");
Pavankumar Kondetibc541332012-04-20 15:32:04 +05303899 ret = PTR_ERR(motg->core_clk);
Manu Gautam5143b252012-01-05 19:25:23 -08003900 goto put_clk;
3901 }
Mayank Rana3eaf28d2013-03-27 14:04:04 +05303902
3903 /*
3904 * Get Max supported clk frequency for USB Core CLK and request
3905 * to set the same.
3906 */
3907 motg->core_clk_rate = clk_round_rate(motg->core_clk, LONG_MAX);
3908 if (IS_ERR_VALUE(motg->core_clk_rate)) {
3909 dev_err(&pdev->dev, "fail to get core clk max freq.\n");
3910 } else {
3911 ret = clk_set_rate(motg->core_clk, motg->core_clk_rate);
3912 if (ret)
3913 dev_err(&pdev->dev, "fail to set core_clk freq:%d\n",
3914 ret);
3915 }
Manu Gautam5143b252012-01-05 19:25:23 -08003916
3917 motg->pclk = clk_get(&pdev->dev, "iface_clk");
3918 if (IS_ERR(motg->pclk)) {
3919 dev_err(&pdev->dev, "failed to get iface_clk\n");
3920 ret = PTR_ERR(motg->pclk);
3921 goto put_core_clk;
3922 }
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05303923
3924 res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
3925 if (!res) {
3926 dev_err(&pdev->dev, "failed to get platform resource mem\n");
3927 ret = -ENODEV;
Manu Gautam5143b252012-01-05 19:25:23 -08003928 goto put_pclk;
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05303929 }
3930
3931 motg->regs = ioremap(res->start, resource_size(res));
3932 if (!motg->regs) {
3933 dev_err(&pdev->dev, "ioremap failed\n");
3934 ret = -ENOMEM;
Manu Gautam5143b252012-01-05 19:25:23 -08003935 goto put_pclk;
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05303936 }
3937 dev_info(&pdev->dev, "OTG regs = %p\n", motg->regs);
3938
3939 motg->irq = platform_get_irq(pdev, 0);
3940 if (!motg->irq) {
3941 dev_err(&pdev->dev, "platform_get_irq failed\n");
3942 ret = -ENODEV;
3943 goto free_regs;
3944 }
3945
Manu Gautamf8c45642012-08-10 10:20:56 -07003946 motg->async_irq = platform_get_irq_byname(pdev, "async_irq");
3947 if (motg->async_irq < 0) {
3948 dev_dbg(&pdev->dev, "platform_get_irq for async_int failed\n");
3949 motg->async_irq = 0;
3950 }
3951
Vijayavardhan Vennapusa0cab6172013-02-20 19:51:15 +05303952 motg->xo_clk = clk_get(&pdev->dev, "xo");
3953 if (IS_ERR(motg->xo_clk)) {
3954 motg->xo_handle = msm_xo_get(MSM_XO_TCXO_D0, "usb");
3955 if (IS_ERR(motg->xo_handle)) {
3956 dev_err(&pdev->dev, "%s fail to get handle for TCXO\n",
3957 __func__);
3958 ret = PTR_ERR(motg->xo_handle);
3959 goto free_regs;
3960 } else {
3961 ret = msm_xo_mode_vote(motg->xo_handle, MSM_XO_MODE_ON);
3962 if (ret) {
3963 dev_err(&pdev->dev, "%s XO voting failed %d\n",
3964 __func__, ret);
3965 goto free_xo_handle;
3966 }
3967 }
3968 } else {
3969 ret = clk_prepare_enable(motg->xo_clk);
3970 if (ret) {
3971 dev_err(&pdev->dev, "%s failed to vote for TCXO %d\n",
3972 __func__, ret);
3973 goto free_xo_handle;
3974 }
Anji jonnala7da3f262011-12-02 17:22:14 -08003975 }
Anji jonnala11aa5c42011-05-04 10:19:48 +05303976
Anji jonnala7da3f262011-12-02 17:22:14 -08003977
Manu Gautam28b1bac2012-01-30 16:43:06 +05303978 clk_prepare_enable(motg->pclk);
Anji jonnala11aa5c42011-05-04 10:19:48 +05303979
Mayank Rana248698c2012-04-19 00:03:16 +05303980 motg->vdd_type = VDDCX_CORNER;
Mayank Rana0f286cf2013-02-27 11:43:27 +05303981 hsusb_vdd = devm_regulator_get(motg->phy.dev, "hsusb_vdd_dig");
3982 if (IS_ERR(hsusb_vdd)) {
3983 hsusb_vdd = devm_regulator_get(motg->phy.dev, "HSUSB_VDDCX");
3984 if (IS_ERR(hsusb_vdd)) {
Steve Mucklef132c6c2012-06-06 18:30:57 -07003985 dev_err(motg->phy.dev, "unable to get hsusb vddcx\n");
Mayank Rana0f286cf2013-02-27 11:43:27 +05303986 ret = PTR_ERR(hsusb_vdd);
Mayank Rana248698c2012-04-19 00:03:16 +05303987 goto devote_xo_handle;
3988 }
3989 motg->vdd_type = VDDCX;
Anji jonnala11aa5c42011-05-04 10:19:48 +05303990 }
3991
Mayank Rana0f286cf2013-02-27 11:43:27 +05303992 if (pdev->dev.of_node) {
3993 of_get_property(pdev->dev.of_node,
3994 "qcom,vdd-voltage-level",
3995 &len);
3996 if (len == sizeof(tmp)) {
3997 of_property_read_u32_array(pdev->dev.of_node,
3998 "qcom,vdd-voltage-level",
3999 tmp, len/sizeof(*tmp));
4000 vdd_val[motg->vdd_type][0] = tmp[0];
4001 vdd_val[motg->vdd_type][1] = tmp[1];
4002 vdd_val[motg->vdd_type][2] = tmp[2];
4003 } else {
4004 dev_dbg(&pdev->dev, "Using default hsusb vdd config.\n");
4005 }
4006 }
4007
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004008 ret = msm_hsusb_config_vddcx(1);
Anji jonnala11aa5c42011-05-04 10:19:48 +05304009 if (ret) {
4010 dev_err(&pdev->dev, "hsusb vddcx configuration failed\n");
Mayank Rana248698c2012-04-19 00:03:16 +05304011 goto devote_xo_handle;
4012 }
4013
Mayank Rana0f286cf2013-02-27 11:43:27 +05304014 ret = regulator_enable(hsusb_vdd);
Mayank Rana248698c2012-04-19 00:03:16 +05304015 if (ret) {
4016 dev_err(&pdev->dev, "unable to enable the hsusb vddcx\n");
4017 goto free_config_vddcx;
Anji jonnala11aa5c42011-05-04 10:19:48 +05304018 }
4019
4020 ret = msm_hsusb_ldo_init(motg, 1);
4021 if (ret) {
4022 dev_err(&pdev->dev, "hsusb vreg configuration failed\n");
Mayank Rana0f286cf2013-02-27 11:43:27 +05304023 goto free_hsusb_vdd;
Anji jonnala11aa5c42011-05-04 10:19:48 +05304024 }
4025
Mayank Rana9e9a2ac2012-03-24 04:05:28 +05304026 if (pdata->mhl_enable) {
Pavankumar Kondeti56dc7422012-07-02 12:45:19 +05304027 mhl_usb_hs_switch = devm_regulator_get(motg->phy.dev,
4028 "mhl_usb_hs_switch");
4029 if (IS_ERR(mhl_usb_hs_switch)) {
4030 dev_err(&pdev->dev, "Unable to get mhl_usb_hs_switch\n");
Hemant Kumar41812392012-07-13 15:26:20 -07004031 ret = PTR_ERR(mhl_usb_hs_switch);
Mayank Rana9e9a2ac2012-03-24 04:05:28 +05304032 goto free_ldo_init;
4033 }
4034 }
4035
Amit Blay81801aa2012-09-19 12:08:12 +02004036 ret = msm_hsusb_ldo_enable(motg, USB_PHY_REG_ON);
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05304037 if (ret) {
4038 dev_err(&pdev->dev, "hsusb vreg enable failed\n");
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004039 goto free_ldo_init;
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05304040 }
Manu Gautam28b1bac2012-01-30 16:43:06 +05304041 clk_prepare_enable(motg->core_clk);
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05304042
Manu Gautam0ddbd922012-09-21 17:17:38 +05304043 /* Check if USB mem_type change is needed to workaround PNOC hw issue */
4044 msm_otg_pnoc_errata_fix(motg);
4045
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05304046 writel(0, USB_USBINTR);
4047 writel(0, USB_OTGSC);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004048 /* Ensure that above STOREs are completed before enabling interrupts */
4049 mb();
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05304050
Pavankumar Kondeti2aec9f32012-06-13 09:06:03 +05304051 ret = msm_otg_mhl_register_callback(motg, msm_otg_mhl_notify_online);
4052 if (ret)
4053 dev_dbg(&pdev->dev, "MHL can not be supported\n");
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004054 wake_lock_init(&motg->wlock, WAKE_LOCK_SUSPEND, "msm_otg");
Vijayavardhan Vennapusaa3152032012-03-05 16:29:30 +05304055 msm_otg_init_timer(motg);
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05304056 INIT_WORK(&motg->sm_work, msm_otg_sm_work);
Pavankumar Kondetid8608522011-05-04 10:19:47 +05304057 INIT_DELAYED_WORK(&motg->chg_work, msm_chg_detect_work);
Vijayavardhan Vennapusa68d55cf2012-06-27 20:06:12 +05304058 INIT_DELAYED_WORK(&motg->pmic_id_status_work, msm_pmic_id_status_w);
Amit Blayd0fe07b2012-09-05 16:42:09 +03004059 INIT_DELAYED_WORK(&motg->suspend_work, msm_otg_suspend_work);
Pavankumar Kondetiaa449e12011-11-04 11:09:26 +05304060 setup_timer(&motg->id_timer, msm_otg_id_timer_func,
4061 (unsigned long) motg);
Pavankumar Kondeti458d8792012-09-28 14:45:18 +05304062 setup_timer(&motg->chg_check_timer, msm_otg_chg_check_timer_func,
4063 (unsigned long) motg);
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05304064 ret = request_irq(motg->irq, msm_otg_irq, IRQF_SHARED,
4065 "msm_otg", motg);
4066 if (ret) {
4067 dev_err(&pdev->dev, "request irq failed\n");
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004068 goto destroy_wlock;
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05304069 }
4070
Manu Gautamf8c45642012-08-10 10:20:56 -07004071 if (motg->async_irq) {
Vijayavardhan Vennapusa9ab6f972012-10-11 19:18:55 +05304072 ret = request_irq(motg->async_irq, msm_otg_irq,
4073 IRQF_TRIGGER_RISING, "msm_otg", motg);
Manu Gautamf8c45642012-08-10 10:20:56 -07004074 if (ret) {
4075 dev_err(&pdev->dev, "request irq failed (ASYNC INT)\n");
4076 goto free_irq;
4077 }
4078 disable_irq(motg->async_irq);
4079 }
4080
Jack Pham87f202f2012-08-06 00:24:22 -07004081 if (pdata->otg_control == OTG_PHY_CONTROL && pdata->mpm_otgsessvld_int)
4082 msm_mpm_enable_pin(pdata->mpm_otgsessvld_int, 1);
4083
Heikki Krogerus1d4c9292012-02-13 13:24:09 +02004084 phy->init = msm_otg_reset;
4085 phy->set_power = msm_otg_set_power;
Steve Mucklef132c6c2012-06-06 18:30:57 -07004086 phy->set_suspend = msm_otg_set_suspend;
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05304087
Heikki Krogerus1d4c9292012-02-13 13:24:09 +02004088 phy->io_ops = &msm_otg_io_ops;
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05304089
Heikki Krogerus1d4c9292012-02-13 13:24:09 +02004090 phy->otg->phy = &motg->phy;
4091 phy->otg->set_host = msm_otg_set_host;
4092 phy->otg->set_peripheral = msm_otg_set_peripheral;
Steve Mucklef132c6c2012-06-06 18:30:57 -07004093 phy->otg->start_hnp = msm_otg_start_hnp;
4094 phy->otg->start_srp = msm_otg_start_srp;
Vamsi Krishna1a1684b2013-03-02 16:14:52 -08004095 if (pdata->dp_manual_pullup)
4096 phy->flags |= ENABLE_DP_MANUAL_PULLUP;
Heikki Krogerus1d4c9292012-02-13 13:24:09 +02004097
4098 ret = usb_set_transceiver(&motg->phy);
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05304099 if (ret) {
Heikki Krogerus1d4c9292012-02-13 13:24:09 +02004100 dev_err(&pdev->dev, "usb_set_transceiver failed\n");
Manu Gautamf8c45642012-08-10 10:20:56 -07004101 goto free_async_irq;
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05304102 }
4103
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05304104 if (motg->pdata->mode == USB_OTG &&
Pavankumar Kondeti0d81f312012-01-13 11:34:10 +05304105 motg->pdata->otg_control == OTG_PMIC_CONTROL) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004106 if (motg->pdata->pmic_id_irq) {
4107 ret = request_irq(motg->pdata->pmic_id_irq,
4108 msm_pmic_id_irq,
4109 IRQF_TRIGGER_RISING |
4110 IRQF_TRIGGER_FALLING,
4111 "msm_otg", motg);
4112 if (ret) {
4113 dev_err(&pdev->dev, "request irq failed for PMIC ID\n");
Steve Mucklef132c6c2012-06-06 18:30:57 -07004114 goto remove_phy;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004115 }
4116 } else {
4117 ret = -ENODEV;
4118 dev_err(&pdev->dev, "PMIC IRQ for ID notifications doesn't exist\n");
Steve Mucklef132c6c2012-06-06 18:30:57 -07004119 goto remove_phy;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004120 }
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05304121 }
4122
Vijayavardhan Vennapusafc464f02011-11-04 21:54:00 +05304123 msm_hsusb_mhl_switch_enable(motg, 1);
4124
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05304125 platform_set_drvdata(pdev, motg);
4126 device_init_wakeup(&pdev->dev, 1);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004127 motg->mA_port = IUNIT;
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05304128
Anji jonnalad270e2d2011-08-09 11:28:32 +05304129 ret = msm_otg_debugfs_init(motg);
4130 if (ret)
4131 dev_dbg(&pdev->dev, "mode debugfs file is"
4132 "not available\n");
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05304133
Amit Blay58b31472011-11-18 09:39:39 +02004134 if (motg->pdata->phy_type == SNPS_28NM_INTEGRATED_PHY) {
4135 if (motg->pdata->otg_control == OTG_PMIC_CONTROL &&
Pavankumar Kondeti0d81f312012-01-13 11:34:10 +05304136 (!(motg->pdata->mode == USB_OTG) ||
4137 motg->pdata->pmic_id_irq))
Amit Blay58b31472011-11-18 09:39:39 +02004138 motg->caps = ALLOW_PHY_POWER_COLLAPSE |
Vijayavardhan Vennapusa03171c72012-04-26 14:44:48 +05304139 ALLOW_PHY_RETENTION;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004140
Amit Blay58b31472011-11-18 09:39:39 +02004141 if (motg->pdata->otg_control == OTG_PHY_CONTROL)
Amit Blay81801aa2012-09-19 12:08:12 +02004142 motg->caps = ALLOW_PHY_RETENTION |
4143 ALLOW_PHY_REGULATORS_LPM;
Amit Blay58b31472011-11-18 09:39:39 +02004144 }
4145
Amit Blay6fa647a2012-05-24 14:12:08 +03004146 if (motg->pdata->enable_lpm_on_dev_suspend)
4147 motg->caps |= ALLOW_LPM_ON_DEV_SUSPEND;
4148
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004149 wake_lock(&motg->wlock);
Pavankumar Kondeti87c01042010-12-07 17:53:58 +05304150 pm_runtime_set_active(&pdev->dev);
Manu Gautamf8c45642012-08-10 10:20:56 -07004151 pm_runtime_enable(&pdev->dev);
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05304152
Amit Blayd6f38282012-10-29 13:13:46 +02004153 if (motg->pdata->delay_lpm_on_disconnect) {
4154 pm_runtime_set_autosuspend_delay(&pdev->dev,
4155 lpm_disconnect_thresh);
4156 pm_runtime_use_autosuspend(&pdev->dev);
4157 }
4158
Manu Gautamcd82e9d2011-12-20 14:17:28 +05304159 if (motg->pdata->bus_scale_table) {
4160 motg->bus_perf_client =
4161 msm_bus_scale_register_client(motg->pdata->bus_scale_table);
4162 if (!motg->bus_perf_client)
Steve Mucklef132c6c2012-06-06 18:30:57 -07004163 dev_err(motg->phy.dev, "%s: Failed to register BUS "
Manu Gautamcd82e9d2011-12-20 14:17:28 +05304164 "scaling client!!\n", __func__);
Manu Gautam8bdcc592012-03-06 11:26:06 +05304165 else
4166 debug_bus_voting_enabled = true;
Manu Gautamcd82e9d2011-12-20 14:17:28 +05304167 }
4168
David Keitel272ce522012-08-17 16:25:24 -07004169 motg->usb_psy.name = "usb";
4170 motg->usb_psy.type = POWER_SUPPLY_TYPE_USB;
4171 motg->usb_psy.supplied_to = otg_pm_power_supplied_to;
4172 motg->usb_psy.num_supplicants = ARRAY_SIZE(otg_pm_power_supplied_to);
4173 motg->usb_psy.properties = otg_pm_power_props_usb;
4174 motg->usb_psy.num_properties = ARRAY_SIZE(otg_pm_power_props_usb);
4175 motg->usb_psy.get_property = otg_power_get_property_usb;
4176 motg->usb_psy.set_property = otg_power_set_property_usb;
David Collinsd79acc52012-11-26 14:59:00 -08004177 motg->usb_psy.property_is_writeable
4178 = otg_power_property_is_writeable_usb;
David Keitel272ce522012-08-17 16:25:24 -07004179
Jack Pham0c695282012-10-19 18:13:03 -07004180 if (!pm8921_charger_register_vbus_sn(NULL)) {
David Keitel272ce522012-08-17 16:25:24 -07004181 /* if pm8921 use legacy implementation */
Jack Pham0c695282012-10-19 18:13:03 -07004182 dev_dbg(motg->phy.dev, "%s: legacy support\n", __func__);
4183 legacy_power_supply = true;
4184 } else {
4185 /* otherwise register our own power supply */
4186 if (!msm_otg_register_power_supply(pdev, motg))
4187 psy = &motg->usb_psy;
David Keitel272ce522012-08-17 16:25:24 -07004188 }
4189
Jack Pham0c695282012-10-19 18:13:03 -07004190 if (legacy_power_supply && pdata->otg_control == OTG_PMIC_CONTROL)
4191 pm8921_charger_register_vbus_sn(&msm_otg_set_vbus_state);
4192
Pavankumar Kondeti87c01042010-12-07 17:53:58 +05304193 return 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004194
Steve Mucklef132c6c2012-06-06 18:30:57 -07004195remove_phy:
4196 usb_set_transceiver(NULL);
Manu Gautamf8c45642012-08-10 10:20:56 -07004197free_async_irq:
4198 if (motg->async_irq)
4199 free_irq(motg->async_irq, motg);
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05304200free_irq:
4201 free_irq(motg->irq, motg);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004202destroy_wlock:
4203 wake_lock_destroy(&motg->wlock);
Manu Gautam28b1bac2012-01-30 16:43:06 +05304204 clk_disable_unprepare(motg->core_clk);
Amit Blay81801aa2012-09-19 12:08:12 +02004205 msm_hsusb_ldo_enable(motg, USB_PHY_REG_OFF);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004206free_ldo_init:
Anji jonnala11aa5c42011-05-04 10:19:48 +05304207 msm_hsusb_ldo_init(motg, 0);
Mayank Rana0f286cf2013-02-27 11:43:27 +05304208free_hsusb_vdd:
4209 regulator_disable(hsusb_vdd);
Mayank Rana248698c2012-04-19 00:03:16 +05304210free_config_vddcx:
Mayank Rana0f286cf2013-02-27 11:43:27 +05304211 regulator_set_voltage(hsusb_vdd,
Mayank Rana248698c2012-04-19 00:03:16 +05304212 vdd_val[motg->vdd_type][VDD_NONE],
4213 vdd_val[motg->vdd_type][VDD_MAX]);
Anji jonnala7da3f262011-12-02 17:22:14 -08004214devote_xo_handle:
Manu Gautam28b1bac2012-01-30 16:43:06 +05304215 clk_disable_unprepare(motg->pclk);
Vijayavardhan Vennapusa0cab6172013-02-20 19:51:15 +05304216 if (!IS_ERR(motg->xo_clk))
4217 clk_disable_unprepare(motg->xo_clk);
4218 else
4219 msm_xo_mode_vote(motg->xo_handle, MSM_XO_MODE_OFF);
Anji jonnala7da3f262011-12-02 17:22:14 -08004220free_xo_handle:
Vijayavardhan Vennapusa0cab6172013-02-20 19:51:15 +05304221 if (!IS_ERR(motg->xo_clk))
4222 clk_put(motg->xo_clk);
4223 else
4224 msm_xo_put(motg->xo_handle);
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05304225free_regs:
4226 iounmap(motg->regs);
Manu Gautam5143b252012-01-05 19:25:23 -08004227put_pclk:
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05304228 clk_put(motg->pclk);
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05304229put_core_clk:
Manu Gautam5143b252012-01-05 19:25:23 -08004230 clk_put(motg->core_clk);
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05304231put_clk:
Pavankumar Kondeti923262e2012-04-20 15:34:24 +05304232 if (!IS_ERR(motg->clk))
4233 clk_put(motg->clk);
Amit Blay02eff132011-09-21 16:46:24 +03004234 if (!IS_ERR(motg->phy_reset_clk))
4235 clk_put(motg->phy_reset_clk);
Steve Mucklef132c6c2012-06-06 18:30:57 -07004236free_otg:
Heikki Krogerus1d4c9292012-02-13 13:24:09 +02004237 kfree(motg->phy.otg);
Pavankumar Kondetiaa449e12011-11-04 11:09:26 +05304238free_motg:
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05304239 kfree(motg);
4240 return ret;
4241}
4242
4243static int __devexit msm_otg_remove(struct platform_device *pdev)
4244{
4245 struct msm_otg *motg = platform_get_drvdata(pdev);
Stephen Boyd9850acb2013-01-28 14:11:20 -08004246 struct usb_phy *phy = &motg->phy;
Pavankumar Kondeti87c01042010-12-07 17:53:58 +05304247 int cnt = 0;
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05304248
Stephen Boyd9850acb2013-01-28 14:11:20 -08004249 if (phy->otg->host || phy->otg->gadget)
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05304250 return -EBUSY;
4251
Pavankumar Kondetieaea7fe2011-10-27 14:46:45 +05304252 if (pdev->dev.of_node)
4253 msm_otg_setup_devices(pdev, motg->pdata->mode, false);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004254 if (motg->pdata->otg_control == OTG_PMIC_CONTROL)
4255 pm8921_charger_unregister_vbus_sn(0);
Pavankumar Kondeti2aec9f32012-06-13 09:06:03 +05304256 msm_otg_mhl_register_callback(motg, NULL);
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05304257 msm_otg_debugfs_cleanup();
Pavankumar Kondetid8608522011-05-04 10:19:47 +05304258 cancel_delayed_work_sync(&motg->chg_work);
Vijayavardhan Vennapusa68d55cf2012-06-27 20:06:12 +05304259 cancel_delayed_work_sync(&motg->pmic_id_status_work);
Amit Blayd0fe07b2012-09-05 16:42:09 +03004260 cancel_delayed_work_sync(&motg->suspend_work);
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05304261 cancel_work_sync(&motg->sm_work);
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05304262
Pavankumar Kondeti70187732011-02-15 09:42:34 +05304263 pm_runtime_resume(&pdev->dev);
Pavankumar Kondeti87c01042010-12-07 17:53:58 +05304264
4265 device_init_wakeup(&pdev->dev, 0);
4266 pm_runtime_disable(&pdev->dev);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004267 wake_lock_destroy(&motg->wlock);
Pavankumar Kondeti87c01042010-12-07 17:53:58 +05304268
Vijayavardhan Vennapusafc464f02011-11-04 21:54:00 +05304269 msm_hsusb_mhl_switch_enable(motg, 0);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004270 if (motg->pdata->pmic_id_irq)
4271 free_irq(motg->pdata->pmic_id_irq, motg);
Heikki Krogerus1d4c9292012-02-13 13:24:09 +02004272 usb_set_transceiver(NULL);
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05304273 free_irq(motg->irq, motg);
4274
Jack Pham87f202f2012-08-06 00:24:22 -07004275 if (motg->pdata->otg_control == OTG_PHY_CONTROL &&
4276 motg->pdata->mpm_otgsessvld_int)
4277 msm_mpm_enable_pin(motg->pdata->mpm_otgsessvld_int, 0);
4278
Pavankumar Kondeti87c01042010-12-07 17:53:58 +05304279 /*
4280 * Put PHY in low power mode.
4281 */
Stephen Boyd9850acb2013-01-28 14:11:20 -08004282 ulpi_read(phy, 0x14);
4283 ulpi_write(phy, 0x08, 0x09);
Pavankumar Kondeti87c01042010-12-07 17:53:58 +05304284
4285 writel(readl(USB_PORTSC) | PORTSC_PHCD, USB_PORTSC);
4286 while (cnt < PHY_SUSPEND_TIMEOUT_USEC) {
4287 if (readl(USB_PORTSC) & PORTSC_PHCD)
4288 break;
4289 udelay(1);
4290 cnt++;
4291 }
4292 if (cnt >= PHY_SUSPEND_TIMEOUT_USEC)
Stephen Boyd9850acb2013-01-28 14:11:20 -08004293 dev_err(phy->dev, "Unable to suspend PHY\n");
Pavankumar Kondeti87c01042010-12-07 17:53:58 +05304294
Manu Gautam28b1bac2012-01-30 16:43:06 +05304295 clk_disable_unprepare(motg->pclk);
4296 clk_disable_unprepare(motg->core_clk);
Vijayavardhan Vennapusa0cab6172013-02-20 19:51:15 +05304297 if (!IS_ERR(motg->xo_clk)) {
4298 clk_disable_unprepare(motg->xo_clk);
4299 clk_put(motg->xo_clk);
4300 } else {
4301 msm_xo_put(motg->xo_handle);
4302 }
Amit Blay81801aa2012-09-19 12:08:12 +02004303 msm_hsusb_ldo_enable(motg, USB_PHY_REG_OFF);
Anji jonnala11aa5c42011-05-04 10:19:48 +05304304 msm_hsusb_ldo_init(motg, 0);
Mayank Rana0f286cf2013-02-27 11:43:27 +05304305 regulator_disable(hsusb_vdd);
4306 regulator_set_voltage(hsusb_vdd,
Mayank Rana248698c2012-04-19 00:03:16 +05304307 vdd_val[motg->vdd_type][VDD_NONE],
4308 vdd_val[motg->vdd_type][VDD_MAX]);
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05304309
4310 iounmap(motg->regs);
Pavankumar Kondeti87c01042010-12-07 17:53:58 +05304311 pm_runtime_set_suspended(&pdev->dev);
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05304312
Amit Blay02eff132011-09-21 16:46:24 +03004313 if (!IS_ERR(motg->phy_reset_clk))
4314 clk_put(motg->phy_reset_clk);
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05304315 clk_put(motg->pclk);
Pavankumar Kondeti923262e2012-04-20 15:34:24 +05304316 if (!IS_ERR(motg->clk))
4317 clk_put(motg->clk);
Manu Gautam5143b252012-01-05 19:25:23 -08004318 clk_put(motg->core_clk);
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05304319
Manu Gautamcd82e9d2011-12-20 14:17:28 +05304320 if (motg->bus_perf_client)
4321 msm_bus_scale_unregister_client(motg->bus_perf_client);
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05304322
Heikki Krogerus1d4c9292012-02-13 13:24:09 +02004323 kfree(motg->phy.otg);
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05304324 kfree(motg);
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05304325 return 0;
4326}
4327
Pavankumar Kondeti87c01042010-12-07 17:53:58 +05304328#ifdef CONFIG_PM_RUNTIME
4329static int msm_otg_runtime_idle(struct device *dev)
4330{
4331 struct msm_otg *motg = dev_get_drvdata(dev);
Steve Mucklef132c6c2012-06-06 18:30:57 -07004332 struct usb_phy *phy = &motg->phy;
Pavankumar Kondeti87c01042010-12-07 17:53:58 +05304333
4334 dev_dbg(dev, "OTG runtime idle\n");
4335
Steve Mucklef132c6c2012-06-06 18:30:57 -07004336 if (phy->state == OTG_STATE_UNDEFINED)
Pavankumar Kondeti8be99cf2011-08-04 10:48:08 +05304337 return -EAGAIN;
4338 else
4339 return 0;
Pavankumar Kondeti87c01042010-12-07 17:53:58 +05304340}
4341
4342static int msm_otg_runtime_suspend(struct device *dev)
4343{
4344 struct msm_otg *motg = dev_get_drvdata(dev);
4345
4346 dev_dbg(dev, "OTG runtime suspend\n");
4347 return msm_otg_suspend(motg);
4348}
4349
4350static int msm_otg_runtime_resume(struct device *dev)
4351{
4352 struct msm_otg *motg = dev_get_drvdata(dev);
4353
4354 dev_dbg(dev, "OTG runtime resume\n");
Pavankumar Kondeti8be99cf2011-08-04 10:48:08 +05304355 pm_runtime_get_noresume(dev);
Pavankumar Kondeti87c01042010-12-07 17:53:58 +05304356 return msm_otg_resume(motg);
4357}
Pavankumar Kondeti87c01042010-12-07 17:53:58 +05304358#endif
4359
Pavankumar Kondeti70187732011-02-15 09:42:34 +05304360#ifdef CONFIG_PM_SLEEP
Pavankumar Kondeti87c01042010-12-07 17:53:58 +05304361static int msm_otg_pm_suspend(struct device *dev)
4362{
Jack Pham5ca279b2012-05-14 18:42:54 -07004363 int ret = 0;
Pavankumar Kondeti87c01042010-12-07 17:53:58 +05304364 struct msm_otg *motg = dev_get_drvdata(dev);
4365
4366 dev_dbg(dev, "OTG PM suspend\n");
Jack Pham5ca279b2012-05-14 18:42:54 -07004367
4368 atomic_set(&motg->pm_suspended, 1);
4369 ret = msm_otg_suspend(motg);
4370 if (ret)
4371 atomic_set(&motg->pm_suspended, 0);
4372
4373 return ret;
Pavankumar Kondeti87c01042010-12-07 17:53:58 +05304374}
4375
4376static int msm_otg_pm_resume(struct device *dev)
4377{
Jack Pham5ca279b2012-05-14 18:42:54 -07004378 int ret = 0;
Pavankumar Kondeti87c01042010-12-07 17:53:58 +05304379 struct msm_otg *motg = dev_get_drvdata(dev);
Pavankumar Kondeti87c01042010-12-07 17:53:58 +05304380
4381 dev_dbg(dev, "OTG PM resume\n");
4382
Jack Pham5ca279b2012-05-14 18:42:54 -07004383 atomic_set(&motg->pm_suspended, 0);
Jack Phamc7edb172012-08-13 15:32:39 -07004384 if (motg->async_int || motg->sm_work_pending) {
Jack Pham5ca279b2012-05-14 18:42:54 -07004385 pm_runtime_get_noresume(dev);
4386 ret = msm_otg_resume(motg);
Pavankumar Kondeti87c01042010-12-07 17:53:58 +05304387
Jack Pham5ca279b2012-05-14 18:42:54 -07004388 /* Update runtime PM status */
4389 pm_runtime_disable(dev);
4390 pm_runtime_set_active(dev);
4391 pm_runtime_enable(dev);
4392
Jack Phamc7edb172012-08-13 15:32:39 -07004393 if (motg->sm_work_pending) {
4394 motg->sm_work_pending = false;
4395 queue_work(system_nrt_wq, &motg->sm_work);
4396 }
Jack Pham5ca279b2012-05-14 18:42:54 -07004397 }
4398
4399 return ret;
Pavankumar Kondeti87c01042010-12-07 17:53:58 +05304400}
Pavankumar Kondeti87c01042010-12-07 17:53:58 +05304401#endif
4402
Pavankumar Kondeti70187732011-02-15 09:42:34 +05304403#ifdef CONFIG_PM
Pavankumar Kondeti87c01042010-12-07 17:53:58 +05304404static const struct dev_pm_ops msm_otg_dev_pm_ops = {
Pavankumar Kondeti70187732011-02-15 09:42:34 +05304405 SET_SYSTEM_SLEEP_PM_OPS(msm_otg_pm_suspend, msm_otg_pm_resume)
4406 SET_RUNTIME_PM_OPS(msm_otg_runtime_suspend, msm_otg_runtime_resume,
4407 msm_otg_runtime_idle)
Pavankumar Kondeti87c01042010-12-07 17:53:58 +05304408};
Pavankumar Kondeti70187732011-02-15 09:42:34 +05304409#endif
Pavankumar Kondeti87c01042010-12-07 17:53:58 +05304410
Pavankumar Kondetieaea7fe2011-10-27 14:46:45 +05304411static struct of_device_id msm_otg_dt_match[] = {
4412 { .compatible = "qcom,hsusb-otg",
4413 },
4414 {}
4415};
4416
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05304417static struct platform_driver msm_otg_driver = {
4418 .remove = __devexit_p(msm_otg_remove),
4419 .driver = {
4420 .name = DRIVER_NAME,
4421 .owner = THIS_MODULE,
Pavankumar Kondeti70187732011-02-15 09:42:34 +05304422#ifdef CONFIG_PM
Pavankumar Kondeti87c01042010-12-07 17:53:58 +05304423 .pm = &msm_otg_dev_pm_ops,
Pavankumar Kondeti70187732011-02-15 09:42:34 +05304424#endif
Pavankumar Kondetieaea7fe2011-10-27 14:46:45 +05304425 .of_match_table = msm_otg_dt_match,
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05304426 },
4427};
4428
4429static int __init msm_otg_init(void)
4430{
4431 return platform_driver_probe(&msm_otg_driver, msm_otg_probe);
4432}
4433
4434static void __exit msm_otg_exit(void)
4435{
4436 platform_driver_unregister(&msm_otg_driver);
4437}
4438
4439module_init(msm_otg_init);
4440module_exit(msm_otg_exit);
4441
4442MODULE_LICENSE("GPL v2");
4443MODULE_DESCRIPTION("MSM USB transceiver driver");