AT91: Move non-portable processor-specific code out of USB Gadget drivers

Andrew Victor avictor.za at gmail.com
Mon May 2 18:00:08 EDT 2011


For supporting multiple AT91 processors in a single kernel image, the
address of system-peripherals cannot be determined at compile-time.
Therefore we need to remove calls to the at91_sys_read/at91_sys_write
macro's and any "#ifdef CONFIG_ARCH_AT91xxx" code.

In the USB Gadget subsystems there are 2 instances:
 * controlling the pullup for the AT91SAM9261.
 * controlling the bias for the AT91SAM9RL.

The following patch add a "pullup" method to the "struct at91_udc_data"
platform-data, and a "set_bias" method to the "struct
usba_platform_data".  The code for the two instances above is moved from
the drivers and into the processor-specific code.  The driver's access
the code via the methods provided in the platform_data.

Signed-off-by: Andrew Victor <linux at maxim.org.za>

 arch/arm/mach-at91/at91sam9261_devices.c |   12 ++++++++++
 arch/arm/mach-at91/at91sam9rl_devices.c  |   12 ++++++++++
 arch/arm/mach-at91/include/mach/board.h  |    1 
 drivers/usb/gadget/at91_udc.c            |   18 +++------------
 drivers/usb/gadget/atmel_usba_udc.c      |   37 +++++++++----------------------
 drivers/usb/gadget/atmel_usba_udc.h      |    1 
 include/linux/usb/atmel_usba_udc.h       |    1 
 7 files changed, 42 insertions(+), 40 deletions(-)


diff --git a/arch/arm/mach-at91/at91sam9261_devices.c b/arch/arm/mach-at91/at91sam9261_devices.c
index dc8bfc3..5614347 100644
--- a/arch/arm/mach-at91/at91sam9261_devices.c
+++ b/arch/arm/mach-at91/at91sam9261_devices.c
@@ -80,6 +80,17 @@ void __init at91_add_device_usbh(struct at91_usbh_data *data) {}
  * -------------------------------------------------------------------- */
 
 #ifdef CONFIG_USB_GADGET_AT91
+
+static void at91sam9261_udc_pullup(int on)
+{
+	u32 usbpucr = at91_sys_read(AT91_MATRIX_USBPUCR);
+
+	if (on)
+		at91_sys_write(AT91_MATRIX_USBPUCR, usbpucr | AT91_MATRIX_USBPUCR_PUON);
+	else
+		at91_sys_write(AT91_MATRIX_USBPUCR, usbpucr & ~AT91_MATRIX_USBPUCR_PUON);
+}
+
 static struct at91_udc_data udc_data;
 
 static struct resource udc_resources[] = {
@@ -116,6 +127,7 @@ void __init at91_add_device_udc(struct at91_udc_data *data)
 	}
 
 	/* Pullup pin is handled internally by USB device peripheral */
+	data->pullup = at91sam9261_udc_pullup;
 
 	udc_data = *data;
 	platform_device_register(&at91sam9261_udc_device);
diff --git a/arch/arm/mach-at91/at91sam9rl_devices.c b/arch/arm/mach-at91/at91sam9rl_devices.c
index ee013c1..2464ef4 100644
--- a/arch/arm/mach-at91/at91sam9rl_devices.c
+++ b/arch/arm/mach-at91/at91sam9rl_devices.c
@@ -22,6 +22,7 @@
 #include <mach/at91sam9rl_matrix.h>
 #include <mach/at91sam9_smc.h>
 #include <mach/at_hdmac.h>
+#include <mach/at91_pmc.h>
 
 #include "generic.h"
 
@@ -77,6 +78,16 @@ void __init at91_add_device_hdmac(void) {}
 
 #if defined(CONFIG_USB_GADGET_ATMEL_USBA) || defined(CONFIG_USB_GADGET_ATMEL_USBA_MODULE)
 
