debugfs.c revision 6038f373a3dc1f1c26496e60b6c40b164716f07e
16edd8ee60ac9b974bd6ec3b1bcb2aab02762fa8cHaavard Skinnemoen/*
26edd8ee60ac9b974bd6ec3b1bcb2aab02762fa8cHaavard Skinnemoen * Debugfs support for hosts and cards
36edd8ee60ac9b974bd6ec3b1bcb2aab02762fa8cHaavard Skinnemoen *
46edd8ee60ac9b974bd6ec3b1bcb2aab02762fa8cHaavard Skinnemoen * Copyright (C) 2008 Atmel Corporation
56edd8ee60ac9b974bd6ec3b1bcb2aab02762fa8cHaavard Skinnemoen *
66edd8ee60ac9b974bd6ec3b1bcb2aab02762fa8cHaavard Skinnemoen * This program is free software; you can redistribute it and/or modify
76edd8ee60ac9b974bd6ec3b1bcb2aab02762fa8cHaavard Skinnemoen * it under the terms of the GNU General Public License version 2 as
86edd8ee60ac9b974bd6ec3b1bcb2aab02762fa8cHaavard Skinnemoen * published by the Free Software Foundation.
96edd8ee60ac9b974bd6ec3b1bcb2aab02762fa8cHaavard Skinnemoen */
106edd8ee60ac9b974bd6ec3b1bcb2aab02762fa8cHaavard Skinnemoen#include <linux/debugfs.h>
116edd8ee60ac9b974bd6ec3b1bcb2aab02762fa8cHaavard Skinnemoen#include <linux/fs.h>
126edd8ee60ac9b974bd6ec3b1bcb2aab02762fa8cHaavard Skinnemoen#include <linux/seq_file.h>
135a0e3ad6af8660be21ca98a971cd00f331318c05Tejun Heo#include <linux/slab.h>
146edd8ee60ac9b974bd6ec3b1bcb2aab02762fa8cHaavard Skinnemoen#include <linux/stat.h>
156edd8ee60ac9b974bd6ec3b1bcb2aab02762fa8cHaavard Skinnemoen
16f4b7f927b531ca350cfc4ca1bdc3377dac7f9a32Haavard Skinnemoen#include <linux/mmc/card.h>
176edd8ee60ac9b974bd6ec3b1bcb2aab02762fa8cHaavard Skinnemoen#include <linux/mmc/host.h>
186edd8ee60ac9b974bd6ec3b1bcb2aab02762fa8cHaavard Skinnemoen
196edd8ee60ac9b974bd6ec3b1bcb2aab02762fa8cHaavard Skinnemoen#include "core.h"
20f4b7f927b531ca350cfc4ca1bdc3377dac7f9a32Haavard Skinnemoen#include "mmc_ops.h"
216edd8ee60ac9b974bd6ec3b1bcb2aab02762fa8cHaavard Skinnemoen
226edd8ee60ac9b974bd6ec3b1bcb2aab02762fa8cHaavard Skinnemoen/* The debugfs functions are optimized away when CONFIG_DEBUG_FS isn't set. */
236edd8ee60ac9b974bd6ec3b1bcb2aab02762fa8cHaavard Skinnemoenstatic int mmc_ios_show(struct seq_file *s, void *data)
246edd8ee60ac9b974bd6ec3b1bcb2aab02762fa8cHaavard Skinnemoen{
256edd8ee60ac9b974bd6ec3b1bcb2aab02762fa8cHaavard Skinnemoen	static const char *vdd_str[] = {
266edd8ee60ac9b974bd6ec3b1bcb2aab02762fa8cHaavard Skinnemoen		[8]	= "2.0",
276edd8ee60ac9b974bd6ec3b1bcb2aab02762fa8cHaavard Skinnemoen		[9]	= "2.1",
286edd8ee60ac9b974bd6ec3b1bcb2aab02762fa8cHaavard Skinnemoen		[10]	= "2.2",
296edd8ee60ac9b974bd6ec3b1bcb2aab02762fa8cHaavard Skinnemoen		[11]	= "2.3",
306edd8ee60ac9b974bd6ec3b1bcb2aab02762fa8cHaavard Skinnemoen		[12]	= "2.4",
316edd8ee60ac9b974bd6ec3b1bcb2aab02762fa8cHaavard Skinnemoen		[13]	= "2.5",
326edd8ee60ac9b974bd6ec3b1bcb2aab02762fa8cHaavard Skinnemoen		[14]	= "2.6",
336edd8ee60ac9b974bd6ec3b1bcb2aab02762fa8cHaavard Skinnemoen		[15]	= "2.7",
346edd8ee60ac9b974bd6ec3b1bcb2aab02762fa8cHaavard Skinnemoen		[16]	= "2.8",
356edd8ee60ac9b974bd6ec3b1bcb2aab02762fa8cHaavard Skinnemoen		[17]	= "2.9",
366edd8ee60ac9b974bd6ec3b1bcb2aab02762fa8cHaavard Skinnemoen		[18]	= "3.0",
376edd8ee60ac9b974bd6ec3b1bcb2aab02762fa8cHaavard Skinnemoen		[19]	= "3.1",
386edd8ee60ac9b974bd6ec3b1bcb2aab02762fa8cHaavard Skinnemoen		[20]	= "3.2",
396edd8ee60ac9b974bd6ec3b1bcb2aab02762fa8cHaavard Skinnemoen		[21]	= "3.3",
406edd8ee60ac9b974bd6ec3b1bcb2aab02762fa8cHaavard Skinnemoen		[22]	= "3.4",
416edd8ee60ac9b974bd6ec3b1bcb2aab02762fa8cHaavard Skinnemoen		[23]	= "3.5",
426edd8ee60ac9b974bd6ec3b1bcb2aab02762fa8cHaavard Skinnemoen		[24]	= "3.6",
436edd8ee60ac9b974bd6ec3b1bcb2aab02762fa8cHaavard Skinnemoen	};
446edd8ee60ac9b974bd6ec3b1bcb2aab02762fa8cHaavard Skinnemoen	struct mmc_host	*host = s->private;
456edd8ee60ac9b974bd6ec3b1bcb2aab02762fa8cHaavard Skinnemoen	struct mmc_ios	*ios = &host->ios;
466edd8ee60ac9b974bd6ec3b1bcb2aab02762fa8cHaavard Skinnemoen	const char *str;
476edd8ee60ac9b974bd6ec3b1bcb2aab02762fa8cHaavard Skinnemoen
486edd8ee60ac9b974bd6ec3b1bcb2aab02762fa8cHaavard Skinnemoen	seq_printf(s, "clock:\t\t%u Hz\n", ios->clock);
496edd8ee60ac9b974bd6ec3b1bcb2aab02762fa8cHaavard Skinnemoen	seq_printf(s, "vdd:\t\t%u ", ios->vdd);
506edd8ee60ac9b974bd6ec3b1bcb2aab02762fa8cHaavard Skinnemoen	if ((1 << ios->vdd) & MMC_VDD_165_195)
516edd8ee60ac9b974bd6ec3b1bcb2aab02762fa8cHaavard Skinnemoen		seq_printf(s, "(1.65 - 1.95 V)\n");
526edd8ee60ac9b974bd6ec3b1bcb2aab02762fa8cHaavard Skinnemoen	else if (ios->vdd < (ARRAY_SIZE(vdd_str) - 1)
536edd8ee60ac9b974bd6ec3b1bcb2aab02762fa8cHaavard Skinnemoen			&& vdd_str[ios->vdd] && vdd_str[ios->vdd + 1])
546edd8ee60ac9b974bd6ec3b1bcb2aab02762fa8cHaavard Skinnemoen		seq_printf(s, "(%s ~ %s V)\n", vdd_str[ios->vdd],
556edd8ee60ac9b974bd6ec3b1bcb2aab02762fa8cHaavard Skinnemoen				vdd_str[ios->vdd + 1]);
566edd8ee60ac9b974bd6ec3b1bcb2aab02762fa8cHaavard Skinnemoen	else
576edd8ee60ac9b974bd6ec3b1bcb2aab02762fa8cHaavard Skinnemoen		seq_printf(s, "(invalid)\n");
586edd8ee60ac9b974bd6ec3b1bcb2aab02762fa8cHaavard Skinnemoen
596edd8ee60ac9b974bd6ec3b1bcb2aab02762fa8cHaavard Skinnemoen	switch (ios->bus_mode) {
606edd8ee60ac9b974bd6ec3b1bcb2aab02762fa8cHaavard Skinnemoen	case MMC_BUSMODE_OPENDRAIN:
616edd8ee60ac9b974bd6ec3b1bcb2aab02762fa8cHaavard Skinnemoen		str = "open drain";
626edd8ee60ac9b974bd6ec3b1bcb2aab02762fa8cHaavard Skinnemoen		break;
636edd8ee60ac9b974bd6ec3b1bcb2aab02762fa8cHaavard Skinnemoen	case MMC_BUSMODE_PUSHPULL:
646edd8ee60ac9b974bd6ec3b1bcb2aab02762fa8cHaavard Skinnemoen		str = "push-pull";
656edd8ee60ac9b974bd6ec3b1bcb2aab02762fa8cHaavard Skinnemoen		break;
666edd8ee60ac9b974bd6ec3b1bcb2aab02762fa8cHaavard Skinnemoen	default:
676edd8ee60ac9b974bd6ec3b1bcb2aab02762fa8cHaavard Skinnemoen		str = "invalid";
686edd8ee60ac9b974bd6ec3b1bcb2aab02762fa8cHaavard Skinnemoen		break;
696edd8ee60ac9b974bd6ec3b1bcb2aab02762fa8cHaavard Skinnemoen	}
706edd8ee60ac9b974bd6ec3b1bcb2aab02762fa8cHaavard Skinnemoen	seq_printf(s, "bus mode:\t%u (%s)\n", ios->bus_mode, str);
716edd8ee60ac9b974bd6ec3b1bcb2aab02762fa8cHaavard Skinnemoen
726edd8ee60ac9b974bd6ec3b1bcb2aab02762fa8cHaavard Skinnemoen	switch (ios->chip_select) {
736edd8ee60ac9b974bd6ec3b1bcb2aab02762fa8cHaavard Skinnemoen	case MMC_CS_DONTCARE:
746edd8ee60ac9b974bd6ec3b1bcb2aab02762fa8cHaavard Skinnemoen		str = "don't care";
756edd8ee60ac9b974bd6ec3b1bcb2aab02762fa8cHaavard Skinnemoen		break;
766edd8ee60ac9b974bd6ec3b1bcb2aab02762fa8cHaavard Skinnemoen	case MMC_CS_HIGH:
776edd8ee60ac9b974bd6ec3b1bcb2aab02762fa8cHaavard Skinnemoen		str = "active high";
786edd8ee60ac9b974bd6ec3b1bcb2aab02762fa8cHaavard Skinnemoen		break;
796edd8ee60ac9b974bd6ec3b1bcb2aab02762fa8cHaavard Skinnemoen	case MMC_CS_LOW:
806edd8ee60ac9b974bd6ec3b1bcb2aab02762fa8cHaavard Skinnemoen		str = "active low";
816edd8ee60ac9b974bd6ec3b1bcb2aab02762fa8cHaavard Skinnemoen		break;
826edd8ee60ac9b974bd6ec3b1bcb2aab02762fa8cHaavard Skinnemoen	default:
836edd8ee60ac9b974bd6ec3b1bcb2aab02762fa8cHaavard Skinnemoen		str = "invalid";
846edd8ee60ac9b974bd6ec3b1bcb2aab02762fa8cHaavard Skinnemoen		break;
856edd8ee60ac9b974bd6ec3b1bcb2aab02762fa8cHaavard Skinnemoen	}
866edd8ee60ac9b974bd6ec3b1bcb2aab02762fa8cHaavard Skinnemoen	seq_printf(s, "chip select:\t%u (%s)\n", ios->chip_select, str);
876edd8ee60ac9b974bd6ec3b1bcb2aab02762fa8cHaavard Skinnemoen
886edd8ee60ac9b974bd6ec3b1bcb2aab02762fa8cHaavard Skinnemoen	switch (ios->power_mode) {
896edd8ee60ac9b974bd6ec3b1bcb2aab02762fa8cHaavard Skinnemoen	case MMC_POWER_OFF:
906edd8ee60ac9b974bd6ec3b1bcb2aab02762fa8cHaavard Skinnemoen		str = "off";
916edd8ee60ac9b974bd6ec3b1bcb2aab02762fa8cHaavard Skinnemoen		break;
926edd8ee60ac9b974bd6ec3b1bcb2aab02762fa8cHaavard Skinnemoen	case MMC_POWER_UP:
936edd8ee60ac9b974bd6ec3b1bcb2aab02762fa8cHaavard Skinnemoen		str = "up";
946edd8ee60ac9b974bd6ec3b1bcb2aab02762fa8cHaavard Skinnemoen		break;
956edd8ee60ac9b974bd6ec3b1bcb2aab02762fa8cHaavard Skinnemoen	case MMC_POWER_ON:
966edd8ee60ac9b974bd6ec3b1bcb2aab02762fa8cHaavard Skinnemoen		str = "on";
976edd8ee60ac9b974bd6ec3b1bcb2aab02762fa8cHaavard Skinnemoen		break;
986edd8ee60ac9b974bd6ec3b1bcb2aab02762fa8cHaavard Skinnemoen	default:
996edd8ee60ac9b974bd6ec3b1bcb2aab02762fa8cHaavard Skinnemoen		str = "invalid";
1006edd8ee60ac9b974bd6ec3b1bcb2aab02762fa8cHaavard Skinnemoen		break;
1016edd8ee60ac9b974bd6ec3b1bcb2aab02762fa8cHaavard Skinnemoen	}
1026edd8ee60ac9b974bd6ec3b1bcb2aab02762fa8cHaavard Skinnemoen	seq_printf(s, "power mode:\t%u (%s)\n", ios->power_mode, str);
1036edd8ee60ac9b974bd6ec3b1bcb2aab02762fa8cHaavard Skinnemoen	seq_printf(s, "bus width:\t%u (%u bits)\n",
1046edd8ee60ac9b974bd6ec3b1bcb2aab02762fa8cHaavard Skinnemoen			ios->bus_width, 1 << ios->bus_width);
1056edd8ee60ac9b974bd6ec3b1bcb2aab02762fa8cHaavard Skinnemoen
1066edd8ee60ac9b974bd6ec3b1bcb2aab02762fa8cHaavard Skinnemoen	switch (ios->timing) {
1076edd8ee60ac9b974bd6ec3b1bcb2aab02762fa8cHaavard Skinnemoen	case MMC_TIMING_LEGACY:
1086edd8ee60ac9b974bd6ec3b1bcb2aab02762fa8cHaavard Skinnemoen		str = "legacy";
1096edd8ee60ac9b974bd6ec3b1bcb2aab02762fa8cHaavard Skinnemoen		break;
1106edd8ee60ac9b974bd6ec3b1bcb2aab02762fa8cHaavard Skinnemoen	case MMC_TIMING_MMC_HS:
1116edd8ee60ac9b974bd6ec3b1bcb2aab02762fa8cHaavard Skinnemoen		str = "mmc high-speed";
1126edd8ee60ac9b974bd6ec3b1bcb2aab02762fa8cHaavard Skinnemoen		break;
1136edd8ee60ac9b974bd6ec3b1bcb2aab02762fa8cHaavard Skinnemoen	case MMC_TIMING_SD_HS:
1146edd8ee60ac9b974bd6ec3b1bcb2aab02762fa8cHaavard Skinnemoen		str = "sd high-speed";
1156edd8ee60ac9b974bd6ec3b1bcb2aab02762fa8cHaavard Skinnemoen		break;
1166edd8ee60ac9b974bd6ec3b1bcb2aab02762fa8cHaavard Skinnemoen	default:
1176edd8ee60ac9b974bd6ec3b1bcb2aab02762fa8cHaavard Skinnemoen		str = "invalid";
1186edd8ee60ac9b974bd6ec3b1bcb2aab02762fa8cHaavard Skinnemoen		break;
1196edd8ee60ac9b974bd6ec3b1bcb2aab02762fa8cHaavard Skinnemoen	}
1206edd8ee60ac9b974bd6ec3b1bcb2aab02762fa8cHaavard Skinnemoen	seq_printf(s, "timing spec:\t%u (%s)\n", ios->timing, str);
1216edd8ee60ac9b974bd6ec3b1bcb2aab02762fa8cHaavard Skinnemoen
1226edd8ee60ac9b974bd6ec3b1bcb2aab02762fa8cHaavard Skinnemoen	return 0;
1236edd8ee60ac9b974bd6ec3b1bcb2aab02762fa8cHaavard Skinnemoen}
1246edd8ee60ac9b974bd6ec3b1bcb2aab02762fa8cHaavard Skinnemoen
1256edd8ee60ac9b974bd6ec3b1bcb2aab02762fa8cHaavard Skinnemoenstatic int mmc_ios_open(struct inode *inode, struct file *file)
1266edd8ee60ac9b974bd6ec3b1bcb2aab02762fa8cHaavard Skinnemoen{
1276edd8ee60ac9b974bd6ec3b1bcb2aab02762fa8cHaavard Skinnemoen	return single_open(file, mmc_ios_show, inode->i_private);
1286edd8ee60ac9b974bd6ec3b1bcb2aab02762fa8cHaavard Skinnemoen}
1296edd8ee60ac9b974bd6ec3b1bcb2aab02762fa8cHaavard Skinnemoen
1306edd8ee60ac9b974bd6ec3b1bcb2aab02762fa8cHaavard Skinnemoenstatic const struct file_operations mmc_ios_fops = {
1316edd8ee60ac9b974bd6ec3b1bcb2aab02762fa8cHaavard Skinnemoen	.open		= mmc_ios_open,
1326edd8ee60ac9b974bd6ec3b1bcb2aab02762fa8cHaavard Skinnemoen	.read		= seq_read,
1336edd8ee60ac9b974bd6ec3b1bcb2aab02762fa8cHaavard Skinnemoen	.llseek		= seq_lseek,
1346edd8ee60ac9b974bd6ec3b1bcb2aab02762fa8cHaavard Skinnemoen	.release	= single_release,
1356edd8ee60ac9b974bd6ec3b1bcb2aab02762fa8cHaavard Skinnemoen};
1366edd8ee60ac9b974bd6ec3b1bcb2aab02762fa8cHaavard Skinnemoen
1376edd8ee60ac9b974bd6ec3b1bcb2aab02762fa8cHaavard Skinnemoenvoid mmc_add_host_debugfs(struct mmc_host *host)
1386edd8ee60ac9b974bd6ec3b1bcb2aab02762fa8cHaavard Skinnemoen{
1396edd8ee60ac9b974bd6ec3b1bcb2aab02762fa8cHaavard Skinnemoen	struct dentry *root;
1406edd8ee60ac9b974bd6ec3b1bcb2aab02762fa8cHaavard Skinnemoen
1416edd8ee60ac9b974bd6ec3b1bcb2aab02762fa8cHaavard Skinnemoen	root = debugfs_create_dir(mmc_hostname(host), NULL);
1426edd8ee60ac9b974bd6ec3b1bcb2aab02762fa8cHaavard Skinnemoen	if (IS_ERR(root))
1436edd8ee60ac9b974bd6ec3b1bcb2aab02762fa8cHaavard Skinnemoen		/* Don't complain -- debugfs just isn't enabled */
1446edd8ee60ac9b974bd6ec3b1bcb2aab02762fa8cHaavard Skinnemoen		return;
1456edd8ee60ac9b974bd6ec3b1bcb2aab02762fa8cHaavard Skinnemoen	if (!root)
1466edd8ee60ac9b974bd6ec3b1bcb2aab02762fa8cHaavard Skinnemoen		/* Complain -- debugfs is enabled, but it failed to
1476edd8ee60ac9b974bd6ec3b1bcb2aab02762fa8cHaavard Skinnemoen		 * create the directory. */
1486edd8ee60ac9b974bd6ec3b1bcb2aab02762fa8cHaavard Skinnemoen		goto err_root;
1496edd8ee60ac9b974bd6ec3b1bcb2aab02762fa8cHaavard Skinnemoen
1506edd8ee60ac9b974bd6ec3b1bcb2aab02762fa8cHaavard Skinnemoen	host->debugfs_root = root;
1516edd8ee60ac9b974bd6ec3b1bcb2aab02762fa8cHaavard Skinnemoen
1526edd8ee60ac9b974bd6ec3b1bcb2aab02762fa8cHaavard Skinnemoen	if (!debugfs_create_file("ios", S_IRUSR, root, host, &mmc_ios_fops))
1536edd8ee60ac9b974bd6ec3b1bcb2aab02762fa8cHaavard Skinnemoen		goto err_ios;
1546edd8ee60ac9b974bd6ec3b1bcb2aab02762fa8cHaavard Skinnemoen
1556edd8ee60ac9b974bd6ec3b1bcb2aab02762fa8cHaavard Skinnemoen	return;
1566edd8ee60ac9b974bd6ec3b1bcb2aab02762fa8cHaavard Skinnemoen
1576edd8ee60ac9b974bd6ec3b1bcb2aab02762fa8cHaavard Skinnemoenerr_ios:
1586edd8ee60ac9b974bd6ec3b1bcb2aab02762fa8cHaavard Skinnemoen	debugfs_remove_recursive(root);
1596edd8ee60ac9b974bd6ec3b1bcb2aab02762fa8cHaavard Skinnemoen	host->debugfs_root = NULL;
1606edd8ee60ac9b974bd6ec3b1bcb2aab02762fa8cHaavard Skinnemoenerr_root:
1616edd8ee60ac9b974bd6ec3b1bcb2aab02762fa8cHaavard Skinnemoen	dev_err(&host->class_dev, "failed to initialize debugfs\n");
1626edd8ee60ac9b974bd6ec3b1bcb2aab02762fa8cHaavard Skinnemoen}
1636edd8ee60ac9b974bd6ec3b1bcb2aab02762fa8cHaavard Skinnemoen
1646edd8ee60ac9b974bd6ec3b1bcb2aab02762fa8cHaavard Skinnemoenvoid mmc_remove_host_debugfs(struct mmc_host *host)
1656edd8ee60ac9b974bd6ec3b1bcb2aab02762fa8cHaavard Skinnemoen{
1666edd8ee60ac9b974bd6ec3b1bcb2aab02762fa8cHaavard Skinnemoen	debugfs_remove_recursive(host->debugfs_root);
1676edd8ee60ac9b974bd6ec3b1bcb2aab02762fa8cHaavard Skinnemoen}
168f4b7f927b531ca350cfc4ca1bdc3377dac7f9a32Haavard Skinnemoen
169f4b7f927b531ca350cfc4ca1bdc3377dac7f9a32Haavard Skinnemoenstatic int mmc_dbg_card_status_get(void *data, u64 *val)
170f4b7f927b531ca350cfc4ca1bdc3377dac7f9a32Haavard Skinnemoen{
171f4b7f927b531ca350cfc4ca1bdc3377dac7f9a32Haavard Skinnemoen	struct mmc_card	*card = data;
172f4b7f927b531ca350cfc4ca1bdc3377dac7f9a32Haavard Skinnemoen	u32		status;
173f4b7f927b531ca350cfc4ca1bdc3377dac7f9a32Haavard Skinnemoen	int		ret;
174f4b7f927b531ca350cfc4ca1bdc3377dac7f9a32Haavard Skinnemoen
175f4b7f927b531ca350cfc4ca1bdc3377dac7f9a32Haavard Skinnemoen	mmc_claim_host(card->host);
176f4b7f927b531ca350cfc4ca1bdc3377dac7f9a32Haavard Skinnemoen
177f4b7f927b531ca350cfc4ca1bdc3377dac7f9a32Haavard Skinnemoen	ret = mmc_send_status(data, &status);
178f4b7f927b531ca350cfc4ca1bdc3377dac7f9a32Haavard Skinnemoen	if (!ret)
179f4b7f927b531ca350cfc4ca1bdc3377dac7f9a32Haavard Skinnemoen		*val = status;
180f4b7f927b531ca350cfc4ca1bdc3377dac7f9a32Haavard Skinnemoen
181f4b7f927b531ca350cfc4ca1bdc3377dac7f9a32Haavard Skinnemoen	mmc_release_host(card->host);
182f4b7f927b531ca350cfc4ca1bdc3377dac7f9a32Haavard Skinnemoen
183f4b7f927b531ca350cfc4ca1bdc3377dac7f9a32Haavard Skinnemoen	return ret;
184f4b7f927b531ca350cfc4ca1bdc3377dac7f9a32Haavard Skinnemoen}
185f4b7f927b531ca350cfc4ca1bdc3377dac7f9a32Haavard SkinnemoenDEFINE_SIMPLE_ATTRIBUTE(mmc_dbg_card_status_fops, mmc_dbg_card_status_get,
186f4b7f927b531ca350cfc4ca1bdc3377dac7f9a32Haavard Skinnemoen		NULL, "%08llx\n");
187f4b7f927b531ca350cfc4ca1bdc3377dac7f9a32Haavard Skinnemoen
188736bb6bb01a2a180b6f062e792bd03658d57ab7eAdrian Hunter#define EXT_CSD_STR_LEN 1025
189736bb6bb01a2a180b6f062e792bd03658d57ab7eAdrian Hunter
190736bb6bb01a2a180b6f062e792bd03658d57ab7eAdrian Hunterstatic int mmc_ext_csd_open(struct inode *inode, struct file *filp)
191736bb6bb01a2a180b6f062e792bd03658d57ab7eAdrian Hunter{
192736bb6bb01a2a180b6f062e792bd03658d57ab7eAdrian Hunter	struct mmc_card *card = inode->i_private;
193736bb6bb01a2a180b6f062e792bd03658d57ab7eAdrian Hunter	char *buf;
194736bb6bb01a2a180b6f062e792bd03658d57ab7eAdrian Hunter	ssize_t n = 0;
195736bb6bb01a2a180b6f062e792bd03658d57ab7eAdrian Hunter	u8 *ext_csd;
196736bb6bb01a2a180b6f062e792bd03658d57ab7eAdrian Hunter	int err, i;
197736bb6bb01a2a180b6f062e792bd03658d57ab7eAdrian Hunter
198736bb6bb01a2a180b6f062e792bd03658d57ab7eAdrian Hunter	buf = kmalloc(EXT_CSD_STR_LEN + 1, GFP_KERNEL);
199736bb6bb01a2a180b6f062e792bd03658d57ab7eAdrian Hunter	if (!buf)
200736bb6bb01a2a180b6f062e792bd03658d57ab7eAdrian Hunter		return -ENOMEM;
201736bb6bb01a2a180b6f062e792bd03658d57ab7eAdrian Hunter
202736bb6bb01a2a180b6f062e792bd03658d57ab7eAdrian Hunter	ext_csd = kmalloc(512, GFP_KERNEL);
203736bb6bb01a2a180b6f062e792bd03658d57ab7eAdrian Hunter	if (!ext_csd) {
204736bb6bb01a2a180b6f062e792bd03658d57ab7eAdrian Hunter		err = -ENOMEM;
205736bb6bb01a2a180b6f062e792bd03658d57ab7eAdrian Hunter		goto out_free;
206736bb6bb01a2a180b6f062e792bd03658d57ab7eAdrian Hunter	}
207736bb6bb01a2a180b6f062e792bd03658d57ab7eAdrian Hunter
208736bb6bb01a2a180b6f062e792bd03658d57ab7eAdrian Hunter	mmc_claim_host(card->host);
209736bb6bb01a2a180b6f062e792bd03658d57ab7eAdrian Hunter	err = mmc_send_ext_csd(card, ext_csd);
210736bb6bb01a2a180b6f062e792bd03658d57ab7eAdrian Hunter	mmc_release_host(card->host);
211736bb6bb01a2a180b6f062e792bd03658d57ab7eAdrian Hunter	if (err)
212736bb6bb01a2a180b6f062e792bd03658d57ab7eAdrian Hunter		goto out_free;
213736bb6bb01a2a180b6f062e792bd03658d57ab7eAdrian Hunter
214736bb6bb01a2a180b6f062e792bd03658d57ab7eAdrian Hunter	for (i = 511; i >= 0; i--)
215736bb6bb01a2a180b6f062e792bd03658d57ab7eAdrian Hunter		n += sprintf(buf + n, "%02x", ext_csd[i]);
216736bb6bb01a2a180b6f062e792bd03658d57ab7eAdrian Hunter	n += sprintf(buf + n, "\n");
217736bb6bb01a2a180b6f062e792bd03658d57ab7eAdrian Hunter	BUG_ON(n != EXT_CSD_STR_LEN);
218736bb6bb01a2a180b6f062e792bd03658d57ab7eAdrian Hunter
219736bb6bb01a2a180b6f062e792bd03658d57ab7eAdrian Hunter	filp->private_data = buf;
220736bb6bb01a2a180b6f062e792bd03658d57ab7eAdrian Hunter	kfree(ext_csd);
221736bb6bb01a2a180b6f062e792bd03658d57ab7eAdrian Hunter	return 0;
222736bb6bb01a2a180b6f062e792bd03658d57ab7eAdrian Hunter
223736bb6bb01a2a180b6f062e792bd03658d57ab7eAdrian Hunterout_free:
224736bb6bb01a2a180b6f062e792bd03658d57ab7eAdrian Hunter	kfree(buf);
225736bb6bb01a2a180b6f062e792bd03658d57ab7eAdrian Hunter	kfree(ext_csd);
226736bb6bb01a2a180b6f062e792bd03658d57ab7eAdrian Hunter	return err;
227736bb6bb01a2a180b6f062e792bd03658d57ab7eAdrian Hunter}
228736bb6bb01a2a180b6f062e792bd03658d57ab7eAdrian Hunter
229736bb6bb01a2a180b6f062e792bd03658d57ab7eAdrian Hunterstatic ssize_t mmc_ext_csd_read(struct file *filp, char __user *ubuf,
230736bb6bb01a2a180b6f062e792bd03658d57ab7eAdrian Hunter				size_t cnt, loff_t *ppos)
231736bb6bb01a2a180b6f062e792bd03658d57ab7eAdrian Hunter{
232736bb6bb01a2a180b6f062e792bd03658d57ab7eAdrian Hunter	char *buf = filp->private_data;
233736bb6bb01a2a180b6f062e792bd03658d57ab7eAdrian Hunter
234736bb6bb01a2a180b6f062e792bd03658d57ab7eAdrian Hunter	return simple_read_from_buffer(ubuf, cnt, ppos,
235736bb6bb01a2a180b6f062e792bd03658d57ab7eAdrian Hunter				       buf, EXT_CSD_STR_LEN);
236736bb6bb01a2a180b6f062e792bd03658d57ab7eAdrian Hunter}
237736bb6bb01a2a180b6f062e792bd03658d57ab7eAdrian Hunter
238736bb6bb01a2a180b6f062e792bd03658d57ab7eAdrian Hunterstatic int mmc_ext_csd_release(struct inode *inode, struct file *file)
239736bb6bb01a2a180b6f062e792bd03658d57ab7eAdrian Hunter{
240736bb6bb01a2a180b6f062e792bd03658d57ab7eAdrian Hunter	kfree(file->private_data);
241736bb6bb01a2a180b6f062e792bd03658d57ab7eAdrian Hunter	return 0;
242736bb6bb01a2a180b6f062e792bd03658d57ab7eAdrian Hunter}
243736bb6bb01a2a180b6f062e792bd03658d57ab7eAdrian Hunter
244828c09509b9695271bcbdc53e9fc9a6a737148d2Alexey Dobriyanstatic const struct file_operations mmc_dbg_ext_csd_fops = {
245736bb6bb01a2a180b6f062e792bd03658d57ab7eAdrian Hunter	.open		= mmc_ext_csd_open,
246736bb6bb01a2a180b6f062e792bd03658d57ab7eAdrian Hunter	.read		= mmc_ext_csd_read,
247736bb6bb01a2a180b6f062e792bd03658d57ab7eAdrian Hunter	.release	= mmc_ext_csd_release,
2486038f373a3dc1f1c26496e60b6c40b164716f07eArnd Bergmann	.llseek		= default_llseek,
249736bb6bb01a2a180b6f062e792bd03658d57ab7eAdrian Hunter};
250736bb6bb01a2a180b6f062e792bd03658d57ab7eAdrian Hunter
251f4b7f927b531ca350cfc4ca1bdc3377dac7f9a32Haavard Skinnemoenvoid mmc_add_card_debugfs(struct mmc_card *card)
252f4b7f927b531ca350cfc4ca1bdc3377dac7f9a32Haavard Skinnemoen{
253f4b7f927b531ca350cfc4ca1bdc3377dac7f9a32Haavard Skinnemoen	struct mmc_host	*host = card->host;
254f4b7f927b531ca350cfc4ca1bdc3377dac7f9a32Haavard Skinnemoen	struct dentry	*root;
255f4b7f927b531ca350cfc4ca1bdc3377dac7f9a32Haavard Skinnemoen
256f4b7f927b531ca350cfc4ca1bdc3377dac7f9a32Haavard Skinnemoen	if (!host->debugfs_root)
257f4b7f927b531ca350cfc4ca1bdc3377dac7f9a32Haavard Skinnemoen		return;
258f4b7f927b531ca350cfc4ca1bdc3377dac7f9a32Haavard Skinnemoen
259f4b7f927b531ca350cfc4ca1bdc3377dac7f9a32Haavard Skinnemoen	root = debugfs_create_dir(mmc_card_id(card), host->debugfs_root);
260f4b7f927b531ca350cfc4ca1bdc3377dac7f9a32Haavard Skinnemoen	if (IS_ERR(root))
261f4b7f927b531ca350cfc4ca1bdc3377dac7f9a32Haavard Skinnemoen		/* Don't complain -- debugfs just isn't enabled */
262f4b7f927b531ca350cfc4ca1bdc3377dac7f9a32Haavard Skinnemoen		return;
263f4b7f927b531ca350cfc4ca1bdc3377dac7f9a32Haavard Skinnemoen	if (!root)
264f4b7f927b531ca350cfc4ca1bdc3377dac7f9a32Haavard Skinnemoen		/* Complain -- debugfs is enabled, but it failed to
265f4b7f927b531ca350cfc4ca1bdc3377dac7f9a32Haavard Skinnemoen		 * create the directory. */
266f4b7f927b531ca350cfc4ca1bdc3377dac7f9a32Haavard Skinnemoen		goto err;
267f4b7f927b531ca350cfc4ca1bdc3377dac7f9a32Haavard Skinnemoen
268f4b7f927b531ca350cfc4ca1bdc3377dac7f9a32Haavard Skinnemoen	card->debugfs_root = root;
269f4b7f927b531ca350cfc4ca1bdc3377dac7f9a32Haavard Skinnemoen
270f4b7f927b531ca350cfc4ca1bdc3377dac7f9a32Haavard Skinnemoen	if (!debugfs_create_x32("state", S_IRUSR, root, &card->state))
271f4b7f927b531ca350cfc4ca1bdc3377dac7f9a32Haavard Skinnemoen		goto err;
272f4b7f927b531ca350cfc4ca1bdc3377dac7f9a32Haavard Skinnemoen
273f4b7f927b531ca350cfc4ca1bdc3377dac7f9a32Haavard Skinnemoen	if (mmc_card_mmc(card) || mmc_card_sd(card))
274f4b7f927b531ca350cfc4ca1bdc3377dac7f9a32Haavard Skinnemoen		if (!debugfs_create_file("status", S_IRUSR, root, card,
275f4b7f927b531ca350cfc4ca1bdc3377dac7f9a32Haavard Skinnemoen					&mmc_dbg_card_status_fops))
276f4b7f927b531ca350cfc4ca1bdc3377dac7f9a32Haavard Skinnemoen			goto err;
277f4b7f927b531ca350cfc4ca1bdc3377dac7f9a32Haavard Skinnemoen
278736bb6bb01a2a180b6f062e792bd03658d57ab7eAdrian Hunter	if (mmc_card_mmc(card))
279736bb6bb01a2a180b6f062e792bd03658d57ab7eAdrian Hunter		if (!debugfs_create_file("ext_csd", S_IRUSR, root, card,
280736bb6bb01a2a180b6f062e792bd03658d57ab7eAdrian Hunter					&mmc_dbg_ext_csd_fops))
281736bb6bb01a2a180b6f062e792bd03658d57ab7eAdrian Hunter			goto err;
282736bb6bb01a2a180b6f062e792bd03658d57ab7eAdrian Hunter
283f4b7f927b531ca350cfc4ca1bdc3377dac7f9a32Haavard Skinnemoen	return;
284f4b7f927b531ca350cfc4ca1bdc3377dac7f9a32Haavard Skinnemoen
285f4b7f927b531ca350cfc4ca1bdc3377dac7f9a32Haavard Skinnemoenerr:
286f4b7f927b531ca350cfc4ca1bdc3377dac7f9a32Haavard Skinnemoen	debugfs_remove_recursive(root);
287f4b7f927b531ca350cfc4ca1bdc3377dac7f9a32Haavard Skinnemoen	card->debugfs_root = NULL;
288f4b7f927b531ca350cfc4ca1bdc3377dac7f9a32Haavard Skinnemoen	dev_err(&card->dev, "failed to initialize debugfs\n");
289f4b7f927b531ca350cfc4ca1bdc3377dac7f9a32Haavard Skinnemoen}
290f4b7f927b531ca350cfc4ca1bdc3377dac7f9a32Haavard Skinnemoen
291f4b7f927b531ca350cfc4ca1bdc3377dac7f9a32Haavard Skinnemoenvoid mmc_remove_card_debugfs(struct mmc_card *card)
292f4b7f927b531ca350cfc4ca1bdc3377dac7f9a32Haavard Skinnemoen{
293f4b7f927b531ca350cfc4ca1bdc3377dac7f9a32Haavard Skinnemoen	debugfs_remove_recursive(card->debugfs_root);
294f4b7f927b531ca350cfc4ca1bdc3377dac7f9a32Haavard Skinnemoen}
295