Commit 3a7655fcb210b349111251689d0a56b7250885ea
Committed by
Greg Kroah-Hartman
1 parent
0f8fd43c42
Exists in
master
and in
6 other branches
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>
Showing 3 changed files with 72 additions and 15 deletions Side-by-side Diff
drivers/usb/host/isp1760-hcd.c
... | ... | @@ -24,6 +24,7 @@ |
24 | 24 | #include <linux/timer.h> |
25 | 25 | #include <asm/unaligned.h> |
26 | 26 | #include <asm/cacheflush.h> |
27 | +#include <linux/gpio.h> | |
27 | 28 | |
28 | 29 | #include "isp1760-hcd.h" |
29 | 30 | |
... | ... | @@ -48,6 +49,8 @@ |
48 | 49 | unsigned long reset_done; |
49 | 50 | unsigned long next_statechange; |
50 | 51 | unsigned int devflags; |
52 | + | |
53 | + int rst_gpio; | |
51 | 54 | }; |
52 | 55 | |
53 | 56 | static inline struct isp1760_hcd *hcd_to_priv(struct usb_hcd *hcd) |
... | ... | @@ -433,6 +436,18 @@ |
433 | 436 | int result; |
434 | 437 | u32 scratch, hwmode; |
435 | 438 | |
439 | + /* low-level chip reset */ | |
440 | + if (gpio_is_valid(priv->rst_gpio)) { | |
441 | + unsigned int rst_lvl; | |
442 | + | |
443 | + rst_lvl = (priv->devflags & | |
444 | + ISP1760_FLAG_RESET_ACTIVE_HIGH) ? 1 : 0; | |
445 | + | |
446 | + gpio_set_value(priv->rst_gpio, rst_lvl); | |
447 | + mdelay(50); | |
448 | + gpio_set_value(priv->rst_gpio, !rst_lvl); | |
449 | + } | |
450 | + | |
436 | 451 | /* Setup HW Mode Control: This assumes a level active-low interrupt */ |
437 | 452 | hwmode = HW_DATA_BUS_32BIT; |
438 | 453 | |
... | ... | @@ -2207,6 +2222,7 @@ |
2207 | 2222 | |
2208 | 2223 | struct usb_hcd *isp1760_register(phys_addr_t res_start, resource_size_t res_len, |
2209 | 2224 | int irq, unsigned long irqflags, |
2225 | + int rst_gpio, | |
2210 | 2226 | struct device *dev, const char *busname, |
2211 | 2227 | unsigned int devflags) |
2212 | 2228 | { |
... | ... | @@ -2226,6 +2242,7 @@ |
2226 | 2242 | |
2227 | 2243 | priv = hcd_to_priv(hcd); |
2228 | 2244 | priv->devflags = devflags; |
2245 | + priv->rst_gpio = rst_gpio; | |
2229 | 2246 | init_memory(priv); |
2230 | 2247 | hcd->regs = ioremap(res_start, res_len); |
2231 | 2248 | if (!hcd->regs) { |
drivers/usb/host/isp1760-hcd.h
... | ... | @@ -4,6 +4,7 @@ |
4 | 4 | /* exports for if */ |
5 | 5 | struct usb_hcd *isp1760_register(phys_addr_t res_start, resource_size_t res_len, |
6 | 6 | int irq, unsigned long irqflags, |
7 | + int rst_gpio, | |
7 | 8 | struct device *dev, const char *busname, |
8 | 9 | unsigned int devflags); |
9 | 10 | int init_kmem_once(void); |
... | ... | @@ -126,6 +127,7 @@ |
126 | 127 | #define ISP1760_FLAG_ISP1761 0x00000040 /* Chip is ISP1761 */ |
127 | 128 | #define ISP1760_FLAG_INTR_POL_HIGH 0x00000080 /* Interrupt polarity active high */ |
128 | 129 | #define ISP1760_FLAG_INTR_EDGE_TRIG 0x00000100 /* Interrupt edge triggered */ |
130 | +#define ISP1760_FLAG_RESET_ACTIVE_HIGH 0x80000000 /* RESET GPIO active high */ | |
129 | 131 | |
130 | 132 | /* chip memory management */ |
131 | 133 | struct memory_chunk { |
drivers/usb/host/isp1760-if.c
... | ... | @@ -18,10 +18,12 @@ |
18 | 18 | #include "isp1760-hcd.h" |
19 | 19 | |
20 | 20 | #ifdef CONFIG_OF |
21 | +#include <linux/slab.h> | |
21 | 22 | #include <linux/of.h> |
22 | 23 | #include <linux/of_platform.h> |
23 | 24 | #include <linux/of_address.h> |
24 | 25 | #include <linux/of_irq.h> |
26 | +#include <linux/of_gpio.h> | |
25 | 27 | #endif |
26 | 28 | |
27 | 29 | #ifdef CONFIG_PCI |
28 | 30 | |
... | ... | @@ -29,9 +31,14 @@ |
29 | 31 | #endif |
30 | 32 | |
31 | 33 | #ifdef CONFIG_OF |
34 | +struct isp1760 { | |
35 | + struct usb_hcd *hcd; | |
36 | + int rst_gpio; | |
37 | +}; | |
38 | + | |
32 | 39 | static int of_isp1760_probe(struct platform_device *dev) |
33 | 40 | { |
34 | - struct usb_hcd *hcd; | |
41 | + struct isp1760 *drvdata; | |
35 | 42 | struct device_node *dp = dev->dev.of_node; |
36 | 43 | struct resource *res; |
37 | 44 | struct resource memory; |
38 | 45 | |
... | ... | @@ -41,7 +48,12 @@ |
41 | 48 | int ret; |
42 | 49 | const unsigned int *prop; |
43 | 50 | unsigned int devflags = 0; |
51 | + enum of_gpio_flags gpio_flags; | |
44 | 52 | |
53 | + drvdata = kzalloc(sizeof(*drvdata), GFP_KERNEL); | |
54 | + if (!drvdata) | |
55 | + return -ENOMEM; | |
56 | + | |
45 | 57 | ret = of_address_to_resource(dp, 0, &memory); |
46 | 58 | if (ret) |
47 | 59 | return -ENXIO; |
48 | 60 | |
49 | 61 | |
50 | 62 | |
51 | 63 | |
52 | 64 | |
... | ... | @@ -80,32 +92,57 @@ |
80 | 92 | if (of_get_property(dp, "dreq-polarity", NULL) != NULL) |
81 | 93 | devflags |= ISP1760_FLAG_DREQ_POL_HIGH; |
82 | 94 | |
83 | - hcd = isp1760_register(memory.start, res_len, virq, | |
84 | - IRQF_SHARED, &dev->dev, dev_name(&dev->dev), | |
85 | - devflags); | |
86 | - if (IS_ERR(hcd)) { | |
87 | - ret = PTR_ERR(hcd); | |
88 | - goto release_reg; | |
95 | + drvdata->rst_gpio = of_get_gpio_flags(dp, 0, &gpio_flags); | |
96 | + if (gpio_is_valid(drvdata->rst_gpio)) { | |
97 | + ret = gpio_request(drvdata->rst_gpio, dev_name(&dev->dev)); | |
98 | + if (!ret) { | |
99 | + if (!(gpio_flags & OF_GPIO_ACTIVE_LOW)) { | |
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 | 120 | return ret; |
93 | 121 | |
122 | +free_gpio: | |
123 | + if (gpio_is_valid(drvdata->rst_gpio)) | |
124 | + gpio_free(drvdata->rst_gpio); | |
94 | 125 | release_reg: |
95 | 126 | release_mem_region(memory.start, res_len); |
127 | + kfree(drvdata); | |
96 | 128 | return ret; |
97 | 129 | } |
98 | 130 | |
99 | 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 | 135 | dev_set_drvdata(&dev->dev, NULL); |
104 | 136 | |
105 | - usb_remove_hcd(hcd); | |
106 | - iounmap(hcd->regs); | |
107 | - release_mem_region(hcd->rsrc_start, hcd->rsrc_len); | |
108 | - usb_put_hcd(hcd); | |
137 | + usb_remove_hcd(drvdata->hcd); | |
138 | + iounmap(drvdata->hcd->regs); | |
139 | + release_mem_region(drvdata->hcd->rsrc_start, drvdata->hcd->rsrc_len); | |
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 | 146 | return 0; |
110 | 147 | } |
111 | 148 | |
... | ... | @@ -242,7 +279,7 @@ |
242 | 279 | |
243 | 280 | dev->dev.dma_mask = NULL; |
244 | 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 | 283 | devflags); |
247 | 284 | if (IS_ERR(hcd)) { |
248 | 285 | ret_status = -ENODEV; |
... | ... | @@ -353,7 +390,8 @@ |
353 | 390 | } |
354 | 391 | |
355 | 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 | 395 | if (IS_ERR(hcd)) { |
358 | 396 | pr_warning("isp1760: Failed to register the HCD device\n"); |
359 | 397 | ret = -ENODEV; |