|
@@ -15,12 +15,14 @@
|
|
|
*
|
|
|
*/
|
|
|
#include <linux/err.h>
|
|
|
+#include <linux/gpio.h>
|
|
|
#include <linux/io.h>
|
|
|
#include <linux/module.h>
|
|
|
#include <linux/pm_runtime.h>
|
|
|
#include <linux/slab.h>
|
|
|
#include <linux/sysfs.h>
|
|
|
#include "common.h"
|
|
|
+#include "rcar2.h"
|
|
|
|
|
|
/*
|
|
|
* image of renesas_usbhs
|
|
@@ -284,6 +286,8 @@ static void usbhsc_set_buswait(struct usbhs_priv *priv)
|
|
|
/*
|
|
|
* platform default param
|
|
|
*/
|
|
|
+
|
|
|
+/* commonly used on old SH-Mobile SoCs */
|
|
|
static u32 usbhsc_default_pipe_type[] = {
|
|
|
USB_ENDPOINT_XFER_CONTROL,
|
|
|
USB_ENDPOINT_XFER_ISOC,
|
|
@@ -297,6 +301,26 @@ static u32 usbhsc_default_pipe_type[] = {
|
|
|
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
|
|
|
*/
|
|
@@ -423,8 +447,7 @@ static int usbhs_probe(struct platform_device *pdev)
|
|
|
int ret;
|
|
|
|
|
|
/* check platform information */
|
|
|
- if (!info ||
|
|
|
- !info->platform_callback.get_id) {
|
|
|
+ if (!info) {
|
|
|
dev_err(&pdev->dev, "no platform information\n");
|
|
|
return -EINVAL;
|
|
|
}
|
|
@@ -451,13 +474,32 @@ static int usbhs_probe(struct platform_device *pdev)
|
|
|
/*
|
|
|
* care platform info
|
|
|
*/
|
|
|
- memcpy(&priv->pfunc,
|
|
|
- &info->platform_callback,
|
|
|
- sizeof(struct renesas_usbhs_platform_callback));
|
|
|
+
|
|
|
memcpy(&priv->dparam,
|
|
|
&info->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 */
|
|
|
dfunc = &info->driver_callback;
|
|
|
dfunc->notify_hotplug = usbhsc_drvcllbck_notify_hotplug;
|
|
@@ -507,6 +549,20 @@ static int usbhs_probe(struct platform_device *pdev)
|
|
|
*/
|
|
|
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
|
|
|
*
|