Commit 3a7655fc authored by Joachim Foerster's avatar Joachim Foerster Committed by Greg Kroah-Hartman

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: default avatarJoachim Foerster <joachim.foerster@missinglinkelectronics.com>
Signed-off-by: default avatarGreg Kroah-Hartman <gregkh@suse.de>
parent 0f8fd43c
...@@ -24,6 +24,7 @@ ...@@ -24,6 +24,7 @@
#include <linux/timer.h> #include <linux/timer.h>
#include <asm/unaligned.h> #include <asm/unaligned.h>
#include <asm/cacheflush.h> #include <asm/cacheflush.h>
#include <linux/gpio.h>
#include "isp1760-hcd.h" #include "isp1760-hcd.h"
...@@ -48,6 +49,8 @@ struct isp1760_hcd { ...@@ -48,6 +49,8 @@ struct isp1760_hcd {
unsigned long reset_done; unsigned long reset_done;
unsigned long next_statechange; unsigned long next_statechange;
unsigned int devflags; unsigned int devflags;
int rst_gpio;
}; };
static inline struct isp1760_hcd *hcd_to_priv(struct usb_hcd *hcd) static inline struct isp1760_hcd *hcd_to_priv(struct usb_hcd *hcd)
...@@ -433,6 +436,18 @@ static int isp1760_hc_setup(struct usb_hcd *hcd) ...@@ -433,6 +436,18 @@ static int isp1760_hc_setup(struct usb_hcd *hcd)
int result; int result;
u32 scratch, hwmode; u32 scratch, hwmode;
/* low-level chip reset */
if (gpio_is_valid(priv->rst_gpio)) {
unsigned int rst_lvl;
rst_lvl = (priv->devflags &
ISP1760_FLAG_RESET_ACTIVE_HIGH) ? 1 : 0;
gpio_set_value(priv->rst_gpio, rst_lvl);
mdelay(50);
gpio_set_value(priv->rst_gpio, !rst_lvl);
}
/* Setup HW Mode Control: This assumes a level active-low interrupt */ /* Setup HW Mode Control: This assumes a level active-low interrupt */
hwmode = HW_DATA_BUS_32BIT; hwmode = HW_DATA_BUS_32BIT;
...@@ -2207,6 +2222,7 @@ void deinit_kmem_cache(void) ...@@ -2207,6 +2222,7 @@ void deinit_kmem_cache(void)
struct usb_hcd *isp1760_register(phys_addr_t res_start, resource_size_t res_len, struct usb_hcd *isp1760_register(phys_addr_t res_start, resource_size_t res_len,
int irq, unsigned long irqflags, int irq, unsigned long irqflags,
int rst_gpio,
struct device *dev, const char *busname, struct device *dev, const char *busname,
unsigned int devflags) unsigned int devflags)
{ {
...@@ -2226,6 +2242,7 @@ struct usb_hcd *isp1760_register(phys_addr_t res_start, resource_size_t res_len, ...@@ -2226,6 +2242,7 @@ struct usb_hcd *isp1760_register(phys_addr_t res_start, resource_size_t res_len,
priv = hcd_to_priv(hcd); priv = hcd_to_priv(hcd);
priv->devflags = devflags; priv->devflags = devflags;
priv->rst_gpio = rst_gpio;
init_memory(priv); init_memory(priv);
hcd->regs = ioremap(res_start, res_len); hcd->regs = ioremap(res_start, res_len);
if (!hcd->regs) { if (!hcd->regs) {
......
...@@ -4,6 +4,7 @@ ...@@ -4,6 +4,7 @@
/* exports for if */ /* exports for if */
struct usb_hcd *isp1760_register(phys_addr_t res_start, resource_size_t res_len, struct usb_hcd *isp1760_register(phys_addr_t res_start, resource_size_t res_len,
int irq, unsigned long irqflags, int irq, unsigned long irqflags,
int rst_gpio,
struct device *dev, const char *busname, struct device *dev, const char *busname,
unsigned int devflags); unsigned int devflags);
int init_kmem_once(void); int init_kmem_once(void);
...@@ -126,6 +127,7 @@ typedef void (packet_enqueue)(struct usb_hcd *hcd, struct isp1760_qh *qh, ...@@ -126,6 +127,7 @@ typedef void (packet_enqueue)(struct usb_hcd *hcd, struct isp1760_qh *qh,
#define ISP1760_FLAG_ISP1761 0x00000040 /* Chip is ISP1761 */ #define ISP1760_FLAG_ISP1761 0x00000040 /* Chip is ISP1761 */
#define ISP1760_FLAG_INTR_POL_HIGH 0x00000080 /* Interrupt polarity active high */ #define ISP1760_FLAG_INTR_POL_HIGH 0x00000080 /* Interrupt polarity active high */
#define ISP1760_FLAG_INTR_EDGE_TRIG 0x00000100 /* Interrupt edge triggered */ #define ISP1760_FLAG_INTR_EDGE_TRIG 0x00000100 /* Interrupt edge triggered */
#define ISP1760_FLAG_RESET_ACTIVE_HIGH 0x80000000 /* RESET GPIO active high */
/* chip memory management */ /* chip memory management */
struct memory_chunk { struct memory_chunk {
......
...@@ -18,10 +18,12 @@ ...@@ -18,10 +18,12 @@
#include "isp1760-hcd.h" #include "isp1760-hcd.h"
#ifdef CONFIG_OF #ifdef CONFIG_OF
#include <linux/slab.h>
#include <linux/of.h> #include <linux/of.h>
#include <linux/of_platform.h> #include <linux/of_platform.h>
#include <linux/of_address.h> #include <linux/of_address.h>
#include <linux/of_irq.h> #include <linux/of_irq.h>
#include <linux/of_gpio.h>
#endif #endif
#ifdef CONFIG_PCI #ifdef CONFIG_PCI
...@@ -29,9 +31,14 @@ ...@@ -29,9 +31,14 @@
#endif #endif
#ifdef CONFIG_OF #ifdef CONFIG_OF
struct isp1760 {
struct usb_hcd *hcd;
int rst_gpio;
};
static int of_isp1760_probe(struct platform_device *dev) static int of_isp1760_probe(struct platform_device *dev)
{ {
struct usb_hcd *hcd; struct isp1760 *drvdata;
struct device_node *dp = dev->dev.of_node; struct device_node *dp = dev->dev.of_node;
struct resource *res; struct resource *res;
struct resource memory; struct resource memory;
...@@ -41,6 +48,11 @@ static int of_isp1760_probe(struct platform_device *dev) ...@@ -41,6 +48,11 @@ static int of_isp1760_probe(struct platform_device *dev)
int ret; int ret;
const unsigned int *prop; const unsigned int *prop;
unsigned int devflags = 0; unsigned int devflags = 0;
enum of_gpio_flags gpio_flags;
drvdata = kzalloc(sizeof(*drvdata), GFP_KERNEL);
if (!drvdata)
return -ENOMEM;
ret = of_address_to_resource(dp, 0, &memory); ret = of_address_to_resource(dp, 0, &memory);
if (ret) if (ret)
...@@ -80,32 +92,57 @@ static int of_isp1760_probe(struct platform_device *dev) ...@@ -80,32 +92,57 @@ static int of_isp1760_probe(struct platform_device *dev)
if (of_get_property(dp, "dreq-polarity", NULL) != NULL) if (of_get_property(dp, "dreq-polarity", NULL) != NULL)
devflags |= ISP1760_FLAG_DREQ_POL_HIGH; devflags |= ISP1760_FLAG_DREQ_POL_HIGH;
hcd = isp1760_register(memory.start, res_len, virq, drvdata->rst_gpio = of_get_gpio_flags(dp, 0, &gpio_flags);
IRQF_SHARED, &dev->dev, dev_name(&dev->dev), if (gpio_is_valid(drvdata->rst_gpio)) {
ret = gpio_request(drvdata->rst_gpio, dev_name(&dev->dev));
if (!ret) {
if (!(gpio_flags & OF_GPIO_ACTIVE_LOW)) {
devflags |= ISP1760_FLAG_RESET_ACTIVE_HIGH;
gpio_direction_output(drvdata->rst_gpio, 0);
} else {
gpio_direction_output(drvdata->rst_gpio, 1);
}
} else {
drvdata->rst_gpio = ret;
}
}
drvdata->hcd = isp1760_register(memory.start, res_len, virq,
IRQF_SHARED, drvdata->rst_gpio,
&dev->dev, dev_name(&dev->dev),
devflags); devflags);
if (IS_ERR(hcd)) { if (IS_ERR(drvdata->hcd)) {
ret = PTR_ERR(hcd); ret = PTR_ERR(drvdata->hcd);
goto release_reg; goto free_gpio;
} }
dev_set_drvdata(&dev->dev, hcd); dev_set_drvdata(&dev->dev, drvdata);
return ret; return ret;
free_gpio:
if (gpio_is_valid(drvdata->rst_gpio))
gpio_free(drvdata->rst_gpio);
release_reg: release_reg:
release_mem_region(memory.start, res_len); release_mem_region(memory.start, res_len);
kfree(drvdata);
return ret; return ret;
} }
static int of_isp1760_remove(struct platform_device *dev) static int of_isp1760_remove(struct platform_device *dev)
{ {
struct usb_hcd *hcd = dev_get_drvdata(&dev->dev); struct isp1760 *drvdata = dev_get_drvdata(&dev->dev);
dev_set_drvdata(&dev->dev, NULL); dev_set_drvdata(&dev->dev, NULL);
usb_remove_hcd(hcd); usb_remove_hcd(drvdata->hcd);
iounmap(hcd->regs); iounmap(drvdata->hcd->regs);
release_mem_region(hcd->rsrc_start, hcd->rsrc_len); release_mem_region(drvdata->hcd->rsrc_start, drvdata->hcd->rsrc_len);
usb_put_hcd(hcd); usb_put_hcd(drvdata->hcd);
if (gpio_is_valid(drvdata->rst_gpio))
gpio_free(drvdata->rst_gpio);
kfree(drvdata);
return 0; return 0;
} }
...@@ -242,7 +279,7 @@ static int __devinit isp1761_pci_probe(struct pci_dev *dev, ...@@ -242,7 +279,7 @@ static int __devinit isp1761_pci_probe(struct pci_dev *dev,
dev->dev.dma_mask = NULL; dev->dev.dma_mask = NULL;
hcd = isp1760_register(pci_mem_phy0, memlength, dev->irq, hcd = isp1760_register(pci_mem_phy0, memlength, dev->irq,
IRQF_SHARED, &dev->dev, dev_name(&dev->dev), IRQF_SHARED, -ENOENT, &dev->dev, dev_name(&dev->dev),
devflags); devflags);
if (IS_ERR(hcd)) { if (IS_ERR(hcd)) {
ret_status = -ENODEV; ret_status = -ENODEV;
...@@ -353,7 +390,8 @@ static int __devinit isp1760_plat_probe(struct platform_device *pdev) ...@@ -353,7 +390,8 @@ static int __devinit isp1760_plat_probe(struct platform_device *pdev)
} }
hcd = isp1760_register(mem_res->start, mem_size, irq_res->start, hcd = isp1760_register(mem_res->start, mem_size, irq_res->start,
irqflags, &pdev->dev, dev_name(&pdev->dev), devflags); irqflags, -ENOENT,
&pdev->dev, dev_name(&pdev->dev), devflags);
if (IS_ERR(hcd)) { if (IS_ERR(hcd)) {
pr_warning("isp1760: Failed to register the HCD device\n"); pr_warning("isp1760: Failed to register the HCD device\n");
ret = -ENODEV; ret = -ENODEV;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment