2016-12-09 19:07:02

by Sergio Prado

[permalink] [raw]
Subject: [PATCH 0/2] usb: gadget: s3c2410: add device tree support

This series adds support for configuring Samsung's s3c2410 and
compatible USB device controller via devicetree.

Tested on FriendlyARM mini2440, based on s3c2440 SoC.

Sergio Prado (2):
dt-bindings: usb: add DT binding for s3c2410 USB device controller
usb: gadget: s3c2410: allow probing from device tree

.../devicetree/bindings/usb/s3c2410-usb.txt | 28 ++++
drivers/usb/gadget/udc/s3c2410_udc.c | 142 +++++++++++++++++----
drivers/usb/gadget/udc/s3c2410_udc.h | 4 +
3 files changed, 151 insertions(+), 23 deletions(-)

--
1.9.1


2016-12-09 19:07:07

by Sergio Prado

[permalink] [raw]
Subject: [PATCH 1/2] dt-bindings: usb: add DT binding for s3c2410 USB device controller

Adds the device tree bindings description for Samsung S3C2410 and
compatible USB device controller.

Signed-off-by: Sergio Prado <[email protected]>
---
.../devicetree/bindings/usb/s3c2410-usb.txt | 28 ++++++++++++++++++++++
1 file changed, 28 insertions(+)

diff --git a/Documentation/devicetree/bindings/usb/s3c2410-usb.txt b/Documentation/devicetree/bindings/usb/s3c2410-usb.txt
index e45b38ce2986..4d3f9894c2d4 100644
--- a/Documentation/devicetree/bindings/usb/s3c2410-usb.txt
+++ b/Documentation/devicetree/bindings/usb/s3c2410-usb.txt
@@ -20,3 +20,31 @@ usb0: ohci@49000000 {
clocks = <&clocks UCLK>, <&clocks HCLK_USBH>;
clock-names = "usb-bus-host", "usb-host";
};
+
+Samsung S3C2410 and compatible USB device controller
+
+Required properties:
+ - compatible: Should be one of the following
+ "samsung,s3c2410-udc"
+ "samsung,s3c2440-udc"
+ - reg: address and length of the controller memory mapped region
+ - interrupts: interrupt number for the USB device controller
+ - clocks: Should reference the bus and host clocks
+ - clock-names: Should contain two strings
+ "usb-bus-gadget" for the USB bus clock
+ "usb-device" for the USB device clock
+
+Optional properties:
+ - samsung,vbus-gpio: If present, specifies a gpio that needs to be
+ activated for the bus to be powered.
+ - samsung,pullup-gpio: If present, specifies a gpio to control the
+ USB D+ pullup.
+
+usb1: udc@52000000 {
+ compatible = "samsung,s3c2440-udc";
+ reg = <0x52000000 0x100000>;
+ interrupts = <0 0 25 3>;
+ clocks = <&clocks UCLK>, <&clocks HCLK_USBD>;
+ clock-names = "usb-bus-gadget", "usb-device";
+ samsung,pullup-gpio = <&gpc 5 GPIO_ACTIVE_HIGH>;
+};
--
1.9.1

2016-12-09 19:07:19

by Sergio Prado

[permalink] [raw]
Subject: [PATCH 2/2] usb: gadget: s3c2410: allow probing from device tree

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

Signed-off-by: Sergio Prado <[email protected]>
---
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 <[email protected]>, " \
"Arnaud Patard <[email protected]>"

+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

2016-12-13 18:59:21

by Rob Herring

[permalink] [raw]
Subject: Re: [PATCH 1/2] dt-bindings: usb: add DT binding for s3c2410 USB device controller

