Commit a9fc15e0 authored by Neil Armstrong's avatar Neil Armstrong Committed by Felipe Balbi
Browse files

usb: dwc3: meson-g12a: add support for GXL and GXM SoCs



In order to add support for the Amlogic GXL/GXM USB Glue, this adds
the corresponding :
- PHY names
- clock names
- USB2 PHY init and mode set
- regmap setup

Reviewed-by: default avatarMartin Blumenstingl <martin.blumenstingl@googlemail.com>
Signed-off-by: default avatarNeil Armstrong <narmstrong@baylibre.com>
Signed-off-by: default avatarFelipe Balbi <balbi@kernel.org>
parent df7e3745
Loading
Loading
Loading
Loading
+101 −1
Original line number Diff line number Diff line
@@ -101,6 +101,11 @@
#define PHY_COUNT						3
#define USB2_OTG_PHY						1

static struct clk_bulk_data meson_gxl_clocks[] = {
	{ .id = "usb_ctrl" },
	{ .id = "ddr" },
};

static struct clk_bulk_data meson_g12a_clocks[] = {
	{ .id = NULL },
};
@@ -111,6 +116,10 @@ static struct clk_bulk_data meson_a1_clocks[] = {
	{ .id = "xtal_usb_ctrl" },
};

static const char *meson_gxm_phy_names[] = {
	"usb2-phy0", "usb2-phy1", "usb2-phy2",
};

static const char *meson_g12a_phy_names[] = {
	"usb2-phy0", "usb2-phy1", "usb3-phy0",
};
@@ -145,16 +154,25 @@ struct dwc3_meson_g12a_drvdata {
	int (*usb_post_init)(struct dwc3_meson_g12a *priv);
};

static int dwc3_meson_gxl_setup_regmaps(struct dwc3_meson_g12a *priv,
					void __iomem *base);
static int dwc3_meson_g12a_setup_regmaps(struct dwc3_meson_g12a *priv,
					 void __iomem *base);

static int dwc3_meson_g12a_usb2_init_phy(struct dwc3_meson_g12a *priv, int i,
					 enum phy_mode mode);
static int dwc3_meson_gxl_usb2_init_phy(struct dwc3_meson_g12a *priv, int i,
					enum phy_mode mode);

static int dwc3_meson_g12a_set_phy_mode(struct dwc3_meson_g12a *priv,
					int i, enum phy_mode mode);
static int dwc3_meson_gxl_set_phy_mode(struct dwc3_meson_g12a *priv,
				       int i, enum phy_mode mode);

static int dwc3_meson_g12a_usb_init(struct dwc3_meson_g12a *priv);
static int dwc3_meson_gxl_usb_init(struct dwc3_meson_g12a *priv);

static int dwc3_meson_gxl_usb_post_init(struct dwc3_meson_g12a *priv);

/*
 * For GXL and GXM SoCs:
@@ -169,6 +187,34 @@ static int dwc3_meson_g12a_usb_init(struct dwc3_meson_g12a *priv);
 * reset to recover usage of the port.
 */

static struct dwc3_meson_g12a_drvdata gxl_drvdata = {
	.otg_switch_supported = true,
	.otg_phy_host_port_disable = true,
	.clks = meson_gxl_clocks,
	.num_clks = ARRAY_SIZE(meson_g12a_clocks),
	.phy_names = meson_a1_phy_names,
	.num_phys = ARRAY_SIZE(meson_a1_phy_names),
	.setup_regmaps = dwc3_meson_gxl_setup_regmaps,
	.usb2_init_phy = dwc3_meson_gxl_usb2_init_phy,
	.set_phy_mode = dwc3_meson_gxl_set_phy_mode,
	.usb_init = dwc3_meson_gxl_usb_init,
	.usb_post_init = dwc3_meson_gxl_usb_post_init,
};

