blob: a83f6d3770c1618324140d70a426b61ae92411bb [file] [log] [blame]
Vijayavardhan Vennapusa39025fe2011-10-15 05:55:10 +05301/* ehci-msm-hsic.c - HSUSB Host Controller Driver Implementation
2 *
Manu Gautam5143b252012-01-05 19:25:23 -08003 * Copyright (c) 2011-2012, Code Aurora Forum. All rights reserved.
Vijayavardhan Vennapusa39025fe2011-10-15 05:55:10 +05304 *
5 * Partly derived from ehci-fsl.c and ehci-hcd.c
6 * Copyright (c) 2000-2004 by David Brownell
7 * Copyright (c) 2005 MontaVista Software
8 *
9 * All source code in this file is licensed under the following license except
10 * where indicated.
11 *
12 * This program is free software; you can redistribute it and/or modify it
13 * under the terms of the GNU General Public License version 2 as published
14 * by the Free Software Foundation.
15 *
16 * This program is distributed in the hope that it will be useful,
17 * but WITHOUT ANY WARRANTY; without even the implied warranty of
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
19 *
20 * See the GNU General Public License for more details.
21 * You should have received a copy of the GNU General Public License
22 * along with this program; if not, you can find it at http://www.fsf.org
23 */
24
25#include <linux/platform_device.h>
26#include <linux/clk.h>
27#include <linux/err.h>
Hemant Kumare6275972012-02-29 20:06:21 -080028#include <linux/debugfs.h>
29#include <linux/seq_file.h>
Vijayavardhan Vennapusa39025fe2011-10-15 05:55:10 +053030#include <linux/wakelock.h>
31#include <linux/pm_runtime.h>
32#include <linux/regulator/consumer.h>
Hemant Kumare6275972012-02-29 20:06:21 -080033#include <mach/msm_bus.h>
Vijayavardhan Vennapusa39025fe2011-10-15 05:55:10 +053034
35#include <linux/usb/msm_hsusb_hw.h>
Vijayavardhan Vennapusae3316a12011-10-15 06:05:17 +053036#include <linux/usb/msm_hsusb.h>
37#include <linux/gpio.h>
Vijayavardhan Vennapusa39025fe2011-10-15 05:55:10 +053038#include <mach/clk.h>
39#include <mach/msm_iomap.h>
Vijayavardhan Vennapusa2b592824f2011-11-02 19:51:32 +053040#include <mach/msm_xo.h>
Vamsi Krishna34f01582011-12-14 19:54:42 -080041#include <linux/spinlock.h>
Vijayavardhan Vennapusa39025fe2011-10-15 05:55:10 +053042
Hemant Kumar68315252012-04-30 17:44:03 -070043#define RUNTIME_SUSP_DELAY 500
44
Vijayavardhan Vennapusa39025fe2011-10-15 05:55:10 +053045#define MSM_USB_BASE (hcd->regs)
46
47struct msm_hsic_hcd {
48 struct ehci_hcd ehci;
49 struct device *dev;
50 struct clk *ahb_clk;
Manu Gautam5143b252012-01-05 19:25:23 -080051 struct clk *core_clk;
52 struct clk *alt_core_clk;
53 struct clk *phy_clk;
Vijayavardhan Vennapusa39025fe2011-10-15 05:55:10 +053054 struct clk *cal_clk;
55 struct regulator *hsic_vddcx;
56 bool async_int;
57 atomic_t in_lpm;
58 struct wake_lock wlock;
Vamsi Krishna34f01582011-12-14 19:54:42 -080059 int peripheral_status_irq;
Vamsi Krishna6921cbe2012-02-21 18:34:43 -080060 int wakeup_irq;
Jack Phamfe441ea2012-03-23 17:03:15 -070061 bool wakeup_irq_enabled;
Hemant Kumar68315252012-04-30 17:44:03 -070062 bool pm_resume;
Hemant Kumare6275972012-02-29 20:06:21 -080063 uint32_t bus_perf_client;
Vijayavardhan Vennapusa39025fe2011-10-15 05:55:10 +053064};
65
Hemant Kumare6275972012-02-29 20:06:21 -080066static bool debug_bus_voting_enabled = true;
Vijayavardhan Vennapusa39025fe2011-10-15 05:55:10 +053067static inline struct msm_hsic_hcd *hcd_to_hsic(struct usb_hcd *hcd)
68{
69 return (struct msm_hsic_hcd *) (hcd->hcd_priv);
70}
71
72static inline struct usb_hcd *hsic_to_hcd(struct msm_hsic_hcd *mehci)
73{
74 return container_of((void *) mehci, struct usb_hcd, hcd_priv);
75}
76
77#define ULPI_IO_TIMEOUT_USEC (10 * 1000)
78
Vamsi Krishna45d88fa2011-11-02 13:28:42 -070079#define USB_PHY_VDD_DIG_VOL_SUSP_MIN 500000 /* uV */
80#define USB_PHY_VDD_DIG_VOL_MIN 1000000 /* uV */
81#define USB_PHY_VDD_DIG_VOL_MAX 1320000 /* uV */
82#define USB_PHY_VDD_DIG_LOAD 49360 /* uA */
Vijayavardhan Vennapusa39025fe2011-10-15 05:55:10 +053083
Lena Salman8c8ba382012-02-14 15:59:31 +020084#define HSIC_DBG1_REG 0x38
85
Vijayavardhan Vennapusa39025fe2011-10-15 05:55:10 +053086static int msm_hsic_init_vddcx(struct msm_hsic_hcd *mehci, int init)
87{
88 int ret = 0;
89
90 if (!init)
91 goto disable_reg;
92
Mayank Rana189ac052012-03-24 04:35:02 +053093 mehci->hsic_vddcx = devm_regulator_get(mehci->dev, "HSIC_VDDCX");
Vijayavardhan Vennapusa39025fe2011-10-15 05:55:10 +053094 if (IS_ERR(mehci->hsic_vddcx)) {
95 dev_err(mehci->dev, "unable to get hsic vddcx\n");
96 return PTR_ERR(mehci->hsic_vddcx);
97 }
98
99 ret = regulator_set_voltage(mehci->hsic_vddcx,
100 USB_PHY_VDD_DIG_VOL_MIN,
101 USB_PHY_VDD_DIG_VOL_MAX);
102 if (ret) {
103 dev_err(mehci->dev, "unable to set the voltage"
104 "for hsic vddcx\n");
Mayank Rana189ac052012-03-24 04:35:02 +0530105 return ret;
Vijayavardhan Vennapusa39025fe2011-10-15 05:55:10 +0530106 }
107
108 ret = regulator_set_optimum_mode(mehci->hsic_vddcx,
109 USB_PHY_VDD_DIG_LOAD);
110 if (ret < 0) {
111 pr_err("%s: Unable to set optimum mode of the regulator:"
112 "VDDCX\n", __func__);
113 goto reg_optimum_mode_err;
114 }
115
116 ret = regulator_enable(mehci->hsic_vddcx);
117 if (ret) {
118 dev_err(mehci->dev, "unable to enable hsic vddcx\n");
119 goto reg_enable_err;
120 }
121
122 return 0;
123
124disable_reg:
125 regulator_disable(mehci->hsic_vddcx);
126reg_enable_err:
127 regulator_set_optimum_mode(mehci->hsic_vddcx, 0);
128reg_optimum_mode_err:
129 regulator_set_voltage(mehci->hsic_vddcx, 0,
130 USB_PHY_VDD_DIG_VOL_MIN);
Vijayavardhan Vennapusa39025fe2011-10-15 05:55:10 +0530131 return ret;
132
133}
134
135static int ulpi_write(struct msm_hsic_hcd *mehci, u32 val, u32 reg)
136{
137 struct usb_hcd *hcd = hsic_to_hcd(mehci);
138 int cnt = 0;
139
140 /* initiate write operation */
141 writel_relaxed(ULPI_RUN | ULPI_WRITE |
142 ULPI_ADDR(reg) | ULPI_DATA(val),
143 USB_ULPI_VIEWPORT);
144
145 /* wait for completion */
146 while (cnt < ULPI_IO_TIMEOUT_USEC) {
147 if (!(readl_relaxed(USB_ULPI_VIEWPORT) & ULPI_RUN))
148 break;
149 udelay(1);
150 cnt++;
151 }
152
153 if (cnt >= ULPI_IO_TIMEOUT_USEC) {
154 dev_err(mehci->dev, "ulpi_write: timeout\n");
155 return -ETIMEDOUT;
156 }
157
158 return 0;
159}
160
Vijayavardhan Vennapusae3316a12011-10-15 06:05:17 +0530161static int msm_hsic_config_gpios(struct msm_hsic_hcd *mehci, int gpio_en)
162{
163 int rc = 0;
164 struct msm_hsic_host_platform_data *pdata;
Vamsi Krishna34f01582011-12-14 19:54:42 -0800165 static int gpio_status;
Vijayavardhan Vennapusae3316a12011-10-15 06:05:17 +0530166
167 pdata = mehci->dev->platform_data;
Vamsi Krishna34f01582011-12-14 19:54:42 -0800168
Lena Salman8c8ba382012-02-14 15:59:31 +0200169 if (!pdata || !pdata->strobe || !pdata->data)
Vijayavardhan Vennapusae3316a12011-10-15 06:05:17 +0530170 return rc;
171
Vamsi Krishna34f01582011-12-14 19:54:42 -0800172 if (gpio_status == gpio_en)
173 return 0;
174
175 gpio_status = gpio_en;
176
Vijayavardhan Vennapusae3316a12011-10-15 06:05:17 +0530177 if (!gpio_en)
178 goto free_gpio;
179
180 rc = gpio_request(pdata->strobe, "HSIC_STROBE_GPIO");
181 if (rc < 0) {
182 dev_err(mehci->dev, "gpio request failed for HSIC STROBE\n");
183 return rc;
184 }
185
186 rc = gpio_request(pdata->data, "HSIC_DATA_GPIO");
187 if (rc < 0) {
188 dev_err(mehci->dev, "gpio request failed for HSIC DATA\n");
189 goto free_strobe;
190 }
191
192 return 0;
193
194free_gpio:
195 gpio_free(pdata->data);
196free_strobe:
197 gpio_free(pdata->strobe);
198
199 return rc;
200}
201
Vijayavardhan Vennapusa39025fe2011-10-15 05:55:10 +0530202static int msm_hsic_phy_clk_reset(struct msm_hsic_hcd *mehci)
203{
204 int ret;
205
Manu Gautam28b1bac2012-01-30 16:43:06 +0530206 clk_prepare_enable(mehci->alt_core_clk);
Vijayavardhan Vennapusa39025fe2011-10-15 05:55:10 +0530207
Manu Gautam5143b252012-01-05 19:25:23 -0800208 ret = clk_reset(mehci->core_clk, CLK_RESET_ASSERT);
Vijayavardhan Vennapusa39025fe2011-10-15 05:55:10 +0530209 if (ret) {
Manu Gautam28b1bac2012-01-30 16:43:06 +0530210 clk_disable_unprepare(mehci->alt_core_clk);
Vijayavardhan Vennapusa39025fe2011-10-15 05:55:10 +0530211 dev_err(mehci->dev, "usb phy clk assert failed\n");
212 return ret;
213 }
214 usleep_range(10000, 12000);
Manu Gautam28b1bac2012-01-30 16:43:06 +0530215 clk_disable_unprepare(mehci->alt_core_clk);
Vijayavardhan Vennapusa39025fe2011-10-15 05:55:10 +0530216
Manu Gautam5143b252012-01-05 19:25:23 -0800217 ret = clk_reset(mehci->core_clk, CLK_RESET_DEASSERT);
Vijayavardhan Vennapusa39025fe2011-10-15 05:55:10 +0530218 if (ret)
219 dev_err(mehci->dev, "usb phy clk deassert failed\n");
220
221 return ret;
222}
223
224static int msm_hsic_phy_reset(struct msm_hsic_hcd *mehci)
225{
226 struct usb_hcd *hcd = hsic_to_hcd(mehci);
227 u32 val;
228 int ret;
229
230 ret = msm_hsic_phy_clk_reset(mehci);
231 if (ret)
232 return ret;
233
234 val = readl_relaxed(USB_PORTSC) & ~PORTSC_PTS_MASK;
235 writel_relaxed(val | PORTSC_PTS_ULPI, USB_PORTSC);
236
237 /* Ensure that RESET operation is completed before turning off clock */
238 mb();
239 dev_dbg(mehci->dev, "phy_reset: success\n");
240
241 return 0;
242}
243
Vijayavardhan Vennapusae3316a12011-10-15 06:05:17 +0530244#define HSIC_GPIO150_PAD_CTL (MSM_TLMM_BASE+0x20C0)
245#define HSIC_GPIO151_PAD_CTL (MSM_TLMM_BASE+0x20C4)
246#define HSIC_CAL_PAD_CTL (MSM_TLMM_BASE+0x20C8)
247#define HSIC_LV_MODE 0x04
248#define HSIC_PAD_CALIBRATION 0xA8
249#define HSIC_GPIO_PAD_VAL 0x0A0AAA10
Vijayavardhan Vennapusa39025fe2011-10-15 05:55:10 +0530250#define LINK_RESET_TIMEOUT_USEC (250 * 1000)
251static int msm_hsic_reset(struct msm_hsic_hcd *mehci)
252{
253 struct usb_hcd *hcd = hsic_to_hcd(mehci);
254 int cnt = 0;
255 int ret;
Lena Salman8c8ba382012-02-14 15:59:31 +0200256 struct msm_hsic_host_platform_data *pdata = mehci->dev->platform_data;
Vijayavardhan Vennapusa39025fe2011-10-15 05:55:10 +0530257
258 ret = msm_hsic_phy_reset(mehci);
259 if (ret) {
260 dev_err(mehci->dev, "phy_reset failed\n");
261 return ret;
262 }
263
264 writel_relaxed(USBCMD_RESET, USB_USBCMD);
265 while (cnt < LINK_RESET_TIMEOUT_USEC) {
266 if (!(readl_relaxed(USB_USBCMD) & USBCMD_RESET))
267 break;
268 udelay(1);
269 cnt++;
270 }
271 if (cnt >= LINK_RESET_TIMEOUT_USEC)
272 return -ETIMEDOUT;
273
Lena Salman8c8ba382012-02-14 15:59:31 +0200274 /* Reset PORTSC and select ULPI phy */
Vijayavardhan Vennapusa39025fe2011-10-15 05:55:10 +0530275 writel_relaxed(0x80000000, USB_PORTSC);
276
277 /* TODO: Need to confirm if HSIC PHY also requires delay after RESET */
278 msleep(100);
279
280 /* HSIC PHY Initialization */
Vijayavardhan Vennapusae3316a12011-10-15 06:05:17 +0530281
Lena Salman8c8ba382012-02-14 15:59:31 +0200282 /* HSIC init sequence when HSIC signals (Strobe/Data) are
283 routed via GPIOs */
284 if (pdata && pdata->strobe && pdata->data) {
Vijayavardhan Vennapusae3316a12011-10-15 06:05:17 +0530285
Lena Salman8c8ba382012-02-14 15:59:31 +0200286 /* Enable LV_MODE in HSIC_CAL_PAD_CTL register */
287 writel_relaxed(HSIC_LV_MODE, HSIC_CAL_PAD_CTL);
Vijayavardhan Vennapusae3316a12011-10-15 06:05:17 +0530288
Lena Salman8c8ba382012-02-14 15:59:31 +0200289 /*set periodic calibration interval to ~2.048sec in
290 HSIC_IO_CAL_REG */
291 ulpi_write(mehci, 0xFF, 0x33);
292
293 /* Enable periodic IO calibration in HSIC_CFG register */
294 ulpi_write(mehci, HSIC_PAD_CALIBRATION, 0x30);
295
296 /* Configure GPIO 150/151 pins for HSIC functionality mode */
297 ret = msm_hsic_config_gpios(mehci, 1);
298 if (ret) {
299 dev_err(mehci->dev, " gpio configuarion failed\n");
300 return ret;
301 }
302 /* Set LV_MODE=0x1 and DCC=0x2 in HSIC_GPIO150/151_PAD_CTL
303 register */
304 writel_relaxed(HSIC_GPIO_PAD_VAL, HSIC_GPIO150_PAD_CTL);
305 writel_relaxed(HSIC_GPIO_PAD_VAL, HSIC_GPIO151_PAD_CTL);
306 /* Enable HSIC mode in HSIC_CFG register */
307 ulpi_write(mehci, 0x01, 0x31);
308 } else {
309 /* HSIC init sequence when HSIC signals (Strobe/Data) are routed
310 via dedicated I/O */
311
312 /* programmable length of connect signaling (33.2ns) */
313 ret = ulpi_write(mehci, 3, HSIC_DBG1_REG);
314 if (ret) {
315 pr_err("%s: Unable to program length of connect "
316 "signaling\n", __func__);
317 }
318
319 /*set periodic calibration interval to ~2.048sec in
320 HSIC_IO_CAL_REG */
321 ulpi_write(mehci, 0xFF, 0x33);
322
323 /* Enable HSIC mode in HSIC_CFG register */
324 ulpi_write(mehci, 0xA9, 0x30);
Vijayavardhan Vennapusae3316a12011-10-15 06:05:17 +0530325 }
326
Vijayavardhan Vennapusa39025fe2011-10-15 05:55:10 +0530327 return 0;
328}
329
330#define PHY_SUSPEND_TIMEOUT_USEC (500 * 1000)
331#define PHY_RESUME_TIMEOUT_USEC (100 * 1000)
332
333#ifdef CONFIG_PM_SLEEP
334static int msm_hsic_suspend(struct msm_hsic_hcd *mehci)
335{
336 struct usb_hcd *hcd = hsic_to_hcd(mehci);
Vijayavardhan Vennapusa2b592824f2011-11-02 19:51:32 +0530337 int cnt = 0, ret;
Vijayavardhan Vennapusa39025fe2011-10-15 05:55:10 +0530338 u32 val;
339
340 if (atomic_read(&mehci->in_lpm)) {
341 dev_dbg(mehci->dev, "%s called in lpm\n", __func__);
342 return 0;
343 }
344
345 disable_irq(hcd->irq);
346 /*
347 * PHY may take some time or even fail to enter into low power
348 * mode (LPM). Hence poll for 500 msec and reset the PHY and link
349 * in failure case.
350 */
351 val = readl_relaxed(USB_PORTSC) | PORTSC_PHCD;
352 writel_relaxed(val, USB_PORTSC);
353 while (cnt < PHY_SUSPEND_TIMEOUT_USEC) {
354 if (readl_relaxed(USB_PORTSC) & PORTSC_PHCD)
355 break;
356 udelay(1);
357 cnt++;
358 }
359
360 if (cnt >= PHY_SUSPEND_TIMEOUT_USEC) {
361 dev_err(mehci->dev, "Unable to suspend PHY\n");
Vijayavardhan Vennapusae3316a12011-10-15 06:05:17 +0530362 msm_hsic_config_gpios(mehci, 0);
Vijayavardhan Vennapusa39025fe2011-10-15 05:55:10 +0530363 msm_hsic_reset(mehci);
Vijayavardhan Vennapusa39025fe2011-10-15 05:55:10 +0530364 }
365
366 /*
367 * PHY has capability to generate interrupt asynchronously in low
368 * power mode (LPM). This interrupt is level triggered. So USB IRQ
369 * line must be disabled till async interrupt enable bit is cleared
370 * in USBCMD register. Assert STP (ULPI interface STOP signal) to
371 * block data communication from PHY.
372 */
373 writel_relaxed(readl_relaxed(USB_USBCMD) | ASYNC_INTR_CTRL |
374 ULPI_STP_CTRL, USB_USBCMD);
375
376 /*
377 * Ensure that hardware is put in low power mode before
378 * clocks are turned OFF and VDD is allowed to minimize.
379 */
380 mb();
381
Manu Gautam28b1bac2012-01-30 16:43:06 +0530382 clk_disable_unprepare(mehci->core_clk);
383 clk_disable_unprepare(mehci->phy_clk);
384 clk_disable_unprepare(mehci->cal_clk);
385 clk_disable_unprepare(mehci->ahb_clk);
Vijayavardhan Vennapusa39025fe2011-10-15 05:55:10 +0530386
Vamsi Krishna45d88fa2011-11-02 13:28:42 -0700387 ret = regulator_set_voltage(mehci->hsic_vddcx,
388 USB_PHY_VDD_DIG_VOL_SUSP_MIN,
389 USB_PHY_VDD_DIG_VOL_MAX);
390 if (ret < 0)
391 dev_err(mehci->dev, "unable to set vddcx voltage: min:0.5v max:1.3v\n");
392
Hemant Kumare6275972012-02-29 20:06:21 -0800393 if (mehci->bus_perf_client && debug_bus_voting_enabled) {
394 ret = msm_bus_scale_client_update_request(
395 mehci->bus_perf_client, 0);
396 if (ret)
397 dev_err(mehci->dev, "%s: Failed to dvote for "
398 "bus bandwidth %d\n", __func__, ret);
399 }
400
Vijayavardhan Vennapusa39025fe2011-10-15 05:55:10 +0530401 atomic_set(&mehci->in_lpm, 1);
402 enable_irq(hcd->irq);
403 wake_unlock(&mehci->wlock);
404
405 dev_info(mehci->dev, "HSIC-USB in low power mode\n");
406
407 return 0;
408}
409
410static int msm_hsic_resume(struct msm_hsic_hcd *mehci)
411{
412 struct usb_hcd *hcd = hsic_to_hcd(mehci);
Vijayavardhan Vennapusa2b592824f2011-11-02 19:51:32 +0530413 int cnt = 0, ret;
Vijayavardhan Vennapusa39025fe2011-10-15 05:55:10 +0530414 unsigned temp;
415
416 if (!atomic_read(&mehci->in_lpm)) {
417 dev_dbg(mehci->dev, "%s called in !in_lpm\n", __func__);
418 return 0;
419 }
420
421 wake_lock(&mehci->wlock);
422
Hemant Kumare6275972012-02-29 20:06:21 -0800423 if (mehci->bus_perf_client && debug_bus_voting_enabled) {
424 ret = msm_bus_scale_client_update_request(
425 mehci->bus_perf_client, 1);
426 if (ret)
427 dev_err(mehci->dev, "%s: Failed to vote for "
428 "bus bandwidth %d\n", __func__, ret);
429 }
430
Vamsi Krishna45d88fa2011-11-02 13:28:42 -0700431 ret = regulator_set_voltage(mehci->hsic_vddcx,
432 USB_PHY_VDD_DIG_VOL_MIN,
433 USB_PHY_VDD_DIG_VOL_MAX);
434 if (ret < 0)
435 dev_err(mehci->dev, "unable to set vddcx voltage: min:1v max:1.3v\n");
436
Manu Gautam28b1bac2012-01-30 16:43:06 +0530437 clk_prepare_enable(mehci->core_clk);
438 clk_prepare_enable(mehci->phy_clk);
439 clk_prepare_enable(mehci->cal_clk);
440 clk_prepare_enable(mehci->ahb_clk);
Vijayavardhan Vennapusa39025fe2011-10-15 05:55:10 +0530441
442 temp = readl_relaxed(USB_USBCMD);
443 temp &= ~ASYNC_INTR_CTRL;
444 temp &= ~ULPI_STP_CTRL;
445 writel_relaxed(temp, USB_USBCMD);
446
447 if (!(readl_relaxed(USB_PORTSC) & PORTSC_PHCD))
448 goto skip_phy_resume;
449
450 temp = readl_relaxed(USB_PORTSC) & ~PORTSC_PHCD;
451 writel_relaxed(temp, USB_PORTSC);
452 while (cnt < PHY_RESUME_TIMEOUT_USEC) {
453 if (!(readl_relaxed(USB_PORTSC) & PORTSC_PHCD) &&
454 (readl_relaxed(USB_ULPI_VIEWPORT) & ULPI_SYNC_STATE))
455 break;
456 udelay(1);
457 cnt++;
458 }
459
460 if (cnt >= PHY_RESUME_TIMEOUT_USEC) {
461 /*
462 * This is a fatal error. Reset the link and
463 * PHY to make hsic working.
464 */
465 dev_err(mehci->dev, "Unable to resume USB. Reset the hsic\n");
Vijayavardhan Vennapusae3316a12011-10-15 06:05:17 +0530466 msm_hsic_config_gpios(mehci, 0);
Vijayavardhan Vennapusa39025fe2011-10-15 05:55:10 +0530467 msm_hsic_reset(mehci);
468 }
469
470skip_phy_resume:
471
472 atomic_set(&mehci->in_lpm, 0);
473
474 if (mehci->async_int) {
475 mehci->async_int = false;
476 pm_runtime_put_noidle(mehci->dev);
477 enable_irq(hcd->irq);
478 }
479
480 dev_info(mehci->dev, "HSIC-USB exited from low power mode\n");
481
482 return 0;
483}
484#endif
485
486static irqreturn_t msm_hsic_irq(struct usb_hcd *hcd)
487{
488 struct msm_hsic_hcd *mehci = hcd_to_hsic(hcd);
489
490 if (atomic_read(&mehci->in_lpm)) {
491 disable_irq_nosync(hcd->irq);
492 mehci->async_int = true;
493 pm_runtime_get(mehci->dev);
494 return IRQ_HANDLED;
495 }
496
497 return ehci_irq(hcd);
498}
499
500static int ehci_hsic_reset(struct usb_hcd *hcd)
501{
502 struct ehci_hcd *ehci = hcd_to_ehci(hcd);
503 int retval;
504
505 ehci->caps = USB_CAPLENGTH;
506 ehci->regs = USB_CAPLENGTH +
507 HC_LENGTH(ehci, ehci_readl(ehci, &ehci->caps->hc_capbase));
508 dbg_hcs_params(ehci, "reset");
509 dbg_hcc_params(ehci, "reset");
510
511 /* cache the data to minimize the chip reads*/
512 ehci->hcs_params = ehci_readl(ehci, &ehci->caps->hcs_params);
513
514 hcd->has_tt = 1;
515 ehci->sbrn = HCD_USB2;
516
517 retval = ehci_halt(ehci);
518 if (retval)
519 return retval;
520
521 /* data structure init */
522 retval = ehci_init(hcd);
523 if (retval)
524 return retval;
525
526 retval = ehci_reset(ehci);
527 if (retval)
528 return retval;
529
530 /* bursts of unspecified length. */
531 writel_relaxed(0, USB_AHBBURST);
532 /* Use the AHB transactor */
Vijayavardhan Vennapusa5f32d7a2012-03-14 16:30:26 +0530533 writel_relaxed(0x08, USB_AHBMODE);
Vijayavardhan Vennapusa39025fe2011-10-15 05:55:10 +0530534 /* Disable streaming mode and select host mode */
535 writel_relaxed(0x13, USB_USBMODE);
536
537 ehci_port_power(ehci, 1);
538 return 0;
539}
540
541static struct hc_driver msm_hsic_driver = {
542 .description = hcd_name,
543 .product_desc = "Qualcomm EHCI Host Controller using HSIC",
544 .hcd_priv_size = sizeof(struct msm_hsic_hcd),
545
546 /*
547 * generic hardware linkage
548 */
549 .irq = msm_hsic_irq,
550 .flags = HCD_USB2 | HCD_MEMORY,
551
552 .reset = ehci_hsic_reset,
553 .start = ehci_run,
554
555 .stop = ehci_stop,
556 .shutdown = ehci_shutdown,
557
558 /*
559 * managing i/o requests and associated device resources
560 */
561 .urb_enqueue = ehci_urb_enqueue,
562 .urb_dequeue = ehci_urb_dequeue,
563 .endpoint_disable = ehci_endpoint_disable,
564 .endpoint_reset = ehci_endpoint_reset,
565 .clear_tt_buffer_complete = ehci_clear_tt_buffer_complete,
566
567 /*
568 * scheduling support
569 */
570 .get_frame_number = ehci_get_frame,
571
572 /*
573 * root hub support
574 */
575 .hub_status_data = ehci_hub_status_data,
576 .hub_control = ehci_hub_control,
577 .relinquish_port = ehci_relinquish_port,
578 .port_handed_over = ehci_port_handed_over,
579
580 /*
581 * PM support
582 */
583 .bus_suspend = ehci_bus_suspend,
584 .bus_resume = ehci_bus_resume,
585};
586
587static int msm_hsic_init_clocks(struct msm_hsic_hcd *mehci, u32 init)
588{
589 int ret = 0;
590
591 if (!init)
592 goto put_clocks;
593
Lena Salman8c8ba382012-02-14 15:59:31 +0200594 /*core_clk is required for LINK protocol engine
595 *clock rate appropriately set by target specific clock driver */
Manu Gautam5143b252012-01-05 19:25:23 -0800596 mehci->core_clk = clk_get(mehci->dev, "core_clk");
597 if (IS_ERR(mehci->core_clk)) {
598 dev_err(mehci->dev, "failed to get core_clk\n");
599 ret = PTR_ERR(mehci->core_clk);
Vijayavardhan Vennapusa39025fe2011-10-15 05:55:10 +0530600 return ret;
601 }
Vijayavardhan Vennapusa39025fe2011-10-15 05:55:10 +0530602
Lena Salman8c8ba382012-02-14 15:59:31 +0200603 /* alt_core_clk is for LINK to be used during PHY RESET
604 * clock rate appropriately set by target specific clock driver */
Manu Gautam5143b252012-01-05 19:25:23 -0800605 mehci->alt_core_clk = clk_get(mehci->dev, "alt_core_clk");
606 if (IS_ERR(mehci->alt_core_clk)) {
607 dev_err(mehci->dev, "failed to core_clk\n");
608 ret = PTR_ERR(mehci->alt_core_clk);
609 goto put_core_clk;
Vijayavardhan Vennapusa39025fe2011-10-15 05:55:10 +0530610 }
Vijayavardhan Vennapusa39025fe2011-10-15 05:55:10 +0530611
Lena Salman8c8ba382012-02-14 15:59:31 +0200612 /* phy_clk is required for HSIC PHY operation
613 * clock rate appropriately set by target specific clock driver */
Manu Gautam5143b252012-01-05 19:25:23 -0800614 mehci->phy_clk = clk_get(mehci->dev, "phy_clk");
615 if (IS_ERR(mehci->phy_clk)) {
616 dev_err(mehci->dev, "failed to get phy_clk\n");
617 ret = PTR_ERR(mehci->phy_clk);
618 goto put_alt_core_clk;
Vijayavardhan Vennapusa39025fe2011-10-15 05:55:10 +0530619 }
Vijayavardhan Vennapusa39025fe2011-10-15 05:55:10 +0530620
621 /* 10MHz cal_clk is required for calibration of I/O pads */
Manu Gautam5143b252012-01-05 19:25:23 -0800622 mehci->cal_clk = clk_get(mehci->dev, "cal_clk");
Vijayavardhan Vennapusa39025fe2011-10-15 05:55:10 +0530623 if (IS_ERR(mehci->cal_clk)) {
Manu Gautam5143b252012-01-05 19:25:23 -0800624 dev_err(mehci->dev, "failed to get cal_clk\n");
Vijayavardhan Vennapusa39025fe2011-10-15 05:55:10 +0530625 ret = PTR_ERR(mehci->cal_clk);
Manu Gautam5143b252012-01-05 19:25:23 -0800626 goto put_phy_clk;
Vijayavardhan Vennapusa39025fe2011-10-15 05:55:10 +0530627 }
628 clk_set_rate(mehci->cal_clk, 10000000);
629
630 /* ahb_clk is required for data transfers */
Manu Gautam5143b252012-01-05 19:25:23 -0800631 mehci->ahb_clk = clk_get(mehci->dev, "iface_clk");
Vijayavardhan Vennapusa39025fe2011-10-15 05:55:10 +0530632 if (IS_ERR(mehci->ahb_clk)) {
Manu Gautam5143b252012-01-05 19:25:23 -0800633 dev_err(mehci->dev, "failed to get iface_clk\n");
Vijayavardhan Vennapusa39025fe2011-10-15 05:55:10 +0530634 ret = PTR_ERR(mehci->ahb_clk);
635 goto put_cal_clk;
636 }
637
Manu Gautam28b1bac2012-01-30 16:43:06 +0530638 clk_prepare_enable(mehci->core_clk);
639 clk_prepare_enable(mehci->phy_clk);
640 clk_prepare_enable(mehci->cal_clk);
641 clk_prepare_enable(mehci->ahb_clk);
Vijayavardhan Vennapusa39025fe2011-10-15 05:55:10 +0530642
643 return 0;
644
645put_clocks:
Jack Phamfd193eb2012-02-22 15:38:08 -0800646 if (!atomic_read(&mehci->in_lpm)) {
647 clk_disable_unprepare(mehci->core_clk);
648 clk_disable_unprepare(mehci->phy_clk);
649 clk_disable_unprepare(mehci->cal_clk);
650 clk_disable_unprepare(mehci->ahb_clk);
651 }
Vijayavardhan Vennapusa39025fe2011-10-15 05:55:10 +0530652 clk_put(mehci->ahb_clk);
653put_cal_clk:
654 clk_put(mehci->cal_clk);
Manu Gautam5143b252012-01-05 19:25:23 -0800655put_phy_clk:
656 clk_put(mehci->phy_clk);
657put_alt_core_clk:
658 clk_put(mehci->alt_core_clk);
659put_core_clk:
660 clk_put(mehci->core_clk);
Vijayavardhan Vennapusa39025fe2011-10-15 05:55:10 +0530661
662 return ret;
663}
Vamsi Krishna34f01582011-12-14 19:54:42 -0800664static irqreturn_t hsic_peripheral_status_change(int irq, void *dev_id)
665{
666 struct msm_hsic_hcd *mehci = dev_id;
667
Vamsi Krishna6921cbe2012-02-21 18:34:43 -0800668 pr_debug("%s: mehci:%p dev_id:%p\n", __func__, mehci, dev_id);
Vamsi Krishna34f01582011-12-14 19:54:42 -0800669
670 if (mehci)
671 msm_hsic_config_gpios(mehci, 0);
672
673 return IRQ_HANDLED;
674}
675
Vamsi Krishna6921cbe2012-02-21 18:34:43 -0800676static irqreturn_t msm_hsic_wakeup_irq(int irq, void *data)
677{
678 struct msm_hsic_hcd *mehci = data;
679
680 dev_dbg(mehci->dev, "%s: hsic remote wakeup interrupt\n", __func__);
681
Jack Phamfe441ea2012-03-23 17:03:15 -0700682 if (mehci->wakeup_irq_enabled) {
683 mehci->wakeup_irq_enabled = 0;
684 disable_irq_wake(irq);
685 disable_irq_nosync(irq);
686 }
687
Vamsi Krishna6921cbe2012-02-21 18:34:43 -0800688 return IRQ_HANDLED;
689}
690
Hemant Kumare6275972012-02-29 20:06:21 -0800691static int ehci_hsic_msm_bus_show(struct seq_file *s, void *unused)
692{
693 if (debug_bus_voting_enabled)
694 seq_printf(s, "enabled\n");
695 else
696 seq_printf(s, "disabled\n");
697
698 return 0;
699}
700
701static int ehci_hsic_msm_bus_open(struct inode *inode, struct file *file)
702{
703 return single_open(file, ehci_hsic_msm_bus_show, inode->i_private);
704}
705
706static ssize_t ehci_hsic_msm_bus_write(struct file *file,
707 const char __user *ubuf, size_t count, loff_t *ppos)
708{
709 char buf[8];
710 int ret;
711 struct seq_file *s = file->private_data;
712 struct msm_hsic_hcd *mehci = s->private;
713
714 memset(buf, 0x00, sizeof(buf));
715
716 if (copy_from_user(&buf, ubuf, min_t(size_t, sizeof(buf) - 1, count)))
717 return -EFAULT;
718
719 if (!strncmp(buf, "enable", 6)) {
720 /* Do not vote here. Let hsic driver decide when to vote */
721 debug_bus_voting_enabled = true;
722 } else {
723 debug_bus_voting_enabled = false;
724 if (mehci->bus_perf_client) {
725 ret = msm_bus_scale_client_update_request(
726 mehci->bus_perf_client, 0);
727 if (ret)
728 dev_err(mehci->dev, "%s: Failed to devote "
729 "for bus bw %d\n", __func__, ret);
730 }
731 }
732
733 return count;
734}
735
736const struct file_operations ehci_hsic_msm_bus_fops = {
737 .open = ehci_hsic_msm_bus_open,
738 .read = seq_read,
739 .write = ehci_hsic_msm_bus_write,
740 .llseek = seq_lseek,
741 .release = single_release,
742};
743
744static struct dentry *ehci_hsic_msm_dbg_root;
745static int ehci_hsic_msm_debugfs_init(struct msm_hsic_hcd *mehci)
746{
747 struct dentry *ehci_hsic_msm_dentry;
748
749 ehci_hsic_msm_dbg_root = debugfs_create_dir("ehci_hsic_msm_dbg", NULL);
750
751 if (!ehci_hsic_msm_dbg_root || IS_ERR(ehci_hsic_msm_dbg_root))
752 return -ENODEV;
753
754 ehci_hsic_msm_dentry = debugfs_create_file("bus_voting",
755 S_IRUGO | S_IWUSR,
756 ehci_hsic_msm_dbg_root, mehci,
757 &ehci_hsic_msm_bus_fops);
758
759 if (!ehci_hsic_msm_dentry) {
760 debugfs_remove_recursive(ehci_hsic_msm_dbg_root);
761 return -ENODEV;
762 }
763
764 return 0;
765}
766
767static void ehci_hsic_msm_debugfs_cleanup(void)
768{
769 debugfs_remove_recursive(ehci_hsic_msm_dbg_root);
770}
771
Vijayavardhan Vennapusa39025fe2011-10-15 05:55:10 +0530772static int __devinit ehci_hsic_msm_probe(struct platform_device *pdev)
773{
774 struct usb_hcd *hcd;
775 struct resource *res;
776 struct msm_hsic_hcd *mehci;
Vijayavardhan Vennapusa2b592824f2011-11-02 19:51:32 +0530777 struct msm_hsic_host_platform_data *pdata;
Vijayavardhan Vennapusa39025fe2011-10-15 05:55:10 +0530778 int ret;
779
780 dev_dbg(&pdev->dev, "ehci_msm-hsic probe\n");
781
Vijayavardhan Vennapusaafbbb8f2012-04-13 16:28:45 +0530782 /* After parent device's probe is executed, it will be put in suspend
783 * mode. When child device's probe is called, driver core is not
784 * resuming parent device due to which parent will be in suspend even
785 * though child is active. Hence resume the parent device explicitly.
786 */
787 if (pdev->dev.parent)
788 pm_runtime_get_sync(pdev->dev.parent);
789
Vijayavardhan Vennapusa39025fe2011-10-15 05:55:10 +0530790 hcd = usb_create_hcd(&msm_hsic_driver, &pdev->dev,
791 dev_name(&pdev->dev));
792 if (!hcd) {
793 dev_err(&pdev->dev, "Unable to create HCD\n");
794 return -ENOMEM;
795 }
796
797 hcd->irq = platform_get_irq(pdev, 0);
798 if (hcd->irq < 0) {
799 dev_err(&pdev->dev, "Unable to get IRQ resource\n");
800 ret = hcd->irq;
801 goto put_hcd;
802 }
803
804 res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
805 if (!res) {
806 dev_err(&pdev->dev, "Unable to get memory resource\n");
807 ret = -ENODEV;
808 goto put_hcd;
809 }
810
811 hcd->rsrc_start = res->start;
812 hcd->rsrc_len = resource_size(res);
813 hcd->regs = ioremap(hcd->rsrc_start, hcd->rsrc_len);
814 if (!hcd->regs) {
815 dev_err(&pdev->dev, "ioremap failed\n");
816 ret = -ENOMEM;
817 goto put_hcd;
818 }
819
820 mehci = hcd_to_hsic(hcd);
821 mehci->dev = &pdev->dev;
822
Vamsi Krishna34f01582011-12-14 19:54:42 -0800823 res = platform_get_resource_byname(pdev,
824 IORESOURCE_IRQ,
825 "peripheral_status_irq");
826 if (res)
827 mehci->peripheral_status_irq = res->start;
828
Vijayavardhan Vennapusa39025fe2011-10-15 05:55:10 +0530829 ret = msm_hsic_init_clocks(mehci, 1);
830 if (ret) {
831 dev_err(&pdev->dev, "unable to initialize clocks\n");
832 ret = -ENODEV;
833 goto unmap;
834 }
835
836 ret = msm_hsic_init_vddcx(mehci, 1);
837 if (ret) {
838 dev_err(&pdev->dev, "unable to initialize VDDCX\n");
839 ret = -ENODEV;
840 goto deinit_clocks;
841 }
842
843 ret = msm_hsic_reset(mehci);
844 if (ret) {
845 dev_err(&pdev->dev, "unable to initialize PHY\n");
Vijayavardhan Vennapusaafbbb8f2012-04-13 16:28:45 +0530846 goto deinit_vddcx;
Vijayavardhan Vennapusa39025fe2011-10-15 05:55:10 +0530847 }
848
849 ret = usb_add_hcd(hcd, hcd->irq, IRQF_SHARED);
850 if (ret) {
851 dev_err(&pdev->dev, "unable to register HCD\n");
Vijayavardhan Vennapusae3316a12011-10-15 06:05:17 +0530852 goto unconfig_gpio;
Vijayavardhan Vennapusa39025fe2011-10-15 05:55:10 +0530853 }
854
855 device_init_wakeup(&pdev->dev, 1);
856 wake_lock_init(&mehci->wlock, WAKE_LOCK_SUSPEND, dev_name(&pdev->dev));
857 wake_lock(&mehci->wlock);
Vamsi Krishna34f01582011-12-14 19:54:42 -0800858
859 if (mehci->peripheral_status_irq) {
860 ret = request_threaded_irq(mehci->peripheral_status_irq,
861 NULL, hsic_peripheral_status_change,
862 IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING
863 | IRQF_SHARED,
864 "hsic_peripheral_status", mehci);
865 if (ret)
866 dev_err(&pdev->dev, "%s:request_irq:%d failed:%d",
867 __func__, mehci->peripheral_status_irq, ret);
868 }
869
Vamsi Krishna6921cbe2012-02-21 18:34:43 -0800870 /* configure wakeup irq */
871 ret = platform_get_irq(pdev, 2);
872 if (ret > 0) {
873 mehci->wakeup_irq = ret;
874 dev_dbg(&pdev->dev, "wakeup_irq: %d\n", mehci->wakeup_irq);
875 ret = request_irq(mehci->wakeup_irq, msm_hsic_wakeup_irq,
876 IRQF_TRIGGER_LOW,
877 "msm_hsic_wakeup", mehci);
878 if (!ret) {
879 disable_irq_nosync(mehci->wakeup_irq);
Vamsi Krishna6921cbe2012-02-21 18:34:43 -0800880 } else {
881 dev_err(&pdev->dev, "request_irq(%d) failed: %d\n",
882 mehci->wakeup_irq, ret);
883 mehci->wakeup_irq = 0;
884 }
885 }
886
Hemant Kumare6275972012-02-29 20:06:21 -0800887 ret = ehci_hsic_msm_debugfs_init(mehci);
888 if (ret)
889 dev_dbg(&pdev->dev, "mode debugfs file is"
890 "not available\n");
891
Vijayavardhan Vennapusaafbbb8f2012-04-13 16:28:45 +0530892 pdata = mehci->dev->platform_data;
Hemant Kumare6275972012-02-29 20:06:21 -0800893 if (pdata && pdata->bus_scale_table) {
894 mehci->bus_perf_client =
895 msm_bus_scale_register_client(pdata->bus_scale_table);
896 /* Configure BUS performance parameters for MAX bandwidth */
897 if (mehci->bus_perf_client) {
898 ret = msm_bus_scale_client_update_request(
899 mehci->bus_perf_client, 1);
900 if (ret)
901 dev_err(&pdev->dev, "%s: Failed to vote for "
902 "bus bandwidth %d\n", __func__, ret);
903 } else {
904 dev_err(&pdev->dev, "%s: Failed to register BUS "
905 "scaling client!!\n", __func__);
906 }
907 }
908
Vijayavardhan Vennapusa39025fe2011-10-15 05:55:10 +0530909 /*
910 * This pdev->dev is assigned parent of root-hub by USB core,
911 * hence, runtime framework automatically calls this driver's
912 * runtime APIs based on root-hub's state.
913 */
914 pm_runtime_set_active(&pdev->dev);
915 pm_runtime_enable(&pdev->dev);
Vijayavardhan Vennapusaafbbb8f2012-04-13 16:28:45 +0530916 /* Decrement the parent device's counter after probe.
917 * As child is active, parent will not be put into
918 * suspend mode.
919 */
920 if (pdev->dev.parent)
921 pm_runtime_put_sync(pdev->dev.parent);
Vijayavardhan Vennapusa39025fe2011-10-15 05:55:10 +0530922
923 return 0;
924
Vijayavardhan Vennapusae3316a12011-10-15 06:05:17 +0530925unconfig_gpio:
926 msm_hsic_config_gpios(mehci, 0);
Vijayavardhan Vennapusa39025fe2011-10-15 05:55:10 +0530927deinit_vddcx:
928 msm_hsic_init_vddcx(mehci, 0);
929deinit_clocks:
930 msm_hsic_init_clocks(mehci, 0);
931unmap:
932 iounmap(hcd->regs);
933put_hcd:
934 usb_put_hcd(hcd);
935
936 return ret;
937}
938
939static int __devexit ehci_hsic_msm_remove(struct platform_device *pdev)
940{
941 struct usb_hcd *hcd = platform_get_drvdata(pdev);
942 struct msm_hsic_hcd *mehci = hcd_to_hsic(hcd);
943
Vamsi Krishna34f01582011-12-14 19:54:42 -0800944 if (mehci->peripheral_status_irq)
945 free_irq(mehci->peripheral_status_irq, mehci);
Jack Phamfe441ea2012-03-23 17:03:15 -0700946
Vamsi Krishna6921cbe2012-02-21 18:34:43 -0800947 if (mehci->wakeup_irq) {
Jack Phamfe441ea2012-03-23 17:03:15 -0700948 if (mehci->wakeup_irq_enabled)
949 disable_irq_wake(mehci->wakeup_irq);
Vamsi Krishna6921cbe2012-02-21 18:34:43 -0800950 free_irq(mehci->wakeup_irq, mehci);
951 }
Vamsi Krishna34f01582011-12-14 19:54:42 -0800952
Hemant Kumare6275972012-02-29 20:06:21 -0800953 if (mehci->bus_perf_client)
954 msm_bus_scale_unregister_client(mehci->bus_perf_client);
955
956 ehci_hsic_msm_debugfs_cleanup();
Vijayavardhan Vennapusa39025fe2011-10-15 05:55:10 +0530957 device_init_wakeup(&pdev->dev, 0);
Hemant Kumar68315252012-04-30 17:44:03 -0700958 mehci->pm_resume = false;
Vijayavardhan Vennapusa39025fe2011-10-15 05:55:10 +0530959 pm_runtime_set_suspended(&pdev->dev);
960
961 usb_remove_hcd(hcd);
Vijayavardhan Vennapusae3316a12011-10-15 06:05:17 +0530962 msm_hsic_config_gpios(mehci, 0);
Vijayavardhan Vennapusa39025fe2011-10-15 05:55:10 +0530963 msm_hsic_init_vddcx(mehci, 0);
964
965 msm_hsic_init_clocks(mehci, 0);
966 wake_lock_destroy(&mehci->wlock);
967 iounmap(hcd->regs);
968 usb_put_hcd(hcd);
969
970 return 0;
971}
972
973#ifdef CONFIG_PM_SLEEP
974static int msm_hsic_pm_suspend(struct device *dev)
975{
976 struct usb_hcd *hcd = dev_get_drvdata(dev);
977 struct msm_hsic_hcd *mehci = hcd_to_hsic(hcd);
978
979 dev_dbg(dev, "ehci-msm-hsic PM suspend\n");
980
981 if (device_may_wakeup(dev))
982 enable_irq_wake(hcd->irq);
983
Hemant Kumar68315252012-04-30 17:44:03 -0700984 mehci->pm_resume = false;
985
Vijayavardhan Vennapusa39025fe2011-10-15 05:55:10 +0530986 return msm_hsic_suspend(mehci);
Jack Phamfe441ea2012-03-23 17:03:15 -0700987}
Vijayavardhan Vennapusa39025fe2011-10-15 05:55:10 +0530988
Jack Phamfe441ea2012-03-23 17:03:15 -0700989static int msm_hsic_pm_suspend_noirq(struct device *dev)
990{
991 struct usb_hcd *hcd = dev_get_drvdata(dev);
992 struct msm_hsic_hcd *mehci = hcd_to_hsic(hcd);
993
994 dev_dbg(dev, "ehci-msm-hsic PM suspend_noirq\n");
995
996 if (device_may_wakeup(dev) && !mehci->wakeup_irq_enabled) {
997 enable_irq(mehci->wakeup_irq);
998 enable_irq_wake(mehci->wakeup_irq);
999 mehci->wakeup_irq_enabled = 1;
1000 }
1001
1002 return 0;
Vijayavardhan Vennapusa39025fe2011-10-15 05:55:10 +05301003}
1004
1005static int msm_hsic_pm_resume(struct device *dev)
1006{
1007 int ret;
1008 struct usb_hcd *hcd = dev_get_drvdata(dev);
1009 struct msm_hsic_hcd *mehci = hcd_to_hsic(hcd);
1010
1011 dev_dbg(dev, "ehci-msm-hsic PM resume\n");
1012
1013 if (device_may_wakeup(dev))
1014 disable_irq_wake(hcd->irq);
1015
Jack Phamfe441ea2012-03-23 17:03:15 -07001016 if (mehci->wakeup_irq_enabled) {
1017 mehci->wakeup_irq_enabled = 0;
1018 disable_irq_wake(mehci->wakeup_irq);
1019 disable_irq_nosync(mehci->wakeup_irq);
1020 }
1021
Hemant Kumar68315252012-04-30 17:44:03 -07001022 mehci->pm_resume = true;
1023
Vijayavardhan Vennapusa39025fe2011-10-15 05:55:10 +05301024 ret = msm_hsic_resume(mehci);
1025 if (ret)
1026 return ret;
1027
1028 /* Bring the device to full powered state upon system resume */
1029 pm_runtime_disable(dev);
1030 pm_runtime_set_active(dev);
1031 pm_runtime_enable(dev);
1032
1033 return 0;
1034}
1035#endif
1036
1037#ifdef CONFIG_PM_RUNTIME
1038static int msm_hsic_runtime_idle(struct device *dev)
1039{
Hemant Kumar68315252012-04-30 17:44:03 -07001040 struct usb_hcd *hcd = dev_get_drvdata(dev);
1041 struct msm_hsic_hcd *mehci = hcd_to_hsic(hcd);
1042
Vijayavardhan Vennapusa39025fe2011-10-15 05:55:10 +05301043 dev_dbg(dev, "EHCI runtime idle\n");
1044
Hemant Kumar68315252012-04-30 17:44:03 -07001045 if (mehci->pm_resume) {
1046 mehci->pm_resume = false;
1047 pm_schedule_suspend(dev, RUNTIME_SUSP_DELAY);
1048 return -EAGAIN;
1049 }
1050
Vijayavardhan Vennapusa39025fe2011-10-15 05:55:10 +05301051 return 0;
1052}
1053
1054static int msm_hsic_runtime_suspend(struct device *dev)
1055{
1056 struct usb_hcd *hcd = dev_get_drvdata(dev);
1057 struct msm_hsic_hcd *mehci = hcd_to_hsic(hcd);
1058
1059 dev_dbg(dev, "EHCI runtime suspend\n");
1060 return msm_hsic_suspend(mehci);
1061}
1062
1063static int msm_hsic_runtime_resume(struct device *dev)
1064{
1065 struct usb_hcd *hcd = dev_get_drvdata(dev);
1066 struct msm_hsic_hcd *mehci = hcd_to_hsic(hcd);
1067
1068 dev_dbg(dev, "EHCI runtime resume\n");
1069 return msm_hsic_resume(mehci);
1070}
1071#endif
1072
1073#ifdef CONFIG_PM
1074static const struct dev_pm_ops msm_hsic_dev_pm_ops = {
1075 SET_SYSTEM_SLEEP_PM_OPS(msm_hsic_pm_suspend, msm_hsic_pm_resume)
Jack Phamfe441ea2012-03-23 17:03:15 -07001076 .suspend_noirq = msm_hsic_pm_suspend_noirq,
Vijayavardhan Vennapusa39025fe2011-10-15 05:55:10 +05301077 SET_RUNTIME_PM_OPS(msm_hsic_runtime_suspend, msm_hsic_runtime_resume,
1078 msm_hsic_runtime_idle)
1079};
1080#endif
1081
1082static struct platform_driver ehci_msm_hsic_driver = {
1083 .probe = ehci_hsic_msm_probe,
1084 .remove = __devexit_p(ehci_hsic_msm_remove),
1085 .driver = {
1086 .name = "msm_hsic_host",
1087#ifdef CONFIG_PM
1088 .pm = &msm_hsic_dev_pm_ops,
1089#endif
1090 },
1091};