blob: ea724d61b59dc1fb9d5c68a4530e1ed9a6fc9126 [file] [log] [blame]
Saket Saurabh2558ea02014-01-10 16:14:27 +05301/* Copyright (c) 2009-2014, Linux Foundation. All rights reserved.
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05302 *
3 * This program is free software; you can redistribute it and/or modify
4 * it under the terms of the GNU General Public License version 2 and
5 * only version 2 as published by the Free Software Foundation.
6 *
7 * This program is distributed in the hope that it will be useful,
8 * but WITHOUT ANY WARRANTY; without even the implied warranty of
9 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10 * GNU General Public License for more details.
11 *
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +053012 */
13
14#include <linux/module.h>
15#include <linux/device.h>
16#include <linux/platform_device.h>
17#include <linux/clk.h>
18#include <linux/slab.h>
19#include <linux/interrupt.h>
20#include <linux/err.h>
21#include <linux/delay.h>
22#include <linux/io.h>
23#include <linux/ioport.h>
24#include <linux/uaccess.h>
25#include <linux/debugfs.h>
26#include <linux/seq_file.h>
Pavankumar Kondeti87c01042010-12-07 17:53:58 +053027#include <linux/pm_runtime.h>
Pavankumar Kondetieaea7fe2011-10-27 14:46:45 +053028#include <linux/of.h>
29#include <linux/dma-mapping.h>
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +053030
31#include <linux/usb.h>
32#include <linux/usb/otg.h>
33#include <linux/usb/ulpi.h>
34#include <linux/usb/gadget.h>
35#include <linux/usb/hcd.h>
Vijayavardhan Vennapusaa3152032012-03-05 16:29:30 +053036#include <linux/usb/quirks.h>
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +053037#include <linux/usb/msm_hsusb.h>
38#include <linux/usb/msm_hsusb_hw.h>
Pavankumar Kondetif1ffbdd2013-06-27 13:31:36 +053039#include <linux/usb/msm_ext_chg.h>
Anji jonnala11aa5c42011-05-04 10:19:48 +053040#include <linux/regulator/consumer.h>
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070041#include <linux/mfd/pm8xxx/pm8921-charger.h>
Pavankumar Kondeti446f4542012-02-01 13:57:13 +053042#include <linux/mfd/pm8xxx/misc.h>
Pavankumar Kondeti2aec9f32012-06-13 09:06:03 +053043#include <linux/mhl_8334.h>
Vijayavardhan Vennapusa29e88802014-02-17 11:09:23 +053044#include <linux/qpnp/qpnp-adc.h>
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +053045
Manu Gautam0ddbd922012-09-21 17:17:38 +053046#include <mach/scm.h>
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +053047#include <mach/clk.h>
Jack Pham87f202f2012-08-06 00:24:22 -070048#include <mach/mpm.h>
Anji jonnala7da3f262011-12-02 17:22:14 -080049#include <mach/msm_xo.h>
Manu Gautamcd82e9d2011-12-20 14:17:28 +053050#include <mach/msm_bus.h>
Mayank Rana248698c2012-04-19 00:03:16 +053051#include <mach/rpm-regulator.h>
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +053052
53#define MSM_USB_BASE (motg->regs)
54#define DRIVER_NAME "msm_otg"
55
Chiranjeevi Velempati489a27c2012-03-29 09:47:17 +053056#define ID_TIMER_FREQ (jiffies + msecs_to_jiffies(500))
Pavankumar Kondeti458d8792012-09-28 14:45:18 +053057#define CHG_RECHECK_DELAY (jiffies + msecs_to_jiffies(2000))
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +053058#define ULPI_IO_TIMEOUT_USEC (10 * 1000)
Anji jonnala11aa5c42011-05-04 10:19:48 +053059#define USB_PHY_3P3_VOL_MIN 3050000 /* uV */
60#define USB_PHY_3P3_VOL_MAX 3300000 /* uV */
61#define USB_PHY_3P3_HPM_LOAD 50000 /* uA */
62#define USB_PHY_3P3_LPM_LOAD 4000 /* uA */
63
64#define USB_PHY_1P8_VOL_MIN 1800000 /* uV */
65#define USB_PHY_1P8_VOL_MAX 1800000 /* uV */
66#define USB_PHY_1P8_HPM_LOAD 50000 /* uA */
67#define USB_PHY_1P8_LPM_LOAD 4000 /* uA */
68
Mayank Rana248698c2012-04-19 00:03:16 +053069#define USB_PHY_VDD_DIG_VOL_NONE 0 /*uV */
Vamsi Krishna132b2762011-11-11 16:09:20 -080070#define USB_PHY_VDD_DIG_VOL_MIN 1045000 /* uV */
Anji jonnala11aa5c42011-05-04 10:19:48 +053071#define USB_PHY_VDD_DIG_VOL_MAX 1320000 /* uV */
72
Amit Blayd0fe07b2012-09-05 16:42:09 +030073#define USB_SUSPEND_DELAY_TIME (500 * HZ/1000) /* 500 msec */
74
Amit Blay81801aa2012-09-19 12:08:12 +020075enum msm_otg_phy_reg_mode {
76 USB_PHY_REG_OFF,
77 USB_PHY_REG_ON,
78 USB_PHY_REG_LPM_ON,
79 USB_PHY_REG_LPM_OFF,
80};
81
Mayank Rana443f9e42012-09-21 18:32:39 +053082static char *override_phy_init;
83module_param(override_phy_init, charp, S_IRUGO|S_IWUSR);
84MODULE_PARM_DESC(override_phy_init,
85 "Override HSUSB PHY Init Settings");
86
Amit Blayd6f38282012-10-29 13:13:46 +020087unsigned int lpm_disconnect_thresh = 1000;
88module_param(lpm_disconnect_thresh , uint, S_IRUGO | S_IWUSR);
89MODULE_PARM_DESC(lpm_disconnect_thresh,
90 "Delay before entering LPM on USB disconnect");
91
zhenhuahb6d5edc2013-06-19 14:37:32 +080092static bool floated_charger_enable;
93module_param(floated_charger_enable , bool, S_IRUGO | S_IWUSR);
94MODULE_PARM_DESC(floated_charger_enable,
95 "Whether to enable floated charger");
96
Pavankumar Kondeti4960f312011-12-06 15:46:14 +053097static DECLARE_COMPLETION(pmic_vbus_init);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070098static struct msm_otg *the_msm_otg;
Pavankumar Kondetiaa449e12011-11-04 11:09:26 +053099static bool debug_aca_enabled;
Manu Gautam8bdcc592012-03-06 11:26:06 +0530100static bool debug_bus_voting_enabled;
Pavankumar Kondeti2aec9f32012-06-13 09:06:03 +0530101static bool mhl_det_in_progress;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700102
Anji jonnala11aa5c42011-05-04 10:19:48 +0530103static struct regulator *hsusb_3p3;
104static struct regulator *hsusb_1p8;
Mayank Rana0f286cf2013-02-27 11:43:27 +0530105static struct regulator *hsusb_vdd;
Mayank Ranae3926882011-12-26 09:47:54 +0530106static struct regulator *vbus_otg;
Pavankumar Kondeti56dc7422012-07-02 12:45:19 +0530107static struct regulator *mhl_usb_hs_switch;
Vijayavardhan Vennapusa05c437c2012-05-25 16:20:46 +0530108static struct power_supply *psy;
Anji jonnala11aa5c42011-05-04 10:19:48 +0530109
Pavankumar Kondeti4960f312011-12-06 15:46:14 +0530110static bool aca_id_turned_on;
David Keitel272ce522012-08-17 16:25:24 -0700111static bool legacy_power_supply;
Pavankumar Kondetiaa449e12011-11-04 11:09:26 +0530112static inline bool aca_enabled(void)
Anji jonnala11aa5c42011-05-04 10:19:48 +0530113{
Pavankumar Kondetiaa449e12011-11-04 11:09:26 +0530114#ifdef CONFIG_USB_MSM_ACA
115 return true;
116#else
117 return debug_aca_enabled;
118#endif
Anji jonnala11aa5c42011-05-04 10:19:48 +0530119}
120
Mayank Rana0f286cf2013-02-27 11:43:27 +0530121static int vdd_val[VDD_TYPE_MAX][VDD_VAL_MAX] = {
Mayank Rana248698c2012-04-19 00:03:16 +0530122 { /* VDD_CX CORNER Voting */
123 [VDD_NONE] = RPM_VREG_CORNER_NONE,
124 [VDD_MIN] = RPM_VREG_CORNER_NOMINAL,
125 [VDD_MAX] = RPM_VREG_CORNER_HIGH,
126 },
127 { /* VDD_CX Voltage Voting */
128 [VDD_NONE] = USB_PHY_VDD_DIG_VOL_NONE,
129 [VDD_MIN] = USB_PHY_VDD_DIG_VOL_MIN,
130 [VDD_MAX] = USB_PHY_VDD_DIG_VOL_MAX,
131 },
132};
Anji jonnala11aa5c42011-05-04 10:19:48 +0530133
134static int msm_hsusb_ldo_init(struct msm_otg *motg, int init)
135{
136 int rc = 0;
137
138 if (init) {
Steve Mucklef132c6c2012-06-06 18:30:57 -0700139 hsusb_3p3 = devm_regulator_get(motg->phy.dev, "HSUSB_3p3");
Anji jonnala11aa5c42011-05-04 10:19:48 +0530140 if (IS_ERR(hsusb_3p3)) {
Heikki Krogerus1d4c9292012-02-13 13:24:09 +0200141 dev_err(motg->phy.dev, "unable to get hsusb 3p3\n");
Anji jonnala11aa5c42011-05-04 10:19:48 +0530142 return PTR_ERR(hsusb_3p3);
143 }
144
145 rc = regulator_set_voltage(hsusb_3p3, USB_PHY_3P3_VOL_MIN,
146 USB_PHY_3P3_VOL_MAX);
147 if (rc) {
Steve Mucklef132c6c2012-06-06 18:30:57 -0700148 dev_err(motg->phy.dev, "unable to set voltage level for"
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700149 "hsusb 3p3\n");
Mayank Rana9e9a2ac2012-03-24 04:05:28 +0530150 return rc;
Anji jonnala11aa5c42011-05-04 10:19:48 +0530151 }
Steve Mucklef132c6c2012-06-06 18:30:57 -0700152 hsusb_1p8 = devm_regulator_get(motg->phy.dev, "HSUSB_1p8");
Anji jonnala11aa5c42011-05-04 10:19:48 +0530153 if (IS_ERR(hsusb_1p8)) {
Heikki Krogerus1d4c9292012-02-13 13:24:09 +0200154 dev_err(motg->phy.dev, "unable to get hsusb 1p8\n");
Anji jonnala11aa5c42011-05-04 10:19:48 +0530155 rc = PTR_ERR(hsusb_1p8);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700156 goto put_3p3_lpm;
Anji jonnala11aa5c42011-05-04 10:19:48 +0530157 }
158 rc = regulator_set_voltage(hsusb_1p8, USB_PHY_1P8_VOL_MIN,
159 USB_PHY_1P8_VOL_MAX);
160 if (rc) {
Stephen Boyd9850acb2013-01-28 14:11:20 -0800161 dev_err(motg->phy.dev, "unable to set voltage level "
162 "for hsusb 1p8\n");
Anji jonnala11aa5c42011-05-04 10:19:48 +0530163 goto put_1p8;
164 }
165
166 return 0;
167 }
168
Anji jonnala11aa5c42011-05-04 10:19:48 +0530169put_1p8:
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700170 regulator_set_voltage(hsusb_1p8, 0, USB_PHY_1P8_VOL_MAX);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700171put_3p3_lpm:
172 regulator_set_voltage(hsusb_3p3, 0, USB_PHY_3P3_VOL_MAX);
Anji jonnala11aa5c42011-05-04 10:19:48 +0530173 return rc;
174}
175
Pavankumar Kondeti04aebcb2011-05-04 10:19:49 +0530176static int msm_hsusb_config_vddcx(int high)
177{
Mayank Rana248698c2012-04-19 00:03:16 +0530178 struct msm_otg *motg = the_msm_otg;
179 enum usb_vdd_type vdd_type = motg->vdd_type;
180 int max_vol = vdd_val[vdd_type][VDD_MAX];
Pavankumar Kondeti04aebcb2011-05-04 10:19:49 +0530181 int min_vol;
182 int ret;
183
Mayank Rana248698c2012-04-19 00:03:16 +0530184 min_vol = vdd_val[vdd_type][!!high];
Mayank Rana0f286cf2013-02-27 11:43:27 +0530185 ret = regulator_set_voltage(hsusb_vdd, min_vol, max_vol);
Pavankumar Kondeti04aebcb2011-05-04 10:19:49 +0530186 if (ret) {
187 pr_err("%s: unable to set the voltage for regulator "
188 "HSUSB_VDDCX\n", __func__);
189 return ret;
190 }
191
192 pr_debug("%s: min_vol:%d max_vol:%d\n", __func__, min_vol, max_vol);
193
194 return ret;
195}
Pavankumar Kondeti04aebcb2011-05-04 10:19:49 +0530196
Amit Blay81801aa2012-09-19 12:08:12 +0200197static int msm_hsusb_ldo_enable(struct msm_otg *motg,
198 enum msm_otg_phy_reg_mode mode)
Anji jonnala11aa5c42011-05-04 10:19:48 +0530199{
200 int ret = 0;
201
Pavankumar Kondeti68964c92011-10-27 14:58:56 +0530202 if (IS_ERR(hsusb_1p8)) {
Anji jonnala11aa5c42011-05-04 10:19:48 +0530203 pr_err("%s: HSUSB_1p8 is not initialized\n", __func__);
204 return -ENODEV;
205 }
206
Pavankumar Kondeti68964c92011-10-27 14:58:56 +0530207 if (IS_ERR(hsusb_3p3)) {
Anji jonnala11aa5c42011-05-04 10:19:48 +0530208 pr_err("%s: HSUSB_3p3 is not initialized\n", __func__);
209 return -ENODEV;
210 }
211
Amit Blay81801aa2012-09-19 12:08:12 +0200212 switch (mode) {
213 case USB_PHY_REG_ON:
Anji jonnala11aa5c42011-05-04 10:19:48 +0530214 ret = regulator_set_optimum_mode(hsusb_1p8,
215 USB_PHY_1P8_HPM_LOAD);
216 if (ret < 0) {
Stephen Boyd9850acb2013-01-28 14:11:20 -0800217 pr_err("%s: Unable to set HPM of the regulator "
Anji jonnala11aa5c42011-05-04 10:19:48 +0530218 "HSUSB_1p8\n", __func__);
219 return ret;
220 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700221
222 ret = regulator_enable(hsusb_1p8);
223 if (ret) {
Steve Mucklef132c6c2012-06-06 18:30:57 -0700224 dev_err(motg->phy.dev, "%s: unable to enable the hsusb 1p8\n",
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700225 __func__);
226 regulator_set_optimum_mode(hsusb_1p8, 0);
227 return ret;
228 }
229
Anji jonnala11aa5c42011-05-04 10:19:48 +0530230 ret = regulator_set_optimum_mode(hsusb_3p3,
231 USB_PHY_3P3_HPM_LOAD);
232 if (ret < 0) {
Stephen Boyd9850acb2013-01-28 14:11:20 -0800233 pr_err("%s: Unable to set HPM of the regulator "
Anji jonnala11aa5c42011-05-04 10:19:48 +0530234 "HSUSB_3p3\n", __func__);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700235 regulator_set_optimum_mode(hsusb_1p8, 0);
236 regulator_disable(hsusb_1p8);
Anji jonnala11aa5c42011-05-04 10:19:48 +0530237 return ret;
238 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700239
240 ret = regulator_enable(hsusb_3p3);
241 if (ret) {
Steve Mucklef132c6c2012-06-06 18:30:57 -0700242 dev_err(motg->phy.dev, "%s: unable to enable the hsusb 3p3\n",
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700243 __func__);
244 regulator_set_optimum_mode(hsusb_3p3, 0);
245 regulator_set_optimum_mode(hsusb_1p8, 0);
246 regulator_disable(hsusb_1p8);
247 return ret;
248 }
249
Amit Blay81801aa2012-09-19 12:08:12 +0200250 break;
251
252 case USB_PHY_REG_OFF:
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700253 ret = regulator_disable(hsusb_1p8);
254 if (ret) {
Steve Mucklef132c6c2012-06-06 18:30:57 -0700255 dev_err(motg->phy.dev, "%s: unable to disable the hsusb 1p8\n",
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700256 __func__);
257 return ret;
258 }
259
260 ret = regulator_set_optimum_mode(hsusb_1p8, 0);
Anji jonnala11aa5c42011-05-04 10:19:48 +0530261 if (ret < 0)
Stephen Boyd9850acb2013-01-28 14:11:20 -0800262 pr_err("%s: Unable to set LPM of the regulator "
Anji jonnala11aa5c42011-05-04 10:19:48 +0530263 "HSUSB_1p8\n", __func__);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700264
265 ret = regulator_disable(hsusb_3p3);
266 if (ret) {
Steve Mucklef132c6c2012-06-06 18:30:57 -0700267 dev_err(motg->phy.dev, "%s: unable to disable the hsusb 3p3\n",
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700268 __func__);
269 return ret;
270 }
271 ret = regulator_set_optimum_mode(hsusb_3p3, 0);
Anji jonnala11aa5c42011-05-04 10:19:48 +0530272 if (ret < 0)
Stephen Boyd9850acb2013-01-28 14:11:20 -0800273 pr_err("%s: Unable to set LPM of the regulator "
Anji jonnala11aa5c42011-05-04 10:19:48 +0530274 "HSUSB_3p3\n", __func__);
Amit Blay81801aa2012-09-19 12:08:12 +0200275
276 break;
277
278 case USB_PHY_REG_LPM_ON:
279 ret = regulator_set_optimum_mode(hsusb_1p8,
280 USB_PHY_1P8_LPM_LOAD);
281 if (ret < 0) {
282 pr_err("%s: Unable to set LPM of the regulator: HSUSB_1p8\n",
283 __func__);
284 return ret;
285 }
286
287 ret = regulator_set_optimum_mode(hsusb_3p3,
288 USB_PHY_3P3_LPM_LOAD);
289 if (ret < 0) {
290 pr_err("%s: Unable to set LPM of the regulator: HSUSB_3p3\n",
291 __func__);
292 regulator_set_optimum_mode(hsusb_1p8, USB_PHY_REG_ON);
293 return ret;
294 }
295
296 break;
297
298 case USB_PHY_REG_LPM_OFF:
299 ret = regulator_set_optimum_mode(hsusb_1p8,
300 USB_PHY_1P8_HPM_LOAD);
301 if (ret < 0) {
302 pr_err("%s: Unable to set HPM of the regulator: HSUSB_1p8\n",
303 __func__);
304 return ret;
305 }
306
307 ret = regulator_set_optimum_mode(hsusb_3p3,
308 USB_PHY_3P3_HPM_LOAD);
309 if (ret < 0) {
310 pr_err("%s: Unable to set HPM of the regulator: HSUSB_3p3\n",
311 __func__);
312 regulator_set_optimum_mode(hsusb_1p8, USB_PHY_REG_ON);
313 return ret;
314 }
315
316 break;
317
318 default:
319 pr_err("%s: Unsupported mode (%d).", __func__, mode);
320 return -ENOTSUPP;
Anji jonnala11aa5c42011-05-04 10:19:48 +0530321 }
322
Amit Blay81801aa2012-09-19 12:08:12 +0200323 pr_debug("%s: USB reg mode (%d) (OFF/HPM/LPM)\n", __func__, mode);
Anji jonnala11aa5c42011-05-04 10:19:48 +0530324 return ret < 0 ? ret : 0;
325}
326
Vijayavardhan Vennapusafc464f02011-11-04 21:54:00 +0530327static void msm_hsusb_mhl_switch_enable(struct msm_otg *motg, bool on)
328{
Vijayavardhan Vennapusafc464f02011-11-04 21:54:00 +0530329 struct msm_otg_platform_data *pdata = motg->pdata;
330
331 if (!pdata->mhl_enable)
332 return;
333
Pavankumar Kondeti56dc7422012-07-02 12:45:19 +0530334 if (!mhl_usb_hs_switch) {
335 pr_err("%s: mhl_usb_hs_switch is NULL.\n", __func__);
Vijayavardhan Vennapusafc464f02011-11-04 21:54:00 +0530336 return;
337 }
338
Mayank Rana9e9a2ac2012-03-24 04:05:28 +0530339 if (on) {
Pavankumar Kondeti56dc7422012-07-02 12:45:19 +0530340 if (regulator_enable(mhl_usb_hs_switch))
341 pr_err("unable to enable mhl_usb_hs_switch\n");
Mayank Rana9e9a2ac2012-03-24 04:05:28 +0530342 } else {
Pavankumar Kondeti56dc7422012-07-02 12:45:19 +0530343 regulator_disable(mhl_usb_hs_switch);
Mayank Rana9e9a2ac2012-03-24 04:05:28 +0530344 }
Vijayavardhan Vennapusafc464f02011-11-04 21:54:00 +0530345}
346
Heikki Krogerus1d4c9292012-02-13 13:24:09 +0200347static int ulpi_read(struct usb_phy *phy, u32 reg)
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +0530348{
Heikki Krogerus1d4c9292012-02-13 13:24:09 +0200349 struct msm_otg *motg = container_of(phy, struct msm_otg, phy);
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +0530350 int cnt = 0;
351
352 /* initiate read operation */
353 writel(ULPI_RUN | ULPI_READ | ULPI_ADDR(reg),
354 USB_ULPI_VIEWPORT);
355
356 /* wait for completion */
357 while (cnt < ULPI_IO_TIMEOUT_USEC) {
358 if (!(readl(USB_ULPI_VIEWPORT) & ULPI_RUN))
359 break;
360 udelay(1);
361 cnt++;
362 }
363
364 if (cnt >= ULPI_IO_TIMEOUT_USEC) {
Heikki Krogerus1d4c9292012-02-13 13:24:09 +0200365 dev_err(phy->dev, "ulpi_read: timeout %08x\n",
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +0530366 readl(USB_ULPI_VIEWPORT));
Mayank Ranab95838b2013-07-31 14:36:35 +0530367 dev_err(phy->dev, "PORTSC: %08x USBCMD: %08x\n",
368 readl_relaxed(USB_PORTSC), readl_relaxed(USB_USBCMD));
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +0530369 return -ETIMEDOUT;
370 }
371 return ULPI_DATA_READ(readl(USB_ULPI_VIEWPORT));
372}
373
Heikki Krogerus1d4c9292012-02-13 13:24:09 +0200374static int ulpi_write(struct usb_phy *phy, u32 val, u32 reg)
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +0530375{
Heikki Krogerus1d4c9292012-02-13 13:24:09 +0200376 struct msm_otg *motg = container_of(phy, struct msm_otg, phy);
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +0530377 int cnt = 0;
378
379 /* initiate write operation */
380 writel(ULPI_RUN | ULPI_WRITE |
381 ULPI_ADDR(reg) | ULPI_DATA(val),
382 USB_ULPI_VIEWPORT);
383
384 /* wait for completion */
385 while (cnt < ULPI_IO_TIMEOUT_USEC) {
386 if (!(readl(USB_ULPI_VIEWPORT) & ULPI_RUN))
387 break;
388 udelay(1);
389 cnt++;
390 }
391
392 if (cnt >= ULPI_IO_TIMEOUT_USEC) {
Heikki Krogerus1d4c9292012-02-13 13:24:09 +0200393 dev_err(phy->dev, "ulpi_write: timeout\n");
Mayank Ranab95838b2013-07-31 14:36:35 +0530394 dev_err(phy->dev, "PORTSC: %08x USBCMD: %08x\n",
395 readl_relaxed(USB_PORTSC), readl_relaxed(USB_USBCMD));
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +0530396 return -ETIMEDOUT;
397 }
398 return 0;
399}
400
Heikki Krogerus1d4c9292012-02-13 13:24:09 +0200401static struct usb_phy_io_ops msm_otg_io_ops = {
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +0530402 .read = ulpi_read,
403 .write = ulpi_write,
404};
405
406static void ulpi_init(struct msm_otg *motg)
407{
408 struct msm_otg_platform_data *pdata = motg->pdata;
Mayank Rana443f9e42012-09-21 18:32:39 +0530409 int aseq[10];
410 int *seq = NULL;
411
412 if (override_phy_init) {
413 pr_debug("%s(): HUSB PHY Init:%s\n", __func__,
414 override_phy_init);
415 get_options(override_phy_init, ARRAY_SIZE(aseq), aseq);
416 seq = &aseq[1];
417 } else {
418 seq = pdata->phy_init_seq;
419 }
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +0530420
421 if (!seq)
422 return;
423
424 while (seq[0] >= 0) {
Mayank Rana443f9e42012-09-21 18:32:39 +0530425 if (override_phy_init)
426 pr_debug("ulpi: write 0x%02x to 0x%02x\n",
427 seq[0], seq[1]);
428
Heikki Krogerus1d4c9292012-02-13 13:24:09 +0200429 dev_vdbg(motg->phy.dev, "ulpi: write 0x%02x to 0x%02x\n",
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +0530430 seq[0], seq[1]);
Heikki Krogerus1d4c9292012-02-13 13:24:09 +0200431 ulpi_write(&motg->phy, seq[0], seq[1]);
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +0530432 seq += 2;
433 }
434}
435
436static int msm_otg_link_clk_reset(struct msm_otg *motg, bool assert)
437{
438 int ret;
439
440 if (assert) {
Manu Gautam5025ff12012-07-20 10:56:50 +0530441 if (!IS_ERR(motg->clk)) {
442 ret = clk_reset(motg->clk, CLK_RESET_ASSERT);
443 } else {
444 /* Using asynchronous block reset to the hardware */
445 dev_dbg(motg->phy.dev, "block_reset ASSERT\n");
446 clk_disable_unprepare(motg->pclk);
447 clk_disable_unprepare(motg->core_clk);
448 ret = clk_reset(motg->core_clk, CLK_RESET_ASSERT);
449 }
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +0530450 if (ret)
Heikki Krogerus1d4c9292012-02-13 13:24:09 +0200451 dev_err(motg->phy.dev, "usb hs_clk assert failed\n");
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +0530452 } else {
Manu Gautam5025ff12012-07-20 10:56:50 +0530453 if (!IS_ERR(motg->clk)) {
454 ret = clk_reset(motg->clk, CLK_RESET_DEASSERT);
455 } else {
456 dev_dbg(motg->phy.dev, "block_reset DEASSERT\n");
457 ret = clk_reset(motg->core_clk, CLK_RESET_DEASSERT);
458 ndelay(200);
Saket Saurabh784546e2014-01-28 17:37:35 +0530459 ret = clk_prepare_enable(motg->core_clk);
460 WARN(ret, "USB core_clk enable failed\n");
461 ret = clk_prepare_enable(motg->pclk);
462 WARN(ret, "USB pclk enable failed\n");
Manu Gautam5025ff12012-07-20 10:56:50 +0530463 }
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +0530464 if (ret)
Heikki Krogerus1d4c9292012-02-13 13:24:09 +0200465 dev_err(motg->phy.dev, "usb hs_clk deassert failed\n");
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +0530466 }
467 return ret;
468}
469
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +0530470static int msm_otg_phy_reset(struct msm_otg *motg)
471{
472 u32 val;
473 int ret;
Manu Gautam0fd2d0e2013-03-26 18:09:11 +0530474 struct msm_otg_platform_data *pdata = motg->pdata;
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +0530475
Mayank Rana34f6f3e2013-11-11 12:40:00 +0530476 /*
477 * AHB2AHB Bypass mode shouldn't be enable before doing
478 * async clock reset. If it is enable, disable the same.
479 */
480 val = readl_relaxed(USB_AHBMODE);
481 if (val & AHB2AHB_BYPASS) {
482 pr_err("%s(): AHB2AHB_BYPASS SET: AHBMODE:%x\n",
483 __func__, val);
484 val &= ~AHB2AHB_BYPASS_BIT_MASK;
485 writel_relaxed(val | AHB2AHB_BYPASS_CLEAR, USB_AHBMODE);
486 pr_err("%s(): AHBMODE: %x\n", __func__,
487 readl_relaxed(USB_AHBMODE));
488 }
489
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +0530490 ret = msm_otg_link_clk_reset(motg, 1);
491 if (ret)
492 return ret;
Amit Blay58dc2bc2013-01-24 12:28:03 +0200493
Mayank Ranab95838b2013-07-31 14:36:35 +0530494 /* wait for 1ms delay as suggested in HPG. */
495 usleep_range(1000, 1200);
496
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +0530497 ret = msm_otg_link_clk_reset(motg, 0);
498 if (ret)
499 return ret;
500
Manu Gautam0fd2d0e2013-03-26 18:09:11 +0530501 if (pdata && pdata->enable_sec_phy)
502 writel_relaxed(readl_relaxed(USB_PHY_CTRL2) | (1<<16),
503 USB_PHY_CTRL2);
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +0530504 val = readl(USB_PORTSC) & ~PORTSC_PTS_MASK;
505 writel(val | PORTSC_PTS_ULPI, USB_PORTSC);
506
Heikki Krogerus1d4c9292012-02-13 13:24:09 +0200507 dev_info(motg->phy.dev, "phy_reset: success\n");
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +0530508 return 0;
509}
510
511#define LINK_RESET_TIMEOUT_USEC (250 * 1000)
Pavankumar Kondetiaa449e12011-11-04 11:09:26 +0530512static int msm_otg_link_reset(struct msm_otg *motg)
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +0530513{
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +0530514 int cnt = 0;
Manu Gautam0fd2d0e2013-03-26 18:09:11 +0530515 struct msm_otg_platform_data *pdata = motg->pdata;
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +0530516
Pavankumar Kondetiaa449e12011-11-04 11:09:26 +0530517 writel_relaxed(USBCMD_RESET, USB_USBCMD);
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +0530518 while (cnt < LINK_RESET_TIMEOUT_USEC) {
Pavankumar Kondetiaa449e12011-11-04 11:09:26 +0530519 if (!(readl_relaxed(USB_USBCMD) & USBCMD_RESET))
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +0530520 break;
521 udelay(1);
522 cnt++;
523 }
524 if (cnt >= LINK_RESET_TIMEOUT_USEC)
525 return -ETIMEDOUT;
526
527 /* select ULPI phy */
Pavankumar Kondetiaa449e12011-11-04 11:09:26 +0530528 writel_relaxed(0x80000000, USB_PORTSC);
529 writel_relaxed(0x0, USB_AHBBURST);
Vijayavardhan Vennapusa5f32d7a2012-03-14 16:30:26 +0530530 writel_relaxed(0x08, USB_AHBMODE);
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +0530531
Manu Gautam0fd2d0e2013-03-26 18:09:11 +0530532 if (pdata && pdata->enable_sec_phy)
533 writel_relaxed(readl_relaxed(USB_PHY_CTRL2) | (1<<16),
534 USB_PHY_CTRL2);
Pavankumar Kondetiaa449e12011-11-04 11:09:26 +0530535 return 0;
536}
537
Mayank Ranab95838b2013-07-31 14:36:35 +0530538static void usb_phy_reset(struct msm_otg *motg)
539{
540 u32 val;
541
542 if (motg->pdata->phy_type != SNPS_28NM_INTEGRATED_PHY)
543 return;
544
545 /* Assert USB PHY_PON */
546 val = readl_relaxed(USB_PHY_CTRL);
547 val &= ~PHY_POR_BIT_MASK;
548 val |= PHY_POR_ASSERT;
549 writel_relaxed(val, USB_PHY_CTRL);
550
551 /* wait for minimum 10 microseconds as suggested in HPG. */
552 usleep_range(10, 15);
553
554 /* Deassert USB PHY_PON */
555 val = readl_relaxed(USB_PHY_CTRL);
556 val &= ~PHY_POR_BIT_MASK;
557 val |= PHY_POR_DEASSERT;
558 writel_relaxed(val, USB_PHY_CTRL);
559
560 /* Ensure that RESET operation is completed. */
561 mb();
562}
563
Steve Mucklef132c6c2012-06-06 18:30:57 -0700564static int msm_otg_reset(struct usb_phy *phy)
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +0530565{
Steve Mucklef132c6c2012-06-06 18:30:57 -0700566 struct msm_otg *motg = container_of(phy, struct msm_otg, phy);
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +0530567 struct msm_otg_platform_data *pdata = motg->pdata;
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +0530568 int ret;
569 u32 val = 0;
570 u32 ulpi_val = 0;
571
Ofir Cohen4da266f2012-01-03 10:19:29 +0200572 /*
573 * USB PHY and Link reset also reset the USB BAM.
574 * Thus perform reset operation only once to avoid
575 * USB BAM reset on other cases e.g. USB cable disconnections.
576 */
577 if (pdata->disable_reset_on_disconnect) {
578 if (motg->reset_counter)
579 return 0;
580 else
581 motg->reset_counter++;
582 }
583
Pavankumar Kondeti923262e2012-04-20 15:34:24 +0530584 if (!IS_ERR(motg->clk))
585 clk_prepare_enable(motg->clk);
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +0530586 ret = msm_otg_phy_reset(motg);
587 if (ret) {
Steve Mucklef132c6c2012-06-06 18:30:57 -0700588 dev_err(phy->dev, "phy_reset failed\n");
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +0530589 return ret;
590 }
591
Pavankumar Kondeti4960f312011-12-06 15:46:14 +0530592 aca_id_turned_on = false;
Pavankumar Kondetiaa449e12011-11-04 11:09:26 +0530593 ret = msm_otg_link_reset(motg);
594 if (ret) {
Steve Mucklef132c6c2012-06-06 18:30:57 -0700595 dev_err(phy->dev, "link reset failed\n");
Pavankumar Kondetiaa449e12011-11-04 11:09:26 +0530596 return ret;
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +0530597 }
Mayank Ranab95838b2013-07-31 14:36:35 +0530598
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +0530599 msleep(100);
600
Mayank Ranab95838b2013-07-31 14:36:35 +0530601 /* Reset USB PHY after performing USB Link RESET */
602 usb_phy_reset(motg);
603
604 /* Program USB PHY Override registers. */
Anji jonnalaa8b8d732011-12-06 10:03:24 +0530605 ulpi_init(motg);
606
Mayank Ranab95838b2013-07-31 14:36:35 +0530607 /*
608 * It is recommended in HPG to reset USB PHY after programming
609 * USB PHY Override registers.
610 */
611 usb_phy_reset(motg);
Pavankumar Kondetiaa449e12011-11-04 11:09:26 +0530612
Pavankumar Kondeti923262e2012-04-20 15:34:24 +0530613 if (!IS_ERR(motg->clk))
614 clk_disable_unprepare(motg->clk);
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +0530615
616 if (pdata->otg_control == OTG_PHY_CONTROL) {
Pavankumar Kondeti4960f312011-12-06 15:46:14 +0530617 val = readl_relaxed(USB_OTGSC);
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +0530618 if (pdata->mode == USB_OTG) {
619 ulpi_val = ULPI_INT_IDGRD | ULPI_INT_SESS_VALID;
620 val |= OTGSC_IDIE | OTGSC_BSVIE;
621 } else if (pdata->mode == USB_PERIPHERAL) {
622 ulpi_val = ULPI_INT_SESS_VALID;
623 val |= OTGSC_BSVIE;
624 }
Pavankumar Kondeti4960f312011-12-06 15:46:14 +0530625 writel_relaxed(val, USB_OTGSC);
Heikki Krogerus1d4c9292012-02-13 13:24:09 +0200626 ulpi_write(phy, ulpi_val, ULPI_USB_INT_EN_RISE);
627 ulpi_write(phy, ulpi_val, ULPI_USB_INT_EN_FALL);
Pavankumar Kondeti446f4542012-02-01 13:57:13 +0530628 } else if (pdata->otg_control == OTG_PMIC_CONTROL) {
Steve Mucklef132c6c2012-06-06 18:30:57 -0700629 ulpi_write(phy, OTG_COMP_DISABLE,
Vijayavardhan Vennapusa03171c72012-04-26 14:44:48 +0530630 ULPI_SET(ULPI_PWR_CLK_MNG_REG));
Pavankumar Kondeti446f4542012-02-01 13:57:13 +0530631 /* Enable PMIC pull-up */
632 pm8xxx_usb_id_pullup(1);
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +0530633 }
634
Saket Saurabhb06a8c62013-11-25 15:17:23 +0530635 if (motg->caps & ALLOW_VDD_MIN_WITH_RETENTION_DISABLED)
636 writel_relaxed(readl_relaxed(USB_OTGSC) & ~(OTGSC_IDPU),
637 USB_OTGSC);
638
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +0530639 return 0;
640}
641
Vijayavardhan Vennapusaa3152032012-03-05 16:29:30 +0530642static const char *timer_string(int bit)
643{
644 switch (bit) {
645 case A_WAIT_VRISE: return "a_wait_vrise";
646 case A_WAIT_VFALL: return "a_wait_vfall";
647 case B_SRP_FAIL: return "b_srp_fail";
648 case A_WAIT_BCON: return "a_wait_bcon";
649 case A_AIDL_BDIS: return "a_aidl_bdis";
650 case A_BIDL_ADIS: return "a_bidl_adis";
651 case B_ASE0_BRST: return "b_ase0_brst";
652 case A_TST_MAINT: return "a_tst_maint";
653 case B_TST_SRP: return "b_tst_srp";
654 case B_TST_CONFIG: return "b_tst_config";
655 default: return "UNDEFINED";
656 }
657}
658
659static enum hrtimer_restart msm_otg_timer_func(struct hrtimer *hrtimer)
660{
661 struct msm_otg *motg = container_of(hrtimer, struct msm_otg, timer);
662
663 switch (motg->active_tmout) {
664 case A_WAIT_VRISE:
665 /* TODO: use vbus_vld interrupt */
666 set_bit(A_VBUS_VLD, &motg->inputs);
667 break;
668 case A_TST_MAINT:
669 /* OTG PET: End session after TA_TST_MAINT */
670 set_bit(A_BUS_DROP, &motg->inputs);
671 break;
672 case B_TST_SRP:
673 /*
674 * OTG PET: Initiate SRP after TB_TST_SRP of
675 * previous session end.
676 */
677 set_bit(B_BUS_REQ, &motg->inputs);
678 break;
679 case B_TST_CONFIG:
680 clear_bit(A_CONN, &motg->inputs);
681 break;
682 default:
683 set_bit(motg->active_tmout, &motg->tmouts);
684 }
685
686 pr_debug("expired %s timer\n", timer_string(motg->active_tmout));
687 queue_work(system_nrt_wq, &motg->sm_work);
688 return HRTIMER_NORESTART;
689}
690
691static void msm_otg_del_timer(struct msm_otg *motg)
692{
693 int bit = motg->active_tmout;
694
695 pr_debug("deleting %s timer. remaining %lld msec\n", timer_string(bit),
696 div_s64(ktime_to_us(hrtimer_get_remaining(
697 &motg->timer)), 1000));
698 hrtimer_cancel(&motg->timer);
699 clear_bit(bit, &motg->tmouts);
700}
701
702static void msm_otg_start_timer(struct msm_otg *motg, int time, int bit)
703{
704 clear_bit(bit, &motg->tmouts);
705 motg->active_tmout = bit;
706 pr_debug("starting %s timer\n", timer_string(bit));
707 hrtimer_start(&motg->timer,
708 ktime_set(time / 1000, (time % 1000) * 1000000),
709 HRTIMER_MODE_REL);
710}
711
712static void msm_otg_init_timer(struct msm_otg *motg)
713{
714 hrtimer_init(&motg->timer, CLOCK_MONOTONIC, HRTIMER_MODE_REL);
715 motg->timer.function = msm_otg_timer_func;
716}
717
Steve Mucklef132c6c2012-06-06 18:30:57 -0700718static int msm_otg_start_hnp(struct usb_otg *otg)
Vijayavardhan Vennapusaa3152032012-03-05 16:29:30 +0530719{
Steve Mucklef132c6c2012-06-06 18:30:57 -0700720 struct msm_otg *motg = container_of(otg->phy, struct msm_otg, phy);
Vijayavardhan Vennapusaa3152032012-03-05 16:29:30 +0530721
Steve Mucklef132c6c2012-06-06 18:30:57 -0700722 if (otg->phy->state != OTG_STATE_A_HOST) {
Vijayavardhan Vennapusaa3152032012-03-05 16:29:30 +0530723 pr_err("HNP can not be initiated in %s state\n",
Steve Mucklef132c6c2012-06-06 18:30:57 -0700724 otg_state_string(otg->phy->state));
Vijayavardhan Vennapusaa3152032012-03-05 16:29:30 +0530725 return -EINVAL;
726 }
727
728 pr_debug("A-Host: HNP initiated\n");
729 clear_bit(A_BUS_REQ, &motg->inputs);
730 queue_work(system_nrt_wq, &motg->sm_work);
731 return 0;
732}
733
Steve Mucklef132c6c2012-06-06 18:30:57 -0700734static int msm_otg_start_srp(struct usb_otg *otg)
Vijayavardhan Vennapusaa3152032012-03-05 16:29:30 +0530735{
Steve Mucklef132c6c2012-06-06 18:30:57 -0700736 struct msm_otg *motg = container_of(otg->phy, struct msm_otg, phy);
Vijayavardhan Vennapusaa3152032012-03-05 16:29:30 +0530737 u32 val;
738 int ret = 0;
739
Steve Mucklef132c6c2012-06-06 18:30:57 -0700740 if (otg->phy->state != OTG_STATE_B_IDLE) {
Vijayavardhan Vennapusaa3152032012-03-05 16:29:30 +0530741 pr_err("SRP can not be initiated in %s state\n",
Steve Mucklef132c6c2012-06-06 18:30:57 -0700742 otg_state_string(otg->phy->state));
Vijayavardhan Vennapusaa3152032012-03-05 16:29:30 +0530743 ret = -EINVAL;
744 goto out;
745 }
746
747 if ((jiffies - motg->b_last_se0_sess) < msecs_to_jiffies(TB_SRP_INIT)) {
748 pr_debug("initial conditions of SRP are not met. Try again"
749 "after some time\n");
750 ret = -EAGAIN;
751 goto out;
752 }
753
754 pr_debug("B-Device SRP started\n");
755
756 /*
757 * PHY won't pull D+ high unless it detects Vbus valid.
758 * Since by definition, SRP is only done when Vbus is not valid,
759 * software work-around needs to be used to spoof the PHY into
760 * thinking it is valid. This can be done using the VBUSVLDEXTSEL and
761 * VBUSVLDEXT register bits.
762 */
Steve Mucklef132c6c2012-06-06 18:30:57 -0700763 ulpi_write(otg->phy, 0x03, 0x97);
Vijayavardhan Vennapusaa3152032012-03-05 16:29:30 +0530764 /*
765 * Harware auto assist data pulsing: Data pulse is given
766 * for 7msec; wait for vbus
767 */
768 val = readl_relaxed(USB_OTGSC);
769 writel_relaxed((val & ~OTGSC_INTSTS_MASK) | OTGSC_HADP, USB_OTGSC);
770
771 /* VBUS plusing is obsoleted in OTG 2.0 supplement */
772out:
773 return ret;
774}
775
Steve Mucklef132c6c2012-06-06 18:30:57 -0700776static void msm_otg_host_hnp_enable(struct usb_otg *otg, bool enable)
Vijayavardhan Vennapusaa3152032012-03-05 16:29:30 +0530777{
778 struct usb_hcd *hcd = bus_to_hcd(otg->host);
779 struct usb_device *rhub = otg->host->root_hub;
780
781 if (enable) {
782 pm_runtime_disable(&rhub->dev);
783 rhub->state = USB_STATE_NOTATTACHED;
784 hcd->driver->bus_suspend(hcd);
785 clear_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags);
786 } else {
787 usb_remove_hcd(hcd);
Steve Mucklef132c6c2012-06-06 18:30:57 -0700788 msm_otg_reset(otg->phy);
Vijayavardhan Vennapusaa3152032012-03-05 16:29:30 +0530789 usb_add_hcd(hcd, hcd->irq, IRQF_SHARED);
790 }
791}
792
Steve Mucklef132c6c2012-06-06 18:30:57 -0700793static int msm_otg_set_suspend(struct usb_phy *phy, int suspend)
Pavankumar Kondeti8be99cf2011-08-04 10:48:08 +0530794{
Steve Mucklef132c6c2012-06-06 18:30:57 -0700795 struct msm_otg *motg = container_of(phy, struct msm_otg, phy);
Pavankumar Kondeti8be99cf2011-08-04 10:48:08 +0530796
Amit Blay6fa647a2012-05-24 14:12:08 +0300797 if (aca_enabled())
Vijayavardhan Vennapusaa3152032012-03-05 16:29:30 +0530798 return 0;
Pavankumar Kondeti8be99cf2011-08-04 10:48:08 +0530799
Pavankumar Kondetie618bf82012-11-28 21:12:44 +0530800 /*
801 * UDC and HCD call usb_phy_set_suspend() to enter/exit LPM
802 * during bus suspend/resume. Update the relevant state
803 * machine inputs and trigger LPM entry/exit. Checking
804 * in_lpm flag would avoid unnecessary work scheduling.
805 */
Vijayavardhan Vennapusaa3152032012-03-05 16:29:30 +0530806 if (suspend) {
Steve Mucklef132c6c2012-06-06 18:30:57 -0700807 switch (phy->state) {
Vijayavardhan Vennapusaa3152032012-03-05 16:29:30 +0530808 case OTG_STATE_A_WAIT_BCON:
809 if (TA_WAIT_BCON > 0)
810 break;
811 /* fall through */
812 case OTG_STATE_A_HOST:
813 pr_debug("host bus suspend\n");
814 clear_bit(A_BUS_REQ, &motg->inputs);
Pavankumar Kondetie618bf82012-11-28 21:12:44 +0530815 if (!atomic_read(&motg->in_lpm))
816 queue_work(system_nrt_wq, &motg->sm_work);
Vijayavardhan Vennapusaa3152032012-03-05 16:29:30 +0530817 break;
Amit Blay6fa647a2012-05-24 14:12:08 +0300818 case OTG_STATE_B_PERIPHERAL:
819 pr_debug("peripheral bus suspend\n");
820 if (!(motg->caps & ALLOW_LPM_ON_DEV_SUSPEND))
821 break;
822 set_bit(A_BUS_SUSPEND, &motg->inputs);
Pavankumar Kondetie618bf82012-11-28 21:12:44 +0530823 if (!atomic_read(&motg->in_lpm))
824 queue_delayed_work(system_nrt_wq,
825 &motg->suspend_work,
826 USB_SUSPEND_DELAY_TIME);
Amit Blay6fa647a2012-05-24 14:12:08 +0300827 break;
828
Vijayavardhan Vennapusaa3152032012-03-05 16:29:30 +0530829 default:
830 break;
831 }
832 } else {
Steve Mucklef132c6c2012-06-06 18:30:57 -0700833 switch (phy->state) {
Pavankumar Kondetie618bf82012-11-28 21:12:44 +0530834 case OTG_STATE_A_WAIT_BCON:
835 /* Remote wakeup or resume */
836 set_bit(A_BUS_REQ, &motg->inputs);
837 /* ensure hardware is not in low power mode */
838 if (atomic_read(&motg->in_lpm))
839 pm_runtime_resume(phy->dev);
840 break;
Vijayavardhan Vennapusaa3152032012-03-05 16:29:30 +0530841 case OTG_STATE_A_SUSPEND:
842 /* Remote wakeup or resume */
843 set_bit(A_BUS_REQ, &motg->inputs);
Steve Mucklef132c6c2012-06-06 18:30:57 -0700844 phy->state = OTG_STATE_A_HOST;
Jack Pham5ca279b2012-05-14 18:42:54 -0700845
846 /* ensure hardware is not in low power mode */
Pavankumar Kondetie618bf82012-11-28 21:12:44 +0530847 if (atomic_read(&motg->in_lpm))
848 pm_runtime_resume(phy->dev);
Vijayavardhan Vennapusaa3152032012-03-05 16:29:30 +0530849 break;
Amit Blay6fa647a2012-05-24 14:12:08 +0300850 case OTG_STATE_B_PERIPHERAL:
851 pr_debug("peripheral bus resume\n");
852 if (!(motg->caps & ALLOW_LPM_ON_DEV_SUSPEND))
853 break;
854 clear_bit(A_BUS_SUSPEND, &motg->inputs);
Pavankumar Kondetie618bf82012-11-28 21:12:44 +0530855 if (atomic_read(&motg->in_lpm))
856 queue_work(system_nrt_wq, &motg->sm_work);
Amit Blay6fa647a2012-05-24 14:12:08 +0300857 break;
Vijayavardhan Vennapusaa3152032012-03-05 16:29:30 +0530858 default:
859 break;
860 }
861 }
Pavankumar Kondeti8be99cf2011-08-04 10:48:08 +0530862 return 0;
863}
864
Manu Gautame3a39082013-06-11 10:42:56 +0530865static void msm_otg_bus_vote(struct msm_otg *motg, enum usb_bus_vote vote)
866{
867 int ret;
868 struct msm_otg_platform_data *pdata = motg->pdata;
869
870 /* Check if target allows min_vote to be same as no_vote */
Ido Shayevitzcf050e22013-07-22 17:31:48 +0300871 if (pdata->bus_scale_table &&
872 vote >= pdata->bus_scale_table->num_usecases)
Manu Gautame3a39082013-06-11 10:42:56 +0530873 vote = USB_NO_PERF_VOTE;
874
875 if (motg->bus_perf_client) {
876 ret = msm_bus_scale_client_update_request(
877 motg->bus_perf_client, vote);
878 if (ret)
879 dev_err(motg->phy.dev, "%s: Failed to vote (%d)\n"
880 "for bus bw %d\n", __func__, vote, ret);
881 }
882}
883
Pavankumar Kondeti87c01042010-12-07 17:53:58 +0530884#define PHY_SUSPEND_TIMEOUT_USEC (500 * 1000)
Pavankumar Kondeti70187732011-02-15 09:42:34 +0530885#define PHY_RESUME_TIMEOUT_USEC (100 * 1000)
886
887#ifdef CONFIG_PM_SLEEP
Pavankumar Kondeti87c01042010-12-07 17:53:58 +0530888static int msm_otg_suspend(struct msm_otg *motg)
889{
Heikki Krogerus1d4c9292012-02-13 13:24:09 +0200890 struct usb_phy *phy = &motg->phy;
891 struct usb_bus *bus = phy->otg->host;
Pavankumar Kondeti87c01042010-12-07 17:53:58 +0530892 struct msm_otg_platform_data *pdata = motg->pdata;
893 int cnt = 0;
Pavankumar Kondeti70970b72013-05-16 13:37:24 +0530894 bool host_bus_suspend, device_bus_suspend, dcp, prop_charger;
zhenhuahb6d5edc2013-06-19 14:37:32 +0800895 bool floated_charger;
Pavankumar Kondeti4960f312011-12-06 15:46:14 +0530896 u32 phy_ctrl_val = 0, cmd_val;
Stephen Boyd30ad10b2012-03-01 14:51:04 -0800897 unsigned ret;
Pavankumar Kondetif1ffbdd2013-06-27 13:31:36 +0530898 u32 portsc, config2;
Saket Saurabhb06a8c62013-11-25 15:17:23 +0530899 u32 func_ctrl;
Pavankumar Kondeti87c01042010-12-07 17:53:58 +0530900
901 if (atomic_read(&motg->in_lpm))
902 return 0;
903
Lena Salmanabde35d2013-04-25 15:29:43 +0300904 if (motg->pdata->delay_lpm_hndshk_on_disconnect && !msm_bam_lpm_ok())
Lena Salman05b544f2013-05-13 15:49:10 +0300905 return -EBUSY;
Lena Salmanabde35d2013-04-25 15:29:43 +0300906
Sujeet Kumarceee6e82013-09-06 11:22:49 +0530907 motg->ui_enabled = 0;
Pavankumar Kondeti87c01042010-12-07 17:53:58 +0530908 disable_irq(motg->irq);
Pavankumar Kondeti2aec9f32012-06-13 09:06:03 +0530909 host_bus_suspend = !test_bit(MHL, &motg->inputs) && phy->otg->host &&
910 !test_bit(ID, &motg->inputs);
Steve Mucklef132c6c2012-06-06 18:30:57 -0700911 device_bus_suspend = phy->otg->gadget && test_bit(ID, &motg->inputs) &&
Amit Blay6fa647a2012-05-24 14:12:08 +0300912 test_bit(A_BUS_SUSPEND, &motg->inputs) &&
913 motg->caps & ALLOW_LPM_ON_DEV_SUSPEND;
Pavankumar Kondeti283146f2012-01-12 12:51:19 +0530914 dcp = motg->chg_type == USB_DCP_CHARGER;
Pavankumar Kondeti70970b72013-05-16 13:37:24 +0530915 prop_charger = motg->chg_type == USB_PROPRIETARY_CHARGER;
zhenhuahb6d5edc2013-06-19 14:37:32 +0800916 floated_charger = motg->chg_type == USB_FLOATED_CHARGER;
Jack Pham502bea32012-08-13 15:34:20 -0700917
Pavankumar Kondetif1ffbdd2013-06-27 13:31:36 +0530918 /* Enable line state difference wakeup fix for only device and host
919 * bus suspend scenarios. Otherwise PHY can not be suspended when
920 * a charger that pulls DP/DM high is connected.
921 */
922 config2 = readl_relaxed(USB_GENCONFIG2);
923 if (device_bus_suspend)
924 config2 |= GENCFG2_LINESTATE_DIFF_WAKEUP_EN;
925 else
926 config2 &= ~GENCFG2_LINESTATE_DIFF_WAKEUP_EN;
927 writel_relaxed(config2, USB_GENCONFIG2);
928
Pavankumar Kondeticfe05392012-10-22 13:21:19 +0530929 /*
930 * Abort suspend when,
931 * 1. charging detection in progress due to cable plug-in
932 * 2. host mode activation in progress due to Micro-A cable insertion
933 */
934
935 if ((test_bit(B_SESS_VLD, &motg->inputs) && !device_bus_suspend &&
zhenhuahb6d5edc2013-06-19 14:37:32 +0800936 !dcp && !prop_charger && !floated_charger) ||
937 test_bit(A_BUS_REQ, &motg->inputs)) {
Sujeet Kumarceee6e82013-09-06 11:22:49 +0530938 motg->ui_enabled = 1;
Jack Pham502bea32012-08-13 15:34:20 -0700939 enable_irq(motg->irq);
940 return -EBUSY;
941 }
942
Pavankumar Kondeti87c01042010-12-07 17:53:58 +0530943 /*
Pavankumar Kondeti04aebcb2011-05-04 10:19:49 +0530944 * Chipidea 45-nm PHY suspend sequence:
945 *
Pavankumar Kondeti87c01042010-12-07 17:53:58 +0530946 * Interrupt Latch Register auto-clear feature is not present
947 * in all PHY versions. Latch register is clear on read type.
948 * Clear latch register to avoid spurious wakeup from
949 * low power mode (LPM).
Pavankumar Kondeti04aebcb2011-05-04 10:19:49 +0530950 *
Pavankumar Kondeti87c01042010-12-07 17:53:58 +0530951 * PHY comparators are disabled when PHY enters into low power
952 * mode (LPM). Keep PHY comparators ON in LPM only when we expect
953 * VBUS/Id notifications from USB PHY. Otherwise turn off USB
954 * PHY comparators. This save significant amount of power.
Pavankumar Kondeti04aebcb2011-05-04 10:19:49 +0530955 *
Pavankumar Kondeti87c01042010-12-07 17:53:58 +0530956 * PLL is not turned off when PHY enters into low power mode (LPM).
957 * Disable PLL for maximum power savings.
958 */
Pavankumar Kondeti04aebcb2011-05-04 10:19:49 +0530959
960 if (motg->pdata->phy_type == CI_45NM_INTEGRATED_PHY) {
Heikki Krogerus1d4c9292012-02-13 13:24:09 +0200961 ulpi_read(phy, 0x14);
Pavankumar Kondeti04aebcb2011-05-04 10:19:49 +0530962 if (pdata->otg_control == OTG_PHY_CONTROL)
Heikki Krogerus1d4c9292012-02-13 13:24:09 +0200963 ulpi_write(phy, 0x01, 0x30);
964 ulpi_write(phy, 0x08, 0x09);
Pavankumar Kondeti04aebcb2011-05-04 10:19:49 +0530965 }
Pavankumar Kondeti87c01042010-12-07 17:53:58 +0530966
Saket Saurabhb06a8c62013-11-25 15:17:23 +0530967 if (motg->caps & ALLOW_VDD_MIN_WITH_RETENTION_DISABLED) {
968 /* put the controller in non-driving mode */
969 func_ctrl = ulpi_read(phy, ULPI_FUNC_CTRL);
970 func_ctrl &= ~ULPI_FUNC_CTRL_OPMODE_MASK;
971 func_ctrl |= ULPI_FUNC_CTRL_OPMODE_NONDRIVING;
972 ulpi_write(phy, func_ctrl, ULPI_FUNC_CTRL);
973 ulpi_write(phy, ULPI_IFC_CTRL_AUTORESUME,
974 ULPI_CLR(ULPI_IFC_CTRL));
975 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700976
Rajkumar Raghupathy242565d2011-12-13 12:10:59 +0530977 /* Set the PHCD bit, only if it is not set by the controller.
Pavankumar Kondeti87c01042010-12-07 17:53:58 +0530978 * PHY may take some time or even fail to enter into low power
979 * mode (LPM). Hence poll for 500 msec and reset the PHY and link
980 * in failure case.
981 */
Rajkumar Raghupathy242565d2011-12-13 12:10:59 +0530982 portsc = readl_relaxed(USB_PORTSC);
983 if (!(portsc & PORTSC_PHCD)) {
984 writel_relaxed(portsc | PORTSC_PHCD,
985 USB_PORTSC);
986 while (cnt < PHY_SUSPEND_TIMEOUT_USEC) {
987 if (readl_relaxed(USB_PORTSC) & PORTSC_PHCD)
988 break;
989 udelay(1);
990 cnt++;
991 }
Pavankumar Kondeti87c01042010-12-07 17:53:58 +0530992 }
993
994 if (cnt >= PHY_SUSPEND_TIMEOUT_USEC) {
Heikki Krogerus1d4c9292012-02-13 13:24:09 +0200995 dev_err(phy->dev, "Unable to suspend PHY\n");
996 msm_otg_reset(phy);
Sujeet Kumarceee6e82013-09-06 11:22:49 +0530997 motg->ui_enabled = 1;
Pavankumar Kondeti87c01042010-12-07 17:53:58 +0530998 enable_irq(motg->irq);
999 return -ETIMEDOUT;
1000 }
1001
1002 /*
1003 * PHY has capability to generate interrupt asynchronously in low
1004 * power mode (LPM). This interrupt is level triggered. So USB IRQ
1005 * line must be disabled till async interrupt enable bit is cleared
1006 * in USBCMD register. Assert STP (ULPI interface STOP signal) to
1007 * block data communication from PHY.
Pavankumar Kondeti6be675f2012-04-16 13:29:24 +05301008 *
1009 * PHY retention mode is disallowed while entering to LPM with wall
1010 * charger connected. But PHY is put into suspend mode. Hence
1011 * enable asynchronous interrupt to detect charger disconnection when
1012 * PMIC notifications are unavailable.
Pavankumar Kondeti87c01042010-12-07 17:53:58 +05301013 */
Pavankumar Kondeti4960f312011-12-06 15:46:14 +05301014 cmd_val = readl_relaxed(USB_USBCMD);
Amit Blay6fa647a2012-05-24 14:12:08 +03001015 if (host_bus_suspend || device_bus_suspend ||
Pavankumar Kondeti70970b72013-05-16 13:37:24 +05301016 (motg->pdata->otg_control == OTG_PHY_CONTROL))
Pavankumar Kondeti4960f312011-12-06 15:46:14 +05301017 cmd_val |= ASYNC_INTR_CTRL | ULPI_STP_CTRL;
1018 else
1019 cmd_val |= ULPI_STP_CTRL;
1020 writel_relaxed(cmd_val, USB_USBCMD);
Pavankumar Kondeti87c01042010-12-07 17:53:58 +05301021
Pavankumar Kondeti283146f2012-01-12 12:51:19 +05301022 /*
1023 * BC1.2 spec mandates PD to enable VDP_SRC when charging from DCP.
1024 * PHY retention and collapse can not happen with VDP_SRC enabled.
1025 */
Vijayavardhan Vennapusa2239b2b2013-06-28 13:16:29 +05301026 if (motg->caps & ALLOW_PHY_RETENTION && !device_bus_suspend && !dcp &&
Vijayavardhan Vennapusa8997e332013-07-15 09:53:51 +05301027 (!host_bus_suspend || ((motg->caps & ALLOW_HOST_PHY_RETENTION)
1028 && (pdata->dpdm_pulldown_added || !(portsc & PORTSC_CCS))))) {
Amit Blay58b31472011-11-18 09:39:39 +02001029 phy_ctrl_val = readl_relaxed(USB_PHY_CTRL);
Vijayavardhan Vennapusa9ab6f972012-10-11 19:18:55 +05301030 if (motg->pdata->otg_control == OTG_PHY_CONTROL) {
Amit Blay58b31472011-11-18 09:39:39 +02001031 /* Enable PHY HV interrupts to wake MPM/Link */
Vijayavardhan Vennapusa9ab6f972012-10-11 19:18:55 +05301032 if ((motg->pdata->mode == USB_OTG) ||
1033 (motg->pdata->mode == USB_HOST))
1034 phy_ctrl_val |= (PHY_IDHV_INTEN |
1035 PHY_OTGSESSVLDHV_INTEN);
1036 else
1037 phy_ctrl_val |= PHY_OTGSESSVLDHV_INTEN;
1038 }
Vijayavardhan Vennapusa2239b2b2013-06-28 13:16:29 +05301039 if (host_bus_suspend)
1040 phy_ctrl_val |= PHY_CLAMP_DPDMSE_EN;
Saket Saurabhb06a8c62013-11-25 15:17:23 +05301041
1042 if (!(motg->caps & ALLOW_VDD_MIN_WITH_RETENTION_DISABLED)) {
1043 writel_relaxed(phy_ctrl_val & ~PHY_RETEN, USB_PHY_CTRL);
1044 motg->lpm_flags |= PHY_RETENTIONED;
1045 } else {
1046 writel_relaxed(phy_ctrl_val, USB_PHY_CTRL);
1047 }
Pavankumar Kondeti04aebcb2011-05-04 10:19:49 +05301048 }
1049
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001050 /* Ensure that above operation is completed before turning off clocks */
1051 mb();
Ido Shayevitzc5c0f572012-07-31 13:58:45 +03001052 /* Consider clocks on workaround flag only in case of bus suspend */
1053 if (!(phy->state == OTG_STATE_B_PERIPHERAL &&
1054 test_bit(A_BUS_SUSPEND, &motg->inputs)) ||
1055 !motg->pdata->core_clk_always_on_workaround) {
Amit Blay9b6e58b2012-06-18 13:12:49 +03001056 clk_disable_unprepare(motg->pclk);
1057 clk_disable_unprepare(motg->core_clk);
Ido Shayevitzc5c0f572012-07-31 13:58:45 +03001058 motg->lpm_flags |= CLOCKS_DOWN;
Amit Blay9b6e58b2012-06-18 13:12:49 +03001059 }
Pavankumar Kondeti87c01042010-12-07 17:53:58 +05301060
Anji jonnala7da3f262011-12-02 17:22:14 -08001061 /* usb phy no more require TCXO clock, hence vote for TCXO disable */
Vijayavardhan Vennapusa8997e332013-07-15 09:53:51 +05301062 if (!host_bus_suspend || ((motg->caps & ALLOW_HOST_PHY_RETENTION) &&
1063 (pdata->dpdm_pulldown_added || !(portsc & PORTSC_CCS)))) {
Vijayavardhan Vennapusa0cab6172013-02-20 19:51:15 +05301064 if (!IS_ERR(motg->xo_clk)) {
1065 clk_disable_unprepare(motg->xo_clk);
Vijayavardhan Vennapusabbdd6082012-06-06 14:14:25 +05301066 motg->lpm_flags |= XO_SHUTDOWN;
Vijayavardhan Vennapusa0cab6172013-02-20 19:51:15 +05301067 } else {
1068 ret = msm_xo_mode_vote(motg->xo_handle,
1069 MSM_XO_MODE_OFF);
1070 if (ret)
1071 dev_err(phy->dev, "%s fail to devote XO %d\n",
1072 __func__, ret);
1073 else
1074 motg->lpm_flags |= XO_SHUTDOWN;
1075 }
Vijayavardhan Vennapusabbdd6082012-06-06 14:14:25 +05301076 }
Anji jonnala7da3f262011-12-02 17:22:14 -08001077
Pavankumar Kondeti283146f2012-01-12 12:51:19 +05301078 if (motg->caps & ALLOW_PHY_POWER_COLLAPSE &&
1079 !host_bus_suspend && !dcp) {
Amit Blay81801aa2012-09-19 12:08:12 +02001080 msm_hsusb_ldo_enable(motg, USB_PHY_REG_OFF);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001081 motg->lpm_flags |= PHY_PWR_COLLAPSED;
Amit Blay81801aa2012-09-19 12:08:12 +02001082 } else if (motg->caps & ALLOW_PHY_REGULATORS_LPM &&
1083 !host_bus_suspend && !device_bus_suspend && !dcp) {
1084 msm_hsusb_ldo_enable(motg, USB_PHY_REG_LPM_ON);
1085 motg->lpm_flags |= PHY_REGULATORS_LPM;
Anji jonnala0f73cac2011-05-04 10:19:46 +05301086 }
1087
Saket Saurabhb06a8c62013-11-25 15:17:23 +05301088 if (motg->lpm_flags & PHY_RETENTIONED ||
1089 (motg->caps & ALLOW_VDD_MIN_WITH_RETENTION_DISABLED)) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001090 msm_hsusb_config_vddcx(0);
Vijayavardhan Vennapusafc464f02011-11-04 21:54:00 +05301091 msm_hsusb_mhl_switch_enable(motg, 0);
1092 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001093
Steve Mucklef132c6c2012-06-06 18:30:57 -07001094 if (device_may_wakeup(phy->dev)) {
Manu Gautamf8c45642012-08-10 10:20:56 -07001095 if (motg->async_irq)
1096 enable_irq_wake(motg->async_irq);
Jack Phamd110a5a2013-02-21 13:34:48 -08001097 else
1098 enable_irq_wake(motg->irq);
1099
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001100 if (motg->pdata->pmic_id_irq)
1101 enable_irq_wake(motg->pdata->pmic_id_irq);
Jack Pham87f202f2012-08-06 00:24:22 -07001102 if (pdata->otg_control == OTG_PHY_CONTROL &&
1103 pdata->mpm_otgsessvld_int)
1104 msm_mpm_set_pin_wake(pdata->mpm_otgsessvld_int, 1);
Vijayavardhan Vennapusa2239b2b2013-06-28 13:16:29 +05301105 if (host_bus_suspend && pdata->mpm_dpshv_int)
1106 msm_mpm_set_pin_wake(pdata->mpm_dpshv_int, 1);
1107 if (host_bus_suspend && pdata->mpm_dmshv_int)
1108 msm_mpm_set_pin_wake(pdata->mpm_dmshv_int, 1);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001109 }
Pavankumar Kondeti87c01042010-12-07 17:53:58 +05301110 if (bus)
1111 clear_bit(HCD_FLAG_HW_ACCESSIBLE, &(bus_to_hcd(bus))->flags);
1112
Manu Gautame3a39082013-06-11 10:42:56 +05301113 msm_otg_bus_vote(motg, USB_NO_PERF_VOTE);
1114
Vijayavardhan Vennapusa2239b2b2013-06-28 13:16:29 +05301115 motg->host_bus_suspend = host_bus_suspend;
Pavankumar Kondeti87c01042010-12-07 17:53:58 +05301116 atomic_set(&motg->in_lpm, 1);
Manu Gautamf8c45642012-08-10 10:20:56 -07001117 /* Enable ASYNC IRQ (if present) during LPM */
1118 if (motg->async_irq)
1119 enable_irq(motg->async_irq);
Sujeet Kumarceee6e82013-09-06 11:22:49 +05301120
1121 /* XO shutdown during idle , non wakeable irqs must be disabled */
1122 if (device_bus_suspend || host_bus_suspend || !motg->async_irq) {
1123 motg->ui_enabled = 1;
1124 enable_irq(motg->irq);
1125 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001126 wake_unlock(&motg->wlock);
Pavankumar Kondeti87c01042010-12-07 17:53:58 +05301127
Heikki Krogerus1d4c9292012-02-13 13:24:09 +02001128 dev_info(phy->dev, "USB in low power mode\n");
Pavankumar Kondeti87c01042010-12-07 17:53:58 +05301129
1130 return 0;
1131}
1132
Pavankumar Kondeti87c01042010-12-07 17:53:58 +05301133static int msm_otg_resume(struct msm_otg *motg)
1134{
Heikki Krogerus1d4c9292012-02-13 13:24:09 +02001135 struct usb_phy *phy = &motg->phy;
1136 struct usb_bus *bus = phy->otg->host;
Jack Pham87f202f2012-08-06 00:24:22 -07001137 struct msm_otg_platform_data *pdata = motg->pdata;
Pavankumar Kondeti87c01042010-12-07 17:53:58 +05301138 int cnt = 0;
1139 unsigned temp;
Amit Blay58b31472011-11-18 09:39:39 +02001140 u32 phy_ctrl_val = 0;
Anji jonnala7da3f262011-12-02 17:22:14 -08001141 unsigned ret;
Saket Saurabhb06a8c62013-11-25 15:17:23 +05301142 u32 func_ctrl;
Pavankumar Kondeti87c01042010-12-07 17:53:58 +05301143
1144 if (!atomic_read(&motg->in_lpm))
1145 return 0;
1146
Ido Shayevitz44ca03c2013-07-09 15:57:21 +03001147 if (motg->pdata->delay_lpm_hndshk_on_disconnect)
1148 msm_bam_notify_lpm_resume();
1149
Sujeet Kumarceee6e82013-09-06 11:22:49 +05301150 if (motg->ui_enabled) {
1151 motg->ui_enabled = 0;
1152 disable_irq(motg->irq);
1153 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001154 wake_lock(&motg->wlock);
Anji jonnala0f73cac2011-05-04 10:19:46 +05301155
Manu Gautame3a39082013-06-11 10:42:56 +05301156 /* Some platforms require BUS vote to enable/disable clocks */
1157 msm_otg_bus_vote(motg, USB_MIN_PERF_VOTE);
1158
Anji jonnala7da3f262011-12-02 17:22:14 -08001159 /* Vote for TCXO when waking up the phy */
Vijayavardhan Vennapusabbdd6082012-06-06 14:14:25 +05301160 if (motg->lpm_flags & XO_SHUTDOWN) {
Vijayavardhan Vennapusa0cab6172013-02-20 19:51:15 +05301161 if (!IS_ERR(motg->xo_clk)) {
1162 clk_prepare_enable(motg->xo_clk);
1163 } else {
1164 ret = msm_xo_mode_vote(motg->xo_handle, MSM_XO_MODE_ON);
1165 if (ret)
1166 dev_err(phy->dev, "%s fail to vote for XO %d\n",
1167 __func__, ret);
1168 }
Vijayavardhan Vennapusabbdd6082012-06-06 14:14:25 +05301169 motg->lpm_flags &= ~XO_SHUTDOWN;
1170 }
Pavankumar Kondeti87c01042010-12-07 17:53:58 +05301171
Ido Shayevitzc5c0f572012-07-31 13:58:45 +03001172 if (motg->lpm_flags & CLOCKS_DOWN) {
Saket Saurabh784546e2014-01-28 17:37:35 +05301173 ret = clk_prepare_enable(motg->core_clk);
1174 WARN(ret, "USB core_clk enable failed\n");
1175 ret = clk_prepare_enable(motg->pclk);
1176 WARN(ret, "USB pclk enable failed\n");
Ido Shayevitzc5c0f572012-07-31 13:58:45 +03001177 motg->lpm_flags &= ~CLOCKS_DOWN;
Amit Blay9b6e58b2012-06-18 13:12:49 +03001178 }
Pavankumar Kondeti87c01042010-12-07 17:53:58 +05301179
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001180 if (motg->lpm_flags & PHY_PWR_COLLAPSED) {
Amit Blay81801aa2012-09-19 12:08:12 +02001181 msm_hsusb_ldo_enable(motg, USB_PHY_REG_ON);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001182 motg->lpm_flags &= ~PHY_PWR_COLLAPSED;
Amit Blay81801aa2012-09-19 12:08:12 +02001183 } else if (motg->lpm_flags & PHY_REGULATORS_LPM) {
1184 msm_hsusb_ldo_enable(motg, USB_PHY_REG_LPM_OFF);
1185 motg->lpm_flags &= ~PHY_REGULATORS_LPM;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001186 }
1187
Saket Saurabhb06a8c62013-11-25 15:17:23 +05301188 if (motg->lpm_flags & PHY_RETENTIONED ||
1189 (motg->caps & ALLOW_VDD_MIN_WITH_RETENTION_DISABLED)) {
Vijayavardhan Vennapusafc464f02011-11-04 21:54:00 +05301190 msm_hsusb_mhl_switch_enable(motg, 1);
Pavankumar Kondeti04aebcb2011-05-04 10:19:49 +05301191 msm_hsusb_config_vddcx(1);
Amit Blay58b31472011-11-18 09:39:39 +02001192 phy_ctrl_val = readl_relaxed(USB_PHY_CTRL);
1193 phy_ctrl_val |= PHY_RETEN;
1194 if (motg->pdata->otg_control == OTG_PHY_CONTROL)
1195 /* Disable PHY HV interrupts */
1196 phy_ctrl_val &=
1197 ~(PHY_IDHV_INTEN | PHY_OTGSESSVLDHV_INTEN);
Vijayavardhan Vennapusa2239b2b2013-06-28 13:16:29 +05301198 phy_ctrl_val &= ~(PHY_CLAMP_DPDMSE_EN);
Amit Blay58b31472011-11-18 09:39:39 +02001199 writel_relaxed(phy_ctrl_val, USB_PHY_CTRL);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001200 motg->lpm_flags &= ~PHY_RETENTIONED;
Pavankumar Kondeti04aebcb2011-05-04 10:19:49 +05301201 }
1202
Pavankumar Kondeti87c01042010-12-07 17:53:58 +05301203 temp = readl(USB_USBCMD);
1204 temp &= ~ASYNC_INTR_CTRL;
1205 temp &= ~ULPI_STP_CTRL;
1206 writel(temp, USB_USBCMD);
1207
1208 /*
1209 * PHY comes out of low power mode (LPM) in case of wakeup
1210 * from asynchronous interrupt.
1211 */
1212 if (!(readl(USB_PORTSC) & PORTSC_PHCD))
1213 goto skip_phy_resume;
1214
1215 writel(readl(USB_PORTSC) & ~PORTSC_PHCD, USB_PORTSC);
1216 while (cnt < PHY_RESUME_TIMEOUT_USEC) {
1217 if (!(readl(USB_PORTSC) & PORTSC_PHCD))
1218 break;
1219 udelay(1);
1220 cnt++;
1221 }
1222
1223 if (cnt >= PHY_RESUME_TIMEOUT_USEC) {
1224 /*
1225 * This is a fatal error. Reset the link and
1226 * PHY. USB state can not be restored. Re-insertion
1227 * of USB cable is the only way to get USB working.
1228 */
Heikki Krogerus1d4c9292012-02-13 13:24:09 +02001229 dev_err(phy->dev, "Unable to resume USB."
Pavankumar Kondeti87c01042010-12-07 17:53:58 +05301230 "Re-plugin the cable\n");
Heikki Krogerus1d4c9292012-02-13 13:24:09 +02001231 msm_otg_reset(phy);
Pavankumar Kondeti87c01042010-12-07 17:53:58 +05301232 }
1233
1234skip_phy_resume:
Saket Saurabhb06a8c62013-11-25 15:17:23 +05301235 if (motg->caps & ALLOW_VDD_MIN_WITH_RETENTION_DISABLED) {
1236 /* put the controller in normal mode */
1237 func_ctrl = ulpi_read(phy, ULPI_FUNC_CTRL);
1238 func_ctrl &= ~ULPI_FUNC_CTRL_OPMODE_MASK;
1239 func_ctrl |= ULPI_FUNC_CTRL_OPMODE_NORMAL;
1240 ulpi_write(phy, func_ctrl, ULPI_FUNC_CTRL);
1241 }
1242
Steve Mucklef132c6c2012-06-06 18:30:57 -07001243 if (device_may_wakeup(phy->dev)) {
Manu Gautamf8c45642012-08-10 10:20:56 -07001244 if (motg->async_irq)
1245 disable_irq_wake(motg->async_irq);
Jack Phamd110a5a2013-02-21 13:34:48 -08001246 else
1247 disable_irq_wake(motg->irq);
1248
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001249 if (motg->pdata->pmic_id_irq)
1250 disable_irq_wake(motg->pdata->pmic_id_irq);
Jack Pham87f202f2012-08-06 00:24:22 -07001251 if (pdata->otg_control == OTG_PHY_CONTROL &&
1252 pdata->mpm_otgsessvld_int)
1253 msm_mpm_set_pin_wake(pdata->mpm_otgsessvld_int, 0);
Vijayavardhan Vennapusa2239b2b2013-06-28 13:16:29 +05301254 if (motg->host_bus_suspend && pdata->mpm_dpshv_int)
1255 msm_mpm_set_pin_wake(pdata->mpm_dpshv_int, 0);
1256 if (motg->host_bus_suspend && pdata->mpm_dmshv_int)
1257 msm_mpm_set_pin_wake(pdata->mpm_dmshv_int, 0);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001258 }
Pavankumar Kondeti87c01042010-12-07 17:53:58 +05301259 if (bus)
1260 set_bit(HCD_FLAG_HW_ACCESSIBLE, &(bus_to_hcd(bus))->flags);
1261
Pavankumar Kondeti2ce2c3a2011-05-02 11:56:33 +05301262 atomic_set(&motg->in_lpm, 0);
1263
Pavankumar Kondeti87c01042010-12-07 17:53:58 +05301264 if (motg->async_int) {
Manu Gautamf8c45642012-08-10 10:20:56 -07001265 /* Match the disable_irq call from ISR */
1266 enable_irq(motg->async_int);
Pavankumar Kondeti87c01042010-12-07 17:53:58 +05301267 motg->async_int = 0;
Pavankumar Kondeti87c01042010-12-07 17:53:58 +05301268 }
Sujeet Kumarceee6e82013-09-06 11:22:49 +05301269 motg->ui_enabled = 1;
Jack Pham8978b892012-10-17 16:31:39 -07001270 enable_irq(motg->irq);
Pavankumar Kondeti87c01042010-12-07 17:53:58 +05301271
Manu Gautamf8c45642012-08-10 10:20:56 -07001272 /* If ASYNC IRQ is present then keep it enabled only during LPM */
1273 if (motg->async_irq)
1274 disable_irq(motg->async_irq);
1275
Heikki Krogerus1d4c9292012-02-13 13:24:09 +02001276 dev_info(phy->dev, "USB exited from low power mode\n");
Pavankumar Kondeti87c01042010-12-07 17:53:58 +05301277
1278 return 0;
1279}
Pavankumar Kondeti70187732011-02-15 09:42:34 +05301280#endif
Pavankumar Kondeti87c01042010-12-07 17:53:58 +05301281
David Keitel272ce522012-08-17 16:25:24 -07001282static void msm_otg_notify_host_mode(struct msm_otg *motg, bool host_mode)
Abhijeet Dharmapurikar5e96aaa2012-06-26 11:21:03 -07001283{
Jack Pham0c695282012-10-19 18:13:03 -07001284 if (!psy) {
David Keitel272ce522012-08-17 16:25:24 -07001285 pr_err("No USB power supply registered!\n");
1286 return;
1287 }
Sridhar Parasuram3c67a412012-09-26 09:36:22 -07001288
Jack Pham0c695282012-10-19 18:13:03 -07001289 if (legacy_power_supply) {
David Keitel272ce522012-08-17 16:25:24 -07001290 /* legacy support */
Pavankumar Kondeti811cab32012-11-09 20:51:36 +05301291 if (host_mode) {
David Keitel272ce522012-08-17 16:25:24 -07001292 power_supply_set_scope(psy, POWER_SUPPLY_SCOPE_SYSTEM);
Pavankumar Kondeti811cab32012-11-09 20:51:36 +05301293 } else {
David Keitel272ce522012-08-17 16:25:24 -07001294 power_supply_set_scope(psy, POWER_SUPPLY_SCOPE_DEVICE);
Pavankumar Kondeti811cab32012-11-09 20:51:36 +05301295 /*
1296 * VBUS comparator is disabled by PMIC charging driver
1297 * when SYSTEM scope is selected. For ID_GND->ID_A
1298 * transition, give 50 msec delay so that PMIC charger
1299 * driver detect the VBUS and ready for accepting
1300 * charging current value from USB.
1301 */
1302 if (test_bit(ID_A, &motg->inputs))
1303 msleep(50);
1304 }
David Keitel272ce522012-08-17 16:25:24 -07001305 } else {
1306 motg->host_mode = host_mode;
Jack Pham0c695282012-10-19 18:13:03 -07001307 power_supply_changed(psy);
David Keitel272ce522012-08-17 16:25:24 -07001308 }
Abhijeet Dharmapurikar5e96aaa2012-06-26 11:21:03 -07001309}
1310
David Keitel081a3e22012-04-18 12:37:07 -07001311static int msm_otg_notify_chg_type(struct msm_otg *motg)
1312{
1313 static int charger_type;
David Keitelba8f8322012-06-01 17:14:10 -07001314
David Keitel081a3e22012-04-18 12:37:07 -07001315 /*
1316 * TODO
1317 * Unify OTG driver charger types and power supply charger types
1318 */
1319 if (charger_type == motg->chg_type)
1320 return 0;
1321
1322 if (motg->chg_type == USB_SDP_CHARGER)
1323 charger_type = POWER_SUPPLY_TYPE_USB;
1324 else if (motg->chg_type == USB_CDP_CHARGER)
1325 charger_type = POWER_SUPPLY_TYPE_USB_CDP;
Pavankumar Kondeti9ec21d32012-05-07 15:50:23 +05301326 else if (motg->chg_type == USB_DCP_CHARGER ||
Zhenhua Huang504ce782013-11-14 12:29:58 +08001327 motg->chg_type == USB_PROPRIETARY_CHARGER ||
1328 motg->chg_type == USB_FLOATED_CHARGER)
David Keitel081a3e22012-04-18 12:37:07 -07001329 charger_type = POWER_SUPPLY_TYPE_USB_DCP;
1330 else if ((motg->chg_type == USB_ACA_DOCK_CHARGER ||
1331 motg->chg_type == USB_ACA_A_CHARGER ||
1332 motg->chg_type == USB_ACA_B_CHARGER ||
1333 motg->chg_type == USB_ACA_C_CHARGER))
1334 charger_type = POWER_SUPPLY_TYPE_USB_ACA;
1335 else
Anirudh Ghayal685a6a52013-01-08 18:28:55 +05301336 charger_type = POWER_SUPPLY_TYPE_UNKNOWN;
David Keitel081a3e22012-04-18 12:37:07 -07001337
Jack Pham0c695282012-10-19 18:13:03 -07001338 if (!psy) {
David Keitelba8f8322012-06-01 17:14:10 -07001339 pr_err("No USB power supply registered!\n");
1340 return -EINVAL;
1341 }
1342
1343 pr_debug("setting usb power supply type %d\n", charger_type);
Jack Pham0c695282012-10-19 18:13:03 -07001344 power_supply_set_supply_type(psy, charger_type);
David Keitelba8f8322012-06-01 17:14:10 -07001345 return 0;
David Keitel081a3e22012-04-18 12:37:07 -07001346}
1347
Amit Blay0f7edf72012-01-15 10:11:27 +02001348static int msm_otg_notify_power_supply(struct msm_otg *motg, unsigned mA)
1349{
Jack Pham0c695282012-10-19 18:13:03 -07001350 if (!psy) {
David Keitel272ce522012-08-17 16:25:24 -07001351 dev_dbg(motg->phy.dev, "no usb power supply registered\n");
1352 goto psy_error;
David Keitelf5c5d602012-08-17 16:25:24 -07001353 }
1354
David Keitel272ce522012-08-17 16:25:24 -07001355 if (motg->cur_power == 0 && mA > 2) {
1356 /* Enable charging */
Jack Pham0c695282012-10-19 18:13:03 -07001357 if (power_supply_set_online(psy, true))
David Keitel272ce522012-08-17 16:25:24 -07001358 goto psy_error;
Jack Pham0c695282012-10-19 18:13:03 -07001359 if (power_supply_set_current_limit(psy, 1000*mA))
David Keitel272ce522012-08-17 16:25:24 -07001360 goto psy_error;
1361 } else if (motg->cur_power > 0 && (mA == 0 || mA == 2)) {
1362 /* Disable charging */
Jack Pham0c695282012-10-19 18:13:03 -07001363 if (power_supply_set_online(psy, false))
David Keitel272ce522012-08-17 16:25:24 -07001364 goto psy_error;
1365 /* Set max current limit */
Jack Pham0c695282012-10-19 18:13:03 -07001366 if (power_supply_set_current_limit(psy, 0))
David Keitel272ce522012-08-17 16:25:24 -07001367 goto psy_error;
Manu Gautamfca298c2013-06-05 15:11:54 +05301368 } else {
1369 if (power_supply_set_online(psy, true))
1370 goto psy_error;
1371 /* Current has changed (100/2 --> 500) */
1372 if (power_supply_set_current_limit(psy, 1000*mA))
1373 goto psy_error;
David Keitel272ce522012-08-17 16:25:24 -07001374 }
Manu Gautamfca298c2013-06-05 15:11:54 +05301375
Jack Pham0c695282012-10-19 18:13:03 -07001376 power_supply_changed(psy);
Amit Blay0f7edf72012-01-15 10:11:27 +02001377 return 0;
1378
David Keitel272ce522012-08-17 16:25:24 -07001379psy_error:
1380 dev_dbg(motg->phy.dev, "power supply error when setting property\n");
Amit Blay0f7edf72012-01-15 10:11:27 +02001381 return -ENXIO;
1382}
1383
Saket Saurabh228bc952014-03-26 12:13:37 +05301384static void msm_otg_set_online_status(struct msm_otg *motg)
1385{
1386 if (!psy)
1387 dev_dbg(motg->phy.dev, "no usb power supply registered\n");
1388
1389 /* Set power supply online status to false */
1390 if (power_supply_set_online(psy, false))
1391 dev_dbg(motg->phy.dev, "error setting power supply property\n");
1392}
1393
Pavankumar Kondetid8608522011-05-04 10:19:47 +05301394static void msm_otg_notify_charger(struct msm_otg *motg, unsigned mA)
1395{
Steve Mucklef132c6c2012-06-06 18:30:57 -07001396 struct usb_gadget *g = motg->phy.otg->gadget;
Vijayavardhan Vennapusaa3152032012-03-05 16:29:30 +05301397
1398 if (g && g->is_a_peripheral)
1399 return;
1400
Pavankumar Kondetiaa449e12011-11-04 11:09:26 +05301401 if ((motg->chg_type == USB_ACA_DOCK_CHARGER ||
1402 motg->chg_type == USB_ACA_A_CHARGER ||
1403 motg->chg_type == USB_ACA_B_CHARGER ||
1404 motg->chg_type == USB_ACA_C_CHARGER) &&
1405 mA > IDEV_ACA_CHG_LIMIT)
1406 mA = IDEV_ACA_CHG_LIMIT;
1407
David Keitel081a3e22012-04-18 12:37:07 -07001408 if (msm_otg_notify_chg_type(motg))
Steve Mucklef132c6c2012-06-06 18:30:57 -07001409 dev_err(motg->phy.dev,
David Keitel081a3e22012-04-18 12:37:07 -07001410 "Failed notifying %d charger type to PMIC\n",
1411 motg->chg_type);
1412
Saket Saurabh228bc952014-03-26 12:13:37 +05301413 /*
1414 * This condition will be true when usb cable is disconnected
1415 * during bootup before charger detection mechanism starts.
1416 */
1417 if (motg->online && motg->cur_power == 0 && mA == 0)
1418 msm_otg_set_online_status(motg);
1419
Pavankumar Kondetid8608522011-05-04 10:19:47 +05301420 if (motg->cur_power == mA)
1421 return;
1422
Heikki Krogerus1d4c9292012-02-13 13:24:09 +02001423 dev_info(motg->phy.dev, "Avail curr from USB = %u\n", mA);
Amit Blay0f7edf72012-01-15 10:11:27 +02001424
1425 /*
1426 * Use Power Supply API if supported, otherwise fallback
1427 * to legacy pm8921 API.
1428 */
1429 if (msm_otg_notify_power_supply(motg, mA))
1430 pm8921_charger_vbus_draw(mA);
1431
Pavankumar Kondetid8608522011-05-04 10:19:47 +05301432 motg->cur_power = mA;
1433}
1434
Heikki Krogerus1d4c9292012-02-13 13:24:09 +02001435static int msm_otg_set_power(struct usb_phy *phy, unsigned mA)
Pavankumar Kondetid8608522011-05-04 10:19:47 +05301436{
Heikki Krogerus1d4c9292012-02-13 13:24:09 +02001437 struct msm_otg *motg = container_of(phy, struct msm_otg, phy);
Pavankumar Kondetid8608522011-05-04 10:19:47 +05301438
1439 /*
1440 * Gadget driver uses set_power method to notify about the
1441 * available current based on suspend/configured states.
1442 *
1443 * IDEV_CHG can be drawn irrespective of suspend/un-configured
1444 * states when CDP/ACA is connected.
1445 */
1446 if (motg->chg_type == USB_SDP_CHARGER)
1447 msm_otg_notify_charger(motg, mA);
1448
1449 return 0;
1450}
1451
Steve Mucklef132c6c2012-06-06 18:30:57 -07001452static void msm_otg_start_host(struct usb_otg *otg, int on)
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05301453{
Steve Mucklef132c6c2012-06-06 18:30:57 -07001454 struct msm_otg *motg = container_of(otg->phy, struct msm_otg, phy);
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05301455 struct msm_otg_platform_data *pdata = motg->pdata;
1456 struct usb_hcd *hcd;
1457
1458 if (!otg->host)
1459 return;
1460
1461 hcd = bus_to_hcd(otg->host);
1462
1463 if (on) {
Steve Mucklef132c6c2012-06-06 18:30:57 -07001464 dev_dbg(otg->phy->dev, "host on\n");
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05301465
Vijayavardhan Vennapusa03171c72012-04-26 14:44:48 +05301466 if (pdata->otg_control == OTG_PHY_CONTROL)
Steve Mucklef132c6c2012-06-06 18:30:57 -07001467 ulpi_write(otg->phy, OTG_COMP_DISABLE,
Vijayavardhan Vennapusa03171c72012-04-26 14:44:48 +05301468 ULPI_SET(ULPI_PWR_CLK_MNG_REG));
1469
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05301470 /*
1471 * Some boards have a switch cotrolled by gpio
1472 * to enable/disable internal HUB. Enable internal
1473 * HUB before kicking the host.
1474 */
1475 if (pdata->setup_gpio)
1476 pdata->setup_gpio(OTG_STATE_A_HOST);
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05301477 usb_add_hcd(hcd, hcd->irq, IRQF_SHARED);
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05301478 } else {
Steve Mucklef132c6c2012-06-06 18:30:57 -07001479 dev_dbg(otg->phy->dev, "host off\n");
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05301480
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05301481 usb_remove_hcd(hcd);
Pavankumar Kondetiaa449e12011-11-04 11:09:26 +05301482 /* HCD core reset all bits of PORTSC. select ULPI phy */
1483 writel_relaxed(0x80000000, USB_PORTSC);
1484
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05301485 if (pdata->setup_gpio)
1486 pdata->setup_gpio(OTG_STATE_UNDEFINED);
Vijayavardhan Vennapusa03171c72012-04-26 14:44:48 +05301487
1488 if (pdata->otg_control == OTG_PHY_CONTROL)
Steve Mucklef132c6c2012-06-06 18:30:57 -07001489 ulpi_write(otg->phy, OTG_COMP_DISABLE,
Vijayavardhan Vennapusa03171c72012-04-26 14:44:48 +05301490 ULPI_CLR(ULPI_PWR_CLK_MNG_REG));
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05301491 }
1492}
1493
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001494static int msm_otg_usbdev_notify(struct notifier_block *self,
1495 unsigned long action, void *priv)
1496{
1497 struct msm_otg *motg = container_of(self, struct msm_otg, usbdev_nb);
Steve Mucklef132c6c2012-06-06 18:30:57 -07001498 struct usb_otg *otg = motg->phy.otg;
Pavankumar Kondetiaa449e12011-11-04 11:09:26 +05301499 struct usb_device *udev = priv;
1500
Pavankumar Kondetiaa449e12011-11-04 11:09:26 +05301501 if (action == USB_BUS_ADD || action == USB_BUS_REMOVE)
1502 goto out;
1503
Steve Mucklef132c6c2012-06-06 18:30:57 -07001504 if (udev->bus != otg->host)
Pavankumar Kondetiaa449e12011-11-04 11:09:26 +05301505 goto out;
1506 /*
1507 * Interested in devices connected directly to the root hub.
1508 * ACA dock can supply IDEV_CHG irrespective devices connected
1509 * on the accessory port.
1510 */
1511 if (!udev->parent || udev->parent->parent ||
1512 motg->chg_type == USB_ACA_DOCK_CHARGER)
1513 goto out;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001514
1515 switch (action) {
1516 case USB_DEVICE_ADD:
Vijayavardhan Vennapusaa3152032012-03-05 16:29:30 +05301517 if (aca_enabled())
1518 usb_disable_autosuspend(udev);
Steve Mucklef132c6c2012-06-06 18:30:57 -07001519 if (otg->phy->state == OTG_STATE_A_WAIT_BCON) {
Vijayavardhan Vennapusaa3152032012-03-05 16:29:30 +05301520 pr_debug("B_CONN set\n");
1521 set_bit(B_CONN, &motg->inputs);
1522 msm_otg_del_timer(motg);
Steve Mucklef132c6c2012-06-06 18:30:57 -07001523 otg->phy->state = OTG_STATE_A_HOST;
Vijayavardhan Vennapusaa3152032012-03-05 16:29:30 +05301524 /*
1525 * OTG PET: A-device must end session within
1526 * 10 sec after PET enumeration.
1527 */
1528 if (udev->quirks & USB_QUIRK_OTG_PET)
1529 msm_otg_start_timer(motg, TA_TST_MAINT,
1530 A_TST_MAINT);
1531 }
Pavankumar Kondetiaa449e12011-11-04 11:09:26 +05301532 /* fall through */
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001533 case USB_DEVICE_CONFIG:
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001534 if (udev->actconfig)
1535 motg->mA_port = udev->actconfig->desc.bMaxPower * 2;
1536 else
1537 motg->mA_port = IUNIT;
Steve Mucklef132c6c2012-06-06 18:30:57 -07001538 if (otg->phy->state == OTG_STATE_B_HOST)
Vijayavardhan Vennapusaa3152032012-03-05 16:29:30 +05301539 msm_otg_del_timer(motg);
Pavankumar Kondetiaa449e12011-11-04 11:09:26 +05301540 break;
1541 case USB_DEVICE_REMOVE:
Steve Mucklef132c6c2012-06-06 18:30:57 -07001542 if ((otg->phy->state == OTG_STATE_A_HOST) ||
1543 (otg->phy->state == OTG_STATE_A_SUSPEND)) {
Vijayavardhan Vennapusaa3152032012-03-05 16:29:30 +05301544 pr_debug("B_CONN clear\n");
1545 clear_bit(B_CONN, &motg->inputs);
1546 /*
1547 * OTG PET: A-device must end session after
1548 * PET disconnection if it is enumerated
1549 * with bcdDevice[0] = 1. USB core sets
1550 * bus->otg_vbus_off for us. clear it here.
1551 */
1552 if (udev->bus->otg_vbus_off) {
1553 udev->bus->otg_vbus_off = 0;
1554 set_bit(A_BUS_DROP, &motg->inputs);
1555 }
1556 queue_work(system_nrt_wq, &motg->sm_work);
1557 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001558 default:
1559 break;
1560 }
Pavankumar Kondetiaa449e12011-11-04 11:09:26 +05301561 if (test_bit(ID_A, &motg->inputs))
1562 msm_otg_notify_charger(motg, IDEV_ACA_CHG_MAX -
1563 motg->mA_port);
1564out:
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001565 return NOTIFY_OK;
1566}
1567
Mayank Ranae3926882011-12-26 09:47:54 +05301568static void msm_hsusb_vbus_power(struct msm_otg *motg, bool on)
1569{
1570 int ret;
1571 static bool vbus_is_on;
1572
1573 if (vbus_is_on == on)
1574 return;
1575
1576 if (motg->pdata->vbus_power) {
Mayank Rana91f597e2012-01-20 10:12:06 +05301577 ret = motg->pdata->vbus_power(on);
1578 if (!ret)
1579 vbus_is_on = on;
Mayank Ranae3926882011-12-26 09:47:54 +05301580 return;
1581 }
1582
1583 if (!vbus_otg) {
1584 pr_err("vbus_otg is NULL.");
1585 return;
1586 }
1587
Abhijeet Dharmapurikarbe054882012-01-03 20:27:07 -08001588 /*
1589 * if entering host mode tell the charger to not draw any current
Abhijeet Dharmapurikar6d941212012-03-05 10:30:56 -08001590 * from usb before turning on the boost.
1591 * if exiting host mode disable the boost before enabling to draw
1592 * current from the source.
Abhijeet Dharmapurikarbe054882012-01-03 20:27:07 -08001593 */
Mayank Ranae3926882011-12-26 09:47:54 +05301594 if (on) {
Abhijeet Dharmapurikar5e96aaa2012-06-26 11:21:03 -07001595 msm_otg_notify_host_mode(motg, on);
Mayank Ranae3926882011-12-26 09:47:54 +05301596 ret = regulator_enable(vbus_otg);
1597 if (ret) {
1598 pr_err("unable to enable vbus_otg\n");
1599 return;
1600 }
1601 vbus_is_on = true;
1602 } else {
1603 ret = regulator_disable(vbus_otg);
1604 if (ret) {
1605 pr_err("unable to disable vbus_otg\n");
1606 return;
1607 }
Abhijeet Dharmapurikar5e96aaa2012-06-26 11:21:03 -07001608 msm_otg_notify_host_mode(motg, on);
Mayank Ranae3926882011-12-26 09:47:54 +05301609 vbus_is_on = false;
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05301610 }
1611}
1612
Heikki Krogerus1d4c9292012-02-13 13:24:09 +02001613static int msm_otg_set_host(struct usb_otg *otg, struct usb_bus *host)
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05301614{
Heikki Krogerus1d4c9292012-02-13 13:24:09 +02001615 struct msm_otg *motg = container_of(otg->phy, struct msm_otg, phy);
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05301616 struct usb_hcd *hcd;
1617
1618 /*
1619 * Fail host registration if this board can support
1620 * only peripheral configuration.
1621 */
1622 if (motg->pdata->mode == USB_PERIPHERAL) {
Heikki Krogerus1d4c9292012-02-13 13:24:09 +02001623 dev_info(otg->phy->dev, "Host mode is not supported\n");
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05301624 return -ENODEV;
1625 }
1626
Mayank Ranae3926882011-12-26 09:47:54 +05301627 if (!motg->pdata->vbus_power && host) {
Steve Mucklef132c6c2012-06-06 18:30:57 -07001628 vbus_otg = devm_regulator_get(motg->phy.dev, "vbus_otg");
Mayank Ranae3926882011-12-26 09:47:54 +05301629 if (IS_ERR(vbus_otg)) {
1630 pr_err("Unable to get vbus_otg\n");
Manu Gautam139a8132013-06-04 16:46:50 +05301631 return PTR_ERR(vbus_otg);
Mayank Ranae3926882011-12-26 09:47:54 +05301632 }
1633 }
1634
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05301635 if (!host) {
Heikki Krogerus1d4c9292012-02-13 13:24:09 +02001636 if (otg->phy->state == OTG_STATE_A_HOST) {
1637 pm_runtime_get_sync(otg->phy->dev);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001638 usb_unregister_notify(&motg->usbdev_nb);
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05301639 msm_otg_start_host(otg, 0);
Mayank Ranae3926882011-12-26 09:47:54 +05301640 msm_hsusb_vbus_power(motg, 0);
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05301641 otg->host = NULL;
Heikki Krogerus1d4c9292012-02-13 13:24:09 +02001642 otg->phy->state = OTG_STATE_UNDEFINED;
Vijayavardhan Vennapusaa3152032012-03-05 16:29:30 +05301643 queue_work(system_nrt_wq, &motg->sm_work);
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05301644 } else {
1645 otg->host = NULL;
1646 }
1647
1648 return 0;
1649 }
1650
1651 hcd = bus_to_hcd(host);
1652 hcd->power_budget = motg->pdata->power_budget;
1653
Vijayavardhan Vennapusaa3152032012-03-05 16:29:30 +05301654#ifdef CONFIG_USB_OTG
1655 host->otg_port = 1;
1656#endif
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001657 motg->usbdev_nb.notifier_call = msm_otg_usbdev_notify;
1658 usb_register_notify(&motg->usbdev_nb);
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05301659 otg->host = host;
Heikki Krogerus1d4c9292012-02-13 13:24:09 +02001660 dev_dbg(otg->phy->dev, "host driver registered w/ tranceiver\n");
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05301661
1662 /*
1663 * Kick the state machine work, if peripheral is not supported
1664 * or peripheral is already registered with us.
1665 */
Pavankumar Kondeti87c01042010-12-07 17:53:58 +05301666 if (motg->pdata->mode == USB_HOST || otg->gadget) {
Heikki Krogerus1d4c9292012-02-13 13:24:09 +02001667 pm_runtime_get_sync(otg->phy->dev);
Vijayavardhan Vennapusaa3152032012-03-05 16:29:30 +05301668 queue_work(system_nrt_wq, &motg->sm_work);
Pavankumar Kondeti87c01042010-12-07 17:53:58 +05301669 }
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05301670
1671 return 0;
1672}
1673
Steve Mucklef132c6c2012-06-06 18:30:57 -07001674static void msm_otg_start_peripheral(struct usb_otg *otg, int on)
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05301675{
Steve Mucklef132c6c2012-06-06 18:30:57 -07001676 struct msm_otg *motg = container_of(otg->phy, struct msm_otg, phy);
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05301677 struct msm_otg_platform_data *pdata = motg->pdata;
1678
1679 if (!otg->gadget)
1680 return;
1681
1682 if (on) {
Steve Mucklef132c6c2012-06-06 18:30:57 -07001683 dev_dbg(otg->phy->dev, "gadget on\n");
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05301684 /*
1685 * Some boards have a switch cotrolled by gpio
1686 * to enable/disable internal HUB. Disable internal
1687 * HUB before kicking the gadget.
1688 */
1689 if (pdata->setup_gpio)
1690 pdata->setup_gpio(OTG_STATE_B_PERIPHERAL);
Ofir Cohen94213a72012-05-03 14:26:32 +03001691
Manu Gautamcd82e9d2011-12-20 14:17:28 +05301692 /* Configure BUS performance parameters for MAX bandwidth */
Manu Gautame3a39082013-06-11 10:42:56 +05301693 if (debug_bus_voting_enabled)
1694 msm_otg_bus_vote(motg, USB_MAX_PERF_VOTE);
1695
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05301696 usb_gadget_vbus_connect(otg->gadget);
1697 } else {
Steve Mucklef132c6c2012-06-06 18:30:57 -07001698 dev_dbg(otg->phy->dev, "gadget off\n");
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05301699 usb_gadget_vbus_disconnect(otg->gadget);
Manu Gautamcd82e9d2011-12-20 14:17:28 +05301700 /* Configure BUS performance parameters to default */
Manu Gautame3a39082013-06-11 10:42:56 +05301701 msm_otg_bus_vote(motg, USB_MIN_PERF_VOTE);
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05301702 if (pdata->setup_gpio)
1703 pdata->setup_gpio(OTG_STATE_UNDEFINED);
1704 }
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05301705}
1706
Heikki Krogerus1d4c9292012-02-13 13:24:09 +02001707static int msm_otg_set_peripheral(struct usb_otg *otg,
Stephen Boyd9850acb2013-01-28 14:11:20 -08001708 struct usb_gadget *gadget)
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05301709{
Heikki Krogerus1d4c9292012-02-13 13:24:09 +02001710 struct msm_otg *motg = container_of(otg->phy, struct msm_otg, phy);
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05301711
1712 /*
1713 * Fail peripheral registration if this board can support
1714 * only host configuration.
1715 */
1716 if (motg->pdata->mode == USB_HOST) {
Heikki Krogerus1d4c9292012-02-13 13:24:09 +02001717 dev_info(otg->phy->dev, "Peripheral mode is not supported\n");
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05301718 return -ENODEV;
1719 }
1720
1721 if (!gadget) {
Heikki Krogerus1d4c9292012-02-13 13:24:09 +02001722 if (otg->phy->state == OTG_STATE_B_PERIPHERAL) {
1723 pm_runtime_get_sync(otg->phy->dev);
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05301724 msm_otg_start_peripheral(otg, 0);
1725 otg->gadget = NULL;
Heikki Krogerus1d4c9292012-02-13 13:24:09 +02001726 otg->phy->state = OTG_STATE_UNDEFINED;
Vijayavardhan Vennapusaa3152032012-03-05 16:29:30 +05301727 queue_work(system_nrt_wq, &motg->sm_work);
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05301728 } else {
1729 otg->gadget = NULL;
1730 }
1731
1732 return 0;
1733 }
1734 otg->gadget = gadget;
Heikki Krogerus1d4c9292012-02-13 13:24:09 +02001735 dev_dbg(otg->phy->dev, "peripheral driver registered w/ tranceiver\n");
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05301736
1737 /*
1738 * Kick the state machine work, if host is not supported
1739 * or host is already registered with us.
1740 */
Pavankumar Kondeti87c01042010-12-07 17:53:58 +05301741 if (motg->pdata->mode == USB_PERIPHERAL || otg->host) {
Heikki Krogerus1d4c9292012-02-13 13:24:09 +02001742 pm_runtime_get_sync(otg->phy->dev);
Vijayavardhan Vennapusaa3152032012-03-05 16:29:30 +05301743 queue_work(system_nrt_wq, &motg->sm_work);
Pavankumar Kondeti87c01042010-12-07 17:53:58 +05301744 }
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05301745
1746 return 0;
1747}
1748
Pavankumar Kondetibecab5b2012-11-06 16:45:10 +05301749static bool msm_otg_read_pmic_id_state(struct msm_otg *motg)
1750{
1751 unsigned long flags;
1752 int id;
1753
1754 if (!motg->pdata->pmic_id_irq)
1755 return -ENODEV;
1756
1757 local_irq_save(flags);
1758 id = irq_read_line(motg->pdata->pmic_id_irq);
1759 local_irq_restore(flags);
1760
1761 /*
1762 * If we can not read ID line state for some reason, treat
1763 * it as float. This would prevent MHL discovery and kicking
1764 * host mode unnecessarily.
1765 */
1766 return !!id;
1767}
1768
Pavankumar Kondeti2aec9f32012-06-13 09:06:03 +05301769static int msm_otg_mhl_register_callback(struct msm_otg *motg,
1770 void (*callback)(int on))
1771{
1772 struct usb_phy *phy = &motg->phy;
1773 int ret;
1774
Manoj Raoa7bddd12012-08-27 20:36:45 -07001775 if (!motg->pdata->mhl_enable) {
1776 dev_dbg(phy->dev, "MHL feature not enabled\n");
1777 return -ENODEV;
1778 }
1779
Pavankumar Kondeti2aec9f32012-06-13 09:06:03 +05301780 if (motg->pdata->otg_control != OTG_PMIC_CONTROL ||
1781 !motg->pdata->pmic_id_irq) {
1782 dev_dbg(phy->dev, "MHL can not be supported without PMIC Id\n");
1783 return -ENODEV;
1784 }
1785
1786 if (!motg->pdata->mhl_dev_name) {
1787 dev_dbg(phy->dev, "MHL device name does not exist.\n");
1788 return -ENODEV;
1789 }
1790
1791 if (callback)
1792 ret = mhl_register_callback(motg->pdata->mhl_dev_name,
1793 callback);
1794 else
1795 ret = mhl_unregister_callback(motg->pdata->mhl_dev_name);
1796
1797 if (ret)
1798 dev_dbg(phy->dev, "mhl_register_callback(%s) return error=%d\n",
1799 motg->pdata->mhl_dev_name, ret);
1800 else
1801 motg->mhl_enabled = true;
1802
1803 return ret;
1804}
1805
1806static void msm_otg_mhl_notify_online(int on)
1807{
1808 struct msm_otg *motg = the_msm_otg;
1809 struct usb_phy *phy = &motg->phy;
1810 bool queue = false;
1811
1812 dev_dbg(phy->dev, "notify MHL %s%s\n", on ? "" : "dis", "connected");
1813
1814 if (on) {
1815 set_bit(MHL, &motg->inputs);
1816 } else {
1817 clear_bit(MHL, &motg->inputs);
1818 queue = true;
1819 }
1820
1821 if (queue && phy->state != OTG_STATE_UNDEFINED)
1822 schedule_work(&motg->sm_work);
1823}
1824
1825static bool msm_otg_is_mhl(struct msm_otg *motg)
1826{
1827 struct usb_phy *phy = &motg->phy;
1828 int is_mhl, ret;
1829
1830 ret = mhl_device_discovery(motg->pdata->mhl_dev_name, &is_mhl);
1831 if (ret || is_mhl != MHL_DISCOVERY_RESULT_MHL) {
1832 /*
1833 * MHL driver calls our callback saying that MHL connected
1834 * if RID_GND is detected. But at later part of discovery
1835 * it may figure out MHL is not connected and returns
1836 * false. Hence clear MHL input here.
1837 */
1838 clear_bit(MHL, &motg->inputs);
1839 dev_dbg(phy->dev, "MHL device not found\n");
1840 return false;
1841 }
1842
1843 set_bit(MHL, &motg->inputs);
1844 dev_dbg(phy->dev, "MHL device found\n");
1845 return true;
1846}
1847
1848static bool msm_chg_mhl_detect(struct msm_otg *motg)
1849{
1850 bool ret, id;
Pavankumar Kondeti2aec9f32012-06-13 09:06:03 +05301851
1852 if (!motg->mhl_enabled)
1853 return false;
1854
Pavankumar Kondetibecab5b2012-11-06 16:45:10 +05301855 id = msm_otg_read_pmic_id_state(motg);
Pavankumar Kondeti2aec9f32012-06-13 09:06:03 +05301856
1857 if (id)
1858 return false;
1859
1860 mhl_det_in_progress = true;
1861 ret = msm_otg_is_mhl(motg);
1862 mhl_det_in_progress = false;
1863
1864 return ret;
1865}
1866
Pavankumar Kondeti458d8792012-09-28 14:45:18 +05301867static void msm_otg_chg_check_timer_func(unsigned long data)
1868{
1869 struct msm_otg *motg = (struct msm_otg *) data;
1870 struct usb_otg *otg = motg->phy.otg;
1871
1872 if (atomic_read(&motg->in_lpm) ||
1873 !test_bit(B_SESS_VLD, &motg->inputs) ||
1874 otg->phy->state != OTG_STATE_B_PERIPHERAL ||
1875 otg->gadget->speed != USB_SPEED_UNKNOWN) {
1876 dev_dbg(otg->phy->dev, "Nothing to do in chg_check_timer\n");
1877 return;
1878 }
1879
1880 if ((readl_relaxed(USB_PORTSC) & PORTSC_LS) == PORTSC_LS) {
1881 dev_dbg(otg->phy->dev, "DCP is detected as SDP\n");
1882 set_bit(B_FALSE_SDP, &motg->inputs);
1883 queue_work(system_nrt_wq, &motg->sm_work);
1884 }
1885}
1886
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001887static bool msm_chg_aca_detect(struct msm_otg *motg)
1888{
Steve Mucklef132c6c2012-06-06 18:30:57 -07001889 struct usb_phy *phy = &motg->phy;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001890 u32 int_sts;
1891 bool ret = false;
1892
Pavankumar Kondetiaa449e12011-11-04 11:09:26 +05301893 if (!aca_enabled())
1894 goto out;
1895
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001896 if (motg->pdata->phy_type == CI_45NM_INTEGRATED_PHY)
1897 goto out;
1898
Steve Mucklef132c6c2012-06-06 18:30:57 -07001899 int_sts = ulpi_read(phy, 0x87);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001900 switch (int_sts & 0x1C) {
1901 case 0x08:
1902 if (!test_and_set_bit(ID_A, &motg->inputs)) {
Steve Mucklef132c6c2012-06-06 18:30:57 -07001903 dev_dbg(phy->dev, "ID_A\n");
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001904 motg->chg_type = USB_ACA_A_CHARGER;
1905 motg->chg_state = USB_CHG_STATE_DETECTED;
1906 clear_bit(ID_B, &motg->inputs);
1907 clear_bit(ID_C, &motg->inputs);
Pavankumar Kondetiaa449e12011-11-04 11:09:26 +05301908 set_bit(ID, &motg->inputs);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001909 ret = true;
1910 }
1911 break;
1912 case 0x0C:
1913 if (!test_and_set_bit(ID_B, &motg->inputs)) {
Steve Mucklef132c6c2012-06-06 18:30:57 -07001914 dev_dbg(phy->dev, "ID_B\n");
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001915 motg->chg_type = USB_ACA_B_CHARGER;
1916 motg->chg_state = USB_CHG_STATE_DETECTED;
1917 clear_bit(ID_A, &motg->inputs);
1918 clear_bit(ID_C, &motg->inputs);
Pavankumar Kondetiaa449e12011-11-04 11:09:26 +05301919 set_bit(ID, &motg->inputs);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001920 ret = true;
1921 }
1922 break;
1923 case 0x10:
1924 if (!test_and_set_bit(ID_C, &motg->inputs)) {
Steve Mucklef132c6c2012-06-06 18:30:57 -07001925 dev_dbg(phy->dev, "ID_C\n");
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001926 motg->chg_type = USB_ACA_C_CHARGER;
1927 motg->chg_state = USB_CHG_STATE_DETECTED;
1928 clear_bit(ID_A, &motg->inputs);
1929 clear_bit(ID_B, &motg->inputs);
Pavankumar Kondetiaa449e12011-11-04 11:09:26 +05301930 set_bit(ID, &motg->inputs);
1931 ret = true;
1932 }
1933 break;
1934 case 0x04:
1935 if (test_and_clear_bit(ID, &motg->inputs)) {
Steve Mucklef132c6c2012-06-06 18:30:57 -07001936 dev_dbg(phy->dev, "ID_GND\n");
Pavankumar Kondetiaa449e12011-11-04 11:09:26 +05301937 motg->chg_type = USB_INVALID_CHARGER;
1938 motg->chg_state = USB_CHG_STATE_UNDEFINED;
1939 clear_bit(ID_A, &motg->inputs);
1940 clear_bit(ID_B, &motg->inputs);
1941 clear_bit(ID_C, &motg->inputs);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001942 ret = true;
1943 }
1944 break;
1945 default:
1946 ret = test_and_clear_bit(ID_A, &motg->inputs) |
1947 test_and_clear_bit(ID_B, &motg->inputs) |
Pavankumar Kondetiaa449e12011-11-04 11:09:26 +05301948 test_and_clear_bit(ID_C, &motg->inputs) |
1949 !test_and_set_bit(ID, &motg->inputs);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001950 if (ret) {
Steve Mucklef132c6c2012-06-06 18:30:57 -07001951 dev_dbg(phy->dev, "ID A/B/C/GND is no more\n");
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001952 motg->chg_type = USB_INVALID_CHARGER;
1953 motg->chg_state = USB_CHG_STATE_UNDEFINED;
1954 }
1955 }
1956out:
1957 return ret;
1958}
1959
1960static void msm_chg_enable_aca_det(struct msm_otg *motg)
1961{
Steve Mucklef132c6c2012-06-06 18:30:57 -07001962 struct usb_phy *phy = &motg->phy;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001963
Pavankumar Kondetiaa449e12011-11-04 11:09:26 +05301964 if (!aca_enabled())
1965 return;
1966
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001967 switch (motg->pdata->phy_type) {
1968 case SNPS_28NM_INTEGRATED_PHY:
Pavankumar Kondetiaa449e12011-11-04 11:09:26 +05301969 /* Disable ID_GND in link and PHY */
1970 writel_relaxed(readl_relaxed(USB_OTGSC) & ~(OTGSC_IDPU |
1971 OTGSC_IDIE), USB_OTGSC);
Steve Mucklef132c6c2012-06-06 18:30:57 -07001972 ulpi_write(phy, 0x01, 0x0C);
1973 ulpi_write(phy, 0x10, 0x0F);
1974 ulpi_write(phy, 0x10, 0x12);
Pavankumar Kondeti446f4542012-02-01 13:57:13 +05301975 /* Disable PMIC ID pull-up */
1976 pm8xxx_usb_id_pullup(0);
Pavankumar Kondetiaa449e12011-11-04 11:09:26 +05301977 /* Enable ACA ID detection */
Steve Mucklef132c6c2012-06-06 18:30:57 -07001978 ulpi_write(phy, 0x20, 0x85);
Pavankumar Kondeti4960f312011-12-06 15:46:14 +05301979 aca_id_turned_on = true;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001980 break;
1981 default:
1982 break;
1983 }
1984}
1985
1986static void msm_chg_enable_aca_intr(struct msm_otg *motg)
1987{
Steve Mucklef132c6c2012-06-06 18:30:57 -07001988 struct usb_phy *phy = &motg->phy;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001989
Pavankumar Kondetiaa449e12011-11-04 11:09:26 +05301990 if (!aca_enabled())
1991 return;
1992
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001993 switch (motg->pdata->phy_type) {
1994 case SNPS_28NM_INTEGRATED_PHY:
Pavankumar Kondetiaa449e12011-11-04 11:09:26 +05301995 /* Enable ACA Detection interrupt (on any RID change) */
Steve Mucklef132c6c2012-06-06 18:30:57 -07001996 ulpi_write(phy, 0x01, 0x94);
Pavankumar Kondetiaa449e12011-11-04 11:09:26 +05301997 break;
1998 default:
1999 break;
2000 }
2001}
2002
2003static void msm_chg_disable_aca_intr(struct msm_otg *motg)
2004{
Steve Mucklef132c6c2012-06-06 18:30:57 -07002005 struct usb_phy *phy = &motg->phy;
Pavankumar Kondetiaa449e12011-11-04 11:09:26 +05302006
2007 if (!aca_enabled())
2008 return;
2009
2010 switch (motg->pdata->phy_type) {
2011 case SNPS_28NM_INTEGRATED_PHY:
Steve Mucklef132c6c2012-06-06 18:30:57 -07002012 ulpi_write(phy, 0x01, 0x95);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002013 break;
2014 default:
2015 break;
2016 }
2017}
2018
2019static bool msm_chg_check_aca_intr(struct msm_otg *motg)
2020{
Steve Mucklef132c6c2012-06-06 18:30:57 -07002021 struct usb_phy *phy = &motg->phy;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002022 bool ret = false;
2023
Pavankumar Kondetiaa449e12011-11-04 11:09:26 +05302024 if (!aca_enabled())
2025 return ret;
2026
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002027 switch (motg->pdata->phy_type) {
2028 case SNPS_28NM_INTEGRATED_PHY:
Steve Mucklef132c6c2012-06-06 18:30:57 -07002029 if (ulpi_read(phy, 0x91) & 1) {
2030 dev_dbg(phy->dev, "RID change\n");
2031 ulpi_write(phy, 0x01, 0x92);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002032 ret = msm_chg_aca_detect(motg);
2033 }
2034 default:
2035 break;
2036 }
2037 return ret;
2038}
Pavankumar Kondetiaa449e12011-11-04 11:09:26 +05302039
2040static void msm_otg_id_timer_func(unsigned long data)
2041{
2042 struct msm_otg *motg = (struct msm_otg *) data;
2043
2044 if (!aca_enabled())
2045 return;
2046
2047 if (atomic_read(&motg->in_lpm)) {
Steve Mucklef132c6c2012-06-06 18:30:57 -07002048 dev_dbg(motg->phy.dev, "timer: in lpm\n");
Pavankumar Kondetiaa449e12011-11-04 11:09:26 +05302049 return;
2050 }
2051
Steve Mucklef132c6c2012-06-06 18:30:57 -07002052 if (motg->phy.state == OTG_STATE_A_SUSPEND)
Vijayavardhan Vennapusaa3152032012-03-05 16:29:30 +05302053 goto out;
2054
Pavankumar Kondetiaa449e12011-11-04 11:09:26 +05302055 if (msm_chg_check_aca_intr(motg)) {
Steve Mucklef132c6c2012-06-06 18:30:57 -07002056 dev_dbg(motg->phy.dev, "timer: aca work\n");
Vijayavardhan Vennapusaa3152032012-03-05 16:29:30 +05302057 queue_work(system_nrt_wq, &motg->sm_work);
Pavankumar Kondetiaa449e12011-11-04 11:09:26 +05302058 }
2059
Vijayavardhan Vennapusaa3152032012-03-05 16:29:30 +05302060out:
Pavankumar Kondetiaa449e12011-11-04 11:09:26 +05302061 if (!test_bit(ID, &motg->inputs) || test_bit(ID_A, &motg->inputs))
2062 mod_timer(&motg->id_timer, ID_TIMER_FREQ);
2063}
2064
Pavankumar Kondetid8608522011-05-04 10:19:47 +05302065static bool msm_chg_check_secondary_det(struct msm_otg *motg)
2066{
Heikki Krogerus1d4c9292012-02-13 13:24:09 +02002067 struct usb_phy *phy = &motg->phy;
Pavankumar Kondetid8608522011-05-04 10:19:47 +05302068 u32 chg_det;
2069 bool ret = false;
2070
2071 switch (motg->pdata->phy_type) {
2072 case CI_45NM_INTEGRATED_PHY:
Heikki Krogerus1d4c9292012-02-13 13:24:09 +02002073 chg_det = ulpi_read(phy, 0x34);
Pavankumar Kondetid8608522011-05-04 10:19:47 +05302074 ret = chg_det & (1 << 4);
2075 break;
2076 case SNPS_28NM_INTEGRATED_PHY:
Heikki Krogerus1d4c9292012-02-13 13:24:09 +02002077 chg_det = ulpi_read(phy, 0x87);
Pavankumar Kondetid8608522011-05-04 10:19:47 +05302078 ret = chg_det & 1;
2079 break;
2080 default:
2081 break;
2082 }
2083 return ret;
2084}
2085
2086static void msm_chg_enable_secondary_det(struct msm_otg *motg)
2087{
Heikki Krogerus1d4c9292012-02-13 13:24:09 +02002088 struct usb_phy *phy = &motg->phy;
Pavankumar Kondetid8608522011-05-04 10:19:47 +05302089 u32 chg_det;
2090
2091 switch (motg->pdata->phy_type) {
2092 case CI_45NM_INTEGRATED_PHY:
Heikki Krogerus1d4c9292012-02-13 13:24:09 +02002093 chg_det = ulpi_read(phy, 0x34);
Pavankumar Kondetid8608522011-05-04 10:19:47 +05302094 /* Turn off charger block */
2095 chg_det |= ~(1 << 1);
Heikki Krogerus1d4c9292012-02-13 13:24:09 +02002096 ulpi_write(phy, chg_det, 0x34);
Pavankumar Kondetid8608522011-05-04 10:19:47 +05302097 udelay(20);
2098 /* control chg block via ULPI */
2099 chg_det &= ~(1 << 3);
Heikki Krogerus1d4c9292012-02-13 13:24:09 +02002100 ulpi_write(phy, chg_det, 0x34);
Pavankumar Kondetid8608522011-05-04 10:19:47 +05302101 /* put it in host mode for enabling D- source */
2102 chg_det &= ~(1 << 2);
Heikki Krogerus1d4c9292012-02-13 13:24:09 +02002103 ulpi_write(phy, chg_det, 0x34);
Pavankumar Kondetid8608522011-05-04 10:19:47 +05302104 /* Turn on chg detect block */
2105 chg_det &= ~(1 << 1);
Heikki Krogerus1d4c9292012-02-13 13:24:09 +02002106 ulpi_write(phy, chg_det, 0x34);
Pavankumar Kondetid8608522011-05-04 10:19:47 +05302107 udelay(20);
2108 /* enable chg detection */
2109 chg_det &= ~(1 << 0);
Heikki Krogerus1d4c9292012-02-13 13:24:09 +02002110 ulpi_write(phy, chg_det, 0x34);
Pavankumar Kondetid8608522011-05-04 10:19:47 +05302111 break;
2112 case SNPS_28NM_INTEGRATED_PHY:
2113 /*
2114 * Configure DM as current source, DP as current sink
2115 * and enable battery charging comparators.
2116 */
Heikki Krogerus1d4c9292012-02-13 13:24:09 +02002117 ulpi_write(phy, 0x8, 0x85);
2118 ulpi_write(phy, 0x2, 0x85);
2119 ulpi_write(phy, 0x1, 0x85);
Pavankumar Kondetid8608522011-05-04 10:19:47 +05302120 break;
2121 default:
2122 break;
2123 }
2124}
2125
2126static bool msm_chg_check_primary_det(struct msm_otg *motg)
2127{
Heikki Krogerus1d4c9292012-02-13 13:24:09 +02002128 struct usb_phy *phy = &motg->phy;
Pavankumar Kondetid8608522011-05-04 10:19:47 +05302129 u32 chg_det;
2130 bool ret = false;
2131
2132 switch (motg->pdata->phy_type) {
2133 case CI_45NM_INTEGRATED_PHY:
Heikki Krogerus1d4c9292012-02-13 13:24:09 +02002134 chg_det = ulpi_read(phy, 0x34);
Pavankumar Kondetid8608522011-05-04 10:19:47 +05302135 ret = chg_det & (1 << 4);
2136 break;
2137 case SNPS_28NM_INTEGRATED_PHY:
Heikki Krogerus1d4c9292012-02-13 13:24:09 +02002138 chg_det = ulpi_read(phy, 0x87);
Pavankumar Kondetid8608522011-05-04 10:19:47 +05302139 ret = chg_det & 1;
Pavankumar Kondeti9ec21d32012-05-07 15:50:23 +05302140 /* Turn off VDP_SRC */
2141 ulpi_write(phy, 0x3, 0x86);
2142 msleep(20);
Pavankumar Kondetid8608522011-05-04 10:19:47 +05302143 break;
2144 default:
2145 break;
2146 }
2147 return ret;
2148}
2149
2150static void msm_chg_enable_primary_det(struct msm_otg *motg)
2151{
Heikki Krogerus1d4c9292012-02-13 13:24:09 +02002152 struct usb_phy *phy = &motg->phy;
Pavankumar Kondetid8608522011-05-04 10:19:47 +05302153 u32 chg_det;
2154
2155 switch (motg->pdata->phy_type) {
2156 case CI_45NM_INTEGRATED_PHY:
Heikki Krogerus1d4c9292012-02-13 13:24:09 +02002157 chg_det = ulpi_read(phy, 0x34);
Pavankumar Kondetid8608522011-05-04 10:19:47 +05302158 /* enable chg detection */
2159 chg_det &= ~(1 << 0);
Heikki Krogerus1d4c9292012-02-13 13:24:09 +02002160 ulpi_write(phy, chg_det, 0x34);
Pavankumar Kondetid8608522011-05-04 10:19:47 +05302161 break;
2162 case SNPS_28NM_INTEGRATED_PHY:
2163 /*
2164 * Configure DP as current source, DM as current sink
2165 * and enable battery charging comparators.
2166 */
Heikki Krogerus1d4c9292012-02-13 13:24:09 +02002167 ulpi_write(phy, 0x2, 0x85);
2168 ulpi_write(phy, 0x1, 0x85);
Pavankumar Kondetid8608522011-05-04 10:19:47 +05302169 break;
2170 default:
2171 break;
2172 }
2173}
2174
2175static bool msm_chg_check_dcd(struct msm_otg *motg)
2176{
Heikki Krogerus1d4c9292012-02-13 13:24:09 +02002177 struct usb_phy *phy = &motg->phy;
Pavankumar Kondetid8608522011-05-04 10:19:47 +05302178 u32 line_state;
2179 bool ret = false;
2180
2181 switch (motg->pdata->phy_type) {
2182 case CI_45NM_INTEGRATED_PHY:
Heikki Krogerus1d4c9292012-02-13 13:24:09 +02002183 line_state = ulpi_read(phy, 0x15);
Pavankumar Kondetid8608522011-05-04 10:19:47 +05302184 ret = !(line_state & 1);
2185 break;
2186 case SNPS_28NM_INTEGRATED_PHY:
Heikki Krogerus1d4c9292012-02-13 13:24:09 +02002187 line_state = ulpi_read(phy, 0x87);
Pavankumar Kondetid8608522011-05-04 10:19:47 +05302188 ret = line_state & 2;
2189 break;
2190 default:
2191 break;
2192 }
2193 return ret;
2194}
2195
2196static void msm_chg_disable_dcd(struct msm_otg *motg)
2197{
Heikki Krogerus1d4c9292012-02-13 13:24:09 +02002198 struct usb_phy *phy = &motg->phy;
Pavankumar Kondetid8608522011-05-04 10:19:47 +05302199 u32 chg_det;
2200
2201 switch (motg->pdata->phy_type) {
2202 case CI_45NM_INTEGRATED_PHY:
Heikki Krogerus1d4c9292012-02-13 13:24:09 +02002203 chg_det = ulpi_read(phy, 0x34);
Pavankumar Kondetid8608522011-05-04 10:19:47 +05302204 chg_det &= ~(1 << 5);
Heikki Krogerus1d4c9292012-02-13 13:24:09 +02002205 ulpi_write(phy, chg_det, 0x34);
Pavankumar Kondetid8608522011-05-04 10:19:47 +05302206 break;
2207 case SNPS_28NM_INTEGRATED_PHY:
Heikki Krogerus1d4c9292012-02-13 13:24:09 +02002208 ulpi_write(phy, 0x10, 0x86);
Pavankumar Kondetid8608522011-05-04 10:19:47 +05302209 break;
2210 default:
2211 break;
2212 }
2213}
2214
2215static void msm_chg_enable_dcd(struct msm_otg *motg)
2216{
Heikki Krogerus1d4c9292012-02-13 13:24:09 +02002217 struct usb_phy *phy = &motg->phy;
Pavankumar Kondetid8608522011-05-04 10:19:47 +05302218 u32 chg_det;
2219
2220 switch (motg->pdata->phy_type) {
2221 case CI_45NM_INTEGRATED_PHY:
Heikki Krogerus1d4c9292012-02-13 13:24:09 +02002222 chg_det = ulpi_read(phy, 0x34);
Pavankumar Kondetid8608522011-05-04 10:19:47 +05302223 /* Turn on D+ current source */
2224 chg_det |= (1 << 5);
Heikki Krogerus1d4c9292012-02-13 13:24:09 +02002225 ulpi_write(phy, chg_det, 0x34);
Pavankumar Kondetid8608522011-05-04 10:19:47 +05302226 break;
2227 case SNPS_28NM_INTEGRATED_PHY:
2228 /* Data contact detection enable */
Heikki Krogerus1d4c9292012-02-13 13:24:09 +02002229 ulpi_write(phy, 0x10, 0x85);
Pavankumar Kondetid8608522011-05-04 10:19:47 +05302230 break;
2231 default:
2232 break;
2233 }
2234}
2235
2236static void msm_chg_block_on(struct msm_otg *motg)
2237{
Heikki Krogerus1d4c9292012-02-13 13:24:09 +02002238 struct usb_phy *phy = &motg->phy;
Pavankumar Kondetid8608522011-05-04 10:19:47 +05302239 u32 func_ctrl, chg_det;
2240
2241 /* put the controller in non-driving mode */
Heikki Krogerus1d4c9292012-02-13 13:24:09 +02002242 func_ctrl = ulpi_read(phy, ULPI_FUNC_CTRL);
Pavankumar Kondetid8608522011-05-04 10:19:47 +05302243 func_ctrl &= ~ULPI_FUNC_CTRL_OPMODE_MASK;
2244 func_ctrl |= ULPI_FUNC_CTRL_OPMODE_NONDRIVING;
Heikki Krogerus1d4c9292012-02-13 13:24:09 +02002245 ulpi_write(phy, func_ctrl, ULPI_FUNC_CTRL);
Pavankumar Kondetid8608522011-05-04 10:19:47 +05302246
2247 switch (motg->pdata->phy_type) {
2248 case CI_45NM_INTEGRATED_PHY:
Heikki Krogerus1d4c9292012-02-13 13:24:09 +02002249 chg_det = ulpi_read(phy, 0x34);
Pavankumar Kondetid8608522011-05-04 10:19:47 +05302250 /* control chg block via ULPI */
2251 chg_det &= ~(1 << 3);
Heikki Krogerus1d4c9292012-02-13 13:24:09 +02002252 ulpi_write(phy, chg_det, 0x34);
Pavankumar Kondetid8608522011-05-04 10:19:47 +05302253 /* Turn on chg detect block */
2254 chg_det &= ~(1 << 1);
Heikki Krogerus1d4c9292012-02-13 13:24:09 +02002255 ulpi_write(phy, chg_det, 0x34);
Pavankumar Kondetid8608522011-05-04 10:19:47 +05302256 udelay(20);
2257 break;
2258 case SNPS_28NM_INTEGRATED_PHY:
Pavankumar Kondeti768dcb82012-10-05 13:21:45 +05302259 /* disable DP and DM pull down resistors */
2260 ulpi_write(phy, 0x6, 0xC);
Pavankumar Kondetid8608522011-05-04 10:19:47 +05302261 /* Clear charger detecting control bits */
Steve Mucklef132c6c2012-06-06 18:30:57 -07002262 ulpi_write(phy, 0x1F, 0x86);
Pavankumar Kondetid8608522011-05-04 10:19:47 +05302263 /* Clear alt interrupt latch and enable bits */
Heikki Krogerus1d4c9292012-02-13 13:24:09 +02002264 ulpi_write(phy, 0x1F, 0x92);
2265 ulpi_write(phy, 0x1F, 0x95);
Pavankumar Kondetid8608522011-05-04 10:19:47 +05302266 udelay(100);
2267 break;
2268 default:
2269 break;
2270 }
2271}
2272
2273static void msm_chg_block_off(struct msm_otg *motg)
2274{
Heikki Krogerus1d4c9292012-02-13 13:24:09 +02002275 struct usb_phy *phy = &motg->phy;
Pavankumar Kondetid8608522011-05-04 10:19:47 +05302276 u32 func_ctrl, chg_det;
2277
2278 switch (motg->pdata->phy_type) {
2279 case CI_45NM_INTEGRATED_PHY:
Heikki Krogerus1d4c9292012-02-13 13:24:09 +02002280 chg_det = ulpi_read(phy, 0x34);
Pavankumar Kondetid8608522011-05-04 10:19:47 +05302281 /* Turn off charger block */
2282 chg_det |= ~(1 << 1);
Heikki Krogerus1d4c9292012-02-13 13:24:09 +02002283 ulpi_write(phy, chg_det, 0x34);
Pavankumar Kondetid8608522011-05-04 10:19:47 +05302284 break;
2285 case SNPS_28NM_INTEGRATED_PHY:
2286 /* Clear charger detecting control bits */
Heikki Krogerus1d4c9292012-02-13 13:24:09 +02002287 ulpi_write(phy, 0x3F, 0x86);
Pavankumar Kondetid8608522011-05-04 10:19:47 +05302288 /* Clear alt interrupt latch and enable bits */
Heikki Krogerus1d4c9292012-02-13 13:24:09 +02002289 ulpi_write(phy, 0x1F, 0x92);
2290 ulpi_write(phy, 0x1F, 0x95);
Pavankumar Kondetic4c69762013-07-08 15:03:26 +05302291 /* re-enable DP and DM pull down resistors */
2292 ulpi_write(phy, 0x6, 0xB);
Pavankumar Kondetid8608522011-05-04 10:19:47 +05302293 break;
2294 default:
2295 break;
2296 }
2297
2298 /* put the controller in normal mode */
Heikki Krogerus1d4c9292012-02-13 13:24:09 +02002299 func_ctrl = ulpi_read(phy, ULPI_FUNC_CTRL);
Pavankumar Kondetid8608522011-05-04 10:19:47 +05302300 func_ctrl &= ~ULPI_FUNC_CTRL_OPMODE_MASK;
2301 func_ctrl |= ULPI_FUNC_CTRL_OPMODE_NORMAL;
Heikki Krogerus1d4c9292012-02-13 13:24:09 +02002302 ulpi_write(phy, func_ctrl, ULPI_FUNC_CTRL);
Pavankumar Kondetid8608522011-05-04 10:19:47 +05302303}
2304
Anji jonnalad270e2d2011-08-09 11:28:32 +05302305static const char *chg_to_string(enum usb_chg_type chg_type)
2306{
2307 switch (chg_type) {
2308 case USB_SDP_CHARGER: return "USB_SDP_CHARGER";
2309 case USB_DCP_CHARGER: return "USB_DCP_CHARGER";
2310 case USB_CDP_CHARGER: return "USB_CDP_CHARGER";
2311 case USB_ACA_A_CHARGER: return "USB_ACA_A_CHARGER";
2312 case USB_ACA_B_CHARGER: return "USB_ACA_B_CHARGER";
2313 case USB_ACA_C_CHARGER: return "USB_ACA_C_CHARGER";
2314 case USB_ACA_DOCK_CHARGER: return "USB_ACA_DOCK_CHARGER";
Pavankumar Kondeti9ec21d32012-05-07 15:50:23 +05302315 case USB_PROPRIETARY_CHARGER: return "USB_PROPRIETARY_CHARGER";
zhenhuahb6d5edc2013-06-19 14:37:32 +08002316 case USB_FLOATED_CHARGER: return "USB_FLOATED_CHARGER";
Anji jonnalad270e2d2011-08-09 11:28:32 +05302317 default: return "INVALID_CHARGER";
2318 }
2319}
2320
Pavankumar Kondetiebb4a2d2013-01-04 12:28:10 +05302321#define MSM_CHG_DCD_TIMEOUT (750 * HZ/1000) /* 750 msec */
2322#define MSM_CHG_DCD_POLL_TIME (50 * HZ/1000) /* 50 msec */
Pavankumar Kondeti283146f2012-01-12 12:51:19 +05302323#define MSM_CHG_PRIMARY_DET_TIME (50 * HZ/1000) /* TVDPSRC_ON */
2324#define MSM_CHG_SECONDARY_DET_TIME (50 * HZ/1000) /* TVDMSRC_ON */
Pavankumar Kondetid8608522011-05-04 10:19:47 +05302325static void msm_chg_detect_work(struct work_struct *w)
2326{
2327 struct msm_otg *motg = container_of(w, struct msm_otg, chg_work.work);
Heikki Krogerus1d4c9292012-02-13 13:24:09 +02002328 struct usb_phy *phy = &motg->phy;
Pavankumar Kondeti2d09e5f2012-01-16 08:56:57 +05302329 bool is_dcd = false, tmout, vout, is_aca;
zhenhuahb6d5edc2013-06-19 14:37:32 +08002330 static bool dcd;
Pavankumar Kondeti9ec21d32012-05-07 15:50:23 +05302331 u32 line_state, dm_vlgc;
Pavankumar Kondetid8608522011-05-04 10:19:47 +05302332 unsigned long delay;
2333
Heikki Krogerus1d4c9292012-02-13 13:24:09 +02002334 dev_dbg(phy->dev, "chg detection work\n");
Pavankumar Kondeti2aec9f32012-06-13 09:06:03 +05302335
2336 if (test_bit(MHL, &motg->inputs)) {
2337 dev_dbg(phy->dev, "detected MHL, escape chg detection work\n");
2338 return;
2339 }
2340
Pavankumar Kondetid8608522011-05-04 10:19:47 +05302341 switch (motg->chg_state) {
2342 case USB_CHG_STATE_UNDEFINED:
Pavankumar Kondetid8608522011-05-04 10:19:47 +05302343 msm_chg_block_on(motg);
Pavankumar Kondeti768dcb82012-10-05 13:21:45 +05302344 msm_chg_enable_dcd(motg);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002345 msm_chg_enable_aca_det(motg);
Pavankumar Kondetid8608522011-05-04 10:19:47 +05302346 motg->chg_state = USB_CHG_STATE_WAIT_FOR_DCD;
Pavankumar Kondetiebb4a2d2013-01-04 12:28:10 +05302347 motg->dcd_time = 0;
Pavankumar Kondetid8608522011-05-04 10:19:47 +05302348 delay = MSM_CHG_DCD_POLL_TIME;
2349 break;
2350 case USB_CHG_STATE_WAIT_FOR_DCD:
Pavankumar Kondeti2aec9f32012-06-13 09:06:03 +05302351 if (msm_chg_mhl_detect(motg)) {
2352 msm_chg_block_off(motg);
2353 motg->chg_state = USB_CHG_STATE_DETECTED;
2354 motg->chg_type = USB_INVALID_CHARGER;
2355 queue_work(system_nrt_wq, &motg->sm_work);
2356 return;
2357 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002358 is_aca = msm_chg_aca_detect(motg);
2359 if (is_aca) {
2360 /*
2361 * ID_A can be ACA dock too. continue
2362 * primary detection after DCD.
2363 */
2364 if (test_bit(ID_A, &motg->inputs)) {
2365 motg->chg_state = USB_CHG_STATE_WAIT_FOR_DCD;
2366 } else {
2367 delay = 0;
2368 break;
2369 }
2370 }
Pavankumar Kondeti768dcb82012-10-05 13:21:45 +05302371 is_dcd = msm_chg_check_dcd(motg);
Pavankumar Kondetiebb4a2d2013-01-04 12:28:10 +05302372 motg->dcd_time += MSM_CHG_DCD_POLL_TIME;
2373 tmout = motg->dcd_time >= MSM_CHG_DCD_TIMEOUT;
Pavankumar Kondetid8608522011-05-04 10:19:47 +05302374 if (is_dcd || tmout) {
zhenhuahb6d5edc2013-06-19 14:37:32 +08002375 if (is_dcd)
2376 dcd = true;
2377 else
2378 dcd = false;
Pavankumar Kondeti768dcb82012-10-05 13:21:45 +05302379 msm_chg_disable_dcd(motg);
Pavankumar Kondetid8608522011-05-04 10:19:47 +05302380 msm_chg_enable_primary_det(motg);
2381 delay = MSM_CHG_PRIMARY_DET_TIME;
2382 motg->chg_state = USB_CHG_STATE_DCD_DONE;
2383 } else {
2384 delay = MSM_CHG_DCD_POLL_TIME;
2385 }
2386 break;
2387 case USB_CHG_STATE_DCD_DONE:
2388 vout = msm_chg_check_primary_det(motg);
Pavankumar Kondeti9ec21d32012-05-07 15:50:23 +05302389 line_state = readl_relaxed(USB_PORTSC) & PORTSC_LS;
2390 dm_vlgc = line_state & PORTSC_LS_DM;
2391 if (vout && !dm_vlgc) { /* VDAT_REF < DM < VLGC */
Pavankumar Kondetiaa449e12011-11-04 11:09:26 +05302392 if (test_bit(ID_A, &motg->inputs)) {
2393 motg->chg_type = USB_ACA_DOCK_CHARGER;
2394 motg->chg_state = USB_CHG_STATE_DETECTED;
2395 delay = 0;
2396 break;
2397 }
Pavankumar Kondeti9ec21d32012-05-07 15:50:23 +05302398 if (line_state) { /* DP > VLGC */
2399 motg->chg_type = USB_PROPRIETARY_CHARGER;
2400 motg->chg_state = USB_CHG_STATE_DETECTED;
2401 delay = 0;
2402 } else {
2403 msm_chg_enable_secondary_det(motg);
2404 delay = MSM_CHG_SECONDARY_DET_TIME;
2405 motg->chg_state = USB_CHG_STATE_PRIMARY_DONE;
2406 }
2407 } else { /* DM < VDAT_REF || DM > VLGC */
Pavankumar Kondetiaa449e12011-11-04 11:09:26 +05302408 if (test_bit(ID_A, &motg->inputs)) {
2409 motg->chg_type = USB_ACA_A_CHARGER;
2410 motg->chg_state = USB_CHG_STATE_DETECTED;
2411 delay = 0;
2412 break;
2413 }
Pavankumar Kondeti9ec21d32012-05-07 15:50:23 +05302414
2415 if (line_state) /* DP > VLGC or/and DM > VLGC */
2416 motg->chg_type = USB_PROPRIETARY_CHARGER;
zhenhuahb6d5edc2013-06-19 14:37:32 +08002417 else if (!dcd && floated_charger_enable)
2418 motg->chg_type = USB_FLOATED_CHARGER;
Pavankumar Kondeti9ec21d32012-05-07 15:50:23 +05302419 else
2420 motg->chg_type = USB_SDP_CHARGER;
2421
Pavankumar Kondetid8608522011-05-04 10:19:47 +05302422 motg->chg_state = USB_CHG_STATE_DETECTED;
2423 delay = 0;
2424 }
2425 break;
2426 case USB_CHG_STATE_PRIMARY_DONE:
2427 vout = msm_chg_check_secondary_det(motg);
2428 if (vout)
2429 motg->chg_type = USB_DCP_CHARGER;
2430 else
2431 motg->chg_type = USB_CDP_CHARGER;
2432 motg->chg_state = USB_CHG_STATE_SECONDARY_DONE;
2433 /* fall through */
2434 case USB_CHG_STATE_SECONDARY_DONE:
2435 motg->chg_state = USB_CHG_STATE_DETECTED;
2436 case USB_CHG_STATE_DETECTED:
Pavankumar Kondetid7b6d1a2013-01-11 15:38:09 +05302437 /*
2438 * Notify the charger type to power supply
2439 * owner as soon as we determine the charger.
2440 */
Saket Saurabh48848182014-05-23 15:15:02 +05302441 if (motg->chg_type == USB_DCP_CHARGER &&
2442 motg->ext_chg_opened) {
2443 init_completion(&motg->ext_chg_wait);
2444 motg->ext_chg_active = DEFAULT;
2445 }
Pavankumar Kondetid7b6d1a2013-01-11 15:38:09 +05302446 msm_otg_notify_chg_type(motg);
Pavankumar Kondetid8608522011-05-04 10:19:47 +05302447 msm_chg_block_off(motg);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002448 msm_chg_enable_aca_det(motg);
Vijayavardhan Vennapusaa3152032012-03-05 16:29:30 +05302449 /*
2450 * Spurious interrupt is seen after enabling ACA detection
2451 * due to which charger detection fails in case of PET.
2452 * Add delay of 100 microsec to avoid that.
2453 */
2454 udelay(100);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002455 msm_chg_enable_aca_intr(motg);
Steve Mucklef132c6c2012-06-06 18:30:57 -07002456 dev_dbg(phy->dev, "chg_type = %s\n",
Anji jonnalad270e2d2011-08-09 11:28:32 +05302457 chg_to_string(motg->chg_type));
Vijayavardhan Vennapusaa3152032012-03-05 16:29:30 +05302458 queue_work(system_nrt_wq, &motg->sm_work);
Pavankumar Kondetid8608522011-05-04 10:19:47 +05302459 return;
2460 default:
2461 return;
2462 }
2463
Vijayavardhan Vennapusaa3152032012-03-05 16:29:30 +05302464 queue_delayed_work(system_nrt_wq, &motg->chg_work, delay);
Pavankumar Kondetid8608522011-05-04 10:19:47 +05302465}
2466
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05302467/*
2468 * We support OTG, Peripheral only and Host only configurations. In case
2469 * of OTG, mode switch (host-->peripheral/peripheral-->host) can happen
2470 * via Id pin status or user request (debugfs). Id/BSV interrupts are not
2471 * enabled when switch is controlled by user and default mode is supplied
2472 * by board file, which can be changed by userspace later.
2473 */
2474static void msm_otg_init_sm(struct msm_otg *motg)
2475{
2476 struct msm_otg_platform_data *pdata = motg->pdata;
2477 u32 otgsc = readl(USB_OTGSC);
2478
2479 switch (pdata->mode) {
2480 case USB_OTG:
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002481 if (pdata->otg_control == OTG_USER_CONTROL) {
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05302482 if (pdata->default_mode == USB_HOST) {
2483 clear_bit(ID, &motg->inputs);
2484 } else if (pdata->default_mode == USB_PERIPHERAL) {
2485 set_bit(ID, &motg->inputs);
2486 set_bit(B_SESS_VLD, &motg->inputs);
2487 } else {
2488 set_bit(ID, &motg->inputs);
2489 clear_bit(B_SESS_VLD, &motg->inputs);
2490 }
Pavankumar Kondeti4960f312011-12-06 15:46:14 +05302491 } else if (pdata->otg_control == OTG_PHY_CONTROL) {
Vijayavardhan Vennapusaa3152032012-03-05 16:29:30 +05302492 if (otgsc & OTGSC_ID) {
Pavankumar Kondeti4960f312011-12-06 15:46:14 +05302493 set_bit(ID, &motg->inputs);
Vijayavardhan Vennapusaa3152032012-03-05 16:29:30 +05302494 } else {
Pavankumar Kondeti4960f312011-12-06 15:46:14 +05302495 clear_bit(ID, &motg->inputs);
Vijayavardhan Vennapusaa3152032012-03-05 16:29:30 +05302496 set_bit(A_BUS_REQ, &motg->inputs);
2497 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002498 if (otgsc & OTGSC_BSV)
2499 set_bit(B_SESS_VLD, &motg->inputs);
2500 else
2501 clear_bit(B_SESS_VLD, &motg->inputs);
Pavankumar Kondeti4960f312011-12-06 15:46:14 +05302502 } else if (pdata->otg_control == OTG_PMIC_CONTROL) {
Pavankumar Kondeti0d81f312012-01-13 11:34:10 +05302503 if (pdata->pmic_id_irq) {
Pavankumar Kondetibecab5b2012-11-06 16:45:10 +05302504 if (msm_otg_read_pmic_id_state(motg))
Pavankumar Kondeti0d81f312012-01-13 11:34:10 +05302505 set_bit(ID, &motg->inputs);
2506 else
2507 clear_bit(ID, &motg->inputs);
2508 }
Pavankumar Kondeti4960f312011-12-06 15:46:14 +05302509 /*
2510 * VBUS initial state is reported after PMIC
2511 * driver initialization. Wait for it.
2512 */
2513 wait_for_completion(&pmic_vbus_init);
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05302514 }
2515 break;
2516 case USB_HOST:
2517 clear_bit(ID, &motg->inputs);
2518 break;
2519 case USB_PERIPHERAL:
2520 set_bit(ID, &motg->inputs);
Pavankumar Kondeti0d81f312012-01-13 11:34:10 +05302521 if (pdata->otg_control == OTG_PHY_CONTROL) {
2522 if (otgsc & OTGSC_BSV)
2523 set_bit(B_SESS_VLD, &motg->inputs);
2524 else
2525 clear_bit(B_SESS_VLD, &motg->inputs);
2526 } else if (pdata->otg_control == OTG_PMIC_CONTROL) {
2527 /*
2528 * VBUS initial state is reported after PMIC
2529 * driver initialization. Wait for it.
2530 */
2531 wait_for_completion(&pmic_vbus_init);
2532 }
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05302533 break;
2534 default:
2535 break;
2536 }
2537}
2538
Pavankumar Kondetif1ffbdd2013-06-27 13:31:36 +05302539static void msm_otg_wait_for_ext_chg_done(struct msm_otg *motg)
2540{
2541 struct usb_phy *phy = &motg->phy;
2542 unsigned long t;
2543
2544 /*
2545 * Defer next cable connect event till external charger
2546 * detection is completed.
2547 */
2548
Saket Saurabh48848182014-05-23 15:15:02 +05302549 if (motg->ext_chg_active == ACTIVE) {
Pavankumar Kondetif1ffbdd2013-06-27 13:31:36 +05302550
Pavankumar Kondeti8cb1e0c2014-05-13 11:33:00 +05302551do_wait:
Pavankumar Kondetif1ffbdd2013-06-27 13:31:36 +05302552 pr_debug("before msm_otg ext chg wait\n");
2553
2554 t = wait_for_completion_timeout(&motg->ext_chg_wait,
2555 msecs_to_jiffies(3000));
2556 if (!t)
2557 pr_err("msm_otg ext chg wait timeout\n");
Saket Saurabh48848182014-05-23 15:15:02 +05302558 else if (motg->ext_chg_active == ACTIVE)
Pavankumar Kondeti8cb1e0c2014-05-13 11:33:00 +05302559 goto do_wait;
Pavankumar Kondetif1ffbdd2013-06-27 13:31:36 +05302560 else
2561 pr_debug("msm_otg ext chg wait done\n");
2562 }
2563
2564 if (motg->ext_chg_opened) {
2565 if (phy->flags & ENABLE_DP_MANUAL_PULLUP) {
2566 ulpi_write(phy, ULPI_MISC_A_VBUSVLDEXT |
2567 ULPI_MISC_A_VBUSVLDEXTSEL,
2568 ULPI_CLR(ULPI_MISC_A));
2569 }
2570 /* clear charging register bits */
2571 ulpi_write(phy, 0x3F, 0x86);
2572 /* re-enable DP and DM pull-down resistors*/
2573 ulpi_write(phy, 0x6, 0xB);
2574 }
2575}
2576
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05302577static void msm_otg_sm_work(struct work_struct *w)
2578{
2579 struct msm_otg *motg = container_of(w, struct msm_otg, sm_work);
Heikki Krogerus1d4c9292012-02-13 13:24:09 +02002580 struct usb_otg *otg = motg->phy.otg;
Pavankumar Kondetif1ffbdd2013-06-27 13:31:36 +05302581 bool work = 0, srp_reqd, dcp;
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05302582
Steve Mucklef132c6c2012-06-06 18:30:57 -07002583 pm_runtime_resume(otg->phy->dev);
Saket Saurabh1a4e2502014-04-22 15:51:38 +05302584 if (motg->pm_done) {
Saket Saurabh2558ea02014-01-10 16:14:27 +05302585 pm_runtime_get_sync(otg->phy->dev);
Saket Saurabh1a4e2502014-04-22 15:51:38 +05302586 motg->pm_done = 0;
2587 }
Steve Mucklef132c6c2012-06-06 18:30:57 -07002588 pr_debug("%s work\n", otg_state_string(otg->phy->state));
Heikki Krogerus1d4c9292012-02-13 13:24:09 +02002589 switch (otg->phy->state) {
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05302590 case OTG_STATE_UNDEFINED:
Heikki Krogerus1d4c9292012-02-13 13:24:09 +02002591 msm_otg_reset(otg->phy);
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05302592 msm_otg_init_sm(motg);
David Keitel272ce522012-08-17 16:25:24 -07002593 if (!psy && legacy_power_supply) {
2594 psy = power_supply_get_by_name("usb");
2595
2596 if (!psy)
2597 pr_err("couldn't get usb power supply\n");
2598 }
2599
Heikki Krogerus1d4c9292012-02-13 13:24:09 +02002600 otg->phy->state = OTG_STATE_B_IDLE;
Pavankumar Kondeti8a379b42011-12-12 13:07:23 +05302601 if (!test_bit(B_SESS_VLD, &motg->inputs) &&
2602 test_bit(ID, &motg->inputs)) {
Steve Mucklef132c6c2012-06-06 18:30:57 -07002603 pm_runtime_put_noidle(otg->phy->dev);
2604 pm_runtime_suspend(otg->phy->dev);
Pavankumar Kondeti8a379b42011-12-12 13:07:23 +05302605 break;
2606 }
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05302607 /* FALL THROUGH */
2608 case OTG_STATE_B_IDLE:
Pavankumar Kondeti2aec9f32012-06-13 09:06:03 +05302609 if (test_bit(MHL, &motg->inputs)) {
2610 /* allow LPM */
2611 pm_runtime_put_noidle(otg->phy->dev);
2612 pm_runtime_suspend(otg->phy->dev);
2613 } else if ((!test_bit(ID, &motg->inputs) ||
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002614 test_bit(ID_A, &motg->inputs)) && otg->host) {
Vijayavardhan Vennapusaa3152032012-03-05 16:29:30 +05302615 pr_debug("!id || id_A\n");
Pavankumar Kondeti2aec9f32012-06-13 09:06:03 +05302616 if (msm_chg_mhl_detect(motg)) {
2617 work = 1;
2618 break;
2619 }
Vijayavardhan Vennapusaa3152032012-03-05 16:29:30 +05302620 clear_bit(B_BUS_REQ, &motg->inputs);
2621 set_bit(A_BUS_REQ, &motg->inputs);
Steve Mucklef132c6c2012-06-06 18:30:57 -07002622 otg->phy->state = OTG_STATE_A_IDLE;
Vijayavardhan Vennapusaa3152032012-03-05 16:29:30 +05302623 work = 1;
Pavankumar Kondetid8608522011-05-04 10:19:47 +05302624 } else if (test_bit(B_SESS_VLD, &motg->inputs)) {
Vijayavardhan Vennapusaa3152032012-03-05 16:29:30 +05302625 pr_debug("b_sess_vld\n");
Pavankumar Kondetid8608522011-05-04 10:19:47 +05302626 switch (motg->chg_state) {
2627 case USB_CHG_STATE_UNDEFINED:
2628 msm_chg_detect_work(&motg->chg_work.work);
2629 break;
2630 case USB_CHG_STATE_DETECTED:
2631 switch (motg->chg_type) {
2632 case USB_DCP_CHARGER:
Pavankumar Kondeti283146f2012-01-12 12:51:19 +05302633 /* Enable VDP_SRC */
Steve Mucklef132c6c2012-06-06 18:30:57 -07002634 ulpi_write(otg->phy, 0x2, 0x85);
Pavankumar Kondeti9ec21d32012-05-07 15:50:23 +05302635 /* fall through */
2636 case USB_PROPRIETARY_CHARGER:
Pavankumar Kondetid8608522011-05-04 10:19:47 +05302637 msm_otg_notify_charger(motg,
2638 IDEV_CHG_MAX);
Pavankumar Kondetif1ffbdd2013-06-27 13:31:36 +05302639 pm_runtime_put_sync(otg->phy->dev);
Pavankumar Kondetid8608522011-05-04 10:19:47 +05302640 break;
zhenhuahb6d5edc2013-06-19 14:37:32 +08002641 case USB_FLOATED_CHARGER:
2642 msm_otg_notify_charger(motg,
2643 IDEV_CHG_MAX);
2644 pm_runtime_put_noidle(otg->phy->dev);
2645 pm_runtime_suspend(otg->phy->dev);
2646 break;
Pavankumar Kondetiaa449e12011-11-04 11:09:26 +05302647 case USB_ACA_B_CHARGER:
2648 msm_otg_notify_charger(motg,
2649 IDEV_ACA_CHG_MAX);
2650 /*
2651 * (ID_B --> ID_C) PHY_ALT interrupt can
2652 * not be detected in LPM.
2653 */
Pavankumar Kondetid8608522011-05-04 10:19:47 +05302654 break;
2655 case USB_CDP_CHARGER:
2656 msm_otg_notify_charger(motg,
2657 IDEV_CHG_MAX);
2658 msm_otg_start_peripheral(otg, 1);
Steve Mucklef132c6c2012-06-06 18:30:57 -07002659 otg->phy->state =
2660 OTG_STATE_B_PERIPHERAL;
Pavankumar Kondetid8608522011-05-04 10:19:47 +05302661 break;
Pavankumar Kondetiaa449e12011-11-04 11:09:26 +05302662 case USB_ACA_C_CHARGER:
2663 msm_otg_notify_charger(motg,
2664 IDEV_ACA_CHG_MAX);
2665 msm_otg_start_peripheral(otg, 1);
Steve Mucklef132c6c2012-06-06 18:30:57 -07002666 otg->phy->state =
2667 OTG_STATE_B_PERIPHERAL;
Pavankumar Kondetid8608522011-05-04 10:19:47 +05302668 break;
2669 case USB_SDP_CHARGER:
Pavankumar Kondetid8608522011-05-04 10:19:47 +05302670 msm_otg_start_peripheral(otg, 1);
Steve Mucklef132c6c2012-06-06 18:30:57 -07002671 otg->phy->state =
2672 OTG_STATE_B_PERIPHERAL;
Pavankumar Kondeti458d8792012-09-28 14:45:18 +05302673 mod_timer(&motg->chg_check_timer,
2674 CHG_RECHECK_DELAY);
Pavankumar Kondetid8608522011-05-04 10:19:47 +05302675 break;
2676 default:
2677 break;
2678 }
2679 break;
2680 default:
2681 break;
2682 }
Vijayavardhan Vennapusaa3152032012-03-05 16:29:30 +05302683 } else if (test_bit(B_BUS_REQ, &motg->inputs)) {
2684 pr_debug("b_sess_end && b_bus_req\n");
2685 if (msm_otg_start_srp(otg) < 0) {
2686 clear_bit(B_BUS_REQ, &motg->inputs);
2687 work = 1;
2688 break;
Pavankumar Kondetid8608522011-05-04 10:19:47 +05302689 }
Steve Mucklef132c6c2012-06-06 18:30:57 -07002690 otg->phy->state = OTG_STATE_B_SRP_INIT;
Vijayavardhan Vennapusaa3152032012-03-05 16:29:30 +05302691 msm_otg_start_timer(motg, TB_SRP_FAIL, B_SRP_FAIL);
2692 break;
Pavankumar Kondetid8608522011-05-04 10:19:47 +05302693 } else {
Vijayavardhan Vennapusaa3152032012-03-05 16:29:30 +05302694 pr_debug("chg_work cancel");
Pavankumar Kondeti458d8792012-09-28 14:45:18 +05302695 del_timer_sync(&motg->chg_check_timer);
2696 clear_bit(B_FALSE_SDP, &motg->inputs);
Mayank Rana8ab00352013-01-23 19:26:21 +05302697 clear_bit(A_BUS_REQ, &motg->inputs);
Pavankumar Kondetiaa449e12011-11-04 11:09:26 +05302698 cancel_delayed_work_sync(&motg->chg_work);
Pavankumar Kondetif1ffbdd2013-06-27 13:31:36 +05302699 dcp = (motg->chg_type == USB_DCP_CHARGER);
Pavankumar Kondetid8608522011-05-04 10:19:47 +05302700 motg->chg_state = USB_CHG_STATE_UNDEFINED;
2701 motg->chg_type = USB_INVALID_CHARGER;
Rajkumar Raghupathy18fd7132012-04-20 11:28:13 +05302702 msm_otg_notify_charger(motg, 0);
Manu Gautam6604b682013-09-04 17:50:17 +05302703 if (dcp) {
Saket Saurabh48848182014-05-23 15:15:02 +05302704 if (motg->ext_chg_active == DEFAULT)
2705 motg->ext_chg_active = INACTIVE;
Pavankumar Kondetif1ffbdd2013-06-27 13:31:36 +05302706 msm_otg_wait_for_ext_chg_done(motg);
Manu Gautam6604b682013-09-04 17:50:17 +05302707 /* Turn off VDP_SRC */
2708 ulpi_write(otg->phy, 0x2, 0x86);
2709 }
ChandanaKishori Chiluveru986dd7c2014-03-27 10:34:34 +05302710 msm_chg_block_off(motg);
Steve Mucklef132c6c2012-06-06 18:30:57 -07002711 msm_otg_reset(otg->phy);
Pavankumar Kondetibecab5b2012-11-06 16:45:10 +05302712 /*
2713 * There is a small window where ID interrupt
2714 * is not monitored during ID detection circuit
2715 * switch from ACA to PMIC. Check ID state
2716 * before entering into low power mode.
2717 */
2718 if (!msm_otg_read_pmic_id_state(motg)) {
2719 pr_debug("process missed ID intr\n");
2720 clear_bit(ID, &motg->inputs);
2721 work = 1;
2722 break;
2723 }
Steve Mucklef132c6c2012-06-06 18:30:57 -07002724 pm_runtime_put_noidle(otg->phy->dev);
Amit Blayd6f38282012-10-29 13:13:46 +02002725 /*
2726 * Only if autosuspend was enabled in probe, it will be
2727 * used here. Otherwise, no delay will be used.
2728 */
2729 pm_runtime_mark_last_busy(otg->phy->dev);
2730 pm_runtime_autosuspend(otg->phy->dev);
Saket Saurabh2558ea02014-01-10 16:14:27 +05302731 motg->pm_done = 1;
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05302732 }
2733 break;
Vijayavardhan Vennapusaa3152032012-03-05 16:29:30 +05302734 case OTG_STATE_B_SRP_INIT:
2735 if (!test_bit(ID, &motg->inputs) ||
2736 test_bit(ID_A, &motg->inputs) ||
2737 test_bit(ID_C, &motg->inputs) ||
2738 (test_bit(B_SESS_VLD, &motg->inputs) &&
2739 !test_bit(ID_B, &motg->inputs))) {
2740 pr_debug("!id || id_a/c || b_sess_vld+!id_b\n");
2741 msm_otg_del_timer(motg);
Steve Mucklef132c6c2012-06-06 18:30:57 -07002742 otg->phy->state = OTG_STATE_B_IDLE;
Vijayavardhan Vennapusaa3152032012-03-05 16:29:30 +05302743 /*
2744 * clear VBUSVLDEXTSEL and VBUSVLDEXT register
2745 * bits after SRP initiation.
2746 */
Steve Mucklef132c6c2012-06-06 18:30:57 -07002747 ulpi_write(otg->phy, 0x0, 0x98);
Vijayavardhan Vennapusaa3152032012-03-05 16:29:30 +05302748 work = 1;
2749 } else if (test_bit(B_SRP_FAIL, &motg->tmouts)) {
2750 pr_debug("b_srp_fail\n");
2751 pr_info("A-device did not respond to SRP\n");
2752 clear_bit(B_BUS_REQ, &motg->inputs);
2753 clear_bit(B_SRP_FAIL, &motg->tmouts);
2754 otg_send_event(OTG_EVENT_NO_RESP_FOR_SRP);
Steve Mucklef132c6c2012-06-06 18:30:57 -07002755 ulpi_write(otg->phy, 0x0, 0x98);
2756 otg->phy->state = OTG_STATE_B_IDLE;
Vijayavardhan Vennapusaa3152032012-03-05 16:29:30 +05302757 motg->b_last_se0_sess = jiffies;
2758 work = 1;
2759 }
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05302760 break;
2761 case OTG_STATE_B_PERIPHERAL:
Pavankumar Kondeti458d8792012-09-28 14:45:18 +05302762 if (test_bit(B_SESS_VLD, &motg->inputs) &&
2763 test_bit(B_FALSE_SDP, &motg->inputs)) {
2764 pr_debug("B_FALSE_SDP\n");
2765 msm_otg_start_peripheral(otg, 0);
2766 motg->chg_type = USB_DCP_CHARGER;
2767 clear_bit(B_FALSE_SDP, &motg->inputs);
2768 otg->phy->state = OTG_STATE_B_IDLE;
2769 work = 1;
2770 } else if (!test_bit(ID, &motg->inputs) ||
Vijayavardhan Vennapusaa3152032012-03-05 16:29:30 +05302771 test_bit(ID_A, &motg->inputs) ||
2772 test_bit(ID_B, &motg->inputs) ||
2773 !test_bit(B_SESS_VLD, &motg->inputs)) {
2774 pr_debug("!id || id_a/b || !b_sess_vld\n");
Pavankumar Kondetid8608522011-05-04 10:19:47 +05302775 motg->chg_state = USB_CHG_STATE_UNDEFINED;
2776 motg->chg_type = USB_INVALID_CHARGER;
Vijayavardhan Vennapusaa3152032012-03-05 16:29:30 +05302777 msm_otg_notify_charger(motg, 0);
2778 srp_reqd = otg->gadget->otg_srp_reqd;
2779 msm_otg_start_peripheral(otg, 0);
Vijayavardhan Vennapusaa3152032012-03-05 16:29:30 +05302780 if (test_bit(ID_B, &motg->inputs))
2781 clear_bit(ID_B, &motg->inputs);
2782 clear_bit(B_BUS_REQ, &motg->inputs);
Steve Mucklef132c6c2012-06-06 18:30:57 -07002783 otg->phy->state = OTG_STATE_B_IDLE;
Vijayavardhan Vennapusaa3152032012-03-05 16:29:30 +05302784 motg->b_last_se0_sess = jiffies;
2785 if (srp_reqd)
2786 msm_otg_start_timer(motg,
2787 TB_TST_SRP, B_TST_SRP);
2788 else
2789 work = 1;
2790 } else if (test_bit(B_BUS_REQ, &motg->inputs) &&
2791 otg->gadget->b_hnp_enable &&
2792 test_bit(A_BUS_SUSPEND, &motg->inputs)) {
2793 pr_debug("b_bus_req && b_hnp_en && a_bus_suspend\n");
2794 msm_otg_start_timer(motg, TB_ASE0_BRST, B_ASE0_BRST);
2795 /* D+ pullup should not be disconnected within 4msec
2796 * after A device suspends the bus. Otherwise PET will
2797 * fail the compliance test.
2798 */
2799 udelay(1000);
2800 msm_otg_start_peripheral(otg, 0);
Steve Mucklef132c6c2012-06-06 18:30:57 -07002801 otg->phy->state = OTG_STATE_B_WAIT_ACON;
Vijayavardhan Vennapusaa3152032012-03-05 16:29:30 +05302802 /*
2803 * start HCD even before A-device enable
2804 * pull-up to meet HNP timings.
2805 */
2806 otg->host->is_b_host = 1;
2807 msm_otg_start_host(otg, 1);
Amit Blay6fa647a2012-05-24 14:12:08 +03002808 } else if (test_bit(A_BUS_SUSPEND, &motg->inputs) &&
2809 test_bit(B_SESS_VLD, &motg->inputs)) {
2810 pr_debug("a_bus_suspend && b_sess_vld\n");
2811 if (motg->caps & ALLOW_LPM_ON_DEV_SUSPEND) {
Steve Mucklef132c6c2012-06-06 18:30:57 -07002812 pm_runtime_put_noidle(otg->phy->dev);
2813 pm_runtime_suspend(otg->phy->dev);
Amit Blay6fa647a2012-05-24 14:12:08 +03002814 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002815 } else if (test_bit(ID_C, &motg->inputs)) {
Pavankumar Kondetiaa449e12011-11-04 11:09:26 +05302816 msm_otg_notify_charger(motg, IDEV_ACA_CHG_MAX);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002817 }
2818 break;
Vijayavardhan Vennapusaa3152032012-03-05 16:29:30 +05302819 case OTG_STATE_B_WAIT_ACON:
2820 if (!test_bit(ID, &motg->inputs) ||
2821 test_bit(ID_A, &motg->inputs) ||
2822 test_bit(ID_B, &motg->inputs) ||
2823 !test_bit(B_SESS_VLD, &motg->inputs)) {
2824 pr_debug("!id || id_a/b || !b_sess_vld\n");
2825 msm_otg_del_timer(motg);
Pavankumar Kondetiaa449e12011-11-04 11:09:26 +05302826 /*
Vijayavardhan Vennapusaa3152032012-03-05 16:29:30 +05302827 * A-device is physically disconnected during
2828 * HNP. Remove HCD.
Pavankumar Kondetiaa449e12011-11-04 11:09:26 +05302829 */
Vijayavardhan Vennapusaa3152032012-03-05 16:29:30 +05302830 msm_otg_start_host(otg, 0);
2831 otg->host->is_b_host = 0;
2832
2833 clear_bit(B_BUS_REQ, &motg->inputs);
2834 clear_bit(A_BUS_SUSPEND, &motg->inputs);
2835 motg->b_last_se0_sess = jiffies;
Heikki Krogerus1d4c9292012-02-13 13:24:09 +02002836 otg->phy->state = OTG_STATE_B_IDLE;
2837 msm_otg_reset(otg->phy);
Vijayavardhan Vennapusaa3152032012-03-05 16:29:30 +05302838 work = 1;
2839 } else if (test_bit(A_CONN, &motg->inputs)) {
2840 pr_debug("a_conn\n");
2841 clear_bit(A_BUS_SUSPEND, &motg->inputs);
Steve Mucklef132c6c2012-06-06 18:30:57 -07002842 otg->phy->state = OTG_STATE_B_HOST;
Vijayavardhan Vennapusaa3152032012-03-05 16:29:30 +05302843 /*
2844 * PET disconnects D+ pullup after reset is generated
2845 * by B device in B_HOST role which is not detected by
2846 * B device. As workaorund , start timer of 300msec
2847 * and stop timer if A device is enumerated else clear
2848 * A_CONN.
2849 */
2850 msm_otg_start_timer(motg, TB_TST_CONFIG,
2851 B_TST_CONFIG);
2852 } else if (test_bit(B_ASE0_BRST, &motg->tmouts)) {
2853 pr_debug("b_ase0_brst_tmout\n");
2854 pr_info("B HNP fail:No response from A device\n");
2855 msm_otg_start_host(otg, 0);
Steve Mucklef132c6c2012-06-06 18:30:57 -07002856 msm_otg_reset(otg->phy);
Vijayavardhan Vennapusaa3152032012-03-05 16:29:30 +05302857 otg->host->is_b_host = 0;
2858 clear_bit(B_ASE0_BRST, &motg->tmouts);
2859 clear_bit(A_BUS_SUSPEND, &motg->inputs);
2860 clear_bit(B_BUS_REQ, &motg->inputs);
2861 otg_send_event(OTG_EVENT_HNP_FAILED);
Steve Mucklef132c6c2012-06-06 18:30:57 -07002862 otg->phy->state = OTG_STATE_B_IDLE;
Vijayavardhan Vennapusaa3152032012-03-05 16:29:30 +05302863 work = 1;
2864 } else if (test_bit(ID_C, &motg->inputs)) {
2865 msm_otg_notify_charger(motg, IDEV_ACA_CHG_MAX);
2866 }
2867 break;
2868 case OTG_STATE_B_HOST:
2869 if (!test_bit(B_BUS_REQ, &motg->inputs) ||
2870 !test_bit(A_CONN, &motg->inputs) ||
2871 !test_bit(B_SESS_VLD, &motg->inputs)) {
2872 pr_debug("!b_bus_req || !a_conn || !b_sess_vld\n");
2873 clear_bit(A_CONN, &motg->inputs);
2874 clear_bit(B_BUS_REQ, &motg->inputs);
2875 msm_otg_start_host(otg, 0);
2876 otg->host->is_b_host = 0;
Steve Mucklef132c6c2012-06-06 18:30:57 -07002877 otg->phy->state = OTG_STATE_B_IDLE;
2878 msm_otg_reset(otg->phy);
Vijayavardhan Vennapusaa3152032012-03-05 16:29:30 +05302879 work = 1;
2880 } else if (test_bit(ID_C, &motg->inputs)) {
2881 msm_otg_notify_charger(motg, IDEV_ACA_CHG_MAX);
2882 }
2883 break;
2884 case OTG_STATE_A_IDLE:
2885 otg->default_a = 1;
2886 if (test_bit(ID, &motg->inputs) &&
2887 !test_bit(ID_A, &motg->inputs)) {
2888 pr_debug("id && !id_a\n");
2889 otg->default_a = 0;
2890 clear_bit(A_BUS_DROP, &motg->inputs);
Steve Mucklef132c6c2012-06-06 18:30:57 -07002891 otg->phy->state = OTG_STATE_B_IDLE;
Vijayavardhan Vennapusaa3152032012-03-05 16:29:30 +05302892 del_timer_sync(&motg->id_timer);
2893 msm_otg_link_reset(motg);
2894 msm_chg_enable_aca_intr(motg);
2895 msm_otg_notify_charger(motg, 0);
2896 work = 1;
2897 } else if (!test_bit(A_BUS_DROP, &motg->inputs) &&
2898 (test_bit(A_SRP_DET, &motg->inputs) ||
2899 test_bit(A_BUS_REQ, &motg->inputs))) {
2900 pr_debug("!a_bus_drop && (a_srp_det || a_bus_req)\n");
2901
2902 clear_bit(A_SRP_DET, &motg->inputs);
2903 /* Disable SRP detection */
2904 writel_relaxed((readl_relaxed(USB_OTGSC) &
2905 ~OTGSC_INTSTS_MASK) &
2906 ~OTGSC_DPIE, USB_OTGSC);
2907
Steve Mucklef132c6c2012-06-06 18:30:57 -07002908 otg->phy->state = OTG_STATE_A_WAIT_VRISE;
Vijayavardhan Vennapusaa3152032012-03-05 16:29:30 +05302909 /* VBUS should not be supplied before end of SRP pulse
2910 * generated by PET, if not complaince test fail.
2911 */
2912 usleep_range(10000, 12000);
2913 /* ACA: ID_A: Stop charging untill enumeration */
2914 if (test_bit(ID_A, &motg->inputs))
2915 msm_otg_notify_charger(motg, 0);
2916 else
2917 msm_hsusb_vbus_power(motg, 1);
2918 msm_otg_start_timer(motg, TA_WAIT_VRISE, A_WAIT_VRISE);
2919 } else {
2920 pr_debug("No session requested\n");
2921 clear_bit(A_BUS_DROP, &motg->inputs);
2922 if (test_bit(ID_A, &motg->inputs)) {
2923 msm_otg_notify_charger(motg,
2924 IDEV_ACA_CHG_MAX);
2925 } else if (!test_bit(ID, &motg->inputs)) {
2926 msm_otg_notify_charger(motg, 0);
2927 /*
2928 * A-device is not providing power on VBUS.
2929 * Enable SRP detection.
2930 */
2931 writel_relaxed(0x13, USB_USBMODE);
2932 writel_relaxed((readl_relaxed(USB_OTGSC) &
2933 ~OTGSC_INTSTS_MASK) |
2934 OTGSC_DPIE, USB_OTGSC);
2935 mb();
2936 }
2937 }
2938 break;
2939 case OTG_STATE_A_WAIT_VRISE:
2940 if ((test_bit(ID, &motg->inputs) &&
2941 !test_bit(ID_A, &motg->inputs)) ||
2942 test_bit(A_BUS_DROP, &motg->inputs) ||
2943 test_bit(A_WAIT_VRISE, &motg->tmouts)) {
2944 pr_debug("id || a_bus_drop || a_wait_vrise_tmout\n");
2945 clear_bit(A_BUS_REQ, &motg->inputs);
2946 msm_otg_del_timer(motg);
2947 msm_hsusb_vbus_power(motg, 0);
Steve Mucklef132c6c2012-06-06 18:30:57 -07002948 otg->phy->state = OTG_STATE_A_WAIT_VFALL;
Vijayavardhan Vennapusaa3152032012-03-05 16:29:30 +05302949 msm_otg_start_timer(motg, TA_WAIT_VFALL, A_WAIT_VFALL);
2950 } else if (test_bit(A_VBUS_VLD, &motg->inputs)) {
2951 pr_debug("a_vbus_vld\n");
Steve Mucklef132c6c2012-06-06 18:30:57 -07002952 otg->phy->state = OTG_STATE_A_WAIT_BCON;
Vijayavardhan Vennapusaa3152032012-03-05 16:29:30 +05302953 if (TA_WAIT_BCON > 0)
2954 msm_otg_start_timer(motg, TA_WAIT_BCON,
2955 A_WAIT_BCON);
Sujeet Kumarebaef0c2013-06-03 15:54:25 +05302956
2957 /* Clear BSV in host mode */
2958 clear_bit(B_SESS_VLD, &motg->inputs);
Vijayavardhan Vennapusaa3152032012-03-05 16:29:30 +05302959 msm_otg_start_host(otg, 1);
2960 msm_chg_enable_aca_det(motg);
2961 msm_chg_disable_aca_intr(motg);
Chiranjeevi Velempati489a27c2012-03-29 09:47:17 +05302962 mod_timer(&motg->id_timer, ID_TIMER_FREQ);
Vijayavardhan Vennapusaa3152032012-03-05 16:29:30 +05302963 if (msm_chg_check_aca_intr(motg))
2964 work = 1;
2965 }
2966 break;
2967 case OTG_STATE_A_WAIT_BCON:
2968 if ((test_bit(ID, &motg->inputs) &&
2969 !test_bit(ID_A, &motg->inputs)) ||
2970 test_bit(A_BUS_DROP, &motg->inputs) ||
2971 test_bit(A_WAIT_BCON, &motg->tmouts)) {
2972 pr_debug("(id && id_a/b/c) || a_bus_drop ||"
2973 "a_wait_bcon_tmout\n");
2974 if (test_bit(A_WAIT_BCON, &motg->tmouts)) {
2975 pr_info("Device No Response\n");
2976 otg_send_event(OTG_EVENT_DEV_CONN_TMOUT);
2977 }
2978 msm_otg_del_timer(motg);
2979 clear_bit(A_BUS_REQ, &motg->inputs);
2980 clear_bit(B_CONN, &motg->inputs);
2981 msm_otg_start_host(otg, 0);
2982 /*
2983 * ACA: ID_A with NO accessory, just the A plug is
2984 * attached to ACA: Use IDCHG_MAX for charging
2985 */
2986 if (test_bit(ID_A, &motg->inputs))
2987 msm_otg_notify_charger(motg, IDEV_CHG_MIN);
2988 else
2989 msm_hsusb_vbus_power(motg, 0);
Steve Mucklef132c6c2012-06-06 18:30:57 -07002990 otg->phy->state = OTG_STATE_A_WAIT_VFALL;
Vijayavardhan Vennapusaa3152032012-03-05 16:29:30 +05302991 msm_otg_start_timer(motg, TA_WAIT_VFALL, A_WAIT_VFALL);
2992 } else if (!test_bit(A_VBUS_VLD, &motg->inputs)) {
2993 pr_debug("!a_vbus_vld\n");
2994 clear_bit(B_CONN, &motg->inputs);
2995 msm_otg_del_timer(motg);
2996 msm_otg_start_host(otg, 0);
Steve Mucklef132c6c2012-06-06 18:30:57 -07002997 otg->phy->state = OTG_STATE_A_VBUS_ERR;
2998 msm_otg_reset(otg->phy);
Vijayavardhan Vennapusaa3152032012-03-05 16:29:30 +05302999 } else if (test_bit(ID_A, &motg->inputs)) {
3000 msm_hsusb_vbus_power(motg, 0);
3001 } else if (!test_bit(A_BUS_REQ, &motg->inputs)) {
3002 /*
3003 * If TA_WAIT_BCON is infinite, we don;t
3004 * turn off VBUS. Enter low power mode.
3005 */
3006 if (TA_WAIT_BCON < 0)
Steve Mucklef132c6c2012-06-06 18:30:57 -07003007 pm_runtime_put_sync(otg->phy->dev);
Vijayavardhan Vennapusaa3152032012-03-05 16:29:30 +05303008 } else if (!test_bit(ID, &motg->inputs)) {
3009 msm_hsusb_vbus_power(motg, 1);
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05303010 }
3011 break;
3012 case OTG_STATE_A_HOST:
Vijayavardhan Vennapusaa3152032012-03-05 16:29:30 +05303013 if ((test_bit(ID, &motg->inputs) &&
3014 !test_bit(ID_A, &motg->inputs)) ||
3015 test_bit(A_BUS_DROP, &motg->inputs)) {
3016 pr_debug("id_a/b/c || a_bus_drop\n");
3017 clear_bit(B_CONN, &motg->inputs);
3018 clear_bit(A_BUS_REQ, &motg->inputs);
3019 msm_otg_del_timer(motg);
Steve Mucklef132c6c2012-06-06 18:30:57 -07003020 otg->phy->state = OTG_STATE_A_WAIT_VFALL;
Vijayavardhan Vennapusaa3152032012-03-05 16:29:30 +05303021 msm_otg_start_host(otg, 0);
3022 if (!test_bit(ID_A, &motg->inputs))
3023 msm_hsusb_vbus_power(motg, 0);
3024 msm_otg_start_timer(motg, TA_WAIT_VFALL, A_WAIT_VFALL);
3025 } else if (!test_bit(A_VBUS_VLD, &motg->inputs)) {
3026 pr_debug("!a_vbus_vld\n");
3027 clear_bit(B_CONN, &motg->inputs);
3028 msm_otg_del_timer(motg);
Steve Mucklef132c6c2012-06-06 18:30:57 -07003029 otg->phy->state = OTG_STATE_A_VBUS_ERR;
Vijayavardhan Vennapusaa3152032012-03-05 16:29:30 +05303030 msm_otg_start_host(otg, 0);
Heikki Krogerus1d4c9292012-02-13 13:24:09 +02003031 msm_otg_reset(otg->phy);
Vijayavardhan Vennapusaa3152032012-03-05 16:29:30 +05303032 } else if (!test_bit(A_BUS_REQ, &motg->inputs)) {
3033 /*
3034 * a_bus_req is de-asserted when root hub is
3035 * suspended or HNP is in progress.
3036 */
3037 pr_debug("!a_bus_req\n");
3038 msm_otg_del_timer(motg);
Steve Mucklef132c6c2012-06-06 18:30:57 -07003039 otg->phy->state = OTG_STATE_A_SUSPEND;
Vijayavardhan Vennapusaa3152032012-03-05 16:29:30 +05303040 if (otg->host->b_hnp_enable)
3041 msm_otg_start_timer(motg, TA_AIDL_BDIS,
3042 A_AIDL_BDIS);
3043 else
Steve Mucklef132c6c2012-06-06 18:30:57 -07003044 pm_runtime_put_sync(otg->phy->dev);
Vijayavardhan Vennapusaa3152032012-03-05 16:29:30 +05303045 } else if (!test_bit(B_CONN, &motg->inputs)) {
3046 pr_debug("!b_conn\n");
3047 msm_otg_del_timer(motg);
Steve Mucklef132c6c2012-06-06 18:30:57 -07003048 otg->phy->state = OTG_STATE_A_WAIT_BCON;
Vijayavardhan Vennapusaa3152032012-03-05 16:29:30 +05303049 if (TA_WAIT_BCON > 0)
3050 msm_otg_start_timer(motg, TA_WAIT_BCON,
3051 A_WAIT_BCON);
3052 if (msm_chg_check_aca_intr(motg))
3053 work = 1;
3054 } else if (test_bit(ID_A, &motg->inputs)) {
3055 msm_otg_del_timer(motg);
3056 msm_hsusb_vbus_power(motg, 0);
3057 if (motg->chg_type == USB_ACA_DOCK_CHARGER)
3058 msm_otg_notify_charger(motg,
3059 IDEV_ACA_CHG_MAX);
3060 else
3061 msm_otg_notify_charger(motg,
3062 IDEV_CHG_MIN - motg->mA_port);
3063 } else if (!test_bit(ID, &motg->inputs)) {
3064 motg->chg_state = USB_CHG_STATE_UNDEFINED;
3065 motg->chg_type = USB_INVALID_CHARGER;
3066 msm_otg_notify_charger(motg, 0);
3067 msm_hsusb_vbus_power(motg, 1);
3068 }
3069 break;
3070 case OTG_STATE_A_SUSPEND:
3071 if ((test_bit(ID, &motg->inputs) &&
3072 !test_bit(ID_A, &motg->inputs)) ||
3073 test_bit(A_BUS_DROP, &motg->inputs) ||
3074 test_bit(A_AIDL_BDIS, &motg->tmouts)) {
3075 pr_debug("id_a/b/c || a_bus_drop ||"
3076 "a_aidl_bdis_tmout\n");
3077 msm_otg_del_timer(motg);
3078 clear_bit(B_CONN, &motg->inputs);
Steve Mucklef132c6c2012-06-06 18:30:57 -07003079 otg->phy->state = OTG_STATE_A_WAIT_VFALL;
Vijayavardhan Vennapusaa3152032012-03-05 16:29:30 +05303080 msm_otg_start_host(otg, 0);
Steve Mucklef132c6c2012-06-06 18:30:57 -07003081 msm_otg_reset(otg->phy);
Vijayavardhan Vennapusaa3152032012-03-05 16:29:30 +05303082 if (!test_bit(ID_A, &motg->inputs))
3083 msm_hsusb_vbus_power(motg, 0);
3084 msm_otg_start_timer(motg, TA_WAIT_VFALL, A_WAIT_VFALL);
3085 } else if (!test_bit(A_VBUS_VLD, &motg->inputs)) {
3086 pr_debug("!a_vbus_vld\n");
3087 msm_otg_del_timer(motg);
3088 clear_bit(B_CONN, &motg->inputs);
Steve Mucklef132c6c2012-06-06 18:30:57 -07003089 otg->phy->state = OTG_STATE_A_VBUS_ERR;
Vijayavardhan Vennapusaa3152032012-03-05 16:29:30 +05303090 msm_otg_start_host(otg, 0);
Steve Mucklef132c6c2012-06-06 18:30:57 -07003091 msm_otg_reset(otg->phy);
Vijayavardhan Vennapusaa3152032012-03-05 16:29:30 +05303092 } else if (!test_bit(B_CONN, &motg->inputs) &&
3093 otg->host->b_hnp_enable) {
3094 pr_debug("!b_conn && b_hnp_enable");
Steve Mucklef132c6c2012-06-06 18:30:57 -07003095 otg->phy->state = OTG_STATE_A_PERIPHERAL;
Vijayavardhan Vennapusaa3152032012-03-05 16:29:30 +05303096 msm_otg_host_hnp_enable(otg, 1);
3097 otg->gadget->is_a_peripheral = 1;
3098 msm_otg_start_peripheral(otg, 1);
3099 } else if (!test_bit(B_CONN, &motg->inputs) &&
3100 !otg->host->b_hnp_enable) {
3101 pr_debug("!b_conn && !b_hnp_enable");
3102 /*
3103 * bus request is dropped during suspend.
3104 * acquire again for next device.
3105 */
3106 set_bit(A_BUS_REQ, &motg->inputs);
Steve Mucklef132c6c2012-06-06 18:30:57 -07003107 otg->phy->state = OTG_STATE_A_WAIT_BCON;
Vijayavardhan Vennapusaa3152032012-03-05 16:29:30 +05303108 if (TA_WAIT_BCON > 0)
3109 msm_otg_start_timer(motg, TA_WAIT_BCON,
3110 A_WAIT_BCON);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003111 } else if (test_bit(ID_A, &motg->inputs)) {
Mayank Ranae3926882011-12-26 09:47:54 +05303112 msm_hsusb_vbus_power(motg, 0);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003113 msm_otg_notify_charger(motg,
Vijayavardhan Vennapusaa3152032012-03-05 16:29:30 +05303114 IDEV_CHG_MIN - motg->mA_port);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003115 } else if (!test_bit(ID, &motg->inputs)) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003116 msm_otg_notify_charger(motg, 0);
Mayank Ranae3926882011-12-26 09:47:54 +05303117 msm_hsusb_vbus_power(motg, 1);
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05303118 }
3119 break;
Vijayavardhan Vennapusaa3152032012-03-05 16:29:30 +05303120 case OTG_STATE_A_PERIPHERAL:
3121 if ((test_bit(ID, &motg->inputs) &&
3122 !test_bit(ID_A, &motg->inputs)) ||
3123 test_bit(A_BUS_DROP, &motg->inputs)) {
3124 pr_debug("id _f/b/c || a_bus_drop\n");
3125 /* Clear BIDL_ADIS timer */
3126 msm_otg_del_timer(motg);
Steve Mucklef132c6c2012-06-06 18:30:57 -07003127 otg->phy->state = OTG_STATE_A_WAIT_VFALL;
Vijayavardhan Vennapusaa3152032012-03-05 16:29:30 +05303128 msm_otg_start_peripheral(otg, 0);
3129 otg->gadget->is_a_peripheral = 0;
3130 msm_otg_start_host(otg, 0);
Steve Mucklef132c6c2012-06-06 18:30:57 -07003131 msm_otg_reset(otg->phy);
Vijayavardhan Vennapusaa3152032012-03-05 16:29:30 +05303132 if (!test_bit(ID_A, &motg->inputs))
3133 msm_hsusb_vbus_power(motg, 0);
3134 msm_otg_start_timer(motg, TA_WAIT_VFALL, A_WAIT_VFALL);
3135 } else if (!test_bit(A_VBUS_VLD, &motg->inputs)) {
3136 pr_debug("!a_vbus_vld\n");
3137 /* Clear BIDL_ADIS timer */
3138 msm_otg_del_timer(motg);
Steve Mucklef132c6c2012-06-06 18:30:57 -07003139 otg->phy->state = OTG_STATE_A_VBUS_ERR;
Vijayavardhan Vennapusaa3152032012-03-05 16:29:30 +05303140 msm_otg_start_peripheral(otg, 0);
3141 otg->gadget->is_a_peripheral = 0;
3142 msm_otg_start_host(otg, 0);
3143 } else if (test_bit(A_BIDL_ADIS, &motg->tmouts)) {
3144 pr_debug("a_bidl_adis_tmout\n");
3145 msm_otg_start_peripheral(otg, 0);
3146 otg->gadget->is_a_peripheral = 0;
Steve Mucklef132c6c2012-06-06 18:30:57 -07003147 otg->phy->state = OTG_STATE_A_WAIT_BCON;
Vijayavardhan Vennapusaa3152032012-03-05 16:29:30 +05303148 set_bit(A_BUS_REQ, &motg->inputs);
3149 msm_otg_host_hnp_enable(otg, 0);
3150 if (TA_WAIT_BCON > 0)
3151 msm_otg_start_timer(motg, TA_WAIT_BCON,
3152 A_WAIT_BCON);
3153 } else if (test_bit(ID_A, &motg->inputs)) {
3154 msm_hsusb_vbus_power(motg, 0);
3155 msm_otg_notify_charger(motg,
3156 IDEV_CHG_MIN - motg->mA_port);
3157 } else if (!test_bit(ID, &motg->inputs)) {
3158 msm_otg_notify_charger(motg, 0);
3159 msm_hsusb_vbus_power(motg, 1);
3160 }
3161 break;
3162 case OTG_STATE_A_WAIT_VFALL:
3163 if (test_bit(A_WAIT_VFALL, &motg->tmouts)) {
3164 clear_bit(A_VBUS_VLD, &motg->inputs);
Steve Mucklef132c6c2012-06-06 18:30:57 -07003165 otg->phy->state = OTG_STATE_A_IDLE;
Vijayavardhan Vennapusaa3152032012-03-05 16:29:30 +05303166 work = 1;
3167 }
3168 break;
3169 case OTG_STATE_A_VBUS_ERR:
3170 if ((test_bit(ID, &motg->inputs) &&
3171 !test_bit(ID_A, &motg->inputs)) ||
3172 test_bit(A_BUS_DROP, &motg->inputs) ||
3173 test_bit(A_CLR_ERR, &motg->inputs)) {
Steve Mucklef132c6c2012-06-06 18:30:57 -07003174 otg->phy->state = OTG_STATE_A_WAIT_VFALL;
Vijayavardhan Vennapusaa3152032012-03-05 16:29:30 +05303175 if (!test_bit(ID_A, &motg->inputs))
3176 msm_hsusb_vbus_power(motg, 0);
3177 msm_otg_start_timer(motg, TA_WAIT_VFALL, A_WAIT_VFALL);
3178 motg->chg_state = USB_CHG_STATE_UNDEFINED;
3179 motg->chg_type = USB_INVALID_CHARGER;
3180 msm_otg_notify_charger(motg, 0);
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05303181 }
3182 break;
3183 default:
3184 break;
3185 }
Vijayavardhan Vennapusaa3152032012-03-05 16:29:30 +05303186 if (work)
3187 queue_work(system_nrt_wq, &motg->sm_work);
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05303188}
3189
Amit Blayd0fe07b2012-09-05 16:42:09 +03003190static void msm_otg_suspend_work(struct work_struct *w)
3191{
3192 struct msm_otg *motg =
3193 container_of(w, struct msm_otg, suspend_work.work);
Pavankumar Kondetie618bf82012-11-28 21:12:44 +05303194
3195 /* This work is only for device bus suspend */
3196 if (test_bit(A_BUS_SUSPEND, &motg->inputs))
3197 msm_otg_sm_work(&motg->sm_work);
Amit Blayd0fe07b2012-09-05 16:42:09 +03003198}
3199
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05303200static irqreturn_t msm_otg_irq(int irq, void *data)
3201{
3202 struct msm_otg *motg = data;
Steve Mucklef132c6c2012-06-06 18:30:57 -07003203 struct usb_otg *otg = motg->phy.otg;
Vijayavardhan Vennapusaa3152032012-03-05 16:29:30 +05303204 u32 otgsc = 0, usbsts, pc;
3205 bool work = 0;
3206 irqreturn_t ret = IRQ_HANDLED;
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05303207
Pavankumar Kondeti87c01042010-12-07 17:53:58 +05303208 if (atomic_read(&motg->in_lpm)) {
Manu Gautamf8c45642012-08-10 10:20:56 -07003209 pr_debug("OTG IRQ: %d in LPM\n", irq);
Pavankumar Kondeti87c01042010-12-07 17:53:58 +05303210 disable_irq_nosync(irq);
Manu Gautamf8c45642012-08-10 10:20:56 -07003211 motg->async_int = irq;
Jack Phamc7edb172012-08-13 15:32:39 -07003212 if (!atomic_read(&motg->pm_suspended))
Steve Mucklef132c6c2012-06-06 18:30:57 -07003213 pm_request_resume(otg->phy->dev);
Pavankumar Kondeti87c01042010-12-07 17:53:58 +05303214 return IRQ_HANDLED;
3215 }
3216
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003217 usbsts = readl(USB_USBSTS);
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05303218 otgsc = readl(USB_OTGSC);
Vijayavardhan Vennapusaa3152032012-03-05 16:29:30 +05303219
3220 if (!(otgsc & OTG_OTGSTS_MASK) && !(usbsts & OTG_USBSTS_MASK))
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05303221 return IRQ_NONE;
3222
3223 if ((otgsc & OTGSC_IDIS) && (otgsc & OTGSC_IDIE)) {
Pavankumar Kondetiaa449e12011-11-04 11:09:26 +05303224 if (otgsc & OTGSC_ID) {
Stephen Boyd9850acb2013-01-28 14:11:20 -08003225 dev_dbg(otg->phy->dev, "ID set\n");
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05303226 set_bit(ID, &motg->inputs);
Pavankumar Kondetiaa449e12011-11-04 11:09:26 +05303227 } else {
Stephen Boyd9850acb2013-01-28 14:11:20 -08003228 dev_dbg(otg->phy->dev, "ID clear\n");
Vijayavardhan Vennapusaa3152032012-03-05 16:29:30 +05303229 /*
3230 * Assert a_bus_req to supply power on
3231 * VBUS when Micro/Mini-A cable is connected
3232 * with out user intervention.
3233 */
3234 set_bit(A_BUS_REQ, &motg->inputs);
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05303235 clear_bit(ID, &motg->inputs);
Pavankumar Kondetiaa449e12011-11-04 11:09:26 +05303236 msm_chg_enable_aca_det(motg);
3237 }
Vijayavardhan Vennapusaa3152032012-03-05 16:29:30 +05303238 writel_relaxed(otgsc, USB_OTGSC);
3239 work = 1;
3240 } else if (otgsc & OTGSC_DPIS) {
3241 pr_debug("DPIS detected\n");
3242 writel_relaxed(otgsc, USB_OTGSC);
3243 set_bit(A_SRP_DET, &motg->inputs);
3244 set_bit(A_BUS_REQ, &motg->inputs);
3245 work = 1;
Vamsi Krishnaef6e1bf2013-03-02 15:36:17 -08003246 } else if ((otgsc & OTGSC_BSVIE) && (otgsc & OTGSC_BSVIS)) {
Vijayavardhan Vennapusaa3152032012-03-05 16:29:30 +05303247 writel_relaxed(otgsc, USB_OTGSC);
3248 /*
3249 * BSV interrupt comes when operating as an A-device
3250 * (VBUS on/off).
3251 * But, handle BSV when charger is removed from ACA in ID_A
3252 */
Steve Mucklef132c6c2012-06-06 18:30:57 -07003253 if ((otg->phy->state >= OTG_STATE_A_IDLE) &&
Vijayavardhan Vennapusaa3152032012-03-05 16:29:30 +05303254 !test_bit(ID_A, &motg->inputs))
3255 return IRQ_HANDLED;
Pavankumar Kondetiaa449e12011-11-04 11:09:26 +05303256 if (otgsc & OTGSC_BSV) {
Stephen Boyd9850acb2013-01-28 14:11:20 -08003257 dev_dbg(otg->phy->dev, "BSV set\n");
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05303258 set_bit(B_SESS_VLD, &motg->inputs);
Pavankumar Kondetiaa449e12011-11-04 11:09:26 +05303259 } else {
Stephen Boyd9850acb2013-01-28 14:11:20 -08003260 dev_dbg(otg->phy->dev, "BSV clear\n");
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05303261 clear_bit(B_SESS_VLD, &motg->inputs);
Amit Blay6fa647a2012-05-24 14:12:08 +03003262 clear_bit(A_BUS_SUSPEND, &motg->inputs);
3263
Pavankumar Kondetiaa449e12011-11-04 11:09:26 +05303264 msm_chg_check_aca_intr(motg);
3265 }
Vijayavardhan Vennapusaa3152032012-03-05 16:29:30 +05303266 work = 1;
3267 } else if (usbsts & STS_PCI) {
3268 pc = readl_relaxed(USB_PORTSC);
3269 pr_debug("portsc = %x\n", pc);
3270 ret = IRQ_NONE;
3271 /*
3272 * HCD Acks PCI interrupt. We use this to switch
3273 * between different OTG states.
3274 */
3275 work = 1;
Steve Mucklef132c6c2012-06-06 18:30:57 -07003276 switch (otg->phy->state) {
Vijayavardhan Vennapusaa3152032012-03-05 16:29:30 +05303277 case OTG_STATE_A_SUSPEND:
3278 if (otg->host->b_hnp_enable && (pc & PORTSC_CSC) &&
3279 !(pc & PORTSC_CCS)) {
3280 pr_debug("B_CONN clear\n");
3281 clear_bit(B_CONN, &motg->inputs);
3282 msm_otg_del_timer(motg);
3283 }
3284 break;
3285 case OTG_STATE_A_PERIPHERAL:
3286 /*
3287 * A-peripheral observed activity on bus.
3288 * clear A_BIDL_ADIS timer.
3289 */
3290 msm_otg_del_timer(motg);
3291 work = 0;
3292 break;
3293 case OTG_STATE_B_WAIT_ACON:
3294 if ((pc & PORTSC_CSC) && (pc & PORTSC_CCS)) {
3295 pr_debug("A_CONN set\n");
3296 set_bit(A_CONN, &motg->inputs);
3297 /* Clear ASE0_BRST timer */
3298 msm_otg_del_timer(motg);
3299 }
3300 break;
3301 case OTG_STATE_B_HOST:
3302 if ((pc & PORTSC_CSC) && !(pc & PORTSC_CCS)) {
3303 pr_debug("A_CONN clear\n");
3304 clear_bit(A_CONN, &motg->inputs);
3305 msm_otg_del_timer(motg);
3306 }
3307 break;
3308 case OTG_STATE_A_WAIT_BCON:
3309 if (TA_WAIT_BCON < 0)
3310 set_bit(A_BUS_REQ, &motg->inputs);
3311 default:
3312 work = 0;
3313 break;
3314 }
3315 } else if (usbsts & STS_URI) {
3316 ret = IRQ_NONE;
Steve Mucklef132c6c2012-06-06 18:30:57 -07003317 switch (otg->phy->state) {
Vijayavardhan Vennapusaa3152032012-03-05 16:29:30 +05303318 case OTG_STATE_A_PERIPHERAL:
3319 /*
3320 * A-peripheral observed activity on bus.
3321 * clear A_BIDL_ADIS timer.
3322 */
3323 msm_otg_del_timer(motg);
3324 work = 0;
3325 break;
3326 default:
3327 work = 0;
3328 break;
3329 }
3330 } else if (usbsts & STS_SLI) {
3331 ret = IRQ_NONE;
3332 work = 0;
Steve Mucklef132c6c2012-06-06 18:30:57 -07003333 switch (otg->phy->state) {
Vijayavardhan Vennapusaa3152032012-03-05 16:29:30 +05303334 case OTG_STATE_B_PERIPHERAL:
3335 if (otg->gadget->b_hnp_enable) {
3336 set_bit(A_BUS_SUSPEND, &motg->inputs);
3337 set_bit(B_BUS_REQ, &motg->inputs);
3338 work = 1;
3339 }
3340 break;
3341 case OTG_STATE_A_PERIPHERAL:
3342 msm_otg_start_timer(motg, TA_BIDL_ADIS,
3343 A_BIDL_ADIS);
3344 break;
3345 default:
3346 break;
3347 }
3348 } else if ((usbsts & PHY_ALT_INT)) {
3349 writel_relaxed(PHY_ALT_INT, USB_USBSTS);
3350 if (msm_chg_check_aca_intr(motg))
3351 work = 1;
3352 ret = IRQ_HANDLED;
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05303353 }
Vijayavardhan Vennapusaa3152032012-03-05 16:29:30 +05303354 if (work)
3355 queue_work(system_nrt_wq, &motg->sm_work);
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05303356
Vijayavardhan Vennapusaa3152032012-03-05 16:29:30 +05303357 return ret;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003358}
3359
3360static void msm_otg_set_vbus_state(int online)
3361{
Pavankumar Kondeti4960f312011-12-06 15:46:14 +05303362 static bool init;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003363 struct msm_otg *motg = the_msm_otg;
Mayank Ranabaf31f42012-07-05 09:43:54 +05303364
Vamsi Krishna945b4a92013-03-02 15:31:16 -08003365 if (online) {
3366 pr_debug("PMIC: BSV set\n");
3367 set_bit(B_SESS_VLD, &motg->inputs);
3368 } else {
3369 pr_debug("PMIC: BSV clear\n");
3370 clear_bit(B_SESS_VLD, &motg->inputs);
3371 }
3372
3373 /* do not queue state m/c work if id is grounded */
Pavankumar Kondetibbaa46ff2012-12-09 20:21:02 +05303374 if (!test_bit(ID, &motg->inputs)) {
3375 /*
3376 * state machine work waits for initial VBUS
3377 * completion in UNDEFINED state. Process
3378 * the initial VBUS event in ID_GND state.
3379 */
3380 if (init)
3381 return;
Pavankumar Kondetibbaa46ff2012-12-09 20:21:02 +05303382 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003383
Pavankumar Kondeti4960f312011-12-06 15:46:14 +05303384 if (!init) {
3385 init = true;
3386 complete(&pmic_vbus_init);
3387 pr_debug("PMIC: BSV init complete\n");
3388 return;
3389 }
3390
Pavankumar Kondeti2aec9f32012-06-13 09:06:03 +05303391 if (test_bit(MHL, &motg->inputs) ||
3392 mhl_det_in_progress) {
3393 pr_debug("PMIC: BSV interrupt ignored in MHL\n");
3394 return;
3395 }
3396
Jack Pham5ca279b2012-05-14 18:42:54 -07003397 if (atomic_read(&motg->pm_suspended))
3398 motg->sm_work_pending = true;
3399 else
3400 queue_work(system_nrt_wq, &motg->sm_work);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003401}
3402
Vijayavardhan Vennapusa68d55cf2012-06-27 20:06:12 +05303403static void msm_pmic_id_status_w(struct work_struct *w)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003404{
Vijayavardhan Vennapusa68d55cf2012-06-27 20:06:12 +05303405 struct msm_otg *motg = container_of(w, struct msm_otg,
3406 pmic_id_status_work.work);
3407 int work = 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003408
Pavankumar Kondetibecab5b2012-11-06 16:45:10 +05303409 if (msm_otg_read_pmic_id_state(motg)) {
Vijayavardhan Vennapusa68d55cf2012-06-27 20:06:12 +05303410 if (!test_and_set_bit(ID, &motg->inputs)) {
3411 pr_debug("PMIC: ID set\n");
3412 work = 1;
3413 }
Pavankumar Kondeti4960f312011-12-06 15:46:14 +05303414 } else {
Vijayavardhan Vennapusa68d55cf2012-06-27 20:06:12 +05303415 if (test_and_clear_bit(ID, &motg->inputs)) {
3416 pr_debug("PMIC: ID clear\n");
3417 set_bit(A_BUS_REQ, &motg->inputs);
3418 work = 1;
3419 }
Pavankumar Kondeti4960f312011-12-06 15:46:14 +05303420 }
3421
Vijayavardhan Vennapusa68d55cf2012-06-27 20:06:12 +05303422 if (work && (motg->phy.state != OTG_STATE_UNDEFINED)) {
Jack Pham5ca279b2012-05-14 18:42:54 -07003423 if (atomic_read(&motg->pm_suspended))
3424 motg->sm_work_pending = true;
3425 else
3426 queue_work(system_nrt_wq, &motg->sm_work);
3427 }
Vijayavardhan Vennapusa68d55cf2012-06-27 20:06:12 +05303428
3429}
3430
3431#define MSM_PMIC_ID_STATUS_DELAY 5 /* 5msec */
3432static irqreturn_t msm_pmic_id_irq(int irq, void *data)
3433{
3434 struct msm_otg *motg = data;
3435
Pavankumar Kondeti2aec9f32012-06-13 09:06:03 +05303436 if (test_bit(MHL, &motg->inputs) ||
3437 mhl_det_in_progress) {
3438 pr_debug("PMIC: Id interrupt ignored in MHL\n");
3439 return IRQ_HANDLED;
3440 }
3441
Vijayavardhan Vennapusa68d55cf2012-06-27 20:06:12 +05303442 if (!aca_id_turned_on)
3443 /*schedule delayed work for 5msec for ID line state to settle*/
3444 queue_delayed_work(system_nrt_wq, &motg->pmic_id_status_work,
3445 msecs_to_jiffies(MSM_PMIC_ID_STATUS_DELAY));
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003446
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05303447 return IRQ_HANDLED;
3448}
3449
3450static int msm_otg_mode_show(struct seq_file *s, void *unused)
3451{
3452 struct msm_otg *motg = s->private;
Stephen Boyd9850acb2013-01-28 14:11:20 -08003453 struct usb_otg *otg = motg->phy.otg;
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05303454
Stephen Boyd9850acb2013-01-28 14:11:20 -08003455 switch (otg->phy->state) {
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05303456 case OTG_STATE_A_HOST:
3457 seq_printf(s, "host\n");
3458 break;
3459 case OTG_STATE_B_PERIPHERAL:
3460 seq_printf(s, "peripheral\n");
3461 break;
3462 default:
3463 seq_printf(s, "none\n");
3464 break;
3465 }
3466
3467 return 0;
3468}
3469
3470static int msm_otg_mode_open(struct inode *inode, struct file *file)
3471{
3472 return single_open(file, msm_otg_mode_show, inode->i_private);
3473}
3474
3475static ssize_t msm_otg_mode_write(struct file *file, const char __user *ubuf,
3476 size_t count, loff_t *ppos)
3477{
Pavankumar Kondetie2904ee2011-02-15 09:42:35 +05303478 struct seq_file *s = file->private_data;
3479 struct msm_otg *motg = s->private;
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05303480 char buf[16];
Steve Mucklef132c6c2012-06-06 18:30:57 -07003481 struct usb_phy *phy = &motg->phy;
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05303482 int status = count;
3483 enum usb_mode_type req_mode;
3484
3485 memset(buf, 0x00, sizeof(buf));
3486
3487 if (copy_from_user(&buf, ubuf, min_t(size_t, sizeof(buf) - 1, count))) {
3488 status = -EFAULT;
3489 goto out;
3490 }
3491
3492 if (!strncmp(buf, "host", 4)) {
3493 req_mode = USB_HOST;
3494 } else if (!strncmp(buf, "peripheral", 10)) {
3495 req_mode = USB_PERIPHERAL;
3496 } else if (!strncmp(buf, "none", 4)) {
3497 req_mode = USB_NONE;
3498 } else {
3499 status = -EINVAL;
3500 goto out;
3501 }
3502
3503 switch (req_mode) {
3504 case USB_NONE:
Steve Mucklef132c6c2012-06-06 18:30:57 -07003505 switch (phy->state) {
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05303506 case OTG_STATE_A_HOST:
3507 case OTG_STATE_B_PERIPHERAL:
3508 set_bit(ID, &motg->inputs);
3509 clear_bit(B_SESS_VLD, &motg->inputs);
3510 break;
3511 default:
3512 goto out;
3513 }
3514 break;
3515 case USB_PERIPHERAL:
Steve Mucklef132c6c2012-06-06 18:30:57 -07003516 switch (phy->state) {
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05303517 case OTG_STATE_B_IDLE:
3518 case OTG_STATE_A_HOST:
3519 set_bit(ID, &motg->inputs);
3520 set_bit(B_SESS_VLD, &motg->inputs);
3521 break;
3522 default:
3523 goto out;
3524 }
3525 break;
3526 case USB_HOST:
Steve Mucklef132c6c2012-06-06 18:30:57 -07003527 switch (phy->state) {
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05303528 case OTG_STATE_B_IDLE:
3529 case OTG_STATE_B_PERIPHERAL:
3530 clear_bit(ID, &motg->inputs);
3531 break;
3532 default:
3533 goto out;
3534 }
3535 break;
3536 default:
3537 goto out;
3538 }
3539
Steve Mucklef132c6c2012-06-06 18:30:57 -07003540 pm_runtime_resume(phy->dev);
Vijayavardhan Vennapusaa3152032012-03-05 16:29:30 +05303541 queue_work(system_nrt_wq, &motg->sm_work);
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05303542out:
3543 return status;
3544}
3545
3546const struct file_operations msm_otg_mode_fops = {
3547 .open = msm_otg_mode_open,
3548 .read = seq_read,
3549 .write = msm_otg_mode_write,
3550 .llseek = seq_lseek,
3551 .release = single_release,
3552};
3553
Chiranjeevi Velempatif9a11542012-03-28 18:18:34 +05303554static int msm_otg_show_otg_state(struct seq_file *s, void *unused)
3555{
3556 struct msm_otg *motg = s->private;
Steve Mucklef132c6c2012-06-06 18:30:57 -07003557 struct usb_phy *phy = &motg->phy;
Chiranjeevi Velempatif9a11542012-03-28 18:18:34 +05303558
Steve Mucklef132c6c2012-06-06 18:30:57 -07003559 seq_printf(s, "%s\n", otg_state_string(phy->state));
Chiranjeevi Velempatif9a11542012-03-28 18:18:34 +05303560 return 0;
3561}
3562
3563static int msm_otg_otg_state_open(struct inode *inode, struct file *file)
3564{
3565 return single_open(file, msm_otg_show_otg_state, inode->i_private);
3566}
3567
3568const struct file_operations msm_otg_state_fops = {
3569 .open = msm_otg_otg_state_open,
3570 .read = seq_read,
3571 .llseek = seq_lseek,
3572 .release = single_release,
3573};
3574
Anji jonnalad270e2d2011-08-09 11:28:32 +05303575static int msm_otg_show_chg_type(struct seq_file *s, void *unused)
3576{
3577 struct msm_otg *motg = s->private;
3578
Pavankumar Kondeti9ef69cb2011-12-12 14:18:22 +05303579 seq_printf(s, "%s\n", chg_to_string(motg->chg_type));
Anji jonnalad270e2d2011-08-09 11:28:32 +05303580 return 0;
3581}
3582
3583static int msm_otg_chg_open(struct inode *inode, struct file *file)
3584{
3585 return single_open(file, msm_otg_show_chg_type, inode->i_private);
3586}
3587
3588const struct file_operations msm_otg_chg_fops = {
3589 .open = msm_otg_chg_open,
3590 .read = seq_read,
3591 .llseek = seq_lseek,
3592 .release = single_release,
3593};
3594
Pavankumar Kondetiaa449e12011-11-04 11:09:26 +05303595static int msm_otg_aca_show(struct seq_file *s, void *unused)
3596{
3597 if (debug_aca_enabled)
3598 seq_printf(s, "enabled\n");
3599 else
3600 seq_printf(s, "disabled\n");
3601
3602 return 0;
3603}
3604
3605static int msm_otg_aca_open(struct inode *inode, struct file *file)
3606{
3607 return single_open(file, msm_otg_aca_show, inode->i_private);
3608}
3609
3610static ssize_t msm_otg_aca_write(struct file *file, const char __user *ubuf,
3611 size_t count, loff_t *ppos)
3612{
3613 char buf[8];
3614
3615 memset(buf, 0x00, sizeof(buf));
3616
3617 if (copy_from_user(&buf, ubuf, min_t(size_t, sizeof(buf) - 1, count)))
3618 return -EFAULT;
3619
3620 if (!strncmp(buf, "enable", 6))
3621 debug_aca_enabled = true;
3622 else
3623 debug_aca_enabled = false;
3624
3625 return count;
3626}
3627
3628const struct file_operations msm_otg_aca_fops = {
3629 .open = msm_otg_aca_open,
3630 .read = seq_read,
3631 .write = msm_otg_aca_write,
3632 .llseek = seq_lseek,
3633 .release = single_release,
3634};
3635
Manu Gautam8bdcc592012-03-06 11:26:06 +05303636static int msm_otg_bus_show(struct seq_file *s, void *unused)
3637{
3638 if (debug_bus_voting_enabled)
3639 seq_printf(s, "enabled\n");
3640 else
3641 seq_printf(s, "disabled\n");
3642
3643 return 0;
3644}
3645
3646static int msm_otg_bus_open(struct inode *inode, struct file *file)
3647{
3648 return single_open(file, msm_otg_bus_show, inode->i_private);
3649}
3650
3651static ssize_t msm_otg_bus_write(struct file *file, const char __user *ubuf,
3652 size_t count, loff_t *ppos)
3653{
3654 char buf[8];
Manu Gautam8bdcc592012-03-06 11:26:06 +05303655 struct seq_file *s = file->private_data;
3656 struct msm_otg *motg = s->private;
3657
3658 memset(buf, 0x00, sizeof(buf));
3659
3660 if (copy_from_user(&buf, ubuf, min_t(size_t, sizeof(buf) - 1, count)))
3661 return -EFAULT;
3662
3663 if (!strncmp(buf, "enable", 6)) {
3664 /* Do not vote here. Let OTG statemachine decide when to vote */
3665 debug_bus_voting_enabled = true;
3666 } else {
3667 debug_bus_voting_enabled = false;
Manu Gautame3a39082013-06-11 10:42:56 +05303668 msm_otg_bus_vote(motg, USB_MIN_PERF_VOTE);
Manu Gautam8bdcc592012-03-06 11:26:06 +05303669 }
3670
3671 return count;
3672}
3673
Vijayavardhan Vennapusa29e88802014-02-17 11:09:23 +05303674static int
3675otg_get_prop_usbin_voltage_now(struct msm_otg *motg)
3676{
3677 int rc = 0;
3678 struct qpnp_vadc_result results;
3679
3680 if (IS_ERR_OR_NULL(motg->vadc_dev)) {
3681 motg->vadc_dev = qpnp_get_vadc(motg->phy.dev, "usbin");
3682 if (IS_ERR(motg->vadc_dev))
3683 return PTR_ERR(motg->vadc_dev);
3684 }
3685
3686 rc = qpnp_vadc_read(motg->vadc_dev, USBIN, &results);
3687 if (rc) {
3688 pr_err("Unable to read usbin rc=%d\n", rc);
3689 return 0;
3690 } else {
3691 return results.physical;
3692 }
3693}
3694
David Keitel272ce522012-08-17 16:25:24 -07003695static int otg_power_get_property_usb(struct power_supply *psy,
3696 enum power_supply_property psp,
3697 union power_supply_propval *val)
3698{
Jack Pham0c695282012-10-19 18:13:03 -07003699 struct msm_otg *motg = container_of(psy, struct msm_otg, usb_psy);
David Keitel272ce522012-08-17 16:25:24 -07003700 switch (psp) {
3701 case POWER_SUPPLY_PROP_SCOPE:
3702 if (motg->host_mode)
3703 val->intval = POWER_SUPPLY_SCOPE_SYSTEM;
3704 else
3705 val->intval = POWER_SUPPLY_SCOPE_DEVICE;
3706 break;
Pavankumar Kondeti254e38d2013-07-16 11:13:05 +05303707 case POWER_SUPPLY_PROP_VOLTAGE_MAX:
3708 val->intval = motg->voltage_max;
3709 break;
David Keitel272ce522012-08-17 16:25:24 -07003710 case POWER_SUPPLY_PROP_CURRENT_MAX:
Pavankumar Kondeti254e38d2013-07-16 11:13:05 +05303711 val->intval = motg->current_max;
David Keitel272ce522012-08-17 16:25:24 -07003712 break;
3713 /* Reflect USB enumeration */
3714 case POWER_SUPPLY_PROP_PRESENT:
3715 case POWER_SUPPLY_PROP_ONLINE:
3716 val->intval = motg->online;
3717 break;
Pavankumar Kondetif1ffbdd2013-06-27 13:31:36 +05303718 case POWER_SUPPLY_PROP_TYPE:
3719 val->intval = psy->type;
3720 break;
Wu Fenglin04ae6de2013-09-09 19:15:06 +08003721 case POWER_SUPPLY_PROP_HEALTH:
3722 val->intval = motg->usbin_health;
3723 break;
Vijayavardhan Vennapusa29e88802014-02-17 11:09:23 +05303724 case POWER_SUPPLY_PROP_VOLTAGE_NOW:
3725 val->intval = otg_get_prop_usbin_voltage_now(motg);
3726 break;
David Keitel272ce522012-08-17 16:25:24 -07003727 default:
3728 return -EINVAL;
3729 }
3730 return 0;
3731}
3732
3733static int otg_power_set_property_usb(struct power_supply *psy,
3734 enum power_supply_property psp,
3735 const union power_supply_propval *val)
3736{
Jack Pham0c695282012-10-19 18:13:03 -07003737 struct msm_otg *motg = container_of(psy, struct msm_otg, usb_psy);
David Keitel272ce522012-08-17 16:25:24 -07003738
3739 switch (psp) {
3740 /* Process PMIC notification in PRESENT prop */
3741 case POWER_SUPPLY_PROP_PRESENT:
3742 msm_otg_set_vbus_state(val->intval);
3743 break;
3744 /* The ONLINE property reflects if usb has enumerated */
3745 case POWER_SUPPLY_PROP_ONLINE:
3746 motg->online = val->intval;
3747 break;
Pavankumar Kondeti254e38d2013-07-16 11:13:05 +05303748 case POWER_SUPPLY_PROP_VOLTAGE_MAX:
3749 motg->voltage_max = val->intval;
3750 break;
David Keitel272ce522012-08-17 16:25:24 -07003751 case POWER_SUPPLY_PROP_CURRENT_MAX:
3752 motg->current_max = val->intval;
3753 break;
Pavankumar Kondetif1ffbdd2013-06-27 13:31:36 +05303754 case POWER_SUPPLY_PROP_TYPE:
3755 psy->type = val->intval;
3756 break;
Wu Fenglin04ae6de2013-09-09 19:15:06 +08003757 case POWER_SUPPLY_PROP_HEALTH:
3758 motg->usbin_health = val->intval;
3759 break;
David Keitel272ce522012-08-17 16:25:24 -07003760 default:
3761 return -EINVAL;
3762 }
3763
3764 power_supply_changed(&motg->usb_psy);
3765 return 0;
3766}
3767
David Collinsd79acc52012-11-26 14:59:00 -08003768static int otg_power_property_is_writeable_usb(struct power_supply *psy,
3769 enum power_supply_property psp)
3770{
3771 switch (psp) {
Wu Fenglin04ae6de2013-09-09 19:15:06 +08003772 case POWER_SUPPLY_PROP_HEALTH:
David Collinsd79acc52012-11-26 14:59:00 -08003773 case POWER_SUPPLY_PROP_PRESENT:
3774 case POWER_SUPPLY_PROP_ONLINE:
Pavankumar Kondeti254e38d2013-07-16 11:13:05 +05303775 case POWER_SUPPLY_PROP_VOLTAGE_MAX:
David Collinsd79acc52012-11-26 14:59:00 -08003776 case POWER_SUPPLY_PROP_CURRENT_MAX:
3777 return 1;
3778 default:
3779 break;
3780 }
3781
3782 return 0;
3783}
3784
David Keitel272ce522012-08-17 16:25:24 -07003785static char *otg_pm_power_supplied_to[] = {
3786 "battery",
3787};
3788
3789static enum power_supply_property otg_pm_power_props_usb[] = {
Wu Fenglin04ae6de2013-09-09 19:15:06 +08003790 POWER_SUPPLY_PROP_HEALTH,
David Keitel272ce522012-08-17 16:25:24 -07003791 POWER_SUPPLY_PROP_PRESENT,
3792 POWER_SUPPLY_PROP_ONLINE,
Pavankumar Kondeti254e38d2013-07-16 11:13:05 +05303793 POWER_SUPPLY_PROP_VOLTAGE_MAX,
David Keitel272ce522012-08-17 16:25:24 -07003794 POWER_SUPPLY_PROP_CURRENT_MAX,
3795 POWER_SUPPLY_PROP_SCOPE,
Pavankumar Kondetif1ffbdd2013-06-27 13:31:36 +05303796 POWER_SUPPLY_PROP_TYPE,
Vijayavardhan Vennapusa29e88802014-02-17 11:09:23 +05303797 POWER_SUPPLY_PROP_VOLTAGE_NOW,
David Keitel272ce522012-08-17 16:25:24 -07003798};
3799
Manu Gautam8bdcc592012-03-06 11:26:06 +05303800const struct file_operations msm_otg_bus_fops = {
3801 .open = msm_otg_bus_open,
3802 .read = seq_read,
3803 .write = msm_otg_bus_write,
3804 .llseek = seq_lseek,
3805 .release = single_release,
3806};
3807
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05303808static struct dentry *msm_otg_dbg_root;
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05303809
3810static int msm_otg_debugfs_init(struct msm_otg *motg)
3811{
Manu Gautam8bdcc592012-03-06 11:26:06 +05303812 struct dentry *msm_otg_dentry;
Anji jonnalad270e2d2011-08-09 11:28:32 +05303813
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05303814 msm_otg_dbg_root = debugfs_create_dir("msm_otg", NULL);
3815
3816 if (!msm_otg_dbg_root || IS_ERR(msm_otg_dbg_root))
3817 return -ENODEV;
3818
Anji jonnalad270e2d2011-08-09 11:28:32 +05303819 if (motg->pdata->mode == USB_OTG &&
3820 motg->pdata->otg_control == OTG_USER_CONTROL) {
3821
Manu Gautam8bdcc592012-03-06 11:26:06 +05303822 msm_otg_dentry = debugfs_create_file("mode", S_IRUGO |
Anji jonnalad270e2d2011-08-09 11:28:32 +05303823 S_IWUSR, msm_otg_dbg_root, motg,
3824 &msm_otg_mode_fops);
3825
Manu Gautam8bdcc592012-03-06 11:26:06 +05303826 if (!msm_otg_dentry) {
Anji jonnalad270e2d2011-08-09 11:28:32 +05303827 debugfs_remove(msm_otg_dbg_root);
3828 msm_otg_dbg_root = NULL;
3829 return -ENODEV;
3830 }
3831 }
3832
Manu Gautam8bdcc592012-03-06 11:26:06 +05303833 msm_otg_dentry = debugfs_create_file("chg_type", S_IRUGO,
Anji jonnalad270e2d2011-08-09 11:28:32 +05303834 msm_otg_dbg_root, motg,
3835 &msm_otg_chg_fops);
3836
Manu Gautam8bdcc592012-03-06 11:26:06 +05303837 if (!msm_otg_dentry) {
Pavankumar Kondetiaa449e12011-11-04 11:09:26 +05303838 debugfs_remove_recursive(msm_otg_dbg_root);
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05303839 return -ENODEV;
3840 }
3841
Manu Gautam8bdcc592012-03-06 11:26:06 +05303842 msm_otg_dentry = debugfs_create_file("aca", S_IRUGO | S_IWUSR,
Pavankumar Kondetiaa449e12011-11-04 11:09:26 +05303843 msm_otg_dbg_root, motg,
3844 &msm_otg_aca_fops);
3845
Manu Gautam8bdcc592012-03-06 11:26:06 +05303846 if (!msm_otg_dentry) {
Pavankumar Kondetiaa449e12011-11-04 11:09:26 +05303847 debugfs_remove_recursive(msm_otg_dbg_root);
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05303848 return -ENODEV;
3849 }
3850
Manu Gautam8bdcc592012-03-06 11:26:06 +05303851 msm_otg_dentry = debugfs_create_file("bus_voting", S_IRUGO | S_IWUSR,
3852 msm_otg_dbg_root, motg,
3853 &msm_otg_bus_fops);
3854
3855 if (!msm_otg_dentry) {
3856 debugfs_remove_recursive(msm_otg_dbg_root);
3857 return -ENODEV;
3858 }
Chiranjeevi Velempatif9a11542012-03-28 18:18:34 +05303859
3860 msm_otg_dentry = debugfs_create_file("otg_state", S_IRUGO,
3861 msm_otg_dbg_root, motg, &msm_otg_state_fops);
3862
3863 if (!msm_otg_dentry) {
3864 debugfs_remove_recursive(msm_otg_dbg_root);
3865 return -ENODEV;
3866 }
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05303867 return 0;
3868}
3869
3870static void msm_otg_debugfs_cleanup(void)
3871{
Anji jonnalad270e2d2011-08-09 11:28:32 +05303872 debugfs_remove_recursive(msm_otg_dbg_root);
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05303873}
3874
Manu Gautam0ddbd922012-09-21 17:17:38 +05303875#define MSM_OTG_CMD_ID 0x09
3876#define MSM_OTG_DEVICE_ID 0x04
3877#define MSM_OTG_VMID_IDX 0xFF
3878#define MSM_OTG_MEM_TYPE 0x02
3879struct msm_otg_scm_cmd_buf {
3880 unsigned int device_id;
3881 unsigned int vmid_idx;
3882 unsigned int mem_type;
3883} __attribute__ ((__packed__));
3884
3885static void msm_otg_pnoc_errata_fix(struct msm_otg *motg)
3886{
3887 int ret;
3888 struct msm_otg_platform_data *pdata = motg->pdata;
3889 struct msm_otg_scm_cmd_buf cmd_buf;
3890
3891 if (!pdata->pnoc_errata_fix)
3892 return;
3893
3894 dev_dbg(motg->phy.dev, "applying fix for pnoc h/w issue\n");
3895
3896 cmd_buf.device_id = MSM_OTG_DEVICE_ID;
3897 cmd_buf.vmid_idx = MSM_OTG_VMID_IDX;
3898 cmd_buf.mem_type = MSM_OTG_MEM_TYPE;
3899
Syed Rameez Mustafa6ab6af32013-03-18 12:53:11 -07003900 ret = scm_call(SCM_SVC_MP, MSM_OTG_CMD_ID, &cmd_buf,
Manu Gautam0ddbd922012-09-21 17:17:38 +05303901 sizeof(cmd_buf), NULL, 0);
3902
3903 if (ret)
3904 dev_err(motg->phy.dev, "scm command failed to update VMIDMT\n");
3905}
3906
Pavankumar Kondetieaea7fe2011-10-27 14:46:45 +05303907static u64 msm_otg_dma_mask = DMA_BIT_MASK(64);
3908static struct platform_device *msm_otg_add_pdev(
3909 struct platform_device *ofdev, const char *name)
3910{
3911 struct platform_device *pdev;
3912 const struct resource *res = ofdev->resource;
3913 unsigned int num = ofdev->num_resources;
3914 int retval;
Amit Blayb4f14532013-06-17 22:33:57 +03003915 struct ci13xxx_platform_data ci_pdata;
3916 struct msm_otg_platform_data *otg_pdata;
Pavankumar Kondetieaea7fe2011-10-27 14:46:45 +05303917
3918 pdev = platform_device_alloc(name, -1);
3919 if (!pdev) {
3920 retval = -ENOMEM;
3921 goto error;
3922 }
3923
3924 pdev->dev.coherent_dma_mask = DMA_BIT_MASK(32);
3925 pdev->dev.dma_mask = &msm_otg_dma_mask;
3926
3927 if (num) {
3928 retval = platform_device_add_resources(pdev, res, num);
3929 if (retval)
3930 goto error;
3931 }
3932
Amit Blayb4f14532013-06-17 22:33:57 +03003933 if (!strcmp(name, "msm_hsusb")) {
3934 otg_pdata =
3935 (struct msm_otg_platform_data *)
3936 ofdev->dev.platform_data;
3937 ci_pdata.log2_itc = otg_pdata->log2_itc;
3938 ci_pdata.usb_core_id = 0;
Shimrit Malichi5a2d5b52013-06-20 19:04:28 +03003939 ci_pdata.l1_supported = otg_pdata->l1_supported;
Mayank Rana34f6f3e2013-11-11 12:40:00 +05303940 ci_pdata.enable_ahb2ahb_bypass =
3941 otg_pdata->enable_ahb2ahb_bypass;
Amit Blayb4f14532013-06-17 22:33:57 +03003942 retval = platform_device_add_data(pdev, &ci_pdata,
3943 sizeof(ci_pdata));
3944 if (retval)
3945 goto error;
3946 }
3947
Pavankumar Kondetieaea7fe2011-10-27 14:46:45 +05303948 retval = platform_device_add(pdev);
3949 if (retval)
3950 goto error;
3951
3952 return pdev;
3953
3954error:
3955 platform_device_put(pdev);
3956 return ERR_PTR(retval);
3957}
3958
3959static int msm_otg_setup_devices(struct platform_device *ofdev,
3960 enum usb_mode_type mode, bool init)
3961{
3962 const char *gadget_name = "msm_hsusb";
3963 const char *host_name = "msm_hsusb_host";
3964 static struct platform_device *gadget_pdev;
3965 static struct platform_device *host_pdev;
3966 int retval = 0;
3967
3968 if (!init) {
3969 if (gadget_pdev)
3970 platform_device_unregister(gadget_pdev);
3971 if (host_pdev)
3972 platform_device_unregister(host_pdev);
3973 return 0;
3974 }
3975
3976 switch (mode) {
3977 case USB_OTG:
3978 /* fall through */
3979 case USB_PERIPHERAL:
3980 gadget_pdev = msm_otg_add_pdev(ofdev, gadget_name);
3981 if (IS_ERR(gadget_pdev)) {
3982 retval = PTR_ERR(gadget_pdev);
3983 break;
3984 }
3985 if (mode == USB_PERIPHERAL)
3986 break;
3987 /* fall through */
3988 case USB_HOST:
3989 host_pdev = msm_otg_add_pdev(ofdev, host_name);
3990 if (IS_ERR(host_pdev)) {
3991 retval = PTR_ERR(host_pdev);
3992 if (mode == USB_OTG)
3993 platform_device_unregister(gadget_pdev);
3994 }
3995 break;
3996 default:
3997 break;
3998 }
3999
4000 return retval;
4001}
4002
David Keitel272ce522012-08-17 16:25:24 -07004003static int msm_otg_register_power_supply(struct platform_device *pdev,
4004 struct msm_otg *motg)
4005{
4006 int ret;
4007
4008 ret = power_supply_register(&pdev->dev, &motg->usb_psy);
4009 if (ret < 0) {
4010 dev_err(motg->phy.dev,
4011 "%s:power_supply_register usb failed\n",
4012 __func__);
4013 return ret;
4014 }
4015
4016 legacy_power_supply = false;
4017 return 0;
4018}
4019
Pavankumar Kondetif1ffbdd2013-06-27 13:31:36 +05304020static int msm_otg_ext_chg_open(struct inode *inode, struct file *file)
4021{
4022 struct msm_otg *motg = the_msm_otg;
4023
4024 pr_debug("msm_otg ext chg open\n");
4025
4026 motg->ext_chg_opened = true;
4027 file->private_data = (void *)motg;
4028 return 0;
4029}
4030
4031static long
4032msm_otg_ext_chg_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
4033{
4034 struct msm_otg *motg = file->private_data;
4035 struct msm_usb_chg_info info = {0};
4036 int ret = 0, val;
4037
4038 switch (cmd) {
4039 case MSM_USB_EXT_CHG_INFO:
4040 info.chg_block_type = USB_CHG_BLOCK_ULPI;
4041 info.page_offset = motg->io_res->start & ~PAGE_MASK;
4042 /* mmap() works on PAGE granularity */
4043 info.length = PAGE_SIZE;
4044
4045 if (copy_to_user((void __user *)arg, &info, sizeof(info))) {
4046 pr_err("%s: copy to user failed\n\n", __func__);
4047 ret = -EFAULT;
4048 }
4049 break;
4050 case MSM_USB_EXT_CHG_BLOCK_LPM:
4051 if (get_user(val, (int __user *)arg)) {
4052 pr_err("%s: get_user failed\n\n", __func__);
4053 ret = -EFAULT;
4054 break;
4055 }
4056 pr_debug("%s: LPM block request %d\n", __func__, val);
4057 if (val) { /* block LPM */
4058 if (motg->chg_type == USB_DCP_CHARGER) {
Saket Saurabh48848182014-05-23 15:15:02 +05304059 motg->ext_chg_active = ACTIVE;
Pavankumar Kondetif1ffbdd2013-06-27 13:31:36 +05304060 /*
4061 * If device is already suspended, resume it.
4062 * The PM usage counter is incremented in
4063 * runtime resume method. if device is not
4064 * suspended, cancel the scheduled suspend
4065 * and increment the PM usage counter.
4066 */
4067 if (pm_runtime_suspended(motg->phy.dev))
4068 pm_runtime_resume(motg->phy.dev);
4069 else
4070 pm_runtime_get_sync(motg->phy.dev);
4071 } else {
Saket Saurabh48848182014-05-23 15:15:02 +05304072 motg->ext_chg_active = INACTIVE;
Pavankumar Kondetif1ffbdd2013-06-27 13:31:36 +05304073 complete(&motg->ext_chg_wait);
4074 ret = -ENODEV;
4075 }
4076 } else {
Saket Saurabh48848182014-05-23 15:15:02 +05304077 motg->ext_chg_active = INACTIVE;
Pavankumar Kondetif1ffbdd2013-06-27 13:31:36 +05304078 complete(&motg->ext_chg_wait);
Saket Saurabhe34c4b42014-05-22 12:53:37 +05304079 /*
4080 * If usb cable is disconnected and then userspace
4081 * calls ioctl to unblock low power mode, make sure
4082 * otg_sm work for usb disconnect is processed first
4083 * followed by decrementing the PM usage counters.
4084 */
4085 flush_work(&motg->sm_work);
4086 pm_runtime_put_noidle(motg->phy.dev);
4087 motg->pm_done = 1;
4088 pm_runtime_suspend(motg->phy.dev);
Pavankumar Kondetif1ffbdd2013-06-27 13:31:36 +05304089 }
4090 break;
Vijayavardhan Vennapusafc71ac22014-02-17 10:41:18 +05304091 case MSM_USB_EXT_CHG_VOLTAGE_INFO:
4092 if (get_user(val, (int __user *)arg)) {
4093 pr_err("%s: get_user failed\n\n", __func__);
4094 ret = -EFAULT;
4095 break;
4096 }
4097
4098 if (val == USB_REQUEST_5V)
4099 pr_debug("%s:voting 5V voltage request\n", __func__);
4100 else if (val == USB_REQUEST_9V)
4101 pr_debug("%s:voting 9V voltage request\n", __func__);
4102 break;
4103 case MSM_USB_EXT_CHG_RESULT:
4104 if (get_user(val, (int __user *)arg)) {
4105 pr_err("%s: get_user failed\n\n", __func__);
4106 ret = -EFAULT;
4107 break;
4108 }
4109
4110 if (!val)
4111 pr_debug("%s:voltage request successful\n", __func__);
4112 else
4113 pr_debug("%s:voltage request failed\n", __func__);
4114 break;
Vijayavardhan Vennapusaa9620e12014-04-28 16:17:29 +05304115 case MSM_USB_EXT_CHG_TYPE:
4116 if (get_user(val, (int __user *)arg)) {
4117 pr_err("%s: get_user failed\n\n", __func__);
4118 ret = -EFAULT;
4119 break;
4120 }
4121
4122 if (val)
4123 pr_debug("%s:charger is external charger\n", __func__);
4124 else
4125 pr_debug("%s:charger is not ext charger\n", __func__);
4126 break;
Pavankumar Kondetif1ffbdd2013-06-27 13:31:36 +05304127 default:
4128 ret = -EINVAL;
4129 }
4130
4131 return ret;
4132}
4133
4134static int msm_otg_ext_chg_mmap(struct file *file, struct vm_area_struct *vma)
4135{
4136 struct msm_otg *motg = file->private_data;
4137 unsigned long vsize = vma->vm_end - vma->vm_start;
4138 int ret;
4139
4140 if (vma->vm_pgoff || vsize > PAGE_SIZE)
4141 return -EINVAL;
4142
4143 vma->vm_pgoff = __phys_to_pfn(motg->io_res->start);
4144 vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot);
4145
4146 ret = io_remap_pfn_range(vma, vma->vm_start, vma->vm_pgoff,
4147 vsize, vma->vm_page_prot);
4148 if (ret < 0) {
4149 pr_err("%s: failed with return val %d\n", __func__, ret);
4150 return ret;
4151 }
4152
4153 return 0;
4154}
4155
4156static int msm_otg_ext_chg_release(struct inode *inode, struct file *file)
4157{
4158 struct msm_otg *motg = file->private_data;
4159
4160 pr_debug("msm_otg ext chg release\n");
4161
4162 motg->ext_chg_opened = false;
4163
4164 return 0;
4165}
4166
4167static const struct file_operations msm_otg_ext_chg_fops = {
4168 .owner = THIS_MODULE,
4169 .open = msm_otg_ext_chg_open,
4170 .unlocked_ioctl = msm_otg_ext_chg_ioctl,
4171 .mmap = msm_otg_ext_chg_mmap,
4172 .release = msm_otg_ext_chg_release,
4173};
4174
4175static int msm_otg_setup_ext_chg_cdev(struct msm_otg *motg)
4176{
4177 int ret;
4178
4179 if (motg->pdata->enable_sec_phy || motg->pdata->mode == USB_HOST ||
4180 motg->pdata->otg_control != OTG_PMIC_CONTROL ||
4181 psy != &motg->usb_psy) {
4182 pr_debug("usb ext chg is not supported by msm otg\n");
4183 return -ENODEV;
4184 }
4185
4186 ret = alloc_chrdev_region(&motg->ext_chg_dev, 0, 1, "usb_ext_chg");
4187 if (ret < 0) {
4188 pr_err("Fail to allocate usb ext char dev region\n");
4189 return ret;
4190 }
4191 motg->ext_chg_class = class_create(THIS_MODULE, "msm_ext_chg");
4192 if (ret < 0) {
4193 pr_err("Fail to create usb ext chg class\n");
4194 goto unreg_chrdev;
4195 }
4196 cdev_init(&motg->ext_chg_cdev, &msm_otg_ext_chg_fops);
4197 motg->ext_chg_cdev.owner = THIS_MODULE;
4198
4199 ret = cdev_add(&motg->ext_chg_cdev, motg->ext_chg_dev, 1);
4200 if (ret < 0) {
4201 pr_err("Fail to add usb ext chg cdev\n");
4202 goto destroy_class;
4203 }
4204 motg->ext_chg_device = device_create(motg->ext_chg_class,
4205 NULL, motg->ext_chg_dev, NULL,
4206 "usb_ext_chg");
4207 if (IS_ERR(motg->ext_chg_device)) {
4208 pr_err("Fail to create usb ext chg device\n");
4209 ret = PTR_ERR(motg->ext_chg_device);
4210 motg->ext_chg_device = NULL;
4211 goto del_cdev;
4212 }
4213
4214 init_completion(&motg->ext_chg_wait);
4215 pr_debug("msm otg ext chg cdev setup success\n");
4216 return 0;
4217
4218del_cdev:
4219 cdev_del(&motg->ext_chg_cdev);
4220destroy_class:
4221 class_destroy(motg->ext_chg_class);
4222unreg_chrdev:
4223 unregister_chrdev_region(motg->ext_chg_dev, 1);
4224
4225 return ret;
4226}
4227
Vijayavardhan Vennapusa8997e332013-07-15 09:53:51 +05304228static ssize_t dpdm_pulldown_enable_show(struct device *dev,
4229 struct device_attribute *attr, char *buf)
4230{
4231 struct msm_otg *motg = the_msm_otg;
4232 struct msm_otg_platform_data *pdata = motg->pdata;
4233
4234 return snprintf(buf, PAGE_SIZE, "%s\n", pdata->dpdm_pulldown_added ?
4235 "enabled" : "disabled");
4236}
4237
4238static ssize_t dpdm_pulldown_enable_store(struct device *dev,
4239 struct device_attribute *attr, const char
4240 *buf, size_t size)
4241{
4242 struct msm_otg *motg = the_msm_otg;
4243 struct msm_otg_platform_data *pdata = motg->pdata;
4244
4245 if (!strnicmp(buf, "enable", 6)) {
4246 pdata->dpdm_pulldown_added = true;
4247 return size;
4248 } else if (!strnicmp(buf, "disable", 7)) {
4249 pdata->dpdm_pulldown_added = false;
4250 return size;
4251 }
4252
4253 return -EINVAL;
4254}
4255
4256static DEVICE_ATTR(dpdm_pulldown_enable, S_IRUGO | S_IWUSR,
4257 dpdm_pulldown_enable_show, dpdm_pulldown_enable_store);
4258
Pavankumar Kondetieaea7fe2011-10-27 14:46:45 +05304259struct msm_otg_platform_data *msm_otg_dt_to_pdata(struct platform_device *pdev)
4260{
4261 struct device_node *node = pdev->dev.of_node;
4262 struct msm_otg_platform_data *pdata;
4263 int len = 0;
4264
4265 pdata = devm_kzalloc(&pdev->dev, sizeof(*pdata), GFP_KERNEL);
4266 if (!pdata) {
4267 pr_err("unable to allocate platform data\n");
4268 return NULL;
4269 }
4270 of_get_property(node, "qcom,hsusb-otg-phy-init-seq", &len);
4271 if (len) {
4272 pdata->phy_init_seq = devm_kzalloc(&pdev->dev, len, GFP_KERNEL);
4273 if (!pdata->phy_init_seq)
4274 return NULL;
4275 of_property_read_u32_array(node, "qcom,hsusb-otg-phy-init-seq",
4276 pdata->phy_init_seq,
4277 len/sizeof(*pdata->phy_init_seq));
4278 }
4279 of_property_read_u32(node, "qcom,hsusb-otg-power-budget",
4280 &pdata->power_budget);
4281 of_property_read_u32(node, "qcom,hsusb-otg-mode",
4282 &pdata->mode);
4283 of_property_read_u32(node, "qcom,hsusb-otg-otg-control",
4284 &pdata->otg_control);
4285 of_property_read_u32(node, "qcom,hsusb-otg-default-mode",
4286 &pdata->default_mode);
4287 of_property_read_u32(node, "qcom,hsusb-otg-phy-type",
4288 &pdata->phy_type);
Manu Gautambd53fba2012-07-31 16:13:06 +05304289 pdata->disable_reset_on_disconnect = of_property_read_bool(node,
4290 "qcom,hsusb-otg-disable-reset");
Manu Gautam0ddbd922012-09-21 17:17:38 +05304291 pdata->pnoc_errata_fix = of_property_read_bool(node,
4292 "qcom,hsusb-otg-pnoc-errata-fix");
Ido Shayevitza7114b92013-01-13 13:34:47 +02004293 pdata->enable_lpm_on_dev_suspend = of_property_read_bool(node,
4294 "qcom,hsusb-otg-lpm-on-dev-suspend");
Ido Shayevitz26193352013-01-21 23:16:54 +02004295 pdata->core_clk_always_on_workaround = of_property_read_bool(node,
4296 "qcom,hsusb-otg-clk-always-on-workaround");
Shimrit Malichiffab5b02013-03-10 11:06:16 +02004297 pdata->delay_lpm_on_disconnect = of_property_read_bool(node,
4298 "qcom,hsusb-otg-delay-lpm");
Lena Salmanabde35d2013-04-25 15:29:43 +03004299 pdata->delay_lpm_hndshk_on_disconnect = of_property_read_bool(node,
4300 "qcom,hsusb-otg-delay-lpm-hndshk-on-disconnect");
Vamsi Krishna1a1684b2013-03-02 16:14:52 -08004301 pdata->dp_manual_pullup = of_property_read_bool(node,
4302 "qcom,dp-manual-pullup");
Manu Gautam0fd2d0e2013-03-26 18:09:11 +05304303 pdata->enable_sec_phy = of_property_read_bool(node,
4304 "qcom,usb2-enable-hsphy2");
Amit Blayb4f14532013-06-17 22:33:57 +03004305 of_property_read_u32(node, "qcom,hsusb-log2-itc",
4306 &pdata->log2_itc);
Manu Gautambd53fba2012-07-31 16:13:06 +05304307
Vijayavardhan Vennapusa2239b2b2013-06-28 13:16:29 +05304308 of_property_read_u32(node, "qcom,hsusb-otg-mpm-dpsehv-int",
4309 &pdata->mpm_dpshv_int);
4310 of_property_read_u32(node, "qcom,hsusb-otg-mpm-dmsehv-int",
4311 &pdata->mpm_dmshv_int);
Manu Gautam0e0c53f2013-04-04 10:55:20 +05304312 pdata->pmic_id_irq = platform_get_irq_byname(pdev, "pmic_id_irq");
4313 if (pdata->pmic_id_irq < 0)
4314 pdata->pmic_id_irq = 0;
4315
Shimrit Malichi5a2d5b52013-06-20 19:04:28 +03004316 pdata->l1_supported = of_property_read_bool(node,
4317 "qcom,hsusb-l1-supported");
Mayank Rana34f6f3e2013-11-11 12:40:00 +05304318 pdata->enable_ahb2ahb_bypass = of_property_read_bool(node,
4319 "qcom,ahb-async-bridge-bypass");
Saket Saurabhb06a8c62013-11-25 15:17:23 +05304320 pdata->disable_retention_with_vdd_min = of_property_read_bool(node,
4321 "qcom,disable-retention-with-vdd-min");
Shimrit Malichi5a2d5b52013-06-20 19:04:28 +03004322
Pavankumar Kondetieaea7fe2011-10-27 14:46:45 +05304323 return pdata;
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05304324}
4325
4326static int __init msm_otg_probe(struct platform_device *pdev)
4327{
Manu Gautamf8c45642012-08-10 10:20:56 -07004328 int ret = 0;
Mayank Rana0f286cf2013-02-27 11:43:27 +05304329 int len = 0;
4330 u32 tmp[3];
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05304331 struct resource *res;
4332 struct msm_otg *motg;
Heikki Krogerus1d4c9292012-02-13 13:24:09 +02004333 struct usb_phy *phy;
Pavankumar Kondetieaea7fe2011-10-27 14:46:45 +05304334 struct msm_otg_platform_data *pdata;
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05304335
4336 dev_info(&pdev->dev, "msm_otg probe\n");
Pavankumar Kondetieaea7fe2011-10-27 14:46:45 +05304337
4338 if (pdev->dev.of_node) {
4339 dev_dbg(&pdev->dev, "device tree enabled\n");
4340 pdata = msm_otg_dt_to_pdata(pdev);
4341 if (!pdata)
4342 return -ENOMEM;
Manu Gautam2e8ac102012-08-31 11:41:16 -07004343
4344 pdata->bus_scale_table = msm_bus_cl_get_pdata(pdev);
4345 if (!pdata->bus_scale_table)
4346 dev_dbg(&pdev->dev, "bus scaling is disabled\n");
4347
Amit Blayb4f14532013-06-17 22:33:57 +03004348 pdev->dev.platform_data = pdata;
Pavankumar Kondetieaea7fe2011-10-27 14:46:45 +05304349 ret = msm_otg_setup_devices(pdev, pdata->mode, true);
4350 if (ret) {
4351 dev_err(&pdev->dev, "devices setup failed\n");
4352 return ret;
4353 }
4354 } else if (!pdev->dev.platform_data) {
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05304355 dev_err(&pdev->dev, "No platform data given. Bailing out\n");
4356 return -ENODEV;
Pavankumar Kondetieaea7fe2011-10-27 14:46:45 +05304357 } else {
4358 pdata = pdev->dev.platform_data;
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05304359 }
4360
Manu Gautame3a39082013-06-11 10:42:56 +05304361 motg = devm_kzalloc(&pdev->dev, sizeof(struct msm_otg), GFP_KERNEL);
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05304362 if (!motg) {
4363 dev_err(&pdev->dev, "unable to allocate msm_otg\n");
4364 return -ENOMEM;
4365 }
4366
Manu Gautame3a39082013-06-11 10:42:56 +05304367 motg->phy.otg = devm_kzalloc(&pdev->dev, sizeof(struct usb_otg),
4368 GFP_KERNEL);
Heikki Krogerus1d4c9292012-02-13 13:24:09 +02004369 if (!motg->phy.otg) {
Steve Mucklef132c6c2012-06-06 18:30:57 -07004370 dev_err(&pdev->dev, "unable to allocate usb_otg\n");
Manu Gautame3a39082013-06-11 10:42:56 +05304371 return -ENOMEM;
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05304372 }
4373
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004374 the_msm_otg = motg;
Pavankumar Kondetieaea7fe2011-10-27 14:46:45 +05304375 motg->pdata = pdata;
Steve Mucklef132c6c2012-06-06 18:30:57 -07004376 phy = &motg->phy;
4377 phy->dev = &pdev->dev;
Anji jonnala0f73cac2011-05-04 10:19:46 +05304378
Manu Gautame3a39082013-06-11 10:42:56 +05304379 if (motg->pdata->bus_scale_table) {
4380 motg->bus_perf_client =
4381 msm_bus_scale_register_client(motg->pdata->bus_scale_table);
4382 if (!motg->bus_perf_client) {
4383 dev_err(motg->phy.dev, "%s: Failed to register BUS\n"
4384 "scaling client!!\n", __func__);
4385 } else {
4386 debug_bus_voting_enabled = true;
4387 /* Some platforms require BUS vote to control clocks */
4388 msm_otg_bus_vote(motg, USB_MIN_PERF_VOTE);
4389 }
4390 }
4391
Anji jonnala0f73cac2011-05-04 10:19:46 +05304392 /*
Pavankumar Kondetiaa449e12011-11-04 11:09:26 +05304393 * ACA ID_GND threshold range is overlapped with OTG ID_FLOAT. Hence
4394 * PHY treat ACA ID_GND as float and no interrupt is generated. But
4395 * PMIC can detect ACA ID_GND and generate an interrupt.
4396 */
4397 if (aca_enabled() && motg->pdata->otg_control != OTG_PMIC_CONTROL) {
4398 dev_err(&pdev->dev, "ACA can not be enabled without PMIC\n");
4399 ret = -EINVAL;
Manu Gautame3a39082013-06-11 10:42:56 +05304400 goto devote_bus_bw;
Pavankumar Kondetiaa449e12011-11-04 11:09:26 +05304401 }
4402
Ofir Cohen4da266f2012-01-03 10:19:29 +02004403 /* initialize reset counter */
4404 motg->reset_counter = 0;
4405
Pavankumar Kondeti923262e2012-04-20 15:34:24 +05304406 /*
4407 * Targets on which link uses asynchronous reset methodology,
4408 * free running clock is not required during the reset.
4409 */
Manu Gautam5143b252012-01-05 19:25:23 -08004410 motg->clk = clk_get(&pdev->dev, "alt_core_clk");
Pavankumar Kondeti923262e2012-04-20 15:34:24 +05304411 if (IS_ERR(motg->clk))
4412 dev_dbg(&pdev->dev, "alt_core_clk is not present\n");
4413 else
4414 clk_set_rate(motg->clk, 60000000);
Anji jonnala0f73cac2011-05-04 10:19:46 +05304415
4416 /*
Manu Gautam5143b252012-01-05 19:25:23 -08004417 * USB Core is running its protocol engine based on CORE CLK,
Anji jonnala0f73cac2011-05-04 10:19:46 +05304418 * CORE CLK must be running at >55Mhz for correct HSUSB
4419 * operation and USB core cannot tolerate frequency changes on
4420 * CORE CLK. For such USB cores, vote for maximum clk frequency
4421 * on pclk source
4422 */
Manu Gautam5143b252012-01-05 19:25:23 -08004423 motg->core_clk = clk_get(&pdev->dev, "core_clk");
4424 if (IS_ERR(motg->core_clk)) {
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05304425 motg->core_clk = NULL;
Manu Gautam5143b252012-01-05 19:25:23 -08004426 dev_err(&pdev->dev, "failed to get core_clk\n");
Pavankumar Kondetibc541332012-04-20 15:32:04 +05304427 ret = PTR_ERR(motg->core_clk);
Manu Gautam5143b252012-01-05 19:25:23 -08004428 goto put_clk;
4429 }
Mayank Rana3eaf28d2013-03-27 14:04:04 +05304430
4431 /*
4432 * Get Max supported clk frequency for USB Core CLK and request
4433 * to set the same.
4434 */
4435 motg->core_clk_rate = clk_round_rate(motg->core_clk, LONG_MAX);
4436 if (IS_ERR_VALUE(motg->core_clk_rate)) {
4437 dev_err(&pdev->dev, "fail to get core clk max freq.\n");
4438 } else {
4439 ret = clk_set_rate(motg->core_clk, motg->core_clk_rate);
4440 if (ret)
4441 dev_err(&pdev->dev, "fail to set core_clk freq:%d\n",
4442 ret);
4443 }
Manu Gautam5143b252012-01-05 19:25:23 -08004444
4445 motg->pclk = clk_get(&pdev->dev, "iface_clk");
4446 if (IS_ERR(motg->pclk)) {
4447 dev_err(&pdev->dev, "failed to get iface_clk\n");
4448 ret = PTR_ERR(motg->pclk);
4449 goto put_core_clk;
4450 }
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05304451
Mayank Ranadd1f1dc2013-07-24 17:02:45 +05304452 /*
4453 * On few platforms USB PHY is fed with sleep clk.
4454 * Hence don't fail probe.
4455 */
4456 motg->sleep_clk = devm_clk_get(&pdev->dev, "sleep_clk");
4457 if (IS_ERR(motg->sleep_clk)) {
4458 dev_dbg(&pdev->dev, "failed to get sleep_clk\n");
4459 } else {
4460 ret = clk_prepare_enable(motg->sleep_clk);
4461 if (ret) {
4462 dev_err(&pdev->dev, "%s failed to vote sleep_clk%d\n",
4463 __func__, ret);
4464 goto put_pclk;
4465 }
4466 }
4467
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05304468 res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
4469 if (!res) {
4470 dev_err(&pdev->dev, "failed to get platform resource mem\n");
4471 ret = -ENODEV;
Mayank Ranadd1f1dc2013-07-24 17:02:45 +05304472 goto disable_sleep_clk;
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05304473 }
4474
Pavankumar Kondetif1ffbdd2013-06-27 13:31:36 +05304475 motg->io_res = res;
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05304476 motg->regs = ioremap(res->start, resource_size(res));
4477 if (!motg->regs) {
4478 dev_err(&pdev->dev, "ioremap failed\n");
4479 ret = -ENOMEM;
Mayank Ranadd1f1dc2013-07-24 17:02:45 +05304480 goto disable_sleep_clk;
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05304481 }
4482 dev_info(&pdev->dev, "OTG regs = %p\n", motg->regs);
4483
4484 motg->irq = platform_get_irq(pdev, 0);
4485 if (!motg->irq) {
4486 dev_err(&pdev->dev, "platform_get_irq failed\n");
4487 ret = -ENODEV;
4488 goto free_regs;
4489 }
4490
Manu Gautamf8c45642012-08-10 10:20:56 -07004491 motg->async_irq = platform_get_irq_byname(pdev, "async_irq");
4492 if (motg->async_irq < 0) {
4493 dev_dbg(&pdev->dev, "platform_get_irq for async_int failed\n");
4494 motg->async_irq = 0;
4495 }
4496
Vijayavardhan Vennapusa0cab6172013-02-20 19:51:15 +05304497 motg->xo_clk = clk_get(&pdev->dev, "xo");
4498 if (IS_ERR(motg->xo_clk)) {
4499 motg->xo_handle = msm_xo_get(MSM_XO_TCXO_D0, "usb");
4500 if (IS_ERR(motg->xo_handle)) {
4501 dev_err(&pdev->dev, "%s fail to get handle for TCXO\n",
4502 __func__);
4503 ret = PTR_ERR(motg->xo_handle);
4504 goto free_regs;
4505 } else {
4506 ret = msm_xo_mode_vote(motg->xo_handle, MSM_XO_MODE_ON);
4507 if (ret) {
4508 dev_err(&pdev->dev, "%s XO voting failed %d\n",
4509 __func__, ret);
4510 goto free_xo_handle;
4511 }
4512 }
4513 } else {
4514 ret = clk_prepare_enable(motg->xo_clk);
4515 if (ret) {
4516 dev_err(&pdev->dev, "%s failed to vote for TCXO %d\n",
4517 __func__, ret);
4518 goto free_xo_handle;
4519 }
Anji jonnala7da3f262011-12-02 17:22:14 -08004520 }
Anji jonnala11aa5c42011-05-04 10:19:48 +05304521
Anji jonnala7da3f262011-12-02 17:22:14 -08004522
Manu Gautam28b1bac2012-01-30 16:43:06 +05304523 clk_prepare_enable(motg->pclk);
Anji jonnala11aa5c42011-05-04 10:19:48 +05304524
Mayank Rana248698c2012-04-19 00:03:16 +05304525 motg->vdd_type = VDDCX_CORNER;
Mayank Rana0f286cf2013-02-27 11:43:27 +05304526 hsusb_vdd = devm_regulator_get(motg->phy.dev, "hsusb_vdd_dig");
4527 if (IS_ERR(hsusb_vdd)) {
4528 hsusb_vdd = devm_regulator_get(motg->phy.dev, "HSUSB_VDDCX");
4529 if (IS_ERR(hsusb_vdd)) {
Steve Mucklef132c6c2012-06-06 18:30:57 -07004530 dev_err(motg->phy.dev, "unable to get hsusb vddcx\n");
Mayank Rana0f286cf2013-02-27 11:43:27 +05304531 ret = PTR_ERR(hsusb_vdd);
Mayank Rana248698c2012-04-19 00:03:16 +05304532 goto devote_xo_handle;
4533 }
4534 motg->vdd_type = VDDCX;
Anji jonnala11aa5c42011-05-04 10:19:48 +05304535 }
4536
Mayank Rana0f286cf2013-02-27 11:43:27 +05304537 if (pdev->dev.of_node) {
4538 of_get_property(pdev->dev.of_node,
4539 "qcom,vdd-voltage-level",
4540 &len);
4541 if (len == sizeof(tmp)) {
4542 of_property_read_u32_array(pdev->dev.of_node,
4543 "qcom,vdd-voltage-level",
4544 tmp, len/sizeof(*tmp));
4545 vdd_val[motg->vdd_type][0] = tmp[0];
4546 vdd_val[motg->vdd_type][1] = tmp[1];
4547 vdd_val[motg->vdd_type][2] = tmp[2];
4548 } else {
4549 dev_dbg(&pdev->dev, "Using default hsusb vdd config.\n");
4550 }
4551 }
4552
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004553 ret = msm_hsusb_config_vddcx(1);
Anji jonnala11aa5c42011-05-04 10:19:48 +05304554 if (ret) {
4555 dev_err(&pdev->dev, "hsusb vddcx configuration failed\n");
Mayank Rana248698c2012-04-19 00:03:16 +05304556 goto devote_xo_handle;
4557 }
4558
Mayank Rana0f286cf2013-02-27 11:43:27 +05304559 ret = regulator_enable(hsusb_vdd);
Mayank Rana248698c2012-04-19 00:03:16 +05304560 if (ret) {
4561 dev_err(&pdev->dev, "unable to enable the hsusb vddcx\n");
4562 goto free_config_vddcx;
Anji jonnala11aa5c42011-05-04 10:19:48 +05304563 }
4564
4565 ret = msm_hsusb_ldo_init(motg, 1);
4566 if (ret) {
4567 dev_err(&pdev->dev, "hsusb vreg configuration failed\n");
Mayank Rana0f286cf2013-02-27 11:43:27 +05304568 goto free_hsusb_vdd;
Anji jonnala11aa5c42011-05-04 10:19:48 +05304569 }
4570
Mayank Rana9e9a2ac2012-03-24 04:05:28 +05304571 if (pdata->mhl_enable) {
Pavankumar Kondeti56dc7422012-07-02 12:45:19 +05304572 mhl_usb_hs_switch = devm_regulator_get(motg->phy.dev,
4573 "mhl_usb_hs_switch");
4574 if (IS_ERR(mhl_usb_hs_switch)) {
4575 dev_err(&pdev->dev, "Unable to get mhl_usb_hs_switch\n");
Hemant Kumar41812392012-07-13 15:26:20 -07004576 ret = PTR_ERR(mhl_usb_hs_switch);
Mayank Rana9e9a2ac2012-03-24 04:05:28 +05304577 goto free_ldo_init;
4578 }
4579 }
4580
Amit Blay81801aa2012-09-19 12:08:12 +02004581 ret = msm_hsusb_ldo_enable(motg, USB_PHY_REG_ON);
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05304582 if (ret) {
4583 dev_err(&pdev->dev, "hsusb vreg enable failed\n");
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004584 goto free_ldo_init;
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05304585 }
Manu Gautam28b1bac2012-01-30 16:43:06 +05304586 clk_prepare_enable(motg->core_clk);
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05304587
Manu Gautam0ddbd922012-09-21 17:17:38 +05304588 /* Check if USB mem_type change is needed to workaround PNOC hw issue */
4589 msm_otg_pnoc_errata_fix(motg);
4590
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05304591 writel(0, USB_USBINTR);
4592 writel(0, USB_OTGSC);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004593 /* Ensure that above STOREs are completed before enabling interrupts */
4594 mb();
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05304595
Pavankumar Kondeti2aec9f32012-06-13 09:06:03 +05304596 ret = msm_otg_mhl_register_callback(motg, msm_otg_mhl_notify_online);
4597 if (ret)
4598 dev_dbg(&pdev->dev, "MHL can not be supported\n");
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004599 wake_lock_init(&motg->wlock, WAKE_LOCK_SUSPEND, "msm_otg");
Vijayavardhan Vennapusaa3152032012-03-05 16:29:30 +05304600 msm_otg_init_timer(motg);
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05304601 INIT_WORK(&motg->sm_work, msm_otg_sm_work);
Pavankumar Kondetid8608522011-05-04 10:19:47 +05304602 INIT_DELAYED_WORK(&motg->chg_work, msm_chg_detect_work);
Vijayavardhan Vennapusa68d55cf2012-06-27 20:06:12 +05304603 INIT_DELAYED_WORK(&motg->pmic_id_status_work, msm_pmic_id_status_w);
Amit Blayd0fe07b2012-09-05 16:42:09 +03004604 INIT_DELAYED_WORK(&motg->suspend_work, msm_otg_suspend_work);
Pavankumar Kondetiaa449e12011-11-04 11:09:26 +05304605 setup_timer(&motg->id_timer, msm_otg_id_timer_func,
4606 (unsigned long) motg);
Pavankumar Kondeti458d8792012-09-28 14:45:18 +05304607 setup_timer(&motg->chg_check_timer, msm_otg_chg_check_timer_func,
4608 (unsigned long) motg);
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05304609 ret = request_irq(motg->irq, msm_otg_irq, IRQF_SHARED,
4610 "msm_otg", motg);
4611 if (ret) {
4612 dev_err(&pdev->dev, "request irq failed\n");
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004613 goto destroy_wlock;
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05304614 }
4615
Manu Gautamf8c45642012-08-10 10:20:56 -07004616 if (motg->async_irq) {
Vijayavardhan Vennapusa9ab6f972012-10-11 19:18:55 +05304617 ret = request_irq(motg->async_irq, msm_otg_irq,
4618 IRQF_TRIGGER_RISING, "msm_otg", motg);
Manu Gautamf8c45642012-08-10 10:20:56 -07004619 if (ret) {
4620 dev_err(&pdev->dev, "request irq failed (ASYNC INT)\n");
4621 goto free_irq;
4622 }
4623 disable_irq(motg->async_irq);
4624 }
4625
Jack Pham87f202f2012-08-06 00:24:22 -07004626 if (pdata->otg_control == OTG_PHY_CONTROL && pdata->mpm_otgsessvld_int)
4627 msm_mpm_enable_pin(pdata->mpm_otgsessvld_int, 1);
4628
Vijayavardhan Vennapusa2239b2b2013-06-28 13:16:29 +05304629 if (pdata->mpm_dpshv_int)
4630 msm_mpm_enable_pin(pdata->mpm_dpshv_int, 1);
4631 if (pdata->mpm_dmshv_int)
4632 msm_mpm_enable_pin(pdata->mpm_dmshv_int, 1);
4633
Heikki Krogerus1d4c9292012-02-13 13:24:09 +02004634 phy->init = msm_otg_reset;
4635 phy->set_power = msm_otg_set_power;
Steve Mucklef132c6c2012-06-06 18:30:57 -07004636 phy->set_suspend = msm_otg_set_suspend;
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05304637
Heikki Krogerus1d4c9292012-02-13 13:24:09 +02004638 phy->io_ops = &msm_otg_io_ops;
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05304639
Heikki Krogerus1d4c9292012-02-13 13:24:09 +02004640 phy->otg->phy = &motg->phy;
4641 phy->otg->set_host = msm_otg_set_host;
4642 phy->otg->set_peripheral = msm_otg_set_peripheral;
Steve Mucklef132c6c2012-06-06 18:30:57 -07004643 phy->otg->start_hnp = msm_otg_start_hnp;
4644 phy->otg->start_srp = msm_otg_start_srp;
Vamsi Krishna1a1684b2013-03-02 16:14:52 -08004645 if (pdata->dp_manual_pullup)
4646 phy->flags |= ENABLE_DP_MANUAL_PULLUP;
Heikki Krogerus1d4c9292012-02-13 13:24:09 +02004647
Manu Gautam0fd2d0e2013-03-26 18:09:11 +05304648 if (pdata->enable_sec_phy)
4649 phy->flags |= ENABLE_SECONDARY_PHY;
4650
Heikki Krogerus1d4c9292012-02-13 13:24:09 +02004651 ret = usb_set_transceiver(&motg->phy);
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05304652 if (ret) {
Heikki Krogerus1d4c9292012-02-13 13:24:09 +02004653 dev_err(&pdev->dev, "usb_set_transceiver failed\n");
Manu Gautamf8c45642012-08-10 10:20:56 -07004654 goto free_async_irq;
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05304655 }
4656
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05304657 if (motg->pdata->mode == USB_OTG &&
Pavankumar Kondeti0d81f312012-01-13 11:34:10 +05304658 motg->pdata->otg_control == OTG_PMIC_CONTROL) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004659 if (motg->pdata->pmic_id_irq) {
4660 ret = request_irq(motg->pdata->pmic_id_irq,
4661 msm_pmic_id_irq,
4662 IRQF_TRIGGER_RISING |
4663 IRQF_TRIGGER_FALLING,
4664 "msm_otg", motg);
4665 if (ret) {
4666 dev_err(&pdev->dev, "request irq failed for PMIC ID\n");
Steve Mucklef132c6c2012-06-06 18:30:57 -07004667 goto remove_phy;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004668 }
4669 } else {
4670 ret = -ENODEV;
4671 dev_err(&pdev->dev, "PMIC IRQ for ID notifications doesn't exist\n");
Steve Mucklef132c6c2012-06-06 18:30:57 -07004672 goto remove_phy;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004673 }
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05304674 }
4675
Vijayavardhan Vennapusafc464f02011-11-04 21:54:00 +05304676 msm_hsusb_mhl_switch_enable(motg, 1);
4677
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05304678 platform_set_drvdata(pdev, motg);
4679 device_init_wakeup(&pdev->dev, 1);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004680 motg->mA_port = IUNIT;
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05304681
Anji jonnalad270e2d2011-08-09 11:28:32 +05304682 ret = msm_otg_debugfs_init(motg);
4683 if (ret)
4684 dev_dbg(&pdev->dev, "mode debugfs file is"
4685 "not available\n");
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05304686
Amit Blay58b31472011-11-18 09:39:39 +02004687 if (motg->pdata->phy_type == SNPS_28NM_INTEGRATED_PHY) {
4688 if (motg->pdata->otg_control == OTG_PMIC_CONTROL &&
Pavankumar Kondeti0d81f312012-01-13 11:34:10 +05304689 (!(motg->pdata->mode == USB_OTG) ||
4690 motg->pdata->pmic_id_irq))
Amit Blay58b31472011-11-18 09:39:39 +02004691 motg->caps = ALLOW_PHY_POWER_COLLAPSE |
Vijayavardhan Vennapusa03171c72012-04-26 14:44:48 +05304692 ALLOW_PHY_RETENTION;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004693
Amit Blay58b31472011-11-18 09:39:39 +02004694 if (motg->pdata->otg_control == OTG_PHY_CONTROL)
Amit Blay81801aa2012-09-19 12:08:12 +02004695 motg->caps = ALLOW_PHY_RETENTION |
4696 ALLOW_PHY_REGULATORS_LPM;
Vijayavardhan Vennapusa2239b2b2013-06-28 13:16:29 +05304697
4698 if (motg->pdata->mpm_dpshv_int || motg->pdata->mpm_dmshv_int)
4699 motg->caps |= ALLOW_HOST_PHY_RETENTION;
Vijayavardhan Vennapusa8997e332013-07-15 09:53:51 +05304700 device_create_file(&pdev->dev,
4701 &dev_attr_dpdm_pulldown_enable);
Amit Blay58b31472011-11-18 09:39:39 +02004702 }
4703
Amit Blay6fa647a2012-05-24 14:12:08 +03004704 if (motg->pdata->enable_lpm_on_dev_suspend)
4705 motg->caps |= ALLOW_LPM_ON_DEV_SUSPEND;
4706
Saket Saurabhb06a8c62013-11-25 15:17:23 +05304707 if (motg->pdata->disable_retention_with_vdd_min)
4708 motg->caps |= ALLOW_VDD_MIN_WITH_RETENTION_DISABLED;
4709
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004710 wake_lock(&motg->wlock);
Pavankumar Kondeti87c01042010-12-07 17:53:58 +05304711 pm_runtime_set_active(&pdev->dev);
Manu Gautamf8c45642012-08-10 10:20:56 -07004712 pm_runtime_enable(&pdev->dev);
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05304713
Amit Blayd6f38282012-10-29 13:13:46 +02004714 if (motg->pdata->delay_lpm_on_disconnect) {
4715 pm_runtime_set_autosuspend_delay(&pdev->dev,
4716 lpm_disconnect_thresh);
4717 pm_runtime_use_autosuspend(&pdev->dev);
4718 }
4719
David Keitel272ce522012-08-17 16:25:24 -07004720 motg->usb_psy.name = "usb";
4721 motg->usb_psy.type = POWER_SUPPLY_TYPE_USB;
4722 motg->usb_psy.supplied_to = otg_pm_power_supplied_to;
4723 motg->usb_psy.num_supplicants = ARRAY_SIZE(otg_pm_power_supplied_to);
4724 motg->usb_psy.properties = otg_pm_power_props_usb;
4725 motg->usb_psy.num_properties = ARRAY_SIZE(otg_pm_power_props_usb);
4726 motg->usb_psy.get_property = otg_power_get_property_usb;
4727 motg->usb_psy.set_property = otg_power_set_property_usb;
David Collinsd79acc52012-11-26 14:59:00 -08004728 motg->usb_psy.property_is_writeable
4729 = otg_power_property_is_writeable_usb;
David Keitel272ce522012-08-17 16:25:24 -07004730
Jack Pham0c695282012-10-19 18:13:03 -07004731 if (!pm8921_charger_register_vbus_sn(NULL)) {
David Keitel272ce522012-08-17 16:25:24 -07004732 /* if pm8921 use legacy implementation */
Jack Pham0c695282012-10-19 18:13:03 -07004733 dev_dbg(motg->phy.dev, "%s: legacy support\n", __func__);
4734 legacy_power_supply = true;
4735 } else {
4736 /* otherwise register our own power supply */
4737 if (!msm_otg_register_power_supply(pdev, motg))
4738 psy = &motg->usb_psy;
David Keitel272ce522012-08-17 16:25:24 -07004739 }
4740
Jack Pham0c695282012-10-19 18:13:03 -07004741 if (legacy_power_supply && pdata->otg_control == OTG_PMIC_CONTROL)
4742 pm8921_charger_register_vbus_sn(&msm_otg_set_vbus_state);
4743
Pavankumar Kondetif1ffbdd2013-06-27 13:31:36 +05304744 ret = msm_otg_setup_ext_chg_cdev(motg);
4745 if (ret)
4746 dev_dbg(&pdev->dev, "fail to setup cdev\n");
4747
Pavankumar Kondeti87c01042010-12-07 17:53:58 +05304748 return 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004749
Steve Mucklef132c6c2012-06-06 18:30:57 -07004750remove_phy:
4751 usb_set_transceiver(NULL);
Manu Gautamf8c45642012-08-10 10:20:56 -07004752free_async_irq:
4753 if (motg->async_irq)
4754 free_irq(motg->async_irq, motg);
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05304755free_irq:
4756 free_irq(motg->irq, motg);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004757destroy_wlock:
4758 wake_lock_destroy(&motg->wlock);
Manu Gautam28b1bac2012-01-30 16:43:06 +05304759 clk_disable_unprepare(motg->core_clk);
Amit Blay81801aa2012-09-19 12:08:12 +02004760 msm_hsusb_ldo_enable(motg, USB_PHY_REG_OFF);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004761free_ldo_init:
Anji jonnala11aa5c42011-05-04 10:19:48 +05304762 msm_hsusb_ldo_init(motg, 0);
Mayank Rana0f286cf2013-02-27 11:43:27 +05304763free_hsusb_vdd:
4764 regulator_disable(hsusb_vdd);
Mayank Rana248698c2012-04-19 00:03:16 +05304765free_config_vddcx:
Mayank Rana0f286cf2013-02-27 11:43:27 +05304766 regulator_set_voltage(hsusb_vdd,
Mayank Rana248698c2012-04-19 00:03:16 +05304767 vdd_val[motg->vdd_type][VDD_NONE],
4768 vdd_val[motg->vdd_type][VDD_MAX]);
Anji jonnala7da3f262011-12-02 17:22:14 -08004769devote_xo_handle:
Manu Gautam28b1bac2012-01-30 16:43:06 +05304770 clk_disable_unprepare(motg->pclk);
Vijayavardhan Vennapusa0cab6172013-02-20 19:51:15 +05304771 if (!IS_ERR(motg->xo_clk))
4772 clk_disable_unprepare(motg->xo_clk);
4773 else
4774 msm_xo_mode_vote(motg->xo_handle, MSM_XO_MODE_OFF);
Anji jonnala7da3f262011-12-02 17:22:14 -08004775free_xo_handle:
Vijayavardhan Vennapusa0cab6172013-02-20 19:51:15 +05304776 if (!IS_ERR(motg->xo_clk))
4777 clk_put(motg->xo_clk);
4778 else
4779 msm_xo_put(motg->xo_handle);
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05304780free_regs:
4781 iounmap(motg->regs);
Mayank Ranadd1f1dc2013-07-24 17:02:45 +05304782disable_sleep_clk:
4783 if (!IS_ERR(motg->sleep_clk))
4784 clk_disable_unprepare(motg->sleep_clk);
Manu Gautam5143b252012-01-05 19:25:23 -08004785put_pclk:
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05304786 clk_put(motg->pclk);
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05304787put_core_clk:
Manu Gautam5143b252012-01-05 19:25:23 -08004788 clk_put(motg->core_clk);
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05304789put_clk:
Pavankumar Kondeti923262e2012-04-20 15:34:24 +05304790 if (!IS_ERR(motg->clk))
4791 clk_put(motg->clk);
Manu Gautame3a39082013-06-11 10:42:56 +05304792devote_bus_bw:
4793 if (motg->bus_perf_client) {
4794 msm_otg_bus_vote(motg, USB_NO_PERF_VOTE);
4795 msm_bus_scale_unregister_client(motg->bus_perf_client);
4796 }
4797
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05304798 return ret;
4799}
4800
4801static int __devexit msm_otg_remove(struct platform_device *pdev)
4802{
4803 struct msm_otg *motg = platform_get_drvdata(pdev);
Stephen Boyd9850acb2013-01-28 14:11:20 -08004804 struct usb_phy *phy = &motg->phy;
Pavankumar Kondeti87c01042010-12-07 17:53:58 +05304805 int cnt = 0;
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05304806
Stephen Boyd9850acb2013-01-28 14:11:20 -08004807 if (phy->otg->host || phy->otg->gadget)
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05304808 return -EBUSY;
4809
Pavankumar Kondetif1ffbdd2013-06-27 13:31:36 +05304810 if (!motg->ext_chg_device) {
4811 device_destroy(motg->ext_chg_class, motg->ext_chg_dev);
4812 cdev_del(&motg->ext_chg_cdev);
4813 class_destroy(motg->ext_chg_class);
4814 unregister_chrdev_region(motg->ext_chg_dev, 1);
4815 }
4816
Pavankumar Kondetieaea7fe2011-10-27 14:46:45 +05304817 if (pdev->dev.of_node)
4818 msm_otg_setup_devices(pdev, motg->pdata->mode, false);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004819 if (motg->pdata->otg_control == OTG_PMIC_CONTROL)
4820 pm8921_charger_unregister_vbus_sn(0);
Pavankumar Kondeti2aec9f32012-06-13 09:06:03 +05304821 msm_otg_mhl_register_callback(motg, NULL);
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05304822 msm_otg_debugfs_cleanup();
Pavankumar Kondetid8608522011-05-04 10:19:47 +05304823 cancel_delayed_work_sync(&motg->chg_work);
Vijayavardhan Vennapusa68d55cf2012-06-27 20:06:12 +05304824 cancel_delayed_work_sync(&motg->pmic_id_status_work);
Amit Blayd0fe07b2012-09-05 16:42:09 +03004825 cancel_delayed_work_sync(&motg->suspend_work);
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05304826 cancel_work_sync(&motg->sm_work);
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05304827
Pavankumar Kondeti70187732011-02-15 09:42:34 +05304828 pm_runtime_resume(&pdev->dev);
Pavankumar Kondeti87c01042010-12-07 17:53:58 +05304829
4830 device_init_wakeup(&pdev->dev, 0);
4831 pm_runtime_disable(&pdev->dev);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004832 wake_lock_destroy(&motg->wlock);
Pavankumar Kondeti87c01042010-12-07 17:53:58 +05304833
Vijayavardhan Vennapusafc464f02011-11-04 21:54:00 +05304834 msm_hsusb_mhl_switch_enable(motg, 0);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004835 if (motg->pdata->pmic_id_irq)
4836 free_irq(motg->pdata->pmic_id_irq, motg);
Heikki Krogerus1d4c9292012-02-13 13:24:09 +02004837 usb_set_transceiver(NULL);
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05304838 free_irq(motg->irq, motg);
4839
Vijayavardhan Vennapusa8997e332013-07-15 09:53:51 +05304840 if ((motg->pdata->phy_type == SNPS_28NM_INTEGRATED_PHY) &&
4841 (motg->pdata->mpm_dpshv_int || motg->pdata->mpm_dmshv_int))
4842 device_remove_file(&pdev->dev,
4843 &dev_attr_dpdm_pulldown_enable);
Jack Pham87f202f2012-08-06 00:24:22 -07004844 if (motg->pdata->otg_control == OTG_PHY_CONTROL &&
4845 motg->pdata->mpm_otgsessvld_int)
4846 msm_mpm_enable_pin(motg->pdata->mpm_otgsessvld_int, 0);
4847
Vijayavardhan Vennapusa2239b2b2013-06-28 13:16:29 +05304848 if (motg->pdata->mpm_dpshv_int)
4849 msm_mpm_enable_pin(motg->pdata->mpm_dpshv_int, 0);
4850 if (motg->pdata->mpm_dmshv_int)
4851 msm_mpm_enable_pin(motg->pdata->mpm_dmshv_int, 0);
4852
Pavankumar Kondeti87c01042010-12-07 17:53:58 +05304853 /*
4854 * Put PHY in low power mode.
4855 */
Stephen Boyd9850acb2013-01-28 14:11:20 -08004856 ulpi_read(phy, 0x14);
4857 ulpi_write(phy, 0x08, 0x09);
Pavankumar Kondeti87c01042010-12-07 17:53:58 +05304858
4859 writel(readl(USB_PORTSC) | PORTSC_PHCD, USB_PORTSC);
4860 while (cnt < PHY_SUSPEND_TIMEOUT_USEC) {
4861 if (readl(USB_PORTSC) & PORTSC_PHCD)
4862 break;
4863 udelay(1);
4864 cnt++;
4865 }
4866 if (cnt >= PHY_SUSPEND_TIMEOUT_USEC)
Stephen Boyd9850acb2013-01-28 14:11:20 -08004867 dev_err(phy->dev, "Unable to suspend PHY\n");
Pavankumar Kondeti87c01042010-12-07 17:53:58 +05304868
Manu Gautam28b1bac2012-01-30 16:43:06 +05304869 clk_disable_unprepare(motg->pclk);
4870 clk_disable_unprepare(motg->core_clk);
Vijayavardhan Vennapusa0cab6172013-02-20 19:51:15 +05304871 if (!IS_ERR(motg->xo_clk)) {
4872 clk_disable_unprepare(motg->xo_clk);
4873 clk_put(motg->xo_clk);
4874 } else {
4875 msm_xo_put(motg->xo_handle);
4876 }
Mayank Ranadd1f1dc2013-07-24 17:02:45 +05304877
4878 if (!IS_ERR(motg->sleep_clk))
4879 clk_disable_unprepare(motg->sleep_clk);
4880
Amit Blay81801aa2012-09-19 12:08:12 +02004881 msm_hsusb_ldo_enable(motg, USB_PHY_REG_OFF);
Anji jonnala11aa5c42011-05-04 10:19:48 +05304882 msm_hsusb_ldo_init(motg, 0);
Mayank Rana0f286cf2013-02-27 11:43:27 +05304883 regulator_disable(hsusb_vdd);
4884 regulator_set_voltage(hsusb_vdd,
Mayank Rana248698c2012-04-19 00:03:16 +05304885 vdd_val[motg->vdd_type][VDD_NONE],
4886 vdd_val[motg->vdd_type][VDD_MAX]);
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05304887
4888 iounmap(motg->regs);
Pavankumar Kondeti87c01042010-12-07 17:53:58 +05304889 pm_runtime_set_suspended(&pdev->dev);
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05304890
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05304891 clk_put(motg->pclk);
Pavankumar Kondeti923262e2012-04-20 15:34:24 +05304892 if (!IS_ERR(motg->clk))
4893 clk_put(motg->clk);
Manu Gautam5143b252012-01-05 19:25:23 -08004894 clk_put(motg->core_clk);
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05304895
Manu Gautame3a39082013-06-11 10:42:56 +05304896 if (motg->bus_perf_client) {
4897 msm_otg_bus_vote(motg, USB_NO_PERF_VOTE);
Manu Gautamcd82e9d2011-12-20 14:17:28 +05304898 msm_bus_scale_unregister_client(motg->bus_perf_client);
Manu Gautame3a39082013-06-11 10:42:56 +05304899 }
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05304900
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05304901 return 0;
4902}
4903
Pavankumar Kondeti87c01042010-12-07 17:53:58 +05304904#ifdef CONFIG_PM_RUNTIME
4905static int msm_otg_runtime_idle(struct device *dev)
4906{
4907 struct msm_otg *motg = dev_get_drvdata(dev);
Steve Mucklef132c6c2012-06-06 18:30:57 -07004908 struct usb_phy *phy = &motg->phy;
Pavankumar Kondeti87c01042010-12-07 17:53:58 +05304909
4910 dev_dbg(dev, "OTG runtime idle\n");
4911
Steve Mucklef132c6c2012-06-06 18:30:57 -07004912 if (phy->state == OTG_STATE_UNDEFINED)
Pavankumar Kondeti8be99cf2011-08-04 10:48:08 +05304913 return -EAGAIN;
Pavankumar Kondetif1ffbdd2013-06-27 13:31:36 +05304914
Saket Saurabh48848182014-05-23 15:15:02 +05304915 if (motg->ext_chg_active == DEFAULT) {
Pavankumar Kondetif1ffbdd2013-06-27 13:31:36 +05304916 dev_dbg(dev, "Deferring LPM\n");
4917 /*
4918 * Charger detection may happen in user space.
4919 * Delay entering LPM by 3 sec. Otherwise we
4920 * have to exit LPM when user space begins
4921 * charger detection.
4922 *
4923 * This timer will be canceled when user space
4924 * votes against LPM by incrementing PM usage
4925 * counter. We enter low power mode when
4926 * PM usage counter is decremented.
4927 */
4928 pm_schedule_suspend(dev, 3000);
4929 return -EAGAIN;
4930 }
4931
4932 return 0;
Pavankumar Kondeti87c01042010-12-07 17:53:58 +05304933}
4934
4935static int msm_otg_runtime_suspend(struct device *dev)
4936{
4937 struct msm_otg *motg = dev_get_drvdata(dev);
4938
4939 dev_dbg(dev, "OTG runtime suspend\n");
4940 return msm_otg_suspend(motg);
4941}
4942
4943static int msm_otg_runtime_resume(struct device *dev)
4944{
4945 struct msm_otg *motg = dev_get_drvdata(dev);
4946
4947 dev_dbg(dev, "OTG runtime resume\n");
Pavankumar Kondeti8be99cf2011-08-04 10:48:08 +05304948 pm_runtime_get_noresume(dev);
Saket Saurabh2558ea02014-01-10 16:14:27 +05304949 motg->pm_done = 0;
Pavankumar Kondeti87c01042010-12-07 17:53:58 +05304950 return msm_otg_resume(motg);
4951}
Pavankumar Kondeti87c01042010-12-07 17:53:58 +05304952#endif
4953
Pavankumar Kondeti70187732011-02-15 09:42:34 +05304954#ifdef CONFIG_PM_SLEEP
Pavankumar Kondeti87c01042010-12-07 17:53:58 +05304955static int msm_otg_pm_suspend(struct device *dev)
4956{
Jack Pham5ca279b2012-05-14 18:42:54 -07004957 int ret = 0;
Pavankumar Kondeti87c01042010-12-07 17:53:58 +05304958 struct msm_otg *motg = dev_get_drvdata(dev);
4959
4960 dev_dbg(dev, "OTG PM suspend\n");
Jack Pham5ca279b2012-05-14 18:42:54 -07004961
4962 atomic_set(&motg->pm_suspended, 1);
4963 ret = msm_otg_suspend(motg);
4964 if (ret)
4965 atomic_set(&motg->pm_suspended, 0);
4966
4967 return ret;
Pavankumar Kondeti87c01042010-12-07 17:53:58 +05304968}
4969
4970static int msm_otg_pm_resume(struct device *dev)
4971{
Jack Pham5ca279b2012-05-14 18:42:54 -07004972 int ret = 0;
Pavankumar Kondeti87c01042010-12-07 17:53:58 +05304973 struct msm_otg *motg = dev_get_drvdata(dev);
Pavankumar Kondeti87c01042010-12-07 17:53:58 +05304974
4975 dev_dbg(dev, "OTG PM resume\n");
4976
Saket Saurabh2558ea02014-01-10 16:14:27 +05304977 motg->pm_done = 0;
Jack Pham5ca279b2012-05-14 18:42:54 -07004978 atomic_set(&motg->pm_suspended, 0);
Jack Phamc7edb172012-08-13 15:32:39 -07004979 if (motg->async_int || motg->sm_work_pending) {
Jack Pham5ca279b2012-05-14 18:42:54 -07004980 pm_runtime_get_noresume(dev);
4981 ret = msm_otg_resume(motg);
Pavankumar Kondeti87c01042010-12-07 17:53:58 +05304982
Jack Pham5ca279b2012-05-14 18:42:54 -07004983 /* Update runtime PM status */
4984 pm_runtime_disable(dev);
4985 pm_runtime_set_active(dev);
4986 pm_runtime_enable(dev);
4987
Jack Phamc7edb172012-08-13 15:32:39 -07004988 if (motg->sm_work_pending) {
4989 motg->sm_work_pending = false;
4990 queue_work(system_nrt_wq, &motg->sm_work);
4991 }
Jack Pham5ca279b2012-05-14 18:42:54 -07004992 }
4993
4994 return ret;
Pavankumar Kondeti87c01042010-12-07 17:53:58 +05304995}
Pavankumar Kondeti87c01042010-12-07 17:53:58 +05304996#endif
4997
Pavankumar Kondeti70187732011-02-15 09:42:34 +05304998#ifdef CONFIG_PM
Pavankumar Kondeti87c01042010-12-07 17:53:58 +05304999static const struct dev_pm_ops msm_otg_dev_pm_ops = {
Pavankumar Kondeti70187732011-02-15 09:42:34 +05305000 SET_SYSTEM_SLEEP_PM_OPS(msm_otg_pm_suspend, msm_otg_pm_resume)
5001 SET_RUNTIME_PM_OPS(msm_otg_runtime_suspend, msm_otg_runtime_resume,
5002 msm_otg_runtime_idle)
Pavankumar Kondeti87c01042010-12-07 17:53:58 +05305003};
Pavankumar Kondeti70187732011-02-15 09:42:34 +05305004#endif
Pavankumar Kondeti87c01042010-12-07 17:53:58 +05305005
Pavankumar Kondetieaea7fe2011-10-27 14:46:45 +05305006static struct of_device_id msm_otg_dt_match[] = {
5007 { .compatible = "qcom,hsusb-otg",
5008 },
5009 {}
5010};
5011
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05305012static struct platform_driver msm_otg_driver = {
5013 .remove = __devexit_p(msm_otg_remove),
5014 .driver = {
5015 .name = DRIVER_NAME,
5016 .owner = THIS_MODULE,
Pavankumar Kondeti70187732011-02-15 09:42:34 +05305017#ifdef CONFIG_PM
Pavankumar Kondeti87c01042010-12-07 17:53:58 +05305018 .pm = &msm_otg_dev_pm_ops,
Pavankumar Kondeti70187732011-02-15 09:42:34 +05305019#endif
Pavankumar Kondetieaea7fe2011-10-27 14:46:45 +05305020 .of_match_table = msm_otg_dt_match,
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05305021 },
5022};
5023
5024static int __init msm_otg_init(void)
5025{
5026 return platform_driver_probe(&msm_otg_driver, msm_otg_probe);
5027}
5028
5029static void __exit msm_otg_exit(void)
5030{
5031 platform_driver_unregister(&msm_otg_driver);
5032}
5033
5034module_init(msm_otg_init);
5035module_exit(msm_otg_exit);
5036
5037MODULE_LICENSE("GPL v2");
5038MODULE_DESCRIPTION("MSM USB transceiver driver");