|
@@ -8,6 +8,7 @@
|
|
* the Free Software Foundation; version 2 of the License.
|
|
* the Free Software Foundation; version 2 of the License.
|
|
*/
|
|
*/
|
|
|
|
|
|
|
|
+#include <linux/debugfs.h>
|
|
#include <linux/delay.h>
|
|
#include <linux/delay.h>
|
|
#include <linux/dma-mapping.h>
|
|
#include <linux/dma-mapping.h>
|
|
#include <linux/err.h>
|
|
#include <linux/err.h>
|
|
@@ -20,6 +21,7 @@
|
|
#include <linux/pm_runtime.h>
|
|
#include <linux/pm_runtime.h>
|
|
#include <linux/sizes.h>
|
|
#include <linux/sizes.h>
|
|
#include <linux/slab.h>
|
|
#include <linux/slab.h>
|
|
|
|
+#include <linux/uaccess.h>
|
|
#include <linux/usb/ch9.h>
|
|
#include <linux/usb/ch9.h>
|
|
#include <linux/usb/gadget.h>
|
|
#include <linux/usb/gadget.h>
|
|
|
|
|
|
@@ -347,6 +349,7 @@ struct renesas_usb3 {
|
|
bool workaround_for_vbus;
|
|
bool workaround_for_vbus;
|
|
bool extcon_host; /* check id and set EXTCON_USB_HOST */
|
|
bool extcon_host; /* check id and set EXTCON_USB_HOST */
|
|
bool extcon_usb; /* check vbus and set EXTCON_USB */
|
|
bool extcon_usb; /* check vbus and set EXTCON_USB */
|
|
|
|
+ bool forced_b_device;
|
|
};
|
|
};
|
|
|
|
|
|
#define gadget_to_renesas_usb3(_gadget) \
|
|
#define gadget_to_renesas_usb3(_gadget) \
|
|
@@ -663,7 +666,9 @@ static void usb3_mode_config(struct renesas_usb3 *usb3, bool host, bool a_dev)
|
|
spin_lock_irqsave(&usb3->lock, flags);
|
|
spin_lock_irqsave(&usb3->lock, flags);
|
|
usb3_set_mode(usb3, host);
|
|
usb3_set_mode(usb3, host);
|
|
usb3_vbus_out(usb3, a_dev);
|
|
usb3_vbus_out(usb3, a_dev);
|
|
- if (!host && a_dev) /* for A-Peripheral */
|
|
|
|
|
|
+ /* for A-Peripheral or forced B-device mode */
|
|
|
|
+ if ((!host && a_dev) ||
|
|
|
|
+ (usb3->workaround_for_vbus && usb3->forced_b_device))
|
|
usb3_connect(usb3);
|
|
usb3_connect(usb3);
|
|
spin_unlock_irqrestore(&usb3->lock, flags);
|
|
spin_unlock_irqrestore(&usb3->lock, flags);
|
|
}
|
|
}
|
|
@@ -677,7 +682,7 @@ static void usb3_check_id(struct renesas_usb3 *usb3)
|
|
{
|
|
{
|
|
usb3->extcon_host = usb3_is_a_device(usb3);
|
|
usb3->extcon_host = usb3_is_a_device(usb3);
|
|
|
|
|
|
- if (usb3->extcon_host)
|
|
|
|
|
|
+ if (usb3->extcon_host && !usb3->forced_b_device)
|
|
usb3_mode_config(usb3, true, true);
|
|
usb3_mode_config(usb3, true, true);
|
|
else
|
|
else
|
|
usb3_mode_config(usb3, false, false);
|
|
usb3_mode_config(usb3, false, false);
|
|
@@ -2272,6 +2277,9 @@ static ssize_t role_store(struct device *dev, struct device_attribute *attr,
|
|
if (!usb3->driver)
|
|
if (!usb3->driver)
|
|
return -ENODEV;
|
|
return -ENODEV;
|
|
|
|
|
|
|
|
+ if (usb3->forced_b_device)
|
|
|
|
+ return -EBUSY;
|
|
|
|
+
|
|
if (!strncmp(buf, "host", strlen("host")))
|
|
if (!strncmp(buf, "host", strlen("host")))
|
|
new_mode_is_host = true;
|
|
new_mode_is_host = true;
|
|
else if (!strncmp(buf, "peripheral", strlen("peripheral")))
|
|
else if (!strncmp(buf, "peripheral", strlen("peripheral")))
|
|
@@ -2299,6 +2307,70 @@ static ssize_t role_show(struct device *dev, struct device_attribute *attr,
|
|
}
|
|
}
|
|
static DEVICE_ATTR_RW(role);
|
|
static DEVICE_ATTR_RW(role);
|
|
|
|
|
|
|
|
+static int renesas_usb3_b_device_show(struct seq_file *s, void *unused)
|
|
|
|
+{
|
|
|
|
+ struct renesas_usb3 *usb3 = s->private;
|
|
|
|
+
|
|
|
|
+ seq_printf(s, "%d\n", usb3->forced_b_device);
|
|
|
|
+
|
|
|
|
+ return 0;
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+static int renesas_usb3_b_device_open(struct inode *inode, struct file *file)
|
|
|
|
+{
|
|
|
|
+ return single_open(file, renesas_usb3_b_device_show, inode->i_private);
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+static ssize_t renesas_usb3_b_device_write(struct file *file,
|
|
|
|
+ const char __user *ubuf,
|
|
|
|
+ size_t count, loff_t *ppos)
|
|
|
|
+{
|
|
|
|
+ struct seq_file *s = file->private_data;
|
|
|
|
+ struct renesas_usb3 *usb3 = s->private;
|
|
|
|
+ char buf[32];
|
|
|
|
+
|
|
|
|
+ if (!usb3->driver)
|
|
|
|
+ return -ENODEV;
|
|
|
|
+
|
|
|
|
+ if (copy_from_user(&buf, ubuf, min_t(size_t, sizeof(buf) - 1, count)))
|
|
|
|
+ return -EFAULT;
|
|
|
|
+
|
|
|
|
+ if (!strncmp(buf, "1", 1))
|
|
|
|
+ usb3->forced_b_device = true;
|
|
|
|
+ else
|
|
|
|
+ usb3->forced_b_device = false;
|
|
|
|
+
|
|
|
|
+ /* Let this driver call usb3_connect() anyway */
|
|
|
|
+ usb3_check_id(usb3);
|
|
|
|
+
|
|
|
|
+ return count;
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+static const struct file_operations renesas_usb3_b_device_fops = {
|
|
|
|
+ .open = renesas_usb3_b_device_open,
|
|
|
|
+ .write = renesas_usb3_b_device_write,
|
|
|
|
+ .read = seq_read,
|
|
|
|
+ .llseek = seq_lseek,
|
|
|
|
+ .release = single_release,
|
|
|
|
+};
|
|
|
|
+
|
|
|
|
+static void renesas_usb3_debugfs_init(struct renesas_usb3 *usb3,
|
|
|
|
+ struct device *dev)
|
|
|
|
+{
|
|
|
|
+ struct dentry *root, *file;
|
|
|
|
+
|
|
|
|
+ root = debugfs_create_dir(dev_name(dev), NULL);
|
|
|
|
+ if (IS_ERR_OR_NULL(root)) {
|
|
|
|
+ dev_info(dev, "%s: Can't create the root\n", __func__);
|
|
|
|
+ return;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ file = debugfs_create_file("b_device", 0644, root, usb3,
|
|
|
|
+ &renesas_usb3_b_device_fops);
|
|
|
|
+ if (!file)
|
|
|
|
+ dev_info(dev, "%s: Can't create debugfs mode\n", __func__);
|
|
|
|
+}
|
|
|
|
+
|
|
/*------- platform_driver ------------------------------------------------*/
|
|
/*------- platform_driver ------------------------------------------------*/
|
|
static int renesas_usb3_remove(struct platform_device *pdev)
|
|
static int renesas_usb3_remove(struct platform_device *pdev)
|
|
{
|
|
{
|
|
@@ -2518,6 +2590,8 @@ static int renesas_usb3_probe(struct platform_device *pdev)
|
|
|
|
|
|
usb3->workaround_for_vbus = priv->workaround_for_vbus;
|
|
usb3->workaround_for_vbus = priv->workaround_for_vbus;
|
|
|
|
|
|
|
|
+ renesas_usb3_debugfs_init(usb3, &pdev->dev);
|
|
|
|
+
|
|
dev_info(&pdev->dev, "probed\n");
|
|
dev_info(&pdev->dev, "probed\n");
|
|
|
|
|
|
return 0;
|
|
return 0;
|