aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorHaavard Skinnemoen <haavard.skinnemoen@atmel.com>2008-07-24 08:18:57 -0400
committerPierre Ossman <drzeus@drzeus.cx>2008-07-26 19:26:16 -0400
commit6edd8ee60ac9b974bd6ec3b1bcb2aab02762fa8c (patch)
tree0f24dc879d9645935974489d152dd83815fcff68
parentc5d5e9c40fc6cabedd5fdc7441e6e9d37f5c9bba (diff)
mmc: Export internal host state through debugfs
When CONFIG_DEBUG_FS is set, create a few files under /sys/kernel/debug containing information about an mmc host's internal state. Currently, just a single file is created, "ios", which contains information about the current operating parameters for the bus (clock speed, bus width, etc.) Host drivers can add additional files and directories under the host's root directory by passing the debugfs_root field in struct mmc_host as the 'parent' parameter to debugfs_create_*. Signed-off-by: Haavard Skinnemoen <haavard.skinnemoen@atmel.com> Signed-off-by: Pierre Ossman <drzeus@drzeus.cx>
-rw-r--r--drivers/mmc/core/Makefile1
-rw-r--r--drivers/mmc/core/core.h4
-rw-r--r--drivers/mmc/core/debugfs.c164
-rw-r--r--drivers/mmc/core/host.c8
-rw-r--r--include/linux/mmc/host.h2
5 files changed, 179 insertions, 0 deletions
diff --git a/drivers/mmc/core/Makefile b/drivers/mmc/core/Makefile
index 19a1a254a0c5..889e5f898f6f 100644
--- a/drivers/mmc/core/Makefile
+++ b/drivers/mmc/core/Makefile
@@ -12,3 +12,4 @@ mmc_core-y := core.o bus.o host.o \
12 sdio.o sdio_ops.o sdio_bus.o \ 12 sdio.o sdio_ops.o sdio_bus.o \
13 sdio_cis.o sdio_io.o sdio_irq.o 13 sdio_cis.o sdio_io.o sdio_irq.o
14 14
15mmc_core-$(CONFIG_DEBUG_FS) += debugfs.o
diff --git a/drivers/mmc/core/core.h b/drivers/mmc/core/core.h
index cdb332b7dedc..745da9881aa7 100644
--- a/drivers/mmc/core/core.h
+++ b/drivers/mmc/core/core.h
@@ -52,5 +52,9 @@ int mmc_attach_sdio(struct mmc_host *host, u32 ocr);
52 52
53extern int use_spi_crc; 53extern int use_spi_crc;
54 54
55/* Debugfs information for hosts and cards */
56void mmc_add_host_debugfs(struct mmc_host *host);
57void mmc_remove_host_debugfs(struct mmc_host *host);
58
55#endif 59#endif
56 60
diff --git a/drivers/mmc/core/debugfs.c b/drivers/mmc/core/debugfs.c
new file mode 100644
index 000000000000..133c6e51f26b
--- /dev/null
+++ b/drivers/mmc/core/debugfs.c
@@ -0,0 +1,164 @@
1/*
2 * Debugfs support for hosts and cards
3 *
4 * Copyright (C) 2008 Atmel Corporation
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License version 2 as
8 * published by the Free Software Foundation.
9 */
10#include <linux/debugfs.h>
11#include <linux/fs.h>
12#include <linux/seq_file.h>
13#include <linux/stat.h>
14
15#include <linux/mmc/host.h>
16
17#include "core.h"
18
19/* The debugfs functions are optimized away when CONFIG_DEBUG_FS isn't set. */
20static int mmc_ios_show(struct seq_file *s, void *data)
21{
22 static const char *vdd_str[] = {
23 [8] = "2.0",
24 [9] = "2.1",
25 [10] = "2.2",
26 [11] = "2.3",
27 [12] = "2.4",
28 [13] = "2.5",
29 [14] = "2.6",
30 [15] = "2.7",
31 [16] = "2.8",
32 [17] = "2.9",
33 [18] = "3.0",
34 [19] = "3.1",
35 [20] = "3.2",
36 [21] = "3.3",
37 [22] = "3.4",
38 [23] = "3.5",
39 [24] = "3.6",
40 };
41 struct mmc_host *host = s->private;
42 struct mmc_ios *ios = &host->ios;
43 const char *str;
44
45 seq_printf(s, "clock:\t\t%u Hz\n", ios->clock);
46 seq_printf(s, "vdd:\t\t%u ", ios->vdd);
47 if ((1 << ios->vdd) & MMC_VDD_165_195)
48 seq_printf(s, "(1.65 - 1.95 V)\n");
49 else if (ios->vdd < (ARRAY_SIZE(vdd_str) - 1)
50 && vdd_str[ios->vdd] && vdd_str[ios->vdd + 1])
51 seq_printf(s, "(%s ~ %s V)\n", vdd_str[ios->vdd],
52 vdd_str[ios->vdd + 1]);
53 else
54 seq_printf(s, "(invalid)\n");
55
56 switch (ios->bus_mode) {
57 case MMC_BUSMODE_OPENDRAIN:
58 str = "open drain";
59 break;
60 case MMC_BUSMODE_PUSHPULL:
61 str = "push-pull";
62 break;
63 default:
64 str = "invalid";
65 break;
66 }
67 seq_printf(s, "bus mode:\t%u (%s)\n", ios->bus_mode, str);
68
69 switch (ios->chip_select) {
70 case MMC_CS_DONTCARE:
71 str = "don't care";
72 break;
73 case MMC_CS_HIGH:
74 str = "active high";
75 break;
76 case MMC_CS_LOW:
77 str = "active low";
78 break;
79 default:
80 str = "invalid";
81 break;
82 }
83 seq_printf(s, "chip select:\t%u (%s)\n", ios->chip_select, str);
84
85 switch (ios->power_mode) {
86 case MMC_POWER_OFF:
87 str = "off";
88 break;
89 case MMC_POWER_UP:
90 str = "up";
91 break;
92 case MMC_POWER_ON:
93 str = "on";
94 break;
95 default:
96 str = "invalid";
97 break;
98 }
99 seq_printf(s, "power mode:\t%u (%s)\n", ios->power_mode, str);
100 seq_printf(s, "bus width:\t%u (%u bits)\n",
101 ios->bus_width, 1 << ios->bus_width);
102
103 switch (ios->timing) {
104 case MMC_TIMING_LEGACY:
105 str = "legacy";
106 break;
107 case MMC_TIMING_MMC_HS:
108 str = "mmc high-speed";
109 break;
110 case MMC_TIMING_SD_HS:
111 str = "sd high-speed";
112 break;
113 default:
114 str = "invalid";
115 break;
116 }
117 seq_printf(s, "timing spec:\t%u (%s)\n", ios->timing, str);
118
119 return 0;
120}
121
122static int mmc_ios_open(struct inode *inode, struct file *file)
123{
124 return single_open(file, mmc_ios_show, inode->i_private);
125}
126
127static const struct file_operations mmc_ios_fops = {
128 .open = mmc_ios_open,
129 .read = seq_read,
130 .llseek = seq_lseek,
131 .release = single_release,
132};
133
134void mmc_add_host_debugfs(struct mmc_host *host)
135{
136 struct dentry *root;
137
138 root = debugfs_create_dir(mmc_hostname(host), NULL);
139 if (IS_ERR(root))
140 /* Don't complain -- debugfs just isn't enabled */
141 return;
142 if (!root)
143 /* Complain -- debugfs is enabled, but it failed to
144 * create the directory. */
145 goto err_root;
146
147 host->debugfs_root = root;
148
149 if (!debugfs_create_file("ios", S_IRUSR, root, host, &mmc_ios_fops))
150 goto err_ios;
151
152 return;
153
154err_ios:
155 debugfs_remove_recursive(root);
156 host->debugfs_root = NULL;
157err_root:
158 dev_err(&host->class_dev, "failed to initialize debugfs\n");
159}
160
161void mmc_remove_host_debugfs(struct mmc_host *host)
162{
163 debugfs_remove_recursive(host->debugfs_root);
164}
diff --git a/drivers/mmc/core/host.c b/drivers/mmc/core/host.c
index 1d795c5379b5..6da80fd4d974 100644
--- a/drivers/mmc/core/host.c
+++ b/drivers/mmc/core/host.c
@@ -127,6 +127,10 @@ int mmc_add_host(struct mmc_host *host)
127 if (err) 127 if (err)
128 return err; 128 return err;
129 129
130#ifdef CONFIG_DEBUG_FS
131 mmc_add_host_debugfs(host);
132#endif
133
130 mmc_start_host(host); 134 mmc_start_host(host);
131 135
132 return 0; 136 return 0;
@@ -146,6 +150,10 @@ void mmc_remove_host(struct mmc_host *host)
146{ 150{
147 mmc_stop_host(host); 151 mmc_stop_host(host);
148 152
153#ifdef CONFIG_DEBUG_FS
154 mmc_remove_host_debugfs(host);
155#endif
156
149 device_del(&host->class_dev); 157 device_del(&host->class_dev);
150 158
151 led_trigger_unregister_simple(host->led); 159 led_trigger_unregister_simple(host->led);
diff --git a/include/linux/mmc/host.h b/include/linux/mmc/host.h
index 10a2080086ca..9c288c909878 100644
--- a/include/linux/mmc/host.h
+++ b/include/linux/mmc/host.h
@@ -157,6 +157,8 @@ struct mmc_host {
157 struct led_trigger *led; /* activity led */ 157 struct led_trigger *led; /* activity led */
158#endif 158#endif
159 159
160 struct dentry *debugfs_root;
161
160 unsigned long private[0] ____cacheline_aligned; 162 unsigned long private[0] ____cacheline_aligned;
161}; 163};
162 164