summaryrefslogtreecommitdiffstats
path: root/drivers/usb/host/isp1760-if.c
diff options
context:
space:
mode:
authorJoachim Foerster <joachim.foerster@missinglinkelectronics.com>2011-10-19 14:18:41 +0200
committerGreg Kroah-Hartman <gregkh@suse.de>2011-10-19 22:29:06 +0200
commit3a7655fcb210b349111251689d0a56b7250885ea (patch)
treeb909f3f73d89d1af8807036a3922a19aca41b514 /drivers/usb/host/isp1760-if.c
parentUSB: gadget: midi: memory leak in f_midi_bind_config() (diff)
downloadlinux-3a7655fcb210b349111251689d0a56b7250885ea.tar.xz
linux-3a7655fcb210b349111251689d0a56b7250885ea.zip
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.c68
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 @@
#include "isp1760-hcd.h"
#ifdef CONFIG_OF
+#include <linux/slab.h>
#include <linux/of.h>
#include <linux/of_platform.h>
#include <linux/of_address.h>
#include <linux/of_irq.h>
+#include <linux/of_gpio.h>
#endif
#ifdef CONFIG_PCI
@@ -29,9 +31,14 @@
#endif
#ifdef CONFIG_OF
+struct isp1760 {
+ struct usb_hcd *hcd;
+ int rst_gpio;
+};
+
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 resource *res;
struct resource memory;
@@ -41,6 +48,11 @@ static int of_isp1760_probe(struct platform_device *dev)
int ret;
const unsigned int *prop;
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);
if (ret)
@@ -80,32 +92,57 @@ static int of_isp1760_probe(struct platform_device *dev)
if (of_get_property(dp, "dreq-polarity", NULL) != NULL)
devflags |= ISP1760_FLAG_DREQ_POL_HIGH;
- hcd = isp1760_register(memory.start, res_len, virq,
- IRQF_SHARED, &dev->dev, dev_name(&dev->dev),
- devflags);
- if (IS_ERR(hcd)) {
- ret = PTR_ERR(hcd);
- goto release_reg;
+ drvdata->rst_gpio = of_get_gpio_flags(dp, 0, &gpio_flags);
+ 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;
+ }
}
- dev_set_drvdata(&dev->dev, hcd);
+ drvdata->hcd = isp1760_register(memory.start, res_len, virq,
+ IRQF_SHARED, drvdata->rst_gpio,
+ &dev->dev, dev_name(&dev->dev),
+ devflags);
+ if (IS_ERR(drvdata->hcd)) {
+ ret = PTR_ERR(drvdata->hcd);
+ goto free_gpio;
+ }
+
+ dev_set_drvdata(&dev->dev, drvdata);
return ret;
+free_gpio:
+ if (gpio_is_valid(drvdata->rst_gpio))
+ gpio_free(drvdata->rst_gpio);
release_reg:
release_mem_region(memory.start, res_len);
+ kfree(drvdata);
return ret;
}
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);
- usb_remove_hcd(hcd);
- iounmap(hcd->regs);
- release_mem_region(hcd->rsrc_start, hcd->rsrc_len);
- usb_put_hcd(hcd);
+ usb_remove_hcd(drvdata->hcd);
+ iounmap(drvdata->hcd->regs);
+ release_mem_region(drvdata->hcd->rsrc_start, drvdata->hcd->rsrc_len);
+ usb_put_hcd(drvdata->hcd);
+
+ if (gpio_is_valid(drvdata->rst_gpio))
+ gpio_free(drvdata->rst_gpio);
+
+ kfree(drvdata);
return 0;
}
@@ -242,7 +279,7 @@ static int __devinit isp1761_pci_probe(struct pci_dev *dev,
dev->dev.dma_mask = NULL;
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);
if (IS_ERR(hcd)) {
ret_status = -ENODEV;
@@ -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,
- irqflags, &pdev->dev, dev_name(&pdev->dev), devflags);
+ irqflags, -ENOENT,
+ &pdev->dev, dev_name(&pdev->dev), devflags);
if (IS_ERR(hcd)) {
pr_warning("isp1760: Failed to register the HCD device\n");
ret = -ENODEV;