blob: 0ed08bee040462ca419481833d97d9b693f869c8 [file] [log] [blame]
Duy Truong790f06d2013-02-13 16:38:12 -08001/* Copyright (c) 2012, The Linux Foundation. All rights reserved.
Ofir Cohen06789f12012-01-16 09:43:13 +02002 *
3 * This program is free software; you can redistribute it and/or modify
4 * it under the terms of the GNU General Public License version 2 and
5 * only version 2 as published by the Free Software Foundation.
6 *
7 * This program is distributed in the hope that it will be useful,
8 * but WITHOUT ANY WARRANTY; without even the implied warranty of
9 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10 * GNU General Public License for more details.
11 */
12
13#include <linux/platform_device.h>
14#include <linux/clk.h>
15#include <linux/err.h>
16#include <linux/wakelock.h>
17#include <linux/pm_runtime.h>
18#include <linux/regulator/consumer.h>
19#include <linux/dma-mapping.h>
20#include <linux/slab.h>
21#include <linux/gpio.h>
22#include <linux/delay.h>
23#include <linux/device.h>
24#include <linux/usb.h>
25
26#include <linux/usb/gadget.h>
27#include <linux/usb/msm_hsusb_hw.h>
28#include <linux/usb/msm_hsusb.h>
29
30#include <mach/clk.h>
31#include <mach/msm_iomap.h>
32#include <mach/msm_xo.h>
Amit Blayd6ea6102012-06-07 16:26:24 +030033#include <mach/rpm-regulator.h>
Ofir Cohen06789f12012-01-16 09:43:13 +020034
35#include "ci13xxx_udc.c"
36
37#define MSM_USB_BASE (mhsic->regs)
38
Ofir Cohendca06cb2012-03-08 16:37:45 +020039#define ULPI_IO_TIMEOUT_USEC (10 * 1000)
Amit Blayd6ea6102012-06-07 16:26:24 +030040#define USB_PHY_VDD_DIG_VOL_NONE 0 /*uV */
Ofir Cohendca06cb2012-03-08 16:37:45 +020041#define USB_PHY_VDD_DIG_VOL_MIN 1045000 /* uV */
42#define USB_PHY_VDD_DIG_VOL_MAX 1320000 /* uV */
Ofir Cohendca06cb2012-03-08 16:37:45 +020043#define LINK_RESET_TIMEOUT_USEC (250 * 1000)
44#define PHY_SUSPEND_TIMEOUT_USEC (500 * 1000)
45#define PHY_RESUME_TIMEOUT_USEC (100 * 1000)
46#define HSIC_CFG_REG 0x30
47#define HSIC_IO_CAL_PER_REG 0x33
48#define HSIC_DBG1_REG 0x38
Ofir Cohen06789f12012-01-16 09:43:13 +020049
50struct msm_hsic_per *the_mhsic;
51
52struct msm_hsic_per {
53 struct device *dev;
54 struct clk *iface_clk;
55 struct clk *core_clk;
56 struct clk *alt_core_clk;
57 struct clk *phy_clk;
58 struct clk *cal_clk;
59 struct regulator *hsic_vddcx;
60 bool async_int;
61 void __iomem *regs;
62 int irq;
Ofir Cohendca06cb2012-03-08 16:37:45 +020063 atomic_t in_lpm;
64 struct wake_lock wlock;
65 struct msm_xo_voter *xo_handle;
66 struct workqueue_struct *wq;
67 struct work_struct suspend_w;
Amit Blay4d57d362012-04-28 11:00:21 +030068 struct msm_hsic_peripheral_platform_data *pdata;
Amit Blayd6ea6102012-06-07 16:26:24 +030069 enum usb_vdd_type vdd_type;
Ido Shayevitzab601632012-09-16 15:11:26 +030070 bool connected;
Amit Blayd6ea6102012-06-07 16:26:24 +030071};
72
73static const int vdd_val[VDD_TYPE_MAX][VDD_VAL_MAX] = {
74 { /* VDD_CX CORNER Voting */
75 [VDD_NONE] = RPM_VREG_CORNER_NONE,
76 [VDD_MIN] = RPM_VREG_CORNER_NOMINAL,
77 [VDD_MAX] = RPM_VREG_CORNER_HIGH,
78 },
79 { /* VDD_CX Voltage Voting */
80 [VDD_NONE] = USB_PHY_VDD_DIG_VOL_NONE,
81 [VDD_MIN] = USB_PHY_VDD_DIG_VOL_MIN,
82 [VDD_MAX] = USB_PHY_VDD_DIG_VOL_MAX,
83 },
Ofir Cohen06789f12012-01-16 09:43:13 +020084};
85
86static int msm_hsic_init_vddcx(struct msm_hsic_per *mhsic, int init)
87{
88 int ret = 0;
Amit Blayd6ea6102012-06-07 16:26:24 +030089 int none_vol, min_vol, max_vol;
90
91 if (!mhsic->hsic_vddcx) {
92 mhsic->vdd_type = VDDCX_CORNER;
93 mhsic->hsic_vddcx = devm_regulator_get(mhsic->dev,
94 "hsic_vdd_dig");
95 if (IS_ERR(mhsic->hsic_vddcx)) {
96 mhsic->hsic_vddcx = devm_regulator_get(mhsic->dev,
97 "HSIC_VDDCX");
98 if (IS_ERR(mhsic->hsic_vddcx)) {
99 dev_err(mhsic->dev, "unable to get hsic vddcx\n");
100 return PTR_ERR(mhsic->hsic_vddcx);
101 }
102 mhsic->vdd_type = VDDCX;
103 }
104 }
105
106 none_vol = vdd_val[mhsic->vdd_type][VDD_NONE];
107 min_vol = vdd_val[mhsic->vdd_type][VDD_MIN];
108 max_vol = vdd_val[mhsic->vdd_type][VDD_MAX];
Ofir Cohen06789f12012-01-16 09:43:13 +0200109
110 if (!init)
111 goto disable_reg;
112
Amit Blayd6ea6102012-06-07 16:26:24 +0300113 ret = regulator_set_voltage(mhsic->hsic_vddcx, min_vol, max_vol);
Ofir Cohen06789f12012-01-16 09:43:13 +0200114 if (ret) {
115 dev_err(mhsic->dev, "unable to set the voltage"
116 "for hsic vddcx\n");
117 goto reg_set_voltage_err;
118 }
119
Ofir Cohen06789f12012-01-16 09:43:13 +0200120 ret = regulator_enable(mhsic->hsic_vddcx);
121 if (ret) {
122 dev_err(mhsic->dev, "unable to enable hsic vddcx\n");
123 goto reg_enable_err;
124 }
125
126 return 0;
127
128disable_reg:
129 regulator_disable(mhsic->hsic_vddcx);
130reg_enable_err:
Amit Blayd6ea6102012-06-07 16:26:24 +0300131 regulator_set_voltage(mhsic->hsic_vddcx, none_vol, max_vol);
Ofir Cohen06789f12012-01-16 09:43:13 +0200132reg_set_voltage_err:
Ofir Cohen06789f12012-01-16 09:43:13 +0200133
134 return ret;
135
136}
137
138static int ulpi_write(struct msm_hsic_per *mhsic, u32 val, u32 reg)
139{
140 int cnt = 0;
141
142 /* initiate write operation */
143 writel_relaxed(ULPI_RUN | ULPI_WRITE |
144 ULPI_ADDR(reg) | ULPI_DATA(val),
145 USB_ULPI_VIEWPORT);
146
147 /* wait for completion */
148 while (cnt < ULPI_IO_TIMEOUT_USEC) {
149 if (!(readl_relaxed(USB_ULPI_VIEWPORT) & ULPI_RUN))
150 break;
151 udelay(1);
152 cnt++;
153 }
154
155 if (cnt >= ULPI_IO_TIMEOUT_USEC) {
156 dev_err(mhsic->dev, "ulpi_write: timeout\n");
157 return -ETIMEDOUT;
158 }
159
160 return 0;
161}
162
163static int msm_hsic_phy_clk_reset(struct msm_hsic_per *mhsic)
164{
165 int ret;
166
167 ret = clk_reset(mhsic->core_clk, CLK_RESET_ASSERT);
168 if (ret) {
169 clk_disable(mhsic->alt_core_clk);
170 dev_err(mhsic->dev, "usb phy clk assert failed\n");
171 return ret;
172 }
173 usleep_range(10000, 12000);
174 clk_disable(mhsic->alt_core_clk);
175
176 ret = clk_reset(mhsic->core_clk, CLK_RESET_DEASSERT);
177 if (ret)
178 dev_err(mhsic->dev, "usb phy clk deassert failed\n");
179
180 return ret;
181}
182
183static int msm_hsic_phy_reset(struct msm_hsic_per *mhsic)
184{
185 u32 val;
186 int ret;
187
188 ret = msm_hsic_phy_clk_reset(mhsic);
189 if (ret)
190 return ret;
191
192 val = readl_relaxed(USB_PORTSC) & ~PORTSC_PTS_MASK;
193 writel_relaxed(val | PORTSC_PTS_ULPI, USB_PORTSC);
194
195 /*
196 * Ensure that RESET operation is completed before
197 * turning off clock.
198 */
199 mb();
200 dev_dbg(mhsic->dev, "phy_reset: success\n");
201
202 return 0;
203}
204
205static int msm_hsic_enable_clocks(struct platform_device *pdev,
206 struct msm_hsic_per *mhsic, bool enable)
207{
208 int ret = 0;
209
210 if (!enable)
211 goto put_clocks;
212
213 mhsic->iface_clk = clk_get(&pdev->dev, "iface_clk");
214 if (IS_ERR(mhsic->iface_clk)) {
215 dev_err(mhsic->dev, "failed to get iface_clk\n");
216 ret = PTR_ERR(mhsic->iface_clk);
217 goto put_iface_clk;
218 }
219
220 mhsic->core_clk = clk_get(&pdev->dev, "core_clk");
221 if (IS_ERR(mhsic->core_clk)) {
222 dev_err(mhsic->dev, "failed to get core_clk\n");
223 ret = PTR_ERR(mhsic->core_clk);
224 goto put_core_clk;
225 }
226
227 mhsic->phy_clk = clk_get(&pdev->dev, "phy_clk");
228 if (IS_ERR(mhsic->phy_clk)) {
229 dev_err(mhsic->dev, "failed to get phy_clk\n");
230 ret = PTR_ERR(mhsic->phy_clk);
231 goto put_phy_clk;
232 }
233
234 mhsic->alt_core_clk = clk_get(&pdev->dev, "alt_core_clk");
235 if (IS_ERR(mhsic->alt_core_clk)) {
236 dev_err(mhsic->dev, "failed to get alt_core_clk\n");
237 ret = PTR_ERR(mhsic->alt_core_clk);
238 goto put_alt_core_clk;
239 }
240
241 mhsic->cal_clk = clk_get(&pdev->dev, "cal_clk");
242 if (IS_ERR(mhsic->cal_clk)) {
243 dev_err(mhsic->dev, "failed to get cal_clk\n");
244 ret = PTR_ERR(mhsic->cal_clk);
245 goto put_cal_clk;
246 }
247
Vikram Mulukutla01144db2012-08-06 13:48:28 -0700248 clk_prepare_enable(mhsic->iface_clk);
249 clk_prepare_enable(mhsic->core_clk);
250 clk_prepare_enable(mhsic->phy_clk);
251 clk_prepare_enable(mhsic->alt_core_clk);
252 clk_prepare_enable(mhsic->cal_clk);
Ofir Cohen06789f12012-01-16 09:43:13 +0200253
254 return 0;
255
256put_clocks:
Vikram Mulukutla01144db2012-08-06 13:48:28 -0700257 clk_disable_unprepare(mhsic->iface_clk);
258 clk_disable_unprepare(mhsic->core_clk);
259 clk_disable_unprepare(mhsic->phy_clk);
260 clk_disable_unprepare(mhsic->alt_core_clk);
261 clk_disable_unprepare(mhsic->cal_clk);
Ofir Cohen06789f12012-01-16 09:43:13 +0200262put_cal_clk:
263 clk_put(mhsic->cal_clk);
264put_alt_core_clk:
265 clk_put(mhsic->alt_core_clk);
266put_phy_clk:
267 clk_put(mhsic->phy_clk);
268put_core_clk:
269 clk_put(mhsic->core_clk);
270put_iface_clk:
271 clk_put(mhsic->iface_clk);
272
273 return ret;
274}
275
276static int msm_hsic_reset(struct msm_hsic_per *mhsic)
277{
278 int cnt = 0;
279 int ret;
280
281 ret = msm_hsic_phy_reset(mhsic);
282 if (ret) {
283 dev_err(mhsic->dev, "phy_reset failed\n");
284 return ret;
285 }
286
287 writel_relaxed(USBCMD_RESET, USB_USBCMD);
288 while (cnt < LINK_RESET_TIMEOUT_USEC) {
289 if (!(readl_relaxed(USB_USBCMD) & USBCMD_RESET))
290 break;
291 udelay(1);
292 cnt++;
293 }
294 if (cnt >= LINK_RESET_TIMEOUT_USEC)
295 return -ETIMEDOUT;
296
297 /* Reset PORTSC and select ULPI phy */
298 writel_relaxed(0x80000000, USB_PORTSC);
299 return 0;
300}
301
Amit Blay725cdeb2012-04-30 14:20:56 +0300302static void msm_hsic_wakeup(void)
303{
304 if (atomic_read(&the_mhsic->in_lpm))
305 pm_runtime_resume(the_mhsic->dev);
306}
307
Ofir Cohen06789f12012-01-16 09:43:13 +0200308static void msm_hsic_start(void)
309{
310 int ret;
311
312 /* programmable length of connect signaling (33.2ns) */
313 ret = ulpi_write(the_mhsic, 3, HSIC_DBG1_REG);
314 if (ret) {
315 pr_err("%s: Unable to program length of connect signaling\n",
316 __func__);
317 }
318
319 /*set periodic calibration interval to ~2.048sec in HSIC_IO_CAL_REG */
320 ret = ulpi_write(the_mhsic, 0xFF, HSIC_IO_CAL_PER_REG);
321
322 if (ret) {
323 pr_err("%s: Unable to set periodic calibration interval\n",
324 __func__);
325 }
326
327 /* Enable periodic IO calibration in HSIC_CFG register */
328 ret = ulpi_write(the_mhsic, 0xE9, HSIC_CFG_REG);
329 if (ret) {
330 pr_err("%s: Unable to enable periodic IO calibration\n",
331 __func__);
332 }
333}
334
Ofir Cohendca06cb2012-03-08 16:37:45 +0200335
336#ifdef CONFIG_PM_SLEEP
337static int msm_hsic_suspend(struct msm_hsic_per *mhsic)
338{
339 int cnt = 0, ret;
340 u32 val;
Amit Blayd6ea6102012-06-07 16:26:24 +0300341 int none_vol, max_vol;
Ofir Cohendca06cb2012-03-08 16:37:45 +0200342
343 if (atomic_read(&mhsic->in_lpm)) {
344 dev_dbg(mhsic->dev, "%s called while in lpm\n", __func__);
345 return 0;
346 }
347 disable_irq(mhsic->irq);
348
349 /*
350 * PHY may take some time or even fail to enter into low power
351 * mode (LPM). Hence poll for 500 msec and reset the PHY and link
352 * in failure case.
353 */
354 val = readl_relaxed(USB_PORTSC) | PORTSC_PHCD;
355 writel_relaxed(val, USB_PORTSC);
356
357 while (cnt < PHY_SUSPEND_TIMEOUT_USEC) {
358 if (readl_relaxed(USB_PORTSC) & PORTSC_PHCD)
359 break;
360 udelay(1);
361 cnt++;
362 }
363
364 if (cnt >= PHY_SUSPEND_TIMEOUT_USEC) {
365 dev_err(mhsic->dev, "Unable to suspend PHY\n");
366 msm_hsic_reset(mhsic);
367 }
368
369 /*
370 * PHY has capability to generate interrupt asynchronously in low
371 * power mode (LPM). This interrupt is level triggered. So USB IRQ
372 * line must be disabled till async interrupt enable bit is cleared
373 * in USBCMD register. Assert STP (ULPI interface STOP signal) to
374 * block data communication from PHY.
375 */
376 writel_relaxed(readl_relaxed(USB_USBCMD) | ASYNC_INTR_CTRL |
377 ULPI_STP_CTRL, USB_USBCMD);
378
379 /*
380 * Ensure that hardware is put in low power mode before
381 * clocks are turned OFF and VDD is allowed to minimize.
382 */
383 mb();
384
Ido Shayevitzab601632012-09-16 15:11:26 +0300385 if (!mhsic->pdata->core_clk_always_on_workaround || !mhsic->connected) {
Amit Blay4d57d362012-04-28 11:00:21 +0300386 clk_disable(mhsic->iface_clk);
387 clk_disable(mhsic->core_clk);
388 }
Ofir Cohendca06cb2012-03-08 16:37:45 +0200389 clk_disable(mhsic->phy_clk);
390 clk_disable(mhsic->cal_clk);
391
392 ret = msm_xo_mode_vote(mhsic->xo_handle, MSM_XO_MODE_OFF);
393 if (ret)
394 dev_err(mhsic->dev, "%s failed to devote for TCXO %d\n"
395 , __func__, ret);
396
Amit Blayd6ea6102012-06-07 16:26:24 +0300397 none_vol = vdd_val[mhsic->vdd_type][VDD_NONE];
398 max_vol = vdd_val[mhsic->vdd_type][VDD_MAX];
399
400 ret = regulator_set_voltage(mhsic->hsic_vddcx, none_vol, max_vol);
Ofir Cohendca06cb2012-03-08 16:37:45 +0200401 if (ret < 0)
Amit Blayd6ea6102012-06-07 16:26:24 +0300402 dev_err(mhsic->dev, "unable to set vddcx voltage for VDD MIN\n");
Ofir Cohendca06cb2012-03-08 16:37:45 +0200403
404 if (device_may_wakeup(mhsic->dev))
405 enable_irq_wake(mhsic->irq);
406
407 atomic_set(&mhsic->in_lpm, 1);
408 enable_irq(mhsic->irq);
409 wake_unlock(&mhsic->wlock);
410
411 dev_info(mhsic->dev, "HSIC-USB in low power mode\n");
412
413 return 0;
414}
415
416static int msm_hsic_resume(struct msm_hsic_per *mhsic)
417{
418 int cnt = 0, ret;
419 unsigned temp;
Amit Blayd6ea6102012-06-07 16:26:24 +0300420 int min_vol, max_vol;
Ofir Cohendca06cb2012-03-08 16:37:45 +0200421
422 if (!atomic_read(&mhsic->in_lpm)) {
423 dev_dbg(mhsic->dev, "%s called while not in lpm\n", __func__);
424 return 0;
425 }
426
427 wake_lock(&mhsic->wlock);
Amit Blayd6ea6102012-06-07 16:26:24 +0300428
429 min_vol = vdd_val[mhsic->vdd_type][VDD_MIN];
430 max_vol = vdd_val[mhsic->vdd_type][VDD_MAX];
431
432 ret = regulator_set_voltage(mhsic->hsic_vddcx, min_vol, max_vol);
Ofir Cohendca06cb2012-03-08 16:37:45 +0200433 if (ret < 0)
434 dev_err(mhsic->dev,
Amit Blayd6ea6102012-06-07 16:26:24 +0300435 "unable to set nominal vddcx voltage (no VDD MIN)\n");
Ofir Cohendca06cb2012-03-08 16:37:45 +0200436
437 ret = msm_xo_mode_vote(mhsic->xo_handle, MSM_XO_MODE_ON);
438 if (ret)
439 dev_err(mhsic->dev, "%s failed to vote for TCXO %d\n",
440 __func__, ret);
441
Ido Shayevitzab601632012-09-16 15:11:26 +0300442 if (!mhsic->pdata->core_clk_always_on_workaround || !mhsic->connected) {
Amit Blay4d57d362012-04-28 11:00:21 +0300443 clk_enable(mhsic->iface_clk);
444 clk_enable(mhsic->core_clk);
445 }
Ofir Cohendca06cb2012-03-08 16:37:45 +0200446 clk_enable(mhsic->phy_clk);
447 clk_enable(mhsic->cal_clk);
448
449 temp = readl_relaxed(USB_USBCMD);
450 temp &= ~ASYNC_INTR_CTRL;
451 temp &= ~ULPI_STP_CTRL;
452 writel_relaxed(temp, USB_USBCMD);
453
454 if (!(readl_relaxed(USB_PORTSC) & PORTSC_PHCD))
455 goto skip_phy_resume;
456
457 temp = readl_relaxed(USB_PORTSC) & ~PORTSC_PHCD;
458 writel_relaxed(temp, USB_PORTSC);
459 while (cnt < PHY_RESUME_TIMEOUT_USEC) {
460 if (!(readl_relaxed(USB_PORTSC) & PORTSC_PHCD) &&
461 (readl_relaxed(USB_ULPI_VIEWPORT) & ULPI_SYNC_STATE))
462 break;
463 udelay(1);
464 cnt++;
465 }
466
467 if (cnt >= PHY_RESUME_TIMEOUT_USEC) {
468 /*
469 * This is a fatal error. Reset the link and
470 * PHY to make hsic working.
471 */
472 dev_err(mhsic->dev, "Unable to resume USB. Reset the hsic\n");
473 msm_hsic_reset(mhsic);
474 }
475skip_phy_resume:
476 if (device_may_wakeup(mhsic->dev))
477 disable_irq_wake(mhsic->irq);
478
479 atomic_set(&mhsic->in_lpm, 0);
480
481 if (mhsic->async_int) {
482 mhsic->async_int = false;
483 enable_irq(mhsic->irq);
484 }
485
486 dev_info(mhsic->dev, "HSIC-USB exited from low power mode\n");
487
488 return 0;
489}
490
491static int msm_hsic_pm_suspend(struct device *dev)
492{
493 struct msm_hsic_per *mhsic = dev_get_drvdata(dev);
494
495 dev_dbg(dev, "MSM HSIC Peripheral PM suspend\n");
496
497 return msm_hsic_suspend(mhsic);
498}
499
500#ifdef CONFIG_PM_RUNTIME
501static int msm_hsic_pm_resume(struct device *dev)
502{
503 dev_dbg(dev, "MSM HSIC Peripheral PM resume\n");
504
505 /*
506 * Do not resume hardware as part of system resume,
507 * rather, wait for the ASYNC INT from the h/w
508 */
509 return 0;
510}
511#else
512static int msm_hsic_pm_resume(struct device *dev)
513{
514 struct msm_hsic_per *mhsic = dev_get_drvdata(dev);
515
516 dev_dbg(dev, "MSM HSIC Peripheral PM resume\n");
517
518 return msm_hsic_resume(mhsic);
519}
520#endif
521
522static void msm_hsic_pm_suspend_work(struct work_struct *w)
523{
524 pm_runtime_put_noidle(the_mhsic->dev);
525 pm_runtime_suspend(the_mhsic->dev);
526}
527#endif /* CONFIG_PM_SLEEP */
528
529#ifdef CONFIG_PM_RUNTIME
530static int msm_hsic_runtime_idle(struct device *dev)
531{
532 dev_dbg(dev, "MSM HSIC Peripheral runtime idle\n");
533
534 return 0;
535}
536
537static int msm_hsic_runtime_suspend(struct device *dev)
538{
539 struct msm_hsic_per *mhsic = dev_get_drvdata(dev);
540
541 dev_dbg(dev, "MSM HSIC Peripheral runtime suspend\n");
542
543 return msm_hsic_suspend(mhsic);
544}
545
546static int msm_hsic_runtime_resume(struct device *dev)
547{
548 struct msm_hsic_per *mhsic = dev_get_drvdata(dev);
549
550 dev_dbg(dev, "MSM HSIC Peripheral runtime resume\n");
551 pm_runtime_get_noresume(mhsic->dev);
552
553 return msm_hsic_resume(mhsic);
554}
555#endif
556
557#ifdef CONFIG_PM
558static const struct dev_pm_ops msm_hsic_dev_pm_ops = {
559 SET_SYSTEM_SLEEP_PM_OPS(msm_hsic_pm_suspend, msm_hsic_pm_resume)
560 SET_RUNTIME_PM_OPS(msm_hsic_runtime_suspend, msm_hsic_runtime_resume,
561 msm_hsic_runtime_idle)
562};
563#endif
564
Ofir Cohen06789f12012-01-16 09:43:13 +0200565/**
566 * Dummy match function - will be called only for HSIC msm
567 * device (msm_device_gadget_hsic_peripheral).
568 */
569static inline int __match(struct device *dev, void *data) { return 1; }
570
571static void msm_hsic_connect_peripheral(struct device *msm_udc_dev)
572{
573 struct device *dev;
574 struct usb_gadget *gadget;
575
576 dev = device_find_child(msm_udc_dev, NULL, __match);
577 gadget = dev_to_usb_gadget(dev);
578 usb_gadget_vbus_connect(gadget);
579}
580
581static irqreturn_t msm_udc_hsic_irq(int irq, void *data)
582{
Ofir Cohendca06cb2012-03-08 16:37:45 +0200583 struct msm_hsic_per *mhsic = data;
584
585 if (atomic_read(&mhsic->in_lpm)) {
586 disable_irq_nosync(mhsic->irq);
587 mhsic->async_int = true;
588 pm_request_resume(mhsic->dev);
589 return IRQ_HANDLED;
590 }
591
Ofir Cohen06789f12012-01-16 09:43:13 +0200592 return udc_irq();
593}
594
595static void ci13xxx_msm_hsic_notify_event(struct ci13xxx *udc, unsigned event)
596{
597 struct device *dev = udc->gadget.dev.parent;
598 struct msm_hsic_per *mhsic = the_mhsic;
599
600 switch (event) {
601 case CI13XXX_CONTROLLER_RESET_EVENT:
Ido Shayevitzab601632012-09-16 15:11:26 +0300602 dev_info(dev, "CI13XXX_CONTROLLER_RESET_EVENT received\n");
Ofir Cohen06789f12012-01-16 09:43:13 +0200603 writel_relaxed(0, USB_AHBBURST);
Vijayavardhan Vennapusa5f32d7a2012-03-14 16:30:26 +0530604 writel_relaxed(0x08, USB_AHBMODE);
Ofir Cohen06789f12012-01-16 09:43:13 +0200605 break;
606 case CI13XXX_CONTROLLER_CONNECT_EVENT:
Ido Shayevitzab601632012-09-16 15:11:26 +0300607 dev_info(dev, "CI13XXX_CONTROLLER_CONNECT_EVENT received\n");
608 msm_hsic_wakeup();
609 the_mhsic->connected = true;
Ofir Cohen06789f12012-01-16 09:43:13 +0200610 break;
Ofir Cohendca06cb2012-03-08 16:37:45 +0200611 case CI13XXX_CONTROLLER_SUSPEND_EVENT:
Ido Shayevitzab601632012-09-16 15:11:26 +0300612 dev_info(dev, "CI13XXX_CONTROLLER_SUSPEND_EVENT received\n");
Ofir Cohendca06cb2012-03-08 16:37:45 +0200613 queue_work(mhsic->wq, &mhsic->suspend_w);
614 break;
Amit Blay725cdeb2012-04-30 14:20:56 +0300615 case CI13XXX_CONTROLLER_REMOTE_WAKEUP_EVENT:
Ido Shayevitzab601632012-09-16 15:11:26 +0300616 dev_info(dev, "CI13XXX_CONTROLLER_REMOTE_WAKEUP_EVENT received\n");
Amit Blay725cdeb2012-04-30 14:20:56 +0300617 msm_hsic_wakeup();
618 break;
Ido Shayevitzab601632012-09-16 15:11:26 +0300619 case CI13XXX_CONTROLLER_UDC_STARTED_EVENT:
620 dev_info(dev, "CI13XXX_CONTROLLER_UDC_STARTED_EVENT received\n");
621 /*
622 * UDC started, suspend the hsic device until it will be
623 * connected by a pullup (CI13XXX_CONTROLLER_CONNECT_EVENT)
624 * Before suspend, finish required configurations.
625 */
626 hw_device_state(_udc->ep0out.qh.dma);
627 msm_hsic_start();
628 usleep(10000);
629
630 mhsic->connected = false;
631 pm_runtime_put_noidle(the_mhsic->dev);
632 pm_runtime_suspend(the_mhsic->dev);
633 break;
Ofir Cohen06789f12012-01-16 09:43:13 +0200634 default:
635 dev_dbg(dev, "unknown ci13xxx_udc event\n");
636 break;
637 }
638}
639
640static struct ci13xxx_udc_driver ci13xxx_msm_udc_hsic_driver = {
641 .name = "ci13xxx_msm_hsic",
642 .flags = CI13XXX_REGS_SHARED |
643 CI13XXX_PULLUP_ON_VBUS |
644 CI13XXX_DISABLE_STREAMING |
645 CI13XXX_ZERO_ITC,
646
647 .notify_event = ci13xxx_msm_hsic_notify_event,
648};
649
650static int __devinit msm_hsic_probe(struct platform_device *pdev)
651{
652 struct resource *res;
653 struct msm_hsic_per *mhsic;
654 int ret = 0;
Ido Shayevitz479f2eb2012-06-27 10:39:57 +0300655 struct ci13xxx_platform_data *pdata;
Ofir Cohen06789f12012-01-16 09:43:13 +0200656
657 dev_dbg(&pdev->dev, "msm-hsic probe\n");
658
Amit Blay4d57d362012-04-28 11:00:21 +0300659 if (!pdev->dev.platform_data) {
660 dev_err(&pdev->dev, "No platform data given. Bailing out\n");
661 return -ENODEV;
662 } else {
663 pdata = pdev->dev.platform_data;
664 }
665
Ofir Cohen06789f12012-01-16 09:43:13 +0200666 mhsic = kzalloc(sizeof(struct msm_hsic_per), GFP_KERNEL);
667 if (!mhsic) {
668 dev_err(&pdev->dev, "unable to allocate msm_hsic\n");
669 return -ENOMEM;
670 }
671 the_mhsic = mhsic;
672 platform_set_drvdata(pdev, mhsic);
673 mhsic->dev = &pdev->dev;
Ido Shayevitz479f2eb2012-06-27 10:39:57 +0300674 mhsic->pdata =
675 (struct msm_hsic_peripheral_platform_data *)pdata->prv_data;
Ofir Cohen06789f12012-01-16 09:43:13 +0200676
677 mhsic->irq = platform_get_irq(pdev, 0);
678 if (mhsic->irq < 0) {
679 dev_err(&pdev->dev, "Unable to get IRQ resource\n");
680 ret = mhsic->irq;
681 goto error;
682 }
683
Ofir Cohendca06cb2012-03-08 16:37:45 +0200684 mhsic->wq = alloc_workqueue("mhsic_wq", WQ_UNBOUND | WQ_MEM_RECLAIM, 1);
685 if (!mhsic->wq) {
686 pr_err("%s: Unable to create workqueue mhsic wq\n",
687 __func__);
688 ret = -ENOMEM;
689 goto error;
690 }
691 INIT_WORK(&mhsic->suspend_w, msm_hsic_pm_suspend_work);
692
Ofir Cohen06789f12012-01-16 09:43:13 +0200693 res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
694 if (!res) {
695 dev_err(&pdev->dev, "Unable to get memory resource\n");
696 ret = -ENODEV;
697 goto error;
698 }
699 mhsic->regs = ioremap(res->start, resource_size(res));
700 if (!mhsic->regs) {
701 dev_err(&pdev->dev, "ioremap failed\n");
702 ret = -ENOMEM;
703 goto unmap;
704 }
705 dev_info(&pdev->dev, "HSIC Peripheral regs = %p\n", mhsic->regs);
706
Ofir Cohena91fab52012-03-25 14:57:28 +0200707 mhsic->xo_handle = msm_xo_get(MSM_XO_TCXO_D0, "hsic_peripheral");
Ofir Cohendca06cb2012-03-08 16:37:45 +0200708 if (IS_ERR(mhsic->xo_handle)) {
709 dev_err(&pdev->dev, "%s not able to get the handle "
710 "to vote for TCXO\n", __func__);
711 ret = PTR_ERR(mhsic->xo_handle);
712 goto unmap;
713 }
714
715 ret = msm_xo_mode_vote(mhsic->xo_handle, MSM_XO_MODE_ON);
716 if (ret) {
717 dev_err(&pdev->dev, "%s failed to vote for TCXO %d\n",
718 __func__, ret);
719 goto free_xo_handle;
720 }
721
Ofir Cohen06789f12012-01-16 09:43:13 +0200722 ret = msm_hsic_enable_clocks(pdev, mhsic, true);
723
724 if (ret) {
725 dev_err(&pdev->dev, "msm_hsic_enable_clocks failed\n");
726 ret = -ENODEV;
727 goto deinit_clocks;
728 }
729 ret = msm_hsic_init_vddcx(mhsic, 1);
730 if (ret) {
731 dev_err(&pdev->dev, "unable to initialize VDDCX\n");
732 ret = -ENODEV;
733 goto deinit_vddcx;
734 }
735
736 ret = msm_hsic_reset(mhsic);
737 if (ret) {
738 dev_err(&pdev->dev, "msm_hsic_reset failed\n");
739 ret = -ENODEV;
740 goto deinit_vddcx;
741 }
742
743 ret = udc_probe(&ci13xxx_msm_udc_hsic_driver, &pdev->dev, mhsic->regs);
744 if (ret < 0) {
745 dev_err(&pdev->dev, "udc_probe failed\n");
746 ret = -ENODEV;
747 goto deinit_vddcx;
748 }
749
750 msm_hsic_connect_peripheral(&pdev->dev);
751
Ofir Cohendca06cb2012-03-08 16:37:45 +0200752 device_init_wakeup(&pdev->dev, 1);
753 wake_lock_init(&mhsic->wlock, WAKE_LOCK_SUSPEND, dev_name(&pdev->dev));
754 wake_lock(&mhsic->wlock);
755
Ofir Cohen06789f12012-01-16 09:43:13 +0200756 ret = request_irq(mhsic->irq, msm_udc_hsic_irq,
Ofir Cohendca06cb2012-03-08 16:37:45 +0200757 IRQF_SHARED, pdev->name, mhsic);
Ofir Cohen06789f12012-01-16 09:43:13 +0200758 if (ret < 0) {
759 dev_err(&pdev->dev, "request_irq failed\n");
760 ret = -ENODEV;
761 goto udc_remove;
762 }
763
Ofir Cohendca06cb2012-03-08 16:37:45 +0200764 pm_runtime_set_active(&pdev->dev);
Ofir Cohen06789f12012-01-16 09:43:13 +0200765 pm_runtime_enable(&pdev->dev);
Ofir Cohendca06cb2012-03-08 16:37:45 +0200766 pm_runtime_get_sync(&pdev->dev);
Ofir Cohen06789f12012-01-16 09:43:13 +0200767
768 return 0;
769udc_remove:
770 udc_remove();
771deinit_vddcx:
772 msm_hsic_init_vddcx(mhsic, 0);
773deinit_clocks:
774 msm_hsic_enable_clocks(pdev, mhsic, 0);
Ofir Cohendca06cb2012-03-08 16:37:45 +0200775 msm_xo_mode_vote(mhsic->xo_handle, MSM_XO_MODE_OFF);
776free_xo_handle:
777 msm_xo_put(mhsic->xo_handle);
Ofir Cohen06789f12012-01-16 09:43:13 +0200778unmap:
779 iounmap(mhsic->regs);
780error:
Ofir Cohendca06cb2012-03-08 16:37:45 +0200781 destroy_workqueue(mhsic->wq);
Ofir Cohen06789f12012-01-16 09:43:13 +0200782 kfree(mhsic);
783 return ret;
784}
785
786static int __devexit hsic_msm_remove(struct platform_device *pdev)
787{
788 struct msm_hsic_per *mhsic = platform_get_drvdata(pdev);
789
790 device_init_wakeup(&pdev->dev, 0);
Ofir Cohendca06cb2012-03-08 16:37:45 +0200791 pm_runtime_disable(&pdev->dev);
792 pm_runtime_set_suspended(&pdev->dev);
793
Ofir Cohen06789f12012-01-16 09:43:13 +0200794 msm_hsic_init_vddcx(mhsic, 0);
795 msm_hsic_enable_clocks(pdev, mhsic, 0);
Ofir Cohendca06cb2012-03-08 16:37:45 +0200796 msm_xo_put(mhsic->xo_handle);
797 wake_lock_destroy(&mhsic->wlock);
798 destroy_workqueue(mhsic->wq);
Ofir Cohen06789f12012-01-16 09:43:13 +0200799 udc_remove();
800 iounmap(mhsic->regs);
801 kfree(mhsic);
802
803 return 0;
804}
Ofir Cohendca06cb2012-03-08 16:37:45 +0200805
Ofir Cohen06789f12012-01-16 09:43:13 +0200806static struct platform_driver msm_hsic_peripheral_driver = {
807 .probe = msm_hsic_probe,
808 .remove = __devexit_p(hsic_msm_remove),
809 .driver = {
810 .name = "msm_hsic_peripheral",
Ofir Cohendca06cb2012-03-08 16:37:45 +0200811#ifdef CONFIG_PM
812 .pm = &msm_hsic_dev_pm_ops,
813#endif
Ofir Cohen06789f12012-01-16 09:43:13 +0200814 },
815};
816
817static int __init msm_hsic_peripheral_init(void)
818{
819 return platform_driver_probe(&msm_hsic_peripheral_driver,
820 msm_hsic_probe);
821}
822
823static void __exit msm_hsic_peripheral_exit(void)
824{
825 platform_driver_unregister(&msm_hsic_peripheral_driver);
826}
827
828module_init(msm_hsic_peripheral_init);
829module_exit(msm_hsic_peripheral_exit);
830
Marc Kleine-Buddebc5acd92011-10-10 18:38:11 +0200831MODULE_LICENSE("GPL v2");