forked from mirrors/linux
Here is the big set of driver core and debugfs updates for 6.14-rc1.
It's coming late in the merge cycle as there are a number of merge
conflicts with your tree now, and I wanted to make sure they were
working properly. To resolve them, look in linux-next, and I will send
the "fixup" patch as a response to the pull request.
Included in here is a bunch of driver core, PCI, OF, and platform rust
bindings (all acked by the different subsystem maintainers), hence the
merge conflict with the rust tree, and some driver core api updates to
mark things as const, which will also require some fixups due to new
stuff coming in through other trees in this merge window.
There are also a bunch of debugfs updates from Al, and there is at least
one user that does have a regression with these, but Al is working on
tracking down the fix for it. In my use (and everyone else's linux-next
use), it does not seem like a big issue at the moment.
Here's a short list of the things in here:
- driver core bindings for PCI, platform, OF, and some i/o functions.
We are almost at the "write a real driver in rust" stage now,
depending on what you want to do.
- misc device rust bindings and a sample driver to show how to use
them
- debugfs cleanups in the fs as well as the users of the fs api for
places where drivers got it wrong or were unnecessarily doing things
in complex ways.
- driver core const work, making more of the api take const * for
different parameters to make the rust bindings easier overall.
- other small fixes and updates
All of these have been in linux-next with all of the aforementioned
merge conflicts, and the one debugfs issue, which looks to be resolved
"soon".
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
-----BEGIN PGP SIGNATURE-----
iG0EABECAC0WIQT0tgzFv3jCIUoxPcsxR9QN2y37KQUCZ5koPA8cZ3JlZ0Brcm9h
aC5jb20ACgkQMUfUDdst+ymFHACfT5acDKf2Bov2Lc/5u3vBW/R6ChsAnj+LmgVI
hcDSPodj4szR40RRnzBd
=u5Ey
-----END PGP SIGNATURE-----
Merge tag 'driver-core-6.14-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/driver-core
Pull driver core and debugfs updates from Greg KH:
"Here is the big set of driver core and debugfs updates for 6.14-rc1.
Included in here is a bunch of driver core, PCI, OF, and platform rust
bindings (all acked by the different subsystem maintainers), hence the
merge conflict with the rust tree, and some driver core api updates to
mark things as const, which will also require some fixups due to new
stuff coming in through other trees in this merge window.
There are also a bunch of debugfs updates from Al, and there is at
least one user that does have a regression with these, but Al is
working on tracking down the fix for it. In my use (and everyone
else's linux-next use), it does not seem like a big issue at the
moment.
Here's a short list of the things in here:
- driver core rust bindings for PCI, platform, OF, and some i/o
functions.
We are almost at the "write a real driver in rust" stage now,
depending on what you want to do.
- misc device rust bindings and a sample driver to show how to use
them
- debugfs cleanups in the fs as well as the users of the fs api for
places where drivers got it wrong or were unnecessarily doing
things in complex ways.
- driver core const work, making more of the api take const * for
different parameters to make the rust bindings easier overall.
- other small fixes and updates
All of these have been in linux-next with all of the aforementioned
merge conflicts, and the one debugfs issue, which looks to be resolved
"soon""
* tag 'driver-core-6.14-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/driver-core: (95 commits)
rust: device: Use as_char_ptr() to avoid explicit cast
rust: device: Replace CString with CStr in property_present()
devcoredump: Constify 'struct bin_attribute'
devcoredump: Define 'struct bin_attribute' through macro
rust: device: Add property_present()
saner replacement for debugfs_rename()
orangefs-debugfs: don't mess with ->d_name
octeontx2: don't mess with ->d_parent or ->d_parent->d_name
arm_scmi: don't mess with ->d_parent->d_name
slub: don't mess with ->d_name
sof-client-ipc-flood-test: don't mess with ->d_name
qat: don't mess with ->d_name
xhci: don't mess with ->d_iname
mtu3: don't mess wiht ->d_iname
greybus/camera - stop messing with ->d_iname
mediatek: stop messing with ->d_iname
netdevsim: don't embed file_operations into your structs
b43legacy: make use of debugfs_get_aux()
b43: stop embedding struct file_operations into their objects
carl9170: stop embedding file_operations into their objects
...
515 lines
13 KiB
C
515 lines
13 KiB
C
// SPDX-License-Identifier: GPL-2.0
|
|
/*
|
|
* mtu3_debugfs.c - debugfs interface
|
|
*
|
|
* Copyright (C) 2019 MediaTek Inc.
|
|
*
|
|
* Author: Chunfeng Yun <chunfeng.yun@mediatek.com>
|
|
*/
|
|
|
|
#include <linux/string_choices.h>
|
|
#include <linux/uaccess.h>
|
|
|
|
#include "mtu3.h"
|
|
#include "mtu3_dr.h"
|
|
#include "mtu3_debug.h"
|
|
|
|
#define dump_register(nm) \
|
|
{ \
|
|
.name = __stringify(nm), \
|
|
.offset = U3D_ ##nm, \
|
|
}
|
|
|
|
#define dump_prb_reg(nm, os) \
|
|
{ \
|
|
.name = nm, \
|
|
.offset = os, \
|
|
}
|
|
|
|
static const struct debugfs_reg32 mtu3_ippc_regs[] = {
|
|
dump_register(SSUSB_IP_PW_CTRL0),
|
|
dump_register(SSUSB_IP_PW_CTRL1),
|
|
dump_register(SSUSB_IP_PW_CTRL2),
|
|
dump_register(SSUSB_IP_PW_CTRL3),
|
|
dump_register(SSUSB_IP_PW_STS1),
|
|
dump_register(SSUSB_OTG_STS),
|
|
dump_register(SSUSB_IP_XHCI_CAP),
|
|
dump_register(SSUSB_IP_DEV_CAP),
|
|
dump_register(SSUSB_U3_CTRL_0P),
|
|
dump_register(SSUSB_U2_CTRL_0P),
|
|
dump_register(SSUSB_HW_ID),
|
|
dump_register(SSUSB_HW_SUB_ID),
|
|
dump_register(SSUSB_IP_SPARE0),
|
|
};
|
|
|
|
static const struct debugfs_reg32 mtu3_dev_regs[] = {
|
|
dump_register(LV1ISR),
|
|
dump_register(LV1IER),
|
|
dump_register(EPISR),
|
|
dump_register(EPIER),
|
|
dump_register(EP0CSR),
|
|
dump_register(RXCOUNT0),
|
|
dump_register(QISAR0),
|
|
dump_register(QIER0),
|
|
dump_register(QISAR1),
|
|
dump_register(QIER1),
|
|
dump_register(CAP_EPNTXFFSZ),
|
|
dump_register(CAP_EPNRXFFSZ),
|
|
dump_register(CAP_EPINFO),
|
|
dump_register(MISC_CTRL),
|
|
};
|
|
|
|
static const struct debugfs_reg32 mtu3_csr_regs[] = {
|
|
dump_register(DEVICE_CONF),
|
|
dump_register(DEV_LINK_INTR_ENABLE),
|
|
dump_register(DEV_LINK_INTR),
|
|
dump_register(LTSSM_CTRL),
|
|
dump_register(USB3_CONFIG),
|
|
dump_register(LINK_STATE_MACHINE),
|
|
dump_register(LTSSM_INTR_ENABLE),
|
|
dump_register(LTSSM_INTR),
|
|
dump_register(U3U2_SWITCH_CTRL),
|
|
dump_register(POWER_MANAGEMENT),
|
|
dump_register(DEVICE_CONTROL),
|
|
dump_register(COMMON_USB_INTR_ENABLE),
|
|
dump_register(COMMON_USB_INTR),
|
|
dump_register(USB20_MISC_CONTROL),
|
|
dump_register(USB20_OPSTATE),
|
|
};
|
|
|
|
static int mtu3_link_state_show(struct seq_file *sf, void *unused)
|
|
{
|
|
struct mtu3 *mtu = sf->private;
|
|
void __iomem *mbase = mtu->mac_base;
|
|
|
|
seq_printf(sf, "opstate: %#x, ltssm: %#x\n",
|
|
mtu3_readl(mbase, U3D_USB20_OPSTATE),
|
|
LTSSM_STATE(mtu3_readl(mbase, U3D_LINK_STATE_MACHINE)));
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int mtu3_ep_used_show(struct seq_file *sf, void *unused)
|
|
{
|
|
struct mtu3 *mtu = sf->private;
|
|
struct mtu3_ep *mep;
|
|
unsigned long flags;
|
|
int used = 0;
|
|
int i;
|
|
|
|
spin_lock_irqsave(&mtu->lock, flags);
|
|
|
|
for (i = 0; i < mtu->num_eps; i++) {
|
|
mep = mtu->in_eps + i;
|
|
if (mep->flags & MTU3_EP_ENABLED) {
|
|
seq_printf(sf, "%s - type: %s\n", mep->name, usb_ep_type_string(mep->type));
|
|
used++;
|
|
}
|
|
|
|
mep = mtu->out_eps + i;
|
|
if (mep->flags & MTU3_EP_ENABLED) {
|
|
seq_printf(sf, "%s - type: %s\n", mep->name, usb_ep_type_string(mep->type));
|
|
used++;
|
|
}
|
|
}
|
|
seq_printf(sf, "total used: %d eps\n", used);
|
|
|
|
spin_unlock_irqrestore(&mtu->lock, flags);
|
|
|
|
return 0;
|
|
}
|
|
|
|
DEFINE_SHOW_ATTRIBUTE(mtu3_link_state);
|
|
DEFINE_SHOW_ATTRIBUTE(mtu3_ep_used);
|
|
|
|
static void mtu3_debugfs_regset(struct mtu3 *mtu, void __iomem *base,
|
|
const struct debugfs_reg32 *regs, size_t nregs,
|
|
const char *name, struct dentry *parent)
|
|
{
|
|
struct debugfs_regset32 *regset;
|
|
struct mtu3_regset *mregs;
|
|
|
|
mregs = devm_kzalloc(mtu->dev, sizeof(*mregs), GFP_KERNEL);
|
|
if (!mregs)
|
|
return;
|
|
|
|
sprintf(mregs->name, "%s", name);
|
|
regset = &mregs->regset;
|
|
regset->regs = regs;
|
|
regset->nregs = nregs;
|
|
regset->base = base;
|
|
|
|
debugfs_create_regset32(mregs->name, 0444, parent, regset);
|
|
}
|
|
|
|
static void mtu3_debugfs_ep_regset(struct mtu3 *mtu, struct mtu3_ep *mep,
|
|
struct dentry *parent)
|
|
{
|
|
struct debugfs_reg32 *regs;
|
|
int epnum = mep->epnum;
|
|
int in = mep->is_in;
|
|
|
|
regs = devm_kcalloc(mtu->dev, 7, sizeof(*regs), GFP_KERNEL);
|
|
if (!regs)
|
|
return;
|
|
|
|
regs[0].name = in ? "TCR0" : "RCR0";
|
|
regs[0].offset = in ? MU3D_EP_TXCR0(epnum) : MU3D_EP_RXCR0(epnum);
|
|
regs[1].name = in ? "TCR1" : "RCR1";
|
|
regs[1].offset = in ? MU3D_EP_TXCR1(epnum) : MU3D_EP_RXCR1(epnum);
|
|
regs[2].name = in ? "TCR2" : "RCR2";
|
|
regs[2].offset = in ? MU3D_EP_TXCR2(epnum) : MU3D_EP_RXCR2(epnum);
|
|
regs[3].name = in ? "TQHIAR" : "RQHIAR";
|
|
regs[3].offset = in ? USB_QMU_TQHIAR(epnum) : USB_QMU_RQHIAR(epnum);
|
|
regs[4].name = in ? "TQCSR" : "RQCSR";
|
|
regs[4].offset = in ? USB_QMU_TQCSR(epnum) : USB_QMU_RQCSR(epnum);
|
|
regs[5].name = in ? "TQSAR" : "RQSAR";
|
|
regs[5].offset = in ? USB_QMU_TQSAR(epnum) : USB_QMU_RQSAR(epnum);
|
|
regs[6].name = in ? "TQCPR" : "RQCPR";
|
|
regs[6].offset = in ? USB_QMU_TQCPR(epnum) : USB_QMU_RQCPR(epnum);
|
|
|
|
mtu3_debugfs_regset(mtu, mtu->mac_base, regs, 7, "ep-regs", parent);
|
|
}
|
|
|
|
static int mtu3_ep_info_show(struct seq_file *sf, void *unused)
|
|
{
|
|
struct mtu3_ep *mep = sf->private;
|
|
struct mtu3 *mtu = mep->mtu;
|
|
unsigned long flags;
|
|
|
|
spin_lock_irqsave(&mtu->lock, flags);
|
|
seq_printf(sf, "ep - type:%s, maxp:%d, slot:%d, flags:%x\n",
|
|
usb_ep_type_string(mep->type), mep->maxp, mep->slot, mep->flags);
|
|
spin_unlock_irqrestore(&mtu->lock, flags);
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int mtu3_fifo_show(struct seq_file *sf, void *unused)
|
|
{
|
|
struct mtu3_ep *mep = sf->private;
|
|
struct mtu3 *mtu = mep->mtu;
|
|
unsigned long flags;
|
|
|
|
spin_lock_irqsave(&mtu->lock, flags);
|
|
seq_printf(sf, "fifo - seg_size:%d, addr:%d, size:%d\n",
|
|
mep->fifo_seg_size, mep->fifo_addr, mep->fifo_size);
|
|
spin_unlock_irqrestore(&mtu->lock, flags);
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int mtu3_qmu_ring_show(struct seq_file *sf, void *unused)
|
|
{
|
|
struct mtu3_ep *mep = sf->private;
|
|
struct mtu3 *mtu = mep->mtu;
|
|
struct mtu3_gpd_ring *ring;
|
|
unsigned long flags;
|
|
|
|
ring = &mep->gpd_ring;
|
|
spin_lock_irqsave(&mtu->lock, flags);
|
|
seq_printf(sf,
|
|
"qmu-ring - dma:%pad, start:%p, end:%p, enq:%p, dep:%p\n",
|
|
&ring->dma, ring->start, ring->end,
|
|
ring->enqueue, ring->dequeue);
|
|
spin_unlock_irqrestore(&mtu->lock, flags);
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int mtu3_qmu_gpd_show(struct seq_file *sf, void *unused)
|
|
{
|
|
struct mtu3_ep *mep = sf->private;
|
|
struct mtu3 *mtu = mep->mtu;
|
|
struct mtu3_gpd_ring *ring;
|
|
struct qmu_gpd *gpd;
|
|
dma_addr_t dma;
|
|
unsigned long flags;
|
|
int i;
|
|
|
|
spin_lock_irqsave(&mtu->lock, flags);
|
|
ring = &mep->gpd_ring;
|
|
gpd = ring->start;
|
|
if (!gpd || !(mep->flags & MTU3_EP_ENABLED)) {
|
|
seq_puts(sf, "empty!\n");
|
|
goto out;
|
|
}
|
|
|
|
for (i = 0; i < MAX_GPD_NUM; i++, gpd++) {
|
|
dma = ring->dma + i * sizeof(*gpd);
|
|
seq_printf(sf, "gpd.%03d -> %pad, %p: %08x %08x %08x %08x\n",
|
|
i, &dma, gpd, gpd->dw0_info, gpd->next_gpd,
|
|
gpd->buffer, gpd->dw3_info);
|
|
}
|
|
|
|
out:
|
|
spin_unlock_irqrestore(&mtu->lock, flags);
|
|
|
|
return 0;
|
|
}
|
|
|
|
static const struct mtu3_file_map mtu3_ep_files[] = {
|
|
{"ep-info", mtu3_ep_info_show, },
|
|
{"fifo", mtu3_fifo_show, },
|
|
{"qmu-ring", mtu3_qmu_ring_show, },
|
|
{"qmu-gpd", mtu3_qmu_gpd_show, },
|
|
};
|
|
|
|
static int mtu3_ep_open(struct inode *inode, struct file *file)
|
|
{
|
|
const struct mtu3_file_map *f_map = debugfs_get_aux(file);
|
|
|
|
return single_open(file, f_map->show, inode->i_private);
|
|
}
|
|
|
|
static const struct file_operations mtu3_ep_fops = {
|
|
.open = mtu3_ep_open,
|
|
.read = seq_read,
|
|
.llseek = seq_lseek,
|
|
.release = single_release,
|
|
};
|
|
|
|
static const struct debugfs_reg32 mtu3_prb_regs[] = {
|
|
dump_prb_reg("enable", U3D_SSUSB_PRB_CTRL0),
|
|
dump_prb_reg("byte-sell", U3D_SSUSB_PRB_CTRL1),
|
|
dump_prb_reg("byte-selh", U3D_SSUSB_PRB_CTRL2),
|
|
dump_prb_reg("module-sel", U3D_SSUSB_PRB_CTRL3),
|
|
dump_prb_reg("sw-out", U3D_SSUSB_PRB_CTRL4),
|
|
dump_prb_reg("data", U3D_SSUSB_PRB_CTRL5),
|
|
};
|
|
|
|
static int mtu3_probe_show(struct seq_file *sf, void *unused)
|
|
{
|
|
struct mtu3 *mtu = sf->private;
|
|
const struct debugfs_reg32 *regs = debugfs_get_aux(sf->file);
|
|
|
|
seq_printf(sf, "0x%04x - 0x%08x\n", (u32)regs->offset,
|
|
mtu3_readl(mtu->ippc_base, (u32)regs->offset));
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int mtu3_probe_open(struct inode *inode, struct file *file)
|
|
{
|
|
return single_open(file, mtu3_probe_show, inode->i_private);
|
|
}
|
|
|
|
static ssize_t mtu3_probe_write(struct file *file, const char __user *ubuf,
|
|
size_t count, loff_t *ppos)
|
|
{
|
|
struct seq_file *sf = file->private_data;
|
|
struct mtu3 *mtu = sf->private;
|
|
const struct debugfs_reg32 *regs = debugfs_get_aux(file);
|
|
char buf[32];
|
|
u32 val;
|
|
|
|
if (copy_from_user(&buf, ubuf, min_t(size_t, sizeof(buf) - 1, count)))
|
|
return -EFAULT;
|
|
|
|
if (kstrtou32(buf, 0, &val))
|
|
return -EINVAL;
|
|
|
|
mtu3_writel(mtu->ippc_base, (u32)regs->offset, val);
|
|
|
|
return count;
|
|
}
|
|
|
|
static const struct file_operations mtu3_probe_fops = {
|
|
.open = mtu3_probe_open,
|
|
.write = mtu3_probe_write,
|
|
.read = seq_read,
|
|
.llseek = seq_lseek,
|
|
.release = single_release,
|
|
};
|
|
|
|
static void mtu3_debugfs_create_prb_files(struct mtu3 *mtu)
|
|
{
|
|
struct ssusb_mtk *ssusb = mtu->ssusb;
|
|
const struct debugfs_reg32 *regs;
|
|
struct dentry *dir_prb;
|
|
int i;
|
|
|
|
dir_prb = debugfs_create_dir("probe", ssusb->dbgfs_root);
|
|
|
|
for (i = 0; i < ARRAY_SIZE(mtu3_prb_regs); i++) {
|
|
regs = &mtu3_prb_regs[i];
|
|
debugfs_create_file_aux(regs->name, 0644, dir_prb,
|
|
mtu, regs, &mtu3_probe_fops);
|
|
}
|
|
|
|
mtu3_debugfs_regset(mtu, mtu->ippc_base, mtu3_prb_regs,
|
|
ARRAY_SIZE(mtu3_prb_regs), "regs", dir_prb);
|
|
}
|
|
|
|
static void mtu3_debugfs_create_ep_dir(struct mtu3_ep *mep,
|
|
struct dentry *parent)
|
|
{
|
|
const struct mtu3_file_map *files;
|
|
struct dentry *dir_ep;
|
|
int i;
|
|
|
|
dir_ep = debugfs_create_dir(mep->name, parent);
|
|
mtu3_debugfs_ep_regset(mep->mtu, mep, dir_ep);
|
|
|
|
for (i = 0; i < ARRAY_SIZE(mtu3_ep_files); i++) {
|
|
files = &mtu3_ep_files[i];
|
|
|
|
debugfs_create_file_aux(files->name, 0444, dir_ep,
|
|
mep, files, &mtu3_ep_fops);
|
|
}
|
|
}
|
|
|
|
static void mtu3_debugfs_create_ep_dirs(struct mtu3 *mtu)
|
|
{
|
|
struct ssusb_mtk *ssusb = mtu->ssusb;
|
|
struct dentry *dir_eps;
|
|
int i;
|
|
|
|
dir_eps = debugfs_create_dir("eps", ssusb->dbgfs_root);
|
|
|
|
for (i = 1; i < mtu->num_eps; i++) {
|
|
mtu3_debugfs_create_ep_dir(mtu->in_eps + i, dir_eps);
|
|
mtu3_debugfs_create_ep_dir(mtu->out_eps + i, dir_eps);
|
|
}
|
|
}
|
|
|
|
void ssusb_dev_debugfs_init(struct ssusb_mtk *ssusb)
|
|
{
|
|
struct mtu3 *mtu = ssusb->u3d;
|
|
struct dentry *dir_regs;
|
|
|
|
dir_regs = debugfs_create_dir("regs", ssusb->dbgfs_root);
|
|
|
|
mtu3_debugfs_regset(mtu, mtu->ippc_base,
|
|
mtu3_ippc_regs, ARRAY_SIZE(mtu3_ippc_regs),
|
|
"reg-ippc", dir_regs);
|
|
|
|
mtu3_debugfs_regset(mtu, mtu->mac_base,
|
|
mtu3_dev_regs, ARRAY_SIZE(mtu3_dev_regs),
|
|
"reg-dev", dir_regs);
|
|
|
|
mtu3_debugfs_regset(mtu, mtu->mac_base,
|
|
mtu3_csr_regs, ARRAY_SIZE(mtu3_csr_regs),
|
|
"reg-csr", dir_regs);
|
|
|
|
mtu3_debugfs_create_ep_dirs(mtu);
|
|
|
|
mtu3_debugfs_create_prb_files(mtu);
|
|
|
|
debugfs_create_file("link-state", 0444, ssusb->dbgfs_root,
|
|
mtu, &mtu3_link_state_fops);
|
|
debugfs_create_file("ep-used", 0444, ssusb->dbgfs_root,
|
|
mtu, &mtu3_ep_used_fops);
|
|
}
|
|
|
|
static int ssusb_mode_show(struct seq_file *sf, void *unused)
|
|
{
|
|
struct ssusb_mtk *ssusb = sf->private;
|
|
|
|
seq_printf(sf, "current mode: %s(%s drd)\n(echo device/host)\n",
|
|
ssusb->is_host ? "host" : "device",
|
|
ssusb->otg_switch.manual_drd_enabled ? "manual" : "auto");
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int ssusb_mode_open(struct inode *inode, struct file *file)
|
|
{
|
|
return single_open(file, ssusb_mode_show, inode->i_private);
|
|
}
|
|
|
|
static ssize_t ssusb_mode_write(struct file *file, const char __user *ubuf,
|
|
size_t count, loff_t *ppos)
|
|
{
|
|
struct seq_file *sf = file->private_data;
|
|
struct ssusb_mtk *ssusb = sf->private;
|
|
char buf[16];
|
|
|
|
if (copy_from_user(&buf, ubuf, min_t(size_t, sizeof(buf) - 1, count)))
|
|
return -EFAULT;
|
|
|
|
if (!strncmp(buf, "host", 4) && !ssusb->is_host) {
|
|
ssusb_mode_switch(ssusb, 1);
|
|
} else if (!strncmp(buf, "device", 6) && ssusb->is_host) {
|
|
ssusb_mode_switch(ssusb, 0);
|
|
} else {
|
|
dev_err(ssusb->dev, "wrong or duplicated setting\n");
|
|
return -EINVAL;
|
|
}
|
|
|
|
return count;
|
|
}
|
|
|
|
static const struct file_operations ssusb_mode_fops = {
|
|
.open = ssusb_mode_open,
|
|
.write = ssusb_mode_write,
|
|
.read = seq_read,
|
|
.llseek = seq_lseek,
|
|
.release = single_release,
|
|
};
|
|
|
|
static int ssusb_vbus_show(struct seq_file *sf, void *unused)
|
|
{
|
|
struct ssusb_mtk *ssusb = sf->private;
|
|
struct otg_switch_mtk *otg_sx = &ssusb->otg_switch;
|
|
|
|
seq_printf(sf, "vbus state: %s\n(echo on/off)\n",
|
|
str_on_off(regulator_is_enabled(otg_sx->vbus)));
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int ssusb_vbus_open(struct inode *inode, struct file *file)
|
|
{
|
|
return single_open(file, ssusb_vbus_show, inode->i_private);
|
|
}
|
|
|
|
static ssize_t ssusb_vbus_write(struct file *file, const char __user *ubuf,
|
|
size_t count, loff_t *ppos)
|
|
{
|
|
struct seq_file *sf = file->private_data;
|
|
struct ssusb_mtk *ssusb = sf->private;
|
|
struct otg_switch_mtk *otg_sx = &ssusb->otg_switch;
|
|
char buf[16];
|
|
bool enable;
|
|
|
|
if (copy_from_user(&buf, ubuf, min_t(size_t, sizeof(buf) - 1, count)))
|
|
return -EFAULT;
|
|
|
|
if (kstrtobool(buf, &enable)) {
|
|
dev_err(ssusb->dev, "wrong setting\n");
|
|
return -EINVAL;
|
|
}
|
|
|
|
ssusb_set_vbus(otg_sx, enable);
|
|
|
|
return count;
|
|
}
|
|
|
|
static const struct file_operations ssusb_vbus_fops = {
|
|
.open = ssusb_vbus_open,
|
|
.write = ssusb_vbus_write,
|
|
.read = seq_read,
|
|
.llseek = seq_lseek,
|
|
.release = single_release,
|
|
};
|
|
|
|
void ssusb_dr_debugfs_init(struct ssusb_mtk *ssusb)
|
|
{
|
|
struct dentry *root = ssusb->dbgfs_root;
|
|
|
|
debugfs_create_file("mode", 0644, root, ssusb, &ssusb_mode_fops);
|
|
debugfs_create_file("vbus", 0644, root, ssusb, &ssusb_vbus_fops);
|
|
}
|
|
|
|
void ssusb_debugfs_create_root(struct ssusb_mtk *ssusb)
|
|
{
|
|
ssusb->dbgfs_root =
|
|
debugfs_create_dir(dev_name(ssusb->dev), usb_debug_root);
|
|
}
|
|
|
|
void ssusb_debugfs_remove_root(struct ssusb_mtk *ssusb)
|
|
{
|
|
debugfs_remove_recursive(ssusb->dbgfs_root);
|
|
ssusb->dbgfs_root = NULL;
|
|
}
|