Skip to content

Commit

Permalink
s3cmci: add debugfs support for examining driver and hardware state
Browse files Browse the repository at this point in the history
Export driver state and hardware register state via debugfs entries
created under a directory formed from dev_name() on the probed device when
CONFIG_DEBUG_FS is set.

Signed-off-by: Ben Dooks <ben@simtec.co.uk>
Cc: <linux-mmc@vger.kernel.org>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
  • Loading branch information
Ben Dooks authored and Linus Torvalds committed Oct 1, 2009
1 parent e6130ae commit 9bdd203
Show file tree
Hide file tree
Showing 2 changed files with 132 additions and 0 deletions.
126 changes: 126 additions & 0 deletions drivers/mmc/host/s3cmci.c
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,8 @@
#include <linux/mmc/host.h>
#include <linux/platform_device.h>
#include <linux/cpufreq.h>
#include <linux/debugfs.h>
#include <linux/seq_file.h>
#include <linux/gpio.h>
#include <linux/irq.h>
#include <linux/io.h>
Expand Down Expand Up @@ -1244,6 +1246,127 @@ static inline void s3cmci_cpufreq_deregister(struct s3cmci_host *host)
#endif


#ifdef CONFIG_DEBUG_FS

static int s3cmci_state_show(struct seq_file *seq, void *v)
{
struct s3cmci_host *host = seq->private;

seq_printf(seq, "Register base = 0x%08x\n", (u32)host->base);
seq_printf(seq, "Clock rate = %ld\n", host->clk_rate);
seq_printf(seq, "Prescale = %d\n", host->prescaler);
seq_printf(seq, "is2440 = %d\n", host->is2440);
seq_printf(seq, "IRQ = %d\n", host->irq);
seq_printf(seq, "CD IRQ = %d\n", host->irq_cd);
seq_printf(seq, "Do DMA = %d\n", host->dodma);
seq_printf(seq, "SDIIMSK at %d\n", host->sdiimsk);
seq_printf(seq, "SDIDATA at %d\n", host->sdidata);

return 0;
}

static int s3cmci_state_open(struct inode *inode, struct file *file)
{
return single_open(file, s3cmci_state_show, inode->i_private);
}

static const struct file_operations s3cmci_fops_state = {
.owner = THIS_MODULE,
.open = s3cmci_state_open,
.read = seq_read,
.llseek = seq_lseek,
.release = single_release,
};

#define DBG_REG(_r) { .addr = S3C2410_SDI##_r, .name = #_r }

struct s3cmci_reg {
unsigned short addr;
unsigned char *name;
} debug_regs[] = {
DBG_REG(CON),
DBG_REG(PRE),
DBG_REG(CMDARG),
DBG_REG(CMDCON),
DBG_REG(CMDSTAT),
DBG_REG(RSP0),
DBG_REG(RSP1),
DBG_REG(RSP2),
DBG_REG(RSP3),
DBG_REG(TIMER),
DBG_REG(BSIZE),
DBG_REG(DCON),
DBG_REG(DCNT),
DBG_REG(DSTA),
DBG_REG(FSTA),
{}
};

static int s3cmci_regs_show(struct seq_file *seq, void *v)
{
struct s3cmci_host *host = seq->private;
struct s3cmci_reg *rptr = debug_regs;

for (; rptr->name; rptr++)
seq_printf(seq, "SDI%s\t=0x%08x\n", rptr->name,
readl(host->base + rptr->addr));

seq_printf(seq, "SDIIMSK\t=0x%08x\n", readl(host->base + host->sdiimsk));

return 0;
}

static int s3cmci_regs_open(struct inode *inode, struct file *file)
{
return single_open(file, s3cmci_regs_show, inode->i_private);
}

static const struct file_operations s3cmci_fops_regs = {
.owner = THIS_MODULE,
.open = s3cmci_regs_open,
.read = seq_read,
.llseek = seq_lseek,
.release = single_release,
};

static void s3cmci_debugfs_attach(struct s3cmci_host *host)
{
struct device *dev = &host->pdev->dev;

host->debug_root = debugfs_create_dir(dev_name(dev), NULL);
if (IS_ERR(host->debug_root)) {
dev_err(dev, "failed to create debugfs root\n");
return;
}

host->debug_state = debugfs_create_file("state", 0444,
host->debug_root, host,
&s3cmci_fops_state);

if (IS_ERR(host->debug_state))
dev_err(dev, "failed to create debug state file\n");

host->debug_regs = debugfs_create_file("regs", 0444,
host->debug_root, host,
&s3cmci_fops_regs);

if (IS_ERR(host->debug_regs))
dev_err(dev, "failed to create debug regs file\n");
}

static void s3cmci_debugfs_remove(struct s3cmci_host *host)
{
debugfs_remove(host->debug_regs);
debugfs_remove(host->debug_state);
debugfs_remove(host->debug_root);
}

#else
static inline void s3cmci_debugfs_attach(struct s3cmci_host *host) { }
static inline void s3cmci_debugfs_remove(struct s3cmci_host *host) { }

#endif /* CONFIG_DEBUG_FS */

static int __devinit s3cmci_probe(struct platform_device *pdev)
{
struct s3cmci_host *host;
Expand Down Expand Up @@ -1435,6 +1558,8 @@ static int __devinit s3cmci_probe(struct platform_device *pdev)
goto free_cpufreq;
}

s3cmci_debugfs_attach(host);

platform_set_drvdata(pdev, mmc);
dev_info(&pdev->dev, "initialisation done.\n");

Expand Down Expand Up @@ -1489,6 +1614,7 @@ static void s3cmci_shutdown(struct platform_device *pdev)
if (host->irq_cd >= 0)
free_irq(host->irq_cd, host);

s3cmci_debugfs_remove(host);
s3cmci_cpufreq_deregister(host);
mmc_remove_host(mmc);
clk_disable(host->clk);
Expand Down
6 changes: 6 additions & 0 deletions drivers/mmc/host/s3cmci.h
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,12 @@ struct s3cmci_host {
unsigned int ccnt, dcnt;
struct tasklet_struct pio_tasklet;

#ifdef CONFIG_DEBUG_FS
struct dentry *debug_root;
struct dentry *debug_state;
struct dentry *debug_regs;
#endif

#ifdef CONFIG_CPU_FREQ
struct notifier_block freq_transition;
#endif
Expand Down

0 comments on commit 9bdd203

Please sign in to comment.