blob: 60018bf7c5776a277b74880e778d3efb82168b17 [file] [log] [blame]
Manu Gautam5143b252012-01-05 19:25:23 -08001/* Copyright (c) 2009-2012, Code Aurora Forum. All rights reserved.
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05302 *
3 * This program is free software; you can redistribute it and/or modify
4 * it under the terms of the GNU General Public License version 2 and
5 * only version 2 as published by the Free Software Foundation.
6 *
7 * This program is distributed in the hope that it will be useful,
8 * but WITHOUT ANY WARRANTY; without even the implied warranty of
9 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10 * GNU General Public License for more details.
11 *
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +053012 */
13
14#include <linux/module.h>
15#include <linux/device.h>
16#include <linux/platform_device.h>
17#include <linux/clk.h>
18#include <linux/slab.h>
19#include <linux/interrupt.h>
20#include <linux/err.h>
21#include <linux/delay.h>
22#include <linux/io.h>
23#include <linux/ioport.h>
24#include <linux/uaccess.h>
25#include <linux/debugfs.h>
26#include <linux/seq_file.h>
Pavankumar Kondeti87c01042010-12-07 17:53:58 +053027#include <linux/pm_runtime.h>
Pavankumar Kondetieaea7fe2011-10-27 14:46:45 +053028#include <linux/of.h>
29#include <linux/dma-mapping.h>
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +053030
31#include <linux/usb.h>
32#include <linux/usb/otg.h>
33#include <linux/usb/ulpi.h>
34#include <linux/usb/gadget.h>
35#include <linux/usb/hcd.h>
Vijayavardhan Vennapusaa3152032012-03-05 16:29:30 +053036#include <linux/usb/quirks.h>
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +053037#include <linux/usb/msm_hsusb.h>
38#include <linux/usb/msm_hsusb_hw.h>
Anji jonnala11aa5c42011-05-04 10:19:48 +053039#include <linux/regulator/consumer.h>
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070040#include <linux/mfd/pm8xxx/pm8921-charger.h>
Pavankumar Kondeti446f4542012-02-01 13:57:13 +053041#include <linux/mfd/pm8xxx/misc.h>
Sridhar Parasuram3c67a412012-09-26 09:36:22 -070042#include <linux/power_supply.h>
Pavankumar Kondeti2aec9f32012-06-13 09:06:03 +053043#include <linux/mhl_8334.h>
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +053044
45#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
Pavankumar Kondeti4960f312011-12-06 15:46:14 +053080static DECLARE_COMPLETION(pmic_vbus_init);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070081static struct msm_otg *the_msm_otg;
Pavankumar Kondetiaa449e12011-11-04 11:09:26 +053082static bool debug_aca_enabled;
Manu Gautam8bdcc592012-03-06 11:26:06 +053083static bool debug_bus_voting_enabled;
Pavankumar Kondeti2aec9f32012-06-13 09:06:03 +053084static bool mhl_det_in_progress;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070085
Anji jonnala11aa5c42011-05-04 10:19:48 +053086static struct regulator *hsusb_3p3;
87static struct regulator *hsusb_1p8;
88static struct regulator *hsusb_vddcx;
Mayank Ranae3926882011-12-26 09:47:54 +053089static struct regulator *vbus_otg;
Pavankumar Kondeti56dc7422012-07-02 12:45:19 +053090static struct regulator *mhl_usb_hs_switch;
Vijayavardhan Vennapusa05c437c2012-05-25 16:20:46 +053091static struct power_supply *psy;
Anji jonnala11aa5c42011-05-04 10:19:48 +053092
Pavankumar Kondeti4960f312011-12-06 15:46:14 +053093static bool aca_id_turned_on;
Pavankumar Kondetiaa449e12011-11-04 11:09:26 +053094static inline bool aca_enabled(void)
Anji jonnala11aa5c42011-05-04 10:19:48 +053095{
Pavankumar Kondetiaa449e12011-11-04 11:09:26 +053096#ifdef CONFIG_USB_MSM_ACA
97 return true;
98#else
99 return debug_aca_enabled;
100#endif
Anji jonnala11aa5c42011-05-04 10:19:48 +0530101}
102
Mayank Rana248698c2012-04-19 00:03:16 +0530103static const int vdd_val[VDD_TYPE_MAX][VDD_VAL_MAX] = {
104 { /* VDD_CX CORNER Voting */
105 [VDD_NONE] = RPM_VREG_CORNER_NONE,
106 [VDD_MIN] = RPM_VREG_CORNER_NOMINAL,
107 [VDD_MAX] = RPM_VREG_CORNER_HIGH,
108 },
109 { /* VDD_CX Voltage Voting */
110 [VDD_NONE] = USB_PHY_VDD_DIG_VOL_NONE,
111 [VDD_MIN] = USB_PHY_VDD_DIG_VOL_MIN,
112 [VDD_MAX] = USB_PHY_VDD_DIG_VOL_MAX,
113 },
114};
Anji jonnala11aa5c42011-05-04 10:19:48 +0530115
116static int msm_hsusb_ldo_init(struct msm_otg *motg, int init)
117{
118 int rc = 0;
119
120 if (init) {
Steve Mucklef132c6c2012-06-06 18:30:57 -0700121 hsusb_3p3 = devm_regulator_get(motg->phy.dev, "HSUSB_3p3");
Anji jonnala11aa5c42011-05-04 10:19:48 +0530122 if (IS_ERR(hsusb_3p3)) {
Heikki Krogerus1d4c9292012-02-13 13:24:09 +0200123 dev_err(motg->phy.dev, "unable to get hsusb 3p3\n");
Anji jonnala11aa5c42011-05-04 10:19:48 +0530124 return PTR_ERR(hsusb_3p3);
125 }
126
127 rc = regulator_set_voltage(hsusb_3p3, USB_PHY_3P3_VOL_MIN,
128 USB_PHY_3P3_VOL_MAX);
129 if (rc) {
Steve Mucklef132c6c2012-06-06 18:30:57 -0700130 dev_err(motg->phy.dev, "unable to set voltage level for"
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700131 "hsusb 3p3\n");
Mayank Rana9e9a2ac2012-03-24 04:05:28 +0530132 return rc;
Anji jonnala11aa5c42011-05-04 10:19:48 +0530133 }
Steve Mucklef132c6c2012-06-06 18:30:57 -0700134 hsusb_1p8 = devm_regulator_get(motg->phy.dev, "HSUSB_1p8");
Anji jonnala11aa5c42011-05-04 10:19:48 +0530135 if (IS_ERR(hsusb_1p8)) {
Heikki Krogerus1d4c9292012-02-13 13:24:09 +0200136 dev_err(motg->phy.dev, "unable to get hsusb 1p8\n");
Anji jonnala11aa5c42011-05-04 10:19:48 +0530137 rc = PTR_ERR(hsusb_1p8);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700138 goto put_3p3_lpm;
Anji jonnala11aa5c42011-05-04 10:19:48 +0530139 }
140 rc = regulator_set_voltage(hsusb_1p8, USB_PHY_1P8_VOL_MIN,
141 USB_PHY_1P8_VOL_MAX);
142 if (rc) {
Steve Mucklef132c6c2012-06-06 18:30:57 -0700143 dev_err(motg->phy.dev, "unable to set voltage level for"
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700144 "hsusb 1p8\n");
Anji jonnala11aa5c42011-05-04 10:19:48 +0530145 goto put_1p8;
146 }
147
148 return 0;
149 }
150
Anji jonnala11aa5c42011-05-04 10:19:48 +0530151put_1p8:
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700152 regulator_set_voltage(hsusb_1p8, 0, USB_PHY_1P8_VOL_MAX);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700153put_3p3_lpm:
154 regulator_set_voltage(hsusb_3p3, 0, USB_PHY_3P3_VOL_MAX);
Anji jonnala11aa5c42011-05-04 10:19:48 +0530155 return rc;
156}
157
Pavankumar Kondeti04aebcb2011-05-04 10:19:49 +0530158static int msm_hsusb_config_vddcx(int high)
159{
Mayank Rana248698c2012-04-19 00:03:16 +0530160 struct msm_otg *motg = the_msm_otg;
161 enum usb_vdd_type vdd_type = motg->vdd_type;
162 int max_vol = vdd_val[vdd_type][VDD_MAX];
Pavankumar Kondeti04aebcb2011-05-04 10:19:49 +0530163 int min_vol;
164 int ret;
165
Mayank Rana248698c2012-04-19 00:03:16 +0530166 min_vol = vdd_val[vdd_type][!!high];
Pavankumar Kondeti04aebcb2011-05-04 10:19:49 +0530167 ret = regulator_set_voltage(hsusb_vddcx, min_vol, max_vol);
168 if (ret) {
169 pr_err("%s: unable to set the voltage for regulator "
170 "HSUSB_VDDCX\n", __func__);
171 return ret;
172 }
173
174 pr_debug("%s: min_vol:%d max_vol:%d\n", __func__, min_vol, max_vol);
175
176 return ret;
177}
Pavankumar Kondeti04aebcb2011-05-04 10:19:49 +0530178
Amit Blay81801aa2012-09-19 12:08:12 +0200179static int msm_hsusb_ldo_enable(struct msm_otg *motg,
180 enum msm_otg_phy_reg_mode mode)
Anji jonnala11aa5c42011-05-04 10:19:48 +0530181{
182 int ret = 0;
183
Pavankumar Kondeti68964c92011-10-27 14:58:56 +0530184 if (IS_ERR(hsusb_1p8)) {
Anji jonnala11aa5c42011-05-04 10:19:48 +0530185 pr_err("%s: HSUSB_1p8 is not initialized\n", __func__);
186 return -ENODEV;
187 }
188
Pavankumar Kondeti68964c92011-10-27 14:58:56 +0530189 if (IS_ERR(hsusb_3p3)) {
Anji jonnala11aa5c42011-05-04 10:19:48 +0530190 pr_err("%s: HSUSB_3p3 is not initialized\n", __func__);
191 return -ENODEV;
192 }
193
Amit Blay81801aa2012-09-19 12:08:12 +0200194 switch (mode) {
195 case USB_PHY_REG_ON:
Anji jonnala11aa5c42011-05-04 10:19:48 +0530196 ret = regulator_set_optimum_mode(hsusb_1p8,
197 USB_PHY_1P8_HPM_LOAD);
198 if (ret < 0) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700199 pr_err("%s: Unable to set HPM of the regulator:"
Anji jonnala11aa5c42011-05-04 10:19:48 +0530200 "HSUSB_1p8\n", __func__);
201 return ret;
202 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700203
204 ret = regulator_enable(hsusb_1p8);
205 if (ret) {
Steve Mucklef132c6c2012-06-06 18:30:57 -0700206 dev_err(motg->phy.dev, "%s: unable to enable the hsusb 1p8\n",
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700207 __func__);
208 regulator_set_optimum_mode(hsusb_1p8, 0);
209 return ret;
210 }
211
Anji jonnala11aa5c42011-05-04 10:19:48 +0530212 ret = regulator_set_optimum_mode(hsusb_3p3,
213 USB_PHY_3P3_HPM_LOAD);
214 if (ret < 0) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700215 pr_err("%s: Unable to set HPM of the regulator:"
Anji jonnala11aa5c42011-05-04 10:19:48 +0530216 "HSUSB_3p3\n", __func__);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700217 regulator_set_optimum_mode(hsusb_1p8, 0);
218 regulator_disable(hsusb_1p8);
Anji jonnala11aa5c42011-05-04 10:19:48 +0530219 return ret;
220 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700221
222 ret = regulator_enable(hsusb_3p3);
223 if (ret) {
Steve Mucklef132c6c2012-06-06 18:30:57 -0700224 dev_err(motg->phy.dev, "%s: unable to enable the hsusb 3p3\n",
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700225 __func__);
226 regulator_set_optimum_mode(hsusb_3p3, 0);
227 regulator_set_optimum_mode(hsusb_1p8, 0);
228 regulator_disable(hsusb_1p8);
229 return ret;
230 }
231
Amit Blay81801aa2012-09-19 12:08:12 +0200232 break;
233
234 case USB_PHY_REG_OFF:
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700235 ret = regulator_disable(hsusb_1p8);
236 if (ret) {
Steve Mucklef132c6c2012-06-06 18:30:57 -0700237 dev_err(motg->phy.dev, "%s: unable to disable the hsusb 1p8\n",
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700238 __func__);
239 return ret;
240 }
241
242 ret = regulator_set_optimum_mode(hsusb_1p8, 0);
Anji jonnala11aa5c42011-05-04 10:19:48 +0530243 if (ret < 0)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700244 pr_err("%s: Unable to set LPM of the regulator:"
Anji jonnala11aa5c42011-05-04 10:19:48 +0530245 "HSUSB_1p8\n", __func__);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700246
247 ret = regulator_disable(hsusb_3p3);
248 if (ret) {
Steve Mucklef132c6c2012-06-06 18:30:57 -0700249 dev_err(motg->phy.dev, "%s: unable to disable the hsusb 3p3\n",
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700250 __func__);
251 return ret;
252 }
253 ret = regulator_set_optimum_mode(hsusb_3p3, 0);
Anji jonnala11aa5c42011-05-04 10:19:48 +0530254 if (ret < 0)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700255 pr_err("%s: Unable to set LPM of the regulator:"
Anji jonnala11aa5c42011-05-04 10:19:48 +0530256 "HSUSB_3p3\n", __func__);
Amit Blay81801aa2012-09-19 12:08:12 +0200257
258 break;
259
260 case USB_PHY_REG_LPM_ON:
261 ret = regulator_set_optimum_mode(hsusb_1p8,
262 USB_PHY_1P8_LPM_LOAD);
263 if (ret < 0) {
264 pr_err("%s: Unable to set LPM of the regulator: HSUSB_1p8\n",
265 __func__);
266 return ret;
267 }
268
269 ret = regulator_set_optimum_mode(hsusb_3p3,
270 USB_PHY_3P3_LPM_LOAD);
271 if (ret < 0) {
272 pr_err("%s: Unable to set LPM of the regulator: HSUSB_3p3\n",
273 __func__);
274 regulator_set_optimum_mode(hsusb_1p8, USB_PHY_REG_ON);
275 return ret;
276 }
277
278 break;
279
280 case USB_PHY_REG_LPM_OFF:
281 ret = regulator_set_optimum_mode(hsusb_1p8,
282 USB_PHY_1P8_HPM_LOAD);
283 if (ret < 0) {
284 pr_err("%s: Unable to set HPM of the regulator: HSUSB_1p8\n",
285 __func__);
286 return ret;
287 }
288
289 ret = regulator_set_optimum_mode(hsusb_3p3,
290 USB_PHY_3P3_HPM_LOAD);
291 if (ret < 0) {
292 pr_err("%s: Unable to set HPM of the regulator: HSUSB_3p3\n",
293 __func__);
294 regulator_set_optimum_mode(hsusb_1p8, USB_PHY_REG_ON);
295 return ret;
296 }
297
298 break;
299
300 default:
301 pr_err("%s: Unsupported mode (%d).", __func__, mode);
302 return -ENOTSUPP;
Anji jonnala11aa5c42011-05-04 10:19:48 +0530303 }
304
Amit Blay81801aa2012-09-19 12:08:12 +0200305 pr_debug("%s: USB reg mode (%d) (OFF/HPM/LPM)\n", __func__, mode);
Anji jonnala11aa5c42011-05-04 10:19:48 +0530306 return ret < 0 ? ret : 0;
307}
308
Vijayavardhan Vennapusafc464f02011-11-04 21:54:00 +0530309static void msm_hsusb_mhl_switch_enable(struct msm_otg *motg, bool on)
310{
Vijayavardhan Vennapusafc464f02011-11-04 21:54:00 +0530311 struct msm_otg_platform_data *pdata = motg->pdata;
312
313 if (!pdata->mhl_enable)
314 return;
315
Pavankumar Kondeti56dc7422012-07-02 12:45:19 +0530316 if (!mhl_usb_hs_switch) {
317 pr_err("%s: mhl_usb_hs_switch is NULL.\n", __func__);
Vijayavardhan Vennapusafc464f02011-11-04 21:54:00 +0530318 return;
319 }
320
Mayank Rana9e9a2ac2012-03-24 04:05:28 +0530321 if (on) {
Pavankumar Kondeti56dc7422012-07-02 12:45:19 +0530322 if (regulator_enable(mhl_usb_hs_switch))
323 pr_err("unable to enable mhl_usb_hs_switch\n");
Mayank Rana9e9a2ac2012-03-24 04:05:28 +0530324 } else {
Pavankumar Kondeti56dc7422012-07-02 12:45:19 +0530325 regulator_disable(mhl_usb_hs_switch);
Mayank Rana9e9a2ac2012-03-24 04:05:28 +0530326 }
Vijayavardhan Vennapusafc464f02011-11-04 21:54:00 +0530327}
328
Heikki Krogerus1d4c9292012-02-13 13:24:09 +0200329static int ulpi_read(struct usb_phy *phy, u32 reg)
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +0530330{
Heikki Krogerus1d4c9292012-02-13 13:24:09 +0200331 struct msm_otg *motg = container_of(phy, struct msm_otg, phy);
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +0530332 int cnt = 0;
333
334 /* initiate read operation */
335 writel(ULPI_RUN | ULPI_READ | ULPI_ADDR(reg),
336 USB_ULPI_VIEWPORT);
337
338 /* wait for completion */
339 while (cnt < ULPI_IO_TIMEOUT_USEC) {
340 if (!(readl(USB_ULPI_VIEWPORT) & ULPI_RUN))
341 break;
342 udelay(1);
343 cnt++;
344 }
345
346 if (cnt >= ULPI_IO_TIMEOUT_USEC) {
Heikki Krogerus1d4c9292012-02-13 13:24:09 +0200347 dev_err(phy->dev, "ulpi_read: timeout %08x\n",
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +0530348 readl(USB_ULPI_VIEWPORT));
349 return -ETIMEDOUT;
350 }
351 return ULPI_DATA_READ(readl(USB_ULPI_VIEWPORT));
352}
353
Heikki Krogerus1d4c9292012-02-13 13:24:09 +0200354static int ulpi_write(struct usb_phy *phy, u32 val, u32 reg)
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +0530355{
Heikki Krogerus1d4c9292012-02-13 13:24:09 +0200356 struct msm_otg *motg = container_of(phy, struct msm_otg, phy);
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +0530357 int cnt = 0;
358
359 /* initiate write operation */
360 writel(ULPI_RUN | ULPI_WRITE |
361 ULPI_ADDR(reg) | ULPI_DATA(val),
362 USB_ULPI_VIEWPORT);
363
364 /* wait for completion */
365 while (cnt < ULPI_IO_TIMEOUT_USEC) {
366 if (!(readl(USB_ULPI_VIEWPORT) & ULPI_RUN))
367 break;
368 udelay(1);
369 cnt++;
370 }
371
372 if (cnt >= ULPI_IO_TIMEOUT_USEC) {
Heikki Krogerus1d4c9292012-02-13 13:24:09 +0200373 dev_err(phy->dev, "ulpi_write: timeout\n");
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +0530374 return -ETIMEDOUT;
375 }
376 return 0;
377}
378
Heikki Krogerus1d4c9292012-02-13 13:24:09 +0200379static struct usb_phy_io_ops msm_otg_io_ops = {
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +0530380 .read = ulpi_read,
381 .write = ulpi_write,
382};
383
384static void ulpi_init(struct msm_otg *motg)
385{
386 struct msm_otg_platform_data *pdata = motg->pdata;
387 int *seq = pdata->phy_init_seq;
388
389 if (!seq)
390 return;
391
392 while (seq[0] >= 0) {
Heikki Krogerus1d4c9292012-02-13 13:24:09 +0200393 dev_vdbg(motg->phy.dev, "ulpi: write 0x%02x to 0x%02x\n",
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +0530394 seq[0], seq[1]);
Heikki Krogerus1d4c9292012-02-13 13:24:09 +0200395 ulpi_write(&motg->phy, seq[0], seq[1]);
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +0530396 seq += 2;
397 }
398}
399
400static int msm_otg_link_clk_reset(struct msm_otg *motg, bool assert)
401{
402 int ret;
403
404 if (assert) {
Manu Gautam5025ff12012-07-20 10:56:50 +0530405 if (!IS_ERR(motg->clk)) {
406 ret = clk_reset(motg->clk, CLK_RESET_ASSERT);
407 } else {
408 /* Using asynchronous block reset to the hardware */
409 dev_dbg(motg->phy.dev, "block_reset ASSERT\n");
410 clk_disable_unprepare(motg->pclk);
411 clk_disable_unprepare(motg->core_clk);
412 ret = clk_reset(motg->core_clk, CLK_RESET_ASSERT);
413 }
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +0530414 if (ret)
Heikki Krogerus1d4c9292012-02-13 13:24:09 +0200415 dev_err(motg->phy.dev, "usb hs_clk assert failed\n");
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +0530416 } else {
Manu Gautam5025ff12012-07-20 10:56:50 +0530417 if (!IS_ERR(motg->clk)) {
418 ret = clk_reset(motg->clk, CLK_RESET_DEASSERT);
419 } else {
420 dev_dbg(motg->phy.dev, "block_reset DEASSERT\n");
421 ret = clk_reset(motg->core_clk, CLK_RESET_DEASSERT);
422 ndelay(200);
423 clk_prepare_enable(motg->core_clk);
424 clk_prepare_enable(motg->pclk);
425 }
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +0530426 if (ret)
Heikki Krogerus1d4c9292012-02-13 13:24:09 +0200427 dev_err(motg->phy.dev, "usb hs_clk deassert failed\n");
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +0530428 }
429 return ret;
430}
431
432static int msm_otg_phy_clk_reset(struct msm_otg *motg)
433{
434 int ret;
435
Amit Blay02eff132011-09-21 16:46:24 +0300436 if (IS_ERR(motg->phy_reset_clk))
437 return 0;
438
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +0530439 ret = clk_reset(motg->phy_reset_clk, CLK_RESET_ASSERT);
440 if (ret) {
Heikki Krogerus1d4c9292012-02-13 13:24:09 +0200441 dev_err(motg->phy.dev, "usb phy clk assert failed\n");
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +0530442 return ret;
443 }
444 usleep_range(10000, 12000);
445 ret = clk_reset(motg->phy_reset_clk, CLK_RESET_DEASSERT);
446 if (ret)
Heikki Krogerus1d4c9292012-02-13 13:24:09 +0200447 dev_err(motg->phy.dev, "usb phy clk deassert failed\n");
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +0530448 return ret;
449}
450
451static int msm_otg_phy_reset(struct msm_otg *motg)
452{
453 u32 val;
454 int ret;
455 int retries;
456
457 ret = msm_otg_link_clk_reset(motg, 1);
458 if (ret)
459 return ret;
460 ret = msm_otg_phy_clk_reset(motg);
461 if (ret)
462 return ret;
463 ret = msm_otg_link_clk_reset(motg, 0);
464 if (ret)
465 return ret;
466
467 val = readl(USB_PORTSC) & ~PORTSC_PTS_MASK;
468 writel(val | PORTSC_PTS_ULPI, USB_PORTSC);
469
470 for (retries = 3; retries > 0; retries--) {
Heikki Krogerus1d4c9292012-02-13 13:24:09 +0200471 ret = ulpi_write(&motg->phy, ULPI_FUNC_CTRL_SUSPENDM,
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +0530472 ULPI_CLR(ULPI_FUNC_CTRL));
473 if (!ret)
474 break;
475 ret = msm_otg_phy_clk_reset(motg);
476 if (ret)
477 return ret;
478 }
479 if (!retries)
480 return -ETIMEDOUT;
481
482 /* This reset calibrates the phy, if the above write succeeded */
483 ret = msm_otg_phy_clk_reset(motg);
484 if (ret)
485 return ret;
486
487 for (retries = 3; retries > 0; retries--) {
Heikki Krogerus1d4c9292012-02-13 13:24:09 +0200488 ret = ulpi_read(&motg->phy, ULPI_DEBUG);
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +0530489 if (ret != -ETIMEDOUT)
490 break;
491 ret = msm_otg_phy_clk_reset(motg);
492 if (ret)
493 return ret;
494 }
495 if (!retries)
496 return -ETIMEDOUT;
497
Heikki Krogerus1d4c9292012-02-13 13:24:09 +0200498 dev_info(motg->phy.dev, "phy_reset: success\n");
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +0530499 return 0;
500}
501
502#define LINK_RESET_TIMEOUT_USEC (250 * 1000)
Pavankumar Kondetiaa449e12011-11-04 11:09:26 +0530503static int msm_otg_link_reset(struct msm_otg *motg)
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +0530504{
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +0530505 int cnt = 0;
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +0530506
Pavankumar Kondetiaa449e12011-11-04 11:09:26 +0530507 writel_relaxed(USBCMD_RESET, USB_USBCMD);
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +0530508 while (cnt < LINK_RESET_TIMEOUT_USEC) {
Pavankumar Kondetiaa449e12011-11-04 11:09:26 +0530509 if (!(readl_relaxed(USB_USBCMD) & USBCMD_RESET))
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +0530510 break;
511 udelay(1);
512 cnt++;
513 }
514 if (cnt >= LINK_RESET_TIMEOUT_USEC)
515 return -ETIMEDOUT;
516
517 /* select ULPI phy */
Pavankumar Kondetiaa449e12011-11-04 11:09:26 +0530518 writel_relaxed(0x80000000, USB_PORTSC);
519 writel_relaxed(0x0, USB_AHBBURST);
Vijayavardhan Vennapusa5f32d7a2012-03-14 16:30:26 +0530520 writel_relaxed(0x08, USB_AHBMODE);
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +0530521
Pavankumar Kondetiaa449e12011-11-04 11:09:26 +0530522 return 0;
523}
524
Steve Mucklef132c6c2012-06-06 18:30:57 -0700525static int msm_otg_reset(struct usb_phy *phy)
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +0530526{
Steve Mucklef132c6c2012-06-06 18:30:57 -0700527 struct msm_otg *motg = container_of(phy, struct msm_otg, phy);
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +0530528 struct msm_otg_platform_data *pdata = motg->pdata;
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +0530529 int ret;
530 u32 val = 0;
531 u32 ulpi_val = 0;
532
Ofir Cohen4da266f2012-01-03 10:19:29 +0200533 /*
534 * USB PHY and Link reset also reset the USB BAM.
535 * Thus perform reset operation only once to avoid
536 * USB BAM reset on other cases e.g. USB cable disconnections.
537 */
538 if (pdata->disable_reset_on_disconnect) {
539 if (motg->reset_counter)
540 return 0;
541 else
542 motg->reset_counter++;
543 }
544
Pavankumar Kondeti923262e2012-04-20 15:34:24 +0530545 if (!IS_ERR(motg->clk))
546 clk_prepare_enable(motg->clk);
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +0530547 ret = msm_otg_phy_reset(motg);
548 if (ret) {
Steve Mucklef132c6c2012-06-06 18:30:57 -0700549 dev_err(phy->dev, "phy_reset failed\n");
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +0530550 return ret;
551 }
552
Pavankumar Kondeti4960f312011-12-06 15:46:14 +0530553 aca_id_turned_on = false;
Pavankumar Kondetiaa449e12011-11-04 11:09:26 +0530554 ret = msm_otg_link_reset(motg);
555 if (ret) {
Steve Mucklef132c6c2012-06-06 18:30:57 -0700556 dev_err(phy->dev, "link reset failed\n");
Pavankumar Kondetiaa449e12011-11-04 11:09:26 +0530557 return ret;
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +0530558 }
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +0530559 msleep(100);
560
Anji jonnalaa8b8d732011-12-06 10:03:24 +0530561 ulpi_init(motg);
562
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700563 /* Ensure that RESET operation is completed before turning off clock */
564 mb();
Pavankumar Kondetiaa449e12011-11-04 11:09:26 +0530565
Pavankumar Kondeti923262e2012-04-20 15:34:24 +0530566 if (!IS_ERR(motg->clk))
567 clk_disable_unprepare(motg->clk);
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +0530568
569 if (pdata->otg_control == OTG_PHY_CONTROL) {
Pavankumar Kondeti4960f312011-12-06 15:46:14 +0530570 val = readl_relaxed(USB_OTGSC);
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +0530571 if (pdata->mode == USB_OTG) {
572 ulpi_val = ULPI_INT_IDGRD | ULPI_INT_SESS_VALID;
573 val |= OTGSC_IDIE | OTGSC_BSVIE;
574 } else if (pdata->mode == USB_PERIPHERAL) {
575 ulpi_val = ULPI_INT_SESS_VALID;
576 val |= OTGSC_BSVIE;
577 }
Pavankumar Kondeti4960f312011-12-06 15:46:14 +0530578 writel_relaxed(val, USB_OTGSC);
Heikki Krogerus1d4c9292012-02-13 13:24:09 +0200579 ulpi_write(phy, ulpi_val, ULPI_USB_INT_EN_RISE);
580 ulpi_write(phy, ulpi_val, ULPI_USB_INT_EN_FALL);
Pavankumar Kondeti446f4542012-02-01 13:57:13 +0530581 } else if (pdata->otg_control == OTG_PMIC_CONTROL) {
Steve Mucklef132c6c2012-06-06 18:30:57 -0700582 ulpi_write(phy, OTG_COMP_DISABLE,
Vijayavardhan Vennapusa03171c72012-04-26 14:44:48 +0530583 ULPI_SET(ULPI_PWR_CLK_MNG_REG));
Pavankumar Kondeti446f4542012-02-01 13:57:13 +0530584 /* Enable PMIC pull-up */
585 pm8xxx_usb_id_pullup(1);
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +0530586 }
587
588 return 0;
589}
590
Vijayavardhan Vennapusaa3152032012-03-05 16:29:30 +0530591static const char *timer_string(int bit)
592{
593 switch (bit) {
594 case A_WAIT_VRISE: return "a_wait_vrise";
595 case A_WAIT_VFALL: return "a_wait_vfall";
596 case B_SRP_FAIL: return "b_srp_fail";
597 case A_WAIT_BCON: return "a_wait_bcon";
598 case A_AIDL_BDIS: return "a_aidl_bdis";
599 case A_BIDL_ADIS: return "a_bidl_adis";
600 case B_ASE0_BRST: return "b_ase0_brst";
601 case A_TST_MAINT: return "a_tst_maint";
602 case B_TST_SRP: return "b_tst_srp";
603 case B_TST_CONFIG: return "b_tst_config";
604 default: return "UNDEFINED";
605 }
606}
607
608static enum hrtimer_restart msm_otg_timer_func(struct hrtimer *hrtimer)
609{
610 struct msm_otg *motg = container_of(hrtimer, struct msm_otg, timer);
611
612 switch (motg->active_tmout) {
613 case A_WAIT_VRISE:
614 /* TODO: use vbus_vld interrupt */
615 set_bit(A_VBUS_VLD, &motg->inputs);
616 break;
617 case A_TST_MAINT:
618 /* OTG PET: End session after TA_TST_MAINT */
619 set_bit(A_BUS_DROP, &motg->inputs);
620 break;
621 case B_TST_SRP:
622 /*
623 * OTG PET: Initiate SRP after TB_TST_SRP of
624 * previous session end.
625 */
626 set_bit(B_BUS_REQ, &motg->inputs);
627 break;
628 case B_TST_CONFIG:
629 clear_bit(A_CONN, &motg->inputs);
630 break;
631 default:
632 set_bit(motg->active_tmout, &motg->tmouts);
633 }
634
635 pr_debug("expired %s timer\n", timer_string(motg->active_tmout));
636 queue_work(system_nrt_wq, &motg->sm_work);
637 return HRTIMER_NORESTART;
638}
639
640static void msm_otg_del_timer(struct msm_otg *motg)
641{
642 int bit = motg->active_tmout;
643
644 pr_debug("deleting %s timer. remaining %lld msec\n", timer_string(bit),
645 div_s64(ktime_to_us(hrtimer_get_remaining(
646 &motg->timer)), 1000));
647 hrtimer_cancel(&motg->timer);
648 clear_bit(bit, &motg->tmouts);
649}
650
651static void msm_otg_start_timer(struct msm_otg *motg, int time, int bit)
652{
653 clear_bit(bit, &motg->tmouts);
654 motg->active_tmout = bit;
655 pr_debug("starting %s timer\n", timer_string(bit));
656 hrtimer_start(&motg->timer,
657 ktime_set(time / 1000, (time % 1000) * 1000000),
658 HRTIMER_MODE_REL);
659}
660
661static void msm_otg_init_timer(struct msm_otg *motg)
662{
663 hrtimer_init(&motg->timer, CLOCK_MONOTONIC, HRTIMER_MODE_REL);
664 motg->timer.function = msm_otg_timer_func;
665}
666
Steve Mucklef132c6c2012-06-06 18:30:57 -0700667static int msm_otg_start_hnp(struct usb_otg *otg)
Vijayavardhan Vennapusaa3152032012-03-05 16:29:30 +0530668{
Steve Mucklef132c6c2012-06-06 18:30:57 -0700669 struct msm_otg *motg = container_of(otg->phy, struct msm_otg, phy);
Vijayavardhan Vennapusaa3152032012-03-05 16:29:30 +0530670
Steve Mucklef132c6c2012-06-06 18:30:57 -0700671 if (otg->phy->state != OTG_STATE_A_HOST) {
Vijayavardhan Vennapusaa3152032012-03-05 16:29:30 +0530672 pr_err("HNP can not be initiated in %s state\n",
Steve Mucklef132c6c2012-06-06 18:30:57 -0700673 otg_state_string(otg->phy->state));
Vijayavardhan Vennapusaa3152032012-03-05 16:29:30 +0530674 return -EINVAL;
675 }
676
677 pr_debug("A-Host: HNP initiated\n");
678 clear_bit(A_BUS_REQ, &motg->inputs);
679 queue_work(system_nrt_wq, &motg->sm_work);
680 return 0;
681}
682
Steve Mucklef132c6c2012-06-06 18:30:57 -0700683static int msm_otg_start_srp(struct usb_otg *otg)
Vijayavardhan Vennapusaa3152032012-03-05 16:29:30 +0530684{
Steve Mucklef132c6c2012-06-06 18:30:57 -0700685 struct msm_otg *motg = container_of(otg->phy, struct msm_otg, phy);
Vijayavardhan Vennapusaa3152032012-03-05 16:29:30 +0530686 u32 val;
687 int ret = 0;
688
Steve Mucklef132c6c2012-06-06 18:30:57 -0700689 if (otg->phy->state != OTG_STATE_B_IDLE) {
Vijayavardhan Vennapusaa3152032012-03-05 16:29:30 +0530690 pr_err("SRP can not be initiated in %s state\n",
Steve Mucklef132c6c2012-06-06 18:30:57 -0700691 otg_state_string(otg->phy->state));
Vijayavardhan Vennapusaa3152032012-03-05 16:29:30 +0530692 ret = -EINVAL;
693 goto out;
694 }
695
696 if ((jiffies - motg->b_last_se0_sess) < msecs_to_jiffies(TB_SRP_INIT)) {
697 pr_debug("initial conditions of SRP are not met. Try again"
698 "after some time\n");
699 ret = -EAGAIN;
700 goto out;
701 }
702
703 pr_debug("B-Device SRP started\n");
704
705 /*
706 * PHY won't pull D+ high unless it detects Vbus valid.
707 * Since by definition, SRP is only done when Vbus is not valid,
708 * software work-around needs to be used to spoof the PHY into
709 * thinking it is valid. This can be done using the VBUSVLDEXTSEL and
710 * VBUSVLDEXT register bits.
711 */
Steve Mucklef132c6c2012-06-06 18:30:57 -0700712 ulpi_write(otg->phy, 0x03, 0x97);
Vijayavardhan Vennapusaa3152032012-03-05 16:29:30 +0530713 /*
714 * Harware auto assist data pulsing: Data pulse is given
715 * for 7msec; wait for vbus
716 */
717 val = readl_relaxed(USB_OTGSC);
718 writel_relaxed((val & ~OTGSC_INTSTS_MASK) | OTGSC_HADP, USB_OTGSC);
719
720 /* VBUS plusing is obsoleted in OTG 2.0 supplement */
721out:
722 return ret;
723}
724
Steve Mucklef132c6c2012-06-06 18:30:57 -0700725static void msm_otg_host_hnp_enable(struct usb_otg *otg, bool enable)
Vijayavardhan Vennapusaa3152032012-03-05 16:29:30 +0530726{
727 struct usb_hcd *hcd = bus_to_hcd(otg->host);
728 struct usb_device *rhub = otg->host->root_hub;
729
730 if (enable) {
731 pm_runtime_disable(&rhub->dev);
732 rhub->state = USB_STATE_NOTATTACHED;
733 hcd->driver->bus_suspend(hcd);
734 clear_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags);
735 } else {
736 usb_remove_hcd(hcd);
Steve Mucklef132c6c2012-06-06 18:30:57 -0700737 msm_otg_reset(otg->phy);
Vijayavardhan Vennapusaa3152032012-03-05 16:29:30 +0530738 usb_add_hcd(hcd, hcd->irq, IRQF_SHARED);
739 }
740}
741
Steve Mucklef132c6c2012-06-06 18:30:57 -0700742static int msm_otg_set_suspend(struct usb_phy *phy, int suspend)
Pavankumar Kondeti8be99cf2011-08-04 10:48:08 +0530743{
Steve Mucklef132c6c2012-06-06 18:30:57 -0700744 struct msm_otg *motg = container_of(phy, struct msm_otg, phy);
Pavankumar Kondeti8be99cf2011-08-04 10:48:08 +0530745
Amit Blay6fa647a2012-05-24 14:12:08 +0300746 if (aca_enabled())
Vijayavardhan Vennapusaa3152032012-03-05 16:29:30 +0530747 return 0;
Pavankumar Kondeti8be99cf2011-08-04 10:48:08 +0530748
Amit Blayd0fe07b2012-09-05 16:42:09 +0300749 if (atomic_read(&motg->in_lpm) == suspend &&
750 !atomic_read(&motg->suspend_work_pending))
Jack Pham69e621d2012-06-25 18:48:07 -0700751 return 0;
752
Vijayavardhan Vennapusaa3152032012-03-05 16:29:30 +0530753 if (suspend) {
Steve Mucklef132c6c2012-06-06 18:30:57 -0700754 switch (phy->state) {
Vijayavardhan Vennapusaa3152032012-03-05 16:29:30 +0530755 case OTG_STATE_A_WAIT_BCON:
756 if (TA_WAIT_BCON > 0)
757 break;
758 /* fall through */
759 case OTG_STATE_A_HOST:
760 pr_debug("host bus suspend\n");
761 clear_bit(A_BUS_REQ, &motg->inputs);
762 queue_work(system_nrt_wq, &motg->sm_work);
763 break;
Amit Blay6fa647a2012-05-24 14:12:08 +0300764 case OTG_STATE_B_PERIPHERAL:
765 pr_debug("peripheral bus suspend\n");
766 if (!(motg->caps & ALLOW_LPM_ON_DEV_SUSPEND))
767 break;
768 set_bit(A_BUS_SUSPEND, &motg->inputs);
Amit Blayd0fe07b2012-09-05 16:42:09 +0300769 atomic_set(&motg->suspend_work_pending, 1);
770 queue_delayed_work(system_nrt_wq, &motg->suspend_work,
771 USB_SUSPEND_DELAY_TIME);
Amit Blay6fa647a2012-05-24 14:12:08 +0300772 break;
773
Vijayavardhan Vennapusaa3152032012-03-05 16:29:30 +0530774 default:
775 break;
776 }
777 } else {
Steve Mucklef132c6c2012-06-06 18:30:57 -0700778 switch (phy->state) {
Vijayavardhan Vennapusaa3152032012-03-05 16:29:30 +0530779 case OTG_STATE_A_SUSPEND:
780 /* Remote wakeup or resume */
781 set_bit(A_BUS_REQ, &motg->inputs);
Steve Mucklef132c6c2012-06-06 18:30:57 -0700782 phy->state = OTG_STATE_A_HOST;
Jack Pham5ca279b2012-05-14 18:42:54 -0700783
784 /* ensure hardware is not in low power mode */
Steve Mucklef132c6c2012-06-06 18:30:57 -0700785 pm_runtime_resume(phy->dev);
Vijayavardhan Vennapusaa3152032012-03-05 16:29:30 +0530786 break;
Amit Blay6fa647a2012-05-24 14:12:08 +0300787 case OTG_STATE_B_PERIPHERAL:
788 pr_debug("peripheral bus resume\n");
789 if (!(motg->caps & ALLOW_LPM_ON_DEV_SUSPEND))
790 break;
791 clear_bit(A_BUS_SUSPEND, &motg->inputs);
792 queue_work(system_nrt_wq, &motg->sm_work);
793 break;
Vijayavardhan Vennapusaa3152032012-03-05 16:29:30 +0530794 default:
795 break;
796 }
797 }
Pavankumar Kondeti8be99cf2011-08-04 10:48:08 +0530798 return 0;
799}
800
Pavankumar Kondeti87c01042010-12-07 17:53:58 +0530801#define PHY_SUSPEND_TIMEOUT_USEC (500 * 1000)
Pavankumar Kondeti70187732011-02-15 09:42:34 +0530802#define PHY_RESUME_TIMEOUT_USEC (100 * 1000)
803
804#ifdef CONFIG_PM_SLEEP
Pavankumar Kondeti87c01042010-12-07 17:53:58 +0530805static int msm_otg_suspend(struct msm_otg *motg)
806{
Heikki Krogerus1d4c9292012-02-13 13:24:09 +0200807 struct usb_phy *phy = &motg->phy;
808 struct usb_bus *bus = phy->otg->host;
Pavankumar Kondeti87c01042010-12-07 17:53:58 +0530809 struct msm_otg_platform_data *pdata = motg->pdata;
810 int cnt = 0;
Amit Blay6fa647a2012-05-24 14:12:08 +0300811 bool host_bus_suspend, device_bus_suspend, dcp;
Pavankumar Kondeti4960f312011-12-06 15:46:14 +0530812 u32 phy_ctrl_val = 0, cmd_val;
Stephen Boyd30ad10b2012-03-01 14:51:04 -0800813 unsigned ret;
Rajkumar Raghupathy242565d2011-12-13 12:10:59 +0530814 u32 portsc;
Pavankumar Kondeti87c01042010-12-07 17:53:58 +0530815
816 if (atomic_read(&motg->in_lpm))
817 return 0;
818
819 disable_irq(motg->irq);
Pavankumar Kondeti2aec9f32012-06-13 09:06:03 +0530820 host_bus_suspend = !test_bit(MHL, &motg->inputs) && phy->otg->host &&
821 !test_bit(ID, &motg->inputs);
Steve Mucklef132c6c2012-06-06 18:30:57 -0700822 device_bus_suspend = phy->otg->gadget && test_bit(ID, &motg->inputs) &&
Amit Blay6fa647a2012-05-24 14:12:08 +0300823 test_bit(A_BUS_SUSPEND, &motg->inputs) &&
824 motg->caps & ALLOW_LPM_ON_DEV_SUSPEND;
Pavankumar Kondeti283146f2012-01-12 12:51:19 +0530825 dcp = motg->chg_type == USB_DCP_CHARGER;
Jack Pham502bea32012-08-13 15:34:20 -0700826
827 /* charging detection in progress due to cable plug-in */
828 if (test_bit(B_SESS_VLD, &motg->inputs) && !device_bus_suspend &&
829 !dcp) {
830 enable_irq(motg->irq);
831 return -EBUSY;
832 }
833
Pavankumar Kondeti87c01042010-12-07 17:53:58 +0530834 /*
Pavankumar Kondeti04aebcb2011-05-04 10:19:49 +0530835 * Chipidea 45-nm PHY suspend sequence:
836 *
Pavankumar Kondeti87c01042010-12-07 17:53:58 +0530837 * Interrupt Latch Register auto-clear feature is not present
838 * in all PHY versions. Latch register is clear on read type.
839 * Clear latch register to avoid spurious wakeup from
840 * low power mode (LPM).
Pavankumar Kondeti04aebcb2011-05-04 10:19:49 +0530841 *
Pavankumar Kondeti87c01042010-12-07 17:53:58 +0530842 * PHY comparators are disabled when PHY enters into low power
843 * mode (LPM). Keep PHY comparators ON in LPM only when we expect
844 * VBUS/Id notifications from USB PHY. Otherwise turn off USB
845 * PHY comparators. This save significant amount of power.
Pavankumar Kondeti04aebcb2011-05-04 10:19:49 +0530846 *
Pavankumar Kondeti87c01042010-12-07 17:53:58 +0530847 * PLL is not turned off when PHY enters into low power mode (LPM).
848 * Disable PLL for maximum power savings.
849 */
Pavankumar Kondeti04aebcb2011-05-04 10:19:49 +0530850
851 if (motg->pdata->phy_type == CI_45NM_INTEGRATED_PHY) {
Heikki Krogerus1d4c9292012-02-13 13:24:09 +0200852 ulpi_read(phy, 0x14);
Pavankumar Kondeti04aebcb2011-05-04 10:19:49 +0530853 if (pdata->otg_control == OTG_PHY_CONTROL)
Heikki Krogerus1d4c9292012-02-13 13:24:09 +0200854 ulpi_write(phy, 0x01, 0x30);
855 ulpi_write(phy, 0x08, 0x09);
Pavankumar Kondeti04aebcb2011-05-04 10:19:49 +0530856 }
Pavankumar Kondeti87c01042010-12-07 17:53:58 +0530857
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700858
Rajkumar Raghupathy242565d2011-12-13 12:10:59 +0530859 /* Set the PHCD bit, only if it is not set by the controller.
Pavankumar Kondeti87c01042010-12-07 17:53:58 +0530860 * PHY may take some time or even fail to enter into low power
861 * mode (LPM). Hence poll for 500 msec and reset the PHY and link
862 * in failure case.
863 */
Rajkumar Raghupathy242565d2011-12-13 12:10:59 +0530864 portsc = readl_relaxed(USB_PORTSC);
865 if (!(portsc & PORTSC_PHCD)) {
866 writel_relaxed(portsc | PORTSC_PHCD,
867 USB_PORTSC);
868 while (cnt < PHY_SUSPEND_TIMEOUT_USEC) {
869 if (readl_relaxed(USB_PORTSC) & PORTSC_PHCD)
870 break;
871 udelay(1);
872 cnt++;
873 }
Pavankumar Kondeti87c01042010-12-07 17:53:58 +0530874 }
875
876 if (cnt >= PHY_SUSPEND_TIMEOUT_USEC) {
Heikki Krogerus1d4c9292012-02-13 13:24:09 +0200877 dev_err(phy->dev, "Unable to suspend PHY\n");
878 msm_otg_reset(phy);
Pavankumar Kondeti87c01042010-12-07 17:53:58 +0530879 enable_irq(motg->irq);
880 return -ETIMEDOUT;
881 }
882
883 /*
884 * PHY has capability to generate interrupt asynchronously in low
885 * power mode (LPM). This interrupt is level triggered. So USB IRQ
886 * line must be disabled till async interrupt enable bit is cleared
887 * in USBCMD register. Assert STP (ULPI interface STOP signal) to
888 * block data communication from PHY.
Pavankumar Kondeti6be675f2012-04-16 13:29:24 +0530889 *
890 * PHY retention mode is disallowed while entering to LPM with wall
891 * charger connected. But PHY is put into suspend mode. Hence
892 * enable asynchronous interrupt to detect charger disconnection when
893 * PMIC notifications are unavailable.
Pavankumar Kondeti87c01042010-12-07 17:53:58 +0530894 */
Pavankumar Kondeti4960f312011-12-06 15:46:14 +0530895 cmd_val = readl_relaxed(USB_USBCMD);
Amit Blay6fa647a2012-05-24 14:12:08 +0300896 if (host_bus_suspend || device_bus_suspend ||
897 (motg->pdata->otg_control == OTG_PHY_CONTROL && dcp))
Pavankumar Kondeti4960f312011-12-06 15:46:14 +0530898 cmd_val |= ASYNC_INTR_CTRL | ULPI_STP_CTRL;
899 else
900 cmd_val |= ULPI_STP_CTRL;
901 writel_relaxed(cmd_val, USB_USBCMD);
Pavankumar Kondeti87c01042010-12-07 17:53:58 +0530902
Pavankumar Kondeti283146f2012-01-12 12:51:19 +0530903 /*
904 * BC1.2 spec mandates PD to enable VDP_SRC when charging from DCP.
905 * PHY retention and collapse can not happen with VDP_SRC enabled.
906 */
Amit Blay6fa647a2012-05-24 14:12:08 +0300907 if (motg->caps & ALLOW_PHY_RETENTION && !host_bus_suspend &&
908 !device_bus_suspend && !dcp) {
Amit Blay58b31472011-11-18 09:39:39 +0200909 phy_ctrl_val = readl_relaxed(USB_PHY_CTRL);
910 if (motg->pdata->otg_control == OTG_PHY_CONTROL)
911 /* Enable PHY HV interrupts to wake MPM/Link */
912 phy_ctrl_val |=
913 (PHY_IDHV_INTEN | PHY_OTGSESSVLDHV_INTEN);
Pavankumar Kondeti04aebcb2011-05-04 10:19:49 +0530914
Amit Blay58b31472011-11-18 09:39:39 +0200915 writel_relaxed(phy_ctrl_val & ~PHY_RETEN, USB_PHY_CTRL);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700916 motg->lpm_flags |= PHY_RETENTIONED;
Pavankumar Kondeti04aebcb2011-05-04 10:19:49 +0530917 }
918
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700919 /* Ensure that above operation is completed before turning off clocks */
920 mb();
Ido Shayevitzc5c0f572012-07-31 13:58:45 +0300921 /* Consider clocks on workaround flag only in case of bus suspend */
922 if (!(phy->state == OTG_STATE_B_PERIPHERAL &&
923 test_bit(A_BUS_SUSPEND, &motg->inputs)) ||
924 !motg->pdata->core_clk_always_on_workaround) {
Amit Blay9b6e58b2012-06-18 13:12:49 +0300925 clk_disable_unprepare(motg->pclk);
926 clk_disable_unprepare(motg->core_clk);
Ido Shayevitzc5c0f572012-07-31 13:58:45 +0300927 motg->lpm_flags |= CLOCKS_DOWN;
Amit Blay9b6e58b2012-06-18 13:12:49 +0300928 }
Pavankumar Kondeti87c01042010-12-07 17:53:58 +0530929
Anji jonnala7da3f262011-12-02 17:22:14 -0800930 /* usb phy no more require TCXO clock, hence vote for TCXO disable */
Vijayavardhan Vennapusabbdd6082012-06-06 14:14:25 +0530931 if (!host_bus_suspend) {
932 ret = msm_xo_mode_vote(motg->xo_handle, MSM_XO_MODE_OFF);
933 if (ret)
Steve Muckle75c34ca2012-06-12 14:27:40 -0700934 dev_err(phy->dev, "%s failed to devote for "
Vijayavardhan Vennapusabbdd6082012-06-06 14:14:25 +0530935 "TCXO D0 buffer%d\n", __func__, ret);
936 else
937 motg->lpm_flags |= XO_SHUTDOWN;
938 }
Anji jonnala7da3f262011-12-02 17:22:14 -0800939
Pavankumar Kondeti283146f2012-01-12 12:51:19 +0530940 if (motg->caps & ALLOW_PHY_POWER_COLLAPSE &&
941 !host_bus_suspend && !dcp) {
Amit Blay81801aa2012-09-19 12:08:12 +0200942 msm_hsusb_ldo_enable(motg, USB_PHY_REG_OFF);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700943 motg->lpm_flags |= PHY_PWR_COLLAPSED;
Amit Blay81801aa2012-09-19 12:08:12 +0200944 } else if (motg->caps & ALLOW_PHY_REGULATORS_LPM &&
945 !host_bus_suspend && !device_bus_suspend && !dcp) {
946 msm_hsusb_ldo_enable(motg, USB_PHY_REG_LPM_ON);
947 motg->lpm_flags |= PHY_REGULATORS_LPM;
Anji jonnala0f73cac2011-05-04 10:19:46 +0530948 }
949
Vijayavardhan Vennapusafc464f02011-11-04 21:54:00 +0530950 if (motg->lpm_flags & PHY_RETENTIONED) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700951 msm_hsusb_config_vddcx(0);
Vijayavardhan Vennapusafc464f02011-11-04 21:54:00 +0530952 msm_hsusb_mhl_switch_enable(motg, 0);
953 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700954
Steve Mucklef132c6c2012-06-06 18:30:57 -0700955 if (device_may_wakeup(phy->dev)) {
Pavankumar Kondeti87c01042010-12-07 17:53:58 +0530956 enable_irq_wake(motg->irq);
Manu Gautamf8c45642012-08-10 10:20:56 -0700957 if (motg->async_irq)
958 enable_irq_wake(motg->async_irq);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700959 if (motg->pdata->pmic_id_irq)
960 enable_irq_wake(motg->pdata->pmic_id_irq);
Jack Pham87f202f2012-08-06 00:24:22 -0700961 if (pdata->otg_control == OTG_PHY_CONTROL &&
962 pdata->mpm_otgsessvld_int)
963 msm_mpm_set_pin_wake(pdata->mpm_otgsessvld_int, 1);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700964 }
Pavankumar Kondeti87c01042010-12-07 17:53:58 +0530965 if (bus)
966 clear_bit(HCD_FLAG_HW_ACCESSIBLE, &(bus_to_hcd(bus))->flags);
967
968 atomic_set(&motg->in_lpm, 1);
Manu Gautamf8c45642012-08-10 10:20:56 -0700969 /* Enable ASYNC IRQ (if present) during LPM */
970 if (motg->async_irq)
971 enable_irq(motg->async_irq);
Pavankumar Kondeti87c01042010-12-07 17:53:58 +0530972 enable_irq(motg->irq);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700973 wake_unlock(&motg->wlock);
Pavankumar Kondeti87c01042010-12-07 17:53:58 +0530974
Heikki Krogerus1d4c9292012-02-13 13:24:09 +0200975 dev_info(phy->dev, "USB in low power mode\n");
Pavankumar Kondeti87c01042010-12-07 17:53:58 +0530976
977 return 0;
978}
979
Pavankumar Kondeti87c01042010-12-07 17:53:58 +0530980static int msm_otg_resume(struct msm_otg *motg)
981{
Heikki Krogerus1d4c9292012-02-13 13:24:09 +0200982 struct usb_phy *phy = &motg->phy;
983 struct usb_bus *bus = phy->otg->host;
Jack Pham87f202f2012-08-06 00:24:22 -0700984 struct msm_otg_platform_data *pdata = motg->pdata;
Pavankumar Kondeti87c01042010-12-07 17:53:58 +0530985 int cnt = 0;
986 unsigned temp;
Amit Blay58b31472011-11-18 09:39:39 +0200987 u32 phy_ctrl_val = 0;
Anji jonnala7da3f262011-12-02 17:22:14 -0800988 unsigned ret;
Pavankumar Kondeti87c01042010-12-07 17:53:58 +0530989
990 if (!atomic_read(&motg->in_lpm))
991 return 0;
992
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700993 wake_lock(&motg->wlock);
Anji jonnala0f73cac2011-05-04 10:19:46 +0530994
Anji jonnala7da3f262011-12-02 17:22:14 -0800995 /* Vote for TCXO when waking up the phy */
Vijayavardhan Vennapusabbdd6082012-06-06 14:14:25 +0530996 if (motg->lpm_flags & XO_SHUTDOWN) {
997 ret = msm_xo_mode_vote(motg->xo_handle, MSM_XO_MODE_ON);
998 if (ret)
Steve Muckle75c34ca2012-06-12 14:27:40 -0700999 dev_err(phy->dev, "%s failed to vote for "
Vijayavardhan Vennapusabbdd6082012-06-06 14:14:25 +05301000 "TCXO D0 buffer%d\n", __func__, ret);
1001 motg->lpm_flags &= ~XO_SHUTDOWN;
1002 }
Pavankumar Kondeti87c01042010-12-07 17:53:58 +05301003
Ido Shayevitzc5c0f572012-07-31 13:58:45 +03001004 if (motg->lpm_flags & CLOCKS_DOWN) {
Amit Blay9b6e58b2012-06-18 13:12:49 +03001005 clk_prepare_enable(motg->core_clk);
1006 clk_prepare_enable(motg->pclk);
Ido Shayevitzc5c0f572012-07-31 13:58:45 +03001007 motg->lpm_flags &= ~CLOCKS_DOWN;
Amit Blay9b6e58b2012-06-18 13:12:49 +03001008 }
Pavankumar Kondeti87c01042010-12-07 17:53:58 +05301009
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001010 if (motg->lpm_flags & PHY_PWR_COLLAPSED) {
Amit Blay81801aa2012-09-19 12:08:12 +02001011 msm_hsusb_ldo_enable(motg, USB_PHY_REG_ON);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001012 motg->lpm_flags &= ~PHY_PWR_COLLAPSED;
Amit Blay81801aa2012-09-19 12:08:12 +02001013 } else if (motg->lpm_flags & PHY_REGULATORS_LPM) {
1014 msm_hsusb_ldo_enable(motg, USB_PHY_REG_LPM_OFF);
1015 motg->lpm_flags &= ~PHY_REGULATORS_LPM;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001016 }
1017
1018 if (motg->lpm_flags & PHY_RETENTIONED) {
Vijayavardhan Vennapusafc464f02011-11-04 21:54:00 +05301019 msm_hsusb_mhl_switch_enable(motg, 1);
Pavankumar Kondeti04aebcb2011-05-04 10:19:49 +05301020 msm_hsusb_config_vddcx(1);
Amit Blay58b31472011-11-18 09:39:39 +02001021 phy_ctrl_val = readl_relaxed(USB_PHY_CTRL);
1022 phy_ctrl_val |= PHY_RETEN;
1023 if (motg->pdata->otg_control == OTG_PHY_CONTROL)
1024 /* Disable PHY HV interrupts */
1025 phy_ctrl_val &=
1026 ~(PHY_IDHV_INTEN | PHY_OTGSESSVLDHV_INTEN);
1027 writel_relaxed(phy_ctrl_val, USB_PHY_CTRL);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001028 motg->lpm_flags &= ~PHY_RETENTIONED;
Pavankumar Kondeti04aebcb2011-05-04 10:19:49 +05301029 }
1030
Pavankumar Kondeti87c01042010-12-07 17:53:58 +05301031 temp = readl(USB_USBCMD);
1032 temp &= ~ASYNC_INTR_CTRL;
1033 temp &= ~ULPI_STP_CTRL;
1034 writel(temp, USB_USBCMD);
1035
1036 /*
1037 * PHY comes out of low power mode (LPM) in case of wakeup
1038 * from asynchronous interrupt.
1039 */
1040 if (!(readl(USB_PORTSC) & PORTSC_PHCD))
1041 goto skip_phy_resume;
1042
1043 writel(readl(USB_PORTSC) & ~PORTSC_PHCD, USB_PORTSC);
1044 while (cnt < PHY_RESUME_TIMEOUT_USEC) {
1045 if (!(readl(USB_PORTSC) & PORTSC_PHCD))
1046 break;
1047 udelay(1);
1048 cnt++;
1049 }
1050
1051 if (cnt >= PHY_RESUME_TIMEOUT_USEC) {
1052 /*
1053 * This is a fatal error. Reset the link and
1054 * PHY. USB state can not be restored. Re-insertion
1055 * of USB cable is the only way to get USB working.
1056 */
Heikki Krogerus1d4c9292012-02-13 13:24:09 +02001057 dev_err(phy->dev, "Unable to resume USB."
Pavankumar Kondeti87c01042010-12-07 17:53:58 +05301058 "Re-plugin the cable\n");
Heikki Krogerus1d4c9292012-02-13 13:24:09 +02001059 msm_otg_reset(phy);
Pavankumar Kondeti87c01042010-12-07 17:53:58 +05301060 }
1061
1062skip_phy_resume:
Steve Mucklef132c6c2012-06-06 18:30:57 -07001063 if (device_may_wakeup(phy->dev)) {
Pavankumar Kondeti87c01042010-12-07 17:53:58 +05301064 disable_irq_wake(motg->irq);
Manu Gautamf8c45642012-08-10 10:20:56 -07001065 if (motg->async_irq)
1066 disable_irq_wake(motg->async_irq);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001067 if (motg->pdata->pmic_id_irq)
1068 disable_irq_wake(motg->pdata->pmic_id_irq);
Jack Pham87f202f2012-08-06 00:24:22 -07001069 if (pdata->otg_control == OTG_PHY_CONTROL &&
1070 pdata->mpm_otgsessvld_int)
1071 msm_mpm_set_pin_wake(pdata->mpm_otgsessvld_int, 0);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001072 }
Pavankumar Kondeti87c01042010-12-07 17:53:58 +05301073 if (bus)
1074 set_bit(HCD_FLAG_HW_ACCESSIBLE, &(bus_to_hcd(bus))->flags);
1075
Pavankumar Kondeti2ce2c3a2011-05-02 11:56:33 +05301076 atomic_set(&motg->in_lpm, 0);
1077
Pavankumar Kondeti87c01042010-12-07 17:53:58 +05301078 if (motg->async_int) {
Manu Gautamf8c45642012-08-10 10:20:56 -07001079 /* Match the disable_irq call from ISR */
1080 enable_irq(motg->async_int);
Pavankumar Kondeti87c01042010-12-07 17:53:58 +05301081 motg->async_int = 0;
Pavankumar Kondeti87c01042010-12-07 17:53:58 +05301082 }
1083
Manu Gautamf8c45642012-08-10 10:20:56 -07001084 /* If ASYNC IRQ is present then keep it enabled only during LPM */
1085 if (motg->async_irq)
1086 disable_irq(motg->async_irq);
1087
Heikki Krogerus1d4c9292012-02-13 13:24:09 +02001088 dev_info(phy->dev, "USB exited from low power mode\n");
Pavankumar Kondeti87c01042010-12-07 17:53:58 +05301089
1090 return 0;
1091}
Pavankumar Kondeti70187732011-02-15 09:42:34 +05301092#endif
Pavankumar Kondeti87c01042010-12-07 17:53:58 +05301093
Sridhar Parasuram3c67a412012-09-26 09:36:22 -07001094static int msm_otg_notify_host_mode(struct msm_otg *motg, bool host_mode)
Abhijeet Dharmapurikar5e96aaa2012-06-26 11:21:03 -07001095{
Sridhar Parasuram3c67a412012-09-26 09:36:22 -07001096 if (!psy)
1097 goto psy_not_supported;
1098
1099 if (host_mode)
1100 power_supply_set_scope(psy, POWER_SUPPLY_SCOPE_SYSTEM);
1101 else
1102 power_supply_set_scope(psy, POWER_SUPPLY_SCOPE_DEVICE);
1103
1104psy_not_supported:
1105 dev_dbg(motg->phy.dev, "Power Supply doesn't support USB charger\n");
1106 return -ENXIO;
Abhijeet Dharmapurikar5e96aaa2012-06-26 11:21:03 -07001107}
1108
David Keitel081a3e22012-04-18 12:37:07 -07001109static int msm_otg_notify_chg_type(struct msm_otg *motg)
1110{
1111 static int charger_type;
David Keitelba8f8322012-06-01 17:14:10 -07001112
David Keitel081a3e22012-04-18 12:37:07 -07001113 /*
1114 * TODO
1115 * Unify OTG driver charger types and power supply charger types
1116 */
1117 if (charger_type == motg->chg_type)
1118 return 0;
1119
1120 if (motg->chg_type == USB_SDP_CHARGER)
1121 charger_type = POWER_SUPPLY_TYPE_USB;
1122 else if (motg->chg_type == USB_CDP_CHARGER)
1123 charger_type = POWER_SUPPLY_TYPE_USB_CDP;
Pavankumar Kondeti9ec21d32012-05-07 15:50:23 +05301124 else if (motg->chg_type == USB_DCP_CHARGER ||
1125 motg->chg_type == USB_PROPRIETARY_CHARGER)
David Keitel081a3e22012-04-18 12:37:07 -07001126 charger_type = POWER_SUPPLY_TYPE_USB_DCP;
1127 else if ((motg->chg_type == USB_ACA_DOCK_CHARGER ||
1128 motg->chg_type == USB_ACA_A_CHARGER ||
1129 motg->chg_type == USB_ACA_B_CHARGER ||
1130 motg->chg_type == USB_ACA_C_CHARGER))
1131 charger_type = POWER_SUPPLY_TYPE_USB_ACA;
1132 else
1133 charger_type = POWER_SUPPLY_TYPE_BATTERY;
1134
Sridhar Parasuram3c67a412012-09-26 09:36:22 -07001135 if (!psy) {
David Keitelba8f8322012-06-01 17:14:10 -07001136 pr_err("No USB power supply registered!\n");
1137 return -EINVAL;
1138 }
1139
1140 pr_debug("setting usb power supply type %d\n", charger_type);
Sridhar Parasuram3c67a412012-09-26 09:36:22 -07001141 power_supply_set_supply_type(psy, charger_type);
David Keitelba8f8322012-06-01 17:14:10 -07001142 return 0;
David Keitel081a3e22012-04-18 12:37:07 -07001143}
1144
Amit Blay0f7edf72012-01-15 10:11:27 +02001145static int msm_otg_notify_power_supply(struct msm_otg *motg, unsigned mA)
1146{
Amit Blay0f7edf72012-01-15 10:11:27 +02001147
Sridhar Parasuram3c67a412012-09-26 09:36:22 -07001148 if (!psy)
1149 goto psy_not_supported;
Amit Blay0f7edf72012-01-15 10:11:27 +02001150
Sridhar Parasuram3c67a412012-09-26 09:36:22 -07001151 if (motg->cur_power == 0 && mA > 0) {
David Keitelf5c5d602012-08-17 16:25:24 -07001152 /* Enable charging */
Sridhar Parasuram3c67a412012-09-26 09:36:22 -07001153 if (power_supply_set_online(psy, true))
1154 goto psy_not_supported;
1155 } else if (motg->cur_power > 0 && mA == 0) {
David Keitelf5c5d602012-08-17 16:25:24 -07001156 /* Disable charging */
Sridhar Parasuram3c67a412012-09-26 09:36:22 -07001157 if (power_supply_set_online(psy, false))
1158 goto psy_not_supported;
1159 return 0;
David Keitelf5c5d602012-08-17 16:25:24 -07001160 }
Sridhar Parasuram3c67a412012-09-26 09:36:22 -07001161 /* Set max current limit */
1162 if (power_supply_set_current_limit(psy, 1000*mA))
1163 goto psy_not_supported;
David Keitelf5c5d602012-08-17 16:25:24 -07001164
Amit Blay0f7edf72012-01-15 10:11:27 +02001165 return 0;
1166
Sridhar Parasuram3c67a412012-09-26 09:36:22 -07001167psy_not_supported:
1168 dev_dbg(motg->phy.dev, "Power Supply doesn't support USB charger\n");
Amit Blay0f7edf72012-01-15 10:11:27 +02001169 return -ENXIO;
1170}
1171
Pavankumar Kondetid8608522011-05-04 10:19:47 +05301172static void msm_otg_notify_charger(struct msm_otg *motg, unsigned mA)
1173{
Steve Mucklef132c6c2012-06-06 18:30:57 -07001174 struct usb_gadget *g = motg->phy.otg->gadget;
Vijayavardhan Vennapusaa3152032012-03-05 16:29:30 +05301175
1176 if (g && g->is_a_peripheral)
1177 return;
1178
Pavankumar Kondetiaa449e12011-11-04 11:09:26 +05301179 if ((motg->chg_type == USB_ACA_DOCK_CHARGER ||
1180 motg->chg_type == USB_ACA_A_CHARGER ||
1181 motg->chg_type == USB_ACA_B_CHARGER ||
1182 motg->chg_type == USB_ACA_C_CHARGER) &&
1183 mA > IDEV_ACA_CHG_LIMIT)
1184 mA = IDEV_ACA_CHG_LIMIT;
1185
David Keitel081a3e22012-04-18 12:37:07 -07001186 if (msm_otg_notify_chg_type(motg))
Steve Mucklef132c6c2012-06-06 18:30:57 -07001187 dev_err(motg->phy.dev,
David Keitel081a3e22012-04-18 12:37:07 -07001188 "Failed notifying %d charger type to PMIC\n",
1189 motg->chg_type);
1190
Pavankumar Kondetid8608522011-05-04 10:19:47 +05301191 if (motg->cur_power == mA)
1192 return;
1193
Heikki Krogerus1d4c9292012-02-13 13:24:09 +02001194 dev_info(motg->phy.dev, "Avail curr from USB = %u\n", mA);
Amit Blay0f7edf72012-01-15 10:11:27 +02001195
1196 /*
1197 * Use Power Supply API if supported, otherwise fallback
1198 * to legacy pm8921 API.
1199 */
1200 if (msm_otg_notify_power_supply(motg, mA))
1201 pm8921_charger_vbus_draw(mA);
1202
Pavankumar Kondetid8608522011-05-04 10:19:47 +05301203 motg->cur_power = mA;
1204}
1205
Heikki Krogerus1d4c9292012-02-13 13:24:09 +02001206static int msm_otg_set_power(struct usb_phy *phy, unsigned mA)
Pavankumar Kondetid8608522011-05-04 10:19:47 +05301207{
Heikki Krogerus1d4c9292012-02-13 13:24:09 +02001208 struct msm_otg *motg = container_of(phy, struct msm_otg, phy);
Pavankumar Kondetid8608522011-05-04 10:19:47 +05301209
1210 /*
1211 * Gadget driver uses set_power method to notify about the
1212 * available current based on suspend/configured states.
1213 *
1214 * IDEV_CHG can be drawn irrespective of suspend/un-configured
1215 * states when CDP/ACA is connected.
1216 */
1217 if (motg->chg_type == USB_SDP_CHARGER)
1218 msm_otg_notify_charger(motg, mA);
1219
1220 return 0;
1221}
1222
Steve Mucklef132c6c2012-06-06 18:30:57 -07001223static void msm_otg_start_host(struct usb_otg *otg, int on)
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05301224{
Steve Mucklef132c6c2012-06-06 18:30:57 -07001225 struct msm_otg *motg = container_of(otg->phy, struct msm_otg, phy);
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05301226 struct msm_otg_platform_data *pdata = motg->pdata;
1227 struct usb_hcd *hcd;
1228
1229 if (!otg->host)
1230 return;
1231
1232 hcd = bus_to_hcd(otg->host);
1233
1234 if (on) {
Steve Mucklef132c6c2012-06-06 18:30:57 -07001235 dev_dbg(otg->phy->dev, "host on\n");
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05301236
Vijayavardhan Vennapusa03171c72012-04-26 14:44:48 +05301237 if (pdata->otg_control == OTG_PHY_CONTROL)
Steve Mucklef132c6c2012-06-06 18:30:57 -07001238 ulpi_write(otg->phy, OTG_COMP_DISABLE,
Vijayavardhan Vennapusa03171c72012-04-26 14:44:48 +05301239 ULPI_SET(ULPI_PWR_CLK_MNG_REG));
1240
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05301241 /*
1242 * Some boards have a switch cotrolled by gpio
1243 * to enable/disable internal HUB. Enable internal
1244 * HUB before kicking the host.
1245 */
1246 if (pdata->setup_gpio)
1247 pdata->setup_gpio(OTG_STATE_A_HOST);
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05301248 usb_add_hcd(hcd, hcd->irq, IRQF_SHARED);
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05301249 } else {
Steve Mucklef132c6c2012-06-06 18:30:57 -07001250 dev_dbg(otg->phy->dev, "host off\n");
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05301251
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05301252 usb_remove_hcd(hcd);
Pavankumar Kondetiaa449e12011-11-04 11:09:26 +05301253 /* HCD core reset all bits of PORTSC. select ULPI phy */
1254 writel_relaxed(0x80000000, USB_PORTSC);
1255
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05301256 if (pdata->setup_gpio)
1257 pdata->setup_gpio(OTG_STATE_UNDEFINED);
Vijayavardhan Vennapusa03171c72012-04-26 14:44:48 +05301258
1259 if (pdata->otg_control == OTG_PHY_CONTROL)
Steve Mucklef132c6c2012-06-06 18:30:57 -07001260 ulpi_write(otg->phy, OTG_COMP_DISABLE,
Vijayavardhan Vennapusa03171c72012-04-26 14:44:48 +05301261 ULPI_CLR(ULPI_PWR_CLK_MNG_REG));
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05301262 }
1263}
1264
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001265static int msm_otg_usbdev_notify(struct notifier_block *self,
1266 unsigned long action, void *priv)
1267{
1268 struct msm_otg *motg = container_of(self, struct msm_otg, usbdev_nb);
Steve Mucklef132c6c2012-06-06 18:30:57 -07001269 struct usb_otg *otg = motg->phy.otg;
Pavankumar Kondetiaa449e12011-11-04 11:09:26 +05301270 struct usb_device *udev = priv;
1271
Pavankumar Kondetiaa449e12011-11-04 11:09:26 +05301272 if (action == USB_BUS_ADD || action == USB_BUS_REMOVE)
1273 goto out;
1274
Steve Mucklef132c6c2012-06-06 18:30:57 -07001275 if (udev->bus != otg->host)
Pavankumar Kondetiaa449e12011-11-04 11:09:26 +05301276 goto out;
1277 /*
1278 * Interested in devices connected directly to the root hub.
1279 * ACA dock can supply IDEV_CHG irrespective devices connected
1280 * on the accessory port.
1281 */
1282 if (!udev->parent || udev->parent->parent ||
1283 motg->chg_type == USB_ACA_DOCK_CHARGER)
1284 goto out;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001285
1286 switch (action) {
1287 case USB_DEVICE_ADD:
Vijayavardhan Vennapusaa3152032012-03-05 16:29:30 +05301288 if (aca_enabled())
1289 usb_disable_autosuspend(udev);
Steve Mucklef132c6c2012-06-06 18:30:57 -07001290 if (otg->phy->state == OTG_STATE_A_WAIT_BCON) {
Vijayavardhan Vennapusaa3152032012-03-05 16:29:30 +05301291 pr_debug("B_CONN set\n");
1292 set_bit(B_CONN, &motg->inputs);
1293 msm_otg_del_timer(motg);
Steve Mucklef132c6c2012-06-06 18:30:57 -07001294 otg->phy->state = OTG_STATE_A_HOST;
Vijayavardhan Vennapusaa3152032012-03-05 16:29:30 +05301295 /*
1296 * OTG PET: A-device must end session within
1297 * 10 sec after PET enumeration.
1298 */
1299 if (udev->quirks & USB_QUIRK_OTG_PET)
1300 msm_otg_start_timer(motg, TA_TST_MAINT,
1301 A_TST_MAINT);
1302 }
Pavankumar Kondetiaa449e12011-11-04 11:09:26 +05301303 /* fall through */
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001304 case USB_DEVICE_CONFIG:
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001305 if (udev->actconfig)
1306 motg->mA_port = udev->actconfig->desc.bMaxPower * 2;
1307 else
1308 motg->mA_port = IUNIT;
Steve Mucklef132c6c2012-06-06 18:30:57 -07001309 if (otg->phy->state == OTG_STATE_B_HOST)
Vijayavardhan Vennapusaa3152032012-03-05 16:29:30 +05301310 msm_otg_del_timer(motg);
Pavankumar Kondetiaa449e12011-11-04 11:09:26 +05301311 break;
1312 case USB_DEVICE_REMOVE:
Steve Mucklef132c6c2012-06-06 18:30:57 -07001313 if ((otg->phy->state == OTG_STATE_A_HOST) ||
1314 (otg->phy->state == OTG_STATE_A_SUSPEND)) {
Vijayavardhan Vennapusaa3152032012-03-05 16:29:30 +05301315 pr_debug("B_CONN clear\n");
1316 clear_bit(B_CONN, &motg->inputs);
1317 /*
1318 * OTG PET: A-device must end session after
1319 * PET disconnection if it is enumerated
1320 * with bcdDevice[0] = 1. USB core sets
1321 * bus->otg_vbus_off for us. clear it here.
1322 */
1323 if (udev->bus->otg_vbus_off) {
1324 udev->bus->otg_vbus_off = 0;
1325 set_bit(A_BUS_DROP, &motg->inputs);
1326 }
1327 queue_work(system_nrt_wq, &motg->sm_work);
1328 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001329 default:
1330 break;
1331 }
Pavankumar Kondetiaa449e12011-11-04 11:09:26 +05301332 if (test_bit(ID_A, &motg->inputs))
1333 msm_otg_notify_charger(motg, IDEV_ACA_CHG_MAX -
1334 motg->mA_port);
1335out:
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001336 return NOTIFY_OK;
1337}
1338
Mayank Ranae3926882011-12-26 09:47:54 +05301339static void msm_hsusb_vbus_power(struct msm_otg *motg, bool on)
1340{
1341 int ret;
1342 static bool vbus_is_on;
1343
1344 if (vbus_is_on == on)
1345 return;
1346
1347 if (motg->pdata->vbus_power) {
Mayank Rana91f597e2012-01-20 10:12:06 +05301348 ret = motg->pdata->vbus_power(on);
1349 if (!ret)
1350 vbus_is_on = on;
Mayank Ranae3926882011-12-26 09:47:54 +05301351 return;
1352 }
1353
1354 if (!vbus_otg) {
1355 pr_err("vbus_otg is NULL.");
1356 return;
1357 }
1358
Abhijeet Dharmapurikarbe054882012-01-03 20:27:07 -08001359 /*
1360 * if entering host mode tell the charger to not draw any current
Abhijeet Dharmapurikar6d941212012-03-05 10:30:56 -08001361 * from usb before turning on the boost.
1362 * if exiting host mode disable the boost before enabling to draw
1363 * current from the source.
Abhijeet Dharmapurikarbe054882012-01-03 20:27:07 -08001364 */
Mayank Ranae3926882011-12-26 09:47:54 +05301365 if (on) {
Abhijeet Dharmapurikar5e96aaa2012-06-26 11:21:03 -07001366 msm_otg_notify_host_mode(motg, on);
Mayank Ranae3926882011-12-26 09:47:54 +05301367 ret = regulator_enable(vbus_otg);
1368 if (ret) {
1369 pr_err("unable to enable vbus_otg\n");
1370 return;
1371 }
1372 vbus_is_on = true;
1373 } else {
1374 ret = regulator_disable(vbus_otg);
1375 if (ret) {
1376 pr_err("unable to disable vbus_otg\n");
1377 return;
1378 }
Abhijeet Dharmapurikar5e96aaa2012-06-26 11:21:03 -07001379 msm_otg_notify_host_mode(motg, on);
Mayank Ranae3926882011-12-26 09:47:54 +05301380 vbus_is_on = false;
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05301381 }
1382}
1383
Heikki Krogerus1d4c9292012-02-13 13:24:09 +02001384static int msm_otg_set_host(struct usb_otg *otg, struct usb_bus *host)
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05301385{
Heikki Krogerus1d4c9292012-02-13 13:24:09 +02001386 struct msm_otg *motg = container_of(otg->phy, struct msm_otg, phy);
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05301387 struct usb_hcd *hcd;
1388
1389 /*
1390 * Fail host registration if this board can support
1391 * only peripheral configuration.
1392 */
1393 if (motg->pdata->mode == USB_PERIPHERAL) {
Heikki Krogerus1d4c9292012-02-13 13:24:09 +02001394 dev_info(otg->phy->dev, "Host mode is not supported\n");
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05301395 return -ENODEV;
1396 }
1397
Mayank Ranae3926882011-12-26 09:47:54 +05301398 if (!motg->pdata->vbus_power && host) {
Steve Mucklef132c6c2012-06-06 18:30:57 -07001399 vbus_otg = devm_regulator_get(motg->phy.dev, "vbus_otg");
Mayank Ranae3926882011-12-26 09:47:54 +05301400 if (IS_ERR(vbus_otg)) {
1401 pr_err("Unable to get vbus_otg\n");
1402 return -ENODEV;
1403 }
1404 }
1405
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05301406 if (!host) {
Heikki Krogerus1d4c9292012-02-13 13:24:09 +02001407 if (otg->phy->state == OTG_STATE_A_HOST) {
1408 pm_runtime_get_sync(otg->phy->dev);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001409 usb_unregister_notify(&motg->usbdev_nb);
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05301410 msm_otg_start_host(otg, 0);
Mayank Ranae3926882011-12-26 09:47:54 +05301411 msm_hsusb_vbus_power(motg, 0);
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05301412 otg->host = NULL;
Heikki Krogerus1d4c9292012-02-13 13:24:09 +02001413 otg->phy->state = OTG_STATE_UNDEFINED;
Vijayavardhan Vennapusaa3152032012-03-05 16:29:30 +05301414 queue_work(system_nrt_wq, &motg->sm_work);
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05301415 } else {
1416 otg->host = NULL;
1417 }
1418
1419 return 0;
1420 }
1421
1422 hcd = bus_to_hcd(host);
1423 hcd->power_budget = motg->pdata->power_budget;
1424
Vijayavardhan Vennapusaa3152032012-03-05 16:29:30 +05301425#ifdef CONFIG_USB_OTG
1426 host->otg_port = 1;
1427#endif
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001428 motg->usbdev_nb.notifier_call = msm_otg_usbdev_notify;
1429 usb_register_notify(&motg->usbdev_nb);
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05301430 otg->host = host;
Heikki Krogerus1d4c9292012-02-13 13:24:09 +02001431 dev_dbg(otg->phy->dev, "host driver registered w/ tranceiver\n");
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05301432
1433 /*
1434 * Kick the state machine work, if peripheral is not supported
1435 * or peripheral is already registered with us.
1436 */
Pavankumar Kondeti87c01042010-12-07 17:53:58 +05301437 if (motg->pdata->mode == USB_HOST || otg->gadget) {
Heikki Krogerus1d4c9292012-02-13 13:24:09 +02001438 pm_runtime_get_sync(otg->phy->dev);
Vijayavardhan Vennapusaa3152032012-03-05 16:29:30 +05301439 queue_work(system_nrt_wq, &motg->sm_work);
Pavankumar Kondeti87c01042010-12-07 17:53:58 +05301440 }
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05301441
1442 return 0;
1443}
1444
Steve Mucklef132c6c2012-06-06 18:30:57 -07001445static void msm_otg_start_peripheral(struct usb_otg *otg, int on)
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05301446{
Manu Gautamcd82e9d2011-12-20 14:17:28 +05301447 int ret;
Steve Mucklef132c6c2012-06-06 18:30:57 -07001448 struct msm_otg *motg = container_of(otg->phy, struct msm_otg, phy);
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05301449 struct msm_otg_platform_data *pdata = motg->pdata;
1450
1451 if (!otg->gadget)
1452 return;
1453
1454 if (on) {
Steve Mucklef132c6c2012-06-06 18:30:57 -07001455 dev_dbg(otg->phy->dev, "gadget on\n");
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05301456 /*
1457 * Some boards have a switch cotrolled by gpio
1458 * to enable/disable internal HUB. Disable internal
1459 * HUB before kicking the gadget.
1460 */
1461 if (pdata->setup_gpio)
1462 pdata->setup_gpio(OTG_STATE_B_PERIPHERAL);
Ofir Cohen94213a72012-05-03 14:26:32 +03001463
Manu Gautamcd82e9d2011-12-20 14:17:28 +05301464 /* Configure BUS performance parameters for MAX bandwidth */
Manu Gautam8bdcc592012-03-06 11:26:06 +05301465 if (motg->bus_perf_client && debug_bus_voting_enabled) {
Manu Gautamcd82e9d2011-12-20 14:17:28 +05301466 ret = msm_bus_scale_client_update_request(
1467 motg->bus_perf_client, 1);
1468 if (ret)
Steve Mucklef132c6c2012-06-06 18:30:57 -07001469 dev_err(motg->phy.dev, "%s: Failed to vote for "
Manu Gautamcd82e9d2011-12-20 14:17:28 +05301470 "bus bandwidth %d\n", __func__, ret);
1471 }
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05301472 usb_gadget_vbus_connect(otg->gadget);
1473 } else {
Steve Mucklef132c6c2012-06-06 18:30:57 -07001474 dev_dbg(otg->phy->dev, "gadget off\n");
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05301475 usb_gadget_vbus_disconnect(otg->gadget);
Manu Gautamcd82e9d2011-12-20 14:17:28 +05301476 /* Configure BUS performance parameters to default */
1477 if (motg->bus_perf_client) {
1478 ret = msm_bus_scale_client_update_request(
1479 motg->bus_perf_client, 0);
1480 if (ret)
Steve Mucklef132c6c2012-06-06 18:30:57 -07001481 dev_err(motg->phy.dev, "%s: Failed to devote "
Manu Gautamcd82e9d2011-12-20 14:17:28 +05301482 "for bus bw %d\n", __func__, ret);
1483 }
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05301484 if (pdata->setup_gpio)
1485 pdata->setup_gpio(OTG_STATE_UNDEFINED);
1486 }
1487
1488}
1489
Heikki Krogerus1d4c9292012-02-13 13:24:09 +02001490static int msm_otg_set_peripheral(struct usb_otg *otg,
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05301491 struct usb_gadget *gadget)
1492{
Heikki Krogerus1d4c9292012-02-13 13:24:09 +02001493 struct msm_otg *motg = container_of(otg->phy, struct msm_otg, phy);
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05301494
1495 /*
1496 * Fail peripheral registration if this board can support
1497 * only host configuration.
1498 */
1499 if (motg->pdata->mode == USB_HOST) {
Heikki Krogerus1d4c9292012-02-13 13:24:09 +02001500 dev_info(otg->phy->dev, "Peripheral mode is not supported\n");
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05301501 return -ENODEV;
1502 }
1503
1504 if (!gadget) {
Heikki Krogerus1d4c9292012-02-13 13:24:09 +02001505 if (otg->phy->state == OTG_STATE_B_PERIPHERAL) {
1506 pm_runtime_get_sync(otg->phy->dev);
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05301507 msm_otg_start_peripheral(otg, 0);
1508 otg->gadget = NULL;
Heikki Krogerus1d4c9292012-02-13 13:24:09 +02001509 otg->phy->state = OTG_STATE_UNDEFINED;
Vijayavardhan Vennapusaa3152032012-03-05 16:29:30 +05301510 queue_work(system_nrt_wq, &motg->sm_work);
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05301511 } else {
1512 otg->gadget = NULL;
1513 }
1514
1515 return 0;
1516 }
1517 otg->gadget = gadget;
Heikki Krogerus1d4c9292012-02-13 13:24:09 +02001518 dev_dbg(otg->phy->dev, "peripheral driver registered w/ tranceiver\n");
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05301519
1520 /*
1521 * Kick the state machine work, if host is not supported
1522 * or host is already registered with us.
1523 */
Pavankumar Kondeti87c01042010-12-07 17:53:58 +05301524 if (motg->pdata->mode == USB_PERIPHERAL || otg->host) {
Heikki Krogerus1d4c9292012-02-13 13:24:09 +02001525 pm_runtime_get_sync(otg->phy->dev);
Vijayavardhan Vennapusaa3152032012-03-05 16:29:30 +05301526 queue_work(system_nrt_wq, &motg->sm_work);
Pavankumar Kondeti87c01042010-12-07 17:53:58 +05301527 }
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05301528
1529 return 0;
1530}
1531
Pavankumar Kondeti2aec9f32012-06-13 09:06:03 +05301532static int msm_otg_mhl_register_callback(struct msm_otg *motg,
1533 void (*callback)(int on))
1534{
1535 struct usb_phy *phy = &motg->phy;
1536 int ret;
1537
Manoj Raoa7bddd12012-08-27 20:36:45 -07001538 if (!motg->pdata->mhl_enable) {
1539 dev_dbg(phy->dev, "MHL feature not enabled\n");
1540 return -ENODEV;
1541 }
1542
Pavankumar Kondeti2aec9f32012-06-13 09:06:03 +05301543 if (motg->pdata->otg_control != OTG_PMIC_CONTROL ||
1544 !motg->pdata->pmic_id_irq) {
1545 dev_dbg(phy->dev, "MHL can not be supported without PMIC Id\n");
1546 return -ENODEV;
1547 }
1548
1549 if (!motg->pdata->mhl_dev_name) {
1550 dev_dbg(phy->dev, "MHL device name does not exist.\n");
1551 return -ENODEV;
1552 }
1553
1554 if (callback)
1555 ret = mhl_register_callback(motg->pdata->mhl_dev_name,
1556 callback);
1557 else
1558 ret = mhl_unregister_callback(motg->pdata->mhl_dev_name);
1559
1560 if (ret)
1561 dev_dbg(phy->dev, "mhl_register_callback(%s) return error=%d\n",
1562 motg->pdata->mhl_dev_name, ret);
1563 else
1564 motg->mhl_enabled = true;
1565
1566 return ret;
1567}
1568
1569static void msm_otg_mhl_notify_online(int on)
1570{
1571 struct msm_otg *motg = the_msm_otg;
1572 struct usb_phy *phy = &motg->phy;
1573 bool queue = false;
1574
1575 dev_dbg(phy->dev, "notify MHL %s%s\n", on ? "" : "dis", "connected");
1576
1577 if (on) {
1578 set_bit(MHL, &motg->inputs);
1579 } else {
1580 clear_bit(MHL, &motg->inputs);
1581 queue = true;
1582 }
1583
1584 if (queue && phy->state != OTG_STATE_UNDEFINED)
1585 schedule_work(&motg->sm_work);
1586}
1587
1588static bool msm_otg_is_mhl(struct msm_otg *motg)
1589{
1590 struct usb_phy *phy = &motg->phy;
1591 int is_mhl, ret;
1592
1593 ret = mhl_device_discovery(motg->pdata->mhl_dev_name, &is_mhl);
1594 if (ret || is_mhl != MHL_DISCOVERY_RESULT_MHL) {
1595 /*
1596 * MHL driver calls our callback saying that MHL connected
1597 * if RID_GND is detected. But at later part of discovery
1598 * it may figure out MHL is not connected and returns
1599 * false. Hence clear MHL input here.
1600 */
1601 clear_bit(MHL, &motg->inputs);
1602 dev_dbg(phy->dev, "MHL device not found\n");
1603 return false;
1604 }
1605
1606 set_bit(MHL, &motg->inputs);
1607 dev_dbg(phy->dev, "MHL device found\n");
1608 return true;
1609}
1610
1611static bool msm_chg_mhl_detect(struct msm_otg *motg)
1612{
1613 bool ret, id;
1614 unsigned long flags;
1615
1616 if (!motg->mhl_enabled)
1617 return false;
1618
1619 local_irq_save(flags);
1620 id = irq_read_line(motg->pdata->pmic_id_irq);
1621 local_irq_restore(flags);
1622
1623 if (id)
1624 return false;
1625
1626 mhl_det_in_progress = true;
1627 ret = msm_otg_is_mhl(motg);
1628 mhl_det_in_progress = false;
1629
1630 return ret;
1631}
1632
Pavankumar Kondeti458d8792012-09-28 14:45:18 +05301633static void msm_otg_chg_check_timer_func(unsigned long data)
1634{
1635 struct msm_otg *motg = (struct msm_otg *) data;
1636 struct usb_otg *otg = motg->phy.otg;
1637
1638 if (atomic_read(&motg->in_lpm) ||
1639 !test_bit(B_SESS_VLD, &motg->inputs) ||
1640 otg->phy->state != OTG_STATE_B_PERIPHERAL ||
1641 otg->gadget->speed != USB_SPEED_UNKNOWN) {
1642 dev_dbg(otg->phy->dev, "Nothing to do in chg_check_timer\n");
1643 return;
1644 }
1645
1646 if ((readl_relaxed(USB_PORTSC) & PORTSC_LS) == PORTSC_LS) {
1647 dev_dbg(otg->phy->dev, "DCP is detected as SDP\n");
1648 set_bit(B_FALSE_SDP, &motg->inputs);
1649 queue_work(system_nrt_wq, &motg->sm_work);
1650 }
1651}
1652
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001653static bool msm_chg_aca_detect(struct msm_otg *motg)
1654{
Steve Mucklef132c6c2012-06-06 18:30:57 -07001655 struct usb_phy *phy = &motg->phy;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001656 u32 int_sts;
1657 bool ret = false;
1658
Pavankumar Kondetiaa449e12011-11-04 11:09:26 +05301659 if (!aca_enabled())
1660 goto out;
1661
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001662 if (motg->pdata->phy_type == CI_45NM_INTEGRATED_PHY)
1663 goto out;
1664
Steve Mucklef132c6c2012-06-06 18:30:57 -07001665 int_sts = ulpi_read(phy, 0x87);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001666 switch (int_sts & 0x1C) {
1667 case 0x08:
1668 if (!test_and_set_bit(ID_A, &motg->inputs)) {
Steve Mucklef132c6c2012-06-06 18:30:57 -07001669 dev_dbg(phy->dev, "ID_A\n");
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001670 motg->chg_type = USB_ACA_A_CHARGER;
1671 motg->chg_state = USB_CHG_STATE_DETECTED;
1672 clear_bit(ID_B, &motg->inputs);
1673 clear_bit(ID_C, &motg->inputs);
Pavankumar Kondetiaa449e12011-11-04 11:09:26 +05301674 set_bit(ID, &motg->inputs);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001675 ret = true;
1676 }
1677 break;
1678 case 0x0C:
1679 if (!test_and_set_bit(ID_B, &motg->inputs)) {
Steve Mucklef132c6c2012-06-06 18:30:57 -07001680 dev_dbg(phy->dev, "ID_B\n");
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001681 motg->chg_type = USB_ACA_B_CHARGER;
1682 motg->chg_state = USB_CHG_STATE_DETECTED;
1683 clear_bit(ID_A, &motg->inputs);
1684 clear_bit(ID_C, &motg->inputs);
Pavankumar Kondetiaa449e12011-11-04 11:09:26 +05301685 set_bit(ID, &motg->inputs);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001686 ret = true;
1687 }
1688 break;
1689 case 0x10:
1690 if (!test_and_set_bit(ID_C, &motg->inputs)) {
Steve Mucklef132c6c2012-06-06 18:30:57 -07001691 dev_dbg(phy->dev, "ID_C\n");
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001692 motg->chg_type = USB_ACA_C_CHARGER;
1693 motg->chg_state = USB_CHG_STATE_DETECTED;
1694 clear_bit(ID_A, &motg->inputs);
1695 clear_bit(ID_B, &motg->inputs);
Pavankumar Kondetiaa449e12011-11-04 11:09:26 +05301696 set_bit(ID, &motg->inputs);
1697 ret = true;
1698 }
1699 break;
1700 case 0x04:
1701 if (test_and_clear_bit(ID, &motg->inputs)) {
Steve Mucklef132c6c2012-06-06 18:30:57 -07001702 dev_dbg(phy->dev, "ID_GND\n");
Pavankumar Kondetiaa449e12011-11-04 11:09:26 +05301703 motg->chg_type = USB_INVALID_CHARGER;
1704 motg->chg_state = USB_CHG_STATE_UNDEFINED;
1705 clear_bit(ID_A, &motg->inputs);
1706 clear_bit(ID_B, &motg->inputs);
1707 clear_bit(ID_C, &motg->inputs);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001708 ret = true;
1709 }
1710 break;
1711 default:
1712 ret = test_and_clear_bit(ID_A, &motg->inputs) |
1713 test_and_clear_bit(ID_B, &motg->inputs) |
Pavankumar Kondetiaa449e12011-11-04 11:09:26 +05301714 test_and_clear_bit(ID_C, &motg->inputs) |
1715 !test_and_set_bit(ID, &motg->inputs);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001716 if (ret) {
Steve Mucklef132c6c2012-06-06 18:30:57 -07001717 dev_dbg(phy->dev, "ID A/B/C/GND is no more\n");
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001718 motg->chg_type = USB_INVALID_CHARGER;
1719 motg->chg_state = USB_CHG_STATE_UNDEFINED;
1720 }
1721 }
1722out:
1723 return ret;
1724}
1725
1726static void msm_chg_enable_aca_det(struct msm_otg *motg)
1727{
Steve Mucklef132c6c2012-06-06 18:30:57 -07001728 struct usb_phy *phy = &motg->phy;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001729
Pavankumar Kondetiaa449e12011-11-04 11:09:26 +05301730 if (!aca_enabled())
1731 return;
1732
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001733 switch (motg->pdata->phy_type) {
1734 case SNPS_28NM_INTEGRATED_PHY:
Pavankumar Kondetiaa449e12011-11-04 11:09:26 +05301735 /* Disable ID_GND in link and PHY */
1736 writel_relaxed(readl_relaxed(USB_OTGSC) & ~(OTGSC_IDPU |
1737 OTGSC_IDIE), USB_OTGSC);
Steve Mucklef132c6c2012-06-06 18:30:57 -07001738 ulpi_write(phy, 0x01, 0x0C);
1739 ulpi_write(phy, 0x10, 0x0F);
1740 ulpi_write(phy, 0x10, 0x12);
Pavankumar Kondeti446f4542012-02-01 13:57:13 +05301741 /* Disable PMIC ID pull-up */
1742 pm8xxx_usb_id_pullup(0);
Pavankumar Kondetiaa449e12011-11-04 11:09:26 +05301743 /* Enable ACA ID detection */
Steve Mucklef132c6c2012-06-06 18:30:57 -07001744 ulpi_write(phy, 0x20, 0x85);
Pavankumar Kondeti4960f312011-12-06 15:46:14 +05301745 aca_id_turned_on = true;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001746 break;
1747 default:
1748 break;
1749 }
1750}
1751
1752static void msm_chg_enable_aca_intr(struct msm_otg *motg)
1753{
Steve Mucklef132c6c2012-06-06 18:30:57 -07001754 struct usb_phy *phy = &motg->phy;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001755
Pavankumar Kondetiaa449e12011-11-04 11:09:26 +05301756 if (!aca_enabled())
1757 return;
1758
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001759 switch (motg->pdata->phy_type) {
1760 case SNPS_28NM_INTEGRATED_PHY:
Pavankumar Kondetiaa449e12011-11-04 11:09:26 +05301761 /* Enable ACA Detection interrupt (on any RID change) */
Steve Mucklef132c6c2012-06-06 18:30:57 -07001762 ulpi_write(phy, 0x01, 0x94);
Pavankumar Kondetiaa449e12011-11-04 11:09:26 +05301763 break;
1764 default:
1765 break;
1766 }
1767}
1768
1769static void msm_chg_disable_aca_intr(struct msm_otg *motg)
1770{
Steve Mucklef132c6c2012-06-06 18:30:57 -07001771 struct usb_phy *phy = &motg->phy;
Pavankumar Kondetiaa449e12011-11-04 11:09:26 +05301772
1773 if (!aca_enabled())
1774 return;
1775
1776 switch (motg->pdata->phy_type) {
1777 case SNPS_28NM_INTEGRATED_PHY:
Steve Mucklef132c6c2012-06-06 18:30:57 -07001778 ulpi_write(phy, 0x01, 0x95);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001779 break;
1780 default:
1781 break;
1782 }
1783}
1784
1785static bool msm_chg_check_aca_intr(struct msm_otg *motg)
1786{
Steve Mucklef132c6c2012-06-06 18:30:57 -07001787 struct usb_phy *phy = &motg->phy;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001788 bool ret = false;
1789
Pavankumar Kondetiaa449e12011-11-04 11:09:26 +05301790 if (!aca_enabled())
1791 return ret;
1792
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001793 switch (motg->pdata->phy_type) {
1794 case SNPS_28NM_INTEGRATED_PHY:
Steve Mucklef132c6c2012-06-06 18:30:57 -07001795 if (ulpi_read(phy, 0x91) & 1) {
1796 dev_dbg(phy->dev, "RID change\n");
1797 ulpi_write(phy, 0x01, 0x92);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001798 ret = msm_chg_aca_detect(motg);
1799 }
1800 default:
1801 break;
1802 }
1803 return ret;
1804}
Pavankumar Kondetiaa449e12011-11-04 11:09:26 +05301805
1806static void msm_otg_id_timer_func(unsigned long data)
1807{
1808 struct msm_otg *motg = (struct msm_otg *) data;
1809
1810 if (!aca_enabled())
1811 return;
1812
1813 if (atomic_read(&motg->in_lpm)) {
Steve Mucklef132c6c2012-06-06 18:30:57 -07001814 dev_dbg(motg->phy.dev, "timer: in lpm\n");
Pavankumar Kondetiaa449e12011-11-04 11:09:26 +05301815 return;
1816 }
1817
Steve Mucklef132c6c2012-06-06 18:30:57 -07001818 if (motg->phy.state == OTG_STATE_A_SUSPEND)
Vijayavardhan Vennapusaa3152032012-03-05 16:29:30 +05301819 goto out;
1820
Pavankumar Kondetiaa449e12011-11-04 11:09:26 +05301821 if (msm_chg_check_aca_intr(motg)) {
Steve Mucklef132c6c2012-06-06 18:30:57 -07001822 dev_dbg(motg->phy.dev, "timer: aca work\n");
Vijayavardhan Vennapusaa3152032012-03-05 16:29:30 +05301823 queue_work(system_nrt_wq, &motg->sm_work);
Pavankumar Kondetiaa449e12011-11-04 11:09:26 +05301824 }
1825
Vijayavardhan Vennapusaa3152032012-03-05 16:29:30 +05301826out:
Pavankumar Kondetiaa449e12011-11-04 11:09:26 +05301827 if (!test_bit(ID, &motg->inputs) || test_bit(ID_A, &motg->inputs))
1828 mod_timer(&motg->id_timer, ID_TIMER_FREQ);
1829}
1830
Pavankumar Kondetid8608522011-05-04 10:19:47 +05301831static bool msm_chg_check_secondary_det(struct msm_otg *motg)
1832{
Heikki Krogerus1d4c9292012-02-13 13:24:09 +02001833 struct usb_phy *phy = &motg->phy;
Pavankumar Kondetid8608522011-05-04 10:19:47 +05301834 u32 chg_det;
1835 bool ret = false;
1836
1837 switch (motg->pdata->phy_type) {
1838 case CI_45NM_INTEGRATED_PHY:
Heikki Krogerus1d4c9292012-02-13 13:24:09 +02001839 chg_det = ulpi_read(phy, 0x34);
Pavankumar Kondetid8608522011-05-04 10:19:47 +05301840 ret = chg_det & (1 << 4);
1841 break;
1842 case SNPS_28NM_INTEGRATED_PHY:
Heikki Krogerus1d4c9292012-02-13 13:24:09 +02001843 chg_det = ulpi_read(phy, 0x87);
Pavankumar Kondetid8608522011-05-04 10:19:47 +05301844 ret = chg_det & 1;
1845 break;
1846 default:
1847 break;
1848 }
1849 return ret;
1850}
1851
1852static void msm_chg_enable_secondary_det(struct msm_otg *motg)
1853{
Heikki Krogerus1d4c9292012-02-13 13:24:09 +02001854 struct usb_phy *phy = &motg->phy;
Pavankumar Kondetid8608522011-05-04 10:19:47 +05301855 u32 chg_det;
1856
1857 switch (motg->pdata->phy_type) {
1858 case CI_45NM_INTEGRATED_PHY:
Heikki Krogerus1d4c9292012-02-13 13:24:09 +02001859 chg_det = ulpi_read(phy, 0x34);
Pavankumar Kondetid8608522011-05-04 10:19:47 +05301860 /* Turn off charger block */
1861 chg_det |= ~(1 << 1);
Heikki Krogerus1d4c9292012-02-13 13:24:09 +02001862 ulpi_write(phy, chg_det, 0x34);
Pavankumar Kondetid8608522011-05-04 10:19:47 +05301863 udelay(20);
1864 /* control chg block via ULPI */
1865 chg_det &= ~(1 << 3);
Heikki Krogerus1d4c9292012-02-13 13:24:09 +02001866 ulpi_write(phy, chg_det, 0x34);
Pavankumar Kondetid8608522011-05-04 10:19:47 +05301867 /* put it in host mode for enabling D- source */
1868 chg_det &= ~(1 << 2);
Heikki Krogerus1d4c9292012-02-13 13:24:09 +02001869 ulpi_write(phy, chg_det, 0x34);
Pavankumar Kondetid8608522011-05-04 10:19:47 +05301870 /* Turn on chg detect block */
1871 chg_det &= ~(1 << 1);
Heikki Krogerus1d4c9292012-02-13 13:24:09 +02001872 ulpi_write(phy, chg_det, 0x34);
Pavankumar Kondetid8608522011-05-04 10:19:47 +05301873 udelay(20);
1874 /* enable chg detection */
1875 chg_det &= ~(1 << 0);
Heikki Krogerus1d4c9292012-02-13 13:24:09 +02001876 ulpi_write(phy, chg_det, 0x34);
Pavankumar Kondetid8608522011-05-04 10:19:47 +05301877 break;
1878 case SNPS_28NM_INTEGRATED_PHY:
1879 /*
1880 * Configure DM as current source, DP as current sink
1881 * and enable battery charging comparators.
1882 */
Heikki Krogerus1d4c9292012-02-13 13:24:09 +02001883 ulpi_write(phy, 0x8, 0x85);
1884 ulpi_write(phy, 0x2, 0x85);
1885 ulpi_write(phy, 0x1, 0x85);
Pavankumar Kondetid8608522011-05-04 10:19:47 +05301886 break;
1887 default:
1888 break;
1889 }
1890}
1891
1892static bool msm_chg_check_primary_det(struct msm_otg *motg)
1893{
Heikki Krogerus1d4c9292012-02-13 13:24:09 +02001894 struct usb_phy *phy = &motg->phy;
Pavankumar Kondetid8608522011-05-04 10:19:47 +05301895 u32 chg_det;
1896 bool ret = false;
1897
1898 switch (motg->pdata->phy_type) {
1899 case CI_45NM_INTEGRATED_PHY:
Heikki Krogerus1d4c9292012-02-13 13:24:09 +02001900 chg_det = ulpi_read(phy, 0x34);
Pavankumar Kondetid8608522011-05-04 10:19:47 +05301901 ret = chg_det & (1 << 4);
1902 break;
1903 case SNPS_28NM_INTEGRATED_PHY:
Heikki Krogerus1d4c9292012-02-13 13:24:09 +02001904 chg_det = ulpi_read(phy, 0x87);
Pavankumar Kondetid8608522011-05-04 10:19:47 +05301905 ret = chg_det & 1;
Pavankumar Kondeti9ec21d32012-05-07 15:50:23 +05301906 /* Turn off VDP_SRC */
1907 ulpi_write(phy, 0x3, 0x86);
1908 msleep(20);
Pavankumar Kondetid8608522011-05-04 10:19:47 +05301909 break;
1910 default:
1911 break;
1912 }
1913 return ret;
1914}
1915
1916static void msm_chg_enable_primary_det(struct msm_otg *motg)
1917{
Heikki Krogerus1d4c9292012-02-13 13:24:09 +02001918 struct usb_phy *phy = &motg->phy;
Pavankumar Kondetid8608522011-05-04 10:19:47 +05301919 u32 chg_det;
1920
1921 switch (motg->pdata->phy_type) {
1922 case CI_45NM_INTEGRATED_PHY:
Heikki Krogerus1d4c9292012-02-13 13:24:09 +02001923 chg_det = ulpi_read(phy, 0x34);
Pavankumar Kondetid8608522011-05-04 10:19:47 +05301924 /* enable chg detection */
1925 chg_det &= ~(1 << 0);
Heikki Krogerus1d4c9292012-02-13 13:24:09 +02001926 ulpi_write(phy, chg_det, 0x34);
Pavankumar Kondetid8608522011-05-04 10:19:47 +05301927 break;
1928 case SNPS_28NM_INTEGRATED_PHY:
1929 /*
1930 * Configure DP as current source, DM as current sink
1931 * and enable battery charging comparators.
1932 */
Heikki Krogerus1d4c9292012-02-13 13:24:09 +02001933 ulpi_write(phy, 0x2, 0x85);
1934 ulpi_write(phy, 0x1, 0x85);
Pavankumar Kondetid8608522011-05-04 10:19:47 +05301935 break;
1936 default:
1937 break;
1938 }
1939}
1940
1941static bool msm_chg_check_dcd(struct msm_otg *motg)
1942{
Heikki Krogerus1d4c9292012-02-13 13:24:09 +02001943 struct usb_phy *phy = &motg->phy;
Pavankumar Kondetid8608522011-05-04 10:19:47 +05301944 u32 line_state;
1945 bool ret = false;
1946
1947 switch (motg->pdata->phy_type) {
1948 case CI_45NM_INTEGRATED_PHY:
Heikki Krogerus1d4c9292012-02-13 13:24:09 +02001949 line_state = ulpi_read(phy, 0x15);
Pavankumar Kondetid8608522011-05-04 10:19:47 +05301950 ret = !(line_state & 1);
1951 break;
1952 case SNPS_28NM_INTEGRATED_PHY:
Heikki Krogerus1d4c9292012-02-13 13:24:09 +02001953 line_state = ulpi_read(phy, 0x87);
Pavankumar Kondetid8608522011-05-04 10:19:47 +05301954 ret = line_state & 2;
1955 break;
1956 default:
1957 break;
1958 }
1959 return ret;
1960}
1961
1962static void msm_chg_disable_dcd(struct msm_otg *motg)
1963{
Heikki Krogerus1d4c9292012-02-13 13:24:09 +02001964 struct usb_phy *phy = &motg->phy;
Pavankumar Kondetid8608522011-05-04 10:19:47 +05301965 u32 chg_det;
1966
1967 switch (motg->pdata->phy_type) {
1968 case CI_45NM_INTEGRATED_PHY:
Heikki Krogerus1d4c9292012-02-13 13:24:09 +02001969 chg_det = ulpi_read(phy, 0x34);
Pavankumar Kondetid8608522011-05-04 10:19:47 +05301970 chg_det &= ~(1 << 5);
Heikki Krogerus1d4c9292012-02-13 13:24:09 +02001971 ulpi_write(phy, chg_det, 0x34);
Pavankumar Kondetid8608522011-05-04 10:19:47 +05301972 break;
1973 case SNPS_28NM_INTEGRATED_PHY:
Heikki Krogerus1d4c9292012-02-13 13:24:09 +02001974 ulpi_write(phy, 0x10, 0x86);
Pavankumar Kondetid8608522011-05-04 10:19:47 +05301975 break;
1976 default:
1977 break;
1978 }
1979}
1980
1981static void msm_chg_enable_dcd(struct msm_otg *motg)
1982{
Heikki Krogerus1d4c9292012-02-13 13:24:09 +02001983 struct usb_phy *phy = &motg->phy;
Pavankumar Kondetid8608522011-05-04 10:19:47 +05301984 u32 chg_det;
1985
1986 switch (motg->pdata->phy_type) {
1987 case CI_45NM_INTEGRATED_PHY:
Heikki Krogerus1d4c9292012-02-13 13:24:09 +02001988 chg_det = ulpi_read(phy, 0x34);
Pavankumar Kondetid8608522011-05-04 10:19:47 +05301989 /* Turn on D+ current source */
1990 chg_det |= (1 << 5);
Heikki Krogerus1d4c9292012-02-13 13:24:09 +02001991 ulpi_write(phy, chg_det, 0x34);
Pavankumar Kondetid8608522011-05-04 10:19:47 +05301992 break;
1993 case SNPS_28NM_INTEGRATED_PHY:
1994 /* Data contact detection enable */
Heikki Krogerus1d4c9292012-02-13 13:24:09 +02001995 ulpi_write(phy, 0x10, 0x85);
Pavankumar Kondetid8608522011-05-04 10:19:47 +05301996 break;
1997 default:
1998 break;
1999 }
2000}
2001
2002static void msm_chg_block_on(struct msm_otg *motg)
2003{
Heikki Krogerus1d4c9292012-02-13 13:24:09 +02002004 struct usb_phy *phy = &motg->phy;
Pavankumar Kondetid8608522011-05-04 10:19:47 +05302005 u32 func_ctrl, chg_det;
2006
2007 /* put the controller in non-driving mode */
Heikki Krogerus1d4c9292012-02-13 13:24:09 +02002008 func_ctrl = ulpi_read(phy, ULPI_FUNC_CTRL);
Pavankumar Kondetid8608522011-05-04 10:19:47 +05302009 func_ctrl &= ~ULPI_FUNC_CTRL_OPMODE_MASK;
2010 func_ctrl |= ULPI_FUNC_CTRL_OPMODE_NONDRIVING;
Heikki Krogerus1d4c9292012-02-13 13:24:09 +02002011 ulpi_write(phy, func_ctrl, ULPI_FUNC_CTRL);
Pavankumar Kondetid8608522011-05-04 10:19:47 +05302012
2013 switch (motg->pdata->phy_type) {
2014 case CI_45NM_INTEGRATED_PHY:
Heikki Krogerus1d4c9292012-02-13 13:24:09 +02002015 chg_det = ulpi_read(phy, 0x34);
Pavankumar Kondetid8608522011-05-04 10:19:47 +05302016 /* control chg block via ULPI */
2017 chg_det &= ~(1 << 3);
Heikki Krogerus1d4c9292012-02-13 13:24:09 +02002018 ulpi_write(phy, chg_det, 0x34);
Pavankumar Kondetid8608522011-05-04 10:19:47 +05302019 /* Turn on chg detect block */
2020 chg_det &= ~(1 << 1);
Heikki Krogerus1d4c9292012-02-13 13:24:09 +02002021 ulpi_write(phy, chg_det, 0x34);
Pavankumar Kondetid8608522011-05-04 10:19:47 +05302022 udelay(20);
2023 break;
2024 case SNPS_28NM_INTEGRATED_PHY:
2025 /* Clear charger detecting control bits */
Steve Mucklef132c6c2012-06-06 18:30:57 -07002026 ulpi_write(phy, 0x1F, 0x86);
Pavankumar Kondetid8608522011-05-04 10:19:47 +05302027 /* Clear alt interrupt latch and enable bits */
Heikki Krogerus1d4c9292012-02-13 13:24:09 +02002028 ulpi_write(phy, 0x1F, 0x92);
2029 ulpi_write(phy, 0x1F, 0x95);
Pavankumar Kondetid8608522011-05-04 10:19:47 +05302030 udelay(100);
2031 break;
2032 default:
2033 break;
2034 }
2035}
2036
2037static void msm_chg_block_off(struct msm_otg *motg)
2038{
Heikki Krogerus1d4c9292012-02-13 13:24:09 +02002039 struct usb_phy *phy = &motg->phy;
Pavankumar Kondetid8608522011-05-04 10:19:47 +05302040 u32 func_ctrl, chg_det;
2041
2042 switch (motg->pdata->phy_type) {
2043 case CI_45NM_INTEGRATED_PHY:
Heikki Krogerus1d4c9292012-02-13 13:24:09 +02002044 chg_det = ulpi_read(phy, 0x34);
Pavankumar Kondetid8608522011-05-04 10:19:47 +05302045 /* Turn off charger block */
2046 chg_det |= ~(1 << 1);
Heikki Krogerus1d4c9292012-02-13 13:24:09 +02002047 ulpi_write(phy, chg_det, 0x34);
Pavankumar Kondetid8608522011-05-04 10:19:47 +05302048 break;
2049 case SNPS_28NM_INTEGRATED_PHY:
2050 /* Clear charger detecting control bits */
Heikki Krogerus1d4c9292012-02-13 13:24:09 +02002051 ulpi_write(phy, 0x3F, 0x86);
Pavankumar Kondetid8608522011-05-04 10:19:47 +05302052 /* Clear alt interrupt latch and enable bits */
Heikki Krogerus1d4c9292012-02-13 13:24:09 +02002053 ulpi_write(phy, 0x1F, 0x92);
2054 ulpi_write(phy, 0x1F, 0x95);
Pavankumar Kondetid8608522011-05-04 10:19:47 +05302055 break;
2056 default:
2057 break;
2058 }
2059
2060 /* put the controller in normal mode */
Heikki Krogerus1d4c9292012-02-13 13:24:09 +02002061 func_ctrl = ulpi_read(phy, ULPI_FUNC_CTRL);
Pavankumar Kondetid8608522011-05-04 10:19:47 +05302062 func_ctrl &= ~ULPI_FUNC_CTRL_OPMODE_MASK;
2063 func_ctrl |= ULPI_FUNC_CTRL_OPMODE_NORMAL;
Heikki Krogerus1d4c9292012-02-13 13:24:09 +02002064 ulpi_write(phy, func_ctrl, ULPI_FUNC_CTRL);
Pavankumar Kondetid8608522011-05-04 10:19:47 +05302065}
2066
Anji jonnalad270e2d2011-08-09 11:28:32 +05302067static const char *chg_to_string(enum usb_chg_type chg_type)
2068{
2069 switch (chg_type) {
2070 case USB_SDP_CHARGER: return "USB_SDP_CHARGER";
2071 case USB_DCP_CHARGER: return "USB_DCP_CHARGER";
2072 case USB_CDP_CHARGER: return "USB_CDP_CHARGER";
2073 case USB_ACA_A_CHARGER: return "USB_ACA_A_CHARGER";
2074 case USB_ACA_B_CHARGER: return "USB_ACA_B_CHARGER";
2075 case USB_ACA_C_CHARGER: return "USB_ACA_C_CHARGER";
2076 case USB_ACA_DOCK_CHARGER: return "USB_ACA_DOCK_CHARGER";
Pavankumar Kondeti9ec21d32012-05-07 15:50:23 +05302077 case USB_PROPRIETARY_CHARGER: return "USB_PROPRIETARY_CHARGER";
Anji jonnalad270e2d2011-08-09 11:28:32 +05302078 default: return "INVALID_CHARGER";
2079 }
2080}
2081
Pavankumar Kondetid8608522011-05-04 10:19:47 +05302082#define MSM_CHG_DCD_POLL_TIME (100 * HZ/1000) /* 100 msec */
2083#define MSM_CHG_DCD_MAX_RETRIES 6 /* Tdcd_tmout = 6 * 100 msec */
Pavankumar Kondeti283146f2012-01-12 12:51:19 +05302084#define MSM_CHG_PRIMARY_DET_TIME (50 * HZ/1000) /* TVDPSRC_ON */
2085#define MSM_CHG_SECONDARY_DET_TIME (50 * HZ/1000) /* TVDMSRC_ON */
Pavankumar Kondetid8608522011-05-04 10:19:47 +05302086static void msm_chg_detect_work(struct work_struct *w)
2087{
2088 struct msm_otg *motg = container_of(w, struct msm_otg, chg_work.work);
Heikki Krogerus1d4c9292012-02-13 13:24:09 +02002089 struct usb_phy *phy = &motg->phy;
Pavankumar Kondeti2d09e5f2012-01-16 08:56:57 +05302090 bool is_dcd = false, tmout, vout, is_aca;
Pavankumar Kondeti9ec21d32012-05-07 15:50:23 +05302091 u32 line_state, dm_vlgc;
Pavankumar Kondetid8608522011-05-04 10:19:47 +05302092 unsigned long delay;
2093
Heikki Krogerus1d4c9292012-02-13 13:24:09 +02002094 dev_dbg(phy->dev, "chg detection work\n");
Pavankumar Kondeti2aec9f32012-06-13 09:06:03 +05302095
2096 if (test_bit(MHL, &motg->inputs)) {
2097 dev_dbg(phy->dev, "detected MHL, escape chg detection work\n");
2098 return;
2099 }
2100
Pavankumar Kondetid8608522011-05-04 10:19:47 +05302101 switch (motg->chg_state) {
2102 case USB_CHG_STATE_UNDEFINED:
Pavankumar Kondetid8608522011-05-04 10:19:47 +05302103 msm_chg_block_on(motg);
Pavankumar Kondeti2d09e5f2012-01-16 08:56:57 +05302104 if (motg->pdata->enable_dcd)
2105 msm_chg_enable_dcd(motg);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002106 msm_chg_enable_aca_det(motg);
Pavankumar Kondetid8608522011-05-04 10:19:47 +05302107 motg->chg_state = USB_CHG_STATE_WAIT_FOR_DCD;
2108 motg->dcd_retries = 0;
2109 delay = MSM_CHG_DCD_POLL_TIME;
2110 break;
2111 case USB_CHG_STATE_WAIT_FOR_DCD:
Pavankumar Kondeti2aec9f32012-06-13 09:06:03 +05302112 if (msm_chg_mhl_detect(motg)) {
2113 msm_chg_block_off(motg);
2114 motg->chg_state = USB_CHG_STATE_DETECTED;
2115 motg->chg_type = USB_INVALID_CHARGER;
2116 queue_work(system_nrt_wq, &motg->sm_work);
2117 return;
2118 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002119 is_aca = msm_chg_aca_detect(motg);
2120 if (is_aca) {
2121 /*
2122 * ID_A can be ACA dock too. continue
2123 * primary detection after DCD.
2124 */
2125 if (test_bit(ID_A, &motg->inputs)) {
2126 motg->chg_state = USB_CHG_STATE_WAIT_FOR_DCD;
2127 } else {
2128 delay = 0;
2129 break;
2130 }
2131 }
Pavankumar Kondeti2d09e5f2012-01-16 08:56:57 +05302132 if (motg->pdata->enable_dcd)
2133 is_dcd = msm_chg_check_dcd(motg);
Pavankumar Kondetid8608522011-05-04 10:19:47 +05302134 tmout = ++motg->dcd_retries == MSM_CHG_DCD_MAX_RETRIES;
2135 if (is_dcd || tmout) {
Pavankumar Kondeti2d09e5f2012-01-16 08:56:57 +05302136 if (motg->pdata->enable_dcd)
2137 msm_chg_disable_dcd(motg);
Pavankumar Kondetid8608522011-05-04 10:19:47 +05302138 msm_chg_enable_primary_det(motg);
2139 delay = MSM_CHG_PRIMARY_DET_TIME;
2140 motg->chg_state = USB_CHG_STATE_DCD_DONE;
2141 } else {
2142 delay = MSM_CHG_DCD_POLL_TIME;
2143 }
2144 break;
2145 case USB_CHG_STATE_DCD_DONE:
2146 vout = msm_chg_check_primary_det(motg);
Pavankumar Kondeti9ec21d32012-05-07 15:50:23 +05302147 line_state = readl_relaxed(USB_PORTSC) & PORTSC_LS;
2148 dm_vlgc = line_state & PORTSC_LS_DM;
2149 if (vout && !dm_vlgc) { /* VDAT_REF < DM < VLGC */
Pavankumar Kondetiaa449e12011-11-04 11:09:26 +05302150 if (test_bit(ID_A, &motg->inputs)) {
2151 motg->chg_type = USB_ACA_DOCK_CHARGER;
2152 motg->chg_state = USB_CHG_STATE_DETECTED;
2153 delay = 0;
2154 break;
2155 }
Pavankumar Kondeti9ec21d32012-05-07 15:50:23 +05302156 if (line_state) { /* DP > VLGC */
2157 motg->chg_type = USB_PROPRIETARY_CHARGER;
2158 motg->chg_state = USB_CHG_STATE_DETECTED;
2159 delay = 0;
2160 } else {
2161 msm_chg_enable_secondary_det(motg);
2162 delay = MSM_CHG_SECONDARY_DET_TIME;
2163 motg->chg_state = USB_CHG_STATE_PRIMARY_DONE;
2164 }
2165 } else { /* DM < VDAT_REF || DM > VLGC */
Pavankumar Kondetiaa449e12011-11-04 11:09:26 +05302166 if (test_bit(ID_A, &motg->inputs)) {
2167 motg->chg_type = USB_ACA_A_CHARGER;
2168 motg->chg_state = USB_CHG_STATE_DETECTED;
2169 delay = 0;
2170 break;
2171 }
Pavankumar Kondeti9ec21d32012-05-07 15:50:23 +05302172
2173 if (line_state) /* DP > VLGC or/and DM > VLGC */
2174 motg->chg_type = USB_PROPRIETARY_CHARGER;
2175 else
2176 motg->chg_type = USB_SDP_CHARGER;
2177
Pavankumar Kondetid8608522011-05-04 10:19:47 +05302178 motg->chg_state = USB_CHG_STATE_DETECTED;
2179 delay = 0;
2180 }
2181 break;
2182 case USB_CHG_STATE_PRIMARY_DONE:
2183 vout = msm_chg_check_secondary_det(motg);
2184 if (vout)
2185 motg->chg_type = USB_DCP_CHARGER;
2186 else
2187 motg->chg_type = USB_CDP_CHARGER;
2188 motg->chg_state = USB_CHG_STATE_SECONDARY_DONE;
2189 /* fall through */
2190 case USB_CHG_STATE_SECONDARY_DONE:
2191 motg->chg_state = USB_CHG_STATE_DETECTED;
2192 case USB_CHG_STATE_DETECTED:
2193 msm_chg_block_off(motg);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002194 msm_chg_enable_aca_det(motg);
Vijayavardhan Vennapusaa3152032012-03-05 16:29:30 +05302195 /*
2196 * Spurious interrupt is seen after enabling ACA detection
2197 * due to which charger detection fails in case of PET.
2198 * Add delay of 100 microsec to avoid that.
2199 */
2200 udelay(100);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002201 msm_chg_enable_aca_intr(motg);
Steve Mucklef132c6c2012-06-06 18:30:57 -07002202 dev_dbg(phy->dev, "chg_type = %s\n",
Anji jonnalad270e2d2011-08-09 11:28:32 +05302203 chg_to_string(motg->chg_type));
Vijayavardhan Vennapusaa3152032012-03-05 16:29:30 +05302204 queue_work(system_nrt_wq, &motg->sm_work);
Pavankumar Kondetid8608522011-05-04 10:19:47 +05302205 return;
2206 default:
2207 return;
2208 }
2209
Vijayavardhan Vennapusaa3152032012-03-05 16:29:30 +05302210 queue_delayed_work(system_nrt_wq, &motg->chg_work, delay);
Pavankumar Kondetid8608522011-05-04 10:19:47 +05302211}
2212
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05302213/*
2214 * We support OTG, Peripheral only and Host only configurations. In case
2215 * of OTG, mode switch (host-->peripheral/peripheral-->host) can happen
2216 * via Id pin status or user request (debugfs). Id/BSV interrupts are not
2217 * enabled when switch is controlled by user and default mode is supplied
2218 * by board file, which can be changed by userspace later.
2219 */
2220static void msm_otg_init_sm(struct msm_otg *motg)
2221{
2222 struct msm_otg_platform_data *pdata = motg->pdata;
2223 u32 otgsc = readl(USB_OTGSC);
2224
2225 switch (pdata->mode) {
2226 case USB_OTG:
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002227 if (pdata->otg_control == OTG_USER_CONTROL) {
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05302228 if (pdata->default_mode == USB_HOST) {
2229 clear_bit(ID, &motg->inputs);
2230 } else if (pdata->default_mode == USB_PERIPHERAL) {
2231 set_bit(ID, &motg->inputs);
2232 set_bit(B_SESS_VLD, &motg->inputs);
2233 } else {
2234 set_bit(ID, &motg->inputs);
2235 clear_bit(B_SESS_VLD, &motg->inputs);
2236 }
Pavankumar Kondeti4960f312011-12-06 15:46:14 +05302237 } else if (pdata->otg_control == OTG_PHY_CONTROL) {
Vijayavardhan Vennapusaa3152032012-03-05 16:29:30 +05302238 if (otgsc & OTGSC_ID) {
Pavankumar Kondeti4960f312011-12-06 15:46:14 +05302239 set_bit(ID, &motg->inputs);
Vijayavardhan Vennapusaa3152032012-03-05 16:29:30 +05302240 } else {
Pavankumar Kondeti4960f312011-12-06 15:46:14 +05302241 clear_bit(ID, &motg->inputs);
Vijayavardhan Vennapusaa3152032012-03-05 16:29:30 +05302242 set_bit(A_BUS_REQ, &motg->inputs);
2243 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002244 if (otgsc & OTGSC_BSV)
2245 set_bit(B_SESS_VLD, &motg->inputs);
2246 else
2247 clear_bit(B_SESS_VLD, &motg->inputs);
Pavankumar Kondeti4960f312011-12-06 15:46:14 +05302248 } else if (pdata->otg_control == OTG_PMIC_CONTROL) {
Pavankumar Kondeti0d81f312012-01-13 11:34:10 +05302249 if (pdata->pmic_id_irq) {
Stephen Boyd431771e2012-04-18 20:00:23 -07002250 unsigned long flags;
2251 local_irq_save(flags);
Pavankumar Kondeti0d81f312012-01-13 11:34:10 +05302252 if (irq_read_line(pdata->pmic_id_irq))
2253 set_bit(ID, &motg->inputs);
2254 else
2255 clear_bit(ID, &motg->inputs);
Stephen Boyd431771e2012-04-18 20:00:23 -07002256 local_irq_restore(flags);
Pavankumar Kondeti0d81f312012-01-13 11:34:10 +05302257 }
Pavankumar Kondeti4960f312011-12-06 15:46:14 +05302258 /*
2259 * VBUS initial state is reported after PMIC
2260 * driver initialization. Wait for it.
2261 */
2262 wait_for_completion(&pmic_vbus_init);
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05302263 }
2264 break;
2265 case USB_HOST:
2266 clear_bit(ID, &motg->inputs);
2267 break;
2268 case USB_PERIPHERAL:
2269 set_bit(ID, &motg->inputs);
Pavankumar Kondeti0d81f312012-01-13 11:34:10 +05302270 if (pdata->otg_control == OTG_PHY_CONTROL) {
2271 if (otgsc & OTGSC_BSV)
2272 set_bit(B_SESS_VLD, &motg->inputs);
2273 else
2274 clear_bit(B_SESS_VLD, &motg->inputs);
2275 } else if (pdata->otg_control == OTG_PMIC_CONTROL) {
2276 /*
2277 * VBUS initial state is reported after PMIC
2278 * driver initialization. Wait for it.
2279 */
2280 wait_for_completion(&pmic_vbus_init);
2281 }
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05302282 break;
2283 default:
2284 break;
2285 }
2286}
2287
2288static void msm_otg_sm_work(struct work_struct *w)
2289{
2290 struct msm_otg *motg = container_of(w, struct msm_otg, sm_work);
Heikki Krogerus1d4c9292012-02-13 13:24:09 +02002291 struct usb_otg *otg = motg->phy.otg;
Vijayavardhan Vennapusaa3152032012-03-05 16:29:30 +05302292 bool work = 0, srp_reqd;
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05302293
Steve Mucklef132c6c2012-06-06 18:30:57 -07002294 pm_runtime_resume(otg->phy->dev);
2295 pr_debug("%s work\n", otg_state_string(otg->phy->state));
Heikki Krogerus1d4c9292012-02-13 13:24:09 +02002296 switch (otg->phy->state) {
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05302297 case OTG_STATE_UNDEFINED:
Heikki Krogerus1d4c9292012-02-13 13:24:09 +02002298 msm_otg_reset(otg->phy);
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05302299 msm_otg_init_sm(motg);
Sridhar Parasuram3c67a412012-09-26 09:36:22 -07002300 psy = power_supply_get_by_name("usb");
2301 if (!psy)
2302 pr_err("couldn't get usb power supply\n");
Heikki Krogerus1d4c9292012-02-13 13:24:09 +02002303 otg->phy->state = OTG_STATE_B_IDLE;
Pavankumar Kondeti8a379b42011-12-12 13:07:23 +05302304 if (!test_bit(B_SESS_VLD, &motg->inputs) &&
2305 test_bit(ID, &motg->inputs)) {
Steve Mucklef132c6c2012-06-06 18:30:57 -07002306 pm_runtime_put_noidle(otg->phy->dev);
2307 pm_runtime_suspend(otg->phy->dev);
Pavankumar Kondeti8a379b42011-12-12 13:07:23 +05302308 break;
2309 }
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05302310 /* FALL THROUGH */
2311 case OTG_STATE_B_IDLE:
Pavankumar Kondeti2aec9f32012-06-13 09:06:03 +05302312 if (test_bit(MHL, &motg->inputs)) {
2313 /* allow LPM */
2314 pm_runtime_put_noidle(otg->phy->dev);
2315 pm_runtime_suspend(otg->phy->dev);
2316 } else if ((!test_bit(ID, &motg->inputs) ||
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002317 test_bit(ID_A, &motg->inputs)) && otg->host) {
Vijayavardhan Vennapusaa3152032012-03-05 16:29:30 +05302318 pr_debug("!id || id_A\n");
Pavankumar Kondeti2aec9f32012-06-13 09:06:03 +05302319 if (msm_chg_mhl_detect(motg)) {
2320 work = 1;
2321 break;
2322 }
Vijayavardhan Vennapusaa3152032012-03-05 16:29:30 +05302323 clear_bit(B_BUS_REQ, &motg->inputs);
2324 set_bit(A_BUS_REQ, &motg->inputs);
Steve Mucklef132c6c2012-06-06 18:30:57 -07002325 otg->phy->state = OTG_STATE_A_IDLE;
Vijayavardhan Vennapusaa3152032012-03-05 16:29:30 +05302326 work = 1;
Pavankumar Kondetid8608522011-05-04 10:19:47 +05302327 } else if (test_bit(B_SESS_VLD, &motg->inputs)) {
Vijayavardhan Vennapusaa3152032012-03-05 16:29:30 +05302328 pr_debug("b_sess_vld\n");
Pavankumar Kondetid8608522011-05-04 10:19:47 +05302329 switch (motg->chg_state) {
2330 case USB_CHG_STATE_UNDEFINED:
2331 msm_chg_detect_work(&motg->chg_work.work);
2332 break;
2333 case USB_CHG_STATE_DETECTED:
2334 switch (motg->chg_type) {
2335 case USB_DCP_CHARGER:
Pavankumar Kondeti283146f2012-01-12 12:51:19 +05302336 /* Enable VDP_SRC */
Steve Mucklef132c6c2012-06-06 18:30:57 -07002337 ulpi_write(otg->phy, 0x2, 0x85);
Pavankumar Kondeti9ec21d32012-05-07 15:50:23 +05302338 /* fall through */
2339 case USB_PROPRIETARY_CHARGER:
Pavankumar Kondetid8608522011-05-04 10:19:47 +05302340 msm_otg_notify_charger(motg,
2341 IDEV_CHG_MAX);
Steve Mucklef132c6c2012-06-06 18:30:57 -07002342 pm_runtime_put_noidle(otg->phy->dev);
2343 pm_runtime_suspend(otg->phy->dev);
Pavankumar Kondetid8608522011-05-04 10:19:47 +05302344 break;
Pavankumar Kondetiaa449e12011-11-04 11:09:26 +05302345 case USB_ACA_B_CHARGER:
2346 msm_otg_notify_charger(motg,
2347 IDEV_ACA_CHG_MAX);
2348 /*
2349 * (ID_B --> ID_C) PHY_ALT interrupt can
2350 * not be detected in LPM.
2351 */
Pavankumar Kondetid8608522011-05-04 10:19:47 +05302352 break;
2353 case USB_CDP_CHARGER:
2354 msm_otg_notify_charger(motg,
2355 IDEV_CHG_MAX);
2356 msm_otg_start_peripheral(otg, 1);
Steve Mucklef132c6c2012-06-06 18:30:57 -07002357 otg->phy->state =
2358 OTG_STATE_B_PERIPHERAL;
Pavankumar Kondetid8608522011-05-04 10:19:47 +05302359 break;
Pavankumar Kondetiaa449e12011-11-04 11:09:26 +05302360 case USB_ACA_C_CHARGER:
2361 msm_otg_notify_charger(motg,
2362 IDEV_ACA_CHG_MAX);
2363 msm_otg_start_peripheral(otg, 1);
Steve Mucklef132c6c2012-06-06 18:30:57 -07002364 otg->phy->state =
2365 OTG_STATE_B_PERIPHERAL;
Pavankumar Kondetid8608522011-05-04 10:19:47 +05302366 break;
2367 case USB_SDP_CHARGER:
Pavankumar Kondetid8608522011-05-04 10:19:47 +05302368 msm_otg_start_peripheral(otg, 1);
Steve Mucklef132c6c2012-06-06 18:30:57 -07002369 otg->phy->state =
2370 OTG_STATE_B_PERIPHERAL;
Pavankumar Kondeti458d8792012-09-28 14:45:18 +05302371 mod_timer(&motg->chg_check_timer,
2372 CHG_RECHECK_DELAY);
Pavankumar Kondetid8608522011-05-04 10:19:47 +05302373 break;
2374 default:
2375 break;
2376 }
2377 break;
2378 default:
2379 break;
2380 }
Vijayavardhan Vennapusaa3152032012-03-05 16:29:30 +05302381 } else if (test_bit(B_BUS_REQ, &motg->inputs)) {
2382 pr_debug("b_sess_end && b_bus_req\n");
2383 if (msm_otg_start_srp(otg) < 0) {
2384 clear_bit(B_BUS_REQ, &motg->inputs);
2385 work = 1;
2386 break;
Pavankumar Kondetid8608522011-05-04 10:19:47 +05302387 }
Steve Mucklef132c6c2012-06-06 18:30:57 -07002388 otg->phy->state = OTG_STATE_B_SRP_INIT;
Vijayavardhan Vennapusaa3152032012-03-05 16:29:30 +05302389 msm_otg_start_timer(motg, TB_SRP_FAIL, B_SRP_FAIL);
2390 break;
Pavankumar Kondetid8608522011-05-04 10:19:47 +05302391 } else {
Vijayavardhan Vennapusaa3152032012-03-05 16:29:30 +05302392 pr_debug("chg_work cancel");
Pavankumar Kondeti458d8792012-09-28 14:45:18 +05302393 del_timer_sync(&motg->chg_check_timer);
2394 clear_bit(B_FALSE_SDP, &motg->inputs);
Pavankumar Kondetiaa449e12011-11-04 11:09:26 +05302395 cancel_delayed_work_sync(&motg->chg_work);
Pavankumar Kondetid8608522011-05-04 10:19:47 +05302396 motg->chg_state = USB_CHG_STATE_UNDEFINED;
2397 motg->chg_type = USB_INVALID_CHARGER;
Rajkumar Raghupathy18fd7132012-04-20 11:28:13 +05302398 msm_otg_notify_charger(motg, 0);
Steve Mucklef132c6c2012-06-06 18:30:57 -07002399 msm_otg_reset(otg->phy);
2400 pm_runtime_put_noidle(otg->phy->dev);
2401 pm_runtime_suspend(otg->phy->dev);
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05302402 }
2403 break;
Vijayavardhan Vennapusaa3152032012-03-05 16:29:30 +05302404 case OTG_STATE_B_SRP_INIT:
2405 if (!test_bit(ID, &motg->inputs) ||
2406 test_bit(ID_A, &motg->inputs) ||
2407 test_bit(ID_C, &motg->inputs) ||
2408 (test_bit(B_SESS_VLD, &motg->inputs) &&
2409 !test_bit(ID_B, &motg->inputs))) {
2410 pr_debug("!id || id_a/c || b_sess_vld+!id_b\n");
2411 msm_otg_del_timer(motg);
Steve Mucklef132c6c2012-06-06 18:30:57 -07002412 otg->phy->state = OTG_STATE_B_IDLE;
Vijayavardhan Vennapusaa3152032012-03-05 16:29:30 +05302413 /*
2414 * clear VBUSVLDEXTSEL and VBUSVLDEXT register
2415 * bits after SRP initiation.
2416 */
Steve Mucklef132c6c2012-06-06 18:30:57 -07002417 ulpi_write(otg->phy, 0x0, 0x98);
Vijayavardhan Vennapusaa3152032012-03-05 16:29:30 +05302418 work = 1;
2419 } else if (test_bit(B_SRP_FAIL, &motg->tmouts)) {
2420 pr_debug("b_srp_fail\n");
2421 pr_info("A-device did not respond to SRP\n");
2422 clear_bit(B_BUS_REQ, &motg->inputs);
2423 clear_bit(B_SRP_FAIL, &motg->tmouts);
2424 otg_send_event(OTG_EVENT_NO_RESP_FOR_SRP);
Steve Mucklef132c6c2012-06-06 18:30:57 -07002425 ulpi_write(otg->phy, 0x0, 0x98);
2426 otg->phy->state = OTG_STATE_B_IDLE;
Vijayavardhan Vennapusaa3152032012-03-05 16:29:30 +05302427 motg->b_last_se0_sess = jiffies;
2428 work = 1;
2429 }
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05302430 break;
2431 case OTG_STATE_B_PERIPHERAL:
Pavankumar Kondeti458d8792012-09-28 14:45:18 +05302432 if (test_bit(B_SESS_VLD, &motg->inputs) &&
2433 test_bit(B_FALSE_SDP, &motg->inputs)) {
2434 pr_debug("B_FALSE_SDP\n");
2435 msm_otg_start_peripheral(otg, 0);
2436 motg->chg_type = USB_DCP_CHARGER;
2437 clear_bit(B_FALSE_SDP, &motg->inputs);
2438 otg->phy->state = OTG_STATE_B_IDLE;
2439 work = 1;
2440 } else if (!test_bit(ID, &motg->inputs) ||
Vijayavardhan Vennapusaa3152032012-03-05 16:29:30 +05302441 test_bit(ID_A, &motg->inputs) ||
2442 test_bit(ID_B, &motg->inputs) ||
2443 !test_bit(B_SESS_VLD, &motg->inputs)) {
2444 pr_debug("!id || id_a/b || !b_sess_vld\n");
Pavankumar Kondetid8608522011-05-04 10:19:47 +05302445 motg->chg_state = USB_CHG_STATE_UNDEFINED;
2446 motg->chg_type = USB_INVALID_CHARGER;
Vijayavardhan Vennapusaa3152032012-03-05 16:29:30 +05302447 msm_otg_notify_charger(motg, 0);
2448 srp_reqd = otg->gadget->otg_srp_reqd;
2449 msm_otg_start_peripheral(otg, 0);
Vijayavardhan Vennapusaa3152032012-03-05 16:29:30 +05302450 if (test_bit(ID_B, &motg->inputs))
2451 clear_bit(ID_B, &motg->inputs);
2452 clear_bit(B_BUS_REQ, &motg->inputs);
Steve Mucklef132c6c2012-06-06 18:30:57 -07002453 otg->phy->state = OTG_STATE_B_IDLE;
Vijayavardhan Vennapusaa3152032012-03-05 16:29:30 +05302454 motg->b_last_se0_sess = jiffies;
2455 if (srp_reqd)
2456 msm_otg_start_timer(motg,
2457 TB_TST_SRP, B_TST_SRP);
2458 else
2459 work = 1;
2460 } else if (test_bit(B_BUS_REQ, &motg->inputs) &&
2461 otg->gadget->b_hnp_enable &&
2462 test_bit(A_BUS_SUSPEND, &motg->inputs)) {
2463 pr_debug("b_bus_req && b_hnp_en && a_bus_suspend\n");
2464 msm_otg_start_timer(motg, TB_ASE0_BRST, B_ASE0_BRST);
2465 /* D+ pullup should not be disconnected within 4msec
2466 * after A device suspends the bus. Otherwise PET will
2467 * fail the compliance test.
2468 */
2469 udelay(1000);
2470 msm_otg_start_peripheral(otg, 0);
Steve Mucklef132c6c2012-06-06 18:30:57 -07002471 otg->phy->state = OTG_STATE_B_WAIT_ACON;
Vijayavardhan Vennapusaa3152032012-03-05 16:29:30 +05302472 /*
2473 * start HCD even before A-device enable
2474 * pull-up to meet HNP timings.
2475 */
2476 otg->host->is_b_host = 1;
2477 msm_otg_start_host(otg, 1);
Amit Blay6fa647a2012-05-24 14:12:08 +03002478 } else if (test_bit(A_BUS_SUSPEND, &motg->inputs) &&
2479 test_bit(B_SESS_VLD, &motg->inputs)) {
2480 pr_debug("a_bus_suspend && b_sess_vld\n");
2481 if (motg->caps & ALLOW_LPM_ON_DEV_SUSPEND) {
Steve Mucklef132c6c2012-06-06 18:30:57 -07002482 pm_runtime_put_noidle(otg->phy->dev);
2483 pm_runtime_suspend(otg->phy->dev);
Amit Blay6fa647a2012-05-24 14:12:08 +03002484 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002485 } else if (test_bit(ID_C, &motg->inputs)) {
Pavankumar Kondetiaa449e12011-11-04 11:09:26 +05302486 msm_otg_notify_charger(motg, IDEV_ACA_CHG_MAX);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002487 }
2488 break;
Vijayavardhan Vennapusaa3152032012-03-05 16:29:30 +05302489 case OTG_STATE_B_WAIT_ACON:
2490 if (!test_bit(ID, &motg->inputs) ||
2491 test_bit(ID_A, &motg->inputs) ||
2492 test_bit(ID_B, &motg->inputs) ||
2493 !test_bit(B_SESS_VLD, &motg->inputs)) {
2494 pr_debug("!id || id_a/b || !b_sess_vld\n");
2495 msm_otg_del_timer(motg);
Pavankumar Kondetiaa449e12011-11-04 11:09:26 +05302496 /*
Vijayavardhan Vennapusaa3152032012-03-05 16:29:30 +05302497 * A-device is physically disconnected during
2498 * HNP. Remove HCD.
Pavankumar Kondetiaa449e12011-11-04 11:09:26 +05302499 */
Vijayavardhan Vennapusaa3152032012-03-05 16:29:30 +05302500 msm_otg_start_host(otg, 0);
2501 otg->host->is_b_host = 0;
2502
2503 clear_bit(B_BUS_REQ, &motg->inputs);
2504 clear_bit(A_BUS_SUSPEND, &motg->inputs);
2505 motg->b_last_se0_sess = jiffies;
Heikki Krogerus1d4c9292012-02-13 13:24:09 +02002506 otg->phy->state = OTG_STATE_B_IDLE;
2507 msm_otg_reset(otg->phy);
Vijayavardhan Vennapusaa3152032012-03-05 16:29:30 +05302508 work = 1;
2509 } else if (test_bit(A_CONN, &motg->inputs)) {
2510 pr_debug("a_conn\n");
2511 clear_bit(A_BUS_SUSPEND, &motg->inputs);
Steve Mucklef132c6c2012-06-06 18:30:57 -07002512 otg->phy->state = OTG_STATE_B_HOST;
Vijayavardhan Vennapusaa3152032012-03-05 16:29:30 +05302513 /*
2514 * PET disconnects D+ pullup after reset is generated
2515 * by B device in B_HOST role which is not detected by
2516 * B device. As workaorund , start timer of 300msec
2517 * and stop timer if A device is enumerated else clear
2518 * A_CONN.
2519 */
2520 msm_otg_start_timer(motg, TB_TST_CONFIG,
2521 B_TST_CONFIG);
2522 } else if (test_bit(B_ASE0_BRST, &motg->tmouts)) {
2523 pr_debug("b_ase0_brst_tmout\n");
2524 pr_info("B HNP fail:No response from A device\n");
2525 msm_otg_start_host(otg, 0);
Steve Mucklef132c6c2012-06-06 18:30:57 -07002526 msm_otg_reset(otg->phy);
Vijayavardhan Vennapusaa3152032012-03-05 16:29:30 +05302527 otg->host->is_b_host = 0;
2528 clear_bit(B_ASE0_BRST, &motg->tmouts);
2529 clear_bit(A_BUS_SUSPEND, &motg->inputs);
2530 clear_bit(B_BUS_REQ, &motg->inputs);
2531 otg_send_event(OTG_EVENT_HNP_FAILED);
Steve Mucklef132c6c2012-06-06 18:30:57 -07002532 otg->phy->state = OTG_STATE_B_IDLE;
Vijayavardhan Vennapusaa3152032012-03-05 16:29:30 +05302533 work = 1;
2534 } else if (test_bit(ID_C, &motg->inputs)) {
2535 msm_otg_notify_charger(motg, IDEV_ACA_CHG_MAX);
2536 }
2537 break;
2538 case OTG_STATE_B_HOST:
2539 if (!test_bit(B_BUS_REQ, &motg->inputs) ||
2540 !test_bit(A_CONN, &motg->inputs) ||
2541 !test_bit(B_SESS_VLD, &motg->inputs)) {
2542 pr_debug("!b_bus_req || !a_conn || !b_sess_vld\n");
2543 clear_bit(A_CONN, &motg->inputs);
2544 clear_bit(B_BUS_REQ, &motg->inputs);
2545 msm_otg_start_host(otg, 0);
2546 otg->host->is_b_host = 0;
Steve Mucklef132c6c2012-06-06 18:30:57 -07002547 otg->phy->state = OTG_STATE_B_IDLE;
2548 msm_otg_reset(otg->phy);
Vijayavardhan Vennapusaa3152032012-03-05 16:29:30 +05302549 work = 1;
2550 } else if (test_bit(ID_C, &motg->inputs)) {
2551 msm_otg_notify_charger(motg, IDEV_ACA_CHG_MAX);
2552 }
2553 break;
2554 case OTG_STATE_A_IDLE:
2555 otg->default_a = 1;
2556 if (test_bit(ID, &motg->inputs) &&
2557 !test_bit(ID_A, &motg->inputs)) {
2558 pr_debug("id && !id_a\n");
2559 otg->default_a = 0;
2560 clear_bit(A_BUS_DROP, &motg->inputs);
Steve Mucklef132c6c2012-06-06 18:30:57 -07002561 otg->phy->state = OTG_STATE_B_IDLE;
Vijayavardhan Vennapusaa3152032012-03-05 16:29:30 +05302562 del_timer_sync(&motg->id_timer);
2563 msm_otg_link_reset(motg);
2564 msm_chg_enable_aca_intr(motg);
2565 msm_otg_notify_charger(motg, 0);
2566 work = 1;
2567 } else if (!test_bit(A_BUS_DROP, &motg->inputs) &&
2568 (test_bit(A_SRP_DET, &motg->inputs) ||
2569 test_bit(A_BUS_REQ, &motg->inputs))) {
2570 pr_debug("!a_bus_drop && (a_srp_det || a_bus_req)\n");
2571
2572 clear_bit(A_SRP_DET, &motg->inputs);
2573 /* Disable SRP detection */
2574 writel_relaxed((readl_relaxed(USB_OTGSC) &
2575 ~OTGSC_INTSTS_MASK) &
2576 ~OTGSC_DPIE, USB_OTGSC);
2577
Steve Mucklef132c6c2012-06-06 18:30:57 -07002578 otg->phy->state = OTG_STATE_A_WAIT_VRISE;
Vijayavardhan Vennapusaa3152032012-03-05 16:29:30 +05302579 /* VBUS should not be supplied before end of SRP pulse
2580 * generated by PET, if not complaince test fail.
2581 */
2582 usleep_range(10000, 12000);
2583 /* ACA: ID_A: Stop charging untill enumeration */
2584 if (test_bit(ID_A, &motg->inputs))
2585 msm_otg_notify_charger(motg, 0);
2586 else
2587 msm_hsusb_vbus_power(motg, 1);
2588 msm_otg_start_timer(motg, TA_WAIT_VRISE, A_WAIT_VRISE);
2589 } else {
2590 pr_debug("No session requested\n");
2591 clear_bit(A_BUS_DROP, &motg->inputs);
2592 if (test_bit(ID_A, &motg->inputs)) {
2593 msm_otg_notify_charger(motg,
2594 IDEV_ACA_CHG_MAX);
2595 } else if (!test_bit(ID, &motg->inputs)) {
2596 msm_otg_notify_charger(motg, 0);
2597 /*
2598 * A-device is not providing power on VBUS.
2599 * Enable SRP detection.
2600 */
2601 writel_relaxed(0x13, USB_USBMODE);
2602 writel_relaxed((readl_relaxed(USB_OTGSC) &
2603 ~OTGSC_INTSTS_MASK) |
2604 OTGSC_DPIE, USB_OTGSC);
2605 mb();
2606 }
2607 }
2608 break;
2609 case OTG_STATE_A_WAIT_VRISE:
2610 if ((test_bit(ID, &motg->inputs) &&
2611 !test_bit(ID_A, &motg->inputs)) ||
2612 test_bit(A_BUS_DROP, &motg->inputs) ||
2613 test_bit(A_WAIT_VRISE, &motg->tmouts)) {
2614 pr_debug("id || a_bus_drop || a_wait_vrise_tmout\n");
2615 clear_bit(A_BUS_REQ, &motg->inputs);
2616 msm_otg_del_timer(motg);
2617 msm_hsusb_vbus_power(motg, 0);
Steve Mucklef132c6c2012-06-06 18:30:57 -07002618 otg->phy->state = OTG_STATE_A_WAIT_VFALL;
Vijayavardhan Vennapusaa3152032012-03-05 16:29:30 +05302619 msm_otg_start_timer(motg, TA_WAIT_VFALL, A_WAIT_VFALL);
2620 } else if (test_bit(A_VBUS_VLD, &motg->inputs)) {
2621 pr_debug("a_vbus_vld\n");
Steve Mucklef132c6c2012-06-06 18:30:57 -07002622 otg->phy->state = OTG_STATE_A_WAIT_BCON;
Vijayavardhan Vennapusaa3152032012-03-05 16:29:30 +05302623 if (TA_WAIT_BCON > 0)
2624 msm_otg_start_timer(motg, TA_WAIT_BCON,
2625 A_WAIT_BCON);
2626 msm_otg_start_host(otg, 1);
2627 msm_chg_enable_aca_det(motg);
2628 msm_chg_disable_aca_intr(motg);
Chiranjeevi Velempati489a27c2012-03-29 09:47:17 +05302629 mod_timer(&motg->id_timer, ID_TIMER_FREQ);
Vijayavardhan Vennapusaa3152032012-03-05 16:29:30 +05302630 if (msm_chg_check_aca_intr(motg))
2631 work = 1;
2632 }
2633 break;
2634 case OTG_STATE_A_WAIT_BCON:
2635 if ((test_bit(ID, &motg->inputs) &&
2636 !test_bit(ID_A, &motg->inputs)) ||
2637 test_bit(A_BUS_DROP, &motg->inputs) ||
2638 test_bit(A_WAIT_BCON, &motg->tmouts)) {
2639 pr_debug("(id && id_a/b/c) || a_bus_drop ||"
2640 "a_wait_bcon_tmout\n");
2641 if (test_bit(A_WAIT_BCON, &motg->tmouts)) {
2642 pr_info("Device No Response\n");
2643 otg_send_event(OTG_EVENT_DEV_CONN_TMOUT);
2644 }
2645 msm_otg_del_timer(motg);
2646 clear_bit(A_BUS_REQ, &motg->inputs);
2647 clear_bit(B_CONN, &motg->inputs);
2648 msm_otg_start_host(otg, 0);
2649 /*
2650 * ACA: ID_A with NO accessory, just the A plug is
2651 * attached to ACA: Use IDCHG_MAX for charging
2652 */
2653 if (test_bit(ID_A, &motg->inputs))
2654 msm_otg_notify_charger(motg, IDEV_CHG_MIN);
2655 else
2656 msm_hsusb_vbus_power(motg, 0);
Steve Mucklef132c6c2012-06-06 18:30:57 -07002657 otg->phy->state = OTG_STATE_A_WAIT_VFALL;
Vijayavardhan Vennapusaa3152032012-03-05 16:29:30 +05302658 msm_otg_start_timer(motg, TA_WAIT_VFALL, A_WAIT_VFALL);
2659 } else if (!test_bit(A_VBUS_VLD, &motg->inputs)) {
2660 pr_debug("!a_vbus_vld\n");
2661 clear_bit(B_CONN, &motg->inputs);
2662 msm_otg_del_timer(motg);
2663 msm_otg_start_host(otg, 0);
Steve Mucklef132c6c2012-06-06 18:30:57 -07002664 otg->phy->state = OTG_STATE_A_VBUS_ERR;
2665 msm_otg_reset(otg->phy);
Vijayavardhan Vennapusaa3152032012-03-05 16:29:30 +05302666 } else if (test_bit(ID_A, &motg->inputs)) {
2667 msm_hsusb_vbus_power(motg, 0);
2668 } else if (!test_bit(A_BUS_REQ, &motg->inputs)) {
2669 /*
2670 * If TA_WAIT_BCON is infinite, we don;t
2671 * turn off VBUS. Enter low power mode.
2672 */
2673 if (TA_WAIT_BCON < 0)
Steve Mucklef132c6c2012-06-06 18:30:57 -07002674 pm_runtime_put_sync(otg->phy->dev);
Vijayavardhan Vennapusaa3152032012-03-05 16:29:30 +05302675 } else if (!test_bit(ID, &motg->inputs)) {
2676 msm_hsusb_vbus_power(motg, 1);
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05302677 }
2678 break;
2679 case OTG_STATE_A_HOST:
Vijayavardhan Vennapusaa3152032012-03-05 16:29:30 +05302680 if ((test_bit(ID, &motg->inputs) &&
2681 !test_bit(ID_A, &motg->inputs)) ||
2682 test_bit(A_BUS_DROP, &motg->inputs)) {
2683 pr_debug("id_a/b/c || a_bus_drop\n");
2684 clear_bit(B_CONN, &motg->inputs);
2685 clear_bit(A_BUS_REQ, &motg->inputs);
2686 msm_otg_del_timer(motg);
Steve Mucklef132c6c2012-06-06 18:30:57 -07002687 otg->phy->state = OTG_STATE_A_WAIT_VFALL;
Vijayavardhan Vennapusaa3152032012-03-05 16:29:30 +05302688 msm_otg_start_host(otg, 0);
2689 if (!test_bit(ID_A, &motg->inputs))
2690 msm_hsusb_vbus_power(motg, 0);
2691 msm_otg_start_timer(motg, TA_WAIT_VFALL, A_WAIT_VFALL);
2692 } else if (!test_bit(A_VBUS_VLD, &motg->inputs)) {
2693 pr_debug("!a_vbus_vld\n");
2694 clear_bit(B_CONN, &motg->inputs);
2695 msm_otg_del_timer(motg);
Steve Mucklef132c6c2012-06-06 18:30:57 -07002696 otg->phy->state = OTG_STATE_A_VBUS_ERR;
Vijayavardhan Vennapusaa3152032012-03-05 16:29:30 +05302697 msm_otg_start_host(otg, 0);
Heikki Krogerus1d4c9292012-02-13 13:24:09 +02002698 msm_otg_reset(otg->phy);
Vijayavardhan Vennapusaa3152032012-03-05 16:29:30 +05302699 } else if (!test_bit(A_BUS_REQ, &motg->inputs)) {
2700 /*
2701 * a_bus_req is de-asserted when root hub is
2702 * suspended or HNP is in progress.
2703 */
2704 pr_debug("!a_bus_req\n");
2705 msm_otg_del_timer(motg);
Steve Mucklef132c6c2012-06-06 18:30:57 -07002706 otg->phy->state = OTG_STATE_A_SUSPEND;
Vijayavardhan Vennapusaa3152032012-03-05 16:29:30 +05302707 if (otg->host->b_hnp_enable)
2708 msm_otg_start_timer(motg, TA_AIDL_BDIS,
2709 A_AIDL_BDIS);
2710 else
Steve Mucklef132c6c2012-06-06 18:30:57 -07002711 pm_runtime_put_sync(otg->phy->dev);
Vijayavardhan Vennapusaa3152032012-03-05 16:29:30 +05302712 } else if (!test_bit(B_CONN, &motg->inputs)) {
2713 pr_debug("!b_conn\n");
2714 msm_otg_del_timer(motg);
Steve Mucklef132c6c2012-06-06 18:30:57 -07002715 otg->phy->state = OTG_STATE_A_WAIT_BCON;
Vijayavardhan Vennapusaa3152032012-03-05 16:29:30 +05302716 if (TA_WAIT_BCON > 0)
2717 msm_otg_start_timer(motg, TA_WAIT_BCON,
2718 A_WAIT_BCON);
2719 if (msm_chg_check_aca_intr(motg))
2720 work = 1;
2721 } else if (test_bit(ID_A, &motg->inputs)) {
2722 msm_otg_del_timer(motg);
2723 msm_hsusb_vbus_power(motg, 0);
2724 if (motg->chg_type == USB_ACA_DOCK_CHARGER)
2725 msm_otg_notify_charger(motg,
2726 IDEV_ACA_CHG_MAX);
2727 else
2728 msm_otg_notify_charger(motg,
2729 IDEV_CHG_MIN - motg->mA_port);
2730 } else if (!test_bit(ID, &motg->inputs)) {
2731 motg->chg_state = USB_CHG_STATE_UNDEFINED;
2732 motg->chg_type = USB_INVALID_CHARGER;
2733 msm_otg_notify_charger(motg, 0);
2734 msm_hsusb_vbus_power(motg, 1);
2735 }
2736 break;
2737 case OTG_STATE_A_SUSPEND:
2738 if ((test_bit(ID, &motg->inputs) &&
2739 !test_bit(ID_A, &motg->inputs)) ||
2740 test_bit(A_BUS_DROP, &motg->inputs) ||
2741 test_bit(A_AIDL_BDIS, &motg->tmouts)) {
2742 pr_debug("id_a/b/c || a_bus_drop ||"
2743 "a_aidl_bdis_tmout\n");
2744 msm_otg_del_timer(motg);
2745 clear_bit(B_CONN, &motg->inputs);
Steve Mucklef132c6c2012-06-06 18:30:57 -07002746 otg->phy->state = OTG_STATE_A_WAIT_VFALL;
Vijayavardhan Vennapusaa3152032012-03-05 16:29:30 +05302747 msm_otg_start_host(otg, 0);
Steve Mucklef132c6c2012-06-06 18:30:57 -07002748 msm_otg_reset(otg->phy);
Vijayavardhan Vennapusaa3152032012-03-05 16:29:30 +05302749 if (!test_bit(ID_A, &motg->inputs))
2750 msm_hsusb_vbus_power(motg, 0);
2751 msm_otg_start_timer(motg, TA_WAIT_VFALL, A_WAIT_VFALL);
2752 } else if (!test_bit(A_VBUS_VLD, &motg->inputs)) {
2753 pr_debug("!a_vbus_vld\n");
2754 msm_otg_del_timer(motg);
2755 clear_bit(B_CONN, &motg->inputs);
Steve Mucklef132c6c2012-06-06 18:30:57 -07002756 otg->phy->state = OTG_STATE_A_VBUS_ERR;
Vijayavardhan Vennapusaa3152032012-03-05 16:29:30 +05302757 msm_otg_start_host(otg, 0);
Steve Mucklef132c6c2012-06-06 18:30:57 -07002758 msm_otg_reset(otg->phy);
Vijayavardhan Vennapusaa3152032012-03-05 16:29:30 +05302759 } else if (!test_bit(B_CONN, &motg->inputs) &&
2760 otg->host->b_hnp_enable) {
2761 pr_debug("!b_conn && b_hnp_enable");
Steve Mucklef132c6c2012-06-06 18:30:57 -07002762 otg->phy->state = OTG_STATE_A_PERIPHERAL;
Vijayavardhan Vennapusaa3152032012-03-05 16:29:30 +05302763 msm_otg_host_hnp_enable(otg, 1);
2764 otg->gadget->is_a_peripheral = 1;
2765 msm_otg_start_peripheral(otg, 1);
2766 } else if (!test_bit(B_CONN, &motg->inputs) &&
2767 !otg->host->b_hnp_enable) {
2768 pr_debug("!b_conn && !b_hnp_enable");
2769 /*
2770 * bus request is dropped during suspend.
2771 * acquire again for next device.
2772 */
2773 set_bit(A_BUS_REQ, &motg->inputs);
Steve Mucklef132c6c2012-06-06 18:30:57 -07002774 otg->phy->state = OTG_STATE_A_WAIT_BCON;
Vijayavardhan Vennapusaa3152032012-03-05 16:29:30 +05302775 if (TA_WAIT_BCON > 0)
2776 msm_otg_start_timer(motg, TA_WAIT_BCON,
2777 A_WAIT_BCON);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002778 } else if (test_bit(ID_A, &motg->inputs)) {
Mayank Ranae3926882011-12-26 09:47:54 +05302779 msm_hsusb_vbus_power(motg, 0);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002780 msm_otg_notify_charger(motg,
Vijayavardhan Vennapusaa3152032012-03-05 16:29:30 +05302781 IDEV_CHG_MIN - motg->mA_port);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002782 } else if (!test_bit(ID, &motg->inputs)) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002783 msm_otg_notify_charger(motg, 0);
Mayank Ranae3926882011-12-26 09:47:54 +05302784 msm_hsusb_vbus_power(motg, 1);
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05302785 }
2786 break;
Vijayavardhan Vennapusaa3152032012-03-05 16:29:30 +05302787 case OTG_STATE_A_PERIPHERAL:
2788 if ((test_bit(ID, &motg->inputs) &&
2789 !test_bit(ID_A, &motg->inputs)) ||
2790 test_bit(A_BUS_DROP, &motg->inputs)) {
2791 pr_debug("id _f/b/c || a_bus_drop\n");
2792 /* Clear BIDL_ADIS timer */
2793 msm_otg_del_timer(motg);
Steve Mucklef132c6c2012-06-06 18:30:57 -07002794 otg->phy->state = OTG_STATE_A_WAIT_VFALL;
Vijayavardhan Vennapusaa3152032012-03-05 16:29:30 +05302795 msm_otg_start_peripheral(otg, 0);
2796 otg->gadget->is_a_peripheral = 0;
2797 msm_otg_start_host(otg, 0);
Steve Mucklef132c6c2012-06-06 18:30:57 -07002798 msm_otg_reset(otg->phy);
Vijayavardhan Vennapusaa3152032012-03-05 16:29:30 +05302799 if (!test_bit(ID_A, &motg->inputs))
2800 msm_hsusb_vbus_power(motg, 0);
2801 msm_otg_start_timer(motg, TA_WAIT_VFALL, A_WAIT_VFALL);
2802 } else if (!test_bit(A_VBUS_VLD, &motg->inputs)) {
2803 pr_debug("!a_vbus_vld\n");
2804 /* Clear BIDL_ADIS timer */
2805 msm_otg_del_timer(motg);
Steve Mucklef132c6c2012-06-06 18:30:57 -07002806 otg->phy->state = OTG_STATE_A_VBUS_ERR;
Vijayavardhan Vennapusaa3152032012-03-05 16:29:30 +05302807 msm_otg_start_peripheral(otg, 0);
2808 otg->gadget->is_a_peripheral = 0;
2809 msm_otg_start_host(otg, 0);
2810 } else if (test_bit(A_BIDL_ADIS, &motg->tmouts)) {
2811 pr_debug("a_bidl_adis_tmout\n");
2812 msm_otg_start_peripheral(otg, 0);
2813 otg->gadget->is_a_peripheral = 0;
Steve Mucklef132c6c2012-06-06 18:30:57 -07002814 otg->phy->state = OTG_STATE_A_WAIT_BCON;
Vijayavardhan Vennapusaa3152032012-03-05 16:29:30 +05302815 set_bit(A_BUS_REQ, &motg->inputs);
2816 msm_otg_host_hnp_enable(otg, 0);
2817 if (TA_WAIT_BCON > 0)
2818 msm_otg_start_timer(motg, TA_WAIT_BCON,
2819 A_WAIT_BCON);
2820 } else if (test_bit(ID_A, &motg->inputs)) {
2821 msm_hsusb_vbus_power(motg, 0);
2822 msm_otg_notify_charger(motg,
2823 IDEV_CHG_MIN - motg->mA_port);
2824 } else if (!test_bit(ID, &motg->inputs)) {
2825 msm_otg_notify_charger(motg, 0);
2826 msm_hsusb_vbus_power(motg, 1);
2827 }
2828 break;
2829 case OTG_STATE_A_WAIT_VFALL:
2830 if (test_bit(A_WAIT_VFALL, &motg->tmouts)) {
2831 clear_bit(A_VBUS_VLD, &motg->inputs);
Steve Mucklef132c6c2012-06-06 18:30:57 -07002832 otg->phy->state = OTG_STATE_A_IDLE;
Vijayavardhan Vennapusaa3152032012-03-05 16:29:30 +05302833 work = 1;
2834 }
2835 break;
2836 case OTG_STATE_A_VBUS_ERR:
2837 if ((test_bit(ID, &motg->inputs) &&
2838 !test_bit(ID_A, &motg->inputs)) ||
2839 test_bit(A_BUS_DROP, &motg->inputs) ||
2840 test_bit(A_CLR_ERR, &motg->inputs)) {
Steve Mucklef132c6c2012-06-06 18:30:57 -07002841 otg->phy->state = OTG_STATE_A_WAIT_VFALL;
Vijayavardhan Vennapusaa3152032012-03-05 16:29:30 +05302842 if (!test_bit(ID_A, &motg->inputs))
2843 msm_hsusb_vbus_power(motg, 0);
2844 msm_otg_start_timer(motg, TA_WAIT_VFALL, A_WAIT_VFALL);
2845 motg->chg_state = USB_CHG_STATE_UNDEFINED;
2846 motg->chg_type = USB_INVALID_CHARGER;
2847 msm_otg_notify_charger(motg, 0);
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05302848 }
2849 break;
2850 default:
2851 break;
2852 }
Vijayavardhan Vennapusaa3152032012-03-05 16:29:30 +05302853 if (work)
2854 queue_work(system_nrt_wq, &motg->sm_work);
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05302855}
2856
Amit Blayd0fe07b2012-09-05 16:42:09 +03002857static void msm_otg_suspend_work(struct work_struct *w)
2858{
2859 struct msm_otg *motg =
2860 container_of(w, struct msm_otg, suspend_work.work);
2861 atomic_set(&motg->suspend_work_pending, 0);
2862 msm_otg_sm_work(&motg->sm_work);
2863}
2864
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05302865static irqreturn_t msm_otg_irq(int irq, void *data)
2866{
2867 struct msm_otg *motg = data;
Steve Mucklef132c6c2012-06-06 18:30:57 -07002868 struct usb_otg *otg = motg->phy.otg;
Vijayavardhan Vennapusaa3152032012-03-05 16:29:30 +05302869 u32 otgsc = 0, usbsts, pc;
2870 bool work = 0;
2871 irqreturn_t ret = IRQ_HANDLED;
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05302872
Pavankumar Kondeti87c01042010-12-07 17:53:58 +05302873 if (atomic_read(&motg->in_lpm)) {
Manu Gautamf8c45642012-08-10 10:20:56 -07002874 pr_debug("OTG IRQ: %d in LPM\n", irq);
Pavankumar Kondeti87c01042010-12-07 17:53:58 +05302875 disable_irq_nosync(irq);
Manu Gautamf8c45642012-08-10 10:20:56 -07002876 motg->async_int = irq;
Jack Phamc7edb172012-08-13 15:32:39 -07002877 if (!atomic_read(&motg->pm_suspended))
Steve Mucklef132c6c2012-06-06 18:30:57 -07002878 pm_request_resume(otg->phy->dev);
Pavankumar Kondeti87c01042010-12-07 17:53:58 +05302879 return IRQ_HANDLED;
2880 }
2881
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002882 usbsts = readl(USB_USBSTS);
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05302883 otgsc = readl(USB_OTGSC);
Vijayavardhan Vennapusaa3152032012-03-05 16:29:30 +05302884
2885 if (!(otgsc & OTG_OTGSTS_MASK) && !(usbsts & OTG_USBSTS_MASK))
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05302886 return IRQ_NONE;
2887
2888 if ((otgsc & OTGSC_IDIS) && (otgsc & OTGSC_IDIE)) {
Pavankumar Kondetiaa449e12011-11-04 11:09:26 +05302889 if (otgsc & OTGSC_ID) {
Vijayavardhan Vennapusaa3152032012-03-05 16:29:30 +05302890 pr_debug("Id set\n");
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05302891 set_bit(ID, &motg->inputs);
Pavankumar Kondetiaa449e12011-11-04 11:09:26 +05302892 } else {
Vijayavardhan Vennapusaa3152032012-03-05 16:29:30 +05302893 pr_debug("Id clear\n");
2894 /*
2895 * Assert a_bus_req to supply power on
2896 * VBUS when Micro/Mini-A cable is connected
2897 * with out user intervention.
2898 */
2899 set_bit(A_BUS_REQ, &motg->inputs);
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05302900 clear_bit(ID, &motg->inputs);
Pavankumar Kondetiaa449e12011-11-04 11:09:26 +05302901 msm_chg_enable_aca_det(motg);
2902 }
Vijayavardhan Vennapusaa3152032012-03-05 16:29:30 +05302903 writel_relaxed(otgsc, USB_OTGSC);
2904 work = 1;
2905 } else if (otgsc & OTGSC_DPIS) {
2906 pr_debug("DPIS detected\n");
2907 writel_relaxed(otgsc, USB_OTGSC);
2908 set_bit(A_SRP_DET, &motg->inputs);
2909 set_bit(A_BUS_REQ, &motg->inputs);
2910 work = 1;
2911 } else if (otgsc & OTGSC_BSVIS) {
2912 writel_relaxed(otgsc, USB_OTGSC);
2913 /*
2914 * BSV interrupt comes when operating as an A-device
2915 * (VBUS on/off).
2916 * But, handle BSV when charger is removed from ACA in ID_A
2917 */
Steve Mucklef132c6c2012-06-06 18:30:57 -07002918 if ((otg->phy->state >= OTG_STATE_A_IDLE) &&
Vijayavardhan Vennapusaa3152032012-03-05 16:29:30 +05302919 !test_bit(ID_A, &motg->inputs))
2920 return IRQ_HANDLED;
Pavankumar Kondetiaa449e12011-11-04 11:09:26 +05302921 if (otgsc & OTGSC_BSV) {
Vijayavardhan Vennapusaa3152032012-03-05 16:29:30 +05302922 pr_debug("BSV set\n");
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05302923 set_bit(B_SESS_VLD, &motg->inputs);
Pavankumar Kondetiaa449e12011-11-04 11:09:26 +05302924 } else {
Vijayavardhan Vennapusaa3152032012-03-05 16:29:30 +05302925 pr_debug("BSV clear\n");
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05302926 clear_bit(B_SESS_VLD, &motg->inputs);
Amit Blay6fa647a2012-05-24 14:12:08 +03002927 clear_bit(A_BUS_SUSPEND, &motg->inputs);
2928
Pavankumar Kondetiaa449e12011-11-04 11:09:26 +05302929 msm_chg_check_aca_intr(motg);
2930 }
Vijayavardhan Vennapusaa3152032012-03-05 16:29:30 +05302931 work = 1;
2932 } else if (usbsts & STS_PCI) {
2933 pc = readl_relaxed(USB_PORTSC);
2934 pr_debug("portsc = %x\n", pc);
2935 ret = IRQ_NONE;
2936 /*
2937 * HCD Acks PCI interrupt. We use this to switch
2938 * between different OTG states.
2939 */
2940 work = 1;
Steve Mucklef132c6c2012-06-06 18:30:57 -07002941 switch (otg->phy->state) {
Vijayavardhan Vennapusaa3152032012-03-05 16:29:30 +05302942 case OTG_STATE_A_SUSPEND:
2943 if (otg->host->b_hnp_enable && (pc & PORTSC_CSC) &&
2944 !(pc & PORTSC_CCS)) {
2945 pr_debug("B_CONN clear\n");
2946 clear_bit(B_CONN, &motg->inputs);
2947 msm_otg_del_timer(motg);
2948 }
2949 break;
2950 case OTG_STATE_A_PERIPHERAL:
2951 /*
2952 * A-peripheral observed activity on bus.
2953 * clear A_BIDL_ADIS timer.
2954 */
2955 msm_otg_del_timer(motg);
2956 work = 0;
2957 break;
2958 case OTG_STATE_B_WAIT_ACON:
2959 if ((pc & PORTSC_CSC) && (pc & PORTSC_CCS)) {
2960 pr_debug("A_CONN set\n");
2961 set_bit(A_CONN, &motg->inputs);
2962 /* Clear ASE0_BRST timer */
2963 msm_otg_del_timer(motg);
2964 }
2965 break;
2966 case OTG_STATE_B_HOST:
2967 if ((pc & PORTSC_CSC) && !(pc & PORTSC_CCS)) {
2968 pr_debug("A_CONN clear\n");
2969 clear_bit(A_CONN, &motg->inputs);
2970 msm_otg_del_timer(motg);
2971 }
2972 break;
2973 case OTG_STATE_A_WAIT_BCON:
2974 if (TA_WAIT_BCON < 0)
2975 set_bit(A_BUS_REQ, &motg->inputs);
2976 default:
2977 work = 0;
2978 break;
2979 }
2980 } else if (usbsts & STS_URI) {
2981 ret = IRQ_NONE;
Steve Mucklef132c6c2012-06-06 18:30:57 -07002982 switch (otg->phy->state) {
Vijayavardhan Vennapusaa3152032012-03-05 16:29:30 +05302983 case OTG_STATE_A_PERIPHERAL:
2984 /*
2985 * A-peripheral observed activity on bus.
2986 * clear A_BIDL_ADIS timer.
2987 */
2988 msm_otg_del_timer(motg);
2989 work = 0;
2990 break;
2991 default:
2992 work = 0;
2993 break;
2994 }
2995 } else if (usbsts & STS_SLI) {
2996 ret = IRQ_NONE;
2997 work = 0;
Steve Mucklef132c6c2012-06-06 18:30:57 -07002998 switch (otg->phy->state) {
Vijayavardhan Vennapusaa3152032012-03-05 16:29:30 +05302999 case OTG_STATE_B_PERIPHERAL:
3000 if (otg->gadget->b_hnp_enable) {
3001 set_bit(A_BUS_SUSPEND, &motg->inputs);
3002 set_bit(B_BUS_REQ, &motg->inputs);
3003 work = 1;
3004 }
3005 break;
3006 case OTG_STATE_A_PERIPHERAL:
3007 msm_otg_start_timer(motg, TA_BIDL_ADIS,
3008 A_BIDL_ADIS);
3009 break;
3010 default:
3011 break;
3012 }
3013 } else if ((usbsts & PHY_ALT_INT)) {
3014 writel_relaxed(PHY_ALT_INT, USB_USBSTS);
3015 if (msm_chg_check_aca_intr(motg))
3016 work = 1;
3017 ret = IRQ_HANDLED;
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05303018 }
Vijayavardhan Vennapusaa3152032012-03-05 16:29:30 +05303019 if (work)
3020 queue_work(system_nrt_wq, &motg->sm_work);
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05303021
Vijayavardhan Vennapusaa3152032012-03-05 16:29:30 +05303022 return ret;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003023}
3024
3025static void msm_otg_set_vbus_state(int online)
3026{
Pavankumar Kondeti4960f312011-12-06 15:46:14 +05303027 static bool init;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003028 struct msm_otg *motg = the_msm_otg;
Mayank Ranabaf31f42012-07-05 09:43:54 +05303029 struct usb_otg *otg = motg->phy.otg;
3030
3031 /* In A Host Mode, ignore received BSV interrupts */
3032 if (otg->phy->state >= OTG_STATE_A_IDLE)
3033 return;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003034
Pavankumar Kondeti4960f312011-12-06 15:46:14 +05303035 if (online) {
3036 pr_debug("PMIC: BSV set\n");
3037 set_bit(B_SESS_VLD, &motg->inputs);
3038 } else {
3039 pr_debug("PMIC: BSV clear\n");
3040 clear_bit(B_SESS_VLD, &motg->inputs);
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05303041 }
3042
Pavankumar Kondeti4960f312011-12-06 15:46:14 +05303043 if (!init) {
3044 init = true;
3045 complete(&pmic_vbus_init);
3046 pr_debug("PMIC: BSV init complete\n");
3047 return;
3048 }
3049
Pavankumar Kondeti2aec9f32012-06-13 09:06:03 +05303050 if (test_bit(MHL, &motg->inputs) ||
3051 mhl_det_in_progress) {
3052 pr_debug("PMIC: BSV interrupt ignored in MHL\n");
3053 return;
3054 }
3055
Jack Pham5ca279b2012-05-14 18:42:54 -07003056 if (atomic_read(&motg->pm_suspended))
3057 motg->sm_work_pending = true;
3058 else
3059 queue_work(system_nrt_wq, &motg->sm_work);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003060}
3061
Vijayavardhan Vennapusa68d55cf2012-06-27 20:06:12 +05303062static void msm_pmic_id_status_w(struct work_struct *w)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003063{
Vijayavardhan Vennapusa68d55cf2012-06-27 20:06:12 +05303064 struct msm_otg *motg = container_of(w, struct msm_otg,
3065 pmic_id_status_work.work);
3066 int work = 0;
3067 unsigned long flags;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003068
Vijayavardhan Vennapusa68d55cf2012-06-27 20:06:12 +05303069 local_irq_save(flags);
Pavankumar Kondeti4960f312011-12-06 15:46:14 +05303070 if (irq_read_line(motg->pdata->pmic_id_irq)) {
Vijayavardhan Vennapusa68d55cf2012-06-27 20:06:12 +05303071 if (!test_and_set_bit(ID, &motg->inputs)) {
3072 pr_debug("PMIC: ID set\n");
3073 work = 1;
3074 }
Pavankumar Kondeti4960f312011-12-06 15:46:14 +05303075 } else {
Vijayavardhan Vennapusa68d55cf2012-06-27 20:06:12 +05303076 if (test_and_clear_bit(ID, &motg->inputs)) {
3077 pr_debug("PMIC: ID clear\n");
3078 set_bit(A_BUS_REQ, &motg->inputs);
3079 work = 1;
3080 }
Pavankumar Kondeti4960f312011-12-06 15:46:14 +05303081 }
3082
Vijayavardhan Vennapusa68d55cf2012-06-27 20:06:12 +05303083 if (work && (motg->phy.state != OTG_STATE_UNDEFINED)) {
Jack Pham5ca279b2012-05-14 18:42:54 -07003084 if (atomic_read(&motg->pm_suspended))
3085 motg->sm_work_pending = true;
3086 else
3087 queue_work(system_nrt_wq, &motg->sm_work);
3088 }
Vijayavardhan Vennapusa68d55cf2012-06-27 20:06:12 +05303089 local_irq_restore(flags);
3090
3091}
3092
3093#define MSM_PMIC_ID_STATUS_DELAY 5 /* 5msec */
3094static irqreturn_t msm_pmic_id_irq(int irq, void *data)
3095{
3096 struct msm_otg *motg = data;
3097
Pavankumar Kondeti2aec9f32012-06-13 09:06:03 +05303098 if (test_bit(MHL, &motg->inputs) ||
3099 mhl_det_in_progress) {
3100 pr_debug("PMIC: Id interrupt ignored in MHL\n");
3101 return IRQ_HANDLED;
3102 }
3103
Vijayavardhan Vennapusa68d55cf2012-06-27 20:06:12 +05303104 if (!aca_id_turned_on)
3105 /*schedule delayed work for 5msec for ID line state to settle*/
3106 queue_delayed_work(system_nrt_wq, &motg->pmic_id_status_work,
3107 msecs_to_jiffies(MSM_PMIC_ID_STATUS_DELAY));
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003108
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05303109 return IRQ_HANDLED;
3110}
3111
3112static int msm_otg_mode_show(struct seq_file *s, void *unused)
3113{
3114 struct msm_otg *motg = s->private;
Steve Mucklef132c6c2012-06-06 18:30:57 -07003115 struct usb_phy *phy = &motg->phy;
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05303116
Steve Mucklef132c6c2012-06-06 18:30:57 -07003117 switch (phy->state) {
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05303118 case OTG_STATE_A_HOST:
3119 seq_printf(s, "host\n");
3120 break;
3121 case OTG_STATE_B_PERIPHERAL:
3122 seq_printf(s, "peripheral\n");
3123 break;
3124 default:
3125 seq_printf(s, "none\n");
3126 break;
3127 }
3128
3129 return 0;
3130}
3131
3132static int msm_otg_mode_open(struct inode *inode, struct file *file)
3133{
3134 return single_open(file, msm_otg_mode_show, inode->i_private);
3135}
3136
3137static ssize_t msm_otg_mode_write(struct file *file, const char __user *ubuf,
3138 size_t count, loff_t *ppos)
3139{
Pavankumar Kondetie2904ee2011-02-15 09:42:35 +05303140 struct seq_file *s = file->private_data;
3141 struct msm_otg *motg = s->private;
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05303142 char buf[16];
Steve Mucklef132c6c2012-06-06 18:30:57 -07003143 struct usb_phy *phy = &motg->phy;
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05303144 int status = count;
3145 enum usb_mode_type req_mode;
3146
3147 memset(buf, 0x00, sizeof(buf));
3148
3149 if (copy_from_user(&buf, ubuf, min_t(size_t, sizeof(buf) - 1, count))) {
3150 status = -EFAULT;
3151 goto out;
3152 }
3153
3154 if (!strncmp(buf, "host", 4)) {
3155 req_mode = USB_HOST;
3156 } else if (!strncmp(buf, "peripheral", 10)) {
3157 req_mode = USB_PERIPHERAL;
3158 } else if (!strncmp(buf, "none", 4)) {
3159 req_mode = USB_NONE;
3160 } else {
3161 status = -EINVAL;
3162 goto out;
3163 }
3164
3165 switch (req_mode) {
3166 case USB_NONE:
Steve Mucklef132c6c2012-06-06 18:30:57 -07003167 switch (phy->state) {
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05303168 case OTG_STATE_A_HOST:
3169 case OTG_STATE_B_PERIPHERAL:
3170 set_bit(ID, &motg->inputs);
3171 clear_bit(B_SESS_VLD, &motg->inputs);
3172 break;
3173 default:
3174 goto out;
3175 }
3176 break;
3177 case USB_PERIPHERAL:
Steve Mucklef132c6c2012-06-06 18:30:57 -07003178 switch (phy->state) {
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05303179 case OTG_STATE_B_IDLE:
3180 case OTG_STATE_A_HOST:
3181 set_bit(ID, &motg->inputs);
3182 set_bit(B_SESS_VLD, &motg->inputs);
3183 break;
3184 default:
3185 goto out;
3186 }
3187 break;
3188 case USB_HOST:
Steve Mucklef132c6c2012-06-06 18:30:57 -07003189 switch (phy->state) {
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05303190 case OTG_STATE_B_IDLE:
3191 case OTG_STATE_B_PERIPHERAL:
3192 clear_bit(ID, &motg->inputs);
3193 break;
3194 default:
3195 goto out;
3196 }
3197 break;
3198 default:
3199 goto out;
3200 }
3201
Steve Mucklef132c6c2012-06-06 18:30:57 -07003202 pm_runtime_resume(phy->dev);
Vijayavardhan Vennapusaa3152032012-03-05 16:29:30 +05303203 queue_work(system_nrt_wq, &motg->sm_work);
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05303204out:
3205 return status;
3206}
3207
3208const struct file_operations msm_otg_mode_fops = {
3209 .open = msm_otg_mode_open,
3210 .read = seq_read,
3211 .write = msm_otg_mode_write,
3212 .llseek = seq_lseek,
3213 .release = single_release,
3214};
3215
Chiranjeevi Velempatif9a11542012-03-28 18:18:34 +05303216static int msm_otg_show_otg_state(struct seq_file *s, void *unused)
3217{
3218 struct msm_otg *motg = s->private;
Steve Mucklef132c6c2012-06-06 18:30:57 -07003219 struct usb_phy *phy = &motg->phy;
Chiranjeevi Velempatif9a11542012-03-28 18:18:34 +05303220
Steve Mucklef132c6c2012-06-06 18:30:57 -07003221 seq_printf(s, "%s\n", otg_state_string(phy->state));
Chiranjeevi Velempatif9a11542012-03-28 18:18:34 +05303222 return 0;
3223}
3224
3225static int msm_otg_otg_state_open(struct inode *inode, struct file *file)
3226{
3227 return single_open(file, msm_otg_show_otg_state, inode->i_private);
3228}
3229
3230const struct file_operations msm_otg_state_fops = {
3231 .open = msm_otg_otg_state_open,
3232 .read = seq_read,
3233 .llseek = seq_lseek,
3234 .release = single_release,
3235};
3236
Anji jonnalad270e2d2011-08-09 11:28:32 +05303237static int msm_otg_show_chg_type(struct seq_file *s, void *unused)
3238{
3239 struct msm_otg *motg = s->private;
3240
Pavankumar Kondeti9ef69cb2011-12-12 14:18:22 +05303241 seq_printf(s, "%s\n", chg_to_string(motg->chg_type));
Anji jonnalad270e2d2011-08-09 11:28:32 +05303242 return 0;
3243}
3244
3245static int msm_otg_chg_open(struct inode *inode, struct file *file)
3246{
3247 return single_open(file, msm_otg_show_chg_type, inode->i_private);
3248}
3249
3250const struct file_operations msm_otg_chg_fops = {
3251 .open = msm_otg_chg_open,
3252 .read = seq_read,
3253 .llseek = seq_lseek,
3254 .release = single_release,
3255};
3256
Pavankumar Kondetiaa449e12011-11-04 11:09:26 +05303257static int msm_otg_aca_show(struct seq_file *s, void *unused)
3258{
3259 if (debug_aca_enabled)
3260 seq_printf(s, "enabled\n");
3261 else
3262 seq_printf(s, "disabled\n");
3263
3264 return 0;
3265}
3266
3267static int msm_otg_aca_open(struct inode *inode, struct file *file)
3268{
3269 return single_open(file, msm_otg_aca_show, inode->i_private);
3270}
3271
3272static ssize_t msm_otg_aca_write(struct file *file, const char __user *ubuf,
3273 size_t count, loff_t *ppos)
3274{
3275 char buf[8];
3276
3277 memset(buf, 0x00, sizeof(buf));
3278
3279 if (copy_from_user(&buf, ubuf, min_t(size_t, sizeof(buf) - 1, count)))
3280 return -EFAULT;
3281
3282 if (!strncmp(buf, "enable", 6))
3283 debug_aca_enabled = true;
3284 else
3285 debug_aca_enabled = false;
3286
3287 return count;
3288}
3289
3290const struct file_operations msm_otg_aca_fops = {
3291 .open = msm_otg_aca_open,
3292 .read = seq_read,
3293 .write = msm_otg_aca_write,
3294 .llseek = seq_lseek,
3295 .release = single_release,
3296};
3297
Manu Gautam8bdcc592012-03-06 11:26:06 +05303298static int msm_otg_bus_show(struct seq_file *s, void *unused)
3299{
3300 if (debug_bus_voting_enabled)
3301 seq_printf(s, "enabled\n");
3302 else
3303 seq_printf(s, "disabled\n");
3304
3305 return 0;
3306}
3307
3308static int msm_otg_bus_open(struct inode *inode, struct file *file)
3309{
3310 return single_open(file, msm_otg_bus_show, inode->i_private);
3311}
3312
3313static ssize_t msm_otg_bus_write(struct file *file, const char __user *ubuf,
3314 size_t count, loff_t *ppos)
3315{
3316 char buf[8];
3317 int ret;
3318 struct seq_file *s = file->private_data;
3319 struct msm_otg *motg = s->private;
3320
3321 memset(buf, 0x00, sizeof(buf));
3322
3323 if (copy_from_user(&buf, ubuf, min_t(size_t, sizeof(buf) - 1, count)))
3324 return -EFAULT;
3325
3326 if (!strncmp(buf, "enable", 6)) {
3327 /* Do not vote here. Let OTG statemachine decide when to vote */
3328 debug_bus_voting_enabled = true;
3329 } else {
3330 debug_bus_voting_enabled = false;
3331 if (motg->bus_perf_client) {
3332 ret = msm_bus_scale_client_update_request(
3333 motg->bus_perf_client, 0);
3334 if (ret)
Steve Mucklef132c6c2012-06-06 18:30:57 -07003335 dev_err(motg->phy.dev, "%s: Failed to devote "
Manu Gautam8bdcc592012-03-06 11:26:06 +05303336 "for bus bw %d\n", __func__, ret);
3337 }
3338 }
3339
3340 return count;
3341}
3342
3343const struct file_operations msm_otg_bus_fops = {
3344 .open = msm_otg_bus_open,
3345 .read = seq_read,
3346 .write = msm_otg_bus_write,
3347 .llseek = seq_lseek,
3348 .release = single_release,
3349};
3350
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05303351static struct dentry *msm_otg_dbg_root;
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05303352
3353static int msm_otg_debugfs_init(struct msm_otg *motg)
3354{
Manu Gautam8bdcc592012-03-06 11:26:06 +05303355 struct dentry *msm_otg_dentry;
Anji jonnalad270e2d2011-08-09 11:28:32 +05303356
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05303357 msm_otg_dbg_root = debugfs_create_dir("msm_otg", NULL);
3358
3359 if (!msm_otg_dbg_root || IS_ERR(msm_otg_dbg_root))
3360 return -ENODEV;
3361
Anji jonnalad270e2d2011-08-09 11:28:32 +05303362 if (motg->pdata->mode == USB_OTG &&
3363 motg->pdata->otg_control == OTG_USER_CONTROL) {
3364
Manu Gautam8bdcc592012-03-06 11:26:06 +05303365 msm_otg_dentry = debugfs_create_file("mode", S_IRUGO |
Anji jonnalad270e2d2011-08-09 11:28:32 +05303366 S_IWUSR, msm_otg_dbg_root, motg,
3367 &msm_otg_mode_fops);
3368
Manu Gautam8bdcc592012-03-06 11:26:06 +05303369 if (!msm_otg_dentry) {
Anji jonnalad270e2d2011-08-09 11:28:32 +05303370 debugfs_remove(msm_otg_dbg_root);
3371 msm_otg_dbg_root = NULL;
3372 return -ENODEV;
3373 }
3374 }
3375
Manu Gautam8bdcc592012-03-06 11:26:06 +05303376 msm_otg_dentry = debugfs_create_file("chg_type", S_IRUGO,
Anji jonnalad270e2d2011-08-09 11:28:32 +05303377 msm_otg_dbg_root, motg,
3378 &msm_otg_chg_fops);
3379
Manu Gautam8bdcc592012-03-06 11:26:06 +05303380 if (!msm_otg_dentry) {
Pavankumar Kondetiaa449e12011-11-04 11:09:26 +05303381 debugfs_remove_recursive(msm_otg_dbg_root);
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05303382 return -ENODEV;
3383 }
3384
Manu Gautam8bdcc592012-03-06 11:26:06 +05303385 msm_otg_dentry = debugfs_create_file("aca", S_IRUGO | S_IWUSR,
Pavankumar Kondetiaa449e12011-11-04 11:09:26 +05303386 msm_otg_dbg_root, motg,
3387 &msm_otg_aca_fops);
3388
Manu Gautam8bdcc592012-03-06 11:26:06 +05303389 if (!msm_otg_dentry) {
Pavankumar Kondetiaa449e12011-11-04 11:09:26 +05303390 debugfs_remove_recursive(msm_otg_dbg_root);
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05303391 return -ENODEV;
3392 }
3393
Manu Gautam8bdcc592012-03-06 11:26:06 +05303394 msm_otg_dentry = debugfs_create_file("bus_voting", S_IRUGO | S_IWUSR,
3395 msm_otg_dbg_root, motg,
3396 &msm_otg_bus_fops);
3397
3398 if (!msm_otg_dentry) {
3399 debugfs_remove_recursive(msm_otg_dbg_root);
3400 return -ENODEV;
3401 }
Chiranjeevi Velempatif9a11542012-03-28 18:18:34 +05303402
3403 msm_otg_dentry = debugfs_create_file("otg_state", S_IRUGO,
3404 msm_otg_dbg_root, motg, &msm_otg_state_fops);
3405
3406 if (!msm_otg_dentry) {
3407 debugfs_remove_recursive(msm_otg_dbg_root);
3408 return -ENODEV;
3409 }
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05303410 return 0;
3411}
3412
3413static void msm_otg_debugfs_cleanup(void)
3414{
Anji jonnalad270e2d2011-08-09 11:28:32 +05303415 debugfs_remove_recursive(msm_otg_dbg_root);
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05303416}
3417
Pavankumar Kondetieaea7fe2011-10-27 14:46:45 +05303418static u64 msm_otg_dma_mask = DMA_BIT_MASK(64);
3419static struct platform_device *msm_otg_add_pdev(
3420 struct platform_device *ofdev, const char *name)
3421{
3422 struct platform_device *pdev;
3423 const struct resource *res = ofdev->resource;
3424 unsigned int num = ofdev->num_resources;
3425 int retval;
3426
3427 pdev = platform_device_alloc(name, -1);
3428 if (!pdev) {
3429 retval = -ENOMEM;
3430 goto error;
3431 }
3432
3433 pdev->dev.coherent_dma_mask = DMA_BIT_MASK(32);
3434 pdev->dev.dma_mask = &msm_otg_dma_mask;
3435
3436 if (num) {
3437 retval = platform_device_add_resources(pdev, res, num);
3438 if (retval)
3439 goto error;
3440 }
3441
3442 retval = platform_device_add(pdev);
3443 if (retval)
3444 goto error;
3445
3446 return pdev;
3447
3448error:
3449 platform_device_put(pdev);
3450 return ERR_PTR(retval);
3451}
3452
3453static int msm_otg_setup_devices(struct platform_device *ofdev,
3454 enum usb_mode_type mode, bool init)
3455{
3456 const char *gadget_name = "msm_hsusb";
3457 const char *host_name = "msm_hsusb_host";
3458 static struct platform_device *gadget_pdev;
3459 static struct platform_device *host_pdev;
3460 int retval = 0;
3461
3462 if (!init) {
3463 if (gadget_pdev)
3464 platform_device_unregister(gadget_pdev);
3465 if (host_pdev)
3466 platform_device_unregister(host_pdev);
3467 return 0;
3468 }
3469
3470 switch (mode) {
3471 case USB_OTG:
3472 /* fall through */
3473 case USB_PERIPHERAL:
3474 gadget_pdev = msm_otg_add_pdev(ofdev, gadget_name);
3475 if (IS_ERR(gadget_pdev)) {
3476 retval = PTR_ERR(gadget_pdev);
3477 break;
3478 }
3479 if (mode == USB_PERIPHERAL)
3480 break;
3481 /* fall through */
3482 case USB_HOST:
3483 host_pdev = msm_otg_add_pdev(ofdev, host_name);
3484 if (IS_ERR(host_pdev)) {
3485 retval = PTR_ERR(host_pdev);
3486 if (mode == USB_OTG)
3487 platform_device_unregister(gadget_pdev);
3488 }
3489 break;
3490 default:
3491 break;
3492 }
3493
3494 return retval;
3495}
3496
3497struct msm_otg_platform_data *msm_otg_dt_to_pdata(struct platform_device *pdev)
3498{
3499 struct device_node *node = pdev->dev.of_node;
3500 struct msm_otg_platform_data *pdata;
3501 int len = 0;
3502
3503 pdata = devm_kzalloc(&pdev->dev, sizeof(*pdata), GFP_KERNEL);
3504 if (!pdata) {
3505 pr_err("unable to allocate platform data\n");
3506 return NULL;
3507 }
3508 of_get_property(node, "qcom,hsusb-otg-phy-init-seq", &len);
3509 if (len) {
3510 pdata->phy_init_seq = devm_kzalloc(&pdev->dev, len, GFP_KERNEL);
3511 if (!pdata->phy_init_seq)
3512 return NULL;
3513 of_property_read_u32_array(node, "qcom,hsusb-otg-phy-init-seq",
3514 pdata->phy_init_seq,
3515 len/sizeof(*pdata->phy_init_seq));
3516 }
3517 of_property_read_u32(node, "qcom,hsusb-otg-power-budget",
3518 &pdata->power_budget);
3519 of_property_read_u32(node, "qcom,hsusb-otg-mode",
3520 &pdata->mode);
3521 of_property_read_u32(node, "qcom,hsusb-otg-otg-control",
3522 &pdata->otg_control);
3523 of_property_read_u32(node, "qcom,hsusb-otg-default-mode",
3524 &pdata->default_mode);
3525 of_property_read_u32(node, "qcom,hsusb-otg-phy-type",
3526 &pdata->phy_type);
3527 of_property_read_u32(node, "qcom,hsusb-otg-pmic-id-irq",
3528 &pdata->pmic_id_irq);
Manu Gautambd53fba2012-07-31 16:13:06 +05303529 pdata->disable_reset_on_disconnect = of_property_read_bool(node,
3530 "qcom,hsusb-otg-disable-reset");
3531
Pavankumar Kondetieaea7fe2011-10-27 14:46:45 +05303532 return pdata;
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05303533}
3534
3535static int __init msm_otg_probe(struct platform_device *pdev)
3536{
Manu Gautamf8c45642012-08-10 10:20:56 -07003537 int ret = 0;
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05303538 struct resource *res;
3539 struct msm_otg *motg;
Heikki Krogerus1d4c9292012-02-13 13:24:09 +02003540 struct usb_phy *phy;
Pavankumar Kondetieaea7fe2011-10-27 14:46:45 +05303541 struct msm_otg_platform_data *pdata;
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05303542
3543 dev_info(&pdev->dev, "msm_otg probe\n");
Pavankumar Kondetieaea7fe2011-10-27 14:46:45 +05303544
3545 if (pdev->dev.of_node) {
3546 dev_dbg(&pdev->dev, "device tree enabled\n");
3547 pdata = msm_otg_dt_to_pdata(pdev);
3548 if (!pdata)
3549 return -ENOMEM;
Manu Gautam2e8ac102012-08-31 11:41:16 -07003550
3551 pdata->bus_scale_table = msm_bus_cl_get_pdata(pdev);
3552 if (!pdata->bus_scale_table)
3553 dev_dbg(&pdev->dev, "bus scaling is disabled\n");
3554
Pavankumar Kondetieaea7fe2011-10-27 14:46:45 +05303555 ret = msm_otg_setup_devices(pdev, pdata->mode, true);
3556 if (ret) {
3557 dev_err(&pdev->dev, "devices setup failed\n");
3558 return ret;
3559 }
3560 } else if (!pdev->dev.platform_data) {
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05303561 dev_err(&pdev->dev, "No platform data given. Bailing out\n");
3562 return -ENODEV;
Pavankumar Kondetieaea7fe2011-10-27 14:46:45 +05303563 } else {
3564 pdata = pdev->dev.platform_data;
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05303565 }
3566
3567 motg = kzalloc(sizeof(struct msm_otg), GFP_KERNEL);
3568 if (!motg) {
3569 dev_err(&pdev->dev, "unable to allocate msm_otg\n");
3570 return -ENOMEM;
3571 }
3572
Heikki Krogerus1d4c9292012-02-13 13:24:09 +02003573 motg->phy.otg = kzalloc(sizeof(struct usb_otg), GFP_KERNEL);
3574 if (!motg->phy.otg) {
Steve Mucklef132c6c2012-06-06 18:30:57 -07003575 dev_err(&pdev->dev, "unable to allocate usb_otg\n");
3576 ret = -ENOMEM;
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05303577 goto free_motg;
3578 }
3579
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003580 the_msm_otg = motg;
Pavankumar Kondetieaea7fe2011-10-27 14:46:45 +05303581 motg->pdata = pdata;
Steve Mucklef132c6c2012-06-06 18:30:57 -07003582 phy = &motg->phy;
3583 phy->dev = &pdev->dev;
Anji jonnala0f73cac2011-05-04 10:19:46 +05303584
3585 /*
Pavankumar Kondetiaa449e12011-11-04 11:09:26 +05303586 * ACA ID_GND threshold range is overlapped with OTG ID_FLOAT. Hence
3587 * PHY treat ACA ID_GND as float and no interrupt is generated. But
3588 * PMIC can detect ACA ID_GND and generate an interrupt.
3589 */
3590 if (aca_enabled() && motg->pdata->otg_control != OTG_PMIC_CONTROL) {
3591 dev_err(&pdev->dev, "ACA can not be enabled without PMIC\n");
3592 ret = -EINVAL;
Steve Mucklef132c6c2012-06-06 18:30:57 -07003593 goto free_otg;
Pavankumar Kondetiaa449e12011-11-04 11:09:26 +05303594 }
3595
Ofir Cohen4da266f2012-01-03 10:19:29 +02003596 /* initialize reset counter */
3597 motg->reset_counter = 0;
3598
Amit Blay02eff132011-09-21 16:46:24 +03003599 /* Some targets don't support PHY clock. */
Manu Gautam5143b252012-01-05 19:25:23 -08003600 motg->phy_reset_clk = clk_get(&pdev->dev, "phy_clk");
Amit Blay02eff132011-09-21 16:46:24 +03003601 if (IS_ERR(motg->phy_reset_clk))
Manu Gautam5143b252012-01-05 19:25:23 -08003602 dev_err(&pdev->dev, "failed to get phy_clk\n");
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05303603
Pavankumar Kondeti923262e2012-04-20 15:34:24 +05303604 /*
3605 * Targets on which link uses asynchronous reset methodology,
3606 * free running clock is not required during the reset.
3607 */
Manu Gautam5143b252012-01-05 19:25:23 -08003608 motg->clk = clk_get(&pdev->dev, "alt_core_clk");
Pavankumar Kondeti923262e2012-04-20 15:34:24 +05303609 if (IS_ERR(motg->clk))
3610 dev_dbg(&pdev->dev, "alt_core_clk is not present\n");
3611 else
3612 clk_set_rate(motg->clk, 60000000);
Anji jonnala0f73cac2011-05-04 10:19:46 +05303613
3614 /*
Manu Gautam5143b252012-01-05 19:25:23 -08003615 * USB Core is running its protocol engine based on CORE CLK,
Anji jonnala0f73cac2011-05-04 10:19:46 +05303616 * CORE CLK must be running at >55Mhz for correct HSUSB
3617 * operation and USB core cannot tolerate frequency changes on
3618 * CORE CLK. For such USB cores, vote for maximum clk frequency
3619 * on pclk source
3620 */
Manu Gautam5143b252012-01-05 19:25:23 -08003621 motg->core_clk = clk_get(&pdev->dev, "core_clk");
3622 if (IS_ERR(motg->core_clk)) {
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05303623 motg->core_clk = NULL;
Manu Gautam5143b252012-01-05 19:25:23 -08003624 dev_err(&pdev->dev, "failed to get core_clk\n");
Pavankumar Kondetibc541332012-04-20 15:32:04 +05303625 ret = PTR_ERR(motg->core_clk);
Manu Gautam5143b252012-01-05 19:25:23 -08003626 goto put_clk;
3627 }
3628 clk_set_rate(motg->core_clk, INT_MAX);
3629
3630 motg->pclk = clk_get(&pdev->dev, "iface_clk");
3631 if (IS_ERR(motg->pclk)) {
3632 dev_err(&pdev->dev, "failed to get iface_clk\n");
3633 ret = PTR_ERR(motg->pclk);
3634 goto put_core_clk;
3635 }
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05303636
3637 res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
3638 if (!res) {
3639 dev_err(&pdev->dev, "failed to get platform resource mem\n");
3640 ret = -ENODEV;
Manu Gautam5143b252012-01-05 19:25:23 -08003641 goto put_pclk;
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05303642 }
3643
3644 motg->regs = ioremap(res->start, resource_size(res));
3645 if (!motg->regs) {
3646 dev_err(&pdev->dev, "ioremap failed\n");
3647 ret = -ENOMEM;
Manu Gautam5143b252012-01-05 19:25:23 -08003648 goto put_pclk;
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05303649 }
3650 dev_info(&pdev->dev, "OTG regs = %p\n", motg->regs);
3651
3652 motg->irq = platform_get_irq(pdev, 0);
3653 if (!motg->irq) {
3654 dev_err(&pdev->dev, "platform_get_irq failed\n");
3655 ret = -ENODEV;
3656 goto free_regs;
3657 }
3658
Manu Gautamf8c45642012-08-10 10:20:56 -07003659 motg->async_irq = platform_get_irq_byname(pdev, "async_irq");
3660 if (motg->async_irq < 0) {
3661 dev_dbg(&pdev->dev, "platform_get_irq for async_int failed\n");
3662 motg->async_irq = 0;
3663 }
3664
Stephen Boyd30ad10b2012-03-01 14:51:04 -08003665 motg->xo_handle = msm_xo_get(MSM_XO_TCXO_D0, "usb");
Anji jonnala7da3f262011-12-02 17:22:14 -08003666 if (IS_ERR(motg->xo_handle)) {
3667 dev_err(&pdev->dev, "%s not able to get the handle "
3668 "to vote for TCXO D0 buffer\n", __func__);
3669 ret = PTR_ERR(motg->xo_handle);
3670 goto free_regs;
3671 }
Anji jonnala11aa5c42011-05-04 10:19:48 +05303672
Stephen Boyd30ad10b2012-03-01 14:51:04 -08003673 ret = msm_xo_mode_vote(motg->xo_handle, MSM_XO_MODE_ON);
Anji jonnala7da3f262011-12-02 17:22:14 -08003674 if (ret) {
3675 dev_err(&pdev->dev, "%s failed to vote for TCXO "
3676 "D0 buffer%d\n", __func__, ret);
3677 goto free_xo_handle;
3678 }
3679
Manu Gautam28b1bac2012-01-30 16:43:06 +05303680 clk_prepare_enable(motg->pclk);
Anji jonnala11aa5c42011-05-04 10:19:48 +05303681
Mayank Rana248698c2012-04-19 00:03:16 +05303682 motg->vdd_type = VDDCX_CORNER;
Steve Mucklef132c6c2012-06-06 18:30:57 -07003683 hsusb_vddcx = devm_regulator_get(motg->phy.dev, "hsusb_vdd_dig");
Mayank Rana248698c2012-04-19 00:03:16 +05303684 if (IS_ERR(hsusb_vddcx)) {
Steve Mucklef132c6c2012-06-06 18:30:57 -07003685 hsusb_vddcx = devm_regulator_get(motg->phy.dev, "HSUSB_VDDCX");
Mayank Rana248698c2012-04-19 00:03:16 +05303686 if (IS_ERR(hsusb_vddcx)) {
Steve Mucklef132c6c2012-06-06 18:30:57 -07003687 dev_err(motg->phy.dev, "unable to get hsusb vddcx\n");
Hemant Kumar41812392012-07-13 15:26:20 -07003688 ret = PTR_ERR(hsusb_vddcx);
Mayank Rana248698c2012-04-19 00:03:16 +05303689 goto devote_xo_handle;
3690 }
3691 motg->vdd_type = VDDCX;
Anji jonnala11aa5c42011-05-04 10:19:48 +05303692 }
3693
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003694 ret = msm_hsusb_config_vddcx(1);
Anji jonnala11aa5c42011-05-04 10:19:48 +05303695 if (ret) {
3696 dev_err(&pdev->dev, "hsusb vddcx configuration failed\n");
Mayank Rana248698c2012-04-19 00:03:16 +05303697 goto devote_xo_handle;
3698 }
3699
3700 ret = regulator_enable(hsusb_vddcx);
3701 if (ret) {
3702 dev_err(&pdev->dev, "unable to enable the hsusb vddcx\n");
3703 goto free_config_vddcx;
Anji jonnala11aa5c42011-05-04 10:19:48 +05303704 }
3705
3706 ret = msm_hsusb_ldo_init(motg, 1);
3707 if (ret) {
3708 dev_err(&pdev->dev, "hsusb vreg configuration failed\n");
Mayank Rana248698c2012-04-19 00:03:16 +05303709 goto free_hsusb_vddcx;
Anji jonnala11aa5c42011-05-04 10:19:48 +05303710 }
3711
Mayank Rana9e9a2ac2012-03-24 04:05:28 +05303712 if (pdata->mhl_enable) {
Pavankumar Kondeti56dc7422012-07-02 12:45:19 +05303713 mhl_usb_hs_switch = devm_regulator_get(motg->phy.dev,
3714 "mhl_usb_hs_switch");
3715 if (IS_ERR(mhl_usb_hs_switch)) {
3716 dev_err(&pdev->dev, "Unable to get mhl_usb_hs_switch\n");
Hemant Kumar41812392012-07-13 15:26:20 -07003717 ret = PTR_ERR(mhl_usb_hs_switch);
Mayank Rana9e9a2ac2012-03-24 04:05:28 +05303718 goto free_ldo_init;
3719 }
3720 }
3721
Amit Blay81801aa2012-09-19 12:08:12 +02003722 ret = msm_hsusb_ldo_enable(motg, USB_PHY_REG_ON);
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05303723 if (ret) {
3724 dev_err(&pdev->dev, "hsusb vreg enable failed\n");
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003725 goto free_ldo_init;
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05303726 }
Manu Gautam28b1bac2012-01-30 16:43:06 +05303727 clk_prepare_enable(motg->core_clk);
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05303728
3729 writel(0, USB_USBINTR);
3730 writel(0, USB_OTGSC);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003731 /* Ensure that above STOREs are completed before enabling interrupts */
3732 mb();
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05303733
Pavankumar Kondeti2aec9f32012-06-13 09:06:03 +05303734 ret = msm_otg_mhl_register_callback(motg, msm_otg_mhl_notify_online);
3735 if (ret)
3736 dev_dbg(&pdev->dev, "MHL can not be supported\n");
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003737 wake_lock_init(&motg->wlock, WAKE_LOCK_SUSPEND, "msm_otg");
Vijayavardhan Vennapusaa3152032012-03-05 16:29:30 +05303738 msm_otg_init_timer(motg);
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05303739 INIT_WORK(&motg->sm_work, msm_otg_sm_work);
Pavankumar Kondetid8608522011-05-04 10:19:47 +05303740 INIT_DELAYED_WORK(&motg->chg_work, msm_chg_detect_work);
Vijayavardhan Vennapusa68d55cf2012-06-27 20:06:12 +05303741 INIT_DELAYED_WORK(&motg->pmic_id_status_work, msm_pmic_id_status_w);
Amit Blayd0fe07b2012-09-05 16:42:09 +03003742 INIT_DELAYED_WORK(&motg->suspend_work, msm_otg_suspend_work);
Pavankumar Kondetiaa449e12011-11-04 11:09:26 +05303743 setup_timer(&motg->id_timer, msm_otg_id_timer_func,
3744 (unsigned long) motg);
Pavankumar Kondeti458d8792012-09-28 14:45:18 +05303745 setup_timer(&motg->chg_check_timer, msm_otg_chg_check_timer_func,
3746 (unsigned long) motg);
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05303747 ret = request_irq(motg->irq, msm_otg_irq, IRQF_SHARED,
3748 "msm_otg", motg);
3749 if (ret) {
3750 dev_err(&pdev->dev, "request irq failed\n");
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003751 goto destroy_wlock;
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05303752 }
3753
Manu Gautamf8c45642012-08-10 10:20:56 -07003754 if (motg->async_irq) {
3755 ret = request_irq(motg->async_irq, msm_otg_irq, IRQF_SHARED,
3756 "msm_otg", motg);
3757 if (ret) {
3758 dev_err(&pdev->dev, "request irq failed (ASYNC INT)\n");
3759 goto free_irq;
3760 }
3761 disable_irq(motg->async_irq);
3762 }
3763
Jack Pham87f202f2012-08-06 00:24:22 -07003764 if (pdata->otg_control == OTG_PHY_CONTROL && pdata->mpm_otgsessvld_int)
3765 msm_mpm_enable_pin(pdata->mpm_otgsessvld_int, 1);
3766
Heikki Krogerus1d4c9292012-02-13 13:24:09 +02003767 phy->init = msm_otg_reset;
3768 phy->set_power = msm_otg_set_power;
Steve Mucklef132c6c2012-06-06 18:30:57 -07003769 phy->set_suspend = msm_otg_set_suspend;
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05303770
Heikki Krogerus1d4c9292012-02-13 13:24:09 +02003771 phy->io_ops = &msm_otg_io_ops;
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05303772
Heikki Krogerus1d4c9292012-02-13 13:24:09 +02003773 phy->otg->phy = &motg->phy;
3774 phy->otg->set_host = msm_otg_set_host;
3775 phy->otg->set_peripheral = msm_otg_set_peripheral;
Steve Mucklef132c6c2012-06-06 18:30:57 -07003776 phy->otg->start_hnp = msm_otg_start_hnp;
3777 phy->otg->start_srp = msm_otg_start_srp;
Heikki Krogerus1d4c9292012-02-13 13:24:09 +02003778
3779 ret = usb_set_transceiver(&motg->phy);
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05303780 if (ret) {
Heikki Krogerus1d4c9292012-02-13 13:24:09 +02003781 dev_err(&pdev->dev, "usb_set_transceiver failed\n");
Manu Gautamf8c45642012-08-10 10:20:56 -07003782 goto free_async_irq;
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05303783 }
3784
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05303785 if (motg->pdata->mode == USB_OTG &&
Pavankumar Kondeti0d81f312012-01-13 11:34:10 +05303786 motg->pdata->otg_control == OTG_PMIC_CONTROL) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003787 if (motg->pdata->pmic_id_irq) {
3788 ret = request_irq(motg->pdata->pmic_id_irq,
3789 msm_pmic_id_irq,
3790 IRQF_TRIGGER_RISING |
3791 IRQF_TRIGGER_FALLING,
3792 "msm_otg", motg);
3793 if (ret) {
3794 dev_err(&pdev->dev, "request irq failed for PMIC ID\n");
Steve Mucklef132c6c2012-06-06 18:30:57 -07003795 goto remove_phy;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003796 }
3797 } else {
3798 ret = -ENODEV;
3799 dev_err(&pdev->dev, "PMIC IRQ for ID notifications doesn't exist\n");
Steve Mucklef132c6c2012-06-06 18:30:57 -07003800 goto remove_phy;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003801 }
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05303802 }
3803
Vijayavardhan Vennapusafc464f02011-11-04 21:54:00 +05303804 msm_hsusb_mhl_switch_enable(motg, 1);
3805
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05303806 platform_set_drvdata(pdev, motg);
3807 device_init_wakeup(&pdev->dev, 1);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003808 motg->mA_port = IUNIT;
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05303809
Anji jonnalad270e2d2011-08-09 11:28:32 +05303810 ret = msm_otg_debugfs_init(motg);
3811 if (ret)
3812 dev_dbg(&pdev->dev, "mode debugfs file is"
3813 "not available\n");
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05303814
Sridhar Parasuram3c67a412012-09-26 09:36:22 -07003815 if (motg->pdata->otg_control == OTG_PMIC_CONTROL)
3816 pm8921_charger_register_vbus_sn(&msm_otg_set_vbus_state);
3817
Amit Blay58b31472011-11-18 09:39:39 +02003818 if (motg->pdata->phy_type == SNPS_28NM_INTEGRATED_PHY) {
3819 if (motg->pdata->otg_control == OTG_PMIC_CONTROL &&
Pavankumar Kondeti0d81f312012-01-13 11:34:10 +05303820 (!(motg->pdata->mode == USB_OTG) ||
3821 motg->pdata->pmic_id_irq))
Amit Blay58b31472011-11-18 09:39:39 +02003822 motg->caps = ALLOW_PHY_POWER_COLLAPSE |
Vijayavardhan Vennapusa03171c72012-04-26 14:44:48 +05303823 ALLOW_PHY_RETENTION;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003824
Amit Blay58b31472011-11-18 09:39:39 +02003825 if (motg->pdata->otg_control == OTG_PHY_CONTROL)
Amit Blay81801aa2012-09-19 12:08:12 +02003826 motg->caps = ALLOW_PHY_RETENTION |
3827 ALLOW_PHY_REGULATORS_LPM;
Amit Blay58b31472011-11-18 09:39:39 +02003828 }
3829
Amit Blay6fa647a2012-05-24 14:12:08 +03003830 if (motg->pdata->enable_lpm_on_dev_suspend)
3831 motg->caps |= ALLOW_LPM_ON_DEV_SUSPEND;
3832
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003833 wake_lock(&motg->wlock);
Pavankumar Kondeti87c01042010-12-07 17:53:58 +05303834 pm_runtime_set_active(&pdev->dev);
Manu Gautamf8c45642012-08-10 10:20:56 -07003835 pm_runtime_enable(&pdev->dev);
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05303836
Manu Gautamcd82e9d2011-12-20 14:17:28 +05303837 if (motg->pdata->bus_scale_table) {
3838 motg->bus_perf_client =
3839 msm_bus_scale_register_client(motg->pdata->bus_scale_table);
3840 if (!motg->bus_perf_client)
Steve Mucklef132c6c2012-06-06 18:30:57 -07003841 dev_err(motg->phy.dev, "%s: Failed to register BUS "
Manu Gautamcd82e9d2011-12-20 14:17:28 +05303842 "scaling client!!\n", __func__);
Manu Gautam8bdcc592012-03-06 11:26:06 +05303843 else
3844 debug_bus_voting_enabled = true;
Manu Gautamcd82e9d2011-12-20 14:17:28 +05303845 }
3846
Pavankumar Kondeti87c01042010-12-07 17:53:58 +05303847 return 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003848
Steve Mucklef132c6c2012-06-06 18:30:57 -07003849remove_phy:
3850 usb_set_transceiver(NULL);
Manu Gautamf8c45642012-08-10 10:20:56 -07003851free_async_irq:
3852 if (motg->async_irq)
3853 free_irq(motg->async_irq, motg);
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05303854free_irq:
3855 free_irq(motg->irq, motg);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003856destroy_wlock:
3857 wake_lock_destroy(&motg->wlock);
Manu Gautam28b1bac2012-01-30 16:43:06 +05303858 clk_disable_unprepare(motg->core_clk);
Amit Blay81801aa2012-09-19 12:08:12 +02003859 msm_hsusb_ldo_enable(motg, USB_PHY_REG_OFF);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003860free_ldo_init:
Anji jonnala11aa5c42011-05-04 10:19:48 +05303861 msm_hsusb_ldo_init(motg, 0);
Mayank Rana248698c2012-04-19 00:03:16 +05303862free_hsusb_vddcx:
3863 regulator_disable(hsusb_vddcx);
3864free_config_vddcx:
3865 regulator_set_voltage(hsusb_vddcx,
3866 vdd_val[motg->vdd_type][VDD_NONE],
3867 vdd_val[motg->vdd_type][VDD_MAX]);
Anji jonnala7da3f262011-12-02 17:22:14 -08003868devote_xo_handle:
Manu Gautam28b1bac2012-01-30 16:43:06 +05303869 clk_disable_unprepare(motg->pclk);
Stephen Boyd30ad10b2012-03-01 14:51:04 -08003870 msm_xo_mode_vote(motg->xo_handle, MSM_XO_MODE_OFF);
Anji jonnala7da3f262011-12-02 17:22:14 -08003871free_xo_handle:
Stephen Boyd30ad10b2012-03-01 14:51:04 -08003872 msm_xo_put(motg->xo_handle);
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05303873free_regs:
3874 iounmap(motg->regs);
Manu Gautam5143b252012-01-05 19:25:23 -08003875put_pclk:
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05303876 clk_put(motg->pclk);
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05303877put_core_clk:
Manu Gautam5143b252012-01-05 19:25:23 -08003878 clk_put(motg->core_clk);
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05303879put_clk:
Pavankumar Kondeti923262e2012-04-20 15:34:24 +05303880 if (!IS_ERR(motg->clk))
3881 clk_put(motg->clk);
Amit Blay02eff132011-09-21 16:46:24 +03003882 if (!IS_ERR(motg->phy_reset_clk))
3883 clk_put(motg->phy_reset_clk);
Steve Mucklef132c6c2012-06-06 18:30:57 -07003884free_otg:
Heikki Krogerus1d4c9292012-02-13 13:24:09 +02003885 kfree(motg->phy.otg);
Pavankumar Kondetiaa449e12011-11-04 11:09:26 +05303886free_motg:
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05303887 kfree(motg);
3888 return ret;
3889}
3890
3891static int __devexit msm_otg_remove(struct platform_device *pdev)
3892{
3893 struct msm_otg *motg = platform_get_drvdata(pdev);
Steve Mucklef132c6c2012-06-06 18:30:57 -07003894 struct usb_otg *otg = motg->phy.otg;
Pavankumar Kondeti87c01042010-12-07 17:53:58 +05303895 int cnt = 0;
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05303896
3897 if (otg->host || otg->gadget)
3898 return -EBUSY;
3899
Pavankumar Kondetieaea7fe2011-10-27 14:46:45 +05303900 if (pdev->dev.of_node)
3901 msm_otg_setup_devices(pdev, motg->pdata->mode, false);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003902 if (motg->pdata->otg_control == OTG_PMIC_CONTROL)
3903 pm8921_charger_unregister_vbus_sn(0);
Pavankumar Kondeti2aec9f32012-06-13 09:06:03 +05303904 msm_otg_mhl_register_callback(motg, NULL);
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05303905 msm_otg_debugfs_cleanup();
Pavankumar Kondetid8608522011-05-04 10:19:47 +05303906 cancel_delayed_work_sync(&motg->chg_work);
Vijayavardhan Vennapusa68d55cf2012-06-27 20:06:12 +05303907 cancel_delayed_work_sync(&motg->pmic_id_status_work);
Amit Blayd0fe07b2012-09-05 16:42:09 +03003908 cancel_delayed_work_sync(&motg->suspend_work);
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05303909 cancel_work_sync(&motg->sm_work);
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05303910
Pavankumar Kondeti70187732011-02-15 09:42:34 +05303911 pm_runtime_resume(&pdev->dev);
Pavankumar Kondeti87c01042010-12-07 17:53:58 +05303912
3913 device_init_wakeup(&pdev->dev, 0);
3914 pm_runtime_disable(&pdev->dev);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003915 wake_lock_destroy(&motg->wlock);
Pavankumar Kondeti87c01042010-12-07 17:53:58 +05303916
Vijayavardhan Vennapusafc464f02011-11-04 21:54:00 +05303917 msm_hsusb_mhl_switch_enable(motg, 0);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003918 if (motg->pdata->pmic_id_irq)
3919 free_irq(motg->pdata->pmic_id_irq, motg);
Heikki Krogerus1d4c9292012-02-13 13:24:09 +02003920 usb_set_transceiver(NULL);
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05303921 free_irq(motg->irq, motg);
3922
Jack Pham87f202f2012-08-06 00:24:22 -07003923 if (motg->pdata->otg_control == OTG_PHY_CONTROL &&
3924 motg->pdata->mpm_otgsessvld_int)
3925 msm_mpm_enable_pin(motg->pdata->mpm_otgsessvld_int, 0);
3926
Pavankumar Kondeti87c01042010-12-07 17:53:58 +05303927 /*
3928 * Put PHY in low power mode.
3929 */
Steve Mucklef132c6c2012-06-06 18:30:57 -07003930 ulpi_read(otg->phy, 0x14);
3931 ulpi_write(otg->phy, 0x08, 0x09);
Pavankumar Kondeti87c01042010-12-07 17:53:58 +05303932
3933 writel(readl(USB_PORTSC) | PORTSC_PHCD, USB_PORTSC);
3934 while (cnt < PHY_SUSPEND_TIMEOUT_USEC) {
3935 if (readl(USB_PORTSC) & PORTSC_PHCD)
3936 break;
3937 udelay(1);
3938 cnt++;
3939 }
3940 if (cnt >= PHY_SUSPEND_TIMEOUT_USEC)
Steve Mucklef132c6c2012-06-06 18:30:57 -07003941 dev_err(otg->phy->dev, "Unable to suspend PHY\n");
Pavankumar Kondeti87c01042010-12-07 17:53:58 +05303942
Manu Gautam28b1bac2012-01-30 16:43:06 +05303943 clk_disable_unprepare(motg->pclk);
3944 clk_disable_unprepare(motg->core_clk);
Stephen Boyd30ad10b2012-03-01 14:51:04 -08003945 msm_xo_put(motg->xo_handle);
Amit Blay81801aa2012-09-19 12:08:12 +02003946 msm_hsusb_ldo_enable(motg, USB_PHY_REG_OFF);
Anji jonnala11aa5c42011-05-04 10:19:48 +05303947 msm_hsusb_ldo_init(motg, 0);
Mayank Rana248698c2012-04-19 00:03:16 +05303948 regulator_disable(hsusb_vddcx);
3949 regulator_set_voltage(hsusb_vddcx,
3950 vdd_val[motg->vdd_type][VDD_NONE],
3951 vdd_val[motg->vdd_type][VDD_MAX]);
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05303952
3953 iounmap(motg->regs);
Pavankumar Kondeti87c01042010-12-07 17:53:58 +05303954 pm_runtime_set_suspended(&pdev->dev);
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05303955
Amit Blay02eff132011-09-21 16:46:24 +03003956 if (!IS_ERR(motg->phy_reset_clk))
3957 clk_put(motg->phy_reset_clk);
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05303958 clk_put(motg->pclk);
Pavankumar Kondeti923262e2012-04-20 15:34:24 +05303959 if (!IS_ERR(motg->clk))
3960 clk_put(motg->clk);
Manu Gautam5143b252012-01-05 19:25:23 -08003961 clk_put(motg->core_clk);
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05303962
Manu Gautamcd82e9d2011-12-20 14:17:28 +05303963 if (motg->bus_perf_client)
3964 msm_bus_scale_unregister_client(motg->bus_perf_client);
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05303965
Heikki Krogerus1d4c9292012-02-13 13:24:09 +02003966 kfree(motg->phy.otg);
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05303967 kfree(motg);
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05303968 return 0;
3969}
3970
Pavankumar Kondeti87c01042010-12-07 17:53:58 +05303971#ifdef CONFIG_PM_RUNTIME
3972static int msm_otg_runtime_idle(struct device *dev)
3973{
3974 struct msm_otg *motg = dev_get_drvdata(dev);
Steve Mucklef132c6c2012-06-06 18:30:57 -07003975 struct usb_phy *phy = &motg->phy;
Pavankumar Kondeti87c01042010-12-07 17:53:58 +05303976
3977 dev_dbg(dev, "OTG runtime idle\n");
3978
Steve Mucklef132c6c2012-06-06 18:30:57 -07003979 if (phy->state == OTG_STATE_UNDEFINED)
Pavankumar Kondeti8be99cf2011-08-04 10:48:08 +05303980 return -EAGAIN;
3981 else
3982 return 0;
Pavankumar Kondeti87c01042010-12-07 17:53:58 +05303983}
3984
3985static int msm_otg_runtime_suspend(struct device *dev)
3986{
3987 struct msm_otg *motg = dev_get_drvdata(dev);
3988
3989 dev_dbg(dev, "OTG runtime suspend\n");
3990 return msm_otg_suspend(motg);
3991}
3992
3993static int msm_otg_runtime_resume(struct device *dev)
3994{
3995 struct msm_otg *motg = dev_get_drvdata(dev);
3996
3997 dev_dbg(dev, "OTG runtime resume\n");
Pavankumar Kondeti8be99cf2011-08-04 10:48:08 +05303998 pm_runtime_get_noresume(dev);
Pavankumar Kondeti87c01042010-12-07 17:53:58 +05303999 return msm_otg_resume(motg);
4000}
Pavankumar Kondeti87c01042010-12-07 17:53:58 +05304001#endif
4002
Pavankumar Kondeti70187732011-02-15 09:42:34 +05304003#ifdef CONFIG_PM_SLEEP
Pavankumar Kondeti87c01042010-12-07 17:53:58 +05304004static int msm_otg_pm_suspend(struct device *dev)
4005{
Jack Pham5ca279b2012-05-14 18:42:54 -07004006 int ret = 0;
Pavankumar Kondeti87c01042010-12-07 17:53:58 +05304007 struct msm_otg *motg = dev_get_drvdata(dev);
4008
4009 dev_dbg(dev, "OTG PM suspend\n");
Jack Pham5ca279b2012-05-14 18:42:54 -07004010
4011 atomic_set(&motg->pm_suspended, 1);
4012 ret = msm_otg_suspend(motg);
4013 if (ret)
4014 atomic_set(&motg->pm_suspended, 0);
4015
4016 return ret;
Pavankumar Kondeti87c01042010-12-07 17:53:58 +05304017}
4018
4019static int msm_otg_pm_resume(struct device *dev)
4020{
Jack Pham5ca279b2012-05-14 18:42:54 -07004021 int ret = 0;
Pavankumar Kondeti87c01042010-12-07 17:53:58 +05304022 struct msm_otg *motg = dev_get_drvdata(dev);
Pavankumar Kondeti87c01042010-12-07 17:53:58 +05304023
4024 dev_dbg(dev, "OTG PM resume\n");
4025
Jack Pham5ca279b2012-05-14 18:42:54 -07004026 atomic_set(&motg->pm_suspended, 0);
Jack Phamc7edb172012-08-13 15:32:39 -07004027 if (motg->async_int || motg->sm_work_pending) {
Jack Pham5ca279b2012-05-14 18:42:54 -07004028 pm_runtime_get_noresume(dev);
4029 ret = msm_otg_resume(motg);
Pavankumar Kondeti87c01042010-12-07 17:53:58 +05304030
Jack Pham5ca279b2012-05-14 18:42:54 -07004031 /* Update runtime PM status */
4032 pm_runtime_disable(dev);
4033 pm_runtime_set_active(dev);
4034 pm_runtime_enable(dev);
4035
Jack Phamc7edb172012-08-13 15:32:39 -07004036 if (motg->sm_work_pending) {
4037 motg->sm_work_pending = false;
4038 queue_work(system_nrt_wq, &motg->sm_work);
4039 }
Jack Pham5ca279b2012-05-14 18:42:54 -07004040 }
4041
4042 return ret;
Pavankumar Kondeti87c01042010-12-07 17:53:58 +05304043}
Pavankumar Kondeti87c01042010-12-07 17:53:58 +05304044#endif
4045
Pavankumar Kondeti70187732011-02-15 09:42:34 +05304046#ifdef CONFIG_PM
Pavankumar Kondeti87c01042010-12-07 17:53:58 +05304047static const struct dev_pm_ops msm_otg_dev_pm_ops = {
Pavankumar Kondeti70187732011-02-15 09:42:34 +05304048 SET_SYSTEM_SLEEP_PM_OPS(msm_otg_pm_suspend, msm_otg_pm_resume)
4049 SET_RUNTIME_PM_OPS(msm_otg_runtime_suspend, msm_otg_runtime_resume,
4050 msm_otg_runtime_idle)
Pavankumar Kondeti87c01042010-12-07 17:53:58 +05304051};
Pavankumar Kondeti70187732011-02-15 09:42:34 +05304052#endif
Pavankumar Kondeti87c01042010-12-07 17:53:58 +05304053
Pavankumar Kondetieaea7fe2011-10-27 14:46:45 +05304054static struct of_device_id msm_otg_dt_match[] = {
4055 { .compatible = "qcom,hsusb-otg",
4056 },
4057 {}
4058};
4059
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05304060static struct platform_driver msm_otg_driver = {
4061 .remove = __devexit_p(msm_otg_remove),
4062 .driver = {
4063 .name = DRIVER_NAME,
4064 .owner = THIS_MODULE,
Pavankumar Kondeti70187732011-02-15 09:42:34 +05304065#ifdef CONFIG_PM
Pavankumar Kondeti87c01042010-12-07 17:53:58 +05304066 .pm = &msm_otg_dev_pm_ops,
Pavankumar Kondeti70187732011-02-15 09:42:34 +05304067#endif
Pavankumar Kondetieaea7fe2011-10-27 14:46:45 +05304068 .of_match_table = msm_otg_dt_match,
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05304069 },
4070};
4071
4072static int __init msm_otg_init(void)
4073{
4074 return platform_driver_probe(&msm_otg_driver, msm_otg_probe);
4075}
4076
4077static void __exit msm_otg_exit(void)
4078{
4079 platform_driver_unregister(&msm_otg_driver);
4080}
4081
4082module_init(msm_otg_init);
4083module_exit(msm_otg_exit);
4084
4085MODULE_LICENSE("GPL v2");
4086MODULE_DESCRIPTION("MSM USB transceiver driver");