Skip to contentSkip to conversation

at91 USB DT support

PATCH New Jean-Christophe PLAGNIOL-VILLARD 3 participants 17 messages Mar 7, 2012 – Apr 18, 2012

Subsystems (7)
lore
Share & tools
lore
#0 lore raw

v2 cover at91 USB DT support

HI,

this is a second version of the patch series to add DT suport for usb host and device on at91

The following changes since commit 3370718be26d86e7f8587390eee563c289542ee7:

ARM: at91/dt: add Calao DAB-MMX daugther board support for USB-A9G20 (2012-03-02 00:46:21 +0800)

are available in the git repository at:
git at github.com:at91linux/linux-at91.git ..BRANCH.NOT.VERIFIED..

Jean-Christophe PLAGNIOL-VILLARD (9):
ARM: at91: usb ohci add dt support
ARM: at91: dt: enable usb ohci for sam9g20, sam9g45 amd sam9x5
ARM: at91: usb ehci add dt support
ARM: at91: dt: enable usb ehci for sam9g45 and sam9x5
USB: at91: Device udc add dt support
ARM: at91: sam9g20 udc add dt support
usb: add Atmel USBA UDC DT support
ARM: at91: sam9g45 add udc DT support
ARM: at91: sam9x5 add udc DT support

 .../devicetree/bindings/usb/atmel-usb.txt          |  135 +++++++++++++
 arch/arm/boot/dts/at91sam9g20.dtsi                 |   14 ++
 arch/arm/boot/dts/at91sam9g25ek.dts                |   17 ++
 arch/arm/boot/dts/at91sam9g45.dtsi                 |   80 ++++++++
 arch/arm/boot/dts/at91sam9m10g45ek.dts             |   15 ++
 arch/arm/boot/dts/at91sam9x5.dtsi                  |   81 ++++++++
 arch/arm/boot/dts/usb_a9g20.dts                    |   10 +
 arch/arm/mach-at91/at91sam9260.c                   |    1 +
 arch/arm/mach-at91/at91sam9g45.c                   |    4 +
 arch/arm/mach-at91/at91sam9x5.c                    |    7 +-
 drivers/usb/Kconfig                                |    2 +-
 drivers/usb/gadget/Kconfig                         |    4 +-
 drivers/usb/gadget/at91_udc.c                      |   40 ++++-
 drivers/usb/gadget/atmel_usba_udc.c                |  209 +++++++++++++++-----
 drivers/usb/gadget/atmel_usba_udc.h                |    1 +
 drivers/usb/host/ehci-atmel.c                      |   24 +++-
 drivers/usb/host/ohci-at91.c                       |  101 ++++++++++-
 17 files changed, 688 insertions(+), 57 deletions(-)
 create mode 100644 Documentation/devicetree/bindings/usb/atmel-usb.txt

Best Regards,
J.

#1 lore raw

PATCH v2 1/9 ARM: at91: usb ohci add dt support

---
 .../devicetree/bindings/usb/atmel-usb.txt          |   19 ++++
 drivers/usb/host/ohci-at91.c                       |  101 +++++++++++++++++++-
 2 files changed, 119 insertions(+), 1 deletions(-)
 create mode 100644 Documentation/devicetree/bindings/usb/atmel-usb.txt
Documentation/devicetree/bindings/usb/atmel-usb.txt new file +19 -0
new file mode 100644
index 0000000..6c7f728
@@ -0,0 +1,19 @@
+Atmel SOC USB controllers
+
+OHCI
+
+Required properties:
+ - compatible: Should be "atmel,at91rm9200-ohci" for USB controllers
+   used in host mode.
+ - num-ports: Number of ports.
+ - atmel,vbus-gpio: If present, specifies a gpio that needs to be
+   activated for the bus to be powered.
+ - atmel,oc-gpio: If present, specifies a gpio that needs to be
+   activated for the overcurrent detection.
+
+usb0: ohci at 00500000 {
+	compatible = "atmel,at91rm9200-ohci", "usb-ohci";
+	reg = <0x00500000 0x100000>;
+	interrupts = <20 4>;
+	num-ports = <2>;
+};
drivers/usb/host/ohci-at91.c +100 -1

124 lines not on this page · raw message

Signature · 1 line
1.7.7
#2 lore raw

PATCH v2 1/9 ARM: at91: usb ohci add dt support

Quoted 9 lines · Jean-Christophe PLAGNIOL-VILLARD
drivers/usb/host/ohci-at91.c +9 -0
+static u64 at91_ohci_dma_mask = DMA_BIT_MASK(32);
+
+static int __devinit ohci_at91_of_init(struct platform_device *pdev)
+{
+	struct device_node *np = pdev->dev.of_node;
+	int i, ret, gpio;
+	enum of_gpio_flags flags;
+	struct at91_usbh_data	*pdata;
+	u32 ports;

drivers/usb/host/ohci-at91.c static irqreturn_t ohci_hcd_at91_overcurrent_irq(int irq, void *data) · line 508

Quoted 10 lines
drivers/usb/host/ohci-at91.c +10 -0
+
+	if (!np)
+		return 0;
+
+	/* Right now device-tree probed devices don't get dma_mask set.
+	 * Since shared usb code relies on it, set it here for now.
+	 * Once we have dma capability bindings this can go away.
+	 */
+	if (!pdev->dev.dma_mask)
+		pdev->dev.dma_mask = &at91_ohci_dma_mask;

That sounds like a rather big omission from DT - what's happening to address this (before we end up with lots of drivers with this). Pretty much any device which does DMA needs both this and the coherent DMA mask set properly.

We really don't want this kind of workaround scattered in every driver which has been converted to DT.

#3 lore raw

PATCH v2 1/9 ARM: at91: usb ohci add dt support

Quoted 26 lines · Russell King - ARM Linux
Quoted 9 lines · Jean-Christophe PLAGNIOL-VILLARD
drivers/usb/host/ohci-at91.c +9 -0
+static u64 at91_ohci_dma_mask = DMA_BIT_MASK(32);
+
+static int __devinit ohci_at91_of_init(struct platform_device *pdev)
+{
+	struct device_node *np = pdev->dev.of_node;
+	int i, ret, gpio;
+	enum of_gpio_flags flags;
+	struct at91_usbh_data	*pdata;
+	u32 ports;

drivers/usb/host/ohci-at91.c static irqreturn_t ohci_hcd_at91_overcurrent_irq(int irq, void *data) · line 508

Quoted 10 lines
drivers/usb/host/ohci-at91.c +10 -0
+
+	if (!np)
+		return 0;
+
+	/* Right now device-tree probed devices don't get dma_mask set.
+	 * Since shared usb code relies on it, set it here for now.
+	 * Once we have dma capability bindings this can go away.
+	 */
+	if (!pdev->dev.dma_mask)
+		pdev->dev.dma_mask = &at91_ohci_dma_mask;

That sounds like a rather big omission from DT - what's happening to address this (before we end up with lots of drivers with this). Pretty much any device which does DMA needs both this and the coherent DMA mask set properly.

Quoted 2 lines

We really don't want this kind of workaround scattered in every driver which has been converted to DT.

Tegra do it also
I do yet found a good generic way in DT

Today only usb need I do plan to drop it for 3.5 can we have for 3.4

Best Regards,
J.

#4 lore raw

PATCH v2 1/9 ARM: at91: usb ohci add dt support

Quoted 27 lines · Jean-Christophe PLAGNIOL-VILLARD
Quoted 26 lines · Russell King - ARM Linux
Quoted 9 lines · Jean-Christophe PLAGNIOL-VILLARD
drivers/usb/host/ohci-at91.c +9 -0
+static u64 at91_ohci_dma_mask = DMA_BIT_MASK(32);
+
+static int __devinit ohci_at91_of_init(struct platform_device *pdev)
+{
+	struct device_node *np = pdev->dev.of_node;
+	int i, ret, gpio;
+	enum of_gpio_flags flags;
+	struct at91_usbh_data	*pdata;
+	u32 ports;

drivers/usb/host/ohci-at91.c static irqreturn_t ohci_hcd_at91_overcurrent_irq(int irq, void *data) · line 508

Quoted 10 lines
drivers/usb/host/ohci-at91.c +10 -0
+
+	if (!np)
+		return 0;
+
+	/* Right now device-tree probed devices don't get dma_mask set.
+	 * Since shared usb code relies on it, set it here for now.
+	 * Once we have dma capability bindings this can go away.
+	 */
+	if (!pdev->dev.dma_mask)
+		pdev->dev.dma_mask = &at91_ohci_dma_mask;

That sounds like a rather big omission from DT - what's happening to address this (before we end up with lots of drivers with this). Pretty much any device which does DMA needs both this and the coherent DMA mask set properly.

Quoted 6 lines
Quoted 2 lines

We really don't want this kind of workaround scattered in every driver which has been converted to DT.

Tegra do it also
I do yet found a good generic way in DT

Today only usb need I do plan to drop it for 3.5 can we have for 3.4

I send a patch to propose a binding for both dma-mask and coherent dma mask

If it does not got for 3.4 can this temporary fix up go?

Best Regards,
J.

#5 lore raw

PATCH v2 2/9 ARM: at91: dt: enable usb ohci for sam9g20, sam9g45 amd sam9x5

In reply to Jean-Christophe PLAGNIOL-VILLARD
---
 arch/arm/boot/dts/at91sam9g20.dtsi     |    7 +++++++
 arch/arm/boot/dts/at91sam9g25ek.dts    |    8 ++++++++
 arch/arm/boot/dts/at91sam9g45.dtsi     |    7 +++++++
 arch/arm/boot/dts/at91sam9m10g45ek.dts |    6 ++++++
 arch/arm/boot/dts/at91sam9x5.dtsi      |    7 +++++++
 arch/arm/boot/dts/usb_a9g20.dts        |    5 +++++
 arch/arm/mach-at91/at91sam9260.c       |    1 +
 arch/arm/mach-at91/at91sam9g45.c       |    1 +
 arch/arm/mach-at91/at91sam9x5.c        |    4 +++-
 9 files changed, 45 insertions(+), 1 deletions(-)
arch/arm/boot/dts/at91sam9g20.dtsi +7 -0
index f803f31..8c5c175 100644
@@ -188,6 +188,13 @@
 				>;
 			status = "disabled";
 		};
+
+		usb0: ohci at 00500000 {
+			compatible = "atmel,at91rm9200-ohci", "usb-ohci";
+			reg = <0x00500000 0x100000>;
+			interrupts = <20 4>;
+			status = "disabled";
+		};
 	};
 
 	i2c-gpio at 0 {
arch/arm/boot/dts/at91sam9g25ek.dts +8 -0
index c7596bf..93d5e36 100644
@@ -33,5 +33,13 @@
 				status = "okay";
 			};
 		};
