diff options
Diffstat (limited to 'drivers/usb/host/isp1760-if.c')
| -rw-r--r-- | drivers/usb/host/isp1760-if.c | 138 |
1 files changed, 94 insertions, 44 deletions
diff --git a/drivers/usb/host/isp1760-if.c b/drivers/usb/host/isp1760-if.c index 3b28dbfca05..df931e9ba5b 100644 --- a/drivers/usb/host/isp1760-if.c +++ b/drivers/usb/host/isp1760-if.c @@ -11,60 +11,75 @@ #include <linux/usb.h> #include <linux/io.h> +#include <linux/module.h> #include <linux/platform_device.h> #include <linux/usb/isp1760.h> #include <linux/usb/hcd.h> #include "isp1760-hcd.h" -#ifdef CONFIG_PPC_OF +#if defined(CONFIG_OF) && defined(CONFIG_OF_IRQ) +#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 #include <linux/pci.h> #endif -#ifdef CONFIG_PPC_OF -static int of_isp1760_probe(struct platform_device *dev, - const struct of_device_id *match) -{ +#if defined(CONFIG_OF) && defined(CONFIG_OF_IRQ) +struct isp1760 { struct usb_hcd *hcd; + int rst_gpio; +}; + +static int of_isp1760_probe(struct platform_device *dev) +{ + struct isp1760 *drvdata; struct device_node *dp = dev->dev.of_node; struct resource *res; struct resource memory; - struct of_irq oirq; int virq; resource_size_t res_len; int ret; - const unsigned int *prop; unsigned int devflags = 0; + enum of_gpio_flags gpio_flags; + u32 bus_width = 0; + + drvdata = kzalloc(sizeof(*drvdata), GFP_KERNEL); + if (!drvdata) + return -ENOMEM; ret = of_address_to_resource(dp, 0, &memory); - if (ret) - return -ENXIO; + if (ret) { + ret = -ENXIO; + goto free_data; + } res_len = resource_size(&memory); res = request_mem_region(memory.start, res_len, dev_name(&dev->dev)); - if (!res) - return -EBUSY; + if (!res) { + ret = -EBUSY; + goto free_data; + } - if (of_irq_map_one(dp, 0, &oirq)) { + virq = irq_of_parse_and_map(dp, 0); + if (!virq) { ret = -ENODEV; goto release_reg; } - virq = irq_create_of_mapping(oirq.controller, oirq.specifier, - oirq.size); - if (of_device_is_compatible(dp, "nxp,usb-isp1761")) devflags |= ISP1760_FLAG_ISP1761; /* Some systems wire up only 16 of the 32 data lines */ - prop = of_get_property(dp, "bus-width", NULL); - if (prop && *prop == 16) + of_property_read_u32(dp, "bus-width", &bus_width); + if (bus_width == 16) devflags |= ISP1760_FLAG_BUS_WIDTH_16; if (of_get_property(dp, "port1-otg", NULL) != NULL) @@ -79,32 +94,56 @@ 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 | IRQF_DISABLED, &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; + } + } + + 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, hcd); + platform_set_drvdata(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); +free_data: + 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 = platform_get_drvdata(dev); - dev_set_drvdata(&dev->dev, NULL); + 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); - usb_remove_hcd(hcd); - iounmap(hcd->regs); - release_mem_region(hcd->rsrc_start, hcd->rsrc_len); - usb_put_hcd(hcd); + if (gpio_is_valid(drvdata->rst_gpio)) + gpio_free(drvdata->rst_gpio); + + kfree(drvdata); return 0; } @@ -119,7 +158,7 @@ static const struct of_device_id of_isp1760_match[] = { }; MODULE_DEVICE_TABLE(of, of_isp1760_match); -static struct of_platform_driver isp1760_of_driver = { +static struct platform_driver isp1760_of_driver = { .driver = { .name = "nxp-isp1760", .owner = THIS_MODULE, @@ -131,7 +170,7 @@ static struct of_platform_driver isp1760_of_driver = { #endif #ifdef CONFIG_PCI -static int __devinit isp1761_pci_probe(struct pci_dev *dev, +static int isp1761_pci_probe(struct pci_dev *dev, const struct pci_device_id *id) { u8 latency, limit; @@ -241,7 +280,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 | IRQF_DISABLED, &dev->dev, dev_name(&dev->dev), + IRQF_SHARED, -ENOENT, &dev->dev, dev_name(&dev->dev), devflags); if (IS_ERR(hcd)) { ret_status = -ENODEV; @@ -305,16 +344,16 @@ static struct pci_driver isp1761_pci_driver = { }; #endif -static int __devinit isp1760_plat_probe(struct platform_device *pdev) +static int isp1760_plat_probe(struct platform_device *pdev) { int ret = 0; struct usb_hcd *hcd; struct resource *mem_res; struct resource *irq_res; resource_size_t mem_size; - struct isp1760_platform_data *priv = pdev->dev.platform_data; + struct isp1760_platform_data *priv = dev_get_platdata(&pdev->dev); unsigned int devflags = 0; - unsigned long irqflags = IRQF_SHARED | IRQF_DISABLED; + unsigned long irqflags = IRQF_SHARED; mem_res = platform_get_resource(pdev, IORESOURCE_MEM, 0); if (!mem_res) { @@ -332,8 +371,10 @@ static int __devinit isp1760_plat_probe(struct platform_device *pdev) irq_res = platform_get_resource(pdev, IORESOURCE_IRQ, 0); if (!irq_res) { pr_warning("isp1760: IRQ resource not available\n"); - return -ENODEV; + ret = -ENODEV; + goto cleanup; } + irqflags |= irq_res->flags & IRQF_TRIGGER_MASK; if (priv) { @@ -352,7 +393,11 @@ 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); + + platform_set_drvdata(pdev, hcd); + if (IS_ERR(hcd)) { pr_warning("isp1760: Failed to register the HCD device\n"); ret = -ENODEV; @@ -368,21 +413,26 @@ out: return ret; } -static int __devexit isp1760_plat_remove(struct platform_device *pdev) +static int isp1760_plat_remove(struct platform_device *pdev) { struct resource *mem_res; resource_size_t mem_size; + struct usb_hcd *hcd = platform_get_drvdata(pdev); + + usb_remove_hcd(hcd); mem_res = platform_get_resource(pdev, IORESOURCE_MEM, 0); mem_size = resource_size(mem_res); release_mem_region(mem_res->start, mem_size); + usb_put_hcd(hcd); + return 0; } static struct platform_driver isp1760_plat_driver = { .probe = isp1760_plat_probe, - .remove = __devexit_p(isp1760_plat_remove), + .remove = isp1760_plat_remove, .driver = { .name = "isp1760", }, @@ -397,8 +447,8 @@ static int __init isp1760_init(void) ret = platform_driver_register(&isp1760_plat_driver); if (!ret) any_ret = 0; -#ifdef CONFIG_PPC_OF - ret = of_register_platform_driver(&isp1760_of_driver); +#if defined(CONFIG_OF) && defined(CONFIG_OF_IRQ) + ret = platform_driver_register(&isp1760_of_driver); if (!ret) any_ret = 0; #endif @@ -417,8 +467,8 @@ module_init(isp1760_init); static void __exit isp1760_exit(void) { platform_driver_unregister(&isp1760_plat_driver); -#ifdef CONFIG_PPC_OF - of_unregister_platform_driver(&isp1760_of_driver); +#if defined(CONFIG_OF) && defined(CONFIG_OF_IRQ) + platform_driver_unregister(&isp1760_of_driver); #endif #ifdef CONFIG_PCI pci_unregister_driver(&isp1761_pci_driver); |
