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 void mmc_add_card_debugfs(struct mmc_card
*card
)
286 struct mmc_host
*host
= card
->host
;
289 if (!host
->debugfs_root
)
292 root
= debugfs_create_dir(mmc_card_id(card
), host
->debugfs_root
);
294 /* Don't complain -- debugfs just isn't enabled */
297 /* Complain -- debugfs is enabled, but it failed to
298 * create the directory. */
301 card
->debugfs_root
= root
;
303 if (!debugfs_create_x32("state", S_IRUSR
, root
, &card
->state
))
309 debugfs_remove_recursive(root
);
310 card
->debugfs_root
= NULL
;
311 dev_err(&card
->dev
, "failed to initialize debugfs\n");
314 void mmc_remove_card_debugfs(struct mmc_card
*card
)
316 debugfs_remove_recursive(card
->debugfs_root
);