+
+		usb0: ohci at 00600000 {
+			status = "okay";
+			num-ports = <2>;
+			atmel,vbus-gpio = <&pioD 19 0
+					   &pioD 20 0
+					  >;
+		};
 	};
 };
arch/arm/boot/dts/at91sam9g45.dtsi +7 -0
index 93e095b..db9a51a 100644
@@ -196,6 +196,13 @@
 				>;
 			status = "disabled";
 		};
+
+		usb0: ohci at 00700000 {
+			compatible = "atmel,at91rm9200-ohci", "usb-ohci";
+			reg = <0x00700000 0x100000>;
+			interrupts = <22 4>;
+			status = "disabled";
+		};
 	};
 
 	i2c-gpio at 0 {
arch/arm/boot/dts/at91sam9m10g45ek.dts +6 -0
index 62ceffe..ce4640e 100644
@@ -57,7 +57,13 @@
 				label = "data";
 				reg = <0x4000000 0xC000000>;
 			};
+		};
 
+		usb0: ohci at 00700000 {
+			status = "okay";
+			num-ports = <2>;
+			atmel,vbus-gpio = <&pioD 1 0
+					   &pioD 3 0>;
 		};
 	};
 
arch/arm/boot/dts/at91sam9x5.dtsi +7 -0
index ad9570b..7b43014 100644
@@ -187,6 +187,13 @@
 				>;
 			status = "disabled";
 		};
+
+		usb0: ohci at 00600000 {
+			compatible = "atmel,at91rm9200-ohci", "usb-ohci";
+			reg = <0x00600000 0x100000>;
+			interrupts = <22 4>;
+			status = "disabled";
+		};
 	};
 
 	i2c-gpio at 0 {
arch/arm/boot/dts/usb_a9g20.dts +5 -0
index 07012ca..55d0e54 100644
@@ -73,6 +73,11 @@
 				reg = <0x7ca0000 0x8360000>;
 			};
 		};
+
+		usb0: ohci at 00500000 {
+			num-ports = <2>;
+			status = "okay";
+		};
 	};
 
 	leds {
arch/arm/mach-at91/at91sam9260.c +1 -0
index 14b5a9c..d1e5750 100644
@@ -216,6 +216,7 @@ static struct clk_lookup periph_clocks_lookups[] = {
 	CLKDEV_CON_DEV_ID("t0_clk", "fffdc000.timer", &tc3_clk),
 	CLKDEV_CON_DEV_ID("t1_clk", "fffdc000.timer", &tc4_clk),
 	CLKDEV_CON_DEV_ID("t2_clk", "fffdc000.timer", &tc5_clk),
+	CLKDEV_CON_DEV_ID("hclk", "500000.ohci", &ohci_clk),
 	/* fake hclk clock */
 	CLKDEV_CON_DEV_ID("hclk", "at91_ohci", &ohci_clk),
 	CLKDEV_CON_ID("pioA", &pioA_clk),
arch/arm/mach-at91/at91sam9g45.c +1 -0
index 0014573..f58775e 100644
@@ -232,6 +232,7 @@ static struct clk_lookup periph_clocks_lookups[] = {
 	/* more tc lookup table for DT entries */
 	CLKDEV_CON_DEV_ID("t0_clk", "fff7c000.timer", &tcb0_clk),
 	CLKDEV_CON_DEV_ID("t0_clk", "fffd4000.timer", &tcb0_clk),
+	CLKDEV_CON_DEV_ID("hclk", "700000.ohci", &uhphs_clk),
 	/* fake hclk clock */
 	CLKDEV_CON_DEV_ID("hclk", "at91_ohci", &uhphs_clk),
 	CLKDEV_CON_ID("pioA", &pioA_clk),
arch/arm/mach-at91/at91sam9x5.c +3 -1
index 7bec5a4..40888ab 100644
@@ -131,7 +131,7 @@ static struct clk dma1_clk = {
 	.type		= CLK_TYPE_PERIPHERAL,
 };
 static struct clk uhphs_clk = {
-	.name		= "uhphs_clk",
+	.name		= "uhphs",
 	.pmc_mask	= 1 << AT91SAM9X5_ID_UHPHS,
 	.type		= CLK_TYPE_PERIPHERAL,
 };
@@ -230,6 +230,8 @@ static struct clk_lookup periph_clocks_lookups[] = {
 	/* additional fake clock for macb_hclk */
 	CLKDEV_CON_DEV_ID("hclk", "f802c000.ethernet", &macb0_clk),
 	CLKDEV_CON_DEV_ID("hclk", "f8030000.ethernet", &macb1_clk),
+	CLKDEV_CON_DEV_ID("hclk", "600000.ohci", &uhphs_clk),
+	CLKDEV_CON_DEV_ID("ohci_clk", "600000.ohci", &uhphs_clk),
 };
 
 /*
Signature · 1 line
1.7.7
#6 lore raw

PATCH v2 3/9 ARM: at91: usb ehci add dt support

In reply to Jean-Christophe PLAGNIOL-VILLARD
---
 .../devicetree/bindings/usb/atmel-usb.txt          |   12 ++++++++++
 drivers/usb/host/ehci-atmel.c                      |   24 +++++++++++++++++++-
 2 files changed, 35 insertions(+), 1 deletions(-)
Documentation/devicetree/bindings/usb/atmel-usb.txt +12 -0
index 6c7f728..0143d7c 100644
@@ -17,3 +17,15 @@ usb0: ohci at 00500000 {
 	interrupts = <20 4>;
 	num-ports = <2>;
 };
+
+EHCI
+
+Required properties:
+ - compatible: Should be "atmel,at91sam9g45-ehci" for USB controllers
+   used in host mode.
+
+usb1: ehci at 00800000 {
+	compatible = "atmel,at91sam9g45-ehci", "usb-ehci";
+	reg = <0x00800000 0x100000>;
+	interrupts = <22 4>;
+};
drivers/usb/host/ehci-atmel.c +23 -1
index a5a3ef1..19f318a 100644
@@ -13,6 +13,7 @@
 
 #include <linux/clk.h>
 #include <linux/platform_device.h>
+#include <linux/of_platform.h>
 
 /* interface and function clocks */
 static struct clk *iclk, *fclk;
@@ -115,6 +116,8 @@ static const struct hc_driver ehci_atmel_hc_driver = {
 	.clear_tt_buffer_complete	= ehci_clear_tt_buffer_complete,
 };
 
+static u64 at91_ehci_dma_mask = DMA_BIT_MASK(32);
+
 static int __devinit ehci_atmel_drv_probe(struct platform_device *pdev)
 {
 	struct usb_hcd *hcd;
@@ -137,6 +140,13 @@ static int __devinit ehci_atmel_drv_probe(struct platform_device *pdev)
 		goto fail_create_hcd;
 	}
 
+	/* Right now device-tree probed devices don't get dma_mask set.
+	 * Since shared usb code relies on it, set it here for now.
+	 * Once we have dma capability bindings this can go away.
+	 */
+	if (!pdev->dev.dma_mask)
+		pdev->dev.dma_mask = &at91_ehci_dma_mask;
+
 	hcd = usb_create_hcd(driver, &pdev->dev, dev_name(&pdev->dev));
 	if (!hcd) {
 		retval = -ENOMEM;
@@ -225,9 +235,21 @@ static int __devexit ehci_atmel_drv_remove(struct platform_device *pdev)
 	return 0;
 }
 
+#ifdef CONFIG_OF
+static const struct of_device_id atmel_ehci_dt_ids[] = {
+	{ .compatible = "atmel,at91sam9g45-ehci" },
+	{ /* sentinel */ }
+};
+
+MODULE_DEVICE_TABLE(of, atmel_ehci_dt_ids);
+#endif
+
 static struct platform_driver ehci_atmel_driver = {
 	.probe		= ehci_atmel_drv_probe,
 	.remove		= __devexit_p(ehci_atmel_drv_remove),
 	.shutdown	= usb_hcd_platform_shutdown,
-	.driver.name	= "atmel-ehci",
+	.driver		= {
+		.name	= "atmel-ehci",
+		.of_match_table	= of_match_ptr(atmel_ehci_dt_ids),
+	},
 };
Signature · 1 line
1.7.7
#7 lore raw

PATCH v2 4/9 ARM: at91: dt: enable usb ehci for sam9g45 and sam9x5

In reply to Jean-Christophe PLAGNIOL-VILLARD
---
 arch/arm/boot/dts/at91sam9g25ek.dts    |    4 ++++
 arch/arm/boot/dts/at91sam9g45.dtsi     |    7 +++++++
 arch/arm/boot/dts/at91sam9m10g45ek.dts |    4 ++++
 arch/arm/boot/dts/at91sam9x5.dtsi      |    7 +++++++
 arch/arm/mach-at91/at91sam9g45.c       |    1 +
 arch/arm/mach-at91/at91sam9x5.c        |    1 +
 drivers/usb/Kconfig                    |    2 +-
 7 files changed, 25 insertions(+), 1 deletions(-)
arch/arm/boot/dts/at91sam9g25ek.dts +4 -0
index 93d5e36..ac0dc00 100644
@@ -41,5 +41,9 @@
 					   &pioD 20 0
 					  >;
 		};
+
+		usb1: ehci at 00700000 {
+			status = "okay";
+		};
 	};
 };
