linuxppc-dev.lists.ozlabs.org archive mirror
 help / color / mirror / Atom feed
* [PATCH v2 0/3] Add USB Host support for MPC5121 SoC
@ 2010-09-28  9:36 Anatolij Gustschin
  2010-09-28  9:36 ` [PATCH v2 1/3] powerpc/fsl_soc.c: remove FSL USB platform code Anatolij Gustschin
                   ` (5 more replies)
  0 siblings, 6 replies; 10+ messages in thread
From: Anatolij Gustschin @ 2010-09-28  9:36 UTC (permalink / raw)
  To: linux-usb
  Cc: David Brownell, Wolfgang Denk, Detlev Zundel, Greg Kroah-Hartman,
	linuxppc-dev, Anatolij Gustschin

This is version 2 of patches to add MPC512x USB support in
mainline kernel. USB OTG support is not included in this
patch series, it will be submitted later.

The patches have been rebased on current linux-next tree
and reworked to address comments from Grant.

Anatolij Gustschin (3):
  powerpc/fsl_soc.c: remove FSL USB platform code
  USB: add of_platform glue driver for FSL USB DR controller
  USB: add USB EHCI support for MPC5121 SoC

 Documentation/powerpc/dts-bindings/fsl/usb.txt |   22 ++
 arch/powerpc/sysdev/fsl_soc.c                  |  163 -------------
 drivers/usb/Kconfig                            |    1 +
 drivers/usb/gadget/Kconfig                     |    1 +
 drivers/usb/host/Kconfig                       |   10 +-
 drivers/usb/host/Makefile                      |    1 +
 drivers/usb/host/ehci-fsl.c                    |   99 ++++++---
 drivers/usb/host/ehci-fsl.h                    |   13 +-
 drivers/usb/host/ehci-mem.c                    |    2 +-
 drivers/usb/host/fsl-mph-dr-of.c               |  302 ++++++++++++++++++++++++
 include/linux/fsl_devices.h                    |   15 ++
 11 files changed, 434 insertions(+), 195 deletions(-)
 create mode 100644 drivers/usb/host/fsl-mph-dr-of.c

^ permalink raw reply	[flat|nested] 10+ messages in thread

* [PATCH v2 1/3] powerpc/fsl_soc.c: remove FSL USB platform code
  2010-09-28  9:36 [PATCH v2 0/3] Add USB Host support for MPC5121 SoC Anatolij Gustschin
@ 2010-09-28  9:36 ` Anatolij Gustschin
  2010-09-28 11:40   ` Anton Vorontsov
  2010-09-28  9:36 ` [PATCH v2 2/3] USB: add of_platform glue driver for FSL USB DR controller Anatolij Gustschin
                   ` (4 subsequent siblings)
  5 siblings, 1 reply; 10+ messages in thread
From: Anatolij Gustschin @ 2010-09-28  9:36 UTC (permalink / raw)
  To: linux-usb
  Cc: David Brownell, Wolfgang Denk, Detlev Zundel, Greg Kroah-Hartman,
	linuxppc-dev, Anatolij Gustschin

This removed code will be replaced by simple of_platform
driver for creation of FSL USB platform devices which is
added by next patch of the series.

Signed-off-by: Anatolij Gustschin <agust@denx.de>
Cc: Kumar Gala <galak@kernel.crashing.org>
Cc: Grant Likely <grant.likely@secretlab.ca>
---
 arch/powerpc/sysdev/fsl_soc.c |  163 -----------------------------------------
 1 files changed, 0 insertions(+), 163 deletions(-)

diff --git a/arch/powerpc/sysdev/fsl_soc.c b/arch/powerpc/sysdev/fsl_soc.c
index b91f7ac..49a51f1 100644
--- a/arch/powerpc/sysdev/fsl_soc.c
+++ b/arch/powerpc/sysdev/fsl_soc.c
@@ -209,169 +209,6 @@ static int __init of_add_fixed_phys(void)
 arch_initcall(of_add_fixed_phys);
 #endif /* CONFIG_FIXED_PHY */
 
-static enum fsl_usb2_phy_modes determine_usb_phy(const char *phy_type)
-{
-	if (!phy_type)
-		return FSL_USB2_PHY_NONE;
-	if (!strcasecmp(phy_type, "ulpi"))
-		return FSL_USB2_PHY_ULPI;
-	if (!strcasecmp(phy_type, "utmi"))
-		return FSL_USB2_PHY_UTMI;
-	if (!strcasecmp(phy_type, "utmi_wide"))
-		return FSL_USB2_PHY_UTMI_WIDE;
-	if (!strcasecmp(phy_type, "serial"))
-		return FSL_USB2_PHY_SERIAL;
-
-	return FSL_USB2_PHY_NONE;
-}
-
-static int __init fsl_usb_of_init(void)
-{
-	struct device_node *np;
-	unsigned int i = 0;
-	struct platform_device *usb_dev_mph = NULL, *usb_dev_dr_host = NULL,
-		*usb_dev_dr_client = NULL;
-	int ret;
-
-	for_each_compatible_node(np, NULL, "fsl-usb2-mph") {
-		struct resource r[2];
-		struct fsl_usb2_platform_data usb_data;
-		const unsigned char *prop = NULL;
-
-		memset(&r, 0, sizeof(r));
-		memset(&usb_data, 0, sizeof(usb_data));
-
-		ret = of_address_to_resource(np, 0, &r[0]);
-		if (ret)
-			goto err;
-
-		of_irq_to_resource(np, 0, &r[1]);
-
-		usb_dev_mph =
-		    platform_device_register_simple("fsl-ehci", i, r, 2);
-		if (IS_ERR(usb_dev_mph)) {
-			ret = PTR_ERR(usb_dev_mph);
-			goto err;
-		}
-
-		usb_dev_mph->dev.coherent_dma_mask = 0xffffffffUL;
-		usb_dev_mph->dev.dma_mask = &usb_dev_mph->dev.coherent_dma_mask;
-
-		usb_data.operating_mode = FSL_USB2_MPH_HOST;
-
-		prop = of_get_property(np, "port0", NULL);
-		if (prop)
-			usb_data.port_enables |= FSL_USB2_PORT0_ENABLED;
-
-		prop = of_get_property(np, "port1", NULL);
-		if (prop)
-			usb_data.port_enables |= FSL_USB2_PORT1_ENABLED;
-
-		prop = of_get_property(np, "phy_type", NULL);
-		usb_data.phy_mode = determine_usb_phy(prop);
-
-		ret =
-		    platform_device_add_data(usb_dev_mph, &usb_data,
-					     sizeof(struct
-						    fsl_usb2_platform_data));
-		if (ret)
-			goto unreg_mph;
-		i++;
-	}
-
-	for_each_compatible_node(np, NULL, "fsl-usb2-dr") {
-		struct resource r[2];
-		struct fsl_usb2_platform_data usb_data;
-		const unsigned char *prop = NULL;
-
-		if (!of_device_is_available(np))
-			continue;
-
-		memset(&r, 0, sizeof(r));
-		memset(&usb_data, 0, sizeof(usb_data));
-
-		ret = of_address_to_resource(np, 0, &r[0]);
-		if (ret)
-			goto unreg_mph;
-
-		of_irq_to_resource(np, 0, &r[1]);
-
-		prop = of_get_property(np, "dr_mode", NULL);
-
-		if (!prop || !strcmp(prop, "host")) {
-			usb_data.operating_mode = FSL_USB2_DR_HOST;
-			usb_dev_dr_host = platform_device_register_simple(
-					"fsl-ehci", i, r, 2);
-			if (IS_ERR(usb_dev_dr_host)) {
-				ret = PTR_ERR(usb_dev_dr_host);
-				goto err;
-			}
-		} else if (prop && !strcmp(prop, "peripheral")) {
-			usb_data.operating_mode = FSL_USB2_DR_DEVICE;
-			usb_dev_dr_client = platform_device_register_simple(
-					"fsl-usb2-udc", i, r, 2);
-			if (IS_ERR(usb_dev_dr_client)) {
-				ret = PTR_ERR(usb_dev_dr_client);
-				goto err;
-			}
-		} else if (prop && !strcmp(prop, "otg")) {
-			usb_data.operating_mode = FSL_USB2_DR_OTG;
-			usb_dev_dr_host = platform_device_register_simple(
-					"fsl-ehci", i, r, 2);
-			if (IS_ERR(usb_dev_dr_host)) {
-				ret = PTR_ERR(usb_dev_dr_host);
-				goto err;
-			}
-			usb_dev_dr_client = platform_device_register_simple(
-					"fsl-usb2-udc", i, r, 2);
-			if (IS_ERR(usb_dev_dr_client)) {
-				ret = PTR_ERR(usb_dev_dr_client);
-				goto err;
-			}
-		} else {
-			ret = -EINVAL;
-			goto err;
-		}
-
-		prop = of_get_property(np, "phy_type", NULL);
-		usb_data.phy_mode = determine_usb_phy(prop);
-
-		if (usb_dev_dr_host) {
-			usb_dev_dr_host->dev.coherent_dma_mask = 0xffffffffUL;
-			usb_dev_dr_host->dev.dma_mask = &usb_dev_dr_host->
-				dev.coherent_dma_mask;
-			if ((ret = platform_device_add_data(usb_dev_dr_host,
-						&usb_data, sizeof(struct
-						fsl_usb2_platform_data))))
-				goto unreg_dr;
-		}
-		if (usb_dev_dr_client) {
-			usb_dev_dr_client->dev.coherent_dma_mask = 0xffffffffUL;
-			usb_dev_dr_client->dev.dma_mask = &usb_dev_dr_client->
-				dev.coherent_dma_mask;
-			if ((ret = platform_device_add_data(usb_dev_dr_client,
-						&usb_data, sizeof(struct
-						fsl_usb2_platform_data))))
-				goto unreg_dr;
-		}
-		i++;
-	}
-	return 0;
-
-unreg_dr:
-	if (usb_dev_dr_host)
-		platform_device_unregister(usb_dev_dr_host);
-	if (usb_dev_dr_client)
-		platform_device_unregister(usb_dev_dr_client);
-unreg_mph:
-	if (usb_dev_mph)
-		platform_device_unregister(usb_dev_mph);
-err:
-	return ret;
-}
-
-arch_initcall(fsl_usb_of_init);
-
 #if defined(CONFIG_FSL_SOC_BOOKE) || defined(CONFIG_PPC_86xx)
 static __be32 __iomem *rstcr;
 
-- 
1.7.0.4

^ permalink raw reply related	[flat|nested] 10+ messages in thread

