.. | .. |
---|
9 | 9 | */ |
---|
10 | 10 | |
---|
11 | 11 | #include <linux/clk.h> |
---|
| 12 | +#include <linux/gpio/consumer.h> |
---|
12 | 13 | #include <linux/io.h> |
---|
13 | 14 | #include <linux/interrupt.h> |
---|
14 | 15 | #include <linux/jiffies.h> |
---|
.. | .. |
---|
39 | 40 | struct phy *usb11_phy; |
---|
40 | 41 | struct regulator *vbus_reg; |
---|
41 | 42 | struct notifier_block nb; |
---|
42 | | - unsigned int reg_enabled; |
---|
| 43 | + struct gpio_desc *oc_gpio; |
---|
43 | 44 | }; |
---|
44 | 45 | |
---|
45 | 46 | #define to_da8xx_ohci(hcd) (struct da8xx_ohci_hcd *)(hcd_to_ohci(hcd)->priv) |
---|
.. | .. |
---|
86 | 87 | static int ohci_da8xx_set_power(struct usb_hcd *hcd, int on) |
---|
87 | 88 | { |
---|
88 | 89 | struct da8xx_ohci_hcd *da8xx_ohci = to_da8xx_ohci(hcd); |
---|
89 | | - struct device *dev = hcd->self.controller; |
---|
90 | | - struct da8xx_ohci_root_hub *hub = dev_get_platdata(dev); |
---|
| 90 | + struct device *dev = hcd->self.controller; |
---|
91 | 91 | int ret; |
---|
92 | | - |
---|
93 | | - if (hub && hub->set_power) |
---|
94 | | - return hub->set_power(1, on); |
---|
95 | 92 | |
---|
96 | 93 | if (!da8xx_ohci->vbus_reg) |
---|
97 | 94 | return 0; |
---|
98 | 95 | |
---|
99 | | - if (on && !da8xx_ohci->reg_enabled) { |
---|
| 96 | + if (on) { |
---|
100 | 97 | ret = regulator_enable(da8xx_ohci->vbus_reg); |
---|
101 | 98 | if (ret) { |
---|
102 | 99 | dev_err(dev, "Failed to enable regulator: %d\n", ret); |
---|
103 | 100 | return ret; |
---|
104 | 101 | } |
---|
105 | | - da8xx_ohci->reg_enabled = 1; |
---|
106 | | - |
---|
107 | | - } else if (!on && da8xx_ohci->reg_enabled) { |
---|
| 102 | + } else { |
---|
108 | 103 | ret = regulator_disable(da8xx_ohci->vbus_reg); |
---|
109 | 104 | if (ret) { |
---|
110 | 105 | dev_err(dev, "Failed to disable regulator: %d\n", ret); |
---|
111 | 106 | return ret; |
---|
112 | 107 | } |
---|
113 | | - da8xx_ohci->reg_enabled = 0; |
---|
114 | 108 | } |
---|
115 | 109 | |
---|
116 | 110 | return 0; |
---|
.. | .. |
---|
119 | 113 | static int ohci_da8xx_get_power(struct usb_hcd *hcd) |
---|
120 | 114 | { |
---|
121 | 115 | struct da8xx_ohci_hcd *da8xx_ohci = to_da8xx_ohci(hcd); |
---|
122 | | - struct device *dev = hcd->self.controller; |
---|
123 | | - struct da8xx_ohci_root_hub *hub = dev_get_platdata(dev); |
---|
124 | | - |
---|
125 | | - if (hub && hub->get_power) |
---|
126 | | - return hub->get_power(1); |
---|
127 | 116 | |
---|
128 | 117 | if (da8xx_ohci->vbus_reg) |
---|
129 | 118 | return regulator_is_enabled(da8xx_ohci->vbus_reg); |
---|
.. | .. |
---|
134 | 123 | static int ohci_da8xx_get_oci(struct usb_hcd *hcd) |
---|
135 | 124 | { |
---|
136 | 125 | struct da8xx_ohci_hcd *da8xx_ohci = to_da8xx_ohci(hcd); |
---|
137 | | - struct device *dev = hcd->self.controller; |
---|
138 | | - struct da8xx_ohci_root_hub *hub = dev_get_platdata(dev); |
---|
139 | 126 | unsigned int flags; |
---|
140 | 127 | int ret; |
---|
141 | 128 | |
---|
142 | | - if (hub && hub->get_oci) |
---|
143 | | - return hub->get_oci(1); |
---|
| 129 | + if (da8xx_ohci->oc_gpio) |
---|
| 130 | + return gpiod_get_value_cansleep(da8xx_ohci->oc_gpio); |
---|
144 | 131 | |
---|
145 | 132 | if (!da8xx_ohci->vbus_reg) |
---|
146 | 133 | return 0; |
---|
.. | .. |
---|
158 | 145 | static int ohci_da8xx_has_set_power(struct usb_hcd *hcd) |
---|
159 | 146 | { |
---|
160 | 147 | struct da8xx_ohci_hcd *da8xx_ohci = to_da8xx_ohci(hcd); |
---|
161 | | - struct device *dev = hcd->self.controller; |
---|
162 | | - struct da8xx_ohci_root_hub *hub = dev_get_platdata(dev); |
---|
163 | | - |
---|
164 | | - if (hub && hub->set_power) |
---|
165 | | - return 1; |
---|
166 | 148 | |
---|
167 | 149 | if (da8xx_ohci->vbus_reg) |
---|
168 | 150 | return 1; |
---|
.. | .. |
---|
173 | 155 | static int ohci_da8xx_has_oci(struct usb_hcd *hcd) |
---|
174 | 156 | { |
---|
175 | 157 | struct da8xx_ohci_hcd *da8xx_ohci = to_da8xx_ohci(hcd); |
---|
176 | | - struct device *dev = hcd->self.controller; |
---|
177 | | - struct da8xx_ohci_root_hub *hub = dev_get_platdata(dev); |
---|
178 | 158 | |
---|
179 | | - if (hub && hub->get_oci) |
---|
| 159 | + if (da8xx_ohci->oc_gpio) |
---|
180 | 160 | return 1; |
---|
181 | 161 | |
---|
182 | 162 | if (da8xx_ohci->vbus_reg) |
---|
.. | .. |
---|
196 | 176 | return 0; |
---|
197 | 177 | } |
---|
198 | 178 | |
---|
199 | | -/* |
---|
200 | | - * Handle the port over-current indicator change. |
---|
201 | | - */ |
---|
202 | | -static void ohci_da8xx_ocic_handler(struct da8xx_ohci_root_hub *hub, |
---|
203 | | - unsigned port) |
---|
204 | | -{ |
---|
205 | | - ocic_mask |= 1 << port; |
---|
206 | | - |
---|
207 | | - /* Once over-current is detected, the port needs to be powered down */ |
---|
208 | | - if (hub->get_oci(port) > 0) |
---|
209 | | - hub->set_power(port, 0); |
---|
210 | | -} |
---|
211 | | - |
---|
212 | 179 | static int ohci_da8xx_regulator_event(struct notifier_block *nb, |
---|
213 | 180 | unsigned long event, void *data) |
---|
214 | 181 | { |
---|
.. | .. |
---|
223 | 190 | return 0; |
---|
224 | 191 | } |
---|
225 | 192 | |
---|
| 193 | +static irqreturn_t ohci_da8xx_oc_thread(int irq, void *data) |
---|
| 194 | +{ |
---|
| 195 | + struct da8xx_ohci_hcd *da8xx_ohci = data; |
---|
| 196 | + struct device *dev = da8xx_ohci->hcd->self.controller; |
---|
| 197 | + int ret; |
---|
| 198 | + |
---|
| 199 | + if (gpiod_get_value_cansleep(da8xx_ohci->oc_gpio) && |
---|
| 200 | + da8xx_ohci->vbus_reg) { |
---|
| 201 | + ret = regulator_disable(da8xx_ohci->vbus_reg); |
---|
| 202 | + if (ret) |
---|
| 203 | + dev_err(dev, "Failed to disable regulator: %d\n", ret); |
---|
| 204 | + } |
---|
| 205 | + |
---|
| 206 | + return IRQ_HANDLED; |
---|
| 207 | +} |
---|
| 208 | + |
---|
226 | 209 | static int ohci_da8xx_register_notify(struct usb_hcd *hcd) |
---|
227 | 210 | { |
---|
228 | 211 | struct da8xx_ohci_hcd *da8xx_ohci = to_da8xx_ohci(hcd); |
---|
229 | 212 | struct device *dev = hcd->self.controller; |
---|
230 | | - struct da8xx_ohci_root_hub *hub = dev_get_platdata(dev); |
---|
231 | 213 | int ret = 0; |
---|
232 | 214 | |
---|
233 | | - if (hub && hub->ocic_notify) { |
---|
234 | | - ret = hub->ocic_notify(ohci_da8xx_ocic_handler); |
---|
235 | | - } else if (da8xx_ohci->vbus_reg) { |
---|
| 215 | + if (!da8xx_ohci->oc_gpio && da8xx_ohci->vbus_reg) { |
---|
236 | 216 | da8xx_ohci->nb.notifier_call = ohci_da8xx_regulator_event; |
---|
237 | 217 | ret = devm_regulator_register_notifier(da8xx_ohci->vbus_reg, |
---|
238 | 218 | &da8xx_ohci->nb); |
---|
.. | .. |
---|
242 | 222 | dev_err(dev, "Failed to register notifier: %d\n", ret); |
---|
243 | 223 | |
---|
244 | 224 | return ret; |
---|
245 | | -} |
---|
246 | | - |
---|
247 | | -static void ohci_da8xx_unregister_notify(struct usb_hcd *hcd) |
---|
248 | | -{ |
---|
249 | | - struct device *dev = hcd->self.controller; |
---|
250 | | - struct da8xx_ohci_root_hub *hub = dev_get_platdata(dev); |
---|
251 | | - |
---|
252 | | - if (hub && hub->ocic_notify) |
---|
253 | | - hub->ocic_notify(NULL); |
---|
254 | 225 | } |
---|
255 | 226 | |
---|
256 | 227 | static int ohci_da8xx_reset(struct usb_hcd *hcd) |
---|
.. | .. |
---|
402 | 373 | static int ohci_da8xx_probe(struct platform_device *pdev) |
---|
403 | 374 | { |
---|
404 | 375 | struct da8xx_ohci_hcd *da8xx_ohci; |
---|
| 376 | + struct device *dev = &pdev->dev; |
---|
| 377 | + int error, hcd_irq, oc_irq; |
---|
405 | 378 | struct usb_hcd *hcd; |
---|
406 | 379 | struct resource *mem; |
---|
407 | | - int error, irq; |
---|
408 | | - hcd = usb_create_hcd(&ohci_da8xx_hc_driver, &pdev->dev, |
---|
409 | | - dev_name(&pdev->dev)); |
---|
| 380 | + |
---|
| 381 | + hcd = usb_create_hcd(&ohci_da8xx_hc_driver, dev, dev_name(dev)); |
---|
410 | 382 | if (!hcd) |
---|
411 | 383 | return -ENOMEM; |
---|
412 | 384 | |
---|
413 | 385 | da8xx_ohci = to_da8xx_ohci(hcd); |
---|
414 | 386 | da8xx_ohci->hcd = hcd; |
---|
415 | 387 | |
---|
416 | | - da8xx_ohci->usb11_clk = devm_clk_get(&pdev->dev, NULL); |
---|
| 388 | + da8xx_ohci->usb11_clk = devm_clk_get(dev, NULL); |
---|
417 | 389 | if (IS_ERR(da8xx_ohci->usb11_clk)) { |
---|
418 | 390 | error = PTR_ERR(da8xx_ohci->usb11_clk); |
---|
419 | 391 | if (error != -EPROBE_DEFER) |
---|
420 | | - dev_err(&pdev->dev, "Failed to get clock.\n"); |
---|
| 392 | + dev_err(dev, "Failed to get clock.\n"); |
---|
421 | 393 | goto err; |
---|
422 | 394 | } |
---|
423 | 395 | |
---|
424 | | - da8xx_ohci->usb11_phy = devm_phy_get(&pdev->dev, "usb-phy"); |
---|
| 396 | + da8xx_ohci->usb11_phy = devm_phy_get(dev, "usb-phy"); |
---|
425 | 397 | if (IS_ERR(da8xx_ohci->usb11_phy)) { |
---|
426 | 398 | error = PTR_ERR(da8xx_ohci->usb11_phy); |
---|
427 | 399 | if (error != -EPROBE_DEFER) |
---|
428 | | - dev_err(&pdev->dev, "Failed to get phy.\n"); |
---|
| 400 | + dev_err(dev, "Failed to get phy.\n"); |
---|
429 | 401 | goto err; |
---|
430 | 402 | } |
---|
431 | 403 | |
---|
432 | | - da8xx_ohci->vbus_reg = devm_regulator_get_optional(&pdev->dev, "vbus"); |
---|
| 404 | + da8xx_ohci->vbus_reg = devm_regulator_get_optional(dev, "vbus"); |
---|
433 | 405 | if (IS_ERR(da8xx_ohci->vbus_reg)) { |
---|
434 | 406 | error = PTR_ERR(da8xx_ohci->vbus_reg); |
---|
435 | 407 | if (error == -ENODEV) { |
---|
.. | .. |
---|
437 | 409 | } else if (error == -EPROBE_DEFER) { |
---|
438 | 410 | goto err; |
---|
439 | 411 | } else { |
---|
440 | | - dev_err(&pdev->dev, "Failed to get regulator\n"); |
---|
| 412 | + dev_err(dev, "Failed to get regulator\n"); |
---|
441 | 413 | goto err; |
---|
442 | 414 | } |
---|
443 | 415 | } |
---|
444 | 416 | |
---|
| 417 | + da8xx_ohci->oc_gpio = devm_gpiod_get_optional(dev, "oc", GPIOD_IN); |
---|
| 418 | + if (IS_ERR(da8xx_ohci->oc_gpio)) { |
---|
| 419 | + error = PTR_ERR(da8xx_ohci->oc_gpio); |
---|
| 420 | + goto err; |
---|
| 421 | + } |
---|
| 422 | + |
---|
| 423 | + if (da8xx_ohci->oc_gpio) { |
---|
| 424 | + oc_irq = gpiod_to_irq(da8xx_ohci->oc_gpio); |
---|
| 425 | + if (oc_irq < 0) { |
---|
| 426 | + error = oc_irq; |
---|
| 427 | + goto err; |
---|
| 428 | + } |
---|
| 429 | + |
---|
| 430 | + error = devm_request_threaded_irq(dev, oc_irq, NULL, |
---|
| 431 | + ohci_da8xx_oc_thread, IRQF_TRIGGER_RISING | |
---|
| 432 | + IRQF_TRIGGER_FALLING | IRQF_ONESHOT, |
---|
| 433 | + "OHCI over-current indicator", da8xx_ohci); |
---|
| 434 | + if (error) |
---|
| 435 | + goto err; |
---|
| 436 | + } |
---|
| 437 | + |
---|
445 | 438 | mem = platform_get_resource(pdev, IORESOURCE_MEM, 0); |
---|
446 | | - hcd->regs = devm_ioremap_resource(&pdev->dev, mem); |
---|
| 439 | + hcd->regs = devm_ioremap_resource(dev, mem); |
---|
447 | 440 | if (IS_ERR(hcd->regs)) { |
---|
448 | 441 | error = PTR_ERR(hcd->regs); |
---|
449 | 442 | goto err; |
---|
.. | .. |
---|
451 | 444 | hcd->rsrc_start = mem->start; |
---|
452 | 445 | hcd->rsrc_len = resource_size(mem); |
---|
453 | 446 | |
---|
454 | | - irq = platform_get_irq(pdev, 0); |
---|
455 | | - if (irq < 0) { |
---|
| 447 | + hcd_irq = platform_get_irq(pdev, 0); |
---|
| 448 | + if (hcd_irq < 0) { |
---|
456 | 449 | error = -ENODEV; |
---|
457 | 450 | goto err; |
---|
458 | 451 | } |
---|
459 | 452 | |
---|
460 | | - error = usb_add_hcd(hcd, irq, 0); |
---|
| 453 | + error = usb_add_hcd(hcd, hcd_irq, 0); |
---|
461 | 454 | if (error) |
---|
462 | 455 | goto err; |
---|
463 | 456 | |
---|
.. | .. |
---|
480 | 473 | { |
---|
481 | 474 | struct usb_hcd *hcd = platform_get_drvdata(pdev); |
---|
482 | 475 | |
---|
483 | | - ohci_da8xx_unregister_notify(hcd); |
---|
484 | 476 | usb_remove_hcd(hcd); |
---|
485 | 477 | usb_put_hcd(hcd); |
---|
486 | 478 | |
---|