[PATCH/RFC] gadget: extend fsl_usb2_udc.c to support i.MX31

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



MPC8313 / MPC8349 PPC SoCs and i.MX31 ARM SoCs use the same USB device 
core, extend the driver to support i.MX31. We just have to disable using 
usb_sys_interface and add clock management.

Signed-off-by: Guennadi Liakhovetski <lg@xxxxxxx>
---

Ok, it does indeed seem to work - tested with g-ether and g-file-storage, 
but my gadgetfs PTP driver (yes, it should be released as open source, 
stay tunes) doesn't work with it. Namely, I'm using pieces from the usb.c 
gadgetfs example, and it generates a random 64-character (128 UCS-2LE byte 
long) string for use as a serial number. And it is this string that cannot 
be transfered. 32-character doesn't work either, only if I reduce it to 
16-character (I guess, data+header should fit in 64-byte packet?), then it 
works. With the Freescale arcotg driver 128-character works too. Any idea 
what the problem is?

diff --git a/drivers/usb/gadget/Kconfig b/drivers/usb/gadget/Kconfig
index 93dbd70..6bcb64c 100644
--- a/drivers/usb/gadget/Kconfig
+++ b/drivers/usb/gadget/Kconfig
@@ -156,7 +156,7 @@ config USB_ATMEL_USBA
 
 config USB_GADGET_FSL_USB2
 	boolean "Freescale Highspeed USB DR Peripheral Controller"
-	depends on FSL_SOC
+	depends on FSL_SOC || ARCH_MXC
 	select USB_GADGET_DUALSPEED
 	help
 	   Some of Freescale PowerPC processors have a High Speed
diff --git a/drivers/usb/gadget/fsl_usb2_udc.c b/drivers/usb/gadget/fsl_usb2_udc.c
index f3c6703..f6b95a1 100644
--- a/drivers/usb/gadget/fsl_usb2_udc.c
+++ b/drivers/usb/gadget/fsl_usb2_udc.c
@@ -38,6 +38,8 @@
 #include <linux/platform_device.h>
 #include <linux/fsl_devices.h>
 #include <linux/dmapool.h>
+#include <linux/delay.h>
+#include <linux/clk.h>
 
 #include <asm/byteorder.h>
 #include <asm/io.h>
@@ -57,7 +59,9 @@ static const char driver_name[] = "fsl-usb2-udc";
 static const char driver_desc[] = DRIVER_DESC;
 
 static struct usb_dr_device *dr_regs;
+#ifndef CONFIG_ARCH_MXC
 static struct usb_sys_interface *usb_sys_regs;
+#endif
 
 /* it is initialized in probe()  */
 static struct fsl_udc *udc_controller = NULL;
@@ -237,9 +241,11 @@ static int dr_controller_setup(struct fsl_udc *udc)
 	fsl_writel(portctrl, &dr_regs->portsc1);
 
 	/* Config control enable i/o output, cpu endian register */
+#ifndef CONFIG_ARCH_MXC
 	ctrl = __raw_readl(&usb_sys_regs->control);
 	ctrl |= USB_CTRL_IOENB;
 	__raw_writel(ctrl, &usb_sys_regs->control);
+#endif
 
 #if defined(CONFIG_PPC32) && !defined(CONFIG_NOT_COHERENT_CACHE)
 	/* Turn on cache snooping hardware, since some PowerPC platforms
@@ -2038,6 +2044,7 @@ static int fsl_proc_read(char *page, char **start, off_t off, int count,
 	size -= t;
 	next += t;
 
+#ifndef CONFIG_ARCH_MXC
 	tmp_reg = usb_sys_regs->snoop1;
 	t = scnprintf(next, size, "Snoop1 Reg : = [0x%x]\n\n", tmp_reg);
 	size -= t;
@@ -2048,6 +2055,7 @@ static int fsl_proc_read(char *page, char **start, off_t off, int count,
 			tmp_reg);
 	size -= t;
 	next += t;
+#endif
 
 	/* ------fsl_udc, fsl_ep, fsl_request structure information ----- */
 	ep = &udc->eps[0];
@@ -2220,6 +2228,61 @@ static int __init struct_ep_setup(struct fsl_udc *udc, unsigned char index,
 	return 0;
 }
 
