blob: 8fb86a5f458e01275186dc83ff86e38b38fff35b [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>
Arnd Bergmannb9b09232016-05-18 23:24:06 +020021#include <linux/extcon.h>
Ivan T. Ivanov6f98f542015-07-28 11:10:22 +030022#include <linux/gpio/consumer.h>
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +053023#include <linux/platform_device.h>
24#include <linux/clk.h>
25#include <linux/slab.h>
26#include <linux/interrupt.h>
27#include <linux/err.h>
28#include <linux/delay.h>
29#include <linux/io.h>
30#include <linux/ioport.h>
31#include <linux/uaccess.h>
32#include <linux/debugfs.h>
33#include <linux/seq_file.h>
Pavankumar Kondeti87c01042010-12-07 17:53:58 +053034#include <linux/pm_runtime.h>
Ivan T. Ivanov8364f9a2014-04-28 16:34:15 +030035#include <linux/of.h>
36#include <linux/of_device.h>
Ivan T. Ivanov6f98f542015-07-28 11:10:22 +030037#include <linux/reboot.h>
Ivan T. Ivanova2734542014-04-28 16:34:16 +030038#include <linux/reset.h>
Arnd Bergmannb9b09232016-05-18 23:24:06 +020039#include <linux/types.h>
40#include <linux/usb/otg.h>
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +053041
42#include <linux/usb.h>
43#include <linux/usb/otg.h>
Ivan T. Ivanov8364f9a2014-04-28 16:34:15 +030044#include <linux/usb/of.h>
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +053045#include <linux/usb/ulpi.h>
46#include <linux/usb/gadget.h>
47#include <linux/usb/hcd.h>
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +053048#include <linux/usb/msm_hsusb_hw.h>
Anji jonnala11aa5c42011-05-04 10:19:48 +053049#include <linux/regulator/consumer.h>
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +053050
Arnd Bergmannb9b09232016-05-18 23:24:06 +020051/**
52 * OTG control
53 *
54 * OTG_NO_CONTROL Id/VBUS notifications not required. Useful in host
55 * only configuration.
56 * OTG_PHY_CONTROL Id/VBUS notifications comes form USB PHY.
57 * OTG_PMIC_CONTROL Id/VBUS notifications comes from PMIC hardware.
58 * OTG_USER_CONTROL Id/VBUS notifcations comes from User via sysfs.
59 *
60 */
61enum otg_control_type {
62 OTG_NO_CONTROL = 0,
63 OTG_PHY_CONTROL,
64 OTG_PMIC_CONTROL,
65 OTG_USER_CONTROL,
66};
67
68/**
69 * PHY used in
70 *
71 * INVALID_PHY Unsupported PHY
72 * CI_45NM_INTEGRATED_PHY Chipidea 45nm integrated PHY
73 * SNPS_28NM_INTEGRATED_PHY Synopsis 28nm integrated PHY
74 *
75 */
76enum msm_usb_phy_type {
77 INVALID_PHY = 0,
78 CI_45NM_INTEGRATED_PHY,
79 SNPS_28NM_INTEGRATED_PHY,
80};
81
82#define IDEV_CHG_MAX 1500
83#define IUNIT 100
84
85/**
86 * Different states involved in USB charger detection.
87 *
88 * USB_CHG_STATE_UNDEFINED USB charger is not connected or detection
89 * process is not yet started.
90 * USB_CHG_STATE_WAIT_FOR_DCD Waiting for Data pins contact.
91 * USB_CHG_STATE_DCD_DONE Data pin contact is detected.
92 * USB_CHG_STATE_PRIMARY_DONE Primary detection is completed (Detects
93 * between SDP and DCP/CDP).
94 * USB_CHG_STATE_SECONDARY_DONE Secondary detection is completed (Detects
95 * between DCP and CDP).
96 * USB_CHG_STATE_DETECTED USB charger type is determined.
97 *
98 */
99enum usb_chg_state {
100 USB_CHG_STATE_UNDEFINED = 0,
101 USB_CHG_STATE_WAIT_FOR_DCD,
102 USB_CHG_STATE_DCD_DONE,
103 USB_CHG_STATE_PRIMARY_DONE,
104 USB_CHG_STATE_SECONDARY_DONE,
105 USB_CHG_STATE_DETECTED,
106};
107
108/**
109 * USB charger types
110 *
111 * USB_INVALID_CHARGER Invalid USB charger.
112 * USB_SDP_CHARGER Standard downstream port. Refers to a downstream port
113 * on USB2.0 compliant host/hub.
114 * USB_DCP_CHARGER Dedicated charger port (AC charger/ Wall charger).
115 * USB_CDP_CHARGER Charging downstream port. Enumeration can happen and
116 * IDEV_CHG_MAX can be drawn irrespective of USB state.
117 *
118 */
119enum usb_chg_type {
120 USB_INVALID_CHARGER = 0,
121 USB_SDP_CHARGER,
122 USB_DCP_CHARGER,
123 USB_CDP_CHARGER,
124};
125
126/**
127 * struct msm_otg_platform_data - platform device data
128 * for msm_otg driver.
129 * @phy_init_seq: PHY configuration sequence values. Value of -1 is reserved as
130 * "do not overwrite default vaule at this address".
131 * @phy_init_sz: PHY configuration sequence size.
132 * @vbus_power: VBUS power on/off routine.
133 * @power_budget: VBUS power budget in mA (0 will be treated as 500mA).
134 * @mode: Supported mode (OTG/peripheral/host).
135 * @otg_control: OTG switch controlled by user/Id pin
136 */
137struct msm_otg_platform_data {
138 int *phy_init_seq;
139 int phy_init_sz;
140 void (*vbus_power)(bool on);
141 unsigned power_budget;
142 enum usb_dr_mode mode;
143 enum otg_control_type otg_control;
144 enum msm_usb_phy_type phy_type;
145 void (*setup_gpio)(enum usb_otg_state state);
146};
147
148/**
Arnd Bergmannb9b09232016-05-18 23:24:06 +0200149 * struct msm_otg: OTG driver data. Shared by HCD and DCD.
150 * @otg: USB OTG Transceiver structure.
151 * @pdata: otg device platform data.
152 * @irq: IRQ number assigned for HSUSB controller.
153 * @clk: clock struct of usb_hs_clk.
154 * @pclk: clock struct of usb_hs_pclk.
155 * @core_clk: clock struct of usb_hs_core_clk.
156 * @regs: ioremapped register base address.
157 * @inputs: OTG state machine inputs(Id, SessValid etc).
158 * @sm_work: OTG state machine work.
159 * @in_lpm: indicates low power mode (LPM) state.
160 * @async_int: Async interrupt arrived.
161 * @cur_power: The amount of mA available from downstream port.
162 * @chg_work: Charger detection work.
163 * @chg_state: The state of charger detection process.
164 * @chg_type: The type of charger attached.
165 * @dcd_retires: The retry count used to track Data contact
166 * detection process.
167 * @manual_pullup: true if VBUS is not routed to USB controller/phy
168 * and controller driver therefore enables pull-up explicitly before
169 * starting controller using usbcmd run/stop bit.
170 * @vbus: VBUS signal state trakining, using extcon framework
171 * @id: ID signal state trakining, using extcon framework
172 * @switch_gpio: Descriptor for GPIO used to control external Dual
173 * SPDT USB Switch.
174 * @reboot: Used to inform the driver to route USB D+/D- line to Device
175 * connector
176 */
177struct msm_otg {
178 struct usb_phy phy;
179 struct msm_otg_platform_data *pdata;
180 int irq;
181 struct clk *clk;
182 struct clk *pclk;
183 struct clk *core_clk;
184 void __iomem *regs;
185#define ID 0
186#define B_SESS_VLD 1
187 unsigned long inputs;
188 struct work_struct sm_work;
189 atomic_t in_lpm;
190 int async_int;
191 unsigned cur_power;
192 int phy_number;
193 struct delayed_work chg_work;
194 enum usb_chg_state chg_state;
195 enum usb_chg_type chg_type;
196 u8 dcd_retries;
197 struct regulator *v3p3;
198 struct regulator *v1p8;
199 struct regulator *vddcx;
200
201 struct reset_control *phy_rst;
202 struct reset_control *link_rst;
203 int vdd_levels[3];
204
205 bool manual_pullup;
206
Arnd Bergmannb9b09232016-05-18 23:24:06 +0200207 struct gpio_desc *switch_gpio;
208 struct notifier_block reboot;
209};
210
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +0530211#define MSM_USB_BASE (motg->regs)
212#define DRIVER_NAME "msm_otg"
213
214#define ULPI_IO_TIMEOUT_USEC (10 * 1000)
Ivan T. Ivanovd69c6f52014-04-28 16:34:18 +0300215#define LINK_RESET_TIMEOUT_USEC (250 * 1000)
Anji jonnala11aa5c42011-05-04 10:19:48 +0530216
217#define USB_PHY_3P3_VOL_MIN 3050000 /* uV */
218#define USB_PHY_3P3_VOL_MAX 3300000 /* uV */
219#define USB_PHY_3P3_HPM_LOAD 50000 /* uA */
220#define USB_PHY_3P3_LPM_LOAD 4000 /* uA */
221
222#define USB_PHY_1P8_VOL_MIN 1800000 /* uV */
223#define USB_PHY_1P8_VOL_MAX 1800000 /* uV */
224#define USB_PHY_1P8_HPM_LOAD 50000 /* uA */
225#define USB_PHY_1P8_LPM_LOAD 4000 /* uA */
226
227#define USB_PHY_VDD_DIG_VOL_MIN 1000000 /* uV */
228#define USB_PHY_VDD_DIG_VOL_MAX 1320000 /* uV */
Ivan T. Ivanov01799b62014-04-28 16:34:22 +0300229#define USB_PHY_SUSP_DIG_VOL 500000 /* uV */
230
231enum vdd_levels {
232 VDD_LEVEL_NONE = 0,
233 VDD_LEVEL_MIN,
234 VDD_LEVEL_MAX,
235};
Anji jonnala11aa5c42011-05-04 10:19:48 +0530236
Anji jonnala11aa5c42011-05-04 10:19:48 +0530237static int msm_hsusb_init_vddcx(struct msm_otg *motg, int init)
238{
239 int ret = 0;
240
241 if (init) {
Ivan T. Ivanov37cfdaf2014-04-28 16:34:06 +0300242 ret = regulator_set_voltage(motg->vddcx,
Ivan T. Ivanov01799b62014-04-28 16:34:22 +0300243 motg->vdd_levels[VDD_LEVEL_MIN],
244 motg->vdd_levels[VDD_LEVEL_MAX]);
Anji jonnala11aa5c42011-05-04 10:19:48 +0530245 if (ret) {
Ivan T. Ivanov3aca0fa2014-04-28 16:34:10 +0300246 dev_err(motg->phy.dev, "Cannot set vddcx voltage\n");
Anji jonnala11aa5c42011-05-04 10:19:48 +0530247 return ret;
248 }
249
Ivan T. Ivanov37cfdaf2014-04-28 16:34:06 +0300250 ret = regulator_enable(motg->vddcx);
Ivan T. Ivanov6b99c68e2014-04-28 16:34:08 +0300251 if (ret)
Heikki Krogerus1d4c9292012-02-13 13:24:09 +0200252 dev_err(motg->phy.dev, "unable to enable hsusb vddcx\n");
Anji jonnala11aa5c42011-05-04 10:19:48 +0530253 } else {
Ivan T. Ivanov37cfdaf2014-04-28 16:34:06 +0300254 ret = regulator_set_voltage(motg->vddcx, 0,
Ivan T. Ivanov01799b62014-04-28 16:34:22 +0300255 motg->vdd_levels[VDD_LEVEL_MAX]);
Mark Browne99c4302011-05-15 09:55:58 -0700256 if (ret)
Ivan T. Ivanov3aca0fa2014-04-28 16:34:10 +0300257 dev_err(motg->phy.dev, "Cannot set vddcx voltage\n");
Ivan T. Ivanov37cfdaf2014-04-28 16:34:06 +0300258 ret = regulator_disable(motg->vddcx);
Anji jonnala11aa5c42011-05-04 10:19:48 +0530259 if (ret)
Heikki Krogerus1d4c9292012-02-13 13:24:09 +0200260 dev_err(motg->phy.dev, "unable to disable hsusb vddcx\n");
Anji jonnala11aa5c42011-05-04 10:19:48 +0530261 }
262
263 return ret;
264}
265
266static int msm_hsusb_ldo_init(struct msm_otg *motg, int init)
267{
268 int rc = 0;
269
270 if (init) {
Ivan T. Ivanov37cfdaf2014-04-28 16:34:06 +0300271 rc = regulator_set_voltage(motg->v3p3, USB_PHY_3P3_VOL_MIN,
Anji jonnala11aa5c42011-05-04 10:19:48 +0530272 USB_PHY_3P3_VOL_MAX);
273 if (rc) {
Ivan T. Ivanov3aca0fa2014-04-28 16:34:10 +0300274 dev_err(motg->phy.dev, "Cannot set v3p3 voltage\n");
Ivan T. Ivanov6b99c68e2014-04-28 16:34:08 +0300275 goto exit;
Anji jonnala11aa5c42011-05-04 10:19:48 +0530276 }
Ivan T. Ivanov37cfdaf2014-04-28 16:34:06 +0300277 rc = regulator_enable(motg->v3p3);
Anji jonnala11aa5c42011-05-04 10:19:48 +0530278 if (rc) {
Heikki Krogerus1d4c9292012-02-13 13:24:09 +0200279 dev_err(motg->phy.dev, "unable to enable the hsusb 3p3\n");
Ivan T. Ivanov6b99c68e2014-04-28 16:34:08 +0300280 goto exit;
Anji jonnala11aa5c42011-05-04 10:19:48 +0530281 }
Ivan T. Ivanov37cfdaf2014-04-28 16:34:06 +0300282 rc = regulator_set_voltage(motg->v1p8, USB_PHY_1P8_VOL_MIN,
Anji jonnala11aa5c42011-05-04 10:19:48 +0530283 USB_PHY_1P8_VOL_MAX);
284 if (rc) {
Ivan T. Ivanov3aca0fa2014-04-28 16:34:10 +0300285 dev_err(motg->phy.dev, "Cannot set v1p8 voltage\n");
Ivan T. Ivanov6b99c68e2014-04-28 16:34:08 +0300286 goto disable_3p3;
Anji jonnala11aa5c42011-05-04 10:19:48 +0530287 }
Ivan T. Ivanov37cfdaf2014-04-28 16:34:06 +0300288 rc = regulator_enable(motg->v1p8);
Anji jonnala11aa5c42011-05-04 10:19:48 +0530289 if (rc) {
Heikki Krogerus1d4c9292012-02-13 13:24:09 +0200290 dev_err(motg->phy.dev, "unable to enable the hsusb 1p8\n");
Ivan T. Ivanov6b99c68e2014-04-28 16:34:08 +0300291 goto disable_3p3;
Anji jonnala11aa5c42011-05-04 10:19:48 +0530292 }
293
294 return 0;
295 }
296
Ivan T. Ivanov37cfdaf2014-04-28 16:34:06 +0300297 regulator_disable(motg->v1p8);
Anji jonnala11aa5c42011-05-04 10:19:48 +0530298disable_3p3:
Ivan T. Ivanov37cfdaf2014-04-28 16:34:06 +0300299 regulator_disable(motg->v3p3);
Ivan T. Ivanov6b99c68e2014-04-28 16:34:08 +0300300exit:
Anji jonnala11aa5c42011-05-04 10:19:48 +0530301 return rc;
302}
303
Ivan T. Ivanov37cfdaf2014-04-28 16:34:06 +0300304static int msm_hsusb_ldo_set_mode(struct msm_otg *motg, int on)
Anji jonnala11aa5c42011-05-04 10:19:48 +0530305{
306 int ret = 0;
307
Anji jonnala11aa5c42011-05-04 10:19:48 +0530308 if (on) {
Bjorn Anderssonfa53e352015-02-11 19:35:30 -0800309 ret = regulator_set_load(motg->v1p8, USB_PHY_1P8_HPM_LOAD);
Anji jonnala11aa5c42011-05-04 10:19:48 +0530310 if (ret < 0) {
Ivan T. Ivanov3aca0fa2014-04-28 16:34:10 +0300311 pr_err("Could not set HPM for v1p8\n");
Anji jonnala11aa5c42011-05-04 10:19:48 +0530312 return ret;
313 }
Bjorn Anderssonfa53e352015-02-11 19:35:30 -0800314 ret = regulator_set_load(motg->v3p3, USB_PHY_3P3_HPM_LOAD);
Anji jonnala11aa5c42011-05-04 10:19:48 +0530315 if (ret < 0) {
Ivan T. Ivanov3aca0fa2014-04-28 16:34:10 +0300316 pr_err("Could not set HPM for v3p3\n");
Bjorn Anderssonfa53e352015-02-11 19:35:30 -0800317 regulator_set_load(motg->v1p8, USB_PHY_1P8_LPM_LOAD);
Anji jonnala11aa5c42011-05-04 10:19:48 +0530318 return ret;
319 }
320 } else {
Bjorn Anderssonfa53e352015-02-11 19:35:30 -0800321 ret = regulator_set_load(motg->v1p8, USB_PHY_1P8_LPM_LOAD);
Anji jonnala11aa5c42011-05-04 10:19:48 +0530322 if (ret < 0)
Ivan T. Ivanov3aca0fa2014-04-28 16:34:10 +0300323 pr_err("Could not set LPM for v1p8\n");
Bjorn Anderssonfa53e352015-02-11 19:35:30 -0800324 ret = regulator_set_load(motg->v3p3, USB_PHY_3P3_LPM_LOAD);
Anji jonnala11aa5c42011-05-04 10:19:48 +0530325 if (ret < 0)
Ivan T. Ivanov3aca0fa2014-04-28 16:34:10 +0300326 pr_err("Could not set LPM for v3p3\n");
Anji jonnala11aa5c42011-05-04 10:19:48 +0530327 }
328
329 pr_debug("reg (%s)\n", on ? "HPM" : "LPM");
330 return ret < 0 ? ret : 0;
331}
332
Heikki Krogerus1d4c9292012-02-13 13:24:09 +0200333static int ulpi_read(struct usb_phy *phy, u32 reg)
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +0530334{
Heikki Krogerus1d4c9292012-02-13 13:24:09 +0200335 struct msm_otg *motg = container_of(phy, struct msm_otg, phy);
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +0530336 int cnt = 0;
337
338 /* initiate read operation */
339 writel(ULPI_RUN | ULPI_READ | ULPI_ADDR(reg),
340 USB_ULPI_VIEWPORT);
341
342 /* wait for completion */
343 while (cnt < ULPI_IO_TIMEOUT_USEC) {
344 if (!(readl(USB_ULPI_VIEWPORT) & ULPI_RUN))
345 break;
346 udelay(1);
347 cnt++;
348 }
349
350 if (cnt >= ULPI_IO_TIMEOUT_USEC) {
Heikki Krogerus1d4c9292012-02-13 13:24:09 +0200351 dev_err(phy->dev, "ulpi_read: timeout %08x\n",
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +0530352 readl(USB_ULPI_VIEWPORT));
353 return -ETIMEDOUT;
354 }
355 return ULPI_DATA_READ(readl(USB_ULPI_VIEWPORT));
356}
357
Heikki Krogerus1d4c9292012-02-13 13:24:09 +0200358static int ulpi_write(struct usb_phy *phy, u32 val, u32 reg)
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +0530359{
Heikki Krogerus1d4c9292012-02-13 13:24:09 +0200360 struct msm_otg *motg = container_of(phy, struct msm_otg, phy);
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +0530361 int cnt = 0;
362
363 /* initiate write operation */
364 writel(ULPI_RUN | ULPI_WRITE |
365 ULPI_ADDR(reg) | ULPI_DATA(val),
366 USB_ULPI_VIEWPORT);
367
368 /* wait for completion */
369 while (cnt < ULPI_IO_TIMEOUT_USEC) {
370 if (!(readl(USB_ULPI_VIEWPORT) & ULPI_RUN))
371 break;
372 udelay(1);
373 cnt++;
374 }
375
376 if (cnt >= ULPI_IO_TIMEOUT_USEC) {
Heikki Krogerus1d4c9292012-02-13 13:24:09 +0200377 dev_err(phy->dev, "ulpi_write: timeout\n");
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +0530378 return -ETIMEDOUT;
379 }
380 return 0;
381}
382
Heikki Krogerus1d4c9292012-02-13 13:24:09 +0200383static struct usb_phy_io_ops msm_otg_io_ops = {
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +0530384 .read = ulpi_read,
385 .write = ulpi_write,
386};
387
388static void ulpi_init(struct msm_otg *motg)
389{
390 struct msm_otg_platform_data *pdata = motg->pdata;
Ivan T. Ivanov8364f9a2014-04-28 16:34:15 +0300391 int *seq = pdata->phy_init_seq, idx;
392 u32 addr = ULPI_EXT_VENDOR_SPECIFIC;
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +0530393
Ivan T. Ivanov8364f9a2014-04-28 16:34:15 +0300394 for (idx = 0; idx < pdata->phy_init_sz; idx++) {
395 if (seq[idx] == -1)
396 continue;
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +0530397
Heikki Krogerus1d4c9292012-02-13 13:24:09 +0200398 dev_vdbg(motg->phy.dev, "ulpi: write 0x%02x to 0x%02x\n",
Ivan T. Ivanov8364f9a2014-04-28 16:34:15 +0300399 seq[idx], addr + idx);
400 ulpi_write(&motg->phy, seq[idx], addr + idx);
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +0530401 }
402}
403
Ivan T. Ivanov349907c2014-04-28 16:34:21 +0300404static int msm_phy_notify_disconnect(struct usb_phy *phy,
405 enum usb_device_speed speed)
406{
Ivan T. Ivanov44e42ae2015-04-09 11:34:33 +0300407 struct msm_otg *motg = container_of(phy, struct msm_otg, phy);
Ivan T. Ivanov349907c2014-04-28 16:34:21 +0300408 int val;
409
Ivan T. Ivanov44e42ae2015-04-09 11:34:33 +0300410 if (motg->manual_pullup) {
411 val = ULPI_MISC_A_VBUSVLDEXT | ULPI_MISC_A_VBUSVLDEXTSEL;
412 usb_phy_io_write(phy, val, ULPI_CLR(ULPI_MISC_A));
413 }
414
Ivan T. Ivanov349907c2014-04-28 16:34:21 +0300415 /*
416 * Put the transceiver in non-driving mode. Otherwise host
417 * may not detect soft-disconnection.
418 */
419 val = ulpi_read(phy, ULPI_FUNC_CTRL);
420 val &= ~ULPI_FUNC_CTRL_OPMODE_MASK;
421 val |= ULPI_FUNC_CTRL_OPMODE_NONDRIVING;
422 ulpi_write(phy, val, ULPI_FUNC_CTRL);
423
424 return 0;
425}
426
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +0530427static int msm_otg_link_clk_reset(struct msm_otg *motg, bool assert)
428{
Ivan T. Ivanova2734542014-04-28 16:34:16 +0300429 int ret;
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +0530430
Stephen Boyd32fc9eb2015-03-13 11:09:42 -0700431 if (assert)
Ivan T. Ivanova2734542014-04-28 16:34:16 +0300432 ret = reset_control_assert(motg->link_rst);
433 else
434 ret = reset_control_deassert(motg->link_rst);
Ivan T. Ivanov5146d772013-12-30 13:15:27 -0800435
Ivan T. Ivanov5146d772013-12-30 13:15:27 -0800436 if (ret)
437 dev_err(motg->phy.dev, "usb link clk reset %s failed\n",
438 assert ? "assert" : "deassert");
439
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +0530440 return ret;
441}
442
443static int msm_otg_phy_clk_reset(struct msm_otg *motg)
444{
Srinivas Kandagatlae44f1f42014-06-30 18:29:49 +0100445 int ret = 0;
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +0530446
Stephen Boyd32fc9eb2015-03-13 11:09:42 -0700447 if (motg->phy_rst)
Ivan T. Ivanova2734542014-04-28 16:34:16 +0300448 ret = reset_control_reset(motg->phy_rst);
Ivan T. Ivanov5146d772013-12-30 13:15:27 -0800449
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +0530450 if (ret)
Ivan T. Ivanov5146d772013-12-30 13:15:27 -0800451 dev_err(motg->phy.dev, "usb phy clk reset failed\n");
452
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +0530453 return ret;
454}
455
Ivan T. Ivanovd69c6f52014-04-28 16:34:18 +0300456static int msm_link_reset(struct msm_otg *motg)
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +0530457{
458 u32 val;
459 int ret;
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +0530460
461 ret = msm_otg_link_clk_reset(motg, 1);
462 if (ret)
463 return ret;
Ivan T. Ivanovd69c6f52014-04-28 16:34:18 +0300464
465 /* wait for 1ms delay as suggested in HPG. */
466 usleep_range(1000, 1200);
467
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +0530468 ret = msm_otg_link_clk_reset(motg, 0);
469 if (ret)
470 return ret;
471
Ivan T. Ivanovcfa3ff52014-04-28 16:34:17 +0300472 if (motg->phy_number)
473 writel(readl(USB_PHY_CTRL2) | BIT(16), USB_PHY_CTRL2);
474
Tim Bird9f27984b2014-04-28 16:34:19 +0300475 /* put transceiver in serial mode as part of reset */
Ivan T. Ivanovd69c6f52014-04-28 16:34:18 +0300476 val = readl(USB_PORTSC) & ~PORTSC_PTS_MASK;
Tim Bird9f27984b2014-04-28 16:34:19 +0300477 writel(val | PORTSC_PTS_SERIAL, USB_PORTSC);
Ivan T. Ivanovd69c6f52014-04-28 16:34:18 +0300478
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +0530479 return 0;
480}
481
Heikki Krogerus1d4c9292012-02-13 13:24:09 +0200482static int msm_otg_reset(struct usb_phy *phy)
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +0530483{
Heikki Krogerus1d4c9292012-02-13 13:24:09 +0200484 struct msm_otg *motg = container_of(phy, struct msm_otg, phy);
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +0530485 int cnt = 0;
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +0530486
487 writel(USBCMD_RESET, USB_USBCMD);
488 while (cnt < LINK_RESET_TIMEOUT_USEC) {
489 if (!(readl(USB_USBCMD) & USBCMD_RESET))
490 break;
491 udelay(1);
492 cnt++;
493 }
494 if (cnt >= LINK_RESET_TIMEOUT_USEC)
495 return -ETIMEDOUT;
496
Tim Bird9f27984b2014-04-28 16:34:19 +0300497 /* select ULPI phy and clear other status/control bits in PORTSC */
498 writel(PORTSC_PTS_ULPI, USB_PORTSC);
499
Ivan T. Ivanovd69c6f52014-04-28 16:34:18 +0300500 writel(0x0, USB_AHBBURST);
501 writel(0x08, USB_AHBMODE);
502
503 if (motg->phy_number)
504 writel(readl(USB_PHY_CTRL2) | BIT(16), USB_PHY_CTRL2);
505 return 0;
506}
507
508static void msm_phy_reset(struct msm_otg *motg)
509{
510 void __iomem *addr;
511
512 if (motg->pdata->phy_type != SNPS_28NM_INTEGRATED_PHY) {
513 msm_otg_phy_clk_reset(motg);
514 return;
515 }
516
517 addr = USB_PHY_CTRL;
518 if (motg->phy_number)
519 addr = USB_PHY_CTRL2;
520
521 /* Assert USB PHY_POR */
522 writel(readl(addr) | PHY_POR_ASSERT, addr);
523
524 /*
525 * wait for minimum 10 microseconds as suggested in HPG.
526 * Use a slightly larger value since the exact value didn't
527 * work 100% of the time.
528 */
529 udelay(12);
530
531 /* Deassert USB PHY_POR */
532 writel(readl(addr) & ~PHY_POR_ASSERT, addr);
533}
534
535static int msm_usb_reset(struct usb_phy *phy)
536{
537 struct msm_otg *motg = container_of(phy, struct msm_otg, phy);
538 int ret;
539
540 if (!IS_ERR(motg->core_clk))
541 clk_prepare_enable(motg->core_clk);
542
543 ret = msm_link_reset(motg);
544 if (ret) {
545 dev_err(phy->dev, "phy_reset failed\n");
546 return ret;
547 }
548
549 ret = msm_otg_reset(&motg->phy);
550 if (ret) {
551 dev_err(phy->dev, "link reset failed\n");
552 return ret;
553 }
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +0530554
555 msleep(100);
556
Ivan T. Ivanovd69c6f52014-04-28 16:34:18 +0300557 /* Reset USB PHY after performing USB Link RESET */
558 msm_phy_reset(motg);
559
560 if (!IS_ERR(motg->core_clk))
561 clk_disable_unprepare(motg->core_clk);
562
563 return 0;
564}
565
566static int msm_phy_init(struct usb_phy *phy)
567{
568 struct msm_otg *motg = container_of(phy, struct msm_otg, phy);
569 struct msm_otg_platform_data *pdata = motg->pdata;
570 u32 val, ulpi_val = 0;
571
572 /* Program USB PHY Override registers. */
573 ulpi_init(motg);
574
575 /*
576 * It is recommended in HPG to reset USB PHY after programming
577 * USB PHY Override registers.
578 */
579 msm_phy_reset(motg);
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +0530580
581 if (pdata->otg_control == OTG_PHY_CONTROL) {
582 val = readl(USB_OTGSC);
Ivan T. Ivanov971232c2014-04-28 16:34:11 +0300583 if (pdata->mode == USB_DR_MODE_OTG) {
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +0530584 ulpi_val = ULPI_INT_IDGRD | ULPI_INT_SESS_VALID;
585 val |= OTGSC_IDIE | OTGSC_BSVIE;
Ivan T. Ivanov971232c2014-04-28 16:34:11 +0300586 } else if (pdata->mode == USB_DR_MODE_PERIPHERAL) {
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +0530587 ulpi_val = ULPI_INT_SESS_VALID;
588 val |= OTGSC_BSVIE;
589 }
590 writel(val, USB_OTGSC);
Heikki Krogerus1d4c9292012-02-13 13:24:09 +0200591 ulpi_write(phy, ulpi_val, ULPI_USB_INT_EN_RISE);
592 ulpi_write(phy, ulpi_val, ULPI_USB_INT_EN_FALL);
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +0530593 }
594
Ivan T. Ivanov44e42ae2015-04-09 11:34:33 +0300595 if (motg->manual_pullup) {
596 val = ULPI_MISC_A_VBUSVLDEXTSEL | ULPI_MISC_A_VBUSVLDEXT;
597 ulpi_write(phy, val, ULPI_SET(ULPI_MISC_A));
598
599 val = readl(USB_GENCONFIG_2);
600 val |= GENCONFIG_2_SESS_VLD_CTRL_EN;
601 writel(val, USB_GENCONFIG_2);
602
603 val = readl(USB_USBCMD);
604 val |= USBCMD_SESS_VLD_CTRL;
605 writel(val, USB_USBCMD);
606
607 val = ulpi_read(phy, ULPI_FUNC_CTRL);
608 val &= ~ULPI_FUNC_CTRL_OPMODE_MASK;
609 val |= ULPI_FUNC_CTRL_OPMODE_NORMAL;
610 ulpi_write(phy, val, ULPI_FUNC_CTRL);
611 }
612
Ivan T. Ivanovcfa3ff52014-04-28 16:34:17 +0300613 if (motg->phy_number)
614 writel(readl(USB_PHY_CTRL2) | BIT(16), USB_PHY_CTRL2);
615
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +0530616 return 0;
617}
618
Pavankumar Kondeti87c01042010-12-07 17:53:58 +0530619#define PHY_SUSPEND_TIMEOUT_USEC (500 * 1000)
Pavankumar Kondeti70187732011-02-15 09:42:34 +0530620#define PHY_RESUME_TIMEOUT_USEC (100 * 1000)
621
Josh Cartwrighte7d613d2014-02-18 10:36:29 -0600622#ifdef CONFIG_PM
623
Ivan T. Ivanov37cfdaf2014-04-28 16:34:06 +0300624static int msm_hsusb_config_vddcx(struct msm_otg *motg, int high)
Josh Cartwrighte7d613d2014-02-18 10:36:29 -0600625{
Ivan T. Ivanov01799b62014-04-28 16:34:22 +0300626 int max_vol = motg->vdd_levels[VDD_LEVEL_MAX];
Josh Cartwrighte7d613d2014-02-18 10:36:29 -0600627 int min_vol;
628 int ret;
629
630 if (high)
Ivan T. Ivanov01799b62014-04-28 16:34:22 +0300631 min_vol = motg->vdd_levels[VDD_LEVEL_MIN];
Josh Cartwrighte7d613d2014-02-18 10:36:29 -0600632 else
Ivan T. Ivanov01799b62014-04-28 16:34:22 +0300633 min_vol = motg->vdd_levels[VDD_LEVEL_NONE];
Josh Cartwrighte7d613d2014-02-18 10:36:29 -0600634
Ivan T. Ivanov37cfdaf2014-04-28 16:34:06 +0300635 ret = regulator_set_voltage(motg->vddcx, min_vol, max_vol);
Josh Cartwrighte7d613d2014-02-18 10:36:29 -0600636 if (ret) {
Ivan T. Ivanov3aca0fa2014-04-28 16:34:10 +0300637 pr_err("Cannot set vddcx voltage\n");
Josh Cartwrighte7d613d2014-02-18 10:36:29 -0600638 return ret;
639 }
640
641 pr_debug("%s: min_vol:%d max_vol:%d\n", __func__, min_vol, max_vol);
642
643 return ret;
644}
645
Pavankumar Kondeti87c01042010-12-07 17:53:58 +0530646static int msm_otg_suspend(struct msm_otg *motg)
647{
Heikki Krogerus1d4c9292012-02-13 13:24:09 +0200648 struct usb_phy *phy = &motg->phy;
649 struct usb_bus *bus = phy->otg->host;
Pavankumar Kondeti87c01042010-12-07 17:53:58 +0530650 struct msm_otg_platform_data *pdata = motg->pdata;
Ivan T. Ivanovcfa3ff52014-04-28 16:34:17 +0300651 void __iomem *addr;
Pavankumar Kondeti87c01042010-12-07 17:53:58 +0530652 int cnt = 0;
653
654 if (atomic_read(&motg->in_lpm))
655 return 0;
656
657 disable_irq(motg->irq);
658 /*
Pavankumar Kondeti04aebcb2011-05-04 10:19:49 +0530659 * Chipidea 45-nm PHY suspend sequence:
660 *
Pavankumar Kondeti87c01042010-12-07 17:53:58 +0530661 * Interrupt Latch Register auto-clear feature is not present
662 * in all PHY versions. Latch register is clear on read type.
663 * Clear latch register to avoid spurious wakeup from
664 * low power mode (LPM).
Pavankumar Kondeti04aebcb2011-05-04 10:19:49 +0530665 *
Pavankumar Kondeti87c01042010-12-07 17:53:58 +0530666 * PHY comparators are disabled when PHY enters into low power
667 * mode (LPM). Keep PHY comparators ON in LPM only when we expect
668 * VBUS/Id notifications from USB PHY. Otherwise turn off USB
669 * PHY comparators. This save significant amount of power.
Pavankumar Kondeti04aebcb2011-05-04 10:19:49 +0530670 *
Pavankumar Kondeti87c01042010-12-07 17:53:58 +0530671 * PLL is not turned off when PHY enters into low power mode (LPM).
672 * Disable PLL for maximum power savings.
673 */
Pavankumar Kondeti04aebcb2011-05-04 10:19:49 +0530674
675 if (motg->pdata->phy_type == CI_45NM_INTEGRATED_PHY) {
Heikki Krogerus1d4c9292012-02-13 13:24:09 +0200676 ulpi_read(phy, 0x14);
Pavankumar Kondeti04aebcb2011-05-04 10:19:49 +0530677 if (pdata->otg_control == OTG_PHY_CONTROL)
Heikki Krogerus1d4c9292012-02-13 13:24:09 +0200678 ulpi_write(phy, 0x01, 0x30);
679 ulpi_write(phy, 0x08, 0x09);
Pavankumar Kondeti04aebcb2011-05-04 10:19:49 +0530680 }
Pavankumar Kondeti87c01042010-12-07 17:53:58 +0530681
682 /*
683 * PHY may take some time or even fail to enter into low power
684 * mode (LPM). Hence poll for 500 msec and reset the PHY and link
685 * in failure case.
686 */
687 writel(readl(USB_PORTSC) | PORTSC_PHCD, USB_PORTSC);
688 while (cnt < PHY_SUSPEND_TIMEOUT_USEC) {
689 if (readl(USB_PORTSC) & PORTSC_PHCD)
690 break;
691 udelay(1);
692 cnt++;
693 }
694
695 if (cnt >= PHY_SUSPEND_TIMEOUT_USEC) {
Heikki Krogerus1d4c9292012-02-13 13:24:09 +0200696 dev_err(phy->dev, "Unable to suspend PHY\n");
697 msm_otg_reset(phy);
Pavankumar Kondeti87c01042010-12-07 17:53:58 +0530698 enable_irq(motg->irq);
699 return -ETIMEDOUT;
700 }
701
702 /*
703 * PHY has capability to generate interrupt asynchronously in low
704 * power mode (LPM). This interrupt is level triggered. So USB IRQ
705 * line must be disabled till async interrupt enable bit is cleared
706 * in USBCMD register. Assert STP (ULPI interface STOP signal) to
707 * block data communication from PHY.
708 */
709 writel(readl(USB_USBCMD) | ASYNC_INTR_CTRL | ULPI_STP_CTRL, USB_USBCMD);
710
Ivan T. Ivanovcfa3ff52014-04-28 16:34:17 +0300711 addr = USB_PHY_CTRL;
712 if (motg->phy_number)
713 addr = USB_PHY_CTRL2;
714
Pavankumar Kondeti04aebcb2011-05-04 10:19:49 +0530715 if (motg->pdata->phy_type == SNPS_28NM_INTEGRATED_PHY &&
716 motg->pdata->otg_control == OTG_PMIC_CONTROL)
Ivan T. Ivanovcfa3ff52014-04-28 16:34:17 +0300717 writel(readl(addr) | PHY_RETEN, addr);
Pavankumar Kondeti04aebcb2011-05-04 10:19:49 +0530718
Stephen Boydb99a8f62013-06-17 10:43:10 -0700719 clk_disable_unprepare(motg->pclk);
720 clk_disable_unprepare(motg->clk);
Ivan T. Ivanov6b99c68e2014-04-28 16:34:08 +0300721 if (!IS_ERR(motg->core_clk))
Stephen Boydb99a8f62013-06-17 10:43:10 -0700722 clk_disable_unprepare(motg->core_clk);
Pavankumar Kondeti87c01042010-12-07 17:53:58 +0530723
Pavankumar Kondeti04aebcb2011-05-04 10:19:49 +0530724 if (motg->pdata->phy_type == SNPS_28NM_INTEGRATED_PHY &&
725 motg->pdata->otg_control == OTG_PMIC_CONTROL) {
Ivan T. Ivanov37cfdaf2014-04-28 16:34:06 +0300726 msm_hsusb_ldo_set_mode(motg, 0);
727 msm_hsusb_config_vddcx(motg, 0);
Pavankumar Kondeti04aebcb2011-05-04 10:19:49 +0530728 }
729
Heikki Krogerus1d4c9292012-02-13 13:24:09 +0200730 if (device_may_wakeup(phy->dev))
Pavankumar Kondeti87c01042010-12-07 17:53:58 +0530731 enable_irq_wake(motg->irq);
732 if (bus)
733 clear_bit(HCD_FLAG_HW_ACCESSIBLE, &(bus_to_hcd(bus))->flags);
734
735 atomic_set(&motg->in_lpm, 1);
736 enable_irq(motg->irq);
737
Heikki Krogerus1d4c9292012-02-13 13:24:09 +0200738 dev_info(phy->dev, "USB in low power mode\n");
Pavankumar Kondeti87c01042010-12-07 17:53:58 +0530739
740 return 0;
741}
742
Pavankumar Kondeti87c01042010-12-07 17:53:58 +0530743static int msm_otg_resume(struct msm_otg *motg)
744{
Heikki Krogerus1d4c9292012-02-13 13:24:09 +0200745 struct usb_phy *phy = &motg->phy;
746 struct usb_bus *bus = phy->otg->host;
Ivan T. Ivanovcfa3ff52014-04-28 16:34:17 +0300747 void __iomem *addr;
Pavankumar Kondeti87c01042010-12-07 17:53:58 +0530748 int cnt = 0;
749 unsigned temp;
750
751 if (!atomic_read(&motg->in_lpm))
752 return 0;
753
Stephen Boydb99a8f62013-06-17 10:43:10 -0700754 clk_prepare_enable(motg->pclk);
755 clk_prepare_enable(motg->clk);
Ivan T. Ivanov6b99c68e2014-04-28 16:34:08 +0300756 if (!IS_ERR(motg->core_clk))
Stephen Boydb99a8f62013-06-17 10:43:10 -0700757 clk_prepare_enable(motg->core_clk);
Pavankumar Kondeti87c01042010-12-07 17:53:58 +0530758
Pavankumar Kondeti04aebcb2011-05-04 10:19:49 +0530759 if (motg->pdata->phy_type == SNPS_28NM_INTEGRATED_PHY &&
760 motg->pdata->otg_control == OTG_PMIC_CONTROL) {
Ivan T. Ivanovcfa3ff52014-04-28 16:34:17 +0300761
762 addr = USB_PHY_CTRL;
763 if (motg->phy_number)
764 addr = USB_PHY_CTRL2;
765
Ivan T. Ivanov37cfdaf2014-04-28 16:34:06 +0300766 msm_hsusb_ldo_set_mode(motg, 1);
767 msm_hsusb_config_vddcx(motg, 1);
Ivan T. Ivanovcfa3ff52014-04-28 16:34:17 +0300768 writel(readl(addr) & ~PHY_RETEN, addr);
Pavankumar Kondeti04aebcb2011-05-04 10:19:49 +0530769 }
770
Pavankumar Kondeti87c01042010-12-07 17:53:58 +0530771 temp = readl(USB_USBCMD);
772 temp &= ~ASYNC_INTR_CTRL;
773 temp &= ~ULPI_STP_CTRL;
774 writel(temp, USB_USBCMD);
775
776 /*
777 * PHY comes out of low power mode (LPM) in case of wakeup
778 * from asynchronous interrupt.
779 */
780 if (!(readl(USB_PORTSC) & PORTSC_PHCD))
781 goto skip_phy_resume;
782
783 writel(readl(USB_PORTSC) & ~PORTSC_PHCD, USB_PORTSC);
784 while (cnt < PHY_RESUME_TIMEOUT_USEC) {
785 if (!(readl(USB_PORTSC) & PORTSC_PHCD))
786 break;
787 udelay(1);
788 cnt++;
789 }
790
791 if (cnt >= PHY_RESUME_TIMEOUT_USEC) {
792 /*
793 * This is a fatal error. Reset the link and
794 * PHY. USB state can not be restored. Re-insertion
795 * of USB cable is the only way to get USB working.
796 */
Ivan T. Ivanov3aca0fa2014-04-28 16:34:10 +0300797 dev_err(phy->dev, "Unable to resume USB. Re-plugin the cable\n");
Heikki Krogerus1d4c9292012-02-13 13:24:09 +0200798 msm_otg_reset(phy);
Pavankumar Kondeti87c01042010-12-07 17:53:58 +0530799 }
800
801skip_phy_resume:
Heikki Krogerus1d4c9292012-02-13 13:24:09 +0200802 if (device_may_wakeup(phy->dev))
Pavankumar Kondeti87c01042010-12-07 17:53:58 +0530803 disable_irq_wake(motg->irq);
804 if (bus)
805 set_bit(HCD_FLAG_HW_ACCESSIBLE, &(bus_to_hcd(bus))->flags);
806
Pavankumar Kondeti2ce2c3a2011-05-02 11:56:33 +0530807 atomic_set(&motg->in_lpm, 0);
808
Pavankumar Kondeti87c01042010-12-07 17:53:58 +0530809 if (motg->async_int) {
810 motg->async_int = 0;
Heikki Krogerus1d4c9292012-02-13 13:24:09 +0200811 pm_runtime_put(phy->dev);
Pavankumar Kondeti87c01042010-12-07 17:53:58 +0530812 enable_irq(motg->irq);
813 }
814
Heikki Krogerus1d4c9292012-02-13 13:24:09 +0200815 dev_info(phy->dev, "USB exited from low power mode\n");
Pavankumar Kondeti87c01042010-12-07 17:53:58 +0530816
817 return 0;
818}
Pavankumar Kondeti70187732011-02-15 09:42:34 +0530819#endif
Pavankumar Kondeti87c01042010-12-07 17:53:58 +0530820
Pavankumar Kondetid8608522011-05-04 10:19:47 +0530821static void msm_otg_notify_charger(struct msm_otg *motg, unsigned mA)
822{
823 if (motg->cur_power == mA)
824 return;
825
826 /* TODO: Notify PMIC about available current */
Heikki Krogerus1d4c9292012-02-13 13:24:09 +0200827 dev_info(motg->phy.dev, "Avail curr from USB = %u\n", mA);
Pavankumar Kondetid8608522011-05-04 10:19:47 +0530828 motg->cur_power = mA;
829}
830
Heikki Krogerus1d4c9292012-02-13 13:24:09 +0200831static void msm_otg_start_host(struct usb_phy *phy, int on)
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +0530832{
Heikki Krogerus1d4c9292012-02-13 13:24:09 +0200833 struct msm_otg *motg = container_of(phy, struct msm_otg, phy);
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +0530834 struct msm_otg_platform_data *pdata = motg->pdata;
835 struct usb_hcd *hcd;
836
Heikki Krogerus1d4c9292012-02-13 13:24:09 +0200837 if (!phy->otg->host)
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +0530838 return;
839
Heikki Krogerus1d4c9292012-02-13 13:24:09 +0200840 hcd = bus_to_hcd(phy->otg->host);
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +0530841
842 if (on) {
Heikki Krogerus1d4c9292012-02-13 13:24:09 +0200843 dev_dbg(phy->dev, "host on\n");
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +0530844
845 if (pdata->vbus_power)
846 pdata->vbus_power(1);
847 /*
848 * Some boards have a switch cotrolled by gpio
849 * to enable/disable internal HUB. Enable internal
850 * HUB before kicking the host.
851 */
852 if (pdata->setup_gpio)
853 pdata->setup_gpio(OTG_STATE_A_HOST);
854#ifdef CONFIG_USB
855 usb_add_hcd(hcd, hcd->irq, IRQF_SHARED);
Peter Chen3c9740a2013-11-05 10:46:02 +0800856 device_wakeup_enable(hcd->self.controller);
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +0530857#endif
858 } else {
Heikki Krogerus1d4c9292012-02-13 13:24:09 +0200859 dev_dbg(phy->dev, "host off\n");
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +0530860
861#ifdef CONFIG_USB
862 usb_remove_hcd(hcd);
863#endif
864 if (pdata->setup_gpio)
865 pdata->setup_gpio(OTG_STATE_UNDEFINED);
866 if (pdata->vbus_power)
867 pdata->vbus_power(0);
868 }
869}
870
Heikki Krogerus1d4c9292012-02-13 13:24:09 +0200871static int msm_otg_set_host(struct usb_otg *otg, struct usb_bus *host)
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +0530872{
Antoine Tenart19c1eac2014-10-30 18:41:14 +0100873 struct msm_otg *motg = container_of(otg->usb_phy, struct msm_otg, phy);
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +0530874 struct usb_hcd *hcd;
875
876 /*
877 * Fail host registration if this board can support
878 * only peripheral configuration.
879 */
Ivan T. Ivanov971232c2014-04-28 16:34:11 +0300880 if (motg->pdata->mode == USB_DR_MODE_PERIPHERAL) {
Antoine Tenart19c1eac2014-10-30 18:41:14 +0100881 dev_info(otg->usb_phy->dev, "Host mode is not supported\n");
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +0530882 return -ENODEV;
883 }
884
885 if (!host) {
Antoine Tenarte47d9252014-10-30 18:41:13 +0100886 if (otg->state == OTG_STATE_A_HOST) {
Antoine Tenart19c1eac2014-10-30 18:41:14 +0100887 pm_runtime_get_sync(otg->usb_phy->dev);
888 msm_otg_start_host(otg->usb_phy, 0);
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +0530889 otg->host = NULL;
Antoine Tenarte47d9252014-10-30 18:41:13 +0100890 otg->state = OTG_STATE_UNDEFINED;
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +0530891 schedule_work(&motg->sm_work);
892 } else {
893 otg->host = NULL;
894 }
895
896 return 0;
897 }
898
899 hcd = bus_to_hcd(host);
900 hcd->power_budget = motg->pdata->power_budget;
901
902 otg->host = host;
Antoine Tenart19c1eac2014-10-30 18:41:14 +0100903 dev_dbg(otg->usb_phy->dev, "host driver registered w/ tranceiver\n");
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +0530904
Ivan T. Ivanov8de4b3a2016-02-05 19:17:09 +0000905 pm_runtime_get_sync(otg->usb_phy->dev);
906 schedule_work(&motg->sm_work);
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +0530907
908 return 0;
909}
910
Heikki Krogerus1d4c9292012-02-13 13:24:09 +0200911static void msm_otg_start_peripheral(struct usb_phy *phy, int on)
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +0530912{
Heikki Krogerus1d4c9292012-02-13 13:24:09 +0200913 struct msm_otg *motg = container_of(phy, struct msm_otg, phy);
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +0530914 struct msm_otg_platform_data *pdata = motg->pdata;
915
Heikki Krogerus1d4c9292012-02-13 13:24:09 +0200916 if (!phy->otg->gadget)
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +0530917 return;
918
919 if (on) {
Heikki Krogerus1d4c9292012-02-13 13:24:09 +0200920 dev_dbg(phy->dev, "gadget on\n");
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +0530921 /*
922 * Some boards have a switch cotrolled by gpio
923 * to enable/disable internal HUB. Disable internal
924 * HUB before kicking the gadget.
925 */
926 if (pdata->setup_gpio)
927 pdata->setup_gpio(OTG_STATE_B_PERIPHERAL);
Heikki Krogerus1d4c9292012-02-13 13:24:09 +0200928 usb_gadget_vbus_connect(phy->otg->gadget);
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +0530929 } else {
Heikki Krogerus1d4c9292012-02-13 13:24:09 +0200930 dev_dbg(phy->dev, "gadget off\n");
931 usb_gadget_vbus_disconnect(phy->otg->gadget);
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +0530932 if (pdata->setup_gpio)
933 pdata->setup_gpio(OTG_STATE_UNDEFINED);
934 }
935
936}
937
Heikki Krogerus1d4c9292012-02-13 13:24:09 +0200938static int msm_otg_set_peripheral(struct usb_otg *otg,
939 struct usb_gadget *gadget)
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +0530940{
Antoine Tenart19c1eac2014-10-30 18:41:14 +0100941 struct msm_otg *motg = container_of(otg->usb_phy, struct msm_otg, phy);
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +0530942
943 /*
944 * Fail peripheral registration if this board can support
945 * only host configuration.
946 */
Ivan T. Ivanov971232c2014-04-28 16:34:11 +0300947 if (motg->pdata->mode == USB_DR_MODE_HOST) {
Antoine Tenart19c1eac2014-10-30 18:41:14 +0100948 dev_info(otg->usb_phy->dev, "Peripheral mode is not supported\n");
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +0530949 return -ENODEV;
950 }
951
952 if (!gadget) {
Antoine Tenarte47d9252014-10-30 18:41:13 +0100953 if (otg->state == OTG_STATE_B_PERIPHERAL) {
Antoine Tenart19c1eac2014-10-30 18:41:14 +0100954 pm_runtime_get_sync(otg->usb_phy->dev);
955 msm_otg_start_peripheral(otg->usb_phy, 0);
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +0530956 otg->gadget = NULL;
Antoine Tenarte47d9252014-10-30 18:41:13 +0100957 otg->state = OTG_STATE_UNDEFINED;
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +0530958 schedule_work(&motg->sm_work);
959 } else {
960 otg->gadget = NULL;
961 }
962
963 return 0;
964 }
965 otg->gadget = gadget;
Antoine Tenart19c1eac2014-10-30 18:41:14 +0100966 dev_dbg(otg->usb_phy->dev,
967 "peripheral driver registered w/ tranceiver\n");
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +0530968
Ivan T. Ivanov8de4b3a2016-02-05 19:17:09 +0000969 pm_runtime_get_sync(otg->usb_phy->dev);
970 schedule_work(&motg->sm_work);
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +0530971
972 return 0;
973}
974
Pavankumar Kondetid8608522011-05-04 10:19:47 +0530975static bool msm_chg_check_secondary_det(struct msm_otg *motg)
976{
Heikki Krogerus1d4c9292012-02-13 13:24:09 +0200977 struct usb_phy *phy = &motg->phy;
Pavankumar Kondetid8608522011-05-04 10:19:47 +0530978 u32 chg_det;
979 bool ret = false;
980
981 switch (motg->pdata->phy_type) {
982 case CI_45NM_INTEGRATED_PHY:
Heikki Krogerus1d4c9292012-02-13 13:24:09 +0200983 chg_det = ulpi_read(phy, 0x34);
Pavankumar Kondetid8608522011-05-04 10:19:47 +0530984 ret = chg_det & (1 << 4);
985 break;
986 case SNPS_28NM_INTEGRATED_PHY:
Heikki Krogerus1d4c9292012-02-13 13:24:09 +0200987 chg_det = ulpi_read(phy, 0x87);
Pavankumar Kondetid8608522011-05-04 10:19:47 +0530988 ret = chg_det & 1;
989 break;
990 default:
991 break;
992 }
993 return ret;
994}
995
996static void msm_chg_enable_secondary_det(struct msm_otg *motg)
997{
Heikki Krogerus1d4c9292012-02-13 13:24:09 +0200998 struct usb_phy *phy = &motg->phy;
Pavankumar Kondetid8608522011-05-04 10:19:47 +0530999 u32 chg_det;
1000
1001 switch (motg->pdata->phy_type) {
1002 case CI_45NM_INTEGRATED_PHY:
Heikki Krogerus1d4c9292012-02-13 13:24:09 +02001003 chg_det = ulpi_read(phy, 0x34);
Pavankumar Kondetid8608522011-05-04 10:19:47 +05301004 /* Turn off charger block */
1005 chg_det |= ~(1 << 1);
Heikki Krogerus1d4c9292012-02-13 13:24:09 +02001006 ulpi_write(phy, chg_det, 0x34);
Pavankumar Kondetid8608522011-05-04 10:19:47 +05301007 udelay(20);
1008 /* control chg block via ULPI */
1009 chg_det &= ~(1 << 3);
Heikki Krogerus1d4c9292012-02-13 13:24:09 +02001010 ulpi_write(phy, chg_det, 0x34);
Pavankumar Kondetid8608522011-05-04 10:19:47 +05301011 /* put it in host mode for enabling D- source */
1012 chg_det &= ~(1 << 2);
Heikki Krogerus1d4c9292012-02-13 13:24:09 +02001013 ulpi_write(phy, chg_det, 0x34);
Pavankumar Kondetid8608522011-05-04 10:19:47 +05301014 /* Turn on chg detect block */
1015 chg_det &= ~(1 << 1);
Heikki Krogerus1d4c9292012-02-13 13:24:09 +02001016 ulpi_write(phy, chg_det, 0x34);
Pavankumar Kondetid8608522011-05-04 10:19:47 +05301017 udelay(20);
1018 /* enable chg detection */
1019 chg_det &= ~(1 << 0);
Heikki Krogerus1d4c9292012-02-13 13:24:09 +02001020 ulpi_write(phy, chg_det, 0x34);
Pavankumar Kondetid8608522011-05-04 10:19:47 +05301021 break;
1022 case SNPS_28NM_INTEGRATED_PHY:
1023 /*
1024 * Configure DM as current source, DP as current sink
1025 * and enable battery charging comparators.
1026 */
Heikki Krogerus1d4c9292012-02-13 13:24:09 +02001027 ulpi_write(phy, 0x8, 0x85);
1028 ulpi_write(phy, 0x2, 0x85);
1029 ulpi_write(phy, 0x1, 0x85);
Pavankumar Kondetid8608522011-05-04 10:19:47 +05301030 break;
1031 default:
1032 break;
1033 }
1034}
1035
1036static bool msm_chg_check_primary_det(struct msm_otg *motg)
1037{
Heikki Krogerus1d4c9292012-02-13 13:24:09 +02001038 struct usb_phy *phy = &motg->phy;
Pavankumar Kondetid8608522011-05-04 10:19:47 +05301039 u32 chg_det;
1040 bool ret = false;
1041
1042 switch (motg->pdata->phy_type) {
1043 case CI_45NM_INTEGRATED_PHY:
Heikki Krogerus1d4c9292012-02-13 13:24:09 +02001044 chg_det = ulpi_read(phy, 0x34);
Pavankumar Kondetid8608522011-05-04 10:19:47 +05301045 ret = chg_det & (1 << 4);
1046 break;
1047 case SNPS_28NM_INTEGRATED_PHY:
Heikki Krogerus1d4c9292012-02-13 13:24:09 +02001048 chg_det = ulpi_read(phy, 0x87);
Pavankumar Kondetid8608522011-05-04 10:19:47 +05301049 ret = chg_det & 1;
1050 break;
1051 default:
1052 break;
1053 }
1054 return ret;
1055}
1056
1057static void msm_chg_enable_primary_det(struct msm_otg *motg)
1058{
Heikki Krogerus1d4c9292012-02-13 13:24:09 +02001059 struct usb_phy *phy = &motg->phy;
Pavankumar Kondetid8608522011-05-04 10:19:47 +05301060 u32 chg_det;
1061
1062 switch (motg->pdata->phy_type) {
1063 case CI_45NM_INTEGRATED_PHY:
Heikki Krogerus1d4c9292012-02-13 13:24:09 +02001064 chg_det = ulpi_read(phy, 0x34);
Pavankumar Kondetid8608522011-05-04 10:19:47 +05301065 /* enable chg detection */
1066 chg_det &= ~(1 << 0);
Heikki Krogerus1d4c9292012-02-13 13:24:09 +02001067 ulpi_write(phy, chg_det, 0x34);
Pavankumar Kondetid8608522011-05-04 10:19:47 +05301068 break;
1069 case SNPS_28NM_INTEGRATED_PHY:
1070 /*
1071 * Configure DP as current source, DM as current sink
1072 * and enable battery charging comparators.
1073 */
Heikki Krogerus1d4c9292012-02-13 13:24:09 +02001074 ulpi_write(phy, 0x2, 0x85);
1075 ulpi_write(phy, 0x1, 0x85);
Pavankumar Kondetid8608522011-05-04 10:19:47 +05301076 break;
1077 default:
1078 break;
1079 }
1080}
1081
1082static bool msm_chg_check_dcd(struct msm_otg *motg)
1083{
Heikki Krogerus1d4c9292012-02-13 13:24:09 +02001084 struct usb_phy *phy = &motg->phy;
Pavankumar Kondetid8608522011-05-04 10:19:47 +05301085 u32 line_state;
1086 bool ret = false;
1087
1088 switch (motg->pdata->phy_type) {
1089 case CI_45NM_INTEGRATED_PHY:
Heikki Krogerus1d4c9292012-02-13 13:24:09 +02001090 line_state = ulpi_read(phy, 0x15);
Pavankumar Kondetid8608522011-05-04 10:19:47 +05301091 ret = !(line_state & 1);
1092 break;
1093 case SNPS_28NM_INTEGRATED_PHY:
Heikki Krogerus1d4c9292012-02-13 13:24:09 +02001094 line_state = ulpi_read(phy, 0x87);
Pavankumar Kondetid8608522011-05-04 10:19:47 +05301095 ret = line_state & 2;
1096 break;
1097 default:
1098 break;
1099 }
1100 return ret;
1101}
1102
1103static void msm_chg_disable_dcd(struct msm_otg *motg)
1104{
Heikki Krogerus1d4c9292012-02-13 13:24:09 +02001105 struct usb_phy *phy = &motg->phy;
Pavankumar Kondetid8608522011-05-04 10:19:47 +05301106 u32 chg_det;
1107
1108 switch (motg->pdata->phy_type) {
1109 case CI_45NM_INTEGRATED_PHY:
Heikki Krogerus1d4c9292012-02-13 13:24:09 +02001110 chg_det = ulpi_read(phy, 0x34);
Pavankumar Kondetid8608522011-05-04 10:19:47 +05301111 chg_det &= ~(1 << 5);
Heikki Krogerus1d4c9292012-02-13 13:24:09 +02001112 ulpi_write(phy, chg_det, 0x34);
Pavankumar Kondetid8608522011-05-04 10:19:47 +05301113 break;
1114 case SNPS_28NM_INTEGRATED_PHY:
Heikki Krogerus1d4c9292012-02-13 13:24:09 +02001115 ulpi_write(phy, 0x10, 0x86);
Pavankumar Kondetid8608522011-05-04 10:19:47 +05301116 break;
1117 default:
1118 break;
1119 }
1120}
1121
1122static void msm_chg_enable_dcd(struct msm_otg *motg)
1123{
Heikki Krogerus1d4c9292012-02-13 13:24:09 +02001124 struct usb_phy *phy = &motg->phy;
Pavankumar Kondetid8608522011-05-04 10:19:47 +05301125 u32 chg_det;
1126
1127 switch (motg->pdata->phy_type) {
1128 case CI_45NM_INTEGRATED_PHY:
Heikki Krogerus1d4c9292012-02-13 13:24:09 +02001129 chg_det = ulpi_read(phy, 0x34);
Pavankumar Kondetid8608522011-05-04 10:19:47 +05301130 /* Turn on D+ current source */
1131 chg_det |= (1 << 5);
Heikki Krogerus1d4c9292012-02-13 13:24:09 +02001132 ulpi_write(phy, chg_det, 0x34);
Pavankumar Kondetid8608522011-05-04 10:19:47 +05301133 break;
1134 case SNPS_28NM_INTEGRATED_PHY:
1135 /* Data contact detection enable */
Heikki Krogerus1d4c9292012-02-13 13:24:09 +02001136 ulpi_write(phy, 0x10, 0x85);
Pavankumar Kondetid8608522011-05-04 10:19:47 +05301137 break;
1138 default:
1139 break;
1140 }
1141}
1142
1143static void msm_chg_block_on(struct msm_otg *motg)
1144{
Heikki Krogerus1d4c9292012-02-13 13:24:09 +02001145 struct usb_phy *phy = &motg->phy;
Pavankumar Kondetid8608522011-05-04 10:19:47 +05301146 u32 func_ctrl, chg_det;
1147
1148 /* put the controller in non-driving mode */
Heikki Krogerus1d4c9292012-02-13 13:24:09 +02001149 func_ctrl = ulpi_read(phy, ULPI_FUNC_CTRL);
Pavankumar Kondetid8608522011-05-04 10:19:47 +05301150 func_ctrl &= ~ULPI_FUNC_CTRL_OPMODE_MASK;
1151 func_ctrl |= ULPI_FUNC_CTRL_OPMODE_NONDRIVING;
Heikki Krogerus1d4c9292012-02-13 13:24:09 +02001152 ulpi_write(phy, func_ctrl, ULPI_FUNC_CTRL);
Pavankumar Kondetid8608522011-05-04 10:19:47 +05301153
1154 switch (motg->pdata->phy_type) {
1155 case CI_45NM_INTEGRATED_PHY:
Heikki Krogerus1d4c9292012-02-13 13:24:09 +02001156 chg_det = ulpi_read(phy, 0x34);
Pavankumar Kondetid8608522011-05-04 10:19:47 +05301157 /* control chg block via ULPI */
1158 chg_det &= ~(1 << 3);
Heikki Krogerus1d4c9292012-02-13 13:24:09 +02001159 ulpi_write(phy, chg_det, 0x34);
Pavankumar Kondetid8608522011-05-04 10:19:47 +05301160 /* Turn on chg detect block */
1161 chg_det &= ~(1 << 1);
Heikki Krogerus1d4c9292012-02-13 13:24:09 +02001162 ulpi_write(phy, chg_det, 0x34);
Pavankumar Kondetid8608522011-05-04 10:19:47 +05301163 udelay(20);
1164 break;
1165 case SNPS_28NM_INTEGRATED_PHY:
1166 /* Clear charger detecting control bits */
Heikki Krogerus1d4c9292012-02-13 13:24:09 +02001167 ulpi_write(phy, 0x3F, 0x86);
Pavankumar Kondetid8608522011-05-04 10:19:47 +05301168 /* Clear alt interrupt latch and enable bits */
Heikki Krogerus1d4c9292012-02-13 13:24:09 +02001169 ulpi_write(phy, 0x1F, 0x92);
1170 ulpi_write(phy, 0x1F, 0x95);
Pavankumar Kondetid8608522011-05-04 10:19:47 +05301171 udelay(100);
1172 break;
1173 default:
1174 break;
1175 }
1176}
1177
1178static void msm_chg_block_off(struct msm_otg *motg)
1179{
Heikki Krogerus1d4c9292012-02-13 13:24:09 +02001180 struct usb_phy *phy = &motg->phy;
Pavankumar Kondetid8608522011-05-04 10:19:47 +05301181 u32 func_ctrl, chg_det;
1182
1183 switch (motg->pdata->phy_type) {
1184 case CI_45NM_INTEGRATED_PHY:
Heikki Krogerus1d4c9292012-02-13 13:24:09 +02001185 chg_det = ulpi_read(phy, 0x34);
Pavankumar Kondetid8608522011-05-04 10:19:47 +05301186 /* Turn off charger block */
1187 chg_det |= ~(1 << 1);
Heikki Krogerus1d4c9292012-02-13 13:24:09 +02001188 ulpi_write(phy, chg_det, 0x34);
Pavankumar Kondetid8608522011-05-04 10:19:47 +05301189 break;
1190 case SNPS_28NM_INTEGRATED_PHY:
1191 /* Clear charger detecting control bits */
Heikki Krogerus1d4c9292012-02-13 13:24:09 +02001192 ulpi_write(phy, 0x3F, 0x86);
Pavankumar Kondetid8608522011-05-04 10:19:47 +05301193 /* Clear alt interrupt latch and enable bits */
Heikki Krogerus1d4c9292012-02-13 13:24:09 +02001194 ulpi_write(phy, 0x1F, 0x92);
1195 ulpi_write(phy, 0x1F, 0x95);
Pavankumar Kondetid8608522011-05-04 10:19:47 +05301196 break;
1197 default:
1198 break;
1199 }
1200
1201 /* put the controller in normal mode */
Heikki Krogerus1d4c9292012-02-13 13:24:09 +02001202 func_ctrl = ulpi_read(phy, ULPI_FUNC_CTRL);
Pavankumar Kondetid8608522011-05-04 10:19:47 +05301203 func_ctrl &= ~ULPI_FUNC_CTRL_OPMODE_MASK;
1204 func_ctrl |= ULPI_FUNC_CTRL_OPMODE_NORMAL;
Heikki Krogerus1d4c9292012-02-13 13:24:09 +02001205 ulpi_write(phy, func_ctrl, ULPI_FUNC_CTRL);
Pavankumar Kondetid8608522011-05-04 10:19:47 +05301206}
1207
1208#define MSM_CHG_DCD_POLL_TIME (100 * HZ/1000) /* 100 msec */
1209#define MSM_CHG_DCD_MAX_RETRIES 6 /* Tdcd_tmout = 6 * 100 msec */
1210#define MSM_CHG_PRIMARY_DET_TIME (40 * HZ/1000) /* TVDPSRC_ON */
1211#define MSM_CHG_SECONDARY_DET_TIME (40 * HZ/1000) /* TVDMSRC_ON */
1212static void msm_chg_detect_work(struct work_struct *w)
1213{
1214 struct msm_otg *motg = container_of(w, struct msm_otg, chg_work.work);
Heikki Krogerus1d4c9292012-02-13 13:24:09 +02001215 struct usb_phy *phy = &motg->phy;
Pavankumar Kondetid8608522011-05-04 10:19:47 +05301216 bool is_dcd, tmout, vout;
1217 unsigned long delay;
1218
Heikki Krogerus1d4c9292012-02-13 13:24:09 +02001219 dev_dbg(phy->dev, "chg detection work\n");
Pavankumar Kondetid8608522011-05-04 10:19:47 +05301220 switch (motg->chg_state) {
1221 case USB_CHG_STATE_UNDEFINED:
Heikki Krogerus1d4c9292012-02-13 13:24:09 +02001222 pm_runtime_get_sync(phy->dev);
Pavankumar Kondetid8608522011-05-04 10:19:47 +05301223 msm_chg_block_on(motg);
1224 msm_chg_enable_dcd(motg);
1225 motg->chg_state = USB_CHG_STATE_WAIT_FOR_DCD;
1226 motg->dcd_retries = 0;
1227 delay = MSM_CHG_DCD_POLL_TIME;
1228 break;
1229 case USB_CHG_STATE_WAIT_FOR_DCD:
1230 is_dcd = msm_chg_check_dcd(motg);
1231 tmout = ++motg->dcd_retries == MSM_CHG_DCD_MAX_RETRIES;
1232 if (is_dcd || tmout) {
1233 msm_chg_disable_dcd(motg);
1234 msm_chg_enable_primary_det(motg);
1235 delay = MSM_CHG_PRIMARY_DET_TIME;
1236 motg->chg_state = USB_CHG_STATE_DCD_DONE;
1237 } else {
1238 delay = MSM_CHG_DCD_POLL_TIME;
1239 }
1240 break;
1241 case USB_CHG_STATE_DCD_DONE:
1242 vout = msm_chg_check_primary_det(motg);
1243 if (vout) {
1244 msm_chg_enable_secondary_det(motg);
1245 delay = MSM_CHG_SECONDARY_DET_TIME;
1246 motg->chg_state = USB_CHG_STATE_PRIMARY_DONE;
1247 } else {
1248 motg->chg_type = USB_SDP_CHARGER;
1249 motg->chg_state = USB_CHG_STATE_DETECTED;
1250 delay = 0;
1251 }
1252 break;
1253 case USB_CHG_STATE_PRIMARY_DONE:
1254 vout = msm_chg_check_secondary_det(motg);
1255 if (vout)
1256 motg->chg_type = USB_DCP_CHARGER;
1257 else
1258 motg->chg_type = USB_CDP_CHARGER;
1259 motg->chg_state = USB_CHG_STATE_SECONDARY_DONE;
1260 /* fall through */
1261 case USB_CHG_STATE_SECONDARY_DONE:
1262 motg->chg_state = USB_CHG_STATE_DETECTED;
1263 case USB_CHG_STATE_DETECTED:
1264 msm_chg_block_off(motg);
Heikki Krogerus1d4c9292012-02-13 13:24:09 +02001265 dev_dbg(phy->dev, "charger = %d\n", motg->chg_type);
Pavankumar Kondetid8608522011-05-04 10:19:47 +05301266 schedule_work(&motg->sm_work);
1267 return;
1268 default:
1269 return;
1270 }
1271
1272 schedule_delayed_work(&motg->chg_work, delay);
1273}
1274
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05301275/*
1276 * We support OTG, Peripheral only and Host only configurations. In case
1277 * of OTG, mode switch (host-->peripheral/peripheral-->host) can happen
1278 * via Id pin status or user request (debugfs). Id/BSV interrupts are not
1279 * enabled when switch is controlled by user and default mode is supplied
1280 * by board file, which can be changed by userspace later.
1281 */
1282static void msm_otg_init_sm(struct msm_otg *motg)
1283{
1284 struct msm_otg_platform_data *pdata = motg->pdata;
1285 u32 otgsc = readl(USB_OTGSC);
1286
1287 switch (pdata->mode) {
Ivan T. Ivanov971232c2014-04-28 16:34:11 +03001288 case USB_DR_MODE_OTG:
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05301289 if (pdata->otg_control == OTG_PHY_CONTROL) {
1290 if (otgsc & OTGSC_ID)
1291 set_bit(ID, &motg->inputs);
1292 else
1293 clear_bit(ID, &motg->inputs);
1294
1295 if (otgsc & OTGSC_BSV)
1296 set_bit(B_SESS_VLD, &motg->inputs);
1297 else
1298 clear_bit(B_SESS_VLD, &motg->inputs);
1299 } else if (pdata->otg_control == OTG_USER_CONTROL) {
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05301300 set_bit(ID, &motg->inputs);
1301 clear_bit(B_SESS_VLD, &motg->inputs);
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05301302 }
1303 break;
Ivan T. Ivanov971232c2014-04-28 16:34:11 +03001304 case USB_DR_MODE_HOST:
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05301305 clear_bit(ID, &motg->inputs);
1306 break;
Ivan T. Ivanov971232c2014-04-28 16:34:11 +03001307 case USB_DR_MODE_PERIPHERAL:
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05301308 set_bit(ID, &motg->inputs);
1309 if (otgsc & OTGSC_BSV)
1310 set_bit(B_SESS_VLD, &motg->inputs);
1311 else
1312 clear_bit(B_SESS_VLD, &motg->inputs);
1313 break;
1314 default:
1315 break;
1316 }
1317}
1318
1319static void msm_otg_sm_work(struct work_struct *w)
1320{
1321 struct msm_otg *motg = container_of(w, struct msm_otg, sm_work);
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_UNDEFINED:
Antoine Tenart19c1eac2014-10-30 18:41:14 +01001326 dev_dbg(otg->usb_phy->dev, "OTG_STATE_UNDEFINED state\n");
1327 msm_otg_reset(otg->usb_phy);
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05301328 msm_otg_init_sm(motg);
Antoine Tenarte47d9252014-10-30 18:41:13 +01001329 otg->state = OTG_STATE_B_IDLE;
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05301330 /* FALL THROUGH */
1331 case OTG_STATE_B_IDLE:
Antoine Tenart19c1eac2014-10-30 18:41:14 +01001332 dev_dbg(otg->usb_phy->dev, "OTG_STATE_B_IDLE state\n");
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05301333 if (!test_bit(ID, &motg->inputs) && otg->host) {
1334 /* disable BSV bit */
1335 writel(readl(USB_OTGSC) & ~OTGSC_BSVIE, USB_OTGSC);
Antoine Tenart19c1eac2014-10-30 18:41:14 +01001336 msm_otg_start_host(otg->usb_phy, 1);
Antoine Tenarte47d9252014-10-30 18:41:13 +01001337 otg->state = OTG_STATE_A_HOST;
Pavankumar Kondetid8608522011-05-04 10:19:47 +05301338 } else if (test_bit(B_SESS_VLD, &motg->inputs)) {
1339 switch (motg->chg_state) {
1340 case USB_CHG_STATE_UNDEFINED:
1341 msm_chg_detect_work(&motg->chg_work.work);
1342 break;
1343 case USB_CHG_STATE_DETECTED:
1344 switch (motg->chg_type) {
1345 case USB_DCP_CHARGER:
1346 msm_otg_notify_charger(motg,
1347 IDEV_CHG_MAX);
1348 break;
1349 case USB_CDP_CHARGER:
1350 msm_otg_notify_charger(motg,
1351 IDEV_CHG_MAX);
Antoine Tenart19c1eac2014-10-30 18:41:14 +01001352 msm_otg_start_peripheral(otg->usb_phy,
1353 1);
Antoine Tenarte47d9252014-10-30 18:41:13 +01001354 otg->state
Heikki Krogerus1d4c9292012-02-13 13:24:09 +02001355 = OTG_STATE_B_PERIPHERAL;
Pavankumar Kondetid8608522011-05-04 10:19:47 +05301356 break;
1357 case USB_SDP_CHARGER:
1358 msm_otg_notify_charger(motg, IUNIT);
Antoine Tenart19c1eac2014-10-30 18:41:14 +01001359 msm_otg_start_peripheral(otg->usb_phy,
1360 1);
Antoine Tenarte47d9252014-10-30 18:41:13 +01001361 otg->state
Heikki Krogerus1d4c9292012-02-13 13:24:09 +02001362 = OTG_STATE_B_PERIPHERAL;
Pavankumar Kondetid8608522011-05-04 10:19:47 +05301363 break;
1364 default:
1365 break;
1366 }
1367 break;
1368 default:
1369 break;
1370 }
1371 } else {
1372 /*
1373 * If charger detection work is pending, decrement
1374 * the pm usage counter to balance with the one that
1375 * is incremented in charger detection work.
1376 */
1377 if (cancel_delayed_work_sync(&motg->chg_work)) {
Antoine Tenart19c1eac2014-10-30 18:41:14 +01001378 pm_runtime_put_sync(otg->usb_phy->dev);
1379 msm_otg_reset(otg->usb_phy);
Pavankumar Kondetid8608522011-05-04 10:19:47 +05301380 }
1381 msm_otg_notify_charger(motg, 0);
1382 motg->chg_state = USB_CHG_STATE_UNDEFINED;
1383 motg->chg_type = USB_INVALID_CHARGER;
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05301384 }
Srinivas Kandagatla508ccea2014-06-30 18:29:57 +01001385
Antoine Tenarte47d9252014-10-30 18:41:13 +01001386 if (otg->state == OTG_STATE_B_IDLE)
Antoine Tenart19c1eac2014-10-30 18:41:14 +01001387 pm_runtime_put_sync(otg->usb_phy->dev);
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05301388 break;
1389 case OTG_STATE_B_PERIPHERAL:
Antoine Tenart19c1eac2014-10-30 18:41:14 +01001390 dev_dbg(otg->usb_phy->dev, "OTG_STATE_B_PERIPHERAL state\n");
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05301391 if (!test_bit(B_SESS_VLD, &motg->inputs) ||
1392 !test_bit(ID, &motg->inputs)) {
Pavankumar Kondetid8608522011-05-04 10:19:47 +05301393 msm_otg_notify_charger(motg, 0);
Antoine Tenart19c1eac2014-10-30 18:41:14 +01001394 msm_otg_start_peripheral(otg->usb_phy, 0);
Pavankumar Kondetid8608522011-05-04 10:19:47 +05301395 motg->chg_state = USB_CHG_STATE_UNDEFINED;
1396 motg->chg_type = USB_INVALID_CHARGER;
Antoine Tenarte47d9252014-10-30 18:41:13 +01001397 otg->state = OTG_STATE_B_IDLE;
Antoine Tenart19c1eac2014-10-30 18:41:14 +01001398 msm_otg_reset(otg->usb_phy);
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05301399 schedule_work(w);
1400 }
1401 break;
1402 case OTG_STATE_A_HOST:
Antoine Tenart19c1eac2014-10-30 18:41:14 +01001403 dev_dbg(otg->usb_phy->dev, "OTG_STATE_A_HOST state\n");
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05301404 if (test_bit(ID, &motg->inputs)) {
Antoine Tenart19c1eac2014-10-30 18:41:14 +01001405 msm_otg_start_host(otg->usb_phy, 0);
Antoine Tenarte47d9252014-10-30 18:41:13 +01001406 otg->state = OTG_STATE_B_IDLE;
Antoine Tenart19c1eac2014-10-30 18:41:14 +01001407 msm_otg_reset(otg->usb_phy);
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05301408 schedule_work(w);
1409 }
1410 break;
1411 default:
1412 break;
1413 }
1414}
1415
1416static irqreturn_t msm_otg_irq(int irq, void *data)
1417{
1418 struct msm_otg *motg = data;
Heikki Krogerus1d4c9292012-02-13 13:24:09 +02001419 struct usb_phy *phy = &motg->phy;
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05301420 u32 otgsc = 0;
1421
Pavankumar Kondeti87c01042010-12-07 17:53:58 +05301422 if (atomic_read(&motg->in_lpm)) {
1423 disable_irq_nosync(irq);
1424 motg->async_int = 1;
Heikki Krogerus1d4c9292012-02-13 13:24:09 +02001425 pm_runtime_get(phy->dev);
Pavankumar Kondeti87c01042010-12-07 17:53:58 +05301426 return IRQ_HANDLED;
1427 }
1428
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05301429 otgsc = readl(USB_OTGSC);
1430 if (!(otgsc & (OTGSC_IDIS | OTGSC_BSVIS)))
1431 return IRQ_NONE;
1432
1433 if ((otgsc & OTGSC_IDIS) && (otgsc & OTGSC_IDIE)) {
1434 if (otgsc & OTGSC_ID)
1435 set_bit(ID, &motg->inputs);
1436 else
1437 clear_bit(ID, &motg->inputs);
Heikki Krogerus1d4c9292012-02-13 13:24:09 +02001438 dev_dbg(phy->dev, "ID set/clear\n");
1439 pm_runtime_get_noresume(phy->dev);
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05301440 } else if ((otgsc & OTGSC_BSVIS) && (otgsc & OTGSC_BSVIE)) {
1441 if (otgsc & OTGSC_BSV)
1442 set_bit(B_SESS_VLD, &motg->inputs);
1443 else
1444 clear_bit(B_SESS_VLD, &motg->inputs);
Heikki Krogerus1d4c9292012-02-13 13:24:09 +02001445 dev_dbg(phy->dev, "BSV set/clear\n");
1446 pm_runtime_get_noresume(phy->dev);
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05301447 }
1448
1449 writel(otgsc, USB_OTGSC);
1450 schedule_work(&motg->sm_work);
1451 return IRQ_HANDLED;
1452}
1453
1454static int msm_otg_mode_show(struct seq_file *s, void *unused)
1455{
1456 struct msm_otg *motg = s->private;
Heikki Krogerus1d4c9292012-02-13 13:24:09 +02001457 struct usb_otg *otg = motg->phy.otg;
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05301458
Antoine Tenarte47d9252014-10-30 18:41:13 +01001459 switch (otg->state) {
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05301460 case OTG_STATE_A_HOST:
Ivan T. Ivanov3aca0fa2014-04-28 16:34:10 +03001461 seq_puts(s, "host\n");
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05301462 break;
1463 case OTG_STATE_B_PERIPHERAL:
Ivan T. Ivanov3aca0fa2014-04-28 16:34:10 +03001464 seq_puts(s, "peripheral\n");
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05301465 break;
1466 default:
Ivan T. Ivanov3aca0fa2014-04-28 16:34:10 +03001467 seq_puts(s, "none\n");
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05301468 break;
1469 }
1470
1471 return 0;
1472}
1473
1474static int msm_otg_mode_open(struct inode *inode, struct file *file)
1475{
1476 return single_open(file, msm_otg_mode_show, inode->i_private);
1477}
1478
1479static ssize_t msm_otg_mode_write(struct file *file, const char __user *ubuf,
1480 size_t count, loff_t *ppos)
1481{
Pavankumar Kondetie2904ee2011-02-15 09:42:35 +05301482 struct seq_file *s = file->private_data;
1483 struct msm_otg *motg = s->private;
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05301484 char buf[16];
Heikki Krogerus1d4c9292012-02-13 13:24:09 +02001485 struct usb_otg *otg = motg->phy.otg;
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05301486 int status = count;
Ivan T. Ivanov971232c2014-04-28 16:34:11 +03001487 enum usb_dr_mode req_mode;
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05301488
1489 memset(buf, 0x00, sizeof(buf));
1490
1491 if (copy_from_user(&buf, ubuf, min_t(size_t, sizeof(buf) - 1, count))) {
1492 status = -EFAULT;
1493 goto out;
1494 }
1495
1496 if (!strncmp(buf, "host", 4)) {
Ivan T. Ivanov971232c2014-04-28 16:34:11 +03001497 req_mode = USB_DR_MODE_HOST;
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05301498 } else if (!strncmp(buf, "peripheral", 10)) {
Ivan T. Ivanov971232c2014-04-28 16:34:11 +03001499 req_mode = USB_DR_MODE_PERIPHERAL;
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05301500 } else if (!strncmp(buf, "none", 4)) {
Ivan T. Ivanov971232c2014-04-28 16:34:11 +03001501 req_mode = USB_DR_MODE_UNKNOWN;
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05301502 } else {
1503 status = -EINVAL;
1504 goto out;
1505 }
1506
1507 switch (req_mode) {
Ivan T. Ivanov971232c2014-04-28 16:34:11 +03001508 case USB_DR_MODE_UNKNOWN:
Antoine Tenarte47d9252014-10-30 18:41:13 +01001509 switch (otg->state) {
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05301510 case OTG_STATE_A_HOST:
1511 case OTG_STATE_B_PERIPHERAL:
1512 set_bit(ID, &motg->inputs);
1513 clear_bit(B_SESS_VLD, &motg->inputs);
1514 break;
1515 default:
1516 goto out;
1517 }
1518 break;
Ivan T. Ivanov971232c2014-04-28 16:34:11 +03001519 case USB_DR_MODE_PERIPHERAL:
Antoine Tenarte47d9252014-10-30 18:41:13 +01001520 switch (otg->state) {
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05301521 case OTG_STATE_B_IDLE:
1522 case OTG_STATE_A_HOST:
1523 set_bit(ID, &motg->inputs);
1524 set_bit(B_SESS_VLD, &motg->inputs);
1525 break;
1526 default:
1527 goto out;
1528 }
1529 break;
Ivan T. Ivanov971232c2014-04-28 16:34:11 +03001530 case USB_DR_MODE_HOST:
Antoine Tenarte47d9252014-10-30 18:41:13 +01001531 switch (otg->state) {
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05301532 case OTG_STATE_B_IDLE:
1533 case OTG_STATE_B_PERIPHERAL:
1534 clear_bit(ID, &motg->inputs);
1535 break;
1536 default:
1537 goto out;
1538 }
1539 break;
1540 default:
1541 goto out;
1542 }
1543
Antoine Tenart19c1eac2014-10-30 18:41:14 +01001544 pm_runtime_get_sync(otg->usb_phy->dev);
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05301545 schedule_work(&motg->sm_work);
1546out:
1547 return status;
1548}
1549
Felipe Balbi8f90afd2014-08-20 13:38:18 -05001550static const struct file_operations msm_otg_mode_fops = {
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05301551 .open = msm_otg_mode_open,
1552 .read = seq_read,
1553 .write = msm_otg_mode_write,
1554 .llseek = seq_lseek,
1555 .release = single_release,
1556};
1557
1558static struct dentry *msm_otg_dbg_root;
1559static struct dentry *msm_otg_dbg_mode;
1560
1561static int msm_otg_debugfs_init(struct msm_otg *motg)
1562{
1563 msm_otg_dbg_root = debugfs_create_dir("msm_otg", NULL);
1564
1565 if (!msm_otg_dbg_root || IS_ERR(msm_otg_dbg_root))
1566 return -ENODEV;
1567
1568 msm_otg_dbg_mode = debugfs_create_file("mode", S_IRUGO | S_IWUSR,
1569 msm_otg_dbg_root, motg, &msm_otg_mode_fops);
1570 if (!msm_otg_dbg_mode) {
1571 debugfs_remove(msm_otg_dbg_root);
1572 msm_otg_dbg_root = NULL;
1573 return -ENODEV;
1574 }
1575
1576 return 0;
1577}
1578
1579static void msm_otg_debugfs_cleanup(void)
1580{
1581 debugfs_remove(msm_otg_dbg_mode);
1582 debugfs_remove(msm_otg_dbg_root);
1583}
1584
Jingoo Han492240b2014-06-18 13:42:44 +09001585static const struct of_device_id msm_otg_dt_match[] = {
Ivan T. Ivanov8364f9a2014-04-28 16:34:15 +03001586 {
1587 .compatible = "qcom,usb-otg-ci",
1588 .data = (void *) CI_45NM_INTEGRATED_PHY
1589 },
1590 {
1591 .compatible = "qcom,usb-otg-snps",
1592 .data = (void *) SNPS_28NM_INTEGRATED_PHY
1593 },
1594 { }
1595};
1596MODULE_DEVICE_TABLE(of, msm_otg_dt_match);
1597
Ivan T. Ivanov591fc112015-04-09 11:34:22 +03001598static int msm_otg_vbus_notifier(struct notifier_block *nb, unsigned long event,
1599 void *ptr)
1600{
Baolin Wangd94e64c2017-05-05 14:12:26 +08001601 struct usb_phy *usb_phy = container_of(nb, struct usb_phy, vbus_nb);
1602 struct msm_otg *motg = container_of(usb_phy, struct msm_otg, phy);
Ivan T. Ivanov591fc112015-04-09 11:34:22 +03001603
1604 if (event)
1605 set_bit(B_SESS_VLD, &motg->inputs);
1606 else
1607 clear_bit(B_SESS_VLD, &motg->inputs);
1608
Ivan T. Ivanov6f98f542015-07-28 11:10:22 +03001609 if (test_bit(B_SESS_VLD, &motg->inputs)) {
1610 /* Switch D+/D- lines to Device connector */
1611 gpiod_set_value_cansleep(motg->switch_gpio, 0);
1612 } else {
1613 /* Switch D+/D- lines to Hub */
1614 gpiod_set_value_cansleep(motg->switch_gpio, 1);
1615 }
1616
Ivan T. Ivanov591fc112015-04-09 11:34:22 +03001617 schedule_work(&motg->sm_work);
1618
1619 return NOTIFY_DONE;
1620}
1621
1622static int msm_otg_id_notifier(struct notifier_block *nb, unsigned long event,
1623 void *ptr)
1624{
Baolin Wangd94e64c2017-05-05 14:12:26 +08001625 struct usb_phy *usb_phy = container_of(nb, struct usb_phy, id_nb);
1626 struct msm_otg *motg = container_of(usb_phy, struct msm_otg, phy);
Ivan T. Ivanov591fc112015-04-09 11:34:22 +03001627
1628 if (event)
1629 clear_bit(ID, &motg->inputs);
1630 else
1631 set_bit(ID, &motg->inputs);
1632
1633 schedule_work(&motg->sm_work);
1634
1635 return NOTIFY_DONE;
1636}
1637
Ivan T. Ivanov8364f9a2014-04-28 16:34:15 +03001638static int msm_otg_read_dt(struct platform_device *pdev, struct msm_otg *motg)
1639{
1640 struct msm_otg_platform_data *pdata;
Ivan T. Ivanov8364f9a2014-04-28 16:34:15 +03001641 struct device_node *node = pdev->dev.of_node;
1642 struct property *prop;
1643 int len, ret, words;
Ivan T. Ivanov01799b62014-04-28 16:34:22 +03001644 u32 val, tmp[3];
Ivan T. Ivanov8364f9a2014-04-28 16:34:15 +03001645
1646 pdata = devm_kzalloc(&pdev->dev, sizeof(*pdata), GFP_KERNEL);
1647 if (!pdata)
1648 return -ENOMEM;
1649
1650 motg->pdata = pdata;
1651
LABBE Corentin928c75f2015-11-24 15:34:09 +01001652 pdata->phy_type = (enum msm_usb_phy_type)of_device_get_match_data(&pdev->dev);
1653 if (!pdata->phy_type)
1654 return 1;
Ivan T. Ivanov8364f9a2014-04-28 16:34:15 +03001655
Ivan T. Ivanova2734542014-04-28 16:34:16 +03001656 motg->link_rst = devm_reset_control_get(&pdev->dev, "link");
1657 if (IS_ERR(motg->link_rst))
1658 return PTR_ERR(motg->link_rst);
1659
1660 motg->phy_rst = devm_reset_control_get(&pdev->dev, "phy");
1661 if (IS_ERR(motg->phy_rst))
Srinivas Kandagatlae44f1f42014-06-30 18:29:49 +01001662 motg->phy_rst = NULL;
Ivan T. Ivanova2734542014-04-28 16:34:16 +03001663
Heikki Krogerus06e71142015-09-21 11:14:34 +03001664 pdata->mode = usb_get_dr_mode(&pdev->dev);
Ivan T. Ivanov8364f9a2014-04-28 16:34:15 +03001665 if (pdata->mode == USB_DR_MODE_UNKNOWN)
1666 pdata->mode = USB_DR_MODE_OTG;
1667
1668 pdata->otg_control = OTG_PHY_CONTROL;
1669 if (!of_property_read_u32(node, "qcom,otg-control", &val))
1670 if (val == OTG_PMIC_CONTROL)
1671 pdata->otg_control = val;
1672
Ivan T. Ivanovcfa3ff52014-04-28 16:34:17 +03001673 if (!of_property_read_u32(node, "qcom,phy-num", &val) && val < 2)
1674 motg->phy_number = val;
1675
Ivan T. Ivanov01799b62014-04-28 16:34:22 +03001676 motg->vdd_levels[VDD_LEVEL_NONE] = USB_PHY_SUSP_DIG_VOL;
1677 motg->vdd_levels[VDD_LEVEL_MIN] = USB_PHY_VDD_DIG_VOL_MIN;
1678 motg->vdd_levels[VDD_LEVEL_MAX] = USB_PHY_VDD_DIG_VOL_MAX;
1679
1680 if (of_get_property(node, "qcom,vdd-levels", &len) &&
1681 len == sizeof(tmp)) {
1682 of_property_read_u32_array(node, "qcom,vdd-levels",
1683 tmp, len / sizeof(*tmp));
1684 motg->vdd_levels[VDD_LEVEL_NONE] = tmp[VDD_LEVEL_NONE];
1685 motg->vdd_levels[VDD_LEVEL_MIN] = tmp[VDD_LEVEL_MIN];
1686 motg->vdd_levels[VDD_LEVEL_MAX] = tmp[VDD_LEVEL_MAX];
1687 }
1688
Ivan T. Ivanov44e42ae2015-04-09 11:34:33 +03001689 motg->manual_pullup = of_property_read_bool(node, "qcom,manual-pullup");
1690
Ivan T. Ivanov6f98f542015-07-28 11:10:22 +03001691 motg->switch_gpio = devm_gpiod_get_optional(&pdev->dev, "switch",
1692 GPIOD_OUT_LOW);
1693 if (IS_ERR(motg->switch_gpio))
1694 return PTR_ERR(motg->switch_gpio);
1695
Ivan T. Ivanov8364f9a2014-04-28 16:34:15 +03001696 prop = of_find_property(node, "qcom,phy-init-sequence", &len);
1697 if (!prop || !len)
1698 return 0;
1699
1700 words = len / sizeof(u32);
1701
1702 if (words >= ULPI_EXT_VENDOR_SPECIFIC) {
1703 dev_warn(&pdev->dev, "Too big PHY init sequence %d\n", words);
1704 return 0;
1705 }
1706
1707 pdata->phy_init_seq = devm_kzalloc(&pdev->dev, len, GFP_KERNEL);
Peter Chen9da22202014-10-14 15:56:17 +08001708 if (!pdata->phy_init_seq)
Ivan T. Ivanov8364f9a2014-04-28 16:34:15 +03001709 return 0;
Ivan T. Ivanov8364f9a2014-04-28 16:34:15 +03001710
1711 ret = of_property_read_u32_array(node, "qcom,phy-init-sequence",
1712 pdata->phy_init_seq, words);
1713 if (!ret)
1714 pdata->phy_init_sz = words;
1715
1716 return 0;
1717}
1718
Ivan T. Ivanov6f98f542015-07-28 11:10:22 +03001719static int msm_otg_reboot_notify(struct notifier_block *this,
1720 unsigned long code, void *unused)
1721{
1722 struct msm_otg *motg = container_of(this, struct msm_otg, reboot);
1723
1724 /*
1725 * Ensure that D+/D- lines are routed to uB connector, so
1726 * we could load bootloader/kernel at next reboot
1727 */
1728 gpiod_set_value_cansleep(motg->switch_gpio, 0);
1729 return NOTIFY_DONE;
1730}
1731
Ivan T. Ivanov06a6ec42014-04-28 16:34:07 +03001732static int msm_otg_probe(struct platform_device *pdev)
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05301733{
Ivan T. Ivanov6b99c68e2014-04-28 16:34:08 +03001734 struct regulator_bulk_data regs[3];
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05301735 int ret = 0;
Ivan T. Ivanov8364f9a2014-04-28 16:34:15 +03001736 struct device_node *np = pdev->dev.of_node;
1737 struct msm_otg_platform_data *pdata;
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05301738 struct resource *res;
1739 struct msm_otg *motg;
Heikki Krogerus1d4c9292012-02-13 13:24:09 +02001740 struct usb_phy *phy;
Tim Bird30bf8662014-04-28 16:34:20 +03001741 void __iomem *phy_select;
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05301742
Ivan T. Ivanov6b99c68e2014-04-28 16:34:08 +03001743 motg = devm_kzalloc(&pdev->dev, sizeof(struct msm_otg), GFP_KERNEL);
Peter Chen9da22202014-10-14 15:56:17 +08001744 if (!motg)
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05301745 return -ENOMEM;
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05301746
Ivan T. Ivanov6b99c68e2014-04-28 16:34:08 +03001747 motg->phy.otg = devm_kzalloc(&pdev->dev, sizeof(struct usb_otg),
1748 GFP_KERNEL);
Peter Chen9da22202014-10-14 15:56:17 +08001749 if (!motg->phy.otg)
Ivan T. Ivanov6b99c68e2014-04-28 16:34:08 +03001750 return -ENOMEM;
Heikki Krogerus1d4c9292012-02-13 13:24:09 +02001751
Heikki Krogerus1d4c9292012-02-13 13:24:09 +02001752 phy = &motg->phy;
1753 phy->dev = &pdev->dev;
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05301754
Ivan T. Ivanov8364f9a2014-04-28 16:34:15 +03001755 motg->clk = devm_clk_get(&pdev->dev, np ? "core" : "usb_hs_clk");
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05301756 if (IS_ERR(motg->clk)) {
1757 dev_err(&pdev->dev, "failed to get usb_hs_clk\n");
Ivan T. Ivanov6b99c68e2014-04-28 16:34:08 +03001758 return PTR_ERR(motg->clk);
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05301759 }
Anji jonnala0f73cac2011-05-04 10:19:46 +05301760
1761 /*
1762 * If USB Core is running its protocol engine based on CORE CLK,
1763 * CORE CLK must be running at >55Mhz for correct HSUSB
1764 * operation and USB core cannot tolerate frequency changes on
Ivan T. Ivanovff0e4a62014-04-28 16:34:12 +03001765 * CORE CLK.
Anji jonnala0f73cac2011-05-04 10:19:46 +05301766 */
Ivan T. Ivanov8364f9a2014-04-28 16:34:15 +03001767 motg->pclk = devm_clk_get(&pdev->dev, np ? "iface" : "usb_hs_pclk");
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05301768 if (IS_ERR(motg->pclk)) {
1769 dev_err(&pdev->dev, "failed to get usb_hs_pclk\n");
Ivan T. Ivanov6b99c68e2014-04-28 16:34:08 +03001770 return PTR_ERR(motg->pclk);
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05301771 }
1772
1773 /*
1774 * USB core clock is not present on all MSM chips. This
1775 * clock is introduced to remove the dependency on AXI
1776 * bus frequency.
1777 */
Ivan T. Ivanov8364f9a2014-04-28 16:34:15 +03001778 motg->core_clk = devm_clk_get(&pdev->dev,
1779 np ? "alt_core" : "usb_hs_core_clk");
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05301780
1781 res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
Dan Carpenter2ea7b142014-05-19 23:35:19 +03001782 if (!res)
1783 return -EINVAL;
1784 motg->regs = devm_ioremap(&pdev->dev, res->start, resource_size(res));
1785 if (!motg->regs)
1786 return -ENOMEM;
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05301787
Srinivas Kandagatlaa38a08d2016-01-13 09:13:10 +00001788 pdata = dev_get_platdata(&pdev->dev);
1789 if (!pdata) {
1790 if (!np)
1791 return -ENXIO;
1792 ret = msm_otg_read_dt(pdev, motg);
1793 if (ret)
1794 return ret;
1795 }
1796
Tim Bird30bf8662014-04-28 16:34:20 +03001797 /*
1798 * NOTE: The PHYs can be multiplexed between the chipidea controller
1799 * and the dwc3 controller, using a single bit. It is important that
1800 * the dwc3 driver does not set this bit in an incompatible way.
1801 */
1802 if (motg->phy_number) {
1803 phy_select = devm_ioremap_nocache(&pdev->dev, USB2_PHY_SEL, 4);
Chanwoo Choie61bebd2017-01-16 21:36:58 +09001804 if (!phy_select)
1805 return -ENOMEM;
1806
Tim Bird30bf8662014-04-28 16:34:20 +03001807 /* Enable second PHY with the OTG port */
Felipe Balbi24597492014-04-30 11:35:22 -05001808 writel(0x1, phy_select);
Tim Bird30bf8662014-04-28 16:34:20 +03001809 }
1810
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05301811 dev_info(&pdev->dev, "OTG regs = %p\n", motg->regs);
1812
1813 motg->irq = platform_get_irq(pdev, 0);
Ivan T. Ivanovf60c1142014-04-28 16:34:14 +03001814 if (motg->irq < 0) {
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05301815 dev_err(&pdev->dev, "platform_get_irq failed\n");
Srinivas Kandagatlaa38a08d2016-01-13 09:13:10 +00001816 ret = motg->irq;
Chanwoo Choie61bebd2017-01-16 21:36:58 +09001817 return motg->irq;
Ivan T. Ivanov6b99c68e2014-04-28 16:34:08 +03001818 }
1819
Ivan T. Ivanovf5ef2372014-04-28 16:34:13 +03001820 regs[0].supply = "vddcx";
1821 regs[1].supply = "v3p3";
1822 regs[2].supply = "v1p8";
Ivan T. Ivanov6b99c68e2014-04-28 16:34:08 +03001823
1824 ret = devm_regulator_bulk_get(motg->phy.dev, ARRAY_SIZE(regs), regs);
1825 if (ret)
Chanwoo Choie61bebd2017-01-16 21:36:58 +09001826 return ret;
Ivan T. Ivanov6b99c68e2014-04-28 16:34:08 +03001827
1828 motg->vddcx = regs[0].consumer;
1829 motg->v3p3 = regs[1].consumer;
1830 motg->v1p8 = regs[2].consumer;
1831
1832 clk_set_rate(motg->clk, 60000000);
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05301833
Stephen Boydb99a8f62013-06-17 10:43:10 -07001834 clk_prepare_enable(motg->clk);
1835 clk_prepare_enable(motg->pclk);
Anji jonnala11aa5c42011-05-04 10:19:48 +05301836
Ivan T. Ivanov6b99c68e2014-04-28 16:34:08 +03001837 if (!IS_ERR(motg->core_clk))
1838 clk_prepare_enable(motg->core_clk);
1839
Anji jonnala11aa5c42011-05-04 10:19:48 +05301840 ret = msm_hsusb_init_vddcx(motg, 1);
1841 if (ret) {
1842 dev_err(&pdev->dev, "hsusb vddcx configuration failed\n");
Ivan T. Ivanov6b99c68e2014-04-28 16:34:08 +03001843 goto disable_clks;
Anji jonnala11aa5c42011-05-04 10:19:48 +05301844 }
1845
1846 ret = msm_hsusb_ldo_init(motg, 1);
1847 if (ret) {
1848 dev_err(&pdev->dev, "hsusb vreg configuration failed\n");
Ivan T. Ivanov6b99c68e2014-04-28 16:34:08 +03001849 goto disable_vddcx;
Anji jonnala11aa5c42011-05-04 10:19:48 +05301850 }
Ivan T. Ivanov37cfdaf2014-04-28 16:34:06 +03001851 ret = msm_hsusb_ldo_set_mode(motg, 1);
Anji jonnala11aa5c42011-05-04 10:19:48 +05301852 if (ret) {
1853 dev_err(&pdev->dev, "hsusb vreg enable failed\n");
Ivan T. Ivanov6b99c68e2014-04-28 16:34:08 +03001854 goto disable_ldo;
Anji jonnala11aa5c42011-05-04 10:19:48 +05301855 }
1856
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05301857 writel(0, USB_USBINTR);
1858 writel(0, USB_OTGSC);
1859
1860 INIT_WORK(&motg->sm_work, msm_otg_sm_work);
Pavankumar Kondetid8608522011-05-04 10:19:47 +05301861 INIT_DELAYED_WORK(&motg->chg_work, msm_chg_detect_work);
Ivan T. Ivanov6b99c68e2014-04-28 16:34:08 +03001862 ret = devm_request_irq(&pdev->dev, motg->irq, msm_otg_irq, IRQF_SHARED,
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05301863 "msm_otg", motg);
1864 if (ret) {
1865 dev_err(&pdev->dev, "request irq failed\n");
Ivan T. Ivanov6b99c68e2014-04-28 16:34:08 +03001866 goto disable_ldo;
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05301867 }
1868
Ivan T. Ivanovd69c6f52014-04-28 16:34:18 +03001869 phy->init = msm_phy_init;
Ivan T. Ivanov349907c2014-04-28 16:34:21 +03001870 phy->notify_disconnect = msm_phy_notify_disconnect;
Ivan T. Ivanove695abb2014-04-28 16:34:23 +03001871 phy->type = USB_PHY_TYPE_USB2;
Baolin Wangd94e64c2017-05-05 14:12:26 +08001872 phy->vbus_nb.notifier_call = msm_otg_vbus_notifier;
1873 phy->id_nb.notifier_call = msm_otg_id_notifier;
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05301874
Heikki Krogerus1d4c9292012-02-13 13:24:09 +02001875 phy->io_ops = &msm_otg_io_ops;
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05301876
Antoine Tenart19c1eac2014-10-30 18:41:14 +01001877 phy->otg->usb_phy = &motg->phy;
Heikki Krogerus1d4c9292012-02-13 13:24:09 +02001878 phy->otg->set_host = msm_otg_set_host;
1879 phy->otg->set_peripheral = msm_otg_set_peripheral;
1880
Ivan T. Ivanovd69c6f52014-04-28 16:34:18 +03001881 msm_usb_reset(phy);
1882
Ivan T. Ivanove695abb2014-04-28 16:34:23 +03001883 ret = usb_add_phy_dev(&motg->phy);
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05301884 if (ret) {
Kishon Vijay Abraham I721002e2012-06-22 17:02:45 +05301885 dev_err(&pdev->dev, "usb_add_phy failed\n");
Ivan T. Ivanov6b99c68e2014-04-28 16:34:08 +03001886 goto disable_ldo;
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05301887 }
1888
Baolin Wangd94e64c2017-05-05 14:12:26 +08001889 ret = extcon_get_state(phy->edev, EXTCON_USB);
1890 if (ret)
1891 set_bit(B_SESS_VLD, &motg->inputs);
1892 else
1893 clear_bit(B_SESS_VLD, &motg->inputs);
1894
1895 ret = extcon_get_state(phy->id_edev, EXTCON_USB_HOST);
1896 if (ret)
1897 clear_bit(ID, &motg->inputs);
1898 else
1899 set_bit(ID, &motg->inputs);
1900
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05301901 platform_set_drvdata(pdev, motg);
1902 device_init_wakeup(&pdev->dev, 1);
1903
Ivan T. Ivanov971232c2014-04-28 16:34:11 +03001904 if (motg->pdata->mode == USB_DR_MODE_OTG &&
Ivan T. Ivanov8364f9a2014-04-28 16:34:15 +03001905 motg->pdata->otg_control == OTG_USER_CONTROL) {
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05301906 ret = msm_otg_debugfs_init(motg);
1907 if (ret)
Ivan T. Ivanov3aca0fa2014-04-28 16:34:10 +03001908 dev_dbg(&pdev->dev, "Can not create mode change file\n");
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05301909 }
1910
Ivan T. Ivanov6f98f542015-07-28 11:10:22 +03001911 if (test_bit(B_SESS_VLD, &motg->inputs)) {
1912 /* Switch D+/D- lines to Device connector */
1913 gpiod_set_value_cansleep(motg->switch_gpio, 0);
1914 } else {
1915 /* Switch D+/D- lines to Hub */
1916 gpiod_set_value_cansleep(motg->switch_gpio, 1);
1917 }
1918
1919 motg->reboot.notifier_call = msm_otg_reboot_notify;
1920 register_reboot_notifier(&motg->reboot);
1921
Pavankumar Kondeti87c01042010-12-07 17:53:58 +05301922 pm_runtime_set_active(&pdev->dev);
1923 pm_runtime_enable(&pdev->dev);
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05301924
Pavankumar Kondeti87c01042010-12-07 17:53:58 +05301925 return 0;
Ivan T. Ivanov6b99c68e2014-04-28 16:34:08 +03001926
1927disable_ldo:
1928 msm_hsusb_ldo_init(motg, 0);
1929disable_vddcx:
1930 msm_hsusb_init_vddcx(motg, 0);
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05301931disable_clks:
Stephen Boydb99a8f62013-06-17 10:43:10 -07001932 clk_disable_unprepare(motg->pclk);
1933 clk_disable_unprepare(motg->clk);
Ivan T. Ivanov6b99c68e2014-04-28 16:34:08 +03001934 if (!IS_ERR(motg->core_clk))
1935 clk_disable_unprepare(motg->core_clk);
Srinivas Kandagatlaa38a08d2016-01-13 09:13:10 +00001936
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05301937 return ret;
1938}
1939
Bill Pembertonfb4e98a2012-11-19 13:26:20 -05001940static int msm_otg_remove(struct platform_device *pdev)
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05301941{
1942 struct msm_otg *motg = platform_get_drvdata(pdev);
Heikki Krogerus1d4c9292012-02-13 13:24:09 +02001943 struct usb_phy *phy = &motg->phy;
Pavankumar Kondeti87c01042010-12-07 17:53:58 +05301944 int cnt = 0;
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05301945
Heikki Krogerus1d4c9292012-02-13 13:24:09 +02001946 if (phy->otg->host || phy->otg->gadget)
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05301947 return -EBUSY;
1948
Ivan T. Ivanov6f98f542015-07-28 11:10:22 +03001949 unregister_reboot_notifier(&motg->reboot);
1950
1951 /*
1952 * Ensure that D+/D- lines are routed to uB connector, so
1953 * we could load bootloader/kernel at next reboot
1954 */
1955 gpiod_set_value_cansleep(motg->switch_gpio, 0);
1956
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05301957 msm_otg_debugfs_cleanup();
Pavankumar Kondetid8608522011-05-04 10:19:47 +05301958 cancel_delayed_work_sync(&motg->chg_work);
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05301959 cancel_work_sync(&motg->sm_work);
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05301960
Pavankumar Kondeti70187732011-02-15 09:42:34 +05301961 pm_runtime_resume(&pdev->dev);
Pavankumar Kondeti87c01042010-12-07 17:53:58 +05301962
1963 device_init_wakeup(&pdev->dev, 0);
1964 pm_runtime_disable(&pdev->dev);
1965
Kishon Vijay Abraham I662dca52012-06-22 17:02:46 +05301966 usb_remove_phy(phy);
Ivan T. Ivanov6b99c68e2014-04-28 16:34:08 +03001967 disable_irq(motg->irq);
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05301968
Pavankumar Kondeti87c01042010-12-07 17:53:58 +05301969 /*
1970 * Put PHY in low power mode.
1971 */
Heikki Krogerus1d4c9292012-02-13 13:24:09 +02001972 ulpi_read(phy, 0x14);
1973 ulpi_write(phy, 0x08, 0x09);
Pavankumar Kondeti87c01042010-12-07 17:53:58 +05301974
1975 writel(readl(USB_PORTSC) | PORTSC_PHCD, USB_PORTSC);
1976 while (cnt < PHY_SUSPEND_TIMEOUT_USEC) {
1977 if (readl(USB_PORTSC) & PORTSC_PHCD)
1978 break;
1979 udelay(1);
1980 cnt++;
1981 }
1982 if (cnt >= PHY_SUSPEND_TIMEOUT_USEC)
Heikki Krogerus1d4c9292012-02-13 13:24:09 +02001983 dev_err(phy->dev, "Unable to suspend PHY\n");
Pavankumar Kondeti87c01042010-12-07 17:53:58 +05301984
Stephen Boydb99a8f62013-06-17 10:43:10 -07001985 clk_disable_unprepare(motg->pclk);
1986 clk_disable_unprepare(motg->clk);
Ivan T. Ivanov6b99c68e2014-04-28 16:34:08 +03001987 if (!IS_ERR(motg->core_clk))
Stephen Boydb99a8f62013-06-17 10:43:10 -07001988 clk_disable_unprepare(motg->core_clk);
Anji jonnala11aa5c42011-05-04 10:19:48 +05301989 msm_hsusb_ldo_init(motg, 0);
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05301990
Pavankumar Kondeti87c01042010-12-07 17:53:58 +05301991 pm_runtime_set_suspended(&pdev->dev);
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05301992
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05301993 return 0;
1994}
1995
Rafael J. Wysockiceb6c9c2014-11-29 23:47:05 +01001996#ifdef CONFIG_PM
Pavankumar Kondeti87c01042010-12-07 17:53:58 +05301997static int msm_otg_runtime_idle(struct device *dev)
1998{
1999 struct msm_otg *motg = dev_get_drvdata(dev);
Heikki Krogerus1d4c9292012-02-13 13:24:09 +02002000 struct usb_otg *otg = motg->phy.otg;
Pavankumar Kondeti87c01042010-12-07 17:53:58 +05302001
2002 dev_dbg(dev, "OTG runtime idle\n");
2003
2004 /*
2005 * It is observed some times that a spurious interrupt
2006 * comes when PHY is put into LPM immediately after PHY reset.
2007 * This 1 sec delay also prevents entering into LPM immediately
2008 * after asynchronous interrupt.
2009 */
Antoine Tenarte47d9252014-10-30 18:41:13 +01002010 if (otg->state != OTG_STATE_UNDEFINED)
Pavankumar Kondeti87c01042010-12-07 17:53:58 +05302011 pm_schedule_suspend(dev, 1000);
2012
2013 return -EAGAIN;
2014}
2015
2016static int msm_otg_runtime_suspend(struct device *dev)
2017{
2018 struct msm_otg *motg = dev_get_drvdata(dev);
2019
2020 dev_dbg(dev, "OTG runtime suspend\n");
2021 return msm_otg_suspend(motg);
2022}
2023
2024static int msm_otg_runtime_resume(struct device *dev)
2025{
2026 struct msm_otg *motg = dev_get_drvdata(dev);
2027
2028 dev_dbg(dev, "OTG runtime resume\n");
2029 return msm_otg_resume(motg);
2030}
Pavankumar Kondeti87c01042010-12-07 17:53:58 +05302031#endif
2032
Pavankumar Kondeti70187732011-02-15 09:42:34 +05302033#ifdef CONFIG_PM_SLEEP
Pavankumar Kondeti87c01042010-12-07 17:53:58 +05302034static int msm_otg_pm_suspend(struct device *dev)
2035{
2036 struct msm_otg *motg = dev_get_drvdata(dev);
2037
2038 dev_dbg(dev, "OTG PM suspend\n");
2039 return msm_otg_suspend(motg);
2040}
2041
2042static int msm_otg_pm_resume(struct device *dev)
2043{
2044 struct msm_otg *motg = dev_get_drvdata(dev);
2045 int ret;
2046
2047 dev_dbg(dev, "OTG PM resume\n");
2048
2049 ret = msm_otg_resume(motg);
2050 if (ret)
2051 return ret;
2052
2053 /*
2054 * Runtime PM Documentation recommends bringing the
2055 * device to full powered state upon resume.
2056 */
2057 pm_runtime_disable(dev);
2058 pm_runtime_set_active(dev);
2059 pm_runtime_enable(dev);
2060
2061 return 0;
2062}
Pavankumar Kondeti87c01042010-12-07 17:53:58 +05302063#endif
2064
2065static const struct dev_pm_ops msm_otg_dev_pm_ops = {
Pavankumar Kondeti70187732011-02-15 09:42:34 +05302066 SET_SYSTEM_SLEEP_PM_OPS(msm_otg_pm_suspend, msm_otg_pm_resume)
2067 SET_RUNTIME_PM_OPS(msm_otg_runtime_suspend, msm_otg_runtime_resume,
2068 msm_otg_runtime_idle)
Pavankumar Kondeti87c01042010-12-07 17:53:58 +05302069};
2070
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05302071static struct platform_driver msm_otg_driver = {
Ivan T. Ivanov06a6ec42014-04-28 16:34:07 +03002072 .probe = msm_otg_probe,
Bill Pemberton76904172012-11-19 13:21:08 -05002073 .remove = msm_otg_remove,
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05302074 .driver = {
2075 .name = DRIVER_NAME,
Pavankumar Kondeti87c01042010-12-07 17:53:58 +05302076 .pm = &msm_otg_dev_pm_ops,
Ivan T. Ivanov8364f9a2014-04-28 16:34:15 +03002077 .of_match_table = msm_otg_dt_match,
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05302078 },
2079};
2080
Ivan T. Ivanov06a6ec42014-04-28 16:34:07 +03002081module_platform_driver(msm_otg_driver);
Pavankumar Kondetie0c201f2010-12-07 17:53:55 +05302082
2083MODULE_LICENSE("GPL v2");
2084MODULE_DESCRIPTION("MSM USB transceiver driver");