Commit 3a7655fcb210b349111251689d0a56b7250885ea

Authored by Joachim Foerster
Committed by Greg Kroah-Hartman
1 parent 0f8fd43c42

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;