summaryrefslogtreecommitdiffstats
path: root/drivers/usb/renesas_usbhs
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/usb/renesas_usbhs')
-rw-r--r--drivers/usb/renesas_usbhs/Kconfig1
-rw-r--r--drivers/usb/renesas_usbhs/Makefile2
-rw-r--r--drivers/usb/renesas_usbhs/common.c160
-rw-r--r--drivers/usb/renesas_usbhs/common.h8
-rw-r--r--drivers/usb/renesas_usbhs/fifo.c15
-rw-r--r--drivers/usb/renesas_usbhs/rza.h1
-rw-r--r--drivers/usb/renesas_usbhs/rza2.c72
7 files changed, 181 insertions, 78 deletions
diff --git a/drivers/usb/renesas_usbhs/Kconfig b/drivers/usb/renesas_usbhs/Kconfig
index 7fdbff23ae8b..d6b3fef3e55b 100644
--- a/drivers/usb/renesas_usbhs/Kconfig
+++ b/drivers/usb/renesas_usbhs/Kconfig
@@ -8,7 +8,6 @@ config USB_RENESAS_USBHS
depends on USB_GADGET
depends on ARCH_RENESAS || SUPERH || COMPILE_TEST
depends on EXTCON || !EXTCON # if EXTCON=m, USBHS cannot be built-in
- default n
help
Renesas USBHS is a discrete USB host and peripheral controller chip
that supports both full and high speed USB 2.0 data transfers.
diff --git a/drivers/usb/renesas_usbhs/Makefile b/drivers/usb/renesas_usbhs/Makefile
index 5c5b51bb48ef..a1fed56b0957 100644
--- a/drivers/usb/renesas_usbhs/Makefile
+++ b/drivers/usb/renesas_usbhs/Makefile
@@ -5,7 +5,7 @@
obj-$(CONFIG_USB_RENESAS_USBHS) += renesas_usbhs.o
-renesas_usbhs-y := common.o mod.o pipe.o fifo.o rcar2.o rcar3.o rza.o
+renesas_usbhs-y := common.o mod.o pipe.o fifo.o rcar2.o rcar3.o rza.o rza2.o
ifneq ($(CONFIG_USB_RENESAS_USBHS_HCD),)
renesas_usbhs-y += mod_host.o
diff --git a/drivers/usb/renesas_usbhs/common.c b/drivers/usb/renesas_usbhs/common.c
index 249fbee97f3f..a501ea609019 100644
--- a/drivers/usb/renesas_usbhs/common.c
+++ b/drivers/usb/renesas_usbhs/common.c
@@ -43,15 +43,6 @@
* | .... | +-----------+
*/
-
-#define USBHSF_RUNTIME_PWCTRL (1 << 0)
-
-/* status */
-#define usbhsc_flags_init(p) do {(p)->flags = 0; } while (0)
-#define usbhsc_flags_set(p, b) ((p)->flags |= (b))
-#define usbhsc_flags_clr(p, b) ((p)->flags &= ~(b))
-#define usbhsc_flags_has(p, b) ((p)->flags & (b))
-
/*
* platform call back
*
@@ -104,10 +95,6 @@ void usbhs_sys_host_ctrl(struct usbhs_priv *priv, int enable)
{
u16 mask = DCFM | DRPD | DPRPU | HSE | USBE;
u16 val = DCFM | DRPD | HSE | USBE;
- int has_otg = usbhs_get_dparam(priv, has_otg);
-
- if (has_otg)
- usbhs_bset(priv, DVSTCTR, (EXTLP | PWEN), (EXTLP | PWEN));
/*
* if enable
@@ -123,6 +110,12 @@ void usbhs_sys_function_ctrl(struct usbhs_priv *priv, int enable)
u16 mask = DCFM | DRPD | DPRPU | HSE | USBE;
u16 val = HSE | USBE;
+ /* CNEN bit is required for function operation */
+ if (usbhs_get_dparam(priv, has_cnen)) {
+ mask |= CNEN;
+ val |= CNEN;
+ }
+
/*
* if enable
*
@@ -479,7 +472,7 @@ static void usbhsc_hotplug(struct usbhs_priv *priv)
dev_dbg(&pdev->dev, "%s enable\n", __func__);
/* power on */
- if (usbhsc_flags_has(priv, USBHSF_RUNTIME_PWCTRL))
+ if (usbhs_get_dparam(priv, runtime_pwctrl))
usbhsc_power_ctrl(priv, enable);
/* bus init */
@@ -499,7 +492,7 @@ static void usbhsc_hotplug(struct usbhs_priv *priv)
usbhsc_bus_init(priv);
/* power off */
- if (usbhsc_flags_has(priv, USBHSF_RUNTIME_PWCTRL))
+ if (usbhs_get_dparam(priv, runtime_pwctrl))
usbhsc_power_ctrl(priv, enable);
usbhs_mod_change(priv, -1);
@@ -535,53 +528,107 @@ static int usbhsc_drvcllbck_notify_hotplug(struct platform_device *pdev)
return 0;
}
+static const struct usbhs_of_data rcar_gen2_data = {
+ .platform_callback = &usbhs_rcar2_ops,
+ .param = {
+ .type = USBHS_TYPE_RCAR_GEN2,
+ .has_usb_dmac = 1,
+ .pipe_configs = usbhsc_new_pipe,
+ .pipe_size = ARRAY_SIZE(usbhsc_new_pipe),
+ }
+};
+
+static const struct usbhs_of_data rcar_gen3_data = {
+ .platform_callback = &usbhs_rcar3_ops,
+ .param = {
+ .type = USBHS_TYPE_RCAR_GEN3,
+ .has_usb_dmac = 1,
+ .pipe_configs = usbhsc_new_pipe,
+ .pipe_size = ARRAY_SIZE(usbhsc_new_pipe),
+ }
+};
+
+static const struct usbhs_of_data rcar_gen3_with_pll_data = {
+ .platform_callback = &usbhs_rcar3_with_pll_ops,
+ .param = {
+ .type = USBHS_TYPE_RCAR_GEN3_WITH_PLL,
+ .has_usb_dmac = 1,
+ .pipe_configs = usbhsc_new_pipe,
+ .pipe_size = ARRAY_SIZE(usbhsc_new_pipe),
+ }
+};
+
+static const struct usbhs_of_data rza1_data = {
+ .platform_callback = &usbhs_rza1_ops,
+ .param = {
+ .type = USBHS_TYPE_RZA1,
+ .pipe_configs = usbhsc_new_pipe,
+ .pipe_size = ARRAY_SIZE(usbhsc_new_pipe),
+ }
+};
+
+static const struct usbhs_of_data rza2_data = {
+ .platform_callback = &usbhs_rza2_ops,
+ .param = {
+ .type = USBHS_TYPE_RZA2,
+ .has_cnen = 1,
+ .cfifo_byte_addr = 1,
+ .pipe_configs = usbhsc_new_pipe,
+ .pipe_size = ARRAY_SIZE(usbhsc_new_pipe),
+ }
+};
+
/*
* platform functions
*/
static const struct of_device_id usbhs_of_match[] = {
{
.compatible = "renesas,usbhs-r8a774c0",
- .data = (void *)USBHS_TYPE_RCAR_GEN3_WITH_PLL,
+ .data = &rcar_gen3_with_pll_data,
},
{
.compatible = "renesas,usbhs-r8a7790",
- .data = (void *)USBHS_TYPE_RCAR_GEN2,
+ .data = &rcar_gen2_data,
},
{
.compatible = "renesas,usbhs-r8a7791",
- .data = (void *)USBHS_TYPE_RCAR_GEN2,
+ .data = &rcar_gen2_data,
},
{
.compatible = "renesas,usbhs-r8a7794",
- .data = (void *)USBHS_TYPE_RCAR_GEN2,
+ .data = &rcar_gen2_data,
},
{
.compatible = "renesas,usbhs-r8a7795",
- .data = (void *)USBHS_TYPE_RCAR_GEN3,
+ .data = &rcar_gen3_data,
},
{
.compatible = "renesas,usbhs-r8a7796",
- .data = (void *)USBHS_TYPE_RCAR_GEN3,
+ .data = &rcar_gen3_data,
},
{
.compatible = "renesas,usbhs-r8a77990",
- .data = (void *)USBHS_TYPE_RCAR_GEN3_WITH_PLL,
+ .data = &rcar_gen3_with_pll_data,
},
{
.compatible = "renesas,usbhs-r8a77995",
- .data = (void *)USBHS_TYPE_RCAR_GEN3_WITH_PLL,
+ .data = &rcar_gen3_with_pll_data,
},
{
.compatible = "renesas,rcar-gen2-usbhs",
- .data = (void *)USBHS_TYPE_RCAR_GEN2,
+ .data = &rcar_gen2_data,
},
{
.compatible = "renesas,rcar-gen3-usbhs",
- .data = (void *)USBHS_TYPE_RCAR_GEN3,
+ .data = &rcar_gen3_data,
},
{
.compatible = "renesas,rza1-usbhs",
- .data = (void *)USBHS_TYPE_RZA1,
+ .data = &rza1_data,
+ },
+ {
+ .compatible = "renesas,rza2-usbhs",
+ .data = &rza2_data,
},
{ },
};
@@ -591,6 +638,7 @@ static struct renesas_usbhs_platform_info *usbhs_parse_dt(struct device *dev)
{
struct renesas_usbhs_platform_info *info;
struct renesas_usbhs_driver_param *dparam;
+ const struct usbhs_of_data *data;
u32 tmp;
int gpio;
@@ -598,8 +646,15 @@ static struct renesas_usbhs_platform_info *usbhs_parse_dt(struct device *dev)
if (!info)
return NULL;
+ data = of_device_get_match_data(dev);
+ if (!data)
+ return NULL;
+
dparam = &info->driver_param;
- dparam->type = (uintptr_t)of_device_get_match_data(dev);
+ memcpy(dparam, &data->param, sizeof(data->param));
+ memcpy(&info->platform_callback, data->platform_callback,
+ sizeof(*data->platform_callback));
+
if (!of_property_read_u32(dev->of_node, "renesas,buswait", &tmp))
dparam->buswait_bwait = tmp;
gpio = of_get_named_gpio_flags(dev->of_node, "renesas,enable-gpio", 0,
@@ -607,19 +662,6 @@ static struct renesas_usbhs_platform_info *usbhs_parse_dt(struct device *dev)
if (gpio > 0)
dparam->enable_gpio = gpio;
- if (dparam->type == USBHS_TYPE_RCAR_GEN2 ||
- dparam->type == USBHS_TYPE_RCAR_GEN3 ||
- dparam->type == USBHS_TYPE_RCAR_GEN3_WITH_PLL) {
- dparam->has_usb_dmac = 1;
- dparam->pipe_configs = usbhsc_new_pipe;
- dparam->pipe_size = ARRAY_SIZE(usbhsc_new_pipe);
- }
-
- if (dparam->type == USBHS_TYPE_RZA1) {
- dparam->pipe_configs = usbhsc_new_pipe;
- dparam->pipe_size = ARRAY_SIZE(usbhsc_new_pipe);
- }
-
return info;
}
@@ -676,29 +718,13 @@ static int usbhs_probe(struct platform_device *pdev)
&info->driver_param,
sizeof(struct renesas_usbhs_driver_param));
- switch (priv->dparam.type) {
- case USBHS_TYPE_RCAR_GEN2:
- priv->pfunc = usbhs_rcar2_ops;
- break;
- case USBHS_TYPE_RCAR_GEN3:
- priv->pfunc = usbhs_rcar3_ops;
- break;
- case USBHS_TYPE_RCAR_GEN3_WITH_PLL:
- priv->pfunc = usbhs_rcar3_with_pll_ops;
- break;
- case USBHS_TYPE_RZA1:
- priv->pfunc = usbhs_rza1_ops;
- break;
- default:
- if (!info->platform_callback.get_id) {
- dev_err(&pdev->dev, "no platform callbacks");
- return -EINVAL;
- }
- memcpy(&priv->pfunc,
- &info->platform_callback,
- sizeof(struct renesas_usbhs_platform_callback));
- break;
+ if (!info->platform_callback.get_id) {
+ dev_err(&pdev->dev, "no platform callbacks");
+ return -EINVAL;
}
+ memcpy(&priv->pfunc,
+ &info->platform_callback,
+ sizeof(struct renesas_usbhs_platform_callback));
/* set driver callback functions for platform */
dfunc = &info->driver_callback;
@@ -715,7 +741,7 @@ static int usbhs_probe(struct platform_device *pdev)
/* FIXME */
/* runtime power control ? */
if (priv->pfunc.get_vbus)
- usbhsc_flags_set(priv, USBHSF_RUNTIME_PWCTRL);
+ usbhs_get_dparam(priv, runtime_pwctrl) = 1;
/*
* priv settings
@@ -789,7 +815,7 @@ static int usbhs_probe(struct platform_device *pdev)
/* power control */
pm_runtime_enable(&pdev->dev);
- if (!usbhsc_flags_has(priv, USBHSF_RUNTIME_PWCTRL)) {
+ if (!usbhs_get_dparam(priv, runtime_pwctrl)) {
usbhsc_power_ctrl(priv, 1);
usbhs_mod_autonomy_mode(priv);
}
@@ -830,7 +856,7 @@ static int usbhs_remove(struct platform_device *pdev)
dfunc->notify_hotplug = NULL;
/* power off */
- if (!usbhsc_flags_has(priv, USBHSF_RUNTIME_PWCTRL))
+ if (!usbhs_get_dparam(priv, runtime_pwctrl))
usbhsc_power_ctrl(priv, 0);
pm_runtime_disable(&pdev->dev);
@@ -855,7 +881,7 @@ static __maybe_unused int usbhsc_suspend(struct device *dev)
usbhs_mod_change(priv, -1);
}
- if (mod || !usbhsc_flags_has(priv, USBHSF_RUNTIME_PWCTRL))
+ if (mod || !usbhs_get_dparam(priv, runtime_pwctrl))
usbhsc_power_ctrl(priv, 0);
return 0;
@@ -866,7 +892,7 @@ static __maybe_unused int usbhsc_resume(struct device *dev)
struct usbhs_priv *priv = dev_get_drvdata(dev);
struct platform_device *pdev = usbhs_priv_to_pdev(priv);
- if (!usbhsc_flags_has(priv, USBHSF_RUNTIME_PWCTRL)) {
+ if (!usbhs_get_dparam(priv, runtime_pwctrl)) {
usbhsc_power_ctrl(priv, 1);
usbhs_mod_autonomy_mode(priv);
}
diff --git a/drivers/usb/renesas_usbhs/common.h b/drivers/usb/renesas_usbhs/common.h
index 3777af848a35..de74ebd1a347 100644
--- a/drivers/usb/renesas_usbhs/common.h
+++ b/drivers/usb/renesas_usbhs/common.h
@@ -104,6 +104,7 @@ struct usbhs_priv;
/* SYSCFG */
#define SCKE (1 << 10) /* USB Module Clock Enable */
+#define CNEN (1 << 8) /* Single-ended receiver operation Enable */
#define HSE (1 << 7) /* High-Speed Operation Enable */
#define DCFM (1 << 6) /* Controller Function Select */
#define DRPD (1 << 5) /* D+ Line/D- Line Resistance Control */
@@ -260,8 +261,6 @@ struct usbhs_priv {
spinlock_t lock;
- u32 flags;
-
/*
* module control
*/
@@ -282,6 +281,11 @@ struct usbhs_priv {
struct clk *clks[2];
};
+struct usbhs_of_data {
+ const struct renesas_usbhs_platform_callback *platform_callback;
+ const struct renesas_usbhs_driver_param param;
+};
+
/*
* common
*/
diff --git a/drivers/usb/renesas_usbhs/fifo.c b/drivers/usb/renesas_usbhs/fifo.c
index 39fa2fc1b8b7..e84d2ac2a30a 100644
--- a/drivers/usb/renesas_usbhs/fifo.c
+++ b/drivers/usb/renesas_usbhs/fifo.c
@@ -12,7 +12,6 @@
#include "pipe.h"
#define usbhsf_get_cfifo(p) (&((p)->fifo_info.cfifo))
-#define usbhsf_is_cfifo(p, f) (usbhsf_get_cfifo(p) == f)
#define usbhsf_fifo_is_busy(f) ((f)->pipe) /* see usbhs_pipe_select_fifo */
@@ -325,10 +324,7 @@ static int usbhsf_fifo_select(struct usbhs_pipe *pipe,
}
/* "base" will be used below */
- if (usbhs_get_dparam(priv, has_sudmac) && !usbhsf_is_cfifo(priv, fifo))
- usbhs_write(priv, fifo->sel, base);
- else
- usbhs_write(priv, fifo->sel, base | MBW_32);
+ usbhs_write(priv, fifo->sel, base | MBW_32);
/* check ISEL and CURPIPE value */
while (timeout--) {
@@ -543,8 +539,13 @@ static int usbhsf_pio_try_push(struct usbhs_pkt *pkt, int *is_done)
}
/* the rest operation */
- for (i = 0; i < len; i++)
- iowrite8(buf[i], addr + (0x03 - (i & 0x03)));
+ if (usbhs_get_dparam(priv, cfifo_byte_addr)) {
+ for (i = 0; i < len; i++)
+ iowrite8(buf[i], addr + (i & 0x03));
+ } else {
+ for (i = 0; i < len; i++)
+ iowrite8(buf[i], addr + (0x03 - (i & 0x03)));
+ }
/*
* variable update
diff --git a/drivers/usb/renesas_usbhs/rza.h b/drivers/usb/renesas_usbhs/rza.h
index ca917ca54f6d..073a53d1d442 100644
--- a/drivers/usb/renesas_usbhs/rza.h
+++ b/drivers/usb/renesas_usbhs/rza.h
@@ -2,3 +2,4 @@
#include "common.h"
extern const struct renesas_usbhs_platform_callback usbhs_rza1_ops;
+extern const struct renesas_usbhs_platform_callback usbhs_rza2_ops;
diff --git a/drivers/usb/renesas_usbhs/rza2.c b/drivers/usb/renesas_usbhs/rza2.c
new file mode 100644
index 000000000000..9d8551f93533
--- /dev/null
+++ b/drivers/usb/renesas_usbhs/rza2.c
@@ -0,0 +1,72 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Renesas USB driver RZ/A2 initialization and power control
+ *
+ * Copyright (C) 2019 Chris Brandt
+ * Copyright (C) 2019 Renesas Electronics Corporation
+ */
+
+#include <linux/delay.h>
+#include <linux/io.h>
+#include <linux/of_device.h>
+#include <linux/phy/phy.h>
+#include "common.h"
+#include "rza.h"
+
+static int usbhs_rza2_hardware_init(struct platform_device *pdev)
+{
+ struct usbhs_priv *priv = usbhs_pdev_to_priv(pdev);
+ struct phy *phy = phy_get(&pdev->dev, "usb");
+
+ if (IS_ERR(phy))
+ return PTR_ERR(phy);
+
+ priv->phy = phy;
+ return 0;
+}
+
+static int usbhs_rza2_hardware_exit(struct platform_device *pdev)
+{
+ struct usbhs_priv *priv = usbhs_pdev_to_priv(pdev);
+
+ phy_put(priv->phy);
+ priv->phy = NULL;
+
+ return 0;
+}
+
+static int usbhs_rza2_power_ctrl(struct platform_device *pdev,
+ void __iomem *base, int enable)
+{
+ struct usbhs_priv *priv = usbhs_pdev_to_priv(pdev);
+ int retval = 0;
+
+ if (!priv->phy)
+ return -ENODEV;
+
+ if (enable) {
+ retval = phy_init(priv->phy);
+ usbhs_bset(priv, SUSPMODE, SUSPM, SUSPM);
+ udelay(100); /* Wait for PLL to become stable */
+ if (!retval)
+ retval = phy_power_on(priv->phy);
+ } else {
+ usbhs_bset(priv, SUSPMODE, SUSPM, 0);
+ phy_power_off(priv->phy);
+ phy_exit(priv->phy);
+ }
+
+ return retval;
+}
+
+static int usbhs_rza2_get_id(struct platform_device *pdev)
+{
+ return USBHS_GADGET;
+}
+
+const struct renesas_usbhs_platform_callback usbhs_rza2_ops = {
+ .hardware_init = usbhs_rza2_hardware_init,
+ .hardware_exit = usbhs_rza2_hardware_exit,
+ .power_ctrl = usbhs_rza2_power_ctrl,
+ .get_id = usbhs_rza2_get_id,
+};