Branch data Line data Source code
1 : : // SPDX-License-Identifier: GPL-2.0-only 2 : : /* 3 : : * Debugfs support for hosts and cards 4 : : * 5 : : * Copyright (C) 2008 Atmel Corporation 6 : : */ 7 : : #include <linux/moduleparam.h> 8 : : #include <linux/export.h> 9 : : #include <linux/debugfs.h> 10 : : #include <linux/fs.h> 11 : : #include <linux/seq_file.h> 12 : : #include <linux/slab.h> 13 : : #include <linux/stat.h> 14 : : #include <linux/fault-inject.h> 15 : : 16 : : #include <linux/mmc/card.h> 17 : : #include <linux/mmc/host.h> 18 : : 19 : : #include "core.h" 20 : : #include "card.h" 21 : : #include "host.h" 22 : : #include "mmc_ops.h" 23 : : 24 : : #ifdef CONFIG_FAIL_MMC_REQUEST 25 : : 26 : : static DECLARE_FAULT_ATTR(fail_default_attr); 27 : : static char *fail_request; 28 : : module_param(fail_request, charp, 0); 29 : : 30 : : #endif /* CONFIG_FAIL_MMC_REQUEST */ 31 : : 32 : : /* The debugfs functions are optimized away when CONFIG_DEBUG_FS isn't set. */ 33 : 0 : static int mmc_ios_show(struct seq_file *s, void *data) 34 : : { 35 : : static const char *vdd_str[] = { 36 : : [8] = "2.0", 37 : : [9] = "2.1", 38 : : [10] = "2.2", 39 : : [11] = "2.3", 40 : : [12] = "2.4", 41 : : [13] = "2.5", 42 : : [14] = "2.6", 43 : : [15] = "2.7", 44 : : [16] = "2.8", 45 : : [17] = "2.9", 46 : : [18] = "3.0", 47 : : [19] = "3.1", 48 : : [20] = "3.2", 49 : : [21] = "3.3", 50 : : [22] = "3.4", 51 : : [23] = "3.5", 52 : : [24] = "3.6", 53 : : }; 54 : 0 : struct mmc_host *host = s->private; 55 : : struct mmc_ios *ios = &host->ios; 56 : : const char *str; 57 : : 58 : 0 : seq_printf(s, "clock:\t\t%u Hz\n", ios->clock); 59 : 0 : if (host->actual_clock) 60 : 0 : seq_printf(s, "actual clock:\t%u Hz\n", host->actual_clock); 61 : 0 : seq_printf(s, "vdd:\t\t%u ", ios->vdd); 62 : 0 : if ((1 << ios->vdd) & MMC_VDD_165_195) 63 : 0 : seq_printf(s, "(1.65 - 1.95 V)\n"); 64 : 0 : else if (ios->vdd < (ARRAY_SIZE(vdd_str) - 1) 65 : 0 : && vdd_str[ios->vdd] && vdd_str[ios->vdd + 1]) 66 : 0 : seq_printf(s, "(%s ~ %s V)\n", vdd_str[ios->vdd], 67 : : vdd_str[ios->vdd + 1]); 68 : : else 69 : 0 : seq_printf(s, "(invalid)\n"); 70 : : 71 : 0 : switch (ios->bus_mode) { 72 : : case MMC_BUSMODE_OPENDRAIN: 73 : : str = "open drain"; 74 : : break; 75 : : case MMC_BUSMODE_PUSHPULL: 76 : : str = "push-pull"; 77 : 0 : break; 78 : : default: 79 : : str = "invalid"; 80 : 0 : break; 81 : : } 82 : 0 : seq_printf(s, "bus mode:\t%u (%s)\n", ios->bus_mode, str); 83 : : 84 : 0 : switch (ios->chip_select) { 85 : : case MMC_CS_DONTCARE: 86 : : str = "don't care"; 87 : : break; 88 : : case MMC_CS_HIGH: 89 : : str = "active high"; 90 : : break; 91 : : case MMC_CS_LOW: 92 : : str = "active low"; 93 : : break; 94 : : default: 95 : : str = "invalid"; 96 : : break; 97 : : } 98 : 0 : seq_printf(s, "chip select:\t%u (%s)\n", ios->chip_select, str); 99 : : 100 : 0 : switch (ios->power_mode) { 101 : : case MMC_POWER_OFF: 102 : : str = "off"; 103 : : break; 104 : : case MMC_POWER_UP: 105 : : str = "up"; 106 : : break; 107 : : case MMC_POWER_ON: 108 : : str = "on"; 109 : : break; 110 : : default: 111 : : str = "invalid"; 112 : : break; 113 : : } 114 : 0 : seq_printf(s, "power mode:\t%u (%s)\n", ios->power_mode, str); 115 : 0 : seq_printf(s, "bus width:\t%u (%u bits)\n", 116 : 0 : ios->bus_width, 1 << ios->bus_width); 117 : : 118 : 0 : switch (ios->timing) { 119 : : case MMC_TIMING_LEGACY: 120 : : str = "legacy"; 121 : : break; 122 : : case MMC_TIMING_MMC_HS: 123 : : str = "mmc high-speed"; 124 : 0 : break; 125 : : case MMC_TIMING_SD_HS: 126 : : str = "sd high-speed"; 127 : 0 : break; 128 : : case MMC_TIMING_UHS_SDR12: 129 : : str = "sd uhs SDR12"; 130 : 0 : break; 131 : : case MMC_TIMING_UHS_SDR25: 132 : : str = "sd uhs SDR25"; 133 : 0 : break; 134 : : case MMC_TIMING_UHS_SDR50: 135 : : str = "sd uhs SDR50"; 136 : 0 : break; 137 : : case MMC_TIMING_UHS_SDR104: 138 : : str = "sd uhs SDR104"; 139 : 0 : break; 140 : : case MMC_TIMING_UHS_DDR50: 141 : : str = "sd uhs DDR50"; 142 : 0 : break; 143 : : case MMC_TIMING_MMC_DDR52: 144 : : str = "mmc DDR52"; 145 : 0 : break; 146 : : case MMC_TIMING_MMC_HS200: 147 : : str = "mmc HS200"; 148 : 0 : break; 149 : : case MMC_TIMING_MMC_HS400: 150 : 0 : str = mmc_card_hs400es(host->card) ? 151 : 0 : "mmc HS400 enhanced strobe" : "mmc HS400"; 152 : 0 : break; 153 : : default: 154 : : str = "invalid"; 155 : 0 : break; 156 : : } 157 : 0 : seq_printf(s, "timing spec:\t%u (%s)\n", ios->timing, str); 158 : : 159 : 0 : switch (ios->signal_voltage) { 160 : : case MMC_SIGNAL_VOLTAGE_330: 161 : : str = "3.30 V"; 162 : : break; 163 : : case MMC_SIGNAL_VOLTAGE_180: 164 : : str = "1.80 V"; 165 : : break; 166 : : case MMC_SIGNAL_VOLTAGE_120: 167 : : str = "1.20 V"; 168 : : break; 169 : : default: 170 : : str = "invalid"; 171 : : break; 172 : : } 173 : 0 : seq_printf(s, "signal voltage:\t%u (%s)\n", ios->signal_voltage, str); 174 : : 175 : 0 : switch (ios->drv_type) { 176 : : case MMC_SET_DRIVER_TYPE_A: 177 : : str = "driver type A"; 178 : : break; 179 : : case MMC_SET_DRIVER_TYPE_B: 180 : : str = "driver type B"; 181 : : break; 182 : : case MMC_SET_DRIVER_TYPE_C: 183 : : str = "driver type C"; 184 : : break; 185 : : case MMC_SET_DRIVER_TYPE_D: 186 : : str = "driver type D"; 187 : : break; 188 : : default: 189 : : str = "invalid"; 190 : : break; 191 : : } 192 : 0 : seq_printf(s, "driver type:\t%u (%s)\n", ios->drv_type, str); 193 : : 194 : 0 : return 0; 195 : : } 196 : 0 : DEFINE_SHOW_ATTRIBUTE(mmc_ios); 197 : : 198 : 0 : static int mmc_clock_opt_get(void *data, u64 *val) 199 : : { 200 : : struct mmc_host *host = data; 201 : : 202 : 0 : *val = host->ios.clock; 203 : : 204 : 0 : return 0; 205 : : } 206 : : 207 : 0 : static int mmc_clock_opt_set(void *data, u64 val) 208 : : { 209 : : struct mmc_host *host = data; 210 : : 211 : : /* We need this check due to input value is u64 */ 212 : 0 : if (val != 0 && (val > host->f_max || val < host->f_min)) 213 : : return -EINVAL; 214 : : 215 : : mmc_claim_host(host); 216 : 0 : mmc_set_clock(host, (unsigned int) val); 217 : 0 : mmc_release_host(host); 218 : : 219 : 0 : return 0; 220 : : } 221 : : 222 : 0 : DEFINE_SIMPLE_ATTRIBUTE(mmc_clock_fops, mmc_clock_opt_get, mmc_clock_opt_set, 223 : : "%llu\n"); 224 : : 225 : 3 : void mmc_add_host_debugfs(struct mmc_host *host) 226 : : { 227 : : struct dentry *root; 228 : : 229 : 3 : root = debugfs_create_dir(mmc_hostname(host), NULL); 230 : 3 : host->debugfs_root = root; 231 : : 232 : 3 : debugfs_create_file("ios", S_IRUSR, root, host, &mmc_ios_fops); 233 : 3 : debugfs_create_x32("caps", S_IRUSR, root, &host->caps); 234 : 3 : debugfs_create_x32("caps2", S_IRUSR, root, &host->caps2); 235 : 3 : debugfs_create_file("clock", S_IRUSR | S_IWUSR, root, host, 236 : : &mmc_clock_fops); 237 : : 238 : : #ifdef CONFIG_FAIL_MMC_REQUEST 239 : : if (fail_request) 240 : : setup_fault_attr(&fail_default_attr, fail_request); 241 : : host->fail_mmc_request = fail_default_attr; 242 : : fault_create_debugfs_attr("fail_mmc_request", root, 243 : : &host->fail_mmc_request); 244 : : #endif 245 : 3 : } 246 : : 247 : 0 : void mmc_remove_host_debugfs(struct mmc_host *host) 248 : : { 249 : 0 : debugfs_remove_recursive(host->debugfs_root); 250 : 0 : } 251 : : 252 : 3 : void mmc_add_card_debugfs(struct mmc_card *card) 253 : : { 254 : 3 : struct mmc_host *host = card->host; 255 : : struct dentry *root; 256 : : 257 : 3 : if (!host->debugfs_root) 258 : 3 : return; 259 : : 260 : 3 : root = debugfs_create_dir(mmc_card_id(card), host->debugfs_root); 261 : 3 : card->debugfs_root = root; 262 : : 263 : 3 : debugfs_create_x32("state", S_IRUSR, root, &card->state); 264 : : } 265 : : 266 : 0 : void mmc_remove_card_debugfs(struct mmc_card *card) 267 : : { 268 : 0 : debugfs_remove_recursive(card->debugfs_root); 269 : 0 : card->debugfs_root = NULL; 270 : 0 : }