* [PATCH v2 2/3] USB: add of_platform glue driver for FSL USB DR controller
  2010-09-28  9:36 [PATCH v2 0/3] Add USB Host support for MPC5121 SoC Anatolij Gustschin
  2010-09-28  9:36 ` [PATCH v2 1/3] powerpc/fsl_soc.c: remove FSL USB platform code Anatolij Gustschin
@ 2010-09-28  9:36 ` Anatolij Gustschin
  2010-09-28 10:01   ` Grant Likely
  2010-09-28  9:36 ` [PATCH v2 3/3] USB: add USB EHCI support for MPC5121 SoC Anatolij Gustschin
                   ` (3 subsequent siblings)
  5 siblings, 1 reply; 10+ messages in thread
From: Anatolij Gustschin @ 2010-09-28  9:36 UTC (permalink / raw)
  To: linux-usb
  Cc: David Brownell, Wolfgang Denk, Detlev Zundel, Greg Kroah-Hartman,
	linuxppc-dev, Anatolij Gustschin

The driver creates platform devices based on the information
from USB nodes in the flat device tree. This is the replacement
for old arch fsl_soc usb code removed by the previous patch.
It uses usual of-style binding, available EHCI-HCD and UDC
drivers can be bound to the created devices. The new of-style
driver additionaly instantiates USB OTG platform device, as the
appropriate USB OTG driver will be added soon.

Signed-off-by: Anatolij Gustschin <agust@denx.de>
Cc: Kumar Gala <galak@kernel.crashing.org>
Cc: Grant Likely <grant.likely@secretlab.ca>
---
v2:
 - drop unneeded PPC_OF dependency
 - fix spelling bug in mode table and fix coding style
 - print a warning if no valid dr_mode found
 - add remove hook to unregister platform devices
   created by probe. So the driver can be unbound
 - fix OTG platform device creation order
 - drop fs_initcall, replaced by module_init() now
 - add module_exit(), MODULE_DESCRIPTION, MODULE_LICENSE

 drivers/usb/gadget/Kconfig       |    1 +
 drivers/usb/host/Kconfig         |    4 +
 drivers/usb/host/Makefile        |    1 +
 drivers/usb/host/fsl-mph-dr-of.c |  213 ++++++++++++++++++++++++++++++++++++++
 4 files changed, 219 insertions(+), 0 deletions(-)
 create mode 100644 drivers/usb/host/fsl-mph-dr-of.c

diff --git a/drivers/usb/gadget/Kconfig b/drivers/usb/gadget/Kconfig
index fab765d..0fe5bc8 100644
--- a/drivers/usb/gadget/Kconfig
+++ b/drivers/usb/gadget/Kconfig
@@ -158,6 +158,7 @@ config USB_GADGET_FSL_USB2
 	boolean "Freescale Highspeed USB DR Peripheral Controller"
 	depends on FSL_SOC || ARCH_MXC
 	select USB_GADGET_DUALSPEED
+	select USB_FSL_MPH_DR_OF
 	help
 	   Some of Freescale PowerPC processors have a High Speed
 	   Dual-Role(DR) USB controller, which supports device mode.
diff --git a/drivers/usb/host/Kconfig b/drivers/usb/host/Kconfig
index 2d926ce..f3a90b0 100644
--- a/drivers/usb/host/Kconfig
+++ b/drivers/usb/host/Kconfig
@@ -112,10 +112,14 @@ config XPS_USB_HCD_XILINX
 		support both high speed and full speed devices, or high speed
 		devices only.
 
+config USB_FSL_MPH_DR_OF
+	tristate
+
 config USB_EHCI_FSL
 	bool "Support for Freescale on-chip EHCI USB controller"
 	depends on USB_EHCI_HCD && FSL_SOC
 	select USB_EHCI_ROOT_HUB_TT
+	select USB_FSL_MPH_DR_OF
 	---help---
 	  Variation of ARC USB block used in some Freescale chips.
 
diff --git a/drivers/usb/host/Makefile b/drivers/usb/host/Makefile
index b6315aa..aacbe82 100644
--- a/drivers/usb/host/Makefile
+++ b/drivers/usb/host/Makefile
@@ -33,4 +33,5 @@ obj-$(CONFIG_USB_R8A66597_HCD)	+= r8a66597-hcd.o
 obj-$(CONFIG_USB_ISP1760_HCD)	+= isp1760.o
 obj-$(CONFIG_USB_HWA_HCD)	+= hwa-hc.o
 obj-$(CONFIG_USB_IMX21_HCD)	+= imx21-hcd.o
+obj-$(CONFIG_USB_FSL_MPH_DR_OF)	+= fsl-mph-dr-of.o
 
diff --git a/drivers/usb/host/fsl-mph-dr-of.c b/drivers/usb/host/fsl-mph-dr-of.c
new file mode 100644
index 0000000..ee8cb94
--- /dev/null
+++ b/drivers/usb/host/fsl-mph-dr-of.c
@@ -0,0 +1,213 @@
+/*
+ * Setup platform devices needed by the Freescale multi-port host
+ * and/or dual-role USB controller modules based on the description
+ * in flat device tree.
+ *
+ * This program is free software; you can redistribute  it and/or modify it
+ * under  the terms of  the GNU General  Public License as published by the
+ * Free Software Foundation;  either version 2 of the  License, or (at your
+ * option) any later version.
+ */
+
+#include <linux/kernel.h>
+#include <linux/platform_device.h>
+#include <linux/fsl_devices.h>
+#include <linux/err.h>
+#include <linux/io.h>
+#include <linux/of_platform.h>
+
+struct fsl_usb2_dev_data {
+	char *dr_mode;		/* controller mode */
+	char *drivers[3];	/* drivers to instantiate for this mode */
+	enum fsl_usb2_operating_modes op_mode;	/* operating mode */
+};
+
+struct fsl_usb2_dev_data dr_mode_data[] __devinitdata = {
+	{
+		.dr_mode = "host",
+		.drivers = { "fsl-ehci", NULL, NULL, },
+		.op_mode = FSL_USB2_DR_HOST,
+	},
+	{
+		.dr_mode = "otg",
+		.drivers = { "fsl-usb2-otg", "fsl-ehci", "fsl-usb2-udc", },
+		.op_mode = FSL_USB2_DR_OTG,
+	},
+	{
+		.dr_mode = "peripheral",
+		.drivers = { "fsl-usb2-udc", NULL, NULL, },
+		.op_mode = FSL_USB2_DR_DEVICE,
+	},
+};
+
+struct fsl_usb2_dev_data * __devinit get_dr_mode_data(struct device_node *np)
+{
+	const unsigned char *prop;
+	int i;
+
+	prop = of_get_property(np, "dr_mode", NULL);
+	if (prop) {
+		for (i = 0; i < ARRAY_SIZE(dr_mode_data); i++) {
+			if (!strcmp(prop, dr_mode_data[i].dr_mode))
+				return &dr_mode_data[i];
+		}
+	}
+	pr_warn("%s: Invalid 'dr_mode' property, fallback to host mode\n",
+		np->full_name);
+	return &dr_mode_data[0]; /* mode not specified, use host */
+}
+
+static enum fsl_usb2_phy_modes __devinit determine_usb_phy(const char *phy_type)
+{
+	if (!phy_type)
+		return FSL_USB2_PHY_NONE;
+	if (!strcasecmp(phy_type, "ulpi"))
+		return FSL_USB2_PHY_ULPI;
+	if (!strcasecmp(phy_type, "utmi"))
+		return FSL_USB2_PHY_UTMI;
+	if (!strcasecmp(phy_type, "utmi_wide"))
+		return FSL_USB2_PHY_UTMI_WIDE;
+	if (!strcasecmp(phy_type, "serial"))
+		return FSL_USB2_PHY_SERIAL;
+
+	return FSL_USB2_PHY_NONE;
+}
+
+struct platform_device * __devinit fsl_usb2_device_register(
+					struct platform_device *ofdev,
+					struct fsl_usb2_platform_data *pdata,
+					const char *name, int id)
+{
+	struct platform_device *pdev;
+	const struct resource *res = ofdev->resource;
+	unsigned int num = ofdev->num_resources;
+	int retval;
+
+	pdev = platform_device_alloc(name, id);
+	if (!pdev) {
+		retval = -ENOMEM;
+		goto error;
+	}
+
+	pdev->dev.parent = &ofdev->dev;
+
+	pdev->dev.coherent_dma_mask = ofdev->dev.coherent_dma_mask;
+	pdev->dev.dma_mask = &pdev->archdata.dma_mask;
+	*pdev->dev.dma_mask = *ofdev->dev.dma_mask;
+
+	retval = platform_device_add_data(pdev, pdata, sizeof(*pdata));
+	if (retval)
+		goto error;
+
+	if (num) {
+		retval = platform_device_add_resources(pdev, res, num);
+		if (retval)
+			goto error;
+	}
+
+	retval = platform_device_add(pdev);
+	if (retval)
+		goto error;
+
+	return pdev;
+
+error:
+	platform_device_put(pdev);
+	return ERR_PTR(retval);
+}
+
+static int __devinit fsl_usb2_mph_dr_of_probe(struct platform_device *ofdev,
+					   const struct of_device_id *match)
+{
+	struct device_node *np = ofdev->dev.of_node;
+	struct platform_device *usb_dev;
+	struct fsl_usb2_platform_data data, *pdata;
+	struct fsl_usb2_dev_data *dev_data;
+	const unsigned char *prop;
+	static unsigned int idx;
+	int i;
+
+	if (!of_device_is_available(np))
+		return -ENODEV;
+
+	pdata = match->data;
+	if (!pdata) {
+		memset(&data, 0, sizeof(data));
+		pdata = &data;
+	}
+
+	dev_data = get_dr_mode_data(np);
+
+	if (of_device_is_compatible(np, "fsl-usb2-mph")) {
+		if (of_get_property(np, "port0", NULL))
+			pdata->port_enables |= FSL_USB2_PORT0_ENABLED;
+
+		if (of_get_property(np, "port1", NULL))
+			pdata->port_enables |= FSL_USB2_PORT1_ENABLED;
+
+		pdata->operating_mode = FSL_USB2_MPH_HOST;
+	} else {
+		/* setup mode selected in the device tree */
+		pdata->operating_mode = dev_data->op_mode;
+	}
+
+	prop = of_get_property(np, "phy_type", NULL);
+	pdata->phy_mode = determine_usb_phy(prop);
+
+	for (i = 0; i < ARRAY_SIZE(dev_data->drivers); i++) {
+		if (!dev_data->drivers[i])
+			continue;
+		usb_dev = fsl_usb2_device_register(ofdev, pdata,
+					dev_data->drivers[i], idx);
+		if (IS_ERR(usb_dev)) {
+			dev_err(&ofdev->dev, "Can't register usb device\n");
+			return PTR_ERR(usb_dev);
+		}
+	}
+	idx++;
+	return 0;
+}
+
+static int __devexit __unregister_subdev(struct device *dev, void *d)
+{
+	platform_device_unregister(to_platform_device(dev));
+	return 0;
+}
+
+static int __devexit fsl_usb2_mph_dr_of_remove(struct platform_device *ofdev)
+{
+	device_for_each_child(&ofdev->dev, NULL, __unregister_subdev);
+	return 0;
+}
+
+static const struct of_device_id fsl_usb2_mph_dr_of_match[] = {
+	{ .compatible = "fsl-usb2-mph", },
+	{ .compatible = "fsl-usb2-dr", },
+	{},
+};
+
+static struct of_platform_driver fsl_usb2_mph_dr_driver = {
+	.driver = {
+		.name = "fsl-usb2-mph-dr",
+		.owner = THIS_MODULE,
+		.of_match_table = fsl_usb2_mph_dr_of_match,
+	},
+	.probe	= fsl_usb2_mph_dr_of_probe,
+	.remove	= __devexit_p(fsl_usb2_mph_dr_of_remove),
+};
+
+static int __init fsl_usb2_mph_dr_init(void)
+{
+	return of_register_platform_driver(&fsl_usb2_mph_dr_driver);
+}
+module_init(fsl_usb2_mph_dr_init);
+
+static void __exit fsl_usb2_mph_dr_exit(void)
+{
+	of_unregister_platform_driver(&fsl_usb2_mph_dr_driver);
+}
+module_exit(fsl_usb2_mph_dr_exit);
+
+MODULE_DESCRIPTION("FSL MPH DR OF devices driver");
+MODULE_AUTHOR("Anatolij Gustschin <agust@denx.de>");
+MODULE_LICENSE("GPL");
-- 
1.7.0.4

^ permalink raw reply related	[flat|nested] 10+ messages in thread

* [PATCH v2 3/3] USB: add USB EHCI support for MPC5121 SoC
  2010-09-28  9:36 [PATCH v2 0/3] Add USB Host support for MPC5121 SoC Anatolij Gustschin
  2010-09-28  9:36 ` [PATCH v2 1/3] powerpc/fsl_soc.c: remove FSL USB platform code Anatolij Gustschin
  2010-09-28  9:36 ` [PATCH v2 2/3] USB: add of_platform glue driver for FSL USB DR controller Anatolij Gustschin
@ 2010-09-28  9:36 ` Anatolij Gustschin
  2010-09-28 18:55 ` [PATCH v3 0/2] Add USB Host " Anatolij Gustschin
                   ` (2 subsequent siblings)
  5 siblings, 0 replies; 10+ messages in thread
From: Anatolij Gustschin @ 2010-09-28  9:36 UTC (permalink / raw)
  To: linux-usb
  Cc: David Brownell, Wolfgang Denk, Detlev Zundel, Greg Kroah-Hartman,
	linuxppc-dev, Anatolij Gustschin

Extends FSL EHCI platform driver glue layer to support
MPC5121 USB controllers. MPC5121 Rev 2.0 silicon EHCI
registers are in big endian format. The appropriate flags
are set using the information in the platform data structure.
MPC83xx system interface registers are not available on
MPC512x, so the access to these registers is isolated in
MPC512x case. Furthermore the USB controller clocks
must be enabled before 512x register accesses which is
done by providing platform specific init callback.

The MPC512x internal USB PHY doesn't provide supply voltage.
For boards using different power switches allow specifying
DRVVBUS and PWR_FAULT signal polarity of the MPC5121 internal
PHY using "fsl,invert-drvvbus" and "fsl,invert-pwr-fault"
properties in the device tree USB nodes. Adds documentation
for this new device tree bindings.

Signed-off-by: Anatolij Gustschin <agust@denx.de>
Cc: Grant Likely <grant.likely@secretlab.ca>
---
v2:
 - rebased on linux-next
 - remove host mode setting in usb_hcd_fsl_probe() since
   this is set in tdi_reset() anyway
 - drop now unneeded defines previously used for host
   mode setting
   
 Documentation/powerpc/dts-bindings/fsl/usb.txt |   22 +++++
 drivers/usb/Kconfig                            |    1 +
 drivers/usb/host/Kconfig                       |    6 +-
 drivers/usb/host/ehci-fsl.c                    |   99 +++++++++++++++++-------
 drivers/usb/host/ehci-fsl.h                    |   13 +++-
 drivers/usb/host/ehci-mem.c                    |    2 +-
 drivers/usb/host/fsl-mph-dr-of.c               |   89 +++++++++++++++++++++
 include/linux/fsl_devices.h                    |   15 ++++
 8 files changed, 215 insertions(+), 32 deletions(-)

diff --git a/Documentation/powerpc/dts-bindings/fsl/usb.txt b/Documentation/powerpc/dts-bindings/fsl/usb.txt
index b001524..bd5723f 100644
--- a/Documentation/powerpc/dts-bindings/fsl/usb.txt
+++ b/Documentation/powerpc/dts-bindings/fsl/usb.txt
@@ -8,6 +8,7 @@ and additions :
 Required properties :
  - compatible : Should be "fsl-usb2-mph" for multi port host USB
    controllers, or "fsl-usb2-dr" for dual role USB controllers
+   or "fsl,mpc5121-usb2-dr" for dual role USB controllers of MPC5121
  - phy_type : For multi port host USB controllers, should be one of
    "ulpi", or "serial". For dual role USB controllers, should be
    one of "ulpi", "utmi", "utmi_wide", or "serial".
@@ -33,6 +34,12 @@ Recommended properties :
  - interrupt-parent : the phandle for the interrupt controller that
    services interrupts for this device.
 
+Optional properties :
+ - fsl,invert-drvvbus : boolean; for MPC5121 USB0 only. Indicates the
+   port power polarity of internal PHY signal DRVVBUS is inverted.
+ - fsl,invert-pwr-fault : boolean; for MPC5121 USB0 only. Indicates
+   the PWR_FAULT signal polarity is inverted.
+
 Example multi port host USB controller device node :
 	usb@22000 {
 		compatible = "fsl-usb2-mph";
@@ -57,3 +64,18 @@ Example dual role USB controller device node :
 		dr_mode = "otg";
 		phy = "ulpi";
 	};
+
+Example dual role USB controller device node for MPC5121ADS:
+
+	usb@4000 {
+		compatible = "fsl,mpc5121-usb2-dr";
+		reg = <0x4000 0x1000>;
+		#address-cells = <1>;
+		#size-cells = <0>;
+		interrupt-parent = < &ipic >;
+		interrupts = <44 0x8>;
+		dr_mode = "otg";
+		phy_type = "utmi_wide";
+		fsl,invert-drvvbus;
+		fsl,invert-pwr-fault;
+	};
diff --git a/drivers/usb/Kconfig b/drivers/usb/Kconfig
index 4aa00e6..67eb377 100644
--- a/drivers/usb/Kconfig
+++ b/drivers/usb/Kconfig
@@ -59,6 +59,7 @@ config USB_ARCH_HAS_OHCI
 config USB_ARCH_HAS_EHCI
 	boolean
 	default y if PPC_83xx
+	default y if PPC_MPC512x
 	default y if SOC_AU1200
 	default y if ARCH_IXP4XX
 	default y if ARCH_W90X900
diff --git a/drivers/usb/host/Kconfig b/drivers/usb/host/Kconfig
index f3a90b0..bf2e7d2 100644
--- a/drivers/usb/host/Kconfig
+++ b/drivers/usb/host/Kconfig
@@ -93,12 +93,14 @@ config USB_EHCI_TT_NEWSCHED
 
 config USB_EHCI_BIG_ENDIAN_MMIO
 	bool
-	depends on USB_EHCI_HCD && (PPC_CELLEB || PPC_PS3 || 440EPX || ARCH_IXP4XX || XPS_USB_HCD_XILINX)
+	depends on USB_EHCI_HCD && (PPC_CELLEB || PPC_PS3 || 440EPX || ARCH_IXP4XX || \
+				    XPS_USB_HCD_XILINX || PPC_MPC512x)
 	default y
 
 config USB_EHCI_BIG_ENDIAN_DESC
 	bool
