Lena Salman | 2098475 | 2012-03-12 17:26:39 +0200 | [diff] [blame] | 1 | /* Copyright (c) 2010-2012, Code Aurora Forum. All rights reserved. |
Pavankumar Kondeti | 33f82f3 | 2010-12-07 17:54:03 +0530 | [diff] [blame] | 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 | * |
Pavankumar Kondeti | 33f82f3 | 2010-12-07 17:54:03 +0530 | [diff] [blame] | 12 | */ |
| 13 | |
| 14 | #include <linux/module.h> |
| 15 | #include <linux/platform_device.h> |
Pavankumar Kondeti | 2d0cdcc | 2010-12-07 17:54:05 +0530 | [diff] [blame] | 16 | #include <linux/pm_runtime.h> |
Pavankumar Kondeti | 33f82f3 | 2010-12-07 17:54:03 +0530 | [diff] [blame] | 17 | #include <linux/usb/msm_hsusb_hw.h> |
| 18 | #include <linux/usb/ulpi.h> |
Steve Muckle | f132c6c | 2012-06-06 18:30:57 -0700 | [diff] [blame] | 19 | #include <linux/gpio.h> |
Pavankumar Kondeti | 33f82f3 | 2010-12-07 17:54:03 +0530 | [diff] [blame] | 20 | |
| 21 | #include "ci13xxx_udc.c" |
| 22 | |
| 23 | #define MSM_USB_BASE (udc->regs) |
| 24 | |
Lena Salman | 2098475 | 2012-03-12 17:26:39 +0200 | [diff] [blame] | 25 | struct ci13xxx_udc_context { |
| 26 | int irq; |
| 27 | void __iomem *regs; |
Amit Blay | 9b03368 | 2012-05-24 16:59:23 +0300 | [diff] [blame] | 28 | int wake_gpio; |
| 29 | int wake_irq; |
| 30 | bool wake_irq_state; |
Lena Salman | 2098475 | 2012-03-12 17:26:39 +0200 | [diff] [blame] | 31 | }; |
Amit Blay | 9b03368 | 2012-05-24 16:59:23 +0300 | [diff] [blame] | 32 | |
Lena Salman | 2098475 | 2012-03-12 17:26:39 +0200 | [diff] [blame] | 33 | static struct ci13xxx_udc_context _udc_ctxt; |
| 34 | |
Pavankumar Kondeti | 33f82f3 | 2010-12-07 17:54:03 +0530 | [diff] [blame] | 35 | static irqreturn_t msm_udc_irq(int irq, void *data) |
| 36 | { |
| 37 | return udc_irq(); |
| 38 | } |
| 39 | |
Amit Blay | 9b03368 | 2012-05-24 16:59:23 +0300 | [diff] [blame] | 40 | static void ci13xxx_msm_suspend(void) |
| 41 | { |
| 42 | struct device *dev = _udc->gadget.dev.parent; |
| 43 | dev_dbg(dev, "ci13xxx_msm_suspend\n"); |
| 44 | |
| 45 | if (_udc_ctxt.wake_irq && !_udc_ctxt.wake_irq_state) { |
| 46 | enable_irq_wake(_udc_ctxt.wake_irq); |
| 47 | enable_irq(_udc_ctxt.wake_irq); |
| 48 | _udc_ctxt.wake_irq_state = true; |
| 49 | } |
| 50 | } |
| 51 | |
| 52 | static void ci13xxx_msm_resume(void) |
| 53 | { |
| 54 | struct device *dev = _udc->gadget.dev.parent; |
| 55 | dev_dbg(dev, "ci13xxx_msm_resume\n"); |
| 56 | |
| 57 | if (_udc_ctxt.wake_irq && _udc_ctxt.wake_irq_state) { |
| 58 | disable_irq_wake(_udc_ctxt.wake_irq); |
Amit Blay | 50256ee | 2012-06-14 14:48:01 +0300 | [diff] [blame] | 59 | disable_irq_nosync(_udc_ctxt.wake_irq); |
Amit Blay | 9b03368 | 2012-05-24 16:59:23 +0300 | [diff] [blame] | 60 | _udc_ctxt.wake_irq_state = false; |
| 61 | } |
| 62 | } |
| 63 | |
Pavankumar Kondeti | 33f82f3 | 2010-12-07 17:54:03 +0530 | [diff] [blame] | 64 | static void ci13xxx_msm_notify_event(struct ci13xxx *udc, unsigned event) |
| 65 | { |
| 66 | struct device *dev = udc->gadget.dev.parent; |
Pavankumar Kondeti | 33f82f3 | 2010-12-07 17:54:03 +0530 | [diff] [blame] | 67 | |
| 68 | switch (event) { |
| 69 | case CI13XXX_CONTROLLER_RESET_EVENT: |
Amit Blay | 9b03368 | 2012-05-24 16:59:23 +0300 | [diff] [blame] | 70 | dev_info(dev, "CI13XXX_CONTROLLER_RESET_EVENT received\n"); |
Pavankumar Kondeti | 33f82f3 | 2010-12-07 17:54:03 +0530 | [diff] [blame] | 71 | writel(0, USB_AHBBURST); |
Vijayavardhan Vennapusa | 5f32d7a | 2012-03-14 16:30:26 +0530 | [diff] [blame] | 72 | writel_relaxed(0x08, USB_AHBMODE); |
Pavankumar Kondeti | 33f82f3 | 2010-12-07 17:54:03 +0530 | [diff] [blame] | 73 | break; |
Amit Blay | 9b03368 | 2012-05-24 16:59:23 +0300 | [diff] [blame] | 74 | case CI13XXX_CONTROLLER_DISCONNECT_EVENT: |
| 75 | dev_info(dev, "CI13XXX_CONTROLLER_DISCONNECT_EVENT received\n"); |
| 76 | ci13xxx_msm_resume(); |
Pavankumar Kondeti | 33f82f3 | 2010-12-07 17:54:03 +0530 | [diff] [blame] | 77 | break; |
Amit Blay | 9b03368 | 2012-05-24 16:59:23 +0300 | [diff] [blame] | 78 | case CI13XXX_CONTROLLER_SUSPEND_EVENT: |
| 79 | dev_info(dev, "CI13XXX_CONTROLLER_SUSPEND_EVENT received\n"); |
| 80 | ci13xxx_msm_suspend(); |
| 81 | break; |
| 82 | case CI13XXX_CONTROLLER_RESUME_EVENT: |
| 83 | dev_info(dev, "CI13XXX_CONTROLLER_RESUME_EVENT received\n"); |
| 84 | ci13xxx_msm_resume(); |
| 85 | break; |
| 86 | |
Pavankumar Kondeti | 33f82f3 | 2010-12-07 17:54:03 +0530 | [diff] [blame] | 87 | default: |
| 88 | dev_dbg(dev, "unknown ci13xxx_udc event\n"); |
| 89 | break; |
| 90 | } |
| 91 | } |
| 92 | |
Amit Blay | 9b03368 | 2012-05-24 16:59:23 +0300 | [diff] [blame] | 93 | static irqreturn_t ci13xxx_msm_resume_irq(int irq, void *data) |
| 94 | { |
| 95 | struct ci13xxx *udc = _udc; |
| 96 | |
| 97 | if (udc->transceiver && udc->vbus_active && udc->suspended) |
Steve Muckle | f132c6c | 2012-06-06 18:30:57 -0700 | [diff] [blame] | 98 | usb_phy_set_suspend(udc->transceiver, 0); |
Amit Blay | 9b03368 | 2012-05-24 16:59:23 +0300 | [diff] [blame] | 99 | else if (!udc->suspended) |
| 100 | ci13xxx_msm_resume(); |
| 101 | |
| 102 | return IRQ_HANDLED; |
| 103 | } |
| 104 | |
Pavankumar Kondeti | 33f82f3 | 2010-12-07 17:54:03 +0530 | [diff] [blame] | 105 | static struct ci13xxx_udc_driver ci13xxx_msm_udc_driver = { |
| 106 | .name = "ci13xxx_msm", |
| 107 | .flags = CI13XXX_REGS_SHARED | |
| 108 | CI13XXX_REQUIRE_TRANSCEIVER | |
| 109 | CI13XXX_PULLUP_ON_VBUS | |
Vijayavardhan Vennapusa | d450cb0 | 2012-02-25 14:35:26 +0530 | [diff] [blame] | 110 | CI13XXX_ZERO_ITC | |
Chiranjeevi Velempati | f117601 | 2012-03-29 13:02:13 +0530 | [diff] [blame] | 111 | CI13XXX_DISABLE_STREAMING | |
Vijayavardhan Vennapusa | d450cb0 | 2012-02-25 14:35:26 +0530 | [diff] [blame] | 112 | CI13XXX_IS_OTG, |
Pavankumar Kondeti | 33f82f3 | 2010-12-07 17:54:03 +0530 | [diff] [blame] | 113 | |
| 114 | .notify_event = ci13xxx_msm_notify_event, |
| 115 | }; |
| 116 | |
Amit Blay | 9b03368 | 2012-05-24 16:59:23 +0300 | [diff] [blame] | 117 | static int ci13xxx_msm_install_wake_gpio(struct platform_device *pdev, |
| 118 | struct resource *res) |
| 119 | { |
| 120 | int wake_irq; |
| 121 | int ret; |
| 122 | |
| 123 | dev_dbg(&pdev->dev, "ci13xxx_msm_install_wake_gpio\n"); |
| 124 | |
| 125 | _udc_ctxt.wake_gpio = res->start; |
| 126 | gpio_request(_udc_ctxt.wake_gpio, "USB_RESUME"); |
| 127 | gpio_direction_input(_udc_ctxt.wake_gpio); |
Steve Muckle | f132c6c | 2012-06-06 18:30:57 -0700 | [diff] [blame] | 128 | wake_irq = gpio_to_irq(_udc_ctxt.wake_gpio); |
Amit Blay | 9b03368 | 2012-05-24 16:59:23 +0300 | [diff] [blame] | 129 | if (wake_irq < 0) { |
| 130 | dev_err(&pdev->dev, "could not register USB_RESUME GPIO.\n"); |
| 131 | return -ENXIO; |
| 132 | } |
| 133 | |
| 134 | dev_dbg(&pdev->dev, "_udc_ctxt.gpio_irq = %d and irq = %d\n", |
| 135 | _udc_ctxt.wake_gpio, wake_irq); |
| 136 | ret = request_irq(wake_irq, ci13xxx_msm_resume_irq, |
Amit Blay | 50256ee | 2012-06-14 14:48:01 +0300 | [diff] [blame] | 137 | IRQF_TRIGGER_RISING | IRQF_ONESHOT, "usb resume", NULL); |
Amit Blay | 9b03368 | 2012-05-24 16:59:23 +0300 | [diff] [blame] | 138 | if (ret < 0) { |
| 139 | dev_err(&pdev->dev, "could not register USB_RESUME IRQ.\n"); |
| 140 | goto gpio_free; |
| 141 | } |
| 142 | disable_irq(wake_irq); |
| 143 | _udc_ctxt.wake_irq = wake_irq; |
| 144 | |
| 145 | return 0; |
| 146 | |
| 147 | gpio_free: |
| 148 | gpio_free(_udc_ctxt.wake_gpio); |
| 149 | _udc_ctxt.wake_gpio = 0; |
| 150 | return ret; |
| 151 | } |
| 152 | |
| 153 | static void ci13xxx_msm_uninstall_wake_gpio(struct platform_device *pdev) |
| 154 | { |
| 155 | dev_dbg(&pdev->dev, "ci13xxx_msm_uninstall_wake_gpio\n"); |
| 156 | |
| 157 | if (_udc_ctxt.wake_gpio) { |
| 158 | gpio_free(_udc_ctxt.wake_gpio); |
| 159 | _udc_ctxt.wake_gpio = 0; |
| 160 | } |
| 161 | } |
| 162 | |
Pavankumar Kondeti | 33f82f3 | 2010-12-07 17:54:03 +0530 | [diff] [blame] | 163 | static int ci13xxx_msm_probe(struct platform_device *pdev) |
| 164 | { |
| 165 | struct resource *res; |
Pavankumar Kondeti | 33f82f3 | 2010-12-07 17:54:03 +0530 | [diff] [blame] | 166 | int ret; |
| 167 | |
| 168 | dev_dbg(&pdev->dev, "ci13xxx_msm_probe\n"); |
| 169 | |
| 170 | res = platform_get_resource(pdev, IORESOURCE_MEM, 0); |
| 171 | if (!res) { |
| 172 | dev_err(&pdev->dev, "failed to get platform resource mem\n"); |
| 173 | return -ENXIO; |
| 174 | } |
| 175 | |
Lena Salman | 2098475 | 2012-03-12 17:26:39 +0200 | [diff] [blame] | 176 | _udc_ctxt.regs = ioremap(res->start, resource_size(res)); |
| 177 | if (!_udc_ctxt.regs) { |
Pavankumar Kondeti | 33f82f3 | 2010-12-07 17:54:03 +0530 | [diff] [blame] | 178 | dev_err(&pdev->dev, "ioremap failed\n"); |
| 179 | return -ENOMEM; |
| 180 | } |
| 181 | |
Lena Salman | 2098475 | 2012-03-12 17:26:39 +0200 | [diff] [blame] | 182 | ret = udc_probe(&ci13xxx_msm_udc_driver, &pdev->dev, _udc_ctxt.regs); |
Pavankumar Kondeti | 33f82f3 | 2010-12-07 17:54:03 +0530 | [diff] [blame] | 183 | if (ret < 0) { |
| 184 | dev_err(&pdev->dev, "udc_probe failed\n"); |
| 185 | goto iounmap; |
| 186 | } |
| 187 | |
Lena Salman | 2098475 | 2012-03-12 17:26:39 +0200 | [diff] [blame] | 188 | _udc_ctxt.irq = platform_get_irq(pdev, 0); |
| 189 | if (_udc_ctxt.irq < 0) { |
Pavankumar Kondeti | 33f82f3 | 2010-12-07 17:54:03 +0530 | [diff] [blame] | 190 | dev_err(&pdev->dev, "IRQ not found\n"); |
| 191 | ret = -ENXIO; |
| 192 | goto udc_remove; |
| 193 | } |
| 194 | |
Amit Blay | 9b03368 | 2012-05-24 16:59:23 +0300 | [diff] [blame] | 195 | res = platform_get_resource_byname(pdev, IORESOURCE_IO, "USB_RESUME"); |
| 196 | if (res) { |
| 197 | ret = ci13xxx_msm_install_wake_gpio(pdev, res); |
| 198 | if (ret < 0) { |
| 199 | dev_err(&pdev->dev, "gpio irq install failed\n"); |
| 200 | goto udc_remove; |
| 201 | } |
| 202 | } |
| 203 | |
Lena Salman | 2098475 | 2012-03-12 17:26:39 +0200 | [diff] [blame] | 204 | ret = request_irq(_udc_ctxt.irq, msm_udc_irq, IRQF_SHARED, pdev->name, |
| 205 | pdev); |
Pavankumar Kondeti | 33f82f3 | 2010-12-07 17:54:03 +0530 | [diff] [blame] | 206 | if (ret < 0) { |
| 207 | dev_err(&pdev->dev, "request_irq failed\n"); |
Amit Blay | 9b03368 | 2012-05-24 16:59:23 +0300 | [diff] [blame] | 208 | goto gpio_uninstall; |
Pavankumar Kondeti | 33f82f3 | 2010-12-07 17:54:03 +0530 | [diff] [blame] | 209 | } |
| 210 | |
Pavankumar Kondeti | 2d0cdcc | 2010-12-07 17:54:05 +0530 | [diff] [blame] | 211 | pm_runtime_no_callbacks(&pdev->dev); |
| 212 | pm_runtime_enable(&pdev->dev); |
| 213 | |
Pavankumar Kondeti | 33f82f3 | 2010-12-07 17:54:03 +0530 | [diff] [blame] | 214 | return 0; |
| 215 | |
Amit Blay | 9b03368 | 2012-05-24 16:59:23 +0300 | [diff] [blame] | 216 | gpio_uninstall: |
| 217 | ci13xxx_msm_uninstall_wake_gpio(pdev); |
Pavankumar Kondeti | 33f82f3 | 2010-12-07 17:54:03 +0530 | [diff] [blame] | 218 | udc_remove: |
| 219 | udc_remove(); |
| 220 | iounmap: |
Lena Salman | 2098475 | 2012-03-12 17:26:39 +0200 | [diff] [blame] | 221 | iounmap(_udc_ctxt.regs); |
Pavankumar Kondeti | 33f82f3 | 2010-12-07 17:54:03 +0530 | [diff] [blame] | 222 | |
| 223 | return ret; |
| 224 | } |
| 225 | |
Lena Salman | 2098475 | 2012-03-12 17:26:39 +0200 | [diff] [blame] | 226 | int ci13xxx_msm_remove(struct platform_device *pdev) |
| 227 | { |
| 228 | pm_runtime_disable(&pdev->dev); |
| 229 | free_irq(_udc_ctxt.irq, pdev); |
Amit Blay | 9b03368 | 2012-05-24 16:59:23 +0300 | [diff] [blame] | 230 | ci13xxx_msm_uninstall_wake_gpio(pdev); |
Lena Salman | 2098475 | 2012-03-12 17:26:39 +0200 | [diff] [blame] | 231 | udc_remove(); |
| 232 | iounmap(_udc_ctxt.regs); |
| 233 | return 0; |
| 234 | } |
| 235 | |
Pavankumar Kondeti | 33f82f3 | 2010-12-07 17:54:03 +0530 | [diff] [blame] | 236 | static struct platform_driver ci13xxx_msm_driver = { |
| 237 | .probe = ci13xxx_msm_probe, |
| 238 | .driver = { .name = "msm_hsusb", }, |
Lena Salman | 2098475 | 2012-03-12 17:26:39 +0200 | [diff] [blame] | 239 | .remove = ci13xxx_msm_remove, |
Pavankumar Kondeti | 33f82f3 | 2010-12-07 17:54:03 +0530 | [diff] [blame] | 240 | }; |
Sebastian Andrzej Siewior | 86081d7 | 2011-06-29 16:41:55 +0300 | [diff] [blame] | 241 | MODULE_ALIAS("platform:msm_hsusb"); |
Pavankumar Kondeti | 33f82f3 | 2010-12-07 17:54:03 +0530 | [diff] [blame] | 242 | |
| 243 | static int __init ci13xxx_msm_init(void) |
| 244 | { |
| 245 | return platform_driver_register(&ci13xxx_msm_driver); |
| 246 | } |
| 247 | module_init(ci13xxx_msm_init); |
Marc Kleine-Budde | 4703d2e | 2011-10-10 18:38:11 +0200 | [diff] [blame] | 248 | |
Lena Salman | 2098475 | 2012-03-12 17:26:39 +0200 | [diff] [blame] | 249 | static void __exit ci13xxx_msm_exit(void) |
| 250 | { |
| 251 | platform_driver_unregister(&ci13xxx_msm_driver); |
| 252 | } |
| 253 | module_exit(ci13xxx_msm_exit); |
| 254 | |
Marc Kleine-Budde | 4703d2e | 2011-10-10 18:38:11 +0200 | [diff] [blame] | 255 | MODULE_LICENSE("GPL v2"); |