From: "Ying-Chun Liu (PaulLiu)" <paul....@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....@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 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.gu...@ti.com> + * Jean-Jacques Hiblot <jjhib...@ti.com> + * Ying-Chun Liu (PaulLiu) <paul....@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), +}; -- 2.30.1