Update Linux to v5.4.2
Change-Id: Idf6911045d9d382da2cfe01b1edff026404ac8fd
diff --git a/drivers/usb/renesas_usbhs/Kconfig b/drivers/usb/renesas_usbhs/Kconfig
index 7fdbff2..d6b3fef 100644
--- a/drivers/usb/renesas_usbhs/Kconfig
+++ b/drivers/usb/renesas_usbhs/Kconfig
@@ -8,7 +8,6 @@
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 5c5b51b..a1fed56 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 4310df4..a3c30b6 100644
--- a/drivers/usb/renesas_usbhs/common.c
+++ b/drivers/usb/renesas_usbhs/common.c
@@ -3,8 +3,10 @@
* Renesas USB driver
*
* Copyright (C) 2011 Renesas Solutions Corp.
+ * Copyright (C) 2019 Renesas Electronics Corporation
* Kuninori Morimoto <kuninori.morimoto.gx@renesas.com>
*/
+#include <linux/clk.h>
#include <linux/err.h>
#include <linux/gpio.h>
#include <linux/io.h>
@@ -12,6 +14,7 @@
#include <linux/of_device.h>
#include <linux/of_gpio.h>
#include <linux/pm_runtime.h>
+#include <linux/reset.h>
#include <linux/slab.h>
#include <linux/sysfs.h>
#include "common.h"
@@ -41,15 +44,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
*
@@ -59,8 +53,8 @@
*/
#define usbhs_platform_call(priv, func, args...)\
(!(priv) ? -ENODEV : \
- !((priv)->pfunc.func) ? 0 : \
- (priv)->pfunc.func(args))
+ !((priv)->pfunc->func) ? 0 : \
+ (priv)->pfunc->func(args))
/*
* common functions
@@ -90,6 +84,11 @@
return dev_get_drvdata(&pdev->dev);
}
+int usbhs_get_id_as_gadget(struct platform_device *pdev)
+{
+ return USBHS_GADGET;
+}
+
/*
* syscfg functions
*/
@@ -102,10 +101,6 @@
{
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
@@ -121,6 +116,12 @@
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
*
@@ -161,17 +162,17 @@
req->bRequest = (val >> 8) & 0xFF;
req->bRequestType = (val >> 0) & 0xFF;
- req->wValue = usbhs_read(priv, USBVAL);
- req->wIndex = usbhs_read(priv, USBINDX);
- req->wLength = usbhs_read(priv, USBLENG);
+ req->wValue = cpu_to_le16(usbhs_read(priv, USBVAL));
+ req->wIndex = cpu_to_le16(usbhs_read(priv, USBINDX));
+ req->wLength = cpu_to_le16(usbhs_read(priv, USBLENG));
}
void usbhs_usbreq_set_val(struct usbhs_priv *priv, struct usb_ctrlrequest *req)
{
usbhs_write(priv, USBREQ, (req->bRequest << 8) | req->bRequestType);
- usbhs_write(priv, USBVAL, req->wValue);
- usbhs_write(priv, USBINDX, req->wIndex);
- usbhs_write(priv, USBLENG, req->wLength);
+ usbhs_write(priv, USBVAL, le16_to_cpu(req->wValue));
+ usbhs_write(priv, USBINDX, le16_to_cpu(req->wIndex));
+ usbhs_write(priv, USBLENG, le16_to_cpu(req->wLength));
usbhs_bset(priv, DCPCTR, SUREQ, SUREQ);
}
@@ -290,6 +291,75 @@
usbhs_bset(priv, BUSWAIT, 0x000F, wait);
}
+static bool usbhsc_is_multi_clks(struct usbhs_priv *priv)
+{
+ return priv->dparam.multi_clks;
+}
+
+static int usbhsc_clk_get(struct device *dev, struct usbhs_priv *priv)
+{
+ if (!usbhsc_is_multi_clks(priv))
+ return 0;
+
+ /* The first clock should exist */
+ priv->clks[0] = of_clk_get(dev_of_node(dev), 0);
+ if (IS_ERR(priv->clks[0]))
+ return PTR_ERR(priv->clks[0]);
+
+ /*
+ * To backward compatibility with old DT, this driver checks the return
+ * value if it's -ENOENT or not.
+ */
+ priv->clks[1] = of_clk_get(dev_of_node(dev), 1);
+ if (PTR_ERR(priv->clks[1]) == -ENOENT)
+ priv->clks[1] = NULL;
+ else if (IS_ERR(priv->clks[1]))
+ return PTR_ERR(priv->clks[1]);
+
+ return 0;
+}
+
+static void usbhsc_clk_put(struct usbhs_priv *priv)
+{
+ int i;
+
+ if (!usbhsc_is_multi_clks(priv))
+ return;
+
+ for (i = 0; i < ARRAY_SIZE(priv->clks); i++)
+ clk_put(priv->clks[i]);
+}
+
+static int usbhsc_clk_prepare_enable(struct usbhs_priv *priv)
+{
+ int i, ret;
+
+ if (!usbhsc_is_multi_clks(priv))
+ return 0;
+
+ for (i = 0; i < ARRAY_SIZE(priv->clks); i++) {
+ ret = clk_prepare_enable(priv->clks[i]);
+ if (ret) {
+ while (--i >= 0)
+ clk_disable_unprepare(priv->clks[i]);
+ return ret;
+ }
+ }
+
+ return ret;
+}
+
+static void usbhsc_clk_disable_unprepare(struct usbhs_priv *priv)
+{
+ int i;
+
+ if (!usbhsc_is_multi_clks(priv))
+ return;
+
+ for (i = 0; i < ARRAY_SIZE(priv->clks); i++)
+ clk_disable_unprepare(priv->clks[i]);
+}
+
/*
* platform default param
*/
@@ -340,6 +410,10 @@
/* enable PM */
pm_runtime_get_sync(dev);
+ /* enable clks */
+ if (usbhsc_clk_prepare_enable(priv))
+ return;
+
/* enable platform power */
usbhs_platform_call(priv, power_ctrl, pdev, priv->base, enable);
@@ -352,6 +426,9 @@
/* disable platform power */
usbhs_platform_call(priv, power_ctrl, pdev, priv->base, enable);
+ /* disable clks */
+ usbhsc_clk_disable_unprepare(priv);
+
/* disable PM */
pm_runtime_put_sync(dev);
}
@@ -372,7 +449,7 @@
/*
* get vbus status from platform
*/
- enable = usbhs_platform_call(priv, get_vbus, pdev);
+ enable = usbhs_mod_info_call(priv, get_vbus, pdev);
/*
* get id from platform
@@ -397,7 +474,7 @@
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 */
@@ -417,7 +494,7 @@
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);
@@ -438,7 +515,7 @@
usbhsc_hotplug(priv);
}
-static int usbhsc_drvcllbck_notify_hotplug(struct platform_device *pdev)
+int usbhsc_schedule_notify_hotplug(struct platform_device *pdev)
{
struct usbhs_priv *priv = usbhs_pdev_to_priv(pdev);
int delay = usbhs_get_dparam(priv, detection_delay);
@@ -458,108 +535,87 @@
*/
static const struct of_device_id usbhs_of_match[] = {
{
+ .compatible = "renesas,usbhs-r8a774c0",
+ .data = &usbhs_rcar_gen3_with_pll_plat_info,
+ },
+ {
.compatible = "renesas,usbhs-r8a7790",
- .data = (void *)USBHS_TYPE_RCAR_GEN2,
+ .data = &usbhs_rcar_gen2_plat_info,
},
{
.compatible = "renesas,usbhs-r8a7791",
- .data = (void *)USBHS_TYPE_RCAR_GEN2,
+ .data = &usbhs_rcar_gen2_plat_info,
},
{
.compatible = "renesas,usbhs-r8a7794",
- .data = (void *)USBHS_TYPE_RCAR_GEN2,
+ .data = &usbhs_rcar_gen2_plat_info,
},
{
.compatible = "renesas,usbhs-r8a7795",
- .data = (void *)USBHS_TYPE_RCAR_GEN3,
+ .data = &usbhs_rcar_gen3_plat_info,
},
{
.compatible = "renesas,usbhs-r8a7796",
- .data = (void *)USBHS_TYPE_RCAR_GEN3,
+ .data = &usbhs_rcar_gen3_plat_info,
+ },
+ {
+ .compatible = "renesas,usbhs-r8a77990",
+ .data = &usbhs_rcar_gen3_with_pll_plat_info,
},
{
.compatible = "renesas,usbhs-r8a77995",
- .data = (void *)USBHS_TYPE_RCAR_GEN3_WITH_PLL,
+ .data = &usbhs_rcar_gen3_with_pll_plat_info,
},
{
.compatible = "renesas,rcar-gen2-usbhs",
- .data = (void *)USBHS_TYPE_RCAR_GEN2,
+ .data = &usbhs_rcar_gen2_plat_info,
},
{
.compatible = "renesas,rcar-gen3-usbhs",
- .data = (void *)USBHS_TYPE_RCAR_GEN3,
+ .data = &usbhs_rcar_gen3_plat_info,
},
{
.compatible = "renesas,rza1-usbhs",
- .data = (void *)USBHS_TYPE_RZA1,
+ .data = &usbhs_rza1_plat_info,
+ },
+ {
+ .compatible = "renesas,rza2-usbhs",
+ .data = &usbhs_rza2_plat_info,
},
{ },
};
MODULE_DEVICE_TABLE(of, usbhs_of_match);
-static struct renesas_usbhs_platform_info *usbhs_parse_dt(struct device *dev)
-{
- struct renesas_usbhs_platform_info *info;
- struct renesas_usbhs_driver_param *dparam;
- u32 tmp;
- int gpio;
-
- info = devm_kzalloc(dev, sizeof(*info), GFP_KERNEL);
- if (!info)
- return NULL;
-
- dparam = &info->driver_param;
- dparam->type = (uintptr_t)of_device_get_match_data(dev);
- 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,
- NULL);
- 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;
-}
-
static int usbhs_probe(struct platform_device *pdev)
{
- struct renesas_usbhs_platform_info *info = renesas_usbhs_get_info(pdev);
- struct renesas_usbhs_driver_callback *dfunc;
+ const struct renesas_usbhs_platform_info *info;
struct usbhs_priv *priv;
struct resource *res, *irq_res;
- int ret;
+ struct device *dev = &pdev->dev;
+ int ret, gpio;
+ u32 tmp;
/* check device node */
- if (pdev->dev.of_node)
- info = pdev->dev.platform_data = usbhs_parse_dt(&pdev->dev);
+ if (dev_of_node(dev))
+ info = of_device_get_match_data(dev);
+ else
+ info = renesas_usbhs_get_info(pdev);
/* check platform information */
if (!info) {
- dev_err(&pdev->dev, "no platform information\n");
+ dev_err(dev, "no platform information\n");
return -EINVAL;
}
/* platform data */
irq_res = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
if (!irq_res) {
- dev_err(&pdev->dev, "Not enough Renesas USB platform resources.\n");
+ dev_err(dev, "Not enough Renesas USB platform resources.\n");
return -ENODEV;
}
/* usb private data */
- priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL);
+ priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
if (!priv)
return -ENOMEM;
@@ -568,69 +624,49 @@
if (IS_ERR(priv->base))
return PTR_ERR(priv->base);
- if (of_property_read_bool(pdev->dev.of_node, "extcon")) {
- priv->edev = extcon_get_edev_by_phandle(&pdev->dev, 0);
+ if (of_property_read_bool(dev_of_node(dev), "extcon")) {
+ priv->edev = extcon_get_edev_by_phandle(dev, 0);
if (IS_ERR(priv->edev))
return PTR_ERR(priv->edev);
}
+ priv->rsts = devm_reset_control_array_get_optional_shared(dev);
+ if (IS_ERR(priv->rsts))
+ return PTR_ERR(priv->rsts);
+
/*
* care platform info
*/
- memcpy(&priv->dparam,
- &info->driver_param,
- sizeof(struct renesas_usbhs_driver_param));
+ priv->dparam = info->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;
- if (!IS_ERR_OR_NULL(priv->edev)) {
- priv->nb.notifier_call = priv->pfunc.notifier;
- ret = devm_extcon_register_notifier(&pdev->dev,
- priv->edev,
- EXTCON_USB_HOST,
- &priv->nb);
- if (ret < 0)
- dev_err(&pdev->dev, "no notifier registered\n");
- }
- 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(dev, "no platform callbacks\n");
+ return -EINVAL;
}
-
- /* set driver callback functions for platform */
- dfunc = &info->driver_callback;
- dfunc->notify_hotplug = usbhsc_drvcllbck_notify_hotplug;
+ priv->pfunc = &info->platform_callback;
/* set default param if platform doesn't have */
- if (!priv->dparam.pipe_configs) {
+ if (usbhs_get_dparam(priv, has_new_pipe_configs)) {
+ priv->dparam.pipe_configs = usbhsc_new_pipe;
+ priv->dparam.pipe_size = ARRAY_SIZE(usbhsc_new_pipe);
+ } else if (!priv->dparam.pipe_configs) {
priv->dparam.pipe_configs = usbhsc_default_pipe;
priv->dparam.pipe_size = ARRAY_SIZE(usbhsc_default_pipe);
}
if (!priv->dparam.pio_dma_border)
priv->dparam.pio_dma_border = 64; /* 64byte */
+ if (!of_property_read_u32(dev_of_node(dev), "renesas,buswait", &tmp))
+ priv->dparam.buswait_bwait = tmp;
+ gpio = of_get_named_gpio_flags(dev_of_node(dev), "renesas,enable-gpio",
+ 0, NULL);
+ if (gpio > 0)
+ priv->dparam.enable_gpio = gpio;
/* FIXME */
/* runtime power control ? */
- if (priv->pfunc.get_vbus)
- usbhsc_flags_set(priv, USBHSF_RUNTIME_PWCTRL);
+ if (priv->pfunc->get_vbus)
+ usbhs_get_dparam(priv, runtime_pwctrl) = 1;
/*
* priv settings
@@ -658,6 +694,14 @@
/* dev_set_drvdata should be called after usbhs_mod_init */
platform_set_drvdata(pdev, priv);
+ ret = reset_control_deassert(priv->rsts);
+ if (ret)
+ goto probe_fail_rst;
+
+ ret = usbhsc_clk_get(dev, priv);
+ if (ret)
+ goto probe_fail_clks;
+
/*
* deviece reset here because
* USB device might be used in boot loader.
@@ -670,8 +714,7 @@
ret = !gpio_get_value(priv->dparam.enable_gpio);
gpio_free(priv->dparam.enable_gpio);
if (ret) {
- dev_warn(&pdev->dev,
- "USB function not selected (GPIO %d)\n",
+ dev_warn(dev, "USB function not selected (GPIO %d)\n",
priv->dparam.enable_gpio);
ret = -ENOTSUPP;
goto probe_end_mod_exit;
@@ -687,7 +730,7 @@
*/
ret = usbhs_platform_call(priv, hardware_init, pdev);
if (ret < 0) {
- dev_err(&pdev->dev, "platform init failed.\n");
+ dev_err(dev, "platform init failed.\n");
goto probe_end_mod_exit;
}
@@ -695,29 +738,35 @@
usbhs_platform_call(priv, phy_reset, pdev);
/* power control */
- pm_runtime_enable(&pdev->dev);
- if (!usbhsc_flags_has(priv, USBHSF_RUNTIME_PWCTRL)) {
+ pm_runtime_enable(dev);
+ if (!usbhs_get_dparam(priv, runtime_pwctrl)) {
usbhsc_power_ctrl(priv, 1);
usbhs_mod_autonomy_mode(priv);
+ } else {
+ usbhs_mod_non_autonomy_mode(priv);
}
/*
* manual call notify_hotplug for cold plug
*/
- usbhsc_drvcllbck_notify_hotplug(pdev);
+ usbhsc_schedule_notify_hotplug(pdev);
- dev_info(&pdev->dev, "probed\n");
+ dev_info(dev, "probed\n");
return ret;
probe_end_mod_exit:
+ usbhsc_clk_put(priv);
+probe_fail_clks:
+ reset_control_assert(priv->rsts);
+probe_fail_rst:
usbhs_mod_remove(priv);
probe_end_fifo_exit:
usbhs_fifo_remove(priv);
probe_end_pipe_exit:
usbhs_pipe_remove(priv);
- dev_info(&pdev->dev, "probe failed (%d)\n", ret);
+ dev_info(dev, "probe failed (%d)\n", ret);
return ret;
}
@@ -725,20 +774,18 @@
static int usbhs_remove(struct platform_device *pdev)
{
struct usbhs_priv *priv = usbhs_pdev_to_priv(pdev);
- struct renesas_usbhs_platform_info *info = renesas_usbhs_get_info(pdev);
- struct renesas_usbhs_driver_callback *dfunc = &info->driver_callback;
dev_dbg(&pdev->dev, "usb remove\n");
- 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);
usbhs_platform_call(priv, hardware_exit, pdev);
+ usbhsc_clk_put(priv);
+ reset_control_assert(priv->rsts);
usbhs_mod_remove(priv);
usbhs_fifo_remove(priv);
usbhs_pipe_remove(priv);
@@ -746,7 +793,7 @@
return 0;
}
-static int usbhsc_suspend(struct device *dev)
+static __maybe_unused int usbhsc_suspend(struct device *dev)
{
struct usbhs_priv *priv = dev_get_drvdata(dev);
struct usbhs_mod *mod = usbhs_mod_get_current(priv);
@@ -756,47 +803,30 @@
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;
}
-static int usbhsc_resume(struct device *dev)
+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);
}
usbhs_platform_call(priv, phy_reset, pdev);
- usbhsc_drvcllbck_notify_hotplug(pdev);
+ usbhsc_schedule_notify_hotplug(pdev);
return 0;
}
-static int usbhsc_runtime_nop(struct device *dev)
-{
- /* Runtime PM callback shared between ->runtime_suspend()
- * and ->runtime_resume(). Simply returns success.
- *
- * This driver re-initializes all registers after
- * pm_runtime_get_sync() anyway so there is no need
- * to save and restore registers here.
- */
- return 0;
-}
-
-static const struct dev_pm_ops usbhsc_pm_ops = {
- .suspend = usbhsc_suspend,
- .resume = usbhsc_resume,
- .runtime_suspend = usbhsc_runtime_nop,
- .runtime_resume = usbhsc_runtime_nop,
-};
+static SIMPLE_DEV_PM_OPS(usbhsc_pm_ops, usbhsc_suspend, usbhsc_resume);
static struct platform_driver renesas_usbhs_driver = {
.driver = {
diff --git a/drivers/usb/renesas_usbhs/common.h b/drivers/usb/renesas_usbhs/common.h
index 6137f79..0824099 100644
--- a/drivers/usb/renesas_usbhs/common.h
+++ b/drivers/usb/renesas_usbhs/common.h
@@ -3,13 +3,16 @@
* Renesas USB driver
*
* Copyright (C) 2011 Renesas Solutions Corp.
+ * Copyright (C) 2019 Renesas Electronics Corporation
* Kuninori Morimoto <kuninori.morimoto.gx@renesas.com>
*/
#ifndef RENESAS_USB_DRIVER_H
#define RENESAS_USB_DRIVER_H
+#include <linux/clk.h>
#include <linux/extcon.h>
#include <linux/platform_device.h>
+#include <linux/reset.h>
#include <linux/usb/renesas_usbhs.h>
struct usbhs_priv;
@@ -102,6 +105,7 @@
/* 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 */
@@ -207,6 +211,7 @@
/* DCPCTR */
#define BSTS (1 << 15) /* Buffer Status */
#define SUREQ (1 << 14) /* Sending SETUP Token */
+#define INBUFM (1 << 14) /* (PIPEnCTR) Transfer Buffer Monitor */
#define CSSTS (1 << 12) /* CSSTS Status */
#define ACLRM (1 << 9) /* Buffer Auto-Clear Mode */
#define SQCLR (1 << 8) /* Toggle Bit Clear */
@@ -248,19 +253,16 @@
unsigned int irq;
unsigned long irqflags;
- struct renesas_usbhs_platform_callback pfunc;
+ const struct renesas_usbhs_platform_callback *pfunc;
struct renesas_usbhs_driver_param dparam;
struct delayed_work notify_hotplug_work;
struct platform_device *pdev;
struct extcon_dev *edev;
- struct notifier_block nb;
spinlock_t lock;
- u32 flags;
-
/*
* module control
*/
@@ -277,6 +279,8 @@
struct usbhs_fifo_info fifo_info;
struct phy *phy;
+ struct reset_control *rsts;
+ struct clk *clks[2];
};
/*
@@ -289,6 +293,8 @@
#define usbhs_lock(p, f) spin_lock_irqsave(usbhs_priv_to_lock(p), f)
#define usbhs_unlock(p, f) spin_unlock_irqrestore(usbhs_priv_to_lock(p), f)
+int usbhs_get_id_as_gadget(struct platform_device *pdev);
+
/*
* sysconfig
*/
@@ -310,6 +316,7 @@
void usbhs_bus_send_reset(struct usbhs_priv *priv);
int usbhs_bus_get_speed(struct usbhs_priv *priv);
int usbhs_vbus_ctrl(struct usbhs_priv *priv, int enable);
+int usbhsc_schedule_notify_hotplug(struct platform_device *pdev);
/*
* frame
diff --git a/drivers/usb/renesas_usbhs/fifo.c b/drivers/usb/renesas_usbhs/fifo.c
index 39fa2fc..86637cd 100644
--- a/drivers/usb/renesas_usbhs/fifo.c
+++ b/drivers/usb/renesas_usbhs/fifo.c
@@ -3,6 +3,7 @@
* Renesas USB driver
*
* Copyright (C) 2011 Renesas Solutions Corp.
+ * Copyright (C) 2019 Renesas Electronics Corporation
* Kuninori Morimoto <kuninori.morimoto.gx@renesas.com>
*/
#include <linux/delay.h>
@@ -12,7 +13,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 */
@@ -89,7 +89,7 @@
list_del_init(&pkt->node);
}
-static struct usbhs_pkt *__usbhsf_pkt_get(struct usbhs_pipe *pipe)
+struct usbhs_pkt *__usbhsf_pkt_get(struct usbhs_pipe *pipe)
{
return list_first_entry_or_null(&pipe->list, struct usbhs_pkt, node);
}
@@ -325,10 +325,7 @@
}
/* "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 +540,13 @@
}
/* 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
@@ -802,9 +804,8 @@
}
static void usbhsf_dma_complete(void *arg);
-static void xfer_work(struct work_struct *work)
+static void usbhsf_dma_xfer_preparing(struct usbhs_pkt *pkt)
{
- struct usbhs_pkt *pkt = container_of(work, struct usbhs_pkt, work);
struct usbhs_pipe *pipe = pkt->pipe;
struct usbhs_fifo *fifo;
struct usbhs_priv *priv = usbhs_pipe_to_priv(pipe);
@@ -812,12 +813,10 @@
struct dma_chan *chan;
struct device *dev = usbhs_priv_to_dev(priv);
enum dma_transfer_direction dir;
- unsigned long flags;
- usbhs_lock(priv, flags);
fifo = usbhs_pipe_to_fifo(pipe);
if (!fifo)
- goto xfer_work_end;
+ return;
chan = usbhsf_dma_chan_get(fifo, pkt);
dir = usbhs_pipe_is_dir_in(pipe) ? DMA_DEV_TO_MEM : DMA_MEM_TO_DEV;
@@ -826,7 +825,7 @@
pkt->trans, dir,
DMA_PREP_INTERRUPT | DMA_CTRL_ACK);
if (!desc)
- goto xfer_work_end;
+ return;
desc->callback = usbhsf_dma_complete;
desc->callback_param = pipe;
@@ -834,7 +833,7 @@
pkt->cookie = dmaengine_submit(desc);
if (pkt->cookie < 0) {
dev_err(dev, "Failed to submit dma descriptor\n");
- goto xfer_work_end;
+ return;
}
dev_dbg(dev, " %s %d (%d/ %d)\n",
@@ -845,8 +844,17 @@
dma_async_issue_pending(chan);
usbhsf_dma_start(pipe, fifo);
usbhs_pipe_enable(pipe);
+}
-xfer_work_end:
+static void xfer_work(struct work_struct *work)
+{
+ struct usbhs_pkt *pkt = container_of(work, struct usbhs_pkt, work);
+ struct usbhs_pipe *pipe = pkt->pipe;
+ struct usbhs_priv *priv = usbhs_pipe_to_priv(pipe);
+ unsigned long flags;
+
+ usbhs_lock(priv, flags);
+ usbhsf_dma_xfer_preparing(pkt);
usbhs_unlock(priv, flags);
}
@@ -899,8 +907,13 @@
pkt->trans = len;
usbhsf_tx_irq_ctrl(pipe, 0);
- INIT_WORK(&pkt->work, xfer_work);
- schedule_work(&pkt->work);
+ /* FIXME: Workaound for usb dmac that driver can be used in atomic */
+ if (usbhs_get_dparam(priv, has_usb_dmac)) {
+ usbhsf_dma_xfer_preparing(pkt);
+ } else {
+ INIT_WORK(&pkt->work, xfer_work);
+ schedule_work(&pkt->work);
+ }
return 0;
@@ -1006,8 +1019,7 @@
pkt->trans = pkt->length;
- INIT_WORK(&pkt->work, xfer_work);
- schedule_work(&pkt->work);
+ usbhsf_dma_xfer_preparing(pkt);
return 0;
@@ -1276,7 +1288,7 @@
{
struct device *dev = usbhs_priv_to_dev(priv);
- if (dev->of_node)
+ if (dev_of_node(dev))
usbhsf_dma_init_dt(dev, fifo, channel);
else
usbhsf_dma_init_pdev(fifo);
diff --git a/drivers/usb/renesas_usbhs/fifo.h b/drivers/usb/renesas_usbhs/fifo.h
index 88d1816..c3d3cc3 100644
--- a/drivers/usb/renesas_usbhs/fifo.h
+++ b/drivers/usb/renesas_usbhs/fifo.h
@@ -97,5 +97,6 @@
void *buf, int len, int zero, int sequence);
struct usbhs_pkt *usbhs_pkt_pop(struct usbhs_pipe *pipe, struct usbhs_pkt *pkt);
void usbhs_pkt_start(struct usbhs_pipe *pipe);
+struct usbhs_pkt *__usbhsf_pkt_get(struct usbhs_pipe *pipe);
#endif /* RENESAS_USB_FIFO_H */
diff --git a/drivers/usb/renesas_usbhs/mod.c b/drivers/usb/renesas_usbhs/mod.c
index 7475c4f..10fc655 100644
--- a/drivers/usb/renesas_usbhs/mod.c
+++ b/drivers/usb/renesas_usbhs/mod.c
@@ -3,6 +3,7 @@
* Renesas USB driver
*
* Copyright (C) 2011 Renesas Solutions Corp.
+ * Copyright (C) 2019 Renesas Electronics Corporation
* Kuninori Morimoto <kuninori.morimoto.gx@renesas.com>
*/
#include <linux/interrupt.h>
@@ -10,15 +11,6 @@
#include "common.h"
#include "mod.h"
-#define usbhs_priv_to_modinfo(priv) (&priv->mod_info)
-#define usbhs_mod_info_call(priv, func, param...) \
-({ \
- struct usbhs_mod_info *info; \
- info = usbhs_priv_to_modinfo(priv); \
- !info->func ? 0 : \
- info->func(param); \
-})
-
/*
* autonomy
*
@@ -41,7 +33,7 @@
{
struct platform_device *pdev = usbhs_priv_to_pdev(priv);
- renesas_usbhs_call_notify_hotplug(pdev);
+ usbhsc_schedule_notify_hotplug(pdev);
return 0;
}
@@ -50,12 +42,19 @@
{
struct usbhs_mod_info *info = usbhs_priv_to_modinfo(priv);
- info->irq_vbus = usbhsm_autonomy_irq_vbus;
- priv->pfunc.get_vbus = usbhsm_autonomy_get_vbus;
+ info->irq_vbus = usbhsm_autonomy_irq_vbus;
+ info->get_vbus = usbhsm_autonomy_get_vbus;
usbhs_irq_callback_update(priv, NULL);
}
+void usbhs_mod_non_autonomy_mode(struct usbhs_priv *priv)
+{
+ struct usbhs_mod_info *info = usbhs_priv_to_modinfo(priv);
+
+ info->get_vbus = priv->pfunc->get_vbus;
+}
+
/*
* host / gadget functions
*
diff --git a/drivers/usb/renesas_usbhs/mod.h b/drivers/usb/renesas_usbhs/mod.h
index a4a61d6..65dc19c 100644
--- a/drivers/usb/renesas_usbhs/mod.h
+++ b/drivers/usb/renesas_usbhs/mod.h
@@ -3,6 +3,7 @@
* Renesas USB driver
*
* Copyright (C) 2011 Renesas Solutions Corp.
+ * Copyright (C) 2019 Renesas Electronics Corporation
* Kuninori Morimoto <kuninori.morimoto.gx@renesas.com>
*/
#ifndef RENESAS_USB_MOD_H
@@ -84,15 +85,20 @@
/*
* INTSTS0 :: VBINT
*
- * This function will be used as autonomy mode
- * when platform cannot call notify_hotplug.
+ * This function will be used as autonomy mode (runtime_pwctrl == 0)
+ * when the platform doesn't have own get_vbus function.
*
- * This callback cannot be member of "struct usbhs_mod"
- * because it will be used even though
- * host/gadget has not been selected.
+ * This callback cannot be member of "struct usbhs_mod" because it
+ * will be used even though host/gadget has not been selected.
*/
int (*irq_vbus)(struct usbhs_priv *priv,
struct usbhs_irq_state *irq_state);
+
+ /*
+ * This function will be used on any gadget mode. To simplify the code,
+ * this member is in here.
+ */
+ int (*get_vbus)(struct platform_device *pdev);
};
/*
@@ -107,6 +113,7 @@
void usbhs_mod_remove(struct usbhs_priv *priv);
void usbhs_mod_autonomy_mode(struct usbhs_priv *priv);
+void usbhs_mod_non_autonomy_mode(struct usbhs_priv *priv);
/*
* status functions
@@ -129,6 +136,15 @@
mod->func(param); \
})
+#define usbhs_priv_to_modinfo(priv) (&priv->mod_info)
+#define usbhs_mod_info_call(priv, func, param...) \
+({ \
+ struct usbhs_mod_info *info; \
+ info = usbhs_priv_to_modinfo(priv); \
+ !info->func ? 0 : \
+ info->func(param); \
+})
+
/*
* host / gadget control
*/
diff --git a/drivers/usb/renesas_usbhs/mod_gadget.c b/drivers/usb/renesas_usbhs/mod_gadget.c
index 59cac40..cd38d74 100644
--- a/drivers/usb/renesas_usbhs/mod_gadget.c
+++ b/drivers/usb/renesas_usbhs/mod_gadget.c
@@ -3,6 +3,7 @@
* Renesas USB driver
*
* Copyright (C) 2011 Renesas Solutions Corp.
+ * Copyright (C) 2019 Renesas Electronics Corporation
* Kuninori Morimoto <kuninori.morimoto.gx@renesas.com>
*/
#include <linux/delay.h>
@@ -264,7 +265,7 @@
case USB_DEVICE_TEST_MODE:
usbhsg_recip_handler_std_control_done(priv, uep, ctrl);
udelay(100);
- usbhs_sys_set_test_mode(priv, le16_to_cpu(ctrl->wIndex >> 8));
+ usbhs_sys_set_test_mode(priv, le16_to_cpu(ctrl->wIndex) >> 8);
break;
default:
usbhsg_recip_handler_std_control_done(priv, uep, ctrl);
@@ -314,7 +315,7 @@
struct usbhs_pipe *pipe = usbhsg_uep_to_pipe(dcp);
struct device *dev = usbhsg_gpriv_to_dev(gpriv);
struct usb_request *req;
- unsigned short *buf;
+ __le16 *buf;
/* alloc new usb_request for recip */
req = usb_ep_alloc_request(&dcp->ep, GFP_ATOMIC);
@@ -721,8 +722,7 @@
struct usbhs_priv *priv = usbhsg_gpriv_to_priv(gpriv);
struct device *dev = usbhsg_gpriv_to_dev(gpriv);
unsigned long flags;
-
- usbhsg_pipe_disable(uep);
+ int ret = 0;
dev_dbg(dev, "set halt %d (pipe %d)\n",
halt, usbhs_pipe_number(pipe));
@@ -730,6 +730,18 @@
/******************** spin lock ********************/
usbhs_lock(priv, flags);
+ /*
+ * According to usb_ep_set_halt()'s description, this function should
+ * return -EAGAIN if the IN endpoint has any queue or data. Note
+ * that the usbhs_pipe_is_dir_in() returns false if the pipe is an
+ * IN endpoint in the gadget mode.
+ */
+ if (!usbhs_pipe_is_dir_in(pipe) && (__usbhsf_pkt_get(pipe) ||
+ usbhs_pipe_contains_transmittable_data(pipe))) {
+ ret = -EAGAIN;
+ goto out;
+ }
+
if (halt)
usbhs_pipe_stall(pipe);
else
@@ -740,10 +752,11 @@
else
usbhsg_status_clr(gpriv, USBHSG_STATUS_WEDGE);
+out:
usbhs_unlock(priv, flags);
/******************** spin unlock ******************/
- return 0;
+ return ret;
}
static int usbhsg_ep_set_halt(struct usb_ep *ep, int value)
@@ -914,8 +927,8 @@
{
struct usbhs_mod_info *info = &priv->mod_info;
- info->irq_vbus = NULL;
- priv->pfunc.get_vbus = usbhsm_phy_get_vbus;
+ info->irq_vbus = NULL;
+ info->get_vbus = usbhsm_phy_get_vbus;
usbhs_irq_callback_update(priv, NULL);
}
@@ -1023,7 +1036,7 @@
gpriv->vbus_active = !!is_active;
- renesas_usbhs_call_notify_hotplug(pdev);
+ usbhsc_schedule_notify_hotplug(pdev);
return 0;
}
diff --git a/drivers/usb/renesas_usbhs/mod_host.c b/drivers/usb/renesas_usbhs/mod_host.c
index 4e59c64..ae54221 100644
--- a/drivers/usb/renesas_usbhs/mod_host.c
+++ b/drivers/usb/renesas_usbhs/mod_host.c
@@ -340,7 +340,7 @@
pipe = usbhsh_uep_to_pipe(uep);
if (unlikely(!pipe)) {
- dev_err(dev, "uep doens't have pipe\n");
+ dev_err(dev, "uep doesn't have pipe\n");
} else if (1 == uep->counter--) { /* last user */
struct usb_host_endpoint *ep = usbhsh_uep_to_ep(uep);
struct usbhsh_device *udev = usbhsh_uep_to_udev(uep);
@@ -1283,7 +1283,7 @@
/*
* generic hardware linkage
*/
- .flags = HCD_USB2,
+ .flags = HCD_DMA | HCD_USB2,
.start = usbhsh_host_start,
.stop = usbhsh_host_stop,
diff --git a/drivers/usb/renesas_usbhs/pipe.c b/drivers/usb/renesas_usbhs/pipe.c
index c4922b9..9e5afdd 100644
--- a/drivers/usb/renesas_usbhs/pipe.c
+++ b/drivers/usb/renesas_usbhs/pipe.c
@@ -277,6 +277,21 @@
return -EBUSY;
}
+bool usbhs_pipe_contains_transmittable_data(struct usbhs_pipe *pipe)
+{
+ u16 val;
+
+ /* Do not support for DCP pipe */
+ if (usbhs_pipe_is_dcp(pipe))
+ return false;
+
+ val = usbhsp_pipectrl_get(pipe);
+ if (val & INBUFM)
+ return true;
+
+ return false;
+}
+
/*
* PID ctrl
*/
diff --git a/drivers/usb/renesas_usbhs/pipe.h b/drivers/usb/renesas_usbhs/pipe.h
index 3080423..3b13052 100644
--- a/drivers/usb/renesas_usbhs/pipe.h
+++ b/drivers/usb/renesas_usbhs/pipe.h
@@ -83,6 +83,7 @@
void usbhs_pipe_clear_without_sequence(struct usbhs_pipe *pipe,
int needs_bfre, int bfre_enable);
int usbhs_pipe_is_accessible(struct usbhs_pipe *pipe);
+bool usbhs_pipe_contains_transmittable_data(struct usbhs_pipe *pipe);
void usbhs_pipe_enable(struct usbhs_pipe *pipe);
void usbhs_pipe_disable(struct usbhs_pipe *pipe);
void usbhs_pipe_stall(struct usbhs_pipe *pipe);
diff --git a/drivers/usb/renesas_usbhs/rcar2.c b/drivers/usb/renesas_usbhs/rcar2.c
index 0027092..440d213 100644
--- a/drivers/usb/renesas_usbhs/rcar2.c
+++ b/drivers/usb/renesas_usbhs/rcar2.c
@@ -3,6 +3,7 @@
* Renesas USB driver R-Car Gen. 2 initialization and power control
*
* Copyright (C) 2014 Ulrich Hecht
+ * Copyright (C) 2019 Renesas Electronics Corporation
*/
#include <linux/gpio.h>
@@ -62,14 +63,15 @@
return retval;
}
-static int usbhs_rcar2_get_id(struct platform_device *pdev)
-{
- return USBHS_GADGET;
-}
-
-const struct renesas_usbhs_platform_callback usbhs_rcar2_ops = {
- .hardware_init = usbhs_rcar2_hardware_init,
- .hardware_exit = usbhs_rcar2_hardware_exit,
- .power_ctrl = usbhs_rcar2_power_ctrl,
- .get_id = usbhs_rcar2_get_id,
+const struct renesas_usbhs_platform_info usbhs_rcar_gen2_plat_info = {
+ .platform_callback = {
+ .hardware_init = usbhs_rcar2_hardware_init,
+ .hardware_exit = usbhs_rcar2_hardware_exit,
+ .power_ctrl = usbhs_rcar2_power_ctrl,
+ .get_id = usbhs_get_id_as_gadget,
+ },
+ .driver_param = {
+ .has_usb_dmac = 1,
+ .has_new_pipe_configs = 1,
+ },
};
diff --git a/drivers/usb/renesas_usbhs/rcar2.h b/drivers/usb/renesas_usbhs/rcar2.h
index 45e3526..7d88732 100644
--- a/drivers/usb/renesas_usbhs/rcar2.h
+++ b/drivers/usb/renesas_usbhs/rcar2.h
@@ -1,5 +1,4 @@
// SPDX-License-Identifier: GPL-2.0
#include "common.h"
-extern const struct renesas_usbhs_platform_callback
- usbhs_rcar2_ops;
+extern const struct renesas_usbhs_platform_info usbhs_rcar_gen2_plat_info;
diff --git a/drivers/usb/renesas_usbhs/rcar3.c b/drivers/usb/renesas_usbhs/rcar3.c
index d0ea4ff..c181b2a 100644
--- a/drivers/usb/renesas_usbhs/rcar3.c
+++ b/drivers/usb/renesas_usbhs/rcar3.c
@@ -2,7 +2,7 @@
/*
* Renesas USB driver R-Car Gen. 3 initialization and power control
*
- * Copyright (C) 2016 Renesas Electronics Corporation
+ * Copyright (C) 2016-2019 Renesas Electronics Corporation
*/
#include <linux/delay.h>
@@ -27,7 +27,6 @@
* Remarks: bit[31:11] and bit[9:6] should be 0
*/
#define UGCTRL2_RESERVED_3 0x00000001 /* bit[3:0] should be B'0001 */
-#define UGCTRL2_USB0SEL_EHCI 0x00000010
#define UGCTRL2_USB0SEL_HSUSB 0x00000020
#define UGCTRL2_USB0SEL_OTG 0x00000030
#define UGCTRL2_VBUSSEL 0x00000400
@@ -50,14 +49,6 @@
usbhs_write32(priv, UGCTRL2, val | UGCTRL2_RESERVED_3);
}
-static void usbhs_rcar3_set_usbsel(struct usbhs_priv *priv, bool ehci)
-{
- if (ehci)
- usbhs_rcar3_set_ugctrl2(priv, UGCTRL2_USB0SEL_EHCI);
- else
- usbhs_rcar3_set_ugctrl2(priv, UGCTRL2_USB0SEL_HSUSB);
-}
-
static int usbhs_rcar3_power_ctrl(struct platform_device *pdev,
void __iomem *base, int enable)
{
@@ -68,7 +59,7 @@
if (enable) {
usbhs_bset(priv, LPSTS, LPSTS_SUSPM, LPSTS_SUSPM);
/* The controller on R-Car Gen3 needs to wait up to 45 usec */
- udelay(45);
+ usleep_range(45, 90);
} else {
usbhs_bset(priv, LPSTS, LPSTS_SUSPM, 0);
}
@@ -83,14 +74,11 @@
struct usbhs_priv *priv = usbhs_pdev_to_priv(pdev);
u32 val;
int timeout = 1000;
- bool is_host = false;
if (enable) {
usbhs_write32(priv, UGCTRL, 0); /* release PLLRESET */
- if (priv->edev)
- is_host = extcon_get_state(priv->edev, EXTCON_USB_HOST);
-
- usbhs_rcar3_set_usbsel(priv, is_host);
+ usbhs_rcar3_set_ugctrl2(priv,
+ UGCTRL2_USB0SEL_OTG | UGCTRL2_VBUSSEL);
usbhs_bset(priv, LPSTS, LPSTS_SUSPM, LPSTS_SUSPM);
do {
@@ -107,28 +95,26 @@
return 0;
}
-static int usbhs_rcar3_get_id(struct platform_device *pdev)
-{
- return USBHS_GADGET;
-}
-
-static int usbhs_rcar3_notifier(struct notifier_block *nb, unsigned long event,
- void *data)
-{
- struct usbhs_priv *priv = container_of(nb, struct usbhs_priv, nb);
-
- usbhs_rcar3_set_usbsel(priv, !!event);
-
- return NOTIFY_DONE;
-}
-
-const struct renesas_usbhs_platform_callback usbhs_rcar3_ops = {
- .power_ctrl = usbhs_rcar3_power_ctrl,
- .get_id = usbhs_rcar3_get_id,
+const struct renesas_usbhs_platform_info usbhs_rcar_gen3_plat_info = {
+ .platform_callback = {
+ .power_ctrl = usbhs_rcar3_power_ctrl,
+ .get_id = usbhs_get_id_as_gadget,
+ },
+ .driver_param = {
+ .has_usb_dmac = 1,
+ .multi_clks = 1,
+ .has_new_pipe_configs = 1,
+ },
};
-const struct renesas_usbhs_platform_callback usbhs_rcar3_with_pll_ops = {
- .power_ctrl = usbhs_rcar3_power_and_pll_ctrl,
- .get_id = usbhs_rcar3_get_id,
- .notifier = usbhs_rcar3_notifier,
+const struct renesas_usbhs_platform_info usbhs_rcar_gen3_with_pll_plat_info = {
+ .platform_callback = {
+ .power_ctrl = usbhs_rcar3_power_and_pll_ctrl,
+ .get_id = usbhs_get_id_as_gadget,
+ },
+ .driver_param = {
+ .has_usb_dmac = 1,
+ .multi_clks = 1,
+ .has_new_pipe_configs = 1,
+ },
};
diff --git a/drivers/usb/renesas_usbhs/rcar3.h b/drivers/usb/renesas_usbhs/rcar3.h
index 49e535a..c7c5ec1 100644
--- a/drivers/usb/renesas_usbhs/rcar3.h
+++ b/drivers/usb/renesas_usbhs/rcar3.h
@@ -1,5 +1,6 @@
// SPDX-License-Identifier: GPL-2.0
#include "common.h"
-extern const struct renesas_usbhs_platform_callback usbhs_rcar3_ops;
-extern const struct renesas_usbhs_platform_callback usbhs_rcar3_with_pll_ops;
+extern const struct renesas_usbhs_platform_info usbhs_rcar_gen3_plat_info;
+extern const struct renesas_usbhs_platform_info
+ usbhs_rcar_gen3_with_pll_plat_info;
diff --git a/drivers/usb/renesas_usbhs/rza.c b/drivers/usb/renesas_usbhs/rza.c
index 5b28725..24de64e 100644
--- a/drivers/usb/renesas_usbhs/rza.c
+++ b/drivers/usb/renesas_usbhs/rza.c
@@ -3,7 +3,7 @@
* Renesas USB driver RZ/A initialization and power control
*
* Copyright (C) 2018 Chris Brandt
- * Copyright (C) 2018 Renesas Electronics Corporation
+ * Copyright (C) 2018-2019 Renesas Electronics Corporation
*/
#include <linux/delay.h>
@@ -35,18 +35,18 @@
/* Enable USB PLL (NOTE: ch0 controls both ch0 and ch1) */
usbhs_bset(priv, SYSCFG, UPLLE, UPLLE);
- udelay(1000);
+ usleep_range(1000, 2000);
usbhs_bset(priv, SUSPMODE, SUSPM, SUSPM);
return 0;
}
-static int usbhs_rza_get_id(struct platform_device *pdev)
-{
- return USBHS_GADGET;
-}
-
-const struct renesas_usbhs_platform_callback usbhs_rza1_ops = {
- .hardware_init = usbhs_rza1_hardware_init,
- .get_id = usbhs_rza_get_id,
+const struct renesas_usbhs_platform_info usbhs_rza1_plat_info = {
+ .platform_callback = {
+ .hardware_init = usbhs_rza1_hardware_init,
+ .get_id = usbhs_get_id_as_gadget,
+ },
+ .driver_param = {
+ .has_new_pipe_configs = 1,
+ },
};
diff --git a/drivers/usb/renesas_usbhs/rza.h b/drivers/usb/renesas_usbhs/rza.h
index ca917ca..1ca42a6 100644
--- a/drivers/usb/renesas_usbhs/rza.h
+++ b/drivers/usb/renesas_usbhs/rza.h
@@ -1,4 +1,5 @@
// SPDX-License-Identifier: GPL-2.0
#include "common.h"
-extern const struct renesas_usbhs_platform_callback usbhs_rza1_ops;
+extern const struct renesas_usbhs_platform_info usbhs_rza1_plat_info;
+extern const struct renesas_usbhs_platform_info usbhs_rza2_plat_info;
diff --git a/drivers/usb/renesas_usbhs/rza2.c b/drivers/usb/renesas_usbhs/rza2.c
new file mode 100644
index 0000000..0217495
--- /dev/null
+++ b/drivers/usb/renesas_usbhs/rza2.c
@@ -0,0 +1,74 @@
+// 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;
+}
+
+const struct renesas_usbhs_platform_info usbhs_rza2_plat_info = {
+ .platform_callback = {
+ .hardware_init = usbhs_rza2_hardware_init,
+ .hardware_exit = usbhs_rza2_hardware_exit,
+ .power_ctrl = usbhs_rza2_power_ctrl,
+ .get_id = usbhs_get_id_as_gadget,
+ },
+ .driver_param = {
+ .has_cnen = 1,
+ .cfifo_byte_addr = 1,
+ .has_new_pipe_configs = 1,
+ },
+};