From: Piyush Mehta <piyush.mehta@amd.com>
To: <gregkh@linuxfoundation.org>, <michal.simek@amd.com>,
<robh+dt@kernel.org>, <krzysztof.kozlowski+dt@linaro.org>,
<conor+dt@kernel.org>, <peter.chen@kernel.org>,
<linus.walleij@linaro.org>, <paul@crapouillou.net>,
<arnd@arndb.de>
Cc: <piyush.mehta@amd.com>, <linux-usb@vger.kernel.org>,
<devicetree@vger.kernel.org>, <linux-kernel@vger.kernel.org>,
<git@amd.com>
Subject: [RFC PATCH 3/3] usb: phy: Add platform driver support for ULPI phys
Date: Fri, 29 Sep 2023 12:18:52 +0530 [thread overview]
Message-ID: <20230929064852.16642-4-piyush.mehta@amd.com> (raw)
In-Reply-To: <20230929064852.16642-1-piyush.mehta@amd.com>
Added platform driver support to ULPI Phys for Zynq. This modification
enables external five volt supply to drive 5-volts on VBUS. This signal
is or’ed with DrvVbus. Some Phys requires ULPI (OTG Control) register
DrvVbusExternal and DrvVbus bit to operate properly to drive the CPEN
pin/ external VBUS power supply.
The ULPI viewport provides a mechanism for software to read and write
PHY registers with explicit control of the address and data using the
usb.VIEWPORT register. Zynq platform access ULPI PHY via viewport.
Signed-off-by: Piyush Mehta <piyush.mehta@amd.com>
---
On zynq platform chipidea USB controller is capable of fulfilling a wide
range of applications for USB 2.0 implementations as a host, a device, or
On-the-Go. The USB controllers are integrated into the PS IOP to bridge
between the PS interconnect and an external ULPI PHY. The register provides
indirect access to the ULPI PHY register set. The ULPI PHY register I/O
interface uses Viewport to access PHY registers.
In current approach we have extended generic ulpi phy driver and made it a
platform driver. This solves the problem, but would like to know if it is
the right approach? Here, we are modifying the phy-ulpi framework by adapting
the platform driver to fulfill our requirements. ULPI PHY register read/write
should be performed via ULPI framework using read/write API call.
The another approach would be to have access to the ULPI register via
viewport flow by creating a new platform driver at path "driver/usb/phy"
using "phy-ulpi-zynq-usb.c" source file, where the source driver would be
particular to the Xilinx/AMD zynq platform. And binding patch [1/3] would
be specific to Xilinx/AMD-specific.
---
drivers/usb/phy/Kconfig | 2 +-
drivers/usb/phy/Kconfig | 2 +-
drivers/usb/phy/phy-ulpi.c | 90 ++++++++++++++++++++++++++++++++++++++
2 files changed, 91 insertions(+), 1 deletion(-)
diff --git a/drivers/usb/phy/Kconfig b/drivers/usb/phy/Kconfig
index 5f629d7cad64..38ae5458528c 100644
--- a/drivers/usb/phy/Kconfig
+++ b/drivers/usb/phy/Kconfig
@@ -160,7 +160,7 @@ config USB_TEGRA_PHY
config USB_ULPI
bool "Generic ULPI Transceiver Driver"
- depends on ARM || ARM64 || COMPILE_TEST
+ depends on ARM || ARM64 || COMPILE_TEST || USB_PHY
select USB_ULPI_VIEWPORT
help
Enable this to support ULPI connected USB OTG transceivers which
diff --git a/drivers/usb/phy/phy-ulpi.c b/drivers/usb/phy/phy-ulpi.c
index e683a37e3a7a..61e15a19ea8c 100644
--- a/drivers/usb/phy/phy-ulpi.c
+++ b/drivers/usb/phy/phy-ulpi.c
@@ -13,9 +13,16 @@
#include <linux/kernel.h>
#include <linux/slab.h>
#include <linux/export.h>
+#include <linux/module.h>
+#include <linux/io.h>
+#include <linux/of.h>
+#include <linux/of_address.h>
+#include <linux/of_device.h>
+#include <linux/platform_device.h>
#include <linux/usb.h>
#include <linux/usb/otg.h>
#include <linux/usb/ulpi.h>
+#include <linux/usb/phy.h>
struct ulpi_info {
@@ -39,6 +46,13 @@ static struct ulpi_info ulpi_ids[] = {
ULPI_INFO(ULPI_ID(0x0451, 0x1507), "TI TUSB1210"),
};
+struct ulpi_phy {
+ struct usb_phy *usb_phy;
+ void __iomem *regs;
+ unsigned int vp_offset;
+ unsigned int flags;
+};
+
static int ulpi_set_otg_flags(struct usb_phy *phy)
{
unsigned int flags = ULPI_OTG_CTRL_DP_PULLDOWN |
@@ -240,6 +254,23 @@ static int ulpi_set_vbus(struct usb_otg *otg, bool on)
return usb_phy_io_write(phy, flags, ULPI_OTG_CTRL);
}
+static int usbphy_set_vbus(struct usb_phy *phy, int on)
+{
+ unsigned int flags = usb_phy_io_read(phy, ULPI_OTG_CTRL);
+
+ flags &= ~(ULPI_OTG_CTRL_DRVVBUS | ULPI_OTG_CTRL_DRVVBUS_EXT);
+
+ if (on) {
+ if (phy->flags & ULPI_OTG_DRVVBUS)
+ flags |= ULPI_OTG_CTRL_DRVVBUS;
+
+ if (phy->flags & ULPI_OTG_DRVVBUS_EXT)
+ flags |= ULPI_OTG_CTRL_DRVVBUS_EXT;
+ }
+
+ 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)
@@ -249,6 +280,7 @@ static void otg_ulpi_init(struct usb_phy *phy, struct usb_otg *otg,
phy->io_ops = ops;
phy->otg = otg;
phy->init = ulpi_init;
+ phy->set_vbus = usbphy_set_vbus;
otg->usb_phy = phy;
otg->set_host = ulpi_set_host;
@@ -301,3 +333,61 @@ devm_otg_ulpi_create(struct device *dev,
return phy;
}
EXPORT_SYMBOL_GPL(devm_otg_ulpi_create);
+
+static int ulpi_phy_probe(struct platform_device *pdev)
+{
+ struct device_node *np = pdev->dev.of_node;
+ struct ulpi_phy *uphy;
+ int ret;
+
+ uphy = devm_kzalloc(&pdev->dev, sizeof(*uphy), GFP_KERNEL);
+ if (!uphy)
+ return -ENOMEM;
+
+ uphy->regs = devm_platform_ioremap_resource(pdev, 0);
+ if (IS_ERR(uphy->regs))
+ return PTR_ERR(uphy->regs);
+
+ if (of_property_read_bool(np, "external-drv-vbus"))
+ uphy->flags |= ULPI_OTG_DRVVBUS | ULPI_OTG_DRVVBUS_EXT;
+
+ ret = of_property_read_u32(np, "view-port", &uphy->vp_offset);
+ if (ret)
+ return ret;
+
+ uphy->usb_phy = otg_ulpi_create(&ulpi_viewport_access_ops, uphy->flags);
+ if (!uphy->usb_phy) {
+ dev_err(&pdev->dev, "Failed to create ULPI OTG\n");
+ return -ENOMEM;
+ }
+
+ uphy->usb_phy->dev = &pdev->dev;
+ uphy->usb_phy->io_priv = uphy->regs + uphy->vp_offset;
+ return usb_add_phy_dev(uphy->usb_phy);
+}
+
+static void ulpi_phy_remove(struct platform_device *pdev)
+{
+ struct ulpi_phy *uphy = platform_get_drvdata(pdev);
+
+ usb_remove_phy(uphy->usb_phy);
+}
+
+static const struct of_device_id ulpi_phy_table[] = {
+ { .compatible = "ulpi-phy" },
+ { },
+};
+MODULE_DEVICE_TABLE(of, ulpi_phy_table);
+
+static struct platform_driver ulpi_phy_driver = {
+ .probe = ulpi_phy_probe,
+ .remove_new = ulpi_phy_remove,
+ .driver = {
+ .name = "ulpi-phy",
+ .of_match_table = ulpi_phy_table,
+ },
+};
+module_platform_driver(ulpi_phy_driver);
+
+MODULE_DESCRIPTION("ULPI PHY driver");
+MODULE_LICENSE("GPL");
--
2.17.1
prev parent reply other threads:[~2023-09-29 6:49 UTC|newest]
Thread overview: 9+ messages / expand[flat|nested] mbox.gz Atom feed top
2023-09-29 6:48 [RFC PATCH 0/3] usb: phy: Add platform driver support for ULPI phys Piyush Mehta
2023-09-29 6:48 ` [RFC PATCH 1/3] dt-binding: usb: ulpi-phy: add ulpi-phy binding Piyush Mehta
2023-09-29 14:04 ` Conor Dooley
2023-09-30 15:15 ` Krzysztof Kozlowski
2023-10-02 17:00 ` Rob Herring
2023-10-04 11:45 ` Mehta, Piyush
2023-12-01 13:07 ` Mehta, Piyush
2023-09-29 6:48 ` [RFC PATCH 2/3] usb: chipidea: add usb2 phy interface for Zynq platform Piyush Mehta
2023-09-29 6:48 ` Piyush Mehta [this message]
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20230929064852.16642-4-piyush.mehta@amd.com \
--to=piyush.mehta@amd.com \
--cc=arnd@arndb.de \
--cc=conor+dt@kernel.org \
--cc=devicetree@vger.kernel.org \
--cc=git@amd.com \
--cc=gregkh@linuxfoundation.org \
--cc=krzysztof.kozlowski+dt@linaro.org \
--cc=linus.walleij@linaro.org \
--cc=linux-kernel@vger.kernel.org \
--cc=linux-usb@vger.kernel.org \
--cc=michal.simek@amd.com \
--cc=paul@crapouillou.net \
--cc=peter.chen@kernel.org \
--cc=robh+dt@kernel.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
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).