[PATCH 3/3] usb: phy: ulpi: implement creating a phy via oftree

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

 



Todo: binding document, more properties

Signed-off-by: Uwe Kleine-König <u.kleine-koenig@xxxxxxxxxxxxxx>
---
 drivers/usb/phy/phy-ulpi.c | 129 +++++++++++++++++++++++++++++++++++++++++----
 1 file changed, 119 insertions(+), 10 deletions(-)

diff --git a/drivers/usb/phy/phy-ulpi.c b/drivers/usb/phy/phy-ulpi.c
index f48a7a21e3c2..b7f9a091834c 100644
--- a/drivers/usb/phy/phy-ulpi.c
+++ b/drivers/usb/phy/phy-ulpi.c
@@ -23,13 +23,16 @@
  * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  */
 
+#include <asm/io.h>
 #include <linux/kernel.h>
 #include <linux/slab.h>
 #include <linux/export.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
 #include <linux/usb.h>
 #include <linux/usb/otg.h>
 #include <linux/usb/ulpi.h>
-
+#include <linux/of.h>
 
 struct ulpi_info {
 	unsigned int	id;
@@ -253,6 +256,20 @@ static int ulpi_set_vbus(struct usb_otg *otg, bool on)
 	return usb_phy_io_write(phy, flags, ULPI_OTG_CTRL);
 }
 
+static void otg_ulpi_init(struct usb_phy *phy, struct usb_otg *otg,
+			  struct usb_phy_io_ops *ops, unsigned int flags)
+{
+	phy->label	= "ULPI";
+	phy->flags	= flags;
+	phy->io_ops	= ops;
+	phy->otg	= otg;
+	phy->init	= ulpi_init;
+
+	otg->usb_phy	= phy;
+	otg->set_host	= ulpi_set_host;
+	otg->set_vbus	= ulpi_set_vbus;
+}
+
 struct usb_phy *
 otg_ulpi_create(struct usb_phy_io_ops *ops,
 		unsigned int flags)
@@ -270,17 +287,109 @@ otg_ulpi_create(struct usb_phy_io_ops *ops,
 		return NULL;
 	}
 
-	phy->label	= "ULPI";
-	phy->flags	= flags;
-	phy->io_ops	= ops;
-	phy->otg	= otg;
-	phy->init	= ulpi_init;
-
-	otg->usb_phy	= phy;
-	otg->set_host	= ulpi_set_host;
-	otg->set_vbus	= ulpi_set_vbus;
+	otg_ulpi_init(phy, otg, ops, flags);
 
 	return phy;
 }
 EXPORT_SYMBOL_GPL(otg_ulpi_create);
 
+struct usb_phy_ulpi_ddata {
+	void __iomem *base;
+	struct usb_phy usbphy;
+	struct usb_otg otg;
+};
+
+static const struct phy_ops usb_phy_ulpi_phy_ops = {
+	.owner = THIS_MODULE,
+};
+
+static void usb_phy_init_dt(struct device_node *np,
+			    struct usb_phy_ulpi_ddata *ddata)
+{
+	struct usb_phy *usbphy = &ddata->usbphy;
+
+
+	/* some bits are missing ... */
+	if (of_get_property(np, "ulpi,otg-id-pullup", NULL))
+		usbphy->flags |= ULPI_OTG_ID_PULLUP;
+
+	if (of_get_property(np, "ulpi,otg-dp-pulldown-disable", NULL))
+		usbphy->flags |= ULPI_OTG_DP_PULLDOWN_DIS;
+
+	if (of_get_property(np, "ulpi,otg-dm-pulldown-disable", NULL))
+		usbphy->flags |= ULPI_OTG_DM_PULLDOWN_DIS;
+
+	if (of_get_property(np, "ulpi,otg-external-vbus", NULL))
+		usbphy->flags |= ULPI_OTG_DRVVBUS_EXT;
+
+	if (of_get_property(np, "ulpi,otg-external-overcurrent-indicator", NULL))
+		usbphy->flags |= ULPI_OTG_EXTVBUSIND;
+}
+
+static int usb_phy_ulpi_probe(struct platform_device *pdev)
+{
+	struct device *dev = &pdev->dev;
+	struct phy *phy;
+	struct phy_provider *phy_provider;
+	struct usb_phy_ulpi_ddata *ddata;
+	int err;
+
+	ddata = devm_kzalloc(dev, sizeof(*ddata), GFP_KERNEL);
+	if (!ddata)
+		return -ENOMEM;
+
+	platform_set_drvdata(pdev, ddata);
+
+	otg_ulpi_init(&ddata->usbphy, &ddata->otg, NULL, 0);
+
+	ddata->usbphy.io_priv = NULL;
+	ddata->usbphy.dev = dev;
+
+	usb_phy_init_dt(dev->of_node, ddata);
+
+	phy = devm_phy_create(dev, NULL, &usb_phy_ulpi_phy_ops);
+	if (IS_ERR(phy)) {
+		err = PTR_ERR(phy);
+		dev_err(dev, "can't create phy device, err: %d\n", err);
+		return err;
+	}
+
+	phy_provider = devm_of_phy_provider_register(dev, of_phy_simple_xlate);
+	if (IS_ERR(phy_provider)) {
+		err = PTR_ERR(phy_provider);
+		dev_err(dev, "can't create phy provider, err: %d\n", err);
+		return err;
+	}
+
+	err = usb_add_phy_dev(&ddata->usbphy);
+	if (err) {
+		dev_err(dev, "can't register usb_phy device, err: %d\n", err);
+		return err;
+	}
+
+	return 0;
+}
+
+static int usb_phy_ulpi_remove(struct platform_device *pdev)
+{
+	struct usb_phy_ulpi_ddata *ddata = platform_get_drvdata(pdev);
+
+	usb_remove_phy(&ddata->usbphy);
+
+	return 0;
+}
+
+static const struct of_device_id usb_phy_ulpi_ids[] = {
+	{ .compatible = "usb-ulpi-xceiv" },
+	{ /* sentinel */ }
+};
+
+static struct platform_driver usb_phy_ulpi_driver = {
+	.probe = usb_phy_ulpi_probe,
+	.remove = usb_phy_ulpi_remove,
+	.driver = {
+		.name = "usb-phy-ulpi",
+		.of_match_table = usb_phy_ulpi_ids,
+	},
+};
+module_platform_driver(usb_phy_ulpi_driver);
-- 
2.6.2

--
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