blob: eb65509ede55a71e6e73b1bd4930ccbe9bcfe2a8 [file] [log] [blame]
Pavankumar Kondetiebb4a2d2013-01-04 12:28:10 +05301/* Copyright (c) 2009-2013, Linux Foundation. All rights reserved.
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05302 *
3 * This program is free software; you can redistribute it and/or modify
4 * it under the terms of the GNU General Public License version 2 and
5 * only version 2 as published by the Free Software Foundation.
6 *
7 * This program is distributed in the hope that it will be useful,
8 * but WITHOUT ANY WARRANTY; without even the implied warranty of
9 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10 * GNU General Public License for more details.
11 *
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +053012 */
13
14#include <linux/module.h>
15#include <linux/device.h>
16#include <linux/platform_device.h>
17#include <linux/clk.h>
18#include <linux/slab.h>
19#include <linux/interrupt.h>
20#include <linux/err.h>
21#include <linux/delay.h>
22#include <linux/io.h>
23#include <linux/ioport.h>
24#include <linux/uaccess.h>
25#include <linux/debugfs.h>
26#include <linux/seq_file.h>
Pavankumar Kondeti87c01042010-12-07 17:53:58 +053027#include <linux/pm_runtime.h>
Pavankumar Kondetieaea7fe2011-10-27 14:46:45 +053028#include <linux/of.h>
29#include <linux/dma-mapping.h>
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +053030
31#include <linux/usb.h>
32#include <linux/usb/otg.h>
33#include <linux/usb/ulpi.h>
34#include <linux/usb/gadget.h>
35#include <linux/usb/hcd.h>
Vijayavardhan Vennapusaa3152032012-03-05 16:29:30 +053036#include <linux/usb/quirks.h>
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +053037#include <linux/usb/msm_hsusb.h>
38#include <linux/usb/msm_hsusb_hw.h>
Anji jonnala11aa5c42011-05-04 10:19:48 +053039#include <linux/regulator/consumer.h>
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070040#include <linux/mfd/pm8xxx/pm8921-charger.h>
Pavankumar Kondeti446f4542012-02-01 13:57:13 +053041#include <linux/mfd/pm8xxx/misc.h>
Pavankumar Kondeti2aec9f32012-06-13 09:06:03 +053042#include <linux/mhl_8334.h>
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +053043
Manu Gautam0ddbd922012-09-21 17:17:38 +053044#include <mach/scm.h>
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +053045#include <mach/clk.h>
Jack Pham87f202f2012-08-06 00:24:22 -070046#include <mach/mpm.h>
Anji jonnala7da3f262011-12-02 17:22:14 -080047#include <mach/msm_xo.h>
Manu Gautamcd82e9d2011-12-20 14:17:28 +053048#include <mach/msm_bus.h>
Mayank Rana248698c2012-04-19 00:03:16 +053049#include <mach/rpm-regulator.h>
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +053050
51#define MSM_USB_BASE (motg->regs)
52#define DRIVER_NAME "msm_otg"
53
Chiranjeevi Velempati489a27c2012-03-29 09:47:17 +053054#define ID_TIMER_FREQ (jiffies + msecs_to_jiffies(500))
Pavankumar Kondeti458d8792012-09-28 14:45:18 +053055#define CHG_RECHECK_DELAY (jiffies + msecs_to_jiffies(2000))
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +053056#define ULPI_IO_TIMEOUT_USEC (10 * 1000)
Anji jonnala11aa5c42011-05-04 10:19:48 +053057#define USB_PHY_3P3_VOL_MIN 3050000 /* uV */
58#define USB_PHY_3P3_VOL_MAX 3300000 /* uV */
59#define USB_PHY_3P3_HPM_LOAD 50000 /* uA */
60#define USB_PHY_3P3_LPM_LOAD 4000 /* uA */
61
62#define USB_PHY_1P8_VOL_MIN 1800000 /* uV */
63#define USB_PHY_1P8_VOL_MAX 1800000 /* uV */
64#define USB_PHY_1P8_HPM_LOAD 50000 /* uA */
65#define USB_PHY_1P8_LPM_LOAD 4000 /* uA */
66
Mayank Rana248698c2012-04-19 00:03:16 +053067#define USB_PHY_VDD_DIG_VOL_NONE 0 /*uV */
Vamsi Krishna132b2762011-11-11 16:09:20 -080068#define USB_PHY_VDD_DIG_VOL_MIN 1045000 /* uV */
Anji jonnala11aa5c42011-05-04 10:19:48 +053069#define USB_PHY_VDD_DIG_VOL_MAX 1320000 /* uV */
70
Amit Blayd0fe07b2012-09-05 16:42:09 +030071#define USB_SUSPEND_DELAY_TIME (500 * HZ/1000) /* 500 msec */
72
Amit Blay81801aa2012-09-19 12:08:12 +020073enum msm_otg_phy_reg_mode {
74 USB_PHY_REG_OFF,
75 USB_PHY_REG_ON,
76 USB_PHY_REG_LPM_ON,
77 USB_PHY_REG_LPM_OFF,
78};
79
Mayank Rana443f9e42012-09-21 18:32:39 +053080static char *override_phy_init;
81module_param(override_phy_init, charp, S_IRUGO|S_IWUSR);
82MODULE_PARM_DESC(override_phy_init,
83 "Override HSUSB PHY Init Settings");
84
Amit Blayd6f38282012-10-29 13:13:46 +020085unsigned int lpm_disconnect_thresh = 1000;
86module_param(lpm_disconnect_thresh , uint, S_IRUGO | S_IWUSR);
87MODULE_PARM_DESC(lpm_disconnect_thresh,
88 "Delay before entering LPM on USB disconnect");
89
zhenhuahb6d5edc2013-06-19 14:37:32 +080090static bool floated_charger_enable;
91module_param(floated_charger_enable , bool, S_IRUGO | S_IWUSR);
92MODULE_PARM_DESC(floated_charger_enable,
93 "Whether to enable floated charger");
94
Pavankumar Kondeti4960f312011-12-06 15:46:14 +053095static DECLARE_COMPLETION(pmic_vbus_init);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070096static struct msm_otg *the_msm_otg;
Pavankumar Kondetiaa449e12011-11-04 11:09:26 +053097static bool debug_aca_enabled;
Manu Gautam8bdcc592012-03-06 11:26:06 +053098static bool debug_bus_voting_enabled;
Pavankumar Kondeti2aec9f32012-06-13 09:06:03 +053099static bool mhl_det_in_progress;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700100
Anji jonnala11aa5c42011-05-04 10:19:48 +0530101static struct regulator *hsusb_3p3;
102static struct regulator *hsusb_1p8;
Mayank Rana0f286cf2013-02-27 11:43:27 +0530103static struct regulator *hsusb_vdd;
Mayank Ranae3926882011-12-26 09:47:54 +0530104static struct regulator *vbus_otg;
Pavankumar Kondeti56dc7422012-07-02 12:45:19 +0530105static struct regulator *mhl_usb_hs_switch;
Vijayavardhan Vennapusa05c437c2012-05-25 16:20:46 +0530106static struct power_supply *psy;
Anji jonnala11aa5c42011-05-04 10:19:48 +0530107
Pavankumar Kondeti4960f312011-12-06 15:46:14 +0530108static bool aca_id_turned_on;
David Keitel272ce522012-08-17 16:25:24 -0700109static bool legacy_power_supply;
Pavankumar Kondetiaa449e12011-11-04 11:09:26 +0530110static inline bool aca_enabled(void)
Anji jonnala11aa5c42011-05-04 10:19:48 +0530111{
Pavankumar Kondetiaa449e12011-11-04 11:09:26 +0530112#ifdef CONFIG_USB_MSM_ACA
113 return true;
114#else
115 return debug_aca_enabled;
116#endif
Anji jonnala11aa5c42011-05-04 10:19:48 +0530117}
118
Mayank Rana0f286cf2013-02-27 11:43:27 +0530119static int vdd_val[VDD_TYPE_MAX][VDD_VAL_MAX] = {
Mayank Rana248698c2012-04-19 00:03:16 +0530120 { /* VDD_CX CORNER Voting */
121 [VDD_NONE] = RPM_VREG_CORNER_NONE,
122 [VDD_MIN] = RPM_VREG_CORNER_NOMINAL,
123 [VDD_MAX] = RPM_VREG_CORNER_HIGH,
124 },
125 { /* VDD_CX Voltage Voting */
126 [VDD_NONE] = USB_PHY_VDD_DIG_VOL_NONE,
127 [VDD_MIN] = USB_PHY_VDD_DIG_VOL_MIN,
128 [VDD_MAX] = USB_PHY_VDD_DIG_VOL_MAX,
129 },
130};
Anji jonnala11aa5c42011-05-04 10:19:48 +0530131
132static int msm_hsusb_ldo_init(struct msm_otg *motg, int init)
133{
134 int rc = 0;
135
136 if (init) {
Steve Mucklef132c6c2012-06-06 18:30:57 -0700137 hsusb_3p3 = devm_regulator_get(motg->phy.dev, "HSUSB_3p3");
Anji jonnala11aa5c42011-05-04 10:19:48 +0530138 if (IS_ERR(hsusb_3p3)) {
Heikki Krogerus1d4c9292012-02-13 13:24:09 +0200139 dev_err(motg->phy.dev, "unable to get hsusb 3p3\n");
Anji jonnala11aa5c42011-05-04 10:19:48 +0530140 return PTR_ERR(hsusb_3p3);
141 }
142
143 rc = regulator_set_voltage(hsusb_3p3, USB_PHY_3P3_VOL_MIN,
144 USB_PHY_3P3_VOL_MAX);
145 if (rc) {
Steve Mucklef132c6c2012-06-06 18:30:57 -0700146 dev_err(motg->phy.dev, "unable to set voltage level for"
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700147 "hsusb 3p3\n");
Mayank Rana9e9a2ac2012-03-24 04:05:28 +0530148 return rc;
Anji jonnala11aa5c42011-05-04 10:19:48 +0530149 }
Steve Mucklef132c6c2012-06-06 18:30:57 -0700150 hsusb_1p8 = devm_regulator_get(motg->phy.dev, "HSUSB_1p8");
Anji jonnala11aa5c42011-05-04 10:19:48 +0530151 if (IS_ERR(hsusb_1p8)) {
Heikki Krogerus1d4c9292012-02-13 13:24:09 +0200152 dev_err(motg->phy.dev, "unable to get hsusb 1p8\n");
Anji jonnala11aa5c42011-05-04 10:19:48 +0530153 rc = PTR_ERR(hsusb_1p8);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700154 goto put_3p3_lpm;
Anji jonnala11aa5c42011-05-04 10:19:48 +0530155 }
156 rc = regulator_set_voltage(hsusb_1p8, USB_PHY_1P8_VOL_MIN,
157 USB_PHY_1P8_VOL_MAX);
158 if (rc) {
Stephen Boyd9850acb2013-01-28 14:11:20 -0800159 dev_err(motg->phy.dev, "unable to set voltage level "
160 "for hsusb 1p8\n");
Anji jonnala11aa5c42011-05-04 10:19:48 +0530161 goto put_1p8;
162 }
163
164 return 0;
165 }
166
Anji jonnala11aa5c42011-05-04 10:19:48 +0530167put_1p8:
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700168 regulator_set_voltage(hsusb_1p8, 0, USB_PHY_1P8_VOL_MAX);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700169put_3p3_lpm:
170 regulator_set_voltage(hsusb_3p3, 0, USB_PHY_3P3_VOL_MAX);
Anji jonnala11aa5c42011-05-04 10:19:48 +0530171 return rc;
172}
173
Pavankumar Kondeti04aebcb2011-05-04 10:19:49 +0530174static int msm_hsusb_config_vddcx(int high)
175{
Mayank Rana248698c2012-04-19 00:03:16 +0530176 struct msm_otg *motg = the_msm_otg;
177 enum usb_vdd_type vdd_type = motg->vdd_type;
178 int max_vol = vdd_val[vdd_type][VDD_MAX];
Pavankumar Kondeti04aebcb2011-05-04 10:19:49 +0530179 int min_vol;
180 int ret;
181
Mayank Rana248698c2012-04-19 00:03:16 +0530182 min_vol = vdd_val[vdd_type][!!high];
Mayank Rana0f286cf2013-02-27 11:43:27 +0530183 ret = regulator_set_voltage(hsusb_vdd, min_vol, max_vol);
Pavankumar Kondeti04aebcb2011-05-04 10:19:49 +0530184 if (ret) {
185 pr_err("%s: unable to set the voltage for regulator "
186 "HSUSB_VDDCX\n", __func__);
187 return ret;
188 }
189
190 pr_debug("%s: min_vol:%d max_vol:%d\n", __func__, min_vol, max_vol);
191
192 return ret;
193}
Pavankumar Kondeti04aebcb2011-05-04 10:19:49 +0530194
Amit Blay81801aa2012-09-19 12:08:12 +0200195static int msm_hsusb_ldo_enable(struct msm_otg *motg,
196 enum msm_otg_phy_reg_mode mode)
Anji jonnala11aa5c42011-05-04 10:19:48 +0530197{
198 int ret = 0;
199
Pavankumar Kondeti68964c92011-10-27 14:58:56 +0530200 if (IS_ERR(hsusb_1p8)) {
Anji jonnala11aa5c42011-05-04 10:19:48 +0530201 pr_err("%s: HSUSB_1p8 is not initialized\n", __func__);
202 return -ENODEV;
203 }
204
Pavankumar Kondeti68964c92011-10-27 14:58:56 +0530205 if (IS_ERR(hsusb_3p3)) {
Anji jonnala11aa5c42011-05-04 10:19:48 +0530206 pr_err("%s: HSUSB_3p3 is not initialized\n", __func__);
207 return -ENODEV;
208 }
209
Amit Blay81801aa2012-09-19 12:08:12 +0200210 switch (mode) {
211 case USB_PHY_REG_ON:
Anji jonnala11aa5c42011-05-04 10:19:48 +0530212 ret = regulator_set_optimum_mode(hsusb_1p8,
213 USB_PHY_1P8_HPM_LOAD);
214 if (ret < 0) {
Stephen Boyd9850acb2013-01-28 14:11:20 -0800215 pr_err("%s: Unable to set HPM of the regulator "
Anji jonnala11aa5c42011-05-04 10:19:48 +0530216 "HSUSB_1p8\n", __func__);
217 return ret;
218 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700219
220 ret = regulator_enable(hsusb_1p8);
221 if (ret) {
Steve Mucklef132c6c2012-06-06 18:30:57 -0700222 dev_err(motg->phy.dev, "%s: unable to enable the hsusb 1p8\n",
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700223 __func__);
224 regulator_set_optimum_mode(hsusb_1p8, 0);
225 return ret;
226 }
227
Anji jonnala11aa5c42011-05-04 10:19:48 +0530228 ret = regulator_set_optimum_mode(hsusb_3p3,
229 USB_PHY_3P3_HPM_LOAD);
230 if (ret < 0) {
Stephen Boyd9850acb2013-01-28 14:11:20 -0800231 pr_err("%s: Unable to set HPM of the regulator "
Anji jonnala11aa5c42011-05-04 10:19:48 +0530232 "HSUSB_3p3\n", __func__);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700233 regulator_set_optimum_mode(hsusb_1p8, 0);
234 regulator_disable(hsusb_1p8);
Anji jonnala11aa5c42011-05-04 10:19:48 +0530235 return ret;
236 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700237
238 ret = regulator_enable(hsusb_3p3);
239 if (ret) {
Steve Mucklef132c6c2012-06-06 18:30:57 -0700240 dev_err(motg->phy.dev, "%s: unable to enable the hsusb 3p3\n",
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700241 __func__);
242 regulator_set_optimum_mode(hsusb_3p3, 0);
243 regulator_set_optimum_mode(hsusb_1p8, 0);
244 regulator_disable(hsusb_1p8);
245 return ret;
246 }
247
Amit Blay81801aa2012-09-19 12:08:12 +0200248 break;
249
250 case USB_PHY_REG_OFF:
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700251 ret = regulator_disable(hsusb_1p8);
252 if (ret) {
Steve Mucklef132c6c2012-06-06 18:30:57 -0700253 dev_err(motg->phy.dev, "%s: unable to disable the hsusb 1p8\n",
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700254 __func__);
255 return ret;
256 }
257
258 ret = regulator_set_optimum_mode(hsusb_1p8, 0);
Anji jonnala11aa5c42011-05-04 10:19:48 +0530259 if (ret < 0)
Stephen Boyd9850acb2013-01-28 14:11:20 -0800260 pr_err("%s: Unable to set LPM of the regulator "
Anji jonnala11aa5c42011-05-04 10:19:48 +0530261 "HSUSB_1p8\n", __func__);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700262
263 ret = regulator_disable(hsusb_3p3);
264 if (ret) {
Steve Mucklef132c6c2012-06-06 18:30:57 -0700265 dev_err(motg->phy.dev, "%s: unable to disable the hsusb 3p3\n",
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700266 __func__);
267 return ret;
268 }
269 ret = regulator_set_optimum_mode(hsusb_3p3, 0);
Anji jonnala11aa5c42011-05-04 10:19:48 +0530270 if (ret < 0)
Stephen Boyd9850acb2013-01-28 14:11:20 -0800271 pr_err("%s: Unable to set LPM of the regulator "
Anji jonnala11aa5c42011-05-04 10:19:48 +0530272 "HSUSB_3p3\n", __func__);
Amit Blay81801aa2012-09-19 12:08:12 +0200273
274 break;
275
276 case USB_PHY_REG_LPM_ON:
277 ret = regulator_set_optimum_mode(hsusb_1p8,
278 USB_PHY_1P8_LPM_LOAD);
279 if (ret < 0) {
280 pr_err("%s: Unable to set LPM of the regulator: HSUSB_1p8\n",
281 __func__);
282 return ret;
283 }
284
285 ret = regulator_set_optimum_mode(hsusb_3p3,
286 USB_PHY_3P3_LPM_LOAD);
287 if (ret < 0) {
288 pr_err("%s: Unable to set LPM of the regulator: HSUSB_3p3\n",
289 __func__);
290 regulator_set_optimum_mode(hsusb_1p8, USB_PHY_REG_ON);
291 return ret;
292 }
293
294 break;
295
296 case USB_PHY_REG_LPM_OFF:
297 ret = regulator_set_optimum_mode(hsusb_1p8,
298 USB_PHY_1P8_HPM_LOAD);
299 if (ret < 0) {
300 pr_err("%s: Unable to set HPM of the regulator: HSUSB_1p8\n",
301 __func__);
302 return ret;
303 }
304
305 ret = regulator_set_optimum_mode(hsusb_3p3,
306 USB_PHY_3P3_HPM_LOAD);
307 if (ret < 0) {
308 pr_err("%s: Unable to set HPM of the regulator: HSUSB_3p3\n",
309 __func__);
310 regulator_set_optimum_mode(hsusb_1p8, USB_PHY_REG_ON);
311 return ret;
312 }
313
314 break;
315
316 default:
317 pr_err("%s: Unsupported mode (%d).", __func__, mode);
318 return -ENOTSUPP;
Anji jonnala11aa5c42011-05-04 10:19:48 +0530319 }
320
Amit Blay81801aa2012-09-19 12:08:12 +0200321 pr_debug("%s: USB reg mode (%d) (OFF/HPM/LPM)\n", __func__, mode);
Anji jonnala11aa5c42011-05-04 10:19:48 +0530322 return ret < 0 ? ret : 0;
323}
324
Vijayavardhan Vennapusafc464f02011-11-04 21:54:00 +0530325static void msm_hsusb_mhl_switch_enable(struct msm_otg *motg, bool on)
326{
Vijayavardhan Vennapusafc464f02011-11-04 21:54:00 +0530327 struct msm_otg_platform_data *pdata = motg->pdata;
328
329 if (!pdata->mhl_enable)
330 return;
331
Pavankumar Kondeti56dc7422012-07-02 12:45:19 +0530332 if (!mhl_usb_hs_switch) {
333 pr_err("%s: mhl_usb_hs_switch is NULL.\n", __func__);
Vijayavardhan Vennapusafc464f02011-11-04 21:54:00 +0530334 return;
335 }
336
Mayank Rana9e9a2ac2012-03-24 04:05:28 +0530337 if (on) {
Pavankumar Kondeti56dc7422012-07-02 12:45:19 +0530338 if (regulator_enable(mhl_usb_hs_switch))
339 pr_err("unable to enable mhl_usb_hs_switch\n");
Mayank Rana9e9a2ac2012-03-24 04:05:28 +0530340 } else {
Pavankumar Kondeti56dc7422012-07-02 12:45:19 +0530341 regulator_disable(mhl_usb_hs_switch);
Mayank Rana9e9a2ac2012-03-24 04:05:28 +0530342 }
Vijayavardhan Vennapusafc464f02011-11-04 21:54:00 +0530343}
344
Heikki Krogerus1d4c9292012-02-13 13:24:09 +0200345static int ulpi_read(struct usb_phy *phy, u32 reg)
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +0530346{
Heikki Krogerus1d4c9292012-02-13 13:24:09 +0200347 struct msm_otg *motg = container_of(phy, struct msm_otg, phy);
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +0530348 int cnt = 0;
349
350 /* initiate read operation */
351 writel(ULPI_RUN | ULPI_READ | ULPI_ADDR(reg),
352 USB_ULPI_VIEWPORT);
353
354 /* wait for completion */
355 while (cnt < ULPI_IO_TIMEOUT_USEC) {
356 if (!(readl(USB_ULPI_VIEWPORT) & ULPI_RUN))
357 break;
358 udelay(1);
359 cnt++;
360 }
361
362 if (cnt >= ULPI_IO_TIMEOUT_USEC) {
Heikki Krogerus1d4c9292012-02-13 13:24:09 +0200363 dev_err(phy->dev, "ulpi_read: timeout %08x\n",
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +0530364 readl(USB_ULPI_VIEWPORT));
365 return -ETIMEDOUT;
366 }
367 return ULPI_DATA_READ(readl(USB_ULPI_VIEWPORT));
368}
369
Heikki Krogerus1d4c9292012-02-13 13:24:09 +0200370static int ulpi_write(struct usb_phy *phy, u32 val, u32 reg)
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +0530371{
Heikki Krogerus1d4c9292012-02-13 13:24:09 +0200372 struct msm_otg *motg = container_of(phy, struct msm_otg, phy);
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +0530373 int cnt = 0;
374
375 /* initiate write operation */
376 writel(ULPI_RUN | ULPI_WRITE |
377 ULPI_ADDR(reg) | ULPI_DATA(val),
378 USB_ULPI_VIEWPORT);
379
380 /* wait for completion */
381 while (cnt < ULPI_IO_TIMEOUT_USEC) {
382 if (!(readl(USB_ULPI_VIEWPORT) & ULPI_RUN))
383 break;
384 udelay(1);
385 cnt++;
386 }
387
388 if (cnt >= ULPI_IO_TIMEOUT_USEC) {
Heikki Krogerus1d4c9292012-02-13 13:24:09 +0200389 dev_err(phy->dev, "ulpi_write: timeout\n");
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +0530390 return -ETIMEDOUT;
391 }
392 return 0;
393}
394
Heikki Krogerus1d4c9292012-02-13 13:24:09 +0200395static struct usb_phy_io_ops msm_otg_io_ops = {
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +0530396 .read = ulpi_read,
397 .write = ulpi_write,
398};
399
400static void ulpi_init(struct msm_otg *motg)
401{
402 struct msm_otg_platform_data *pdata = motg->pdata;
Mayank Rana443f9e42012-09-21 18:32:39 +0530403 int aseq[10];
404 int *seq = NULL;
405
406 if (override_phy_init) {
407 pr_debug("%s(): HUSB PHY Init:%s\n", __func__,
408 override_phy_init);
409 get_options(override_phy_init, ARRAY_SIZE(aseq), aseq);
410 seq = &aseq[1];
411 } else {
412 seq = pdata->phy_init_seq;
413 }
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +0530414
415 if (!seq)
416 return;
417
418 while (seq[0] >= 0) {
Mayank Rana443f9e42012-09-21 18:32:39 +0530419 if (override_phy_init)
420 pr_debug("ulpi: write 0x%02x to 0x%02x\n",
421 seq[0], seq[1]);
422
Heikki Krogerus1d4c9292012-02-13 13:24:09 +0200423 dev_vdbg(motg->phy.dev, "ulpi: write 0x%02x to 0x%02x\n",
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +0530424 seq[0], seq[1]);
Heikki Krogerus1d4c9292012-02-13 13:24:09 +0200425 ulpi_write(&motg->phy, seq[0], seq[1]);
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +0530426 seq += 2;
427 }
428}
429
430static int msm_otg_link_clk_reset(struct msm_otg *motg, bool assert)
431{
432 int ret;
433
434 if (assert) {
Manu Gautam5025ff12012-07-20 10:56:50 +0530435 if (!IS_ERR(motg->clk)) {
436 ret = clk_reset(motg->clk, CLK_RESET_ASSERT);
437 } else {
438 /* Using asynchronous block reset to the hardware */
439 dev_dbg(motg->phy.dev, "block_reset ASSERT\n");
440 clk_disable_unprepare(motg->pclk);
441 clk_disable_unprepare(motg->core_clk);
442 ret = clk_reset(motg->core_clk, CLK_RESET_ASSERT);
443 }
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +0530444 if (ret)
Heikki Krogerus1d4c9292012-02-13 13:24:09 +0200445 dev_err(motg->phy.dev, "usb hs_clk assert failed\n");
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +0530446 } else {
Manu Gautam5025ff12012-07-20 10:56:50 +0530447 if (!IS_ERR(motg->clk)) {
448 ret = clk_reset(motg->clk, CLK_RESET_DEASSERT);
449 } else {
450 dev_dbg(motg->phy.dev, "block_reset DEASSERT\n");
451 ret = clk_reset(motg->core_clk, CLK_RESET_DEASSERT);
452 ndelay(200);
453 clk_prepare_enable(motg->core_clk);
454 clk_prepare_enable(motg->pclk);
455 }
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +0530456 if (ret)
Heikki Krogerus1d4c9292012-02-13 13:24:09 +0200457 dev_err(motg->phy.dev, "usb hs_clk deassert failed\n");
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +0530458 }
459 return ret;
460}
461
462static int msm_otg_phy_clk_reset(struct msm_otg *motg)
463{
464 int ret;
465
Amit Blay02eff132011-09-21 16:46:24 +0300466 if (IS_ERR(motg->phy_reset_clk))
467 return 0;
468
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +0530469 ret = clk_reset(motg->phy_reset_clk, CLK_RESET_ASSERT);
470 if (ret) {
Heikki Krogerus1d4c9292012-02-13 13:24:09 +0200471 dev_err(motg->phy.dev, "usb phy clk assert failed\n");
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +0530472 return ret;
473 }
474 usleep_range(10000, 12000);
475 ret = clk_reset(motg->phy_reset_clk, CLK_RESET_DEASSERT);
476 if (ret)
Heikki Krogerus1d4c9292012-02-13 13:24:09 +0200477 dev_err(motg->phy.dev, "usb phy clk deassert failed\n");
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +0530478 return ret;
479}
480
481static int msm_otg_phy_reset(struct msm_otg *motg)
482{
483 u32 val;
484 int ret;
485 int retries;
Manu Gautam0fd2d0e2013-03-26 18:09:11 +0530486 struct msm_otg_platform_data *pdata = motg->pdata;
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +0530487
488 ret = msm_otg_link_clk_reset(motg, 1);
489 if (ret)
490 return ret;
491 ret = msm_otg_phy_clk_reset(motg);
492 if (ret)
493 return ret;
Amit Blay58dc2bc2013-01-24 12:28:03 +0200494
495 /*
496 * 10 usec delay is required according to spec. Using larger value
497 * since the exact value proved to not work 100% of the time.
498 */
Bar Weinere7129cb2012-11-28 08:44:14 +0200499 if (IS_ERR(motg->phy_reset_clk))
Amit Blay58dc2bc2013-01-24 12:28:03 +0200500 usleep_range(100, 120);
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +0530501 ret = msm_otg_link_clk_reset(motg, 0);
502 if (ret)
503 return ret;
504
Manu Gautam0fd2d0e2013-03-26 18:09:11 +0530505 if (pdata && pdata->enable_sec_phy)
506 writel_relaxed(readl_relaxed(USB_PHY_CTRL2) | (1<<16),
507 USB_PHY_CTRL2);
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +0530508 val = readl(USB_PORTSC) & ~PORTSC_PTS_MASK;
509 writel(val | PORTSC_PTS_ULPI, USB_PORTSC);
510
511 for (retries = 3; retries > 0; retries--) {
Heikki Krogerus1d4c9292012-02-13 13:24:09 +0200512 ret = ulpi_write(&motg->phy, ULPI_FUNC_CTRL_SUSPENDM,
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +0530513 ULPI_CLR(ULPI_FUNC_CTRL));
514 if (!ret)
515 break;
516 ret = msm_otg_phy_clk_reset(motg);
517 if (ret)
518 return ret;
519 }
520 if (!retries)
521 return -ETIMEDOUT;
522
523 /* This reset calibrates the phy, if the above write succeeded */
524 ret = msm_otg_phy_clk_reset(motg);
525 if (ret)
526 return ret;
527
528 for (retries = 3; retries > 0; retries--) {
Heikki Krogerus1d4c9292012-02-13 13:24:09 +0200529 ret = ulpi_read(&motg->phy, ULPI_DEBUG);
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +0530530 if (ret != -ETIMEDOUT)
531 break;
532 ret = msm_otg_phy_clk_reset(motg);
533 if (ret)
534 return ret;
535 }
536 if (!retries)
537 return -ETIMEDOUT;
538
Heikki Krogerus1d4c9292012-02-13 13:24:09 +0200539 dev_info(motg->phy.dev, "phy_reset: success\n");
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +0530540 return 0;
541}
542
543#define LINK_RESET_TIMEOUT_USEC (250 * 1000)
Pavankumar Kondetiaa449e12011-11-04 11:09:26 +0530544static int msm_otg_link_reset(struct msm_otg *motg)
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +0530545{
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +0530546 int cnt = 0;
Manu Gautam0fd2d0e2013-03-26 18:09:11 +0530547 struct msm_otg_platform_data *pdata = motg->pdata;
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +0530548
Pavankumar Kondetiaa449e12011-11-04 11:09:26 +0530549 writel_relaxed(USBCMD_RESET, USB_USBCMD);
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +0530550 while (cnt < LINK_RESET_TIMEOUT_USEC) {
Pavankumar Kondetiaa449e12011-11-04 11:09:26 +0530551 if (!(readl_relaxed(USB_USBCMD) & USBCMD_RESET))
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +0530552 break;
553 udelay(1);
554 cnt++;
555 }
556 if (cnt >= LINK_RESET_TIMEOUT_USEC)
557 return -ETIMEDOUT;
558
559 /* select ULPI phy */
Pavankumar Kondetiaa449e12011-11-04 11:09:26 +0530560 writel_relaxed(0x80000000, USB_PORTSC);
561 writel_relaxed(0x0, USB_AHBBURST);
Vijayavardhan Vennapusa5f32d7a2012-03-14 16:30:26 +0530562 writel_relaxed(0x08, USB_AHBMODE);
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +0530563
Manu Gautam0fd2d0e2013-03-26 18:09:11 +0530564 if (pdata && pdata->enable_sec_phy)
565 writel_relaxed(readl_relaxed(USB_PHY_CTRL2) | (1<<16),
566 USB_PHY_CTRL2);
Pavankumar Kondetiaa449e12011-11-04 11:09:26 +0530567 return 0;
568}
569
Steve Mucklef132c6c2012-06-06 18:30:57 -0700570static int msm_otg_reset(struct usb_phy *phy)
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +0530571{
Steve Mucklef132c6c2012-06-06 18:30:57 -0700572 struct msm_otg *motg = container_of(phy, struct msm_otg, phy);
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +0530573 struct msm_otg_platform_data *pdata = motg->pdata;
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +0530574 int ret;
575 u32 val = 0;
576 u32 ulpi_val = 0;
577
Ofir Cohen4da266f2012-01-03 10:19:29 +0200578 /*
579 * USB PHY and Link reset also reset the USB BAM.
580 * Thus perform reset operation only once to avoid
581 * USB BAM reset on other cases e.g. USB cable disconnections.
582 */
583 if (pdata->disable_reset_on_disconnect) {
584 if (motg->reset_counter)
585 return 0;
586 else
587 motg->reset_counter++;
588 }
589
Pavankumar Kondeti923262e2012-04-20 15:34:24 +0530590 if (!IS_ERR(motg->clk))
591 clk_prepare_enable(motg->clk);
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +0530592 ret = msm_otg_phy_reset(motg);
593 if (ret) {
Steve Mucklef132c6c2012-06-06 18:30:57 -0700594 dev_err(phy->dev, "phy_reset failed\n");
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +0530595 return ret;
596 }
597
Pavankumar Kondeti4960f312011-12-06 15:46:14 +0530598 aca_id_turned_on = false;
Pavankumar Kondetiaa449e12011-11-04 11:09:26 +0530599 ret = msm_otg_link_reset(motg);
600 if (ret) {
Steve Mucklef132c6c2012-06-06 18:30:57 -0700601 dev_err(phy->dev, "link reset failed\n");
Pavankumar Kondetiaa449e12011-11-04 11:09:26 +0530602 return ret;
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +0530603 }
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +0530604 msleep(100);
605
Anji jonnalaa8b8d732011-12-06 10:03:24 +0530606 ulpi_init(motg);
607
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700608 /* Ensure that RESET operation is completed before turning off clock */
609 mb();
Pavankumar Kondetiaa449e12011-11-04 11:09:26 +0530610
Pavankumar Kondeti923262e2012-04-20 15:34:24 +0530611 if (!IS_ERR(motg->clk))
612 clk_disable_unprepare(motg->clk);
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +0530613
614 if (pdata->otg_control == OTG_PHY_CONTROL) {
Pavankumar Kondeti4960f312011-12-06 15:46:14 +0530615 val = readl_relaxed(USB_OTGSC);
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +0530616 if (pdata->mode == USB_OTG) {
617 ulpi_val = ULPI_INT_IDGRD | ULPI_INT_SESS_VALID;
618 val |= OTGSC_IDIE | OTGSC_BSVIE;
619 } else if (pdata->mode == USB_PERIPHERAL) {
620 ulpi_val = ULPI_INT_SESS_VALID;
621 val |= OTGSC_BSVIE;
622 }
Pavankumar Kondeti4960f312011-12-06 15:46:14 +0530623 writel_relaxed(val, USB_OTGSC);
Heikki Krogerus1d4c9292012-02-13 13:24:09 +0200624 ulpi_write(phy, ulpi_val, ULPI_USB_INT_EN_RISE);
625 ulpi_write(phy, ulpi_val, ULPI_USB_INT_EN_FALL);
Pavankumar Kondeti446f4542012-02-01 13:57:13 +0530626 } else if (pdata->otg_control == OTG_PMIC_CONTROL) {
Steve Mucklef132c6c2012-06-06 18:30:57 -0700627 ulpi_write(phy, OTG_COMP_DISABLE,
Vijayavardhan Vennapusa03171c72012-04-26 14:44:48 +0530628 ULPI_SET(ULPI_PWR_CLK_MNG_REG));
Pavankumar Kondeti446f4542012-02-01 13:57:13 +0530629 /* Enable PMIC pull-up */
630 pm8xxx_usb_id_pullup(1);
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +0530631 }
632
633 return 0;
634}
635
Vijayavardhan Vennapusaa3152032012-03-05 16:29:30 +0530636static const char *timer_string(int bit)
637{
638 switch (bit) {
639 case A_WAIT_VRISE: return "a_wait_vrise";
640 case A_WAIT_VFALL: return "a_wait_vfall";
641 case B_SRP_FAIL: return "b_srp_fail";
642 case A_WAIT_BCON: return "a_wait_bcon";
643 case A_AIDL_BDIS: return "a_aidl_bdis";
644 case A_BIDL_ADIS: return "a_bidl_adis";
645 case B_ASE0_BRST: return "b_ase0_brst";
646 case A_TST_MAINT: return "a_tst_maint";
647 case B_TST_SRP: return "b_tst_srp";
648 case B_TST_CONFIG: return "b_tst_config";
649 default: return "UNDEFINED";
650 }
651}
652
653static enum hrtimer_restart msm_otg_timer_func(struct hrtimer *hrtimer)
654{
655 struct msm_otg *motg = container_of(hrtimer, struct msm_otg, timer);
656
657 switch (motg->active_tmout) {
658 case A_WAIT_VRISE:
659 /* TODO: use vbus_vld interrupt */
660 set_bit(A_VBUS_VLD, &motg->inputs);
661 break;
662 case A_TST_MAINT:
663 /* OTG PET: End session after TA_TST_MAINT */
664 set_bit(A_BUS_DROP, &motg->inputs);
665 break;
666 case B_TST_SRP:
667 /*
668 * OTG PET: Initiate SRP after TB_TST_SRP of
669 * previous session end.
670 */
671 set_bit(B_BUS_REQ, &motg->inputs);
672 break;
673 case B_TST_CONFIG:
674 clear_bit(A_CONN, &motg->inputs);
675 break;
676 default:
677 set_bit(motg->active_tmout, &motg->tmouts);
678 }
679
680 pr_debug("expired %s timer\n", timer_string(motg->active_tmout));
681 queue_work(system_nrt_wq, &motg->sm_work);
682 return HRTIMER_NORESTART;
683}
684
685static void msm_otg_del_timer(struct msm_otg *motg)
686{
687 int bit = motg->active_tmout;
688
689 pr_debug("deleting %s timer. remaining %lld msec\n", timer_string(bit),
690 div_s64(ktime_to_us(hrtimer_get_remaining(
691 &motg->timer)), 1000));
692 hrtimer_cancel(&motg->timer);
693 clear_bit(bit, &motg->tmouts);
694}
695
696static void msm_otg_start_timer(struct msm_otg *motg, int time, int bit)
697{
698 clear_bit(bit, &motg->tmouts);
699 motg->active_tmout = bit;
700 pr_debug("starting %s timer\n", timer_string(bit));
701 hrtimer_start(&motg->timer,
702 ktime_set(time / 1000, (time % 1000) * 1000000),
703 HRTIMER_MODE_REL);
704}
705
706static void msm_otg_init_timer(struct msm_otg *motg)
707{
708 hrtimer_init(&motg->timer, CLOCK_MONOTONIC, HRTIMER_MODE_REL);
709 motg->timer.function = msm_otg_timer_func;
710}
711
Steve Mucklef132c6c2012-06-06 18:30:57 -0700712static int msm_otg_start_hnp(struct usb_otg *otg)
Vijayavardhan Vennapusaa3152032012-03-05 16:29:30 +0530713{
Steve Mucklef132c6c2012-06-06 18:30:57 -0700714 struct msm_otg *motg = container_of(otg->phy, struct msm_otg, phy);
Vijayavardhan Vennapusaa3152032012-03-05 16:29:30 +0530715
Steve Mucklef132c6c2012-06-06 18:30:57 -0700716 if (otg->phy->state != OTG_STATE_A_HOST) {
Vijayavardhan Vennapusaa3152032012-03-05 16:29:30 +0530717 pr_err("HNP can not be initiated in %s state\n",
Steve Mucklef132c6c2012-06-06 18:30:57 -0700718 otg_state_string(otg->phy->state));
Vijayavardhan Vennapusaa3152032012-03-05 16:29:30 +0530719 return -EINVAL;
720 }
721
722 pr_debug("A-Host: HNP initiated\n");
723 clear_bit(A_BUS_REQ, &motg->inputs);
724 queue_work(system_nrt_wq, &motg->sm_work);
725 return 0;
726}
727
Steve Mucklef132c6c2012-06-06 18:30:57 -0700728static int msm_otg_start_srp(struct usb_otg *otg)
Vijayavardhan Vennapusaa3152032012-03-05 16:29:30 +0530729{
Steve Mucklef132c6c2012-06-06 18:30:57 -0700730 struct msm_otg *motg = container_of(otg->phy, struct msm_otg, phy);
Vijayavardhan Vennapusaa3152032012-03-05 16:29:30 +0530731 u32 val;
732 int ret = 0;
733
Steve Mucklef132c6c2012-06-06 18:30:57 -0700734 if (otg->phy->state != OTG_STATE_B_IDLE) {
Vijayavardhan Vennapusaa3152032012-03-05 16:29:30 +0530735 pr_err("SRP can not be initiated in %s state\n",
Steve Mucklef132c6c2012-06-06 18:30:57 -0700736 otg_state_string(otg->phy->state));
Vijayavardhan Vennapusaa3152032012-03-05 16:29:30 +0530737 ret = -EINVAL;
738 goto out;
739 }
740
741 if ((jiffies - motg->b_last_se0_sess) < msecs_to_jiffies(TB_SRP_INIT)) {
742 pr_debug("initial conditions of SRP are not met. Try again"
743 "after some time\n");
744 ret = -EAGAIN;
745 goto out;
746 }
747
748 pr_debug("B-Device SRP started\n");
749
750 /*
751 * PHY won't pull D+ high unless it detects Vbus valid.
752 * Since by definition, SRP is only done when Vbus is not valid,
753 * software work-around needs to be used to spoof the PHY into
754 * thinking it is valid. This can be done using the VBUSVLDEXTSEL and
755 * VBUSVLDEXT register bits.
756 */
Steve Mucklef132c6c2012-06-06 18:30:57 -0700757 ulpi_write(otg->phy, 0x03, 0x97);
Vijayavardhan Vennapusaa3152032012-03-05 16:29:30 +0530758 /*
759 * Harware auto assist data pulsing: Data pulse is given
760 * for 7msec; wait for vbus
761 */
762 val = readl_relaxed(USB_OTGSC);
763 writel_relaxed((val & ~OTGSC_INTSTS_MASK) | OTGSC_HADP, USB_OTGSC);
764
765 /* VBUS plusing is obsoleted in OTG 2.0 supplement */
766out:
767 return ret;
768}
769
Steve Mucklef132c6c2012-06-06 18:30:57 -0700770static void msm_otg_host_hnp_enable(struct usb_otg *otg, bool enable)
Vijayavardhan Vennapusaa3152032012-03-05 16:29:30 +0530771{
772 struct usb_hcd *hcd = bus_to_hcd(otg->host);
773 struct usb_device *rhub = otg->host->root_hub;
774
775 if (enable) {
776 pm_runtime_disable(&rhub->dev);
777 rhub->state = USB_STATE_NOTATTACHED;
778 hcd->driver->bus_suspend(hcd);
779 clear_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags);
780 } else {
781 usb_remove_hcd(hcd);
Steve Mucklef132c6c2012-06-06 18:30:57 -0700782 msm_otg_reset(otg->phy);
Vijayavardhan Vennapusaa3152032012-03-05 16:29:30 +0530783 usb_add_hcd(hcd, hcd->irq, IRQF_SHARED);
784 }
785}
786
Steve Mucklef132c6c2012-06-06 18:30:57 -0700787static int msm_otg_set_suspend(struct usb_phy *phy, int suspend)
Pavankumar Kondeti8be99cf2011-08-04 10:48:08 +0530788{
Steve Mucklef132c6c2012-06-06 18:30:57 -0700789 struct msm_otg *motg = container_of(phy, struct msm_otg, phy);
Pavankumar Kondeti8be99cf2011-08-04 10:48:08 +0530790
Amit Blay6fa647a2012-05-24 14:12:08 +0300791 if (aca_enabled())
Vijayavardhan Vennapusaa3152032012-03-05 16:29:30 +0530792 return 0;
Pavankumar Kondeti8be99cf2011-08-04 10:48:08 +0530793
Pavankumar Kondetie618bf82012-11-28 21:12:44 +0530794 /*
795 * UDC and HCD call usb_phy_set_suspend() to enter/exit LPM
796 * during bus suspend/resume. Update the relevant state
797 * machine inputs and trigger LPM entry/exit. Checking
798 * in_lpm flag would avoid unnecessary work scheduling.
799 */
Vijayavardhan Vennapusaa3152032012-03-05 16:29:30 +0530800 if (suspend) {
Steve Mucklef132c6c2012-06-06 18:30:57 -0700801 switch (phy->state) {
Vijayavardhan Vennapusaa3152032012-03-05 16:29:30 +0530802 case OTG_STATE_A_WAIT_BCON:
803 if (TA_WAIT_BCON > 0)
804 break;
805 /* fall through */
806 case OTG_STATE_A_HOST:
807 pr_debug("host bus suspend\n");
808 clear_bit(A_BUS_REQ, &motg->inputs);
Pavankumar Kondetie618bf82012-11-28 21:12:44 +0530809 if (!atomic_read(&motg->in_lpm))
810 queue_work(system_nrt_wq, &motg->sm_work);
Vijayavardhan Vennapusaa3152032012-03-05 16:29:30 +0530811 break;
Amit Blay6fa647a2012-05-24 14:12:08 +0300812 case OTG_STATE_B_PERIPHERAL:
813 pr_debug("peripheral bus suspend\n");
814 if (!(motg->caps & ALLOW_LPM_ON_DEV_SUSPEND))
815 break;
816 set_bit(A_BUS_SUSPEND, &motg->inputs);
Pavankumar Kondetie618bf82012-11-28 21:12:44 +0530817 if (!atomic_read(&motg->in_lpm))
818 queue_delayed_work(system_nrt_wq,
819 &motg->suspend_work,
820 USB_SUSPEND_DELAY_TIME);
Amit Blay6fa647a2012-05-24 14:12:08 +0300821 break;
822
Vijayavardhan Vennapusaa3152032012-03-05 16:29:30 +0530823 default:
824 break;
825 }
826 } else {
Steve Mucklef132c6c2012-06-06 18:30:57 -0700827 switch (phy->state) {
Pavankumar Kondetie618bf82012-11-28 21:12:44 +0530828 case OTG_STATE_A_WAIT_BCON:
829 /* Remote wakeup or resume */
830 set_bit(A_BUS_REQ, &motg->inputs);
831 /* ensure hardware is not in low power mode */
832 if (atomic_read(&motg->in_lpm))
833 pm_runtime_resume(phy->dev);
834 break;
Vijayavardhan Vennapusaa3152032012-03-05 16:29:30 +0530835 case OTG_STATE_A_SUSPEND:
836 /* Remote wakeup or resume */
837 set_bit(A_BUS_REQ, &motg->inputs);
Steve Mucklef132c6c2012-06-06 18:30:57 -0700838 phy->state = OTG_STATE_A_HOST;
Jack Pham5ca279b2012-05-14 18:42:54 -0700839
840 /* ensure hardware is not in low power mode */
Pavankumar Kondetie618bf82012-11-28 21:12:44 +0530841 if (atomic_read(&motg->in_lpm))
842 pm_runtime_resume(phy->dev);
Vijayavardhan Vennapusaa3152032012-03-05 16:29:30 +0530843 break;
Amit Blay6fa647a2012-05-24 14:12:08 +0300844 case OTG_STATE_B_PERIPHERAL:
845 pr_debug("peripheral bus resume\n");
846 if (!(motg->caps & ALLOW_LPM_ON_DEV_SUSPEND))
847 break;
848 clear_bit(A_BUS_SUSPEND, &motg->inputs);
Pavankumar Kondetie618bf82012-11-28 21:12:44 +0530849 if (atomic_read(&motg->in_lpm))
850 queue_work(system_nrt_wq, &motg->sm_work);
Amit Blay6fa647a2012-05-24 14:12:08 +0300851 break;
Vijayavardhan Vennapusaa3152032012-03-05 16:29:30 +0530852 default:
853 break;
854 }
855 }
Pavankumar Kondeti8be99cf2011-08-04 10:48:08 +0530856 return 0;
857}
858
Manu Gautame3a39082013-06-11 10:42:56 +0530859static void msm_otg_bus_vote(struct msm_otg *motg, enum usb_bus_vote vote)
860{
861 int ret;
862 struct msm_otg_platform_data *pdata = motg->pdata;
863
864 /* Check if target allows min_vote to be same as no_vote */
865 if (vote >= pdata->bus_scale_table->num_usecases)
866 vote = USB_NO_PERF_VOTE;
867
868 if (motg->bus_perf_client) {
869 ret = msm_bus_scale_client_update_request(
870 motg->bus_perf_client, vote);
871 if (ret)
872 dev_err(motg->phy.dev, "%s: Failed to vote (%d)\n"
873 "for bus bw %d\n", __func__, vote, ret);
874 }
875}
876
Pavankumar Kondeti87c01042010-12-07 17:53:58 +0530877#define PHY_SUSPEND_TIMEOUT_USEC (500 * 1000)
Pavankumar Kondeti70187732011-02-15 09:42:34 +0530878#define PHY_RESUME_TIMEOUT_USEC (100 * 1000)
879
880#ifdef CONFIG_PM_SLEEP
Pavankumar Kondeti87c01042010-12-07 17:53:58 +0530881static int msm_otg_suspend(struct msm_otg *motg)
882{
Heikki Krogerus1d4c9292012-02-13 13:24:09 +0200883 struct usb_phy *phy = &motg->phy;
884 struct usb_bus *bus = phy->otg->host;
Pavankumar Kondeti87c01042010-12-07 17:53:58 +0530885 struct msm_otg_platform_data *pdata = motg->pdata;
886 int cnt = 0;
Pavankumar Kondeti70970b72013-05-16 13:37:24 +0530887 bool host_bus_suspend, device_bus_suspend, dcp, prop_charger;
zhenhuahb6d5edc2013-06-19 14:37:32 +0800888 bool floated_charger;
Pavankumar Kondeti4960f312011-12-06 15:46:14 +0530889 u32 phy_ctrl_val = 0, cmd_val;
Stephen Boyd30ad10b2012-03-01 14:51:04 -0800890 unsigned ret;
Rajkumar Raghupathy242565d2011-12-13 12:10:59 +0530891 u32 portsc;
Pavankumar Kondeti87c01042010-12-07 17:53:58 +0530892
893 if (atomic_read(&motg->in_lpm))
894 return 0;
895
Lena Salmanabde35d2013-04-25 15:29:43 +0300896 if (motg->pdata->delay_lpm_hndshk_on_disconnect && !msm_bam_lpm_ok())
Lena Salman05b544f2013-05-13 15:49:10 +0300897 return -EBUSY;
Lena Salmanabde35d2013-04-25 15:29:43 +0300898
Pavankumar Kondeti87c01042010-12-07 17:53:58 +0530899 disable_irq(motg->irq);
Pavankumar Kondeti2aec9f32012-06-13 09:06:03 +0530900 host_bus_suspend = !test_bit(MHL, &motg->inputs) && phy->otg->host &&
901 !test_bit(ID, &motg->inputs);
Steve Mucklef132c6c2012-06-06 18:30:57 -0700902 device_bus_suspend = phy->otg->gadget && test_bit(ID, &motg->inputs) &&
Amit Blay6fa647a2012-05-24 14:12:08 +0300903 test_bit(A_BUS_SUSPEND, &motg->inputs) &&
904 motg->caps & ALLOW_LPM_ON_DEV_SUSPEND;
Pavankumar Kondeti283146f2012-01-12 12:51:19 +0530905 dcp = motg->chg_type == USB_DCP_CHARGER;
Pavankumar Kondeti70970b72013-05-16 13:37:24 +0530906 prop_charger = motg->chg_type == USB_PROPRIETARY_CHARGER;
zhenhuahb6d5edc2013-06-19 14:37:32 +0800907 floated_charger = motg->chg_type == USB_FLOATED_CHARGER;
Jack Pham502bea32012-08-13 15:34:20 -0700908
Pavankumar Kondeticfe05392012-10-22 13:21:19 +0530909 /*
910 * Abort suspend when,
911 * 1. charging detection in progress due to cable plug-in
912 * 2. host mode activation in progress due to Micro-A cable insertion
913 */
914
915 if ((test_bit(B_SESS_VLD, &motg->inputs) && !device_bus_suspend &&
zhenhuahb6d5edc2013-06-19 14:37:32 +0800916 !dcp && !prop_charger && !floated_charger) ||
917 test_bit(A_BUS_REQ, &motg->inputs)) {
Jack Pham502bea32012-08-13 15:34:20 -0700918 enable_irq(motg->irq);
919 return -EBUSY;
920 }
921
Pavankumar Kondeti87c01042010-12-07 17:53:58 +0530922 /*
Pavankumar Kondeti04aebcb2011-05-04 10:19:49 +0530923 * Chipidea 45-nm PHY suspend sequence:
924 *
Pavankumar Kondeti87c01042010-12-07 17:53:58 +0530925 * Interrupt Latch Register auto-clear feature is not present
926 * in all PHY versions. Latch register is clear on read type.
927 * Clear latch register to avoid spurious wakeup from
928 * low power mode (LPM).
Pavankumar Kondeti04aebcb2011-05-04 10:19:49 +0530929 *
Pavankumar Kondeti87c01042010-12-07 17:53:58 +0530930 * PHY comparators are disabled when PHY enters into low power
931 * mode (LPM). Keep PHY comparators ON in LPM only when we expect
932 * VBUS/Id notifications from USB PHY. Otherwise turn off USB
933 * PHY comparators. This save significant amount of power.
Pavankumar Kondeti04aebcb2011-05-04 10:19:49 +0530934 *
Pavankumar Kondeti87c01042010-12-07 17:53:58 +0530935 * PLL is not turned off when PHY enters into low power mode (LPM).
936 * Disable PLL for maximum power savings.
937 */
Pavankumar Kondeti04aebcb2011-05-04 10:19:49 +0530938
939 if (motg->pdata->phy_type == CI_45NM_INTEGRATED_PHY) {
Heikki Krogerus1d4c9292012-02-13 13:24:09 +0200940 ulpi_read(phy, 0x14);
Pavankumar Kondeti04aebcb2011-05-04 10:19:49 +0530941 if (pdata->otg_control == OTG_PHY_CONTROL)
Heikki Krogerus1d4c9292012-02-13 13:24:09 +0200942 ulpi_write(phy, 0x01, 0x30);
943 ulpi_write(phy, 0x08, 0x09);
Pavankumar Kondeti04aebcb2011-05-04 10:19:49 +0530944 }
Pavankumar Kondeti87c01042010-12-07 17:53:58 +0530945
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700946
Rajkumar Raghupathy242565d2011-12-13 12:10:59 +0530947 /* Set the PHCD bit, only if it is not set by the controller.
Pavankumar Kondeti87c01042010-12-07 17:53:58 +0530948 * PHY may take some time or even fail to enter into low power
949 * mode (LPM). Hence poll for 500 msec and reset the PHY and link
950 * in failure case.
951 */
Rajkumar Raghupathy242565d2011-12-13 12:10:59 +0530952 portsc = readl_relaxed(USB_PORTSC);
953 if (!(portsc & PORTSC_PHCD)) {
954 writel_relaxed(portsc | PORTSC_PHCD,
955 USB_PORTSC);
956 while (cnt < PHY_SUSPEND_TIMEOUT_USEC) {
957 if (readl_relaxed(USB_PORTSC) & PORTSC_PHCD)
958 break;
959 udelay(1);
960 cnt++;
961 }
Pavankumar Kondeti87c01042010-12-07 17:53:58 +0530962 }
963
964 if (cnt >= PHY_SUSPEND_TIMEOUT_USEC) {
Heikki Krogerus1d4c9292012-02-13 13:24:09 +0200965 dev_err(phy->dev, "Unable to suspend PHY\n");
966 msm_otg_reset(phy);
Pavankumar Kondeti87c01042010-12-07 17:53:58 +0530967 enable_irq(motg->irq);
968 return -ETIMEDOUT;
969 }
970
971 /*
972 * PHY has capability to generate interrupt asynchronously in low
973 * power mode (LPM). This interrupt is level triggered. So USB IRQ
974 * line must be disabled till async interrupt enable bit is cleared
975 * in USBCMD register. Assert STP (ULPI interface STOP signal) to
976 * block data communication from PHY.
Pavankumar Kondeti6be675f2012-04-16 13:29:24 +0530977 *
978 * PHY retention mode is disallowed while entering to LPM with wall
979 * charger connected. But PHY is put into suspend mode. Hence
980 * enable asynchronous interrupt to detect charger disconnection when
981 * PMIC notifications are unavailable.
Pavankumar Kondeti87c01042010-12-07 17:53:58 +0530982 */
Pavankumar Kondeti4960f312011-12-06 15:46:14 +0530983 cmd_val = readl_relaxed(USB_USBCMD);
Amit Blay6fa647a2012-05-24 14:12:08 +0300984 if (host_bus_suspend || device_bus_suspend ||
Pavankumar Kondeti70970b72013-05-16 13:37:24 +0530985 (motg->pdata->otg_control == OTG_PHY_CONTROL))
Pavankumar Kondeti4960f312011-12-06 15:46:14 +0530986 cmd_val |= ASYNC_INTR_CTRL | ULPI_STP_CTRL;
987 else
988 cmd_val |= ULPI_STP_CTRL;
989 writel_relaxed(cmd_val, USB_USBCMD);
Pavankumar Kondeti87c01042010-12-07 17:53:58 +0530990
Pavankumar Kondeti283146f2012-01-12 12:51:19 +0530991 /*
992 * BC1.2 spec mandates PD to enable VDP_SRC when charging from DCP.
993 * PHY retention and collapse can not happen with VDP_SRC enabled.
994 */
Vijayavardhan Vennapusa2239b2b2013-06-28 13:16:29 +0530995 if (motg->caps & ALLOW_PHY_RETENTION && !device_bus_suspend && !dcp &&
996 (!host_bus_suspend || motg->caps & ALLOW_HOST_PHY_RETENTION)) {
Amit Blay58b31472011-11-18 09:39:39 +0200997 phy_ctrl_val = readl_relaxed(USB_PHY_CTRL);
Vijayavardhan Vennapusa9ab6f972012-10-11 19:18:55 +0530998 if (motg->pdata->otg_control == OTG_PHY_CONTROL) {
Amit Blay58b31472011-11-18 09:39:39 +0200999 /* Enable PHY HV interrupts to wake MPM/Link */
Vijayavardhan Vennapusa9ab6f972012-10-11 19:18:55 +05301000 if ((motg->pdata->mode == USB_OTG) ||
1001 (motg->pdata->mode == USB_HOST))
1002 phy_ctrl_val |= (PHY_IDHV_INTEN |
1003 PHY_OTGSESSVLDHV_INTEN);
1004 else
1005 phy_ctrl_val |= PHY_OTGSESSVLDHV_INTEN;
1006 }
Vijayavardhan Vennapusa2239b2b2013-06-28 13:16:29 +05301007 if (host_bus_suspend)
1008 phy_ctrl_val |= PHY_CLAMP_DPDMSE_EN;
Amit Blay58b31472011-11-18 09:39:39 +02001009 writel_relaxed(phy_ctrl_val & ~PHY_RETEN, USB_PHY_CTRL);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001010 motg->lpm_flags |= PHY_RETENTIONED;
Pavankumar Kondeti04aebcb2011-05-04 10:19:49 +05301011 }
1012
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001013 /* Ensure that above operation is completed before turning off clocks */
1014 mb();
Ido Shayevitzc5c0f572012-07-31 13:58:45 +03001015 /* Consider clocks on workaround flag only in case of bus suspend */
1016 if (!(phy->state == OTG_STATE_B_PERIPHERAL &&
1017 test_bit(A_BUS_SUSPEND, &motg->inputs)) ||
1018 !motg->pdata->core_clk_always_on_workaround) {
Amit Blay9b6e58b2012-06-18 13:12:49 +03001019 clk_disable_unprepare(motg->pclk);
1020 clk_disable_unprepare(motg->core_clk);
Ido Shayevitzc5c0f572012-07-31 13:58:45 +03001021 motg->lpm_flags |= CLOCKS_DOWN;
Amit Blay9b6e58b2012-06-18 13:12:49 +03001022 }
Pavankumar Kondeti87c01042010-12-07 17:53:58 +05301023
Anji jonnala7da3f262011-12-02 17:22:14 -08001024 /* usb phy no more require TCXO clock, hence vote for TCXO disable */
Vijayavardhan Vennapusa2239b2b2013-06-28 13:16:29 +05301025 if (!host_bus_suspend || (motg->caps & ALLOW_HOST_PHY_RETENTION)) {
Vijayavardhan Vennapusa0cab6172013-02-20 19:51:15 +05301026 if (!IS_ERR(motg->xo_clk)) {
1027 clk_disable_unprepare(motg->xo_clk);
Vijayavardhan Vennapusabbdd6082012-06-06 14:14:25 +05301028 motg->lpm_flags |= XO_SHUTDOWN;
Vijayavardhan Vennapusa0cab6172013-02-20 19:51:15 +05301029 } else {
1030 ret = msm_xo_mode_vote(motg->xo_handle,
1031 MSM_XO_MODE_OFF);
1032 if (ret)
1033 dev_err(phy->dev, "%s fail to devote XO %d\n",
1034 __func__, ret);
1035 else
1036 motg->lpm_flags |= XO_SHUTDOWN;
1037 }
Vijayavardhan Vennapusabbdd6082012-06-06 14:14:25 +05301038 }
Anji jonnala7da3f262011-12-02 17:22:14 -08001039
Pavankumar Kondeti283146f2012-01-12 12:51:19 +05301040 if (motg->caps & ALLOW_PHY_POWER_COLLAPSE &&
1041 !host_bus_suspend && !dcp) {
Amit Blay81801aa2012-09-19 12:08:12 +02001042 msm_hsusb_ldo_enable(motg, USB_PHY_REG_OFF);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001043 motg->lpm_flags |= PHY_PWR_COLLAPSED;
Amit Blay81801aa2012-09-19 12:08:12 +02001044 } else if (motg->caps & ALLOW_PHY_REGULATORS_LPM &&
1045 !host_bus_suspend && !device_bus_suspend && !dcp) {
1046 msm_hsusb_ldo_enable(motg, USB_PHY_REG_LPM_ON);
1047 motg->lpm_flags |= PHY_REGULATORS_LPM;
Anji jonnala0f73cac2011-05-04 10:19:46 +05301048 }
1049
Vijayavardhan Vennapusafc464f02011-11-04 21:54:00 +05301050 if (motg->lpm_flags & PHY_RETENTIONED) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001051 msm_hsusb_config_vddcx(0);
Vijayavardhan Vennapusafc464f02011-11-04 21:54:00 +05301052 msm_hsusb_mhl_switch_enable(motg, 0);
1053 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001054
Steve Mucklef132c6c2012-06-06 18:30:57 -07001055 if (device_may_wakeup(phy->dev)) {
Manu Gautamf8c45642012-08-10 10:20:56 -07001056 if (motg->async_irq)
1057 enable_irq_wake(motg->async_irq);
Jack Phamd110a5a2013-02-21 13:34:48 -08001058 else
1059 enable_irq_wake(motg->irq);
1060
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001061 if (motg->pdata->pmic_id_irq)
1062 enable_irq_wake(motg->pdata->pmic_id_irq);
Jack Pham87f202f2012-08-06 00:24:22 -07001063 if (pdata->otg_control == OTG_PHY_CONTROL &&
1064 pdata->mpm_otgsessvld_int)
1065 msm_mpm_set_pin_wake(pdata->mpm_otgsessvld_int, 1);
Vijayavardhan Vennapusa2239b2b2013-06-28 13:16:29 +05301066 if (host_bus_suspend && pdata->mpm_dpshv_int)
1067 msm_mpm_set_pin_wake(pdata->mpm_dpshv_int, 1);
1068 if (host_bus_suspend && pdata->mpm_dmshv_int)
1069 msm_mpm_set_pin_wake(pdata->mpm_dmshv_int, 1);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001070 }
Pavankumar Kondeti87c01042010-12-07 17:53:58 +05301071 if (bus)
1072 clear_bit(HCD_FLAG_HW_ACCESSIBLE, &(bus_to_hcd(bus))->flags);
1073
Manu Gautame3a39082013-06-11 10:42:56 +05301074 msm_otg_bus_vote(motg, USB_NO_PERF_VOTE);
1075
Vijayavardhan Vennapusa2239b2b2013-06-28 13:16:29 +05301076 motg->host_bus_suspend = host_bus_suspend;
Pavankumar Kondeti87c01042010-12-07 17:53:58 +05301077 atomic_set(&motg->in_lpm, 1);
Manu Gautamf8c45642012-08-10 10:20:56 -07001078 /* Enable ASYNC IRQ (if present) during LPM */
1079 if (motg->async_irq)
1080 enable_irq(motg->async_irq);
Pavankumar Kondeti87c01042010-12-07 17:53:58 +05301081 enable_irq(motg->irq);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001082 wake_unlock(&motg->wlock);
Pavankumar Kondeti87c01042010-12-07 17:53:58 +05301083
Heikki Krogerus1d4c9292012-02-13 13:24:09 +02001084 dev_info(phy->dev, "USB in low power mode\n");
Pavankumar Kondeti87c01042010-12-07 17:53:58 +05301085
1086 return 0;
1087}
1088
Pavankumar Kondeti87c01042010-12-07 17:53:58 +05301089static int msm_otg_resume(struct msm_otg *motg)
1090{
Heikki Krogerus1d4c9292012-02-13 13:24:09 +02001091 struct usb_phy *phy = &motg->phy;
1092 struct usb_bus *bus = phy->otg->host;
Jack Pham87f202f2012-08-06 00:24:22 -07001093 struct msm_otg_platform_data *pdata = motg->pdata;
Pavankumar Kondeti87c01042010-12-07 17:53:58 +05301094 int cnt = 0;
1095 unsigned temp;
Amit Blay58b31472011-11-18 09:39:39 +02001096 u32 phy_ctrl_val = 0;
Anji jonnala7da3f262011-12-02 17:22:14 -08001097 unsigned ret;
Pavankumar Kondeti87c01042010-12-07 17:53:58 +05301098
1099 if (!atomic_read(&motg->in_lpm))
1100 return 0;
1101
Jack Pham8978b892012-10-17 16:31:39 -07001102 disable_irq(motg->irq);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001103 wake_lock(&motg->wlock);
Anji jonnala0f73cac2011-05-04 10:19:46 +05301104
Manu Gautame3a39082013-06-11 10:42:56 +05301105 /* Some platforms require BUS vote to enable/disable clocks */
1106 msm_otg_bus_vote(motg, USB_MIN_PERF_VOTE);
1107
Anji jonnala7da3f262011-12-02 17:22:14 -08001108 /* Vote for TCXO when waking up the phy */
Vijayavardhan Vennapusabbdd6082012-06-06 14:14:25 +05301109 if (motg->lpm_flags & XO_SHUTDOWN) {
Vijayavardhan Vennapusa0cab6172013-02-20 19:51:15 +05301110 if (!IS_ERR(motg->xo_clk)) {
1111 clk_prepare_enable(motg->xo_clk);
1112 } else {
1113 ret = msm_xo_mode_vote(motg->xo_handle, MSM_XO_MODE_ON);
1114 if (ret)
1115 dev_err(phy->dev, "%s fail to vote for XO %d\n",
1116 __func__, ret);
1117 }
Vijayavardhan Vennapusabbdd6082012-06-06 14:14:25 +05301118 motg->lpm_flags &= ~XO_SHUTDOWN;
1119 }
Pavankumar Kondeti87c01042010-12-07 17:53:58 +05301120
Ido Shayevitzc5c0f572012-07-31 13:58:45 +03001121 if (motg->lpm_flags & CLOCKS_DOWN) {
Amit Blay9b6e58b2012-06-18 13:12:49 +03001122 clk_prepare_enable(motg->core_clk);
1123 clk_prepare_enable(motg->pclk);
Ido Shayevitzc5c0f572012-07-31 13:58:45 +03001124 motg->lpm_flags &= ~CLOCKS_DOWN;
Amit Blay9b6e58b2012-06-18 13:12:49 +03001125 }
Pavankumar Kondeti87c01042010-12-07 17:53:58 +05301126
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001127 if (motg->lpm_flags & PHY_PWR_COLLAPSED) {
Amit Blay81801aa2012-09-19 12:08:12 +02001128 msm_hsusb_ldo_enable(motg, USB_PHY_REG_ON);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001129 motg->lpm_flags &= ~PHY_PWR_COLLAPSED;
Amit Blay81801aa2012-09-19 12:08:12 +02001130 } else if (motg->lpm_flags & PHY_REGULATORS_LPM) {
1131 msm_hsusb_ldo_enable(motg, USB_PHY_REG_LPM_OFF);
1132 motg->lpm_flags &= ~PHY_REGULATORS_LPM;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001133 }
1134
1135 if (motg->lpm_flags & PHY_RETENTIONED) {
Vijayavardhan Vennapusafc464f02011-11-04 21:54:00 +05301136 msm_hsusb_mhl_switch_enable(motg, 1);
Pavankumar Kondeti04aebcb2011-05-04 10:19:49 +05301137 msm_hsusb_config_vddcx(1);
Amit Blay58b31472011-11-18 09:39:39 +02001138 phy_ctrl_val = readl_relaxed(USB_PHY_CTRL);
1139 phy_ctrl_val |= PHY_RETEN;
1140 if (motg->pdata->otg_control == OTG_PHY_CONTROL)
1141 /* Disable PHY HV interrupts */
1142 phy_ctrl_val &=
1143 ~(PHY_IDHV_INTEN | PHY_OTGSESSVLDHV_INTEN);
Vijayavardhan Vennapusa2239b2b2013-06-28 13:16:29 +05301144 phy_ctrl_val &= ~(PHY_CLAMP_DPDMSE_EN);
Amit Blay58b31472011-11-18 09:39:39 +02001145 writel_relaxed(phy_ctrl_val, USB_PHY_CTRL);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001146 motg->lpm_flags &= ~PHY_RETENTIONED;
Pavankumar Kondeti04aebcb2011-05-04 10:19:49 +05301147 }
1148
Pavankumar Kondeti87c01042010-12-07 17:53:58 +05301149 temp = readl(USB_USBCMD);
1150 temp &= ~ASYNC_INTR_CTRL;
1151 temp &= ~ULPI_STP_CTRL;
1152 writel(temp, USB_USBCMD);
1153
1154 /*
1155 * PHY comes out of low power mode (LPM) in case of wakeup
1156 * from asynchronous interrupt.
1157 */
1158 if (!(readl(USB_PORTSC) & PORTSC_PHCD))
1159 goto skip_phy_resume;
1160
1161 writel(readl(USB_PORTSC) & ~PORTSC_PHCD, USB_PORTSC);
1162 while (cnt < PHY_RESUME_TIMEOUT_USEC) {
1163 if (!(readl(USB_PORTSC) & PORTSC_PHCD))
1164 break;
1165 udelay(1);
1166 cnt++;
1167 }
1168
1169 if (cnt >= PHY_RESUME_TIMEOUT_USEC) {
1170 /*
1171 * This is a fatal error. Reset the link and
1172 * PHY. USB state can not be restored. Re-insertion
1173 * of USB cable is the only way to get USB working.
1174 */
Heikki Krogerus1d4c9292012-02-13 13:24:09 +02001175 dev_err(phy->dev, "Unable to resume USB."
Pavankumar Kondeti87c01042010-12-07 17:53:58 +05301176 "Re-plugin the cable\n");
Heikki Krogerus1d4c9292012-02-13 13:24:09 +02001177 msm_otg_reset(phy);
Pavankumar Kondeti87c01042010-12-07 17:53:58 +05301178 }
1179
1180skip_phy_resume:
Steve Mucklef132c6c2012-06-06 18:30:57 -07001181 if (device_may_wakeup(phy->dev)) {
Manu Gautamf8c45642012-08-10 10:20:56 -07001182 if (motg->async_irq)
1183 disable_irq_wake(motg->async_irq);
Jack Phamd110a5a2013-02-21 13:34:48 -08001184 else
1185 disable_irq_wake(motg->irq);
1186
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001187 if (motg->pdata->pmic_id_irq)
1188 disable_irq_wake(motg->pdata->pmic_id_irq);
Jack Pham87f202f2012-08-06 00:24:22 -07001189 if (pdata->otg_control == OTG_PHY_CONTROL &&
1190 pdata->mpm_otgsessvld_int)
1191 msm_mpm_set_pin_wake(pdata->mpm_otgsessvld_int, 0);
Vijayavardhan Vennapusa2239b2b2013-06-28 13:16:29 +05301192 if (motg->host_bus_suspend && pdata->mpm_dpshv_int)
1193 msm_mpm_set_pin_wake(pdata->mpm_dpshv_int, 0);
1194 if (motg->host_bus_suspend && pdata->mpm_dmshv_int)
1195 msm_mpm_set_pin_wake(pdata->mpm_dmshv_int, 0);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001196 }
Pavankumar Kondeti87c01042010-12-07 17:53:58 +05301197 if (bus)
1198 set_bit(HCD_FLAG_HW_ACCESSIBLE, &(bus_to_hcd(bus))->flags);
1199
Pavankumar Kondeti2ce2c3a2011-05-02 11:56:33 +05301200 atomic_set(&motg->in_lpm, 0);
1201
Pavankumar Kondeti87c01042010-12-07 17:53:58 +05301202 if (motg->async_int) {
Manu Gautamf8c45642012-08-10 10:20:56 -07001203 /* Match the disable_irq call from ISR */
1204 enable_irq(motg->async_int);
Pavankumar Kondeti87c01042010-12-07 17:53:58 +05301205 motg->async_int = 0;
Pavankumar Kondeti87c01042010-12-07 17:53:58 +05301206 }
Jack Pham8978b892012-10-17 16:31:39 -07001207 enable_irq(motg->irq);
Pavankumar Kondeti87c01042010-12-07 17:53:58 +05301208
Manu Gautamf8c45642012-08-10 10:20:56 -07001209 /* If ASYNC IRQ is present then keep it enabled only during LPM */
1210 if (motg->async_irq)
1211 disable_irq(motg->async_irq);
1212
Heikki Krogerus1d4c9292012-02-13 13:24:09 +02001213 dev_info(phy->dev, "USB exited from low power mode\n");
Pavankumar Kondeti87c01042010-12-07 17:53:58 +05301214
1215 return 0;
1216}
Pavankumar Kondeti70187732011-02-15 09:42:34 +05301217#endif
Pavankumar Kondeti87c01042010-12-07 17:53:58 +05301218
David Keitel272ce522012-08-17 16:25:24 -07001219static void msm_otg_notify_host_mode(struct msm_otg *motg, bool host_mode)
Abhijeet Dharmapurikar5e96aaa2012-06-26 11:21:03 -07001220{
Jack Pham0c695282012-10-19 18:13:03 -07001221 if (!psy) {
David Keitel272ce522012-08-17 16:25:24 -07001222 pr_err("No USB power supply registered!\n");
1223 return;
1224 }
Sridhar Parasuram3c67a412012-09-26 09:36:22 -07001225
Jack Pham0c695282012-10-19 18:13:03 -07001226 if (legacy_power_supply) {
David Keitel272ce522012-08-17 16:25:24 -07001227 /* legacy support */
Pavankumar Kondeti811cab32012-11-09 20:51:36 +05301228 if (host_mode) {
David Keitel272ce522012-08-17 16:25:24 -07001229 power_supply_set_scope(psy, POWER_SUPPLY_SCOPE_SYSTEM);
Pavankumar Kondeti811cab32012-11-09 20:51:36 +05301230 } else {
David Keitel272ce522012-08-17 16:25:24 -07001231 power_supply_set_scope(psy, POWER_SUPPLY_SCOPE_DEVICE);
Pavankumar Kondeti811cab32012-11-09 20:51:36 +05301232 /*
1233 * VBUS comparator is disabled by PMIC charging driver
1234 * when SYSTEM scope is selected. For ID_GND->ID_A
1235 * transition, give 50 msec delay so that PMIC charger
1236 * driver detect the VBUS and ready for accepting
1237 * charging current value from USB.
1238 */
1239 if (test_bit(ID_A, &motg->inputs))
1240 msleep(50);
1241 }
David Keitel272ce522012-08-17 16:25:24 -07001242 } else {
1243 motg->host_mode = host_mode;
Jack Pham0c695282012-10-19 18:13:03 -07001244 power_supply_changed(psy);
David Keitel272ce522012-08-17 16:25:24 -07001245 }
Abhijeet Dharmapurikar5e96aaa2012-06-26 11:21:03 -07001246}
1247
David Keitel081a3e22012-04-18 12:37:07 -07001248static int msm_otg_notify_chg_type(struct msm_otg *motg)
1249{
1250 static int charger_type;
David Keitelba8f8322012-06-01 17:14:10 -07001251
David Keitel081a3e22012-04-18 12:37:07 -07001252 /*
1253 * TODO
1254 * Unify OTG driver charger types and power supply charger types
1255 */
1256 if (charger_type == motg->chg_type)
1257 return 0;
1258
1259 if (motg->chg_type == USB_SDP_CHARGER)
1260 charger_type = POWER_SUPPLY_TYPE_USB;
1261 else if (motg->chg_type == USB_CDP_CHARGER)
1262 charger_type = POWER_SUPPLY_TYPE_USB_CDP;
Pavankumar Kondeti9ec21d32012-05-07 15:50:23 +05301263 else if (motg->chg_type == USB_DCP_CHARGER ||
1264 motg->chg_type == USB_PROPRIETARY_CHARGER)
David Keitel081a3e22012-04-18 12:37:07 -07001265 charger_type = POWER_SUPPLY_TYPE_USB_DCP;
1266 else if ((motg->chg_type == USB_ACA_DOCK_CHARGER ||
1267 motg->chg_type == USB_ACA_A_CHARGER ||
1268 motg->chg_type == USB_ACA_B_CHARGER ||
1269 motg->chg_type == USB_ACA_C_CHARGER))
1270 charger_type = POWER_SUPPLY_TYPE_USB_ACA;
1271 else
Anirudh Ghayal685a6a52013-01-08 18:28:55 +05301272 charger_type = POWER_SUPPLY_TYPE_UNKNOWN;
David Keitel081a3e22012-04-18 12:37:07 -07001273
Jack Pham0c695282012-10-19 18:13:03 -07001274 if (!psy) {
David Keitelba8f8322012-06-01 17:14:10 -07001275 pr_err("No USB power supply registered!\n");
1276 return -EINVAL;
1277 }
1278
1279 pr_debug("setting usb power supply type %d\n", charger_type);
Jack Pham0c695282012-10-19 18:13:03 -07001280 power_supply_set_supply_type(psy, charger_type);
David Keitelba8f8322012-06-01 17:14:10 -07001281 return 0;
David Keitel081a3e22012-04-18 12:37:07 -07001282}
1283
Amit Blay0f7edf72012-01-15 10:11:27 +02001284static int msm_otg_notify_power_supply(struct msm_otg *motg, unsigned mA)
1285{
Jack Pham0c695282012-10-19 18:13:03 -07001286 if (!psy) {
David Keitel272ce522012-08-17 16:25:24 -07001287 dev_dbg(motg->phy.dev, "no usb power supply registered\n");
1288 goto psy_error;
David Keitelf5c5d602012-08-17 16:25:24 -07001289 }
1290
David Keitel272ce522012-08-17 16:25:24 -07001291 if (motg->cur_power == 0 && mA > 2) {
1292 /* Enable charging */
Jack Pham0c695282012-10-19 18:13:03 -07001293 if (power_supply_set_online(psy, true))
David Keitel272ce522012-08-17 16:25:24 -07001294 goto psy_error;
Jack Pham0c695282012-10-19 18:13:03 -07001295 if (power_supply_set_current_limit(psy, 1000*mA))
David Keitel272ce522012-08-17 16:25:24 -07001296 goto psy_error;
1297 } else if (motg->cur_power > 0 && (mA == 0 || mA == 2)) {
1298 /* Disable charging */
Jack Pham0c695282012-10-19 18:13:03 -07001299 if (power_supply_set_online(psy, false))
David Keitel272ce522012-08-17 16:25:24 -07001300 goto psy_error;
1301 /* Set max current limit */
Jack Pham0c695282012-10-19 18:13:03 -07001302 if (power_supply_set_current_limit(psy, 0))
David Keitel272ce522012-08-17 16:25:24 -07001303 goto psy_error;
Manu Gautamfca298c2013-06-05 15:11:54 +05301304 } else {
1305 if (power_supply_set_online(psy, true))
1306 goto psy_error;
1307 /* Current has changed (100/2 --> 500) */
1308 if (power_supply_set_current_limit(psy, 1000*mA))
1309 goto psy_error;
David Keitel272ce522012-08-17 16:25:24 -07001310 }
Manu Gautamfca298c2013-06-05 15:11:54 +05301311
Jack Pham0c695282012-10-19 18:13:03 -07001312 power_supply_changed(psy);
Amit Blay0f7edf72012-01-15 10:11:27 +02001313 return 0;
1314
David Keitel272ce522012-08-17 16:25:24 -07001315psy_error:
1316 dev_dbg(motg->phy.dev, "power supply error when setting property\n");
Amit Blay0f7edf72012-01-15 10:11:27 +02001317 return -ENXIO;
1318}
1319
Pavankumar Kondetid8608522011-05-04 10:19:47 +05301320static void msm_otg_notify_charger(struct msm_otg *motg, unsigned mA)
1321{
Steve Mucklef132c6c2012-06-06 18:30:57 -07001322 struct usb_gadget *g = motg->phy.otg->gadget;
Vijayavardhan Vennapusaa3152032012-03-05 16:29:30 +05301323
1324 if (g && g->is_a_peripheral)
1325 return;
1326
Pavankumar Kondetiaa449e12011-11-04 11:09:26 +05301327 if ((motg->chg_type == USB_ACA_DOCK_CHARGER ||
1328 motg->chg_type == USB_ACA_A_CHARGER ||
1329 motg->chg_type == USB_ACA_B_CHARGER ||
1330 motg->chg_type == USB_ACA_C_CHARGER) &&
1331 mA > IDEV_ACA_CHG_LIMIT)
1332 mA = IDEV_ACA_CHG_LIMIT;
1333
David Keitel081a3e22012-04-18 12:37:07 -07001334 if (msm_otg_notify_chg_type(motg))
Steve Mucklef132c6c2012-06-06 18:30:57 -07001335 dev_err(motg->phy.dev,
David Keitel081a3e22012-04-18 12:37:07 -07001336 "Failed notifying %d charger type to PMIC\n",
1337 motg->chg_type);
1338
Pavankumar Kondetid8608522011-05-04 10:19:47 +05301339 if (motg->cur_power == mA)
1340 return;
1341
Heikki Krogerus1d4c9292012-02-13 13:24:09 +02001342 dev_info(motg->phy.dev, "Avail curr from USB = %u\n", mA);
Amit Blay0f7edf72012-01-15 10:11:27 +02001343
1344 /*
1345 * Use Power Supply API if supported, otherwise fallback
1346 * to legacy pm8921 API.
1347 */
1348 if (msm_otg_notify_power_supply(motg, mA))
1349 pm8921_charger_vbus_draw(mA);
1350
Pavankumar Kondetid8608522011-05-04 10:19:47 +05301351 motg->cur_power = mA;
1352}
1353
Heikki Krogerus1d4c9292012-02-13 13:24:09 +02001354static int msm_otg_set_power(struct usb_phy *phy, unsigned mA)
Pavankumar Kondetid8608522011-05-04 10:19:47 +05301355{
Heikki Krogerus1d4c9292012-02-13 13:24:09 +02001356 struct msm_otg *motg = container_of(phy, struct msm_otg, phy);
Pavankumar Kondetid8608522011-05-04 10:19:47 +05301357
1358 /*
1359 * Gadget driver uses set_power method to notify about the
1360 * available current based on suspend/configured states.
1361 *
1362 * IDEV_CHG can be drawn irrespective of suspend/un-configured
1363 * states when CDP/ACA is connected.
1364 */
1365 if (motg->chg_type == USB_SDP_CHARGER)
1366 msm_otg_notify_charger(motg, mA);
1367
1368 return 0;
1369}
1370
Steve Mucklef132c6c2012-06-06 18:30:57 -07001371static void msm_otg_start_host(struct usb_otg *otg, int on)
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05301372{
Steve Mucklef132c6c2012-06-06 18:30:57 -07001373 struct msm_otg *motg = container_of(otg->phy, struct msm_otg, phy);
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05301374 struct msm_otg_platform_data *pdata = motg->pdata;
1375 struct usb_hcd *hcd;
1376
1377 if (!otg->host)
1378 return;
1379
1380 hcd = bus_to_hcd(otg->host);
1381
1382 if (on) {
Steve Mucklef132c6c2012-06-06 18:30:57 -07001383 dev_dbg(otg->phy->dev, "host on\n");
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05301384
Vijayavardhan Vennapusa03171c72012-04-26 14:44:48 +05301385 if (pdata->otg_control == OTG_PHY_CONTROL)
Steve Mucklef132c6c2012-06-06 18:30:57 -07001386 ulpi_write(otg->phy, OTG_COMP_DISABLE,
Vijayavardhan Vennapusa03171c72012-04-26 14:44:48 +05301387 ULPI_SET(ULPI_PWR_CLK_MNG_REG));
1388
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05301389 /*
1390 * Some boards have a switch cotrolled by gpio
1391 * to enable/disable internal HUB. Enable internal
1392 * HUB before kicking the host.
1393 */
1394 if (pdata->setup_gpio)
1395 pdata->setup_gpio(OTG_STATE_A_HOST);
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05301396 usb_add_hcd(hcd, hcd->irq, IRQF_SHARED);
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05301397 } else {
Steve Mucklef132c6c2012-06-06 18:30:57 -07001398 dev_dbg(otg->phy->dev, "host off\n");
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05301399
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05301400 usb_remove_hcd(hcd);
Pavankumar Kondetiaa449e12011-11-04 11:09:26 +05301401 /* HCD core reset all bits of PORTSC. select ULPI phy */
1402 writel_relaxed(0x80000000, USB_PORTSC);
1403
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05301404 if (pdata->setup_gpio)
1405 pdata->setup_gpio(OTG_STATE_UNDEFINED);
Vijayavardhan Vennapusa03171c72012-04-26 14:44:48 +05301406
1407 if (pdata->otg_control == OTG_PHY_CONTROL)
Steve Mucklef132c6c2012-06-06 18:30:57 -07001408 ulpi_write(otg->phy, OTG_COMP_DISABLE,
Vijayavardhan Vennapusa03171c72012-04-26 14:44:48 +05301409 ULPI_CLR(ULPI_PWR_CLK_MNG_REG));
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05301410 }
1411}
1412
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001413static int msm_otg_usbdev_notify(struct notifier_block *self,
1414 unsigned long action, void *priv)
1415{
1416 struct msm_otg *motg = container_of(self, struct msm_otg, usbdev_nb);
Steve Mucklef132c6c2012-06-06 18:30:57 -07001417 struct usb_otg *otg = motg->phy.otg;
Pavankumar Kondetiaa449e12011-11-04 11:09:26 +05301418 struct usb_device *udev = priv;
1419
Pavankumar Kondetiaa449e12011-11-04 11:09:26 +05301420 if (action == USB_BUS_ADD || action == USB_BUS_REMOVE)
1421 goto out;
1422
Steve Mucklef132c6c2012-06-06 18:30:57 -07001423 if (udev->bus != otg->host)
Pavankumar Kondetiaa449e12011-11-04 11:09:26 +05301424 goto out;
1425 /*
1426 * Interested in devices connected directly to the root hub.
1427 * ACA dock can supply IDEV_CHG irrespective devices connected
1428 * on the accessory port.
1429 */
1430 if (!udev->parent || udev->parent->parent ||
1431 motg->chg_type == USB_ACA_DOCK_CHARGER)
1432 goto out;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001433
1434 switch (action) {
1435 case USB_DEVICE_ADD:
Vijayavardhan Vennapusaa3152032012-03-05 16:29:30 +05301436 if (aca_enabled())
1437 usb_disable_autosuspend(udev);
Steve Mucklef132c6c2012-06-06 18:30:57 -07001438 if (otg->phy->state == OTG_STATE_A_WAIT_BCON) {
Vijayavardhan Vennapusaa3152032012-03-05 16:29:30 +05301439 pr_debug("B_CONN set\n");
1440 set_bit(B_CONN, &motg->inputs);
1441 msm_otg_del_timer(motg);
Steve Mucklef132c6c2012-06-06 18:30:57 -07001442 otg->phy->state = OTG_STATE_A_HOST;
Vijayavardhan Vennapusaa3152032012-03-05 16:29:30 +05301443 /*
1444 * OTG PET: A-device must end session within
1445 * 10 sec after PET enumeration.
1446 */
1447 if (udev->quirks & USB_QUIRK_OTG_PET)
1448 msm_otg_start_timer(motg, TA_TST_MAINT,
1449 A_TST_MAINT);
1450 }
Pavankumar Kondetiaa449e12011-11-04 11:09:26 +05301451 /* fall through */
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001452 case USB_DEVICE_CONFIG:
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001453 if (udev->actconfig)
1454 motg->mA_port = udev->actconfig->desc.bMaxPower * 2;
1455 else
1456 motg->mA_port = IUNIT;
Steve Mucklef132c6c2012-06-06 18:30:57 -07001457 if (otg->phy->state == OTG_STATE_B_HOST)
Vijayavardhan Vennapusaa3152032012-03-05 16:29:30 +05301458 msm_otg_del_timer(motg);
Pavankumar Kondetiaa449e12011-11-04 11:09:26 +05301459 break;
1460 case USB_DEVICE_REMOVE:
Steve Mucklef132c6c2012-06-06 18:30:57 -07001461 if ((otg->phy->state == OTG_STATE_A_HOST) ||
1462 (otg->phy->state == OTG_STATE_A_SUSPEND)) {
Vijayavardhan Vennapusaa3152032012-03-05 16:29:30 +05301463 pr_debug("B_CONN clear\n");
1464 clear_bit(B_CONN, &motg->inputs);
1465 /*
1466 * OTG PET: A-device must end session after
1467 * PET disconnection if it is enumerated
1468 * with bcdDevice[0] = 1. USB core sets
1469 * bus->otg_vbus_off for us. clear it here.
1470 */
1471 if (udev->bus->otg_vbus_off) {
1472 udev->bus->otg_vbus_off = 0;
1473 set_bit(A_BUS_DROP, &motg->inputs);
1474 }
1475 queue_work(system_nrt_wq, &motg->sm_work);
1476 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001477 default:
1478 break;
1479 }
Pavankumar Kondetiaa449e12011-11-04 11:09:26 +05301480 if (test_bit(ID_A, &motg->inputs))
1481 msm_otg_notify_charger(motg, IDEV_ACA_CHG_MAX -
1482 motg->mA_port);
1483out:
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001484 return NOTIFY_OK;
1485}
1486
Mayank Ranae3926882011-12-26 09:47:54 +05301487static void msm_hsusb_vbus_power(struct msm_otg *motg, bool on)
1488{
1489 int ret;
1490 static bool vbus_is_on;
1491
1492 if (vbus_is_on == on)
1493 return;
1494
1495 if (motg->pdata->vbus_power) {
Mayank Rana91f597e2012-01-20 10:12:06 +05301496 ret = motg->pdata->vbus_power(on);
1497 if (!ret)
1498 vbus_is_on = on;
Mayank Ranae3926882011-12-26 09:47:54 +05301499 return;
1500 }
1501
1502 if (!vbus_otg) {
1503 pr_err("vbus_otg is NULL.");
1504 return;
1505 }
1506
Abhijeet Dharmapurikarbe054882012-01-03 20:27:07 -08001507 /*
1508 * if entering host mode tell the charger to not draw any current
Abhijeet Dharmapurikar6d941212012-03-05 10:30:56 -08001509 * from usb before turning on the boost.
1510 * if exiting host mode disable the boost before enabling to draw
1511 * current from the source.
Abhijeet Dharmapurikarbe054882012-01-03 20:27:07 -08001512 */
Mayank Ranae3926882011-12-26 09:47:54 +05301513 if (on) {
Abhijeet Dharmapurikar5e96aaa2012-06-26 11:21:03 -07001514 msm_otg_notify_host_mode(motg, on);
Mayank Ranae3926882011-12-26 09:47:54 +05301515 ret = regulator_enable(vbus_otg);
1516 if (ret) {
1517 pr_err("unable to enable vbus_otg\n");
1518 return;
1519 }
1520 vbus_is_on = true;
1521 } else {
1522 ret = regulator_disable(vbus_otg);
1523 if (ret) {
1524 pr_err("unable to disable vbus_otg\n");
1525 return;
1526 }
Abhijeet Dharmapurikar5e96aaa2012-06-26 11:21:03 -07001527 msm_otg_notify_host_mode(motg, on);
Mayank Ranae3926882011-12-26 09:47:54 +05301528 vbus_is_on = false;
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05301529 }
1530}
1531
Heikki Krogerus1d4c9292012-02-13 13:24:09 +02001532static int msm_otg_set_host(struct usb_otg *otg, struct usb_bus *host)
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05301533{
Heikki Krogerus1d4c9292012-02-13 13:24:09 +02001534 struct msm_otg *motg = container_of(otg->phy, struct msm_otg, phy);
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05301535 struct usb_hcd *hcd;
1536
1537 /*
1538 * Fail host registration if this board can support
1539 * only peripheral configuration.
1540 */
1541 if (motg->pdata->mode == USB_PERIPHERAL) {
Heikki Krogerus1d4c9292012-02-13 13:24:09 +02001542 dev_info(otg->phy->dev, "Host mode is not supported\n");
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05301543 return -ENODEV;
1544 }
1545
Mayank Ranae3926882011-12-26 09:47:54 +05301546 if (!motg->pdata->vbus_power && host) {
Steve Mucklef132c6c2012-06-06 18:30:57 -07001547 vbus_otg = devm_regulator_get(motg->phy.dev, "vbus_otg");
Mayank Ranae3926882011-12-26 09:47:54 +05301548 if (IS_ERR(vbus_otg)) {
1549 pr_err("Unable to get vbus_otg\n");
Manu Gautam139a8132013-06-04 16:46:50 +05301550 return PTR_ERR(vbus_otg);
Mayank Ranae3926882011-12-26 09:47:54 +05301551 }
1552 }
1553
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05301554 if (!host) {
Heikki Krogerus1d4c9292012-02-13 13:24:09 +02001555 if (otg->phy->state == OTG_STATE_A_HOST) {
1556 pm_runtime_get_sync(otg->phy->dev);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001557 usb_unregister_notify(&motg->usbdev_nb);
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05301558 msm_otg_start_host(otg, 0);
Mayank Ranae3926882011-12-26 09:47:54 +05301559 msm_hsusb_vbus_power(motg, 0);
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05301560 otg->host = NULL;
Heikki Krogerus1d4c9292012-02-13 13:24:09 +02001561 otg->phy->state = OTG_STATE_UNDEFINED;
Vijayavardhan Vennapusaa3152032012-03-05 16:29:30 +05301562 queue_work(system_nrt_wq, &motg->sm_work);
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05301563 } else {
1564 otg->host = NULL;
1565 }
1566
1567 return 0;
1568 }
1569
1570 hcd = bus_to_hcd(host);
1571 hcd->power_budget = motg->pdata->power_budget;
1572
Vijayavardhan Vennapusaa3152032012-03-05 16:29:30 +05301573#ifdef CONFIG_USB_OTG
1574 host->otg_port = 1;
1575#endif
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001576 motg->usbdev_nb.notifier_call = msm_otg_usbdev_notify;
1577 usb_register_notify(&motg->usbdev_nb);
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05301578 otg->host = host;
Heikki Krogerus1d4c9292012-02-13 13:24:09 +02001579 dev_dbg(otg->phy->dev, "host driver registered w/ tranceiver\n");
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05301580
1581 /*
1582 * Kick the state machine work, if peripheral is not supported
1583 * or peripheral is already registered with us.
1584 */
Pavankumar Kondeti87c01042010-12-07 17:53:58 +05301585 if (motg->pdata->mode == USB_HOST || otg->gadget) {
Heikki Krogerus1d4c9292012-02-13 13:24:09 +02001586 pm_runtime_get_sync(otg->phy->dev);
Vijayavardhan Vennapusaa3152032012-03-05 16:29:30 +05301587 queue_work(system_nrt_wq, &motg->sm_work);
Pavankumar Kondeti87c01042010-12-07 17:53:58 +05301588 }
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05301589
1590 return 0;
1591}
1592
Steve Mucklef132c6c2012-06-06 18:30:57 -07001593static void msm_otg_start_peripheral(struct usb_otg *otg, int on)
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05301594{
Steve Mucklef132c6c2012-06-06 18:30:57 -07001595 struct msm_otg *motg = container_of(otg->phy, struct msm_otg, phy);
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05301596 struct msm_otg_platform_data *pdata = motg->pdata;
1597
1598 if (!otg->gadget)
1599 return;
1600
1601 if (on) {
Steve Mucklef132c6c2012-06-06 18:30:57 -07001602 dev_dbg(otg->phy->dev, "gadget on\n");
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05301603 /*
1604 * Some boards have a switch cotrolled by gpio
1605 * to enable/disable internal HUB. Disable internal
1606 * HUB before kicking the gadget.
1607 */
1608 if (pdata->setup_gpio)
1609 pdata->setup_gpio(OTG_STATE_B_PERIPHERAL);
Ofir Cohen94213a72012-05-03 14:26:32 +03001610
Manu Gautamcd82e9d2011-12-20 14:17:28 +05301611 /* Configure BUS performance parameters for MAX bandwidth */
Manu Gautame3a39082013-06-11 10:42:56 +05301612 if (debug_bus_voting_enabled)
1613 msm_otg_bus_vote(motg, USB_MAX_PERF_VOTE);
1614
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05301615 usb_gadget_vbus_connect(otg->gadget);
1616 } else {
Steve Mucklef132c6c2012-06-06 18:30:57 -07001617 dev_dbg(otg->phy->dev, "gadget off\n");
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05301618 usb_gadget_vbus_disconnect(otg->gadget);
Manu Gautamcd82e9d2011-12-20 14:17:28 +05301619 /* Configure BUS performance parameters to default */
Manu Gautame3a39082013-06-11 10:42:56 +05301620 msm_otg_bus_vote(motg, USB_MIN_PERF_VOTE);
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05301621 if (pdata->setup_gpio)
1622 pdata->setup_gpio(OTG_STATE_UNDEFINED);
1623 }
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05301624}
1625
Heikki Krogerus1d4c9292012-02-13 13:24:09 +02001626static int msm_otg_set_peripheral(struct usb_otg *otg,
Stephen Boyd9850acb2013-01-28 14:11:20 -08001627 struct usb_gadget *gadget)
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05301628{
Heikki Krogerus1d4c9292012-02-13 13:24:09 +02001629 struct msm_otg *motg = container_of(otg->phy, struct msm_otg, phy);
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05301630
1631 /*
1632 * Fail peripheral registration if this board can support
1633 * only host configuration.
1634 */
1635 if (motg->pdata->mode == USB_HOST) {
Heikki Krogerus1d4c9292012-02-13 13:24:09 +02001636 dev_info(otg->phy->dev, "Peripheral mode is not supported\n");
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05301637 return -ENODEV;
1638 }
1639
1640 if (!gadget) {
Heikki Krogerus1d4c9292012-02-13 13:24:09 +02001641 if (otg->phy->state == OTG_STATE_B_PERIPHERAL) {
1642 pm_runtime_get_sync(otg->phy->dev);
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05301643 msm_otg_start_peripheral(otg, 0);
1644 otg->gadget = NULL;
Heikki Krogerus1d4c9292012-02-13 13:24:09 +02001645 otg->phy->state = OTG_STATE_UNDEFINED;
Vijayavardhan Vennapusaa3152032012-03-05 16:29:30 +05301646 queue_work(system_nrt_wq, &motg->sm_work);
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05301647 } else {
1648 otg->gadget = NULL;
1649 }
1650
1651 return 0;
1652 }
1653 otg->gadget = gadget;
Heikki Krogerus1d4c9292012-02-13 13:24:09 +02001654 dev_dbg(otg->phy->dev, "peripheral driver registered w/ tranceiver\n");
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05301655
1656 /*
1657 * Kick the state machine work, if host is not supported
1658 * or host is already registered with us.
1659 */
Pavankumar Kondeti87c01042010-12-07 17:53:58 +05301660 if (motg->pdata->mode == USB_PERIPHERAL || otg->host) {
Heikki Krogerus1d4c9292012-02-13 13:24:09 +02001661 pm_runtime_get_sync(otg->phy->dev);
Vijayavardhan Vennapusaa3152032012-03-05 16:29:30 +05301662 queue_work(system_nrt_wq, &motg->sm_work);
Pavankumar Kondeti87c01042010-12-07 17:53:58 +05301663 }
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05301664
1665 return 0;
1666}
1667
Pavankumar Kondetibecab5b2012-11-06 16:45:10 +05301668static bool msm_otg_read_pmic_id_state(struct msm_otg *motg)
1669{
1670 unsigned long flags;
1671 int id;
1672
1673 if (!motg->pdata->pmic_id_irq)
1674 return -ENODEV;
1675
1676 local_irq_save(flags);
1677 id = irq_read_line(motg->pdata->pmic_id_irq);
1678 local_irq_restore(flags);
1679
1680 /*
1681 * If we can not read ID line state for some reason, treat
1682 * it as float. This would prevent MHL discovery and kicking
1683 * host mode unnecessarily.
1684 */
1685 return !!id;
1686}
1687
Pavankumar Kondeti2aec9f32012-06-13 09:06:03 +05301688static int msm_otg_mhl_register_callback(struct msm_otg *motg,
1689 void (*callback)(int on))
1690{
1691 struct usb_phy *phy = &motg->phy;
1692 int ret;
1693
Manoj Raoa7bddd12012-08-27 20:36:45 -07001694 if (!motg->pdata->mhl_enable) {
1695 dev_dbg(phy->dev, "MHL feature not enabled\n");
1696 return -ENODEV;
1697 }
1698
Pavankumar Kondeti2aec9f32012-06-13 09:06:03 +05301699 if (motg->pdata->otg_control != OTG_PMIC_CONTROL ||
1700 !motg->pdata->pmic_id_irq) {
1701 dev_dbg(phy->dev, "MHL can not be supported without PMIC Id\n");
1702 return -ENODEV;
1703 }
1704
1705 if (!motg->pdata->mhl_dev_name) {
1706 dev_dbg(phy->dev, "MHL device name does not exist.\n");
1707 return -ENODEV;
1708 }
1709
1710 if (callback)
1711 ret = mhl_register_callback(motg->pdata->mhl_dev_name,
1712 callback);
1713 else
1714 ret = mhl_unregister_callback(motg->pdata->mhl_dev_name);
1715
1716 if (ret)
1717 dev_dbg(phy->dev, "mhl_register_callback(%s) return error=%d\n",
1718 motg->pdata->mhl_dev_name, ret);
1719 else
1720 motg->mhl_enabled = true;
1721
1722 return ret;
1723}
1724
1725static void msm_otg_mhl_notify_online(int on)
1726{
1727 struct msm_otg *motg = the_msm_otg;
1728 struct usb_phy *phy = &motg->phy;
1729 bool queue = false;
1730
1731 dev_dbg(phy->dev, "notify MHL %s%s\n", on ? "" : "dis", "connected");
1732
1733 if (on) {
1734 set_bit(MHL, &motg->inputs);
1735 } else {
1736 clear_bit(MHL, &motg->inputs);
1737 queue = true;
1738 }
1739
1740 if (queue && phy->state != OTG_STATE_UNDEFINED)
1741 schedule_work(&motg->sm_work);
1742}
1743
1744static bool msm_otg_is_mhl(struct msm_otg *motg)
1745{
1746 struct usb_phy *phy = &motg->phy;
1747 int is_mhl, ret;
1748
1749 ret = mhl_device_discovery(motg->pdata->mhl_dev_name, &is_mhl);
1750 if (ret || is_mhl != MHL_DISCOVERY_RESULT_MHL) {
1751 /*
1752 * MHL driver calls our callback saying that MHL connected
1753 * if RID_GND is detected. But at later part of discovery
1754 * it may figure out MHL is not connected and returns
1755 * false. Hence clear MHL input here.
1756 */
1757 clear_bit(MHL, &motg->inputs);
1758 dev_dbg(phy->dev, "MHL device not found\n");
1759 return false;
1760 }
1761
1762 set_bit(MHL, &motg->inputs);
1763 dev_dbg(phy->dev, "MHL device found\n");
1764 return true;
1765}
1766
1767static bool msm_chg_mhl_detect(struct msm_otg *motg)
1768{
1769 bool ret, id;
Pavankumar Kondeti2aec9f32012-06-13 09:06:03 +05301770
1771 if (!motg->mhl_enabled)
1772 return false;
1773
Pavankumar Kondetibecab5b2012-11-06 16:45:10 +05301774 id = msm_otg_read_pmic_id_state(motg);
Pavankumar Kondeti2aec9f32012-06-13 09:06:03 +05301775
1776 if (id)
1777 return false;
1778
1779 mhl_det_in_progress = true;
1780 ret = msm_otg_is_mhl(motg);
1781 mhl_det_in_progress = false;
1782
1783 return ret;
1784}
1785
Pavankumar Kondeti458d8792012-09-28 14:45:18 +05301786static void msm_otg_chg_check_timer_func(unsigned long data)
1787{
1788 struct msm_otg *motg = (struct msm_otg *) data;
1789 struct usb_otg *otg = motg->phy.otg;
1790
1791 if (atomic_read(&motg->in_lpm) ||
1792 !test_bit(B_SESS_VLD, &motg->inputs) ||
1793 otg->phy->state != OTG_STATE_B_PERIPHERAL ||
1794 otg->gadget->speed != USB_SPEED_UNKNOWN) {
1795 dev_dbg(otg->phy->dev, "Nothing to do in chg_check_timer\n");
1796 return;
1797 }
1798
1799 if ((readl_relaxed(USB_PORTSC) & PORTSC_LS) == PORTSC_LS) {
1800 dev_dbg(otg->phy->dev, "DCP is detected as SDP\n");
1801 set_bit(B_FALSE_SDP, &motg->inputs);
1802 queue_work(system_nrt_wq, &motg->sm_work);
1803 }
1804}
1805
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001806static bool msm_chg_aca_detect(struct msm_otg *motg)
1807{
Steve Mucklef132c6c2012-06-06 18:30:57 -07001808 struct usb_phy *phy = &motg->phy;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001809 u32 int_sts;
1810 bool ret = false;
1811
Pavankumar Kondetiaa449e12011-11-04 11:09:26 +05301812 if (!aca_enabled())
1813 goto out;
1814
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001815 if (motg->pdata->phy_type == CI_45NM_INTEGRATED_PHY)
1816 goto out;
1817
Steve Mucklef132c6c2012-06-06 18:30:57 -07001818 int_sts = ulpi_read(phy, 0x87);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001819 switch (int_sts & 0x1C) {
1820 case 0x08:
1821 if (!test_and_set_bit(ID_A, &motg->inputs)) {
Steve Mucklef132c6c2012-06-06 18:30:57 -07001822 dev_dbg(phy->dev, "ID_A\n");
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001823 motg->chg_type = USB_ACA_A_CHARGER;
1824 motg->chg_state = USB_CHG_STATE_DETECTED;
1825 clear_bit(ID_B, &motg->inputs);
1826 clear_bit(ID_C, &motg->inputs);
Pavankumar Kondetiaa449e12011-11-04 11:09:26 +05301827 set_bit(ID, &motg->inputs);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001828 ret = true;
1829 }
1830 break;
1831 case 0x0C:
1832 if (!test_and_set_bit(ID_B, &motg->inputs)) {
Steve Mucklef132c6c2012-06-06 18:30:57 -07001833 dev_dbg(phy->dev, "ID_B\n");
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001834 motg->chg_type = USB_ACA_B_CHARGER;
1835 motg->chg_state = USB_CHG_STATE_DETECTED;
1836 clear_bit(ID_A, &motg->inputs);
1837 clear_bit(ID_C, &motg->inputs);
Pavankumar Kondetiaa449e12011-11-04 11:09:26 +05301838 set_bit(ID, &motg->inputs);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001839 ret = true;
1840 }
1841 break;
1842 case 0x10:
1843 if (!test_and_set_bit(ID_C, &motg->inputs)) {
Steve Mucklef132c6c2012-06-06 18:30:57 -07001844 dev_dbg(phy->dev, "ID_C\n");
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001845 motg->chg_type = USB_ACA_C_CHARGER;
1846 motg->chg_state = USB_CHG_STATE_DETECTED;
1847 clear_bit(ID_A, &motg->inputs);
1848 clear_bit(ID_B, &motg->inputs);
Pavankumar Kondetiaa449e12011-11-04 11:09:26 +05301849 set_bit(ID, &motg->inputs);
1850 ret = true;
1851 }
1852 break;
1853 case 0x04:
1854 if (test_and_clear_bit(ID, &motg->inputs)) {
Steve Mucklef132c6c2012-06-06 18:30:57 -07001855 dev_dbg(phy->dev, "ID_GND\n");
Pavankumar Kondetiaa449e12011-11-04 11:09:26 +05301856 motg->chg_type = USB_INVALID_CHARGER;
1857 motg->chg_state = USB_CHG_STATE_UNDEFINED;
1858 clear_bit(ID_A, &motg->inputs);
1859 clear_bit(ID_B, &motg->inputs);
1860 clear_bit(ID_C, &motg->inputs);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001861 ret = true;
1862 }
1863 break;
1864 default:
1865 ret = test_and_clear_bit(ID_A, &motg->inputs) |
1866 test_and_clear_bit(ID_B, &motg->inputs) |
Pavankumar Kondetiaa449e12011-11-04 11:09:26 +05301867 test_and_clear_bit(ID_C, &motg->inputs) |
1868 !test_and_set_bit(ID, &motg->inputs);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001869 if (ret) {
Steve Mucklef132c6c2012-06-06 18:30:57 -07001870 dev_dbg(phy->dev, "ID A/B/C/GND is no more\n");
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001871 motg->chg_type = USB_INVALID_CHARGER;
1872 motg->chg_state = USB_CHG_STATE_UNDEFINED;
1873 }
1874 }
1875out:
1876 return ret;
1877}
1878
1879static void msm_chg_enable_aca_det(struct msm_otg *motg)
1880{
Steve Mucklef132c6c2012-06-06 18:30:57 -07001881 struct usb_phy *phy = &motg->phy;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001882
Pavankumar Kondetiaa449e12011-11-04 11:09:26 +05301883 if (!aca_enabled())
1884 return;
1885
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001886 switch (motg->pdata->phy_type) {
1887 case SNPS_28NM_INTEGRATED_PHY:
Pavankumar Kondetiaa449e12011-11-04 11:09:26 +05301888 /* Disable ID_GND in link and PHY */
1889 writel_relaxed(readl_relaxed(USB_OTGSC) & ~(OTGSC_IDPU |
1890 OTGSC_IDIE), USB_OTGSC);
Steve Mucklef132c6c2012-06-06 18:30:57 -07001891 ulpi_write(phy, 0x01, 0x0C);
1892 ulpi_write(phy, 0x10, 0x0F);
1893 ulpi_write(phy, 0x10, 0x12);
Pavankumar Kondeti446f4542012-02-01 13:57:13 +05301894 /* Disable PMIC ID pull-up */
1895 pm8xxx_usb_id_pullup(0);
Pavankumar Kondetiaa449e12011-11-04 11:09:26 +05301896 /* Enable ACA ID detection */
Steve Mucklef132c6c2012-06-06 18:30:57 -07001897 ulpi_write(phy, 0x20, 0x85);
Pavankumar Kondeti4960f312011-12-06 15:46:14 +05301898 aca_id_turned_on = true;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001899 break;
1900 default:
1901 break;
1902 }
1903}
1904
1905static void msm_chg_enable_aca_intr(struct msm_otg *motg)
1906{
Steve Mucklef132c6c2012-06-06 18:30:57 -07001907 struct usb_phy *phy = &motg->phy;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001908
Pavankumar Kondetiaa449e12011-11-04 11:09:26 +05301909 if (!aca_enabled())
1910 return;
1911
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001912 switch (motg->pdata->phy_type) {
1913 case SNPS_28NM_INTEGRATED_PHY:
Pavankumar Kondetiaa449e12011-11-04 11:09:26 +05301914 /* Enable ACA Detection interrupt (on any RID change) */
Steve Mucklef132c6c2012-06-06 18:30:57 -07001915 ulpi_write(phy, 0x01, 0x94);
Pavankumar Kondetiaa449e12011-11-04 11:09:26 +05301916 break;
1917 default:
1918 break;
1919 }
1920}
1921
1922static void msm_chg_disable_aca_intr(struct msm_otg *motg)
1923{
Steve Mucklef132c6c2012-06-06 18:30:57 -07001924 struct usb_phy *phy = &motg->phy;
Pavankumar Kondetiaa449e12011-11-04 11:09:26 +05301925
1926 if (!aca_enabled())
1927 return;
1928
1929 switch (motg->pdata->phy_type) {
1930 case SNPS_28NM_INTEGRATED_PHY:
Steve Mucklef132c6c2012-06-06 18:30:57 -07001931 ulpi_write(phy, 0x01, 0x95);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001932 break;
1933 default:
1934 break;
1935 }
1936}
1937
1938static bool msm_chg_check_aca_intr(struct msm_otg *motg)
1939{
Steve Mucklef132c6c2012-06-06 18:30:57 -07001940 struct usb_phy *phy = &motg->phy;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001941 bool ret = false;
1942
Pavankumar Kondetiaa449e12011-11-04 11:09:26 +05301943 if (!aca_enabled())
1944 return ret;
1945
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001946 switch (motg->pdata->phy_type) {
1947 case SNPS_28NM_INTEGRATED_PHY:
Steve Mucklef132c6c2012-06-06 18:30:57 -07001948 if (ulpi_read(phy, 0x91) & 1) {
1949 dev_dbg(phy->dev, "RID change\n");
1950 ulpi_write(phy, 0x01, 0x92);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001951 ret = msm_chg_aca_detect(motg);
1952 }
1953 default:
1954 break;
1955 }
1956 return ret;
1957}
Pavankumar Kondetiaa449e12011-11-04 11:09:26 +05301958
1959static void msm_otg_id_timer_func(unsigned long data)
1960{
1961 struct msm_otg *motg = (struct msm_otg *) data;
1962
1963 if (!aca_enabled())
1964 return;
1965
1966 if (atomic_read(&motg->in_lpm)) {
Steve Mucklef132c6c2012-06-06 18:30:57 -07001967 dev_dbg(motg->phy.dev, "timer: in lpm\n");
Pavankumar Kondetiaa449e12011-11-04 11:09:26 +05301968 return;
1969 }
1970
Steve Mucklef132c6c2012-06-06 18:30:57 -07001971 if (motg->phy.state == OTG_STATE_A_SUSPEND)
Vijayavardhan Vennapusaa3152032012-03-05 16:29:30 +05301972 goto out;
1973
Pavankumar Kondetiaa449e12011-11-04 11:09:26 +05301974 if (msm_chg_check_aca_intr(motg)) {
Steve Mucklef132c6c2012-06-06 18:30:57 -07001975 dev_dbg(motg->phy.dev, "timer: aca work\n");
Vijayavardhan Vennapusaa3152032012-03-05 16:29:30 +05301976 queue_work(system_nrt_wq, &motg->sm_work);
Pavankumar Kondetiaa449e12011-11-04 11:09:26 +05301977 }
1978
Vijayavardhan Vennapusaa3152032012-03-05 16:29:30 +05301979out:
Pavankumar Kondetiaa449e12011-11-04 11:09:26 +05301980 if (!test_bit(ID, &motg->inputs) || test_bit(ID_A, &motg->inputs))
1981 mod_timer(&motg->id_timer, ID_TIMER_FREQ);
1982}
1983
Pavankumar Kondetid8608522011-05-04 10:19:47 +05301984static bool msm_chg_check_secondary_det(struct msm_otg *motg)
1985{
Heikki Krogerus1d4c9292012-02-13 13:24:09 +02001986 struct usb_phy *phy = &motg->phy;
Pavankumar Kondetid8608522011-05-04 10:19:47 +05301987 u32 chg_det;
1988 bool ret = false;
1989
1990 switch (motg->pdata->phy_type) {
1991 case CI_45NM_INTEGRATED_PHY:
Heikki Krogerus1d4c9292012-02-13 13:24:09 +02001992 chg_det = ulpi_read(phy, 0x34);
Pavankumar Kondetid8608522011-05-04 10:19:47 +05301993 ret = chg_det & (1 << 4);
1994 break;
1995 case SNPS_28NM_INTEGRATED_PHY:
Heikki Krogerus1d4c9292012-02-13 13:24:09 +02001996 chg_det = ulpi_read(phy, 0x87);
Pavankumar Kondetid8608522011-05-04 10:19:47 +05301997 ret = chg_det & 1;
1998 break;
1999 default:
2000 break;
2001 }
2002 return ret;
2003}
2004
2005static void msm_chg_enable_secondary_det(struct msm_otg *motg)
2006{
Heikki Krogerus1d4c9292012-02-13 13:24:09 +02002007 struct usb_phy *phy = &motg->phy;
Pavankumar Kondetid8608522011-05-04 10:19:47 +05302008 u32 chg_det;
2009
2010 switch (motg->pdata->phy_type) {
2011 case CI_45NM_INTEGRATED_PHY:
Heikki Krogerus1d4c9292012-02-13 13:24:09 +02002012 chg_det = ulpi_read(phy, 0x34);
Pavankumar Kondetid8608522011-05-04 10:19:47 +05302013 /* Turn off charger block */
2014 chg_det |= ~(1 << 1);
Heikki Krogerus1d4c9292012-02-13 13:24:09 +02002015 ulpi_write(phy, chg_det, 0x34);
Pavankumar Kondetid8608522011-05-04 10:19:47 +05302016 udelay(20);
2017 /* control chg block via ULPI */
2018 chg_det &= ~(1 << 3);
Heikki Krogerus1d4c9292012-02-13 13:24:09 +02002019 ulpi_write(phy, chg_det, 0x34);
Pavankumar Kondetid8608522011-05-04 10:19:47 +05302020 /* put it in host mode for enabling D- source */
2021 chg_det &= ~(1 << 2);
Heikki Krogerus1d4c9292012-02-13 13:24:09 +02002022 ulpi_write(phy, chg_det, 0x34);
Pavankumar Kondetid8608522011-05-04 10:19:47 +05302023 /* Turn on chg detect block */
2024 chg_det &= ~(1 << 1);
Heikki Krogerus1d4c9292012-02-13 13:24:09 +02002025 ulpi_write(phy, chg_det, 0x34);
Pavankumar Kondetid8608522011-05-04 10:19:47 +05302026 udelay(20);
2027 /* enable chg detection */
2028 chg_det &= ~(1 << 0);
Heikki Krogerus1d4c9292012-02-13 13:24:09 +02002029 ulpi_write(phy, chg_det, 0x34);
Pavankumar Kondetid8608522011-05-04 10:19:47 +05302030 break;
2031 case SNPS_28NM_INTEGRATED_PHY:
2032 /*
2033 * Configure DM as current source, DP as current sink
2034 * and enable battery charging comparators.
2035 */
Heikki Krogerus1d4c9292012-02-13 13:24:09 +02002036 ulpi_write(phy, 0x8, 0x85);
2037 ulpi_write(phy, 0x2, 0x85);
2038 ulpi_write(phy, 0x1, 0x85);
Pavankumar Kondetid8608522011-05-04 10:19:47 +05302039 break;
2040 default:
2041 break;
2042 }
2043}
2044
2045static bool msm_chg_check_primary_det(struct msm_otg *motg)
2046{
Heikki Krogerus1d4c9292012-02-13 13:24:09 +02002047 struct usb_phy *phy = &motg->phy;
Pavankumar Kondetid8608522011-05-04 10:19:47 +05302048 u32 chg_det;
2049 bool ret = false;
2050
2051 switch (motg->pdata->phy_type) {
2052 case CI_45NM_INTEGRATED_PHY:
Heikki Krogerus1d4c9292012-02-13 13:24:09 +02002053 chg_det = ulpi_read(phy, 0x34);
Pavankumar Kondetid8608522011-05-04 10:19:47 +05302054 ret = chg_det & (1 << 4);
2055 break;
2056 case SNPS_28NM_INTEGRATED_PHY:
Heikki Krogerus1d4c9292012-02-13 13:24:09 +02002057 chg_det = ulpi_read(phy, 0x87);
Pavankumar Kondetid8608522011-05-04 10:19:47 +05302058 ret = chg_det & 1;
Pavankumar Kondeti9ec21d32012-05-07 15:50:23 +05302059 /* Turn off VDP_SRC */
2060 ulpi_write(phy, 0x3, 0x86);
2061 msleep(20);
Pavankumar Kondetid8608522011-05-04 10:19:47 +05302062 break;
2063 default:
2064 break;
2065 }
2066 return ret;
2067}
2068
2069static void msm_chg_enable_primary_det(struct msm_otg *motg)
2070{
Heikki Krogerus1d4c9292012-02-13 13:24:09 +02002071 struct usb_phy *phy = &motg->phy;
Pavankumar Kondetid8608522011-05-04 10:19:47 +05302072 u32 chg_det;
2073
2074 switch (motg->pdata->phy_type) {
2075 case CI_45NM_INTEGRATED_PHY:
Heikki Krogerus1d4c9292012-02-13 13:24:09 +02002076 chg_det = ulpi_read(phy, 0x34);
Pavankumar Kondetid8608522011-05-04 10:19:47 +05302077 /* enable chg detection */
2078 chg_det &= ~(1 << 0);
Heikki Krogerus1d4c9292012-02-13 13:24:09 +02002079 ulpi_write(phy, chg_det, 0x34);
Pavankumar Kondetid8608522011-05-04 10:19:47 +05302080 break;
2081 case SNPS_28NM_INTEGRATED_PHY:
2082 /*
2083 * Configure DP as current source, DM as current sink
2084 * and enable battery charging comparators.
2085 */
Heikki Krogerus1d4c9292012-02-13 13:24:09 +02002086 ulpi_write(phy, 0x2, 0x85);
2087 ulpi_write(phy, 0x1, 0x85);
Pavankumar Kondetid8608522011-05-04 10:19:47 +05302088 break;
2089 default:
2090 break;
2091 }
2092}
2093
2094static bool msm_chg_check_dcd(struct msm_otg *motg)
2095{
Heikki Krogerus1d4c9292012-02-13 13:24:09 +02002096 struct usb_phy *phy = &motg->phy;
Pavankumar Kondetid8608522011-05-04 10:19:47 +05302097 u32 line_state;
2098 bool ret = false;
2099
2100 switch (motg->pdata->phy_type) {
2101 case CI_45NM_INTEGRATED_PHY:
Heikki Krogerus1d4c9292012-02-13 13:24:09 +02002102 line_state = ulpi_read(phy, 0x15);
Pavankumar Kondetid8608522011-05-04 10:19:47 +05302103 ret = !(line_state & 1);
2104 break;
2105 case SNPS_28NM_INTEGRATED_PHY:
Heikki Krogerus1d4c9292012-02-13 13:24:09 +02002106 line_state = ulpi_read(phy, 0x87);
Pavankumar Kondetid8608522011-05-04 10:19:47 +05302107 ret = line_state & 2;
2108 break;
2109 default:
2110 break;
2111 }
2112 return ret;
2113}
2114
2115static void msm_chg_disable_dcd(struct msm_otg *motg)
2116{
Heikki Krogerus1d4c9292012-02-13 13:24:09 +02002117 struct usb_phy *phy = &motg->phy;
Pavankumar Kondetid8608522011-05-04 10:19:47 +05302118 u32 chg_det;
2119
2120 switch (motg->pdata->phy_type) {
2121 case CI_45NM_INTEGRATED_PHY:
Heikki Krogerus1d4c9292012-02-13 13:24:09 +02002122 chg_det = ulpi_read(phy, 0x34);
Pavankumar Kondetid8608522011-05-04 10:19:47 +05302123 chg_det &= ~(1 << 5);
Heikki Krogerus1d4c9292012-02-13 13:24:09 +02002124 ulpi_write(phy, chg_det, 0x34);
Pavankumar Kondetid8608522011-05-04 10:19:47 +05302125 break;
2126 case SNPS_28NM_INTEGRATED_PHY:
Heikki Krogerus1d4c9292012-02-13 13:24:09 +02002127 ulpi_write(phy, 0x10, 0x86);
Pavankumar Kondetid8608522011-05-04 10:19:47 +05302128 break;
2129 default:
2130 break;
2131 }
2132}
2133
2134static void msm_chg_enable_dcd(struct msm_otg *motg)
2135{
Heikki Krogerus1d4c9292012-02-13 13:24:09 +02002136 struct usb_phy *phy = &motg->phy;
Pavankumar Kondetid8608522011-05-04 10:19:47 +05302137 u32 chg_det;
2138
2139 switch (motg->pdata->phy_type) {
2140 case CI_45NM_INTEGRATED_PHY:
Heikki Krogerus1d4c9292012-02-13 13:24:09 +02002141 chg_det = ulpi_read(phy, 0x34);
Pavankumar Kondetid8608522011-05-04 10:19:47 +05302142 /* Turn on D+ current source */
2143 chg_det |= (1 << 5);
Heikki Krogerus1d4c9292012-02-13 13:24:09 +02002144 ulpi_write(phy, chg_det, 0x34);
Pavankumar Kondetid8608522011-05-04 10:19:47 +05302145 break;
2146 case SNPS_28NM_INTEGRATED_PHY:
2147 /* Data contact detection enable */
Heikki Krogerus1d4c9292012-02-13 13:24:09 +02002148 ulpi_write(phy, 0x10, 0x85);
Pavankumar Kondetid8608522011-05-04 10:19:47 +05302149 break;
2150 default:
2151 break;
2152 }
2153}
2154
2155static void msm_chg_block_on(struct msm_otg *motg)
2156{
Heikki Krogerus1d4c9292012-02-13 13:24:09 +02002157 struct usb_phy *phy = &motg->phy;
Pavankumar Kondetid8608522011-05-04 10:19:47 +05302158 u32 func_ctrl, chg_det;
2159
2160 /* put the controller in non-driving mode */
Heikki Krogerus1d4c9292012-02-13 13:24:09 +02002161 func_ctrl = ulpi_read(phy, ULPI_FUNC_CTRL);
Pavankumar Kondetid8608522011-05-04 10:19:47 +05302162 func_ctrl &= ~ULPI_FUNC_CTRL_OPMODE_MASK;
2163 func_ctrl |= ULPI_FUNC_CTRL_OPMODE_NONDRIVING;
Heikki Krogerus1d4c9292012-02-13 13:24:09 +02002164 ulpi_write(phy, func_ctrl, ULPI_FUNC_CTRL);
Pavankumar Kondetid8608522011-05-04 10:19:47 +05302165
2166 switch (motg->pdata->phy_type) {
2167 case CI_45NM_INTEGRATED_PHY:
Heikki Krogerus1d4c9292012-02-13 13:24:09 +02002168 chg_det = ulpi_read(phy, 0x34);
Pavankumar Kondetid8608522011-05-04 10:19:47 +05302169 /* control chg block via ULPI */
2170 chg_det &= ~(1 << 3);
Heikki Krogerus1d4c9292012-02-13 13:24:09 +02002171 ulpi_write(phy, chg_det, 0x34);
Pavankumar Kondetid8608522011-05-04 10:19:47 +05302172 /* Turn on chg detect block */
2173 chg_det &= ~(1 << 1);
Heikki Krogerus1d4c9292012-02-13 13:24:09 +02002174 ulpi_write(phy, chg_det, 0x34);
Pavankumar Kondetid8608522011-05-04 10:19:47 +05302175 udelay(20);
2176 break;
2177 case SNPS_28NM_INTEGRATED_PHY:
Pavankumar Kondeti768dcb82012-10-05 13:21:45 +05302178 /* disable DP and DM pull down resistors */
2179 ulpi_write(phy, 0x6, 0xC);
Pavankumar Kondetid8608522011-05-04 10:19:47 +05302180 /* Clear charger detecting control bits */
Steve Mucklef132c6c2012-06-06 18:30:57 -07002181 ulpi_write(phy, 0x1F, 0x86);
Pavankumar Kondetid8608522011-05-04 10:19:47 +05302182 /* Clear alt interrupt latch and enable bits */
Heikki Krogerus1d4c9292012-02-13 13:24:09 +02002183 ulpi_write(phy, 0x1F, 0x92);
2184 ulpi_write(phy, 0x1F, 0x95);
Pavankumar Kondetid8608522011-05-04 10:19:47 +05302185 udelay(100);
2186 break;
2187 default:
2188 break;
2189 }
2190}
2191
2192static void msm_chg_block_off(struct msm_otg *motg)
2193{
Heikki Krogerus1d4c9292012-02-13 13:24:09 +02002194 struct usb_phy *phy = &motg->phy;
Pavankumar Kondetid8608522011-05-04 10:19:47 +05302195 u32 func_ctrl, chg_det;
2196
2197 switch (motg->pdata->phy_type) {
2198 case CI_45NM_INTEGRATED_PHY:
Heikki Krogerus1d4c9292012-02-13 13:24:09 +02002199 chg_det = ulpi_read(phy, 0x34);
Pavankumar Kondetid8608522011-05-04 10:19:47 +05302200 /* Turn off charger block */
2201 chg_det |= ~(1 << 1);
Heikki Krogerus1d4c9292012-02-13 13:24:09 +02002202 ulpi_write(phy, chg_det, 0x34);
Pavankumar Kondetid8608522011-05-04 10:19:47 +05302203 break;
2204 case SNPS_28NM_INTEGRATED_PHY:
2205 /* Clear charger detecting control bits */
Heikki Krogerus1d4c9292012-02-13 13:24:09 +02002206 ulpi_write(phy, 0x3F, 0x86);
Pavankumar Kondetid8608522011-05-04 10:19:47 +05302207 /* Clear alt interrupt latch and enable bits */
Heikki Krogerus1d4c9292012-02-13 13:24:09 +02002208 ulpi_write(phy, 0x1F, 0x92);
2209 ulpi_write(phy, 0x1F, 0x95);
Pavankumar Kondetid8608522011-05-04 10:19:47 +05302210 break;
2211 default:
2212 break;
2213 }
2214
2215 /* put the controller in normal mode */
Heikki Krogerus1d4c9292012-02-13 13:24:09 +02002216 func_ctrl = ulpi_read(phy, ULPI_FUNC_CTRL);
Pavankumar Kondetid8608522011-05-04 10:19:47 +05302217 func_ctrl &= ~ULPI_FUNC_CTRL_OPMODE_MASK;
2218 func_ctrl |= ULPI_FUNC_CTRL_OPMODE_NORMAL;
Heikki Krogerus1d4c9292012-02-13 13:24:09 +02002219 ulpi_write(phy, func_ctrl, ULPI_FUNC_CTRL);
Pavankumar Kondetid8608522011-05-04 10:19:47 +05302220}
2221
Anji jonnalad270e2d2011-08-09 11:28:32 +05302222static const char *chg_to_string(enum usb_chg_type chg_type)
2223{
2224 switch (chg_type) {
2225 case USB_SDP_CHARGER: return "USB_SDP_CHARGER";
2226 case USB_DCP_CHARGER: return "USB_DCP_CHARGER";
2227 case USB_CDP_CHARGER: return "USB_CDP_CHARGER";
2228 case USB_ACA_A_CHARGER: return "USB_ACA_A_CHARGER";
2229 case USB_ACA_B_CHARGER: return "USB_ACA_B_CHARGER";
2230 case USB_ACA_C_CHARGER: return "USB_ACA_C_CHARGER";
2231 case USB_ACA_DOCK_CHARGER: return "USB_ACA_DOCK_CHARGER";
Pavankumar Kondeti9ec21d32012-05-07 15:50:23 +05302232 case USB_PROPRIETARY_CHARGER: return "USB_PROPRIETARY_CHARGER";
zhenhuahb6d5edc2013-06-19 14:37:32 +08002233 case USB_FLOATED_CHARGER: return "USB_FLOATED_CHARGER";
Anji jonnalad270e2d2011-08-09 11:28:32 +05302234 default: return "INVALID_CHARGER";
2235 }
2236}
2237
Pavankumar Kondetiebb4a2d2013-01-04 12:28:10 +05302238#define MSM_CHG_DCD_TIMEOUT (750 * HZ/1000) /* 750 msec */
2239#define MSM_CHG_DCD_POLL_TIME (50 * HZ/1000) /* 50 msec */
Pavankumar Kondeti283146f2012-01-12 12:51:19 +05302240#define MSM_CHG_PRIMARY_DET_TIME (50 * HZ/1000) /* TVDPSRC_ON */
2241#define MSM_CHG_SECONDARY_DET_TIME (50 * HZ/1000) /* TVDMSRC_ON */
Pavankumar Kondetid8608522011-05-04 10:19:47 +05302242static void msm_chg_detect_work(struct work_struct *w)
2243{
2244 struct msm_otg *motg = container_of(w, struct msm_otg, chg_work.work);
Heikki Krogerus1d4c9292012-02-13 13:24:09 +02002245 struct usb_phy *phy = &motg->phy;
Pavankumar Kondeti2d09e5f2012-01-16 08:56:57 +05302246 bool is_dcd = false, tmout, vout, is_aca;
zhenhuahb6d5edc2013-06-19 14:37:32 +08002247 static bool dcd;
Pavankumar Kondeti9ec21d32012-05-07 15:50:23 +05302248 u32 line_state, dm_vlgc;
Pavankumar Kondetid8608522011-05-04 10:19:47 +05302249 unsigned long delay;
2250
Heikki Krogerus1d4c9292012-02-13 13:24:09 +02002251 dev_dbg(phy->dev, "chg detection work\n");
Pavankumar Kondeti2aec9f32012-06-13 09:06:03 +05302252
2253 if (test_bit(MHL, &motg->inputs)) {
2254 dev_dbg(phy->dev, "detected MHL, escape chg detection work\n");
2255 return;
2256 }
2257
Pavankumar Kondetid8608522011-05-04 10:19:47 +05302258 switch (motg->chg_state) {
2259 case USB_CHG_STATE_UNDEFINED:
Pavankumar Kondetid8608522011-05-04 10:19:47 +05302260 msm_chg_block_on(motg);
Pavankumar Kondeti768dcb82012-10-05 13:21:45 +05302261 msm_chg_enable_dcd(motg);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002262 msm_chg_enable_aca_det(motg);
Pavankumar Kondetid8608522011-05-04 10:19:47 +05302263 motg->chg_state = USB_CHG_STATE_WAIT_FOR_DCD;
Pavankumar Kondetiebb4a2d2013-01-04 12:28:10 +05302264 motg->dcd_time = 0;
Pavankumar Kondetid8608522011-05-04 10:19:47 +05302265 delay = MSM_CHG_DCD_POLL_TIME;
2266 break;
2267 case USB_CHG_STATE_WAIT_FOR_DCD:
Pavankumar Kondeti2aec9f32012-06-13 09:06:03 +05302268 if (msm_chg_mhl_detect(motg)) {
2269 msm_chg_block_off(motg);
2270 motg->chg_state = USB_CHG_STATE_DETECTED;
2271 motg->chg_type = USB_INVALID_CHARGER;
2272 queue_work(system_nrt_wq, &motg->sm_work);
2273 return;
2274 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002275 is_aca = msm_chg_aca_detect(motg);
2276 if (is_aca) {
2277 /*
2278 * ID_A can be ACA dock too. continue
2279 * primary detection after DCD.
2280 */
2281 if (test_bit(ID_A, &motg->inputs)) {
2282 motg->chg_state = USB_CHG_STATE_WAIT_FOR_DCD;
2283 } else {
2284 delay = 0;
2285 break;
2286 }
2287 }
Pavankumar Kondeti768dcb82012-10-05 13:21:45 +05302288 is_dcd = msm_chg_check_dcd(motg);
Pavankumar Kondetiebb4a2d2013-01-04 12:28:10 +05302289 motg->dcd_time += MSM_CHG_DCD_POLL_TIME;
2290 tmout = motg->dcd_time >= MSM_CHG_DCD_TIMEOUT;
Pavankumar Kondetid8608522011-05-04 10:19:47 +05302291 if (is_dcd || tmout) {
zhenhuahb6d5edc2013-06-19 14:37:32 +08002292 if (is_dcd)
2293 dcd = true;
2294 else
2295 dcd = false;
Pavankumar Kondeti768dcb82012-10-05 13:21:45 +05302296 msm_chg_disable_dcd(motg);
Pavankumar Kondetid8608522011-05-04 10:19:47 +05302297 msm_chg_enable_primary_det(motg);
2298 delay = MSM_CHG_PRIMARY_DET_TIME;
2299 motg->chg_state = USB_CHG_STATE_DCD_DONE;
2300 } else {
2301 delay = MSM_CHG_DCD_POLL_TIME;
2302 }
2303 break;
2304 case USB_CHG_STATE_DCD_DONE:
2305 vout = msm_chg_check_primary_det(motg);
Pavankumar Kondeti9ec21d32012-05-07 15:50:23 +05302306 line_state = readl_relaxed(USB_PORTSC) & PORTSC_LS;
2307 dm_vlgc = line_state & PORTSC_LS_DM;
2308 if (vout && !dm_vlgc) { /* VDAT_REF < DM < VLGC */
Pavankumar Kondetiaa449e12011-11-04 11:09:26 +05302309 if (test_bit(ID_A, &motg->inputs)) {
2310 motg->chg_type = USB_ACA_DOCK_CHARGER;
2311 motg->chg_state = USB_CHG_STATE_DETECTED;
2312 delay = 0;
2313 break;
2314 }
Pavankumar Kondeti9ec21d32012-05-07 15:50:23 +05302315 if (line_state) { /* DP > VLGC */
2316 motg->chg_type = USB_PROPRIETARY_CHARGER;
2317 motg->chg_state = USB_CHG_STATE_DETECTED;
2318 delay = 0;
2319 } else {
2320 msm_chg_enable_secondary_det(motg);
2321 delay = MSM_CHG_SECONDARY_DET_TIME;
2322 motg->chg_state = USB_CHG_STATE_PRIMARY_DONE;
2323 }
2324 } else { /* DM < VDAT_REF || DM > VLGC */
Pavankumar Kondetiaa449e12011-11-04 11:09:26 +05302325 if (test_bit(ID_A, &motg->inputs)) {
2326 motg->chg_type = USB_ACA_A_CHARGER;
2327 motg->chg_state = USB_CHG_STATE_DETECTED;
2328 delay = 0;
2329 break;
2330 }
Pavankumar Kondeti9ec21d32012-05-07 15:50:23 +05302331
2332 if (line_state) /* DP > VLGC or/and DM > VLGC */
2333 motg->chg_type = USB_PROPRIETARY_CHARGER;
zhenhuahb6d5edc2013-06-19 14:37:32 +08002334 else if (!dcd && floated_charger_enable)
2335 motg->chg_type = USB_FLOATED_CHARGER;
Pavankumar Kondeti9ec21d32012-05-07 15:50:23 +05302336 else
2337 motg->chg_type = USB_SDP_CHARGER;
2338
Pavankumar Kondetid8608522011-05-04 10:19:47 +05302339 motg->chg_state = USB_CHG_STATE_DETECTED;
2340 delay = 0;
2341 }
2342 break;
2343 case USB_CHG_STATE_PRIMARY_DONE:
2344 vout = msm_chg_check_secondary_det(motg);
2345 if (vout)
2346 motg->chg_type = USB_DCP_CHARGER;
2347 else
2348 motg->chg_type = USB_CDP_CHARGER;
2349 motg->chg_state = USB_CHG_STATE_SECONDARY_DONE;
2350 /* fall through */
2351 case USB_CHG_STATE_SECONDARY_DONE:
2352 motg->chg_state = USB_CHG_STATE_DETECTED;
2353 case USB_CHG_STATE_DETECTED:
Pavankumar Kondetid7b6d1a2013-01-11 15:38:09 +05302354 /*
2355 * Notify the charger type to power supply
2356 * owner as soon as we determine the charger.
2357 */
2358 msm_otg_notify_chg_type(motg);
Pavankumar Kondetid8608522011-05-04 10:19:47 +05302359 msm_chg_block_off(motg);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002360 msm_chg_enable_aca_det(motg);
Vijayavardhan Vennapusaa3152032012-03-05 16:29:30 +05302361 /*
2362 * Spurious interrupt is seen after enabling ACA detection
2363 * due to which charger detection fails in case of PET.
2364 * Add delay of 100 microsec to avoid that.
2365 */
2366 udelay(100);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002367 msm_chg_enable_aca_intr(motg);
Steve Mucklef132c6c2012-06-06 18:30:57 -07002368 dev_dbg(phy->dev, "chg_type = %s\n",
Anji jonnalad270e2d2011-08-09 11:28:32 +05302369 chg_to_string(motg->chg_type));
Vijayavardhan Vennapusaa3152032012-03-05 16:29:30 +05302370 queue_work(system_nrt_wq, &motg->sm_work);
Pavankumar Kondetid8608522011-05-04 10:19:47 +05302371 return;
2372 default:
2373 return;
2374 }
2375
Vijayavardhan Vennapusaa3152032012-03-05 16:29:30 +05302376 queue_delayed_work(system_nrt_wq, &motg->chg_work, delay);
Pavankumar Kondetid8608522011-05-04 10:19:47 +05302377}
2378
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05302379/*
2380 * We support OTG, Peripheral only and Host only configurations. In case
2381 * of OTG, mode switch (host-->peripheral/peripheral-->host) can happen
2382 * via Id pin status or user request (debugfs). Id/BSV interrupts are not
2383 * enabled when switch is controlled by user and default mode is supplied
2384 * by board file, which can be changed by userspace later.
2385 */
2386static void msm_otg_init_sm(struct msm_otg *motg)
2387{
2388 struct msm_otg_platform_data *pdata = motg->pdata;
2389 u32 otgsc = readl(USB_OTGSC);
2390
2391 switch (pdata->mode) {
2392 case USB_OTG:
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002393 if (pdata->otg_control == OTG_USER_CONTROL) {
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05302394 if (pdata->default_mode == USB_HOST) {
2395 clear_bit(ID, &motg->inputs);
2396 } else if (pdata->default_mode == USB_PERIPHERAL) {
2397 set_bit(ID, &motg->inputs);
2398 set_bit(B_SESS_VLD, &motg->inputs);
2399 } else {
2400 set_bit(ID, &motg->inputs);
2401 clear_bit(B_SESS_VLD, &motg->inputs);
2402 }
Pavankumar Kondeti4960f312011-12-06 15:46:14 +05302403 } else if (pdata->otg_control == OTG_PHY_CONTROL) {
Vijayavardhan Vennapusaa3152032012-03-05 16:29:30 +05302404 if (otgsc & OTGSC_ID) {
Pavankumar Kondeti4960f312011-12-06 15:46:14 +05302405 set_bit(ID, &motg->inputs);
Vijayavardhan Vennapusaa3152032012-03-05 16:29:30 +05302406 } else {
Pavankumar Kondeti4960f312011-12-06 15:46:14 +05302407 clear_bit(ID, &motg->inputs);
Vijayavardhan Vennapusaa3152032012-03-05 16:29:30 +05302408 set_bit(A_BUS_REQ, &motg->inputs);
2409 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002410 if (otgsc & OTGSC_BSV)
2411 set_bit(B_SESS_VLD, &motg->inputs);
2412 else
2413 clear_bit(B_SESS_VLD, &motg->inputs);
Pavankumar Kondeti4960f312011-12-06 15:46:14 +05302414 } else if (pdata->otg_control == OTG_PMIC_CONTROL) {
Pavankumar Kondeti0d81f312012-01-13 11:34:10 +05302415 if (pdata->pmic_id_irq) {
Pavankumar Kondetibecab5b2012-11-06 16:45:10 +05302416 if (msm_otg_read_pmic_id_state(motg))
Pavankumar Kondeti0d81f312012-01-13 11:34:10 +05302417 set_bit(ID, &motg->inputs);
2418 else
2419 clear_bit(ID, &motg->inputs);
2420 }
Pavankumar Kondeti4960f312011-12-06 15:46:14 +05302421 /*
2422 * VBUS initial state is reported after PMIC
2423 * driver initialization. Wait for it.
2424 */
2425 wait_for_completion(&pmic_vbus_init);
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05302426 }
2427 break;
2428 case USB_HOST:
2429 clear_bit(ID, &motg->inputs);
2430 break;
2431 case USB_PERIPHERAL:
2432 set_bit(ID, &motg->inputs);
Pavankumar Kondeti0d81f312012-01-13 11:34:10 +05302433 if (pdata->otg_control == OTG_PHY_CONTROL) {
2434 if (otgsc & OTGSC_BSV)
2435 set_bit(B_SESS_VLD, &motg->inputs);
2436 else
2437 clear_bit(B_SESS_VLD, &motg->inputs);
2438 } else if (pdata->otg_control == OTG_PMIC_CONTROL) {
2439 /*
2440 * VBUS initial state is reported after PMIC
2441 * driver initialization. Wait for it.
2442 */
2443 wait_for_completion(&pmic_vbus_init);
2444 }
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05302445 break;
2446 default:
2447 break;
2448 }
2449}
2450
2451static void msm_otg_sm_work(struct work_struct *w)
2452{
2453 struct msm_otg *motg = container_of(w, struct msm_otg, sm_work);
Heikki Krogerus1d4c9292012-02-13 13:24:09 +02002454 struct usb_otg *otg = motg->phy.otg;
Vijayavardhan Vennapusaa3152032012-03-05 16:29:30 +05302455 bool work = 0, srp_reqd;
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05302456
Steve Mucklef132c6c2012-06-06 18:30:57 -07002457 pm_runtime_resume(otg->phy->dev);
2458 pr_debug("%s work\n", otg_state_string(otg->phy->state));
Heikki Krogerus1d4c9292012-02-13 13:24:09 +02002459 switch (otg->phy->state) {
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05302460 case OTG_STATE_UNDEFINED:
Heikki Krogerus1d4c9292012-02-13 13:24:09 +02002461 msm_otg_reset(otg->phy);
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05302462 msm_otg_init_sm(motg);
David Keitel272ce522012-08-17 16:25:24 -07002463 if (!psy && legacy_power_supply) {
2464 psy = power_supply_get_by_name("usb");
2465
2466 if (!psy)
2467 pr_err("couldn't get usb power supply\n");
2468 }
2469
Heikki Krogerus1d4c9292012-02-13 13:24:09 +02002470 otg->phy->state = OTG_STATE_B_IDLE;
Pavankumar Kondeti8a379b42011-12-12 13:07:23 +05302471 if (!test_bit(B_SESS_VLD, &motg->inputs) &&
2472 test_bit(ID, &motg->inputs)) {
Steve Mucklef132c6c2012-06-06 18:30:57 -07002473 pm_runtime_put_noidle(otg->phy->dev);
2474 pm_runtime_suspend(otg->phy->dev);
Pavankumar Kondeti8a379b42011-12-12 13:07:23 +05302475 break;
2476 }
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05302477 /* FALL THROUGH */
2478 case OTG_STATE_B_IDLE:
Pavankumar Kondeti2aec9f32012-06-13 09:06:03 +05302479 if (test_bit(MHL, &motg->inputs)) {
2480 /* allow LPM */
2481 pm_runtime_put_noidle(otg->phy->dev);
2482 pm_runtime_suspend(otg->phy->dev);
2483 } else if ((!test_bit(ID, &motg->inputs) ||
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002484 test_bit(ID_A, &motg->inputs)) && otg->host) {
Vijayavardhan Vennapusaa3152032012-03-05 16:29:30 +05302485 pr_debug("!id || id_A\n");
Pavankumar Kondeti2aec9f32012-06-13 09:06:03 +05302486 if (msm_chg_mhl_detect(motg)) {
2487 work = 1;
2488 break;
2489 }
Vijayavardhan Vennapusaa3152032012-03-05 16:29:30 +05302490 clear_bit(B_BUS_REQ, &motg->inputs);
2491 set_bit(A_BUS_REQ, &motg->inputs);
Steve Mucklef132c6c2012-06-06 18:30:57 -07002492 otg->phy->state = OTG_STATE_A_IDLE;
Vijayavardhan Vennapusaa3152032012-03-05 16:29:30 +05302493 work = 1;
Pavankumar Kondetid8608522011-05-04 10:19:47 +05302494 } else if (test_bit(B_SESS_VLD, &motg->inputs)) {
Vijayavardhan Vennapusaa3152032012-03-05 16:29:30 +05302495 pr_debug("b_sess_vld\n");
Pavankumar Kondetid8608522011-05-04 10:19:47 +05302496 switch (motg->chg_state) {
2497 case USB_CHG_STATE_UNDEFINED:
2498 msm_chg_detect_work(&motg->chg_work.work);
2499 break;
2500 case USB_CHG_STATE_DETECTED:
2501 switch (motg->chg_type) {
2502 case USB_DCP_CHARGER:
Pavankumar Kondeti283146f2012-01-12 12:51:19 +05302503 /* Enable VDP_SRC */
Steve Mucklef132c6c2012-06-06 18:30:57 -07002504 ulpi_write(otg->phy, 0x2, 0x85);
Pavankumar Kondeti9ec21d32012-05-07 15:50:23 +05302505 /* fall through */
2506 case USB_PROPRIETARY_CHARGER:
Pavankumar Kondetid8608522011-05-04 10:19:47 +05302507 msm_otg_notify_charger(motg,
2508 IDEV_CHG_MAX);
Steve Mucklef132c6c2012-06-06 18:30:57 -07002509 pm_runtime_put_noidle(otg->phy->dev);
2510 pm_runtime_suspend(otg->phy->dev);
Pavankumar Kondetid8608522011-05-04 10:19:47 +05302511 break;
zhenhuahb6d5edc2013-06-19 14:37:32 +08002512 case USB_FLOATED_CHARGER:
2513 msm_otg_notify_charger(motg,
2514 IDEV_CHG_MAX);
2515 pm_runtime_put_noidle(otg->phy->dev);
2516 pm_runtime_suspend(otg->phy->dev);
2517 break;
Pavankumar Kondetiaa449e12011-11-04 11:09:26 +05302518 case USB_ACA_B_CHARGER:
2519 msm_otg_notify_charger(motg,
2520 IDEV_ACA_CHG_MAX);
2521 /*
2522 * (ID_B --> ID_C) PHY_ALT interrupt can
2523 * not be detected in LPM.
2524 */
Pavankumar Kondetid8608522011-05-04 10:19:47 +05302525 break;
2526 case USB_CDP_CHARGER:
2527 msm_otg_notify_charger(motg,
2528 IDEV_CHG_MAX);
2529 msm_otg_start_peripheral(otg, 1);
Steve Mucklef132c6c2012-06-06 18:30:57 -07002530 otg->phy->state =
2531 OTG_STATE_B_PERIPHERAL;
Pavankumar Kondetid8608522011-05-04 10:19:47 +05302532 break;
Pavankumar Kondetiaa449e12011-11-04 11:09:26 +05302533 case USB_ACA_C_CHARGER:
2534 msm_otg_notify_charger(motg,
2535 IDEV_ACA_CHG_MAX);
2536 msm_otg_start_peripheral(otg, 1);
Steve Mucklef132c6c2012-06-06 18:30:57 -07002537 otg->phy->state =
2538 OTG_STATE_B_PERIPHERAL;
Pavankumar Kondetid8608522011-05-04 10:19:47 +05302539 break;
2540 case USB_SDP_CHARGER:
Pavankumar Kondetid8608522011-05-04 10:19:47 +05302541 msm_otg_start_peripheral(otg, 1);
Steve Mucklef132c6c2012-06-06 18:30:57 -07002542 otg->phy->state =
2543 OTG_STATE_B_PERIPHERAL;
Pavankumar Kondeti458d8792012-09-28 14:45:18 +05302544 mod_timer(&motg->chg_check_timer,
2545 CHG_RECHECK_DELAY);
Pavankumar Kondetid8608522011-05-04 10:19:47 +05302546 break;
2547 default:
2548 break;
2549 }
2550 break;
2551 default:
2552 break;
2553 }
Vijayavardhan Vennapusaa3152032012-03-05 16:29:30 +05302554 } else if (test_bit(B_BUS_REQ, &motg->inputs)) {
2555 pr_debug("b_sess_end && b_bus_req\n");
2556 if (msm_otg_start_srp(otg) < 0) {
2557 clear_bit(B_BUS_REQ, &motg->inputs);
2558 work = 1;
2559 break;
Pavankumar Kondetid8608522011-05-04 10:19:47 +05302560 }
Steve Mucklef132c6c2012-06-06 18:30:57 -07002561 otg->phy->state = OTG_STATE_B_SRP_INIT;
Vijayavardhan Vennapusaa3152032012-03-05 16:29:30 +05302562 msm_otg_start_timer(motg, TB_SRP_FAIL, B_SRP_FAIL);
2563 break;
Pavankumar Kondetid8608522011-05-04 10:19:47 +05302564 } else {
Vijayavardhan Vennapusaa3152032012-03-05 16:29:30 +05302565 pr_debug("chg_work cancel");
Pavankumar Kondeti458d8792012-09-28 14:45:18 +05302566 del_timer_sync(&motg->chg_check_timer);
2567 clear_bit(B_FALSE_SDP, &motg->inputs);
Mayank Rana8ab00352013-01-23 19:26:21 +05302568 clear_bit(A_BUS_REQ, &motg->inputs);
Pavankumar Kondetiaa449e12011-11-04 11:09:26 +05302569 cancel_delayed_work_sync(&motg->chg_work);
Pavankumar Kondetid8608522011-05-04 10:19:47 +05302570 motg->chg_state = USB_CHG_STATE_UNDEFINED;
2571 motg->chg_type = USB_INVALID_CHARGER;
Rajkumar Raghupathy18fd7132012-04-20 11:28:13 +05302572 msm_otg_notify_charger(motg, 0);
Steve Mucklef132c6c2012-06-06 18:30:57 -07002573 msm_otg_reset(otg->phy);
Pavankumar Kondetibecab5b2012-11-06 16:45:10 +05302574 /*
2575 * There is a small window where ID interrupt
2576 * is not monitored during ID detection circuit
2577 * switch from ACA to PMIC. Check ID state
2578 * before entering into low power mode.
2579 */
2580 if (!msm_otg_read_pmic_id_state(motg)) {
2581 pr_debug("process missed ID intr\n");
2582 clear_bit(ID, &motg->inputs);
2583 work = 1;
2584 break;
2585 }
Steve Mucklef132c6c2012-06-06 18:30:57 -07002586 pm_runtime_put_noidle(otg->phy->dev);
Amit Blayd6f38282012-10-29 13:13:46 +02002587 /*
2588 * Only if autosuspend was enabled in probe, it will be
2589 * used here. Otherwise, no delay will be used.
2590 */
2591 pm_runtime_mark_last_busy(otg->phy->dev);
2592 pm_runtime_autosuspend(otg->phy->dev);
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05302593 }
2594 break;
Vijayavardhan Vennapusaa3152032012-03-05 16:29:30 +05302595 case OTG_STATE_B_SRP_INIT:
2596 if (!test_bit(ID, &motg->inputs) ||
2597 test_bit(ID_A, &motg->inputs) ||
2598 test_bit(ID_C, &motg->inputs) ||
2599 (test_bit(B_SESS_VLD, &motg->inputs) &&
2600 !test_bit(ID_B, &motg->inputs))) {
2601 pr_debug("!id || id_a/c || b_sess_vld+!id_b\n");
2602 msm_otg_del_timer(motg);
Steve Mucklef132c6c2012-06-06 18:30:57 -07002603 otg->phy->state = OTG_STATE_B_IDLE;
Vijayavardhan Vennapusaa3152032012-03-05 16:29:30 +05302604 /*
2605 * clear VBUSVLDEXTSEL and VBUSVLDEXT register
2606 * bits after SRP initiation.
2607 */
Steve Mucklef132c6c2012-06-06 18:30:57 -07002608 ulpi_write(otg->phy, 0x0, 0x98);
Vijayavardhan Vennapusaa3152032012-03-05 16:29:30 +05302609 work = 1;
2610 } else if (test_bit(B_SRP_FAIL, &motg->tmouts)) {
2611 pr_debug("b_srp_fail\n");
2612 pr_info("A-device did not respond to SRP\n");
2613 clear_bit(B_BUS_REQ, &motg->inputs);
2614 clear_bit(B_SRP_FAIL, &motg->tmouts);
2615 otg_send_event(OTG_EVENT_NO_RESP_FOR_SRP);
Steve Mucklef132c6c2012-06-06 18:30:57 -07002616 ulpi_write(otg->phy, 0x0, 0x98);
2617 otg->phy->state = OTG_STATE_B_IDLE;
Vijayavardhan Vennapusaa3152032012-03-05 16:29:30 +05302618 motg->b_last_se0_sess = jiffies;
2619 work = 1;
2620 }
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05302621 break;
2622 case OTG_STATE_B_PERIPHERAL:
Pavankumar Kondeti458d8792012-09-28 14:45:18 +05302623 if (test_bit(B_SESS_VLD, &motg->inputs) &&
2624 test_bit(B_FALSE_SDP, &motg->inputs)) {
2625 pr_debug("B_FALSE_SDP\n");
2626 msm_otg_start_peripheral(otg, 0);
2627 motg->chg_type = USB_DCP_CHARGER;
2628 clear_bit(B_FALSE_SDP, &motg->inputs);
2629 otg->phy->state = OTG_STATE_B_IDLE;
2630 work = 1;
2631 } else if (!test_bit(ID, &motg->inputs) ||
Vijayavardhan Vennapusaa3152032012-03-05 16:29:30 +05302632 test_bit(ID_A, &motg->inputs) ||
2633 test_bit(ID_B, &motg->inputs) ||
2634 !test_bit(B_SESS_VLD, &motg->inputs)) {
2635 pr_debug("!id || id_a/b || !b_sess_vld\n");
Pavankumar Kondetid8608522011-05-04 10:19:47 +05302636 motg->chg_state = USB_CHG_STATE_UNDEFINED;
2637 motg->chg_type = USB_INVALID_CHARGER;
Vijayavardhan Vennapusaa3152032012-03-05 16:29:30 +05302638 msm_otg_notify_charger(motg, 0);
2639 srp_reqd = otg->gadget->otg_srp_reqd;
2640 msm_otg_start_peripheral(otg, 0);
Vijayavardhan Vennapusaa3152032012-03-05 16:29:30 +05302641 if (test_bit(ID_B, &motg->inputs))
2642 clear_bit(ID_B, &motg->inputs);
2643 clear_bit(B_BUS_REQ, &motg->inputs);
Steve Mucklef132c6c2012-06-06 18:30:57 -07002644 otg->phy->state = OTG_STATE_B_IDLE;
Vijayavardhan Vennapusaa3152032012-03-05 16:29:30 +05302645 motg->b_last_se0_sess = jiffies;
2646 if (srp_reqd)
2647 msm_otg_start_timer(motg,
2648 TB_TST_SRP, B_TST_SRP);
2649 else
2650 work = 1;
2651 } else if (test_bit(B_BUS_REQ, &motg->inputs) &&
2652 otg->gadget->b_hnp_enable &&
2653 test_bit(A_BUS_SUSPEND, &motg->inputs)) {
2654 pr_debug("b_bus_req && b_hnp_en && a_bus_suspend\n");
2655 msm_otg_start_timer(motg, TB_ASE0_BRST, B_ASE0_BRST);
2656 /* D+ pullup should not be disconnected within 4msec
2657 * after A device suspends the bus. Otherwise PET will
2658 * fail the compliance test.
2659 */
2660 udelay(1000);
2661 msm_otg_start_peripheral(otg, 0);
Steve Mucklef132c6c2012-06-06 18:30:57 -07002662 otg->phy->state = OTG_STATE_B_WAIT_ACON;
Vijayavardhan Vennapusaa3152032012-03-05 16:29:30 +05302663 /*
2664 * start HCD even before A-device enable
2665 * pull-up to meet HNP timings.
2666 */
2667 otg->host->is_b_host = 1;
2668 msm_otg_start_host(otg, 1);
Amit Blay6fa647a2012-05-24 14:12:08 +03002669 } else if (test_bit(A_BUS_SUSPEND, &motg->inputs) &&
2670 test_bit(B_SESS_VLD, &motg->inputs)) {
2671 pr_debug("a_bus_suspend && b_sess_vld\n");
2672 if (motg->caps & ALLOW_LPM_ON_DEV_SUSPEND) {
Steve Mucklef132c6c2012-06-06 18:30:57 -07002673 pm_runtime_put_noidle(otg->phy->dev);
2674 pm_runtime_suspend(otg->phy->dev);
Amit Blay6fa647a2012-05-24 14:12:08 +03002675 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002676 } else if (test_bit(ID_C, &motg->inputs)) {
Pavankumar Kondetiaa449e12011-11-04 11:09:26 +05302677 msm_otg_notify_charger(motg, IDEV_ACA_CHG_MAX);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002678 }
2679 break;
Vijayavardhan Vennapusaa3152032012-03-05 16:29:30 +05302680 case OTG_STATE_B_WAIT_ACON:
2681 if (!test_bit(ID, &motg->inputs) ||
2682 test_bit(ID_A, &motg->inputs) ||
2683 test_bit(ID_B, &motg->inputs) ||
2684 !test_bit(B_SESS_VLD, &motg->inputs)) {
2685 pr_debug("!id || id_a/b || !b_sess_vld\n");
2686 msm_otg_del_timer(motg);
Pavankumar Kondetiaa449e12011-11-04 11:09:26 +05302687 /*
Vijayavardhan Vennapusaa3152032012-03-05 16:29:30 +05302688 * A-device is physically disconnected during
2689 * HNP. Remove HCD.
Pavankumar Kondetiaa449e12011-11-04 11:09:26 +05302690 */
Vijayavardhan Vennapusaa3152032012-03-05 16:29:30 +05302691 msm_otg_start_host(otg, 0);
2692 otg->host->is_b_host = 0;
2693
2694 clear_bit(B_BUS_REQ, &motg->inputs);
2695 clear_bit(A_BUS_SUSPEND, &motg->inputs);
2696 motg->b_last_se0_sess = jiffies;
Heikki Krogerus1d4c9292012-02-13 13:24:09 +02002697 otg->phy->state = OTG_STATE_B_IDLE;
2698 msm_otg_reset(otg->phy);
Vijayavardhan Vennapusaa3152032012-03-05 16:29:30 +05302699 work = 1;
2700 } else if (test_bit(A_CONN, &motg->inputs)) {
2701 pr_debug("a_conn\n");
2702 clear_bit(A_BUS_SUSPEND, &motg->inputs);
Steve Mucklef132c6c2012-06-06 18:30:57 -07002703 otg->phy->state = OTG_STATE_B_HOST;
Vijayavardhan Vennapusaa3152032012-03-05 16:29:30 +05302704 /*
2705 * PET disconnects D+ pullup after reset is generated
2706 * by B device in B_HOST role which is not detected by
2707 * B device. As workaorund , start timer of 300msec
2708 * and stop timer if A device is enumerated else clear
2709 * A_CONN.
2710 */
2711 msm_otg_start_timer(motg, TB_TST_CONFIG,
2712 B_TST_CONFIG);
2713 } else if (test_bit(B_ASE0_BRST, &motg->tmouts)) {
2714 pr_debug("b_ase0_brst_tmout\n");
2715 pr_info("B HNP fail:No response from A device\n");
2716 msm_otg_start_host(otg, 0);
Steve Mucklef132c6c2012-06-06 18:30:57 -07002717 msm_otg_reset(otg->phy);
Vijayavardhan Vennapusaa3152032012-03-05 16:29:30 +05302718 otg->host->is_b_host = 0;
2719 clear_bit(B_ASE0_BRST, &motg->tmouts);
2720 clear_bit(A_BUS_SUSPEND, &motg->inputs);
2721 clear_bit(B_BUS_REQ, &motg->inputs);
2722 otg_send_event(OTG_EVENT_HNP_FAILED);
Steve Mucklef132c6c2012-06-06 18:30:57 -07002723 otg->phy->state = OTG_STATE_B_IDLE;
Vijayavardhan Vennapusaa3152032012-03-05 16:29:30 +05302724 work = 1;
2725 } else if (test_bit(ID_C, &motg->inputs)) {
2726 msm_otg_notify_charger(motg, IDEV_ACA_CHG_MAX);
2727 }
2728 break;
2729 case OTG_STATE_B_HOST:
2730 if (!test_bit(B_BUS_REQ, &motg->inputs) ||
2731 !test_bit(A_CONN, &motg->inputs) ||
2732 !test_bit(B_SESS_VLD, &motg->inputs)) {
2733 pr_debug("!b_bus_req || !a_conn || !b_sess_vld\n");
2734 clear_bit(A_CONN, &motg->inputs);
2735 clear_bit(B_BUS_REQ, &motg->inputs);
2736 msm_otg_start_host(otg, 0);
2737 otg->host->is_b_host = 0;
Steve Mucklef132c6c2012-06-06 18:30:57 -07002738 otg->phy->state = OTG_STATE_B_IDLE;
2739 msm_otg_reset(otg->phy);
Vijayavardhan Vennapusaa3152032012-03-05 16:29:30 +05302740 work = 1;
2741 } else if (test_bit(ID_C, &motg->inputs)) {
2742 msm_otg_notify_charger(motg, IDEV_ACA_CHG_MAX);
2743 }
2744 break;
2745 case OTG_STATE_A_IDLE:
2746 otg->default_a = 1;
2747 if (test_bit(ID, &motg->inputs) &&
2748 !test_bit(ID_A, &motg->inputs)) {
2749 pr_debug("id && !id_a\n");
2750 otg->default_a = 0;
2751 clear_bit(A_BUS_DROP, &motg->inputs);
Steve Mucklef132c6c2012-06-06 18:30:57 -07002752 otg->phy->state = OTG_STATE_B_IDLE;
Vijayavardhan Vennapusaa3152032012-03-05 16:29:30 +05302753 del_timer_sync(&motg->id_timer);
2754 msm_otg_link_reset(motg);
2755 msm_chg_enable_aca_intr(motg);
2756 msm_otg_notify_charger(motg, 0);
2757 work = 1;
2758 } else if (!test_bit(A_BUS_DROP, &motg->inputs) &&
2759 (test_bit(A_SRP_DET, &motg->inputs) ||
2760 test_bit(A_BUS_REQ, &motg->inputs))) {
2761 pr_debug("!a_bus_drop && (a_srp_det || a_bus_req)\n");
2762
2763 clear_bit(A_SRP_DET, &motg->inputs);
2764 /* Disable SRP detection */
2765 writel_relaxed((readl_relaxed(USB_OTGSC) &
2766 ~OTGSC_INTSTS_MASK) &
2767 ~OTGSC_DPIE, USB_OTGSC);
2768
Steve Mucklef132c6c2012-06-06 18:30:57 -07002769 otg->phy->state = OTG_STATE_A_WAIT_VRISE;
Vijayavardhan Vennapusaa3152032012-03-05 16:29:30 +05302770 /* VBUS should not be supplied before end of SRP pulse
2771 * generated by PET, if not complaince test fail.
2772 */
2773 usleep_range(10000, 12000);
2774 /* ACA: ID_A: Stop charging untill enumeration */
2775 if (test_bit(ID_A, &motg->inputs))
2776 msm_otg_notify_charger(motg, 0);
2777 else
2778 msm_hsusb_vbus_power(motg, 1);
2779 msm_otg_start_timer(motg, TA_WAIT_VRISE, A_WAIT_VRISE);
2780 } else {
2781 pr_debug("No session requested\n");
2782 clear_bit(A_BUS_DROP, &motg->inputs);
2783 if (test_bit(ID_A, &motg->inputs)) {
2784 msm_otg_notify_charger(motg,
2785 IDEV_ACA_CHG_MAX);
2786 } else if (!test_bit(ID, &motg->inputs)) {
2787 msm_otg_notify_charger(motg, 0);
2788 /*
2789 * A-device is not providing power on VBUS.
2790 * Enable SRP detection.
2791 */
2792 writel_relaxed(0x13, USB_USBMODE);
2793 writel_relaxed((readl_relaxed(USB_OTGSC) &
2794 ~OTGSC_INTSTS_MASK) |
2795 OTGSC_DPIE, USB_OTGSC);
2796 mb();
2797 }
2798 }
2799 break;
2800 case OTG_STATE_A_WAIT_VRISE:
2801 if ((test_bit(ID, &motg->inputs) &&
2802 !test_bit(ID_A, &motg->inputs)) ||
2803 test_bit(A_BUS_DROP, &motg->inputs) ||
2804 test_bit(A_WAIT_VRISE, &motg->tmouts)) {
2805 pr_debug("id || a_bus_drop || a_wait_vrise_tmout\n");
2806 clear_bit(A_BUS_REQ, &motg->inputs);
2807 msm_otg_del_timer(motg);
2808 msm_hsusb_vbus_power(motg, 0);
Steve Mucklef132c6c2012-06-06 18:30:57 -07002809 otg->phy->state = OTG_STATE_A_WAIT_VFALL;
Vijayavardhan Vennapusaa3152032012-03-05 16:29:30 +05302810 msm_otg_start_timer(motg, TA_WAIT_VFALL, A_WAIT_VFALL);
2811 } else if (test_bit(A_VBUS_VLD, &motg->inputs)) {
2812 pr_debug("a_vbus_vld\n");
Steve Mucklef132c6c2012-06-06 18:30:57 -07002813 otg->phy->state = OTG_STATE_A_WAIT_BCON;
Vijayavardhan Vennapusaa3152032012-03-05 16:29:30 +05302814 if (TA_WAIT_BCON > 0)
2815 msm_otg_start_timer(motg, TA_WAIT_BCON,
2816 A_WAIT_BCON);
Sujeet Kumarebaef0c2013-06-03 15:54:25 +05302817
2818 /* Clear BSV in host mode */
2819 clear_bit(B_SESS_VLD, &motg->inputs);
Vijayavardhan Vennapusaa3152032012-03-05 16:29:30 +05302820 msm_otg_start_host(otg, 1);
2821 msm_chg_enable_aca_det(motg);
2822 msm_chg_disable_aca_intr(motg);
Chiranjeevi Velempati489a27c2012-03-29 09:47:17 +05302823 mod_timer(&motg->id_timer, ID_TIMER_FREQ);
Vijayavardhan Vennapusaa3152032012-03-05 16:29:30 +05302824 if (msm_chg_check_aca_intr(motg))
2825 work = 1;
2826 }
2827 break;
2828 case OTG_STATE_A_WAIT_BCON:
2829 if ((test_bit(ID, &motg->inputs) &&
2830 !test_bit(ID_A, &motg->inputs)) ||
2831 test_bit(A_BUS_DROP, &motg->inputs) ||
2832 test_bit(A_WAIT_BCON, &motg->tmouts)) {
2833 pr_debug("(id && id_a/b/c) || a_bus_drop ||"
2834 "a_wait_bcon_tmout\n");
2835 if (test_bit(A_WAIT_BCON, &motg->tmouts)) {
2836 pr_info("Device No Response\n");
2837 otg_send_event(OTG_EVENT_DEV_CONN_TMOUT);
2838 }
2839 msm_otg_del_timer(motg);
2840 clear_bit(A_BUS_REQ, &motg->inputs);
2841 clear_bit(B_CONN, &motg->inputs);
2842 msm_otg_start_host(otg, 0);
2843 /*
2844 * ACA: ID_A with NO accessory, just the A plug is
2845 * attached to ACA: Use IDCHG_MAX for charging
2846 */
2847 if (test_bit(ID_A, &motg->inputs))
2848 msm_otg_notify_charger(motg, IDEV_CHG_MIN);
2849 else
2850 msm_hsusb_vbus_power(motg, 0);
Steve Mucklef132c6c2012-06-06 18:30:57 -07002851 otg->phy->state = OTG_STATE_A_WAIT_VFALL;
Vijayavardhan Vennapusaa3152032012-03-05 16:29:30 +05302852 msm_otg_start_timer(motg, TA_WAIT_VFALL, A_WAIT_VFALL);
2853 } else if (!test_bit(A_VBUS_VLD, &motg->inputs)) {
2854 pr_debug("!a_vbus_vld\n");
2855 clear_bit(B_CONN, &motg->inputs);
2856 msm_otg_del_timer(motg);
2857 msm_otg_start_host(otg, 0);
Steve Mucklef132c6c2012-06-06 18:30:57 -07002858 otg->phy->state = OTG_STATE_A_VBUS_ERR;
2859 msm_otg_reset(otg->phy);
Vijayavardhan Vennapusaa3152032012-03-05 16:29:30 +05302860 } else if (test_bit(ID_A, &motg->inputs)) {
2861 msm_hsusb_vbus_power(motg, 0);
2862 } else if (!test_bit(A_BUS_REQ, &motg->inputs)) {
2863 /*
2864 * If TA_WAIT_BCON is infinite, we don;t
2865 * turn off VBUS. Enter low power mode.
2866 */
2867 if (TA_WAIT_BCON < 0)
Steve Mucklef132c6c2012-06-06 18:30:57 -07002868 pm_runtime_put_sync(otg->phy->dev);
Vijayavardhan Vennapusaa3152032012-03-05 16:29:30 +05302869 } else if (!test_bit(ID, &motg->inputs)) {
2870 msm_hsusb_vbus_power(motg, 1);
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05302871 }
2872 break;
2873 case OTG_STATE_A_HOST:
Vijayavardhan Vennapusaa3152032012-03-05 16:29:30 +05302874 if ((test_bit(ID, &motg->inputs) &&
2875 !test_bit(ID_A, &motg->inputs)) ||
2876 test_bit(A_BUS_DROP, &motg->inputs)) {
2877 pr_debug("id_a/b/c || a_bus_drop\n");
2878 clear_bit(B_CONN, &motg->inputs);
2879 clear_bit(A_BUS_REQ, &motg->inputs);
2880 msm_otg_del_timer(motg);
Steve Mucklef132c6c2012-06-06 18:30:57 -07002881 otg->phy->state = OTG_STATE_A_WAIT_VFALL;
Vijayavardhan Vennapusaa3152032012-03-05 16:29:30 +05302882 msm_otg_start_host(otg, 0);
2883 if (!test_bit(ID_A, &motg->inputs))
2884 msm_hsusb_vbus_power(motg, 0);
2885 msm_otg_start_timer(motg, TA_WAIT_VFALL, A_WAIT_VFALL);
2886 } else if (!test_bit(A_VBUS_VLD, &motg->inputs)) {
2887 pr_debug("!a_vbus_vld\n");
2888 clear_bit(B_CONN, &motg->inputs);
2889 msm_otg_del_timer(motg);
Steve Mucklef132c6c2012-06-06 18:30:57 -07002890 otg->phy->state = OTG_STATE_A_VBUS_ERR;
Vijayavardhan Vennapusaa3152032012-03-05 16:29:30 +05302891 msm_otg_start_host(otg, 0);
Heikki Krogerus1d4c9292012-02-13 13:24:09 +02002892 msm_otg_reset(otg->phy);
Vijayavardhan Vennapusaa3152032012-03-05 16:29:30 +05302893 } else if (!test_bit(A_BUS_REQ, &motg->inputs)) {
2894 /*
2895 * a_bus_req is de-asserted when root hub is
2896 * suspended or HNP is in progress.
2897 */
2898 pr_debug("!a_bus_req\n");
2899 msm_otg_del_timer(motg);
Steve Mucklef132c6c2012-06-06 18:30:57 -07002900 otg->phy->state = OTG_STATE_A_SUSPEND;
Vijayavardhan Vennapusaa3152032012-03-05 16:29:30 +05302901 if (otg->host->b_hnp_enable)
2902 msm_otg_start_timer(motg, TA_AIDL_BDIS,
2903 A_AIDL_BDIS);
2904 else
Steve Mucklef132c6c2012-06-06 18:30:57 -07002905 pm_runtime_put_sync(otg->phy->dev);
Vijayavardhan Vennapusaa3152032012-03-05 16:29:30 +05302906 } else if (!test_bit(B_CONN, &motg->inputs)) {
2907 pr_debug("!b_conn\n");
2908 msm_otg_del_timer(motg);
Steve Mucklef132c6c2012-06-06 18:30:57 -07002909 otg->phy->state = OTG_STATE_A_WAIT_BCON;
Vijayavardhan Vennapusaa3152032012-03-05 16:29:30 +05302910 if (TA_WAIT_BCON > 0)
2911 msm_otg_start_timer(motg, TA_WAIT_BCON,
2912 A_WAIT_BCON);
2913 if (msm_chg_check_aca_intr(motg))
2914 work = 1;
2915 } else if (test_bit(ID_A, &motg->inputs)) {
2916 msm_otg_del_timer(motg);
2917 msm_hsusb_vbus_power(motg, 0);
2918 if (motg->chg_type == USB_ACA_DOCK_CHARGER)
2919 msm_otg_notify_charger(motg,
2920 IDEV_ACA_CHG_MAX);
2921 else
2922 msm_otg_notify_charger(motg,
2923 IDEV_CHG_MIN - motg->mA_port);
2924 } else if (!test_bit(ID, &motg->inputs)) {
2925 motg->chg_state = USB_CHG_STATE_UNDEFINED;
2926 motg->chg_type = USB_INVALID_CHARGER;
2927 msm_otg_notify_charger(motg, 0);
2928 msm_hsusb_vbus_power(motg, 1);
2929 }
2930 break;
2931 case OTG_STATE_A_SUSPEND:
2932 if ((test_bit(ID, &motg->inputs) &&
2933 !test_bit(ID_A, &motg->inputs)) ||
2934 test_bit(A_BUS_DROP, &motg->inputs) ||
2935 test_bit(A_AIDL_BDIS, &motg->tmouts)) {
2936 pr_debug("id_a/b/c || a_bus_drop ||"
2937 "a_aidl_bdis_tmout\n");
2938 msm_otg_del_timer(motg);
2939 clear_bit(B_CONN, &motg->inputs);
Steve Mucklef132c6c2012-06-06 18:30:57 -07002940 otg->phy->state = OTG_STATE_A_WAIT_VFALL;
Vijayavardhan Vennapusaa3152032012-03-05 16:29:30 +05302941 msm_otg_start_host(otg, 0);
Steve Mucklef132c6c2012-06-06 18:30:57 -07002942 msm_otg_reset(otg->phy);
Vijayavardhan Vennapusaa3152032012-03-05 16:29:30 +05302943 if (!test_bit(ID_A, &motg->inputs))
2944 msm_hsusb_vbus_power(motg, 0);
2945 msm_otg_start_timer(motg, TA_WAIT_VFALL, A_WAIT_VFALL);
2946 } else if (!test_bit(A_VBUS_VLD, &motg->inputs)) {
2947 pr_debug("!a_vbus_vld\n");
2948 msm_otg_del_timer(motg);
2949 clear_bit(B_CONN, &motg->inputs);
Steve Mucklef132c6c2012-06-06 18:30:57 -07002950 otg->phy->state = OTG_STATE_A_VBUS_ERR;
Vijayavardhan Vennapusaa3152032012-03-05 16:29:30 +05302951 msm_otg_start_host(otg, 0);
Steve Mucklef132c6c2012-06-06 18:30:57 -07002952 msm_otg_reset(otg->phy);
Vijayavardhan Vennapusaa3152032012-03-05 16:29:30 +05302953 } else if (!test_bit(B_CONN, &motg->inputs) &&
2954 otg->host->b_hnp_enable) {
2955 pr_debug("!b_conn && b_hnp_enable");
Steve Mucklef132c6c2012-06-06 18:30:57 -07002956 otg->phy->state = OTG_STATE_A_PERIPHERAL;
Vijayavardhan Vennapusaa3152032012-03-05 16:29:30 +05302957 msm_otg_host_hnp_enable(otg, 1);
2958 otg->gadget->is_a_peripheral = 1;
2959 msm_otg_start_peripheral(otg, 1);
2960 } else if (!test_bit(B_CONN, &motg->inputs) &&
2961 !otg->host->b_hnp_enable) {
2962 pr_debug("!b_conn && !b_hnp_enable");
2963 /*
2964 * bus request is dropped during suspend.
2965 * acquire again for next device.
2966 */
2967 set_bit(A_BUS_REQ, &motg->inputs);
Steve Mucklef132c6c2012-06-06 18:30:57 -07002968 otg->phy->state = OTG_STATE_A_WAIT_BCON;
Vijayavardhan Vennapusaa3152032012-03-05 16:29:30 +05302969 if (TA_WAIT_BCON > 0)
2970 msm_otg_start_timer(motg, TA_WAIT_BCON,
2971 A_WAIT_BCON);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002972 } else if (test_bit(ID_A, &motg->inputs)) {
Mayank Ranae3926882011-12-26 09:47:54 +05302973 msm_hsusb_vbus_power(motg, 0);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002974 msm_otg_notify_charger(motg,
Vijayavardhan Vennapusaa3152032012-03-05 16:29:30 +05302975 IDEV_CHG_MIN - motg->mA_port);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002976 } else if (!test_bit(ID, &motg->inputs)) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002977 msm_otg_notify_charger(motg, 0);
Mayank Ranae3926882011-12-26 09:47:54 +05302978 msm_hsusb_vbus_power(motg, 1);
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05302979 }
2980 break;
Vijayavardhan Vennapusaa3152032012-03-05 16:29:30 +05302981 case OTG_STATE_A_PERIPHERAL:
2982 if ((test_bit(ID, &motg->inputs) &&
2983 !test_bit(ID_A, &motg->inputs)) ||
2984 test_bit(A_BUS_DROP, &motg->inputs)) {
2985 pr_debug("id _f/b/c || a_bus_drop\n");
2986 /* Clear BIDL_ADIS timer */
2987 msm_otg_del_timer(motg);
Steve Mucklef132c6c2012-06-06 18:30:57 -07002988 otg->phy->state = OTG_STATE_A_WAIT_VFALL;
Vijayavardhan Vennapusaa3152032012-03-05 16:29:30 +05302989 msm_otg_start_peripheral(otg, 0);
2990 otg->gadget->is_a_peripheral = 0;
2991 msm_otg_start_host(otg, 0);
Steve Mucklef132c6c2012-06-06 18:30:57 -07002992 msm_otg_reset(otg->phy);
Vijayavardhan Vennapusaa3152032012-03-05 16:29:30 +05302993 if (!test_bit(ID_A, &motg->inputs))
2994 msm_hsusb_vbus_power(motg, 0);
2995 msm_otg_start_timer(motg, TA_WAIT_VFALL, A_WAIT_VFALL);
2996 } else if (!test_bit(A_VBUS_VLD, &motg->inputs)) {
2997 pr_debug("!a_vbus_vld\n");
2998 /* Clear BIDL_ADIS timer */
2999 msm_otg_del_timer(motg);
Steve Mucklef132c6c2012-06-06 18:30:57 -07003000 otg->phy->state = OTG_STATE_A_VBUS_ERR;
Vijayavardhan Vennapusaa3152032012-03-05 16:29:30 +05303001 msm_otg_start_peripheral(otg, 0);
3002 otg->gadget->is_a_peripheral = 0;
3003 msm_otg_start_host(otg, 0);
3004 } else if (test_bit(A_BIDL_ADIS, &motg->tmouts)) {
3005 pr_debug("a_bidl_adis_tmout\n");
3006 msm_otg_start_peripheral(otg, 0);
3007 otg->gadget->is_a_peripheral = 0;
Steve Mucklef132c6c2012-06-06 18:30:57 -07003008 otg->phy->state = OTG_STATE_A_WAIT_BCON;
Vijayavardhan Vennapusaa3152032012-03-05 16:29:30 +05303009 set_bit(A_BUS_REQ, &motg->inputs);
3010 msm_otg_host_hnp_enable(otg, 0);
3011 if (TA_WAIT_BCON > 0)
3012 msm_otg_start_timer(motg, TA_WAIT_BCON,
3013 A_WAIT_BCON);
3014 } else if (test_bit(ID_A, &motg->inputs)) {
3015 msm_hsusb_vbus_power(motg, 0);
3016 msm_otg_notify_charger(motg,
3017 IDEV_CHG_MIN - motg->mA_port);
3018 } else if (!test_bit(ID, &motg->inputs)) {
3019 msm_otg_notify_charger(motg, 0);
3020 msm_hsusb_vbus_power(motg, 1);
3021 }
3022 break;
3023 case OTG_STATE_A_WAIT_VFALL:
3024 if (test_bit(A_WAIT_VFALL, &motg->tmouts)) {
3025 clear_bit(A_VBUS_VLD, &motg->inputs);
Steve Mucklef132c6c2012-06-06 18:30:57 -07003026 otg->phy->state = OTG_STATE_A_IDLE;
Vijayavardhan Vennapusaa3152032012-03-05 16:29:30 +05303027 work = 1;
3028 }
3029 break;
3030 case OTG_STATE_A_VBUS_ERR:
3031 if ((test_bit(ID, &motg->inputs) &&
3032 !test_bit(ID_A, &motg->inputs)) ||
3033 test_bit(A_BUS_DROP, &motg->inputs) ||
3034 test_bit(A_CLR_ERR, &motg->inputs)) {
Steve Mucklef132c6c2012-06-06 18:30:57 -07003035 otg->phy->state = OTG_STATE_A_WAIT_VFALL;
Vijayavardhan Vennapusaa3152032012-03-05 16:29:30 +05303036 if (!test_bit(ID_A, &motg->inputs))
3037 msm_hsusb_vbus_power(motg, 0);
3038 msm_otg_start_timer(motg, TA_WAIT_VFALL, A_WAIT_VFALL);
3039 motg->chg_state = USB_CHG_STATE_UNDEFINED;
3040 motg->chg_type = USB_INVALID_CHARGER;
3041 msm_otg_notify_charger(motg, 0);
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05303042 }
3043 break;
3044 default:
3045 break;
3046 }
Vijayavardhan Vennapusaa3152032012-03-05 16:29:30 +05303047 if (work)
3048 queue_work(system_nrt_wq, &motg->sm_work);
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05303049}
3050
Amit Blayd0fe07b2012-09-05 16:42:09 +03003051static void msm_otg_suspend_work(struct work_struct *w)
3052{
3053 struct msm_otg *motg =
3054 container_of(w, struct msm_otg, suspend_work.work);
Pavankumar Kondetie618bf82012-11-28 21:12:44 +05303055
3056 /* This work is only for device bus suspend */
3057 if (test_bit(A_BUS_SUSPEND, &motg->inputs))
3058 msm_otg_sm_work(&motg->sm_work);
Amit Blayd0fe07b2012-09-05 16:42:09 +03003059}
3060
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05303061static irqreturn_t msm_otg_irq(int irq, void *data)
3062{
3063 struct msm_otg *motg = data;
Steve Mucklef132c6c2012-06-06 18:30:57 -07003064 struct usb_otg *otg = motg->phy.otg;
Vijayavardhan Vennapusaa3152032012-03-05 16:29:30 +05303065 u32 otgsc = 0, usbsts, pc;
3066 bool work = 0;
3067 irqreturn_t ret = IRQ_HANDLED;
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05303068
Pavankumar Kondeti87c01042010-12-07 17:53:58 +05303069 if (atomic_read(&motg->in_lpm)) {
Manu Gautamf8c45642012-08-10 10:20:56 -07003070 pr_debug("OTG IRQ: %d in LPM\n", irq);
Pavankumar Kondeti87c01042010-12-07 17:53:58 +05303071 disable_irq_nosync(irq);
Manu Gautamf8c45642012-08-10 10:20:56 -07003072 motg->async_int = irq;
Jack Phamc7edb172012-08-13 15:32:39 -07003073 if (!atomic_read(&motg->pm_suspended))
Steve Mucklef132c6c2012-06-06 18:30:57 -07003074 pm_request_resume(otg->phy->dev);
Pavankumar Kondeti87c01042010-12-07 17:53:58 +05303075 return IRQ_HANDLED;
3076 }
3077
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003078 usbsts = readl(USB_USBSTS);
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05303079 otgsc = readl(USB_OTGSC);
Vijayavardhan Vennapusaa3152032012-03-05 16:29:30 +05303080
3081 if (!(otgsc & OTG_OTGSTS_MASK) && !(usbsts & OTG_USBSTS_MASK))
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05303082 return IRQ_NONE;
3083
3084 if ((otgsc & OTGSC_IDIS) && (otgsc & OTGSC_IDIE)) {
Pavankumar Kondetiaa449e12011-11-04 11:09:26 +05303085 if (otgsc & OTGSC_ID) {
Stephen Boyd9850acb2013-01-28 14:11:20 -08003086 dev_dbg(otg->phy->dev, "ID set\n");
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05303087 set_bit(ID, &motg->inputs);
Pavankumar Kondetiaa449e12011-11-04 11:09:26 +05303088 } else {
Stephen Boyd9850acb2013-01-28 14:11:20 -08003089 dev_dbg(otg->phy->dev, "ID clear\n");
Vijayavardhan Vennapusaa3152032012-03-05 16:29:30 +05303090 /*
3091 * Assert a_bus_req to supply power on
3092 * VBUS when Micro/Mini-A cable is connected
3093 * with out user intervention.
3094 */
3095 set_bit(A_BUS_REQ, &motg->inputs);
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05303096 clear_bit(ID, &motg->inputs);
Pavankumar Kondetiaa449e12011-11-04 11:09:26 +05303097 msm_chg_enable_aca_det(motg);
3098 }
Vijayavardhan Vennapusaa3152032012-03-05 16:29:30 +05303099 writel_relaxed(otgsc, USB_OTGSC);
3100 work = 1;
3101 } else if (otgsc & OTGSC_DPIS) {
3102 pr_debug("DPIS detected\n");
3103 writel_relaxed(otgsc, USB_OTGSC);
3104 set_bit(A_SRP_DET, &motg->inputs);
3105 set_bit(A_BUS_REQ, &motg->inputs);
3106 work = 1;
Vamsi Krishnaef6e1bf2013-03-02 15:36:17 -08003107 } else if ((otgsc & OTGSC_BSVIE) && (otgsc & OTGSC_BSVIS)) {
Vijayavardhan Vennapusaa3152032012-03-05 16:29:30 +05303108 writel_relaxed(otgsc, USB_OTGSC);
3109 /*
3110 * BSV interrupt comes when operating as an A-device
3111 * (VBUS on/off).
3112 * But, handle BSV when charger is removed from ACA in ID_A
3113 */
Steve Mucklef132c6c2012-06-06 18:30:57 -07003114 if ((otg->phy->state >= OTG_STATE_A_IDLE) &&
Vijayavardhan Vennapusaa3152032012-03-05 16:29:30 +05303115 !test_bit(ID_A, &motg->inputs))
3116 return IRQ_HANDLED;
Pavankumar Kondetiaa449e12011-11-04 11:09:26 +05303117 if (otgsc & OTGSC_BSV) {
Stephen Boyd9850acb2013-01-28 14:11:20 -08003118 dev_dbg(otg->phy->dev, "BSV set\n");
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05303119 set_bit(B_SESS_VLD, &motg->inputs);
Pavankumar Kondetiaa449e12011-11-04 11:09:26 +05303120 } else {
Stephen Boyd9850acb2013-01-28 14:11:20 -08003121 dev_dbg(otg->phy->dev, "BSV clear\n");
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05303122 clear_bit(B_SESS_VLD, &motg->inputs);
Amit Blay6fa647a2012-05-24 14:12:08 +03003123 clear_bit(A_BUS_SUSPEND, &motg->inputs);
3124
Pavankumar Kondetiaa449e12011-11-04 11:09:26 +05303125 msm_chg_check_aca_intr(motg);
3126 }
Vijayavardhan Vennapusaa3152032012-03-05 16:29:30 +05303127 work = 1;
3128 } else if (usbsts & STS_PCI) {
3129 pc = readl_relaxed(USB_PORTSC);
3130 pr_debug("portsc = %x\n", pc);
3131 ret = IRQ_NONE;
3132 /*
3133 * HCD Acks PCI interrupt. We use this to switch
3134 * between different OTG states.
3135 */
3136 work = 1;
Steve Mucklef132c6c2012-06-06 18:30:57 -07003137 switch (otg->phy->state) {
Vijayavardhan Vennapusaa3152032012-03-05 16:29:30 +05303138 case OTG_STATE_A_SUSPEND:
3139 if (otg->host->b_hnp_enable && (pc & PORTSC_CSC) &&
3140 !(pc & PORTSC_CCS)) {
3141 pr_debug("B_CONN clear\n");
3142 clear_bit(B_CONN, &motg->inputs);
3143 msm_otg_del_timer(motg);
3144 }
3145 break;
3146 case OTG_STATE_A_PERIPHERAL:
3147 /*
3148 * A-peripheral observed activity on bus.
3149 * clear A_BIDL_ADIS timer.
3150 */
3151 msm_otg_del_timer(motg);
3152 work = 0;
3153 break;
3154 case OTG_STATE_B_WAIT_ACON:
3155 if ((pc & PORTSC_CSC) && (pc & PORTSC_CCS)) {
3156 pr_debug("A_CONN set\n");
3157 set_bit(A_CONN, &motg->inputs);
3158 /* Clear ASE0_BRST timer */
3159 msm_otg_del_timer(motg);
3160 }
3161 break;
3162 case OTG_STATE_B_HOST:
3163 if ((pc & PORTSC_CSC) && !(pc & PORTSC_CCS)) {
3164 pr_debug("A_CONN clear\n");
3165 clear_bit(A_CONN, &motg->inputs);
3166 msm_otg_del_timer(motg);
3167 }
3168 break;
3169 case OTG_STATE_A_WAIT_BCON:
3170 if (TA_WAIT_BCON < 0)
3171 set_bit(A_BUS_REQ, &motg->inputs);
3172 default:
3173 work = 0;
3174 break;
3175 }
3176 } else if (usbsts & STS_URI) {
3177 ret = IRQ_NONE;
Steve Mucklef132c6c2012-06-06 18:30:57 -07003178 switch (otg->phy->state) {
Vijayavardhan Vennapusaa3152032012-03-05 16:29:30 +05303179 case OTG_STATE_A_PERIPHERAL:
3180 /*
3181 * A-peripheral observed activity on bus.
3182 * clear A_BIDL_ADIS timer.
3183 */
3184 msm_otg_del_timer(motg);
3185 work = 0;
3186 break;
3187 default:
3188 work = 0;
3189 break;
3190 }
3191 } else if (usbsts & STS_SLI) {
3192 ret = IRQ_NONE;
3193 work = 0;
Steve Mucklef132c6c2012-06-06 18:30:57 -07003194 switch (otg->phy->state) {
Vijayavardhan Vennapusaa3152032012-03-05 16:29:30 +05303195 case OTG_STATE_B_PERIPHERAL:
3196 if (otg->gadget->b_hnp_enable) {
3197 set_bit(A_BUS_SUSPEND, &motg->inputs);
3198 set_bit(B_BUS_REQ, &motg->inputs);
3199 work = 1;
3200 }
3201 break;
3202 case OTG_STATE_A_PERIPHERAL:
3203 msm_otg_start_timer(motg, TA_BIDL_ADIS,
3204 A_BIDL_ADIS);
3205 break;
3206 default:
3207 break;
3208 }
3209 } else if ((usbsts & PHY_ALT_INT)) {
3210 writel_relaxed(PHY_ALT_INT, USB_USBSTS);
3211 if (msm_chg_check_aca_intr(motg))
3212 work = 1;
3213 ret = IRQ_HANDLED;
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05303214 }
Vijayavardhan Vennapusaa3152032012-03-05 16:29:30 +05303215 if (work)
3216 queue_work(system_nrt_wq, &motg->sm_work);
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05303217
Vijayavardhan Vennapusaa3152032012-03-05 16:29:30 +05303218 return ret;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003219}
3220
3221static void msm_otg_set_vbus_state(int online)
3222{
Pavankumar Kondeti4960f312011-12-06 15:46:14 +05303223 static bool init;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003224 struct msm_otg *motg = the_msm_otg;
Mayank Ranabaf31f42012-07-05 09:43:54 +05303225
Vamsi Krishna945b4a92013-03-02 15:31:16 -08003226 if (online) {
3227 pr_debug("PMIC: BSV set\n");
3228 set_bit(B_SESS_VLD, &motg->inputs);
3229 } else {
3230 pr_debug("PMIC: BSV clear\n");
3231 clear_bit(B_SESS_VLD, &motg->inputs);
3232 }
3233
3234 /* do not queue state m/c work if id is grounded */
Pavankumar Kondetibbaa46ff2012-12-09 20:21:02 +05303235 if (!test_bit(ID, &motg->inputs)) {
3236 /*
3237 * state machine work waits for initial VBUS
3238 * completion in UNDEFINED state. Process
3239 * the initial VBUS event in ID_GND state.
3240 */
3241 if (init)
3242 return;
Pavankumar Kondetibbaa46ff2012-12-09 20:21:02 +05303243 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003244
Pavankumar Kondeti4960f312011-12-06 15:46:14 +05303245 if (!init) {
3246 init = true;
3247 complete(&pmic_vbus_init);
3248 pr_debug("PMIC: BSV init complete\n");
3249 return;
3250 }
3251
Pavankumar Kondeti2aec9f32012-06-13 09:06:03 +05303252 if (test_bit(MHL, &motg->inputs) ||
3253 mhl_det_in_progress) {
3254 pr_debug("PMIC: BSV interrupt ignored in MHL\n");
3255 return;
3256 }
3257
Jack Pham5ca279b2012-05-14 18:42:54 -07003258 if (atomic_read(&motg->pm_suspended))
3259 motg->sm_work_pending = true;
3260 else
3261 queue_work(system_nrt_wq, &motg->sm_work);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003262}
3263
Vijayavardhan Vennapusa68d55cf2012-06-27 20:06:12 +05303264static void msm_pmic_id_status_w(struct work_struct *w)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003265{
Vijayavardhan Vennapusa68d55cf2012-06-27 20:06:12 +05303266 struct msm_otg *motg = container_of(w, struct msm_otg,
3267 pmic_id_status_work.work);
3268 int work = 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003269
Pavankumar Kondetibecab5b2012-11-06 16:45:10 +05303270 if (msm_otg_read_pmic_id_state(motg)) {
Vijayavardhan Vennapusa68d55cf2012-06-27 20:06:12 +05303271 if (!test_and_set_bit(ID, &motg->inputs)) {
3272 pr_debug("PMIC: ID set\n");
3273 work = 1;
3274 }
Pavankumar Kondeti4960f312011-12-06 15:46:14 +05303275 } else {
Vijayavardhan Vennapusa68d55cf2012-06-27 20:06:12 +05303276 if (test_and_clear_bit(ID, &motg->inputs)) {
3277 pr_debug("PMIC: ID clear\n");
3278 set_bit(A_BUS_REQ, &motg->inputs);
3279 work = 1;
3280 }
Pavankumar Kondeti4960f312011-12-06 15:46:14 +05303281 }
3282
Vijayavardhan Vennapusa68d55cf2012-06-27 20:06:12 +05303283 if (work && (motg->phy.state != OTG_STATE_UNDEFINED)) {
Jack Pham5ca279b2012-05-14 18:42:54 -07003284 if (atomic_read(&motg->pm_suspended))
3285 motg->sm_work_pending = true;
3286 else
3287 queue_work(system_nrt_wq, &motg->sm_work);
3288 }
Vijayavardhan Vennapusa68d55cf2012-06-27 20:06:12 +05303289
3290}
3291
3292#define MSM_PMIC_ID_STATUS_DELAY 5 /* 5msec */
3293static irqreturn_t msm_pmic_id_irq(int irq, void *data)
3294{
3295 struct msm_otg *motg = data;
3296
Pavankumar Kondeti2aec9f32012-06-13 09:06:03 +05303297 if (test_bit(MHL, &motg->inputs) ||
3298 mhl_det_in_progress) {
3299 pr_debug("PMIC: Id interrupt ignored in MHL\n");
3300 return IRQ_HANDLED;
3301 }
3302
Vijayavardhan Vennapusa68d55cf2012-06-27 20:06:12 +05303303 if (!aca_id_turned_on)
3304 /*schedule delayed work for 5msec for ID line state to settle*/
3305 queue_delayed_work(system_nrt_wq, &motg->pmic_id_status_work,
3306 msecs_to_jiffies(MSM_PMIC_ID_STATUS_DELAY));
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003307
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05303308 return IRQ_HANDLED;
3309}
3310
3311static int msm_otg_mode_show(struct seq_file *s, void *unused)
3312{
3313 struct msm_otg *motg = s->private;
Stephen Boyd9850acb2013-01-28 14:11:20 -08003314 struct usb_otg *otg = motg->phy.otg;
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05303315
Stephen Boyd9850acb2013-01-28 14:11:20 -08003316 switch (otg->phy->state) {
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05303317 case OTG_STATE_A_HOST:
3318 seq_printf(s, "host\n");
3319 break;
3320 case OTG_STATE_B_PERIPHERAL:
3321 seq_printf(s, "peripheral\n");
3322 break;
3323 default:
3324 seq_printf(s, "none\n");
3325 break;
3326 }
3327
3328 return 0;
3329}
3330
3331static int msm_otg_mode_open(struct inode *inode, struct file *file)
3332{
3333 return single_open(file, msm_otg_mode_show, inode->i_private);
3334}
3335
3336static ssize_t msm_otg_mode_write(struct file *file, const char __user *ubuf,
3337 size_t count, loff_t *ppos)
3338{
Pavankumar Kondetie2904ee2011-02-15 09:42:35 +05303339 struct seq_file *s = file->private_data;
3340 struct msm_otg *motg = s->private;
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05303341 char buf[16];
Steve Mucklef132c6c2012-06-06 18:30:57 -07003342 struct usb_phy *phy = &motg->phy;
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05303343 int status = count;
3344 enum usb_mode_type req_mode;
3345
3346 memset(buf, 0x00, sizeof(buf));
3347
3348 if (copy_from_user(&buf, ubuf, min_t(size_t, sizeof(buf) - 1, count))) {
3349 status = -EFAULT;
3350 goto out;
3351 }
3352
3353 if (!strncmp(buf, "host", 4)) {
3354 req_mode = USB_HOST;
3355 } else if (!strncmp(buf, "peripheral", 10)) {
3356 req_mode = USB_PERIPHERAL;
3357 } else if (!strncmp(buf, "none", 4)) {
3358 req_mode = USB_NONE;
3359 } else {
3360 status = -EINVAL;
3361 goto out;
3362 }
3363
3364 switch (req_mode) {
3365 case USB_NONE:
Steve Mucklef132c6c2012-06-06 18:30:57 -07003366 switch (phy->state) {
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05303367 case OTG_STATE_A_HOST:
3368 case OTG_STATE_B_PERIPHERAL:
3369 set_bit(ID, &motg->inputs);
3370 clear_bit(B_SESS_VLD, &motg->inputs);
3371 break;
3372 default:
3373 goto out;
3374 }
3375 break;
3376 case USB_PERIPHERAL:
Steve Mucklef132c6c2012-06-06 18:30:57 -07003377 switch (phy->state) {
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05303378 case OTG_STATE_B_IDLE:
3379 case OTG_STATE_A_HOST:
3380 set_bit(ID, &motg->inputs);
3381 set_bit(B_SESS_VLD, &motg->inputs);
3382 break;
3383 default:
3384 goto out;
3385 }
3386 break;
3387 case USB_HOST:
Steve Mucklef132c6c2012-06-06 18:30:57 -07003388 switch (phy->state) {
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05303389 case OTG_STATE_B_IDLE:
3390 case OTG_STATE_B_PERIPHERAL:
3391 clear_bit(ID, &motg->inputs);
3392 break;
3393 default:
3394 goto out;
3395 }
3396 break;
3397 default:
3398 goto out;
3399 }
3400
Steve Mucklef132c6c2012-06-06 18:30:57 -07003401 pm_runtime_resume(phy->dev);
Vijayavardhan Vennapusaa3152032012-03-05 16:29:30 +05303402 queue_work(system_nrt_wq, &motg->sm_work);
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05303403out:
3404 return status;
3405}
3406
3407const struct file_operations msm_otg_mode_fops = {
3408 .open = msm_otg_mode_open,
3409 .read = seq_read,
3410 .write = msm_otg_mode_write,
3411 .llseek = seq_lseek,
3412 .release = single_release,
3413};
3414
Chiranjeevi Velempatif9a11542012-03-28 18:18:34 +05303415static int msm_otg_show_otg_state(struct seq_file *s, void *unused)
3416{
3417 struct msm_otg *motg = s->private;
Steve Mucklef132c6c2012-06-06 18:30:57 -07003418 struct usb_phy *phy = &motg->phy;
Chiranjeevi Velempatif9a11542012-03-28 18:18:34 +05303419
Steve Mucklef132c6c2012-06-06 18:30:57 -07003420 seq_printf(s, "%s\n", otg_state_string(phy->state));
Chiranjeevi Velempatif9a11542012-03-28 18:18:34 +05303421 return 0;
3422}
3423
3424static int msm_otg_otg_state_open(struct inode *inode, struct file *file)
3425{
3426 return single_open(file, msm_otg_show_otg_state, inode->i_private);
3427}
3428
3429const struct file_operations msm_otg_state_fops = {
3430 .open = msm_otg_otg_state_open,
3431 .read = seq_read,
3432 .llseek = seq_lseek,
3433 .release = single_release,
3434};
3435
Anji jonnalad270e2d2011-08-09 11:28:32 +05303436static int msm_otg_show_chg_type(struct seq_file *s, void *unused)
3437{
3438 struct msm_otg *motg = s->private;
3439
Pavankumar Kondeti9ef69cb2011-12-12 14:18:22 +05303440 seq_printf(s, "%s\n", chg_to_string(motg->chg_type));
Anji jonnalad270e2d2011-08-09 11:28:32 +05303441 return 0;
3442}
3443
3444static int msm_otg_chg_open(struct inode *inode, struct file *file)
3445{
3446 return single_open(file, msm_otg_show_chg_type, inode->i_private);
3447}
3448
3449const struct file_operations msm_otg_chg_fops = {
3450 .open = msm_otg_chg_open,
3451 .read = seq_read,
3452 .llseek = seq_lseek,
3453 .release = single_release,
3454};
3455
Pavankumar Kondetiaa449e12011-11-04 11:09:26 +05303456static int msm_otg_aca_show(struct seq_file *s, void *unused)
3457{
3458 if (debug_aca_enabled)
3459 seq_printf(s, "enabled\n");
3460 else
3461 seq_printf(s, "disabled\n");
3462
3463 return 0;
3464}
3465
3466static int msm_otg_aca_open(struct inode *inode, struct file *file)
3467{
3468 return single_open(file, msm_otg_aca_show, inode->i_private);
3469}
3470
3471static ssize_t msm_otg_aca_write(struct file *file, const char __user *ubuf,
3472 size_t count, loff_t *ppos)
3473{
3474 char buf[8];
3475
3476 memset(buf, 0x00, sizeof(buf));
3477
3478 if (copy_from_user(&buf, ubuf, min_t(size_t, sizeof(buf) - 1, count)))
3479 return -EFAULT;
3480
3481 if (!strncmp(buf, "enable", 6))
3482 debug_aca_enabled = true;
3483 else
3484 debug_aca_enabled = false;
3485
3486 return count;
3487}
3488
3489const struct file_operations msm_otg_aca_fops = {
3490 .open = msm_otg_aca_open,
3491 .read = seq_read,
3492 .write = msm_otg_aca_write,
3493 .llseek = seq_lseek,
3494 .release = single_release,
3495};
3496
Manu Gautam8bdcc592012-03-06 11:26:06 +05303497static int msm_otg_bus_show(struct seq_file *s, void *unused)
3498{
3499 if (debug_bus_voting_enabled)
3500 seq_printf(s, "enabled\n");
3501 else
3502 seq_printf(s, "disabled\n");
3503
3504 return 0;
3505}
3506
3507static int msm_otg_bus_open(struct inode *inode, struct file *file)
3508{
3509 return single_open(file, msm_otg_bus_show, inode->i_private);
3510}
3511
3512static ssize_t msm_otg_bus_write(struct file *file, const char __user *ubuf,
3513 size_t count, loff_t *ppos)
3514{
3515 char buf[8];
Manu Gautam8bdcc592012-03-06 11:26:06 +05303516 struct seq_file *s = file->private_data;
3517 struct msm_otg *motg = s->private;
3518
3519 memset(buf, 0x00, sizeof(buf));
3520
3521 if (copy_from_user(&buf, ubuf, min_t(size_t, sizeof(buf) - 1, count)))
3522 return -EFAULT;
3523
3524 if (!strncmp(buf, "enable", 6)) {
3525 /* Do not vote here. Let OTG statemachine decide when to vote */
3526 debug_bus_voting_enabled = true;
3527 } else {
3528 debug_bus_voting_enabled = false;
Manu Gautame3a39082013-06-11 10:42:56 +05303529 msm_otg_bus_vote(motg, USB_MIN_PERF_VOTE);
Manu Gautam8bdcc592012-03-06 11:26:06 +05303530 }
3531
3532 return count;
3533}
3534
David Keitel272ce522012-08-17 16:25:24 -07003535static int otg_power_get_property_usb(struct power_supply *psy,
3536 enum power_supply_property psp,
3537 union power_supply_propval *val)
3538{
Jack Pham0c695282012-10-19 18:13:03 -07003539 struct msm_otg *motg = container_of(psy, struct msm_otg, usb_psy);
David Keitel272ce522012-08-17 16:25:24 -07003540 switch (psp) {
3541 case POWER_SUPPLY_PROP_SCOPE:
3542 if (motg->host_mode)
3543 val->intval = POWER_SUPPLY_SCOPE_SYSTEM;
3544 else
3545 val->intval = POWER_SUPPLY_SCOPE_DEVICE;
3546 break;
3547 case POWER_SUPPLY_PROP_CURRENT_MAX:
3548 val->intval = motg->current_max;
3549 break;
3550 /* Reflect USB enumeration */
3551 case POWER_SUPPLY_PROP_PRESENT:
3552 case POWER_SUPPLY_PROP_ONLINE:
3553 val->intval = motg->online;
3554 break;
3555 default:
3556 return -EINVAL;
3557 }
3558 return 0;
3559}
3560
3561static int otg_power_set_property_usb(struct power_supply *psy,
3562 enum power_supply_property psp,
3563 const union power_supply_propval *val)
3564{
Jack Pham0c695282012-10-19 18:13:03 -07003565 struct msm_otg *motg = container_of(psy, struct msm_otg, usb_psy);
David Keitel272ce522012-08-17 16:25:24 -07003566
3567 switch (psp) {
3568 /* Process PMIC notification in PRESENT prop */
3569 case POWER_SUPPLY_PROP_PRESENT:
3570 msm_otg_set_vbus_state(val->intval);
3571 break;
3572 /* The ONLINE property reflects if usb has enumerated */
3573 case POWER_SUPPLY_PROP_ONLINE:
3574 motg->online = val->intval;
3575 break;
3576 case POWER_SUPPLY_PROP_CURRENT_MAX:
3577 motg->current_max = val->intval;
3578 break;
3579 default:
3580 return -EINVAL;
3581 }
3582
3583 power_supply_changed(&motg->usb_psy);
3584 return 0;
3585}
3586
David Collinsd79acc52012-11-26 14:59:00 -08003587static int otg_power_property_is_writeable_usb(struct power_supply *psy,
3588 enum power_supply_property psp)
3589{
3590 switch (psp) {
3591 case POWER_SUPPLY_PROP_PRESENT:
3592 case POWER_SUPPLY_PROP_ONLINE:
3593 case POWER_SUPPLY_PROP_CURRENT_MAX:
3594 return 1;
3595 default:
3596 break;
3597 }
3598
3599 return 0;
3600}
3601
David Keitel272ce522012-08-17 16:25:24 -07003602static char *otg_pm_power_supplied_to[] = {
3603 "battery",
3604};
3605
3606static enum power_supply_property otg_pm_power_props_usb[] = {
3607 POWER_SUPPLY_PROP_PRESENT,
3608 POWER_SUPPLY_PROP_ONLINE,
3609 POWER_SUPPLY_PROP_CURRENT_MAX,
3610 POWER_SUPPLY_PROP_SCOPE,
3611};
3612
Manu Gautam8bdcc592012-03-06 11:26:06 +05303613const struct file_operations msm_otg_bus_fops = {
3614 .open = msm_otg_bus_open,
3615 .read = seq_read,
3616 .write = msm_otg_bus_write,
3617 .llseek = seq_lseek,
3618 .release = single_release,
3619};
3620
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05303621static struct dentry *msm_otg_dbg_root;
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05303622
3623static int msm_otg_debugfs_init(struct msm_otg *motg)
3624{
Manu Gautam8bdcc592012-03-06 11:26:06 +05303625 struct dentry *msm_otg_dentry;
Anji jonnalad270e2d2011-08-09 11:28:32 +05303626
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05303627 msm_otg_dbg_root = debugfs_create_dir("msm_otg", NULL);
3628
3629 if (!msm_otg_dbg_root || IS_ERR(msm_otg_dbg_root))
3630 return -ENODEV;
3631
Anji jonnalad270e2d2011-08-09 11:28:32 +05303632 if (motg->pdata->mode == USB_OTG &&
3633 motg->pdata->otg_control == OTG_USER_CONTROL) {
3634
Manu Gautam8bdcc592012-03-06 11:26:06 +05303635 msm_otg_dentry = debugfs_create_file("mode", S_IRUGO |
Anji jonnalad270e2d2011-08-09 11:28:32 +05303636 S_IWUSR, msm_otg_dbg_root, motg,
3637 &msm_otg_mode_fops);
3638
Manu Gautam8bdcc592012-03-06 11:26:06 +05303639 if (!msm_otg_dentry) {
Anji jonnalad270e2d2011-08-09 11:28:32 +05303640 debugfs_remove(msm_otg_dbg_root);
3641 msm_otg_dbg_root = NULL;
3642 return -ENODEV;
3643 }
3644 }
3645
Manu Gautam8bdcc592012-03-06 11:26:06 +05303646 msm_otg_dentry = debugfs_create_file("chg_type", S_IRUGO,
Anji jonnalad270e2d2011-08-09 11:28:32 +05303647 msm_otg_dbg_root, motg,
3648 &msm_otg_chg_fops);
3649
Manu Gautam8bdcc592012-03-06 11:26:06 +05303650 if (!msm_otg_dentry) {
Pavankumar Kondetiaa449e12011-11-04 11:09:26 +05303651 debugfs_remove_recursive(msm_otg_dbg_root);
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05303652 return -ENODEV;
3653 }
3654
Manu Gautam8bdcc592012-03-06 11:26:06 +05303655 msm_otg_dentry = debugfs_create_file("aca", S_IRUGO | S_IWUSR,
Pavankumar Kondetiaa449e12011-11-04 11:09:26 +05303656 msm_otg_dbg_root, motg,
3657 &msm_otg_aca_fops);
3658
Manu Gautam8bdcc592012-03-06 11:26:06 +05303659 if (!msm_otg_dentry) {
Pavankumar Kondetiaa449e12011-11-04 11:09:26 +05303660 debugfs_remove_recursive(msm_otg_dbg_root);
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05303661 return -ENODEV;
3662 }
3663
Manu Gautam8bdcc592012-03-06 11:26:06 +05303664 msm_otg_dentry = debugfs_create_file("bus_voting", S_IRUGO | S_IWUSR,
3665 msm_otg_dbg_root, motg,
3666 &msm_otg_bus_fops);
3667
3668 if (!msm_otg_dentry) {
3669 debugfs_remove_recursive(msm_otg_dbg_root);
3670 return -ENODEV;
3671 }
Chiranjeevi Velempatif9a11542012-03-28 18:18:34 +05303672
3673 msm_otg_dentry = debugfs_create_file("otg_state", S_IRUGO,
3674 msm_otg_dbg_root, motg, &msm_otg_state_fops);
3675
3676 if (!msm_otg_dentry) {
3677 debugfs_remove_recursive(msm_otg_dbg_root);
3678 return -ENODEV;
3679 }
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05303680 return 0;
3681}
3682
3683static void msm_otg_debugfs_cleanup(void)
3684{
Anji jonnalad270e2d2011-08-09 11:28:32 +05303685 debugfs_remove_recursive(msm_otg_dbg_root);
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05303686}
3687
Manu Gautam0ddbd922012-09-21 17:17:38 +05303688#define MSM_OTG_CMD_ID 0x09
3689#define MSM_OTG_DEVICE_ID 0x04
3690#define MSM_OTG_VMID_IDX 0xFF
3691#define MSM_OTG_MEM_TYPE 0x02
3692struct msm_otg_scm_cmd_buf {
3693 unsigned int device_id;
3694 unsigned int vmid_idx;
3695 unsigned int mem_type;
3696} __attribute__ ((__packed__));
3697
3698static void msm_otg_pnoc_errata_fix(struct msm_otg *motg)
3699{
3700 int ret;
3701 struct msm_otg_platform_data *pdata = motg->pdata;
3702 struct msm_otg_scm_cmd_buf cmd_buf;
3703
3704 if (!pdata->pnoc_errata_fix)
3705 return;
3706
3707 dev_dbg(motg->phy.dev, "applying fix for pnoc h/w issue\n");
3708
3709 cmd_buf.device_id = MSM_OTG_DEVICE_ID;
3710 cmd_buf.vmid_idx = MSM_OTG_VMID_IDX;
3711 cmd_buf.mem_type = MSM_OTG_MEM_TYPE;
3712
Syed Rameez Mustafa6ab6af32013-03-18 12:53:11 -07003713 ret = scm_call(SCM_SVC_MP, MSM_OTG_CMD_ID, &cmd_buf,
Manu Gautam0ddbd922012-09-21 17:17:38 +05303714 sizeof(cmd_buf), NULL, 0);
3715
3716 if (ret)
3717 dev_err(motg->phy.dev, "scm command failed to update VMIDMT\n");
3718}
3719
Pavankumar Kondetieaea7fe2011-10-27 14:46:45 +05303720static u64 msm_otg_dma_mask = DMA_BIT_MASK(64);
3721static struct platform_device *msm_otg_add_pdev(
3722 struct platform_device *ofdev, const char *name)
3723{
3724 struct platform_device *pdev;
3725 const struct resource *res = ofdev->resource;
3726 unsigned int num = ofdev->num_resources;
3727 int retval;
Amit Blayb4f14532013-06-17 22:33:57 +03003728 struct ci13xxx_platform_data ci_pdata;
3729 struct msm_otg_platform_data *otg_pdata;
Pavankumar Kondetieaea7fe2011-10-27 14:46:45 +05303730
3731 pdev = platform_device_alloc(name, -1);
3732 if (!pdev) {
3733 retval = -ENOMEM;
3734 goto error;
3735 }
3736
3737 pdev->dev.coherent_dma_mask = DMA_BIT_MASK(32);
3738 pdev->dev.dma_mask = &msm_otg_dma_mask;
3739
3740 if (num) {
3741 retval = platform_device_add_resources(pdev, res, num);
3742 if (retval)
3743 goto error;
3744 }
3745
Amit Blayb4f14532013-06-17 22:33:57 +03003746 if (!strcmp(name, "msm_hsusb")) {
3747 otg_pdata =
3748 (struct msm_otg_platform_data *)
3749 ofdev->dev.platform_data;
3750 ci_pdata.log2_itc = otg_pdata->log2_itc;
3751 ci_pdata.usb_core_id = 0;
Shimrit Malichi5a2d5b52013-06-20 19:04:28 +03003752 ci_pdata.l1_supported = otg_pdata->l1_supported;
Amit Blayb4f14532013-06-17 22:33:57 +03003753 retval = platform_device_add_data(pdev, &ci_pdata,
3754 sizeof(ci_pdata));
3755 if (retval)
3756 goto error;
3757 }
3758
Pavankumar Kondetieaea7fe2011-10-27 14:46:45 +05303759 retval = platform_device_add(pdev);
3760 if (retval)
3761 goto error;
3762
3763 return pdev;
3764
3765error:
3766 platform_device_put(pdev);
3767 return ERR_PTR(retval);
3768}
3769
3770static int msm_otg_setup_devices(struct platform_device *ofdev,
3771 enum usb_mode_type mode, bool init)
3772{
3773 const char *gadget_name = "msm_hsusb";
3774 const char *host_name = "msm_hsusb_host";
3775 static struct platform_device *gadget_pdev;
3776 static struct platform_device *host_pdev;
3777 int retval = 0;
3778
3779 if (!init) {
3780 if (gadget_pdev)
3781 platform_device_unregister(gadget_pdev);
3782 if (host_pdev)
3783 platform_device_unregister(host_pdev);
3784 return 0;
3785 }
3786
3787 switch (mode) {
3788 case USB_OTG:
3789 /* fall through */
3790 case USB_PERIPHERAL:
3791 gadget_pdev = msm_otg_add_pdev(ofdev, gadget_name);
3792 if (IS_ERR(gadget_pdev)) {
3793 retval = PTR_ERR(gadget_pdev);
3794 break;
3795 }
3796 if (mode == USB_PERIPHERAL)
3797 break;
3798 /* fall through */
3799 case USB_HOST:
3800 host_pdev = msm_otg_add_pdev(ofdev, host_name);
3801 if (IS_ERR(host_pdev)) {
3802 retval = PTR_ERR(host_pdev);
3803 if (mode == USB_OTG)
3804 platform_device_unregister(gadget_pdev);
3805 }
3806 break;
3807 default:
3808 break;
3809 }
3810
3811 return retval;
3812}
3813
David Keitel272ce522012-08-17 16:25:24 -07003814static int msm_otg_register_power_supply(struct platform_device *pdev,
3815 struct msm_otg *motg)
3816{
3817 int ret;
3818
3819 ret = power_supply_register(&pdev->dev, &motg->usb_psy);
3820 if (ret < 0) {
3821 dev_err(motg->phy.dev,
3822 "%s:power_supply_register usb failed\n",
3823 __func__);
3824 return ret;
3825 }
3826
3827 legacy_power_supply = false;
3828 return 0;
3829}
3830
Pavankumar Kondetieaea7fe2011-10-27 14:46:45 +05303831struct msm_otg_platform_data *msm_otg_dt_to_pdata(struct platform_device *pdev)
3832{
3833 struct device_node *node = pdev->dev.of_node;
3834 struct msm_otg_platform_data *pdata;
3835 int len = 0;
3836
3837 pdata = devm_kzalloc(&pdev->dev, sizeof(*pdata), GFP_KERNEL);
3838 if (!pdata) {
3839 pr_err("unable to allocate platform data\n");
3840 return NULL;
3841 }
3842 of_get_property(node, "qcom,hsusb-otg-phy-init-seq", &len);
3843 if (len) {
3844 pdata->phy_init_seq = devm_kzalloc(&pdev->dev, len, GFP_KERNEL);
3845 if (!pdata->phy_init_seq)
3846 return NULL;
3847 of_property_read_u32_array(node, "qcom,hsusb-otg-phy-init-seq",
3848 pdata->phy_init_seq,
3849 len/sizeof(*pdata->phy_init_seq));
3850 }
3851 of_property_read_u32(node, "qcom,hsusb-otg-power-budget",
3852 &pdata->power_budget);
3853 of_property_read_u32(node, "qcom,hsusb-otg-mode",
3854 &pdata->mode);
3855 of_property_read_u32(node, "qcom,hsusb-otg-otg-control",
3856 &pdata->otg_control);
3857 of_property_read_u32(node, "qcom,hsusb-otg-default-mode",
3858 &pdata->default_mode);
3859 of_property_read_u32(node, "qcom,hsusb-otg-phy-type",
3860 &pdata->phy_type);
Manu Gautambd53fba2012-07-31 16:13:06 +05303861 pdata->disable_reset_on_disconnect = of_property_read_bool(node,
3862 "qcom,hsusb-otg-disable-reset");
Manu Gautam0ddbd922012-09-21 17:17:38 +05303863 pdata->pnoc_errata_fix = of_property_read_bool(node,
3864 "qcom,hsusb-otg-pnoc-errata-fix");
Ido Shayevitza7114b92013-01-13 13:34:47 +02003865 pdata->enable_lpm_on_dev_suspend = of_property_read_bool(node,
3866 "qcom,hsusb-otg-lpm-on-dev-suspend");
Ido Shayevitz26193352013-01-21 23:16:54 +02003867 pdata->core_clk_always_on_workaround = of_property_read_bool(node,
3868 "qcom,hsusb-otg-clk-always-on-workaround");
Shimrit Malichiffab5b02013-03-10 11:06:16 +02003869 pdata->delay_lpm_on_disconnect = of_property_read_bool(node,
3870 "qcom,hsusb-otg-delay-lpm");
Lena Salmanabde35d2013-04-25 15:29:43 +03003871 pdata->delay_lpm_hndshk_on_disconnect = of_property_read_bool(node,
3872 "qcom,hsusb-otg-delay-lpm-hndshk-on-disconnect");
Vamsi Krishna1a1684b2013-03-02 16:14:52 -08003873 pdata->dp_manual_pullup = of_property_read_bool(node,
3874 "qcom,dp-manual-pullup");
Manu Gautam0fd2d0e2013-03-26 18:09:11 +05303875 pdata->enable_sec_phy = of_property_read_bool(node,
3876 "qcom,usb2-enable-hsphy2");
Amit Blayb4f14532013-06-17 22:33:57 +03003877 of_property_read_u32(node, "qcom,hsusb-log2-itc",
3878 &pdata->log2_itc);
Manu Gautambd53fba2012-07-31 16:13:06 +05303879
Vijayavardhan Vennapusa2239b2b2013-06-28 13:16:29 +05303880 of_property_read_u32(node, "qcom,hsusb-otg-mpm-dpsehv-int",
3881 &pdata->mpm_dpshv_int);
3882 of_property_read_u32(node, "qcom,hsusb-otg-mpm-dmsehv-int",
3883 &pdata->mpm_dmshv_int);
Manu Gautam0e0c53f2013-04-04 10:55:20 +05303884 pdata->pmic_id_irq = platform_get_irq_byname(pdev, "pmic_id_irq");
3885 if (pdata->pmic_id_irq < 0)
3886 pdata->pmic_id_irq = 0;
3887
Shimrit Malichi5a2d5b52013-06-20 19:04:28 +03003888 pdata->l1_supported = of_property_read_bool(node,
3889 "qcom,hsusb-l1-supported");
3890
Pavankumar Kondetieaea7fe2011-10-27 14:46:45 +05303891 return pdata;
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05303892}
3893
3894static int __init msm_otg_probe(struct platform_device *pdev)
3895{
Manu Gautamf8c45642012-08-10 10:20:56 -07003896 int ret = 0;
Mayank Rana0f286cf2013-02-27 11:43:27 +05303897 int len = 0;
3898 u32 tmp[3];
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05303899 struct resource *res;
3900 struct msm_otg *motg;
Heikki Krogerus1d4c9292012-02-13 13:24:09 +02003901 struct usb_phy *phy;
Pavankumar Kondetieaea7fe2011-10-27 14:46:45 +05303902 struct msm_otg_platform_data *pdata;
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05303903
3904 dev_info(&pdev->dev, "msm_otg probe\n");
Pavankumar Kondetieaea7fe2011-10-27 14:46:45 +05303905
3906 if (pdev->dev.of_node) {
3907 dev_dbg(&pdev->dev, "device tree enabled\n");
3908 pdata = msm_otg_dt_to_pdata(pdev);
3909 if (!pdata)
3910 return -ENOMEM;
Manu Gautam2e8ac102012-08-31 11:41:16 -07003911
3912 pdata->bus_scale_table = msm_bus_cl_get_pdata(pdev);
3913 if (!pdata->bus_scale_table)
3914 dev_dbg(&pdev->dev, "bus scaling is disabled\n");
3915
Amit Blayb4f14532013-06-17 22:33:57 +03003916 pdev->dev.platform_data = pdata;
Pavankumar Kondetieaea7fe2011-10-27 14:46:45 +05303917 ret = msm_otg_setup_devices(pdev, pdata->mode, true);
3918 if (ret) {
3919 dev_err(&pdev->dev, "devices setup failed\n");
3920 return ret;
3921 }
3922 } else if (!pdev->dev.platform_data) {
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05303923 dev_err(&pdev->dev, "No platform data given. Bailing out\n");
3924 return -ENODEV;
Pavankumar Kondetieaea7fe2011-10-27 14:46:45 +05303925 } else {
3926 pdata = pdev->dev.platform_data;
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05303927 }
3928
Manu Gautame3a39082013-06-11 10:42:56 +05303929 motg = devm_kzalloc(&pdev->dev, sizeof(struct msm_otg), GFP_KERNEL);
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05303930 if (!motg) {
3931 dev_err(&pdev->dev, "unable to allocate msm_otg\n");
3932 return -ENOMEM;
3933 }
3934
Manu Gautame3a39082013-06-11 10:42:56 +05303935 motg->phy.otg = devm_kzalloc(&pdev->dev, sizeof(struct usb_otg),
3936 GFP_KERNEL);
Heikki Krogerus1d4c9292012-02-13 13:24:09 +02003937 if (!motg->phy.otg) {
Steve Mucklef132c6c2012-06-06 18:30:57 -07003938 dev_err(&pdev->dev, "unable to allocate usb_otg\n");
Manu Gautame3a39082013-06-11 10:42:56 +05303939 return -ENOMEM;
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05303940 }
3941
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003942 the_msm_otg = motg;
Pavankumar Kondetieaea7fe2011-10-27 14:46:45 +05303943 motg->pdata = pdata;
Steve Mucklef132c6c2012-06-06 18:30:57 -07003944 phy = &motg->phy;
3945 phy->dev = &pdev->dev;
Anji jonnala0f73cac2011-05-04 10:19:46 +05303946
Manu Gautame3a39082013-06-11 10:42:56 +05303947 if (motg->pdata->bus_scale_table) {
3948 motg->bus_perf_client =
3949 msm_bus_scale_register_client(motg->pdata->bus_scale_table);
3950 if (!motg->bus_perf_client) {
3951 dev_err(motg->phy.dev, "%s: Failed to register BUS\n"
3952 "scaling client!!\n", __func__);
3953 } else {
3954 debug_bus_voting_enabled = true;
3955 /* Some platforms require BUS vote to control clocks */
3956 msm_otg_bus_vote(motg, USB_MIN_PERF_VOTE);
3957 }
3958 }
3959
Anji jonnala0f73cac2011-05-04 10:19:46 +05303960 /*
Pavankumar Kondetiaa449e12011-11-04 11:09:26 +05303961 * ACA ID_GND threshold range is overlapped with OTG ID_FLOAT. Hence
3962 * PHY treat ACA ID_GND as float and no interrupt is generated. But
3963 * PMIC can detect ACA ID_GND and generate an interrupt.
3964 */
3965 if (aca_enabled() && motg->pdata->otg_control != OTG_PMIC_CONTROL) {
3966 dev_err(&pdev->dev, "ACA can not be enabled without PMIC\n");
3967 ret = -EINVAL;
Manu Gautame3a39082013-06-11 10:42:56 +05303968 goto devote_bus_bw;
Pavankumar Kondetiaa449e12011-11-04 11:09:26 +05303969 }
3970
Ofir Cohen4da266f2012-01-03 10:19:29 +02003971 /* initialize reset counter */
3972 motg->reset_counter = 0;
3973
Amit Blay02eff132011-09-21 16:46:24 +03003974 /* Some targets don't support PHY clock. */
Manu Gautam5143b252012-01-05 19:25:23 -08003975 motg->phy_reset_clk = clk_get(&pdev->dev, "phy_clk");
Amit Blay02eff132011-09-21 16:46:24 +03003976 if (IS_ERR(motg->phy_reset_clk))
Manu Gautam5143b252012-01-05 19:25:23 -08003977 dev_err(&pdev->dev, "failed to get phy_clk\n");
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05303978
Pavankumar Kondeti923262e2012-04-20 15:34:24 +05303979 /*
3980 * Targets on which link uses asynchronous reset methodology,
3981 * free running clock is not required during the reset.
3982 */
Manu Gautam5143b252012-01-05 19:25:23 -08003983 motg->clk = clk_get(&pdev->dev, "alt_core_clk");
Pavankumar Kondeti923262e2012-04-20 15:34:24 +05303984 if (IS_ERR(motg->clk))
3985 dev_dbg(&pdev->dev, "alt_core_clk is not present\n");
3986 else
3987 clk_set_rate(motg->clk, 60000000);
Anji jonnala0f73cac2011-05-04 10:19:46 +05303988
3989 /*
Manu Gautam5143b252012-01-05 19:25:23 -08003990 * USB Core is running its protocol engine based on CORE CLK,
Anji jonnala0f73cac2011-05-04 10:19:46 +05303991 * CORE CLK must be running at >55Mhz for correct HSUSB
3992 * operation and USB core cannot tolerate frequency changes on
3993 * CORE CLK. For such USB cores, vote for maximum clk frequency
3994 * on pclk source
3995 */
Manu Gautam5143b252012-01-05 19:25:23 -08003996 motg->core_clk = clk_get(&pdev->dev, "core_clk");
3997 if (IS_ERR(motg->core_clk)) {
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05303998 motg->core_clk = NULL;
Manu Gautam5143b252012-01-05 19:25:23 -08003999 dev_err(&pdev->dev, "failed to get core_clk\n");
Pavankumar Kondetibc541332012-04-20 15:32:04 +05304000 ret = PTR_ERR(motg->core_clk);
Manu Gautam5143b252012-01-05 19:25:23 -08004001 goto put_clk;
4002 }
Mayank Rana3eaf28d2013-03-27 14:04:04 +05304003
4004 /*
4005 * Get Max supported clk frequency for USB Core CLK and request
4006 * to set the same.
4007 */
4008 motg->core_clk_rate = clk_round_rate(motg->core_clk, LONG_MAX);
4009 if (IS_ERR_VALUE(motg->core_clk_rate)) {
4010 dev_err(&pdev->dev, "fail to get core clk max freq.\n");
4011 } else {
4012 ret = clk_set_rate(motg->core_clk, motg->core_clk_rate);
4013 if (ret)
4014 dev_err(&pdev->dev, "fail to set core_clk freq:%d\n",
4015 ret);
4016 }
Manu Gautam5143b252012-01-05 19:25:23 -08004017
4018 motg->pclk = clk_get(&pdev->dev, "iface_clk");
4019 if (IS_ERR(motg->pclk)) {
4020 dev_err(&pdev->dev, "failed to get iface_clk\n");
4021 ret = PTR_ERR(motg->pclk);
4022 goto put_core_clk;
4023 }
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05304024
4025 res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
4026 if (!res) {
4027 dev_err(&pdev->dev, "failed to get platform resource mem\n");
4028 ret = -ENODEV;
Manu Gautam5143b252012-01-05 19:25:23 -08004029 goto put_pclk;
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05304030 }
4031
4032 motg->regs = ioremap(res->start, resource_size(res));
4033 if (!motg->regs) {
4034 dev_err(&pdev->dev, "ioremap failed\n");
4035 ret = -ENOMEM;
Manu Gautam5143b252012-01-05 19:25:23 -08004036 goto put_pclk;
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05304037 }
4038 dev_info(&pdev->dev, "OTG regs = %p\n", motg->regs);
4039
4040 motg->irq = platform_get_irq(pdev, 0);
4041 if (!motg->irq) {
4042 dev_err(&pdev->dev, "platform_get_irq failed\n");
4043 ret = -ENODEV;
4044 goto free_regs;
4045 }
4046
Manu Gautamf8c45642012-08-10 10:20:56 -07004047 motg->async_irq = platform_get_irq_byname(pdev, "async_irq");
4048 if (motg->async_irq < 0) {
4049 dev_dbg(&pdev->dev, "platform_get_irq for async_int failed\n");
4050 motg->async_irq = 0;
4051 }
4052
Vijayavardhan Vennapusa0cab6172013-02-20 19:51:15 +05304053 motg->xo_clk = clk_get(&pdev->dev, "xo");
4054 if (IS_ERR(motg->xo_clk)) {
4055 motg->xo_handle = msm_xo_get(MSM_XO_TCXO_D0, "usb");
4056 if (IS_ERR(motg->xo_handle)) {
4057 dev_err(&pdev->dev, "%s fail to get handle for TCXO\n",
4058 __func__);
4059 ret = PTR_ERR(motg->xo_handle);
4060 goto free_regs;
4061 } else {
4062 ret = msm_xo_mode_vote(motg->xo_handle, MSM_XO_MODE_ON);
4063 if (ret) {
4064 dev_err(&pdev->dev, "%s XO voting failed %d\n",
4065 __func__, ret);
4066 goto free_xo_handle;
4067 }
4068 }
4069 } else {
4070 ret = clk_prepare_enable(motg->xo_clk);
4071 if (ret) {
4072 dev_err(&pdev->dev, "%s failed to vote for TCXO %d\n",
4073 __func__, ret);
4074 goto free_xo_handle;
4075 }
Anji jonnala7da3f262011-12-02 17:22:14 -08004076 }
Anji jonnala11aa5c42011-05-04 10:19:48 +05304077
Anji jonnala7da3f262011-12-02 17:22:14 -08004078
Manu Gautam28b1bac2012-01-30 16:43:06 +05304079 clk_prepare_enable(motg->pclk);
Anji jonnala11aa5c42011-05-04 10:19:48 +05304080
Mayank Rana248698c2012-04-19 00:03:16 +05304081 motg->vdd_type = VDDCX_CORNER;
Mayank Rana0f286cf2013-02-27 11:43:27 +05304082 hsusb_vdd = devm_regulator_get(motg->phy.dev, "hsusb_vdd_dig");
4083 if (IS_ERR(hsusb_vdd)) {
4084 hsusb_vdd = devm_regulator_get(motg->phy.dev, "HSUSB_VDDCX");
4085 if (IS_ERR(hsusb_vdd)) {
Steve Mucklef132c6c2012-06-06 18:30:57 -07004086 dev_err(motg->phy.dev, "unable to get hsusb vddcx\n");
Mayank Rana0f286cf2013-02-27 11:43:27 +05304087 ret = PTR_ERR(hsusb_vdd);
Mayank Rana248698c2012-04-19 00:03:16 +05304088 goto devote_xo_handle;
4089 }
4090 motg->vdd_type = VDDCX;
Anji jonnala11aa5c42011-05-04 10:19:48 +05304091 }
4092
Mayank Rana0f286cf2013-02-27 11:43:27 +05304093 if (pdev->dev.of_node) {
4094 of_get_property(pdev->dev.of_node,
4095 "qcom,vdd-voltage-level",
4096 &len);
4097 if (len == sizeof(tmp)) {
4098 of_property_read_u32_array(pdev->dev.of_node,
4099 "qcom,vdd-voltage-level",
4100 tmp, len/sizeof(*tmp));
4101 vdd_val[motg->vdd_type][0] = tmp[0];
4102 vdd_val[motg->vdd_type][1] = tmp[1];
4103 vdd_val[motg->vdd_type][2] = tmp[2];
4104 } else {
4105 dev_dbg(&pdev->dev, "Using default hsusb vdd config.\n");
4106 }
4107 }
4108
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004109 ret = msm_hsusb_config_vddcx(1);
Anji jonnala11aa5c42011-05-04 10:19:48 +05304110 if (ret) {
4111 dev_err(&pdev->dev, "hsusb vddcx configuration failed\n");
Mayank Rana248698c2012-04-19 00:03:16 +05304112 goto devote_xo_handle;
4113 }
4114
Mayank Rana0f286cf2013-02-27 11:43:27 +05304115 ret = regulator_enable(hsusb_vdd);
Mayank Rana248698c2012-04-19 00:03:16 +05304116 if (ret) {
4117 dev_err(&pdev->dev, "unable to enable the hsusb vddcx\n");
4118 goto free_config_vddcx;
Anji jonnala11aa5c42011-05-04 10:19:48 +05304119 }
4120
4121 ret = msm_hsusb_ldo_init(motg, 1);
4122 if (ret) {
4123 dev_err(&pdev->dev, "hsusb vreg configuration failed\n");
Mayank Rana0f286cf2013-02-27 11:43:27 +05304124 goto free_hsusb_vdd;
Anji jonnala11aa5c42011-05-04 10:19:48 +05304125 }
4126
Mayank Rana9e9a2ac2012-03-24 04:05:28 +05304127 if (pdata->mhl_enable) {
Pavankumar Kondeti56dc7422012-07-02 12:45:19 +05304128 mhl_usb_hs_switch = devm_regulator_get(motg->phy.dev,
4129 "mhl_usb_hs_switch");
4130 if (IS_ERR(mhl_usb_hs_switch)) {
4131 dev_err(&pdev->dev, "Unable to get mhl_usb_hs_switch\n");
Hemant Kumar41812392012-07-13 15:26:20 -07004132 ret = PTR_ERR(mhl_usb_hs_switch);
Mayank Rana9e9a2ac2012-03-24 04:05:28 +05304133 goto free_ldo_init;
4134 }
4135 }
4136
Amit Blay81801aa2012-09-19 12:08:12 +02004137 ret = msm_hsusb_ldo_enable(motg, USB_PHY_REG_ON);
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05304138 if (ret) {
4139 dev_err(&pdev->dev, "hsusb vreg enable failed\n");
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004140 goto free_ldo_init;
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05304141 }
Manu Gautam28b1bac2012-01-30 16:43:06 +05304142 clk_prepare_enable(motg->core_clk);
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05304143
Manu Gautam0ddbd922012-09-21 17:17:38 +05304144 /* Check if USB mem_type change is needed to workaround PNOC hw issue */
4145 msm_otg_pnoc_errata_fix(motg);
4146
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05304147 writel(0, USB_USBINTR);
4148 writel(0, USB_OTGSC);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004149 /* Ensure that above STOREs are completed before enabling interrupts */
4150 mb();
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05304151
Pavankumar Kondeti2aec9f32012-06-13 09:06:03 +05304152 ret = msm_otg_mhl_register_callback(motg, msm_otg_mhl_notify_online);
4153 if (ret)
4154 dev_dbg(&pdev->dev, "MHL can not be supported\n");
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004155 wake_lock_init(&motg->wlock, WAKE_LOCK_SUSPEND, "msm_otg");
Vijayavardhan Vennapusaa3152032012-03-05 16:29:30 +05304156 msm_otg_init_timer(motg);
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05304157 INIT_WORK(&motg->sm_work, msm_otg_sm_work);
Pavankumar Kondetid8608522011-05-04 10:19:47 +05304158 INIT_DELAYED_WORK(&motg->chg_work, msm_chg_detect_work);
Vijayavardhan Vennapusa68d55cf2012-06-27 20:06:12 +05304159 INIT_DELAYED_WORK(&motg->pmic_id_status_work, msm_pmic_id_status_w);
Amit Blayd0fe07b2012-09-05 16:42:09 +03004160 INIT_DELAYED_WORK(&motg->suspend_work, msm_otg_suspend_work);
Pavankumar Kondetiaa449e12011-11-04 11:09:26 +05304161 setup_timer(&motg->id_timer, msm_otg_id_timer_func,
4162 (unsigned long) motg);
Pavankumar Kondeti458d8792012-09-28 14:45:18 +05304163 setup_timer(&motg->chg_check_timer, msm_otg_chg_check_timer_func,
4164 (unsigned long) motg);
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05304165 ret = request_irq(motg->irq, msm_otg_irq, IRQF_SHARED,
4166 "msm_otg", motg);
4167 if (ret) {
4168 dev_err(&pdev->dev, "request irq failed\n");
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004169 goto destroy_wlock;
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05304170 }
4171
Manu Gautamf8c45642012-08-10 10:20:56 -07004172 if (motg->async_irq) {
Vijayavardhan Vennapusa9ab6f972012-10-11 19:18:55 +05304173 ret = request_irq(motg->async_irq, msm_otg_irq,
4174 IRQF_TRIGGER_RISING, "msm_otg", motg);
Manu Gautamf8c45642012-08-10 10:20:56 -07004175 if (ret) {
4176 dev_err(&pdev->dev, "request irq failed (ASYNC INT)\n");
4177 goto free_irq;
4178 }
4179 disable_irq(motg->async_irq);
4180 }
4181
Jack Pham87f202f2012-08-06 00:24:22 -07004182 if (pdata->otg_control == OTG_PHY_CONTROL && pdata->mpm_otgsessvld_int)
4183 msm_mpm_enable_pin(pdata->mpm_otgsessvld_int, 1);
4184
Vijayavardhan Vennapusa2239b2b2013-06-28 13:16:29 +05304185 if (pdata->mpm_dpshv_int)
4186 msm_mpm_enable_pin(pdata->mpm_dpshv_int, 1);
4187 if (pdata->mpm_dmshv_int)
4188 msm_mpm_enable_pin(pdata->mpm_dmshv_int, 1);
4189
Heikki Krogerus1d4c9292012-02-13 13:24:09 +02004190 phy->init = msm_otg_reset;
4191 phy->set_power = msm_otg_set_power;
Steve Mucklef132c6c2012-06-06 18:30:57 -07004192 phy->set_suspend = msm_otg_set_suspend;
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05304193
Heikki Krogerus1d4c9292012-02-13 13:24:09 +02004194 phy->io_ops = &msm_otg_io_ops;
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05304195
Heikki Krogerus1d4c9292012-02-13 13:24:09 +02004196 phy->otg->phy = &motg->phy;
4197 phy->otg->set_host = msm_otg_set_host;
4198 phy->otg->set_peripheral = msm_otg_set_peripheral;
Steve Mucklef132c6c2012-06-06 18:30:57 -07004199 phy->otg->start_hnp = msm_otg_start_hnp;
4200 phy->otg->start_srp = msm_otg_start_srp;
Vamsi Krishna1a1684b2013-03-02 16:14:52 -08004201 if (pdata->dp_manual_pullup)
4202 phy->flags |= ENABLE_DP_MANUAL_PULLUP;
Heikki Krogerus1d4c9292012-02-13 13:24:09 +02004203
Manu Gautam0fd2d0e2013-03-26 18:09:11 +05304204 if (pdata->enable_sec_phy)
4205 phy->flags |= ENABLE_SECONDARY_PHY;
4206
Heikki Krogerus1d4c9292012-02-13 13:24:09 +02004207 ret = usb_set_transceiver(&motg->phy);
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05304208 if (ret) {
Heikki Krogerus1d4c9292012-02-13 13:24:09 +02004209 dev_err(&pdev->dev, "usb_set_transceiver failed\n");
Manu Gautamf8c45642012-08-10 10:20:56 -07004210 goto free_async_irq;
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05304211 }
4212
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05304213 if (motg->pdata->mode == USB_OTG &&
Pavankumar Kondeti0d81f312012-01-13 11:34:10 +05304214 motg->pdata->otg_control == OTG_PMIC_CONTROL) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004215 if (motg->pdata->pmic_id_irq) {
4216 ret = request_irq(motg->pdata->pmic_id_irq,
4217 msm_pmic_id_irq,
4218 IRQF_TRIGGER_RISING |
4219 IRQF_TRIGGER_FALLING,
4220 "msm_otg", motg);
4221 if (ret) {
4222 dev_err(&pdev->dev, "request irq failed for PMIC ID\n");
Steve Mucklef132c6c2012-06-06 18:30:57 -07004223 goto remove_phy;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004224 }
4225 } else {
4226 ret = -ENODEV;
4227 dev_err(&pdev->dev, "PMIC IRQ for ID notifications doesn't exist\n");
Steve Mucklef132c6c2012-06-06 18:30:57 -07004228 goto remove_phy;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004229 }
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05304230 }
4231
Vijayavardhan Vennapusafc464f02011-11-04 21:54:00 +05304232 msm_hsusb_mhl_switch_enable(motg, 1);
4233
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05304234 platform_set_drvdata(pdev, motg);
4235 device_init_wakeup(&pdev->dev, 1);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004236 motg->mA_port = IUNIT;
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05304237
Anji jonnalad270e2d2011-08-09 11:28:32 +05304238 ret = msm_otg_debugfs_init(motg);
4239 if (ret)
4240 dev_dbg(&pdev->dev, "mode debugfs file is"
4241 "not available\n");
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05304242
Amit Blay58b31472011-11-18 09:39:39 +02004243 if (motg->pdata->phy_type == SNPS_28NM_INTEGRATED_PHY) {
4244 if (motg->pdata->otg_control == OTG_PMIC_CONTROL &&
Pavankumar Kondeti0d81f312012-01-13 11:34:10 +05304245 (!(motg->pdata->mode == USB_OTG) ||
4246 motg->pdata->pmic_id_irq))
Amit Blay58b31472011-11-18 09:39:39 +02004247 motg->caps = ALLOW_PHY_POWER_COLLAPSE |
Vijayavardhan Vennapusa03171c72012-04-26 14:44:48 +05304248 ALLOW_PHY_RETENTION;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004249
Amit Blay58b31472011-11-18 09:39:39 +02004250 if (motg->pdata->otg_control == OTG_PHY_CONTROL)
Amit Blay81801aa2012-09-19 12:08:12 +02004251 motg->caps = ALLOW_PHY_RETENTION |
4252 ALLOW_PHY_REGULATORS_LPM;
Vijayavardhan Vennapusa2239b2b2013-06-28 13:16:29 +05304253
4254 if (motg->pdata->mpm_dpshv_int || motg->pdata->mpm_dmshv_int)
4255 motg->caps |= ALLOW_HOST_PHY_RETENTION;
Amit Blay58b31472011-11-18 09:39:39 +02004256 }
4257
Amit Blay6fa647a2012-05-24 14:12:08 +03004258 if (motg->pdata->enable_lpm_on_dev_suspend)
4259 motg->caps |= ALLOW_LPM_ON_DEV_SUSPEND;
4260
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004261 wake_lock(&motg->wlock);
Pavankumar Kondeti87c01042010-12-07 17:53:58 +05304262 pm_runtime_set_active(&pdev->dev);
Manu Gautamf8c45642012-08-10 10:20:56 -07004263 pm_runtime_enable(&pdev->dev);
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05304264
Amit Blayd6f38282012-10-29 13:13:46 +02004265 if (motg->pdata->delay_lpm_on_disconnect) {
4266 pm_runtime_set_autosuspend_delay(&pdev->dev,
4267 lpm_disconnect_thresh);
4268 pm_runtime_use_autosuspend(&pdev->dev);
4269 }
4270
David Keitel272ce522012-08-17 16:25:24 -07004271 motg->usb_psy.name = "usb";
4272 motg->usb_psy.type = POWER_SUPPLY_TYPE_USB;
4273 motg->usb_psy.supplied_to = otg_pm_power_supplied_to;
4274 motg->usb_psy.num_supplicants = ARRAY_SIZE(otg_pm_power_supplied_to);
4275 motg->usb_psy.properties = otg_pm_power_props_usb;
4276 motg->usb_psy.num_properties = ARRAY_SIZE(otg_pm_power_props_usb);
4277 motg->usb_psy.get_property = otg_power_get_property_usb;
4278 motg->usb_psy.set_property = otg_power_set_property_usb;
David Collinsd79acc52012-11-26 14:59:00 -08004279 motg->usb_psy.property_is_writeable
4280 = otg_power_property_is_writeable_usb;
David Keitel272ce522012-08-17 16:25:24 -07004281
Jack Pham0c695282012-10-19 18:13:03 -07004282 if (!pm8921_charger_register_vbus_sn(NULL)) {
David Keitel272ce522012-08-17 16:25:24 -07004283 /* if pm8921 use legacy implementation */
Jack Pham0c695282012-10-19 18:13:03 -07004284 dev_dbg(motg->phy.dev, "%s: legacy support\n", __func__);
4285 legacy_power_supply = true;
4286 } else {
4287 /* otherwise register our own power supply */
4288 if (!msm_otg_register_power_supply(pdev, motg))
4289 psy = &motg->usb_psy;
David Keitel272ce522012-08-17 16:25:24 -07004290 }
4291
Jack Pham0c695282012-10-19 18:13:03 -07004292 if (legacy_power_supply && pdata->otg_control == OTG_PMIC_CONTROL)
4293 pm8921_charger_register_vbus_sn(&msm_otg_set_vbus_state);
4294
Pavankumar Kondeti87c01042010-12-07 17:53:58 +05304295 return 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004296
Steve Mucklef132c6c2012-06-06 18:30:57 -07004297remove_phy:
4298 usb_set_transceiver(NULL);
Manu Gautamf8c45642012-08-10 10:20:56 -07004299free_async_irq:
4300 if (motg->async_irq)
4301 free_irq(motg->async_irq, motg);
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05304302free_irq:
4303 free_irq(motg->irq, motg);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004304destroy_wlock:
4305 wake_lock_destroy(&motg->wlock);
Manu Gautam28b1bac2012-01-30 16:43:06 +05304306 clk_disable_unprepare(motg->core_clk);
Amit Blay81801aa2012-09-19 12:08:12 +02004307 msm_hsusb_ldo_enable(motg, USB_PHY_REG_OFF);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004308free_ldo_init:
Anji jonnala11aa5c42011-05-04 10:19:48 +05304309 msm_hsusb_ldo_init(motg, 0);
Mayank Rana0f286cf2013-02-27 11:43:27 +05304310free_hsusb_vdd:
4311 regulator_disable(hsusb_vdd);
Mayank Rana248698c2012-04-19 00:03:16 +05304312free_config_vddcx:
Mayank Rana0f286cf2013-02-27 11:43:27 +05304313 regulator_set_voltage(hsusb_vdd,
Mayank Rana248698c2012-04-19 00:03:16 +05304314 vdd_val[motg->vdd_type][VDD_NONE],
4315 vdd_val[motg->vdd_type][VDD_MAX]);
Anji jonnala7da3f262011-12-02 17:22:14 -08004316devote_xo_handle:
Manu Gautam28b1bac2012-01-30 16:43:06 +05304317 clk_disable_unprepare(motg->pclk);
Vijayavardhan Vennapusa0cab6172013-02-20 19:51:15 +05304318 if (!IS_ERR(motg->xo_clk))
4319 clk_disable_unprepare(motg->xo_clk);
4320 else
4321 msm_xo_mode_vote(motg->xo_handle, MSM_XO_MODE_OFF);
Anji jonnala7da3f262011-12-02 17:22:14 -08004322free_xo_handle:
Vijayavardhan Vennapusa0cab6172013-02-20 19:51:15 +05304323 if (!IS_ERR(motg->xo_clk))
4324 clk_put(motg->xo_clk);
4325 else
4326 msm_xo_put(motg->xo_handle);
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05304327free_regs:
4328 iounmap(motg->regs);
Manu Gautam5143b252012-01-05 19:25:23 -08004329put_pclk:
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05304330 clk_put(motg->pclk);
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05304331put_core_clk:
Manu Gautam5143b252012-01-05 19:25:23 -08004332 clk_put(motg->core_clk);
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05304333put_clk:
Pavankumar Kondeti923262e2012-04-20 15:34:24 +05304334 if (!IS_ERR(motg->clk))
4335 clk_put(motg->clk);
Amit Blay02eff132011-09-21 16:46:24 +03004336 if (!IS_ERR(motg->phy_reset_clk))
4337 clk_put(motg->phy_reset_clk);
Manu Gautame3a39082013-06-11 10:42:56 +05304338devote_bus_bw:
4339 if (motg->bus_perf_client) {
4340 msm_otg_bus_vote(motg, USB_NO_PERF_VOTE);
4341 msm_bus_scale_unregister_client(motg->bus_perf_client);
4342 }
4343
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05304344 return ret;
4345}
4346
4347static int __devexit msm_otg_remove(struct platform_device *pdev)
4348{
4349 struct msm_otg *motg = platform_get_drvdata(pdev);
Stephen Boyd9850acb2013-01-28 14:11:20 -08004350 struct usb_phy *phy = &motg->phy;
Pavankumar Kondeti87c01042010-12-07 17:53:58 +05304351 int cnt = 0;
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05304352
Stephen Boyd9850acb2013-01-28 14:11:20 -08004353 if (phy->otg->host || phy->otg->gadget)
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05304354 return -EBUSY;
4355
Pavankumar Kondetieaea7fe2011-10-27 14:46:45 +05304356 if (pdev->dev.of_node)
4357 msm_otg_setup_devices(pdev, motg->pdata->mode, false);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004358 if (motg->pdata->otg_control == OTG_PMIC_CONTROL)
4359 pm8921_charger_unregister_vbus_sn(0);
Pavankumar Kondeti2aec9f32012-06-13 09:06:03 +05304360 msm_otg_mhl_register_callback(motg, NULL);
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05304361 msm_otg_debugfs_cleanup();
Pavankumar Kondetid8608522011-05-04 10:19:47 +05304362 cancel_delayed_work_sync(&motg->chg_work);
Vijayavardhan Vennapusa68d55cf2012-06-27 20:06:12 +05304363 cancel_delayed_work_sync(&motg->pmic_id_status_work);
Amit Blayd0fe07b2012-09-05 16:42:09 +03004364 cancel_delayed_work_sync(&motg->suspend_work);
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05304365 cancel_work_sync(&motg->sm_work);
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05304366
Pavankumar Kondeti70187732011-02-15 09:42:34 +05304367 pm_runtime_resume(&pdev->dev);
Pavankumar Kondeti87c01042010-12-07 17:53:58 +05304368
4369 device_init_wakeup(&pdev->dev, 0);
4370 pm_runtime_disable(&pdev->dev);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004371 wake_lock_destroy(&motg->wlock);
Pavankumar Kondeti87c01042010-12-07 17:53:58 +05304372
Vijayavardhan Vennapusafc464f02011-11-04 21:54:00 +05304373 msm_hsusb_mhl_switch_enable(motg, 0);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004374 if (motg->pdata->pmic_id_irq)
4375 free_irq(motg->pdata->pmic_id_irq, motg);
Heikki Krogerus1d4c9292012-02-13 13:24:09 +02004376 usb_set_transceiver(NULL);
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05304377 free_irq(motg->irq, motg);
4378
Jack Pham87f202f2012-08-06 00:24:22 -07004379 if (motg->pdata->otg_control == OTG_PHY_CONTROL &&
4380 motg->pdata->mpm_otgsessvld_int)
4381 msm_mpm_enable_pin(motg->pdata->mpm_otgsessvld_int, 0);
4382
Vijayavardhan Vennapusa2239b2b2013-06-28 13:16:29 +05304383 if (motg->pdata->mpm_dpshv_int)
4384 msm_mpm_enable_pin(motg->pdata->mpm_dpshv_int, 0);
4385 if (motg->pdata->mpm_dmshv_int)
4386 msm_mpm_enable_pin(motg->pdata->mpm_dmshv_int, 0);
4387
Pavankumar Kondeti87c01042010-12-07 17:53:58 +05304388 /*
4389 * Put PHY in low power mode.
4390 */
Stephen Boyd9850acb2013-01-28 14:11:20 -08004391 ulpi_read(phy, 0x14);
4392 ulpi_write(phy, 0x08, 0x09);
Pavankumar Kondeti87c01042010-12-07 17:53:58 +05304393
4394 writel(readl(USB_PORTSC) | PORTSC_PHCD, USB_PORTSC);
4395 while (cnt < PHY_SUSPEND_TIMEOUT_USEC) {
4396 if (readl(USB_PORTSC) & PORTSC_PHCD)
4397 break;
4398 udelay(1);
4399 cnt++;
4400 }
4401 if (cnt >= PHY_SUSPEND_TIMEOUT_USEC)
Stephen Boyd9850acb2013-01-28 14:11:20 -08004402 dev_err(phy->dev, "Unable to suspend PHY\n");
Pavankumar Kondeti87c01042010-12-07 17:53:58 +05304403
Manu Gautam28b1bac2012-01-30 16:43:06 +05304404 clk_disable_unprepare(motg->pclk);
4405 clk_disable_unprepare(motg->core_clk);
Vijayavardhan Vennapusa0cab6172013-02-20 19:51:15 +05304406 if (!IS_ERR(motg->xo_clk)) {
4407 clk_disable_unprepare(motg->xo_clk);
4408 clk_put(motg->xo_clk);
4409 } else {
4410 msm_xo_put(motg->xo_handle);
4411 }
Amit Blay81801aa2012-09-19 12:08:12 +02004412 msm_hsusb_ldo_enable(motg, USB_PHY_REG_OFF);
Anji jonnala11aa5c42011-05-04 10:19:48 +05304413 msm_hsusb_ldo_init(motg, 0);
Mayank Rana0f286cf2013-02-27 11:43:27 +05304414 regulator_disable(hsusb_vdd);
4415 regulator_set_voltage(hsusb_vdd,
Mayank Rana248698c2012-04-19 00:03:16 +05304416 vdd_val[motg->vdd_type][VDD_NONE],
4417 vdd_val[motg->vdd_type][VDD_MAX]);
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05304418
4419 iounmap(motg->regs);
Pavankumar Kondeti87c01042010-12-07 17:53:58 +05304420 pm_runtime_set_suspended(&pdev->dev);
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05304421
Amit Blay02eff132011-09-21 16:46:24 +03004422 if (!IS_ERR(motg->phy_reset_clk))
4423 clk_put(motg->phy_reset_clk);
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05304424 clk_put(motg->pclk);
Pavankumar Kondeti923262e2012-04-20 15:34:24 +05304425 if (!IS_ERR(motg->clk))
4426 clk_put(motg->clk);
Manu Gautam5143b252012-01-05 19:25:23 -08004427 clk_put(motg->core_clk);
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05304428
Manu Gautame3a39082013-06-11 10:42:56 +05304429 if (motg->bus_perf_client) {
4430 msm_otg_bus_vote(motg, USB_NO_PERF_VOTE);
Manu Gautamcd82e9d2011-12-20 14:17:28 +05304431 msm_bus_scale_unregister_client(motg->bus_perf_client);
Manu Gautame3a39082013-06-11 10:42:56 +05304432 }
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05304433
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05304434 return 0;
4435}
4436
Pavankumar Kondeti87c01042010-12-07 17:53:58 +05304437#ifdef CONFIG_PM_RUNTIME
4438static int msm_otg_runtime_idle(struct device *dev)
4439{
4440 struct msm_otg *motg = dev_get_drvdata(dev);
Steve Mucklef132c6c2012-06-06 18:30:57 -07004441 struct usb_phy *phy = &motg->phy;
Pavankumar Kondeti87c01042010-12-07 17:53:58 +05304442
4443 dev_dbg(dev, "OTG runtime idle\n");
4444
Steve Mucklef132c6c2012-06-06 18:30:57 -07004445 if (phy->state == OTG_STATE_UNDEFINED)
Pavankumar Kondeti8be99cf2011-08-04 10:48:08 +05304446 return -EAGAIN;
4447 else
4448 return 0;
Pavankumar Kondeti87c01042010-12-07 17:53:58 +05304449}
4450
4451static int msm_otg_runtime_suspend(struct device *dev)
4452{
4453 struct msm_otg *motg = dev_get_drvdata(dev);
4454
4455 dev_dbg(dev, "OTG runtime suspend\n");
4456 return msm_otg_suspend(motg);
4457}
4458
4459static int msm_otg_runtime_resume(struct device *dev)
4460{
4461 struct msm_otg *motg = dev_get_drvdata(dev);
4462
4463 dev_dbg(dev, "OTG runtime resume\n");
Pavankumar Kondeti8be99cf2011-08-04 10:48:08 +05304464 pm_runtime_get_noresume(dev);
Pavankumar Kondeti87c01042010-12-07 17:53:58 +05304465 return msm_otg_resume(motg);
4466}
Pavankumar Kondeti87c01042010-12-07 17:53:58 +05304467#endif
4468
Pavankumar Kondeti70187732011-02-15 09:42:34 +05304469#ifdef CONFIG_PM_SLEEP
Pavankumar Kondeti87c01042010-12-07 17:53:58 +05304470static int msm_otg_pm_suspend(struct device *dev)
4471{
Jack Pham5ca279b2012-05-14 18:42:54 -07004472 int ret = 0;
Pavankumar Kondeti87c01042010-12-07 17:53:58 +05304473 struct msm_otg *motg = dev_get_drvdata(dev);
4474
4475 dev_dbg(dev, "OTG PM suspend\n");
Jack Pham5ca279b2012-05-14 18:42:54 -07004476
4477 atomic_set(&motg->pm_suspended, 1);
4478 ret = msm_otg_suspend(motg);
4479 if (ret)
4480 atomic_set(&motg->pm_suspended, 0);
4481
4482 return ret;
Pavankumar Kondeti87c01042010-12-07 17:53:58 +05304483}
4484
4485static int msm_otg_pm_resume(struct device *dev)
4486{
Jack Pham5ca279b2012-05-14 18:42:54 -07004487 int ret = 0;
Pavankumar Kondeti87c01042010-12-07 17:53:58 +05304488 struct msm_otg *motg = dev_get_drvdata(dev);
Pavankumar Kondeti87c01042010-12-07 17:53:58 +05304489
4490 dev_dbg(dev, "OTG PM resume\n");
4491
Jack Pham5ca279b2012-05-14 18:42:54 -07004492 atomic_set(&motg->pm_suspended, 0);
Jack Phamc7edb172012-08-13 15:32:39 -07004493 if (motg->async_int || motg->sm_work_pending) {
Jack Pham5ca279b2012-05-14 18:42:54 -07004494 pm_runtime_get_noresume(dev);
4495 ret = msm_otg_resume(motg);
Pavankumar Kondeti87c01042010-12-07 17:53:58 +05304496
Jack Pham5ca279b2012-05-14 18:42:54 -07004497 /* Update runtime PM status */
4498 pm_runtime_disable(dev);
4499 pm_runtime_set_active(dev);
4500 pm_runtime_enable(dev);
4501
Jack Phamc7edb172012-08-13 15:32:39 -07004502 if (motg->sm_work_pending) {
4503 motg->sm_work_pending = false;
4504 queue_work(system_nrt_wq, &motg->sm_work);
4505 }
Jack Pham5ca279b2012-05-14 18:42:54 -07004506 }
4507
4508 return ret;
Pavankumar Kondeti87c01042010-12-07 17:53:58 +05304509}
Pavankumar Kondeti87c01042010-12-07 17:53:58 +05304510#endif
4511
Pavankumar Kondeti70187732011-02-15 09:42:34 +05304512#ifdef CONFIG_PM
Pavankumar Kondeti87c01042010-12-07 17:53:58 +05304513static const struct dev_pm_ops msm_otg_dev_pm_ops = {
Pavankumar Kondeti70187732011-02-15 09:42:34 +05304514 SET_SYSTEM_SLEEP_PM_OPS(msm_otg_pm_suspend, msm_otg_pm_resume)
4515 SET_RUNTIME_PM_OPS(msm_otg_runtime_suspend, msm_otg_runtime_resume,
4516 msm_otg_runtime_idle)
Pavankumar Kondeti87c01042010-12-07 17:53:58 +05304517};
Pavankumar Kondeti70187732011-02-15 09:42:34 +05304518#endif
Pavankumar Kondeti87c01042010-12-07 17:53:58 +05304519
Pavankumar Kondetieaea7fe2011-10-27 14:46:45 +05304520static struct of_device_id msm_otg_dt_match[] = {
4521 { .compatible = "qcom,hsusb-otg",
4522 },
4523 {}
4524};
4525
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05304526static struct platform_driver msm_otg_driver = {
4527 .remove = __devexit_p(msm_otg_remove),
4528 .driver = {
4529 .name = DRIVER_NAME,
4530 .owner = THIS_MODULE,
Pavankumar Kondeti70187732011-02-15 09:42:34 +05304531#ifdef CONFIG_PM
Pavankumar Kondeti87c01042010-12-07 17:53:58 +05304532 .pm = &msm_otg_dev_pm_ops,
Pavankumar Kondeti70187732011-02-15 09:42:34 +05304533#endif
Pavankumar Kondetieaea7fe2011-10-27 14:46:45 +05304534 .of_match_table = msm_otg_dt_match,
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05304535 },
4536};
4537
4538static int __init msm_otg_init(void)
4539{
4540 return platform_driver_probe(&msm_otg_driver, msm_otg_probe);
4541}
4542
4543static void __exit msm_otg_exit(void)
4544{
4545 platform_driver_unregister(&msm_otg_driver);
4546}
4547
4548module_init(msm_otg_init);
4549module_exit(msm_otg_exit);
4550
4551MODULE_LICENSE("GPL v2");
4552MODULE_DESCRIPTION("MSM USB transceiver driver");