blob: a95198ca3c2977fdd662126d9ecdae661f542b0a [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>
33
34#include <linux/usb/msm_hsusb_hw.h>
Vijayavardhan Vennapusae3316a12011-10-15 06:05:17 +053035#include <linux/usb/msm_hsusb.h>
36#include <linux/gpio.h>
Amit Blayd6ea6102012-06-07 16:26:24 +030037#include <linux/spinlock.h>
38
39#include <mach/msm_bus.h>
Vijayavardhan Vennapusa39025fe2011-10-15 05:55:10 +053040#include <mach/clk.h>
41#include <mach/msm_iomap.h>
Vijayavardhan Vennapusa2b592824f2011-11-02 19:51:32 +053042#include <mach/msm_xo.h>
Vamsi Krishna34f01582011-12-14 19:54:42 -080043#include <linux/spinlock.h>
Hemant Kumar45d211b2012-05-31 17:58:43 -070044#include <linux/cpu.h>
Amit Blayd6ea6102012-06-07 16:26:24 +030045#include <mach/rpm-regulator.h>
Vijayavardhan Vennapusa39025fe2011-10-15 05:55:10 +053046
47#define MSM_USB_BASE (hcd->regs)
48
49struct msm_hsic_hcd {
50 struct ehci_hcd ehci;
51 struct device *dev;
52 struct clk *ahb_clk;
Manu Gautam5143b252012-01-05 19:25:23 -080053 struct clk *core_clk;
54 struct clk *alt_core_clk;
55 struct clk *phy_clk;
Vijayavardhan Vennapusa39025fe2011-10-15 05:55:10 +053056 struct clk *cal_clk;
57 struct regulator *hsic_vddcx;
58 bool async_int;
59 atomic_t in_lpm;
60 struct wake_lock wlock;
Vamsi Krishna34f01582011-12-14 19:54:42 -080061 int peripheral_status_irq;
Vamsi Krishna6921cbe2012-02-21 18:34:43 -080062 int wakeup_irq;
Hemant Kumar6fd65032012-05-23 13:02:24 -070063 int wakeup_gpio;
Jack Phamfe441ea2012-03-23 17:03:15 -070064 bool wakeup_irq_enabled;
Hemant Kumar6fd65032012-05-23 13:02:24 -070065 atomic_t pm_usage_cnt;
Hemant Kumare6275972012-02-29 20:06:21 -080066 uint32_t bus_perf_client;
Hemant Kumar6fd65032012-05-23 13:02:24 -070067 uint32_t wakeup_int_cnt;
Amit Blayd6ea6102012-06-07 16:26:24 +030068 enum usb_vdd_type vdd_type;
Vijayavardhan Vennapusa39025fe2011-10-15 05:55:10 +053069};
70
Hemant Kumare6275972012-02-29 20:06:21 -080071static bool debug_bus_voting_enabled = true;
Hemant Kumar45d211b2012-05-31 17:58:43 -070072
73static unsigned int enable_dbg_log = 1;
74module_param(enable_dbg_log, uint, S_IRUGO | S_IWUSR);
75/*by default log ep0 and efs sync ep*/
76static unsigned int ep_addr_rxdbg_mask = 9;
77module_param(ep_addr_rxdbg_mask, uint, S_IRUGO | S_IWUSR);
78static unsigned int ep_addr_txdbg_mask = 9;
79module_param(ep_addr_txdbg_mask, uint, S_IRUGO | S_IWUSR);
80
81/* Maximum debug message length */
82#define DBG_MSG_LEN 100UL
83
84/* Maximum number of messages */
85#define DBG_MAX_MSG 256UL
86
87#define TIME_BUF_LEN 20
88
89enum event_type {
90 EVENT_UNDEF = -1,
91 URB_SUBMIT,
92 URB_COMPLETE,
93 EVENT_NONE,
94};
95
96#define EVENT_STR_LEN 5
97
98static char *event_to_str(enum event_type e)
99{
100 switch (e) {
101 case URB_SUBMIT:
102 return "S";
103 case URB_COMPLETE:
104 return "C";
105 case EVENT_NONE:
106 return "NONE";
107 default:
108 return "UNDEF";
109 }
110}
111
112static enum event_type str_to_event(const char *name)
113{
114 if (!strncasecmp("S", name, EVENT_STR_LEN))
115 return URB_SUBMIT;
116 if (!strncasecmp("C", name, EVENT_STR_LEN))
117 return URB_COMPLETE;
118 if (!strncasecmp("", name, EVENT_STR_LEN))
119 return EVENT_NONE;
120
121 return EVENT_UNDEF;
122}
123
124/*log ep0 activity*/
125static struct {
126 char (buf[DBG_MAX_MSG])[DBG_MSG_LEN]; /* buffer */
127 unsigned idx; /* index */
128 rwlock_t lck; /* lock */
129} dbg_hsic_ctrl = {
130 .idx = 0,
131 .lck = __RW_LOCK_UNLOCKED(lck)
132};
133
134static struct {
135 char (buf[DBG_MAX_MSG])[DBG_MSG_LEN]; /* buffer */
136 unsigned idx; /* index */
137 rwlock_t lck; /* lock */
138} dbg_hsic_data = {
139 .idx = 0,
140 .lck = __RW_LOCK_UNLOCKED(lck)
141};
142
143/**
144 * dbg_inc: increments debug event index
145 * @idx: buffer index
146 */
147static void dbg_inc(unsigned *idx)
148{
149 *idx = (*idx + 1) & (DBG_MAX_MSG-1);
150}
151
152/*get_timestamp - returns time of day in us */
153static char *get_timestamp(char *tbuf)
154{
155 unsigned long long t;
156 unsigned long nanosec_rem;
157
158 t = cpu_clock(smp_processor_id());
159 nanosec_rem = do_div(t, 1000000000)/1000;
160 scnprintf(tbuf, TIME_BUF_LEN, "[%5lu.%06lu] ", (unsigned long)t,
161 nanosec_rem);
162 return tbuf;
163}
164
165static int allow_dbg_log(int ep_addr)
166{
167 int dir, num;
168
169 dir = ep_addr & USB_DIR_IN ? USB_DIR_IN : USB_DIR_OUT;
170 num = ep_addr & ~USB_DIR_IN;
171 num = 1 << num;
172
173 if ((dir == USB_DIR_IN) && (num & ep_addr_rxdbg_mask))
174 return 1;
175 if ((dir == USB_DIR_OUT) && (num & ep_addr_txdbg_mask))
176 return 1;
177
178 return 0;
179}
180
181static void dbg_log_event(struct urb *urb, char * event, unsigned extra)
182{
183 unsigned long flags;
184 int ep_addr;
185 char tbuf[TIME_BUF_LEN];
186
187 if (!enable_dbg_log)
188 return;
189
190 if (!urb) {
191 write_lock_irqsave(&dbg_hsic_ctrl.lck, flags);
192 scnprintf(dbg_hsic_ctrl.buf[dbg_hsic_ctrl.idx], DBG_MSG_LEN,
193 "%s: %s : %u\n", get_timestamp(tbuf), event, extra);
194 dbg_inc(&dbg_hsic_ctrl.idx);
195 write_unlock_irqrestore(&dbg_hsic_ctrl.lck, flags);
196 return;
197 }
198
199 ep_addr = urb->ep->desc.bEndpointAddress;
200 if (!allow_dbg_log(ep_addr))
201 return;
202
203 if ((ep_addr & 0x0f) == 0x0) {
204 /*submit event*/
205 if (!str_to_event(event)) {
206 write_lock_irqsave(&dbg_hsic_ctrl.lck, flags);
207 scnprintf(dbg_hsic_ctrl.buf[dbg_hsic_ctrl.idx],
208 DBG_MSG_LEN, "%s: [%s : %p]:[%s] "
209 "%02x %02x %04x %04x %04x %u %d\n",
210 get_timestamp(tbuf), event, urb,
211 (ep_addr & USB_DIR_IN) ? "in" : "out",
212 urb->setup_packet[0], urb->setup_packet[1],
213 (urb->setup_packet[3] << 8) |
214 urb->setup_packet[2],
215 (urb->setup_packet[5] << 8) |
216 urb->setup_packet[4],
217 (urb->setup_packet[7] << 8) |
218 urb->setup_packet[6],
219 urb->transfer_buffer_length, urb->status);
220
221 dbg_inc(&dbg_hsic_ctrl.idx);
222 write_unlock_irqrestore(&dbg_hsic_ctrl.lck, flags);
223 } else {
224 write_lock_irqsave(&dbg_hsic_ctrl.lck, flags);
225 scnprintf(dbg_hsic_ctrl.buf[dbg_hsic_ctrl.idx],
226 DBG_MSG_LEN, "%s: [%s : %p]:[%s] %u %d\n",
227 get_timestamp(tbuf), event, urb,
228 (ep_addr & USB_DIR_IN) ? "in" : "out",
229 urb->actual_length, extra);
230
231 dbg_inc(&dbg_hsic_ctrl.idx);
232 write_unlock_irqrestore(&dbg_hsic_ctrl.lck, flags);
233 }
234 } else {
235 write_lock_irqsave(&dbg_hsic_data.lck, flags);
236 scnprintf(dbg_hsic_data.buf[dbg_hsic_data.idx], DBG_MSG_LEN,
237 "%s: [%s : %p]:ep%d[%s] %u %d\n",
238 get_timestamp(tbuf), event, urb, ep_addr & 0x0f,
239 (ep_addr & USB_DIR_IN) ? "in" : "out",
240 str_to_event(event) ? urb->actual_length :
241 urb->transfer_buffer_length,
242 str_to_event(event) ? extra : urb->status);
243
244 dbg_inc(&dbg_hsic_data.idx);
245 write_unlock_irqrestore(&dbg_hsic_data.lck, flags);
246 }
247}
248
Vijayavardhan Vennapusa39025fe2011-10-15 05:55:10 +0530249static inline struct msm_hsic_hcd *hcd_to_hsic(struct usb_hcd *hcd)
250{
251 return (struct msm_hsic_hcd *) (hcd->hcd_priv);
252}
253
254static inline struct usb_hcd *hsic_to_hcd(struct msm_hsic_hcd *mehci)
255{
256 return container_of((void *) mehci, struct usb_hcd, hcd_priv);
257}
258
259#define ULPI_IO_TIMEOUT_USEC (10 * 1000)
260
Amit Blayd6ea6102012-06-07 16:26:24 +0300261#define USB_PHY_VDD_DIG_VOL_NONE 0 /*uV */
Vamsi Krishna45d88fa2011-11-02 13:28:42 -0700262#define USB_PHY_VDD_DIG_VOL_MIN 1000000 /* uV */
263#define USB_PHY_VDD_DIG_VOL_MAX 1320000 /* uV */
Vijayavardhan Vennapusa39025fe2011-10-15 05:55:10 +0530264
Lena Salman8c8ba382012-02-14 15:59:31 +0200265#define HSIC_DBG1_REG 0x38
266
Amit Blayd6ea6102012-06-07 16:26:24 +0300267static const int vdd_val[VDD_TYPE_MAX][VDD_VAL_MAX] = {
268 { /* VDD_CX CORNER Voting */
269 [VDD_NONE] = RPM_VREG_CORNER_NONE,
270 [VDD_MIN] = RPM_VREG_CORNER_NOMINAL,
271 [VDD_MAX] = RPM_VREG_CORNER_HIGH,
272 },
273 { /* VDD_CX Voltage Voting */
274 [VDD_NONE] = USB_PHY_VDD_DIG_VOL_NONE,
275 [VDD_MIN] = USB_PHY_VDD_DIG_VOL_MIN,
276 [VDD_MAX] = USB_PHY_VDD_DIG_VOL_MAX,
277 },
278};
279
Vijayavardhan Vennapusa39025fe2011-10-15 05:55:10 +0530280static int msm_hsic_init_vddcx(struct msm_hsic_hcd *mehci, int init)
281{
282 int ret = 0;
Amit Blayd6ea6102012-06-07 16:26:24 +0300283 int none_vol, min_vol, max_vol;
284
285 if (!mehci->hsic_vddcx) {
286 mehci->vdd_type = VDDCX_CORNER;
287 mehci->hsic_vddcx = devm_regulator_get(mehci->dev,
288 "hsic_vdd_dig");
289 if (IS_ERR(mehci->hsic_vddcx)) {
290 mehci->hsic_vddcx = devm_regulator_get(mehci->dev,
291 "HSIC_VDDCX");
292 if (IS_ERR(mehci->hsic_vddcx)) {
293 dev_err(mehci->dev, "unable to get hsic vddcx\n");
294 return PTR_ERR(mehci->hsic_vddcx);
295 }
296 mehci->vdd_type = VDDCX;
297 }
298 }
299
300 none_vol = vdd_val[mehci->vdd_type][VDD_NONE];
301 min_vol = vdd_val[mehci->vdd_type][VDD_MIN];
302 max_vol = vdd_val[mehci->vdd_type][VDD_MAX];
Vijayavardhan Vennapusa39025fe2011-10-15 05:55:10 +0530303
304 if (!init)
305 goto disable_reg;
306
Amit Blayd6ea6102012-06-07 16:26:24 +0300307 ret = regulator_set_voltage(mehci->hsic_vddcx, min_vol, max_vol);
Vijayavardhan Vennapusa39025fe2011-10-15 05:55:10 +0530308 if (ret) {
309 dev_err(mehci->dev, "unable to set the voltage"
310 "for hsic vddcx\n");
Mayank Rana189ac052012-03-24 04:35:02 +0530311 return ret;
Vijayavardhan Vennapusa39025fe2011-10-15 05:55:10 +0530312 }
313
Vijayavardhan Vennapusa39025fe2011-10-15 05:55:10 +0530314 ret = regulator_enable(mehci->hsic_vddcx);
315 if (ret) {
316 dev_err(mehci->dev, "unable to enable hsic vddcx\n");
317 goto reg_enable_err;
318 }
319
320 return 0;
321
322disable_reg:
323 regulator_disable(mehci->hsic_vddcx);
324reg_enable_err:
Amit Blayd6ea6102012-06-07 16:26:24 +0300325 regulator_set_voltage(mehci->hsic_vddcx, none_vol, max_vol);
326
Vijayavardhan Vennapusa39025fe2011-10-15 05:55:10 +0530327 return ret;
328
329}
330
Vamsi Krishna8e6edcb2012-06-20 18:08:50 -0700331static int ulpi_read(struct msm_hsic_hcd *mehci, u32 reg)
332{
333 struct usb_hcd *hcd = hsic_to_hcd(mehci);
334 unsigned long timeout;
335
336 /* initiate read operation */
337 writel_relaxed(ULPI_RUN | ULPI_READ | ULPI_ADDR(reg),
338 USB_ULPI_VIEWPORT);
339
340 /* wait for completion */
341 timeout = jiffies + usecs_to_jiffies(ULPI_IO_TIMEOUT_USEC);
342 while (readl_relaxed(USB_ULPI_VIEWPORT) & ULPI_RUN) {
343 if (time_after(jiffies, timeout)) {
344 dev_err(mehci->dev, "ulpi_read: timeout %08x\n",
345 readl_relaxed(USB_ULPI_VIEWPORT));
346 return -ETIMEDOUT;
347 }
348 udelay(1);
349 }
350
351 return ULPI_DATA_READ(readl_relaxed(USB_ULPI_VIEWPORT));
352}
353
Vijayavardhan Vennapusa39025fe2011-10-15 05:55:10 +0530354static int ulpi_write(struct msm_hsic_hcd *mehci, u32 val, u32 reg)
355{
356 struct usb_hcd *hcd = hsic_to_hcd(mehci);
357 int cnt = 0;
358
359 /* initiate write operation */
360 writel_relaxed(ULPI_RUN | ULPI_WRITE |
361 ULPI_ADDR(reg) | ULPI_DATA(val),
362 USB_ULPI_VIEWPORT);
363
364 /* wait for completion */
365 while (cnt < ULPI_IO_TIMEOUT_USEC) {
366 if (!(readl_relaxed(USB_ULPI_VIEWPORT) & ULPI_RUN))
367 break;
368 udelay(1);
369 cnt++;
370 }
371
372 if (cnt >= ULPI_IO_TIMEOUT_USEC) {
373 dev_err(mehci->dev, "ulpi_write: timeout\n");
374 return -ETIMEDOUT;
375 }
376
377 return 0;
378}
379
Vamsi Krishna8e6edcb2012-06-20 18:08:50 -0700380#define HSIC_DBG1 0X38
381#define ULPI_MANUAL_ENABLE BIT(4)
382#define ULPI_LINESTATE_DATA BIT(5)
383#define ULPI_LINESTATE_STROBE BIT(6)
384static void ehci_msm_enable_ulpi_control(struct usb_hcd *hcd, u32 linestate)
385{
386 struct msm_hsic_hcd *mehci = hcd_to_hsic(hcd);
387 int val;
388
389 switch (linestate) {
390 case PORT_RESET:
391 val = ulpi_read(mehci, HSIC_DBG1);
392 val |= ULPI_MANUAL_ENABLE;
393 val &= ~(ULPI_LINESTATE_DATA | ULPI_LINESTATE_STROBE);
394 ulpi_write(mehci, val, HSIC_DBG1);
395 break;
396 default:
397 pr_info("%s: Unknown linestate:%0x\n", __func__, linestate);
398 }
399}
400
401static void ehci_msm_disable_ulpi_control(struct usb_hcd *hcd)
402{
403 struct msm_hsic_hcd *mehci = hcd_to_hsic(hcd);
404 int val;
405
406 val = ulpi_read(mehci, HSIC_DBG1);
407 val &= ~ULPI_MANUAL_ENABLE;
408 ulpi_write(mehci, val, HSIC_DBG1);
409}
410
Vijayavardhan Vennapusae3316a12011-10-15 06:05:17 +0530411static int msm_hsic_config_gpios(struct msm_hsic_hcd *mehci, int gpio_en)
412{
413 int rc = 0;
414 struct msm_hsic_host_platform_data *pdata;
Vamsi Krishna34f01582011-12-14 19:54:42 -0800415 static int gpio_status;
Vijayavardhan Vennapusae3316a12011-10-15 06:05:17 +0530416
417 pdata = mehci->dev->platform_data;
Vamsi Krishna34f01582011-12-14 19:54:42 -0800418
Lena Salman8c8ba382012-02-14 15:59:31 +0200419 if (!pdata || !pdata->strobe || !pdata->data)
Vijayavardhan Vennapusae3316a12011-10-15 06:05:17 +0530420 return rc;
421
Vamsi Krishna34f01582011-12-14 19:54:42 -0800422 if (gpio_status == gpio_en)
423 return 0;
424
425 gpio_status = gpio_en;
426
Vijayavardhan Vennapusae3316a12011-10-15 06:05:17 +0530427 if (!gpio_en)
428 goto free_gpio;
429
430 rc = gpio_request(pdata->strobe, "HSIC_STROBE_GPIO");
431 if (rc < 0) {
432 dev_err(mehci->dev, "gpio request failed for HSIC STROBE\n");
433 return rc;
434 }
435
436 rc = gpio_request(pdata->data, "HSIC_DATA_GPIO");
437 if (rc < 0) {
438 dev_err(mehci->dev, "gpio request failed for HSIC DATA\n");
439 goto free_strobe;
440 }
441
Hemant Kumar6fd65032012-05-23 13:02:24 -0700442 if (mehci->wakeup_gpio) {
443 rc = gpio_request(mehci->wakeup_gpio, "HSIC_WAKEUP_GPIO");
444 if (rc < 0) {
445 dev_err(mehci->dev, "gpio request failed for HSIC WAKEUP\n");
446 goto free_data;
447 }
448 }
449
Vijayavardhan Vennapusae3316a12011-10-15 06:05:17 +0530450 return 0;
451
452free_gpio:
Hemant Kumar6fd65032012-05-23 13:02:24 -0700453 if (mehci->wakeup_gpio)
454 gpio_free(mehci->wakeup_gpio);
455free_data:
Vijayavardhan Vennapusae3316a12011-10-15 06:05:17 +0530456 gpio_free(pdata->data);
457free_strobe:
458 gpio_free(pdata->strobe);
459
460 return rc;
461}
462
Vamsi Krishna64b48612012-06-14 16:08:11 -0700463static void msm_hsic_clk_reset(struct msm_hsic_hcd *mehci)
Vijayavardhan Vennapusa39025fe2011-10-15 05:55:10 +0530464{
465 int ret;
466
Manu Gautam5143b252012-01-05 19:25:23 -0800467 ret = clk_reset(mehci->core_clk, CLK_RESET_ASSERT);
Vijayavardhan Vennapusa39025fe2011-10-15 05:55:10 +0530468 if (ret) {
Vamsi Krishna64b48612012-06-14 16:08:11 -0700469 dev_err(mehci->dev, "hsic clk assert failed:%d\n", ret);
470 return;
Vijayavardhan Vennapusa39025fe2011-10-15 05:55:10 +0530471 }
Vamsi Krishna64b48612012-06-14 16:08:11 -0700472 clk_disable(mehci->core_clk);
Vijayavardhan Vennapusa39025fe2011-10-15 05:55:10 +0530473
Manu Gautam5143b252012-01-05 19:25:23 -0800474 ret = clk_reset(mehci->core_clk, CLK_RESET_DEASSERT);
Vijayavardhan Vennapusa39025fe2011-10-15 05:55:10 +0530475 if (ret)
Vamsi Krishna64b48612012-06-14 16:08:11 -0700476 dev_err(mehci->dev, "hsic clk deassert failed:%d\n", ret);
Vijayavardhan Vennapusa39025fe2011-10-15 05:55:10 +0530477
Vamsi Krishna64b48612012-06-14 16:08:11 -0700478 usleep_range(10000, 12000);
479
480 clk_enable(mehci->core_clk);
Vijayavardhan Vennapusa39025fe2011-10-15 05:55:10 +0530481}
482
Vamsi Krishna64b48612012-06-14 16:08:11 -0700483#define HSIC_STROBE_GPIO_PAD_CTL (MSM_TLMM_BASE+0x20C0)
484#define HSIC_DATA_GPIO_PAD_CTL (MSM_TLMM_BASE+0x20C4)
Vijayavardhan Vennapusae3316a12011-10-15 06:05:17 +0530485#define HSIC_CAL_PAD_CTL (MSM_TLMM_BASE+0x20C8)
486#define HSIC_LV_MODE 0x04
487#define HSIC_PAD_CALIBRATION 0xA8
488#define HSIC_GPIO_PAD_VAL 0x0A0AAA10
Vijayavardhan Vennapusa39025fe2011-10-15 05:55:10 +0530489#define LINK_RESET_TIMEOUT_USEC (250 * 1000)
490static int msm_hsic_reset(struct msm_hsic_hcd *mehci)
491{
492 struct usb_hcd *hcd = hsic_to_hcd(mehci);
Vijayavardhan Vennapusa39025fe2011-10-15 05:55:10 +0530493 int ret;
Lena Salman8c8ba382012-02-14 15:59:31 +0200494 struct msm_hsic_host_platform_data *pdata = mehci->dev->platform_data;
Vijayavardhan Vennapusa39025fe2011-10-15 05:55:10 +0530495
Vamsi Krishna64b48612012-06-14 16:08:11 -0700496 msm_hsic_clk_reset(mehci);
Vijayavardhan Vennapusa39025fe2011-10-15 05:55:10 +0530497
Vamsi Krishna64b48612012-06-14 16:08:11 -0700498 /* select ulpi phy */
Vijayavardhan Vennapusa39025fe2011-10-15 05:55:10 +0530499 writel_relaxed(0x80000000, USB_PORTSC);
500
Vamsi Krishna64b48612012-06-14 16:08:11 -0700501 mb();
Vijayavardhan Vennapusae3316a12011-10-15 06:05:17 +0530502
Lena Salman8c8ba382012-02-14 15:59:31 +0200503 /* HSIC init sequence when HSIC signals (Strobe/Data) are
504 routed via GPIOs */
505 if (pdata && pdata->strobe && pdata->data) {
Vijayavardhan Vennapusae3316a12011-10-15 06:05:17 +0530506
Lena Salman8c8ba382012-02-14 15:59:31 +0200507 /* Enable LV_MODE in HSIC_CAL_PAD_CTL register */
508 writel_relaxed(HSIC_LV_MODE, HSIC_CAL_PAD_CTL);
Vijayavardhan Vennapusae3316a12011-10-15 06:05:17 +0530509
Vamsi Krishna64b48612012-06-14 16:08:11 -0700510 mb();
511
Lena Salman8c8ba382012-02-14 15:59:31 +0200512 /*set periodic calibration interval to ~2.048sec in
513 HSIC_IO_CAL_REG */
514 ulpi_write(mehci, 0xFF, 0x33);
515
516 /* Enable periodic IO calibration in HSIC_CFG register */
517 ulpi_write(mehci, HSIC_PAD_CALIBRATION, 0x30);
518
Vamsi Krishna64b48612012-06-14 16:08:11 -0700519 /* Configure GPIO pins for HSIC functionality mode */
Lena Salman8c8ba382012-02-14 15:59:31 +0200520 ret = msm_hsic_config_gpios(mehci, 1);
521 if (ret) {
522 dev_err(mehci->dev, " gpio configuarion failed\n");
523 return ret;
524 }
Vamsi Krishna64b48612012-06-14 16:08:11 -0700525 /* Set LV_MODE=0x1 and DCC=0x2 in HSIC_GPIO PAD_CTL register */
526 writel_relaxed(HSIC_GPIO_PAD_VAL, HSIC_STROBE_GPIO_PAD_CTL);
527 writel_relaxed(HSIC_GPIO_PAD_VAL, HSIC_DATA_GPIO_PAD_CTL);
528
529 mb();
530
Lena Salman8c8ba382012-02-14 15:59:31 +0200531 /* Enable HSIC mode in HSIC_CFG register */
532 ulpi_write(mehci, 0x01, 0x31);
533 } else {
534 /* HSIC init sequence when HSIC signals (Strobe/Data) are routed
535 via dedicated I/O */
536
537 /* programmable length of connect signaling (33.2ns) */
538 ret = ulpi_write(mehci, 3, HSIC_DBG1_REG);
539 if (ret) {
540 pr_err("%s: Unable to program length of connect "
541 "signaling\n", __func__);
542 }
543
544 /*set periodic calibration interval to ~2.048sec in
545 HSIC_IO_CAL_REG */
546 ulpi_write(mehci, 0xFF, 0x33);
547
548 /* Enable HSIC mode in HSIC_CFG register */
549 ulpi_write(mehci, 0xA9, 0x30);
Vijayavardhan Vennapusae3316a12011-10-15 06:05:17 +0530550 }
551
Hemant Kumar6fd65032012-05-23 13:02:24 -0700552 /*disable auto resume*/
553 ulpi_write(mehci, ULPI_IFC_CTRL_AUTORESUME, ULPI_CLR(ULPI_IFC_CTRL));
554
Vijayavardhan Vennapusa39025fe2011-10-15 05:55:10 +0530555 return 0;
556}
557
558#define PHY_SUSPEND_TIMEOUT_USEC (500 * 1000)
559#define PHY_RESUME_TIMEOUT_USEC (100 * 1000)
560
561#ifdef CONFIG_PM_SLEEP
562static int msm_hsic_suspend(struct msm_hsic_hcd *mehci)
563{
564 struct usb_hcd *hcd = hsic_to_hcd(mehci);
Vijayavardhan Vennapusa2b592824f2011-11-02 19:51:32 +0530565 int cnt = 0, ret;
Vijayavardhan Vennapusa39025fe2011-10-15 05:55:10 +0530566 u32 val;
Amit Blayd6ea6102012-06-07 16:26:24 +0300567 int none_vol, max_vol;
Vijayavardhan Vennapusa39025fe2011-10-15 05:55:10 +0530568
569 if (atomic_read(&mehci->in_lpm)) {
570 dev_dbg(mehci->dev, "%s called in lpm\n", __func__);
571 return 0;
572 }
573
Hemant Kumar7f374632012-05-31 20:10:32 -0700574 if (!(readl_relaxed(USB_PORTSC) & PORT_PE)) {
575 dev_dbg(mehci->dev, "%s:port is not enabled skip suspend\n",
576 __func__);
577 return -EAGAIN;
578 }
579
Vijayavardhan Vennapusa39025fe2011-10-15 05:55:10 +0530580 disable_irq(hcd->irq);
Jack Phambe05fbb2012-05-16 10:56:26 -0700581
582 /* make sure we don't race against a remote wakeup */
583 if (test_bit(HCD_FLAG_WAKEUP_PENDING, &hcd->flags) ||
584 readl_relaxed(USB_PORTSC) & PORT_RESUME) {
585 dev_dbg(mehci->dev, "wakeup pending, aborting suspend\n");
586 enable_irq(hcd->irq);
587 return -EBUSY;
588 }
589
Vijayavardhan Vennapusa39025fe2011-10-15 05:55:10 +0530590 /*
591 * PHY may take some time or even fail to enter into low power
592 * mode (LPM). Hence poll for 500 msec and reset the PHY and link
593 * in failure case.
594 */
Hemant Kumar3dbc5b32012-05-09 15:36:11 -0700595 val = readl_relaxed(USB_PORTSC);
596 val &= ~PORT_RWC_BITS;
597 val |= PORTSC_PHCD;
Vijayavardhan Vennapusa39025fe2011-10-15 05:55:10 +0530598 writel_relaxed(val, USB_PORTSC);
599 while (cnt < PHY_SUSPEND_TIMEOUT_USEC) {
600 if (readl_relaxed(USB_PORTSC) & PORTSC_PHCD)
601 break;
602 udelay(1);
603 cnt++;
604 }
605
606 if (cnt >= PHY_SUSPEND_TIMEOUT_USEC) {
607 dev_err(mehci->dev, "Unable to suspend PHY\n");
Vijayavardhan Vennapusae3316a12011-10-15 06:05:17 +0530608 msm_hsic_config_gpios(mehci, 0);
Vijayavardhan Vennapusa39025fe2011-10-15 05:55:10 +0530609 msm_hsic_reset(mehci);
Vijayavardhan Vennapusa39025fe2011-10-15 05:55:10 +0530610 }
611
612 /*
613 * PHY has capability to generate interrupt asynchronously in low
614 * power mode (LPM). This interrupt is level triggered. So USB IRQ
615 * line must be disabled till async interrupt enable bit is cleared
616 * in USBCMD register. Assert STP (ULPI interface STOP signal) to
617 * block data communication from PHY.
618 */
619 writel_relaxed(readl_relaxed(USB_USBCMD) | ASYNC_INTR_CTRL |
620 ULPI_STP_CTRL, USB_USBCMD);
621
622 /*
623 * Ensure that hardware is put in low power mode before
624 * clocks are turned OFF and VDD is allowed to minimize.
625 */
626 mb();
627
Manu Gautam28b1bac2012-01-30 16:43:06 +0530628 clk_disable_unprepare(mehci->core_clk);
629 clk_disable_unprepare(mehci->phy_clk);
630 clk_disable_unprepare(mehci->cal_clk);
631 clk_disable_unprepare(mehci->ahb_clk);
Vijayavardhan Vennapusa39025fe2011-10-15 05:55:10 +0530632
Amit Blayd6ea6102012-06-07 16:26:24 +0300633 none_vol = vdd_val[mehci->vdd_type][VDD_NONE];
634 max_vol = vdd_val[mehci->vdd_type][VDD_MAX];
635
636 ret = regulator_set_voltage(mehci->hsic_vddcx, none_vol, max_vol);
Vamsi Krishna45d88fa2011-11-02 13:28:42 -0700637 if (ret < 0)
Amit Blayd6ea6102012-06-07 16:26:24 +0300638 dev_err(mehci->dev, "unable to set vddcx voltage for VDD MIN\n");
Vamsi Krishna45d88fa2011-11-02 13:28:42 -0700639
Hemant Kumare6275972012-02-29 20:06:21 -0800640 if (mehci->bus_perf_client && debug_bus_voting_enabled) {
641 ret = msm_bus_scale_client_update_request(
642 mehci->bus_perf_client, 0);
643 if (ret)
644 dev_err(mehci->dev, "%s: Failed to dvote for "
645 "bus bandwidth %d\n", __func__, ret);
646 }
647
Vijayavardhan Vennapusa39025fe2011-10-15 05:55:10 +0530648 atomic_set(&mehci->in_lpm, 1);
649 enable_irq(hcd->irq);
Hemant Kumar6fd65032012-05-23 13:02:24 -0700650
651 mehci->wakeup_irq_enabled = 1;
652 enable_irq_wake(mehci->wakeup_irq);
653 enable_irq(mehci->wakeup_irq);
654
Vijayavardhan Vennapusa39025fe2011-10-15 05:55:10 +0530655 wake_unlock(&mehci->wlock);
656
657 dev_info(mehci->dev, "HSIC-USB in low power mode\n");
658
659 return 0;
660}
661
662static int msm_hsic_resume(struct msm_hsic_hcd *mehci)
663{
664 struct usb_hcd *hcd = hsic_to_hcd(mehci);
Vijayavardhan Vennapusa2b592824f2011-11-02 19:51:32 +0530665 int cnt = 0, ret;
Vijayavardhan Vennapusa39025fe2011-10-15 05:55:10 +0530666 unsigned temp;
Amit Blayd6ea6102012-06-07 16:26:24 +0300667 int min_vol, max_vol;
Vijayavardhan Vennapusa39025fe2011-10-15 05:55:10 +0530668
669 if (!atomic_read(&mehci->in_lpm)) {
670 dev_dbg(mehci->dev, "%s called in !in_lpm\n", __func__);
671 return 0;
672 }
673
Hemant Kumar6fd65032012-05-23 13:02:24 -0700674 if (mehci->wakeup_irq_enabled) {
675 disable_irq_wake(mehci->wakeup_irq);
676 disable_irq_nosync(mehci->wakeup_irq);
677 mehci->wakeup_irq_enabled = 0;
678 }
679
Vijayavardhan Vennapusa39025fe2011-10-15 05:55:10 +0530680 wake_lock(&mehci->wlock);
681
Hemant Kumare6275972012-02-29 20:06:21 -0800682 if (mehci->bus_perf_client && debug_bus_voting_enabled) {
683 ret = msm_bus_scale_client_update_request(
684 mehci->bus_perf_client, 1);
685 if (ret)
686 dev_err(mehci->dev, "%s: Failed to vote for "
687 "bus bandwidth %d\n", __func__, ret);
688 }
689
Amit Blayd6ea6102012-06-07 16:26:24 +0300690 min_vol = vdd_val[mehci->vdd_type][VDD_MIN];
691 max_vol = vdd_val[mehci->vdd_type][VDD_MAX];
692
693 ret = regulator_set_voltage(mehci->hsic_vddcx, min_vol, max_vol);
Vamsi Krishna45d88fa2011-11-02 13:28:42 -0700694 if (ret < 0)
Amit Blayd6ea6102012-06-07 16:26:24 +0300695 dev_err(mehci->dev, "unable to set nominal vddcx voltage (no VDD MIN)\n");
Vamsi Krishna45d88fa2011-11-02 13:28:42 -0700696
Manu Gautam28b1bac2012-01-30 16:43:06 +0530697 clk_prepare_enable(mehci->core_clk);
698 clk_prepare_enable(mehci->phy_clk);
699 clk_prepare_enable(mehci->cal_clk);
700 clk_prepare_enable(mehci->ahb_clk);
Vijayavardhan Vennapusa39025fe2011-10-15 05:55:10 +0530701
702 temp = readl_relaxed(USB_USBCMD);
703 temp &= ~ASYNC_INTR_CTRL;
704 temp &= ~ULPI_STP_CTRL;
705 writel_relaxed(temp, USB_USBCMD);
706
707 if (!(readl_relaxed(USB_PORTSC) & PORTSC_PHCD))
708 goto skip_phy_resume;
709
Hemant Kumar3dbc5b32012-05-09 15:36:11 -0700710 temp = readl_relaxed(USB_PORTSC);
711 temp &= ~(PORT_RWC_BITS | PORTSC_PHCD);
Vijayavardhan Vennapusa39025fe2011-10-15 05:55:10 +0530712 writel_relaxed(temp, USB_PORTSC);
713 while (cnt < PHY_RESUME_TIMEOUT_USEC) {
714 if (!(readl_relaxed(USB_PORTSC) & PORTSC_PHCD) &&
715 (readl_relaxed(USB_ULPI_VIEWPORT) & ULPI_SYNC_STATE))
716 break;
717 udelay(1);
718 cnt++;
719 }
720
721 if (cnt >= PHY_RESUME_TIMEOUT_USEC) {
722 /*
723 * This is a fatal error. Reset the link and
724 * PHY to make hsic working.
725 */
726 dev_err(mehci->dev, "Unable to resume USB. Reset the hsic\n");
Vijayavardhan Vennapusae3316a12011-10-15 06:05:17 +0530727 msm_hsic_config_gpios(mehci, 0);
Vijayavardhan Vennapusa39025fe2011-10-15 05:55:10 +0530728 msm_hsic_reset(mehci);
729 }
730
731skip_phy_resume:
732
Hemant Kumard4ee29f2012-06-06 11:47:50 -0700733 if (!(readl_relaxed(USB_USBCMD) & CMD_RUN) &&
734 (readl_relaxed(USB_PORTSC) & PORT_SUSPEND)) {
735 writel_relaxed(readl_relaxed(USB_USBCMD) | CMD_RUN ,
736 USB_USBCMD);
737 dbg_log_event(NULL, "Set RS", readl_relaxed(USB_USBCMD));
738 }
739
Hemant Kumar6fd65032012-05-23 13:02:24 -0700740 usb_hcd_resume_root_hub(hcd);
741
Vijayavardhan Vennapusa39025fe2011-10-15 05:55:10 +0530742 atomic_set(&mehci->in_lpm, 0);
743
744 if (mehci->async_int) {
745 mehci->async_int = false;
746 pm_runtime_put_noidle(mehci->dev);
747 enable_irq(hcd->irq);
748 }
749
Hemant Kumar6fd65032012-05-23 13:02:24 -0700750 if (atomic_read(&mehci->pm_usage_cnt)) {
751 atomic_set(&mehci->pm_usage_cnt, 0);
752 pm_runtime_put_noidle(mehci->dev);
753 }
754
Vijayavardhan Vennapusa39025fe2011-10-15 05:55:10 +0530755 dev_info(mehci->dev, "HSIC-USB exited from low power mode\n");
756
757 return 0;
758}
759#endif
760
761static irqreturn_t msm_hsic_irq(struct usb_hcd *hcd)
762{
763 struct msm_hsic_hcd *mehci = hcd_to_hsic(hcd);
764
765 if (atomic_read(&mehci->in_lpm)) {
766 disable_irq_nosync(hcd->irq);
Hemant Kumar3dbc5b32012-05-09 15:36:11 -0700767 dev_dbg(mehci->dev, "phy async intr\n");
Vijayavardhan Vennapusa39025fe2011-10-15 05:55:10 +0530768 mehci->async_int = true;
769 pm_runtime_get(mehci->dev);
770 return IRQ_HANDLED;
771 }
772
773 return ehci_irq(hcd);
774}
775
776static int ehci_hsic_reset(struct usb_hcd *hcd)
777{
778 struct ehci_hcd *ehci = hcd_to_ehci(hcd);
779 int retval;
780
781 ehci->caps = USB_CAPLENGTH;
782 ehci->regs = USB_CAPLENGTH +
783 HC_LENGTH(ehci, ehci_readl(ehci, &ehci->caps->hc_capbase));
784 dbg_hcs_params(ehci, "reset");
785 dbg_hcc_params(ehci, "reset");
786
787 /* cache the data to minimize the chip reads*/
788 ehci->hcs_params = ehci_readl(ehci, &ehci->caps->hcs_params);
789
790 hcd->has_tt = 1;
791 ehci->sbrn = HCD_USB2;
792
793 retval = ehci_halt(ehci);
794 if (retval)
795 return retval;
796
797 /* data structure init */
798 retval = ehci_init(hcd);
799 if (retval)
800 return retval;
801
802 retval = ehci_reset(ehci);
803 if (retval)
804 return retval;
805
806 /* bursts of unspecified length. */
807 writel_relaxed(0, USB_AHBBURST);
808 /* Use the AHB transactor */
Vijayavardhan Vennapusa5f32d7a2012-03-14 16:30:26 +0530809 writel_relaxed(0x08, USB_AHBMODE);
Vijayavardhan Vennapusa39025fe2011-10-15 05:55:10 +0530810 /* Disable streaming mode and select host mode */
811 writel_relaxed(0x13, USB_USBMODE);
812
813 ehci_port_power(ehci, 1);
814 return 0;
815}
816
Hemant Kumar45d211b2012-05-31 17:58:43 -0700817static int ehci_hsic_urb_enqueue(struct usb_hcd *hcd, struct urb *urb,
818 gfp_t mem_flags)
819{
820 dbg_log_event(urb, event_to_str(URB_SUBMIT), 0);
821 return ehci_urb_enqueue(hcd, urb, mem_flags);
822}
823
824static int ehci_hsic_bus_suspend(struct usb_hcd *hcd)
825{
826 dbg_log_event(NULL, "Suspend RH", 0);
827 return ehci_bus_suspend(hcd);
828}
829
830static int ehci_hsic_bus_resume(struct usb_hcd *hcd)
831{
832 dbg_log_event(NULL, "Resume RH", 0);
833 return ehci_bus_resume(hcd);
834}
835
Vijayavardhan Vennapusa39025fe2011-10-15 05:55:10 +0530836static struct hc_driver msm_hsic_driver = {
837 .description = hcd_name,
838 .product_desc = "Qualcomm EHCI Host Controller using HSIC",
839 .hcd_priv_size = sizeof(struct msm_hsic_hcd),
840
841 /*
842 * generic hardware linkage
843 */
844 .irq = msm_hsic_irq,
Vamsi Krishna8e6edcb2012-06-20 18:08:50 -0700845 .flags = HCD_USB2 | HCD_MEMORY | HCD_OLD_ENUM,
Vijayavardhan Vennapusa39025fe2011-10-15 05:55:10 +0530846
847 .reset = ehci_hsic_reset,
848 .start = ehci_run,
849
850 .stop = ehci_stop,
851 .shutdown = ehci_shutdown,
852
853 /*
854 * managing i/o requests and associated device resources
855 */
Hemant Kumar45d211b2012-05-31 17:58:43 -0700856 .urb_enqueue = ehci_hsic_urb_enqueue,
Vijayavardhan Vennapusa39025fe2011-10-15 05:55:10 +0530857 .urb_dequeue = ehci_urb_dequeue,
858 .endpoint_disable = ehci_endpoint_disable,
859 .endpoint_reset = ehci_endpoint_reset,
860 .clear_tt_buffer_complete = ehci_clear_tt_buffer_complete,
861
862 /*
863 * scheduling support
864 */
865 .get_frame_number = ehci_get_frame,
866
867 /*
868 * root hub support
869 */
870 .hub_status_data = ehci_hub_status_data,
871 .hub_control = ehci_hub_control,
872 .relinquish_port = ehci_relinquish_port,
873 .port_handed_over = ehci_port_handed_over,
874
875 /*
876 * PM support
877 */
Hemant Kumar45d211b2012-05-31 17:58:43 -0700878 .bus_suspend = ehci_hsic_bus_suspend,
879 .bus_resume = ehci_hsic_bus_resume,
880
881 .log_urb_complete = dbg_log_event,
Vamsi Krishna8e6edcb2012-06-20 18:08:50 -0700882
883 .enable_ulpi_control = ehci_msm_enable_ulpi_control,
884 .disable_ulpi_control = ehci_msm_disable_ulpi_control,
Vijayavardhan Vennapusa39025fe2011-10-15 05:55:10 +0530885};
886
887static int msm_hsic_init_clocks(struct msm_hsic_hcd *mehci, u32 init)
888{
889 int ret = 0;
890
891 if (!init)
892 goto put_clocks;
893
Lena Salman8c8ba382012-02-14 15:59:31 +0200894 /*core_clk is required for LINK protocol engine
895 *clock rate appropriately set by target specific clock driver */
Manu Gautam5143b252012-01-05 19:25:23 -0800896 mehci->core_clk = clk_get(mehci->dev, "core_clk");
897 if (IS_ERR(mehci->core_clk)) {
898 dev_err(mehci->dev, "failed to get core_clk\n");
899 ret = PTR_ERR(mehci->core_clk);
Vijayavardhan Vennapusa39025fe2011-10-15 05:55:10 +0530900 return ret;
901 }
Vijayavardhan Vennapusa39025fe2011-10-15 05:55:10 +0530902
Lena Salman8c8ba382012-02-14 15:59:31 +0200903 /* alt_core_clk is for LINK to be used during PHY RESET
904 * clock rate appropriately set by target specific clock driver */
Manu Gautam5143b252012-01-05 19:25:23 -0800905 mehci->alt_core_clk = clk_get(mehci->dev, "alt_core_clk");
906 if (IS_ERR(mehci->alt_core_clk)) {
907 dev_err(mehci->dev, "failed to core_clk\n");
908 ret = PTR_ERR(mehci->alt_core_clk);
909 goto put_core_clk;
Vijayavardhan Vennapusa39025fe2011-10-15 05:55:10 +0530910 }
Vijayavardhan Vennapusa39025fe2011-10-15 05:55:10 +0530911
Lena Salman8c8ba382012-02-14 15:59:31 +0200912 /* phy_clk is required for HSIC PHY operation
913 * clock rate appropriately set by target specific clock driver */
Manu Gautam5143b252012-01-05 19:25:23 -0800914 mehci->phy_clk = clk_get(mehci->dev, "phy_clk");
915 if (IS_ERR(mehci->phy_clk)) {
916 dev_err(mehci->dev, "failed to get phy_clk\n");
917 ret = PTR_ERR(mehci->phy_clk);
918 goto put_alt_core_clk;
Vijayavardhan Vennapusa39025fe2011-10-15 05:55:10 +0530919 }
Vijayavardhan Vennapusa39025fe2011-10-15 05:55:10 +0530920
921 /* 10MHz cal_clk is required for calibration of I/O pads */
Manu Gautam5143b252012-01-05 19:25:23 -0800922 mehci->cal_clk = clk_get(mehci->dev, "cal_clk");
Vijayavardhan Vennapusa39025fe2011-10-15 05:55:10 +0530923 if (IS_ERR(mehci->cal_clk)) {
Manu Gautam5143b252012-01-05 19:25:23 -0800924 dev_err(mehci->dev, "failed to get cal_clk\n");
Vijayavardhan Vennapusa39025fe2011-10-15 05:55:10 +0530925 ret = PTR_ERR(mehci->cal_clk);
Manu Gautam5143b252012-01-05 19:25:23 -0800926 goto put_phy_clk;
Vijayavardhan Vennapusa39025fe2011-10-15 05:55:10 +0530927 }
928 clk_set_rate(mehci->cal_clk, 10000000);
929
930 /* ahb_clk is required for data transfers */
Manu Gautam5143b252012-01-05 19:25:23 -0800931 mehci->ahb_clk = clk_get(mehci->dev, "iface_clk");
Vijayavardhan Vennapusa39025fe2011-10-15 05:55:10 +0530932 if (IS_ERR(mehci->ahb_clk)) {
Manu Gautam5143b252012-01-05 19:25:23 -0800933 dev_err(mehci->dev, "failed to get iface_clk\n");
Vijayavardhan Vennapusa39025fe2011-10-15 05:55:10 +0530934 ret = PTR_ERR(mehci->ahb_clk);
935 goto put_cal_clk;
936 }
937
Manu Gautam28b1bac2012-01-30 16:43:06 +0530938 clk_prepare_enable(mehci->core_clk);
939 clk_prepare_enable(mehci->phy_clk);
940 clk_prepare_enable(mehci->cal_clk);
941 clk_prepare_enable(mehci->ahb_clk);
Vijayavardhan Vennapusa39025fe2011-10-15 05:55:10 +0530942
943 return 0;
944
945put_clocks:
Jack Phamfd193eb2012-02-22 15:38:08 -0800946 if (!atomic_read(&mehci->in_lpm)) {
947 clk_disable_unprepare(mehci->core_clk);
948 clk_disable_unprepare(mehci->phy_clk);
949 clk_disable_unprepare(mehci->cal_clk);
950 clk_disable_unprepare(mehci->ahb_clk);
951 }
Vijayavardhan Vennapusa39025fe2011-10-15 05:55:10 +0530952 clk_put(mehci->ahb_clk);
953put_cal_clk:
954 clk_put(mehci->cal_clk);
Manu Gautam5143b252012-01-05 19:25:23 -0800955put_phy_clk:
956 clk_put(mehci->phy_clk);
957put_alt_core_clk:
958 clk_put(mehci->alt_core_clk);
959put_core_clk:
960 clk_put(mehci->core_clk);
Vijayavardhan Vennapusa39025fe2011-10-15 05:55:10 +0530961
962 return ret;
963}
Vamsi Krishna34f01582011-12-14 19:54:42 -0800964static irqreturn_t hsic_peripheral_status_change(int irq, void *dev_id)
965{
966 struct msm_hsic_hcd *mehci = dev_id;
967
Vamsi Krishna6921cbe2012-02-21 18:34:43 -0800968 pr_debug("%s: mehci:%p dev_id:%p\n", __func__, mehci, dev_id);
Vamsi Krishna34f01582011-12-14 19:54:42 -0800969
970 if (mehci)
971 msm_hsic_config_gpios(mehci, 0);
972
973 return IRQ_HANDLED;
974}
975
Vamsi Krishna6921cbe2012-02-21 18:34:43 -0800976static irqreturn_t msm_hsic_wakeup_irq(int irq, void *data)
977{
978 struct msm_hsic_hcd *mehci = data;
979
Hemant Kumar6fd65032012-05-23 13:02:24 -0700980 mehci->wakeup_int_cnt++;
Hemant Kumar45d211b2012-05-31 17:58:43 -0700981 dbg_log_event(NULL, "Remote Wakeup IRQ", mehci->wakeup_int_cnt);
Hemant Kumar6fd65032012-05-23 13:02:24 -0700982 dev_dbg(mehci->dev, "%s: hsic remote wakeup interrupt cnt: %u\n",
983 __func__, mehci->wakeup_int_cnt);
984
985 wake_lock(&mehci->wlock);
Vamsi Krishna6921cbe2012-02-21 18:34:43 -0800986
Jack Phamfe441ea2012-03-23 17:03:15 -0700987 if (mehci->wakeup_irq_enabled) {
988 mehci->wakeup_irq_enabled = 0;
989 disable_irq_wake(irq);
990 disable_irq_nosync(irq);
991 }
992
Hemant Kumar6fd65032012-05-23 13:02:24 -0700993 if (!atomic_read(&mehci->pm_usage_cnt)) {
994 atomic_set(&mehci->pm_usage_cnt, 1);
995 pm_runtime_get(mehci->dev);
996 }
997
Vamsi Krishna6921cbe2012-02-21 18:34:43 -0800998 return IRQ_HANDLED;
999}
1000
Hemant Kumare6275972012-02-29 20:06:21 -08001001static int ehci_hsic_msm_bus_show(struct seq_file *s, void *unused)
1002{
1003 if (debug_bus_voting_enabled)
1004 seq_printf(s, "enabled\n");
1005 else
1006 seq_printf(s, "disabled\n");
1007
1008 return 0;
1009}
1010
1011static int ehci_hsic_msm_bus_open(struct inode *inode, struct file *file)
1012{
1013 return single_open(file, ehci_hsic_msm_bus_show, inode->i_private);
1014}
1015
1016static ssize_t ehci_hsic_msm_bus_write(struct file *file,
1017 const char __user *ubuf, size_t count, loff_t *ppos)
1018{
1019 char buf[8];
1020 int ret;
1021 struct seq_file *s = file->private_data;
1022 struct msm_hsic_hcd *mehci = s->private;
1023
1024 memset(buf, 0x00, sizeof(buf));
1025
1026 if (copy_from_user(&buf, ubuf, min_t(size_t, sizeof(buf) - 1, count)))
1027 return -EFAULT;
1028
1029 if (!strncmp(buf, "enable", 6)) {
1030 /* Do not vote here. Let hsic driver decide when to vote */
1031 debug_bus_voting_enabled = true;
1032 } else {
1033 debug_bus_voting_enabled = false;
1034 if (mehci->bus_perf_client) {
1035 ret = msm_bus_scale_client_update_request(
1036 mehci->bus_perf_client, 0);
1037 if (ret)
1038 dev_err(mehci->dev, "%s: Failed to devote "
1039 "for bus bw %d\n", __func__, ret);
1040 }
1041 }
1042
1043 return count;
1044}
1045
1046const struct file_operations ehci_hsic_msm_bus_fops = {
1047 .open = ehci_hsic_msm_bus_open,
1048 .read = seq_read,
1049 .write = ehci_hsic_msm_bus_write,
1050 .llseek = seq_lseek,
1051 .release = single_release,
1052};
1053
Hemant Kumar6fd65032012-05-23 13:02:24 -07001054static int ehci_hsic_msm_wakeup_cnt_show(struct seq_file *s, void *unused)
1055{
1056 struct msm_hsic_hcd *mehci = s->private;
1057
1058 seq_printf(s, "%u\n", mehci->wakeup_int_cnt);
1059
1060 return 0;
1061}
1062
1063static int ehci_hsic_msm_wakeup_cnt_open(struct inode *inode, struct file *f)
1064{
1065 return single_open(f, ehci_hsic_msm_wakeup_cnt_show, inode->i_private);
1066}
1067
1068const struct file_operations ehci_hsic_msm_wakeup_cnt_fops = {
1069 .open = ehci_hsic_msm_wakeup_cnt_open,
1070 .read = seq_read,
1071 .llseek = seq_lseek,
1072 .release = single_release,
1073};
1074
Hemant Kumar45d211b2012-05-31 17:58:43 -07001075static int ehci_hsic_msm_data_events_show(struct seq_file *s, void *unused)
1076{
1077 unsigned long flags;
1078 unsigned i;
1079
1080 read_lock_irqsave(&dbg_hsic_data.lck, flags);
1081
1082 i = dbg_hsic_data.idx;
1083 for (dbg_inc(&i); i != dbg_hsic_data.idx; dbg_inc(&i)) {
1084 if (!strnlen(dbg_hsic_data.buf[i], DBG_MSG_LEN))
1085 continue;
1086 seq_printf(s, "%s\n", dbg_hsic_data.buf[i]);
1087 }
1088
1089 read_unlock_irqrestore(&dbg_hsic_data.lck, flags);
1090
1091 return 0;
1092}
1093
1094static int ehci_hsic_msm_data_events_open(struct inode *inode, struct file *f)
1095{
1096 return single_open(f, ehci_hsic_msm_data_events_show, inode->i_private);
1097}
1098
1099const struct file_operations ehci_hsic_msm_dbg_data_fops = {
1100 .open = ehci_hsic_msm_data_events_open,
1101 .read = seq_read,
1102 .llseek = seq_lseek,
1103 .release = single_release,
1104};
1105
1106static int ehci_hsic_msm_ctrl_events_show(struct seq_file *s, void *unused)
1107{
1108 unsigned long flags;
1109 unsigned i;
1110
1111 read_lock_irqsave(&dbg_hsic_ctrl.lck, flags);
1112
1113 i = dbg_hsic_ctrl.idx;
1114 for (dbg_inc(&i); i != dbg_hsic_ctrl.idx; dbg_inc(&i)) {
1115 if (!strnlen(dbg_hsic_ctrl.buf[i], DBG_MSG_LEN))
1116 continue;
1117 seq_printf(s, "%s\n", dbg_hsic_ctrl.buf[i]);
1118 }
1119
1120 read_unlock_irqrestore(&dbg_hsic_ctrl.lck, flags);
1121
1122 return 0;
1123}
1124
1125static int ehci_hsic_msm_ctrl_events_open(struct inode *inode, struct file *f)
1126{
1127 return single_open(f, ehci_hsic_msm_ctrl_events_show, inode->i_private);
1128}
1129
1130const struct file_operations ehci_hsic_msm_dbg_ctrl_fops = {
1131 .open = ehci_hsic_msm_ctrl_events_open,
1132 .read = seq_read,
1133 .llseek = seq_lseek,
1134 .release = single_release,
1135};
1136
Hemant Kumare6275972012-02-29 20:06:21 -08001137static struct dentry *ehci_hsic_msm_dbg_root;
1138static int ehci_hsic_msm_debugfs_init(struct msm_hsic_hcd *mehci)
1139{
1140 struct dentry *ehci_hsic_msm_dentry;
1141
1142 ehci_hsic_msm_dbg_root = debugfs_create_dir("ehci_hsic_msm_dbg", NULL);
1143
1144 if (!ehci_hsic_msm_dbg_root || IS_ERR(ehci_hsic_msm_dbg_root))
1145 return -ENODEV;
1146
1147 ehci_hsic_msm_dentry = debugfs_create_file("bus_voting",
1148 S_IRUGO | S_IWUSR,
1149 ehci_hsic_msm_dbg_root, mehci,
1150 &ehci_hsic_msm_bus_fops);
1151
1152 if (!ehci_hsic_msm_dentry) {
1153 debugfs_remove_recursive(ehci_hsic_msm_dbg_root);
1154 return -ENODEV;
1155 }
1156
Hemant Kumar6fd65032012-05-23 13:02:24 -07001157 ehci_hsic_msm_dentry = debugfs_create_file("wakeup_cnt",
1158 S_IRUGO,
1159 ehci_hsic_msm_dbg_root, mehci,
1160 &ehci_hsic_msm_wakeup_cnt_fops);
1161
1162 if (!ehci_hsic_msm_dentry) {
1163 debugfs_remove_recursive(ehci_hsic_msm_dbg_root);
1164 return -ENODEV;
1165 }
1166
Hemant Kumar45d211b2012-05-31 17:58:43 -07001167 ehci_hsic_msm_dentry = debugfs_create_file("show_ctrl_events",
1168 S_IRUGO,
1169 ehci_hsic_msm_dbg_root, mehci,
1170 &ehci_hsic_msm_dbg_ctrl_fops);
1171
1172 if (!ehci_hsic_msm_dentry) {
1173 debugfs_remove_recursive(ehci_hsic_msm_dbg_root);
1174 return -ENODEV;
1175 }
1176
1177 ehci_hsic_msm_dentry = debugfs_create_file("show_data_events",
1178 S_IRUGO,
1179 ehci_hsic_msm_dbg_root, mehci,
1180 &ehci_hsic_msm_dbg_data_fops);
1181
1182 if (!ehci_hsic_msm_dentry) {
1183 debugfs_remove_recursive(ehci_hsic_msm_dbg_root);
1184 return -ENODEV;
1185 }
1186
Hemant Kumare6275972012-02-29 20:06:21 -08001187 return 0;
1188}
1189
1190static void ehci_hsic_msm_debugfs_cleanup(void)
1191{
1192 debugfs_remove_recursive(ehci_hsic_msm_dbg_root);
1193}
1194
Vijayavardhan Vennapusa39025fe2011-10-15 05:55:10 +05301195static int __devinit ehci_hsic_msm_probe(struct platform_device *pdev)
1196{
1197 struct usb_hcd *hcd;
1198 struct resource *res;
1199 struct msm_hsic_hcd *mehci;
Vijayavardhan Vennapusa2b592824f2011-11-02 19:51:32 +05301200 struct msm_hsic_host_platform_data *pdata;
Vijayavardhan Vennapusa39025fe2011-10-15 05:55:10 +05301201 int ret;
1202
1203 dev_dbg(&pdev->dev, "ehci_msm-hsic probe\n");
1204
Vijayavardhan Vennapusaafbbb8f2012-04-13 16:28:45 +05301205 /* After parent device's probe is executed, it will be put in suspend
1206 * mode. When child device's probe is called, driver core is not
1207 * resuming parent device due to which parent will be in suspend even
1208 * though child is active. Hence resume the parent device explicitly.
1209 */
1210 if (pdev->dev.parent)
1211 pm_runtime_get_sync(pdev->dev.parent);
1212
Vijayavardhan Vennapusa39025fe2011-10-15 05:55:10 +05301213 hcd = usb_create_hcd(&msm_hsic_driver, &pdev->dev,
1214 dev_name(&pdev->dev));
1215 if (!hcd) {
1216 dev_err(&pdev->dev, "Unable to create HCD\n");
1217 return -ENOMEM;
1218 }
1219
1220 hcd->irq = platform_get_irq(pdev, 0);
1221 if (hcd->irq < 0) {
1222 dev_err(&pdev->dev, "Unable to get IRQ resource\n");
1223 ret = hcd->irq;
1224 goto put_hcd;
1225 }
1226
1227 res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
1228 if (!res) {
1229 dev_err(&pdev->dev, "Unable to get memory resource\n");
1230 ret = -ENODEV;
1231 goto put_hcd;
1232 }
1233
1234 hcd->rsrc_start = res->start;
1235 hcd->rsrc_len = resource_size(res);
1236 hcd->regs = ioremap(hcd->rsrc_start, hcd->rsrc_len);
1237 if (!hcd->regs) {
1238 dev_err(&pdev->dev, "ioremap failed\n");
1239 ret = -ENOMEM;
1240 goto put_hcd;
1241 }
1242
1243 mehci = hcd_to_hsic(hcd);
1244 mehci->dev = &pdev->dev;
1245
Hemant Kumar38ce5d82012-05-29 13:00:58 -07001246 mehci->ehci.susp_sof_bug = 1;
Vamsi Krishna8e6edcb2012-06-20 18:08:50 -07001247 mehci->ehci.reset_sof_bug = 1;
Hemant Kumar38ce5d82012-05-29 13:00:58 -07001248
Hemant Kumar933e0402012-05-22 11:11:40 -07001249 mehci->ehci.max_log2_irq_thresh = 6;
1250
Vamsi Krishna34f01582011-12-14 19:54:42 -08001251 res = platform_get_resource_byname(pdev,
1252 IORESOURCE_IRQ,
1253 "peripheral_status_irq");
1254 if (res)
1255 mehci->peripheral_status_irq = res->start;
1256
Hemant Kumar6fd65032012-05-23 13:02:24 -07001257 res = platform_get_resource_byname(pdev, IORESOURCE_IO, "wakeup");
1258 if (res) {
1259 mehci->wakeup_gpio = res->start;
1260 mehci->wakeup_irq = MSM_GPIO_TO_INT(res->start);
1261 dev_dbg(mehci->dev, "wakeup_irq: %d\n", mehci->wakeup_irq);
1262 }
1263
Vijayavardhan Vennapusa39025fe2011-10-15 05:55:10 +05301264 ret = msm_hsic_init_clocks(mehci, 1);
1265 if (ret) {
1266 dev_err(&pdev->dev, "unable to initialize clocks\n");
1267 ret = -ENODEV;
1268 goto unmap;
1269 }
1270
1271 ret = msm_hsic_init_vddcx(mehci, 1);
1272 if (ret) {
1273 dev_err(&pdev->dev, "unable to initialize VDDCX\n");
1274 ret = -ENODEV;
1275 goto deinit_clocks;
1276 }
1277
1278 ret = msm_hsic_reset(mehci);
1279 if (ret) {
1280 dev_err(&pdev->dev, "unable to initialize PHY\n");
Vijayavardhan Vennapusaafbbb8f2012-04-13 16:28:45 +05301281 goto deinit_vddcx;
Vijayavardhan Vennapusa39025fe2011-10-15 05:55:10 +05301282 }
1283
1284 ret = usb_add_hcd(hcd, hcd->irq, IRQF_SHARED);
1285 if (ret) {
1286 dev_err(&pdev->dev, "unable to register HCD\n");
Vijayavardhan Vennapusae3316a12011-10-15 06:05:17 +05301287 goto unconfig_gpio;
Vijayavardhan Vennapusa39025fe2011-10-15 05:55:10 +05301288 }
1289
1290 device_init_wakeup(&pdev->dev, 1);
1291 wake_lock_init(&mehci->wlock, WAKE_LOCK_SUSPEND, dev_name(&pdev->dev));
1292 wake_lock(&mehci->wlock);
Vamsi Krishna34f01582011-12-14 19:54:42 -08001293
1294 if (mehci->peripheral_status_irq) {
1295 ret = request_threaded_irq(mehci->peripheral_status_irq,
1296 NULL, hsic_peripheral_status_change,
1297 IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING
1298 | IRQF_SHARED,
1299 "hsic_peripheral_status", mehci);
1300 if (ret)
1301 dev_err(&pdev->dev, "%s:request_irq:%d failed:%d",
1302 __func__, mehci->peripheral_status_irq, ret);
1303 }
1304
Vamsi Krishna6921cbe2012-02-21 18:34:43 -08001305 /* configure wakeup irq */
Hemant Kumar6fd65032012-05-23 13:02:24 -07001306 if (mehci->wakeup_irq) {
Vamsi Krishna6921cbe2012-02-21 18:34:43 -08001307 ret = request_irq(mehci->wakeup_irq, msm_hsic_wakeup_irq,
Hemant Kumar6fd65032012-05-23 13:02:24 -07001308 IRQF_TRIGGER_HIGH,
Vamsi Krishna6921cbe2012-02-21 18:34:43 -08001309 "msm_hsic_wakeup", mehci);
1310 if (!ret) {
1311 disable_irq_nosync(mehci->wakeup_irq);
Vamsi Krishna6921cbe2012-02-21 18:34:43 -08001312 } else {
1313 dev_err(&pdev->dev, "request_irq(%d) failed: %d\n",
1314 mehci->wakeup_irq, ret);
1315 mehci->wakeup_irq = 0;
1316 }
1317 }
1318
Hemant Kumare6275972012-02-29 20:06:21 -08001319 ret = ehci_hsic_msm_debugfs_init(mehci);
1320 if (ret)
1321 dev_dbg(&pdev->dev, "mode debugfs file is"
1322 "not available\n");
1323
Vijayavardhan Vennapusaafbbb8f2012-04-13 16:28:45 +05301324 pdata = mehci->dev->platform_data;
Hemant Kumare6275972012-02-29 20:06:21 -08001325 if (pdata && pdata->bus_scale_table) {
1326 mehci->bus_perf_client =
1327 msm_bus_scale_register_client(pdata->bus_scale_table);
1328 /* Configure BUS performance parameters for MAX bandwidth */
1329 if (mehci->bus_perf_client) {
1330 ret = msm_bus_scale_client_update_request(
1331 mehci->bus_perf_client, 1);
1332 if (ret)
1333 dev_err(&pdev->dev, "%s: Failed to vote for "
1334 "bus bandwidth %d\n", __func__, ret);
1335 } else {
1336 dev_err(&pdev->dev, "%s: Failed to register BUS "
1337 "scaling client!!\n", __func__);
1338 }
1339 }
1340
Vijayavardhan Vennapusa39025fe2011-10-15 05:55:10 +05301341 /*
1342 * This pdev->dev is assigned parent of root-hub by USB core,
1343 * hence, runtime framework automatically calls this driver's
1344 * runtime APIs based on root-hub's state.
1345 */
1346 pm_runtime_set_active(&pdev->dev);
1347 pm_runtime_enable(&pdev->dev);
Vijayavardhan Vennapusaafbbb8f2012-04-13 16:28:45 +05301348 /* Decrement the parent device's counter after probe.
1349 * As child is active, parent will not be put into
1350 * suspend mode.
1351 */
1352 if (pdev->dev.parent)
1353 pm_runtime_put_sync(pdev->dev.parent);
Vijayavardhan Vennapusa39025fe2011-10-15 05:55:10 +05301354
1355 return 0;
1356
Vijayavardhan Vennapusae3316a12011-10-15 06:05:17 +05301357unconfig_gpio:
1358 msm_hsic_config_gpios(mehci, 0);
Vijayavardhan Vennapusa39025fe2011-10-15 05:55:10 +05301359deinit_vddcx:
1360 msm_hsic_init_vddcx(mehci, 0);
1361deinit_clocks:
1362 msm_hsic_init_clocks(mehci, 0);
1363unmap:
1364 iounmap(hcd->regs);
1365put_hcd:
1366 usb_put_hcd(hcd);
1367
1368 return ret;
1369}
1370
1371static int __devexit ehci_hsic_msm_remove(struct platform_device *pdev)
1372{
1373 struct usb_hcd *hcd = platform_get_drvdata(pdev);
1374 struct msm_hsic_hcd *mehci = hcd_to_hsic(hcd);
1375
Vamsi Krishna34f01582011-12-14 19:54:42 -08001376 if (mehci->peripheral_status_irq)
1377 free_irq(mehci->peripheral_status_irq, mehci);
Jack Phamfe441ea2012-03-23 17:03:15 -07001378
Vamsi Krishna6921cbe2012-02-21 18:34:43 -08001379 if (mehci->wakeup_irq) {
Jack Phamfe441ea2012-03-23 17:03:15 -07001380 if (mehci->wakeup_irq_enabled)
1381 disable_irq_wake(mehci->wakeup_irq);
Vamsi Krishna6921cbe2012-02-21 18:34:43 -08001382 free_irq(mehci->wakeup_irq, mehci);
1383 }
Vamsi Krishna34f01582011-12-14 19:54:42 -08001384
Hemant Kumare6275972012-02-29 20:06:21 -08001385 if (mehci->bus_perf_client)
1386 msm_bus_scale_unregister_client(mehci->bus_perf_client);
1387
1388 ehci_hsic_msm_debugfs_cleanup();
Vijayavardhan Vennapusa39025fe2011-10-15 05:55:10 +05301389 device_init_wakeup(&pdev->dev, 0);
Vijayavardhan Vennapusa39025fe2011-10-15 05:55:10 +05301390 pm_runtime_set_suspended(&pdev->dev);
1391
1392 usb_remove_hcd(hcd);
Vijayavardhan Vennapusae3316a12011-10-15 06:05:17 +05301393 msm_hsic_config_gpios(mehci, 0);
Vijayavardhan Vennapusa39025fe2011-10-15 05:55:10 +05301394 msm_hsic_init_vddcx(mehci, 0);
1395
1396 msm_hsic_init_clocks(mehci, 0);
1397 wake_lock_destroy(&mehci->wlock);
1398 iounmap(hcd->regs);
1399 usb_put_hcd(hcd);
1400
1401 return 0;
1402}
1403
1404#ifdef CONFIG_PM_SLEEP
1405static int msm_hsic_pm_suspend(struct device *dev)
1406{
Jack Phambe05fbb2012-05-16 10:56:26 -07001407 int ret;
Vijayavardhan Vennapusa39025fe2011-10-15 05:55:10 +05301408 struct usb_hcd *hcd = dev_get_drvdata(dev);
1409 struct msm_hsic_hcd *mehci = hcd_to_hsic(hcd);
1410
1411 dev_dbg(dev, "ehci-msm-hsic PM suspend\n");
1412
Hemant Kumar45d211b2012-05-31 17:58:43 -07001413 dbg_log_event(NULL, "PM Suspend", 0);
1414
Vijayavardhan Vennapusa39025fe2011-10-15 05:55:10 +05301415 if (device_may_wakeup(dev))
1416 enable_irq_wake(hcd->irq);
1417
Jack Phambe05fbb2012-05-16 10:56:26 -07001418 ret = msm_hsic_suspend(mehci);
1419
1420 if (ret && device_may_wakeup(dev))
1421 disable_irq_wake(hcd->irq);
1422
1423 return ret;
Jack Phamfe441ea2012-03-23 17:03:15 -07001424}
Vijayavardhan Vennapusa39025fe2011-10-15 05:55:10 +05301425
Vijayavardhan Vennapusa39025fe2011-10-15 05:55:10 +05301426static int msm_hsic_pm_resume(struct device *dev)
1427{
1428 int ret;
1429 struct usb_hcd *hcd = dev_get_drvdata(dev);
1430 struct msm_hsic_hcd *mehci = hcd_to_hsic(hcd);
1431
Hemant Kumar45d211b2012-05-31 17:58:43 -07001432 dbg_log_event(NULL, "PM Resume", 0);
1433
Vijayavardhan Vennapusa39025fe2011-10-15 05:55:10 +05301434 if (device_may_wakeup(dev))
1435 disable_irq_wake(hcd->irq);
1436
1437 ret = msm_hsic_resume(mehci);
1438 if (ret)
1439 return ret;
1440
1441 /* Bring the device to full powered state upon system resume */
1442 pm_runtime_disable(dev);
1443 pm_runtime_set_active(dev);
1444 pm_runtime_enable(dev);
1445
1446 return 0;
1447}
1448#endif
1449
1450#ifdef CONFIG_PM_RUNTIME
1451static int msm_hsic_runtime_idle(struct device *dev)
1452{
1453 dev_dbg(dev, "EHCI runtime idle\n");
Vijayavardhan Vennapusa39025fe2011-10-15 05:55:10 +05301454 return 0;
1455}
1456
1457static int msm_hsic_runtime_suspend(struct device *dev)
1458{
1459 struct usb_hcd *hcd = dev_get_drvdata(dev);
1460 struct msm_hsic_hcd *mehci = hcd_to_hsic(hcd);
1461
1462 dev_dbg(dev, "EHCI runtime suspend\n");
Hemant Kumar45d211b2012-05-31 17:58:43 -07001463
1464 dbg_log_event(NULL, "Run Time PM Suspend", 0);
1465
Vijayavardhan Vennapusa39025fe2011-10-15 05:55:10 +05301466 return msm_hsic_suspend(mehci);
1467}
1468
1469static int msm_hsic_runtime_resume(struct device *dev)
1470{
1471 struct usb_hcd *hcd = dev_get_drvdata(dev);
1472 struct msm_hsic_hcd *mehci = hcd_to_hsic(hcd);
1473
1474 dev_dbg(dev, "EHCI runtime resume\n");
Hemant Kumar45d211b2012-05-31 17:58:43 -07001475
1476 dbg_log_event(NULL, "Run Time PM Resume", 0);
1477
Vijayavardhan Vennapusa39025fe2011-10-15 05:55:10 +05301478 return msm_hsic_resume(mehci);
1479}
1480#endif
1481
1482#ifdef CONFIG_PM
1483static const struct dev_pm_ops msm_hsic_dev_pm_ops = {
1484 SET_SYSTEM_SLEEP_PM_OPS(msm_hsic_pm_suspend, msm_hsic_pm_resume)
Vijayavardhan Vennapusa39025fe2011-10-15 05:55:10 +05301485 SET_RUNTIME_PM_OPS(msm_hsic_runtime_suspend, msm_hsic_runtime_resume,
1486 msm_hsic_runtime_idle)
1487};
1488#endif
1489
1490static struct platform_driver ehci_msm_hsic_driver = {
1491 .probe = ehci_hsic_msm_probe,
1492 .remove = __devexit_p(ehci_hsic_msm_remove),
1493 .driver = {
1494 .name = "msm_hsic_host",
1495#ifdef CONFIG_PM
1496 .pm = &msm_hsic_dev_pm_ops,
1497#endif
1498 },
1499};