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

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
...@@ -101,6 +101,11 @@ ...@@ -101,6 +101,11 @@
#define PHY_COUNT 3 #define PHY_COUNT 3
#define USB2_OTG_PHY 1 #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[] = { static struct clk_bulk_data meson_g12a_clocks[] = {
{ .id = NULL }, { .id = NULL },
}; };
...@@ -111,6 +116,10 @@ static struct clk_bulk_data meson_a1_clocks[] = { ...@@ -111,6 +116,10 @@ static struct clk_bulk_data meson_a1_clocks[] = {
{ .id = "xtal_usb_ctrl" }, { .id = "xtal_usb_ctrl" },
}; };
static const char *meson_gxm_phy_names[] = {
"usb2-phy0", "usb2-phy1", "usb2-phy2",
};
static const char *meson_g12a_phy_names[] = { static const char *meson_g12a_phy_names[] = {
"usb2-phy0", "usb2-phy1", "usb3-phy0", "usb2-phy0", "usb2-phy1", "usb3-phy0",
}; };
...@@ -145,16 +154,25 @@ struct dwc3_meson_g12a_drvdata { ...@@ -145,16 +154,25 @@ struct dwc3_meson_g12a_drvdata {
int (*usb_post_init)(struct dwc3_meson_g12a *priv); 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, static int dwc3_meson_g12a_setup_regmaps(struct dwc3_meson_g12a *priv,
void __iomem *base); void __iomem *base);
static int dwc3_meson_g12a_usb2_init_phy(struct dwc3_meson_g12a *priv, int i, static int dwc3_meson_g12a_usb2_init_phy(struct dwc3_meson_g12a *priv, int i,
enum phy_mode mode); 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, static int dwc3_meson_g12a_set_phy_mode(struct dwc3_meson_g12a *priv,
int i, enum phy_mode mode); 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_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: * For GXL and GXM SoCs:
...@@ -169,6 +187,34 @@ static int dwc3_meson_g12a_usb_init(struct dwc3_meson_g12a *priv); ...@@ -169,6 +187,34 @@ static int dwc3_meson_g12a_usb_init(struct dwc3_meson_g12a *priv);
* reset to recover usage of the port. * 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 = { static struct dwc3_meson_g12a_drvdata g12a_drvdata = {
.otg_switch_supported = true, .otg_switch_supported = true,
.clks = meson_g12a_clocks, .clks = meson_g12a_clocks,
...@@ -209,6 +255,21 @@ struct dwc3_meson_g12a { ...@@ -209,6 +255,21 @@ struct dwc3_meson_g12a {
const struct dwc3_meson_g12a_drvdata *drvdata; 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, static int dwc3_meson_g12a_set_phy_mode(struct dwc3_meson_g12a *priv,
int i, enum phy_mode mode) int i, enum phy_mode mode)
{ {
...@@ -559,6 +620,18 @@ static int dwc3_meson_g12a_otg_init(struct platform_device *pdev, ...@@ -559,6 +620,18 @@ static int dwc3_meson_g12a_otg_init(struct platform_device *pdev,
return 0; 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, static int dwc3_meson_g12a_setup_regmaps(struct dwc3_meson_g12a *priv,
void __iomem *base) void __iomem *base)
{ {
...@@ -599,6 +672,25 @@ static int dwc3_meson_g12a_usb_init(struct dwc3_meson_g12a *priv) ...@@ -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); 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) static int dwc3_meson_g12a_probe(struct platform_device *pdev)
{ {
struct dwc3_meson_g12a *priv; struct dwc3_meson_g12a *priv;
...@@ -830,6 +922,14 @@ static const struct dev_pm_ops dwc3_meson_g12a_dev_pm_ops = { ...@@ -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[] = { 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", .compatible = "amlogic,meson-g12a-usb-ctrl",
.data = &g12a_drvdata, .data = &g12a_drvdata,
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment