diff options
Diffstat (limited to 'drivers/usb/host/isp1760-if.c')
| -rw-r--r-- | drivers/usb/host/isp1760-if.c | 262 |
1 files changed, 198 insertions, 64 deletions
diff --git a/drivers/usb/host/isp1760-if.c b/drivers/usb/host/isp1760-if.c index 4cf7ca428b3..df931e9ba5b 100644 --- a/drivers/usb/host/isp1760-if.c +++ b/drivers/usb/host/isp1760-if.c @@ -3,6 +3,7 @@ * Currently there is support for * - OpenFirmware * - PCI + * - PDEV (generic platform device centralized driver model) * * (c) 2007 Sebastian Siewior <bigeasy@linutronix.de> * @@ -10,59 +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 "../core/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 of_device *dev, - const struct of_device_id *match) -{ +#if defined(CONFIG_OF) && defined(CONFIG_OF_IRQ) +struct isp1760 { struct usb_hcd *hcd; - struct device_node *dp = dev->node; + 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; - u64 res_len; + 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 = request_mem_region(memory.start, memory.end - memory.start + 1, - dev_name(&dev->dev)); - if (!res) - return -EBUSY; + res_len = resource_size(&memory); - res_len = memory.end - memory.start + 1; + res = request_mem_region(memory.start, res_len, dev_name(&dev->dev)); + 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) @@ -77,36 +94,60 @@ static int of_isp1760_probe(struct of_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; + } } - 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; + } + + 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, memory.end - memory.start + 1); + release_mem_region(memory.start, res_len); +free_data: + kfree(drvdata); return ret; } -static int of_isp1760_remove(struct of_device *dev) +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; } -static struct of_device_id of_isp1760_match[] = { +static const struct of_device_id of_isp1760_match[] = { { .compatible = "nxp,usb-isp1760", }, @@ -117,16 +158,19 @@ static struct of_device_id of_isp1760_match[] = { }; MODULE_DEVICE_TABLE(of, of_isp1760_match); -static struct of_platform_driver isp1760_of_driver = { - .name = "nxp-isp1760", - .match_table = of_isp1760_match, +static struct platform_driver isp1760_of_driver = { + .driver = { + .name = "nxp-isp1760", + .owner = THIS_MODULE, + .of_match_table = of_isp1760_match, + }, .probe = of_isp1760_probe, .remove = of_isp1760_remove, }; #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; @@ -236,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; @@ -300,41 +344,131 @@ static struct pci_driver isp1761_pci_driver = { }; #endif +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 = dev_get_platdata(&pdev->dev); + unsigned int devflags = 0; + unsigned long irqflags = IRQF_SHARED; + + mem_res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + if (!mem_res) { + pr_warning("isp1760: Memory resource not available\n"); + ret = -ENODEV; + goto out; + } + mem_size = resource_size(mem_res); + if (!request_mem_region(mem_res->start, mem_size, "isp1760")) { + pr_warning("isp1760: Cannot reserve the memory resource\n"); + ret = -EBUSY; + goto out; + } + + irq_res = platform_get_resource(pdev, IORESOURCE_IRQ, 0); + if (!irq_res) { + pr_warning("isp1760: IRQ resource not available\n"); + ret = -ENODEV; + goto cleanup; + } + + irqflags |= irq_res->flags & IRQF_TRIGGER_MASK; + + if (priv) { + if (priv->is_isp1761) + devflags |= ISP1760_FLAG_ISP1761; + if (priv->bus_width_16) + devflags |= ISP1760_FLAG_BUS_WIDTH_16; + if (priv->port1_otg) + devflags |= ISP1760_FLAG_OTG_EN; + if (priv->analog_oc) + devflags |= ISP1760_FLAG_ANALOG_OC; + if (priv->dack_polarity_high) + devflags |= ISP1760_FLAG_DACK_POL_HIGH; + if (priv->dreq_polarity_high) + devflags |= ISP1760_FLAG_DREQ_POL_HIGH; + } + + hcd = isp1760_register(mem_res->start, mem_size, irq_res->start, + 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; + goto cleanup; + } + + pr_info("ISP1760 USB device initialised\n"); + return ret; + +cleanup: + release_mem_region(mem_res->start, mem_size); +out: + return ret; +} + +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 = isp1760_plat_remove, + .driver = { + .name = "isp1760", + }, +}; + static int __init isp1760_init(void) { - int ret; + int ret, any_ret = -ENODEV; init_kmem_once(); -#ifdef CONFIG_PPC_OF - ret = of_register_platform_driver(&isp1760_of_driver); - if (ret) { - deinit_kmem_cache(); - return ret; - } + ret = platform_driver_register(&isp1760_plat_driver); + if (!ret) + any_ret = 0; +#if defined(CONFIG_OF) && defined(CONFIG_OF_IRQ) + ret = platform_driver_register(&isp1760_of_driver); + if (!ret) + any_ret = 0; #endif #ifdef CONFIG_PCI ret = pci_register_driver(&isp1761_pci_driver); - if (ret) - goto unreg_of; + if (!ret) + any_ret = 0; #endif - return ret; -#ifdef CONFIG_PCI -unreg_of: -#endif -#ifdef CONFIG_PPC_OF - of_unregister_platform_driver(&isp1760_of_driver); -#endif - deinit_kmem_cache(); - return ret; + if (any_ret) + deinit_kmem_cache(); + return any_ret; } module_init(isp1760_init); static void __exit isp1760_exit(void) { -#ifdef CONFIG_PPC_OF - of_unregister_platform_driver(&isp1760_of_driver); + platform_driver_unregister(&isp1760_plat_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); |
