blob: 4948d03687695bd4a53f22ee7657cf4ae102efa6 [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
43#define MSM_USB_BASE (hcd->regs)
44
45struct msm_hsic_hcd {
46 struct ehci_hcd ehci;
47 struct device *dev;
48 struct clk *ahb_clk;
Manu Gautam5143b252012-01-05 19:25:23 -080049 struct clk *core_clk;
50 struct clk *alt_core_clk;
51 struct clk *phy_clk;
Vijayavardhan Vennapusa39025fe2011-10-15 05:55:10 +053052 struct clk *cal_clk;
53 struct regulator *hsic_vddcx;
54 bool async_int;
55 atomic_t in_lpm;
56 struct wake_lock wlock;
Vamsi Krishna34f01582011-12-14 19:54:42 -080057 int peripheral_status_irq;
Vamsi Krishna6921cbe2012-02-21 18:34:43 -080058 int wakeup_irq;
Hemant Kumar6fd65032012-05-23 13:02:24 -070059 int wakeup_gpio;
Jack Phamfe441ea2012-03-23 17:03:15 -070060 bool wakeup_irq_enabled;
Hemant Kumar6fd65032012-05-23 13:02:24 -070061 atomic_t pm_usage_cnt;
Hemant Kumare6275972012-02-29 20:06:21 -080062 uint32_t bus_perf_client;
Hemant Kumar6fd65032012-05-23 13:02:24 -070063 uint32_t wakeup_int_cnt;
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
Hemant Kumar6fd65032012-05-23 13:02:24 -0700192 if (mehci->wakeup_gpio) {
193 rc = gpio_request(mehci->wakeup_gpio, "HSIC_WAKEUP_GPIO");
194 if (rc < 0) {
195 dev_err(mehci->dev, "gpio request failed for HSIC WAKEUP\n");
196 goto free_data;
197 }
198 }
199
Vijayavardhan Vennapusae3316a12011-10-15 06:05:17 +0530200 return 0;
201
202free_gpio:
Hemant Kumar6fd65032012-05-23 13:02:24 -0700203 if (mehci->wakeup_gpio)
204 gpio_free(mehci->wakeup_gpio);
205free_data:
Vijayavardhan Vennapusae3316a12011-10-15 06:05:17 +0530206 gpio_free(pdata->data);
207free_strobe:
208 gpio_free(pdata->strobe);
209
210 return rc;
211}
212
Vijayavardhan Vennapusa39025fe2011-10-15 05:55:10 +0530213static int msm_hsic_phy_clk_reset(struct msm_hsic_hcd *mehci)
214{
215 int ret;
216
Manu Gautam28b1bac2012-01-30 16:43:06 +0530217 clk_prepare_enable(mehci->alt_core_clk);
Vijayavardhan Vennapusa39025fe2011-10-15 05:55:10 +0530218
Manu Gautam5143b252012-01-05 19:25:23 -0800219 ret = clk_reset(mehci->core_clk, CLK_RESET_ASSERT);
Vijayavardhan Vennapusa39025fe2011-10-15 05:55:10 +0530220 if (ret) {
Manu Gautam28b1bac2012-01-30 16:43:06 +0530221 clk_disable_unprepare(mehci->alt_core_clk);
Vijayavardhan Vennapusa39025fe2011-10-15 05:55:10 +0530222 dev_err(mehci->dev, "usb phy clk assert failed\n");
223 return ret;
224 }
225 usleep_range(10000, 12000);
Manu Gautam28b1bac2012-01-30 16:43:06 +0530226 clk_disable_unprepare(mehci->alt_core_clk);
Vijayavardhan Vennapusa39025fe2011-10-15 05:55:10 +0530227
Manu Gautam5143b252012-01-05 19:25:23 -0800228 ret = clk_reset(mehci->core_clk, CLK_RESET_DEASSERT);
Vijayavardhan Vennapusa39025fe2011-10-15 05:55:10 +0530229 if (ret)
230 dev_err(mehci->dev, "usb phy clk deassert failed\n");
231
232 return ret;
233}
234
235static int msm_hsic_phy_reset(struct msm_hsic_hcd *mehci)
236{
237 struct usb_hcd *hcd = hsic_to_hcd(mehci);
238 u32 val;
239 int ret;
240
241 ret = msm_hsic_phy_clk_reset(mehci);
242 if (ret)
243 return ret;
244
245 val = readl_relaxed(USB_PORTSC) & ~PORTSC_PTS_MASK;
246 writel_relaxed(val | PORTSC_PTS_ULPI, USB_PORTSC);
247
248 /* Ensure that RESET operation is completed before turning off clock */
249 mb();
250 dev_dbg(mehci->dev, "phy_reset: success\n");
251
252 return 0;
253}
254
Vijayavardhan Vennapusae3316a12011-10-15 06:05:17 +0530255#define HSIC_GPIO150_PAD_CTL (MSM_TLMM_BASE+0x20C0)
256#define HSIC_GPIO151_PAD_CTL (MSM_TLMM_BASE+0x20C4)
257#define HSIC_CAL_PAD_CTL (MSM_TLMM_BASE+0x20C8)
258#define HSIC_LV_MODE 0x04
259#define HSIC_PAD_CALIBRATION 0xA8
260#define HSIC_GPIO_PAD_VAL 0x0A0AAA10
Vijayavardhan Vennapusa39025fe2011-10-15 05:55:10 +0530261#define LINK_RESET_TIMEOUT_USEC (250 * 1000)
262static int msm_hsic_reset(struct msm_hsic_hcd *mehci)
263{
264 struct usb_hcd *hcd = hsic_to_hcd(mehci);
265 int cnt = 0;
266 int ret;
Lena Salman8c8ba382012-02-14 15:59:31 +0200267 struct msm_hsic_host_platform_data *pdata = mehci->dev->platform_data;
Vijayavardhan Vennapusa39025fe2011-10-15 05:55:10 +0530268
269 ret = msm_hsic_phy_reset(mehci);
270 if (ret) {
271 dev_err(mehci->dev, "phy_reset failed\n");
272 return ret;
273 }
274
275 writel_relaxed(USBCMD_RESET, USB_USBCMD);
276 while (cnt < LINK_RESET_TIMEOUT_USEC) {
277 if (!(readl_relaxed(USB_USBCMD) & USBCMD_RESET))
278 break;
279 udelay(1);
280 cnt++;
281 }
282 if (cnt >= LINK_RESET_TIMEOUT_USEC)
283 return -ETIMEDOUT;
284
Lena Salman8c8ba382012-02-14 15:59:31 +0200285 /* Reset PORTSC and select ULPI phy */
Vijayavardhan Vennapusa39025fe2011-10-15 05:55:10 +0530286 writel_relaxed(0x80000000, USB_PORTSC);
287
288 /* TODO: Need to confirm if HSIC PHY also requires delay after RESET */
289 msleep(100);
290
291 /* HSIC PHY Initialization */
Vijayavardhan Vennapusae3316a12011-10-15 06:05:17 +0530292
Lena Salman8c8ba382012-02-14 15:59:31 +0200293 /* HSIC init sequence when HSIC signals (Strobe/Data) are
294 routed via GPIOs */
295 if (pdata && pdata->strobe && pdata->data) {
Vijayavardhan Vennapusae3316a12011-10-15 06:05:17 +0530296
Lena Salman8c8ba382012-02-14 15:59:31 +0200297 /* Enable LV_MODE in HSIC_CAL_PAD_CTL register */
298 writel_relaxed(HSIC_LV_MODE, HSIC_CAL_PAD_CTL);
Vijayavardhan Vennapusae3316a12011-10-15 06:05:17 +0530299
Lena Salman8c8ba382012-02-14 15:59:31 +0200300 /*set periodic calibration interval to ~2.048sec in
301 HSIC_IO_CAL_REG */
302 ulpi_write(mehci, 0xFF, 0x33);
303
304 /* Enable periodic IO calibration in HSIC_CFG register */
305 ulpi_write(mehci, HSIC_PAD_CALIBRATION, 0x30);
306
307 /* Configure GPIO 150/151 pins for HSIC functionality mode */
308 ret = msm_hsic_config_gpios(mehci, 1);
309 if (ret) {
310 dev_err(mehci->dev, " gpio configuarion failed\n");
311 return ret;
312 }
313 /* Set LV_MODE=0x1 and DCC=0x2 in HSIC_GPIO150/151_PAD_CTL
314 register */
315 writel_relaxed(HSIC_GPIO_PAD_VAL, HSIC_GPIO150_PAD_CTL);
316 writel_relaxed(HSIC_GPIO_PAD_VAL, HSIC_GPIO151_PAD_CTL);
317 /* Enable HSIC mode in HSIC_CFG register */
318 ulpi_write(mehci, 0x01, 0x31);
319 } else {
320 /* HSIC init sequence when HSIC signals (Strobe/Data) are routed
321 via dedicated I/O */
322
323 /* programmable length of connect signaling (33.2ns) */
324 ret = ulpi_write(mehci, 3, HSIC_DBG1_REG);
325 if (ret) {
326 pr_err("%s: Unable to program length of connect "
327 "signaling\n", __func__);
328 }
329
330 /*set periodic calibration interval to ~2.048sec in
331 HSIC_IO_CAL_REG */
332 ulpi_write(mehci, 0xFF, 0x33);
333
334 /* Enable HSIC mode in HSIC_CFG register */
335 ulpi_write(mehci, 0xA9, 0x30);
Vijayavardhan Vennapusae3316a12011-10-15 06:05:17 +0530336 }
337
Hemant Kumar6fd65032012-05-23 13:02:24 -0700338 /*disable auto resume*/
339 ulpi_write(mehci, ULPI_IFC_CTRL_AUTORESUME, ULPI_CLR(ULPI_IFC_CTRL));
340
Vijayavardhan Vennapusa39025fe2011-10-15 05:55:10 +0530341 return 0;
342}
343
344#define PHY_SUSPEND_TIMEOUT_USEC (500 * 1000)
345#define PHY_RESUME_TIMEOUT_USEC (100 * 1000)
346
347#ifdef CONFIG_PM_SLEEP
348static int msm_hsic_suspend(struct msm_hsic_hcd *mehci)
349{
350 struct usb_hcd *hcd = hsic_to_hcd(mehci);
Vijayavardhan Vennapusa2b592824f2011-11-02 19:51:32 +0530351 int cnt = 0, ret;
Vijayavardhan Vennapusa39025fe2011-10-15 05:55:10 +0530352 u32 val;
353
354 if (atomic_read(&mehci->in_lpm)) {
355 dev_dbg(mehci->dev, "%s called in lpm\n", __func__);
356 return 0;
357 }
358
359 disable_irq(hcd->irq);
Jack Phambe05fbb2012-05-16 10:56:26 -0700360
361 /* make sure we don't race against a remote wakeup */
362 if (test_bit(HCD_FLAG_WAKEUP_PENDING, &hcd->flags) ||
363 readl_relaxed(USB_PORTSC) & PORT_RESUME) {
364 dev_dbg(mehci->dev, "wakeup pending, aborting suspend\n");
365 enable_irq(hcd->irq);
366 return -EBUSY;
367 }
368
Vijayavardhan Vennapusa39025fe2011-10-15 05:55:10 +0530369 /*
370 * PHY may take some time or even fail to enter into low power
371 * mode (LPM). Hence poll for 500 msec and reset the PHY and link
372 * in failure case.
373 */
Hemant Kumar3dbc5b32012-05-09 15:36:11 -0700374 val = readl_relaxed(USB_PORTSC);
375 val &= ~PORT_RWC_BITS;
376 val |= PORTSC_PHCD;
Vijayavardhan Vennapusa39025fe2011-10-15 05:55:10 +0530377 writel_relaxed(val, USB_PORTSC);
378 while (cnt < PHY_SUSPEND_TIMEOUT_USEC) {
379 if (readl_relaxed(USB_PORTSC) & PORTSC_PHCD)
380 break;
381 udelay(1);
382 cnt++;
383 }
384
385 if (cnt >= PHY_SUSPEND_TIMEOUT_USEC) {
386 dev_err(mehci->dev, "Unable to suspend PHY\n");
Vijayavardhan Vennapusae3316a12011-10-15 06:05:17 +0530387 msm_hsic_config_gpios(mehci, 0);
Vijayavardhan Vennapusa39025fe2011-10-15 05:55:10 +0530388 msm_hsic_reset(mehci);
Vijayavardhan Vennapusa39025fe2011-10-15 05:55:10 +0530389 }
390
391 /*
392 * PHY has capability to generate interrupt asynchronously in low
393 * power mode (LPM). This interrupt is level triggered. So USB IRQ
394 * line must be disabled till async interrupt enable bit is cleared
395 * in USBCMD register. Assert STP (ULPI interface STOP signal) to
396 * block data communication from PHY.
397 */
398 writel_relaxed(readl_relaxed(USB_USBCMD) | ASYNC_INTR_CTRL |
399 ULPI_STP_CTRL, USB_USBCMD);
400
401 /*
402 * Ensure that hardware is put in low power mode before
403 * clocks are turned OFF and VDD is allowed to minimize.
404 */
405 mb();
406
Manu Gautam28b1bac2012-01-30 16:43:06 +0530407 clk_disable_unprepare(mehci->core_clk);
408 clk_disable_unprepare(mehci->phy_clk);
409 clk_disable_unprepare(mehci->cal_clk);
410 clk_disable_unprepare(mehci->ahb_clk);
Vijayavardhan Vennapusa39025fe2011-10-15 05:55:10 +0530411
Vamsi Krishna45d88fa2011-11-02 13:28:42 -0700412 ret = regulator_set_voltage(mehci->hsic_vddcx,
413 USB_PHY_VDD_DIG_VOL_SUSP_MIN,
414 USB_PHY_VDD_DIG_VOL_MAX);
415 if (ret < 0)
416 dev_err(mehci->dev, "unable to set vddcx voltage: min:0.5v max:1.3v\n");
417
Hemant Kumare6275972012-02-29 20:06:21 -0800418 if (mehci->bus_perf_client && debug_bus_voting_enabled) {
419 ret = msm_bus_scale_client_update_request(
420 mehci->bus_perf_client, 0);
421 if (ret)
422 dev_err(mehci->dev, "%s: Failed to dvote for "
423 "bus bandwidth %d\n", __func__, ret);
424 }
425
Vijayavardhan Vennapusa39025fe2011-10-15 05:55:10 +0530426 atomic_set(&mehci->in_lpm, 1);
427 enable_irq(hcd->irq);
Hemant Kumar6fd65032012-05-23 13:02:24 -0700428
429 mehci->wakeup_irq_enabled = 1;
430 enable_irq_wake(mehci->wakeup_irq);
431 enable_irq(mehci->wakeup_irq);
432
Vijayavardhan Vennapusa39025fe2011-10-15 05:55:10 +0530433 wake_unlock(&mehci->wlock);
434
435 dev_info(mehci->dev, "HSIC-USB in low power mode\n");
436
437 return 0;
438}
439
440static int msm_hsic_resume(struct msm_hsic_hcd *mehci)
441{
442 struct usb_hcd *hcd = hsic_to_hcd(mehci);
Vijayavardhan Vennapusa2b592824f2011-11-02 19:51:32 +0530443 int cnt = 0, ret;
Vijayavardhan Vennapusa39025fe2011-10-15 05:55:10 +0530444 unsigned temp;
445
446 if (!atomic_read(&mehci->in_lpm)) {
447 dev_dbg(mehci->dev, "%s called in !in_lpm\n", __func__);
448 return 0;
449 }
450
Hemant Kumar6fd65032012-05-23 13:02:24 -0700451 if (mehci->wakeup_irq_enabled) {
452 disable_irq_wake(mehci->wakeup_irq);
453 disable_irq_nosync(mehci->wakeup_irq);
454 mehci->wakeup_irq_enabled = 0;
455 }
456
Vijayavardhan Vennapusa39025fe2011-10-15 05:55:10 +0530457 wake_lock(&mehci->wlock);
458
Hemant Kumare6275972012-02-29 20:06:21 -0800459 if (mehci->bus_perf_client && debug_bus_voting_enabled) {
460 ret = msm_bus_scale_client_update_request(
461 mehci->bus_perf_client, 1);
462 if (ret)
463 dev_err(mehci->dev, "%s: Failed to vote for "
464 "bus bandwidth %d\n", __func__, ret);
465 }
466
Vamsi Krishna45d88fa2011-11-02 13:28:42 -0700467 ret = regulator_set_voltage(mehci->hsic_vddcx,
468 USB_PHY_VDD_DIG_VOL_MIN,
469 USB_PHY_VDD_DIG_VOL_MAX);
470 if (ret < 0)
471 dev_err(mehci->dev, "unable to set vddcx voltage: min:1v max:1.3v\n");
472
Manu Gautam28b1bac2012-01-30 16:43:06 +0530473 clk_prepare_enable(mehci->core_clk);
474 clk_prepare_enable(mehci->phy_clk);
475 clk_prepare_enable(mehci->cal_clk);
476 clk_prepare_enable(mehci->ahb_clk);
Vijayavardhan Vennapusa39025fe2011-10-15 05:55:10 +0530477
478 temp = readl_relaxed(USB_USBCMD);
479 temp &= ~ASYNC_INTR_CTRL;
480 temp &= ~ULPI_STP_CTRL;
481 writel_relaxed(temp, USB_USBCMD);
482
483 if (!(readl_relaxed(USB_PORTSC) & PORTSC_PHCD))
484 goto skip_phy_resume;
485
Hemant Kumar3dbc5b32012-05-09 15:36:11 -0700486 temp = readl_relaxed(USB_PORTSC);
487 temp &= ~(PORT_RWC_BITS | PORTSC_PHCD);
Vijayavardhan Vennapusa39025fe2011-10-15 05:55:10 +0530488 writel_relaxed(temp, USB_PORTSC);
489 while (cnt < PHY_RESUME_TIMEOUT_USEC) {
490 if (!(readl_relaxed(USB_PORTSC) & PORTSC_PHCD) &&
491 (readl_relaxed(USB_ULPI_VIEWPORT) & ULPI_SYNC_STATE))
492 break;
493 udelay(1);
494 cnt++;
495 }
496
497 if (cnt >= PHY_RESUME_TIMEOUT_USEC) {
498 /*
499 * This is a fatal error. Reset the link and
500 * PHY to make hsic working.
501 */
502 dev_err(mehci->dev, "Unable to resume USB. Reset the hsic\n");
Vijayavardhan Vennapusae3316a12011-10-15 06:05:17 +0530503 msm_hsic_config_gpios(mehci, 0);
Vijayavardhan Vennapusa39025fe2011-10-15 05:55:10 +0530504 msm_hsic_reset(mehci);
505 }
506
507skip_phy_resume:
508
Hemant Kumar6fd65032012-05-23 13:02:24 -0700509 usb_hcd_resume_root_hub(hcd);
510
Vijayavardhan Vennapusa39025fe2011-10-15 05:55:10 +0530511 atomic_set(&mehci->in_lpm, 0);
512
513 if (mehci->async_int) {
514 mehci->async_int = false;
515 pm_runtime_put_noidle(mehci->dev);
516 enable_irq(hcd->irq);
517 }
518
Hemant Kumar6fd65032012-05-23 13:02:24 -0700519 if (atomic_read(&mehci->pm_usage_cnt)) {
520 atomic_set(&mehci->pm_usage_cnt, 0);
521 pm_runtime_put_noidle(mehci->dev);
522 }
523
Vijayavardhan Vennapusa39025fe2011-10-15 05:55:10 +0530524 dev_info(mehci->dev, "HSIC-USB exited from low power mode\n");
525
526 return 0;
527}
528#endif
529
530static irqreturn_t msm_hsic_irq(struct usb_hcd *hcd)
531{
532 struct msm_hsic_hcd *mehci = hcd_to_hsic(hcd);
533
534 if (atomic_read(&mehci->in_lpm)) {
535 disable_irq_nosync(hcd->irq);
Hemant Kumar3dbc5b32012-05-09 15:36:11 -0700536 dev_dbg(mehci->dev, "phy async intr\n");
Vijayavardhan Vennapusa39025fe2011-10-15 05:55:10 +0530537 mehci->async_int = true;
538 pm_runtime_get(mehci->dev);
539 return IRQ_HANDLED;
540 }
541
542 return ehci_irq(hcd);
543}
544
545static int ehci_hsic_reset(struct usb_hcd *hcd)
546{
547 struct ehci_hcd *ehci = hcd_to_ehci(hcd);
548 int retval;
549
550 ehci->caps = USB_CAPLENGTH;
551 ehci->regs = USB_CAPLENGTH +
552 HC_LENGTH(ehci, ehci_readl(ehci, &ehci->caps->hc_capbase));
553 dbg_hcs_params(ehci, "reset");
554 dbg_hcc_params(ehci, "reset");
555
556 /* cache the data to minimize the chip reads*/
557 ehci->hcs_params = ehci_readl(ehci, &ehci->caps->hcs_params);
558
559 hcd->has_tt = 1;
560 ehci->sbrn = HCD_USB2;
561
562 retval = ehci_halt(ehci);
563 if (retval)
564 return retval;
565
566 /* data structure init */
567 retval = ehci_init(hcd);
568 if (retval)
569 return retval;
570
571 retval = ehci_reset(ehci);
572 if (retval)
573 return retval;
574
575 /* bursts of unspecified length. */
576 writel_relaxed(0, USB_AHBBURST);
577 /* Use the AHB transactor */
Vijayavardhan Vennapusa5f32d7a2012-03-14 16:30:26 +0530578 writel_relaxed(0x08, USB_AHBMODE);
Vijayavardhan Vennapusa39025fe2011-10-15 05:55:10 +0530579 /* Disable streaming mode and select host mode */
580 writel_relaxed(0x13, USB_USBMODE);
581
582 ehci_port_power(ehci, 1);
583 return 0;
584}
585
586static struct hc_driver msm_hsic_driver = {
587 .description = hcd_name,
588 .product_desc = "Qualcomm EHCI Host Controller using HSIC",
589 .hcd_priv_size = sizeof(struct msm_hsic_hcd),
590
591 /*
592 * generic hardware linkage
593 */
594 .irq = msm_hsic_irq,
595 .flags = HCD_USB2 | HCD_MEMORY,
596
597 .reset = ehci_hsic_reset,
598 .start = ehci_run,
599
600 .stop = ehci_stop,
601 .shutdown = ehci_shutdown,
602
603 /*
604 * managing i/o requests and associated device resources
605 */
606 .urb_enqueue = ehci_urb_enqueue,
607 .urb_dequeue = ehci_urb_dequeue,
608 .endpoint_disable = ehci_endpoint_disable,
609 .endpoint_reset = ehci_endpoint_reset,
610 .clear_tt_buffer_complete = ehci_clear_tt_buffer_complete,
611
612 /*
613 * scheduling support
614 */
615 .get_frame_number = ehci_get_frame,
616
617 /*
618 * root hub support
619 */
620 .hub_status_data = ehci_hub_status_data,
621 .hub_control = ehci_hub_control,
622 .relinquish_port = ehci_relinquish_port,
623 .port_handed_over = ehci_port_handed_over,
624
625 /*
626 * PM support
627 */
628 .bus_suspend = ehci_bus_suspend,
629 .bus_resume = ehci_bus_resume,
630};
631
632static int msm_hsic_init_clocks(struct msm_hsic_hcd *mehci, u32 init)
633{
634 int ret = 0;
635
636 if (!init)
637 goto put_clocks;
638
Lena Salman8c8ba382012-02-14 15:59:31 +0200639 /*core_clk is required for LINK protocol engine
640 *clock rate appropriately set by target specific clock driver */
Manu Gautam5143b252012-01-05 19:25:23 -0800641 mehci->core_clk = clk_get(mehci->dev, "core_clk");
642 if (IS_ERR(mehci->core_clk)) {
643 dev_err(mehci->dev, "failed to get core_clk\n");
644 ret = PTR_ERR(mehci->core_clk);
Vijayavardhan Vennapusa39025fe2011-10-15 05:55:10 +0530645 return ret;
646 }
Vijayavardhan Vennapusa39025fe2011-10-15 05:55:10 +0530647
Lena Salman8c8ba382012-02-14 15:59:31 +0200648 /* alt_core_clk is for LINK to be used during PHY RESET
649 * clock rate appropriately set by target specific clock driver */
Manu Gautam5143b252012-01-05 19:25:23 -0800650 mehci->alt_core_clk = clk_get(mehci->dev, "alt_core_clk");
651 if (IS_ERR(mehci->alt_core_clk)) {
652 dev_err(mehci->dev, "failed to core_clk\n");
653 ret = PTR_ERR(mehci->alt_core_clk);
654 goto put_core_clk;
Vijayavardhan Vennapusa39025fe2011-10-15 05:55:10 +0530655 }
Vijayavardhan Vennapusa39025fe2011-10-15 05:55:10 +0530656
Lena Salman8c8ba382012-02-14 15:59:31 +0200657 /* phy_clk is required for HSIC PHY operation
658 * clock rate appropriately set by target specific clock driver */
Manu Gautam5143b252012-01-05 19:25:23 -0800659 mehci->phy_clk = clk_get(mehci->dev, "phy_clk");
660 if (IS_ERR(mehci->phy_clk)) {
661 dev_err(mehci->dev, "failed to get phy_clk\n");
662 ret = PTR_ERR(mehci->phy_clk);
663 goto put_alt_core_clk;
Vijayavardhan Vennapusa39025fe2011-10-15 05:55:10 +0530664 }
Vijayavardhan Vennapusa39025fe2011-10-15 05:55:10 +0530665
666 /* 10MHz cal_clk is required for calibration of I/O pads */
Manu Gautam5143b252012-01-05 19:25:23 -0800667 mehci->cal_clk = clk_get(mehci->dev, "cal_clk");
Vijayavardhan Vennapusa39025fe2011-10-15 05:55:10 +0530668 if (IS_ERR(mehci->cal_clk)) {
Manu Gautam5143b252012-01-05 19:25:23 -0800669 dev_err(mehci->dev, "failed to get cal_clk\n");
Vijayavardhan Vennapusa39025fe2011-10-15 05:55:10 +0530670 ret = PTR_ERR(mehci->cal_clk);
Manu Gautam5143b252012-01-05 19:25:23 -0800671 goto put_phy_clk;
Vijayavardhan Vennapusa39025fe2011-10-15 05:55:10 +0530672 }
673 clk_set_rate(mehci->cal_clk, 10000000);
674
675 /* ahb_clk is required for data transfers */
Manu Gautam5143b252012-01-05 19:25:23 -0800676 mehci->ahb_clk = clk_get(mehci->dev, "iface_clk");
Vijayavardhan Vennapusa39025fe2011-10-15 05:55:10 +0530677 if (IS_ERR(mehci->ahb_clk)) {
Manu Gautam5143b252012-01-05 19:25:23 -0800678 dev_err(mehci->dev, "failed to get iface_clk\n");
Vijayavardhan Vennapusa39025fe2011-10-15 05:55:10 +0530679 ret = PTR_ERR(mehci->ahb_clk);
680 goto put_cal_clk;
681 }
682
Manu Gautam28b1bac2012-01-30 16:43:06 +0530683 clk_prepare_enable(mehci->core_clk);
684 clk_prepare_enable(mehci->phy_clk);
685 clk_prepare_enable(mehci->cal_clk);
686 clk_prepare_enable(mehci->ahb_clk);
Vijayavardhan Vennapusa39025fe2011-10-15 05:55:10 +0530687
688 return 0;
689
690put_clocks:
Jack Phamfd193eb2012-02-22 15:38:08 -0800691 if (!atomic_read(&mehci->in_lpm)) {
692 clk_disable_unprepare(mehci->core_clk);
693 clk_disable_unprepare(mehci->phy_clk);
694 clk_disable_unprepare(mehci->cal_clk);
695 clk_disable_unprepare(mehci->ahb_clk);
696 }
Vijayavardhan Vennapusa39025fe2011-10-15 05:55:10 +0530697 clk_put(mehci->ahb_clk);
698put_cal_clk:
699 clk_put(mehci->cal_clk);
Manu Gautam5143b252012-01-05 19:25:23 -0800700put_phy_clk:
701 clk_put(mehci->phy_clk);
702put_alt_core_clk:
703 clk_put(mehci->alt_core_clk);
704put_core_clk:
705 clk_put(mehci->core_clk);
Vijayavardhan Vennapusa39025fe2011-10-15 05:55:10 +0530706
707 return ret;
708}
Vamsi Krishna34f01582011-12-14 19:54:42 -0800709static irqreturn_t hsic_peripheral_status_change(int irq, void *dev_id)
710{
711 struct msm_hsic_hcd *mehci = dev_id;
712
Vamsi Krishna6921cbe2012-02-21 18:34:43 -0800713 pr_debug("%s: mehci:%p dev_id:%p\n", __func__, mehci, dev_id);
Vamsi Krishna34f01582011-12-14 19:54:42 -0800714
715 if (mehci)
716 msm_hsic_config_gpios(mehci, 0);
717
718 return IRQ_HANDLED;
719}
720
Vamsi Krishna6921cbe2012-02-21 18:34:43 -0800721static irqreturn_t msm_hsic_wakeup_irq(int irq, void *data)
722{
723 struct msm_hsic_hcd *mehci = data;
724
Hemant Kumar6fd65032012-05-23 13:02:24 -0700725 mehci->wakeup_int_cnt++;
726 dev_dbg(mehci->dev, "%s: hsic remote wakeup interrupt cnt: %u\n",
727 __func__, mehci->wakeup_int_cnt);
728
729 wake_lock(&mehci->wlock);
Vamsi Krishna6921cbe2012-02-21 18:34:43 -0800730
Jack Phamfe441ea2012-03-23 17:03:15 -0700731 if (mehci->wakeup_irq_enabled) {
732 mehci->wakeup_irq_enabled = 0;
733 disable_irq_wake(irq);
734 disable_irq_nosync(irq);
735 }
736
Hemant Kumar6fd65032012-05-23 13:02:24 -0700737 if (!atomic_read(&mehci->pm_usage_cnt)) {
738 atomic_set(&mehci->pm_usage_cnt, 1);
739 pm_runtime_get(mehci->dev);
740 }
741
Vamsi Krishna6921cbe2012-02-21 18:34:43 -0800742 return IRQ_HANDLED;
743}
744
Hemant Kumare6275972012-02-29 20:06:21 -0800745static int ehci_hsic_msm_bus_show(struct seq_file *s, void *unused)
746{
747 if (debug_bus_voting_enabled)
748 seq_printf(s, "enabled\n");
749 else
750 seq_printf(s, "disabled\n");
751
752 return 0;
753}
754
755static int ehci_hsic_msm_bus_open(struct inode *inode, struct file *file)
756{
757 return single_open(file, ehci_hsic_msm_bus_show, inode->i_private);
758}
759
760static ssize_t ehci_hsic_msm_bus_write(struct file *file,
761 const char __user *ubuf, size_t count, loff_t *ppos)
762{
763 char buf[8];
764 int ret;
765 struct seq_file *s = file->private_data;
766 struct msm_hsic_hcd *mehci = s->private;
767
768 memset(buf, 0x00, sizeof(buf));
769
770 if (copy_from_user(&buf, ubuf, min_t(size_t, sizeof(buf) - 1, count)))
771 return -EFAULT;
772
773 if (!strncmp(buf, "enable", 6)) {
774 /* Do not vote here. Let hsic driver decide when to vote */
775 debug_bus_voting_enabled = true;
776 } else {
777 debug_bus_voting_enabled = false;
778 if (mehci->bus_perf_client) {
779 ret = msm_bus_scale_client_update_request(
780 mehci->bus_perf_client, 0);
781 if (ret)
782 dev_err(mehci->dev, "%s: Failed to devote "
783 "for bus bw %d\n", __func__, ret);
784 }
785 }
786
787 return count;
788}
789
790const struct file_operations ehci_hsic_msm_bus_fops = {
791 .open = ehci_hsic_msm_bus_open,
792 .read = seq_read,
793 .write = ehci_hsic_msm_bus_write,
794 .llseek = seq_lseek,
795 .release = single_release,
796};
797
Hemant Kumar6fd65032012-05-23 13:02:24 -0700798static int ehci_hsic_msm_wakeup_cnt_show(struct seq_file *s, void *unused)
799{
800 struct msm_hsic_hcd *mehci = s->private;
801
802 seq_printf(s, "%u\n", mehci->wakeup_int_cnt);
803
804 return 0;
805}
806
807static int ehci_hsic_msm_wakeup_cnt_open(struct inode *inode, struct file *f)
808{
809 return single_open(f, ehci_hsic_msm_wakeup_cnt_show, inode->i_private);
810}
811
812const struct file_operations ehci_hsic_msm_wakeup_cnt_fops = {
813 .open = ehci_hsic_msm_wakeup_cnt_open,
814 .read = seq_read,
815 .llseek = seq_lseek,
816 .release = single_release,
817};
818
Hemant Kumare6275972012-02-29 20:06:21 -0800819static struct dentry *ehci_hsic_msm_dbg_root;
820static int ehci_hsic_msm_debugfs_init(struct msm_hsic_hcd *mehci)
821{
822 struct dentry *ehci_hsic_msm_dentry;
823
824 ehci_hsic_msm_dbg_root = debugfs_create_dir("ehci_hsic_msm_dbg", NULL);
825
826 if (!ehci_hsic_msm_dbg_root || IS_ERR(ehci_hsic_msm_dbg_root))
827 return -ENODEV;
828
829 ehci_hsic_msm_dentry = debugfs_create_file("bus_voting",
830 S_IRUGO | S_IWUSR,
831 ehci_hsic_msm_dbg_root, mehci,
832 &ehci_hsic_msm_bus_fops);
833
834 if (!ehci_hsic_msm_dentry) {
835 debugfs_remove_recursive(ehci_hsic_msm_dbg_root);
836 return -ENODEV;
837 }
838
Hemant Kumar6fd65032012-05-23 13:02:24 -0700839 ehci_hsic_msm_dentry = debugfs_create_file("wakeup_cnt",
840 S_IRUGO,
841 ehci_hsic_msm_dbg_root, mehci,
842 &ehci_hsic_msm_wakeup_cnt_fops);
843
844 if (!ehci_hsic_msm_dentry) {
845 debugfs_remove_recursive(ehci_hsic_msm_dbg_root);
846 return -ENODEV;
847 }
848
Hemant Kumare6275972012-02-29 20:06:21 -0800849 return 0;
850}
851
852static void ehci_hsic_msm_debugfs_cleanup(void)
853{
854 debugfs_remove_recursive(ehci_hsic_msm_dbg_root);
855}
856
Vijayavardhan Vennapusa39025fe2011-10-15 05:55:10 +0530857static int __devinit ehci_hsic_msm_probe(struct platform_device *pdev)
858{
859 struct usb_hcd *hcd;
860 struct resource *res;
861 struct msm_hsic_hcd *mehci;
Vijayavardhan Vennapusa2b592824f2011-11-02 19:51:32 +0530862 struct msm_hsic_host_platform_data *pdata;
Vijayavardhan Vennapusa39025fe2011-10-15 05:55:10 +0530863 int ret;
864
865 dev_dbg(&pdev->dev, "ehci_msm-hsic probe\n");
866
Vijayavardhan Vennapusaafbbb8f2012-04-13 16:28:45 +0530867 /* After parent device's probe is executed, it will be put in suspend
868 * mode. When child device's probe is called, driver core is not
869 * resuming parent device due to which parent will be in suspend even
870 * though child is active. Hence resume the parent device explicitly.
871 */
872 if (pdev->dev.parent)
873 pm_runtime_get_sync(pdev->dev.parent);
874
Vijayavardhan Vennapusa39025fe2011-10-15 05:55:10 +0530875 hcd = usb_create_hcd(&msm_hsic_driver, &pdev->dev,
876 dev_name(&pdev->dev));
877 if (!hcd) {
878 dev_err(&pdev->dev, "Unable to create HCD\n");
879 return -ENOMEM;
880 }
881
882 hcd->irq = platform_get_irq(pdev, 0);
883 if (hcd->irq < 0) {
884 dev_err(&pdev->dev, "Unable to get IRQ resource\n");
885 ret = hcd->irq;
886 goto put_hcd;
887 }
888
889 res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
890 if (!res) {
891 dev_err(&pdev->dev, "Unable to get memory resource\n");
892 ret = -ENODEV;
893 goto put_hcd;
894 }
895
896 hcd->rsrc_start = res->start;
897 hcd->rsrc_len = resource_size(res);
898 hcd->regs = ioremap(hcd->rsrc_start, hcd->rsrc_len);
899 if (!hcd->regs) {
900 dev_err(&pdev->dev, "ioremap failed\n");
901 ret = -ENOMEM;
902 goto put_hcd;
903 }
904
905 mehci = hcd_to_hsic(hcd);
906 mehci->dev = &pdev->dev;
907
Hemant Kumar38ce5d82012-05-29 13:00:58 -0700908 mehci->ehci.susp_sof_bug = 1;
909
Vamsi Krishna34f01582011-12-14 19:54:42 -0800910 res = platform_get_resource_byname(pdev,
911 IORESOURCE_IRQ,
912 "peripheral_status_irq");
913 if (res)
914 mehci->peripheral_status_irq = res->start;
915
Hemant Kumar6fd65032012-05-23 13:02:24 -0700916 res = platform_get_resource_byname(pdev, IORESOURCE_IO, "wakeup");
917 if (res) {
918 mehci->wakeup_gpio = res->start;
919 mehci->wakeup_irq = MSM_GPIO_TO_INT(res->start);
920 dev_dbg(mehci->dev, "wakeup_irq: %d\n", mehci->wakeup_irq);
921 }
922
Vijayavardhan Vennapusa39025fe2011-10-15 05:55:10 +0530923 ret = msm_hsic_init_clocks(mehci, 1);
924 if (ret) {
925 dev_err(&pdev->dev, "unable to initialize clocks\n");
926 ret = -ENODEV;
927 goto unmap;
928 }
929
930 ret = msm_hsic_init_vddcx(mehci, 1);
931 if (ret) {
932 dev_err(&pdev->dev, "unable to initialize VDDCX\n");
933 ret = -ENODEV;
934 goto deinit_clocks;
935 }
936
937 ret = msm_hsic_reset(mehci);
938 if (ret) {
939 dev_err(&pdev->dev, "unable to initialize PHY\n");
Vijayavardhan Vennapusaafbbb8f2012-04-13 16:28:45 +0530940 goto deinit_vddcx;
Vijayavardhan Vennapusa39025fe2011-10-15 05:55:10 +0530941 }
942
943 ret = usb_add_hcd(hcd, hcd->irq, IRQF_SHARED);
944 if (ret) {
945 dev_err(&pdev->dev, "unable to register HCD\n");
Vijayavardhan Vennapusae3316a12011-10-15 06:05:17 +0530946 goto unconfig_gpio;
Vijayavardhan Vennapusa39025fe2011-10-15 05:55:10 +0530947 }
948
949 device_init_wakeup(&pdev->dev, 1);
950 wake_lock_init(&mehci->wlock, WAKE_LOCK_SUSPEND, dev_name(&pdev->dev));
951 wake_lock(&mehci->wlock);
Vamsi Krishna34f01582011-12-14 19:54:42 -0800952
953 if (mehci->peripheral_status_irq) {
954 ret = request_threaded_irq(mehci->peripheral_status_irq,
955 NULL, hsic_peripheral_status_change,
956 IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING
957 | IRQF_SHARED,
958 "hsic_peripheral_status", mehci);
959 if (ret)
960 dev_err(&pdev->dev, "%s:request_irq:%d failed:%d",
961 __func__, mehci->peripheral_status_irq, ret);
962 }
963
Vamsi Krishna6921cbe2012-02-21 18:34:43 -0800964 /* configure wakeup irq */
Hemant Kumar6fd65032012-05-23 13:02:24 -0700965 if (mehci->wakeup_irq) {
Vamsi Krishna6921cbe2012-02-21 18:34:43 -0800966 ret = request_irq(mehci->wakeup_irq, msm_hsic_wakeup_irq,
Hemant Kumar6fd65032012-05-23 13:02:24 -0700967 IRQF_TRIGGER_HIGH,
Vamsi Krishna6921cbe2012-02-21 18:34:43 -0800968 "msm_hsic_wakeup", mehci);
969 if (!ret) {
970 disable_irq_nosync(mehci->wakeup_irq);
Vamsi Krishna6921cbe2012-02-21 18:34:43 -0800971 } else {
972 dev_err(&pdev->dev, "request_irq(%d) failed: %d\n",
973 mehci->wakeup_irq, ret);
974 mehci->wakeup_irq = 0;
975 }
976 }
977
Hemant Kumare6275972012-02-29 20:06:21 -0800978 ret = ehci_hsic_msm_debugfs_init(mehci);
979 if (ret)
980 dev_dbg(&pdev->dev, "mode debugfs file is"
981 "not available\n");
982
Vijayavardhan Vennapusaafbbb8f2012-04-13 16:28:45 +0530983 pdata = mehci->dev->platform_data;
Hemant Kumare6275972012-02-29 20:06:21 -0800984 if (pdata && pdata->bus_scale_table) {
985 mehci->bus_perf_client =
986 msm_bus_scale_register_client(pdata->bus_scale_table);
987 /* Configure BUS performance parameters for MAX bandwidth */
988 if (mehci->bus_perf_client) {
989 ret = msm_bus_scale_client_update_request(
990 mehci->bus_perf_client, 1);
991 if (ret)
992 dev_err(&pdev->dev, "%s: Failed to vote for "
993 "bus bandwidth %d\n", __func__, ret);
994 } else {
995 dev_err(&pdev->dev, "%s: Failed to register BUS "
996 "scaling client!!\n", __func__);
997 }
998 }
999
Vijayavardhan Vennapusa39025fe2011-10-15 05:55:10 +05301000 /*
1001 * This pdev->dev is assigned parent of root-hub by USB core,
1002 * hence, runtime framework automatically calls this driver's
1003 * runtime APIs based on root-hub's state.
1004 */
1005 pm_runtime_set_active(&pdev->dev);
1006 pm_runtime_enable(&pdev->dev);
Vijayavardhan Vennapusaafbbb8f2012-04-13 16:28:45 +05301007 /* Decrement the parent device's counter after probe.
1008 * As child is active, parent will not be put into
1009 * suspend mode.
1010 */
1011 if (pdev->dev.parent)
1012 pm_runtime_put_sync(pdev->dev.parent);
Vijayavardhan Vennapusa39025fe2011-10-15 05:55:10 +05301013
1014 return 0;
1015
Vijayavardhan Vennapusae3316a12011-10-15 06:05:17 +05301016unconfig_gpio:
1017 msm_hsic_config_gpios(mehci, 0);
Vijayavardhan Vennapusa39025fe2011-10-15 05:55:10 +05301018deinit_vddcx:
1019 msm_hsic_init_vddcx(mehci, 0);
1020deinit_clocks:
1021 msm_hsic_init_clocks(mehci, 0);
1022unmap:
1023 iounmap(hcd->regs);
1024put_hcd:
1025 usb_put_hcd(hcd);
1026
1027 return ret;
1028}
1029
1030static int __devexit ehci_hsic_msm_remove(struct platform_device *pdev)
1031{
1032 struct usb_hcd *hcd = platform_get_drvdata(pdev);
1033 struct msm_hsic_hcd *mehci = hcd_to_hsic(hcd);
1034
Vamsi Krishna34f01582011-12-14 19:54:42 -08001035 if (mehci->peripheral_status_irq)
1036 free_irq(mehci->peripheral_status_irq, mehci);
Jack Phamfe441ea2012-03-23 17:03:15 -07001037
Vamsi Krishna6921cbe2012-02-21 18:34:43 -08001038 if (mehci->wakeup_irq) {
Jack Phamfe441ea2012-03-23 17:03:15 -07001039 if (mehci->wakeup_irq_enabled)
1040 disable_irq_wake(mehci->wakeup_irq);
Vamsi Krishna6921cbe2012-02-21 18:34:43 -08001041 free_irq(mehci->wakeup_irq, mehci);
1042 }
Vamsi Krishna34f01582011-12-14 19:54:42 -08001043
Hemant Kumare6275972012-02-29 20:06:21 -08001044 if (mehci->bus_perf_client)
1045 msm_bus_scale_unregister_client(mehci->bus_perf_client);
1046
1047 ehci_hsic_msm_debugfs_cleanup();
Vijayavardhan Vennapusa39025fe2011-10-15 05:55:10 +05301048 device_init_wakeup(&pdev->dev, 0);
Vijayavardhan Vennapusa39025fe2011-10-15 05:55:10 +05301049 pm_runtime_set_suspended(&pdev->dev);
1050
1051 usb_remove_hcd(hcd);
Vijayavardhan Vennapusae3316a12011-10-15 06:05:17 +05301052 msm_hsic_config_gpios(mehci, 0);
Vijayavardhan Vennapusa39025fe2011-10-15 05:55:10 +05301053 msm_hsic_init_vddcx(mehci, 0);
1054
1055 msm_hsic_init_clocks(mehci, 0);
1056 wake_lock_destroy(&mehci->wlock);
1057 iounmap(hcd->regs);
1058 usb_put_hcd(hcd);
1059
1060 return 0;
1061}
1062
1063#ifdef CONFIG_PM_SLEEP
1064static int msm_hsic_pm_suspend(struct device *dev)
1065{
Jack Phambe05fbb2012-05-16 10:56:26 -07001066 int ret;
Vijayavardhan Vennapusa39025fe2011-10-15 05:55:10 +05301067 struct usb_hcd *hcd = dev_get_drvdata(dev);
1068 struct msm_hsic_hcd *mehci = hcd_to_hsic(hcd);
1069
1070 dev_dbg(dev, "ehci-msm-hsic PM suspend\n");
1071
1072 if (device_may_wakeup(dev))
1073 enable_irq_wake(hcd->irq);
1074
Jack Phambe05fbb2012-05-16 10:56:26 -07001075 ret = msm_hsic_suspend(mehci);
1076
1077 if (ret && device_may_wakeup(dev))
1078 disable_irq_wake(hcd->irq);
1079
1080 return ret;
Jack Phamfe441ea2012-03-23 17:03:15 -07001081}
Vijayavardhan Vennapusa39025fe2011-10-15 05:55:10 +05301082
Vijayavardhan Vennapusa39025fe2011-10-15 05:55:10 +05301083static int msm_hsic_pm_resume(struct device *dev)
1084{
1085 int ret;
1086 struct usb_hcd *hcd = dev_get_drvdata(dev);
1087 struct msm_hsic_hcd *mehci = hcd_to_hsic(hcd);
1088
Vijayavardhan Vennapusa39025fe2011-10-15 05:55:10 +05301089 if (device_may_wakeup(dev))
1090 disable_irq_wake(hcd->irq);
1091
1092 ret = msm_hsic_resume(mehci);
1093 if (ret)
1094 return ret;
1095
1096 /* Bring the device to full powered state upon system resume */
1097 pm_runtime_disable(dev);
1098 pm_runtime_set_active(dev);
1099 pm_runtime_enable(dev);
1100
1101 return 0;
1102}
1103#endif
1104
1105#ifdef CONFIG_PM_RUNTIME
1106static int msm_hsic_runtime_idle(struct device *dev)
1107{
1108 dev_dbg(dev, "EHCI runtime idle\n");
Vijayavardhan Vennapusa39025fe2011-10-15 05:55:10 +05301109 return 0;
1110}
1111
1112static int msm_hsic_runtime_suspend(struct device *dev)
1113{
1114 struct usb_hcd *hcd = dev_get_drvdata(dev);
1115 struct msm_hsic_hcd *mehci = hcd_to_hsic(hcd);
1116
1117 dev_dbg(dev, "EHCI runtime suspend\n");
1118 return msm_hsic_suspend(mehci);
1119}
1120
1121static int msm_hsic_runtime_resume(struct device *dev)
1122{
1123 struct usb_hcd *hcd = dev_get_drvdata(dev);
1124 struct msm_hsic_hcd *mehci = hcd_to_hsic(hcd);
1125
1126 dev_dbg(dev, "EHCI runtime resume\n");
1127 return msm_hsic_resume(mehci);
1128}
1129#endif
1130
1131#ifdef CONFIG_PM
1132static const struct dev_pm_ops msm_hsic_dev_pm_ops = {
1133 SET_SYSTEM_SLEEP_PM_OPS(msm_hsic_pm_suspend, msm_hsic_pm_resume)
Vijayavardhan Vennapusa39025fe2011-10-15 05:55:10 +05301134 SET_RUNTIME_PM_OPS(msm_hsic_runtime_suspend, msm_hsic_runtime_resume,
1135 msm_hsic_runtime_idle)
1136};
1137#endif
1138
1139static struct platform_driver ehci_msm_hsic_driver = {
1140 .probe = ehci_hsic_msm_probe,
1141 .remove = __devexit_p(ehci_hsic_msm_remove),
1142 .driver = {
1143 .name = "msm_hsic_host",
1144#ifdef CONFIG_PM
1145 .pm = &msm_hsic_dev_pm_ops,
1146#endif
1147 },
1148};