blob: 807a89db49fabcbaf61207c68fe847ce44d68f0f [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>
Amit Blay0f7edf72012-01-15 10:11:27 +020042#include <linux/power_supply.h>
Pavankumar Kondeti2aec9f32012-06-13 09:06:03 +053043#include <linux/mhl_8334.h>
jh.koo78df86f2012-09-04 20:13:19 +090044#include <linux/slimport.h>
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +053045
Devin Kimd10f03c2012-06-25 17:05:13 -070046#include <asm/mach-types.h>
47
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +053048#include <mach/clk.h>
Jack Pham87f202f2012-08-06 00:24:22 -070049#include <mach/mpm.h>
Anji jonnala7da3f262011-12-02 17:22:14 -080050#include <mach/msm_xo.h>
Manu Gautamcd82e9d2011-12-20 14:17:28 +053051#include <mach/msm_bus.h>
Mayank Rana248698c2012-04-19 00:03:16 +053052#include <mach/rpm-regulator.h>
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +053053
54#define MSM_USB_BASE (motg->regs)
55#define DRIVER_NAME "msm_otg"
56
Chiranjeevi Velempati489a27c2012-03-29 09:47:17 +053057#define ID_TIMER_FREQ (jiffies + msecs_to_jiffies(500))
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +053058#define ULPI_IO_TIMEOUT_USEC (10 * 1000)
Anji jonnala11aa5c42011-05-04 10:19:48 +053059#define USB_PHY_3P3_VOL_MIN 3050000 /* uV */
60#define USB_PHY_3P3_VOL_MAX 3300000 /* uV */
61#define USB_PHY_3P3_HPM_LOAD 50000 /* uA */
62#define USB_PHY_3P3_LPM_LOAD 4000 /* uA */
63
64#define USB_PHY_1P8_VOL_MIN 1800000 /* uV */
65#define USB_PHY_1P8_VOL_MAX 1800000 /* uV */
66#define USB_PHY_1P8_HPM_LOAD 50000 /* uA */
67#define USB_PHY_1P8_LPM_LOAD 4000 /* uA */
68
Mayank Rana248698c2012-04-19 00:03:16 +053069#define USB_PHY_VDD_DIG_VOL_NONE 0 /*uV */
Vamsi Krishna132b2762011-11-11 16:09:20 -080070#define USB_PHY_VDD_DIG_VOL_MIN 1045000 /* uV */
Anji jonnala11aa5c42011-05-04 10:19:48 +053071#define USB_PHY_VDD_DIG_VOL_MAX 1320000 /* uV */
72
Pavankumar Kondeti4960f312011-12-06 15:46:14 +053073static DECLARE_COMPLETION(pmic_vbus_init);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070074static struct msm_otg *the_msm_otg;
Pavankumar Kondetiaa449e12011-11-04 11:09:26 +053075static bool debug_aca_enabled;
Manu Gautam8bdcc592012-03-06 11:26:06 +053076static bool debug_bus_voting_enabled;
Pavankumar Kondeti2aec9f32012-06-13 09:06:03 +053077static bool mhl_det_in_progress;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070078
Anji jonnala11aa5c42011-05-04 10:19:48 +053079static struct regulator *hsusb_3p3;
80static struct regulator *hsusb_1p8;
81static struct regulator *hsusb_vddcx;
Mayank Ranae3926882011-12-26 09:47:54 +053082static struct regulator *vbus_otg;
Pavankumar Kondeti56dc7422012-07-02 12:45:19 +053083static struct regulator *mhl_usb_hs_switch;
Vijayavardhan Vennapusa05c437c2012-05-25 16:20:46 +053084static struct power_supply *psy;
Anji jonnala11aa5c42011-05-04 10:19:48 +053085
Pavankumar Kondeti4960f312011-12-06 15:46:14 +053086static bool aca_id_turned_on;
Pavankumar Kondetiaa449e12011-11-04 11:09:26 +053087static inline bool aca_enabled(void)
Anji jonnala11aa5c42011-05-04 10:19:48 +053088{
Pavankumar Kondetiaa449e12011-11-04 11:09:26 +053089#ifdef CONFIG_USB_MSM_ACA
90 return true;
91#else
92 return debug_aca_enabled;
93#endif
Anji jonnala11aa5c42011-05-04 10:19:48 +053094}
95
Mayank Rana248698c2012-04-19 00:03:16 +053096static const int vdd_val[VDD_TYPE_MAX][VDD_VAL_MAX] = {
97 { /* VDD_CX CORNER Voting */
98 [VDD_NONE] = RPM_VREG_CORNER_NONE,
99 [VDD_MIN] = RPM_VREG_CORNER_NOMINAL,
100 [VDD_MAX] = RPM_VREG_CORNER_HIGH,
101 },
102 { /* VDD_CX Voltage Voting */
103 [VDD_NONE] = USB_PHY_VDD_DIG_VOL_NONE,
104 [VDD_MIN] = USB_PHY_VDD_DIG_VOL_MIN,
105 [VDD_MAX] = USB_PHY_VDD_DIG_VOL_MAX,
106 },
107};
Anji jonnala11aa5c42011-05-04 10:19:48 +0530108
109static int msm_hsusb_ldo_init(struct msm_otg *motg, int init)
110{
111 int rc = 0;
112
113 if (init) {
Steve Mucklef132c6c2012-06-06 18:30:57 -0700114 hsusb_3p3 = devm_regulator_get(motg->phy.dev, "HSUSB_3p3");
Anji jonnala11aa5c42011-05-04 10:19:48 +0530115 if (IS_ERR(hsusb_3p3)) {
Heikki Krogerus1d4c9292012-02-13 13:24:09 +0200116 dev_err(motg->phy.dev, "unable to get hsusb 3p3\n");
Anji jonnala11aa5c42011-05-04 10:19:48 +0530117 return PTR_ERR(hsusb_3p3);
118 }
119
120 rc = regulator_set_voltage(hsusb_3p3, USB_PHY_3P3_VOL_MIN,
121 USB_PHY_3P3_VOL_MAX);
122 if (rc) {
Steve Mucklef132c6c2012-06-06 18:30:57 -0700123 dev_err(motg->phy.dev, "unable to set voltage level for"
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700124 "hsusb 3p3\n");
Mayank Rana9e9a2ac2012-03-24 04:05:28 +0530125 return rc;
Anji jonnala11aa5c42011-05-04 10:19:48 +0530126 }
Steve Mucklef132c6c2012-06-06 18:30:57 -0700127 hsusb_1p8 = devm_regulator_get(motg->phy.dev, "HSUSB_1p8");
Anji jonnala11aa5c42011-05-04 10:19:48 +0530128 if (IS_ERR(hsusb_1p8)) {
Heikki Krogerus1d4c9292012-02-13 13:24:09 +0200129 dev_err(motg->phy.dev, "unable to get hsusb 1p8\n");
Anji jonnala11aa5c42011-05-04 10:19:48 +0530130 rc = PTR_ERR(hsusb_1p8);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700131 goto put_3p3_lpm;
Anji jonnala11aa5c42011-05-04 10:19:48 +0530132 }
133 rc = regulator_set_voltage(hsusb_1p8, USB_PHY_1P8_VOL_MIN,
134 USB_PHY_1P8_VOL_MAX);
135 if (rc) {
Steve Mucklef132c6c2012-06-06 18:30:57 -0700136 dev_err(motg->phy.dev, "unable to set voltage level for"
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700137 "hsusb 1p8\n");
Anji jonnala11aa5c42011-05-04 10:19:48 +0530138 goto put_1p8;
139 }
140
141 return 0;
142 }
143
Anji jonnala11aa5c42011-05-04 10:19:48 +0530144put_1p8:
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700145 regulator_set_voltage(hsusb_1p8, 0, USB_PHY_1P8_VOL_MAX);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700146put_3p3_lpm:
147 regulator_set_voltage(hsusb_3p3, 0, USB_PHY_3P3_VOL_MAX);
Anji jonnala11aa5c42011-05-04 10:19:48 +0530148 return rc;
149}
150
Pavankumar Kondeti04aebcb2011-05-04 10:19:49 +0530151static int msm_hsusb_config_vddcx(int high)
152{
Mayank Rana248698c2012-04-19 00:03:16 +0530153 struct msm_otg *motg = the_msm_otg;
154 enum usb_vdd_type vdd_type = motg->vdd_type;
155 int max_vol = vdd_val[vdd_type][VDD_MAX];
Pavankumar Kondeti04aebcb2011-05-04 10:19:49 +0530156 int min_vol;
157 int ret;
158
Mayank Rana248698c2012-04-19 00:03:16 +0530159 min_vol = vdd_val[vdd_type][!!high];
Pavankumar Kondeti04aebcb2011-05-04 10:19:49 +0530160 ret = regulator_set_voltage(hsusb_vddcx, min_vol, max_vol);
161 if (ret) {
162 pr_err("%s: unable to set the voltage for regulator "
163 "HSUSB_VDDCX\n", __func__);
164 return ret;
165 }
166
167 pr_debug("%s: min_vol:%d max_vol:%d\n", __func__, min_vol, max_vol);
168
169 return ret;
170}
Pavankumar Kondeti04aebcb2011-05-04 10:19:49 +0530171
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700172static int msm_hsusb_ldo_enable(struct msm_otg *motg, int on)
Anji jonnala11aa5c42011-05-04 10:19:48 +0530173{
174 int ret = 0;
175
Pavankumar Kondeti68964c92011-10-27 14:58:56 +0530176 if (IS_ERR(hsusb_1p8)) {
Anji jonnala11aa5c42011-05-04 10:19:48 +0530177 pr_err("%s: HSUSB_1p8 is not initialized\n", __func__);
178 return -ENODEV;
179 }
180
Pavankumar Kondeti68964c92011-10-27 14:58:56 +0530181 if (IS_ERR(hsusb_3p3)) {
Anji jonnala11aa5c42011-05-04 10:19:48 +0530182 pr_err("%s: HSUSB_3p3 is not initialized\n", __func__);
183 return -ENODEV;
184 }
185
186 if (on) {
187 ret = regulator_set_optimum_mode(hsusb_1p8,
188 USB_PHY_1P8_HPM_LOAD);
189 if (ret < 0) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700190 pr_err("%s: Unable to set HPM of the regulator:"
Anji jonnala11aa5c42011-05-04 10:19:48 +0530191 "HSUSB_1p8\n", __func__);
192 return ret;
193 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700194
195 ret = regulator_enable(hsusb_1p8);
196 if (ret) {
Steve Mucklef132c6c2012-06-06 18:30:57 -0700197 dev_err(motg->phy.dev, "%s: unable to enable the hsusb 1p8\n",
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700198 __func__);
199 regulator_set_optimum_mode(hsusb_1p8, 0);
200 return ret;
201 }
202
Anji jonnala11aa5c42011-05-04 10:19:48 +0530203 ret = regulator_set_optimum_mode(hsusb_3p3,
204 USB_PHY_3P3_HPM_LOAD);
205 if (ret < 0) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700206 pr_err("%s: Unable to set HPM of the regulator:"
Anji jonnala11aa5c42011-05-04 10:19:48 +0530207 "HSUSB_3p3\n", __func__);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700208 regulator_set_optimum_mode(hsusb_1p8, 0);
209 regulator_disable(hsusb_1p8);
Anji jonnala11aa5c42011-05-04 10:19:48 +0530210 return ret;
211 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700212
213 ret = regulator_enable(hsusb_3p3);
214 if (ret) {
Steve Mucklef132c6c2012-06-06 18:30:57 -0700215 dev_err(motg->phy.dev, "%s: unable to enable the hsusb 3p3\n",
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700216 __func__);
217 regulator_set_optimum_mode(hsusb_3p3, 0);
218 regulator_set_optimum_mode(hsusb_1p8, 0);
219 regulator_disable(hsusb_1p8);
220 return ret;
221 }
222
Anji jonnala11aa5c42011-05-04 10:19:48 +0530223 } else {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700224 ret = regulator_disable(hsusb_1p8);
225 if (ret) {
Steve Mucklef132c6c2012-06-06 18:30:57 -0700226 dev_err(motg->phy.dev, "%s: unable to disable the hsusb 1p8\n",
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700227 __func__);
228 return ret;
229 }
230
231 ret = regulator_set_optimum_mode(hsusb_1p8, 0);
Anji jonnala11aa5c42011-05-04 10:19:48 +0530232 if (ret < 0)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700233 pr_err("%s: Unable to set LPM of the regulator:"
Anji jonnala11aa5c42011-05-04 10:19:48 +0530234 "HSUSB_1p8\n", __func__);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700235
236 ret = regulator_disable(hsusb_3p3);
237 if (ret) {
Steve Mucklef132c6c2012-06-06 18:30:57 -0700238 dev_err(motg->phy.dev, "%s: unable to disable the hsusb 3p3\n",
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700239 __func__);
240 return ret;
241 }
242 ret = regulator_set_optimum_mode(hsusb_3p3, 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_3p3\n", __func__);
246 }
247
248 pr_debug("reg (%s)\n", on ? "HPM" : "LPM");
249 return ret < 0 ? ret : 0;
250}
251
Vijayavardhan Vennapusafc464f02011-11-04 21:54:00 +0530252static void msm_hsusb_mhl_switch_enable(struct msm_otg *motg, bool on)
253{
Vijayavardhan Vennapusafc464f02011-11-04 21:54:00 +0530254 struct msm_otg_platform_data *pdata = motg->pdata;
255
256 if (!pdata->mhl_enable)
257 return;
258
Pavankumar Kondeti56dc7422012-07-02 12:45:19 +0530259 if (!mhl_usb_hs_switch) {
260 pr_err("%s: mhl_usb_hs_switch is NULL.\n", __func__);
Vijayavardhan Vennapusafc464f02011-11-04 21:54:00 +0530261 return;
262 }
263
Mayank Rana9e9a2ac2012-03-24 04:05:28 +0530264 if (on) {
Pavankumar Kondeti56dc7422012-07-02 12:45:19 +0530265 if (regulator_enable(mhl_usb_hs_switch))
266 pr_err("unable to enable mhl_usb_hs_switch\n");
Mayank Rana9e9a2ac2012-03-24 04:05:28 +0530267 } else {
Pavankumar Kondeti56dc7422012-07-02 12:45:19 +0530268 regulator_disable(mhl_usb_hs_switch);
Mayank Rana9e9a2ac2012-03-24 04:05:28 +0530269 }
Vijayavardhan Vennapusafc464f02011-11-04 21:54:00 +0530270}
271
Heikki Krogerus1d4c9292012-02-13 13:24:09 +0200272static int ulpi_read(struct usb_phy *phy, u32 reg)
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +0530273{
Heikki Krogerus1d4c9292012-02-13 13:24:09 +0200274 struct msm_otg *motg = container_of(phy, struct msm_otg, phy);
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +0530275 int cnt = 0;
276
277 /* initiate read operation */
278 writel(ULPI_RUN | ULPI_READ | ULPI_ADDR(reg),
279 USB_ULPI_VIEWPORT);
280
281 /* wait for completion */
282 while (cnt < ULPI_IO_TIMEOUT_USEC) {
283 if (!(readl(USB_ULPI_VIEWPORT) & ULPI_RUN))
284 break;
285 udelay(1);
286 cnt++;
287 }
288
289 if (cnt >= ULPI_IO_TIMEOUT_USEC) {
Heikki Krogerus1d4c9292012-02-13 13:24:09 +0200290 dev_err(phy->dev, "ulpi_read: timeout %08x\n",
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +0530291 readl(USB_ULPI_VIEWPORT));
292 return -ETIMEDOUT;
293 }
294 return ULPI_DATA_READ(readl(USB_ULPI_VIEWPORT));
295}
296
Heikki Krogerus1d4c9292012-02-13 13:24:09 +0200297static int ulpi_write(struct usb_phy *phy, u32 val, u32 reg)
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +0530298{
Heikki Krogerus1d4c9292012-02-13 13:24:09 +0200299 struct msm_otg *motg = container_of(phy, struct msm_otg, phy);
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +0530300 int cnt = 0;
301
302 /* initiate write operation */
303 writel(ULPI_RUN | ULPI_WRITE |
304 ULPI_ADDR(reg) | ULPI_DATA(val),
305 USB_ULPI_VIEWPORT);
306
307 /* wait for completion */
308 while (cnt < ULPI_IO_TIMEOUT_USEC) {
309 if (!(readl(USB_ULPI_VIEWPORT) & ULPI_RUN))
310 break;
311 udelay(1);
312 cnt++;
313 }
314
315 if (cnt >= ULPI_IO_TIMEOUT_USEC) {
Heikki Krogerus1d4c9292012-02-13 13:24:09 +0200316 dev_err(phy->dev, "ulpi_write: timeout\n");
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +0530317 return -ETIMEDOUT;
318 }
319 return 0;
320}
321
Heikki Krogerus1d4c9292012-02-13 13:24:09 +0200322static struct usb_phy_io_ops msm_otg_io_ops = {
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +0530323 .read = ulpi_read,
324 .write = ulpi_write,
325};
326
327static void ulpi_init(struct msm_otg *motg)
328{
329 struct msm_otg_platform_data *pdata = motg->pdata;
330 int *seq = pdata->phy_init_seq;
331
332 if (!seq)
333 return;
334
335 while (seq[0] >= 0) {
Heikki Krogerus1d4c9292012-02-13 13:24:09 +0200336 dev_vdbg(motg->phy.dev, "ulpi: write 0x%02x to 0x%02x\n",
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +0530337 seq[0], seq[1]);
Heikki Krogerus1d4c9292012-02-13 13:24:09 +0200338 ulpi_write(&motg->phy, seq[0], seq[1]);
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +0530339 seq += 2;
340 }
341}
342
343static int msm_otg_link_clk_reset(struct msm_otg *motg, bool assert)
344{
345 int ret;
346
347 if (assert) {
Manu Gautam5025ff12012-07-20 10:56:50 +0530348 if (!IS_ERR(motg->clk)) {
349 ret = clk_reset(motg->clk, CLK_RESET_ASSERT);
350 } else {
351 /* Using asynchronous block reset to the hardware */
352 dev_dbg(motg->phy.dev, "block_reset ASSERT\n");
353 clk_disable_unprepare(motg->pclk);
354 clk_disable_unprepare(motg->core_clk);
355 ret = clk_reset(motg->core_clk, CLK_RESET_ASSERT);
356 }
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +0530357 if (ret)
Heikki Krogerus1d4c9292012-02-13 13:24:09 +0200358 dev_err(motg->phy.dev, "usb hs_clk assert failed\n");
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +0530359 } else {
Manu Gautam5025ff12012-07-20 10:56:50 +0530360 if (!IS_ERR(motg->clk)) {
361 ret = clk_reset(motg->clk, CLK_RESET_DEASSERT);
362 } else {
363 dev_dbg(motg->phy.dev, "block_reset DEASSERT\n");
364 ret = clk_reset(motg->core_clk, CLK_RESET_DEASSERT);
365 ndelay(200);
366 clk_prepare_enable(motg->core_clk);
367 clk_prepare_enable(motg->pclk);
368 }
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +0530369 if (ret)
Heikki Krogerus1d4c9292012-02-13 13:24:09 +0200370 dev_err(motg->phy.dev, "usb hs_clk deassert failed\n");
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +0530371 }
372 return ret;
373}
374
375static int msm_otg_phy_clk_reset(struct msm_otg *motg)
376{
377 int ret;
378
Amit Blay02eff132011-09-21 16:46:24 +0300379 if (IS_ERR(motg->phy_reset_clk))
380 return 0;
381
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +0530382 ret = clk_reset(motg->phy_reset_clk, CLK_RESET_ASSERT);
383 if (ret) {
Heikki Krogerus1d4c9292012-02-13 13:24:09 +0200384 dev_err(motg->phy.dev, "usb phy clk assert failed\n");
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +0530385 return ret;
386 }
387 usleep_range(10000, 12000);
388 ret = clk_reset(motg->phy_reset_clk, CLK_RESET_DEASSERT);
389 if (ret)
Heikki Krogerus1d4c9292012-02-13 13:24:09 +0200390 dev_err(motg->phy.dev, "usb phy clk deassert failed\n");
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +0530391 return ret;
392}
393
394static int msm_otg_phy_reset(struct msm_otg *motg)
395{
396 u32 val;
397 int ret;
398 int retries;
399
400 ret = msm_otg_link_clk_reset(motg, 1);
401 if (ret)
402 return ret;
403 ret = msm_otg_phy_clk_reset(motg);
404 if (ret)
405 return ret;
406 ret = msm_otg_link_clk_reset(motg, 0);
407 if (ret)
408 return ret;
409
410 val = readl(USB_PORTSC) & ~PORTSC_PTS_MASK;
411 writel(val | PORTSC_PTS_ULPI, USB_PORTSC);
412
413 for (retries = 3; retries > 0; retries--) {
Heikki Krogerus1d4c9292012-02-13 13:24:09 +0200414 ret = ulpi_write(&motg->phy, ULPI_FUNC_CTRL_SUSPENDM,
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +0530415 ULPI_CLR(ULPI_FUNC_CTRL));
416 if (!ret)
417 break;
418 ret = msm_otg_phy_clk_reset(motg);
419 if (ret)
420 return ret;
421 }
422 if (!retries)
423 return -ETIMEDOUT;
424
425 /* This reset calibrates the phy, if the above write succeeded */
426 ret = msm_otg_phy_clk_reset(motg);
427 if (ret)
428 return ret;
429
430 for (retries = 3; retries > 0; retries--) {
Heikki Krogerus1d4c9292012-02-13 13:24:09 +0200431 ret = ulpi_read(&motg->phy, ULPI_DEBUG);
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +0530432 if (ret != -ETIMEDOUT)
433 break;
434 ret = msm_otg_phy_clk_reset(motg);
435 if (ret)
436 return ret;
437 }
438 if (!retries)
439 return -ETIMEDOUT;
440
Heikki Krogerus1d4c9292012-02-13 13:24:09 +0200441 dev_info(motg->phy.dev, "phy_reset: success\n");
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +0530442 return 0;
443}
444
445#define LINK_RESET_TIMEOUT_USEC (250 * 1000)
Pavankumar Kondetiaa449e12011-11-04 11:09:26 +0530446static int msm_otg_link_reset(struct msm_otg *motg)
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +0530447{
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +0530448 int cnt = 0;
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +0530449
Pavankumar Kondetiaa449e12011-11-04 11:09:26 +0530450 writel_relaxed(USBCMD_RESET, USB_USBCMD);
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +0530451 while (cnt < LINK_RESET_TIMEOUT_USEC) {
Pavankumar Kondetiaa449e12011-11-04 11:09:26 +0530452 if (!(readl_relaxed(USB_USBCMD) & USBCMD_RESET))
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +0530453 break;
454 udelay(1);
455 cnt++;
456 }
457 if (cnt >= LINK_RESET_TIMEOUT_USEC)
458 return -ETIMEDOUT;
459
460 /* select ULPI phy */
Pavankumar Kondetiaa449e12011-11-04 11:09:26 +0530461 writel_relaxed(0x80000000, USB_PORTSC);
462 writel_relaxed(0x0, USB_AHBBURST);
Vijayavardhan Vennapusa5f32d7a2012-03-14 16:30:26 +0530463 writel_relaxed(0x08, USB_AHBMODE);
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +0530464
Pavankumar Kondetiaa449e12011-11-04 11:09:26 +0530465 return 0;
466}
467
Steve Mucklef132c6c2012-06-06 18:30:57 -0700468static int msm_otg_reset(struct usb_phy *phy)
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +0530469{
Steve Mucklef132c6c2012-06-06 18:30:57 -0700470 struct msm_otg *motg = container_of(phy, struct msm_otg, phy);
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +0530471 struct msm_otg_platform_data *pdata = motg->pdata;
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +0530472 int ret;
473 u32 val = 0;
474 u32 ulpi_val = 0;
475
Ofir Cohen4da266f2012-01-03 10:19:29 +0200476 /*
477 * USB PHY and Link reset also reset the USB BAM.
478 * Thus perform reset operation only once to avoid
479 * USB BAM reset on other cases e.g. USB cable disconnections.
480 */
481 if (pdata->disable_reset_on_disconnect) {
482 if (motg->reset_counter)
483 return 0;
484 else
485 motg->reset_counter++;
486 }
487
Pavankumar Kondeti923262e2012-04-20 15:34:24 +0530488 if (!IS_ERR(motg->clk))
489 clk_prepare_enable(motg->clk);
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +0530490 ret = msm_otg_phy_reset(motg);
491 if (ret) {
Steve Mucklef132c6c2012-06-06 18:30:57 -0700492 dev_err(phy->dev, "phy_reset failed\n");
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +0530493 return ret;
494 }
495
Pavankumar Kondeti4960f312011-12-06 15:46:14 +0530496 aca_id_turned_on = false;
Pavankumar Kondetiaa449e12011-11-04 11:09:26 +0530497 ret = msm_otg_link_reset(motg);
498 if (ret) {
Steve Mucklef132c6c2012-06-06 18:30:57 -0700499 dev_err(phy->dev, "link reset failed\n");
Pavankumar Kondetiaa449e12011-11-04 11:09:26 +0530500 return ret;
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +0530501 }
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +0530502 msleep(100);
503
Anji jonnalaa8b8d732011-12-06 10:03:24 +0530504 ulpi_init(motg);
505
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700506 /* Ensure that RESET operation is completed before turning off clock */
507 mb();
Pavankumar Kondetiaa449e12011-11-04 11:09:26 +0530508
Pavankumar Kondeti923262e2012-04-20 15:34:24 +0530509 if (!IS_ERR(motg->clk))
510 clk_disable_unprepare(motg->clk);
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +0530511
512 if (pdata->otg_control == OTG_PHY_CONTROL) {
Pavankumar Kondeti4960f312011-12-06 15:46:14 +0530513 val = readl_relaxed(USB_OTGSC);
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +0530514 if (pdata->mode == USB_OTG) {
515 ulpi_val = ULPI_INT_IDGRD | ULPI_INT_SESS_VALID;
516 val |= OTGSC_IDIE | OTGSC_BSVIE;
517 } else if (pdata->mode == USB_PERIPHERAL) {
518 ulpi_val = ULPI_INT_SESS_VALID;
519 val |= OTGSC_BSVIE;
520 }
Pavankumar Kondeti4960f312011-12-06 15:46:14 +0530521 writel_relaxed(val, USB_OTGSC);
Heikki Krogerus1d4c9292012-02-13 13:24:09 +0200522 ulpi_write(phy, ulpi_val, ULPI_USB_INT_EN_RISE);
523 ulpi_write(phy, ulpi_val, ULPI_USB_INT_EN_FALL);
Pavankumar Kondeti446f4542012-02-01 13:57:13 +0530524 } else if (pdata->otg_control == OTG_PMIC_CONTROL) {
Steve Mucklef132c6c2012-06-06 18:30:57 -0700525 ulpi_write(phy, OTG_COMP_DISABLE,
Vijayavardhan Vennapusa03171c72012-04-26 14:44:48 +0530526 ULPI_SET(ULPI_PWR_CLK_MNG_REG));
Pavankumar Kondeti446f4542012-02-01 13:57:13 +0530527 /* Enable PMIC pull-up */
528 pm8xxx_usb_id_pullup(1);
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +0530529 }
530
531 return 0;
532}
533
Vijayavardhan Vennapusaa3152032012-03-05 16:29:30 +0530534static const char *timer_string(int bit)
535{
536 switch (bit) {
537 case A_WAIT_VRISE: return "a_wait_vrise";
538 case A_WAIT_VFALL: return "a_wait_vfall";
539 case B_SRP_FAIL: return "b_srp_fail";
540 case A_WAIT_BCON: return "a_wait_bcon";
541 case A_AIDL_BDIS: return "a_aidl_bdis";
542 case A_BIDL_ADIS: return "a_bidl_adis";
543 case B_ASE0_BRST: return "b_ase0_brst";
544 case A_TST_MAINT: return "a_tst_maint";
545 case B_TST_SRP: return "b_tst_srp";
546 case B_TST_CONFIG: return "b_tst_config";
547 default: return "UNDEFINED";
548 }
549}
550
551static enum hrtimer_restart msm_otg_timer_func(struct hrtimer *hrtimer)
552{
553 struct msm_otg *motg = container_of(hrtimer, struct msm_otg, timer);
554
555 switch (motg->active_tmout) {
556 case A_WAIT_VRISE:
557 /* TODO: use vbus_vld interrupt */
558 set_bit(A_VBUS_VLD, &motg->inputs);
559 break;
560 case A_TST_MAINT:
561 /* OTG PET: End session after TA_TST_MAINT */
562 set_bit(A_BUS_DROP, &motg->inputs);
563 break;
564 case B_TST_SRP:
565 /*
566 * OTG PET: Initiate SRP after TB_TST_SRP of
567 * previous session end.
568 */
569 set_bit(B_BUS_REQ, &motg->inputs);
570 break;
571 case B_TST_CONFIG:
572 clear_bit(A_CONN, &motg->inputs);
573 break;
574 default:
575 set_bit(motg->active_tmout, &motg->tmouts);
576 }
577
578 pr_debug("expired %s timer\n", timer_string(motg->active_tmout));
579 queue_work(system_nrt_wq, &motg->sm_work);
580 return HRTIMER_NORESTART;
581}
582
583static void msm_otg_del_timer(struct msm_otg *motg)
584{
585 int bit = motg->active_tmout;
586
587 pr_debug("deleting %s timer. remaining %lld msec\n", timer_string(bit),
588 div_s64(ktime_to_us(hrtimer_get_remaining(
589 &motg->timer)), 1000));
590 hrtimer_cancel(&motg->timer);
591 clear_bit(bit, &motg->tmouts);
592}
593
594static void msm_otg_start_timer(struct msm_otg *motg, int time, int bit)
595{
596 clear_bit(bit, &motg->tmouts);
597 motg->active_tmout = bit;
598 pr_debug("starting %s timer\n", timer_string(bit));
599 hrtimer_start(&motg->timer,
600 ktime_set(time / 1000, (time % 1000) * 1000000),
601 HRTIMER_MODE_REL);
602}
603
604static void msm_otg_init_timer(struct msm_otg *motg)
605{
606 hrtimer_init(&motg->timer, CLOCK_MONOTONIC, HRTIMER_MODE_REL);
607 motg->timer.function = msm_otg_timer_func;
608}
609
Steve Mucklef132c6c2012-06-06 18:30:57 -0700610static int msm_otg_start_hnp(struct usb_otg *otg)
Vijayavardhan Vennapusaa3152032012-03-05 16:29:30 +0530611{
Steve Mucklef132c6c2012-06-06 18:30:57 -0700612 struct msm_otg *motg = container_of(otg->phy, struct msm_otg, phy);
Vijayavardhan Vennapusaa3152032012-03-05 16:29:30 +0530613
Steve Mucklef132c6c2012-06-06 18:30:57 -0700614 if (otg->phy->state != OTG_STATE_A_HOST) {
Vijayavardhan Vennapusaa3152032012-03-05 16:29:30 +0530615 pr_err("HNP can not be initiated in %s state\n",
Steve Mucklef132c6c2012-06-06 18:30:57 -0700616 otg_state_string(otg->phy->state));
Vijayavardhan Vennapusaa3152032012-03-05 16:29:30 +0530617 return -EINVAL;
618 }
619
620 pr_debug("A-Host: HNP initiated\n");
621 clear_bit(A_BUS_REQ, &motg->inputs);
622 queue_work(system_nrt_wq, &motg->sm_work);
623 return 0;
624}
625
Steve Mucklef132c6c2012-06-06 18:30:57 -0700626static int msm_otg_start_srp(struct usb_otg *otg)
Vijayavardhan Vennapusaa3152032012-03-05 16:29:30 +0530627{
Steve Mucklef132c6c2012-06-06 18:30:57 -0700628 struct msm_otg *motg = container_of(otg->phy, struct msm_otg, phy);
Vijayavardhan Vennapusaa3152032012-03-05 16:29:30 +0530629 u32 val;
630 int ret = 0;
631
Steve Mucklef132c6c2012-06-06 18:30:57 -0700632 if (otg->phy->state != OTG_STATE_B_IDLE) {
Vijayavardhan Vennapusaa3152032012-03-05 16:29:30 +0530633 pr_err("SRP can not be initiated in %s state\n",
Steve Mucklef132c6c2012-06-06 18:30:57 -0700634 otg_state_string(otg->phy->state));
Vijayavardhan Vennapusaa3152032012-03-05 16:29:30 +0530635 ret = -EINVAL;
636 goto out;
637 }
638
639 if ((jiffies - motg->b_last_se0_sess) < msecs_to_jiffies(TB_SRP_INIT)) {
640 pr_debug("initial conditions of SRP are not met. Try again"
641 "after some time\n");
642 ret = -EAGAIN;
643 goto out;
644 }
645
646 pr_debug("B-Device SRP started\n");
647
648 /*
649 * PHY won't pull D+ high unless it detects Vbus valid.
650 * Since by definition, SRP is only done when Vbus is not valid,
651 * software work-around needs to be used to spoof the PHY into
652 * thinking it is valid. This can be done using the VBUSVLDEXTSEL and
653 * VBUSVLDEXT register bits.
654 */
Steve Mucklef132c6c2012-06-06 18:30:57 -0700655 ulpi_write(otg->phy, 0x03, 0x97);
Vijayavardhan Vennapusaa3152032012-03-05 16:29:30 +0530656 /*
657 * Harware auto assist data pulsing: Data pulse is given
658 * for 7msec; wait for vbus
659 */
660 val = readl_relaxed(USB_OTGSC);
661 writel_relaxed((val & ~OTGSC_INTSTS_MASK) | OTGSC_HADP, USB_OTGSC);
662
663 /* VBUS plusing is obsoleted in OTG 2.0 supplement */
664out:
665 return ret;
666}
667
Steve Mucklef132c6c2012-06-06 18:30:57 -0700668static void msm_otg_host_hnp_enable(struct usb_otg *otg, bool enable)
Vijayavardhan Vennapusaa3152032012-03-05 16:29:30 +0530669{
670 struct usb_hcd *hcd = bus_to_hcd(otg->host);
671 struct usb_device *rhub = otg->host->root_hub;
672
673 if (enable) {
674 pm_runtime_disable(&rhub->dev);
675 rhub->state = USB_STATE_NOTATTACHED;
676 hcd->driver->bus_suspend(hcd);
677 clear_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags);
678 } else {
679 usb_remove_hcd(hcd);
Steve Mucklef132c6c2012-06-06 18:30:57 -0700680 msm_otg_reset(otg->phy);
Vijayavardhan Vennapusaa3152032012-03-05 16:29:30 +0530681 usb_add_hcd(hcd, hcd->irq, IRQF_SHARED);
682 }
683}
684
Steve Mucklef132c6c2012-06-06 18:30:57 -0700685static int msm_otg_set_suspend(struct usb_phy *phy, int suspend)
Pavankumar Kondeti8be99cf2011-08-04 10:48:08 +0530686{
Steve Mucklef132c6c2012-06-06 18:30:57 -0700687 struct msm_otg *motg = container_of(phy, struct msm_otg, phy);
Pavankumar Kondeti8be99cf2011-08-04 10:48:08 +0530688
Amit Blay6fa647a2012-05-24 14:12:08 +0300689 if (aca_enabled())
Vijayavardhan Vennapusaa3152032012-03-05 16:29:30 +0530690 return 0;
Pavankumar Kondeti8be99cf2011-08-04 10:48:08 +0530691
Jack Pham69e621d2012-06-25 18:48:07 -0700692 if (atomic_read(&motg->in_lpm) == suspend)
693 return 0;
694
Vijayavardhan Vennapusaa3152032012-03-05 16:29:30 +0530695 if (suspend) {
Steve Mucklef132c6c2012-06-06 18:30:57 -0700696 switch (phy->state) {
Vijayavardhan Vennapusaa3152032012-03-05 16:29:30 +0530697 case OTG_STATE_A_WAIT_BCON:
698 if (TA_WAIT_BCON > 0)
699 break;
700 /* fall through */
701 case OTG_STATE_A_HOST:
702 pr_debug("host bus suspend\n");
703 clear_bit(A_BUS_REQ, &motg->inputs);
704 queue_work(system_nrt_wq, &motg->sm_work);
705 break;
Amit Blay6fa647a2012-05-24 14:12:08 +0300706 case OTG_STATE_B_PERIPHERAL:
707 pr_debug("peripheral bus suspend\n");
708 if (!(motg->caps & ALLOW_LPM_ON_DEV_SUSPEND))
709 break;
710 set_bit(A_BUS_SUSPEND, &motg->inputs);
711 queue_work(system_nrt_wq, &motg->sm_work);
712 break;
713
Vijayavardhan Vennapusaa3152032012-03-05 16:29:30 +0530714 default:
715 break;
716 }
717 } else {
Steve Mucklef132c6c2012-06-06 18:30:57 -0700718 switch (phy->state) {
Vijayavardhan Vennapusaa3152032012-03-05 16:29:30 +0530719 case OTG_STATE_A_SUSPEND:
720 /* Remote wakeup or resume */
721 set_bit(A_BUS_REQ, &motg->inputs);
Steve Mucklef132c6c2012-06-06 18:30:57 -0700722 phy->state = OTG_STATE_A_HOST;
Jack Pham5ca279b2012-05-14 18:42:54 -0700723
724 /* ensure hardware is not in low power mode */
Steve Mucklef132c6c2012-06-06 18:30:57 -0700725 pm_runtime_resume(phy->dev);
Vijayavardhan Vennapusaa3152032012-03-05 16:29:30 +0530726 break;
Amit Blay6fa647a2012-05-24 14:12:08 +0300727 case OTG_STATE_B_PERIPHERAL:
728 pr_debug("peripheral bus resume\n");
729 if (!(motg->caps & ALLOW_LPM_ON_DEV_SUSPEND))
730 break;
731 clear_bit(A_BUS_SUSPEND, &motg->inputs);
732 queue_work(system_nrt_wq, &motg->sm_work);
733 break;
Vijayavardhan Vennapusaa3152032012-03-05 16:29:30 +0530734 default:
735 break;
736 }
737 }
Pavankumar Kondeti8be99cf2011-08-04 10:48:08 +0530738 return 0;
739}
740
Pavankumar Kondeti87c01042010-12-07 17:53:58 +0530741#define PHY_SUSPEND_TIMEOUT_USEC (500 * 1000)
Pavankumar Kondeti70187732011-02-15 09:42:34 +0530742#define PHY_RESUME_TIMEOUT_USEC (100 * 1000)
743
744#ifdef CONFIG_PM_SLEEP
Pavankumar Kondeti87c01042010-12-07 17:53:58 +0530745static int msm_otg_suspend(struct msm_otg *motg)
746{
Heikki Krogerus1d4c9292012-02-13 13:24:09 +0200747 struct usb_phy *phy = &motg->phy;
748 struct usb_bus *bus = phy->otg->host;
Pavankumar Kondeti87c01042010-12-07 17:53:58 +0530749 struct msm_otg_platform_data *pdata = motg->pdata;
750 int cnt = 0;
Amit Blay6fa647a2012-05-24 14:12:08 +0300751 bool host_bus_suspend, device_bus_suspend, dcp;
Pavankumar Kondeti4960f312011-12-06 15:46:14 +0530752 u32 phy_ctrl_val = 0, cmd_val;
Stephen Boyd30ad10b2012-03-01 14:51:04 -0800753 unsigned ret;
Rajkumar Raghupathy242565d2011-12-13 12:10:59 +0530754 u32 portsc;
Pavankumar Kondeti87c01042010-12-07 17:53:58 +0530755
756 if (atomic_read(&motg->in_lpm))
757 return 0;
758
759 disable_irq(motg->irq);
Pavankumar Kondeti2aec9f32012-06-13 09:06:03 +0530760 host_bus_suspend = !test_bit(MHL, &motg->inputs) && phy->otg->host &&
761 !test_bit(ID, &motg->inputs);
Steve Mucklef132c6c2012-06-06 18:30:57 -0700762 device_bus_suspend = phy->otg->gadget && test_bit(ID, &motg->inputs) &&
Amit Blay6fa647a2012-05-24 14:12:08 +0300763 test_bit(A_BUS_SUSPEND, &motg->inputs) &&
764 motg->caps & ALLOW_LPM_ON_DEV_SUSPEND;
Pavankumar Kondeti283146f2012-01-12 12:51:19 +0530765 dcp = motg->chg_type == USB_DCP_CHARGER;
Pavankumar Kondeti87c01042010-12-07 17:53:58 +0530766 /*
Pavankumar Kondeti04aebcb2011-05-04 10:19:49 +0530767 * Chipidea 45-nm PHY suspend sequence:
768 *
Pavankumar Kondeti87c01042010-12-07 17:53:58 +0530769 * Interrupt Latch Register auto-clear feature is not present
770 * in all PHY versions. Latch register is clear on read type.
771 * Clear latch register to avoid spurious wakeup from
772 * low power mode (LPM).
Pavankumar Kondeti04aebcb2011-05-04 10:19:49 +0530773 *
Pavankumar Kondeti87c01042010-12-07 17:53:58 +0530774 * PHY comparators are disabled when PHY enters into low power
775 * mode (LPM). Keep PHY comparators ON in LPM only when we expect
776 * VBUS/Id notifications from USB PHY. Otherwise turn off USB
777 * PHY comparators. This save significant amount of power.
Pavankumar Kondeti04aebcb2011-05-04 10:19:49 +0530778 *
Pavankumar Kondeti87c01042010-12-07 17:53:58 +0530779 * PLL is not turned off when PHY enters into low power mode (LPM).
780 * Disable PLL for maximum power savings.
781 */
Pavankumar Kondeti04aebcb2011-05-04 10:19:49 +0530782
783 if (motg->pdata->phy_type == CI_45NM_INTEGRATED_PHY) {
Heikki Krogerus1d4c9292012-02-13 13:24:09 +0200784 ulpi_read(phy, 0x14);
Pavankumar Kondeti04aebcb2011-05-04 10:19:49 +0530785 if (pdata->otg_control == OTG_PHY_CONTROL)
Heikki Krogerus1d4c9292012-02-13 13:24:09 +0200786 ulpi_write(phy, 0x01, 0x30);
787 ulpi_write(phy, 0x08, 0x09);
Pavankumar Kondeti04aebcb2011-05-04 10:19:49 +0530788 }
Pavankumar Kondeti87c01042010-12-07 17:53:58 +0530789
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700790
Rajkumar Raghupathy242565d2011-12-13 12:10:59 +0530791 /* Set the PHCD bit, only if it is not set by the controller.
Pavankumar Kondeti87c01042010-12-07 17:53:58 +0530792 * PHY may take some time or even fail to enter into low power
793 * mode (LPM). Hence poll for 500 msec and reset the PHY and link
794 * in failure case.
795 */
Rajkumar Raghupathy242565d2011-12-13 12:10:59 +0530796 portsc = readl_relaxed(USB_PORTSC);
797 if (!(portsc & PORTSC_PHCD)) {
798 writel_relaxed(portsc | PORTSC_PHCD,
799 USB_PORTSC);
800 while (cnt < PHY_SUSPEND_TIMEOUT_USEC) {
801 if (readl_relaxed(USB_PORTSC) & PORTSC_PHCD)
802 break;
803 udelay(1);
804 cnt++;
805 }
Pavankumar Kondeti87c01042010-12-07 17:53:58 +0530806 }
807
808 if (cnt >= PHY_SUSPEND_TIMEOUT_USEC) {
Heikki Krogerus1d4c9292012-02-13 13:24:09 +0200809 dev_err(phy->dev, "Unable to suspend PHY\n");
810 msm_otg_reset(phy);
Pavankumar Kondeti87c01042010-12-07 17:53:58 +0530811 enable_irq(motg->irq);
812 return -ETIMEDOUT;
813 }
814
815 /*
816 * PHY has capability to generate interrupt asynchronously in low
817 * power mode (LPM). This interrupt is level triggered. So USB IRQ
818 * line must be disabled till async interrupt enable bit is cleared
819 * in USBCMD register. Assert STP (ULPI interface STOP signal) to
820 * block data communication from PHY.
Pavankumar Kondeti6be675f2012-04-16 13:29:24 +0530821 *
822 * PHY retention mode is disallowed while entering to LPM with wall
823 * charger connected. But PHY is put into suspend mode. Hence
824 * enable asynchronous interrupt to detect charger disconnection when
825 * PMIC notifications are unavailable.
Pavankumar Kondeti87c01042010-12-07 17:53:58 +0530826 */
Pavankumar Kondeti4960f312011-12-06 15:46:14 +0530827 cmd_val = readl_relaxed(USB_USBCMD);
Amit Blay6fa647a2012-05-24 14:12:08 +0300828 if (host_bus_suspend || device_bus_suspend ||
829 (motg->pdata->otg_control == OTG_PHY_CONTROL && dcp))
Pavankumar Kondeti4960f312011-12-06 15:46:14 +0530830 cmd_val |= ASYNC_INTR_CTRL | ULPI_STP_CTRL;
831 else
832 cmd_val |= ULPI_STP_CTRL;
833 writel_relaxed(cmd_val, USB_USBCMD);
Pavankumar Kondeti87c01042010-12-07 17:53:58 +0530834
Pavankumar Kondeti283146f2012-01-12 12:51:19 +0530835 /*
836 * BC1.2 spec mandates PD to enable VDP_SRC when charging from DCP.
837 * PHY retention and collapse can not happen with VDP_SRC enabled.
838 */
Amit Blay6fa647a2012-05-24 14:12:08 +0300839 if (motg->caps & ALLOW_PHY_RETENTION && !host_bus_suspend &&
840 !device_bus_suspend && !dcp) {
Amit Blay58b31472011-11-18 09:39:39 +0200841 phy_ctrl_val = readl_relaxed(USB_PHY_CTRL);
842 if (motg->pdata->otg_control == OTG_PHY_CONTROL)
843 /* Enable PHY HV interrupts to wake MPM/Link */
844 phy_ctrl_val |=
845 (PHY_IDHV_INTEN | PHY_OTGSESSVLDHV_INTEN);
Pavankumar Kondeti04aebcb2011-05-04 10:19:49 +0530846
Amit Blay58b31472011-11-18 09:39:39 +0200847 writel_relaxed(phy_ctrl_val & ~PHY_RETEN, USB_PHY_CTRL);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700848 motg->lpm_flags |= PHY_RETENTIONED;
Pavankumar Kondeti04aebcb2011-05-04 10:19:49 +0530849 }
850
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700851 /* Ensure that above operation is completed before turning off clocks */
852 mb();
Ido Shayevitzc5c0f572012-07-31 13:58:45 +0300853 /* Consider clocks on workaround flag only in case of bus suspend */
854 if (!(phy->state == OTG_STATE_B_PERIPHERAL &&
855 test_bit(A_BUS_SUSPEND, &motg->inputs)) ||
856 !motg->pdata->core_clk_always_on_workaround) {
Amit Blay9b6e58b2012-06-18 13:12:49 +0300857 clk_disable_unprepare(motg->pclk);
858 clk_disable_unprepare(motg->core_clk);
Ido Shayevitzc5c0f572012-07-31 13:58:45 +0300859 motg->lpm_flags |= CLOCKS_DOWN;
Amit Blay9b6e58b2012-06-18 13:12:49 +0300860 }
Pavankumar Kondeti87c01042010-12-07 17:53:58 +0530861
Anji jonnala7da3f262011-12-02 17:22:14 -0800862 /* usb phy no more require TCXO clock, hence vote for TCXO disable */
Vijayavardhan Vennapusabbdd6082012-06-06 14:14:25 +0530863 if (!host_bus_suspend) {
864 ret = msm_xo_mode_vote(motg->xo_handle, MSM_XO_MODE_OFF);
865 if (ret)
Steve Muckle75c34ca2012-06-12 14:27:40 -0700866 dev_err(phy->dev, "%s failed to devote for "
Vijayavardhan Vennapusabbdd6082012-06-06 14:14:25 +0530867 "TCXO D0 buffer%d\n", __func__, ret);
868 else
869 motg->lpm_flags |= XO_SHUTDOWN;
870 }
Anji jonnala7da3f262011-12-02 17:22:14 -0800871
Pavankumar Kondeti283146f2012-01-12 12:51:19 +0530872 if (motg->caps & ALLOW_PHY_POWER_COLLAPSE &&
873 !host_bus_suspend && !dcp) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700874 msm_hsusb_ldo_enable(motg, 0);
875 motg->lpm_flags |= PHY_PWR_COLLAPSED;
Anji jonnala0f73cac2011-05-04 10:19:46 +0530876 }
877
Vijayavardhan Vennapusafc464f02011-11-04 21:54:00 +0530878 if (motg->lpm_flags & PHY_RETENTIONED) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700879 msm_hsusb_config_vddcx(0);
Vijayavardhan Vennapusafc464f02011-11-04 21:54:00 +0530880 msm_hsusb_mhl_switch_enable(motg, 0);
881 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700882
Steve Mucklef132c6c2012-06-06 18:30:57 -0700883 if (device_may_wakeup(phy->dev)) {
Pavankumar Kondeti87c01042010-12-07 17:53:58 +0530884 enable_irq_wake(motg->irq);
Manu Gautamf8c45642012-08-10 10:20:56 -0700885 if (motg->async_irq)
886 enable_irq_wake(motg->async_irq);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700887 if (motg->pdata->pmic_id_irq)
888 enable_irq_wake(motg->pdata->pmic_id_irq);
Jack Pham87f202f2012-08-06 00:24:22 -0700889 if (pdata->otg_control == OTG_PHY_CONTROL &&
890 pdata->mpm_otgsessvld_int)
891 msm_mpm_set_pin_wake(pdata->mpm_otgsessvld_int, 1);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700892 }
Pavankumar Kondeti87c01042010-12-07 17:53:58 +0530893 if (bus)
894 clear_bit(HCD_FLAG_HW_ACCESSIBLE, &(bus_to_hcd(bus))->flags);
895
896 atomic_set(&motg->in_lpm, 1);
Manu Gautamf8c45642012-08-10 10:20:56 -0700897 /* Enable ASYNC IRQ (if present) during LPM */
898 if (motg->async_irq)
899 enable_irq(motg->async_irq);
Pavankumar Kondeti87c01042010-12-07 17:53:58 +0530900 enable_irq(motg->irq);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700901 wake_unlock(&motg->wlock);
Pavankumar Kondeti87c01042010-12-07 17:53:58 +0530902
Heikki Krogerus1d4c9292012-02-13 13:24:09 +0200903 dev_info(phy->dev, "USB in low power mode\n");
Pavankumar Kondeti87c01042010-12-07 17:53:58 +0530904
905 return 0;
906}
907
Pavankumar Kondeti87c01042010-12-07 17:53:58 +0530908static int msm_otg_resume(struct msm_otg *motg)
909{
Heikki Krogerus1d4c9292012-02-13 13:24:09 +0200910 struct usb_phy *phy = &motg->phy;
911 struct usb_bus *bus = phy->otg->host;
Jack Pham87f202f2012-08-06 00:24:22 -0700912 struct msm_otg_platform_data *pdata = motg->pdata;
Pavankumar Kondeti87c01042010-12-07 17:53:58 +0530913 int cnt = 0;
914 unsigned temp;
Amit Blay58b31472011-11-18 09:39:39 +0200915 u32 phy_ctrl_val = 0;
Anji jonnala7da3f262011-12-02 17:22:14 -0800916 unsigned ret;
Pavankumar Kondeti87c01042010-12-07 17:53:58 +0530917
918 if (!atomic_read(&motg->in_lpm))
919 return 0;
920
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700921 wake_lock(&motg->wlock);
Anji jonnala0f73cac2011-05-04 10:19:46 +0530922
Anji jonnala7da3f262011-12-02 17:22:14 -0800923 /* Vote for TCXO when waking up the phy */
Vijayavardhan Vennapusabbdd6082012-06-06 14:14:25 +0530924 if (motg->lpm_flags & XO_SHUTDOWN) {
925 ret = msm_xo_mode_vote(motg->xo_handle, MSM_XO_MODE_ON);
926 if (ret)
Steve Muckle75c34ca2012-06-12 14:27:40 -0700927 dev_err(phy->dev, "%s failed to vote for "
Vijayavardhan Vennapusabbdd6082012-06-06 14:14:25 +0530928 "TCXO D0 buffer%d\n", __func__, ret);
929 motg->lpm_flags &= ~XO_SHUTDOWN;
930 }
Pavankumar Kondeti87c01042010-12-07 17:53:58 +0530931
Ido Shayevitzc5c0f572012-07-31 13:58:45 +0300932 if (motg->lpm_flags & CLOCKS_DOWN) {
Amit Blay9b6e58b2012-06-18 13:12:49 +0300933 clk_prepare_enable(motg->core_clk);
934 clk_prepare_enable(motg->pclk);
Ido Shayevitzc5c0f572012-07-31 13:58:45 +0300935 motg->lpm_flags &= ~CLOCKS_DOWN;
Amit Blay9b6e58b2012-06-18 13:12:49 +0300936 }
Pavankumar Kondeti87c01042010-12-07 17:53:58 +0530937
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700938 if (motg->lpm_flags & PHY_PWR_COLLAPSED) {
939 msm_hsusb_ldo_enable(motg, 1);
940 motg->lpm_flags &= ~PHY_PWR_COLLAPSED;
941 }
942
943 if (motg->lpm_flags & PHY_RETENTIONED) {
Vijayavardhan Vennapusafc464f02011-11-04 21:54:00 +0530944 msm_hsusb_mhl_switch_enable(motg, 1);
Pavankumar Kondeti04aebcb2011-05-04 10:19:49 +0530945 msm_hsusb_config_vddcx(1);
Amit Blay58b31472011-11-18 09:39:39 +0200946 phy_ctrl_val = readl_relaxed(USB_PHY_CTRL);
947 phy_ctrl_val |= PHY_RETEN;
948 if (motg->pdata->otg_control == OTG_PHY_CONTROL)
949 /* Disable PHY HV interrupts */
950 phy_ctrl_val &=
951 ~(PHY_IDHV_INTEN | PHY_OTGSESSVLDHV_INTEN);
952 writel_relaxed(phy_ctrl_val, USB_PHY_CTRL);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700953 motg->lpm_flags &= ~PHY_RETENTIONED;
Pavankumar Kondeti04aebcb2011-05-04 10:19:49 +0530954 }
955
Pavankumar Kondeti87c01042010-12-07 17:53:58 +0530956 temp = readl(USB_USBCMD);
957 temp &= ~ASYNC_INTR_CTRL;
958 temp &= ~ULPI_STP_CTRL;
959 writel(temp, USB_USBCMD);
960
961 /*
962 * PHY comes out of low power mode (LPM) in case of wakeup
963 * from asynchronous interrupt.
964 */
965 if (!(readl(USB_PORTSC) & PORTSC_PHCD))
966 goto skip_phy_resume;
967
968 writel(readl(USB_PORTSC) & ~PORTSC_PHCD, USB_PORTSC);
969 while (cnt < PHY_RESUME_TIMEOUT_USEC) {
970 if (!(readl(USB_PORTSC) & PORTSC_PHCD))
971 break;
972 udelay(1);
973 cnt++;
974 }
975
976 if (cnt >= PHY_RESUME_TIMEOUT_USEC) {
977 /*
978 * This is a fatal error. Reset the link and
979 * PHY. USB state can not be restored. Re-insertion
980 * of USB cable is the only way to get USB working.
981 */
Heikki Krogerus1d4c9292012-02-13 13:24:09 +0200982 dev_err(phy->dev, "Unable to resume USB."
Pavankumar Kondeti87c01042010-12-07 17:53:58 +0530983 "Re-plugin the cable\n");
Heikki Krogerus1d4c9292012-02-13 13:24:09 +0200984 msm_otg_reset(phy);
Pavankumar Kondeti87c01042010-12-07 17:53:58 +0530985 }
986
987skip_phy_resume:
Steve Mucklef132c6c2012-06-06 18:30:57 -0700988 if (device_may_wakeup(phy->dev)) {
Pavankumar Kondeti87c01042010-12-07 17:53:58 +0530989 disable_irq_wake(motg->irq);
Manu Gautamf8c45642012-08-10 10:20:56 -0700990 if (motg->async_irq)
991 disable_irq_wake(motg->async_irq);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700992 if (motg->pdata->pmic_id_irq)
993 disable_irq_wake(motg->pdata->pmic_id_irq);
Jack Pham87f202f2012-08-06 00:24:22 -0700994 if (pdata->otg_control == OTG_PHY_CONTROL &&
995 pdata->mpm_otgsessvld_int)
996 msm_mpm_set_pin_wake(pdata->mpm_otgsessvld_int, 0);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700997 }
Pavankumar Kondeti87c01042010-12-07 17:53:58 +0530998 if (bus)
999 set_bit(HCD_FLAG_HW_ACCESSIBLE, &(bus_to_hcd(bus))->flags);
1000
Pavankumar Kondeti2ce2c3a2011-05-02 11:56:33 +05301001 atomic_set(&motg->in_lpm, 0);
1002
Pavankumar Kondeti87c01042010-12-07 17:53:58 +05301003 if (motg->async_int) {
Manu Gautamf8c45642012-08-10 10:20:56 -07001004 /* Match the disable_irq call from ISR */
1005 enable_irq(motg->async_int);
Pavankumar Kondeti87c01042010-12-07 17:53:58 +05301006 motg->async_int = 0;
Pavankumar Kondeti87c01042010-12-07 17:53:58 +05301007 }
1008
Manu Gautamf8c45642012-08-10 10:20:56 -07001009 /* If ASYNC IRQ is present then keep it enabled only during LPM */
1010 if (motg->async_irq)
1011 disable_irq(motg->async_irq);
1012
Heikki Krogerus1d4c9292012-02-13 13:24:09 +02001013 dev_info(phy->dev, "USB exited from low power mode\n");
Pavankumar Kondeti87c01042010-12-07 17:53:58 +05301014
1015 return 0;
1016}
Pavankumar Kondeti70187732011-02-15 09:42:34 +05301017#endif
Pavankumar Kondeti87c01042010-12-07 17:53:58 +05301018
Abhijeet Dharmapurikar5e96aaa2012-06-26 11:21:03 -07001019static int msm_otg_notify_host_mode(struct msm_otg *motg, bool host_mode)
1020{
1021 if (!psy)
1022 goto psy_not_supported;
1023
1024 if (host_mode)
1025 power_supply_set_scope(psy, POWER_SUPPLY_SCOPE_SYSTEM);
1026 else
1027 power_supply_set_scope(psy, POWER_SUPPLY_SCOPE_DEVICE);
1028
1029psy_not_supported:
1030 dev_dbg(motg->phy.dev, "Power Supply doesn't support USB charger\n");
1031 return -ENXIO;
1032}
1033
David Keitel081a3e22012-04-18 12:37:07 -07001034static int msm_otg_notify_chg_type(struct msm_otg *motg)
1035{
roy.parkd063ef32012-08-30 09:37:38 -07001036 int charger_type;
David Keitel081a3e22012-04-18 12:37:07 -07001037 /*
1038 * TODO
1039 * Unify OTG driver charger types and power supply charger types
1040 */
David Keitel081a3e22012-04-18 12:37:07 -07001041
1042 if (motg->chg_type == USB_SDP_CHARGER)
1043 charger_type = POWER_SUPPLY_TYPE_USB;
1044 else if (motg->chg_type == USB_CDP_CHARGER)
1045 charger_type = POWER_SUPPLY_TYPE_USB_CDP;
Pavankumar Kondeti9ec21d32012-05-07 15:50:23 +05301046 else if (motg->chg_type == USB_DCP_CHARGER ||
1047 motg->chg_type == USB_PROPRIETARY_CHARGER)
David Keitel081a3e22012-04-18 12:37:07 -07001048 charger_type = POWER_SUPPLY_TYPE_USB_DCP;
1049 else if ((motg->chg_type == USB_ACA_DOCK_CHARGER ||
1050 motg->chg_type == USB_ACA_A_CHARGER ||
1051 motg->chg_type == USB_ACA_B_CHARGER ||
1052 motg->chg_type == USB_ACA_C_CHARGER))
1053 charger_type = POWER_SUPPLY_TYPE_USB_ACA;
1054 else
1055 charger_type = POWER_SUPPLY_TYPE_BATTERY;
1056
1057 return pm8921_set_usb_power_supply_type(charger_type);
1058}
1059
Amit Blay0f7edf72012-01-15 10:11:27 +02001060static int msm_otg_notify_power_supply(struct msm_otg *motg, unsigned mA)
1061{
Amit Blay0f7edf72012-01-15 10:11:27 +02001062
Amit Blay0f7edf72012-01-15 10:11:27 +02001063 if (!psy)
1064 goto psy_not_supported;
1065
1066 if (motg->cur_power == 0 && mA > 0) {
1067 /* Enable charging */
1068 if (power_supply_set_online(psy, true))
1069 goto psy_not_supported;
1070 } else if (motg->cur_power > 0 && mA == 0) {
1071 /* Disable charging */
1072 if (power_supply_set_online(psy, false))
1073 goto psy_not_supported;
1074 return 0;
1075 }
1076 /* Set max current limit */
Devin Kim81265542012-09-01 05:06:22 -07001077 dev_info(motg->phy.dev, "current: %d -> %d (mA)\n",
1078 motg->cur_power, mA);
Amit Blay0f7edf72012-01-15 10:11:27 +02001079 if (power_supply_set_current_limit(psy, 1000*mA))
1080 goto psy_not_supported;
1081
1082 return 0;
1083
1084psy_not_supported:
Steve Mucklef132c6c2012-06-06 18:30:57 -07001085 dev_dbg(motg->phy.dev, "Power Supply doesn't support USB charger\n");
Amit Blay0f7edf72012-01-15 10:11:27 +02001086 return -ENXIO;
1087}
1088
Pavankumar Kondetid8608522011-05-04 10:19:47 +05301089static void msm_otg_notify_charger(struct msm_otg *motg, unsigned mA)
1090{
Steve Mucklef132c6c2012-06-06 18:30:57 -07001091 struct usb_gadget *g = motg->phy.otg->gadget;
Vijayavardhan Vennapusaa3152032012-03-05 16:29:30 +05301092
1093 if (g && g->is_a_peripheral)
1094 return;
1095
Pavankumar Kondetiaa449e12011-11-04 11:09:26 +05301096 if ((motg->chg_type == USB_ACA_DOCK_CHARGER ||
1097 motg->chg_type == USB_ACA_A_CHARGER ||
1098 motg->chg_type == USB_ACA_B_CHARGER ||
1099 motg->chg_type == USB_ACA_C_CHARGER) &&
1100 mA > IDEV_ACA_CHG_LIMIT)
1101 mA = IDEV_ACA_CHG_LIMIT;
1102
David Keitel081a3e22012-04-18 12:37:07 -07001103 if (msm_otg_notify_chg_type(motg))
Steve Mucklef132c6c2012-06-06 18:30:57 -07001104 dev_err(motg->phy.dev,
David Keitel081a3e22012-04-18 12:37:07 -07001105 "Failed notifying %d charger type to PMIC\n",
1106 motg->chg_type);
1107
Pavankumar Kondetid8608522011-05-04 10:19:47 +05301108 if (motg->cur_power == mA)
1109 return;
1110
Heikki Krogerus1d4c9292012-02-13 13:24:09 +02001111 dev_info(motg->phy.dev, "Avail curr from USB = %u\n", mA);
Amit Blay0f7edf72012-01-15 10:11:27 +02001112
Devin Kim2073afb2012-09-05 13:01:51 -07001113 pm8921_charger_vbus_draw(mA);
1114 msm_otg_notify_power_supply(motg, mA);
Amit Blay0f7edf72012-01-15 10:11:27 +02001115
Pavankumar Kondetid8608522011-05-04 10:19:47 +05301116 motg->cur_power = mA;
1117}
1118
Heikki Krogerus1d4c9292012-02-13 13:24:09 +02001119static int msm_otg_set_power(struct usb_phy *phy, unsigned mA)
Pavankumar Kondetid8608522011-05-04 10:19:47 +05301120{
Heikki Krogerus1d4c9292012-02-13 13:24:09 +02001121 struct msm_otg *motg = container_of(phy, struct msm_otg, phy);
Pavankumar Kondetid8608522011-05-04 10:19:47 +05301122
1123 /*
1124 * Gadget driver uses set_power method to notify about the
1125 * available current based on suspend/configured states.
1126 *
1127 * IDEV_CHG can be drawn irrespective of suspend/un-configured
1128 * states when CDP/ACA is connected.
1129 */
1130 if (motg->chg_type == USB_SDP_CHARGER)
1131 msm_otg_notify_charger(motg, mA);
1132
1133 return 0;
1134}
1135
Steve Mucklef132c6c2012-06-06 18:30:57 -07001136static void msm_otg_start_host(struct usb_otg *otg, int on)
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05301137{
Steve Mucklef132c6c2012-06-06 18:30:57 -07001138 struct msm_otg *motg = container_of(otg->phy, struct msm_otg, phy);
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05301139 struct msm_otg_platform_data *pdata = motg->pdata;
1140 struct usb_hcd *hcd;
1141
1142 if (!otg->host)
1143 return;
1144
1145 hcd = bus_to_hcd(otg->host);
1146
1147 if (on) {
Steve Mucklef132c6c2012-06-06 18:30:57 -07001148 dev_dbg(otg->phy->dev, "host on\n");
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05301149
Vijayavardhan Vennapusa03171c72012-04-26 14:44:48 +05301150 if (pdata->otg_control == OTG_PHY_CONTROL)
Steve Mucklef132c6c2012-06-06 18:30:57 -07001151 ulpi_write(otg->phy, OTG_COMP_DISABLE,
Vijayavardhan Vennapusa03171c72012-04-26 14:44:48 +05301152 ULPI_SET(ULPI_PWR_CLK_MNG_REG));
1153
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05301154 /*
1155 * Some boards have a switch cotrolled by gpio
1156 * to enable/disable internal HUB. Enable internal
1157 * HUB before kicking the host.
1158 */
1159 if (pdata->setup_gpio)
1160 pdata->setup_gpio(OTG_STATE_A_HOST);
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05301161 usb_add_hcd(hcd, hcd->irq, IRQF_SHARED);
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05301162 } else {
Steve Mucklef132c6c2012-06-06 18:30:57 -07001163 dev_dbg(otg->phy->dev, "host off\n");
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05301164
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05301165 usb_remove_hcd(hcd);
Pavankumar Kondetiaa449e12011-11-04 11:09:26 +05301166 /* HCD core reset all bits of PORTSC. select ULPI phy */
1167 writel_relaxed(0x80000000, USB_PORTSC);
1168
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05301169 if (pdata->setup_gpio)
1170 pdata->setup_gpio(OTG_STATE_UNDEFINED);
Vijayavardhan Vennapusa03171c72012-04-26 14:44:48 +05301171
1172 if (pdata->otg_control == OTG_PHY_CONTROL)
Steve Mucklef132c6c2012-06-06 18:30:57 -07001173 ulpi_write(otg->phy, OTG_COMP_DISABLE,
Vijayavardhan Vennapusa03171c72012-04-26 14:44:48 +05301174 ULPI_CLR(ULPI_PWR_CLK_MNG_REG));
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05301175 }
1176}
1177
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001178static int msm_otg_usbdev_notify(struct notifier_block *self,
1179 unsigned long action, void *priv)
1180{
1181 struct msm_otg *motg = container_of(self, struct msm_otg, usbdev_nb);
Steve Mucklef132c6c2012-06-06 18:30:57 -07001182 struct usb_otg *otg = motg->phy.otg;
Pavankumar Kondetiaa449e12011-11-04 11:09:26 +05301183 struct usb_device *udev = priv;
1184
Pavankumar Kondetiaa449e12011-11-04 11:09:26 +05301185 if (action == USB_BUS_ADD || action == USB_BUS_REMOVE)
1186 goto out;
1187
Steve Mucklef132c6c2012-06-06 18:30:57 -07001188 if (udev->bus != otg->host)
Pavankumar Kondetiaa449e12011-11-04 11:09:26 +05301189 goto out;
1190 /*
1191 * Interested in devices connected directly to the root hub.
1192 * ACA dock can supply IDEV_CHG irrespective devices connected
1193 * on the accessory port.
1194 */
1195 if (!udev->parent || udev->parent->parent ||
1196 motg->chg_type == USB_ACA_DOCK_CHARGER)
1197 goto out;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001198
1199 switch (action) {
1200 case USB_DEVICE_ADD:
Vijayavardhan Vennapusaa3152032012-03-05 16:29:30 +05301201 if (aca_enabled())
1202 usb_disable_autosuspend(udev);
Steve Mucklef132c6c2012-06-06 18:30:57 -07001203 if (otg->phy->state == OTG_STATE_A_WAIT_BCON) {
Vijayavardhan Vennapusaa3152032012-03-05 16:29:30 +05301204 pr_debug("B_CONN set\n");
1205 set_bit(B_CONN, &motg->inputs);
1206 msm_otg_del_timer(motg);
Steve Mucklef132c6c2012-06-06 18:30:57 -07001207 otg->phy->state = OTG_STATE_A_HOST;
Vijayavardhan Vennapusaa3152032012-03-05 16:29:30 +05301208 /*
1209 * OTG PET: A-device must end session within
1210 * 10 sec after PET enumeration.
1211 */
1212 if (udev->quirks & USB_QUIRK_OTG_PET)
1213 msm_otg_start_timer(motg, TA_TST_MAINT,
1214 A_TST_MAINT);
1215 }
Pavankumar Kondetiaa449e12011-11-04 11:09:26 +05301216 /* fall through */
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001217 case USB_DEVICE_CONFIG:
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001218 if (udev->actconfig)
1219 motg->mA_port = udev->actconfig->desc.bMaxPower * 2;
1220 else
1221 motg->mA_port = IUNIT;
Steve Mucklef132c6c2012-06-06 18:30:57 -07001222 if (otg->phy->state == OTG_STATE_B_HOST)
Vijayavardhan Vennapusaa3152032012-03-05 16:29:30 +05301223 msm_otg_del_timer(motg);
Pavankumar Kondetiaa449e12011-11-04 11:09:26 +05301224 break;
1225 case USB_DEVICE_REMOVE:
Steve Mucklef132c6c2012-06-06 18:30:57 -07001226 if ((otg->phy->state == OTG_STATE_A_HOST) ||
1227 (otg->phy->state == OTG_STATE_A_SUSPEND)) {
Vijayavardhan Vennapusaa3152032012-03-05 16:29:30 +05301228 pr_debug("B_CONN clear\n");
1229 clear_bit(B_CONN, &motg->inputs);
1230 /*
1231 * OTG PET: A-device must end session after
1232 * PET disconnection if it is enumerated
1233 * with bcdDevice[0] = 1. USB core sets
1234 * bus->otg_vbus_off for us. clear it here.
1235 */
1236 if (udev->bus->otg_vbus_off) {
1237 udev->bus->otg_vbus_off = 0;
1238 set_bit(A_BUS_DROP, &motg->inputs);
1239 }
1240 queue_work(system_nrt_wq, &motg->sm_work);
1241 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001242 default:
1243 break;
1244 }
Pavankumar Kondetiaa449e12011-11-04 11:09:26 +05301245 if (test_bit(ID_A, &motg->inputs))
1246 msm_otg_notify_charger(motg, IDEV_ACA_CHG_MAX -
1247 motg->mA_port);
1248out:
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001249 return NOTIFY_OK;
1250}
1251
Mayank Ranae3926882011-12-26 09:47:54 +05301252static void msm_hsusb_vbus_power(struct msm_otg *motg, bool on)
1253{
1254 int ret;
1255 static bool vbus_is_on;
1256
1257 if (vbus_is_on == on)
1258 return;
1259
1260 if (motg->pdata->vbus_power) {
Mayank Rana91f597e2012-01-20 10:12:06 +05301261 ret = motg->pdata->vbus_power(on);
1262 if (!ret)
1263 vbus_is_on = on;
Mayank Ranae3926882011-12-26 09:47:54 +05301264 return;
1265 }
1266
1267 if (!vbus_otg) {
1268 pr_err("vbus_otg is NULL.");
1269 return;
1270 }
1271
Abhijeet Dharmapurikarbe054882012-01-03 20:27:07 -08001272 /*
1273 * if entering host mode tell the charger to not draw any current
Abhijeet Dharmapurikar6d941212012-03-05 10:30:56 -08001274 * from usb before turning on the boost.
1275 * if exiting host mode disable the boost before enabling to draw
1276 * current from the source.
Abhijeet Dharmapurikarbe054882012-01-03 20:27:07 -08001277 */
Mayank Ranae3926882011-12-26 09:47:54 +05301278 if (on) {
Abhijeet Dharmapurikar5e96aaa2012-06-26 11:21:03 -07001279 msm_otg_notify_host_mode(motg, on);
Mayank Ranae3926882011-12-26 09:47:54 +05301280 ret = regulator_enable(vbus_otg);
1281 if (ret) {
1282 pr_err("unable to enable vbus_otg\n");
1283 return;
1284 }
1285 vbus_is_on = true;
1286 } else {
1287 ret = regulator_disable(vbus_otg);
1288 if (ret) {
1289 pr_err("unable to disable vbus_otg\n");
1290 return;
1291 }
Abhijeet Dharmapurikar5e96aaa2012-06-26 11:21:03 -07001292 msm_otg_notify_host_mode(motg, on);
Mayank Ranae3926882011-12-26 09:47:54 +05301293 vbus_is_on = false;
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05301294 }
1295}
1296
Heikki Krogerus1d4c9292012-02-13 13:24:09 +02001297static int msm_otg_set_host(struct usb_otg *otg, struct usb_bus *host)
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05301298{
Heikki Krogerus1d4c9292012-02-13 13:24:09 +02001299 struct msm_otg *motg = container_of(otg->phy, struct msm_otg, phy);
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05301300 struct usb_hcd *hcd;
1301
1302 /*
1303 * Fail host registration if this board can support
1304 * only peripheral configuration.
1305 */
1306 if (motg->pdata->mode == USB_PERIPHERAL) {
Heikki Krogerus1d4c9292012-02-13 13:24:09 +02001307 dev_info(otg->phy->dev, "Host mode is not supported\n");
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05301308 return -ENODEV;
1309 }
1310
Devin Kimd10f03c2012-06-25 17:05:13 -07001311 if (!machine_is_apq8064_mako()) {
1312 if (!motg->pdata->vbus_power && host) {
1313 vbus_otg = devm_regulator_get(motg->phy.dev, "vbus_otg");
1314 if (IS_ERR(vbus_otg)) {
1315 pr_err("Unable to get vbus_otg\n");
1316 return -ENODEV;
1317 }
Mayank Ranae3926882011-12-26 09:47:54 +05301318 }
1319 }
1320
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05301321 if (!host) {
Heikki Krogerus1d4c9292012-02-13 13:24:09 +02001322 if (otg->phy->state == OTG_STATE_A_HOST) {
1323 pm_runtime_get_sync(otg->phy->dev);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001324 usb_unregister_notify(&motg->usbdev_nb);
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05301325 msm_otg_start_host(otg, 0);
Mayank Ranae3926882011-12-26 09:47:54 +05301326 msm_hsusb_vbus_power(motg, 0);
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05301327 otg->host = NULL;
Heikki Krogerus1d4c9292012-02-13 13:24:09 +02001328 otg->phy->state = OTG_STATE_UNDEFINED;
Vijayavardhan Vennapusaa3152032012-03-05 16:29:30 +05301329 queue_work(system_nrt_wq, &motg->sm_work);
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05301330 } else {
1331 otg->host = NULL;
1332 }
1333
1334 return 0;
1335 }
1336
1337 hcd = bus_to_hcd(host);
1338 hcd->power_budget = motg->pdata->power_budget;
1339
Vijayavardhan Vennapusaa3152032012-03-05 16:29:30 +05301340#ifdef CONFIG_USB_OTG
1341 host->otg_port = 1;
1342#endif
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001343 motg->usbdev_nb.notifier_call = msm_otg_usbdev_notify;
1344 usb_register_notify(&motg->usbdev_nb);
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05301345 otg->host = host;
Heikki Krogerus1d4c9292012-02-13 13:24:09 +02001346 dev_dbg(otg->phy->dev, "host driver registered w/ tranceiver\n");
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05301347
1348 /*
1349 * Kick the state machine work, if peripheral is not supported
1350 * or peripheral is already registered with us.
1351 */
Pavankumar Kondeti87c01042010-12-07 17:53:58 +05301352 if (motg->pdata->mode == USB_HOST || otg->gadget) {
Heikki Krogerus1d4c9292012-02-13 13:24:09 +02001353 pm_runtime_get_sync(otg->phy->dev);
Vijayavardhan Vennapusaa3152032012-03-05 16:29:30 +05301354 queue_work(system_nrt_wq, &motg->sm_work);
Pavankumar Kondeti87c01042010-12-07 17:53:58 +05301355 }
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05301356
1357 return 0;
1358}
1359
Steve Mucklef132c6c2012-06-06 18:30:57 -07001360static void msm_otg_start_peripheral(struct usb_otg *otg, int on)
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05301361{
Manu Gautamcd82e9d2011-12-20 14:17:28 +05301362 int ret;
Steve Mucklef132c6c2012-06-06 18:30:57 -07001363 struct msm_otg *motg = container_of(otg->phy, struct msm_otg, phy);
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05301364 struct msm_otg_platform_data *pdata = motg->pdata;
1365
1366 if (!otg->gadget)
1367 return;
1368
1369 if (on) {
Steve Mucklef132c6c2012-06-06 18:30:57 -07001370 dev_dbg(otg->phy->dev, "gadget on\n");
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05301371 /*
1372 * Some boards have a switch cotrolled by gpio
1373 * to enable/disable internal HUB. Disable internal
1374 * HUB before kicking the gadget.
1375 */
1376 if (pdata->setup_gpio)
1377 pdata->setup_gpio(OTG_STATE_B_PERIPHERAL);
Ofir Cohen94213a72012-05-03 14:26:32 +03001378
Manu Gautamcd82e9d2011-12-20 14:17:28 +05301379 /* Configure BUS performance parameters for MAX bandwidth */
Manu Gautam8bdcc592012-03-06 11:26:06 +05301380 if (motg->bus_perf_client && debug_bus_voting_enabled) {
Manu Gautamcd82e9d2011-12-20 14:17:28 +05301381 ret = msm_bus_scale_client_update_request(
1382 motg->bus_perf_client, 1);
1383 if (ret)
Steve Mucklef132c6c2012-06-06 18:30:57 -07001384 dev_err(motg->phy.dev, "%s: Failed to vote for "
Manu Gautamcd82e9d2011-12-20 14:17:28 +05301385 "bus bandwidth %d\n", __func__, ret);
1386 }
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05301387 usb_gadget_vbus_connect(otg->gadget);
1388 } else {
Steve Mucklef132c6c2012-06-06 18:30:57 -07001389 dev_dbg(otg->phy->dev, "gadget off\n");
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05301390 usb_gadget_vbus_disconnect(otg->gadget);
Manu Gautamcd82e9d2011-12-20 14:17:28 +05301391 /* Configure BUS performance parameters to default */
1392 if (motg->bus_perf_client) {
1393 ret = msm_bus_scale_client_update_request(
1394 motg->bus_perf_client, 0);
1395 if (ret)
Steve Mucklef132c6c2012-06-06 18:30:57 -07001396 dev_err(motg->phy.dev, "%s: Failed to devote "
Manu Gautamcd82e9d2011-12-20 14:17:28 +05301397 "for bus bw %d\n", __func__, ret);
1398 }
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05301399 if (pdata->setup_gpio)
1400 pdata->setup_gpio(OTG_STATE_UNDEFINED);
1401 }
1402
1403}
1404
Heikki Krogerus1d4c9292012-02-13 13:24:09 +02001405static int msm_otg_set_peripheral(struct usb_otg *otg,
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05301406 struct usb_gadget *gadget)
1407{
Heikki Krogerus1d4c9292012-02-13 13:24:09 +02001408 struct msm_otg *motg = container_of(otg->phy, struct msm_otg, phy);
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05301409
1410 /*
1411 * Fail peripheral registration if this board can support
1412 * only host configuration.
1413 */
1414 if (motg->pdata->mode == USB_HOST) {
Heikki Krogerus1d4c9292012-02-13 13:24:09 +02001415 dev_info(otg->phy->dev, "Peripheral mode is not supported\n");
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05301416 return -ENODEV;
1417 }
1418
1419 if (!gadget) {
Heikki Krogerus1d4c9292012-02-13 13:24:09 +02001420 if (otg->phy->state == OTG_STATE_B_PERIPHERAL) {
1421 pm_runtime_get_sync(otg->phy->dev);
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05301422 msm_otg_start_peripheral(otg, 0);
1423 otg->gadget = NULL;
Heikki Krogerus1d4c9292012-02-13 13:24:09 +02001424 otg->phy->state = OTG_STATE_UNDEFINED;
Vijayavardhan Vennapusaa3152032012-03-05 16:29:30 +05301425 queue_work(system_nrt_wq, &motg->sm_work);
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05301426 } else {
1427 otg->gadget = NULL;
1428 }
1429
1430 return 0;
1431 }
1432 otg->gadget = gadget;
Heikki Krogerus1d4c9292012-02-13 13:24:09 +02001433 dev_dbg(otg->phy->dev, "peripheral driver registered w/ tranceiver\n");
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05301434
1435 /*
1436 * Kick the state machine work, if host is not supported
1437 * or host is already registered with us.
1438 */
Pavankumar Kondeti87c01042010-12-07 17:53:58 +05301439 if (motg->pdata->mode == USB_PERIPHERAL || otg->host) {
Heikki Krogerus1d4c9292012-02-13 13:24:09 +02001440 pm_runtime_get_sync(otg->phy->dev);
Vijayavardhan Vennapusaa3152032012-03-05 16:29:30 +05301441 queue_work(system_nrt_wq, &motg->sm_work);
Pavankumar Kondeti87c01042010-12-07 17:53:58 +05301442 }
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05301443
1444 return 0;
1445}
1446
Pavankumar Kondeti2aec9f32012-06-13 09:06:03 +05301447static int msm_otg_mhl_register_callback(struct msm_otg *motg,
1448 void (*callback)(int on))
1449{
1450 struct usb_phy *phy = &motg->phy;
1451 int ret;
1452
1453 if (motg->pdata->otg_control != OTG_PMIC_CONTROL ||
1454 !motg->pdata->pmic_id_irq) {
1455 dev_dbg(phy->dev, "MHL can not be supported without PMIC Id\n");
1456 return -ENODEV;
1457 }
1458
1459 if (!motg->pdata->mhl_dev_name) {
1460 dev_dbg(phy->dev, "MHL device name does not exist.\n");
1461 return -ENODEV;
1462 }
1463
1464 if (callback)
1465 ret = mhl_register_callback(motg->pdata->mhl_dev_name,
1466 callback);
1467 else
1468 ret = mhl_unregister_callback(motg->pdata->mhl_dev_name);
1469
1470 if (ret)
1471 dev_dbg(phy->dev, "mhl_register_callback(%s) return error=%d\n",
1472 motg->pdata->mhl_dev_name, ret);
1473 else
1474 motg->mhl_enabled = true;
1475
1476 return ret;
1477}
1478
1479static void msm_otg_mhl_notify_online(int on)
1480{
1481 struct msm_otg *motg = the_msm_otg;
1482 struct usb_phy *phy = &motg->phy;
1483 bool queue = false;
1484
1485 dev_dbg(phy->dev, "notify MHL %s%s\n", on ? "" : "dis", "connected");
1486
1487 if (on) {
1488 set_bit(MHL, &motg->inputs);
1489 } else {
1490 clear_bit(MHL, &motg->inputs);
1491 queue = true;
1492 }
1493
1494 if (queue && phy->state != OTG_STATE_UNDEFINED)
1495 schedule_work(&motg->sm_work);
1496}
1497
1498static bool msm_otg_is_mhl(struct msm_otg *motg)
1499{
1500 struct usb_phy *phy = &motg->phy;
1501 int is_mhl, ret;
1502
1503 ret = mhl_device_discovery(motg->pdata->mhl_dev_name, &is_mhl);
1504 if (ret || is_mhl != MHL_DISCOVERY_RESULT_MHL) {
1505 /*
1506 * MHL driver calls our callback saying that MHL connected
1507 * if RID_GND is detected. But at later part of discovery
1508 * it may figure out MHL is not connected and returns
1509 * false. Hence clear MHL input here.
1510 */
1511 clear_bit(MHL, &motg->inputs);
1512 dev_dbg(phy->dev, "MHL device not found\n");
1513 return false;
1514 }
1515
1516 set_bit(MHL, &motg->inputs);
1517 dev_dbg(phy->dev, "MHL device found\n");
1518 return true;
1519}
1520
1521static bool msm_chg_mhl_detect(struct msm_otg *motg)
1522{
1523 bool ret, id;
1524 unsigned long flags;
1525
1526 if (!motg->mhl_enabled)
1527 return false;
1528
1529 local_irq_save(flags);
1530 id = irq_read_line(motg->pdata->pmic_id_irq);
1531 local_irq_restore(flags);
1532
1533 if (id)
1534 return false;
1535
1536 mhl_det_in_progress = true;
1537 ret = msm_otg_is_mhl(motg);
1538 mhl_det_in_progress = false;
1539
1540 return ret;
1541}
1542
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001543static bool msm_chg_aca_detect(struct msm_otg *motg)
1544{
Steve Mucklef132c6c2012-06-06 18:30:57 -07001545 struct usb_phy *phy = &motg->phy;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001546 u32 int_sts;
1547 bool ret = false;
1548
Pavankumar Kondetiaa449e12011-11-04 11:09:26 +05301549 if (!aca_enabled())
1550 goto out;
1551
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001552 if (motg->pdata->phy_type == CI_45NM_INTEGRATED_PHY)
1553 goto out;
1554
Steve Mucklef132c6c2012-06-06 18:30:57 -07001555 int_sts = ulpi_read(phy, 0x87);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001556 switch (int_sts & 0x1C) {
1557 case 0x08:
1558 if (!test_and_set_bit(ID_A, &motg->inputs)) {
Steve Mucklef132c6c2012-06-06 18:30:57 -07001559 dev_dbg(phy->dev, "ID_A\n");
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001560 motg->chg_type = USB_ACA_A_CHARGER;
1561 motg->chg_state = USB_CHG_STATE_DETECTED;
1562 clear_bit(ID_B, &motg->inputs);
1563 clear_bit(ID_C, &motg->inputs);
Pavankumar Kondetiaa449e12011-11-04 11:09:26 +05301564 set_bit(ID, &motg->inputs);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001565 ret = true;
1566 }
1567 break;
1568 case 0x0C:
1569 if (!test_and_set_bit(ID_B, &motg->inputs)) {
Steve Mucklef132c6c2012-06-06 18:30:57 -07001570 dev_dbg(phy->dev, "ID_B\n");
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001571 motg->chg_type = USB_ACA_B_CHARGER;
1572 motg->chg_state = USB_CHG_STATE_DETECTED;
1573 clear_bit(ID_A, &motg->inputs);
1574 clear_bit(ID_C, &motg->inputs);
Pavankumar Kondetiaa449e12011-11-04 11:09:26 +05301575 set_bit(ID, &motg->inputs);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001576 ret = true;
1577 }
1578 break;
1579 case 0x10:
1580 if (!test_and_set_bit(ID_C, &motg->inputs)) {
Steve Mucklef132c6c2012-06-06 18:30:57 -07001581 dev_dbg(phy->dev, "ID_C\n");
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001582 motg->chg_type = USB_ACA_C_CHARGER;
1583 motg->chg_state = USB_CHG_STATE_DETECTED;
1584 clear_bit(ID_A, &motg->inputs);
1585 clear_bit(ID_B, &motg->inputs);
Pavankumar Kondetiaa449e12011-11-04 11:09:26 +05301586 set_bit(ID, &motg->inputs);
1587 ret = true;
1588 }
1589 break;
1590 case 0x04:
1591 if (test_and_clear_bit(ID, &motg->inputs)) {
Steve Mucklef132c6c2012-06-06 18:30:57 -07001592 dev_dbg(phy->dev, "ID_GND\n");
Pavankumar Kondetiaa449e12011-11-04 11:09:26 +05301593 motg->chg_type = USB_INVALID_CHARGER;
1594 motg->chg_state = USB_CHG_STATE_UNDEFINED;
1595 clear_bit(ID_A, &motg->inputs);
1596 clear_bit(ID_B, &motg->inputs);
1597 clear_bit(ID_C, &motg->inputs);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001598 ret = true;
1599 }
1600 break;
1601 default:
1602 ret = test_and_clear_bit(ID_A, &motg->inputs) |
1603 test_and_clear_bit(ID_B, &motg->inputs) |
Pavankumar Kondetiaa449e12011-11-04 11:09:26 +05301604 test_and_clear_bit(ID_C, &motg->inputs) |
1605 !test_and_set_bit(ID, &motg->inputs);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001606 if (ret) {
Steve Mucklef132c6c2012-06-06 18:30:57 -07001607 dev_dbg(phy->dev, "ID A/B/C/GND is no more\n");
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001608 motg->chg_type = USB_INVALID_CHARGER;
1609 motg->chg_state = USB_CHG_STATE_UNDEFINED;
1610 }
1611 }
1612out:
1613 return ret;
1614}
1615
1616static void msm_chg_enable_aca_det(struct msm_otg *motg)
1617{
Steve Mucklef132c6c2012-06-06 18:30:57 -07001618 struct usb_phy *phy = &motg->phy;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001619
Pavankumar Kondetiaa449e12011-11-04 11:09:26 +05301620 if (!aca_enabled())
1621 return;
1622
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001623 switch (motg->pdata->phy_type) {
1624 case SNPS_28NM_INTEGRATED_PHY:
Pavankumar Kondetiaa449e12011-11-04 11:09:26 +05301625 /* Disable ID_GND in link and PHY */
1626 writel_relaxed(readl_relaxed(USB_OTGSC) & ~(OTGSC_IDPU |
1627 OTGSC_IDIE), USB_OTGSC);
Steve Mucklef132c6c2012-06-06 18:30:57 -07001628 ulpi_write(phy, 0x01, 0x0C);
1629 ulpi_write(phy, 0x10, 0x0F);
1630 ulpi_write(phy, 0x10, 0x12);
Pavankumar Kondeti446f4542012-02-01 13:57:13 +05301631 /* Disable PMIC ID pull-up */
1632 pm8xxx_usb_id_pullup(0);
Pavankumar Kondetiaa449e12011-11-04 11:09:26 +05301633 /* Enable ACA ID detection */
Steve Mucklef132c6c2012-06-06 18:30:57 -07001634 ulpi_write(phy, 0x20, 0x85);
Pavankumar Kondeti4960f312011-12-06 15:46:14 +05301635 aca_id_turned_on = true;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001636 break;
1637 default:
1638 break;
1639 }
1640}
1641
1642static void msm_chg_enable_aca_intr(struct msm_otg *motg)
1643{
Steve Mucklef132c6c2012-06-06 18:30:57 -07001644 struct usb_phy *phy = &motg->phy;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001645
Pavankumar Kondetiaa449e12011-11-04 11:09:26 +05301646 if (!aca_enabled())
1647 return;
1648
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001649 switch (motg->pdata->phy_type) {
1650 case SNPS_28NM_INTEGRATED_PHY:
Pavankumar Kondetiaa449e12011-11-04 11:09:26 +05301651 /* Enable ACA Detection interrupt (on any RID change) */
Steve Mucklef132c6c2012-06-06 18:30:57 -07001652 ulpi_write(phy, 0x01, 0x94);
Pavankumar Kondetiaa449e12011-11-04 11:09:26 +05301653 break;
1654 default:
1655 break;
1656 }
1657}
1658
1659static void msm_chg_disable_aca_intr(struct msm_otg *motg)
1660{
Steve Mucklef132c6c2012-06-06 18:30:57 -07001661 struct usb_phy *phy = &motg->phy;
Pavankumar Kondetiaa449e12011-11-04 11:09:26 +05301662
1663 if (!aca_enabled())
1664 return;
1665
1666 switch (motg->pdata->phy_type) {
1667 case SNPS_28NM_INTEGRATED_PHY:
Steve Mucklef132c6c2012-06-06 18:30:57 -07001668 ulpi_write(phy, 0x01, 0x95);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001669 break;
1670 default:
1671 break;
1672 }
1673}
1674
1675static bool msm_chg_check_aca_intr(struct msm_otg *motg)
1676{
Steve Mucklef132c6c2012-06-06 18:30:57 -07001677 struct usb_phy *phy = &motg->phy;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001678 bool ret = false;
1679
Pavankumar Kondetiaa449e12011-11-04 11:09:26 +05301680 if (!aca_enabled())
1681 return ret;
1682
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001683 switch (motg->pdata->phy_type) {
1684 case SNPS_28NM_INTEGRATED_PHY:
Steve Mucklef132c6c2012-06-06 18:30:57 -07001685 if (ulpi_read(phy, 0x91) & 1) {
1686 dev_dbg(phy->dev, "RID change\n");
1687 ulpi_write(phy, 0x01, 0x92);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001688 ret = msm_chg_aca_detect(motg);
1689 }
1690 default:
1691 break;
1692 }
1693 return ret;
1694}
Pavankumar Kondetiaa449e12011-11-04 11:09:26 +05301695
1696static void msm_otg_id_timer_func(unsigned long data)
1697{
1698 struct msm_otg *motg = (struct msm_otg *) data;
1699
1700 if (!aca_enabled())
1701 return;
1702
1703 if (atomic_read(&motg->in_lpm)) {
Steve Mucklef132c6c2012-06-06 18:30:57 -07001704 dev_dbg(motg->phy.dev, "timer: in lpm\n");
Pavankumar Kondetiaa449e12011-11-04 11:09:26 +05301705 return;
1706 }
1707
Steve Mucklef132c6c2012-06-06 18:30:57 -07001708 if (motg->phy.state == OTG_STATE_A_SUSPEND)
Vijayavardhan Vennapusaa3152032012-03-05 16:29:30 +05301709 goto out;
1710
Pavankumar Kondetiaa449e12011-11-04 11:09:26 +05301711 if (msm_chg_check_aca_intr(motg)) {
Steve Mucklef132c6c2012-06-06 18:30:57 -07001712 dev_dbg(motg->phy.dev, "timer: aca work\n");
Vijayavardhan Vennapusaa3152032012-03-05 16:29:30 +05301713 queue_work(system_nrt_wq, &motg->sm_work);
Pavankumar Kondetiaa449e12011-11-04 11:09:26 +05301714 }
1715
Vijayavardhan Vennapusaa3152032012-03-05 16:29:30 +05301716out:
Pavankumar Kondetiaa449e12011-11-04 11:09:26 +05301717 if (!test_bit(ID, &motg->inputs) || test_bit(ID_A, &motg->inputs))
1718 mod_timer(&motg->id_timer, ID_TIMER_FREQ);
1719}
1720
Pavankumar Kondetid8608522011-05-04 10:19:47 +05301721static bool msm_chg_check_secondary_det(struct msm_otg *motg)
1722{
Heikki Krogerus1d4c9292012-02-13 13:24:09 +02001723 struct usb_phy *phy = &motg->phy;
Pavankumar Kondetid8608522011-05-04 10:19:47 +05301724 u32 chg_det;
1725 bool ret = false;
1726
1727 switch (motg->pdata->phy_type) {
1728 case CI_45NM_INTEGRATED_PHY:
Heikki Krogerus1d4c9292012-02-13 13:24:09 +02001729 chg_det = ulpi_read(phy, 0x34);
Pavankumar Kondetid8608522011-05-04 10:19:47 +05301730 ret = chg_det & (1 << 4);
1731 break;
1732 case SNPS_28NM_INTEGRATED_PHY:
Heikki Krogerus1d4c9292012-02-13 13:24:09 +02001733 chg_det = ulpi_read(phy, 0x87);
Pavankumar Kondetid8608522011-05-04 10:19:47 +05301734 ret = chg_det & 1;
1735 break;
1736 default:
1737 break;
1738 }
1739 return ret;
1740}
1741
1742static void msm_chg_enable_secondary_det(struct msm_otg *motg)
1743{
Heikki Krogerus1d4c9292012-02-13 13:24:09 +02001744 struct usb_phy *phy = &motg->phy;
Pavankumar Kondetid8608522011-05-04 10:19:47 +05301745 u32 chg_det;
1746
1747 switch (motg->pdata->phy_type) {
1748 case CI_45NM_INTEGRATED_PHY:
Heikki Krogerus1d4c9292012-02-13 13:24:09 +02001749 chg_det = ulpi_read(phy, 0x34);
Pavankumar Kondetid8608522011-05-04 10:19:47 +05301750 /* Turn off charger block */
1751 chg_det |= ~(1 << 1);
Heikki Krogerus1d4c9292012-02-13 13:24:09 +02001752 ulpi_write(phy, chg_det, 0x34);
Pavankumar Kondetid8608522011-05-04 10:19:47 +05301753 udelay(20);
1754 /* control chg block via ULPI */
1755 chg_det &= ~(1 << 3);
Heikki Krogerus1d4c9292012-02-13 13:24:09 +02001756 ulpi_write(phy, chg_det, 0x34);
Pavankumar Kondetid8608522011-05-04 10:19:47 +05301757 /* put it in host mode for enabling D- source */
1758 chg_det &= ~(1 << 2);
Heikki Krogerus1d4c9292012-02-13 13:24:09 +02001759 ulpi_write(phy, chg_det, 0x34);
Pavankumar Kondetid8608522011-05-04 10:19:47 +05301760 /* Turn on chg detect block */
1761 chg_det &= ~(1 << 1);
Heikki Krogerus1d4c9292012-02-13 13:24:09 +02001762 ulpi_write(phy, chg_det, 0x34);
Pavankumar Kondetid8608522011-05-04 10:19:47 +05301763 udelay(20);
1764 /* enable chg detection */
1765 chg_det &= ~(1 << 0);
Heikki Krogerus1d4c9292012-02-13 13:24:09 +02001766 ulpi_write(phy, chg_det, 0x34);
Pavankumar Kondetid8608522011-05-04 10:19:47 +05301767 break;
1768 case SNPS_28NM_INTEGRATED_PHY:
1769 /*
1770 * Configure DM as current source, DP as current sink
1771 * and enable battery charging comparators.
1772 */
Heikki Krogerus1d4c9292012-02-13 13:24:09 +02001773 ulpi_write(phy, 0x8, 0x85);
1774 ulpi_write(phy, 0x2, 0x85);
1775 ulpi_write(phy, 0x1, 0x85);
Pavankumar Kondetid8608522011-05-04 10:19:47 +05301776 break;
1777 default:
1778 break;
1779 }
1780}
1781
1782static bool msm_chg_check_primary_det(struct msm_otg *motg)
1783{
Heikki Krogerus1d4c9292012-02-13 13:24:09 +02001784 struct usb_phy *phy = &motg->phy;
Pavankumar Kondetid8608522011-05-04 10:19:47 +05301785 u32 chg_det;
1786 bool ret = false;
1787
1788 switch (motg->pdata->phy_type) {
1789 case CI_45NM_INTEGRATED_PHY:
Heikki Krogerus1d4c9292012-02-13 13:24:09 +02001790 chg_det = ulpi_read(phy, 0x34);
Pavankumar Kondetid8608522011-05-04 10:19:47 +05301791 ret = chg_det & (1 << 4);
1792 break;
1793 case SNPS_28NM_INTEGRATED_PHY:
Heikki Krogerus1d4c9292012-02-13 13:24:09 +02001794 chg_det = ulpi_read(phy, 0x87);
Pavankumar Kondetid8608522011-05-04 10:19:47 +05301795 ret = chg_det & 1;
Pavankumar Kondeti9ec21d32012-05-07 15:50:23 +05301796 /* Turn off VDP_SRC */
1797 ulpi_write(phy, 0x3, 0x86);
1798 msleep(20);
Pavankumar Kondetid8608522011-05-04 10:19:47 +05301799 break;
1800 default:
1801 break;
1802 }
1803 return ret;
1804}
1805
1806static void msm_chg_enable_primary_det(struct msm_otg *motg)
1807{
Heikki Krogerus1d4c9292012-02-13 13:24:09 +02001808 struct usb_phy *phy = &motg->phy;
Pavankumar Kondetid8608522011-05-04 10:19:47 +05301809 u32 chg_det;
1810
1811 switch (motg->pdata->phy_type) {
1812 case CI_45NM_INTEGRATED_PHY:
Heikki Krogerus1d4c9292012-02-13 13:24:09 +02001813 chg_det = ulpi_read(phy, 0x34);
Pavankumar Kondetid8608522011-05-04 10:19:47 +05301814 /* enable chg detection */
1815 chg_det &= ~(1 << 0);
Heikki Krogerus1d4c9292012-02-13 13:24:09 +02001816 ulpi_write(phy, chg_det, 0x34);
Pavankumar Kondetid8608522011-05-04 10:19:47 +05301817 break;
1818 case SNPS_28NM_INTEGRATED_PHY:
1819 /*
1820 * Configure DP as current source, DM as current sink
1821 * and enable battery charging comparators.
1822 */
Heikki Krogerus1d4c9292012-02-13 13:24:09 +02001823 ulpi_write(phy, 0x2, 0x85);
1824 ulpi_write(phy, 0x1, 0x85);
Pavankumar Kondetid8608522011-05-04 10:19:47 +05301825 break;
1826 default:
1827 break;
1828 }
1829}
1830
1831static bool msm_chg_check_dcd(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 line_state;
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 line_state = ulpi_read(phy, 0x15);
Pavankumar Kondetid8608522011-05-04 10:19:47 +05301840 ret = !(line_state & 1);
1841 break;
1842 case SNPS_28NM_INTEGRATED_PHY:
Heikki Krogerus1d4c9292012-02-13 13:24:09 +02001843 line_state = ulpi_read(phy, 0x87);
Pavankumar Kondetid8608522011-05-04 10:19:47 +05301844 ret = line_state & 2;
1845 break;
1846 default:
1847 break;
1848 }
1849 return ret;
1850}
1851
1852static void msm_chg_disable_dcd(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 chg_det &= ~(1 << 5);
Heikki Krogerus1d4c9292012-02-13 13:24:09 +02001861 ulpi_write(phy, chg_det, 0x34);
Pavankumar Kondetid8608522011-05-04 10:19:47 +05301862 break;
1863 case SNPS_28NM_INTEGRATED_PHY:
Heikki Krogerus1d4c9292012-02-13 13:24:09 +02001864 ulpi_write(phy, 0x10, 0x86);
Pavankumar Kondetid8608522011-05-04 10:19:47 +05301865 break;
1866 default:
1867 break;
1868 }
1869}
1870
1871static void msm_chg_enable_dcd(struct msm_otg *motg)
1872{
Heikki Krogerus1d4c9292012-02-13 13:24:09 +02001873 struct usb_phy *phy = &motg->phy;
Pavankumar Kondetid8608522011-05-04 10:19:47 +05301874 u32 chg_det;
1875
1876 switch (motg->pdata->phy_type) {
1877 case CI_45NM_INTEGRATED_PHY:
Heikki Krogerus1d4c9292012-02-13 13:24:09 +02001878 chg_det = ulpi_read(phy, 0x34);
Pavankumar Kondetid8608522011-05-04 10:19:47 +05301879 /* Turn on D+ current source */
1880 chg_det |= (1 << 5);
Heikki Krogerus1d4c9292012-02-13 13:24:09 +02001881 ulpi_write(phy, chg_det, 0x34);
Pavankumar Kondetid8608522011-05-04 10:19:47 +05301882 break;
1883 case SNPS_28NM_INTEGRATED_PHY:
1884 /* Data contact detection enable */
Heikki Krogerus1d4c9292012-02-13 13:24:09 +02001885 ulpi_write(phy, 0x10, 0x85);
Pavankumar Kondetid8608522011-05-04 10:19:47 +05301886 break;
1887 default:
1888 break;
1889 }
1890}
1891
1892static void msm_chg_block_on(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 func_ctrl, chg_det;
1896
1897 /* put the controller in non-driving mode */
Heikki Krogerus1d4c9292012-02-13 13:24:09 +02001898 func_ctrl = ulpi_read(phy, ULPI_FUNC_CTRL);
Pavankumar Kondetid8608522011-05-04 10:19:47 +05301899 func_ctrl &= ~ULPI_FUNC_CTRL_OPMODE_MASK;
1900 func_ctrl |= ULPI_FUNC_CTRL_OPMODE_NONDRIVING;
Heikki Krogerus1d4c9292012-02-13 13:24:09 +02001901 ulpi_write(phy, func_ctrl, ULPI_FUNC_CTRL);
Pavankumar Kondetid8608522011-05-04 10:19:47 +05301902
1903 switch (motg->pdata->phy_type) {
1904 case CI_45NM_INTEGRATED_PHY:
Heikki Krogerus1d4c9292012-02-13 13:24:09 +02001905 chg_det = ulpi_read(phy, 0x34);
Pavankumar Kondetid8608522011-05-04 10:19:47 +05301906 /* control chg block via ULPI */
1907 chg_det &= ~(1 << 3);
Heikki Krogerus1d4c9292012-02-13 13:24:09 +02001908 ulpi_write(phy, chg_det, 0x34);
Pavankumar Kondetid8608522011-05-04 10:19:47 +05301909 /* Turn on chg detect block */
1910 chg_det &= ~(1 << 1);
Heikki Krogerus1d4c9292012-02-13 13:24:09 +02001911 ulpi_write(phy, chg_det, 0x34);
Pavankumar Kondetid8608522011-05-04 10:19:47 +05301912 udelay(20);
1913 break;
1914 case SNPS_28NM_INTEGRATED_PHY:
1915 /* Clear charger detecting control bits */
Steve Mucklef132c6c2012-06-06 18:30:57 -07001916 ulpi_write(phy, 0x1F, 0x86);
Pavankumar Kondetid8608522011-05-04 10:19:47 +05301917 /* Clear alt interrupt latch and enable bits */
Heikki Krogerus1d4c9292012-02-13 13:24:09 +02001918 ulpi_write(phy, 0x1F, 0x92);
1919 ulpi_write(phy, 0x1F, 0x95);
Pavankumar Kondetid8608522011-05-04 10:19:47 +05301920 udelay(100);
1921 break;
1922 default:
1923 break;
1924 }
1925}
1926
1927static void msm_chg_block_off(struct msm_otg *motg)
1928{
Heikki Krogerus1d4c9292012-02-13 13:24:09 +02001929 struct usb_phy *phy = &motg->phy;
Pavankumar Kondetid8608522011-05-04 10:19:47 +05301930 u32 func_ctrl, chg_det;
1931
1932 switch (motg->pdata->phy_type) {
1933 case CI_45NM_INTEGRATED_PHY:
Heikki Krogerus1d4c9292012-02-13 13:24:09 +02001934 chg_det = ulpi_read(phy, 0x34);
Pavankumar Kondetid8608522011-05-04 10:19:47 +05301935 /* Turn off charger block */
1936 chg_det |= ~(1 << 1);
Heikki Krogerus1d4c9292012-02-13 13:24:09 +02001937 ulpi_write(phy, chg_det, 0x34);
Pavankumar Kondetid8608522011-05-04 10:19:47 +05301938 break;
1939 case SNPS_28NM_INTEGRATED_PHY:
1940 /* Clear charger detecting control bits */
Heikki Krogerus1d4c9292012-02-13 13:24:09 +02001941 ulpi_write(phy, 0x3F, 0x86);
Pavankumar Kondetid8608522011-05-04 10:19:47 +05301942 /* Clear alt interrupt latch and enable bits */
Heikki Krogerus1d4c9292012-02-13 13:24:09 +02001943 ulpi_write(phy, 0x1F, 0x92);
1944 ulpi_write(phy, 0x1F, 0x95);
Pavankumar Kondetid8608522011-05-04 10:19:47 +05301945 break;
1946 default:
1947 break;
1948 }
1949
1950 /* put the controller in normal mode */
Heikki Krogerus1d4c9292012-02-13 13:24:09 +02001951 func_ctrl = ulpi_read(phy, ULPI_FUNC_CTRL);
Pavankumar Kondetid8608522011-05-04 10:19:47 +05301952 func_ctrl &= ~ULPI_FUNC_CTRL_OPMODE_MASK;
1953 func_ctrl |= ULPI_FUNC_CTRL_OPMODE_NORMAL;
Heikki Krogerus1d4c9292012-02-13 13:24:09 +02001954 ulpi_write(phy, func_ctrl, ULPI_FUNC_CTRL);
Pavankumar Kondetid8608522011-05-04 10:19:47 +05301955}
1956
Anji jonnalad270e2d2011-08-09 11:28:32 +05301957static const char *chg_to_string(enum usb_chg_type chg_type)
1958{
1959 switch (chg_type) {
1960 case USB_SDP_CHARGER: return "USB_SDP_CHARGER";
1961 case USB_DCP_CHARGER: return "USB_DCP_CHARGER";
1962 case USB_CDP_CHARGER: return "USB_CDP_CHARGER";
1963 case USB_ACA_A_CHARGER: return "USB_ACA_A_CHARGER";
1964 case USB_ACA_B_CHARGER: return "USB_ACA_B_CHARGER";
1965 case USB_ACA_C_CHARGER: return "USB_ACA_C_CHARGER";
1966 case USB_ACA_DOCK_CHARGER: return "USB_ACA_DOCK_CHARGER";
Pavankumar Kondeti9ec21d32012-05-07 15:50:23 +05301967 case USB_PROPRIETARY_CHARGER: return "USB_PROPRIETARY_CHARGER";
Anji jonnalad270e2d2011-08-09 11:28:32 +05301968 default: return "INVALID_CHARGER";
1969 }
1970}
kibum.leeec040442012-08-22 22:29:46 +09001971
Devin Kimd93ff032012-09-14 15:01:31 -07001972#define MSM_CHECK_TA_DELAY (5 * HZ)
1973#define PORTSC_LS (3 << 10) /* Read - Port's Line status */
kibum.leeec040442012-08-22 22:29:46 +09001974static void msm_ta_detect_work(struct work_struct *w)
1975{
Devin Kimd93ff032012-09-14 15:01:31 -07001976 struct msm_otg *motg = container_of(w, struct msm_otg, check_ta_work.work);
kibum.leeec040442012-08-22 22:29:46 +09001977 struct usb_otg *otg = motg->phy.otg;
kibum.leeec040442012-08-22 22:29:46 +09001978
Devin Kimd93ff032012-09-14 15:01:31 -07001979 pr_info("msm_ta_detect_work: ta detection work\n");
1980
1981 /* Presence of FRame Index or FRINDEX rollover implies USB communication */
1982 if( (readl(USB_FRINDEX) != 0) || ( readl(USB_USBSTS) & (1<<3) ) ) {
1983 pr_info("msm_ta_detect_work: USB exit ta detection - frindex\n");
1984 return;
1985 }
1986
1987 if ((readl(USB_PORTSC) & PORTSC_LS) == PORTSC_LS) {
1988 pr_info("msm_ta_detect_work: ta dectection success\n");
kibum.leeec040442012-08-22 22:29:46 +09001989 /* inform to user space that SDP is no longer detected */
1990 msm_otg_notify_charger(motg, 0);
1991 motg->chg_state = USB_CHG_STATE_DETECTED;
1992 motg->chg_type = USB_DCP_CHARGER;
1993 motg->cur_power = 0;
1994 msm_otg_start_peripheral(otg, 0);
1995 otg->phy->state = OTG_STATE_B_IDLE;
1996 schedule_work(&motg->sm_work);
1997 return;
kibum.leeec040442012-08-22 22:29:46 +09001998 }
Devin Kimd93ff032012-09-14 15:01:31 -07001999 schedule_delayed_work(&motg->check_ta_work, MSM_CHECK_TA_DELAY);
kibum.leeec040442012-08-22 22:29:46 +09002000}
Anji jonnalad270e2d2011-08-09 11:28:32 +05302001
Pavankumar Kondetid8608522011-05-04 10:19:47 +05302002#define MSM_CHG_DCD_POLL_TIME (100 * HZ/1000) /* 100 msec */
2003#define MSM_CHG_DCD_MAX_RETRIES 6 /* Tdcd_tmout = 6 * 100 msec */
Pavankumar Kondeti283146f2012-01-12 12:51:19 +05302004#define MSM_CHG_PRIMARY_DET_TIME (50 * HZ/1000) /* TVDPSRC_ON */
2005#define MSM_CHG_SECONDARY_DET_TIME (50 * HZ/1000) /* TVDMSRC_ON */
Pavankumar Kondetid8608522011-05-04 10:19:47 +05302006static void msm_chg_detect_work(struct work_struct *w)
2007{
2008 struct msm_otg *motg = container_of(w, struct msm_otg, chg_work.work);
Heikki Krogerus1d4c9292012-02-13 13:24:09 +02002009 struct usb_phy *phy = &motg->phy;
Pavankumar Kondeti2d09e5f2012-01-16 08:56:57 +05302010 bool is_dcd = false, tmout, vout, is_aca;
Pavankumar Kondeti9ec21d32012-05-07 15:50:23 +05302011 u32 line_state, dm_vlgc;
Pavankumar Kondetid8608522011-05-04 10:19:47 +05302012 unsigned long delay;
2013
Heikki Krogerus1d4c9292012-02-13 13:24:09 +02002014 dev_dbg(phy->dev, "chg detection work\n");
Pavankumar Kondeti2aec9f32012-06-13 09:06:03 +05302015
2016 if (test_bit(MHL, &motg->inputs)) {
2017 dev_dbg(phy->dev, "detected MHL, escape chg detection work\n");
2018 return;
2019 }
2020
Pavankumar Kondetid8608522011-05-04 10:19:47 +05302021 switch (motg->chg_state) {
2022 case USB_CHG_STATE_UNDEFINED:
Pavankumar Kondetid8608522011-05-04 10:19:47 +05302023 msm_chg_block_on(motg);
Pavankumar Kondeti2d09e5f2012-01-16 08:56:57 +05302024 if (motg->pdata->enable_dcd)
2025 msm_chg_enable_dcd(motg);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002026 msm_chg_enable_aca_det(motg);
Pavankumar Kondetid8608522011-05-04 10:19:47 +05302027 motg->chg_state = USB_CHG_STATE_WAIT_FOR_DCD;
2028 motg->dcd_retries = 0;
2029 delay = MSM_CHG_DCD_POLL_TIME;
2030 break;
2031 case USB_CHG_STATE_WAIT_FOR_DCD:
jh.koo78df86f2012-09-04 20:13:19 +09002032 if (slimport_is_connected()) {
2033 msm_chg_block_off(motg);
2034 motg->chg_state = USB_CHG_STATE_DETECTED;
2035 motg->chg_type = USB_SDP_CHARGER;
2036 queue_work(system_nrt_wq, &motg->sm_work);
2037 return;
2038 }
Pavankumar Kondeti2aec9f32012-06-13 09:06:03 +05302039 if (msm_chg_mhl_detect(motg)) {
2040 msm_chg_block_off(motg);
2041 motg->chg_state = USB_CHG_STATE_DETECTED;
2042 motg->chg_type = USB_INVALID_CHARGER;
2043 queue_work(system_nrt_wq, &motg->sm_work);
2044 return;
2045 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002046 is_aca = msm_chg_aca_detect(motg);
2047 if (is_aca) {
2048 /*
2049 * ID_A can be ACA dock too. continue
2050 * primary detection after DCD.
2051 */
2052 if (test_bit(ID_A, &motg->inputs)) {
2053 motg->chg_state = USB_CHG_STATE_WAIT_FOR_DCD;
2054 } else {
2055 delay = 0;
2056 break;
2057 }
2058 }
Pavankumar Kondeti2d09e5f2012-01-16 08:56:57 +05302059 if (motg->pdata->enable_dcd)
2060 is_dcd = msm_chg_check_dcd(motg);
Pavankumar Kondetid8608522011-05-04 10:19:47 +05302061 tmout = ++motg->dcd_retries == MSM_CHG_DCD_MAX_RETRIES;
2062 if (is_dcd || tmout) {
Pavankumar Kondeti2d09e5f2012-01-16 08:56:57 +05302063 if (motg->pdata->enable_dcd)
2064 msm_chg_disable_dcd(motg);
Pavankumar Kondetid8608522011-05-04 10:19:47 +05302065 msm_chg_enable_primary_det(motg);
2066 delay = MSM_CHG_PRIMARY_DET_TIME;
2067 motg->chg_state = USB_CHG_STATE_DCD_DONE;
2068 } else {
2069 delay = MSM_CHG_DCD_POLL_TIME;
2070 }
2071 break;
2072 case USB_CHG_STATE_DCD_DONE:
2073 vout = msm_chg_check_primary_det(motg);
Pavankumar Kondeti9ec21d32012-05-07 15:50:23 +05302074 line_state = readl_relaxed(USB_PORTSC) & PORTSC_LS;
2075 dm_vlgc = line_state & PORTSC_LS_DM;
2076 if (vout && !dm_vlgc) { /* VDAT_REF < DM < VLGC */
Pavankumar Kondetiaa449e12011-11-04 11:09:26 +05302077 if (test_bit(ID_A, &motg->inputs)) {
2078 motg->chg_type = USB_ACA_DOCK_CHARGER;
2079 motg->chg_state = USB_CHG_STATE_DETECTED;
2080 delay = 0;
2081 break;
2082 }
Pavankumar Kondeti9ec21d32012-05-07 15:50:23 +05302083 if (line_state) { /* DP > VLGC */
2084 motg->chg_type = USB_PROPRIETARY_CHARGER;
2085 motg->chg_state = USB_CHG_STATE_DETECTED;
2086 delay = 0;
2087 } else {
2088 msm_chg_enable_secondary_det(motg);
2089 delay = MSM_CHG_SECONDARY_DET_TIME;
2090 motg->chg_state = USB_CHG_STATE_PRIMARY_DONE;
2091 }
2092 } else { /* DM < VDAT_REF || DM > VLGC */
Pavankumar Kondetiaa449e12011-11-04 11:09:26 +05302093 if (test_bit(ID_A, &motg->inputs)) {
2094 motg->chg_type = USB_ACA_A_CHARGER;
2095 motg->chg_state = USB_CHG_STATE_DETECTED;
2096 delay = 0;
2097 break;
2098 }
Pavankumar Kondeti9ec21d32012-05-07 15:50:23 +05302099
2100 if (line_state) /* DP > VLGC or/and DM > VLGC */
2101 motg->chg_type = USB_PROPRIETARY_CHARGER;
2102 else
2103 motg->chg_type = USB_SDP_CHARGER;
2104
Pavankumar Kondetid8608522011-05-04 10:19:47 +05302105 motg->chg_state = USB_CHG_STATE_DETECTED;
2106 delay = 0;
2107 }
2108 break;
2109 case USB_CHG_STATE_PRIMARY_DONE:
2110 vout = msm_chg_check_secondary_det(motg);
2111 if (vout)
2112 motg->chg_type = USB_DCP_CHARGER;
2113 else
2114 motg->chg_type = USB_CDP_CHARGER;
2115 motg->chg_state = USB_CHG_STATE_SECONDARY_DONE;
2116 /* fall through */
2117 case USB_CHG_STATE_SECONDARY_DONE:
2118 motg->chg_state = USB_CHG_STATE_DETECTED;
2119 case USB_CHG_STATE_DETECTED:
2120 msm_chg_block_off(motg);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002121 msm_chg_enable_aca_det(motg);
Vijayavardhan Vennapusaa3152032012-03-05 16:29:30 +05302122 /*
2123 * Spurious interrupt is seen after enabling ACA detection
2124 * due to which charger detection fails in case of PET.
2125 * Add delay of 100 microsec to avoid that.
2126 */
2127 udelay(100);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002128 msm_chg_enable_aca_intr(motg);
Steve Mucklef132c6c2012-06-06 18:30:57 -07002129 dev_dbg(phy->dev, "chg_type = %s\n",
Anji jonnalad270e2d2011-08-09 11:28:32 +05302130 chg_to_string(motg->chg_type));
Vijayavardhan Vennapusaa3152032012-03-05 16:29:30 +05302131 queue_work(system_nrt_wq, &motg->sm_work);
Pavankumar Kondetid8608522011-05-04 10:19:47 +05302132 return;
2133 default:
2134 return;
2135 }
2136
Vijayavardhan Vennapusaa3152032012-03-05 16:29:30 +05302137 queue_delayed_work(system_nrt_wq, &motg->chg_work, delay);
Pavankumar Kondetid8608522011-05-04 10:19:47 +05302138}
2139
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05302140/*
2141 * We support OTG, Peripheral only and Host only configurations. In case
2142 * of OTG, mode switch (host-->peripheral/peripheral-->host) can happen
2143 * via Id pin status or user request (debugfs). Id/BSV interrupts are not
2144 * enabled when switch is controlled by user and default mode is supplied
2145 * by board file, which can be changed by userspace later.
2146 */
2147static void msm_otg_init_sm(struct msm_otg *motg)
2148{
2149 struct msm_otg_platform_data *pdata = motg->pdata;
2150 u32 otgsc = readl(USB_OTGSC);
2151
2152 switch (pdata->mode) {
2153 case USB_OTG:
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002154 if (pdata->otg_control == OTG_USER_CONTROL) {
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05302155 if (pdata->default_mode == USB_HOST) {
2156 clear_bit(ID, &motg->inputs);
2157 } else if (pdata->default_mode == USB_PERIPHERAL) {
2158 set_bit(ID, &motg->inputs);
2159 set_bit(B_SESS_VLD, &motg->inputs);
2160 } else {
2161 set_bit(ID, &motg->inputs);
2162 clear_bit(B_SESS_VLD, &motg->inputs);
2163 }
Pavankumar Kondeti4960f312011-12-06 15:46:14 +05302164 } else if (pdata->otg_control == OTG_PHY_CONTROL) {
Vijayavardhan Vennapusaa3152032012-03-05 16:29:30 +05302165 if (otgsc & OTGSC_ID) {
Pavankumar Kondeti4960f312011-12-06 15:46:14 +05302166 set_bit(ID, &motg->inputs);
Vijayavardhan Vennapusaa3152032012-03-05 16:29:30 +05302167 } else {
Pavankumar Kondeti4960f312011-12-06 15:46:14 +05302168 clear_bit(ID, &motg->inputs);
Vijayavardhan Vennapusaa3152032012-03-05 16:29:30 +05302169 set_bit(A_BUS_REQ, &motg->inputs);
2170 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002171 if (otgsc & OTGSC_BSV)
2172 set_bit(B_SESS_VLD, &motg->inputs);
2173 else
2174 clear_bit(B_SESS_VLD, &motg->inputs);
Pavankumar Kondeti4960f312011-12-06 15:46:14 +05302175 } else if (pdata->otg_control == OTG_PMIC_CONTROL) {
Pavankumar Kondeti0d81f312012-01-13 11:34:10 +05302176 if (pdata->pmic_id_irq) {
Stephen Boyd431771e2012-04-18 20:00:23 -07002177 unsigned long flags;
2178 local_irq_save(flags);
Pavankumar Kondeti0d81f312012-01-13 11:34:10 +05302179 if (irq_read_line(pdata->pmic_id_irq))
2180 set_bit(ID, &motg->inputs);
2181 else
2182 clear_bit(ID, &motg->inputs);
Stephen Boyd431771e2012-04-18 20:00:23 -07002183 local_irq_restore(flags);
Pavankumar Kondeti0d81f312012-01-13 11:34:10 +05302184 }
Pavankumar Kondeti4960f312011-12-06 15:46:14 +05302185 /*
2186 * VBUS initial state is reported after PMIC
2187 * driver initialization. Wait for it.
2188 */
2189 wait_for_completion(&pmic_vbus_init);
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05302190 }
2191 break;
2192 case USB_HOST:
2193 clear_bit(ID, &motg->inputs);
2194 break;
2195 case USB_PERIPHERAL:
2196 set_bit(ID, &motg->inputs);
Pavankumar Kondeti0d81f312012-01-13 11:34:10 +05302197 if (pdata->otg_control == OTG_PHY_CONTROL) {
2198 if (otgsc & OTGSC_BSV)
2199 set_bit(B_SESS_VLD, &motg->inputs);
2200 else
2201 clear_bit(B_SESS_VLD, &motg->inputs);
2202 } else if (pdata->otg_control == OTG_PMIC_CONTROL) {
2203 /*
2204 * VBUS initial state is reported after PMIC
2205 * driver initialization. Wait for it.
2206 */
2207 wait_for_completion(&pmic_vbus_init);
2208 }
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05302209 break;
2210 default:
2211 break;
2212 }
2213}
2214
2215static void msm_otg_sm_work(struct work_struct *w)
2216{
2217 struct msm_otg *motg = container_of(w, struct msm_otg, sm_work);
Heikki Krogerus1d4c9292012-02-13 13:24:09 +02002218 struct usb_otg *otg = motg->phy.otg;
Vijayavardhan Vennapusaa3152032012-03-05 16:29:30 +05302219 bool work = 0, srp_reqd;
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05302220
Steve Mucklef132c6c2012-06-06 18:30:57 -07002221 pm_runtime_resume(otg->phy->dev);
2222 pr_debug("%s work\n", otg_state_string(otg->phy->state));
Heikki Krogerus1d4c9292012-02-13 13:24:09 +02002223 switch (otg->phy->state) {
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05302224 case OTG_STATE_UNDEFINED:
Heikki Krogerus1d4c9292012-02-13 13:24:09 +02002225 msm_otg_reset(otg->phy);
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05302226 msm_otg_init_sm(motg);
Vijayavardhan Vennapusa05c437c2012-05-25 16:20:46 +05302227 psy = power_supply_get_by_name("usb");
2228 if (!psy)
2229 pr_err("couldn't get usb power supply\n");
Heikki Krogerus1d4c9292012-02-13 13:24:09 +02002230 otg->phy->state = OTG_STATE_B_IDLE;
Pavankumar Kondeti8a379b42011-12-12 13:07:23 +05302231 if (!test_bit(B_SESS_VLD, &motg->inputs) &&
2232 test_bit(ID, &motg->inputs)) {
Steve Mucklef132c6c2012-06-06 18:30:57 -07002233 pm_runtime_put_noidle(otg->phy->dev);
2234 pm_runtime_suspend(otg->phy->dev);
Pavankumar Kondeti8a379b42011-12-12 13:07:23 +05302235 break;
2236 }
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05302237 /* FALL THROUGH */
2238 case OTG_STATE_B_IDLE:
Pavankumar Kondeti2aec9f32012-06-13 09:06:03 +05302239 if (test_bit(MHL, &motg->inputs)) {
2240 /* allow LPM */
2241 pm_runtime_put_noidle(otg->phy->dev);
2242 pm_runtime_suspend(otg->phy->dev);
2243 } else if ((!test_bit(ID, &motg->inputs) ||
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002244 test_bit(ID_A, &motg->inputs)) && otg->host) {
Vijayavardhan Vennapusaa3152032012-03-05 16:29:30 +05302245 pr_debug("!id || id_A\n");
jh.koo78df86f2012-09-04 20:13:19 +09002246 if (slimport_is_connected()) {
2247 work = 1;
2248 break;
2249 }
Pavankumar Kondeti2aec9f32012-06-13 09:06:03 +05302250 if (msm_chg_mhl_detect(motg)) {
2251 work = 1;
2252 break;
2253 }
Vijayavardhan Vennapusaa3152032012-03-05 16:29:30 +05302254 clear_bit(B_BUS_REQ, &motg->inputs);
2255 set_bit(A_BUS_REQ, &motg->inputs);
Steve Mucklef132c6c2012-06-06 18:30:57 -07002256 otg->phy->state = OTG_STATE_A_IDLE;
Vijayavardhan Vennapusaa3152032012-03-05 16:29:30 +05302257 work = 1;
Pavankumar Kondetid8608522011-05-04 10:19:47 +05302258 } else if (test_bit(B_SESS_VLD, &motg->inputs)) {
Vijayavardhan Vennapusaa3152032012-03-05 16:29:30 +05302259 pr_debug("b_sess_vld\n");
Pavankumar Kondetid8608522011-05-04 10:19:47 +05302260 switch (motg->chg_state) {
2261 case USB_CHG_STATE_UNDEFINED:
2262 msm_chg_detect_work(&motg->chg_work.work);
2263 break;
2264 case USB_CHG_STATE_DETECTED:
2265 switch (motg->chg_type) {
2266 case USB_DCP_CHARGER:
Pavankumar Kondeti283146f2012-01-12 12:51:19 +05302267 /* Enable VDP_SRC */
Steve Mucklef132c6c2012-06-06 18:30:57 -07002268 ulpi_write(otg->phy, 0x2, 0x85);
Pavankumar Kondeti9ec21d32012-05-07 15:50:23 +05302269 /* fall through */
2270 case USB_PROPRIETARY_CHARGER:
Pavankumar Kondetid8608522011-05-04 10:19:47 +05302271 msm_otg_notify_charger(motg,
2272 IDEV_CHG_MAX);
Steve Mucklef132c6c2012-06-06 18:30:57 -07002273 pm_runtime_put_noidle(otg->phy->dev);
2274 pm_runtime_suspend(otg->phy->dev);
Pavankumar Kondetid8608522011-05-04 10:19:47 +05302275 break;
Pavankumar Kondetiaa449e12011-11-04 11:09:26 +05302276 case USB_ACA_B_CHARGER:
2277 msm_otg_notify_charger(motg,
2278 IDEV_ACA_CHG_MAX);
2279 /*
2280 * (ID_B --> ID_C) PHY_ALT interrupt can
2281 * not be detected in LPM.
2282 */
Pavankumar Kondetid8608522011-05-04 10:19:47 +05302283 break;
2284 case USB_CDP_CHARGER:
2285 msm_otg_notify_charger(motg,
2286 IDEV_CHG_MAX);
2287 msm_otg_start_peripheral(otg, 1);
Steve Mucklef132c6c2012-06-06 18:30:57 -07002288 otg->phy->state =
2289 OTG_STATE_B_PERIPHERAL;
Pavankumar Kondetid8608522011-05-04 10:19:47 +05302290 break;
Pavankumar Kondetiaa449e12011-11-04 11:09:26 +05302291 case USB_ACA_C_CHARGER:
2292 msm_otg_notify_charger(motg,
2293 IDEV_ACA_CHG_MAX);
2294 msm_otg_start_peripheral(otg, 1);
Steve Mucklef132c6c2012-06-06 18:30:57 -07002295 otg->phy->state =
2296 OTG_STATE_B_PERIPHERAL;
Pavankumar Kondetid8608522011-05-04 10:19:47 +05302297 break;
2298 case USB_SDP_CHARGER:
roy.park99cef212012-07-26 17:00:40 -07002299 msm_otg_notify_charger(motg,
2300 IDEV_CHG_MIN);
jh.koo78df86f2012-09-04 20:13:19 +09002301 if(!slimport_is_connected()) {
2302 msm_otg_start_peripheral(otg, 1);
2303 otg->phy->state =
2304 OTG_STATE_B_PERIPHERAL;
2305 }
kibum.leeec040442012-08-22 22:29:46 +09002306 schedule_delayed_work(&motg->check_ta_work,
2307 MSM_CHECK_TA_DELAY);
Pavankumar Kondetid8608522011-05-04 10:19:47 +05302308 break;
2309 default:
2310 break;
2311 }
2312 break;
2313 default:
2314 break;
2315 }
Vijayavardhan Vennapusaa3152032012-03-05 16:29:30 +05302316 } else if (test_bit(B_BUS_REQ, &motg->inputs)) {
2317 pr_debug("b_sess_end && b_bus_req\n");
2318 if (msm_otg_start_srp(otg) < 0) {
2319 clear_bit(B_BUS_REQ, &motg->inputs);
2320 work = 1;
2321 break;
Pavankumar Kondetid8608522011-05-04 10:19:47 +05302322 }
Steve Mucklef132c6c2012-06-06 18:30:57 -07002323 otg->phy->state = OTG_STATE_B_SRP_INIT;
Vijayavardhan Vennapusaa3152032012-03-05 16:29:30 +05302324 msm_otg_start_timer(motg, TB_SRP_FAIL, B_SRP_FAIL);
2325 break;
Pavankumar Kondetid8608522011-05-04 10:19:47 +05302326 } else {
Vijayavardhan Vennapusaa3152032012-03-05 16:29:30 +05302327 pr_debug("chg_work cancel");
Pavankumar Kondetiaa449e12011-11-04 11:09:26 +05302328 cancel_delayed_work_sync(&motg->chg_work);
kibum.leeec040442012-08-22 22:29:46 +09002329 cancel_delayed_work_sync(&motg->check_ta_work);
Pavankumar Kondetid8608522011-05-04 10:19:47 +05302330 motg->chg_state = USB_CHG_STATE_UNDEFINED;
2331 motg->chg_type = USB_INVALID_CHARGER;
Rajkumar Raghupathy18fd7132012-04-20 11:28:13 +05302332 msm_otg_notify_charger(motg, 0);
Steve Mucklef132c6c2012-06-06 18:30:57 -07002333 msm_otg_reset(otg->phy);
2334 pm_runtime_put_noidle(otg->phy->dev);
2335 pm_runtime_suspend(otg->phy->dev);
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05302336 }
2337 break;
Vijayavardhan Vennapusaa3152032012-03-05 16:29:30 +05302338 case OTG_STATE_B_SRP_INIT:
2339 if (!test_bit(ID, &motg->inputs) ||
2340 test_bit(ID_A, &motg->inputs) ||
2341 test_bit(ID_C, &motg->inputs) ||
2342 (test_bit(B_SESS_VLD, &motg->inputs) &&
2343 !test_bit(ID_B, &motg->inputs))) {
2344 pr_debug("!id || id_a/c || b_sess_vld+!id_b\n");
2345 msm_otg_del_timer(motg);
Steve Mucklef132c6c2012-06-06 18:30:57 -07002346 otg->phy->state = OTG_STATE_B_IDLE;
Vijayavardhan Vennapusaa3152032012-03-05 16:29:30 +05302347 /*
2348 * clear VBUSVLDEXTSEL and VBUSVLDEXT register
2349 * bits after SRP initiation.
2350 */
Steve Mucklef132c6c2012-06-06 18:30:57 -07002351 ulpi_write(otg->phy, 0x0, 0x98);
Vijayavardhan Vennapusaa3152032012-03-05 16:29:30 +05302352 work = 1;
2353 } else if (test_bit(B_SRP_FAIL, &motg->tmouts)) {
2354 pr_debug("b_srp_fail\n");
2355 pr_info("A-device did not respond to SRP\n");
2356 clear_bit(B_BUS_REQ, &motg->inputs);
2357 clear_bit(B_SRP_FAIL, &motg->tmouts);
2358 otg_send_event(OTG_EVENT_NO_RESP_FOR_SRP);
Steve Mucklef132c6c2012-06-06 18:30:57 -07002359 ulpi_write(otg->phy, 0x0, 0x98);
2360 otg->phy->state = OTG_STATE_B_IDLE;
Vijayavardhan Vennapusaa3152032012-03-05 16:29:30 +05302361 motg->b_last_se0_sess = jiffies;
2362 work = 1;
2363 }
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05302364 break;
2365 case OTG_STATE_B_PERIPHERAL:
Vijayavardhan Vennapusaa3152032012-03-05 16:29:30 +05302366 if (!test_bit(ID, &motg->inputs) ||
2367 test_bit(ID_A, &motg->inputs) ||
2368 test_bit(ID_B, &motg->inputs) ||
2369 !test_bit(B_SESS_VLD, &motg->inputs)) {
2370 pr_debug("!id || id_a/b || !b_sess_vld\n");
Pavankumar Kondetid8608522011-05-04 10:19:47 +05302371 motg->chg_state = USB_CHG_STATE_UNDEFINED;
2372 motg->chg_type = USB_INVALID_CHARGER;
Vijayavardhan Vennapusaa3152032012-03-05 16:29:30 +05302373 msm_otg_notify_charger(motg, 0);
2374 srp_reqd = otg->gadget->otg_srp_reqd;
2375 msm_otg_start_peripheral(otg, 0);
Vijayavardhan Vennapusaa3152032012-03-05 16:29:30 +05302376 if (test_bit(ID_B, &motg->inputs))
2377 clear_bit(ID_B, &motg->inputs);
2378 clear_bit(B_BUS_REQ, &motg->inputs);
Steve Mucklef132c6c2012-06-06 18:30:57 -07002379 otg->phy->state = OTG_STATE_B_IDLE;
Vijayavardhan Vennapusaa3152032012-03-05 16:29:30 +05302380 motg->b_last_se0_sess = jiffies;
2381 if (srp_reqd)
2382 msm_otg_start_timer(motg,
2383 TB_TST_SRP, B_TST_SRP);
2384 else
2385 work = 1;
2386 } else if (test_bit(B_BUS_REQ, &motg->inputs) &&
2387 otg->gadget->b_hnp_enable &&
2388 test_bit(A_BUS_SUSPEND, &motg->inputs)) {
2389 pr_debug("b_bus_req && b_hnp_en && a_bus_suspend\n");
2390 msm_otg_start_timer(motg, TB_ASE0_BRST, B_ASE0_BRST);
2391 /* D+ pullup should not be disconnected within 4msec
2392 * after A device suspends the bus. Otherwise PET will
2393 * fail the compliance test.
2394 */
2395 udelay(1000);
2396 msm_otg_start_peripheral(otg, 0);
Steve Mucklef132c6c2012-06-06 18:30:57 -07002397 otg->phy->state = OTG_STATE_B_WAIT_ACON;
Vijayavardhan Vennapusaa3152032012-03-05 16:29:30 +05302398 /*
2399 * start HCD even before A-device enable
2400 * pull-up to meet HNP timings.
2401 */
2402 otg->host->is_b_host = 1;
2403 msm_otg_start_host(otg, 1);
Amit Blay6fa647a2012-05-24 14:12:08 +03002404 } else if (test_bit(A_BUS_SUSPEND, &motg->inputs) &&
2405 test_bit(B_SESS_VLD, &motg->inputs)) {
2406 pr_debug("a_bus_suspend && b_sess_vld\n");
2407 if (motg->caps & ALLOW_LPM_ON_DEV_SUSPEND) {
Steve Mucklef132c6c2012-06-06 18:30:57 -07002408 pm_runtime_put_noidle(otg->phy->dev);
2409 pm_runtime_suspend(otg->phy->dev);
Amit Blay6fa647a2012-05-24 14:12:08 +03002410 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002411 } else if (test_bit(ID_C, &motg->inputs)) {
Pavankumar Kondetiaa449e12011-11-04 11:09:26 +05302412 msm_otg_notify_charger(motg, IDEV_ACA_CHG_MAX);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002413 }
2414 break;
Vijayavardhan Vennapusaa3152032012-03-05 16:29:30 +05302415 case OTG_STATE_B_WAIT_ACON:
2416 if (!test_bit(ID, &motg->inputs) ||
2417 test_bit(ID_A, &motg->inputs) ||
2418 test_bit(ID_B, &motg->inputs) ||
2419 !test_bit(B_SESS_VLD, &motg->inputs)) {
2420 pr_debug("!id || id_a/b || !b_sess_vld\n");
2421 msm_otg_del_timer(motg);
Pavankumar Kondetiaa449e12011-11-04 11:09:26 +05302422 /*
Vijayavardhan Vennapusaa3152032012-03-05 16:29:30 +05302423 * A-device is physically disconnected during
2424 * HNP. Remove HCD.
Pavankumar Kondetiaa449e12011-11-04 11:09:26 +05302425 */
Vijayavardhan Vennapusaa3152032012-03-05 16:29:30 +05302426 msm_otg_start_host(otg, 0);
2427 otg->host->is_b_host = 0;
2428
2429 clear_bit(B_BUS_REQ, &motg->inputs);
2430 clear_bit(A_BUS_SUSPEND, &motg->inputs);
2431 motg->b_last_se0_sess = jiffies;
Heikki Krogerus1d4c9292012-02-13 13:24:09 +02002432 otg->phy->state = OTG_STATE_B_IDLE;
2433 msm_otg_reset(otg->phy);
Vijayavardhan Vennapusaa3152032012-03-05 16:29:30 +05302434 work = 1;
2435 } else if (test_bit(A_CONN, &motg->inputs)) {
2436 pr_debug("a_conn\n");
2437 clear_bit(A_BUS_SUSPEND, &motg->inputs);
Steve Mucklef132c6c2012-06-06 18:30:57 -07002438 otg->phy->state = OTG_STATE_B_HOST;
Vijayavardhan Vennapusaa3152032012-03-05 16:29:30 +05302439 /*
2440 * PET disconnects D+ pullup after reset is generated
2441 * by B device in B_HOST role which is not detected by
2442 * B device. As workaorund , start timer of 300msec
2443 * and stop timer if A device is enumerated else clear
2444 * A_CONN.
2445 */
2446 msm_otg_start_timer(motg, TB_TST_CONFIG,
2447 B_TST_CONFIG);
2448 } else if (test_bit(B_ASE0_BRST, &motg->tmouts)) {
2449 pr_debug("b_ase0_brst_tmout\n");
2450 pr_info("B HNP fail:No response from A device\n");
2451 msm_otg_start_host(otg, 0);
Steve Mucklef132c6c2012-06-06 18:30:57 -07002452 msm_otg_reset(otg->phy);
Vijayavardhan Vennapusaa3152032012-03-05 16:29:30 +05302453 otg->host->is_b_host = 0;
2454 clear_bit(B_ASE0_BRST, &motg->tmouts);
2455 clear_bit(A_BUS_SUSPEND, &motg->inputs);
2456 clear_bit(B_BUS_REQ, &motg->inputs);
2457 otg_send_event(OTG_EVENT_HNP_FAILED);
Steve Mucklef132c6c2012-06-06 18:30:57 -07002458 otg->phy->state = OTG_STATE_B_IDLE;
Vijayavardhan Vennapusaa3152032012-03-05 16:29:30 +05302459 work = 1;
2460 } else if (test_bit(ID_C, &motg->inputs)) {
2461 msm_otg_notify_charger(motg, IDEV_ACA_CHG_MAX);
2462 }
2463 break;
2464 case OTG_STATE_B_HOST:
2465 if (!test_bit(B_BUS_REQ, &motg->inputs) ||
2466 !test_bit(A_CONN, &motg->inputs) ||
2467 !test_bit(B_SESS_VLD, &motg->inputs)) {
2468 pr_debug("!b_bus_req || !a_conn || !b_sess_vld\n");
2469 clear_bit(A_CONN, &motg->inputs);
2470 clear_bit(B_BUS_REQ, &motg->inputs);
2471 msm_otg_start_host(otg, 0);
2472 otg->host->is_b_host = 0;
Steve Mucklef132c6c2012-06-06 18:30:57 -07002473 otg->phy->state = OTG_STATE_B_IDLE;
2474 msm_otg_reset(otg->phy);
Vijayavardhan Vennapusaa3152032012-03-05 16:29:30 +05302475 work = 1;
2476 } else if (test_bit(ID_C, &motg->inputs)) {
2477 msm_otg_notify_charger(motg, IDEV_ACA_CHG_MAX);
2478 }
2479 break;
2480 case OTG_STATE_A_IDLE:
2481 otg->default_a = 1;
2482 if (test_bit(ID, &motg->inputs) &&
2483 !test_bit(ID_A, &motg->inputs)) {
2484 pr_debug("id && !id_a\n");
2485 otg->default_a = 0;
2486 clear_bit(A_BUS_DROP, &motg->inputs);
Steve Mucklef132c6c2012-06-06 18:30:57 -07002487 otg->phy->state = OTG_STATE_B_IDLE;
Vijayavardhan Vennapusaa3152032012-03-05 16:29:30 +05302488 del_timer_sync(&motg->id_timer);
2489 msm_otg_link_reset(motg);
2490 msm_chg_enable_aca_intr(motg);
2491 msm_otg_notify_charger(motg, 0);
2492 work = 1;
2493 } else if (!test_bit(A_BUS_DROP, &motg->inputs) &&
2494 (test_bit(A_SRP_DET, &motg->inputs) ||
2495 test_bit(A_BUS_REQ, &motg->inputs))) {
2496 pr_debug("!a_bus_drop && (a_srp_det || a_bus_req)\n");
2497
2498 clear_bit(A_SRP_DET, &motg->inputs);
2499 /* Disable SRP detection */
2500 writel_relaxed((readl_relaxed(USB_OTGSC) &
2501 ~OTGSC_INTSTS_MASK) &
2502 ~OTGSC_DPIE, USB_OTGSC);
2503
Steve Mucklef132c6c2012-06-06 18:30:57 -07002504 otg->phy->state = OTG_STATE_A_WAIT_VRISE;
Vijayavardhan Vennapusaa3152032012-03-05 16:29:30 +05302505 /* VBUS should not be supplied before end of SRP pulse
2506 * generated by PET, if not complaince test fail.
2507 */
2508 usleep_range(10000, 12000);
2509 /* ACA: ID_A: Stop charging untill enumeration */
2510 if (test_bit(ID_A, &motg->inputs))
2511 msm_otg_notify_charger(motg, 0);
2512 else
2513 msm_hsusb_vbus_power(motg, 1);
2514 msm_otg_start_timer(motg, TA_WAIT_VRISE, A_WAIT_VRISE);
2515 } else {
2516 pr_debug("No session requested\n");
2517 clear_bit(A_BUS_DROP, &motg->inputs);
2518 if (test_bit(ID_A, &motg->inputs)) {
2519 msm_otg_notify_charger(motg,
2520 IDEV_ACA_CHG_MAX);
2521 } else if (!test_bit(ID, &motg->inputs)) {
2522 msm_otg_notify_charger(motg, 0);
2523 /*
2524 * A-device is not providing power on VBUS.
2525 * Enable SRP detection.
2526 */
2527 writel_relaxed(0x13, USB_USBMODE);
2528 writel_relaxed((readl_relaxed(USB_OTGSC) &
2529 ~OTGSC_INTSTS_MASK) |
2530 OTGSC_DPIE, USB_OTGSC);
2531 mb();
2532 }
2533 }
2534 break;
2535 case OTG_STATE_A_WAIT_VRISE:
2536 if ((test_bit(ID, &motg->inputs) &&
2537 !test_bit(ID_A, &motg->inputs)) ||
2538 test_bit(A_BUS_DROP, &motg->inputs) ||
2539 test_bit(A_WAIT_VRISE, &motg->tmouts)) {
2540 pr_debug("id || a_bus_drop || a_wait_vrise_tmout\n");
2541 clear_bit(A_BUS_REQ, &motg->inputs);
2542 msm_otg_del_timer(motg);
2543 msm_hsusb_vbus_power(motg, 0);
Steve Mucklef132c6c2012-06-06 18:30:57 -07002544 otg->phy->state = OTG_STATE_A_WAIT_VFALL;
Vijayavardhan Vennapusaa3152032012-03-05 16:29:30 +05302545 msm_otg_start_timer(motg, TA_WAIT_VFALL, A_WAIT_VFALL);
2546 } else if (test_bit(A_VBUS_VLD, &motg->inputs)) {
2547 pr_debug("a_vbus_vld\n");
Steve Mucklef132c6c2012-06-06 18:30:57 -07002548 otg->phy->state = OTG_STATE_A_WAIT_BCON;
Vijayavardhan Vennapusaa3152032012-03-05 16:29:30 +05302549 if (TA_WAIT_BCON > 0)
2550 msm_otg_start_timer(motg, TA_WAIT_BCON,
2551 A_WAIT_BCON);
2552 msm_otg_start_host(otg, 1);
2553 msm_chg_enable_aca_det(motg);
2554 msm_chg_disable_aca_intr(motg);
Chiranjeevi Velempati489a27c2012-03-29 09:47:17 +05302555 mod_timer(&motg->id_timer, ID_TIMER_FREQ);
Vijayavardhan Vennapusaa3152032012-03-05 16:29:30 +05302556 if (msm_chg_check_aca_intr(motg))
2557 work = 1;
2558 }
2559 break;
2560 case OTG_STATE_A_WAIT_BCON:
2561 if ((test_bit(ID, &motg->inputs) &&
2562 !test_bit(ID_A, &motg->inputs)) ||
2563 test_bit(A_BUS_DROP, &motg->inputs) ||
2564 test_bit(A_WAIT_BCON, &motg->tmouts)) {
2565 pr_debug("(id && id_a/b/c) || a_bus_drop ||"
2566 "a_wait_bcon_tmout\n");
2567 if (test_bit(A_WAIT_BCON, &motg->tmouts)) {
2568 pr_info("Device No Response\n");
2569 otg_send_event(OTG_EVENT_DEV_CONN_TMOUT);
2570 }
2571 msm_otg_del_timer(motg);
2572 clear_bit(A_BUS_REQ, &motg->inputs);
2573 clear_bit(B_CONN, &motg->inputs);
2574 msm_otg_start_host(otg, 0);
2575 /*
2576 * ACA: ID_A with NO accessory, just the A plug is
2577 * attached to ACA: Use IDCHG_MAX for charging
2578 */
2579 if (test_bit(ID_A, &motg->inputs))
2580 msm_otg_notify_charger(motg, IDEV_CHG_MIN);
2581 else
2582 msm_hsusb_vbus_power(motg, 0);
Steve Mucklef132c6c2012-06-06 18:30:57 -07002583 otg->phy->state = OTG_STATE_A_WAIT_VFALL;
Vijayavardhan Vennapusaa3152032012-03-05 16:29:30 +05302584 msm_otg_start_timer(motg, TA_WAIT_VFALL, A_WAIT_VFALL);
2585 } else if (!test_bit(A_VBUS_VLD, &motg->inputs)) {
2586 pr_debug("!a_vbus_vld\n");
2587 clear_bit(B_CONN, &motg->inputs);
2588 msm_otg_del_timer(motg);
2589 msm_otg_start_host(otg, 0);
Steve Mucklef132c6c2012-06-06 18:30:57 -07002590 otg->phy->state = OTG_STATE_A_VBUS_ERR;
2591 msm_otg_reset(otg->phy);
Vijayavardhan Vennapusaa3152032012-03-05 16:29:30 +05302592 } else if (test_bit(ID_A, &motg->inputs)) {
2593 msm_hsusb_vbus_power(motg, 0);
2594 } else if (!test_bit(A_BUS_REQ, &motg->inputs)) {
2595 /*
2596 * If TA_WAIT_BCON is infinite, we don;t
2597 * turn off VBUS. Enter low power mode.
2598 */
2599 if (TA_WAIT_BCON < 0)
Steve Mucklef132c6c2012-06-06 18:30:57 -07002600 pm_runtime_put_sync(otg->phy->dev);
Vijayavardhan Vennapusaa3152032012-03-05 16:29:30 +05302601 } else if (!test_bit(ID, &motg->inputs)) {
2602 msm_hsusb_vbus_power(motg, 1);
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05302603 }
2604 break;
2605 case OTG_STATE_A_HOST:
Vijayavardhan Vennapusaa3152032012-03-05 16:29:30 +05302606 if ((test_bit(ID, &motg->inputs) &&
2607 !test_bit(ID_A, &motg->inputs)) ||
2608 test_bit(A_BUS_DROP, &motg->inputs)) {
2609 pr_debug("id_a/b/c || a_bus_drop\n");
2610 clear_bit(B_CONN, &motg->inputs);
2611 clear_bit(A_BUS_REQ, &motg->inputs);
2612 msm_otg_del_timer(motg);
Steve Mucklef132c6c2012-06-06 18:30:57 -07002613 otg->phy->state = OTG_STATE_A_WAIT_VFALL;
Vijayavardhan Vennapusaa3152032012-03-05 16:29:30 +05302614 msm_otg_start_host(otg, 0);
2615 if (!test_bit(ID_A, &motg->inputs))
2616 msm_hsusb_vbus_power(motg, 0);
2617 msm_otg_start_timer(motg, TA_WAIT_VFALL, A_WAIT_VFALL);
2618 } else if (!test_bit(A_VBUS_VLD, &motg->inputs)) {
2619 pr_debug("!a_vbus_vld\n");
2620 clear_bit(B_CONN, &motg->inputs);
2621 msm_otg_del_timer(motg);
Steve Mucklef132c6c2012-06-06 18:30:57 -07002622 otg->phy->state = OTG_STATE_A_VBUS_ERR;
Vijayavardhan Vennapusaa3152032012-03-05 16:29:30 +05302623 msm_otg_start_host(otg, 0);
Heikki Krogerus1d4c9292012-02-13 13:24:09 +02002624 msm_otg_reset(otg->phy);
Vijayavardhan Vennapusaa3152032012-03-05 16:29:30 +05302625 } else if (!test_bit(A_BUS_REQ, &motg->inputs)) {
2626 /*
2627 * a_bus_req is de-asserted when root hub is
2628 * suspended or HNP is in progress.
2629 */
2630 pr_debug("!a_bus_req\n");
2631 msm_otg_del_timer(motg);
Steve Mucklef132c6c2012-06-06 18:30:57 -07002632 otg->phy->state = OTG_STATE_A_SUSPEND;
Vijayavardhan Vennapusaa3152032012-03-05 16:29:30 +05302633 if (otg->host->b_hnp_enable)
2634 msm_otg_start_timer(motg, TA_AIDL_BDIS,
2635 A_AIDL_BDIS);
2636 else
Steve Mucklef132c6c2012-06-06 18:30:57 -07002637 pm_runtime_put_sync(otg->phy->dev);
Vijayavardhan Vennapusaa3152032012-03-05 16:29:30 +05302638 } else if (!test_bit(B_CONN, &motg->inputs)) {
2639 pr_debug("!b_conn\n");
2640 msm_otg_del_timer(motg);
Steve Mucklef132c6c2012-06-06 18:30:57 -07002641 otg->phy->state = OTG_STATE_A_WAIT_BCON;
Vijayavardhan Vennapusaa3152032012-03-05 16:29:30 +05302642 if (TA_WAIT_BCON > 0)
2643 msm_otg_start_timer(motg, TA_WAIT_BCON,
2644 A_WAIT_BCON);
2645 if (msm_chg_check_aca_intr(motg))
2646 work = 1;
2647 } else if (test_bit(ID_A, &motg->inputs)) {
2648 msm_otg_del_timer(motg);
2649 msm_hsusb_vbus_power(motg, 0);
2650 if (motg->chg_type == USB_ACA_DOCK_CHARGER)
2651 msm_otg_notify_charger(motg,
2652 IDEV_ACA_CHG_MAX);
2653 else
2654 msm_otg_notify_charger(motg,
2655 IDEV_CHG_MIN - motg->mA_port);
2656 } else if (!test_bit(ID, &motg->inputs)) {
2657 motg->chg_state = USB_CHG_STATE_UNDEFINED;
2658 motg->chg_type = USB_INVALID_CHARGER;
2659 msm_otg_notify_charger(motg, 0);
2660 msm_hsusb_vbus_power(motg, 1);
2661 }
2662 break;
2663 case OTG_STATE_A_SUSPEND:
2664 if ((test_bit(ID, &motg->inputs) &&
2665 !test_bit(ID_A, &motg->inputs)) ||
2666 test_bit(A_BUS_DROP, &motg->inputs) ||
2667 test_bit(A_AIDL_BDIS, &motg->tmouts)) {
2668 pr_debug("id_a/b/c || a_bus_drop ||"
2669 "a_aidl_bdis_tmout\n");
2670 msm_otg_del_timer(motg);
2671 clear_bit(B_CONN, &motg->inputs);
Steve Mucklef132c6c2012-06-06 18:30:57 -07002672 otg->phy->state = OTG_STATE_A_WAIT_VFALL;
Vijayavardhan Vennapusaa3152032012-03-05 16:29:30 +05302673 msm_otg_start_host(otg, 0);
Steve Mucklef132c6c2012-06-06 18:30:57 -07002674 msm_otg_reset(otg->phy);
Vijayavardhan Vennapusaa3152032012-03-05 16:29:30 +05302675 if (!test_bit(ID_A, &motg->inputs))
2676 msm_hsusb_vbus_power(motg, 0);
2677 msm_otg_start_timer(motg, TA_WAIT_VFALL, A_WAIT_VFALL);
2678 } else if (!test_bit(A_VBUS_VLD, &motg->inputs)) {
2679 pr_debug("!a_vbus_vld\n");
2680 msm_otg_del_timer(motg);
2681 clear_bit(B_CONN, &motg->inputs);
Steve Mucklef132c6c2012-06-06 18:30:57 -07002682 otg->phy->state = OTG_STATE_A_VBUS_ERR;
Vijayavardhan Vennapusaa3152032012-03-05 16:29:30 +05302683 msm_otg_start_host(otg, 0);
Steve Mucklef132c6c2012-06-06 18:30:57 -07002684 msm_otg_reset(otg->phy);
Vijayavardhan Vennapusaa3152032012-03-05 16:29:30 +05302685 } else if (!test_bit(B_CONN, &motg->inputs) &&
2686 otg->host->b_hnp_enable) {
2687 pr_debug("!b_conn && b_hnp_enable");
Steve Mucklef132c6c2012-06-06 18:30:57 -07002688 otg->phy->state = OTG_STATE_A_PERIPHERAL;
Vijayavardhan Vennapusaa3152032012-03-05 16:29:30 +05302689 msm_otg_host_hnp_enable(otg, 1);
2690 otg->gadget->is_a_peripheral = 1;
2691 msm_otg_start_peripheral(otg, 1);
2692 } else if (!test_bit(B_CONN, &motg->inputs) &&
2693 !otg->host->b_hnp_enable) {
2694 pr_debug("!b_conn && !b_hnp_enable");
2695 /*
2696 * bus request is dropped during suspend.
2697 * acquire again for next device.
2698 */
2699 set_bit(A_BUS_REQ, &motg->inputs);
Steve Mucklef132c6c2012-06-06 18:30:57 -07002700 otg->phy->state = OTG_STATE_A_WAIT_BCON;
Vijayavardhan Vennapusaa3152032012-03-05 16:29:30 +05302701 if (TA_WAIT_BCON > 0)
2702 msm_otg_start_timer(motg, TA_WAIT_BCON,
2703 A_WAIT_BCON);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002704 } else if (test_bit(ID_A, &motg->inputs)) {
Mayank Ranae3926882011-12-26 09:47:54 +05302705 msm_hsusb_vbus_power(motg, 0);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002706 msm_otg_notify_charger(motg,
Vijayavardhan Vennapusaa3152032012-03-05 16:29:30 +05302707 IDEV_CHG_MIN - motg->mA_port);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002708 } else if (!test_bit(ID, &motg->inputs)) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002709 msm_otg_notify_charger(motg, 0);
Mayank Ranae3926882011-12-26 09:47:54 +05302710 msm_hsusb_vbus_power(motg, 1);
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05302711 }
2712 break;
Vijayavardhan Vennapusaa3152032012-03-05 16:29:30 +05302713 case OTG_STATE_A_PERIPHERAL:
2714 if ((test_bit(ID, &motg->inputs) &&
2715 !test_bit(ID_A, &motg->inputs)) ||
2716 test_bit(A_BUS_DROP, &motg->inputs)) {
2717 pr_debug("id _f/b/c || a_bus_drop\n");
2718 /* Clear BIDL_ADIS timer */
2719 msm_otg_del_timer(motg);
Steve Mucklef132c6c2012-06-06 18:30:57 -07002720 otg->phy->state = OTG_STATE_A_WAIT_VFALL;
Vijayavardhan Vennapusaa3152032012-03-05 16:29:30 +05302721 msm_otg_start_peripheral(otg, 0);
2722 otg->gadget->is_a_peripheral = 0;
2723 msm_otg_start_host(otg, 0);
Steve Mucklef132c6c2012-06-06 18:30:57 -07002724 msm_otg_reset(otg->phy);
Vijayavardhan Vennapusaa3152032012-03-05 16:29:30 +05302725 if (!test_bit(ID_A, &motg->inputs))
2726 msm_hsusb_vbus_power(motg, 0);
2727 msm_otg_start_timer(motg, TA_WAIT_VFALL, A_WAIT_VFALL);
2728 } else if (!test_bit(A_VBUS_VLD, &motg->inputs)) {
2729 pr_debug("!a_vbus_vld\n");
2730 /* Clear BIDL_ADIS timer */
2731 msm_otg_del_timer(motg);
Steve Mucklef132c6c2012-06-06 18:30:57 -07002732 otg->phy->state = OTG_STATE_A_VBUS_ERR;
Vijayavardhan Vennapusaa3152032012-03-05 16:29:30 +05302733 msm_otg_start_peripheral(otg, 0);
2734 otg->gadget->is_a_peripheral = 0;
2735 msm_otg_start_host(otg, 0);
2736 } else if (test_bit(A_BIDL_ADIS, &motg->tmouts)) {
2737 pr_debug("a_bidl_adis_tmout\n");
2738 msm_otg_start_peripheral(otg, 0);
2739 otg->gadget->is_a_peripheral = 0;
Steve Mucklef132c6c2012-06-06 18:30:57 -07002740 otg->phy->state = OTG_STATE_A_WAIT_BCON;
Vijayavardhan Vennapusaa3152032012-03-05 16:29:30 +05302741 set_bit(A_BUS_REQ, &motg->inputs);
2742 msm_otg_host_hnp_enable(otg, 0);
2743 if (TA_WAIT_BCON > 0)
2744 msm_otg_start_timer(motg, TA_WAIT_BCON,
2745 A_WAIT_BCON);
2746 } else if (test_bit(ID_A, &motg->inputs)) {
2747 msm_hsusb_vbus_power(motg, 0);
2748 msm_otg_notify_charger(motg,
2749 IDEV_CHG_MIN - motg->mA_port);
2750 } else if (!test_bit(ID, &motg->inputs)) {
2751 msm_otg_notify_charger(motg, 0);
2752 msm_hsusb_vbus_power(motg, 1);
2753 }
2754 break;
2755 case OTG_STATE_A_WAIT_VFALL:
2756 if (test_bit(A_WAIT_VFALL, &motg->tmouts)) {
2757 clear_bit(A_VBUS_VLD, &motg->inputs);
Steve Mucklef132c6c2012-06-06 18:30:57 -07002758 otg->phy->state = OTG_STATE_A_IDLE;
Vijayavardhan Vennapusaa3152032012-03-05 16:29:30 +05302759 work = 1;
2760 }
2761 break;
2762 case OTG_STATE_A_VBUS_ERR:
2763 if ((test_bit(ID, &motg->inputs) &&
2764 !test_bit(ID_A, &motg->inputs)) ||
2765 test_bit(A_BUS_DROP, &motg->inputs) ||
2766 test_bit(A_CLR_ERR, &motg->inputs)) {
Steve Mucklef132c6c2012-06-06 18:30:57 -07002767 otg->phy->state = OTG_STATE_A_WAIT_VFALL;
Vijayavardhan Vennapusaa3152032012-03-05 16:29:30 +05302768 if (!test_bit(ID_A, &motg->inputs))
2769 msm_hsusb_vbus_power(motg, 0);
2770 msm_otg_start_timer(motg, TA_WAIT_VFALL, A_WAIT_VFALL);
2771 motg->chg_state = USB_CHG_STATE_UNDEFINED;
2772 motg->chg_type = USB_INVALID_CHARGER;
2773 msm_otg_notify_charger(motg, 0);
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05302774 }
2775 break;
2776 default:
2777 break;
2778 }
Vijayavardhan Vennapusaa3152032012-03-05 16:29:30 +05302779 if (work)
2780 queue_work(system_nrt_wq, &motg->sm_work);
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05302781}
2782
2783static irqreturn_t msm_otg_irq(int irq, void *data)
2784{
2785 struct msm_otg *motg = data;
Steve Mucklef132c6c2012-06-06 18:30:57 -07002786 struct usb_otg *otg = motg->phy.otg;
Vijayavardhan Vennapusaa3152032012-03-05 16:29:30 +05302787 u32 otgsc = 0, usbsts, pc;
2788 bool work = 0;
2789 irqreturn_t ret = IRQ_HANDLED;
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05302790
Pavankumar Kondeti87c01042010-12-07 17:53:58 +05302791 if (atomic_read(&motg->in_lpm)) {
Manu Gautamf8c45642012-08-10 10:20:56 -07002792 pr_debug("OTG IRQ: %d in LPM\n", irq);
Pavankumar Kondeti87c01042010-12-07 17:53:58 +05302793 disable_irq_nosync(irq);
Manu Gautamf8c45642012-08-10 10:20:56 -07002794 motg->async_int = irq;
Vijayavardhan Vennapusa6d783712012-08-06 17:18:56 +05302795 if (atomic_read(&motg->pm_suspended)) {
Jack Pham5ca279b2012-05-14 18:42:54 -07002796 motg->sm_work_pending = true;
Vijayavardhan Vennapusa6d783712012-08-06 17:18:56 +05302797 if ((otg->phy->state == OTG_STATE_A_SUSPEND) ||
2798 (otg->phy->state == OTG_STATE_A_WAIT_BCON))
2799 set_bit(A_BUS_REQ, &motg->inputs);
2800 } else {
Steve Mucklef132c6c2012-06-06 18:30:57 -07002801 pm_request_resume(otg->phy->dev);
Vijayavardhan Vennapusa6d783712012-08-06 17:18:56 +05302802 }
Pavankumar Kondeti87c01042010-12-07 17:53:58 +05302803 return IRQ_HANDLED;
2804 }
2805
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002806 usbsts = readl(USB_USBSTS);
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05302807 otgsc = readl(USB_OTGSC);
Vijayavardhan Vennapusaa3152032012-03-05 16:29:30 +05302808
2809 if (!(otgsc & OTG_OTGSTS_MASK) && !(usbsts & OTG_USBSTS_MASK))
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05302810 return IRQ_NONE;
2811
2812 if ((otgsc & OTGSC_IDIS) && (otgsc & OTGSC_IDIE)) {
Pavankumar Kondetiaa449e12011-11-04 11:09:26 +05302813 if (otgsc & OTGSC_ID) {
Vijayavardhan Vennapusaa3152032012-03-05 16:29:30 +05302814 pr_debug("Id set\n");
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05302815 set_bit(ID, &motg->inputs);
Pavankumar Kondetiaa449e12011-11-04 11:09:26 +05302816 } else {
Vijayavardhan Vennapusaa3152032012-03-05 16:29:30 +05302817 pr_debug("Id clear\n");
2818 /*
2819 * Assert a_bus_req to supply power on
2820 * VBUS when Micro/Mini-A cable is connected
2821 * with out user intervention.
2822 */
2823 set_bit(A_BUS_REQ, &motg->inputs);
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05302824 clear_bit(ID, &motg->inputs);
Pavankumar Kondetiaa449e12011-11-04 11:09:26 +05302825 msm_chg_enable_aca_det(motg);
2826 }
Vijayavardhan Vennapusaa3152032012-03-05 16:29:30 +05302827 writel_relaxed(otgsc, USB_OTGSC);
2828 work = 1;
2829 } else if (otgsc & OTGSC_DPIS) {
2830 pr_debug("DPIS detected\n");
2831 writel_relaxed(otgsc, USB_OTGSC);
2832 set_bit(A_SRP_DET, &motg->inputs);
2833 set_bit(A_BUS_REQ, &motg->inputs);
2834 work = 1;
2835 } else if (otgsc & OTGSC_BSVIS) {
2836 writel_relaxed(otgsc, USB_OTGSC);
2837 /*
2838 * BSV interrupt comes when operating as an A-device
2839 * (VBUS on/off).
2840 * But, handle BSV when charger is removed from ACA in ID_A
2841 */
Steve Mucklef132c6c2012-06-06 18:30:57 -07002842 if ((otg->phy->state >= OTG_STATE_A_IDLE) &&
Vijayavardhan Vennapusaa3152032012-03-05 16:29:30 +05302843 !test_bit(ID_A, &motg->inputs))
2844 return IRQ_HANDLED;
Pavankumar Kondetiaa449e12011-11-04 11:09:26 +05302845 if (otgsc & OTGSC_BSV) {
Vijayavardhan Vennapusaa3152032012-03-05 16:29:30 +05302846 pr_debug("BSV set\n");
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05302847 set_bit(B_SESS_VLD, &motg->inputs);
Pavankumar Kondetiaa449e12011-11-04 11:09:26 +05302848 } else {
Vijayavardhan Vennapusaa3152032012-03-05 16:29:30 +05302849 pr_debug("BSV clear\n");
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05302850 clear_bit(B_SESS_VLD, &motg->inputs);
Amit Blay6fa647a2012-05-24 14:12:08 +03002851 clear_bit(A_BUS_SUSPEND, &motg->inputs);
2852
Pavankumar Kondetiaa449e12011-11-04 11:09:26 +05302853 msm_chg_check_aca_intr(motg);
2854 }
Vijayavardhan Vennapusaa3152032012-03-05 16:29:30 +05302855 work = 1;
2856 } else if (usbsts & STS_PCI) {
2857 pc = readl_relaxed(USB_PORTSC);
2858 pr_debug("portsc = %x\n", pc);
2859 ret = IRQ_NONE;
2860 /*
2861 * HCD Acks PCI interrupt. We use this to switch
2862 * between different OTG states.
2863 */
2864 work = 1;
Steve Mucklef132c6c2012-06-06 18:30:57 -07002865 switch (otg->phy->state) {
Vijayavardhan Vennapusaa3152032012-03-05 16:29:30 +05302866 case OTG_STATE_A_SUSPEND:
2867 if (otg->host->b_hnp_enable && (pc & PORTSC_CSC) &&
2868 !(pc & PORTSC_CCS)) {
2869 pr_debug("B_CONN clear\n");
2870 clear_bit(B_CONN, &motg->inputs);
2871 msm_otg_del_timer(motg);
2872 }
2873 break;
2874 case OTG_STATE_A_PERIPHERAL:
2875 /*
2876 * A-peripheral observed activity on bus.
2877 * clear A_BIDL_ADIS timer.
2878 */
2879 msm_otg_del_timer(motg);
2880 work = 0;
2881 break;
2882 case OTG_STATE_B_WAIT_ACON:
2883 if ((pc & PORTSC_CSC) && (pc & PORTSC_CCS)) {
2884 pr_debug("A_CONN set\n");
2885 set_bit(A_CONN, &motg->inputs);
2886 /* Clear ASE0_BRST timer */
2887 msm_otg_del_timer(motg);
2888 }
2889 break;
2890 case OTG_STATE_B_HOST:
2891 if ((pc & PORTSC_CSC) && !(pc & PORTSC_CCS)) {
2892 pr_debug("A_CONN clear\n");
2893 clear_bit(A_CONN, &motg->inputs);
2894 msm_otg_del_timer(motg);
2895 }
2896 break;
2897 case OTG_STATE_A_WAIT_BCON:
2898 if (TA_WAIT_BCON < 0)
2899 set_bit(A_BUS_REQ, &motg->inputs);
2900 default:
2901 work = 0;
2902 break;
2903 }
2904 } else if (usbsts & STS_URI) {
2905 ret = IRQ_NONE;
Steve Mucklef132c6c2012-06-06 18:30:57 -07002906 switch (otg->phy->state) {
Vijayavardhan Vennapusaa3152032012-03-05 16:29:30 +05302907 case OTG_STATE_A_PERIPHERAL:
2908 /*
2909 * A-peripheral observed activity on bus.
2910 * clear A_BIDL_ADIS timer.
2911 */
2912 msm_otg_del_timer(motg);
2913 work = 0;
2914 break;
2915 default:
2916 work = 0;
2917 break;
2918 }
2919 } else if (usbsts & STS_SLI) {
2920 ret = IRQ_NONE;
2921 work = 0;
Steve Mucklef132c6c2012-06-06 18:30:57 -07002922 switch (otg->phy->state) {
Vijayavardhan Vennapusaa3152032012-03-05 16:29:30 +05302923 case OTG_STATE_B_PERIPHERAL:
2924 if (otg->gadget->b_hnp_enable) {
2925 set_bit(A_BUS_SUSPEND, &motg->inputs);
2926 set_bit(B_BUS_REQ, &motg->inputs);
2927 work = 1;
2928 }
2929 break;
2930 case OTG_STATE_A_PERIPHERAL:
2931 msm_otg_start_timer(motg, TA_BIDL_ADIS,
2932 A_BIDL_ADIS);
2933 break;
2934 default:
2935 break;
2936 }
2937 } else if ((usbsts & PHY_ALT_INT)) {
2938 writel_relaxed(PHY_ALT_INT, USB_USBSTS);
2939 if (msm_chg_check_aca_intr(motg))
2940 work = 1;
2941 ret = IRQ_HANDLED;
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05302942 }
Vijayavardhan Vennapusaa3152032012-03-05 16:29:30 +05302943 if (work)
2944 queue_work(system_nrt_wq, &motg->sm_work);
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05302945
Vijayavardhan Vennapusaa3152032012-03-05 16:29:30 +05302946 return ret;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002947}
2948
2949static void msm_otg_set_vbus_state(int online)
2950{
Pavankumar Kondeti4960f312011-12-06 15:46:14 +05302951 static bool init;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002952 struct msm_otg *motg = the_msm_otg;
Mayank Ranabaf31f42012-07-05 09:43:54 +05302953 struct usb_otg *otg = motg->phy.otg;
2954
2955 /* In A Host Mode, ignore received BSV interrupts */
2956 if (otg->phy->state >= OTG_STATE_A_IDLE)
2957 return;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002958
Pavankumar Kondeti4960f312011-12-06 15:46:14 +05302959 if (online) {
2960 pr_debug("PMIC: BSV set\n");
2961 set_bit(B_SESS_VLD, &motg->inputs);
2962 } else {
2963 pr_debug("PMIC: BSV clear\n");
2964 clear_bit(B_SESS_VLD, &motg->inputs);
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05302965 }
2966
Pavankumar Kondeti4960f312011-12-06 15:46:14 +05302967 if (!init) {
2968 init = true;
2969 complete(&pmic_vbus_init);
2970 pr_debug("PMIC: BSV init complete\n");
2971 return;
2972 }
2973
Pavankumar Kondeti2aec9f32012-06-13 09:06:03 +05302974 if (test_bit(MHL, &motg->inputs) ||
2975 mhl_det_in_progress) {
2976 pr_debug("PMIC: BSV interrupt ignored in MHL\n");
2977 return;
2978 }
2979
Jack Pham5ca279b2012-05-14 18:42:54 -07002980 if (atomic_read(&motg->pm_suspended))
2981 motg->sm_work_pending = true;
2982 else
2983 queue_work(system_nrt_wq, &motg->sm_work);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002984}
2985
Vijayavardhan Vennapusa68d55cf2012-06-27 20:06:12 +05302986static void msm_pmic_id_status_w(struct work_struct *w)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002987{
Vijayavardhan Vennapusa68d55cf2012-06-27 20:06:12 +05302988 struct msm_otg *motg = container_of(w, struct msm_otg,
2989 pmic_id_status_work.work);
2990 int work = 0;
2991 unsigned long flags;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002992
Vijayavardhan Vennapusa68d55cf2012-06-27 20:06:12 +05302993 local_irq_save(flags);
Pavankumar Kondeti4960f312011-12-06 15:46:14 +05302994 if (irq_read_line(motg->pdata->pmic_id_irq)) {
Vijayavardhan Vennapusa68d55cf2012-06-27 20:06:12 +05302995 if (!test_and_set_bit(ID, &motg->inputs)) {
2996 pr_debug("PMIC: ID set\n");
2997 work = 1;
2998 }
Pavankumar Kondeti4960f312011-12-06 15:46:14 +05302999 } else {
Vijayavardhan Vennapusa68d55cf2012-06-27 20:06:12 +05303000 if (test_and_clear_bit(ID, &motg->inputs)) {
3001 pr_debug("PMIC: ID clear\n");
3002 set_bit(A_BUS_REQ, &motg->inputs);
3003 work = 1;
3004 }
Pavankumar Kondeti4960f312011-12-06 15:46:14 +05303005 }
3006
Vijayavardhan Vennapusa68d55cf2012-06-27 20:06:12 +05303007 if (work && (motg->phy.state != OTG_STATE_UNDEFINED)) {
Jack Pham5ca279b2012-05-14 18:42:54 -07003008 if (atomic_read(&motg->pm_suspended))
3009 motg->sm_work_pending = true;
3010 else
3011 queue_work(system_nrt_wq, &motg->sm_work);
3012 }
Vijayavardhan Vennapusa68d55cf2012-06-27 20:06:12 +05303013 local_irq_restore(flags);
3014
3015}
3016
3017#define MSM_PMIC_ID_STATUS_DELAY 5 /* 5msec */
3018static irqreturn_t msm_pmic_id_irq(int irq, void *data)
3019{
3020 struct msm_otg *motg = data;
3021
Pavankumar Kondeti2aec9f32012-06-13 09:06:03 +05303022 if (test_bit(MHL, &motg->inputs) ||
3023 mhl_det_in_progress) {
3024 pr_debug("PMIC: Id interrupt ignored in MHL\n");
3025 return IRQ_HANDLED;
3026 }
3027
Vijayavardhan Vennapusa68d55cf2012-06-27 20:06:12 +05303028 if (!aca_id_turned_on)
3029 /*schedule delayed work for 5msec for ID line state to settle*/
3030 queue_delayed_work(system_nrt_wq, &motg->pmic_id_status_work,
3031 msecs_to_jiffies(MSM_PMIC_ID_STATUS_DELAY));
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003032
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05303033 return IRQ_HANDLED;
3034}
3035
3036static int msm_otg_mode_show(struct seq_file *s, void *unused)
3037{
3038 struct msm_otg *motg = s->private;
Steve Mucklef132c6c2012-06-06 18:30:57 -07003039 struct usb_phy *phy = &motg->phy;
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05303040
Steve Mucklef132c6c2012-06-06 18:30:57 -07003041 switch (phy->state) {
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05303042 case OTG_STATE_A_HOST:
3043 seq_printf(s, "host\n");
3044 break;
3045 case OTG_STATE_B_PERIPHERAL:
3046 seq_printf(s, "peripheral\n");
3047 break;
3048 default:
3049 seq_printf(s, "none\n");
3050 break;
3051 }
3052
3053 return 0;
3054}
3055
3056static int msm_otg_mode_open(struct inode *inode, struct file *file)
3057{
3058 return single_open(file, msm_otg_mode_show, inode->i_private);
3059}
3060
3061static ssize_t msm_otg_mode_write(struct file *file, const char __user *ubuf,
3062 size_t count, loff_t *ppos)
3063{
Pavankumar Kondetie2904ee2011-02-15 09:42:35 +05303064 struct seq_file *s = file->private_data;
3065 struct msm_otg *motg = s->private;
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05303066 char buf[16];
Steve Mucklef132c6c2012-06-06 18:30:57 -07003067 struct usb_phy *phy = &motg->phy;
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05303068 int status = count;
3069 enum usb_mode_type req_mode;
3070
3071 memset(buf, 0x00, sizeof(buf));
3072
3073 if (copy_from_user(&buf, ubuf, min_t(size_t, sizeof(buf) - 1, count))) {
3074 status = -EFAULT;
3075 goto out;
3076 }
3077
3078 if (!strncmp(buf, "host", 4)) {
3079 req_mode = USB_HOST;
3080 } else if (!strncmp(buf, "peripheral", 10)) {
3081 req_mode = USB_PERIPHERAL;
3082 } else if (!strncmp(buf, "none", 4)) {
3083 req_mode = USB_NONE;
3084 } else {
3085 status = -EINVAL;
3086 goto out;
3087 }
3088
3089 switch (req_mode) {
3090 case USB_NONE:
Steve Mucklef132c6c2012-06-06 18:30:57 -07003091 switch (phy->state) {
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05303092 case OTG_STATE_A_HOST:
3093 case OTG_STATE_B_PERIPHERAL:
3094 set_bit(ID, &motg->inputs);
3095 clear_bit(B_SESS_VLD, &motg->inputs);
3096 break;
3097 default:
3098 goto out;
3099 }
3100 break;
3101 case USB_PERIPHERAL:
Steve Mucklef132c6c2012-06-06 18:30:57 -07003102 switch (phy->state) {
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05303103 case OTG_STATE_B_IDLE:
3104 case OTG_STATE_A_HOST:
3105 set_bit(ID, &motg->inputs);
3106 set_bit(B_SESS_VLD, &motg->inputs);
3107 break;
3108 default:
3109 goto out;
3110 }
3111 break;
3112 case USB_HOST:
Steve Mucklef132c6c2012-06-06 18:30:57 -07003113 switch (phy->state) {
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05303114 case OTG_STATE_B_IDLE:
3115 case OTG_STATE_B_PERIPHERAL:
3116 clear_bit(ID, &motg->inputs);
3117 break;
3118 default:
3119 goto out;
3120 }
3121 break;
3122 default:
3123 goto out;
3124 }
3125
Steve Mucklef132c6c2012-06-06 18:30:57 -07003126 pm_runtime_resume(phy->dev);
Vijayavardhan Vennapusaa3152032012-03-05 16:29:30 +05303127 queue_work(system_nrt_wq, &motg->sm_work);
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05303128out:
3129 return status;
3130}
3131
3132const struct file_operations msm_otg_mode_fops = {
3133 .open = msm_otg_mode_open,
3134 .read = seq_read,
3135 .write = msm_otg_mode_write,
3136 .llseek = seq_lseek,
3137 .release = single_release,
3138};
3139
Chiranjeevi Velempatif9a11542012-03-28 18:18:34 +05303140static int msm_otg_show_otg_state(struct seq_file *s, void *unused)
3141{
3142 struct msm_otg *motg = s->private;
Steve Mucklef132c6c2012-06-06 18:30:57 -07003143 struct usb_phy *phy = &motg->phy;
Chiranjeevi Velempatif9a11542012-03-28 18:18:34 +05303144
Steve Mucklef132c6c2012-06-06 18:30:57 -07003145 seq_printf(s, "%s\n", otg_state_string(phy->state));
Chiranjeevi Velempatif9a11542012-03-28 18:18:34 +05303146 return 0;
3147}
3148
3149static int msm_otg_otg_state_open(struct inode *inode, struct file *file)
3150{
3151 return single_open(file, msm_otg_show_otg_state, inode->i_private);
3152}
3153
3154const struct file_operations msm_otg_state_fops = {
3155 .open = msm_otg_otg_state_open,
3156 .read = seq_read,
3157 .llseek = seq_lseek,
3158 .release = single_release,
3159};
3160
Anji jonnalad270e2d2011-08-09 11:28:32 +05303161static int msm_otg_show_chg_type(struct seq_file *s, void *unused)
3162{
3163 struct msm_otg *motg = s->private;
3164
Pavankumar Kondeti9ef69cb2011-12-12 14:18:22 +05303165 seq_printf(s, "%s\n", chg_to_string(motg->chg_type));
Anji jonnalad270e2d2011-08-09 11:28:32 +05303166 return 0;
3167}
3168
3169static int msm_otg_chg_open(struct inode *inode, struct file *file)
3170{
3171 return single_open(file, msm_otg_show_chg_type, inode->i_private);
3172}
3173
3174const struct file_operations msm_otg_chg_fops = {
3175 .open = msm_otg_chg_open,
3176 .read = seq_read,
3177 .llseek = seq_lseek,
3178 .release = single_release,
3179};
3180
Pavankumar Kondetiaa449e12011-11-04 11:09:26 +05303181static int msm_otg_aca_show(struct seq_file *s, void *unused)
3182{
3183 if (debug_aca_enabled)
3184 seq_printf(s, "enabled\n");
3185 else
3186 seq_printf(s, "disabled\n");
3187
3188 return 0;
3189}
3190
3191static int msm_otg_aca_open(struct inode *inode, struct file *file)
3192{
3193 return single_open(file, msm_otg_aca_show, inode->i_private);
3194}
3195
3196static ssize_t msm_otg_aca_write(struct file *file, const char __user *ubuf,
3197 size_t count, loff_t *ppos)
3198{
3199 char buf[8];
3200
3201 memset(buf, 0x00, sizeof(buf));
3202
3203 if (copy_from_user(&buf, ubuf, min_t(size_t, sizeof(buf) - 1, count)))
3204 return -EFAULT;
3205
3206 if (!strncmp(buf, "enable", 6))
3207 debug_aca_enabled = true;
3208 else
3209 debug_aca_enabled = false;
3210
3211 return count;
3212}
3213
3214const struct file_operations msm_otg_aca_fops = {
3215 .open = msm_otg_aca_open,
3216 .read = seq_read,
3217 .write = msm_otg_aca_write,
3218 .llseek = seq_lseek,
3219 .release = single_release,
3220};
3221
Manu Gautam8bdcc592012-03-06 11:26:06 +05303222static int msm_otg_bus_show(struct seq_file *s, void *unused)
3223{
3224 if (debug_bus_voting_enabled)
3225 seq_printf(s, "enabled\n");
3226 else
3227 seq_printf(s, "disabled\n");
3228
3229 return 0;
3230}
3231
3232static int msm_otg_bus_open(struct inode *inode, struct file *file)
3233{
3234 return single_open(file, msm_otg_bus_show, inode->i_private);
3235}
3236
3237static ssize_t msm_otg_bus_write(struct file *file, const char __user *ubuf,
3238 size_t count, loff_t *ppos)
3239{
3240 char buf[8];
3241 int ret;
3242 struct seq_file *s = file->private_data;
3243 struct msm_otg *motg = s->private;
3244
3245 memset(buf, 0x00, sizeof(buf));
3246
3247 if (copy_from_user(&buf, ubuf, min_t(size_t, sizeof(buf) - 1, count)))
3248 return -EFAULT;
3249
3250 if (!strncmp(buf, "enable", 6)) {
3251 /* Do not vote here. Let OTG statemachine decide when to vote */
3252 debug_bus_voting_enabled = true;
3253 } else {
3254 debug_bus_voting_enabled = false;
3255 if (motg->bus_perf_client) {
3256 ret = msm_bus_scale_client_update_request(
3257 motg->bus_perf_client, 0);
3258 if (ret)
Steve Mucklef132c6c2012-06-06 18:30:57 -07003259 dev_err(motg->phy.dev, "%s: Failed to devote "
Manu Gautam8bdcc592012-03-06 11:26:06 +05303260 "for bus bw %d\n", __func__, ret);
3261 }
3262 }
3263
3264 return count;
3265}
3266
3267const struct file_operations msm_otg_bus_fops = {
3268 .open = msm_otg_bus_open,
3269 .read = seq_read,
3270 .write = msm_otg_bus_write,
3271 .llseek = seq_lseek,
3272 .release = single_release,
3273};
3274
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05303275static struct dentry *msm_otg_dbg_root;
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05303276
3277static int msm_otg_debugfs_init(struct msm_otg *motg)
3278{
Manu Gautam8bdcc592012-03-06 11:26:06 +05303279 struct dentry *msm_otg_dentry;
Anji jonnalad270e2d2011-08-09 11:28:32 +05303280
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05303281 msm_otg_dbg_root = debugfs_create_dir("msm_otg", NULL);
3282
3283 if (!msm_otg_dbg_root || IS_ERR(msm_otg_dbg_root))
3284 return -ENODEV;
3285
Anji jonnalad270e2d2011-08-09 11:28:32 +05303286 if (motg->pdata->mode == USB_OTG &&
3287 motg->pdata->otg_control == OTG_USER_CONTROL) {
3288
Manu Gautam8bdcc592012-03-06 11:26:06 +05303289 msm_otg_dentry = debugfs_create_file("mode", S_IRUGO |
Anji jonnalad270e2d2011-08-09 11:28:32 +05303290 S_IWUSR, msm_otg_dbg_root, motg,
3291 &msm_otg_mode_fops);
3292
Manu Gautam8bdcc592012-03-06 11:26:06 +05303293 if (!msm_otg_dentry) {
Anji jonnalad270e2d2011-08-09 11:28:32 +05303294 debugfs_remove(msm_otg_dbg_root);
3295 msm_otg_dbg_root = NULL;
3296 return -ENODEV;
3297 }
3298 }
3299
Manu Gautam8bdcc592012-03-06 11:26:06 +05303300 msm_otg_dentry = debugfs_create_file("chg_type", S_IRUGO,
Anji jonnalad270e2d2011-08-09 11:28:32 +05303301 msm_otg_dbg_root, motg,
3302 &msm_otg_chg_fops);
3303
Manu Gautam8bdcc592012-03-06 11:26:06 +05303304 if (!msm_otg_dentry) {
Pavankumar Kondetiaa449e12011-11-04 11:09:26 +05303305 debugfs_remove_recursive(msm_otg_dbg_root);
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05303306 return -ENODEV;
3307 }
3308
Manu Gautam8bdcc592012-03-06 11:26:06 +05303309 msm_otg_dentry = debugfs_create_file("aca", S_IRUGO | S_IWUSR,
Pavankumar Kondetiaa449e12011-11-04 11:09:26 +05303310 msm_otg_dbg_root, motg,
3311 &msm_otg_aca_fops);
3312
Manu Gautam8bdcc592012-03-06 11:26:06 +05303313 if (!msm_otg_dentry) {
Pavankumar Kondetiaa449e12011-11-04 11:09:26 +05303314 debugfs_remove_recursive(msm_otg_dbg_root);
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05303315 return -ENODEV;
3316 }
3317
Manu Gautam8bdcc592012-03-06 11:26:06 +05303318 msm_otg_dentry = debugfs_create_file("bus_voting", S_IRUGO | S_IWUSR,
3319 msm_otg_dbg_root, motg,
3320 &msm_otg_bus_fops);
3321
3322 if (!msm_otg_dentry) {
3323 debugfs_remove_recursive(msm_otg_dbg_root);
3324 return -ENODEV;
3325 }
Chiranjeevi Velempatif9a11542012-03-28 18:18:34 +05303326
3327 msm_otg_dentry = debugfs_create_file("otg_state", S_IRUGO,
3328 msm_otg_dbg_root, motg, &msm_otg_state_fops);
3329
3330 if (!msm_otg_dentry) {
3331 debugfs_remove_recursive(msm_otg_dbg_root);
3332 return -ENODEV;
3333 }
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05303334 return 0;
3335}
3336
3337static void msm_otg_debugfs_cleanup(void)
3338{
Anji jonnalad270e2d2011-08-09 11:28:32 +05303339 debugfs_remove_recursive(msm_otg_dbg_root);
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05303340}
3341
Pavankumar Kondetieaea7fe2011-10-27 14:46:45 +05303342static u64 msm_otg_dma_mask = DMA_BIT_MASK(64);
3343static struct platform_device *msm_otg_add_pdev(
3344 struct platform_device *ofdev, const char *name)
3345{
3346 struct platform_device *pdev;
3347 const struct resource *res = ofdev->resource;
3348 unsigned int num = ofdev->num_resources;
3349 int retval;
3350
3351 pdev = platform_device_alloc(name, -1);
3352 if (!pdev) {
3353 retval = -ENOMEM;
3354 goto error;
3355 }
3356
3357 pdev->dev.coherent_dma_mask = DMA_BIT_MASK(32);
3358 pdev->dev.dma_mask = &msm_otg_dma_mask;
3359
3360 if (num) {
3361 retval = platform_device_add_resources(pdev, res, num);
3362 if (retval)
3363 goto error;
3364 }
3365
3366 retval = platform_device_add(pdev);
3367 if (retval)
3368 goto error;
3369
3370 return pdev;
3371
3372error:
3373 platform_device_put(pdev);
3374 return ERR_PTR(retval);
3375}
3376
3377static int msm_otg_setup_devices(struct platform_device *ofdev,
3378 enum usb_mode_type mode, bool init)
3379{
3380 const char *gadget_name = "msm_hsusb";
3381 const char *host_name = "msm_hsusb_host";
3382 static struct platform_device *gadget_pdev;
3383 static struct platform_device *host_pdev;
3384 int retval = 0;
3385
3386 if (!init) {
3387 if (gadget_pdev)
3388 platform_device_unregister(gadget_pdev);
3389 if (host_pdev)
3390 platform_device_unregister(host_pdev);
3391 return 0;
3392 }
3393
3394 switch (mode) {
3395 case USB_OTG:
3396 /* fall through */
3397 case USB_PERIPHERAL:
3398 gadget_pdev = msm_otg_add_pdev(ofdev, gadget_name);
3399 if (IS_ERR(gadget_pdev)) {
3400 retval = PTR_ERR(gadget_pdev);
3401 break;
3402 }
3403 if (mode == USB_PERIPHERAL)
3404 break;
3405 /* fall through */
3406 case USB_HOST:
3407 host_pdev = msm_otg_add_pdev(ofdev, host_name);
3408 if (IS_ERR(host_pdev)) {
3409 retval = PTR_ERR(host_pdev);
3410 if (mode == USB_OTG)
3411 platform_device_unregister(gadget_pdev);
3412 }
3413 break;
3414 default:
3415 break;
3416 }
3417
3418 return retval;
3419}
3420
3421struct msm_otg_platform_data *msm_otg_dt_to_pdata(struct platform_device *pdev)
3422{
3423 struct device_node *node = pdev->dev.of_node;
3424 struct msm_otg_platform_data *pdata;
3425 int len = 0;
3426
3427 pdata = devm_kzalloc(&pdev->dev, sizeof(*pdata), GFP_KERNEL);
3428 if (!pdata) {
3429 pr_err("unable to allocate platform data\n");
3430 return NULL;
3431 }
3432 of_get_property(node, "qcom,hsusb-otg-phy-init-seq", &len);
3433 if (len) {
3434 pdata->phy_init_seq = devm_kzalloc(&pdev->dev, len, GFP_KERNEL);
3435 if (!pdata->phy_init_seq)
3436 return NULL;
3437 of_property_read_u32_array(node, "qcom,hsusb-otg-phy-init-seq",
3438 pdata->phy_init_seq,
3439 len/sizeof(*pdata->phy_init_seq));
3440 }
3441 of_property_read_u32(node, "qcom,hsusb-otg-power-budget",
3442 &pdata->power_budget);
3443 of_property_read_u32(node, "qcom,hsusb-otg-mode",
3444 &pdata->mode);
3445 of_property_read_u32(node, "qcom,hsusb-otg-otg-control",
3446 &pdata->otg_control);
3447 of_property_read_u32(node, "qcom,hsusb-otg-default-mode",
3448 &pdata->default_mode);
3449 of_property_read_u32(node, "qcom,hsusb-otg-phy-type",
3450 &pdata->phy_type);
3451 of_property_read_u32(node, "qcom,hsusb-otg-pmic-id-irq",
3452 &pdata->pmic_id_irq);
Manu Gautambd53fba2012-07-31 16:13:06 +05303453 pdata->disable_reset_on_disconnect = of_property_read_bool(node,
3454 "qcom,hsusb-otg-disable-reset");
3455
Pavankumar Kondetieaea7fe2011-10-27 14:46:45 +05303456 return pdata;
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05303457}
3458
3459static int __init msm_otg_probe(struct platform_device *pdev)
3460{
3461 int ret = 0;
3462 struct resource *res;
3463 struct msm_otg *motg;
Heikki Krogerus1d4c9292012-02-13 13:24:09 +02003464 struct usb_phy *phy;
Pavankumar Kondetieaea7fe2011-10-27 14:46:45 +05303465 struct msm_otg_platform_data *pdata;
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05303466
3467 dev_info(&pdev->dev, "msm_otg probe\n");
Pavankumar Kondetieaea7fe2011-10-27 14:46:45 +05303468
3469 if (pdev->dev.of_node) {
3470 dev_dbg(&pdev->dev, "device tree enabled\n");
3471 pdata = msm_otg_dt_to_pdata(pdev);
3472 if (!pdata)
3473 return -ENOMEM;
3474 ret = msm_otg_setup_devices(pdev, pdata->mode, true);
3475 if (ret) {
3476 dev_err(&pdev->dev, "devices setup failed\n");
3477 return ret;
3478 }
3479 } else if (!pdev->dev.platform_data) {
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05303480 dev_err(&pdev->dev, "No platform data given. Bailing out\n");
3481 return -ENODEV;
Pavankumar Kondetieaea7fe2011-10-27 14:46:45 +05303482 } else {
3483 pdata = pdev->dev.platform_data;
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05303484 }
3485
3486 motg = kzalloc(sizeof(struct msm_otg), GFP_KERNEL);
3487 if (!motg) {
3488 dev_err(&pdev->dev, "unable to allocate msm_otg\n");
3489 return -ENOMEM;
3490 }
3491
Heikki Krogerus1d4c9292012-02-13 13:24:09 +02003492 motg->phy.otg = kzalloc(sizeof(struct usb_otg), GFP_KERNEL);
3493 if (!motg->phy.otg) {
Steve Mucklef132c6c2012-06-06 18:30:57 -07003494 dev_err(&pdev->dev, "unable to allocate usb_otg\n");
3495 ret = -ENOMEM;
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05303496 goto free_motg;
3497 }
3498
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003499 the_msm_otg = motg;
Pavankumar Kondetieaea7fe2011-10-27 14:46:45 +05303500 motg->pdata = pdata;
Steve Mucklef132c6c2012-06-06 18:30:57 -07003501 phy = &motg->phy;
3502 phy->dev = &pdev->dev;
Anji jonnala0f73cac2011-05-04 10:19:46 +05303503
3504 /*
Pavankumar Kondetiaa449e12011-11-04 11:09:26 +05303505 * ACA ID_GND threshold range is overlapped with OTG ID_FLOAT. Hence
3506 * PHY treat ACA ID_GND as float and no interrupt is generated. But
3507 * PMIC can detect ACA ID_GND and generate an interrupt.
3508 */
3509 if (aca_enabled() && motg->pdata->otg_control != OTG_PMIC_CONTROL) {
3510 dev_err(&pdev->dev, "ACA can not be enabled without PMIC\n");
3511 ret = -EINVAL;
Steve Mucklef132c6c2012-06-06 18:30:57 -07003512 goto free_otg;
Pavankumar Kondetiaa449e12011-11-04 11:09:26 +05303513 }
3514
Ofir Cohen4da266f2012-01-03 10:19:29 +02003515 /* initialize reset counter */
3516 motg->reset_counter = 0;
3517
Amit Blay02eff132011-09-21 16:46:24 +03003518 /* Some targets don't support PHY clock. */
Manu Gautam5143b252012-01-05 19:25:23 -08003519 motg->phy_reset_clk = clk_get(&pdev->dev, "phy_clk");
Amit Blay02eff132011-09-21 16:46:24 +03003520 if (IS_ERR(motg->phy_reset_clk))
Manu Gautam5143b252012-01-05 19:25:23 -08003521 dev_err(&pdev->dev, "failed to get phy_clk\n");
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05303522
Pavankumar Kondeti923262e2012-04-20 15:34:24 +05303523 /*
3524 * Targets on which link uses asynchronous reset methodology,
3525 * free running clock is not required during the reset.
3526 */
Manu Gautam5143b252012-01-05 19:25:23 -08003527 motg->clk = clk_get(&pdev->dev, "alt_core_clk");
Pavankumar Kondeti923262e2012-04-20 15:34:24 +05303528 if (IS_ERR(motg->clk))
3529 dev_dbg(&pdev->dev, "alt_core_clk is not present\n");
3530 else
3531 clk_set_rate(motg->clk, 60000000);
Anji jonnala0f73cac2011-05-04 10:19:46 +05303532
3533 /*
Manu Gautam5143b252012-01-05 19:25:23 -08003534 * USB Core is running its protocol engine based on CORE CLK,
Anji jonnala0f73cac2011-05-04 10:19:46 +05303535 * CORE CLK must be running at >55Mhz for correct HSUSB
3536 * operation and USB core cannot tolerate frequency changes on
3537 * CORE CLK. For such USB cores, vote for maximum clk frequency
3538 * on pclk source
3539 */
Manu Gautam5143b252012-01-05 19:25:23 -08003540 motg->core_clk = clk_get(&pdev->dev, "core_clk");
3541 if (IS_ERR(motg->core_clk)) {
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05303542 motg->core_clk = NULL;
Manu Gautam5143b252012-01-05 19:25:23 -08003543 dev_err(&pdev->dev, "failed to get core_clk\n");
Pavankumar Kondetibc541332012-04-20 15:32:04 +05303544 ret = PTR_ERR(motg->core_clk);
Manu Gautam5143b252012-01-05 19:25:23 -08003545 goto put_clk;
3546 }
3547 clk_set_rate(motg->core_clk, INT_MAX);
3548
3549 motg->pclk = clk_get(&pdev->dev, "iface_clk");
3550 if (IS_ERR(motg->pclk)) {
3551 dev_err(&pdev->dev, "failed to get iface_clk\n");
3552 ret = PTR_ERR(motg->pclk);
3553 goto put_core_clk;
3554 }
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05303555
3556 res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
3557 if (!res) {
3558 dev_err(&pdev->dev, "failed to get platform resource mem\n");
3559 ret = -ENODEV;
Manu Gautam5143b252012-01-05 19:25:23 -08003560 goto put_pclk;
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05303561 }
3562
3563 motg->regs = ioremap(res->start, resource_size(res));
3564 if (!motg->regs) {
3565 dev_err(&pdev->dev, "ioremap failed\n");
3566 ret = -ENOMEM;
Manu Gautam5143b252012-01-05 19:25:23 -08003567 goto put_pclk;
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05303568 }
3569 dev_info(&pdev->dev, "OTG regs = %p\n", motg->regs);
3570
3571 motg->irq = platform_get_irq(pdev, 0);
3572 if (!motg->irq) {
3573 dev_err(&pdev->dev, "platform_get_irq failed\n");
3574 ret = -ENODEV;
3575 goto free_regs;
3576 }
3577
Manu Gautamf8c45642012-08-10 10:20:56 -07003578 motg->async_irq = platform_get_irq_byname(pdev, "async_irq");
3579 if (motg->async_irq < 0) {
3580 dev_dbg(&pdev->dev, "platform_get_irq for async_int failed\n");
3581 motg->async_irq = 0;
3582 }
3583
Stephen Boyd30ad10b2012-03-01 14:51:04 -08003584 motg->xo_handle = msm_xo_get(MSM_XO_TCXO_D0, "usb");
Anji jonnala7da3f262011-12-02 17:22:14 -08003585 if (IS_ERR(motg->xo_handle)) {
3586 dev_err(&pdev->dev, "%s not able to get the handle "
3587 "to vote for TCXO D0 buffer\n", __func__);
3588 ret = PTR_ERR(motg->xo_handle);
3589 goto free_regs;
3590 }
Anji jonnala11aa5c42011-05-04 10:19:48 +05303591
Stephen Boyd30ad10b2012-03-01 14:51:04 -08003592 ret = msm_xo_mode_vote(motg->xo_handle, MSM_XO_MODE_ON);
Anji jonnala7da3f262011-12-02 17:22:14 -08003593 if (ret) {
3594 dev_err(&pdev->dev, "%s failed to vote for TCXO "
3595 "D0 buffer%d\n", __func__, ret);
3596 goto free_xo_handle;
3597 }
3598
Manu Gautam28b1bac2012-01-30 16:43:06 +05303599 clk_prepare_enable(motg->pclk);
Anji jonnala11aa5c42011-05-04 10:19:48 +05303600
Mayank Rana248698c2012-04-19 00:03:16 +05303601 motg->vdd_type = VDDCX_CORNER;
Steve Mucklef132c6c2012-06-06 18:30:57 -07003602 hsusb_vddcx = devm_regulator_get(motg->phy.dev, "hsusb_vdd_dig");
Mayank Rana248698c2012-04-19 00:03:16 +05303603 if (IS_ERR(hsusb_vddcx)) {
Steve Mucklef132c6c2012-06-06 18:30:57 -07003604 hsusb_vddcx = devm_regulator_get(motg->phy.dev, "HSUSB_VDDCX");
Mayank Rana248698c2012-04-19 00:03:16 +05303605 if (IS_ERR(hsusb_vddcx)) {
Steve Mucklef132c6c2012-06-06 18:30:57 -07003606 dev_err(motg->phy.dev, "unable to get hsusb vddcx\n");
Hemant Kumar41812392012-07-13 15:26:20 -07003607 ret = PTR_ERR(hsusb_vddcx);
Mayank Rana248698c2012-04-19 00:03:16 +05303608 goto devote_xo_handle;
3609 }
3610 motg->vdd_type = VDDCX;
Anji jonnala11aa5c42011-05-04 10:19:48 +05303611 }
3612
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003613 ret = msm_hsusb_config_vddcx(1);
Anji jonnala11aa5c42011-05-04 10:19:48 +05303614 if (ret) {
3615 dev_err(&pdev->dev, "hsusb vddcx configuration failed\n");
Mayank Rana248698c2012-04-19 00:03:16 +05303616 goto devote_xo_handle;
3617 }
3618
3619 ret = regulator_enable(hsusb_vddcx);
3620 if (ret) {
3621 dev_err(&pdev->dev, "unable to enable the hsusb vddcx\n");
3622 goto free_config_vddcx;
Anji jonnala11aa5c42011-05-04 10:19:48 +05303623 }
3624
3625 ret = msm_hsusb_ldo_init(motg, 1);
3626 if (ret) {
3627 dev_err(&pdev->dev, "hsusb vreg configuration failed\n");
Mayank Rana248698c2012-04-19 00:03:16 +05303628 goto free_hsusb_vddcx;
Anji jonnala11aa5c42011-05-04 10:19:48 +05303629 }
3630
Mayank Rana9e9a2ac2012-03-24 04:05:28 +05303631 if (pdata->mhl_enable) {
Pavankumar Kondeti56dc7422012-07-02 12:45:19 +05303632 mhl_usb_hs_switch = devm_regulator_get(motg->phy.dev,
3633 "mhl_usb_hs_switch");
3634 if (IS_ERR(mhl_usb_hs_switch)) {
3635 dev_err(&pdev->dev, "Unable to get mhl_usb_hs_switch\n");
Hemant Kumar41812392012-07-13 15:26:20 -07003636 ret = PTR_ERR(mhl_usb_hs_switch);
Mayank Rana9e9a2ac2012-03-24 04:05:28 +05303637 goto free_ldo_init;
3638 }
3639 }
3640
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003641 ret = msm_hsusb_ldo_enable(motg, 1);
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05303642 if (ret) {
3643 dev_err(&pdev->dev, "hsusb vreg enable failed\n");
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003644 goto free_ldo_init;
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05303645 }
Manu Gautam28b1bac2012-01-30 16:43:06 +05303646 clk_prepare_enable(motg->core_clk);
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05303647
3648 writel(0, USB_USBINTR);
3649 writel(0, USB_OTGSC);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003650 /* Ensure that above STOREs are completed before enabling interrupts */
3651 mb();
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05303652
Pavankumar Kondeti2aec9f32012-06-13 09:06:03 +05303653 ret = msm_otg_mhl_register_callback(motg, msm_otg_mhl_notify_online);
3654 if (ret)
3655 dev_dbg(&pdev->dev, "MHL can not be supported\n");
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003656 wake_lock_init(&motg->wlock, WAKE_LOCK_SUSPEND, "msm_otg");
Vijayavardhan Vennapusaa3152032012-03-05 16:29:30 +05303657 msm_otg_init_timer(motg);
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05303658 INIT_WORK(&motg->sm_work, msm_otg_sm_work);
Pavankumar Kondetid8608522011-05-04 10:19:47 +05303659 INIT_DELAYED_WORK(&motg->chg_work, msm_chg_detect_work);
Vijayavardhan Vennapusa68d55cf2012-06-27 20:06:12 +05303660 INIT_DELAYED_WORK(&motg->pmic_id_status_work, msm_pmic_id_status_w);
kibum.leeec040442012-08-22 22:29:46 +09003661 INIT_DELAYED_WORK(&motg->check_ta_work, msm_ta_detect_work);
Pavankumar Kondetiaa449e12011-11-04 11:09:26 +05303662 setup_timer(&motg->id_timer, msm_otg_id_timer_func,
3663 (unsigned long) motg);
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05303664 ret = request_irq(motg->irq, msm_otg_irq, IRQF_SHARED,
3665 "msm_otg", motg);
3666 if (ret) {
3667 dev_err(&pdev->dev, "request irq failed\n");
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003668 goto destroy_wlock;
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05303669 }
3670
Manu Gautamf8c45642012-08-10 10:20:56 -07003671 if (motg->async_irq) {
3672 ret = request_irq(motg->async_irq, msm_otg_irq, IRQF_SHARED,
3673 "msm_otg", motg);
3674 if (ret) {
3675 dev_err(&pdev->dev, "request irq failed (ASYNC INT)\n");
3676 goto free_irq;
3677 }
3678 disable_irq(motg->async_irq);
3679 }
3680
Jack Pham87f202f2012-08-06 00:24:22 -07003681 if (pdata->otg_control == OTG_PHY_CONTROL && pdata->mpm_otgsessvld_int)
3682 msm_mpm_enable_pin(pdata->mpm_otgsessvld_int, 1);
3683
Heikki Krogerus1d4c9292012-02-13 13:24:09 +02003684 phy->init = msm_otg_reset;
3685 phy->set_power = msm_otg_set_power;
Steve Mucklef132c6c2012-06-06 18:30:57 -07003686 phy->set_suspend = msm_otg_set_suspend;
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05303687
Heikki Krogerus1d4c9292012-02-13 13:24:09 +02003688 phy->io_ops = &msm_otg_io_ops;
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05303689
Heikki Krogerus1d4c9292012-02-13 13:24:09 +02003690 phy->otg->phy = &motg->phy;
3691 phy->otg->set_host = msm_otg_set_host;
3692 phy->otg->set_peripheral = msm_otg_set_peripheral;
Steve Mucklef132c6c2012-06-06 18:30:57 -07003693 phy->otg->start_hnp = msm_otg_start_hnp;
3694 phy->otg->start_srp = msm_otg_start_srp;
Heikki Krogerus1d4c9292012-02-13 13:24:09 +02003695
3696 ret = usb_set_transceiver(&motg->phy);
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05303697 if (ret) {
Heikki Krogerus1d4c9292012-02-13 13:24:09 +02003698 dev_err(&pdev->dev, "usb_set_transceiver failed\n");
Manu Gautamf8c45642012-08-10 10:20:56 -07003699 goto free_async_irq;
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05303700 }
3701
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05303702 if (motg->pdata->mode == USB_OTG &&
Pavankumar Kondeti0d81f312012-01-13 11:34:10 +05303703 motg->pdata->otg_control == OTG_PMIC_CONTROL) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003704 if (motg->pdata->pmic_id_irq) {
3705 ret = request_irq(motg->pdata->pmic_id_irq,
3706 msm_pmic_id_irq,
3707 IRQF_TRIGGER_RISING |
3708 IRQF_TRIGGER_FALLING,
3709 "msm_otg", motg);
3710 if (ret) {
3711 dev_err(&pdev->dev, "request irq failed for PMIC ID\n");
Steve Mucklef132c6c2012-06-06 18:30:57 -07003712 goto remove_phy;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003713 }
3714 } else {
3715 ret = -ENODEV;
3716 dev_err(&pdev->dev, "PMIC IRQ for ID notifications doesn't exist\n");
Steve Mucklef132c6c2012-06-06 18:30:57 -07003717 goto remove_phy;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003718 }
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05303719 }
3720
Vijayavardhan Vennapusafc464f02011-11-04 21:54:00 +05303721 msm_hsusb_mhl_switch_enable(motg, 1);
3722
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05303723 platform_set_drvdata(pdev, motg);
3724 device_init_wakeup(&pdev->dev, 1);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003725 motg->mA_port = IUNIT;
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05303726
Anji jonnalad270e2d2011-08-09 11:28:32 +05303727 ret = msm_otg_debugfs_init(motg);
3728 if (ret)
3729 dev_dbg(&pdev->dev, "mode debugfs file is"
3730 "not available\n");
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05303731
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003732 if (motg->pdata->otg_control == OTG_PMIC_CONTROL)
3733 pm8921_charger_register_vbus_sn(&msm_otg_set_vbus_state);
3734
Amit Blay58b31472011-11-18 09:39:39 +02003735 if (motg->pdata->phy_type == SNPS_28NM_INTEGRATED_PHY) {
3736 if (motg->pdata->otg_control == OTG_PMIC_CONTROL &&
Pavankumar Kondeti0d81f312012-01-13 11:34:10 +05303737 (!(motg->pdata->mode == USB_OTG) ||
3738 motg->pdata->pmic_id_irq))
Amit Blay58b31472011-11-18 09:39:39 +02003739 motg->caps = ALLOW_PHY_POWER_COLLAPSE |
Vijayavardhan Vennapusa03171c72012-04-26 14:44:48 +05303740 ALLOW_PHY_RETENTION;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003741
Amit Blay58b31472011-11-18 09:39:39 +02003742 if (motg->pdata->otg_control == OTG_PHY_CONTROL)
3743 motg->caps = ALLOW_PHY_RETENTION;
3744 }
3745
Amit Blay6fa647a2012-05-24 14:12:08 +03003746 if (motg->pdata->enable_lpm_on_dev_suspend)
3747 motg->caps |= ALLOW_LPM_ON_DEV_SUSPEND;
3748
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003749 wake_lock(&motg->wlock);
Pavankumar Kondeti87c01042010-12-07 17:53:58 +05303750 pm_runtime_set_active(&pdev->dev);
3751 pm_runtime_enable(&pdev->dev);
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05303752
Manu Gautamcd82e9d2011-12-20 14:17:28 +05303753 if (motg->pdata->bus_scale_table) {
3754 motg->bus_perf_client =
3755 msm_bus_scale_register_client(motg->pdata->bus_scale_table);
3756 if (!motg->bus_perf_client)
Steve Mucklef132c6c2012-06-06 18:30:57 -07003757 dev_err(motg->phy.dev, "%s: Failed to register BUS "
Manu Gautamcd82e9d2011-12-20 14:17:28 +05303758 "scaling client!!\n", __func__);
Manu Gautam8bdcc592012-03-06 11:26:06 +05303759 else
3760 debug_bus_voting_enabled = true;
Manu Gautamcd82e9d2011-12-20 14:17:28 +05303761 }
3762
Pavankumar Kondeti87c01042010-12-07 17:53:58 +05303763 return 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003764
Steve Mucklef132c6c2012-06-06 18:30:57 -07003765remove_phy:
3766 usb_set_transceiver(NULL);
Manu Gautamf8c45642012-08-10 10:20:56 -07003767free_async_irq:
3768 if (motg->async_irq)
3769 free_irq(motg->async_irq, motg);
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05303770free_irq:
3771 free_irq(motg->irq, motg);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003772destroy_wlock:
3773 wake_lock_destroy(&motg->wlock);
Manu Gautam28b1bac2012-01-30 16:43:06 +05303774 clk_disable_unprepare(motg->core_clk);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003775 msm_hsusb_ldo_enable(motg, 0);
3776free_ldo_init:
Anji jonnala11aa5c42011-05-04 10:19:48 +05303777 msm_hsusb_ldo_init(motg, 0);
Mayank Rana248698c2012-04-19 00:03:16 +05303778free_hsusb_vddcx:
3779 regulator_disable(hsusb_vddcx);
3780free_config_vddcx:
3781 regulator_set_voltage(hsusb_vddcx,
3782 vdd_val[motg->vdd_type][VDD_NONE],
3783 vdd_val[motg->vdd_type][VDD_MAX]);
Anji jonnala7da3f262011-12-02 17:22:14 -08003784devote_xo_handle:
Manu Gautam28b1bac2012-01-30 16:43:06 +05303785 clk_disable_unprepare(motg->pclk);
Stephen Boyd30ad10b2012-03-01 14:51:04 -08003786 msm_xo_mode_vote(motg->xo_handle, MSM_XO_MODE_OFF);
Anji jonnala7da3f262011-12-02 17:22:14 -08003787free_xo_handle:
Stephen Boyd30ad10b2012-03-01 14:51:04 -08003788 msm_xo_put(motg->xo_handle);
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05303789free_regs:
3790 iounmap(motg->regs);
Manu Gautam5143b252012-01-05 19:25:23 -08003791put_pclk:
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05303792 clk_put(motg->pclk);
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05303793put_core_clk:
Manu Gautam5143b252012-01-05 19:25:23 -08003794 clk_put(motg->core_clk);
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05303795put_clk:
Pavankumar Kondeti923262e2012-04-20 15:34:24 +05303796 if (!IS_ERR(motg->clk))
3797 clk_put(motg->clk);
Amit Blay02eff132011-09-21 16:46:24 +03003798 if (!IS_ERR(motg->phy_reset_clk))
3799 clk_put(motg->phy_reset_clk);
Steve Mucklef132c6c2012-06-06 18:30:57 -07003800free_otg:
Heikki Krogerus1d4c9292012-02-13 13:24:09 +02003801 kfree(motg->phy.otg);
Pavankumar Kondetiaa449e12011-11-04 11:09:26 +05303802free_motg:
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05303803 kfree(motg);
3804 return ret;
3805}
3806
3807static int __devexit msm_otg_remove(struct platform_device *pdev)
3808{
3809 struct msm_otg *motg = platform_get_drvdata(pdev);
Steve Mucklef132c6c2012-06-06 18:30:57 -07003810 struct usb_otg *otg = motg->phy.otg;
Pavankumar Kondeti87c01042010-12-07 17:53:58 +05303811 int cnt = 0;
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05303812
3813 if (otg->host || otg->gadget)
3814 return -EBUSY;
3815
Pavankumar Kondetieaea7fe2011-10-27 14:46:45 +05303816 if (pdev->dev.of_node)
3817 msm_otg_setup_devices(pdev, motg->pdata->mode, false);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003818 if (motg->pdata->otg_control == OTG_PMIC_CONTROL)
3819 pm8921_charger_unregister_vbus_sn(0);
Pavankumar Kondeti2aec9f32012-06-13 09:06:03 +05303820 msm_otg_mhl_register_callback(motg, NULL);
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05303821 msm_otg_debugfs_cleanup();
Pavankumar Kondetid8608522011-05-04 10:19:47 +05303822 cancel_delayed_work_sync(&motg->chg_work);
Vijayavardhan Vennapusa68d55cf2012-06-27 20:06:12 +05303823 cancel_delayed_work_sync(&motg->pmic_id_status_work);
kibum.leeec040442012-08-22 22:29:46 +09003824 cancel_delayed_work_sync(&motg->check_ta_work);
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05303825 cancel_work_sync(&motg->sm_work);
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05303826
Pavankumar Kondeti70187732011-02-15 09:42:34 +05303827 pm_runtime_resume(&pdev->dev);
Pavankumar Kondeti87c01042010-12-07 17:53:58 +05303828
3829 device_init_wakeup(&pdev->dev, 0);
3830 pm_runtime_disable(&pdev->dev);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003831 wake_lock_destroy(&motg->wlock);
Pavankumar Kondeti87c01042010-12-07 17:53:58 +05303832
Vijayavardhan Vennapusafc464f02011-11-04 21:54:00 +05303833 msm_hsusb_mhl_switch_enable(motg, 0);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003834 if (motg->pdata->pmic_id_irq)
3835 free_irq(motg->pdata->pmic_id_irq, motg);
Heikki Krogerus1d4c9292012-02-13 13:24:09 +02003836 usb_set_transceiver(NULL);
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05303837 free_irq(motg->irq, motg);
3838
Jack Pham87f202f2012-08-06 00:24:22 -07003839 if (motg->pdata->otg_control == OTG_PHY_CONTROL &&
3840 motg->pdata->mpm_otgsessvld_int)
3841 msm_mpm_enable_pin(motg->pdata->mpm_otgsessvld_int, 0);
3842
Pavankumar Kondeti87c01042010-12-07 17:53:58 +05303843 /*
3844 * Put PHY in low power mode.
3845 */
Steve Mucklef132c6c2012-06-06 18:30:57 -07003846 ulpi_read(otg->phy, 0x14);
3847 ulpi_write(otg->phy, 0x08, 0x09);
Pavankumar Kondeti87c01042010-12-07 17:53:58 +05303848
3849 writel(readl(USB_PORTSC) | PORTSC_PHCD, USB_PORTSC);
3850 while (cnt < PHY_SUSPEND_TIMEOUT_USEC) {
3851 if (readl(USB_PORTSC) & PORTSC_PHCD)
3852 break;
3853 udelay(1);
3854 cnt++;
3855 }
3856 if (cnt >= PHY_SUSPEND_TIMEOUT_USEC)
Steve Mucklef132c6c2012-06-06 18:30:57 -07003857 dev_err(otg->phy->dev, "Unable to suspend PHY\n");
Pavankumar Kondeti87c01042010-12-07 17:53:58 +05303858
Manu Gautam28b1bac2012-01-30 16:43:06 +05303859 clk_disable_unprepare(motg->pclk);
3860 clk_disable_unprepare(motg->core_clk);
Stephen Boyd30ad10b2012-03-01 14:51:04 -08003861 msm_xo_put(motg->xo_handle);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003862 msm_hsusb_ldo_enable(motg, 0);
Anji jonnala11aa5c42011-05-04 10:19:48 +05303863 msm_hsusb_ldo_init(motg, 0);
Mayank Rana248698c2012-04-19 00:03:16 +05303864 regulator_disable(hsusb_vddcx);
3865 regulator_set_voltage(hsusb_vddcx,
3866 vdd_val[motg->vdd_type][VDD_NONE],
3867 vdd_val[motg->vdd_type][VDD_MAX]);
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05303868
3869 iounmap(motg->regs);
Pavankumar Kondeti87c01042010-12-07 17:53:58 +05303870 pm_runtime_set_suspended(&pdev->dev);
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05303871
Amit Blay02eff132011-09-21 16:46:24 +03003872 if (!IS_ERR(motg->phy_reset_clk))
3873 clk_put(motg->phy_reset_clk);
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05303874 clk_put(motg->pclk);
Pavankumar Kondeti923262e2012-04-20 15:34:24 +05303875 if (!IS_ERR(motg->clk))
3876 clk_put(motg->clk);
Manu Gautam5143b252012-01-05 19:25:23 -08003877 clk_put(motg->core_clk);
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05303878
Manu Gautamcd82e9d2011-12-20 14:17:28 +05303879 if (motg->bus_perf_client)
3880 msm_bus_scale_unregister_client(motg->bus_perf_client);
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05303881
Heikki Krogerus1d4c9292012-02-13 13:24:09 +02003882 kfree(motg->phy.otg);
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05303883 kfree(motg);
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05303884 return 0;
3885}
3886
Pavankumar Kondeti87c01042010-12-07 17:53:58 +05303887#ifdef CONFIG_PM_RUNTIME
3888static int msm_otg_runtime_idle(struct device *dev)
3889{
3890 struct msm_otg *motg = dev_get_drvdata(dev);
Steve Mucklef132c6c2012-06-06 18:30:57 -07003891 struct usb_phy *phy = &motg->phy;
Pavankumar Kondeti87c01042010-12-07 17:53:58 +05303892
3893 dev_dbg(dev, "OTG runtime idle\n");
3894
Steve Mucklef132c6c2012-06-06 18:30:57 -07003895 if (phy->state == OTG_STATE_UNDEFINED)
Pavankumar Kondeti8be99cf2011-08-04 10:48:08 +05303896 return -EAGAIN;
3897 else
3898 return 0;
Pavankumar Kondeti87c01042010-12-07 17:53:58 +05303899}
3900
3901static int msm_otg_runtime_suspend(struct device *dev)
3902{
3903 struct msm_otg *motg = dev_get_drvdata(dev);
3904
3905 dev_dbg(dev, "OTG runtime suspend\n");
3906 return msm_otg_suspend(motg);
3907}
3908
3909static int msm_otg_runtime_resume(struct device *dev)
3910{
3911 struct msm_otg *motg = dev_get_drvdata(dev);
3912
3913 dev_dbg(dev, "OTG runtime resume\n");
Pavankumar Kondeti8be99cf2011-08-04 10:48:08 +05303914 pm_runtime_get_noresume(dev);
Pavankumar Kondeti87c01042010-12-07 17:53:58 +05303915 return msm_otg_resume(motg);
3916}
Pavankumar Kondeti87c01042010-12-07 17:53:58 +05303917#endif
3918
Pavankumar Kondeti70187732011-02-15 09:42:34 +05303919#ifdef CONFIG_PM_SLEEP
Pavankumar Kondeti87c01042010-12-07 17:53:58 +05303920static int msm_otg_pm_suspend(struct device *dev)
3921{
Jack Pham5ca279b2012-05-14 18:42:54 -07003922 int ret = 0;
Pavankumar Kondeti87c01042010-12-07 17:53:58 +05303923 struct msm_otg *motg = dev_get_drvdata(dev);
3924
3925 dev_dbg(dev, "OTG PM suspend\n");
Jack Pham5ca279b2012-05-14 18:42:54 -07003926
3927 atomic_set(&motg->pm_suspended, 1);
3928 ret = msm_otg_suspend(motg);
3929 if (ret)
3930 atomic_set(&motg->pm_suspended, 0);
3931
3932 return ret;
Pavankumar Kondeti87c01042010-12-07 17:53:58 +05303933}
3934
3935static int msm_otg_pm_resume(struct device *dev)
3936{
Jack Pham5ca279b2012-05-14 18:42:54 -07003937 int ret = 0;
Pavankumar Kondeti87c01042010-12-07 17:53:58 +05303938 struct msm_otg *motg = dev_get_drvdata(dev);
Pavankumar Kondeti87c01042010-12-07 17:53:58 +05303939
3940 dev_dbg(dev, "OTG PM resume\n");
3941
Jack Pham5ca279b2012-05-14 18:42:54 -07003942 atomic_set(&motg->pm_suspended, 0);
3943 if (motg->sm_work_pending) {
3944 motg->sm_work_pending = false;
Pavankumar Kondeti87c01042010-12-07 17:53:58 +05303945
Jack Pham5ca279b2012-05-14 18:42:54 -07003946 pm_runtime_get_noresume(dev);
3947 ret = msm_otg_resume(motg);
Pavankumar Kondeti87c01042010-12-07 17:53:58 +05303948
Jack Pham5ca279b2012-05-14 18:42:54 -07003949 /* Update runtime PM status */
3950 pm_runtime_disable(dev);
3951 pm_runtime_set_active(dev);
3952 pm_runtime_enable(dev);
3953
3954 queue_work(system_nrt_wq, &motg->sm_work);
3955 }
3956
3957 return ret;
Pavankumar Kondeti87c01042010-12-07 17:53:58 +05303958}
Pavankumar Kondeti87c01042010-12-07 17:53:58 +05303959#endif
3960
Pavankumar Kondeti70187732011-02-15 09:42:34 +05303961#ifdef CONFIG_PM
Pavankumar Kondeti87c01042010-12-07 17:53:58 +05303962static const struct dev_pm_ops msm_otg_dev_pm_ops = {
Pavankumar Kondeti70187732011-02-15 09:42:34 +05303963 SET_SYSTEM_SLEEP_PM_OPS(msm_otg_pm_suspend, msm_otg_pm_resume)
3964 SET_RUNTIME_PM_OPS(msm_otg_runtime_suspend, msm_otg_runtime_resume,
3965 msm_otg_runtime_idle)
Pavankumar Kondeti87c01042010-12-07 17:53:58 +05303966};
Pavankumar Kondeti70187732011-02-15 09:42:34 +05303967#endif
Pavankumar Kondeti87c01042010-12-07 17:53:58 +05303968
Pavankumar Kondetieaea7fe2011-10-27 14:46:45 +05303969static struct of_device_id msm_otg_dt_match[] = {
3970 { .compatible = "qcom,hsusb-otg",
3971 },
3972 {}
3973};
3974
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05303975static struct platform_driver msm_otg_driver = {
3976 .remove = __devexit_p(msm_otg_remove),
3977 .driver = {
3978 .name = DRIVER_NAME,
3979 .owner = THIS_MODULE,
Pavankumar Kondeti70187732011-02-15 09:42:34 +05303980#ifdef CONFIG_PM
Pavankumar Kondeti87c01042010-12-07 17:53:58 +05303981 .pm = &msm_otg_dev_pm_ops,
Pavankumar Kondeti70187732011-02-15 09:42:34 +05303982#endif
Pavankumar Kondetieaea7fe2011-10-27 14:46:45 +05303983 .of_match_table = msm_otg_dt_match,
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05303984 },
3985};
3986
3987static int __init msm_otg_init(void)
3988{
3989 return platform_driver_probe(&msm_otg_driver, msm_otg_probe);
3990}
3991
3992static void __exit msm_otg_exit(void)
3993{
3994 platform_driver_unregister(&msm_otg_driver);
3995}
3996
3997module_init(msm_otg_init);
3998module_exit(msm_otg_exit);
3999
4000MODULE_LICENSE("GPL v2");
4001MODULE_DESCRIPTION("MSM USB transceiver driver");