blob: db8d963776202897968b51b11ab902c4e9f5db20 [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>
Ivan T. Ivanov8364f9a2014-04-28 16:34:15 +030033#include <linux/of.h>
34#include <linux/of_device.h>
Ivan T. Ivanova2734542014-04-28 16:34:16 +030035#include <linux/reset.h>
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +053036
37#include <linux/usb.h>
38#include <linux/usb/otg.h>
Ivan T. Ivanov8364f9a2014-04-28 16:34:15 +030039#include <linux/usb/of.h>
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +053040#include <linux/usb/ulpi.h>
41#include <linux/usb/gadget.h>
42#include <linux/usb/hcd.h>
43#include <linux/usb/msm_hsusb.h>
44#include <linux/usb/msm_hsusb_hw.h>
Anji jonnala11aa5c42011-05-04 10:19:48 +053045#include <linux/regulator/consumer.h>
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +053046
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +053047#define MSM_USB_BASE (motg->regs)
48#define DRIVER_NAME "msm_otg"
49
50#define ULPI_IO_TIMEOUT_USEC (10 * 1000)
Ivan T. Ivanovd69c6f52014-04-28 16:34:18 +030051#define LINK_RESET_TIMEOUT_USEC (250 * 1000)
Anji jonnala11aa5c42011-05-04 10:19:48 +053052
53#define USB_PHY_3P3_VOL_MIN 3050000 /* uV */
54#define USB_PHY_3P3_VOL_MAX 3300000 /* uV */
55#define USB_PHY_3P3_HPM_LOAD 50000 /* uA */
56#define USB_PHY_3P3_LPM_LOAD 4000 /* uA */
57
58#define USB_PHY_1P8_VOL_MIN 1800000 /* uV */
59#define USB_PHY_1P8_VOL_MAX 1800000 /* uV */
60#define USB_PHY_1P8_HPM_LOAD 50000 /* uA */
61#define USB_PHY_1P8_LPM_LOAD 4000 /* uA */
62
63#define USB_PHY_VDD_DIG_VOL_MIN 1000000 /* uV */
64#define USB_PHY_VDD_DIG_VOL_MAX 1320000 /* uV */
65
Anji jonnala11aa5c42011-05-04 10:19:48 +053066static int msm_hsusb_init_vddcx(struct msm_otg *motg, int init)
67{
68 int ret = 0;
69
70 if (init) {
Ivan T. Ivanov37cfdaf2014-04-28 16:34:06 +030071 ret = regulator_set_voltage(motg->vddcx,
Anji jonnala11aa5c42011-05-04 10:19:48 +053072 USB_PHY_VDD_DIG_VOL_MIN,
73 USB_PHY_VDD_DIG_VOL_MAX);
74 if (ret) {
Ivan T. Ivanov3aca0fa2014-04-28 16:34:10 +030075 dev_err(motg->phy.dev, "Cannot set vddcx voltage\n");
Anji jonnala11aa5c42011-05-04 10:19:48 +053076 return ret;
77 }
78
Ivan T. Ivanov37cfdaf2014-04-28 16:34:06 +030079 ret = regulator_enable(motg->vddcx);
Ivan T. Ivanov6b99c68e2014-04-28 16:34:08 +030080 if (ret)
Heikki Krogerus1d4c9292012-02-13 13:24:09 +020081 dev_err(motg->phy.dev, "unable to enable hsusb vddcx\n");
Anji jonnala11aa5c42011-05-04 10:19:48 +053082 } else {
Ivan T. Ivanov37cfdaf2014-04-28 16:34:06 +030083 ret = regulator_set_voltage(motg->vddcx, 0,
Mark Brown7b521fc2011-05-15 09:55:57 -070084 USB_PHY_VDD_DIG_VOL_MAX);
Mark Browne99c4302011-05-15 09:55:58 -070085 if (ret)
Ivan T. Ivanov3aca0fa2014-04-28 16:34:10 +030086 dev_err(motg->phy.dev, "Cannot set vddcx voltage\n");
Ivan T. Ivanov37cfdaf2014-04-28 16:34:06 +030087 ret = regulator_disable(motg->vddcx);
Anji jonnala11aa5c42011-05-04 10:19:48 +053088 if (ret)
Heikki Krogerus1d4c9292012-02-13 13:24:09 +020089 dev_err(motg->phy.dev, "unable to disable hsusb vddcx\n");
Anji jonnala11aa5c42011-05-04 10:19:48 +053090 }
91
92 return ret;
93}
94
95static int msm_hsusb_ldo_init(struct msm_otg *motg, int init)
96{
97 int rc = 0;
98
99 if (init) {
Ivan T. Ivanov37cfdaf2014-04-28 16:34:06 +0300100 rc = regulator_set_voltage(motg->v3p3, USB_PHY_3P3_VOL_MIN,
Anji jonnala11aa5c42011-05-04 10:19:48 +0530101 USB_PHY_3P3_VOL_MAX);
102 if (rc) {
Ivan T. Ivanov3aca0fa2014-04-28 16:34:10 +0300103 dev_err(motg->phy.dev, "Cannot set v3p3 voltage\n");
Ivan T. Ivanov6b99c68e2014-04-28 16:34:08 +0300104 goto exit;
Anji jonnala11aa5c42011-05-04 10:19:48 +0530105 }
Ivan T. Ivanov37cfdaf2014-04-28 16:34:06 +0300106 rc = regulator_enable(motg->v3p3);
Anji jonnala11aa5c42011-05-04 10:19:48 +0530107 if (rc) {
Heikki Krogerus1d4c9292012-02-13 13:24:09 +0200108 dev_err(motg->phy.dev, "unable to enable the hsusb 3p3\n");
Ivan T. Ivanov6b99c68e2014-04-28 16:34:08 +0300109 goto exit;
Anji jonnala11aa5c42011-05-04 10:19:48 +0530110 }
Ivan T. Ivanov37cfdaf2014-04-28 16:34:06 +0300111 rc = regulator_set_voltage(motg->v1p8, USB_PHY_1P8_VOL_MIN,
Anji jonnala11aa5c42011-05-04 10:19:48 +0530112 USB_PHY_1P8_VOL_MAX);
113 if (rc) {
Ivan T. Ivanov3aca0fa2014-04-28 16:34:10 +0300114 dev_err(motg->phy.dev, "Cannot set v1p8 voltage\n");
Ivan T. Ivanov6b99c68e2014-04-28 16:34:08 +0300115 goto disable_3p3;
Anji jonnala11aa5c42011-05-04 10:19:48 +0530116 }
Ivan T. Ivanov37cfdaf2014-04-28 16:34:06 +0300117 rc = regulator_enable(motg->v1p8);
Anji jonnala11aa5c42011-05-04 10:19:48 +0530118 if (rc) {
Heikki Krogerus1d4c9292012-02-13 13:24:09 +0200119 dev_err(motg->phy.dev, "unable to enable the hsusb 1p8\n");
Ivan T. Ivanov6b99c68e2014-04-28 16:34:08 +0300120 goto disable_3p3;
Anji jonnala11aa5c42011-05-04 10:19:48 +0530121 }
122
123 return 0;
124 }
125
Ivan T. Ivanov37cfdaf2014-04-28 16:34:06 +0300126 regulator_disable(motg->v1p8);
Anji jonnala11aa5c42011-05-04 10:19:48 +0530127disable_3p3:
Ivan T. Ivanov37cfdaf2014-04-28 16:34:06 +0300128 regulator_disable(motg->v3p3);
Ivan T. Ivanov6b99c68e2014-04-28 16:34:08 +0300129exit:
Anji jonnala11aa5c42011-05-04 10:19:48 +0530130 return rc;
131}
132
Ivan T. Ivanov37cfdaf2014-04-28 16:34:06 +0300133static int msm_hsusb_ldo_set_mode(struct msm_otg *motg, int on)
Anji jonnala11aa5c42011-05-04 10:19:48 +0530134{
135 int ret = 0;
136
Anji jonnala11aa5c42011-05-04 10:19:48 +0530137 if (on) {
Ivan T. Ivanov37cfdaf2014-04-28 16:34:06 +0300138 ret = regulator_set_optimum_mode(motg->v1p8,
Anji jonnala11aa5c42011-05-04 10:19:48 +0530139 USB_PHY_1P8_HPM_LOAD);
140 if (ret < 0) {
Ivan T. Ivanov3aca0fa2014-04-28 16:34:10 +0300141 pr_err("Could not set HPM for v1p8\n");
Anji jonnala11aa5c42011-05-04 10:19:48 +0530142 return ret;
143 }
Ivan T. Ivanov37cfdaf2014-04-28 16:34:06 +0300144 ret = regulator_set_optimum_mode(motg->v3p3,
Anji jonnala11aa5c42011-05-04 10:19:48 +0530145 USB_PHY_3P3_HPM_LOAD);
146 if (ret < 0) {
Ivan T. Ivanov3aca0fa2014-04-28 16:34:10 +0300147 pr_err("Could not set HPM for v3p3\n");
Ivan T. Ivanov37cfdaf2014-04-28 16:34:06 +0300148 regulator_set_optimum_mode(motg->v1p8,
Anji jonnala11aa5c42011-05-04 10:19:48 +0530149 USB_PHY_1P8_LPM_LOAD);
150 return ret;
151 }
152 } else {
Ivan T. Ivanov37cfdaf2014-04-28 16:34:06 +0300153 ret = regulator_set_optimum_mode(motg->v1p8,
Anji jonnala11aa5c42011-05-04 10:19:48 +0530154 USB_PHY_1P8_LPM_LOAD);
155 if (ret < 0)
Ivan T. Ivanov3aca0fa2014-04-28 16:34:10 +0300156 pr_err("Could not set LPM for v1p8\n");
Ivan T. Ivanov37cfdaf2014-04-28 16:34:06 +0300157 ret = regulator_set_optimum_mode(motg->v3p3,
Anji jonnala11aa5c42011-05-04 10:19:48 +0530158 USB_PHY_3P3_LPM_LOAD);
159 if (ret < 0)
Ivan T. Ivanov3aca0fa2014-04-28 16:34:10 +0300160 pr_err("Could not set LPM for v3p3\n");
Anji jonnala11aa5c42011-05-04 10:19:48 +0530161 }
162
163 pr_debug("reg (%s)\n", on ? "HPM" : "LPM");
164 return ret < 0 ? ret : 0;
165}
166
Heikki Krogerus1d4c9292012-02-13 13:24:09 +0200167static int ulpi_read(struct usb_phy *phy, u32 reg)
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +0530168{
Heikki Krogerus1d4c9292012-02-13 13:24:09 +0200169 struct msm_otg *motg = container_of(phy, struct msm_otg, phy);
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +0530170 int cnt = 0;
171
172 /* initiate read operation */
173 writel(ULPI_RUN | ULPI_READ | ULPI_ADDR(reg),
174 USB_ULPI_VIEWPORT);
175
176 /* wait for completion */
177 while (cnt < ULPI_IO_TIMEOUT_USEC) {
178 if (!(readl(USB_ULPI_VIEWPORT) & ULPI_RUN))
179 break;
180 udelay(1);
181 cnt++;
182 }
183
184 if (cnt >= ULPI_IO_TIMEOUT_USEC) {
Heikki Krogerus1d4c9292012-02-13 13:24:09 +0200185 dev_err(phy->dev, "ulpi_read: timeout %08x\n",
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +0530186 readl(USB_ULPI_VIEWPORT));
187 return -ETIMEDOUT;
188 }
189 return ULPI_DATA_READ(readl(USB_ULPI_VIEWPORT));
190}
191
Heikki Krogerus1d4c9292012-02-13 13:24:09 +0200192static int ulpi_write(struct usb_phy *phy, u32 val, u32 reg)
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +0530193{
Heikki Krogerus1d4c9292012-02-13 13:24:09 +0200194 struct msm_otg *motg = container_of(phy, struct msm_otg, phy);
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +0530195 int cnt = 0;
196
197 /* initiate write operation */
198 writel(ULPI_RUN | ULPI_WRITE |
199 ULPI_ADDR(reg) | ULPI_DATA(val),
200 USB_ULPI_VIEWPORT);
201
202 /* wait for completion */
203 while (cnt < ULPI_IO_TIMEOUT_USEC) {
204 if (!(readl(USB_ULPI_VIEWPORT) & ULPI_RUN))
205 break;
206 udelay(1);
207 cnt++;
208 }
209
210 if (cnt >= ULPI_IO_TIMEOUT_USEC) {
Heikki Krogerus1d4c9292012-02-13 13:24:09 +0200211 dev_err(phy->dev, "ulpi_write: timeout\n");
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +0530212 return -ETIMEDOUT;
213 }
214 return 0;
215}
216
Heikki Krogerus1d4c9292012-02-13 13:24:09 +0200217static struct usb_phy_io_ops msm_otg_io_ops = {
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +0530218 .read = ulpi_read,
219 .write = ulpi_write,
220};
221
222static void ulpi_init(struct msm_otg *motg)
223{
224 struct msm_otg_platform_data *pdata = motg->pdata;
Ivan T. Ivanov8364f9a2014-04-28 16:34:15 +0300225 int *seq = pdata->phy_init_seq, idx;
226 u32 addr = ULPI_EXT_VENDOR_SPECIFIC;
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +0530227
Ivan T. Ivanov8364f9a2014-04-28 16:34:15 +0300228 for (idx = 0; idx < pdata->phy_init_sz; idx++) {
229 if (seq[idx] == -1)
230 continue;
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +0530231
Heikki Krogerus1d4c9292012-02-13 13:24:09 +0200232 dev_vdbg(motg->phy.dev, "ulpi: write 0x%02x to 0x%02x\n",
Ivan T. Ivanov8364f9a2014-04-28 16:34:15 +0300233 seq[idx], addr + idx);
234 ulpi_write(&motg->phy, seq[idx], addr + idx);
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +0530235 }
236}
237
238static int msm_otg_link_clk_reset(struct msm_otg *motg, bool assert)
239{
Ivan T. Ivanova2734542014-04-28 16:34:16 +0300240 int ret;
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +0530241
Ivan T. Ivanova2734542014-04-28 16:34:16 +0300242 if (motg->pdata->link_clk_reset)
243 ret = motg->pdata->link_clk_reset(motg->clk, assert);
244 else if (assert)
245 ret = reset_control_assert(motg->link_rst);
246 else
247 ret = reset_control_deassert(motg->link_rst);
Ivan T. Ivanov5146d772013-12-30 13:15:27 -0800248
Ivan T. Ivanov5146d772013-12-30 13:15:27 -0800249 if (ret)
250 dev_err(motg->phy.dev, "usb link clk reset %s failed\n",
251 assert ? "assert" : "deassert");
252
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +0530253 return ret;
254}
255
256static int msm_otg_phy_clk_reset(struct msm_otg *motg)
257{
Ivan T. Ivanova2734542014-04-28 16:34:16 +0300258 int ret;
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +0530259
Ivan T. Ivanova2734542014-04-28 16:34:16 +0300260 if (motg->pdata->phy_clk_reset)
261 ret = motg->pdata->phy_clk_reset(motg->phy_reset_clk);
262 else
263 ret = reset_control_reset(motg->phy_rst);
Ivan T. Ivanov5146d772013-12-30 13:15:27 -0800264
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +0530265 if (ret)
Ivan T. Ivanov5146d772013-12-30 13:15:27 -0800266 dev_err(motg->phy.dev, "usb phy clk reset failed\n");
267
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +0530268 return ret;
269}
270
Ivan T. Ivanovd69c6f52014-04-28 16:34:18 +0300271static int msm_link_reset(struct msm_otg *motg)
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +0530272{
273 u32 val;
274 int ret;
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +0530275
276 ret = msm_otg_link_clk_reset(motg, 1);
277 if (ret)
278 return ret;
Ivan T. Ivanovd69c6f52014-04-28 16:34:18 +0300279
280 /* wait for 1ms delay as suggested in HPG. */
281 usleep_range(1000, 1200);
282
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +0530283 ret = msm_otg_link_clk_reset(motg, 0);
284 if (ret)
285 return ret;
286
Ivan T. Ivanovcfa3ff52014-04-28 16:34:17 +0300287 if (motg->phy_number)
288 writel(readl(USB_PHY_CTRL2) | BIT(16), USB_PHY_CTRL2);
289
Tim Bird9f27984b2014-04-28 16:34:19 +0300290 /* put transceiver in serial mode as part of reset */
Ivan T. Ivanovd69c6f52014-04-28 16:34:18 +0300291 val = readl(USB_PORTSC) & ~PORTSC_PTS_MASK;
Tim Bird9f27984b2014-04-28 16:34:19 +0300292 writel(val | PORTSC_PTS_SERIAL, USB_PORTSC);
Ivan T. Ivanovd69c6f52014-04-28 16:34:18 +0300293
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +0530294 return 0;
295}
296
Heikki Krogerus1d4c9292012-02-13 13:24:09 +0200297static int msm_otg_reset(struct usb_phy *phy)
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +0530298{
Heikki Krogerus1d4c9292012-02-13 13:24:09 +0200299 struct msm_otg *motg = container_of(phy, struct msm_otg, phy);
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +0530300 int cnt = 0;
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +0530301
302 writel(USBCMD_RESET, USB_USBCMD);
303 while (cnt < LINK_RESET_TIMEOUT_USEC) {
304 if (!(readl(USB_USBCMD) & USBCMD_RESET))
305 break;
306 udelay(1);
307 cnt++;
308 }
309 if (cnt >= LINK_RESET_TIMEOUT_USEC)
310 return -ETIMEDOUT;
311
Tim Bird9f27984b2014-04-28 16:34:19 +0300312 /* select ULPI phy and clear other status/control bits in PORTSC */
313 writel(PORTSC_PTS_ULPI, USB_PORTSC);
314
Ivan T. Ivanovd69c6f52014-04-28 16:34:18 +0300315 writel(0x0, USB_AHBBURST);
316 writel(0x08, USB_AHBMODE);
317
318 if (motg->phy_number)
319 writel(readl(USB_PHY_CTRL2) | BIT(16), USB_PHY_CTRL2);
320 return 0;
321}
322
323static void msm_phy_reset(struct msm_otg *motg)
324{
325 void __iomem *addr;
326
327 if (motg->pdata->phy_type != SNPS_28NM_INTEGRATED_PHY) {
328 msm_otg_phy_clk_reset(motg);
329 return;
330 }
331
332 addr = USB_PHY_CTRL;
333 if (motg->phy_number)
334 addr = USB_PHY_CTRL2;
335
336 /* Assert USB PHY_POR */
337 writel(readl(addr) | PHY_POR_ASSERT, addr);
338
339 /*
340 * wait for minimum 10 microseconds as suggested in HPG.
341 * Use a slightly larger value since the exact value didn't
342 * work 100% of the time.
343 */
344 udelay(12);
345
346 /* Deassert USB PHY_POR */
347 writel(readl(addr) & ~PHY_POR_ASSERT, addr);
348}
349
350static int msm_usb_reset(struct usb_phy *phy)
351{
352 struct msm_otg *motg = container_of(phy, struct msm_otg, phy);
353 int ret;
354
355 if (!IS_ERR(motg->core_clk))
356 clk_prepare_enable(motg->core_clk);
357
358 ret = msm_link_reset(motg);
359 if (ret) {
360 dev_err(phy->dev, "phy_reset failed\n");
361 return ret;
362 }
363
364 ret = msm_otg_reset(&motg->phy);
365 if (ret) {
366 dev_err(phy->dev, "link reset failed\n");
367 return ret;
368 }
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +0530369
370 msleep(100);
371
Ivan T. Ivanovd69c6f52014-04-28 16:34:18 +0300372 /* Reset USB PHY after performing USB Link RESET */
373 msm_phy_reset(motg);
374
375 if (!IS_ERR(motg->core_clk))
376 clk_disable_unprepare(motg->core_clk);
377
378 return 0;
379}
380
381static int msm_phy_init(struct usb_phy *phy)
382{
383 struct msm_otg *motg = container_of(phy, struct msm_otg, phy);
384 struct msm_otg_platform_data *pdata = motg->pdata;
385 u32 val, ulpi_val = 0;
386
387 /* Program USB PHY Override registers. */
388 ulpi_init(motg);
389
390 /*
391 * It is recommended in HPG to reset USB PHY after programming
392 * USB PHY Override registers.
393 */
394 msm_phy_reset(motg);
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +0530395
396 if (pdata->otg_control == OTG_PHY_CONTROL) {
397 val = readl(USB_OTGSC);
Ivan T. Ivanov971232c2014-04-28 16:34:11 +0300398 if (pdata->mode == USB_DR_MODE_OTG) {
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +0530399 ulpi_val = ULPI_INT_IDGRD | ULPI_INT_SESS_VALID;
400 val |= OTGSC_IDIE | OTGSC_BSVIE;
Ivan T. Ivanov971232c2014-04-28 16:34:11 +0300401 } else if (pdata->mode == USB_DR_MODE_PERIPHERAL) {
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +0530402 ulpi_val = ULPI_INT_SESS_VALID;
403 val |= OTGSC_BSVIE;
404 }
405 writel(val, USB_OTGSC);
Heikki Krogerus1d4c9292012-02-13 13:24:09 +0200406 ulpi_write(phy, ulpi_val, ULPI_USB_INT_EN_RISE);
407 ulpi_write(phy, ulpi_val, ULPI_USB_INT_EN_FALL);
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +0530408 }
409
Ivan T. Ivanovcfa3ff52014-04-28 16:34:17 +0300410 if (motg->phy_number)
411 writel(readl(USB_PHY_CTRL2) | BIT(16), USB_PHY_CTRL2);
412
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +0530413 return 0;
414}
415
Pavankumar Kondeti87c01042010-12-07 17:53:58 +0530416#define PHY_SUSPEND_TIMEOUT_USEC (500 * 1000)
Pavankumar Kondeti70187732011-02-15 09:42:34 +0530417#define PHY_RESUME_TIMEOUT_USEC (100 * 1000)
418
Josh Cartwrighte7d613d2014-02-18 10:36:29 -0600419#ifdef CONFIG_PM
420
421#define USB_PHY_SUSP_DIG_VOL 500000
Ivan T. Ivanov37cfdaf2014-04-28 16:34:06 +0300422static int msm_hsusb_config_vddcx(struct msm_otg *motg, int high)
Josh Cartwrighte7d613d2014-02-18 10:36:29 -0600423{
424 int max_vol = USB_PHY_VDD_DIG_VOL_MAX;
425 int min_vol;
426 int ret;
427
428 if (high)
429 min_vol = USB_PHY_VDD_DIG_VOL_MIN;
430 else
431 min_vol = USB_PHY_SUSP_DIG_VOL;
432
Ivan T. Ivanov37cfdaf2014-04-28 16:34:06 +0300433 ret = regulator_set_voltage(motg->vddcx, min_vol, max_vol);
Josh Cartwrighte7d613d2014-02-18 10:36:29 -0600434 if (ret) {
Ivan T. Ivanov3aca0fa2014-04-28 16:34:10 +0300435 pr_err("Cannot set vddcx voltage\n");
Josh Cartwrighte7d613d2014-02-18 10:36:29 -0600436 return ret;
437 }
438
439 pr_debug("%s: min_vol:%d max_vol:%d\n", __func__, min_vol, max_vol);
440
441 return ret;
442}
443
Pavankumar Kondeti87c01042010-12-07 17:53:58 +0530444static int msm_otg_suspend(struct msm_otg *motg)
445{
Heikki Krogerus1d4c9292012-02-13 13:24:09 +0200446 struct usb_phy *phy = &motg->phy;
447 struct usb_bus *bus = phy->otg->host;
Pavankumar Kondeti87c01042010-12-07 17:53:58 +0530448 struct msm_otg_platform_data *pdata = motg->pdata;
Ivan T. Ivanovcfa3ff52014-04-28 16:34:17 +0300449 void __iomem *addr;
Pavankumar Kondeti87c01042010-12-07 17:53:58 +0530450 int cnt = 0;
451
452 if (atomic_read(&motg->in_lpm))
453 return 0;
454
455 disable_irq(motg->irq);
456 /*
Pavankumar Kondeti04aebcb2011-05-04 10:19:49 +0530457 * Chipidea 45-nm PHY suspend sequence:
458 *
Pavankumar Kondeti87c01042010-12-07 17:53:58 +0530459 * Interrupt Latch Register auto-clear feature is not present
460 * in all PHY versions. Latch register is clear on read type.
461 * Clear latch register to avoid spurious wakeup from
462 * low power mode (LPM).
Pavankumar Kondeti04aebcb2011-05-04 10:19:49 +0530463 *
Pavankumar Kondeti87c01042010-12-07 17:53:58 +0530464 * PHY comparators are disabled when PHY enters into low power
465 * mode (LPM). Keep PHY comparators ON in LPM only when we expect
466 * VBUS/Id notifications from USB PHY. Otherwise turn off USB
467 * PHY comparators. This save significant amount of power.
Pavankumar Kondeti04aebcb2011-05-04 10:19:49 +0530468 *
Pavankumar Kondeti87c01042010-12-07 17:53:58 +0530469 * PLL is not turned off when PHY enters into low power mode (LPM).
470 * Disable PLL for maximum power savings.
471 */
Pavankumar Kondeti04aebcb2011-05-04 10:19:49 +0530472
473 if (motg->pdata->phy_type == CI_45NM_INTEGRATED_PHY) {
Heikki Krogerus1d4c9292012-02-13 13:24:09 +0200474 ulpi_read(phy, 0x14);
Pavankumar Kondeti04aebcb2011-05-04 10:19:49 +0530475 if (pdata->otg_control == OTG_PHY_CONTROL)
Heikki Krogerus1d4c9292012-02-13 13:24:09 +0200476 ulpi_write(phy, 0x01, 0x30);
477 ulpi_write(phy, 0x08, 0x09);
Pavankumar Kondeti04aebcb2011-05-04 10:19:49 +0530478 }
Pavankumar Kondeti87c01042010-12-07 17:53:58 +0530479
480 /*
481 * PHY may take some time or even fail to enter into low power
482 * mode (LPM). Hence poll for 500 msec and reset the PHY and link
483 * in failure case.
484 */
485 writel(readl(USB_PORTSC) | PORTSC_PHCD, USB_PORTSC);
486 while (cnt < PHY_SUSPEND_TIMEOUT_USEC) {
487 if (readl(USB_PORTSC) & PORTSC_PHCD)
488 break;
489 udelay(1);
490 cnt++;
491 }
492
493 if (cnt >= PHY_SUSPEND_TIMEOUT_USEC) {
Heikki Krogerus1d4c9292012-02-13 13:24:09 +0200494 dev_err(phy->dev, "Unable to suspend PHY\n");
495 msm_otg_reset(phy);
Pavankumar Kondeti87c01042010-12-07 17:53:58 +0530496 enable_irq(motg->irq);
497 return -ETIMEDOUT;
498 }
499
500 /*
501 * PHY has capability to generate interrupt asynchronously in low
502 * power mode (LPM). This interrupt is level triggered. So USB IRQ
503 * line must be disabled till async interrupt enable bit is cleared
504 * in USBCMD register. Assert STP (ULPI interface STOP signal) to
505 * block data communication from PHY.
506 */
507 writel(readl(USB_USBCMD) | ASYNC_INTR_CTRL | ULPI_STP_CTRL, USB_USBCMD);
508
Ivan T. Ivanovcfa3ff52014-04-28 16:34:17 +0300509 addr = USB_PHY_CTRL;
510 if (motg->phy_number)
511 addr = USB_PHY_CTRL2;
512
Pavankumar Kondeti04aebcb2011-05-04 10:19:49 +0530513 if (motg->pdata->phy_type == SNPS_28NM_INTEGRATED_PHY &&
514 motg->pdata->otg_control == OTG_PMIC_CONTROL)
Ivan T. Ivanovcfa3ff52014-04-28 16:34:17 +0300515 writel(readl(addr) | PHY_RETEN, addr);
Pavankumar Kondeti04aebcb2011-05-04 10:19:49 +0530516
Stephen Boydb99a8f62013-06-17 10:43:10 -0700517 clk_disable_unprepare(motg->pclk);
518 clk_disable_unprepare(motg->clk);
Ivan T. Ivanov6b99c68e2014-04-28 16:34:08 +0300519 if (!IS_ERR(motg->core_clk))
Stephen Boydb99a8f62013-06-17 10:43:10 -0700520 clk_disable_unprepare(motg->core_clk);
Pavankumar Kondeti87c01042010-12-07 17:53:58 +0530521
Pavankumar Kondeti04aebcb2011-05-04 10:19:49 +0530522 if (motg->pdata->phy_type == SNPS_28NM_INTEGRATED_PHY &&
523 motg->pdata->otg_control == OTG_PMIC_CONTROL) {
Ivan T. Ivanov37cfdaf2014-04-28 16:34:06 +0300524 msm_hsusb_ldo_set_mode(motg, 0);
525 msm_hsusb_config_vddcx(motg, 0);
Pavankumar Kondeti04aebcb2011-05-04 10:19:49 +0530526 }
527
Heikki Krogerus1d4c9292012-02-13 13:24:09 +0200528 if (device_may_wakeup(phy->dev))
Pavankumar Kondeti87c01042010-12-07 17:53:58 +0530529 enable_irq_wake(motg->irq);
530 if (bus)
531 clear_bit(HCD_FLAG_HW_ACCESSIBLE, &(bus_to_hcd(bus))->flags);
532
533 atomic_set(&motg->in_lpm, 1);
534 enable_irq(motg->irq);
535
Heikki Krogerus1d4c9292012-02-13 13:24:09 +0200536 dev_info(phy->dev, "USB in low power mode\n");
Pavankumar Kondeti87c01042010-12-07 17:53:58 +0530537
538 return 0;
539}
540
Pavankumar Kondeti87c01042010-12-07 17:53:58 +0530541static int msm_otg_resume(struct msm_otg *motg)
542{
Heikki Krogerus1d4c9292012-02-13 13:24:09 +0200543 struct usb_phy *phy = &motg->phy;
544 struct usb_bus *bus = phy->otg->host;
Ivan T. Ivanovcfa3ff52014-04-28 16:34:17 +0300545 void __iomem *addr;
Pavankumar Kondeti87c01042010-12-07 17:53:58 +0530546 int cnt = 0;
547 unsigned temp;
548
549 if (!atomic_read(&motg->in_lpm))
550 return 0;
551
Stephen Boydb99a8f62013-06-17 10:43:10 -0700552 clk_prepare_enable(motg->pclk);
553 clk_prepare_enable(motg->clk);
Ivan T. Ivanov6b99c68e2014-04-28 16:34:08 +0300554 if (!IS_ERR(motg->core_clk))
Stephen Boydb99a8f62013-06-17 10:43:10 -0700555 clk_prepare_enable(motg->core_clk);
Pavankumar Kondeti87c01042010-12-07 17:53:58 +0530556
Pavankumar Kondeti04aebcb2011-05-04 10:19:49 +0530557 if (motg->pdata->phy_type == SNPS_28NM_INTEGRATED_PHY &&
558 motg->pdata->otg_control == OTG_PMIC_CONTROL) {
Ivan T. Ivanovcfa3ff52014-04-28 16:34:17 +0300559
560 addr = USB_PHY_CTRL;
561 if (motg->phy_number)
562 addr = USB_PHY_CTRL2;
563
Ivan T. Ivanov37cfdaf2014-04-28 16:34:06 +0300564 msm_hsusb_ldo_set_mode(motg, 1);
565 msm_hsusb_config_vddcx(motg, 1);
Ivan T. Ivanovcfa3ff52014-04-28 16:34:17 +0300566 writel(readl(addr) & ~PHY_RETEN, addr);
Pavankumar Kondeti04aebcb2011-05-04 10:19:49 +0530567 }
568
Pavankumar Kondeti87c01042010-12-07 17:53:58 +0530569 temp = readl(USB_USBCMD);
570 temp &= ~ASYNC_INTR_CTRL;
571 temp &= ~ULPI_STP_CTRL;
572 writel(temp, USB_USBCMD);
573
574 /*
575 * PHY comes out of low power mode (LPM) in case of wakeup
576 * from asynchronous interrupt.
577 */
578 if (!(readl(USB_PORTSC) & PORTSC_PHCD))
579 goto skip_phy_resume;
580
581 writel(readl(USB_PORTSC) & ~PORTSC_PHCD, USB_PORTSC);
582 while (cnt < PHY_RESUME_TIMEOUT_USEC) {
583 if (!(readl(USB_PORTSC) & PORTSC_PHCD))
584 break;
585 udelay(1);
586 cnt++;
587 }
588
589 if (cnt >= PHY_RESUME_TIMEOUT_USEC) {
590 /*
591 * This is a fatal error. Reset the link and
592 * PHY. USB state can not be restored. Re-insertion
593 * of USB cable is the only way to get USB working.
594 */
Ivan T. Ivanov3aca0fa2014-04-28 16:34:10 +0300595 dev_err(phy->dev, "Unable to resume USB. Re-plugin the cable\n");
Heikki Krogerus1d4c9292012-02-13 13:24:09 +0200596 msm_otg_reset(phy);
Pavankumar Kondeti87c01042010-12-07 17:53:58 +0530597 }
598
599skip_phy_resume:
Heikki Krogerus1d4c9292012-02-13 13:24:09 +0200600 if (device_may_wakeup(phy->dev))
Pavankumar Kondeti87c01042010-12-07 17:53:58 +0530601 disable_irq_wake(motg->irq);
602 if (bus)
603 set_bit(HCD_FLAG_HW_ACCESSIBLE, &(bus_to_hcd(bus))->flags);
604
Pavankumar Kondeti2ce2c3a2011-05-02 11:56:33 +0530605 atomic_set(&motg->in_lpm, 0);
606
Pavankumar Kondeti87c01042010-12-07 17:53:58 +0530607 if (motg->async_int) {
608 motg->async_int = 0;
Heikki Krogerus1d4c9292012-02-13 13:24:09 +0200609 pm_runtime_put(phy->dev);
Pavankumar Kondeti87c01042010-12-07 17:53:58 +0530610 enable_irq(motg->irq);
611 }
612
Heikki Krogerus1d4c9292012-02-13 13:24:09 +0200613 dev_info(phy->dev, "USB exited from low power mode\n");
Pavankumar Kondeti87c01042010-12-07 17:53:58 +0530614
615 return 0;
616}
Pavankumar Kondeti70187732011-02-15 09:42:34 +0530617#endif
Pavankumar Kondeti87c01042010-12-07 17:53:58 +0530618
Pavankumar Kondetid8608522011-05-04 10:19:47 +0530619static void msm_otg_notify_charger(struct msm_otg *motg, unsigned mA)
620{
621 if (motg->cur_power == mA)
622 return;
623
624 /* TODO: Notify PMIC about available current */
Heikki Krogerus1d4c9292012-02-13 13:24:09 +0200625 dev_info(motg->phy.dev, "Avail curr from USB = %u\n", mA);
Pavankumar Kondetid8608522011-05-04 10:19:47 +0530626 motg->cur_power = mA;
627}
628
Heikki Krogerus1d4c9292012-02-13 13:24:09 +0200629static int msm_otg_set_power(struct usb_phy *phy, unsigned mA)
Pavankumar Kondetid8608522011-05-04 10:19:47 +0530630{
Heikki Krogerus1d4c9292012-02-13 13:24:09 +0200631 struct msm_otg *motg = container_of(phy, struct msm_otg, phy);
Pavankumar Kondetid8608522011-05-04 10:19:47 +0530632
633 /*
634 * Gadget driver uses set_power method to notify about the
635 * available current based on suspend/configured states.
636 *
637 * IDEV_CHG can be drawn irrespective of suspend/un-configured
638 * states when CDP/ACA is connected.
639 */
640 if (motg->chg_type == USB_SDP_CHARGER)
641 msm_otg_notify_charger(motg, mA);
642
643 return 0;
644}
645
Heikki Krogerus1d4c9292012-02-13 13:24:09 +0200646static void msm_otg_start_host(struct usb_phy *phy, int on)
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +0530647{
Heikki Krogerus1d4c9292012-02-13 13:24:09 +0200648 struct msm_otg *motg = container_of(phy, struct msm_otg, phy);
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +0530649 struct msm_otg_platform_data *pdata = motg->pdata;
650 struct usb_hcd *hcd;
651
Heikki Krogerus1d4c9292012-02-13 13:24:09 +0200652 if (!phy->otg->host)
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +0530653 return;
654
Heikki Krogerus1d4c9292012-02-13 13:24:09 +0200655 hcd = bus_to_hcd(phy->otg->host);
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +0530656
657 if (on) {
Heikki Krogerus1d4c9292012-02-13 13:24:09 +0200658 dev_dbg(phy->dev, "host on\n");
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +0530659
660 if (pdata->vbus_power)
661 pdata->vbus_power(1);
662 /*
663 * Some boards have a switch cotrolled by gpio
664 * to enable/disable internal HUB. Enable internal
665 * HUB before kicking the host.
666 */
667 if (pdata->setup_gpio)
668 pdata->setup_gpio(OTG_STATE_A_HOST);
669#ifdef CONFIG_USB
670 usb_add_hcd(hcd, hcd->irq, IRQF_SHARED);
Peter Chen3c9740a2013-11-05 10:46:02 +0800671 device_wakeup_enable(hcd->self.controller);
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +0530672#endif
673 } else {
Heikki Krogerus1d4c9292012-02-13 13:24:09 +0200674 dev_dbg(phy->dev, "host off\n");
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +0530675
676#ifdef CONFIG_USB
677 usb_remove_hcd(hcd);
678#endif
679 if (pdata->setup_gpio)
680 pdata->setup_gpio(OTG_STATE_UNDEFINED);
681 if (pdata->vbus_power)
682 pdata->vbus_power(0);
683 }
684}
685
Heikki Krogerus1d4c9292012-02-13 13:24:09 +0200686static int msm_otg_set_host(struct usb_otg *otg, struct usb_bus *host)
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +0530687{
Heikki Krogerus1d4c9292012-02-13 13:24:09 +0200688 struct msm_otg *motg = container_of(otg->phy, struct msm_otg, phy);
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +0530689 struct usb_hcd *hcd;
690
691 /*
692 * Fail host registration if this board can support
693 * only peripheral configuration.
694 */
Ivan T. Ivanov971232c2014-04-28 16:34:11 +0300695 if (motg->pdata->mode == USB_DR_MODE_PERIPHERAL) {
Heikki Krogerus1d4c9292012-02-13 13:24:09 +0200696 dev_info(otg->phy->dev, "Host mode is not supported\n");
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +0530697 return -ENODEV;
698 }
699
700 if (!host) {
Heikki Krogerus1d4c9292012-02-13 13:24:09 +0200701 if (otg->phy->state == OTG_STATE_A_HOST) {
702 pm_runtime_get_sync(otg->phy->dev);
703 msm_otg_start_host(otg->phy, 0);
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +0530704 otg->host = NULL;
Heikki Krogerus1d4c9292012-02-13 13:24:09 +0200705 otg->phy->state = OTG_STATE_UNDEFINED;
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +0530706 schedule_work(&motg->sm_work);
707 } else {
708 otg->host = NULL;
709 }
710
711 return 0;
712 }
713
714 hcd = bus_to_hcd(host);
715 hcd->power_budget = motg->pdata->power_budget;
716
717 otg->host = host;
Heikki Krogerus1d4c9292012-02-13 13:24:09 +0200718 dev_dbg(otg->phy->dev, "host driver registered w/ tranceiver\n");
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +0530719
720 /*
721 * Kick the state machine work, if peripheral is not supported
722 * or peripheral is already registered with us.
723 */
Ivan T. Ivanov971232c2014-04-28 16:34:11 +0300724 if (motg->pdata->mode == USB_DR_MODE_HOST || otg->gadget) {
Heikki Krogerus1d4c9292012-02-13 13:24:09 +0200725 pm_runtime_get_sync(otg->phy->dev);
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +0530726 schedule_work(&motg->sm_work);
Pavankumar Kondeti87c01042010-12-07 17:53:58 +0530727 }
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +0530728
729 return 0;
730}
731
Heikki Krogerus1d4c9292012-02-13 13:24:09 +0200732static void msm_otg_start_peripheral(struct usb_phy *phy, int on)
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +0530733{
Heikki Krogerus1d4c9292012-02-13 13:24:09 +0200734 struct msm_otg *motg = container_of(phy, struct msm_otg, phy);
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +0530735 struct msm_otg_platform_data *pdata = motg->pdata;
736
Heikki Krogerus1d4c9292012-02-13 13:24:09 +0200737 if (!phy->otg->gadget)
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +0530738 return;
739
740 if (on) {
Heikki Krogerus1d4c9292012-02-13 13:24:09 +0200741 dev_dbg(phy->dev, "gadget on\n");
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +0530742 /*
743 * Some boards have a switch cotrolled by gpio
744 * to enable/disable internal HUB. Disable internal
745 * HUB before kicking the gadget.
746 */
747 if (pdata->setup_gpio)
748 pdata->setup_gpio(OTG_STATE_B_PERIPHERAL);
Heikki Krogerus1d4c9292012-02-13 13:24:09 +0200749 usb_gadget_vbus_connect(phy->otg->gadget);
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +0530750 } else {
Heikki Krogerus1d4c9292012-02-13 13:24:09 +0200751 dev_dbg(phy->dev, "gadget off\n");
752 usb_gadget_vbus_disconnect(phy->otg->gadget);
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +0530753 if (pdata->setup_gpio)
754 pdata->setup_gpio(OTG_STATE_UNDEFINED);
755 }
756
757}
758
Heikki Krogerus1d4c9292012-02-13 13:24:09 +0200759static int msm_otg_set_peripheral(struct usb_otg *otg,
760 struct usb_gadget *gadget)
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +0530761{
Heikki Krogerus1d4c9292012-02-13 13:24:09 +0200762 struct msm_otg *motg = container_of(otg->phy, struct msm_otg, phy);
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +0530763
764 /*
765 * Fail peripheral registration if this board can support
766 * only host configuration.
767 */
Ivan T. Ivanov971232c2014-04-28 16:34:11 +0300768 if (motg->pdata->mode == USB_DR_MODE_HOST) {
Heikki Krogerus1d4c9292012-02-13 13:24:09 +0200769 dev_info(otg->phy->dev, "Peripheral mode is not supported\n");
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +0530770 return -ENODEV;
771 }
772
773 if (!gadget) {
Heikki Krogerus1d4c9292012-02-13 13:24:09 +0200774 if (otg->phy->state == OTG_STATE_B_PERIPHERAL) {
775 pm_runtime_get_sync(otg->phy->dev);
776 msm_otg_start_peripheral(otg->phy, 0);
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +0530777 otg->gadget = NULL;
Heikki Krogerus1d4c9292012-02-13 13:24:09 +0200778 otg->phy->state = OTG_STATE_UNDEFINED;
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +0530779 schedule_work(&motg->sm_work);
780 } else {
781 otg->gadget = NULL;
782 }
783
784 return 0;
785 }
786 otg->gadget = gadget;
Heikki Krogerus1d4c9292012-02-13 13:24:09 +0200787 dev_dbg(otg->phy->dev, "peripheral driver registered w/ tranceiver\n");
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +0530788
789 /*
790 * Kick the state machine work, if host is not supported
791 * or host is already registered with us.
792 */
Ivan T. Ivanov971232c2014-04-28 16:34:11 +0300793 if (motg->pdata->mode == USB_DR_MODE_PERIPHERAL || otg->host) {
Heikki Krogerus1d4c9292012-02-13 13:24:09 +0200794 pm_runtime_get_sync(otg->phy->dev);
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +0530795 schedule_work(&motg->sm_work);
Pavankumar Kondeti87c01042010-12-07 17:53:58 +0530796 }
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +0530797
798 return 0;
799}
800
Pavankumar Kondetid8608522011-05-04 10:19:47 +0530801static bool msm_chg_check_secondary_det(struct msm_otg *motg)
802{
Heikki Krogerus1d4c9292012-02-13 13:24:09 +0200803 struct usb_phy *phy = &motg->phy;
Pavankumar Kondetid8608522011-05-04 10:19:47 +0530804 u32 chg_det;
805 bool ret = false;
806
807 switch (motg->pdata->phy_type) {
808 case CI_45NM_INTEGRATED_PHY:
Heikki Krogerus1d4c9292012-02-13 13:24:09 +0200809 chg_det = ulpi_read(phy, 0x34);
Pavankumar Kondetid8608522011-05-04 10:19:47 +0530810 ret = chg_det & (1 << 4);
811 break;
812 case SNPS_28NM_INTEGRATED_PHY:
Heikki Krogerus1d4c9292012-02-13 13:24:09 +0200813 chg_det = ulpi_read(phy, 0x87);
Pavankumar Kondetid8608522011-05-04 10:19:47 +0530814 ret = chg_det & 1;
815 break;
816 default:
817 break;
818 }
819 return ret;
820}
821
822static void msm_chg_enable_secondary_det(struct msm_otg *motg)
823{
Heikki Krogerus1d4c9292012-02-13 13:24:09 +0200824 struct usb_phy *phy = &motg->phy;
Pavankumar Kondetid8608522011-05-04 10:19:47 +0530825 u32 chg_det;
826
827 switch (motg->pdata->phy_type) {
828 case CI_45NM_INTEGRATED_PHY:
Heikki Krogerus1d4c9292012-02-13 13:24:09 +0200829 chg_det = ulpi_read(phy, 0x34);
Pavankumar Kondetid8608522011-05-04 10:19:47 +0530830 /* Turn off charger block */
831 chg_det |= ~(1 << 1);
Heikki Krogerus1d4c9292012-02-13 13:24:09 +0200832 ulpi_write(phy, chg_det, 0x34);
Pavankumar Kondetid8608522011-05-04 10:19:47 +0530833 udelay(20);
834 /* control chg block via ULPI */
835 chg_det &= ~(1 << 3);
Heikki Krogerus1d4c9292012-02-13 13:24:09 +0200836 ulpi_write(phy, chg_det, 0x34);
Pavankumar Kondetid8608522011-05-04 10:19:47 +0530837 /* put it in host mode for enabling D- source */
838 chg_det &= ~(1 << 2);
Heikki Krogerus1d4c9292012-02-13 13:24:09 +0200839 ulpi_write(phy, chg_det, 0x34);
Pavankumar Kondetid8608522011-05-04 10:19:47 +0530840 /* Turn on chg detect block */
841 chg_det &= ~(1 << 1);
Heikki Krogerus1d4c9292012-02-13 13:24:09 +0200842 ulpi_write(phy, chg_det, 0x34);
Pavankumar Kondetid8608522011-05-04 10:19:47 +0530843 udelay(20);
844 /* enable chg detection */
845 chg_det &= ~(1 << 0);
Heikki Krogerus1d4c9292012-02-13 13:24:09 +0200846 ulpi_write(phy, chg_det, 0x34);
Pavankumar Kondetid8608522011-05-04 10:19:47 +0530847 break;
848 case SNPS_28NM_INTEGRATED_PHY:
849 /*
850 * Configure DM as current source, DP as current sink
851 * and enable battery charging comparators.
852 */
Heikki Krogerus1d4c9292012-02-13 13:24:09 +0200853 ulpi_write(phy, 0x8, 0x85);
854 ulpi_write(phy, 0x2, 0x85);
855 ulpi_write(phy, 0x1, 0x85);
Pavankumar Kondetid8608522011-05-04 10:19:47 +0530856 break;
857 default:
858 break;
859 }
860}
861
862static bool msm_chg_check_primary_det(struct msm_otg *motg)
863{
Heikki Krogerus1d4c9292012-02-13 13:24:09 +0200864 struct usb_phy *phy = &motg->phy;
Pavankumar Kondetid8608522011-05-04 10:19:47 +0530865 u32 chg_det;
866 bool ret = false;
867
868 switch (motg->pdata->phy_type) {
869 case CI_45NM_INTEGRATED_PHY:
Heikki Krogerus1d4c9292012-02-13 13:24:09 +0200870 chg_det = ulpi_read(phy, 0x34);
Pavankumar Kondetid8608522011-05-04 10:19:47 +0530871 ret = chg_det & (1 << 4);
872 break;
873 case SNPS_28NM_INTEGRATED_PHY:
Heikki Krogerus1d4c9292012-02-13 13:24:09 +0200874 chg_det = ulpi_read(phy, 0x87);
Pavankumar Kondetid8608522011-05-04 10:19:47 +0530875 ret = chg_det & 1;
876 break;
877 default:
878 break;
879 }
880 return ret;
881}
882
883static void msm_chg_enable_primary_det(struct msm_otg *motg)
884{
Heikki Krogerus1d4c9292012-02-13 13:24:09 +0200885 struct usb_phy *phy = &motg->phy;
Pavankumar Kondetid8608522011-05-04 10:19:47 +0530886 u32 chg_det;
887
888 switch (motg->pdata->phy_type) {
889 case CI_45NM_INTEGRATED_PHY:
Heikki Krogerus1d4c9292012-02-13 13:24:09 +0200890 chg_det = ulpi_read(phy, 0x34);
Pavankumar Kondetid8608522011-05-04 10:19:47 +0530891 /* enable chg detection */
892 chg_det &= ~(1 << 0);
Heikki Krogerus1d4c9292012-02-13 13:24:09 +0200893 ulpi_write(phy, chg_det, 0x34);
Pavankumar Kondetid8608522011-05-04 10:19:47 +0530894 break;
895 case SNPS_28NM_INTEGRATED_PHY:
896 /*
897 * Configure DP as current source, DM as current sink
898 * and enable battery charging comparators.
899 */
Heikki Krogerus1d4c9292012-02-13 13:24:09 +0200900 ulpi_write(phy, 0x2, 0x85);
901 ulpi_write(phy, 0x1, 0x85);
Pavankumar Kondetid8608522011-05-04 10:19:47 +0530902 break;
903 default:
904 break;
905 }
906}
907
908static bool msm_chg_check_dcd(struct msm_otg *motg)
909{
Heikki Krogerus1d4c9292012-02-13 13:24:09 +0200910 struct usb_phy *phy = &motg->phy;
Pavankumar Kondetid8608522011-05-04 10:19:47 +0530911 u32 line_state;
912 bool ret = false;
913
914 switch (motg->pdata->phy_type) {
915 case CI_45NM_INTEGRATED_PHY:
Heikki Krogerus1d4c9292012-02-13 13:24:09 +0200916 line_state = ulpi_read(phy, 0x15);
Pavankumar Kondetid8608522011-05-04 10:19:47 +0530917 ret = !(line_state & 1);
918 break;
919 case SNPS_28NM_INTEGRATED_PHY:
Heikki Krogerus1d4c9292012-02-13 13:24:09 +0200920 line_state = ulpi_read(phy, 0x87);
Pavankumar Kondetid8608522011-05-04 10:19:47 +0530921 ret = line_state & 2;
922 break;
923 default:
924 break;
925 }
926 return ret;
927}
928
929static void msm_chg_disable_dcd(struct msm_otg *motg)
930{
Heikki Krogerus1d4c9292012-02-13 13:24:09 +0200931 struct usb_phy *phy = &motg->phy;
Pavankumar Kondetid8608522011-05-04 10:19:47 +0530932 u32 chg_det;
933
934 switch (motg->pdata->phy_type) {
935 case CI_45NM_INTEGRATED_PHY:
Heikki Krogerus1d4c9292012-02-13 13:24:09 +0200936 chg_det = ulpi_read(phy, 0x34);
Pavankumar Kondetid8608522011-05-04 10:19:47 +0530937 chg_det &= ~(1 << 5);
Heikki Krogerus1d4c9292012-02-13 13:24:09 +0200938 ulpi_write(phy, chg_det, 0x34);
Pavankumar Kondetid8608522011-05-04 10:19:47 +0530939 break;
940 case SNPS_28NM_INTEGRATED_PHY:
Heikki Krogerus1d4c9292012-02-13 13:24:09 +0200941 ulpi_write(phy, 0x10, 0x86);
Pavankumar Kondetid8608522011-05-04 10:19:47 +0530942 break;
943 default:
944 break;
945 }
946}
947
948static void msm_chg_enable_dcd(struct msm_otg *motg)
949{
Heikki Krogerus1d4c9292012-02-13 13:24:09 +0200950 struct usb_phy *phy = &motg->phy;
Pavankumar Kondetid8608522011-05-04 10:19:47 +0530951 u32 chg_det;
952
953 switch (motg->pdata->phy_type) {
954 case CI_45NM_INTEGRATED_PHY:
Heikki Krogerus1d4c9292012-02-13 13:24:09 +0200955 chg_det = ulpi_read(phy, 0x34);
Pavankumar Kondetid8608522011-05-04 10:19:47 +0530956 /* Turn on D+ current source */
957 chg_det |= (1 << 5);
Heikki Krogerus1d4c9292012-02-13 13:24:09 +0200958 ulpi_write(phy, chg_det, 0x34);
Pavankumar Kondetid8608522011-05-04 10:19:47 +0530959 break;
960 case SNPS_28NM_INTEGRATED_PHY:
961 /* Data contact detection enable */
Heikki Krogerus1d4c9292012-02-13 13:24:09 +0200962 ulpi_write(phy, 0x10, 0x85);
Pavankumar Kondetid8608522011-05-04 10:19:47 +0530963 break;
964 default:
965 break;
966 }
967}
968
969static void msm_chg_block_on(struct msm_otg *motg)
970{
Heikki Krogerus1d4c9292012-02-13 13:24:09 +0200971 struct usb_phy *phy = &motg->phy;
Pavankumar Kondetid8608522011-05-04 10:19:47 +0530972 u32 func_ctrl, chg_det;
973
974 /* put the controller in non-driving mode */
Heikki Krogerus1d4c9292012-02-13 13:24:09 +0200975 func_ctrl = ulpi_read(phy, ULPI_FUNC_CTRL);
Pavankumar Kondetid8608522011-05-04 10:19:47 +0530976 func_ctrl &= ~ULPI_FUNC_CTRL_OPMODE_MASK;
977 func_ctrl |= ULPI_FUNC_CTRL_OPMODE_NONDRIVING;
Heikki Krogerus1d4c9292012-02-13 13:24:09 +0200978 ulpi_write(phy, func_ctrl, ULPI_FUNC_CTRL);
Pavankumar Kondetid8608522011-05-04 10:19:47 +0530979
980 switch (motg->pdata->phy_type) {
981 case CI_45NM_INTEGRATED_PHY:
Heikki Krogerus1d4c9292012-02-13 13:24:09 +0200982 chg_det = ulpi_read(phy, 0x34);
Pavankumar Kondetid8608522011-05-04 10:19:47 +0530983 /* control chg block via ULPI */
984 chg_det &= ~(1 << 3);
Heikki Krogerus1d4c9292012-02-13 13:24:09 +0200985 ulpi_write(phy, chg_det, 0x34);
Pavankumar Kondetid8608522011-05-04 10:19:47 +0530986 /* Turn on chg detect block */
987 chg_det &= ~(1 << 1);
Heikki Krogerus1d4c9292012-02-13 13:24:09 +0200988 ulpi_write(phy, chg_det, 0x34);
Pavankumar Kondetid8608522011-05-04 10:19:47 +0530989 udelay(20);
990 break;
991 case SNPS_28NM_INTEGRATED_PHY:
992 /* Clear charger detecting control bits */
Heikki Krogerus1d4c9292012-02-13 13:24:09 +0200993 ulpi_write(phy, 0x3F, 0x86);
Pavankumar Kondetid8608522011-05-04 10:19:47 +0530994 /* Clear alt interrupt latch and enable bits */
Heikki Krogerus1d4c9292012-02-13 13:24:09 +0200995 ulpi_write(phy, 0x1F, 0x92);
996 ulpi_write(phy, 0x1F, 0x95);
Pavankumar Kondetid8608522011-05-04 10:19:47 +0530997 udelay(100);
998 break;
999 default:
1000 break;
1001 }
1002}
1003
1004static void msm_chg_block_off(struct msm_otg *motg)
1005{
Heikki Krogerus1d4c9292012-02-13 13:24:09 +02001006 struct usb_phy *phy = &motg->phy;
Pavankumar Kondetid8608522011-05-04 10:19:47 +05301007 u32 func_ctrl, chg_det;
1008
1009 switch (motg->pdata->phy_type) {
1010 case CI_45NM_INTEGRATED_PHY:
Heikki Krogerus1d4c9292012-02-13 13:24:09 +02001011 chg_det = ulpi_read(phy, 0x34);
Pavankumar Kondetid8608522011-05-04 10:19:47 +05301012 /* Turn off charger block */
1013 chg_det |= ~(1 << 1);
Heikki Krogerus1d4c9292012-02-13 13:24:09 +02001014 ulpi_write(phy, chg_det, 0x34);
Pavankumar Kondetid8608522011-05-04 10:19:47 +05301015 break;
1016 case SNPS_28NM_INTEGRATED_PHY:
1017 /* Clear charger detecting control bits */
Heikki Krogerus1d4c9292012-02-13 13:24:09 +02001018 ulpi_write(phy, 0x3F, 0x86);
Pavankumar Kondetid8608522011-05-04 10:19:47 +05301019 /* Clear alt interrupt latch and enable bits */
Heikki Krogerus1d4c9292012-02-13 13:24:09 +02001020 ulpi_write(phy, 0x1F, 0x92);
1021 ulpi_write(phy, 0x1F, 0x95);
Pavankumar Kondetid8608522011-05-04 10:19:47 +05301022 break;
1023 default:
1024 break;
1025 }
1026
1027 /* put the controller in normal mode */
Heikki Krogerus1d4c9292012-02-13 13:24:09 +02001028 func_ctrl = ulpi_read(phy, ULPI_FUNC_CTRL);
Pavankumar Kondetid8608522011-05-04 10:19:47 +05301029 func_ctrl &= ~ULPI_FUNC_CTRL_OPMODE_MASK;
1030 func_ctrl |= ULPI_FUNC_CTRL_OPMODE_NORMAL;
Heikki Krogerus1d4c9292012-02-13 13:24:09 +02001031 ulpi_write(phy, func_ctrl, ULPI_FUNC_CTRL);
Pavankumar Kondetid8608522011-05-04 10:19:47 +05301032}
1033
1034#define MSM_CHG_DCD_POLL_TIME (100 * HZ/1000) /* 100 msec */
1035#define MSM_CHG_DCD_MAX_RETRIES 6 /* Tdcd_tmout = 6 * 100 msec */
1036#define MSM_CHG_PRIMARY_DET_TIME (40 * HZ/1000) /* TVDPSRC_ON */
1037#define MSM_CHG_SECONDARY_DET_TIME (40 * HZ/1000) /* TVDMSRC_ON */
1038static void msm_chg_detect_work(struct work_struct *w)
1039{
1040 struct msm_otg *motg = container_of(w, struct msm_otg, chg_work.work);
Heikki Krogerus1d4c9292012-02-13 13:24:09 +02001041 struct usb_phy *phy = &motg->phy;
Pavankumar Kondetid8608522011-05-04 10:19:47 +05301042 bool is_dcd, tmout, vout;
1043 unsigned long delay;
1044
Heikki Krogerus1d4c9292012-02-13 13:24:09 +02001045 dev_dbg(phy->dev, "chg detection work\n");
Pavankumar Kondetid8608522011-05-04 10:19:47 +05301046 switch (motg->chg_state) {
1047 case USB_CHG_STATE_UNDEFINED:
Heikki Krogerus1d4c9292012-02-13 13:24:09 +02001048 pm_runtime_get_sync(phy->dev);
Pavankumar Kondetid8608522011-05-04 10:19:47 +05301049 msm_chg_block_on(motg);
1050 msm_chg_enable_dcd(motg);
1051 motg->chg_state = USB_CHG_STATE_WAIT_FOR_DCD;
1052 motg->dcd_retries = 0;
1053 delay = MSM_CHG_DCD_POLL_TIME;
1054 break;
1055 case USB_CHG_STATE_WAIT_FOR_DCD:
1056 is_dcd = msm_chg_check_dcd(motg);
1057 tmout = ++motg->dcd_retries == MSM_CHG_DCD_MAX_RETRIES;
1058 if (is_dcd || tmout) {
1059 msm_chg_disable_dcd(motg);
1060 msm_chg_enable_primary_det(motg);
1061 delay = MSM_CHG_PRIMARY_DET_TIME;
1062 motg->chg_state = USB_CHG_STATE_DCD_DONE;
1063 } else {
1064 delay = MSM_CHG_DCD_POLL_TIME;
1065 }
1066 break;
1067 case USB_CHG_STATE_DCD_DONE:
1068 vout = msm_chg_check_primary_det(motg);
1069 if (vout) {
1070 msm_chg_enable_secondary_det(motg);
1071 delay = MSM_CHG_SECONDARY_DET_TIME;
1072 motg->chg_state = USB_CHG_STATE_PRIMARY_DONE;
1073 } else {
1074 motg->chg_type = USB_SDP_CHARGER;
1075 motg->chg_state = USB_CHG_STATE_DETECTED;
1076 delay = 0;
1077 }
1078 break;
1079 case USB_CHG_STATE_PRIMARY_DONE:
1080 vout = msm_chg_check_secondary_det(motg);
1081 if (vout)
1082 motg->chg_type = USB_DCP_CHARGER;
1083 else
1084 motg->chg_type = USB_CDP_CHARGER;
1085 motg->chg_state = USB_CHG_STATE_SECONDARY_DONE;
1086 /* fall through */
1087 case USB_CHG_STATE_SECONDARY_DONE:
1088 motg->chg_state = USB_CHG_STATE_DETECTED;
1089 case USB_CHG_STATE_DETECTED:
1090 msm_chg_block_off(motg);
Heikki Krogerus1d4c9292012-02-13 13:24:09 +02001091 dev_dbg(phy->dev, "charger = %d\n", motg->chg_type);
Pavankumar Kondetid8608522011-05-04 10:19:47 +05301092 schedule_work(&motg->sm_work);
1093 return;
1094 default:
1095 return;
1096 }
1097
1098 schedule_delayed_work(&motg->chg_work, delay);
1099}
1100
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05301101/*
1102 * We support OTG, Peripheral only and Host only configurations. In case
1103 * of OTG, mode switch (host-->peripheral/peripheral-->host) can happen
1104 * via Id pin status or user request (debugfs). Id/BSV interrupts are not
1105 * enabled when switch is controlled by user and default mode is supplied
1106 * by board file, which can be changed by userspace later.
1107 */
1108static void msm_otg_init_sm(struct msm_otg *motg)
1109{
1110 struct msm_otg_platform_data *pdata = motg->pdata;
1111 u32 otgsc = readl(USB_OTGSC);
1112
1113 switch (pdata->mode) {
Ivan T. Ivanov971232c2014-04-28 16:34:11 +03001114 case USB_DR_MODE_OTG:
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05301115 if (pdata->otg_control == OTG_PHY_CONTROL) {
1116 if (otgsc & OTGSC_ID)
1117 set_bit(ID, &motg->inputs);
1118 else
1119 clear_bit(ID, &motg->inputs);
1120
1121 if (otgsc & OTGSC_BSV)
1122 set_bit(B_SESS_VLD, &motg->inputs);
1123 else
1124 clear_bit(B_SESS_VLD, &motg->inputs);
1125 } else if (pdata->otg_control == OTG_USER_CONTROL) {
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05301126 set_bit(ID, &motg->inputs);
1127 clear_bit(B_SESS_VLD, &motg->inputs);
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05301128 }
1129 break;
Ivan T. Ivanov971232c2014-04-28 16:34:11 +03001130 case USB_DR_MODE_HOST:
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05301131 clear_bit(ID, &motg->inputs);
1132 break;
Ivan T. Ivanov971232c2014-04-28 16:34:11 +03001133 case USB_DR_MODE_PERIPHERAL:
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05301134 set_bit(ID, &motg->inputs);
1135 if (otgsc & OTGSC_BSV)
1136 set_bit(B_SESS_VLD, &motg->inputs);
1137 else
1138 clear_bit(B_SESS_VLD, &motg->inputs);
1139 break;
1140 default:
1141 break;
1142 }
1143}
1144
1145static void msm_otg_sm_work(struct work_struct *w)
1146{
1147 struct msm_otg *motg = container_of(w, struct msm_otg, sm_work);
Heikki Krogerus1d4c9292012-02-13 13:24:09 +02001148 struct usb_otg *otg = motg->phy.otg;
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05301149
Heikki Krogerus1d4c9292012-02-13 13:24:09 +02001150 switch (otg->phy->state) {
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05301151 case OTG_STATE_UNDEFINED:
Heikki Krogerus1d4c9292012-02-13 13:24:09 +02001152 dev_dbg(otg->phy->dev, "OTG_STATE_UNDEFINED state\n");
1153 msm_otg_reset(otg->phy);
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05301154 msm_otg_init_sm(motg);
Heikki Krogerus1d4c9292012-02-13 13:24:09 +02001155 otg->phy->state = OTG_STATE_B_IDLE;
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05301156 /* FALL THROUGH */
1157 case OTG_STATE_B_IDLE:
Heikki Krogerus1d4c9292012-02-13 13:24:09 +02001158 dev_dbg(otg->phy->dev, "OTG_STATE_B_IDLE state\n");
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05301159 if (!test_bit(ID, &motg->inputs) && otg->host) {
1160 /* disable BSV bit */
1161 writel(readl(USB_OTGSC) & ~OTGSC_BSVIE, USB_OTGSC);
Heikki Krogerus1d4c9292012-02-13 13:24:09 +02001162 msm_otg_start_host(otg->phy, 1);
1163 otg->phy->state = OTG_STATE_A_HOST;
Pavankumar Kondetid8608522011-05-04 10:19:47 +05301164 } else if (test_bit(B_SESS_VLD, &motg->inputs)) {
1165 switch (motg->chg_state) {
1166 case USB_CHG_STATE_UNDEFINED:
1167 msm_chg_detect_work(&motg->chg_work.work);
1168 break;
1169 case USB_CHG_STATE_DETECTED:
1170 switch (motg->chg_type) {
1171 case USB_DCP_CHARGER:
1172 msm_otg_notify_charger(motg,
1173 IDEV_CHG_MAX);
1174 break;
1175 case USB_CDP_CHARGER:
1176 msm_otg_notify_charger(motg,
1177 IDEV_CHG_MAX);
Heikki Krogerus1d4c9292012-02-13 13:24:09 +02001178 msm_otg_start_peripheral(otg->phy, 1);
1179 otg->phy->state
1180 = OTG_STATE_B_PERIPHERAL;
Pavankumar Kondetid8608522011-05-04 10:19:47 +05301181 break;
1182 case USB_SDP_CHARGER:
1183 msm_otg_notify_charger(motg, IUNIT);
Heikki Krogerus1d4c9292012-02-13 13:24:09 +02001184 msm_otg_start_peripheral(otg->phy, 1);
1185 otg->phy->state
1186 = OTG_STATE_B_PERIPHERAL;
Pavankumar Kondetid8608522011-05-04 10:19:47 +05301187 break;
1188 default:
1189 break;
1190 }
1191 break;
1192 default:
1193 break;
1194 }
1195 } else {
1196 /*
1197 * If charger detection work is pending, decrement
1198 * the pm usage counter to balance with the one that
1199 * is incremented in charger detection work.
1200 */
1201 if (cancel_delayed_work_sync(&motg->chg_work)) {
Heikki Krogerus1d4c9292012-02-13 13:24:09 +02001202 pm_runtime_put_sync(otg->phy->dev);
1203 msm_otg_reset(otg->phy);
Pavankumar Kondetid8608522011-05-04 10:19:47 +05301204 }
1205 msm_otg_notify_charger(motg, 0);
1206 motg->chg_state = USB_CHG_STATE_UNDEFINED;
1207 motg->chg_type = USB_INVALID_CHARGER;
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05301208 }
Heikki Krogerus1d4c9292012-02-13 13:24:09 +02001209 pm_runtime_put_sync(otg->phy->dev);
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05301210 break;
1211 case OTG_STATE_B_PERIPHERAL:
Heikki Krogerus1d4c9292012-02-13 13:24:09 +02001212 dev_dbg(otg->phy->dev, "OTG_STATE_B_PERIPHERAL state\n");
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05301213 if (!test_bit(B_SESS_VLD, &motg->inputs) ||
1214 !test_bit(ID, &motg->inputs)) {
Pavankumar Kondetid8608522011-05-04 10:19:47 +05301215 msm_otg_notify_charger(motg, 0);
Heikki Krogerus1d4c9292012-02-13 13:24:09 +02001216 msm_otg_start_peripheral(otg->phy, 0);
Pavankumar Kondetid8608522011-05-04 10:19:47 +05301217 motg->chg_state = USB_CHG_STATE_UNDEFINED;
1218 motg->chg_type = USB_INVALID_CHARGER;
Heikki Krogerus1d4c9292012-02-13 13:24:09 +02001219 otg->phy->state = OTG_STATE_B_IDLE;
1220 msm_otg_reset(otg->phy);
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05301221 schedule_work(w);
1222 }
1223 break;
1224 case OTG_STATE_A_HOST:
Heikki Krogerus1d4c9292012-02-13 13:24:09 +02001225 dev_dbg(otg->phy->dev, "OTG_STATE_A_HOST state\n");
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05301226 if (test_bit(ID, &motg->inputs)) {
Heikki Krogerus1d4c9292012-02-13 13:24:09 +02001227 msm_otg_start_host(otg->phy, 0);
1228 otg->phy->state = OTG_STATE_B_IDLE;
1229 msm_otg_reset(otg->phy);
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05301230 schedule_work(w);
1231 }
1232 break;
1233 default:
1234 break;
1235 }
1236}
1237
1238static irqreturn_t msm_otg_irq(int irq, void *data)
1239{
1240 struct msm_otg *motg = data;
Heikki Krogerus1d4c9292012-02-13 13:24:09 +02001241 struct usb_phy *phy = &motg->phy;
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05301242 u32 otgsc = 0;
1243
Pavankumar Kondeti87c01042010-12-07 17:53:58 +05301244 if (atomic_read(&motg->in_lpm)) {
1245 disable_irq_nosync(irq);
1246 motg->async_int = 1;
Heikki Krogerus1d4c9292012-02-13 13:24:09 +02001247 pm_runtime_get(phy->dev);
Pavankumar Kondeti87c01042010-12-07 17:53:58 +05301248 return IRQ_HANDLED;
1249 }
1250
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05301251 otgsc = readl(USB_OTGSC);
1252 if (!(otgsc & (OTGSC_IDIS | OTGSC_BSVIS)))
1253 return IRQ_NONE;
1254
1255 if ((otgsc & OTGSC_IDIS) && (otgsc & OTGSC_IDIE)) {
1256 if (otgsc & OTGSC_ID)
1257 set_bit(ID, &motg->inputs);
1258 else
1259 clear_bit(ID, &motg->inputs);
Heikki Krogerus1d4c9292012-02-13 13:24:09 +02001260 dev_dbg(phy->dev, "ID set/clear\n");
1261 pm_runtime_get_noresume(phy->dev);
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05301262 } else if ((otgsc & OTGSC_BSVIS) && (otgsc & OTGSC_BSVIE)) {
1263 if (otgsc & OTGSC_BSV)
1264 set_bit(B_SESS_VLD, &motg->inputs);
1265 else
1266 clear_bit(B_SESS_VLD, &motg->inputs);
Heikki Krogerus1d4c9292012-02-13 13:24:09 +02001267 dev_dbg(phy->dev, "BSV set/clear\n");
1268 pm_runtime_get_noresume(phy->dev);
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05301269 }
1270
1271 writel(otgsc, USB_OTGSC);
1272 schedule_work(&motg->sm_work);
1273 return IRQ_HANDLED;
1274}
1275
1276static int msm_otg_mode_show(struct seq_file *s, void *unused)
1277{
1278 struct msm_otg *motg = s->private;
Heikki Krogerus1d4c9292012-02-13 13:24:09 +02001279 struct usb_otg *otg = motg->phy.otg;
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05301280
Heikki Krogerus1d4c9292012-02-13 13:24:09 +02001281 switch (otg->phy->state) {
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05301282 case OTG_STATE_A_HOST:
Ivan T. Ivanov3aca0fa2014-04-28 16:34:10 +03001283 seq_puts(s, "host\n");
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05301284 break;
1285 case OTG_STATE_B_PERIPHERAL:
Ivan T. Ivanov3aca0fa2014-04-28 16:34:10 +03001286 seq_puts(s, "peripheral\n");
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05301287 break;
1288 default:
Ivan T. Ivanov3aca0fa2014-04-28 16:34:10 +03001289 seq_puts(s, "none\n");
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05301290 break;
1291 }
1292
1293 return 0;
1294}
1295
1296static int msm_otg_mode_open(struct inode *inode, struct file *file)
1297{
1298 return single_open(file, msm_otg_mode_show, inode->i_private);
1299}
1300
1301static ssize_t msm_otg_mode_write(struct file *file, const char __user *ubuf,
1302 size_t count, loff_t *ppos)
1303{
Pavankumar Kondetie2904ee2011-02-15 09:42:35 +05301304 struct seq_file *s = file->private_data;
1305 struct msm_otg *motg = s->private;
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05301306 char buf[16];
Heikki Krogerus1d4c9292012-02-13 13:24:09 +02001307 struct usb_otg *otg = motg->phy.otg;
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05301308 int status = count;
Ivan T. Ivanov971232c2014-04-28 16:34:11 +03001309 enum usb_dr_mode req_mode;
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05301310
1311 memset(buf, 0x00, sizeof(buf));
1312
1313 if (copy_from_user(&buf, ubuf, min_t(size_t, sizeof(buf) - 1, count))) {
1314 status = -EFAULT;
1315 goto out;
1316 }
1317
1318 if (!strncmp(buf, "host", 4)) {
Ivan T. Ivanov971232c2014-04-28 16:34:11 +03001319 req_mode = USB_DR_MODE_HOST;
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05301320 } else if (!strncmp(buf, "peripheral", 10)) {
Ivan T. Ivanov971232c2014-04-28 16:34:11 +03001321 req_mode = USB_DR_MODE_PERIPHERAL;
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05301322 } else if (!strncmp(buf, "none", 4)) {
Ivan T. Ivanov971232c2014-04-28 16:34:11 +03001323 req_mode = USB_DR_MODE_UNKNOWN;
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05301324 } else {
1325 status = -EINVAL;
1326 goto out;
1327 }
1328
1329 switch (req_mode) {
Ivan T. Ivanov971232c2014-04-28 16:34:11 +03001330 case USB_DR_MODE_UNKNOWN:
Heikki Krogerus1d4c9292012-02-13 13:24:09 +02001331 switch (otg->phy->state) {
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05301332 case OTG_STATE_A_HOST:
1333 case OTG_STATE_B_PERIPHERAL:
1334 set_bit(ID, &motg->inputs);
1335 clear_bit(B_SESS_VLD, &motg->inputs);
1336 break;
1337 default:
1338 goto out;
1339 }
1340 break;
Ivan T. Ivanov971232c2014-04-28 16:34:11 +03001341 case USB_DR_MODE_PERIPHERAL:
Heikki Krogerus1d4c9292012-02-13 13:24:09 +02001342 switch (otg->phy->state) {
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05301343 case OTG_STATE_B_IDLE:
1344 case OTG_STATE_A_HOST:
1345 set_bit(ID, &motg->inputs);
1346 set_bit(B_SESS_VLD, &motg->inputs);
1347 break;
1348 default:
1349 goto out;
1350 }
1351 break;
Ivan T. Ivanov971232c2014-04-28 16:34:11 +03001352 case USB_DR_MODE_HOST:
Heikki Krogerus1d4c9292012-02-13 13:24:09 +02001353 switch (otg->phy->state) {
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05301354 case OTG_STATE_B_IDLE:
1355 case OTG_STATE_B_PERIPHERAL:
1356 clear_bit(ID, &motg->inputs);
1357 break;
1358 default:
1359 goto out;
1360 }
1361 break;
1362 default:
1363 goto out;
1364 }
1365
Heikki Krogerus1d4c9292012-02-13 13:24:09 +02001366 pm_runtime_get_sync(otg->phy->dev);
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05301367 schedule_work(&motg->sm_work);
1368out:
1369 return status;
1370}
1371
1372const struct file_operations msm_otg_mode_fops = {
1373 .open = msm_otg_mode_open,
1374 .read = seq_read,
1375 .write = msm_otg_mode_write,
1376 .llseek = seq_lseek,
1377 .release = single_release,
1378};
1379
1380static struct dentry *msm_otg_dbg_root;
1381static struct dentry *msm_otg_dbg_mode;
1382
1383static int msm_otg_debugfs_init(struct msm_otg *motg)
1384{
1385 msm_otg_dbg_root = debugfs_create_dir("msm_otg", NULL);
1386
1387 if (!msm_otg_dbg_root || IS_ERR(msm_otg_dbg_root))
1388 return -ENODEV;
1389
1390 msm_otg_dbg_mode = debugfs_create_file("mode", S_IRUGO | S_IWUSR,
1391 msm_otg_dbg_root, motg, &msm_otg_mode_fops);
1392 if (!msm_otg_dbg_mode) {
1393 debugfs_remove(msm_otg_dbg_root);
1394 msm_otg_dbg_root = NULL;
1395 return -ENODEV;
1396 }
1397
1398 return 0;
1399}
1400
1401static void msm_otg_debugfs_cleanup(void)
1402{
1403 debugfs_remove(msm_otg_dbg_mode);
1404 debugfs_remove(msm_otg_dbg_root);
1405}
1406
Ivan T. Ivanov8364f9a2014-04-28 16:34:15 +03001407static struct of_device_id msm_otg_dt_match[] = {
1408 {
1409 .compatible = "qcom,usb-otg-ci",
1410 .data = (void *) CI_45NM_INTEGRATED_PHY
1411 },
1412 {
1413 .compatible = "qcom,usb-otg-snps",
1414 .data = (void *) SNPS_28NM_INTEGRATED_PHY
1415 },
1416 { }
1417};
1418MODULE_DEVICE_TABLE(of, msm_otg_dt_match);
1419
1420static int msm_otg_read_dt(struct platform_device *pdev, struct msm_otg *motg)
1421{
1422 struct msm_otg_platform_data *pdata;
1423 const struct of_device_id *id;
1424 struct device_node *node = pdev->dev.of_node;
1425 struct property *prop;
1426 int len, ret, words;
1427 u32 val;
1428
1429 pdata = devm_kzalloc(&pdev->dev, sizeof(*pdata), GFP_KERNEL);
1430 if (!pdata)
1431 return -ENOMEM;
1432
1433 motg->pdata = pdata;
1434
1435 id = of_match_device(msm_otg_dt_match, &pdev->dev);
1436 pdata->phy_type = (int) id->data;
1437
Ivan T. Ivanova2734542014-04-28 16:34:16 +03001438 motg->link_rst = devm_reset_control_get(&pdev->dev, "link");
1439 if (IS_ERR(motg->link_rst))
1440 return PTR_ERR(motg->link_rst);
1441
1442 motg->phy_rst = devm_reset_control_get(&pdev->dev, "phy");
1443 if (IS_ERR(motg->phy_rst))
1444 return PTR_ERR(motg->phy_rst);
1445
Ivan T. Ivanov8364f9a2014-04-28 16:34:15 +03001446 pdata->mode = of_usb_get_dr_mode(node);
1447 if (pdata->mode == USB_DR_MODE_UNKNOWN)
1448 pdata->mode = USB_DR_MODE_OTG;
1449
1450 pdata->otg_control = OTG_PHY_CONTROL;
1451 if (!of_property_read_u32(node, "qcom,otg-control", &val))
1452 if (val == OTG_PMIC_CONTROL)
1453 pdata->otg_control = val;
1454
Ivan T. Ivanovcfa3ff52014-04-28 16:34:17 +03001455 if (!of_property_read_u32(node, "qcom,phy-num", &val) && val < 2)
1456 motg->phy_number = val;
1457
Ivan T. Ivanov8364f9a2014-04-28 16:34:15 +03001458 prop = of_find_property(node, "qcom,phy-init-sequence", &len);
1459 if (!prop || !len)
1460 return 0;
1461
1462 words = len / sizeof(u32);
1463
1464 if (words >= ULPI_EXT_VENDOR_SPECIFIC) {
1465 dev_warn(&pdev->dev, "Too big PHY init sequence %d\n", words);
1466 return 0;
1467 }
1468
1469 pdata->phy_init_seq = devm_kzalloc(&pdev->dev, len, GFP_KERNEL);
1470 if (!pdata->phy_init_seq) {
1471 dev_warn(&pdev->dev, "No space for PHY init sequence\n");
1472 return 0;
1473 }
1474
1475 ret = of_property_read_u32_array(node, "qcom,phy-init-sequence",
1476 pdata->phy_init_seq, words);
1477 if (!ret)
1478 pdata->phy_init_sz = words;
1479
1480 return 0;
1481}
1482
Ivan T. Ivanov06a6ec42014-04-28 16:34:07 +03001483static int msm_otg_probe(struct platform_device *pdev)
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05301484{
Ivan T. Ivanov6b99c68e2014-04-28 16:34:08 +03001485 struct regulator_bulk_data regs[3];
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05301486 int ret = 0;
Ivan T. Ivanov8364f9a2014-04-28 16:34:15 +03001487 struct device_node *np = pdev->dev.of_node;
1488 struct msm_otg_platform_data *pdata;
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05301489 struct resource *res;
1490 struct msm_otg *motg;
Heikki Krogerus1d4c9292012-02-13 13:24:09 +02001491 struct usb_phy *phy;
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05301492
Ivan T. Ivanov6b99c68e2014-04-28 16:34:08 +03001493 motg = devm_kzalloc(&pdev->dev, sizeof(struct msm_otg), GFP_KERNEL);
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05301494 if (!motg) {
1495 dev_err(&pdev->dev, "unable to allocate msm_otg\n");
1496 return -ENOMEM;
1497 }
1498
Ivan T. Ivanov8364f9a2014-04-28 16:34:15 +03001499 pdata = dev_get_platdata(&pdev->dev);
1500 if (!pdata) {
1501 if (!np)
1502 return -ENXIO;
1503 ret = msm_otg_read_dt(pdev, motg);
1504 if (ret)
1505 return ret;
1506 }
1507
Ivan T. Ivanov6b99c68e2014-04-28 16:34:08 +03001508 motg->phy.otg = devm_kzalloc(&pdev->dev, sizeof(struct usb_otg),
1509 GFP_KERNEL);
Heikki Krogerus1d4c9292012-02-13 13:24:09 +02001510 if (!motg->phy.otg) {
1511 dev_err(&pdev->dev, "unable to allocate msm_otg\n");
Ivan T. Ivanov6b99c68e2014-04-28 16:34:08 +03001512 return -ENOMEM;
Heikki Krogerus1d4c9292012-02-13 13:24:09 +02001513 }
1514
Heikki Krogerus1d4c9292012-02-13 13:24:09 +02001515 phy = &motg->phy;
1516 phy->dev = &pdev->dev;
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05301517
Ivan T. Ivanov8364f9a2014-04-28 16:34:15 +03001518 motg->phy_reset_clk = devm_clk_get(&pdev->dev,
1519 np ? "phy" : "usb_phy_clk");
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05301520 if (IS_ERR(motg->phy_reset_clk)) {
1521 dev_err(&pdev->dev, "failed to get usb_phy_clk\n");
Ivan T. Ivanov6b99c68e2014-04-28 16:34:08 +03001522 return PTR_ERR(motg->phy_reset_clk);
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05301523 }
1524
Ivan T. Ivanov8364f9a2014-04-28 16:34:15 +03001525 motg->clk = devm_clk_get(&pdev->dev, np ? "core" : "usb_hs_clk");
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05301526 if (IS_ERR(motg->clk)) {
1527 dev_err(&pdev->dev, "failed to get usb_hs_clk\n");
Ivan T. Ivanov6b99c68e2014-04-28 16:34:08 +03001528 return PTR_ERR(motg->clk);
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05301529 }
Anji jonnala0f73cac82011-05-04 10:19:46 +05301530
1531 /*
1532 * If USB Core is running its protocol engine based on CORE CLK,
1533 * CORE CLK must be running at >55Mhz for correct HSUSB
1534 * operation and USB core cannot tolerate frequency changes on
Ivan T. Ivanovff0e4a62014-04-28 16:34:12 +03001535 * CORE CLK.
Anji jonnala0f73cac82011-05-04 10:19:46 +05301536 */
Ivan T. Ivanov8364f9a2014-04-28 16:34:15 +03001537 motg->pclk = devm_clk_get(&pdev->dev, np ? "iface" : "usb_hs_pclk");
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05301538 if (IS_ERR(motg->pclk)) {
1539 dev_err(&pdev->dev, "failed to get usb_hs_pclk\n");
Ivan T. Ivanov6b99c68e2014-04-28 16:34:08 +03001540 return PTR_ERR(motg->pclk);
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05301541 }
1542
1543 /*
1544 * USB core clock is not present on all MSM chips. This
1545 * clock is introduced to remove the dependency on AXI
1546 * bus frequency.
1547 */
Ivan T. Ivanov8364f9a2014-04-28 16:34:15 +03001548 motg->core_clk = devm_clk_get(&pdev->dev,
1549 np ? "alt_core" : "usb_hs_core_clk");
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05301550
1551 res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
Ivan T. Ivanov6b99c68e2014-04-28 16:34:08 +03001552 motg->regs = devm_ioremap(&pdev->dev, res->start, resource_size(res));
1553 if (IS_ERR(motg->regs))
1554 return PTR_ERR(motg->regs);
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05301555
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05301556 dev_info(&pdev->dev, "OTG regs = %p\n", motg->regs);
1557
1558 motg->irq = platform_get_irq(pdev, 0);
Ivan T. Ivanovf60c1142014-04-28 16:34:14 +03001559 if (motg->irq < 0) {
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05301560 dev_err(&pdev->dev, "platform_get_irq failed\n");
Ivan T. Ivanov6b99c68e2014-04-28 16:34:08 +03001561 return motg->irq;
1562 }
1563
Ivan T. Ivanovf5ef2372014-04-28 16:34:13 +03001564 regs[0].supply = "vddcx";
1565 regs[1].supply = "v3p3";
1566 regs[2].supply = "v1p8";
Ivan T. Ivanov6b99c68e2014-04-28 16:34:08 +03001567
1568 ret = devm_regulator_bulk_get(motg->phy.dev, ARRAY_SIZE(regs), regs);
1569 if (ret)
1570 return ret;
1571
1572 motg->vddcx = regs[0].consumer;
1573 motg->v3p3 = regs[1].consumer;
1574 motg->v1p8 = regs[2].consumer;
1575
1576 clk_set_rate(motg->clk, 60000000);
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05301577
Stephen Boydb99a8f62013-06-17 10:43:10 -07001578 clk_prepare_enable(motg->clk);
1579 clk_prepare_enable(motg->pclk);
Anji jonnala11aa5c42011-05-04 10:19:48 +05301580
Ivan T. Ivanov6b99c68e2014-04-28 16:34:08 +03001581 if (!IS_ERR(motg->core_clk))
1582 clk_prepare_enable(motg->core_clk);
1583
Anji jonnala11aa5c42011-05-04 10:19:48 +05301584 ret = msm_hsusb_init_vddcx(motg, 1);
1585 if (ret) {
1586 dev_err(&pdev->dev, "hsusb vddcx configuration failed\n");
Ivan T. Ivanov6b99c68e2014-04-28 16:34:08 +03001587 goto disable_clks;
Anji jonnala11aa5c42011-05-04 10:19:48 +05301588 }
1589
1590 ret = msm_hsusb_ldo_init(motg, 1);
1591 if (ret) {
1592 dev_err(&pdev->dev, "hsusb vreg configuration failed\n");
Ivan T. Ivanov6b99c68e2014-04-28 16:34:08 +03001593 goto disable_vddcx;
Anji jonnala11aa5c42011-05-04 10:19:48 +05301594 }
Ivan T. Ivanov37cfdaf2014-04-28 16:34:06 +03001595 ret = msm_hsusb_ldo_set_mode(motg, 1);
Anji jonnala11aa5c42011-05-04 10:19:48 +05301596 if (ret) {
1597 dev_err(&pdev->dev, "hsusb vreg enable failed\n");
Ivan T. Ivanov6b99c68e2014-04-28 16:34:08 +03001598 goto disable_ldo;
Anji jonnala11aa5c42011-05-04 10:19:48 +05301599 }
1600
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05301601 writel(0, USB_USBINTR);
1602 writel(0, USB_OTGSC);
1603
1604 INIT_WORK(&motg->sm_work, msm_otg_sm_work);
Pavankumar Kondetid8608522011-05-04 10:19:47 +05301605 INIT_DELAYED_WORK(&motg->chg_work, msm_chg_detect_work);
Ivan T. Ivanov6b99c68e2014-04-28 16:34:08 +03001606 ret = devm_request_irq(&pdev->dev, motg->irq, msm_otg_irq, IRQF_SHARED,
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05301607 "msm_otg", motg);
1608 if (ret) {
1609 dev_err(&pdev->dev, "request irq failed\n");
Ivan T. Ivanov6b99c68e2014-04-28 16:34:08 +03001610 goto disable_ldo;
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05301611 }
1612
Ivan T. Ivanovd69c6f52014-04-28 16:34:18 +03001613 phy->init = msm_phy_init;
Heikki Krogerus1d4c9292012-02-13 13:24:09 +02001614 phy->set_power = msm_otg_set_power;
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05301615
Heikki Krogerus1d4c9292012-02-13 13:24:09 +02001616 phy->io_ops = &msm_otg_io_ops;
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05301617
Heikki Krogerus1d4c9292012-02-13 13:24:09 +02001618 phy->otg->phy = &motg->phy;
1619 phy->otg->set_host = msm_otg_set_host;
1620 phy->otg->set_peripheral = msm_otg_set_peripheral;
1621
Ivan T. Ivanovd69c6f52014-04-28 16:34:18 +03001622 msm_usb_reset(phy);
1623
Kishon Vijay Abraham I662dca52012-06-22 17:02:46 +05301624 ret = usb_add_phy(&motg->phy, USB_PHY_TYPE_USB2);
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05301625 if (ret) {
Kishon Vijay Abraham I721002e2012-06-22 17:02:45 +05301626 dev_err(&pdev->dev, "usb_add_phy failed\n");
Ivan T. Ivanov6b99c68e2014-04-28 16:34:08 +03001627 goto disable_ldo;
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05301628 }
1629
1630 platform_set_drvdata(pdev, motg);
1631 device_init_wakeup(&pdev->dev, 1);
1632
Ivan T. Ivanov971232c2014-04-28 16:34:11 +03001633 if (motg->pdata->mode == USB_DR_MODE_OTG &&
Ivan T. Ivanov8364f9a2014-04-28 16:34:15 +03001634 motg->pdata->otg_control == OTG_USER_CONTROL) {
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05301635 ret = msm_otg_debugfs_init(motg);
1636 if (ret)
Ivan T. Ivanov3aca0fa2014-04-28 16:34:10 +03001637 dev_dbg(&pdev->dev, "Can not create mode change file\n");
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05301638 }
1639
Pavankumar Kondeti87c01042010-12-07 17:53:58 +05301640 pm_runtime_set_active(&pdev->dev);
1641 pm_runtime_enable(&pdev->dev);
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05301642
Pavankumar Kondeti87c01042010-12-07 17:53:58 +05301643 return 0;
Ivan T. Ivanov6b99c68e2014-04-28 16:34:08 +03001644
1645disable_ldo:
1646 msm_hsusb_ldo_init(motg, 0);
1647disable_vddcx:
1648 msm_hsusb_init_vddcx(motg, 0);
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05301649disable_clks:
Stephen Boydb99a8f62013-06-17 10:43:10 -07001650 clk_disable_unprepare(motg->pclk);
1651 clk_disable_unprepare(motg->clk);
Ivan T. Ivanov6b99c68e2014-04-28 16:34:08 +03001652 if (!IS_ERR(motg->core_clk))
1653 clk_disable_unprepare(motg->core_clk);
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05301654 return ret;
1655}
1656
Bill Pembertonfb4e98a2012-11-19 13:26:20 -05001657static int msm_otg_remove(struct platform_device *pdev)
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05301658{
1659 struct msm_otg *motg = platform_get_drvdata(pdev);
Heikki Krogerus1d4c9292012-02-13 13:24:09 +02001660 struct usb_phy *phy = &motg->phy;
Pavankumar Kondeti87c01042010-12-07 17:53:58 +05301661 int cnt = 0;
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05301662
Heikki Krogerus1d4c9292012-02-13 13:24:09 +02001663 if (phy->otg->host || phy->otg->gadget)
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05301664 return -EBUSY;
1665
1666 msm_otg_debugfs_cleanup();
Pavankumar Kondetid8608522011-05-04 10:19:47 +05301667 cancel_delayed_work_sync(&motg->chg_work);
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05301668 cancel_work_sync(&motg->sm_work);
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05301669
Pavankumar Kondeti70187732011-02-15 09:42:34 +05301670 pm_runtime_resume(&pdev->dev);
Pavankumar Kondeti87c01042010-12-07 17:53:58 +05301671
1672 device_init_wakeup(&pdev->dev, 0);
1673 pm_runtime_disable(&pdev->dev);
1674
Kishon Vijay Abraham I662dca52012-06-22 17:02:46 +05301675 usb_remove_phy(phy);
Ivan T. Ivanov6b99c68e2014-04-28 16:34:08 +03001676 disable_irq(motg->irq);
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05301677
Pavankumar Kondeti87c01042010-12-07 17:53:58 +05301678 /*
1679 * Put PHY in low power mode.
1680 */
Heikki Krogerus1d4c9292012-02-13 13:24:09 +02001681 ulpi_read(phy, 0x14);
1682 ulpi_write(phy, 0x08, 0x09);
Pavankumar Kondeti87c01042010-12-07 17:53:58 +05301683
1684 writel(readl(USB_PORTSC) | PORTSC_PHCD, USB_PORTSC);
1685 while (cnt < PHY_SUSPEND_TIMEOUT_USEC) {
1686 if (readl(USB_PORTSC) & PORTSC_PHCD)
1687 break;
1688 udelay(1);
1689 cnt++;
1690 }
1691 if (cnt >= PHY_SUSPEND_TIMEOUT_USEC)
Heikki Krogerus1d4c9292012-02-13 13:24:09 +02001692 dev_err(phy->dev, "Unable to suspend PHY\n");
Pavankumar Kondeti87c01042010-12-07 17:53:58 +05301693
Stephen Boydb99a8f62013-06-17 10:43:10 -07001694 clk_disable_unprepare(motg->pclk);
1695 clk_disable_unprepare(motg->clk);
Ivan T. Ivanov6b99c68e2014-04-28 16:34:08 +03001696 if (!IS_ERR(motg->core_clk))
Stephen Boydb99a8f62013-06-17 10:43:10 -07001697 clk_disable_unprepare(motg->core_clk);
Anji jonnala11aa5c42011-05-04 10:19:48 +05301698 msm_hsusb_ldo_init(motg, 0);
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05301699
Pavankumar Kondeti87c01042010-12-07 17:53:58 +05301700 pm_runtime_set_suspended(&pdev->dev);
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05301701
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05301702 return 0;
1703}
1704
Pavankumar Kondeti87c01042010-12-07 17:53:58 +05301705#ifdef CONFIG_PM_RUNTIME
1706static int msm_otg_runtime_idle(struct device *dev)
1707{
1708 struct msm_otg *motg = dev_get_drvdata(dev);
Heikki Krogerus1d4c9292012-02-13 13:24:09 +02001709 struct usb_otg *otg = motg->phy.otg;
Pavankumar Kondeti87c01042010-12-07 17:53:58 +05301710
1711 dev_dbg(dev, "OTG runtime idle\n");
1712
1713 /*
1714 * It is observed some times that a spurious interrupt
1715 * comes when PHY is put into LPM immediately after PHY reset.
1716 * This 1 sec delay also prevents entering into LPM immediately
1717 * after asynchronous interrupt.
1718 */
Heikki Krogerus1d4c9292012-02-13 13:24:09 +02001719 if (otg->phy->state != OTG_STATE_UNDEFINED)
Pavankumar Kondeti87c01042010-12-07 17:53:58 +05301720 pm_schedule_suspend(dev, 1000);
1721
1722 return -EAGAIN;
1723}
1724
1725static int msm_otg_runtime_suspend(struct device *dev)
1726{
1727 struct msm_otg *motg = dev_get_drvdata(dev);
1728
1729 dev_dbg(dev, "OTG runtime suspend\n");
1730 return msm_otg_suspend(motg);
1731}
1732
1733static int msm_otg_runtime_resume(struct device *dev)
1734{
1735 struct msm_otg *motg = dev_get_drvdata(dev);
1736
1737 dev_dbg(dev, "OTG runtime resume\n");
1738 return msm_otg_resume(motg);
1739}
Pavankumar Kondeti87c01042010-12-07 17:53:58 +05301740#endif
1741
Pavankumar Kondeti70187732011-02-15 09:42:34 +05301742#ifdef CONFIG_PM_SLEEP
Pavankumar Kondeti87c01042010-12-07 17:53:58 +05301743static int msm_otg_pm_suspend(struct device *dev)
1744{
1745 struct msm_otg *motg = dev_get_drvdata(dev);
1746
1747 dev_dbg(dev, "OTG PM suspend\n");
1748 return msm_otg_suspend(motg);
1749}
1750
1751static int msm_otg_pm_resume(struct device *dev)
1752{
1753 struct msm_otg *motg = dev_get_drvdata(dev);
1754 int ret;
1755
1756 dev_dbg(dev, "OTG PM resume\n");
1757
1758 ret = msm_otg_resume(motg);
1759 if (ret)
1760 return ret;
1761
1762 /*
1763 * Runtime PM Documentation recommends bringing the
1764 * device to full powered state upon resume.
1765 */
1766 pm_runtime_disable(dev);
1767 pm_runtime_set_active(dev);
1768 pm_runtime_enable(dev);
1769
1770 return 0;
1771}
Pavankumar Kondeti87c01042010-12-07 17:53:58 +05301772#endif
1773
1774static const struct dev_pm_ops msm_otg_dev_pm_ops = {
Pavankumar Kondeti70187732011-02-15 09:42:34 +05301775 SET_SYSTEM_SLEEP_PM_OPS(msm_otg_pm_suspend, msm_otg_pm_resume)
1776 SET_RUNTIME_PM_OPS(msm_otg_runtime_suspend, msm_otg_runtime_resume,
1777 msm_otg_runtime_idle)
Pavankumar Kondeti87c01042010-12-07 17:53:58 +05301778};
1779
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05301780static struct platform_driver msm_otg_driver = {
Ivan T. Ivanov06a6ec42014-04-28 16:34:07 +03001781 .probe = msm_otg_probe,
Bill Pemberton76904172012-11-19 13:21:08 -05001782 .remove = msm_otg_remove,
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05301783 .driver = {
1784 .name = DRIVER_NAME,
1785 .owner = THIS_MODULE,
Pavankumar Kondeti87c01042010-12-07 17:53:58 +05301786 .pm = &msm_otg_dev_pm_ops,
Ivan T. Ivanov8364f9a2014-04-28 16:34:15 +03001787 .of_match_table = msm_otg_dt_match,
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05301788 },
1789};
1790
Ivan T. Ivanov06a6ec42014-04-28 16:34:07 +03001791module_platform_driver(msm_otg_driver);
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05301792
1793MODULE_LICENSE("GPL v2");
1794MODULE_DESCRIPTION("MSM USB transceiver driver");