arch/arm/boot/dts/at91sam9g45.dtsi +7 -0
index db9a51a..4b54424 100644
@@ -203,6 +203,13 @@
 			interrupts = <22 4>;
 			status = "disabled";
 		};
+
+		usb1: ehci at 00800000 {
+			compatible = "atmel,at91sam9g45-ehci", "usb-ehci";
+			reg = <0x00800000 0x100000>;
+			interrupts = <22 4>;
+			status = "disabled";
+		};
 	};
 
 	i2c-gpio at 0 {
arch/arm/boot/dts/at91sam9m10g45ek.dts +4 -0
index ce4640e..4b1eb36 100644
@@ -65,6 +65,10 @@
 			atmel,vbus-gpio = <&pioD 1 0
 					   &pioD 3 0>;
 		};
+
+		usb1: ehci at 00800000 {
+			status = "okay";
+		};
 	};
 
 	leds {
arch/arm/boot/dts/at91sam9x5.dtsi +7 -0
index 7b43014..ac3c96c 100644
@@ -194,6 +194,13 @@
 			interrupts = <22 4>;
 			status = "disabled";
 		};
+
+		usb1: ehci at 00700000 {
+			compatible = "atmel,at91sam9g45-ehci", "usb-ehci";
+			reg = <0x00700000 0x100000>;
+			interrupts = <22 4>;
+			status = "disabled";
+		};
 	};
 
 	i2c-gpio at 0 {
arch/arm/mach-at91/at91sam9g45.c +1 -0
index f58775e..df3bcea 100644
@@ -233,6 +233,7 @@ static struct clk_lookup periph_clocks_lookups[] = {
 	CLKDEV_CON_DEV_ID("t0_clk", "fff7c000.timer", &tcb0_clk),
 	CLKDEV_CON_DEV_ID("t0_clk", "fffd4000.timer", &tcb0_clk),
 	CLKDEV_CON_DEV_ID("hclk", "700000.ohci", &uhphs_clk),
+	CLKDEV_CON_DEV_ID("ehci_clk", "800000.ehci", &uhphs_clk),
 	/* fake hclk clock */
 	CLKDEV_CON_DEV_ID("hclk", "at91_ohci", &uhphs_clk),
 	CLKDEV_CON_ID("pioA", &pioA_clk),
arch/arm/mach-at91/at91sam9x5.c +1 -0
index 40888ab..7333276 100644
@@ -232,6 +232,7 @@ static struct clk_lookup periph_clocks_lookups[] = {
 	CLKDEV_CON_DEV_ID("hclk", "f8030000.ethernet", &macb1_clk),
 	CLKDEV_CON_DEV_ID("hclk", "600000.ohci", &uhphs_clk),
 	CLKDEV_CON_DEV_ID("ohci_clk", "600000.ohci", &uhphs_clk),
+	CLKDEV_CON_DEV_ID("ehci_clk", "700000.ehci", &uhphs_clk),
 };
 
 /*
drivers/usb/Kconfig +1 -1
index 75823a1..afee052 100644
@@ -65,7 +65,7 @@ config USB_ARCH_HAS_EHCI
 	default y if PPC_MPC512x
 	default y if ARCH_IXP4XX
 	default y if ARCH_W90X900
-	default y if ARCH_AT91SAM9G45
+	default y if ARCH_AT91SAM9G45 || ARCH_AT91SAM9X5
 	default y if ARCH_MXC
 	default y if ARCH_OMAP3
 	default y if ARCH_CNS3XXX
Signature · 1 line
1.7.7
#8 lore raw

PATCH v2 5/9 USB: at91: Device udc add dt support

In reply to Jean-Christophe PLAGNIOL-VILLARD

Allow to compile it if AT91 is enable.

Cc Nicolas Ferre <[email protected]>
Cc linux-usb at vger.kernel.org

---
Hi Greg

	if it's ok with you I apply with the rest of the USB patch series via
	at91

Best Regards,
J.

 .../devicetree/bindings/usb/atmel-usb.txt          |   18 +++++++++
 drivers/usb/gadget/Kconfig                         |    2 +-
 drivers/usb/gadget/at91_udc.c                      |   40 +++++++++++++++++++-
 3 files changed, 57 insertions(+), 3 deletions(-)
Documentation/devicetree/bindings/usb/atmel-usb.txt +18 -0
index 0143d7c..60bd215 100644
@@ -29,3 +29,21 @@ usb1: ehci at 00800000 {
 	reg = <0x00800000 0x100000>;
 	interrupts = <22 4>;
 };
+
+AT91 USB device controller
+
+Required properties:
+ - compatible: Should be "atmel,at91rm9200-udc"
+ - reg: Address and length of the register set for the device
+ - interrupts: Should contain macb interrupt
+
+Optional properties:
+ - atmel,vbus-gpio: If present, specifies a gpio that needs to be
+   activated for the bus to be powered.
+
+usb1: gadget at fffa4000 {
+	compatible = "atmel,at91rm9200-udc";
+	reg = <0xfffa4000 0x4000>;
+	interrupts = <10 4>;
+	atmel,vbus-gpio = <&pioC 5 0>;
+};
drivers/usb/gadget/Kconfig +1 -1
index 85ae4b4..edf1144 100644
@@ -137,7 +137,7 @@ choice
 
 config USB_AT91
 	tristate "Atmel AT91 USB Device Port"
-	depends on ARCH_AT91 && !ARCH_AT91SAM9RL && !ARCH_AT91SAM9G45
+	depends on ARCH_AT91
 	help
 	   Many Atmel AT91 processors (such as the AT91RM2000) have a
 	   full speed USB Device Port with support for five configurable
drivers/usb/gadget/at91_udc.c +38 -2
index f99b3dc..4063209 100644
@@ -30,6 +30,8 @@
 #include <linux/usb/ch9.h>
 #include <linux/usb/gadget.h>
 #include <linux/prefetch.h>
+#include <linux/of.h>
+#include <linux/of_gpio.h>
 
 #include <asm/byteorder.h>
 #include <mach/hardware.h>
@@ -1707,7 +1709,27 @@ static void at91udc_shutdown(struct platform_device *dev)
 	spin_unlock_irqrestore(&udc->lock, flags);
 }
 
-static int __init at91udc_probe(struct platform_device *pdev)
+static void __devinit at91udc_of_init(struct at91_udc *udc,
+				     struct device_node *np)
+{
+	struct at91_udc_data *board = &udc->board;
+	u32 val;
+	enum of_gpio_flags flags;
+
+	if (of_property_read_u32(np, "atmel,vbus-polled", &val) == 0)
+		board->vbus_polled = 1;
+
+	board->vbus_pin = of_get_named_gpio_flags(np, "atmel,vbus-gpio", 0,
+						  &flags);
+	board->vbus_active_low = (flags & OF_GPIO_ACTIVE_LOW) ? 1 : 0;
+
+	board->pullup_pin = of_get_named_gpio_flags(np, "atmel,pullup-gpio", 0,
+						  &flags);
+
+	board->pullup_active_low = (flags & OF_GPIO_ACTIVE_LOW) ? 1 : 0;
+}
+
+static int __devinit at91udc_probe(struct platform_device *pdev)
 {
 	struct device	*dev = &pdev->dev;
 	struct at91_udc	*udc;
@@ -1742,7 +1764,11 @@ static int __init at91udc_probe(struct platform_device *pdev)
 	/* init software state */
 	udc = &controller;
 	udc->gadget.dev.parent = dev;
-	udc->board = *(struct at91_udc_data *) dev->platform_data;
+	if (pdev->dev.of_node)
+		at91udc_of_init(udc, pdev->dev.of_node);
+	else
+		memcpy(&udc->board, dev->platform_data,
+		       sizeof(struct at91_udc_data));
 	udc->pdev = pdev;
 	udc->enabled = 0;
 	spin_lock_init(&udc->lock);
@@ -1971,6 +1997,15 @@ static int at91udc_resume(struct platform_device *pdev)
 #define	at91udc_resume	NULL
 #endif
 
+#if defined(CONFIG_OF)
+static const struct of_device_id at91_udc_dt_ids[] = {
+	{ .compatible = "atmel,at91rm9200-udc" },
+	{ /* sentinel */ }
+};
+
+MODULE_DEVICE_TABLE(of, at91_udc_dt_ids);
+#endif
+
 static struct platform_driver at91_udc_driver = {
 	.remove		= __exit_p(at91udc_remove),
 	.shutdown	= at91udc_shutdown,
@@ -1979,6 +2014,7 @@ static struct platform_driver at91_udc_driver = {
 	.driver		= {
 		.name	= (char *) driver_name,
 		.owner	= THIS_MODULE,
+		.of_match_table	= of_match_ptr(at91_udc_dt_ids),
 	},
 };
 
Signature · 1 line
1.7.7
#10 lore raw

PATCH v2 6/9 ARM: at91: sam9g20 udc add dt support

In reply to Jean-Christophe PLAGNIOL-VILLARD
---
 arch/arm/boot/dts/at91sam9g20.dtsi |    7 +++++++
 arch/arm/boot/dts/usb_a9g20.dts    |    5 +++++
 2 files changed, 12 insertions(+), 0 deletions(-)
arch/arm/boot/dts/at91sam9g20.dtsi +7 -0
index 8c5c175..c030703 100644
@@ -171,6 +171,13 @@
 				interrupts = <21 4>;
 				status = "disabled";
 			};
+
+			usb1: gadget at fffa4000 {
+				compatible = "atmel,at91rm9200-udc";
+				reg = <0xfffa4000 0x4000>;
+				interrupts = <10 4>;
+				status = "disabled";
+			};
 		};
 
 		nand0: nand at 40000000 {
arch/arm/boot/dts/usb_a9g20.dts +5 -0
index 55d0e54..e4a732f 100644
@@ -30,6 +30,11 @@
 				phy-mode = "rmii";
 				status = "okay";
 			};
+
+			usb1: gadget at fffa4000 {
+				atmel,vbus-gpio = <&pioC 5 0>;
+				status = "okay";
+			};
 		};
 
 		nand0: nand at 40000000 {
Signature · 1 line
1.7.7
#11 lore raw

PATCH v2 7/9 usb: add Atmel USBA UDC DT support

In reply to Jean-Christophe PLAGNIOL-VILLARD

Allow to compile the driver all the time if AT91 enabled.

Cc Nicolas Ferre <[email protected]>
Cc linux-usb at vger.kernel.org

---
Hi Greg

	if it's ok with you I apply with the rest of the USB patch series via
	at91

Best Regards,
J. .../devicetree/bindings/usb/atmel-usb.txt | 86 ++++++++

 drivers/usb/gadget/Kconfig                         |    2 +-
 drivers/usb/gadget/atmel_usba_udc.c                |  209 +++++++++++++++-----
 drivers/usb/gadget/atmel_usba_udc.h                |    1 +
 4 files changed, 248 insertions(+), 50 deletions(-)
Documentation/devicetree/bindings/usb/atmel-usb.txt +86 -0
index 60bd215..b44f87e 100644
@@ -47,3 +47,89 @@ usb1: gadget at fffa4000 {
 	interrupts = <10 4>;
 	atmel,vbus-gpio = <&pioC 5 0>;
 };
+
+Atmel High-Speed USB device controller
+
+Required properties:
+ - compatible: Should be "atmel,at91sam9rl-udc"
+ - reg: Address and length of the register set for the device
+ - interrupts: Should contain macb interrupt
+ - ep childnode: To specifiy the number of endpoints and their properties.
+
+Optional properties:
+ - atmel,vbus-gpio: If present, specifies a gpio that needs to be
+   activated for the bus to be powered.
+
+Required child node properties:
+ - name: Name of the endpoint.
+ - reg: Num of the endpoint.
+ - atmel,fifo-size: Size of the fifo.
+ - atmel,nb-banks: Number of banks.
+ - atmel,can-dma: Boolean to specify if the endpoint support DMA.
+ - atmel,can-isoc: Boolean to specify if the endpoint support ISOC.
+
+usb2: gadget at fff78000 {
+	#address-cells = <1>;
+	#size-cells = <0>;
+	compatible = "atmel,at91sam9rl-udc";
+	reg = <0x00600000 0x80000
+	       0xfff78000 0x400>;
+	interrupts = <27 4>;
+	atmel,vbus-gpio = <&pioB 19 0>;
+
+	ep0 {
+		reg = <0>;
+		atmel,fifo-size = <64>;
+		atmel,nb-banks = <1>;
+		atmel,can-dma = <0>;
+		atmel,can-isoc = <0>;
+	};
+
+	ep1 {
+		reg = <1>;
+		atmel,fifo-size = <1024>;
+		atmel,nb-banks = <2>;
+		atmel,can-dma = <1>;
+		atmel,can-isoc = <1>;
+	};
+
+	ep2 {
+		reg = <2>;
+		atmel,fifo-size = <1024>;
+		atmel,nb-banks = <2>;
+		atmel,can-dma = <1>;
+		atmel,can-isoc = <1>;
+	};
+
+	ep3 {
+		reg = <3>;
+		atmel,fifo-size = <1024>;
+		atmel,nb-banks = <3>;
+		atmel,can-dma = <1>;
+		atmel,can-isoc = <0>;
+	};
+
+	ep4 {
+		reg = <4>;
+		atmel,fifo-size = <1024>;
+		atmel,nb-banks = <3>;
+		atmel,can-dma = <1>;
+		atmel,can-isoc = <0>;
+	};
+
+	ep5 {
+		reg = <5>;
+		atmel,fifo-size = <1024>;
+		atmel,nb-banks = <3>;
+		atmel,can-dma = <1>;
+		atmel,can-isoc = <1>;
+	};
+
+	ep6 {
+		reg = <6>;
+		atmel,fifo-size = <1024>;
+		atmel,nb-banks = <3>;
+		atmel,can-dma = <1>;
+		atmel,can-isoc = <1>;
+	};
+};
drivers/usb/gadget/Kconfig +1 -1
index edf1144..1dbba6c 100644
@@ -150,7 +150,7 @@ config USB_AT91
 config USB_ATMEL_USBA
 	tristate "Atmel USBA"
 	select USB_GADGET_DUALSPEED
-	depends on AVR32 || ARCH_AT91SAM9RL || ARCH_AT91SAM9G45
+	depends on AVR32 || ARCH_AT91
 	help
 	  USBA is the integrated high-speed USB Device controller on
 	  the AT32AP700x, some AT91SAM9 and AT91CAP9 processors from Atmel.
drivers/usb/gadget/atmel_usba_udc.c +160 -49

275 lines not on this page · raw message

drivers/usb/gadget/atmel_usba_udc.h +1 -0
index 88a2e07..2c068e7 100644
@@ -324,6 +324,7 @@ struct usba_udc {
 	int irq;
 	int vbus_pin;
 	int vbus_pin_inverted;
+	int num_ep;
 	struct clk *pclk;
 	struct clk *hclk;
 
Signature · 1 line
1.7.7
#12 lore raw

PATCH v2 7/9 usb: add Atmel USBA UDC DT support

Hi,

except the boolean that I need to update is it ok?

Best Regards,
J.

Quoted 427 lines · Jean-Christophe PLAGNIOL-VILLARD

Allow to compile the driver all the time if AT91 enabled.

Cc Nicolas Ferre <[email protected]>
Cc linux-usb at vger.kernel.org

---
Hi Greg

	if it's ok with you I apply with the rest of the USB patch series via
	at91

Best Regards,
J. .../devicetree/bindings/usb/atmel-usb.txt | 86 ++++++++

 drivers/usb/gadget/Kconfig                         |    2 +-
 drivers/usb/gadget/atmel_usba_udc.c                |  209 +++++++++++++++-----
 drivers/usb/gadget/atmel_usba_udc.h                |    1 +
 4 files changed, 248 insertions(+), 50 deletions(-)
Documentation/devicetree/bindings/usb/atmel-usb.txt +86 -0
index 60bd215..b44f87e 100644
@@ -47,3 +47,89 @@ usb1: gadget at fffa4000 {
 	interrupts = <10 4>;
 	atmel,vbus-gpio = <&pioC 5 0>;
 };
+
+Atmel High-Speed USB device controller
+
+Required properties:
+ - compatible: Should be "atmel,at91sam9rl-udc"
+ - reg: Address and length of the register set for the device
+ - interrupts: Should contain macb interrupt
+ - ep childnode: To specifiy the number of endpoints and their properties.
+
+Optional properties:
+ - atmel,vbus-gpio: If present, specifies a gpio that needs to be
+   activated for the bus to be powered.
+
+Required child node properties:
+ - name: Name of the endpoint.
+ - reg: Num of the endpoint.
+ - atmel,fifo-size: Size of the fifo.
+ - atmel,nb-banks: Number of banks.
+ - atmel,can-dma: Boolean to specify if the endpoint support DMA.
+ - atmel,can-isoc: Boolean to specify if the endpoint support ISOC.
+
+usb2: gadget at fff78000 {
+	#address-cells = <1>;
+	#size-cells = <0>;
+	compatible = "atmel,at91sam9rl-udc";
+	reg = <0x00600000 0x80000
+	       0xfff78000 0x400>;
+	interrupts = <27 4>;
+	atmel,vbus-gpio = <&pioB 19 0>;
+
+	ep0 {
+		reg = <0>;
+		atmel,fifo-size = <64>;
+		atmel,nb-banks = <1>;
+		atmel,can-dma = <0>;
+		atmel,can-isoc = <0>;
+	};
+
+	ep1 {
+		reg = <1>;
+		atmel,fifo-size = <1024>;
+		atmel,nb-banks = <2>;
+		atmel,can-dma = <1>;
+		atmel,can-isoc = <1>;
+	};
+
+	ep2 {
+		reg = <2>;
+		atmel,fifo-size = <1024>;
+		atmel,nb-banks = <2>;
+		atmel,can-dma = <1>;
+		atmel,can-isoc = <1>;
+	};
+
+	ep3 {
+		reg = <3>;
+		atmel,fifo-size = <1024>;
+		atmel,nb-banks = <3>;
+		atmel,can-dma = <1>;
+		atmel,can-isoc = <0>;
+	};
+
+	ep4 {
+		reg = <4>;
+		atmel,fifo-size = <1024>;
+		atmel,nb-banks = <3>;
+		atmel,can-dma = <1>;
+		atmel,can-isoc = <0>;
+	};
+
+	ep5 {
+		reg = <5>;
+		atmel,fifo-size = <1024>;
+		atmel,nb-banks = <3>;
+		atmel,can-dma = <1>;
+		atmel,can-isoc = <1>;
+	};
+
+	ep6 {
+		reg = <6>;
+		atmel,fifo-size = <1024>;
+		atmel,nb-banks = <3>;
+		atmel,can-dma = <1>;
+		atmel,can-isoc = <1>;
+	};
+};
drivers/usb/gadget/Kconfig +1 -1
index edf1144..1dbba6c 100644
@@ -150,7 +150,7 @@ config USB_AT91
 config USB_ATMEL_USBA
 	tristate "Atmel USBA"
 	select USB_GADGET_DUALSPEED
-	depends on AVR32 || ARCH_AT91SAM9RL || ARCH_AT91SAM9G45
+	depends on AVR32 || ARCH_AT91
 	help
 	  USBA is the integrated high-speed USB Device controller on
 	  the AT32AP700x, some AT91SAM9 and AT91CAP9 processors from Atmel.
drivers/usb/gadget/atmel_usba_udc.c +160 -49
index ce9dffb..234eabb 100644
@@ -21,6 +21,8 @@
 #include <linux/usb/gadget.h>
 #include <linux/usb/atmel_usba_udc.h>
 #include <linux/delay.h>
+#include <linux/of.h>
+#include <linux/of_gpio.h>
 
 #include <asm/gpio.h>
 #include <mach/board.h>
@@ -1885,9 +1887,143 @@ static int atmel_usba_stop(struct usb_gadget_driver *driver)
 	return 0;
 }
 
-static int __init usba_udc_probe(struct platform_device *pdev)
+#ifdef CONFIG_OF
+static struct usba_ep * __devinit atmel_udc_of_init(struct platform_device *pdev,
+						    struct usba_udc *udc)
+{
+	u32 val;
+	const char *name;
+	enum of_gpio_flags flags;
+	struct device_node *np = pdev->dev.of_node;
+	struct device_node *pp;
+	int i, ret;
+	struct usba_ep *eps, *ep;
+
+	udc->num_ep = 0;
+
+	udc->vbus_pin = of_get_named_gpio_flags(np, "atmel,vbus-gpio", 0,
+						&flags);
+	udc->vbus_pin_inverted = (flags & OF_GPIO_ACTIVE_LOW) ? 1 : 0;
+
+	pp = NULL;
+	while ((pp = of_get_next_child(np, pp)))
+		udc->num_ep++;
+
+	eps = devm_kzalloc(&pdev->dev, sizeof(struct usba_ep) * udc->num_ep,
+			   GFP_KERNEL);
+	if (!eps)
+		return ERR_PTR(-ENOMEM);
+
+	udc->gadget.ep0 = &eps[0].ep;
+
+	INIT_LIST_HEAD(&eps[0].ep.ep_list);
+
+	pp = NULL;
+	i = 0;
+	while ((pp = of_get_next_child(np, pp))) {
+		ep = &eps[i];
+
+		ret = of_property_read_u32(pp, "reg", &val);
+		if (ret) {
+			dev_err(&pdev->dev, "of_probe: reg error(%d)\n", ret);
+			goto err;
+		}
+		ep->index = val;
+
+		ret = of_property_read_u32(pp, "atmel,fifo-size", &val);
+		if (ret) {
+			dev_err(&pdev->dev, "of_probe: fifo-size error(%d)\n", ret);
+			goto err;
+		}
+		ep->fifo_size = val;
+
+		ret = of_property_read_u32(pp, "atmel,nb-banks", &val);
+		if (ret) {
+			dev_err(&pdev->dev, "of_probe: nb-banks error(%d)\n", ret);
+			goto err;
+		}
+		ep->nr_banks = val;
+
+		ep->can_dma = of_property_read_bool(pp, "atmel,can-dma");
+		ep->can_isoc = of_property_read_bool(pp, "atmel,can-isoc");
+
+		ret = of_property_read_string(pp, "name", &name);
+		ep->ep.name = name;
+
+		ep->ep_regs = udc->regs + USBA_EPT_BASE(i);
+		ep->dma_regs = udc->regs + USBA_DMA_BASE(i);
+		ep->fifo = udc->fifo + USBA_FIFO_BASE(i);
+		ep->ep.ops = &usba_ep_ops;
+		ep->ep.maxpacket = ep->fifo_size;
+		ep->udc = udc;
+		INIT_LIST_HEAD(&ep->queue);
+
+		if (i)
+			list_add_tail(&ep->ep.ep_list, &udc->gadget.ep_list);
+
+		i++;
+	}
+
+	return eps;
+err:
+	return ERR_PTR(ret);
+}
+#else
+static struct usba_ep * __devinit atmel_udc_of_init(struct platform_device *pdev,
+						    struct usba_udc *udc)
+{
+	return ERR_PTR(-ENOSYS);
+}
+#endif
+
+static struct usba_ep * __devinit usba_udc_pdata(struct platform_device *pdev,
+						 struct usba_udc *udc)
 {
 	struct usba_platform_data *pdata = pdev->dev.platform_data;
+	struct usba_ep *eps;
+	int i;
+
+	if (!pdata)
+		return ERR_PTR(-ENXIO);
+
+	eps = devm_kzalloc(&pdev->dev, sizeof(struct usba_ep) * pdata->num_ep,
+			   GFP_KERNEL);
+	if (!eps)
+		return ERR_PTR(-ENOMEM);
+
+	udc->gadget.ep0 = &eps[0].ep;
+
+	udc->vbus_pin = pdata->vbus_pin;
+	udc->vbus_pin_inverted = pdata->vbus_pin_inverted;
+	udc->num_ep = pdata->num_ep;
+
+	INIT_LIST_HEAD(&eps[0].ep.ep_list);
+
+	for (i = 0; i < pdata->num_ep; i++) {
+		struct usba_ep *ep = &eps[i];
+
+		ep->ep_regs = udc->regs + USBA_EPT_BASE(i);
+		ep->dma_regs = udc->regs + USBA_DMA_BASE(i);
+		ep->fifo = udc->fifo + USBA_FIFO_BASE(i);
+		ep->ep.ops = &usba_ep_ops;
+		ep->ep.name = pdata->ep[i].name;
+		ep->fifo_size = ep->ep.maxpacket = pdata->ep[i].fifo_size;
+		ep->udc = udc;
+		INIT_LIST_HEAD(&ep->queue);
+		ep->nr_banks = pdata->ep[i].nr_banks;
+		ep->index = pdata->ep[i].index;
+		ep->can_dma = pdata->ep[i].can_dma;
+		ep->can_isoc = pdata->ep[i].can_isoc;
+
+		if (i)
+			list_add_tail(&ep->ep.ep_list, &udc->gadget.ep_list);
+	}
+
+	return eps;
+}
+
+static int __init usba_udc_probe(struct platform_device *pdev)
+{
 	struct resource *regs, *fifo;
 	struct clk *pclk, *hclk;
 	struct usba_udc *udc = &the_udc;
@@ -1895,7 +2031,7 @@ static int __init usba_udc_probe(struct platform_device *pdev)
 
 	regs = platform_get_resource(pdev, IORESOURCE_MEM, CTRL_IOMEM_ID);
 	fifo = platform_get_resource(pdev, IORESOURCE_MEM, FIFO_IOMEM_ID);
-	if (!regs || !fifo || !pdata)
+	if (!regs || !fifo)
 		return -ENXIO;
 
 	irq = platform_get_irq(pdev, 0);
@@ -1945,46 +2081,14 @@ static int __init usba_udc_probe(struct platform_device *pdev)
 	usba_writel(udc, CTRL, USBA_DISABLE_MASK);
 	clk_disable(pclk);
 
-	usba_ep = kzalloc(sizeof(struct usba_ep) * pdata->num_ep,
-			  GFP_KERNEL);
-	if (!usba_ep)
-		goto err_alloc_ep;
-
-	the_udc.gadget.ep0 = &usba_ep[0].ep;
-
-	INIT_LIST_HEAD(&usba_ep[0].ep.ep_list);
-	usba_ep[0].ep_regs = udc->regs + USBA_EPT_BASE(0);
-	usba_ep[0].dma_regs = udc->regs + USBA_DMA_BASE(0);
-	usba_ep[0].fifo = udc->fifo + USBA_FIFO_BASE(0);
-	usba_ep[0].ep.ops = &usba_ep_ops;
-	usba_ep[0].ep.name = pdata->ep[0].name;
-	usba_ep[0].ep.maxpacket = pdata->ep[0].fifo_size;
-	usba_ep[0].udc = &the_udc;
-	INIT_LIST_HEAD(&usba_ep[0].queue);
-	usba_ep[0].fifo_size = pdata->ep[0].fifo_size;
-	usba_ep[0].nr_banks = pdata->ep[0].nr_banks;
-	usba_ep[0].index = pdata->ep[0].index;
-	usba_ep[0].can_dma = pdata->ep[0].can_dma;
-	usba_ep[0].can_isoc = pdata->ep[0].can_isoc;
-
-	for (i = 1; i < pdata->num_ep; i++) {
-		struct usba_ep *ep = &usba_ep[i];
-
-		ep->ep_regs = udc->regs + USBA_EPT_BASE(i);
-		ep->dma_regs = udc->regs + USBA_DMA_BASE(i);
-		ep->fifo = udc->fifo + USBA_FIFO_BASE(i);
-		ep->ep.ops = &usba_ep_ops;
-		ep->ep.name = pdata->ep[i].name;
-		ep->ep.maxpacket = pdata->ep[i].fifo_size;
-		ep->udc = &the_udc;
-		INIT_LIST_HEAD(&ep->queue);
-		ep->fifo_size = pdata->ep[i].fifo_size;
-		ep->nr_banks = pdata->ep[i].nr_banks;
-		ep->index = pdata->ep[i].index;
-		ep->can_dma = pdata->ep[i].can_dma;
-		ep->can_isoc = pdata->ep[i].can_isoc;
+	if (pdev->dev.of_node)
+		usba_ep = atmel_udc_of_init(pdev, udc);
+	else
+		usba_ep = usba_udc_pdata(pdev, udc);
 
-		list_add_tail(&ep->ep.ep_list, &udc->gadget.ep_list);
+	if (IS_ERR(usba_ep)) {
+		ret = PTR_ERR(usba_ep);
+		goto err_alloc_ep;
 	}
 
 	ret = request_irq(irq, usba_udc_irq, 0, "atmel_usba_udc", udc);
@@ -2001,10 +2105,8 @@ static int __init usba_udc_probe(struct platform_device *pdev)
 		goto err_device_add;
 	}
 
-	if (gpio_is_valid(pdata->vbus_pin)) {
-		if (!gpio_request(pdata->vbus_pin, "atmel_usba_udc")) {
-			udc->vbus_pin = pdata->vbus_pin;
-			udc->vbus_pin_inverted = pdata->vbus_pin_inverted;
+	if (gpio_is_valid(udc->vbus_pin)) {
+		if (!gpio_request(udc->vbus_pin, "atmel_usba_udc")) {
 
 			ret = request_irq(gpio_to_irq(udc->vbus_pin),
 					usba_vbus_irq, 0,
@@ -2029,13 +2131,13 @@ static int __init usba_udc_probe(struct platform_device *pdev)
 		goto err_add_udc;
 
 	usba_init_debugfs(udc);
-	for (i = 1; i < pdata->num_ep; i++)
+	for (i = 1; i < udc->num_ep; i++)
 		usba_ep_init_debugfs(udc, &usba_ep[i]);
 
 	return 0;
 
 err_add_udc:
-	if (gpio_is_valid(pdata->vbus_pin)) {
+	if (gpio_is_valid(udc->vbus_pin)) {
 		free_irq(gpio_to_irq(udc->vbus_pin), udc);
 		gpio_free(udc->vbus_pin);
 	}
@@ -2064,13 +2166,12 @@ static int __exit usba_udc_remove(struct platform_device *pdev)
 {
 	struct usba_udc *udc;
 	int i;
-	struct usba_platform_data *pdata = pdev->dev.platform_data;
 
 	udc = platform_get_drvdata(pdev);
 
 	usb_del_gadget_udc(&udc->gadget);
 
-	for (i = 1; i < pdata->num_ep; i++)
+	for (i = 1; i < udc->num_ep; i++)
 		usba_ep_cleanup_debugfs(&usba_ep[i]);
 	usba_cleanup_debugfs(udc);
 
@@ -2091,11 +2192,21 @@ static int __exit usba_udc_remove(struct platform_device *pdev)
 	return 0;
 }
 
+#if defined(CONFIG_OF)
+static const struct of_device_id atmel_udc_dt_ids[] = {
+	{ .compatible = "atmel,at91sam9rl-udc" },
+	{ /* sentinel */ }
+};
+
+MODULE_DEVICE_TABLE(of, atmel_udc_dt_ids);
+#endif
+
 static struct platform_driver udc_driver = {
 	.remove		= __exit_p(usba_udc_remove),
 	.driver		= {
 		.name		= "atmel_usba_udc",
 		.owner		= THIS_MODULE,
+		.of_match_table	= of_match_ptr(atmel_udc_dt_ids),
 	},
 };
 
drivers/usb/gadget/atmel_usba_udc.h +1 -0
index 88a2e07..2c068e7 100644
@@ -324,6 +324,7 @@ struct usba_udc {
 	int irq;
 	int vbus_pin;
 	int vbus_pin_inverted;
+	int num_ep;
 	struct clk *pclk;
 	struct clk *hclk;
 
Signature · 1 line
1.7.7
#13 lore raw

PATCH v2 7/9 usb: add Atmel USBA UDC DT support

Quoted 3 lines · Jean-Christophe PLAGNIOL-VILLARD

Hi,

except the boolean that I need to update is it ok?

Grant is it ok?

Best Regards,
J.

Quoted 432 lines · Jean-Christophe PLAGNIOL-VILLARD
Quoted 427 lines

Allow to compile the driver all the time if AT91 enabled.

Cc Nicolas Ferre <[email protected]>
Cc linux-usb at vger.kernel.org

---
Hi Greg

	if it's ok with you I apply with the rest of the USB patch series via
	at91

Best Regards,
J. .../devicetree/bindings/usb/atmel-usb.txt | 86 ++++++++

 drivers/usb/gadget/Kconfig                         |    2 +-
 drivers/usb/gadget/atmel_usba_udc.c                |  209 +++++++++++++++-----
 drivers/usb/gadget/atmel_usba_udc.h                |    1 +
 4 files changed, 248 insertions(+), 50 deletions(-)
Documentation/devicetree/bindings/usb/atmel-usb.txt +86 -0
index 60bd215..b44f87e 100644
@@ -47,3 +47,89 @@ usb1: gadget at fffa4000 {
 	interrupts = <10 4>;
 	atmel,vbus-gpio = <&pioC 5 0>;
 };
+
+Atmel High-Speed USB device controller
+
+Required properties:
+ - compatible: Should be "atmel,at91sam9rl-udc"
+ - reg: Address and length of the register set for the device
+ - interrupts: Should contain macb interrupt
+ - ep childnode: To specifiy the number of endpoints and their properties.
+
+Optional properties:
+ - atmel,vbus-gpio: If present, specifies a gpio that needs to be
+   activated for the bus to be powered.
+
+Required child node properties:
+ - name: Name of the endpoint.
+ - reg: Num of the endpoint.
+ - atmel,fifo-size: Size of the fifo.
+ - atmel,nb-banks: Number of banks.
+ - atmel,can-dma: Boolean to specify if the endpoint support DMA.
+ - atmel,can-isoc: Boolean to specify if the endpoint support ISOC.
+
+usb2: gadget at fff78000 {
+	#address-cells = <1>;
+	#size-cells = <0>;
+	compatible = "atmel,at91sam9rl-udc";
+	reg = <0x00600000 0x80000
+	       0xfff78000 0x400>;
+	interrupts = <27 4>;
+	atmel,vbus-gpio = <&pioB 19 0>;
+
+	ep0 {
+		reg = <0>;
+		atmel,fifo-size = <64>;
+		atmel,nb-banks = <1>;
+		atmel,can-dma = <0>;
+		atmel,can-isoc = <0>;
+	};
+
+	ep1 {
+		reg = <1>;
+		atmel,fifo-size = <1024>;
+		atmel,nb-banks = <2>;
+		atmel,can-dma = <1>;
+		atmel,can-isoc = <1>;
+	};
+
+	ep2 {
+		reg = <2>;
+		atmel,fifo-size = <1024>;
+		atmel,nb-banks = <2>;
+		atmel,can-dma = <1>;
+		atmel,can-isoc = <1>;
+	};
+
+	ep3 {
+		reg = <3>;
+		atmel,fifo-size = <1024>;
+		atmel,nb-banks = <3>;
+		atmel,can-dma = <1>;
+		atmel,can-isoc = <0>;
+	};
+
+	ep4 {
+		reg = <4>;
+		atmel,fifo-size = <1024>;
+		atmel,nb-banks = <3>;
+		atmel,can-dma = <1>;
+		atmel,can-isoc = <0>;
+	};
+
+	ep5 {
+		reg = <5>;
+		atmel,fifo-size = <1024>;
+		atmel,nb-banks = <3>;
+		atmel,can-dma = <1>;
+		atmel,can-isoc = <1>;
+	};
+
+	ep6 {
+		reg = <6>;
+		atmel,fifo-size = <1024>;
+		atmel,nb-banks = <3>;
+		atmel,can-dma = <1>;
+		atmel,can-isoc = <1>;
+	};
+};
drivers/usb/gadget/Kconfig +1 -1
index edf1144..1dbba6c 100644
@@ -150,7 +150,7 @@ config USB_AT91
 config USB_ATMEL_USBA
 	tristate "Atmel USBA"
 	select USB_GADGET_DUALSPEED
-	depends on AVR32 || ARCH_AT91SAM9RL || ARCH_AT91SAM9G45
+	depends on AVR32 || ARCH_AT91
 	help
 	  USBA is the integrated high-speed USB Device controller on
 	  the AT32AP700x, some AT91SAM9 and AT91CAP9 processors from Atmel.
drivers/usb/gadget/atmel_usba_udc.c +160 -49
index ce9dffb..234eabb 100644
@@ -21,6 +21,8 @@
 #include <linux/usb/gadget.h>
 #include <linux/usb/atmel_usba_udc.h>
 #include <linux/delay.h>
+#include <linux/of.h>
+#include <linux/of_gpio.h>
 
 #include <asm/gpio.h>
 #include <mach/board.h>
@@ -1885,9 +1887,143 @@ static int atmel_usba_stop(struct usb_gadget_driver *driver)
 	return 0;
 }
 
-static int __init usba_udc_probe(struct platform_device *pdev)
+#ifdef CONFIG_OF
+static struct usba_ep * __devinit atmel_udc_of_init(struct platform_device *pdev,
+						    struct usba_udc *udc)
+{
+	u32 val;
+	const char *name;
+	enum of_gpio_flags flags;
+	struct device_node *np = pdev->dev.of_node;
+	struct device_node *pp;
+	int i, ret;
+	struct usba_ep *eps, *ep;
+
+	udc->num_ep = 0;
+
+	udc->vbus_pin = of_get_named_gpio_flags(np, "atmel,vbus-gpio", 0,
+						&flags);
+	udc->vbus_pin_inverted = (flags & OF_GPIO_ACTIVE_LOW) ? 1 : 0;
+
+	pp = NULL;
+	while ((pp = of_get_next_child(np, pp)))
+		udc->num_ep++;
+
+	eps = devm_kzalloc(&pdev->dev, sizeof(struct usba_ep) * udc->num_ep,
+			   GFP_KERNEL);
+	if (!eps)
+		return ERR_PTR(-ENOMEM);
+
+	udc->gadget.ep0 = &eps[0].ep;
+
+	INIT_LIST_HEAD(&eps[0].ep.ep_list);
+
+	pp = NULL;
+	i = 0;
+	while ((pp = of_get_next_child(np, pp))) {
+		ep = &eps[i];
+
+		ret = of_property_read_u32(pp, "reg", &val);
+		if (ret) {
+			dev_err(&pdev->dev, "of_probe: reg error(%d)\n", ret);
+			goto err;
+		}
+		ep->index = val;
+
+		ret = of_property_read_u32(pp, "atmel,fifo-size", &val);
+		if (ret) {
+			dev_err(&pdev->dev, "of_probe: fifo-size error(%d)\n", ret);
+			goto err;
+		}
+		ep->fifo_size = val;
+
+		ret = of_property_read_u32(pp, "atmel,nb-banks", &val);
+		if (ret) {
+			dev_err(&pdev->dev, "of_probe: nb-banks error(%d)\n", ret);
+			goto err;
+		}
+		ep->nr_banks = val;
+
+		ep->can_dma = of_property_read_bool(pp, "atmel,can-dma");
+		ep->can_isoc = of_property_read_bool(pp, "atmel,can-isoc");
+
+		ret = of_property_read_string(pp, "name", &name);
+		ep->ep.name = name;
+
+		ep->ep_regs = udc->regs + USBA_EPT_BASE(i);
+		ep->dma_regs = udc->regs + USBA_DMA_BASE(i);
+		ep->fifo = udc->fifo + USBA_FIFO_BASE(i);
+		ep->ep.ops = &usba_ep_ops;
+		ep->ep.maxpacket = ep->fifo_size;
+		ep->udc = udc;
+		INIT_LIST_HEAD(&ep->queue);
+
+		if (i)
+			list_add_tail(&ep->ep.ep_list, &udc->gadget.ep_list);
+
+		i++;
+	}
+
+	return eps;
+err:
+	return ERR_PTR(ret);
+}
+#else
+static struct usba_ep * __devinit atmel_udc_of_init(struct platform_device *pdev,
+						    struct usba_udc *udc)
+{
+	return ERR_PTR(-ENOSYS);
+}
+#endif
+
+static struct usba_ep * __devinit usba_udc_pdata(struct platform_device *pdev,
+						 struct usba_udc *udc)
 {
 	struct usba_platform_data *pdata = pdev->dev.platform_data;
+	struct usba_ep *eps;
+	int i;
+
+	if (!pdata)
+		return ERR_PTR(-ENXIO);
+
+	eps = devm_kzalloc(&pdev->dev, sizeof(struct usba_ep) * pdata->num_ep,
+			   GFP_KERNEL);
+	if (!eps)
+		return ERR_PTR(-ENOMEM);
+
+	udc->gadget.ep0 = &eps[0].ep;
+
+	udc->vbus_pin = pdata->vbus_pin;
+	udc->vbus_pin_inverted = pdata->vbus_pin_inverted;
+	udc->num_ep = pdata->num_ep;
+
+	INIT_LIST_HEAD(&eps[0].ep.ep_list);
+
+	for (i = 0; i < pdata->num_ep; i++) {
+		struct usba_ep *ep = &eps[i];
+
+		ep->ep_regs = udc->regs + USBA_EPT_BASE(i);
+		ep->dma_regs = udc->regs + USBA_DMA_BASE(i);
+		ep->fifo = udc->fifo + USBA_FIFO_BASE(i);
+		ep->ep.ops = &usba_ep_ops;
+		ep->ep.name = pdata->ep[i].name;
+		ep->fifo_size = ep->ep.maxpacket = pdata->ep[i].fifo_size;
+		ep->udc = udc;
+		INIT_LIST_HEAD(&ep->queue);
+		ep->nr_banks = pdata->ep[i].nr_banks;
+		ep->index = pdata->ep[i].index;
+		ep->can_dma = pdata->ep[i].can_dma;
+		ep->can_isoc = pdata->ep[i].can_isoc;
+
+		if (i)
+			list_add_tail(&ep->ep.ep_list, &udc->gadget.ep_list);
+	}
+
+	return eps;
+}
+
+static int __init usba_udc_probe(struct platform_device *pdev)
+{
 	struct resource *regs, *fifo;
 	struct clk *pclk, *hclk;
 	struct usba_udc *udc = &the_udc;
@@ -1895,7 +2031,7 @@ static int __init usba_udc_probe(struct platform_device *pdev)
 
 	regs = platform_get_resource(pdev, IORESOURCE_MEM, CTRL_IOMEM_ID);
 	fifo = platform_get_resource(pdev, IORESOURCE_MEM, FIFO_IOMEM_ID);
-	if (!regs || !fifo || !pdata)
+	if (!regs || !fifo)
 		return -ENXIO;
 
 	irq = platform_get_irq(pdev, 0);
@@ -1945,46 +2081,14 @@ static int __init usba_udc_probe(struct platform_device *pdev)
 	usba_writel(udc, CTRL, USBA_DISABLE_MASK);
 	clk_disable(pclk);
 
-	usba_ep = kzalloc(sizeof(struct usba_ep) * pdata->num_ep,
-			  GFP_KERNEL);
-	if (!usba_ep)
-		goto err_alloc_ep;
-
-	the_udc.gadget.ep0 = &usba_ep[0].ep;
-
-	INIT_LIST_HEAD(&usba_ep[0].ep.ep_list);
-	usba_ep[0].ep_regs = udc->regs + USBA_EPT_BASE(0);
-	usba_ep[0].dma_regs = udc->regs + USBA_DMA_BASE(0);
-	usba_ep[0].fifo = udc->fifo + USBA_FIFO_BASE(0);
-	usba_ep[0].ep.ops = &usba_ep_ops;
-	usba_ep[0].ep.name = pdata->ep[0].name;
-	usba_ep[0].ep.maxpacket = pdata->ep[0].fifo_size;
-	usba_ep[0].udc = &the_udc;
-	INIT_LIST_HEAD(&usba_ep[0].queue);
-	usba_ep[0].fifo_size = pdata->ep[0].fifo_size;
-	usba_ep[0].nr_banks = pdata->ep[0].nr_banks;
-	usba_ep[0].index = pdata->ep[0].index;
-	usba_ep[0].can_dma = pdata->ep[0].can_dma;
-	usba_ep[0].can_isoc = pdata->ep[0].can_isoc;
-
-	for (i = 1; i < pdata->num_ep; i++) {
-		struct usba_ep *ep = &usba_ep[i];
-
-		ep->ep_regs = udc->regs + USBA_EPT_BASE(i);
-		ep->dma_regs = udc->regs + USBA_DMA_BASE(i);
-		ep->fifo = udc->fifo + USBA_FIFO_BASE(i);
-		ep->ep.ops = &usba_ep_ops;
-		ep->ep.name = pdata->ep[i].name;
-		ep->ep.maxpacket = pdata->ep[i].fifo_size;
-		ep->udc = &the_udc;
-		INIT_LIST_HEAD(&ep->queue);
-		ep->fifo_size = pdata->ep[i].fifo_size;
-		ep->nr_banks = pdata->ep[i].nr_banks;
-		ep->index = pdata->ep[i].index;
-		ep->can_dma = pdata->ep[i].can_dma;
-		ep->can_isoc = pdata->ep[i].can_isoc;
+	if (pdev->dev.of_node)
+		usba_ep = atmel_udc_of_init(pdev, udc);
+	else
+		usba_ep = usba_udc_pdata(pdev, udc);
 
-		list_add_tail(&ep->ep.ep_list, &udc->gadget.ep_list);
+	if (IS_ERR(usba_ep)) {
+		ret = PTR_ERR(usba_ep);
+		goto err_alloc_ep;
 	}
 
 	ret = request_irq(irq, usba_udc_irq, 0, "atmel_usba_udc", udc);
@@ -2001,10 +2105,8 @@ static int __init usba_udc_probe(struct platform_device *pdev)
 		goto err_device_add;
 	}
 
-	if (gpio_is_valid(pdata->vbus_pin)) {
-		if (!gpio_request(pdata->vbus_pin, "atmel_usba_udc")) {
-			udc->vbus_pin = pdata->vbus_pin;
-			udc->vbus_pin_inverted = pdata->vbus_pin_inverted;
+	if (gpio_is_valid(udc->vbus_pin)) {
+		if (!gpio_request(udc->vbus_pin, "atmel_usba_udc")) {
 
 			ret = request_irq(gpio_to_irq(udc->vbus_pin),
 					usba_vbus_irq, 0,
@@ -2029,13 +2131,13 @@ static int __init usba_udc_probe(struct platform_device *pdev)
 		goto err_add_udc;
 
 	usba_init_debugfs(udc);
-	for (i = 1; i < pdata->num_ep; i++)
+	for (i = 1; i < udc->num_ep; i++)
 		usba_ep_init_debugfs(udc, &usba_ep[i]);
 
 	return 0;
 
 err_add_udc:
-	if (gpio_is_valid(pdata->vbus_pin)) {
+	if (gpio_is_valid(udc->vbus_pin)) {
 		free_irq(gpio_to_irq(udc->vbus_pin), udc);
 		gpio_free(udc->vbus_pin);
 	}
@@ -2064,13 +2166,12 @@ static int __exit usba_udc_remove(struct platform_device *pdev)
 {
 	struct usba_udc *udc;
 	int i;
-	struct usba_platform_data *pdata = pdev->dev.platform_data;
 
 	udc = platform_get_drvdata(pdev);
 
 	usb_del_gadget_udc(&udc->gadget);
 
-	for (i = 1; i < pdata->num_ep; i++)
+	for (i = 1; i < udc->num_ep; i++)
 		usba_ep_cleanup_debugfs(&usba_ep[i]);
 	usba_cleanup_debugfs(udc);
 
@@ -2091,11 +2192,21 @@ static int __exit usba_udc_remove(struct platform_device *pdev)
 	return 0;
 }
 
+#if defined(CONFIG_OF)
+static const struct of_device_id atmel_udc_dt_ids[] = {
+	{ .compatible = "atmel,at91sam9rl-udc" },
+	{ /* sentinel */ }
+};
+
+MODULE_DEVICE_TABLE(of, atmel_udc_dt_ids);
+#endif
+
 static struct platform_driver udc_driver = {
 	.remove		= __exit_p(usba_udc_remove),
 	.driver		= {
 		.name		= "atmel_usba_udc",
 		.owner		= THIS_MODULE,
+		.of_match_table	= of_match_ptr(atmel_udc_dt_ids),
 	},
 };
 
drivers/usb/gadget/atmel_usba_udc.h +1 -0
index 88a2e07..2c068e7 100644
@@ -324,6 +324,7 @@ struct usba_udc {
 	int irq;
 	int vbus_pin;
 	int vbus_pin_inverted;
+	int num_ep;
 	struct clk *pclk;
 	struct clk *hclk;
 
Signature · 1 line
1.7.7

_______________________________________________
devicetree-discuss mailing list
devicetree-discuss at lists.ozlabs.org
https://lists.ozlabs.org/listinfo/devicetree-discuss

#14 lore raw

PATCH v2 7/9 usb: add Atmel USBA UDC DT support

Quoted 5 lines · Jean-Christophe PLAGNIOL-VILLARD
Quoted 3 lines · Jean-Christophe PLAGNIOL-VILLARD

Hi,

except the boolean that I need to update is it ok?

Grant is it ok?

Grant re-ping

Best Regards,
J.

#15 lore raw

PATCH v2 8/9 ARM: at91: sam9g45 add udc DT support

In reply to Jean-Christophe PLAGNIOL-VILLARD
---
 arch/arm/boot/dts/at91sam9g45.dtsi     |   66 ++++++++++++++++++++++++++++++++
 arch/arm/boot/dts/at91sam9m10g45ek.dts |    5 ++
 arch/arm/mach-at91/at91sam9g45.c       |    2 +
 3 files changed, 73 insertions(+), 0 deletions(-)
arch/arm/boot/dts/at91sam9g45.dtsi +66 -0
index 4b54424..98407c7 100644
@@ -179,6 +179,72 @@
 				interrupts = <25 4>;
 				status = "disabled";
 			};
+
+			usb2: gadget at fff78000 {
+				#address-cells = <1>;
+				#size-cells = <0>;
+				compatible = "atmel,at91sam9rl-udc";
+				reg = <0x00600000 0x80000
+				       0xfff78000 0x400>;
+				interrupts = <27 4>;
+				status = "disabled";
+
+				ep0 {
+					reg = <0>;
+					atmel,fifo-size = <64>;
+					atmel,nb-banks = <1>;
+					atmel,can-dma = <0>;
+					atmel,can-isoc = <0>;
+				};
+
+				ep1 {
+					reg = <1>;
+					atmel,fifo-size = <1024>;
+					atmel,nb-banks = <2>;
+					atmel,can-dma = <1>;
+					atmel,can-isoc = <1>;
+				};
+
+				ep2 {
+					reg = <2>;
+					atmel,fifo-size = <1024>;
+					atmel,nb-banks = <2>;
+					atmel,can-dma = <1>;
+					atmel,can-isoc = <1>;
+				};
+
+				ep3 {
+					reg = <3>;
+					atmel,fifo-size = <1024>;
+					atmel,nb-banks = <3>;
+					atmel,can-dma = <1>;
+					atmel,can-isoc = <0>;
+				};
+
+				ep4 {
+					reg = <4>;
+					atmel,fifo-size = <1024>;
+					atmel,nb-banks = <3>;
+					atmel,can-dma = <1>;
+					atmel,can-isoc = <0>;
+				};
+
+				ep5 {
+					reg = <5>;
+					atmel,fifo-size = <1024>;
+					atmel,nb-banks = <3>;
+					atmel,can-dma = <1>;
+					atmel,can-isoc = <1>;
+				};
+
+				ep6 {
+					reg = <6>;
+					atmel,fifo-size = <1024>;
+					atmel,nb-banks = <3>;
+					atmel,can-dma = <1>;
+					atmel,can-isoc = <1>;
+				};
+			};
 		};
 
 		nand0: nand at 40000000 {
arch/arm/boot/dts/at91sam9m10g45ek.dts +5 -0
index 4b1eb36..6dd2044 100644
@@ -35,6 +35,11 @@
 				phy-mode = "rmii";
 				status = "okay";
 			};
+
+			usb2: gadget at fff78000 {
+				atmel,vbus-gpio = <&pioB 19 0>;
+				status = "okay";
+			};
 		};
 
 		nand0: nand at 40000000 {
arch/arm/mach-at91/at91sam9g45.c +2 -0
index df3bcea..da80f0c 100644
@@ -234,6 +234,8 @@ static struct clk_lookup periph_clocks_lookups[] = {
 	CLKDEV_CON_DEV_ID("t0_clk", "fffd4000.timer", &tcb0_clk),
 	CLKDEV_CON_DEV_ID("hclk", "700000.ohci", &uhphs_clk),
 	CLKDEV_CON_DEV_ID("ehci_clk", "800000.ehci", &uhphs_clk),
+	CLKDEV_CON_DEV_ID("hclk", "600000.gadget", &utmi_clk),
+	CLKDEV_CON_DEV_ID("pclk", "600000.gadget", &udphs_clk),
 	/* fake hclk clock */
 	CLKDEV_CON_DEV_ID("hclk", "at91_ohci", &uhphs_clk),
 	CLKDEV_CON_ID("pioA", &pioA_clk),
Signature · 1 line
1.7.7
#16 lore raw

PATCH v2 9/9 ARM: at91: sam9x5 add udc DT support

In reply to Jean-Christophe PLAGNIOL-VILLARD
---
 arch/arm/boot/dts/at91sam9g25ek.dts |    5 +++
 arch/arm/boot/dts/at91sam9x5.dtsi   |   67 +++++++++++++++++++++++++++++++++++
 arch/arm/mach-at91/at91sam9x5.c     |    2 +
 3 files changed, 74 insertions(+), 0 deletions(-)
arch/arm/boot/dts/at91sam9g25ek.dts +5 -0
index ac0dc00..8e949d3 100644
@@ -32,6 +32,11 @@
 				phy-mode = "rmii";
 				status = "okay";
 			};
+
+			usb2: gadget at f803c000 {
+				atmel,vbus-gpio = <&pioB 16 0>;
+				status = "okay";
+			};
 		};
 
 		usb0: ohci at 00600000 {
arch/arm/boot/dts/at91sam9x5.dtsi +67 -0

73 lines not on this page · raw message

arch/arm/mach-at91/at91sam9x5.c +2 -0
index 7333276..66f2cb5 100644
@@ -233,6 +233,8 @@ static struct clk_lookup periph_clocks_lookups[] = {
 	CLKDEV_CON_DEV_ID("hclk", "600000.ohci", &uhphs_clk),
 	CLKDEV_CON_DEV_ID("ohci_clk", "600000.ohci", &uhphs_clk),
 	CLKDEV_CON_DEV_ID("ehci_clk", "700000.ehci", &uhphs_clk),
+	CLKDEV_CON_DEV_ID("hclk", "500000.gadget", &utmi_clk),
+	CLKDEV_CON_DEV_ID("pclk", "500000.gadget", &udphs_clk),
 };
 
 /*
Signature · 1 line
1.7.7