blob: b6fc43ffd6a09a73689f82132834e56f982e3a5b [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>
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +053044
45#include <mach/clk.h>
Anji jonnala7da3f262011-12-02 17:22:14 -080046#include <mach/msm_xo.h>
Manu Gautamcd82e9d2011-12-20 14:17:28 +053047#include <mach/msm_bus.h>
Mayank Rana248698c2012-04-19 00:03:16 +053048#include <mach/rpm-regulator.h>
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +053049
50#define MSM_USB_BASE (motg->regs)
51#define DRIVER_NAME "msm_otg"
52
Chiranjeevi Velempati489a27c2012-03-29 09:47:17 +053053#define ID_TIMER_FREQ (jiffies + msecs_to_jiffies(500))
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +053054#define ULPI_IO_TIMEOUT_USEC (10 * 1000)
Anji jonnala11aa5c42011-05-04 10:19:48 +053055#define USB_PHY_3P3_VOL_MIN 3050000 /* uV */
56#define USB_PHY_3P3_VOL_MAX 3300000 /* uV */
57#define USB_PHY_3P3_HPM_LOAD 50000 /* uA */
58#define USB_PHY_3P3_LPM_LOAD 4000 /* uA */
59
60#define USB_PHY_1P8_VOL_MIN 1800000 /* uV */
61#define USB_PHY_1P8_VOL_MAX 1800000 /* uV */
62#define USB_PHY_1P8_HPM_LOAD 50000 /* uA */
63#define USB_PHY_1P8_LPM_LOAD 4000 /* uA */
64
Mayank Rana248698c2012-04-19 00:03:16 +053065#define USB_PHY_VDD_DIG_VOL_NONE 0 /*uV */
Vamsi Krishna132b2762011-11-11 16:09:20 -080066#define USB_PHY_VDD_DIG_VOL_MIN 1045000 /* uV */
Anji jonnala11aa5c42011-05-04 10:19:48 +053067#define USB_PHY_VDD_DIG_VOL_MAX 1320000 /* uV */
68
Pavankumar Kondeti4960f312011-12-06 15:46:14 +053069static DECLARE_COMPLETION(pmic_vbus_init);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070070static struct msm_otg *the_msm_otg;
Pavankumar Kondetiaa449e12011-11-04 11:09:26 +053071static bool debug_aca_enabled;
Manu Gautam8bdcc592012-03-06 11:26:06 +053072static bool debug_bus_voting_enabled;
Pavankumar Kondeti2aec9f32012-06-13 09:06:03 +053073static bool mhl_det_in_progress;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070074
Anji jonnala11aa5c42011-05-04 10:19:48 +053075static struct regulator *hsusb_3p3;
76static struct regulator *hsusb_1p8;
77static struct regulator *hsusb_vddcx;
Mayank Ranae3926882011-12-26 09:47:54 +053078static struct regulator *vbus_otg;
Pavankumar Kondeti56dc7422012-07-02 12:45:19 +053079static struct regulator *mhl_usb_hs_switch;
Vijayavardhan Vennapusa05c437c2012-05-25 16:20:46 +053080static struct power_supply *psy;
Anji jonnala11aa5c42011-05-04 10:19:48 +053081
Pavankumar Kondeti4960f312011-12-06 15:46:14 +053082static bool aca_id_turned_on;
Pavankumar Kondetiaa449e12011-11-04 11:09:26 +053083static inline bool aca_enabled(void)
Anji jonnala11aa5c42011-05-04 10:19:48 +053084{
Pavankumar Kondetiaa449e12011-11-04 11:09:26 +053085#ifdef CONFIG_USB_MSM_ACA
86 return true;
87#else
88 return debug_aca_enabled;
89#endif
Anji jonnala11aa5c42011-05-04 10:19:48 +053090}
91
Mayank Rana248698c2012-04-19 00:03:16 +053092static const int vdd_val[VDD_TYPE_MAX][VDD_VAL_MAX] = {
93 { /* VDD_CX CORNER Voting */
94 [VDD_NONE] = RPM_VREG_CORNER_NONE,
95 [VDD_MIN] = RPM_VREG_CORNER_NOMINAL,
96 [VDD_MAX] = RPM_VREG_CORNER_HIGH,
97 },
98 { /* VDD_CX Voltage Voting */
99 [VDD_NONE] = USB_PHY_VDD_DIG_VOL_NONE,
100 [VDD_MIN] = USB_PHY_VDD_DIG_VOL_MIN,
101 [VDD_MAX] = USB_PHY_VDD_DIG_VOL_MAX,
102 },
103};
Anji jonnala11aa5c42011-05-04 10:19:48 +0530104
105static int msm_hsusb_ldo_init(struct msm_otg *motg, int init)
106{
107 int rc = 0;
108
109 if (init) {
Steve Mucklef132c6c2012-06-06 18:30:57 -0700110 hsusb_3p3 = devm_regulator_get(motg->phy.dev, "HSUSB_3p3");
Anji jonnala11aa5c42011-05-04 10:19:48 +0530111 if (IS_ERR(hsusb_3p3)) {
Heikki Krogerus1d4c9292012-02-13 13:24:09 +0200112 dev_err(motg->phy.dev, "unable to get hsusb 3p3\n");
Anji jonnala11aa5c42011-05-04 10:19:48 +0530113 return PTR_ERR(hsusb_3p3);
114 }
115
116 rc = regulator_set_voltage(hsusb_3p3, USB_PHY_3P3_VOL_MIN,
117 USB_PHY_3P3_VOL_MAX);
118 if (rc) {
Steve Mucklef132c6c2012-06-06 18:30:57 -0700119 dev_err(motg->phy.dev, "unable to set voltage level for"
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700120 "hsusb 3p3\n");
Mayank Rana9e9a2ac2012-03-24 04:05:28 +0530121 return rc;
Anji jonnala11aa5c42011-05-04 10:19:48 +0530122 }
Steve Mucklef132c6c2012-06-06 18:30:57 -0700123 hsusb_1p8 = devm_regulator_get(motg->phy.dev, "HSUSB_1p8");
Anji jonnala11aa5c42011-05-04 10:19:48 +0530124 if (IS_ERR(hsusb_1p8)) {
Heikki Krogerus1d4c9292012-02-13 13:24:09 +0200125 dev_err(motg->phy.dev, "unable to get hsusb 1p8\n");
Anji jonnala11aa5c42011-05-04 10:19:48 +0530126 rc = PTR_ERR(hsusb_1p8);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700127 goto put_3p3_lpm;
Anji jonnala11aa5c42011-05-04 10:19:48 +0530128 }
129 rc = regulator_set_voltage(hsusb_1p8, USB_PHY_1P8_VOL_MIN,
130 USB_PHY_1P8_VOL_MAX);
131 if (rc) {
Steve Mucklef132c6c2012-06-06 18:30:57 -0700132 dev_err(motg->phy.dev, "unable to set voltage level for"
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700133 "hsusb 1p8\n");
Anji jonnala11aa5c42011-05-04 10:19:48 +0530134 goto put_1p8;
135 }
136
137 return 0;
138 }
139
Anji jonnala11aa5c42011-05-04 10:19:48 +0530140put_1p8:
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700141 regulator_set_voltage(hsusb_1p8, 0, USB_PHY_1P8_VOL_MAX);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700142put_3p3_lpm:
143 regulator_set_voltage(hsusb_3p3, 0, USB_PHY_3P3_VOL_MAX);
Anji jonnala11aa5c42011-05-04 10:19:48 +0530144 return rc;
145}
146
Pavankumar Kondeti04aebcb2011-05-04 10:19:49 +0530147static int msm_hsusb_config_vddcx(int high)
148{
Mayank Rana248698c2012-04-19 00:03:16 +0530149 struct msm_otg *motg = the_msm_otg;
150 enum usb_vdd_type vdd_type = motg->vdd_type;
151 int max_vol = vdd_val[vdd_type][VDD_MAX];
Pavankumar Kondeti04aebcb2011-05-04 10:19:49 +0530152 int min_vol;
153 int ret;
154
Mayank Rana248698c2012-04-19 00:03:16 +0530155 min_vol = vdd_val[vdd_type][!!high];
Pavankumar Kondeti04aebcb2011-05-04 10:19:49 +0530156 ret = regulator_set_voltage(hsusb_vddcx, min_vol, max_vol);
157 if (ret) {
158 pr_err("%s: unable to set the voltage for regulator "
159 "HSUSB_VDDCX\n", __func__);
160 return ret;
161 }
162
163 pr_debug("%s: min_vol:%d max_vol:%d\n", __func__, min_vol, max_vol);
164
165 return ret;
166}
Pavankumar Kondeti04aebcb2011-05-04 10:19:49 +0530167
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700168static int msm_hsusb_ldo_enable(struct msm_otg *motg, int on)
Anji jonnala11aa5c42011-05-04 10:19:48 +0530169{
170 int ret = 0;
171
Pavankumar Kondeti68964c92011-10-27 14:58:56 +0530172 if (IS_ERR(hsusb_1p8)) {
Anji jonnala11aa5c42011-05-04 10:19:48 +0530173 pr_err("%s: HSUSB_1p8 is not initialized\n", __func__);
174 return -ENODEV;
175 }
176
Pavankumar Kondeti68964c92011-10-27 14:58:56 +0530177 if (IS_ERR(hsusb_3p3)) {
Anji jonnala11aa5c42011-05-04 10:19:48 +0530178 pr_err("%s: HSUSB_3p3 is not initialized\n", __func__);
179 return -ENODEV;
180 }
181
182 if (on) {
183 ret = regulator_set_optimum_mode(hsusb_1p8,
184 USB_PHY_1P8_HPM_LOAD);
185 if (ret < 0) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700186 pr_err("%s: Unable to set HPM of the regulator:"
Anji jonnala11aa5c42011-05-04 10:19:48 +0530187 "HSUSB_1p8\n", __func__);
188 return ret;
189 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700190
191 ret = regulator_enable(hsusb_1p8);
192 if (ret) {
Steve Mucklef132c6c2012-06-06 18:30:57 -0700193 dev_err(motg->phy.dev, "%s: unable to enable the hsusb 1p8\n",
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700194 __func__);
195 regulator_set_optimum_mode(hsusb_1p8, 0);
196 return ret;
197 }
198
Anji jonnala11aa5c42011-05-04 10:19:48 +0530199 ret = regulator_set_optimum_mode(hsusb_3p3,
200 USB_PHY_3P3_HPM_LOAD);
201 if (ret < 0) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700202 pr_err("%s: Unable to set HPM of the regulator:"
Anji jonnala11aa5c42011-05-04 10:19:48 +0530203 "HSUSB_3p3\n", __func__);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700204 regulator_set_optimum_mode(hsusb_1p8, 0);
205 regulator_disable(hsusb_1p8);
Anji jonnala11aa5c42011-05-04 10:19:48 +0530206 return ret;
207 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700208
209 ret = regulator_enable(hsusb_3p3);
210 if (ret) {
Steve Mucklef132c6c2012-06-06 18:30:57 -0700211 dev_err(motg->phy.dev, "%s: unable to enable the hsusb 3p3\n",
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700212 __func__);
213 regulator_set_optimum_mode(hsusb_3p3, 0);
214 regulator_set_optimum_mode(hsusb_1p8, 0);
215 regulator_disable(hsusb_1p8);
216 return ret;
217 }
218
Anji jonnala11aa5c42011-05-04 10:19:48 +0530219 } else {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700220 ret = regulator_disable(hsusb_1p8);
221 if (ret) {
Steve Mucklef132c6c2012-06-06 18:30:57 -0700222 dev_err(motg->phy.dev, "%s: unable to disable the hsusb 1p8\n",
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700223 __func__);
224 return ret;
225 }
226
227 ret = regulator_set_optimum_mode(hsusb_1p8, 0);
Anji jonnala11aa5c42011-05-04 10:19:48 +0530228 if (ret < 0)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700229 pr_err("%s: Unable to set LPM of the regulator:"
Anji jonnala11aa5c42011-05-04 10:19:48 +0530230 "HSUSB_1p8\n", __func__);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700231
232 ret = regulator_disable(hsusb_3p3);
233 if (ret) {
Steve Mucklef132c6c2012-06-06 18:30:57 -0700234 dev_err(motg->phy.dev, "%s: unable to disable the hsusb 3p3\n",
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700235 __func__);
236 return ret;
237 }
238 ret = regulator_set_optimum_mode(hsusb_3p3, 0);
Anji jonnala11aa5c42011-05-04 10:19:48 +0530239 if (ret < 0)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700240 pr_err("%s: Unable to set LPM of the regulator:"
Anji jonnala11aa5c42011-05-04 10:19:48 +0530241 "HSUSB_3p3\n", __func__);
242 }
243
244 pr_debug("reg (%s)\n", on ? "HPM" : "LPM");
245 return ret < 0 ? ret : 0;
246}
247
Vijayavardhan Vennapusafc464f02011-11-04 21:54:00 +0530248static void msm_hsusb_mhl_switch_enable(struct msm_otg *motg, bool on)
249{
Vijayavardhan Vennapusafc464f02011-11-04 21:54:00 +0530250 struct msm_otg_platform_data *pdata = motg->pdata;
251
252 if (!pdata->mhl_enable)
253 return;
254
Pavankumar Kondeti56dc7422012-07-02 12:45:19 +0530255 if (!mhl_usb_hs_switch) {
256 pr_err("%s: mhl_usb_hs_switch is NULL.\n", __func__);
Vijayavardhan Vennapusafc464f02011-11-04 21:54:00 +0530257 return;
258 }
259
Mayank Rana9e9a2ac2012-03-24 04:05:28 +0530260 if (on) {
Pavankumar Kondeti56dc7422012-07-02 12:45:19 +0530261 if (regulator_enable(mhl_usb_hs_switch))
262 pr_err("unable to enable mhl_usb_hs_switch\n");
Mayank Rana9e9a2ac2012-03-24 04:05:28 +0530263 } else {
Pavankumar Kondeti56dc7422012-07-02 12:45:19 +0530264 regulator_disable(mhl_usb_hs_switch);
Mayank Rana9e9a2ac2012-03-24 04:05:28 +0530265 }
Vijayavardhan Vennapusafc464f02011-11-04 21:54:00 +0530266}
267
Heikki Krogerus1d4c9292012-02-13 13:24:09 +0200268static int ulpi_read(struct usb_phy *phy, u32 reg)
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +0530269{
Heikki Krogerus1d4c9292012-02-13 13:24:09 +0200270 struct msm_otg *motg = container_of(phy, struct msm_otg, phy);
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +0530271 int cnt = 0;
272
273 /* initiate read operation */
274 writel(ULPI_RUN | ULPI_READ | ULPI_ADDR(reg),
275 USB_ULPI_VIEWPORT);
276
277 /* wait for completion */
278 while (cnt < ULPI_IO_TIMEOUT_USEC) {
279 if (!(readl(USB_ULPI_VIEWPORT) & ULPI_RUN))
280 break;
281 udelay(1);
282 cnt++;
283 }
284
285 if (cnt >= ULPI_IO_TIMEOUT_USEC) {
Heikki Krogerus1d4c9292012-02-13 13:24:09 +0200286 dev_err(phy->dev, "ulpi_read: timeout %08x\n",
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +0530287 readl(USB_ULPI_VIEWPORT));
288 return -ETIMEDOUT;
289 }
290 return ULPI_DATA_READ(readl(USB_ULPI_VIEWPORT));
291}
292
Heikki Krogerus1d4c9292012-02-13 13:24:09 +0200293static int ulpi_write(struct usb_phy *phy, u32 val, u32 reg)
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +0530294{
Heikki Krogerus1d4c9292012-02-13 13:24:09 +0200295 struct msm_otg *motg = container_of(phy, struct msm_otg, phy);
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +0530296 int cnt = 0;
297
298 /* initiate write operation */
299 writel(ULPI_RUN | ULPI_WRITE |
300 ULPI_ADDR(reg) | ULPI_DATA(val),
301 USB_ULPI_VIEWPORT);
302
303 /* wait for completion */
304 while (cnt < ULPI_IO_TIMEOUT_USEC) {
305 if (!(readl(USB_ULPI_VIEWPORT) & ULPI_RUN))
306 break;
307 udelay(1);
308 cnt++;
309 }
310
311 if (cnt >= ULPI_IO_TIMEOUT_USEC) {
Heikki Krogerus1d4c9292012-02-13 13:24:09 +0200312 dev_err(phy->dev, "ulpi_write: timeout\n");
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +0530313 return -ETIMEDOUT;
314 }
315 return 0;
316}
317
Heikki Krogerus1d4c9292012-02-13 13:24:09 +0200318static struct usb_phy_io_ops msm_otg_io_ops = {
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +0530319 .read = ulpi_read,
320 .write = ulpi_write,
321};
322
323static void ulpi_init(struct msm_otg *motg)
324{
325 struct msm_otg_platform_data *pdata = motg->pdata;
326 int *seq = pdata->phy_init_seq;
327
328 if (!seq)
329 return;
330
331 while (seq[0] >= 0) {
Heikki Krogerus1d4c9292012-02-13 13:24:09 +0200332 dev_vdbg(motg->phy.dev, "ulpi: write 0x%02x to 0x%02x\n",
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +0530333 seq[0], seq[1]);
Heikki Krogerus1d4c9292012-02-13 13:24:09 +0200334 ulpi_write(&motg->phy, seq[0], seq[1]);
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +0530335 seq += 2;
336 }
337}
338
339static int msm_otg_link_clk_reset(struct msm_otg *motg, bool assert)
340{
341 int ret;
342
Pavankumar Kondeti923262e2012-04-20 15:34:24 +0530343 if (IS_ERR(motg->clk))
344 return 0;
345
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +0530346 if (assert) {
347 ret = clk_reset(motg->clk, CLK_RESET_ASSERT);
348 if (ret)
Heikki Krogerus1d4c9292012-02-13 13:24:09 +0200349 dev_err(motg->phy.dev, "usb hs_clk assert failed\n");
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +0530350 } else {
351 ret = clk_reset(motg->clk, CLK_RESET_DEASSERT);
352 if (ret)
Heikki Krogerus1d4c9292012-02-13 13:24:09 +0200353 dev_err(motg->phy.dev, "usb hs_clk deassert failed\n");
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +0530354 }
355 return ret;
356}
357
358static int msm_otg_phy_clk_reset(struct msm_otg *motg)
359{
360 int ret;
361
Amit Blay02eff132011-09-21 16:46:24 +0300362 if (IS_ERR(motg->phy_reset_clk))
363 return 0;
364
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +0530365 ret = clk_reset(motg->phy_reset_clk, CLK_RESET_ASSERT);
366 if (ret) {
Heikki Krogerus1d4c9292012-02-13 13:24:09 +0200367 dev_err(motg->phy.dev, "usb phy clk assert failed\n");
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +0530368 return ret;
369 }
370 usleep_range(10000, 12000);
371 ret = clk_reset(motg->phy_reset_clk, CLK_RESET_DEASSERT);
372 if (ret)
Heikki Krogerus1d4c9292012-02-13 13:24:09 +0200373 dev_err(motg->phy.dev, "usb phy clk deassert failed\n");
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +0530374 return ret;
375}
376
377static int msm_otg_phy_reset(struct msm_otg *motg)
378{
379 u32 val;
380 int ret;
381 int retries;
382
383 ret = msm_otg_link_clk_reset(motg, 1);
384 if (ret)
385 return ret;
386 ret = msm_otg_phy_clk_reset(motg);
387 if (ret)
388 return ret;
389 ret = msm_otg_link_clk_reset(motg, 0);
390 if (ret)
391 return ret;
392
393 val = readl(USB_PORTSC) & ~PORTSC_PTS_MASK;
394 writel(val | PORTSC_PTS_ULPI, USB_PORTSC);
395
396 for (retries = 3; retries > 0; retries--) {
Heikki Krogerus1d4c9292012-02-13 13:24:09 +0200397 ret = ulpi_write(&motg->phy, ULPI_FUNC_CTRL_SUSPENDM,
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +0530398 ULPI_CLR(ULPI_FUNC_CTRL));
399 if (!ret)
400 break;
401 ret = msm_otg_phy_clk_reset(motg);
402 if (ret)
403 return ret;
404 }
405 if (!retries)
406 return -ETIMEDOUT;
407
408 /* This reset calibrates the phy, if the above write succeeded */
409 ret = msm_otg_phy_clk_reset(motg);
410 if (ret)
411 return ret;
412
413 for (retries = 3; retries > 0; retries--) {
Heikki Krogerus1d4c9292012-02-13 13:24:09 +0200414 ret = ulpi_read(&motg->phy, ULPI_DEBUG);
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +0530415 if (ret != -ETIMEDOUT)
416 break;
417 ret = msm_otg_phy_clk_reset(motg);
418 if (ret)
419 return ret;
420 }
421 if (!retries)
422 return -ETIMEDOUT;
423
Heikki Krogerus1d4c9292012-02-13 13:24:09 +0200424 dev_info(motg->phy.dev, "phy_reset: success\n");
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +0530425 return 0;
426}
427
428#define LINK_RESET_TIMEOUT_USEC (250 * 1000)
Pavankumar Kondetiaa449e12011-11-04 11:09:26 +0530429static int msm_otg_link_reset(struct msm_otg *motg)
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +0530430{
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +0530431 int cnt = 0;
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +0530432
Pavankumar Kondetiaa449e12011-11-04 11:09:26 +0530433 writel_relaxed(USBCMD_RESET, USB_USBCMD);
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +0530434 while (cnt < LINK_RESET_TIMEOUT_USEC) {
Pavankumar Kondetiaa449e12011-11-04 11:09:26 +0530435 if (!(readl_relaxed(USB_USBCMD) & USBCMD_RESET))
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +0530436 break;
437 udelay(1);
438 cnt++;
439 }
440 if (cnt >= LINK_RESET_TIMEOUT_USEC)
441 return -ETIMEDOUT;
442
443 /* select ULPI phy */
Pavankumar Kondetiaa449e12011-11-04 11:09:26 +0530444 writel_relaxed(0x80000000, USB_PORTSC);
445 writel_relaxed(0x0, USB_AHBBURST);
Vijayavardhan Vennapusa5f32d7a2012-03-14 16:30:26 +0530446 writel_relaxed(0x08, USB_AHBMODE);
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +0530447
Pavankumar Kondetiaa449e12011-11-04 11:09:26 +0530448 return 0;
449}
450
Steve Mucklef132c6c2012-06-06 18:30:57 -0700451static int msm_otg_reset(struct usb_phy *phy)
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +0530452{
Steve Mucklef132c6c2012-06-06 18:30:57 -0700453 struct msm_otg *motg = container_of(phy, struct msm_otg, phy);
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +0530454 struct msm_otg_platform_data *pdata = motg->pdata;
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +0530455 int ret;
456 u32 val = 0;
457 u32 ulpi_val = 0;
458
Ofir Cohen4da266f2012-01-03 10:19:29 +0200459 /*
460 * USB PHY and Link reset also reset the USB BAM.
461 * Thus perform reset operation only once to avoid
462 * USB BAM reset on other cases e.g. USB cable disconnections.
463 */
464 if (pdata->disable_reset_on_disconnect) {
465 if (motg->reset_counter)
466 return 0;
467 else
468 motg->reset_counter++;
469 }
470
Pavankumar Kondeti923262e2012-04-20 15:34:24 +0530471 if (!IS_ERR(motg->clk))
472 clk_prepare_enable(motg->clk);
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +0530473 ret = msm_otg_phy_reset(motg);
474 if (ret) {
Steve Mucklef132c6c2012-06-06 18:30:57 -0700475 dev_err(phy->dev, "phy_reset failed\n");
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +0530476 return ret;
477 }
478
Pavankumar Kondeti4960f312011-12-06 15:46:14 +0530479 aca_id_turned_on = false;
Pavankumar Kondetiaa449e12011-11-04 11:09:26 +0530480 ret = msm_otg_link_reset(motg);
481 if (ret) {
Steve Mucklef132c6c2012-06-06 18:30:57 -0700482 dev_err(phy->dev, "link reset failed\n");
Pavankumar Kondetiaa449e12011-11-04 11:09:26 +0530483 return ret;
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +0530484 }
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +0530485 msleep(100);
486
Anji jonnalaa8b8d732011-12-06 10:03:24 +0530487 ulpi_init(motg);
488
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700489 /* Ensure that RESET operation is completed before turning off clock */
490 mb();
Pavankumar Kondetiaa449e12011-11-04 11:09:26 +0530491
Pavankumar Kondeti923262e2012-04-20 15:34:24 +0530492 if (!IS_ERR(motg->clk))
493 clk_disable_unprepare(motg->clk);
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +0530494
495 if (pdata->otg_control == OTG_PHY_CONTROL) {
Pavankumar Kondeti4960f312011-12-06 15:46:14 +0530496 val = readl_relaxed(USB_OTGSC);
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +0530497 if (pdata->mode == USB_OTG) {
498 ulpi_val = ULPI_INT_IDGRD | ULPI_INT_SESS_VALID;
499 val |= OTGSC_IDIE | OTGSC_BSVIE;
500 } else if (pdata->mode == USB_PERIPHERAL) {
501 ulpi_val = ULPI_INT_SESS_VALID;
502 val |= OTGSC_BSVIE;
503 }
Pavankumar Kondeti4960f312011-12-06 15:46:14 +0530504 writel_relaxed(val, USB_OTGSC);
Heikki Krogerus1d4c9292012-02-13 13:24:09 +0200505 ulpi_write(phy, ulpi_val, ULPI_USB_INT_EN_RISE);
506 ulpi_write(phy, ulpi_val, ULPI_USB_INT_EN_FALL);
Pavankumar Kondeti446f4542012-02-01 13:57:13 +0530507 } else if (pdata->otg_control == OTG_PMIC_CONTROL) {
Steve Mucklef132c6c2012-06-06 18:30:57 -0700508 ulpi_write(phy, OTG_COMP_DISABLE,
Vijayavardhan Vennapusa03171c72012-04-26 14:44:48 +0530509 ULPI_SET(ULPI_PWR_CLK_MNG_REG));
Pavankumar Kondeti446f4542012-02-01 13:57:13 +0530510 /* Enable PMIC pull-up */
511 pm8xxx_usb_id_pullup(1);
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +0530512 }
513
514 return 0;
515}
516
Vijayavardhan Vennapusaa3152032012-03-05 16:29:30 +0530517static const char *timer_string(int bit)
518{
519 switch (bit) {
520 case A_WAIT_VRISE: return "a_wait_vrise";
521 case A_WAIT_VFALL: return "a_wait_vfall";
522 case B_SRP_FAIL: return "b_srp_fail";
523 case A_WAIT_BCON: return "a_wait_bcon";
524 case A_AIDL_BDIS: return "a_aidl_bdis";
525 case A_BIDL_ADIS: return "a_bidl_adis";
526 case B_ASE0_BRST: return "b_ase0_brst";
527 case A_TST_MAINT: return "a_tst_maint";
528 case B_TST_SRP: return "b_tst_srp";
529 case B_TST_CONFIG: return "b_tst_config";
530 default: return "UNDEFINED";
531 }
532}
533
534static enum hrtimer_restart msm_otg_timer_func(struct hrtimer *hrtimer)
535{
536 struct msm_otg *motg = container_of(hrtimer, struct msm_otg, timer);
537
538 switch (motg->active_tmout) {
539 case A_WAIT_VRISE:
540 /* TODO: use vbus_vld interrupt */
541 set_bit(A_VBUS_VLD, &motg->inputs);
542 break;
543 case A_TST_MAINT:
544 /* OTG PET: End session after TA_TST_MAINT */
545 set_bit(A_BUS_DROP, &motg->inputs);
546 break;
547 case B_TST_SRP:
548 /*
549 * OTG PET: Initiate SRP after TB_TST_SRP of
550 * previous session end.
551 */
552 set_bit(B_BUS_REQ, &motg->inputs);
553 break;
554 case B_TST_CONFIG:
555 clear_bit(A_CONN, &motg->inputs);
556 break;
557 default:
558 set_bit(motg->active_tmout, &motg->tmouts);
559 }
560
561 pr_debug("expired %s timer\n", timer_string(motg->active_tmout));
562 queue_work(system_nrt_wq, &motg->sm_work);
563 return HRTIMER_NORESTART;
564}
565
566static void msm_otg_del_timer(struct msm_otg *motg)
567{
568 int bit = motg->active_tmout;
569
570 pr_debug("deleting %s timer. remaining %lld msec\n", timer_string(bit),
571 div_s64(ktime_to_us(hrtimer_get_remaining(
572 &motg->timer)), 1000));
573 hrtimer_cancel(&motg->timer);
574 clear_bit(bit, &motg->tmouts);
575}
576
577static void msm_otg_start_timer(struct msm_otg *motg, int time, int bit)
578{
579 clear_bit(bit, &motg->tmouts);
580 motg->active_tmout = bit;
581 pr_debug("starting %s timer\n", timer_string(bit));
582 hrtimer_start(&motg->timer,
583 ktime_set(time / 1000, (time % 1000) * 1000000),
584 HRTIMER_MODE_REL);
585}
586
587static void msm_otg_init_timer(struct msm_otg *motg)
588{
589 hrtimer_init(&motg->timer, CLOCK_MONOTONIC, HRTIMER_MODE_REL);
590 motg->timer.function = msm_otg_timer_func;
591}
592
Steve Mucklef132c6c2012-06-06 18:30:57 -0700593static int msm_otg_start_hnp(struct usb_otg *otg)
Vijayavardhan Vennapusaa3152032012-03-05 16:29:30 +0530594{
Steve Mucklef132c6c2012-06-06 18:30:57 -0700595 struct msm_otg *motg = container_of(otg->phy, struct msm_otg, phy);
Vijayavardhan Vennapusaa3152032012-03-05 16:29:30 +0530596
Steve Mucklef132c6c2012-06-06 18:30:57 -0700597 if (otg->phy->state != OTG_STATE_A_HOST) {
Vijayavardhan Vennapusaa3152032012-03-05 16:29:30 +0530598 pr_err("HNP can not be initiated in %s state\n",
Steve Mucklef132c6c2012-06-06 18:30:57 -0700599 otg_state_string(otg->phy->state));
Vijayavardhan Vennapusaa3152032012-03-05 16:29:30 +0530600 return -EINVAL;
601 }
602
603 pr_debug("A-Host: HNP initiated\n");
604 clear_bit(A_BUS_REQ, &motg->inputs);
605 queue_work(system_nrt_wq, &motg->sm_work);
606 return 0;
607}
608
Steve Mucklef132c6c2012-06-06 18:30:57 -0700609static int msm_otg_start_srp(struct usb_otg *otg)
Vijayavardhan Vennapusaa3152032012-03-05 16:29:30 +0530610{
Steve Mucklef132c6c2012-06-06 18:30:57 -0700611 struct msm_otg *motg = container_of(otg->phy, struct msm_otg, phy);
Vijayavardhan Vennapusaa3152032012-03-05 16:29:30 +0530612 u32 val;
613 int ret = 0;
614
Steve Mucklef132c6c2012-06-06 18:30:57 -0700615 if (otg->phy->state != OTG_STATE_B_IDLE) {
Vijayavardhan Vennapusaa3152032012-03-05 16:29:30 +0530616 pr_err("SRP can not be initiated in %s state\n",
Steve Mucklef132c6c2012-06-06 18:30:57 -0700617 otg_state_string(otg->phy->state));
Vijayavardhan Vennapusaa3152032012-03-05 16:29:30 +0530618 ret = -EINVAL;
619 goto out;
620 }
621
622 if ((jiffies - motg->b_last_se0_sess) < msecs_to_jiffies(TB_SRP_INIT)) {
623 pr_debug("initial conditions of SRP are not met. Try again"
624 "after some time\n");
625 ret = -EAGAIN;
626 goto out;
627 }
628
629 pr_debug("B-Device SRP started\n");
630
631 /*
632 * PHY won't pull D+ high unless it detects Vbus valid.
633 * Since by definition, SRP is only done when Vbus is not valid,
634 * software work-around needs to be used to spoof the PHY into
635 * thinking it is valid. This can be done using the VBUSVLDEXTSEL and
636 * VBUSVLDEXT register bits.
637 */
Steve Mucklef132c6c2012-06-06 18:30:57 -0700638 ulpi_write(otg->phy, 0x03, 0x97);
Vijayavardhan Vennapusaa3152032012-03-05 16:29:30 +0530639 /*
640 * Harware auto assist data pulsing: Data pulse is given
641 * for 7msec; wait for vbus
642 */
643 val = readl_relaxed(USB_OTGSC);
644 writel_relaxed((val & ~OTGSC_INTSTS_MASK) | OTGSC_HADP, USB_OTGSC);
645
646 /* VBUS plusing is obsoleted in OTG 2.0 supplement */
647out:
648 return ret;
649}
650
Steve Mucklef132c6c2012-06-06 18:30:57 -0700651static void msm_otg_host_hnp_enable(struct usb_otg *otg, bool enable)
Vijayavardhan Vennapusaa3152032012-03-05 16:29:30 +0530652{
653 struct usb_hcd *hcd = bus_to_hcd(otg->host);
654 struct usb_device *rhub = otg->host->root_hub;
655
656 if (enable) {
657 pm_runtime_disable(&rhub->dev);
658 rhub->state = USB_STATE_NOTATTACHED;
659 hcd->driver->bus_suspend(hcd);
660 clear_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags);
661 } else {
662 usb_remove_hcd(hcd);
Steve Mucklef132c6c2012-06-06 18:30:57 -0700663 msm_otg_reset(otg->phy);
Vijayavardhan Vennapusaa3152032012-03-05 16:29:30 +0530664 usb_add_hcd(hcd, hcd->irq, IRQF_SHARED);
665 }
666}
667
Steve Mucklef132c6c2012-06-06 18:30:57 -0700668static int msm_otg_set_suspend(struct usb_phy *phy, int suspend)
Pavankumar Kondeti8be99cf2011-08-04 10:48:08 +0530669{
Steve Mucklef132c6c2012-06-06 18:30:57 -0700670 struct msm_otg *motg = container_of(phy, struct msm_otg, phy);
Pavankumar Kondeti8be99cf2011-08-04 10:48:08 +0530671
Amit Blay6fa647a2012-05-24 14:12:08 +0300672 if (aca_enabled())
Vijayavardhan Vennapusaa3152032012-03-05 16:29:30 +0530673 return 0;
Pavankumar Kondeti8be99cf2011-08-04 10:48:08 +0530674
Jack Pham69e621d2012-06-25 18:48:07 -0700675 if (atomic_read(&motg->in_lpm) == suspend)
676 return 0;
677
Vijayavardhan Vennapusaa3152032012-03-05 16:29:30 +0530678 if (suspend) {
Steve Mucklef132c6c2012-06-06 18:30:57 -0700679 switch (phy->state) {
Vijayavardhan Vennapusaa3152032012-03-05 16:29:30 +0530680 case OTG_STATE_A_WAIT_BCON:
681 if (TA_WAIT_BCON > 0)
682 break;
683 /* fall through */
684 case OTG_STATE_A_HOST:
685 pr_debug("host bus suspend\n");
686 clear_bit(A_BUS_REQ, &motg->inputs);
687 queue_work(system_nrt_wq, &motg->sm_work);
688 break;
Amit Blay6fa647a2012-05-24 14:12:08 +0300689 case OTG_STATE_B_PERIPHERAL:
690 pr_debug("peripheral bus suspend\n");
691 if (!(motg->caps & ALLOW_LPM_ON_DEV_SUSPEND))
692 break;
693 set_bit(A_BUS_SUSPEND, &motg->inputs);
694 queue_work(system_nrt_wq, &motg->sm_work);
695 break;
696
Vijayavardhan Vennapusaa3152032012-03-05 16:29:30 +0530697 default:
698 break;
699 }
700 } else {
Steve Mucklef132c6c2012-06-06 18:30:57 -0700701 switch (phy->state) {
Vijayavardhan Vennapusaa3152032012-03-05 16:29:30 +0530702 case OTG_STATE_A_SUSPEND:
703 /* Remote wakeup or resume */
704 set_bit(A_BUS_REQ, &motg->inputs);
Steve Mucklef132c6c2012-06-06 18:30:57 -0700705 phy->state = OTG_STATE_A_HOST;
Jack Pham5ca279b2012-05-14 18:42:54 -0700706
707 /* ensure hardware is not in low power mode */
Steve Mucklef132c6c2012-06-06 18:30:57 -0700708 pm_runtime_resume(phy->dev);
Vijayavardhan Vennapusaa3152032012-03-05 16:29:30 +0530709 break;
Amit Blay6fa647a2012-05-24 14:12:08 +0300710 case OTG_STATE_B_PERIPHERAL:
711 pr_debug("peripheral bus resume\n");
712 if (!(motg->caps & ALLOW_LPM_ON_DEV_SUSPEND))
713 break;
714 clear_bit(A_BUS_SUSPEND, &motg->inputs);
715 queue_work(system_nrt_wq, &motg->sm_work);
716 break;
Vijayavardhan Vennapusaa3152032012-03-05 16:29:30 +0530717 default:
718 break;
719 }
720 }
Pavankumar Kondeti8be99cf2011-08-04 10:48:08 +0530721 return 0;
722}
723
Pavankumar Kondeti87c01042010-12-07 17:53:58 +0530724#define PHY_SUSPEND_TIMEOUT_USEC (500 * 1000)
Pavankumar Kondeti70187732011-02-15 09:42:34 +0530725#define PHY_RESUME_TIMEOUT_USEC (100 * 1000)
726
727#ifdef CONFIG_PM_SLEEP
Pavankumar Kondeti87c01042010-12-07 17:53:58 +0530728static int msm_otg_suspend(struct msm_otg *motg)
729{
Heikki Krogerus1d4c9292012-02-13 13:24:09 +0200730 struct usb_phy *phy = &motg->phy;
731 struct usb_bus *bus = phy->otg->host;
Pavankumar Kondeti87c01042010-12-07 17:53:58 +0530732 struct msm_otg_platform_data *pdata = motg->pdata;
733 int cnt = 0;
Amit Blay6fa647a2012-05-24 14:12:08 +0300734 bool host_bus_suspend, device_bus_suspend, dcp;
Pavankumar Kondeti4960f312011-12-06 15:46:14 +0530735 u32 phy_ctrl_val = 0, cmd_val;
Stephen Boyd30ad10b2012-03-01 14:51:04 -0800736 unsigned ret;
Rajkumar Raghupathy242565d2011-12-13 12:10:59 +0530737 u32 portsc;
Pavankumar Kondeti87c01042010-12-07 17:53:58 +0530738
739 if (atomic_read(&motg->in_lpm))
740 return 0;
741
742 disable_irq(motg->irq);
Pavankumar Kondeti2aec9f32012-06-13 09:06:03 +0530743 host_bus_suspend = !test_bit(MHL, &motg->inputs) && phy->otg->host &&
744 !test_bit(ID, &motg->inputs);
Steve Mucklef132c6c2012-06-06 18:30:57 -0700745 device_bus_suspend = phy->otg->gadget && test_bit(ID, &motg->inputs) &&
Amit Blay6fa647a2012-05-24 14:12:08 +0300746 test_bit(A_BUS_SUSPEND, &motg->inputs) &&
747 motg->caps & ALLOW_LPM_ON_DEV_SUSPEND;
Pavankumar Kondeti283146f2012-01-12 12:51:19 +0530748 dcp = motg->chg_type == USB_DCP_CHARGER;
Pavankumar Kondeti87c01042010-12-07 17:53:58 +0530749 /*
Pavankumar Kondeti04aebcb2011-05-04 10:19:49 +0530750 * Chipidea 45-nm PHY suspend sequence:
751 *
Pavankumar Kondeti87c01042010-12-07 17:53:58 +0530752 * Interrupt Latch Register auto-clear feature is not present
753 * in all PHY versions. Latch register is clear on read type.
754 * Clear latch register to avoid spurious wakeup from
755 * low power mode (LPM).
Pavankumar Kondeti04aebcb2011-05-04 10:19:49 +0530756 *
Pavankumar Kondeti87c01042010-12-07 17:53:58 +0530757 * PHY comparators are disabled when PHY enters into low power
758 * mode (LPM). Keep PHY comparators ON in LPM only when we expect
759 * VBUS/Id notifications from USB PHY. Otherwise turn off USB
760 * PHY comparators. This save significant amount of power.
Pavankumar Kondeti04aebcb2011-05-04 10:19:49 +0530761 *
Pavankumar Kondeti87c01042010-12-07 17:53:58 +0530762 * PLL is not turned off when PHY enters into low power mode (LPM).
763 * Disable PLL for maximum power savings.
764 */
Pavankumar Kondeti04aebcb2011-05-04 10:19:49 +0530765
766 if (motg->pdata->phy_type == CI_45NM_INTEGRATED_PHY) {
Heikki Krogerus1d4c9292012-02-13 13:24:09 +0200767 ulpi_read(phy, 0x14);
Pavankumar Kondeti04aebcb2011-05-04 10:19:49 +0530768 if (pdata->otg_control == OTG_PHY_CONTROL)
Heikki Krogerus1d4c9292012-02-13 13:24:09 +0200769 ulpi_write(phy, 0x01, 0x30);
770 ulpi_write(phy, 0x08, 0x09);
Pavankumar Kondeti04aebcb2011-05-04 10:19:49 +0530771 }
Pavankumar Kondeti87c01042010-12-07 17:53:58 +0530772
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700773
Rajkumar Raghupathy242565d2011-12-13 12:10:59 +0530774 /* Set the PHCD bit, only if it is not set by the controller.
Pavankumar Kondeti87c01042010-12-07 17:53:58 +0530775 * PHY may take some time or even fail to enter into low power
776 * mode (LPM). Hence poll for 500 msec and reset the PHY and link
777 * in failure case.
778 */
Rajkumar Raghupathy242565d2011-12-13 12:10:59 +0530779 portsc = readl_relaxed(USB_PORTSC);
780 if (!(portsc & PORTSC_PHCD)) {
781 writel_relaxed(portsc | PORTSC_PHCD,
782 USB_PORTSC);
783 while (cnt < PHY_SUSPEND_TIMEOUT_USEC) {
784 if (readl_relaxed(USB_PORTSC) & PORTSC_PHCD)
785 break;
786 udelay(1);
787 cnt++;
788 }
Pavankumar Kondeti87c01042010-12-07 17:53:58 +0530789 }
790
791 if (cnt >= PHY_SUSPEND_TIMEOUT_USEC) {
Heikki Krogerus1d4c9292012-02-13 13:24:09 +0200792 dev_err(phy->dev, "Unable to suspend PHY\n");
793 msm_otg_reset(phy);
Pavankumar Kondeti87c01042010-12-07 17:53:58 +0530794 enable_irq(motg->irq);
795 return -ETIMEDOUT;
796 }
797
798 /*
799 * PHY has capability to generate interrupt asynchronously in low
800 * power mode (LPM). This interrupt is level triggered. So USB IRQ
801 * line must be disabled till async interrupt enable bit is cleared
802 * in USBCMD register. Assert STP (ULPI interface STOP signal) to
803 * block data communication from PHY.
Pavankumar Kondeti6be675f2012-04-16 13:29:24 +0530804 *
805 * PHY retention mode is disallowed while entering to LPM with wall
806 * charger connected. But PHY is put into suspend mode. Hence
807 * enable asynchronous interrupt to detect charger disconnection when
808 * PMIC notifications are unavailable.
Pavankumar Kondeti87c01042010-12-07 17:53:58 +0530809 */
Pavankumar Kondeti4960f312011-12-06 15:46:14 +0530810 cmd_val = readl_relaxed(USB_USBCMD);
Amit Blay6fa647a2012-05-24 14:12:08 +0300811 if (host_bus_suspend || device_bus_suspend ||
812 (motg->pdata->otg_control == OTG_PHY_CONTROL && dcp))
Pavankumar Kondeti4960f312011-12-06 15:46:14 +0530813 cmd_val |= ASYNC_INTR_CTRL | ULPI_STP_CTRL;
814 else
815 cmd_val |= ULPI_STP_CTRL;
816 writel_relaxed(cmd_val, USB_USBCMD);
Pavankumar Kondeti87c01042010-12-07 17:53:58 +0530817
Pavankumar Kondeti283146f2012-01-12 12:51:19 +0530818 /*
819 * BC1.2 spec mandates PD to enable VDP_SRC when charging from DCP.
820 * PHY retention and collapse can not happen with VDP_SRC enabled.
821 */
Amit Blay6fa647a2012-05-24 14:12:08 +0300822 if (motg->caps & ALLOW_PHY_RETENTION && !host_bus_suspend &&
823 !device_bus_suspend && !dcp) {
Amit Blay58b31472011-11-18 09:39:39 +0200824 phy_ctrl_val = readl_relaxed(USB_PHY_CTRL);
825 if (motg->pdata->otg_control == OTG_PHY_CONTROL)
826 /* Enable PHY HV interrupts to wake MPM/Link */
827 phy_ctrl_val |=
828 (PHY_IDHV_INTEN | PHY_OTGSESSVLDHV_INTEN);
Pavankumar Kondeti04aebcb2011-05-04 10:19:49 +0530829
Amit Blay58b31472011-11-18 09:39:39 +0200830 writel_relaxed(phy_ctrl_val & ~PHY_RETEN, USB_PHY_CTRL);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700831 motg->lpm_flags |= PHY_RETENTIONED;
Pavankumar Kondeti04aebcb2011-05-04 10:19:49 +0530832 }
833
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700834 /* Ensure that above operation is completed before turning off clocks */
835 mb();
Amit Blay9b6e58b2012-06-18 13:12:49 +0300836 if (!motg->pdata->core_clk_always_on_workaround) {
837 clk_disable_unprepare(motg->pclk);
838 clk_disable_unprepare(motg->core_clk);
839 }
Pavankumar Kondeti87c01042010-12-07 17:53:58 +0530840
Anji jonnala7da3f262011-12-02 17:22:14 -0800841 /* usb phy no more require TCXO clock, hence vote for TCXO disable */
Vijayavardhan Vennapusabbdd6082012-06-06 14:14:25 +0530842 if (!host_bus_suspend) {
843 ret = msm_xo_mode_vote(motg->xo_handle, MSM_XO_MODE_OFF);
844 if (ret)
Steve Muckle75c34ca2012-06-12 14:27:40 -0700845 dev_err(phy->dev, "%s failed to devote for "
Vijayavardhan Vennapusabbdd6082012-06-06 14:14:25 +0530846 "TCXO D0 buffer%d\n", __func__, ret);
847 else
848 motg->lpm_flags |= XO_SHUTDOWN;
849 }
Anji jonnala7da3f262011-12-02 17:22:14 -0800850
Pavankumar Kondeti283146f2012-01-12 12:51:19 +0530851 if (motg->caps & ALLOW_PHY_POWER_COLLAPSE &&
852 !host_bus_suspend && !dcp) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700853 msm_hsusb_ldo_enable(motg, 0);
854 motg->lpm_flags |= PHY_PWR_COLLAPSED;
Anji jonnala0f73cac2011-05-04 10:19:46 +0530855 }
856
Vijayavardhan Vennapusafc464f02011-11-04 21:54:00 +0530857 if (motg->lpm_flags & PHY_RETENTIONED) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700858 msm_hsusb_config_vddcx(0);
Vijayavardhan Vennapusafc464f02011-11-04 21:54:00 +0530859 msm_hsusb_mhl_switch_enable(motg, 0);
860 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700861
Steve Mucklef132c6c2012-06-06 18:30:57 -0700862 if (device_may_wakeup(phy->dev)) {
Pavankumar Kondeti87c01042010-12-07 17:53:58 +0530863 enable_irq_wake(motg->irq);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700864 if (motg->pdata->pmic_id_irq)
865 enable_irq_wake(motg->pdata->pmic_id_irq);
866 }
Pavankumar Kondeti87c01042010-12-07 17:53:58 +0530867 if (bus)
868 clear_bit(HCD_FLAG_HW_ACCESSIBLE, &(bus_to_hcd(bus))->flags);
869
870 atomic_set(&motg->in_lpm, 1);
871 enable_irq(motg->irq);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700872 wake_unlock(&motg->wlock);
Pavankumar Kondeti87c01042010-12-07 17:53:58 +0530873
Heikki Krogerus1d4c9292012-02-13 13:24:09 +0200874 dev_info(phy->dev, "USB in low power mode\n");
Pavankumar Kondeti87c01042010-12-07 17:53:58 +0530875
876 return 0;
877}
878
Pavankumar Kondeti87c01042010-12-07 17:53:58 +0530879static int msm_otg_resume(struct msm_otg *motg)
880{
Heikki Krogerus1d4c9292012-02-13 13:24:09 +0200881 struct usb_phy *phy = &motg->phy;
882 struct usb_bus *bus = phy->otg->host;
Pavankumar Kondeti87c01042010-12-07 17:53:58 +0530883 int cnt = 0;
884 unsigned temp;
Amit Blay58b31472011-11-18 09:39:39 +0200885 u32 phy_ctrl_val = 0;
Anji jonnala7da3f262011-12-02 17:22:14 -0800886 unsigned ret;
Pavankumar Kondeti87c01042010-12-07 17:53:58 +0530887
888 if (!atomic_read(&motg->in_lpm))
889 return 0;
890
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700891 wake_lock(&motg->wlock);
Anji jonnala0f73cac2011-05-04 10:19:46 +0530892
Anji jonnala7da3f262011-12-02 17:22:14 -0800893 /* Vote for TCXO when waking up the phy */
Vijayavardhan Vennapusabbdd6082012-06-06 14:14:25 +0530894 if (motg->lpm_flags & XO_SHUTDOWN) {
895 ret = msm_xo_mode_vote(motg->xo_handle, MSM_XO_MODE_ON);
896 if (ret)
Steve Muckle75c34ca2012-06-12 14:27:40 -0700897 dev_err(phy->dev, "%s failed to vote for "
Vijayavardhan Vennapusabbdd6082012-06-06 14:14:25 +0530898 "TCXO D0 buffer%d\n", __func__, ret);
899 motg->lpm_flags &= ~XO_SHUTDOWN;
900 }
Pavankumar Kondeti87c01042010-12-07 17:53:58 +0530901
Amit Blay9b6e58b2012-06-18 13:12:49 +0300902 if (!motg->pdata->core_clk_always_on_workaround) {
903 clk_prepare_enable(motg->core_clk);
904 clk_prepare_enable(motg->pclk);
905 }
Pavankumar Kondeti87c01042010-12-07 17:53:58 +0530906
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700907 if (motg->lpm_flags & PHY_PWR_COLLAPSED) {
908 msm_hsusb_ldo_enable(motg, 1);
909 motg->lpm_flags &= ~PHY_PWR_COLLAPSED;
910 }
911
912 if (motg->lpm_flags & PHY_RETENTIONED) {
Vijayavardhan Vennapusafc464f02011-11-04 21:54:00 +0530913 msm_hsusb_mhl_switch_enable(motg, 1);
Pavankumar Kondeti04aebcb2011-05-04 10:19:49 +0530914 msm_hsusb_config_vddcx(1);
Amit Blay58b31472011-11-18 09:39:39 +0200915 phy_ctrl_val = readl_relaxed(USB_PHY_CTRL);
916 phy_ctrl_val |= PHY_RETEN;
917 if (motg->pdata->otg_control == OTG_PHY_CONTROL)
918 /* Disable PHY HV interrupts */
919 phy_ctrl_val &=
920 ~(PHY_IDHV_INTEN | PHY_OTGSESSVLDHV_INTEN);
921 writel_relaxed(phy_ctrl_val, USB_PHY_CTRL);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700922 motg->lpm_flags &= ~PHY_RETENTIONED;
Pavankumar Kondeti04aebcb2011-05-04 10:19:49 +0530923 }
924
Pavankumar Kondeti87c01042010-12-07 17:53:58 +0530925 temp = readl(USB_USBCMD);
926 temp &= ~ASYNC_INTR_CTRL;
927 temp &= ~ULPI_STP_CTRL;
928 writel(temp, USB_USBCMD);
929
930 /*
931 * PHY comes out of low power mode (LPM) in case of wakeup
932 * from asynchronous interrupt.
933 */
934 if (!(readl(USB_PORTSC) & PORTSC_PHCD))
935 goto skip_phy_resume;
936
937 writel(readl(USB_PORTSC) & ~PORTSC_PHCD, USB_PORTSC);
938 while (cnt < PHY_RESUME_TIMEOUT_USEC) {
939 if (!(readl(USB_PORTSC) & PORTSC_PHCD))
940 break;
941 udelay(1);
942 cnt++;
943 }
944
945 if (cnt >= PHY_RESUME_TIMEOUT_USEC) {
946 /*
947 * This is a fatal error. Reset the link and
948 * PHY. USB state can not be restored. Re-insertion
949 * of USB cable is the only way to get USB working.
950 */
Heikki Krogerus1d4c9292012-02-13 13:24:09 +0200951 dev_err(phy->dev, "Unable to resume USB."
Pavankumar Kondeti87c01042010-12-07 17:53:58 +0530952 "Re-plugin the cable\n");
Heikki Krogerus1d4c9292012-02-13 13:24:09 +0200953 msm_otg_reset(phy);
Pavankumar Kondeti87c01042010-12-07 17:53:58 +0530954 }
955
956skip_phy_resume:
Steve Mucklef132c6c2012-06-06 18:30:57 -0700957 if (device_may_wakeup(phy->dev)) {
Pavankumar Kondeti87c01042010-12-07 17:53:58 +0530958 disable_irq_wake(motg->irq);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700959 if (motg->pdata->pmic_id_irq)
960 disable_irq_wake(motg->pdata->pmic_id_irq);
961 }
Pavankumar Kondeti87c01042010-12-07 17:53:58 +0530962 if (bus)
963 set_bit(HCD_FLAG_HW_ACCESSIBLE, &(bus_to_hcd(bus))->flags);
964
Pavankumar Kondeti2ce2c3a2011-05-02 11:56:33 +0530965 atomic_set(&motg->in_lpm, 0);
966
Pavankumar Kondeti87c01042010-12-07 17:53:58 +0530967 if (motg->async_int) {
968 motg->async_int = 0;
Pavankumar Kondeti87c01042010-12-07 17:53:58 +0530969 enable_irq(motg->irq);
970 }
971
Heikki Krogerus1d4c9292012-02-13 13:24:09 +0200972 dev_info(phy->dev, "USB exited from low power mode\n");
Pavankumar Kondeti87c01042010-12-07 17:53:58 +0530973
974 return 0;
975}
Pavankumar Kondeti70187732011-02-15 09:42:34 +0530976#endif
Pavankumar Kondeti87c01042010-12-07 17:53:58 +0530977
Abhijeet Dharmapurikar5e96aaa2012-06-26 11:21:03 -0700978static int msm_otg_notify_host_mode(struct msm_otg *motg, bool host_mode)
979{
980 if (!psy)
981 goto psy_not_supported;
982
983 if (host_mode)
984 power_supply_set_scope(psy, POWER_SUPPLY_SCOPE_SYSTEM);
985 else
986 power_supply_set_scope(psy, POWER_SUPPLY_SCOPE_DEVICE);
987
988psy_not_supported:
989 dev_dbg(motg->phy.dev, "Power Supply doesn't support USB charger\n");
990 return -ENXIO;
991}
992
David Keitel081a3e22012-04-18 12:37:07 -0700993static int msm_otg_notify_chg_type(struct msm_otg *motg)
994{
995 static int charger_type;
996 /*
997 * TODO
998 * Unify OTG driver charger types and power supply charger types
999 */
1000 if (charger_type == motg->chg_type)
1001 return 0;
1002
1003 if (motg->chg_type == USB_SDP_CHARGER)
1004 charger_type = POWER_SUPPLY_TYPE_USB;
1005 else if (motg->chg_type == USB_CDP_CHARGER)
1006 charger_type = POWER_SUPPLY_TYPE_USB_CDP;
Pavankumar Kondeti9ec21d32012-05-07 15:50:23 +05301007 else if (motg->chg_type == USB_DCP_CHARGER ||
1008 motg->chg_type == USB_PROPRIETARY_CHARGER)
David Keitel081a3e22012-04-18 12:37:07 -07001009 charger_type = POWER_SUPPLY_TYPE_USB_DCP;
1010 else if ((motg->chg_type == USB_ACA_DOCK_CHARGER ||
1011 motg->chg_type == USB_ACA_A_CHARGER ||
1012 motg->chg_type == USB_ACA_B_CHARGER ||
1013 motg->chg_type == USB_ACA_C_CHARGER))
1014 charger_type = POWER_SUPPLY_TYPE_USB_ACA;
1015 else
1016 charger_type = POWER_SUPPLY_TYPE_BATTERY;
1017
1018 return pm8921_set_usb_power_supply_type(charger_type);
1019}
1020
Amit Blay0f7edf72012-01-15 10:11:27 +02001021static int msm_otg_notify_power_supply(struct msm_otg *motg, unsigned mA)
1022{
Amit Blay0f7edf72012-01-15 10:11:27 +02001023
Amit Blay0f7edf72012-01-15 10:11:27 +02001024 if (!psy)
1025 goto psy_not_supported;
1026
1027 if (motg->cur_power == 0 && mA > 0) {
1028 /* Enable charging */
1029 if (power_supply_set_online(psy, true))
1030 goto psy_not_supported;
1031 } else if (motg->cur_power > 0 && mA == 0) {
1032 /* Disable charging */
1033 if (power_supply_set_online(psy, false))
1034 goto psy_not_supported;
1035 return 0;
1036 }
1037 /* Set max current limit */
1038 if (power_supply_set_current_limit(psy, 1000*mA))
1039 goto psy_not_supported;
1040
1041 return 0;
1042
1043psy_not_supported:
Steve Mucklef132c6c2012-06-06 18:30:57 -07001044 dev_dbg(motg->phy.dev, "Power Supply doesn't support USB charger\n");
Amit Blay0f7edf72012-01-15 10:11:27 +02001045 return -ENXIO;
1046}
1047
Pavankumar Kondetid8608522011-05-04 10:19:47 +05301048static void msm_otg_notify_charger(struct msm_otg *motg, unsigned mA)
1049{
Steve Mucklef132c6c2012-06-06 18:30:57 -07001050 struct usb_gadget *g = motg->phy.otg->gadget;
Vijayavardhan Vennapusaa3152032012-03-05 16:29:30 +05301051
1052 if (g && g->is_a_peripheral)
1053 return;
1054
Pavankumar Kondetiaa449e12011-11-04 11:09:26 +05301055 if ((motg->chg_type == USB_ACA_DOCK_CHARGER ||
1056 motg->chg_type == USB_ACA_A_CHARGER ||
1057 motg->chg_type == USB_ACA_B_CHARGER ||
1058 motg->chg_type == USB_ACA_C_CHARGER) &&
1059 mA > IDEV_ACA_CHG_LIMIT)
1060 mA = IDEV_ACA_CHG_LIMIT;
1061
David Keitel081a3e22012-04-18 12:37:07 -07001062 if (msm_otg_notify_chg_type(motg))
Steve Mucklef132c6c2012-06-06 18:30:57 -07001063 dev_err(motg->phy.dev,
David Keitel081a3e22012-04-18 12:37:07 -07001064 "Failed notifying %d charger type to PMIC\n",
1065 motg->chg_type);
1066
Pavankumar Kondetid8608522011-05-04 10:19:47 +05301067 if (motg->cur_power == mA)
1068 return;
1069
Heikki Krogerus1d4c9292012-02-13 13:24:09 +02001070 dev_info(motg->phy.dev, "Avail curr from USB = %u\n", mA);
Amit Blay0f7edf72012-01-15 10:11:27 +02001071
1072 /*
1073 * Use Power Supply API if supported, otherwise fallback
1074 * to legacy pm8921 API.
1075 */
1076 if (msm_otg_notify_power_supply(motg, mA))
1077 pm8921_charger_vbus_draw(mA);
1078
Pavankumar Kondetid8608522011-05-04 10:19:47 +05301079 motg->cur_power = mA;
1080}
1081
Heikki Krogerus1d4c9292012-02-13 13:24:09 +02001082static int msm_otg_set_power(struct usb_phy *phy, unsigned mA)
Pavankumar Kondetid8608522011-05-04 10:19:47 +05301083{
Heikki Krogerus1d4c9292012-02-13 13:24:09 +02001084 struct msm_otg *motg = container_of(phy, struct msm_otg, phy);
Pavankumar Kondetid8608522011-05-04 10:19:47 +05301085
1086 /*
1087 * Gadget driver uses set_power method to notify about the
1088 * available current based on suspend/configured states.
1089 *
1090 * IDEV_CHG can be drawn irrespective of suspend/un-configured
1091 * states when CDP/ACA is connected.
1092 */
1093 if (motg->chg_type == USB_SDP_CHARGER)
1094 msm_otg_notify_charger(motg, mA);
1095
1096 return 0;
1097}
1098
Steve Mucklef132c6c2012-06-06 18:30:57 -07001099static void msm_otg_start_host(struct usb_otg *otg, int on)
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05301100{
Steve Mucklef132c6c2012-06-06 18:30:57 -07001101 struct msm_otg *motg = container_of(otg->phy, struct msm_otg, phy);
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05301102 struct msm_otg_platform_data *pdata = motg->pdata;
1103 struct usb_hcd *hcd;
1104
1105 if (!otg->host)
1106 return;
1107
1108 hcd = bus_to_hcd(otg->host);
1109
1110 if (on) {
Steve Mucklef132c6c2012-06-06 18:30:57 -07001111 dev_dbg(otg->phy->dev, "host on\n");
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05301112
Vijayavardhan Vennapusa03171c72012-04-26 14:44:48 +05301113 if (pdata->otg_control == OTG_PHY_CONTROL)
Steve Mucklef132c6c2012-06-06 18:30:57 -07001114 ulpi_write(otg->phy, OTG_COMP_DISABLE,
Vijayavardhan Vennapusa03171c72012-04-26 14:44:48 +05301115 ULPI_SET(ULPI_PWR_CLK_MNG_REG));
1116
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05301117 /*
1118 * Some boards have a switch cotrolled by gpio
1119 * to enable/disable internal HUB. Enable internal
1120 * HUB before kicking the host.
1121 */
1122 if (pdata->setup_gpio)
1123 pdata->setup_gpio(OTG_STATE_A_HOST);
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05301124 usb_add_hcd(hcd, hcd->irq, IRQF_SHARED);
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05301125 } else {
Steve Mucklef132c6c2012-06-06 18:30:57 -07001126 dev_dbg(otg->phy->dev, "host off\n");
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05301127
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05301128 usb_remove_hcd(hcd);
Pavankumar Kondetiaa449e12011-11-04 11:09:26 +05301129 /* HCD core reset all bits of PORTSC. select ULPI phy */
1130 writel_relaxed(0x80000000, USB_PORTSC);
1131
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05301132 if (pdata->setup_gpio)
1133 pdata->setup_gpio(OTG_STATE_UNDEFINED);
Vijayavardhan Vennapusa03171c72012-04-26 14:44:48 +05301134
1135 if (pdata->otg_control == OTG_PHY_CONTROL)
Steve Mucklef132c6c2012-06-06 18:30:57 -07001136 ulpi_write(otg->phy, OTG_COMP_DISABLE,
Vijayavardhan Vennapusa03171c72012-04-26 14:44:48 +05301137 ULPI_CLR(ULPI_PWR_CLK_MNG_REG));
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05301138 }
1139}
1140
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001141static int msm_otg_usbdev_notify(struct notifier_block *self,
1142 unsigned long action, void *priv)
1143{
1144 struct msm_otg *motg = container_of(self, struct msm_otg, usbdev_nb);
Steve Mucklef132c6c2012-06-06 18:30:57 -07001145 struct usb_otg *otg = motg->phy.otg;
Pavankumar Kondetiaa449e12011-11-04 11:09:26 +05301146 struct usb_device *udev = priv;
1147
Pavankumar Kondetiaa449e12011-11-04 11:09:26 +05301148 if (action == USB_BUS_ADD || action == USB_BUS_REMOVE)
1149 goto out;
1150
Steve Mucklef132c6c2012-06-06 18:30:57 -07001151 if (udev->bus != otg->host)
Pavankumar Kondetiaa449e12011-11-04 11:09:26 +05301152 goto out;
1153 /*
1154 * Interested in devices connected directly to the root hub.
1155 * ACA dock can supply IDEV_CHG irrespective devices connected
1156 * on the accessory port.
1157 */
1158 if (!udev->parent || udev->parent->parent ||
1159 motg->chg_type == USB_ACA_DOCK_CHARGER)
1160 goto out;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001161
1162 switch (action) {
1163 case USB_DEVICE_ADD:
Vijayavardhan Vennapusaa3152032012-03-05 16:29:30 +05301164 if (aca_enabled())
1165 usb_disable_autosuspend(udev);
Steve Mucklef132c6c2012-06-06 18:30:57 -07001166 if (otg->phy->state == OTG_STATE_A_WAIT_BCON) {
Vijayavardhan Vennapusaa3152032012-03-05 16:29:30 +05301167 pr_debug("B_CONN set\n");
1168 set_bit(B_CONN, &motg->inputs);
1169 msm_otg_del_timer(motg);
Steve Mucklef132c6c2012-06-06 18:30:57 -07001170 otg->phy->state = OTG_STATE_A_HOST;
Vijayavardhan Vennapusaa3152032012-03-05 16:29:30 +05301171 /*
1172 * OTG PET: A-device must end session within
1173 * 10 sec after PET enumeration.
1174 */
1175 if (udev->quirks & USB_QUIRK_OTG_PET)
1176 msm_otg_start_timer(motg, TA_TST_MAINT,
1177 A_TST_MAINT);
1178 }
Pavankumar Kondetiaa449e12011-11-04 11:09:26 +05301179 /* fall through */
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001180 case USB_DEVICE_CONFIG:
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001181 if (udev->actconfig)
1182 motg->mA_port = udev->actconfig->desc.bMaxPower * 2;
1183 else
1184 motg->mA_port = IUNIT;
Steve Mucklef132c6c2012-06-06 18:30:57 -07001185 if (otg->phy->state == OTG_STATE_B_HOST)
Vijayavardhan Vennapusaa3152032012-03-05 16:29:30 +05301186 msm_otg_del_timer(motg);
Pavankumar Kondetiaa449e12011-11-04 11:09:26 +05301187 break;
1188 case USB_DEVICE_REMOVE:
Steve Mucklef132c6c2012-06-06 18:30:57 -07001189 if ((otg->phy->state == OTG_STATE_A_HOST) ||
1190 (otg->phy->state == OTG_STATE_A_SUSPEND)) {
Vijayavardhan Vennapusaa3152032012-03-05 16:29:30 +05301191 pr_debug("B_CONN clear\n");
1192 clear_bit(B_CONN, &motg->inputs);
1193 /*
1194 * OTG PET: A-device must end session after
1195 * PET disconnection if it is enumerated
1196 * with bcdDevice[0] = 1. USB core sets
1197 * bus->otg_vbus_off for us. clear it here.
1198 */
1199 if (udev->bus->otg_vbus_off) {
1200 udev->bus->otg_vbus_off = 0;
1201 set_bit(A_BUS_DROP, &motg->inputs);
1202 }
1203 queue_work(system_nrt_wq, &motg->sm_work);
1204 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001205 default:
1206 break;
1207 }
Pavankumar Kondetiaa449e12011-11-04 11:09:26 +05301208 if (test_bit(ID_A, &motg->inputs))
1209 msm_otg_notify_charger(motg, IDEV_ACA_CHG_MAX -
1210 motg->mA_port);
1211out:
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001212 return NOTIFY_OK;
1213}
1214
Mayank Ranae3926882011-12-26 09:47:54 +05301215static void msm_hsusb_vbus_power(struct msm_otg *motg, bool on)
1216{
1217 int ret;
1218 static bool vbus_is_on;
1219
1220 if (vbus_is_on == on)
1221 return;
1222
1223 if (motg->pdata->vbus_power) {
Mayank Rana91f597e2012-01-20 10:12:06 +05301224 ret = motg->pdata->vbus_power(on);
1225 if (!ret)
1226 vbus_is_on = on;
Mayank Ranae3926882011-12-26 09:47:54 +05301227 return;
1228 }
1229
1230 if (!vbus_otg) {
1231 pr_err("vbus_otg is NULL.");
1232 return;
1233 }
1234
Abhijeet Dharmapurikarbe054882012-01-03 20:27:07 -08001235 /*
1236 * if entering host mode tell the charger to not draw any current
Abhijeet Dharmapurikar6d941212012-03-05 10:30:56 -08001237 * from usb before turning on the boost.
1238 * if exiting host mode disable the boost before enabling to draw
1239 * current from the source.
Abhijeet Dharmapurikarbe054882012-01-03 20:27:07 -08001240 */
Mayank Ranae3926882011-12-26 09:47:54 +05301241 if (on) {
Abhijeet Dharmapurikar5e96aaa2012-06-26 11:21:03 -07001242 msm_otg_notify_host_mode(motg, on);
Mayank Ranae3926882011-12-26 09:47:54 +05301243 ret = regulator_enable(vbus_otg);
1244 if (ret) {
1245 pr_err("unable to enable vbus_otg\n");
1246 return;
1247 }
1248 vbus_is_on = true;
1249 } else {
1250 ret = regulator_disable(vbus_otg);
1251 if (ret) {
1252 pr_err("unable to disable vbus_otg\n");
1253 return;
1254 }
Abhijeet Dharmapurikar5e96aaa2012-06-26 11:21:03 -07001255 msm_otg_notify_host_mode(motg, on);
Mayank Ranae3926882011-12-26 09:47:54 +05301256 vbus_is_on = false;
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05301257 }
1258}
1259
Heikki Krogerus1d4c9292012-02-13 13:24:09 +02001260static int msm_otg_set_host(struct usb_otg *otg, struct usb_bus *host)
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05301261{
Heikki Krogerus1d4c9292012-02-13 13:24:09 +02001262 struct msm_otg *motg = container_of(otg->phy, struct msm_otg, phy);
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05301263 struct usb_hcd *hcd;
1264
1265 /*
1266 * Fail host registration if this board can support
1267 * only peripheral configuration.
1268 */
1269 if (motg->pdata->mode == USB_PERIPHERAL) {
Heikki Krogerus1d4c9292012-02-13 13:24:09 +02001270 dev_info(otg->phy->dev, "Host mode is not supported\n");
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05301271 return -ENODEV;
1272 }
1273
Mayank Ranae3926882011-12-26 09:47:54 +05301274 if (!motg->pdata->vbus_power && host) {
Steve Mucklef132c6c2012-06-06 18:30:57 -07001275 vbus_otg = devm_regulator_get(motg->phy.dev, "vbus_otg");
Mayank Ranae3926882011-12-26 09:47:54 +05301276 if (IS_ERR(vbus_otg)) {
1277 pr_err("Unable to get vbus_otg\n");
1278 return -ENODEV;
1279 }
1280 }
1281
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05301282 if (!host) {
Heikki Krogerus1d4c9292012-02-13 13:24:09 +02001283 if (otg->phy->state == OTG_STATE_A_HOST) {
1284 pm_runtime_get_sync(otg->phy->dev);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001285 usb_unregister_notify(&motg->usbdev_nb);
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05301286 msm_otg_start_host(otg, 0);
Mayank Ranae3926882011-12-26 09:47:54 +05301287 msm_hsusb_vbus_power(motg, 0);
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05301288 otg->host = NULL;
Heikki Krogerus1d4c9292012-02-13 13:24:09 +02001289 otg->phy->state = OTG_STATE_UNDEFINED;
Vijayavardhan Vennapusaa3152032012-03-05 16:29:30 +05301290 queue_work(system_nrt_wq, &motg->sm_work);
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05301291 } else {
1292 otg->host = NULL;
1293 }
1294
1295 return 0;
1296 }
1297
1298 hcd = bus_to_hcd(host);
1299 hcd->power_budget = motg->pdata->power_budget;
1300
Vijayavardhan Vennapusaa3152032012-03-05 16:29:30 +05301301#ifdef CONFIG_USB_OTG
1302 host->otg_port = 1;
1303#endif
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001304 motg->usbdev_nb.notifier_call = msm_otg_usbdev_notify;
1305 usb_register_notify(&motg->usbdev_nb);
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05301306 otg->host = host;
Heikki Krogerus1d4c9292012-02-13 13:24:09 +02001307 dev_dbg(otg->phy->dev, "host driver registered w/ tranceiver\n");
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05301308
1309 /*
1310 * Kick the state machine work, if peripheral is not supported
1311 * or peripheral is already registered with us.
1312 */
Pavankumar Kondeti87c01042010-12-07 17:53:58 +05301313 if (motg->pdata->mode == USB_HOST || otg->gadget) {
Heikki Krogerus1d4c9292012-02-13 13:24:09 +02001314 pm_runtime_get_sync(otg->phy->dev);
Vijayavardhan Vennapusaa3152032012-03-05 16:29:30 +05301315 queue_work(system_nrt_wq, &motg->sm_work);
Pavankumar Kondeti87c01042010-12-07 17:53:58 +05301316 }
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05301317
1318 return 0;
1319}
1320
Steve Mucklef132c6c2012-06-06 18:30:57 -07001321static void msm_otg_start_peripheral(struct usb_otg *otg, int on)
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05301322{
Manu Gautamcd82e9d2011-12-20 14:17:28 +05301323 int ret;
Steve Mucklef132c6c2012-06-06 18:30:57 -07001324 struct msm_otg *motg = container_of(otg->phy, struct msm_otg, phy);
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05301325 struct msm_otg_platform_data *pdata = motg->pdata;
1326
1327 if (!otg->gadget)
1328 return;
1329
1330 if (on) {
Steve Mucklef132c6c2012-06-06 18:30:57 -07001331 dev_dbg(otg->phy->dev, "gadget on\n");
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05301332 /*
1333 * Some boards have a switch cotrolled by gpio
1334 * to enable/disable internal HUB. Disable internal
1335 * HUB before kicking the gadget.
1336 */
1337 if (pdata->setup_gpio)
1338 pdata->setup_gpio(OTG_STATE_B_PERIPHERAL);
Ofir Cohen94213a72012-05-03 14:26:32 +03001339
Manu Gautamcd82e9d2011-12-20 14:17:28 +05301340 /* Configure BUS performance parameters for MAX bandwidth */
Manu Gautam8bdcc592012-03-06 11:26:06 +05301341 if (motg->bus_perf_client && debug_bus_voting_enabled) {
Manu Gautamcd82e9d2011-12-20 14:17:28 +05301342 ret = msm_bus_scale_client_update_request(
1343 motg->bus_perf_client, 1);
1344 if (ret)
Steve Mucklef132c6c2012-06-06 18:30:57 -07001345 dev_err(motg->phy.dev, "%s: Failed to vote for "
Manu Gautamcd82e9d2011-12-20 14:17:28 +05301346 "bus bandwidth %d\n", __func__, ret);
1347 }
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05301348 usb_gadget_vbus_connect(otg->gadget);
1349 } else {
Steve Mucklef132c6c2012-06-06 18:30:57 -07001350 dev_dbg(otg->phy->dev, "gadget off\n");
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05301351 usb_gadget_vbus_disconnect(otg->gadget);
Manu Gautamcd82e9d2011-12-20 14:17:28 +05301352 /* Configure BUS performance parameters to default */
1353 if (motg->bus_perf_client) {
1354 ret = msm_bus_scale_client_update_request(
1355 motg->bus_perf_client, 0);
1356 if (ret)
Steve Mucklef132c6c2012-06-06 18:30:57 -07001357 dev_err(motg->phy.dev, "%s: Failed to devote "
Manu Gautamcd82e9d2011-12-20 14:17:28 +05301358 "for bus bw %d\n", __func__, ret);
1359 }
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05301360 if (pdata->setup_gpio)
1361 pdata->setup_gpio(OTG_STATE_UNDEFINED);
1362 }
1363
1364}
1365
Heikki Krogerus1d4c9292012-02-13 13:24:09 +02001366static int msm_otg_set_peripheral(struct usb_otg *otg,
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05301367 struct usb_gadget *gadget)
1368{
Heikki Krogerus1d4c9292012-02-13 13:24:09 +02001369 struct msm_otg *motg = container_of(otg->phy, struct msm_otg, phy);
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05301370
1371 /*
1372 * Fail peripheral registration if this board can support
1373 * only host configuration.
1374 */
1375 if (motg->pdata->mode == USB_HOST) {
Heikki Krogerus1d4c9292012-02-13 13:24:09 +02001376 dev_info(otg->phy->dev, "Peripheral mode is not supported\n");
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05301377 return -ENODEV;
1378 }
1379
1380 if (!gadget) {
Heikki Krogerus1d4c9292012-02-13 13:24:09 +02001381 if (otg->phy->state == OTG_STATE_B_PERIPHERAL) {
1382 pm_runtime_get_sync(otg->phy->dev);
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05301383 msm_otg_start_peripheral(otg, 0);
1384 otg->gadget = NULL;
Heikki Krogerus1d4c9292012-02-13 13:24:09 +02001385 otg->phy->state = OTG_STATE_UNDEFINED;
Vijayavardhan Vennapusaa3152032012-03-05 16:29:30 +05301386 queue_work(system_nrt_wq, &motg->sm_work);
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05301387 } else {
1388 otg->gadget = NULL;
1389 }
1390
1391 return 0;
1392 }
1393 otg->gadget = gadget;
Heikki Krogerus1d4c9292012-02-13 13:24:09 +02001394 dev_dbg(otg->phy->dev, "peripheral driver registered w/ tranceiver\n");
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05301395
1396 /*
1397 * Kick the state machine work, if host is not supported
1398 * or host is already registered with us.
1399 */
Pavankumar Kondeti87c01042010-12-07 17:53:58 +05301400 if (motg->pdata->mode == USB_PERIPHERAL || otg->host) {
Heikki Krogerus1d4c9292012-02-13 13:24:09 +02001401 pm_runtime_get_sync(otg->phy->dev);
Vijayavardhan Vennapusaa3152032012-03-05 16:29:30 +05301402 queue_work(system_nrt_wq, &motg->sm_work);
Pavankumar Kondeti87c01042010-12-07 17:53:58 +05301403 }
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05301404
1405 return 0;
1406}
1407
Pavankumar Kondeti2aec9f32012-06-13 09:06:03 +05301408static int msm_otg_mhl_register_callback(struct msm_otg *motg,
1409 void (*callback)(int on))
1410{
1411 struct usb_phy *phy = &motg->phy;
1412 int ret;
1413
1414 if (motg->pdata->otg_control != OTG_PMIC_CONTROL ||
1415 !motg->pdata->pmic_id_irq) {
1416 dev_dbg(phy->dev, "MHL can not be supported without PMIC Id\n");
1417 return -ENODEV;
1418 }
1419
1420 if (!motg->pdata->mhl_dev_name) {
1421 dev_dbg(phy->dev, "MHL device name does not exist.\n");
1422 return -ENODEV;
1423 }
1424
1425 if (callback)
1426 ret = mhl_register_callback(motg->pdata->mhl_dev_name,
1427 callback);
1428 else
1429 ret = mhl_unregister_callback(motg->pdata->mhl_dev_name);
1430
1431 if (ret)
1432 dev_dbg(phy->dev, "mhl_register_callback(%s) return error=%d\n",
1433 motg->pdata->mhl_dev_name, ret);
1434 else
1435 motg->mhl_enabled = true;
1436
1437 return ret;
1438}
1439
1440static void msm_otg_mhl_notify_online(int on)
1441{
1442 struct msm_otg *motg = the_msm_otg;
1443 struct usb_phy *phy = &motg->phy;
1444 bool queue = false;
1445
1446 dev_dbg(phy->dev, "notify MHL %s%s\n", on ? "" : "dis", "connected");
1447
1448 if (on) {
1449 set_bit(MHL, &motg->inputs);
1450 } else {
1451 clear_bit(MHL, &motg->inputs);
1452 queue = true;
1453 }
1454
1455 if (queue && phy->state != OTG_STATE_UNDEFINED)
1456 schedule_work(&motg->sm_work);
1457}
1458
1459static bool msm_otg_is_mhl(struct msm_otg *motg)
1460{
1461 struct usb_phy *phy = &motg->phy;
1462 int is_mhl, ret;
1463
1464 ret = mhl_device_discovery(motg->pdata->mhl_dev_name, &is_mhl);
1465 if (ret || is_mhl != MHL_DISCOVERY_RESULT_MHL) {
1466 /*
1467 * MHL driver calls our callback saying that MHL connected
1468 * if RID_GND is detected. But at later part of discovery
1469 * it may figure out MHL is not connected and returns
1470 * false. Hence clear MHL input here.
1471 */
1472 clear_bit(MHL, &motg->inputs);
1473 dev_dbg(phy->dev, "MHL device not found\n");
1474 return false;
1475 }
1476
1477 set_bit(MHL, &motg->inputs);
1478 dev_dbg(phy->dev, "MHL device found\n");
1479 return true;
1480}
1481
1482static bool msm_chg_mhl_detect(struct msm_otg *motg)
1483{
1484 bool ret, id;
1485 unsigned long flags;
1486
1487 if (!motg->mhl_enabled)
1488 return false;
1489
1490 local_irq_save(flags);
1491 id = irq_read_line(motg->pdata->pmic_id_irq);
1492 local_irq_restore(flags);
1493
1494 if (id)
1495 return false;
1496
1497 mhl_det_in_progress = true;
1498 ret = msm_otg_is_mhl(motg);
1499 mhl_det_in_progress = false;
1500
1501 return ret;
1502}
1503
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001504static bool msm_chg_aca_detect(struct msm_otg *motg)
1505{
Steve Mucklef132c6c2012-06-06 18:30:57 -07001506 struct usb_phy *phy = &motg->phy;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001507 u32 int_sts;
1508 bool ret = false;
1509
Pavankumar Kondetiaa449e12011-11-04 11:09:26 +05301510 if (!aca_enabled())
1511 goto out;
1512
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001513 if (motg->pdata->phy_type == CI_45NM_INTEGRATED_PHY)
1514 goto out;
1515
Steve Mucklef132c6c2012-06-06 18:30:57 -07001516 int_sts = ulpi_read(phy, 0x87);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001517 switch (int_sts & 0x1C) {
1518 case 0x08:
1519 if (!test_and_set_bit(ID_A, &motg->inputs)) {
Steve Mucklef132c6c2012-06-06 18:30:57 -07001520 dev_dbg(phy->dev, "ID_A\n");
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001521 motg->chg_type = USB_ACA_A_CHARGER;
1522 motg->chg_state = USB_CHG_STATE_DETECTED;
1523 clear_bit(ID_B, &motg->inputs);
1524 clear_bit(ID_C, &motg->inputs);
Pavankumar Kondetiaa449e12011-11-04 11:09:26 +05301525 set_bit(ID, &motg->inputs);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001526 ret = true;
1527 }
1528 break;
1529 case 0x0C:
1530 if (!test_and_set_bit(ID_B, &motg->inputs)) {
Steve Mucklef132c6c2012-06-06 18:30:57 -07001531 dev_dbg(phy->dev, "ID_B\n");
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001532 motg->chg_type = USB_ACA_B_CHARGER;
1533 motg->chg_state = USB_CHG_STATE_DETECTED;
1534 clear_bit(ID_A, &motg->inputs);
1535 clear_bit(ID_C, &motg->inputs);
Pavankumar Kondetiaa449e12011-11-04 11:09:26 +05301536 set_bit(ID, &motg->inputs);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001537 ret = true;
1538 }
1539 break;
1540 case 0x10:
1541 if (!test_and_set_bit(ID_C, &motg->inputs)) {
Steve Mucklef132c6c2012-06-06 18:30:57 -07001542 dev_dbg(phy->dev, "ID_C\n");
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001543 motg->chg_type = USB_ACA_C_CHARGER;
1544 motg->chg_state = USB_CHG_STATE_DETECTED;
1545 clear_bit(ID_A, &motg->inputs);
1546 clear_bit(ID_B, &motg->inputs);
Pavankumar Kondetiaa449e12011-11-04 11:09:26 +05301547 set_bit(ID, &motg->inputs);
1548 ret = true;
1549 }
1550 break;
1551 case 0x04:
1552 if (test_and_clear_bit(ID, &motg->inputs)) {
Steve Mucklef132c6c2012-06-06 18:30:57 -07001553 dev_dbg(phy->dev, "ID_GND\n");
Pavankumar Kondetiaa449e12011-11-04 11:09:26 +05301554 motg->chg_type = USB_INVALID_CHARGER;
1555 motg->chg_state = USB_CHG_STATE_UNDEFINED;
1556 clear_bit(ID_A, &motg->inputs);
1557 clear_bit(ID_B, &motg->inputs);
1558 clear_bit(ID_C, &motg->inputs);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001559 ret = true;
1560 }
1561 break;
1562 default:
1563 ret = test_and_clear_bit(ID_A, &motg->inputs) |
1564 test_and_clear_bit(ID_B, &motg->inputs) |
Pavankumar Kondetiaa449e12011-11-04 11:09:26 +05301565 test_and_clear_bit(ID_C, &motg->inputs) |
1566 !test_and_set_bit(ID, &motg->inputs);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001567 if (ret) {
Steve Mucklef132c6c2012-06-06 18:30:57 -07001568 dev_dbg(phy->dev, "ID A/B/C/GND is no more\n");
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001569 motg->chg_type = USB_INVALID_CHARGER;
1570 motg->chg_state = USB_CHG_STATE_UNDEFINED;
1571 }
1572 }
1573out:
1574 return ret;
1575}
1576
1577static void msm_chg_enable_aca_det(struct msm_otg *motg)
1578{
Steve Mucklef132c6c2012-06-06 18:30:57 -07001579 struct usb_phy *phy = &motg->phy;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001580
Pavankumar Kondetiaa449e12011-11-04 11:09:26 +05301581 if (!aca_enabled())
1582 return;
1583
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001584 switch (motg->pdata->phy_type) {
1585 case SNPS_28NM_INTEGRATED_PHY:
Pavankumar Kondetiaa449e12011-11-04 11:09:26 +05301586 /* Disable ID_GND in link and PHY */
1587 writel_relaxed(readl_relaxed(USB_OTGSC) & ~(OTGSC_IDPU |
1588 OTGSC_IDIE), USB_OTGSC);
Steve Mucklef132c6c2012-06-06 18:30:57 -07001589 ulpi_write(phy, 0x01, 0x0C);
1590 ulpi_write(phy, 0x10, 0x0F);
1591 ulpi_write(phy, 0x10, 0x12);
Pavankumar Kondeti446f4542012-02-01 13:57:13 +05301592 /* Disable PMIC ID pull-up */
1593 pm8xxx_usb_id_pullup(0);
Pavankumar Kondetiaa449e12011-11-04 11:09:26 +05301594 /* Enable ACA ID detection */
Steve Mucklef132c6c2012-06-06 18:30:57 -07001595 ulpi_write(phy, 0x20, 0x85);
Pavankumar Kondeti4960f312011-12-06 15:46:14 +05301596 aca_id_turned_on = true;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001597 break;
1598 default:
1599 break;
1600 }
1601}
1602
1603static void msm_chg_enable_aca_intr(struct msm_otg *motg)
1604{
Steve Mucklef132c6c2012-06-06 18:30:57 -07001605 struct usb_phy *phy = &motg->phy;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001606
Pavankumar Kondetiaa449e12011-11-04 11:09:26 +05301607 if (!aca_enabled())
1608 return;
1609
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001610 switch (motg->pdata->phy_type) {
1611 case SNPS_28NM_INTEGRATED_PHY:
Pavankumar Kondetiaa449e12011-11-04 11:09:26 +05301612 /* Enable ACA Detection interrupt (on any RID change) */
Steve Mucklef132c6c2012-06-06 18:30:57 -07001613 ulpi_write(phy, 0x01, 0x94);
Pavankumar Kondetiaa449e12011-11-04 11:09:26 +05301614 break;
1615 default:
1616 break;
1617 }
1618}
1619
1620static void msm_chg_disable_aca_intr(struct msm_otg *motg)
1621{
Steve Mucklef132c6c2012-06-06 18:30:57 -07001622 struct usb_phy *phy = &motg->phy;
Pavankumar Kondetiaa449e12011-11-04 11:09:26 +05301623
1624 if (!aca_enabled())
1625 return;
1626
1627 switch (motg->pdata->phy_type) {
1628 case SNPS_28NM_INTEGRATED_PHY:
Steve Mucklef132c6c2012-06-06 18:30:57 -07001629 ulpi_write(phy, 0x01, 0x95);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001630 break;
1631 default:
1632 break;
1633 }
1634}
1635
1636static bool msm_chg_check_aca_intr(struct msm_otg *motg)
1637{
Steve Mucklef132c6c2012-06-06 18:30:57 -07001638 struct usb_phy *phy = &motg->phy;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001639 bool ret = false;
1640
Pavankumar Kondetiaa449e12011-11-04 11:09:26 +05301641 if (!aca_enabled())
1642 return ret;
1643
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001644 switch (motg->pdata->phy_type) {
1645 case SNPS_28NM_INTEGRATED_PHY:
Steve Mucklef132c6c2012-06-06 18:30:57 -07001646 if (ulpi_read(phy, 0x91) & 1) {
1647 dev_dbg(phy->dev, "RID change\n");
1648 ulpi_write(phy, 0x01, 0x92);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001649 ret = msm_chg_aca_detect(motg);
1650 }
1651 default:
1652 break;
1653 }
1654 return ret;
1655}
Pavankumar Kondetiaa449e12011-11-04 11:09:26 +05301656
1657static void msm_otg_id_timer_func(unsigned long data)
1658{
1659 struct msm_otg *motg = (struct msm_otg *) data;
1660
1661 if (!aca_enabled())
1662 return;
1663
1664 if (atomic_read(&motg->in_lpm)) {
Steve Mucklef132c6c2012-06-06 18:30:57 -07001665 dev_dbg(motg->phy.dev, "timer: in lpm\n");
Pavankumar Kondetiaa449e12011-11-04 11:09:26 +05301666 return;
1667 }
1668
Steve Mucklef132c6c2012-06-06 18:30:57 -07001669 if (motg->phy.state == OTG_STATE_A_SUSPEND)
Vijayavardhan Vennapusaa3152032012-03-05 16:29:30 +05301670 goto out;
1671
Pavankumar Kondetiaa449e12011-11-04 11:09:26 +05301672 if (msm_chg_check_aca_intr(motg)) {
Steve Mucklef132c6c2012-06-06 18:30:57 -07001673 dev_dbg(motg->phy.dev, "timer: aca work\n");
Vijayavardhan Vennapusaa3152032012-03-05 16:29:30 +05301674 queue_work(system_nrt_wq, &motg->sm_work);
Pavankumar Kondetiaa449e12011-11-04 11:09:26 +05301675 }
1676
Vijayavardhan Vennapusaa3152032012-03-05 16:29:30 +05301677out:
Pavankumar Kondetiaa449e12011-11-04 11:09:26 +05301678 if (!test_bit(ID, &motg->inputs) || test_bit(ID_A, &motg->inputs))
1679 mod_timer(&motg->id_timer, ID_TIMER_FREQ);
1680}
1681
Pavankumar Kondetid8608522011-05-04 10:19:47 +05301682static bool msm_chg_check_secondary_det(struct msm_otg *motg)
1683{
Heikki Krogerus1d4c9292012-02-13 13:24:09 +02001684 struct usb_phy *phy = &motg->phy;
Pavankumar Kondetid8608522011-05-04 10:19:47 +05301685 u32 chg_det;
1686 bool ret = false;
1687
1688 switch (motg->pdata->phy_type) {
1689 case CI_45NM_INTEGRATED_PHY:
Heikki Krogerus1d4c9292012-02-13 13:24:09 +02001690 chg_det = ulpi_read(phy, 0x34);
Pavankumar Kondetid8608522011-05-04 10:19:47 +05301691 ret = chg_det & (1 << 4);
1692 break;
1693 case SNPS_28NM_INTEGRATED_PHY:
Heikki Krogerus1d4c9292012-02-13 13:24:09 +02001694 chg_det = ulpi_read(phy, 0x87);
Pavankumar Kondetid8608522011-05-04 10:19:47 +05301695 ret = chg_det & 1;
1696 break;
1697 default:
1698 break;
1699 }
1700 return ret;
1701}
1702
1703static void msm_chg_enable_secondary_det(struct msm_otg *motg)
1704{
Heikki Krogerus1d4c9292012-02-13 13:24:09 +02001705 struct usb_phy *phy = &motg->phy;
Pavankumar Kondetid8608522011-05-04 10:19:47 +05301706 u32 chg_det;
1707
1708 switch (motg->pdata->phy_type) {
1709 case CI_45NM_INTEGRATED_PHY:
Heikki Krogerus1d4c9292012-02-13 13:24:09 +02001710 chg_det = ulpi_read(phy, 0x34);
Pavankumar Kondetid8608522011-05-04 10:19:47 +05301711 /* Turn off charger block */
1712 chg_det |= ~(1 << 1);
Heikki Krogerus1d4c9292012-02-13 13:24:09 +02001713 ulpi_write(phy, chg_det, 0x34);
Pavankumar Kondetid8608522011-05-04 10:19:47 +05301714 udelay(20);
1715 /* control chg block via ULPI */
1716 chg_det &= ~(1 << 3);
Heikki Krogerus1d4c9292012-02-13 13:24:09 +02001717 ulpi_write(phy, chg_det, 0x34);
Pavankumar Kondetid8608522011-05-04 10:19:47 +05301718 /* put it in host mode for enabling D- source */
1719 chg_det &= ~(1 << 2);
Heikki Krogerus1d4c9292012-02-13 13:24:09 +02001720 ulpi_write(phy, chg_det, 0x34);
Pavankumar Kondetid8608522011-05-04 10:19:47 +05301721 /* Turn on chg detect block */
1722 chg_det &= ~(1 << 1);
Heikki Krogerus1d4c9292012-02-13 13:24:09 +02001723 ulpi_write(phy, chg_det, 0x34);
Pavankumar Kondetid8608522011-05-04 10:19:47 +05301724 udelay(20);
1725 /* enable chg detection */
1726 chg_det &= ~(1 << 0);
Heikki Krogerus1d4c9292012-02-13 13:24:09 +02001727 ulpi_write(phy, chg_det, 0x34);
Pavankumar Kondetid8608522011-05-04 10:19:47 +05301728 break;
1729 case SNPS_28NM_INTEGRATED_PHY:
1730 /*
1731 * Configure DM as current source, DP as current sink
1732 * and enable battery charging comparators.
1733 */
Heikki Krogerus1d4c9292012-02-13 13:24:09 +02001734 ulpi_write(phy, 0x8, 0x85);
1735 ulpi_write(phy, 0x2, 0x85);
1736 ulpi_write(phy, 0x1, 0x85);
Pavankumar Kondetid8608522011-05-04 10:19:47 +05301737 break;
1738 default:
1739 break;
1740 }
1741}
1742
1743static bool msm_chg_check_primary_det(struct msm_otg *motg)
1744{
Heikki Krogerus1d4c9292012-02-13 13:24:09 +02001745 struct usb_phy *phy = &motg->phy;
Pavankumar Kondetid8608522011-05-04 10:19:47 +05301746 u32 chg_det;
1747 bool ret = false;
1748
1749 switch (motg->pdata->phy_type) {
1750 case CI_45NM_INTEGRATED_PHY:
Heikki Krogerus1d4c9292012-02-13 13:24:09 +02001751 chg_det = ulpi_read(phy, 0x34);
Pavankumar Kondetid8608522011-05-04 10:19:47 +05301752 ret = chg_det & (1 << 4);
1753 break;
1754 case SNPS_28NM_INTEGRATED_PHY:
Heikki Krogerus1d4c9292012-02-13 13:24:09 +02001755 chg_det = ulpi_read(phy, 0x87);
Pavankumar Kondetid8608522011-05-04 10:19:47 +05301756 ret = chg_det & 1;
Pavankumar Kondeti9ec21d32012-05-07 15:50:23 +05301757 /* Turn off VDP_SRC */
1758 ulpi_write(phy, 0x3, 0x86);
1759 msleep(20);
Pavankumar Kondetid8608522011-05-04 10:19:47 +05301760 break;
1761 default:
1762 break;
1763 }
1764 return ret;
1765}
1766
1767static void msm_chg_enable_primary_det(struct msm_otg *motg)
1768{
Heikki Krogerus1d4c9292012-02-13 13:24:09 +02001769 struct usb_phy *phy = &motg->phy;
Pavankumar Kondetid8608522011-05-04 10:19:47 +05301770 u32 chg_det;
1771
1772 switch (motg->pdata->phy_type) {
1773 case CI_45NM_INTEGRATED_PHY:
Heikki Krogerus1d4c9292012-02-13 13:24:09 +02001774 chg_det = ulpi_read(phy, 0x34);
Pavankumar Kondetid8608522011-05-04 10:19:47 +05301775 /* enable chg detection */
1776 chg_det &= ~(1 << 0);
Heikki Krogerus1d4c9292012-02-13 13:24:09 +02001777 ulpi_write(phy, chg_det, 0x34);
Pavankumar Kondetid8608522011-05-04 10:19:47 +05301778 break;
1779 case SNPS_28NM_INTEGRATED_PHY:
1780 /*
1781 * Configure DP as current source, DM as current sink
1782 * and enable battery charging comparators.
1783 */
Heikki Krogerus1d4c9292012-02-13 13:24:09 +02001784 ulpi_write(phy, 0x2, 0x85);
1785 ulpi_write(phy, 0x1, 0x85);
Pavankumar Kondetid8608522011-05-04 10:19:47 +05301786 break;
1787 default:
1788 break;
1789 }
1790}
1791
1792static bool msm_chg_check_dcd(struct msm_otg *motg)
1793{
Heikki Krogerus1d4c9292012-02-13 13:24:09 +02001794 struct usb_phy *phy = &motg->phy;
Pavankumar Kondetid8608522011-05-04 10:19:47 +05301795 u32 line_state;
1796 bool ret = false;
1797
1798 switch (motg->pdata->phy_type) {
1799 case CI_45NM_INTEGRATED_PHY:
Heikki Krogerus1d4c9292012-02-13 13:24:09 +02001800 line_state = ulpi_read(phy, 0x15);
Pavankumar Kondetid8608522011-05-04 10:19:47 +05301801 ret = !(line_state & 1);
1802 break;
1803 case SNPS_28NM_INTEGRATED_PHY:
Heikki Krogerus1d4c9292012-02-13 13:24:09 +02001804 line_state = ulpi_read(phy, 0x87);
Pavankumar Kondetid8608522011-05-04 10:19:47 +05301805 ret = line_state & 2;
1806 break;
1807 default:
1808 break;
1809 }
1810 return ret;
1811}
1812
1813static void msm_chg_disable_dcd(struct msm_otg *motg)
1814{
Heikki Krogerus1d4c9292012-02-13 13:24:09 +02001815 struct usb_phy *phy = &motg->phy;
Pavankumar Kondetid8608522011-05-04 10:19:47 +05301816 u32 chg_det;
1817
1818 switch (motg->pdata->phy_type) {
1819 case CI_45NM_INTEGRATED_PHY:
Heikki Krogerus1d4c9292012-02-13 13:24:09 +02001820 chg_det = ulpi_read(phy, 0x34);
Pavankumar Kondetid8608522011-05-04 10:19:47 +05301821 chg_det &= ~(1 << 5);
Heikki Krogerus1d4c9292012-02-13 13:24:09 +02001822 ulpi_write(phy, chg_det, 0x34);
Pavankumar Kondetid8608522011-05-04 10:19:47 +05301823 break;
1824 case SNPS_28NM_INTEGRATED_PHY:
Heikki Krogerus1d4c9292012-02-13 13:24:09 +02001825 ulpi_write(phy, 0x10, 0x86);
Pavankumar Kondetid8608522011-05-04 10:19:47 +05301826 break;
1827 default:
1828 break;
1829 }
1830}
1831
1832static void msm_chg_enable_dcd(struct msm_otg *motg)
1833{
Heikki Krogerus1d4c9292012-02-13 13:24:09 +02001834 struct usb_phy *phy = &motg->phy;
Pavankumar Kondetid8608522011-05-04 10:19:47 +05301835 u32 chg_det;
1836
1837 switch (motg->pdata->phy_type) {
1838 case CI_45NM_INTEGRATED_PHY:
Heikki Krogerus1d4c9292012-02-13 13:24:09 +02001839 chg_det = ulpi_read(phy, 0x34);
Pavankumar Kondetid8608522011-05-04 10:19:47 +05301840 /* Turn on D+ current source */
1841 chg_det |= (1 << 5);
Heikki Krogerus1d4c9292012-02-13 13:24:09 +02001842 ulpi_write(phy, chg_det, 0x34);
Pavankumar Kondetid8608522011-05-04 10:19:47 +05301843 break;
1844 case SNPS_28NM_INTEGRATED_PHY:
1845 /* Data contact detection enable */
Heikki Krogerus1d4c9292012-02-13 13:24:09 +02001846 ulpi_write(phy, 0x10, 0x85);
Pavankumar Kondetid8608522011-05-04 10:19:47 +05301847 break;
1848 default:
1849 break;
1850 }
1851}
1852
1853static void msm_chg_block_on(struct msm_otg *motg)
1854{
Heikki Krogerus1d4c9292012-02-13 13:24:09 +02001855 struct usb_phy *phy = &motg->phy;
Pavankumar Kondetid8608522011-05-04 10:19:47 +05301856 u32 func_ctrl, chg_det;
1857
1858 /* put the controller in non-driving mode */
Heikki Krogerus1d4c9292012-02-13 13:24:09 +02001859 func_ctrl = ulpi_read(phy, ULPI_FUNC_CTRL);
Pavankumar Kondetid8608522011-05-04 10:19:47 +05301860 func_ctrl &= ~ULPI_FUNC_CTRL_OPMODE_MASK;
1861 func_ctrl |= ULPI_FUNC_CTRL_OPMODE_NONDRIVING;
Heikki Krogerus1d4c9292012-02-13 13:24:09 +02001862 ulpi_write(phy, func_ctrl, ULPI_FUNC_CTRL);
Pavankumar Kondetid8608522011-05-04 10:19:47 +05301863
1864 switch (motg->pdata->phy_type) {
1865 case CI_45NM_INTEGRATED_PHY:
Heikki Krogerus1d4c9292012-02-13 13:24:09 +02001866 chg_det = ulpi_read(phy, 0x34);
Pavankumar Kondetid8608522011-05-04 10:19:47 +05301867 /* control chg block via ULPI */
1868 chg_det &= ~(1 << 3);
Heikki Krogerus1d4c9292012-02-13 13:24:09 +02001869 ulpi_write(phy, chg_det, 0x34);
Pavankumar Kondetid8608522011-05-04 10:19:47 +05301870 /* Turn on chg detect block */
1871 chg_det &= ~(1 << 1);
Heikki Krogerus1d4c9292012-02-13 13:24:09 +02001872 ulpi_write(phy, chg_det, 0x34);
Pavankumar Kondetid8608522011-05-04 10:19:47 +05301873 udelay(20);
1874 break;
1875 case SNPS_28NM_INTEGRATED_PHY:
1876 /* Clear charger detecting control bits */
Steve Mucklef132c6c2012-06-06 18:30:57 -07001877 ulpi_write(phy, 0x1F, 0x86);
Pavankumar Kondetid8608522011-05-04 10:19:47 +05301878 /* Clear alt interrupt latch and enable bits */
Heikki Krogerus1d4c9292012-02-13 13:24:09 +02001879 ulpi_write(phy, 0x1F, 0x92);
1880 ulpi_write(phy, 0x1F, 0x95);
Pavankumar Kondetid8608522011-05-04 10:19:47 +05301881 udelay(100);
1882 break;
1883 default:
1884 break;
1885 }
1886}
1887
1888static void msm_chg_block_off(struct msm_otg *motg)
1889{
Heikki Krogerus1d4c9292012-02-13 13:24:09 +02001890 struct usb_phy *phy = &motg->phy;
Pavankumar Kondetid8608522011-05-04 10:19:47 +05301891 u32 func_ctrl, chg_det;
1892
1893 switch (motg->pdata->phy_type) {
1894 case CI_45NM_INTEGRATED_PHY:
Heikki Krogerus1d4c9292012-02-13 13:24:09 +02001895 chg_det = ulpi_read(phy, 0x34);
Pavankumar Kondetid8608522011-05-04 10:19:47 +05301896 /* Turn off charger block */
1897 chg_det |= ~(1 << 1);
Heikki Krogerus1d4c9292012-02-13 13:24:09 +02001898 ulpi_write(phy, chg_det, 0x34);
Pavankumar Kondetid8608522011-05-04 10:19:47 +05301899 break;
1900 case SNPS_28NM_INTEGRATED_PHY:
1901 /* Clear charger detecting control bits */
Heikki Krogerus1d4c9292012-02-13 13:24:09 +02001902 ulpi_write(phy, 0x3F, 0x86);
Pavankumar Kondetid8608522011-05-04 10:19:47 +05301903 /* Clear alt interrupt latch and enable bits */
Heikki Krogerus1d4c9292012-02-13 13:24:09 +02001904 ulpi_write(phy, 0x1F, 0x92);
1905 ulpi_write(phy, 0x1F, 0x95);
Pavankumar Kondetid8608522011-05-04 10:19:47 +05301906 break;
1907 default:
1908 break;
1909 }
1910
1911 /* put the controller in normal mode */
Heikki Krogerus1d4c9292012-02-13 13:24:09 +02001912 func_ctrl = ulpi_read(phy, ULPI_FUNC_CTRL);
Pavankumar Kondetid8608522011-05-04 10:19:47 +05301913 func_ctrl &= ~ULPI_FUNC_CTRL_OPMODE_MASK;
1914 func_ctrl |= ULPI_FUNC_CTRL_OPMODE_NORMAL;
Heikki Krogerus1d4c9292012-02-13 13:24:09 +02001915 ulpi_write(phy, func_ctrl, ULPI_FUNC_CTRL);
Pavankumar Kondetid8608522011-05-04 10:19:47 +05301916}
1917
Anji jonnalad270e2d2011-08-09 11:28:32 +05301918static const char *chg_to_string(enum usb_chg_type chg_type)
1919{
1920 switch (chg_type) {
1921 case USB_SDP_CHARGER: return "USB_SDP_CHARGER";
1922 case USB_DCP_CHARGER: return "USB_DCP_CHARGER";
1923 case USB_CDP_CHARGER: return "USB_CDP_CHARGER";
1924 case USB_ACA_A_CHARGER: return "USB_ACA_A_CHARGER";
1925 case USB_ACA_B_CHARGER: return "USB_ACA_B_CHARGER";
1926 case USB_ACA_C_CHARGER: return "USB_ACA_C_CHARGER";
1927 case USB_ACA_DOCK_CHARGER: return "USB_ACA_DOCK_CHARGER";
Pavankumar Kondeti9ec21d32012-05-07 15:50:23 +05301928 case USB_PROPRIETARY_CHARGER: return "USB_PROPRIETARY_CHARGER";
Anji jonnalad270e2d2011-08-09 11:28:32 +05301929 default: return "INVALID_CHARGER";
1930 }
1931}
1932
Pavankumar Kondetid8608522011-05-04 10:19:47 +05301933#define MSM_CHG_DCD_POLL_TIME (100 * HZ/1000) /* 100 msec */
1934#define MSM_CHG_DCD_MAX_RETRIES 6 /* Tdcd_tmout = 6 * 100 msec */
Pavankumar Kondeti283146f2012-01-12 12:51:19 +05301935#define MSM_CHG_PRIMARY_DET_TIME (50 * HZ/1000) /* TVDPSRC_ON */
1936#define MSM_CHG_SECONDARY_DET_TIME (50 * HZ/1000) /* TVDMSRC_ON */
Pavankumar Kondetid8608522011-05-04 10:19:47 +05301937static void msm_chg_detect_work(struct work_struct *w)
1938{
1939 struct msm_otg *motg = container_of(w, struct msm_otg, chg_work.work);
Heikki Krogerus1d4c9292012-02-13 13:24:09 +02001940 struct usb_phy *phy = &motg->phy;
Pavankumar Kondeti2d09e5f2012-01-16 08:56:57 +05301941 bool is_dcd = false, tmout, vout, is_aca;
Pavankumar Kondeti9ec21d32012-05-07 15:50:23 +05301942 u32 line_state, dm_vlgc;
Pavankumar Kondetid8608522011-05-04 10:19:47 +05301943 unsigned long delay;
1944
Heikki Krogerus1d4c9292012-02-13 13:24:09 +02001945 dev_dbg(phy->dev, "chg detection work\n");
Pavankumar Kondeti2aec9f32012-06-13 09:06:03 +05301946
1947 if (test_bit(MHL, &motg->inputs)) {
1948 dev_dbg(phy->dev, "detected MHL, escape chg detection work\n");
1949 return;
1950 }
1951
Pavankumar Kondetid8608522011-05-04 10:19:47 +05301952 switch (motg->chg_state) {
1953 case USB_CHG_STATE_UNDEFINED:
Pavankumar Kondetid8608522011-05-04 10:19:47 +05301954 msm_chg_block_on(motg);
Pavankumar Kondeti2d09e5f2012-01-16 08:56:57 +05301955 if (motg->pdata->enable_dcd)
1956 msm_chg_enable_dcd(motg);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001957 msm_chg_enable_aca_det(motg);
Pavankumar Kondetid8608522011-05-04 10:19:47 +05301958 motg->chg_state = USB_CHG_STATE_WAIT_FOR_DCD;
1959 motg->dcd_retries = 0;
1960 delay = MSM_CHG_DCD_POLL_TIME;
1961 break;
1962 case USB_CHG_STATE_WAIT_FOR_DCD:
Pavankumar Kondeti2aec9f32012-06-13 09:06:03 +05301963 if (msm_chg_mhl_detect(motg)) {
1964 msm_chg_block_off(motg);
1965 motg->chg_state = USB_CHG_STATE_DETECTED;
1966 motg->chg_type = USB_INVALID_CHARGER;
1967 queue_work(system_nrt_wq, &motg->sm_work);
1968 return;
1969 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001970 is_aca = msm_chg_aca_detect(motg);
1971 if (is_aca) {
1972 /*
1973 * ID_A can be ACA dock too. continue
1974 * primary detection after DCD.
1975 */
1976 if (test_bit(ID_A, &motg->inputs)) {
1977 motg->chg_state = USB_CHG_STATE_WAIT_FOR_DCD;
1978 } else {
1979 delay = 0;
1980 break;
1981 }
1982 }
Pavankumar Kondeti2d09e5f2012-01-16 08:56:57 +05301983 if (motg->pdata->enable_dcd)
1984 is_dcd = msm_chg_check_dcd(motg);
Pavankumar Kondetid8608522011-05-04 10:19:47 +05301985 tmout = ++motg->dcd_retries == MSM_CHG_DCD_MAX_RETRIES;
1986 if (is_dcd || tmout) {
Pavankumar Kondeti2d09e5f2012-01-16 08:56:57 +05301987 if (motg->pdata->enable_dcd)
1988 msm_chg_disable_dcd(motg);
Pavankumar Kondetid8608522011-05-04 10:19:47 +05301989 msm_chg_enable_primary_det(motg);
1990 delay = MSM_CHG_PRIMARY_DET_TIME;
1991 motg->chg_state = USB_CHG_STATE_DCD_DONE;
1992 } else {
1993 delay = MSM_CHG_DCD_POLL_TIME;
1994 }
1995 break;
1996 case USB_CHG_STATE_DCD_DONE:
1997 vout = msm_chg_check_primary_det(motg);
Pavankumar Kondeti9ec21d32012-05-07 15:50:23 +05301998 line_state = readl_relaxed(USB_PORTSC) & PORTSC_LS;
1999 dm_vlgc = line_state & PORTSC_LS_DM;
2000 if (vout && !dm_vlgc) { /* VDAT_REF < DM < VLGC */
Pavankumar Kondetiaa449e12011-11-04 11:09:26 +05302001 if (test_bit(ID_A, &motg->inputs)) {
2002 motg->chg_type = USB_ACA_DOCK_CHARGER;
2003 motg->chg_state = USB_CHG_STATE_DETECTED;
2004 delay = 0;
2005 break;
2006 }
Pavankumar Kondeti9ec21d32012-05-07 15:50:23 +05302007 if (line_state) { /* DP > VLGC */
2008 motg->chg_type = USB_PROPRIETARY_CHARGER;
2009 motg->chg_state = USB_CHG_STATE_DETECTED;
2010 delay = 0;
2011 } else {
2012 msm_chg_enable_secondary_det(motg);
2013 delay = MSM_CHG_SECONDARY_DET_TIME;
2014 motg->chg_state = USB_CHG_STATE_PRIMARY_DONE;
2015 }
2016 } else { /* DM < VDAT_REF || DM > VLGC */
Pavankumar Kondetiaa449e12011-11-04 11:09:26 +05302017 if (test_bit(ID_A, &motg->inputs)) {
2018 motg->chg_type = USB_ACA_A_CHARGER;
2019 motg->chg_state = USB_CHG_STATE_DETECTED;
2020 delay = 0;
2021 break;
2022 }
Pavankumar Kondeti9ec21d32012-05-07 15:50:23 +05302023
2024 if (line_state) /* DP > VLGC or/and DM > VLGC */
2025 motg->chg_type = USB_PROPRIETARY_CHARGER;
2026 else
2027 motg->chg_type = USB_SDP_CHARGER;
2028
Pavankumar Kondetid8608522011-05-04 10:19:47 +05302029 motg->chg_state = USB_CHG_STATE_DETECTED;
2030 delay = 0;
2031 }
2032 break;
2033 case USB_CHG_STATE_PRIMARY_DONE:
2034 vout = msm_chg_check_secondary_det(motg);
2035 if (vout)
2036 motg->chg_type = USB_DCP_CHARGER;
2037 else
2038 motg->chg_type = USB_CDP_CHARGER;
2039 motg->chg_state = USB_CHG_STATE_SECONDARY_DONE;
2040 /* fall through */
2041 case USB_CHG_STATE_SECONDARY_DONE:
2042 motg->chg_state = USB_CHG_STATE_DETECTED;
2043 case USB_CHG_STATE_DETECTED:
2044 msm_chg_block_off(motg);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002045 msm_chg_enable_aca_det(motg);
Vijayavardhan Vennapusaa3152032012-03-05 16:29:30 +05302046 /*
2047 * Spurious interrupt is seen after enabling ACA detection
2048 * due to which charger detection fails in case of PET.
2049 * Add delay of 100 microsec to avoid that.
2050 */
2051 udelay(100);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002052 msm_chg_enable_aca_intr(motg);
Steve Mucklef132c6c2012-06-06 18:30:57 -07002053 dev_dbg(phy->dev, "chg_type = %s\n",
Anji jonnalad270e2d2011-08-09 11:28:32 +05302054 chg_to_string(motg->chg_type));
Vijayavardhan Vennapusaa3152032012-03-05 16:29:30 +05302055 queue_work(system_nrt_wq, &motg->sm_work);
Pavankumar Kondetid8608522011-05-04 10:19:47 +05302056 return;
2057 default:
2058 return;
2059 }
2060
Vijayavardhan Vennapusaa3152032012-03-05 16:29:30 +05302061 queue_delayed_work(system_nrt_wq, &motg->chg_work, delay);
Pavankumar Kondetid8608522011-05-04 10:19:47 +05302062}
2063
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05302064/*
2065 * We support OTG, Peripheral only and Host only configurations. In case
2066 * of OTG, mode switch (host-->peripheral/peripheral-->host) can happen
2067 * via Id pin status or user request (debugfs). Id/BSV interrupts are not
2068 * enabled when switch is controlled by user and default mode is supplied
2069 * by board file, which can be changed by userspace later.
2070 */
2071static void msm_otg_init_sm(struct msm_otg *motg)
2072{
2073 struct msm_otg_platform_data *pdata = motg->pdata;
2074 u32 otgsc = readl(USB_OTGSC);
2075
2076 switch (pdata->mode) {
2077 case USB_OTG:
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002078 if (pdata->otg_control == OTG_USER_CONTROL) {
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05302079 if (pdata->default_mode == USB_HOST) {
2080 clear_bit(ID, &motg->inputs);
2081 } else if (pdata->default_mode == USB_PERIPHERAL) {
2082 set_bit(ID, &motg->inputs);
2083 set_bit(B_SESS_VLD, &motg->inputs);
2084 } else {
2085 set_bit(ID, &motg->inputs);
2086 clear_bit(B_SESS_VLD, &motg->inputs);
2087 }
Pavankumar Kondeti4960f312011-12-06 15:46:14 +05302088 } else if (pdata->otg_control == OTG_PHY_CONTROL) {
Vijayavardhan Vennapusaa3152032012-03-05 16:29:30 +05302089 if (otgsc & OTGSC_ID) {
Pavankumar Kondeti4960f312011-12-06 15:46:14 +05302090 set_bit(ID, &motg->inputs);
Vijayavardhan Vennapusaa3152032012-03-05 16:29:30 +05302091 } else {
Pavankumar Kondeti4960f312011-12-06 15:46:14 +05302092 clear_bit(ID, &motg->inputs);
Vijayavardhan Vennapusaa3152032012-03-05 16:29:30 +05302093 set_bit(A_BUS_REQ, &motg->inputs);
2094 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002095 if (otgsc & OTGSC_BSV)
2096 set_bit(B_SESS_VLD, &motg->inputs);
2097 else
2098 clear_bit(B_SESS_VLD, &motg->inputs);
Pavankumar Kondeti4960f312011-12-06 15:46:14 +05302099 } else if (pdata->otg_control == OTG_PMIC_CONTROL) {
Pavankumar Kondeti0d81f312012-01-13 11:34:10 +05302100 if (pdata->pmic_id_irq) {
Stephen Boyd431771e2012-04-18 20:00:23 -07002101 unsigned long flags;
2102 local_irq_save(flags);
Pavankumar Kondeti0d81f312012-01-13 11:34:10 +05302103 if (irq_read_line(pdata->pmic_id_irq))
2104 set_bit(ID, &motg->inputs);
2105 else
2106 clear_bit(ID, &motg->inputs);
Stephen Boyd431771e2012-04-18 20:00:23 -07002107 local_irq_restore(flags);
Pavankumar Kondeti0d81f312012-01-13 11:34:10 +05302108 }
Pavankumar Kondeti4960f312011-12-06 15:46:14 +05302109 /*
2110 * VBUS initial state is reported after PMIC
2111 * driver initialization. Wait for it.
2112 */
2113 wait_for_completion(&pmic_vbus_init);
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05302114 }
2115 break;
2116 case USB_HOST:
2117 clear_bit(ID, &motg->inputs);
2118 break;
2119 case USB_PERIPHERAL:
2120 set_bit(ID, &motg->inputs);
Pavankumar Kondeti0d81f312012-01-13 11:34:10 +05302121 if (pdata->otg_control == OTG_PHY_CONTROL) {
2122 if (otgsc & OTGSC_BSV)
2123 set_bit(B_SESS_VLD, &motg->inputs);
2124 else
2125 clear_bit(B_SESS_VLD, &motg->inputs);
2126 } else if (pdata->otg_control == OTG_PMIC_CONTROL) {
2127 /*
2128 * VBUS initial state is reported after PMIC
2129 * driver initialization. Wait for it.
2130 */
2131 wait_for_completion(&pmic_vbus_init);
2132 }
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05302133 break;
2134 default:
2135 break;
2136 }
2137}
2138
2139static void msm_otg_sm_work(struct work_struct *w)
2140{
2141 struct msm_otg *motg = container_of(w, struct msm_otg, sm_work);
Heikki Krogerus1d4c9292012-02-13 13:24:09 +02002142 struct usb_otg *otg = motg->phy.otg;
Vijayavardhan Vennapusaa3152032012-03-05 16:29:30 +05302143 bool work = 0, srp_reqd;
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05302144
Steve Mucklef132c6c2012-06-06 18:30:57 -07002145 pm_runtime_resume(otg->phy->dev);
2146 pr_debug("%s work\n", otg_state_string(otg->phy->state));
Heikki Krogerus1d4c9292012-02-13 13:24:09 +02002147 switch (otg->phy->state) {
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05302148 case OTG_STATE_UNDEFINED:
Heikki Krogerus1d4c9292012-02-13 13:24:09 +02002149 msm_otg_reset(otg->phy);
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05302150 msm_otg_init_sm(motg);
Vijayavardhan Vennapusa05c437c2012-05-25 16:20:46 +05302151 psy = power_supply_get_by_name("usb");
2152 if (!psy)
2153 pr_err("couldn't get usb power supply\n");
Heikki Krogerus1d4c9292012-02-13 13:24:09 +02002154 otg->phy->state = OTG_STATE_B_IDLE;
Pavankumar Kondeti8a379b42011-12-12 13:07:23 +05302155 if (!test_bit(B_SESS_VLD, &motg->inputs) &&
2156 test_bit(ID, &motg->inputs)) {
Steve Mucklef132c6c2012-06-06 18:30:57 -07002157 pm_runtime_put_noidle(otg->phy->dev);
2158 pm_runtime_suspend(otg->phy->dev);
Pavankumar Kondeti8a379b42011-12-12 13:07:23 +05302159 break;
2160 }
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05302161 /* FALL THROUGH */
2162 case OTG_STATE_B_IDLE:
Pavankumar Kondeti2aec9f32012-06-13 09:06:03 +05302163 if (test_bit(MHL, &motg->inputs)) {
2164 /* allow LPM */
2165 pm_runtime_put_noidle(otg->phy->dev);
2166 pm_runtime_suspend(otg->phy->dev);
2167 } else if ((!test_bit(ID, &motg->inputs) ||
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002168 test_bit(ID_A, &motg->inputs)) && otg->host) {
Vijayavardhan Vennapusaa3152032012-03-05 16:29:30 +05302169 pr_debug("!id || id_A\n");
Pavankumar Kondeti2aec9f32012-06-13 09:06:03 +05302170 if (msm_chg_mhl_detect(motg)) {
2171 work = 1;
2172 break;
2173 }
Vijayavardhan Vennapusaa3152032012-03-05 16:29:30 +05302174 clear_bit(B_BUS_REQ, &motg->inputs);
2175 set_bit(A_BUS_REQ, &motg->inputs);
Steve Mucklef132c6c2012-06-06 18:30:57 -07002176 otg->phy->state = OTG_STATE_A_IDLE;
Vijayavardhan Vennapusaa3152032012-03-05 16:29:30 +05302177 work = 1;
Pavankumar Kondetid8608522011-05-04 10:19:47 +05302178 } else if (test_bit(B_SESS_VLD, &motg->inputs)) {
Vijayavardhan Vennapusaa3152032012-03-05 16:29:30 +05302179 pr_debug("b_sess_vld\n");
Pavankumar Kondetid8608522011-05-04 10:19:47 +05302180 switch (motg->chg_state) {
2181 case USB_CHG_STATE_UNDEFINED:
2182 msm_chg_detect_work(&motg->chg_work.work);
2183 break;
2184 case USB_CHG_STATE_DETECTED:
2185 switch (motg->chg_type) {
2186 case USB_DCP_CHARGER:
Pavankumar Kondeti283146f2012-01-12 12:51:19 +05302187 /* Enable VDP_SRC */
Steve Mucklef132c6c2012-06-06 18:30:57 -07002188 ulpi_write(otg->phy, 0x2, 0x85);
Pavankumar Kondeti9ec21d32012-05-07 15:50:23 +05302189 /* fall through */
2190 case USB_PROPRIETARY_CHARGER:
Pavankumar Kondetid8608522011-05-04 10:19:47 +05302191 msm_otg_notify_charger(motg,
2192 IDEV_CHG_MAX);
Steve Mucklef132c6c2012-06-06 18:30:57 -07002193 pm_runtime_put_noidle(otg->phy->dev);
2194 pm_runtime_suspend(otg->phy->dev);
Pavankumar Kondetid8608522011-05-04 10:19:47 +05302195 break;
Pavankumar Kondetiaa449e12011-11-04 11:09:26 +05302196 case USB_ACA_B_CHARGER:
2197 msm_otg_notify_charger(motg,
2198 IDEV_ACA_CHG_MAX);
2199 /*
2200 * (ID_B --> ID_C) PHY_ALT interrupt can
2201 * not be detected in LPM.
2202 */
Pavankumar Kondetid8608522011-05-04 10:19:47 +05302203 break;
2204 case USB_CDP_CHARGER:
2205 msm_otg_notify_charger(motg,
2206 IDEV_CHG_MAX);
2207 msm_otg_start_peripheral(otg, 1);
Steve Mucklef132c6c2012-06-06 18:30:57 -07002208 otg->phy->state =
2209 OTG_STATE_B_PERIPHERAL;
Pavankumar Kondetid8608522011-05-04 10:19:47 +05302210 break;
Pavankumar Kondetiaa449e12011-11-04 11:09:26 +05302211 case USB_ACA_C_CHARGER:
2212 msm_otg_notify_charger(motg,
2213 IDEV_ACA_CHG_MAX);
2214 msm_otg_start_peripheral(otg, 1);
Steve Mucklef132c6c2012-06-06 18:30:57 -07002215 otg->phy->state =
2216 OTG_STATE_B_PERIPHERAL;
Pavankumar Kondetid8608522011-05-04 10:19:47 +05302217 break;
2218 case USB_SDP_CHARGER:
Pavankumar Kondetid8608522011-05-04 10:19:47 +05302219 msm_otg_start_peripheral(otg, 1);
Steve Mucklef132c6c2012-06-06 18:30:57 -07002220 otg->phy->state =
2221 OTG_STATE_B_PERIPHERAL;
Pavankumar Kondetid8608522011-05-04 10:19:47 +05302222 break;
2223 default:
2224 break;
2225 }
2226 break;
2227 default:
2228 break;
2229 }
Vijayavardhan Vennapusaa3152032012-03-05 16:29:30 +05302230 } else if (test_bit(B_BUS_REQ, &motg->inputs)) {
2231 pr_debug("b_sess_end && b_bus_req\n");
2232 if (msm_otg_start_srp(otg) < 0) {
2233 clear_bit(B_BUS_REQ, &motg->inputs);
2234 work = 1;
2235 break;
Pavankumar Kondetid8608522011-05-04 10:19:47 +05302236 }
Steve Mucklef132c6c2012-06-06 18:30:57 -07002237 otg->phy->state = OTG_STATE_B_SRP_INIT;
Vijayavardhan Vennapusaa3152032012-03-05 16:29:30 +05302238 msm_otg_start_timer(motg, TB_SRP_FAIL, B_SRP_FAIL);
2239 break;
Pavankumar Kondetid8608522011-05-04 10:19:47 +05302240 } else {
Vijayavardhan Vennapusaa3152032012-03-05 16:29:30 +05302241 pr_debug("chg_work cancel");
Pavankumar Kondetiaa449e12011-11-04 11:09:26 +05302242 cancel_delayed_work_sync(&motg->chg_work);
Pavankumar Kondetid8608522011-05-04 10:19:47 +05302243 motg->chg_state = USB_CHG_STATE_UNDEFINED;
2244 motg->chg_type = USB_INVALID_CHARGER;
Rajkumar Raghupathy18fd7132012-04-20 11:28:13 +05302245 msm_otg_notify_charger(motg, 0);
Steve Mucklef132c6c2012-06-06 18:30:57 -07002246 msm_otg_reset(otg->phy);
2247 pm_runtime_put_noidle(otg->phy->dev);
2248 pm_runtime_suspend(otg->phy->dev);
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05302249 }
2250 break;
Vijayavardhan Vennapusaa3152032012-03-05 16:29:30 +05302251 case OTG_STATE_B_SRP_INIT:
2252 if (!test_bit(ID, &motg->inputs) ||
2253 test_bit(ID_A, &motg->inputs) ||
2254 test_bit(ID_C, &motg->inputs) ||
2255 (test_bit(B_SESS_VLD, &motg->inputs) &&
2256 !test_bit(ID_B, &motg->inputs))) {
2257 pr_debug("!id || id_a/c || b_sess_vld+!id_b\n");
2258 msm_otg_del_timer(motg);
Steve Mucklef132c6c2012-06-06 18:30:57 -07002259 otg->phy->state = OTG_STATE_B_IDLE;
Vijayavardhan Vennapusaa3152032012-03-05 16:29:30 +05302260 /*
2261 * clear VBUSVLDEXTSEL and VBUSVLDEXT register
2262 * bits after SRP initiation.
2263 */
Steve Mucklef132c6c2012-06-06 18:30:57 -07002264 ulpi_write(otg->phy, 0x0, 0x98);
Vijayavardhan Vennapusaa3152032012-03-05 16:29:30 +05302265 work = 1;
2266 } else if (test_bit(B_SRP_FAIL, &motg->tmouts)) {
2267 pr_debug("b_srp_fail\n");
2268 pr_info("A-device did not respond to SRP\n");
2269 clear_bit(B_BUS_REQ, &motg->inputs);
2270 clear_bit(B_SRP_FAIL, &motg->tmouts);
2271 otg_send_event(OTG_EVENT_NO_RESP_FOR_SRP);
Steve Mucklef132c6c2012-06-06 18:30:57 -07002272 ulpi_write(otg->phy, 0x0, 0x98);
2273 otg->phy->state = OTG_STATE_B_IDLE;
Vijayavardhan Vennapusaa3152032012-03-05 16:29:30 +05302274 motg->b_last_se0_sess = jiffies;
2275 work = 1;
2276 }
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05302277 break;
2278 case OTG_STATE_B_PERIPHERAL:
Vijayavardhan Vennapusaa3152032012-03-05 16:29:30 +05302279 if (!test_bit(ID, &motg->inputs) ||
2280 test_bit(ID_A, &motg->inputs) ||
2281 test_bit(ID_B, &motg->inputs) ||
2282 !test_bit(B_SESS_VLD, &motg->inputs)) {
2283 pr_debug("!id || id_a/b || !b_sess_vld\n");
Pavankumar Kondetid8608522011-05-04 10:19:47 +05302284 motg->chg_state = USB_CHG_STATE_UNDEFINED;
2285 motg->chg_type = USB_INVALID_CHARGER;
Vijayavardhan Vennapusaa3152032012-03-05 16:29:30 +05302286 msm_otg_notify_charger(motg, 0);
2287 srp_reqd = otg->gadget->otg_srp_reqd;
2288 msm_otg_start_peripheral(otg, 0);
Vijayavardhan Vennapusaa3152032012-03-05 16:29:30 +05302289 if (test_bit(ID_B, &motg->inputs))
2290 clear_bit(ID_B, &motg->inputs);
2291 clear_bit(B_BUS_REQ, &motg->inputs);
Steve Mucklef132c6c2012-06-06 18:30:57 -07002292 otg->phy->state = OTG_STATE_B_IDLE;
Vijayavardhan Vennapusaa3152032012-03-05 16:29:30 +05302293 motg->b_last_se0_sess = jiffies;
2294 if (srp_reqd)
2295 msm_otg_start_timer(motg,
2296 TB_TST_SRP, B_TST_SRP);
2297 else
2298 work = 1;
2299 } else if (test_bit(B_BUS_REQ, &motg->inputs) &&
2300 otg->gadget->b_hnp_enable &&
2301 test_bit(A_BUS_SUSPEND, &motg->inputs)) {
2302 pr_debug("b_bus_req && b_hnp_en && a_bus_suspend\n");
2303 msm_otg_start_timer(motg, TB_ASE0_BRST, B_ASE0_BRST);
2304 /* D+ pullup should not be disconnected within 4msec
2305 * after A device suspends the bus. Otherwise PET will
2306 * fail the compliance test.
2307 */
2308 udelay(1000);
2309 msm_otg_start_peripheral(otg, 0);
Steve Mucklef132c6c2012-06-06 18:30:57 -07002310 otg->phy->state = OTG_STATE_B_WAIT_ACON;
Vijayavardhan Vennapusaa3152032012-03-05 16:29:30 +05302311 /*
2312 * start HCD even before A-device enable
2313 * pull-up to meet HNP timings.
2314 */
2315 otg->host->is_b_host = 1;
2316 msm_otg_start_host(otg, 1);
Amit Blay6fa647a2012-05-24 14:12:08 +03002317 } else if (test_bit(A_BUS_SUSPEND, &motg->inputs) &&
2318 test_bit(B_SESS_VLD, &motg->inputs)) {
2319 pr_debug("a_bus_suspend && b_sess_vld\n");
2320 if (motg->caps & ALLOW_LPM_ON_DEV_SUSPEND) {
Steve Mucklef132c6c2012-06-06 18:30:57 -07002321 pm_runtime_put_noidle(otg->phy->dev);
2322 pm_runtime_suspend(otg->phy->dev);
Amit Blay6fa647a2012-05-24 14:12:08 +03002323 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002324 } else if (test_bit(ID_C, &motg->inputs)) {
Pavankumar Kondetiaa449e12011-11-04 11:09:26 +05302325 msm_otg_notify_charger(motg, IDEV_ACA_CHG_MAX);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002326 }
2327 break;
Vijayavardhan Vennapusaa3152032012-03-05 16:29:30 +05302328 case OTG_STATE_B_WAIT_ACON:
2329 if (!test_bit(ID, &motg->inputs) ||
2330 test_bit(ID_A, &motg->inputs) ||
2331 test_bit(ID_B, &motg->inputs) ||
2332 !test_bit(B_SESS_VLD, &motg->inputs)) {
2333 pr_debug("!id || id_a/b || !b_sess_vld\n");
2334 msm_otg_del_timer(motg);
Pavankumar Kondetiaa449e12011-11-04 11:09:26 +05302335 /*
Vijayavardhan Vennapusaa3152032012-03-05 16:29:30 +05302336 * A-device is physically disconnected during
2337 * HNP. Remove HCD.
Pavankumar Kondetiaa449e12011-11-04 11:09:26 +05302338 */
Vijayavardhan Vennapusaa3152032012-03-05 16:29:30 +05302339 msm_otg_start_host(otg, 0);
2340 otg->host->is_b_host = 0;
2341
2342 clear_bit(B_BUS_REQ, &motg->inputs);
2343 clear_bit(A_BUS_SUSPEND, &motg->inputs);
2344 motg->b_last_se0_sess = jiffies;
Heikki Krogerus1d4c9292012-02-13 13:24:09 +02002345 otg->phy->state = OTG_STATE_B_IDLE;
2346 msm_otg_reset(otg->phy);
Vijayavardhan Vennapusaa3152032012-03-05 16:29:30 +05302347 work = 1;
2348 } else if (test_bit(A_CONN, &motg->inputs)) {
2349 pr_debug("a_conn\n");
2350 clear_bit(A_BUS_SUSPEND, &motg->inputs);
Steve Mucklef132c6c2012-06-06 18:30:57 -07002351 otg->phy->state = OTG_STATE_B_HOST;
Vijayavardhan Vennapusaa3152032012-03-05 16:29:30 +05302352 /*
2353 * PET disconnects D+ pullup after reset is generated
2354 * by B device in B_HOST role which is not detected by
2355 * B device. As workaorund , start timer of 300msec
2356 * and stop timer if A device is enumerated else clear
2357 * A_CONN.
2358 */
2359 msm_otg_start_timer(motg, TB_TST_CONFIG,
2360 B_TST_CONFIG);
2361 } else if (test_bit(B_ASE0_BRST, &motg->tmouts)) {
2362 pr_debug("b_ase0_brst_tmout\n");
2363 pr_info("B HNP fail:No response from A device\n");
2364 msm_otg_start_host(otg, 0);
Steve Mucklef132c6c2012-06-06 18:30:57 -07002365 msm_otg_reset(otg->phy);
Vijayavardhan Vennapusaa3152032012-03-05 16:29:30 +05302366 otg->host->is_b_host = 0;
2367 clear_bit(B_ASE0_BRST, &motg->tmouts);
2368 clear_bit(A_BUS_SUSPEND, &motg->inputs);
2369 clear_bit(B_BUS_REQ, &motg->inputs);
2370 otg_send_event(OTG_EVENT_HNP_FAILED);
Steve Mucklef132c6c2012-06-06 18:30:57 -07002371 otg->phy->state = OTG_STATE_B_IDLE;
Vijayavardhan Vennapusaa3152032012-03-05 16:29:30 +05302372 work = 1;
2373 } else if (test_bit(ID_C, &motg->inputs)) {
2374 msm_otg_notify_charger(motg, IDEV_ACA_CHG_MAX);
2375 }
2376 break;
2377 case OTG_STATE_B_HOST:
2378 if (!test_bit(B_BUS_REQ, &motg->inputs) ||
2379 !test_bit(A_CONN, &motg->inputs) ||
2380 !test_bit(B_SESS_VLD, &motg->inputs)) {
2381 pr_debug("!b_bus_req || !a_conn || !b_sess_vld\n");
2382 clear_bit(A_CONN, &motg->inputs);
2383 clear_bit(B_BUS_REQ, &motg->inputs);
2384 msm_otg_start_host(otg, 0);
2385 otg->host->is_b_host = 0;
Steve Mucklef132c6c2012-06-06 18:30:57 -07002386 otg->phy->state = OTG_STATE_B_IDLE;
2387 msm_otg_reset(otg->phy);
Vijayavardhan Vennapusaa3152032012-03-05 16:29:30 +05302388 work = 1;
2389 } else if (test_bit(ID_C, &motg->inputs)) {
2390 msm_otg_notify_charger(motg, IDEV_ACA_CHG_MAX);
2391 }
2392 break;
2393 case OTG_STATE_A_IDLE:
2394 otg->default_a = 1;
2395 if (test_bit(ID, &motg->inputs) &&
2396 !test_bit(ID_A, &motg->inputs)) {
2397 pr_debug("id && !id_a\n");
2398 otg->default_a = 0;
2399 clear_bit(A_BUS_DROP, &motg->inputs);
Steve Mucklef132c6c2012-06-06 18:30:57 -07002400 otg->phy->state = OTG_STATE_B_IDLE;
Vijayavardhan Vennapusaa3152032012-03-05 16:29:30 +05302401 del_timer_sync(&motg->id_timer);
2402 msm_otg_link_reset(motg);
2403 msm_chg_enable_aca_intr(motg);
2404 msm_otg_notify_charger(motg, 0);
2405 work = 1;
2406 } else if (!test_bit(A_BUS_DROP, &motg->inputs) &&
2407 (test_bit(A_SRP_DET, &motg->inputs) ||
2408 test_bit(A_BUS_REQ, &motg->inputs))) {
2409 pr_debug("!a_bus_drop && (a_srp_det || a_bus_req)\n");
2410
2411 clear_bit(A_SRP_DET, &motg->inputs);
2412 /* Disable SRP detection */
2413 writel_relaxed((readl_relaxed(USB_OTGSC) &
2414 ~OTGSC_INTSTS_MASK) &
2415 ~OTGSC_DPIE, USB_OTGSC);
2416
Steve Mucklef132c6c2012-06-06 18:30:57 -07002417 otg->phy->state = OTG_STATE_A_WAIT_VRISE;
Vijayavardhan Vennapusaa3152032012-03-05 16:29:30 +05302418 /* VBUS should not be supplied before end of SRP pulse
2419 * generated by PET, if not complaince test fail.
2420 */
2421 usleep_range(10000, 12000);
2422 /* ACA: ID_A: Stop charging untill enumeration */
2423 if (test_bit(ID_A, &motg->inputs))
2424 msm_otg_notify_charger(motg, 0);
2425 else
2426 msm_hsusb_vbus_power(motg, 1);
2427 msm_otg_start_timer(motg, TA_WAIT_VRISE, A_WAIT_VRISE);
2428 } else {
2429 pr_debug("No session requested\n");
2430 clear_bit(A_BUS_DROP, &motg->inputs);
2431 if (test_bit(ID_A, &motg->inputs)) {
2432 msm_otg_notify_charger(motg,
2433 IDEV_ACA_CHG_MAX);
2434 } else if (!test_bit(ID, &motg->inputs)) {
2435 msm_otg_notify_charger(motg, 0);
2436 /*
2437 * A-device is not providing power on VBUS.
2438 * Enable SRP detection.
2439 */
2440 writel_relaxed(0x13, USB_USBMODE);
2441 writel_relaxed((readl_relaxed(USB_OTGSC) &
2442 ~OTGSC_INTSTS_MASK) |
2443 OTGSC_DPIE, USB_OTGSC);
2444 mb();
2445 }
2446 }
2447 break;
2448 case OTG_STATE_A_WAIT_VRISE:
2449 if ((test_bit(ID, &motg->inputs) &&
2450 !test_bit(ID_A, &motg->inputs)) ||
2451 test_bit(A_BUS_DROP, &motg->inputs) ||
2452 test_bit(A_WAIT_VRISE, &motg->tmouts)) {
2453 pr_debug("id || a_bus_drop || a_wait_vrise_tmout\n");
2454 clear_bit(A_BUS_REQ, &motg->inputs);
2455 msm_otg_del_timer(motg);
2456 msm_hsusb_vbus_power(motg, 0);
Steve Mucklef132c6c2012-06-06 18:30:57 -07002457 otg->phy->state = OTG_STATE_A_WAIT_VFALL;
Vijayavardhan Vennapusaa3152032012-03-05 16:29:30 +05302458 msm_otg_start_timer(motg, TA_WAIT_VFALL, A_WAIT_VFALL);
2459 } else if (test_bit(A_VBUS_VLD, &motg->inputs)) {
2460 pr_debug("a_vbus_vld\n");
Steve Mucklef132c6c2012-06-06 18:30:57 -07002461 otg->phy->state = OTG_STATE_A_WAIT_BCON;
Vijayavardhan Vennapusaa3152032012-03-05 16:29:30 +05302462 if (TA_WAIT_BCON > 0)
2463 msm_otg_start_timer(motg, TA_WAIT_BCON,
2464 A_WAIT_BCON);
2465 msm_otg_start_host(otg, 1);
2466 msm_chg_enable_aca_det(motg);
2467 msm_chg_disable_aca_intr(motg);
Chiranjeevi Velempati489a27c2012-03-29 09:47:17 +05302468 mod_timer(&motg->id_timer, ID_TIMER_FREQ);
Vijayavardhan Vennapusaa3152032012-03-05 16:29:30 +05302469 if (msm_chg_check_aca_intr(motg))
2470 work = 1;
2471 }
2472 break;
2473 case OTG_STATE_A_WAIT_BCON:
2474 if ((test_bit(ID, &motg->inputs) &&
2475 !test_bit(ID_A, &motg->inputs)) ||
2476 test_bit(A_BUS_DROP, &motg->inputs) ||
2477 test_bit(A_WAIT_BCON, &motg->tmouts)) {
2478 pr_debug("(id && id_a/b/c) || a_bus_drop ||"
2479 "a_wait_bcon_tmout\n");
2480 if (test_bit(A_WAIT_BCON, &motg->tmouts)) {
2481 pr_info("Device No Response\n");
2482 otg_send_event(OTG_EVENT_DEV_CONN_TMOUT);
2483 }
2484 msm_otg_del_timer(motg);
2485 clear_bit(A_BUS_REQ, &motg->inputs);
2486 clear_bit(B_CONN, &motg->inputs);
2487 msm_otg_start_host(otg, 0);
2488 /*
2489 * ACA: ID_A with NO accessory, just the A plug is
2490 * attached to ACA: Use IDCHG_MAX for charging
2491 */
2492 if (test_bit(ID_A, &motg->inputs))
2493 msm_otg_notify_charger(motg, IDEV_CHG_MIN);
2494 else
2495 msm_hsusb_vbus_power(motg, 0);
Steve Mucklef132c6c2012-06-06 18:30:57 -07002496 otg->phy->state = OTG_STATE_A_WAIT_VFALL;
Vijayavardhan Vennapusaa3152032012-03-05 16:29:30 +05302497 msm_otg_start_timer(motg, TA_WAIT_VFALL, A_WAIT_VFALL);
2498 } else if (!test_bit(A_VBUS_VLD, &motg->inputs)) {
2499 pr_debug("!a_vbus_vld\n");
2500 clear_bit(B_CONN, &motg->inputs);
2501 msm_otg_del_timer(motg);
2502 msm_otg_start_host(otg, 0);
Steve Mucklef132c6c2012-06-06 18:30:57 -07002503 otg->phy->state = OTG_STATE_A_VBUS_ERR;
2504 msm_otg_reset(otg->phy);
Vijayavardhan Vennapusaa3152032012-03-05 16:29:30 +05302505 } else if (test_bit(ID_A, &motg->inputs)) {
2506 msm_hsusb_vbus_power(motg, 0);
2507 } else if (!test_bit(A_BUS_REQ, &motg->inputs)) {
2508 /*
2509 * If TA_WAIT_BCON is infinite, we don;t
2510 * turn off VBUS. Enter low power mode.
2511 */
2512 if (TA_WAIT_BCON < 0)
Steve Mucklef132c6c2012-06-06 18:30:57 -07002513 pm_runtime_put_sync(otg->phy->dev);
Vijayavardhan Vennapusaa3152032012-03-05 16:29:30 +05302514 } else if (!test_bit(ID, &motg->inputs)) {
2515 msm_hsusb_vbus_power(motg, 1);
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05302516 }
2517 break;
2518 case OTG_STATE_A_HOST:
Vijayavardhan Vennapusaa3152032012-03-05 16:29:30 +05302519 if ((test_bit(ID, &motg->inputs) &&
2520 !test_bit(ID_A, &motg->inputs)) ||
2521 test_bit(A_BUS_DROP, &motg->inputs)) {
2522 pr_debug("id_a/b/c || a_bus_drop\n");
2523 clear_bit(B_CONN, &motg->inputs);
2524 clear_bit(A_BUS_REQ, &motg->inputs);
2525 msm_otg_del_timer(motg);
Steve Mucklef132c6c2012-06-06 18:30:57 -07002526 otg->phy->state = OTG_STATE_A_WAIT_VFALL;
Vijayavardhan Vennapusaa3152032012-03-05 16:29:30 +05302527 msm_otg_start_host(otg, 0);
2528 if (!test_bit(ID_A, &motg->inputs))
2529 msm_hsusb_vbus_power(motg, 0);
2530 msm_otg_start_timer(motg, TA_WAIT_VFALL, A_WAIT_VFALL);
2531 } else if (!test_bit(A_VBUS_VLD, &motg->inputs)) {
2532 pr_debug("!a_vbus_vld\n");
2533 clear_bit(B_CONN, &motg->inputs);
2534 msm_otg_del_timer(motg);
Steve Mucklef132c6c2012-06-06 18:30:57 -07002535 otg->phy->state = OTG_STATE_A_VBUS_ERR;
Vijayavardhan Vennapusaa3152032012-03-05 16:29:30 +05302536 msm_otg_start_host(otg, 0);
Heikki Krogerus1d4c9292012-02-13 13:24:09 +02002537 msm_otg_reset(otg->phy);
Vijayavardhan Vennapusaa3152032012-03-05 16:29:30 +05302538 } else if (!test_bit(A_BUS_REQ, &motg->inputs)) {
2539 /*
2540 * a_bus_req is de-asserted when root hub is
2541 * suspended or HNP is in progress.
2542 */
2543 pr_debug("!a_bus_req\n");
2544 msm_otg_del_timer(motg);
Steve Mucklef132c6c2012-06-06 18:30:57 -07002545 otg->phy->state = OTG_STATE_A_SUSPEND;
Vijayavardhan Vennapusaa3152032012-03-05 16:29:30 +05302546 if (otg->host->b_hnp_enable)
2547 msm_otg_start_timer(motg, TA_AIDL_BDIS,
2548 A_AIDL_BDIS);
2549 else
Steve Mucklef132c6c2012-06-06 18:30:57 -07002550 pm_runtime_put_sync(otg->phy->dev);
Vijayavardhan Vennapusaa3152032012-03-05 16:29:30 +05302551 } else if (!test_bit(B_CONN, &motg->inputs)) {
2552 pr_debug("!b_conn\n");
2553 msm_otg_del_timer(motg);
Steve Mucklef132c6c2012-06-06 18:30:57 -07002554 otg->phy->state = OTG_STATE_A_WAIT_BCON;
Vijayavardhan Vennapusaa3152032012-03-05 16:29:30 +05302555 if (TA_WAIT_BCON > 0)
2556 msm_otg_start_timer(motg, TA_WAIT_BCON,
2557 A_WAIT_BCON);
2558 if (msm_chg_check_aca_intr(motg))
2559 work = 1;
2560 } else if (test_bit(ID_A, &motg->inputs)) {
2561 msm_otg_del_timer(motg);
2562 msm_hsusb_vbus_power(motg, 0);
2563 if (motg->chg_type == USB_ACA_DOCK_CHARGER)
2564 msm_otg_notify_charger(motg,
2565 IDEV_ACA_CHG_MAX);
2566 else
2567 msm_otg_notify_charger(motg,
2568 IDEV_CHG_MIN - motg->mA_port);
2569 } else if (!test_bit(ID, &motg->inputs)) {
2570 motg->chg_state = USB_CHG_STATE_UNDEFINED;
2571 motg->chg_type = USB_INVALID_CHARGER;
2572 msm_otg_notify_charger(motg, 0);
2573 msm_hsusb_vbus_power(motg, 1);
2574 }
2575 break;
2576 case OTG_STATE_A_SUSPEND:
2577 if ((test_bit(ID, &motg->inputs) &&
2578 !test_bit(ID_A, &motg->inputs)) ||
2579 test_bit(A_BUS_DROP, &motg->inputs) ||
2580 test_bit(A_AIDL_BDIS, &motg->tmouts)) {
2581 pr_debug("id_a/b/c || a_bus_drop ||"
2582 "a_aidl_bdis_tmout\n");
2583 msm_otg_del_timer(motg);
2584 clear_bit(B_CONN, &motg->inputs);
Steve Mucklef132c6c2012-06-06 18:30:57 -07002585 otg->phy->state = OTG_STATE_A_WAIT_VFALL;
Vijayavardhan Vennapusaa3152032012-03-05 16:29:30 +05302586 msm_otg_start_host(otg, 0);
Steve Mucklef132c6c2012-06-06 18:30:57 -07002587 msm_otg_reset(otg->phy);
Vijayavardhan Vennapusaa3152032012-03-05 16:29:30 +05302588 if (!test_bit(ID_A, &motg->inputs))
2589 msm_hsusb_vbus_power(motg, 0);
2590 msm_otg_start_timer(motg, TA_WAIT_VFALL, A_WAIT_VFALL);
2591 } else if (!test_bit(A_VBUS_VLD, &motg->inputs)) {
2592 pr_debug("!a_vbus_vld\n");
2593 msm_otg_del_timer(motg);
2594 clear_bit(B_CONN, &motg->inputs);
Steve Mucklef132c6c2012-06-06 18:30:57 -07002595 otg->phy->state = OTG_STATE_A_VBUS_ERR;
Vijayavardhan Vennapusaa3152032012-03-05 16:29:30 +05302596 msm_otg_start_host(otg, 0);
Steve Mucklef132c6c2012-06-06 18:30:57 -07002597 msm_otg_reset(otg->phy);
Vijayavardhan Vennapusaa3152032012-03-05 16:29:30 +05302598 } else if (!test_bit(B_CONN, &motg->inputs) &&
2599 otg->host->b_hnp_enable) {
2600 pr_debug("!b_conn && b_hnp_enable");
Steve Mucklef132c6c2012-06-06 18:30:57 -07002601 otg->phy->state = OTG_STATE_A_PERIPHERAL;
Vijayavardhan Vennapusaa3152032012-03-05 16:29:30 +05302602 msm_otg_host_hnp_enable(otg, 1);
2603 otg->gadget->is_a_peripheral = 1;
2604 msm_otg_start_peripheral(otg, 1);
2605 } else if (!test_bit(B_CONN, &motg->inputs) &&
2606 !otg->host->b_hnp_enable) {
2607 pr_debug("!b_conn && !b_hnp_enable");
2608 /*
2609 * bus request is dropped during suspend.
2610 * acquire again for next device.
2611 */
2612 set_bit(A_BUS_REQ, &motg->inputs);
Steve Mucklef132c6c2012-06-06 18:30:57 -07002613 otg->phy->state = OTG_STATE_A_WAIT_BCON;
Vijayavardhan Vennapusaa3152032012-03-05 16:29:30 +05302614 if (TA_WAIT_BCON > 0)
2615 msm_otg_start_timer(motg, TA_WAIT_BCON,
2616 A_WAIT_BCON);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002617 } else if (test_bit(ID_A, &motg->inputs)) {
Mayank Ranae3926882011-12-26 09:47:54 +05302618 msm_hsusb_vbus_power(motg, 0);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002619 msm_otg_notify_charger(motg,
Vijayavardhan Vennapusaa3152032012-03-05 16:29:30 +05302620 IDEV_CHG_MIN - motg->mA_port);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002621 } else if (!test_bit(ID, &motg->inputs)) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002622 msm_otg_notify_charger(motg, 0);
Mayank Ranae3926882011-12-26 09:47:54 +05302623 msm_hsusb_vbus_power(motg, 1);
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05302624 }
2625 break;
Vijayavardhan Vennapusaa3152032012-03-05 16:29:30 +05302626 case OTG_STATE_A_PERIPHERAL:
2627 if ((test_bit(ID, &motg->inputs) &&
2628 !test_bit(ID_A, &motg->inputs)) ||
2629 test_bit(A_BUS_DROP, &motg->inputs)) {
2630 pr_debug("id _f/b/c || a_bus_drop\n");
2631 /* Clear BIDL_ADIS timer */
2632 msm_otg_del_timer(motg);
Steve Mucklef132c6c2012-06-06 18:30:57 -07002633 otg->phy->state = OTG_STATE_A_WAIT_VFALL;
Vijayavardhan Vennapusaa3152032012-03-05 16:29:30 +05302634 msm_otg_start_peripheral(otg, 0);
2635 otg->gadget->is_a_peripheral = 0;
2636 msm_otg_start_host(otg, 0);
Steve Mucklef132c6c2012-06-06 18:30:57 -07002637 msm_otg_reset(otg->phy);
Vijayavardhan Vennapusaa3152032012-03-05 16:29:30 +05302638 if (!test_bit(ID_A, &motg->inputs))
2639 msm_hsusb_vbus_power(motg, 0);
2640 msm_otg_start_timer(motg, TA_WAIT_VFALL, A_WAIT_VFALL);
2641 } else if (!test_bit(A_VBUS_VLD, &motg->inputs)) {
2642 pr_debug("!a_vbus_vld\n");
2643 /* Clear BIDL_ADIS timer */
2644 msm_otg_del_timer(motg);
Steve Mucklef132c6c2012-06-06 18:30:57 -07002645 otg->phy->state = OTG_STATE_A_VBUS_ERR;
Vijayavardhan Vennapusaa3152032012-03-05 16:29:30 +05302646 msm_otg_start_peripheral(otg, 0);
2647 otg->gadget->is_a_peripheral = 0;
2648 msm_otg_start_host(otg, 0);
2649 } else if (test_bit(A_BIDL_ADIS, &motg->tmouts)) {
2650 pr_debug("a_bidl_adis_tmout\n");
2651 msm_otg_start_peripheral(otg, 0);
2652 otg->gadget->is_a_peripheral = 0;
Steve Mucklef132c6c2012-06-06 18:30:57 -07002653 otg->phy->state = OTG_STATE_A_WAIT_BCON;
Vijayavardhan Vennapusaa3152032012-03-05 16:29:30 +05302654 set_bit(A_BUS_REQ, &motg->inputs);
2655 msm_otg_host_hnp_enable(otg, 0);
2656 if (TA_WAIT_BCON > 0)
2657 msm_otg_start_timer(motg, TA_WAIT_BCON,
2658 A_WAIT_BCON);
2659 } else if (test_bit(ID_A, &motg->inputs)) {
2660 msm_hsusb_vbus_power(motg, 0);
2661 msm_otg_notify_charger(motg,
2662 IDEV_CHG_MIN - motg->mA_port);
2663 } else if (!test_bit(ID, &motg->inputs)) {
2664 msm_otg_notify_charger(motg, 0);
2665 msm_hsusb_vbus_power(motg, 1);
2666 }
2667 break;
2668 case OTG_STATE_A_WAIT_VFALL:
2669 if (test_bit(A_WAIT_VFALL, &motg->tmouts)) {
2670 clear_bit(A_VBUS_VLD, &motg->inputs);
Steve Mucklef132c6c2012-06-06 18:30:57 -07002671 otg->phy->state = OTG_STATE_A_IDLE;
Vijayavardhan Vennapusaa3152032012-03-05 16:29:30 +05302672 work = 1;
2673 }
2674 break;
2675 case OTG_STATE_A_VBUS_ERR:
2676 if ((test_bit(ID, &motg->inputs) &&
2677 !test_bit(ID_A, &motg->inputs)) ||
2678 test_bit(A_BUS_DROP, &motg->inputs) ||
2679 test_bit(A_CLR_ERR, &motg->inputs)) {
Steve Mucklef132c6c2012-06-06 18:30:57 -07002680 otg->phy->state = OTG_STATE_A_WAIT_VFALL;
Vijayavardhan Vennapusaa3152032012-03-05 16:29:30 +05302681 if (!test_bit(ID_A, &motg->inputs))
2682 msm_hsusb_vbus_power(motg, 0);
2683 msm_otg_start_timer(motg, TA_WAIT_VFALL, A_WAIT_VFALL);
2684 motg->chg_state = USB_CHG_STATE_UNDEFINED;
2685 motg->chg_type = USB_INVALID_CHARGER;
2686 msm_otg_notify_charger(motg, 0);
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05302687 }
2688 break;
2689 default:
2690 break;
2691 }
Vijayavardhan Vennapusaa3152032012-03-05 16:29:30 +05302692 if (work)
2693 queue_work(system_nrt_wq, &motg->sm_work);
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05302694}
2695
2696static irqreturn_t msm_otg_irq(int irq, void *data)
2697{
2698 struct msm_otg *motg = data;
Steve Mucklef132c6c2012-06-06 18:30:57 -07002699 struct usb_otg *otg = motg->phy.otg;
Vijayavardhan Vennapusaa3152032012-03-05 16:29:30 +05302700 u32 otgsc = 0, usbsts, pc;
2701 bool work = 0;
2702 irqreturn_t ret = IRQ_HANDLED;
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05302703
Pavankumar Kondeti87c01042010-12-07 17:53:58 +05302704 if (atomic_read(&motg->in_lpm)) {
Pavankumar Kondeti4960f312011-12-06 15:46:14 +05302705 pr_debug("OTG IRQ: in LPM\n");
Pavankumar Kondeti87c01042010-12-07 17:53:58 +05302706 disable_irq_nosync(irq);
2707 motg->async_int = 1;
Jack Pham5ca279b2012-05-14 18:42:54 -07002708 if (atomic_read(&motg->pm_suspended))
2709 motg->sm_work_pending = true;
2710 else
Steve Mucklef132c6c2012-06-06 18:30:57 -07002711 pm_request_resume(otg->phy->dev);
Pavankumar Kondeti87c01042010-12-07 17:53:58 +05302712 return IRQ_HANDLED;
2713 }
2714
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002715 usbsts = readl(USB_USBSTS);
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05302716 otgsc = readl(USB_OTGSC);
Vijayavardhan Vennapusaa3152032012-03-05 16:29:30 +05302717
2718 if (!(otgsc & OTG_OTGSTS_MASK) && !(usbsts & OTG_USBSTS_MASK))
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05302719 return IRQ_NONE;
2720
2721 if ((otgsc & OTGSC_IDIS) && (otgsc & OTGSC_IDIE)) {
Pavankumar Kondetiaa449e12011-11-04 11:09:26 +05302722 if (otgsc & OTGSC_ID) {
Vijayavardhan Vennapusaa3152032012-03-05 16:29:30 +05302723 pr_debug("Id set\n");
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05302724 set_bit(ID, &motg->inputs);
Pavankumar Kondetiaa449e12011-11-04 11:09:26 +05302725 } else {
Vijayavardhan Vennapusaa3152032012-03-05 16:29:30 +05302726 pr_debug("Id clear\n");
2727 /*
2728 * Assert a_bus_req to supply power on
2729 * VBUS when Micro/Mini-A cable is connected
2730 * with out user intervention.
2731 */
2732 set_bit(A_BUS_REQ, &motg->inputs);
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05302733 clear_bit(ID, &motg->inputs);
Pavankumar Kondetiaa449e12011-11-04 11:09:26 +05302734 msm_chg_enable_aca_det(motg);
2735 }
Vijayavardhan Vennapusaa3152032012-03-05 16:29:30 +05302736 writel_relaxed(otgsc, USB_OTGSC);
2737 work = 1;
2738 } else if (otgsc & OTGSC_DPIS) {
2739 pr_debug("DPIS detected\n");
2740 writel_relaxed(otgsc, USB_OTGSC);
2741 set_bit(A_SRP_DET, &motg->inputs);
2742 set_bit(A_BUS_REQ, &motg->inputs);
2743 work = 1;
2744 } else if (otgsc & OTGSC_BSVIS) {
2745 writel_relaxed(otgsc, USB_OTGSC);
2746 /*
2747 * BSV interrupt comes when operating as an A-device
2748 * (VBUS on/off).
2749 * But, handle BSV when charger is removed from ACA in ID_A
2750 */
Steve Mucklef132c6c2012-06-06 18:30:57 -07002751 if ((otg->phy->state >= OTG_STATE_A_IDLE) &&
Vijayavardhan Vennapusaa3152032012-03-05 16:29:30 +05302752 !test_bit(ID_A, &motg->inputs))
2753 return IRQ_HANDLED;
Pavankumar Kondetiaa449e12011-11-04 11:09:26 +05302754 if (otgsc & OTGSC_BSV) {
Vijayavardhan Vennapusaa3152032012-03-05 16:29:30 +05302755 pr_debug("BSV set\n");
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05302756 set_bit(B_SESS_VLD, &motg->inputs);
Pavankumar Kondetiaa449e12011-11-04 11:09:26 +05302757 } else {
Vijayavardhan Vennapusaa3152032012-03-05 16:29:30 +05302758 pr_debug("BSV clear\n");
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05302759 clear_bit(B_SESS_VLD, &motg->inputs);
Amit Blay6fa647a2012-05-24 14:12:08 +03002760 clear_bit(A_BUS_SUSPEND, &motg->inputs);
2761
Pavankumar Kondetiaa449e12011-11-04 11:09:26 +05302762 msm_chg_check_aca_intr(motg);
2763 }
Vijayavardhan Vennapusaa3152032012-03-05 16:29:30 +05302764 work = 1;
2765 } else if (usbsts & STS_PCI) {
2766 pc = readl_relaxed(USB_PORTSC);
2767 pr_debug("portsc = %x\n", pc);
2768 ret = IRQ_NONE;
2769 /*
2770 * HCD Acks PCI interrupt. We use this to switch
2771 * between different OTG states.
2772 */
2773 work = 1;
Steve Mucklef132c6c2012-06-06 18:30:57 -07002774 switch (otg->phy->state) {
Vijayavardhan Vennapusaa3152032012-03-05 16:29:30 +05302775 case OTG_STATE_A_SUSPEND:
2776 if (otg->host->b_hnp_enable && (pc & PORTSC_CSC) &&
2777 !(pc & PORTSC_CCS)) {
2778 pr_debug("B_CONN clear\n");
2779 clear_bit(B_CONN, &motg->inputs);
2780 msm_otg_del_timer(motg);
2781 }
2782 break;
2783 case OTG_STATE_A_PERIPHERAL:
2784 /*
2785 * A-peripheral observed activity on bus.
2786 * clear A_BIDL_ADIS timer.
2787 */
2788 msm_otg_del_timer(motg);
2789 work = 0;
2790 break;
2791 case OTG_STATE_B_WAIT_ACON:
2792 if ((pc & PORTSC_CSC) && (pc & PORTSC_CCS)) {
2793 pr_debug("A_CONN set\n");
2794 set_bit(A_CONN, &motg->inputs);
2795 /* Clear ASE0_BRST timer */
2796 msm_otg_del_timer(motg);
2797 }
2798 break;
2799 case OTG_STATE_B_HOST:
2800 if ((pc & PORTSC_CSC) && !(pc & PORTSC_CCS)) {
2801 pr_debug("A_CONN clear\n");
2802 clear_bit(A_CONN, &motg->inputs);
2803 msm_otg_del_timer(motg);
2804 }
2805 break;
2806 case OTG_STATE_A_WAIT_BCON:
2807 if (TA_WAIT_BCON < 0)
2808 set_bit(A_BUS_REQ, &motg->inputs);
2809 default:
2810 work = 0;
2811 break;
2812 }
2813 } else if (usbsts & STS_URI) {
2814 ret = IRQ_NONE;
Steve Mucklef132c6c2012-06-06 18:30:57 -07002815 switch (otg->phy->state) {
Vijayavardhan Vennapusaa3152032012-03-05 16:29:30 +05302816 case OTG_STATE_A_PERIPHERAL:
2817 /*
2818 * A-peripheral observed activity on bus.
2819 * clear A_BIDL_ADIS timer.
2820 */
2821 msm_otg_del_timer(motg);
2822 work = 0;
2823 break;
2824 default:
2825 work = 0;
2826 break;
2827 }
2828 } else if (usbsts & STS_SLI) {
2829 ret = IRQ_NONE;
2830 work = 0;
Steve Mucklef132c6c2012-06-06 18:30:57 -07002831 switch (otg->phy->state) {
Vijayavardhan Vennapusaa3152032012-03-05 16:29:30 +05302832 case OTG_STATE_B_PERIPHERAL:
2833 if (otg->gadget->b_hnp_enable) {
2834 set_bit(A_BUS_SUSPEND, &motg->inputs);
2835 set_bit(B_BUS_REQ, &motg->inputs);
2836 work = 1;
2837 }
2838 break;
2839 case OTG_STATE_A_PERIPHERAL:
2840 msm_otg_start_timer(motg, TA_BIDL_ADIS,
2841 A_BIDL_ADIS);
2842 break;
2843 default:
2844 break;
2845 }
2846 } else if ((usbsts & PHY_ALT_INT)) {
2847 writel_relaxed(PHY_ALT_INT, USB_USBSTS);
2848 if (msm_chg_check_aca_intr(motg))
2849 work = 1;
2850 ret = IRQ_HANDLED;
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05302851 }
Vijayavardhan Vennapusaa3152032012-03-05 16:29:30 +05302852 if (work)
2853 queue_work(system_nrt_wq, &motg->sm_work);
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05302854
Vijayavardhan Vennapusaa3152032012-03-05 16:29:30 +05302855 return ret;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002856}
2857
2858static void msm_otg_set_vbus_state(int online)
2859{
Pavankumar Kondeti4960f312011-12-06 15:46:14 +05302860 static bool init;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002861 struct msm_otg *motg = the_msm_otg;
Mayank Ranabaf31f42012-07-05 09:43:54 +05302862 struct usb_otg *otg = motg->phy.otg;
2863
2864 /* In A Host Mode, ignore received BSV interrupts */
2865 if (otg->phy->state >= OTG_STATE_A_IDLE)
2866 return;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002867
Pavankumar Kondeti4960f312011-12-06 15:46:14 +05302868 if (online) {
2869 pr_debug("PMIC: BSV set\n");
2870 set_bit(B_SESS_VLD, &motg->inputs);
2871 } else {
2872 pr_debug("PMIC: BSV clear\n");
2873 clear_bit(B_SESS_VLD, &motg->inputs);
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05302874 }
2875
Pavankumar Kondeti4960f312011-12-06 15:46:14 +05302876 if (!init) {
2877 init = true;
2878 complete(&pmic_vbus_init);
2879 pr_debug("PMIC: BSV init complete\n");
2880 return;
2881 }
2882
Pavankumar Kondeti2aec9f32012-06-13 09:06:03 +05302883 if (test_bit(MHL, &motg->inputs) ||
2884 mhl_det_in_progress) {
2885 pr_debug("PMIC: BSV interrupt ignored in MHL\n");
2886 return;
2887 }
2888
Jack Pham5ca279b2012-05-14 18:42:54 -07002889 if (atomic_read(&motg->pm_suspended))
2890 motg->sm_work_pending = true;
2891 else
2892 queue_work(system_nrt_wq, &motg->sm_work);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002893}
2894
Vijayavardhan Vennapusa68d55cf2012-06-27 20:06:12 +05302895static void msm_pmic_id_status_w(struct work_struct *w)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002896{
Vijayavardhan Vennapusa68d55cf2012-06-27 20:06:12 +05302897 struct msm_otg *motg = container_of(w, struct msm_otg,
2898 pmic_id_status_work.work);
2899 int work = 0;
2900 unsigned long flags;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002901
Vijayavardhan Vennapusa68d55cf2012-06-27 20:06:12 +05302902 local_irq_save(flags);
Pavankumar Kondeti4960f312011-12-06 15:46:14 +05302903 if (irq_read_line(motg->pdata->pmic_id_irq)) {
Vijayavardhan Vennapusa68d55cf2012-06-27 20:06:12 +05302904 if (!test_and_set_bit(ID, &motg->inputs)) {
2905 pr_debug("PMIC: ID set\n");
2906 work = 1;
2907 }
Pavankumar Kondeti4960f312011-12-06 15:46:14 +05302908 } else {
Vijayavardhan Vennapusa68d55cf2012-06-27 20:06:12 +05302909 if (test_and_clear_bit(ID, &motg->inputs)) {
2910 pr_debug("PMIC: ID clear\n");
2911 set_bit(A_BUS_REQ, &motg->inputs);
2912 work = 1;
2913 }
Pavankumar Kondeti4960f312011-12-06 15:46:14 +05302914 }
2915
Vijayavardhan Vennapusa68d55cf2012-06-27 20:06:12 +05302916 if (work && (motg->phy.state != OTG_STATE_UNDEFINED)) {
Jack Pham5ca279b2012-05-14 18:42:54 -07002917 if (atomic_read(&motg->pm_suspended))
2918 motg->sm_work_pending = true;
2919 else
2920 queue_work(system_nrt_wq, &motg->sm_work);
2921 }
Vijayavardhan Vennapusa68d55cf2012-06-27 20:06:12 +05302922 local_irq_restore(flags);
2923
2924}
2925
2926#define MSM_PMIC_ID_STATUS_DELAY 5 /* 5msec */
2927static irqreturn_t msm_pmic_id_irq(int irq, void *data)
2928{
2929 struct msm_otg *motg = data;
2930
Pavankumar Kondeti2aec9f32012-06-13 09:06:03 +05302931 if (test_bit(MHL, &motg->inputs) ||
2932 mhl_det_in_progress) {
2933 pr_debug("PMIC: Id interrupt ignored in MHL\n");
2934 return IRQ_HANDLED;
2935 }
2936
Vijayavardhan Vennapusa68d55cf2012-06-27 20:06:12 +05302937 if (!aca_id_turned_on)
2938 /*schedule delayed work for 5msec for ID line state to settle*/
2939 queue_delayed_work(system_nrt_wq, &motg->pmic_id_status_work,
2940 msecs_to_jiffies(MSM_PMIC_ID_STATUS_DELAY));
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002941
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05302942 return IRQ_HANDLED;
2943}
2944
2945static int msm_otg_mode_show(struct seq_file *s, void *unused)
2946{
2947 struct msm_otg *motg = s->private;
Steve Mucklef132c6c2012-06-06 18:30:57 -07002948 struct usb_phy *phy = &motg->phy;
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05302949
Steve Mucklef132c6c2012-06-06 18:30:57 -07002950 switch (phy->state) {
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05302951 case OTG_STATE_A_HOST:
2952 seq_printf(s, "host\n");
2953 break;
2954 case OTG_STATE_B_PERIPHERAL:
2955 seq_printf(s, "peripheral\n");
2956 break;
2957 default:
2958 seq_printf(s, "none\n");
2959 break;
2960 }
2961
2962 return 0;
2963}
2964
2965static int msm_otg_mode_open(struct inode *inode, struct file *file)
2966{
2967 return single_open(file, msm_otg_mode_show, inode->i_private);
2968}
2969
2970static ssize_t msm_otg_mode_write(struct file *file, const char __user *ubuf,
2971 size_t count, loff_t *ppos)
2972{
Pavankumar Kondetie2904ee2011-02-15 09:42:35 +05302973 struct seq_file *s = file->private_data;
2974 struct msm_otg *motg = s->private;
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05302975 char buf[16];
Steve Mucklef132c6c2012-06-06 18:30:57 -07002976 struct usb_phy *phy = &motg->phy;
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05302977 int status = count;
2978 enum usb_mode_type req_mode;
2979
2980 memset(buf, 0x00, sizeof(buf));
2981
2982 if (copy_from_user(&buf, ubuf, min_t(size_t, sizeof(buf) - 1, count))) {
2983 status = -EFAULT;
2984 goto out;
2985 }
2986
2987 if (!strncmp(buf, "host", 4)) {
2988 req_mode = USB_HOST;
2989 } else if (!strncmp(buf, "peripheral", 10)) {
2990 req_mode = USB_PERIPHERAL;
2991 } else if (!strncmp(buf, "none", 4)) {
2992 req_mode = USB_NONE;
2993 } else {
2994 status = -EINVAL;
2995 goto out;
2996 }
2997
2998 switch (req_mode) {
2999 case USB_NONE:
Steve Mucklef132c6c2012-06-06 18:30:57 -07003000 switch (phy->state) {
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05303001 case OTG_STATE_A_HOST:
3002 case OTG_STATE_B_PERIPHERAL:
3003 set_bit(ID, &motg->inputs);
3004 clear_bit(B_SESS_VLD, &motg->inputs);
3005 break;
3006 default:
3007 goto out;
3008 }
3009 break;
3010 case USB_PERIPHERAL:
Steve Mucklef132c6c2012-06-06 18:30:57 -07003011 switch (phy->state) {
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05303012 case OTG_STATE_B_IDLE:
3013 case OTG_STATE_A_HOST:
3014 set_bit(ID, &motg->inputs);
3015 set_bit(B_SESS_VLD, &motg->inputs);
3016 break;
3017 default:
3018 goto out;
3019 }
3020 break;
3021 case USB_HOST:
Steve Mucklef132c6c2012-06-06 18:30:57 -07003022 switch (phy->state) {
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05303023 case OTG_STATE_B_IDLE:
3024 case OTG_STATE_B_PERIPHERAL:
3025 clear_bit(ID, &motg->inputs);
3026 break;
3027 default:
3028 goto out;
3029 }
3030 break;
3031 default:
3032 goto out;
3033 }
3034
Steve Mucklef132c6c2012-06-06 18:30:57 -07003035 pm_runtime_resume(phy->dev);
Vijayavardhan Vennapusaa3152032012-03-05 16:29:30 +05303036 queue_work(system_nrt_wq, &motg->sm_work);
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05303037out:
3038 return status;
3039}
3040
3041const struct file_operations msm_otg_mode_fops = {
3042 .open = msm_otg_mode_open,
3043 .read = seq_read,
3044 .write = msm_otg_mode_write,
3045 .llseek = seq_lseek,
3046 .release = single_release,
3047};
3048
Chiranjeevi Velempatif9a11542012-03-28 18:18:34 +05303049static int msm_otg_show_otg_state(struct seq_file *s, void *unused)
3050{
3051 struct msm_otg *motg = s->private;
Steve Mucklef132c6c2012-06-06 18:30:57 -07003052 struct usb_phy *phy = &motg->phy;
Chiranjeevi Velempatif9a11542012-03-28 18:18:34 +05303053
Steve Mucklef132c6c2012-06-06 18:30:57 -07003054 seq_printf(s, "%s\n", otg_state_string(phy->state));
Chiranjeevi Velempatif9a11542012-03-28 18:18:34 +05303055 return 0;
3056}
3057
3058static int msm_otg_otg_state_open(struct inode *inode, struct file *file)
3059{
3060 return single_open(file, msm_otg_show_otg_state, inode->i_private);
3061}
3062
3063const struct file_operations msm_otg_state_fops = {
3064 .open = msm_otg_otg_state_open,
3065 .read = seq_read,
3066 .llseek = seq_lseek,
3067 .release = single_release,
3068};
3069
Anji jonnalad270e2d2011-08-09 11:28:32 +05303070static int msm_otg_show_chg_type(struct seq_file *s, void *unused)
3071{
3072 struct msm_otg *motg = s->private;
3073
Pavankumar Kondeti9ef69cb2011-12-12 14:18:22 +05303074 seq_printf(s, "%s\n", chg_to_string(motg->chg_type));
Anji jonnalad270e2d2011-08-09 11:28:32 +05303075 return 0;
3076}
3077
3078static int msm_otg_chg_open(struct inode *inode, struct file *file)
3079{
3080 return single_open(file, msm_otg_show_chg_type, inode->i_private);
3081}
3082
3083const struct file_operations msm_otg_chg_fops = {
3084 .open = msm_otg_chg_open,
3085 .read = seq_read,
3086 .llseek = seq_lseek,
3087 .release = single_release,
3088};
3089
Pavankumar Kondetiaa449e12011-11-04 11:09:26 +05303090static int msm_otg_aca_show(struct seq_file *s, void *unused)
3091{
3092 if (debug_aca_enabled)
3093 seq_printf(s, "enabled\n");
3094 else
3095 seq_printf(s, "disabled\n");
3096
3097 return 0;
3098}
3099
3100static int msm_otg_aca_open(struct inode *inode, struct file *file)
3101{
3102 return single_open(file, msm_otg_aca_show, inode->i_private);
3103}
3104
3105static ssize_t msm_otg_aca_write(struct file *file, const char __user *ubuf,
3106 size_t count, loff_t *ppos)
3107{
3108 char buf[8];
3109
3110 memset(buf, 0x00, sizeof(buf));
3111
3112 if (copy_from_user(&buf, ubuf, min_t(size_t, sizeof(buf) - 1, count)))
3113 return -EFAULT;
3114
3115 if (!strncmp(buf, "enable", 6))
3116 debug_aca_enabled = true;
3117 else
3118 debug_aca_enabled = false;
3119
3120 return count;
3121}
3122
3123const struct file_operations msm_otg_aca_fops = {
3124 .open = msm_otg_aca_open,
3125 .read = seq_read,
3126 .write = msm_otg_aca_write,
3127 .llseek = seq_lseek,
3128 .release = single_release,
3129};
3130
Manu Gautam8bdcc592012-03-06 11:26:06 +05303131static int msm_otg_bus_show(struct seq_file *s, void *unused)
3132{
3133 if (debug_bus_voting_enabled)
3134 seq_printf(s, "enabled\n");
3135 else
3136 seq_printf(s, "disabled\n");
3137
3138 return 0;
3139}
3140
3141static int msm_otg_bus_open(struct inode *inode, struct file *file)
3142{
3143 return single_open(file, msm_otg_bus_show, inode->i_private);
3144}
3145
3146static ssize_t msm_otg_bus_write(struct file *file, const char __user *ubuf,
3147 size_t count, loff_t *ppos)
3148{
3149 char buf[8];
3150 int ret;
3151 struct seq_file *s = file->private_data;
3152 struct msm_otg *motg = s->private;
3153
3154 memset(buf, 0x00, sizeof(buf));
3155
3156 if (copy_from_user(&buf, ubuf, min_t(size_t, sizeof(buf) - 1, count)))
3157 return -EFAULT;
3158
3159 if (!strncmp(buf, "enable", 6)) {
3160 /* Do not vote here. Let OTG statemachine decide when to vote */
3161 debug_bus_voting_enabled = true;
3162 } else {
3163 debug_bus_voting_enabled = false;
3164 if (motg->bus_perf_client) {
3165 ret = msm_bus_scale_client_update_request(
3166 motg->bus_perf_client, 0);
3167 if (ret)
Steve Mucklef132c6c2012-06-06 18:30:57 -07003168 dev_err(motg->phy.dev, "%s: Failed to devote "
Manu Gautam8bdcc592012-03-06 11:26:06 +05303169 "for bus bw %d\n", __func__, ret);
3170 }
3171 }
3172
3173 return count;
3174}
3175
3176const struct file_operations msm_otg_bus_fops = {
3177 .open = msm_otg_bus_open,
3178 .read = seq_read,
3179 .write = msm_otg_bus_write,
3180 .llseek = seq_lseek,
3181 .release = single_release,
3182};
3183
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05303184static struct dentry *msm_otg_dbg_root;
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05303185
3186static int msm_otg_debugfs_init(struct msm_otg *motg)
3187{
Manu Gautam8bdcc592012-03-06 11:26:06 +05303188 struct dentry *msm_otg_dentry;
Anji jonnalad270e2d2011-08-09 11:28:32 +05303189
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05303190 msm_otg_dbg_root = debugfs_create_dir("msm_otg", NULL);
3191
3192 if (!msm_otg_dbg_root || IS_ERR(msm_otg_dbg_root))
3193 return -ENODEV;
3194
Anji jonnalad270e2d2011-08-09 11:28:32 +05303195 if (motg->pdata->mode == USB_OTG &&
3196 motg->pdata->otg_control == OTG_USER_CONTROL) {
3197
Manu Gautam8bdcc592012-03-06 11:26:06 +05303198 msm_otg_dentry = debugfs_create_file("mode", S_IRUGO |
Anji jonnalad270e2d2011-08-09 11:28:32 +05303199 S_IWUSR, msm_otg_dbg_root, motg,
3200 &msm_otg_mode_fops);
3201
Manu Gautam8bdcc592012-03-06 11:26:06 +05303202 if (!msm_otg_dentry) {
Anji jonnalad270e2d2011-08-09 11:28:32 +05303203 debugfs_remove(msm_otg_dbg_root);
3204 msm_otg_dbg_root = NULL;
3205 return -ENODEV;
3206 }
3207 }
3208
Manu Gautam8bdcc592012-03-06 11:26:06 +05303209 msm_otg_dentry = debugfs_create_file("chg_type", S_IRUGO,
Anji jonnalad270e2d2011-08-09 11:28:32 +05303210 msm_otg_dbg_root, motg,
3211 &msm_otg_chg_fops);
3212
Manu Gautam8bdcc592012-03-06 11:26:06 +05303213 if (!msm_otg_dentry) {
Pavankumar Kondetiaa449e12011-11-04 11:09:26 +05303214 debugfs_remove_recursive(msm_otg_dbg_root);
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05303215 return -ENODEV;
3216 }
3217
Manu Gautam8bdcc592012-03-06 11:26:06 +05303218 msm_otg_dentry = debugfs_create_file("aca", S_IRUGO | S_IWUSR,
Pavankumar Kondetiaa449e12011-11-04 11:09:26 +05303219 msm_otg_dbg_root, motg,
3220 &msm_otg_aca_fops);
3221
Manu Gautam8bdcc592012-03-06 11:26:06 +05303222 if (!msm_otg_dentry) {
Pavankumar Kondetiaa449e12011-11-04 11:09:26 +05303223 debugfs_remove_recursive(msm_otg_dbg_root);
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05303224 return -ENODEV;
3225 }
3226
Manu Gautam8bdcc592012-03-06 11:26:06 +05303227 msm_otg_dentry = debugfs_create_file("bus_voting", S_IRUGO | S_IWUSR,
3228 msm_otg_dbg_root, motg,
3229 &msm_otg_bus_fops);
3230
3231 if (!msm_otg_dentry) {
3232 debugfs_remove_recursive(msm_otg_dbg_root);
3233 return -ENODEV;
3234 }
Chiranjeevi Velempatif9a11542012-03-28 18:18:34 +05303235
3236 msm_otg_dentry = debugfs_create_file("otg_state", S_IRUGO,
3237 msm_otg_dbg_root, motg, &msm_otg_state_fops);
3238
3239 if (!msm_otg_dentry) {
3240 debugfs_remove_recursive(msm_otg_dbg_root);
3241 return -ENODEV;
3242 }
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05303243 return 0;
3244}
3245
3246static void msm_otg_debugfs_cleanup(void)
3247{
Anji jonnalad270e2d2011-08-09 11:28:32 +05303248 debugfs_remove_recursive(msm_otg_dbg_root);
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05303249}
3250
Pavankumar Kondetieaea7fe2011-10-27 14:46:45 +05303251static u64 msm_otg_dma_mask = DMA_BIT_MASK(64);
3252static struct platform_device *msm_otg_add_pdev(
3253 struct platform_device *ofdev, const char *name)
3254{
3255 struct platform_device *pdev;
3256 const struct resource *res = ofdev->resource;
3257 unsigned int num = ofdev->num_resources;
3258 int retval;
3259
3260 pdev = platform_device_alloc(name, -1);
3261 if (!pdev) {
3262 retval = -ENOMEM;
3263 goto error;
3264 }
3265
3266 pdev->dev.coherent_dma_mask = DMA_BIT_MASK(32);
3267 pdev->dev.dma_mask = &msm_otg_dma_mask;
3268
3269 if (num) {
3270 retval = platform_device_add_resources(pdev, res, num);
3271 if (retval)
3272 goto error;
3273 }
3274
3275 retval = platform_device_add(pdev);
3276 if (retval)
3277 goto error;
3278
3279 return pdev;
3280
3281error:
3282 platform_device_put(pdev);
3283 return ERR_PTR(retval);
3284}
3285
3286static int msm_otg_setup_devices(struct platform_device *ofdev,
3287 enum usb_mode_type mode, bool init)
3288{
3289 const char *gadget_name = "msm_hsusb";
3290 const char *host_name = "msm_hsusb_host";
3291 static struct platform_device *gadget_pdev;
3292 static struct platform_device *host_pdev;
3293 int retval = 0;
3294
3295 if (!init) {
3296 if (gadget_pdev)
3297 platform_device_unregister(gadget_pdev);
3298 if (host_pdev)
3299 platform_device_unregister(host_pdev);
3300 return 0;
3301 }
3302
3303 switch (mode) {
3304 case USB_OTG:
3305 /* fall through */
3306 case USB_PERIPHERAL:
3307 gadget_pdev = msm_otg_add_pdev(ofdev, gadget_name);
3308 if (IS_ERR(gadget_pdev)) {
3309 retval = PTR_ERR(gadget_pdev);
3310 break;
3311 }
3312 if (mode == USB_PERIPHERAL)
3313 break;
3314 /* fall through */
3315 case USB_HOST:
3316 host_pdev = msm_otg_add_pdev(ofdev, host_name);
3317 if (IS_ERR(host_pdev)) {
3318 retval = PTR_ERR(host_pdev);
3319 if (mode == USB_OTG)
3320 platform_device_unregister(gadget_pdev);
3321 }
3322 break;
3323 default:
3324 break;
3325 }
3326
3327 return retval;
3328}
3329
3330struct msm_otg_platform_data *msm_otg_dt_to_pdata(struct platform_device *pdev)
3331{
3332 struct device_node *node = pdev->dev.of_node;
3333 struct msm_otg_platform_data *pdata;
3334 int len = 0;
3335
3336 pdata = devm_kzalloc(&pdev->dev, sizeof(*pdata), GFP_KERNEL);
3337 if (!pdata) {
3338 pr_err("unable to allocate platform data\n");
3339 return NULL;
3340 }
3341 of_get_property(node, "qcom,hsusb-otg-phy-init-seq", &len);
3342 if (len) {
3343 pdata->phy_init_seq = devm_kzalloc(&pdev->dev, len, GFP_KERNEL);
3344 if (!pdata->phy_init_seq)
3345 return NULL;
3346 of_property_read_u32_array(node, "qcom,hsusb-otg-phy-init-seq",
3347 pdata->phy_init_seq,
3348 len/sizeof(*pdata->phy_init_seq));
3349 }
3350 of_property_read_u32(node, "qcom,hsusb-otg-power-budget",
3351 &pdata->power_budget);
3352 of_property_read_u32(node, "qcom,hsusb-otg-mode",
3353 &pdata->mode);
3354 of_property_read_u32(node, "qcom,hsusb-otg-otg-control",
3355 &pdata->otg_control);
3356 of_property_read_u32(node, "qcom,hsusb-otg-default-mode",
3357 &pdata->default_mode);
3358 of_property_read_u32(node, "qcom,hsusb-otg-phy-type",
3359 &pdata->phy_type);
3360 of_property_read_u32(node, "qcom,hsusb-otg-pmic-id-irq",
3361 &pdata->pmic_id_irq);
Pavankumar Kondetieaea7fe2011-10-27 14:46:45 +05303362 return pdata;
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05303363}
3364
3365static int __init msm_otg_probe(struct platform_device *pdev)
3366{
3367 int ret = 0;
3368 struct resource *res;
3369 struct msm_otg *motg;
Heikki Krogerus1d4c9292012-02-13 13:24:09 +02003370 struct usb_phy *phy;
Pavankumar Kondetieaea7fe2011-10-27 14:46:45 +05303371 struct msm_otg_platform_data *pdata;
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05303372
3373 dev_info(&pdev->dev, "msm_otg probe\n");
Pavankumar Kondetieaea7fe2011-10-27 14:46:45 +05303374
3375 if (pdev->dev.of_node) {
3376 dev_dbg(&pdev->dev, "device tree enabled\n");
3377 pdata = msm_otg_dt_to_pdata(pdev);
3378 if (!pdata)
3379 return -ENOMEM;
3380 ret = msm_otg_setup_devices(pdev, pdata->mode, true);
3381 if (ret) {
3382 dev_err(&pdev->dev, "devices setup failed\n");
3383 return ret;
3384 }
3385 } else if (!pdev->dev.platform_data) {
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05303386 dev_err(&pdev->dev, "No platform data given. Bailing out\n");
3387 return -ENODEV;
Pavankumar Kondetieaea7fe2011-10-27 14:46:45 +05303388 } else {
3389 pdata = pdev->dev.platform_data;
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05303390 }
3391
3392 motg = kzalloc(sizeof(struct msm_otg), GFP_KERNEL);
3393 if (!motg) {
3394 dev_err(&pdev->dev, "unable to allocate msm_otg\n");
3395 return -ENOMEM;
3396 }
3397
Heikki Krogerus1d4c9292012-02-13 13:24:09 +02003398 motg->phy.otg = kzalloc(sizeof(struct usb_otg), GFP_KERNEL);
3399 if (!motg->phy.otg) {
Steve Mucklef132c6c2012-06-06 18:30:57 -07003400 dev_err(&pdev->dev, "unable to allocate usb_otg\n");
3401 ret = -ENOMEM;
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05303402 goto free_motg;
3403 }
3404
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003405 the_msm_otg = motg;
Pavankumar Kondetieaea7fe2011-10-27 14:46:45 +05303406 motg->pdata = pdata;
Steve Mucklef132c6c2012-06-06 18:30:57 -07003407 phy = &motg->phy;
3408 phy->dev = &pdev->dev;
Anji jonnala0f73cac2011-05-04 10:19:46 +05303409
3410 /*
Pavankumar Kondetiaa449e12011-11-04 11:09:26 +05303411 * ACA ID_GND threshold range is overlapped with OTG ID_FLOAT. Hence
3412 * PHY treat ACA ID_GND as float and no interrupt is generated. But
3413 * PMIC can detect ACA ID_GND and generate an interrupt.
3414 */
3415 if (aca_enabled() && motg->pdata->otg_control != OTG_PMIC_CONTROL) {
3416 dev_err(&pdev->dev, "ACA can not be enabled without PMIC\n");
3417 ret = -EINVAL;
Steve Mucklef132c6c2012-06-06 18:30:57 -07003418 goto free_otg;
Pavankumar Kondetiaa449e12011-11-04 11:09:26 +05303419 }
3420
Ofir Cohen4da266f2012-01-03 10:19:29 +02003421 /* initialize reset counter */
3422 motg->reset_counter = 0;
3423
Amit Blay02eff132011-09-21 16:46:24 +03003424 /* Some targets don't support PHY clock. */
Manu Gautam5143b252012-01-05 19:25:23 -08003425 motg->phy_reset_clk = clk_get(&pdev->dev, "phy_clk");
Amit Blay02eff132011-09-21 16:46:24 +03003426 if (IS_ERR(motg->phy_reset_clk))
Manu Gautam5143b252012-01-05 19:25:23 -08003427 dev_err(&pdev->dev, "failed to get phy_clk\n");
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05303428
Pavankumar Kondeti923262e2012-04-20 15:34:24 +05303429 /*
3430 * Targets on which link uses asynchronous reset methodology,
3431 * free running clock is not required during the reset.
3432 */
Manu Gautam5143b252012-01-05 19:25:23 -08003433 motg->clk = clk_get(&pdev->dev, "alt_core_clk");
Pavankumar Kondeti923262e2012-04-20 15:34:24 +05303434 if (IS_ERR(motg->clk))
3435 dev_dbg(&pdev->dev, "alt_core_clk is not present\n");
3436 else
3437 clk_set_rate(motg->clk, 60000000);
Anji jonnala0f73cac2011-05-04 10:19:46 +05303438
3439 /*
Manu Gautam5143b252012-01-05 19:25:23 -08003440 * USB Core is running its protocol engine based on CORE CLK,
Anji jonnala0f73cac2011-05-04 10:19:46 +05303441 * CORE CLK must be running at >55Mhz for correct HSUSB
3442 * operation and USB core cannot tolerate frequency changes on
3443 * CORE CLK. For such USB cores, vote for maximum clk frequency
3444 * on pclk source
3445 */
Manu Gautam5143b252012-01-05 19:25:23 -08003446 motg->core_clk = clk_get(&pdev->dev, "core_clk");
3447 if (IS_ERR(motg->core_clk)) {
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05303448 motg->core_clk = NULL;
Manu Gautam5143b252012-01-05 19:25:23 -08003449 dev_err(&pdev->dev, "failed to get core_clk\n");
Pavankumar Kondetibc541332012-04-20 15:32:04 +05303450 ret = PTR_ERR(motg->core_clk);
Manu Gautam5143b252012-01-05 19:25:23 -08003451 goto put_clk;
3452 }
3453 clk_set_rate(motg->core_clk, INT_MAX);
3454
3455 motg->pclk = clk_get(&pdev->dev, "iface_clk");
3456 if (IS_ERR(motg->pclk)) {
3457 dev_err(&pdev->dev, "failed to get iface_clk\n");
3458 ret = PTR_ERR(motg->pclk);
3459 goto put_core_clk;
3460 }
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05303461
3462 res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
3463 if (!res) {
3464 dev_err(&pdev->dev, "failed to get platform resource mem\n");
3465 ret = -ENODEV;
Manu Gautam5143b252012-01-05 19:25:23 -08003466 goto put_pclk;
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05303467 }
3468
3469 motg->regs = ioremap(res->start, resource_size(res));
3470 if (!motg->regs) {
3471 dev_err(&pdev->dev, "ioremap failed\n");
3472 ret = -ENOMEM;
Manu Gautam5143b252012-01-05 19:25:23 -08003473 goto put_pclk;
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05303474 }
3475 dev_info(&pdev->dev, "OTG regs = %p\n", motg->regs);
3476
3477 motg->irq = platform_get_irq(pdev, 0);
3478 if (!motg->irq) {
3479 dev_err(&pdev->dev, "platform_get_irq failed\n");
3480 ret = -ENODEV;
3481 goto free_regs;
3482 }
3483
Stephen Boyd30ad10b2012-03-01 14:51:04 -08003484 motg->xo_handle = msm_xo_get(MSM_XO_TCXO_D0, "usb");
Anji jonnala7da3f262011-12-02 17:22:14 -08003485 if (IS_ERR(motg->xo_handle)) {
3486 dev_err(&pdev->dev, "%s not able to get the handle "
3487 "to vote for TCXO D0 buffer\n", __func__);
3488 ret = PTR_ERR(motg->xo_handle);
3489 goto free_regs;
3490 }
Anji jonnala11aa5c42011-05-04 10:19:48 +05303491
Stephen Boyd30ad10b2012-03-01 14:51:04 -08003492 ret = msm_xo_mode_vote(motg->xo_handle, MSM_XO_MODE_ON);
Anji jonnala7da3f262011-12-02 17:22:14 -08003493 if (ret) {
3494 dev_err(&pdev->dev, "%s failed to vote for TCXO "
3495 "D0 buffer%d\n", __func__, ret);
3496 goto free_xo_handle;
3497 }
3498
Manu Gautam28b1bac2012-01-30 16:43:06 +05303499 clk_prepare_enable(motg->pclk);
Anji jonnala11aa5c42011-05-04 10:19:48 +05303500
Mayank Rana248698c2012-04-19 00:03:16 +05303501 motg->vdd_type = VDDCX_CORNER;
Steve Mucklef132c6c2012-06-06 18:30:57 -07003502 hsusb_vddcx = devm_regulator_get(motg->phy.dev, "hsusb_vdd_dig");
Mayank Rana248698c2012-04-19 00:03:16 +05303503 if (IS_ERR(hsusb_vddcx)) {
Steve Mucklef132c6c2012-06-06 18:30:57 -07003504 hsusb_vddcx = devm_regulator_get(motg->phy.dev, "HSUSB_VDDCX");
Mayank Rana248698c2012-04-19 00:03:16 +05303505 if (IS_ERR(hsusb_vddcx)) {
Steve Mucklef132c6c2012-06-06 18:30:57 -07003506 dev_err(motg->phy.dev, "unable to get hsusb vddcx\n");
Mayank Rana248698c2012-04-19 00:03:16 +05303507 goto devote_xo_handle;
3508 }
3509 motg->vdd_type = VDDCX;
Anji jonnala11aa5c42011-05-04 10:19:48 +05303510 }
3511
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003512 ret = msm_hsusb_config_vddcx(1);
Anji jonnala11aa5c42011-05-04 10:19:48 +05303513 if (ret) {
3514 dev_err(&pdev->dev, "hsusb vddcx configuration failed\n");
Mayank Rana248698c2012-04-19 00:03:16 +05303515 goto devote_xo_handle;
3516 }
3517
3518 ret = regulator_enable(hsusb_vddcx);
3519 if (ret) {
3520 dev_err(&pdev->dev, "unable to enable the hsusb vddcx\n");
3521 goto free_config_vddcx;
Anji jonnala11aa5c42011-05-04 10:19:48 +05303522 }
3523
3524 ret = msm_hsusb_ldo_init(motg, 1);
3525 if (ret) {
3526 dev_err(&pdev->dev, "hsusb vreg configuration failed\n");
Mayank Rana248698c2012-04-19 00:03:16 +05303527 goto free_hsusb_vddcx;
Anji jonnala11aa5c42011-05-04 10:19:48 +05303528 }
3529
Mayank Rana9e9a2ac2012-03-24 04:05:28 +05303530 if (pdata->mhl_enable) {
Pavankumar Kondeti56dc7422012-07-02 12:45:19 +05303531 mhl_usb_hs_switch = devm_regulator_get(motg->phy.dev,
3532 "mhl_usb_hs_switch");
3533 if (IS_ERR(mhl_usb_hs_switch)) {
3534 dev_err(&pdev->dev, "Unable to get mhl_usb_hs_switch\n");
Mayank Rana9e9a2ac2012-03-24 04:05:28 +05303535 goto free_ldo_init;
3536 }
3537 }
3538
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003539 ret = msm_hsusb_ldo_enable(motg, 1);
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05303540 if (ret) {
3541 dev_err(&pdev->dev, "hsusb vreg enable failed\n");
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003542 goto free_ldo_init;
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05303543 }
Manu Gautam28b1bac2012-01-30 16:43:06 +05303544 clk_prepare_enable(motg->core_clk);
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05303545
3546 writel(0, USB_USBINTR);
3547 writel(0, USB_OTGSC);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003548 /* Ensure that above STOREs are completed before enabling interrupts */
3549 mb();
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05303550
Pavankumar Kondeti2aec9f32012-06-13 09:06:03 +05303551 ret = msm_otg_mhl_register_callback(motg, msm_otg_mhl_notify_online);
3552 if (ret)
3553 dev_dbg(&pdev->dev, "MHL can not be supported\n");
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003554 wake_lock_init(&motg->wlock, WAKE_LOCK_SUSPEND, "msm_otg");
Vijayavardhan Vennapusaa3152032012-03-05 16:29:30 +05303555 msm_otg_init_timer(motg);
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05303556 INIT_WORK(&motg->sm_work, msm_otg_sm_work);
Pavankumar Kondetid8608522011-05-04 10:19:47 +05303557 INIT_DELAYED_WORK(&motg->chg_work, msm_chg_detect_work);
Vijayavardhan Vennapusa68d55cf2012-06-27 20:06:12 +05303558 INIT_DELAYED_WORK(&motg->pmic_id_status_work, msm_pmic_id_status_w);
Pavankumar Kondetiaa449e12011-11-04 11:09:26 +05303559 setup_timer(&motg->id_timer, msm_otg_id_timer_func,
3560 (unsigned long) motg);
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05303561 ret = request_irq(motg->irq, msm_otg_irq, IRQF_SHARED,
3562 "msm_otg", motg);
3563 if (ret) {
3564 dev_err(&pdev->dev, "request irq failed\n");
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003565 goto destroy_wlock;
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05303566 }
3567
Heikki Krogerus1d4c9292012-02-13 13:24:09 +02003568 phy->init = msm_otg_reset;
3569 phy->set_power = msm_otg_set_power;
Steve Mucklef132c6c2012-06-06 18:30:57 -07003570 phy->set_suspend = msm_otg_set_suspend;
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05303571
Heikki Krogerus1d4c9292012-02-13 13:24:09 +02003572 phy->io_ops = &msm_otg_io_ops;
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05303573
Heikki Krogerus1d4c9292012-02-13 13:24:09 +02003574 phy->otg->phy = &motg->phy;
3575 phy->otg->set_host = msm_otg_set_host;
3576 phy->otg->set_peripheral = msm_otg_set_peripheral;
Steve Mucklef132c6c2012-06-06 18:30:57 -07003577 phy->otg->start_hnp = msm_otg_start_hnp;
3578 phy->otg->start_srp = msm_otg_start_srp;
Heikki Krogerus1d4c9292012-02-13 13:24:09 +02003579
3580 ret = usb_set_transceiver(&motg->phy);
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05303581 if (ret) {
Heikki Krogerus1d4c9292012-02-13 13:24:09 +02003582 dev_err(&pdev->dev, "usb_set_transceiver failed\n");
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05303583 goto free_irq;
3584 }
3585
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05303586 if (motg->pdata->mode == USB_OTG &&
Pavankumar Kondeti0d81f312012-01-13 11:34:10 +05303587 motg->pdata->otg_control == OTG_PMIC_CONTROL) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003588 if (motg->pdata->pmic_id_irq) {
3589 ret = request_irq(motg->pdata->pmic_id_irq,
3590 msm_pmic_id_irq,
3591 IRQF_TRIGGER_RISING |
3592 IRQF_TRIGGER_FALLING,
3593 "msm_otg", motg);
3594 if (ret) {
3595 dev_err(&pdev->dev, "request irq failed for PMIC ID\n");
Steve Mucklef132c6c2012-06-06 18:30:57 -07003596 goto remove_phy;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003597 }
3598 } else {
3599 ret = -ENODEV;
3600 dev_err(&pdev->dev, "PMIC IRQ for ID notifications doesn't exist\n");
Steve Mucklef132c6c2012-06-06 18:30:57 -07003601 goto remove_phy;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003602 }
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05303603 }
3604
Vijayavardhan Vennapusafc464f02011-11-04 21:54:00 +05303605 msm_hsusb_mhl_switch_enable(motg, 1);
3606
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05303607 platform_set_drvdata(pdev, motg);
3608 device_init_wakeup(&pdev->dev, 1);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003609 motg->mA_port = IUNIT;
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05303610
Anji jonnalad270e2d2011-08-09 11:28:32 +05303611 ret = msm_otg_debugfs_init(motg);
3612 if (ret)
3613 dev_dbg(&pdev->dev, "mode debugfs file is"
3614 "not available\n");
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05303615
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003616 if (motg->pdata->otg_control == OTG_PMIC_CONTROL)
3617 pm8921_charger_register_vbus_sn(&msm_otg_set_vbus_state);
3618
Amit Blay58b31472011-11-18 09:39:39 +02003619 if (motg->pdata->phy_type == SNPS_28NM_INTEGRATED_PHY) {
3620 if (motg->pdata->otg_control == OTG_PMIC_CONTROL &&
Pavankumar Kondeti0d81f312012-01-13 11:34:10 +05303621 (!(motg->pdata->mode == USB_OTG) ||
3622 motg->pdata->pmic_id_irq))
Amit Blay58b31472011-11-18 09:39:39 +02003623 motg->caps = ALLOW_PHY_POWER_COLLAPSE |
Vijayavardhan Vennapusa03171c72012-04-26 14:44:48 +05303624 ALLOW_PHY_RETENTION;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003625
Amit Blay58b31472011-11-18 09:39:39 +02003626 if (motg->pdata->otg_control == OTG_PHY_CONTROL)
3627 motg->caps = ALLOW_PHY_RETENTION;
3628 }
3629
Amit Blay6fa647a2012-05-24 14:12:08 +03003630 if (motg->pdata->enable_lpm_on_dev_suspend)
3631 motg->caps |= ALLOW_LPM_ON_DEV_SUSPEND;
3632
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003633 wake_lock(&motg->wlock);
Pavankumar Kondeti87c01042010-12-07 17:53:58 +05303634 pm_runtime_set_active(&pdev->dev);
3635 pm_runtime_enable(&pdev->dev);
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05303636
Manu Gautamcd82e9d2011-12-20 14:17:28 +05303637 if (motg->pdata->bus_scale_table) {
3638 motg->bus_perf_client =
3639 msm_bus_scale_register_client(motg->pdata->bus_scale_table);
3640 if (!motg->bus_perf_client)
Steve Mucklef132c6c2012-06-06 18:30:57 -07003641 dev_err(motg->phy.dev, "%s: Failed to register BUS "
Manu Gautamcd82e9d2011-12-20 14:17:28 +05303642 "scaling client!!\n", __func__);
Manu Gautam8bdcc592012-03-06 11:26:06 +05303643 else
3644 debug_bus_voting_enabled = true;
Manu Gautamcd82e9d2011-12-20 14:17:28 +05303645 }
3646
Pavankumar Kondeti87c01042010-12-07 17:53:58 +05303647 return 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003648
Steve Mucklef132c6c2012-06-06 18:30:57 -07003649remove_phy:
3650 usb_set_transceiver(NULL);
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05303651free_irq:
3652 free_irq(motg->irq, motg);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003653destroy_wlock:
3654 wake_lock_destroy(&motg->wlock);
Manu Gautam28b1bac2012-01-30 16:43:06 +05303655 clk_disable_unprepare(motg->core_clk);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003656 msm_hsusb_ldo_enable(motg, 0);
3657free_ldo_init:
Anji jonnala11aa5c42011-05-04 10:19:48 +05303658 msm_hsusb_ldo_init(motg, 0);
Mayank Rana248698c2012-04-19 00:03:16 +05303659free_hsusb_vddcx:
3660 regulator_disable(hsusb_vddcx);
3661free_config_vddcx:
3662 regulator_set_voltage(hsusb_vddcx,
3663 vdd_val[motg->vdd_type][VDD_NONE],
3664 vdd_val[motg->vdd_type][VDD_MAX]);
Anji jonnala7da3f262011-12-02 17:22:14 -08003665devote_xo_handle:
Manu Gautam28b1bac2012-01-30 16:43:06 +05303666 clk_disable_unprepare(motg->pclk);
Stephen Boyd30ad10b2012-03-01 14:51:04 -08003667 msm_xo_mode_vote(motg->xo_handle, MSM_XO_MODE_OFF);
Anji jonnala7da3f262011-12-02 17:22:14 -08003668free_xo_handle:
Stephen Boyd30ad10b2012-03-01 14:51:04 -08003669 msm_xo_put(motg->xo_handle);
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05303670free_regs:
3671 iounmap(motg->regs);
Manu Gautam5143b252012-01-05 19:25:23 -08003672put_pclk:
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05303673 clk_put(motg->pclk);
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05303674put_core_clk:
Manu Gautam5143b252012-01-05 19:25:23 -08003675 clk_put(motg->core_clk);
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05303676put_clk:
Pavankumar Kondeti923262e2012-04-20 15:34:24 +05303677 if (!IS_ERR(motg->clk))
3678 clk_put(motg->clk);
Amit Blay02eff132011-09-21 16:46:24 +03003679 if (!IS_ERR(motg->phy_reset_clk))
3680 clk_put(motg->phy_reset_clk);
Steve Mucklef132c6c2012-06-06 18:30:57 -07003681free_otg:
Heikki Krogerus1d4c9292012-02-13 13:24:09 +02003682 kfree(motg->phy.otg);
Pavankumar Kondetiaa449e12011-11-04 11:09:26 +05303683free_motg:
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05303684 kfree(motg);
3685 return ret;
3686}
3687
3688static int __devexit msm_otg_remove(struct platform_device *pdev)
3689{
3690 struct msm_otg *motg = platform_get_drvdata(pdev);
Steve Mucklef132c6c2012-06-06 18:30:57 -07003691 struct usb_otg *otg = motg->phy.otg;
Pavankumar Kondeti87c01042010-12-07 17:53:58 +05303692 int cnt = 0;
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05303693
3694 if (otg->host || otg->gadget)
3695 return -EBUSY;
3696
Pavankumar Kondetieaea7fe2011-10-27 14:46:45 +05303697 if (pdev->dev.of_node)
3698 msm_otg_setup_devices(pdev, motg->pdata->mode, false);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003699 if (motg->pdata->otg_control == OTG_PMIC_CONTROL)
3700 pm8921_charger_unregister_vbus_sn(0);
Pavankumar Kondeti2aec9f32012-06-13 09:06:03 +05303701 msm_otg_mhl_register_callback(motg, NULL);
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05303702 msm_otg_debugfs_cleanup();
Pavankumar Kondetid8608522011-05-04 10:19:47 +05303703 cancel_delayed_work_sync(&motg->chg_work);
Vijayavardhan Vennapusa68d55cf2012-06-27 20:06:12 +05303704 cancel_delayed_work_sync(&motg->pmic_id_status_work);
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05303705 cancel_work_sync(&motg->sm_work);
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05303706
Pavankumar Kondeti70187732011-02-15 09:42:34 +05303707 pm_runtime_resume(&pdev->dev);
Pavankumar Kondeti87c01042010-12-07 17:53:58 +05303708
3709 device_init_wakeup(&pdev->dev, 0);
3710 pm_runtime_disable(&pdev->dev);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003711 wake_lock_destroy(&motg->wlock);
Pavankumar Kondeti87c01042010-12-07 17:53:58 +05303712
Vijayavardhan Vennapusafc464f02011-11-04 21:54:00 +05303713 msm_hsusb_mhl_switch_enable(motg, 0);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003714 if (motg->pdata->pmic_id_irq)
3715 free_irq(motg->pdata->pmic_id_irq, motg);
Heikki Krogerus1d4c9292012-02-13 13:24:09 +02003716 usb_set_transceiver(NULL);
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05303717 free_irq(motg->irq, motg);
3718
Pavankumar Kondeti87c01042010-12-07 17:53:58 +05303719 /*
3720 * Put PHY in low power mode.
3721 */
Steve Mucklef132c6c2012-06-06 18:30:57 -07003722 ulpi_read(otg->phy, 0x14);
3723 ulpi_write(otg->phy, 0x08, 0x09);
Pavankumar Kondeti87c01042010-12-07 17:53:58 +05303724
3725 writel(readl(USB_PORTSC) | PORTSC_PHCD, USB_PORTSC);
3726 while (cnt < PHY_SUSPEND_TIMEOUT_USEC) {
3727 if (readl(USB_PORTSC) & PORTSC_PHCD)
3728 break;
3729 udelay(1);
3730 cnt++;
3731 }
3732 if (cnt >= PHY_SUSPEND_TIMEOUT_USEC)
Steve Mucklef132c6c2012-06-06 18:30:57 -07003733 dev_err(otg->phy->dev, "Unable to suspend PHY\n");
Pavankumar Kondeti87c01042010-12-07 17:53:58 +05303734
Manu Gautam28b1bac2012-01-30 16:43:06 +05303735 clk_disable_unprepare(motg->pclk);
3736 clk_disable_unprepare(motg->core_clk);
Stephen Boyd30ad10b2012-03-01 14:51:04 -08003737 msm_xo_put(motg->xo_handle);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003738 msm_hsusb_ldo_enable(motg, 0);
Anji jonnala11aa5c42011-05-04 10:19:48 +05303739 msm_hsusb_ldo_init(motg, 0);
Mayank Rana248698c2012-04-19 00:03:16 +05303740 regulator_disable(hsusb_vddcx);
3741 regulator_set_voltage(hsusb_vddcx,
3742 vdd_val[motg->vdd_type][VDD_NONE],
3743 vdd_val[motg->vdd_type][VDD_MAX]);
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05303744
3745 iounmap(motg->regs);
Pavankumar Kondeti87c01042010-12-07 17:53:58 +05303746 pm_runtime_set_suspended(&pdev->dev);
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05303747
Amit Blay02eff132011-09-21 16:46:24 +03003748 if (!IS_ERR(motg->phy_reset_clk))
3749 clk_put(motg->phy_reset_clk);
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05303750 clk_put(motg->pclk);
Pavankumar Kondeti923262e2012-04-20 15:34:24 +05303751 if (!IS_ERR(motg->clk))
3752 clk_put(motg->clk);
Manu Gautam5143b252012-01-05 19:25:23 -08003753 clk_put(motg->core_clk);
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05303754
Manu Gautamcd82e9d2011-12-20 14:17:28 +05303755 if (motg->bus_perf_client)
3756 msm_bus_scale_unregister_client(motg->bus_perf_client);
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05303757
Heikki Krogerus1d4c9292012-02-13 13:24:09 +02003758 kfree(motg->phy.otg);
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05303759 kfree(motg);
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05303760 return 0;
3761}
3762
Pavankumar Kondeti87c01042010-12-07 17:53:58 +05303763#ifdef CONFIG_PM_RUNTIME
3764static int msm_otg_runtime_idle(struct device *dev)
3765{
3766 struct msm_otg *motg = dev_get_drvdata(dev);
Steve Mucklef132c6c2012-06-06 18:30:57 -07003767 struct usb_phy *phy = &motg->phy;
Pavankumar Kondeti87c01042010-12-07 17:53:58 +05303768
3769 dev_dbg(dev, "OTG runtime idle\n");
3770
Steve Mucklef132c6c2012-06-06 18:30:57 -07003771 if (phy->state == OTG_STATE_UNDEFINED)
Pavankumar Kondeti8be99cf2011-08-04 10:48:08 +05303772 return -EAGAIN;
3773 else
3774 return 0;
Pavankumar Kondeti87c01042010-12-07 17:53:58 +05303775}
3776
3777static int msm_otg_runtime_suspend(struct device *dev)
3778{
3779 struct msm_otg *motg = dev_get_drvdata(dev);
3780
3781 dev_dbg(dev, "OTG runtime suspend\n");
3782 return msm_otg_suspend(motg);
3783}
3784
3785static int msm_otg_runtime_resume(struct device *dev)
3786{
3787 struct msm_otg *motg = dev_get_drvdata(dev);
3788
3789 dev_dbg(dev, "OTG runtime resume\n");
Pavankumar Kondeti8be99cf2011-08-04 10:48:08 +05303790 pm_runtime_get_noresume(dev);
Pavankumar Kondeti87c01042010-12-07 17:53:58 +05303791 return msm_otg_resume(motg);
3792}
Pavankumar Kondeti87c01042010-12-07 17:53:58 +05303793#endif
3794
Pavankumar Kondeti70187732011-02-15 09:42:34 +05303795#ifdef CONFIG_PM_SLEEP
Pavankumar Kondeti87c01042010-12-07 17:53:58 +05303796static int msm_otg_pm_suspend(struct device *dev)
3797{
Jack Pham5ca279b2012-05-14 18:42:54 -07003798 int ret = 0;
Pavankumar Kondeti87c01042010-12-07 17:53:58 +05303799 struct msm_otg *motg = dev_get_drvdata(dev);
3800
3801 dev_dbg(dev, "OTG PM suspend\n");
Jack Pham5ca279b2012-05-14 18:42:54 -07003802
3803 atomic_set(&motg->pm_suspended, 1);
3804 ret = msm_otg_suspend(motg);
3805 if (ret)
3806 atomic_set(&motg->pm_suspended, 0);
3807
3808 return ret;
Pavankumar Kondeti87c01042010-12-07 17:53:58 +05303809}
3810
3811static int msm_otg_pm_resume(struct device *dev)
3812{
Jack Pham5ca279b2012-05-14 18:42:54 -07003813 int ret = 0;
Pavankumar Kondeti87c01042010-12-07 17:53:58 +05303814 struct msm_otg *motg = dev_get_drvdata(dev);
Pavankumar Kondeti87c01042010-12-07 17:53:58 +05303815
3816 dev_dbg(dev, "OTG PM resume\n");
3817
Jack Pham5ca279b2012-05-14 18:42:54 -07003818 atomic_set(&motg->pm_suspended, 0);
3819 if (motg->sm_work_pending) {
3820 motg->sm_work_pending = false;
Pavankumar Kondeti87c01042010-12-07 17:53:58 +05303821
Jack Pham5ca279b2012-05-14 18:42:54 -07003822 pm_runtime_get_noresume(dev);
3823 ret = msm_otg_resume(motg);
Pavankumar Kondeti87c01042010-12-07 17:53:58 +05303824
Jack Pham5ca279b2012-05-14 18:42:54 -07003825 /* Update runtime PM status */
3826 pm_runtime_disable(dev);
3827 pm_runtime_set_active(dev);
3828 pm_runtime_enable(dev);
3829
3830 queue_work(system_nrt_wq, &motg->sm_work);
3831 }
3832
3833 return ret;
Pavankumar Kondeti87c01042010-12-07 17:53:58 +05303834}
Pavankumar Kondeti87c01042010-12-07 17:53:58 +05303835#endif
3836
Pavankumar Kondeti70187732011-02-15 09:42:34 +05303837#ifdef CONFIG_PM
Pavankumar Kondeti87c01042010-12-07 17:53:58 +05303838static const struct dev_pm_ops msm_otg_dev_pm_ops = {
Pavankumar Kondeti70187732011-02-15 09:42:34 +05303839 SET_SYSTEM_SLEEP_PM_OPS(msm_otg_pm_suspend, msm_otg_pm_resume)
3840 SET_RUNTIME_PM_OPS(msm_otg_runtime_suspend, msm_otg_runtime_resume,
3841 msm_otg_runtime_idle)
Pavankumar Kondeti87c01042010-12-07 17:53:58 +05303842};
Pavankumar Kondeti70187732011-02-15 09:42:34 +05303843#endif
Pavankumar Kondeti87c01042010-12-07 17:53:58 +05303844
Pavankumar Kondetieaea7fe2011-10-27 14:46:45 +05303845static struct of_device_id msm_otg_dt_match[] = {
3846 { .compatible = "qcom,hsusb-otg",
3847 },
3848 {}
3849};
3850
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05303851static struct platform_driver msm_otg_driver = {
3852 .remove = __devexit_p(msm_otg_remove),
3853 .driver = {
3854 .name = DRIVER_NAME,
3855 .owner = THIS_MODULE,
Pavankumar Kondeti70187732011-02-15 09:42:34 +05303856#ifdef CONFIG_PM
Pavankumar Kondeti87c01042010-12-07 17:53:58 +05303857 .pm = &msm_otg_dev_pm_ops,
Pavankumar Kondeti70187732011-02-15 09:42:34 +05303858#endif
Pavankumar Kondetieaea7fe2011-10-27 14:46:45 +05303859 .of_match_table = msm_otg_dt_match,
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05303860 },
3861};
3862
3863static int __init msm_otg_init(void)
3864{
3865 return platform_driver_probe(&msm_otg_driver, msm_otg_probe);
3866}
3867
3868static void __exit msm_otg_exit(void)
3869{
3870 platform_driver_unregister(&msm_otg_driver);
3871}
3872
3873module_init(msm_otg_init);
3874module_exit(msm_otg_exit);
3875
3876MODULE_LICENSE("GPL v2");
3877MODULE_DESCRIPTION("MSM USB transceiver driver");