blob: 00c49bb1bd29a8ac9a63d6f6a69aea6a71e837d8 [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 */
Ivan T. Ivanov01799b62014-04-28 16:34:22 +030065#define USB_PHY_SUSP_DIG_VOL 500000 /* uV */
66
67enum vdd_levels {
68 VDD_LEVEL_NONE = 0,
69 VDD_LEVEL_MIN,
70 VDD_LEVEL_MAX,
71};
Anji jonnala11aa5c42011-05-04 10:19:48 +053072
Anji jonnala11aa5c42011-05-04 10:19:48 +053073static int msm_hsusb_init_vddcx(struct msm_otg *motg, int init)
74{
75 int ret = 0;
76
77 if (init) {
Ivan T. Ivanov37cfdaf2014-04-28 16:34:06 +030078 ret = regulator_set_voltage(motg->vddcx,
Ivan T. Ivanov01799b62014-04-28 16:34:22 +030079 motg->vdd_levels[VDD_LEVEL_MIN],
80 motg->vdd_levels[VDD_LEVEL_MAX]);
Anji jonnala11aa5c42011-05-04 10:19:48 +053081 if (ret) {
Ivan T. Ivanov3aca0fa2014-04-28 16:34:10 +030082 dev_err(motg->phy.dev, "Cannot set vddcx voltage\n");
Anji jonnala11aa5c42011-05-04 10:19:48 +053083 return ret;
84 }
85
Ivan T. Ivanov37cfdaf2014-04-28 16:34:06 +030086 ret = regulator_enable(motg->vddcx);
Ivan T. Ivanov6b99c68e2014-04-28 16:34:08 +030087 if (ret)
Heikki Krogerus1d4c9292012-02-13 13:24:09 +020088 dev_err(motg->phy.dev, "unable to enable hsusb vddcx\n");
Anji jonnala11aa5c42011-05-04 10:19:48 +053089 } else {
Ivan T. Ivanov37cfdaf2014-04-28 16:34:06 +030090 ret = regulator_set_voltage(motg->vddcx, 0,
Ivan T. Ivanov01799b62014-04-28 16:34:22 +030091 motg->vdd_levels[VDD_LEVEL_MAX]);
Mark Browne99c4302011-05-15 09:55:58 -070092 if (ret)
Ivan T. Ivanov3aca0fa2014-04-28 16:34:10 +030093 dev_err(motg->phy.dev, "Cannot set vddcx voltage\n");
Ivan T. Ivanov37cfdaf2014-04-28 16:34:06 +030094 ret = regulator_disable(motg->vddcx);
Anji jonnala11aa5c42011-05-04 10:19:48 +053095 if (ret)
Heikki Krogerus1d4c9292012-02-13 13:24:09 +020096 dev_err(motg->phy.dev, "unable to disable hsusb vddcx\n");
Anji jonnala11aa5c42011-05-04 10:19:48 +053097 }
98
99 return ret;
100}
101
102static int msm_hsusb_ldo_init(struct msm_otg *motg, int init)
103{
104 int rc = 0;
105
106 if (init) {
Ivan T. Ivanov37cfdaf2014-04-28 16:34:06 +0300107 rc = regulator_set_voltage(motg->v3p3, USB_PHY_3P3_VOL_MIN,
Anji jonnala11aa5c42011-05-04 10:19:48 +0530108 USB_PHY_3P3_VOL_MAX);
109 if (rc) {
Ivan T. Ivanov3aca0fa2014-04-28 16:34:10 +0300110 dev_err(motg->phy.dev, "Cannot set v3p3 voltage\n");
Ivan T. Ivanov6b99c68e2014-04-28 16:34:08 +0300111 goto exit;
Anji jonnala11aa5c42011-05-04 10:19:48 +0530112 }
Ivan T. Ivanov37cfdaf2014-04-28 16:34:06 +0300113 rc = regulator_enable(motg->v3p3);
Anji jonnala11aa5c42011-05-04 10:19:48 +0530114 if (rc) {
Heikki Krogerus1d4c9292012-02-13 13:24:09 +0200115 dev_err(motg->phy.dev, "unable to enable the hsusb 3p3\n");
Ivan T. Ivanov6b99c68e2014-04-28 16:34:08 +0300116 goto exit;
Anji jonnala11aa5c42011-05-04 10:19:48 +0530117 }
Ivan T. Ivanov37cfdaf2014-04-28 16:34:06 +0300118 rc = regulator_set_voltage(motg->v1p8, USB_PHY_1P8_VOL_MIN,
Anji jonnala11aa5c42011-05-04 10:19:48 +0530119 USB_PHY_1P8_VOL_MAX);
120 if (rc) {
Ivan T. Ivanov3aca0fa2014-04-28 16:34:10 +0300121 dev_err(motg->phy.dev, "Cannot set v1p8 voltage\n");
Ivan T. Ivanov6b99c68e2014-04-28 16:34:08 +0300122 goto disable_3p3;
Anji jonnala11aa5c42011-05-04 10:19:48 +0530123 }
Ivan T. Ivanov37cfdaf2014-04-28 16:34:06 +0300124 rc = regulator_enable(motg->v1p8);
Anji jonnala11aa5c42011-05-04 10:19:48 +0530125 if (rc) {
Heikki Krogerus1d4c9292012-02-13 13:24:09 +0200126 dev_err(motg->phy.dev, "unable to enable the hsusb 1p8\n");
Ivan T. Ivanov6b99c68e2014-04-28 16:34:08 +0300127 goto disable_3p3;
Anji jonnala11aa5c42011-05-04 10:19:48 +0530128 }
129
130 return 0;
131 }
132
Ivan T. Ivanov37cfdaf2014-04-28 16:34:06 +0300133 regulator_disable(motg->v1p8);
Anji jonnala11aa5c42011-05-04 10:19:48 +0530134disable_3p3:
Ivan T. Ivanov37cfdaf2014-04-28 16:34:06 +0300135 regulator_disable(motg->v3p3);
Ivan T. Ivanov6b99c68e2014-04-28 16:34:08 +0300136exit:
Anji jonnala11aa5c42011-05-04 10:19:48 +0530137 return rc;
138}
139
Ivan T. Ivanov37cfdaf2014-04-28 16:34:06 +0300140static int msm_hsusb_ldo_set_mode(struct msm_otg *motg, int on)
Anji jonnala11aa5c42011-05-04 10:19:48 +0530141{
142 int ret = 0;
143
Anji jonnala11aa5c42011-05-04 10:19:48 +0530144 if (on) {
Bjorn Anderssonfa53e352015-02-11 19:35:30 -0800145 ret = regulator_set_load(motg->v1p8, USB_PHY_1P8_HPM_LOAD);
Anji jonnala11aa5c42011-05-04 10:19:48 +0530146 if (ret < 0) {
Ivan T. Ivanov3aca0fa2014-04-28 16:34:10 +0300147 pr_err("Could not set HPM for v1p8\n");
Anji jonnala11aa5c42011-05-04 10:19:48 +0530148 return ret;
149 }
Bjorn Anderssonfa53e352015-02-11 19:35:30 -0800150 ret = regulator_set_load(motg->v3p3, USB_PHY_3P3_HPM_LOAD);
Anji jonnala11aa5c42011-05-04 10:19:48 +0530151 if (ret < 0) {
Ivan T. Ivanov3aca0fa2014-04-28 16:34:10 +0300152 pr_err("Could not set HPM for v3p3\n");
Bjorn Anderssonfa53e352015-02-11 19:35:30 -0800153 regulator_set_load(motg->v1p8, USB_PHY_1P8_LPM_LOAD);
Anji jonnala11aa5c42011-05-04 10:19:48 +0530154 return ret;
155 }
156 } else {
Bjorn Anderssonfa53e352015-02-11 19:35:30 -0800157 ret = regulator_set_load(motg->v1p8, USB_PHY_1P8_LPM_LOAD);
Anji jonnala11aa5c42011-05-04 10:19:48 +0530158 if (ret < 0)
Ivan T. Ivanov3aca0fa2014-04-28 16:34:10 +0300159 pr_err("Could not set LPM for v1p8\n");
Bjorn Anderssonfa53e352015-02-11 19:35:30 -0800160 ret = regulator_set_load(motg->v3p3, USB_PHY_3P3_LPM_LOAD);
Anji jonnala11aa5c42011-05-04 10:19:48 +0530161 if (ret < 0)
Ivan T. Ivanov3aca0fa2014-04-28 16:34:10 +0300162 pr_err("Could not set LPM for v3p3\n");
Anji jonnala11aa5c42011-05-04 10:19:48 +0530163 }
164
165 pr_debug("reg (%s)\n", on ? "HPM" : "LPM");
166 return ret < 0 ? ret : 0;
167}
168
Heikki Krogerus1d4c9292012-02-13 13:24:09 +0200169static int ulpi_read(struct usb_phy *phy, u32 reg)
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +0530170{
Heikki Krogerus1d4c9292012-02-13 13:24:09 +0200171 struct msm_otg *motg = container_of(phy, struct msm_otg, phy);
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +0530172 int cnt = 0;
173
174 /* initiate read operation */
175 writel(ULPI_RUN | ULPI_READ | ULPI_ADDR(reg),
176 USB_ULPI_VIEWPORT);
177
178 /* wait for completion */
179 while (cnt < ULPI_IO_TIMEOUT_USEC) {
180 if (!(readl(USB_ULPI_VIEWPORT) & ULPI_RUN))
181 break;
182 udelay(1);
183 cnt++;
184 }
185
186 if (cnt >= ULPI_IO_TIMEOUT_USEC) {
Heikki Krogerus1d4c9292012-02-13 13:24:09 +0200187 dev_err(phy->dev, "ulpi_read: timeout %08x\n",
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +0530188 readl(USB_ULPI_VIEWPORT));
189 return -ETIMEDOUT;
190 }
191 return ULPI_DATA_READ(readl(USB_ULPI_VIEWPORT));
192}
193
Heikki Krogerus1d4c9292012-02-13 13:24:09 +0200194static int ulpi_write(struct usb_phy *phy, u32 val, u32 reg)
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +0530195{
Heikki Krogerus1d4c9292012-02-13 13:24:09 +0200196 struct msm_otg *motg = container_of(phy, struct msm_otg, phy);
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +0530197 int cnt = 0;
198
199 /* initiate write operation */
200 writel(ULPI_RUN | ULPI_WRITE |
201 ULPI_ADDR(reg) | ULPI_DATA(val),
202 USB_ULPI_VIEWPORT);
203
204 /* wait for completion */
205 while (cnt < ULPI_IO_TIMEOUT_USEC) {
206 if (!(readl(USB_ULPI_VIEWPORT) & ULPI_RUN))
207 break;
208 udelay(1);
209 cnt++;
210 }
211
212 if (cnt >= ULPI_IO_TIMEOUT_USEC) {
Heikki Krogerus1d4c9292012-02-13 13:24:09 +0200213 dev_err(phy->dev, "ulpi_write: timeout\n");
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +0530214 return -ETIMEDOUT;
215 }
216 return 0;
217}
218
Heikki Krogerus1d4c9292012-02-13 13:24:09 +0200219static struct usb_phy_io_ops msm_otg_io_ops = {
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +0530220 .read = ulpi_read,
221 .write = ulpi_write,
222};
223
224static void ulpi_init(struct msm_otg *motg)
225{
226 struct msm_otg_platform_data *pdata = motg->pdata;
Ivan T. Ivanov8364f9a2014-04-28 16:34:15 +0300227 int *seq = pdata->phy_init_seq, idx;
228 u32 addr = ULPI_EXT_VENDOR_SPECIFIC;
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +0530229
Ivan T. Ivanov8364f9a2014-04-28 16:34:15 +0300230 for (idx = 0; idx < pdata->phy_init_sz; idx++) {
231 if (seq[idx] == -1)
232 continue;
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +0530233
Heikki Krogerus1d4c9292012-02-13 13:24:09 +0200234 dev_vdbg(motg->phy.dev, "ulpi: write 0x%02x to 0x%02x\n",
Ivan T. Ivanov8364f9a2014-04-28 16:34:15 +0300235 seq[idx], addr + idx);
236 ulpi_write(&motg->phy, seq[idx], addr + idx);
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +0530237 }
238}
239
Ivan T. Ivanov349907c2014-04-28 16:34:21 +0300240static int msm_phy_notify_disconnect(struct usb_phy *phy,
241 enum usb_device_speed speed)
242{
Ivan T. Ivanov44e42ae2015-04-09 11:34:33 +0300243 struct msm_otg *motg = container_of(phy, struct msm_otg, phy);
Ivan T. Ivanov349907c2014-04-28 16:34:21 +0300244 int val;
245
Ivan T. Ivanov44e42ae2015-04-09 11:34:33 +0300246 if (motg->manual_pullup) {
247 val = ULPI_MISC_A_VBUSVLDEXT | ULPI_MISC_A_VBUSVLDEXTSEL;
248 usb_phy_io_write(phy, val, ULPI_CLR(ULPI_MISC_A));
249 }
250
Ivan T. Ivanov349907c2014-04-28 16:34:21 +0300251 /*
252 * Put the transceiver in non-driving mode. Otherwise host
253 * may not detect soft-disconnection.
254 */
255 val = ulpi_read(phy, ULPI_FUNC_CTRL);
256 val &= ~ULPI_FUNC_CTRL_OPMODE_MASK;
257 val |= ULPI_FUNC_CTRL_OPMODE_NONDRIVING;
258 ulpi_write(phy, val, ULPI_FUNC_CTRL);
259
260 return 0;
261}
262
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +0530263static int msm_otg_link_clk_reset(struct msm_otg *motg, bool assert)
264{
Ivan T. Ivanova2734542014-04-28 16:34:16 +0300265 int ret;
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +0530266
Stephen Boyd32fc9eb2015-03-13 11:09:42 -0700267 if (assert)
Ivan T. Ivanova2734542014-04-28 16:34:16 +0300268 ret = reset_control_assert(motg->link_rst);
269 else
270 ret = reset_control_deassert(motg->link_rst);
Ivan T. Ivanov5146d772013-12-30 13:15:27 -0800271
Ivan T. Ivanov5146d772013-12-30 13:15:27 -0800272 if (ret)
273 dev_err(motg->phy.dev, "usb link clk reset %s failed\n",
274 assert ? "assert" : "deassert");
275
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +0530276 return ret;
277}
278
279static int msm_otg_phy_clk_reset(struct msm_otg *motg)
280{
Srinivas Kandagatlae44f1f42014-06-30 18:29:49 +0100281 int ret = 0;
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +0530282
Stephen Boyd32fc9eb2015-03-13 11:09:42 -0700283 if (motg->phy_rst)
Ivan T. Ivanova2734542014-04-28 16:34:16 +0300284 ret = reset_control_reset(motg->phy_rst);
Ivan T. Ivanov5146d772013-12-30 13:15:27 -0800285
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +0530286 if (ret)
Ivan T. Ivanov5146d772013-12-30 13:15:27 -0800287 dev_err(motg->phy.dev, "usb phy clk reset failed\n");
288
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +0530289 return ret;
290}
291
Ivan T. Ivanovd69c6f52014-04-28 16:34:18 +0300292static int msm_link_reset(struct msm_otg *motg)
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +0530293{
294 u32 val;
295 int ret;
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +0530296
297 ret = msm_otg_link_clk_reset(motg, 1);
298 if (ret)
299 return ret;
Ivan T. Ivanovd69c6f52014-04-28 16:34:18 +0300300
301 /* wait for 1ms delay as suggested in HPG. */
302 usleep_range(1000, 1200);
303
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +0530304 ret = msm_otg_link_clk_reset(motg, 0);
305 if (ret)
306 return ret;
307
Ivan T. Ivanovcfa3ff52014-04-28 16:34:17 +0300308 if (motg->phy_number)
309 writel(readl(USB_PHY_CTRL2) | BIT(16), USB_PHY_CTRL2);
310
Tim Bird9f27984b2014-04-28 16:34:19 +0300311 /* put transceiver in serial mode as part of reset */
Ivan T. Ivanovd69c6f52014-04-28 16:34:18 +0300312 val = readl(USB_PORTSC) & ~PORTSC_PTS_MASK;
Tim Bird9f27984b2014-04-28 16:34:19 +0300313 writel(val | PORTSC_PTS_SERIAL, USB_PORTSC);
Ivan T. Ivanovd69c6f52014-04-28 16:34:18 +0300314
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +0530315 return 0;
316}
317
Heikki Krogerus1d4c9292012-02-13 13:24:09 +0200318static int msm_otg_reset(struct usb_phy *phy)
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +0530319{
Heikki Krogerus1d4c9292012-02-13 13:24:09 +0200320 struct msm_otg *motg = container_of(phy, struct msm_otg, phy);
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +0530321 int cnt = 0;
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +0530322
323 writel(USBCMD_RESET, USB_USBCMD);
324 while (cnt < LINK_RESET_TIMEOUT_USEC) {
325 if (!(readl(USB_USBCMD) & USBCMD_RESET))
326 break;
327 udelay(1);
328 cnt++;
329 }
330 if (cnt >= LINK_RESET_TIMEOUT_USEC)
331 return -ETIMEDOUT;
332
Tim Bird9f27984b2014-04-28 16:34:19 +0300333 /* select ULPI phy and clear other status/control bits in PORTSC */
334 writel(PORTSC_PTS_ULPI, USB_PORTSC);
335
Ivan T. Ivanovd69c6f52014-04-28 16:34:18 +0300336 writel(0x0, USB_AHBBURST);
337 writel(0x08, USB_AHBMODE);
338
339 if (motg->phy_number)
340 writel(readl(USB_PHY_CTRL2) | BIT(16), USB_PHY_CTRL2);
341 return 0;
342}
343
344static void msm_phy_reset(struct msm_otg *motg)
345{
346 void __iomem *addr;
347
348 if (motg->pdata->phy_type != SNPS_28NM_INTEGRATED_PHY) {
349 msm_otg_phy_clk_reset(motg);
350 return;
351 }
352
353 addr = USB_PHY_CTRL;
354 if (motg->phy_number)
355 addr = USB_PHY_CTRL2;
356
357 /* Assert USB PHY_POR */
358 writel(readl(addr) | PHY_POR_ASSERT, addr);
359
360 /*
361 * wait for minimum 10 microseconds as suggested in HPG.
362 * Use a slightly larger value since the exact value didn't
363 * work 100% of the time.
364 */
365 udelay(12);
366
367 /* Deassert USB PHY_POR */
368 writel(readl(addr) & ~PHY_POR_ASSERT, addr);
369}
370
371static int msm_usb_reset(struct usb_phy *phy)
372{
373 struct msm_otg *motg = container_of(phy, struct msm_otg, phy);
374 int ret;
375
376 if (!IS_ERR(motg->core_clk))
377 clk_prepare_enable(motg->core_clk);
378
379 ret = msm_link_reset(motg);
380 if (ret) {
381 dev_err(phy->dev, "phy_reset failed\n");
382 return ret;
383 }
384
385 ret = msm_otg_reset(&motg->phy);
386 if (ret) {
387 dev_err(phy->dev, "link reset failed\n");
388 return ret;
389 }
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +0530390
391 msleep(100);
392
Ivan T. Ivanovd69c6f52014-04-28 16:34:18 +0300393 /* Reset USB PHY after performing USB Link RESET */
394 msm_phy_reset(motg);
395
396 if (!IS_ERR(motg->core_clk))
397 clk_disable_unprepare(motg->core_clk);
398
399 return 0;
400}
401
402static int msm_phy_init(struct usb_phy *phy)
403{
404 struct msm_otg *motg = container_of(phy, struct msm_otg, phy);
405 struct msm_otg_platform_data *pdata = motg->pdata;
406 u32 val, ulpi_val = 0;
407
408 /* Program USB PHY Override registers. */
409 ulpi_init(motg);
410
411 /*
412 * It is recommended in HPG to reset USB PHY after programming
413 * USB PHY Override registers.
414 */
415 msm_phy_reset(motg);
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +0530416
417 if (pdata->otg_control == OTG_PHY_CONTROL) {
418 val = readl(USB_OTGSC);
Ivan T. Ivanov971232c2014-04-28 16:34:11 +0300419 if (pdata->mode == USB_DR_MODE_OTG) {
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +0530420 ulpi_val = ULPI_INT_IDGRD | ULPI_INT_SESS_VALID;
421 val |= OTGSC_IDIE | OTGSC_BSVIE;
Ivan T. Ivanov971232c2014-04-28 16:34:11 +0300422 } else if (pdata->mode == USB_DR_MODE_PERIPHERAL) {
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +0530423 ulpi_val = ULPI_INT_SESS_VALID;
424 val |= OTGSC_BSVIE;
425 }
426 writel(val, USB_OTGSC);
Heikki Krogerus1d4c9292012-02-13 13:24:09 +0200427 ulpi_write(phy, ulpi_val, ULPI_USB_INT_EN_RISE);
428 ulpi_write(phy, ulpi_val, ULPI_USB_INT_EN_FALL);
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +0530429 }
430
Ivan T. Ivanov44e42ae2015-04-09 11:34:33 +0300431 if (motg->manual_pullup) {
432 val = ULPI_MISC_A_VBUSVLDEXTSEL | ULPI_MISC_A_VBUSVLDEXT;
433 ulpi_write(phy, val, ULPI_SET(ULPI_MISC_A));
434
435 val = readl(USB_GENCONFIG_2);
436 val |= GENCONFIG_2_SESS_VLD_CTRL_EN;
437 writel(val, USB_GENCONFIG_2);
438
439 val = readl(USB_USBCMD);
440 val |= USBCMD_SESS_VLD_CTRL;
441 writel(val, USB_USBCMD);
442
443 val = ulpi_read(phy, ULPI_FUNC_CTRL);
444 val &= ~ULPI_FUNC_CTRL_OPMODE_MASK;
445 val |= ULPI_FUNC_CTRL_OPMODE_NORMAL;
446 ulpi_write(phy, val, ULPI_FUNC_CTRL);
447 }
448
Ivan T. Ivanovcfa3ff52014-04-28 16:34:17 +0300449 if (motg->phy_number)
450 writel(readl(USB_PHY_CTRL2) | BIT(16), USB_PHY_CTRL2);
451
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +0530452 return 0;
453}
454
Pavankumar Kondeti87c01042010-12-07 17:53:58 +0530455#define PHY_SUSPEND_TIMEOUT_USEC (500 * 1000)
Pavankumar Kondeti70187732011-02-15 09:42:34 +0530456#define PHY_RESUME_TIMEOUT_USEC (100 * 1000)
457
Josh Cartwrighte7d613d2014-02-18 10:36:29 -0600458#ifdef CONFIG_PM
459
Ivan T. Ivanov37cfdaf2014-04-28 16:34:06 +0300460static int msm_hsusb_config_vddcx(struct msm_otg *motg, int high)
Josh Cartwrighte7d613d2014-02-18 10:36:29 -0600461{
Ivan T. Ivanov01799b62014-04-28 16:34:22 +0300462 int max_vol = motg->vdd_levels[VDD_LEVEL_MAX];
Josh Cartwrighte7d613d2014-02-18 10:36:29 -0600463 int min_vol;
464 int ret;
465
466 if (high)
Ivan T. Ivanov01799b62014-04-28 16:34:22 +0300467 min_vol = motg->vdd_levels[VDD_LEVEL_MIN];
Josh Cartwrighte7d613d2014-02-18 10:36:29 -0600468 else
Ivan T. Ivanov01799b62014-04-28 16:34:22 +0300469 min_vol = motg->vdd_levels[VDD_LEVEL_NONE];
Josh Cartwrighte7d613d2014-02-18 10:36:29 -0600470
Ivan T. Ivanov37cfdaf2014-04-28 16:34:06 +0300471 ret = regulator_set_voltage(motg->vddcx, min_vol, max_vol);
Josh Cartwrighte7d613d2014-02-18 10:36:29 -0600472 if (ret) {
Ivan T. Ivanov3aca0fa2014-04-28 16:34:10 +0300473 pr_err("Cannot set vddcx voltage\n");
Josh Cartwrighte7d613d2014-02-18 10:36:29 -0600474 return ret;
475 }
476
477 pr_debug("%s: min_vol:%d max_vol:%d\n", __func__, min_vol, max_vol);
478
479 return ret;
480}
481
Pavankumar Kondeti87c01042010-12-07 17:53:58 +0530482static int msm_otg_suspend(struct msm_otg *motg)
483{
Heikki Krogerus1d4c9292012-02-13 13:24:09 +0200484 struct usb_phy *phy = &motg->phy;
485 struct usb_bus *bus = phy->otg->host;
Pavankumar Kondeti87c01042010-12-07 17:53:58 +0530486 struct msm_otg_platform_data *pdata = motg->pdata;
Ivan T. Ivanovcfa3ff52014-04-28 16:34:17 +0300487 void __iomem *addr;
Pavankumar Kondeti87c01042010-12-07 17:53:58 +0530488 int cnt = 0;
489
490 if (atomic_read(&motg->in_lpm))
491 return 0;
492
493 disable_irq(motg->irq);
494 /*
Pavankumar Kondeti04aebcb2011-05-04 10:19:49 +0530495 * Chipidea 45-nm PHY suspend sequence:
496 *
Pavankumar Kondeti87c01042010-12-07 17:53:58 +0530497 * Interrupt Latch Register auto-clear feature is not present
498 * in all PHY versions. Latch register is clear on read type.
499 * Clear latch register to avoid spurious wakeup from
500 * low power mode (LPM).
Pavankumar Kondeti04aebcb2011-05-04 10:19:49 +0530501 *
Pavankumar Kondeti87c01042010-12-07 17:53:58 +0530502 * PHY comparators are disabled when PHY enters into low power
503 * mode (LPM). Keep PHY comparators ON in LPM only when we expect
504 * VBUS/Id notifications from USB PHY. Otherwise turn off USB
505 * PHY comparators. This save significant amount of power.
Pavankumar Kondeti04aebcb2011-05-04 10:19:49 +0530506 *
Pavankumar Kondeti87c01042010-12-07 17:53:58 +0530507 * PLL is not turned off when PHY enters into low power mode (LPM).
508 * Disable PLL for maximum power savings.
509 */
Pavankumar Kondeti04aebcb2011-05-04 10:19:49 +0530510
511 if (motg->pdata->phy_type == CI_45NM_INTEGRATED_PHY) {
Heikki Krogerus1d4c9292012-02-13 13:24:09 +0200512 ulpi_read(phy, 0x14);
Pavankumar Kondeti04aebcb2011-05-04 10:19:49 +0530513 if (pdata->otg_control == OTG_PHY_CONTROL)
Heikki Krogerus1d4c9292012-02-13 13:24:09 +0200514 ulpi_write(phy, 0x01, 0x30);
515 ulpi_write(phy, 0x08, 0x09);
Pavankumar Kondeti04aebcb2011-05-04 10:19:49 +0530516 }
Pavankumar Kondeti87c01042010-12-07 17:53:58 +0530517
518 /*
519 * PHY may take some time or even fail to enter into low power
520 * mode (LPM). Hence poll for 500 msec and reset the PHY and link
521 * in failure case.
522 */
523 writel(readl(USB_PORTSC) | PORTSC_PHCD, USB_PORTSC);
524 while (cnt < PHY_SUSPEND_TIMEOUT_USEC) {
525 if (readl(USB_PORTSC) & PORTSC_PHCD)
526 break;
527 udelay(1);
528 cnt++;
529 }
530
531 if (cnt >= PHY_SUSPEND_TIMEOUT_USEC) {
Heikki Krogerus1d4c9292012-02-13 13:24:09 +0200532 dev_err(phy->dev, "Unable to suspend PHY\n");
533 msm_otg_reset(phy);
Pavankumar Kondeti87c01042010-12-07 17:53:58 +0530534 enable_irq(motg->irq);
535 return -ETIMEDOUT;
536 }
537
538 /*
539 * PHY has capability to generate interrupt asynchronously in low
540 * power mode (LPM). This interrupt is level triggered. So USB IRQ
541 * line must be disabled till async interrupt enable bit is cleared
542 * in USBCMD register. Assert STP (ULPI interface STOP signal) to
543 * block data communication from PHY.
544 */
545 writel(readl(USB_USBCMD) | ASYNC_INTR_CTRL | ULPI_STP_CTRL, USB_USBCMD);
546
Ivan T. Ivanovcfa3ff52014-04-28 16:34:17 +0300547 addr = USB_PHY_CTRL;
548 if (motg->phy_number)
549 addr = USB_PHY_CTRL2;
550
Pavankumar Kondeti04aebcb2011-05-04 10:19:49 +0530551 if (motg->pdata->phy_type == SNPS_28NM_INTEGRATED_PHY &&
552 motg->pdata->otg_control == OTG_PMIC_CONTROL)
Ivan T. Ivanovcfa3ff52014-04-28 16:34:17 +0300553 writel(readl(addr) | PHY_RETEN, addr);
Pavankumar Kondeti04aebcb2011-05-04 10:19:49 +0530554
Stephen Boydb99a8f62013-06-17 10:43:10 -0700555 clk_disable_unprepare(motg->pclk);
556 clk_disable_unprepare(motg->clk);
Ivan T. Ivanov6b99c68e2014-04-28 16:34:08 +0300557 if (!IS_ERR(motg->core_clk))
Stephen Boydb99a8f62013-06-17 10:43:10 -0700558 clk_disable_unprepare(motg->core_clk);
Pavankumar Kondeti87c01042010-12-07 17:53:58 +0530559
Pavankumar Kondeti04aebcb2011-05-04 10:19:49 +0530560 if (motg->pdata->phy_type == SNPS_28NM_INTEGRATED_PHY &&
561 motg->pdata->otg_control == OTG_PMIC_CONTROL) {
Ivan T. Ivanov37cfdaf2014-04-28 16:34:06 +0300562 msm_hsusb_ldo_set_mode(motg, 0);
563 msm_hsusb_config_vddcx(motg, 0);
Pavankumar Kondeti04aebcb2011-05-04 10:19:49 +0530564 }
565
Heikki Krogerus1d4c9292012-02-13 13:24:09 +0200566 if (device_may_wakeup(phy->dev))
Pavankumar Kondeti87c01042010-12-07 17:53:58 +0530567 enable_irq_wake(motg->irq);
568 if (bus)
569 clear_bit(HCD_FLAG_HW_ACCESSIBLE, &(bus_to_hcd(bus))->flags);
570
571 atomic_set(&motg->in_lpm, 1);
572 enable_irq(motg->irq);
573
Heikki Krogerus1d4c9292012-02-13 13:24:09 +0200574 dev_info(phy->dev, "USB in low power mode\n");
Pavankumar Kondeti87c01042010-12-07 17:53:58 +0530575
576 return 0;
577}
578
Pavankumar Kondeti87c01042010-12-07 17:53:58 +0530579static int msm_otg_resume(struct msm_otg *motg)
580{
Heikki Krogerus1d4c9292012-02-13 13:24:09 +0200581 struct usb_phy *phy = &motg->phy;
582 struct usb_bus *bus = phy->otg->host;
Ivan T. Ivanovcfa3ff52014-04-28 16:34:17 +0300583 void __iomem *addr;
Pavankumar Kondeti87c01042010-12-07 17:53:58 +0530584 int cnt = 0;
585 unsigned temp;
586
587 if (!atomic_read(&motg->in_lpm))
588 return 0;
589
Stephen Boydb99a8f62013-06-17 10:43:10 -0700590 clk_prepare_enable(motg->pclk);
591 clk_prepare_enable(motg->clk);
Ivan T. Ivanov6b99c68e2014-04-28 16:34:08 +0300592 if (!IS_ERR(motg->core_clk))
Stephen Boydb99a8f62013-06-17 10:43:10 -0700593 clk_prepare_enable(motg->core_clk);
Pavankumar Kondeti87c01042010-12-07 17:53:58 +0530594
Pavankumar Kondeti04aebcb2011-05-04 10:19:49 +0530595 if (motg->pdata->phy_type == SNPS_28NM_INTEGRATED_PHY &&
596 motg->pdata->otg_control == OTG_PMIC_CONTROL) {
Ivan T. Ivanovcfa3ff52014-04-28 16:34:17 +0300597
598 addr = USB_PHY_CTRL;
599 if (motg->phy_number)
600 addr = USB_PHY_CTRL2;
601
Ivan T. Ivanov37cfdaf2014-04-28 16:34:06 +0300602 msm_hsusb_ldo_set_mode(motg, 1);
603 msm_hsusb_config_vddcx(motg, 1);
Ivan T. Ivanovcfa3ff52014-04-28 16:34:17 +0300604 writel(readl(addr) & ~PHY_RETEN, addr);
Pavankumar Kondeti04aebcb2011-05-04 10:19:49 +0530605 }
606
Pavankumar Kondeti87c01042010-12-07 17:53:58 +0530607 temp = readl(USB_USBCMD);
608 temp &= ~ASYNC_INTR_CTRL;
609 temp &= ~ULPI_STP_CTRL;
610 writel(temp, USB_USBCMD);
611
612 /*
613 * PHY comes out of low power mode (LPM) in case of wakeup
614 * from asynchronous interrupt.
615 */
616 if (!(readl(USB_PORTSC) & PORTSC_PHCD))
617 goto skip_phy_resume;
618
619 writel(readl(USB_PORTSC) & ~PORTSC_PHCD, USB_PORTSC);
620 while (cnt < PHY_RESUME_TIMEOUT_USEC) {
621 if (!(readl(USB_PORTSC) & PORTSC_PHCD))
622 break;
623 udelay(1);
624 cnt++;
625 }
626
627 if (cnt >= PHY_RESUME_TIMEOUT_USEC) {
628 /*
629 * This is a fatal error. Reset the link and
630 * PHY. USB state can not be restored. Re-insertion
631 * of USB cable is the only way to get USB working.
632 */
Ivan T. Ivanov3aca0fa2014-04-28 16:34:10 +0300633 dev_err(phy->dev, "Unable to resume USB. Re-plugin the cable\n");
Heikki Krogerus1d4c9292012-02-13 13:24:09 +0200634 msm_otg_reset(phy);
Pavankumar Kondeti87c01042010-12-07 17:53:58 +0530635 }
636
637skip_phy_resume:
Heikki Krogerus1d4c9292012-02-13 13:24:09 +0200638 if (device_may_wakeup(phy->dev))
Pavankumar Kondeti87c01042010-12-07 17:53:58 +0530639 disable_irq_wake(motg->irq);
640 if (bus)
641 set_bit(HCD_FLAG_HW_ACCESSIBLE, &(bus_to_hcd(bus))->flags);
642
Pavankumar Kondeti2ce2c3a2011-05-02 11:56:33 +0530643 atomic_set(&motg->in_lpm, 0);
644
Pavankumar Kondeti87c01042010-12-07 17:53:58 +0530645 if (motg->async_int) {
646 motg->async_int = 0;
Heikki Krogerus1d4c9292012-02-13 13:24:09 +0200647 pm_runtime_put(phy->dev);
Pavankumar Kondeti87c01042010-12-07 17:53:58 +0530648 enable_irq(motg->irq);
649 }
650
Heikki Krogerus1d4c9292012-02-13 13:24:09 +0200651 dev_info(phy->dev, "USB exited from low power mode\n");
Pavankumar Kondeti87c01042010-12-07 17:53:58 +0530652
653 return 0;
654}
Pavankumar Kondeti70187732011-02-15 09:42:34 +0530655#endif
Pavankumar Kondeti87c01042010-12-07 17:53:58 +0530656
Pavankumar Kondetid8608522011-05-04 10:19:47 +0530657static void msm_otg_notify_charger(struct msm_otg *motg, unsigned mA)
658{
659 if (motg->cur_power == mA)
660 return;
661
662 /* TODO: Notify PMIC about available current */
Heikki Krogerus1d4c9292012-02-13 13:24:09 +0200663 dev_info(motg->phy.dev, "Avail curr from USB = %u\n", mA);
Pavankumar Kondetid8608522011-05-04 10:19:47 +0530664 motg->cur_power = mA;
665}
666
Heikki Krogerus1d4c9292012-02-13 13:24:09 +0200667static int msm_otg_set_power(struct usb_phy *phy, unsigned mA)
Pavankumar Kondetid8608522011-05-04 10:19:47 +0530668{
Heikki Krogerus1d4c9292012-02-13 13:24:09 +0200669 struct msm_otg *motg = container_of(phy, struct msm_otg, phy);
Pavankumar Kondetid8608522011-05-04 10:19:47 +0530670
671 /*
672 * Gadget driver uses set_power method to notify about the
673 * available current based on suspend/configured states.
674 *
675 * IDEV_CHG can be drawn irrespective of suspend/un-configured
676 * states when CDP/ACA is connected.
677 */
678 if (motg->chg_type == USB_SDP_CHARGER)
679 msm_otg_notify_charger(motg, mA);
680
681 return 0;
682}
683
Heikki Krogerus1d4c9292012-02-13 13:24:09 +0200684static void msm_otg_start_host(struct usb_phy *phy, int on)
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +0530685{
Heikki Krogerus1d4c9292012-02-13 13:24:09 +0200686 struct msm_otg *motg = container_of(phy, struct msm_otg, phy);
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +0530687 struct msm_otg_platform_data *pdata = motg->pdata;
688 struct usb_hcd *hcd;
689
Heikki Krogerus1d4c9292012-02-13 13:24:09 +0200690 if (!phy->otg->host)
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +0530691 return;
692
Heikki Krogerus1d4c9292012-02-13 13:24:09 +0200693 hcd = bus_to_hcd(phy->otg->host);
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +0530694
695 if (on) {
Heikki Krogerus1d4c9292012-02-13 13:24:09 +0200696 dev_dbg(phy->dev, "host on\n");
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +0530697
698 if (pdata->vbus_power)
699 pdata->vbus_power(1);
700 /*
701 * Some boards have a switch cotrolled by gpio
702 * to enable/disable internal HUB. Enable internal
703 * HUB before kicking the host.
704 */
705 if (pdata->setup_gpio)
706 pdata->setup_gpio(OTG_STATE_A_HOST);
707#ifdef CONFIG_USB
708 usb_add_hcd(hcd, hcd->irq, IRQF_SHARED);
Peter Chen3c9740a2013-11-05 10:46:02 +0800709 device_wakeup_enable(hcd->self.controller);
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +0530710#endif
711 } else {
Heikki Krogerus1d4c9292012-02-13 13:24:09 +0200712 dev_dbg(phy->dev, "host off\n");
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +0530713
714#ifdef CONFIG_USB
715 usb_remove_hcd(hcd);
716#endif
717 if (pdata->setup_gpio)
718 pdata->setup_gpio(OTG_STATE_UNDEFINED);
719 if (pdata->vbus_power)
720 pdata->vbus_power(0);
721 }
722}
723
Heikki Krogerus1d4c9292012-02-13 13:24:09 +0200724static int msm_otg_set_host(struct usb_otg *otg, struct usb_bus *host)
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +0530725{
Antoine Tenart19c1eac2014-10-30 18:41:14 +0100726 struct msm_otg *motg = container_of(otg->usb_phy, struct msm_otg, phy);
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +0530727 struct usb_hcd *hcd;
728
729 /*
730 * Fail host registration if this board can support
731 * only peripheral configuration.
732 */
Ivan T. Ivanov971232c2014-04-28 16:34:11 +0300733 if (motg->pdata->mode == USB_DR_MODE_PERIPHERAL) {
Antoine Tenart19c1eac2014-10-30 18:41:14 +0100734 dev_info(otg->usb_phy->dev, "Host mode is not supported\n");
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +0530735 return -ENODEV;
736 }
737
738 if (!host) {
Antoine Tenarte47d9252014-10-30 18:41:13 +0100739 if (otg->state == OTG_STATE_A_HOST) {
Antoine Tenart19c1eac2014-10-30 18:41:14 +0100740 pm_runtime_get_sync(otg->usb_phy->dev);
741 msm_otg_start_host(otg->usb_phy, 0);
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +0530742 otg->host = NULL;
Antoine Tenarte47d9252014-10-30 18:41:13 +0100743 otg->state = OTG_STATE_UNDEFINED;
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +0530744 schedule_work(&motg->sm_work);
745 } else {
746 otg->host = NULL;
747 }
748
749 return 0;
750 }
751
752 hcd = bus_to_hcd(host);
753 hcd->power_budget = motg->pdata->power_budget;
754
755 otg->host = host;
Antoine Tenart19c1eac2014-10-30 18:41:14 +0100756 dev_dbg(otg->usb_phy->dev, "host driver registered w/ tranceiver\n");
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +0530757
758 /*
759 * Kick the state machine work, if peripheral is not supported
760 * or peripheral is already registered with us.
761 */
Ivan T. Ivanov971232c2014-04-28 16:34:11 +0300762 if (motg->pdata->mode == USB_DR_MODE_HOST || otg->gadget) {
Antoine Tenart19c1eac2014-10-30 18:41:14 +0100763 pm_runtime_get_sync(otg->usb_phy->dev);
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +0530764 schedule_work(&motg->sm_work);
Pavankumar Kondeti87c01042010-12-07 17:53:58 +0530765 }
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +0530766
767 return 0;
768}
769
Heikki Krogerus1d4c9292012-02-13 13:24:09 +0200770static void msm_otg_start_peripheral(struct usb_phy *phy, int on)
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +0530771{
Heikki Krogerus1d4c9292012-02-13 13:24:09 +0200772 struct msm_otg *motg = container_of(phy, struct msm_otg, phy);
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +0530773 struct msm_otg_platform_data *pdata = motg->pdata;
774
Heikki Krogerus1d4c9292012-02-13 13:24:09 +0200775 if (!phy->otg->gadget)
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +0530776 return;
777
778 if (on) {
Heikki Krogerus1d4c9292012-02-13 13:24:09 +0200779 dev_dbg(phy->dev, "gadget on\n");
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +0530780 /*
781 * Some boards have a switch cotrolled by gpio
782 * to enable/disable internal HUB. Disable internal
783 * HUB before kicking the gadget.
784 */
785 if (pdata->setup_gpio)
786 pdata->setup_gpio(OTG_STATE_B_PERIPHERAL);
Heikki Krogerus1d4c9292012-02-13 13:24:09 +0200787 usb_gadget_vbus_connect(phy->otg->gadget);
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +0530788 } else {
Heikki Krogerus1d4c9292012-02-13 13:24:09 +0200789 dev_dbg(phy->dev, "gadget off\n");
790 usb_gadget_vbus_disconnect(phy->otg->gadget);
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +0530791 if (pdata->setup_gpio)
792 pdata->setup_gpio(OTG_STATE_UNDEFINED);
793 }
794
795}
796
Heikki Krogerus1d4c9292012-02-13 13:24:09 +0200797static int msm_otg_set_peripheral(struct usb_otg *otg,
798 struct usb_gadget *gadget)
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +0530799{
Antoine Tenart19c1eac2014-10-30 18:41:14 +0100800 struct msm_otg *motg = container_of(otg->usb_phy, struct msm_otg, phy);
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +0530801
802 /*
803 * Fail peripheral registration if this board can support
804 * only host configuration.
805 */
Ivan T. Ivanov971232c2014-04-28 16:34:11 +0300806 if (motg->pdata->mode == USB_DR_MODE_HOST) {
Antoine Tenart19c1eac2014-10-30 18:41:14 +0100807 dev_info(otg->usb_phy->dev, "Peripheral mode is not supported\n");
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +0530808 return -ENODEV;
809 }
810
811 if (!gadget) {
Antoine Tenarte47d9252014-10-30 18:41:13 +0100812 if (otg->state == OTG_STATE_B_PERIPHERAL) {
Antoine Tenart19c1eac2014-10-30 18:41:14 +0100813 pm_runtime_get_sync(otg->usb_phy->dev);
814 msm_otg_start_peripheral(otg->usb_phy, 0);
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +0530815 otg->gadget = NULL;
Antoine Tenarte47d9252014-10-30 18:41:13 +0100816 otg->state = OTG_STATE_UNDEFINED;
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +0530817 schedule_work(&motg->sm_work);
818 } else {
819 otg->gadget = NULL;
820 }
821
822 return 0;
823 }
824 otg->gadget = gadget;
Antoine Tenart19c1eac2014-10-30 18:41:14 +0100825 dev_dbg(otg->usb_phy->dev,
826 "peripheral driver registered w/ tranceiver\n");
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +0530827
828 /*
829 * Kick the state machine work, if host is not supported
830 * or host is already registered with us.
831 */
Ivan T. Ivanov971232c2014-04-28 16:34:11 +0300832 if (motg->pdata->mode == USB_DR_MODE_PERIPHERAL || otg->host) {
Antoine Tenart19c1eac2014-10-30 18:41:14 +0100833 pm_runtime_get_sync(otg->usb_phy->dev);
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +0530834 schedule_work(&motg->sm_work);
Pavankumar Kondeti87c01042010-12-07 17:53:58 +0530835 }
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +0530836
837 return 0;
838}
839
Pavankumar Kondetid8608522011-05-04 10:19:47 +0530840static bool msm_chg_check_secondary_det(struct msm_otg *motg)
841{
Heikki Krogerus1d4c9292012-02-13 13:24:09 +0200842 struct usb_phy *phy = &motg->phy;
Pavankumar Kondetid8608522011-05-04 10:19:47 +0530843 u32 chg_det;
844 bool ret = false;
845
846 switch (motg->pdata->phy_type) {
847 case CI_45NM_INTEGRATED_PHY:
Heikki Krogerus1d4c9292012-02-13 13:24:09 +0200848 chg_det = ulpi_read(phy, 0x34);
Pavankumar Kondetid8608522011-05-04 10:19:47 +0530849 ret = chg_det & (1 << 4);
850 break;
851 case SNPS_28NM_INTEGRATED_PHY:
Heikki Krogerus1d4c9292012-02-13 13:24:09 +0200852 chg_det = ulpi_read(phy, 0x87);
Pavankumar Kondetid8608522011-05-04 10:19:47 +0530853 ret = chg_det & 1;
854 break;
855 default:
856 break;
857 }
858 return ret;
859}
860
861static void msm_chg_enable_secondary_det(struct msm_otg *motg)
862{
Heikki Krogerus1d4c9292012-02-13 13:24:09 +0200863 struct usb_phy *phy = &motg->phy;
Pavankumar Kondetid8608522011-05-04 10:19:47 +0530864 u32 chg_det;
865
866 switch (motg->pdata->phy_type) {
867 case CI_45NM_INTEGRATED_PHY:
Heikki Krogerus1d4c9292012-02-13 13:24:09 +0200868 chg_det = ulpi_read(phy, 0x34);
Pavankumar Kondetid8608522011-05-04 10:19:47 +0530869 /* Turn off charger block */
870 chg_det |= ~(1 << 1);
Heikki Krogerus1d4c9292012-02-13 13:24:09 +0200871 ulpi_write(phy, chg_det, 0x34);
Pavankumar Kondetid8608522011-05-04 10:19:47 +0530872 udelay(20);
873 /* control chg block via ULPI */
874 chg_det &= ~(1 << 3);
Heikki Krogerus1d4c9292012-02-13 13:24:09 +0200875 ulpi_write(phy, chg_det, 0x34);
Pavankumar Kondetid8608522011-05-04 10:19:47 +0530876 /* put it in host mode for enabling D- source */
877 chg_det &= ~(1 << 2);
Heikki Krogerus1d4c9292012-02-13 13:24:09 +0200878 ulpi_write(phy, chg_det, 0x34);
Pavankumar Kondetid8608522011-05-04 10:19:47 +0530879 /* Turn on chg detect block */
880 chg_det &= ~(1 << 1);
Heikki Krogerus1d4c9292012-02-13 13:24:09 +0200881 ulpi_write(phy, chg_det, 0x34);
Pavankumar Kondetid8608522011-05-04 10:19:47 +0530882 udelay(20);
883 /* enable chg detection */
884 chg_det &= ~(1 << 0);
Heikki Krogerus1d4c9292012-02-13 13:24:09 +0200885 ulpi_write(phy, chg_det, 0x34);
Pavankumar Kondetid8608522011-05-04 10:19:47 +0530886 break;
887 case SNPS_28NM_INTEGRATED_PHY:
888 /*
889 * Configure DM as current source, DP as current sink
890 * and enable battery charging comparators.
891 */
Heikki Krogerus1d4c9292012-02-13 13:24:09 +0200892 ulpi_write(phy, 0x8, 0x85);
893 ulpi_write(phy, 0x2, 0x85);
894 ulpi_write(phy, 0x1, 0x85);
Pavankumar Kondetid8608522011-05-04 10:19:47 +0530895 break;
896 default:
897 break;
898 }
899}
900
901static bool msm_chg_check_primary_det(struct msm_otg *motg)
902{
Heikki Krogerus1d4c9292012-02-13 13:24:09 +0200903 struct usb_phy *phy = &motg->phy;
Pavankumar Kondetid8608522011-05-04 10:19:47 +0530904 u32 chg_det;
905 bool ret = false;
906
907 switch (motg->pdata->phy_type) {
908 case CI_45NM_INTEGRATED_PHY:
Heikki Krogerus1d4c9292012-02-13 13:24:09 +0200909 chg_det = ulpi_read(phy, 0x34);
Pavankumar Kondetid8608522011-05-04 10:19:47 +0530910 ret = chg_det & (1 << 4);
911 break;
912 case SNPS_28NM_INTEGRATED_PHY:
Heikki Krogerus1d4c9292012-02-13 13:24:09 +0200913 chg_det = ulpi_read(phy, 0x87);
Pavankumar Kondetid8608522011-05-04 10:19:47 +0530914 ret = chg_det & 1;
915 break;
916 default:
917 break;
918 }
919 return ret;
920}
921
922static void msm_chg_enable_primary_det(struct msm_otg *motg)
923{
Heikki Krogerus1d4c9292012-02-13 13:24:09 +0200924 struct usb_phy *phy = &motg->phy;
Pavankumar Kondetid8608522011-05-04 10:19:47 +0530925 u32 chg_det;
926
927 switch (motg->pdata->phy_type) {
928 case CI_45NM_INTEGRATED_PHY:
Heikki Krogerus1d4c9292012-02-13 13:24:09 +0200929 chg_det = ulpi_read(phy, 0x34);
Pavankumar Kondetid8608522011-05-04 10:19:47 +0530930 /* enable chg detection */
931 chg_det &= ~(1 << 0);
Heikki Krogerus1d4c9292012-02-13 13:24:09 +0200932 ulpi_write(phy, chg_det, 0x34);
Pavankumar Kondetid8608522011-05-04 10:19:47 +0530933 break;
934 case SNPS_28NM_INTEGRATED_PHY:
935 /*
936 * Configure DP as current source, DM as current sink
937 * and enable battery charging comparators.
938 */
Heikki Krogerus1d4c9292012-02-13 13:24:09 +0200939 ulpi_write(phy, 0x2, 0x85);
940 ulpi_write(phy, 0x1, 0x85);
Pavankumar Kondetid8608522011-05-04 10:19:47 +0530941 break;
942 default:
943 break;
944 }
945}
946
947static bool msm_chg_check_dcd(struct msm_otg *motg)
948{
Heikki Krogerus1d4c9292012-02-13 13:24:09 +0200949 struct usb_phy *phy = &motg->phy;
Pavankumar Kondetid8608522011-05-04 10:19:47 +0530950 u32 line_state;
951 bool ret = false;
952
953 switch (motg->pdata->phy_type) {
954 case CI_45NM_INTEGRATED_PHY:
Heikki Krogerus1d4c9292012-02-13 13:24:09 +0200955 line_state = ulpi_read(phy, 0x15);
Pavankumar Kondetid8608522011-05-04 10:19:47 +0530956 ret = !(line_state & 1);
957 break;
958 case SNPS_28NM_INTEGRATED_PHY:
Heikki Krogerus1d4c9292012-02-13 13:24:09 +0200959 line_state = ulpi_read(phy, 0x87);
Pavankumar Kondetid8608522011-05-04 10:19:47 +0530960 ret = line_state & 2;
961 break;
962 default:
963 break;
964 }
965 return ret;
966}
967
968static void msm_chg_disable_dcd(struct msm_otg *motg)
969{
Heikki Krogerus1d4c9292012-02-13 13:24:09 +0200970 struct usb_phy *phy = &motg->phy;
Pavankumar Kondetid8608522011-05-04 10:19:47 +0530971 u32 chg_det;
972
973 switch (motg->pdata->phy_type) {
974 case CI_45NM_INTEGRATED_PHY:
Heikki Krogerus1d4c9292012-02-13 13:24:09 +0200975 chg_det = ulpi_read(phy, 0x34);
Pavankumar Kondetid8608522011-05-04 10:19:47 +0530976 chg_det &= ~(1 << 5);
Heikki Krogerus1d4c9292012-02-13 13:24:09 +0200977 ulpi_write(phy, chg_det, 0x34);
Pavankumar Kondetid8608522011-05-04 10:19:47 +0530978 break;
979 case SNPS_28NM_INTEGRATED_PHY:
Heikki Krogerus1d4c9292012-02-13 13:24:09 +0200980 ulpi_write(phy, 0x10, 0x86);
Pavankumar Kondetid8608522011-05-04 10:19:47 +0530981 break;
982 default:
983 break;
984 }
985}
986
987static void msm_chg_enable_dcd(struct msm_otg *motg)
988{
Heikki Krogerus1d4c9292012-02-13 13:24:09 +0200989 struct usb_phy *phy = &motg->phy;
Pavankumar Kondetid8608522011-05-04 10:19:47 +0530990 u32 chg_det;
991
992 switch (motg->pdata->phy_type) {
993 case CI_45NM_INTEGRATED_PHY:
Heikki Krogerus1d4c9292012-02-13 13:24:09 +0200994 chg_det = ulpi_read(phy, 0x34);
Pavankumar Kondetid8608522011-05-04 10:19:47 +0530995 /* Turn on D+ current source */
996 chg_det |= (1 << 5);
Heikki Krogerus1d4c9292012-02-13 13:24:09 +0200997 ulpi_write(phy, chg_det, 0x34);
Pavankumar Kondetid8608522011-05-04 10:19:47 +0530998 break;
999 case SNPS_28NM_INTEGRATED_PHY:
1000 /* Data contact detection enable */
Heikki Krogerus1d4c9292012-02-13 13:24:09 +02001001 ulpi_write(phy, 0x10, 0x85);
Pavankumar Kondetid8608522011-05-04 10:19:47 +05301002 break;
1003 default:
1004 break;
1005 }
1006}
1007
1008static void msm_chg_block_on(struct msm_otg *motg)
1009{
Heikki Krogerus1d4c9292012-02-13 13:24:09 +02001010 struct usb_phy *phy = &motg->phy;
Pavankumar Kondetid8608522011-05-04 10:19:47 +05301011 u32 func_ctrl, chg_det;
1012
1013 /* put the controller in non-driving mode */
Heikki Krogerus1d4c9292012-02-13 13:24:09 +02001014 func_ctrl = ulpi_read(phy, ULPI_FUNC_CTRL);
Pavankumar Kondetid8608522011-05-04 10:19:47 +05301015 func_ctrl &= ~ULPI_FUNC_CTRL_OPMODE_MASK;
1016 func_ctrl |= ULPI_FUNC_CTRL_OPMODE_NONDRIVING;
Heikki Krogerus1d4c9292012-02-13 13:24:09 +02001017 ulpi_write(phy, func_ctrl, ULPI_FUNC_CTRL);
Pavankumar Kondetid8608522011-05-04 10:19:47 +05301018
1019 switch (motg->pdata->phy_type) {
1020 case CI_45NM_INTEGRATED_PHY:
Heikki Krogerus1d4c9292012-02-13 13:24:09 +02001021 chg_det = ulpi_read(phy, 0x34);
Pavankumar Kondetid8608522011-05-04 10:19:47 +05301022 /* control chg block via ULPI */
1023 chg_det &= ~(1 << 3);
Heikki Krogerus1d4c9292012-02-13 13:24:09 +02001024 ulpi_write(phy, chg_det, 0x34);
Pavankumar Kondetid8608522011-05-04 10:19:47 +05301025 /* Turn on chg detect block */
1026 chg_det &= ~(1 << 1);
Heikki Krogerus1d4c9292012-02-13 13:24:09 +02001027 ulpi_write(phy, chg_det, 0x34);
Pavankumar Kondetid8608522011-05-04 10:19:47 +05301028 udelay(20);
1029 break;
1030 case SNPS_28NM_INTEGRATED_PHY:
1031 /* Clear charger detecting control bits */
Heikki Krogerus1d4c9292012-02-13 13:24:09 +02001032 ulpi_write(phy, 0x3F, 0x86);
Pavankumar Kondetid8608522011-05-04 10:19:47 +05301033 /* Clear alt interrupt latch and enable bits */
Heikki Krogerus1d4c9292012-02-13 13:24:09 +02001034 ulpi_write(phy, 0x1F, 0x92);
1035 ulpi_write(phy, 0x1F, 0x95);
Pavankumar Kondetid8608522011-05-04 10:19:47 +05301036 udelay(100);
1037 break;
1038 default:
1039 break;
1040 }
1041}
1042
1043static void msm_chg_block_off(struct msm_otg *motg)
1044{
Heikki Krogerus1d4c9292012-02-13 13:24:09 +02001045 struct usb_phy *phy = &motg->phy;
Pavankumar Kondetid8608522011-05-04 10:19:47 +05301046 u32 func_ctrl, chg_det;
1047
1048 switch (motg->pdata->phy_type) {
1049 case CI_45NM_INTEGRATED_PHY:
Heikki Krogerus1d4c9292012-02-13 13:24:09 +02001050 chg_det = ulpi_read(phy, 0x34);
Pavankumar Kondetid8608522011-05-04 10:19:47 +05301051 /* Turn off charger block */
1052 chg_det |= ~(1 << 1);
Heikki Krogerus1d4c9292012-02-13 13:24:09 +02001053 ulpi_write(phy, chg_det, 0x34);
Pavankumar Kondetid8608522011-05-04 10:19:47 +05301054 break;
1055 case SNPS_28NM_INTEGRATED_PHY:
1056 /* Clear charger detecting control bits */
Heikki Krogerus1d4c9292012-02-13 13:24:09 +02001057 ulpi_write(phy, 0x3F, 0x86);
Pavankumar Kondetid8608522011-05-04 10:19:47 +05301058 /* Clear alt interrupt latch and enable bits */
Heikki Krogerus1d4c9292012-02-13 13:24:09 +02001059 ulpi_write(phy, 0x1F, 0x92);
1060 ulpi_write(phy, 0x1F, 0x95);
Pavankumar Kondetid8608522011-05-04 10:19:47 +05301061 break;
1062 default:
1063 break;
1064 }
1065
1066 /* put the controller in normal mode */
Heikki Krogerus1d4c9292012-02-13 13:24:09 +02001067 func_ctrl = ulpi_read(phy, ULPI_FUNC_CTRL);
Pavankumar Kondetid8608522011-05-04 10:19:47 +05301068 func_ctrl &= ~ULPI_FUNC_CTRL_OPMODE_MASK;
1069 func_ctrl |= ULPI_FUNC_CTRL_OPMODE_NORMAL;
Heikki Krogerus1d4c9292012-02-13 13:24:09 +02001070 ulpi_write(phy, func_ctrl, ULPI_FUNC_CTRL);
Pavankumar Kondetid8608522011-05-04 10:19:47 +05301071}
1072
1073#define MSM_CHG_DCD_POLL_TIME (100 * HZ/1000) /* 100 msec */
1074#define MSM_CHG_DCD_MAX_RETRIES 6 /* Tdcd_tmout = 6 * 100 msec */
1075#define MSM_CHG_PRIMARY_DET_TIME (40 * HZ/1000) /* TVDPSRC_ON */
1076#define MSM_CHG_SECONDARY_DET_TIME (40 * HZ/1000) /* TVDMSRC_ON */
1077static void msm_chg_detect_work(struct work_struct *w)
1078{
1079 struct msm_otg *motg = container_of(w, struct msm_otg, chg_work.work);
Heikki Krogerus1d4c9292012-02-13 13:24:09 +02001080 struct usb_phy *phy = &motg->phy;
Pavankumar Kondetid8608522011-05-04 10:19:47 +05301081 bool is_dcd, tmout, vout;
1082 unsigned long delay;
1083
Heikki Krogerus1d4c9292012-02-13 13:24:09 +02001084 dev_dbg(phy->dev, "chg detection work\n");
Pavankumar Kondetid8608522011-05-04 10:19:47 +05301085 switch (motg->chg_state) {
1086 case USB_CHG_STATE_UNDEFINED:
Heikki Krogerus1d4c9292012-02-13 13:24:09 +02001087 pm_runtime_get_sync(phy->dev);
Pavankumar Kondetid8608522011-05-04 10:19:47 +05301088 msm_chg_block_on(motg);
1089 msm_chg_enable_dcd(motg);
1090 motg->chg_state = USB_CHG_STATE_WAIT_FOR_DCD;
1091 motg->dcd_retries = 0;
1092 delay = MSM_CHG_DCD_POLL_TIME;
1093 break;
1094 case USB_CHG_STATE_WAIT_FOR_DCD:
1095 is_dcd = msm_chg_check_dcd(motg);
1096 tmout = ++motg->dcd_retries == MSM_CHG_DCD_MAX_RETRIES;
1097 if (is_dcd || tmout) {
1098 msm_chg_disable_dcd(motg);
1099 msm_chg_enable_primary_det(motg);
1100 delay = MSM_CHG_PRIMARY_DET_TIME;
1101 motg->chg_state = USB_CHG_STATE_DCD_DONE;
1102 } else {
1103 delay = MSM_CHG_DCD_POLL_TIME;
1104 }
1105 break;
1106 case USB_CHG_STATE_DCD_DONE:
1107 vout = msm_chg_check_primary_det(motg);
1108 if (vout) {
1109 msm_chg_enable_secondary_det(motg);
1110 delay = MSM_CHG_SECONDARY_DET_TIME;
1111 motg->chg_state = USB_CHG_STATE_PRIMARY_DONE;
1112 } else {
1113 motg->chg_type = USB_SDP_CHARGER;
1114 motg->chg_state = USB_CHG_STATE_DETECTED;
1115 delay = 0;
1116 }
1117 break;
1118 case USB_CHG_STATE_PRIMARY_DONE:
1119 vout = msm_chg_check_secondary_det(motg);
1120 if (vout)
1121 motg->chg_type = USB_DCP_CHARGER;
1122 else
1123 motg->chg_type = USB_CDP_CHARGER;
1124 motg->chg_state = USB_CHG_STATE_SECONDARY_DONE;
1125 /* fall through */
1126 case USB_CHG_STATE_SECONDARY_DONE:
1127 motg->chg_state = USB_CHG_STATE_DETECTED;
1128 case USB_CHG_STATE_DETECTED:
1129 msm_chg_block_off(motg);
Heikki Krogerus1d4c9292012-02-13 13:24:09 +02001130 dev_dbg(phy->dev, "charger = %d\n", motg->chg_type);
Pavankumar Kondetid8608522011-05-04 10:19:47 +05301131 schedule_work(&motg->sm_work);
1132 return;
1133 default:
1134 return;
1135 }
1136
1137 schedule_delayed_work(&motg->chg_work, delay);
1138}
1139
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05301140/*
1141 * We support OTG, Peripheral only and Host only configurations. In case
1142 * of OTG, mode switch (host-->peripheral/peripheral-->host) can happen
1143 * via Id pin status or user request (debugfs). Id/BSV interrupts are not
1144 * enabled when switch is controlled by user and default mode is supplied
1145 * by board file, which can be changed by userspace later.
1146 */
1147static void msm_otg_init_sm(struct msm_otg *motg)
1148{
1149 struct msm_otg_platform_data *pdata = motg->pdata;
1150 u32 otgsc = readl(USB_OTGSC);
1151
1152 switch (pdata->mode) {
Ivan T. Ivanov971232c2014-04-28 16:34:11 +03001153 case USB_DR_MODE_OTG:
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05301154 if (pdata->otg_control == OTG_PHY_CONTROL) {
1155 if (otgsc & OTGSC_ID)
1156 set_bit(ID, &motg->inputs);
1157 else
1158 clear_bit(ID, &motg->inputs);
1159
1160 if (otgsc & OTGSC_BSV)
1161 set_bit(B_SESS_VLD, &motg->inputs);
1162 else
1163 clear_bit(B_SESS_VLD, &motg->inputs);
1164 } else if (pdata->otg_control == OTG_USER_CONTROL) {
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05301165 set_bit(ID, &motg->inputs);
1166 clear_bit(B_SESS_VLD, &motg->inputs);
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05301167 }
1168 break;
Ivan T. Ivanov971232c2014-04-28 16:34:11 +03001169 case USB_DR_MODE_HOST:
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05301170 clear_bit(ID, &motg->inputs);
1171 break;
Ivan T. Ivanov971232c2014-04-28 16:34:11 +03001172 case USB_DR_MODE_PERIPHERAL:
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05301173 set_bit(ID, &motg->inputs);
1174 if (otgsc & OTGSC_BSV)
1175 set_bit(B_SESS_VLD, &motg->inputs);
1176 else
1177 clear_bit(B_SESS_VLD, &motg->inputs);
1178 break;
1179 default:
1180 break;
1181 }
1182}
1183
1184static void msm_otg_sm_work(struct work_struct *w)
1185{
1186 struct msm_otg *motg = container_of(w, struct msm_otg, sm_work);
Heikki Krogerus1d4c9292012-02-13 13:24:09 +02001187 struct usb_otg *otg = motg->phy.otg;
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05301188
Antoine Tenarte47d9252014-10-30 18:41:13 +01001189 switch (otg->state) {
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05301190 case OTG_STATE_UNDEFINED:
Antoine Tenart19c1eac2014-10-30 18:41:14 +01001191 dev_dbg(otg->usb_phy->dev, "OTG_STATE_UNDEFINED state\n");
1192 msm_otg_reset(otg->usb_phy);
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05301193 msm_otg_init_sm(motg);
Antoine Tenarte47d9252014-10-30 18:41:13 +01001194 otg->state = OTG_STATE_B_IDLE;
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05301195 /* FALL THROUGH */
1196 case OTG_STATE_B_IDLE:
Antoine Tenart19c1eac2014-10-30 18:41:14 +01001197 dev_dbg(otg->usb_phy->dev, "OTG_STATE_B_IDLE state\n");
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05301198 if (!test_bit(ID, &motg->inputs) && otg->host) {
1199 /* disable BSV bit */
1200 writel(readl(USB_OTGSC) & ~OTGSC_BSVIE, USB_OTGSC);
Antoine Tenart19c1eac2014-10-30 18:41:14 +01001201 msm_otg_start_host(otg->usb_phy, 1);
Antoine Tenarte47d9252014-10-30 18:41:13 +01001202 otg->state = OTG_STATE_A_HOST;
Pavankumar Kondetid8608522011-05-04 10:19:47 +05301203 } else if (test_bit(B_SESS_VLD, &motg->inputs)) {
1204 switch (motg->chg_state) {
1205 case USB_CHG_STATE_UNDEFINED:
1206 msm_chg_detect_work(&motg->chg_work.work);
1207 break;
1208 case USB_CHG_STATE_DETECTED:
1209 switch (motg->chg_type) {
1210 case USB_DCP_CHARGER:
1211 msm_otg_notify_charger(motg,
1212 IDEV_CHG_MAX);
1213 break;
1214 case USB_CDP_CHARGER:
1215 msm_otg_notify_charger(motg,
1216 IDEV_CHG_MAX);
Antoine Tenart19c1eac2014-10-30 18:41:14 +01001217 msm_otg_start_peripheral(otg->usb_phy,
1218 1);
Antoine Tenarte47d9252014-10-30 18:41:13 +01001219 otg->state
Heikki Krogerus1d4c9292012-02-13 13:24:09 +02001220 = OTG_STATE_B_PERIPHERAL;
Pavankumar Kondetid8608522011-05-04 10:19:47 +05301221 break;
1222 case USB_SDP_CHARGER:
1223 msm_otg_notify_charger(motg, IUNIT);
Antoine Tenart19c1eac2014-10-30 18:41:14 +01001224 msm_otg_start_peripheral(otg->usb_phy,
1225 1);
Antoine Tenarte47d9252014-10-30 18:41:13 +01001226 otg->state
Heikki Krogerus1d4c9292012-02-13 13:24:09 +02001227 = OTG_STATE_B_PERIPHERAL;
Pavankumar Kondetid8608522011-05-04 10:19:47 +05301228 break;
1229 default:
1230 break;
1231 }
1232 break;
1233 default:
1234 break;
1235 }
1236 } else {
1237 /*
1238 * If charger detection work is pending, decrement
1239 * the pm usage counter to balance with the one that
1240 * is incremented in charger detection work.
1241 */
1242 if (cancel_delayed_work_sync(&motg->chg_work)) {
Antoine Tenart19c1eac2014-10-30 18:41:14 +01001243 pm_runtime_put_sync(otg->usb_phy->dev);
1244 msm_otg_reset(otg->usb_phy);
Pavankumar Kondetid8608522011-05-04 10:19:47 +05301245 }
1246 msm_otg_notify_charger(motg, 0);
1247 motg->chg_state = USB_CHG_STATE_UNDEFINED;
1248 motg->chg_type = USB_INVALID_CHARGER;
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05301249 }
Srinivas Kandagatla508ccea2014-06-30 18:29:57 +01001250
Antoine Tenarte47d9252014-10-30 18:41:13 +01001251 if (otg->state == OTG_STATE_B_IDLE)
Antoine Tenart19c1eac2014-10-30 18:41:14 +01001252 pm_runtime_put_sync(otg->usb_phy->dev);
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05301253 break;
1254 case OTG_STATE_B_PERIPHERAL:
Antoine Tenart19c1eac2014-10-30 18:41:14 +01001255 dev_dbg(otg->usb_phy->dev, "OTG_STATE_B_PERIPHERAL state\n");
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05301256 if (!test_bit(B_SESS_VLD, &motg->inputs) ||
1257 !test_bit(ID, &motg->inputs)) {
Pavankumar Kondetid8608522011-05-04 10:19:47 +05301258 msm_otg_notify_charger(motg, 0);
Antoine Tenart19c1eac2014-10-30 18:41:14 +01001259 msm_otg_start_peripheral(otg->usb_phy, 0);
Pavankumar Kondetid8608522011-05-04 10:19:47 +05301260 motg->chg_state = USB_CHG_STATE_UNDEFINED;
1261 motg->chg_type = USB_INVALID_CHARGER;
Antoine Tenarte47d9252014-10-30 18:41:13 +01001262 otg->state = OTG_STATE_B_IDLE;
Antoine Tenart19c1eac2014-10-30 18:41:14 +01001263 msm_otg_reset(otg->usb_phy);
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05301264 schedule_work(w);
1265 }
1266 break;
1267 case OTG_STATE_A_HOST:
Antoine Tenart19c1eac2014-10-30 18:41:14 +01001268 dev_dbg(otg->usb_phy->dev, "OTG_STATE_A_HOST state\n");
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05301269 if (test_bit(ID, &motg->inputs)) {
Antoine Tenart19c1eac2014-10-30 18:41:14 +01001270 msm_otg_start_host(otg->usb_phy, 0);
Antoine Tenarte47d9252014-10-30 18:41:13 +01001271 otg->state = OTG_STATE_B_IDLE;
Antoine Tenart19c1eac2014-10-30 18:41:14 +01001272 msm_otg_reset(otg->usb_phy);
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05301273 schedule_work(w);
1274 }
1275 break;
1276 default:
1277 break;
1278 }
1279}
1280
1281static irqreturn_t msm_otg_irq(int irq, void *data)
1282{
1283 struct msm_otg *motg = data;
Heikki Krogerus1d4c9292012-02-13 13:24:09 +02001284 struct usb_phy *phy = &motg->phy;
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05301285 u32 otgsc = 0;
1286
Pavankumar Kondeti87c01042010-12-07 17:53:58 +05301287 if (atomic_read(&motg->in_lpm)) {
1288 disable_irq_nosync(irq);
1289 motg->async_int = 1;
Heikki Krogerus1d4c9292012-02-13 13:24:09 +02001290 pm_runtime_get(phy->dev);
Pavankumar Kondeti87c01042010-12-07 17:53:58 +05301291 return IRQ_HANDLED;
1292 }
1293
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05301294 otgsc = readl(USB_OTGSC);
1295 if (!(otgsc & (OTGSC_IDIS | OTGSC_BSVIS)))
1296 return IRQ_NONE;
1297
1298 if ((otgsc & OTGSC_IDIS) && (otgsc & OTGSC_IDIE)) {
1299 if (otgsc & OTGSC_ID)
1300 set_bit(ID, &motg->inputs);
1301 else
1302 clear_bit(ID, &motg->inputs);
Heikki Krogerus1d4c9292012-02-13 13:24:09 +02001303 dev_dbg(phy->dev, "ID set/clear\n");
1304 pm_runtime_get_noresume(phy->dev);
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05301305 } else if ((otgsc & OTGSC_BSVIS) && (otgsc & OTGSC_BSVIE)) {
1306 if (otgsc & OTGSC_BSV)
1307 set_bit(B_SESS_VLD, &motg->inputs);
1308 else
1309 clear_bit(B_SESS_VLD, &motg->inputs);
Heikki Krogerus1d4c9292012-02-13 13:24:09 +02001310 dev_dbg(phy->dev, "BSV set/clear\n");
1311 pm_runtime_get_noresume(phy->dev);
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05301312 }
1313
1314 writel(otgsc, USB_OTGSC);
1315 schedule_work(&motg->sm_work);
1316 return IRQ_HANDLED;
1317}
1318
1319static int msm_otg_mode_show(struct seq_file *s, void *unused)
1320{
1321 struct msm_otg *motg = s->private;
Heikki Krogerus1d4c9292012-02-13 13:24:09 +02001322 struct usb_otg *otg = motg->phy.otg;
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05301323
Antoine Tenarte47d9252014-10-30 18:41:13 +01001324 switch (otg->state) {
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05301325 case OTG_STATE_A_HOST:
Ivan T. Ivanov3aca0fa2014-04-28 16:34:10 +03001326 seq_puts(s, "host\n");
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05301327 break;
1328 case OTG_STATE_B_PERIPHERAL:
Ivan T. Ivanov3aca0fa2014-04-28 16:34:10 +03001329 seq_puts(s, "peripheral\n");
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05301330 break;
1331 default:
Ivan T. Ivanov3aca0fa2014-04-28 16:34:10 +03001332 seq_puts(s, "none\n");
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05301333 break;
1334 }
1335
1336 return 0;
1337}
1338
1339static int msm_otg_mode_open(struct inode *inode, struct file *file)
1340{
1341 return single_open(file, msm_otg_mode_show, inode->i_private);
1342}
1343
1344static ssize_t msm_otg_mode_write(struct file *file, const char __user *ubuf,
1345 size_t count, loff_t *ppos)
1346{
Pavankumar Kondetie2904ee2011-02-15 09:42:35 +05301347 struct seq_file *s = file->private_data;
1348 struct msm_otg *motg = s->private;
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05301349 char buf[16];
Heikki Krogerus1d4c9292012-02-13 13:24:09 +02001350 struct usb_otg *otg = motg->phy.otg;
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05301351 int status = count;
Ivan T. Ivanov971232c2014-04-28 16:34:11 +03001352 enum usb_dr_mode req_mode;
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05301353
1354 memset(buf, 0x00, sizeof(buf));
1355
1356 if (copy_from_user(&buf, ubuf, min_t(size_t, sizeof(buf) - 1, count))) {
1357 status = -EFAULT;
1358 goto out;
1359 }
1360
1361 if (!strncmp(buf, "host", 4)) {
Ivan T. Ivanov971232c2014-04-28 16:34:11 +03001362 req_mode = USB_DR_MODE_HOST;
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05301363 } else if (!strncmp(buf, "peripheral", 10)) {
Ivan T. Ivanov971232c2014-04-28 16:34:11 +03001364 req_mode = USB_DR_MODE_PERIPHERAL;
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05301365 } else if (!strncmp(buf, "none", 4)) {
Ivan T. Ivanov971232c2014-04-28 16:34:11 +03001366 req_mode = USB_DR_MODE_UNKNOWN;
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05301367 } else {
1368 status = -EINVAL;
1369 goto out;
1370 }
1371
1372 switch (req_mode) {
Ivan T. Ivanov971232c2014-04-28 16:34:11 +03001373 case USB_DR_MODE_UNKNOWN:
Antoine Tenarte47d9252014-10-30 18:41:13 +01001374 switch (otg->state) {
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05301375 case OTG_STATE_A_HOST:
1376 case OTG_STATE_B_PERIPHERAL:
1377 set_bit(ID, &motg->inputs);
1378 clear_bit(B_SESS_VLD, &motg->inputs);
1379 break;
1380 default:
1381 goto out;
1382 }
1383 break;
Ivan T. Ivanov971232c2014-04-28 16:34:11 +03001384 case USB_DR_MODE_PERIPHERAL:
Antoine Tenarte47d9252014-10-30 18:41:13 +01001385 switch (otg->state) {
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05301386 case OTG_STATE_B_IDLE:
1387 case OTG_STATE_A_HOST:
1388 set_bit(ID, &motg->inputs);
1389 set_bit(B_SESS_VLD, &motg->inputs);
1390 break;
1391 default:
1392 goto out;
1393 }
1394 break;
Ivan T. Ivanov971232c2014-04-28 16:34:11 +03001395 case USB_DR_MODE_HOST:
Antoine Tenarte47d9252014-10-30 18:41:13 +01001396 switch (otg->state) {
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05301397 case OTG_STATE_B_IDLE:
1398 case OTG_STATE_B_PERIPHERAL:
1399 clear_bit(ID, &motg->inputs);
1400 break;
1401 default:
1402 goto out;
1403 }
1404 break;
1405 default:
1406 goto out;
1407 }
1408
Antoine Tenart19c1eac2014-10-30 18:41:14 +01001409 pm_runtime_get_sync(otg->usb_phy->dev);
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05301410 schedule_work(&motg->sm_work);
1411out:
1412 return status;
1413}
1414
Felipe Balbi8f90afd2014-08-20 13:38:18 -05001415static const struct file_operations msm_otg_mode_fops = {
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05301416 .open = msm_otg_mode_open,
1417 .read = seq_read,
1418 .write = msm_otg_mode_write,
1419 .llseek = seq_lseek,
1420 .release = single_release,
1421};
1422
1423static struct dentry *msm_otg_dbg_root;
1424static struct dentry *msm_otg_dbg_mode;
1425
1426static int msm_otg_debugfs_init(struct msm_otg *motg)
1427{
1428 msm_otg_dbg_root = debugfs_create_dir("msm_otg", NULL);
1429
1430 if (!msm_otg_dbg_root || IS_ERR(msm_otg_dbg_root))
1431 return -ENODEV;
1432
1433 msm_otg_dbg_mode = debugfs_create_file("mode", S_IRUGO | S_IWUSR,
1434 msm_otg_dbg_root, motg, &msm_otg_mode_fops);
1435 if (!msm_otg_dbg_mode) {
1436 debugfs_remove(msm_otg_dbg_root);
1437 msm_otg_dbg_root = NULL;
1438 return -ENODEV;
1439 }
1440
1441 return 0;
1442}
1443
1444static void msm_otg_debugfs_cleanup(void)
1445{
1446 debugfs_remove(msm_otg_dbg_mode);
1447 debugfs_remove(msm_otg_dbg_root);
1448}
1449
Jingoo Han492240b2014-06-18 13:42:44 +09001450static const struct of_device_id msm_otg_dt_match[] = {
Ivan T. Ivanov8364f9a2014-04-28 16:34:15 +03001451 {
1452 .compatible = "qcom,usb-otg-ci",
1453 .data = (void *) CI_45NM_INTEGRATED_PHY
1454 },
1455 {
1456 .compatible = "qcom,usb-otg-snps",
1457 .data = (void *) SNPS_28NM_INTEGRATED_PHY
1458 },
1459 { }
1460};
1461MODULE_DEVICE_TABLE(of, msm_otg_dt_match);
1462
Ivan T. Ivanov591fc112015-04-09 11:34:22 +03001463static int msm_otg_vbus_notifier(struct notifier_block *nb, unsigned long event,
1464 void *ptr)
1465{
1466 struct msm_usb_cable *vbus = container_of(nb, struct msm_usb_cable, nb);
1467 struct msm_otg *motg = container_of(vbus, struct msm_otg, vbus);
1468
1469 if (event)
1470 set_bit(B_SESS_VLD, &motg->inputs);
1471 else
1472 clear_bit(B_SESS_VLD, &motg->inputs);
1473
1474 schedule_work(&motg->sm_work);
1475
1476 return NOTIFY_DONE;
1477}
1478
1479static int msm_otg_id_notifier(struct notifier_block *nb, unsigned long event,
1480 void *ptr)
1481{
1482 struct msm_usb_cable *id = container_of(nb, struct msm_usb_cable, nb);
1483 struct msm_otg *motg = container_of(id, struct msm_otg, id);
1484
1485 if (event)
1486 clear_bit(ID, &motg->inputs);
1487 else
1488 set_bit(ID, &motg->inputs);
1489
1490 schedule_work(&motg->sm_work);
1491
1492 return NOTIFY_DONE;
1493}
1494
Ivan T. Ivanov8364f9a2014-04-28 16:34:15 +03001495static int msm_otg_read_dt(struct platform_device *pdev, struct msm_otg *motg)
1496{
1497 struct msm_otg_platform_data *pdata;
Ivan T. Ivanov591fc112015-04-09 11:34:22 +03001498 struct extcon_dev *ext_id, *ext_vbus;
Ivan T. Ivanov8364f9a2014-04-28 16:34:15 +03001499 const struct of_device_id *id;
1500 struct device_node *node = pdev->dev.of_node;
1501 struct property *prop;
1502 int len, ret, words;
Ivan T. Ivanov01799b62014-04-28 16:34:22 +03001503 u32 val, tmp[3];
Ivan T. Ivanov8364f9a2014-04-28 16:34:15 +03001504
1505 pdata = devm_kzalloc(&pdev->dev, sizeof(*pdata), GFP_KERNEL);
1506 if (!pdata)
1507 return -ENOMEM;
1508
1509 motg->pdata = pdata;
1510
1511 id = of_match_device(msm_otg_dt_match, &pdev->dev);
Felipe Balbib3025e62014-04-30 11:33:04 -05001512 pdata->phy_type = (enum msm_usb_phy_type) id->data;
Ivan T. Ivanov8364f9a2014-04-28 16:34:15 +03001513
Ivan T. Ivanova2734542014-04-28 16:34:16 +03001514 motg->link_rst = devm_reset_control_get(&pdev->dev, "link");
1515 if (IS_ERR(motg->link_rst))
1516 return PTR_ERR(motg->link_rst);
1517
1518 motg->phy_rst = devm_reset_control_get(&pdev->dev, "phy");
1519 if (IS_ERR(motg->phy_rst))
Srinivas Kandagatlae44f1f42014-06-30 18:29:49 +01001520 motg->phy_rst = NULL;
Ivan T. Ivanova2734542014-04-28 16:34:16 +03001521
Ivan T. Ivanov8364f9a2014-04-28 16:34:15 +03001522 pdata->mode = of_usb_get_dr_mode(node);
1523 if (pdata->mode == USB_DR_MODE_UNKNOWN)
1524 pdata->mode = USB_DR_MODE_OTG;
1525
1526 pdata->otg_control = OTG_PHY_CONTROL;
1527 if (!of_property_read_u32(node, "qcom,otg-control", &val))
1528 if (val == OTG_PMIC_CONTROL)
1529 pdata->otg_control = val;
1530
Ivan T. Ivanovcfa3ff52014-04-28 16:34:17 +03001531 if (!of_property_read_u32(node, "qcom,phy-num", &val) && val < 2)
1532 motg->phy_number = val;
1533
Ivan T. Ivanov01799b62014-04-28 16:34:22 +03001534 motg->vdd_levels[VDD_LEVEL_NONE] = USB_PHY_SUSP_DIG_VOL;
1535 motg->vdd_levels[VDD_LEVEL_MIN] = USB_PHY_VDD_DIG_VOL_MIN;
1536 motg->vdd_levels[VDD_LEVEL_MAX] = USB_PHY_VDD_DIG_VOL_MAX;
1537
1538 if (of_get_property(node, "qcom,vdd-levels", &len) &&
1539 len == sizeof(tmp)) {
1540 of_property_read_u32_array(node, "qcom,vdd-levels",
1541 tmp, len / sizeof(*tmp));
1542 motg->vdd_levels[VDD_LEVEL_NONE] = tmp[VDD_LEVEL_NONE];
1543 motg->vdd_levels[VDD_LEVEL_MIN] = tmp[VDD_LEVEL_MIN];
1544 motg->vdd_levels[VDD_LEVEL_MAX] = tmp[VDD_LEVEL_MAX];
1545 }
1546
Ivan T. Ivanov44e42ae2015-04-09 11:34:33 +03001547 motg->manual_pullup = of_property_read_bool(node, "qcom,manual-pullup");
1548
Ivan T. Ivanov591fc112015-04-09 11:34:22 +03001549 ext_id = ERR_PTR(-ENODEV);
1550 ext_vbus = ERR_PTR(-ENODEV);
1551 if (of_property_read_bool(node, "extcon")) {
1552
1553 /* Each one of them is not mandatory */
1554 ext_vbus = extcon_get_edev_by_phandle(&pdev->dev, 0);
1555 if (IS_ERR(ext_vbus) && PTR_ERR(ext_vbus) != -ENODEV)
1556 return PTR_ERR(ext_vbus);
1557
1558 ext_id = extcon_get_edev_by_phandle(&pdev->dev, 1);
1559 if (IS_ERR(ext_id) && PTR_ERR(ext_id) != -ENODEV)
1560 return PTR_ERR(ext_id);
1561 }
1562
1563 if (!IS_ERR(ext_vbus)) {
1564 motg->vbus.nb.notifier_call = msm_otg_vbus_notifier;
1565 ret = extcon_register_interest(&motg->vbus.conn, ext_vbus->name,
1566 "USB", &motg->vbus.nb);
1567 if (ret < 0) {
1568 dev_err(&pdev->dev, "register VBUS notifier failed\n");
1569 return ret;
1570 }
1571
1572 ret = extcon_get_cable_state(ext_vbus, "USB");
1573 if (ret)
1574 set_bit(B_SESS_VLD, &motg->inputs);
1575 else
1576 clear_bit(B_SESS_VLD, &motg->inputs);
1577 }
1578
1579 if (!IS_ERR(ext_id)) {
1580 motg->id.nb.notifier_call = msm_otg_id_notifier;
1581 ret = extcon_register_interest(&motg->id.conn, ext_id->name,
1582 "USB-HOST", &motg->id.nb);
1583 if (ret < 0) {
1584 dev_err(&pdev->dev, "register ID notifier failed\n");
1585 return ret;
1586 }
1587
1588 ret = extcon_get_cable_state(ext_id, "USB-HOST");
1589 if (ret)
1590 clear_bit(ID, &motg->inputs);
1591 else
1592 set_bit(ID, &motg->inputs);
1593 }
1594
Ivan T. Ivanov8364f9a2014-04-28 16:34:15 +03001595 prop = of_find_property(node, "qcom,phy-init-sequence", &len);
1596 if (!prop || !len)
1597 return 0;
1598
1599 words = len / sizeof(u32);
1600
1601 if (words >= ULPI_EXT_VENDOR_SPECIFIC) {
1602 dev_warn(&pdev->dev, "Too big PHY init sequence %d\n", words);
1603 return 0;
1604 }
1605
1606 pdata->phy_init_seq = devm_kzalloc(&pdev->dev, len, GFP_KERNEL);
Peter Chen9da22202014-10-14 15:56:17 +08001607 if (!pdata->phy_init_seq)
Ivan T. Ivanov8364f9a2014-04-28 16:34:15 +03001608 return 0;
Ivan T. Ivanov8364f9a2014-04-28 16:34:15 +03001609
1610 ret = of_property_read_u32_array(node, "qcom,phy-init-sequence",
1611 pdata->phy_init_seq, words);
1612 if (!ret)
1613 pdata->phy_init_sz = words;
1614
1615 return 0;
1616}
1617
Ivan T. Ivanov06a6ec42014-04-28 16:34:07 +03001618static int msm_otg_probe(struct platform_device *pdev)
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05301619{
Ivan T. Ivanov6b99c68e2014-04-28 16:34:08 +03001620 struct regulator_bulk_data regs[3];
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05301621 int ret = 0;
Ivan T. Ivanov8364f9a2014-04-28 16:34:15 +03001622 struct device_node *np = pdev->dev.of_node;
1623 struct msm_otg_platform_data *pdata;
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05301624 struct resource *res;
1625 struct msm_otg *motg;
Heikki Krogerus1d4c9292012-02-13 13:24:09 +02001626 struct usb_phy *phy;
Tim Bird30bf8662014-04-28 16:34:20 +03001627 void __iomem *phy_select;
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05301628
Ivan T. Ivanov6b99c68e2014-04-28 16:34:08 +03001629 motg = devm_kzalloc(&pdev->dev, sizeof(struct msm_otg), GFP_KERNEL);
Peter Chen9da22202014-10-14 15:56:17 +08001630 if (!motg)
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05301631 return -ENOMEM;
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05301632
Ivan T. Ivanov8364f9a2014-04-28 16:34:15 +03001633 pdata = dev_get_platdata(&pdev->dev);
1634 if (!pdata) {
1635 if (!np)
1636 return -ENXIO;
1637 ret = msm_otg_read_dt(pdev, motg);
1638 if (ret)
1639 return ret;
1640 }
1641
Ivan T. Ivanov6b99c68e2014-04-28 16:34:08 +03001642 motg->phy.otg = devm_kzalloc(&pdev->dev, sizeof(struct usb_otg),
1643 GFP_KERNEL);
Peter Chen9da22202014-10-14 15:56:17 +08001644 if (!motg->phy.otg)
Ivan T. Ivanov6b99c68e2014-04-28 16:34:08 +03001645 return -ENOMEM;
Heikki Krogerus1d4c9292012-02-13 13:24:09 +02001646
Heikki Krogerus1d4c9292012-02-13 13:24:09 +02001647 phy = &motg->phy;
1648 phy->dev = &pdev->dev;
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05301649
Ivan T. Ivanov8364f9a2014-04-28 16:34:15 +03001650 motg->clk = devm_clk_get(&pdev->dev, np ? "core" : "usb_hs_clk");
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05301651 if (IS_ERR(motg->clk)) {
1652 dev_err(&pdev->dev, "failed to get usb_hs_clk\n");
Ivan T. Ivanov6b99c68e2014-04-28 16:34:08 +03001653 return PTR_ERR(motg->clk);
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05301654 }
Anji jonnala0f73cac2011-05-04 10:19:46 +05301655
1656 /*
1657 * If USB Core is running its protocol engine based on CORE CLK,
1658 * CORE CLK must be running at >55Mhz for correct HSUSB
1659 * operation and USB core cannot tolerate frequency changes on
Ivan T. Ivanovff0e4a62014-04-28 16:34:12 +03001660 * CORE CLK.
Anji jonnala0f73cac2011-05-04 10:19:46 +05301661 */
Ivan T. Ivanov8364f9a2014-04-28 16:34:15 +03001662 motg->pclk = devm_clk_get(&pdev->dev, np ? "iface" : "usb_hs_pclk");
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05301663 if (IS_ERR(motg->pclk)) {
1664 dev_err(&pdev->dev, "failed to get usb_hs_pclk\n");
Ivan T. Ivanov6b99c68e2014-04-28 16:34:08 +03001665 return PTR_ERR(motg->pclk);
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05301666 }
1667
1668 /*
1669 * USB core clock is not present on all MSM chips. This
1670 * clock is introduced to remove the dependency on AXI
1671 * bus frequency.
1672 */
Ivan T. Ivanov8364f9a2014-04-28 16:34:15 +03001673 motg->core_clk = devm_clk_get(&pdev->dev,
1674 np ? "alt_core" : "usb_hs_core_clk");
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05301675
1676 res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
Dan Carpenter2ea7b142014-05-19 23:35:19 +03001677 if (!res)
1678 return -EINVAL;
1679 motg->regs = devm_ioremap(&pdev->dev, res->start, resource_size(res));
1680 if (!motg->regs)
1681 return -ENOMEM;
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05301682
Tim Bird30bf8662014-04-28 16:34:20 +03001683 /*
1684 * NOTE: The PHYs can be multiplexed between the chipidea controller
1685 * and the dwc3 controller, using a single bit. It is important that
1686 * the dwc3 driver does not set this bit in an incompatible way.
1687 */
1688 if (motg->phy_number) {
1689 phy_select = devm_ioremap_nocache(&pdev->dev, USB2_PHY_SEL, 4);
Wei Yongjun716d28e2014-07-20 11:40:37 +08001690 if (!phy_select)
1691 return -ENOMEM;
Tim Bird30bf8662014-04-28 16:34:20 +03001692 /* Enable second PHY with the OTG port */
Felipe Balbi24597492014-04-30 11:35:22 -05001693 writel(0x1, phy_select);
Tim Bird30bf8662014-04-28 16:34:20 +03001694 }
1695
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05301696 dev_info(&pdev->dev, "OTG regs = %p\n", motg->regs);
1697
1698 motg->irq = platform_get_irq(pdev, 0);
Ivan T. Ivanovf60c1142014-04-28 16:34:14 +03001699 if (motg->irq < 0) {
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05301700 dev_err(&pdev->dev, "platform_get_irq failed\n");
Ivan T. Ivanov6b99c68e2014-04-28 16:34:08 +03001701 return motg->irq;
1702 }
1703
Ivan T. Ivanovf5ef2372014-04-28 16:34:13 +03001704 regs[0].supply = "vddcx";
1705 regs[1].supply = "v3p3";
1706 regs[2].supply = "v1p8";
Ivan T. Ivanov6b99c68e2014-04-28 16:34:08 +03001707
1708 ret = devm_regulator_bulk_get(motg->phy.dev, ARRAY_SIZE(regs), regs);
1709 if (ret)
1710 return ret;
1711
1712 motg->vddcx = regs[0].consumer;
1713 motg->v3p3 = regs[1].consumer;
1714 motg->v1p8 = regs[2].consumer;
1715
1716 clk_set_rate(motg->clk, 60000000);
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05301717
Stephen Boydb99a8f62013-06-17 10:43:10 -07001718 clk_prepare_enable(motg->clk);
1719 clk_prepare_enable(motg->pclk);
Anji jonnala11aa5c42011-05-04 10:19:48 +05301720
Ivan T. Ivanov6b99c68e2014-04-28 16:34:08 +03001721 if (!IS_ERR(motg->core_clk))
1722 clk_prepare_enable(motg->core_clk);
1723
Anji jonnala11aa5c42011-05-04 10:19:48 +05301724 ret = msm_hsusb_init_vddcx(motg, 1);
1725 if (ret) {
1726 dev_err(&pdev->dev, "hsusb vddcx configuration failed\n");
Ivan T. Ivanov6b99c68e2014-04-28 16:34:08 +03001727 goto disable_clks;
Anji jonnala11aa5c42011-05-04 10:19:48 +05301728 }
1729
1730 ret = msm_hsusb_ldo_init(motg, 1);
1731 if (ret) {
1732 dev_err(&pdev->dev, "hsusb vreg configuration failed\n");
Ivan T. Ivanov6b99c68e2014-04-28 16:34:08 +03001733 goto disable_vddcx;
Anji jonnala11aa5c42011-05-04 10:19:48 +05301734 }
Ivan T. Ivanov37cfdaf2014-04-28 16:34:06 +03001735 ret = msm_hsusb_ldo_set_mode(motg, 1);
Anji jonnala11aa5c42011-05-04 10:19:48 +05301736 if (ret) {
1737 dev_err(&pdev->dev, "hsusb vreg enable failed\n");
Ivan T. Ivanov6b99c68e2014-04-28 16:34:08 +03001738 goto disable_ldo;
Anji jonnala11aa5c42011-05-04 10:19:48 +05301739 }
1740
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05301741 writel(0, USB_USBINTR);
1742 writel(0, USB_OTGSC);
1743
1744 INIT_WORK(&motg->sm_work, msm_otg_sm_work);
Pavankumar Kondetid8608522011-05-04 10:19:47 +05301745 INIT_DELAYED_WORK(&motg->chg_work, msm_chg_detect_work);
Ivan T. Ivanov6b99c68e2014-04-28 16:34:08 +03001746 ret = devm_request_irq(&pdev->dev, motg->irq, msm_otg_irq, IRQF_SHARED,
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05301747 "msm_otg", motg);
1748 if (ret) {
1749 dev_err(&pdev->dev, "request irq failed\n");
Ivan T. Ivanov6b99c68e2014-04-28 16:34:08 +03001750 goto disable_ldo;
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05301751 }
1752
Ivan T. Ivanovd69c6f52014-04-28 16:34:18 +03001753 phy->init = msm_phy_init;
Heikki Krogerus1d4c9292012-02-13 13:24:09 +02001754 phy->set_power = msm_otg_set_power;
Ivan T. Ivanov349907c2014-04-28 16:34:21 +03001755 phy->notify_disconnect = msm_phy_notify_disconnect;
Ivan T. Ivanove695abb2014-04-28 16:34:23 +03001756 phy->type = USB_PHY_TYPE_USB2;
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05301757
Heikki Krogerus1d4c9292012-02-13 13:24:09 +02001758 phy->io_ops = &msm_otg_io_ops;
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05301759
Antoine Tenart19c1eac2014-10-30 18:41:14 +01001760 phy->otg->usb_phy = &motg->phy;
Heikki Krogerus1d4c9292012-02-13 13:24:09 +02001761 phy->otg->set_host = msm_otg_set_host;
1762 phy->otg->set_peripheral = msm_otg_set_peripheral;
1763
Ivan T. Ivanovd69c6f52014-04-28 16:34:18 +03001764 msm_usb_reset(phy);
1765
Ivan T. Ivanove695abb2014-04-28 16:34:23 +03001766 ret = usb_add_phy_dev(&motg->phy);
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05301767 if (ret) {
Kishon Vijay Abraham I721002e2012-06-22 17:02:45 +05301768 dev_err(&pdev->dev, "usb_add_phy failed\n");
Ivan T. Ivanov6b99c68e2014-04-28 16:34:08 +03001769 goto disable_ldo;
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05301770 }
1771
1772 platform_set_drvdata(pdev, motg);
1773 device_init_wakeup(&pdev->dev, 1);
1774
Ivan T. Ivanov971232c2014-04-28 16:34:11 +03001775 if (motg->pdata->mode == USB_DR_MODE_OTG &&
Ivan T. Ivanov8364f9a2014-04-28 16:34:15 +03001776 motg->pdata->otg_control == OTG_USER_CONTROL) {
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05301777 ret = msm_otg_debugfs_init(motg);
1778 if (ret)
Ivan T. Ivanov3aca0fa2014-04-28 16:34:10 +03001779 dev_dbg(&pdev->dev, "Can not create mode change file\n");
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05301780 }
1781
Pavankumar Kondeti87c01042010-12-07 17:53:58 +05301782 pm_runtime_set_active(&pdev->dev);
1783 pm_runtime_enable(&pdev->dev);
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05301784
Pavankumar Kondeti87c01042010-12-07 17:53:58 +05301785 return 0;
Ivan T. Ivanov6b99c68e2014-04-28 16:34:08 +03001786
1787disable_ldo:
1788 msm_hsusb_ldo_init(motg, 0);
1789disable_vddcx:
1790 msm_hsusb_init_vddcx(motg, 0);
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05301791disable_clks:
Stephen Boydb99a8f62013-06-17 10:43:10 -07001792 clk_disable_unprepare(motg->pclk);
1793 clk_disable_unprepare(motg->clk);
Ivan T. Ivanov6b99c68e2014-04-28 16:34:08 +03001794 if (!IS_ERR(motg->core_clk))
1795 clk_disable_unprepare(motg->core_clk);
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05301796 return ret;
1797}
1798
Bill Pembertonfb4e98a2012-11-19 13:26:20 -05001799static int msm_otg_remove(struct platform_device *pdev)
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05301800{
1801 struct msm_otg *motg = platform_get_drvdata(pdev);
Heikki Krogerus1d4c9292012-02-13 13:24:09 +02001802 struct usb_phy *phy = &motg->phy;
Pavankumar Kondeti87c01042010-12-07 17:53:58 +05301803 int cnt = 0;
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05301804
Heikki Krogerus1d4c9292012-02-13 13:24:09 +02001805 if (phy->otg->host || phy->otg->gadget)
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05301806 return -EBUSY;
1807
Ivan T. Ivanov591fc112015-04-09 11:34:22 +03001808 if (motg->id.conn.edev)
1809 extcon_unregister_interest(&motg->id.conn);
1810 if (motg->vbus.conn.edev)
1811 extcon_unregister_interest(&motg->vbus.conn);
1812
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05301813 msm_otg_debugfs_cleanup();
Pavankumar Kondetid8608522011-05-04 10:19:47 +05301814 cancel_delayed_work_sync(&motg->chg_work);
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05301815 cancel_work_sync(&motg->sm_work);
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05301816
Pavankumar Kondeti70187732011-02-15 09:42:34 +05301817 pm_runtime_resume(&pdev->dev);
Pavankumar Kondeti87c01042010-12-07 17:53:58 +05301818
1819 device_init_wakeup(&pdev->dev, 0);
1820 pm_runtime_disable(&pdev->dev);
1821
Kishon Vijay Abraham I662dca52012-06-22 17:02:46 +05301822 usb_remove_phy(phy);
Ivan T. Ivanov6b99c68e2014-04-28 16:34:08 +03001823 disable_irq(motg->irq);
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05301824
Pavankumar Kondeti87c01042010-12-07 17:53:58 +05301825 /*
1826 * Put PHY in low power mode.
1827 */
Heikki Krogerus1d4c9292012-02-13 13:24:09 +02001828 ulpi_read(phy, 0x14);
1829 ulpi_write(phy, 0x08, 0x09);
Pavankumar Kondeti87c01042010-12-07 17:53:58 +05301830
1831 writel(readl(USB_PORTSC) | PORTSC_PHCD, USB_PORTSC);
1832 while (cnt < PHY_SUSPEND_TIMEOUT_USEC) {
1833 if (readl(USB_PORTSC) & PORTSC_PHCD)
1834 break;
1835 udelay(1);
1836 cnt++;
1837 }
1838 if (cnt >= PHY_SUSPEND_TIMEOUT_USEC)
Heikki Krogerus1d4c9292012-02-13 13:24:09 +02001839 dev_err(phy->dev, "Unable to suspend PHY\n");
Pavankumar Kondeti87c01042010-12-07 17:53:58 +05301840
Stephen Boydb99a8f62013-06-17 10:43:10 -07001841 clk_disable_unprepare(motg->pclk);
1842 clk_disable_unprepare(motg->clk);
Ivan T. Ivanov6b99c68e2014-04-28 16:34:08 +03001843 if (!IS_ERR(motg->core_clk))
Stephen Boydb99a8f62013-06-17 10:43:10 -07001844 clk_disable_unprepare(motg->core_clk);
Anji jonnala11aa5c42011-05-04 10:19:48 +05301845 msm_hsusb_ldo_init(motg, 0);
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05301846
Pavankumar Kondeti87c01042010-12-07 17:53:58 +05301847 pm_runtime_set_suspended(&pdev->dev);
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05301848
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05301849 return 0;
1850}
1851
Rafael J. Wysockiceb6c9c2014-11-29 23:47:05 +01001852#ifdef CONFIG_PM
Pavankumar Kondeti87c01042010-12-07 17:53:58 +05301853static int msm_otg_runtime_idle(struct device *dev)
1854{
1855 struct msm_otg *motg = dev_get_drvdata(dev);
Heikki Krogerus1d4c9292012-02-13 13:24:09 +02001856 struct usb_otg *otg = motg->phy.otg;
Pavankumar Kondeti87c01042010-12-07 17:53:58 +05301857
1858 dev_dbg(dev, "OTG runtime idle\n");
1859
1860 /*
1861 * It is observed some times that a spurious interrupt
1862 * comes when PHY is put into LPM immediately after PHY reset.
1863 * This 1 sec delay also prevents entering into LPM immediately
1864 * after asynchronous interrupt.
1865 */
Antoine Tenarte47d9252014-10-30 18:41:13 +01001866 if (otg->state != OTG_STATE_UNDEFINED)
Pavankumar Kondeti87c01042010-12-07 17:53:58 +05301867 pm_schedule_suspend(dev, 1000);
1868
1869 return -EAGAIN;
1870}
1871
1872static int msm_otg_runtime_suspend(struct device *dev)
1873{
1874 struct msm_otg *motg = dev_get_drvdata(dev);
1875
1876 dev_dbg(dev, "OTG runtime suspend\n");
1877 return msm_otg_suspend(motg);
1878}
1879
1880static int msm_otg_runtime_resume(struct device *dev)
1881{
1882 struct msm_otg *motg = dev_get_drvdata(dev);
1883
1884 dev_dbg(dev, "OTG runtime resume\n");
1885 return msm_otg_resume(motg);
1886}
Pavankumar Kondeti87c01042010-12-07 17:53:58 +05301887#endif
1888
Pavankumar Kondeti70187732011-02-15 09:42:34 +05301889#ifdef CONFIG_PM_SLEEP
Pavankumar Kondeti87c01042010-12-07 17:53:58 +05301890static int msm_otg_pm_suspend(struct device *dev)
1891{
1892 struct msm_otg *motg = dev_get_drvdata(dev);
1893
1894 dev_dbg(dev, "OTG PM suspend\n");
1895 return msm_otg_suspend(motg);
1896}
1897
1898static int msm_otg_pm_resume(struct device *dev)
1899{
1900 struct msm_otg *motg = dev_get_drvdata(dev);
1901 int ret;
1902
1903 dev_dbg(dev, "OTG PM resume\n");
1904
1905 ret = msm_otg_resume(motg);
1906 if (ret)
1907 return ret;
1908
1909 /*
1910 * Runtime PM Documentation recommends bringing the
1911 * device to full powered state upon resume.
1912 */
1913 pm_runtime_disable(dev);
1914 pm_runtime_set_active(dev);
1915 pm_runtime_enable(dev);
1916
1917 return 0;
1918}
Pavankumar Kondeti87c01042010-12-07 17:53:58 +05301919#endif
1920
1921static const struct dev_pm_ops msm_otg_dev_pm_ops = {
Pavankumar Kondeti70187732011-02-15 09:42:34 +05301922 SET_SYSTEM_SLEEP_PM_OPS(msm_otg_pm_suspend, msm_otg_pm_resume)
1923 SET_RUNTIME_PM_OPS(msm_otg_runtime_suspend, msm_otg_runtime_resume,
1924 msm_otg_runtime_idle)
Pavankumar Kondeti87c01042010-12-07 17:53:58 +05301925};
1926
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05301927static struct platform_driver msm_otg_driver = {
Ivan T. Ivanov06a6ec42014-04-28 16:34:07 +03001928 .probe = msm_otg_probe,
Bill Pemberton76904172012-11-19 13:21:08 -05001929 .remove = msm_otg_remove,
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05301930 .driver = {
1931 .name = DRIVER_NAME,
Pavankumar Kondeti87c01042010-12-07 17:53:58 +05301932 .pm = &msm_otg_dev_pm_ops,
Ivan T. Ivanov8364f9a2014-04-28 16:34:15 +03001933 .of_match_table = msm_otg_dt_match,
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05301934 },
1935};
1936
Ivan T. Ivanov06a6ec42014-04-28 16:34:07 +03001937module_platform_driver(msm_otg_driver);
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05301938
1939MODULE_LICENSE("GPL v2");
1940MODULE_DESCRIPTION("MSM USB transceiver driver");