-	depends on USB_EHCI_HCD && (440EPX || ARCH_IXP4XX || XPS_USB_HCD_XILINX)
+	depends on USB_EHCI_HCD && (440EPX || ARCH_IXP4XX || XPS_USB_HCD_XILINX || \
+				    PPC_MPC512x)
 	default y
 
 config XPS_USB_HCD_XILINX
diff --git a/drivers/usb/host/ehci-fsl.c b/drivers/usb/host/ehci-fsl.c
index 8600317..86e4289 100644
--- a/drivers/usb/host/ehci-fsl.c
+++ b/drivers/usb/host/ehci-fsl.c
@@ -116,13 +116,33 @@ static int usb_hcd_fsl_probe(const struct hc_driver *driver,
 		goto err3;
 	}
 
-	/* Enable USB controller */
-	temp = in_be32(hcd->regs + 0x500);
-	out_be32(hcd->regs + 0x500, temp | 0x4);
+	pdata->regs = hcd->regs;
 
-	/* Set to Host mode */
-	temp = in_le32(hcd->regs + 0x1a8);
-	out_le32(hcd->regs + 0x1a8, temp | 0x3);
+	/*
+	 * do platform specific init: check the clock, grab/config pins, etc.
+	 */
+	if (pdata->init && pdata->init(pdev)) {
+		retval = -ENODEV;
+		goto err3;
+	}
+
+	/*
+	 * Check if it is MPC5121 SoC, otherwise set pdata->have_sysif_regs
+	 * flag for 83xx or 8536 system interface registers.
+	 */
+	if (pdata->big_endian_mmio)
+		temp = in_be32(hcd->regs + FSL_SOC_USB_ID);
+	else
+		temp = in_le32(hcd->regs + FSL_SOC_USB_ID);
+
+	if ((temp & ID_MSK) != (~((temp & NID_MSK) >> 8) & ID_MSK))
+		pdata->have_sysif_regs = 1;
+
+	/* Enable USB controller, 83xx or 8536 */
+	if (pdata->have_sysif_regs)
+		setbits32(hcd->regs + FSL_SOC_USB_CTRL, 0x4);
+
+	/* Don't need to set host mode here. It will be done by tdi_reset() */
 
 	retval = usb_add_hcd(hcd, irq, IRQF_DISABLED | IRQF_SHARED);
 	if (retval != 0)
@@ -137,6 +157,8 @@ static int usb_hcd_fsl_probe(const struct hc_driver *driver,
 	usb_put_hcd(hcd);
       err1:
 	dev_err(&pdev->dev, "init %s fail, %d\n", dev_name(&pdev->dev), retval);
+	if (pdata->exit)
+		pdata->exit(pdev);
 	return retval;
 }
 