+#ifdef CONFIG_ARCH_MXC
+static struct clk *mxc_ahb_clk;
+static struct clk *mxc_usb_clk;
+
+static int mxc_udc_init(struct platform_device *pdev)
+{
+	struct fsl_usb2_platform_data *pdata;
+	unsigned long freq;
+	int ret;
+
+	pdata = pdev->dev.platform_data;
+
+	mxc_ahb_clk = clk_get(NULL, "usb_ahb_clk");
+	if (IS_ERR(mxc_ahb_clk))
+		return PTR_ERR(mxc_ahb_clk);
+
+	ret = clk_enable(mxc_ahb_clk);
+	if (ret < 0) {
+		dev_err(&pdev->dev, "clk_enable(\"usb_ahb_clk\") failed\n");
+		goto eenahb;
+	}
+
+	/* make sure USB_CLK is running at 60 MHz +/- 1000 Hz */
+	mxc_usb_clk = clk_get(NULL, "usb_clk");
+	if (IS_ERR(mxc_usb_clk)) {
+		dev_err(&pdev->dev, "clk_get(\"usb_usb_clk\") failed\n");
+		ret = PTR_ERR(mxc_usb_clk);
+		goto egusb;
+	}
+
+	freq = clk_get_rate(mxc_usb_clk);
+	if ((freq < 59999000) || (freq > 60001000))
+		dev_warn(&pdev->dev, "USB_CLK=%lu, should be 60MHz\n", freq);
+
+	/* Turn off the usbpll for ulpi transceivers */
+	if (pdata->phy_mode != FSL_USB2_PHY_ULPI) {
+		ret = clk_enable(mxc_usb_clk);
+		if (ret < 0) {
+			dev_err(&pdev->dev, "clk_enable(\"usb_clk\") failed\n");
+			goto eenusb;;
+		}
+	}
+
+	return 0;
+
+eenusb:
+	clk_put(mxc_usb_clk);
+egusb:
+	clk_disable(mxc_ahb_clk);
+eenahb:
+	clk_put(mxc_ahb_clk);
+	return ret;
+}
+#endif
+
 /* Driver probe function
  * all intialization operations implemented here except enabling usb_intr reg
  * board setup should have been done in the platform code
@@ -2258,14 +2323,21 @@ static int __init fsl_udc_probe(struct platform_device *pdev)
 		goto err_kfree;
 	}
 
-	dr_regs = ioremap(res->start, res->end - res->start + 1);
+	dr_regs = ioremap(res->start, resource_size(res));
 	if (!dr_regs) {
 		ret = -ENOMEM;
 		goto err_release_mem_region;
 	}
 
+#ifndef CONFIG_ARCH_MXC
 	usb_sys_regs = (struct usb_sys_interface *)
 			((u32)dr_regs + USB_DR_SYS_OFFSET);
+#else
+	/* Initialize USB clocks */
+	ret = mxc_udc_init(pdev);
+	if (ret < 0)
+		goto err_iounmap_noclk;
+#endif
 
 	/* Read Device Controller Capability Parameters register */
 	dccparams = fsl_readl(&dr_regs->dccparams);
@@ -2357,6 +2429,15 @@ err_unregister:
 err_free_irq:
 	free_irq(udc_controller->irq, udc_controller);
 err_iounmap:
+#ifdef CONFIG_ARCH_MXC
+	if (mxc_usb_clk) {
+		clk_disable(mxc_usb_clk);
+		clk_put(mxc_usb_clk);
+	}
+	clk_disable(mxc_ahb_clk);
+	clk_put(mxc_ahb_clk);
+err_iounmap_noclk:
+#endif
 	iounmap(dr_regs);
 err_release_mem_region:
 	release_mem_region(res->start, res->end - res->start + 1);
@@ -2379,6 +2460,15 @@ static int __exit fsl_udc_remove(struct platform_device *pdev)
 		return -ENODEV;
 	udc_controller->done = &done;
 
+#ifdef CONFIG_ARCH_MXC
+	if (mxc_usb_clk) {
+		clk_disable(mxc_usb_clk);
+		clk_put(mxc_usb_clk);
+	}
+	clk_disable(mxc_ahb_clk);
+	clk_put(mxc_ahb_clk);
+#endif
+
 	/* DR has been stopped in usb_gadget_unregister_driver() */
 	remove_proc_file();
 
--
To unsubscribe from this list: send the line "unsubscribe linux-usb" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at  http://vger.kernel.org/majordomo-info.html

[Index of Archives]     [Linux Media]     [Linux Input]     [Linux Audio Users]     [Yosemite News]     [Linux Kernel]     [Linux SCSI]     [Old Linux USB Devel Archive]

  Powered by Linux