blob: 970a30e155cb51bfd1d15126d8cdc65f9adf579c [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>
Ivan T. Ivanov6f98f542015-07-28 11:10:22 +030021#include <linux/gpio/consumer.h>
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +053022#include <linux/platform_device.h>
23#include <linux/clk.h>
24#include <linux/slab.h>
25#include <linux/interrupt.h>
26#include <linux/err.h>
27#include <linux/delay.h>
28#include <linux/io.h>
29#include <linux/ioport.h>
30#include <linux/uaccess.h>
31#include <linux/debugfs.h>
32#include <linux/seq_file.h>
Pavankumar Kondeti87c01042010-12-07 17:53:58 +053033#include <linux/pm_runtime.h>
Ivan T. Ivanov8364f9a2014-04-28 16:34:15 +030034#include <linux/of.h>
35#include <linux/of_device.h>
Ivan T. Ivanov6f98f542015-07-28 11:10:22 +030036#include <linux/reboot.h>
Ivan T. Ivanova2734542014-04-28 16:34:16 +030037#include <linux/reset.h>
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +053038
39#include <linux/usb.h>
40#include <linux/usb/otg.h>
Ivan T. Ivanov8364f9a2014-04-28 16:34:15 +030041#include <linux/usb/of.h>
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +053042#include <linux/usb/ulpi.h>
43#include <linux/usb/gadget.h>
44#include <linux/usb/hcd.h>
45#include <linux/usb/msm_hsusb.h>
46#include <linux/usb/msm_hsusb_hw.h>
Anji jonnala11aa5c42011-05-04 10:19:48 +053047#include <linux/regulator/consumer.h>
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +053048
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +053049#define MSM_USB_BASE (motg->regs)
50#define DRIVER_NAME "msm_otg"
51
52#define ULPI_IO_TIMEOUT_USEC (10 * 1000)
Ivan T. Ivanovd69c6f52014-04-28 16:34:18 +030053#define LINK_RESET_TIMEOUT_USEC (250 * 1000)
Anji jonnala11aa5c42011-05-04 10:19:48 +053054
55#define USB_PHY_3P3_VOL_MIN 3050000 /* uV */
56#define USB_PHY_3P3_VOL_MAX 3300000 /* uV */
57#define USB_PHY_3P3_HPM_LOAD 50000 /* uA */
58#define USB_PHY_3P3_LPM_LOAD 4000 /* uA */
59
60#define USB_PHY_1P8_VOL_MIN 1800000 /* uV */
61#define USB_PHY_1P8_VOL_MAX 1800000 /* uV */
62#define USB_PHY_1P8_HPM_LOAD 50000 /* uA */
63#define USB_PHY_1P8_LPM_LOAD 4000 /* uA */
64
65#define USB_PHY_VDD_DIG_VOL_MIN 1000000 /* uV */
66#define USB_PHY_VDD_DIG_VOL_MAX 1320000 /* uV */
Ivan T. Ivanov01799b62014-04-28 16:34:22 +030067#define USB_PHY_SUSP_DIG_VOL 500000 /* uV */
68
69enum vdd_levels {
70 VDD_LEVEL_NONE = 0,
71 VDD_LEVEL_MIN,
72 VDD_LEVEL_MAX,
73};
Anji jonnala11aa5c42011-05-04 10:19:48 +053074
Anji jonnala11aa5c42011-05-04 10:19:48 +053075static int msm_hsusb_init_vddcx(struct msm_otg *motg, int init)
76{
77 int ret = 0;
78
79 if (init) {
Ivan T. Ivanov37cfdaf2014-04-28 16:34:06 +030080 ret = regulator_set_voltage(motg->vddcx,
Ivan T. Ivanov01799b62014-04-28 16:34:22 +030081 motg->vdd_levels[VDD_LEVEL_MIN],
82 motg->vdd_levels[VDD_LEVEL_MAX]);
Anji jonnala11aa5c42011-05-04 10:19:48 +053083 if (ret) {
Ivan T. Ivanov3aca0fa2014-04-28 16:34:10 +030084 dev_err(motg->phy.dev, "Cannot set vddcx voltage\n");
Anji jonnala11aa5c42011-05-04 10:19:48 +053085 return ret;
86 }
87
Ivan T. Ivanov37cfdaf2014-04-28 16:34:06 +030088 ret = regulator_enable(motg->vddcx);
Ivan T. Ivanov6b99c68e2014-04-28 16:34:08 +030089 if (ret)
Heikki Krogerus1d4c9292012-02-13 13:24:09 +020090 dev_err(motg->phy.dev, "unable to enable hsusb vddcx\n");
Anji jonnala11aa5c42011-05-04 10:19:48 +053091 } else {
Ivan T. Ivanov37cfdaf2014-04-28 16:34:06 +030092 ret = regulator_set_voltage(motg->vddcx, 0,
Ivan T. Ivanov01799b62014-04-28 16:34:22 +030093 motg->vdd_levels[VDD_LEVEL_MAX]);
Mark Browne99c4302011-05-15 09:55:58 -070094 if (ret)
Ivan T. Ivanov3aca0fa2014-04-28 16:34:10 +030095 dev_err(motg->phy.dev, "Cannot set vddcx voltage\n");
Ivan T. Ivanov37cfdaf2014-04-28 16:34:06 +030096 ret = regulator_disable(motg->vddcx);
Anji jonnala11aa5c42011-05-04 10:19:48 +053097 if (ret)
Heikki Krogerus1d4c9292012-02-13 13:24:09 +020098 dev_err(motg->phy.dev, "unable to disable hsusb vddcx\n");
Anji jonnala11aa5c42011-05-04 10:19:48 +053099 }
100
101 return ret;
102}
103
104static int msm_hsusb_ldo_init(struct msm_otg *motg, int init)
105{
106 int rc = 0;
107
108 if (init) {
Ivan T. Ivanov37cfdaf2014-04-28 16:34:06 +0300109 rc = regulator_set_voltage(motg->v3p3, USB_PHY_3P3_VOL_MIN,
Anji jonnala11aa5c42011-05-04 10:19:48 +0530110 USB_PHY_3P3_VOL_MAX);
111 if (rc) {
Ivan T. Ivanov3aca0fa2014-04-28 16:34:10 +0300112 dev_err(motg->phy.dev, "Cannot set v3p3 voltage\n");
Ivan T. Ivanov6b99c68e2014-04-28 16:34:08 +0300113 goto exit;
Anji jonnala11aa5c42011-05-04 10:19:48 +0530114 }
Ivan T. Ivanov37cfdaf2014-04-28 16:34:06 +0300115 rc = regulator_enable(motg->v3p3);
Anji jonnala11aa5c42011-05-04 10:19:48 +0530116 if (rc) {
Heikki Krogerus1d4c9292012-02-13 13:24:09 +0200117 dev_err(motg->phy.dev, "unable to enable the hsusb 3p3\n");
Ivan T. Ivanov6b99c68e2014-04-28 16:34:08 +0300118 goto exit;
Anji jonnala11aa5c42011-05-04 10:19:48 +0530119 }
Ivan T. Ivanov37cfdaf2014-04-28 16:34:06 +0300120 rc = regulator_set_voltage(motg->v1p8, USB_PHY_1P8_VOL_MIN,
Anji jonnala11aa5c42011-05-04 10:19:48 +0530121 USB_PHY_1P8_VOL_MAX);
122 if (rc) {
Ivan T. Ivanov3aca0fa2014-04-28 16:34:10 +0300123 dev_err(motg->phy.dev, "Cannot set v1p8 voltage\n");
Ivan T. Ivanov6b99c68e2014-04-28 16:34:08 +0300124 goto disable_3p3;
Anji jonnala11aa5c42011-05-04 10:19:48 +0530125 }
Ivan T. Ivanov37cfdaf2014-04-28 16:34:06 +0300126 rc = regulator_enable(motg->v1p8);
Anji jonnala11aa5c42011-05-04 10:19:48 +0530127 if (rc) {
Heikki Krogerus1d4c9292012-02-13 13:24:09 +0200128 dev_err(motg->phy.dev, "unable to enable the hsusb 1p8\n");
Ivan T. Ivanov6b99c68e2014-04-28 16:34:08 +0300129 goto disable_3p3;
Anji jonnala11aa5c42011-05-04 10:19:48 +0530130 }
131
132 return 0;
133 }
134
Ivan T. Ivanov37cfdaf2014-04-28 16:34:06 +0300135 regulator_disable(motg->v1p8);
Anji jonnala11aa5c42011-05-04 10:19:48 +0530136disable_3p3:
Ivan T. Ivanov37cfdaf2014-04-28 16:34:06 +0300137 regulator_disable(motg->v3p3);
Ivan T. Ivanov6b99c68e2014-04-28 16:34:08 +0300138exit:
Anji jonnala11aa5c42011-05-04 10:19:48 +0530139 return rc;
140}
141
Ivan T. Ivanov37cfdaf2014-04-28 16:34:06 +0300142static int msm_hsusb_ldo_set_mode(struct msm_otg *motg, int on)
Anji jonnala11aa5c42011-05-04 10:19:48 +0530143{
144 int ret = 0;
145
Anji jonnala11aa5c42011-05-04 10:19:48 +0530146 if (on) {
Bjorn Anderssonfa53e352015-02-11 19:35:30 -0800147 ret = regulator_set_load(motg->v1p8, USB_PHY_1P8_HPM_LOAD);
Anji jonnala11aa5c42011-05-04 10:19:48 +0530148 if (ret < 0) {
Ivan T. Ivanov3aca0fa2014-04-28 16:34:10 +0300149 pr_err("Could not set HPM for v1p8\n");
Anji jonnala11aa5c42011-05-04 10:19:48 +0530150 return ret;
151 }
Bjorn Anderssonfa53e352015-02-11 19:35:30 -0800152 ret = regulator_set_load(motg->v3p3, USB_PHY_3P3_HPM_LOAD);
Anji jonnala11aa5c42011-05-04 10:19:48 +0530153 if (ret < 0) {
Ivan T. Ivanov3aca0fa2014-04-28 16:34:10 +0300154 pr_err("Could not set HPM for v3p3\n");
Bjorn Anderssonfa53e352015-02-11 19:35:30 -0800155 regulator_set_load(motg->v1p8, USB_PHY_1P8_LPM_LOAD);
Anji jonnala11aa5c42011-05-04 10:19:48 +0530156 return ret;
157 }
158 } else {
Bjorn Anderssonfa53e352015-02-11 19:35:30 -0800159 ret = regulator_set_load(motg->v1p8, USB_PHY_1P8_LPM_LOAD);
Anji jonnala11aa5c42011-05-04 10:19:48 +0530160 if (ret < 0)
Ivan T. Ivanov3aca0fa2014-04-28 16:34:10 +0300161 pr_err("Could not set LPM for v1p8\n");
Bjorn Anderssonfa53e352015-02-11 19:35:30 -0800162 ret = regulator_set_load(motg->v3p3, USB_PHY_3P3_LPM_LOAD);
Anji jonnala11aa5c42011-05-04 10:19:48 +0530163 if (ret < 0)
Ivan T. Ivanov3aca0fa2014-04-28 16:34:10 +0300164 pr_err("Could not set LPM for v3p3\n");
Anji jonnala11aa5c42011-05-04 10:19:48 +0530165 }
166
167 pr_debug("reg (%s)\n", on ? "HPM" : "LPM");
168 return ret < 0 ? ret : 0;
169}
170
Heikki Krogerus1d4c9292012-02-13 13:24:09 +0200171static int ulpi_read(struct usb_phy *phy, u32 reg)
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +0530172{
Heikki Krogerus1d4c9292012-02-13 13:24:09 +0200173 struct msm_otg *motg = container_of(phy, struct msm_otg, phy);
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +0530174 int cnt = 0;
175
176 /* initiate read operation */
177 writel(ULPI_RUN | ULPI_READ | ULPI_ADDR(reg),
178 USB_ULPI_VIEWPORT);
179
180 /* wait for completion */
181 while (cnt < ULPI_IO_TIMEOUT_USEC) {
182 if (!(readl(USB_ULPI_VIEWPORT) & ULPI_RUN))
183 break;
184 udelay(1);
185 cnt++;
186 }
187
188 if (cnt >= ULPI_IO_TIMEOUT_USEC) {
Heikki Krogerus1d4c9292012-02-13 13:24:09 +0200189 dev_err(phy->dev, "ulpi_read: timeout %08x\n",
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +0530190 readl(USB_ULPI_VIEWPORT));
191 return -ETIMEDOUT;
192 }
193 return ULPI_DATA_READ(readl(USB_ULPI_VIEWPORT));
194}
195
Heikki Krogerus1d4c9292012-02-13 13:24:09 +0200196static int ulpi_write(struct usb_phy *phy, u32 val, u32 reg)
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +0530197{
Heikki Krogerus1d4c9292012-02-13 13:24:09 +0200198 struct msm_otg *motg = container_of(phy, struct msm_otg, phy);
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +0530199 int cnt = 0;
200
201 /* initiate write operation */
202 writel(ULPI_RUN | ULPI_WRITE |
203 ULPI_ADDR(reg) | ULPI_DATA(val),
204 USB_ULPI_VIEWPORT);
205
206 /* wait for completion */
207 while (cnt < ULPI_IO_TIMEOUT_USEC) {
208 if (!(readl(USB_ULPI_VIEWPORT) & ULPI_RUN))
209 break;
210 udelay(1);
211 cnt++;
212 }
213
214 if (cnt >= ULPI_IO_TIMEOUT_USEC) {
Heikki Krogerus1d4c9292012-02-13 13:24:09 +0200215 dev_err(phy->dev, "ulpi_write: timeout\n");
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +0530216 return -ETIMEDOUT;
217 }
218 return 0;
219}
220
Heikki Krogerus1d4c9292012-02-13 13:24:09 +0200221static struct usb_phy_io_ops msm_otg_io_ops = {
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +0530222 .read = ulpi_read,
223 .write = ulpi_write,
224};
225
226static void ulpi_init(struct msm_otg *motg)
227{
228 struct msm_otg_platform_data *pdata = motg->pdata;
Ivan T. Ivanov8364f9a2014-04-28 16:34:15 +0300229 int *seq = pdata->phy_init_seq, idx;
230 u32 addr = ULPI_EXT_VENDOR_SPECIFIC;
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +0530231
Ivan T. Ivanov8364f9a2014-04-28 16:34:15 +0300232 for (idx = 0; idx < pdata->phy_init_sz; idx++) {
233 if (seq[idx] == -1)
234 continue;
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +0530235
Heikki Krogerus1d4c9292012-02-13 13:24:09 +0200236 dev_vdbg(motg->phy.dev, "ulpi: write 0x%02x to 0x%02x\n",
Ivan T. Ivanov8364f9a2014-04-28 16:34:15 +0300237 seq[idx], addr + idx);
238 ulpi_write(&motg->phy, seq[idx], addr + idx);
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +0530239 }
240}
241
Ivan T. Ivanov349907c2014-04-28 16:34:21 +0300242static int msm_phy_notify_disconnect(struct usb_phy *phy,
243 enum usb_device_speed speed)
244{
Ivan T. Ivanov44e42ae2015-04-09 11:34:33 +0300245 struct msm_otg *motg = container_of(phy, struct msm_otg, phy);
Ivan T. Ivanov349907c2014-04-28 16:34:21 +0300246 int val;
247
Ivan T. Ivanov44e42ae2015-04-09 11:34:33 +0300248 if (motg->manual_pullup) {
249 val = ULPI_MISC_A_VBUSVLDEXT | ULPI_MISC_A_VBUSVLDEXTSEL;
250 usb_phy_io_write(phy, val, ULPI_CLR(ULPI_MISC_A));
251 }
252
Ivan T. Ivanov349907c2014-04-28 16:34:21 +0300253 /*
254 * Put the transceiver in non-driving mode. Otherwise host
255 * may not detect soft-disconnection.
256 */
257 val = ulpi_read(phy, ULPI_FUNC_CTRL);
258 val &= ~ULPI_FUNC_CTRL_OPMODE_MASK;
259 val |= ULPI_FUNC_CTRL_OPMODE_NONDRIVING;
260 ulpi_write(phy, val, ULPI_FUNC_CTRL);
261
262 return 0;
263}
264
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +0530265static int msm_otg_link_clk_reset(struct msm_otg *motg, bool assert)
266{
Ivan T. Ivanova2734542014-04-28 16:34:16 +0300267 int ret;
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +0530268
Stephen Boyd32fc9eb2015-03-13 11:09:42 -0700269 if (assert)
Ivan T. Ivanova2734542014-04-28 16:34:16 +0300270 ret = reset_control_assert(motg->link_rst);
271 else
272 ret = reset_control_deassert(motg->link_rst);
Ivan T. Ivanov5146d772013-12-30 13:15:27 -0800273
Ivan T. Ivanov5146d772013-12-30 13:15:27 -0800274 if (ret)
275 dev_err(motg->phy.dev, "usb link clk reset %s failed\n",
276 assert ? "assert" : "deassert");
277
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +0530278 return ret;
279}
280
281static int msm_otg_phy_clk_reset(struct msm_otg *motg)
282{
Srinivas Kandagatlae44f1f42014-06-30 18:29:49 +0100283 int ret = 0;
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +0530284
Stephen Boyd32fc9eb2015-03-13 11:09:42 -0700285 if (motg->phy_rst)
Ivan T. Ivanova2734542014-04-28 16:34:16 +0300286 ret = reset_control_reset(motg->phy_rst);
Ivan T. Ivanov5146d772013-12-30 13:15:27 -0800287
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +0530288 if (ret)
Ivan T. Ivanov5146d772013-12-30 13:15:27 -0800289 dev_err(motg->phy.dev, "usb phy clk reset failed\n");
290
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +0530291 return ret;
292}
293
Ivan T. Ivanovd69c6f52014-04-28 16:34:18 +0300294static int msm_link_reset(struct msm_otg *motg)
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +0530295{
296 u32 val;
297 int ret;
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +0530298
299 ret = msm_otg_link_clk_reset(motg, 1);
300 if (ret)
301 return ret;
Ivan T. Ivanovd69c6f52014-04-28 16:34:18 +0300302
303 /* wait for 1ms delay as suggested in HPG. */
304 usleep_range(1000, 1200);
305
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +0530306 ret = msm_otg_link_clk_reset(motg, 0);
307 if (ret)
308 return ret;
309
Ivan T. Ivanovcfa3ff52014-04-28 16:34:17 +0300310 if (motg->phy_number)
311 writel(readl(USB_PHY_CTRL2) | BIT(16), USB_PHY_CTRL2);
312
Tim Bird9f27984b2014-04-28 16:34:19 +0300313 /* put transceiver in serial mode as part of reset */
Ivan T. Ivanovd69c6f52014-04-28 16:34:18 +0300314 val = readl(USB_PORTSC) & ~PORTSC_PTS_MASK;
Tim Bird9f27984b2014-04-28 16:34:19 +0300315 writel(val | PORTSC_PTS_SERIAL, USB_PORTSC);
Ivan T. Ivanovd69c6f52014-04-28 16:34:18 +0300316
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +0530317 return 0;
318}
319
Heikki Krogerus1d4c9292012-02-13 13:24:09 +0200320static int msm_otg_reset(struct usb_phy *phy)
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +0530321{
Heikki Krogerus1d4c9292012-02-13 13:24:09 +0200322 struct msm_otg *motg = container_of(phy, struct msm_otg, phy);
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +0530323 int cnt = 0;
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +0530324
325 writel(USBCMD_RESET, USB_USBCMD);
326 while (cnt < LINK_RESET_TIMEOUT_USEC) {
327 if (!(readl(USB_USBCMD) & USBCMD_RESET))
328 break;
329 udelay(1);
330 cnt++;
331 }
332 if (cnt >= LINK_RESET_TIMEOUT_USEC)
333 return -ETIMEDOUT;
334
Tim Bird9f27984b2014-04-28 16:34:19 +0300335 /* select ULPI phy and clear other status/control bits in PORTSC */
336 writel(PORTSC_PTS_ULPI, USB_PORTSC);
337
Ivan T. Ivanovd69c6f52014-04-28 16:34:18 +0300338 writel(0x0, USB_AHBBURST);
339 writel(0x08, USB_AHBMODE);
340
341 if (motg->phy_number)
342 writel(readl(USB_PHY_CTRL2) | BIT(16), USB_PHY_CTRL2);
343 return 0;
344}
345
346static void msm_phy_reset(struct msm_otg *motg)
347{
348 void __iomem *addr;
349
350 if (motg->pdata->phy_type != SNPS_28NM_INTEGRATED_PHY) {
351 msm_otg_phy_clk_reset(motg);
352 return;
353 }
354
355 addr = USB_PHY_CTRL;
356 if (motg->phy_number)
357 addr = USB_PHY_CTRL2;
358
359 /* Assert USB PHY_POR */
360 writel(readl(addr) | PHY_POR_ASSERT, addr);
361
362 /*
363 * wait for minimum 10 microseconds as suggested in HPG.
364 * Use a slightly larger value since the exact value didn't
365 * work 100% of the time.
366 */
367 udelay(12);
368
369 /* Deassert USB PHY_POR */
370 writel(readl(addr) & ~PHY_POR_ASSERT, addr);
371}
372
373static int msm_usb_reset(struct usb_phy *phy)
374{
375 struct msm_otg *motg = container_of(phy, struct msm_otg, phy);
376 int ret;
377
378 if (!IS_ERR(motg->core_clk))
379 clk_prepare_enable(motg->core_clk);
380
381 ret = msm_link_reset(motg);
382 if (ret) {
383 dev_err(phy->dev, "phy_reset failed\n");
384 return ret;
385 }
386
387 ret = msm_otg_reset(&motg->phy);
388 if (ret) {
389 dev_err(phy->dev, "link reset failed\n");
390 return ret;
391 }
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +0530392
393 msleep(100);
394
Ivan T. Ivanovd69c6f52014-04-28 16:34:18 +0300395 /* Reset USB PHY after performing USB Link RESET */
396 msm_phy_reset(motg);
397
398 if (!IS_ERR(motg->core_clk))
399 clk_disable_unprepare(motg->core_clk);
400
401 return 0;
402}
403
404static int msm_phy_init(struct usb_phy *phy)
405{
406 struct msm_otg *motg = container_of(phy, struct msm_otg, phy);
407 struct msm_otg_platform_data *pdata = motg->pdata;
408 u32 val, ulpi_val = 0;
409
410 /* Program USB PHY Override registers. */
411 ulpi_init(motg);
412
413 /*
414 * It is recommended in HPG to reset USB PHY after programming
415 * USB PHY Override registers.
416 */
417 msm_phy_reset(motg);
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +0530418
419 if (pdata->otg_control == OTG_PHY_CONTROL) {
420 val = readl(USB_OTGSC);
Ivan T. Ivanov971232c2014-04-28 16:34:11 +0300421 if (pdata->mode == USB_DR_MODE_OTG) {
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +0530422 ulpi_val = ULPI_INT_IDGRD | ULPI_INT_SESS_VALID;
423 val |= OTGSC_IDIE | OTGSC_BSVIE;
Ivan T. Ivanov971232c2014-04-28 16:34:11 +0300424 } else if (pdata->mode == USB_DR_MODE_PERIPHERAL) {
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +0530425 ulpi_val = ULPI_INT_SESS_VALID;
426 val |= OTGSC_BSVIE;
427 }
428 writel(val, USB_OTGSC);
Heikki Krogerus1d4c9292012-02-13 13:24:09 +0200429 ulpi_write(phy, ulpi_val, ULPI_USB_INT_EN_RISE);
430 ulpi_write(phy, ulpi_val, ULPI_USB_INT_EN_FALL);
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +0530431 }
432
Ivan T. Ivanov44e42ae2015-04-09 11:34:33 +0300433 if (motg->manual_pullup) {
434 val = ULPI_MISC_A_VBUSVLDEXTSEL | ULPI_MISC_A_VBUSVLDEXT;
435 ulpi_write(phy, val, ULPI_SET(ULPI_MISC_A));
436
437 val = readl(USB_GENCONFIG_2);
438 val |= GENCONFIG_2_SESS_VLD_CTRL_EN;
439 writel(val, USB_GENCONFIG_2);
440
441 val = readl(USB_USBCMD);
442 val |= USBCMD_SESS_VLD_CTRL;
443 writel(val, USB_USBCMD);
444
445 val = ulpi_read(phy, ULPI_FUNC_CTRL);
446 val &= ~ULPI_FUNC_CTRL_OPMODE_MASK;
447 val |= ULPI_FUNC_CTRL_OPMODE_NORMAL;
448 ulpi_write(phy, val, ULPI_FUNC_CTRL);
449 }
450
Ivan T. Ivanovcfa3ff52014-04-28 16:34:17 +0300451 if (motg->phy_number)
452 writel(readl(USB_PHY_CTRL2) | BIT(16), USB_PHY_CTRL2);
453
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +0530454 return 0;
455}
456
Pavankumar Kondeti87c01042010-12-07 17:53:58 +0530457#define PHY_SUSPEND_TIMEOUT_USEC (500 * 1000)
Pavankumar Kondeti70187732011-02-15 09:42:34 +0530458#define PHY_RESUME_TIMEOUT_USEC (100 * 1000)
459
Josh Cartwrighte7d613d2014-02-18 10:36:29 -0600460#ifdef CONFIG_PM
461
Ivan T. Ivanov37cfdaf2014-04-28 16:34:06 +0300462static int msm_hsusb_config_vddcx(struct msm_otg *motg, int high)
Josh Cartwrighte7d613d2014-02-18 10:36:29 -0600463{
Ivan T. Ivanov01799b62014-04-28 16:34:22 +0300464 int max_vol = motg->vdd_levels[VDD_LEVEL_MAX];
Josh Cartwrighte7d613d2014-02-18 10:36:29 -0600465 int min_vol;
466 int ret;
467
468 if (high)
Ivan T. Ivanov01799b62014-04-28 16:34:22 +0300469 min_vol = motg->vdd_levels[VDD_LEVEL_MIN];
Josh Cartwrighte7d613d2014-02-18 10:36:29 -0600470 else
Ivan T. Ivanov01799b62014-04-28 16:34:22 +0300471 min_vol = motg->vdd_levels[VDD_LEVEL_NONE];
Josh Cartwrighte7d613d2014-02-18 10:36:29 -0600472
Ivan T. Ivanov37cfdaf2014-04-28 16:34:06 +0300473 ret = regulator_set_voltage(motg->vddcx, min_vol, max_vol);
Josh Cartwrighte7d613d2014-02-18 10:36:29 -0600474 if (ret) {
Ivan T. Ivanov3aca0fa2014-04-28 16:34:10 +0300475 pr_err("Cannot set vddcx voltage\n");
Josh Cartwrighte7d613d2014-02-18 10:36:29 -0600476 return ret;
477 }
478
479 pr_debug("%s: min_vol:%d max_vol:%d\n", __func__, min_vol, max_vol);
480
481 return ret;
482}
483
Pavankumar Kondeti87c01042010-12-07 17:53:58 +0530484static int msm_otg_suspend(struct msm_otg *motg)
485{
Heikki Krogerus1d4c9292012-02-13 13:24:09 +0200486 struct usb_phy *phy = &motg->phy;
487 struct usb_bus *bus = phy->otg->host;
Pavankumar Kondeti87c01042010-12-07 17:53:58 +0530488 struct msm_otg_platform_data *pdata = motg->pdata;
Ivan T. Ivanovcfa3ff52014-04-28 16:34:17 +0300489 void __iomem *addr;
Pavankumar Kondeti87c01042010-12-07 17:53:58 +0530490 int cnt = 0;
491
492 if (atomic_read(&motg->in_lpm))
493 return 0;
494
495 disable_irq(motg->irq);
496 /*
Pavankumar Kondeti04aebcb2011-05-04 10:19:49 +0530497 * Chipidea 45-nm PHY suspend sequence:
498 *
Pavankumar Kondeti87c01042010-12-07 17:53:58 +0530499 * Interrupt Latch Register auto-clear feature is not present
500 * in all PHY versions. Latch register is clear on read type.
501 * Clear latch register to avoid spurious wakeup from
502 * low power mode (LPM).
Pavankumar Kondeti04aebcb2011-05-04 10:19:49 +0530503 *
Pavankumar Kondeti87c01042010-12-07 17:53:58 +0530504 * PHY comparators are disabled when PHY enters into low power
505 * mode (LPM). Keep PHY comparators ON in LPM only when we expect
506 * VBUS/Id notifications from USB PHY. Otherwise turn off USB
507 * PHY comparators. This save significant amount of power.
Pavankumar Kondeti04aebcb2011-05-04 10:19:49 +0530508 *
Pavankumar Kondeti87c01042010-12-07 17:53:58 +0530509 * PLL is not turned off when PHY enters into low power mode (LPM).
510 * Disable PLL for maximum power savings.
511 */
Pavankumar Kondeti04aebcb2011-05-04 10:19:49 +0530512
513 if (motg->pdata->phy_type == CI_45NM_INTEGRATED_PHY) {
Heikki Krogerus1d4c9292012-02-13 13:24:09 +0200514 ulpi_read(phy, 0x14);
Pavankumar Kondeti04aebcb2011-05-04 10:19:49 +0530515 if (pdata->otg_control == OTG_PHY_CONTROL)
Heikki Krogerus1d4c9292012-02-13 13:24:09 +0200516 ulpi_write(phy, 0x01, 0x30);
517 ulpi_write(phy, 0x08, 0x09);
Pavankumar Kondeti04aebcb2011-05-04 10:19:49 +0530518 }
Pavankumar Kondeti87c01042010-12-07 17:53:58 +0530519
520 /*
521 * PHY may take some time or even fail to enter into low power
522 * mode (LPM). Hence poll for 500 msec and reset the PHY and link
523 * in failure case.
524 */
525 writel(readl(USB_PORTSC) | PORTSC_PHCD, USB_PORTSC);
526 while (cnt < PHY_SUSPEND_TIMEOUT_USEC) {
527 if (readl(USB_PORTSC) & PORTSC_PHCD)
528 break;
529 udelay(1);
530 cnt++;
531 }
532
533 if (cnt >= PHY_SUSPEND_TIMEOUT_USEC) {
Heikki Krogerus1d4c9292012-02-13 13:24:09 +0200534 dev_err(phy->dev, "Unable to suspend PHY\n");
535 msm_otg_reset(phy);
Pavankumar Kondeti87c01042010-12-07 17:53:58 +0530536 enable_irq(motg->irq);
537 return -ETIMEDOUT;
538 }
539
540 /*
541 * PHY has capability to generate interrupt asynchronously in low
542 * power mode (LPM). This interrupt is level triggered. So USB IRQ
543 * line must be disabled till async interrupt enable bit is cleared
544 * in USBCMD register. Assert STP (ULPI interface STOP signal) to
545 * block data communication from PHY.
546 */
547 writel(readl(USB_USBCMD) | ASYNC_INTR_CTRL | ULPI_STP_CTRL, USB_USBCMD);
548
Ivan T. Ivanovcfa3ff52014-04-28 16:34:17 +0300549 addr = USB_PHY_CTRL;
550 if (motg->phy_number)
551 addr = USB_PHY_CTRL2;
552
Pavankumar Kondeti04aebcb2011-05-04 10:19:49 +0530553 if (motg->pdata->phy_type == SNPS_28NM_INTEGRATED_PHY &&
554 motg->pdata->otg_control == OTG_PMIC_CONTROL)
Ivan T. Ivanovcfa3ff52014-04-28 16:34:17 +0300555 writel(readl(addr) | PHY_RETEN, addr);
Pavankumar Kondeti04aebcb2011-05-04 10:19:49 +0530556
Stephen Boydb99a8f62013-06-17 10:43:10 -0700557 clk_disable_unprepare(motg->pclk);
558 clk_disable_unprepare(motg->clk);
Ivan T. Ivanov6b99c68e2014-04-28 16:34:08 +0300559 if (!IS_ERR(motg->core_clk))
Stephen Boydb99a8f62013-06-17 10:43:10 -0700560 clk_disable_unprepare(motg->core_clk);
Pavankumar Kondeti87c01042010-12-07 17:53:58 +0530561
Pavankumar Kondeti04aebcb2011-05-04 10:19:49 +0530562 if (motg->pdata->phy_type == SNPS_28NM_INTEGRATED_PHY &&
563 motg->pdata->otg_control == OTG_PMIC_CONTROL) {
Ivan T. Ivanov37cfdaf2014-04-28 16:34:06 +0300564 msm_hsusb_ldo_set_mode(motg, 0);
565 msm_hsusb_config_vddcx(motg, 0);
Pavankumar Kondeti04aebcb2011-05-04 10:19:49 +0530566 }
567
Heikki Krogerus1d4c9292012-02-13 13:24:09 +0200568 if (device_may_wakeup(phy->dev))
Pavankumar Kondeti87c01042010-12-07 17:53:58 +0530569 enable_irq_wake(motg->irq);
570 if (bus)
571 clear_bit(HCD_FLAG_HW_ACCESSIBLE, &(bus_to_hcd(bus))->flags);
572
573 atomic_set(&motg->in_lpm, 1);
574 enable_irq(motg->irq);
575
Heikki Krogerus1d4c9292012-02-13 13:24:09 +0200576 dev_info(phy->dev, "USB in low power mode\n");
Pavankumar Kondeti87c01042010-12-07 17:53:58 +0530577
578 return 0;
579}
580
Pavankumar Kondeti87c01042010-12-07 17:53:58 +0530581static int msm_otg_resume(struct msm_otg *motg)
582{
Heikki Krogerus1d4c9292012-02-13 13:24:09 +0200583 struct usb_phy *phy = &motg->phy;
584 struct usb_bus *bus = phy->otg->host;
Ivan T. Ivanovcfa3ff52014-04-28 16:34:17 +0300585 void __iomem *addr;
Pavankumar Kondeti87c01042010-12-07 17:53:58 +0530586 int cnt = 0;
587 unsigned temp;
588
589 if (!atomic_read(&motg->in_lpm))
590 return 0;
591
Stephen Boydb99a8f62013-06-17 10:43:10 -0700592 clk_prepare_enable(motg->pclk);
593 clk_prepare_enable(motg->clk);
Ivan T. Ivanov6b99c68e2014-04-28 16:34:08 +0300594 if (!IS_ERR(motg->core_clk))
Stephen Boydb99a8f62013-06-17 10:43:10 -0700595 clk_prepare_enable(motg->core_clk);
Pavankumar Kondeti87c01042010-12-07 17:53:58 +0530596
Pavankumar Kondeti04aebcb2011-05-04 10:19:49 +0530597 if (motg->pdata->phy_type == SNPS_28NM_INTEGRATED_PHY &&
598 motg->pdata->otg_control == OTG_PMIC_CONTROL) {
Ivan T. Ivanovcfa3ff52014-04-28 16:34:17 +0300599
600 addr = USB_PHY_CTRL;
601 if (motg->phy_number)
602 addr = USB_PHY_CTRL2;
603
Ivan T. Ivanov37cfdaf2014-04-28 16:34:06 +0300604 msm_hsusb_ldo_set_mode(motg, 1);
605 msm_hsusb_config_vddcx(motg, 1);
Ivan T. Ivanovcfa3ff52014-04-28 16:34:17 +0300606 writel(readl(addr) & ~PHY_RETEN, addr);
Pavankumar Kondeti04aebcb2011-05-04 10:19:49 +0530607 }
608
Pavankumar Kondeti87c01042010-12-07 17:53:58 +0530609 temp = readl(USB_USBCMD);
610 temp &= ~ASYNC_INTR_CTRL;
611 temp &= ~ULPI_STP_CTRL;
612 writel(temp, USB_USBCMD);
613
614 /*
615 * PHY comes out of low power mode (LPM) in case of wakeup
616 * from asynchronous interrupt.
617 */
618 if (!(readl(USB_PORTSC) & PORTSC_PHCD))
619 goto skip_phy_resume;
620
621 writel(readl(USB_PORTSC) & ~PORTSC_PHCD, USB_PORTSC);
622 while (cnt < PHY_RESUME_TIMEOUT_USEC) {
623 if (!(readl(USB_PORTSC) & PORTSC_PHCD))
624 break;
625 udelay(1);
626 cnt++;
627 }
628
629 if (cnt >= PHY_RESUME_TIMEOUT_USEC) {
630 /*
631 * This is a fatal error. Reset the link and
632 * PHY. USB state can not be restored. Re-insertion
633 * of USB cable is the only way to get USB working.
634 */
Ivan T. Ivanov3aca0fa2014-04-28 16:34:10 +0300635 dev_err(phy->dev, "Unable to resume USB. Re-plugin the cable\n");
Heikki Krogerus1d4c9292012-02-13 13:24:09 +0200636 msm_otg_reset(phy);
Pavankumar Kondeti87c01042010-12-07 17:53:58 +0530637 }
638
639skip_phy_resume:
Heikki Krogerus1d4c9292012-02-13 13:24:09 +0200640 if (device_may_wakeup(phy->dev))
Pavankumar Kondeti87c01042010-12-07 17:53:58 +0530641 disable_irq_wake(motg->irq);
642 if (bus)
643 set_bit(HCD_FLAG_HW_ACCESSIBLE, &(bus_to_hcd(bus))->flags);
644
Pavankumar Kondeti2ce2c3a2011-05-02 11:56:33 +0530645 atomic_set(&motg->in_lpm, 0);
646
Pavankumar Kondeti87c01042010-12-07 17:53:58 +0530647 if (motg->async_int) {
648 motg->async_int = 0;
Heikki Krogerus1d4c9292012-02-13 13:24:09 +0200649 pm_runtime_put(phy->dev);
Pavankumar Kondeti87c01042010-12-07 17:53:58 +0530650 enable_irq(motg->irq);
651 }
652
Heikki Krogerus1d4c9292012-02-13 13:24:09 +0200653 dev_info(phy->dev, "USB exited from low power mode\n");
Pavankumar Kondeti87c01042010-12-07 17:53:58 +0530654
655 return 0;
656}
Pavankumar Kondeti70187732011-02-15 09:42:34 +0530657#endif
Pavankumar Kondeti87c01042010-12-07 17:53:58 +0530658
Pavankumar Kondetid8608522011-05-04 10:19:47 +0530659static void msm_otg_notify_charger(struct msm_otg *motg, unsigned mA)
660{
661 if (motg->cur_power == mA)
662 return;
663
664 /* TODO: Notify PMIC about available current */
Heikki Krogerus1d4c9292012-02-13 13:24:09 +0200665 dev_info(motg->phy.dev, "Avail curr from USB = %u\n", mA);
Pavankumar Kondetid8608522011-05-04 10:19:47 +0530666 motg->cur_power = mA;
667}
668
Heikki Krogerus1d4c9292012-02-13 13:24:09 +0200669static int msm_otg_set_power(struct usb_phy *phy, unsigned mA)
Pavankumar Kondetid8608522011-05-04 10:19:47 +0530670{
Heikki Krogerus1d4c9292012-02-13 13:24:09 +0200671 struct msm_otg *motg = container_of(phy, struct msm_otg, phy);
Pavankumar Kondetid8608522011-05-04 10:19:47 +0530672
673 /*
674 * Gadget driver uses set_power method to notify about the
675 * available current based on suspend/configured states.
676 *
677 * IDEV_CHG can be drawn irrespective of suspend/un-configured
678 * states when CDP/ACA is connected.
679 */
680 if (motg->chg_type == USB_SDP_CHARGER)
681 msm_otg_notify_charger(motg, mA);
682
683 return 0;
684}
685
Heikki Krogerus1d4c9292012-02-13 13:24:09 +0200686static void msm_otg_start_host(struct usb_phy *phy, int on)
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +0530687{
Heikki Krogerus1d4c9292012-02-13 13:24:09 +0200688 struct msm_otg *motg = container_of(phy, struct msm_otg, phy);
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +0530689 struct msm_otg_platform_data *pdata = motg->pdata;
690 struct usb_hcd *hcd;
691
Heikki Krogerus1d4c9292012-02-13 13:24:09 +0200692 if (!phy->otg->host)
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +0530693 return;
694
Heikki Krogerus1d4c9292012-02-13 13:24:09 +0200695 hcd = bus_to_hcd(phy->otg->host);
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +0530696
697 if (on) {
Heikki Krogerus1d4c9292012-02-13 13:24:09 +0200698 dev_dbg(phy->dev, "host on\n");
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +0530699
700 if (pdata->vbus_power)
701 pdata->vbus_power(1);
702 /*
703 * Some boards have a switch cotrolled by gpio
704 * to enable/disable internal HUB. Enable internal
705 * HUB before kicking the host.
706 */
707 if (pdata->setup_gpio)
708 pdata->setup_gpio(OTG_STATE_A_HOST);
709#ifdef CONFIG_USB
710 usb_add_hcd(hcd, hcd->irq, IRQF_SHARED);
Peter Chen3c9740a2013-11-05 10:46:02 +0800711 device_wakeup_enable(hcd->self.controller);
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +0530712#endif
713 } else {
Heikki Krogerus1d4c9292012-02-13 13:24:09 +0200714 dev_dbg(phy->dev, "host off\n");
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +0530715
716#ifdef CONFIG_USB
717 usb_remove_hcd(hcd);
718#endif
719 if (pdata->setup_gpio)
720 pdata->setup_gpio(OTG_STATE_UNDEFINED);
721 if (pdata->vbus_power)
722 pdata->vbus_power(0);
723 }
724}
725
Heikki Krogerus1d4c9292012-02-13 13:24:09 +0200726static int msm_otg_set_host(struct usb_otg *otg, struct usb_bus *host)
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +0530727{
Antoine Tenart19c1eac2014-10-30 18:41:14 +0100728 struct msm_otg *motg = container_of(otg->usb_phy, struct msm_otg, phy);
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +0530729 struct usb_hcd *hcd;
730
731 /*
732 * Fail host registration if this board can support
733 * only peripheral configuration.
734 */
Ivan T. Ivanov971232c2014-04-28 16:34:11 +0300735 if (motg->pdata->mode == USB_DR_MODE_PERIPHERAL) {
Antoine Tenart19c1eac2014-10-30 18:41:14 +0100736 dev_info(otg->usb_phy->dev, "Host mode is not supported\n");
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +0530737 return -ENODEV;
738 }
739
740 if (!host) {
Antoine Tenarte47d9252014-10-30 18:41:13 +0100741 if (otg->state == OTG_STATE_A_HOST) {
Antoine Tenart19c1eac2014-10-30 18:41:14 +0100742 pm_runtime_get_sync(otg->usb_phy->dev);
743 msm_otg_start_host(otg->usb_phy, 0);
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +0530744 otg->host = NULL;
Antoine Tenarte47d9252014-10-30 18:41:13 +0100745 otg->state = OTG_STATE_UNDEFINED;
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +0530746 schedule_work(&motg->sm_work);
747 } else {
748 otg->host = NULL;
749 }
750
751 return 0;
752 }
753
754 hcd = bus_to_hcd(host);
755 hcd->power_budget = motg->pdata->power_budget;
756
757 otg->host = host;
Antoine Tenart19c1eac2014-10-30 18:41:14 +0100758 dev_dbg(otg->usb_phy->dev, "host driver registered w/ tranceiver\n");
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +0530759
760 /*
761 * Kick the state machine work, if peripheral is not supported
762 * or peripheral is already registered with us.
763 */
Ivan T. Ivanov971232c2014-04-28 16:34:11 +0300764 if (motg->pdata->mode == USB_DR_MODE_HOST || otg->gadget) {
Antoine Tenart19c1eac2014-10-30 18:41:14 +0100765 pm_runtime_get_sync(otg->usb_phy->dev);
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +0530766 schedule_work(&motg->sm_work);
Pavankumar Kondeti87c01042010-12-07 17:53:58 +0530767 }
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +0530768
769 return 0;
770}
771
Heikki Krogerus1d4c9292012-02-13 13:24:09 +0200772static void msm_otg_start_peripheral(struct usb_phy *phy, int on)
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +0530773{
Heikki Krogerus1d4c9292012-02-13 13:24:09 +0200774 struct msm_otg *motg = container_of(phy, struct msm_otg, phy);
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +0530775 struct msm_otg_platform_data *pdata = motg->pdata;
776
Heikki Krogerus1d4c9292012-02-13 13:24:09 +0200777 if (!phy->otg->gadget)
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +0530778 return;
779
780 if (on) {
Heikki Krogerus1d4c9292012-02-13 13:24:09 +0200781 dev_dbg(phy->dev, "gadget on\n");
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +0530782 /*
783 * Some boards have a switch cotrolled by gpio
784 * to enable/disable internal HUB. Disable internal
785 * HUB before kicking the gadget.
786 */
787 if (pdata->setup_gpio)
788 pdata->setup_gpio(OTG_STATE_B_PERIPHERAL);
Heikki Krogerus1d4c9292012-02-13 13:24:09 +0200789 usb_gadget_vbus_connect(phy->otg->gadget);
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +0530790 } else {
Heikki Krogerus1d4c9292012-02-13 13:24:09 +0200791 dev_dbg(phy->dev, "gadget off\n");
792 usb_gadget_vbus_disconnect(phy->otg->gadget);
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +0530793 if (pdata->setup_gpio)
794 pdata->setup_gpio(OTG_STATE_UNDEFINED);
795 }
796
797}
798
Heikki Krogerus1d4c9292012-02-13 13:24:09 +0200799static int msm_otg_set_peripheral(struct usb_otg *otg,
800 struct usb_gadget *gadget)
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +0530801{
Antoine Tenart19c1eac2014-10-30 18:41:14 +0100802 struct msm_otg *motg = container_of(otg->usb_phy, struct msm_otg, phy);
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +0530803
804 /*
805 * Fail peripheral registration if this board can support
806 * only host configuration.
807 */
Ivan T. Ivanov971232c2014-04-28 16:34:11 +0300808 if (motg->pdata->mode == USB_DR_MODE_HOST) {
Antoine Tenart19c1eac2014-10-30 18:41:14 +0100809 dev_info(otg->usb_phy->dev, "Peripheral mode is not supported\n");
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +0530810 return -ENODEV;
811 }
812
813 if (!gadget) {
Antoine Tenarte47d9252014-10-30 18:41:13 +0100814 if (otg->state == OTG_STATE_B_PERIPHERAL) {
Antoine Tenart19c1eac2014-10-30 18:41:14 +0100815 pm_runtime_get_sync(otg->usb_phy->dev);
816 msm_otg_start_peripheral(otg->usb_phy, 0);
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +0530817 otg->gadget = NULL;
Antoine Tenarte47d9252014-10-30 18:41:13 +0100818 otg->state = OTG_STATE_UNDEFINED;
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +0530819 schedule_work(&motg->sm_work);
820 } else {
821 otg->gadget = NULL;
822 }
823
824 return 0;
825 }
826 otg->gadget = gadget;
Antoine Tenart19c1eac2014-10-30 18:41:14 +0100827 dev_dbg(otg->usb_phy->dev,
828 "peripheral driver registered w/ tranceiver\n");
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +0530829
830 /*
831 * Kick the state machine work, if host is not supported
832 * or host is already registered with us.
833 */
Ivan T. Ivanov971232c2014-04-28 16:34:11 +0300834 if (motg->pdata->mode == USB_DR_MODE_PERIPHERAL || otg->host) {
Antoine Tenart19c1eac2014-10-30 18:41:14 +0100835 pm_runtime_get_sync(otg->usb_phy->dev);
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +0530836 schedule_work(&motg->sm_work);
Pavankumar Kondeti87c01042010-12-07 17:53:58 +0530837 }
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +0530838
839 return 0;
840}
841
Pavankumar Kondetid8608522011-05-04 10:19:47 +0530842static bool msm_chg_check_secondary_det(struct msm_otg *motg)
843{
Heikki Krogerus1d4c9292012-02-13 13:24:09 +0200844 struct usb_phy *phy = &motg->phy;
Pavankumar Kondetid8608522011-05-04 10:19:47 +0530845 u32 chg_det;
846 bool ret = false;
847
848 switch (motg->pdata->phy_type) {
849 case CI_45NM_INTEGRATED_PHY:
Heikki Krogerus1d4c9292012-02-13 13:24:09 +0200850 chg_det = ulpi_read(phy, 0x34);
Pavankumar Kondetid8608522011-05-04 10:19:47 +0530851 ret = chg_det & (1 << 4);
852 break;
853 case SNPS_28NM_INTEGRATED_PHY:
Heikki Krogerus1d4c9292012-02-13 13:24:09 +0200854 chg_det = ulpi_read(phy, 0x87);
Pavankumar Kondetid8608522011-05-04 10:19:47 +0530855 ret = chg_det & 1;
856 break;
857 default:
858 break;
859 }
860 return ret;
861}
862
863static void msm_chg_enable_secondary_det(struct msm_otg *motg)
864{
Heikki Krogerus1d4c9292012-02-13 13:24:09 +0200865 struct usb_phy *phy = &motg->phy;
Pavankumar Kondetid8608522011-05-04 10:19:47 +0530866 u32 chg_det;
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 /* Turn off charger block */
872 chg_det |= ~(1 << 1);
Heikki Krogerus1d4c9292012-02-13 13:24:09 +0200873 ulpi_write(phy, chg_det, 0x34);
Pavankumar Kondetid8608522011-05-04 10:19:47 +0530874 udelay(20);
875 /* control chg block via ULPI */
876 chg_det &= ~(1 << 3);
Heikki Krogerus1d4c9292012-02-13 13:24:09 +0200877 ulpi_write(phy, chg_det, 0x34);
Pavankumar Kondetid8608522011-05-04 10:19:47 +0530878 /* put it in host mode for enabling D- source */
879 chg_det &= ~(1 << 2);
Heikki Krogerus1d4c9292012-02-13 13:24:09 +0200880 ulpi_write(phy, chg_det, 0x34);
Pavankumar Kondetid8608522011-05-04 10:19:47 +0530881 /* Turn on chg detect block */
882 chg_det &= ~(1 << 1);
Heikki Krogerus1d4c9292012-02-13 13:24:09 +0200883 ulpi_write(phy, chg_det, 0x34);
Pavankumar Kondetid8608522011-05-04 10:19:47 +0530884 udelay(20);
885 /* enable chg detection */
886 chg_det &= ~(1 << 0);
Heikki Krogerus1d4c9292012-02-13 13:24:09 +0200887 ulpi_write(phy, chg_det, 0x34);
Pavankumar Kondetid8608522011-05-04 10:19:47 +0530888 break;
889 case SNPS_28NM_INTEGRATED_PHY:
890 /*
891 * Configure DM as current source, DP as current sink
892 * and enable battery charging comparators.
893 */
Heikki Krogerus1d4c9292012-02-13 13:24:09 +0200894 ulpi_write(phy, 0x8, 0x85);
895 ulpi_write(phy, 0x2, 0x85);
896 ulpi_write(phy, 0x1, 0x85);
Pavankumar Kondetid8608522011-05-04 10:19:47 +0530897 break;
898 default:
899 break;
900 }
901}
902
903static bool msm_chg_check_primary_det(struct msm_otg *motg)
904{
Heikki Krogerus1d4c9292012-02-13 13:24:09 +0200905 struct usb_phy *phy = &motg->phy;
Pavankumar Kondetid8608522011-05-04 10:19:47 +0530906 u32 chg_det;
907 bool ret = false;
908
909 switch (motg->pdata->phy_type) {
910 case CI_45NM_INTEGRATED_PHY:
Heikki Krogerus1d4c9292012-02-13 13:24:09 +0200911 chg_det = ulpi_read(phy, 0x34);
Pavankumar Kondetid8608522011-05-04 10:19:47 +0530912 ret = chg_det & (1 << 4);
913 break;
914 case SNPS_28NM_INTEGRATED_PHY:
Heikki Krogerus1d4c9292012-02-13 13:24:09 +0200915 chg_det = ulpi_read(phy, 0x87);
Pavankumar Kondetid8608522011-05-04 10:19:47 +0530916 ret = chg_det & 1;
917 break;
918 default:
919 break;
920 }
921 return ret;
922}
923
924static void msm_chg_enable_primary_det(struct msm_otg *motg)
925{
Heikki Krogerus1d4c9292012-02-13 13:24:09 +0200926 struct usb_phy *phy = &motg->phy;
Pavankumar Kondetid8608522011-05-04 10:19:47 +0530927 u32 chg_det;
928
929 switch (motg->pdata->phy_type) {
930 case CI_45NM_INTEGRATED_PHY:
Heikki Krogerus1d4c9292012-02-13 13:24:09 +0200931 chg_det = ulpi_read(phy, 0x34);
Pavankumar Kondetid8608522011-05-04 10:19:47 +0530932 /* enable chg detection */
933 chg_det &= ~(1 << 0);
Heikki Krogerus1d4c9292012-02-13 13:24:09 +0200934 ulpi_write(phy, chg_det, 0x34);
Pavankumar Kondetid8608522011-05-04 10:19:47 +0530935 break;
936 case SNPS_28NM_INTEGRATED_PHY:
937 /*
938 * Configure DP as current source, DM as current sink
939 * and enable battery charging comparators.
940 */
Heikki Krogerus1d4c9292012-02-13 13:24:09 +0200941 ulpi_write(phy, 0x2, 0x85);
942 ulpi_write(phy, 0x1, 0x85);
Pavankumar Kondetid8608522011-05-04 10:19:47 +0530943 break;
944 default:
945 break;
946 }
947}
948
949static bool msm_chg_check_dcd(struct msm_otg *motg)
950{
Heikki Krogerus1d4c9292012-02-13 13:24:09 +0200951 struct usb_phy *phy = &motg->phy;
Pavankumar Kondetid8608522011-05-04 10:19:47 +0530952 u32 line_state;
953 bool ret = false;
954
955 switch (motg->pdata->phy_type) {
956 case CI_45NM_INTEGRATED_PHY:
Heikki Krogerus1d4c9292012-02-13 13:24:09 +0200957 line_state = ulpi_read(phy, 0x15);
Pavankumar Kondetid8608522011-05-04 10:19:47 +0530958 ret = !(line_state & 1);
959 break;
960 case SNPS_28NM_INTEGRATED_PHY:
Heikki Krogerus1d4c9292012-02-13 13:24:09 +0200961 line_state = ulpi_read(phy, 0x87);
Pavankumar Kondetid8608522011-05-04 10:19:47 +0530962 ret = line_state & 2;
963 break;
964 default:
965 break;
966 }
967 return ret;
968}
969
970static void msm_chg_disable_dcd(struct msm_otg *motg)
971{
Heikki Krogerus1d4c9292012-02-13 13:24:09 +0200972 struct usb_phy *phy = &motg->phy;
Pavankumar Kondetid8608522011-05-04 10:19:47 +0530973 u32 chg_det;
974
975 switch (motg->pdata->phy_type) {
976 case CI_45NM_INTEGRATED_PHY:
Heikki Krogerus1d4c9292012-02-13 13:24:09 +0200977 chg_det = ulpi_read(phy, 0x34);
Pavankumar Kondetid8608522011-05-04 10:19:47 +0530978 chg_det &= ~(1 << 5);
Heikki Krogerus1d4c9292012-02-13 13:24:09 +0200979 ulpi_write(phy, chg_det, 0x34);
Pavankumar Kondetid8608522011-05-04 10:19:47 +0530980 break;
981 case SNPS_28NM_INTEGRATED_PHY:
Heikki Krogerus1d4c9292012-02-13 13:24:09 +0200982 ulpi_write(phy, 0x10, 0x86);
Pavankumar Kondetid8608522011-05-04 10:19:47 +0530983 break;
984 default:
985 break;
986 }
987}
988
989static void msm_chg_enable_dcd(struct msm_otg *motg)
990{
Heikki Krogerus1d4c9292012-02-13 13:24:09 +0200991 struct usb_phy *phy = &motg->phy;
Pavankumar Kondetid8608522011-05-04 10:19:47 +0530992 u32 chg_det;
993
994 switch (motg->pdata->phy_type) {
995 case CI_45NM_INTEGRATED_PHY:
Heikki Krogerus1d4c9292012-02-13 13:24:09 +0200996 chg_det = ulpi_read(phy, 0x34);
Pavankumar Kondetid8608522011-05-04 10:19:47 +0530997 /* Turn on D+ current source */
998 chg_det |= (1 << 5);
Heikki Krogerus1d4c9292012-02-13 13:24:09 +0200999 ulpi_write(phy, chg_det, 0x34);
Pavankumar Kondetid8608522011-05-04 10:19:47 +05301000 break;
1001 case SNPS_28NM_INTEGRATED_PHY:
1002 /* Data contact detection enable */
Heikki Krogerus1d4c9292012-02-13 13:24:09 +02001003 ulpi_write(phy, 0x10, 0x85);
Pavankumar Kondetid8608522011-05-04 10:19:47 +05301004 break;
1005 default:
1006 break;
1007 }
1008}
1009
1010static void msm_chg_block_on(struct msm_otg *motg)
1011{
Heikki Krogerus1d4c9292012-02-13 13:24:09 +02001012 struct usb_phy *phy = &motg->phy;
Pavankumar Kondetid8608522011-05-04 10:19:47 +05301013 u32 func_ctrl, chg_det;
1014
1015 /* put the controller in non-driving mode */
Heikki Krogerus1d4c9292012-02-13 13:24:09 +02001016 func_ctrl = ulpi_read(phy, ULPI_FUNC_CTRL);
Pavankumar Kondetid8608522011-05-04 10:19:47 +05301017 func_ctrl &= ~ULPI_FUNC_CTRL_OPMODE_MASK;
1018 func_ctrl |= ULPI_FUNC_CTRL_OPMODE_NONDRIVING;
Heikki Krogerus1d4c9292012-02-13 13:24:09 +02001019 ulpi_write(phy, func_ctrl, ULPI_FUNC_CTRL);
Pavankumar Kondetid8608522011-05-04 10:19:47 +05301020
1021 switch (motg->pdata->phy_type) {
1022 case CI_45NM_INTEGRATED_PHY:
Heikki Krogerus1d4c9292012-02-13 13:24:09 +02001023 chg_det = ulpi_read(phy, 0x34);
Pavankumar Kondetid8608522011-05-04 10:19:47 +05301024 /* control chg block via ULPI */
1025 chg_det &= ~(1 << 3);
Heikki Krogerus1d4c9292012-02-13 13:24:09 +02001026 ulpi_write(phy, chg_det, 0x34);
Pavankumar Kondetid8608522011-05-04 10:19:47 +05301027 /* Turn on chg detect block */
1028 chg_det &= ~(1 << 1);
Heikki Krogerus1d4c9292012-02-13 13:24:09 +02001029 ulpi_write(phy, chg_det, 0x34);
Pavankumar Kondetid8608522011-05-04 10:19:47 +05301030 udelay(20);
1031 break;
1032 case SNPS_28NM_INTEGRATED_PHY:
1033 /* Clear charger detecting control bits */
Heikki Krogerus1d4c9292012-02-13 13:24:09 +02001034 ulpi_write(phy, 0x3F, 0x86);
Pavankumar Kondetid8608522011-05-04 10:19:47 +05301035 /* Clear alt interrupt latch and enable bits */
Heikki Krogerus1d4c9292012-02-13 13:24:09 +02001036 ulpi_write(phy, 0x1F, 0x92);
1037 ulpi_write(phy, 0x1F, 0x95);
Pavankumar Kondetid8608522011-05-04 10:19:47 +05301038 udelay(100);
1039 break;
1040 default:
1041 break;
1042 }
1043}
1044
1045static void msm_chg_block_off(struct msm_otg *motg)
1046{
Heikki Krogerus1d4c9292012-02-13 13:24:09 +02001047 struct usb_phy *phy = &motg->phy;
Pavankumar Kondetid8608522011-05-04 10:19:47 +05301048 u32 func_ctrl, chg_det;
1049
1050 switch (motg->pdata->phy_type) {
1051 case CI_45NM_INTEGRATED_PHY:
Heikki Krogerus1d4c9292012-02-13 13:24:09 +02001052 chg_det = ulpi_read(phy, 0x34);
Pavankumar Kondetid8608522011-05-04 10:19:47 +05301053 /* Turn off charger block */
1054 chg_det |= ~(1 << 1);
Heikki Krogerus1d4c9292012-02-13 13:24:09 +02001055 ulpi_write(phy, chg_det, 0x34);
Pavankumar Kondetid8608522011-05-04 10:19:47 +05301056 break;
1057 case SNPS_28NM_INTEGRATED_PHY:
1058 /* Clear charger detecting control bits */
Heikki Krogerus1d4c9292012-02-13 13:24:09 +02001059 ulpi_write(phy, 0x3F, 0x86);
Pavankumar Kondetid8608522011-05-04 10:19:47 +05301060 /* Clear alt interrupt latch and enable bits */
Heikki Krogerus1d4c9292012-02-13 13:24:09 +02001061 ulpi_write(phy, 0x1F, 0x92);
1062 ulpi_write(phy, 0x1F, 0x95);
Pavankumar Kondetid8608522011-05-04 10:19:47 +05301063 break;
1064 default:
1065 break;
1066 }
1067
1068 /* put the controller in normal mode */
Heikki Krogerus1d4c9292012-02-13 13:24:09 +02001069 func_ctrl = ulpi_read(phy, ULPI_FUNC_CTRL);
Pavankumar Kondetid8608522011-05-04 10:19:47 +05301070 func_ctrl &= ~ULPI_FUNC_CTRL_OPMODE_MASK;
1071 func_ctrl |= ULPI_FUNC_CTRL_OPMODE_NORMAL;
Heikki Krogerus1d4c9292012-02-13 13:24:09 +02001072 ulpi_write(phy, func_ctrl, ULPI_FUNC_CTRL);
Pavankumar Kondetid8608522011-05-04 10:19:47 +05301073}
1074
1075#define MSM_CHG_DCD_POLL_TIME (100 * HZ/1000) /* 100 msec */
1076#define MSM_CHG_DCD_MAX_RETRIES 6 /* Tdcd_tmout = 6 * 100 msec */
1077#define MSM_CHG_PRIMARY_DET_TIME (40 * HZ/1000) /* TVDPSRC_ON */
1078#define MSM_CHG_SECONDARY_DET_TIME (40 * HZ/1000) /* TVDMSRC_ON */
1079static void msm_chg_detect_work(struct work_struct *w)
1080{
1081 struct msm_otg *motg = container_of(w, struct msm_otg, chg_work.work);
Heikki Krogerus1d4c9292012-02-13 13:24:09 +02001082 struct usb_phy *phy = &motg->phy;
Pavankumar Kondetid8608522011-05-04 10:19:47 +05301083 bool is_dcd, tmout, vout;
1084 unsigned long delay;
1085
Heikki Krogerus1d4c9292012-02-13 13:24:09 +02001086 dev_dbg(phy->dev, "chg detection work\n");
Pavankumar Kondetid8608522011-05-04 10:19:47 +05301087 switch (motg->chg_state) {
1088 case USB_CHG_STATE_UNDEFINED:
Heikki Krogerus1d4c9292012-02-13 13:24:09 +02001089 pm_runtime_get_sync(phy->dev);
Pavankumar Kondetid8608522011-05-04 10:19:47 +05301090 msm_chg_block_on(motg);
1091 msm_chg_enable_dcd(motg);
1092 motg->chg_state = USB_CHG_STATE_WAIT_FOR_DCD;
1093 motg->dcd_retries = 0;
1094 delay = MSM_CHG_DCD_POLL_TIME;
1095 break;
1096 case USB_CHG_STATE_WAIT_FOR_DCD:
1097 is_dcd = msm_chg_check_dcd(motg);
1098 tmout = ++motg->dcd_retries == MSM_CHG_DCD_MAX_RETRIES;
1099 if (is_dcd || tmout) {
1100 msm_chg_disable_dcd(motg);
1101 msm_chg_enable_primary_det(motg);
1102 delay = MSM_CHG_PRIMARY_DET_TIME;
1103 motg->chg_state = USB_CHG_STATE_DCD_DONE;
1104 } else {
1105 delay = MSM_CHG_DCD_POLL_TIME;
1106 }
1107 break;
1108 case USB_CHG_STATE_DCD_DONE:
1109 vout = msm_chg_check_primary_det(motg);
1110 if (vout) {
1111 msm_chg_enable_secondary_det(motg);
1112 delay = MSM_CHG_SECONDARY_DET_TIME;
1113 motg->chg_state = USB_CHG_STATE_PRIMARY_DONE;
1114 } else {
1115 motg->chg_type = USB_SDP_CHARGER;
1116 motg->chg_state = USB_CHG_STATE_DETECTED;
1117 delay = 0;
1118 }
1119 break;
1120 case USB_CHG_STATE_PRIMARY_DONE:
1121 vout = msm_chg_check_secondary_det(motg);
1122 if (vout)
1123 motg->chg_type = USB_DCP_CHARGER;
1124 else
1125 motg->chg_type = USB_CDP_CHARGER;
1126 motg->chg_state = USB_CHG_STATE_SECONDARY_DONE;
1127 /* fall through */
1128 case USB_CHG_STATE_SECONDARY_DONE:
1129 motg->chg_state = USB_CHG_STATE_DETECTED;
1130 case USB_CHG_STATE_DETECTED:
1131 msm_chg_block_off(motg);
Heikki Krogerus1d4c9292012-02-13 13:24:09 +02001132 dev_dbg(phy->dev, "charger = %d\n", motg->chg_type);
Pavankumar Kondetid8608522011-05-04 10:19:47 +05301133 schedule_work(&motg->sm_work);
1134 return;
1135 default:
1136 return;
1137 }
1138
1139 schedule_delayed_work(&motg->chg_work, delay);
1140}
1141
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05301142/*
1143 * We support OTG, Peripheral only and Host only configurations. In case
1144 * of OTG, mode switch (host-->peripheral/peripheral-->host) can happen
1145 * via Id pin status or user request (debugfs). Id/BSV interrupts are not
1146 * enabled when switch is controlled by user and default mode is supplied
1147 * by board file, which can be changed by userspace later.
1148 */
1149static void msm_otg_init_sm(struct msm_otg *motg)
1150{
1151 struct msm_otg_platform_data *pdata = motg->pdata;
1152 u32 otgsc = readl(USB_OTGSC);
1153
1154 switch (pdata->mode) {
Ivan T. Ivanov971232c2014-04-28 16:34:11 +03001155 case USB_DR_MODE_OTG:
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05301156 if (pdata->otg_control == OTG_PHY_CONTROL) {
1157 if (otgsc & OTGSC_ID)
1158 set_bit(ID, &motg->inputs);
1159 else
1160 clear_bit(ID, &motg->inputs);
1161
1162 if (otgsc & OTGSC_BSV)
1163 set_bit(B_SESS_VLD, &motg->inputs);
1164 else
1165 clear_bit(B_SESS_VLD, &motg->inputs);
1166 } else if (pdata->otg_control == OTG_USER_CONTROL) {
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05301167 set_bit(ID, &motg->inputs);
1168 clear_bit(B_SESS_VLD, &motg->inputs);
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05301169 }
1170 break;
Ivan T. Ivanov971232c2014-04-28 16:34:11 +03001171 case USB_DR_MODE_HOST:
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05301172 clear_bit(ID, &motg->inputs);
1173 break;
Ivan T. Ivanov971232c2014-04-28 16:34:11 +03001174 case USB_DR_MODE_PERIPHERAL:
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05301175 set_bit(ID, &motg->inputs);
1176 if (otgsc & OTGSC_BSV)
1177 set_bit(B_SESS_VLD, &motg->inputs);
1178 else
1179 clear_bit(B_SESS_VLD, &motg->inputs);
1180 break;
1181 default:
1182 break;
1183 }
1184}
1185
1186static void msm_otg_sm_work(struct work_struct *w)
1187{
1188 struct msm_otg *motg = container_of(w, struct msm_otg, sm_work);
Heikki Krogerus1d4c9292012-02-13 13:24:09 +02001189 struct usb_otg *otg = motg->phy.otg;
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05301190
Antoine Tenarte47d9252014-10-30 18:41:13 +01001191 switch (otg->state) {
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05301192 case OTG_STATE_UNDEFINED:
Antoine Tenart19c1eac2014-10-30 18:41:14 +01001193 dev_dbg(otg->usb_phy->dev, "OTG_STATE_UNDEFINED state\n");
1194 msm_otg_reset(otg->usb_phy);
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05301195 msm_otg_init_sm(motg);
Antoine Tenarte47d9252014-10-30 18:41:13 +01001196 otg->state = OTG_STATE_B_IDLE;
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05301197 /* FALL THROUGH */
1198 case OTG_STATE_B_IDLE:
Antoine Tenart19c1eac2014-10-30 18:41:14 +01001199 dev_dbg(otg->usb_phy->dev, "OTG_STATE_B_IDLE state\n");
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05301200 if (!test_bit(ID, &motg->inputs) && otg->host) {
1201 /* disable BSV bit */
1202 writel(readl(USB_OTGSC) & ~OTGSC_BSVIE, USB_OTGSC);
Antoine Tenart19c1eac2014-10-30 18:41:14 +01001203 msm_otg_start_host(otg->usb_phy, 1);
Antoine Tenarte47d9252014-10-30 18:41:13 +01001204 otg->state = OTG_STATE_A_HOST;
Pavankumar Kondetid8608522011-05-04 10:19:47 +05301205 } else if (test_bit(B_SESS_VLD, &motg->inputs)) {
1206 switch (motg->chg_state) {
1207 case USB_CHG_STATE_UNDEFINED:
1208 msm_chg_detect_work(&motg->chg_work.work);
1209 break;
1210 case USB_CHG_STATE_DETECTED:
1211 switch (motg->chg_type) {
1212 case USB_DCP_CHARGER:
1213 msm_otg_notify_charger(motg,
1214 IDEV_CHG_MAX);
1215 break;
1216 case USB_CDP_CHARGER:
1217 msm_otg_notify_charger(motg,
1218 IDEV_CHG_MAX);
Antoine Tenart19c1eac2014-10-30 18:41:14 +01001219 msm_otg_start_peripheral(otg->usb_phy,
1220 1);
Antoine Tenarte47d9252014-10-30 18:41:13 +01001221 otg->state
Heikki Krogerus1d4c9292012-02-13 13:24:09 +02001222 = OTG_STATE_B_PERIPHERAL;
Pavankumar Kondetid8608522011-05-04 10:19:47 +05301223 break;
1224 case USB_SDP_CHARGER:
1225 msm_otg_notify_charger(motg, IUNIT);
Antoine Tenart19c1eac2014-10-30 18:41:14 +01001226 msm_otg_start_peripheral(otg->usb_phy,
1227 1);
Antoine Tenarte47d9252014-10-30 18:41:13 +01001228 otg->state
Heikki Krogerus1d4c9292012-02-13 13:24:09 +02001229 = OTG_STATE_B_PERIPHERAL;
Pavankumar Kondetid8608522011-05-04 10:19:47 +05301230 break;
1231 default:
1232 break;
1233 }
1234 break;
1235 default:
1236 break;
1237 }
1238 } else {
1239 /*
1240 * If charger detection work is pending, decrement
1241 * the pm usage counter to balance with the one that
1242 * is incremented in charger detection work.
1243 */
1244 if (cancel_delayed_work_sync(&motg->chg_work)) {
Antoine Tenart19c1eac2014-10-30 18:41:14 +01001245 pm_runtime_put_sync(otg->usb_phy->dev);
1246 msm_otg_reset(otg->usb_phy);
Pavankumar Kondetid8608522011-05-04 10:19:47 +05301247 }
1248 msm_otg_notify_charger(motg, 0);
1249 motg->chg_state = USB_CHG_STATE_UNDEFINED;
1250 motg->chg_type = USB_INVALID_CHARGER;
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05301251 }
Srinivas Kandagatla508ccea2014-06-30 18:29:57 +01001252
Antoine Tenarte47d9252014-10-30 18:41:13 +01001253 if (otg->state == OTG_STATE_B_IDLE)
Antoine Tenart19c1eac2014-10-30 18:41:14 +01001254 pm_runtime_put_sync(otg->usb_phy->dev);
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05301255 break;
1256 case OTG_STATE_B_PERIPHERAL:
Antoine Tenart19c1eac2014-10-30 18:41:14 +01001257 dev_dbg(otg->usb_phy->dev, "OTG_STATE_B_PERIPHERAL state\n");
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05301258 if (!test_bit(B_SESS_VLD, &motg->inputs) ||
1259 !test_bit(ID, &motg->inputs)) {
Pavankumar Kondetid8608522011-05-04 10:19:47 +05301260 msm_otg_notify_charger(motg, 0);
Antoine Tenart19c1eac2014-10-30 18:41:14 +01001261 msm_otg_start_peripheral(otg->usb_phy, 0);
Pavankumar Kondetid8608522011-05-04 10:19:47 +05301262 motg->chg_state = USB_CHG_STATE_UNDEFINED;
1263 motg->chg_type = USB_INVALID_CHARGER;
Antoine Tenarte47d9252014-10-30 18:41:13 +01001264 otg->state = OTG_STATE_B_IDLE;
Antoine Tenart19c1eac2014-10-30 18:41:14 +01001265 msm_otg_reset(otg->usb_phy);
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05301266 schedule_work(w);
1267 }
1268 break;
1269 case OTG_STATE_A_HOST:
Antoine Tenart19c1eac2014-10-30 18:41:14 +01001270 dev_dbg(otg->usb_phy->dev, "OTG_STATE_A_HOST state\n");
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05301271 if (test_bit(ID, &motg->inputs)) {
Antoine Tenart19c1eac2014-10-30 18:41:14 +01001272 msm_otg_start_host(otg->usb_phy, 0);
Antoine Tenarte47d9252014-10-30 18:41:13 +01001273 otg->state = OTG_STATE_B_IDLE;
Antoine Tenart19c1eac2014-10-30 18:41:14 +01001274 msm_otg_reset(otg->usb_phy);
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05301275 schedule_work(w);
1276 }
1277 break;
1278 default:
1279 break;
1280 }
1281}
1282
1283static irqreturn_t msm_otg_irq(int irq, void *data)
1284{
1285 struct msm_otg *motg = data;
Heikki Krogerus1d4c9292012-02-13 13:24:09 +02001286 struct usb_phy *phy = &motg->phy;
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05301287 u32 otgsc = 0;
1288
Pavankumar Kondeti87c01042010-12-07 17:53:58 +05301289 if (atomic_read(&motg->in_lpm)) {
1290 disable_irq_nosync(irq);
1291 motg->async_int = 1;
Heikki Krogerus1d4c9292012-02-13 13:24:09 +02001292 pm_runtime_get(phy->dev);
Pavankumar Kondeti87c01042010-12-07 17:53:58 +05301293 return IRQ_HANDLED;
1294 }
1295
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05301296 otgsc = readl(USB_OTGSC);
1297 if (!(otgsc & (OTGSC_IDIS | OTGSC_BSVIS)))
1298 return IRQ_NONE;
1299
1300 if ((otgsc & OTGSC_IDIS) && (otgsc & OTGSC_IDIE)) {
1301 if (otgsc & OTGSC_ID)
1302 set_bit(ID, &motg->inputs);
1303 else
1304 clear_bit(ID, &motg->inputs);
Heikki Krogerus1d4c9292012-02-13 13:24:09 +02001305 dev_dbg(phy->dev, "ID set/clear\n");
1306 pm_runtime_get_noresume(phy->dev);
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05301307 } else if ((otgsc & OTGSC_BSVIS) && (otgsc & OTGSC_BSVIE)) {
1308 if (otgsc & OTGSC_BSV)
1309 set_bit(B_SESS_VLD, &motg->inputs);
1310 else
1311 clear_bit(B_SESS_VLD, &motg->inputs);
Heikki Krogerus1d4c9292012-02-13 13:24:09 +02001312 dev_dbg(phy->dev, "BSV set/clear\n");
1313 pm_runtime_get_noresume(phy->dev);
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05301314 }
1315
1316 writel(otgsc, USB_OTGSC);
1317 schedule_work(&motg->sm_work);
1318 return IRQ_HANDLED;
1319}
1320
1321static int msm_otg_mode_show(struct seq_file *s, void *unused)
1322{
1323 struct msm_otg *motg = s->private;
Heikki Krogerus1d4c9292012-02-13 13:24:09 +02001324 struct usb_otg *otg = motg->phy.otg;
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05301325
Antoine Tenarte47d9252014-10-30 18:41:13 +01001326 switch (otg->state) {
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05301327 case OTG_STATE_A_HOST:
Ivan T. Ivanov3aca0fa2014-04-28 16:34:10 +03001328 seq_puts(s, "host\n");
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05301329 break;
1330 case OTG_STATE_B_PERIPHERAL:
Ivan T. Ivanov3aca0fa2014-04-28 16:34:10 +03001331 seq_puts(s, "peripheral\n");
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05301332 break;
1333 default:
Ivan T. Ivanov3aca0fa2014-04-28 16:34:10 +03001334 seq_puts(s, "none\n");
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05301335 break;
1336 }
1337
1338 return 0;
1339}
1340
1341static int msm_otg_mode_open(struct inode *inode, struct file *file)
1342{
1343 return single_open(file, msm_otg_mode_show, inode->i_private);
1344}
1345
1346static ssize_t msm_otg_mode_write(struct file *file, const char __user *ubuf,
1347 size_t count, loff_t *ppos)
1348{
Pavankumar Kondetie2904ee2011-02-15 09:42:35 +05301349 struct seq_file *s = file->private_data;
1350 struct msm_otg *motg = s->private;
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05301351 char buf[16];
Heikki Krogerus1d4c9292012-02-13 13:24:09 +02001352 struct usb_otg *otg = motg->phy.otg;
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05301353 int status = count;
Ivan T. Ivanov971232c2014-04-28 16:34:11 +03001354 enum usb_dr_mode req_mode;
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05301355
1356 memset(buf, 0x00, sizeof(buf));
1357
1358 if (copy_from_user(&buf, ubuf, min_t(size_t, sizeof(buf) - 1, count))) {
1359 status = -EFAULT;
1360 goto out;
1361 }
1362
1363 if (!strncmp(buf, "host", 4)) {
Ivan T. Ivanov971232c2014-04-28 16:34:11 +03001364 req_mode = USB_DR_MODE_HOST;
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05301365 } else if (!strncmp(buf, "peripheral", 10)) {
Ivan T. Ivanov971232c2014-04-28 16:34:11 +03001366 req_mode = USB_DR_MODE_PERIPHERAL;
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05301367 } else if (!strncmp(buf, "none", 4)) {
Ivan T. Ivanov971232c2014-04-28 16:34:11 +03001368 req_mode = USB_DR_MODE_UNKNOWN;
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05301369 } else {
1370 status = -EINVAL;
1371 goto out;
1372 }
1373
1374 switch (req_mode) {
Ivan T. Ivanov971232c2014-04-28 16:34:11 +03001375 case USB_DR_MODE_UNKNOWN:
Antoine Tenarte47d9252014-10-30 18:41:13 +01001376 switch (otg->state) {
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05301377 case OTG_STATE_A_HOST:
1378 case OTG_STATE_B_PERIPHERAL:
1379 set_bit(ID, &motg->inputs);
1380 clear_bit(B_SESS_VLD, &motg->inputs);
1381 break;
1382 default:
1383 goto out;
1384 }
1385 break;
Ivan T. Ivanov971232c2014-04-28 16:34:11 +03001386 case USB_DR_MODE_PERIPHERAL:
Antoine Tenarte47d9252014-10-30 18:41:13 +01001387 switch (otg->state) {
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05301388 case OTG_STATE_B_IDLE:
1389 case OTG_STATE_A_HOST:
1390 set_bit(ID, &motg->inputs);
1391 set_bit(B_SESS_VLD, &motg->inputs);
1392 break;
1393 default:
1394 goto out;
1395 }
1396 break;
Ivan T. Ivanov971232c2014-04-28 16:34:11 +03001397 case USB_DR_MODE_HOST:
Antoine Tenarte47d9252014-10-30 18:41:13 +01001398 switch (otg->state) {
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05301399 case OTG_STATE_B_IDLE:
1400 case OTG_STATE_B_PERIPHERAL:
1401 clear_bit(ID, &motg->inputs);
1402 break;
1403 default:
1404 goto out;
1405 }
1406 break;
1407 default:
1408 goto out;
1409 }
1410
Antoine Tenart19c1eac2014-10-30 18:41:14 +01001411 pm_runtime_get_sync(otg->usb_phy->dev);
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05301412 schedule_work(&motg->sm_work);
1413out:
1414 return status;
1415}
1416
Felipe Balbi8f90afd2014-08-20 13:38:18 -05001417static const struct file_operations msm_otg_mode_fops = {
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05301418 .open = msm_otg_mode_open,
1419 .read = seq_read,
1420 .write = msm_otg_mode_write,
1421 .llseek = seq_lseek,
1422 .release = single_release,
1423};
1424
1425static struct dentry *msm_otg_dbg_root;
1426static struct dentry *msm_otg_dbg_mode;
1427
1428static int msm_otg_debugfs_init(struct msm_otg *motg)
1429{
1430 msm_otg_dbg_root = debugfs_create_dir("msm_otg", NULL);
1431
1432 if (!msm_otg_dbg_root || IS_ERR(msm_otg_dbg_root))
1433 return -ENODEV;
1434
1435 msm_otg_dbg_mode = debugfs_create_file("mode", S_IRUGO | S_IWUSR,
1436 msm_otg_dbg_root, motg, &msm_otg_mode_fops);
1437 if (!msm_otg_dbg_mode) {
1438 debugfs_remove(msm_otg_dbg_root);
1439 msm_otg_dbg_root = NULL;
1440 return -ENODEV;
1441 }
1442
1443 return 0;
1444}
1445
1446static void msm_otg_debugfs_cleanup(void)
1447{
1448 debugfs_remove(msm_otg_dbg_mode);
1449 debugfs_remove(msm_otg_dbg_root);
1450}
1451
Jingoo Han492240b2014-06-18 13:42:44 +09001452static const struct of_device_id msm_otg_dt_match[] = {
Ivan T. Ivanov8364f9a2014-04-28 16:34:15 +03001453 {
1454 .compatible = "qcom,usb-otg-ci",
1455 .data = (void *) CI_45NM_INTEGRATED_PHY
1456 },
1457 {
1458 .compatible = "qcom,usb-otg-snps",
1459 .data = (void *) SNPS_28NM_INTEGRATED_PHY
1460 },
1461 { }
1462};
1463MODULE_DEVICE_TABLE(of, msm_otg_dt_match);
1464
Ivan T. Ivanov591fc112015-04-09 11:34:22 +03001465static int msm_otg_vbus_notifier(struct notifier_block *nb, unsigned long event,
1466 void *ptr)
1467{
1468 struct msm_usb_cable *vbus = container_of(nb, struct msm_usb_cable, nb);
1469 struct msm_otg *motg = container_of(vbus, struct msm_otg, vbus);
1470
1471 if (event)
1472 set_bit(B_SESS_VLD, &motg->inputs);
1473 else
1474 clear_bit(B_SESS_VLD, &motg->inputs);
1475
Ivan T. Ivanov6f98f542015-07-28 11:10:22 +03001476 if (test_bit(B_SESS_VLD, &motg->inputs)) {
1477 /* Switch D+/D- lines to Device connector */
1478 gpiod_set_value_cansleep(motg->switch_gpio, 0);
1479 } else {
1480 /* Switch D+/D- lines to Hub */
1481 gpiod_set_value_cansleep(motg->switch_gpio, 1);
1482 }
1483
Ivan T. Ivanov591fc112015-04-09 11:34:22 +03001484 schedule_work(&motg->sm_work);
1485
1486 return NOTIFY_DONE;
1487}
1488
1489static int msm_otg_id_notifier(struct notifier_block *nb, unsigned long event,
1490 void *ptr)
1491{
1492 struct msm_usb_cable *id = container_of(nb, struct msm_usb_cable, nb);
1493 struct msm_otg *motg = container_of(id, struct msm_otg, id);
1494
1495 if (event)
1496 clear_bit(ID, &motg->inputs);
1497 else
1498 set_bit(ID, &motg->inputs);
1499
1500 schedule_work(&motg->sm_work);
1501
1502 return NOTIFY_DONE;
1503}
1504
Ivan T. Ivanov8364f9a2014-04-28 16:34:15 +03001505static int msm_otg_read_dt(struct platform_device *pdev, struct msm_otg *motg)
1506{
1507 struct msm_otg_platform_data *pdata;
Ivan T. Ivanov591fc112015-04-09 11:34:22 +03001508 struct extcon_dev *ext_id, *ext_vbus;
Ivan T. Ivanov8364f9a2014-04-28 16:34:15 +03001509 struct device_node *node = pdev->dev.of_node;
1510 struct property *prop;
1511 int len, ret, words;
Ivan T. Ivanov01799b62014-04-28 16:34:22 +03001512 u32 val, tmp[3];
Ivan T. Ivanov8364f9a2014-04-28 16:34:15 +03001513
1514 pdata = devm_kzalloc(&pdev->dev, sizeof(*pdata), GFP_KERNEL);
1515 if (!pdata)
1516 return -ENOMEM;
1517
1518 motg->pdata = pdata;
1519
LABBE Corentin928c75f2015-11-24 15:34:09 +01001520 pdata->phy_type = (enum msm_usb_phy_type)of_device_get_match_data(&pdev->dev);
1521 if (!pdata->phy_type)
1522 return 1;
Ivan T. Ivanov8364f9a2014-04-28 16:34:15 +03001523
Ivan T. Ivanova2734542014-04-28 16:34:16 +03001524 motg->link_rst = devm_reset_control_get(&pdev->dev, "link");
1525 if (IS_ERR(motg->link_rst))
1526 return PTR_ERR(motg->link_rst);
1527
1528 motg->phy_rst = devm_reset_control_get(&pdev->dev, "phy");
1529 if (IS_ERR(motg->phy_rst))
Srinivas Kandagatlae44f1f42014-06-30 18:29:49 +01001530 motg->phy_rst = NULL;
Ivan T. Ivanova2734542014-04-28 16:34:16 +03001531
Heikki Krogerus06e71142015-09-21 11:14:34 +03001532 pdata->mode = usb_get_dr_mode(&pdev->dev);
Ivan T. Ivanov8364f9a2014-04-28 16:34:15 +03001533 if (pdata->mode == USB_DR_MODE_UNKNOWN)
1534 pdata->mode = USB_DR_MODE_OTG;
1535
1536 pdata->otg_control = OTG_PHY_CONTROL;
1537 if (!of_property_read_u32(node, "qcom,otg-control", &val))
1538 if (val == OTG_PMIC_CONTROL)
1539 pdata->otg_control = val;
1540
Ivan T. Ivanovcfa3ff52014-04-28 16:34:17 +03001541 if (!of_property_read_u32(node, "qcom,phy-num", &val) && val < 2)
1542 motg->phy_number = val;
1543
Ivan T. Ivanov01799b62014-04-28 16:34:22 +03001544 motg->vdd_levels[VDD_LEVEL_NONE] = USB_PHY_SUSP_DIG_VOL;
1545 motg->vdd_levels[VDD_LEVEL_MIN] = USB_PHY_VDD_DIG_VOL_MIN;
1546 motg->vdd_levels[VDD_LEVEL_MAX] = USB_PHY_VDD_DIG_VOL_MAX;
1547
1548 if (of_get_property(node, "qcom,vdd-levels", &len) &&
1549 len == sizeof(tmp)) {
1550 of_property_read_u32_array(node, "qcom,vdd-levels",
1551 tmp, len / sizeof(*tmp));
1552 motg->vdd_levels[VDD_LEVEL_NONE] = tmp[VDD_LEVEL_NONE];
1553 motg->vdd_levels[VDD_LEVEL_MIN] = tmp[VDD_LEVEL_MIN];
1554 motg->vdd_levels[VDD_LEVEL_MAX] = tmp[VDD_LEVEL_MAX];
1555 }
1556
Ivan T. Ivanov44e42ae2015-04-09 11:34:33 +03001557 motg->manual_pullup = of_property_read_bool(node, "qcom,manual-pullup");
1558
Ivan T. Ivanov6f98f542015-07-28 11:10:22 +03001559 motg->switch_gpio = devm_gpiod_get_optional(&pdev->dev, "switch",
1560 GPIOD_OUT_LOW);
1561 if (IS_ERR(motg->switch_gpio))
1562 return PTR_ERR(motg->switch_gpio);
1563
Ivan T. Ivanov591fc112015-04-09 11:34:22 +03001564 ext_id = ERR_PTR(-ENODEV);
1565 ext_vbus = ERR_PTR(-ENODEV);
1566 if (of_property_read_bool(node, "extcon")) {
1567
1568 /* Each one of them is not mandatory */
1569 ext_vbus = extcon_get_edev_by_phandle(&pdev->dev, 0);
1570 if (IS_ERR(ext_vbus) && PTR_ERR(ext_vbus) != -ENODEV)
1571 return PTR_ERR(ext_vbus);
1572
1573 ext_id = extcon_get_edev_by_phandle(&pdev->dev, 1);
1574 if (IS_ERR(ext_id) && PTR_ERR(ext_id) != -ENODEV)
1575 return PTR_ERR(ext_id);
1576 }
1577
1578 if (!IS_ERR(ext_vbus)) {
Chanwoo Choi83b7b672015-07-01 13:11:34 +09001579 motg->vbus.extcon = ext_vbus;
Ivan T. Ivanov591fc112015-04-09 11:34:22 +03001580 motg->vbus.nb.notifier_call = msm_otg_vbus_notifier;
Chanwoo Choi83b7b672015-07-01 13:11:34 +09001581 ret = extcon_register_notifier(ext_vbus, EXTCON_USB,
1582 &motg->vbus.nb);
Ivan T. Ivanov591fc112015-04-09 11:34:22 +03001583 if (ret < 0) {
1584 dev_err(&pdev->dev, "register VBUS notifier failed\n");
1585 return ret;
1586 }
1587
Chanwoo Choi83b7b672015-07-01 13:11:34 +09001588 ret = extcon_get_cable_state_(ext_vbus, EXTCON_USB);
Ivan T. Ivanov591fc112015-04-09 11:34:22 +03001589 if (ret)
1590 set_bit(B_SESS_VLD, &motg->inputs);
1591 else
1592 clear_bit(B_SESS_VLD, &motg->inputs);
1593 }
1594
1595 if (!IS_ERR(ext_id)) {
Chanwoo Choi83b7b672015-07-01 13:11:34 +09001596 motg->id.extcon = ext_id;
Ivan T. Ivanov591fc112015-04-09 11:34:22 +03001597 motg->id.nb.notifier_call = msm_otg_id_notifier;
Chanwoo Choi83b7b672015-07-01 13:11:34 +09001598 ret = extcon_register_notifier(ext_id, EXTCON_USB_HOST,
1599 &motg->id.nb);
Ivan T. Ivanov591fc112015-04-09 11:34:22 +03001600 if (ret < 0) {
1601 dev_err(&pdev->dev, "register ID notifier failed\n");
Srinivas Kandagatlaa38a08d2016-01-13 09:13:10 +00001602 extcon_unregister_notifier(motg->vbus.extcon,
1603 EXTCON_USB, &motg->vbus.nb);
Ivan T. Ivanov591fc112015-04-09 11:34:22 +03001604 return ret;
1605 }
1606
Chanwoo Choi83b7b672015-07-01 13:11:34 +09001607 ret = extcon_get_cable_state_(ext_id, EXTCON_USB_HOST);
Ivan T. Ivanov591fc112015-04-09 11:34:22 +03001608 if (ret)
1609 clear_bit(ID, &motg->inputs);
1610 else
1611 set_bit(ID, &motg->inputs);
1612 }
1613
Ivan T. Ivanov8364f9a2014-04-28 16:34:15 +03001614 prop = of_find_property(node, "qcom,phy-init-sequence", &len);
1615 if (!prop || !len)
1616 return 0;
1617
1618 words = len / sizeof(u32);
1619
1620 if (words >= ULPI_EXT_VENDOR_SPECIFIC) {
1621 dev_warn(&pdev->dev, "Too big PHY init sequence %d\n", words);
1622 return 0;
1623 }
1624
1625 pdata->phy_init_seq = devm_kzalloc(&pdev->dev, len, GFP_KERNEL);
Peter Chen9da22202014-10-14 15:56:17 +08001626 if (!pdata->phy_init_seq)
Ivan T. Ivanov8364f9a2014-04-28 16:34:15 +03001627 return 0;
Ivan T. Ivanov8364f9a2014-04-28 16:34:15 +03001628
1629 ret = of_property_read_u32_array(node, "qcom,phy-init-sequence",
1630 pdata->phy_init_seq, words);
1631 if (!ret)
1632 pdata->phy_init_sz = words;
1633
1634 return 0;
1635}
1636
Ivan T. Ivanov6f98f542015-07-28 11:10:22 +03001637static int msm_otg_reboot_notify(struct notifier_block *this,
1638 unsigned long code, void *unused)
1639{
1640 struct msm_otg *motg = container_of(this, struct msm_otg, reboot);
1641
1642 /*
1643 * Ensure that D+/D- lines are routed to uB connector, so
1644 * we could load bootloader/kernel at next reboot
1645 */
1646 gpiod_set_value_cansleep(motg->switch_gpio, 0);
1647 return NOTIFY_DONE;
1648}
1649
Ivan T. Ivanov06a6ec42014-04-28 16:34:07 +03001650static int msm_otg_probe(struct platform_device *pdev)
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05301651{
Ivan T. Ivanov6b99c68e2014-04-28 16:34:08 +03001652 struct regulator_bulk_data regs[3];
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05301653 int ret = 0;
Ivan T. Ivanov8364f9a2014-04-28 16:34:15 +03001654 struct device_node *np = pdev->dev.of_node;
1655 struct msm_otg_platform_data *pdata;
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05301656 struct resource *res;
1657 struct msm_otg *motg;
Heikki Krogerus1d4c9292012-02-13 13:24:09 +02001658 struct usb_phy *phy;
Tim Bird30bf8662014-04-28 16:34:20 +03001659 void __iomem *phy_select;
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05301660
Ivan T. Ivanov6b99c68e2014-04-28 16:34:08 +03001661 motg = devm_kzalloc(&pdev->dev, sizeof(struct msm_otg), GFP_KERNEL);
Peter Chen9da22202014-10-14 15:56:17 +08001662 if (!motg)
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05301663 return -ENOMEM;
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05301664
Ivan T. Ivanov6b99c68e2014-04-28 16:34:08 +03001665 motg->phy.otg = devm_kzalloc(&pdev->dev, sizeof(struct usb_otg),
1666 GFP_KERNEL);
Peter Chen9da22202014-10-14 15:56:17 +08001667 if (!motg->phy.otg)
Ivan T. Ivanov6b99c68e2014-04-28 16:34:08 +03001668 return -ENOMEM;
Heikki Krogerus1d4c9292012-02-13 13:24:09 +02001669
Heikki Krogerus1d4c9292012-02-13 13:24:09 +02001670 phy = &motg->phy;
1671 phy->dev = &pdev->dev;
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05301672
Ivan T. Ivanov8364f9a2014-04-28 16:34:15 +03001673 motg->clk = devm_clk_get(&pdev->dev, np ? "core" : "usb_hs_clk");
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05301674 if (IS_ERR(motg->clk)) {
1675 dev_err(&pdev->dev, "failed to get usb_hs_clk\n");
Ivan T. Ivanov6b99c68e2014-04-28 16:34:08 +03001676 return PTR_ERR(motg->clk);
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05301677 }
Anji jonnala0f73cac2011-05-04 10:19:46 +05301678
1679 /*
1680 * If USB Core is running its protocol engine based on CORE CLK,
1681 * CORE CLK must be running at >55Mhz for correct HSUSB
1682 * operation and USB core cannot tolerate frequency changes on
Ivan T. Ivanovff0e4a62014-04-28 16:34:12 +03001683 * CORE CLK.
Anji jonnala0f73cac2011-05-04 10:19:46 +05301684 */
Ivan T. Ivanov8364f9a2014-04-28 16:34:15 +03001685 motg->pclk = devm_clk_get(&pdev->dev, np ? "iface" : "usb_hs_pclk");
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05301686 if (IS_ERR(motg->pclk)) {
1687 dev_err(&pdev->dev, "failed to get usb_hs_pclk\n");
Ivan T. Ivanov6b99c68e2014-04-28 16:34:08 +03001688 return PTR_ERR(motg->pclk);
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05301689 }
1690
1691 /*
1692 * USB core clock is not present on all MSM chips. This
1693 * clock is introduced to remove the dependency on AXI
1694 * bus frequency.
1695 */
Ivan T. Ivanov8364f9a2014-04-28 16:34:15 +03001696 motg->core_clk = devm_clk_get(&pdev->dev,
1697 np ? "alt_core" : "usb_hs_core_clk");
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05301698
1699 res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
Dan Carpenter2ea7b142014-05-19 23:35:19 +03001700 if (!res)
1701 return -EINVAL;
1702 motg->regs = devm_ioremap(&pdev->dev, res->start, resource_size(res));
1703 if (!motg->regs)
1704 return -ENOMEM;
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05301705
Srinivas Kandagatlaa38a08d2016-01-13 09:13:10 +00001706 pdata = dev_get_platdata(&pdev->dev);
1707 if (!pdata) {
1708 if (!np)
1709 return -ENXIO;
1710 ret = msm_otg_read_dt(pdev, motg);
1711 if (ret)
1712 return ret;
1713 }
1714
Tim Bird30bf8662014-04-28 16:34:20 +03001715 /*
1716 * NOTE: The PHYs can be multiplexed between the chipidea controller
1717 * and the dwc3 controller, using a single bit. It is important that
1718 * the dwc3 driver does not set this bit in an incompatible way.
1719 */
1720 if (motg->phy_number) {
1721 phy_select = devm_ioremap_nocache(&pdev->dev, USB2_PHY_SEL, 4);
Srinivas Kandagatlaa38a08d2016-01-13 09:13:10 +00001722 if (!phy_select) {
1723 ret = -ENOMEM;
1724 goto unregister_extcon;
1725 }
Tim Bird30bf8662014-04-28 16:34:20 +03001726 /* Enable second PHY with the OTG port */
Felipe Balbi24597492014-04-30 11:35:22 -05001727 writel(0x1, phy_select);
Tim Bird30bf8662014-04-28 16:34:20 +03001728 }
1729
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05301730 dev_info(&pdev->dev, "OTG regs = %p\n", motg->regs);
1731
1732 motg->irq = platform_get_irq(pdev, 0);
Ivan T. Ivanovf60c1142014-04-28 16:34:14 +03001733 if (motg->irq < 0) {
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05301734 dev_err(&pdev->dev, "platform_get_irq failed\n");
Srinivas Kandagatlaa38a08d2016-01-13 09:13:10 +00001735 ret = motg->irq;
1736 goto unregister_extcon;
Ivan T. Ivanov6b99c68e2014-04-28 16:34:08 +03001737 }
1738
Ivan T. Ivanovf5ef2372014-04-28 16:34:13 +03001739 regs[0].supply = "vddcx";
1740 regs[1].supply = "v3p3";
1741 regs[2].supply = "v1p8";
Ivan T. Ivanov6b99c68e2014-04-28 16:34:08 +03001742
1743 ret = devm_regulator_bulk_get(motg->phy.dev, ARRAY_SIZE(regs), regs);
1744 if (ret)
Srinivas Kandagatlaa38a08d2016-01-13 09:13:10 +00001745 goto unregister_extcon;
Ivan T. Ivanov6b99c68e2014-04-28 16:34:08 +03001746
1747 motg->vddcx = regs[0].consumer;
1748 motg->v3p3 = regs[1].consumer;
1749 motg->v1p8 = regs[2].consumer;
1750
1751 clk_set_rate(motg->clk, 60000000);
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05301752
Stephen Boydb99a8f62013-06-17 10:43:10 -07001753 clk_prepare_enable(motg->clk);
1754 clk_prepare_enable(motg->pclk);
Anji jonnala11aa5c42011-05-04 10:19:48 +05301755
Ivan T. Ivanov6b99c68e2014-04-28 16:34:08 +03001756 if (!IS_ERR(motg->core_clk))
1757 clk_prepare_enable(motg->core_clk);
1758
Anji jonnala11aa5c42011-05-04 10:19:48 +05301759 ret = msm_hsusb_init_vddcx(motg, 1);
1760 if (ret) {
1761 dev_err(&pdev->dev, "hsusb vddcx configuration failed\n");
Ivan T. Ivanov6b99c68e2014-04-28 16:34:08 +03001762 goto disable_clks;
Anji jonnala11aa5c42011-05-04 10:19:48 +05301763 }
1764
1765 ret = msm_hsusb_ldo_init(motg, 1);
1766 if (ret) {
1767 dev_err(&pdev->dev, "hsusb vreg configuration failed\n");
Ivan T. Ivanov6b99c68e2014-04-28 16:34:08 +03001768 goto disable_vddcx;
Anji jonnala11aa5c42011-05-04 10:19:48 +05301769 }
Ivan T. Ivanov37cfdaf2014-04-28 16:34:06 +03001770 ret = msm_hsusb_ldo_set_mode(motg, 1);
Anji jonnala11aa5c42011-05-04 10:19:48 +05301771 if (ret) {
1772 dev_err(&pdev->dev, "hsusb vreg enable failed\n");
Ivan T. Ivanov6b99c68e2014-04-28 16:34:08 +03001773 goto disable_ldo;
Anji jonnala11aa5c42011-05-04 10:19:48 +05301774 }
1775
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05301776 writel(0, USB_USBINTR);
1777 writel(0, USB_OTGSC);
1778
1779 INIT_WORK(&motg->sm_work, msm_otg_sm_work);
Pavankumar Kondetid8608522011-05-04 10:19:47 +05301780 INIT_DELAYED_WORK(&motg->chg_work, msm_chg_detect_work);
Ivan T. Ivanov6b99c68e2014-04-28 16:34:08 +03001781 ret = devm_request_irq(&pdev->dev, motg->irq, msm_otg_irq, IRQF_SHARED,
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05301782 "msm_otg", motg);
1783 if (ret) {
1784 dev_err(&pdev->dev, "request irq failed\n");
Ivan T. Ivanov6b99c68e2014-04-28 16:34:08 +03001785 goto disable_ldo;
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05301786 }
1787
Ivan T. Ivanovd69c6f52014-04-28 16:34:18 +03001788 phy->init = msm_phy_init;
Heikki Krogerus1d4c9292012-02-13 13:24:09 +02001789 phy->set_power = msm_otg_set_power;
Ivan T. Ivanov349907c2014-04-28 16:34:21 +03001790 phy->notify_disconnect = msm_phy_notify_disconnect;
Ivan T. Ivanove695abb2014-04-28 16:34:23 +03001791 phy->type = USB_PHY_TYPE_USB2;
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05301792
Heikki Krogerus1d4c9292012-02-13 13:24:09 +02001793 phy->io_ops = &msm_otg_io_ops;
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05301794
Antoine Tenart19c1eac2014-10-30 18:41:14 +01001795 phy->otg->usb_phy = &motg->phy;
Heikki Krogerus1d4c9292012-02-13 13:24:09 +02001796 phy->otg->set_host = msm_otg_set_host;
1797 phy->otg->set_peripheral = msm_otg_set_peripheral;
1798
Ivan T. Ivanovd69c6f52014-04-28 16:34:18 +03001799 msm_usb_reset(phy);
1800
Ivan T. Ivanove695abb2014-04-28 16:34:23 +03001801 ret = usb_add_phy_dev(&motg->phy);
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05301802 if (ret) {
Kishon Vijay Abraham I721002e2012-06-22 17:02:45 +05301803 dev_err(&pdev->dev, "usb_add_phy failed\n");
Ivan T. Ivanov6b99c68e2014-04-28 16:34:08 +03001804 goto disable_ldo;
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05301805 }
1806
1807 platform_set_drvdata(pdev, motg);
1808 device_init_wakeup(&pdev->dev, 1);
1809
Ivan T. Ivanov971232c2014-04-28 16:34:11 +03001810 if (motg->pdata->mode == USB_DR_MODE_OTG &&
Ivan T. Ivanov8364f9a2014-04-28 16:34:15 +03001811 motg->pdata->otg_control == OTG_USER_CONTROL) {
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05301812 ret = msm_otg_debugfs_init(motg);
1813 if (ret)
Ivan T. Ivanov3aca0fa2014-04-28 16:34:10 +03001814 dev_dbg(&pdev->dev, "Can not create mode change file\n");
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05301815 }
1816
Ivan T. Ivanov6f98f542015-07-28 11:10:22 +03001817 if (test_bit(B_SESS_VLD, &motg->inputs)) {
1818 /* Switch D+/D- lines to Device connector */
1819 gpiod_set_value_cansleep(motg->switch_gpio, 0);
1820 } else {
1821 /* Switch D+/D- lines to Hub */
1822 gpiod_set_value_cansleep(motg->switch_gpio, 1);
1823 }
1824
1825 motg->reboot.notifier_call = msm_otg_reboot_notify;
1826 register_reboot_notifier(&motg->reboot);
1827
Pavankumar Kondeti87c01042010-12-07 17:53:58 +05301828 pm_runtime_set_active(&pdev->dev);
1829 pm_runtime_enable(&pdev->dev);
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05301830
Pavankumar Kondeti87c01042010-12-07 17:53:58 +05301831 return 0;
Ivan T. Ivanov6b99c68e2014-04-28 16:34:08 +03001832
1833disable_ldo:
1834 msm_hsusb_ldo_init(motg, 0);
1835disable_vddcx:
1836 msm_hsusb_init_vddcx(motg, 0);
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05301837disable_clks:
Stephen Boydb99a8f62013-06-17 10:43:10 -07001838 clk_disable_unprepare(motg->pclk);
1839 clk_disable_unprepare(motg->clk);
Ivan T. Ivanov6b99c68e2014-04-28 16:34:08 +03001840 if (!IS_ERR(motg->core_clk))
1841 clk_disable_unprepare(motg->core_clk);
Srinivas Kandagatlaa38a08d2016-01-13 09:13:10 +00001842unregister_extcon:
1843 extcon_unregister_notifier(motg->id.extcon,
1844 EXTCON_USB_HOST, &motg->id.nb);
1845 extcon_unregister_notifier(motg->vbus.extcon,
1846 EXTCON_USB, &motg->vbus.nb);
1847
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05301848 return ret;
1849}
1850
Bill Pembertonfb4e98a2012-11-19 13:26:20 -05001851static int msm_otg_remove(struct platform_device *pdev)
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05301852{
1853 struct msm_otg *motg = platform_get_drvdata(pdev);
Heikki Krogerus1d4c9292012-02-13 13:24:09 +02001854 struct usb_phy *phy = &motg->phy;
Pavankumar Kondeti87c01042010-12-07 17:53:58 +05301855 int cnt = 0;
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05301856
Heikki Krogerus1d4c9292012-02-13 13:24:09 +02001857 if (phy->otg->host || phy->otg->gadget)
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05301858 return -EBUSY;
1859
Ivan T. Ivanov6f98f542015-07-28 11:10:22 +03001860 unregister_reboot_notifier(&motg->reboot);
1861
1862 /*
1863 * Ensure that D+/D- lines are routed to uB connector, so
1864 * we could load bootloader/kernel at next reboot
1865 */
1866 gpiod_set_value_cansleep(motg->switch_gpio, 0);
1867
Chanwoo Choi83b7b672015-07-01 13:11:34 +09001868 extcon_unregister_notifier(motg->id.extcon, EXTCON_USB_HOST, &motg->id.nb);
1869 extcon_unregister_notifier(motg->vbus.extcon, EXTCON_USB, &motg->vbus.nb);
Ivan T. Ivanov591fc112015-04-09 11:34:22 +03001870
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05301871 msm_otg_debugfs_cleanup();
Pavankumar Kondetid8608522011-05-04 10:19:47 +05301872 cancel_delayed_work_sync(&motg->chg_work);
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05301873 cancel_work_sync(&motg->sm_work);
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05301874
Pavankumar Kondeti70187732011-02-15 09:42:34 +05301875 pm_runtime_resume(&pdev->dev);
Pavankumar Kondeti87c01042010-12-07 17:53:58 +05301876
1877 device_init_wakeup(&pdev->dev, 0);
1878 pm_runtime_disable(&pdev->dev);
1879
Kishon Vijay Abraham I662dca52012-06-22 17:02:46 +05301880 usb_remove_phy(phy);
Ivan T. Ivanov6b99c68e2014-04-28 16:34:08 +03001881 disable_irq(motg->irq);
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05301882
Pavankumar Kondeti87c01042010-12-07 17:53:58 +05301883 /*
1884 * Put PHY in low power mode.
1885 */
Heikki Krogerus1d4c9292012-02-13 13:24:09 +02001886 ulpi_read(phy, 0x14);
1887 ulpi_write(phy, 0x08, 0x09);
Pavankumar Kondeti87c01042010-12-07 17:53:58 +05301888
1889 writel(readl(USB_PORTSC) | PORTSC_PHCD, USB_PORTSC);
1890 while (cnt < PHY_SUSPEND_TIMEOUT_USEC) {
1891 if (readl(USB_PORTSC) & PORTSC_PHCD)
1892 break;
1893 udelay(1);
1894 cnt++;
1895 }
1896 if (cnt >= PHY_SUSPEND_TIMEOUT_USEC)
Heikki Krogerus1d4c9292012-02-13 13:24:09 +02001897 dev_err(phy->dev, "Unable to suspend PHY\n");
Pavankumar Kondeti87c01042010-12-07 17:53:58 +05301898
Stephen Boydb99a8f62013-06-17 10:43:10 -07001899 clk_disable_unprepare(motg->pclk);
1900 clk_disable_unprepare(motg->clk);
Ivan T. Ivanov6b99c68e2014-04-28 16:34:08 +03001901 if (!IS_ERR(motg->core_clk))
Stephen Boydb99a8f62013-06-17 10:43:10 -07001902 clk_disable_unprepare(motg->core_clk);
Anji jonnala11aa5c42011-05-04 10:19:48 +05301903 msm_hsusb_ldo_init(motg, 0);
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05301904
Pavankumar Kondeti87c01042010-12-07 17:53:58 +05301905 pm_runtime_set_suspended(&pdev->dev);
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05301906
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05301907 return 0;
1908}
1909
Rafael J. Wysockiceb6c9c2014-11-29 23:47:05 +01001910#ifdef CONFIG_PM
Pavankumar Kondeti87c01042010-12-07 17:53:58 +05301911static int msm_otg_runtime_idle(struct device *dev)
1912{
1913 struct msm_otg *motg = dev_get_drvdata(dev);
Heikki Krogerus1d4c9292012-02-13 13:24:09 +02001914 struct usb_otg *otg = motg->phy.otg;
Pavankumar Kondeti87c01042010-12-07 17:53:58 +05301915
1916 dev_dbg(dev, "OTG runtime idle\n");
1917
1918 /*
1919 * It is observed some times that a spurious interrupt
1920 * comes when PHY is put into LPM immediately after PHY reset.
1921 * This 1 sec delay also prevents entering into LPM immediately
1922 * after asynchronous interrupt.
1923 */
Antoine Tenarte47d9252014-10-30 18:41:13 +01001924 if (otg->state != OTG_STATE_UNDEFINED)
Pavankumar Kondeti87c01042010-12-07 17:53:58 +05301925 pm_schedule_suspend(dev, 1000);
1926
1927 return -EAGAIN;
1928}
1929
1930static int msm_otg_runtime_suspend(struct device *dev)
1931{
1932 struct msm_otg *motg = dev_get_drvdata(dev);
1933
1934 dev_dbg(dev, "OTG runtime suspend\n");
1935 return msm_otg_suspend(motg);
1936}
1937
1938static int msm_otg_runtime_resume(struct device *dev)
1939{
1940 struct msm_otg *motg = dev_get_drvdata(dev);
1941
1942 dev_dbg(dev, "OTG runtime resume\n");
1943 return msm_otg_resume(motg);
1944}
Pavankumar Kondeti87c01042010-12-07 17:53:58 +05301945#endif
1946
Pavankumar Kondeti70187732011-02-15 09:42:34 +05301947#ifdef CONFIG_PM_SLEEP
Pavankumar Kondeti87c01042010-12-07 17:53:58 +05301948static int msm_otg_pm_suspend(struct device *dev)
1949{
1950 struct msm_otg *motg = dev_get_drvdata(dev);
1951
1952 dev_dbg(dev, "OTG PM suspend\n");
1953 return msm_otg_suspend(motg);
1954}
1955
1956static int msm_otg_pm_resume(struct device *dev)
1957{
1958 struct msm_otg *motg = dev_get_drvdata(dev);
1959 int ret;
1960
1961 dev_dbg(dev, "OTG PM resume\n");
1962
1963 ret = msm_otg_resume(motg);
1964 if (ret)
1965 return ret;
1966
1967 /*
1968 * Runtime PM Documentation recommends bringing the
1969 * device to full powered state upon resume.
1970 */
1971 pm_runtime_disable(dev);
1972 pm_runtime_set_active(dev);
1973 pm_runtime_enable(dev);
1974
1975 return 0;
1976}
Pavankumar Kondeti87c01042010-12-07 17:53:58 +05301977#endif
1978
1979static const struct dev_pm_ops msm_otg_dev_pm_ops = {
Pavankumar Kondeti70187732011-02-15 09:42:34 +05301980 SET_SYSTEM_SLEEP_PM_OPS(msm_otg_pm_suspend, msm_otg_pm_resume)
1981 SET_RUNTIME_PM_OPS(msm_otg_runtime_suspend, msm_otg_runtime_resume,
1982 msm_otg_runtime_idle)
Pavankumar Kondeti87c01042010-12-07 17:53:58 +05301983};
1984
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05301985static struct platform_driver msm_otg_driver = {
Ivan T. Ivanov06a6ec42014-04-28 16:34:07 +03001986 .probe = msm_otg_probe,
Bill Pemberton76904172012-11-19 13:21:08 -05001987 .remove = msm_otg_remove,
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05301988 .driver = {
1989 .name = DRIVER_NAME,
Pavankumar Kondeti87c01042010-12-07 17:53:58 +05301990 .pm = &msm_otg_dev_pm_ops,
Ivan T. Ivanov8364f9a2014-04-28 16:34:15 +03001991 .of_match_table = msm_otg_dt_match,
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05301992 },
1993};
1994
Ivan T. Ivanov06a6ec42014-04-28 16:34:07 +03001995module_platform_driver(msm_otg_driver);
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05301996
1997MODULE_LICENSE("GPL v2");
1998MODULE_DESCRIPTION("MSM USB transceiver driver");