blob: 18f8729c4ec2cdccc84e872467de13855ac11a57 [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
Jack Pham8978b892012-10-17 16:31:39 -07001018 disable_irq(motg->irq);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001019 wake_lock(&motg->wlock);
Anji jonnala0f73cac2011-05-04 10:19:46 +05301020
Anji jonnala7da3f262011-12-02 17:22:14 -08001021 /* Vote for TCXO when waking up the phy */
Vijayavardhan Vennapusabbdd6082012-06-06 14:14:25 +05301022 if (motg->lpm_flags & XO_SHUTDOWN) {
1023 ret = msm_xo_mode_vote(motg->xo_handle, MSM_XO_MODE_ON);
1024 if (ret)
Steve Muckle75c34ca2012-06-12 14:27:40 -07001025 dev_err(phy->dev, "%s failed to vote for "
Vijayavardhan Vennapusabbdd6082012-06-06 14:14:25 +05301026 "TCXO D0 buffer%d\n", __func__, ret);
1027 motg->lpm_flags &= ~XO_SHUTDOWN;
1028 }
Pavankumar Kondeti87c01042010-12-07 17:53:58 +05301029
Ido Shayevitzc5c0f572012-07-31 13:58:45 +03001030 if (motg->lpm_flags & CLOCKS_DOWN) {
Amit Blay9b6e58b2012-06-18 13:12:49 +03001031 clk_prepare_enable(motg->core_clk);
1032 clk_prepare_enable(motg->pclk);
Ido Shayevitzc5c0f572012-07-31 13:58:45 +03001033 motg->lpm_flags &= ~CLOCKS_DOWN;
Amit Blay9b6e58b2012-06-18 13:12:49 +03001034 }
Pavankumar Kondeti87c01042010-12-07 17:53:58 +05301035
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001036 if (motg->lpm_flags & PHY_PWR_COLLAPSED) {
Amit Blay81801aa2012-09-19 12:08:12 +02001037 msm_hsusb_ldo_enable(motg, USB_PHY_REG_ON);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001038 motg->lpm_flags &= ~PHY_PWR_COLLAPSED;
Amit Blay81801aa2012-09-19 12:08:12 +02001039 } else if (motg->lpm_flags & PHY_REGULATORS_LPM) {
1040 msm_hsusb_ldo_enable(motg, USB_PHY_REG_LPM_OFF);
1041 motg->lpm_flags &= ~PHY_REGULATORS_LPM;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001042 }
1043
1044 if (motg->lpm_flags & PHY_RETENTIONED) {
Vijayavardhan Vennapusafc464f02011-11-04 21:54:00 +05301045 msm_hsusb_mhl_switch_enable(motg, 1);
Pavankumar Kondeti04aebcb2011-05-04 10:19:49 +05301046 msm_hsusb_config_vddcx(1);
Amit Blay58b31472011-11-18 09:39:39 +02001047 phy_ctrl_val = readl_relaxed(USB_PHY_CTRL);
1048 phy_ctrl_val |= PHY_RETEN;
1049 if (motg->pdata->otg_control == OTG_PHY_CONTROL)
1050 /* Disable PHY HV interrupts */
1051 phy_ctrl_val &=
1052 ~(PHY_IDHV_INTEN | PHY_OTGSESSVLDHV_INTEN);
1053 writel_relaxed(phy_ctrl_val, USB_PHY_CTRL);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001054 motg->lpm_flags &= ~PHY_RETENTIONED;
Pavankumar Kondeti04aebcb2011-05-04 10:19:49 +05301055 }
1056
Pavankumar Kondeti87c01042010-12-07 17:53:58 +05301057 temp = readl(USB_USBCMD);
1058 temp &= ~ASYNC_INTR_CTRL;
1059 temp &= ~ULPI_STP_CTRL;
1060 writel(temp, USB_USBCMD);
1061
1062 /*
1063 * PHY comes out of low power mode (LPM) in case of wakeup
1064 * from asynchronous interrupt.
1065 */
1066 if (!(readl(USB_PORTSC) & PORTSC_PHCD))
1067 goto skip_phy_resume;
1068
1069 writel(readl(USB_PORTSC) & ~PORTSC_PHCD, USB_PORTSC);
1070 while (cnt < PHY_RESUME_TIMEOUT_USEC) {
1071 if (!(readl(USB_PORTSC) & PORTSC_PHCD))
1072 break;
1073 udelay(1);
1074 cnt++;
1075 }
1076
1077 if (cnt >= PHY_RESUME_TIMEOUT_USEC) {
1078 /*
1079 * This is a fatal error. Reset the link and
1080 * PHY. USB state can not be restored. Re-insertion
1081 * of USB cable is the only way to get USB working.
1082 */
Heikki Krogerus1d4c9292012-02-13 13:24:09 +02001083 dev_err(phy->dev, "Unable to resume USB."
Pavankumar Kondeti87c01042010-12-07 17:53:58 +05301084 "Re-plugin the cable\n");
Heikki Krogerus1d4c9292012-02-13 13:24:09 +02001085 msm_otg_reset(phy);
Pavankumar Kondeti87c01042010-12-07 17:53:58 +05301086 }
1087
1088skip_phy_resume:
Steve Mucklef132c6c2012-06-06 18:30:57 -07001089 if (device_may_wakeup(phy->dev)) {
Pavankumar Kondeti87c01042010-12-07 17:53:58 +05301090 disable_irq_wake(motg->irq);
Manu Gautamf8c45642012-08-10 10:20:56 -07001091 if (motg->async_irq)
1092 disable_irq_wake(motg->async_irq);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001093 if (motg->pdata->pmic_id_irq)
1094 disable_irq_wake(motg->pdata->pmic_id_irq);
Jack Pham87f202f2012-08-06 00:24:22 -07001095 if (pdata->otg_control == OTG_PHY_CONTROL &&
1096 pdata->mpm_otgsessvld_int)
1097 msm_mpm_set_pin_wake(pdata->mpm_otgsessvld_int, 0);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001098 }
Pavankumar Kondeti87c01042010-12-07 17:53:58 +05301099 if (bus)
1100 set_bit(HCD_FLAG_HW_ACCESSIBLE, &(bus_to_hcd(bus))->flags);
1101
Pavankumar Kondeti2ce2c3a2011-05-02 11:56:33 +05301102 atomic_set(&motg->in_lpm, 0);
1103
Pavankumar Kondeti87c01042010-12-07 17:53:58 +05301104 if (motg->async_int) {
Manu Gautamf8c45642012-08-10 10:20:56 -07001105 /* Match the disable_irq call from ISR */
1106 enable_irq(motg->async_int);
Pavankumar Kondeti87c01042010-12-07 17:53:58 +05301107 motg->async_int = 0;
Pavankumar Kondeti87c01042010-12-07 17:53:58 +05301108 }
Jack Pham8978b892012-10-17 16:31:39 -07001109 enable_irq(motg->irq);
Pavankumar Kondeti87c01042010-12-07 17:53:58 +05301110
Manu Gautamf8c45642012-08-10 10:20:56 -07001111 /* If ASYNC IRQ is present then keep it enabled only during LPM */
1112 if (motg->async_irq)
1113 disable_irq(motg->async_irq);
1114
Heikki Krogerus1d4c9292012-02-13 13:24:09 +02001115 dev_info(phy->dev, "USB exited from low power mode\n");
Pavankumar Kondeti87c01042010-12-07 17:53:58 +05301116
1117 return 0;
1118}
Pavankumar Kondeti70187732011-02-15 09:42:34 +05301119#endif
Pavankumar Kondeti87c01042010-12-07 17:53:58 +05301120
David Keitel272ce522012-08-17 16:25:24 -07001121static void msm_otg_notify_host_mode(struct msm_otg *motg, bool host_mode)
Abhijeet Dharmapurikar5e96aaa2012-06-26 11:21:03 -07001122{
David Keitel272ce522012-08-17 16:25:24 -07001123 struct power_supply *usb = psy ? psy : &motg->usb_psy;
Sridhar Parasuram3c67a412012-09-26 09:36:22 -07001124
David Keitel272ce522012-08-17 16:25:24 -07001125 if (!usb) {
1126 pr_err("No USB power supply registered!\n");
1127 return;
1128 }
Sridhar Parasuram3c67a412012-09-26 09:36:22 -07001129
David Keitel272ce522012-08-17 16:25:24 -07001130 if (psy) {
1131 /* legacy support */
1132 if (host_mode)
1133 power_supply_set_scope(psy, POWER_SUPPLY_SCOPE_SYSTEM);
1134 else
1135 power_supply_set_scope(psy, POWER_SUPPLY_SCOPE_DEVICE);
1136 return;
1137 } else {
1138 motg->host_mode = host_mode;
1139 power_supply_changed(usb);
1140 }
Abhijeet Dharmapurikar5e96aaa2012-06-26 11:21:03 -07001141}
1142
David Keitel081a3e22012-04-18 12:37:07 -07001143static int msm_otg_notify_chg_type(struct msm_otg *motg)
1144{
1145 static int charger_type;
David Keitel272ce522012-08-17 16:25:24 -07001146 struct power_supply *usb = psy ? psy : &motg->usb_psy;
David Keitelba8f8322012-06-01 17:14:10 -07001147
David Keitel081a3e22012-04-18 12:37:07 -07001148 /*
1149 * TODO
1150 * Unify OTG driver charger types and power supply charger types
1151 */
1152 if (charger_type == motg->chg_type)
1153 return 0;
1154
1155 if (motg->chg_type == USB_SDP_CHARGER)
1156 charger_type = POWER_SUPPLY_TYPE_USB;
1157 else if (motg->chg_type == USB_CDP_CHARGER)
1158 charger_type = POWER_SUPPLY_TYPE_USB_CDP;
Pavankumar Kondeti9ec21d32012-05-07 15:50:23 +05301159 else if (motg->chg_type == USB_DCP_CHARGER ||
1160 motg->chg_type == USB_PROPRIETARY_CHARGER)
David Keitel081a3e22012-04-18 12:37:07 -07001161 charger_type = POWER_SUPPLY_TYPE_USB_DCP;
1162 else if ((motg->chg_type == USB_ACA_DOCK_CHARGER ||
1163 motg->chg_type == USB_ACA_A_CHARGER ||
1164 motg->chg_type == USB_ACA_B_CHARGER ||
1165 motg->chg_type == USB_ACA_C_CHARGER))
1166 charger_type = POWER_SUPPLY_TYPE_USB_ACA;
1167 else
1168 charger_type = POWER_SUPPLY_TYPE_BATTERY;
1169
David Keitel272ce522012-08-17 16:25:24 -07001170 if (!usb) {
David Keitelba8f8322012-06-01 17:14:10 -07001171 pr_err("No USB power supply registered!\n");
1172 return -EINVAL;
1173 }
1174
1175 pr_debug("setting usb power supply type %d\n", charger_type);
David Keitel272ce522012-08-17 16:25:24 -07001176 power_supply_set_supply_type(usb, charger_type);
David Keitelba8f8322012-06-01 17:14:10 -07001177 return 0;
David Keitel081a3e22012-04-18 12:37:07 -07001178}
1179
Amit Blay0f7edf72012-01-15 10:11:27 +02001180static int msm_otg_notify_power_supply(struct msm_otg *motg, unsigned mA)
1181{
David Keitel272ce522012-08-17 16:25:24 -07001182 struct power_supply *usb = psy ? psy : &motg->usb_psy;
Amit Blay0f7edf72012-01-15 10:11:27 +02001183
David Keitel272ce522012-08-17 16:25:24 -07001184 if (!usb) {
1185 dev_dbg(motg->phy.dev, "no usb power supply registered\n");
1186 goto psy_error;
David Keitelf5c5d602012-08-17 16:25:24 -07001187 }
1188
David Keitel272ce522012-08-17 16:25:24 -07001189 if (motg->cur_power == 0 && mA > 2) {
1190 /* Enable charging */
1191 if (power_supply_set_online(usb, true))
1192 goto psy_error;
1193 if (power_supply_set_current_limit(usb, 1000*mA))
1194 goto psy_error;
1195 } else if (motg->cur_power > 0 && (mA == 0 || mA == 2)) {
1196 /* Disable charging */
1197 if (power_supply_set_online(usb, false))
1198 goto psy_error;
1199 /* Set max current limit */
1200 if (power_supply_set_current_limit(usb, 0))
1201 goto psy_error;
1202 }
1203 power_supply_changed(usb);
Amit Blay0f7edf72012-01-15 10:11:27 +02001204 return 0;
1205
David Keitel272ce522012-08-17 16:25:24 -07001206psy_error:
1207 dev_dbg(motg->phy.dev, "power supply error when setting property\n");
Amit Blay0f7edf72012-01-15 10:11:27 +02001208 return -ENXIO;
1209}
1210
Pavankumar Kondetid8608522011-05-04 10:19:47 +05301211static void msm_otg_notify_charger(struct msm_otg *motg, unsigned mA)
1212{
Steve Mucklef132c6c2012-06-06 18:30:57 -07001213 struct usb_gadget *g = motg->phy.otg->gadget;
Vijayavardhan Vennapusaa3152032012-03-05 16:29:30 +05301214
1215 if (g && g->is_a_peripheral)
1216 return;
1217
Pavankumar Kondetiaa449e12011-11-04 11:09:26 +05301218 if ((motg->chg_type == USB_ACA_DOCK_CHARGER ||
1219 motg->chg_type == USB_ACA_A_CHARGER ||
1220 motg->chg_type == USB_ACA_B_CHARGER ||
1221 motg->chg_type == USB_ACA_C_CHARGER) &&
1222 mA > IDEV_ACA_CHG_LIMIT)
1223 mA = IDEV_ACA_CHG_LIMIT;
1224
David Keitel081a3e22012-04-18 12:37:07 -07001225 if (msm_otg_notify_chg_type(motg))
Steve Mucklef132c6c2012-06-06 18:30:57 -07001226 dev_err(motg->phy.dev,
David Keitel081a3e22012-04-18 12:37:07 -07001227 "Failed notifying %d charger type to PMIC\n",
1228 motg->chg_type);
1229
Pavankumar Kondetid8608522011-05-04 10:19:47 +05301230 if (motg->cur_power == mA)
1231 return;
1232
Heikki Krogerus1d4c9292012-02-13 13:24:09 +02001233 dev_info(motg->phy.dev, "Avail curr from USB = %u\n", mA);
Amit Blay0f7edf72012-01-15 10:11:27 +02001234
1235 /*
1236 * Use Power Supply API if supported, otherwise fallback
1237 * to legacy pm8921 API.
1238 */
1239 if (msm_otg_notify_power_supply(motg, mA))
1240 pm8921_charger_vbus_draw(mA);
1241
Pavankumar Kondetid8608522011-05-04 10:19:47 +05301242 motg->cur_power = mA;
1243}
1244
Heikki Krogerus1d4c9292012-02-13 13:24:09 +02001245static int msm_otg_set_power(struct usb_phy *phy, unsigned mA)
Pavankumar Kondetid8608522011-05-04 10:19:47 +05301246{
Heikki Krogerus1d4c9292012-02-13 13:24:09 +02001247 struct msm_otg *motg = container_of(phy, struct msm_otg, phy);
Pavankumar Kondetid8608522011-05-04 10:19:47 +05301248
1249 /*
1250 * Gadget driver uses set_power method to notify about the
1251 * available current based on suspend/configured states.
1252 *
1253 * IDEV_CHG can be drawn irrespective of suspend/un-configured
1254 * states when CDP/ACA is connected.
1255 */
1256 if (motg->chg_type == USB_SDP_CHARGER)
1257 msm_otg_notify_charger(motg, mA);
1258
1259 return 0;
1260}
1261
Steve Mucklef132c6c2012-06-06 18:30:57 -07001262static void msm_otg_start_host(struct usb_otg *otg, int on)
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05301263{
Steve Mucklef132c6c2012-06-06 18:30:57 -07001264 struct msm_otg *motg = container_of(otg->phy, struct msm_otg, phy);
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05301265 struct msm_otg_platform_data *pdata = motg->pdata;
1266 struct usb_hcd *hcd;
1267
1268 if (!otg->host)
1269 return;
1270
1271 hcd = bus_to_hcd(otg->host);
1272
1273 if (on) {
Steve Mucklef132c6c2012-06-06 18:30:57 -07001274 dev_dbg(otg->phy->dev, "host on\n");
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05301275
Vijayavardhan Vennapusa03171c72012-04-26 14:44:48 +05301276 if (pdata->otg_control == OTG_PHY_CONTROL)
Steve Mucklef132c6c2012-06-06 18:30:57 -07001277 ulpi_write(otg->phy, OTG_COMP_DISABLE,
Vijayavardhan Vennapusa03171c72012-04-26 14:44:48 +05301278 ULPI_SET(ULPI_PWR_CLK_MNG_REG));
1279
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05301280 /*
1281 * Some boards have a switch cotrolled by gpio
1282 * to enable/disable internal HUB. Enable internal
1283 * HUB before kicking the host.
1284 */
1285 if (pdata->setup_gpio)
1286 pdata->setup_gpio(OTG_STATE_A_HOST);
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05301287 usb_add_hcd(hcd, hcd->irq, IRQF_SHARED);
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05301288 } else {
Steve Mucklef132c6c2012-06-06 18:30:57 -07001289 dev_dbg(otg->phy->dev, "host off\n");
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05301290
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05301291 usb_remove_hcd(hcd);
Pavankumar Kondetiaa449e12011-11-04 11:09:26 +05301292 /* HCD core reset all bits of PORTSC. select ULPI phy */
1293 writel_relaxed(0x80000000, USB_PORTSC);
1294
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05301295 if (pdata->setup_gpio)
1296 pdata->setup_gpio(OTG_STATE_UNDEFINED);
Vijayavardhan Vennapusa03171c72012-04-26 14:44:48 +05301297
1298 if (pdata->otg_control == OTG_PHY_CONTROL)
Steve Mucklef132c6c2012-06-06 18:30:57 -07001299 ulpi_write(otg->phy, OTG_COMP_DISABLE,
Vijayavardhan Vennapusa03171c72012-04-26 14:44:48 +05301300 ULPI_CLR(ULPI_PWR_CLK_MNG_REG));
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05301301 }
1302}
1303
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001304static int msm_otg_usbdev_notify(struct notifier_block *self,
1305 unsigned long action, void *priv)
1306{
1307 struct msm_otg *motg = container_of(self, struct msm_otg, usbdev_nb);
Steve Mucklef132c6c2012-06-06 18:30:57 -07001308 struct usb_otg *otg = motg->phy.otg;
Pavankumar Kondetiaa449e12011-11-04 11:09:26 +05301309 struct usb_device *udev = priv;
1310
Pavankumar Kondetiaa449e12011-11-04 11:09:26 +05301311 if (action == USB_BUS_ADD || action == USB_BUS_REMOVE)
1312 goto out;
1313
Steve Mucklef132c6c2012-06-06 18:30:57 -07001314 if (udev->bus != otg->host)
Pavankumar Kondetiaa449e12011-11-04 11:09:26 +05301315 goto out;
1316 /*
1317 * Interested in devices connected directly to the root hub.
1318 * ACA dock can supply IDEV_CHG irrespective devices connected
1319 * on the accessory port.
1320 */
1321 if (!udev->parent || udev->parent->parent ||
1322 motg->chg_type == USB_ACA_DOCK_CHARGER)
1323 goto out;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001324
1325 switch (action) {
1326 case USB_DEVICE_ADD:
Vijayavardhan Vennapusaa3152032012-03-05 16:29:30 +05301327 if (aca_enabled())
1328 usb_disable_autosuspend(udev);
Steve Mucklef132c6c2012-06-06 18:30:57 -07001329 if (otg->phy->state == OTG_STATE_A_WAIT_BCON) {
Vijayavardhan Vennapusaa3152032012-03-05 16:29:30 +05301330 pr_debug("B_CONN set\n");
1331 set_bit(B_CONN, &motg->inputs);
1332 msm_otg_del_timer(motg);
Steve Mucklef132c6c2012-06-06 18:30:57 -07001333 otg->phy->state = OTG_STATE_A_HOST;
Vijayavardhan Vennapusaa3152032012-03-05 16:29:30 +05301334 /*
1335 * OTG PET: A-device must end session within
1336 * 10 sec after PET enumeration.
1337 */
1338 if (udev->quirks & USB_QUIRK_OTG_PET)
1339 msm_otg_start_timer(motg, TA_TST_MAINT,
1340 A_TST_MAINT);
1341 }
Pavankumar Kondetiaa449e12011-11-04 11:09:26 +05301342 /* fall through */
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001343 case USB_DEVICE_CONFIG:
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001344 if (udev->actconfig)
1345 motg->mA_port = udev->actconfig->desc.bMaxPower * 2;
1346 else
1347 motg->mA_port = IUNIT;
Steve Mucklef132c6c2012-06-06 18:30:57 -07001348 if (otg->phy->state == OTG_STATE_B_HOST)
Vijayavardhan Vennapusaa3152032012-03-05 16:29:30 +05301349 msm_otg_del_timer(motg);
Pavankumar Kondetiaa449e12011-11-04 11:09:26 +05301350 break;
1351 case USB_DEVICE_REMOVE:
Steve Mucklef132c6c2012-06-06 18:30:57 -07001352 if ((otg->phy->state == OTG_STATE_A_HOST) ||
1353 (otg->phy->state == OTG_STATE_A_SUSPEND)) {
Vijayavardhan Vennapusaa3152032012-03-05 16:29:30 +05301354 pr_debug("B_CONN clear\n");
1355 clear_bit(B_CONN, &motg->inputs);
1356 /*
1357 * OTG PET: A-device must end session after
1358 * PET disconnection if it is enumerated
1359 * with bcdDevice[0] = 1. USB core sets
1360 * bus->otg_vbus_off for us. clear it here.
1361 */
1362 if (udev->bus->otg_vbus_off) {
1363 udev->bus->otg_vbus_off = 0;
1364 set_bit(A_BUS_DROP, &motg->inputs);
1365 }
1366 queue_work(system_nrt_wq, &motg->sm_work);
1367 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001368 default:
1369 break;
1370 }
Pavankumar Kondetiaa449e12011-11-04 11:09:26 +05301371 if (test_bit(ID_A, &motg->inputs))
1372 msm_otg_notify_charger(motg, IDEV_ACA_CHG_MAX -
1373 motg->mA_port);
1374out:
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001375 return NOTIFY_OK;
1376}
1377
Mayank Ranae3926882011-12-26 09:47:54 +05301378static void msm_hsusb_vbus_power(struct msm_otg *motg, bool on)
1379{
1380 int ret;
1381 static bool vbus_is_on;
1382
1383 if (vbus_is_on == on)
1384 return;
1385
1386 if (motg->pdata->vbus_power) {
Mayank Rana91f597e2012-01-20 10:12:06 +05301387 ret = motg->pdata->vbus_power(on);
1388 if (!ret)
1389 vbus_is_on = on;
Mayank Ranae3926882011-12-26 09:47:54 +05301390 return;
1391 }
1392
1393 if (!vbus_otg) {
1394 pr_err("vbus_otg is NULL.");
1395 return;
1396 }
1397
Abhijeet Dharmapurikarbe054882012-01-03 20:27:07 -08001398 /*
1399 * if entering host mode tell the charger to not draw any current
Abhijeet Dharmapurikar6d941212012-03-05 10:30:56 -08001400 * from usb before turning on the boost.
1401 * if exiting host mode disable the boost before enabling to draw
1402 * current from the source.
Abhijeet Dharmapurikarbe054882012-01-03 20:27:07 -08001403 */
Mayank Ranae3926882011-12-26 09:47:54 +05301404 if (on) {
Abhijeet Dharmapurikar5e96aaa2012-06-26 11:21:03 -07001405 msm_otg_notify_host_mode(motg, on);
Mayank Ranae3926882011-12-26 09:47:54 +05301406 ret = regulator_enable(vbus_otg);
1407 if (ret) {
1408 pr_err("unable to enable vbus_otg\n");
1409 return;
1410 }
1411 vbus_is_on = true;
1412 } else {
1413 ret = regulator_disable(vbus_otg);
1414 if (ret) {
1415 pr_err("unable to disable vbus_otg\n");
1416 return;
1417 }
Abhijeet Dharmapurikar5e96aaa2012-06-26 11:21:03 -07001418 msm_otg_notify_host_mode(motg, on);
Mayank Ranae3926882011-12-26 09:47:54 +05301419 vbus_is_on = false;
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05301420 }
1421}
1422
Heikki Krogerus1d4c9292012-02-13 13:24:09 +02001423static int msm_otg_set_host(struct usb_otg *otg, struct usb_bus *host)
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05301424{
Heikki Krogerus1d4c9292012-02-13 13:24:09 +02001425 struct msm_otg *motg = container_of(otg->phy, struct msm_otg, phy);
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05301426 struct usb_hcd *hcd;
1427
1428 /*
1429 * Fail host registration if this board can support
1430 * only peripheral configuration.
1431 */
1432 if (motg->pdata->mode == USB_PERIPHERAL) {
Heikki Krogerus1d4c9292012-02-13 13:24:09 +02001433 dev_info(otg->phy->dev, "Host mode is not supported\n");
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05301434 return -ENODEV;
1435 }
1436
Mayank Ranae3926882011-12-26 09:47:54 +05301437 if (!motg->pdata->vbus_power && host) {
Steve Mucklef132c6c2012-06-06 18:30:57 -07001438 vbus_otg = devm_regulator_get(motg->phy.dev, "vbus_otg");
Mayank Ranae3926882011-12-26 09:47:54 +05301439 if (IS_ERR(vbus_otg)) {
1440 pr_err("Unable to get vbus_otg\n");
1441 return -ENODEV;
1442 }
1443 }
1444
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05301445 if (!host) {
Heikki Krogerus1d4c9292012-02-13 13:24:09 +02001446 if (otg->phy->state == OTG_STATE_A_HOST) {
1447 pm_runtime_get_sync(otg->phy->dev);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001448 usb_unregister_notify(&motg->usbdev_nb);
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05301449 msm_otg_start_host(otg, 0);
Mayank Ranae3926882011-12-26 09:47:54 +05301450 msm_hsusb_vbus_power(motg, 0);
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05301451 otg->host = NULL;
Heikki Krogerus1d4c9292012-02-13 13:24:09 +02001452 otg->phy->state = OTG_STATE_UNDEFINED;
Vijayavardhan Vennapusaa3152032012-03-05 16:29:30 +05301453 queue_work(system_nrt_wq, &motg->sm_work);
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05301454 } else {
1455 otg->host = NULL;
1456 }
1457
1458 return 0;
1459 }
1460
1461 hcd = bus_to_hcd(host);
1462 hcd->power_budget = motg->pdata->power_budget;
1463
Vijayavardhan Vennapusaa3152032012-03-05 16:29:30 +05301464#ifdef CONFIG_USB_OTG
1465 host->otg_port = 1;
1466#endif
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001467 motg->usbdev_nb.notifier_call = msm_otg_usbdev_notify;
1468 usb_register_notify(&motg->usbdev_nb);
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05301469 otg->host = host;
Heikki Krogerus1d4c9292012-02-13 13:24:09 +02001470 dev_dbg(otg->phy->dev, "host driver registered w/ tranceiver\n");
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05301471
1472 /*
1473 * Kick the state machine work, if peripheral is not supported
1474 * or peripheral is already registered with us.
1475 */
Pavankumar Kondeti87c01042010-12-07 17:53:58 +05301476 if (motg->pdata->mode == USB_HOST || otg->gadget) {
Heikki Krogerus1d4c9292012-02-13 13:24:09 +02001477 pm_runtime_get_sync(otg->phy->dev);
Vijayavardhan Vennapusaa3152032012-03-05 16:29:30 +05301478 queue_work(system_nrt_wq, &motg->sm_work);
Pavankumar Kondeti87c01042010-12-07 17:53:58 +05301479 }
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05301480
1481 return 0;
1482}
1483
Steve Mucklef132c6c2012-06-06 18:30:57 -07001484static void msm_otg_start_peripheral(struct usb_otg *otg, int on)
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05301485{
Manu Gautamcd82e9d2011-12-20 14:17:28 +05301486 int ret;
Steve Mucklef132c6c2012-06-06 18:30:57 -07001487 struct msm_otg *motg = container_of(otg->phy, struct msm_otg, phy);
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05301488 struct msm_otg_platform_data *pdata = motg->pdata;
1489
1490 if (!otg->gadget)
1491 return;
1492
1493 if (on) {
Steve Mucklef132c6c2012-06-06 18:30:57 -07001494 dev_dbg(otg->phy->dev, "gadget on\n");
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05301495 /*
1496 * Some boards have a switch cotrolled by gpio
1497 * to enable/disable internal HUB. Disable internal
1498 * HUB before kicking the gadget.
1499 */
1500 if (pdata->setup_gpio)
1501 pdata->setup_gpio(OTG_STATE_B_PERIPHERAL);
Ofir Cohen94213a72012-05-03 14:26:32 +03001502
Manu Gautamcd82e9d2011-12-20 14:17:28 +05301503 /* Configure BUS performance parameters for MAX bandwidth */
Manu Gautam8bdcc592012-03-06 11:26:06 +05301504 if (motg->bus_perf_client && debug_bus_voting_enabled) {
Manu Gautamcd82e9d2011-12-20 14:17:28 +05301505 ret = msm_bus_scale_client_update_request(
1506 motg->bus_perf_client, 1);
1507 if (ret)
Steve Mucklef132c6c2012-06-06 18:30:57 -07001508 dev_err(motg->phy.dev, "%s: Failed to vote for "
Manu Gautamcd82e9d2011-12-20 14:17:28 +05301509 "bus bandwidth %d\n", __func__, ret);
1510 }
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05301511 usb_gadget_vbus_connect(otg->gadget);
1512 } else {
Steve Mucklef132c6c2012-06-06 18:30:57 -07001513 dev_dbg(otg->phy->dev, "gadget off\n");
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05301514 usb_gadget_vbus_disconnect(otg->gadget);
Manu Gautamcd82e9d2011-12-20 14:17:28 +05301515 /* Configure BUS performance parameters to default */
1516 if (motg->bus_perf_client) {
1517 ret = msm_bus_scale_client_update_request(
1518 motg->bus_perf_client, 0);
1519 if (ret)
Steve Mucklef132c6c2012-06-06 18:30:57 -07001520 dev_err(motg->phy.dev, "%s: Failed to devote "
Manu Gautamcd82e9d2011-12-20 14:17:28 +05301521 "for bus bw %d\n", __func__, ret);
1522 }
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05301523 if (pdata->setup_gpio)
1524 pdata->setup_gpio(OTG_STATE_UNDEFINED);
1525 }
1526
1527}
1528
Heikki Krogerus1d4c9292012-02-13 13:24:09 +02001529static int msm_otg_set_peripheral(struct usb_otg *otg,
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05301530 struct usb_gadget *gadget)
1531{
Heikki Krogerus1d4c9292012-02-13 13:24:09 +02001532 struct msm_otg *motg = container_of(otg->phy, struct msm_otg, phy);
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05301533
1534 /*
1535 * Fail peripheral registration if this board can support
1536 * only host configuration.
1537 */
1538 if (motg->pdata->mode == USB_HOST) {
Heikki Krogerus1d4c9292012-02-13 13:24:09 +02001539 dev_info(otg->phy->dev, "Peripheral mode is not supported\n");
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05301540 return -ENODEV;
1541 }
1542
1543 if (!gadget) {
Heikki Krogerus1d4c9292012-02-13 13:24:09 +02001544 if (otg->phy->state == OTG_STATE_B_PERIPHERAL) {
1545 pm_runtime_get_sync(otg->phy->dev);
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05301546 msm_otg_start_peripheral(otg, 0);
1547 otg->gadget = NULL;
Heikki Krogerus1d4c9292012-02-13 13:24:09 +02001548 otg->phy->state = OTG_STATE_UNDEFINED;
Vijayavardhan Vennapusaa3152032012-03-05 16:29:30 +05301549 queue_work(system_nrt_wq, &motg->sm_work);
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05301550 } else {
1551 otg->gadget = NULL;
1552 }
1553
1554 return 0;
1555 }
1556 otg->gadget = gadget;
Heikki Krogerus1d4c9292012-02-13 13:24:09 +02001557 dev_dbg(otg->phy->dev, "peripheral driver registered w/ tranceiver\n");
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05301558
1559 /*
1560 * Kick the state machine work, if host is not supported
1561 * or host is already registered with us.
1562 */
Pavankumar Kondeti87c01042010-12-07 17:53:58 +05301563 if (motg->pdata->mode == USB_PERIPHERAL || otg->host) {
Heikki Krogerus1d4c9292012-02-13 13:24:09 +02001564 pm_runtime_get_sync(otg->phy->dev);
Vijayavardhan Vennapusaa3152032012-03-05 16:29:30 +05301565 queue_work(system_nrt_wq, &motg->sm_work);
Pavankumar Kondeti87c01042010-12-07 17:53:58 +05301566 }
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05301567
1568 return 0;
1569}
1570
Pavankumar Kondeti2aec9f32012-06-13 09:06:03 +05301571static int msm_otg_mhl_register_callback(struct msm_otg *motg,
1572 void (*callback)(int on))
1573{
1574 struct usb_phy *phy = &motg->phy;
1575 int ret;
1576
Manoj Raoa7bddd12012-08-27 20:36:45 -07001577 if (!motg->pdata->mhl_enable) {
1578 dev_dbg(phy->dev, "MHL feature not enabled\n");
1579 return -ENODEV;
1580 }
1581
Pavankumar Kondeti2aec9f32012-06-13 09:06:03 +05301582 if (motg->pdata->otg_control != OTG_PMIC_CONTROL ||
1583 !motg->pdata->pmic_id_irq) {
1584 dev_dbg(phy->dev, "MHL can not be supported without PMIC Id\n");
1585 return -ENODEV;
1586 }
1587
1588 if (!motg->pdata->mhl_dev_name) {
1589 dev_dbg(phy->dev, "MHL device name does not exist.\n");
1590 return -ENODEV;
1591 }
1592
1593 if (callback)
1594 ret = mhl_register_callback(motg->pdata->mhl_dev_name,
1595 callback);
1596 else
1597 ret = mhl_unregister_callback(motg->pdata->mhl_dev_name);
1598
1599 if (ret)
1600 dev_dbg(phy->dev, "mhl_register_callback(%s) return error=%d\n",
1601 motg->pdata->mhl_dev_name, ret);
1602 else
1603 motg->mhl_enabled = true;
1604
1605 return ret;
1606}
1607
1608static void msm_otg_mhl_notify_online(int on)
1609{
1610 struct msm_otg *motg = the_msm_otg;
1611 struct usb_phy *phy = &motg->phy;
1612 bool queue = false;
1613
1614 dev_dbg(phy->dev, "notify MHL %s%s\n", on ? "" : "dis", "connected");
1615
1616 if (on) {
1617 set_bit(MHL, &motg->inputs);
1618 } else {
1619 clear_bit(MHL, &motg->inputs);
1620 queue = true;
1621 }
1622
1623 if (queue && phy->state != OTG_STATE_UNDEFINED)
1624 schedule_work(&motg->sm_work);
1625}
1626
1627static bool msm_otg_is_mhl(struct msm_otg *motg)
1628{
1629 struct usb_phy *phy = &motg->phy;
1630 int is_mhl, ret;
1631
1632 ret = mhl_device_discovery(motg->pdata->mhl_dev_name, &is_mhl);
1633 if (ret || is_mhl != MHL_DISCOVERY_RESULT_MHL) {
1634 /*
1635 * MHL driver calls our callback saying that MHL connected
1636 * if RID_GND is detected. But at later part of discovery
1637 * it may figure out MHL is not connected and returns
1638 * false. Hence clear MHL input here.
1639 */
1640 clear_bit(MHL, &motg->inputs);
1641 dev_dbg(phy->dev, "MHL device not found\n");
1642 return false;
1643 }
1644
1645 set_bit(MHL, &motg->inputs);
1646 dev_dbg(phy->dev, "MHL device found\n");
1647 return true;
1648}
1649
1650static bool msm_chg_mhl_detect(struct msm_otg *motg)
1651{
1652 bool ret, id;
1653 unsigned long flags;
1654
1655 if (!motg->mhl_enabled)
1656 return false;
1657
1658 local_irq_save(flags);
1659 id = irq_read_line(motg->pdata->pmic_id_irq);
1660 local_irq_restore(flags);
1661
1662 if (id)
1663 return false;
1664
1665 mhl_det_in_progress = true;
1666 ret = msm_otg_is_mhl(motg);
1667 mhl_det_in_progress = false;
1668
1669 return ret;
1670}
1671
Pavankumar Kondeti458d8792012-09-28 14:45:18 +05301672static void msm_otg_chg_check_timer_func(unsigned long data)
1673{
1674 struct msm_otg *motg = (struct msm_otg *) data;
1675 struct usb_otg *otg = motg->phy.otg;
1676
1677 if (atomic_read(&motg->in_lpm) ||
1678 !test_bit(B_SESS_VLD, &motg->inputs) ||
1679 otg->phy->state != OTG_STATE_B_PERIPHERAL ||
1680 otg->gadget->speed != USB_SPEED_UNKNOWN) {
1681 dev_dbg(otg->phy->dev, "Nothing to do in chg_check_timer\n");
1682 return;
1683 }
1684
1685 if ((readl_relaxed(USB_PORTSC) & PORTSC_LS) == PORTSC_LS) {
1686 dev_dbg(otg->phy->dev, "DCP is detected as SDP\n");
1687 set_bit(B_FALSE_SDP, &motg->inputs);
1688 queue_work(system_nrt_wq, &motg->sm_work);
1689 }
1690}
1691
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001692static bool msm_chg_aca_detect(struct msm_otg *motg)
1693{
Steve Mucklef132c6c2012-06-06 18:30:57 -07001694 struct usb_phy *phy = &motg->phy;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001695 u32 int_sts;
1696 bool ret = false;
1697
Pavankumar Kondetiaa449e12011-11-04 11:09:26 +05301698 if (!aca_enabled())
1699 goto out;
1700
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001701 if (motg->pdata->phy_type == CI_45NM_INTEGRATED_PHY)
1702 goto out;
1703
Steve Mucklef132c6c2012-06-06 18:30:57 -07001704 int_sts = ulpi_read(phy, 0x87);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001705 switch (int_sts & 0x1C) {
1706 case 0x08:
1707 if (!test_and_set_bit(ID_A, &motg->inputs)) {
Steve Mucklef132c6c2012-06-06 18:30:57 -07001708 dev_dbg(phy->dev, "ID_A\n");
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001709 motg->chg_type = USB_ACA_A_CHARGER;
1710 motg->chg_state = USB_CHG_STATE_DETECTED;
1711 clear_bit(ID_B, &motg->inputs);
1712 clear_bit(ID_C, &motg->inputs);
Pavankumar Kondetiaa449e12011-11-04 11:09:26 +05301713 set_bit(ID, &motg->inputs);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001714 ret = true;
1715 }
1716 break;
1717 case 0x0C:
1718 if (!test_and_set_bit(ID_B, &motg->inputs)) {
Steve Mucklef132c6c2012-06-06 18:30:57 -07001719 dev_dbg(phy->dev, "ID_B\n");
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001720 motg->chg_type = USB_ACA_B_CHARGER;
1721 motg->chg_state = USB_CHG_STATE_DETECTED;
1722 clear_bit(ID_A, &motg->inputs);
1723 clear_bit(ID_C, &motg->inputs);
Pavankumar Kondetiaa449e12011-11-04 11:09:26 +05301724 set_bit(ID, &motg->inputs);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001725 ret = true;
1726 }
1727 break;
1728 case 0x10:
1729 if (!test_and_set_bit(ID_C, &motg->inputs)) {
Steve Mucklef132c6c2012-06-06 18:30:57 -07001730 dev_dbg(phy->dev, "ID_C\n");
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001731 motg->chg_type = USB_ACA_C_CHARGER;
1732 motg->chg_state = USB_CHG_STATE_DETECTED;
1733 clear_bit(ID_A, &motg->inputs);
1734 clear_bit(ID_B, &motg->inputs);
Pavankumar Kondetiaa449e12011-11-04 11:09:26 +05301735 set_bit(ID, &motg->inputs);
1736 ret = true;
1737 }
1738 break;
1739 case 0x04:
1740 if (test_and_clear_bit(ID, &motg->inputs)) {
Steve Mucklef132c6c2012-06-06 18:30:57 -07001741 dev_dbg(phy->dev, "ID_GND\n");
Pavankumar Kondetiaa449e12011-11-04 11:09:26 +05301742 motg->chg_type = USB_INVALID_CHARGER;
1743 motg->chg_state = USB_CHG_STATE_UNDEFINED;
1744 clear_bit(ID_A, &motg->inputs);
1745 clear_bit(ID_B, &motg->inputs);
1746 clear_bit(ID_C, &motg->inputs);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001747 ret = true;
1748 }
1749 break;
1750 default:
1751 ret = test_and_clear_bit(ID_A, &motg->inputs) |
1752 test_and_clear_bit(ID_B, &motg->inputs) |
Pavankumar Kondetiaa449e12011-11-04 11:09:26 +05301753 test_and_clear_bit(ID_C, &motg->inputs) |
1754 !test_and_set_bit(ID, &motg->inputs);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001755 if (ret) {
Steve Mucklef132c6c2012-06-06 18:30:57 -07001756 dev_dbg(phy->dev, "ID A/B/C/GND is no more\n");
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001757 motg->chg_type = USB_INVALID_CHARGER;
1758 motg->chg_state = USB_CHG_STATE_UNDEFINED;
1759 }
1760 }
1761out:
1762 return ret;
1763}
1764
1765static void msm_chg_enable_aca_det(struct msm_otg *motg)
1766{
Steve Mucklef132c6c2012-06-06 18:30:57 -07001767 struct usb_phy *phy = &motg->phy;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001768
Pavankumar Kondetiaa449e12011-11-04 11:09:26 +05301769 if (!aca_enabled())
1770 return;
1771
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001772 switch (motg->pdata->phy_type) {
1773 case SNPS_28NM_INTEGRATED_PHY:
Pavankumar Kondetiaa449e12011-11-04 11:09:26 +05301774 /* Disable ID_GND in link and PHY */
1775 writel_relaxed(readl_relaxed(USB_OTGSC) & ~(OTGSC_IDPU |
1776 OTGSC_IDIE), USB_OTGSC);
Steve Mucklef132c6c2012-06-06 18:30:57 -07001777 ulpi_write(phy, 0x01, 0x0C);
1778 ulpi_write(phy, 0x10, 0x0F);
1779 ulpi_write(phy, 0x10, 0x12);
Pavankumar Kondeti446f4542012-02-01 13:57:13 +05301780 /* Disable PMIC ID pull-up */
1781 pm8xxx_usb_id_pullup(0);
Pavankumar Kondetiaa449e12011-11-04 11:09:26 +05301782 /* Enable ACA ID detection */
Steve Mucklef132c6c2012-06-06 18:30:57 -07001783 ulpi_write(phy, 0x20, 0x85);
Pavankumar Kondeti4960f312011-12-06 15:46:14 +05301784 aca_id_turned_on = true;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001785 break;
1786 default:
1787 break;
1788 }
1789}
1790
1791static void msm_chg_enable_aca_intr(struct msm_otg *motg)
1792{
Steve Mucklef132c6c2012-06-06 18:30:57 -07001793 struct usb_phy *phy = &motg->phy;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001794
Pavankumar Kondetiaa449e12011-11-04 11:09:26 +05301795 if (!aca_enabled())
1796 return;
1797
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001798 switch (motg->pdata->phy_type) {
1799 case SNPS_28NM_INTEGRATED_PHY:
Pavankumar Kondetiaa449e12011-11-04 11:09:26 +05301800 /* Enable ACA Detection interrupt (on any RID change) */
Steve Mucklef132c6c2012-06-06 18:30:57 -07001801 ulpi_write(phy, 0x01, 0x94);
Pavankumar Kondetiaa449e12011-11-04 11:09:26 +05301802 break;
1803 default:
1804 break;
1805 }
1806}
1807
1808static void msm_chg_disable_aca_intr(struct msm_otg *motg)
1809{
Steve Mucklef132c6c2012-06-06 18:30:57 -07001810 struct usb_phy *phy = &motg->phy;
Pavankumar Kondetiaa449e12011-11-04 11:09:26 +05301811
1812 if (!aca_enabled())
1813 return;
1814
1815 switch (motg->pdata->phy_type) {
1816 case SNPS_28NM_INTEGRATED_PHY:
Steve Mucklef132c6c2012-06-06 18:30:57 -07001817 ulpi_write(phy, 0x01, 0x95);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001818 break;
1819 default:
1820 break;
1821 }
1822}
1823
1824static bool msm_chg_check_aca_intr(struct msm_otg *motg)
1825{
Steve Mucklef132c6c2012-06-06 18:30:57 -07001826 struct usb_phy *phy = &motg->phy;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001827 bool ret = false;
1828
Pavankumar Kondetiaa449e12011-11-04 11:09:26 +05301829 if (!aca_enabled())
1830 return ret;
1831
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001832 switch (motg->pdata->phy_type) {
1833 case SNPS_28NM_INTEGRATED_PHY:
Steve Mucklef132c6c2012-06-06 18:30:57 -07001834 if (ulpi_read(phy, 0x91) & 1) {
1835 dev_dbg(phy->dev, "RID change\n");
1836 ulpi_write(phy, 0x01, 0x92);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001837 ret = msm_chg_aca_detect(motg);
1838 }
1839 default:
1840 break;
1841 }
1842 return ret;
1843}
Pavankumar Kondetiaa449e12011-11-04 11:09:26 +05301844
1845static void msm_otg_id_timer_func(unsigned long data)
1846{
1847 struct msm_otg *motg = (struct msm_otg *) data;
1848
1849 if (!aca_enabled())
1850 return;
1851
1852 if (atomic_read(&motg->in_lpm)) {
Steve Mucklef132c6c2012-06-06 18:30:57 -07001853 dev_dbg(motg->phy.dev, "timer: in lpm\n");
Pavankumar Kondetiaa449e12011-11-04 11:09:26 +05301854 return;
1855 }
1856
Steve Mucklef132c6c2012-06-06 18:30:57 -07001857 if (motg->phy.state == OTG_STATE_A_SUSPEND)
Vijayavardhan Vennapusaa3152032012-03-05 16:29:30 +05301858 goto out;
1859
Pavankumar Kondetiaa449e12011-11-04 11:09:26 +05301860 if (msm_chg_check_aca_intr(motg)) {
Steve Mucklef132c6c2012-06-06 18:30:57 -07001861 dev_dbg(motg->phy.dev, "timer: aca work\n");
Vijayavardhan Vennapusaa3152032012-03-05 16:29:30 +05301862 queue_work(system_nrt_wq, &motg->sm_work);
Pavankumar Kondetiaa449e12011-11-04 11:09:26 +05301863 }
1864
Vijayavardhan Vennapusaa3152032012-03-05 16:29:30 +05301865out:
Pavankumar Kondetiaa449e12011-11-04 11:09:26 +05301866 if (!test_bit(ID, &motg->inputs) || test_bit(ID_A, &motg->inputs))
1867 mod_timer(&motg->id_timer, ID_TIMER_FREQ);
1868}
1869
Pavankumar Kondetid8608522011-05-04 10:19:47 +05301870static bool msm_chg_check_secondary_det(struct msm_otg *motg)
1871{
Heikki Krogerus1d4c9292012-02-13 13:24:09 +02001872 struct usb_phy *phy = &motg->phy;
Pavankumar Kondetid8608522011-05-04 10:19:47 +05301873 u32 chg_det;
1874 bool ret = false;
1875
1876 switch (motg->pdata->phy_type) {
1877 case CI_45NM_INTEGRATED_PHY:
Heikki Krogerus1d4c9292012-02-13 13:24:09 +02001878 chg_det = ulpi_read(phy, 0x34);
Pavankumar Kondetid8608522011-05-04 10:19:47 +05301879 ret = chg_det & (1 << 4);
1880 break;
1881 case SNPS_28NM_INTEGRATED_PHY:
Heikki Krogerus1d4c9292012-02-13 13:24:09 +02001882 chg_det = ulpi_read(phy, 0x87);
Pavankumar Kondetid8608522011-05-04 10:19:47 +05301883 ret = chg_det & 1;
1884 break;
1885 default:
1886 break;
1887 }
1888 return ret;
1889}
1890
1891static void msm_chg_enable_secondary_det(struct msm_otg *motg)
1892{
Heikki Krogerus1d4c9292012-02-13 13:24:09 +02001893 struct usb_phy *phy = &motg->phy;
Pavankumar Kondetid8608522011-05-04 10:19:47 +05301894 u32 chg_det;
1895
1896 switch (motg->pdata->phy_type) {
1897 case CI_45NM_INTEGRATED_PHY:
Heikki Krogerus1d4c9292012-02-13 13:24:09 +02001898 chg_det = ulpi_read(phy, 0x34);
Pavankumar Kondetid8608522011-05-04 10:19:47 +05301899 /* Turn off charger block */
1900 chg_det |= ~(1 << 1);
Heikki Krogerus1d4c9292012-02-13 13:24:09 +02001901 ulpi_write(phy, chg_det, 0x34);
Pavankumar Kondetid8608522011-05-04 10:19:47 +05301902 udelay(20);
1903 /* control chg block via ULPI */
1904 chg_det &= ~(1 << 3);
Heikki Krogerus1d4c9292012-02-13 13:24:09 +02001905 ulpi_write(phy, chg_det, 0x34);
Pavankumar Kondetid8608522011-05-04 10:19:47 +05301906 /* put it in host mode for enabling D- source */
1907 chg_det &= ~(1 << 2);
Heikki Krogerus1d4c9292012-02-13 13:24:09 +02001908 ulpi_write(phy, chg_det, 0x34);
Pavankumar Kondetid8608522011-05-04 10:19:47 +05301909 /* Turn on chg detect block */
1910 chg_det &= ~(1 << 1);
Heikki Krogerus1d4c9292012-02-13 13:24:09 +02001911 ulpi_write(phy, chg_det, 0x34);
Pavankumar Kondetid8608522011-05-04 10:19:47 +05301912 udelay(20);
1913 /* enable chg detection */
1914 chg_det &= ~(1 << 0);
Heikki Krogerus1d4c9292012-02-13 13:24:09 +02001915 ulpi_write(phy, chg_det, 0x34);
Pavankumar Kondetid8608522011-05-04 10:19:47 +05301916 break;
1917 case SNPS_28NM_INTEGRATED_PHY:
1918 /*
1919 * Configure DM as current source, DP as current sink
1920 * and enable battery charging comparators.
1921 */
Heikki Krogerus1d4c9292012-02-13 13:24:09 +02001922 ulpi_write(phy, 0x8, 0x85);
1923 ulpi_write(phy, 0x2, 0x85);
1924 ulpi_write(phy, 0x1, 0x85);
Pavankumar Kondetid8608522011-05-04 10:19:47 +05301925 break;
1926 default:
1927 break;
1928 }
1929}
1930
1931static bool msm_chg_check_primary_det(struct msm_otg *motg)
1932{
Heikki Krogerus1d4c9292012-02-13 13:24:09 +02001933 struct usb_phy *phy = &motg->phy;
Pavankumar Kondetid8608522011-05-04 10:19:47 +05301934 u32 chg_det;
1935 bool ret = false;
1936
1937 switch (motg->pdata->phy_type) {
1938 case CI_45NM_INTEGRATED_PHY:
Heikki Krogerus1d4c9292012-02-13 13:24:09 +02001939 chg_det = ulpi_read(phy, 0x34);
Pavankumar Kondetid8608522011-05-04 10:19:47 +05301940 ret = chg_det & (1 << 4);
1941 break;
1942 case SNPS_28NM_INTEGRATED_PHY:
Heikki Krogerus1d4c9292012-02-13 13:24:09 +02001943 chg_det = ulpi_read(phy, 0x87);
Pavankumar Kondetid8608522011-05-04 10:19:47 +05301944 ret = chg_det & 1;
Pavankumar Kondeti9ec21d32012-05-07 15:50:23 +05301945 /* Turn off VDP_SRC */
1946 ulpi_write(phy, 0x3, 0x86);
1947 msleep(20);
Pavankumar Kondetid8608522011-05-04 10:19:47 +05301948 break;
1949 default:
1950 break;
1951 }
1952 return ret;
1953}
1954
1955static void msm_chg_enable_primary_det(struct msm_otg *motg)
1956{
Heikki Krogerus1d4c9292012-02-13 13:24:09 +02001957 struct usb_phy *phy = &motg->phy;
Pavankumar Kondetid8608522011-05-04 10:19:47 +05301958 u32 chg_det;
1959
1960 switch (motg->pdata->phy_type) {
1961 case CI_45NM_INTEGRATED_PHY:
Heikki Krogerus1d4c9292012-02-13 13:24:09 +02001962 chg_det = ulpi_read(phy, 0x34);
Pavankumar Kondetid8608522011-05-04 10:19:47 +05301963 /* enable chg detection */
1964 chg_det &= ~(1 << 0);
Heikki Krogerus1d4c9292012-02-13 13:24:09 +02001965 ulpi_write(phy, chg_det, 0x34);
Pavankumar Kondetid8608522011-05-04 10:19:47 +05301966 break;
1967 case SNPS_28NM_INTEGRATED_PHY:
1968 /*
1969 * Configure DP as current source, DM as current sink
1970 * and enable battery charging comparators.
1971 */
Heikki Krogerus1d4c9292012-02-13 13:24:09 +02001972 ulpi_write(phy, 0x2, 0x85);
1973 ulpi_write(phy, 0x1, 0x85);
Pavankumar Kondetid8608522011-05-04 10:19:47 +05301974 break;
1975 default:
1976 break;
1977 }
1978}
1979
1980static bool msm_chg_check_dcd(struct msm_otg *motg)
1981{
Heikki Krogerus1d4c9292012-02-13 13:24:09 +02001982 struct usb_phy *phy = &motg->phy;
Pavankumar Kondetid8608522011-05-04 10:19:47 +05301983 u32 line_state;
1984 bool ret = false;
1985
1986 switch (motg->pdata->phy_type) {
1987 case CI_45NM_INTEGRATED_PHY:
Heikki Krogerus1d4c9292012-02-13 13:24:09 +02001988 line_state = ulpi_read(phy, 0x15);
Pavankumar Kondetid8608522011-05-04 10:19:47 +05301989 ret = !(line_state & 1);
1990 break;
1991 case SNPS_28NM_INTEGRATED_PHY:
Heikki Krogerus1d4c9292012-02-13 13:24:09 +02001992 line_state = ulpi_read(phy, 0x87);
Pavankumar Kondetid8608522011-05-04 10:19:47 +05301993 ret = line_state & 2;
1994 break;
1995 default:
1996 break;
1997 }
1998 return ret;
1999}
2000
2001static void msm_chg_disable_dcd(struct msm_otg *motg)
2002{
Heikki Krogerus1d4c9292012-02-13 13:24:09 +02002003 struct usb_phy *phy = &motg->phy;
Pavankumar Kondetid8608522011-05-04 10:19:47 +05302004 u32 chg_det;
2005
2006 switch (motg->pdata->phy_type) {
2007 case CI_45NM_INTEGRATED_PHY:
Heikki Krogerus1d4c9292012-02-13 13:24:09 +02002008 chg_det = ulpi_read(phy, 0x34);
Pavankumar Kondetid8608522011-05-04 10:19:47 +05302009 chg_det &= ~(1 << 5);
Heikki Krogerus1d4c9292012-02-13 13:24:09 +02002010 ulpi_write(phy, chg_det, 0x34);
Pavankumar Kondetid8608522011-05-04 10:19:47 +05302011 break;
2012 case SNPS_28NM_INTEGRATED_PHY:
Heikki Krogerus1d4c9292012-02-13 13:24:09 +02002013 ulpi_write(phy, 0x10, 0x86);
Pavankumar Kondetid8608522011-05-04 10:19:47 +05302014 break;
2015 default:
2016 break;
2017 }
2018}
2019
2020static void msm_chg_enable_dcd(struct msm_otg *motg)
2021{
Heikki Krogerus1d4c9292012-02-13 13:24:09 +02002022 struct usb_phy *phy = &motg->phy;
Pavankumar Kondetid8608522011-05-04 10:19:47 +05302023 u32 chg_det;
2024
2025 switch (motg->pdata->phy_type) {
2026 case CI_45NM_INTEGRATED_PHY:
Heikki Krogerus1d4c9292012-02-13 13:24:09 +02002027 chg_det = ulpi_read(phy, 0x34);
Pavankumar Kondetid8608522011-05-04 10:19:47 +05302028 /* Turn on D+ current source */
2029 chg_det |= (1 << 5);
Heikki Krogerus1d4c9292012-02-13 13:24:09 +02002030 ulpi_write(phy, chg_det, 0x34);
Pavankumar Kondetid8608522011-05-04 10:19:47 +05302031 break;
2032 case SNPS_28NM_INTEGRATED_PHY:
2033 /* Data contact detection enable */
Heikki Krogerus1d4c9292012-02-13 13:24:09 +02002034 ulpi_write(phy, 0x10, 0x85);
Pavankumar Kondetid8608522011-05-04 10:19:47 +05302035 break;
2036 default:
2037 break;
2038 }
2039}
2040
2041static void msm_chg_block_on(struct msm_otg *motg)
2042{
Heikki Krogerus1d4c9292012-02-13 13:24:09 +02002043 struct usb_phy *phy = &motg->phy;
Pavankumar Kondetid8608522011-05-04 10:19:47 +05302044 u32 func_ctrl, chg_det;
2045
2046 /* put the controller in non-driving mode */
Heikki Krogerus1d4c9292012-02-13 13:24:09 +02002047 func_ctrl = ulpi_read(phy, ULPI_FUNC_CTRL);
Pavankumar Kondetid8608522011-05-04 10:19:47 +05302048 func_ctrl &= ~ULPI_FUNC_CTRL_OPMODE_MASK;
2049 func_ctrl |= ULPI_FUNC_CTRL_OPMODE_NONDRIVING;
Heikki Krogerus1d4c9292012-02-13 13:24:09 +02002050 ulpi_write(phy, func_ctrl, ULPI_FUNC_CTRL);
Pavankumar Kondetid8608522011-05-04 10:19:47 +05302051
2052 switch (motg->pdata->phy_type) {
2053 case CI_45NM_INTEGRATED_PHY:
Heikki Krogerus1d4c9292012-02-13 13:24:09 +02002054 chg_det = ulpi_read(phy, 0x34);
Pavankumar Kondetid8608522011-05-04 10:19:47 +05302055 /* control chg block via ULPI */
2056 chg_det &= ~(1 << 3);
Heikki Krogerus1d4c9292012-02-13 13:24:09 +02002057 ulpi_write(phy, chg_det, 0x34);
Pavankumar Kondetid8608522011-05-04 10:19:47 +05302058 /* Turn on chg detect block */
2059 chg_det &= ~(1 << 1);
Heikki Krogerus1d4c9292012-02-13 13:24:09 +02002060 ulpi_write(phy, chg_det, 0x34);
Pavankumar Kondetid8608522011-05-04 10:19:47 +05302061 udelay(20);
2062 break;
2063 case SNPS_28NM_INTEGRATED_PHY:
Pavankumar Kondeti768dcb82012-10-05 13:21:45 +05302064 /* disable DP and DM pull down resistors */
2065 ulpi_write(phy, 0x6, 0xC);
Pavankumar Kondetid8608522011-05-04 10:19:47 +05302066 /* Clear charger detecting control bits */
Steve Mucklef132c6c2012-06-06 18:30:57 -07002067 ulpi_write(phy, 0x1F, 0x86);
Pavankumar Kondetid8608522011-05-04 10:19:47 +05302068 /* Clear alt interrupt latch and enable bits */
Heikki Krogerus1d4c9292012-02-13 13:24:09 +02002069 ulpi_write(phy, 0x1F, 0x92);
2070 ulpi_write(phy, 0x1F, 0x95);
Pavankumar Kondetid8608522011-05-04 10:19:47 +05302071 udelay(100);
2072 break;
2073 default:
2074 break;
2075 }
2076}
2077
2078static void msm_chg_block_off(struct msm_otg *motg)
2079{
Heikki Krogerus1d4c9292012-02-13 13:24:09 +02002080 struct usb_phy *phy = &motg->phy;
Pavankumar Kondetid8608522011-05-04 10:19:47 +05302081 u32 func_ctrl, chg_det;
2082
2083 switch (motg->pdata->phy_type) {
2084 case CI_45NM_INTEGRATED_PHY:
Heikki Krogerus1d4c9292012-02-13 13:24:09 +02002085 chg_det = ulpi_read(phy, 0x34);
Pavankumar Kondetid8608522011-05-04 10:19:47 +05302086 /* Turn off charger block */
2087 chg_det |= ~(1 << 1);
Heikki Krogerus1d4c9292012-02-13 13:24:09 +02002088 ulpi_write(phy, chg_det, 0x34);
Pavankumar Kondetid8608522011-05-04 10:19:47 +05302089 break;
2090 case SNPS_28NM_INTEGRATED_PHY:
2091 /* Clear charger detecting control bits */
Heikki Krogerus1d4c9292012-02-13 13:24:09 +02002092 ulpi_write(phy, 0x3F, 0x86);
Pavankumar Kondetid8608522011-05-04 10:19:47 +05302093 /* Clear alt interrupt latch and enable bits */
Heikki Krogerus1d4c9292012-02-13 13:24:09 +02002094 ulpi_write(phy, 0x1F, 0x92);
2095 ulpi_write(phy, 0x1F, 0x95);
Pavankumar Kondetid8608522011-05-04 10:19:47 +05302096 break;
2097 default:
2098 break;
2099 }
2100
2101 /* put the controller in normal mode */
Heikki Krogerus1d4c9292012-02-13 13:24:09 +02002102 func_ctrl = ulpi_read(phy, ULPI_FUNC_CTRL);
Pavankumar Kondetid8608522011-05-04 10:19:47 +05302103 func_ctrl &= ~ULPI_FUNC_CTRL_OPMODE_MASK;
2104 func_ctrl |= ULPI_FUNC_CTRL_OPMODE_NORMAL;
Heikki Krogerus1d4c9292012-02-13 13:24:09 +02002105 ulpi_write(phy, func_ctrl, ULPI_FUNC_CTRL);
Pavankumar Kondetid8608522011-05-04 10:19:47 +05302106}
2107
Anji jonnalad270e2d2011-08-09 11:28:32 +05302108static const char *chg_to_string(enum usb_chg_type chg_type)
2109{
2110 switch (chg_type) {
2111 case USB_SDP_CHARGER: return "USB_SDP_CHARGER";
2112 case USB_DCP_CHARGER: return "USB_DCP_CHARGER";
2113 case USB_CDP_CHARGER: return "USB_CDP_CHARGER";
2114 case USB_ACA_A_CHARGER: return "USB_ACA_A_CHARGER";
2115 case USB_ACA_B_CHARGER: return "USB_ACA_B_CHARGER";
2116 case USB_ACA_C_CHARGER: return "USB_ACA_C_CHARGER";
2117 case USB_ACA_DOCK_CHARGER: return "USB_ACA_DOCK_CHARGER";
Pavankumar Kondeti9ec21d32012-05-07 15:50:23 +05302118 case USB_PROPRIETARY_CHARGER: return "USB_PROPRIETARY_CHARGER";
Anji jonnalad270e2d2011-08-09 11:28:32 +05302119 default: return "INVALID_CHARGER";
2120 }
2121}
2122
Pavankumar Kondetid8608522011-05-04 10:19:47 +05302123#define MSM_CHG_DCD_POLL_TIME (100 * HZ/1000) /* 100 msec */
2124#define MSM_CHG_DCD_MAX_RETRIES 6 /* Tdcd_tmout = 6 * 100 msec */
Pavankumar Kondeti283146f2012-01-12 12:51:19 +05302125#define MSM_CHG_PRIMARY_DET_TIME (50 * HZ/1000) /* TVDPSRC_ON */
2126#define MSM_CHG_SECONDARY_DET_TIME (50 * HZ/1000) /* TVDMSRC_ON */
Pavankumar Kondetid8608522011-05-04 10:19:47 +05302127static void msm_chg_detect_work(struct work_struct *w)
2128{
2129 struct msm_otg *motg = container_of(w, struct msm_otg, chg_work.work);
Heikki Krogerus1d4c9292012-02-13 13:24:09 +02002130 struct usb_phy *phy = &motg->phy;
Pavankumar Kondeti2d09e5f2012-01-16 08:56:57 +05302131 bool is_dcd = false, tmout, vout, is_aca;
Pavankumar Kondeti9ec21d32012-05-07 15:50:23 +05302132 u32 line_state, dm_vlgc;
Pavankumar Kondetid8608522011-05-04 10:19:47 +05302133 unsigned long delay;
2134
Heikki Krogerus1d4c9292012-02-13 13:24:09 +02002135 dev_dbg(phy->dev, "chg detection work\n");
Pavankumar Kondeti2aec9f32012-06-13 09:06:03 +05302136
2137 if (test_bit(MHL, &motg->inputs)) {
2138 dev_dbg(phy->dev, "detected MHL, escape chg detection work\n");
2139 return;
2140 }
2141
Pavankumar Kondetid8608522011-05-04 10:19:47 +05302142 switch (motg->chg_state) {
2143 case USB_CHG_STATE_UNDEFINED:
Pavankumar Kondetid8608522011-05-04 10:19:47 +05302144 msm_chg_block_on(motg);
Pavankumar Kondeti768dcb82012-10-05 13:21:45 +05302145 msm_chg_enable_dcd(motg);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002146 msm_chg_enable_aca_det(motg);
Pavankumar Kondetid8608522011-05-04 10:19:47 +05302147 motg->chg_state = USB_CHG_STATE_WAIT_FOR_DCD;
2148 motg->dcd_retries = 0;
2149 delay = MSM_CHG_DCD_POLL_TIME;
2150 break;
2151 case USB_CHG_STATE_WAIT_FOR_DCD:
Pavankumar Kondeti2aec9f32012-06-13 09:06:03 +05302152 if (msm_chg_mhl_detect(motg)) {
2153 msm_chg_block_off(motg);
2154 motg->chg_state = USB_CHG_STATE_DETECTED;
2155 motg->chg_type = USB_INVALID_CHARGER;
2156 queue_work(system_nrt_wq, &motg->sm_work);
2157 return;
2158 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002159 is_aca = msm_chg_aca_detect(motg);
2160 if (is_aca) {
2161 /*
2162 * ID_A can be ACA dock too. continue
2163 * primary detection after DCD.
2164 */
2165 if (test_bit(ID_A, &motg->inputs)) {
2166 motg->chg_state = USB_CHG_STATE_WAIT_FOR_DCD;
2167 } else {
2168 delay = 0;
2169 break;
2170 }
2171 }
Pavankumar Kondeti768dcb82012-10-05 13:21:45 +05302172 is_dcd = msm_chg_check_dcd(motg);
Pavankumar Kondetid8608522011-05-04 10:19:47 +05302173 tmout = ++motg->dcd_retries == MSM_CHG_DCD_MAX_RETRIES;
2174 if (is_dcd || tmout) {
Pavankumar Kondeti768dcb82012-10-05 13:21:45 +05302175 msm_chg_disable_dcd(motg);
Pavankumar Kondetid8608522011-05-04 10:19:47 +05302176 msm_chg_enable_primary_det(motg);
2177 delay = MSM_CHG_PRIMARY_DET_TIME;
2178 motg->chg_state = USB_CHG_STATE_DCD_DONE;
2179 } else {
2180 delay = MSM_CHG_DCD_POLL_TIME;
2181 }
2182 break;
2183 case USB_CHG_STATE_DCD_DONE:
2184 vout = msm_chg_check_primary_det(motg);
Pavankumar Kondeti9ec21d32012-05-07 15:50:23 +05302185 line_state = readl_relaxed(USB_PORTSC) & PORTSC_LS;
2186 dm_vlgc = line_state & PORTSC_LS_DM;
2187 if (vout && !dm_vlgc) { /* VDAT_REF < DM < VLGC */
Pavankumar Kondetiaa449e12011-11-04 11:09:26 +05302188 if (test_bit(ID_A, &motg->inputs)) {
2189 motg->chg_type = USB_ACA_DOCK_CHARGER;
2190 motg->chg_state = USB_CHG_STATE_DETECTED;
2191 delay = 0;
2192 break;
2193 }
Pavankumar Kondeti9ec21d32012-05-07 15:50:23 +05302194 if (line_state) { /* DP > VLGC */
2195 motg->chg_type = USB_PROPRIETARY_CHARGER;
2196 motg->chg_state = USB_CHG_STATE_DETECTED;
2197 delay = 0;
2198 } else {
2199 msm_chg_enable_secondary_det(motg);
2200 delay = MSM_CHG_SECONDARY_DET_TIME;
2201 motg->chg_state = USB_CHG_STATE_PRIMARY_DONE;
2202 }
2203 } else { /* DM < VDAT_REF || DM > VLGC */
Pavankumar Kondetiaa449e12011-11-04 11:09:26 +05302204 if (test_bit(ID_A, &motg->inputs)) {
2205 motg->chg_type = USB_ACA_A_CHARGER;
2206 motg->chg_state = USB_CHG_STATE_DETECTED;
2207 delay = 0;
2208 break;
2209 }
Pavankumar Kondeti9ec21d32012-05-07 15:50:23 +05302210
2211 if (line_state) /* DP > VLGC or/and DM > VLGC */
2212 motg->chg_type = USB_PROPRIETARY_CHARGER;
2213 else
2214 motg->chg_type = USB_SDP_CHARGER;
2215
Pavankumar Kondetid8608522011-05-04 10:19:47 +05302216 motg->chg_state = USB_CHG_STATE_DETECTED;
2217 delay = 0;
2218 }
2219 break;
2220 case USB_CHG_STATE_PRIMARY_DONE:
2221 vout = msm_chg_check_secondary_det(motg);
2222 if (vout)
2223 motg->chg_type = USB_DCP_CHARGER;
2224 else
2225 motg->chg_type = USB_CDP_CHARGER;
2226 motg->chg_state = USB_CHG_STATE_SECONDARY_DONE;
2227 /* fall through */
2228 case USB_CHG_STATE_SECONDARY_DONE:
2229 motg->chg_state = USB_CHG_STATE_DETECTED;
2230 case USB_CHG_STATE_DETECTED:
2231 msm_chg_block_off(motg);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002232 msm_chg_enable_aca_det(motg);
Vijayavardhan Vennapusaa3152032012-03-05 16:29:30 +05302233 /*
2234 * Spurious interrupt is seen after enabling ACA detection
2235 * due to which charger detection fails in case of PET.
2236 * Add delay of 100 microsec to avoid that.
2237 */
2238 udelay(100);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002239 msm_chg_enable_aca_intr(motg);
Steve Mucklef132c6c2012-06-06 18:30:57 -07002240 dev_dbg(phy->dev, "chg_type = %s\n",
Anji jonnalad270e2d2011-08-09 11:28:32 +05302241 chg_to_string(motg->chg_type));
Vijayavardhan Vennapusaa3152032012-03-05 16:29:30 +05302242 queue_work(system_nrt_wq, &motg->sm_work);
Pavankumar Kondetid8608522011-05-04 10:19:47 +05302243 return;
2244 default:
2245 return;
2246 }
2247
Vijayavardhan Vennapusaa3152032012-03-05 16:29:30 +05302248 queue_delayed_work(system_nrt_wq, &motg->chg_work, delay);
Pavankumar Kondetid8608522011-05-04 10:19:47 +05302249}
2250
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05302251/*
2252 * We support OTG, Peripheral only and Host only configurations. In case
2253 * of OTG, mode switch (host-->peripheral/peripheral-->host) can happen
2254 * via Id pin status or user request (debugfs). Id/BSV interrupts are not
2255 * enabled when switch is controlled by user and default mode is supplied
2256 * by board file, which can be changed by userspace later.
2257 */
2258static void msm_otg_init_sm(struct msm_otg *motg)
2259{
2260 struct msm_otg_platform_data *pdata = motg->pdata;
2261 u32 otgsc = readl(USB_OTGSC);
2262
2263 switch (pdata->mode) {
2264 case USB_OTG:
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002265 if (pdata->otg_control == OTG_USER_CONTROL) {
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05302266 if (pdata->default_mode == USB_HOST) {
2267 clear_bit(ID, &motg->inputs);
2268 } else if (pdata->default_mode == USB_PERIPHERAL) {
2269 set_bit(ID, &motg->inputs);
2270 set_bit(B_SESS_VLD, &motg->inputs);
2271 } else {
2272 set_bit(ID, &motg->inputs);
2273 clear_bit(B_SESS_VLD, &motg->inputs);
2274 }
Pavankumar Kondeti4960f312011-12-06 15:46:14 +05302275 } else if (pdata->otg_control == OTG_PHY_CONTROL) {
Vijayavardhan Vennapusaa3152032012-03-05 16:29:30 +05302276 if (otgsc & OTGSC_ID) {
Pavankumar Kondeti4960f312011-12-06 15:46:14 +05302277 set_bit(ID, &motg->inputs);
Vijayavardhan Vennapusaa3152032012-03-05 16:29:30 +05302278 } else {
Pavankumar Kondeti4960f312011-12-06 15:46:14 +05302279 clear_bit(ID, &motg->inputs);
Vijayavardhan Vennapusaa3152032012-03-05 16:29:30 +05302280 set_bit(A_BUS_REQ, &motg->inputs);
2281 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002282 if (otgsc & OTGSC_BSV)
2283 set_bit(B_SESS_VLD, &motg->inputs);
2284 else
2285 clear_bit(B_SESS_VLD, &motg->inputs);
Pavankumar Kondeti4960f312011-12-06 15:46:14 +05302286 } else if (pdata->otg_control == OTG_PMIC_CONTROL) {
Pavankumar Kondeti0d81f312012-01-13 11:34:10 +05302287 if (pdata->pmic_id_irq) {
Stephen Boyd431771e2012-04-18 20:00:23 -07002288 unsigned long flags;
2289 local_irq_save(flags);
Pavankumar Kondeti0d81f312012-01-13 11:34:10 +05302290 if (irq_read_line(pdata->pmic_id_irq))
2291 set_bit(ID, &motg->inputs);
2292 else
2293 clear_bit(ID, &motg->inputs);
Stephen Boyd431771e2012-04-18 20:00:23 -07002294 local_irq_restore(flags);
Pavankumar Kondeti0d81f312012-01-13 11:34:10 +05302295 }
Pavankumar Kondeti4960f312011-12-06 15:46:14 +05302296 /*
2297 * VBUS initial state is reported after PMIC
2298 * driver initialization. Wait for it.
2299 */
2300 wait_for_completion(&pmic_vbus_init);
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05302301 }
2302 break;
2303 case USB_HOST:
2304 clear_bit(ID, &motg->inputs);
2305 break;
2306 case USB_PERIPHERAL:
2307 set_bit(ID, &motg->inputs);
Pavankumar Kondeti0d81f312012-01-13 11:34:10 +05302308 if (pdata->otg_control == OTG_PHY_CONTROL) {
2309 if (otgsc & OTGSC_BSV)
2310 set_bit(B_SESS_VLD, &motg->inputs);
2311 else
2312 clear_bit(B_SESS_VLD, &motg->inputs);
2313 } else if (pdata->otg_control == OTG_PMIC_CONTROL) {
2314 /*
2315 * VBUS initial state is reported after PMIC
2316 * driver initialization. Wait for it.
2317 */
2318 wait_for_completion(&pmic_vbus_init);
2319 }
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05302320 break;
2321 default:
2322 break;
2323 }
2324}
2325
2326static void msm_otg_sm_work(struct work_struct *w)
2327{
2328 struct msm_otg *motg = container_of(w, struct msm_otg, sm_work);
Heikki Krogerus1d4c9292012-02-13 13:24:09 +02002329 struct usb_otg *otg = motg->phy.otg;
Vijayavardhan Vennapusaa3152032012-03-05 16:29:30 +05302330 bool work = 0, srp_reqd;
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05302331
Steve Mucklef132c6c2012-06-06 18:30:57 -07002332 pm_runtime_resume(otg->phy->dev);
2333 pr_debug("%s work\n", otg_state_string(otg->phy->state));
Heikki Krogerus1d4c9292012-02-13 13:24:09 +02002334 switch (otg->phy->state) {
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05302335 case OTG_STATE_UNDEFINED:
Heikki Krogerus1d4c9292012-02-13 13:24:09 +02002336 msm_otg_reset(otg->phy);
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05302337 msm_otg_init_sm(motg);
David Keitel272ce522012-08-17 16:25:24 -07002338 if (!psy && legacy_power_supply) {
2339 psy = power_supply_get_by_name("usb");
2340
2341 if (!psy)
2342 pr_err("couldn't get usb power supply\n");
2343 }
2344
Heikki Krogerus1d4c9292012-02-13 13:24:09 +02002345 otg->phy->state = OTG_STATE_B_IDLE;
Pavankumar Kondeti8a379b42011-12-12 13:07:23 +05302346 if (!test_bit(B_SESS_VLD, &motg->inputs) &&
2347 test_bit(ID, &motg->inputs)) {
Steve Mucklef132c6c2012-06-06 18:30:57 -07002348 pm_runtime_put_noidle(otg->phy->dev);
2349 pm_runtime_suspend(otg->phy->dev);
Pavankumar Kondeti8a379b42011-12-12 13:07:23 +05302350 break;
2351 }
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05302352 /* FALL THROUGH */
2353 case OTG_STATE_B_IDLE:
Pavankumar Kondeti2aec9f32012-06-13 09:06:03 +05302354 if (test_bit(MHL, &motg->inputs)) {
2355 /* allow LPM */
2356 pm_runtime_put_noidle(otg->phy->dev);
2357 pm_runtime_suspend(otg->phy->dev);
2358 } else if ((!test_bit(ID, &motg->inputs) ||
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002359 test_bit(ID_A, &motg->inputs)) && otg->host) {
Vijayavardhan Vennapusaa3152032012-03-05 16:29:30 +05302360 pr_debug("!id || id_A\n");
Pavankumar Kondeti2aec9f32012-06-13 09:06:03 +05302361 if (msm_chg_mhl_detect(motg)) {
2362 work = 1;
2363 break;
2364 }
Vijayavardhan Vennapusaa3152032012-03-05 16:29:30 +05302365 clear_bit(B_BUS_REQ, &motg->inputs);
2366 set_bit(A_BUS_REQ, &motg->inputs);
Steve Mucklef132c6c2012-06-06 18:30:57 -07002367 otg->phy->state = OTG_STATE_A_IDLE;
Vijayavardhan Vennapusaa3152032012-03-05 16:29:30 +05302368 work = 1;
Pavankumar Kondetid8608522011-05-04 10:19:47 +05302369 } else if (test_bit(B_SESS_VLD, &motg->inputs)) {
Vijayavardhan Vennapusaa3152032012-03-05 16:29:30 +05302370 pr_debug("b_sess_vld\n");
Pavankumar Kondetid8608522011-05-04 10:19:47 +05302371 switch (motg->chg_state) {
2372 case USB_CHG_STATE_UNDEFINED:
2373 msm_chg_detect_work(&motg->chg_work.work);
2374 break;
2375 case USB_CHG_STATE_DETECTED:
2376 switch (motg->chg_type) {
2377 case USB_DCP_CHARGER:
Pavankumar Kondeti283146f2012-01-12 12:51:19 +05302378 /* Enable VDP_SRC */
Steve Mucklef132c6c2012-06-06 18:30:57 -07002379 ulpi_write(otg->phy, 0x2, 0x85);
Pavankumar Kondeti9ec21d32012-05-07 15:50:23 +05302380 /* fall through */
2381 case USB_PROPRIETARY_CHARGER:
Pavankumar Kondetid8608522011-05-04 10:19:47 +05302382 msm_otg_notify_charger(motg,
2383 IDEV_CHG_MAX);
Steve Mucklef132c6c2012-06-06 18:30:57 -07002384 pm_runtime_put_noidle(otg->phy->dev);
2385 pm_runtime_suspend(otg->phy->dev);
Pavankumar Kondetid8608522011-05-04 10:19:47 +05302386 break;
Pavankumar Kondetiaa449e12011-11-04 11:09:26 +05302387 case USB_ACA_B_CHARGER:
2388 msm_otg_notify_charger(motg,
2389 IDEV_ACA_CHG_MAX);
2390 /*
2391 * (ID_B --> ID_C) PHY_ALT interrupt can
2392 * not be detected in LPM.
2393 */
Pavankumar Kondetid8608522011-05-04 10:19:47 +05302394 break;
2395 case USB_CDP_CHARGER:
2396 msm_otg_notify_charger(motg,
2397 IDEV_CHG_MAX);
2398 msm_otg_start_peripheral(otg, 1);
Steve Mucklef132c6c2012-06-06 18:30:57 -07002399 otg->phy->state =
2400 OTG_STATE_B_PERIPHERAL;
Pavankumar Kondetid8608522011-05-04 10:19:47 +05302401 break;
Pavankumar Kondetiaa449e12011-11-04 11:09:26 +05302402 case USB_ACA_C_CHARGER:
2403 msm_otg_notify_charger(motg,
2404 IDEV_ACA_CHG_MAX);
2405 msm_otg_start_peripheral(otg, 1);
Steve Mucklef132c6c2012-06-06 18:30:57 -07002406 otg->phy->state =
2407 OTG_STATE_B_PERIPHERAL;
Pavankumar Kondetid8608522011-05-04 10:19:47 +05302408 break;
2409 case USB_SDP_CHARGER:
Pavankumar Kondetid8608522011-05-04 10:19:47 +05302410 msm_otg_start_peripheral(otg, 1);
Steve Mucklef132c6c2012-06-06 18:30:57 -07002411 otg->phy->state =
2412 OTG_STATE_B_PERIPHERAL;
Pavankumar Kondeti458d8792012-09-28 14:45:18 +05302413 mod_timer(&motg->chg_check_timer,
2414 CHG_RECHECK_DELAY);
Pavankumar Kondetid8608522011-05-04 10:19:47 +05302415 break;
2416 default:
2417 break;
2418 }
2419 break;
2420 default:
2421 break;
2422 }
Vijayavardhan Vennapusaa3152032012-03-05 16:29:30 +05302423 } else if (test_bit(B_BUS_REQ, &motg->inputs)) {
2424 pr_debug("b_sess_end && b_bus_req\n");
2425 if (msm_otg_start_srp(otg) < 0) {
2426 clear_bit(B_BUS_REQ, &motg->inputs);
2427 work = 1;
2428 break;
Pavankumar Kondetid8608522011-05-04 10:19:47 +05302429 }
Steve Mucklef132c6c2012-06-06 18:30:57 -07002430 otg->phy->state = OTG_STATE_B_SRP_INIT;
Vijayavardhan Vennapusaa3152032012-03-05 16:29:30 +05302431 msm_otg_start_timer(motg, TB_SRP_FAIL, B_SRP_FAIL);
2432 break;
Pavankumar Kondetid8608522011-05-04 10:19:47 +05302433 } else {
Vijayavardhan Vennapusaa3152032012-03-05 16:29:30 +05302434 pr_debug("chg_work cancel");
Pavankumar Kondeti458d8792012-09-28 14:45:18 +05302435 del_timer_sync(&motg->chg_check_timer);
2436 clear_bit(B_FALSE_SDP, &motg->inputs);
Pavankumar Kondetiaa449e12011-11-04 11:09:26 +05302437 cancel_delayed_work_sync(&motg->chg_work);
Pavankumar Kondetid8608522011-05-04 10:19:47 +05302438 motg->chg_state = USB_CHG_STATE_UNDEFINED;
2439 motg->chg_type = USB_INVALID_CHARGER;
Rajkumar Raghupathy18fd7132012-04-20 11:28:13 +05302440 msm_otg_notify_charger(motg, 0);
Steve Mucklef132c6c2012-06-06 18:30:57 -07002441 msm_otg_reset(otg->phy);
2442 pm_runtime_put_noidle(otg->phy->dev);
2443 pm_runtime_suspend(otg->phy->dev);
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05302444 }
2445 break;
Vijayavardhan Vennapusaa3152032012-03-05 16:29:30 +05302446 case OTG_STATE_B_SRP_INIT:
2447 if (!test_bit(ID, &motg->inputs) ||
2448 test_bit(ID_A, &motg->inputs) ||
2449 test_bit(ID_C, &motg->inputs) ||
2450 (test_bit(B_SESS_VLD, &motg->inputs) &&
2451 !test_bit(ID_B, &motg->inputs))) {
2452 pr_debug("!id || id_a/c || b_sess_vld+!id_b\n");
2453 msm_otg_del_timer(motg);
Steve Mucklef132c6c2012-06-06 18:30:57 -07002454 otg->phy->state = OTG_STATE_B_IDLE;
Vijayavardhan Vennapusaa3152032012-03-05 16:29:30 +05302455 /*
2456 * clear VBUSVLDEXTSEL and VBUSVLDEXT register
2457 * bits after SRP initiation.
2458 */
Steve Mucklef132c6c2012-06-06 18:30:57 -07002459 ulpi_write(otg->phy, 0x0, 0x98);
Vijayavardhan Vennapusaa3152032012-03-05 16:29:30 +05302460 work = 1;
2461 } else if (test_bit(B_SRP_FAIL, &motg->tmouts)) {
2462 pr_debug("b_srp_fail\n");
2463 pr_info("A-device did not respond to SRP\n");
2464 clear_bit(B_BUS_REQ, &motg->inputs);
2465 clear_bit(B_SRP_FAIL, &motg->tmouts);
2466 otg_send_event(OTG_EVENT_NO_RESP_FOR_SRP);
Steve Mucklef132c6c2012-06-06 18:30:57 -07002467 ulpi_write(otg->phy, 0x0, 0x98);
2468 otg->phy->state = OTG_STATE_B_IDLE;
Vijayavardhan Vennapusaa3152032012-03-05 16:29:30 +05302469 motg->b_last_se0_sess = jiffies;
2470 work = 1;
2471 }
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05302472 break;
2473 case OTG_STATE_B_PERIPHERAL:
Pavankumar Kondeti458d8792012-09-28 14:45:18 +05302474 if (test_bit(B_SESS_VLD, &motg->inputs) &&
2475 test_bit(B_FALSE_SDP, &motg->inputs)) {
2476 pr_debug("B_FALSE_SDP\n");
2477 msm_otg_start_peripheral(otg, 0);
2478 motg->chg_type = USB_DCP_CHARGER;
2479 clear_bit(B_FALSE_SDP, &motg->inputs);
2480 otg->phy->state = OTG_STATE_B_IDLE;
2481 work = 1;
2482 } else if (!test_bit(ID, &motg->inputs) ||
Vijayavardhan Vennapusaa3152032012-03-05 16:29:30 +05302483 test_bit(ID_A, &motg->inputs) ||
2484 test_bit(ID_B, &motg->inputs) ||
2485 !test_bit(B_SESS_VLD, &motg->inputs)) {
2486 pr_debug("!id || id_a/b || !b_sess_vld\n");
Pavankumar Kondetid8608522011-05-04 10:19:47 +05302487 motg->chg_state = USB_CHG_STATE_UNDEFINED;
2488 motg->chg_type = USB_INVALID_CHARGER;
Vijayavardhan Vennapusaa3152032012-03-05 16:29:30 +05302489 msm_otg_notify_charger(motg, 0);
2490 srp_reqd = otg->gadget->otg_srp_reqd;
2491 msm_otg_start_peripheral(otg, 0);
Vijayavardhan Vennapusaa3152032012-03-05 16:29:30 +05302492 if (test_bit(ID_B, &motg->inputs))
2493 clear_bit(ID_B, &motg->inputs);
2494 clear_bit(B_BUS_REQ, &motg->inputs);
Steve Mucklef132c6c2012-06-06 18:30:57 -07002495 otg->phy->state = OTG_STATE_B_IDLE;
Vijayavardhan Vennapusaa3152032012-03-05 16:29:30 +05302496 motg->b_last_se0_sess = jiffies;
2497 if (srp_reqd)
2498 msm_otg_start_timer(motg,
2499 TB_TST_SRP, B_TST_SRP);
2500 else
2501 work = 1;
2502 } else if (test_bit(B_BUS_REQ, &motg->inputs) &&
2503 otg->gadget->b_hnp_enable &&
2504 test_bit(A_BUS_SUSPEND, &motg->inputs)) {
2505 pr_debug("b_bus_req && b_hnp_en && a_bus_suspend\n");
2506 msm_otg_start_timer(motg, TB_ASE0_BRST, B_ASE0_BRST);
2507 /* D+ pullup should not be disconnected within 4msec
2508 * after A device suspends the bus. Otherwise PET will
2509 * fail the compliance test.
2510 */
2511 udelay(1000);
2512 msm_otg_start_peripheral(otg, 0);
Steve Mucklef132c6c2012-06-06 18:30:57 -07002513 otg->phy->state = OTG_STATE_B_WAIT_ACON;
Vijayavardhan Vennapusaa3152032012-03-05 16:29:30 +05302514 /*
2515 * start HCD even before A-device enable
2516 * pull-up to meet HNP timings.
2517 */
2518 otg->host->is_b_host = 1;
2519 msm_otg_start_host(otg, 1);
Amit Blay6fa647a2012-05-24 14:12:08 +03002520 } else if (test_bit(A_BUS_SUSPEND, &motg->inputs) &&
2521 test_bit(B_SESS_VLD, &motg->inputs)) {
2522 pr_debug("a_bus_suspend && b_sess_vld\n");
2523 if (motg->caps & ALLOW_LPM_ON_DEV_SUSPEND) {
Steve Mucklef132c6c2012-06-06 18:30:57 -07002524 pm_runtime_put_noidle(otg->phy->dev);
2525 pm_runtime_suspend(otg->phy->dev);
Amit Blay6fa647a2012-05-24 14:12:08 +03002526 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002527 } else if (test_bit(ID_C, &motg->inputs)) {
Pavankumar Kondetiaa449e12011-11-04 11:09:26 +05302528 msm_otg_notify_charger(motg, IDEV_ACA_CHG_MAX);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002529 }
2530 break;
Vijayavardhan Vennapusaa3152032012-03-05 16:29:30 +05302531 case OTG_STATE_B_WAIT_ACON:
2532 if (!test_bit(ID, &motg->inputs) ||
2533 test_bit(ID_A, &motg->inputs) ||
2534 test_bit(ID_B, &motg->inputs) ||
2535 !test_bit(B_SESS_VLD, &motg->inputs)) {
2536 pr_debug("!id || id_a/b || !b_sess_vld\n");
2537 msm_otg_del_timer(motg);
Pavankumar Kondetiaa449e12011-11-04 11:09:26 +05302538 /*
Vijayavardhan Vennapusaa3152032012-03-05 16:29:30 +05302539 * A-device is physically disconnected during
2540 * HNP. Remove HCD.
Pavankumar Kondetiaa449e12011-11-04 11:09:26 +05302541 */
Vijayavardhan Vennapusaa3152032012-03-05 16:29:30 +05302542 msm_otg_start_host(otg, 0);
2543 otg->host->is_b_host = 0;
2544
2545 clear_bit(B_BUS_REQ, &motg->inputs);
2546 clear_bit(A_BUS_SUSPEND, &motg->inputs);
2547 motg->b_last_se0_sess = jiffies;
Heikki Krogerus1d4c9292012-02-13 13:24:09 +02002548 otg->phy->state = OTG_STATE_B_IDLE;
2549 msm_otg_reset(otg->phy);
Vijayavardhan Vennapusaa3152032012-03-05 16:29:30 +05302550 work = 1;
2551 } else if (test_bit(A_CONN, &motg->inputs)) {
2552 pr_debug("a_conn\n");
2553 clear_bit(A_BUS_SUSPEND, &motg->inputs);
Steve Mucklef132c6c2012-06-06 18:30:57 -07002554 otg->phy->state = OTG_STATE_B_HOST;
Vijayavardhan Vennapusaa3152032012-03-05 16:29:30 +05302555 /*
2556 * PET disconnects D+ pullup after reset is generated
2557 * by B device in B_HOST role which is not detected by
2558 * B device. As workaorund , start timer of 300msec
2559 * and stop timer if A device is enumerated else clear
2560 * A_CONN.
2561 */
2562 msm_otg_start_timer(motg, TB_TST_CONFIG,
2563 B_TST_CONFIG);
2564 } else if (test_bit(B_ASE0_BRST, &motg->tmouts)) {
2565 pr_debug("b_ase0_brst_tmout\n");
2566 pr_info("B HNP fail:No response from A device\n");
2567 msm_otg_start_host(otg, 0);
Steve Mucklef132c6c2012-06-06 18:30:57 -07002568 msm_otg_reset(otg->phy);
Vijayavardhan Vennapusaa3152032012-03-05 16:29:30 +05302569 otg->host->is_b_host = 0;
2570 clear_bit(B_ASE0_BRST, &motg->tmouts);
2571 clear_bit(A_BUS_SUSPEND, &motg->inputs);
2572 clear_bit(B_BUS_REQ, &motg->inputs);
2573 otg_send_event(OTG_EVENT_HNP_FAILED);
Steve Mucklef132c6c2012-06-06 18:30:57 -07002574 otg->phy->state = OTG_STATE_B_IDLE;
Vijayavardhan Vennapusaa3152032012-03-05 16:29:30 +05302575 work = 1;
2576 } else if (test_bit(ID_C, &motg->inputs)) {
2577 msm_otg_notify_charger(motg, IDEV_ACA_CHG_MAX);
2578 }
2579 break;
2580 case OTG_STATE_B_HOST:
2581 if (!test_bit(B_BUS_REQ, &motg->inputs) ||
2582 !test_bit(A_CONN, &motg->inputs) ||
2583 !test_bit(B_SESS_VLD, &motg->inputs)) {
2584 pr_debug("!b_bus_req || !a_conn || !b_sess_vld\n");
2585 clear_bit(A_CONN, &motg->inputs);
2586 clear_bit(B_BUS_REQ, &motg->inputs);
2587 msm_otg_start_host(otg, 0);
2588 otg->host->is_b_host = 0;
Steve Mucklef132c6c2012-06-06 18:30:57 -07002589 otg->phy->state = OTG_STATE_B_IDLE;
2590 msm_otg_reset(otg->phy);
Vijayavardhan Vennapusaa3152032012-03-05 16:29:30 +05302591 work = 1;
2592 } else if (test_bit(ID_C, &motg->inputs)) {
2593 msm_otg_notify_charger(motg, IDEV_ACA_CHG_MAX);
2594 }
2595 break;
2596 case OTG_STATE_A_IDLE:
2597 otg->default_a = 1;
2598 if (test_bit(ID, &motg->inputs) &&
2599 !test_bit(ID_A, &motg->inputs)) {
2600 pr_debug("id && !id_a\n");
2601 otg->default_a = 0;
2602 clear_bit(A_BUS_DROP, &motg->inputs);
Steve Mucklef132c6c2012-06-06 18:30:57 -07002603 otg->phy->state = OTG_STATE_B_IDLE;
Vijayavardhan Vennapusaa3152032012-03-05 16:29:30 +05302604 del_timer_sync(&motg->id_timer);
2605 msm_otg_link_reset(motg);
2606 msm_chg_enable_aca_intr(motg);
2607 msm_otg_notify_charger(motg, 0);
2608 work = 1;
2609 } else if (!test_bit(A_BUS_DROP, &motg->inputs) &&
2610 (test_bit(A_SRP_DET, &motg->inputs) ||
2611 test_bit(A_BUS_REQ, &motg->inputs))) {
2612 pr_debug("!a_bus_drop && (a_srp_det || a_bus_req)\n");
2613
2614 clear_bit(A_SRP_DET, &motg->inputs);
2615 /* Disable SRP detection */
2616 writel_relaxed((readl_relaxed(USB_OTGSC) &
2617 ~OTGSC_INTSTS_MASK) &
2618 ~OTGSC_DPIE, USB_OTGSC);
2619
Steve Mucklef132c6c2012-06-06 18:30:57 -07002620 otg->phy->state = OTG_STATE_A_WAIT_VRISE;
Vijayavardhan Vennapusaa3152032012-03-05 16:29:30 +05302621 /* VBUS should not be supplied before end of SRP pulse
2622 * generated by PET, if not complaince test fail.
2623 */
2624 usleep_range(10000, 12000);
2625 /* ACA: ID_A: Stop charging untill enumeration */
2626 if (test_bit(ID_A, &motg->inputs))
2627 msm_otg_notify_charger(motg, 0);
2628 else
2629 msm_hsusb_vbus_power(motg, 1);
2630 msm_otg_start_timer(motg, TA_WAIT_VRISE, A_WAIT_VRISE);
2631 } else {
2632 pr_debug("No session requested\n");
2633 clear_bit(A_BUS_DROP, &motg->inputs);
2634 if (test_bit(ID_A, &motg->inputs)) {
2635 msm_otg_notify_charger(motg,
2636 IDEV_ACA_CHG_MAX);
2637 } else if (!test_bit(ID, &motg->inputs)) {
2638 msm_otg_notify_charger(motg, 0);
2639 /*
2640 * A-device is not providing power on VBUS.
2641 * Enable SRP detection.
2642 */
2643 writel_relaxed(0x13, USB_USBMODE);
2644 writel_relaxed((readl_relaxed(USB_OTGSC) &
2645 ~OTGSC_INTSTS_MASK) |
2646 OTGSC_DPIE, USB_OTGSC);
2647 mb();
2648 }
2649 }
2650 break;
2651 case OTG_STATE_A_WAIT_VRISE:
2652 if ((test_bit(ID, &motg->inputs) &&
2653 !test_bit(ID_A, &motg->inputs)) ||
2654 test_bit(A_BUS_DROP, &motg->inputs) ||
2655 test_bit(A_WAIT_VRISE, &motg->tmouts)) {
2656 pr_debug("id || a_bus_drop || a_wait_vrise_tmout\n");
2657 clear_bit(A_BUS_REQ, &motg->inputs);
2658 msm_otg_del_timer(motg);
2659 msm_hsusb_vbus_power(motg, 0);
Steve Mucklef132c6c2012-06-06 18:30:57 -07002660 otg->phy->state = OTG_STATE_A_WAIT_VFALL;
Vijayavardhan Vennapusaa3152032012-03-05 16:29:30 +05302661 msm_otg_start_timer(motg, TA_WAIT_VFALL, A_WAIT_VFALL);
2662 } else if (test_bit(A_VBUS_VLD, &motg->inputs)) {
2663 pr_debug("a_vbus_vld\n");
Steve Mucklef132c6c2012-06-06 18:30:57 -07002664 otg->phy->state = OTG_STATE_A_WAIT_BCON;
Vijayavardhan Vennapusaa3152032012-03-05 16:29:30 +05302665 if (TA_WAIT_BCON > 0)
2666 msm_otg_start_timer(motg, TA_WAIT_BCON,
2667 A_WAIT_BCON);
2668 msm_otg_start_host(otg, 1);
2669 msm_chg_enable_aca_det(motg);
2670 msm_chg_disable_aca_intr(motg);
Chiranjeevi Velempati489a27c2012-03-29 09:47:17 +05302671 mod_timer(&motg->id_timer, ID_TIMER_FREQ);
Vijayavardhan Vennapusaa3152032012-03-05 16:29:30 +05302672 if (msm_chg_check_aca_intr(motg))
2673 work = 1;
2674 }
2675 break;
2676 case OTG_STATE_A_WAIT_BCON:
2677 if ((test_bit(ID, &motg->inputs) &&
2678 !test_bit(ID_A, &motg->inputs)) ||
2679 test_bit(A_BUS_DROP, &motg->inputs) ||
2680 test_bit(A_WAIT_BCON, &motg->tmouts)) {
2681 pr_debug("(id && id_a/b/c) || a_bus_drop ||"
2682 "a_wait_bcon_tmout\n");
2683 if (test_bit(A_WAIT_BCON, &motg->tmouts)) {
2684 pr_info("Device No Response\n");
2685 otg_send_event(OTG_EVENT_DEV_CONN_TMOUT);
2686 }
2687 msm_otg_del_timer(motg);
2688 clear_bit(A_BUS_REQ, &motg->inputs);
2689 clear_bit(B_CONN, &motg->inputs);
2690 msm_otg_start_host(otg, 0);
2691 /*
2692 * ACA: ID_A with NO accessory, just the A plug is
2693 * attached to ACA: Use IDCHG_MAX for charging
2694 */
2695 if (test_bit(ID_A, &motg->inputs))
2696 msm_otg_notify_charger(motg, IDEV_CHG_MIN);
2697 else
2698 msm_hsusb_vbus_power(motg, 0);
Steve Mucklef132c6c2012-06-06 18:30:57 -07002699 otg->phy->state = OTG_STATE_A_WAIT_VFALL;
Vijayavardhan Vennapusaa3152032012-03-05 16:29:30 +05302700 msm_otg_start_timer(motg, TA_WAIT_VFALL, A_WAIT_VFALL);
2701 } else if (!test_bit(A_VBUS_VLD, &motg->inputs)) {
2702 pr_debug("!a_vbus_vld\n");
2703 clear_bit(B_CONN, &motg->inputs);
2704 msm_otg_del_timer(motg);
2705 msm_otg_start_host(otg, 0);
Steve Mucklef132c6c2012-06-06 18:30:57 -07002706 otg->phy->state = OTG_STATE_A_VBUS_ERR;
2707 msm_otg_reset(otg->phy);
Vijayavardhan Vennapusaa3152032012-03-05 16:29:30 +05302708 } else if (test_bit(ID_A, &motg->inputs)) {
2709 msm_hsusb_vbus_power(motg, 0);
2710 } else if (!test_bit(A_BUS_REQ, &motg->inputs)) {
2711 /*
2712 * If TA_WAIT_BCON is infinite, we don;t
2713 * turn off VBUS. Enter low power mode.
2714 */
2715 if (TA_WAIT_BCON < 0)
Steve Mucklef132c6c2012-06-06 18:30:57 -07002716 pm_runtime_put_sync(otg->phy->dev);
Vijayavardhan Vennapusaa3152032012-03-05 16:29:30 +05302717 } else if (!test_bit(ID, &motg->inputs)) {
2718 msm_hsusb_vbus_power(motg, 1);
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05302719 }
2720 break;
2721 case OTG_STATE_A_HOST:
Vijayavardhan Vennapusaa3152032012-03-05 16:29:30 +05302722 if ((test_bit(ID, &motg->inputs) &&
2723 !test_bit(ID_A, &motg->inputs)) ||
2724 test_bit(A_BUS_DROP, &motg->inputs)) {
2725 pr_debug("id_a/b/c || a_bus_drop\n");
2726 clear_bit(B_CONN, &motg->inputs);
2727 clear_bit(A_BUS_REQ, &motg->inputs);
2728 msm_otg_del_timer(motg);
Steve Mucklef132c6c2012-06-06 18:30:57 -07002729 otg->phy->state = OTG_STATE_A_WAIT_VFALL;
Vijayavardhan Vennapusaa3152032012-03-05 16:29:30 +05302730 msm_otg_start_host(otg, 0);
2731 if (!test_bit(ID_A, &motg->inputs))
2732 msm_hsusb_vbus_power(motg, 0);
2733 msm_otg_start_timer(motg, TA_WAIT_VFALL, A_WAIT_VFALL);
2734 } else if (!test_bit(A_VBUS_VLD, &motg->inputs)) {
2735 pr_debug("!a_vbus_vld\n");
2736 clear_bit(B_CONN, &motg->inputs);
2737 msm_otg_del_timer(motg);
Steve Mucklef132c6c2012-06-06 18:30:57 -07002738 otg->phy->state = OTG_STATE_A_VBUS_ERR;
Vijayavardhan Vennapusaa3152032012-03-05 16:29:30 +05302739 msm_otg_start_host(otg, 0);
Heikki Krogerus1d4c9292012-02-13 13:24:09 +02002740 msm_otg_reset(otg->phy);
Vijayavardhan Vennapusaa3152032012-03-05 16:29:30 +05302741 } else if (!test_bit(A_BUS_REQ, &motg->inputs)) {
2742 /*
2743 * a_bus_req is de-asserted when root hub is
2744 * suspended or HNP is in progress.
2745 */
2746 pr_debug("!a_bus_req\n");
2747 msm_otg_del_timer(motg);
Steve Mucklef132c6c2012-06-06 18:30:57 -07002748 otg->phy->state = OTG_STATE_A_SUSPEND;
Vijayavardhan Vennapusaa3152032012-03-05 16:29:30 +05302749 if (otg->host->b_hnp_enable)
2750 msm_otg_start_timer(motg, TA_AIDL_BDIS,
2751 A_AIDL_BDIS);
2752 else
Steve Mucklef132c6c2012-06-06 18:30:57 -07002753 pm_runtime_put_sync(otg->phy->dev);
Vijayavardhan Vennapusaa3152032012-03-05 16:29:30 +05302754 } else if (!test_bit(B_CONN, &motg->inputs)) {
2755 pr_debug("!b_conn\n");
2756 msm_otg_del_timer(motg);
Steve Mucklef132c6c2012-06-06 18:30:57 -07002757 otg->phy->state = OTG_STATE_A_WAIT_BCON;
Vijayavardhan Vennapusaa3152032012-03-05 16:29:30 +05302758 if (TA_WAIT_BCON > 0)
2759 msm_otg_start_timer(motg, TA_WAIT_BCON,
2760 A_WAIT_BCON);
2761 if (msm_chg_check_aca_intr(motg))
2762 work = 1;
2763 } else if (test_bit(ID_A, &motg->inputs)) {
2764 msm_otg_del_timer(motg);
2765 msm_hsusb_vbus_power(motg, 0);
2766 if (motg->chg_type == USB_ACA_DOCK_CHARGER)
2767 msm_otg_notify_charger(motg,
2768 IDEV_ACA_CHG_MAX);
2769 else
2770 msm_otg_notify_charger(motg,
2771 IDEV_CHG_MIN - motg->mA_port);
2772 } else if (!test_bit(ID, &motg->inputs)) {
2773 motg->chg_state = USB_CHG_STATE_UNDEFINED;
2774 motg->chg_type = USB_INVALID_CHARGER;
2775 msm_otg_notify_charger(motg, 0);
2776 msm_hsusb_vbus_power(motg, 1);
2777 }
2778 break;
2779 case OTG_STATE_A_SUSPEND:
2780 if ((test_bit(ID, &motg->inputs) &&
2781 !test_bit(ID_A, &motg->inputs)) ||
2782 test_bit(A_BUS_DROP, &motg->inputs) ||
2783 test_bit(A_AIDL_BDIS, &motg->tmouts)) {
2784 pr_debug("id_a/b/c || a_bus_drop ||"
2785 "a_aidl_bdis_tmout\n");
2786 msm_otg_del_timer(motg);
2787 clear_bit(B_CONN, &motg->inputs);
Steve Mucklef132c6c2012-06-06 18:30:57 -07002788 otg->phy->state = OTG_STATE_A_WAIT_VFALL;
Vijayavardhan Vennapusaa3152032012-03-05 16:29:30 +05302789 msm_otg_start_host(otg, 0);
Steve Mucklef132c6c2012-06-06 18:30:57 -07002790 msm_otg_reset(otg->phy);
Vijayavardhan Vennapusaa3152032012-03-05 16:29:30 +05302791 if (!test_bit(ID_A, &motg->inputs))
2792 msm_hsusb_vbus_power(motg, 0);
2793 msm_otg_start_timer(motg, TA_WAIT_VFALL, A_WAIT_VFALL);
2794 } else if (!test_bit(A_VBUS_VLD, &motg->inputs)) {
2795 pr_debug("!a_vbus_vld\n");
2796 msm_otg_del_timer(motg);
2797 clear_bit(B_CONN, &motg->inputs);
Steve Mucklef132c6c2012-06-06 18:30:57 -07002798 otg->phy->state = OTG_STATE_A_VBUS_ERR;
Vijayavardhan Vennapusaa3152032012-03-05 16:29:30 +05302799 msm_otg_start_host(otg, 0);
Steve Mucklef132c6c2012-06-06 18:30:57 -07002800 msm_otg_reset(otg->phy);
Vijayavardhan Vennapusaa3152032012-03-05 16:29:30 +05302801 } else if (!test_bit(B_CONN, &motg->inputs) &&
2802 otg->host->b_hnp_enable) {
2803 pr_debug("!b_conn && b_hnp_enable");
Steve Mucklef132c6c2012-06-06 18:30:57 -07002804 otg->phy->state = OTG_STATE_A_PERIPHERAL;
Vijayavardhan Vennapusaa3152032012-03-05 16:29:30 +05302805 msm_otg_host_hnp_enable(otg, 1);
2806 otg->gadget->is_a_peripheral = 1;
2807 msm_otg_start_peripheral(otg, 1);
2808 } else if (!test_bit(B_CONN, &motg->inputs) &&
2809 !otg->host->b_hnp_enable) {
2810 pr_debug("!b_conn && !b_hnp_enable");
2811 /*
2812 * bus request is dropped during suspend.
2813 * acquire again for next device.
2814 */
2815 set_bit(A_BUS_REQ, &motg->inputs);
Steve Mucklef132c6c2012-06-06 18:30:57 -07002816 otg->phy->state = OTG_STATE_A_WAIT_BCON;
Vijayavardhan Vennapusaa3152032012-03-05 16:29:30 +05302817 if (TA_WAIT_BCON > 0)
2818 msm_otg_start_timer(motg, TA_WAIT_BCON,
2819 A_WAIT_BCON);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002820 } else if (test_bit(ID_A, &motg->inputs)) {
Mayank Ranae3926882011-12-26 09:47:54 +05302821 msm_hsusb_vbus_power(motg, 0);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002822 msm_otg_notify_charger(motg,
Vijayavardhan Vennapusaa3152032012-03-05 16:29:30 +05302823 IDEV_CHG_MIN - motg->mA_port);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002824 } else if (!test_bit(ID, &motg->inputs)) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002825 msm_otg_notify_charger(motg, 0);
Mayank Ranae3926882011-12-26 09:47:54 +05302826 msm_hsusb_vbus_power(motg, 1);
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05302827 }
2828 break;
Vijayavardhan Vennapusaa3152032012-03-05 16:29:30 +05302829 case OTG_STATE_A_PERIPHERAL:
2830 if ((test_bit(ID, &motg->inputs) &&
2831 !test_bit(ID_A, &motg->inputs)) ||
2832 test_bit(A_BUS_DROP, &motg->inputs)) {
2833 pr_debug("id _f/b/c || a_bus_drop\n");
2834 /* Clear BIDL_ADIS timer */
2835 msm_otg_del_timer(motg);
Steve Mucklef132c6c2012-06-06 18:30:57 -07002836 otg->phy->state = OTG_STATE_A_WAIT_VFALL;
Vijayavardhan Vennapusaa3152032012-03-05 16:29:30 +05302837 msm_otg_start_peripheral(otg, 0);
2838 otg->gadget->is_a_peripheral = 0;
2839 msm_otg_start_host(otg, 0);
Steve Mucklef132c6c2012-06-06 18:30:57 -07002840 msm_otg_reset(otg->phy);
Vijayavardhan Vennapusaa3152032012-03-05 16:29:30 +05302841 if (!test_bit(ID_A, &motg->inputs))
2842 msm_hsusb_vbus_power(motg, 0);
2843 msm_otg_start_timer(motg, TA_WAIT_VFALL, A_WAIT_VFALL);
2844 } else if (!test_bit(A_VBUS_VLD, &motg->inputs)) {
2845 pr_debug("!a_vbus_vld\n");
2846 /* Clear BIDL_ADIS timer */
2847 msm_otg_del_timer(motg);
Steve Mucklef132c6c2012-06-06 18:30:57 -07002848 otg->phy->state = OTG_STATE_A_VBUS_ERR;
Vijayavardhan Vennapusaa3152032012-03-05 16:29:30 +05302849 msm_otg_start_peripheral(otg, 0);
2850 otg->gadget->is_a_peripheral = 0;
2851 msm_otg_start_host(otg, 0);
2852 } else if (test_bit(A_BIDL_ADIS, &motg->tmouts)) {
2853 pr_debug("a_bidl_adis_tmout\n");
2854 msm_otg_start_peripheral(otg, 0);
2855 otg->gadget->is_a_peripheral = 0;
Steve Mucklef132c6c2012-06-06 18:30:57 -07002856 otg->phy->state = OTG_STATE_A_WAIT_BCON;
Vijayavardhan Vennapusaa3152032012-03-05 16:29:30 +05302857 set_bit(A_BUS_REQ, &motg->inputs);
2858 msm_otg_host_hnp_enable(otg, 0);
2859 if (TA_WAIT_BCON > 0)
2860 msm_otg_start_timer(motg, TA_WAIT_BCON,
2861 A_WAIT_BCON);
2862 } else if (test_bit(ID_A, &motg->inputs)) {
2863 msm_hsusb_vbus_power(motg, 0);
2864 msm_otg_notify_charger(motg,
2865 IDEV_CHG_MIN - motg->mA_port);
2866 } else if (!test_bit(ID, &motg->inputs)) {
2867 msm_otg_notify_charger(motg, 0);
2868 msm_hsusb_vbus_power(motg, 1);
2869 }
2870 break;
2871 case OTG_STATE_A_WAIT_VFALL:
2872 if (test_bit(A_WAIT_VFALL, &motg->tmouts)) {
2873 clear_bit(A_VBUS_VLD, &motg->inputs);
Steve Mucklef132c6c2012-06-06 18:30:57 -07002874 otg->phy->state = OTG_STATE_A_IDLE;
Vijayavardhan Vennapusaa3152032012-03-05 16:29:30 +05302875 work = 1;
2876 }
2877 break;
2878 case OTG_STATE_A_VBUS_ERR:
2879 if ((test_bit(ID, &motg->inputs) &&
2880 !test_bit(ID_A, &motg->inputs)) ||
2881 test_bit(A_BUS_DROP, &motg->inputs) ||
2882 test_bit(A_CLR_ERR, &motg->inputs)) {
Steve Mucklef132c6c2012-06-06 18:30:57 -07002883 otg->phy->state = OTG_STATE_A_WAIT_VFALL;
Vijayavardhan Vennapusaa3152032012-03-05 16:29:30 +05302884 if (!test_bit(ID_A, &motg->inputs))
2885 msm_hsusb_vbus_power(motg, 0);
2886 msm_otg_start_timer(motg, TA_WAIT_VFALL, A_WAIT_VFALL);
2887 motg->chg_state = USB_CHG_STATE_UNDEFINED;
2888 motg->chg_type = USB_INVALID_CHARGER;
2889 msm_otg_notify_charger(motg, 0);
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05302890 }
2891 break;
2892 default:
2893 break;
2894 }
Vijayavardhan Vennapusaa3152032012-03-05 16:29:30 +05302895 if (work)
2896 queue_work(system_nrt_wq, &motg->sm_work);
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05302897}
2898
Amit Blayd0fe07b2012-09-05 16:42:09 +03002899static void msm_otg_suspend_work(struct work_struct *w)
2900{
2901 struct msm_otg *motg =
2902 container_of(w, struct msm_otg, suspend_work.work);
2903 atomic_set(&motg->suspend_work_pending, 0);
2904 msm_otg_sm_work(&motg->sm_work);
2905}
2906
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05302907static irqreturn_t msm_otg_irq(int irq, void *data)
2908{
2909 struct msm_otg *motg = data;
Steve Mucklef132c6c2012-06-06 18:30:57 -07002910 struct usb_otg *otg = motg->phy.otg;
Vijayavardhan Vennapusaa3152032012-03-05 16:29:30 +05302911 u32 otgsc = 0, usbsts, pc;
2912 bool work = 0;
2913 irqreturn_t ret = IRQ_HANDLED;
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05302914
Pavankumar Kondeti87c01042010-12-07 17:53:58 +05302915 if (atomic_read(&motg->in_lpm)) {
Manu Gautamf8c45642012-08-10 10:20:56 -07002916 pr_debug("OTG IRQ: %d in LPM\n", irq);
Pavankumar Kondeti87c01042010-12-07 17:53:58 +05302917 disable_irq_nosync(irq);
Manu Gautamf8c45642012-08-10 10:20:56 -07002918 motg->async_int = irq;
Jack Phamc7edb172012-08-13 15:32:39 -07002919 if (!atomic_read(&motg->pm_suspended))
Steve Mucklef132c6c2012-06-06 18:30:57 -07002920 pm_request_resume(otg->phy->dev);
Pavankumar Kondeti87c01042010-12-07 17:53:58 +05302921 return IRQ_HANDLED;
2922 }
2923
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002924 usbsts = readl(USB_USBSTS);
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05302925 otgsc = readl(USB_OTGSC);
Vijayavardhan Vennapusaa3152032012-03-05 16:29:30 +05302926
2927 if (!(otgsc & OTG_OTGSTS_MASK) && !(usbsts & OTG_USBSTS_MASK))
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05302928 return IRQ_NONE;
2929
2930 if ((otgsc & OTGSC_IDIS) && (otgsc & OTGSC_IDIE)) {
Pavankumar Kondetiaa449e12011-11-04 11:09:26 +05302931 if (otgsc & OTGSC_ID) {
Vijayavardhan Vennapusaa3152032012-03-05 16:29:30 +05302932 pr_debug("Id set\n");
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05302933 set_bit(ID, &motg->inputs);
Pavankumar Kondetiaa449e12011-11-04 11:09:26 +05302934 } else {
Vijayavardhan Vennapusaa3152032012-03-05 16:29:30 +05302935 pr_debug("Id clear\n");
2936 /*
2937 * Assert a_bus_req to supply power on
2938 * VBUS when Micro/Mini-A cable is connected
2939 * with out user intervention.
2940 */
2941 set_bit(A_BUS_REQ, &motg->inputs);
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05302942 clear_bit(ID, &motg->inputs);
Pavankumar Kondetiaa449e12011-11-04 11:09:26 +05302943 msm_chg_enable_aca_det(motg);
2944 }
Vijayavardhan Vennapusaa3152032012-03-05 16:29:30 +05302945 writel_relaxed(otgsc, USB_OTGSC);
2946 work = 1;
2947 } else if (otgsc & OTGSC_DPIS) {
2948 pr_debug("DPIS detected\n");
2949 writel_relaxed(otgsc, USB_OTGSC);
2950 set_bit(A_SRP_DET, &motg->inputs);
2951 set_bit(A_BUS_REQ, &motg->inputs);
2952 work = 1;
2953 } else if (otgsc & OTGSC_BSVIS) {
2954 writel_relaxed(otgsc, USB_OTGSC);
2955 /*
2956 * BSV interrupt comes when operating as an A-device
2957 * (VBUS on/off).
2958 * But, handle BSV when charger is removed from ACA in ID_A
2959 */
Steve Mucklef132c6c2012-06-06 18:30:57 -07002960 if ((otg->phy->state >= OTG_STATE_A_IDLE) &&
Vijayavardhan Vennapusaa3152032012-03-05 16:29:30 +05302961 !test_bit(ID_A, &motg->inputs))
2962 return IRQ_HANDLED;
Pavankumar Kondetiaa449e12011-11-04 11:09:26 +05302963 if (otgsc & OTGSC_BSV) {
Vijayavardhan Vennapusaa3152032012-03-05 16:29:30 +05302964 pr_debug("BSV set\n");
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05302965 set_bit(B_SESS_VLD, &motg->inputs);
Pavankumar Kondetiaa449e12011-11-04 11:09:26 +05302966 } else {
Vijayavardhan Vennapusaa3152032012-03-05 16:29:30 +05302967 pr_debug("BSV clear\n");
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05302968 clear_bit(B_SESS_VLD, &motg->inputs);
Amit Blay6fa647a2012-05-24 14:12:08 +03002969 clear_bit(A_BUS_SUSPEND, &motg->inputs);
2970
Pavankumar Kondetiaa449e12011-11-04 11:09:26 +05302971 msm_chg_check_aca_intr(motg);
2972 }
Vijayavardhan Vennapusaa3152032012-03-05 16:29:30 +05302973 work = 1;
2974 } else if (usbsts & STS_PCI) {
2975 pc = readl_relaxed(USB_PORTSC);
2976 pr_debug("portsc = %x\n", pc);
2977 ret = IRQ_NONE;
2978 /*
2979 * HCD Acks PCI interrupt. We use this to switch
2980 * between different OTG states.
2981 */
2982 work = 1;
Steve Mucklef132c6c2012-06-06 18:30:57 -07002983 switch (otg->phy->state) {
Vijayavardhan Vennapusaa3152032012-03-05 16:29:30 +05302984 case OTG_STATE_A_SUSPEND:
2985 if (otg->host->b_hnp_enable && (pc & PORTSC_CSC) &&
2986 !(pc & PORTSC_CCS)) {
2987 pr_debug("B_CONN clear\n");
2988 clear_bit(B_CONN, &motg->inputs);
2989 msm_otg_del_timer(motg);
2990 }
2991 break;
2992 case OTG_STATE_A_PERIPHERAL:
2993 /*
2994 * A-peripheral observed activity on bus.
2995 * clear A_BIDL_ADIS timer.
2996 */
2997 msm_otg_del_timer(motg);
2998 work = 0;
2999 break;
3000 case OTG_STATE_B_WAIT_ACON:
3001 if ((pc & PORTSC_CSC) && (pc & PORTSC_CCS)) {
3002 pr_debug("A_CONN set\n");
3003 set_bit(A_CONN, &motg->inputs);
3004 /* Clear ASE0_BRST timer */
3005 msm_otg_del_timer(motg);
3006 }
3007 break;
3008 case OTG_STATE_B_HOST:
3009 if ((pc & PORTSC_CSC) && !(pc & PORTSC_CCS)) {
3010 pr_debug("A_CONN clear\n");
3011 clear_bit(A_CONN, &motg->inputs);
3012 msm_otg_del_timer(motg);
3013 }
3014 break;
3015 case OTG_STATE_A_WAIT_BCON:
3016 if (TA_WAIT_BCON < 0)
3017 set_bit(A_BUS_REQ, &motg->inputs);
3018 default:
3019 work = 0;
3020 break;
3021 }
3022 } else if (usbsts & STS_URI) {
3023 ret = IRQ_NONE;
Steve Mucklef132c6c2012-06-06 18:30:57 -07003024 switch (otg->phy->state) {
Vijayavardhan Vennapusaa3152032012-03-05 16:29:30 +05303025 case OTG_STATE_A_PERIPHERAL:
3026 /*
3027 * A-peripheral observed activity on bus.
3028 * clear A_BIDL_ADIS timer.
3029 */
3030 msm_otg_del_timer(motg);
3031 work = 0;
3032 break;
3033 default:
3034 work = 0;
3035 break;
3036 }
3037 } else if (usbsts & STS_SLI) {
3038 ret = IRQ_NONE;
3039 work = 0;
Steve Mucklef132c6c2012-06-06 18:30:57 -07003040 switch (otg->phy->state) {
Vijayavardhan Vennapusaa3152032012-03-05 16:29:30 +05303041 case OTG_STATE_B_PERIPHERAL:
3042 if (otg->gadget->b_hnp_enable) {
3043 set_bit(A_BUS_SUSPEND, &motg->inputs);
3044 set_bit(B_BUS_REQ, &motg->inputs);
3045 work = 1;
3046 }
3047 break;
3048 case OTG_STATE_A_PERIPHERAL:
3049 msm_otg_start_timer(motg, TA_BIDL_ADIS,
3050 A_BIDL_ADIS);
3051 break;
3052 default:
3053 break;
3054 }
3055 } else if ((usbsts & PHY_ALT_INT)) {
3056 writel_relaxed(PHY_ALT_INT, USB_USBSTS);
3057 if (msm_chg_check_aca_intr(motg))
3058 work = 1;
3059 ret = IRQ_HANDLED;
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05303060 }
Vijayavardhan Vennapusaa3152032012-03-05 16:29:30 +05303061 if (work)
3062 queue_work(system_nrt_wq, &motg->sm_work);
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05303063
Vijayavardhan Vennapusaa3152032012-03-05 16:29:30 +05303064 return ret;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003065}
3066
3067static void msm_otg_set_vbus_state(int online)
3068{
Pavankumar Kondeti4960f312011-12-06 15:46:14 +05303069 static bool init;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003070 struct msm_otg *motg = the_msm_otg;
Mayank Ranabaf31f42012-07-05 09:43:54 +05303071 struct usb_otg *otg = motg->phy.otg;
3072
3073 /* In A Host Mode, ignore received BSV interrupts */
3074 if (otg->phy->state >= OTG_STATE_A_IDLE)
3075 return;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003076
Pavankumar Kondeti4960f312011-12-06 15:46:14 +05303077 if (online) {
3078 pr_debug("PMIC: BSV set\n");
3079 set_bit(B_SESS_VLD, &motg->inputs);
3080 } else {
3081 pr_debug("PMIC: BSV clear\n");
3082 clear_bit(B_SESS_VLD, &motg->inputs);
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05303083 }
3084
Pavankumar Kondeti4960f312011-12-06 15:46:14 +05303085 if (!init) {
3086 init = true;
3087 complete(&pmic_vbus_init);
3088 pr_debug("PMIC: BSV init complete\n");
3089 return;
3090 }
3091
Pavankumar Kondeti2aec9f32012-06-13 09:06:03 +05303092 if (test_bit(MHL, &motg->inputs) ||
3093 mhl_det_in_progress) {
3094 pr_debug("PMIC: BSV interrupt ignored in MHL\n");
3095 return;
3096 }
3097
Jack Pham5ca279b2012-05-14 18:42:54 -07003098 if (atomic_read(&motg->pm_suspended))
3099 motg->sm_work_pending = true;
3100 else
3101 queue_work(system_nrt_wq, &motg->sm_work);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003102}
3103
Vijayavardhan Vennapusa68d55cf2012-06-27 20:06:12 +05303104static void msm_pmic_id_status_w(struct work_struct *w)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003105{
Vijayavardhan Vennapusa68d55cf2012-06-27 20:06:12 +05303106 struct msm_otg *motg = container_of(w, struct msm_otg,
3107 pmic_id_status_work.work);
3108 int work = 0;
3109 unsigned long flags;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003110
Vijayavardhan Vennapusa68d55cf2012-06-27 20:06:12 +05303111 local_irq_save(flags);
Pavankumar Kondeti4960f312011-12-06 15:46:14 +05303112 if (irq_read_line(motg->pdata->pmic_id_irq)) {
Vijayavardhan Vennapusa68d55cf2012-06-27 20:06:12 +05303113 if (!test_and_set_bit(ID, &motg->inputs)) {
3114 pr_debug("PMIC: ID set\n");
3115 work = 1;
3116 }
Pavankumar Kondeti4960f312011-12-06 15:46:14 +05303117 } else {
Vijayavardhan Vennapusa68d55cf2012-06-27 20:06:12 +05303118 if (test_and_clear_bit(ID, &motg->inputs)) {
3119 pr_debug("PMIC: ID clear\n");
3120 set_bit(A_BUS_REQ, &motg->inputs);
3121 work = 1;
3122 }
Pavankumar Kondeti4960f312011-12-06 15:46:14 +05303123 }
3124
Vijayavardhan Vennapusa68d55cf2012-06-27 20:06:12 +05303125 if (work && (motg->phy.state != OTG_STATE_UNDEFINED)) {
Jack Pham5ca279b2012-05-14 18:42:54 -07003126 if (atomic_read(&motg->pm_suspended))
3127 motg->sm_work_pending = true;
3128 else
3129 queue_work(system_nrt_wq, &motg->sm_work);
3130 }
Vijayavardhan Vennapusa68d55cf2012-06-27 20:06:12 +05303131 local_irq_restore(flags);
3132
3133}
3134
3135#define MSM_PMIC_ID_STATUS_DELAY 5 /* 5msec */
3136static irqreturn_t msm_pmic_id_irq(int irq, void *data)
3137{
3138 struct msm_otg *motg = data;
3139
Pavankumar Kondeti2aec9f32012-06-13 09:06:03 +05303140 if (test_bit(MHL, &motg->inputs) ||
3141 mhl_det_in_progress) {
3142 pr_debug("PMIC: Id interrupt ignored in MHL\n");
3143 return IRQ_HANDLED;
3144 }
3145
Vijayavardhan Vennapusa68d55cf2012-06-27 20:06:12 +05303146 if (!aca_id_turned_on)
3147 /*schedule delayed work for 5msec for ID line state to settle*/
3148 queue_delayed_work(system_nrt_wq, &motg->pmic_id_status_work,
3149 msecs_to_jiffies(MSM_PMIC_ID_STATUS_DELAY));
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003150
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05303151 return IRQ_HANDLED;
3152}
3153
3154static int msm_otg_mode_show(struct seq_file *s, void *unused)
3155{
3156 struct msm_otg *motg = s->private;
Steve Mucklef132c6c2012-06-06 18:30:57 -07003157 struct usb_phy *phy = &motg->phy;
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05303158
Steve Mucklef132c6c2012-06-06 18:30:57 -07003159 switch (phy->state) {
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05303160 case OTG_STATE_A_HOST:
3161 seq_printf(s, "host\n");
3162 break;
3163 case OTG_STATE_B_PERIPHERAL:
3164 seq_printf(s, "peripheral\n");
3165 break;
3166 default:
3167 seq_printf(s, "none\n");
3168 break;
3169 }
3170
3171 return 0;
3172}
3173
3174static int msm_otg_mode_open(struct inode *inode, struct file *file)
3175{
3176 return single_open(file, msm_otg_mode_show, inode->i_private);
3177}
3178
3179static ssize_t msm_otg_mode_write(struct file *file, const char __user *ubuf,
3180 size_t count, loff_t *ppos)
3181{
Pavankumar Kondetie2904ee2011-02-15 09:42:35 +05303182 struct seq_file *s = file->private_data;
3183 struct msm_otg *motg = s->private;
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05303184 char buf[16];
Steve Mucklef132c6c2012-06-06 18:30:57 -07003185 struct usb_phy *phy = &motg->phy;
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05303186 int status = count;
3187 enum usb_mode_type req_mode;
3188
3189 memset(buf, 0x00, sizeof(buf));
3190
3191 if (copy_from_user(&buf, ubuf, min_t(size_t, sizeof(buf) - 1, count))) {
3192 status = -EFAULT;
3193 goto out;
3194 }
3195
3196 if (!strncmp(buf, "host", 4)) {
3197 req_mode = USB_HOST;
3198 } else if (!strncmp(buf, "peripheral", 10)) {
3199 req_mode = USB_PERIPHERAL;
3200 } else if (!strncmp(buf, "none", 4)) {
3201 req_mode = USB_NONE;
3202 } else {
3203 status = -EINVAL;
3204 goto out;
3205 }
3206
3207 switch (req_mode) {
3208 case USB_NONE:
Steve Mucklef132c6c2012-06-06 18:30:57 -07003209 switch (phy->state) {
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05303210 case OTG_STATE_A_HOST:
3211 case OTG_STATE_B_PERIPHERAL:
3212 set_bit(ID, &motg->inputs);
3213 clear_bit(B_SESS_VLD, &motg->inputs);
3214 break;
3215 default:
3216 goto out;
3217 }
3218 break;
3219 case USB_PERIPHERAL:
Steve Mucklef132c6c2012-06-06 18:30:57 -07003220 switch (phy->state) {
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05303221 case OTG_STATE_B_IDLE:
3222 case OTG_STATE_A_HOST:
3223 set_bit(ID, &motg->inputs);
3224 set_bit(B_SESS_VLD, &motg->inputs);
3225 break;
3226 default:
3227 goto out;
3228 }
3229 break;
3230 case USB_HOST:
Steve Mucklef132c6c2012-06-06 18:30:57 -07003231 switch (phy->state) {
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05303232 case OTG_STATE_B_IDLE:
3233 case OTG_STATE_B_PERIPHERAL:
3234 clear_bit(ID, &motg->inputs);
3235 break;
3236 default:
3237 goto out;
3238 }
3239 break;
3240 default:
3241 goto out;
3242 }
3243
Steve Mucklef132c6c2012-06-06 18:30:57 -07003244 pm_runtime_resume(phy->dev);
Vijayavardhan Vennapusaa3152032012-03-05 16:29:30 +05303245 queue_work(system_nrt_wq, &motg->sm_work);
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05303246out:
3247 return status;
3248}
3249
3250const struct file_operations msm_otg_mode_fops = {
3251 .open = msm_otg_mode_open,
3252 .read = seq_read,
3253 .write = msm_otg_mode_write,
3254 .llseek = seq_lseek,
3255 .release = single_release,
3256};
3257
Chiranjeevi Velempatif9a11542012-03-28 18:18:34 +05303258static int msm_otg_show_otg_state(struct seq_file *s, void *unused)
3259{
3260 struct msm_otg *motg = s->private;
Steve Mucklef132c6c2012-06-06 18:30:57 -07003261 struct usb_phy *phy = &motg->phy;
Chiranjeevi Velempatif9a11542012-03-28 18:18:34 +05303262
Steve Mucklef132c6c2012-06-06 18:30:57 -07003263 seq_printf(s, "%s\n", otg_state_string(phy->state));
Chiranjeevi Velempatif9a11542012-03-28 18:18:34 +05303264 return 0;
3265}
3266
3267static int msm_otg_otg_state_open(struct inode *inode, struct file *file)
3268{
3269 return single_open(file, msm_otg_show_otg_state, inode->i_private);
3270}
3271
3272const struct file_operations msm_otg_state_fops = {
3273 .open = msm_otg_otg_state_open,
3274 .read = seq_read,
3275 .llseek = seq_lseek,
3276 .release = single_release,
3277};
3278
Anji jonnalad270e2d2011-08-09 11:28:32 +05303279static int msm_otg_show_chg_type(struct seq_file *s, void *unused)
3280{
3281 struct msm_otg *motg = s->private;
3282
Pavankumar Kondeti9ef69cb2011-12-12 14:18:22 +05303283 seq_printf(s, "%s\n", chg_to_string(motg->chg_type));
Anji jonnalad270e2d2011-08-09 11:28:32 +05303284 return 0;
3285}
3286
3287static int msm_otg_chg_open(struct inode *inode, struct file *file)
3288{
3289 return single_open(file, msm_otg_show_chg_type, inode->i_private);
3290}
3291
3292const struct file_operations msm_otg_chg_fops = {
3293 .open = msm_otg_chg_open,
3294 .read = seq_read,
3295 .llseek = seq_lseek,
3296 .release = single_release,
3297};
3298
Pavankumar Kondetiaa449e12011-11-04 11:09:26 +05303299static int msm_otg_aca_show(struct seq_file *s, void *unused)
3300{
3301 if (debug_aca_enabled)
3302 seq_printf(s, "enabled\n");
3303 else
3304 seq_printf(s, "disabled\n");
3305
3306 return 0;
3307}
3308
3309static int msm_otg_aca_open(struct inode *inode, struct file *file)
3310{
3311 return single_open(file, msm_otg_aca_show, inode->i_private);
3312}
3313
3314static ssize_t msm_otg_aca_write(struct file *file, const char __user *ubuf,
3315 size_t count, loff_t *ppos)
3316{
3317 char buf[8];
3318
3319 memset(buf, 0x00, sizeof(buf));
3320
3321 if (copy_from_user(&buf, ubuf, min_t(size_t, sizeof(buf) - 1, count)))
3322 return -EFAULT;
3323
3324 if (!strncmp(buf, "enable", 6))
3325 debug_aca_enabled = true;
3326 else
3327 debug_aca_enabled = false;
3328
3329 return count;
3330}
3331
3332const struct file_operations msm_otg_aca_fops = {
3333 .open = msm_otg_aca_open,
3334 .read = seq_read,
3335 .write = msm_otg_aca_write,
3336 .llseek = seq_lseek,
3337 .release = single_release,
3338};
3339
Manu Gautam8bdcc592012-03-06 11:26:06 +05303340static int msm_otg_bus_show(struct seq_file *s, void *unused)
3341{
3342 if (debug_bus_voting_enabled)
3343 seq_printf(s, "enabled\n");
3344 else
3345 seq_printf(s, "disabled\n");
3346
3347 return 0;
3348}
3349
3350static int msm_otg_bus_open(struct inode *inode, struct file *file)
3351{
3352 return single_open(file, msm_otg_bus_show, inode->i_private);
3353}
3354
3355static ssize_t msm_otg_bus_write(struct file *file, const char __user *ubuf,
3356 size_t count, loff_t *ppos)
3357{
3358 char buf[8];
3359 int ret;
3360 struct seq_file *s = file->private_data;
3361 struct msm_otg *motg = s->private;
3362
3363 memset(buf, 0x00, sizeof(buf));
3364
3365 if (copy_from_user(&buf, ubuf, min_t(size_t, sizeof(buf) - 1, count)))
3366 return -EFAULT;
3367
3368 if (!strncmp(buf, "enable", 6)) {
3369 /* Do not vote here. Let OTG statemachine decide when to vote */
3370 debug_bus_voting_enabled = true;
3371 } else {
3372 debug_bus_voting_enabled = false;
3373 if (motg->bus_perf_client) {
3374 ret = msm_bus_scale_client_update_request(
3375 motg->bus_perf_client, 0);
3376 if (ret)
Steve Mucklef132c6c2012-06-06 18:30:57 -07003377 dev_err(motg->phy.dev, "%s: Failed to devote "
Manu Gautam8bdcc592012-03-06 11:26:06 +05303378 "for bus bw %d\n", __func__, ret);
3379 }
3380 }
3381
3382 return count;
3383}
3384
David Keitel272ce522012-08-17 16:25:24 -07003385static int otg_power_get_property_usb(struct power_supply *psy,
3386 enum power_supply_property psp,
3387 union power_supply_propval *val)
3388{
3389 struct msm_otg *motg = container_of(psy, struct msm_otg,
3390 usb_psy);
3391 switch (psp) {
3392 case POWER_SUPPLY_PROP_SCOPE:
3393 if (motg->host_mode)
3394 val->intval = POWER_SUPPLY_SCOPE_SYSTEM;
3395 else
3396 val->intval = POWER_SUPPLY_SCOPE_DEVICE;
3397 break;
3398 case POWER_SUPPLY_PROP_CURRENT_MAX:
3399 val->intval = motg->current_max;
3400 break;
3401 /* Reflect USB enumeration */
3402 case POWER_SUPPLY_PROP_PRESENT:
3403 case POWER_SUPPLY_PROP_ONLINE:
3404 val->intval = motg->online;
3405 break;
3406 default:
3407 return -EINVAL;
3408 }
3409 return 0;
3410}
3411
3412static int otg_power_set_property_usb(struct power_supply *psy,
3413 enum power_supply_property psp,
3414 const union power_supply_propval *val)
3415{
3416 struct msm_otg *motg = container_of(psy, struct msm_otg,
3417 usb_psy);
3418
3419 switch (psp) {
3420 /* Process PMIC notification in PRESENT prop */
3421 case POWER_SUPPLY_PROP_PRESENT:
3422 msm_otg_set_vbus_state(val->intval);
3423 break;
3424 /* The ONLINE property reflects if usb has enumerated */
3425 case POWER_SUPPLY_PROP_ONLINE:
3426 motg->online = val->intval;
3427 break;
3428 case POWER_SUPPLY_PROP_CURRENT_MAX:
3429 motg->current_max = val->intval;
3430 break;
3431 default:
3432 return -EINVAL;
3433 }
3434
3435 power_supply_changed(&motg->usb_psy);
3436 return 0;
3437}
3438
3439static char *otg_pm_power_supplied_to[] = {
3440 "battery",
3441};
3442
3443static enum power_supply_property otg_pm_power_props_usb[] = {
3444 POWER_SUPPLY_PROP_PRESENT,
3445 POWER_SUPPLY_PROP_ONLINE,
3446 POWER_SUPPLY_PROP_CURRENT_MAX,
3447 POWER_SUPPLY_PROP_SCOPE,
3448};
3449
Manu Gautam8bdcc592012-03-06 11:26:06 +05303450const struct file_operations msm_otg_bus_fops = {
3451 .open = msm_otg_bus_open,
3452 .read = seq_read,
3453 .write = msm_otg_bus_write,
3454 .llseek = seq_lseek,
3455 .release = single_release,
3456};
3457
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05303458static struct dentry *msm_otg_dbg_root;
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05303459
3460static int msm_otg_debugfs_init(struct msm_otg *motg)
3461{
Manu Gautam8bdcc592012-03-06 11:26:06 +05303462 struct dentry *msm_otg_dentry;
Anji jonnalad270e2d2011-08-09 11:28:32 +05303463
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05303464 msm_otg_dbg_root = debugfs_create_dir("msm_otg", NULL);
3465
3466 if (!msm_otg_dbg_root || IS_ERR(msm_otg_dbg_root))
3467 return -ENODEV;
3468
Anji jonnalad270e2d2011-08-09 11:28:32 +05303469 if (motg->pdata->mode == USB_OTG &&
3470 motg->pdata->otg_control == OTG_USER_CONTROL) {
3471
Manu Gautam8bdcc592012-03-06 11:26:06 +05303472 msm_otg_dentry = debugfs_create_file("mode", S_IRUGO |
Anji jonnalad270e2d2011-08-09 11:28:32 +05303473 S_IWUSR, msm_otg_dbg_root, motg,
3474 &msm_otg_mode_fops);
3475
Manu Gautam8bdcc592012-03-06 11:26:06 +05303476 if (!msm_otg_dentry) {
Anji jonnalad270e2d2011-08-09 11:28:32 +05303477 debugfs_remove(msm_otg_dbg_root);
3478 msm_otg_dbg_root = NULL;
3479 return -ENODEV;
3480 }
3481 }
3482
Manu Gautam8bdcc592012-03-06 11:26:06 +05303483 msm_otg_dentry = debugfs_create_file("chg_type", S_IRUGO,
Anji jonnalad270e2d2011-08-09 11:28:32 +05303484 msm_otg_dbg_root, motg,
3485 &msm_otg_chg_fops);
3486
Manu Gautam8bdcc592012-03-06 11:26:06 +05303487 if (!msm_otg_dentry) {
Pavankumar Kondetiaa449e12011-11-04 11:09:26 +05303488 debugfs_remove_recursive(msm_otg_dbg_root);
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05303489 return -ENODEV;
3490 }
3491
Manu Gautam8bdcc592012-03-06 11:26:06 +05303492 msm_otg_dentry = debugfs_create_file("aca", S_IRUGO | S_IWUSR,
Pavankumar Kondetiaa449e12011-11-04 11:09:26 +05303493 msm_otg_dbg_root, motg,
3494 &msm_otg_aca_fops);
3495
Manu Gautam8bdcc592012-03-06 11:26:06 +05303496 if (!msm_otg_dentry) {
Pavankumar Kondetiaa449e12011-11-04 11:09:26 +05303497 debugfs_remove_recursive(msm_otg_dbg_root);
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05303498 return -ENODEV;
3499 }
3500
Manu Gautam8bdcc592012-03-06 11:26:06 +05303501 msm_otg_dentry = debugfs_create_file("bus_voting", S_IRUGO | S_IWUSR,
3502 msm_otg_dbg_root, motg,
3503 &msm_otg_bus_fops);
3504
3505 if (!msm_otg_dentry) {
3506 debugfs_remove_recursive(msm_otg_dbg_root);
3507 return -ENODEV;
3508 }
Chiranjeevi Velempatif9a11542012-03-28 18:18:34 +05303509
3510 msm_otg_dentry = debugfs_create_file("otg_state", S_IRUGO,
3511 msm_otg_dbg_root, motg, &msm_otg_state_fops);
3512
3513 if (!msm_otg_dentry) {
3514 debugfs_remove_recursive(msm_otg_dbg_root);
3515 return -ENODEV;
3516 }
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05303517 return 0;
3518}
3519
3520static void msm_otg_debugfs_cleanup(void)
3521{
Anji jonnalad270e2d2011-08-09 11:28:32 +05303522 debugfs_remove_recursive(msm_otg_dbg_root);
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05303523}
3524
Manu Gautam0ddbd922012-09-21 17:17:38 +05303525#define MSM_OTG_CMD_ID 0x09
3526#define MSM_OTG_DEVICE_ID 0x04
3527#define MSM_OTG_VMID_IDX 0xFF
3528#define MSM_OTG_MEM_TYPE 0x02
3529struct msm_otg_scm_cmd_buf {
3530 unsigned int device_id;
3531 unsigned int vmid_idx;
3532 unsigned int mem_type;
3533} __attribute__ ((__packed__));
3534
3535static void msm_otg_pnoc_errata_fix(struct msm_otg *motg)
3536{
3537 int ret;
3538 struct msm_otg_platform_data *pdata = motg->pdata;
3539 struct msm_otg_scm_cmd_buf cmd_buf;
3540
3541 if (!pdata->pnoc_errata_fix)
3542 return;
3543
3544 dev_dbg(motg->phy.dev, "applying fix for pnoc h/w issue\n");
3545
3546 cmd_buf.device_id = MSM_OTG_DEVICE_ID;
3547 cmd_buf.vmid_idx = MSM_OTG_VMID_IDX;
3548 cmd_buf.mem_type = MSM_OTG_MEM_TYPE;
3549
3550 ret = scm_call(SCM_SVC_CP, MSM_OTG_CMD_ID, &cmd_buf,
3551 sizeof(cmd_buf), NULL, 0);
3552
3553 if (ret)
3554 dev_err(motg->phy.dev, "scm command failed to update VMIDMT\n");
3555}
3556
Pavankumar Kondetieaea7fe2011-10-27 14:46:45 +05303557static u64 msm_otg_dma_mask = DMA_BIT_MASK(64);
3558static struct platform_device *msm_otg_add_pdev(
3559 struct platform_device *ofdev, const char *name)
3560{
3561 struct platform_device *pdev;
3562 const struct resource *res = ofdev->resource;
3563 unsigned int num = ofdev->num_resources;
3564 int retval;
3565
3566 pdev = platform_device_alloc(name, -1);
3567 if (!pdev) {
3568 retval = -ENOMEM;
3569 goto error;
3570 }
3571
3572 pdev->dev.coherent_dma_mask = DMA_BIT_MASK(32);
3573 pdev->dev.dma_mask = &msm_otg_dma_mask;
3574
3575 if (num) {
3576 retval = platform_device_add_resources(pdev, res, num);
3577 if (retval)
3578 goto error;
3579 }
3580
3581 retval = platform_device_add(pdev);
3582 if (retval)
3583 goto error;
3584
3585 return pdev;
3586
3587error:
3588 platform_device_put(pdev);
3589 return ERR_PTR(retval);
3590}
3591
3592static int msm_otg_setup_devices(struct platform_device *ofdev,
3593 enum usb_mode_type mode, bool init)
3594{
3595 const char *gadget_name = "msm_hsusb";
3596 const char *host_name = "msm_hsusb_host";
3597 static struct platform_device *gadget_pdev;
3598 static struct platform_device *host_pdev;
3599 int retval = 0;
3600
3601 if (!init) {
3602 if (gadget_pdev)
3603 platform_device_unregister(gadget_pdev);
3604 if (host_pdev)
3605 platform_device_unregister(host_pdev);
3606 return 0;
3607 }
3608
3609 switch (mode) {
3610 case USB_OTG:
3611 /* fall through */
3612 case USB_PERIPHERAL:
3613 gadget_pdev = msm_otg_add_pdev(ofdev, gadget_name);
3614 if (IS_ERR(gadget_pdev)) {
3615 retval = PTR_ERR(gadget_pdev);
3616 break;
3617 }
3618 if (mode == USB_PERIPHERAL)
3619 break;
3620 /* fall through */
3621 case USB_HOST:
3622 host_pdev = msm_otg_add_pdev(ofdev, host_name);
3623 if (IS_ERR(host_pdev)) {
3624 retval = PTR_ERR(host_pdev);
3625 if (mode == USB_OTG)
3626 platform_device_unregister(gadget_pdev);
3627 }
3628 break;
3629 default:
3630 break;
3631 }
3632
3633 return retval;
3634}
3635
David Keitel272ce522012-08-17 16:25:24 -07003636static int msm_otg_register_power_supply(struct platform_device *pdev,
3637 struct msm_otg *motg)
3638{
3639 int ret;
3640
3641 ret = power_supply_register(&pdev->dev, &motg->usb_psy);
3642 if (ret < 0) {
3643 dev_err(motg->phy.dev,
3644 "%s:power_supply_register usb failed\n",
3645 __func__);
3646 return ret;
3647 }
3648
3649 legacy_power_supply = false;
3650 return 0;
3651}
3652
Pavankumar Kondetieaea7fe2011-10-27 14:46:45 +05303653struct msm_otg_platform_data *msm_otg_dt_to_pdata(struct platform_device *pdev)
3654{
3655 struct device_node *node = pdev->dev.of_node;
3656 struct msm_otg_platform_data *pdata;
3657 int len = 0;
3658
3659 pdata = devm_kzalloc(&pdev->dev, sizeof(*pdata), GFP_KERNEL);
3660 if (!pdata) {
3661 pr_err("unable to allocate platform data\n");
3662 return NULL;
3663 }
3664 of_get_property(node, "qcom,hsusb-otg-phy-init-seq", &len);
3665 if (len) {
3666 pdata->phy_init_seq = devm_kzalloc(&pdev->dev, len, GFP_KERNEL);
3667 if (!pdata->phy_init_seq)
3668 return NULL;
3669 of_property_read_u32_array(node, "qcom,hsusb-otg-phy-init-seq",
3670 pdata->phy_init_seq,
3671 len/sizeof(*pdata->phy_init_seq));
3672 }
3673 of_property_read_u32(node, "qcom,hsusb-otg-power-budget",
3674 &pdata->power_budget);
3675 of_property_read_u32(node, "qcom,hsusb-otg-mode",
3676 &pdata->mode);
3677 of_property_read_u32(node, "qcom,hsusb-otg-otg-control",
3678 &pdata->otg_control);
3679 of_property_read_u32(node, "qcom,hsusb-otg-default-mode",
3680 &pdata->default_mode);
3681 of_property_read_u32(node, "qcom,hsusb-otg-phy-type",
3682 &pdata->phy_type);
3683 of_property_read_u32(node, "qcom,hsusb-otg-pmic-id-irq",
3684 &pdata->pmic_id_irq);
Manu Gautambd53fba2012-07-31 16:13:06 +05303685 pdata->disable_reset_on_disconnect = of_property_read_bool(node,
3686 "qcom,hsusb-otg-disable-reset");
Manu Gautam0ddbd922012-09-21 17:17:38 +05303687 pdata->pnoc_errata_fix = of_property_read_bool(node,
3688 "qcom,hsusb-otg-pnoc-errata-fix");
Manu Gautambd53fba2012-07-31 16:13:06 +05303689
Pavankumar Kondetieaea7fe2011-10-27 14:46:45 +05303690 return pdata;
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05303691}
3692
3693static int __init msm_otg_probe(struct platform_device *pdev)
3694{
Manu Gautamf8c45642012-08-10 10:20:56 -07003695 int ret = 0;
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05303696 struct resource *res;
3697 struct msm_otg *motg;
Heikki Krogerus1d4c9292012-02-13 13:24:09 +02003698 struct usb_phy *phy;
Pavankumar Kondetieaea7fe2011-10-27 14:46:45 +05303699 struct msm_otg_platform_data *pdata;
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05303700
3701 dev_info(&pdev->dev, "msm_otg probe\n");
Pavankumar Kondetieaea7fe2011-10-27 14:46:45 +05303702
3703 if (pdev->dev.of_node) {
3704 dev_dbg(&pdev->dev, "device tree enabled\n");
3705 pdata = msm_otg_dt_to_pdata(pdev);
3706 if (!pdata)
3707 return -ENOMEM;
Manu Gautam2e8ac102012-08-31 11:41:16 -07003708
3709 pdata->bus_scale_table = msm_bus_cl_get_pdata(pdev);
3710 if (!pdata->bus_scale_table)
3711 dev_dbg(&pdev->dev, "bus scaling is disabled\n");
3712
Pavankumar Kondetieaea7fe2011-10-27 14:46:45 +05303713 ret = msm_otg_setup_devices(pdev, pdata->mode, true);
3714 if (ret) {
3715 dev_err(&pdev->dev, "devices setup failed\n");
3716 return ret;
3717 }
3718 } else if (!pdev->dev.platform_data) {
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05303719 dev_err(&pdev->dev, "No platform data given. Bailing out\n");
3720 return -ENODEV;
Pavankumar Kondetieaea7fe2011-10-27 14:46:45 +05303721 } else {
3722 pdata = pdev->dev.platform_data;
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05303723 }
3724
3725 motg = kzalloc(sizeof(struct msm_otg), GFP_KERNEL);
3726 if (!motg) {
3727 dev_err(&pdev->dev, "unable to allocate msm_otg\n");
3728 return -ENOMEM;
3729 }
3730
Heikki Krogerus1d4c9292012-02-13 13:24:09 +02003731 motg->phy.otg = kzalloc(sizeof(struct usb_otg), GFP_KERNEL);
3732 if (!motg->phy.otg) {
Steve Mucklef132c6c2012-06-06 18:30:57 -07003733 dev_err(&pdev->dev, "unable to allocate usb_otg\n");
3734 ret = -ENOMEM;
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05303735 goto free_motg;
3736 }
3737
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003738 the_msm_otg = motg;
Pavankumar Kondetieaea7fe2011-10-27 14:46:45 +05303739 motg->pdata = pdata;
Steve Mucklef132c6c2012-06-06 18:30:57 -07003740 phy = &motg->phy;
3741 phy->dev = &pdev->dev;
Anji jonnala0f73cac2011-05-04 10:19:46 +05303742
3743 /*
Pavankumar Kondetiaa449e12011-11-04 11:09:26 +05303744 * ACA ID_GND threshold range is overlapped with OTG ID_FLOAT. Hence
3745 * PHY treat ACA ID_GND as float and no interrupt is generated. But
3746 * PMIC can detect ACA ID_GND and generate an interrupt.
3747 */
3748 if (aca_enabled() && motg->pdata->otg_control != OTG_PMIC_CONTROL) {
3749 dev_err(&pdev->dev, "ACA can not be enabled without PMIC\n");
3750 ret = -EINVAL;
Steve Mucklef132c6c2012-06-06 18:30:57 -07003751 goto free_otg;
Pavankumar Kondetiaa449e12011-11-04 11:09:26 +05303752 }
3753
Ofir Cohen4da266f2012-01-03 10:19:29 +02003754 /* initialize reset counter */
3755 motg->reset_counter = 0;
3756
Amit Blay02eff132011-09-21 16:46:24 +03003757 /* Some targets don't support PHY clock. */
Manu Gautam5143b252012-01-05 19:25:23 -08003758 motg->phy_reset_clk = clk_get(&pdev->dev, "phy_clk");
Amit Blay02eff132011-09-21 16:46:24 +03003759 if (IS_ERR(motg->phy_reset_clk))
Manu Gautam5143b252012-01-05 19:25:23 -08003760 dev_err(&pdev->dev, "failed to get phy_clk\n");
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05303761
Pavankumar Kondeti923262e2012-04-20 15:34:24 +05303762 /*
3763 * Targets on which link uses asynchronous reset methodology,
3764 * free running clock is not required during the reset.
3765 */
Manu Gautam5143b252012-01-05 19:25:23 -08003766 motg->clk = clk_get(&pdev->dev, "alt_core_clk");
Pavankumar Kondeti923262e2012-04-20 15:34:24 +05303767 if (IS_ERR(motg->clk))
3768 dev_dbg(&pdev->dev, "alt_core_clk is not present\n");
3769 else
3770 clk_set_rate(motg->clk, 60000000);
Anji jonnala0f73cac2011-05-04 10:19:46 +05303771
3772 /*
Manu Gautam5143b252012-01-05 19:25:23 -08003773 * USB Core is running its protocol engine based on CORE CLK,
Anji jonnala0f73cac2011-05-04 10:19:46 +05303774 * CORE CLK must be running at >55Mhz for correct HSUSB
3775 * operation and USB core cannot tolerate frequency changes on
3776 * CORE CLK. For such USB cores, vote for maximum clk frequency
3777 * on pclk source
3778 */
Manu Gautam5143b252012-01-05 19:25:23 -08003779 motg->core_clk = clk_get(&pdev->dev, "core_clk");
3780 if (IS_ERR(motg->core_clk)) {
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05303781 motg->core_clk = NULL;
Manu Gautam5143b252012-01-05 19:25:23 -08003782 dev_err(&pdev->dev, "failed to get core_clk\n");
Pavankumar Kondetibc541332012-04-20 15:32:04 +05303783 ret = PTR_ERR(motg->core_clk);
Manu Gautam5143b252012-01-05 19:25:23 -08003784 goto put_clk;
3785 }
3786 clk_set_rate(motg->core_clk, INT_MAX);
3787
3788 motg->pclk = clk_get(&pdev->dev, "iface_clk");
3789 if (IS_ERR(motg->pclk)) {
3790 dev_err(&pdev->dev, "failed to get iface_clk\n");
3791 ret = PTR_ERR(motg->pclk);
3792 goto put_core_clk;
3793 }
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05303794
3795 res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
3796 if (!res) {
3797 dev_err(&pdev->dev, "failed to get platform resource mem\n");
3798 ret = -ENODEV;
Manu Gautam5143b252012-01-05 19:25:23 -08003799 goto put_pclk;
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05303800 }
3801
3802 motg->regs = ioremap(res->start, resource_size(res));
3803 if (!motg->regs) {
3804 dev_err(&pdev->dev, "ioremap failed\n");
3805 ret = -ENOMEM;
Manu Gautam5143b252012-01-05 19:25:23 -08003806 goto put_pclk;
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05303807 }
3808 dev_info(&pdev->dev, "OTG regs = %p\n", motg->regs);
3809
3810 motg->irq = platform_get_irq(pdev, 0);
3811 if (!motg->irq) {
3812 dev_err(&pdev->dev, "platform_get_irq failed\n");
3813 ret = -ENODEV;
3814 goto free_regs;
3815 }
3816
Manu Gautamf8c45642012-08-10 10:20:56 -07003817 motg->async_irq = platform_get_irq_byname(pdev, "async_irq");
3818 if (motg->async_irq < 0) {
3819 dev_dbg(&pdev->dev, "platform_get_irq for async_int failed\n");
3820 motg->async_irq = 0;
3821 }
3822
Stephen Boyd30ad10b2012-03-01 14:51:04 -08003823 motg->xo_handle = msm_xo_get(MSM_XO_TCXO_D0, "usb");
Anji jonnala7da3f262011-12-02 17:22:14 -08003824 if (IS_ERR(motg->xo_handle)) {
3825 dev_err(&pdev->dev, "%s not able to get the handle "
3826 "to vote for TCXO D0 buffer\n", __func__);
3827 ret = PTR_ERR(motg->xo_handle);
3828 goto free_regs;
3829 }
Anji jonnala11aa5c42011-05-04 10:19:48 +05303830
Stephen Boyd30ad10b2012-03-01 14:51:04 -08003831 ret = msm_xo_mode_vote(motg->xo_handle, MSM_XO_MODE_ON);
Anji jonnala7da3f262011-12-02 17:22:14 -08003832 if (ret) {
3833 dev_err(&pdev->dev, "%s failed to vote for TCXO "
3834 "D0 buffer%d\n", __func__, ret);
3835 goto free_xo_handle;
3836 }
3837
Manu Gautam28b1bac2012-01-30 16:43:06 +05303838 clk_prepare_enable(motg->pclk);
Anji jonnala11aa5c42011-05-04 10:19:48 +05303839
Mayank Rana248698c2012-04-19 00:03:16 +05303840 motg->vdd_type = VDDCX_CORNER;
Steve Mucklef132c6c2012-06-06 18:30:57 -07003841 hsusb_vddcx = devm_regulator_get(motg->phy.dev, "hsusb_vdd_dig");
Mayank Rana248698c2012-04-19 00:03:16 +05303842 if (IS_ERR(hsusb_vddcx)) {
Steve Mucklef132c6c2012-06-06 18:30:57 -07003843 hsusb_vddcx = devm_regulator_get(motg->phy.dev, "HSUSB_VDDCX");
Mayank Rana248698c2012-04-19 00:03:16 +05303844 if (IS_ERR(hsusb_vddcx)) {
Steve Mucklef132c6c2012-06-06 18:30:57 -07003845 dev_err(motg->phy.dev, "unable to get hsusb vddcx\n");
Hemant Kumar41812392012-07-13 15:26:20 -07003846 ret = PTR_ERR(hsusb_vddcx);
Mayank Rana248698c2012-04-19 00:03:16 +05303847 goto devote_xo_handle;
3848 }
3849 motg->vdd_type = VDDCX;
Anji jonnala11aa5c42011-05-04 10:19:48 +05303850 }
3851
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003852 ret = msm_hsusb_config_vddcx(1);
Anji jonnala11aa5c42011-05-04 10:19:48 +05303853 if (ret) {
3854 dev_err(&pdev->dev, "hsusb vddcx configuration failed\n");
Mayank Rana248698c2012-04-19 00:03:16 +05303855 goto devote_xo_handle;
3856 }
3857
3858 ret = regulator_enable(hsusb_vddcx);
3859 if (ret) {
3860 dev_err(&pdev->dev, "unable to enable the hsusb vddcx\n");
3861 goto free_config_vddcx;
Anji jonnala11aa5c42011-05-04 10:19:48 +05303862 }
3863
3864 ret = msm_hsusb_ldo_init(motg, 1);
3865 if (ret) {
3866 dev_err(&pdev->dev, "hsusb vreg configuration failed\n");
Mayank Rana248698c2012-04-19 00:03:16 +05303867 goto free_hsusb_vddcx;
Anji jonnala11aa5c42011-05-04 10:19:48 +05303868 }
3869
Mayank Rana9e9a2ac2012-03-24 04:05:28 +05303870 if (pdata->mhl_enable) {
Pavankumar Kondeti56dc7422012-07-02 12:45:19 +05303871 mhl_usb_hs_switch = devm_regulator_get(motg->phy.dev,
3872 "mhl_usb_hs_switch");
3873 if (IS_ERR(mhl_usb_hs_switch)) {
3874 dev_err(&pdev->dev, "Unable to get mhl_usb_hs_switch\n");
Hemant Kumar41812392012-07-13 15:26:20 -07003875 ret = PTR_ERR(mhl_usb_hs_switch);
Mayank Rana9e9a2ac2012-03-24 04:05:28 +05303876 goto free_ldo_init;
3877 }
3878 }
3879
Amit Blay81801aa2012-09-19 12:08:12 +02003880 ret = msm_hsusb_ldo_enable(motg, USB_PHY_REG_ON);
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05303881 if (ret) {
3882 dev_err(&pdev->dev, "hsusb vreg enable failed\n");
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003883 goto free_ldo_init;
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05303884 }
Manu Gautam28b1bac2012-01-30 16:43:06 +05303885 clk_prepare_enable(motg->core_clk);
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05303886
Manu Gautam0ddbd922012-09-21 17:17:38 +05303887 /* Check if USB mem_type change is needed to workaround PNOC hw issue */
3888 msm_otg_pnoc_errata_fix(motg);
3889
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05303890 writel(0, USB_USBINTR);
3891 writel(0, USB_OTGSC);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003892 /* Ensure that above STOREs are completed before enabling interrupts */
3893 mb();
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05303894
Pavankumar Kondeti2aec9f32012-06-13 09:06:03 +05303895 ret = msm_otg_mhl_register_callback(motg, msm_otg_mhl_notify_online);
3896 if (ret)
3897 dev_dbg(&pdev->dev, "MHL can not be supported\n");
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003898 wake_lock_init(&motg->wlock, WAKE_LOCK_SUSPEND, "msm_otg");
Vijayavardhan Vennapusaa3152032012-03-05 16:29:30 +05303899 msm_otg_init_timer(motg);
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05303900 INIT_WORK(&motg->sm_work, msm_otg_sm_work);
Pavankumar Kondetid8608522011-05-04 10:19:47 +05303901 INIT_DELAYED_WORK(&motg->chg_work, msm_chg_detect_work);
Vijayavardhan Vennapusa68d55cf2012-06-27 20:06:12 +05303902 INIT_DELAYED_WORK(&motg->pmic_id_status_work, msm_pmic_id_status_w);
Amit Blayd0fe07b2012-09-05 16:42:09 +03003903 INIT_DELAYED_WORK(&motg->suspend_work, msm_otg_suspend_work);
Pavankumar Kondetiaa449e12011-11-04 11:09:26 +05303904 setup_timer(&motg->id_timer, msm_otg_id_timer_func,
3905 (unsigned long) motg);
Pavankumar Kondeti458d8792012-09-28 14:45:18 +05303906 setup_timer(&motg->chg_check_timer, msm_otg_chg_check_timer_func,
3907 (unsigned long) motg);
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05303908 ret = request_irq(motg->irq, msm_otg_irq, IRQF_SHARED,
3909 "msm_otg", motg);
3910 if (ret) {
3911 dev_err(&pdev->dev, "request irq failed\n");
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003912 goto destroy_wlock;
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05303913 }
3914
Manu Gautamf8c45642012-08-10 10:20:56 -07003915 if (motg->async_irq) {
Vijayavardhan Vennapusa9ab6f972012-10-11 19:18:55 +05303916 ret = request_irq(motg->async_irq, msm_otg_irq,
3917 IRQF_TRIGGER_RISING, "msm_otg", motg);
Manu Gautamf8c45642012-08-10 10:20:56 -07003918 if (ret) {
3919 dev_err(&pdev->dev, "request irq failed (ASYNC INT)\n");
3920 goto free_irq;
3921 }
3922 disable_irq(motg->async_irq);
3923 }
3924
Jack Pham87f202f2012-08-06 00:24:22 -07003925 if (pdata->otg_control == OTG_PHY_CONTROL && pdata->mpm_otgsessvld_int)
3926 msm_mpm_enable_pin(pdata->mpm_otgsessvld_int, 1);
3927
Heikki Krogerus1d4c9292012-02-13 13:24:09 +02003928 phy->init = msm_otg_reset;
3929 phy->set_power = msm_otg_set_power;
Steve Mucklef132c6c2012-06-06 18:30:57 -07003930 phy->set_suspend = msm_otg_set_suspend;
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05303931
Heikki Krogerus1d4c9292012-02-13 13:24:09 +02003932 phy->io_ops = &msm_otg_io_ops;
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05303933
Heikki Krogerus1d4c9292012-02-13 13:24:09 +02003934 phy->otg->phy = &motg->phy;
3935 phy->otg->set_host = msm_otg_set_host;
3936 phy->otg->set_peripheral = msm_otg_set_peripheral;
Steve Mucklef132c6c2012-06-06 18:30:57 -07003937 phy->otg->start_hnp = msm_otg_start_hnp;
3938 phy->otg->start_srp = msm_otg_start_srp;
Heikki Krogerus1d4c9292012-02-13 13:24:09 +02003939
3940 ret = usb_set_transceiver(&motg->phy);
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05303941 if (ret) {
Heikki Krogerus1d4c9292012-02-13 13:24:09 +02003942 dev_err(&pdev->dev, "usb_set_transceiver failed\n");
Manu Gautamf8c45642012-08-10 10:20:56 -07003943 goto free_async_irq;
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05303944 }
3945
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05303946 if (motg->pdata->mode == USB_OTG &&
Pavankumar Kondeti0d81f312012-01-13 11:34:10 +05303947 motg->pdata->otg_control == OTG_PMIC_CONTROL) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003948 if (motg->pdata->pmic_id_irq) {
3949 ret = request_irq(motg->pdata->pmic_id_irq,
3950 msm_pmic_id_irq,
3951 IRQF_TRIGGER_RISING |
3952 IRQF_TRIGGER_FALLING,
3953 "msm_otg", motg);
3954 if (ret) {
3955 dev_err(&pdev->dev, "request irq failed for PMIC ID\n");
Steve Mucklef132c6c2012-06-06 18:30:57 -07003956 goto remove_phy;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003957 }
3958 } else {
3959 ret = -ENODEV;
3960 dev_err(&pdev->dev, "PMIC IRQ for ID notifications doesn't exist\n");
Steve Mucklef132c6c2012-06-06 18:30:57 -07003961 goto remove_phy;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003962 }
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05303963 }
3964
Vijayavardhan Vennapusafc464f02011-11-04 21:54:00 +05303965 msm_hsusb_mhl_switch_enable(motg, 1);
3966
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05303967 platform_set_drvdata(pdev, motg);
3968 device_init_wakeup(&pdev->dev, 1);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003969 motg->mA_port = IUNIT;
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05303970
Anji jonnalad270e2d2011-08-09 11:28:32 +05303971 ret = msm_otg_debugfs_init(motg);
3972 if (ret)
3973 dev_dbg(&pdev->dev, "mode debugfs file is"
3974 "not available\n");
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05303975
Amit Blay58b31472011-11-18 09:39:39 +02003976 if (motg->pdata->phy_type == SNPS_28NM_INTEGRATED_PHY) {
3977 if (motg->pdata->otg_control == OTG_PMIC_CONTROL &&
Pavankumar Kondeti0d81f312012-01-13 11:34:10 +05303978 (!(motg->pdata->mode == USB_OTG) ||
3979 motg->pdata->pmic_id_irq))
Amit Blay58b31472011-11-18 09:39:39 +02003980 motg->caps = ALLOW_PHY_POWER_COLLAPSE |
Vijayavardhan Vennapusa03171c72012-04-26 14:44:48 +05303981 ALLOW_PHY_RETENTION;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003982
Amit Blay58b31472011-11-18 09:39:39 +02003983 if (motg->pdata->otg_control == OTG_PHY_CONTROL)
Amit Blay81801aa2012-09-19 12:08:12 +02003984 motg->caps = ALLOW_PHY_RETENTION |
3985 ALLOW_PHY_REGULATORS_LPM;
Amit Blay58b31472011-11-18 09:39:39 +02003986 }
3987
Amit Blay6fa647a2012-05-24 14:12:08 +03003988 if (motg->pdata->enable_lpm_on_dev_suspend)
3989 motg->caps |= ALLOW_LPM_ON_DEV_SUSPEND;
3990
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003991 wake_lock(&motg->wlock);
Pavankumar Kondeti87c01042010-12-07 17:53:58 +05303992 pm_runtime_set_active(&pdev->dev);
Manu Gautamf8c45642012-08-10 10:20:56 -07003993 pm_runtime_enable(&pdev->dev);
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05303994
Manu Gautamcd82e9d2011-12-20 14:17:28 +05303995 if (motg->pdata->bus_scale_table) {
3996 motg->bus_perf_client =
3997 msm_bus_scale_register_client(motg->pdata->bus_scale_table);
3998 if (!motg->bus_perf_client)
Steve Mucklef132c6c2012-06-06 18:30:57 -07003999 dev_err(motg->phy.dev, "%s: Failed to register BUS "
Manu Gautamcd82e9d2011-12-20 14:17:28 +05304000 "scaling client!!\n", __func__);
Manu Gautam8bdcc592012-03-06 11:26:06 +05304001 else
4002 debug_bus_voting_enabled = true;
Manu Gautamcd82e9d2011-12-20 14:17:28 +05304003 }
4004
David Keitel272ce522012-08-17 16:25:24 -07004005 motg->usb_psy.name = "usb";
4006 motg->usb_psy.type = POWER_SUPPLY_TYPE_USB;
4007 motg->usb_psy.supplied_to = otg_pm_power_supplied_to;
4008 motg->usb_psy.num_supplicants = ARRAY_SIZE(otg_pm_power_supplied_to);
4009 motg->usb_psy.properties = otg_pm_power_props_usb;
4010 motg->usb_psy.num_properties = ARRAY_SIZE(otg_pm_power_props_usb);
4011 motg->usb_psy.get_property = otg_power_get_property_usb;
4012 motg->usb_psy.set_property = otg_power_set_property_usb;
4013
4014 if (motg->pdata->otg_control == OTG_PMIC_CONTROL) {
4015 /* if pm8921 use legacy implementation */
4016 if (!pm8921_charger_register_vbus_sn(&msm_otg_set_vbus_state)) {
4017 dev_dbg(motg->phy.dev, "%s: legacy support\n",
4018 __func__);
4019 legacy_power_supply = true;
4020 } else {
4021 ret = msm_otg_register_power_supply(pdev, motg);
4022 if (ret)
4023 goto remove_phy;
4024 }
David Keitel272ce522012-08-17 16:25:24 -07004025 }
4026
Pavankumar Kondeti87c01042010-12-07 17:53:58 +05304027 return 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004028
Steve Mucklef132c6c2012-06-06 18:30:57 -07004029remove_phy:
4030 usb_set_transceiver(NULL);
Manu Gautamf8c45642012-08-10 10:20:56 -07004031free_async_irq:
4032 if (motg->async_irq)
4033 free_irq(motg->async_irq, motg);
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05304034free_irq:
4035 free_irq(motg->irq, motg);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004036destroy_wlock:
4037 wake_lock_destroy(&motg->wlock);
Manu Gautam28b1bac2012-01-30 16:43:06 +05304038 clk_disable_unprepare(motg->core_clk);
Amit Blay81801aa2012-09-19 12:08:12 +02004039 msm_hsusb_ldo_enable(motg, USB_PHY_REG_OFF);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004040free_ldo_init:
Anji jonnala11aa5c42011-05-04 10:19:48 +05304041 msm_hsusb_ldo_init(motg, 0);
Mayank Rana248698c2012-04-19 00:03:16 +05304042free_hsusb_vddcx:
4043 regulator_disable(hsusb_vddcx);
4044free_config_vddcx:
4045 regulator_set_voltage(hsusb_vddcx,
4046 vdd_val[motg->vdd_type][VDD_NONE],
4047 vdd_val[motg->vdd_type][VDD_MAX]);
Anji jonnala7da3f262011-12-02 17:22:14 -08004048devote_xo_handle:
Manu Gautam28b1bac2012-01-30 16:43:06 +05304049 clk_disable_unprepare(motg->pclk);
Stephen Boyd30ad10b2012-03-01 14:51:04 -08004050 msm_xo_mode_vote(motg->xo_handle, MSM_XO_MODE_OFF);
Anji jonnala7da3f262011-12-02 17:22:14 -08004051free_xo_handle:
Stephen Boyd30ad10b2012-03-01 14:51:04 -08004052 msm_xo_put(motg->xo_handle);
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05304053free_regs:
4054 iounmap(motg->regs);
Manu Gautam5143b252012-01-05 19:25:23 -08004055put_pclk:
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05304056 clk_put(motg->pclk);
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05304057put_core_clk:
Manu Gautam5143b252012-01-05 19:25:23 -08004058 clk_put(motg->core_clk);
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05304059put_clk:
Pavankumar Kondeti923262e2012-04-20 15:34:24 +05304060 if (!IS_ERR(motg->clk))
4061 clk_put(motg->clk);
Amit Blay02eff132011-09-21 16:46:24 +03004062 if (!IS_ERR(motg->phy_reset_clk))
4063 clk_put(motg->phy_reset_clk);
Steve Mucklef132c6c2012-06-06 18:30:57 -07004064free_otg:
Heikki Krogerus1d4c9292012-02-13 13:24:09 +02004065 kfree(motg->phy.otg);
Pavankumar Kondetiaa449e12011-11-04 11:09:26 +05304066free_motg:
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05304067 kfree(motg);
4068 return ret;
4069}
4070
4071static int __devexit msm_otg_remove(struct platform_device *pdev)
4072{
4073 struct msm_otg *motg = platform_get_drvdata(pdev);
Steve Mucklef132c6c2012-06-06 18:30:57 -07004074 struct usb_otg *otg = motg->phy.otg;
Pavankumar Kondeti87c01042010-12-07 17:53:58 +05304075 int cnt = 0;
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05304076
4077 if (otg->host || otg->gadget)
4078 return -EBUSY;
4079
Pavankumar Kondetieaea7fe2011-10-27 14:46:45 +05304080 if (pdev->dev.of_node)
4081 msm_otg_setup_devices(pdev, motg->pdata->mode, false);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004082 if (motg->pdata->otg_control == OTG_PMIC_CONTROL)
4083 pm8921_charger_unregister_vbus_sn(0);
Pavankumar Kondeti2aec9f32012-06-13 09:06:03 +05304084 msm_otg_mhl_register_callback(motg, NULL);
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05304085 msm_otg_debugfs_cleanup();
Pavankumar Kondetid8608522011-05-04 10:19:47 +05304086 cancel_delayed_work_sync(&motg->chg_work);
Vijayavardhan Vennapusa68d55cf2012-06-27 20:06:12 +05304087 cancel_delayed_work_sync(&motg->pmic_id_status_work);
Amit Blayd0fe07b2012-09-05 16:42:09 +03004088 cancel_delayed_work_sync(&motg->suspend_work);
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05304089 cancel_work_sync(&motg->sm_work);
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05304090
Pavankumar Kondeti70187732011-02-15 09:42:34 +05304091 pm_runtime_resume(&pdev->dev);
Pavankumar Kondeti87c01042010-12-07 17:53:58 +05304092
4093 device_init_wakeup(&pdev->dev, 0);
4094 pm_runtime_disable(&pdev->dev);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004095 wake_lock_destroy(&motg->wlock);
Pavankumar Kondeti87c01042010-12-07 17:53:58 +05304096
Vijayavardhan Vennapusafc464f02011-11-04 21:54:00 +05304097 msm_hsusb_mhl_switch_enable(motg, 0);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004098 if (motg->pdata->pmic_id_irq)
4099 free_irq(motg->pdata->pmic_id_irq, motg);
Heikki Krogerus1d4c9292012-02-13 13:24:09 +02004100 usb_set_transceiver(NULL);
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05304101 free_irq(motg->irq, motg);
4102
Jack Pham87f202f2012-08-06 00:24:22 -07004103 if (motg->pdata->otg_control == OTG_PHY_CONTROL &&
4104 motg->pdata->mpm_otgsessvld_int)
4105 msm_mpm_enable_pin(motg->pdata->mpm_otgsessvld_int, 0);
4106
Pavankumar Kondeti87c01042010-12-07 17:53:58 +05304107 /*
4108 * Put PHY in low power mode.
4109 */
Steve Mucklef132c6c2012-06-06 18:30:57 -07004110 ulpi_read(otg->phy, 0x14);
4111 ulpi_write(otg->phy, 0x08, 0x09);
Pavankumar Kondeti87c01042010-12-07 17:53:58 +05304112
4113 writel(readl(USB_PORTSC) | PORTSC_PHCD, USB_PORTSC);
4114 while (cnt < PHY_SUSPEND_TIMEOUT_USEC) {
4115 if (readl(USB_PORTSC) & PORTSC_PHCD)
4116 break;
4117 udelay(1);
4118 cnt++;
4119 }
4120 if (cnt >= PHY_SUSPEND_TIMEOUT_USEC)
Steve Mucklef132c6c2012-06-06 18:30:57 -07004121 dev_err(otg->phy->dev, "Unable to suspend PHY\n");
Pavankumar Kondeti87c01042010-12-07 17:53:58 +05304122
Manu Gautam28b1bac2012-01-30 16:43:06 +05304123 clk_disable_unprepare(motg->pclk);
4124 clk_disable_unprepare(motg->core_clk);
Stephen Boyd30ad10b2012-03-01 14:51:04 -08004125 msm_xo_put(motg->xo_handle);
Amit Blay81801aa2012-09-19 12:08:12 +02004126 msm_hsusb_ldo_enable(motg, USB_PHY_REG_OFF);
Anji jonnala11aa5c42011-05-04 10:19:48 +05304127 msm_hsusb_ldo_init(motg, 0);
Mayank Rana248698c2012-04-19 00:03:16 +05304128 regulator_disable(hsusb_vddcx);
4129 regulator_set_voltage(hsusb_vddcx,
4130 vdd_val[motg->vdd_type][VDD_NONE],
4131 vdd_val[motg->vdd_type][VDD_MAX]);
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05304132
4133 iounmap(motg->regs);
Pavankumar Kondeti87c01042010-12-07 17:53:58 +05304134 pm_runtime_set_suspended(&pdev->dev);
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05304135
Amit Blay02eff132011-09-21 16:46:24 +03004136 if (!IS_ERR(motg->phy_reset_clk))
4137 clk_put(motg->phy_reset_clk);
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05304138 clk_put(motg->pclk);
Pavankumar Kondeti923262e2012-04-20 15:34:24 +05304139 if (!IS_ERR(motg->clk))
4140 clk_put(motg->clk);
Manu Gautam5143b252012-01-05 19:25:23 -08004141 clk_put(motg->core_clk);
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05304142
Manu Gautamcd82e9d2011-12-20 14:17:28 +05304143 if (motg->bus_perf_client)
4144 msm_bus_scale_unregister_client(motg->bus_perf_client);
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05304145
Heikki Krogerus1d4c9292012-02-13 13:24:09 +02004146 kfree(motg->phy.otg);
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05304147 kfree(motg);
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05304148 return 0;
4149}
4150
Pavankumar Kondeti87c01042010-12-07 17:53:58 +05304151#ifdef CONFIG_PM_RUNTIME
4152static int msm_otg_runtime_idle(struct device *dev)
4153{
4154 struct msm_otg *motg = dev_get_drvdata(dev);
Steve Mucklef132c6c2012-06-06 18:30:57 -07004155 struct usb_phy *phy = &motg->phy;
Pavankumar Kondeti87c01042010-12-07 17:53:58 +05304156
4157 dev_dbg(dev, "OTG runtime idle\n");
4158
Steve Mucklef132c6c2012-06-06 18:30:57 -07004159 if (phy->state == OTG_STATE_UNDEFINED)
Pavankumar Kondeti8be99cf2011-08-04 10:48:08 +05304160 return -EAGAIN;
4161 else
4162 return 0;
Pavankumar Kondeti87c01042010-12-07 17:53:58 +05304163}
4164
4165static int msm_otg_runtime_suspend(struct device *dev)
4166{
4167 struct msm_otg *motg = dev_get_drvdata(dev);
4168
4169 dev_dbg(dev, "OTG runtime suspend\n");
4170 return msm_otg_suspend(motg);
4171}
4172
4173static int msm_otg_runtime_resume(struct device *dev)
4174{
4175 struct msm_otg *motg = dev_get_drvdata(dev);
4176
4177 dev_dbg(dev, "OTG runtime resume\n");
Pavankumar Kondeti8be99cf2011-08-04 10:48:08 +05304178 pm_runtime_get_noresume(dev);
Pavankumar Kondeti87c01042010-12-07 17:53:58 +05304179 return msm_otg_resume(motg);
4180}
Pavankumar Kondeti87c01042010-12-07 17:53:58 +05304181#endif
4182
Pavankumar Kondeti70187732011-02-15 09:42:34 +05304183#ifdef CONFIG_PM_SLEEP
Pavankumar Kondeti87c01042010-12-07 17:53:58 +05304184static int msm_otg_pm_suspend(struct device *dev)
4185{
Jack Pham5ca279b2012-05-14 18:42:54 -07004186 int ret = 0;
Pavankumar Kondeti87c01042010-12-07 17:53:58 +05304187 struct msm_otg *motg = dev_get_drvdata(dev);
4188
4189 dev_dbg(dev, "OTG PM suspend\n");
Jack Pham5ca279b2012-05-14 18:42:54 -07004190
4191 atomic_set(&motg->pm_suspended, 1);
4192 ret = msm_otg_suspend(motg);
4193 if (ret)
4194 atomic_set(&motg->pm_suspended, 0);
4195
4196 return ret;
Pavankumar Kondeti87c01042010-12-07 17:53:58 +05304197}
4198
4199static int msm_otg_pm_resume(struct device *dev)
4200{
Jack Pham5ca279b2012-05-14 18:42:54 -07004201 int ret = 0;
Pavankumar Kondeti87c01042010-12-07 17:53:58 +05304202 struct msm_otg *motg = dev_get_drvdata(dev);
Pavankumar Kondeti87c01042010-12-07 17:53:58 +05304203
4204 dev_dbg(dev, "OTG PM resume\n");
4205
Jack Pham5ca279b2012-05-14 18:42:54 -07004206 atomic_set(&motg->pm_suspended, 0);
Jack Phamc7edb172012-08-13 15:32:39 -07004207 if (motg->async_int || motg->sm_work_pending) {
Jack Pham5ca279b2012-05-14 18:42:54 -07004208 pm_runtime_get_noresume(dev);
4209 ret = msm_otg_resume(motg);
Pavankumar Kondeti87c01042010-12-07 17:53:58 +05304210
Jack Pham5ca279b2012-05-14 18:42:54 -07004211 /* Update runtime PM status */
4212 pm_runtime_disable(dev);
4213 pm_runtime_set_active(dev);
4214 pm_runtime_enable(dev);
4215
Jack Phamc7edb172012-08-13 15:32:39 -07004216 if (motg->sm_work_pending) {
4217 motg->sm_work_pending = false;
4218 queue_work(system_nrt_wq, &motg->sm_work);
4219 }
Jack Pham5ca279b2012-05-14 18:42:54 -07004220 }
4221
4222 return ret;
Pavankumar Kondeti87c01042010-12-07 17:53:58 +05304223}
Pavankumar Kondeti87c01042010-12-07 17:53:58 +05304224#endif
4225
Pavankumar Kondeti70187732011-02-15 09:42:34 +05304226#ifdef CONFIG_PM
Pavankumar Kondeti87c01042010-12-07 17:53:58 +05304227static const struct dev_pm_ops msm_otg_dev_pm_ops = {
Pavankumar Kondeti70187732011-02-15 09:42:34 +05304228 SET_SYSTEM_SLEEP_PM_OPS(msm_otg_pm_suspend, msm_otg_pm_resume)
4229 SET_RUNTIME_PM_OPS(msm_otg_runtime_suspend, msm_otg_runtime_resume,
4230 msm_otg_runtime_idle)
Pavankumar Kondeti87c01042010-12-07 17:53:58 +05304231};
Pavankumar Kondeti70187732011-02-15 09:42:34 +05304232#endif
Pavankumar Kondeti87c01042010-12-07 17:53:58 +05304233
Pavankumar Kondetieaea7fe2011-10-27 14:46:45 +05304234static struct of_device_id msm_otg_dt_match[] = {
4235 { .compatible = "qcom,hsusb-otg",
4236 },
4237 {}
4238};
4239
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05304240static struct platform_driver msm_otg_driver = {
4241 .remove = __devexit_p(msm_otg_remove),
4242 .driver = {
4243 .name = DRIVER_NAME,
4244 .owner = THIS_MODULE,
Pavankumar Kondeti70187732011-02-15 09:42:34 +05304245#ifdef CONFIG_PM
Pavankumar Kondeti87c01042010-12-07 17:53:58 +05304246 .pm = &msm_otg_dev_pm_ops,
Pavankumar Kondeti70187732011-02-15 09:42:34 +05304247#endif
Pavankumar Kondetieaea7fe2011-10-27 14:46:45 +05304248 .of_match_table = msm_otg_dt_match,
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05304249 },
4250};
4251
4252static int __init msm_otg_init(void)
4253{
4254 return platform_driver_probe(&msm_otg_driver, msm_otg_probe);
4255}
4256
4257static void __exit msm_otg_exit(void)
4258{
4259 platform_driver_unregister(&msm_otg_driver);
4260}
4261
4262module_init(msm_otg_init);
4263module_exit(msm_otg_exit);
4264
4265MODULE_LICENSE("GPL v2");
4266MODULE_DESCRIPTION("MSM USB transceiver driver");