aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorBartosz Golaszewski <bgolaszewski@baylibre.com>2019-02-11 05:36:59 -0500
committerSekhar Nori <nsekhar@ti.com>2019-02-12 03:18:51 -0500
commitd193abf1c91307d8a2d5a3b984ddcf66f5dcfbea (patch)
tree5b71978ebf3bed2ab7188a3faccd338f7ac04597
parent1703cf5d4fc064852d09a877ef71befb6ba386e6 (diff)
usb: ohci-da8xx: add vbus and overcurrent gpios
There are two users upstream which register external callbacks for switching the port power on/off and overcurrent protection. Both users only use two GPIOs for that. Instead of having that functionality in the board files, move the logic into the OHCI driver - including the interrupt handler for overcurrent detection. Signed-off-by: Bartosz Golaszewski <bgolaszewski@baylibre.com> Acked-by: Alan Stern <stern@rowland.harvard.edu> Signed-off-by: Sekhar Nori <nsekhar@ti.com>
-rw-r--r--drivers/usb/host/ohci-da8xx.c99
1 files changed, 50 insertions, 49 deletions
diff --git a/drivers/usb/host/ohci-da8xx.c b/drivers/usb/host/ohci-da8xx.c
index e8ede0b5e3f0..ca8a94f15ac0 100644
--- a/drivers/usb/host/ohci-da8xx.c
+++ b/drivers/usb/host/ohci-da8xx.c
@@ -9,6 +9,7 @@
9 */ 9 */
10 10
11#include <linux/clk.h> 11#include <linux/clk.h>
12#include <linux/gpio/consumer.h>
12#include <linux/io.h> 13#include <linux/io.h>
13#include <linux/interrupt.h> 14#include <linux/interrupt.h>
14#include <linux/jiffies.h> 15#include <linux/jiffies.h>
@@ -40,6 +41,8 @@ struct da8xx_ohci_hcd {
40 struct regulator *vbus_reg; 41 struct regulator *vbus_reg;
41 struct notifier_block nb; 42 struct notifier_block nb;
42 unsigned int reg_enabled; 43 unsigned int reg_enabled;
44 struct gpio_desc *vbus_gpio;
45 struct gpio_desc *oc_gpio;
43}; 46};
44 47
45#define to_da8xx_ohci(hcd) (struct da8xx_ohci_hcd *)(hcd_to_ohci(hcd)->priv) 48#define to_da8xx_ohci(hcd) (struct da8xx_ohci_hcd *)(hcd_to_ohci(hcd)->priv)
@@ -86,12 +89,13 @@ static void ohci_da8xx_disable(struct usb_hcd *hcd)
86static int ohci_da8xx_set_power(struct usb_hcd *hcd, int on) 89static int ohci_da8xx_set_power(struct usb_hcd *hcd, int on)
87{ 90{
88 struct da8xx_ohci_hcd *da8xx_ohci = to_da8xx_ohci(hcd); 91 struct da8xx_ohci_hcd *da8xx_ohci = to_da8xx_ohci(hcd);
89 struct device *dev = hcd->self.controller; 92 struct device *dev = hcd->self.controller;
90 struct da8xx_ohci_root_hub *hub = dev_get_platdata(dev);
91 int ret; 93 int ret;
92 94
93 if (hub && hub->set_power) 95 if (da8xx_ohci->vbus_gpio) {
94 return hub->set_power(1, on); 96 gpiod_set_value_cansleep(da8xx_ohci->vbus_gpio, on);
97 return 0;
98 }
95 99
96 if (!da8xx_ohci->vbus_reg) 100 if (!da8xx_ohci->vbus_reg)
97 return 0; 101 return 0;
@@ -119,11 +123,9 @@ static int ohci_da8xx_set_power(struct usb_hcd *hcd, int on)
119static int ohci_da8xx_get_power(struct usb_hcd *hcd) 123static int ohci_da8xx_get_power(struct usb_hcd *hcd)
120{ 124{
121 struct da8xx_ohci_hcd *da8xx_ohci = to_da8xx_ohci(hcd); 125 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 126
125 if (hub && hub->get_power) 127 if (da8xx_ohci->vbus_gpio)
126 return hub->get_power(1); 128 return gpiod_get_value_cansleep(da8xx_ohci->vbus_gpio);
127 129
128 if (da8xx_ohci->vbus_reg) 130 if (da8xx_ohci->vbus_reg)
129 return regulator_is_enabled(da8xx_ohci->vbus_reg); 131 return regulator_is_enabled(da8xx_ohci->vbus_reg);
@@ -134,13 +136,11 @@ static int ohci_da8xx_get_power(struct usb_hcd *hcd)
134static int ohci_da8xx_get_oci(struct usb_hcd *hcd) 136static int ohci_da8xx_get_oci(struct usb_hcd *hcd)
135{ 137{
136 struct da8xx_ohci_hcd *da8xx_ohci = to_da8xx_ohci(hcd); 138 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 unsigned int flags; 139 unsigned int flags;
140 int ret; 140 int ret;
141 141
142 if (hub && hub->get_oci) 142 if (da8xx_ohci->oc_gpio)
143 return hub->get_oci(1); 143 return gpiod_get_value_cansleep(da8xx_ohci->oc_gpio);
144 144
145 if (!da8xx_ohci->vbus_reg) 145 if (!da8xx_ohci->vbus_reg)
146 return 0; 146 return 0;
@@ -158,10 +158,8 @@ static int ohci_da8xx_get_oci(struct usb_hcd *hcd)
158static int ohci_da8xx_has_set_power(struct usb_hcd *hcd) 158static int ohci_da8xx_has_set_power(struct usb_hcd *hcd)
159{ 159{
160 struct da8xx_ohci_hcd *da8xx_ohci = to_da8xx_ohci(hcd); 160 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 161
164 if (hub && hub->set_power) 162 if (da8xx_ohci->vbus_gpio)
165 return 1; 163 return 1;
166 164
167 if (da8xx_ohci->vbus_reg) 165 if (da8xx_ohci->vbus_reg)
@@ -173,10 +171,8 @@ static int ohci_da8xx_has_set_power(struct usb_hcd *hcd)
173static int ohci_da8xx_has_oci(struct usb_hcd *hcd) 171static int ohci_da8xx_has_oci(struct usb_hcd *hcd)
174{ 172{
175 struct da8xx_ohci_hcd *da8xx_ohci = to_da8xx_ohci(hcd); 173 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 174
179 if (hub && hub->get_oci) 175 if (da8xx_ohci->oc_gpio)
180 return 1; 176 return 1;
181 177
182 if (da8xx_ohci->vbus_reg) 178 if (da8xx_ohci->vbus_reg)
@@ -196,19 +192,6 @@ static int ohci_da8xx_has_potpgt(struct usb_hcd *hcd)
196 return 0; 192 return 0;
197} 193}
198 194
199/*
200 * Handle the port over-current indicator change.
201 */
202static 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
212static int ohci_da8xx_regulator_event(struct notifier_block *nb, 195static int ohci_da8xx_regulator_event(struct notifier_block *nb,
213 unsigned long event, void *data) 196 unsigned long event, void *data)
214{ 197{
@@ -223,16 +206,23 @@ static int ohci_da8xx_regulator_event(struct notifier_block *nb,
223 return 0; 206 return 0;
224} 207}
225 208
209static irqreturn_t ohci_da8xx_oc_handler(int irq, void *data)
210{
211 struct da8xx_ohci_hcd *da8xx_ohci = data;
212
213 if (gpiod_get_value(da8xx_ohci->oc_gpio))
214 gpiod_set_value(da8xx_ohci->vbus_gpio, 0);
215
216 return IRQ_HANDLED;
217}
218
226static int ohci_da8xx_register_notify(struct usb_hcd *hcd) 219static int ohci_da8xx_register_notify(struct usb_hcd *hcd)
227{ 220{
228 struct da8xx_ohci_hcd *da8xx_ohci = to_da8xx_ohci(hcd); 221 struct da8xx_ohci_hcd *da8xx_ohci = to_da8xx_ohci(hcd);
229 struct device *dev = hcd->self.controller; 222 struct device *dev = hcd->self.controller;
230 struct da8xx_ohci_root_hub *hub = dev_get_platdata(dev);
231 int ret = 0; 223 int ret = 0;
232 224
233 if (hub && hub->ocic_notify) { 225 if (!da8xx_ohci->oc_gpio && da8xx_ohci->vbus_reg) {
234 ret = hub->ocic_notify(ohci_da8xx_ocic_handler);
235 } else if (da8xx_ohci->vbus_reg) {
236 da8xx_ohci->nb.notifier_call = ohci_da8xx_regulator_event; 226 da8xx_ohci->nb.notifier_call = ohci_da8xx_regulator_event;
237 ret = devm_regulator_register_notifier(da8xx_ohci->vbus_reg, 227 ret = devm_regulator_register_notifier(da8xx_ohci->vbus_reg,
238 &da8xx_ohci->nb); 228 &da8xx_ohci->nb);
@@ -244,15 +234,6 @@ static int ohci_da8xx_register_notify(struct usb_hcd *hcd)
244 return ret; 234 return ret;
245} 235}
246 236
247static 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}
255
256static int ohci_da8xx_reset(struct usb_hcd *hcd) 237static int ohci_da8xx_reset(struct usb_hcd *hcd)
257{ 238{
258 struct device *dev = hcd->self.controller; 239 struct device *dev = hcd->self.controller;
@@ -403,9 +384,9 @@ static int ohci_da8xx_probe(struct platform_device *pdev)
403{ 384{
404 struct da8xx_ohci_hcd *da8xx_ohci; 385 struct da8xx_ohci_hcd *da8xx_ohci;
405 struct device *dev = &pdev->dev; 386 struct device *dev = &pdev->dev;
387 int error, hcd_irq, oc_irq;
406 struct usb_hcd *hcd; 388 struct usb_hcd *hcd;
407 struct resource *mem; 389 struct resource *mem;
408 int error, irq;
409 390
410 hcd = usb_create_hcd(&ohci_da8xx_hc_driver, dev, dev_name(dev)); 391 hcd = usb_create_hcd(&ohci_da8xx_hc_driver, dev, dev_name(dev));
411 if (!hcd) 392 if (!hcd)
@@ -443,6 +424,27 @@ static int ohci_da8xx_probe(struct platform_device *pdev)
443 } 424 }
444 } 425 }
445 426
427 da8xx_ohci->vbus_gpio = devm_gpiod_get_optional(dev, "vbus",
428 GPIOD_OUT_HIGH);
429 if (IS_ERR(da8xx_ohci->vbus_gpio))
430 goto err;
431
432 da8xx_ohci->oc_gpio = devm_gpiod_get_optional(dev, "oc", GPIOD_IN);
433 if (IS_ERR(da8xx_ohci->oc_gpio))
434 goto err;
435
436 if (da8xx_ohci->oc_gpio) {
437 oc_irq = gpiod_to_irq(da8xx_ohci->oc_gpio);
438 if (oc_irq < 0)
439 goto err;
440
441 error = devm_request_irq(dev, oc_irq, ohci_da8xx_oc_handler,
442 IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING,
443 "OHCI over-current indicator", da8xx_ohci);
444 if (error)
445 goto err;
446 }
447
446 mem = platform_get_resource(pdev, IORESOURCE_MEM, 0); 448 mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
447 hcd->regs = devm_ioremap_resource(dev, mem); 449 hcd->regs = devm_ioremap_resource(dev, mem);
448 if (IS_ERR(hcd->regs)) { 450 if (IS_ERR(hcd->regs)) {
@@ -452,13 +454,13 @@ static int ohci_da8xx_probe(struct platform_device *pdev)
452 hcd->rsrc_start = mem->start; 454 hcd->rsrc_start = mem->start;
453 hcd->rsrc_len = resource_size(mem); 455 hcd->rsrc_len = resource_size(mem);
454 456
455 irq = platform_get_irq(pdev, 0); 457 hcd_irq = platform_get_irq(pdev, 0);
456 if (irq < 0) { 458 if (hcd_irq < 0) {
457 error = -ENODEV; 459 error = -ENODEV;
458 goto err; 460 goto err;
459 } 461 }
460 462
461 error = usb_add_hcd(hcd, irq, 0); 463 error = usb_add_hcd(hcd, hcd_irq, 0);
462 if (error) 464 if (error)
463 goto err; 465 goto err;
464 466
@@ -481,7 +483,6 @@ static int ohci_da8xx_remove(struct platform_device *pdev)
481{ 483{
482 struct usb_hcd *hcd = platform_get_drvdata(pdev); 484 struct usb_hcd *hcd = platform_get_drvdata(pdev);
483 485
484 ohci_da8xx_unregister_notify(hcd);
485 usb_remove_hcd(hcd); 486 usb_remove_hcd(hcd);
486 usb_put_hcd(hcd); 487 usb_put_hcd(hcd);
487 488