[1/2] drivers: usb: phy: add driver for usb-nop-xceiv

Message ID 20210307185829.97583-2-grandpaul@gmail.com
State New
Headers show
Series
  • drivers: usb: phy: add driver for usb-nop-xceiv
Related show

Commit Message

Ying-Chun Liu March 7, 2021, 6:58 p.m.
From: "Ying-Chun Liu (PaulLiu)" <paul.liu@linaro.org>


implement the generic NOP USB transceiver for all USB transceiver
which are either built-in into USB IP or which are mostly autonomous.

Signed-off-by: Ying-Chun Liu (PaulLiu) <paul.liu@linaro.org>

---
 drivers/usb/phy/Kconfig       |   8 ++
 drivers/usb/phy/Makefile      |   1 +
 drivers/usb/phy/usb_nop_phy.c | 137 ++++++++++++++++++++++++++++++++++
 3 files changed, 146 insertions(+)
 create mode 100644 drivers/usb/phy/usb_nop_phy.c

-- 
2.30.1

Patch

diff --git a/drivers/usb/phy/Kconfig b/drivers/usb/phy/Kconfig
index 8741553d09..663b50a937 100644
--- a/drivers/usb/phy/Kconfig
+++ b/drivers/usb/phy/Kconfig
@@ -13,3 +13,11 @@  config OMAP_USB_PHY
 
 config ROCKCHIP_USB2_PHY
 	bool "Rockchip USB2 PHY"
+
+config NOP_USB_XCEIV
+	bool "NOP USB Transceiver Driver"
+	depends on PHY
+	help
+	  This driver is to be used by all the usb transceiver which are either
+	  built-in with usb ip or which are autonomous and doesn't require any
+	  phy programming such as ISP1x04 etc.
diff --git a/drivers/usb/phy/Makefile b/drivers/usb/phy/Makefile
index 20f7edf48d..079e24770f 100644
--- a/drivers/usb/phy/Makefile
+++ b/drivers/usb/phy/Makefile
@@ -6,3 +6,4 @@ 
 obj-$(CONFIG_TWL4030_USB) += twl4030.o
 obj-$(CONFIG_OMAP_USB_PHY) += omap_usb_phy.o
 obj-$(CONFIG_ROCKCHIP_USB2_PHY) += rockchip_usb2_phy.o
+obj-$(CONFIG_NOP_USB_XCEIV) += usb_nop_phy.o
diff --git a/drivers/usb/phy/usb_nop_phy.c b/drivers/usb/phy/usb_nop_phy.c
new file mode 100644
index 0000000000..7f4133af39
--- /dev/null
+++ b/drivers/usb/phy/usb_nop_phy.c
@@ -0,0 +1,137 @@ 
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * NOP USB transceiver for all USB transceiver which are either built-in
+ * into USB IP or which are mostly autonomous.
+ *
+ * Copyright (C) 2009 Texas Instruments Inc
+ * Copyright (C) 2017 Texas Instruments Incorporated - http://www.ti.com/
+ * Copyright (C) 2021 Linaro
+ * Author: Ajay Kumar Gupta <ajay.gupta@ti.com>
+ *         Jean-Jacques Hiblot  <jjhiblot@ti.com>
+ *         Ying-Chun Liu (PaulLiu) <paul.liu@linaro.org>
+ * Current status:
+ *      This provides a "nop" transceiver for PHYs which are
+ *      autonomous such as isp1504, isp1707, etc.
+ */
+
+#include <clk.h>
+#include <common.h>
+#include <generic-phy.h>
+#include <asm/gpio.h>
+#include <dm.h>
+#include <dm/device.h>
+#include <dm/device_compat.h>
+#include <linux/delay.h>
+#include <power/regulator.h>
+
+struct usb_nop_phy_priv {
+	struct clk_bulk bulk;
+	struct udevice *vcc;
+	struct gpio_desc *gpiod_reset;
+	struct gpio_desc *gpiod_vbus;
+};
+
+static int usb_nop_phy_reset(struct phy *phy)
+{
+	int ret = 0;
+	struct usb_nop_phy_priv *priv = dev_get_priv(phy->dev);
+
+	if (!priv->gpiod_reset)
+		return ret;
+
+	ret = dm_gpio_set_value(priv->gpiod_reset, 1);
+	mdelay(20);
+	ret = dm_gpio_set_value(priv->gpiod_reset, 0);
+
+	return ret;
+}
+
+static int usb_nop_phy_init(struct phy *phy)
+{
+	struct usb_nop_phy_priv *priv = dev_get_priv(phy->dev);
+	int ret = 0;
+
+	if (CONFIG_IS_ENABLED(DM_REGULATOR) && priv->vcc) {
+		ret = regulator_set_enable(priv->vcc, true);
+		if (ret < 0) {
+			dev_err(phy->dev, "Failed to enable power: %d\n", ret);
+			return ret;
+		}
+	}
+
+	if (CONFIG_IS_ENABLED(CLK)) {
+		ret = clk_enable_bulk(&priv->bulk);
+		if (ret < 0) {
+			dev_err(phy->dev, "Failed to enable clk: %d\n", ret);
+			return ret;
+		}
+	}
+
+	return ret;
+}
+
+static int usb_nop_phy_probe(struct udevice *dev)
+{
+	struct usb_nop_phy_priv *priv = dev_get_priv(dev);
+	u32 clk_rate = 0;
+	int i, ret = 0;
+
+	/* Get all clocks. Actually only main_clk should be assigned */
+	if (CONFIG_IS_ENABLED(CLK)) {
+		ret = clk_get_bulk(dev, &priv->bulk);
+		if (ret < 0)
+			dev_info(dev, "failed to get clock: %d\n", ret);
+	}
+
+	/* Get vcc-supply */
+	if (CONFIG_IS_ENABLED(DM_REGULATOR)) {
+		ret = device_get_supply_regulator(dev, "vcc-supply", &priv->vcc);
+		if (ret < 0) {
+			dev_info(dev, "failed to get vcc-supply: %d\n", ret);
+			priv->vcc = NULL;
+		}
+	}
+
+	ret = ofnode_read_u32(dev_ofnode(dev), "clock-frequency", &clk_rate);
+	if (ret < 0)
+		clk_rate = 0;
+
+	priv->gpiod_reset = devm_gpiod_get_optional(dev, "reset", 0);
+	if (priv->gpiod_reset)
+		priv->gpiod_vbus = devm_gpiod_get_optional(dev,
+							   "vbus-detect",
+							   0);
+
+	if (clk_rate)
+		for (i = 0; i < priv->bulk.count; i++) {
+			ret = clk_set_rate(&priv->bulk.clks[i], clk_rate);
+			if (ret < 0) {
+				dev_err(dev,
+					"Failed to set clk rate %d: %d\n",
+					clk_rate,
+					ret);
+				return ret;
+			}
+		}
+
+	return 0;
+}
+
+static const struct udevice_id usb_nop_phy_ids[] = {
+	{ .compatible = "usb-nop-xceiv" },
+	{ }
+};
+
+static struct phy_ops usb_nop_phy_ops = {
+	.init = usb_nop_phy_init,
+	.reset = usb_nop_phy_reset,
+};
+
+U_BOOT_DRIVER(usb_nop_phy) = {
+	.name	= "usb_nop_phy",
+	.id	= UCLASS_PHY,
+	.of_match = usb_nop_phy_ids,
+	.ops = &usb_nop_phy_ops,
+	.probe = usb_nop_phy_probe,
+	.priv_auto	= sizeof(struct usb_nop_phy_priv),
+};