On Sat, Jul 09, 2016 at 10:00:54AM +0530, Rajesh Bhagat wrote: > Adds qoriq usb 2.0 phy driver support for LS1021A and LS1012A > platform. > > Signed-off-by: Rajesh Bhagat <rajesh.bhagat@xxxxxxx> > --- > Changes in v2: > - Replaced Freescale with QorIQ in comments section > - Changed the compatible string to fsl,qoriq-usb2-phy and added version > - Added dependency on ARCH_MXC/ARCH_LAYERSCAPE and OF in Kconfig > - Dropped CONFIG_ULPI #ifdefs to make code generic > - Removed calls to devm free/release calls > > drivers/phy/Kconfig | 8 ++ > drivers/phy/Makefile | 1 + > drivers/phy/phy-qoriq-usb2.c | 228 +++++++++++++++++++++++++++++++++++++++++++ > drivers/phy/phy-qoriq-usb2.h | 50 ++++++++++ > 4 files changed, 287 insertions(+) > create mode 100644 drivers/phy/phy-qoriq-usb2.c > create mode 100644 drivers/phy/phy-qoriq-usb2.h > > diff --git a/drivers/phy/Kconfig b/drivers/phy/Kconfig > index b869b98..cc69299 100644 > --- a/drivers/phy/Kconfig > +++ b/drivers/phy/Kconfig > @@ -434,4 +434,12 @@ config PHY_CYGNUS_PCIE > > source "drivers/phy/tegra/Kconfig" > > +config PHY_QORIQ_USB2 > + tristate "QorIQ USB 2.0 PHY driver" > + depends on ARCH_MXC || ARCH_LAYERSCAPE It seems mxc platforms do not use this PHY. Besides, if you are using ULPI phy, you need to depend on ULPI bus. Peter > + depends on OF > + select GENERIC_PHY > + help > + Enable this to support the USB2.0 PHY on the QorIQ SoC. > + > endmenu > diff --git a/drivers/phy/Makefile b/drivers/phy/Makefile > index 9c3e73c..044105a 100644 > --- a/drivers/phy/Makefile > +++ b/drivers/phy/Makefile > @@ -53,5 +53,6 @@ obj-$(CONFIG_PHY_TUSB1210) += phy-tusb1210.o > obj-$(CONFIG_PHY_BRCM_SATA) += phy-brcm-sata.o > obj-$(CONFIG_PHY_PISTACHIO_USB) += phy-pistachio-usb.o > obj-$(CONFIG_PHY_CYGNUS_PCIE) += phy-bcm-cygnus-pcie.o > +obj-$(CONFIG_PHY_QORIQ_USB2) += phy-qoriq-usb2.o > > obj-$(CONFIG_ARCH_TEGRA) += tegra/ > diff --git a/drivers/phy/phy-qoriq-usb2.c b/drivers/phy/phy-qoriq-usb2.c > new file mode 100644 > index 0000000..f74d255 > --- /dev/null > +++ b/drivers/phy/phy-qoriq-usb2.c > @@ -0,0 +1,228 @@ > +/* > + * QorIQ SoC USB 2.0 PHY driver > + * > + * Copyright 2016 Freescale Semiconductor, Inc. > + * Author: Rajesh Bhagat <rajesh.bhagat@xxxxxxx> > + * > + * This program is free software; you can redistribute it and/or modify > + * it under the terms of the GNU General Public License version 2 as > + * published by the Free Software Foundation. > + * > + */ > +#include <linux/clk.h> > +#include <linux/clk-provider.h> > +#include <linux/io.h> > +#include <linux/kernel.h> > +#include <linux/module.h> > +#include <linux/of.h> > +#include <linux/usb/of.h> > +#include <linux/of_address.h> > +#include <linux/of_platform.h> > +#include <linux/phy/phy.h> > +#include <linux/usb/phy.h> > +#include <linux/usb/ulpi.h> > +#include <linux/of_platform.h> > +#include <linux/platform_device.h> > + > +#include "phy-qoriq-usb2.h" > + > +static int qoriq_usb2_phy_init(struct phy *_phy) > +{ > + struct qoriq_usb2_phy_ctx *ctx = phy_get_drvdata(_phy); > + struct device *dev = ctx->dev; > + > + if (ctx->ulpi_phy) { > + if (usb_phy_init(ctx->ulpi_phy)) { > + dev_err(dev, "unable to init transceiver, probably missing\n"); > + return -ENODEV; > + } > + } > + > + return 0; > +} > + > +static int qoriq_usb2_phy_power_on(struct phy *_phy) > +{ > + struct qoriq_usb2_phy_ctx *ctx = phy_get_drvdata(_phy); > + u32 flags; > + > + if (ctx->ulpi_phy) { > + flags = usb_phy_io_read(ctx->ulpi_phy, ULPI_OTG_CTRL); > + usb_phy_io_write(ctx->ulpi_phy, flags | > + (ULPI_OTG_CTRL_DRVVBUS_EXT | > + ULPI_OTG_CTRL_EXTVBUSIND), ULPI_OTG_CTRL); > + flags = usb_phy_io_read(ctx->ulpi_phy, ULPI_IFC_CTRL); > + usb_phy_io_write(ctx->ulpi_phy, flags | > + (ULPI_IFC_CTRL_EXTERNAL_VBUS | > + ULPI_IFC_CTRL_PASSTHRU), ULPI_IFC_CTRL); > + } > + > + return 0; > +} > + > +static int qoriq_usb2_phy_power_off(struct phy *_phy) > +{ > + /* TODO: Add logic to power off phy */ > + > + return 0; > +} > + > +static int qoriq_usb2_phy_exit(struct phy *_phy) > +{ > + struct qoriq_usb2_phy_ctx *ctx = phy_get_drvdata(_phy); > + > + if (ctx->ulpi_phy) > + usb_phy_shutdown(ctx->ulpi_phy); > + > + return 0; > +} > + > +static const struct phy_ops ops = { > + .init = qoriq_usb2_phy_init, > + .power_on = qoriq_usb2_phy_power_on, > + .power_off = qoriq_usb2_phy_power_off, > + .exit = qoriq_usb2_phy_exit, > + .owner = THIS_MODULE, > +}; > + > + > +static enum qoriq_usb2_phy_ver of_usb_get_phy_version(struct device_node *np) > +{ > + enum qoriq_usb2_phy_ver phy_version = QORIQ_PHY_UNKNOWN; > + > + if (of_device_is_compatible(np, "fsl,qoriq-usb2-phy")) { > + if (of_device_is_compatible(np, "fsl,qoriq-usb2-phy-v1.0")) > + phy_version = QORIQ_PHY_LEGACY; > + else if (of_device_is_compatible(np, "fsl,qoriq-usb2-phy-v2.0")) > + phy_version = QORIQ_PHY_NXP_ISP1508; > + } > + return phy_version; > +} > + > +static int qoriq_usb2_phy_probe(struct platform_device *pdev) > +{ > + int ret; > + struct resource *res; > + struct qoriq_usb2_phy_ctx *ctx; > + struct device *dev = &pdev->dev; > + const struct of_device_id *of_id; > + struct phy_provider *phy_provider; > + struct device_node *np = pdev->dev.of_node; > + > + ctx = devm_kzalloc(dev, sizeof(*ctx), GFP_KERNEL); > + if (!ctx) > + return -ENOMEM; > + > + ctx->dev = dev; > + > + of_id = of_match_device(dev->driver->of_match_table, dev); > + if (!of_id) { > + dev_err(dev, "failed to get device match\n"); > + ret = -EINVAL; > + goto err_out; > + } > + > + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); > + if (!res) { > + dev_err(dev, "failed to get I/O memory\n"); > + ret = -ENOENT; > + goto err_out; > + } > + > + ctx->regs = devm_ioremap(dev, res->start, resource_size(res)); > + if (!ctx->regs) { > + dev_err(dev, "failed to remap I/O memory\n"); > + ret = -ENOMEM; > + goto err_out; > + } > + > + platform_set_drvdata(pdev, ctx); > + > + ctx->phy = devm_phy_create(ctx->dev, NULL, &ops); > + if (IS_ERR(ctx->phy)) { > + dev_err(dev, "failed to create PHY\n"); > + ret = PTR_ERR(ctx->phy); > + goto err_out; > + } > + phy_set_drvdata(ctx->phy, ctx); > + > + ctx->phy_version = of_usb_get_phy_version(np); > + if (ctx->phy_version == QORIQ_PHY_UNKNOWN) { > + ret = -EINVAL; > + dev_err(dev, "failed to get PHY version\n"); > + goto err_out; > + } > + > + ctx->phy_type = of_usb_get_phy_mode(np); > + switch (ctx->phy_type) { > + case USBPHY_INTERFACE_MODE_ULPI: > + switch (ctx->phy_version) { > + case QORIQ_PHY_NXP_ISP1508: > + ctx->ulpi_phy = qoriq_otg_ulpi_create(0); > + if (!ctx->ulpi_phy) { > + dev_err(dev, "qoriq_otg_ulpi_create returned NULL\n"); > + ret = -ENOMEM; > + goto err_out; > + } > + ctx->ulpi_phy->io_priv = ctx->regs + ULPI_VIEWPORT; > + break; > + default: > + ctx->ulpi_phy = NULL; > + break; > + } > + break; > + default: > + dev_err(&pdev->dev, "phy_type %d is invalid or unsupported\n", > + ctx->phy_type); > + ret = -EINVAL; > + goto err_out; > + } > + > + phy_provider = devm_of_phy_provider_register(dev, of_phy_simple_xlate); > + if (IS_ERR(phy_provider)) { > + dev_err(dev, "failed to register phy_provider\n"); > + ret = PTR_ERR_OR_ZERO(phy_provider); > + goto err_out; > + } > + > + dev_dbg(dev, "initialized\n"); > + return 0; > + > +err_out: > + return ret; > +} > + > +static int qoriq_usb2_phy_remove(struct platform_device *pdev) > +{ > + struct device *dev = &pdev->dev; > + struct qoriq_usb2_phy_ctx *ctx = platform_get_drvdata(pdev); > + > + devm_phy_destroy(ctx->dev, ctx->phy); > + devm_iounmap(dev, ctx->regs); > + dev_dbg(dev, "de-initialized\n"); > + return 0; > +} > + > +static const struct of_device_id qoriq_usb2_phy_dt_ids[] = { > + { .compatible = "fsl,qoriq-usb2-phy"}, > + {} > +}; > + > +MODULE_DEVICE_TABLE(of, qoriq_usb2_phy_dt_ids); > + > +static struct platform_driver qoriq_usb2_phy_driver = { > + .probe = qoriq_usb2_phy_probe, > + .remove = qoriq_usb2_phy_remove, > + .driver = { > + .name = "qoriq_usb2_phy", > + .owner = THIS_MODULE, > + .of_match_table = of_match_ptr(qoriq_usb2_phy_dt_ids), > + }, > +}; > + > +module_platform_driver(qoriq_usb2_phy_driver); > + > +MODULE_ALIAS("platform:qoriq-usb2-phy"); > +MODULE_LICENSE("GPL v2"); > +MODULE_DESCRIPTION("QorIQ SoC USB PHY driver"); > +MODULE_AUTHOR("Rajesh Bhagat <rajesh.bhagat@xxxxxxx>"); > diff --git a/drivers/phy/phy-qoriq-usb2.h b/drivers/phy/phy-qoriq-usb2.h > new file mode 100644 > index 0000000..47c37a5 > --- /dev/null > +++ b/drivers/phy/phy-qoriq-usb2.h > @@ -0,0 +1,50 @@ > +/* > + * Freescale SoC USB 2.0 PHY driver > + * > + * Copyright 2016 Freescale Semiconductor, Inc. > + * Author: Rajesh Bhagat <rajesh.bhagat@xxxxxxx> > + * > + * This program is free software; you can redistribute it and/or modify > + * it under the terms of the GNU General Public License version 2 as > + * published by the Free Software Foundation. > + * > + */ > +#ifndef _PHY_QORIQ_USB2_H > +#define _PHY_QORIQ_USB2_H > + > +#include <linux/clk.h> > +#include <linux/phy/phy.h> > +#include <linux/device.h> > +#include <linux/regmap.h> > + > +#define ULPI_VIEWPORT 0x170 > + > +enum qoriq_usb2_phy_ver { > + QORIQ_PHY_LEGACY, > + QORIQ_PHY_NXP_ISP1508, > + QORIQ_PHY_UNKNOWN, > +}; > + > +struct qoriq_usb2_phy_ctx { > + struct phy *phy; > + struct clk *clk; > + struct device *dev; > + void __iomem *regs; > + struct usb_phy *ulpi_phy; > + enum usb_phy_interface phy_type; > + enum qoriq_usb2_phy_ver phy_version; > +}; > + > +#ifdef CONFIG_USB_ULPI_VIEWPORT > +static inline struct usb_phy *qoriq_otg_ulpi_create(unsigned int flags) > +{ > + return otg_ulpi_create(&ulpi_viewport_access_ops, flags); > +} > +#else > +static inline struct usb_phy *qoriq_otg_ulpi_create(unsigned int flags) > +{ > + return NULL; > +} > +#endif > + > +#endif > -- > 2.6.2.198.g614a2ac > > -- > 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 -- Best Regards, Peter Chen -- To unsubscribe from this list: send the line "unsubscribe devicetree" in the body of a message to majordomo@xxxxxxxxxxxxxxx More majordomo info at http://vger.kernel.org/majordomo-info.html