.. | .. |
---|
7 | 7 | |
---|
8 | 8 | #include <linux/kernel.h> |
---|
9 | 9 | #include <linux/platform_device.h> |
---|
10 | | -#include <linux/gpio.h> |
---|
| 10 | +#include <linux/gpio/consumer.h> |
---|
11 | 11 | #include <linux/module.h> |
---|
12 | 12 | #include <linux/slab.h> |
---|
13 | 13 | #include <linux/interrupt.h> |
---|
.. | .. |
---|
17 | 17 | #include <linux/regulator/consumer.h> |
---|
18 | 18 | |
---|
19 | 19 | #include <linux/usb/gadget.h> |
---|
20 | | -#include <linux/usb/gpio_vbus.h> |
---|
21 | 20 | #include <linux/usb/otg.h> |
---|
22 | 21 | |
---|
23 | 22 | |
---|
.. | .. |
---|
29 | 28 | * Needs to be loaded before the UDC driver that will use it. |
---|
30 | 29 | */ |
---|
31 | 30 | struct gpio_vbus_data { |
---|
| 31 | + struct gpio_desc *vbus_gpiod; |
---|
| 32 | + struct gpio_desc *pullup_gpiod; |
---|
32 | 33 | struct usb_phy phy; |
---|
33 | 34 | struct device *dev; |
---|
34 | 35 | struct regulator *vbus_draw; |
---|
.. | .. |
---|
83 | 84 | gpio_vbus->mA = mA; |
---|
84 | 85 | } |
---|
85 | 86 | |
---|
86 | | -static int is_vbus_powered(struct gpio_vbus_mach_info *pdata) |
---|
| 87 | +static int is_vbus_powered(struct gpio_vbus_data *gpio_vbus) |
---|
87 | 88 | { |
---|
88 | | - int vbus; |
---|
89 | | - |
---|
90 | | - vbus = gpio_get_value(pdata->gpio_vbus); |
---|
91 | | - if (pdata->gpio_vbus_inverted) |
---|
92 | | - vbus = !vbus; |
---|
93 | | - |
---|
94 | | - return vbus; |
---|
| 89 | + return gpiod_get_value(gpio_vbus->vbus_gpiod); |
---|
95 | 90 | } |
---|
96 | 91 | |
---|
97 | 92 | static void gpio_vbus_work(struct work_struct *work) |
---|
98 | 93 | { |
---|
99 | 94 | struct gpio_vbus_data *gpio_vbus = |
---|
100 | 95 | container_of(work, struct gpio_vbus_data, work.work); |
---|
101 | | - struct gpio_vbus_mach_info *pdata = dev_get_platdata(gpio_vbus->dev); |
---|
102 | | - int gpio, status, vbus; |
---|
| 96 | + int status, vbus; |
---|
103 | 97 | |
---|
104 | 98 | if (!gpio_vbus->phy.otg->gadget) |
---|
105 | 99 | return; |
---|
106 | 100 | |
---|
107 | | - vbus = is_vbus_powered(pdata); |
---|
| 101 | + vbus = is_vbus_powered(gpio_vbus); |
---|
108 | 102 | if ((vbus ^ gpio_vbus->vbus) == 0) |
---|
109 | 103 | return; |
---|
110 | 104 | gpio_vbus->vbus = vbus; |
---|
111 | 105 | |
---|
112 | 106 | /* Peripheral controllers which manage the pullup themselves won't have |
---|
113 | | - * gpio_pullup configured here. If it's configured here, we'll do what |
---|
114 | | - * isp1301_omap::b_peripheral() does and enable the pullup here... although |
---|
115 | | - * that may complicate usb_gadget_{,dis}connect() support. |
---|
| 107 | + * a pullup GPIO configured here. If it's configured here, we'll do |
---|
| 108 | + * what isp1301_omap::b_peripheral() does and enable the pullup here... |
---|
| 109 | + * although that may complicate usb_gadget_{,dis}connect() support. |
---|
116 | 110 | */ |
---|
117 | | - gpio = pdata->gpio_pullup; |
---|
118 | 111 | |
---|
119 | 112 | if (vbus) { |
---|
120 | 113 | status = USB_EVENT_VBUS; |
---|
.. | .. |
---|
126 | 119 | set_vbus_draw(gpio_vbus, 100); |
---|
127 | 120 | |
---|
128 | 121 | /* optionally enable D+ pullup */ |
---|
129 | | - if (gpio_is_valid(gpio)) |
---|
130 | | - gpio_set_value(gpio, !pdata->gpio_pullup_inverted); |
---|
| 122 | + if (gpio_vbus->pullup_gpiod) |
---|
| 123 | + gpiod_set_value(gpio_vbus->pullup_gpiod, 1); |
---|
131 | 124 | |
---|
132 | 125 | atomic_notifier_call_chain(&gpio_vbus->phy.notifier, |
---|
133 | 126 | status, gpio_vbus->phy.otg->gadget); |
---|
134 | 127 | usb_phy_set_event(&gpio_vbus->phy, USB_EVENT_ENUMERATED); |
---|
135 | 128 | } else { |
---|
136 | 129 | /* optionally disable D+ pullup */ |
---|
137 | | - if (gpio_is_valid(gpio)) |
---|
138 | | - gpio_set_value(gpio, pdata->gpio_pullup_inverted); |
---|
| 130 | + if (gpio_vbus->pullup_gpiod) |
---|
| 131 | + gpiod_set_value(gpio_vbus->pullup_gpiod, 0); |
---|
139 | 132 | |
---|
140 | 133 | set_vbus_draw(gpio_vbus, 0); |
---|
141 | 134 | |
---|
.. | .. |
---|
154 | 147 | static irqreturn_t gpio_vbus_irq(int irq, void *data) |
---|
155 | 148 | { |
---|
156 | 149 | struct platform_device *pdev = data; |
---|
157 | | - struct gpio_vbus_mach_info *pdata = dev_get_platdata(&pdev->dev); |
---|
158 | 150 | struct gpio_vbus_data *gpio_vbus = platform_get_drvdata(pdev); |
---|
159 | 151 | struct usb_otg *otg = gpio_vbus->phy.otg; |
---|
160 | 152 | |
---|
161 | 153 | dev_dbg(&pdev->dev, "VBUS %s (gadget: %s)\n", |
---|
162 | | - is_vbus_powered(pdata) ? "supplied" : "inactive", |
---|
| 154 | + is_vbus_powered(gpio_vbus) ? "supplied" : "inactive", |
---|
163 | 155 | otg->gadget ? otg->gadget->name : "none"); |
---|
164 | 156 | |
---|
165 | 157 | if (otg->gadget) |
---|
.. | .. |
---|
175 | 167 | struct usb_gadget *gadget) |
---|
176 | 168 | { |
---|
177 | 169 | struct gpio_vbus_data *gpio_vbus; |
---|
178 | | - struct gpio_vbus_mach_info *pdata; |
---|
179 | 170 | struct platform_device *pdev; |
---|
180 | | - int gpio; |
---|
181 | 171 | |
---|
182 | 172 | gpio_vbus = container_of(otg->usb_phy, struct gpio_vbus_data, phy); |
---|
183 | 173 | pdev = to_platform_device(gpio_vbus->dev); |
---|
184 | | - pdata = dev_get_platdata(gpio_vbus->dev); |
---|
185 | | - gpio = pdata->gpio_pullup; |
---|
186 | 174 | |
---|
187 | 175 | if (!gadget) { |
---|
188 | 176 | dev_dbg(&pdev->dev, "unregistering gadget '%s'\n", |
---|
189 | 177 | otg->gadget->name); |
---|
190 | 178 | |
---|
191 | 179 | /* optionally disable D+ pullup */ |
---|
192 | | - if (gpio_is_valid(gpio)) |
---|
193 | | - gpio_set_value(gpio, pdata->gpio_pullup_inverted); |
---|
| 180 | + if (gpio_vbus->pullup_gpiod) |
---|
| 181 | + gpiod_set_value(gpio_vbus->pullup_gpiod, 0); |
---|
194 | 182 | |
---|
195 | 183 | set_vbus_draw(gpio_vbus, 0); |
---|
196 | 184 | |
---|
.. | .. |
---|
242 | 230 | |
---|
243 | 231 | static int gpio_vbus_probe(struct platform_device *pdev) |
---|
244 | 232 | { |
---|
245 | | - struct gpio_vbus_mach_info *pdata = dev_get_platdata(&pdev->dev); |
---|
246 | 233 | struct gpio_vbus_data *gpio_vbus; |
---|
247 | 234 | struct resource *res; |
---|
248 | | - int err, gpio, irq; |
---|
| 235 | + struct device *dev = &pdev->dev; |
---|
| 236 | + int err, irq; |
---|
249 | 237 | unsigned long irqflags; |
---|
250 | | - |
---|
251 | | - if (!pdata || !gpio_is_valid(pdata->gpio_vbus)) |
---|
252 | | - return -EINVAL; |
---|
253 | | - gpio = pdata->gpio_vbus; |
---|
254 | 238 | |
---|
255 | 239 | gpio_vbus = devm_kzalloc(&pdev->dev, sizeof(struct gpio_vbus_data), |
---|
256 | 240 | GFP_KERNEL); |
---|
.. | .. |
---|
273 | 257 | gpio_vbus->phy.otg->usb_phy = &gpio_vbus->phy; |
---|
274 | 258 | gpio_vbus->phy.otg->set_peripheral = gpio_vbus_set_peripheral; |
---|
275 | 259 | |
---|
276 | | - err = devm_gpio_request(&pdev->dev, gpio, "vbus_detect"); |
---|
277 | | - if (err) { |
---|
278 | | - dev_err(&pdev->dev, "can't request vbus gpio %d, err: %d\n", |
---|
279 | | - gpio, err); |
---|
| 260 | + /* Look up the VBUS sensing GPIO */ |
---|
| 261 | + gpio_vbus->vbus_gpiod = devm_gpiod_get(dev, "vbus", GPIOD_IN); |
---|
| 262 | + if (IS_ERR(gpio_vbus->vbus_gpiod)) { |
---|
| 263 | + err = PTR_ERR(gpio_vbus->vbus_gpiod); |
---|
| 264 | + dev_err(&pdev->dev, "can't request vbus gpio, err: %d\n", err); |
---|
280 | 265 | return err; |
---|
281 | 266 | } |
---|
282 | | - gpio_direction_input(gpio); |
---|
| 267 | + gpiod_set_consumer_name(gpio_vbus->vbus_gpiod, "vbus_detect"); |
---|
283 | 268 | |
---|
284 | 269 | res = platform_get_resource(pdev, IORESOURCE_IRQ, 0); |
---|
285 | 270 | if (res) { |
---|
286 | 271 | irq = res->start; |
---|
287 | 272 | irqflags = (res->flags & IRQF_TRIGGER_MASK) | IRQF_SHARED; |
---|
288 | 273 | } else { |
---|
289 | | - irq = gpio_to_irq(gpio); |
---|
| 274 | + irq = gpiod_to_irq(gpio_vbus->vbus_gpiod); |
---|
290 | 275 | irqflags = VBUS_IRQ_FLAGS; |
---|
291 | 276 | } |
---|
292 | 277 | |
---|
293 | 278 | gpio_vbus->irq = irq; |
---|
294 | 279 | |
---|
295 | | - /* if data line pullup is in use, initialize it to "not pulling up" */ |
---|
296 | | - gpio = pdata->gpio_pullup; |
---|
297 | | - if (gpio_is_valid(gpio)) { |
---|
298 | | - err = devm_gpio_request(&pdev->dev, gpio, "udc_pullup"); |
---|
299 | | - if (err) { |
---|
300 | | - dev_err(&pdev->dev, |
---|
301 | | - "can't request pullup gpio %d, err: %d\n", |
---|
302 | | - gpio, err); |
---|
303 | | - return err; |
---|
304 | | - } |
---|
305 | | - gpio_direction_output(gpio, pdata->gpio_pullup_inverted); |
---|
| 280 | + /* |
---|
| 281 | + * The VBUS sensing GPIO should have a pulldown, which will normally be |
---|
| 282 | + * part of a resistor ladder turning a 4.0V-5.25V level on VBUS into a |
---|
| 283 | + * value the GPIO detects as active. Some systems will use comparators. |
---|
| 284 | + * Get the optional D+ or D- pullup GPIO. If the data line pullup is |
---|
| 285 | + * in use, initialize it to "not pulling up" |
---|
| 286 | + */ |
---|
| 287 | + gpio_vbus->pullup_gpiod = devm_gpiod_get_optional(dev, "pullup", |
---|
| 288 | + GPIOD_OUT_LOW); |
---|
| 289 | + if (IS_ERR(gpio_vbus->pullup_gpiod)) { |
---|
| 290 | + err = PTR_ERR(gpio_vbus->pullup_gpiod); |
---|
| 291 | + dev_err(&pdev->dev, "can't request pullup gpio, err: %d\n", |
---|
| 292 | + err); |
---|
| 293 | + return err; |
---|
306 | 294 | } |
---|
| 295 | + if (gpio_vbus->pullup_gpiod) |
---|
| 296 | + gpiod_set_consumer_name(gpio_vbus->pullup_gpiod, "udc_pullup"); |
---|
307 | 297 | |
---|
308 | 298 | err = devm_request_irq(&pdev->dev, irq, gpio_vbus_irq, irqflags, |
---|
309 | 299 | "vbus_detect", pdev); |
---|
.. | .. |
---|
330 | 320 | return err; |
---|
331 | 321 | } |
---|
332 | 322 | |
---|
333 | | - device_init_wakeup(&pdev->dev, pdata->wakeup); |
---|
| 323 | + /* TODO: wakeup could be enabled here with device_init_wakeup(dev, 1) */ |
---|
334 | 324 | |
---|
335 | 325 | return 0; |
---|
336 | 326 | } |
---|