upload tizen1.0 source
[kernel/linux-2.6.36.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 void mmc_add_host_debugfs(struct mmc_host *host)
138 {
139         struct dentry *root;
140
141         root = debugfs_create_dir(mmc_hostname(host), NULL);
142         if (IS_ERR(root))
143                 /* Don't complain -- debugfs just isn't enabled */
144                 return;
145         if (!root)
146                 /* Complain -- debugfs is enabled, but it failed to
147                  * create the directory. */
148                 goto err_root;
149
150         host->debugfs_root = root;
151
152         if (!debugfs_create_file("ios", S_IRUSR, root, host, &mmc_ios_fops))
153                 goto err_ios;
154
155 #ifdef CONFIG_MMC_CLKGATE
156         if (!debugfs_create_u32("clk_delay", (S_IRUSR | S_IWUSR),
157                                 root, &host->clk_delay))
158                 goto err_ios;
159 #endif
160         return;
161
162 err_ios:
163         debugfs_remove_recursive(root);
164         host->debugfs_root = NULL;
165 err_root:
166         dev_err(&host->class_dev, "failed to initialize debugfs\n");
167 }
168
169 void mmc_remove_host_debugfs(struct mmc_host *host)
170 {
171         debugfs_remove_recursive(host->debugfs_root);
172 }
173
174 static int mmc_dbg_card_status_get(void *data, u64 *val)
175 {
176         struct mmc_card *card = data;
177         u32             status;
178         int             ret;
179
180         mmc_claim_host(card->host);
181
182         ret = mmc_send_status(data, &status);
183         if (!ret)
184                 *val = status;
185
186         mmc_release_host(card->host);
187
188         return ret;
189 }
190 DEFINE_SIMPLE_ATTRIBUTE(mmc_dbg_card_status_fops, mmc_dbg_card_status_get,
191                 NULL, "%08llx\n");
192
193 #define EXT_CSD_STR_LEN 1025
194
195 static int mmc_ext_csd_open(struct inode *inode, struct file *filp)
196 {
197         struct mmc_card *card = inode->i_private;
198         char *buf;
199         ssize_t n = 0;
200         u8 *ext_csd;
201         int err, i;
202
203         buf = kmalloc(EXT_CSD_STR_LEN + 1, GFP_KERNEL);
204         if (!buf)
205                 return -ENOMEM;
206
207         ext_csd = kmalloc(512, GFP_KERNEL);
208         if (!ext_csd) {
209                 err = -ENOMEM;
210                 goto out_free;
211         }
212
213         mmc_claim_host(card->host);
214         err = mmc_send_ext_csd(card, ext_csd);
215         mmc_release_host(card->host);
216         if (err)
217                 goto out_free;
218
219         for (i = 511; i >= 0; i--)
220                 n += sprintf(buf + n, "%02x", ext_csd[i]);
221         n += sprintf(buf + n, "\n");
222         BUG_ON(n != EXT_CSD_STR_LEN);
223
224         filp->private_data = buf;
225         kfree(ext_csd);
226         return 0;
227
228 out_free:
229         kfree(buf);
230         kfree(ext_csd);
231         return err;
232 }
233
234 static ssize_t mmc_ext_csd_read(struct file *filp, char __user *ubuf,
235                                 size_t cnt, loff_t *ppos)
236 {
237         char *buf = filp->private_data;
238
239         return simple_read_from_buffer(ubuf, cnt, ppos,
240                                        buf, EXT_CSD_STR_LEN);
241 }
242
243 static int mmc_ext_csd_release(struct inode *inode, struct file *file)
244 {
245         kfree(file->private_data);
246         return 0;
247 }
248
249 static const struct file_operations mmc_dbg_ext_csd_fops = {
250         .open           = mmc_ext_csd_open,
251         .read           = mmc_ext_csd_read,
252         .release        = mmc_ext_csd_release,
253 };
254
255 void mmc_add_card_debugfs(struct mmc_card *card)
256 {
257         struct mmc_host *host = card->host;
258         struct dentry   *root;
259
260         if (!host->debugfs_root)
261                 return;
262
263         root = debugfs_create_dir(mmc_card_id(card), host->debugfs_root);
264         if (IS_ERR(root))
265                 /* Don't complain -- debugfs just isn't enabled */
266                 return;
267         if (!root)
268                 /* Complain -- debugfs is enabled, but it failed to
269                  * create the directory. */
270                 goto err;
271
272         card->debugfs_root = root;
273
274         if (!debugfs_create_x32("state", S_IRUSR, root, &card->state))
275                 goto err;
276
277         if (mmc_card_mmc(card) || mmc_card_sd(card))
278                 if (!debugfs_create_file("status", S_IRUSR, root, card,
279                                         &mmc_dbg_card_status_fops))
280                         goto err;
281
282         if (mmc_card_mmc(card))
283                 if (!debugfs_create_file("ext_csd", S_IRUSR, root, card,
284                                         &mmc_dbg_ext_csd_fops))
285                         goto err;
286
287         return;
288
289 err:
290         debugfs_remove_recursive(root);
291         card->debugfs_root = NULL;
292         dev_err(&card->dev, "failed to initialize debugfs\n");
293 }
294
295 void mmc_remove_card_debugfs(struct mmc_card *card)
296 {
297         debugfs_remove_recursive(card->debugfs_root);
298 }