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 */
103f102ae926c01bccc9520a62cff833fde889ed6aStephen Rothwell#include <linux/moduleparam.h>
113ef77af154b03776c6c662c68c6332719e9eecacPaul Gortmaker#include <linux/export.h>
126edd8ee60ac9b974bd6ec3b1bcb2aab02762fa8cHaavard Skinnemoen#include <linux/debugfs.h>
136edd8ee60ac9b974bd6ec3b1bcb2aab02762fa8cHaavard Skinnemoen#include <linux/fs.h>
146edd8ee60ac9b974bd6ec3b1bcb2aab02762fa8cHaavard Skinnemoen#include <linux/seq_file.h>
155a0e3ad6af8660be21ca98a971cd00f331318c05Tejun Heo#include <linux/slab.h>
166edd8ee60ac9b974bd6ec3b1bcb2aab02762fa8cHaavard Skinnemoen#include <linux/stat.h>
171b676f70c108cda90cf9d114d16c677584400efcPer Forlin#include <linux/fault-inject.h>
186edd8ee60ac9b974bd6ec3b1bcb2aab02762fa8cHaavard Skinnemoen
19f4b7f927b531ca350cfc4ca1bdc3377dac7f9a32Haavard Skinnemoen#include <linux/mmc/card.h>
206edd8ee60ac9b974bd6ec3b1bcb2aab02762fa8cHaavard Skinnemoen#include <linux/mmc/host.h>
216edd8ee60ac9b974bd6ec3b1bcb2aab02762fa8cHaavard Skinnemoen
226edd8ee60ac9b974bd6ec3b1bcb2aab02762fa8cHaavard Skinnemoen#include "core.h"
23f4b7f927b531ca350cfc4ca1bdc3377dac7f9a32Haavard Skinnemoen#include "mmc_ops.h"
246edd8ee60ac9b974bd6ec3b1bcb2aab02762fa8cHaavard Skinnemoen
2534f5050800d600551cca9bcfb463cc6699d82d04Per Forlin#ifdef CONFIG_FAIL_MMC_REQUEST
2634f5050800d600551cca9bcfb463cc6699d82d04Per Forlin
2734f5050800d600551cca9bcfb463cc6699d82d04Per Forlinstatic DECLARE_FAULT_ATTR(fail_default_attr);
2834f5050800d600551cca9bcfb463cc6699d82d04Per Forlinstatic char *fail_request;
2934f5050800d600551cca9bcfb463cc6699d82d04Per Forlinmodule_param(fail_request, charp, 0);
3034f5050800d600551cca9bcfb463cc6699d82d04Per Forlin
3134f5050800d600551cca9bcfb463cc6699d82d04Per Forlin#endif /* CONFIG_FAIL_MMC_REQUEST */
3234f5050800d600551cca9bcfb463cc6699d82d04Per Forlin
336edd8ee60ac9b974bd6ec3b1bcb2aab02762fa8cHaavard Skinnemoen/* The debugfs functions are optimized away when CONFIG_DEBUG_FS isn't set. */
346edd8ee60ac9b974bd6ec3b1bcb2aab02762fa8cHaavard Skinnemoenstatic int mmc_ios_show(struct seq_file *s, void *data)
356edd8ee60ac9b974bd6ec3b1bcb2aab02762fa8cHaavard Skinnemoen{
366edd8ee60ac9b974bd6ec3b1bcb2aab02762fa8cHaavard Skinnemoen	static const char *vdd_str[] = {
376edd8ee60ac9b974bd6ec3b1bcb2aab02762fa8cHaavard Skinnemoen		[8]	= "2.0",
386edd8ee60ac9b974bd6ec3b1bcb2aab02762fa8cHaavard Skinnemoen		[9]	= "2.1",
396edd8ee60ac9b974bd6ec3b1bcb2aab02762fa8cHaavard Skinnemoen		[10]	= "2.2",
406edd8ee60ac9b974bd6ec3b1bcb2aab02762fa8cHaavard Skinnemoen		[11]	= "2.3",
416edd8ee60ac9b974bd6ec3b1bcb2aab02762fa8cHaavard Skinnemoen		[12]	= "2.4",
426edd8ee60ac9b974bd6ec3b1bcb2aab02762fa8cHaavard Skinnemoen		[13]	= "2.5",
436edd8ee60ac9b974bd6ec3b1bcb2aab02762fa8cHaavard Skinnemoen		[14]	= "2.6",
446edd8ee60ac9b974bd6ec3b1bcb2aab02762fa8cHaavard Skinnemoen		[15]	= "2.7",
456edd8ee60ac9b974bd6ec3b1bcb2aab02762fa8cHaavard Skinnemoen		[16]	= "2.8",
466edd8ee60ac9b974bd6ec3b1bcb2aab02762fa8cHaavard Skinnemoen		[17]	= "2.9",
476edd8ee60ac9b974bd6ec3b1bcb2aab02762fa8cHaavard Skinnemoen		[18]	= "3.0",
486edd8ee60ac9b974bd6ec3b1bcb2aab02762fa8cHaavard Skinnemoen		[19]	= "3.1",
496edd8ee60ac9b974bd6ec3b1bcb2aab02762fa8cHaavard Skinnemoen		[20]	= "3.2",
506edd8ee60ac9b974bd6ec3b1bcb2aab02762fa8cHaavard Skinnemoen		[21]	= "3.3",
516edd8ee60ac9b974bd6ec3b1bcb2aab02762fa8cHaavard Skinnemoen		[22]	= "3.4",
526edd8ee60ac9b974bd6ec3b1bcb2aab02762fa8cHaavard Skinnemoen		[23]	= "3.5",
536edd8ee60ac9b974bd6ec3b1bcb2aab02762fa8cHaavard Skinnemoen		[24]	= "3.6",
546edd8ee60ac9b974bd6ec3b1bcb2aab02762fa8cHaavard Skinnemoen	};
556edd8ee60ac9b974bd6ec3b1bcb2aab02762fa8cHaavard Skinnemoen	struct mmc_host	*host = s->private;
566edd8ee60ac9b974bd6ec3b1bcb2aab02762fa8cHaavard Skinnemoen	struct mmc_ios	*ios = &host->ios;
576edd8ee60ac9b974bd6ec3b1bcb2aab02762fa8cHaavard Skinnemoen	const char *str;
586edd8ee60ac9b974bd6ec3b1bcb2aab02762fa8cHaavard Skinnemoen
596edd8ee60ac9b974bd6ec3b1bcb2aab02762fa8cHaavard Skinnemoen	seq_printf(s, "clock:\t\t%u Hz\n", ios->clock);
60df16219f365f7f5a2d88a6e123251d57255cca3fGiuseppe CAVALLARO	if (host->actual_clock)
61df16219f365f7f5a2d88a6e123251d57255cca3fGiuseppe CAVALLARO		seq_printf(s, "actual clock:\t%u Hz\n", host->actual_clock);
626edd8ee60ac9b974bd6ec3b1bcb2aab02762fa8cHaavard Skinnemoen	seq_printf(s, "vdd:\t\t%u ", ios->vdd);
636edd8ee60ac9b974bd6ec3b1bcb2aab02762fa8cHaavard Skinnemoen	if ((1 << ios->vdd) & MMC_VDD_165_195)
646edd8ee60ac9b974bd6ec3b1bcb2aab02762fa8cHaavard Skinnemoen		seq_printf(s, "(1.65 - 1.95 V)\n");
656edd8ee60ac9b974bd6ec3b1bcb2aab02762fa8cHaavard Skinnemoen	else if (ios->vdd < (ARRAY_SIZE(vdd_str) - 1)
666edd8ee60ac9b974bd6ec3b1bcb2aab02762fa8cHaavard Skinnemoen			&& vdd_str[ios->vdd] && vdd_str[ios->vdd + 1])
676edd8ee60ac9b974bd6ec3b1bcb2aab02762fa8cHaavard Skinnemoen		seq_printf(s, "(%s ~ %s V)\n", vdd_str[ios->vdd],
686edd8ee60ac9b974bd6ec3b1bcb2aab02762fa8cHaavard Skinnemoen				vdd_str[ios->vdd + 1]);
696edd8ee60ac9b974bd6ec3b1bcb2aab02762fa8cHaavard Skinnemoen	else
706edd8ee60ac9b974bd6ec3b1bcb2aab02762fa8cHaavard Skinnemoen		seq_printf(s, "(invalid)\n");
716edd8ee60ac9b974bd6ec3b1bcb2aab02762fa8cHaavard Skinnemoen
726edd8ee60ac9b974bd6ec3b1bcb2aab02762fa8cHaavard Skinnemoen	switch (ios->bus_mode) {
736edd8ee60ac9b974bd6ec3b1bcb2aab02762fa8cHaavard Skinnemoen	case MMC_BUSMODE_OPENDRAIN:
746edd8ee60ac9b974bd6ec3b1bcb2aab02762fa8cHaavard Skinnemoen		str = "open drain";
756edd8ee60ac9b974bd6ec3b1bcb2aab02762fa8cHaavard Skinnemoen		break;
766edd8ee60ac9b974bd6ec3b1bcb2aab02762fa8cHaavard Skinnemoen	case MMC_BUSMODE_PUSHPULL:
776edd8ee60ac9b974bd6ec3b1bcb2aab02762fa8cHaavard Skinnemoen		str = "push-pull";
786edd8ee60ac9b974bd6ec3b1bcb2aab02762fa8cHaavard Skinnemoen		break;
796edd8ee60ac9b974bd6ec3b1bcb2aab02762fa8cHaavard Skinnemoen	default:
806edd8ee60ac9b974bd6ec3b1bcb2aab02762fa8cHaavard Skinnemoen		str = "invalid";
816edd8ee60ac9b974bd6ec3b1bcb2aab02762fa8cHaavard Skinnemoen		break;
826edd8ee60ac9b974bd6ec3b1bcb2aab02762fa8cHaavard Skinnemoen	}
836edd8ee60ac9b974bd6ec3b1bcb2aab02762fa8cHaavard Skinnemoen	seq_printf(s, "bus mode:\t%u (%s)\n", ios->bus_mode, str);
846edd8ee60ac9b974bd6ec3b1bcb2aab02762fa8cHaavard Skinnemoen
856edd8ee60ac9b974bd6ec3b1bcb2aab02762fa8cHaavard Skinnemoen	switch (ios->chip_select) {
866edd8ee60ac9b974bd6ec3b1bcb2aab02762fa8cHaavard Skinnemoen	case MMC_CS_DONTCARE:
876edd8ee60ac9b974bd6ec3b1bcb2aab02762fa8cHaavard Skinnemoen		str = "don't care";
886edd8ee60ac9b974bd6ec3b1bcb2aab02762fa8cHaavard Skinnemoen		break;
896edd8ee60ac9b974bd6ec3b1bcb2aab02762fa8cHaavard Skinnemoen	case MMC_CS_HIGH:
906edd8ee60ac9b974bd6ec3b1bcb2aab02762fa8cHaavard Skinnemoen		str = "active high";
916edd8ee60ac9b974bd6ec3b1bcb2aab02762fa8cHaavard Skinnemoen		break;
926edd8ee60ac9b974bd6ec3b1bcb2aab02762fa8cHaavard Skinnemoen	case MMC_CS_LOW:
936edd8ee60ac9b974bd6ec3b1bcb2aab02762fa8cHaavard Skinnemoen		str = "active low";
946edd8ee60ac9b974bd6ec3b1bcb2aab02762fa8cHaavard Skinnemoen		break;
956edd8ee60ac9b974bd6ec3b1bcb2aab02762fa8cHaavard Skinnemoen	default:
966edd8ee60ac9b974bd6ec3b1bcb2aab02762fa8cHaavard Skinnemoen		str = "invalid";
976edd8ee60ac9b974bd6ec3b1bcb2aab02762fa8cHaavard Skinnemoen		break;
986edd8ee60ac9b974bd6ec3b1bcb2aab02762fa8cHaavard Skinnemoen	}
996edd8ee60ac9b974bd6ec3b1bcb2aab02762fa8cHaavard Skinnemoen	seq_printf(s, "chip select:\t%u (%s)\n", ios->chip_select, str);
1006edd8ee60ac9b974bd6ec3b1bcb2aab02762fa8cHaavard Skinnemoen
1016edd8ee60ac9b974bd6ec3b1bcb2aab02762fa8cHaavard Skinnemoen	switch (ios->power_mode) {
1026edd8ee60ac9b974bd6ec3b1bcb2aab02762fa8cHaavard Skinnemoen	case MMC_POWER_OFF:
1036edd8ee60ac9b974bd6ec3b1bcb2aab02762fa8cHaavard Skinnemoen		str = "off";
1046edd8ee60ac9b974bd6ec3b1bcb2aab02762fa8cHaavard Skinnemoen		break;
1056edd8ee60ac9b974bd6ec3b1bcb2aab02762fa8cHaavard Skinnemoen	case MMC_POWER_UP:
1066edd8ee60ac9b974bd6ec3b1bcb2aab02762fa8cHaavard Skinnemoen		str = "up";
1076edd8ee60ac9b974bd6ec3b1bcb2aab02762fa8cHaavard Skinnemoen		break;
1086edd8ee60ac9b974bd6ec3b1bcb2aab02762fa8cHaavard Skinnemoen	case MMC_POWER_ON:
1096edd8ee60ac9b974bd6ec3b1bcb2aab02762fa8cHaavard Skinnemoen		str = "on";
1106edd8ee60ac9b974bd6ec3b1bcb2aab02762fa8cHaavard Skinnemoen		break;
1116edd8ee60ac9b974bd6ec3b1bcb2aab02762fa8cHaavard Skinnemoen	default:
1126edd8ee60ac9b974bd6ec3b1bcb2aab02762fa8cHaavard Skinnemoen		str = "invalid";
1136edd8ee60ac9b974bd6ec3b1bcb2aab02762fa8cHaavard Skinnemoen		break;
1146edd8ee60ac9b974bd6ec3b1bcb2aab02762fa8cHaavard Skinnemoen	}
1156edd8ee60ac9b974bd6ec3b1bcb2aab02762fa8cHaavard Skinnemoen	seq_printf(s, "power mode:\t%u (%s)\n", ios->power_mode, str);
1166edd8ee60ac9b974bd6ec3b1bcb2aab02762fa8cHaavard Skinnemoen	seq_printf(s, "bus width:\t%u (%u bits)\n",
1176edd8ee60ac9b974bd6ec3b1bcb2aab02762fa8cHaavard Skinnemoen			ios->bus_width, 1 << ios->bus_width);
1186edd8ee60ac9b974bd6ec3b1bcb2aab02762fa8cHaavard Skinnemoen
1196edd8ee60ac9b974bd6ec3b1bcb2aab02762fa8cHaavard Skinnemoen	switch (ios->timing) {
1206edd8ee60ac9b974bd6ec3b1bcb2aab02762fa8cHaavard Skinnemoen	case MMC_TIMING_LEGACY:
1216edd8ee60ac9b974bd6ec3b1bcb2aab02762fa8cHaavard Skinnemoen		str = "legacy";
1226edd8ee60ac9b974bd6ec3b1bcb2aab02762fa8cHaavard Skinnemoen		break;
1236edd8ee60ac9b974bd6ec3b1bcb2aab02762fa8cHaavard Skinnemoen	case MMC_TIMING_MMC_HS:
1246edd8ee60ac9b974bd6ec3b1bcb2aab02762fa8cHaavard Skinnemoen		str = "mmc high-speed";
1256edd8ee60ac9b974bd6ec3b1bcb2aab02762fa8cHaavard Skinnemoen		break;
1266edd8ee60ac9b974bd6ec3b1bcb2aab02762fa8cHaavard Skinnemoen	case MMC_TIMING_SD_HS:
1276edd8ee60ac9b974bd6ec3b1bcb2aab02762fa8cHaavard Skinnemoen		str = "sd high-speed";
1286edd8ee60ac9b974bd6ec3b1bcb2aab02762fa8cHaavard Skinnemoen		break;
129cd8a3666987ba20908bbeb7c78ed9ba82b365643Aaron Lu	case MMC_TIMING_UHS_SDR50:
130cd8a3666987ba20908bbeb7c78ed9ba82b365643Aaron Lu		str = "sd uhs SDR50";
131cd8a3666987ba20908bbeb7c78ed9ba82b365643Aaron Lu		break;
132cd8a3666987ba20908bbeb7c78ed9ba82b365643Aaron Lu	case MMC_TIMING_UHS_SDR104:
133cd8a3666987ba20908bbeb7c78ed9ba82b365643Aaron Lu		str = "sd uhs SDR104";
134cd8a3666987ba20908bbeb7c78ed9ba82b365643Aaron Lu		break;
135cd8a3666987ba20908bbeb7c78ed9ba82b365643Aaron Lu	case MMC_TIMING_UHS_DDR50:
136cd8a3666987ba20908bbeb7c78ed9ba82b365643Aaron Lu		str = "sd uhs DDR50";
137cd8a3666987ba20908bbeb7c78ed9ba82b365643Aaron Lu		break;
13879f7ae7c45a6ccf04e2908337461dee615f6afb0Seungwon Jeon	case MMC_TIMING_MMC_DDR52:
13979f7ae7c45a6ccf04e2908337461dee615f6afb0Seungwon Jeon		str = "mmc DDR52";
14079f7ae7c45a6ccf04e2908337461dee615f6afb0Seungwon Jeon		break;
141a4924c71aa43d4f8a3f342b1f71788349472e684Girish K S	case MMC_TIMING_MMC_HS200:
142577fb13199b11d8cd75609183649be4b5561243fSeungwon Jeon		str = "mmc HS200";
143a4924c71aa43d4f8a3f342b1f71788349472e684Girish K S		break;
1440a5b6438ee482696360bb013e67b8488f63d3e9eSeungwon Jeon	case MMC_TIMING_MMC_HS400:
1450a5b6438ee482696360bb013e67b8488f63d3e9eSeungwon Jeon		str = "mmc HS400";
1460a5b6438ee482696360bb013e67b8488f63d3e9eSeungwon Jeon		break;
1476edd8ee60ac9b974bd6ec3b1bcb2aab02762fa8cHaavard Skinnemoen	default:
1486edd8ee60ac9b974bd6ec3b1bcb2aab02762fa8cHaavard Skinnemoen		str = "invalid";
1496edd8ee60ac9b974bd6ec3b1bcb2aab02762fa8cHaavard Skinnemoen		break;
1506edd8ee60ac9b974bd6ec3b1bcb2aab02762fa8cHaavard Skinnemoen	}
1516edd8ee60ac9b974bd6ec3b1bcb2aab02762fa8cHaavard Skinnemoen	seq_printf(s, "timing spec:\t%u (%s)\n", ios->timing, str);
1526edd8ee60ac9b974bd6ec3b1bcb2aab02762fa8cHaavard Skinnemoen
15342cd95a0603e0497e7221816bb5ddfe861ee9325Johan Rudholm	switch (ios->signal_voltage) {
15442cd95a0603e0497e7221816bb5ddfe861ee9325Johan Rudholm	case MMC_SIGNAL_VOLTAGE_330:
15542cd95a0603e0497e7221816bb5ddfe861ee9325Johan Rudholm		str = "3.30 V";
15642cd95a0603e0497e7221816bb5ddfe861ee9325Johan Rudholm		break;
15742cd95a0603e0497e7221816bb5ddfe861ee9325Johan Rudholm	case MMC_SIGNAL_VOLTAGE_180:
15842cd95a0603e0497e7221816bb5ddfe861ee9325Johan Rudholm		str = "1.80 V";
15942cd95a0603e0497e7221816bb5ddfe861ee9325Johan Rudholm		break;
16042cd95a0603e0497e7221816bb5ddfe861ee9325Johan Rudholm	case MMC_SIGNAL_VOLTAGE_120:
16142cd95a0603e0497e7221816bb5ddfe861ee9325Johan Rudholm		str = "1.20 V";
16242cd95a0603e0497e7221816bb5ddfe861ee9325Johan Rudholm		break;
16342cd95a0603e0497e7221816bb5ddfe861ee9325Johan Rudholm	default:
16442cd95a0603e0497e7221816bb5ddfe861ee9325Johan Rudholm		str = "invalid";
16542cd95a0603e0497e7221816bb5ddfe861ee9325Johan Rudholm		break;
16642cd95a0603e0497e7221816bb5ddfe861ee9325Johan Rudholm	}
16742cd95a0603e0497e7221816bb5ddfe861ee9325Johan Rudholm	seq_printf(s, "signal voltage:\t%u (%s)\n", ios->chip_select, str);
16842cd95a0603e0497e7221816bb5ddfe861ee9325Johan Rudholm
1696edd8ee60ac9b974bd6ec3b1bcb2aab02762fa8cHaavard Skinnemoen	return 0;
1706edd8ee60ac9b974bd6ec3b1bcb2aab02762fa8cHaavard Skinnemoen}
1716edd8ee60ac9b974bd6ec3b1bcb2aab02762fa8cHaavard Skinnemoen
1726edd8ee60ac9b974bd6ec3b1bcb2aab02762fa8cHaavard Skinnemoenstatic int mmc_ios_open(struct inode *inode, struct file *file)
1736edd8ee60ac9b974bd6ec3b1bcb2aab02762fa8cHaavard Skinnemoen{
1746edd8ee60ac9b974bd6ec3b1bcb2aab02762fa8cHaavard Skinnemoen	return single_open(file, mmc_ios_show, inode->i_private);
1756edd8ee60ac9b974bd6ec3b1bcb2aab02762fa8cHaavard Skinnemoen}
1766edd8ee60ac9b974bd6ec3b1bcb2aab02762fa8cHaavard Skinnemoen
1776edd8ee60ac9b974bd6ec3b1bcb2aab02762fa8cHaavard Skinnemoenstatic const struct file_operations mmc_ios_fops = {
1786edd8ee60ac9b974bd6ec3b1bcb2aab02762fa8cHaavard Skinnemoen	.open		= mmc_ios_open,
1796edd8ee60ac9b974bd6ec3b1bcb2aab02762fa8cHaavard Skinnemoen	.read		= seq_read,
1806edd8ee60ac9b974bd6ec3b1bcb2aab02762fa8cHaavard Skinnemoen	.llseek		= seq_lseek,
1816edd8ee60ac9b974bd6ec3b1bcb2aab02762fa8cHaavard Skinnemoen	.release	= single_release,
1826edd8ee60ac9b974bd6ec3b1bcb2aab02762fa8cHaavard Skinnemoen};
1836edd8ee60ac9b974bd6ec3b1bcb2aab02762fa8cHaavard Skinnemoen
184703aae3d09a4b351866f1a97b2afafb905bdbf1eAndy Shevchenkostatic int mmc_clock_opt_get(void *data, u64 *val)
185703aae3d09a4b351866f1a97b2afafb905bdbf1eAndy Shevchenko{
186703aae3d09a4b351866f1a97b2afafb905bdbf1eAndy Shevchenko	struct mmc_host *host = data;
187703aae3d09a4b351866f1a97b2afafb905bdbf1eAndy Shevchenko
188703aae3d09a4b351866f1a97b2afafb905bdbf1eAndy Shevchenko	*val = host->ios.clock;
189703aae3d09a4b351866f1a97b2afafb905bdbf1eAndy Shevchenko
190703aae3d09a4b351866f1a97b2afafb905bdbf1eAndy Shevchenko	return 0;
191703aae3d09a4b351866f1a97b2afafb905bdbf1eAndy Shevchenko}
192703aae3d09a4b351866f1a97b2afafb905bdbf1eAndy Shevchenko
193703aae3d09a4b351866f1a97b2afafb905bdbf1eAndy Shevchenkostatic int mmc_clock_opt_set(void *data, u64 val)
194703aae3d09a4b351866f1a97b2afafb905bdbf1eAndy Shevchenko{
195703aae3d09a4b351866f1a97b2afafb905bdbf1eAndy Shevchenko	struct mmc_host *host = data;
196703aae3d09a4b351866f1a97b2afafb905bdbf1eAndy Shevchenko
197703aae3d09a4b351866f1a97b2afafb905bdbf1eAndy Shevchenko	/* We need this check due to input value is u64 */
198703aae3d09a4b351866f1a97b2afafb905bdbf1eAndy Shevchenko	if (val > host->f_max)
199703aae3d09a4b351866f1a97b2afafb905bdbf1eAndy Shevchenko		return -EINVAL;
200703aae3d09a4b351866f1a97b2afafb905bdbf1eAndy Shevchenko
201703aae3d09a4b351866f1a97b2afafb905bdbf1eAndy Shevchenko	mmc_claim_host(host);
202703aae3d09a4b351866f1a97b2afafb905bdbf1eAndy Shevchenko	mmc_set_clock(host, (unsigned int) val);
203703aae3d09a4b351866f1a97b2afafb905bdbf1eAndy Shevchenko	mmc_release_host(host);
204703aae3d09a4b351866f1a97b2afafb905bdbf1eAndy Shevchenko
205703aae3d09a4b351866f1a97b2afafb905bdbf1eAndy Shevchenko	return 0;
206703aae3d09a4b351866f1a97b2afafb905bdbf1eAndy Shevchenko}
207703aae3d09a4b351866f1a97b2afafb905bdbf1eAndy Shevchenko
208703aae3d09a4b351866f1a97b2afafb905bdbf1eAndy ShevchenkoDEFINE_SIMPLE_ATTRIBUTE(mmc_clock_fops, mmc_clock_opt_get, mmc_clock_opt_set,
209703aae3d09a4b351866f1a97b2afafb905bdbf1eAndy Shevchenko	"%llu\n");
210703aae3d09a4b351866f1a97b2afafb905bdbf1eAndy Shevchenko
2116edd8ee60ac9b974bd6ec3b1bcb2aab02762fa8cHaavard Skinnemoenvoid mmc_add_host_debugfs(struct mmc_host *host)
2126edd8ee60ac9b974bd6ec3b1bcb2aab02762fa8cHaavard Skinnemoen{
2136edd8ee60ac9b974bd6ec3b1bcb2aab02762fa8cHaavard Skinnemoen	struct dentry *root;
2146edd8ee60ac9b974bd6ec3b1bcb2aab02762fa8cHaavard Skinnemoen
2156edd8ee60ac9b974bd6ec3b1bcb2aab02762fa8cHaavard Skinnemoen	root = debugfs_create_dir(mmc_hostname(host), NULL);
2166edd8ee60ac9b974bd6ec3b1bcb2aab02762fa8cHaavard Skinnemoen	if (IS_ERR(root))
2176edd8ee60ac9b974bd6ec3b1bcb2aab02762fa8cHaavard Skinnemoen		/* Don't complain -- debugfs just isn't enabled */
2186edd8ee60ac9b974bd6ec3b1bcb2aab02762fa8cHaavard Skinnemoen		return;
2196edd8ee60ac9b974bd6ec3b1bcb2aab02762fa8cHaavard Skinnemoen	if (!root)
2206edd8ee60ac9b974bd6ec3b1bcb2aab02762fa8cHaavard Skinnemoen		/* Complain -- debugfs is enabled, but it failed to
2216edd8ee60ac9b974bd6ec3b1bcb2aab02762fa8cHaavard Skinnemoen		 * create the directory. */
2226edd8ee60ac9b974bd6ec3b1bcb2aab02762fa8cHaavard Skinnemoen		goto err_root;
2236edd8ee60ac9b974bd6ec3b1bcb2aab02762fa8cHaavard Skinnemoen
2246edd8ee60ac9b974bd6ec3b1bcb2aab02762fa8cHaavard Skinnemoen	host->debugfs_root = root;
2256edd8ee60ac9b974bd6ec3b1bcb2aab02762fa8cHaavard Skinnemoen
2266edd8ee60ac9b974bd6ec3b1bcb2aab02762fa8cHaavard Skinnemoen	if (!debugfs_create_file("ios", S_IRUSR, root, host, &mmc_ios_fops))
227703aae3d09a4b351866f1a97b2afafb905bdbf1eAndy Shevchenko		goto err_node;
228703aae3d09a4b351866f1a97b2afafb905bdbf1eAndy Shevchenko
229703aae3d09a4b351866f1a97b2afafb905bdbf1eAndy Shevchenko	if (!debugfs_create_file("clock", S_IRUSR | S_IWUSR, root, host,
230703aae3d09a4b351866f1a97b2afafb905bdbf1eAndy Shevchenko			&mmc_clock_fops))
231703aae3d09a4b351866f1a97b2afafb905bdbf1eAndy Shevchenko		goto err_node;
2326edd8ee60ac9b974bd6ec3b1bcb2aab02762fa8cHaavard Skinnemoen
23304566831a703ae3ef4b49a2deae261c9ed26e020Linus Walleij#ifdef CONFIG_MMC_CLKGATE
23404566831a703ae3ef4b49a2deae261c9ed26e020Linus Walleij	if (!debugfs_create_u32("clk_delay", (S_IRUSR | S_IWUSR),
23504566831a703ae3ef4b49a2deae261c9ed26e020Linus Walleij				root, &host->clk_delay))
23604566831a703ae3ef4b49a2deae261c9ed26e020Linus Walleij		goto err_node;
23704566831a703ae3ef4b49a2deae261c9ed26e020Linus Walleij#endif
2381b676f70c108cda90cf9d114d16c677584400efcPer Forlin#ifdef CONFIG_FAIL_MMC_REQUEST
23934f5050800d600551cca9bcfb463cc6699d82d04Per Forlin	if (fail_request)
24034f5050800d600551cca9bcfb463cc6699d82d04Per Forlin		setup_fault_attr(&fail_default_attr, fail_request);
24134f5050800d600551cca9bcfb463cc6699d82d04Per Forlin	host->fail_mmc_request = fail_default_attr;
2421b676f70c108cda90cf9d114d16c677584400efcPer Forlin	if (IS_ERR(fault_create_debugfs_attr("fail_mmc_request",
2431b676f70c108cda90cf9d114d16c677584400efcPer Forlin					     root,
2441b676f70c108cda90cf9d114d16c677584400efcPer Forlin					     &host->fail_mmc_request)))
2451b676f70c108cda90cf9d114d16c677584400efcPer Forlin		goto err_node;
2461b676f70c108cda90cf9d114d16c677584400efcPer Forlin#endif
2476edd8ee60ac9b974bd6ec3b1bcb2aab02762fa8cHaavard Skinnemoen	return;
2486edd8ee60ac9b974bd6ec3b1bcb2aab02762fa8cHaavard Skinnemoen
249703aae3d09a4b351866f1a97b2afafb905bdbf1eAndy Shevchenkoerr_node:
2506edd8ee60ac9b974bd6ec3b1bcb2aab02762fa8cHaavard Skinnemoen	debugfs_remove_recursive(root);
2516edd8ee60ac9b974bd6ec3b1bcb2aab02762fa8cHaavard Skinnemoen	host->debugfs_root = NULL;
2526edd8ee60ac9b974bd6ec3b1bcb2aab02762fa8cHaavard Skinnemoenerr_root:
2536edd8ee60ac9b974bd6ec3b1bcb2aab02762fa8cHaavard Skinnemoen	dev_err(&host->class_dev, "failed to initialize debugfs\n");
2546edd8ee60ac9b974bd6ec3b1bcb2aab02762fa8cHaavard Skinnemoen}
2556edd8ee60ac9b974bd6ec3b1bcb2aab02762fa8cHaavard Skinnemoen
2566edd8ee60ac9b974bd6ec3b1bcb2aab02762fa8cHaavard Skinnemoenvoid mmc_remove_host_debugfs(struct mmc_host *host)
2576edd8ee60ac9b974bd6ec3b1bcb2aab02762fa8cHaavard Skinnemoen{
2586edd8ee60ac9b974bd6ec3b1bcb2aab02762fa8cHaavard Skinnemoen	debugfs_remove_recursive(host->debugfs_root);
2596edd8ee60ac9b974bd6ec3b1bcb2aab02762fa8cHaavard Skinnemoen}
260f4b7f927b531ca350cfc4ca1bdc3377dac7f9a32Haavard Skinnemoen
261f4b7f927b531ca350cfc4ca1bdc3377dac7f9a32Haavard Skinnemoenstatic int mmc_dbg_card_status_get(void *data, u64 *val)
262f4b7f927b531ca350cfc4ca1bdc3377dac7f9a32Haavard Skinnemoen{
263f4b7f927b531ca350cfc4ca1bdc3377dac7f9a32Haavard Skinnemoen	struct mmc_card	*card = data;
264f4b7f927b531ca350cfc4ca1bdc3377dac7f9a32Haavard Skinnemoen	u32		status;
265f4b7f927b531ca350cfc4ca1bdc3377dac7f9a32Haavard Skinnemoen	int		ret;
266f4b7f927b531ca350cfc4ca1bdc3377dac7f9a32Haavard Skinnemoen
267e94cfef698aae6b209d8918dd319312e4b02118dUlf Hansson	mmc_get_card(card);
268f4b7f927b531ca350cfc4ca1bdc3377dac7f9a32Haavard Skinnemoen
269f4b7f927b531ca350cfc4ca1bdc3377dac7f9a32Haavard Skinnemoen	ret = mmc_send_status(data, &status);
270f4b7f927b531ca350cfc4ca1bdc3377dac7f9a32Haavard Skinnemoen	if (!ret)
271f4b7f927b531ca350cfc4ca1bdc3377dac7f9a32Haavard Skinnemoen		*val = status;
272f4b7f927b531ca350cfc4ca1bdc3377dac7f9a32Haavard Skinnemoen
273e94cfef698aae6b209d8918dd319312e4b02118dUlf Hansson	mmc_put_card(card);
274f4b7f927b531ca350cfc4ca1bdc3377dac7f9a32Haavard Skinnemoen
275f4b7f927b531ca350cfc4ca1bdc3377dac7f9a32Haavard Skinnemoen	return ret;
276f4b7f927b531ca350cfc4ca1bdc3377dac7f9a32Haavard Skinnemoen}
277f4b7f927b531ca350cfc4ca1bdc3377dac7f9a32Haavard SkinnemoenDEFINE_SIMPLE_ATTRIBUTE(mmc_dbg_card_status_fops, mmc_dbg_card_status_get,
278f4b7f927b531ca350cfc4ca1bdc3377dac7f9a32Haavard Skinnemoen		NULL, "%08llx\n");
279f4b7f927b531ca350cfc4ca1bdc3377dac7f9a32Haavard Skinnemoen
280736bb6bb01a2a180b6f062e792bd03658d57ab7eAdrian Hunter#define EXT_CSD_STR_LEN 1025
281736bb6bb01a2a180b6f062e792bd03658d57ab7eAdrian Hunter
282736bb6bb01a2a180b6f062e792bd03658d57ab7eAdrian Hunterstatic int mmc_ext_csd_open(struct inode *inode, struct file *filp)
283736bb6bb01a2a180b6f062e792bd03658d57ab7eAdrian Hunter{
284736bb6bb01a2a180b6f062e792bd03658d57ab7eAdrian Hunter	struct mmc_card *card = inode->i_private;
285736bb6bb01a2a180b6f062e792bd03658d57ab7eAdrian Hunter	char *buf;
286736bb6bb01a2a180b6f062e792bd03658d57ab7eAdrian Hunter	ssize_t n = 0;
287736bb6bb01a2a180b6f062e792bd03658d57ab7eAdrian Hunter	u8 *ext_csd;
288736bb6bb01a2a180b6f062e792bd03658d57ab7eAdrian Hunter	int err, i;
289736bb6bb01a2a180b6f062e792bd03658d57ab7eAdrian Hunter
290736bb6bb01a2a180b6f062e792bd03658d57ab7eAdrian Hunter	buf = kmalloc(EXT_CSD_STR_LEN + 1, GFP_KERNEL);
291736bb6bb01a2a180b6f062e792bd03658d57ab7eAdrian Hunter	if (!buf)
292736bb6bb01a2a180b6f062e792bd03658d57ab7eAdrian Hunter		return -ENOMEM;
293736bb6bb01a2a180b6f062e792bd03658d57ab7eAdrian Hunter
294736bb6bb01a2a180b6f062e792bd03658d57ab7eAdrian Hunter	ext_csd = kmalloc(512, GFP_KERNEL);
295736bb6bb01a2a180b6f062e792bd03658d57ab7eAdrian Hunter	if (!ext_csd) {
296736bb6bb01a2a180b6f062e792bd03658d57ab7eAdrian Hunter		err = -ENOMEM;
297736bb6bb01a2a180b6f062e792bd03658d57ab7eAdrian Hunter		goto out_free;
298736bb6bb01a2a180b6f062e792bd03658d57ab7eAdrian Hunter	}
299736bb6bb01a2a180b6f062e792bd03658d57ab7eAdrian Hunter
300e94cfef698aae6b209d8918dd319312e4b02118dUlf Hansson	mmc_get_card(card);
301736bb6bb01a2a180b6f062e792bd03658d57ab7eAdrian Hunter	err = mmc_send_ext_csd(card, ext_csd);
302e94cfef698aae6b209d8918dd319312e4b02118dUlf Hansson	mmc_put_card(card);
303736bb6bb01a2a180b6f062e792bd03658d57ab7eAdrian Hunter	if (err)
304736bb6bb01a2a180b6f062e792bd03658d57ab7eAdrian Hunter		goto out_free;
305736bb6bb01a2a180b6f062e792bd03658d57ab7eAdrian Hunter
3066780162c0097915dbc4e8fc11af662a270093d85Venkatraman S	for (i = 0; i < 512; i++)
307736bb6bb01a2a180b6f062e792bd03658d57ab7eAdrian Hunter		n += sprintf(buf + n, "%02x", ext_csd[i]);
308736bb6bb01a2a180b6f062e792bd03658d57ab7eAdrian Hunter	n += sprintf(buf + n, "\n");
309736bb6bb01a2a180b6f062e792bd03658d57ab7eAdrian Hunter	BUG_ON(n != EXT_CSD_STR_LEN);
310736bb6bb01a2a180b6f062e792bd03658d57ab7eAdrian Hunter
311736bb6bb01a2a180b6f062e792bd03658d57ab7eAdrian Hunter	filp->private_data = buf;
312736bb6bb01a2a180b6f062e792bd03658d57ab7eAdrian Hunter	kfree(ext_csd);
313736bb6bb01a2a180b6f062e792bd03658d57ab7eAdrian Hunter	return 0;
314736bb6bb01a2a180b6f062e792bd03658d57ab7eAdrian Hunter
315736bb6bb01a2a180b6f062e792bd03658d57ab7eAdrian Hunterout_free:
316736bb6bb01a2a180b6f062e792bd03658d57ab7eAdrian Hunter	kfree(buf);
317736bb6bb01a2a180b6f062e792bd03658d57ab7eAdrian Hunter	kfree(ext_csd);
318736bb6bb01a2a180b6f062e792bd03658d57ab7eAdrian Hunter	return err;
319736bb6bb01a2a180b6f062e792bd03658d57ab7eAdrian Hunter}
320736bb6bb01a2a180b6f062e792bd03658d57ab7eAdrian Hunter
321736bb6bb01a2a180b6f062e792bd03658d57ab7eAdrian Hunterstatic ssize_t mmc_ext_csd_read(struct file *filp, char __user *ubuf,
322736bb6bb01a2a180b6f062e792bd03658d57ab7eAdrian Hunter				size_t cnt, loff_t *ppos)
323736bb6bb01a2a180b6f062e792bd03658d57ab7eAdrian Hunter{
324736bb6bb01a2a180b6f062e792bd03658d57ab7eAdrian Hunter	char *buf = filp->private_data;
325736bb6bb01a2a180b6f062e792bd03658d57ab7eAdrian Hunter
326736bb6bb01a2a180b6f062e792bd03658d57ab7eAdrian Hunter	return simple_read_from_buffer(ubuf, cnt, ppos,
327736bb6bb01a2a180b6f062e792bd03658d57ab7eAdrian Hunter				       buf, EXT_CSD_STR_LEN);
328736bb6bb01a2a180b6f062e792bd03658d57ab7eAdrian Hunter}
329736bb6bb01a2a180b6f062e792bd03658d57ab7eAdrian Hunter
330736bb6bb01a2a180b6f062e792bd03658d57ab7eAdrian Hunterstatic int mmc_ext_csd_release(struct inode *inode, struct file *file)
331736bb6bb01a2a180b6f062e792bd03658d57ab7eAdrian Hunter{
332736bb6bb01a2a180b6f062e792bd03658d57ab7eAdrian Hunter	kfree(file->private_data);
333736bb6bb01a2a180b6f062e792bd03658d57ab7eAdrian Hunter	return 0;
334736bb6bb01a2a180b6f062e792bd03658d57ab7eAdrian Hunter}
335736bb6bb01a2a180b6f062e792bd03658d57ab7eAdrian Hunter
336828c09509b9695271bcbdc53e9fc9a6a737148d2Alexey Dobriyanstatic const struct file_operations mmc_dbg_ext_csd_fops = {
337736bb6bb01a2a180b6f062e792bd03658d57ab7eAdrian Hunter	.open		= mmc_ext_csd_open,
338736bb6bb01a2a180b6f062e792bd03658d57ab7eAdrian Hunter	.read		= mmc_ext_csd_read,
339736bb6bb01a2a180b6f062e792bd03658d57ab7eAdrian Hunter	.release	= mmc_ext_csd_release,
3406038f373a3dc1f1c26496e60b6c40b164716f07eArnd Bergmann	.llseek		= default_llseek,
341736bb6bb01a2a180b6f062e792bd03658d57ab7eAdrian Hunter};
342736bb6bb01a2a180b6f062e792bd03658d57ab7eAdrian Hunter
343f4b7f927b531ca350cfc4ca1bdc3377dac7f9a32Haavard Skinnemoenvoid mmc_add_card_debugfs(struct mmc_card *card)
344f4b7f927b531ca350cfc4ca1bdc3377dac7f9a32Haavard Skinnemoen{
345f4b7f927b531ca350cfc4ca1bdc3377dac7f9a32Haavard Skinnemoen	struct mmc_host	*host = card->host;
346f4b7f927b531ca350cfc4ca1bdc3377dac7f9a32Haavard Skinnemoen	struct dentry	*root;
347f4b7f927b531ca350cfc4ca1bdc3377dac7f9a32Haavard Skinnemoen
348f4b7f927b531ca350cfc4ca1bdc3377dac7f9a32Haavard Skinnemoen	if (!host->debugfs_root)
349f4b7f927b531ca350cfc4ca1bdc3377dac7f9a32Haavard Skinnemoen		return;
350f4b7f927b531ca350cfc4ca1bdc3377dac7f9a32Haavard Skinnemoen
351f4b7f927b531ca350cfc4ca1bdc3377dac7f9a32Haavard Skinnemoen	root = debugfs_create_dir(mmc_card_id(card), host->debugfs_root);
352f4b7f927b531ca350cfc4ca1bdc3377dac7f9a32Haavard Skinnemoen	if (IS_ERR(root))
353f4b7f927b531ca350cfc4ca1bdc3377dac7f9a32Haavard Skinnemoen		/* Don't complain -- debugfs just isn't enabled */
354f4b7f927b531ca350cfc4ca1bdc3377dac7f9a32Haavard Skinnemoen		return;
355f4b7f927b531ca350cfc4ca1bdc3377dac7f9a32Haavard Skinnemoen	if (!root)
356f4b7f927b531ca350cfc4ca1bdc3377dac7f9a32Haavard Skinnemoen		/* Complain -- debugfs is enabled, but it failed to
357f4b7f927b531ca350cfc4ca1bdc3377dac7f9a32Haavard Skinnemoen		 * create the directory. */
358f4b7f927b531ca350cfc4ca1bdc3377dac7f9a32Haavard Skinnemoen		goto err;
359f4b7f927b531ca350cfc4ca1bdc3377dac7f9a32Haavard Skinnemoen
360f4b7f927b531ca350cfc4ca1bdc3377dac7f9a32Haavard Skinnemoen	card->debugfs_root = root;
361f4b7f927b531ca350cfc4ca1bdc3377dac7f9a32Haavard Skinnemoen
362f4b7f927b531ca350cfc4ca1bdc3377dac7f9a32Haavard Skinnemoen	if (!debugfs_create_x32("state", S_IRUSR, root, &card->state))
363f4b7f927b531ca350cfc4ca1bdc3377dac7f9a32Haavard Skinnemoen		goto err;
364f4b7f927b531ca350cfc4ca1bdc3377dac7f9a32Haavard Skinnemoen
365f4b7f927b531ca350cfc4ca1bdc3377dac7f9a32Haavard Skinnemoen	if (mmc_card_mmc(card) || mmc_card_sd(card))
366f4b7f927b531ca350cfc4ca1bdc3377dac7f9a32Haavard Skinnemoen		if (!debugfs_create_file("status", S_IRUSR, root, card,
367f4b7f927b531ca350cfc4ca1bdc3377dac7f9a32Haavard Skinnemoen					&mmc_dbg_card_status_fops))
368f4b7f927b531ca350cfc4ca1bdc3377dac7f9a32Haavard Skinnemoen			goto err;
369f4b7f927b531ca350cfc4ca1bdc3377dac7f9a32Haavard Skinnemoen
370736bb6bb01a2a180b6f062e792bd03658d57ab7eAdrian Hunter	if (mmc_card_mmc(card))
371736bb6bb01a2a180b6f062e792bd03658d57ab7eAdrian Hunter		if (!debugfs_create_file("ext_csd", S_IRUSR, root, card,
372736bb6bb01a2a180b6f062e792bd03658d57ab7eAdrian Hunter					&mmc_dbg_ext_csd_fops))
373736bb6bb01a2a180b6f062e792bd03658d57ab7eAdrian Hunter			goto err;
374736bb6bb01a2a180b6f062e792bd03658d57ab7eAdrian Hunter
375f4b7f927b531ca350cfc4ca1bdc3377dac7f9a32Haavard Skinnemoen	return;
376f4b7f927b531ca350cfc4ca1bdc3377dac7f9a32Haavard Skinnemoen
377f4b7f927b531ca350cfc4ca1bdc3377dac7f9a32Haavard Skinnemoenerr:
378f4b7f927b531ca350cfc4ca1bdc3377dac7f9a32Haavard Skinnemoen	debugfs_remove_recursive(root);
379f4b7f927b531ca350cfc4ca1bdc3377dac7f9a32Haavard Skinnemoen	card->debugfs_root = NULL;
380f4b7f927b531ca350cfc4ca1bdc3377dac7f9a32Haavard Skinnemoen	dev_err(&card->dev, "failed to initialize debugfs\n");
381f4b7f927b531ca350cfc4ca1bdc3377dac7f9a32Haavard Skinnemoen}
382f4b7f927b531ca350cfc4ca1bdc3377dac7f9a32Haavard Skinnemoen
383f4b7f927b531ca350cfc4ca1bdc3377dac7f9a32Haavard Skinnemoenvoid mmc_remove_card_debugfs(struct mmc_card *card)
384f4b7f927b531ca350cfc4ca1bdc3377dac7f9a32Haavard Skinnemoen{
385f4b7f927b531ca350cfc4ca1bdc3377dac7f9a32Haavard Skinnemoen	debugfs_remove_recursive(card->debugfs_root);
386f4b7f927b531ca350cfc4ca1bdc3377dac7f9a32Haavard Skinnemoen}
387