usb: rockchip-phy: implement USB2.0 phy control
authorXu Ziyuan <xzy.xu@rock-chips.com>
Thu, 14 Jul 2016 06:52:32 +0000 (14:52 +0800)
committerSimon Glass <sjg@chromium.org>
Tue, 26 Jul 2016 02:44:19 +0000 (20:44 -0600)
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 <xzy.xu@rock-chips.com>
Acked-by: Simon Glass <sjg@chromium.org>
drivers/usb/phy/Makefile
drivers/usb/phy/rockchip_usb2_phy.c [new file with mode: 0644]
include/usb/dwc2_udc.h

index 93d147e26f17fb985e803db7c79d7d9eb054bf63..4e548c24ec859cf92749afea8ecd8bf16b46401b 100644 (file)
@@ -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 (file)
index 0000000..1958478
--- /dev/null
@@ -0,0 +1,107 @@
+/*
+ * Copyright 2016 Rockchip Electronics Co., Ltd
+ *
+ * SPDX-License-Identifier:    GPL-2.0+
+ */
+
+#include <common.h>
+#include <asm/io.h>
+#include <libfdt.h>
+
+#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);
+}
index 302e9a35a23389c82925a7ec0c9bcc9746f0fa5b..3ce43f8c011be3c8dd685838beb5a515fc470e4e 100644 (file)
@@ -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;