From 3a7655fcb210b349111251689d0a56b7250885ea Mon Sep 17 00:00:00 2001 From: Joachim Foerster Date: Wed, 19 Oct 2011 14:18:41 +0200 Subject: 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 Signed-off-by: Greg Kroah-Hartman --- drivers/usb/host/isp1760-if.c | 68 +++++++++++++++++++++++++++++++++---------- 1 file changed, 53 insertions(+), 15 deletions(-) (limited to 'drivers/usb/host/isp1760-if.c') diff --git a/drivers/usb/host/isp1760-if.c b/drivers/usb/host/isp1760-if.c index 791792d..2c7fc83 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 #include #include #include #include +#include #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; -- cgit v1.1