Allows configuring Samsung's s3c2410 and compatible USB device
controller using a devicetree.

Signed-off-by: Sergio Prado <sergio.pr...@e-labworks.com>
---
 drivers/usb/gadget/udc/s3c2410_udc.c | 142 +++++++++++++++++++++++++++++------
 drivers/usb/gadget/udc/s3c2410_udc.h |   4 +
 2 files changed, 123 insertions(+), 23 deletions(-)

diff --git a/drivers/usb/gadget/udc/s3c2410_udc.c 
b/drivers/usb/gadget/udc/s3c2410_udc.c
index 4643a01262b4..e3b5a0e6646e 100644
--- a/drivers/usb/gadget/udc/s3c2410_udc.c
+++ b/drivers/usb/gadget/udc/s3c2410_udc.c
@@ -30,6 +30,9 @@
 #include <linux/gpio.h>
 #include <linux/prefetch.h>
 #include <linux/io.h>
+#include <linux/of.h>
+#include <linux/of_device.h>
+#include <linux/of_gpio.h>
 
 #include <linux/debugfs.h>
 #include <linux/seq_file.h>
@@ -55,6 +58,18 @@
 #define DRIVER_AUTHOR  "Herbert Pƶtzl <herb...@13thfloor.at>, " \
                        "Arnaud Patard <arnaud.pat...@rtp-net.org>"
 
+struct s3c2410_udc_drv_data {
+       int ep_fifo_size;
+};
+
+static const struct s3c2410_udc_drv_data s3c2410_udc_2410_drv_data = {
+       .ep_fifo_size = EP_FIFO_SIZE,
+};
+
+static const struct s3c2410_udc_drv_data s3c2410_udc_2440_drv_data = {
+       .ep_fifo_size = S3C2440_EP_FIFO_SIZE,
+};
+
 static const char              gadget_name[] = "s3c2410_udc";
 static const char              driver_desc[] = DRIVER_DESC;
 
@@ -62,8 +77,6 @@
 static struct clk              *udc_clock;
 static struct clk              *usb_bus_clock;
 static void __iomem            *base_addr;
-static u64                     rsrc_start;
-static u64                     rsrc_len;
 static struct dentry           *s3c2410_udc_debugfs_root;
 
 static inline u32 udc_read(u32 reg)
@@ -997,7 +1010,7 @@ static irqreturn_t s3c2410_udc_irq(int dummy, void *_dev)
                }
        }
 
-       dprintk(DEBUG_VERBOSE, "irq: %d s3c2410_udc_done.\n", IRQ_USBD);
+       dprintk(DEBUG_VERBOSE, "irq: %d s3c2410_udc_done.\n", dev->irq);
 
        /* Restore old index */
        udc_write(idx, S3C2410_UDC_INDEX_REG);
@@ -1757,6 +1770,49 @@ static int s3c2410_udc_stop(struct usb_gadget *g)
 
 };
 
+static int s3c2410_udc_probe_dt(struct s3c2410_udc *udc)
+{
+       const struct s3c2410_udc_drv_data *drvdata;
+       struct platform_device *pdev = udc->pdev;
+       struct s3c2410_udc_mach_info *pdata;
+       int gpio;
+
+       drvdata = of_device_get_match_data(&pdev->dev);
+
+       if (drvdata)
+               udc->ep_fifo_size = drvdata->ep_fifo_size;
+
+       pdata = devm_kzalloc(&pdev->dev, sizeof(*pdata), GFP_KERNEL);
+       if (!pdata)
+               return -ENOMEM;
+
+       gpio = of_get_named_gpio(pdev->dev.of_node, "samsung,vbus-gpio", 0);
+       if (gpio_is_valid(gpio))
+               pdata->vbus_pin = gpio;
+
+       gpio = of_get_named_gpio(pdev->dev.of_node, "samsung,pullup-gpio", 0);
+       if (gpio_is_valid(gpio))
+               pdata->pullup_pin = gpio;
+
+       pdev->dev.platform_data = pdata;
+
+       return 0;
+}
+
+static int s3c2410_udc_probe_pdata(struct s3c2410_udc *udc)
+{
+       const struct s3c2410_udc_drv_data *drvdata;
+       struct platform_device *pdev = udc->pdev;
+
+       drvdata = (struct s3c2410_udc_drv_data *)
+               platform_get_device_id(pdev)->driver_data;
+
+       if (drvdata)
+               udc->ep_fifo_size = drvdata->ep_fifo_size;
+
+       return 0;
+}
+
 /*
  *     probe - binds to the platform device
  */
