diff options
author | Joachim Foerster <joachim.foerster@missinglinkelectronics.com> | 2011-10-19 08:18:41 -0400 |
---|---|---|
committer | Greg Kroah-Hartman <gregkh@suse.de> | 2011-10-19 16:29:06 -0400 |
commit | 3a7655fcb210b349111251689d0a56b7250885ea (patch) | |
tree | b909f3f73d89d1af8807036a3922a19aca41b514 /drivers/usb/host/isp1760-if.c | |
parent | 0f8fd43c42f2cc249943be76a4db0d058c16b6dc (diff) |
usb/isp1760: Allow to optionally trigger low-level chip reset via GPIOLIB.
Properly triggering the reset wire is necessary with the ISP1761 used
on Terasic DE4 Altera-FPGA boards using a NIOS2 processor, for example.
This is an optional implementation for the OF binding only. The other
bindings just pass an invalid GPIO to the isp1760_register() routine.
Example, usage in DTS:
gpios = <&pio_isp1761rst_0 0 1>;
to point to a GPIO controller from within the ISP1761 node: GPIO 0, active low.
Signed-off-by: Joachim Foerster <joachim.foerster@missinglinkelectronics.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
Diffstat (limited to 'drivers/usb/host/isp1760-if.c')
-rw-r--r-- | drivers/usb/host/isp1760-if.c | 68 |
1 files changed, 53 insertions, 15 deletions
diff --git a/drivers/usb/host/isp1760-if.c b/drivers/usb/host/isp1760-if.c index 791792db6e12..2c7fc830c9e4 100644 --- a/drivers/usb/host/isp1760-if.c +++ b/drivers/usb/host/isp1760-if.c | |||
@@ -18,10 +18,12 @@ | |||
18 | #include "isp1760-hcd.h" | 18 | #include "isp1760-hcd.h" |
19 | 19 | ||
20 | #ifdef CONFIG_OF | 20 | #ifdef CONFIG_OF |
21 | #include <linux/slab.h> | ||
21 | #include <linux/of.h> | 22 | #include <linux/of.h> |
22 | #include <linux/of_platform.h> | 23 | #include <linux/of_platform.h> |
23 | #include <linux/of_address.h> | 24 | #include <linux/of_address.h> |
24 | #include <linux/of_irq.h> | 25 | #include <linux/of_irq.h> |
26 | #include <linux/of_gpio.h> | ||
25 | #endif | 27 | #endif |
26 | 28 | ||
27 | #ifdef CONFIG_PCI | 29 | #ifdef CONFIG_PCI |
@@ -29,9 +31,14 @@ | |||
29 | #endif | 31 | #endif |
30 | 32 | ||
31 | #ifdef CONFIG_OF | 33 | #ifdef CONFIG_OF |
34 | struct isp1760 { | ||
35 | struct usb_hcd *hcd; | ||
36 | int rst_gpio; | ||
37 | }; | ||
38 | |||
32 | static int of_isp1760_probe(struct platform_device *dev) | 39 | static int of_isp1760_probe(struct platform_device *dev) |
33 | { | 40 | { |
34 | struct usb_hcd *hcd; | 41 | struct isp1760 *drvdata; |
35 | struct device_node *dp = dev->dev.of_node; | 42 | struct device_node *dp = dev->dev.of_node; |
36 | struct resource *res; | 43 | struct resource *res; |
37 | struct resource memory; | 44 | struct resource memory; |
@@ -41,6 +48,11 @@ static int of_isp1760_probe(struct platform_device *dev) | |||
41 | int ret; | 48 | int ret; |
42 | const unsigned int *prop; | 49 | const unsigned int *prop; |
43 | unsigned int devflags = 0; | 50 | unsigned int devflags = 0; |
51 | enum of_gpio_flags gpio_flags; | ||
52 | |||
53 | drvdata = kzalloc(sizeof(*drvdata), GFP_KERNEL); | ||
54 | if (!drvdata) | ||
55 | return -ENOMEM; | ||
44 | 56 | ||
45 | ret = of_address_to_resource(dp, 0, &memory); | 57 | ret = of_address_to_resource(dp, 0, &memory); |
46 | if (ret) | 58 | if (ret) |
@@ -80,32 +92,57 @@ static int of_isp1760_probe(struct platform_device *dev) | |||
80 | if (of_get_property(dp, "dreq-polarity", NULL) != NULL) | 92 | if (of_get_property(dp, "dreq-polarity", NULL) != NULL) |
81 | devflags |= ISP1760_FLAG_DREQ_POL_HIGH; | 93 | devflags |= ISP1760_FLAG_DREQ_POL_HIGH; |
82 | 94 | ||
83 | hcd = isp1760_register(memory.start, res_len, virq, | 95 | drvdata->rst_gpio = of_get_gpio_flags(dp, 0, &gpio_flags); |
84 | IRQF_SHARED, &dev->dev, dev_name(&dev->dev), | 96 | if (gpio_is_valid(drvdata->rst_gpio)) { |
85 | devflags); | 97 | ret = gpio_request(drvdata->rst_gpio, dev_name(&dev->dev)); |
86 | if (IS_ERR(hcd)) { | 98 | if (!ret) { |
87 | ret = PTR_ERR(hcd); | 99 | if (!(gpio_flags & OF_GPIO_ACTIVE_LOW)) { |
88 | goto release_reg; | 100 | devflags |= ISP1760_FLAG_RESET_ACTIVE_HIGH; |
101 | gpio_direction_output(drvdata->rst_gpio, 0); | ||
102 | } else { | ||
103 | gpio_direction_output(drvdata->rst_gpio, 1); | ||
104 | } | ||
105 | } else { | ||
106 | drvdata->rst_gpio = ret; | ||
107 | } | ||
89 | } | 108 | } |
90 | 109 | ||
91 | dev_set_drvdata(&dev->dev, hcd); | 110 | drvdata->hcd = isp1760_register(memory.start, res_len, virq, |
111 | IRQF_SHARED, drvdata->rst_gpio, | ||
112 | &dev->dev, dev_name(&dev->dev), | ||
113 | devflags); | ||
114 | if (IS_ERR(drvdata->hcd)) { | ||
115 | ret = PTR_ERR(drvdata->hcd); | ||
116 | goto free_gpio; | ||
117 | } | ||
118 | |||
119 | dev_set_drvdata(&dev->dev, drvdata); | ||
92 | return ret; | 120 | return ret; |
93 | 121 | ||
122 | free_gpio: | ||
123 | if (gpio_is_valid(drvdata->rst_gpio)) | ||
124 | gpio_free(drvdata->rst_gpio); | ||
94 | release_reg: | 125 | release_reg: |
95 | release_mem_region(memory.start, res_len); | 126 | release_mem_region(memory.start, res_len); |
127 | kfree(drvdata); | ||
96 | return ret; | 128 | return ret; |
97 | } | 129 | } |
98 | 130 | ||
99 | static int of_isp1760_remove(struct platform_device *dev) | 131 | static int of_isp1760_remove(struct platform_device *dev) |
100 | { | 132 | { |
101 | struct usb_hcd *hcd = dev_get_drvdata(&dev->dev); | 133 | struct isp1760 *drvdata = dev_get_drvdata(&dev->dev); |
102 | 134 | ||
103 | dev_set_drvdata(&dev->dev, NULL); | 135 | dev_set_drvdata(&dev->dev, NULL); |
104 | 136 | ||
105 | usb_remove_hcd(hcd); | 137 | usb_remove_hcd(drvdata->hcd); |
106 | iounmap(hcd->regs); | 138 | iounmap(drvdata->hcd->regs); |
107 | release_mem_region(hcd->rsrc_start, hcd->rsrc_len); | 139 | release_mem_region(drvdata->hcd->rsrc_start, drvdata->hcd->rsrc_len); |
108 | usb_put_hcd(hcd); | 140 | usb_put_hcd(drvdata->hcd); |
141 | |||
142 | if (gpio_is_valid(drvdata->rst_gpio)) | ||
143 | gpio_free(drvdata->rst_gpio); | ||
144 | |||
145 | kfree(drvdata); | ||
109 | return 0; | 146 | return 0; |
110 | } | 147 | } |
111 | 148 | ||
@@ -242,7 +279,7 @@ static int __devinit isp1761_pci_probe(struct pci_dev *dev, | |||
242 | 279 | ||
243 | dev->dev.dma_mask = NULL; | 280 | dev->dev.dma_mask = NULL; |
244 | hcd = isp1760_register(pci_mem_phy0, memlength, dev->irq, | 281 | hcd = isp1760_register(pci_mem_phy0, memlength, dev->irq, |
245 | IRQF_SHARED, &dev->dev, dev_name(&dev->dev), | 282 | IRQF_SHARED, -ENOENT, &dev->dev, dev_name(&dev->dev), |
246 | devflags); | 283 | devflags); |
247 | if (IS_ERR(hcd)) { | 284 | if (IS_ERR(hcd)) { |
248 | ret_status = -ENODEV; | 285 | ret_status = -ENODEV; |
@@ -353,7 +390,8 @@ static int __devinit isp1760_plat_probe(struct platform_device *pdev) | |||
353 | } | 390 | } |
354 | 391 | ||
355 | hcd = isp1760_register(mem_res->start, mem_size, irq_res->start, | 392 | hcd = isp1760_register(mem_res->start, mem_size, irq_res->start, |
356 | irqflags, &pdev->dev, dev_name(&pdev->dev), devflags); | 393 | irqflags, -ENOENT, |
394 | &pdev->dev, dev_name(&pdev->dev), devflags); | ||
357 | if (IS_ERR(hcd)) { | 395 | if (IS_ERR(hcd)) { |
358 | pr_warning("isp1760: Failed to register the HCD device\n"); | 396 | pr_warning("isp1760: Failed to register the HCD device\n"); |
359 | ret = -ENODEV; | 397 | ret = -ENODEV; |