2 * Debugfs support for hosts and cards
4 * Copyright (C) 2008 Atmel Corporation
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.
10 #include <linux/moduleparam.h>
11 #include <linux/export.h>
12 #include <linux/debugfs.h>
14 #include <linux/seq_file.h>
15 #include <linux/slab.h>
16 #include <linux/stat.h>
17 #include <linux/fault-inject.h>
19 #include <linux/mmc/card.h>
20 #include <linux/mmc/host.h>
27 #ifdef CONFIG_FAIL_MMC_REQUEST
29 static DECLARE_FAULT_ATTR(fail_default_attr
);
30 static char *fail_request
;
31 module_param(fail_request
, charp
, 0);
33 #endif /* CONFIG_FAIL_MMC_REQUEST */
35 /* The debugfs functions are optimized away when CONFIG_DEBUG_FS isn't set. */
36 static int mmc_ios_show(struct seq_file
*s
, void *data
)
38 static const char *vdd_str
[] = {
57 struct mmc_host
*host
= s
->private;
58 struct mmc_ios
*ios
= &host
->ios
;
61 seq_printf(s
, "clock:\t\t%u Hz\n", ios
->clock
);
62 if (host
->actual_clock
)
63 seq_printf(s
, "actual clock:\t%u Hz\n", host
->actual_clock
);
64 seq_printf(s
, "vdd:\t\t%u ", ios
->vdd
);
65 if ((1 << ios
->vdd
) & MMC_VDD_165_195
)
66 seq_printf(s
, "(1.65 - 1.95 V)\n");
67 else if (ios
->vdd
< (ARRAY_SIZE(vdd_str
) - 1)
68 && vdd_str
[ios
->vdd
] && vdd_str
[ios
->vdd
+ 1])
69 seq_printf(s
, "(%s ~ %s V)\n", vdd_str
[ios
->vdd
],
70 vdd_str
[ios
->vdd
+ 1]);
72 seq_printf(s
, "(invalid)\n");
74 switch (ios
->bus_mode
) {
75 case MMC_BUSMODE_OPENDRAIN
:
78 case MMC_BUSMODE_PUSHPULL
:
85 seq_printf(s
, "bus mode:\t%u (%s)\n", ios
->bus_mode
, str
);
87 switch (ios
->chip_select
) {
101 seq_printf(s
, "chip select:\t%u (%s)\n", ios
->chip_select
, str
);
103 switch (ios
->power_mode
) {
117 seq_printf(s
, "power mode:\t%u (%s)\n", ios
->power_mode
, str
);
118 seq_printf(s
, "bus width:\t%u (%u bits)\n",
119 ios
->bus_width
, 1 << ios
->bus_width
);
121 switch (ios
->timing
) {
122 case MMC_TIMING_LEGACY
:
125 case MMC_TIMING_MMC_HS
:
126 str
= "mmc high-speed";
128 case MMC_TIMING_SD_HS
:
129 str
= "sd high-speed";
131 case MMC_TIMING_UHS_SDR12
:
132 str
= "sd uhs SDR12";
134 case MMC_TIMING_UHS_SDR25
:
135 str
= "sd uhs SDR25";
137 case MMC_TIMING_UHS_SDR50
:
138 str
= "sd uhs SDR50";
140 case MMC_TIMING_UHS_SDR104
:
141 str
= "sd uhs SDR104";
143 case MMC_TIMING_UHS_DDR50
:
144 str
= "sd uhs DDR50";
146 case MMC_TIMING_MMC_DDR52
:
149 case MMC_TIMING_MMC_HS200
:
152 case MMC_TIMING_MMC_HS400
:
153 str
= mmc_card_hs400es(host
->card
) ?
154 "mmc HS400 enhanced strobe" : "mmc HS400";
160 seq_printf(s
, "timing spec:\t%u (%s)\n", ios
->timing
, str
);
162 switch (ios
->signal_voltage
) {
163 case MMC_SIGNAL_VOLTAGE_330
:
166 case MMC_SIGNAL_VOLTAGE_180
:
169 case MMC_SIGNAL_VOLTAGE_120
:
176 seq_printf(s
, "signal voltage:\t%u (%s)\n", ios
->signal_voltage
, str
);
178 switch (ios
->drv_type
) {
179 case MMC_SET_DRIVER_TYPE_A
:
180 str
= "driver type A";
182 case MMC_SET_DRIVER_TYPE_B
:
183 str
= "driver type B";
185 case MMC_SET_DRIVER_TYPE_C
:
186 str
= "driver type C";
188 case MMC_SET_DRIVER_TYPE_D
:
189 str
= "driver type D";
195 seq_printf(s
, "driver type:\t%u (%s)\n", ios
->drv_type
, str
);
200 static int mmc_ios_open(struct inode
*inode
, struct file
*file
)
202 return single_open(file
, mmc_ios_show
, inode
->i_private
);
205 static const struct file_operations mmc_ios_fops
= {
206 .open
= mmc_ios_open
,
209 .release
= single_release
,
212 static int mmc_clock_opt_get(void *data
, u64
*val
)
214 struct mmc_host
*host
= data
;
216 *val
= host
->ios
.clock
;
221 static int mmc_clock_opt_set(void *data
, u64 val
)
223 struct mmc_host
*host
= data
;
225 /* We need this check due to input value is u64 */
226 if (val
!= 0 && (val
> host
->f_max
|| val
< host
->f_min
))
229 mmc_claim_host(host
);
230 mmc_set_clock(host
, (unsigned int) val
);
231 mmc_release_host(host
);
236 DEFINE_SIMPLE_ATTRIBUTE(mmc_clock_fops
, mmc_clock_opt_get
, mmc_clock_opt_set
,
239 void mmc_add_host_debugfs(struct mmc_host
*host
)
243 root
= debugfs_create_dir(mmc_hostname(host
), NULL
);
245 /* Don't complain -- debugfs just isn't enabled */
248 /* Complain -- debugfs is enabled, but it failed to
249 * create the directory. */
252 host
->debugfs_root
= root
;
254 if (!debugfs_create_file("ios", S_IRUSR
, root
, host
, &mmc_ios_fops
))
257 if (!debugfs_create_file("clock", S_IRUSR
| S_IWUSR
, root
, host
,
261 #ifdef CONFIG_FAIL_MMC_REQUEST
263 setup_fault_attr(&fail_default_attr
, fail_request
);
264 host
->fail_mmc_request
= fail_default_attr
;
265 if (IS_ERR(fault_create_debugfs_attr("fail_mmc_request",
267 &host
->fail_mmc_request
)))
273 debugfs_remove_recursive(root
);
274 host
->debugfs_root
= NULL
;
276 dev_err(&host
->class_dev
, "failed to initialize debugfs\n");
279 void mmc_remove_host_debugfs(struct mmc_host
*host
)
281 debugfs_remove_recursive(host
->debugfs_root
);
284 static int mmc_dbg_card_status_get(void *data
, u64
*val
)
286 struct mmc_card
*card
= data
;
292 ret
= mmc_send_status(data
, &status
);
300 DEFINE_SIMPLE_ATTRIBUTE(mmc_dbg_card_status_fops
, mmc_dbg_card_status_get
,
303 #define EXT_CSD_STR_LEN 1025
305 static int mmc_ext_csd_open(struct inode
*inode
, struct file
*filp
)
307 struct mmc_card
*card
= inode
->i_private
;
313 buf
= kmalloc(EXT_CSD_STR_LEN
+ 1, GFP_KERNEL
);
318 err
= mmc_get_ext_csd(card
, &ext_csd
);
323 for (i
= 0; i
< 512; i
++)
324 n
+= sprintf(buf
+ n
, "%02x", ext_csd
[i
]);
325 n
+= sprintf(buf
+ n
, "\n");
327 if (n
!= EXT_CSD_STR_LEN
) {
332 filp
->private_data
= buf
;
341 static ssize_t
mmc_ext_csd_read(struct file
*filp
, char __user
*ubuf
,
342 size_t cnt
, loff_t
*ppos
)
344 char *buf
= filp
->private_data
;
346 return simple_read_from_buffer(ubuf
, cnt
, ppos
,
347 buf
, EXT_CSD_STR_LEN
);
350 static int mmc_ext_csd_release(struct inode
*inode
, struct file
*file
)
352 kfree(file
->private_data
);
356 static const struct file_operations mmc_dbg_ext_csd_fops
= {
357 .open
= mmc_ext_csd_open
,
358 .read
= mmc_ext_csd_read
,
359 .release
= mmc_ext_csd_release
,
360 .llseek
= default_llseek
,
363 void mmc_add_card_debugfs(struct mmc_card
*card
)
365 struct mmc_host
*host
= card
->host
;
368 if (!host
->debugfs_root
)
371 root
= debugfs_create_dir(mmc_card_id(card
), host
->debugfs_root
);
373 /* Don't complain -- debugfs just isn't enabled */
376 /* Complain -- debugfs is enabled, but it failed to
377 * create the directory. */
380 card
->debugfs_root
= root
;
382 if (!debugfs_create_x32("state", S_IRUSR
, root
, &card
->state
))
385 if (mmc_card_mmc(card
) || mmc_card_sd(card
))
386 if (!debugfs_create_file("status", S_IRUSR
, root
, card
,
387 &mmc_dbg_card_status_fops
))
390 if (mmc_card_mmc(card
))
391 if (!debugfs_create_file("ext_csd", S_IRUSR
, root
, card
,
392 &mmc_dbg_ext_csd_fops
))
398 debugfs_remove_recursive(root
);
399 card
->debugfs_root
= NULL
;
400 dev_err(&card
->dev
, "failed to initialize debugfs\n");
403 void mmc_remove_card_debugfs(struct mmc_card
*card
)
405 debugfs_remove_recursive(card
->debugfs_root
);