blob: 1e52d79ba94ee552944079add502c0beb09b0732 [file] [log] [blame]
Vijayavardhan Vennapusa39025fe2011-10-15 05:55:10 +05301/* ehci-msm-hsic.c - HSUSB Host Controller Driver Implementation
2 *
Pavankumar Kondetibbd05822013-01-28 17:04:39 +05303 * Copyright (c) 2011-2013, Linux Foundation. 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>
Ajay Dudaniab3bf192012-08-28 09:58:04 -070030#include <linux/wakelock.h>
Vijayavardhan Vennapusa39025fe2011-10-15 05:55:10 +053031#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>
Ajay Dudani11ab1d52012-08-17 17:12:26 -070038#include <linux/kthread.h>
39#include <linux/wait.h>
Pavankumar Kondetife2d4d32012-09-07 15:33:09 +053040#include <linux/pm_qos.h>
Hemant Kumar5e386632012-08-30 14:23:38 -070041#include <linux/irq.h>
Amit Blayd6ea6102012-06-07 16:26:24 +030042
43#include <mach/msm_bus.h>
Vijayavardhan Vennapusa39025fe2011-10-15 05:55:10 +053044#include <mach/clk.h>
45#include <mach/msm_iomap.h>
Vijayavardhan Vennapusa2b592824f2011-11-02 19:51:32 +053046#include <mach/msm_xo.h>
Vamsi Krishna34f01582011-12-14 19:54:42 -080047#include <linux/spinlock.h>
Hemant Kumar45d211b2012-05-31 17:58:43 -070048#include <linux/cpu.h>
Amit Blayd6ea6102012-06-07 16:26:24 +030049#include <mach/rpm-regulator.h>
Vijayavardhan Vennapusa39025fe2011-10-15 05:55:10 +053050
51#define MSM_USB_BASE (hcd->regs)
Hemant Kumar105d07f2012-07-02 15:33:07 -070052#define USB_REG_START_OFFSET 0x90
53#define USB_REG_END_OFFSET 0x250
Vijayavardhan Vennapusa39025fe2011-10-15 05:55:10 +053054
Hemant Kumar2309eaa2012-08-14 16:46:42 -070055static struct workqueue_struct *ehci_wq;
Ajay Dudani11ab1d52012-08-17 17:12:26 -070056struct ehci_timer {
57#define GPT_LD(p) ((p) & 0x00FFFFFF)
58 u32 gptimer0_ld;
59#define GPT_RUN BIT(31)
60#define GPT_RESET BIT(30)
61#define GPT_MODE BIT(24)
62#define GPT_CNT(p) ((p) & 0x00FFFFFF)
63 u32 gptimer0_ctrl;
64
65 u32 gptimer1_ld;
66 u32 gptimer1_ctrl;
67};
Hemant Kumar2309eaa2012-08-14 16:46:42 -070068
Vijayavardhan Vennapusa39025fe2011-10-15 05:55:10 +053069struct msm_hsic_hcd {
70 struct ehci_hcd ehci;
Hemant Kumar4cd49e12012-09-06 19:57:14 -070071 spinlock_t wakeup_lock;
Vijayavardhan Vennapusa39025fe2011-10-15 05:55:10 +053072 struct device *dev;
73 struct clk *ahb_clk;
Manu Gautam5143b252012-01-05 19:25:23 -080074 struct clk *core_clk;
75 struct clk *alt_core_clk;
76 struct clk *phy_clk;
Vijayavardhan Vennapusa39025fe2011-10-15 05:55:10 +053077 struct clk *cal_clk;
78 struct regulator *hsic_vddcx;
Pavankumar Kondetibbd05822013-01-28 17:04:39 +053079 atomic_t async_int;
Vijayavardhan Vennapusa39025fe2011-10-15 05:55:10 +053080 atomic_t in_lpm;
Ajay Dudaniab3bf192012-08-28 09:58:04 -070081 struct wake_lock wlock;
Vamsi Krishna34f01582011-12-14 19:54:42 -080082 int peripheral_status_irq;
Vamsi Krishna6921cbe2012-02-21 18:34:43 -080083 int wakeup_irq;
Hemant Kumar6fd65032012-05-23 13:02:24 -070084 int wakeup_gpio;
Jack Phamfe441ea2012-03-23 17:03:15 -070085 bool wakeup_irq_enabled;
Ajay Dudaniab3bf192012-08-28 09:58:04 -070086 atomic_t pm_usage_cnt;
Hemant Kumare6275972012-02-29 20:06:21 -080087 uint32_t bus_perf_client;
Hemant Kumar6fd65032012-05-23 13:02:24 -070088 uint32_t wakeup_int_cnt;
Amit Blayd6ea6102012-06-07 16:26:24 +030089 enum usb_vdd_type vdd_type;
Hemant Kumar2309eaa2012-08-14 16:46:42 -070090
91 struct work_struct bus_vote_w;
92 bool bus_vote;
Ajay Dudani11ab1d52012-08-17 17:12:26 -070093
94 /* gp timer */
95 struct ehci_timer __iomem *timer;
96 struct completion gpt0_completion;
97 struct completion rt_completion;
98 int resume_status;
99 int resume_again;
Pavankumar Kondetife2d4d32012-09-07 15:33:09 +0530100
101 struct pm_qos_request pm_qos_req_dma;
Vijayavardhan Vennapusa39025fe2011-10-15 05:55:10 +0530102};
103
Hemant Kumar105d07f2012-07-02 15:33:07 -0700104struct msm_hsic_hcd *__mehci;
105
Hemant Kumare6275972012-02-29 20:06:21 -0800106static bool debug_bus_voting_enabled = true;
Hemant Kumar45d211b2012-05-31 17:58:43 -0700107
Hemant Kumardf2d84d2012-08-15 09:06:35 -0700108static unsigned int enable_payload_log = 1;
109module_param(enable_payload_log, uint, S_IRUGO | S_IWUSR);
Hemant Kumar45d211b2012-05-31 17:58:43 -0700110static unsigned int enable_dbg_log = 1;
111module_param(enable_dbg_log, uint, S_IRUGO | S_IWUSR);
112/*by default log ep0 and efs sync ep*/
113static unsigned int ep_addr_rxdbg_mask = 9;
114module_param(ep_addr_rxdbg_mask, uint, S_IRUGO | S_IWUSR);
115static unsigned int ep_addr_txdbg_mask = 9;
116module_param(ep_addr_txdbg_mask, uint, S_IRUGO | S_IWUSR);
117
118/* Maximum debug message length */
Hemant Kumardf2d84d2012-08-15 09:06:35 -0700119#define DBG_MSG_LEN 128UL
Hemant Kumar45d211b2012-05-31 17:58:43 -0700120
121/* Maximum number of messages */
122#define DBG_MAX_MSG 256UL
123
124#define TIME_BUF_LEN 20
Hemant Kumardf2d84d2012-08-15 09:06:35 -0700125#define HEX_DUMP_LEN 72
Hemant Kumar45d211b2012-05-31 17:58:43 -0700126
127enum event_type {
128 EVENT_UNDEF = -1,
129 URB_SUBMIT,
130 URB_COMPLETE,
131 EVENT_NONE,
132};
133
134#define EVENT_STR_LEN 5
135
Hemant Kumar45d211b2012-05-31 17:58:43 -0700136static enum event_type str_to_event(const char *name)
137{
138 if (!strncasecmp("S", name, EVENT_STR_LEN))
139 return URB_SUBMIT;
140 if (!strncasecmp("C", name, EVENT_STR_LEN))
141 return URB_COMPLETE;
142 if (!strncasecmp("", name, EVENT_STR_LEN))
143 return EVENT_NONE;
144
145 return EVENT_UNDEF;
146}
147
148/*log ep0 activity*/
149static struct {
150 char (buf[DBG_MAX_MSG])[DBG_MSG_LEN]; /* buffer */
151 unsigned idx; /* index */
152 rwlock_t lck; /* lock */
153} dbg_hsic_ctrl = {
154 .idx = 0,
155 .lck = __RW_LOCK_UNLOCKED(lck)
156};
157
158static struct {
159 char (buf[DBG_MAX_MSG])[DBG_MSG_LEN]; /* buffer */
160 unsigned idx; /* index */
161 rwlock_t lck; /* lock */
162} dbg_hsic_data = {
163 .idx = 0,
164 .lck = __RW_LOCK_UNLOCKED(lck)
165};
166
167/**
168 * dbg_inc: increments debug event index
169 * @idx: buffer index
170 */
171static void dbg_inc(unsigned *idx)
172{
173 *idx = (*idx + 1) & (DBG_MAX_MSG-1);
174}
175
176/*get_timestamp - returns time of day in us */
177static char *get_timestamp(char *tbuf)
178{
179 unsigned long long t;
180 unsigned long nanosec_rem;
181
182 t = cpu_clock(smp_processor_id());
183 nanosec_rem = do_div(t, 1000000000)/1000;
184 scnprintf(tbuf, TIME_BUF_LEN, "[%5lu.%06lu] ", (unsigned long)t,
185 nanosec_rem);
186 return tbuf;
187}
188
189static int allow_dbg_log(int ep_addr)
190{
191 int dir, num;
192
193 dir = ep_addr & USB_DIR_IN ? USB_DIR_IN : USB_DIR_OUT;
194 num = ep_addr & ~USB_DIR_IN;
195 num = 1 << num;
196
197 if ((dir == USB_DIR_IN) && (num & ep_addr_rxdbg_mask))
198 return 1;
199 if ((dir == USB_DIR_OUT) && (num & ep_addr_txdbg_mask))
200 return 1;
201
202 return 0;
203}
204
Hemant Kumardf2d84d2012-08-15 09:06:35 -0700205static char *get_hex_data(char *dbuf, struct urb *urb, int event, int status)
206{
207 int ep_addr = urb->ep->desc.bEndpointAddress;
208 char *ubuf = urb->transfer_buffer;
209 size_t len = event ? \
210 urb->actual_length : urb->transfer_buffer_length;
211
212 if (status == -EINPROGRESS)
213 status = 0;
214
215 /*Only dump ep in completions and epout submissions*/
216 if (len && !status &&
217 (((ep_addr & USB_DIR_IN) && event) ||
218 (!(ep_addr & USB_DIR_IN) && !event))) {
219 if (len >= 32)
220 len = 32;
221 hex_dump_to_buffer(ubuf, len, 32, 4, dbuf, HEX_DUMP_LEN, 0);
222 } else {
223 dbuf = "";
224 }
225
226 return dbuf;
227}
228
Hemant Kumar45d211b2012-05-31 17:58:43 -0700229static void dbg_log_event(struct urb *urb, char * event, unsigned extra)
230{
231 unsigned long flags;
232 int ep_addr;
233 char tbuf[TIME_BUF_LEN];
Hemant Kumardf2d84d2012-08-15 09:06:35 -0700234 char dbuf[HEX_DUMP_LEN];
Hemant Kumar45d211b2012-05-31 17:58:43 -0700235
236 if (!enable_dbg_log)
237 return;
238
239 if (!urb) {
240 write_lock_irqsave(&dbg_hsic_ctrl.lck, flags);
241 scnprintf(dbg_hsic_ctrl.buf[dbg_hsic_ctrl.idx], DBG_MSG_LEN,
Hemant Kumardf2d84d2012-08-15 09:06:35 -0700242 "%s: %s : %u", get_timestamp(tbuf), event, extra);
Hemant Kumar45d211b2012-05-31 17:58:43 -0700243 dbg_inc(&dbg_hsic_ctrl.idx);
244 write_unlock_irqrestore(&dbg_hsic_ctrl.lck, flags);
245 return;
246 }
247
248 ep_addr = urb->ep->desc.bEndpointAddress;
249 if (!allow_dbg_log(ep_addr))
250 return;
251
252 if ((ep_addr & 0x0f) == 0x0) {
253 /*submit event*/
254 if (!str_to_event(event)) {
255 write_lock_irqsave(&dbg_hsic_ctrl.lck, flags);
256 scnprintf(dbg_hsic_ctrl.buf[dbg_hsic_ctrl.idx],
257 DBG_MSG_LEN, "%s: [%s : %p]:[%s] "
Hemant Kumardf2d84d2012-08-15 09:06:35 -0700258 "%02x %02x %04x %04x %04x %u %d",
Hemant Kumar45d211b2012-05-31 17:58:43 -0700259 get_timestamp(tbuf), event, urb,
260 (ep_addr & USB_DIR_IN) ? "in" : "out",
261 urb->setup_packet[0], urb->setup_packet[1],
262 (urb->setup_packet[3] << 8) |
263 urb->setup_packet[2],
264 (urb->setup_packet[5] << 8) |
265 urb->setup_packet[4],
266 (urb->setup_packet[7] << 8) |
267 urb->setup_packet[6],
Hemant Kumardf2d84d2012-08-15 09:06:35 -0700268 urb->transfer_buffer_length, extra);
Hemant Kumar45d211b2012-05-31 17:58:43 -0700269
270 dbg_inc(&dbg_hsic_ctrl.idx);
271 write_unlock_irqrestore(&dbg_hsic_ctrl.lck, flags);
272 } else {
273 write_lock_irqsave(&dbg_hsic_ctrl.lck, flags);
274 scnprintf(dbg_hsic_ctrl.buf[dbg_hsic_ctrl.idx],
Hemant Kumardf2d84d2012-08-15 09:06:35 -0700275 DBG_MSG_LEN, "%s: [%s : %p]:[%s] %u %d",
Hemant Kumar45d211b2012-05-31 17:58:43 -0700276 get_timestamp(tbuf), event, urb,
277 (ep_addr & USB_DIR_IN) ? "in" : "out",
278 urb->actual_length, extra);
279
280 dbg_inc(&dbg_hsic_ctrl.idx);
281 write_unlock_irqrestore(&dbg_hsic_ctrl.lck, flags);
282 }
283 } else {
284 write_lock_irqsave(&dbg_hsic_data.lck, flags);
285 scnprintf(dbg_hsic_data.buf[dbg_hsic_data.idx], DBG_MSG_LEN,
Hemant Kumardf2d84d2012-08-15 09:06:35 -0700286 "%s: [%s : %p]:ep%d[%s] %u %d %s",
Hemant Kumar45d211b2012-05-31 17:58:43 -0700287 get_timestamp(tbuf), event, urb, ep_addr & 0x0f,
288 (ep_addr & USB_DIR_IN) ? "in" : "out",
289 str_to_event(event) ? urb->actual_length :
Hemant Kumardf2d84d2012-08-15 09:06:35 -0700290 urb->transfer_buffer_length, extra,
291 enable_payload_log ? get_hex_data(dbuf, urb,
292 str_to_event(event), extra) : "");
Hemant Kumar45d211b2012-05-31 17:58:43 -0700293
294 dbg_inc(&dbg_hsic_data.idx);
295 write_unlock_irqrestore(&dbg_hsic_data.lck, flags);
296 }
297}
298
Vijayavardhan Vennapusa39025fe2011-10-15 05:55:10 +0530299static inline struct msm_hsic_hcd *hcd_to_hsic(struct usb_hcd *hcd)
300{
301 return (struct msm_hsic_hcd *) (hcd->hcd_priv);
302}
303
304static inline struct usb_hcd *hsic_to_hcd(struct msm_hsic_hcd *mehci)
305{
306 return container_of((void *) mehci, struct usb_hcd, hcd_priv);
307}
308
Hemant Kumar105d07f2012-07-02 15:33:07 -0700309static void dump_hsic_regs(struct usb_hcd *hcd)
310{
311 int i;
312 struct msm_hsic_hcd *mehci = hcd_to_hsic(hcd);
313
314 if (atomic_read(&mehci->in_lpm))
315 return;
316
317 for (i = USB_REG_START_OFFSET; i <= USB_REG_END_OFFSET; i += 0x10)
318 pr_info("%p: %08x\t%08x\t%08x\t%08x\n", hcd->regs + i,
319 readl_relaxed(hcd->regs + i),
320 readl_relaxed(hcd->regs + i + 4),
321 readl_relaxed(hcd->regs + i + 8),
322 readl_relaxed(hcd->regs + i + 0xc));
323}
324
Vijayavardhan Vennapusa39025fe2011-10-15 05:55:10 +0530325#define ULPI_IO_TIMEOUT_USEC (10 * 1000)
326
Amit Blayd6ea6102012-06-07 16:26:24 +0300327#define USB_PHY_VDD_DIG_VOL_NONE 0 /*uV */
Hemant Kumar266d9d52012-10-17 13:48:10 -0700328#define USB_PHY_VDD_DIG_VOL_MIN 945000 /* uV */
Vamsi Krishna45d88fa2011-11-02 13:28:42 -0700329#define USB_PHY_VDD_DIG_VOL_MAX 1320000 /* uV */
Vijayavardhan Vennapusa39025fe2011-10-15 05:55:10 +0530330
Lena Salman8c8ba382012-02-14 15:59:31 +0200331#define HSIC_DBG1_REG 0x38
332
Amit Blayd6ea6102012-06-07 16:26:24 +0300333static const int vdd_val[VDD_TYPE_MAX][VDD_VAL_MAX] = {
334 { /* VDD_CX CORNER Voting */
335 [VDD_NONE] = RPM_VREG_CORNER_NONE,
336 [VDD_MIN] = RPM_VREG_CORNER_NOMINAL,
337 [VDD_MAX] = RPM_VREG_CORNER_HIGH,
338 },
339 { /* VDD_CX Voltage Voting */
340 [VDD_NONE] = USB_PHY_VDD_DIG_VOL_NONE,
341 [VDD_MIN] = USB_PHY_VDD_DIG_VOL_MIN,
342 [VDD_MAX] = USB_PHY_VDD_DIG_VOL_MAX,
343 },
344};
345
Vijayavardhan Vennapusa39025fe2011-10-15 05:55:10 +0530346static int msm_hsic_init_vddcx(struct msm_hsic_hcd *mehci, int init)
347{
348 int ret = 0;
Amit Blayd6ea6102012-06-07 16:26:24 +0300349 int none_vol, min_vol, max_vol;
350
351 if (!mehci->hsic_vddcx) {
352 mehci->vdd_type = VDDCX_CORNER;
353 mehci->hsic_vddcx = devm_regulator_get(mehci->dev,
354 "hsic_vdd_dig");
355 if (IS_ERR(mehci->hsic_vddcx)) {
356 mehci->hsic_vddcx = devm_regulator_get(mehci->dev,
357 "HSIC_VDDCX");
358 if (IS_ERR(mehci->hsic_vddcx)) {
359 dev_err(mehci->dev, "unable to get hsic vddcx\n");
360 return PTR_ERR(mehci->hsic_vddcx);
361 }
362 mehci->vdd_type = VDDCX;
363 }
364 }
365
366 none_vol = vdd_val[mehci->vdd_type][VDD_NONE];
367 min_vol = vdd_val[mehci->vdd_type][VDD_MIN];
368 max_vol = vdd_val[mehci->vdd_type][VDD_MAX];
Vijayavardhan Vennapusa39025fe2011-10-15 05:55:10 +0530369
370 if (!init)
371 goto disable_reg;
372
Amit Blayd6ea6102012-06-07 16:26:24 +0300373 ret = regulator_set_voltage(mehci->hsic_vddcx, min_vol, max_vol);
Vijayavardhan Vennapusa39025fe2011-10-15 05:55:10 +0530374 if (ret) {
375 dev_err(mehci->dev, "unable to set the voltage"
376 "for hsic vddcx\n");
Mayank Rana189ac052012-03-24 04:35:02 +0530377 return ret;
Vijayavardhan Vennapusa39025fe2011-10-15 05:55:10 +0530378 }
379
Vijayavardhan Vennapusa39025fe2011-10-15 05:55:10 +0530380 ret = regulator_enable(mehci->hsic_vddcx);
381 if (ret) {
382 dev_err(mehci->dev, "unable to enable hsic vddcx\n");
383 goto reg_enable_err;
384 }
385
386 return 0;
387
388disable_reg:
389 regulator_disable(mehci->hsic_vddcx);
390reg_enable_err:
Amit Blayd6ea6102012-06-07 16:26:24 +0300391 regulator_set_voltage(mehci->hsic_vddcx, none_vol, max_vol);
392
Vijayavardhan Vennapusa39025fe2011-10-15 05:55:10 +0530393 return ret;
394
395}
396
Vamsi Krishna8e6edcb2012-06-20 18:08:50 -0700397static int ulpi_read(struct msm_hsic_hcd *mehci, u32 reg)
398{
399 struct usb_hcd *hcd = hsic_to_hcd(mehci);
Devin Kim01e5a5b2012-08-30 02:52:45 -0700400 int cnt = 0;
Vamsi Krishna8e6edcb2012-06-20 18:08:50 -0700401
402 /* initiate read operation */
403 writel_relaxed(ULPI_RUN | ULPI_READ | ULPI_ADDR(reg),
404 USB_ULPI_VIEWPORT);
405
406 /* wait for completion */
Devin Kim01e5a5b2012-08-30 02:52:45 -0700407 while (cnt < ULPI_IO_TIMEOUT_USEC) {
408 if (!(readl_relaxed(USB_ULPI_VIEWPORT) & ULPI_RUN))
409 break;
Vamsi Krishna8e6edcb2012-06-20 18:08:50 -0700410 udelay(1);
Devin Kim01e5a5b2012-08-30 02:52:45 -0700411 cnt++;
412 }
413
414 if (cnt >= ULPI_IO_TIMEOUT_USEC) {
415 dev_err(mehci->dev, "ulpi_read: timeout ULPI_VIEWPORT: %08x\n",
416 readl_relaxed(USB_ULPI_VIEWPORT));
417 dev_err(mehci->dev, "PORTSC: %08x USBCMD: %08x FRINDEX: %08x\n",
418 readl_relaxed(USB_PORTSC),
419 readl_relaxed(USB_USBCMD),
420 readl_relaxed(USB_FRINDEX));
421
422 /*frame counter increments afte 125us*/
423 udelay(130);
424 dev_err(mehci->dev, "ulpi_read: FRINDEX: %08x\n",
425 readl_relaxed(USB_FRINDEX));
426 return -ETIMEDOUT;
Vamsi Krishna8e6edcb2012-06-20 18:08:50 -0700427 }
428
429 return ULPI_DATA_READ(readl_relaxed(USB_ULPI_VIEWPORT));
430}
431
Vijayavardhan Vennapusa39025fe2011-10-15 05:55:10 +0530432static int ulpi_write(struct msm_hsic_hcd *mehci, u32 val, u32 reg)
433{
434 struct usb_hcd *hcd = hsic_to_hcd(mehci);
435 int cnt = 0;
436
437 /* initiate write operation */
438 writel_relaxed(ULPI_RUN | ULPI_WRITE |
439 ULPI_ADDR(reg) | ULPI_DATA(val),
440 USB_ULPI_VIEWPORT);
441
442 /* wait for completion */
443 while (cnt < ULPI_IO_TIMEOUT_USEC) {
444 if (!(readl_relaxed(USB_ULPI_VIEWPORT) & ULPI_RUN))
445 break;
446 udelay(1);
447 cnt++;
448 }
449
450 if (cnt >= ULPI_IO_TIMEOUT_USEC) {
Devin Kim01e5a5b2012-08-30 02:52:45 -0700451 dev_err(mehci->dev, "ulpi_write: timeout ULPI_VIEWPORT: %08x\n",
452 readl_relaxed(USB_ULPI_VIEWPORT));
453 dev_err(mehci->dev, "PORTSC: %08x USBCMD: %08x FRINDEX: %08x\n",
454 readl_relaxed(USB_PORTSC),
455 readl_relaxed(USB_USBCMD),
456 readl_relaxed(USB_FRINDEX));
457
458 /*frame counter increments afte 125us*/
459 udelay(130);
460 dev_err(mehci->dev, "ulpi_write: FRINDEX: %08x\n",
461 readl_relaxed(USB_FRINDEX));
Vijayavardhan Vennapusa39025fe2011-10-15 05:55:10 +0530462 return -ETIMEDOUT;
463 }
464
465 return 0;
466}
467
Vamsi Krishna8e6edcb2012-06-20 18:08:50 -0700468#define HSIC_DBG1 0X38
469#define ULPI_MANUAL_ENABLE BIT(4)
470#define ULPI_LINESTATE_DATA BIT(5)
471#define ULPI_LINESTATE_STROBE BIT(6)
472static void ehci_msm_enable_ulpi_control(struct usb_hcd *hcd, u32 linestate)
473{
474 struct msm_hsic_hcd *mehci = hcd_to_hsic(hcd);
475 int val;
476
477 switch (linestate) {
478 case PORT_RESET:
479 val = ulpi_read(mehci, HSIC_DBG1);
480 val |= ULPI_MANUAL_ENABLE;
481 val &= ~(ULPI_LINESTATE_DATA | ULPI_LINESTATE_STROBE);
482 ulpi_write(mehci, val, HSIC_DBG1);
483 break;
484 default:
485 pr_info("%s: Unknown linestate:%0x\n", __func__, linestate);
486 }
487}
488
489static void ehci_msm_disable_ulpi_control(struct usb_hcd *hcd)
490{
491 struct msm_hsic_hcd *mehci = hcd_to_hsic(hcd);
492 int val;
493
494 val = ulpi_read(mehci, HSIC_DBG1);
495 val &= ~ULPI_MANUAL_ENABLE;
496 ulpi_write(mehci, val, HSIC_DBG1);
497}
498
Vijayavardhan Vennapusae3316a12011-10-15 06:05:17 +0530499static int msm_hsic_config_gpios(struct msm_hsic_hcd *mehci, int gpio_en)
500{
501 int rc = 0;
502 struct msm_hsic_host_platform_data *pdata;
Vamsi Krishna34f01582011-12-14 19:54:42 -0800503 static int gpio_status;
Vijayavardhan Vennapusae3316a12011-10-15 06:05:17 +0530504
505 pdata = mehci->dev->platform_data;
Vamsi Krishna34f01582011-12-14 19:54:42 -0800506
Lena Salman8c8ba382012-02-14 15:59:31 +0200507 if (!pdata || !pdata->strobe || !pdata->data)
Vijayavardhan Vennapusae3316a12011-10-15 06:05:17 +0530508 return rc;
509
Vamsi Krishna34f01582011-12-14 19:54:42 -0800510 if (gpio_status == gpio_en)
511 return 0;
512
513 gpio_status = gpio_en;
514
Vijayavardhan Vennapusae3316a12011-10-15 06:05:17 +0530515 if (!gpio_en)
516 goto free_gpio;
517
518 rc = gpio_request(pdata->strobe, "HSIC_STROBE_GPIO");
519 if (rc < 0) {
520 dev_err(mehci->dev, "gpio request failed for HSIC STROBE\n");
521 return rc;
522 }
523
524 rc = gpio_request(pdata->data, "HSIC_DATA_GPIO");
525 if (rc < 0) {
526 dev_err(mehci->dev, "gpio request failed for HSIC DATA\n");
527 goto free_strobe;
528 }
529
Hemant Kumar6fd65032012-05-23 13:02:24 -0700530 if (mehci->wakeup_gpio) {
531 rc = gpio_request(mehci->wakeup_gpio, "HSIC_WAKEUP_GPIO");
532 if (rc < 0) {
533 dev_err(mehci->dev, "gpio request failed for HSIC WAKEUP\n");
534 goto free_data;
535 }
536 }
537
Vijayavardhan Vennapusae3316a12011-10-15 06:05:17 +0530538 return 0;
539
540free_gpio:
Hemant Kumar6fd65032012-05-23 13:02:24 -0700541 if (mehci->wakeup_gpio)
542 gpio_free(mehci->wakeup_gpio);
543free_data:
Vijayavardhan Vennapusae3316a12011-10-15 06:05:17 +0530544 gpio_free(pdata->data);
545free_strobe:
546 gpio_free(pdata->strobe);
547
548 return rc;
549}
550
Vamsi Krishna64b48612012-06-14 16:08:11 -0700551static void msm_hsic_clk_reset(struct msm_hsic_hcd *mehci)
Vijayavardhan Vennapusa39025fe2011-10-15 05:55:10 +0530552{
553 int ret;
554
Manu Gautam5143b252012-01-05 19:25:23 -0800555 ret = clk_reset(mehci->core_clk, CLK_RESET_ASSERT);
Vijayavardhan Vennapusa39025fe2011-10-15 05:55:10 +0530556 if (ret) {
Vamsi Krishna64b48612012-06-14 16:08:11 -0700557 dev_err(mehci->dev, "hsic clk assert failed:%d\n", ret);
558 return;
Vijayavardhan Vennapusa39025fe2011-10-15 05:55:10 +0530559 }
Vamsi Krishna64b48612012-06-14 16:08:11 -0700560 clk_disable(mehci->core_clk);
Vijayavardhan Vennapusa39025fe2011-10-15 05:55:10 +0530561
Manu Gautam5143b252012-01-05 19:25:23 -0800562 ret = clk_reset(mehci->core_clk, CLK_RESET_DEASSERT);
Vijayavardhan Vennapusa39025fe2011-10-15 05:55:10 +0530563 if (ret)
Vamsi Krishna64b48612012-06-14 16:08:11 -0700564 dev_err(mehci->dev, "hsic clk deassert failed:%d\n", ret);
Vijayavardhan Vennapusa39025fe2011-10-15 05:55:10 +0530565
Vamsi Krishna64b48612012-06-14 16:08:11 -0700566 usleep_range(10000, 12000);
567
568 clk_enable(mehci->core_clk);
Vijayavardhan Vennapusa39025fe2011-10-15 05:55:10 +0530569}
570
Vamsi Krishna64b48612012-06-14 16:08:11 -0700571#define HSIC_STROBE_GPIO_PAD_CTL (MSM_TLMM_BASE+0x20C0)
572#define HSIC_DATA_GPIO_PAD_CTL (MSM_TLMM_BASE+0x20C4)
Vijayavardhan Vennapusae3316a12011-10-15 06:05:17 +0530573#define HSIC_CAL_PAD_CTL (MSM_TLMM_BASE+0x20C8)
574#define HSIC_LV_MODE 0x04
575#define HSIC_PAD_CALIBRATION 0xA8
576#define HSIC_GPIO_PAD_VAL 0x0A0AAA10
Vijayavardhan Vennapusa39025fe2011-10-15 05:55:10 +0530577#define LINK_RESET_TIMEOUT_USEC (250 * 1000)
578static int msm_hsic_reset(struct msm_hsic_hcd *mehci)
579{
580 struct usb_hcd *hcd = hsic_to_hcd(mehci);
Vijayavardhan Vennapusa39025fe2011-10-15 05:55:10 +0530581 int ret;
Lena Salman8c8ba382012-02-14 15:59:31 +0200582 struct msm_hsic_host_platform_data *pdata = mehci->dev->platform_data;
Vijayavardhan Vennapusa39025fe2011-10-15 05:55:10 +0530583
Vamsi Krishna64b48612012-06-14 16:08:11 -0700584 msm_hsic_clk_reset(mehci);
Vijayavardhan Vennapusa39025fe2011-10-15 05:55:10 +0530585
Vamsi Krishna64b48612012-06-14 16:08:11 -0700586 /* select ulpi phy */
Vijayavardhan Vennapusa39025fe2011-10-15 05:55:10 +0530587 writel_relaxed(0x80000000, USB_PORTSC);
588
Vamsi Krishna64b48612012-06-14 16:08:11 -0700589 mb();
Vijayavardhan Vennapusae3316a12011-10-15 06:05:17 +0530590
Lena Salman8c8ba382012-02-14 15:59:31 +0200591 /* HSIC init sequence when HSIC signals (Strobe/Data) are
592 routed via GPIOs */
593 if (pdata && pdata->strobe && pdata->data) {
Vijayavardhan Vennapusae3316a12011-10-15 06:05:17 +0530594
Lena Salman8c8ba382012-02-14 15:59:31 +0200595 /* Enable LV_MODE in HSIC_CAL_PAD_CTL register */
596 writel_relaxed(HSIC_LV_MODE, HSIC_CAL_PAD_CTL);
Vijayavardhan Vennapusae3316a12011-10-15 06:05:17 +0530597
Vamsi Krishna64b48612012-06-14 16:08:11 -0700598 mb();
599
Lena Salman8c8ba382012-02-14 15:59:31 +0200600 /*set periodic calibration interval to ~2.048sec in
601 HSIC_IO_CAL_REG */
602 ulpi_write(mehci, 0xFF, 0x33);
603
604 /* Enable periodic IO calibration in HSIC_CFG register */
605 ulpi_write(mehci, HSIC_PAD_CALIBRATION, 0x30);
606
Vamsi Krishna64b48612012-06-14 16:08:11 -0700607 /* Configure GPIO pins for HSIC functionality mode */
Lena Salman8c8ba382012-02-14 15:59:31 +0200608 ret = msm_hsic_config_gpios(mehci, 1);
609 if (ret) {
610 dev_err(mehci->dev, " gpio configuarion failed\n");
611 return ret;
612 }
Vamsi Krishna64b48612012-06-14 16:08:11 -0700613 /* Set LV_MODE=0x1 and DCC=0x2 in HSIC_GPIO PAD_CTL register */
614 writel_relaxed(HSIC_GPIO_PAD_VAL, HSIC_STROBE_GPIO_PAD_CTL);
615 writel_relaxed(HSIC_GPIO_PAD_VAL, HSIC_DATA_GPIO_PAD_CTL);
616
617 mb();
618
Lena Salman8c8ba382012-02-14 15:59:31 +0200619 /* Enable HSIC mode in HSIC_CFG register */
620 ulpi_write(mehci, 0x01, 0x31);
621 } else {
622 /* HSIC init sequence when HSIC signals (Strobe/Data) are routed
623 via dedicated I/O */
624
625 /* programmable length of connect signaling (33.2ns) */
626 ret = ulpi_write(mehci, 3, HSIC_DBG1_REG);
627 if (ret) {
628 pr_err("%s: Unable to program length of connect "
629 "signaling\n", __func__);
630 }
631
632 /*set periodic calibration interval to ~2.048sec in
633 HSIC_IO_CAL_REG */
634 ulpi_write(mehci, 0xFF, 0x33);
635
636 /* Enable HSIC mode in HSIC_CFG register */
637 ulpi_write(mehci, 0xA9, 0x30);
Vijayavardhan Vennapusae3316a12011-10-15 06:05:17 +0530638 }
639
Hemant Kumar6fd65032012-05-23 13:02:24 -0700640 /*disable auto resume*/
641 ulpi_write(mehci, ULPI_IFC_CTRL_AUTORESUME, ULPI_CLR(ULPI_IFC_CTRL));
642
Vijayavardhan Vennapusa39025fe2011-10-15 05:55:10 +0530643 return 0;
644}
645
646#define PHY_SUSPEND_TIMEOUT_USEC (500 * 1000)
647#define PHY_RESUME_TIMEOUT_USEC (100 * 1000)
648
649#ifdef CONFIG_PM_SLEEP
650static int msm_hsic_suspend(struct msm_hsic_hcd *mehci)
651{
652 struct usb_hcd *hcd = hsic_to_hcd(mehci);
Vijayavardhan Vennapusa2b592824f2011-11-02 19:51:32 +0530653 int cnt = 0, ret;
Vijayavardhan Vennapusa39025fe2011-10-15 05:55:10 +0530654 u32 val;
Amit Blayd6ea6102012-06-07 16:26:24 +0300655 int none_vol, max_vol;
Vijayavardhan Vennapusa39025fe2011-10-15 05:55:10 +0530656
657 if (atomic_read(&mehci->in_lpm)) {
658 dev_dbg(mehci->dev, "%s called in lpm\n", __func__);
659 return 0;
660 }
661
662 disable_irq(hcd->irq);
Jack Phambe05fbb2012-05-16 10:56:26 -0700663
Ajay Dudaniab3bf192012-08-28 09:58:04 -0700664 /* make sure we don't race against a remote wakeup */
665 if (test_bit(HCD_FLAG_WAKEUP_PENDING, &hcd->flags) ||
Jack Phambe05fbb2012-05-16 10:56:26 -0700666 readl_relaxed(USB_PORTSC) & PORT_RESUME) {
Ajay Dudaniab3bf192012-08-28 09:58:04 -0700667 dev_dbg(mehci->dev, "wakeup pending, aborting suspend\n");
Jack Phambe05fbb2012-05-16 10:56:26 -0700668 enable_irq(hcd->irq);
669 return -EBUSY;
670 }
671
Vijayavardhan Vennapusa39025fe2011-10-15 05:55:10 +0530672 /*
673 * PHY may take some time or even fail to enter into low power
674 * mode (LPM). Hence poll for 500 msec and reset the PHY and link
675 * in failure case.
676 */
Hemant Kumar3dbc5b32012-05-09 15:36:11 -0700677 val = readl_relaxed(USB_PORTSC);
678 val &= ~PORT_RWC_BITS;
679 val |= PORTSC_PHCD;
Vijayavardhan Vennapusa39025fe2011-10-15 05:55:10 +0530680 writel_relaxed(val, USB_PORTSC);
681 while (cnt < PHY_SUSPEND_TIMEOUT_USEC) {
682 if (readl_relaxed(USB_PORTSC) & PORTSC_PHCD)
683 break;
684 udelay(1);
685 cnt++;
686 }
687
688 if (cnt >= PHY_SUSPEND_TIMEOUT_USEC) {
689 dev_err(mehci->dev, "Unable to suspend PHY\n");
Vijayavardhan Vennapusae3316a12011-10-15 06:05:17 +0530690 msm_hsic_config_gpios(mehci, 0);
Vijayavardhan Vennapusa39025fe2011-10-15 05:55:10 +0530691 msm_hsic_reset(mehci);
Vijayavardhan Vennapusa39025fe2011-10-15 05:55:10 +0530692 }
693
694 /*
695 * PHY has capability to generate interrupt asynchronously in low
696 * power mode (LPM). This interrupt is level triggered. So USB IRQ
697 * line must be disabled till async interrupt enable bit is cleared
698 * in USBCMD register. Assert STP (ULPI interface STOP signal) to
699 * block data communication from PHY.
700 */
701 writel_relaxed(readl_relaxed(USB_USBCMD) | ASYNC_INTR_CTRL |
702 ULPI_STP_CTRL, USB_USBCMD);
703
704 /*
705 * Ensure that hardware is put in low power mode before
706 * clocks are turned OFF and VDD is allowed to minimize.
707 */
708 mb();
709
Manu Gautam28b1bac2012-01-30 16:43:06 +0530710 clk_disable_unprepare(mehci->core_clk);
711 clk_disable_unprepare(mehci->phy_clk);
712 clk_disable_unprepare(mehci->cal_clk);
713 clk_disable_unprepare(mehci->ahb_clk);
Vijayavardhan Vennapusa39025fe2011-10-15 05:55:10 +0530714
Amit Blayd6ea6102012-06-07 16:26:24 +0300715 none_vol = vdd_val[mehci->vdd_type][VDD_NONE];
716 max_vol = vdd_val[mehci->vdd_type][VDD_MAX];
717
718 ret = regulator_set_voltage(mehci->hsic_vddcx, none_vol, max_vol);
Vamsi Krishna45d88fa2011-11-02 13:28:42 -0700719 if (ret < 0)
Amit Blayd6ea6102012-06-07 16:26:24 +0300720 dev_err(mehci->dev, "unable to set vddcx voltage for VDD MIN\n");
Vamsi Krishna45d88fa2011-11-02 13:28:42 -0700721
Hemant Kumare6275972012-02-29 20:06:21 -0800722 if (mehci->bus_perf_client && debug_bus_voting_enabled) {
Hemant Kumar2309eaa2012-08-14 16:46:42 -0700723 mehci->bus_vote = false;
724 queue_work(ehci_wq, &mehci->bus_vote_w);
Hemant Kumare6275972012-02-29 20:06:21 -0800725 }
726
Vijayavardhan Vennapusa39025fe2011-10-15 05:55:10 +0530727 atomic_set(&mehci->in_lpm, 1);
728 enable_irq(hcd->irq);
Hemant Kumar6fd65032012-05-23 13:02:24 -0700729
730 mehci->wakeup_irq_enabled = 1;
731 enable_irq_wake(mehci->wakeup_irq);
732 enable_irq(mehci->wakeup_irq);
733
Ajay Dudaniab3bf192012-08-28 09:58:04 -0700734 wake_unlock(&mehci->wlock);
735
Devin Kim476bbd72012-07-19 18:11:11 -0700736 dev_dbg(mehci->dev, "HSIC-USB in low power mode\n");
Vijayavardhan Vennapusa39025fe2011-10-15 05:55:10 +0530737
738 return 0;
739}
740
741static int msm_hsic_resume(struct msm_hsic_hcd *mehci)
742{
743 struct usb_hcd *hcd = hsic_to_hcd(mehci);
Vijayavardhan Vennapusa2b592824f2011-11-02 19:51:32 +0530744 int cnt = 0, ret;
Vijayavardhan Vennapusa39025fe2011-10-15 05:55:10 +0530745 unsigned temp;
Amit Blayd6ea6102012-06-07 16:26:24 +0300746 int min_vol, max_vol;
Hemant Kumar4cd49e12012-09-06 19:57:14 -0700747 unsigned long flags;
Vijayavardhan Vennapusa39025fe2011-10-15 05:55:10 +0530748
749 if (!atomic_read(&mehci->in_lpm)) {
750 dev_dbg(mehci->dev, "%s called in !in_lpm\n", __func__);
751 return 0;
752 }
753
Pavankumar Kondetibbd05822013-01-28 17:04:39 +0530754 /* Handles race with Async interrupt */
755 disable_irq(hcd->irq);
756
Hemant Kumar4cd49e12012-09-06 19:57:14 -0700757 spin_lock_irqsave(&mehci->wakeup_lock, flags);
Hemant Kumar6fd65032012-05-23 13:02:24 -0700758 if (mehci->wakeup_irq_enabled) {
759 disable_irq_wake(mehci->wakeup_irq);
760 disable_irq_nosync(mehci->wakeup_irq);
761 mehci->wakeup_irq_enabled = 0;
762 }
Hemant Kumar4cd49e12012-09-06 19:57:14 -0700763 spin_unlock_irqrestore(&mehci->wakeup_lock, flags);
Hemant Kumar6fd65032012-05-23 13:02:24 -0700764
Ajay Dudaniab3bf192012-08-28 09:58:04 -0700765 wake_lock(&mehci->wlock);
766
Hemant Kumare6275972012-02-29 20:06:21 -0800767 if (mehci->bus_perf_client && debug_bus_voting_enabled) {
Hemant Kumar2309eaa2012-08-14 16:46:42 -0700768 mehci->bus_vote = true;
769 queue_work(ehci_wq, &mehci->bus_vote_w);
Hemant Kumare6275972012-02-29 20:06:21 -0800770 }
771
Amit Blayd6ea6102012-06-07 16:26:24 +0300772 min_vol = vdd_val[mehci->vdd_type][VDD_MIN];
773 max_vol = vdd_val[mehci->vdd_type][VDD_MAX];
774
775 ret = regulator_set_voltage(mehci->hsic_vddcx, min_vol, max_vol);
Vamsi Krishna45d88fa2011-11-02 13:28:42 -0700776 if (ret < 0)
Amit Blayd6ea6102012-06-07 16:26:24 +0300777 dev_err(mehci->dev, "unable to set nominal vddcx voltage (no VDD MIN)\n");
Vamsi Krishna45d88fa2011-11-02 13:28:42 -0700778
Manu Gautam28b1bac2012-01-30 16:43:06 +0530779 clk_prepare_enable(mehci->core_clk);
780 clk_prepare_enable(mehci->phy_clk);
781 clk_prepare_enable(mehci->cal_clk);
782 clk_prepare_enable(mehci->ahb_clk);
Vijayavardhan Vennapusa39025fe2011-10-15 05:55:10 +0530783
784 temp = readl_relaxed(USB_USBCMD);
785 temp &= ~ASYNC_INTR_CTRL;
786 temp &= ~ULPI_STP_CTRL;
787 writel_relaxed(temp, USB_USBCMD);
788
789 if (!(readl_relaxed(USB_PORTSC) & PORTSC_PHCD))
790 goto skip_phy_resume;
791
Hemant Kumar3dbc5b32012-05-09 15:36:11 -0700792 temp = readl_relaxed(USB_PORTSC);
793 temp &= ~(PORT_RWC_BITS | PORTSC_PHCD);
Vijayavardhan Vennapusa39025fe2011-10-15 05:55:10 +0530794 writel_relaxed(temp, USB_PORTSC);
795 while (cnt < PHY_RESUME_TIMEOUT_USEC) {
796 if (!(readl_relaxed(USB_PORTSC) & PORTSC_PHCD) &&
797 (readl_relaxed(USB_ULPI_VIEWPORT) & ULPI_SYNC_STATE))
798 break;
799 udelay(1);
800 cnt++;
801 }
802
803 if (cnt >= PHY_RESUME_TIMEOUT_USEC) {
804 /*
805 * This is a fatal error. Reset the link and
806 * PHY to make hsic working.
807 */
808 dev_err(mehci->dev, "Unable to resume USB. Reset the hsic\n");
Vijayavardhan Vennapusae3316a12011-10-15 06:05:17 +0530809 msm_hsic_config_gpios(mehci, 0);
Vijayavardhan Vennapusa39025fe2011-10-15 05:55:10 +0530810 msm_hsic_reset(mehci);
811 }
812
813skip_phy_resume:
814
Hemant Kumar6fd65032012-05-23 13:02:24 -0700815 usb_hcd_resume_root_hub(hcd);
816
Vijayavardhan Vennapusa39025fe2011-10-15 05:55:10 +0530817 atomic_set(&mehci->in_lpm, 0);
818
Pavankumar Kondetibbd05822013-01-28 17:04:39 +0530819 if (atomic_read(&mehci->async_int)) {
820 atomic_set(&mehci->async_int, 0);
Vijayavardhan Vennapusa39025fe2011-10-15 05:55:10 +0530821 pm_runtime_put_noidle(mehci->dev);
Jack Phamdd5ad792012-07-26 10:31:03 -0700822 enable_irq(hcd->irq);
Hemant Kumar6fd65032012-05-23 13:02:24 -0700823 }
824
Ajay Dudaniab3bf192012-08-28 09:58:04 -0700825 if (atomic_read(&mehci->pm_usage_cnt)) {
826 atomic_set(&mehci->pm_usage_cnt, 0);
827 pm_runtime_put_noidle(mehci->dev);
828 }
Jack Phamdd5ad792012-07-26 10:31:03 -0700829
Pavankumar Kondetibbd05822013-01-28 17:04:39 +0530830 enable_irq(hcd->irq);
Devin Kim476bbd72012-07-19 18:11:11 -0700831 dev_dbg(mehci->dev, "HSIC-USB exited from low power mode\n");
Vijayavardhan Vennapusa39025fe2011-10-15 05:55:10 +0530832
833 return 0;
834}
835#endif
836
Hemant Kumar2309eaa2012-08-14 16:46:42 -0700837static void ehci_hsic_bus_vote_w(struct work_struct *w)
838{
839 struct msm_hsic_hcd *mehci =
840 container_of(w, struct msm_hsic_hcd, bus_vote_w);
841 int ret;
842
843 ret = msm_bus_scale_client_update_request(mehci->bus_perf_client,
844 mehci->bus_vote);
845 if (ret)
846 dev_err(mehci->dev, "%s: Failed to vote for bus bandwidth %d\n",
847 __func__, ret);
848}
849
Ajay Dudani11ab1d52012-08-17 17:12:26 -0700850#define STS_GPTIMER0_INTERRUPT BIT(24)
Vijayavardhan Vennapusa39025fe2011-10-15 05:55:10 +0530851static irqreturn_t msm_hsic_irq(struct usb_hcd *hcd)
852{
Ajay Dudani11ab1d52012-08-17 17:12:26 -0700853 struct ehci_hcd *ehci = hcd_to_ehci(hcd);
Vijayavardhan Vennapusa39025fe2011-10-15 05:55:10 +0530854 struct msm_hsic_hcd *mehci = hcd_to_hsic(hcd);
Ajay Dudani11ab1d52012-08-17 17:12:26 -0700855 u32 status;
Pavankumar Kondetibbd05822013-01-28 17:04:39 +0530856 int ret;
Vijayavardhan Vennapusa39025fe2011-10-15 05:55:10 +0530857
858 if (atomic_read(&mehci->in_lpm)) {
Hemant Kumar3dbc5b32012-05-09 15:36:11 -0700859 dev_dbg(mehci->dev, "phy async intr\n");
Pavankumar Kondetibbd05822013-01-28 17:04:39 +0530860 dbg_log_event(NULL, "Async IRQ", 0);
861 ret = pm_runtime_get(mehci->dev);
862 if ((ret == 1) || (ret == -EINPROGRESS)) {
863 pm_runtime_put_noidle(mehci->dev);
864 } else {
865 disable_irq_nosync(hcd->irq);
866 atomic_set(&mehci->async_int, 1);
867 }
868
Vijayavardhan Vennapusa39025fe2011-10-15 05:55:10 +0530869 return IRQ_HANDLED;
870 }
871
Ajay Dudani11ab1d52012-08-17 17:12:26 -0700872 status = ehci_readl(ehci, &ehci->regs->status);
873
874 if (status & STS_GPTIMER0_INTERRUPT) {
875 int timeleft;
876
877 dbg_log_event(NULL, "FPR: gpt0_isr", 0);
878
879 timeleft = GPT_CNT(ehci_readl(ehci,
880 &mehci->timer->gptimer1_ctrl));
881 if (timeleft) {
882 ehci_writel(ehci, ehci_readl(ehci,
883 &ehci->regs->command) | CMD_RUN,
884 &ehci->regs->command);
885 } else
886 mehci->resume_again = 1;
887
888 dbg_log_event(NULL, "FPR: timeleft", timeleft);
889
890 complete(&mehci->gpt0_completion);
891 ehci_writel(ehci, STS_GPTIMER0_INTERRUPT, &ehci->regs->status);
892 }
893
Vijayavardhan Vennapusa39025fe2011-10-15 05:55:10 +0530894 return ehci_irq(hcd);
895}
896
897static int ehci_hsic_reset(struct usb_hcd *hcd)
898{
899 struct ehci_hcd *ehci = hcd_to_ehci(hcd);
Ajay Dudani11ab1d52012-08-17 17:12:26 -0700900 struct msm_hsic_hcd *mehci = hcd_to_hsic(hcd);
Vijayavardhan Vennapusa39025fe2011-10-15 05:55:10 +0530901 int retval;
902
Ajay Dudani11ab1d52012-08-17 17:12:26 -0700903 mehci->timer = USB_HS_GPTIMER_BASE;
Vijayavardhan Vennapusa39025fe2011-10-15 05:55:10 +0530904 ehci->caps = USB_CAPLENGTH;
905 ehci->regs = USB_CAPLENGTH +
906 HC_LENGTH(ehci, ehci_readl(ehci, &ehci->caps->hc_capbase));
907 dbg_hcs_params(ehci, "reset");
908 dbg_hcc_params(ehci, "reset");
909
910 /* cache the data to minimize the chip reads*/
911 ehci->hcs_params = ehci_readl(ehci, &ehci->caps->hcs_params);
912
913 hcd->has_tt = 1;
914 ehci->sbrn = HCD_USB2;
915
916 retval = ehci_halt(ehci);
917 if (retval)
918 return retval;
919
920 /* data structure init */
921 retval = ehci_init(hcd);
922 if (retval)
923 return retval;
924
925 retval = ehci_reset(ehci);
926 if (retval)
927 return retval;
928
929 /* bursts of unspecified length. */
930 writel_relaxed(0, USB_AHBBURST);
931 /* Use the AHB transactor */
Vijayavardhan Vennapusa5f32d7a2012-03-14 16:30:26 +0530932 writel_relaxed(0x08, USB_AHBMODE);
Vijayavardhan Vennapusa39025fe2011-10-15 05:55:10 +0530933 /* Disable streaming mode and select host mode */
934 writel_relaxed(0x13, USB_USBMODE);
935
936 ehci_port_power(ehci, 1);
937 return 0;
938}
939
Hemant Kumar45d211b2012-05-31 17:58:43 -0700940static int ehci_hsic_bus_suspend(struct usb_hcd *hcd)
941{
Pavankumar Kondeti3c137392012-09-14 14:02:36 +0530942 struct msm_hsic_hcd *mehci = hcd_to_hsic(hcd);
943
944 if (!(readl_relaxed(USB_PORTSC) & PORT_PE)) {
945 dbg_log_event(NULL, "RH suspend attempt failed", 0);
946 dev_dbg(mehci->dev, "%s:port is not enabled skip suspend\n",
947 __func__);
948 return -EAGAIN;
949 }
950
Hemant Kumar45d211b2012-05-31 17:58:43 -0700951 dbg_log_event(NULL, "Suspend RH", 0);
952 return ehci_bus_suspend(hcd);
953}
954
Ajay Dudani11ab1d52012-08-17 17:12:26 -0700955#define RESUME_RETRY_LIMIT 3
956#define RESUME_SIGNAL_TIME_MS (21 * 999)
957#define RESUME_SIGNAL_TIME_SOF_MS (23 * 999)
958static int msm_hsic_resume_thread(void *data)
959{
960 struct msm_hsic_hcd *mehci = data;
961 struct usb_hcd *hcd = hsic_to_hcd(mehci);
962 struct ehci_hcd *ehci = hcd_to_ehci(hcd);
963 u32 temp;
964 unsigned long resume_needed = 0;
965 int retry_cnt = 0;
966 int tight_resume = 0;
Pavankumar Kondetife2d4d32012-09-07 15:33:09 +0530967 struct msm_hsic_host_platform_data *pdata = mehci->dev->platform_data;
Ajay Dudani11ab1d52012-08-17 17:12:26 -0700968
969 dbg_log_event(NULL, "Resume RH", 0);
970
971 /* keep delay between bus states */
972 if (time_before(jiffies, ehci->next_statechange))
973 usleep_range(5000, 5000);
974
975 spin_lock_irq(&ehci->lock);
976 if (!HCD_HW_ACCESSIBLE(hcd)) {
977 spin_unlock_irq(&ehci->lock);
978 mehci->resume_status = -ESHUTDOWN;
979 complete(&mehci->rt_completion);
980 return 0;
981 }
982
983 if (unlikely(ehci->debug)) {
984 if (!dbgp_reset_prep())
985 ehci->debug = NULL;
986 else
987 dbgp_external_startup();
988 }
989
990 /* at least some APM implementations will try to deliver
991 * IRQs right away, so delay them until we're ready.
992 */
993 ehci_writel(ehci, 0, &ehci->regs->intr_enable);
994
995 /* re-init operational registers */
996 ehci_writel(ehci, 0, &ehci->regs->segment);
997 ehci_writel(ehci, ehci->periodic_dma, &ehci->regs->frame_list);
998 ehci_writel(ehci, (u32) ehci->async->qh_dma, &ehci->regs->async_next);
999
1000 /*CMD_RUN will be set after, PORT_RESUME gets cleared*/
1001 if (ehci->resume_sof_bug)
1002 ehci->command &= ~CMD_RUN;
1003
1004 /* restore CMD_RUN, framelist size, and irq threshold */
1005 ehci_writel(ehci, ehci->command, &ehci->regs->command);
1006
1007 /* manually resume the ports we suspended during bus_suspend() */
1008resume_again:
1009 if (retry_cnt >= RESUME_RETRY_LIMIT) {
1010 pr_info("retry count(%d) reached max, resume in tight loop\n",
1011 retry_cnt);
1012 tight_resume = 1;
1013 }
1014
1015
1016 temp = ehci_readl(ehci, &ehci->regs->port_status[0]);
1017 temp &= ~(PORT_RWC_BITS | PORT_WAKE_BITS);
1018 if (test_bit(0, &ehci->bus_suspended) && (temp & PORT_SUSPEND)) {
1019 temp |= PORT_RESUME;
1020 set_bit(0, &resume_needed);
1021 }
1022 dbg_log_event(NULL, "FPR: Set", temp);
1023 ehci_writel(ehci, temp, &ehci->regs->port_status[0]);
1024
1025 /* HSIC controller has a h/w bug due to which it can try to send SOFs
1026 * (start of frames) during port resume resulting in phy lockup. HSIC hw
1027 * controller in MSM clears FPR bit after driving the resume signal for
1028 * 20ms. Workaround is to stop SOFs before driving resume and then start
1029 * sending SOFs immediately. Need to send SOFs within 3ms of resume
1030 * completion otherwise peripheral may enter undefined state. As
1031 * usleep_range does not gurantee exact sleep time, GPTimer is used to
1032 * to time the resume sequence. If driver exceeds allowable time SOFs,
1033 * repeat the resume process.
1034 */
1035 if (ehci->resume_sof_bug && resume_needed) {
1036 if (!tight_resume) {
1037 mehci->resume_again = 0;
1038 ehci_writel(ehci, GPT_LD(RESUME_SIGNAL_TIME_MS),
1039 &mehci->timer->gptimer0_ld);
1040 ehci_writel(ehci, GPT_RESET | GPT_RUN,
1041 &mehci->timer->gptimer0_ctrl);
1042 ehci_writel(ehci, INTR_MASK | STS_GPTIMER0_INTERRUPT,
1043 &ehci->regs->intr_enable);
1044
1045 ehci_writel(ehci, GPT_LD(RESUME_SIGNAL_TIME_SOF_MS),
1046 &mehci->timer->gptimer1_ld);
1047 ehci_writel(ehci, GPT_RESET | GPT_RUN,
1048 &mehci->timer->gptimer1_ctrl);
1049
1050 spin_unlock_irq(&ehci->lock);
Pavankumar Kondetife2d4d32012-09-07 15:33:09 +05301051 if (pdata && pdata->swfi_latency)
1052 pm_qos_update_request(&mehci->pm_qos_req_dma,
1053 pdata->swfi_latency + 1);
Ajay Dudani11ab1d52012-08-17 17:12:26 -07001054 wait_for_completion(&mehci->gpt0_completion);
Pavankumar Kondetife2d4d32012-09-07 15:33:09 +05301055 if (pdata && pdata->swfi_latency)
1056 pm_qos_update_request(&mehci->pm_qos_req_dma,
1057 PM_QOS_DEFAULT_VALUE);
Ajay Dudani11ab1d52012-08-17 17:12:26 -07001058 spin_lock_irq(&ehci->lock);
1059 } else {
1060 dbg_log_event(NULL, "FPR: Tightloop", 0);
1061 /* do the resume in a tight loop */
1062 handshake(ehci, &ehci->regs->port_status[0],
1063 PORT_RESUME, 0, 22 * 1000);
1064 ehci_writel(ehci, ehci_readl(ehci,
1065 &ehci->regs->command) | CMD_RUN,
1066 &ehci->regs->command);
1067 }
1068
1069 if (mehci->resume_again) {
1070 int temp;
1071
1072 dbg_log_event(NULL, "FPR: Re-Resume", retry_cnt);
1073 pr_info("FPR: retry count: %d\n", retry_cnt);
1074 spin_unlock_irq(&ehci->lock);
1075 temp = ehci_readl(ehci, &ehci->regs->port_status[0]);
1076 temp &= ~PORT_RWC_BITS;
1077 temp |= PORT_SUSPEND;
1078 ehci_writel(ehci, temp, &ehci->regs->port_status[0]);
1079 /* Keep the bus idle for 5ms so that peripheral
1080 * can detect and initiate suspend
1081 */
1082 usleep_range(5000, 5000);
1083 dbg_log_event(NULL,
1084 "FPR: RResume",
1085 ehci_readl(ehci, &ehci->regs->port_status[0]));
1086 spin_lock_irq(&ehci->lock);
1087 mehci->resume_again = 0;
1088 retry_cnt++;
1089 goto resume_again;
1090 }
1091 }
1092
1093 dbg_log_event(NULL, "FPR: RT-Done", 0);
1094 mehci->resume_status = 1;
1095 spin_unlock_irq(&ehci->lock);
1096
1097 complete(&mehci->rt_completion);
1098
1099 return 0;
1100}
1101
Hemant Kumar45d211b2012-05-31 17:58:43 -07001102static int ehci_hsic_bus_resume(struct usb_hcd *hcd)
1103{
Ajay Dudani11ab1d52012-08-17 17:12:26 -07001104 struct msm_hsic_hcd *mehci = hcd_to_hsic(hcd);
1105 struct ehci_hcd *ehci = hcd_to_ehci(hcd);
1106 u32 temp;
1107 struct task_struct *resume_thread = NULL;
1108
1109 mehci->resume_status = 0;
1110 resume_thread = kthread_run(msm_hsic_resume_thread,
1111 mehci, "hsic_resume_thread");
1112 if (IS_ERR(resume_thread)) {
1113 pr_err("Error creating resume thread:%lu\n",
1114 PTR_ERR(resume_thread));
1115 return PTR_ERR(resume_thread);
1116 }
1117
1118 wait_for_completion(&mehci->rt_completion);
1119
1120 if (mehci->resume_status < 0)
1121 return mehci->resume_status;
1122
1123 dbg_log_event(NULL, "FPR: Wokeup", 0);
1124 spin_lock_irq(&ehci->lock);
1125 (void) ehci_readl(ehci, &ehci->regs->command);
1126
1127 temp = 0;
1128 if (ehci->async->qh_next.qh)
1129 temp |= CMD_ASE;
1130 if (ehci->periodic_sched)
1131 temp |= CMD_PSE;
1132 if (temp) {
1133 ehci->command |= temp;
1134 ehci_writel(ehci, ehci->command, &ehci->regs->command);
1135 }
1136
1137 ehci->next_statechange = jiffies + msecs_to_jiffies(5);
1138 hcd->state = HC_STATE_RUNNING;
1139 ehci->rh_state = EHCI_RH_RUNNING;
1140
1141 /* Now we can safely re-enable irqs */
1142 ehci_writel(ehci, INTR_MASK, &ehci->regs->intr_enable);
1143
1144 spin_unlock_irq(&ehci->lock);
1145
1146 return 0;
Hemant Kumar45d211b2012-05-31 17:58:43 -07001147}
1148
Vijayavardhan Vennapusa39025fe2011-10-15 05:55:10 +05301149static struct hc_driver msm_hsic_driver = {
1150 .description = hcd_name,
1151 .product_desc = "Qualcomm EHCI Host Controller using HSIC",
1152 .hcd_priv_size = sizeof(struct msm_hsic_hcd),
1153
1154 /*
1155 * generic hardware linkage
1156 */
1157 .irq = msm_hsic_irq,
Vamsi Krishna8e6edcb2012-06-20 18:08:50 -07001158 .flags = HCD_USB2 | HCD_MEMORY | HCD_OLD_ENUM,
Vijayavardhan Vennapusa39025fe2011-10-15 05:55:10 +05301159
1160 .reset = ehci_hsic_reset,
1161 .start = ehci_run,
1162
1163 .stop = ehci_stop,
1164 .shutdown = ehci_shutdown,
1165
1166 /*
1167 * managing i/o requests and associated device resources
1168 */
Hemant Kumardf2d84d2012-08-15 09:06:35 -07001169 .urb_enqueue = ehci_urb_enqueue,
Vijayavardhan Vennapusa39025fe2011-10-15 05:55:10 +05301170 .urb_dequeue = ehci_urb_dequeue,
1171 .endpoint_disable = ehci_endpoint_disable,
1172 .endpoint_reset = ehci_endpoint_reset,
1173 .clear_tt_buffer_complete = ehci_clear_tt_buffer_complete,
1174
1175 /*
1176 * scheduling support
1177 */
1178 .get_frame_number = ehci_get_frame,
1179
1180 /*
1181 * root hub support
1182 */
1183 .hub_status_data = ehci_hub_status_data,
1184 .hub_control = ehci_hub_control,
1185 .relinquish_port = ehci_relinquish_port,
1186 .port_handed_over = ehci_port_handed_over,
1187
1188 /*
1189 * PM support
1190 */
Hemant Kumar45d211b2012-05-31 17:58:43 -07001191 .bus_suspend = ehci_hsic_bus_suspend,
1192 .bus_resume = ehci_hsic_bus_resume,
1193
Hemant Kumardf2d84d2012-08-15 09:06:35 -07001194 .log_urb = dbg_log_event,
Hemant Kumar105d07f2012-07-02 15:33:07 -07001195 .dump_regs = dump_hsic_regs,
Vamsi Krishna8e6edcb2012-06-20 18:08:50 -07001196
1197 .enable_ulpi_control = ehci_msm_enable_ulpi_control,
1198 .disable_ulpi_control = ehci_msm_disable_ulpi_control,
Vijayavardhan Vennapusa39025fe2011-10-15 05:55:10 +05301199};
1200
1201static int msm_hsic_init_clocks(struct msm_hsic_hcd *mehci, u32 init)
1202{
1203 int ret = 0;
1204
1205 if (!init)
1206 goto put_clocks;
1207
Lena Salman8c8ba382012-02-14 15:59:31 +02001208 /*core_clk is required for LINK protocol engine
1209 *clock rate appropriately set by target specific clock driver */
Manu Gautam5143b252012-01-05 19:25:23 -08001210 mehci->core_clk = clk_get(mehci->dev, "core_clk");
1211 if (IS_ERR(mehci->core_clk)) {
1212 dev_err(mehci->dev, "failed to get core_clk\n");
1213 ret = PTR_ERR(mehci->core_clk);
Vijayavardhan Vennapusa39025fe2011-10-15 05:55:10 +05301214 return ret;
1215 }
Vijayavardhan Vennapusa39025fe2011-10-15 05:55:10 +05301216
Lena Salman8c8ba382012-02-14 15:59:31 +02001217 /* alt_core_clk is for LINK to be used during PHY RESET
1218 * clock rate appropriately set by target specific clock driver */
Manu Gautam5143b252012-01-05 19:25:23 -08001219 mehci->alt_core_clk = clk_get(mehci->dev, "alt_core_clk");
1220 if (IS_ERR(mehci->alt_core_clk)) {
1221 dev_err(mehci->dev, "failed to core_clk\n");
1222 ret = PTR_ERR(mehci->alt_core_clk);
1223 goto put_core_clk;
Vijayavardhan Vennapusa39025fe2011-10-15 05:55:10 +05301224 }
Vijayavardhan Vennapusa39025fe2011-10-15 05:55:10 +05301225
Lena Salman8c8ba382012-02-14 15:59:31 +02001226 /* phy_clk is required for HSIC PHY operation
1227 * clock rate appropriately set by target specific clock driver */
Manu Gautam5143b252012-01-05 19:25:23 -08001228 mehci->phy_clk = clk_get(mehci->dev, "phy_clk");
1229 if (IS_ERR(mehci->phy_clk)) {
1230 dev_err(mehci->dev, "failed to get phy_clk\n");
1231 ret = PTR_ERR(mehci->phy_clk);
1232 goto put_alt_core_clk;
Vijayavardhan Vennapusa39025fe2011-10-15 05:55:10 +05301233 }
Vijayavardhan Vennapusa39025fe2011-10-15 05:55:10 +05301234
1235 /* 10MHz cal_clk is required for calibration of I/O pads */
Manu Gautam5143b252012-01-05 19:25:23 -08001236 mehci->cal_clk = clk_get(mehci->dev, "cal_clk");
Vijayavardhan Vennapusa39025fe2011-10-15 05:55:10 +05301237 if (IS_ERR(mehci->cal_clk)) {
Manu Gautam5143b252012-01-05 19:25:23 -08001238 dev_err(mehci->dev, "failed to get cal_clk\n");
Vijayavardhan Vennapusa39025fe2011-10-15 05:55:10 +05301239 ret = PTR_ERR(mehci->cal_clk);
Manu Gautam5143b252012-01-05 19:25:23 -08001240 goto put_phy_clk;
Vijayavardhan Vennapusa39025fe2011-10-15 05:55:10 +05301241 }
1242 clk_set_rate(mehci->cal_clk, 10000000);
1243
1244 /* ahb_clk is required for data transfers */
Manu Gautam5143b252012-01-05 19:25:23 -08001245 mehci->ahb_clk = clk_get(mehci->dev, "iface_clk");
Vijayavardhan Vennapusa39025fe2011-10-15 05:55:10 +05301246 if (IS_ERR(mehci->ahb_clk)) {
Manu Gautam5143b252012-01-05 19:25:23 -08001247 dev_err(mehci->dev, "failed to get iface_clk\n");
Vijayavardhan Vennapusa39025fe2011-10-15 05:55:10 +05301248 ret = PTR_ERR(mehci->ahb_clk);
1249 goto put_cal_clk;
1250 }
1251
Manu Gautam28b1bac2012-01-30 16:43:06 +05301252 clk_prepare_enable(mehci->core_clk);
1253 clk_prepare_enable(mehci->phy_clk);
1254 clk_prepare_enable(mehci->cal_clk);
1255 clk_prepare_enable(mehci->ahb_clk);
Vijayavardhan Vennapusa39025fe2011-10-15 05:55:10 +05301256
1257 return 0;
1258
1259put_clocks:
Jack Phamfd193eb2012-02-22 15:38:08 -08001260 if (!atomic_read(&mehci->in_lpm)) {
1261 clk_disable_unprepare(mehci->core_clk);
1262 clk_disable_unprepare(mehci->phy_clk);
1263 clk_disable_unprepare(mehci->cal_clk);
1264 clk_disable_unprepare(mehci->ahb_clk);
1265 }
Vijayavardhan Vennapusa39025fe2011-10-15 05:55:10 +05301266 clk_put(mehci->ahb_clk);
1267put_cal_clk:
1268 clk_put(mehci->cal_clk);
Manu Gautam5143b252012-01-05 19:25:23 -08001269put_phy_clk:
1270 clk_put(mehci->phy_clk);
1271put_alt_core_clk:
1272 clk_put(mehci->alt_core_clk);
1273put_core_clk:
1274 clk_put(mehci->core_clk);
Vijayavardhan Vennapusa39025fe2011-10-15 05:55:10 +05301275
1276 return ret;
1277}
Vamsi Krishna34f01582011-12-14 19:54:42 -08001278static irqreturn_t hsic_peripheral_status_change(int irq, void *dev_id)
1279{
1280 struct msm_hsic_hcd *mehci = dev_id;
1281
Vamsi Krishna6921cbe2012-02-21 18:34:43 -08001282 pr_debug("%s: mehci:%p dev_id:%p\n", __func__, mehci, dev_id);
Vamsi Krishna34f01582011-12-14 19:54:42 -08001283
1284 if (mehci)
1285 msm_hsic_config_gpios(mehci, 0);
1286
1287 return IRQ_HANDLED;
1288}
1289
Vamsi Krishna6921cbe2012-02-21 18:34:43 -08001290static irqreturn_t msm_hsic_wakeup_irq(int irq, void *data)
1291{
1292 struct msm_hsic_hcd *mehci = data;
Ajay Dudanid666daf2012-09-27 12:04:12 +05301293 int ret;
Vamsi Krishna6921cbe2012-02-21 18:34:43 -08001294
Hemant Kumar6fd65032012-05-23 13:02:24 -07001295 mehci->wakeup_int_cnt++;
Hemant Kumar45d211b2012-05-31 17:58:43 -07001296 dbg_log_event(NULL, "Remote Wakeup IRQ", mehci->wakeup_int_cnt);
Hemant Kumar6fd65032012-05-23 13:02:24 -07001297 dev_dbg(mehci->dev, "%s: hsic remote wakeup interrupt cnt: %u\n",
1298 __func__, mehci->wakeup_int_cnt);
1299
Ajay Dudaniab3bf192012-08-28 09:58:04 -07001300 wake_lock(&mehci->wlock);
Vamsi Krishna6921cbe2012-02-21 18:34:43 -08001301
Hemant Kumar4cd49e12012-09-06 19:57:14 -07001302 spin_lock(&mehci->wakeup_lock);
Jack Phamfe441ea2012-03-23 17:03:15 -07001303 if (mehci->wakeup_irq_enabled) {
1304 mehci->wakeup_irq_enabled = 0;
1305 disable_irq_wake(irq);
1306 disable_irq_nosync(irq);
1307 }
Hemant Kumar4cd49e12012-09-06 19:57:14 -07001308 spin_unlock(&mehci->wakeup_lock);
Jack Phamfe441ea2012-03-23 17:03:15 -07001309
Ajay Dudaniab3bf192012-08-28 09:58:04 -07001310 if (!atomic_read(&mehci->pm_usage_cnt)) {
Ajay Dudanid666daf2012-09-27 12:04:12 +05301311 ret = pm_runtime_get(mehci->dev);
1312 /*
1313 * HSIC runtime resume can race with us.
1314 * if we are active (ret == 1) or resuming
1315 * (ret == -EINPROGRESS), decrement the
1316 * PM usage counter before returning.
1317 */
1318 if ((ret == 1) || (ret == -EINPROGRESS))
1319 pm_runtime_put_noidle(mehci->dev);
1320 else
1321 atomic_set(&mehci->pm_usage_cnt, 1);
Ajay Dudaniab3bf192012-08-28 09:58:04 -07001322 }
1323
Vamsi Krishna6921cbe2012-02-21 18:34:43 -08001324 return IRQ_HANDLED;
1325}
1326
Hemant Kumare6275972012-02-29 20:06:21 -08001327static int ehci_hsic_msm_bus_show(struct seq_file *s, void *unused)
1328{
1329 if (debug_bus_voting_enabled)
1330 seq_printf(s, "enabled\n");
1331 else
1332 seq_printf(s, "disabled\n");
1333
1334 return 0;
1335}
1336
1337static int ehci_hsic_msm_bus_open(struct inode *inode, struct file *file)
1338{
1339 return single_open(file, ehci_hsic_msm_bus_show, inode->i_private);
1340}
1341
1342static ssize_t ehci_hsic_msm_bus_write(struct file *file,
1343 const char __user *ubuf, size_t count, loff_t *ppos)
1344{
1345 char buf[8];
1346 int ret;
1347 struct seq_file *s = file->private_data;
1348 struct msm_hsic_hcd *mehci = s->private;
1349
1350 memset(buf, 0x00, sizeof(buf));
1351
1352 if (copy_from_user(&buf, ubuf, min_t(size_t, sizeof(buf) - 1, count)))
1353 return -EFAULT;
1354
1355 if (!strncmp(buf, "enable", 6)) {
1356 /* Do not vote here. Let hsic driver decide when to vote */
1357 debug_bus_voting_enabled = true;
1358 } else {
1359 debug_bus_voting_enabled = false;
1360 if (mehci->bus_perf_client) {
1361 ret = msm_bus_scale_client_update_request(
1362 mehci->bus_perf_client, 0);
1363 if (ret)
1364 dev_err(mehci->dev, "%s: Failed to devote "
1365 "for bus bw %d\n", __func__, ret);
1366 }
1367 }
1368
1369 return count;
1370}
1371
1372const struct file_operations ehci_hsic_msm_bus_fops = {
1373 .open = ehci_hsic_msm_bus_open,
1374 .read = seq_read,
1375 .write = ehci_hsic_msm_bus_write,
1376 .llseek = seq_lseek,
1377 .release = single_release,
1378};
1379
Hemant Kumar6fd65032012-05-23 13:02:24 -07001380static int ehci_hsic_msm_wakeup_cnt_show(struct seq_file *s, void *unused)
1381{
1382 struct msm_hsic_hcd *mehci = s->private;
1383
1384 seq_printf(s, "%u\n", mehci->wakeup_int_cnt);
1385
1386 return 0;
1387}
1388
1389static int ehci_hsic_msm_wakeup_cnt_open(struct inode *inode, struct file *f)
1390{
1391 return single_open(f, ehci_hsic_msm_wakeup_cnt_show, inode->i_private);
1392}
1393
1394const struct file_operations ehci_hsic_msm_wakeup_cnt_fops = {
1395 .open = ehci_hsic_msm_wakeup_cnt_open,
1396 .read = seq_read,
1397 .llseek = seq_lseek,
1398 .release = single_release,
1399};
1400
Hemant Kumar45d211b2012-05-31 17:58:43 -07001401static int ehci_hsic_msm_data_events_show(struct seq_file *s, void *unused)
1402{
1403 unsigned long flags;
1404 unsigned i;
1405
1406 read_lock_irqsave(&dbg_hsic_data.lck, flags);
1407
1408 i = dbg_hsic_data.idx;
1409 for (dbg_inc(&i); i != dbg_hsic_data.idx; dbg_inc(&i)) {
1410 if (!strnlen(dbg_hsic_data.buf[i], DBG_MSG_LEN))
1411 continue;
1412 seq_printf(s, "%s\n", dbg_hsic_data.buf[i]);
1413 }
1414
1415 read_unlock_irqrestore(&dbg_hsic_data.lck, flags);
1416
1417 return 0;
1418}
1419
1420static int ehci_hsic_msm_data_events_open(struct inode *inode, struct file *f)
1421{
1422 return single_open(f, ehci_hsic_msm_data_events_show, inode->i_private);
1423}
1424
1425const struct file_operations ehci_hsic_msm_dbg_data_fops = {
1426 .open = ehci_hsic_msm_data_events_open,
1427 .read = seq_read,
1428 .llseek = seq_lseek,
1429 .release = single_release,
1430};
1431
1432static int ehci_hsic_msm_ctrl_events_show(struct seq_file *s, void *unused)
1433{
1434 unsigned long flags;
1435 unsigned i;
1436
1437 read_lock_irqsave(&dbg_hsic_ctrl.lck, flags);
1438
1439 i = dbg_hsic_ctrl.idx;
1440 for (dbg_inc(&i); i != dbg_hsic_ctrl.idx; dbg_inc(&i)) {
1441 if (!strnlen(dbg_hsic_ctrl.buf[i], DBG_MSG_LEN))
1442 continue;
1443 seq_printf(s, "%s\n", dbg_hsic_ctrl.buf[i]);
1444 }
1445
1446 read_unlock_irqrestore(&dbg_hsic_ctrl.lck, flags);
1447
1448 return 0;
1449}
1450
1451static int ehci_hsic_msm_ctrl_events_open(struct inode *inode, struct file *f)
1452{
1453 return single_open(f, ehci_hsic_msm_ctrl_events_show, inode->i_private);
1454}
1455
1456const struct file_operations ehci_hsic_msm_dbg_ctrl_fops = {
1457 .open = ehci_hsic_msm_ctrl_events_open,
1458 .read = seq_read,
1459 .llseek = seq_lseek,
1460 .release = single_release,
1461};
1462
Hemant Kumare6275972012-02-29 20:06:21 -08001463static struct dentry *ehci_hsic_msm_dbg_root;
1464static int ehci_hsic_msm_debugfs_init(struct msm_hsic_hcd *mehci)
1465{
1466 struct dentry *ehci_hsic_msm_dentry;
1467
1468 ehci_hsic_msm_dbg_root = debugfs_create_dir("ehci_hsic_msm_dbg", NULL);
1469
1470 if (!ehci_hsic_msm_dbg_root || IS_ERR(ehci_hsic_msm_dbg_root))
1471 return -ENODEV;
1472
1473 ehci_hsic_msm_dentry = debugfs_create_file("bus_voting",
1474 S_IRUGO | S_IWUSR,
1475 ehci_hsic_msm_dbg_root, mehci,
1476 &ehci_hsic_msm_bus_fops);
1477
1478 if (!ehci_hsic_msm_dentry) {
1479 debugfs_remove_recursive(ehci_hsic_msm_dbg_root);
1480 return -ENODEV;
1481 }
1482
Hemant Kumar6fd65032012-05-23 13:02:24 -07001483 ehci_hsic_msm_dentry = debugfs_create_file("wakeup_cnt",
1484 S_IRUGO,
1485 ehci_hsic_msm_dbg_root, mehci,
1486 &ehci_hsic_msm_wakeup_cnt_fops);
1487
1488 if (!ehci_hsic_msm_dentry) {
1489 debugfs_remove_recursive(ehci_hsic_msm_dbg_root);
1490 return -ENODEV;
1491 }
1492
Hemant Kumar45d211b2012-05-31 17:58:43 -07001493 ehci_hsic_msm_dentry = debugfs_create_file("show_ctrl_events",
1494 S_IRUGO,
1495 ehci_hsic_msm_dbg_root, mehci,
1496 &ehci_hsic_msm_dbg_ctrl_fops);
1497
1498 if (!ehci_hsic_msm_dentry) {
1499 debugfs_remove_recursive(ehci_hsic_msm_dbg_root);
1500 return -ENODEV;
1501 }
1502
1503 ehci_hsic_msm_dentry = debugfs_create_file("show_data_events",
1504 S_IRUGO,
1505 ehci_hsic_msm_dbg_root, mehci,
1506 &ehci_hsic_msm_dbg_data_fops);
1507
1508 if (!ehci_hsic_msm_dentry) {
1509 debugfs_remove_recursive(ehci_hsic_msm_dbg_root);
1510 return -ENODEV;
1511 }
1512
Hemant Kumare6275972012-02-29 20:06:21 -08001513 return 0;
1514}
1515
1516static void ehci_hsic_msm_debugfs_cleanup(void)
1517{
1518 debugfs_remove_recursive(ehci_hsic_msm_dbg_root);
1519}
1520
Vijayavardhan Vennapusa39025fe2011-10-15 05:55:10 +05301521static int __devinit ehci_hsic_msm_probe(struct platform_device *pdev)
1522{
1523 struct usb_hcd *hcd;
1524 struct resource *res;
1525 struct msm_hsic_hcd *mehci;
Vijayavardhan Vennapusa2b592824f2011-11-02 19:51:32 +05301526 struct msm_hsic_host_platform_data *pdata;
Vijayavardhan Vennapusa39025fe2011-10-15 05:55:10 +05301527 int ret;
1528
1529 dev_dbg(&pdev->dev, "ehci_msm-hsic probe\n");
1530
Vijayavardhan Vennapusaafbbb8f2012-04-13 16:28:45 +05301531 /* After parent device's probe is executed, it will be put in suspend
1532 * mode. When child device's probe is called, driver core is not
1533 * resuming parent device due to which parent will be in suspend even
1534 * though child is active. Hence resume the parent device explicitly.
1535 */
1536 if (pdev->dev.parent)
1537 pm_runtime_get_sync(pdev->dev.parent);
1538
Vijayavardhan Vennapusa39025fe2011-10-15 05:55:10 +05301539 hcd = usb_create_hcd(&msm_hsic_driver, &pdev->dev,
1540 dev_name(&pdev->dev));
1541 if (!hcd) {
1542 dev_err(&pdev->dev, "Unable to create HCD\n");
1543 return -ENOMEM;
1544 }
1545
Pavankumar Kondeti1c851692012-09-18 17:52:51 +05301546 hcd_to_bus(hcd)->skip_resume = true;
1547
Vijayavardhan Vennapusa39025fe2011-10-15 05:55:10 +05301548 hcd->irq = platform_get_irq(pdev, 0);
1549 if (hcd->irq < 0) {
1550 dev_err(&pdev->dev, "Unable to get IRQ resource\n");
1551 ret = hcd->irq;
1552 goto put_hcd;
1553 }
1554
1555 res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
1556 if (!res) {
1557 dev_err(&pdev->dev, "Unable to get memory resource\n");
1558 ret = -ENODEV;
1559 goto put_hcd;
1560 }
1561
1562 hcd->rsrc_start = res->start;
1563 hcd->rsrc_len = resource_size(res);
1564 hcd->regs = ioremap(hcd->rsrc_start, hcd->rsrc_len);
1565 if (!hcd->regs) {
1566 dev_err(&pdev->dev, "ioremap failed\n");
1567 ret = -ENOMEM;
1568 goto put_hcd;
1569 }
1570
1571 mehci = hcd_to_hsic(hcd);
1572 mehci->dev = &pdev->dev;
Ajay Dudanic4e40db2012-08-20 14:44:40 -07001573 pdata = mehci->dev->platform_data;
Vijayavardhan Vennapusa39025fe2011-10-15 05:55:10 +05301574
Hemant Kumar4cd49e12012-09-06 19:57:14 -07001575 spin_lock_init(&mehci->wakeup_lock);
1576
Hemant Kumar38ce5d82012-05-29 13:00:58 -07001577 mehci->ehci.susp_sof_bug = 1;
Vamsi Krishna8e6edcb2012-06-20 18:08:50 -07001578 mehci->ehci.reset_sof_bug = 1;
Hemant Kumar38ce5d82012-05-29 13:00:58 -07001579
Hemant Kumare4040492012-06-21 17:35:42 -07001580 mehci->ehci.resume_sof_bug = 1;
1581
Ajay Dudanic4e40db2012-08-20 14:44:40 -07001582 if (pdata)
1583 mehci->ehci.log2_irq_thresh = pdata->log2_irq_thresh;
Hemant Kumar933e0402012-05-22 11:11:40 -07001584
Vamsi Krishna34f01582011-12-14 19:54:42 -08001585 res = platform_get_resource_byname(pdev,
1586 IORESOURCE_IRQ,
1587 "peripheral_status_irq");
1588 if (res)
1589 mehci->peripheral_status_irq = res->start;
1590
Hemant Kumar6fd65032012-05-23 13:02:24 -07001591 res = platform_get_resource_byname(pdev, IORESOURCE_IO, "wakeup");
1592 if (res) {
1593 mehci->wakeup_gpio = res->start;
1594 mehci->wakeup_irq = MSM_GPIO_TO_INT(res->start);
1595 dev_dbg(mehci->dev, "wakeup_irq: %d\n", mehci->wakeup_irq);
1596 }
1597
Vijayavardhan Vennapusa39025fe2011-10-15 05:55:10 +05301598 ret = msm_hsic_init_clocks(mehci, 1);
1599 if (ret) {
1600 dev_err(&pdev->dev, "unable to initialize clocks\n");
1601 ret = -ENODEV;
1602 goto unmap;
1603 }
1604
1605 ret = msm_hsic_init_vddcx(mehci, 1);
1606 if (ret) {
1607 dev_err(&pdev->dev, "unable to initialize VDDCX\n");
1608 ret = -ENODEV;
1609 goto deinit_clocks;
1610 }
1611
Ajay Dudani11ab1d52012-08-17 17:12:26 -07001612 init_completion(&mehci->rt_completion);
1613 init_completion(&mehci->gpt0_completion);
Vijayavardhan Vennapusa39025fe2011-10-15 05:55:10 +05301614 ret = msm_hsic_reset(mehci);
1615 if (ret) {
1616 dev_err(&pdev->dev, "unable to initialize PHY\n");
Vijayavardhan Vennapusaafbbb8f2012-04-13 16:28:45 +05301617 goto deinit_vddcx;
Vijayavardhan Vennapusa39025fe2011-10-15 05:55:10 +05301618 }
1619
Hemant Kumar2309eaa2012-08-14 16:46:42 -07001620 ehci_wq = create_singlethread_workqueue("ehci_wq");
1621 if (!ehci_wq) {
1622 dev_err(&pdev->dev, "unable to create workqueue\n");
1623 ret = -ENOMEM;
1624 goto deinit_vddcx;
1625 }
1626
1627 INIT_WORK(&mehci->bus_vote_w, ehci_hsic_bus_vote_w);
1628
Vijayavardhan Vennapusa39025fe2011-10-15 05:55:10 +05301629 ret = usb_add_hcd(hcd, hcd->irq, IRQF_SHARED);
1630 if (ret) {
1631 dev_err(&pdev->dev, "unable to register HCD\n");
Vijayavardhan Vennapusae3316a12011-10-15 06:05:17 +05301632 goto unconfig_gpio;
Vijayavardhan Vennapusa39025fe2011-10-15 05:55:10 +05301633 }
1634
1635 device_init_wakeup(&pdev->dev, 1);
Ajay Dudaniab3bf192012-08-28 09:58:04 -07001636 wake_lock_init(&mehci->wlock, WAKE_LOCK_SUSPEND, dev_name(&pdev->dev));
1637 wake_lock(&mehci->wlock);
Vamsi Krishna34f01582011-12-14 19:54:42 -08001638
1639 if (mehci->peripheral_status_irq) {
1640 ret = request_threaded_irq(mehci->peripheral_status_irq,
1641 NULL, hsic_peripheral_status_change,
1642 IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING
1643 | IRQF_SHARED,
1644 "hsic_peripheral_status", mehci);
1645 if (ret)
1646 dev_err(&pdev->dev, "%s:request_irq:%d failed:%d",
1647 __func__, mehci->peripheral_status_irq, ret);
1648 }
1649
Vamsi Krishna6921cbe2012-02-21 18:34:43 -08001650 /* configure wakeup irq */
Hemant Kumar6fd65032012-05-23 13:02:24 -07001651 if (mehci->wakeup_irq) {
Hemant Kumar5e386632012-08-30 14:23:38 -07001652 /* In case if wakeup gpio is pulled high at this point
1653 * remote wakeup interrupt fires right after request_irq.
1654 * Remote wake up interrupt only needs to be enabled when
1655 * HSIC bus goes to suspend.
1656 */
1657 irq_set_status_flags(mehci->wakeup_irq, IRQ_NOAUTOEN);
Vamsi Krishna6921cbe2012-02-21 18:34:43 -08001658 ret = request_irq(mehci->wakeup_irq, msm_hsic_wakeup_irq,
Hemant Kumar6fd65032012-05-23 13:02:24 -07001659 IRQF_TRIGGER_HIGH,
Vamsi Krishna6921cbe2012-02-21 18:34:43 -08001660 "msm_hsic_wakeup", mehci);
Hemant Kumar5e386632012-08-30 14:23:38 -07001661 if (ret) {
Vamsi Krishna6921cbe2012-02-21 18:34:43 -08001662 dev_err(&pdev->dev, "request_irq(%d) failed: %d\n",
1663 mehci->wakeup_irq, ret);
1664 mehci->wakeup_irq = 0;
1665 }
1666 }
1667
Hemant Kumare6275972012-02-29 20:06:21 -08001668 ret = ehci_hsic_msm_debugfs_init(mehci);
1669 if (ret)
1670 dev_dbg(&pdev->dev, "mode debugfs file is"
1671 "not available\n");
1672
1673 if (pdata && pdata->bus_scale_table) {
1674 mehci->bus_perf_client =
1675 msm_bus_scale_register_client(pdata->bus_scale_table);
1676 /* Configure BUS performance parameters for MAX bandwidth */
1677 if (mehci->bus_perf_client) {
Hemant Kumar2309eaa2012-08-14 16:46:42 -07001678 mehci->bus_vote = true;
1679 queue_work(ehci_wq, &mehci->bus_vote_w);
Hemant Kumare6275972012-02-29 20:06:21 -08001680 } else {
1681 dev_err(&pdev->dev, "%s: Failed to register BUS "
1682 "scaling client!!\n", __func__);
1683 }
1684 }
1685
Hemant Kumar105d07f2012-07-02 15:33:07 -07001686 __mehci = mehci;
1687
Pavankumar Kondetife2d4d32012-09-07 15:33:09 +05301688 if (pdata && pdata->swfi_latency)
1689 pm_qos_add_request(&mehci->pm_qos_req_dma,
1690 PM_QOS_CPU_DMA_LATENCY, PM_QOS_DEFAULT_VALUE);
1691
Vijayavardhan Vennapusa39025fe2011-10-15 05:55:10 +05301692 /*
1693 * This pdev->dev is assigned parent of root-hub by USB core,
1694 * hence, runtime framework automatically calls this driver's
1695 * runtime APIs based on root-hub's state.
1696 */
1697 pm_runtime_set_active(&pdev->dev);
1698 pm_runtime_enable(&pdev->dev);
Vijayavardhan Vennapusaafbbb8f2012-04-13 16:28:45 +05301699 /* Decrement the parent device's counter after probe.
1700 * As child is active, parent will not be put into
1701 * suspend mode.
1702 */
1703 if (pdev->dev.parent)
1704 pm_runtime_put_sync(pdev->dev.parent);
Vijayavardhan Vennapusa39025fe2011-10-15 05:55:10 +05301705
1706 return 0;
1707
Vijayavardhan Vennapusae3316a12011-10-15 06:05:17 +05301708unconfig_gpio:
Hemant Kumar2309eaa2012-08-14 16:46:42 -07001709 destroy_workqueue(ehci_wq);
Vijayavardhan Vennapusae3316a12011-10-15 06:05:17 +05301710 msm_hsic_config_gpios(mehci, 0);
Vijayavardhan Vennapusa39025fe2011-10-15 05:55:10 +05301711deinit_vddcx:
1712 msm_hsic_init_vddcx(mehci, 0);
1713deinit_clocks:
1714 msm_hsic_init_clocks(mehci, 0);
1715unmap:
1716 iounmap(hcd->regs);
1717put_hcd:
1718 usb_put_hcd(hcd);
1719
1720 return ret;
1721}
1722
1723static int __devexit ehci_hsic_msm_remove(struct platform_device *pdev)
1724{
1725 struct usb_hcd *hcd = platform_get_drvdata(pdev);
1726 struct msm_hsic_hcd *mehci = hcd_to_hsic(hcd);
Pavankumar Kondetife2d4d32012-09-07 15:33:09 +05301727 struct msm_hsic_host_platform_data *pdata = mehci->dev->platform_data;
1728
1729 if (pdata && pdata->swfi_latency)
1730 pm_qos_remove_request(&mehci->pm_qos_req_dma);
Vijayavardhan Vennapusa39025fe2011-10-15 05:55:10 +05301731
Vamsi Krishna34f01582011-12-14 19:54:42 -08001732 if (mehci->peripheral_status_irq)
1733 free_irq(mehci->peripheral_status_irq, mehci);
Jack Phamfe441ea2012-03-23 17:03:15 -07001734
Vamsi Krishna6921cbe2012-02-21 18:34:43 -08001735 if (mehci->wakeup_irq) {
Jack Phamfe441ea2012-03-23 17:03:15 -07001736 if (mehci->wakeup_irq_enabled)
1737 disable_irq_wake(mehci->wakeup_irq);
Vamsi Krishna6921cbe2012-02-21 18:34:43 -08001738 free_irq(mehci->wakeup_irq, mehci);
1739 }
Vamsi Krishna34f01582011-12-14 19:54:42 -08001740
Hemant Kumar2309eaa2012-08-14 16:46:42 -07001741 /*
1742 * If the update request is called after unregister, the request will
1743 * fail. Results are undefined if unregister is called in the middle of
1744 * update request.
1745 */
1746 mehci->bus_vote = false;
1747 cancel_work_sync(&mehci->bus_vote_w);
1748
Hemant Kumare6275972012-02-29 20:06:21 -08001749 if (mehci->bus_perf_client)
1750 msm_bus_scale_unregister_client(mehci->bus_perf_client);
1751
1752 ehci_hsic_msm_debugfs_cleanup();
Vijayavardhan Vennapusa39025fe2011-10-15 05:55:10 +05301753 device_init_wakeup(&pdev->dev, 0);
Vijayavardhan Vennapusa39025fe2011-10-15 05:55:10 +05301754 pm_runtime_set_suspended(&pdev->dev);
1755
Hemant Kumar2309eaa2012-08-14 16:46:42 -07001756 destroy_workqueue(ehci_wq);
1757
Vijayavardhan Vennapusa39025fe2011-10-15 05:55:10 +05301758 usb_remove_hcd(hcd);
Vijayavardhan Vennapusae3316a12011-10-15 06:05:17 +05301759 msm_hsic_config_gpios(mehci, 0);
Vijayavardhan Vennapusa39025fe2011-10-15 05:55:10 +05301760 msm_hsic_init_vddcx(mehci, 0);
1761
1762 msm_hsic_init_clocks(mehci, 0);
Ajay Dudaniab3bf192012-08-28 09:58:04 -07001763 wake_lock_destroy(&mehci->wlock);
Vijayavardhan Vennapusa39025fe2011-10-15 05:55:10 +05301764 iounmap(hcd->regs);
1765 usb_put_hcd(hcd);
1766
1767 return 0;
1768}
1769
1770#ifdef CONFIG_PM_SLEEP
1771static int msm_hsic_pm_suspend(struct device *dev)
1772{
Jack Phambe05fbb2012-05-16 10:56:26 -07001773 int ret;
Vijayavardhan Vennapusa39025fe2011-10-15 05:55:10 +05301774 struct usb_hcd *hcd = dev_get_drvdata(dev);
1775 struct msm_hsic_hcd *mehci = hcd_to_hsic(hcd);
1776
1777 dev_dbg(dev, "ehci-msm-hsic PM suspend\n");
1778
Hemant Kumar45d211b2012-05-31 17:58:43 -07001779 dbg_log_event(NULL, "PM Suspend", 0);
1780
Vijayavardhan Vennapusa39025fe2011-10-15 05:55:10 +05301781 if (device_may_wakeup(dev))
1782 enable_irq_wake(hcd->irq);
1783
Jack Phambe05fbb2012-05-16 10:56:26 -07001784 ret = msm_hsic_suspend(mehci);
1785
1786 if (ret && device_may_wakeup(dev))
1787 disable_irq_wake(hcd->irq);
1788
1789 return ret;
Jack Phamfe441ea2012-03-23 17:03:15 -07001790}
Vijayavardhan Vennapusa39025fe2011-10-15 05:55:10 +05301791
Jack Pham16b06f82012-08-14 20:03:59 -07001792static int msm_hsic_pm_suspend_noirq(struct device *dev)
1793{
1794 struct usb_hcd *hcd = dev_get_drvdata(dev);
1795 struct msm_hsic_hcd *mehci = hcd_to_hsic(hcd);
1796
Pavankumar Kondetibbd05822013-01-28 17:04:39 +05301797 if (atomic_read(&mehci->async_int)) {
Jack Pham16b06f82012-08-14 20:03:59 -07001798 dev_dbg(dev, "suspend_noirq: Aborting due to pending interrupt\n");
1799 return -EBUSY;
1800 }
1801
1802 return 0;
1803}
1804
Vijayavardhan Vennapusa39025fe2011-10-15 05:55:10 +05301805static int msm_hsic_pm_resume(struct device *dev)
1806{
1807 int ret;
1808 struct usb_hcd *hcd = dev_get_drvdata(dev);
1809 struct msm_hsic_hcd *mehci = hcd_to_hsic(hcd);
1810
Jack Pham16b06f82012-08-14 20:03:59 -07001811 dev_dbg(dev, "ehci-msm-hsic PM resume\n");
Hemant Kumar45d211b2012-05-31 17:58:43 -07001812 dbg_log_event(NULL, "PM Resume", 0);
1813
Vijayavardhan Vennapusa39025fe2011-10-15 05:55:10 +05301814 if (device_may_wakeup(dev))
1815 disable_irq_wake(hcd->irq);
1816
Pavankumar Kondeti1c851692012-09-18 17:52:51 +05301817 /*
1818 * Keep HSIC in Low Power Mode if system is resumed
1819 * by any other wakeup source. HSIC is resumed later
1820 * when remote wakeup is received or interface driver
1821 * start I/O.
1822 */
Pavankumar Kondeti98089c02012-11-09 10:54:00 +05301823 if (!atomic_read(&mehci->pm_usage_cnt) &&
Pavankumar Kondetibbd05822013-01-28 17:04:39 +05301824 !atomic_read(&mehci->async_int) &&
Pavankumar Kondeti98089c02012-11-09 10:54:00 +05301825 pm_runtime_suspended(dev))
Pavankumar Kondeti1c851692012-09-18 17:52:51 +05301826 return 0;
1827
Vijayavardhan Vennapusa39025fe2011-10-15 05:55:10 +05301828 ret = msm_hsic_resume(mehci);
1829 if (ret)
1830 return ret;
1831
1832 /* Bring the device to full powered state upon system resume */
1833 pm_runtime_disable(dev);
1834 pm_runtime_set_active(dev);
1835 pm_runtime_enable(dev);
1836
1837 return 0;
1838}
1839#endif
1840
1841#ifdef CONFIG_PM_RUNTIME
1842static int msm_hsic_runtime_idle(struct device *dev)
1843{
1844 dev_dbg(dev, "EHCI runtime idle\n");
Vijayavardhan Vennapusa39025fe2011-10-15 05:55:10 +05301845 return 0;
1846}
1847
1848static int msm_hsic_runtime_suspend(struct device *dev)
1849{
1850 struct usb_hcd *hcd = dev_get_drvdata(dev);
1851 struct msm_hsic_hcd *mehci = hcd_to_hsic(hcd);
1852
1853 dev_dbg(dev, "EHCI runtime suspend\n");
Hemant Kumar45d211b2012-05-31 17:58:43 -07001854
1855 dbg_log_event(NULL, "Run Time PM Suspend", 0);
1856
Vijayavardhan Vennapusa39025fe2011-10-15 05:55:10 +05301857 return msm_hsic_suspend(mehci);
1858}
1859
1860static int msm_hsic_runtime_resume(struct device *dev)
1861{
1862 struct usb_hcd *hcd = dev_get_drvdata(dev);
1863 struct msm_hsic_hcd *mehci = hcd_to_hsic(hcd);
1864
1865 dev_dbg(dev, "EHCI runtime resume\n");
Hemant Kumar45d211b2012-05-31 17:58:43 -07001866
1867 dbg_log_event(NULL, "Run Time PM Resume", 0);
1868
Vijayavardhan Vennapusa39025fe2011-10-15 05:55:10 +05301869 return msm_hsic_resume(mehci);
1870}
1871#endif
1872
1873#ifdef CONFIG_PM
1874static const struct dev_pm_ops msm_hsic_dev_pm_ops = {
1875 SET_SYSTEM_SLEEP_PM_OPS(msm_hsic_pm_suspend, msm_hsic_pm_resume)
Jack Pham16b06f82012-08-14 20:03:59 -07001876 .suspend_noirq = msm_hsic_pm_suspend_noirq,
Vijayavardhan Vennapusa39025fe2011-10-15 05:55:10 +05301877 SET_RUNTIME_PM_OPS(msm_hsic_runtime_suspend, msm_hsic_runtime_resume,
1878 msm_hsic_runtime_idle)
1879};
1880#endif
1881
1882static struct platform_driver ehci_msm_hsic_driver = {
1883 .probe = ehci_hsic_msm_probe,
1884 .remove = __devexit_p(ehci_hsic_msm_remove),
1885 .driver = {
1886 .name = "msm_hsic_host",
1887#ifdef CONFIG_PM
1888 .pm = &msm_hsic_dev_pm_ops,
1889#endif
1890 },
1891};