static struct dwc3_meson_g12a_drvdata gxm_drvdata = {
	.otg_switch_supported = true,
	.otg_phy_host_port_disable = true,
	.clks = meson_gxl_clocks,
	.num_clks = ARRAY_SIZE(meson_g12a_clocks),
	.phy_names = meson_gxm_phy_names,
	.num_phys = ARRAY_SIZE(meson_gxm_phy_names),
	.setup_regmaps = dwc3_meson_gxl_setup_regmaps,
	.usb2_init_phy = dwc3_meson_gxl_usb2_init_phy,
	.set_phy_mode = dwc3_meson_gxl_set_phy_mode,
	.usb_init = dwc3_meson_gxl_usb_init,
	.usb_post_init = dwc3_meson_gxl_usb_post_init,
};

static struct dwc3_meson_g12a_drvdata g12a_drvdata = {
	.otg_switch_supported = true,
	.clks = meson_g12a_clocks,
@@ -209,6 +255,21 @@ struct dwc3_meson_g12a {
	const struct dwc3_meson_g12a_drvdata *drvdata;
};

static int dwc3_meson_gxl_set_phy_mode(struct dwc3_meson_g12a *priv,
					 int i, enum phy_mode mode)
{
	return phy_set_mode(priv->phys[i], mode);
}

static int dwc3_meson_gxl_usb2_init_phy(struct dwc3_meson_g12a *priv, int i,
					enum phy_mode mode)
{
	/* On GXL PHY must be started in device mode for DWC2 init */
	return priv->drvdata->set_phy_mode(priv, i,
				(i == USB2_OTG_PHY) ? PHY_MODE_USB_DEVICE
						    : PHY_MODE_USB_HOST);
}

static int dwc3_meson_g12a_set_phy_mode(struct dwc3_meson_g12a *priv,
					 int i, enum phy_mode mode)
{
@@ -559,6 +620,18 @@ static int dwc3_meson_g12a_otg_init(struct platform_device *pdev,
	return 0;
}

static int dwc3_meson_gxl_setup_regmaps(struct dwc3_meson_g12a *priv,
					void __iomem *base)
{
	/* GXL controls the PHY mode in the PHY registers unlike G12A */
	priv->usb_glue_regmap = devm_regmap_init_mmio(priv->dev, base,
					&phy_meson_g12a_usb_glue_regmap_conf);
	if (IS_ERR(priv->usb_glue_regmap))
		return PTR_ERR(priv->usb_glue_regmap);

	return 0;
}

static int dwc3_meson_g12a_setup_regmaps(struct dwc3_meson_g12a *priv,
					 void __iomem *base)
{
@@ -599,6 +672,25 @@ static int dwc3_meson_g12a_usb_init(struct dwc3_meson_g12a *priv)
	return dwc3_meson_g12a_usb_init_glue(priv, priv->otg_phy_mode);
}

static int dwc3_meson_gxl_usb_init(struct dwc3_meson_g12a *priv)
{
	return dwc3_meson_g12a_usb_init_glue(priv, PHY_MODE_USB_DEVICE);
}

static int dwc3_meson_gxl_usb_post_init(struct dwc3_meson_g12a *priv)
{
	int ret;

	ret = priv->drvdata->set_phy_mode(priv, USB2_OTG_PHY,
					  priv->otg_phy_mode);
	if (ret)
		return ret;

	dwc3_meson_g12a_usb_otg_apply_mode(priv, priv->otg_phy_mode);

	return 0;
}

static int dwc3_meson_g12a_probe(struct platform_device *pdev)
{
	struct dwc3_meson_g12a	*priv;
@@ -830,6 +922,14 @@ static const struct dev_pm_ops dwc3_meson_g12a_dev_pm_ops = {
};

static const struct of_device_id dwc3_meson_g12a_match[] = {
	{
		.compatible = "amlogic,meson-gxl-usb-ctrl",
		.data = &gxl_drvdata,
	},
	{
		.compatible = "amlogic,meson-gxm-usb-ctrl",
		.data = &gxm_drvdata,
	},
	{
		.compatible = "amlogic,meson-g12a-usb-ctrl",
		.data = &g12a_drvdata,