blob: 26f1b84642a877351ecadb22e0130cd743b809ea [file] [log] [blame]
Manu Gautam5143b252012-01-05 19:25:23 -08001/* Copyright (c) 2009-2012, Code Aurora Forum. All rights reserved.
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05302 *
3 * This program is free software; you can redistribute it and/or modify
4 * it under the terms of the GNU General Public License version 2 and
5 * only version 2 as published by the Free Software Foundation.
6 *
7 * This program is distributed in the hope that it will be useful,
8 * but WITHOUT ANY WARRANTY; without even the implied warranty of
9 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10 * GNU General Public License for more details.
11 *
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +053012 */
13
14#include <linux/module.h>
15#include <linux/device.h>
16#include <linux/platform_device.h>
17#include <linux/clk.h>
18#include <linux/slab.h>
19#include <linux/interrupt.h>
20#include <linux/err.h>
21#include <linux/delay.h>
22#include <linux/io.h>
23#include <linux/ioport.h>
24#include <linux/uaccess.h>
25#include <linux/debugfs.h>
26#include <linux/seq_file.h>
Pavankumar Kondeti87c01042010-12-07 17:53:58 +053027#include <linux/pm_runtime.h>
Pavankumar Kondetieaea7fe2011-10-27 14:46:45 +053028#include <linux/of.h>
29#include <linux/dma-mapping.h>
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +053030
31#include <linux/usb.h>
32#include <linux/usb/otg.h>
33#include <linux/usb/ulpi.h>
34#include <linux/usb/gadget.h>
35#include <linux/usb/hcd.h>
Vijayavardhan Vennapusaa3152032012-03-05 16:29:30 +053036#include <linux/usb/quirks.h>
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +053037#include <linux/usb/msm_hsusb.h>
38#include <linux/usb/msm_hsusb_hw.h>
Anji jonnala11aa5c42011-05-04 10:19:48 +053039#include <linux/regulator/consumer.h>
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070040#include <linux/mfd/pm8xxx/pm8921-charger.h>
Pavankumar Kondeti446f4542012-02-01 13:57:13 +053041#include <linux/mfd/pm8xxx/misc.h>
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
Pavankumar Kondeti4960f312011-12-06 15:46:14 +053085static DECLARE_COMPLETION(pmic_vbus_init);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070086static struct msm_otg *the_msm_otg;
Pavankumar Kondetiaa449e12011-11-04 11:09:26 +053087static bool debug_aca_enabled;
Manu Gautam8bdcc592012-03-06 11:26:06 +053088static bool debug_bus_voting_enabled;
Pavankumar Kondeti2aec9f32012-06-13 09:06:03 +053089static bool mhl_det_in_progress;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070090
Anji jonnala11aa5c42011-05-04 10:19:48 +053091static struct regulator *hsusb_3p3;
92static struct regulator *hsusb_1p8;
93static struct regulator *hsusb_vddcx;
Mayank Ranae3926882011-12-26 09:47:54 +053094static struct regulator *vbus_otg;
Pavankumar Kondeti56dc7422012-07-02 12:45:19 +053095static struct regulator *mhl_usb_hs_switch;
Vijayavardhan Vennapusa05c437c2012-05-25 16:20:46 +053096static struct power_supply *psy;
Anji jonnala11aa5c42011-05-04 10:19:48 +053097
Pavankumar Kondeti4960f312011-12-06 15:46:14 +053098static bool aca_id_turned_on;
David Keitel272ce522012-08-17 16:25:24 -070099static bool legacy_power_supply;
Pavankumar Kondetiaa449e12011-11-04 11:09:26 +0530100static inline bool aca_enabled(void)
Anji jonnala11aa5c42011-05-04 10:19:48 +0530101{
Pavankumar Kondetiaa449e12011-11-04 11:09:26 +0530102#ifdef CONFIG_USB_MSM_ACA
103 return true;
104#else
105 return debug_aca_enabled;
106#endif
Anji jonnala11aa5c42011-05-04 10:19:48 +0530107}
108
Mayank Rana248698c2012-04-19 00:03:16 +0530109static const int vdd_val[VDD_TYPE_MAX][VDD_VAL_MAX] = {
110 { /* VDD_CX CORNER Voting */
111 [VDD_NONE] = RPM_VREG_CORNER_NONE,
112 [VDD_MIN] = RPM_VREG_CORNER_NOMINAL,
113 [VDD_MAX] = RPM_VREG_CORNER_HIGH,
114 },
115 { /* VDD_CX Voltage Voting */
116 [VDD_NONE] = USB_PHY_VDD_DIG_VOL_NONE,
117 [VDD_MIN] = USB_PHY_VDD_DIG_VOL_MIN,
118 [VDD_MAX] = USB_PHY_VDD_DIG_VOL_MAX,
119 },
120};
Anji jonnala11aa5c42011-05-04 10:19:48 +0530121
122static int msm_hsusb_ldo_init(struct msm_otg *motg, int init)
123{
124 int rc = 0;
125
126 if (init) {
Steve Mucklef132c6c2012-06-06 18:30:57 -0700127 hsusb_3p3 = devm_regulator_get(motg->phy.dev, "HSUSB_3p3");
Anji jonnala11aa5c42011-05-04 10:19:48 +0530128 if (IS_ERR(hsusb_3p3)) {
Heikki Krogerus1d4c9292012-02-13 13:24:09 +0200129 dev_err(motg->phy.dev, "unable to get hsusb 3p3\n");
Anji jonnala11aa5c42011-05-04 10:19:48 +0530130 return PTR_ERR(hsusb_3p3);
131 }
132
133 rc = regulator_set_voltage(hsusb_3p3, USB_PHY_3P3_VOL_MIN,
134 USB_PHY_3P3_VOL_MAX);
135 if (rc) {
Steve Mucklef132c6c2012-06-06 18:30:57 -0700136 dev_err(motg->phy.dev, "unable to set voltage level for"
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700137 "hsusb 3p3\n");
Mayank Rana9e9a2ac2012-03-24 04:05:28 +0530138 return rc;
Anji jonnala11aa5c42011-05-04 10:19:48 +0530139 }
Steve Mucklef132c6c2012-06-06 18:30:57 -0700140 hsusb_1p8 = devm_regulator_get(motg->phy.dev, "HSUSB_1p8");
Anji jonnala11aa5c42011-05-04 10:19:48 +0530141 if (IS_ERR(hsusb_1p8)) {
Heikki Krogerus1d4c9292012-02-13 13:24:09 +0200142 dev_err(motg->phy.dev, "unable to get hsusb 1p8\n");
Anji jonnala11aa5c42011-05-04 10:19:48 +0530143 rc = PTR_ERR(hsusb_1p8);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700144 goto put_3p3_lpm;
Anji jonnala11aa5c42011-05-04 10:19:48 +0530145 }
146 rc = regulator_set_voltage(hsusb_1p8, USB_PHY_1P8_VOL_MIN,
147 USB_PHY_1P8_VOL_MAX);
148 if (rc) {
Steve Mucklef132c6c2012-06-06 18:30:57 -0700149 dev_err(motg->phy.dev, "unable to set voltage level for"
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700150 "hsusb 1p8\n");
Anji jonnala11aa5c42011-05-04 10:19:48 +0530151 goto put_1p8;
152 }
153
154 return 0;
155 }
156
Anji jonnala11aa5c42011-05-04 10:19:48 +0530157put_1p8:
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700158 regulator_set_voltage(hsusb_1p8, 0, USB_PHY_1P8_VOL_MAX);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700159put_3p3_lpm:
160 regulator_set_voltage(hsusb_3p3, 0, USB_PHY_3P3_VOL_MAX);
Anji jonnala11aa5c42011-05-04 10:19:48 +0530161 return rc;
162}
163
Pavankumar Kondeti04aebcb2011-05-04 10:19:49 +0530164static int msm_hsusb_config_vddcx(int high)
165{
Mayank Rana248698c2012-04-19 00:03:16 +0530166 struct msm_otg *motg = the_msm_otg;
167 enum usb_vdd_type vdd_type = motg->vdd_type;
168 int max_vol = vdd_val[vdd_type][VDD_MAX];
Pavankumar Kondeti04aebcb2011-05-04 10:19:49 +0530169 int min_vol;
170 int ret;
171
Mayank Rana248698c2012-04-19 00:03:16 +0530172 min_vol = vdd_val[vdd_type][!!high];
Pavankumar Kondeti04aebcb2011-05-04 10:19:49 +0530173 ret = regulator_set_voltage(hsusb_vddcx, min_vol, max_vol);
174 if (ret) {
175 pr_err("%s: unable to set the voltage for regulator "
176 "HSUSB_VDDCX\n", __func__);
177 return ret;
178 }
179
180 pr_debug("%s: min_vol:%d max_vol:%d\n", __func__, min_vol, max_vol);
181
182 return ret;
183}
Pavankumar Kondeti04aebcb2011-05-04 10:19:49 +0530184
Amit Blay81801aa2012-09-19 12:08:12 +0200185static int msm_hsusb_ldo_enable(struct msm_otg *motg,
186 enum msm_otg_phy_reg_mode mode)
Anji jonnala11aa5c42011-05-04 10:19:48 +0530187{
188 int ret = 0;
189
Pavankumar Kondeti68964c92011-10-27 14:58:56 +0530190 if (IS_ERR(hsusb_1p8)) {
Anji jonnala11aa5c42011-05-04 10:19:48 +0530191 pr_err("%s: HSUSB_1p8 is not initialized\n", __func__);
192 return -ENODEV;
193 }
194
Pavankumar Kondeti68964c92011-10-27 14:58:56 +0530195 if (IS_ERR(hsusb_3p3)) {
Anji jonnala11aa5c42011-05-04 10:19:48 +0530196 pr_err("%s: HSUSB_3p3 is not initialized\n", __func__);
197 return -ENODEV;
198 }
199
Amit Blay81801aa2012-09-19 12:08:12 +0200200 switch (mode) {
201 case USB_PHY_REG_ON:
Anji jonnala11aa5c42011-05-04 10:19:48 +0530202 ret = regulator_set_optimum_mode(hsusb_1p8,
203 USB_PHY_1P8_HPM_LOAD);
204 if (ret < 0) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700205 pr_err("%s: Unable to set HPM of the regulator:"
Anji jonnala11aa5c42011-05-04 10:19:48 +0530206 "HSUSB_1p8\n", __func__);
207 return ret;
208 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700209
210 ret = regulator_enable(hsusb_1p8);
211 if (ret) {
Steve Mucklef132c6c2012-06-06 18:30:57 -0700212 dev_err(motg->phy.dev, "%s: unable to enable the hsusb 1p8\n",
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700213 __func__);
214 regulator_set_optimum_mode(hsusb_1p8, 0);
215 return ret;
216 }
217
Anji jonnala11aa5c42011-05-04 10:19:48 +0530218 ret = regulator_set_optimum_mode(hsusb_3p3,
219 USB_PHY_3P3_HPM_LOAD);
220 if (ret < 0) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700221 pr_err("%s: Unable to set HPM of the regulator:"
Anji jonnala11aa5c42011-05-04 10:19:48 +0530222 "HSUSB_3p3\n", __func__);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700223 regulator_set_optimum_mode(hsusb_1p8, 0);
224 regulator_disable(hsusb_1p8);
Anji jonnala11aa5c42011-05-04 10:19:48 +0530225 return ret;
226 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700227
228 ret = regulator_enable(hsusb_3p3);
229 if (ret) {
Steve Mucklef132c6c2012-06-06 18:30:57 -0700230 dev_err(motg->phy.dev, "%s: unable to enable the hsusb 3p3\n",
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700231 __func__);
232 regulator_set_optimum_mode(hsusb_3p3, 0);
233 regulator_set_optimum_mode(hsusb_1p8, 0);
234 regulator_disable(hsusb_1p8);
235 return ret;
236 }
237
Amit Blay81801aa2012-09-19 12:08:12 +0200238 break;
239
240 case USB_PHY_REG_OFF:
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700241 ret = regulator_disable(hsusb_1p8);
242 if (ret) {
Steve Mucklef132c6c2012-06-06 18:30:57 -0700243 dev_err(motg->phy.dev, "%s: unable to disable the hsusb 1p8\n",
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700244 __func__);
245 return ret;
246 }
247
248 ret = regulator_set_optimum_mode(hsusb_1p8, 0);
Anji jonnala11aa5c42011-05-04 10:19:48 +0530249 if (ret < 0)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700250 pr_err("%s: Unable to set LPM of the regulator:"
Anji jonnala11aa5c42011-05-04 10:19:48 +0530251 "HSUSB_1p8\n", __func__);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700252
253 ret = regulator_disable(hsusb_3p3);
254 if (ret) {
Steve Mucklef132c6c2012-06-06 18:30:57 -0700255 dev_err(motg->phy.dev, "%s: unable to disable the hsusb 3p3\n",
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700256 __func__);
257 return ret;
258 }
259 ret = regulator_set_optimum_mode(hsusb_3p3, 0);
Anji jonnala11aa5c42011-05-04 10:19:48 +0530260 if (ret < 0)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700261 pr_err("%s: Unable to set LPM of the regulator:"
Anji jonnala11aa5c42011-05-04 10:19:48 +0530262 "HSUSB_3p3\n", __func__);
Amit Blay81801aa2012-09-19 12:08:12 +0200263
264 break;
265
266 case USB_PHY_REG_LPM_ON:
267 ret = regulator_set_optimum_mode(hsusb_1p8,
268 USB_PHY_1P8_LPM_LOAD);
269 if (ret < 0) {
270 pr_err("%s: Unable to set LPM of the regulator: HSUSB_1p8\n",
271 __func__);
272 return ret;
273 }
274
275 ret = regulator_set_optimum_mode(hsusb_3p3,
276 USB_PHY_3P3_LPM_LOAD);
277 if (ret < 0) {
278 pr_err("%s: Unable to set LPM of the regulator: HSUSB_3p3\n",
279 __func__);
280 regulator_set_optimum_mode(hsusb_1p8, USB_PHY_REG_ON);
281 return ret;
282 }
283
284 break;
285
286 case USB_PHY_REG_LPM_OFF:
287 ret = regulator_set_optimum_mode(hsusb_1p8,
288 USB_PHY_1P8_HPM_LOAD);
289 if (ret < 0) {
290 pr_err("%s: Unable to set HPM of the regulator: HSUSB_1p8\n",
291 __func__);
292 return ret;
293 }
294
295 ret = regulator_set_optimum_mode(hsusb_3p3,
296 USB_PHY_3P3_HPM_LOAD);
297 if (ret < 0) {
298 pr_err("%s: Unable to set HPM of the regulator: HSUSB_3p3\n",
299 __func__);
300 regulator_set_optimum_mode(hsusb_1p8, USB_PHY_REG_ON);
301 return ret;
302 }
303
304 break;
305
306 default:
307 pr_err("%s: Unsupported mode (%d).", __func__, mode);
308 return -ENOTSUPP;
Anji jonnala11aa5c42011-05-04 10:19:48 +0530309 }
310
Amit Blay81801aa2012-09-19 12:08:12 +0200311 pr_debug("%s: USB reg mode (%d) (OFF/HPM/LPM)\n", __func__, mode);
Anji jonnala11aa5c42011-05-04 10:19:48 +0530312 return ret < 0 ? ret : 0;
313}
314
Vijayavardhan Vennapusafc464f02011-11-04 21:54:00 +0530315static void msm_hsusb_mhl_switch_enable(struct msm_otg *motg, bool on)
316{
Vijayavardhan Vennapusafc464f02011-11-04 21:54:00 +0530317 struct msm_otg_platform_data *pdata = motg->pdata;
318
319 if (!pdata->mhl_enable)
320 return;
321
Pavankumar Kondeti56dc7422012-07-02 12:45:19 +0530322 if (!mhl_usb_hs_switch) {
323 pr_err("%s: mhl_usb_hs_switch is NULL.\n", __func__);
Vijayavardhan Vennapusafc464f02011-11-04 21:54:00 +0530324 return;
325 }
326
Mayank Rana9e9a2ac2012-03-24 04:05:28 +0530327 if (on) {
Pavankumar Kondeti56dc7422012-07-02 12:45:19 +0530328 if (regulator_enable(mhl_usb_hs_switch))
329 pr_err("unable to enable mhl_usb_hs_switch\n");
Mayank Rana9e9a2ac2012-03-24 04:05:28 +0530330 } else {
Pavankumar Kondeti56dc7422012-07-02 12:45:19 +0530331 regulator_disable(mhl_usb_hs_switch);
Mayank Rana9e9a2ac2012-03-24 04:05:28 +0530332 }
Vijayavardhan Vennapusafc464f02011-11-04 21:54:00 +0530333}
334
Heikki Krogerus1d4c9292012-02-13 13:24:09 +0200335static int ulpi_read(struct usb_phy *phy, u32 reg)
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +0530336{
Heikki Krogerus1d4c9292012-02-13 13:24:09 +0200337 struct msm_otg *motg = container_of(phy, struct msm_otg, phy);
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +0530338 int cnt = 0;
339
340 /* initiate read operation */
341 writel(ULPI_RUN | ULPI_READ | ULPI_ADDR(reg),
342 USB_ULPI_VIEWPORT);
343
344 /* wait for completion */
345 while (cnt < ULPI_IO_TIMEOUT_USEC) {
346 if (!(readl(USB_ULPI_VIEWPORT) & ULPI_RUN))
347 break;
348 udelay(1);
349 cnt++;
350 }
351
352 if (cnt >= ULPI_IO_TIMEOUT_USEC) {
Heikki Krogerus1d4c9292012-02-13 13:24:09 +0200353 dev_err(phy->dev, "ulpi_read: timeout %08x\n",
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +0530354 readl(USB_ULPI_VIEWPORT));
355 return -ETIMEDOUT;
356 }
357 return ULPI_DATA_READ(readl(USB_ULPI_VIEWPORT));
358}
359
Heikki Krogerus1d4c9292012-02-13 13:24:09 +0200360static int ulpi_write(struct usb_phy *phy, u32 val, u32 reg)
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +0530361{
Heikki Krogerus1d4c9292012-02-13 13:24:09 +0200362 struct msm_otg *motg = container_of(phy, struct msm_otg, phy);
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +0530363 int cnt = 0;
364
365 /* initiate write operation */
366 writel(ULPI_RUN | ULPI_WRITE |
367 ULPI_ADDR(reg) | ULPI_DATA(val),
368 USB_ULPI_VIEWPORT);
369
370 /* wait for completion */
371 while (cnt < ULPI_IO_TIMEOUT_USEC) {
372 if (!(readl(USB_ULPI_VIEWPORT) & ULPI_RUN))
373 break;
374 udelay(1);
375 cnt++;
376 }
377
378 if (cnt >= ULPI_IO_TIMEOUT_USEC) {
Heikki Krogerus1d4c9292012-02-13 13:24:09 +0200379 dev_err(phy->dev, "ulpi_write: timeout\n");
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +0530380 return -ETIMEDOUT;
381 }
382 return 0;
383}
384
Heikki Krogerus1d4c9292012-02-13 13:24:09 +0200385static struct usb_phy_io_ops msm_otg_io_ops = {
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +0530386 .read = ulpi_read,
387 .write = ulpi_write,
388};
389
390static void ulpi_init(struct msm_otg *motg)
391{
392 struct msm_otg_platform_data *pdata = motg->pdata;
Mayank Rana443f9e42012-09-21 18:32:39 +0530393 int aseq[10];
394 int *seq = NULL;
395
396 if (override_phy_init) {
397 pr_debug("%s(): HUSB PHY Init:%s\n", __func__,
398 override_phy_init);
399 get_options(override_phy_init, ARRAY_SIZE(aseq), aseq);
400 seq = &aseq[1];
401 } else {
402 seq = pdata->phy_init_seq;
403 }
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +0530404
405 if (!seq)
406 return;
407
408 while (seq[0] >= 0) {
Mayank Rana443f9e42012-09-21 18:32:39 +0530409 if (override_phy_init)
410 pr_debug("ulpi: write 0x%02x to 0x%02x\n",
411 seq[0], seq[1]);
412
Heikki Krogerus1d4c9292012-02-13 13:24:09 +0200413 dev_vdbg(motg->phy.dev, "ulpi: write 0x%02x to 0x%02x\n",
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +0530414 seq[0], seq[1]);
Heikki Krogerus1d4c9292012-02-13 13:24:09 +0200415 ulpi_write(&motg->phy, seq[0], seq[1]);
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +0530416 seq += 2;
417 }
418}
419
420static int msm_otg_link_clk_reset(struct msm_otg *motg, bool assert)
421{
422 int ret;
423
424 if (assert) {
Manu Gautam5025ff12012-07-20 10:56:50 +0530425 if (!IS_ERR(motg->clk)) {
426 ret = clk_reset(motg->clk, CLK_RESET_ASSERT);
427 } else {
428 /* Using asynchronous block reset to the hardware */
429 dev_dbg(motg->phy.dev, "block_reset ASSERT\n");
430 clk_disable_unprepare(motg->pclk);
431 clk_disable_unprepare(motg->core_clk);
432 ret = clk_reset(motg->core_clk, CLK_RESET_ASSERT);
433 }
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +0530434 if (ret)
Heikki Krogerus1d4c9292012-02-13 13:24:09 +0200435 dev_err(motg->phy.dev, "usb hs_clk assert failed\n");
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +0530436 } else {
Manu Gautam5025ff12012-07-20 10:56:50 +0530437 if (!IS_ERR(motg->clk)) {
438 ret = clk_reset(motg->clk, CLK_RESET_DEASSERT);
439 } else {
440 dev_dbg(motg->phy.dev, "block_reset DEASSERT\n");
441 ret = clk_reset(motg->core_clk, CLK_RESET_DEASSERT);
442 ndelay(200);
443 clk_prepare_enable(motg->core_clk);
444 clk_prepare_enable(motg->pclk);
445 }
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +0530446 if (ret)
Heikki Krogerus1d4c9292012-02-13 13:24:09 +0200447 dev_err(motg->phy.dev, "usb hs_clk deassert failed\n");
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +0530448 }
449 return ret;
450}
451
452static int msm_otg_phy_clk_reset(struct msm_otg *motg)
453{
454 int ret;
455
Amit Blay02eff132011-09-21 16:46:24 +0300456 if (IS_ERR(motg->phy_reset_clk))
457 return 0;
458
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +0530459 ret = clk_reset(motg->phy_reset_clk, CLK_RESET_ASSERT);
460 if (ret) {
Heikki Krogerus1d4c9292012-02-13 13:24:09 +0200461 dev_err(motg->phy.dev, "usb phy clk assert failed\n");
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +0530462 return ret;
463 }
464 usleep_range(10000, 12000);
465 ret = clk_reset(motg->phy_reset_clk, CLK_RESET_DEASSERT);
466 if (ret)
Heikki Krogerus1d4c9292012-02-13 13:24:09 +0200467 dev_err(motg->phy.dev, "usb phy clk deassert failed\n");
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +0530468 return ret;
469}
470
471static int msm_otg_phy_reset(struct msm_otg *motg)
472{
473 u32 val;
474 int ret;
475 int retries;
476
477 ret = msm_otg_link_clk_reset(motg, 1);
478 if (ret)
479 return ret;
480 ret = msm_otg_phy_clk_reset(motg);
481 if (ret)
482 return ret;
483 ret = msm_otg_link_clk_reset(motg, 0);
484 if (ret)
485 return ret;
486
487 val = readl(USB_PORTSC) & ~PORTSC_PTS_MASK;
488 writel(val | PORTSC_PTS_ULPI, USB_PORTSC);
489
490 for (retries = 3; retries > 0; retries--) {
Heikki Krogerus1d4c9292012-02-13 13:24:09 +0200491 ret = ulpi_write(&motg->phy, ULPI_FUNC_CTRL_SUSPENDM,
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +0530492 ULPI_CLR(ULPI_FUNC_CTRL));
493 if (!ret)
494 break;
495 ret = msm_otg_phy_clk_reset(motg);
496 if (ret)
497 return ret;
498 }
499 if (!retries)
500 return -ETIMEDOUT;
501
502 /* This reset calibrates the phy, if the above write succeeded */
503 ret = msm_otg_phy_clk_reset(motg);
504 if (ret)
505 return ret;
506
507 for (retries = 3; retries > 0; retries--) {
Heikki Krogerus1d4c9292012-02-13 13:24:09 +0200508 ret = ulpi_read(&motg->phy, ULPI_DEBUG);
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +0530509 if (ret != -ETIMEDOUT)
510 break;
511 ret = msm_otg_phy_clk_reset(motg);
512 if (ret)
513 return ret;
514 }
515 if (!retries)
516 return -ETIMEDOUT;
517
Heikki Krogerus1d4c9292012-02-13 13:24:09 +0200518 dev_info(motg->phy.dev, "phy_reset: success\n");
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +0530519 return 0;
520}
521
522#define LINK_RESET_TIMEOUT_USEC (250 * 1000)
Pavankumar Kondetiaa449e12011-11-04 11:09:26 +0530523static int msm_otg_link_reset(struct msm_otg *motg)
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +0530524{
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +0530525 int cnt = 0;
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +0530526
Pavankumar Kondetiaa449e12011-11-04 11:09:26 +0530527 writel_relaxed(USBCMD_RESET, USB_USBCMD);
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +0530528 while (cnt < LINK_RESET_TIMEOUT_USEC) {
Pavankumar Kondetiaa449e12011-11-04 11:09:26 +0530529 if (!(readl_relaxed(USB_USBCMD) & USBCMD_RESET))
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +0530530 break;
531 udelay(1);
532 cnt++;
533 }
534 if (cnt >= LINK_RESET_TIMEOUT_USEC)
535 return -ETIMEDOUT;
536
537 /* select ULPI phy */
Pavankumar Kondetiaa449e12011-11-04 11:09:26 +0530538 writel_relaxed(0x80000000, USB_PORTSC);
539 writel_relaxed(0x0, USB_AHBBURST);
Vijayavardhan Vennapusa5f32d7a2012-03-14 16:30:26 +0530540 writel_relaxed(0x08, USB_AHBMODE);
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +0530541
Pavankumar Kondetiaa449e12011-11-04 11:09:26 +0530542 return 0;
543}
544
Steve Mucklef132c6c2012-06-06 18:30:57 -0700545static int msm_otg_reset(struct usb_phy *phy)
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +0530546{
Steve Mucklef132c6c2012-06-06 18:30:57 -0700547 struct msm_otg *motg = container_of(phy, struct msm_otg, phy);
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +0530548 struct msm_otg_platform_data *pdata = motg->pdata;
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +0530549 int ret;
550 u32 val = 0;
551 u32 ulpi_val = 0;
552
Ofir Cohen4da266f2012-01-03 10:19:29 +0200553 /*
554 * USB PHY and Link reset also reset the USB BAM.
555 * Thus perform reset operation only once to avoid
556 * USB BAM reset on other cases e.g. USB cable disconnections.
557 */
558 if (pdata->disable_reset_on_disconnect) {
559 if (motg->reset_counter)
560 return 0;
561 else
562 motg->reset_counter++;
563 }
564
Pavankumar Kondeti923262e2012-04-20 15:34:24 +0530565 if (!IS_ERR(motg->clk))
566 clk_prepare_enable(motg->clk);
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +0530567 ret = msm_otg_phy_reset(motg);
568 if (ret) {
Steve Mucklef132c6c2012-06-06 18:30:57 -0700569 dev_err(phy->dev, "phy_reset failed\n");
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +0530570 return ret;
571 }
572
Pavankumar Kondeti4960f312011-12-06 15:46:14 +0530573 aca_id_turned_on = false;
Pavankumar Kondetiaa449e12011-11-04 11:09:26 +0530574 ret = msm_otg_link_reset(motg);
575 if (ret) {
Steve Mucklef132c6c2012-06-06 18:30:57 -0700576 dev_err(phy->dev, "link reset failed\n");
Pavankumar Kondetiaa449e12011-11-04 11:09:26 +0530577 return ret;
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +0530578 }
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +0530579 msleep(100);
580
Anji jonnalaa8b8d732011-12-06 10:03:24 +0530581 ulpi_init(motg);
582
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700583 /* Ensure that RESET operation is completed before turning off clock */
584 mb();
Pavankumar Kondetiaa449e12011-11-04 11:09:26 +0530585
Pavankumar Kondeti923262e2012-04-20 15:34:24 +0530586 if (!IS_ERR(motg->clk))
587 clk_disable_unprepare(motg->clk);
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +0530588
589 if (pdata->otg_control == OTG_PHY_CONTROL) {
Pavankumar Kondeti4960f312011-12-06 15:46:14 +0530590 val = readl_relaxed(USB_OTGSC);
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +0530591 if (pdata->mode == USB_OTG) {
592 ulpi_val = ULPI_INT_IDGRD | ULPI_INT_SESS_VALID;
593 val |= OTGSC_IDIE | OTGSC_BSVIE;
594 } else if (pdata->mode == USB_PERIPHERAL) {
595 ulpi_val = ULPI_INT_SESS_VALID;
596 val |= OTGSC_BSVIE;
597 }
Pavankumar Kondeti4960f312011-12-06 15:46:14 +0530598 writel_relaxed(val, USB_OTGSC);
Heikki Krogerus1d4c9292012-02-13 13:24:09 +0200599 ulpi_write(phy, ulpi_val, ULPI_USB_INT_EN_RISE);
600 ulpi_write(phy, ulpi_val, ULPI_USB_INT_EN_FALL);
Pavankumar Kondeti446f4542012-02-01 13:57:13 +0530601 } else if (pdata->otg_control == OTG_PMIC_CONTROL) {
Steve Mucklef132c6c2012-06-06 18:30:57 -0700602 ulpi_write(phy, OTG_COMP_DISABLE,
Vijayavardhan Vennapusa03171c72012-04-26 14:44:48 +0530603 ULPI_SET(ULPI_PWR_CLK_MNG_REG));
Pavankumar Kondeti446f4542012-02-01 13:57:13 +0530604 /* Enable PMIC pull-up */
605 pm8xxx_usb_id_pullup(1);
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +0530606 }
607
608 return 0;
609}
610
Vijayavardhan Vennapusaa3152032012-03-05 16:29:30 +0530611static const char *timer_string(int bit)
612{
613 switch (bit) {
614 case A_WAIT_VRISE: return "a_wait_vrise";
615 case A_WAIT_VFALL: return "a_wait_vfall";
616 case B_SRP_FAIL: return "b_srp_fail";
617 case A_WAIT_BCON: return "a_wait_bcon";
618 case A_AIDL_BDIS: return "a_aidl_bdis";
619 case A_BIDL_ADIS: return "a_bidl_adis";
620 case B_ASE0_BRST: return "b_ase0_brst";
621 case A_TST_MAINT: return "a_tst_maint";
622 case B_TST_SRP: return "b_tst_srp";
623 case B_TST_CONFIG: return "b_tst_config";
624 default: return "UNDEFINED";
625 }
626}
627
628static enum hrtimer_restart msm_otg_timer_func(struct hrtimer *hrtimer)
629{
630 struct msm_otg *motg = container_of(hrtimer, struct msm_otg, timer);
631
632 switch (motg->active_tmout) {
633 case A_WAIT_VRISE:
634 /* TODO: use vbus_vld interrupt */
635 set_bit(A_VBUS_VLD, &motg->inputs);
636 break;
637 case A_TST_MAINT:
638 /* OTG PET: End session after TA_TST_MAINT */
639 set_bit(A_BUS_DROP, &motg->inputs);
640 break;
641 case B_TST_SRP:
642 /*
643 * OTG PET: Initiate SRP after TB_TST_SRP of
644 * previous session end.
645 */
646 set_bit(B_BUS_REQ, &motg->inputs);
647 break;
648 case B_TST_CONFIG:
649 clear_bit(A_CONN, &motg->inputs);
650 break;
651 default:
652 set_bit(motg->active_tmout, &motg->tmouts);
653 }
654
655 pr_debug("expired %s timer\n", timer_string(motg->active_tmout));
656 queue_work(system_nrt_wq, &motg->sm_work);
657 return HRTIMER_NORESTART;
658}
659
660static void msm_otg_del_timer(struct msm_otg *motg)
661{
662 int bit = motg->active_tmout;
663
664 pr_debug("deleting %s timer. remaining %lld msec\n", timer_string(bit),
665 div_s64(ktime_to_us(hrtimer_get_remaining(
666 &motg->timer)), 1000));
667 hrtimer_cancel(&motg->timer);
668 clear_bit(bit, &motg->tmouts);
669}
670
671static void msm_otg_start_timer(struct msm_otg *motg, int time, int bit)
672{
673 clear_bit(bit, &motg->tmouts);
674 motg->active_tmout = bit;
675 pr_debug("starting %s timer\n", timer_string(bit));
676 hrtimer_start(&motg->timer,
677 ktime_set(time / 1000, (time % 1000) * 1000000),
678 HRTIMER_MODE_REL);
679}
680
681static void msm_otg_init_timer(struct msm_otg *motg)
682{
683 hrtimer_init(&motg->timer, CLOCK_MONOTONIC, HRTIMER_MODE_REL);
684 motg->timer.function = msm_otg_timer_func;
685}
686
Steve Mucklef132c6c2012-06-06 18:30:57 -0700687static int msm_otg_start_hnp(struct usb_otg *otg)
Vijayavardhan Vennapusaa3152032012-03-05 16:29:30 +0530688{
Steve Mucklef132c6c2012-06-06 18:30:57 -0700689 struct msm_otg *motg = container_of(otg->phy, struct msm_otg, phy);
Vijayavardhan Vennapusaa3152032012-03-05 16:29:30 +0530690
Steve Mucklef132c6c2012-06-06 18:30:57 -0700691 if (otg->phy->state != OTG_STATE_A_HOST) {
Vijayavardhan Vennapusaa3152032012-03-05 16:29:30 +0530692 pr_err("HNP can not be initiated in %s state\n",
Steve Mucklef132c6c2012-06-06 18:30:57 -0700693 otg_state_string(otg->phy->state));
Vijayavardhan Vennapusaa3152032012-03-05 16:29:30 +0530694 return -EINVAL;
695 }
696
697 pr_debug("A-Host: HNP initiated\n");
698 clear_bit(A_BUS_REQ, &motg->inputs);
699 queue_work(system_nrt_wq, &motg->sm_work);
700 return 0;
701}
702
Steve Mucklef132c6c2012-06-06 18:30:57 -0700703static int msm_otg_start_srp(struct usb_otg *otg)
Vijayavardhan Vennapusaa3152032012-03-05 16:29:30 +0530704{
Steve Mucklef132c6c2012-06-06 18:30:57 -0700705 struct msm_otg *motg = container_of(otg->phy, struct msm_otg, phy);
Vijayavardhan Vennapusaa3152032012-03-05 16:29:30 +0530706 u32 val;
707 int ret = 0;
708
Steve Mucklef132c6c2012-06-06 18:30:57 -0700709 if (otg->phy->state != OTG_STATE_B_IDLE) {
Vijayavardhan Vennapusaa3152032012-03-05 16:29:30 +0530710 pr_err("SRP can not be initiated in %s state\n",
Steve Mucklef132c6c2012-06-06 18:30:57 -0700711 otg_state_string(otg->phy->state));
Vijayavardhan Vennapusaa3152032012-03-05 16:29:30 +0530712 ret = -EINVAL;
713 goto out;
714 }
715
716 if ((jiffies - motg->b_last_se0_sess) < msecs_to_jiffies(TB_SRP_INIT)) {
717 pr_debug("initial conditions of SRP are not met. Try again"
718 "after some time\n");
719 ret = -EAGAIN;
720 goto out;
721 }
722
723 pr_debug("B-Device SRP started\n");
724
725 /*
726 * PHY won't pull D+ high unless it detects Vbus valid.
727 * Since by definition, SRP is only done when Vbus is not valid,
728 * software work-around needs to be used to spoof the PHY into
729 * thinking it is valid. This can be done using the VBUSVLDEXTSEL and
730 * VBUSVLDEXT register bits.
731 */
Steve Mucklef132c6c2012-06-06 18:30:57 -0700732 ulpi_write(otg->phy, 0x03, 0x97);
Vijayavardhan Vennapusaa3152032012-03-05 16:29:30 +0530733 /*
734 * Harware auto assist data pulsing: Data pulse is given
735 * for 7msec; wait for vbus
736 */
737 val = readl_relaxed(USB_OTGSC);
738 writel_relaxed((val & ~OTGSC_INTSTS_MASK) | OTGSC_HADP, USB_OTGSC);
739
740 /* VBUS plusing is obsoleted in OTG 2.0 supplement */
741out:
742 return ret;
743}
744
Steve Mucklef132c6c2012-06-06 18:30:57 -0700745static void msm_otg_host_hnp_enable(struct usb_otg *otg, bool enable)
Vijayavardhan Vennapusaa3152032012-03-05 16:29:30 +0530746{
747 struct usb_hcd *hcd = bus_to_hcd(otg->host);
748 struct usb_device *rhub = otg->host->root_hub;
749
750 if (enable) {
751 pm_runtime_disable(&rhub->dev);
752 rhub->state = USB_STATE_NOTATTACHED;
753 hcd->driver->bus_suspend(hcd);
754 clear_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags);
755 } else {
756 usb_remove_hcd(hcd);
Steve Mucklef132c6c2012-06-06 18:30:57 -0700757 msm_otg_reset(otg->phy);
Vijayavardhan Vennapusaa3152032012-03-05 16:29:30 +0530758 usb_add_hcd(hcd, hcd->irq, IRQF_SHARED);
759 }
760}
761
Steve Mucklef132c6c2012-06-06 18:30:57 -0700762static int msm_otg_set_suspend(struct usb_phy *phy, int suspend)
Pavankumar Kondeti8be99cf2011-08-04 10:48:08 +0530763{
Steve Mucklef132c6c2012-06-06 18:30:57 -0700764 struct msm_otg *motg = container_of(phy, struct msm_otg, phy);
Pavankumar Kondeti8be99cf2011-08-04 10:48:08 +0530765
Amit Blay6fa647a2012-05-24 14:12:08 +0300766 if (aca_enabled())
Vijayavardhan Vennapusaa3152032012-03-05 16:29:30 +0530767 return 0;
Pavankumar Kondeti8be99cf2011-08-04 10:48:08 +0530768
Amit Blayd0fe07b2012-09-05 16:42:09 +0300769 if (atomic_read(&motg->in_lpm) == suspend &&
770 !atomic_read(&motg->suspend_work_pending))
Jack Pham69e621d2012-06-25 18:48:07 -0700771 return 0;
772
Vijayavardhan Vennapusaa3152032012-03-05 16:29:30 +0530773 if (suspend) {
Steve Mucklef132c6c2012-06-06 18:30:57 -0700774 switch (phy->state) {
Vijayavardhan Vennapusaa3152032012-03-05 16:29:30 +0530775 case OTG_STATE_A_WAIT_BCON:
776 if (TA_WAIT_BCON > 0)
777 break;
778 /* fall through */
779 case OTG_STATE_A_HOST:
780 pr_debug("host bus suspend\n");
781 clear_bit(A_BUS_REQ, &motg->inputs);
782 queue_work(system_nrt_wq, &motg->sm_work);
783 break;
Amit Blay6fa647a2012-05-24 14:12:08 +0300784 case OTG_STATE_B_PERIPHERAL:
785 pr_debug("peripheral bus suspend\n");
786 if (!(motg->caps & ALLOW_LPM_ON_DEV_SUSPEND))
787 break;
788 set_bit(A_BUS_SUSPEND, &motg->inputs);
Amit Blayd0fe07b2012-09-05 16:42:09 +0300789 atomic_set(&motg->suspend_work_pending, 1);
790 queue_delayed_work(system_nrt_wq, &motg->suspend_work,
791 USB_SUSPEND_DELAY_TIME);
Amit Blay6fa647a2012-05-24 14:12:08 +0300792 break;
793
Vijayavardhan Vennapusaa3152032012-03-05 16:29:30 +0530794 default:
795 break;
796 }
797 } else {
Steve Mucklef132c6c2012-06-06 18:30:57 -0700798 switch (phy->state) {
Vijayavardhan Vennapusaa3152032012-03-05 16:29:30 +0530799 case OTG_STATE_A_SUSPEND:
800 /* Remote wakeup or resume */
801 set_bit(A_BUS_REQ, &motg->inputs);
Steve Mucklef132c6c2012-06-06 18:30:57 -0700802 phy->state = OTG_STATE_A_HOST;
Jack Pham5ca279b2012-05-14 18:42:54 -0700803
804 /* ensure hardware is not in low power mode */
Steve Mucklef132c6c2012-06-06 18:30:57 -0700805 pm_runtime_resume(phy->dev);
Vijayavardhan Vennapusaa3152032012-03-05 16:29:30 +0530806 break;
Amit Blay6fa647a2012-05-24 14:12:08 +0300807 case OTG_STATE_B_PERIPHERAL:
808 pr_debug("peripheral bus resume\n");
809 if (!(motg->caps & ALLOW_LPM_ON_DEV_SUSPEND))
810 break;
811 clear_bit(A_BUS_SUSPEND, &motg->inputs);
812 queue_work(system_nrt_wq, &motg->sm_work);
813 break;
Vijayavardhan Vennapusaa3152032012-03-05 16:29:30 +0530814 default:
815 break;
816 }
817 }
Pavankumar Kondeti8be99cf2011-08-04 10:48:08 +0530818 return 0;
819}
820
Pavankumar Kondeti87c01042010-12-07 17:53:58 +0530821#define PHY_SUSPEND_TIMEOUT_USEC (500 * 1000)
Pavankumar Kondeti70187732011-02-15 09:42:34 +0530822#define PHY_RESUME_TIMEOUT_USEC (100 * 1000)
823
824#ifdef CONFIG_PM_SLEEP
Pavankumar Kondeti87c01042010-12-07 17:53:58 +0530825static int msm_otg_suspend(struct msm_otg *motg)
826{
Heikki Krogerus1d4c9292012-02-13 13:24:09 +0200827 struct usb_phy *phy = &motg->phy;
828 struct usb_bus *bus = phy->otg->host;
Pavankumar Kondeti87c01042010-12-07 17:53:58 +0530829 struct msm_otg_platform_data *pdata = motg->pdata;
830 int cnt = 0;
Amit Blay6fa647a2012-05-24 14:12:08 +0300831 bool host_bus_suspend, device_bus_suspend, dcp;
Pavankumar Kondeti4960f312011-12-06 15:46:14 +0530832 u32 phy_ctrl_val = 0, cmd_val;
Stephen Boyd30ad10b2012-03-01 14:51:04 -0800833 unsigned ret;
Rajkumar Raghupathy242565d2011-12-13 12:10:59 +0530834 u32 portsc;
Pavankumar Kondeti87c01042010-12-07 17:53:58 +0530835
836 if (atomic_read(&motg->in_lpm))
837 return 0;
838
839 disable_irq(motg->irq);
Pavankumar Kondeti2aec9f32012-06-13 09:06:03 +0530840 host_bus_suspend = !test_bit(MHL, &motg->inputs) && phy->otg->host &&
841 !test_bit(ID, &motg->inputs);
Steve Mucklef132c6c2012-06-06 18:30:57 -0700842 device_bus_suspend = phy->otg->gadget && test_bit(ID, &motg->inputs) &&
Amit Blay6fa647a2012-05-24 14:12:08 +0300843 test_bit(A_BUS_SUSPEND, &motg->inputs) &&
844 motg->caps & ALLOW_LPM_ON_DEV_SUSPEND;
Pavankumar Kondeti283146f2012-01-12 12:51:19 +0530845 dcp = motg->chg_type == USB_DCP_CHARGER;
Jack Pham502bea32012-08-13 15:34:20 -0700846
847 /* charging detection in progress due to cable plug-in */
848 if (test_bit(B_SESS_VLD, &motg->inputs) && !device_bus_suspend &&
849 !dcp) {
850 enable_irq(motg->irq);
851 return -EBUSY;
852 }
853
Pavankumar Kondeti87c01042010-12-07 17:53:58 +0530854 /*
Pavankumar Kondeti04aebcb2011-05-04 10:19:49 +0530855 * Chipidea 45-nm PHY suspend sequence:
856 *
Pavankumar Kondeti87c01042010-12-07 17:53:58 +0530857 * Interrupt Latch Register auto-clear feature is not present
858 * in all PHY versions. Latch register is clear on read type.
859 * Clear latch register to avoid spurious wakeup from
860 * low power mode (LPM).
Pavankumar Kondeti04aebcb2011-05-04 10:19:49 +0530861 *
Pavankumar Kondeti87c01042010-12-07 17:53:58 +0530862 * PHY comparators are disabled when PHY enters into low power
863 * mode (LPM). Keep PHY comparators ON in LPM only when we expect
864 * VBUS/Id notifications from USB PHY. Otherwise turn off USB
865 * PHY comparators. This save significant amount of power.
Pavankumar Kondeti04aebcb2011-05-04 10:19:49 +0530866 *
Pavankumar Kondeti87c01042010-12-07 17:53:58 +0530867 * PLL is not turned off when PHY enters into low power mode (LPM).
868 * Disable PLL for maximum power savings.
869 */
Pavankumar Kondeti04aebcb2011-05-04 10:19:49 +0530870
871 if (motg->pdata->phy_type == CI_45NM_INTEGRATED_PHY) {
Heikki Krogerus1d4c9292012-02-13 13:24:09 +0200872 ulpi_read(phy, 0x14);
Pavankumar Kondeti04aebcb2011-05-04 10:19:49 +0530873 if (pdata->otg_control == OTG_PHY_CONTROL)
Heikki Krogerus1d4c9292012-02-13 13:24:09 +0200874 ulpi_write(phy, 0x01, 0x30);
875 ulpi_write(phy, 0x08, 0x09);
Pavankumar Kondeti04aebcb2011-05-04 10:19:49 +0530876 }
Pavankumar Kondeti87c01042010-12-07 17:53:58 +0530877
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700878
Rajkumar Raghupathy242565d2011-12-13 12:10:59 +0530879 /* Set the PHCD bit, only if it is not set by the controller.
Pavankumar Kondeti87c01042010-12-07 17:53:58 +0530880 * PHY may take some time or even fail to enter into low power
881 * mode (LPM). Hence poll for 500 msec and reset the PHY and link
882 * in failure case.
883 */
Rajkumar Raghupathy242565d2011-12-13 12:10:59 +0530884 portsc = readl_relaxed(USB_PORTSC);
885 if (!(portsc & PORTSC_PHCD)) {
886 writel_relaxed(portsc | PORTSC_PHCD,
887 USB_PORTSC);
888 while (cnt < PHY_SUSPEND_TIMEOUT_USEC) {
889 if (readl_relaxed(USB_PORTSC) & PORTSC_PHCD)
890 break;
891 udelay(1);
892 cnt++;
893 }
Pavankumar Kondeti87c01042010-12-07 17:53:58 +0530894 }
895
896 if (cnt >= PHY_SUSPEND_TIMEOUT_USEC) {
Heikki Krogerus1d4c9292012-02-13 13:24:09 +0200897 dev_err(phy->dev, "Unable to suspend PHY\n");
898 msm_otg_reset(phy);
Pavankumar Kondeti87c01042010-12-07 17:53:58 +0530899 enable_irq(motg->irq);
900 return -ETIMEDOUT;
901 }
902
903 /*
904 * PHY has capability to generate interrupt asynchronously in low
905 * power mode (LPM). This interrupt is level triggered. So USB IRQ
906 * line must be disabled till async interrupt enable bit is cleared
907 * in USBCMD register. Assert STP (ULPI interface STOP signal) to
908 * block data communication from PHY.
Pavankumar Kondeti6be675f2012-04-16 13:29:24 +0530909 *
910 * PHY retention mode is disallowed while entering to LPM with wall
911 * charger connected. But PHY is put into suspend mode. Hence
912 * enable asynchronous interrupt to detect charger disconnection when
913 * PMIC notifications are unavailable.
Pavankumar Kondeti87c01042010-12-07 17:53:58 +0530914 */
Pavankumar Kondeti4960f312011-12-06 15:46:14 +0530915 cmd_val = readl_relaxed(USB_USBCMD);
Amit Blay6fa647a2012-05-24 14:12:08 +0300916 if (host_bus_suspend || device_bus_suspend ||
917 (motg->pdata->otg_control == OTG_PHY_CONTROL && dcp))
Pavankumar Kondeti4960f312011-12-06 15:46:14 +0530918 cmd_val |= ASYNC_INTR_CTRL | ULPI_STP_CTRL;
919 else
920 cmd_val |= ULPI_STP_CTRL;
921 writel_relaxed(cmd_val, USB_USBCMD);
Pavankumar Kondeti87c01042010-12-07 17:53:58 +0530922
Pavankumar Kondeti283146f2012-01-12 12:51:19 +0530923 /*
924 * BC1.2 spec mandates PD to enable VDP_SRC when charging from DCP.
925 * PHY retention and collapse can not happen with VDP_SRC enabled.
926 */
Amit Blay6fa647a2012-05-24 14:12:08 +0300927 if (motg->caps & ALLOW_PHY_RETENTION && !host_bus_suspend &&
928 !device_bus_suspend && !dcp) {
Amit Blay58b31472011-11-18 09:39:39 +0200929 phy_ctrl_val = readl_relaxed(USB_PHY_CTRL);
Vijayavardhan Vennapusa9ab6f972012-10-11 19:18:55 +0530930 if (motg->pdata->otg_control == OTG_PHY_CONTROL) {
Amit Blay58b31472011-11-18 09:39:39 +0200931 /* Enable PHY HV interrupts to wake MPM/Link */
Vijayavardhan Vennapusa9ab6f972012-10-11 19:18:55 +0530932 if ((motg->pdata->mode == USB_OTG) ||
933 (motg->pdata->mode == USB_HOST))
934 phy_ctrl_val |= (PHY_IDHV_INTEN |
935 PHY_OTGSESSVLDHV_INTEN);
936 else
937 phy_ctrl_val |= PHY_OTGSESSVLDHV_INTEN;
938 }
Pavankumar Kondeti04aebcb2011-05-04 10:19:49 +0530939
Amit Blay58b31472011-11-18 09:39:39 +0200940 writel_relaxed(phy_ctrl_val & ~PHY_RETEN, USB_PHY_CTRL);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700941 motg->lpm_flags |= PHY_RETENTIONED;
Pavankumar Kondeti04aebcb2011-05-04 10:19:49 +0530942 }
943
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700944 /* Ensure that above operation is completed before turning off clocks */
945 mb();
Ido Shayevitzc5c0f572012-07-31 13:58:45 +0300946 /* Consider clocks on workaround flag only in case of bus suspend */
947 if (!(phy->state == OTG_STATE_B_PERIPHERAL &&
948 test_bit(A_BUS_SUSPEND, &motg->inputs)) ||
949 !motg->pdata->core_clk_always_on_workaround) {
Amit Blay9b6e58b2012-06-18 13:12:49 +0300950 clk_disable_unprepare(motg->pclk);
951 clk_disable_unprepare(motg->core_clk);
Ido Shayevitzc5c0f572012-07-31 13:58:45 +0300952 motg->lpm_flags |= CLOCKS_DOWN;
Amit Blay9b6e58b2012-06-18 13:12:49 +0300953 }
Pavankumar Kondeti87c01042010-12-07 17:53:58 +0530954
Anji jonnala7da3f262011-12-02 17:22:14 -0800955 /* usb phy no more require TCXO clock, hence vote for TCXO disable */
Vijayavardhan Vennapusabbdd6082012-06-06 14:14:25 +0530956 if (!host_bus_suspend) {
957 ret = msm_xo_mode_vote(motg->xo_handle, MSM_XO_MODE_OFF);
958 if (ret)
Steve Muckle75c34ca2012-06-12 14:27:40 -0700959 dev_err(phy->dev, "%s failed to devote for "
Vijayavardhan Vennapusabbdd6082012-06-06 14:14:25 +0530960 "TCXO D0 buffer%d\n", __func__, ret);
961 else
962 motg->lpm_flags |= XO_SHUTDOWN;
963 }
Anji jonnala7da3f262011-12-02 17:22:14 -0800964
Pavankumar Kondeti283146f2012-01-12 12:51:19 +0530965 if (motg->caps & ALLOW_PHY_POWER_COLLAPSE &&
966 !host_bus_suspend && !dcp) {
Amit Blay81801aa2012-09-19 12:08:12 +0200967 msm_hsusb_ldo_enable(motg, USB_PHY_REG_OFF);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700968 motg->lpm_flags |= PHY_PWR_COLLAPSED;
Amit Blay81801aa2012-09-19 12:08:12 +0200969 } else if (motg->caps & ALLOW_PHY_REGULATORS_LPM &&
970 !host_bus_suspend && !device_bus_suspend && !dcp) {
971 msm_hsusb_ldo_enable(motg, USB_PHY_REG_LPM_ON);
972 motg->lpm_flags |= PHY_REGULATORS_LPM;
Anji jonnala0f73cac2011-05-04 10:19:46 +0530973 }
974
Vijayavardhan Vennapusafc464f02011-11-04 21:54:00 +0530975 if (motg->lpm_flags & PHY_RETENTIONED) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700976 msm_hsusb_config_vddcx(0);
Vijayavardhan Vennapusafc464f02011-11-04 21:54:00 +0530977 msm_hsusb_mhl_switch_enable(motg, 0);
978 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700979
Steve Mucklef132c6c2012-06-06 18:30:57 -0700980 if (device_may_wakeup(phy->dev)) {
Pavankumar Kondeti87c01042010-12-07 17:53:58 +0530981 enable_irq_wake(motg->irq);
Manu Gautamf8c45642012-08-10 10:20:56 -0700982 if (motg->async_irq)
983 enable_irq_wake(motg->async_irq);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700984 if (motg->pdata->pmic_id_irq)
985 enable_irq_wake(motg->pdata->pmic_id_irq);
Jack Pham87f202f2012-08-06 00:24:22 -0700986 if (pdata->otg_control == OTG_PHY_CONTROL &&
987 pdata->mpm_otgsessvld_int)
988 msm_mpm_set_pin_wake(pdata->mpm_otgsessvld_int, 1);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700989 }
Pavankumar Kondeti87c01042010-12-07 17:53:58 +0530990 if (bus)
991 clear_bit(HCD_FLAG_HW_ACCESSIBLE, &(bus_to_hcd(bus))->flags);
992
993 atomic_set(&motg->in_lpm, 1);
Manu Gautamf8c45642012-08-10 10:20:56 -0700994 /* Enable ASYNC IRQ (if present) during LPM */
995 if (motg->async_irq)
996 enable_irq(motg->async_irq);
Pavankumar Kondeti87c01042010-12-07 17:53:58 +0530997 enable_irq(motg->irq);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700998 wake_unlock(&motg->wlock);
Pavankumar Kondeti87c01042010-12-07 17:53:58 +0530999
Heikki Krogerus1d4c9292012-02-13 13:24:09 +02001000 dev_info(phy->dev, "USB in low power mode\n");
Pavankumar Kondeti87c01042010-12-07 17:53:58 +05301001
1002 return 0;
1003}
1004
Pavankumar Kondeti87c01042010-12-07 17:53:58 +05301005static int msm_otg_resume(struct msm_otg *motg)
1006{
Heikki Krogerus1d4c9292012-02-13 13:24:09 +02001007 struct usb_phy *phy = &motg->phy;
1008 struct usb_bus *bus = phy->otg->host;
Jack Pham87f202f2012-08-06 00:24:22 -07001009 struct msm_otg_platform_data *pdata = motg->pdata;
Pavankumar Kondeti87c01042010-12-07 17:53:58 +05301010 int cnt = 0;
1011 unsigned temp;
Amit Blay58b31472011-11-18 09:39:39 +02001012 u32 phy_ctrl_val = 0;
Anji jonnala7da3f262011-12-02 17:22:14 -08001013 unsigned ret;
Pavankumar Kondeti87c01042010-12-07 17:53:58 +05301014
1015 if (!atomic_read(&motg->in_lpm))
1016 return 0;
1017
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001018 wake_lock(&motg->wlock);
Anji jonnala0f73cac2011-05-04 10:19:46 +05301019
Anji jonnala7da3f262011-12-02 17:22:14 -08001020 /* Vote for TCXO when waking up the phy */
Vijayavardhan Vennapusabbdd6082012-06-06 14:14:25 +05301021 if (motg->lpm_flags & XO_SHUTDOWN) {
1022 ret = msm_xo_mode_vote(motg->xo_handle, MSM_XO_MODE_ON);
1023 if (ret)
Steve Muckle75c34ca2012-06-12 14:27:40 -07001024 dev_err(phy->dev, "%s failed to vote for "
Vijayavardhan Vennapusabbdd6082012-06-06 14:14:25 +05301025 "TCXO D0 buffer%d\n", __func__, ret);
1026 motg->lpm_flags &= ~XO_SHUTDOWN;
1027 }
Pavankumar Kondeti87c01042010-12-07 17:53:58 +05301028
Ido Shayevitzc5c0f572012-07-31 13:58:45 +03001029 if (motg->lpm_flags & CLOCKS_DOWN) {
Amit Blay9b6e58b2012-06-18 13:12:49 +03001030 clk_prepare_enable(motg->core_clk);
1031 clk_prepare_enable(motg->pclk);
Ido Shayevitzc5c0f572012-07-31 13:58:45 +03001032 motg->lpm_flags &= ~CLOCKS_DOWN;
Amit Blay9b6e58b2012-06-18 13:12:49 +03001033 }
Pavankumar Kondeti87c01042010-12-07 17:53:58 +05301034
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001035 if (motg->lpm_flags & PHY_PWR_COLLAPSED) {
Amit Blay81801aa2012-09-19 12:08:12 +02001036 msm_hsusb_ldo_enable(motg, USB_PHY_REG_ON);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001037 motg->lpm_flags &= ~PHY_PWR_COLLAPSED;
Amit Blay81801aa2012-09-19 12:08:12 +02001038 } else if (motg->lpm_flags & PHY_REGULATORS_LPM) {
1039 msm_hsusb_ldo_enable(motg, USB_PHY_REG_LPM_OFF);
1040 motg->lpm_flags &= ~PHY_REGULATORS_LPM;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001041 }
1042
1043 if (motg->lpm_flags & PHY_RETENTIONED) {
Vijayavardhan Vennapusafc464f02011-11-04 21:54:00 +05301044 msm_hsusb_mhl_switch_enable(motg, 1);
Pavankumar Kondeti04aebcb2011-05-04 10:19:49 +05301045 msm_hsusb_config_vddcx(1);
Amit Blay58b31472011-11-18 09:39:39 +02001046 phy_ctrl_val = readl_relaxed(USB_PHY_CTRL);
1047 phy_ctrl_val |= PHY_RETEN;
1048 if (motg->pdata->otg_control == OTG_PHY_CONTROL)
1049 /* Disable PHY HV interrupts */
1050 phy_ctrl_val &=
1051 ~(PHY_IDHV_INTEN | PHY_OTGSESSVLDHV_INTEN);
1052 writel_relaxed(phy_ctrl_val, USB_PHY_CTRL);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001053 motg->lpm_flags &= ~PHY_RETENTIONED;
Pavankumar Kondeti04aebcb2011-05-04 10:19:49 +05301054 }
1055
Pavankumar Kondeti87c01042010-12-07 17:53:58 +05301056 temp = readl(USB_USBCMD);
1057 temp &= ~ASYNC_INTR_CTRL;
1058 temp &= ~ULPI_STP_CTRL;
1059 writel(temp, USB_USBCMD);
1060
1061 /*
1062 * PHY comes out of low power mode (LPM) in case of wakeup
1063 * from asynchronous interrupt.
1064 */
1065 if (!(readl(USB_PORTSC) & PORTSC_PHCD))
1066 goto skip_phy_resume;
1067
1068 writel(readl(USB_PORTSC) & ~PORTSC_PHCD, USB_PORTSC);
1069 while (cnt < PHY_RESUME_TIMEOUT_USEC) {
1070 if (!(readl(USB_PORTSC) & PORTSC_PHCD))
1071 break;
1072 udelay(1);
1073 cnt++;
1074 }
1075
1076 if (cnt >= PHY_RESUME_TIMEOUT_USEC) {
1077 /*
1078 * This is a fatal error. Reset the link and
1079 * PHY. USB state can not be restored. Re-insertion
1080 * of USB cable is the only way to get USB working.
1081 */
Heikki Krogerus1d4c9292012-02-13 13:24:09 +02001082 dev_err(phy->dev, "Unable to resume USB."
Pavankumar Kondeti87c01042010-12-07 17:53:58 +05301083 "Re-plugin the cable\n");
Heikki Krogerus1d4c9292012-02-13 13:24:09 +02001084 msm_otg_reset(phy);
Pavankumar Kondeti87c01042010-12-07 17:53:58 +05301085 }
1086
1087skip_phy_resume:
Steve Mucklef132c6c2012-06-06 18:30:57 -07001088 if (device_may_wakeup(phy->dev)) {
Pavankumar Kondeti87c01042010-12-07 17:53:58 +05301089 disable_irq_wake(motg->irq);
Manu Gautamf8c45642012-08-10 10:20:56 -07001090 if (motg->async_irq)
1091 disable_irq_wake(motg->async_irq);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001092 if (motg->pdata->pmic_id_irq)
1093 disable_irq_wake(motg->pdata->pmic_id_irq);
Jack Pham87f202f2012-08-06 00:24:22 -07001094 if (pdata->otg_control == OTG_PHY_CONTROL &&
1095 pdata->mpm_otgsessvld_int)
1096 msm_mpm_set_pin_wake(pdata->mpm_otgsessvld_int, 0);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001097 }
Pavankumar Kondeti87c01042010-12-07 17:53:58 +05301098 if (bus)
1099 set_bit(HCD_FLAG_HW_ACCESSIBLE, &(bus_to_hcd(bus))->flags);
1100
Pavankumar Kondeti2ce2c3a2011-05-02 11:56:33 +05301101 atomic_set(&motg->in_lpm, 0);
1102
Pavankumar Kondeti87c01042010-12-07 17:53:58 +05301103 if (motg->async_int) {
Manu Gautamf8c45642012-08-10 10:20:56 -07001104 /* Match the disable_irq call from ISR */
1105 enable_irq(motg->async_int);
Pavankumar Kondeti87c01042010-12-07 17:53:58 +05301106 motg->async_int = 0;
Pavankumar Kondeti87c01042010-12-07 17:53:58 +05301107 }
1108
Manu Gautamf8c45642012-08-10 10:20:56 -07001109 /* If ASYNC IRQ is present then keep it enabled only during LPM */
1110 if (motg->async_irq)
1111 disable_irq(motg->async_irq);
1112
Heikki Krogerus1d4c9292012-02-13 13:24:09 +02001113 dev_info(phy->dev, "USB exited from low power mode\n");
Pavankumar Kondeti87c01042010-12-07 17:53:58 +05301114
1115 return 0;
1116}
Pavankumar Kondeti70187732011-02-15 09:42:34 +05301117#endif
Pavankumar Kondeti87c01042010-12-07 17:53:58 +05301118
David Keitel272ce522012-08-17 16:25:24 -07001119static void msm_otg_notify_host_mode(struct msm_otg *motg, bool host_mode)
Abhijeet Dharmapurikar5e96aaa2012-06-26 11:21:03 -07001120{
David Keitel272ce522012-08-17 16:25:24 -07001121 struct power_supply *usb = psy ? psy : &motg->usb_psy;
Sridhar Parasuram3c67a412012-09-26 09:36:22 -07001122
David Keitel272ce522012-08-17 16:25:24 -07001123 if (!usb) {
1124 pr_err("No USB power supply registered!\n");
1125 return;
1126 }
Sridhar Parasuram3c67a412012-09-26 09:36:22 -07001127
David Keitel272ce522012-08-17 16:25:24 -07001128 if (psy) {
1129 /* legacy support */
1130 if (host_mode)
1131 power_supply_set_scope(psy, POWER_SUPPLY_SCOPE_SYSTEM);
1132 else
1133 power_supply_set_scope(psy, POWER_SUPPLY_SCOPE_DEVICE);
1134 return;
1135 } else {
1136 motg->host_mode = host_mode;
1137 power_supply_changed(usb);
1138 }
Abhijeet Dharmapurikar5e96aaa2012-06-26 11:21:03 -07001139}
1140
David Keitel081a3e22012-04-18 12:37:07 -07001141static int msm_otg_notify_chg_type(struct msm_otg *motg)
1142{
1143 static int charger_type;
David Keitel272ce522012-08-17 16:25:24 -07001144 struct power_supply *usb = psy ? psy : &motg->usb_psy;
David Keitelba8f8322012-06-01 17:14:10 -07001145
David Keitel081a3e22012-04-18 12:37:07 -07001146 /*
1147 * TODO
1148 * Unify OTG driver charger types and power supply charger types
1149 */
1150 if (charger_type == motg->chg_type)
1151 return 0;
1152
1153 if (motg->chg_type == USB_SDP_CHARGER)
1154 charger_type = POWER_SUPPLY_TYPE_USB;
1155 else if (motg->chg_type == USB_CDP_CHARGER)
1156 charger_type = POWER_SUPPLY_TYPE_USB_CDP;
Pavankumar Kondeti9ec21d32012-05-07 15:50:23 +05301157 else if (motg->chg_type == USB_DCP_CHARGER ||
1158 motg->chg_type == USB_PROPRIETARY_CHARGER)
David Keitel081a3e22012-04-18 12:37:07 -07001159 charger_type = POWER_SUPPLY_TYPE_USB_DCP;
1160 else if ((motg->chg_type == USB_ACA_DOCK_CHARGER ||
1161 motg->chg_type == USB_ACA_A_CHARGER ||
1162 motg->chg_type == USB_ACA_B_CHARGER ||
1163 motg->chg_type == USB_ACA_C_CHARGER))
1164 charger_type = POWER_SUPPLY_TYPE_USB_ACA;
1165 else
1166 charger_type = POWER_SUPPLY_TYPE_BATTERY;
1167
David Keitel272ce522012-08-17 16:25:24 -07001168 if (!usb) {
David Keitelba8f8322012-06-01 17:14:10 -07001169 pr_err("No USB power supply registered!\n");
1170 return -EINVAL;
1171 }
1172
1173 pr_debug("setting usb power supply type %d\n", charger_type);
David Keitel272ce522012-08-17 16:25:24 -07001174 power_supply_set_supply_type(usb, charger_type);
David Keitelba8f8322012-06-01 17:14:10 -07001175 return 0;
David Keitel081a3e22012-04-18 12:37:07 -07001176}
1177
Amit Blay0f7edf72012-01-15 10:11:27 +02001178static int msm_otg_notify_power_supply(struct msm_otg *motg, unsigned mA)
1179{
David Keitel272ce522012-08-17 16:25:24 -07001180 struct power_supply *usb = psy ? psy : &motg->usb_psy;
Amit Blay0f7edf72012-01-15 10:11:27 +02001181
David Keitel272ce522012-08-17 16:25:24 -07001182 if (!usb) {
1183 dev_dbg(motg->phy.dev, "no usb power supply registered\n");
1184 goto psy_error;
David Keitelf5c5d602012-08-17 16:25:24 -07001185 }
1186
David Keitel272ce522012-08-17 16:25:24 -07001187 if (motg->cur_power == 0 && mA > 2) {
1188 /* Enable charging */
1189 if (power_supply_set_online(usb, true))
1190 goto psy_error;
1191 if (power_supply_set_current_limit(usb, 1000*mA))
1192 goto psy_error;
1193 } else if (motg->cur_power > 0 && (mA == 0 || mA == 2)) {
1194 /* Disable charging */
1195 if (power_supply_set_online(usb, false))
1196 goto psy_error;
1197 /* Set max current limit */
1198 if (power_supply_set_current_limit(usb, 0))
1199 goto psy_error;
1200 }
1201 power_supply_changed(usb);
Amit Blay0f7edf72012-01-15 10:11:27 +02001202 return 0;
1203
David Keitel272ce522012-08-17 16:25:24 -07001204psy_error:
1205 dev_dbg(motg->phy.dev, "power supply error when setting property\n");
Amit Blay0f7edf72012-01-15 10:11:27 +02001206 return -ENXIO;
1207}
1208
Pavankumar Kondetid8608522011-05-04 10:19:47 +05301209static void msm_otg_notify_charger(struct msm_otg *motg, unsigned mA)
1210{
Steve Mucklef132c6c2012-06-06 18:30:57 -07001211 struct usb_gadget *g = motg->phy.otg->gadget;
Vijayavardhan Vennapusaa3152032012-03-05 16:29:30 +05301212
1213 if (g && g->is_a_peripheral)
1214 return;
1215
Pavankumar Kondetiaa449e12011-11-04 11:09:26 +05301216 if ((motg->chg_type == USB_ACA_DOCK_CHARGER ||
1217 motg->chg_type == USB_ACA_A_CHARGER ||
1218 motg->chg_type == USB_ACA_B_CHARGER ||
1219 motg->chg_type == USB_ACA_C_CHARGER) &&
1220 mA > IDEV_ACA_CHG_LIMIT)
1221 mA = IDEV_ACA_CHG_LIMIT;
1222
David Keitel081a3e22012-04-18 12:37:07 -07001223 if (msm_otg_notify_chg_type(motg))
Steve Mucklef132c6c2012-06-06 18:30:57 -07001224 dev_err(motg->phy.dev,
David Keitel081a3e22012-04-18 12:37:07 -07001225 "Failed notifying %d charger type to PMIC\n",
1226 motg->chg_type);
1227
Pavankumar Kondetid8608522011-05-04 10:19:47 +05301228 if (motg->cur_power == mA)
1229 return;
1230
Heikki Krogerus1d4c9292012-02-13 13:24:09 +02001231 dev_info(motg->phy.dev, "Avail curr from USB = %u\n", mA);
Amit Blay0f7edf72012-01-15 10:11:27 +02001232
1233 /*
1234 * Use Power Supply API if supported, otherwise fallback
1235 * to legacy pm8921 API.
1236 */
1237 if (msm_otg_notify_power_supply(motg, mA))
1238 pm8921_charger_vbus_draw(mA);
1239
Pavankumar Kondetid8608522011-05-04 10:19:47 +05301240 motg->cur_power = mA;
1241}
1242
Heikki Krogerus1d4c9292012-02-13 13:24:09 +02001243static int msm_otg_set_power(struct usb_phy *phy, unsigned mA)
Pavankumar Kondetid8608522011-05-04 10:19:47 +05301244{
Heikki Krogerus1d4c9292012-02-13 13:24:09 +02001245 struct msm_otg *motg = container_of(phy, struct msm_otg, phy);
Pavankumar Kondetid8608522011-05-04 10:19:47 +05301246
1247 /*
1248 * Gadget driver uses set_power method to notify about the
1249 * available current based on suspend/configured states.
1250 *
1251 * IDEV_CHG can be drawn irrespective of suspend/un-configured
1252 * states when CDP/ACA is connected.
1253 */
1254 if (motg->chg_type == USB_SDP_CHARGER)
1255 msm_otg_notify_charger(motg, mA);
1256
1257 return 0;
1258}
1259
Steve Mucklef132c6c2012-06-06 18:30:57 -07001260static void msm_otg_start_host(struct usb_otg *otg, int on)
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05301261{
Steve Mucklef132c6c2012-06-06 18:30:57 -07001262 struct msm_otg *motg = container_of(otg->phy, struct msm_otg, phy);
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05301263 struct msm_otg_platform_data *pdata = motg->pdata;
1264 struct usb_hcd *hcd;
1265
1266 if (!otg->host)
1267 return;
1268
1269 hcd = bus_to_hcd(otg->host);
1270
1271 if (on) {
Steve Mucklef132c6c2012-06-06 18:30:57 -07001272 dev_dbg(otg->phy->dev, "host on\n");
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05301273
Vijayavardhan Vennapusa03171c72012-04-26 14:44:48 +05301274 if (pdata->otg_control == OTG_PHY_CONTROL)
Steve Mucklef132c6c2012-06-06 18:30:57 -07001275 ulpi_write(otg->phy, OTG_COMP_DISABLE,
Vijayavardhan Vennapusa03171c72012-04-26 14:44:48 +05301276 ULPI_SET(ULPI_PWR_CLK_MNG_REG));
1277
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05301278 /*
1279 * Some boards have a switch cotrolled by gpio
1280 * to enable/disable internal HUB. Enable internal
1281 * HUB before kicking the host.
1282 */
1283 if (pdata->setup_gpio)
1284 pdata->setup_gpio(OTG_STATE_A_HOST);
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05301285 usb_add_hcd(hcd, hcd->irq, IRQF_SHARED);
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05301286 } else {
Steve Mucklef132c6c2012-06-06 18:30:57 -07001287 dev_dbg(otg->phy->dev, "host off\n");
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05301288
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05301289 usb_remove_hcd(hcd);
Pavankumar Kondetiaa449e12011-11-04 11:09:26 +05301290 /* HCD core reset all bits of PORTSC. select ULPI phy */
1291 writel_relaxed(0x80000000, USB_PORTSC);
1292
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05301293 if (pdata->setup_gpio)
1294 pdata->setup_gpio(OTG_STATE_UNDEFINED);
Vijayavardhan Vennapusa03171c72012-04-26 14:44:48 +05301295
1296 if (pdata->otg_control == OTG_PHY_CONTROL)
Steve Mucklef132c6c2012-06-06 18:30:57 -07001297 ulpi_write(otg->phy, OTG_COMP_DISABLE,
Vijayavardhan Vennapusa03171c72012-04-26 14:44:48 +05301298 ULPI_CLR(ULPI_PWR_CLK_MNG_REG));
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05301299 }
1300}
1301
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001302static int msm_otg_usbdev_notify(struct notifier_block *self,
1303 unsigned long action, void *priv)
1304{
1305 struct msm_otg *motg = container_of(self, struct msm_otg, usbdev_nb);
Steve Mucklef132c6c2012-06-06 18:30:57 -07001306 struct usb_otg *otg = motg->phy.otg;
Pavankumar Kondetiaa449e12011-11-04 11:09:26 +05301307 struct usb_device *udev = priv;
1308
Pavankumar Kondetiaa449e12011-11-04 11:09:26 +05301309 if (action == USB_BUS_ADD || action == USB_BUS_REMOVE)
1310 goto out;
1311
Steve Mucklef132c6c2012-06-06 18:30:57 -07001312 if (udev->bus != otg->host)
Pavankumar Kondetiaa449e12011-11-04 11:09:26 +05301313 goto out;
1314 /*
1315 * Interested in devices connected directly to the root hub.
1316 * ACA dock can supply IDEV_CHG irrespective devices connected
1317 * on the accessory port.
1318 */
1319 if (!udev->parent || udev->parent->parent ||
1320 motg->chg_type == USB_ACA_DOCK_CHARGER)
1321 goto out;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001322
1323 switch (action) {
1324 case USB_DEVICE_ADD:
Vijayavardhan Vennapusaa3152032012-03-05 16:29:30 +05301325 if (aca_enabled())
1326 usb_disable_autosuspend(udev);
Steve Mucklef132c6c2012-06-06 18:30:57 -07001327 if (otg->phy->state == OTG_STATE_A_WAIT_BCON) {
Vijayavardhan Vennapusaa3152032012-03-05 16:29:30 +05301328 pr_debug("B_CONN set\n");
1329 set_bit(B_CONN, &motg->inputs);
1330 msm_otg_del_timer(motg);
Steve Mucklef132c6c2012-06-06 18:30:57 -07001331 otg->phy->state = OTG_STATE_A_HOST;
Vijayavardhan Vennapusaa3152032012-03-05 16:29:30 +05301332 /*
1333 * OTG PET: A-device must end session within
1334 * 10 sec after PET enumeration.
1335 */
1336 if (udev->quirks & USB_QUIRK_OTG_PET)
1337 msm_otg_start_timer(motg, TA_TST_MAINT,
1338 A_TST_MAINT);
1339 }
Pavankumar Kondetiaa449e12011-11-04 11:09:26 +05301340 /* fall through */
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001341 case USB_DEVICE_CONFIG:
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001342 if (udev->actconfig)
1343 motg->mA_port = udev->actconfig->desc.bMaxPower * 2;
1344 else
1345 motg->mA_port = IUNIT;
Steve Mucklef132c6c2012-06-06 18:30:57 -07001346 if (otg->phy->state == OTG_STATE_B_HOST)
Vijayavardhan Vennapusaa3152032012-03-05 16:29:30 +05301347 msm_otg_del_timer(motg);
Pavankumar Kondetiaa449e12011-11-04 11:09:26 +05301348 break;
1349 case USB_DEVICE_REMOVE:
Steve Mucklef132c6c2012-06-06 18:30:57 -07001350 if ((otg->phy->state == OTG_STATE_A_HOST) ||
1351 (otg->phy->state == OTG_STATE_A_SUSPEND)) {
Vijayavardhan Vennapusaa3152032012-03-05 16:29:30 +05301352 pr_debug("B_CONN clear\n");
1353 clear_bit(B_CONN, &motg->inputs);
1354 /*
1355 * OTG PET: A-device must end session after
1356 * PET disconnection if it is enumerated
1357 * with bcdDevice[0] = 1. USB core sets
1358 * bus->otg_vbus_off for us. clear it here.
1359 */
1360 if (udev->bus->otg_vbus_off) {
1361 udev->bus->otg_vbus_off = 0;
1362 set_bit(A_BUS_DROP, &motg->inputs);
1363 }
1364 queue_work(system_nrt_wq, &motg->sm_work);
1365 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001366 default:
1367 break;
1368 }
Pavankumar Kondetiaa449e12011-11-04 11:09:26 +05301369 if (test_bit(ID_A, &motg->inputs))
1370 msm_otg_notify_charger(motg, IDEV_ACA_CHG_MAX -
1371 motg->mA_port);
1372out:
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001373 return NOTIFY_OK;
1374}
1375
Mayank Ranae3926882011-12-26 09:47:54 +05301376static void msm_hsusb_vbus_power(struct msm_otg *motg, bool on)
1377{
1378 int ret;
1379 static bool vbus_is_on;
1380
1381 if (vbus_is_on == on)
1382 return;
1383
1384 if (motg->pdata->vbus_power) {
Mayank Rana91f597e2012-01-20 10:12:06 +05301385 ret = motg->pdata->vbus_power(on);
1386 if (!ret)
1387 vbus_is_on = on;
Mayank Ranae3926882011-12-26 09:47:54 +05301388 return;
1389 }
1390
1391 if (!vbus_otg) {
1392 pr_err("vbus_otg is NULL.");
1393 return;
1394 }
1395
Abhijeet Dharmapurikarbe054882012-01-03 20:27:07 -08001396 /*
1397 * if entering host mode tell the charger to not draw any current
Abhijeet Dharmapurikar6d941212012-03-05 10:30:56 -08001398 * from usb before turning on the boost.
1399 * if exiting host mode disable the boost before enabling to draw
1400 * current from the source.
Abhijeet Dharmapurikarbe054882012-01-03 20:27:07 -08001401 */
Mayank Ranae3926882011-12-26 09:47:54 +05301402 if (on) {
Abhijeet Dharmapurikar5e96aaa2012-06-26 11:21:03 -07001403 msm_otg_notify_host_mode(motg, on);
Mayank Ranae3926882011-12-26 09:47:54 +05301404 ret = regulator_enable(vbus_otg);
1405 if (ret) {
1406 pr_err("unable to enable vbus_otg\n");
1407 return;
1408 }
1409 vbus_is_on = true;
1410 } else {
1411 ret = regulator_disable(vbus_otg);
1412 if (ret) {
1413 pr_err("unable to disable vbus_otg\n");
1414 return;
1415 }
Abhijeet Dharmapurikar5e96aaa2012-06-26 11:21:03 -07001416 msm_otg_notify_host_mode(motg, on);
Mayank Ranae3926882011-12-26 09:47:54 +05301417 vbus_is_on = false;
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05301418 }
1419}
1420
Heikki Krogerus1d4c9292012-02-13 13:24:09 +02001421static int msm_otg_set_host(struct usb_otg *otg, struct usb_bus *host)
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05301422{
Heikki Krogerus1d4c9292012-02-13 13:24:09 +02001423 struct msm_otg *motg = container_of(otg->phy, struct msm_otg, phy);
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05301424 struct usb_hcd *hcd;
1425
1426 /*
1427 * Fail host registration if this board can support
1428 * only peripheral configuration.
1429 */
1430 if (motg->pdata->mode == USB_PERIPHERAL) {
Heikki Krogerus1d4c9292012-02-13 13:24:09 +02001431 dev_info(otg->phy->dev, "Host mode is not supported\n");
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05301432 return -ENODEV;
1433 }
1434
Mayank Ranae3926882011-12-26 09:47:54 +05301435 if (!motg->pdata->vbus_power && host) {
Steve Mucklef132c6c2012-06-06 18:30:57 -07001436 vbus_otg = devm_regulator_get(motg->phy.dev, "vbus_otg");
Mayank Ranae3926882011-12-26 09:47:54 +05301437 if (IS_ERR(vbus_otg)) {
1438 pr_err("Unable to get vbus_otg\n");
1439 return -ENODEV;
1440 }
1441 }
1442
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05301443 if (!host) {
Heikki Krogerus1d4c9292012-02-13 13:24:09 +02001444 if (otg->phy->state == OTG_STATE_A_HOST) {
1445 pm_runtime_get_sync(otg->phy->dev);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001446 usb_unregister_notify(&motg->usbdev_nb);
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05301447 msm_otg_start_host(otg, 0);
Mayank Ranae3926882011-12-26 09:47:54 +05301448 msm_hsusb_vbus_power(motg, 0);
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05301449 otg->host = NULL;
Heikki Krogerus1d4c9292012-02-13 13:24:09 +02001450 otg->phy->state = OTG_STATE_UNDEFINED;
Vijayavardhan Vennapusaa3152032012-03-05 16:29:30 +05301451 queue_work(system_nrt_wq, &motg->sm_work);
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05301452 } else {
1453 otg->host = NULL;
1454 }
1455
1456 return 0;
1457 }
1458
1459 hcd = bus_to_hcd(host);
1460 hcd->power_budget = motg->pdata->power_budget;
1461
Vijayavardhan Vennapusaa3152032012-03-05 16:29:30 +05301462#ifdef CONFIG_USB_OTG
1463 host->otg_port = 1;
1464#endif
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001465 motg->usbdev_nb.notifier_call = msm_otg_usbdev_notify;
1466 usb_register_notify(&motg->usbdev_nb);
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05301467 otg->host = host;
Heikki Krogerus1d4c9292012-02-13 13:24:09 +02001468 dev_dbg(otg->phy->dev, "host driver registered w/ tranceiver\n");
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05301469
1470 /*
1471 * Kick the state machine work, if peripheral is not supported
1472 * or peripheral is already registered with us.
1473 */
Pavankumar Kondeti87c01042010-12-07 17:53:58 +05301474 if (motg->pdata->mode == USB_HOST || otg->gadget) {
Heikki Krogerus1d4c9292012-02-13 13:24:09 +02001475 pm_runtime_get_sync(otg->phy->dev);
Vijayavardhan Vennapusaa3152032012-03-05 16:29:30 +05301476 queue_work(system_nrt_wq, &motg->sm_work);
Pavankumar Kondeti87c01042010-12-07 17:53:58 +05301477 }
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05301478
1479 return 0;
1480}
1481
Steve Mucklef132c6c2012-06-06 18:30:57 -07001482static void msm_otg_start_peripheral(struct usb_otg *otg, int on)
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05301483{
Manu Gautamcd82e9d2011-12-20 14:17:28 +05301484 int ret;
Steve Mucklef132c6c2012-06-06 18:30:57 -07001485 struct msm_otg *motg = container_of(otg->phy, struct msm_otg, phy);
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05301486 struct msm_otg_platform_data *pdata = motg->pdata;
1487
1488 if (!otg->gadget)
1489 return;
1490
1491 if (on) {
Steve Mucklef132c6c2012-06-06 18:30:57 -07001492 dev_dbg(otg->phy->dev, "gadget on\n");
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05301493 /*
1494 * Some boards have a switch cotrolled by gpio
1495 * to enable/disable internal HUB. Disable internal
1496 * HUB before kicking the gadget.
1497 */
1498 if (pdata->setup_gpio)
1499 pdata->setup_gpio(OTG_STATE_B_PERIPHERAL);
Ofir Cohen94213a72012-05-03 14:26:32 +03001500
Manu Gautamcd82e9d2011-12-20 14:17:28 +05301501 /* Configure BUS performance parameters for MAX bandwidth */
Manu Gautam8bdcc592012-03-06 11:26:06 +05301502 if (motg->bus_perf_client && debug_bus_voting_enabled) {
Manu Gautamcd82e9d2011-12-20 14:17:28 +05301503 ret = msm_bus_scale_client_update_request(
1504 motg->bus_perf_client, 1);
1505 if (ret)
Steve Mucklef132c6c2012-06-06 18:30:57 -07001506 dev_err(motg->phy.dev, "%s: Failed to vote for "
Manu Gautamcd82e9d2011-12-20 14:17:28 +05301507 "bus bandwidth %d\n", __func__, ret);
1508 }
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05301509 usb_gadget_vbus_connect(otg->gadget);
1510 } else {
Steve Mucklef132c6c2012-06-06 18:30:57 -07001511 dev_dbg(otg->phy->dev, "gadget off\n");
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05301512 usb_gadget_vbus_disconnect(otg->gadget);
Manu Gautamcd82e9d2011-12-20 14:17:28 +05301513 /* Configure BUS performance parameters to default */
1514 if (motg->bus_perf_client) {
1515 ret = msm_bus_scale_client_update_request(
1516 motg->bus_perf_client, 0);
1517 if (ret)
Steve Mucklef132c6c2012-06-06 18:30:57 -07001518 dev_err(motg->phy.dev, "%s: Failed to devote "
Manu Gautamcd82e9d2011-12-20 14:17:28 +05301519 "for bus bw %d\n", __func__, ret);
1520 }
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05301521 if (pdata->setup_gpio)
1522 pdata->setup_gpio(OTG_STATE_UNDEFINED);
1523 }
1524
1525}
1526
Heikki Krogerus1d4c9292012-02-13 13:24:09 +02001527static int msm_otg_set_peripheral(struct usb_otg *otg,
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05301528 struct usb_gadget *gadget)
1529{
Heikki Krogerus1d4c9292012-02-13 13:24:09 +02001530 struct msm_otg *motg = container_of(otg->phy, struct msm_otg, phy);
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05301531
1532 /*
1533 * Fail peripheral registration if this board can support
1534 * only host configuration.
1535 */
1536 if (motg->pdata->mode == USB_HOST) {
Heikki Krogerus1d4c9292012-02-13 13:24:09 +02001537 dev_info(otg->phy->dev, "Peripheral mode is not supported\n");
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05301538 return -ENODEV;
1539 }
1540
1541 if (!gadget) {
Heikki Krogerus1d4c9292012-02-13 13:24:09 +02001542 if (otg->phy->state == OTG_STATE_B_PERIPHERAL) {
1543 pm_runtime_get_sync(otg->phy->dev);
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05301544 msm_otg_start_peripheral(otg, 0);
1545 otg->gadget = NULL;
Heikki Krogerus1d4c9292012-02-13 13:24:09 +02001546 otg->phy->state = OTG_STATE_UNDEFINED;
Vijayavardhan Vennapusaa3152032012-03-05 16:29:30 +05301547 queue_work(system_nrt_wq, &motg->sm_work);
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05301548 } else {
1549 otg->gadget = NULL;
1550 }
1551
1552 return 0;
1553 }
1554 otg->gadget = gadget;
Heikki Krogerus1d4c9292012-02-13 13:24:09 +02001555 dev_dbg(otg->phy->dev, "peripheral driver registered w/ tranceiver\n");
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05301556
1557 /*
1558 * Kick the state machine work, if host is not supported
1559 * or host is already registered with us.
1560 */
Pavankumar Kondeti87c01042010-12-07 17:53:58 +05301561 if (motg->pdata->mode == USB_PERIPHERAL || otg->host) {
Heikki Krogerus1d4c9292012-02-13 13:24:09 +02001562 pm_runtime_get_sync(otg->phy->dev);
Vijayavardhan Vennapusaa3152032012-03-05 16:29:30 +05301563 queue_work(system_nrt_wq, &motg->sm_work);
Pavankumar Kondeti87c01042010-12-07 17:53:58 +05301564 }
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05301565
1566 return 0;
1567}
1568
Pavankumar Kondeti2aec9f32012-06-13 09:06:03 +05301569static int msm_otg_mhl_register_callback(struct msm_otg *motg,
1570 void (*callback)(int on))
1571{
1572 struct usb_phy *phy = &motg->phy;
1573 int ret;
1574
Manoj Raoa7bddd12012-08-27 20:36:45 -07001575 if (!motg->pdata->mhl_enable) {
1576 dev_dbg(phy->dev, "MHL feature not enabled\n");
1577 return -ENODEV;
1578 }
1579
Pavankumar Kondeti2aec9f32012-06-13 09:06:03 +05301580 if (motg->pdata->otg_control != OTG_PMIC_CONTROL ||
1581 !motg->pdata->pmic_id_irq) {
1582 dev_dbg(phy->dev, "MHL can not be supported without PMIC Id\n");
1583 return -ENODEV;
1584 }
1585
1586 if (!motg->pdata->mhl_dev_name) {
1587 dev_dbg(phy->dev, "MHL device name does not exist.\n");
1588 return -ENODEV;
1589 }
1590
1591 if (callback)
1592 ret = mhl_register_callback(motg->pdata->mhl_dev_name,
1593 callback);
1594 else
1595 ret = mhl_unregister_callback(motg->pdata->mhl_dev_name);
1596
1597 if (ret)
1598 dev_dbg(phy->dev, "mhl_register_callback(%s) return error=%d\n",
1599 motg->pdata->mhl_dev_name, ret);
1600 else
1601 motg->mhl_enabled = true;
1602
1603 return ret;
1604}
1605
1606static void msm_otg_mhl_notify_online(int on)
1607{
1608 struct msm_otg *motg = the_msm_otg;
1609 struct usb_phy *phy = &motg->phy;
1610 bool queue = false;
1611
1612 dev_dbg(phy->dev, "notify MHL %s%s\n", on ? "" : "dis", "connected");
1613
1614 if (on) {
1615 set_bit(MHL, &motg->inputs);
1616 } else {
1617 clear_bit(MHL, &motg->inputs);
1618 queue = true;
1619 }
1620
1621 if (queue && phy->state != OTG_STATE_UNDEFINED)
1622 schedule_work(&motg->sm_work);
1623}
1624
1625static bool msm_otg_is_mhl(struct msm_otg *motg)
1626{
1627 struct usb_phy *phy = &motg->phy;
1628 int is_mhl, ret;
1629
1630 ret = mhl_device_discovery(motg->pdata->mhl_dev_name, &is_mhl);
1631 if (ret || is_mhl != MHL_DISCOVERY_RESULT_MHL) {
1632 /*
1633 * MHL driver calls our callback saying that MHL connected
1634 * if RID_GND is detected. But at later part of discovery
1635 * it may figure out MHL is not connected and returns
1636 * false. Hence clear MHL input here.
1637 */
1638 clear_bit(MHL, &motg->inputs);
1639 dev_dbg(phy->dev, "MHL device not found\n");
1640 return false;
1641 }
1642
1643 set_bit(MHL, &motg->inputs);
1644 dev_dbg(phy->dev, "MHL device found\n");
1645 return true;
1646}
1647
1648static bool msm_chg_mhl_detect(struct msm_otg *motg)
1649{
1650 bool ret, id;
1651 unsigned long flags;
1652
1653 if (!motg->mhl_enabled)
1654 return false;
1655
1656 local_irq_save(flags);
1657 id = irq_read_line(motg->pdata->pmic_id_irq);
1658 local_irq_restore(flags);
1659
1660 if (id)
1661 return false;
1662
1663 mhl_det_in_progress = true;
1664 ret = msm_otg_is_mhl(motg);
1665 mhl_det_in_progress = false;
1666
1667 return ret;
1668}
1669
Pavankumar Kondeti458d8792012-09-28 14:45:18 +05301670static void msm_otg_chg_check_timer_func(unsigned long data)
1671{
1672 struct msm_otg *motg = (struct msm_otg *) data;
1673 struct usb_otg *otg = motg->phy.otg;
1674
1675 if (atomic_read(&motg->in_lpm) ||
1676 !test_bit(B_SESS_VLD, &motg->inputs) ||
1677 otg->phy->state != OTG_STATE_B_PERIPHERAL ||
1678 otg->gadget->speed != USB_SPEED_UNKNOWN) {
1679 dev_dbg(otg->phy->dev, "Nothing to do in chg_check_timer\n");
1680 return;
1681 }
1682
1683 if ((readl_relaxed(USB_PORTSC) & PORTSC_LS) == PORTSC_LS) {
1684 dev_dbg(otg->phy->dev, "DCP is detected as SDP\n");
1685 set_bit(B_FALSE_SDP, &motg->inputs);
1686 queue_work(system_nrt_wq, &motg->sm_work);
1687 }
1688}
1689
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001690static bool msm_chg_aca_detect(struct msm_otg *motg)
1691{
Steve Mucklef132c6c2012-06-06 18:30:57 -07001692 struct usb_phy *phy = &motg->phy;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001693 u32 int_sts;
1694 bool ret = false;
1695
Pavankumar Kondetiaa449e12011-11-04 11:09:26 +05301696 if (!aca_enabled())
1697 goto out;
1698
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001699 if (motg->pdata->phy_type == CI_45NM_INTEGRATED_PHY)
1700 goto out;
1701
Steve Mucklef132c6c2012-06-06 18:30:57 -07001702 int_sts = ulpi_read(phy, 0x87);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001703 switch (int_sts & 0x1C) {
1704 case 0x08:
1705 if (!test_and_set_bit(ID_A, &motg->inputs)) {
Steve Mucklef132c6c2012-06-06 18:30:57 -07001706 dev_dbg(phy->dev, "ID_A\n");
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001707 motg->chg_type = USB_ACA_A_CHARGER;
1708 motg->chg_state = USB_CHG_STATE_DETECTED;
1709 clear_bit(ID_B, &motg->inputs);
1710 clear_bit(ID_C, &motg->inputs);
Pavankumar Kondetiaa449e12011-11-04 11:09:26 +05301711 set_bit(ID, &motg->inputs);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001712 ret = true;
1713 }
1714 break;
1715 case 0x0C:
1716 if (!test_and_set_bit(ID_B, &motg->inputs)) {
Steve Mucklef132c6c2012-06-06 18:30:57 -07001717 dev_dbg(phy->dev, "ID_B\n");
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001718 motg->chg_type = USB_ACA_B_CHARGER;
1719 motg->chg_state = USB_CHG_STATE_DETECTED;
1720 clear_bit(ID_A, &motg->inputs);
1721 clear_bit(ID_C, &motg->inputs);
Pavankumar Kondetiaa449e12011-11-04 11:09:26 +05301722 set_bit(ID, &motg->inputs);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001723 ret = true;
1724 }
1725 break;
1726 case 0x10:
1727 if (!test_and_set_bit(ID_C, &motg->inputs)) {
Steve Mucklef132c6c2012-06-06 18:30:57 -07001728 dev_dbg(phy->dev, "ID_C\n");
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001729 motg->chg_type = USB_ACA_C_CHARGER;
1730 motg->chg_state = USB_CHG_STATE_DETECTED;
1731 clear_bit(ID_A, &motg->inputs);
1732 clear_bit(ID_B, &motg->inputs);
Pavankumar Kondetiaa449e12011-11-04 11:09:26 +05301733 set_bit(ID, &motg->inputs);
1734 ret = true;
1735 }
1736 break;
1737 case 0x04:
1738 if (test_and_clear_bit(ID, &motg->inputs)) {
Steve Mucklef132c6c2012-06-06 18:30:57 -07001739 dev_dbg(phy->dev, "ID_GND\n");
Pavankumar Kondetiaa449e12011-11-04 11:09:26 +05301740 motg->chg_type = USB_INVALID_CHARGER;
1741 motg->chg_state = USB_CHG_STATE_UNDEFINED;
1742 clear_bit(ID_A, &motg->inputs);
1743 clear_bit(ID_B, &motg->inputs);
1744 clear_bit(ID_C, &motg->inputs);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001745 ret = true;
1746 }
1747 break;
1748 default:
1749 ret = test_and_clear_bit(ID_A, &motg->inputs) |
1750 test_and_clear_bit(ID_B, &motg->inputs) |
Pavankumar Kondetiaa449e12011-11-04 11:09:26 +05301751 test_and_clear_bit(ID_C, &motg->inputs) |
1752 !test_and_set_bit(ID, &motg->inputs);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001753 if (ret) {
Steve Mucklef132c6c2012-06-06 18:30:57 -07001754 dev_dbg(phy->dev, "ID A/B/C/GND is no more\n");
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001755 motg->chg_type = USB_INVALID_CHARGER;
1756 motg->chg_state = USB_CHG_STATE_UNDEFINED;
1757 }
1758 }
1759out:
1760 return ret;
1761}
1762
1763static void msm_chg_enable_aca_det(struct msm_otg *motg)
1764{
Steve Mucklef132c6c2012-06-06 18:30:57 -07001765 struct usb_phy *phy = &motg->phy;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001766
Pavankumar Kondetiaa449e12011-11-04 11:09:26 +05301767 if (!aca_enabled())
1768 return;
1769
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001770 switch (motg->pdata->phy_type) {
1771 case SNPS_28NM_INTEGRATED_PHY:
Pavankumar Kondetiaa449e12011-11-04 11:09:26 +05301772 /* Disable ID_GND in link and PHY */
1773 writel_relaxed(readl_relaxed(USB_OTGSC) & ~(OTGSC_IDPU |
1774 OTGSC_IDIE), USB_OTGSC);
Steve Mucklef132c6c2012-06-06 18:30:57 -07001775 ulpi_write(phy, 0x01, 0x0C);
1776 ulpi_write(phy, 0x10, 0x0F);
1777 ulpi_write(phy, 0x10, 0x12);
Pavankumar Kondeti446f4542012-02-01 13:57:13 +05301778 /* Disable PMIC ID pull-up */
1779 pm8xxx_usb_id_pullup(0);
Pavankumar Kondetiaa449e12011-11-04 11:09:26 +05301780 /* Enable ACA ID detection */
Steve Mucklef132c6c2012-06-06 18:30:57 -07001781 ulpi_write(phy, 0x20, 0x85);
Pavankumar Kondeti4960f312011-12-06 15:46:14 +05301782 aca_id_turned_on = true;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001783 break;
1784 default:
1785 break;
1786 }
1787}
1788
1789static void msm_chg_enable_aca_intr(struct msm_otg *motg)
1790{
Steve Mucklef132c6c2012-06-06 18:30:57 -07001791 struct usb_phy *phy = &motg->phy;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001792
Pavankumar Kondetiaa449e12011-11-04 11:09:26 +05301793 if (!aca_enabled())
1794 return;
1795
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001796 switch (motg->pdata->phy_type) {
1797 case SNPS_28NM_INTEGRATED_PHY:
Pavankumar Kondetiaa449e12011-11-04 11:09:26 +05301798 /* Enable ACA Detection interrupt (on any RID change) */
Steve Mucklef132c6c2012-06-06 18:30:57 -07001799 ulpi_write(phy, 0x01, 0x94);
Pavankumar Kondetiaa449e12011-11-04 11:09:26 +05301800 break;
1801 default:
1802 break;
1803 }
1804}
1805
1806static void msm_chg_disable_aca_intr(struct msm_otg *motg)
1807{
Steve Mucklef132c6c2012-06-06 18:30:57 -07001808 struct usb_phy *phy = &motg->phy;
Pavankumar Kondetiaa449e12011-11-04 11:09:26 +05301809
1810 if (!aca_enabled())
1811 return;
1812
1813 switch (motg->pdata->phy_type) {
1814 case SNPS_28NM_INTEGRATED_PHY:
Steve Mucklef132c6c2012-06-06 18:30:57 -07001815 ulpi_write(phy, 0x01, 0x95);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001816 break;
1817 default:
1818 break;
1819 }
1820}
1821
1822static bool msm_chg_check_aca_intr(struct msm_otg *motg)
1823{
Steve Mucklef132c6c2012-06-06 18:30:57 -07001824 struct usb_phy *phy = &motg->phy;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001825 bool ret = false;
1826
Pavankumar Kondetiaa449e12011-11-04 11:09:26 +05301827 if (!aca_enabled())
1828 return ret;
1829
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001830 switch (motg->pdata->phy_type) {
1831 case SNPS_28NM_INTEGRATED_PHY:
Steve Mucklef132c6c2012-06-06 18:30:57 -07001832 if (ulpi_read(phy, 0x91) & 1) {
1833 dev_dbg(phy->dev, "RID change\n");
1834 ulpi_write(phy, 0x01, 0x92);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001835 ret = msm_chg_aca_detect(motg);
1836 }
1837 default:
1838 break;
1839 }
1840 return ret;
1841}
Pavankumar Kondetiaa449e12011-11-04 11:09:26 +05301842
1843static void msm_otg_id_timer_func(unsigned long data)
1844{
1845 struct msm_otg *motg = (struct msm_otg *) data;
1846
1847 if (!aca_enabled())
1848 return;
1849
1850 if (atomic_read(&motg->in_lpm)) {
Steve Mucklef132c6c2012-06-06 18:30:57 -07001851 dev_dbg(motg->phy.dev, "timer: in lpm\n");
Pavankumar Kondetiaa449e12011-11-04 11:09:26 +05301852 return;
1853 }
1854
Steve Mucklef132c6c2012-06-06 18:30:57 -07001855 if (motg->phy.state == OTG_STATE_A_SUSPEND)
Vijayavardhan Vennapusaa3152032012-03-05 16:29:30 +05301856 goto out;
1857
Pavankumar Kondetiaa449e12011-11-04 11:09:26 +05301858 if (msm_chg_check_aca_intr(motg)) {
Steve Mucklef132c6c2012-06-06 18:30:57 -07001859 dev_dbg(motg->phy.dev, "timer: aca work\n");
Vijayavardhan Vennapusaa3152032012-03-05 16:29:30 +05301860 queue_work(system_nrt_wq, &motg->sm_work);
Pavankumar Kondetiaa449e12011-11-04 11:09:26 +05301861 }
1862
Vijayavardhan Vennapusaa3152032012-03-05 16:29:30 +05301863out:
Pavankumar Kondetiaa449e12011-11-04 11:09:26 +05301864 if (!test_bit(ID, &motg->inputs) || test_bit(ID_A, &motg->inputs))
1865 mod_timer(&motg->id_timer, ID_TIMER_FREQ);
1866}
1867
Pavankumar Kondetid8608522011-05-04 10:19:47 +05301868static bool msm_chg_check_secondary_det(struct msm_otg *motg)
1869{
Heikki Krogerus1d4c9292012-02-13 13:24:09 +02001870 struct usb_phy *phy = &motg->phy;
Pavankumar Kondetid8608522011-05-04 10:19:47 +05301871 u32 chg_det;
1872 bool ret = false;
1873
1874 switch (motg->pdata->phy_type) {
1875 case CI_45NM_INTEGRATED_PHY:
Heikki Krogerus1d4c9292012-02-13 13:24:09 +02001876 chg_det = ulpi_read(phy, 0x34);
Pavankumar Kondetid8608522011-05-04 10:19:47 +05301877 ret = chg_det & (1 << 4);
1878 break;
1879 case SNPS_28NM_INTEGRATED_PHY:
Heikki Krogerus1d4c9292012-02-13 13:24:09 +02001880 chg_det = ulpi_read(phy, 0x87);
Pavankumar Kondetid8608522011-05-04 10:19:47 +05301881 ret = chg_det & 1;
1882 break;
1883 default:
1884 break;
1885 }
1886 return ret;
1887}
1888
1889static void msm_chg_enable_secondary_det(struct msm_otg *motg)
1890{
Heikki Krogerus1d4c9292012-02-13 13:24:09 +02001891 struct usb_phy *phy = &motg->phy;
Pavankumar Kondetid8608522011-05-04 10:19:47 +05301892 u32 chg_det;
1893
1894 switch (motg->pdata->phy_type) {
1895 case CI_45NM_INTEGRATED_PHY:
Heikki Krogerus1d4c9292012-02-13 13:24:09 +02001896 chg_det = ulpi_read(phy, 0x34);
Pavankumar Kondetid8608522011-05-04 10:19:47 +05301897 /* Turn off charger block */
1898 chg_det |= ~(1 << 1);
Heikki Krogerus1d4c9292012-02-13 13:24:09 +02001899 ulpi_write(phy, chg_det, 0x34);
Pavankumar Kondetid8608522011-05-04 10:19:47 +05301900 udelay(20);
1901 /* control chg block via ULPI */
1902 chg_det &= ~(1 << 3);
Heikki Krogerus1d4c9292012-02-13 13:24:09 +02001903 ulpi_write(phy, chg_det, 0x34);
Pavankumar Kondetid8608522011-05-04 10:19:47 +05301904 /* put it in host mode for enabling D- source */
1905 chg_det &= ~(1 << 2);
Heikki Krogerus1d4c9292012-02-13 13:24:09 +02001906 ulpi_write(phy, chg_det, 0x34);
Pavankumar Kondetid8608522011-05-04 10:19:47 +05301907 /* Turn on chg detect block */
1908 chg_det &= ~(1 << 1);
Heikki Krogerus1d4c9292012-02-13 13:24:09 +02001909 ulpi_write(phy, chg_det, 0x34);
Pavankumar Kondetid8608522011-05-04 10:19:47 +05301910 udelay(20);
1911 /* enable chg detection */
1912 chg_det &= ~(1 << 0);
Heikki Krogerus1d4c9292012-02-13 13:24:09 +02001913 ulpi_write(phy, chg_det, 0x34);
Pavankumar Kondetid8608522011-05-04 10:19:47 +05301914 break;
1915 case SNPS_28NM_INTEGRATED_PHY:
1916 /*
1917 * Configure DM as current source, DP as current sink
1918 * and enable battery charging comparators.
1919 */
Heikki Krogerus1d4c9292012-02-13 13:24:09 +02001920 ulpi_write(phy, 0x8, 0x85);
1921 ulpi_write(phy, 0x2, 0x85);
1922 ulpi_write(phy, 0x1, 0x85);
Pavankumar Kondetid8608522011-05-04 10:19:47 +05301923 break;
1924 default:
1925 break;
1926 }
1927}
1928
1929static bool msm_chg_check_primary_det(struct msm_otg *motg)
1930{
Heikki Krogerus1d4c9292012-02-13 13:24:09 +02001931 struct usb_phy *phy = &motg->phy;
Pavankumar Kondetid8608522011-05-04 10:19:47 +05301932 u32 chg_det;
1933 bool ret = false;
1934
1935 switch (motg->pdata->phy_type) {
1936 case CI_45NM_INTEGRATED_PHY:
Heikki Krogerus1d4c9292012-02-13 13:24:09 +02001937 chg_det = ulpi_read(phy, 0x34);
Pavankumar Kondetid8608522011-05-04 10:19:47 +05301938 ret = chg_det & (1 << 4);
1939 break;
1940 case SNPS_28NM_INTEGRATED_PHY:
Heikki Krogerus1d4c9292012-02-13 13:24:09 +02001941 chg_det = ulpi_read(phy, 0x87);
Pavankumar Kondetid8608522011-05-04 10:19:47 +05301942 ret = chg_det & 1;
Pavankumar Kondeti9ec21d32012-05-07 15:50:23 +05301943 /* Turn off VDP_SRC */
1944 ulpi_write(phy, 0x3, 0x86);
1945 msleep(20);
Pavankumar Kondetid8608522011-05-04 10:19:47 +05301946 break;
1947 default:
1948 break;
1949 }
1950 return ret;
1951}
1952
1953static void msm_chg_enable_primary_det(struct msm_otg *motg)
1954{
Heikki Krogerus1d4c9292012-02-13 13:24:09 +02001955 struct usb_phy *phy = &motg->phy;
Pavankumar Kondetid8608522011-05-04 10:19:47 +05301956 u32 chg_det;
1957
1958 switch (motg->pdata->phy_type) {
1959 case CI_45NM_INTEGRATED_PHY:
Heikki Krogerus1d4c9292012-02-13 13:24:09 +02001960 chg_det = ulpi_read(phy, 0x34);
Pavankumar Kondetid8608522011-05-04 10:19:47 +05301961 /* enable chg detection */
1962 chg_det &= ~(1 << 0);
Heikki Krogerus1d4c9292012-02-13 13:24:09 +02001963 ulpi_write(phy, chg_det, 0x34);
Pavankumar Kondetid8608522011-05-04 10:19:47 +05301964 break;
1965 case SNPS_28NM_INTEGRATED_PHY:
1966 /*
1967 * Configure DP as current source, DM as current sink
1968 * and enable battery charging comparators.
1969 */
Heikki Krogerus1d4c9292012-02-13 13:24:09 +02001970 ulpi_write(phy, 0x2, 0x85);
1971 ulpi_write(phy, 0x1, 0x85);
Pavankumar Kondetid8608522011-05-04 10:19:47 +05301972 break;
1973 default:
1974 break;
1975 }
1976}
1977
1978static bool msm_chg_check_dcd(struct msm_otg *motg)
1979{
Heikki Krogerus1d4c9292012-02-13 13:24:09 +02001980 struct usb_phy *phy = &motg->phy;
Pavankumar Kondetid8608522011-05-04 10:19:47 +05301981 u32 line_state;
1982 bool ret = false;
1983
1984 switch (motg->pdata->phy_type) {
1985 case CI_45NM_INTEGRATED_PHY:
Heikki Krogerus1d4c9292012-02-13 13:24:09 +02001986 line_state = ulpi_read(phy, 0x15);
Pavankumar Kondetid8608522011-05-04 10:19:47 +05301987 ret = !(line_state & 1);
1988 break;
1989 case SNPS_28NM_INTEGRATED_PHY:
Heikki Krogerus1d4c9292012-02-13 13:24:09 +02001990 line_state = ulpi_read(phy, 0x87);
Pavankumar Kondetid8608522011-05-04 10:19:47 +05301991 ret = line_state & 2;
1992 break;
1993 default:
1994 break;
1995 }
1996 return ret;
1997}
1998
1999static void msm_chg_disable_dcd(struct msm_otg *motg)
2000{
Heikki Krogerus1d4c9292012-02-13 13:24:09 +02002001 struct usb_phy *phy = &motg->phy;
Pavankumar Kondetid8608522011-05-04 10:19:47 +05302002 u32 chg_det;
2003
2004 switch (motg->pdata->phy_type) {
2005 case CI_45NM_INTEGRATED_PHY:
Heikki Krogerus1d4c9292012-02-13 13:24:09 +02002006 chg_det = ulpi_read(phy, 0x34);
Pavankumar Kondetid8608522011-05-04 10:19:47 +05302007 chg_det &= ~(1 << 5);
Heikki Krogerus1d4c9292012-02-13 13:24:09 +02002008 ulpi_write(phy, chg_det, 0x34);
Pavankumar Kondetid8608522011-05-04 10:19:47 +05302009 break;
2010 case SNPS_28NM_INTEGRATED_PHY:
Heikki Krogerus1d4c9292012-02-13 13:24:09 +02002011 ulpi_write(phy, 0x10, 0x86);
Pavankumar Kondetid8608522011-05-04 10:19:47 +05302012 break;
2013 default:
2014 break;
2015 }
2016}
2017
2018static void msm_chg_enable_dcd(struct msm_otg *motg)
2019{
Heikki Krogerus1d4c9292012-02-13 13:24:09 +02002020 struct usb_phy *phy = &motg->phy;
Pavankumar Kondetid8608522011-05-04 10:19:47 +05302021 u32 chg_det;
2022
2023 switch (motg->pdata->phy_type) {
2024 case CI_45NM_INTEGRATED_PHY:
Heikki Krogerus1d4c9292012-02-13 13:24:09 +02002025 chg_det = ulpi_read(phy, 0x34);
Pavankumar Kondetid8608522011-05-04 10:19:47 +05302026 /* Turn on D+ current source */
2027 chg_det |= (1 << 5);
Heikki Krogerus1d4c9292012-02-13 13:24:09 +02002028 ulpi_write(phy, chg_det, 0x34);
Pavankumar Kondetid8608522011-05-04 10:19:47 +05302029 break;
2030 case SNPS_28NM_INTEGRATED_PHY:
2031 /* Data contact detection enable */
Heikki Krogerus1d4c9292012-02-13 13:24:09 +02002032 ulpi_write(phy, 0x10, 0x85);
Pavankumar Kondetid8608522011-05-04 10:19:47 +05302033 break;
2034 default:
2035 break;
2036 }
2037}
2038
2039static void msm_chg_block_on(struct msm_otg *motg)
2040{
Heikki Krogerus1d4c9292012-02-13 13:24:09 +02002041 struct usb_phy *phy = &motg->phy;
Pavankumar Kondetid8608522011-05-04 10:19:47 +05302042 u32 func_ctrl, chg_det;
2043
2044 /* put the controller in non-driving mode */
Heikki Krogerus1d4c9292012-02-13 13:24:09 +02002045 func_ctrl = ulpi_read(phy, ULPI_FUNC_CTRL);
Pavankumar Kondetid8608522011-05-04 10:19:47 +05302046 func_ctrl &= ~ULPI_FUNC_CTRL_OPMODE_MASK;
2047 func_ctrl |= ULPI_FUNC_CTRL_OPMODE_NONDRIVING;
Heikki Krogerus1d4c9292012-02-13 13:24:09 +02002048 ulpi_write(phy, func_ctrl, ULPI_FUNC_CTRL);
Pavankumar Kondetid8608522011-05-04 10:19:47 +05302049
2050 switch (motg->pdata->phy_type) {
2051 case CI_45NM_INTEGRATED_PHY:
Heikki Krogerus1d4c9292012-02-13 13:24:09 +02002052 chg_det = ulpi_read(phy, 0x34);
Pavankumar Kondetid8608522011-05-04 10:19:47 +05302053 /* control chg block via ULPI */
2054 chg_det &= ~(1 << 3);
Heikki Krogerus1d4c9292012-02-13 13:24:09 +02002055 ulpi_write(phy, chg_det, 0x34);
Pavankumar Kondetid8608522011-05-04 10:19:47 +05302056 /* Turn on chg detect block */
2057 chg_det &= ~(1 << 1);
Heikki Krogerus1d4c9292012-02-13 13:24:09 +02002058 ulpi_write(phy, chg_det, 0x34);
Pavankumar Kondetid8608522011-05-04 10:19:47 +05302059 udelay(20);
2060 break;
2061 case SNPS_28NM_INTEGRATED_PHY:
Pavankumar Kondeti768dcb82012-10-05 13:21:45 +05302062 /* disable DP and DM pull down resistors */
2063 ulpi_write(phy, 0x6, 0xC);
Pavankumar Kondetid8608522011-05-04 10:19:47 +05302064 /* Clear charger detecting control bits */
Steve Mucklef132c6c2012-06-06 18:30:57 -07002065 ulpi_write(phy, 0x1F, 0x86);
Pavankumar Kondetid8608522011-05-04 10:19:47 +05302066 /* Clear alt interrupt latch and enable bits */
Heikki Krogerus1d4c9292012-02-13 13:24:09 +02002067 ulpi_write(phy, 0x1F, 0x92);
2068 ulpi_write(phy, 0x1F, 0x95);
Pavankumar Kondetid8608522011-05-04 10:19:47 +05302069 udelay(100);
2070 break;
2071 default:
2072 break;
2073 }
2074}
2075
2076static void msm_chg_block_off(struct msm_otg *motg)
2077{
Heikki Krogerus1d4c9292012-02-13 13:24:09 +02002078 struct usb_phy *phy = &motg->phy;
Pavankumar Kondetid8608522011-05-04 10:19:47 +05302079 u32 func_ctrl, chg_det;
2080
2081 switch (motg->pdata->phy_type) {
2082 case CI_45NM_INTEGRATED_PHY:
Heikki Krogerus1d4c9292012-02-13 13:24:09 +02002083 chg_det = ulpi_read(phy, 0x34);
Pavankumar Kondetid8608522011-05-04 10:19:47 +05302084 /* Turn off charger block */
2085 chg_det |= ~(1 << 1);
Heikki Krogerus1d4c9292012-02-13 13:24:09 +02002086 ulpi_write(phy, chg_det, 0x34);
Pavankumar Kondetid8608522011-05-04 10:19:47 +05302087 break;
2088 case SNPS_28NM_INTEGRATED_PHY:
2089 /* Clear charger detecting control bits */
Heikki Krogerus1d4c9292012-02-13 13:24:09 +02002090 ulpi_write(phy, 0x3F, 0x86);
Pavankumar Kondetid8608522011-05-04 10:19:47 +05302091 /* Clear alt interrupt latch and enable bits */
Heikki Krogerus1d4c9292012-02-13 13:24:09 +02002092 ulpi_write(phy, 0x1F, 0x92);
2093 ulpi_write(phy, 0x1F, 0x95);
Pavankumar Kondetid8608522011-05-04 10:19:47 +05302094 break;
2095 default:
2096 break;
2097 }
2098
2099 /* put the controller in normal mode */
Heikki Krogerus1d4c9292012-02-13 13:24:09 +02002100 func_ctrl = ulpi_read(phy, ULPI_FUNC_CTRL);
Pavankumar Kondetid8608522011-05-04 10:19:47 +05302101 func_ctrl &= ~ULPI_FUNC_CTRL_OPMODE_MASK;
2102 func_ctrl |= ULPI_FUNC_CTRL_OPMODE_NORMAL;
Heikki Krogerus1d4c9292012-02-13 13:24:09 +02002103 ulpi_write(phy, func_ctrl, ULPI_FUNC_CTRL);
Pavankumar Kondetid8608522011-05-04 10:19:47 +05302104}
2105
Anji jonnalad270e2d2011-08-09 11:28:32 +05302106static const char *chg_to_string(enum usb_chg_type chg_type)
2107{
2108 switch (chg_type) {
2109 case USB_SDP_CHARGER: return "USB_SDP_CHARGER";
2110 case USB_DCP_CHARGER: return "USB_DCP_CHARGER";
2111 case USB_CDP_CHARGER: return "USB_CDP_CHARGER";
2112 case USB_ACA_A_CHARGER: return "USB_ACA_A_CHARGER";
2113 case USB_ACA_B_CHARGER: return "USB_ACA_B_CHARGER";
2114 case USB_ACA_C_CHARGER: return "USB_ACA_C_CHARGER";
2115 case USB_ACA_DOCK_CHARGER: return "USB_ACA_DOCK_CHARGER";
Pavankumar Kondeti9ec21d32012-05-07 15:50:23 +05302116 case USB_PROPRIETARY_CHARGER: return "USB_PROPRIETARY_CHARGER";
Anji jonnalad270e2d2011-08-09 11:28:32 +05302117 default: return "INVALID_CHARGER";
2118 }
2119}
2120
Pavankumar Kondetid8608522011-05-04 10:19:47 +05302121#define MSM_CHG_DCD_POLL_TIME (100 * HZ/1000) /* 100 msec */
2122#define MSM_CHG_DCD_MAX_RETRIES 6 /* Tdcd_tmout = 6 * 100 msec */
Pavankumar Kondeti283146f2012-01-12 12:51:19 +05302123#define MSM_CHG_PRIMARY_DET_TIME (50 * HZ/1000) /* TVDPSRC_ON */
2124#define MSM_CHG_SECONDARY_DET_TIME (50 * HZ/1000) /* TVDMSRC_ON */
Pavankumar Kondetid8608522011-05-04 10:19:47 +05302125static void msm_chg_detect_work(struct work_struct *w)
2126{
2127 struct msm_otg *motg = container_of(w, struct msm_otg, chg_work.work);
Heikki Krogerus1d4c9292012-02-13 13:24:09 +02002128 struct usb_phy *phy = &motg->phy;
Pavankumar Kondeti2d09e5f2012-01-16 08:56:57 +05302129 bool is_dcd = false, tmout, vout, is_aca;
Pavankumar Kondeti9ec21d32012-05-07 15:50:23 +05302130 u32 line_state, dm_vlgc;
Pavankumar Kondetid8608522011-05-04 10:19:47 +05302131 unsigned long delay;
2132
Heikki Krogerus1d4c9292012-02-13 13:24:09 +02002133 dev_dbg(phy->dev, "chg detection work\n");
Pavankumar Kondeti2aec9f32012-06-13 09:06:03 +05302134
2135 if (test_bit(MHL, &motg->inputs)) {
2136 dev_dbg(phy->dev, "detected MHL, escape chg detection work\n");
2137 return;
2138 }
2139
Pavankumar Kondetid8608522011-05-04 10:19:47 +05302140 switch (motg->chg_state) {
2141 case USB_CHG_STATE_UNDEFINED:
Pavankumar Kondetid8608522011-05-04 10:19:47 +05302142 msm_chg_block_on(motg);
Pavankumar Kondeti768dcb82012-10-05 13:21:45 +05302143 msm_chg_enable_dcd(motg);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002144 msm_chg_enable_aca_det(motg);
Pavankumar Kondetid8608522011-05-04 10:19:47 +05302145 motg->chg_state = USB_CHG_STATE_WAIT_FOR_DCD;
2146 motg->dcd_retries = 0;
2147 delay = MSM_CHG_DCD_POLL_TIME;
2148 break;
2149 case USB_CHG_STATE_WAIT_FOR_DCD:
Pavankumar Kondeti2aec9f32012-06-13 09:06:03 +05302150 if (msm_chg_mhl_detect(motg)) {
2151 msm_chg_block_off(motg);
2152 motg->chg_state = USB_CHG_STATE_DETECTED;
2153 motg->chg_type = USB_INVALID_CHARGER;
2154 queue_work(system_nrt_wq, &motg->sm_work);
2155 return;
2156 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002157 is_aca = msm_chg_aca_detect(motg);
2158 if (is_aca) {
2159 /*
2160 * ID_A can be ACA dock too. continue
2161 * primary detection after DCD.
2162 */
2163 if (test_bit(ID_A, &motg->inputs)) {
2164 motg->chg_state = USB_CHG_STATE_WAIT_FOR_DCD;
2165 } else {
2166 delay = 0;
2167 break;
2168 }
2169 }
Pavankumar Kondeti768dcb82012-10-05 13:21:45 +05302170 is_dcd = msm_chg_check_dcd(motg);
Pavankumar Kondetid8608522011-05-04 10:19:47 +05302171 tmout = ++motg->dcd_retries == MSM_CHG_DCD_MAX_RETRIES;
2172 if (is_dcd || tmout) {
Pavankumar Kondeti768dcb82012-10-05 13:21:45 +05302173 msm_chg_disable_dcd(motg);
Pavankumar Kondetid8608522011-05-04 10:19:47 +05302174 msm_chg_enable_primary_det(motg);
2175 delay = MSM_CHG_PRIMARY_DET_TIME;
2176 motg->chg_state = USB_CHG_STATE_DCD_DONE;
2177 } else {
2178 delay = MSM_CHG_DCD_POLL_TIME;
2179 }
2180 break;
2181 case USB_CHG_STATE_DCD_DONE:
2182 vout = msm_chg_check_primary_det(motg);
Pavankumar Kondeti9ec21d32012-05-07 15:50:23 +05302183 line_state = readl_relaxed(USB_PORTSC) & PORTSC_LS;
2184 dm_vlgc = line_state & PORTSC_LS_DM;
2185 if (vout && !dm_vlgc) { /* VDAT_REF < DM < VLGC */
Pavankumar Kondetiaa449e12011-11-04 11:09:26 +05302186 if (test_bit(ID_A, &motg->inputs)) {
2187 motg->chg_type = USB_ACA_DOCK_CHARGER;
2188 motg->chg_state = USB_CHG_STATE_DETECTED;
2189 delay = 0;
2190 break;
2191 }
Pavankumar Kondeti9ec21d32012-05-07 15:50:23 +05302192 if (line_state) { /* DP > VLGC */
2193 motg->chg_type = USB_PROPRIETARY_CHARGER;
2194 motg->chg_state = USB_CHG_STATE_DETECTED;
2195 delay = 0;
2196 } else {
2197 msm_chg_enable_secondary_det(motg);
2198 delay = MSM_CHG_SECONDARY_DET_TIME;
2199 motg->chg_state = USB_CHG_STATE_PRIMARY_DONE;
2200 }
2201 } else { /* DM < VDAT_REF || DM > VLGC */
Pavankumar Kondetiaa449e12011-11-04 11:09:26 +05302202 if (test_bit(ID_A, &motg->inputs)) {
2203 motg->chg_type = USB_ACA_A_CHARGER;
2204 motg->chg_state = USB_CHG_STATE_DETECTED;
2205 delay = 0;
2206 break;
2207 }
Pavankumar Kondeti9ec21d32012-05-07 15:50:23 +05302208
2209 if (line_state) /* DP > VLGC or/and DM > VLGC */
2210 motg->chg_type = USB_PROPRIETARY_CHARGER;
2211 else
2212 motg->chg_type = USB_SDP_CHARGER;
2213
Pavankumar Kondetid8608522011-05-04 10:19:47 +05302214 motg->chg_state = USB_CHG_STATE_DETECTED;
2215 delay = 0;
2216 }
2217 break;
2218 case USB_CHG_STATE_PRIMARY_DONE:
2219 vout = msm_chg_check_secondary_det(motg);
2220 if (vout)
2221 motg->chg_type = USB_DCP_CHARGER;
2222 else
2223 motg->chg_type = USB_CDP_CHARGER;
2224 motg->chg_state = USB_CHG_STATE_SECONDARY_DONE;
2225 /* fall through */
2226 case USB_CHG_STATE_SECONDARY_DONE:
2227 motg->chg_state = USB_CHG_STATE_DETECTED;
2228 case USB_CHG_STATE_DETECTED:
2229 msm_chg_block_off(motg);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002230 msm_chg_enable_aca_det(motg);
Vijayavardhan Vennapusaa3152032012-03-05 16:29:30 +05302231 /*
2232 * Spurious interrupt is seen after enabling ACA detection
2233 * due to which charger detection fails in case of PET.
2234 * Add delay of 100 microsec to avoid that.
2235 */
2236 udelay(100);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002237 msm_chg_enable_aca_intr(motg);
Steve Mucklef132c6c2012-06-06 18:30:57 -07002238 dev_dbg(phy->dev, "chg_type = %s\n",
Anji jonnalad270e2d2011-08-09 11:28:32 +05302239 chg_to_string(motg->chg_type));
Vijayavardhan Vennapusaa3152032012-03-05 16:29:30 +05302240 queue_work(system_nrt_wq, &motg->sm_work);
Pavankumar Kondetid8608522011-05-04 10:19:47 +05302241 return;
2242 default:
2243 return;
2244 }
2245
Vijayavardhan Vennapusaa3152032012-03-05 16:29:30 +05302246 queue_delayed_work(system_nrt_wq, &motg->chg_work, delay);
Pavankumar Kondetid8608522011-05-04 10:19:47 +05302247}
2248
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05302249/*
2250 * We support OTG, Peripheral only and Host only configurations. In case
2251 * of OTG, mode switch (host-->peripheral/peripheral-->host) can happen
2252 * via Id pin status or user request (debugfs). Id/BSV interrupts are not
2253 * enabled when switch is controlled by user and default mode is supplied
2254 * by board file, which can be changed by userspace later.
2255 */
2256static void msm_otg_init_sm(struct msm_otg *motg)
2257{
2258 struct msm_otg_platform_data *pdata = motg->pdata;
2259 u32 otgsc = readl(USB_OTGSC);
2260
2261 switch (pdata->mode) {
2262 case USB_OTG:
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002263 if (pdata->otg_control == OTG_USER_CONTROL) {
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05302264 if (pdata->default_mode == USB_HOST) {
2265 clear_bit(ID, &motg->inputs);
2266 } else if (pdata->default_mode == USB_PERIPHERAL) {
2267 set_bit(ID, &motg->inputs);
2268 set_bit(B_SESS_VLD, &motg->inputs);
2269 } else {
2270 set_bit(ID, &motg->inputs);
2271 clear_bit(B_SESS_VLD, &motg->inputs);
2272 }
Pavankumar Kondeti4960f312011-12-06 15:46:14 +05302273 } else if (pdata->otg_control == OTG_PHY_CONTROL) {
Vijayavardhan Vennapusaa3152032012-03-05 16:29:30 +05302274 if (otgsc & OTGSC_ID) {
Pavankumar Kondeti4960f312011-12-06 15:46:14 +05302275 set_bit(ID, &motg->inputs);
Vijayavardhan Vennapusaa3152032012-03-05 16:29:30 +05302276 } else {
Pavankumar Kondeti4960f312011-12-06 15:46:14 +05302277 clear_bit(ID, &motg->inputs);
Vijayavardhan Vennapusaa3152032012-03-05 16:29:30 +05302278 set_bit(A_BUS_REQ, &motg->inputs);
2279 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002280 if (otgsc & OTGSC_BSV)
2281 set_bit(B_SESS_VLD, &motg->inputs);
2282 else
2283 clear_bit(B_SESS_VLD, &motg->inputs);
Pavankumar Kondeti4960f312011-12-06 15:46:14 +05302284 } else if (pdata->otg_control == OTG_PMIC_CONTROL) {
Pavankumar Kondeti0d81f312012-01-13 11:34:10 +05302285 if (pdata->pmic_id_irq) {
Stephen Boyd431771e2012-04-18 20:00:23 -07002286 unsigned long flags;
2287 local_irq_save(flags);
Pavankumar Kondeti0d81f312012-01-13 11:34:10 +05302288 if (irq_read_line(pdata->pmic_id_irq))
2289 set_bit(ID, &motg->inputs);
2290 else
2291 clear_bit(ID, &motg->inputs);
Stephen Boyd431771e2012-04-18 20:00:23 -07002292 local_irq_restore(flags);
Pavankumar Kondeti0d81f312012-01-13 11:34:10 +05302293 }
Pavankumar Kondeti4960f312011-12-06 15:46:14 +05302294 /*
2295 * VBUS initial state is reported after PMIC
2296 * driver initialization. Wait for it.
2297 */
2298 wait_for_completion(&pmic_vbus_init);
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05302299 }
2300 break;
2301 case USB_HOST:
2302 clear_bit(ID, &motg->inputs);
2303 break;
2304 case USB_PERIPHERAL:
2305 set_bit(ID, &motg->inputs);
Pavankumar Kondeti0d81f312012-01-13 11:34:10 +05302306 if (pdata->otg_control == OTG_PHY_CONTROL) {
2307 if (otgsc & OTGSC_BSV)
2308 set_bit(B_SESS_VLD, &motg->inputs);
2309 else
2310 clear_bit(B_SESS_VLD, &motg->inputs);
2311 } else if (pdata->otg_control == OTG_PMIC_CONTROL) {
2312 /*
2313 * VBUS initial state is reported after PMIC
2314 * driver initialization. Wait for it.
2315 */
2316 wait_for_completion(&pmic_vbus_init);
2317 }
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05302318 break;
2319 default:
2320 break;
2321 }
2322}
2323
2324static void msm_otg_sm_work(struct work_struct *w)
2325{
2326 struct msm_otg *motg = container_of(w, struct msm_otg, sm_work);
Heikki Krogerus1d4c9292012-02-13 13:24:09 +02002327 struct usb_otg *otg = motg->phy.otg;
Vijayavardhan Vennapusaa3152032012-03-05 16:29:30 +05302328 bool work = 0, srp_reqd;
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05302329
Steve Mucklef132c6c2012-06-06 18:30:57 -07002330 pm_runtime_resume(otg->phy->dev);
2331 pr_debug("%s work\n", otg_state_string(otg->phy->state));
Heikki Krogerus1d4c9292012-02-13 13:24:09 +02002332 switch (otg->phy->state) {
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05302333 case OTG_STATE_UNDEFINED:
Heikki Krogerus1d4c9292012-02-13 13:24:09 +02002334 msm_otg_reset(otg->phy);
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05302335 msm_otg_init_sm(motg);
David Keitel272ce522012-08-17 16:25:24 -07002336 if (!psy && legacy_power_supply) {
2337 psy = power_supply_get_by_name("usb");
2338
2339 if (!psy)
2340 pr_err("couldn't get usb power supply\n");
2341 }
2342
Heikki Krogerus1d4c9292012-02-13 13:24:09 +02002343 otg->phy->state = OTG_STATE_B_IDLE;
Pavankumar Kondeti8a379b42011-12-12 13:07:23 +05302344 if (!test_bit(B_SESS_VLD, &motg->inputs) &&
2345 test_bit(ID, &motg->inputs)) {
Steve Mucklef132c6c2012-06-06 18:30:57 -07002346 pm_runtime_put_noidle(otg->phy->dev);
2347 pm_runtime_suspend(otg->phy->dev);
Pavankumar Kondeti8a379b42011-12-12 13:07:23 +05302348 break;
2349 }
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05302350 /* FALL THROUGH */
2351 case OTG_STATE_B_IDLE:
Pavankumar Kondeti2aec9f32012-06-13 09:06:03 +05302352 if (test_bit(MHL, &motg->inputs)) {
2353 /* allow LPM */
2354 pm_runtime_put_noidle(otg->phy->dev);
2355 pm_runtime_suspend(otg->phy->dev);
2356 } else if ((!test_bit(ID, &motg->inputs) ||
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002357 test_bit(ID_A, &motg->inputs)) && otg->host) {
Vijayavardhan Vennapusaa3152032012-03-05 16:29:30 +05302358 pr_debug("!id || id_A\n");
Pavankumar Kondeti2aec9f32012-06-13 09:06:03 +05302359 if (msm_chg_mhl_detect(motg)) {
2360 work = 1;
2361 break;
2362 }
Vijayavardhan Vennapusaa3152032012-03-05 16:29:30 +05302363 clear_bit(B_BUS_REQ, &motg->inputs);
2364 set_bit(A_BUS_REQ, &motg->inputs);
Steve Mucklef132c6c2012-06-06 18:30:57 -07002365 otg->phy->state = OTG_STATE_A_IDLE;
Vijayavardhan Vennapusaa3152032012-03-05 16:29:30 +05302366 work = 1;
Pavankumar Kondetid8608522011-05-04 10:19:47 +05302367 } else if (test_bit(B_SESS_VLD, &motg->inputs)) {
Vijayavardhan Vennapusaa3152032012-03-05 16:29:30 +05302368 pr_debug("b_sess_vld\n");
Pavankumar Kondetid8608522011-05-04 10:19:47 +05302369 switch (motg->chg_state) {
2370 case USB_CHG_STATE_UNDEFINED:
2371 msm_chg_detect_work(&motg->chg_work.work);
2372 break;
2373 case USB_CHG_STATE_DETECTED:
2374 switch (motg->chg_type) {
2375 case USB_DCP_CHARGER:
Pavankumar Kondeti283146f2012-01-12 12:51:19 +05302376 /* Enable VDP_SRC */
Steve Mucklef132c6c2012-06-06 18:30:57 -07002377 ulpi_write(otg->phy, 0x2, 0x85);
Pavankumar Kondeti9ec21d32012-05-07 15:50:23 +05302378 /* fall through */
2379 case USB_PROPRIETARY_CHARGER:
Pavankumar Kondetid8608522011-05-04 10:19:47 +05302380 msm_otg_notify_charger(motg,
2381 IDEV_CHG_MAX);
Steve Mucklef132c6c2012-06-06 18:30:57 -07002382 pm_runtime_put_noidle(otg->phy->dev);
2383 pm_runtime_suspend(otg->phy->dev);
Pavankumar Kondetid8608522011-05-04 10:19:47 +05302384 break;
Pavankumar Kondetiaa449e12011-11-04 11:09:26 +05302385 case USB_ACA_B_CHARGER:
2386 msm_otg_notify_charger(motg,
2387 IDEV_ACA_CHG_MAX);
2388 /*
2389 * (ID_B --> ID_C) PHY_ALT interrupt can
2390 * not be detected in LPM.
2391 */
Pavankumar Kondetid8608522011-05-04 10:19:47 +05302392 break;
2393 case USB_CDP_CHARGER:
2394 msm_otg_notify_charger(motg,
2395 IDEV_CHG_MAX);
2396 msm_otg_start_peripheral(otg, 1);
Steve Mucklef132c6c2012-06-06 18:30:57 -07002397 otg->phy->state =
2398 OTG_STATE_B_PERIPHERAL;
Pavankumar Kondetid8608522011-05-04 10:19:47 +05302399 break;
Pavankumar Kondetiaa449e12011-11-04 11:09:26 +05302400 case USB_ACA_C_CHARGER:
2401 msm_otg_notify_charger(motg,
2402 IDEV_ACA_CHG_MAX);
2403 msm_otg_start_peripheral(otg, 1);
Steve Mucklef132c6c2012-06-06 18:30:57 -07002404 otg->phy->state =
2405 OTG_STATE_B_PERIPHERAL;
Pavankumar Kondetid8608522011-05-04 10:19:47 +05302406 break;
2407 case USB_SDP_CHARGER:
Pavankumar Kondetid8608522011-05-04 10:19:47 +05302408 msm_otg_start_peripheral(otg, 1);
Steve Mucklef132c6c2012-06-06 18:30:57 -07002409 otg->phy->state =
2410 OTG_STATE_B_PERIPHERAL;
Pavankumar Kondeti458d8792012-09-28 14:45:18 +05302411 mod_timer(&motg->chg_check_timer,
2412 CHG_RECHECK_DELAY);
Pavankumar Kondetid8608522011-05-04 10:19:47 +05302413 break;
2414 default:
2415 break;
2416 }
2417 break;
2418 default:
2419 break;
2420 }
Vijayavardhan Vennapusaa3152032012-03-05 16:29:30 +05302421 } else if (test_bit(B_BUS_REQ, &motg->inputs)) {
2422 pr_debug("b_sess_end && b_bus_req\n");
2423 if (msm_otg_start_srp(otg) < 0) {
2424 clear_bit(B_BUS_REQ, &motg->inputs);
2425 work = 1;
2426 break;
Pavankumar Kondetid8608522011-05-04 10:19:47 +05302427 }
Steve Mucklef132c6c2012-06-06 18:30:57 -07002428 otg->phy->state = OTG_STATE_B_SRP_INIT;
Vijayavardhan Vennapusaa3152032012-03-05 16:29:30 +05302429 msm_otg_start_timer(motg, TB_SRP_FAIL, B_SRP_FAIL);
2430 break;
Pavankumar Kondetid8608522011-05-04 10:19:47 +05302431 } else {
Vijayavardhan Vennapusaa3152032012-03-05 16:29:30 +05302432 pr_debug("chg_work cancel");
Pavankumar Kondeti458d8792012-09-28 14:45:18 +05302433 del_timer_sync(&motg->chg_check_timer);
2434 clear_bit(B_FALSE_SDP, &motg->inputs);
Pavankumar Kondetiaa449e12011-11-04 11:09:26 +05302435 cancel_delayed_work_sync(&motg->chg_work);
Pavankumar Kondetid8608522011-05-04 10:19:47 +05302436 motg->chg_state = USB_CHG_STATE_UNDEFINED;
2437 motg->chg_type = USB_INVALID_CHARGER;
Rajkumar Raghupathy18fd7132012-04-20 11:28:13 +05302438 msm_otg_notify_charger(motg, 0);
Steve Mucklef132c6c2012-06-06 18:30:57 -07002439 msm_otg_reset(otg->phy);
2440 pm_runtime_put_noidle(otg->phy->dev);
2441 pm_runtime_suspend(otg->phy->dev);
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05302442 }
2443 break;
Vijayavardhan Vennapusaa3152032012-03-05 16:29:30 +05302444 case OTG_STATE_B_SRP_INIT:
2445 if (!test_bit(ID, &motg->inputs) ||
2446 test_bit(ID_A, &motg->inputs) ||
2447 test_bit(ID_C, &motg->inputs) ||
2448 (test_bit(B_SESS_VLD, &motg->inputs) &&
2449 !test_bit(ID_B, &motg->inputs))) {
2450 pr_debug("!id || id_a/c || b_sess_vld+!id_b\n");
2451 msm_otg_del_timer(motg);
Steve Mucklef132c6c2012-06-06 18:30:57 -07002452 otg->phy->state = OTG_STATE_B_IDLE;
Vijayavardhan Vennapusaa3152032012-03-05 16:29:30 +05302453 /*
2454 * clear VBUSVLDEXTSEL and VBUSVLDEXT register
2455 * bits after SRP initiation.
2456 */
Steve Mucklef132c6c2012-06-06 18:30:57 -07002457 ulpi_write(otg->phy, 0x0, 0x98);
Vijayavardhan Vennapusaa3152032012-03-05 16:29:30 +05302458 work = 1;
2459 } else if (test_bit(B_SRP_FAIL, &motg->tmouts)) {
2460 pr_debug("b_srp_fail\n");
2461 pr_info("A-device did not respond to SRP\n");
2462 clear_bit(B_BUS_REQ, &motg->inputs);
2463 clear_bit(B_SRP_FAIL, &motg->tmouts);
2464 otg_send_event(OTG_EVENT_NO_RESP_FOR_SRP);
Steve Mucklef132c6c2012-06-06 18:30:57 -07002465 ulpi_write(otg->phy, 0x0, 0x98);
2466 otg->phy->state = OTG_STATE_B_IDLE;
Vijayavardhan Vennapusaa3152032012-03-05 16:29:30 +05302467 motg->b_last_se0_sess = jiffies;
2468 work = 1;
2469 }
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05302470 break;
2471 case OTG_STATE_B_PERIPHERAL:
Pavankumar Kondeti458d8792012-09-28 14:45:18 +05302472 if (test_bit(B_SESS_VLD, &motg->inputs) &&
2473 test_bit(B_FALSE_SDP, &motg->inputs)) {
2474 pr_debug("B_FALSE_SDP\n");
2475 msm_otg_start_peripheral(otg, 0);
2476 motg->chg_type = USB_DCP_CHARGER;
2477 clear_bit(B_FALSE_SDP, &motg->inputs);
2478 otg->phy->state = OTG_STATE_B_IDLE;
2479 work = 1;
2480 } else if (!test_bit(ID, &motg->inputs) ||
Vijayavardhan Vennapusaa3152032012-03-05 16:29:30 +05302481 test_bit(ID_A, &motg->inputs) ||
2482 test_bit(ID_B, &motg->inputs) ||
2483 !test_bit(B_SESS_VLD, &motg->inputs)) {
2484 pr_debug("!id || id_a/b || !b_sess_vld\n");
Pavankumar Kondetid8608522011-05-04 10:19:47 +05302485 motg->chg_state = USB_CHG_STATE_UNDEFINED;
2486 motg->chg_type = USB_INVALID_CHARGER;
Vijayavardhan Vennapusaa3152032012-03-05 16:29:30 +05302487 msm_otg_notify_charger(motg, 0);
2488 srp_reqd = otg->gadget->otg_srp_reqd;
2489 msm_otg_start_peripheral(otg, 0);
Vijayavardhan Vennapusaa3152032012-03-05 16:29:30 +05302490 if (test_bit(ID_B, &motg->inputs))
2491 clear_bit(ID_B, &motg->inputs);
2492 clear_bit(B_BUS_REQ, &motg->inputs);
Steve Mucklef132c6c2012-06-06 18:30:57 -07002493 otg->phy->state = OTG_STATE_B_IDLE;
Vijayavardhan Vennapusaa3152032012-03-05 16:29:30 +05302494 motg->b_last_se0_sess = jiffies;
2495 if (srp_reqd)
2496 msm_otg_start_timer(motg,
2497 TB_TST_SRP, B_TST_SRP);
2498 else
2499 work = 1;
2500 } else if (test_bit(B_BUS_REQ, &motg->inputs) &&
2501 otg->gadget->b_hnp_enable &&
2502 test_bit(A_BUS_SUSPEND, &motg->inputs)) {
2503 pr_debug("b_bus_req && b_hnp_en && a_bus_suspend\n");
2504 msm_otg_start_timer(motg, TB_ASE0_BRST, B_ASE0_BRST);
2505 /* D+ pullup should not be disconnected within 4msec
2506 * after A device suspends the bus. Otherwise PET will
2507 * fail the compliance test.
2508 */
2509 udelay(1000);
2510 msm_otg_start_peripheral(otg, 0);
Steve Mucklef132c6c2012-06-06 18:30:57 -07002511 otg->phy->state = OTG_STATE_B_WAIT_ACON;
Vijayavardhan Vennapusaa3152032012-03-05 16:29:30 +05302512 /*
2513 * start HCD even before A-device enable
2514 * pull-up to meet HNP timings.
2515 */
2516 otg->host->is_b_host = 1;
2517 msm_otg_start_host(otg, 1);
Amit Blay6fa647a2012-05-24 14:12:08 +03002518 } else if (test_bit(A_BUS_SUSPEND, &motg->inputs) &&
2519 test_bit(B_SESS_VLD, &motg->inputs)) {
2520 pr_debug("a_bus_suspend && b_sess_vld\n");
2521 if (motg->caps & ALLOW_LPM_ON_DEV_SUSPEND) {
Steve Mucklef132c6c2012-06-06 18:30:57 -07002522 pm_runtime_put_noidle(otg->phy->dev);
2523 pm_runtime_suspend(otg->phy->dev);
Amit Blay6fa647a2012-05-24 14:12:08 +03002524 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002525 } else if (test_bit(ID_C, &motg->inputs)) {
Pavankumar Kondetiaa449e12011-11-04 11:09:26 +05302526 msm_otg_notify_charger(motg, IDEV_ACA_CHG_MAX);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002527 }
2528 break;
Vijayavardhan Vennapusaa3152032012-03-05 16:29:30 +05302529 case OTG_STATE_B_WAIT_ACON:
2530 if (!test_bit(ID, &motg->inputs) ||
2531 test_bit(ID_A, &motg->inputs) ||
2532 test_bit(ID_B, &motg->inputs) ||
2533 !test_bit(B_SESS_VLD, &motg->inputs)) {
2534 pr_debug("!id || id_a/b || !b_sess_vld\n");
2535 msm_otg_del_timer(motg);
Pavankumar Kondetiaa449e12011-11-04 11:09:26 +05302536 /*
Vijayavardhan Vennapusaa3152032012-03-05 16:29:30 +05302537 * A-device is physically disconnected during
2538 * HNP. Remove HCD.
Pavankumar Kondetiaa449e12011-11-04 11:09:26 +05302539 */
Vijayavardhan Vennapusaa3152032012-03-05 16:29:30 +05302540 msm_otg_start_host(otg, 0);
2541 otg->host->is_b_host = 0;
2542
2543 clear_bit(B_BUS_REQ, &motg->inputs);
2544 clear_bit(A_BUS_SUSPEND, &motg->inputs);
2545 motg->b_last_se0_sess = jiffies;
Heikki Krogerus1d4c9292012-02-13 13:24:09 +02002546 otg->phy->state = OTG_STATE_B_IDLE;
2547 msm_otg_reset(otg->phy);
Vijayavardhan Vennapusaa3152032012-03-05 16:29:30 +05302548 work = 1;
2549 } else if (test_bit(A_CONN, &motg->inputs)) {
2550 pr_debug("a_conn\n");
2551 clear_bit(A_BUS_SUSPEND, &motg->inputs);
Steve Mucklef132c6c2012-06-06 18:30:57 -07002552 otg->phy->state = OTG_STATE_B_HOST;
Vijayavardhan Vennapusaa3152032012-03-05 16:29:30 +05302553 /*
2554 * PET disconnects D+ pullup after reset is generated
2555 * by B device in B_HOST role which is not detected by
2556 * B device. As workaorund , start timer of 300msec
2557 * and stop timer if A device is enumerated else clear
2558 * A_CONN.
2559 */
2560 msm_otg_start_timer(motg, TB_TST_CONFIG,
2561 B_TST_CONFIG);
2562 } else if (test_bit(B_ASE0_BRST, &motg->tmouts)) {
2563 pr_debug("b_ase0_brst_tmout\n");
2564 pr_info("B HNP fail:No response from A device\n");
2565 msm_otg_start_host(otg, 0);
Steve Mucklef132c6c2012-06-06 18:30:57 -07002566 msm_otg_reset(otg->phy);
Vijayavardhan Vennapusaa3152032012-03-05 16:29:30 +05302567 otg->host->is_b_host = 0;
2568 clear_bit(B_ASE0_BRST, &motg->tmouts);
2569 clear_bit(A_BUS_SUSPEND, &motg->inputs);
2570 clear_bit(B_BUS_REQ, &motg->inputs);
2571 otg_send_event(OTG_EVENT_HNP_FAILED);
Steve Mucklef132c6c2012-06-06 18:30:57 -07002572 otg->phy->state = OTG_STATE_B_IDLE;
Vijayavardhan Vennapusaa3152032012-03-05 16:29:30 +05302573 work = 1;
2574 } else if (test_bit(ID_C, &motg->inputs)) {
2575 msm_otg_notify_charger(motg, IDEV_ACA_CHG_MAX);
2576 }
2577 break;
2578 case OTG_STATE_B_HOST:
2579 if (!test_bit(B_BUS_REQ, &motg->inputs) ||
2580 !test_bit(A_CONN, &motg->inputs) ||
2581 !test_bit(B_SESS_VLD, &motg->inputs)) {
2582 pr_debug("!b_bus_req || !a_conn || !b_sess_vld\n");
2583 clear_bit(A_CONN, &motg->inputs);
2584 clear_bit(B_BUS_REQ, &motg->inputs);
2585 msm_otg_start_host(otg, 0);
2586 otg->host->is_b_host = 0;
Steve Mucklef132c6c2012-06-06 18:30:57 -07002587 otg->phy->state = OTG_STATE_B_IDLE;
2588 msm_otg_reset(otg->phy);
Vijayavardhan Vennapusaa3152032012-03-05 16:29:30 +05302589 work = 1;
2590 } else if (test_bit(ID_C, &motg->inputs)) {
2591 msm_otg_notify_charger(motg, IDEV_ACA_CHG_MAX);
2592 }
2593 break;
2594 case OTG_STATE_A_IDLE:
2595 otg->default_a = 1;
2596 if (test_bit(ID, &motg->inputs) &&
2597 !test_bit(ID_A, &motg->inputs)) {
2598 pr_debug("id && !id_a\n");
2599 otg->default_a = 0;
2600 clear_bit(A_BUS_DROP, &motg->inputs);
Steve Mucklef132c6c2012-06-06 18:30:57 -07002601 otg->phy->state = OTG_STATE_B_IDLE;
Vijayavardhan Vennapusaa3152032012-03-05 16:29:30 +05302602 del_timer_sync(&motg->id_timer);
2603 msm_otg_link_reset(motg);
2604 msm_chg_enable_aca_intr(motg);
2605 msm_otg_notify_charger(motg, 0);
2606 work = 1;
2607 } else if (!test_bit(A_BUS_DROP, &motg->inputs) &&
2608 (test_bit(A_SRP_DET, &motg->inputs) ||
2609 test_bit(A_BUS_REQ, &motg->inputs))) {
2610 pr_debug("!a_bus_drop && (a_srp_det || a_bus_req)\n");
2611
2612 clear_bit(A_SRP_DET, &motg->inputs);
2613 /* Disable SRP detection */
2614 writel_relaxed((readl_relaxed(USB_OTGSC) &
2615 ~OTGSC_INTSTS_MASK) &
2616 ~OTGSC_DPIE, USB_OTGSC);
2617
Steve Mucklef132c6c2012-06-06 18:30:57 -07002618 otg->phy->state = OTG_STATE_A_WAIT_VRISE;
Vijayavardhan Vennapusaa3152032012-03-05 16:29:30 +05302619 /* VBUS should not be supplied before end of SRP pulse
2620 * generated by PET, if not complaince test fail.
2621 */
2622 usleep_range(10000, 12000);
2623 /* ACA: ID_A: Stop charging untill enumeration */
2624 if (test_bit(ID_A, &motg->inputs))
2625 msm_otg_notify_charger(motg, 0);
2626 else
2627 msm_hsusb_vbus_power(motg, 1);
2628 msm_otg_start_timer(motg, TA_WAIT_VRISE, A_WAIT_VRISE);
2629 } else {
2630 pr_debug("No session requested\n");
2631 clear_bit(A_BUS_DROP, &motg->inputs);
2632 if (test_bit(ID_A, &motg->inputs)) {
2633 msm_otg_notify_charger(motg,
2634 IDEV_ACA_CHG_MAX);
2635 } else if (!test_bit(ID, &motg->inputs)) {
2636 msm_otg_notify_charger(motg, 0);
2637 /*
2638 * A-device is not providing power on VBUS.
2639 * Enable SRP detection.
2640 */
2641 writel_relaxed(0x13, USB_USBMODE);
2642 writel_relaxed((readl_relaxed(USB_OTGSC) &
2643 ~OTGSC_INTSTS_MASK) |
2644 OTGSC_DPIE, USB_OTGSC);
2645 mb();
2646 }
2647 }
2648 break;
2649 case OTG_STATE_A_WAIT_VRISE:
2650 if ((test_bit(ID, &motg->inputs) &&
2651 !test_bit(ID_A, &motg->inputs)) ||
2652 test_bit(A_BUS_DROP, &motg->inputs) ||
2653 test_bit(A_WAIT_VRISE, &motg->tmouts)) {
2654 pr_debug("id || a_bus_drop || a_wait_vrise_tmout\n");
2655 clear_bit(A_BUS_REQ, &motg->inputs);
2656 msm_otg_del_timer(motg);
2657 msm_hsusb_vbus_power(motg, 0);
Steve Mucklef132c6c2012-06-06 18:30:57 -07002658 otg->phy->state = OTG_STATE_A_WAIT_VFALL;
Vijayavardhan Vennapusaa3152032012-03-05 16:29:30 +05302659 msm_otg_start_timer(motg, TA_WAIT_VFALL, A_WAIT_VFALL);
2660 } else if (test_bit(A_VBUS_VLD, &motg->inputs)) {
2661 pr_debug("a_vbus_vld\n");
Steve Mucklef132c6c2012-06-06 18:30:57 -07002662 otg->phy->state = OTG_STATE_A_WAIT_BCON;
Vijayavardhan Vennapusaa3152032012-03-05 16:29:30 +05302663 if (TA_WAIT_BCON > 0)
2664 msm_otg_start_timer(motg, TA_WAIT_BCON,
2665 A_WAIT_BCON);
2666 msm_otg_start_host(otg, 1);
2667 msm_chg_enable_aca_det(motg);
2668 msm_chg_disable_aca_intr(motg);
Chiranjeevi Velempati489a27c2012-03-29 09:47:17 +05302669 mod_timer(&motg->id_timer, ID_TIMER_FREQ);
Vijayavardhan Vennapusaa3152032012-03-05 16:29:30 +05302670 if (msm_chg_check_aca_intr(motg))
2671 work = 1;
2672 }
2673 break;
2674 case OTG_STATE_A_WAIT_BCON:
2675 if ((test_bit(ID, &motg->inputs) &&
2676 !test_bit(ID_A, &motg->inputs)) ||
2677 test_bit(A_BUS_DROP, &motg->inputs) ||
2678 test_bit(A_WAIT_BCON, &motg->tmouts)) {
2679 pr_debug("(id && id_a/b/c) || a_bus_drop ||"
2680 "a_wait_bcon_tmout\n");
2681 if (test_bit(A_WAIT_BCON, &motg->tmouts)) {
2682 pr_info("Device No Response\n");
2683 otg_send_event(OTG_EVENT_DEV_CONN_TMOUT);
2684 }
2685 msm_otg_del_timer(motg);
2686 clear_bit(A_BUS_REQ, &motg->inputs);
2687 clear_bit(B_CONN, &motg->inputs);
2688 msm_otg_start_host(otg, 0);
2689 /*
2690 * ACA: ID_A with NO accessory, just the A plug is
2691 * attached to ACA: Use IDCHG_MAX for charging
2692 */
2693 if (test_bit(ID_A, &motg->inputs))
2694 msm_otg_notify_charger(motg, IDEV_CHG_MIN);
2695 else
2696 msm_hsusb_vbus_power(motg, 0);
Steve Mucklef132c6c2012-06-06 18:30:57 -07002697 otg->phy->state = OTG_STATE_A_WAIT_VFALL;
Vijayavardhan Vennapusaa3152032012-03-05 16:29:30 +05302698 msm_otg_start_timer(motg, TA_WAIT_VFALL, A_WAIT_VFALL);
2699 } else if (!test_bit(A_VBUS_VLD, &motg->inputs)) {
2700 pr_debug("!a_vbus_vld\n");
2701 clear_bit(B_CONN, &motg->inputs);
2702 msm_otg_del_timer(motg);
2703 msm_otg_start_host(otg, 0);
Steve Mucklef132c6c2012-06-06 18:30:57 -07002704 otg->phy->state = OTG_STATE_A_VBUS_ERR;
2705 msm_otg_reset(otg->phy);
Vijayavardhan Vennapusaa3152032012-03-05 16:29:30 +05302706 } else if (test_bit(ID_A, &motg->inputs)) {
2707 msm_hsusb_vbus_power(motg, 0);
2708 } else if (!test_bit(A_BUS_REQ, &motg->inputs)) {
2709 /*
2710 * If TA_WAIT_BCON is infinite, we don;t
2711 * turn off VBUS. Enter low power mode.
2712 */
2713 if (TA_WAIT_BCON < 0)
Steve Mucklef132c6c2012-06-06 18:30:57 -07002714 pm_runtime_put_sync(otg->phy->dev);
Vijayavardhan Vennapusaa3152032012-03-05 16:29:30 +05302715 } else if (!test_bit(ID, &motg->inputs)) {
2716 msm_hsusb_vbus_power(motg, 1);
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05302717 }
2718 break;
2719 case OTG_STATE_A_HOST:
Vijayavardhan Vennapusaa3152032012-03-05 16:29:30 +05302720 if ((test_bit(ID, &motg->inputs) &&
2721 !test_bit(ID_A, &motg->inputs)) ||
2722 test_bit(A_BUS_DROP, &motg->inputs)) {
2723 pr_debug("id_a/b/c || a_bus_drop\n");
2724 clear_bit(B_CONN, &motg->inputs);
2725 clear_bit(A_BUS_REQ, &motg->inputs);
2726 msm_otg_del_timer(motg);
Steve Mucklef132c6c2012-06-06 18:30:57 -07002727 otg->phy->state = OTG_STATE_A_WAIT_VFALL;
Vijayavardhan Vennapusaa3152032012-03-05 16:29:30 +05302728 msm_otg_start_host(otg, 0);
2729 if (!test_bit(ID_A, &motg->inputs))
2730 msm_hsusb_vbus_power(motg, 0);
2731 msm_otg_start_timer(motg, TA_WAIT_VFALL, A_WAIT_VFALL);
2732 } else if (!test_bit(A_VBUS_VLD, &motg->inputs)) {
2733 pr_debug("!a_vbus_vld\n");
2734 clear_bit(B_CONN, &motg->inputs);
2735 msm_otg_del_timer(motg);
Steve Mucklef132c6c2012-06-06 18:30:57 -07002736 otg->phy->state = OTG_STATE_A_VBUS_ERR;
Vijayavardhan Vennapusaa3152032012-03-05 16:29:30 +05302737 msm_otg_start_host(otg, 0);
Heikki Krogerus1d4c9292012-02-13 13:24:09 +02002738 msm_otg_reset(otg->phy);
Vijayavardhan Vennapusaa3152032012-03-05 16:29:30 +05302739 } else if (!test_bit(A_BUS_REQ, &motg->inputs)) {
2740 /*
2741 * a_bus_req is de-asserted when root hub is
2742 * suspended or HNP is in progress.
2743 */
2744 pr_debug("!a_bus_req\n");
2745 msm_otg_del_timer(motg);
Steve Mucklef132c6c2012-06-06 18:30:57 -07002746 otg->phy->state = OTG_STATE_A_SUSPEND;
Vijayavardhan Vennapusaa3152032012-03-05 16:29:30 +05302747 if (otg->host->b_hnp_enable)
2748 msm_otg_start_timer(motg, TA_AIDL_BDIS,
2749 A_AIDL_BDIS);
2750 else
Steve Mucklef132c6c2012-06-06 18:30:57 -07002751 pm_runtime_put_sync(otg->phy->dev);
Vijayavardhan Vennapusaa3152032012-03-05 16:29:30 +05302752 } else if (!test_bit(B_CONN, &motg->inputs)) {
2753 pr_debug("!b_conn\n");
2754 msm_otg_del_timer(motg);
Steve Mucklef132c6c2012-06-06 18:30:57 -07002755 otg->phy->state = OTG_STATE_A_WAIT_BCON;
Vijayavardhan Vennapusaa3152032012-03-05 16:29:30 +05302756 if (TA_WAIT_BCON > 0)
2757 msm_otg_start_timer(motg, TA_WAIT_BCON,
2758 A_WAIT_BCON);
2759 if (msm_chg_check_aca_intr(motg))
2760 work = 1;
2761 } else if (test_bit(ID_A, &motg->inputs)) {
2762 msm_otg_del_timer(motg);
2763 msm_hsusb_vbus_power(motg, 0);
2764 if (motg->chg_type == USB_ACA_DOCK_CHARGER)
2765 msm_otg_notify_charger(motg,
2766 IDEV_ACA_CHG_MAX);
2767 else
2768 msm_otg_notify_charger(motg,
2769 IDEV_CHG_MIN - motg->mA_port);
2770 } else if (!test_bit(ID, &motg->inputs)) {
2771 motg->chg_state = USB_CHG_STATE_UNDEFINED;
2772 motg->chg_type = USB_INVALID_CHARGER;
2773 msm_otg_notify_charger(motg, 0);
2774 msm_hsusb_vbus_power(motg, 1);
2775 }
2776 break;
2777 case OTG_STATE_A_SUSPEND:
2778 if ((test_bit(ID, &motg->inputs) &&
2779 !test_bit(ID_A, &motg->inputs)) ||
2780 test_bit(A_BUS_DROP, &motg->inputs) ||
2781 test_bit(A_AIDL_BDIS, &motg->tmouts)) {
2782 pr_debug("id_a/b/c || a_bus_drop ||"
2783 "a_aidl_bdis_tmout\n");
2784 msm_otg_del_timer(motg);
2785 clear_bit(B_CONN, &motg->inputs);
Steve Mucklef132c6c2012-06-06 18:30:57 -07002786 otg->phy->state = OTG_STATE_A_WAIT_VFALL;
Vijayavardhan Vennapusaa3152032012-03-05 16:29:30 +05302787 msm_otg_start_host(otg, 0);
Steve Mucklef132c6c2012-06-06 18:30:57 -07002788 msm_otg_reset(otg->phy);
Vijayavardhan Vennapusaa3152032012-03-05 16:29:30 +05302789 if (!test_bit(ID_A, &motg->inputs))
2790 msm_hsusb_vbus_power(motg, 0);
2791 msm_otg_start_timer(motg, TA_WAIT_VFALL, A_WAIT_VFALL);
2792 } else if (!test_bit(A_VBUS_VLD, &motg->inputs)) {
2793 pr_debug("!a_vbus_vld\n");
2794 msm_otg_del_timer(motg);
2795 clear_bit(B_CONN, &motg->inputs);
Steve Mucklef132c6c2012-06-06 18:30:57 -07002796 otg->phy->state = OTG_STATE_A_VBUS_ERR;
Vijayavardhan Vennapusaa3152032012-03-05 16:29:30 +05302797 msm_otg_start_host(otg, 0);
Steve Mucklef132c6c2012-06-06 18:30:57 -07002798 msm_otg_reset(otg->phy);
Vijayavardhan Vennapusaa3152032012-03-05 16:29:30 +05302799 } else if (!test_bit(B_CONN, &motg->inputs) &&
2800 otg->host->b_hnp_enable) {
2801 pr_debug("!b_conn && b_hnp_enable");
Steve Mucklef132c6c2012-06-06 18:30:57 -07002802 otg->phy->state = OTG_STATE_A_PERIPHERAL;
Vijayavardhan Vennapusaa3152032012-03-05 16:29:30 +05302803 msm_otg_host_hnp_enable(otg, 1);
2804 otg->gadget->is_a_peripheral = 1;
2805 msm_otg_start_peripheral(otg, 1);
2806 } else if (!test_bit(B_CONN, &motg->inputs) &&
2807 !otg->host->b_hnp_enable) {
2808 pr_debug("!b_conn && !b_hnp_enable");
2809 /*
2810 * bus request is dropped during suspend.
2811 * acquire again for next device.
2812 */
2813 set_bit(A_BUS_REQ, &motg->inputs);
Steve Mucklef132c6c2012-06-06 18:30:57 -07002814 otg->phy->state = OTG_STATE_A_WAIT_BCON;
Vijayavardhan Vennapusaa3152032012-03-05 16:29:30 +05302815 if (TA_WAIT_BCON > 0)
2816 msm_otg_start_timer(motg, TA_WAIT_BCON,
2817 A_WAIT_BCON);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002818 } else if (test_bit(ID_A, &motg->inputs)) {
Mayank Ranae3926882011-12-26 09:47:54 +05302819 msm_hsusb_vbus_power(motg, 0);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002820 msm_otg_notify_charger(motg,
Vijayavardhan Vennapusaa3152032012-03-05 16:29:30 +05302821 IDEV_CHG_MIN - motg->mA_port);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002822 } else if (!test_bit(ID, &motg->inputs)) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002823 msm_otg_notify_charger(motg, 0);
Mayank Ranae3926882011-12-26 09:47:54 +05302824 msm_hsusb_vbus_power(motg, 1);
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05302825 }
2826 break;
Vijayavardhan Vennapusaa3152032012-03-05 16:29:30 +05302827 case OTG_STATE_A_PERIPHERAL:
2828 if ((test_bit(ID, &motg->inputs) &&
2829 !test_bit(ID_A, &motg->inputs)) ||
2830 test_bit(A_BUS_DROP, &motg->inputs)) {
2831 pr_debug("id _f/b/c || a_bus_drop\n");
2832 /* Clear BIDL_ADIS timer */
2833 msm_otg_del_timer(motg);
Steve Mucklef132c6c2012-06-06 18:30:57 -07002834 otg->phy->state = OTG_STATE_A_WAIT_VFALL;
Vijayavardhan Vennapusaa3152032012-03-05 16:29:30 +05302835 msm_otg_start_peripheral(otg, 0);
2836 otg->gadget->is_a_peripheral = 0;
2837 msm_otg_start_host(otg, 0);
Steve Mucklef132c6c2012-06-06 18:30:57 -07002838 msm_otg_reset(otg->phy);
Vijayavardhan Vennapusaa3152032012-03-05 16:29:30 +05302839 if (!test_bit(ID_A, &motg->inputs))
2840 msm_hsusb_vbus_power(motg, 0);
2841 msm_otg_start_timer(motg, TA_WAIT_VFALL, A_WAIT_VFALL);
2842 } else if (!test_bit(A_VBUS_VLD, &motg->inputs)) {
2843 pr_debug("!a_vbus_vld\n");
2844 /* Clear BIDL_ADIS timer */
2845 msm_otg_del_timer(motg);
Steve Mucklef132c6c2012-06-06 18:30:57 -07002846 otg->phy->state = OTG_STATE_A_VBUS_ERR;
Vijayavardhan Vennapusaa3152032012-03-05 16:29:30 +05302847 msm_otg_start_peripheral(otg, 0);
2848 otg->gadget->is_a_peripheral = 0;
2849 msm_otg_start_host(otg, 0);
2850 } else if (test_bit(A_BIDL_ADIS, &motg->tmouts)) {
2851 pr_debug("a_bidl_adis_tmout\n");
2852 msm_otg_start_peripheral(otg, 0);
2853 otg->gadget->is_a_peripheral = 0;
Steve Mucklef132c6c2012-06-06 18:30:57 -07002854 otg->phy->state = OTG_STATE_A_WAIT_BCON;
Vijayavardhan Vennapusaa3152032012-03-05 16:29:30 +05302855 set_bit(A_BUS_REQ, &motg->inputs);
2856 msm_otg_host_hnp_enable(otg, 0);
2857 if (TA_WAIT_BCON > 0)
2858 msm_otg_start_timer(motg, TA_WAIT_BCON,
2859 A_WAIT_BCON);
2860 } else if (test_bit(ID_A, &motg->inputs)) {
2861 msm_hsusb_vbus_power(motg, 0);
2862 msm_otg_notify_charger(motg,
2863 IDEV_CHG_MIN - motg->mA_port);
2864 } else if (!test_bit(ID, &motg->inputs)) {
2865 msm_otg_notify_charger(motg, 0);
2866 msm_hsusb_vbus_power(motg, 1);
2867 }
2868 break;
2869 case OTG_STATE_A_WAIT_VFALL:
2870 if (test_bit(A_WAIT_VFALL, &motg->tmouts)) {
2871 clear_bit(A_VBUS_VLD, &motg->inputs);
Steve Mucklef132c6c2012-06-06 18:30:57 -07002872 otg->phy->state = OTG_STATE_A_IDLE;
Vijayavardhan Vennapusaa3152032012-03-05 16:29:30 +05302873 work = 1;
2874 }
2875 break;
2876 case OTG_STATE_A_VBUS_ERR:
2877 if ((test_bit(ID, &motg->inputs) &&
2878 !test_bit(ID_A, &motg->inputs)) ||
2879 test_bit(A_BUS_DROP, &motg->inputs) ||
2880 test_bit(A_CLR_ERR, &motg->inputs)) {
Steve Mucklef132c6c2012-06-06 18:30:57 -07002881 otg->phy->state = OTG_STATE_A_WAIT_VFALL;
Vijayavardhan Vennapusaa3152032012-03-05 16:29:30 +05302882 if (!test_bit(ID_A, &motg->inputs))
2883 msm_hsusb_vbus_power(motg, 0);
2884 msm_otg_start_timer(motg, TA_WAIT_VFALL, A_WAIT_VFALL);
2885 motg->chg_state = USB_CHG_STATE_UNDEFINED;
2886 motg->chg_type = USB_INVALID_CHARGER;
2887 msm_otg_notify_charger(motg, 0);
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05302888 }
2889 break;
2890 default:
2891 break;
2892 }
Vijayavardhan Vennapusaa3152032012-03-05 16:29:30 +05302893 if (work)
2894 queue_work(system_nrt_wq, &motg->sm_work);
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05302895}
2896
Amit Blayd0fe07b2012-09-05 16:42:09 +03002897static void msm_otg_suspend_work(struct work_struct *w)
2898{
2899 struct msm_otg *motg =
2900 container_of(w, struct msm_otg, suspend_work.work);
2901 atomic_set(&motg->suspend_work_pending, 0);
2902 msm_otg_sm_work(&motg->sm_work);
2903}
2904
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05302905static irqreturn_t msm_otg_irq(int irq, void *data)
2906{
2907 struct msm_otg *motg = data;
Steve Mucklef132c6c2012-06-06 18:30:57 -07002908 struct usb_otg *otg = motg->phy.otg;
Vijayavardhan Vennapusaa3152032012-03-05 16:29:30 +05302909 u32 otgsc = 0, usbsts, pc;
2910 bool work = 0;
2911 irqreturn_t ret = IRQ_HANDLED;
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05302912
Pavankumar Kondeti87c01042010-12-07 17:53:58 +05302913 if (atomic_read(&motg->in_lpm)) {
Manu Gautamf8c45642012-08-10 10:20:56 -07002914 pr_debug("OTG IRQ: %d in LPM\n", irq);
Pavankumar Kondeti87c01042010-12-07 17:53:58 +05302915 disable_irq_nosync(irq);
Manu Gautamf8c45642012-08-10 10:20:56 -07002916 motg->async_int = irq;
Jack Phamc7edb172012-08-13 15:32:39 -07002917 if (!atomic_read(&motg->pm_suspended))
Steve Mucklef132c6c2012-06-06 18:30:57 -07002918 pm_request_resume(otg->phy->dev);
Pavankumar Kondeti87c01042010-12-07 17:53:58 +05302919 return IRQ_HANDLED;
2920 }
2921
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002922 usbsts = readl(USB_USBSTS);
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05302923 otgsc = readl(USB_OTGSC);
Vijayavardhan Vennapusaa3152032012-03-05 16:29:30 +05302924
2925 if (!(otgsc & OTG_OTGSTS_MASK) && !(usbsts & OTG_USBSTS_MASK))
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05302926 return IRQ_NONE;
2927
2928 if ((otgsc & OTGSC_IDIS) && (otgsc & OTGSC_IDIE)) {
Pavankumar Kondetiaa449e12011-11-04 11:09:26 +05302929 if (otgsc & OTGSC_ID) {
Vijayavardhan Vennapusaa3152032012-03-05 16:29:30 +05302930 pr_debug("Id set\n");
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05302931 set_bit(ID, &motg->inputs);
Pavankumar Kondetiaa449e12011-11-04 11:09:26 +05302932 } else {
Vijayavardhan Vennapusaa3152032012-03-05 16:29:30 +05302933 pr_debug("Id clear\n");
2934 /*
2935 * Assert a_bus_req to supply power on
2936 * VBUS when Micro/Mini-A cable is connected
2937 * with out user intervention.
2938 */
2939 set_bit(A_BUS_REQ, &motg->inputs);
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05302940 clear_bit(ID, &motg->inputs);
Pavankumar Kondetiaa449e12011-11-04 11:09:26 +05302941 msm_chg_enable_aca_det(motg);
2942 }
Vijayavardhan Vennapusaa3152032012-03-05 16:29:30 +05302943 writel_relaxed(otgsc, USB_OTGSC);
2944 work = 1;
2945 } else if (otgsc & OTGSC_DPIS) {
2946 pr_debug("DPIS detected\n");
2947 writel_relaxed(otgsc, USB_OTGSC);
2948 set_bit(A_SRP_DET, &motg->inputs);
2949 set_bit(A_BUS_REQ, &motg->inputs);
2950 work = 1;
2951 } else if (otgsc & OTGSC_BSVIS) {
2952 writel_relaxed(otgsc, USB_OTGSC);
2953 /*
2954 * BSV interrupt comes when operating as an A-device
2955 * (VBUS on/off).
2956 * But, handle BSV when charger is removed from ACA in ID_A
2957 */
Steve Mucklef132c6c2012-06-06 18:30:57 -07002958 if ((otg->phy->state >= OTG_STATE_A_IDLE) &&
Vijayavardhan Vennapusaa3152032012-03-05 16:29:30 +05302959 !test_bit(ID_A, &motg->inputs))
2960 return IRQ_HANDLED;
Pavankumar Kondetiaa449e12011-11-04 11:09:26 +05302961 if (otgsc & OTGSC_BSV) {
Vijayavardhan Vennapusaa3152032012-03-05 16:29:30 +05302962 pr_debug("BSV set\n");
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05302963 set_bit(B_SESS_VLD, &motg->inputs);
Pavankumar Kondetiaa449e12011-11-04 11:09:26 +05302964 } else {
Vijayavardhan Vennapusaa3152032012-03-05 16:29:30 +05302965 pr_debug("BSV clear\n");
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05302966 clear_bit(B_SESS_VLD, &motg->inputs);
Amit Blay6fa647a2012-05-24 14:12:08 +03002967 clear_bit(A_BUS_SUSPEND, &motg->inputs);
2968
Pavankumar Kondetiaa449e12011-11-04 11:09:26 +05302969 msm_chg_check_aca_intr(motg);
2970 }
Vijayavardhan Vennapusaa3152032012-03-05 16:29:30 +05302971 work = 1;
2972 } else if (usbsts & STS_PCI) {
2973 pc = readl_relaxed(USB_PORTSC);
2974 pr_debug("portsc = %x\n", pc);
2975 ret = IRQ_NONE;
2976 /*
2977 * HCD Acks PCI interrupt. We use this to switch
2978 * between different OTG states.
2979 */
2980 work = 1;
Steve Mucklef132c6c2012-06-06 18:30:57 -07002981 switch (otg->phy->state) {
Vijayavardhan Vennapusaa3152032012-03-05 16:29:30 +05302982 case OTG_STATE_A_SUSPEND:
2983 if (otg->host->b_hnp_enable && (pc & PORTSC_CSC) &&
2984 !(pc & PORTSC_CCS)) {
2985 pr_debug("B_CONN clear\n");
2986 clear_bit(B_CONN, &motg->inputs);
2987 msm_otg_del_timer(motg);
2988 }
2989 break;
2990 case OTG_STATE_A_PERIPHERAL:
2991 /*
2992 * A-peripheral observed activity on bus.
2993 * clear A_BIDL_ADIS timer.
2994 */
2995 msm_otg_del_timer(motg);
2996 work = 0;
2997 break;
2998 case OTG_STATE_B_WAIT_ACON:
2999 if ((pc & PORTSC_CSC) && (pc & PORTSC_CCS)) {
3000 pr_debug("A_CONN set\n");
3001 set_bit(A_CONN, &motg->inputs);
3002 /* Clear ASE0_BRST timer */
3003 msm_otg_del_timer(motg);
3004 }
3005 break;
3006 case OTG_STATE_B_HOST:
3007 if ((pc & PORTSC_CSC) && !(pc & PORTSC_CCS)) {
3008 pr_debug("A_CONN clear\n");
3009 clear_bit(A_CONN, &motg->inputs);
3010 msm_otg_del_timer(motg);
3011 }
3012 break;
3013 case OTG_STATE_A_WAIT_BCON:
3014 if (TA_WAIT_BCON < 0)
3015 set_bit(A_BUS_REQ, &motg->inputs);
3016 default:
3017 work = 0;
3018 break;
3019 }
3020 } else if (usbsts & STS_URI) {
3021 ret = IRQ_NONE;
Steve Mucklef132c6c2012-06-06 18:30:57 -07003022 switch (otg->phy->state) {
Vijayavardhan Vennapusaa3152032012-03-05 16:29:30 +05303023 case OTG_STATE_A_PERIPHERAL:
3024 /*
3025 * A-peripheral observed activity on bus.
3026 * clear A_BIDL_ADIS timer.
3027 */
3028 msm_otg_del_timer(motg);
3029 work = 0;
3030 break;
3031 default:
3032 work = 0;
3033 break;
3034 }
3035 } else if (usbsts & STS_SLI) {
3036 ret = IRQ_NONE;
3037 work = 0;
Steve Mucklef132c6c2012-06-06 18:30:57 -07003038 switch (otg->phy->state) {
Vijayavardhan Vennapusaa3152032012-03-05 16:29:30 +05303039 case OTG_STATE_B_PERIPHERAL:
3040 if (otg->gadget->b_hnp_enable) {
3041 set_bit(A_BUS_SUSPEND, &motg->inputs);
3042 set_bit(B_BUS_REQ, &motg->inputs);
3043 work = 1;
3044 }
3045 break;
3046 case OTG_STATE_A_PERIPHERAL:
3047 msm_otg_start_timer(motg, TA_BIDL_ADIS,
3048 A_BIDL_ADIS);
3049 break;
3050 default:
3051 break;
3052 }
3053 } else if ((usbsts & PHY_ALT_INT)) {
3054 writel_relaxed(PHY_ALT_INT, USB_USBSTS);
3055 if (msm_chg_check_aca_intr(motg))
3056 work = 1;
3057 ret = IRQ_HANDLED;
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05303058 }
Vijayavardhan Vennapusaa3152032012-03-05 16:29:30 +05303059 if (work)
3060 queue_work(system_nrt_wq, &motg->sm_work);
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05303061
Vijayavardhan Vennapusaa3152032012-03-05 16:29:30 +05303062 return ret;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003063}
3064
3065static void msm_otg_set_vbus_state(int online)
3066{
Pavankumar Kondeti4960f312011-12-06 15:46:14 +05303067 static bool init;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003068 struct msm_otg *motg = the_msm_otg;
Mayank Ranabaf31f42012-07-05 09:43:54 +05303069 struct usb_otg *otg = motg->phy.otg;
3070
3071 /* In A Host Mode, ignore received BSV interrupts */
3072 if (otg->phy->state >= OTG_STATE_A_IDLE)
3073 return;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003074
Pavankumar Kondeti4960f312011-12-06 15:46:14 +05303075 if (online) {
3076 pr_debug("PMIC: BSV set\n");
3077 set_bit(B_SESS_VLD, &motg->inputs);
3078 } else {
3079 pr_debug("PMIC: BSV clear\n");
3080 clear_bit(B_SESS_VLD, &motg->inputs);
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05303081 }
3082
Pavankumar Kondeti4960f312011-12-06 15:46:14 +05303083 if (!init) {
3084 init = true;
3085 complete(&pmic_vbus_init);
3086 pr_debug("PMIC: BSV init complete\n");
3087 return;
3088 }
3089
Pavankumar Kondeti2aec9f32012-06-13 09:06:03 +05303090 if (test_bit(MHL, &motg->inputs) ||
3091 mhl_det_in_progress) {
3092 pr_debug("PMIC: BSV interrupt ignored in MHL\n");
3093 return;
3094 }
3095
Jack Pham5ca279b2012-05-14 18:42:54 -07003096 if (atomic_read(&motg->pm_suspended))
3097 motg->sm_work_pending = true;
3098 else
3099 queue_work(system_nrt_wq, &motg->sm_work);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003100}
3101
Vijayavardhan Vennapusa68d55cf2012-06-27 20:06:12 +05303102static void msm_pmic_id_status_w(struct work_struct *w)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003103{
Vijayavardhan Vennapusa68d55cf2012-06-27 20:06:12 +05303104 struct msm_otg *motg = container_of(w, struct msm_otg,
3105 pmic_id_status_work.work);
3106 int work = 0;
3107 unsigned long flags;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003108
Vijayavardhan Vennapusa68d55cf2012-06-27 20:06:12 +05303109 local_irq_save(flags);
Pavankumar Kondeti4960f312011-12-06 15:46:14 +05303110 if (irq_read_line(motg->pdata->pmic_id_irq)) {
Vijayavardhan Vennapusa68d55cf2012-06-27 20:06:12 +05303111 if (!test_and_set_bit(ID, &motg->inputs)) {
3112 pr_debug("PMIC: ID set\n");
3113 work = 1;
3114 }
Pavankumar Kondeti4960f312011-12-06 15:46:14 +05303115 } else {
Vijayavardhan Vennapusa68d55cf2012-06-27 20:06:12 +05303116 if (test_and_clear_bit(ID, &motg->inputs)) {
3117 pr_debug("PMIC: ID clear\n");
3118 set_bit(A_BUS_REQ, &motg->inputs);
3119 work = 1;
3120 }
Pavankumar Kondeti4960f312011-12-06 15:46:14 +05303121 }
3122
Vijayavardhan Vennapusa68d55cf2012-06-27 20:06:12 +05303123 if (work && (motg->phy.state != OTG_STATE_UNDEFINED)) {
Jack Pham5ca279b2012-05-14 18:42:54 -07003124 if (atomic_read(&motg->pm_suspended))
3125 motg->sm_work_pending = true;
3126 else
3127 queue_work(system_nrt_wq, &motg->sm_work);
3128 }
Vijayavardhan Vennapusa68d55cf2012-06-27 20:06:12 +05303129 local_irq_restore(flags);
3130
3131}
3132
3133#define MSM_PMIC_ID_STATUS_DELAY 5 /* 5msec */
3134static irqreturn_t msm_pmic_id_irq(int irq, void *data)
3135{
3136 struct msm_otg *motg = data;
3137
Pavankumar Kondeti2aec9f32012-06-13 09:06:03 +05303138 if (test_bit(MHL, &motg->inputs) ||
3139 mhl_det_in_progress) {
3140 pr_debug("PMIC: Id interrupt ignored in MHL\n");
3141 return IRQ_HANDLED;
3142 }
3143
Vijayavardhan Vennapusa68d55cf2012-06-27 20:06:12 +05303144 if (!aca_id_turned_on)
3145 /*schedule delayed work for 5msec for ID line state to settle*/
3146 queue_delayed_work(system_nrt_wq, &motg->pmic_id_status_work,
3147 msecs_to_jiffies(MSM_PMIC_ID_STATUS_DELAY));
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003148
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05303149 return IRQ_HANDLED;
3150}
3151
3152static int msm_otg_mode_show(struct seq_file *s, void *unused)
3153{
3154 struct msm_otg *motg = s->private;
Steve Mucklef132c6c2012-06-06 18:30:57 -07003155 struct usb_phy *phy = &motg->phy;
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05303156
Steve Mucklef132c6c2012-06-06 18:30:57 -07003157 switch (phy->state) {
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05303158 case OTG_STATE_A_HOST:
3159 seq_printf(s, "host\n");
3160 break;
3161 case OTG_STATE_B_PERIPHERAL:
3162 seq_printf(s, "peripheral\n");
3163 break;
3164 default:
3165 seq_printf(s, "none\n");
3166 break;
3167 }
3168
3169 return 0;
3170}
3171
3172static int msm_otg_mode_open(struct inode *inode, struct file *file)
3173{
3174 return single_open(file, msm_otg_mode_show, inode->i_private);
3175}
3176
3177static ssize_t msm_otg_mode_write(struct file *file, const char __user *ubuf,
3178 size_t count, loff_t *ppos)
3179{
Pavankumar Kondetie2904ee2011-02-15 09:42:35 +05303180 struct seq_file *s = file->private_data;
3181 struct msm_otg *motg = s->private;
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05303182 char buf[16];
Steve Mucklef132c6c2012-06-06 18:30:57 -07003183 struct usb_phy *phy = &motg->phy;
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05303184 int status = count;
3185 enum usb_mode_type req_mode;
3186
3187 memset(buf, 0x00, sizeof(buf));
3188
3189 if (copy_from_user(&buf, ubuf, min_t(size_t, sizeof(buf) - 1, count))) {
3190 status = -EFAULT;
3191 goto out;
3192 }
3193
3194 if (!strncmp(buf, "host", 4)) {
3195 req_mode = USB_HOST;
3196 } else if (!strncmp(buf, "peripheral", 10)) {
3197 req_mode = USB_PERIPHERAL;
3198 } else if (!strncmp(buf, "none", 4)) {
3199 req_mode = USB_NONE;
3200 } else {
3201 status = -EINVAL;
3202 goto out;
3203 }
3204
3205 switch (req_mode) {
3206 case USB_NONE:
Steve Mucklef132c6c2012-06-06 18:30:57 -07003207 switch (phy->state) {
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05303208 case OTG_STATE_A_HOST:
3209 case OTG_STATE_B_PERIPHERAL:
3210 set_bit(ID, &motg->inputs);
3211 clear_bit(B_SESS_VLD, &motg->inputs);
3212 break;
3213 default:
3214 goto out;
3215 }
3216 break;
3217 case USB_PERIPHERAL:
Steve Mucklef132c6c2012-06-06 18:30:57 -07003218 switch (phy->state) {
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05303219 case OTG_STATE_B_IDLE:
3220 case OTG_STATE_A_HOST:
3221 set_bit(ID, &motg->inputs);
3222 set_bit(B_SESS_VLD, &motg->inputs);
3223 break;
3224 default:
3225 goto out;
3226 }
3227 break;
3228 case USB_HOST:
Steve Mucklef132c6c2012-06-06 18:30:57 -07003229 switch (phy->state) {
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05303230 case OTG_STATE_B_IDLE:
3231 case OTG_STATE_B_PERIPHERAL:
3232 clear_bit(ID, &motg->inputs);
3233 break;
3234 default:
3235 goto out;
3236 }
3237 break;
3238 default:
3239 goto out;
3240 }
3241
Steve Mucklef132c6c2012-06-06 18:30:57 -07003242 pm_runtime_resume(phy->dev);
Vijayavardhan Vennapusaa3152032012-03-05 16:29:30 +05303243 queue_work(system_nrt_wq, &motg->sm_work);
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05303244out:
3245 return status;
3246}
3247
3248const struct file_operations msm_otg_mode_fops = {
3249 .open = msm_otg_mode_open,
3250 .read = seq_read,
3251 .write = msm_otg_mode_write,
3252 .llseek = seq_lseek,
3253 .release = single_release,
3254};
3255
Chiranjeevi Velempatif9a11542012-03-28 18:18:34 +05303256static int msm_otg_show_otg_state(struct seq_file *s, void *unused)
3257{
3258 struct msm_otg *motg = s->private;
Steve Mucklef132c6c2012-06-06 18:30:57 -07003259 struct usb_phy *phy = &motg->phy;
Chiranjeevi Velempatif9a11542012-03-28 18:18:34 +05303260
Steve Mucklef132c6c2012-06-06 18:30:57 -07003261 seq_printf(s, "%s\n", otg_state_string(phy->state));
Chiranjeevi Velempatif9a11542012-03-28 18:18:34 +05303262 return 0;
3263}
3264
3265static int msm_otg_otg_state_open(struct inode *inode, struct file *file)
3266{
3267 return single_open(file, msm_otg_show_otg_state, inode->i_private);
3268}
3269
3270const struct file_operations msm_otg_state_fops = {
3271 .open = msm_otg_otg_state_open,
3272 .read = seq_read,
3273 .llseek = seq_lseek,
3274 .release = single_release,
3275};
3276
Anji jonnalad270e2d2011-08-09 11:28:32 +05303277static int msm_otg_show_chg_type(struct seq_file *s, void *unused)
3278{
3279 struct msm_otg *motg = s->private;
3280
Pavankumar Kondeti9ef69cb2011-12-12 14:18:22 +05303281 seq_printf(s, "%s\n", chg_to_string(motg->chg_type));
Anji jonnalad270e2d2011-08-09 11:28:32 +05303282 return 0;
3283}
3284
3285static int msm_otg_chg_open(struct inode *inode, struct file *file)
3286{
3287 return single_open(file, msm_otg_show_chg_type, inode->i_private);
3288}
3289
3290const struct file_operations msm_otg_chg_fops = {
3291 .open = msm_otg_chg_open,
3292 .read = seq_read,
3293 .llseek = seq_lseek,
3294 .release = single_release,
3295};
3296
Pavankumar Kondetiaa449e12011-11-04 11:09:26 +05303297static int msm_otg_aca_show(struct seq_file *s, void *unused)
3298{
3299 if (debug_aca_enabled)
3300 seq_printf(s, "enabled\n");
3301 else
3302 seq_printf(s, "disabled\n");
3303
3304 return 0;
3305}
3306
3307static int msm_otg_aca_open(struct inode *inode, struct file *file)
3308{
3309 return single_open(file, msm_otg_aca_show, inode->i_private);
3310}
3311
3312static ssize_t msm_otg_aca_write(struct file *file, const char __user *ubuf,
3313 size_t count, loff_t *ppos)
3314{
3315 char buf[8];
3316
3317 memset(buf, 0x00, sizeof(buf));
3318
3319 if (copy_from_user(&buf, ubuf, min_t(size_t, sizeof(buf) - 1, count)))
3320 return -EFAULT;
3321
3322 if (!strncmp(buf, "enable", 6))
3323 debug_aca_enabled = true;
3324 else
3325 debug_aca_enabled = false;
3326
3327 return count;
3328}
3329
3330const struct file_operations msm_otg_aca_fops = {
3331 .open = msm_otg_aca_open,
3332 .read = seq_read,
3333 .write = msm_otg_aca_write,
3334 .llseek = seq_lseek,
3335 .release = single_release,
3336};
3337
Manu Gautam8bdcc592012-03-06 11:26:06 +05303338static int msm_otg_bus_show(struct seq_file *s, void *unused)
3339{
3340 if (debug_bus_voting_enabled)
3341 seq_printf(s, "enabled\n");
3342 else
3343 seq_printf(s, "disabled\n");
3344
3345 return 0;
3346}
3347
3348static int msm_otg_bus_open(struct inode *inode, struct file *file)
3349{
3350 return single_open(file, msm_otg_bus_show, inode->i_private);
3351}
3352
3353static ssize_t msm_otg_bus_write(struct file *file, const char __user *ubuf,
3354 size_t count, loff_t *ppos)
3355{
3356 char buf[8];
3357 int ret;
3358 struct seq_file *s = file->private_data;
3359 struct msm_otg *motg = s->private;
3360
3361 memset(buf, 0x00, sizeof(buf));
3362
3363 if (copy_from_user(&buf, ubuf, min_t(size_t, sizeof(buf) - 1, count)))
3364 return -EFAULT;
3365
3366 if (!strncmp(buf, "enable", 6)) {
3367 /* Do not vote here. Let OTG statemachine decide when to vote */
3368 debug_bus_voting_enabled = true;
3369 } else {
3370 debug_bus_voting_enabled = false;
3371 if (motg->bus_perf_client) {
3372 ret = msm_bus_scale_client_update_request(
3373 motg->bus_perf_client, 0);
3374 if (ret)
Steve Mucklef132c6c2012-06-06 18:30:57 -07003375 dev_err(motg->phy.dev, "%s: Failed to devote "
Manu Gautam8bdcc592012-03-06 11:26:06 +05303376 "for bus bw %d\n", __func__, ret);
3377 }
3378 }
3379
3380 return count;
3381}
3382
David Keitel272ce522012-08-17 16:25:24 -07003383static int otg_power_get_property_usb(struct power_supply *psy,
3384 enum power_supply_property psp,
3385 union power_supply_propval *val)
3386{
3387 struct msm_otg *motg = container_of(psy, struct msm_otg,
3388 usb_psy);
3389 switch (psp) {
3390 case POWER_SUPPLY_PROP_SCOPE:
3391 if (motg->host_mode)
3392 val->intval = POWER_SUPPLY_SCOPE_SYSTEM;
3393 else
3394 val->intval = POWER_SUPPLY_SCOPE_DEVICE;
3395 break;
3396 case POWER_SUPPLY_PROP_CURRENT_MAX:
3397 val->intval = motg->current_max;
3398 break;
3399 /* Reflect USB enumeration */
3400 case POWER_SUPPLY_PROP_PRESENT:
3401 case POWER_SUPPLY_PROP_ONLINE:
3402 val->intval = motg->online;
3403 break;
3404 default:
3405 return -EINVAL;
3406 }
3407 return 0;
3408}
3409
3410static int otg_power_set_property_usb(struct power_supply *psy,
3411 enum power_supply_property psp,
3412 const union power_supply_propval *val)
3413{
3414 struct msm_otg *motg = container_of(psy, struct msm_otg,
3415 usb_psy);
3416
3417 switch (psp) {
3418 /* Process PMIC notification in PRESENT prop */
3419 case POWER_SUPPLY_PROP_PRESENT:
3420 msm_otg_set_vbus_state(val->intval);
3421 break;
3422 /* The ONLINE property reflects if usb has enumerated */
3423 case POWER_SUPPLY_PROP_ONLINE:
3424 motg->online = val->intval;
3425 break;
3426 case POWER_SUPPLY_PROP_CURRENT_MAX:
3427 motg->current_max = val->intval;
3428 break;
3429 default:
3430 return -EINVAL;
3431 }
3432
3433 power_supply_changed(&motg->usb_psy);
3434 return 0;
3435}
3436
3437static char *otg_pm_power_supplied_to[] = {
3438 "battery",
3439};
3440
3441static enum power_supply_property otg_pm_power_props_usb[] = {
3442 POWER_SUPPLY_PROP_PRESENT,
3443 POWER_SUPPLY_PROP_ONLINE,
3444 POWER_SUPPLY_PROP_CURRENT_MAX,
3445 POWER_SUPPLY_PROP_SCOPE,
3446};
3447
Manu Gautam8bdcc592012-03-06 11:26:06 +05303448const struct file_operations msm_otg_bus_fops = {
3449 .open = msm_otg_bus_open,
3450 .read = seq_read,
3451 .write = msm_otg_bus_write,
3452 .llseek = seq_lseek,
3453 .release = single_release,
3454};
3455
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05303456static struct dentry *msm_otg_dbg_root;
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05303457
3458static int msm_otg_debugfs_init(struct msm_otg *motg)
3459{
Manu Gautam8bdcc592012-03-06 11:26:06 +05303460 struct dentry *msm_otg_dentry;
Anji jonnalad270e2d2011-08-09 11:28:32 +05303461
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05303462 msm_otg_dbg_root = debugfs_create_dir("msm_otg", NULL);
3463
3464 if (!msm_otg_dbg_root || IS_ERR(msm_otg_dbg_root))
3465 return -ENODEV;
3466
Anji jonnalad270e2d2011-08-09 11:28:32 +05303467 if (motg->pdata->mode == USB_OTG &&
3468 motg->pdata->otg_control == OTG_USER_CONTROL) {
3469
Manu Gautam8bdcc592012-03-06 11:26:06 +05303470 msm_otg_dentry = debugfs_create_file("mode", S_IRUGO |
Anji jonnalad270e2d2011-08-09 11:28:32 +05303471 S_IWUSR, msm_otg_dbg_root, motg,
3472 &msm_otg_mode_fops);
3473
Manu Gautam8bdcc592012-03-06 11:26:06 +05303474 if (!msm_otg_dentry) {
Anji jonnalad270e2d2011-08-09 11:28:32 +05303475 debugfs_remove(msm_otg_dbg_root);
3476 msm_otg_dbg_root = NULL;
3477 return -ENODEV;
3478 }
3479 }
3480
Manu Gautam8bdcc592012-03-06 11:26:06 +05303481 msm_otg_dentry = debugfs_create_file("chg_type", S_IRUGO,
Anji jonnalad270e2d2011-08-09 11:28:32 +05303482 msm_otg_dbg_root, motg,
3483 &msm_otg_chg_fops);
3484
Manu Gautam8bdcc592012-03-06 11:26:06 +05303485 if (!msm_otg_dentry) {
Pavankumar Kondetiaa449e12011-11-04 11:09:26 +05303486 debugfs_remove_recursive(msm_otg_dbg_root);
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05303487 return -ENODEV;
3488 }
3489
Manu Gautam8bdcc592012-03-06 11:26:06 +05303490 msm_otg_dentry = debugfs_create_file("aca", S_IRUGO | S_IWUSR,
Pavankumar Kondetiaa449e12011-11-04 11:09:26 +05303491 msm_otg_dbg_root, motg,
3492 &msm_otg_aca_fops);
3493
Manu Gautam8bdcc592012-03-06 11:26:06 +05303494 if (!msm_otg_dentry) {
Pavankumar Kondetiaa449e12011-11-04 11:09:26 +05303495 debugfs_remove_recursive(msm_otg_dbg_root);
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05303496 return -ENODEV;
3497 }
3498
Manu Gautam8bdcc592012-03-06 11:26:06 +05303499 msm_otg_dentry = debugfs_create_file("bus_voting", S_IRUGO | S_IWUSR,
3500 msm_otg_dbg_root, motg,
3501 &msm_otg_bus_fops);
3502
3503 if (!msm_otg_dentry) {
3504 debugfs_remove_recursive(msm_otg_dbg_root);
3505 return -ENODEV;
3506 }
Chiranjeevi Velempatif9a11542012-03-28 18:18:34 +05303507
3508 msm_otg_dentry = debugfs_create_file("otg_state", S_IRUGO,
3509 msm_otg_dbg_root, motg, &msm_otg_state_fops);
3510
3511 if (!msm_otg_dentry) {
3512 debugfs_remove_recursive(msm_otg_dbg_root);
3513 return -ENODEV;
3514 }
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05303515 return 0;
3516}
3517
3518static void msm_otg_debugfs_cleanup(void)
3519{
Anji jonnalad270e2d2011-08-09 11:28:32 +05303520 debugfs_remove_recursive(msm_otg_dbg_root);
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05303521}
3522
Manu Gautam0ddbd922012-09-21 17:17:38 +05303523#define MSM_OTG_CMD_ID 0x09
3524#define MSM_OTG_DEVICE_ID 0x04
3525#define MSM_OTG_VMID_IDX 0xFF
3526#define MSM_OTG_MEM_TYPE 0x02
3527struct msm_otg_scm_cmd_buf {
3528 unsigned int device_id;
3529 unsigned int vmid_idx;
3530 unsigned int mem_type;
3531} __attribute__ ((__packed__));
3532
3533static void msm_otg_pnoc_errata_fix(struct msm_otg *motg)
3534{
3535 int ret;
3536 struct msm_otg_platform_data *pdata = motg->pdata;
3537 struct msm_otg_scm_cmd_buf cmd_buf;
3538
3539 if (!pdata->pnoc_errata_fix)
3540 return;
3541
3542 dev_dbg(motg->phy.dev, "applying fix for pnoc h/w issue\n");
3543
3544 cmd_buf.device_id = MSM_OTG_DEVICE_ID;
3545 cmd_buf.vmid_idx = MSM_OTG_VMID_IDX;
3546 cmd_buf.mem_type = MSM_OTG_MEM_TYPE;
3547
3548 ret = scm_call(SCM_SVC_CP, MSM_OTG_CMD_ID, &cmd_buf,
3549 sizeof(cmd_buf), NULL, 0);
3550
3551 if (ret)
3552 dev_err(motg->phy.dev, "scm command failed to update VMIDMT\n");
3553}
3554
Pavankumar Kondetieaea7fe2011-10-27 14:46:45 +05303555static u64 msm_otg_dma_mask = DMA_BIT_MASK(64);
3556static struct platform_device *msm_otg_add_pdev(
3557 struct platform_device *ofdev, const char *name)
3558{
3559 struct platform_device *pdev;
3560 const struct resource *res = ofdev->resource;
3561 unsigned int num = ofdev->num_resources;
3562 int retval;
3563
3564 pdev = platform_device_alloc(name, -1);
3565 if (!pdev) {
3566 retval = -ENOMEM;
3567 goto error;
3568 }
3569
3570 pdev->dev.coherent_dma_mask = DMA_BIT_MASK(32);
3571 pdev->dev.dma_mask = &msm_otg_dma_mask;
3572
3573 if (num) {
3574 retval = platform_device_add_resources(pdev, res, num);
3575 if (retval)
3576 goto error;
3577 }
3578
3579 retval = platform_device_add(pdev);
3580 if (retval)
3581 goto error;
3582
3583 return pdev;
3584
3585error:
3586 platform_device_put(pdev);
3587 return ERR_PTR(retval);
3588}
3589
3590static int msm_otg_setup_devices(struct platform_device *ofdev,
3591 enum usb_mode_type mode, bool init)
3592{
3593 const char *gadget_name = "msm_hsusb";
3594 const char *host_name = "msm_hsusb_host";
3595 static struct platform_device *gadget_pdev;
3596 static struct platform_device *host_pdev;
3597 int retval = 0;
3598
3599 if (!init) {
3600 if (gadget_pdev)
3601 platform_device_unregister(gadget_pdev);
3602 if (host_pdev)
3603 platform_device_unregister(host_pdev);
3604 return 0;
3605 }
3606
3607 switch (mode) {
3608 case USB_OTG:
3609 /* fall through */
3610 case USB_PERIPHERAL:
3611 gadget_pdev = msm_otg_add_pdev(ofdev, gadget_name);
3612 if (IS_ERR(gadget_pdev)) {
3613 retval = PTR_ERR(gadget_pdev);
3614 break;
3615 }
3616 if (mode == USB_PERIPHERAL)
3617 break;
3618 /* fall through */
3619 case USB_HOST:
3620 host_pdev = msm_otg_add_pdev(ofdev, host_name);
3621 if (IS_ERR(host_pdev)) {
3622 retval = PTR_ERR(host_pdev);
3623 if (mode == USB_OTG)
3624 platform_device_unregister(gadget_pdev);
3625 }
3626 break;
3627 default:
3628 break;
3629 }
3630
3631 return retval;
3632}
3633
David Keitel272ce522012-08-17 16:25:24 -07003634static int msm_otg_register_power_supply(struct platform_device *pdev,
3635 struct msm_otg *motg)
3636{
3637 int ret;
3638
3639 ret = power_supply_register(&pdev->dev, &motg->usb_psy);
3640 if (ret < 0) {
3641 dev_err(motg->phy.dev,
3642 "%s:power_supply_register usb failed\n",
3643 __func__);
3644 return ret;
3645 }
3646
3647 legacy_power_supply = false;
3648 return 0;
3649}
3650
Pavankumar Kondetieaea7fe2011-10-27 14:46:45 +05303651struct msm_otg_platform_data *msm_otg_dt_to_pdata(struct platform_device *pdev)
3652{
3653 struct device_node *node = pdev->dev.of_node;
3654 struct msm_otg_platform_data *pdata;
3655 int len = 0;
3656
3657 pdata = devm_kzalloc(&pdev->dev, sizeof(*pdata), GFP_KERNEL);
3658 if (!pdata) {
3659 pr_err("unable to allocate platform data\n");
3660 return NULL;
3661 }
3662 of_get_property(node, "qcom,hsusb-otg-phy-init-seq", &len);
3663 if (len) {
3664 pdata->phy_init_seq = devm_kzalloc(&pdev->dev, len, GFP_KERNEL);
3665 if (!pdata->phy_init_seq)
3666 return NULL;
3667 of_property_read_u32_array(node, "qcom,hsusb-otg-phy-init-seq",
3668 pdata->phy_init_seq,
3669 len/sizeof(*pdata->phy_init_seq));
3670 }
3671 of_property_read_u32(node, "qcom,hsusb-otg-power-budget",
3672 &pdata->power_budget);
3673 of_property_read_u32(node, "qcom,hsusb-otg-mode",
3674 &pdata->mode);
3675 of_property_read_u32(node, "qcom,hsusb-otg-otg-control",
3676 &pdata->otg_control);
3677 of_property_read_u32(node, "qcom,hsusb-otg-default-mode",
3678 &pdata->default_mode);
3679 of_property_read_u32(node, "qcom,hsusb-otg-phy-type",
3680 &pdata->phy_type);
3681 of_property_read_u32(node, "qcom,hsusb-otg-pmic-id-irq",
3682 &pdata->pmic_id_irq);
Manu Gautambd53fba2012-07-31 16:13:06 +05303683 pdata->disable_reset_on_disconnect = of_property_read_bool(node,
3684 "qcom,hsusb-otg-disable-reset");
Manu Gautam0ddbd922012-09-21 17:17:38 +05303685 pdata->pnoc_errata_fix = of_property_read_bool(node,
3686 "qcom,hsusb-otg-pnoc-errata-fix");
Manu Gautambd53fba2012-07-31 16:13:06 +05303687
Pavankumar Kondetieaea7fe2011-10-27 14:46:45 +05303688 return pdata;
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05303689}
3690
3691static int __init msm_otg_probe(struct platform_device *pdev)
3692{
Manu Gautamf8c45642012-08-10 10:20:56 -07003693 int ret = 0;
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05303694 struct resource *res;
3695 struct msm_otg *motg;
Heikki Krogerus1d4c9292012-02-13 13:24:09 +02003696 struct usb_phy *phy;
Pavankumar Kondetieaea7fe2011-10-27 14:46:45 +05303697 struct msm_otg_platform_data *pdata;
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05303698
3699 dev_info(&pdev->dev, "msm_otg probe\n");
Pavankumar Kondetieaea7fe2011-10-27 14:46:45 +05303700
3701 if (pdev->dev.of_node) {
3702 dev_dbg(&pdev->dev, "device tree enabled\n");
3703 pdata = msm_otg_dt_to_pdata(pdev);
3704 if (!pdata)
3705 return -ENOMEM;
Manu Gautam2e8ac102012-08-31 11:41:16 -07003706
3707 pdata->bus_scale_table = msm_bus_cl_get_pdata(pdev);
3708 if (!pdata->bus_scale_table)
3709 dev_dbg(&pdev->dev, "bus scaling is disabled\n");
3710
Pavankumar Kondetieaea7fe2011-10-27 14:46:45 +05303711 ret = msm_otg_setup_devices(pdev, pdata->mode, true);
3712 if (ret) {
3713 dev_err(&pdev->dev, "devices setup failed\n");
3714 return ret;
3715 }
3716 } else if (!pdev->dev.platform_data) {
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05303717 dev_err(&pdev->dev, "No platform data given. Bailing out\n");
3718 return -ENODEV;
Pavankumar Kondetieaea7fe2011-10-27 14:46:45 +05303719 } else {
3720 pdata = pdev->dev.platform_data;
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05303721 }
3722
3723 motg = kzalloc(sizeof(struct msm_otg), GFP_KERNEL);
3724 if (!motg) {
3725 dev_err(&pdev->dev, "unable to allocate msm_otg\n");
3726 return -ENOMEM;
3727 }
3728
Heikki Krogerus1d4c9292012-02-13 13:24:09 +02003729 motg->phy.otg = kzalloc(sizeof(struct usb_otg), GFP_KERNEL);
3730 if (!motg->phy.otg) {
Steve Mucklef132c6c2012-06-06 18:30:57 -07003731 dev_err(&pdev->dev, "unable to allocate usb_otg\n");
3732 ret = -ENOMEM;
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05303733 goto free_motg;
3734 }
3735
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003736 the_msm_otg = motg;
Pavankumar Kondetieaea7fe2011-10-27 14:46:45 +05303737 motg->pdata = pdata;
Steve Mucklef132c6c2012-06-06 18:30:57 -07003738 phy = &motg->phy;
3739 phy->dev = &pdev->dev;
Anji jonnala0f73cac2011-05-04 10:19:46 +05303740
3741 /*
Pavankumar Kondetiaa449e12011-11-04 11:09:26 +05303742 * ACA ID_GND threshold range is overlapped with OTG ID_FLOAT. Hence
3743 * PHY treat ACA ID_GND as float and no interrupt is generated. But
3744 * PMIC can detect ACA ID_GND and generate an interrupt.
3745 */
3746 if (aca_enabled() && motg->pdata->otg_control != OTG_PMIC_CONTROL) {
3747 dev_err(&pdev->dev, "ACA can not be enabled without PMIC\n");
3748 ret = -EINVAL;
Steve Mucklef132c6c2012-06-06 18:30:57 -07003749 goto free_otg;
Pavankumar Kondetiaa449e12011-11-04 11:09:26 +05303750 }
3751
Ofir Cohen4da266f2012-01-03 10:19:29 +02003752 /* initialize reset counter */
3753 motg->reset_counter = 0;
3754
Amit Blay02eff132011-09-21 16:46:24 +03003755 /* Some targets don't support PHY clock. */
Manu Gautam5143b252012-01-05 19:25:23 -08003756 motg->phy_reset_clk = clk_get(&pdev->dev, "phy_clk");
Amit Blay02eff132011-09-21 16:46:24 +03003757 if (IS_ERR(motg->phy_reset_clk))
Manu Gautam5143b252012-01-05 19:25:23 -08003758 dev_err(&pdev->dev, "failed to get phy_clk\n");
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05303759
Pavankumar Kondeti923262e2012-04-20 15:34:24 +05303760 /*
3761 * Targets on which link uses asynchronous reset methodology,
3762 * free running clock is not required during the reset.
3763 */
Manu Gautam5143b252012-01-05 19:25:23 -08003764 motg->clk = clk_get(&pdev->dev, "alt_core_clk");
Pavankumar Kondeti923262e2012-04-20 15:34:24 +05303765 if (IS_ERR(motg->clk))
3766 dev_dbg(&pdev->dev, "alt_core_clk is not present\n");
3767 else
3768 clk_set_rate(motg->clk, 60000000);
Anji jonnala0f73cac2011-05-04 10:19:46 +05303769
3770 /*
Manu Gautam5143b252012-01-05 19:25:23 -08003771 * USB Core is running its protocol engine based on CORE CLK,
Anji jonnala0f73cac2011-05-04 10:19:46 +05303772 * CORE CLK must be running at >55Mhz for correct HSUSB
3773 * operation and USB core cannot tolerate frequency changes on
3774 * CORE CLK. For such USB cores, vote for maximum clk frequency
3775 * on pclk source
3776 */
Manu Gautam5143b252012-01-05 19:25:23 -08003777 motg->core_clk = clk_get(&pdev->dev, "core_clk");
3778 if (IS_ERR(motg->core_clk)) {
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05303779 motg->core_clk = NULL;
Manu Gautam5143b252012-01-05 19:25:23 -08003780 dev_err(&pdev->dev, "failed to get core_clk\n");
Pavankumar Kondetibc541332012-04-20 15:32:04 +05303781 ret = PTR_ERR(motg->core_clk);
Manu Gautam5143b252012-01-05 19:25:23 -08003782 goto put_clk;
3783 }
3784 clk_set_rate(motg->core_clk, INT_MAX);
3785
3786 motg->pclk = clk_get(&pdev->dev, "iface_clk");
3787 if (IS_ERR(motg->pclk)) {
3788 dev_err(&pdev->dev, "failed to get iface_clk\n");
3789 ret = PTR_ERR(motg->pclk);
3790 goto put_core_clk;
3791 }
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05303792
3793 res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
3794 if (!res) {
3795 dev_err(&pdev->dev, "failed to get platform resource mem\n");
3796 ret = -ENODEV;
Manu Gautam5143b252012-01-05 19:25:23 -08003797 goto put_pclk;
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05303798 }
3799
3800 motg->regs = ioremap(res->start, resource_size(res));
3801 if (!motg->regs) {
3802 dev_err(&pdev->dev, "ioremap failed\n");
3803 ret = -ENOMEM;
Manu Gautam5143b252012-01-05 19:25:23 -08003804 goto put_pclk;
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05303805 }
3806 dev_info(&pdev->dev, "OTG regs = %p\n", motg->regs);
3807
3808 motg->irq = platform_get_irq(pdev, 0);
3809 if (!motg->irq) {
3810 dev_err(&pdev->dev, "platform_get_irq failed\n");
3811 ret = -ENODEV;
3812 goto free_regs;
3813 }
3814
Manu Gautamf8c45642012-08-10 10:20:56 -07003815 motg->async_irq = platform_get_irq_byname(pdev, "async_irq");
3816 if (motg->async_irq < 0) {
3817 dev_dbg(&pdev->dev, "platform_get_irq for async_int failed\n");
3818 motg->async_irq = 0;
3819 }
3820
Stephen Boyd30ad10b2012-03-01 14:51:04 -08003821 motg->xo_handle = msm_xo_get(MSM_XO_TCXO_D0, "usb");
Anji jonnala7da3f262011-12-02 17:22:14 -08003822 if (IS_ERR(motg->xo_handle)) {
3823 dev_err(&pdev->dev, "%s not able to get the handle "
3824 "to vote for TCXO D0 buffer\n", __func__);
3825 ret = PTR_ERR(motg->xo_handle);
3826 goto free_regs;
3827 }
Anji jonnala11aa5c42011-05-04 10:19:48 +05303828
Stephen Boyd30ad10b2012-03-01 14:51:04 -08003829 ret = msm_xo_mode_vote(motg->xo_handle, MSM_XO_MODE_ON);
Anji jonnala7da3f262011-12-02 17:22:14 -08003830 if (ret) {
3831 dev_err(&pdev->dev, "%s failed to vote for TCXO "
3832 "D0 buffer%d\n", __func__, ret);
3833 goto free_xo_handle;
3834 }
3835
Manu Gautam28b1bac2012-01-30 16:43:06 +05303836 clk_prepare_enable(motg->pclk);
Anji jonnala11aa5c42011-05-04 10:19:48 +05303837
Mayank Rana248698c2012-04-19 00:03:16 +05303838 motg->vdd_type = VDDCX_CORNER;
Steve Mucklef132c6c2012-06-06 18:30:57 -07003839 hsusb_vddcx = devm_regulator_get(motg->phy.dev, "hsusb_vdd_dig");
Mayank Rana248698c2012-04-19 00:03:16 +05303840 if (IS_ERR(hsusb_vddcx)) {
Steve Mucklef132c6c2012-06-06 18:30:57 -07003841 hsusb_vddcx = devm_regulator_get(motg->phy.dev, "HSUSB_VDDCX");
Mayank Rana248698c2012-04-19 00:03:16 +05303842 if (IS_ERR(hsusb_vddcx)) {
Steve Mucklef132c6c2012-06-06 18:30:57 -07003843 dev_err(motg->phy.dev, "unable to get hsusb vddcx\n");
Hemant Kumar41812392012-07-13 15:26:20 -07003844 ret = PTR_ERR(hsusb_vddcx);
Mayank Rana248698c2012-04-19 00:03:16 +05303845 goto devote_xo_handle;
3846 }
3847 motg->vdd_type = VDDCX;
Anji jonnala11aa5c42011-05-04 10:19:48 +05303848 }
3849
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003850 ret = msm_hsusb_config_vddcx(1);
Anji jonnala11aa5c42011-05-04 10:19:48 +05303851 if (ret) {
3852 dev_err(&pdev->dev, "hsusb vddcx configuration failed\n");
Mayank Rana248698c2012-04-19 00:03:16 +05303853 goto devote_xo_handle;
3854 }
3855
3856 ret = regulator_enable(hsusb_vddcx);
3857 if (ret) {
3858 dev_err(&pdev->dev, "unable to enable the hsusb vddcx\n");
3859 goto free_config_vddcx;
Anji jonnala11aa5c42011-05-04 10:19:48 +05303860 }
3861
3862 ret = msm_hsusb_ldo_init(motg, 1);
3863 if (ret) {
3864 dev_err(&pdev->dev, "hsusb vreg configuration failed\n");
Mayank Rana248698c2012-04-19 00:03:16 +05303865 goto free_hsusb_vddcx;
Anji jonnala11aa5c42011-05-04 10:19:48 +05303866 }
3867
Mayank Rana9e9a2ac2012-03-24 04:05:28 +05303868 if (pdata->mhl_enable) {
Pavankumar Kondeti56dc7422012-07-02 12:45:19 +05303869 mhl_usb_hs_switch = devm_regulator_get(motg->phy.dev,
3870 "mhl_usb_hs_switch");
3871 if (IS_ERR(mhl_usb_hs_switch)) {
3872 dev_err(&pdev->dev, "Unable to get mhl_usb_hs_switch\n");
Hemant Kumar41812392012-07-13 15:26:20 -07003873 ret = PTR_ERR(mhl_usb_hs_switch);
Mayank Rana9e9a2ac2012-03-24 04:05:28 +05303874 goto free_ldo_init;
3875 }
3876 }
3877
Amit Blay81801aa2012-09-19 12:08:12 +02003878 ret = msm_hsusb_ldo_enable(motg, USB_PHY_REG_ON);
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05303879 if (ret) {
3880 dev_err(&pdev->dev, "hsusb vreg enable failed\n");
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003881 goto free_ldo_init;
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05303882 }
Manu Gautam28b1bac2012-01-30 16:43:06 +05303883 clk_prepare_enable(motg->core_clk);
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05303884
Manu Gautam0ddbd922012-09-21 17:17:38 +05303885 /* Check if USB mem_type change is needed to workaround PNOC hw issue */
3886 msm_otg_pnoc_errata_fix(motg);
3887
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05303888 writel(0, USB_USBINTR);
3889 writel(0, USB_OTGSC);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003890 /* Ensure that above STOREs are completed before enabling interrupts */
3891 mb();
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05303892
Pavankumar Kondeti2aec9f32012-06-13 09:06:03 +05303893 ret = msm_otg_mhl_register_callback(motg, msm_otg_mhl_notify_online);
3894 if (ret)
3895 dev_dbg(&pdev->dev, "MHL can not be supported\n");
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003896 wake_lock_init(&motg->wlock, WAKE_LOCK_SUSPEND, "msm_otg");
Vijayavardhan Vennapusaa3152032012-03-05 16:29:30 +05303897 msm_otg_init_timer(motg);
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05303898 INIT_WORK(&motg->sm_work, msm_otg_sm_work);
Pavankumar Kondetid8608522011-05-04 10:19:47 +05303899 INIT_DELAYED_WORK(&motg->chg_work, msm_chg_detect_work);
Vijayavardhan Vennapusa68d55cf2012-06-27 20:06:12 +05303900 INIT_DELAYED_WORK(&motg->pmic_id_status_work, msm_pmic_id_status_w);
Amit Blayd0fe07b2012-09-05 16:42:09 +03003901 INIT_DELAYED_WORK(&motg->suspend_work, msm_otg_suspend_work);
Pavankumar Kondetiaa449e12011-11-04 11:09:26 +05303902 setup_timer(&motg->id_timer, msm_otg_id_timer_func,
3903 (unsigned long) motg);
Pavankumar Kondeti458d8792012-09-28 14:45:18 +05303904 setup_timer(&motg->chg_check_timer, msm_otg_chg_check_timer_func,
3905 (unsigned long) motg);
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05303906 ret = request_irq(motg->irq, msm_otg_irq, IRQF_SHARED,
3907 "msm_otg", motg);
3908 if (ret) {
3909 dev_err(&pdev->dev, "request irq failed\n");
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003910 goto destroy_wlock;
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05303911 }
3912
Manu Gautamf8c45642012-08-10 10:20:56 -07003913 if (motg->async_irq) {
Vijayavardhan Vennapusa9ab6f972012-10-11 19:18:55 +05303914 ret = request_irq(motg->async_irq, msm_otg_irq,
3915 IRQF_TRIGGER_RISING, "msm_otg", motg);
Manu Gautamf8c45642012-08-10 10:20:56 -07003916 if (ret) {
3917 dev_err(&pdev->dev, "request irq failed (ASYNC INT)\n");
3918 goto free_irq;
3919 }
3920 disable_irq(motg->async_irq);
3921 }
3922
Jack Pham87f202f2012-08-06 00:24:22 -07003923 if (pdata->otg_control == OTG_PHY_CONTROL && pdata->mpm_otgsessvld_int)
3924 msm_mpm_enable_pin(pdata->mpm_otgsessvld_int, 1);
3925
Heikki Krogerus1d4c9292012-02-13 13:24:09 +02003926 phy->init = msm_otg_reset;
3927 phy->set_power = msm_otg_set_power;
Steve Mucklef132c6c2012-06-06 18:30:57 -07003928 phy->set_suspend = msm_otg_set_suspend;
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05303929
Heikki Krogerus1d4c9292012-02-13 13:24:09 +02003930 phy->io_ops = &msm_otg_io_ops;
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05303931
Heikki Krogerus1d4c9292012-02-13 13:24:09 +02003932 phy->otg->phy = &motg->phy;
3933 phy->otg->set_host = msm_otg_set_host;
3934 phy->otg->set_peripheral = msm_otg_set_peripheral;
Steve Mucklef132c6c2012-06-06 18:30:57 -07003935 phy->otg->start_hnp = msm_otg_start_hnp;
3936 phy->otg->start_srp = msm_otg_start_srp;
Heikki Krogerus1d4c9292012-02-13 13:24:09 +02003937
3938 ret = usb_set_transceiver(&motg->phy);
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05303939 if (ret) {
Heikki Krogerus1d4c9292012-02-13 13:24:09 +02003940 dev_err(&pdev->dev, "usb_set_transceiver failed\n");
Manu Gautamf8c45642012-08-10 10:20:56 -07003941 goto free_async_irq;
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05303942 }
3943
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05303944 if (motg->pdata->mode == USB_OTG &&
Pavankumar Kondeti0d81f312012-01-13 11:34:10 +05303945 motg->pdata->otg_control == OTG_PMIC_CONTROL) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003946 if (motg->pdata->pmic_id_irq) {
3947 ret = request_irq(motg->pdata->pmic_id_irq,
3948 msm_pmic_id_irq,
3949 IRQF_TRIGGER_RISING |
3950 IRQF_TRIGGER_FALLING,
3951 "msm_otg", motg);
3952 if (ret) {
3953 dev_err(&pdev->dev, "request irq failed for PMIC ID\n");
Steve Mucklef132c6c2012-06-06 18:30:57 -07003954 goto remove_phy;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003955 }
3956 } else {
3957 ret = -ENODEV;
3958 dev_err(&pdev->dev, "PMIC IRQ for ID notifications doesn't exist\n");
Steve Mucklef132c6c2012-06-06 18:30:57 -07003959 goto remove_phy;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003960 }
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05303961 }
3962
Vijayavardhan Vennapusafc464f02011-11-04 21:54:00 +05303963 msm_hsusb_mhl_switch_enable(motg, 1);
3964
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05303965 platform_set_drvdata(pdev, motg);
3966 device_init_wakeup(&pdev->dev, 1);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003967 motg->mA_port = IUNIT;
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05303968
Anji jonnalad270e2d2011-08-09 11:28:32 +05303969 ret = msm_otg_debugfs_init(motg);
3970 if (ret)
3971 dev_dbg(&pdev->dev, "mode debugfs file is"
3972 "not available\n");
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05303973
Amit Blay58b31472011-11-18 09:39:39 +02003974 if (motg->pdata->phy_type == SNPS_28NM_INTEGRATED_PHY) {
3975 if (motg->pdata->otg_control == OTG_PMIC_CONTROL &&
Pavankumar Kondeti0d81f312012-01-13 11:34:10 +05303976 (!(motg->pdata->mode == USB_OTG) ||
3977 motg->pdata->pmic_id_irq))
Amit Blay58b31472011-11-18 09:39:39 +02003978 motg->caps = ALLOW_PHY_POWER_COLLAPSE |
Vijayavardhan Vennapusa03171c72012-04-26 14:44:48 +05303979 ALLOW_PHY_RETENTION;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003980
Amit Blay58b31472011-11-18 09:39:39 +02003981 if (motg->pdata->otg_control == OTG_PHY_CONTROL)
Amit Blay81801aa2012-09-19 12:08:12 +02003982 motg->caps = ALLOW_PHY_RETENTION |
3983 ALLOW_PHY_REGULATORS_LPM;
Amit Blay58b31472011-11-18 09:39:39 +02003984 }
3985
Amit Blay6fa647a2012-05-24 14:12:08 +03003986 if (motg->pdata->enable_lpm_on_dev_suspend)
3987 motg->caps |= ALLOW_LPM_ON_DEV_SUSPEND;
3988
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003989 wake_lock(&motg->wlock);
Pavankumar Kondeti87c01042010-12-07 17:53:58 +05303990 pm_runtime_set_active(&pdev->dev);
Manu Gautamf8c45642012-08-10 10:20:56 -07003991 pm_runtime_enable(&pdev->dev);
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05303992
Manu Gautamcd82e9d2011-12-20 14:17:28 +05303993 if (motg->pdata->bus_scale_table) {
3994 motg->bus_perf_client =
3995 msm_bus_scale_register_client(motg->pdata->bus_scale_table);
3996 if (!motg->bus_perf_client)
Steve Mucklef132c6c2012-06-06 18:30:57 -07003997 dev_err(motg->phy.dev, "%s: Failed to register BUS "
Manu Gautamcd82e9d2011-12-20 14:17:28 +05303998 "scaling client!!\n", __func__);
Manu Gautam8bdcc592012-03-06 11:26:06 +05303999 else
4000 debug_bus_voting_enabled = true;
Manu Gautamcd82e9d2011-12-20 14:17:28 +05304001 }
4002
David Keitel272ce522012-08-17 16:25:24 -07004003 motg->usb_psy.name = "usb";
4004 motg->usb_psy.type = POWER_SUPPLY_TYPE_USB;
4005 motg->usb_psy.supplied_to = otg_pm_power_supplied_to;
4006 motg->usb_psy.num_supplicants = ARRAY_SIZE(otg_pm_power_supplied_to);
4007 motg->usb_psy.properties = otg_pm_power_props_usb;
4008 motg->usb_psy.num_properties = ARRAY_SIZE(otg_pm_power_props_usb);
4009 motg->usb_psy.get_property = otg_power_get_property_usb;
4010 motg->usb_psy.set_property = otg_power_set_property_usb;
4011
4012 if (motg->pdata->otg_control == OTG_PMIC_CONTROL) {
4013 /* if pm8921 use legacy implementation */
4014 if (!pm8921_charger_register_vbus_sn(&msm_otg_set_vbus_state)) {
4015 dev_dbg(motg->phy.dev, "%s: legacy support\n",
4016 __func__);
4017 legacy_power_supply = true;
4018 } else {
4019 ret = msm_otg_register_power_supply(pdev, motg);
4020 if (ret)
4021 goto remove_phy;
4022 }
4023 } else {
4024 ret = msm_otg_register_power_supply(pdev, motg);
4025 if (ret)
4026 goto remove_phy;
4027 }
4028
Pavankumar Kondeti87c01042010-12-07 17:53:58 +05304029 return 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004030
Steve Mucklef132c6c2012-06-06 18:30:57 -07004031remove_phy:
4032 usb_set_transceiver(NULL);
Manu Gautamf8c45642012-08-10 10:20:56 -07004033free_async_irq:
4034 if (motg->async_irq)
4035 free_irq(motg->async_irq, motg);
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05304036free_irq:
4037 free_irq(motg->irq, motg);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004038destroy_wlock:
4039 wake_lock_destroy(&motg->wlock);
Manu Gautam28b1bac2012-01-30 16:43:06 +05304040 clk_disable_unprepare(motg->core_clk);
Amit Blay81801aa2012-09-19 12:08:12 +02004041 msm_hsusb_ldo_enable(motg, USB_PHY_REG_OFF);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004042free_ldo_init:
Anji jonnala11aa5c42011-05-04 10:19:48 +05304043 msm_hsusb_ldo_init(motg, 0);
Mayank Rana248698c2012-04-19 00:03:16 +05304044free_hsusb_vddcx:
4045 regulator_disable(hsusb_vddcx);
4046free_config_vddcx:
4047 regulator_set_voltage(hsusb_vddcx,
4048 vdd_val[motg->vdd_type][VDD_NONE],
4049 vdd_val[motg->vdd_type][VDD_MAX]);
Anji jonnala7da3f262011-12-02 17:22:14 -08004050devote_xo_handle:
Manu Gautam28b1bac2012-01-30 16:43:06 +05304051 clk_disable_unprepare(motg->pclk);
Stephen Boyd30ad10b2012-03-01 14:51:04 -08004052 msm_xo_mode_vote(motg->xo_handle, MSM_XO_MODE_OFF);
Anji jonnala7da3f262011-12-02 17:22:14 -08004053free_xo_handle:
Stephen Boyd30ad10b2012-03-01 14:51:04 -08004054 msm_xo_put(motg->xo_handle);
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05304055free_regs:
4056 iounmap(motg->regs);
Manu Gautam5143b252012-01-05 19:25:23 -08004057put_pclk:
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05304058 clk_put(motg->pclk);
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05304059put_core_clk:
Manu Gautam5143b252012-01-05 19:25:23 -08004060 clk_put(motg->core_clk);
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05304061put_clk:
Pavankumar Kondeti923262e2012-04-20 15:34:24 +05304062 if (!IS_ERR(motg->clk))
4063 clk_put(motg->clk);
Amit Blay02eff132011-09-21 16:46:24 +03004064 if (!IS_ERR(motg->phy_reset_clk))
4065 clk_put(motg->phy_reset_clk);
Steve Mucklef132c6c2012-06-06 18:30:57 -07004066free_otg:
Heikki Krogerus1d4c9292012-02-13 13:24:09 +02004067 kfree(motg->phy.otg);
Pavankumar Kondetiaa449e12011-11-04 11:09:26 +05304068free_motg:
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05304069 kfree(motg);
4070 return ret;
4071}
4072
4073static int __devexit msm_otg_remove(struct platform_device *pdev)
4074{
4075 struct msm_otg *motg = platform_get_drvdata(pdev);
Steve Mucklef132c6c2012-06-06 18:30:57 -07004076 struct usb_otg *otg = motg->phy.otg;
Pavankumar Kondeti87c01042010-12-07 17:53:58 +05304077 int cnt = 0;
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05304078
4079 if (otg->host || otg->gadget)
4080 return -EBUSY;
4081
Pavankumar Kondetieaea7fe2011-10-27 14:46:45 +05304082 if (pdev->dev.of_node)
4083 msm_otg_setup_devices(pdev, motg->pdata->mode, false);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004084 if (motg->pdata->otg_control == OTG_PMIC_CONTROL)
4085 pm8921_charger_unregister_vbus_sn(0);
Pavankumar Kondeti2aec9f32012-06-13 09:06:03 +05304086 msm_otg_mhl_register_callback(motg, NULL);
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05304087 msm_otg_debugfs_cleanup();
Pavankumar Kondetid8608522011-05-04 10:19:47 +05304088 cancel_delayed_work_sync(&motg->chg_work);
Vijayavardhan Vennapusa68d55cf2012-06-27 20:06:12 +05304089 cancel_delayed_work_sync(&motg->pmic_id_status_work);
Amit Blayd0fe07b2012-09-05 16:42:09 +03004090 cancel_delayed_work_sync(&motg->suspend_work);
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05304091 cancel_work_sync(&motg->sm_work);
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05304092
Pavankumar Kondeti70187732011-02-15 09:42:34 +05304093 pm_runtime_resume(&pdev->dev);
Pavankumar Kondeti87c01042010-12-07 17:53:58 +05304094
4095 device_init_wakeup(&pdev->dev, 0);
4096 pm_runtime_disable(&pdev->dev);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004097 wake_lock_destroy(&motg->wlock);
Pavankumar Kondeti87c01042010-12-07 17:53:58 +05304098
Vijayavardhan Vennapusafc464f02011-11-04 21:54:00 +05304099 msm_hsusb_mhl_switch_enable(motg, 0);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004100 if (motg->pdata->pmic_id_irq)
4101 free_irq(motg->pdata->pmic_id_irq, motg);
Heikki Krogerus1d4c9292012-02-13 13:24:09 +02004102 usb_set_transceiver(NULL);
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05304103 free_irq(motg->irq, motg);
4104
Jack Pham87f202f2012-08-06 00:24:22 -07004105 if (motg->pdata->otg_control == OTG_PHY_CONTROL &&
4106 motg->pdata->mpm_otgsessvld_int)
4107 msm_mpm_enable_pin(motg->pdata->mpm_otgsessvld_int, 0);
4108
Pavankumar Kondeti87c01042010-12-07 17:53:58 +05304109 /*
4110 * Put PHY in low power mode.
4111 */
Steve Mucklef132c6c2012-06-06 18:30:57 -07004112 ulpi_read(otg->phy, 0x14);
4113 ulpi_write(otg->phy, 0x08, 0x09);
Pavankumar Kondeti87c01042010-12-07 17:53:58 +05304114
4115 writel(readl(USB_PORTSC) | PORTSC_PHCD, USB_PORTSC);
4116 while (cnt < PHY_SUSPEND_TIMEOUT_USEC) {
4117 if (readl(USB_PORTSC) & PORTSC_PHCD)
4118 break;
4119 udelay(1);
4120 cnt++;
4121 }
4122 if (cnt >= PHY_SUSPEND_TIMEOUT_USEC)
Steve Mucklef132c6c2012-06-06 18:30:57 -07004123 dev_err(otg->phy->dev, "Unable to suspend PHY\n");
Pavankumar Kondeti87c01042010-12-07 17:53:58 +05304124
Manu Gautam28b1bac2012-01-30 16:43:06 +05304125 clk_disable_unprepare(motg->pclk);
4126 clk_disable_unprepare(motg->core_clk);
Stephen Boyd30ad10b2012-03-01 14:51:04 -08004127 msm_xo_put(motg->xo_handle);
Amit Blay81801aa2012-09-19 12:08:12 +02004128 msm_hsusb_ldo_enable(motg, USB_PHY_REG_OFF);
Anji jonnala11aa5c42011-05-04 10:19:48 +05304129 msm_hsusb_ldo_init(motg, 0);
Mayank Rana248698c2012-04-19 00:03:16 +05304130 regulator_disable(hsusb_vddcx);
4131 regulator_set_voltage(hsusb_vddcx,
4132 vdd_val[motg->vdd_type][VDD_NONE],
4133 vdd_val[motg->vdd_type][VDD_MAX]);
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05304134
4135 iounmap(motg->regs);
Pavankumar Kondeti87c01042010-12-07 17:53:58 +05304136 pm_runtime_set_suspended(&pdev->dev);
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05304137
Amit Blay02eff132011-09-21 16:46:24 +03004138 if (!IS_ERR(motg->phy_reset_clk))
4139 clk_put(motg->phy_reset_clk);
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05304140 clk_put(motg->pclk);
Pavankumar Kondeti923262e2012-04-20 15:34:24 +05304141 if (!IS_ERR(motg->clk))
4142 clk_put(motg->clk);
Manu Gautam5143b252012-01-05 19:25:23 -08004143 clk_put(motg->core_clk);
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05304144
Manu Gautamcd82e9d2011-12-20 14:17:28 +05304145 if (motg->bus_perf_client)
4146 msm_bus_scale_unregister_client(motg->bus_perf_client);
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05304147
Heikki Krogerus1d4c9292012-02-13 13:24:09 +02004148 kfree(motg->phy.otg);
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05304149 kfree(motg);
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05304150 return 0;
4151}
4152
Pavankumar Kondeti87c01042010-12-07 17:53:58 +05304153#ifdef CONFIG_PM_RUNTIME
4154static int msm_otg_runtime_idle(struct device *dev)
4155{
4156 struct msm_otg *motg = dev_get_drvdata(dev);
Steve Mucklef132c6c2012-06-06 18:30:57 -07004157 struct usb_phy *phy = &motg->phy;
Pavankumar Kondeti87c01042010-12-07 17:53:58 +05304158
4159 dev_dbg(dev, "OTG runtime idle\n");
4160
Steve Mucklef132c6c2012-06-06 18:30:57 -07004161 if (phy->state == OTG_STATE_UNDEFINED)
Pavankumar Kondeti8be99cf2011-08-04 10:48:08 +05304162 return -EAGAIN;
4163 else
4164 return 0;
Pavankumar Kondeti87c01042010-12-07 17:53:58 +05304165}
4166
4167static int msm_otg_runtime_suspend(struct device *dev)
4168{
4169 struct msm_otg *motg = dev_get_drvdata(dev);
4170
4171 dev_dbg(dev, "OTG runtime suspend\n");
4172 return msm_otg_suspend(motg);
4173}
4174
4175static int msm_otg_runtime_resume(struct device *dev)
4176{
4177 struct msm_otg *motg = dev_get_drvdata(dev);
4178
4179 dev_dbg(dev, "OTG runtime resume\n");
Pavankumar Kondeti8be99cf2011-08-04 10:48:08 +05304180 pm_runtime_get_noresume(dev);
Pavankumar Kondeti87c01042010-12-07 17:53:58 +05304181 return msm_otg_resume(motg);
4182}
Pavankumar Kondeti87c01042010-12-07 17:53:58 +05304183#endif
4184
Pavankumar Kondeti70187732011-02-15 09:42:34 +05304185#ifdef CONFIG_PM_SLEEP
Pavankumar Kondeti87c01042010-12-07 17:53:58 +05304186static int msm_otg_pm_suspend(struct device *dev)
4187{
Jack Pham5ca279b2012-05-14 18:42:54 -07004188 int ret = 0;
Pavankumar Kondeti87c01042010-12-07 17:53:58 +05304189 struct msm_otg *motg = dev_get_drvdata(dev);
4190
4191 dev_dbg(dev, "OTG PM suspend\n");
Jack Pham5ca279b2012-05-14 18:42:54 -07004192
4193 atomic_set(&motg->pm_suspended, 1);
4194 ret = msm_otg_suspend(motg);
4195 if (ret)
4196 atomic_set(&motg->pm_suspended, 0);
4197
4198 return ret;
Pavankumar Kondeti87c01042010-12-07 17:53:58 +05304199}
4200
4201static int msm_otg_pm_resume(struct device *dev)
4202{
Jack Pham5ca279b2012-05-14 18:42:54 -07004203 int ret = 0;
Pavankumar Kondeti87c01042010-12-07 17:53:58 +05304204 struct msm_otg *motg = dev_get_drvdata(dev);
Pavankumar Kondeti87c01042010-12-07 17:53:58 +05304205
4206 dev_dbg(dev, "OTG PM resume\n");
4207
Jack Pham5ca279b2012-05-14 18:42:54 -07004208 atomic_set(&motg->pm_suspended, 0);
Jack Phamc7edb172012-08-13 15:32:39 -07004209 if (motg->async_int || motg->sm_work_pending) {
Jack Pham5ca279b2012-05-14 18:42:54 -07004210 pm_runtime_get_noresume(dev);
4211 ret = msm_otg_resume(motg);
Pavankumar Kondeti87c01042010-12-07 17:53:58 +05304212
Jack Pham5ca279b2012-05-14 18:42:54 -07004213 /* Update runtime PM status */
4214 pm_runtime_disable(dev);
4215 pm_runtime_set_active(dev);
4216 pm_runtime_enable(dev);
4217
Jack Phamc7edb172012-08-13 15:32:39 -07004218 if (motg->sm_work_pending) {
4219 motg->sm_work_pending = false;
4220 queue_work(system_nrt_wq, &motg->sm_work);
4221 }
Jack Pham5ca279b2012-05-14 18:42:54 -07004222 }
4223
4224 return ret;
Pavankumar Kondeti87c01042010-12-07 17:53:58 +05304225}
Pavankumar Kondeti87c01042010-12-07 17:53:58 +05304226#endif
4227
Pavankumar Kondeti70187732011-02-15 09:42:34 +05304228#ifdef CONFIG_PM
Pavankumar Kondeti87c01042010-12-07 17:53:58 +05304229static const struct dev_pm_ops msm_otg_dev_pm_ops = {
Pavankumar Kondeti70187732011-02-15 09:42:34 +05304230 SET_SYSTEM_SLEEP_PM_OPS(msm_otg_pm_suspend, msm_otg_pm_resume)
4231 SET_RUNTIME_PM_OPS(msm_otg_runtime_suspend, msm_otg_runtime_resume,
4232 msm_otg_runtime_idle)
Pavankumar Kondeti87c01042010-12-07 17:53:58 +05304233};
Pavankumar Kondeti70187732011-02-15 09:42:34 +05304234#endif
Pavankumar Kondeti87c01042010-12-07 17:53:58 +05304235
Pavankumar Kondetieaea7fe2011-10-27 14:46:45 +05304236static struct of_device_id msm_otg_dt_match[] = {
4237 { .compatible = "qcom,hsusb-otg",
4238 },
4239 {}
4240};
4241
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05304242static struct platform_driver msm_otg_driver = {
4243 .remove = __devexit_p(msm_otg_remove),
4244 .driver = {
4245 .name = DRIVER_NAME,
4246 .owner = THIS_MODULE,
Pavankumar Kondeti70187732011-02-15 09:42:34 +05304247#ifdef CONFIG_PM
Pavankumar Kondeti87c01042010-12-07 17:53:58 +05304248 .pm = &msm_otg_dev_pm_ops,
Pavankumar Kondeti70187732011-02-15 09:42:34 +05304249#endif
Pavankumar Kondetieaea7fe2011-10-27 14:46:45 +05304250 .of_match_table = msm_otg_dt_match,
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05304251 },
4252};
4253
4254static int __init msm_otg_init(void)
4255{
4256 return platform_driver_probe(&msm_otg_driver, msm_otg_probe);
4257}
4258
4259static void __exit msm_otg_exit(void)
4260{
4261 platform_driver_unregister(&msm_otg_driver);
4262}
4263
4264module_init(msm_otg_init);
4265module_exit(msm_otg_exit);
4266
4267MODULE_LICENSE("GPL v2");
4268MODULE_DESCRIPTION("MSM USB transceiver driver");