From: Xu Ziyuan Date: Thu, 14 Jul 2016 06:52:32 +0000 (+0800) Subject: usb: rockchip-phy: implement USB2.0 phy control X-Git-Tag: v2016.09-rc2~201 X-Git-Url: https://git.librecmc.org/?a=commitdiff_plain;h=fab3357916096d4c61a5e2fe5d28f5aeb78c6957;p=oweals%2Fu-boot.git usb: rockchip-phy: implement USB2.0 phy control So far, Rockchip SoCs have two kinds of USB2.0 phy, such as Synopsys and Innosilicon. This patch applys dwc2 usb driver framework to implement phy_init() and phy_off() methods for Synopsys phy on Rockchip platform. Signed-off-by: Ziyuan Xu Acked-by: Simon Glass --- diff --git a/drivers/usb/phy/Makefile b/drivers/usb/phy/Makefile index 93d147e26f..4e548c24ec 100644 --- a/drivers/usb/phy/Makefile +++ b/drivers/usb/phy/Makefile @@ -7,3 +7,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 diff --git a/drivers/usb/phy/rockchip_usb2_phy.c b/drivers/usb/phy/rockchip_usb2_phy.c new file mode 100644 index 0000000000..1958478d62 --- /dev/null +++ b/drivers/usb/phy/rockchip_usb2_phy.c @@ -0,0 +1,107 @@ +/* + * Copyright 2016 Rockchip Electronics Co., Ltd + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +#include +#include +#include + +#include "../gadget/dwc2_udc_otg_priv.h" + +DECLARE_GLOBAL_DATA_PTR; + +#define BIT_WRITEABLE_SHIFT 16 + +struct usb2phy_reg { + unsigned int offset; + unsigned int bitend; + unsigned int bitstart; + unsigned int disable; + unsigned int enable; +}; + +/** + * struct rockchip_usb2_phy_cfg: usb-phy port configuration + * @port_reset: usb otg per-port reset register + * @soft_con: software control usb otg register + * @suspend: phy suspend register + */ +struct rockchip_usb2_phy_cfg { + struct usb2phy_reg port_reset; + struct usb2phy_reg soft_con; + struct usb2phy_reg suspend; +}; + +struct rockchip_usb2_phy_dt_id { + char compatible[128]; + const void *data; +}; + +static const struct rockchip_usb2_phy_cfg rk3288_pdata = { + .port_reset = {0x00, 12, 12, 0, 1}, + .soft_con = {0x08, 2, 2, 0, 1}, + .suspend = {0x0c, 5, 0, 0x01, 0x2A}, +}; + +static struct rockchip_usb2_phy_dt_id rockchip_usb2_phy_dt_ids[] = { + { .compatible = "rockchip,rk3288-usb-phy", .data = &rk3288_pdata }, + {} +}; + +static void property_enable(struct dwc2_plat_otg_data *pdata, + const struct usb2phy_reg *reg, bool en) +{ + unsigned int val, mask, tmp; + + tmp = en ? reg->enable : reg->disable; + mask = GENMASK(reg->bitend, reg->bitstart); + val = (tmp << reg->bitstart) | (mask << BIT_WRITEABLE_SHIFT); + + writel(val, pdata->regs_phy + reg->offset); +} + + +void otg_phy_init(struct dwc2_udc *dev) +{ + struct dwc2_plat_otg_data *pdata = dev->pdata; + struct rockchip_usb2_phy_cfg *phy_cfg = NULL; + struct rockchip_usb2_phy_dt_id *of_id; + int i; + + for (i = 0; i < ARRAY_SIZE(rockchip_usb2_phy_dt_ids); i++) { + of_id = &rockchip_usb2_phy_dt_ids[i]; + if (fdt_node_check_compatible(gd->fdt_blob, pdata->phy_of_node, + of_id->compatible) == 0) { + phy_cfg = (struct rockchip_usb2_phy_cfg *)of_id->data; + break; + } + } + if (!phy_cfg) { + debug("Can't find device platform data\n"); + + hang(); + return; + } + pdata->priv = phy_cfg; + /* disable software control */ + property_enable(pdata, &phy_cfg->soft_con, false); + + /* reset otg port */ + property_enable(pdata, &phy_cfg->port_reset, true); + mdelay(1); + property_enable(pdata, &phy_cfg->port_reset, false); + udelay(1); +} + +void otg_phy_off(struct dwc2_udc *dev) +{ + struct dwc2_plat_otg_data *pdata = dev->pdata; + struct rockchip_usb2_phy_cfg *phy_cfg = pdata->priv; + + /* enable software control */ + property_enable(pdata, &phy_cfg->soft_con, true); + /* enter suspend */ + property_enable(pdata, &phy_cfg->suspend, true); +} diff --git a/include/usb/dwc2_udc.h b/include/usb/dwc2_udc.h index 302e9a35a2..3ce43f8c01 100644 --- a/include/usb/dwc2_udc.h +++ b/include/usb/dwc2_udc.h @@ -12,6 +12,8 @@ #define PHY0_SLEEP (1 << 5) struct dwc2_plat_otg_data { + void *priv; + int phy_of_node; int (*phy_control)(int on); unsigned int regs_phy; unsigned int regs_otg;