On Fri, Dec 09, 2016 at 05:06:39PM -0200, Sergio Prado wrote:
> Adds the device tree bindings description for Samsung S3C2410 and
> compatible USB device controller.
>
> Signed-off-by: Sergio Prado <[email protected]>
> ---
> .../devicetree/bindings/usb/s3c2410-usb.txt | 28 ++++++++++++++++++++++
> 1 file changed, 28 insertions(+)
>
> diff --git a/Documentation/devicetree/bindings/usb/s3c2410-usb.txt b/Documentation/devicetree/bindings/usb/s3c2410-usb.txt
> index e45b38ce2986..4d3f9894c2d4 100644
> --- a/Documentation/devicetree/bindings/usb/s3c2410-usb.txt
> +++ b/Documentation/devicetree/bindings/usb/s3c2410-usb.txt
> @@ -20,3 +20,31 @@ usb0: ohci@49000000 {
> clocks = <&clocks UCLK>, <&clocks HCLK_USBH>;
> clock-names = "usb-bus-host", "usb-host";
> };
> +
> +Samsung S3C2410 and compatible USB device controller
> +
> +Required properties:
> + - compatible: Should be one of the following
> + "samsung,s3c2410-udc"
> + "samsung,s3c2440-udc"
> + - reg: address and length of the controller memory mapped region
> + - interrupts: interrupt number for the USB device controller
> + - clocks: Should reference the bus and host clocks
> + - clock-names: Should contain two strings
> + "usb-bus-gadget" for the USB bus clock

Pretty sure the h/w clock name in the datasheet does not use the Linux
term gadget.

> + "usb-device" for the USB device clock
> +
> +Optional properties:
> + - samsung,vbus-gpio: If present, specifies a gpio that needs to be
> + activated for the bus to be powered.

Isn't it the host side that controls Vbus?

> + - samsung,pullup-gpio: If present, specifies a gpio to control the

Both GPIOs need to specify the active state.

> + USB D+ pullup.
> +
> +usb1: udc@52000000 {
> + compatible = "samsung,s3c2440-udc";
> + reg = <0x52000000 0x100000>;
> + interrupts = <0 0 25 3>;
> + clocks = <&clocks UCLK>, <&clocks HCLK_USBD>;
> + clock-names = "usb-bus-gadget", "usb-device";
> + samsung,pullup-gpio = <&gpc 5 GPIO_ACTIVE_HIGH>;
> +};
> --
> 1.9.1
>

2016-12-17 12:50:22

by Sergio Prado

[permalink] [raw]
Subject: Re: [PATCH 1/2] dt-bindings: usb: add DT binding for s3c2410 USB device controller

On Tue, Dec 13, 2016 at 12:59:15PM -0600, Rob Herring wrote:
> > +Samsung S3C2410 and compatible USB device controller
> > +
> > +Required properties:
> > + - compatible: Should be one of the following
> > + "samsung,s3c2410-udc"
> > + "samsung,s3c2440-udc"
> > + - reg: address and length of the controller memory mapped region
> > + - interrupts: interrupt number for the USB device controller
> > + - clocks: Should reference the bus and host clocks
> > + - clock-names: Should contain two strings
> > + "usb-bus-gadget" for the USB bus clock
>
> Pretty sure the h/w clock name in the datasheet does not use the Linux
> term gadget.

You are right. The datasheet calls it UCLK. In the S3c24010 clock driver
(clk-s3c2410.c), there's is a clock alias to UCLK called
"usb-bus-gadget" that was used in the USB device controller's driver.
We can change the driver and the DT binding to use "uclk" to
better reflect the name used in the datasheet. What do you think?

>
> > + "usb-device" for the USB device clock
> > +
> > +Optional properties:
> > + - samsung,vbus-gpio: If present, specifies a gpio that needs to be
> > + activated for the bus to be powered.
>
> Isn't it the host side that controls Vbus?

Yes. I'll change the description to "specifies a gpio that allows to
detect whether vbus is present (USB is connected)."

>
> > + - samsung,pullup-gpio: If present, specifies a gpio to control the
>
> Both GPIOs need to specify the active state.

OK.

>
> > + USB D+ pullup.
> > +
> > +usb1: udc@52000000 {
> > + compatible = "samsung,s3c2440-udc";
> > + reg = <0x52000000 0x100000>;
> > + interrupts = <0 0 25 3>;
> > + clocks = <&clocks UCLK>, <&clocks HCLK_USBD>;
> > + clock-names = "usb-bus-gadget", "usb-device";
> > + samsung,pullup-gpio = <&gpc 5 GPIO_ACTIVE_HIGH>;
> > +};
> > --
> > 1.9.1
> >

Best regards,

--
Sergio Prado
Embedded Labworks