@@ -154,17 +176,30 @@ static int usb_hcd_fsl_probe(const struct hc_driver *driver,
 static void usb_hcd_fsl_remove(struct usb_hcd *hcd,
 			       struct platform_device *pdev)
 {
+	struct fsl_usb2_platform_data *pdata = pdev->dev.platform_data;
+
 	usb_remove_hcd(hcd);
+
+	/*
+	 * do platform specific un-initialization:
+	 * release iomux pins, disable clock, etc.
+	 */
+	if (pdata->exit)
+		pdata->exit(pdev);
 	iounmap(hcd->regs);
 	release_mem_region(hcd->rsrc_start, hcd->rsrc_len);
 	usb_put_hcd(hcd);
 }
 
-static void mpc83xx_setup_phy(struct ehci_hcd *ehci,
-			      enum fsl_usb2_phy_modes phy_mode,
-			      unsigned int port_offset)
+static void ehci_fsl_setup_phy(struct ehci_hcd *ehci,
+			       enum fsl_usb2_phy_modes phy_mode,
+			       unsigned int port_offset)
 {
-	u32 portsc = 0;
+	u32 portsc;
+
+	portsc = ehci_readl(ehci, &ehci->regs->port_status[port_offset]);
+	portsc &= ~(PORT_PTS_MSK | PORT_PTS_PTW);
+
 	switch (phy_mode) {
 	case FSL_USB2_PHY_ULPI:
 		portsc |= PORT_PTS_ULPI;
@@ -184,20 +219,21 @@ static void mpc83xx_setup_phy(struct ehci_hcd *ehci,
 	ehci_writel(ehci, portsc, &ehci->regs->port_status[port_offset]);
 }
 
-static void mpc83xx_usb_setup(struct usb_hcd *hcd)
+static void ehci_fsl_usb_setup(struct ehci_hcd *ehci)
 {
-	struct ehci_hcd *ehci = hcd_to_ehci(hcd);
+	struct usb_hcd *hcd = ehci_to_hcd(ehci);
 	struct fsl_usb2_platform_data *pdata;
 	void __iomem *non_ehci = hcd->regs;
 	u32 temp;
 
-	pdata =
-	    (struct fsl_usb2_platform_data *)hcd->self.controller->
-	    platform_data;
+	pdata = hcd->self.controller->platform_data;
+
 	/* Enable PHY interface in the control reg. */
-	temp = in_be32(non_ehci + FSL_SOC_USB_CTRL);
-	out_be32(non_ehci + FSL_SOC_USB_CTRL, temp | 0x00000004);
-	out_be32(non_ehci + FSL_SOC_USB_SNOOP1, 0x0000001b);
+	if (pdata->have_sysif_regs) {
+		temp = in_be32(non_ehci + FSL_SOC_USB_CTRL);
+		out_be32(non_ehci + FSL_SOC_USB_CTRL, temp | 0x00000004);
+		out_be32(non_ehci + FSL_SOC_USB_SNOOP1, 0x0000001b);
+	}
 
 #if defined(CONFIG_PPC32) && !defined(CONFIG_NOT_COHERENT_CACHE)
 	/*
@@ -214,7 +250,7 @@ static void mpc83xx_usb_setup(struct usb_hcd *hcd)
 
 	if ((pdata->operating_mode == FSL_USB2_DR_HOST) ||
 			(pdata->operating_mode == FSL_USB2_DR_OTG))
-		mpc83xx_setup_phy(ehci, pdata->phy_mode, 0);
+		ehci_fsl_setup_phy(ehci, pdata->phy_mode, 0);
 
 	if (pdata->operating_mode == FSL_USB2_MPH_HOST) {
 		unsigned int chip, rev, svr;
@@ -228,25 +264,27 @@ static void mpc83xx_usb_setup(struct usb_hcd *hcd)
 			ehci->has_fsl_port_bug = 1;
 
 		if (pdata->port_enables & FSL_USB2_PORT0_ENABLED)
-			mpc83xx_setup_phy(ehci, pdata->phy_mode, 0);
+			ehci_fsl_setup_phy(ehci, pdata->phy_mode, 0);
 		if (pdata->port_enables & FSL_USB2_PORT1_ENABLED)
-			mpc83xx_setup_phy(ehci, pdata->phy_mode, 1);
+			ehci_fsl_setup_phy(ehci, pdata->phy_mode, 1);
 	}
 
+	if (pdata->have_sysif_regs) {
 #ifdef CONFIG_PPC_85xx
-	out_be32(non_ehci + FSL_SOC_USB_PRICTRL, 0x00000008);
-	out_be32(non_ehci + FSL_SOC_USB_AGECNTTHRSH, 0x00000080);
+		out_be32(non_ehci + FSL_SOC_USB_PRICTRL, 0x00000008);
+		out_be32(non_ehci + FSL_SOC_USB_AGECNTTHRSH, 0x00000080);
 #else
-	out_be32(non_ehci + FSL_SOC_USB_PRICTRL, 0x0000000c);
-	out_be32(non_ehci + FSL_SOC_USB_AGECNTTHRSH, 0x00000040);
+		out_be32(non_ehci + FSL_SOC_USB_PRICTRL, 0x0000000c);
+		out_be32(non_ehci + FSL_SOC_USB_AGECNTTHRSH, 0x00000040);
 #endif
-	out_be32(non_ehci + FSL_SOC_USB_SICTRL, 0x00000001);
+		out_be32(non_ehci + FSL_SOC_USB_SICTRL, 0x00000001);
+	}
 }
 
 /* called after powerup, by probe or system-pm "wakeup" */
 static int ehci_fsl_reinit(struct ehci_hcd *ehci)
 {
-	mpc83xx_usb_setup(ehci_to_hcd(ehci));
+	ehci_fsl_usb_setup(ehci);
 	ehci_port_power(ehci, 0);
 
 	return 0;
@@ -257,6 +295,11 @@ static int ehci_fsl_setup(struct usb_hcd *hcd)
 {
 	struct ehci_hcd *ehci = hcd_to_ehci(hcd);
 	int retval;
+	struct fsl_usb2_platform_data *pdata;
+
+	pdata = hcd->self.controller->platform_data;
+	ehci->big_endian_desc = pdata->big_endian_desc;
+	ehci->big_endian_mmio = pdata->big_endian_mmio;
 
 	/* EHCI registers start at offset 0x100 */
 	ehci->caps = hcd->regs + 0x100;
@@ -370,7 +413,7 @@ static const struct hc_driver ehci_fsl_hc_driver = {
 	 * generic hardware linkage
 	 */
 	.irq = ehci_irq,
-	.flags = HCD_USB2,
+	.flags = HCD_USB2 | HCD_MEMORY,
 
 	/*
 	 * basic lifecycle operations
diff --git a/drivers/usb/host/ehci-fsl.h b/drivers/usb/host/ehci-fsl.h
index eb537aa..2c83537 100644
--- a/drivers/usb/host/ehci-fsl.h
+++ b/drivers/usb/host/ehci-fsl.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2005 freescale semiconductor
+/* Copyright (C) 2005-2010 Freescale Semiconductor, Inc.
  * Copyright (c) 2005 MontaVista Software
  *
  * This program is free software; you can redistribute  it and/or modify it
@@ -19,6 +19,9 @@
 #define _EHCI_FSL_H
 
 /* offsets for the non-ehci registers in the FSL SOC USB controller */
+#define FSL_SOC_USB_ID		0x0
+#define ID_MSK			0x3f
+#define NID_MSK			0x3f00
 #define FSL_SOC_USB_ULPIVP	0x170
 #define FSL_SOC_USB_PORTSC1	0x184
 #define PORT_PTS_MSK		(3<<30)
@@ -27,6 +30,14 @@
 #define	PORT_PTS_SERIAL		(3<<30)
 #define PORT_PTS_PTW		(1<<28)
 #define FSL_SOC_USB_PORTSC2	0x188
+
+#define FSL_SOC_USB_USBGENCTRL	0x200
+#define USBGENCTRL_PPP		(1 << 3)
+#define USBGENCTRL_PFP		(1 << 2)
+#define FSL_SOC_USB_ISIPHYCTRL	0x204
+#define ISIPHYCTRL_PXE		(1)
+#define ISIPHYCTRL_PHYE		(1 << 4)
+
 #define FSL_SOC_USB_SNOOP1	0x400	/* NOTE: big-endian */
 #define FSL_SOC_USB_SNOOP2	0x404	/* NOTE: big-endian */
 #define FSL_SOC_USB_AGECNTTHRSH	0x408	/* NOTE: big-endian */
diff --git a/drivers/usb/host/ehci-mem.c b/drivers/usb/host/ehci-mem.c
index 1f3f01e..d36e4e7 100644
--- a/drivers/usb/host/ehci-mem.c
+++ b/drivers/usb/host/ehci-mem.c
@@ -40,7 +40,7 @@ static inline void ehci_qtd_init(struct ehci_hcd *ehci, struct ehci_qtd *qtd,
 {
 	memset (qtd, 0, sizeof *qtd);
 	qtd->qtd_dma = dma;
-	qtd->hw_token = cpu_to_le32 (QTD_STS_HALT);
+	qtd->hw_token = cpu_to_hc32(ehci, QTD_STS_HALT);
 	qtd->hw_next = EHCI_LIST_END(ehci);
 	qtd->hw_alt_next = EHCI_LIST_END(ehci);
 	INIT_LIST_HEAD (&qtd->qtd_list);
diff --git a/drivers/usb/host/fsl-mph-dr-of.c b/drivers/usb/host/fsl-mph-dr-of.c
index ee8cb94..7e99ddd 100644
--- a/drivers/usb/host/fsl-mph-dr-of.c
+++ b/drivers/usb/host/fsl-mph-dr-of.c
@@ -15,6 +15,7 @@
 #include <linux/err.h>
 #include <linux/io.h>
 #include <linux/of_platform.h>
+#include <linux/clk.h>
 
 struct fsl_usb2_dev_data {
 	char *dr_mode;		/* controller mode */
@@ -147,6 +148,12 @@ static int __devinit fsl_usb2_mph_dr_of_probe(struct platform_device *ofdev,
 
 		pdata->operating_mode = FSL_USB2_MPH_HOST;
 	} else {
+		if (of_get_property(np, "fsl,invert-drvvbus", NULL))
+			pdata->invert_drvvbus = 1;
+
+		if (of_get_property(np, "fsl,invert-pwr-fault", NULL))
+			pdata->invert_pwr_fault = 1;
+
 		/* setup mode selected in the device tree */
 		pdata->operating_mode = dev_data->op_mode;
 	}
@@ -180,9 +187,91 @@ static int __devexit fsl_usb2_mph_dr_of_remove(struct platform_device *ofdev)
 	return 0;
 }
 
+#ifdef CONFIG_PPC_MPC512x
+
+#define USBGENCTRL		0x200		/* NOTE: big endian */
+#define GC_WU_INT_CLR		(1 << 5)	/* Wakeup int clear */
+#define GC_ULPI_SEL		(1 << 4)	/* ULPI i/f select (usb0 only)*/
+#define GC_PPP			(1 << 3)	/* Inv. Port Power Polarity */
+#define GC_PFP			(1 << 2)	/* Inv. Power Fault Polarity */
+#define GC_WU_ULPI_EN		(1 << 1)	/* Wakeup on ULPI event */
+#define GC_WU_IE		(1 << 1)	/* Wakeup interrupt enable */
+
+#define ISIPHYCTRL		0x204		/* NOTE: big endian */
+#define PHYCTRL_PHYE		(1 << 4)	/* On-chip UTMI PHY enable */
+#define PHYCTRL_BSENH		(1 << 3)	/* Bit Stuff Enable High */
+#define PHYCTRL_BSEN		(1 << 2)	/* Bit Stuff Enable */
+#define PHYCTRL_LSFE		(1 << 1)	/* Line State Filter Enable */
+#define PHYCTRL_PXE		(1 << 0)	/* PHY oscillator enable */
+
+int fsl_usb2_mpc5121_init(struct platform_device *pdev)
+{
+	struct fsl_usb2_platform_data *pdata = pdev->dev.platform_data;
+	struct clk *clk;
+	char clk_name[10];
+	int base, clk_num;
+
+	base = pdev->resource->start & 0xf000;
+	if (base == 0x3000)
+		clk_num = 1;
+	else if (base == 0x4000)
+		clk_num = 2;
+	else
+		return -ENODEV;
+
+	snprintf(clk_name, sizeof(clk_name), "usb%d_clk", clk_num);
+	clk = clk_get(&pdev->dev, clk_name);
+	if (IS_ERR(clk)) {
+		dev_err(&pdev->dev, "failed to get clk\n");
+		return PTR_ERR(clk);
+	}
+
+	clk_enable(clk);
+	pdata->clk = clk;
+
+	if (pdata->phy_mode == FSL_USB2_PHY_UTMI_WIDE) {
+		u32 reg = 0;
+
+		if (pdata->invert_drvvbus)
+			reg |= GC_PPP;
+
+		if (pdata->invert_pwr_fault)
+			reg |= GC_PFP;
+
+		out_be32(pdata->regs + ISIPHYCTRL, PHYCTRL_PHYE | PHYCTRL_PXE);
+		out_be32(pdata->regs + USBGENCTRL, reg);
+	}
+	return 0;
+}
+
+static void fsl_usb2_mpc5121_exit(struct platform_device *pdev)
+{
+	struct fsl_usb2_platform_data *pdata = pdev->dev.platform_data;
+
+	pdata->regs = NULL;
+
+	if (pdata->clk) {
+		clk_disable(pdata->clk);
+		clk_put(pdata->clk);
+	}
+}
+
+struct fsl_usb2_platform_data fsl_usb2_mpc5121_pd = {
+	.big_endian_desc = 1,
+	.big_endian_mmio = 1,
+	.es = 1,
+	.le_setup_buf = 1,
+	.init = fsl_usb2_mpc5121_init,
+	.exit = fsl_usb2_mpc5121_exit,
+};
+#endif /* CONFIG_PPC_MPC512x */
+
 static const struct of_device_id fsl_usb2_mph_dr_of_match[] = {
 	{ .compatible = "fsl-usb2-mph", },
 	{ .compatible = "fsl-usb2-dr", },
+#ifdef CONFIG_PPC_MPC512x
+	{ .compatible = "fsl,mpc5121-usb2-dr", .data = &fsl_usb2_mpc5121_pd, },
+#endif
 	{},
 };
 
diff --git a/include/linux/fsl_devices.h b/include/linux/fsl_devices.h
index 28e33fe..d5f9a74 100644
--- a/include/linux/fsl_devices.h
+++ b/include/linux/fsl_devices.h
@@ -58,11 +58,26 @@ enum fsl_usb2_phy_modes {
 	FSL_USB2_PHY_SERIAL,
 };
 
+struct clk;
+struct platform_device;
+
 struct fsl_usb2_platform_data {
 	/* board specific information */
 	enum fsl_usb2_operating_modes	operating_mode;
 	enum fsl_usb2_phy_modes		phy_mode;
 	unsigned int			port_enables;
+
+	int		(*init)(struct platform_device *);
+	void		(*exit)(struct platform_device *);
+	void __iomem	*regs;		/* ioremap'd register base */
+	struct clk	*clk;
+	unsigned	big_endian_mmio:1;
+	unsigned	big_endian_desc:1;
+	unsigned	es:1;		/* need USBMODE:ES */
+	unsigned	le_setup_buf:1;
+	unsigned	have_sysif_regs:1;
+	unsigned	invert_drvvbus:1;
+	unsigned	invert_pwr_fault:1;
 };
 
 /* Flags in fsl_usb2_mph_platform_data */
-- 
1.7.0.4

^ permalink raw reply related	[flat|nested] 10+ messages in thread

* Re: [PATCH v2 2/3] USB: add of_platform glue driver for FSL USB DR controller
  2010-09-28  9:36 ` [PATCH v2 2/3] USB: add of_platform glue driver for FSL USB DR controller Anatolij Gustschin
@ 2010-09-28 10:01   ` Grant Likely
  2010-09-28 11:35     ` Anatolij Gustschin
  0 siblings, 1 reply; 10+ messages in thread
From: Grant Likely @ 2010-09-28 10:01 UTC (permalink / raw)
  To: Anatolij Gustschin
  Cc: Greg Kroah-Hartman, Wolfgang Denk, Detlev Zundel, linux-usb,
	linuxppc-dev, David Brownell

Hi Anatolij

Looks pretty good.  Comments below.  Main comment is that with the
recent changes in mainline, this no longer needs to be an
of_platform_driver.  It can be a plain old platform_driver instead.
It gets registered as a platform_driver anyway, but of_platform_driver
is a shim that adds a bit of overhead, so it is best to avoid it.
I'll detail the changes you need to make in my comments below.

On Tue, Sep 28, 2010 at 6:36 PM, Anatolij Gustschin <agust@denx.de> wrote:
> The driver creates platform devices based on the information
> from USB nodes in the flat device tree. This is the replacement
> for old arch fsl_soc usb code removed by the previous patch.
> It uses usual of-style binding, available EHCI-HCD and UDC
> drivers can be bound to the created devices. The new of-style
> driver additionaly instantiates USB OTG platform device, as the
> appropriate USB OTG driver will be added soon.
>
> Signed-off-by: Anatolij Gustschin <agust@denx.de>
> Cc: Kumar Gala <galak@kernel.crashing.org>
> Cc: Grant Likely <grant.likely@secretlab.ca>
> ---
> v2:
> =A0- drop unneeded PPC_OF dependency
> =A0- fix spelling bug in mode table and fix coding style
> =A0- print a warning if no valid dr_mode found
> =A0- add remove hook to unregister platform devices
> =A0 created by probe. So the driver can be unbound
> =A0- fix OTG platform device creation order
> =A0- drop fs_initcall, replaced by module_init() now
> =A0- add module_exit(), MODULE_DESCRIPTION, MODULE_LICENSE
>
> =A0drivers/usb/gadget/Kconfig =A0 =A0 =A0 | =A0 =A01 +
> =A0drivers/usb/host/Kconfig =A0 =A0 =A0 =A0 | =A0 =A04 +
> =A0drivers/usb/host/Makefile =A0 =A0 =A0 =A0| =A0 =A01 +
> =A0drivers/usb/host/fsl-mph-dr-of.c | =A0213 ++++++++++++++++++++++++++++=
++++++++++
> =A04 files changed, 219 insertions(+), 0 deletions(-)
> =A0create mode 100644 drivers/usb/host/fsl-mph-dr-of.c
>
> diff --git a/drivers/usb/gadget/Kconfig b/drivers/usb/gadget/Kconfig
> index fab765d..0fe5bc8 100644
> --- a/drivers/usb/gadget/Kconfig
> +++ b/drivers/usb/gadget/Kconfig
> @@ -158,6 +158,7 @@ config USB_GADGET_FSL_USB2
> =A0 =A0 =A0 =A0boolean "Freescale Highspeed USB DR Peripheral Controller"
> =A0 =A0 =A0 =A0depends on FSL_SOC || ARCH_MXC
> =A0 =A0 =A0 =A0select USB_GADGET_DUALSPEED
> + =A0 =A0 =A0 select USB_FSL_MPH_DR_OF
> =A0 =A0 =A0 =A0help
> =A0 =A0 =A0 =A0 =A0 Some of Freescale PowerPC processors have a High Spee=
d
> =A0 =A0 =A0 =A0 =A0 Dual-Role(DR) USB controller, which supports device m=
ode.
> diff --git a/drivers/usb/host/Kconfig b/drivers/usb/host/Kconfig
> index 2d926ce..f3a90b0 100644
> --- a/drivers/usb/host/Kconfig
> +++ b/drivers/usb/host/Kconfig
> @@ -112,10 +112,14 @@ config XPS_USB_HCD_XILINX
> =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0support both high speed and full speed dev=
ices, or high speed
> =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0devices only.
>
> +config USB_FSL_MPH_DR_OF
> + =A0 =A0 =A0 tristate
> +
> =A0config USB_EHCI_FSL
> =A0 =A0 =A0 =A0bool "Support for Freescale on-chip EHCI USB controller"
> =A0 =A0 =A0 =A0depends on USB_EHCI_HCD && FSL_SOC
> =A0 =A0 =A0 =A0select USB_EHCI_ROOT_HUB_TT
> + =A0 =A0 =A0 select USB_FSL_MPH_DR_OF
> =A0 =A0 =A0 =A0---help---
> =A0 =A0 =A0 =A0 =A0Variation of ARC USB block used in some Freescale chip=
s.
>
> diff --git a/drivers/usb/host/Makefile b/drivers/usb/host/Makefile
> index b6315aa..aacbe82 100644
> --- a/drivers/usb/host/Makefile
> +++ b/drivers/usb/host/Makefile
> @@ -33,4 +33,5 @@ obj-$(CONFIG_USB_R8A66597_HCD) =A0 =A0 =A0 =A0+=3D r8a6=
6597-hcd.o
> =A0obj-$(CONFIG_USB_ISP1760_HCD) =A0+=3D isp1760.o
> =A0obj-$(CONFIG_USB_HWA_HCD) =A0 =A0 =A0+=3D hwa-hc.o
> =A0obj-$(CONFIG_USB_IMX21_HCD) =A0 =A0+=3D imx21-hcd.o
> +obj-$(CONFIG_USB_FSL_MPH_DR_OF) =A0 =A0 =A0 =A0+=3D fsl-mph-dr-of.o
>
> diff --git a/drivers/usb/host/fsl-mph-dr-of.c b/drivers/usb/host/fsl-mph-=
dr-of.c
> new file mode 100644
> index 0000000..ee8cb94
> --- /dev/null
> +++ b/drivers/usb/host/fsl-mph-dr-of.c
> @@ -0,0 +1,213 @@
> +/*
> + * Setup platform devices needed by the Freescale multi-port host
> + * and/or dual-role USB controller modules based on the description
> + * in flat device tree.
> + *
> + * This program is free software; you can redistribute =A0it and/or modi=
fy it
> + * under =A0the terms of =A0the GNU General =A0Public License as publish=
ed by the
> + * Free Software Foundation; =A0either version 2 of the =A0License, or (=
at your
> + * option) any later version.
> + */
> +
> +#include <linux/kernel.h>
> +#include <linux/platform_device.h>
> +#include <linux/fsl_devices.h>
> +#include <linux/err.h>
> +#include <linux/io.h>
> +#include <linux/of_platform.h>
> +
> +struct fsl_usb2_dev_data {
> + =A0 =A0 =A0 char *dr_mode; =A0 =A0 =A0 =A0 =A0/* controller mode */
> + =A0 =A0 =A0 char *drivers[3]; =A0 =A0 =A0 /* drivers to instantiate for=
 this mode */
> + =A0 =A0 =A0 enum fsl_usb2_operating_modes op_mode; =A0/* operating mode=
 */
> +};
> +
> +struct fsl_usb2_dev_data dr_mode_data[] __devinitdata =3D {
> + =A0 =A0 =A0 {
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 .dr_mode =3D "host",
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 .drivers =3D { "fsl-ehci", NULL, NULL, },
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 .op_mode =3D FSL_USB2_DR_HOST,
> + =A0 =A0 =A0 },
> + =A0 =A0 =A0 {
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 .dr_mode =3D "otg",
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 .drivers =3D { "fsl-usb2-otg", "fsl-ehci", =
"fsl-usb2-udc", },
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 .op_mode =3D FSL_USB2_DR_OTG,
> + =A0 =A0 =A0 },
> + =A0 =A0 =A0 {
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 .dr_mode =3D "peripheral",
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 .drivers =3D { "fsl-usb2-udc", NULL, NULL, =
},
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 .op_mode =3D FSL_USB2_DR_DEVICE,
> + =A0 =A0 =A0 },
> +};
> +
> +struct fsl_usb2_dev_data * __devinit get_dr_mode_data(struct device_node=
 *np)
> +{
> + =A0 =A0 =A0 const unsigned char *prop;
> + =A0 =A0 =A0 int i;
> +
> + =A0 =A0 =A0 prop =3D of_get_property(np, "dr_mode", NULL);
> + =A0 =A0 =A0 if (prop) {
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 for (i =3D 0; i < ARRAY_SIZE(dr_mode_data);=
 i++) {
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 if (!strcmp(prop, dr_mode_d=
ata[i].dr_mode))
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 return &dr_=
mode_data[i];
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 }
> + =A0 =A0 =A0 }
> + =A0 =A0 =A0 pr_warn("%s: Invalid 'dr_mode' property, fallback to host m=
ode\n",
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 np->full_name);
> + =A0 =A0 =A0 return &dr_mode_data[0]; /* mode not specified, use host */
> +}
> +
> +static enum fsl_usb2_phy_modes __devinit determine_usb_phy(const char *p=
hy_type)
> +{
> + =A0 =A0 =A0 if (!phy_type)
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 return FSL_USB2_PHY_NONE;
> + =A0 =A0 =A0 if (!strcasecmp(phy_type, "ulpi"))
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 return FSL_USB2_PHY_ULPI;
> + =A0 =A0 =A0 if (!strcasecmp(phy_type, "utmi"))
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 return FSL_USB2_PHY_UTMI;
> + =A0 =A0 =A0 if (!strcasecmp(phy_type, "utmi_wide"))
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 return FSL_USB2_PHY_UTMI_WIDE;
> + =A0 =A0 =A0 if (!strcasecmp(phy_type, "serial"))
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 return FSL_USB2_PHY_SERIAL;
> +
> + =A0 =A0 =A0 return FSL_USB2_PHY_NONE;
> +}
> +
> +struct platform_device * __devinit fsl_usb2_device_register(
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0=
 =A0 struct platform_device *ofdev,
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0=
 =A0 struct fsl_usb2_platform_data *pdata,
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0=
 =A0 const char *name, int id)
> +{
> + =A0 =A0 =A0 struct platform_device *pdev;
> + =A0 =A0 =A0 const struct resource *res =3D ofdev->resource;
> + =A0 =A0 =A0 unsigned int num =3D ofdev->num_resources;
> + =A0 =A0 =A0 int retval;
> +
> + =A0 =A0 =A0 pdev =3D platform_device_alloc(name, id);
> + =A0 =A0 =A0 if (!pdev) {
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 retval =3D -ENOMEM;
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 goto error;
> + =A0 =A0 =A0 }
> +
> + =A0 =A0 =A0 pdev->dev.parent =3D &ofdev->dev;
> +
> + =A0 =A0 =A0 pdev->dev.coherent_dma_mask =3D ofdev->dev.coherent_dma_mas=
k;
> + =A0 =A0 =A0 pdev->dev.dma_mask =3D &pdev->archdata.dma_mask;
> + =A0 =A0 =A0 *pdev->dev.dma_mask =3D *ofdev->dev.dma_mask;
> +
> + =A0 =A0 =A0 retval =3D platform_device_add_data(pdev, pdata, sizeof(*pd=
ata));
> + =A0 =A0 =A0 if (retval)
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 goto error;
> +
> + =A0 =A0 =A0 if (num) {
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 retval =3D platform_device_add_resources(pd=
ev, res, num);
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 if (retval)
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 goto error;
> + =A0 =A0 =A0 }
> +
> + =A0 =A0 =A0 retval =3D platform_device_add(pdev);
> + =A0 =A0 =A0 if (retval)
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 goto error;
> +
> + =A0 =A0 =A0 return pdev;
> +
> +error:
> + =A0 =A0 =A0 platform_device_put(pdev);
> + =A0 =A0 =A0 return ERR_PTR(retval);
> +}
> +
> +static int __devinit fsl_usb2_mph_dr_of_probe(struct platform_device *of=
dev,
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0=
 =A0 =A0 =A0const struct of_device_id *match)

Change to:
static int __devinit fsl_usb2_mph_dr_of_probe(struct platform_device *ofdev=
)

You can get the 'match' pointer by calling of_match_device().

> +{
> + =A0 =A0 =A0 struct device_node *np =3D ofdev->dev.of_node;
> + =A0 =A0 =A0 struct platform_device *usb_dev;
> + =A0 =A0 =A0 struct fsl_usb2_platform_data data, *pdata;
> + =A0 =A0 =A0 struct fsl_usb2_dev_data *dev_data;
> + =A0 =A0 =A0 const unsigned char *prop;
> + =A0 =A0 =A0 static unsigned int idx;
> + =A0 =A0 =A0 int i;
> +
> + =A0 =A0 =A0 if (!of_device_is_available(np))
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 return -ENODEV;
> +
> + =A0 =A0 =A0 pdata =3D match->data;
> + =A0 =A0 =A0 if (!pdata) {
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 memset(&data, 0, sizeof(data));
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 pdata =3D &data;
> + =A0 =A0 =A0 }

This is bad behaviour.  *match->data must not be modified in probe
because multiple instances of the device can exist.  The target of
pdata is modified later in the probe routine.

However, the above 4 lines can be removed entirely since none of the
fsl_usb2_mph_dr_of_match entries actually set the data pointer.  The
local 'data' structure can be used directly.

> +
> + =A0 =A0 =A0 dev_data =3D get_dr_mode_data(np);
> +
> + =A0 =A0 =A0 if (of_device_is_compatible(np, "fsl-usb2-mph")) {
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 if (of_get_property(np, "port0", NULL))
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 pdata->port_enables |=3D FS=
L_USB2_PORT0_ENABLED;
> +
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 if (of_get_property(np, "port1", NULL))
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 pdata->port_enables |=3D FS=
L_USB2_PORT1_ENABLED;
> +
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 pdata->operating_mode =3D FSL_USB2_MPH_HOST=
;
> + =A0 =A0 =A0 } else {
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 /* setup mode selected in the device tree *=
/
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 pdata->operating_mode =3D dev_data->op_mode=
;
> + =A0 =A0 =A0 }
> +
> + =A0 =A0 =A0 prop =3D of_get_property(np, "phy_type", NULL);
> + =A0 =A0 =A0 pdata->phy_mode =3D determine_usb_phy(prop);
> +
> + =A0 =A0 =A0 for (i =3D 0; i < ARRAY_SIZE(dev_data->drivers); i++) {
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 if (!dev_data->drivers[i])
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 continue;
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 usb_dev =3D fsl_usb2_device_register(ofdev,=
 pdata,
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0=
 =A0 dev_data->drivers[i], idx);
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 if (IS_ERR(usb_dev)) {
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 dev_err(&ofdev->dev, "Can't=
 register usb device\n");
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 return PTR_ERR(usb_dev);
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 }
> + =A0 =A0 =A0 }
> + =A0 =A0 =A0 idx++;
> + =A0 =A0 =A0 return 0;
> +}
> +
> +static int __devexit __unregister_subdev(struct device *dev, void *d)
> +{
> + =A0 =A0 =A0 platform_device_unregister(to_platform_device(dev));
> + =A0 =A0 =A0 return 0;
> +}
> +
> +static int __devexit fsl_usb2_mph_dr_of_remove(struct platform_device *o=
fdev)
> +{
> + =A0 =A0 =A0 device_for_each_child(&ofdev->dev, NULL, __unregister_subde=
v);
> + =A0 =A0 =A0 return 0;
> +}
> +
> +static const struct of_device_id fsl_usb2_mph_dr_of_match[] =3D {
> + =A0 =A0 =A0 { .compatible =3D "fsl-usb2-mph", },
> + =A0 =A0 =A0 { .compatible =3D "fsl-usb2-dr", },
> + =A0 =A0 =A0 {},
> +};
> +
> +static struct of_platform_driver fsl_usb2_mph_dr_driver =3D {
> + =A0 =A0 =A0 .driver =3D {
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 .name =3D "fsl-usb2-mph-dr",
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 .owner =3D THIS_MODULE,
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 .of_match_table =3D fsl_usb2_mph_dr_of_matc=
h,
> + =A0 =A0 =A0 },
> + =A0 =A0 =A0 .probe =A0=3D fsl_usb2_mph_dr_of_probe,
> + =A0 =A0 =A0 .remove =3D __devexit_p(fsl_usb2_mph_dr_of_remove),
> +};

Change of_platform_driver to platform_driver

> +
> +static int __init fsl_usb2_mph_dr_init(void)
> +{
> + =A0 =A0 =A0 return of_register_platform_driver(&fsl_usb2_mph_dr_driver)=
;

change to platform_driver_register()

> +}
> +module_init(fsl_usb2_mph_dr_init);
> +
> +static void __exit fsl_usb2_mph_dr_exit(void)
> +{
> + =A0 =A0 =A0 of_unregister_platform_driver(&fsl_usb2_mph_dr_driver);

change to platform_driver_unregister()

> +}
> +module_exit(fsl_usb2_mph_dr_exit);
> +
> +MODULE_DESCRIPTION("FSL MPH DR OF devices driver");
> +MODULE_AUTHOR("Anatolij Gustschin <agust@denx.de>");
> +MODULE_LICENSE("GPL");
> --
> 1.7.0.4
>
>



--=20
Grant Likely, B.Sc., P.Eng.
Secret Lab Technologies Ltd.

^ permalink raw reply	[flat|nested] 10+ messages in thread

* Re: [PATCH v2 2/3] USB: add of_platform glue driver for FSL USB DR controller
  2010-09-28 10:01   ` Grant Likely
@ 2010-09-28 11:35     ` Anatolij Gustschin
  0 siblings, 0 replies; 10+ messages in thread
From: Anatolij Gustschin @ 2010-09-28 11:35 UTC (permalink / raw)
  To: Grant Likely
  Cc: Greg Kroah-Hartman, Wolfgang Denk, Detlev Zundel, linux-usb,
	linuxppc-dev, David Brownell

Hi Grant,

On Tue, 28 Sep 2010 19:01:28 +0900
Grant Likely <grant.likely@secretlab.ca> wrote:
...
> Looks pretty good.  Comments below.  Main comment is that with the
> recent changes in mainline, this no longer needs to be an
> of_platform_driver.  It can be a plain old platform_driver instead.
> It gets registered as a platform_driver anyway, but of_platform_driver
> is a shim that adds a bit of overhead, so it is best to avoid it.
> I'll detail the changes you need to make in my comments below.

Thanks. I'll change to platform_driver. My reply below.

...
> > +{
> > + =A0 =A0 =A0 struct device_node *np =3D ofdev->dev.of_node;
> > + =A0 =A0 =A0 struct platform_device *usb_dev;
> > + =A0 =A0 =A0 struct fsl_usb2_platform_data data, *pdata;
> > + =A0 =A0 =A0 struct fsl_usb2_dev_data *dev_data;
> > + =A0 =A0 =A0 const unsigned char *prop;
> > + =A0 =A0 =A0 static unsigned int idx;
> > + =A0 =A0 =A0 int i;
> > +
> > + =A0 =A0 =A0 if (!of_device_is_available(np))
> > + =A0 =A0 =A0 =A0 =A0 =A0 =A0 return -ENODEV;
> > +
> > + =A0 =A0 =A0 pdata =3D match->data;
> > + =A0 =A0 =A0 if (!pdata) {
> > + =A0 =A0 =A0 =A0 =A0 =A0 =A0 memset(&data, 0, sizeof(data));
> > + =A0 =A0 =A0 =A0 =A0 =A0 =A0 pdata =3D &data;
> > + =A0 =A0 =A0 }
>=20
> This is bad behaviour.  *match->data must not be modified in probe
> because multiple instances of the device can exist.  The target of
> pdata is modified later in the probe routine.
>=20
> However, the above 4 lines can be removed entirely since none of the
> fsl_usb2_mph_dr_of_match entries actually set the data pointer.  The
> local 'data' structure can be used directly.

A match entry for mpc5121 is added by the third patch. I'll fix
this so that only local 'data' structure is modified later in the
probe routine.

Thanks,
Anatolij

^ permalink raw reply	[flat|nested] 10+ messages in thread

* Re: [PATCH v2 1/3] powerpc/fsl_soc.c: remove FSL USB platform code
  2010-09-28  9:36 ` [PATCH v2 1/3] powerpc/fsl_soc.c: remove FSL USB platform code Anatolij Gustschin
@ 2010-09-28 11:40   ` Anton Vorontsov
  0 siblings, 0 replies; 10+ messages in thread
From: Anton Vorontsov @ 2010-09-28 11:40 UTC (permalink / raw)
  To: Anatolij Gustschin
  Cc: David Brownell, Wolfgang Denk, Detlev Zundel, linux-usb,
	linuxppc-dev, Greg Kroah-Hartman

On Tue, Sep 28, 2010 at 11:36:32AM +0200, Anatolij Gustschin wrote:
> This removed code will be replaced by simple of_platform
> driver for creation of FSL USB platform devices which is
> added by next patch of the series.
> 
> Signed-off-by: Anatolij Gustschin <agust@denx.de>
> Cc: Kumar Gala <galak@kernel.crashing.org>
> Cc: Grant Likely <grant.likely@secretlab.ca>
> ---

This is not bisectable. You have to merge 1/3 and 2/3.

Thanks,

-- 
Anton Vorontsov
email: cbouatmailru@gmail.com
irc://irc.freenode.net/bd2

^ permalink raw reply	[flat|nested] 10+ messages in thread

* [PATCH v3 0/2] Add USB Host support for MPC5121 SoC
  2010-09-28  9:36 [PATCH v2 0/3] Add USB Host support for MPC5121 SoC Anatolij Gustschin
                   ` (2 preceding siblings ...)
  2010-09-28  9:36 ` [PATCH v2 3/3] USB: add USB EHCI support for MPC5121 SoC Anatolij Gustschin
@ 2010-09-28 18:55 ` Anatolij Gustschin
  2010-09-28 18:55 ` [PATCH v3 1/2] USB: add platform glue driver for FSL USB DR controller Anatolij Gustschin
  2010-09-28 18:55 ` [PATCH v3 2/2] USB: add USB EHCI support for MPC5121 SoC Anatolij Gustschin
  5 siblings, 0 replies; 10+ messages in thread
From: Anatolij Gustschin @ 2010-09-28 18:55 UTC (permalink / raw)
  To: linux-usb
  Cc: David Brownell, Wolfgang Denk, Detlev Zundel, Greg Kroah-Hartman,
	linuxppc-dev, Anatolij Gustschin

Version 3 of the patches to add MPC512x USB support in
mainline kernel. USB OTG support is not included in
this patch series, it will be submitted later.

There are only two patches now: patches 1/3 and 2/3 of
the previous version are merged into the first patch and
now bisectable. Additionally the 2nd patch of the previous
version is changed as requested by Grant. Please consider
for inclusion in 2.6.37.

Anatolij Gustschin (2):
  USB: add platform glue driver for FSL USB DR controller
  USB: add USB EHCI support for MPC5121 SoC

 Documentation/powerpc/dts-bindings/fsl/usb.txt |   22 ++
 arch/powerpc/sysdev/fsl_soc.c                  |  163 -------------
 drivers/usb/Kconfig                            |    1 +
 drivers/usb/gadget/Kconfig                     |    1 +
 drivers/usb/host/Kconfig                       |   10 +-
 drivers/usb/host/Makefile                      |    1 +
 drivers/usb/host/ehci-fsl.c                    |   99 ++++++---
 drivers/usb/host/ehci-fsl.h                    |   13 +-
 drivers/usb/host/ehci-mem.c                    |    2 +-
 drivers/usb/host/fsl-mph-dr-of.c               |  308 ++++++++++++++++++++++++
 include/linux/fsl_devices.h                    |   15 ++
 11 files changed, 440 insertions(+), 195 deletions(-)
 create mode 100644 drivers/usb/host/fsl-mph-dr-of.c

^ permalink raw reply	[flat|nested] 10+ messages in thread

* [PATCH v3 1/2] USB: add platform glue driver for FSL USB DR controller
  2010-09-28  9:36 [PATCH v2 0/3] Add USB Host support for MPC5121 SoC Anatolij Gustschin
                   ` (3 preceding siblings ...)
  2010-09-28 18:55 ` [PATCH v3 0/2] Add USB Host " Anatolij Gustschin
@ 2010-09-28 18:55 ` Anatolij Gustschin
  2010-09-28 18:55 ` [PATCH v3 2/2] USB: add USB EHCI support for MPC5121 SoC Anatolij Gustschin
  5 siblings, 0 replies; 10+ messages in thread
From: Anatolij Gustschin @ 2010-09-28 18:55 UTC (permalink / raw)
  To: linux-usb
  Cc: David Brownell, Wolfgang Denk, Detlev Zundel, Greg Kroah-Hartman,
	linuxppc-dev, Anatolij Gustschin

Replace FSL USB platform code by simple platform driver for
creation of FSL USB platform devices.

The driver creates platform devices based on the information
from USB nodes in the flat device tree. This is the replacement
for old arch fsl_soc usb code removed by this patch. The driver
uses usual of-style binding, available EHCI-HCD and UDC
drivers can be bound to the created devices. The new of-style
driver additionaly instantiates USB OTG platform device, as the
appropriate USB OTG driver will be added soon.

Signed-off-by: Anatolij Gustschin <agust@denx.de>
Cc: Kumar Gala <galak@kernel.crashing.org>
Cc: Grant Likely <grant.likely@secretlab.ca>
---
v3:
 - merged patches 1/3 and 2/3 of the previous version
 - changed to platform_driver as requested
 - fixed probe() to avoid modification of driver's
   shared platform data struct pointed to by 'data' in
   the match table which is added by the next patch of
   the series

 arch/powerpc/sysdev/fsl_soc.c    |  163 ----------------------------
 drivers/usb/gadget/Kconfig       |    1 +
 drivers/usb/host/Kconfig         |    4 +
 drivers/usb/host/Makefile        |    1 +
 drivers/usb/host/fsl-mph-dr-of.c |  219 ++++++++++++++++++++++++++++++++++++++
 5 files changed, 225 insertions(+), 163 deletions(-)
 create mode 100644 drivers/usb/host/fsl-mph-dr-of.c

diff --git a/arch/powerpc/sysdev/fsl_soc.c b/arch/powerpc/sysdev/fsl_soc.c
index b91f7ac..49a51f1 100644
--- a/arch/powerpc/sysdev/fsl_soc.c
+++ b/arch/powerpc/sysdev/fsl_soc.c
@@ -209,169 +209,6 @@ static int __init of_add_fixed_phys(void)
 arch_initcall(of_add_fixed_phys);
 #endif /* CONFIG_FIXED_PHY */
 
-static enum fsl_usb2_phy_modes determine_usb_phy(const char *phy_type)
-{
-	if (!phy_type)
-		return FSL_USB2_PHY_NONE;
-	if (!strcasecmp(phy_type, "ulpi"))
-		return FSL_USB2_PHY_ULPI;
-	if (!strcasecmp(phy_type, "utmi"))
-		return FSL_USB2_PHY_UTMI;
-	if (!strcasecmp(phy_type, "utmi_wide"))
-		return FSL_USB2_PHY_UTMI_WIDE;
-	if (!strcasecmp(phy_type, "serial"))
-		return FSL_USB2_PHY_SERIAL;
-
-	return FSL_USB2_PHY_NONE;
-}
-
-static int __init fsl_usb_of_init(void)
-{
-	struct device_node *np;
-	unsigned int i = 0;
-	struct platform_device *usb_dev_mph = NULL, *usb_dev_dr_host = NULL,
-		*usb_dev_dr_client = NULL;
-	int ret;
-
-	for_each_compatible_node(np, NULL, "fsl-usb2-mph") {
-		struct resource r[2];
-		struct fsl_usb2_platform_data usb_data;
-		const unsigned char *prop = NULL;
-
-		memset(&r, 0, sizeof(r));
-		memset(&usb_data, 0, sizeof(usb_data));
-
-		ret = of_address_to_resource(np, 0, &r[0]);
-		if (ret)
-			goto err;
-
-		of_irq_to_resource(np, 0, &r[1]);
-
-		usb_dev_mph =
-		    platform_device_register_simple("fsl-ehci", i, r, 2);
-		if (IS_ERR(usb_dev_mph)) {
-			ret = PTR_ERR(usb_dev_mph);
-			goto err;
-		}
-
-		usb_dev_mph->dev.coherent_dma_mask = 0xffffffffUL;
-		usb_dev_mph->dev.dma_mask = &usb_dev_mph->dev.coherent_dma_mask;
-
-		usb_data.operating_mode = FSL_USB2_MPH_HOST;
-
-		prop = of_get_property(np, "port0", NULL);
-		if (prop)
-			usb_data.port_enables |= FSL_USB2_PORT0_ENABLED;
-
-		prop = of_get_property(np, "port1", NULL);
-		if (prop)
-			usb_data.port_enables |= FSL_USB2_PORT1_ENABLED;
-
-		prop = of_get_property(np, "phy_type", NULL);
-		usb_data.phy_mode = determine_usb_phy(prop);
-
-		ret =
-		    platform_device_add_data(usb_dev_mph, &usb_data,
-					     sizeof(struct
-						    fsl_usb2_platform_data));
-		if (ret)
-			goto unreg_mph;
-		i++;
-	}
-
-	for_each_compatible_node(np, NULL, "fsl-usb2-dr") {
-		struct resource r[2];
-		struct fsl_usb2_platform_data usb_data;
-		const unsigned char *prop = NULL;
-
-		if (!of_device_is_available(np))
-			continue;
-
-		memset(&r, 0, sizeof(r));
-		memset(&usb_data, 0, sizeof(usb_data));
-
-		ret = of_address_to_resource(np, 0, &r[0]);
-		if (ret)
-			goto unreg_mph;
-
-		of_irq_to_resource(np, 0, &r[1]);
-
-		prop = of_get_property(np, "dr_mode", NULL);
-
-		if (!prop || !strcmp(prop, "host")) {
-			usb_data.operating_mode = FSL_USB2_DR_HOST;
-			usb_dev_dr_host = platform_device_register_simple(
-					"fsl-ehci", i, r, 2);
-			if (IS_ERR(usb_dev_dr_host)) {
-				ret = PTR_ERR(usb_dev_dr_host);
-				goto err;
-			}
-		} else if (prop && !strcmp(prop, "peripheral")) {
-			usb_data.operating_mode = FSL_USB2_DR_DEVICE;
-			usb_dev_dr_client = platform_device_register_simple(
-					"fsl-usb2-udc", i, r, 2);
-			if (IS_ERR(usb_dev_dr_client)) {
-				ret = PTR_ERR(usb_dev_dr_client);
-				goto err;
-			}
-		} else if (prop && !strcmp(prop, "otg")) {
-			usb_data.operating_mode = FSL_USB2_DR_OTG;
-			usb_dev_dr_host = platform_device_register_simple(
-					"fsl-ehci", i, r, 2);
-			if (IS_ERR(usb_dev_dr_host)) {
-				ret = PTR_ERR(usb_dev_dr_host);
-				goto err;
-			}
-			usb_dev_dr_client = platform_device_register_simple(
-					"fsl-usb2-udc", i, r, 2);
-			if (IS_ERR(usb_dev_dr_client)) {
-				ret = PTR_ERR(usb_dev_dr_client);
-				goto err;
-			}
-		} else {
-			ret = -EINVAL;
-			goto err;
-		}
-
-		prop = of_get_property(np, "phy_type", NULL);
-		usb_data.phy_mode = determine_usb_phy(prop);
-
-		if (usb_dev_dr_host) {
-			usb_dev_dr_host->dev.coherent_dma_mask = 0xffffffffUL;
-			usb_dev_dr_host->dev.dma_mask = &usb_dev_dr_host->
-				dev.coherent_dma_mask;
-			if ((ret = platform_device_add_data(usb_dev_dr_host,
-						&usb_data, sizeof(struct
-						fsl_usb2_platform_data))))
-				goto unreg_dr;
-		}
-		if (usb_dev_dr_client) {
-			usb_dev_dr_client->dev.coherent_dma_mask = 0xffffffffUL;
-			usb_dev_dr_client->dev.dma_mask = &usb_dev_dr_client->
-				dev.coherent_dma_mask;
-			if ((ret = platform_device_add_data(usb_dev_dr_client,
-						&usb_data, sizeof(struct
-						fsl_usb2_platform_data))))
-				goto unreg_dr;
-		}
-		i++;
-	}
-	return 0;
-
-unreg_dr:
-	if (usb_dev_dr_host)
-		platform_device_unregister(usb_dev_dr_host);
-	if (usb_dev_dr_client)
-		platform_device_unregister(usb_dev_dr_client);
-unreg_mph:
-	if (usb_dev_mph)
-		platform_device_unregister(usb_dev_mph);
-err:
-	return ret;
-}
-
-arch_initcall(fsl_usb_of_init);
-
 #if defined(CONFIG_FSL_SOC_BOOKE) || defined(CONFIG_PPC_86xx)
 static __be32 __iomem *rstcr;
 
diff --git a/drivers/usb/gadget/Kconfig b/drivers/usb/gadget/Kconfig
index fab765d..0fe5bc8 100644
--- a/drivers/usb/gadget/Kconfig
+++ b/drivers/usb/gadget/Kconfig
@@ -158,6 +158,7 @@ config USB_GADGET_FSL_USB2
 	boolean "Freescale Highspeed USB DR Peripheral Controller"
 	depends on FSL_SOC || ARCH_MXC
 	select USB_GADGET_DUALSPEED
+	select USB_FSL_MPH_DR_OF
 	help
 	   Some of Freescale PowerPC processors have a High Speed
 	   Dual-Role(DR) USB controller, which supports device mode.
diff --git a/drivers/usb/host/Kconfig b/drivers/usb/host/Kconfig
index 2d926ce..f3a90b0 100644
--- a/drivers/usb/host/Kconfig
+++ b/drivers/usb/host/Kconfig
@@ -112,10 +112,14 @@ config XPS_USB_HCD_XILINX
 		support both high speed and full speed devices, or high speed
 		devices only.
 
+config USB_FSL_MPH_DR_OF
+	tristate
+
 config USB_EHCI_FSL
 	bool "Support for Freescale on-chip EHCI USB controller"
 	depends on USB_EHCI_HCD && FSL_SOC
 	select USB_EHCI_ROOT_HUB_TT
+	select USB_FSL_MPH_DR_OF
 	---help---
 	  Variation of ARC USB block used in some Freescale chips.
 
diff --git a/drivers/usb/host/Makefile b/drivers/usb/host/Makefile
index b6315aa..aacbe82 100644
--- a/drivers/usb/host/Makefile
+++ b/drivers/usb/host/Makefile
@@ -33,4 +33,5 @@ obj-$(CONFIG_USB_R8A66597_HCD)	+= r8a66597-hcd.o
 obj-$(CONFIG_USB_ISP1760_HCD)	+= isp1760.o
 obj-$(CONFIG_USB_HWA_HCD)	+= hwa-hc.o
 obj-$(CONFIG_USB_IMX21_HCD)	+= imx21-hcd.o
+obj-$(CONFIG_USB_FSL_MPH_DR_OF)	+= fsl-mph-dr-of.o
 
diff --git a/drivers/usb/host/fsl-mph-dr-of.c b/drivers/usb/host/fsl-mph-dr-of.c
new file mode 100644
index 0000000..12db5d5
--- /dev/null
+++ b/drivers/usb/host/fsl-mph-dr-of.c
@@ -0,0 +1,219 @@
+/*
+ * Setup platform devices needed by the Freescale multi-port host
+ * and/or dual-role USB controller modules based on the description
+ * in flat device tree.
+ *
+ * This program is free software; you can redistribute  it and/or modify it
+ * under  the terms of  the GNU General  Public License as published by the
+ * Free Software Foundation;  either version 2 of the  License, or (at your
+ * option) any later version.
+ */
+
+#include <linux/kernel.h>
+#include <linux/platform_device.h>
+#include <linux/fsl_devices.h>
+#include <linux/err.h>
+#include <linux/io.h>
+#include <linux/of_platform.h>
+
+struct fsl_usb2_dev_data {
+	char *dr_mode;		/* controller mode */
+	char *drivers[3];	/* drivers to instantiate for this mode */
+	enum fsl_usb2_operating_modes op_mode;	/* operating mode */
+};
+
+struct fsl_usb2_dev_data dr_mode_data[] __devinitdata = {
+	{
+		.dr_mode = "host",
+		.drivers = { "fsl-ehci", NULL, NULL, },
+		.op_mode = FSL_USB2_DR_HOST,
+	},
+	{
+		.dr_mode = "otg",
+		.drivers = { "fsl-usb2-otg", "fsl-ehci", "fsl-usb2-udc", },
+		.op_mode = FSL_USB2_DR_OTG,
+	},
+	{
+		.dr_mode = "peripheral",
+		.drivers = { "fsl-usb2-udc", NULL, NULL, },
+		.op_mode = FSL_USB2_DR_DEVICE,
+	},
+};
+
+struct fsl_usb2_dev_data * __devinit get_dr_mode_data(struct device_node *np)
+{
+	const unsigned char *prop;
+	int i;
+
+	prop = of_get_property(np, "dr_mode", NULL);
+	if (prop) {
+		for (i = 0; i < ARRAY_SIZE(dr_mode_data); i++) {
+			if (!strcmp(prop, dr_mode_data[i].dr_mode))
+				return &dr_mode_data[i];
+		}
+	}
+	pr_warn("%s: Invalid 'dr_mode' property, fallback to host mode\n",
+		np->full_name);
+	return &dr_mode_data[0]; /* mode not specified, use host */
+}
+
+static enum fsl_usb2_phy_modes __devinit determine_usb_phy(const char *phy_type)
+{
+	if (!phy_type)
+		return FSL_USB2_PHY_NONE;
+	if (!strcasecmp(phy_type, "ulpi"))
+		return FSL_USB2_PHY_ULPI;
+	if (!strcasecmp(phy_type, "utmi"))
+		return FSL_USB2_PHY_UTMI;
+	if (!strcasecmp(phy_type, "utmi_wide"))
+		return FSL_USB2_PHY_UTMI_WIDE;
+	if (!strcasecmp(phy_type, "serial"))
+		return FSL_USB2_PHY_SERIAL;
+
+	return FSL_USB2_PHY_NONE;
+}
+
+struct platform_device * __devinit fsl_usb2_device_register(
+					struct platform_device *ofdev,
+					struct fsl_usb2_platform_data *pdata,
+					const char *name, int id)
+{
+	struct platform_device *pdev;
+	const struct resource *res = ofdev->resource;
+	unsigned int num = ofdev->num_resources;
+	int retval;
+
+	pdev = platform_device_alloc(name, id);
+	if (!pdev) {
+		retval = -ENOMEM;
+		goto error;
+	}
+
+	pdev->dev.parent = &ofdev->dev;
+
+	pdev->dev.coherent_dma_mask = ofdev->dev.coherent_dma_mask;
+	pdev->dev.dma_mask = &pdev->archdata.dma_mask;
+	*pdev->dev.dma_mask = *ofdev->dev.dma_mask;
+
+	retval = platform_device_add_data(pdev, pdata, sizeof(*pdata));
+	if (retval)
+		goto error;
+
+	if (num) {
+		retval = platform_device_add_resources(pdev, res, num);
+		if (retval)
+			goto error;
+	}
+
+	retval = platform_device_add(pdev);
+	if (retval)
+		goto error;
+
+	return pdev;
+
+error:
+	platform_device_put(pdev);
+	return ERR_PTR(retval);
+}
+
+static const struct of_device_id fsl_usb2_mph_dr_of_match[];
+
+static int __devinit fsl_usb2_mph_dr_of_probe(struct platform_device *ofdev)
+{
+	struct device_node *np = ofdev->dev.of_node;
+	struct platform_device *usb_dev;
+	struct fsl_usb2_platform_data data, *pdata;
+	struct fsl_usb2_dev_data *dev_data;
+	const struct of_device_id *match;
+	const unsigned char *prop;
+	static unsigned int idx;
+	int i;
+
+	if (!of_device_is_available(np))
+		return -ENODEV;
+
+	match = of_match_device(fsl_usb2_mph_dr_of_match, &ofdev->dev);
+	if (!match)
+		return -ENODEV;
+
+	pdata = &data;
+	if (match->data)
+		memcpy(pdata, match->data, sizeof(data));
+	else
+		memset(pdata, 0, sizeof(data));
+
+	dev_data = get_dr_mode_data(np);
+
+	if (of_device_is_compatible(np, "fsl-usb2-mph")) {
+		if (of_get_property(np, "port0", NULL))
+			pdata->port_enables |= FSL_USB2_PORT0_ENABLED;
+
+		if (of_get_property(np, "port1", NULL))
+			pdata->port_enables |= FSL_USB2_PORT1_ENABLED;
+
+		pdata->operating_mode = FSL_USB2_MPH_HOST;
+	} else {
+		/* setup mode selected in the device tree */
+		pdata->operating_mode = dev_data->op_mode;
+	}
+
+	prop = of_get_property(np, "phy_type", NULL);
+	pdata->phy_mode = determine_usb_phy(prop);
+
+	for (i = 0; i < ARRAY_SIZE(dev_data->drivers); i++) {
+		if (!dev_data->drivers[i])
+			continue;
+		usb_dev = fsl_usb2_device_register(ofdev, pdata,
+					dev_data->drivers[i], idx);
+		if (IS_ERR(usb_dev)) {
+			dev_err(&ofdev->dev, "Can't register usb device\n");
+			return PTR_ERR(usb_dev);
+		}
+	}
+	idx++;
+	return 0;
+}
+
+static int __devexit __unregister_subdev(struct device *dev, void *d)
+{
+	platform_device_unregister(to_platform_device(dev));
+	return 0;
+}
+
+static int __devexit fsl_usb2_mph_dr_of_remove(struct platform_device *ofdev)
+{
+	device_for_each_child(&ofdev->dev, NULL, __unregister_subdev);
+	return 0;
+}
+
+static const struct of_device_id fsl_usb2_mph_dr_of_match[] = {
+	{ .compatible = "fsl-usb2-mph", },
+	{ .compatible = "fsl-usb2-dr", },
+	{},
+};
+
+static struct platform_driver fsl_usb2_mph_dr_driver = {
+	.driver = {
+		.name = "fsl-usb2-mph-dr",
+		.owner = THIS_MODULE,
+		.of_match_table = fsl_usb2_mph_dr_of_match,
+	},
+	.probe	= fsl_usb2_mph_dr_of_probe,
+	.remove	= __devexit_p(fsl_usb2_mph_dr_of_remove),
+};
+
+static int __init fsl_usb2_mph_dr_init(void)
+{
+	return platform_driver_register(&fsl_usb2_mph_dr_driver);
+}
+module_init(fsl_usb2_mph_dr_init);
+
+static void __exit fsl_usb2_mph_dr_exit(void)
+{
+	platform_driver_unregister(&fsl_usb2_mph_dr_driver);
+}
+module_exit(fsl_usb2_mph_dr_exit);
+
+MODULE_DESCRIPTION("FSL MPH DR OF devices driver");
+MODULE_AUTHOR("Anatolij Gustschin <agust@denx.de>");
+MODULE_LICENSE("GPL");
-- 
1.7.0.4

^ permalink raw reply related	[flat|nested] 10+ messages in thread

* [PATCH v3 2/2] USB: add USB EHCI support for MPC5121 SoC
  2010-09-28  9:36 [PATCH v2 0/3] Add USB Host support for MPC5121 SoC Anatolij Gustschin
                   ` (4 preceding siblings ...)
  2010-09-28 18:55 ` [PATCH v3 1/2] USB: add platform glue driver for FSL USB DR controller Anatolij Gustschin
@ 2010-09-28 18:55 ` Anatolij Gustschin
  5 siblings, 0 replies; 10+ messages in thread
From: Anatolij Gustschin @ 2010-09-28 18:55 UTC (permalink / raw)
  To: linux-usb
  Cc: David Brownell, Wolfgang Denk, Detlev Zundel, Greg Kroah-Hartman,
	linuxppc-dev, Anatolij Gustschin

Extends FSL EHCI platform driver glue layer to support
MPC5121 USB controllers. MPC5121 Rev 2.0 silicon EHCI
registers are in big endian format. The appropriate flags
are set using the information in the platform data structure.
MPC83xx system interface registers are not available on
MPC512x, so the access to these registers is isolated in
MPC512x case. Furthermore the USB controller clocks
must be enabled before 512x register accesses which is
done by providing platform specific init callback.

The MPC512x internal USB PHY doesn't provide supply voltage.
For boards using different power switches allow specifying
DRVVBUS and PWR_FAULT signal polarity of the MPC5121 internal
PHY using "fsl,invert-drvvbus" and "fsl,invert-pwr-fault"
properties in the device tree USB nodes. Adds documentation
for this new device tree bindings.

Signed-off-by: Anatolij Gustschin <agust@denx.de>
Cc: Grant Likely <grant.likely@secretlab.ca>
---
v3:
 - rebased after changing of_platform_driver to platform_driver

 Documentation/powerpc/dts-bindings/fsl/usb.txt |   22 +++++
 drivers/usb/Kconfig                            |    1 +
 drivers/usb/host/Kconfig                       |    6 +-
 drivers/usb/host/ehci-fsl.c                    |   99 +++++++++++++++++-------
 drivers/usb/host/ehci-fsl.h                    |   13 +++-
 drivers/usb/host/ehci-mem.c                    |    2 +-
 drivers/usb/host/fsl-mph-dr-of.c               |   89 +++++++++++++++++++++
 include/linux/fsl_devices.h                    |   15 ++++
 8 files changed, 215 insertions(+), 32 deletions(-)

diff --git a/Documentation/powerpc/dts-bindings/fsl/usb.txt b/Documentation/powerpc/dts-bindings/fsl/usb.txt
index b001524..bd5723f 100644
--- a/Documentation/powerpc/dts-bindings/fsl/usb.txt
+++ b/Documentation/powerpc/dts-bindings/fsl/usb.txt
@@ -8,6 +8,7 @@ and additions :
 Required properties :
  - compatible : Should be "fsl-usb2-mph" for multi port host USB
    controllers, or "fsl-usb2-dr" for dual role USB controllers
+   or "fsl,mpc5121-usb2-dr" for dual role USB controllers of MPC5121
  - phy_type : For multi port host USB controllers, should be one of
    "ulpi", or "serial". For dual role USB controllers, should be
    one of "ulpi", "utmi", "utmi_wide", or "serial".
@@ -33,6 +34,12 @@ Recommended properties :
  - interrupt-parent : the phandle for the interrupt controller that
    services interrupts for this device.
 
+Optional properties :
+ - fsl,invert-drvvbus : boolean; for MPC5121 USB0 only. Indicates the
+   port power polarity of internal PHY signal DRVVBUS is inverted.
+ - fsl,invert-pwr-fault : boolean; for MPC5121 USB0 only. Indicates
+   the PWR_FAULT signal polarity is inverted.
+
 Example multi port host USB controller device node :
 	usb@22000 {
 		compatible = "fsl-usb2-mph";
@@ -57,3 +64,18 @@ Example dual role USB controller device node :
 		dr_mode = "otg";
 		phy = "ulpi";
 	};
+
+Example dual role USB controller device node for MPC5121ADS:
+
+	usb@4000 {
+		compatible = "fsl,mpc5121-usb2-dr";
+		reg = <0x4000 0x1000>;
+		#address-cells = <1>;
+		#size-cells = <0>;
+		interrupt-parent = < &ipic >;
+		interrupts = <44 0x8>;
+		dr_mode = "otg";
+		phy_type = "utmi_wide";
+		fsl,invert-drvvbus;
+		fsl,invert-pwr-fault;
+	};
diff --git a/drivers/usb/Kconfig b/drivers/usb/Kconfig
index 4aa00e6..67eb377 100644
--- a/drivers/usb/Kconfig
+++ b/drivers/usb/Kconfig
@@ -59,6 +59,7 @@ config USB_ARCH_HAS_OHCI
 config USB_ARCH_HAS_EHCI
 	boolean
 	default y if PPC_83xx
+	default y if PPC_MPC512x
 	default y if SOC_AU1200
 	default y if ARCH_IXP4XX
 	default y if ARCH_W90X900
diff --git a/drivers/usb/host/Kconfig b/drivers/usb/host/Kconfig
index f3a90b0..bf2e7d2 100644
--- a/drivers/usb/host/Kconfig
+++ b/drivers/usb/host/Kconfig
@@ -93,12 +93,14 @@ config USB_EHCI_TT_NEWSCHED
 
 config USB_EHCI_BIG_ENDIAN_MMIO
 	bool
-	depends on USB_EHCI_HCD && (PPC_CELLEB || PPC_PS3 || 440EPX || ARCH_IXP4XX || XPS_USB_HCD_XILINX)
+	depends on USB_EHCI_HCD && (PPC_CELLEB || PPC_PS3 || 440EPX || ARCH_IXP4XX || \
+				    XPS_USB_HCD_XILINX || PPC_MPC512x)
 	default y
 
 config USB_EHCI_BIG_ENDIAN_DESC
 	bool
-	depends on USB_EHCI_HCD && (440EPX || ARCH_IXP4XX || XPS_USB_HCD_XILINX)
+	depends on USB_EHCI_HCD && (440EPX || ARCH_IXP4XX || XPS_USB_HCD_XILINX || \
+				    PPC_MPC512x)
 	default y
 
 config XPS_USB_HCD_XILINX
diff --git a/drivers/usb/host/ehci-fsl.c b/drivers/usb/host/ehci-fsl.c
index 8600317..86e4289 100644
--- a/drivers/usb/host/ehci-fsl.c
+++ b/drivers/usb/host/ehci-fsl.c
@@ -116,13 +116,33 @@ static int usb_hcd_fsl_probe(const struct hc_driver *driver,
 		goto err3;
 	}
 
-	/* Enable USB controller */
-	temp = in_be32(hcd->regs + 0x500);
-	out_be32(hcd->regs + 0x500, temp | 0x4);
+	pdata->regs = hcd->regs;
 
-	/* Set to Host mode */
-	temp = in_le32(hcd->regs + 0x1a8);
-	out_le32(hcd->regs + 0x1a8, temp | 0x3);
+	/*
+	 * do platform specific init: check the clock, grab/config pins, etc.
+	 */
+	if (pdata->init && pdata->init(pdev)) {
+		retval = -ENODEV;
+		goto err3;
+	}
+
+	/*
+	 * Check if it is MPC5121 SoC, otherwise set pdata->have_sysif_regs
+	 * flag for 83xx or 8536 system interface registers.
+	 */
+	if (pdata->big_endian_mmio)
+		temp = in_be32(hcd->regs + FSL_SOC_USB_ID);
+	else
+		temp = in_le32(hcd->regs + FSL_SOC_USB_ID);
+
+	if ((temp & ID_MSK) != (~((temp & NID_MSK) >> 8) & ID_MSK))
+		pdata->have_sysif_regs = 1;
+
+	/* Enable USB controller, 83xx or 8536 */
+	if (pdata->have_sysif_regs)
+		setbits32(hcd->regs + FSL_SOC_USB_CTRL, 0x4);
+
+	/* Don't need to set host mode here. It will be done by tdi_reset() */
 
 	retval = usb_add_hcd(hcd, irq, IRQF_DISABLED | IRQF_SHARED);
 	if (retval != 0)
@@ -137,6 +157,8 @@ static int usb_hcd_fsl_probe(const struct hc_driver *driver,
 	usb_put_hcd(hcd);
       err1:
 	dev_err(&pdev->dev, "init %s fail, %d\n", dev_name(&pdev->dev), retval);
+	if (pdata->exit)
+		pdata->exit(pdev);
 	return retval;
 }
 
@@ -154,17 +176,30 @@ static int usb_hcd_fsl_probe(const struct hc_driver *driver,
 static void usb_hcd_fsl_remove(struct usb_hcd *hcd,
 			       struct platform_device *pdev)
 {
+	struct fsl_usb2_platform_data *pdata = pdev->dev.platform_data;
+
 	usb_remove_hcd(hcd);
+
+	/*
+	 * do platform specific un-initialization:
+	 * release iomux pins, disable clock, etc.
+	 */
+	if (pdata->exit)
+		pdata->exit(pdev);
 	iounmap(hcd->regs);
 	release_mem_region(hcd->rsrc_start, hcd->rsrc_len);
 	usb_put_hcd(hcd);
 }
 
-static void mpc83xx_setup_phy(struct ehci_hcd *ehci,
-			      enum fsl_usb2_phy_modes phy_mode,
-			      unsigned int port_offset)
+static void ehci_fsl_setup_phy(struct ehci_hcd *ehci,
+			       enum fsl_usb2_phy_modes phy_mode,
+			       unsigned int port_offset)
 {
-	u32 portsc = 0;
+	u32 portsc;
+
+	portsc = ehci_readl(ehci, &ehci->regs->port_status[port_offset]);
+	portsc &= ~(PORT_PTS_MSK | PORT_PTS_PTW);
+
 	switch (phy_mode) {
 	case FSL_USB2_PHY_ULPI:
 		portsc |= PORT_PTS_ULPI;
@@ -184,20 +219,21 @@ static void mpc83xx_setup_phy(struct ehci_hcd *ehci,
 	ehci_writel(ehci, portsc, &ehci->regs->port_status[port_offset]);
 }
 
-static void mpc83xx_usb_setup(struct usb_hcd *hcd)
+static void ehci_fsl_usb_setup(struct ehci_hcd *ehci)
 {
-	struct ehci_hcd *ehci = hcd_to_ehci(hcd);
+	struct usb_hcd *hcd = ehci_to_hcd(ehci);
 	struct fsl_usb2_platform_data *pdata;
 	void __iomem *non_ehci = hcd->regs;
 	u32 temp;
 
-	pdata =
-	    (struct fsl_usb2_platform_data *)hcd->self.controller->
-	    platform_data;
+	pdata = hcd->self.controller->platform_data;
+
 	/* Enable PHY interface in the control reg. */
-	temp = in_be32(non_ehci + FSL_SOC_USB_CTRL);
-	out_be32(non_ehci + FSL_SOC_USB_CTRL, temp | 0x00000004);
-	out_be32(non_ehci + FSL_SOC_USB_SNOOP1, 0x0000001b);
+	if (pdata->have_sysif_regs) {
+		temp = in_be32(non_ehci + FSL_SOC_USB_CTRL);
+		out_be32(non_ehci + FSL_SOC_USB_CTRL, temp | 0x00000004);
+		out_be32(non_ehci + FSL_SOC_USB_SNOOP1, 0x0000001b);
+	}
 
 #if defined(CONFIG_PPC32) && !defined(CONFIG_NOT_COHERENT_CACHE)
 	/*
@@ -214,7 +250,7 @@ static void mpc83xx_usb_setup(struct usb_hcd *hcd)
 
 	if ((pdata->operating_mode == FSL_USB2_DR_HOST) ||
 			(pdata->operating_mode == FSL_USB2_DR_OTG))
-		mpc83xx_setup_phy(ehci, pdata->phy_mode, 0);
+		ehci_fsl_setup_phy(ehci, pdata->phy_mode, 0);
 
 	if (pdata->operating_mode == FSL_USB2_MPH_HOST) {
 		unsigned int chip, rev, svr;
@@ -228,25 +264,27 @@ static void mpc83xx_usb_setup(struct usb_hcd *hcd)
 			ehci->has_fsl_port_bug = 1;
 
 		if (pdata->port_enables & FSL_USB2_PORT0_ENABLED)
-			mpc83xx_setup_phy(ehci, pdata->phy_mode, 0);
+			ehci_fsl_setup_phy(ehci, pdata->phy_mode, 0);
 		if (pdata->port_enables & FSL_USB2_PORT1_ENABLED)
-			mpc83xx_setup_phy(ehci, pdata->phy_mode, 1);
+			ehci_fsl_setup_phy(ehci, pdata->phy_mode, 1);
 	}
 
+	if (pdata->have_sysif_regs) {
 #ifdef CONFIG_PPC_85xx
-	out_be32(non_ehci + FSL_SOC_USB_PRICTRL, 0x00000008);
-	out_be32(non_ehci + FSL_SOC_USB_AGECNTTHRSH, 0x00000080);
+		out_be32(non_ehci + FSL_SOC_USB_PRICTRL, 0x00000008);
+		out_be32(non_ehci + FSL_SOC_USB_AGECNTTHRSH, 0x00000080);
 #else
-	out_be32(non_ehci + FSL_SOC_USB_PRICTRL, 0x0000000c);
-	out_be32(non_ehci + FSL_SOC_USB_AGECNTTHRSH, 0x00000040);
+		out_be32(non_ehci + FSL_SOC_USB_PRICTRL, 0x0000000c);
+		out_be32(non_ehci + FSL_SOC_USB_AGECNTTHRSH, 0x00000040);
 #endif
-	out_be32(non_ehci + FSL_SOC_USB_SICTRL, 0x00000001);
+		out_be32(non_ehci + FSL_SOC_USB_SICTRL, 0x00000001);
+	}
 }
 
 /* called after powerup, by probe or system-pm "wakeup" */
 static int ehci_fsl_reinit(struct ehci_hcd *ehci)
 {
-	mpc83xx_usb_setup(ehci_to_hcd(ehci));
+	ehci_fsl_usb_setup(ehci);
 	ehci_port_power(ehci, 0);
 
 	return 0;
@@ -257,6 +295,11 @@ static int ehci_fsl_setup(struct usb_hcd *hcd)
 {
 	struct ehci_hcd *ehci = hcd_to_ehci(hcd);
 	int retval;
+	struct fsl_usb2_platform_data *pdata;
+
+	pdata = hcd->self.controller->platform_data;
+	ehci->big_endian_desc = pdata->big_endian_desc;
+	ehci->big_endian_mmio = pdata->big_endian_mmio;
 
 	/* EHCI registers start at offset 0x100 */
 	ehci->caps = hcd->regs + 0x100;
@@ -370,7 +413,7 @@ static const struct hc_driver ehci_fsl_hc_driver = {
 	 * generic hardware linkage
 	 */
 	.irq = ehci_irq,
-	.flags = HCD_USB2,
+	.flags = HCD_USB2 | HCD_MEMORY,
 
 	/*
 	 * basic lifecycle operations
diff --git a/drivers/usb/host/ehci-fsl.h b/drivers/usb/host/ehci-fsl.h
index eb537aa..2c83537 100644
--- a/drivers/usb/host/ehci-fsl.h
+++ b/drivers/usb/host/ehci-fsl.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2005 freescale semiconductor
+/* Copyright (C) 2005-2010 Freescale Semiconductor, Inc.
  * Copyright (c) 2005 MontaVista Software
  *
  * This program is free software; you can redistribute  it and/or modify it
@@ -19,6 +19,9 @@
 #define _EHCI_FSL_H
 
 /* offsets for the non-ehci registers in the FSL SOC USB controller */
+#define FSL_SOC_USB_ID		0x0
+#define ID_MSK			0x3f
+#define NID_MSK			0x3f00
 #define FSL_SOC_USB_ULPIVP	0x170
 #define FSL_SOC_USB_PORTSC1	0x184
 #define PORT_PTS_MSK		(3<<30)
@@ -27,6 +30,14 @@
 #define	PORT_PTS_SERIAL		(3<<30)
 #define PORT_PTS_PTW		(1<<28)
 #define FSL_SOC_USB_PORTSC2	0x188
+
+#define FSL_SOC_USB_USBGENCTRL	0x200
+#define USBGENCTRL_PPP		(1 << 3)
+#define USBGENCTRL_PFP		(1 << 2)
+#define FSL_SOC_USB_ISIPHYCTRL	0x204
+#define ISIPHYCTRL_PXE		(1)
+#define ISIPHYCTRL_PHYE		(1 << 4)
+
 #define FSL_SOC_USB_SNOOP1	0x400	/* NOTE: big-endian */
 #define FSL_SOC_USB_SNOOP2	0x404	/* NOTE: big-endian */
 #define FSL_SOC_USB_AGECNTTHRSH	0x408	/* NOTE: big-endian */
diff --git a/drivers/usb/host/ehci-mem.c b/drivers/usb/host/ehci-mem.c
index 1f3f01e..d36e4e7 100644
--- a/drivers/usb/host/ehci-mem.c
+++ b/drivers/usb/host/ehci-mem.c
@@ -40,7 +40,7 @@ static inline void ehci_qtd_init(struct ehci_hcd *ehci, struct ehci_qtd *qtd,
 {
 	memset (qtd, 0, sizeof *qtd);
 	qtd->qtd_dma = dma;
-	qtd->hw_token = cpu_to_le32 (QTD_STS_HALT);
+	qtd->hw_token = cpu_to_hc32(ehci, QTD_STS_HALT);
 	qtd->hw_next = EHCI_LIST_END(ehci);
 	qtd->hw_alt_next = EHCI_LIST_END(ehci);
 	INIT_LIST_HEAD (&qtd->qtd_list);
diff --git a/drivers/usb/host/fsl-mph-dr-of.c b/drivers/usb/host/fsl-mph-dr-of.c
index 12db5d5..574b99e 100644
--- a/drivers/usb/host/fsl-mph-dr-of.c
+++ b/drivers/usb/host/fsl-mph-dr-of.c
@@ -15,6 +15,7 @@
 #include <linux/err.h>
 #include <linux/io.h>
 #include <linux/of_platform.h>
+#include <linux/clk.h>
 
 struct fsl_usb2_dev_data {
 	char *dr_mode;		/* controller mode */
@@ -153,6 +154,12 @@ static int __devinit fsl_usb2_mph_dr_of_probe(struct platform_device *ofdev)
 
 		pdata->operating_mode = FSL_USB2_MPH_HOST;
 	} else {
+		if (of_get_property(np, "fsl,invert-drvvbus", NULL))
+			pdata->invert_drvvbus = 1;
+
+		if (of_get_property(np, "fsl,invert-pwr-fault", NULL))
+			pdata->invert_pwr_fault = 1;
+
 		/* setup mode selected in the device tree */
 		pdata->operating_mode = dev_data->op_mode;
 	}
@@ -186,9 +193,91 @@ static int __devexit fsl_usb2_mph_dr_of_remove(struct platform_device *ofdev)
 	return 0;
 }
 
+#ifdef CONFIG_PPC_MPC512x
+
+#define USBGENCTRL		0x200		/* NOTE: big endian */
+#define GC_WU_INT_CLR		(1 << 5)	/* Wakeup int clear */
+#define GC_ULPI_SEL		(1 << 4)	/* ULPI i/f select (usb0 only)*/
+#define GC_PPP			(1 << 3)	/* Inv. Port Power Polarity */
+#define GC_PFP			(1 << 2)	/* Inv. Power Fault Polarity */
+#define GC_WU_ULPI_EN		(1 << 1)	/* Wakeup on ULPI event */
+#define GC_WU_IE		(1 << 1)	/* Wakeup interrupt enable */
+
+#define ISIPHYCTRL		0x204		/* NOTE: big endian */
+#define PHYCTRL_PHYE		(1 << 4)	/* On-chip UTMI PHY enable */
+#define PHYCTRL_BSENH		(1 << 3)	/* Bit Stuff Enable High */
+#define PHYCTRL_BSEN		(1 << 2)	/* Bit Stuff Enable */
+#define PHYCTRL_LSFE		(1 << 1)	/* Line State Filter Enable */
+#define PHYCTRL_PXE		(1 << 0)	/* PHY oscillator enable */
+
+int fsl_usb2_mpc5121_init(struct platform_device *pdev)
+{
+	struct fsl_usb2_platform_data *pdata = pdev->dev.platform_data;
+	struct clk *clk;
+	char clk_name[10];
+	int base, clk_num;
+
+	base = pdev->resource->start & 0xf000;
+	if (base == 0x3000)
+		clk_num = 1;
+	else if (base == 0x4000)
+		clk_num = 2;
+	else
+		return -ENODEV;
+
+	snprintf(clk_name, sizeof(clk_name), "usb%d_clk", clk_num);
+	clk = clk_get(&pdev->dev, clk_name);
+	if (IS_ERR(clk)) {
+		dev_err(&pdev->dev, "failed to get clk\n");
+		return PTR_ERR(clk);
+	}
+
+	clk_enable(clk);
+	pdata->clk = clk;
+
+	if (pdata->phy_mode == FSL_USB2_PHY_UTMI_WIDE) {
+		u32 reg = 0;
+
+		if (pdata->invert_drvvbus)
+			reg |= GC_PPP;
+
+		if (pdata->invert_pwr_fault)
+			reg |= GC_PFP;
+
+		out_be32(pdata->regs + ISIPHYCTRL, PHYCTRL_PHYE | PHYCTRL_PXE);
+		out_be32(pdata->regs + USBGENCTRL, reg);
+	}
+	return 0;
+}
+
+static void fsl_usb2_mpc5121_exit(struct platform_device *pdev)
+{
+	struct fsl_usb2_platform_data *pdata = pdev->dev.platform_data;
+
+	pdata->regs = NULL;
+
+	if (pdata->clk) {
+		clk_disable(pdata->clk);
+		clk_put(pdata->clk);
+	}
+}
+
+struct fsl_usb2_platform_data fsl_usb2_mpc5121_pd = {
+	.big_endian_desc = 1,
+	.big_endian_mmio = 1,
+	.es = 1,
+	.le_setup_buf = 1,
+	.init = fsl_usb2_mpc5121_init,
+	.exit = fsl_usb2_mpc5121_exit,
+};
+#endif /* CONFIG_PPC_MPC512x */
+
 static const struct of_device_id fsl_usb2_mph_dr_of_match[] = {
 	{ .compatible = "fsl-usb2-mph", },
 	{ .compatible = "fsl-usb2-dr", },
+#ifdef CONFIG_PPC_MPC512x
+	{ .compatible = "fsl,mpc5121-usb2-dr", .data = &fsl_usb2_mpc5121_pd, },
+#endif
 	{},
 };
 
diff --git a/include/linux/fsl_devices.h b/include/linux/fsl_devices.h
index 28e33fe..d5f9a74 100644
--- a/include/linux/fsl_devices.h
+++ b/include/linux/fsl_devices.h
@@ -58,11 +58,26 @@ enum fsl_usb2_phy_modes {
 	FSL_USB2_PHY_SERIAL,
 };
 
+struct clk;
+struct platform_device;
+
 struct fsl_usb2_platform_data {
 	/* board specific information */
 	enum fsl_usb2_operating_modes	operating_mode;
 	enum fsl_usb2_phy_modes		phy_mode;
 	unsigned int			port_enables;
+
+	int		(*init)(struct platform_device *);
+	void		(*exit)(struct platform_device *);
+	void __iomem	*regs;		/* ioremap'd register base */
+	struct clk	*clk;
+	unsigned	big_endian_mmio:1;
+	unsigned	big_endian_desc:1;
+	unsigned	es:1;		/* need USBMODE:ES */
+	unsigned	le_setup_buf:1;
+	unsigned	have_sysif_regs:1;
+	unsigned	invert_drvvbus:1;
+	unsigned	invert_pwr_fault:1;
 };
 
 /* Flags in fsl_usb2_mph_platform_data */
-- 
1.7.0.4

^ permalink raw reply related	[flat|nested] 10+ messages in thread

end of thread, other threads:[~2010-09-28 18:57 UTC | newest]

Thread overview: 10+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2010-09-28  9:36 [PATCH v2 0/3] Add USB Host support for MPC5121 SoC Anatolij Gustschin
2010-09-28  9:36 ` [PATCH v2 1/3] powerpc/fsl_soc.c: remove FSL USB platform code Anatolij Gustschin
2010-09-28 11:40   ` Anton Vorontsov
2010-09-28  9:36 ` [PATCH v2 2/3] USB: add of_platform glue driver for FSL USB DR controller Anatolij Gustschin
2010-09-28 10:01   ` Grant Likely
2010-09-28 11:35     ` Anatolij Gustschin
2010-09-28  9:36 ` [PATCH v2 3/3] USB: add USB EHCI support for MPC5121 SoC Anatolij Gustschin
2010-09-28 18:55 ` [PATCH v3 0/2] Add USB Host " Anatolij Gustschin
2010-09-28 18:55 ` [PATCH v3 1/2] USB: add platform glue driver for FSL USB DR controller Anatolij Gustschin
2010-09-28 18:55 ` [PATCH v3 2/2] USB: add USB EHCI support for MPC5121 SoC Anatolij Gustschin

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).