blob: 30b45eb4ae63fa0e28318f65e54ce30fd71e99f9 [file] [log] [blame]
Ofir Cohen06789f12012-01-16 09:43:13 +02001/* Copyright (c) 2012, Code Aurora Forum. All rights reserved.
2 *
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;
70};
71
72static const int vdd_val[VDD_TYPE_MAX][VDD_VAL_MAX] = {
73 { /* VDD_CX CORNER Voting */
74 [VDD_NONE] = RPM_VREG_CORNER_NONE,
75 [VDD_MIN] = RPM_VREG_CORNER_NOMINAL,
76 [VDD_MAX] = RPM_VREG_CORNER_HIGH,
77 },
78 { /* VDD_CX Voltage Voting */
79 [VDD_NONE] = USB_PHY_VDD_DIG_VOL_NONE,
80 [VDD_MIN] = USB_PHY_VDD_DIG_VOL_MIN,
81 [VDD_MAX] = USB_PHY_VDD_DIG_VOL_MAX,
82 },
Ofir Cohen06789f12012-01-16 09:43:13 +020083};
84
85static int msm_hsic_init_vddcx(struct msm_hsic_per *mhsic, int init)
86{
87 int ret = 0;
Amit Blayd6ea6102012-06-07 16:26:24 +030088 int none_vol, min_vol, max_vol;
89
90 if (!mhsic->hsic_vddcx) {
91 mhsic->vdd_type = VDDCX_CORNER;
92 mhsic->hsic_vddcx = devm_regulator_get(mhsic->dev,
93 "hsic_vdd_dig");
94 if (IS_ERR(mhsic->hsic_vddcx)) {
95 mhsic->hsic_vddcx = devm_regulator_get(mhsic->dev,
96 "HSIC_VDDCX");
97 if (IS_ERR(mhsic->hsic_vddcx)) {
98 dev_err(mhsic->dev, "unable to get hsic vddcx\n");
99 return PTR_ERR(mhsic->hsic_vddcx);
100 }
101 mhsic->vdd_type = VDDCX;
102 }
103 }
104
105 none_vol = vdd_val[mhsic->vdd_type][VDD_NONE];
106 min_vol = vdd_val[mhsic->vdd_type][VDD_MIN];
107 max_vol = vdd_val[mhsic->vdd_type][VDD_MAX];
Ofir Cohen06789f12012-01-16 09:43:13 +0200108
109 if (!init)
110 goto disable_reg;
111
Amit Blayd6ea6102012-06-07 16:26:24 +0300112 ret = regulator_set_voltage(mhsic->hsic_vddcx, min_vol, max_vol);
Ofir Cohen06789f12012-01-16 09:43:13 +0200113 if (ret) {
114 dev_err(mhsic->dev, "unable to set the voltage"
115 "for hsic vddcx\n");
116 goto reg_set_voltage_err;
117 }
118
Ofir Cohen06789f12012-01-16 09:43:13 +0200119 ret = regulator_enable(mhsic->hsic_vddcx);
120 if (ret) {
121 dev_err(mhsic->dev, "unable to enable hsic vddcx\n");
122 goto reg_enable_err;
123 }
124
125 return 0;
126
127disable_reg:
128 regulator_disable(mhsic->hsic_vddcx);
129reg_enable_err:
Amit Blayd6ea6102012-06-07 16:26:24 +0300130 regulator_set_voltage(mhsic->hsic_vddcx, none_vol, max_vol);
Ofir Cohen06789f12012-01-16 09:43:13 +0200131reg_set_voltage_err:
Ofir Cohen06789f12012-01-16 09:43:13 +0200132
133 return ret;
134
135}
136
137static int ulpi_write(struct msm_hsic_per *mhsic, u32 val, u32 reg)
138{
139 int cnt = 0;
140
141 /* initiate write operation */
142 writel_relaxed(ULPI_RUN | ULPI_WRITE |
143 ULPI_ADDR(reg) | ULPI_DATA(val),
144 USB_ULPI_VIEWPORT);
145
146 /* wait for completion */
147 while (cnt < ULPI_IO_TIMEOUT_USEC) {
148 if (!(readl_relaxed(USB_ULPI_VIEWPORT) & ULPI_RUN))
149 break;
150 udelay(1);
151 cnt++;
152 }
153
154 if (cnt >= ULPI_IO_TIMEOUT_USEC) {
155 dev_err(mhsic->dev, "ulpi_write: timeout\n");
156 return -ETIMEDOUT;
157 }
158
159 return 0;
160}
161
162static int msm_hsic_phy_clk_reset(struct msm_hsic_per *mhsic)
163{
164 int ret;
165
166 ret = clk_reset(mhsic->core_clk, CLK_RESET_ASSERT);
167 if (ret) {
168 clk_disable(mhsic->alt_core_clk);
169 dev_err(mhsic->dev, "usb phy clk assert failed\n");
170 return ret;
171 }
172 usleep_range(10000, 12000);
173 clk_disable(mhsic->alt_core_clk);
174
175 ret = clk_reset(mhsic->core_clk, CLK_RESET_DEASSERT);
176 if (ret)
177 dev_err(mhsic->dev, "usb phy clk deassert failed\n");
178
179 return ret;
180}
181
182static int msm_hsic_phy_reset(struct msm_hsic_per *mhsic)
183{
184 u32 val;
185 int ret;
186
187 ret = msm_hsic_phy_clk_reset(mhsic);
188 if (ret)
189 return ret;
190
191 val = readl_relaxed(USB_PORTSC) & ~PORTSC_PTS_MASK;
192 writel_relaxed(val | PORTSC_PTS_ULPI, USB_PORTSC);
193
194 /*
195 * Ensure that RESET operation is completed before
196 * turning off clock.
197 */
198 mb();
199 dev_dbg(mhsic->dev, "phy_reset: success\n");
200
201 return 0;
202}
203
204static int msm_hsic_enable_clocks(struct platform_device *pdev,
205 struct msm_hsic_per *mhsic, bool enable)
206{
207 int ret = 0;
208
209 if (!enable)
210 goto put_clocks;
211
212 mhsic->iface_clk = clk_get(&pdev->dev, "iface_clk");
213 if (IS_ERR(mhsic->iface_clk)) {
214 dev_err(mhsic->dev, "failed to get iface_clk\n");
215 ret = PTR_ERR(mhsic->iface_clk);
216 goto put_iface_clk;
217 }
218
219 mhsic->core_clk = clk_get(&pdev->dev, "core_clk");
220 if (IS_ERR(mhsic->core_clk)) {
221 dev_err(mhsic->dev, "failed to get core_clk\n");
222 ret = PTR_ERR(mhsic->core_clk);
223 goto put_core_clk;
224 }
225
226 mhsic->phy_clk = clk_get(&pdev->dev, "phy_clk");
227 if (IS_ERR(mhsic->phy_clk)) {
228 dev_err(mhsic->dev, "failed to get phy_clk\n");
229 ret = PTR_ERR(mhsic->phy_clk);
230 goto put_phy_clk;
231 }
232
233 mhsic->alt_core_clk = clk_get(&pdev->dev, "alt_core_clk");
234 if (IS_ERR(mhsic->alt_core_clk)) {
235 dev_err(mhsic->dev, "failed to get alt_core_clk\n");
236 ret = PTR_ERR(mhsic->alt_core_clk);
237 goto put_alt_core_clk;
238 }
239
240 mhsic->cal_clk = clk_get(&pdev->dev, "cal_clk");
241 if (IS_ERR(mhsic->cal_clk)) {
242 dev_err(mhsic->dev, "failed to get cal_clk\n");
243 ret = PTR_ERR(mhsic->cal_clk);
244 goto put_cal_clk;
245 }
246
247 clk_enable(mhsic->iface_clk);
248 clk_enable(mhsic->core_clk);
249 clk_enable(mhsic->phy_clk);
250 clk_enable(mhsic->alt_core_clk);
251 clk_enable(mhsic->cal_clk);
252
253 return 0;
254
255put_clocks:
256 clk_disable(mhsic->iface_clk);
257 clk_disable(mhsic->core_clk);
258 clk_disable(mhsic->phy_clk);
259 clk_disable(mhsic->alt_core_clk);
260 clk_disable(mhsic->cal_clk);
261put_cal_clk:
262 clk_put(mhsic->cal_clk);
263put_alt_core_clk:
264 clk_put(mhsic->alt_core_clk);
265put_phy_clk:
266 clk_put(mhsic->phy_clk);
267put_core_clk:
268 clk_put(mhsic->core_clk);
269put_iface_clk:
270 clk_put(mhsic->iface_clk);
271
272 return ret;
273}
274
275static int msm_hsic_reset(struct msm_hsic_per *mhsic)
276{
277 int cnt = 0;
278 int ret;
279
280 ret = msm_hsic_phy_reset(mhsic);
281 if (ret) {
282 dev_err(mhsic->dev, "phy_reset failed\n");
283 return ret;
284 }
285
286 writel_relaxed(USBCMD_RESET, USB_USBCMD);
287 while (cnt < LINK_RESET_TIMEOUT_USEC) {
288 if (!(readl_relaxed(USB_USBCMD) & USBCMD_RESET))
289 break;
290 udelay(1);
291 cnt++;
292 }
293 if (cnt >= LINK_RESET_TIMEOUT_USEC)
294 return -ETIMEDOUT;
295
296 /* Reset PORTSC and select ULPI phy */
297 writel_relaxed(0x80000000, USB_PORTSC);
298 return 0;
299}
300
Amit Blay725cdeb2012-04-30 14:20:56 +0300301static void msm_hsic_wakeup(void)
302{
303 if (atomic_read(&the_mhsic->in_lpm))
304 pm_runtime_resume(the_mhsic->dev);
305}
306
Ofir Cohen06789f12012-01-16 09:43:13 +0200307static void msm_hsic_start(void)
308{
309 int ret;
310
311 /* programmable length of connect signaling (33.2ns) */
312 ret = ulpi_write(the_mhsic, 3, HSIC_DBG1_REG);
313 if (ret) {
314 pr_err("%s: Unable to program length of connect signaling\n",
315 __func__);
316 }
317
318 /*set periodic calibration interval to ~2.048sec in HSIC_IO_CAL_REG */
319 ret = ulpi_write(the_mhsic, 0xFF, HSIC_IO_CAL_PER_REG);
320
321 if (ret) {
322 pr_err("%s: Unable to set periodic calibration interval\n",
323 __func__);
324 }
325
326 /* Enable periodic IO calibration in HSIC_CFG register */
327 ret = ulpi_write(the_mhsic, 0xE9, HSIC_CFG_REG);
328 if (ret) {
329 pr_err("%s: Unable to enable periodic IO calibration\n",
330 __func__);
331 }
332}
333
Ofir Cohendca06cb2012-03-08 16:37:45 +0200334
335#ifdef CONFIG_PM_SLEEP
336static int msm_hsic_suspend(struct msm_hsic_per *mhsic)
337{
338 int cnt = 0, ret;
339 u32 val;
Amit Blayd6ea6102012-06-07 16:26:24 +0300340 int none_vol, max_vol;
Ofir Cohendca06cb2012-03-08 16:37:45 +0200341
342 if (atomic_read(&mhsic->in_lpm)) {
343 dev_dbg(mhsic->dev, "%s called while in lpm\n", __func__);
344 return 0;
345 }
346 disable_irq(mhsic->irq);
347
348 /*
349 * PHY may take some time or even fail to enter into low power
350 * mode (LPM). Hence poll for 500 msec and reset the PHY and link
351 * in failure case.
352 */
353 val = readl_relaxed(USB_PORTSC) | PORTSC_PHCD;
354 writel_relaxed(val, USB_PORTSC);
355
356 while (cnt < PHY_SUSPEND_TIMEOUT_USEC) {
357 if (readl_relaxed(USB_PORTSC) & PORTSC_PHCD)
358 break;
359 udelay(1);
360 cnt++;
361 }
362
363 if (cnt >= PHY_SUSPEND_TIMEOUT_USEC) {
364 dev_err(mhsic->dev, "Unable to suspend PHY\n");
365 msm_hsic_reset(mhsic);
366 }
367
368 /*
369 * PHY has capability to generate interrupt asynchronously in low
370 * power mode (LPM). This interrupt is level triggered. So USB IRQ
371 * line must be disabled till async interrupt enable bit is cleared
372 * in USBCMD register. Assert STP (ULPI interface STOP signal) to
373 * block data communication from PHY.
374 */
375 writel_relaxed(readl_relaxed(USB_USBCMD) | ASYNC_INTR_CTRL |
376 ULPI_STP_CTRL, USB_USBCMD);
377
378 /*
379 * Ensure that hardware is put in low power mode before
380 * clocks are turned OFF and VDD is allowed to minimize.
381 */
382 mb();
383
Amit Blay4d57d362012-04-28 11:00:21 +0300384 if (!mhsic->pdata->keep_core_clk_on_suspend_workaround) {
385 clk_disable(mhsic->iface_clk);
386 clk_disable(mhsic->core_clk);
387 }
Ofir Cohendca06cb2012-03-08 16:37:45 +0200388 clk_disable(mhsic->phy_clk);
389 clk_disable(mhsic->cal_clk);
390
391 ret = msm_xo_mode_vote(mhsic->xo_handle, MSM_XO_MODE_OFF);
392 if (ret)
393 dev_err(mhsic->dev, "%s failed to devote for TCXO %d\n"
394 , __func__, ret);
395
Amit Blayd6ea6102012-06-07 16:26:24 +0300396 none_vol = vdd_val[mhsic->vdd_type][VDD_NONE];
397 max_vol = vdd_val[mhsic->vdd_type][VDD_MAX];
398
399 ret = regulator_set_voltage(mhsic->hsic_vddcx, none_vol, max_vol);
Ofir Cohendca06cb2012-03-08 16:37:45 +0200400 if (ret < 0)
Amit Blayd6ea6102012-06-07 16:26:24 +0300401 dev_err(mhsic->dev, "unable to set vddcx voltage for VDD MIN\n");
Ofir Cohendca06cb2012-03-08 16:37:45 +0200402
403 if (device_may_wakeup(mhsic->dev))
404 enable_irq_wake(mhsic->irq);
405
406 atomic_set(&mhsic->in_lpm, 1);
407 enable_irq(mhsic->irq);
408 wake_unlock(&mhsic->wlock);
409
410 dev_info(mhsic->dev, "HSIC-USB in low power mode\n");
411
412 return 0;
413}
414
415static int msm_hsic_resume(struct msm_hsic_per *mhsic)
416{
417 int cnt = 0, ret;
418 unsigned temp;
Amit Blayd6ea6102012-06-07 16:26:24 +0300419 int min_vol, max_vol;
Ofir Cohendca06cb2012-03-08 16:37:45 +0200420
421 if (!atomic_read(&mhsic->in_lpm)) {
422 dev_dbg(mhsic->dev, "%s called while not in lpm\n", __func__);
423 return 0;
424 }
425
426 wake_lock(&mhsic->wlock);
Amit Blayd6ea6102012-06-07 16:26:24 +0300427
428 min_vol = vdd_val[mhsic->vdd_type][VDD_MIN];
429 max_vol = vdd_val[mhsic->vdd_type][VDD_MAX];
430
431 ret = regulator_set_voltage(mhsic->hsic_vddcx, min_vol, max_vol);
Ofir Cohendca06cb2012-03-08 16:37:45 +0200432 if (ret < 0)
433 dev_err(mhsic->dev,
Amit Blayd6ea6102012-06-07 16:26:24 +0300434 "unable to set nominal vddcx voltage (no VDD MIN)\n");
Ofir Cohendca06cb2012-03-08 16:37:45 +0200435
436 ret = msm_xo_mode_vote(mhsic->xo_handle, MSM_XO_MODE_ON);
437 if (ret)
438 dev_err(mhsic->dev, "%s failed to vote for TCXO %d\n",
439 __func__, ret);
440
Amit Blay4d57d362012-04-28 11:00:21 +0300441 if (!mhsic->pdata->keep_core_clk_on_suspend_workaround) {
442 clk_enable(mhsic->iface_clk);
443 clk_enable(mhsic->core_clk);
444 }
Ofir Cohendca06cb2012-03-08 16:37:45 +0200445 clk_enable(mhsic->phy_clk);
446 clk_enable(mhsic->cal_clk);
447
448 temp = readl_relaxed(USB_USBCMD);
449 temp &= ~ASYNC_INTR_CTRL;
450 temp &= ~ULPI_STP_CTRL;
451 writel_relaxed(temp, USB_USBCMD);
452
453 if (!(readl_relaxed(USB_PORTSC) & PORTSC_PHCD))
454 goto skip_phy_resume;
455
456 temp = readl_relaxed(USB_PORTSC) & ~PORTSC_PHCD;
457 writel_relaxed(temp, USB_PORTSC);
458 while (cnt < PHY_RESUME_TIMEOUT_USEC) {
459 if (!(readl_relaxed(USB_PORTSC) & PORTSC_PHCD) &&
460 (readl_relaxed(USB_ULPI_VIEWPORT) & ULPI_SYNC_STATE))
461 break;
462 udelay(1);
463 cnt++;
464 }
465
466 if (cnt >= PHY_RESUME_TIMEOUT_USEC) {
467 /*
468 * This is a fatal error. Reset the link and
469 * PHY to make hsic working.
470 */
471 dev_err(mhsic->dev, "Unable to resume USB. Reset the hsic\n");
472 msm_hsic_reset(mhsic);
473 }
474skip_phy_resume:
475 if (device_may_wakeup(mhsic->dev))
476 disable_irq_wake(mhsic->irq);
477
478 atomic_set(&mhsic->in_lpm, 0);
479
480 if (mhsic->async_int) {
481 mhsic->async_int = false;
482 enable_irq(mhsic->irq);
483 }
484
485 dev_info(mhsic->dev, "HSIC-USB exited from low power mode\n");
486
487 return 0;
488}
489
490static int msm_hsic_pm_suspend(struct device *dev)
491{
492 struct msm_hsic_per *mhsic = dev_get_drvdata(dev);
493
494 dev_dbg(dev, "MSM HSIC Peripheral PM suspend\n");
495
496 return msm_hsic_suspend(mhsic);
497}
498
499#ifdef CONFIG_PM_RUNTIME
500static int msm_hsic_pm_resume(struct device *dev)
501{
502 dev_dbg(dev, "MSM HSIC Peripheral PM resume\n");
503
504 /*
505 * Do not resume hardware as part of system resume,
506 * rather, wait for the ASYNC INT from the h/w
507 */
508 return 0;
509}
510#else
511static int msm_hsic_pm_resume(struct device *dev)
512{
513 struct msm_hsic_per *mhsic = dev_get_drvdata(dev);
514
515 dev_dbg(dev, "MSM HSIC Peripheral PM resume\n");
516
517 return msm_hsic_resume(mhsic);
518}
519#endif
520
521static void msm_hsic_pm_suspend_work(struct work_struct *w)
522{
523 pm_runtime_put_noidle(the_mhsic->dev);
524 pm_runtime_suspend(the_mhsic->dev);
525}
526#endif /* CONFIG_PM_SLEEP */
527
528#ifdef CONFIG_PM_RUNTIME
529static int msm_hsic_runtime_idle(struct device *dev)
530{
531 dev_dbg(dev, "MSM HSIC Peripheral runtime idle\n");
532
533 return 0;
534}
535
536static int msm_hsic_runtime_suspend(struct device *dev)
537{
538 struct msm_hsic_per *mhsic = dev_get_drvdata(dev);
539
540 dev_dbg(dev, "MSM HSIC Peripheral runtime suspend\n");
541
542 return msm_hsic_suspend(mhsic);
543}
544
545static int msm_hsic_runtime_resume(struct device *dev)
546{
547 struct msm_hsic_per *mhsic = dev_get_drvdata(dev);
548
549 dev_dbg(dev, "MSM HSIC Peripheral runtime resume\n");
550 pm_runtime_get_noresume(mhsic->dev);
551
552 return msm_hsic_resume(mhsic);
553}
554#endif
555
556#ifdef CONFIG_PM
557static const struct dev_pm_ops msm_hsic_dev_pm_ops = {
558 SET_SYSTEM_SLEEP_PM_OPS(msm_hsic_pm_suspend, msm_hsic_pm_resume)
559 SET_RUNTIME_PM_OPS(msm_hsic_runtime_suspend, msm_hsic_runtime_resume,
560 msm_hsic_runtime_idle)
561};
562#endif
563
Ofir Cohen06789f12012-01-16 09:43:13 +0200564/**
565 * Dummy match function - will be called only for HSIC msm
566 * device (msm_device_gadget_hsic_peripheral).
567 */
568static inline int __match(struct device *dev, void *data) { return 1; }
569
570static void msm_hsic_connect_peripheral(struct device *msm_udc_dev)
571{
572 struct device *dev;
573 struct usb_gadget *gadget;
574
575 dev = device_find_child(msm_udc_dev, NULL, __match);
576 gadget = dev_to_usb_gadget(dev);
577 usb_gadget_vbus_connect(gadget);
578}
579
580static irqreturn_t msm_udc_hsic_irq(int irq, void *data)
581{
Ofir Cohendca06cb2012-03-08 16:37:45 +0200582 struct msm_hsic_per *mhsic = data;
583
584 if (atomic_read(&mhsic->in_lpm)) {
585 disable_irq_nosync(mhsic->irq);
586 mhsic->async_int = true;
587 pm_request_resume(mhsic->dev);
588 return IRQ_HANDLED;
589 }
590
Ofir Cohen06789f12012-01-16 09:43:13 +0200591 return udc_irq();
592}
593
594static void ci13xxx_msm_hsic_notify_event(struct ci13xxx *udc, unsigned event)
595{
596 struct device *dev = udc->gadget.dev.parent;
597 struct msm_hsic_per *mhsic = the_mhsic;
598
599 switch (event) {
600 case CI13XXX_CONTROLLER_RESET_EVENT:
601 dev_dbg(dev, "CI13XXX_CONTROLLER_RESET_EVENT received\n");
602 writel_relaxed(0, USB_AHBBURST);
Vijayavardhan Vennapusa5f32d7a2012-03-14 16:30:26 +0530603 writel_relaxed(0x08, USB_AHBMODE);
Ofir Cohen06789f12012-01-16 09:43:13 +0200604 break;
605 case CI13XXX_CONTROLLER_CONNECT_EVENT:
606 dev_dbg(dev, "CI13XXX_CONTROLLER_CONNECT_EVENT received\n");
607 msm_hsic_start();
608 break;
Ofir Cohendca06cb2012-03-08 16:37:45 +0200609 case CI13XXX_CONTROLLER_SUSPEND_EVENT:
610 dev_dbg(dev, "CI13XXX_CONTROLLER_SUSPEND_EVENT received\n");
611 queue_work(mhsic->wq, &mhsic->suspend_w);
612 break;
Amit Blay725cdeb2012-04-30 14:20:56 +0300613 case CI13XXX_CONTROLLER_REMOTE_WAKEUP_EVENT:
614 dev_dbg(dev, "CI13XXX_CONTROLLER_REMOTE_WAKEUP_EVENT received\n");
615 msm_hsic_wakeup();
616 break;
Ofir Cohen06789f12012-01-16 09:43:13 +0200617 default:
618 dev_dbg(dev, "unknown ci13xxx_udc event\n");
619 break;
620 }
621}
622
623static struct ci13xxx_udc_driver ci13xxx_msm_udc_hsic_driver = {
624 .name = "ci13xxx_msm_hsic",
625 .flags = CI13XXX_REGS_SHARED |
626 CI13XXX_PULLUP_ON_VBUS |
627 CI13XXX_DISABLE_STREAMING |
628 CI13XXX_ZERO_ITC,
629
630 .notify_event = ci13xxx_msm_hsic_notify_event,
631};
632
633static int __devinit msm_hsic_probe(struct platform_device *pdev)
634{
635 struct resource *res;
636 struct msm_hsic_per *mhsic;
637 int ret = 0;
Amit Blay4d57d362012-04-28 11:00:21 +0300638 struct msm_hsic_peripheral_platform_data *pdata;
Ofir Cohen06789f12012-01-16 09:43:13 +0200639
640 dev_dbg(&pdev->dev, "msm-hsic probe\n");
641
Amit Blay4d57d362012-04-28 11:00:21 +0300642 if (!pdev->dev.platform_data) {
643 dev_err(&pdev->dev, "No platform data given. Bailing out\n");
644 return -ENODEV;
645 } else {
646 pdata = pdev->dev.platform_data;
647 }
648
Ofir Cohen06789f12012-01-16 09:43:13 +0200649 mhsic = kzalloc(sizeof(struct msm_hsic_per), GFP_KERNEL);
650 if (!mhsic) {
651 dev_err(&pdev->dev, "unable to allocate msm_hsic\n");
652 return -ENOMEM;
653 }
654 the_mhsic = mhsic;
655 platform_set_drvdata(pdev, mhsic);
656 mhsic->dev = &pdev->dev;
Amit Blay4d57d362012-04-28 11:00:21 +0300657 mhsic->pdata = pdata;
Ofir Cohen06789f12012-01-16 09:43:13 +0200658
659 mhsic->irq = platform_get_irq(pdev, 0);
660 if (mhsic->irq < 0) {
661 dev_err(&pdev->dev, "Unable to get IRQ resource\n");
662 ret = mhsic->irq;
663 goto error;
664 }
665
Ofir Cohendca06cb2012-03-08 16:37:45 +0200666 mhsic->wq = alloc_workqueue("mhsic_wq", WQ_UNBOUND | WQ_MEM_RECLAIM, 1);
667 if (!mhsic->wq) {
668 pr_err("%s: Unable to create workqueue mhsic wq\n",
669 __func__);
670 ret = -ENOMEM;
671 goto error;
672 }
673 INIT_WORK(&mhsic->suspend_w, msm_hsic_pm_suspend_work);
674
Ofir Cohen06789f12012-01-16 09:43:13 +0200675 res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
676 if (!res) {
677 dev_err(&pdev->dev, "Unable to get memory resource\n");
678 ret = -ENODEV;
679 goto error;
680 }
681 mhsic->regs = ioremap(res->start, resource_size(res));
682 if (!mhsic->regs) {
683 dev_err(&pdev->dev, "ioremap failed\n");
684 ret = -ENOMEM;
685 goto unmap;
686 }
687 dev_info(&pdev->dev, "HSIC Peripheral regs = %p\n", mhsic->regs);
688
Ofir Cohena91fab52012-03-25 14:57:28 +0200689 mhsic->xo_handle = msm_xo_get(MSM_XO_TCXO_D0, "hsic_peripheral");
Ofir Cohendca06cb2012-03-08 16:37:45 +0200690 if (IS_ERR(mhsic->xo_handle)) {
691 dev_err(&pdev->dev, "%s not able to get the handle "
692 "to vote for TCXO\n", __func__);
693 ret = PTR_ERR(mhsic->xo_handle);
694 goto unmap;
695 }
696
697 ret = msm_xo_mode_vote(mhsic->xo_handle, MSM_XO_MODE_ON);
698 if (ret) {
699 dev_err(&pdev->dev, "%s failed to vote for TCXO %d\n",
700 __func__, ret);
701 goto free_xo_handle;
702 }
703
Ofir Cohen06789f12012-01-16 09:43:13 +0200704 ret = msm_hsic_enable_clocks(pdev, mhsic, true);
705
706 if (ret) {
707 dev_err(&pdev->dev, "msm_hsic_enable_clocks failed\n");
708 ret = -ENODEV;
709 goto deinit_clocks;
710 }
711 ret = msm_hsic_init_vddcx(mhsic, 1);
712 if (ret) {
713 dev_err(&pdev->dev, "unable to initialize VDDCX\n");
714 ret = -ENODEV;
715 goto deinit_vddcx;
716 }
717
718 ret = msm_hsic_reset(mhsic);
719 if (ret) {
720 dev_err(&pdev->dev, "msm_hsic_reset failed\n");
721 ret = -ENODEV;
722 goto deinit_vddcx;
723 }
724
725 ret = udc_probe(&ci13xxx_msm_udc_hsic_driver, &pdev->dev, mhsic->regs);
726 if (ret < 0) {
727 dev_err(&pdev->dev, "udc_probe failed\n");
728 ret = -ENODEV;
729 goto deinit_vddcx;
730 }
731
732 msm_hsic_connect_peripheral(&pdev->dev);
733
Ofir Cohendca06cb2012-03-08 16:37:45 +0200734 device_init_wakeup(&pdev->dev, 1);
735 wake_lock_init(&mhsic->wlock, WAKE_LOCK_SUSPEND, dev_name(&pdev->dev));
736 wake_lock(&mhsic->wlock);
737
Ofir Cohen06789f12012-01-16 09:43:13 +0200738 ret = request_irq(mhsic->irq, msm_udc_hsic_irq,
Ofir Cohendca06cb2012-03-08 16:37:45 +0200739 IRQF_SHARED, pdev->name, mhsic);
Ofir Cohen06789f12012-01-16 09:43:13 +0200740 if (ret < 0) {
741 dev_err(&pdev->dev, "request_irq failed\n");
742 ret = -ENODEV;
743 goto udc_remove;
744 }
745
Ofir Cohendca06cb2012-03-08 16:37:45 +0200746 pm_runtime_set_active(&pdev->dev);
Ofir Cohen06789f12012-01-16 09:43:13 +0200747 pm_runtime_enable(&pdev->dev);
Ofir Cohendca06cb2012-03-08 16:37:45 +0200748 pm_runtime_get_sync(&pdev->dev);
Ofir Cohen06789f12012-01-16 09:43:13 +0200749
750 return 0;
751udc_remove:
752 udc_remove();
753deinit_vddcx:
754 msm_hsic_init_vddcx(mhsic, 0);
755deinit_clocks:
756 msm_hsic_enable_clocks(pdev, mhsic, 0);
Ofir Cohendca06cb2012-03-08 16:37:45 +0200757 msm_xo_mode_vote(mhsic->xo_handle, MSM_XO_MODE_OFF);
758free_xo_handle:
759 msm_xo_put(mhsic->xo_handle);
Ofir Cohen06789f12012-01-16 09:43:13 +0200760unmap:
761 iounmap(mhsic->regs);
762error:
Ofir Cohendca06cb2012-03-08 16:37:45 +0200763 destroy_workqueue(mhsic->wq);
Ofir Cohen06789f12012-01-16 09:43:13 +0200764 kfree(mhsic);
765 return ret;
766}
767
768static int __devexit hsic_msm_remove(struct platform_device *pdev)
769{
770 struct msm_hsic_per *mhsic = platform_get_drvdata(pdev);
771
772 device_init_wakeup(&pdev->dev, 0);
Ofir Cohendca06cb2012-03-08 16:37:45 +0200773 pm_runtime_disable(&pdev->dev);
774 pm_runtime_set_suspended(&pdev->dev);
775
Ofir Cohen06789f12012-01-16 09:43:13 +0200776 msm_hsic_init_vddcx(mhsic, 0);
777 msm_hsic_enable_clocks(pdev, mhsic, 0);
Ofir Cohendca06cb2012-03-08 16:37:45 +0200778 msm_xo_put(mhsic->xo_handle);
779 wake_lock_destroy(&mhsic->wlock);
780 destroy_workqueue(mhsic->wq);
Ofir Cohen06789f12012-01-16 09:43:13 +0200781 udc_remove();
782 iounmap(mhsic->regs);
783 kfree(mhsic);
784
785 return 0;
786}
Ofir Cohendca06cb2012-03-08 16:37:45 +0200787
Ofir Cohen06789f12012-01-16 09:43:13 +0200788static struct platform_driver msm_hsic_peripheral_driver = {
789 .probe = msm_hsic_probe,
790 .remove = __devexit_p(hsic_msm_remove),
791 .driver = {
792 .name = "msm_hsic_peripheral",
Ofir Cohendca06cb2012-03-08 16:37:45 +0200793#ifdef CONFIG_PM
794 .pm = &msm_hsic_dev_pm_ops,
795#endif
Ofir Cohen06789f12012-01-16 09:43:13 +0200796 },
797};
798
799static int __init msm_hsic_peripheral_init(void)
800{
801 return platform_driver_probe(&msm_hsic_peripheral_driver,
802 msm_hsic_probe);
803}
804
805static void __exit msm_hsic_peripheral_exit(void)
806{
807 platform_driver_unregister(&msm_hsic_peripheral_driver);
808}
809
810module_init(msm_hsic_peripheral_init);
811module_exit(msm_hsic_peripheral_exit);
812
Marc Kleine-Buddebc5acd92011-10-10 18:38:11 +0200813MODULE_LICENSE("GPL v2");