+static void at91sam9rl_udc_bias(int on)
+{
+	unsigned int uckr = __raw_readl(AT91SAM9RL_PMC + AT91_CKGR_UCKR);
+
+	if (on)
+		__raw_writel(uckr | AT91_PMC_BIASEN, AT91SAM9RL_PMC + AT91_CKGR_UCKR);
+	else
+		__raw_writel(uckr & ~(AT91_PMC_BIASEN), AT91SAM9RL_PMC + AT91_CKGR_UCKR);
+}
+
 static struct resource usba_udc_resources[] = {
 	[0] = {
 		.start	= AT91SAM9RL_UDPHS_FIFO,
@@ -154,6 +165,7 @@ void __init at91_add_device_usba(struct usba_platform_data *data)
 	}
 
 	/* Pullup pin is handled internally by USB device peripheral */
+	usba_udc_data.pdata.set_bias = at91sam9rl_udc_bias;
 
 	/* Clocks */
 	at91_clock_associate("utmi_clk", &at91_usba_udc_device.dev, "hclk");
diff --git a/arch/arm/mach-at91/include/mach/board.h b/arch/arm/mach-at91/include/mach/board.h
index 2b499eb..918826e 100644
--- a/arch/arm/mach-at91/include/mach/board.h
+++ b/arch/arm/mach-at91/include/mach/board.h
@@ -48,6 +48,7 @@ struct at91_udc_data {
 	u8	vbus_polled;		/* Use polling, not interrupt */
 	u8	pullup_pin;		/* active == D+ pulled up */
 	u8	pullup_active_low;	/* true == pullup_pin is active low */
+	void	(*pullup)(int on);	/* external pullup control */
 };
 extern void __init at91_add_device_udc(struct at91_udc_data *data);
 
diff --git a/drivers/usb/gadget/at91_udc.c b/drivers/usb/gadget/at91_udc.c
index 9b7cdb1..3e85969 100644
--- a/drivers/usb/gadget/at91_udc.c
+++ b/drivers/usb/gadget/at91_udc.c
@@ -915,13 +915,8 @@ static void pullup(struct at91_udc *udc, int is_on)
 
 			txvc |= AT91_UDP_TXVC_PUON;
 			at91_udp_write(udc, AT91_UDP_TXVC, txvc);
-		} else if (cpu_is_at91sam9261() || cpu_is_at91sam9g10()) {
-			u32	usbpucr;
-
-			usbpucr = at91_sys_read(AT91_MATRIX_USBPUCR);
-			usbpucr |= AT91_MATRIX_USBPUCR_PUON;
-			at91_sys_write(AT91_MATRIX_USBPUCR, usbpucr);
-		}
+		} else if (udc->board.pullup)
+			(udc->board.pullup)(is_on);
 	} else {
 		stop_activity(udc);
 		at91_udp_write(udc, AT91_UDP_IDR, AT91_UDP_RXRSM);
@@ -933,13 +928,8 @@ static void pullup(struct at91_udc *udc, int is_on)
 
 			txvc &= ~AT91_UDP_TXVC_PUON;
 			at91_udp_write(udc, AT91_UDP_TXVC, txvc);
-		} else if (cpu_is_at91sam9261() || cpu_is_at91sam9g10()) {
-			u32	usbpucr;
-
-			usbpucr = at91_sys_read(AT91_MATRIX_USBPUCR);
-			usbpucr &= ~AT91_MATRIX_USBPUCR_PUON;
-			at91_sys_write(AT91_MATRIX_USBPUCR, usbpucr);
-		}
+		} else if (udc->board.pullup)
+			(udc->board.pullup)(is_on);
 		clk_off(udc);
 	}
 }
diff --git a/drivers/usb/gadget/atmel_usba_udc.c b/drivers/usb/gadget/atmel_usba_udc.c
index c137b99..377b090 100644
--- a/drivers/usb/gadget/atmel_usba_udc.c
+++ b/drivers/usb/gadget/atmel_usba_udc.c
@@ -326,28 +326,12 @@ static int vbus_is_present(struct usba_udc *udc)
 	return 1;
 }
 
-#if defined(CONFIG_ARCH_AT91SAM9RL)
-
-#include <mach/at91_pmc.h>
-
-static void toggle_bias(int is_on)
-{
-	unsigned int uckr = at91_sys_read(AT91SAM9RL_PMC + AT91_CKGR_UCKR);
-
-	if (is_on)
-		at91_sys_write(AT91SAM9RL_PMC + AT91_CKGR_UCKR, uckr | AT91_PMC_BIASEN);
-	else
-		at91_sys_write(AT91SAM9RL_PMC + AT91_CKGR_UCKR, uckr & ~(AT91_PMC_BIASEN));
-}
-
-#else
-
-static void toggle_bias(int is_on)
+static void toggle_bias(struct usba_udc *udc, int is_on)
 {
+	if (udc->set_bias)
+		(udc->set_bias)(is_on);
 }
 
