mirror of
https://github.com/hardkernel/linux.git
synced 2026-06-08 20:07:46 +09:00
usb: dwc3: rockchip: use sysfs instead of debugfs
Debugfs may not support on some platforms. So remove the debugfs and add sysfs interface. This patch also change the name "rk_usb_force_mode" to "dwc3_mode". Change-Id: I461919a02b1ee126c494f43f74af5295bb20c0a4 Signed-off-by: William Wu <william.wu@rock-chips.com>
This commit is contained in:
@@ -23,7 +23,6 @@
|
||||
#include <linux/dma-mapping.h>
|
||||
#include <linux/clk.h>
|
||||
#include <linux/clk-provider.h>
|
||||
#include <linux/debugfs.h>
|
||||
#include <linux/of.h>
|
||||
#include <linux/of_platform.h>
|
||||
#include <linux/pm_runtime.h>
|
||||
@@ -31,7 +30,6 @@
|
||||
#include <linux/freezer.h>
|
||||
#include <linux/iopoll.h>
|
||||
#include <linux/reset.h>
|
||||
#include <linux/uaccess.h>
|
||||
#include <linux/usb.h>
|
||||
#include <linux/usb/hcd.h>
|
||||
#include <linux/usb/ch9.h>
|
||||
@@ -50,10 +48,11 @@ struct dwc3_rockchip {
|
||||
bool connected;
|
||||
bool skip_suspend;
|
||||
bool suspended;
|
||||
bool force_mode;
|
||||
enum usb_dr_mode original_dr_mode;
|
||||
struct device *dev;
|
||||
struct clk **clks;
|
||||
struct dwc3 *dwc;
|
||||
struct dentry *root;
|
||||
struct reset_control *otg_rst;
|
||||
struct extcon_dev *edev;
|
||||
struct notifier_block device_nb;
|
||||
@@ -62,46 +61,45 @@ struct dwc3_rockchip {
|
||||
struct mutex lock;
|
||||
};
|
||||
|
||||
static int dwc3_rockchip_force_mode_show(struct seq_file *s, void *unused)
|
||||
static ssize_t dwc3_mode_show(struct device *device,
|
||||
struct device_attribute *attr, char *buf)
|
||||
{
|
||||
struct dwc3_rockchip *rockchip = s->private;
|
||||
struct dwc3_rockchip *rockchip = dev_get_drvdata(device);
|
||||
struct dwc3 *dwc = rockchip->dwc;
|
||||
int ret;
|
||||
|
||||
switch (dwc->dr_mode) {
|
||||
case USB_DR_MODE_HOST:
|
||||
seq_puts(s, "host\n");
|
||||
ret = sprintf(buf, "host\n");
|
||||
break;
|
||||
case USB_DR_MODE_PERIPHERAL:
|
||||
seq_puts(s, "peripheral\n");
|
||||
ret = sprintf(buf, "peripheral\n");
|
||||
break;
|
||||
case USB_DR_MODE_OTG:
|
||||
seq_puts(s, "otg\n");
|
||||
ret = sprintf(buf, "otg\n");
|
||||
break;
|
||||
default:
|
||||
seq_puts(s, "UNKNOWN\n");
|
||||
ret = sprintf(buf, "UNKNOWN\n");
|
||||
}
|
||||
|
||||
return 0;
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int dwc3_rockchip_force_mode_open(struct inode *inode, struct file *file)
|
||||
static ssize_t dwc3_mode_store(struct device *device,
|
||||
struct device_attribute *attr,
|
||||
const char *buf, size_t count)
|
||||
{
|
||||
return single_open(file, dwc3_rockchip_force_mode_show,
|
||||
inode->i_private);
|
||||
}
|
||||
|
||||
static ssize_t dwc3_rockchip_force_mode_write(struct file *file,
|
||||
const char __user *ubuf,
|
||||
size_t count, loff_t *ppos)
|
||||
{
|
||||
struct seq_file *s = file->private_data;
|
||||
struct dwc3_rockchip *rockchip = s->private;
|
||||
struct dwc3_rockchip *rockchip = dev_get_drvdata(device);
|
||||
struct dwc3 *dwc = rockchip->dwc;
|
||||
enum usb_dr_mode new_dr_mode;
|
||||
char buf[32];
|
||||
|
||||
if (copy_from_user(&buf, ubuf, min_t(size_t, sizeof(buf) - 1, count)))
|
||||
return -EFAULT;
|
||||
if (!rockchip->original_dr_mode)
|
||||
rockchip->original_dr_mode = dwc->dr_mode;
|
||||
|
||||
if (rockchip->original_dr_mode != USB_DR_MODE_OTG) {
|
||||
dev_err(rockchip->dev, "Not support set mode!\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (!strncmp(buf, "0", 1) || !strncmp(buf, "otg", 3)) {
|
||||
new_dr_mode = USB_DR_MODE_OTG;
|
||||
@@ -119,108 +117,37 @@ static ssize_t dwc3_rockchip_force_mode_write(struct file *file,
|
||||
return count;
|
||||
}
|
||||
|
||||
rockchip->force_mode = true;
|
||||
|
||||
/*
|
||||
* Disconnect vbus to trigger gadget disconnect process by setting
|
||||
* the mode of phy to invalid if the current dr_mode of controller
|
||||
* is peripheral, than schedule otg work to change connect status
|
||||
* and suspend the controller.
|
||||
* If force to host mode from current peripheral mode, firstly,
|
||||
* set the usb2 phy mode to PHY_MODE_INVALID to disable vbus
|
||||
* detection function in usb2 phy, this can help to trigger
|
||||
* the peripheral disconnect by software.
|
||||
*/
|
||||
if (dwc->dr_mode == USB_DR_MODE_PERIPHERAL)
|
||||
phy_set_mode(dwc->usb2_generic_phy, PHY_MODE_INVALID);
|
||||
|
||||
dwc->dr_mode = USB_DR_MODE_OTG;
|
||||
schedule_work(&rockchip->otg_work);
|
||||
flush_work(&rockchip->otg_work);
|
||||
|
||||
/*
|
||||
* Schedule otg work to change connect status and resume the
|
||||
* controller, than connect vbus to trigger connect interrupt
|
||||
* and connect gadget by setting the mode of phy to device if
|
||||
* the dr_mode is peripheral.
|
||||
*/
|
||||
/* Schedule the otg work to set the otg to new mode. */
|
||||
dwc->dr_mode = new_dr_mode;
|
||||
schedule_work(&rockchip->otg_work);
|
||||
flush_work(&rockchip->otg_work);
|
||||
|
||||
/* Set phy mode */
|
||||
if (dwc->dr_mode == USB_DR_MODE_PERIPHERAL)
|
||||
phy_set_mode(dwc->usb2_generic_phy, PHY_MODE_USB_DEVICE);
|
||||
else if (dwc->dr_mode == USB_DR_MODE_HOST)
|
||||
phy_set_mode(dwc->usb2_generic_phy, PHY_MODE_USB_HOST);
|
||||
|
||||
dev_info(rockchip->dev, "set new mode successfully\n");
|
||||
return count;
|
||||
}
|
||||
|
||||
static const struct file_operations dwc3_rockchip_force_mode_fops = {
|
||||
.open = dwc3_rockchip_force_mode_open,
|
||||
.write = dwc3_rockchip_force_mode_write,
|
||||
.read = seq_read,
|
||||
.llseek = seq_lseek,
|
||||
.release = single_release,
|
||||
};
|
||||
|
||||
static int dwc3_rockchip_host_testmode_show(struct seq_file *s, void *unused)
|
||||
{
|
||||
struct dwc3_rockchip *rockchip = s->private;
|
||||
struct dwc3 *dwc = rockchip->dwc;
|
||||
struct usb_hcd *hcd = dev_get_drvdata(&dwc->xhci->dev);
|
||||
struct xhci_hcd *xhci = hcd_to_xhci(hcd);
|
||||
__le32 __iomem **port_array;
|
||||
u32 reg;
|
||||
|
||||
if (rockchip->dwc->dr_mode == USB_DR_MODE_PERIPHERAL) {
|
||||
dev_warn(rockchip->dev, "USB HOST not support!\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (hcd->state == HC_STATE_HALT) {
|
||||
dev_warn(rockchip->dev, "HOST is halted, set test mode first!\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
port_array = xhci->usb2_ports;
|
||||
reg = readl(port_array[0] + PORTPMSC);
|
||||
reg &= XHCI_TSTCTRL_MASK;
|
||||
reg >>= 28;
|
||||
|
||||
switch (reg) {
|
||||
case 0:
|
||||
seq_puts(s, "U2: no test\n");
|
||||
break;
|
||||
case TEST_J:
|
||||
seq_puts(s, "U2: test_j\n");
|
||||
break;
|
||||
case TEST_K:
|
||||
seq_puts(s, "U2: test_k\n");
|
||||
break;
|
||||
case TEST_SE0_NAK:
|
||||
seq_puts(s, "U2: test_se0_nak\n");
|
||||
break;
|
||||
case TEST_PACKET:
|
||||
seq_puts(s, "U2: test_packet\n");
|
||||
break;
|
||||
case TEST_FORCE_EN:
|
||||
seq_puts(s, "U2: test_force_enable\n");
|
||||
break;
|
||||
default:
|
||||
seq_printf(s, "U2: UNKNOWN %d\n", reg);
|
||||
}
|
||||
|
||||
port_array = xhci->usb3_ports;
|
||||
reg = readl(port_array[0]);
|
||||
reg &= PORT_PLS_MASK;
|
||||
if (reg == USB_SS_PORT_LS_COMP_MOD)
|
||||
seq_puts(s, "U3: compliance mode\n");
|
||||
else
|
||||
seq_printf(s, "U3: UNKNOWN %d\n", reg >> 5);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int dwc3_rockchip_host_testmode_open(struct inode *inode,
|
||||
struct file *file)
|
||||
{
|
||||
return single_open(file, dwc3_rockchip_host_testmode_show,
|
||||
inode->i_private);
|
||||
}
|
||||
|
||||
#if defined(CONFIG_USB_DWC3_HOST) || defined(CONFIG_USB_DWC3_DUAL_ROLE)
|
||||
/**
|
||||
* dwc3_rockchip_set_test_mode - Enables USB2/USB3 HOST Test Modes
|
||||
* @rockchip: pointer to our context structure
|
||||
@@ -273,26 +200,81 @@ static int dwc3_rockchip_set_test_mode(struct dwc3_rockchip *rockchip,
|
||||
return 0;
|
||||
}
|
||||
|
||||
static ssize_t dwc3_rockchip_host_testmode_write(struct file *file,
|
||||
const char __user *ubuf,
|
||||
size_t count, loff_t *ppos)
|
||||
static ssize_t host_testmode_show(struct device *device,
|
||||
struct device_attribute *attr, char *buf)
|
||||
{
|
||||
struct seq_file *s = file->private_data;
|
||||
struct dwc3_rockchip *rockchip = s->private;
|
||||
struct dwc3_rockchip *rockchip = dev_get_drvdata(device);
|
||||
struct dwc3 *dwc = rockchip->dwc;
|
||||
struct usb_hcd *hcd = dev_get_drvdata(&dwc->xhci->dev);
|
||||
struct xhci_hcd *xhci = hcd_to_xhci(hcd);
|
||||
__le32 __iomem **port_array;
|
||||
u32 reg;
|
||||
int ret;
|
||||
|
||||
if (rockchip->dwc->dr_mode == USB_DR_MODE_PERIPHERAL) {
|
||||
dev_warn(rockchip->dev, "USB peripheral not support!\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (hcd->state == HC_STATE_HALT) {
|
||||
dev_warn(rockchip->dev, "HOST is halted, set test mode first!\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
port_array = xhci->usb2_ports;
|
||||
reg = readl(port_array[0] + PORTPMSC);
|
||||
reg &= XHCI_TSTCTRL_MASK;
|
||||
reg >>= 28;
|
||||
|
||||
switch (reg) {
|
||||
case 0:
|
||||
ret = sprintf(buf, "U2: no test\n");
|
||||
break;
|
||||
case TEST_J:
|
||||
ret = sprintf(buf, "U2: test_j\n");
|
||||
break;
|
||||
case TEST_K:
|
||||
ret = sprintf(buf, "U2: test_k\n");
|
||||
break;
|
||||
case TEST_SE0_NAK:
|
||||
ret = sprintf(buf, "U2: test_se0_nak\n");
|
||||
break;
|
||||
case TEST_PACKET:
|
||||
ret = sprintf(buf, "U2: test_packet\n");
|
||||
break;
|
||||
case TEST_FORCE_EN:
|
||||
ret = sprintf(buf, "U2: test_force_enable\n");
|
||||
break;
|
||||
default:
|
||||
ret = sprintf(buf, "U2: UNKNOWN %d\n", reg);
|
||||
}
|
||||
|
||||
port_array = xhci->usb3_ports;
|
||||
reg = readl(port_array[0]);
|
||||
reg &= PORT_PLS_MASK;
|
||||
if (reg == USB_SS_PORT_LS_COMP_MOD)
|
||||
ret += sprintf(buf + ret, "U3: compliance mode\n");
|
||||
else
|
||||
ret += sprintf(buf + ret, "U3: UNKNOWN %d\n", reg >> 5);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static ssize_t host_testmode_store(struct device *device,
|
||||
struct device_attribute *attr,
|
||||
const char *buf, size_t count)
|
||||
{
|
||||
struct dwc3_rockchip *rockchip = dev_get_drvdata(device);
|
||||
struct extcon_dev *edev = rockchip->edev;
|
||||
u32 testmode = 0;
|
||||
bool flip = 0;
|
||||
char buf[32];
|
||||
bool flip = false;
|
||||
union extcon_property_value property;
|
||||
|
||||
if (rockchip->dwc->dr_mode == USB_DR_MODE_PERIPHERAL) {
|
||||
dev_warn(rockchip->dev, "USB HOST not support!\n");
|
||||
return -EINVAL;
|
||||
dev_warn(rockchip->dev, "USB peripheral not support!\n");
|
||||
return count;
|
||||
}
|
||||
|
||||
if (copy_from_user(&buf, ubuf, min_t(size_t, sizeof(buf) - 1, count)))
|
||||
return -EFAULT;
|
||||
|
||||
if (!strncmp(buf, "test_j", 6)) {
|
||||
testmode = TEST_J;
|
||||
} else if (!strncmp(buf, "test_k", 6)) {
|
||||
@@ -307,10 +289,10 @@ static ssize_t dwc3_rockchip_host_testmode_write(struct file *file,
|
||||
testmode = USB_SS_PORT_LS_COMP_MOD;
|
||||
} else if (!strncmp(buf, "test_flip_u3", 12)) {
|
||||
testmode = USB_SS_PORT_LS_COMP_MOD;
|
||||
flip = 1;
|
||||
flip = true;
|
||||
} else {
|
||||
dev_warn(rockchip->dev, "Test cmd not support!\n");
|
||||
return -EINVAL;
|
||||
dev_warn(rockchip->dev, "Cmd not support! Try test_u3 or test_packet\n");
|
||||
return count;
|
||||
}
|
||||
|
||||
if (edev && !extcon_get_cable_state_(edev, EXTCON_USB_HOST)) {
|
||||
@@ -324,6 +306,8 @@ static ssize_t dwc3_rockchip_host_testmode_write(struct file *file,
|
||||
|
||||
/* Add a delay 1s to wait for XHCI HCD init */
|
||||
msleep(1000);
|
||||
|
||||
rockchip->dwc->dr_mode = USB_DR_MODE_HOST;
|
||||
}
|
||||
|
||||
dwc3_rockchip_set_test_mode(rockchip, testmode);
|
||||
@@ -331,47 +315,23 @@ static ssize_t dwc3_rockchip_host_testmode_write(struct file *file,
|
||||
return count;
|
||||
}
|
||||
|
||||
static const struct file_operations dwc3_host_testmode_fops = {
|
||||
.open = dwc3_rockchip_host_testmode_open,
|
||||
.write = dwc3_rockchip_host_testmode_write,
|
||||
.read = seq_read,
|
||||
.llseek = seq_lseek,
|
||||
.release = single_release,
|
||||
static DEVICE_ATTR_RW(host_testmode);
|
||||
#endif
|
||||
|
||||
static DEVICE_ATTR_RW(dwc3_mode);
|
||||
|
||||
static struct attribute *dwc3_rockchip_attrs[] = {
|
||||
&dev_attr_dwc3_mode.attr,
|
||||
#if defined(CONFIG_USB_DWC3_HOST) || defined(CONFIG_USB_DWC3_DUAL_ROLE)
|
||||
&dev_attr_host_testmode.attr,
|
||||
#endif
|
||||
NULL,
|
||||
};
|
||||
|
||||
static void dwc3_rockchip_debugfs_init(struct dwc3_rockchip *rockchip)
|
||||
{
|
||||
struct dentry *root;
|
||||
struct dentry *file;
|
||||
|
||||
root = debugfs_create_dir(dev_name(rockchip->dev), NULL);
|
||||
if (IS_ERR_OR_NULL(root)) {
|
||||
if (!root)
|
||||
dev_err(rockchip->dev, "Can't create debugfs root\n");
|
||||
return;
|
||||
}
|
||||
rockchip->root = root;
|
||||
|
||||
if (IS_ENABLED(CONFIG_USB_DWC3_DUAL_ROLE) ||
|
||||
IS_ENABLED(CONFIG_USB_DWC3_HOST)) {
|
||||
file = debugfs_create_file("host_testmode", S_IRUSR | S_IWUSR,
|
||||
root, rockchip,
|
||||
&dwc3_host_testmode_fops);
|
||||
if (!file)
|
||||
dev_dbg(rockchip->dev, "Can't create debugfs host_testmode\n");
|
||||
}
|
||||
|
||||
if (IS_ENABLED(CONFIG_USB_DWC3_DUAL_ROLE) &&
|
||||
!rockchip->edev && (rockchip->dwc->dr_mode == USB_DR_MODE_OTG)) {
|
||||
file = debugfs_create_file("rk_usb_force_mode",
|
||||
S_IRUSR | S_IWUSR,
|
||||
root, rockchip,
|
||||
&dwc3_rockchip_force_mode_fops);
|
||||
if (!file)
|
||||
dev_dbg(rockchip->dev,
|
||||
"Can't create debugfs rk_usb_force_mode\n");
|
||||
}
|
||||
}
|
||||
static struct attribute_group dwc3_rockchip_attr_group = {
|
||||
.name = NULL, /* we want them in the same directory */
|
||||
.attrs = dwc3_rockchip_attrs,
|
||||
};
|
||||
|
||||
static int dwc3_rockchip_device_notifier(struct notifier_block *nb,
|
||||
unsigned long event, void *ptr)
|
||||
@@ -413,8 +373,8 @@ static void dwc3_rockchip_otg_extcon_evt_work(struct work_struct *work)
|
||||
|
||||
mutex_lock(&rockchip->lock);
|
||||
|
||||
if (rockchip->edev ? extcon_get_cable_state_(edev, EXTCON_USB) :
|
||||
(dwc->dr_mode == USB_DR_MODE_PERIPHERAL)) {
|
||||
if (rockchip->force_mode ? dwc->dr_mode == USB_DR_MODE_PERIPHERAL :
|
||||
extcon_get_cable_state_(edev, EXTCON_USB)) {
|
||||
if (rockchip->connected)
|
||||
goto out;
|
||||
|
||||
@@ -465,9 +425,8 @@ static void dwc3_rockchip_otg_extcon_evt_work(struct work_struct *work)
|
||||
|
||||
rockchip->connected = true;
|
||||
dev_info(rockchip->dev, "USB peripheral connected\n");
|
||||
} else if (rockchip->edev ?
|
||||
extcon_get_cable_state_(edev, EXTCON_USB_HOST) :
|
||||
(dwc->dr_mode == USB_DR_MODE_HOST)) {
|
||||
} else if (rockchip->force_mode ? dwc->dr_mode == USB_DR_MODE_HOST :
|
||||
extcon_get_cable_state_(edev, EXTCON_USB_HOST)) {
|
||||
if (rockchip->connected) {
|
||||
reg = dwc3_readl(dwc->regs, DWC3_GCTL);
|
||||
|
||||
@@ -847,7 +806,9 @@ static int dwc3_rockchip_probe(struct platform_device *pdev)
|
||||
rockchip->connected = true;
|
||||
}
|
||||
|
||||
dwc3_rockchip_debugfs_init(rockchip);
|
||||
ret = sysfs_create_group(&dev->kobj, &dwc3_rockchip_attr_group);
|
||||
if (ret)
|
||||
dev_err(dev, "failed to create sysfs group: %d\n", ret);
|
||||
|
||||
mutex_unlock(&rockchip->lock);
|
||||
|
||||
@@ -881,7 +842,7 @@ static int dwc3_rockchip_remove(struct platform_device *pdev)
|
||||
|
||||
dwc3_rockchip_extcon_unregister(rockchip);
|
||||
|
||||
debugfs_remove_recursive(rockchip->root);
|
||||
sysfs_remove_group(&dev->kobj, &dwc3_rockchip_attr_group);
|
||||
|
||||
/* Restore hcd state before unregistering xhci */
|
||||
if (rockchip->edev && !rockchip->connected) {
|
||||
|
||||
Reference in New Issue
Block a user