diff options
Diffstat (limited to 'drivers/usb/renesas_usbhs')
-rw-r--r-- | drivers/usb/renesas_usbhs/Kconfig | 1 | ||||
-rw-r--r-- | drivers/usb/renesas_usbhs/Makefile | 2 | ||||
-rw-r--r-- | drivers/usb/renesas_usbhs/common.c | 160 | ||||
-rw-r--r-- | drivers/usb/renesas_usbhs/common.h | 8 | ||||
-rw-r--r-- | drivers/usb/renesas_usbhs/fifo.c | 15 | ||||
-rw-r--r-- | drivers/usb/renesas_usbhs/rza.h | 1 | ||||
-rw-r--r-- | drivers/usb/renesas_usbhs/rza2.c | 72 |
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, +}; |