-#endif /* CONFIG_ARCH_AT91SAM9RL */
-
 static void next_fifo_transaction(struct usba_ep *ep, struct usba_request *req)
 {
 	unsigned int transaction_len;
@@ -1648,7 +1632,7 @@ static irqreturn_t usba_udc_irq(int irq, void *devid)
 	DBG(DBG_INT, "irq, status=%#08x\n", status);
 
 	if (status & USBA_DET_SUSPEND) {
-		toggle_bias(0);
+		toggle_bias(udc, 0);
 		usba_writel(udc, INT_CLR, USBA_DET_SUSPEND);
 		DBG(DBG_BUS, "Suspend detected\n");
 		if (udc->gadget.speed != USB_SPEED_UNKNOWN
@@ -1660,7 +1644,7 @@ static irqreturn_t usba_udc_irq(int irq, void *devid)
 	}
 
 	if (status & USBA_WAKE_UP) {
-		toggle_bias(1);
+		toggle_bias(udc, 1);
 		usba_writel(udc, INT_CLR, USBA_WAKE_UP);
 		DBG(DBG_BUS, "Wake Up CPU detected\n");
 	}
@@ -1766,13 +1750,13 @@ static irqreturn_t usba_vbus_irq(int irq, void *devid)
 	vbus = vbus_is_present(udc);
 	if (vbus != udc->vbus_prev) {
 		if (vbus) {
-			toggle_bias(1);
+			toggle_bias(udc, 1);
 			usba_writel(udc, CTRL, USBA_ENABLE_MASK);
 			usba_writel(udc, INT_ENB, USBA_END_OF_RESET);
 		} else {
 			udc->gadget.speed = USB_SPEED_UNKNOWN;
 			reset_all_endpoints(udc);
-			toggle_bias(0);
+			toggle_bias(udc, 0);
 			usba_writel(udc, CTRL, USBA_DISABLE_MASK);
 			if (udc->driver->disconnect) {
 				spin_unlock(&udc->lock);
@@ -1829,7 +1813,7 @@ int usb_gadget_probe_driver(struct usb_gadget_driver *driver,
 	/* If Vbus is present, enable the controller and wait for reset */
 	spin_lock_irqsave(&udc->lock, flags);
 	if (vbus_is_present(udc) && udc->vbus_prev == 0) {
-		toggle_bias(1);
+		toggle_bias(udc, 1);
 		usba_writel(udc, CTRL, USBA_ENABLE_MASK);
 		usba_writel(udc, INT_ENB, USBA_END_OF_RESET);
 	}
@@ -1863,7 +1847,7 @@ int usb_gadget_unregister_driver(struct usb_gadget_driver *driver)
 	spin_unlock_irqrestore(&udc->lock, flags);
 
 	/* This will also disable the DP pullup */
-	toggle_bias(0);
+	toggle_bias(udc, 0);
 	usba_writel(udc, CTRL, USBA_DISABLE_MASK);
 
 	if (udc->driver->disconnect)
@@ -1933,12 +1917,13 @@ static int __init usba_udc_probe(struct platform_device *pdev)
 	device_initialize(&udc->gadget.dev);
 	udc->gadget.dev.parent = &pdev->dev;
 	udc->gadget.dev.dma_mask = pdev->dev.dma_mask;
+	udc->set_bias = pdata->set_bias;
 
 	platform_set_drvdata(pdev, udc);
 
 	/* Make sure we start from a clean slate */
 	clk_enable(pclk);
-	toggle_bias(0);
+	toggle_bias(udc, 0);
 	usba_writel(udc, CTRL, USBA_DISABLE_MASK);
 	clk_disable(pclk);
 
diff --git a/drivers/usb/gadget/atmel_usba_udc.h b/drivers/usb/gadget/atmel_usba_udc.h
index 88a2e07..a6ff9a7 100644
--- a/drivers/usb/gadget/atmel_usba_udc.h
+++ b/drivers/usb/gadget/atmel_usba_udc.h
@@ -324,6 +324,7 @@ struct usba_udc {
 	int irq;
 	int vbus_pin;
 	int vbus_pin_inverted;
+	void (*set_bias)(int on);
 	struct clk *pclk;
 	struct clk *hclk;
 
diff --git a/include/linux/usb/atmel_usba_udc.h b/include/linux/usb/atmel_usba_udc.h
index ba99af2..8336ae2 100644
--- a/include/linux/usb/atmel_usba_udc.h
+++ b/include/linux/usb/atmel_usba_udc.h
@@ -16,6 +16,7 @@ struct usba_ep_data {
 struct usba_platform_data {
 	int			vbus_pin;
 	int			vbus_pin_inverted;
+	void			(*set_bias)(int on);
 	int			num_ep;
 	struct usba_ep_data	ep[0];
 };





More information about the linux-arm-kernel mailing list