blob: 878f67d29ed54215db952590d1f8d725fa41b939 [file] [log] [blame]
Pavankumar Kondetid8608522011-05-04 10:19:47 +05301/* Copyright (c) 2009-2011, 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 *
12 * You should have received a copy of the GNU General Public License
13 * along with this program; if not, write to the Free Software
14 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
15 * 02110-1301, USA.
16 *
17 */
18
19#include <linux/module.h>
20#include <linux/device.h>
21#include <linux/platform_device.h>
22#include <linux/clk.h>
23#include <linux/slab.h>
24#include <linux/interrupt.h>
25#include <linux/err.h>
26#include <linux/delay.h>
27#include <linux/io.h>
28#include <linux/ioport.h>
29#include <linux/uaccess.h>
30#include <linux/debugfs.h>
31#include <linux/seq_file.h>
Pavankumar Kondeti87c01042010-12-07 17:53:58 +053032#include <linux/pm_runtime.h>
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +053033
34#include <linux/usb.h>
35#include <linux/usb/otg.h>
36#include <linux/usb/ulpi.h>
37#include <linux/usb/gadget.h>
38#include <linux/usb/hcd.h>
39#include <linux/usb/msm_hsusb.h>
40#include <linux/usb/msm_hsusb_hw.h>
Anji jonnala11aa5c42011-05-04 10:19:48 +053041#include <linux/regulator/consumer.h>
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +053042
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +053043#define MSM_USB_BASE (motg->regs)
44#define DRIVER_NAME "msm_otg"
45
46#define ULPI_IO_TIMEOUT_USEC (10 * 1000)
Anji jonnala11aa5c42011-05-04 10:19:48 +053047
48#define USB_PHY_3P3_VOL_MIN 3050000 /* uV */
49#define USB_PHY_3P3_VOL_MAX 3300000 /* uV */
50#define USB_PHY_3P3_HPM_LOAD 50000 /* uA */
51#define USB_PHY_3P3_LPM_LOAD 4000 /* uA */
52
53#define USB_PHY_1P8_VOL_MIN 1800000 /* uV */
54#define USB_PHY_1P8_VOL_MAX 1800000 /* uV */
55#define USB_PHY_1P8_HPM_LOAD 50000 /* uA */
56#define USB_PHY_1P8_LPM_LOAD 4000 /* uA */
57
58#define USB_PHY_VDD_DIG_VOL_MIN 1000000 /* uV */
59#define USB_PHY_VDD_DIG_VOL_MAX 1320000 /* uV */
60
Anji jonnala11aa5c42011-05-04 10:19:48 +053061static int msm_hsusb_init_vddcx(struct msm_otg *motg, int init)
62{
63 int ret = 0;
64
65 if (init) {
Ivan T. Ivanov37cfdaf2014-04-28 16:34:06 +030066 motg->vddcx = regulator_get(motg->phy.dev, "HSUSB_VDDCX");
67 if (IS_ERR(motg->vddcx)) {
Heikki Krogerus1d4c9292012-02-13 13:24:09 +020068 dev_err(motg->phy.dev, "unable to get hsusb vddcx\n");
Ivan T. Ivanov37cfdaf2014-04-28 16:34:06 +030069 return PTR_ERR(motg->vddcx);
Anji jonnala11aa5c42011-05-04 10:19:48 +053070 }
71
Ivan T. Ivanov37cfdaf2014-04-28 16:34:06 +030072 ret = regulator_set_voltage(motg->vddcx,
Anji jonnala11aa5c42011-05-04 10:19:48 +053073 USB_PHY_VDD_DIG_VOL_MIN,
74 USB_PHY_VDD_DIG_VOL_MAX);
75 if (ret) {
Heikki Krogerus1d4c9292012-02-13 13:24:09 +020076 dev_err(motg->phy.dev, "unable to set the voltage "
Anji jonnala11aa5c42011-05-04 10:19:48 +053077 "for hsusb vddcx\n");
Ivan T. Ivanov37cfdaf2014-04-28 16:34:06 +030078 regulator_put(motg->vddcx);
Anji jonnala11aa5c42011-05-04 10:19:48 +053079 return ret;
80 }
81
Ivan T. Ivanov37cfdaf2014-04-28 16:34:06 +030082 ret = regulator_enable(motg->vddcx);
Anji jonnala11aa5c42011-05-04 10:19:48 +053083 if (ret) {
Heikki Krogerus1d4c9292012-02-13 13:24:09 +020084 dev_err(motg->phy.dev, "unable to enable hsusb vddcx\n");
Ivan T. Ivanov37cfdaf2014-04-28 16:34:06 +030085 regulator_put(motg->vddcx);
Anji jonnala11aa5c42011-05-04 10:19:48 +053086 }
87 } else {
Ivan T. Ivanov37cfdaf2014-04-28 16:34:06 +030088 ret = regulator_set_voltage(motg->vddcx, 0,
Mark Brown7b521fc2011-05-15 09:55:57 -070089 USB_PHY_VDD_DIG_VOL_MAX);
Mark Browne99c4302011-05-15 09:55:58 -070090 if (ret)
Heikki Krogerus1d4c9292012-02-13 13:24:09 +020091 dev_err(motg->phy.dev, "unable to set the voltage "
Anji jonnala11aa5c42011-05-04 10:19:48 +053092 "for hsusb vddcx\n");
Ivan T. Ivanov37cfdaf2014-04-28 16:34:06 +030093 ret = regulator_disable(motg->vddcx);
Anji jonnala11aa5c42011-05-04 10:19:48 +053094 if (ret)
Heikki Krogerus1d4c9292012-02-13 13:24:09 +020095 dev_err(motg->phy.dev, "unable to disable hsusb vddcx\n");
Anji jonnala11aa5c42011-05-04 10:19:48 +053096
Ivan T. Ivanov37cfdaf2014-04-28 16:34:06 +030097 regulator_put(motg->vddcx);
Anji jonnala11aa5c42011-05-04 10:19:48 +053098 }
99
100 return ret;
101}
102
103static int msm_hsusb_ldo_init(struct msm_otg *motg, int init)
104{
105 int rc = 0;
106
107 if (init) {
Ivan T. Ivanov37cfdaf2014-04-28 16:34:06 +0300108 motg->v3p3 = regulator_get(motg->phy.dev, "HSUSB_3p3");
109 if (IS_ERR(motg->v3p3)) {
Heikki Krogerus1d4c9292012-02-13 13:24:09 +0200110 dev_err(motg->phy.dev, "unable to get hsusb 3p3\n");
Ivan T. Ivanov37cfdaf2014-04-28 16:34:06 +0300111 return PTR_ERR(motg->v3p3);
Anji jonnala11aa5c42011-05-04 10:19:48 +0530112 }
113
Ivan T. Ivanov37cfdaf2014-04-28 16:34:06 +0300114 rc = regulator_set_voltage(motg->v3p3, USB_PHY_3P3_VOL_MIN,
Anji jonnala11aa5c42011-05-04 10:19:48 +0530115 USB_PHY_3P3_VOL_MAX);
116 if (rc) {
Heikki Krogerus1d4c9292012-02-13 13:24:09 +0200117 dev_err(motg->phy.dev, "unable to set voltage level "
Anji jonnala11aa5c42011-05-04 10:19:48 +0530118 "for hsusb 3p3\n");
119 goto put_3p3;
120 }
Ivan T. Ivanov37cfdaf2014-04-28 16:34:06 +0300121 rc = regulator_enable(motg->v3p3);
Anji jonnala11aa5c42011-05-04 10:19:48 +0530122 if (rc) {
Heikki Krogerus1d4c9292012-02-13 13:24:09 +0200123 dev_err(motg->phy.dev, "unable to enable the hsusb 3p3\n");
Anji jonnala11aa5c42011-05-04 10:19:48 +0530124 goto put_3p3;
125 }
Ivan T. Ivanov37cfdaf2014-04-28 16:34:06 +0300126 motg->v1p8 = regulator_get(motg->phy.dev, "HSUSB_1p8");
127 if (IS_ERR(motg->v1p8)) {
Heikki Krogerus1d4c9292012-02-13 13:24:09 +0200128 dev_err(motg->phy.dev, "unable to get hsusb 1p8\n");
Ivan T. Ivanov37cfdaf2014-04-28 16:34:06 +0300129 rc = PTR_ERR(motg->v1p8);
Anji jonnala11aa5c42011-05-04 10:19:48 +0530130 goto disable_3p3;
131 }
Ivan T. Ivanov37cfdaf2014-04-28 16:34:06 +0300132 rc = regulator_set_voltage(motg->v1p8, USB_PHY_1P8_VOL_MIN,
Anji jonnala11aa5c42011-05-04 10:19:48 +0530133 USB_PHY_1P8_VOL_MAX);
134 if (rc) {
Heikki Krogerus1d4c9292012-02-13 13:24:09 +0200135 dev_err(motg->phy.dev, "unable to set voltage level "
Anji jonnala11aa5c42011-05-04 10:19:48 +0530136 "for hsusb 1p8\n");
137 goto put_1p8;
138 }
Ivan T. Ivanov37cfdaf2014-04-28 16:34:06 +0300139 rc = regulator_enable(motg->v1p8);
Anji jonnala11aa5c42011-05-04 10:19:48 +0530140 if (rc) {
Heikki Krogerus1d4c9292012-02-13 13:24:09 +0200141 dev_err(motg->phy.dev, "unable to enable the hsusb 1p8\n");
Anji jonnala11aa5c42011-05-04 10:19:48 +0530142 goto put_1p8;
143 }
144
145 return 0;
146 }
147
Ivan T. Ivanov37cfdaf2014-04-28 16:34:06 +0300148 regulator_disable(motg->v1p8);
Anji jonnala11aa5c42011-05-04 10:19:48 +0530149put_1p8:
Ivan T. Ivanov37cfdaf2014-04-28 16:34:06 +0300150 regulator_put(motg->v1p8);
Anji jonnala11aa5c42011-05-04 10:19:48 +0530151disable_3p3:
Ivan T. Ivanov37cfdaf2014-04-28 16:34:06 +0300152 regulator_disable(motg->v3p3);
Anji jonnala11aa5c42011-05-04 10:19:48 +0530153put_3p3:
Ivan T. Ivanov37cfdaf2014-04-28 16:34:06 +0300154 regulator_put(motg->v3p3);
Anji jonnala11aa5c42011-05-04 10:19:48 +0530155 return rc;
156}
157
Ivan T. Ivanov37cfdaf2014-04-28 16:34:06 +0300158static int msm_hsusb_ldo_set_mode(struct msm_otg *motg, int on)
Anji jonnala11aa5c42011-05-04 10:19:48 +0530159{
160 int ret = 0;
161
Ivan T. Ivanov37cfdaf2014-04-28 16:34:06 +0300162 if (!motg->v1p8 || IS_ERR(motg->v1p8)) {
Anji jonnala11aa5c42011-05-04 10:19:48 +0530163 pr_err("%s: HSUSB_1p8 is not initialized\n", __func__);
164 return -ENODEV;
165 }
166
Ivan T. Ivanov37cfdaf2014-04-28 16:34:06 +0300167 if (!motg->v3p3 || IS_ERR(motg->v3p3)) {
Anji jonnala11aa5c42011-05-04 10:19:48 +0530168 pr_err("%s: HSUSB_3p3 is not initialized\n", __func__);
169 return -ENODEV;
170 }
171
172 if (on) {
Ivan T. Ivanov37cfdaf2014-04-28 16:34:06 +0300173 ret = regulator_set_optimum_mode(motg->v1p8,
Anji jonnala11aa5c42011-05-04 10:19:48 +0530174 USB_PHY_1P8_HPM_LOAD);
175 if (ret < 0) {
176 pr_err("%s: Unable to set HPM of the regulator "
177 "HSUSB_1p8\n", __func__);
178 return ret;
179 }
Ivan T. Ivanov37cfdaf2014-04-28 16:34:06 +0300180 ret = regulator_set_optimum_mode(motg->v3p3,
Anji jonnala11aa5c42011-05-04 10:19:48 +0530181 USB_PHY_3P3_HPM_LOAD);
182 if (ret < 0) {
183 pr_err("%s: Unable to set HPM of the regulator "
184 "HSUSB_3p3\n", __func__);
Ivan T. Ivanov37cfdaf2014-04-28 16:34:06 +0300185 regulator_set_optimum_mode(motg->v1p8,
Anji jonnala11aa5c42011-05-04 10:19:48 +0530186 USB_PHY_1P8_LPM_LOAD);
187 return ret;
188 }
189 } else {
Ivan T. Ivanov37cfdaf2014-04-28 16:34:06 +0300190 ret = regulator_set_optimum_mode(motg->v1p8,
Anji jonnala11aa5c42011-05-04 10:19:48 +0530191 USB_PHY_1P8_LPM_LOAD);
192 if (ret < 0)
193 pr_err("%s: Unable to set LPM of the regulator "
194 "HSUSB_1p8\n", __func__);
Ivan T. Ivanov37cfdaf2014-04-28 16:34:06 +0300195 ret = regulator_set_optimum_mode(motg->v3p3,
Anji jonnala11aa5c42011-05-04 10:19:48 +0530196 USB_PHY_3P3_LPM_LOAD);
197 if (ret < 0)
198 pr_err("%s: Unable to set LPM of the regulator "
199 "HSUSB_3p3\n", __func__);
200 }
201
202 pr_debug("reg (%s)\n", on ? "HPM" : "LPM");
203 return ret < 0 ? ret : 0;
204}
205
Heikki Krogerus1d4c9292012-02-13 13:24:09 +0200206static int ulpi_read(struct usb_phy *phy, u32 reg)
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +0530207{
Heikki Krogerus1d4c9292012-02-13 13:24:09 +0200208 struct msm_otg *motg = container_of(phy, struct msm_otg, phy);
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +0530209 int cnt = 0;
210
211 /* initiate read operation */
212 writel(ULPI_RUN | ULPI_READ | ULPI_ADDR(reg),
213 USB_ULPI_VIEWPORT);
214
215 /* wait for completion */
216 while (cnt < ULPI_IO_TIMEOUT_USEC) {
217 if (!(readl(USB_ULPI_VIEWPORT) & ULPI_RUN))
218 break;
219 udelay(1);
220 cnt++;
221 }
222
223 if (cnt >= ULPI_IO_TIMEOUT_USEC) {
Heikki Krogerus1d4c9292012-02-13 13:24:09 +0200224 dev_err(phy->dev, "ulpi_read: timeout %08x\n",
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +0530225 readl(USB_ULPI_VIEWPORT));
226 return -ETIMEDOUT;
227 }
228 return ULPI_DATA_READ(readl(USB_ULPI_VIEWPORT));
229}
230
Heikki Krogerus1d4c9292012-02-13 13:24:09 +0200231static int ulpi_write(struct usb_phy *phy, u32 val, u32 reg)
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +0530232{
Heikki Krogerus1d4c9292012-02-13 13:24:09 +0200233 struct msm_otg *motg = container_of(phy, struct msm_otg, phy);
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +0530234 int cnt = 0;
235
236 /* initiate write operation */
237 writel(ULPI_RUN | ULPI_WRITE |
238 ULPI_ADDR(reg) | ULPI_DATA(val),
239 USB_ULPI_VIEWPORT);
240
241 /* wait for completion */
242 while (cnt < ULPI_IO_TIMEOUT_USEC) {
243 if (!(readl(USB_ULPI_VIEWPORT) & ULPI_RUN))
244 break;
245 udelay(1);
246 cnt++;
247 }
248
249 if (cnt >= ULPI_IO_TIMEOUT_USEC) {
Heikki Krogerus1d4c9292012-02-13 13:24:09 +0200250 dev_err(phy->dev, "ulpi_write: timeout\n");
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +0530251 return -ETIMEDOUT;
252 }
253 return 0;
254}
255
Heikki Krogerus1d4c9292012-02-13 13:24:09 +0200256static struct usb_phy_io_ops msm_otg_io_ops = {
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +0530257 .read = ulpi_read,
258 .write = ulpi_write,
259};
260
261static void ulpi_init(struct msm_otg *motg)
262{
263 struct msm_otg_platform_data *pdata = motg->pdata;
264 int *seq = pdata->phy_init_seq;
265
266 if (!seq)
267 return;
268
269 while (seq[0] >= 0) {
Heikki Krogerus1d4c9292012-02-13 13:24:09 +0200270 dev_vdbg(motg->phy.dev, "ulpi: write 0x%02x to 0x%02x\n",
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +0530271 seq[0], seq[1]);
Heikki Krogerus1d4c9292012-02-13 13:24:09 +0200272 ulpi_write(&motg->phy, seq[0], seq[1]);
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +0530273 seq += 2;
274 }
275}
276
277static int msm_otg_link_clk_reset(struct msm_otg *motg, bool assert)
278{
Ivan T. Ivanov5146d772013-12-30 13:15:27 -0800279 int ret = 0;
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +0530280
Ivan T. Ivanov5146d772013-12-30 13:15:27 -0800281 if (!motg->pdata->link_clk_reset)
282 return ret;
283
284 ret = motg->pdata->link_clk_reset(motg->clk, assert);
285 if (ret)
286 dev_err(motg->phy.dev, "usb link clk reset %s failed\n",
287 assert ? "assert" : "deassert");
288
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +0530289 return ret;
290}
291
292static int msm_otg_phy_clk_reset(struct msm_otg *motg)
293{
Ivan T. Ivanov5146d772013-12-30 13:15:27 -0800294 int ret = 0;
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +0530295
Ivan T. Ivanov5146d772013-12-30 13:15:27 -0800296 if (!motg->pdata->phy_clk_reset)
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +0530297 return ret;
Ivan T. Ivanov5146d772013-12-30 13:15:27 -0800298
299 ret = motg->pdata->phy_clk_reset(motg->phy_reset_clk);
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +0530300 if (ret)
Ivan T. Ivanov5146d772013-12-30 13:15:27 -0800301 dev_err(motg->phy.dev, "usb phy clk reset failed\n");
302
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +0530303 return ret;
304}
305
306static int msm_otg_phy_reset(struct msm_otg *motg)
307{
308 u32 val;
309 int ret;
310 int retries;
311
312 ret = msm_otg_link_clk_reset(motg, 1);
313 if (ret)
314 return ret;
315 ret = msm_otg_phy_clk_reset(motg);
316 if (ret)
317 return ret;
318 ret = msm_otg_link_clk_reset(motg, 0);
319 if (ret)
320 return ret;
321
322 val = readl(USB_PORTSC) & ~PORTSC_PTS_MASK;
323 writel(val | PORTSC_PTS_ULPI, USB_PORTSC);
324
325 for (retries = 3; retries > 0; retries--) {
Heikki Krogerus1d4c9292012-02-13 13:24:09 +0200326 ret = ulpi_write(&motg->phy, ULPI_FUNC_CTRL_SUSPENDM,
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +0530327 ULPI_CLR(ULPI_FUNC_CTRL));
328 if (!ret)
329 break;
330 ret = msm_otg_phy_clk_reset(motg);
331 if (ret)
332 return ret;
333 }
334 if (!retries)
335 return -ETIMEDOUT;
336
337 /* This reset calibrates the phy, if the above write succeeded */
338 ret = msm_otg_phy_clk_reset(motg);
339 if (ret)
340 return ret;
341
342 for (retries = 3; retries > 0; retries--) {
Heikki Krogerus1d4c9292012-02-13 13:24:09 +0200343 ret = ulpi_read(&motg->phy, ULPI_DEBUG);
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +0530344 if (ret != -ETIMEDOUT)
345 break;
346 ret = msm_otg_phy_clk_reset(motg);
347 if (ret)
348 return ret;
349 }
350 if (!retries)
351 return -ETIMEDOUT;
352
Heikki Krogerus1d4c9292012-02-13 13:24:09 +0200353 dev_info(motg->phy.dev, "phy_reset: success\n");
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +0530354 return 0;
355}
356
357#define LINK_RESET_TIMEOUT_USEC (250 * 1000)
Heikki Krogerus1d4c9292012-02-13 13:24:09 +0200358static int msm_otg_reset(struct usb_phy *phy)
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +0530359{
Heikki Krogerus1d4c9292012-02-13 13:24:09 +0200360 struct msm_otg *motg = container_of(phy, struct msm_otg, phy);
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +0530361 struct msm_otg_platform_data *pdata = motg->pdata;
362 int cnt = 0;
363 int ret;
364 u32 val = 0;
365 u32 ulpi_val = 0;
366
367 ret = msm_otg_phy_reset(motg);
368 if (ret) {
Heikki Krogerus1d4c9292012-02-13 13:24:09 +0200369 dev_err(phy->dev, "phy_reset failed\n");
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +0530370 return ret;
371 }
372
373 ulpi_init(motg);
374
375 writel(USBCMD_RESET, USB_USBCMD);
376 while (cnt < LINK_RESET_TIMEOUT_USEC) {
377 if (!(readl(USB_USBCMD) & USBCMD_RESET))
378 break;
379 udelay(1);
380 cnt++;
381 }
382 if (cnt >= LINK_RESET_TIMEOUT_USEC)
383 return -ETIMEDOUT;
384
385 /* select ULPI phy */
386 writel(0x80000000, USB_PORTSC);
387
388 msleep(100);
389
390 writel(0x0, USB_AHBBURST);
391 writel(0x00, USB_AHBMODE);
392
393 if (pdata->otg_control == OTG_PHY_CONTROL) {
394 val = readl(USB_OTGSC);
395 if (pdata->mode == USB_OTG) {
396 ulpi_val = ULPI_INT_IDGRD | ULPI_INT_SESS_VALID;
397 val |= OTGSC_IDIE | OTGSC_BSVIE;
398 } else if (pdata->mode == USB_PERIPHERAL) {
399 ulpi_val = ULPI_INT_SESS_VALID;
400 val |= OTGSC_BSVIE;
401 }
402 writel(val, USB_OTGSC);
Heikki Krogerus1d4c9292012-02-13 13:24:09 +0200403 ulpi_write(phy, ulpi_val, ULPI_USB_INT_EN_RISE);
404 ulpi_write(phy, ulpi_val, ULPI_USB_INT_EN_FALL);
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +0530405 }
406
407 return 0;
408}
409
Pavankumar Kondeti87c01042010-12-07 17:53:58 +0530410#define PHY_SUSPEND_TIMEOUT_USEC (500 * 1000)
Pavankumar Kondeti70187732011-02-15 09:42:34 +0530411#define PHY_RESUME_TIMEOUT_USEC (100 * 1000)
412
Josh Cartwrighte7d613d2014-02-18 10:36:29 -0600413#ifdef CONFIG_PM
414
415#define USB_PHY_SUSP_DIG_VOL 500000
Ivan T. Ivanov37cfdaf2014-04-28 16:34:06 +0300416static int msm_hsusb_config_vddcx(struct msm_otg *motg, int high)
Josh Cartwrighte7d613d2014-02-18 10:36:29 -0600417{
418 int max_vol = USB_PHY_VDD_DIG_VOL_MAX;
419 int min_vol;
420 int ret;
421
422 if (high)
423 min_vol = USB_PHY_VDD_DIG_VOL_MIN;
424 else
425 min_vol = USB_PHY_SUSP_DIG_VOL;
426
Ivan T. Ivanov37cfdaf2014-04-28 16:34:06 +0300427 ret = regulator_set_voltage(motg->vddcx, min_vol, max_vol);
Josh Cartwrighte7d613d2014-02-18 10:36:29 -0600428 if (ret) {
429 pr_err("%s: unable to set the voltage for regulator "
430 "HSUSB_VDDCX\n", __func__);
431 return ret;
432 }
433
434 pr_debug("%s: min_vol:%d max_vol:%d\n", __func__, min_vol, max_vol);
435
436 return ret;
437}
438
Pavankumar Kondeti87c01042010-12-07 17:53:58 +0530439static int msm_otg_suspend(struct msm_otg *motg)
440{
Heikki Krogerus1d4c9292012-02-13 13:24:09 +0200441 struct usb_phy *phy = &motg->phy;
442 struct usb_bus *bus = phy->otg->host;
Pavankumar Kondeti87c01042010-12-07 17:53:58 +0530443 struct msm_otg_platform_data *pdata = motg->pdata;
444 int cnt = 0;
445
446 if (atomic_read(&motg->in_lpm))
447 return 0;
448
449 disable_irq(motg->irq);
450 /*
Pavankumar Kondeti04aebcb2011-05-04 10:19:49 +0530451 * Chipidea 45-nm PHY suspend sequence:
452 *
Pavankumar Kondeti87c01042010-12-07 17:53:58 +0530453 * Interrupt Latch Register auto-clear feature is not present
454 * in all PHY versions. Latch register is clear on read type.
455 * Clear latch register to avoid spurious wakeup from
456 * low power mode (LPM).
Pavankumar Kondeti04aebcb2011-05-04 10:19:49 +0530457 *
Pavankumar Kondeti87c01042010-12-07 17:53:58 +0530458 * PHY comparators are disabled when PHY enters into low power
459 * mode (LPM). Keep PHY comparators ON in LPM only when we expect
460 * VBUS/Id notifications from USB PHY. Otherwise turn off USB
461 * PHY comparators. This save significant amount of power.
Pavankumar Kondeti04aebcb2011-05-04 10:19:49 +0530462 *
Pavankumar Kondeti87c01042010-12-07 17:53:58 +0530463 * PLL is not turned off when PHY enters into low power mode (LPM).
464 * Disable PLL for maximum power savings.
465 */
Pavankumar Kondeti04aebcb2011-05-04 10:19:49 +0530466
467 if (motg->pdata->phy_type == CI_45NM_INTEGRATED_PHY) {
Heikki Krogerus1d4c9292012-02-13 13:24:09 +0200468 ulpi_read(phy, 0x14);
Pavankumar Kondeti04aebcb2011-05-04 10:19:49 +0530469 if (pdata->otg_control == OTG_PHY_CONTROL)
Heikki Krogerus1d4c9292012-02-13 13:24:09 +0200470 ulpi_write(phy, 0x01, 0x30);
471 ulpi_write(phy, 0x08, 0x09);
Pavankumar Kondeti04aebcb2011-05-04 10:19:49 +0530472 }
Pavankumar Kondeti87c01042010-12-07 17:53:58 +0530473
474 /*
475 * PHY may take some time or even fail to enter into low power
476 * mode (LPM). Hence poll for 500 msec and reset the PHY and link
477 * in failure case.
478 */
479 writel(readl(USB_PORTSC) | PORTSC_PHCD, USB_PORTSC);
480 while (cnt < PHY_SUSPEND_TIMEOUT_USEC) {
481 if (readl(USB_PORTSC) & PORTSC_PHCD)
482 break;
483 udelay(1);
484 cnt++;
485 }
486
487 if (cnt >= PHY_SUSPEND_TIMEOUT_USEC) {
Heikki Krogerus1d4c9292012-02-13 13:24:09 +0200488 dev_err(phy->dev, "Unable to suspend PHY\n");
489 msm_otg_reset(phy);
Pavankumar Kondeti87c01042010-12-07 17:53:58 +0530490 enable_irq(motg->irq);
491 return -ETIMEDOUT;
492 }
493
494 /*
495 * PHY has capability to generate interrupt asynchronously in low
496 * power mode (LPM). This interrupt is level triggered. So USB IRQ
497 * line must be disabled till async interrupt enable bit is cleared
498 * in USBCMD register. Assert STP (ULPI interface STOP signal) to
499 * block data communication from PHY.
500 */
501 writel(readl(USB_USBCMD) | ASYNC_INTR_CTRL | ULPI_STP_CTRL, USB_USBCMD);
502
Pavankumar Kondeti04aebcb2011-05-04 10:19:49 +0530503 if (motg->pdata->phy_type == SNPS_28NM_INTEGRATED_PHY &&
504 motg->pdata->otg_control == OTG_PMIC_CONTROL)
505 writel(readl(USB_PHY_CTRL) | PHY_RETEN, USB_PHY_CTRL);
506
Stephen Boydb99a8f62013-06-17 10:43:10 -0700507 clk_disable_unprepare(motg->pclk);
508 clk_disable_unprepare(motg->clk);
Pavankumar Kondeti87c01042010-12-07 17:53:58 +0530509 if (motg->core_clk)
Stephen Boydb99a8f62013-06-17 10:43:10 -0700510 clk_disable_unprepare(motg->core_clk);
Pavankumar Kondeti87c01042010-12-07 17:53:58 +0530511
Anji jonnala0f73cac2011-05-04 10:19:46 +0530512 if (!IS_ERR(motg->pclk_src))
Stephen Boydb99a8f62013-06-17 10:43:10 -0700513 clk_disable_unprepare(motg->pclk_src);
Anji jonnala0f73cac2011-05-04 10:19:46 +0530514
Pavankumar Kondeti04aebcb2011-05-04 10:19:49 +0530515 if (motg->pdata->phy_type == SNPS_28NM_INTEGRATED_PHY &&
516 motg->pdata->otg_control == OTG_PMIC_CONTROL) {
Ivan T. Ivanov37cfdaf2014-04-28 16:34:06 +0300517 msm_hsusb_ldo_set_mode(motg, 0);
518 msm_hsusb_config_vddcx(motg, 0);
Pavankumar Kondeti04aebcb2011-05-04 10:19:49 +0530519 }
520
Heikki Krogerus1d4c9292012-02-13 13:24:09 +0200521 if (device_may_wakeup(phy->dev))
Pavankumar Kondeti87c01042010-12-07 17:53:58 +0530522 enable_irq_wake(motg->irq);
523 if (bus)
524 clear_bit(HCD_FLAG_HW_ACCESSIBLE, &(bus_to_hcd(bus))->flags);
525
526 atomic_set(&motg->in_lpm, 1);
527 enable_irq(motg->irq);
528
Heikki Krogerus1d4c9292012-02-13 13:24:09 +0200529 dev_info(phy->dev, "USB in low power mode\n");
Pavankumar Kondeti87c01042010-12-07 17:53:58 +0530530
531 return 0;
532}
533
Pavankumar Kondeti87c01042010-12-07 17:53:58 +0530534static int msm_otg_resume(struct msm_otg *motg)
535{
Heikki Krogerus1d4c9292012-02-13 13:24:09 +0200536 struct usb_phy *phy = &motg->phy;
537 struct usb_bus *bus = phy->otg->host;
Pavankumar Kondeti87c01042010-12-07 17:53:58 +0530538 int cnt = 0;
539 unsigned temp;
540
541 if (!atomic_read(&motg->in_lpm))
542 return 0;
543
Anji jonnala0f73cac2011-05-04 10:19:46 +0530544 if (!IS_ERR(motg->pclk_src))
Stephen Boydb99a8f62013-06-17 10:43:10 -0700545 clk_prepare_enable(motg->pclk_src);
Anji jonnala0f73cac2011-05-04 10:19:46 +0530546
Stephen Boydb99a8f62013-06-17 10:43:10 -0700547 clk_prepare_enable(motg->pclk);
548 clk_prepare_enable(motg->clk);
Pavankumar Kondeti87c01042010-12-07 17:53:58 +0530549 if (motg->core_clk)
Stephen Boydb99a8f62013-06-17 10:43:10 -0700550 clk_prepare_enable(motg->core_clk);
Pavankumar Kondeti87c01042010-12-07 17:53:58 +0530551
Pavankumar Kondeti04aebcb2011-05-04 10:19:49 +0530552 if (motg->pdata->phy_type == SNPS_28NM_INTEGRATED_PHY &&
553 motg->pdata->otg_control == OTG_PMIC_CONTROL) {
Ivan T. Ivanov37cfdaf2014-04-28 16:34:06 +0300554 msm_hsusb_ldo_set_mode(motg, 1);
555 msm_hsusb_config_vddcx(motg, 1);
Pavankumar Kondeti04aebcb2011-05-04 10:19:49 +0530556 writel(readl(USB_PHY_CTRL) & ~PHY_RETEN, USB_PHY_CTRL);
557 }
558
Pavankumar Kondeti87c01042010-12-07 17:53:58 +0530559 temp = readl(USB_USBCMD);
560 temp &= ~ASYNC_INTR_CTRL;
561 temp &= ~ULPI_STP_CTRL;
562 writel(temp, USB_USBCMD);
563
564 /*
565 * PHY comes out of low power mode (LPM) in case of wakeup
566 * from asynchronous interrupt.
567 */
568 if (!(readl(USB_PORTSC) & PORTSC_PHCD))
569 goto skip_phy_resume;
570
571 writel(readl(USB_PORTSC) & ~PORTSC_PHCD, USB_PORTSC);
572 while (cnt < PHY_RESUME_TIMEOUT_USEC) {
573 if (!(readl(USB_PORTSC) & PORTSC_PHCD))
574 break;
575 udelay(1);
576 cnt++;
577 }
578
579 if (cnt >= PHY_RESUME_TIMEOUT_USEC) {
580 /*
581 * This is a fatal error. Reset the link and
582 * PHY. USB state can not be restored. Re-insertion
583 * of USB cable is the only way to get USB working.
584 */
Heikki Krogerus1d4c9292012-02-13 13:24:09 +0200585 dev_err(phy->dev, "Unable to resume USB."
Pavankumar Kondeti87c01042010-12-07 17:53:58 +0530586 "Re-plugin the cable\n");
Heikki Krogerus1d4c9292012-02-13 13:24:09 +0200587 msm_otg_reset(phy);
Pavankumar Kondeti87c01042010-12-07 17:53:58 +0530588 }
589
590skip_phy_resume:
Heikki Krogerus1d4c9292012-02-13 13:24:09 +0200591 if (device_may_wakeup(phy->dev))
Pavankumar Kondeti87c01042010-12-07 17:53:58 +0530592 disable_irq_wake(motg->irq);
593 if (bus)
594 set_bit(HCD_FLAG_HW_ACCESSIBLE, &(bus_to_hcd(bus))->flags);
595
Pavankumar Kondeti2ce2c3a2011-05-02 11:56:33 +0530596 atomic_set(&motg->in_lpm, 0);
597
Pavankumar Kondeti87c01042010-12-07 17:53:58 +0530598 if (motg->async_int) {
599 motg->async_int = 0;
Heikki Krogerus1d4c9292012-02-13 13:24:09 +0200600 pm_runtime_put(phy->dev);
Pavankumar Kondeti87c01042010-12-07 17:53:58 +0530601 enable_irq(motg->irq);
602 }
603
Heikki Krogerus1d4c9292012-02-13 13:24:09 +0200604 dev_info(phy->dev, "USB exited from low power mode\n");
Pavankumar Kondeti87c01042010-12-07 17:53:58 +0530605
606 return 0;
607}
Pavankumar Kondeti70187732011-02-15 09:42:34 +0530608#endif
Pavankumar Kondeti87c01042010-12-07 17:53:58 +0530609
Pavankumar Kondetid8608522011-05-04 10:19:47 +0530610static void msm_otg_notify_charger(struct msm_otg *motg, unsigned mA)
611{
612 if (motg->cur_power == mA)
613 return;
614
615 /* TODO: Notify PMIC about available current */
Heikki Krogerus1d4c9292012-02-13 13:24:09 +0200616 dev_info(motg->phy.dev, "Avail curr from USB = %u\n", mA);
Pavankumar Kondetid8608522011-05-04 10:19:47 +0530617 motg->cur_power = mA;
618}
619
Heikki Krogerus1d4c9292012-02-13 13:24:09 +0200620static int msm_otg_set_power(struct usb_phy *phy, unsigned mA)
Pavankumar Kondetid8608522011-05-04 10:19:47 +0530621{
Heikki Krogerus1d4c9292012-02-13 13:24:09 +0200622 struct msm_otg *motg = container_of(phy, struct msm_otg, phy);
Pavankumar Kondetid8608522011-05-04 10:19:47 +0530623
624 /*
625 * Gadget driver uses set_power method to notify about the
626 * available current based on suspend/configured states.
627 *
628 * IDEV_CHG can be drawn irrespective of suspend/un-configured
629 * states when CDP/ACA is connected.
630 */
631 if (motg->chg_type == USB_SDP_CHARGER)
632 msm_otg_notify_charger(motg, mA);
633
634 return 0;
635}
636
Heikki Krogerus1d4c9292012-02-13 13:24:09 +0200637static void msm_otg_start_host(struct usb_phy *phy, int on)
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +0530638{
Heikki Krogerus1d4c9292012-02-13 13:24:09 +0200639 struct msm_otg *motg = container_of(phy, struct msm_otg, phy);
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +0530640 struct msm_otg_platform_data *pdata = motg->pdata;
641 struct usb_hcd *hcd;
642
Heikki Krogerus1d4c9292012-02-13 13:24:09 +0200643 if (!phy->otg->host)
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +0530644 return;
645
Heikki Krogerus1d4c9292012-02-13 13:24:09 +0200646 hcd = bus_to_hcd(phy->otg->host);
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +0530647
648 if (on) {
Heikki Krogerus1d4c9292012-02-13 13:24:09 +0200649 dev_dbg(phy->dev, "host on\n");
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +0530650
651 if (pdata->vbus_power)
652 pdata->vbus_power(1);
653 /*
654 * Some boards have a switch cotrolled by gpio
655 * to enable/disable internal HUB. Enable internal
656 * HUB before kicking the host.
657 */
658 if (pdata->setup_gpio)
659 pdata->setup_gpio(OTG_STATE_A_HOST);
660#ifdef CONFIG_USB
661 usb_add_hcd(hcd, hcd->irq, IRQF_SHARED);
Peter Chen3c9740a2013-11-05 10:46:02 +0800662 device_wakeup_enable(hcd->self.controller);
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +0530663#endif
664 } else {
Heikki Krogerus1d4c9292012-02-13 13:24:09 +0200665 dev_dbg(phy->dev, "host off\n");
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +0530666
667#ifdef CONFIG_USB
668 usb_remove_hcd(hcd);
669#endif
670 if (pdata->setup_gpio)
671 pdata->setup_gpio(OTG_STATE_UNDEFINED);
672 if (pdata->vbus_power)
673 pdata->vbus_power(0);
674 }
675}
676
Heikki Krogerus1d4c9292012-02-13 13:24:09 +0200677static int msm_otg_set_host(struct usb_otg *otg, struct usb_bus *host)
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +0530678{
Heikki Krogerus1d4c9292012-02-13 13:24:09 +0200679 struct msm_otg *motg = container_of(otg->phy, struct msm_otg, phy);
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +0530680 struct usb_hcd *hcd;
681
682 /*
683 * Fail host registration if this board can support
684 * only peripheral configuration.
685 */
686 if (motg->pdata->mode == USB_PERIPHERAL) {
Heikki Krogerus1d4c9292012-02-13 13:24:09 +0200687 dev_info(otg->phy->dev, "Host mode is not supported\n");
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +0530688 return -ENODEV;
689 }
690
691 if (!host) {
Heikki Krogerus1d4c9292012-02-13 13:24:09 +0200692 if (otg->phy->state == OTG_STATE_A_HOST) {
693 pm_runtime_get_sync(otg->phy->dev);
694 msm_otg_start_host(otg->phy, 0);
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +0530695 otg->host = NULL;
Heikki Krogerus1d4c9292012-02-13 13:24:09 +0200696 otg->phy->state = OTG_STATE_UNDEFINED;
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +0530697 schedule_work(&motg->sm_work);
698 } else {
699 otg->host = NULL;
700 }
701
702 return 0;
703 }
704
705 hcd = bus_to_hcd(host);
706 hcd->power_budget = motg->pdata->power_budget;
707
708 otg->host = host;
Heikki Krogerus1d4c9292012-02-13 13:24:09 +0200709 dev_dbg(otg->phy->dev, "host driver registered w/ tranceiver\n");
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +0530710
711 /*
712 * Kick the state machine work, if peripheral is not supported
713 * or peripheral is already registered with us.
714 */
Pavankumar Kondeti87c01042010-12-07 17:53:58 +0530715 if (motg->pdata->mode == USB_HOST || otg->gadget) {
Heikki Krogerus1d4c9292012-02-13 13:24:09 +0200716 pm_runtime_get_sync(otg->phy->dev);
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +0530717 schedule_work(&motg->sm_work);
Pavankumar Kondeti87c01042010-12-07 17:53:58 +0530718 }
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +0530719
720 return 0;
721}
722
Heikki Krogerus1d4c9292012-02-13 13:24:09 +0200723static void msm_otg_start_peripheral(struct usb_phy *phy, int on)
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +0530724{
Heikki Krogerus1d4c9292012-02-13 13:24:09 +0200725 struct msm_otg *motg = container_of(phy, struct msm_otg, phy);
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +0530726 struct msm_otg_platform_data *pdata = motg->pdata;
727
Heikki Krogerus1d4c9292012-02-13 13:24:09 +0200728 if (!phy->otg->gadget)
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +0530729 return;
730
731 if (on) {
Heikki Krogerus1d4c9292012-02-13 13:24:09 +0200732 dev_dbg(phy->dev, "gadget on\n");
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +0530733 /*
734 * Some boards have a switch cotrolled by gpio
735 * to enable/disable internal HUB. Disable internal
736 * HUB before kicking the gadget.
737 */
738 if (pdata->setup_gpio)
739 pdata->setup_gpio(OTG_STATE_B_PERIPHERAL);
Heikki Krogerus1d4c9292012-02-13 13:24:09 +0200740 usb_gadget_vbus_connect(phy->otg->gadget);
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +0530741 } else {
Heikki Krogerus1d4c9292012-02-13 13:24:09 +0200742 dev_dbg(phy->dev, "gadget off\n");
743 usb_gadget_vbus_disconnect(phy->otg->gadget);
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +0530744 if (pdata->setup_gpio)
745 pdata->setup_gpio(OTG_STATE_UNDEFINED);
746 }
747
748}
749
Heikki Krogerus1d4c9292012-02-13 13:24:09 +0200750static int msm_otg_set_peripheral(struct usb_otg *otg,
751 struct usb_gadget *gadget)
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +0530752{
Heikki Krogerus1d4c9292012-02-13 13:24:09 +0200753 struct msm_otg *motg = container_of(otg->phy, struct msm_otg, phy);
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +0530754
755 /*
756 * Fail peripheral registration if this board can support
757 * only host configuration.
758 */
759 if (motg->pdata->mode == USB_HOST) {
Heikki Krogerus1d4c9292012-02-13 13:24:09 +0200760 dev_info(otg->phy->dev, "Peripheral mode is not supported\n");
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +0530761 return -ENODEV;
762 }
763
764 if (!gadget) {
Heikki Krogerus1d4c9292012-02-13 13:24:09 +0200765 if (otg->phy->state == OTG_STATE_B_PERIPHERAL) {
766 pm_runtime_get_sync(otg->phy->dev);
767 msm_otg_start_peripheral(otg->phy, 0);
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +0530768 otg->gadget = NULL;
Heikki Krogerus1d4c9292012-02-13 13:24:09 +0200769 otg->phy->state = OTG_STATE_UNDEFINED;
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +0530770 schedule_work(&motg->sm_work);
771 } else {
772 otg->gadget = NULL;
773 }
774
775 return 0;
776 }
777 otg->gadget = gadget;
Heikki Krogerus1d4c9292012-02-13 13:24:09 +0200778 dev_dbg(otg->phy->dev, "peripheral driver registered w/ tranceiver\n");
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +0530779
780 /*
781 * Kick the state machine work, if host is not supported
782 * or host is already registered with us.
783 */
Pavankumar Kondeti87c01042010-12-07 17:53:58 +0530784 if (motg->pdata->mode == USB_PERIPHERAL || otg->host) {
Heikki Krogerus1d4c9292012-02-13 13:24:09 +0200785 pm_runtime_get_sync(otg->phy->dev);
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +0530786 schedule_work(&motg->sm_work);
Pavankumar Kondeti87c01042010-12-07 17:53:58 +0530787 }
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +0530788
789 return 0;
790}
791
Pavankumar Kondetid8608522011-05-04 10:19:47 +0530792static bool msm_chg_check_secondary_det(struct msm_otg *motg)
793{
Heikki Krogerus1d4c9292012-02-13 13:24:09 +0200794 struct usb_phy *phy = &motg->phy;
Pavankumar Kondetid8608522011-05-04 10:19:47 +0530795 u32 chg_det;
796 bool ret = false;
797
798 switch (motg->pdata->phy_type) {
799 case CI_45NM_INTEGRATED_PHY:
Heikki Krogerus1d4c9292012-02-13 13:24:09 +0200800 chg_det = ulpi_read(phy, 0x34);
Pavankumar Kondetid8608522011-05-04 10:19:47 +0530801 ret = chg_det & (1 << 4);
802 break;
803 case SNPS_28NM_INTEGRATED_PHY:
Heikki Krogerus1d4c9292012-02-13 13:24:09 +0200804 chg_det = ulpi_read(phy, 0x87);
Pavankumar Kondetid8608522011-05-04 10:19:47 +0530805 ret = chg_det & 1;
806 break;
807 default:
808 break;
809 }
810 return ret;
811}
812
813static void msm_chg_enable_secondary_det(struct msm_otg *motg)
814{
Heikki Krogerus1d4c9292012-02-13 13:24:09 +0200815 struct usb_phy *phy = &motg->phy;
Pavankumar Kondetid8608522011-05-04 10:19:47 +0530816 u32 chg_det;
817
818 switch (motg->pdata->phy_type) {
819 case CI_45NM_INTEGRATED_PHY:
Heikki Krogerus1d4c9292012-02-13 13:24:09 +0200820 chg_det = ulpi_read(phy, 0x34);
Pavankumar Kondetid8608522011-05-04 10:19:47 +0530821 /* Turn off charger block */
822 chg_det |= ~(1 << 1);
Heikki Krogerus1d4c9292012-02-13 13:24:09 +0200823 ulpi_write(phy, chg_det, 0x34);
Pavankumar Kondetid8608522011-05-04 10:19:47 +0530824 udelay(20);
825 /* control chg block via ULPI */
826 chg_det &= ~(1 << 3);
Heikki Krogerus1d4c9292012-02-13 13:24:09 +0200827 ulpi_write(phy, chg_det, 0x34);
Pavankumar Kondetid8608522011-05-04 10:19:47 +0530828 /* put it in host mode for enabling D- source */
829 chg_det &= ~(1 << 2);
Heikki Krogerus1d4c9292012-02-13 13:24:09 +0200830 ulpi_write(phy, chg_det, 0x34);
Pavankumar Kondetid8608522011-05-04 10:19:47 +0530831 /* Turn on chg detect block */
832 chg_det &= ~(1 << 1);
Heikki Krogerus1d4c9292012-02-13 13:24:09 +0200833 ulpi_write(phy, chg_det, 0x34);
Pavankumar Kondetid8608522011-05-04 10:19:47 +0530834 udelay(20);
835 /* enable chg detection */
836 chg_det &= ~(1 << 0);
Heikki Krogerus1d4c9292012-02-13 13:24:09 +0200837 ulpi_write(phy, chg_det, 0x34);
Pavankumar Kondetid8608522011-05-04 10:19:47 +0530838 break;
839 case SNPS_28NM_INTEGRATED_PHY:
840 /*
841 * Configure DM as current source, DP as current sink
842 * and enable battery charging comparators.
843 */
Heikki Krogerus1d4c9292012-02-13 13:24:09 +0200844 ulpi_write(phy, 0x8, 0x85);
845 ulpi_write(phy, 0x2, 0x85);
846 ulpi_write(phy, 0x1, 0x85);
Pavankumar Kondetid8608522011-05-04 10:19:47 +0530847 break;
848 default:
849 break;
850 }
851}
852
853static bool msm_chg_check_primary_det(struct msm_otg *motg)
854{
Heikki Krogerus1d4c9292012-02-13 13:24:09 +0200855 struct usb_phy *phy = &motg->phy;
Pavankumar Kondetid8608522011-05-04 10:19:47 +0530856 u32 chg_det;
857 bool ret = false;
858
859 switch (motg->pdata->phy_type) {
860 case CI_45NM_INTEGRATED_PHY:
Heikki Krogerus1d4c9292012-02-13 13:24:09 +0200861 chg_det = ulpi_read(phy, 0x34);
Pavankumar Kondetid8608522011-05-04 10:19:47 +0530862 ret = chg_det & (1 << 4);
863 break;
864 case SNPS_28NM_INTEGRATED_PHY:
Heikki Krogerus1d4c9292012-02-13 13:24:09 +0200865 chg_det = ulpi_read(phy, 0x87);
Pavankumar Kondetid8608522011-05-04 10:19:47 +0530866 ret = chg_det & 1;
867 break;
868 default:
869 break;
870 }
871 return ret;
872}
873
874static void msm_chg_enable_primary_det(struct msm_otg *motg)
875{
Heikki Krogerus1d4c9292012-02-13 13:24:09 +0200876 struct usb_phy *phy = &motg->phy;
Pavankumar Kondetid8608522011-05-04 10:19:47 +0530877 u32 chg_det;
878
879 switch (motg->pdata->phy_type) {
880 case CI_45NM_INTEGRATED_PHY:
Heikki Krogerus1d4c9292012-02-13 13:24:09 +0200881 chg_det = ulpi_read(phy, 0x34);
Pavankumar Kondetid8608522011-05-04 10:19:47 +0530882 /* enable chg detection */
883 chg_det &= ~(1 << 0);
Heikki Krogerus1d4c9292012-02-13 13:24:09 +0200884 ulpi_write(phy, chg_det, 0x34);
Pavankumar Kondetid8608522011-05-04 10:19:47 +0530885 break;
886 case SNPS_28NM_INTEGRATED_PHY:
887 /*
888 * Configure DP as current source, DM as current sink
889 * and enable battery charging comparators.
890 */
Heikki Krogerus1d4c9292012-02-13 13:24:09 +0200891 ulpi_write(phy, 0x2, 0x85);
892 ulpi_write(phy, 0x1, 0x85);
Pavankumar Kondetid8608522011-05-04 10:19:47 +0530893 break;
894 default:
895 break;
896 }
897}
898
899static bool msm_chg_check_dcd(struct msm_otg *motg)
900{
Heikki Krogerus1d4c9292012-02-13 13:24:09 +0200901 struct usb_phy *phy = &motg->phy;
Pavankumar Kondetid8608522011-05-04 10:19:47 +0530902 u32 line_state;
903 bool ret = false;
904
905 switch (motg->pdata->phy_type) {
906 case CI_45NM_INTEGRATED_PHY:
Heikki Krogerus1d4c9292012-02-13 13:24:09 +0200907 line_state = ulpi_read(phy, 0x15);
Pavankumar Kondetid8608522011-05-04 10:19:47 +0530908 ret = !(line_state & 1);
909 break;
910 case SNPS_28NM_INTEGRATED_PHY:
Heikki Krogerus1d4c9292012-02-13 13:24:09 +0200911 line_state = ulpi_read(phy, 0x87);
Pavankumar Kondetid8608522011-05-04 10:19:47 +0530912 ret = line_state & 2;
913 break;
914 default:
915 break;
916 }
917 return ret;
918}
919
920static void msm_chg_disable_dcd(struct msm_otg *motg)
921{
Heikki Krogerus1d4c9292012-02-13 13:24:09 +0200922 struct usb_phy *phy = &motg->phy;
Pavankumar Kondetid8608522011-05-04 10:19:47 +0530923 u32 chg_det;
924
925 switch (motg->pdata->phy_type) {
926 case CI_45NM_INTEGRATED_PHY:
Heikki Krogerus1d4c9292012-02-13 13:24:09 +0200927 chg_det = ulpi_read(phy, 0x34);
Pavankumar Kondetid8608522011-05-04 10:19:47 +0530928 chg_det &= ~(1 << 5);
Heikki Krogerus1d4c9292012-02-13 13:24:09 +0200929 ulpi_write(phy, chg_det, 0x34);
Pavankumar Kondetid8608522011-05-04 10:19:47 +0530930 break;
931 case SNPS_28NM_INTEGRATED_PHY:
Heikki Krogerus1d4c9292012-02-13 13:24:09 +0200932 ulpi_write(phy, 0x10, 0x86);
Pavankumar Kondetid8608522011-05-04 10:19:47 +0530933 break;
934 default:
935 break;
936 }
937}
938
939static void msm_chg_enable_dcd(struct msm_otg *motg)
940{
Heikki Krogerus1d4c9292012-02-13 13:24:09 +0200941 struct usb_phy *phy = &motg->phy;
Pavankumar Kondetid8608522011-05-04 10:19:47 +0530942 u32 chg_det;
943
944 switch (motg->pdata->phy_type) {
945 case CI_45NM_INTEGRATED_PHY:
Heikki Krogerus1d4c9292012-02-13 13:24:09 +0200946 chg_det = ulpi_read(phy, 0x34);
Pavankumar Kondetid8608522011-05-04 10:19:47 +0530947 /* Turn on D+ current source */
948 chg_det |= (1 << 5);
Heikki Krogerus1d4c9292012-02-13 13:24:09 +0200949 ulpi_write(phy, chg_det, 0x34);
Pavankumar Kondetid8608522011-05-04 10:19:47 +0530950 break;
951 case SNPS_28NM_INTEGRATED_PHY:
952 /* Data contact detection enable */
Heikki Krogerus1d4c9292012-02-13 13:24:09 +0200953 ulpi_write(phy, 0x10, 0x85);
Pavankumar Kondetid8608522011-05-04 10:19:47 +0530954 break;
955 default:
956 break;
957 }
958}
959
960static void msm_chg_block_on(struct msm_otg *motg)
961{
Heikki Krogerus1d4c9292012-02-13 13:24:09 +0200962 struct usb_phy *phy = &motg->phy;
Pavankumar Kondetid8608522011-05-04 10:19:47 +0530963 u32 func_ctrl, chg_det;
964
965 /* put the controller in non-driving mode */
Heikki Krogerus1d4c9292012-02-13 13:24:09 +0200966 func_ctrl = ulpi_read(phy, ULPI_FUNC_CTRL);
Pavankumar Kondetid8608522011-05-04 10:19:47 +0530967 func_ctrl &= ~ULPI_FUNC_CTRL_OPMODE_MASK;
968 func_ctrl |= ULPI_FUNC_CTRL_OPMODE_NONDRIVING;
Heikki Krogerus1d4c9292012-02-13 13:24:09 +0200969 ulpi_write(phy, func_ctrl, ULPI_FUNC_CTRL);
Pavankumar Kondetid8608522011-05-04 10:19:47 +0530970
971 switch (motg->pdata->phy_type) {
972 case CI_45NM_INTEGRATED_PHY:
Heikki Krogerus1d4c9292012-02-13 13:24:09 +0200973 chg_det = ulpi_read(phy, 0x34);
Pavankumar Kondetid8608522011-05-04 10:19:47 +0530974 /* control chg block via ULPI */
975 chg_det &= ~(1 << 3);
Heikki Krogerus1d4c9292012-02-13 13:24:09 +0200976 ulpi_write(phy, chg_det, 0x34);
Pavankumar Kondetid8608522011-05-04 10:19:47 +0530977 /* Turn on chg detect block */
978 chg_det &= ~(1 << 1);
Heikki Krogerus1d4c9292012-02-13 13:24:09 +0200979 ulpi_write(phy, chg_det, 0x34);
Pavankumar Kondetid8608522011-05-04 10:19:47 +0530980 udelay(20);
981 break;
982 case SNPS_28NM_INTEGRATED_PHY:
983 /* Clear charger detecting control bits */
Heikki Krogerus1d4c9292012-02-13 13:24:09 +0200984 ulpi_write(phy, 0x3F, 0x86);
Pavankumar Kondetid8608522011-05-04 10:19:47 +0530985 /* Clear alt interrupt latch and enable bits */
Heikki Krogerus1d4c9292012-02-13 13:24:09 +0200986 ulpi_write(phy, 0x1F, 0x92);
987 ulpi_write(phy, 0x1F, 0x95);
Pavankumar Kondetid8608522011-05-04 10:19:47 +0530988 udelay(100);
989 break;
990 default:
991 break;
992 }
993}
994
995static void msm_chg_block_off(struct msm_otg *motg)
996{
Heikki Krogerus1d4c9292012-02-13 13:24:09 +0200997 struct usb_phy *phy = &motg->phy;
Pavankumar Kondetid8608522011-05-04 10:19:47 +0530998 u32 func_ctrl, chg_det;
999
1000 switch (motg->pdata->phy_type) {
1001 case CI_45NM_INTEGRATED_PHY:
Heikki Krogerus1d4c9292012-02-13 13:24:09 +02001002 chg_det = ulpi_read(phy, 0x34);
Pavankumar Kondetid8608522011-05-04 10:19:47 +05301003 /* Turn off charger block */
1004 chg_det |= ~(1 << 1);
Heikki Krogerus1d4c9292012-02-13 13:24:09 +02001005 ulpi_write(phy, chg_det, 0x34);
Pavankumar Kondetid8608522011-05-04 10:19:47 +05301006 break;
1007 case SNPS_28NM_INTEGRATED_PHY:
1008 /* Clear charger detecting control bits */
Heikki Krogerus1d4c9292012-02-13 13:24:09 +02001009 ulpi_write(phy, 0x3F, 0x86);
Pavankumar Kondetid8608522011-05-04 10:19:47 +05301010 /* Clear alt interrupt latch and enable bits */
Heikki Krogerus1d4c9292012-02-13 13:24:09 +02001011 ulpi_write(phy, 0x1F, 0x92);
1012 ulpi_write(phy, 0x1F, 0x95);
Pavankumar Kondetid8608522011-05-04 10:19:47 +05301013 break;
1014 default:
1015 break;
1016 }
1017
1018 /* put the controller in normal mode */
Heikki Krogerus1d4c9292012-02-13 13:24:09 +02001019 func_ctrl = ulpi_read(phy, ULPI_FUNC_CTRL);
Pavankumar Kondetid8608522011-05-04 10:19:47 +05301020 func_ctrl &= ~ULPI_FUNC_CTRL_OPMODE_MASK;
1021 func_ctrl |= ULPI_FUNC_CTRL_OPMODE_NORMAL;
Heikki Krogerus1d4c9292012-02-13 13:24:09 +02001022 ulpi_write(phy, func_ctrl, ULPI_FUNC_CTRL);
Pavankumar Kondetid8608522011-05-04 10:19:47 +05301023}
1024
1025#define MSM_CHG_DCD_POLL_TIME (100 * HZ/1000) /* 100 msec */
1026#define MSM_CHG_DCD_MAX_RETRIES 6 /* Tdcd_tmout = 6 * 100 msec */
1027#define MSM_CHG_PRIMARY_DET_TIME (40 * HZ/1000) /* TVDPSRC_ON */
1028#define MSM_CHG_SECONDARY_DET_TIME (40 * HZ/1000) /* TVDMSRC_ON */
1029static void msm_chg_detect_work(struct work_struct *w)
1030{
1031 struct msm_otg *motg = container_of(w, struct msm_otg, chg_work.work);
Heikki Krogerus1d4c9292012-02-13 13:24:09 +02001032 struct usb_phy *phy = &motg->phy;
Pavankumar Kondetid8608522011-05-04 10:19:47 +05301033 bool is_dcd, tmout, vout;
1034 unsigned long delay;
1035
Heikki Krogerus1d4c9292012-02-13 13:24:09 +02001036 dev_dbg(phy->dev, "chg detection work\n");
Pavankumar Kondetid8608522011-05-04 10:19:47 +05301037 switch (motg->chg_state) {
1038 case USB_CHG_STATE_UNDEFINED:
Heikki Krogerus1d4c9292012-02-13 13:24:09 +02001039 pm_runtime_get_sync(phy->dev);
Pavankumar Kondetid8608522011-05-04 10:19:47 +05301040 msm_chg_block_on(motg);
1041 msm_chg_enable_dcd(motg);
1042 motg->chg_state = USB_CHG_STATE_WAIT_FOR_DCD;
1043 motg->dcd_retries = 0;
1044 delay = MSM_CHG_DCD_POLL_TIME;
1045 break;
1046 case USB_CHG_STATE_WAIT_FOR_DCD:
1047 is_dcd = msm_chg_check_dcd(motg);
1048 tmout = ++motg->dcd_retries == MSM_CHG_DCD_MAX_RETRIES;
1049 if (is_dcd || tmout) {
1050 msm_chg_disable_dcd(motg);
1051 msm_chg_enable_primary_det(motg);
1052 delay = MSM_CHG_PRIMARY_DET_TIME;
1053 motg->chg_state = USB_CHG_STATE_DCD_DONE;
1054 } else {
1055 delay = MSM_CHG_DCD_POLL_TIME;
1056 }
1057 break;
1058 case USB_CHG_STATE_DCD_DONE:
1059 vout = msm_chg_check_primary_det(motg);
1060 if (vout) {
1061 msm_chg_enable_secondary_det(motg);
1062 delay = MSM_CHG_SECONDARY_DET_TIME;
1063 motg->chg_state = USB_CHG_STATE_PRIMARY_DONE;
1064 } else {
1065 motg->chg_type = USB_SDP_CHARGER;
1066 motg->chg_state = USB_CHG_STATE_DETECTED;
1067 delay = 0;
1068 }
1069 break;
1070 case USB_CHG_STATE_PRIMARY_DONE:
1071 vout = msm_chg_check_secondary_det(motg);
1072 if (vout)
1073 motg->chg_type = USB_DCP_CHARGER;
1074 else
1075 motg->chg_type = USB_CDP_CHARGER;
1076 motg->chg_state = USB_CHG_STATE_SECONDARY_DONE;
1077 /* fall through */
1078 case USB_CHG_STATE_SECONDARY_DONE:
1079 motg->chg_state = USB_CHG_STATE_DETECTED;
1080 case USB_CHG_STATE_DETECTED:
1081 msm_chg_block_off(motg);
Heikki Krogerus1d4c9292012-02-13 13:24:09 +02001082 dev_dbg(phy->dev, "charger = %d\n", motg->chg_type);
Pavankumar Kondetid8608522011-05-04 10:19:47 +05301083 schedule_work(&motg->sm_work);
1084 return;
1085 default:
1086 return;
1087 }
1088
1089 schedule_delayed_work(&motg->chg_work, delay);
1090}
1091
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05301092/*
1093 * We support OTG, Peripheral only and Host only configurations. In case
1094 * of OTG, mode switch (host-->peripheral/peripheral-->host) can happen
1095 * via Id pin status or user request (debugfs). Id/BSV interrupts are not
1096 * enabled when switch is controlled by user and default mode is supplied
1097 * by board file, which can be changed by userspace later.
1098 */
1099static void msm_otg_init_sm(struct msm_otg *motg)
1100{
1101 struct msm_otg_platform_data *pdata = motg->pdata;
1102 u32 otgsc = readl(USB_OTGSC);
1103
1104 switch (pdata->mode) {
1105 case USB_OTG:
1106 if (pdata->otg_control == OTG_PHY_CONTROL) {
1107 if (otgsc & OTGSC_ID)
1108 set_bit(ID, &motg->inputs);
1109 else
1110 clear_bit(ID, &motg->inputs);
1111
1112 if (otgsc & OTGSC_BSV)
1113 set_bit(B_SESS_VLD, &motg->inputs);
1114 else
1115 clear_bit(B_SESS_VLD, &motg->inputs);
1116 } else if (pdata->otg_control == OTG_USER_CONTROL) {
1117 if (pdata->default_mode == USB_HOST) {
1118 clear_bit(ID, &motg->inputs);
1119 } else if (pdata->default_mode == USB_PERIPHERAL) {
1120 set_bit(ID, &motg->inputs);
1121 set_bit(B_SESS_VLD, &motg->inputs);
1122 } else {
1123 set_bit(ID, &motg->inputs);
1124 clear_bit(B_SESS_VLD, &motg->inputs);
1125 }
1126 }
1127 break;
1128 case USB_HOST:
1129 clear_bit(ID, &motg->inputs);
1130 break;
1131 case USB_PERIPHERAL:
1132 set_bit(ID, &motg->inputs);
1133 if (otgsc & OTGSC_BSV)
1134 set_bit(B_SESS_VLD, &motg->inputs);
1135 else
1136 clear_bit(B_SESS_VLD, &motg->inputs);
1137 break;
1138 default:
1139 break;
1140 }
1141}
1142
1143static void msm_otg_sm_work(struct work_struct *w)
1144{
1145 struct msm_otg *motg = container_of(w, struct msm_otg, sm_work);
Heikki Krogerus1d4c9292012-02-13 13:24:09 +02001146 struct usb_otg *otg = motg->phy.otg;
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05301147
Heikki Krogerus1d4c9292012-02-13 13:24:09 +02001148 switch (otg->phy->state) {
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05301149 case OTG_STATE_UNDEFINED:
Heikki Krogerus1d4c9292012-02-13 13:24:09 +02001150 dev_dbg(otg->phy->dev, "OTG_STATE_UNDEFINED state\n");
1151 msm_otg_reset(otg->phy);
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05301152 msm_otg_init_sm(motg);
Heikki Krogerus1d4c9292012-02-13 13:24:09 +02001153 otg->phy->state = OTG_STATE_B_IDLE;
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05301154 /* FALL THROUGH */
1155 case OTG_STATE_B_IDLE:
Heikki Krogerus1d4c9292012-02-13 13:24:09 +02001156 dev_dbg(otg->phy->dev, "OTG_STATE_B_IDLE state\n");
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05301157 if (!test_bit(ID, &motg->inputs) && otg->host) {
1158 /* disable BSV bit */
1159 writel(readl(USB_OTGSC) & ~OTGSC_BSVIE, USB_OTGSC);
Heikki Krogerus1d4c9292012-02-13 13:24:09 +02001160 msm_otg_start_host(otg->phy, 1);
1161 otg->phy->state = OTG_STATE_A_HOST;
Pavankumar Kondetid8608522011-05-04 10:19:47 +05301162 } else if (test_bit(B_SESS_VLD, &motg->inputs)) {
1163 switch (motg->chg_state) {
1164 case USB_CHG_STATE_UNDEFINED:
1165 msm_chg_detect_work(&motg->chg_work.work);
1166 break;
1167 case USB_CHG_STATE_DETECTED:
1168 switch (motg->chg_type) {
1169 case USB_DCP_CHARGER:
1170 msm_otg_notify_charger(motg,
1171 IDEV_CHG_MAX);
1172 break;
1173 case USB_CDP_CHARGER:
1174 msm_otg_notify_charger(motg,
1175 IDEV_CHG_MAX);
Heikki Krogerus1d4c9292012-02-13 13:24:09 +02001176 msm_otg_start_peripheral(otg->phy, 1);
1177 otg->phy->state
1178 = OTG_STATE_B_PERIPHERAL;
Pavankumar Kondetid8608522011-05-04 10:19:47 +05301179 break;
1180 case USB_SDP_CHARGER:
1181 msm_otg_notify_charger(motg, IUNIT);
Heikki Krogerus1d4c9292012-02-13 13:24:09 +02001182 msm_otg_start_peripheral(otg->phy, 1);
1183 otg->phy->state
1184 = OTG_STATE_B_PERIPHERAL;
Pavankumar Kondetid8608522011-05-04 10:19:47 +05301185 break;
1186 default:
1187 break;
1188 }
1189 break;
1190 default:
1191 break;
1192 }
1193 } else {
1194 /*
1195 * If charger detection work is pending, decrement
1196 * the pm usage counter to balance with the one that
1197 * is incremented in charger detection work.
1198 */
1199 if (cancel_delayed_work_sync(&motg->chg_work)) {
Heikki Krogerus1d4c9292012-02-13 13:24:09 +02001200 pm_runtime_put_sync(otg->phy->dev);
1201 msm_otg_reset(otg->phy);
Pavankumar Kondetid8608522011-05-04 10:19:47 +05301202 }
1203 msm_otg_notify_charger(motg, 0);
1204 motg->chg_state = USB_CHG_STATE_UNDEFINED;
1205 motg->chg_type = USB_INVALID_CHARGER;
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05301206 }
Heikki Krogerus1d4c9292012-02-13 13:24:09 +02001207 pm_runtime_put_sync(otg->phy->dev);
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05301208 break;
1209 case OTG_STATE_B_PERIPHERAL:
Heikki Krogerus1d4c9292012-02-13 13:24:09 +02001210 dev_dbg(otg->phy->dev, "OTG_STATE_B_PERIPHERAL state\n");
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05301211 if (!test_bit(B_SESS_VLD, &motg->inputs) ||
1212 !test_bit(ID, &motg->inputs)) {
Pavankumar Kondetid8608522011-05-04 10:19:47 +05301213 msm_otg_notify_charger(motg, 0);
Heikki Krogerus1d4c9292012-02-13 13:24:09 +02001214 msm_otg_start_peripheral(otg->phy, 0);
Pavankumar Kondetid8608522011-05-04 10:19:47 +05301215 motg->chg_state = USB_CHG_STATE_UNDEFINED;
1216 motg->chg_type = USB_INVALID_CHARGER;
Heikki Krogerus1d4c9292012-02-13 13:24:09 +02001217 otg->phy->state = OTG_STATE_B_IDLE;
1218 msm_otg_reset(otg->phy);
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05301219 schedule_work(w);
1220 }
1221 break;
1222 case OTG_STATE_A_HOST:
Heikki Krogerus1d4c9292012-02-13 13:24:09 +02001223 dev_dbg(otg->phy->dev, "OTG_STATE_A_HOST state\n");
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05301224 if (test_bit(ID, &motg->inputs)) {
Heikki Krogerus1d4c9292012-02-13 13:24:09 +02001225 msm_otg_start_host(otg->phy, 0);
1226 otg->phy->state = OTG_STATE_B_IDLE;
1227 msm_otg_reset(otg->phy);
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05301228 schedule_work(w);
1229 }
1230 break;
1231 default:
1232 break;
1233 }
1234}
1235
1236static irqreturn_t msm_otg_irq(int irq, void *data)
1237{
1238 struct msm_otg *motg = data;
Heikki Krogerus1d4c9292012-02-13 13:24:09 +02001239 struct usb_phy *phy = &motg->phy;
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05301240 u32 otgsc = 0;
1241
Pavankumar Kondeti87c01042010-12-07 17:53:58 +05301242 if (atomic_read(&motg->in_lpm)) {
1243 disable_irq_nosync(irq);
1244 motg->async_int = 1;
Heikki Krogerus1d4c9292012-02-13 13:24:09 +02001245 pm_runtime_get(phy->dev);
Pavankumar Kondeti87c01042010-12-07 17:53:58 +05301246 return IRQ_HANDLED;
1247 }
1248
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05301249 otgsc = readl(USB_OTGSC);
1250 if (!(otgsc & (OTGSC_IDIS | OTGSC_BSVIS)))
1251 return IRQ_NONE;
1252
1253 if ((otgsc & OTGSC_IDIS) && (otgsc & OTGSC_IDIE)) {
1254 if (otgsc & OTGSC_ID)
1255 set_bit(ID, &motg->inputs);
1256 else
1257 clear_bit(ID, &motg->inputs);
Heikki Krogerus1d4c9292012-02-13 13:24:09 +02001258 dev_dbg(phy->dev, "ID set/clear\n");
1259 pm_runtime_get_noresume(phy->dev);
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05301260 } else if ((otgsc & OTGSC_BSVIS) && (otgsc & OTGSC_BSVIE)) {
1261 if (otgsc & OTGSC_BSV)
1262 set_bit(B_SESS_VLD, &motg->inputs);
1263 else
1264 clear_bit(B_SESS_VLD, &motg->inputs);
Heikki Krogerus1d4c9292012-02-13 13:24:09 +02001265 dev_dbg(phy->dev, "BSV set/clear\n");
1266 pm_runtime_get_noresume(phy->dev);
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05301267 }
1268
1269 writel(otgsc, USB_OTGSC);
1270 schedule_work(&motg->sm_work);
1271 return IRQ_HANDLED;
1272}
1273
1274static int msm_otg_mode_show(struct seq_file *s, void *unused)
1275{
1276 struct msm_otg *motg = s->private;
Heikki Krogerus1d4c9292012-02-13 13:24:09 +02001277 struct usb_otg *otg = motg->phy.otg;
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05301278
Heikki Krogerus1d4c9292012-02-13 13:24:09 +02001279 switch (otg->phy->state) {
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05301280 case OTG_STATE_A_HOST:
1281 seq_printf(s, "host\n");
1282 break;
1283 case OTG_STATE_B_PERIPHERAL:
1284 seq_printf(s, "peripheral\n");
1285 break;
1286 default:
1287 seq_printf(s, "none\n");
1288 break;
1289 }
1290
1291 return 0;
1292}
1293
1294static int msm_otg_mode_open(struct inode *inode, struct file *file)
1295{
1296 return single_open(file, msm_otg_mode_show, inode->i_private);
1297}
1298
1299static ssize_t msm_otg_mode_write(struct file *file, const char __user *ubuf,
1300 size_t count, loff_t *ppos)
1301{
Pavankumar Kondetie2904ee2011-02-15 09:42:35 +05301302 struct seq_file *s = file->private_data;
1303 struct msm_otg *motg = s->private;
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05301304 char buf[16];
Heikki Krogerus1d4c9292012-02-13 13:24:09 +02001305 struct usb_otg *otg = motg->phy.otg;
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05301306 int status = count;
1307 enum usb_mode_type req_mode;
1308
1309 memset(buf, 0x00, sizeof(buf));
1310
1311 if (copy_from_user(&buf, ubuf, min_t(size_t, sizeof(buf) - 1, count))) {
1312 status = -EFAULT;
1313 goto out;
1314 }
1315
1316 if (!strncmp(buf, "host", 4)) {
1317 req_mode = USB_HOST;
1318 } else if (!strncmp(buf, "peripheral", 10)) {
1319 req_mode = USB_PERIPHERAL;
1320 } else if (!strncmp(buf, "none", 4)) {
1321 req_mode = USB_NONE;
1322 } else {
1323 status = -EINVAL;
1324 goto out;
1325 }
1326
1327 switch (req_mode) {
1328 case USB_NONE:
Heikki Krogerus1d4c9292012-02-13 13:24:09 +02001329 switch (otg->phy->state) {
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05301330 case OTG_STATE_A_HOST:
1331 case OTG_STATE_B_PERIPHERAL:
1332 set_bit(ID, &motg->inputs);
1333 clear_bit(B_SESS_VLD, &motg->inputs);
1334 break;
1335 default:
1336 goto out;
1337 }
1338 break;
1339 case USB_PERIPHERAL:
Heikki Krogerus1d4c9292012-02-13 13:24:09 +02001340 switch (otg->phy->state) {
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05301341 case OTG_STATE_B_IDLE:
1342 case OTG_STATE_A_HOST:
1343 set_bit(ID, &motg->inputs);
1344 set_bit(B_SESS_VLD, &motg->inputs);
1345 break;
1346 default:
1347 goto out;
1348 }
1349 break;
1350 case USB_HOST:
Heikki Krogerus1d4c9292012-02-13 13:24:09 +02001351 switch (otg->phy->state) {
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05301352 case OTG_STATE_B_IDLE:
1353 case OTG_STATE_B_PERIPHERAL:
1354 clear_bit(ID, &motg->inputs);
1355 break;
1356 default:
1357 goto out;
1358 }
1359 break;
1360 default:
1361 goto out;
1362 }
1363
Heikki Krogerus1d4c9292012-02-13 13:24:09 +02001364 pm_runtime_get_sync(otg->phy->dev);
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05301365 schedule_work(&motg->sm_work);
1366out:
1367 return status;
1368}
1369
1370const struct file_operations msm_otg_mode_fops = {
1371 .open = msm_otg_mode_open,
1372 .read = seq_read,
1373 .write = msm_otg_mode_write,
1374 .llseek = seq_lseek,
1375 .release = single_release,
1376};
1377
1378static struct dentry *msm_otg_dbg_root;
1379static struct dentry *msm_otg_dbg_mode;
1380
1381static int msm_otg_debugfs_init(struct msm_otg *motg)
1382{
1383 msm_otg_dbg_root = debugfs_create_dir("msm_otg", NULL);
1384
1385 if (!msm_otg_dbg_root || IS_ERR(msm_otg_dbg_root))
1386 return -ENODEV;
1387
1388 msm_otg_dbg_mode = debugfs_create_file("mode", S_IRUGO | S_IWUSR,
1389 msm_otg_dbg_root, motg, &msm_otg_mode_fops);
1390 if (!msm_otg_dbg_mode) {
1391 debugfs_remove(msm_otg_dbg_root);
1392 msm_otg_dbg_root = NULL;
1393 return -ENODEV;
1394 }
1395
1396 return 0;
1397}
1398
1399static void msm_otg_debugfs_cleanup(void)
1400{
1401 debugfs_remove(msm_otg_dbg_mode);
1402 debugfs_remove(msm_otg_dbg_root);
1403}
1404
1405static int __init msm_otg_probe(struct platform_device *pdev)
1406{
1407 int ret = 0;
1408 struct resource *res;
1409 struct msm_otg *motg;
Heikki Krogerus1d4c9292012-02-13 13:24:09 +02001410 struct usb_phy *phy;
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05301411
1412 dev_info(&pdev->dev, "msm_otg probe\n");
Jingoo Han19f9e182013-07-30 17:02:13 +09001413 if (!dev_get_platdata(&pdev->dev)) {
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05301414 dev_err(&pdev->dev, "No platform data given. Bailing out\n");
1415 return -ENODEV;
1416 }
1417
1418 motg = kzalloc(sizeof(struct msm_otg), GFP_KERNEL);
1419 if (!motg) {
1420 dev_err(&pdev->dev, "unable to allocate msm_otg\n");
1421 return -ENOMEM;
1422 }
1423
Heikki Krogerus1d4c9292012-02-13 13:24:09 +02001424 motg->phy.otg = kzalloc(sizeof(struct usb_otg), GFP_KERNEL);
1425 if (!motg->phy.otg) {
1426 dev_err(&pdev->dev, "unable to allocate msm_otg\n");
Dan Carpenter5c73e742014-01-21 09:50:51 +03001427 ret = -ENOMEM;
1428 goto free_motg;
Heikki Krogerus1d4c9292012-02-13 13:24:09 +02001429 }
1430
Jingoo Han19f9e182013-07-30 17:02:13 +09001431 motg->pdata = dev_get_platdata(&pdev->dev);
Heikki Krogerus1d4c9292012-02-13 13:24:09 +02001432 phy = &motg->phy;
1433 phy->dev = &pdev->dev;
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05301434
1435 motg->phy_reset_clk = clk_get(&pdev->dev, "usb_phy_clk");
1436 if (IS_ERR(motg->phy_reset_clk)) {
1437 dev_err(&pdev->dev, "failed to get usb_phy_clk\n");
1438 ret = PTR_ERR(motg->phy_reset_clk);
1439 goto free_motg;
1440 }
1441
1442 motg->clk = clk_get(&pdev->dev, "usb_hs_clk");
1443 if (IS_ERR(motg->clk)) {
1444 dev_err(&pdev->dev, "failed to get usb_hs_clk\n");
1445 ret = PTR_ERR(motg->clk);
1446 goto put_phy_reset_clk;
1447 }
Anji jonnala0f73cac2011-05-04 10:19:46 +05301448 clk_set_rate(motg->clk, 60000000);
1449
1450 /*
1451 * If USB Core is running its protocol engine based on CORE CLK,
1452 * CORE CLK must be running at >55Mhz for correct HSUSB
1453 * operation and USB core cannot tolerate frequency changes on
1454 * CORE CLK. For such USB cores, vote for maximum clk frequency
1455 * on pclk source
1456 */
1457 if (motg->pdata->pclk_src_name) {
1458 motg->pclk_src = clk_get(&pdev->dev,
1459 motg->pdata->pclk_src_name);
1460 if (IS_ERR(motg->pclk_src))
1461 goto put_clk;
1462 clk_set_rate(motg->pclk_src, INT_MAX);
Stephen Boydb99a8f62013-06-17 10:43:10 -07001463 clk_prepare_enable(motg->pclk_src);
Anji jonnala0f73cac2011-05-04 10:19:46 +05301464 } else
1465 motg->pclk_src = ERR_PTR(-ENOENT);
1466
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05301467
1468 motg->pclk = clk_get(&pdev->dev, "usb_hs_pclk");
1469 if (IS_ERR(motg->pclk)) {
1470 dev_err(&pdev->dev, "failed to get usb_hs_pclk\n");
1471 ret = PTR_ERR(motg->pclk);
Anji jonnala0f73cac2011-05-04 10:19:46 +05301472 goto put_pclk_src;
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05301473 }
1474
1475 /*
1476 * USB core clock is not present on all MSM chips. This
1477 * clock is introduced to remove the dependency on AXI
1478 * bus frequency.
1479 */
1480 motg->core_clk = clk_get(&pdev->dev, "usb_hs_core_clk");
1481 if (IS_ERR(motg->core_clk))
1482 motg->core_clk = NULL;
1483
1484 res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
1485 if (!res) {
1486 dev_err(&pdev->dev, "failed to get platform resource mem\n");
1487 ret = -ENODEV;
1488 goto put_core_clk;
1489 }
1490
1491 motg->regs = ioremap(res->start, resource_size(res));
1492 if (!motg->regs) {
1493 dev_err(&pdev->dev, "ioremap failed\n");
1494 ret = -ENOMEM;
1495 goto put_core_clk;
1496 }
1497 dev_info(&pdev->dev, "OTG regs = %p\n", motg->regs);
1498
1499 motg->irq = platform_get_irq(pdev, 0);
1500 if (!motg->irq) {
1501 dev_err(&pdev->dev, "platform_get_irq failed\n");
1502 ret = -ENODEV;
1503 goto free_regs;
1504 }
1505
Stephen Boydb99a8f62013-06-17 10:43:10 -07001506 clk_prepare_enable(motg->clk);
1507 clk_prepare_enable(motg->pclk);
Anji jonnala11aa5c42011-05-04 10:19:48 +05301508
1509 ret = msm_hsusb_init_vddcx(motg, 1);
1510 if (ret) {
1511 dev_err(&pdev->dev, "hsusb vddcx configuration failed\n");
1512 goto free_regs;
1513 }
1514
1515 ret = msm_hsusb_ldo_init(motg, 1);
1516 if (ret) {
1517 dev_err(&pdev->dev, "hsusb vreg configuration failed\n");
1518 goto vddcx_exit;
1519 }
Ivan T. Ivanov37cfdaf2014-04-28 16:34:06 +03001520 ret = msm_hsusb_ldo_set_mode(motg, 1);
Anji jonnala11aa5c42011-05-04 10:19:48 +05301521 if (ret) {
1522 dev_err(&pdev->dev, "hsusb vreg enable failed\n");
1523 goto ldo_exit;
1524 }
1525
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05301526 if (motg->core_clk)
Stephen Boydb99a8f62013-06-17 10:43:10 -07001527 clk_prepare_enable(motg->core_clk);
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05301528
1529 writel(0, USB_USBINTR);
1530 writel(0, USB_OTGSC);
1531
1532 INIT_WORK(&motg->sm_work, msm_otg_sm_work);
Pavankumar Kondetid8608522011-05-04 10:19:47 +05301533 INIT_DELAYED_WORK(&motg->chg_work, msm_chg_detect_work);
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05301534 ret = request_irq(motg->irq, msm_otg_irq, IRQF_SHARED,
1535 "msm_otg", motg);
1536 if (ret) {
1537 dev_err(&pdev->dev, "request irq failed\n");
1538 goto disable_clks;
1539 }
1540
Heikki Krogerus1d4c9292012-02-13 13:24:09 +02001541 phy->init = msm_otg_reset;
1542 phy->set_power = msm_otg_set_power;
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05301543
Heikki Krogerus1d4c9292012-02-13 13:24:09 +02001544 phy->io_ops = &msm_otg_io_ops;
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05301545
Heikki Krogerus1d4c9292012-02-13 13:24:09 +02001546 phy->otg->phy = &motg->phy;
1547 phy->otg->set_host = msm_otg_set_host;
1548 phy->otg->set_peripheral = msm_otg_set_peripheral;
1549
Kishon Vijay Abraham I662dca52012-06-22 17:02:46 +05301550 ret = usb_add_phy(&motg->phy, USB_PHY_TYPE_USB2);
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05301551 if (ret) {
Kishon Vijay Abraham I721002e2012-06-22 17:02:45 +05301552 dev_err(&pdev->dev, "usb_add_phy failed\n");
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05301553 goto free_irq;
1554 }
1555
1556 platform_set_drvdata(pdev, motg);
1557 device_init_wakeup(&pdev->dev, 1);
1558
1559 if (motg->pdata->mode == USB_OTG &&
1560 motg->pdata->otg_control == OTG_USER_CONTROL) {
1561 ret = msm_otg_debugfs_init(motg);
1562 if (ret)
1563 dev_dbg(&pdev->dev, "mode debugfs file is"
1564 "not available\n");
1565 }
1566
Pavankumar Kondeti87c01042010-12-07 17:53:58 +05301567 pm_runtime_set_active(&pdev->dev);
1568 pm_runtime_enable(&pdev->dev);
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05301569
Pavankumar Kondeti87c01042010-12-07 17:53:58 +05301570 return 0;
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05301571free_irq:
1572 free_irq(motg->irq, motg);
1573disable_clks:
Stephen Boydb99a8f62013-06-17 10:43:10 -07001574 clk_disable_unprepare(motg->pclk);
1575 clk_disable_unprepare(motg->clk);
Anji jonnala11aa5c42011-05-04 10:19:48 +05301576ldo_exit:
1577 msm_hsusb_ldo_init(motg, 0);
1578vddcx_exit:
1579 msm_hsusb_init_vddcx(motg, 0);
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05301580free_regs:
1581 iounmap(motg->regs);
1582put_core_clk:
1583 if (motg->core_clk)
1584 clk_put(motg->core_clk);
1585 clk_put(motg->pclk);
Anji jonnala0f73cac2011-05-04 10:19:46 +05301586put_pclk_src:
1587 if (!IS_ERR(motg->pclk_src)) {
Stephen Boydb99a8f62013-06-17 10:43:10 -07001588 clk_disable_unprepare(motg->pclk_src);
Anji jonnala0f73cac2011-05-04 10:19:46 +05301589 clk_put(motg->pclk_src);
1590 }
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05301591put_clk:
1592 clk_put(motg->clk);
1593put_phy_reset_clk:
1594 clk_put(motg->phy_reset_clk);
1595free_motg:
Heikki Krogerus1d4c9292012-02-13 13:24:09 +02001596 kfree(motg->phy.otg);
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05301597 kfree(motg);
1598 return ret;
1599}
1600
Bill Pembertonfb4e98a2012-11-19 13:26:20 -05001601static int msm_otg_remove(struct platform_device *pdev)
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05301602{
1603 struct msm_otg *motg = platform_get_drvdata(pdev);
Heikki Krogerus1d4c9292012-02-13 13:24:09 +02001604 struct usb_phy *phy = &motg->phy;
Pavankumar Kondeti87c01042010-12-07 17:53:58 +05301605 int cnt = 0;
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05301606
Heikki Krogerus1d4c9292012-02-13 13:24:09 +02001607 if (phy->otg->host || phy->otg->gadget)
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05301608 return -EBUSY;
1609
1610 msm_otg_debugfs_cleanup();
Pavankumar Kondetid8608522011-05-04 10:19:47 +05301611 cancel_delayed_work_sync(&motg->chg_work);
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05301612 cancel_work_sync(&motg->sm_work);
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05301613
Pavankumar Kondeti70187732011-02-15 09:42:34 +05301614 pm_runtime_resume(&pdev->dev);
Pavankumar Kondeti87c01042010-12-07 17:53:58 +05301615
1616 device_init_wakeup(&pdev->dev, 0);
1617 pm_runtime_disable(&pdev->dev);
1618
Kishon Vijay Abraham I662dca52012-06-22 17:02:46 +05301619 usb_remove_phy(phy);
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05301620 free_irq(motg->irq, motg);
1621
Pavankumar Kondeti87c01042010-12-07 17:53:58 +05301622 /*
1623 * Put PHY in low power mode.
1624 */
Heikki Krogerus1d4c9292012-02-13 13:24:09 +02001625 ulpi_read(phy, 0x14);
1626 ulpi_write(phy, 0x08, 0x09);
Pavankumar Kondeti87c01042010-12-07 17:53:58 +05301627
1628 writel(readl(USB_PORTSC) | PORTSC_PHCD, USB_PORTSC);
1629 while (cnt < PHY_SUSPEND_TIMEOUT_USEC) {
1630 if (readl(USB_PORTSC) & PORTSC_PHCD)
1631 break;
1632 udelay(1);
1633 cnt++;
1634 }
1635 if (cnt >= PHY_SUSPEND_TIMEOUT_USEC)
Heikki Krogerus1d4c9292012-02-13 13:24:09 +02001636 dev_err(phy->dev, "Unable to suspend PHY\n");
Pavankumar Kondeti87c01042010-12-07 17:53:58 +05301637
Stephen Boydb99a8f62013-06-17 10:43:10 -07001638 clk_disable_unprepare(motg->pclk);
1639 clk_disable_unprepare(motg->clk);
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05301640 if (motg->core_clk)
Stephen Boydb99a8f62013-06-17 10:43:10 -07001641 clk_disable_unprepare(motg->core_clk);
Anji jonnala0f73cac2011-05-04 10:19:46 +05301642 if (!IS_ERR(motg->pclk_src)) {
Stephen Boydb99a8f62013-06-17 10:43:10 -07001643 clk_disable_unprepare(motg->pclk_src);
Anji jonnala0f73cac2011-05-04 10:19:46 +05301644 clk_put(motg->pclk_src);
1645 }
Anji jonnala11aa5c42011-05-04 10:19:48 +05301646 msm_hsusb_ldo_init(motg, 0);
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05301647
1648 iounmap(motg->regs);
Pavankumar Kondeti87c01042010-12-07 17:53:58 +05301649 pm_runtime_set_suspended(&pdev->dev);
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05301650
1651 clk_put(motg->phy_reset_clk);
1652 clk_put(motg->pclk);
1653 clk_put(motg->clk);
1654 if (motg->core_clk)
1655 clk_put(motg->core_clk);
1656
Heikki Krogerus1d4c9292012-02-13 13:24:09 +02001657 kfree(motg->phy.otg);
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05301658 kfree(motg);
1659
1660 return 0;
1661}
1662
Pavankumar Kondeti87c01042010-12-07 17:53:58 +05301663#ifdef CONFIG_PM_RUNTIME
1664static int msm_otg_runtime_idle(struct device *dev)
1665{
1666 struct msm_otg *motg = dev_get_drvdata(dev);
Heikki Krogerus1d4c9292012-02-13 13:24:09 +02001667 struct usb_otg *otg = motg->phy.otg;
Pavankumar Kondeti87c01042010-12-07 17:53:58 +05301668
1669 dev_dbg(dev, "OTG runtime idle\n");
1670
1671 /*
1672 * It is observed some times that a spurious interrupt
1673 * comes when PHY is put into LPM immediately after PHY reset.
1674 * This 1 sec delay also prevents entering into LPM immediately
1675 * after asynchronous interrupt.
1676 */
Heikki Krogerus1d4c9292012-02-13 13:24:09 +02001677 if (otg->phy->state != OTG_STATE_UNDEFINED)
Pavankumar Kondeti87c01042010-12-07 17:53:58 +05301678 pm_schedule_suspend(dev, 1000);
1679
1680 return -EAGAIN;
1681}
1682
1683static int msm_otg_runtime_suspend(struct device *dev)
1684{
1685 struct msm_otg *motg = dev_get_drvdata(dev);
1686
1687 dev_dbg(dev, "OTG runtime suspend\n");
1688 return msm_otg_suspend(motg);
1689}
1690
1691static int msm_otg_runtime_resume(struct device *dev)
1692{
1693 struct msm_otg *motg = dev_get_drvdata(dev);
1694
1695 dev_dbg(dev, "OTG runtime resume\n");
1696 return msm_otg_resume(motg);
1697}
Pavankumar Kondeti87c01042010-12-07 17:53:58 +05301698#endif
1699
Pavankumar Kondeti70187732011-02-15 09:42:34 +05301700#ifdef CONFIG_PM_SLEEP
Pavankumar Kondeti87c01042010-12-07 17:53:58 +05301701static int msm_otg_pm_suspend(struct device *dev)
1702{
1703 struct msm_otg *motg = dev_get_drvdata(dev);
1704
1705 dev_dbg(dev, "OTG PM suspend\n");
1706 return msm_otg_suspend(motg);
1707}
1708
1709static int msm_otg_pm_resume(struct device *dev)
1710{
1711 struct msm_otg *motg = dev_get_drvdata(dev);
1712 int ret;
1713
1714 dev_dbg(dev, "OTG PM resume\n");
1715
1716 ret = msm_otg_resume(motg);
1717 if (ret)
1718 return ret;
1719
1720 /*
1721 * Runtime PM Documentation recommends bringing the
1722 * device to full powered state upon resume.
1723 */
1724 pm_runtime_disable(dev);
1725 pm_runtime_set_active(dev);
1726 pm_runtime_enable(dev);
1727
1728 return 0;
1729}
Pavankumar Kondeti87c01042010-12-07 17:53:58 +05301730#endif
1731
1732static const struct dev_pm_ops msm_otg_dev_pm_ops = {
Pavankumar Kondeti70187732011-02-15 09:42:34 +05301733 SET_SYSTEM_SLEEP_PM_OPS(msm_otg_pm_suspend, msm_otg_pm_resume)
1734 SET_RUNTIME_PM_OPS(msm_otg_runtime_suspend, msm_otg_runtime_resume,
1735 msm_otg_runtime_idle)
Pavankumar Kondeti87c01042010-12-07 17:53:58 +05301736};
1737
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05301738static struct platform_driver msm_otg_driver = {
Bill Pemberton76904172012-11-19 13:21:08 -05001739 .remove = msm_otg_remove,
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05301740 .driver = {
1741 .name = DRIVER_NAME,
1742 .owner = THIS_MODULE,
Pavankumar Kondeti87c01042010-12-07 17:53:58 +05301743 .pm = &msm_otg_dev_pm_ops,
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05301744 },
1745};
1746
Fabio Porcedda52f7a822013-01-09 12:15:28 +01001747module_platform_driver_probe(msm_otg_driver, msm_otg_probe);
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05301748
1749MODULE_LICENSE("GPL v2");
1750MODULE_DESCRIPTION("MSM USB transceiver driver");