]> git.karo-electronics.de Git - mv-sheeva.git/blob - drivers/mmc/core/debugfs.c
998797ed67a6d0f49802985c31d70b8f4cef0be8
[mv-sheeva.git] / drivers / mmc / core / debugfs.c
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/slab.h>
14 #include <linux/stat.h>
15
16 #include <linux/mmc/card.h>
17 #include <linux/mmc/host.h>
18
19 #include "core.h"
20 #include "mmc_ops.h"
21
22 /* The debugfs functions are optimized away when CONFIG_DEBUG_FS isn't set. */
23 static int mmc_ios_show(struct seq_file *s, void *data)
24 {
25         static const char *vdd_str[] = {
26                 [8]     = "2.0",
27                 [9]     = "2.1",
28                 [10]    = "2.2",
29                 [11]    = "2.3",
30                 [12]    = "2.4",
31                 [13]    = "2.5",
32                 [14]    = "2.6",
33                 [15]    = "2.7",
34                 [16]    = "2.8",
35                 [17]    = "2.9",
36                 [18]    = "3.0",
37                 [19]    = "3.1",
38                 [20]    = "3.2",
39                 [21]    = "3.3",
40                 [22]    = "3.4",
41                 [23]    = "3.5",
42                 [24]    = "3.6",
43         };
44         struct mmc_host *host = s->private;
45         struct mmc_ios  *ios = &host->ios;
46         const char *str;
47
48         seq_printf(s, "clock:\t\t%u Hz\n", ios->clock);
49         seq_printf(s, "vdd:\t\t%u ", ios->vdd);
50         if ((1 << ios->vdd) & MMC_VDD_165_195)
51                 seq_printf(s, "(1.65 - 1.95 V)\n");
52         else if (ios->vdd < (ARRAY_SIZE(vdd_str) - 1)
53                         && vdd_str[ios->vdd] && vdd_str[ios->vdd + 1])
54                 seq_printf(s, "(%s ~ %s V)\n", vdd_str[ios->vdd],
55                                 vdd_str[ios->vdd + 1]);
56         else
57                 seq_printf(s, "(invalid)\n");
58
59         switch (ios->bus_mode) {
60         case MMC_BUSMODE_OPENDRAIN:
61                 str = "open drain";
62                 break;
63         case MMC_BUSMODE_PUSHPULL:
64                 str = "push-pull";
65                 break;
66         default:
67                 str = "invalid";
68                 break;
69         }
70         seq_printf(s, "bus mode:\t%u (%s)\n", ios->bus_mode, str);
71
72         switch (ios->chip_select) {
73         case MMC_CS_DONTCARE:
74                 str = "don't care";
75                 break;
76         case MMC_CS_HIGH:
77                 str = "active high";
78                 break;
79         case MMC_CS_LOW:
80                 str = "active low";
81                 break;
82         default:
83                 str = "invalid";
84                 break;
85         }
86         seq_printf(s, "chip select:\t%u (%s)\n", ios->chip_select, str);
87
88         switch (ios->power_mode) {
89         case MMC_POWER_OFF:
90                 str = "off";
91                 break;
92         case MMC_POWER_UP:
93                 str = "up";
94                 break;
95         case MMC_POWER_ON:
96                 str = "on";
97                 break;
98         default:
99                 str = "invalid";
100                 break;
101         }
102         seq_printf(s, "power mode:\t%u (%s)\n", ios->power_mode, str);
103         seq_printf(s, "bus width:\t%u (%u bits)\n",
104                         ios->bus_width, 1 << ios->bus_width);
105
106         switch (ios->timing) {
107         case MMC_TIMING_LEGACY:
108                 str = "legacy";
109                 break;
110         case MMC_TIMING_MMC_HS:
111                 str = "mmc high-speed";
112                 break;
113         case MMC_TIMING_SD_HS:
114                 str = "sd high-speed";
115                 break;
116         default:
117                 str = "invalid";
118                 break;
119         }
120         seq_printf(s, "timing spec:\t%u (%s)\n", ios->timing, str);
121
122         return 0;
123 }
124
125 static int mmc_ios_open(struct inode *inode, struct file *file)
126 {
127         return single_open(file, mmc_ios_show, inode->i_private);
128 }
129
130 static const struct file_operations mmc_ios_fops = {
131         .open           = mmc_ios_open,
132         .read           = seq_read,
133         .llseek         = seq_lseek,
134         .release        = single_release,
135 };
136
137 static int mmc_clock_opt_get(void *data, u64 *val)
138 {
139         struct mmc_host *host = data;
140
141         *val = host->ios.clock;
142
143         return 0;
144 }
145
146 static int mmc_clock_opt_set(void *data, u64 val)
147 {
148         struct mmc_host *host = data;
149
150         /* We need this check due to input value is u64 */
151         if (val > host->f_max)
152                 return -EINVAL;
153
154         mmc_claim_host(host);
155         mmc_set_clock(host, (unsigned int) val);
156         mmc_release_host(host);
157
158         return 0;
159 }
160
161 DEFINE_SIMPLE_ATTRIBUTE(mmc_clock_fops, mmc_clock_opt_get, mmc_clock_opt_set,
162         "%llu\n");
163
164 void mmc_add_host_debugfs(struct mmc_host *host)
165 {
166         struct dentry *root;
167
168         root = debugfs_create_dir(mmc_hostname(host), NULL);
169         if (IS_ERR(root))
170                 /* Don't complain -- debugfs just isn't enabled */
171                 return;
172         if (!root)
173                 /* Complain -- debugfs is enabled, but it failed to
174                  * create the directory. */
175                 goto err_root;
176
177         host->debugfs_root = root;
178
179         if (!debugfs_create_file("ios", S_IRUSR, root, host, &mmc_ios_fops))
180                 goto err_node;
181
182         if (!debugfs_create_file("clock", S_IRUSR | S_IWUSR, root, host,
183                         &mmc_clock_fops))
184                 goto err_node;
185
186 #ifdef CONFIG_MMC_CLKGATE
187         if (!debugfs_create_u32("clk_delay", (S_IRUSR | S_IWUSR),
188                                 root, &host->clk_delay))
189                 goto err_node;
190 #endif
191         return;
192
193 err_node:
194         debugfs_remove_recursive(root);
195         host->debugfs_root = NULL;
196 err_root:
197         dev_err(&host->class_dev, "failed to initialize debugfs\n");
198 }
199
200 void mmc_remove_host_debugfs(struct mmc_host *host)
201 {
202         debugfs_remove_recursive(host->debugfs_root);
203 }
204
205 static int mmc_dbg_card_status_get(void *data, u64 *val)
206 {
207         struct mmc_card *card = data;
208         u32             status;
209         int             ret;
210
211         mmc_claim_host(card->host);
212
213         ret = mmc_send_status(data, &status);
214         if (!ret)
215                 *val = status;
216
217         mmc_release_host(card->host);
218
219         return ret;
220 }
221 DEFINE_SIMPLE_ATTRIBUTE(mmc_dbg_card_status_fops, mmc_dbg_card_status_get,
222                 NULL, "%08llx\n");
223
224 #define EXT_CSD_STR_LEN 1025
225
226 static int mmc_ext_csd_open(struct inode *inode, struct file *filp)
227 {
228         struct mmc_card *card = inode->i_private;
229         char *buf;
230         ssize_t n = 0;
231         u8 *ext_csd;
232         int err, i;
233
234         buf = kmalloc(EXT_CSD_STR_LEN + 1, GFP_KERNEL);
235         if (!buf)
236                 return -ENOMEM;
237
238         ext_csd = kmalloc(512, GFP_KERNEL);
239         if (!ext_csd) {
240                 err = -ENOMEM;
241                 goto out_free;
242         }
243
244         mmc_claim_host(card->host);
245         err = mmc_send_ext_csd(card, ext_csd);
246         mmc_release_host(card->host);
247         if (err)
248                 goto out_free;
249
250         for (i = 511; i >= 0; i--)
251                 n += sprintf(buf + n, "%02x", ext_csd[i]);
252         n += sprintf(buf + n, "\n");
253         BUG_ON(n != EXT_CSD_STR_LEN);
254
255         filp->private_data = buf;
256         kfree(ext_csd);
257         return 0;
258
259 out_free:
260         kfree(buf);
261         kfree(ext_csd);
262         return err;
263 }
264
265 static ssize_t mmc_ext_csd_read(struct file *filp, char __user *ubuf,
266                                 size_t cnt, loff_t *ppos)
267 {
268         char *buf = filp->private_data;
269
270         return simple_read_from_buffer(ubuf, cnt, ppos,
271                                        buf, EXT_CSD_STR_LEN);
272 }
273
274 static int mmc_ext_csd_release(struct inode *inode, struct file *file)
275 {
276         kfree(file->private_data);
277         return 0;
278 }
279
280 static const struct file_operations mmc_dbg_ext_csd_fops = {
281         .open           = mmc_ext_csd_open,
282         .read           = mmc_ext_csd_read,
283         .release        = mmc_ext_csd_release,
284         .llseek         = default_llseek,
285 };
286
287 void mmc_add_card_debugfs(struct mmc_card *card)
288 {
289         struct mmc_host *host = card->host;
290         struct dentry   *root;
291
292         if (!host->debugfs_root)
293                 return;
294
295         root = debugfs_create_dir(mmc_card_id(card), host->debugfs_root);
296         if (IS_ERR(root))
297                 /* Don't complain -- debugfs just isn't enabled */
298                 return;
299         if (!root)
300                 /* Complain -- debugfs is enabled, but it failed to
301                  * create the directory. */
302                 goto err;
303
304         card->debugfs_root = root;
305
306         if (!debugfs_create_x32("state", S_IRUSR, root, &card->state))
307                 goto err;
308
309         if (mmc_card_mmc(card) || mmc_card_sd(card))
310                 if (!debugfs_create_file("status", S_IRUSR, root, card,
311                                         &mmc_dbg_card_status_fops))
312                         goto err;
313
314         if (mmc_card_mmc(card))
315                 if (!debugfs_create_file("ext_csd", S_IRUSR, root, card,
316                                         &mmc_dbg_ext_csd_fops))
317                         goto err;
318
319         return;
320
321 err:
322         debugfs_remove_recursive(root);
323         card->debugfs_root = NULL;
324         dev_err(&card->dev, "failed to initialize debugfs\n");
325 }
326
327 void mmc_remove_card_debugfs(struct mmc_card *card)
328 {
329         debugfs_remove_recursive(card->debugfs_root);
330 }