@@ -1769,6 +1825,16 @@ static int s3c2410_udc_probe(struct platform_device 
*pdev)
 
        dev_dbg(dev, "%s()\n", __func__);
 
+       udc->pdev = pdev;
+
+       if (pdev->dev.of_node)
+               retval = s3c2410_udc_probe_dt(udc);
+       else
+               retval = s3c2410_udc_probe_pdata(udc);
+
+       if (retval)
+               return retval;
+
        usb_bus_clock = clk_get(NULL, "usb-bus-gadget");
        if (IS_ERR(usb_bus_clock)) {
                dev_err(dev, "failed to get usb bus clock source\n");
@@ -1789,24 +1855,27 @@ static int s3c2410_udc_probe(struct platform_device 
*pdev)
 
        dev_dbg(dev, "got and enabled clocks\n");
 
-       if (strncmp(pdev->name, "s3c2440", 7) == 0) {
-               dev_info(dev, "S3C2440: increasing FIFO to 128 bytes\n");
-               memory.ep[1].fifo_size = S3C2440_EP_FIFO_SIZE;
-               memory.ep[2].fifo_size = S3C2440_EP_FIFO_SIZE;
-               memory.ep[3].fifo_size = S3C2440_EP_FIFO_SIZE;
-               memory.ep[4].fifo_size = S3C2440_EP_FIFO_SIZE;
+       if (udc->ep_fifo_size) {
+               dev_info(dev, "setting FIFO to %d bytes\n", udc->ep_fifo_size);
+               memory.ep[1].fifo_size = udc->ep_fifo_size;
+               memory.ep[2].fifo_size = udc->ep_fifo_size;
+               memory.ep[3].fifo_size = udc->ep_fifo_size;
+               memory.ep[4].fifo_size = udc->ep_fifo_size;
        }
 
        spin_lock_init(&udc->lock);
        udc_info = dev_get_platdata(&pdev->dev);
 
-       rsrc_start = S3C2410_PA_USBDEV;
-       rsrc_len   = S3C24XX_SZ_USBDEV;
+       udc->mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+       if (!udc->mem) {
+               dev_err(dev, "failed to get I/O memory region\n");
+               return -ENOENT;
+       }
 
-       if (!request_mem_region(rsrc_start, rsrc_len, gadget_name))
+       if (!request_mem_region(udc->mem->start, resource_size(udc->mem), 
gadget_name))
                return -EBUSY;
 
-       base_addr = ioremap(rsrc_start, rsrc_len);
+       base_addr = ioremap(udc->mem->start, resource_size(udc->mem));
        if (!base_addr) {
                retval = -ENOMEM;
                goto err_mem;
@@ -1818,17 +1887,24 @@ static int s3c2410_udc_probe(struct platform_device 
*pdev)
        s3c2410_udc_disable(udc);
        s3c2410_udc_reinit(udc);
 
+       udc->irq = platform_get_irq(pdev, 0);
+       if (udc->irq == 0) {
+               dev_err(dev, "failed to get interrupt\n");
+               retval = -EINVAL;
+               goto err_map;
+       }
+
        /* irq setup after old hardware state is cleaned up */
-       retval = request_irq(IRQ_USBD, s3c2410_udc_irq,
+       retval = request_irq(udc->irq, s3c2410_udc_irq,
                             0, gadget_name, udc);
 
        if (retval != 0) {
-               dev_err(dev, "cannot get irq %i, err %d\n", IRQ_USBD, retval);
+               dev_err(dev, "cannot get irq %i, err %d\n", udc->irq, retval);
                retval = -EBUSY;
                goto err_map;
        }
 
-       dev_dbg(dev, "got irq %i\n", IRQ_USBD);
+       dev_dbg(dev, "got irq %i\n", udc->irq);
 
        if (udc_info && udc_info->vbus_pin > 0) {
                retval = gpio_request(udc_info->vbus_pin, "udc vbus");
@@ -1899,11 +1975,11 @@ static int s3c2410_udc_probe(struct platform_device 
*pdev)
        if (udc_info && udc_info->vbus_pin > 0)
                gpio_free(udc_info->vbus_pin);
 err_int:
-       free_irq(IRQ_USBD, udc);
+       free_irq(udc->irq, udc);
 err_map:
        iounmap(base_addr);
 err_mem:
-       release_mem_region(rsrc_start, rsrc_len);
+       release_mem_region(udc->mem->start, resource_size(udc->mem));
 
        return retval;
 }
@@ -1933,10 +2009,10 @@ static int s3c2410_udc_remove(struct platform_device 
*pdev)
                free_irq(irq, udc);
        }
 
-       free_irq(IRQ_USBD, udc);
+       free_irq(udc->irq, udc);
 
        iounmap(base_addr);
-       release_mem_region(rsrc_start, rsrc_len);
+       release_mem_region(udc->mem->start, resource_size(udc->mem));
 
        if (!IS_ERR(udc_clock) && udc_clock != NULL) {
                clk_disable_unprepare(udc_clock);
@@ -1974,16 +2050,36 @@ static int s3c2410_udc_resume(struct platform_device 
*pdev)
 #define s3c2410_udc_resume     NULL
 #endif
 
+static const struct of_device_id s3c_udc_dt_ids[] = {
+       {
+               .compatible = "samsung,s3c2410-udc",
+               .data = &s3c2410_udc_2410_drv_data,
+       },
+       {
+               .compatible = "samsung,s3c2440-udc",
+               .data = &s3c2410_udc_2440_drv_data,
+       },
+       { /* sentinel */ },
+};
+MODULE_DEVICE_TABLE(of, s3c_udc_dt_ids);
+
 static const struct platform_device_id s3c_udc_ids[] = {
-       { "s3c2410-usbgadget", },
-       { "s3c2440-usbgadget", },
-       { }
+       {
+               .name = "s3c2410-usbgadget",
+               .driver_data = (kernel_ulong_t) &s3c2410_udc_2410_drv_data,
+       },
+       {
+               .name = "s3c2440-usbgadget",
+               .driver_data = (kernel_ulong_t) &s3c2410_udc_2440_drv_data,
+       },
+       { /* sentinel */},
 };
 MODULE_DEVICE_TABLE(platform, s3c_udc_ids);
 
 static struct platform_driver udc_driver_24x0 = {
        .driver         = {
                .name   = "s3c24x0-usbgadget",
+               .of_match_table = s3c_udc_dt_ids,
        },
        .probe          = s3c2410_udc_probe,
        .remove         = s3c2410_udc_remove,
diff --git a/drivers/usb/gadget/udc/s3c2410_udc.h 
b/drivers/usb/gadget/udc/s3c2410_udc.h
index 93bf225f1969..8fdbe77a804d 100644
--- a/drivers/usb/gadget/udc/s3c2410_udc.h
+++ b/drivers/usb/gadget/udc/s3c2410_udc.h
@@ -94,6 +94,10 @@ struct s3c2410_udc {
        unsigned                        req_pending : 1;
        u8                              vbus;
        struct dentry                   *regs_info;
+       struct platform_device          *pdev;
+       struct resource                 *mem;
+       int                             irq;
+       unsigned int                    ep_fifo_size;
 };
 #define to_s3c2410(g)  (container_of((g), struct s3c2410_udc, gadget))
 
-- 
1.9.1

--
To unsubscribe from this list: send the line "unsubscribe linux-usb" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

Reply via email to