aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/mmc/host/atmel-mci.c
diff options
context:
space:
mode:
authorHaavard Skinnemoen <haavard.skinnemoen@atmel.com>2008-07-27 07:54:08 -0400
committerHaavard Skinnemoen <haavard.skinnemoen@atmel.com>2008-07-27 07:54:08 -0400
commiteda3d8f5604860aae1bb9996bb5efc4213778369 (patch)
tree9d3887d2665bcc5f5abf200758794545c7b2c69b /drivers/mmc/host/atmel-mci.c
parent87a9f704658a40940e740b1d73d861667e9164d3 (diff)
parent8be1a6d6c77ab4532e4476fdb8177030ef48b52c (diff)
Merge commit 'upstream/master'
Diffstat (limited to 'drivers/mmc/host/atmel-mci.c')
-rw-r--r--drivers/mmc/host/atmel-mci.c189
1 files changed, 189 insertions, 0 deletions
diff --git a/drivers/mmc/host/atmel-mci.c b/drivers/mmc/host/atmel-mci.c
index c2f8aa840e82..82bbbe998169 100644
--- a/drivers/mmc/host/atmel-mci.c
+++ b/drivers/mmc/host/atmel-mci.c
@@ -9,6 +9,7 @@
9 */ 9 */
10#include <linux/blkdev.h> 10#include <linux/blkdev.h>
11#include <linux/clk.h> 11#include <linux/clk.h>
12#include <linux/debugfs.h>
12#include <linux/device.h> 13#include <linux/device.h>
13#include <linux/err.h> 14#include <linux/err.h>
14#include <linux/init.h> 15#include <linux/init.h>
@@ -17,6 +18,8 @@
17#include <linux/module.h> 18#include <linux/module.h>
18#include <linux/platform_device.h> 19#include <linux/platform_device.h>
19#include <linux/scatterlist.h> 20#include <linux/scatterlist.h>
21#include <linux/seq_file.h>
22#include <linux/stat.h>
20 23
21#include <linux/mmc/host.h> 24#include <linux/mmc/host.h>
22 25
@@ -89,6 +92,188 @@ struct atmel_mci {
89#define atmci_clear_pending(host, event) \ 92#define atmci_clear_pending(host, event) \
90 clear_bit(event, &host->pending_events) 93 clear_bit(event, &host->pending_events)
91 94
95/*
96 * The debugfs stuff below is mostly optimized away when
97 * CONFIG_DEBUG_FS is not set.
98 */
99static int atmci_req_show(struct seq_file *s, void *v)
100{
101 struct atmel_mci *host = s->private;
102 struct mmc_request *mrq = host->mrq;
103 struct mmc_command *cmd;
104 struct mmc_command *stop;
105 struct mmc_data *data;
106
107 /* Make sure we get a consistent snapshot */
108 spin_lock_irq(&host->mmc->lock);
109
110 if (mrq) {
111 cmd = mrq->cmd;
112 data = mrq->data;
113 stop = mrq->stop;
114
115 if (cmd)
116 seq_printf(s,
117 "CMD%u(0x%x) flg %x rsp %x %x %x %x err %d\n",
118 cmd->opcode, cmd->arg, cmd->flags,
119 cmd->resp[0], cmd->resp[1], cmd->resp[2],
120 cmd->resp[2], cmd->error);
121 if (data)
122 seq_printf(s, "DATA %u / %u * %u flg %x err %d\n",
123 data->bytes_xfered, data->blocks,
124 data->blksz, data->flags, data->error);
125 if (stop)
126 seq_printf(s,
127 "CMD%u(0x%x) flg %x rsp %x %x %x %x err %d\n",
128 stop->opcode, stop->arg, stop->flags,
129 stop->resp[0], stop->resp[1], stop->resp[2],
130 stop->resp[2], stop->error);
131 }
132
133 spin_unlock_irq(&host->mmc->lock);
134
135 return 0;
136}
137
138static int atmci_req_open(struct inode *inode, struct file *file)
139{
140 return single_open(file, atmci_req_show, inode->i_private);
141}
142
143static const struct file_operations atmci_req_fops = {
144 .owner = THIS_MODULE,
145 .open = atmci_req_open,
146 .read = seq_read,
147 .llseek = seq_lseek,
148 .release = single_release,
149};
150
151static void atmci_show_status_reg(struct seq_file *s,
152 const char *regname, u32 value)
153{
154 static const char *sr_bit[] = {
155 [0] = "CMDRDY",
156 [1] = "RXRDY",
157 [2] = "TXRDY",
158 [3] = "BLKE",
159 [4] = "DTIP",
160 [5] = "NOTBUSY",
161 [8] = "SDIOIRQA",
162 [9] = "SDIOIRQB",
163 [16] = "RINDE",
164 [17] = "RDIRE",
165 [18] = "RCRCE",
166 [19] = "RENDE",
167 [20] = "RTOE",
168 [21] = "DCRCE",
169 [22] = "DTOE",
170 [30] = "OVRE",
171 [31] = "UNRE",
172 };
173 unsigned int i;
174
175 seq_printf(s, "%s:\t0x%08x", regname, value);
176 for (i = 0; i < ARRAY_SIZE(sr_bit); i++) {
177 if (value & (1 << i)) {
178 if (sr_bit[i])
179 seq_printf(s, " %s", sr_bit[i]);
180 else
181 seq_puts(s, " UNKNOWN");
182 }
183 }
184 seq_putc(s, '\n');
185}
186
187static int atmci_regs_show(struct seq_file *s, void *v)
188{
189 struct atmel_mci *host = s->private;
190 u32 *buf;
191
192 buf = kmalloc(MCI_REGS_SIZE, GFP_KERNEL);
193 if (!buf)
194 return -ENOMEM;
195
196 /* Grab a more or less consistent snapshot */
197 spin_lock_irq(&host->mmc->lock);
198 memcpy_fromio(buf, host->regs, MCI_REGS_SIZE);
199 spin_unlock_irq(&host->mmc->lock);
200
201 seq_printf(s, "MR:\t0x%08x%s%s CLKDIV=%u\n",
202 buf[MCI_MR / 4],
203 buf[MCI_MR / 4] & MCI_MR_RDPROOF ? " RDPROOF" : "",
204 buf[MCI_MR / 4] & MCI_MR_WRPROOF ? " WRPROOF" : "",
205 buf[MCI_MR / 4] & 0xff);
206 seq_printf(s, "DTOR:\t0x%08x\n", buf[MCI_DTOR / 4]);
207 seq_printf(s, "SDCR:\t0x%08x\n", buf[MCI_SDCR / 4]);
208 seq_printf(s, "ARGR:\t0x%08x\n", buf[MCI_ARGR / 4]);
209 seq_printf(s, "BLKR:\t0x%08x BCNT=%u BLKLEN=%u\n",
210 buf[MCI_BLKR / 4],
211 buf[MCI_BLKR / 4] & 0xffff,
212 (buf[MCI_BLKR / 4] >> 16) & 0xffff);
213
214 /* Don't read RSPR and RDR; it will consume the data there */
215
216 atmci_show_status_reg(s, "SR", buf[MCI_SR / 4]);
217 atmci_show_status_reg(s, "IMR", buf[MCI_IMR / 4]);
218
219 return 0;
220}
221
222static int atmci_regs_open(struct inode *inode, struct file *file)
223{
224 return single_open(file, atmci_regs_show, inode->i_private);
225}
226
227static const struct file_operations atmci_regs_fops = {
228 .owner = THIS_MODULE,
229 .open = atmci_regs_open,
230 .read = seq_read,
231 .llseek = seq_lseek,
232 .release = single_release,
233};
234
235static void atmci_init_debugfs(struct atmel_mci *host)
236{
237 struct mmc_host *mmc;
238 struct dentry *root;
239 struct dentry *node;
240 struct resource *res;
241
242 mmc = host->mmc;
243 root = mmc->debugfs_root;
244 if (!root)
245 return;
246
247 node = debugfs_create_file("regs", S_IRUSR, root, host,
248 &atmci_regs_fops);
249 if (IS_ERR(node))
250 return;
251 if (!node)
252 goto err;
253
254 res = platform_get_resource(host->pdev, IORESOURCE_MEM, 0);
255 node->d_inode->i_size = res->end - res->start + 1;
256
257 node = debugfs_create_file("req", S_IRUSR, root, host, &atmci_req_fops);
258 if (!node)
259 goto err;
260
261 node = debugfs_create_x32("pending_events", S_IRUSR, root,
262 (u32 *)&host->pending_events);
263 if (!node)
264 goto err;
265
266 node = debugfs_create_x32("completed_events", S_IRUSR, root,
267 (u32 *)&host->completed_events);
268 if (!node)
269 goto err;
270
271 return;
272
273err:
274 dev_err(&host->pdev->dev,
275 "failed to initialize debugfs for controller\n");
276}
92 277
93static void atmci_enable(struct atmel_mci *host) 278static void atmci_enable(struct atmel_mci *host)
94{ 279{
@@ -906,6 +1091,8 @@ static int __init atmci_probe(struct platform_device *pdev)
906 "Atmel MCI controller at 0x%08lx irq %d\n", 1091 "Atmel MCI controller at 0x%08lx irq %d\n",
907 host->mapbase, irq); 1092 host->mapbase, irq);
908 1093
1094 atmci_init_debugfs(host);
1095
909 return 0; 1096 return 0;
910 1097
911err_request_irq: 1098err_request_irq:
@@ -924,6 +1111,8 @@ static int __exit atmci_remove(struct platform_device *pdev)
924 platform_set_drvdata(pdev, NULL); 1111 platform_set_drvdata(pdev, NULL);
925 1112
926 if (host) { 1113 if (host) {
1114 /* Debugfs stuff is cleaned up by mmc core */
1115
927 if (host->detect_pin >= 0) { 1116 if (host->detect_pin >= 0) {
928 int pin = host->detect_pin; 1117 int pin = host->detect_pin;
929 1118