Commit 8ecef00f authored by Ulrich Hecht's avatar Ulrich Hecht Committed by Felipe Balbi

usb: renesas_usbhs: add R-Car Gen. 2 init and power control

In preparation for DT conversion to reduce reliance on platform device
callbacks.
Signed-off-by: default avatarUlrich Hecht <ulrich.hecht+renesas@gmail.com>
Signed-off-by: default avatarFelipe Balbi <balbi@ti.com>
parent f2267089
...@@ -4,7 +4,7 @@ ...@@ -4,7 +4,7 @@
obj-$(CONFIG_USB_RENESAS_USBHS) += renesas_usbhs.o obj-$(CONFIG_USB_RENESAS_USBHS) += renesas_usbhs.o
renesas_usbhs-y := common.o mod.o pipe.o fifo.o renesas_usbhs-y := common.o mod.o pipe.o fifo.o rcar2.o
ifneq ($(CONFIG_USB_RENESAS_USBHS_HCD),) ifneq ($(CONFIG_USB_RENESAS_USBHS_HCD),)
renesas_usbhs-y += mod_host.o renesas_usbhs-y += mod_host.o
......
...@@ -15,12 +15,14 @@ ...@@ -15,12 +15,14 @@
* *
*/ */
#include <linux/err.h> #include <linux/err.h>
#include <linux/gpio.h>
#include <linux/io.h> #include <linux/io.h>
#include <linux/module.h> #include <linux/module.h>
#include <linux/pm_runtime.h> #include <linux/pm_runtime.h>
#include <linux/slab.h> #include <linux/slab.h>
#include <linux/sysfs.h> #include <linux/sysfs.h>
#include "common.h" #include "common.h"
#include "rcar2.h"
/* /*
* image of renesas_usbhs * image of renesas_usbhs
...@@ -284,6 +286,8 @@ static void usbhsc_set_buswait(struct usbhs_priv *priv) ...@@ -284,6 +286,8 @@ static void usbhsc_set_buswait(struct usbhs_priv *priv)
/* /*
* platform default param * platform default param
*/ */
/* commonly used on old SH-Mobile SoCs */
static u32 usbhsc_default_pipe_type[] = { static u32 usbhsc_default_pipe_type[] = {
USB_ENDPOINT_XFER_CONTROL, USB_ENDPOINT_XFER_CONTROL,
USB_ENDPOINT_XFER_ISOC, USB_ENDPOINT_XFER_ISOC,
...@@ -297,6 +301,26 @@ static u32 usbhsc_default_pipe_type[] = { ...@@ -297,6 +301,26 @@ static u32 usbhsc_default_pipe_type[] = {
USB_ENDPOINT_XFER_INT, USB_ENDPOINT_XFER_INT,
}; };
/* commonly used on newer SH-Mobile and R-Car SoCs */
static u32 usbhsc_new_pipe_type[] = {
USB_ENDPOINT_XFER_CONTROL,
USB_ENDPOINT_XFER_ISOC,
USB_ENDPOINT_XFER_ISOC,
USB_ENDPOINT_XFER_BULK,
USB_ENDPOINT_XFER_BULK,
USB_ENDPOINT_XFER_BULK,
USB_ENDPOINT_XFER_INT,
USB_ENDPOINT_XFER_INT,
USB_ENDPOINT_XFER_INT,
USB_ENDPOINT_XFER_BULK,
USB_ENDPOINT_XFER_BULK,
USB_ENDPOINT_XFER_BULK,
USB_ENDPOINT_XFER_BULK,
USB_ENDPOINT_XFER_BULK,
USB_ENDPOINT_XFER_BULK,
USB_ENDPOINT_XFER_BULK,
};
/* /*
* power control * power control
*/ */
...@@ -423,8 +447,7 @@ static int usbhs_probe(struct platform_device *pdev) ...@@ -423,8 +447,7 @@ static int usbhs_probe(struct platform_device *pdev)
int ret; int ret;
/* check platform information */ /* check platform information */
if (!info || if (!info) {
!info->platform_callback.get_id) {
dev_err(&pdev->dev, "no platform information\n"); dev_err(&pdev->dev, "no platform information\n");
return -EINVAL; return -EINVAL;
} }
...@@ -451,13 +474,32 @@ static int usbhs_probe(struct platform_device *pdev) ...@@ -451,13 +474,32 @@ static int usbhs_probe(struct platform_device *pdev)
/* /*
* care platform info * care platform info
*/ */
memcpy(&priv->pfunc,
&info->platform_callback,
sizeof(struct renesas_usbhs_platform_callback));
memcpy(&priv->dparam, memcpy(&priv->dparam,
&info->driver_param, &info->driver_param,
sizeof(struct renesas_usbhs_driver_param)); sizeof(struct renesas_usbhs_driver_param));
switch (priv->dparam.type) {
case USBHS_TYPE_R8A7790:
case USBHS_TYPE_R8A7791:
priv->pfunc = usbhs_rcar2_ops;
if (!priv->dparam.pipe_type) {
priv->dparam.pipe_type = usbhsc_new_pipe_type;
priv->dparam.pipe_size =
ARRAY_SIZE(usbhsc_new_pipe_type);
}
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;
}
/* set driver callback functions for platform */ /* set driver callback functions for platform */
dfunc = &info->driver_callback; dfunc = &info->driver_callback;
dfunc->notify_hotplug = usbhsc_drvcllbck_notify_hotplug; dfunc->notify_hotplug = usbhsc_drvcllbck_notify_hotplug;
...@@ -507,6 +549,20 @@ static int usbhs_probe(struct platform_device *pdev) ...@@ -507,6 +549,20 @@ static int usbhs_probe(struct platform_device *pdev)
*/ */
usbhs_sys_clock_ctrl(priv, 0); usbhs_sys_clock_ctrl(priv, 0);
/* check GPIO determining if USB function should be enabled */
if (priv->dparam.enable_gpio) {
gpio_request_one(priv->dparam.enable_gpio, GPIOF_IN, NULL);
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",
priv->dparam.enable_gpio);
ret = -ENOTSUPP;
goto probe_end_mod_exit;
}
}
/* /*
* platform call * platform call
* *
......
...@@ -268,6 +268,8 @@ struct usbhs_priv { ...@@ -268,6 +268,8 @@ struct usbhs_priv {
* fifo control * fifo control
*/ */
struct usbhs_fifo_info fifo_info; struct usbhs_fifo_info fifo_info;
struct usb_phy *phy;
}; };
/* /*
......
/*
* Renesas USB driver R-Car Gen. 2 initialization and power control
*
* Copyright (C) 2014 Ulrich Hecht
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
*/
#include <linux/gpio.h>
#include <linux/of_gpio.h>
#include <linux/platform_data/gpio-rcar.h>
#include <linux/usb/phy.h>
#include "common.h"
#include "rcar2.h"
static int usbhs_rcar2_hardware_init(struct platform_device *pdev)
{
struct usbhs_priv *priv = usbhs_pdev_to_priv(pdev);
struct usb_phy *phy;
phy = usb_get_phy_dev(&pdev->dev, 0);
if (IS_ERR(phy))
return PTR_ERR(phy);
priv->phy = phy;
return 0;
}
static int usbhs_rcar2_hardware_exit(struct platform_device *pdev)
{
struct usbhs_priv *priv = usbhs_pdev_to_priv(pdev);
if (!priv->phy)
return 0;
usb_put_phy(priv->phy);
priv->phy = NULL;
return 0;
}
static int usbhs_rcar2_power_ctrl(struct platform_device *pdev,
void __iomem *base, int enable)
{
struct usbhs_priv *priv = usbhs_pdev_to_priv(pdev);
if (!priv->phy)
return -ENODEV;
if (enable) {
int retval = usb_phy_init(priv->phy);
if (!retval)
retval = usb_phy_set_suspend(priv->phy, 0);
return retval;
}
usb_phy_set_suspend(priv->phy, 1);
usb_phy_shutdown(priv->phy);
return 0;
}
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,
};
#include "common.h"
extern const struct renesas_usbhs_platform_callback
usbhs_rcar2_ops;
...@@ -153,6 +153,9 @@ struct renesas_usbhs_driver_param { ...@@ -153,6 +153,9 @@ struct renesas_usbhs_driver_param {
*/ */
int pio_dma_border; /* default is 64byte */ int pio_dma_border; /* default is 64byte */
u32 type;
u32 enable_gpio;
/* /*
* option: * option:
*/ */
...@@ -160,6 +163,9 @@ struct renesas_usbhs_driver_param { ...@@ -160,6 +163,9 @@ struct renesas_usbhs_driver_param {
u32 has_sudmac:1; /* for SUDMAC */ u32 has_sudmac:1; /* for SUDMAC */
}; };
#define USBHS_TYPE_R8A7790 1
#define USBHS_TYPE_R8A7791 2
/* /*
* option: * option:
* *
......
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