Release 4.7 drivers/mmc/core/sd.c
  
  
/*
 *  linux/drivers/mmc/core/sd.c
 *
 *  Copyright (C) 2003-2004 Russell King, All Rights Reserved.
 *  SD support Copyright (C) 2004 Ian Molton, All Rights Reserved.
 *  Copyright (C) 2005-2007 Pierre Ossman, All Rights Reserved.
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License version 2 as
 * published by the Free Software Foundation.
 */
#include <linux/err.h>
#include <linux/sizes.h>
#include <linux/slab.h>
#include <linux/stat.h>
#include <linux/pm_runtime.h>
#include <linux/mmc/host.h>
#include <linux/mmc/card.h>
#include <linux/mmc/mmc.h>
#include <linux/mmc/sd.h>
#include "core.h"
#include "bus.h"
#include "mmc_ops.h"
#include "sd.h"
#include "sd_ops.h"
static const unsigned int tran_exp[] = {
	10000,		100000,		1000000,	10000000,
	0,		0,		0,		0
};
static const unsigned char tran_mant[] = {
	0,	10,	12,	13,	15,	20,	25,	30,
	35,	40,	45,	50,	55,	60,	70,	80,
};
static const unsigned int tacc_exp[] = {
	1,	10,	100,	1000,	10000,	100000,	1000000, 10000000,
};
static const unsigned int tacc_mant[] = {
	0,	10,	12,	13,	15,	20,	25,	30,
	35,	40,	45,	50,	55,	60,	70,	80,
};
static const unsigned int sd_au_size[] = {
	0,		SZ_16K / 512,		SZ_32K / 512,	SZ_64K / 512,
	SZ_128K / 512,	SZ_256K / 512,		SZ_512K / 512,	SZ_1M / 512,
	SZ_2M / 512,	SZ_4M / 512,		SZ_8M / 512,	(SZ_8M + SZ_4M) / 512,
	SZ_16M / 512,	(SZ_16M + SZ_8M) / 512,	SZ_32M / 512,	SZ_64M / 512,
};
#define UNSTUFF_BITS(resp,start,size)					\
	({                                                              \
                const int __size = size;                                \
                const u32 __mask = (__size < 32 ? 1 << __size : 0) - 1; \
                const int __off = 3 - ((start) / 32);                   \
                const int __shft = (start) & 31;                        \
                u32 __res;                                              \
                                                                        \
                __res = resp[__off] >> __shft;                          \
                if (__size + __shft > 32)                               \
                        __res |= resp[__off-1] << ((32 - __shft) % 32); \
                __res & __mask;                                         \
        })
/*
 * Given the decoded CSD structure, decode the raw CID to our CID structure.
 */
void mmc_decode_cid(struct mmc_card *card)
{
	u32 *resp = card->raw_cid;
	/*
         * SD doesn't currently have a version field so we will
         * have to assume we can parse this.
         */
	card->cid.manfid		= UNSTUFF_BITS(resp, 120, 8);
	card->cid.oemid			= UNSTUFF_BITS(resp, 104, 16);
	card->cid.prod_name[0]		= UNSTUFF_BITS(resp, 96, 8);
	card->cid.prod_name[1]		= UNSTUFF_BITS(resp, 88, 8);
	card->cid.prod_name[2]		= UNSTUFF_BITS(resp, 80, 8);
	card->cid.prod_name[3]		= UNSTUFF_BITS(resp, 72, 8);
	card->cid.prod_name[4]		= UNSTUFF_BITS(resp, 64, 8);
	card->cid.hwrev			= UNSTUFF_BITS(resp, 60, 4);
	card->cid.fwrev			= UNSTUFF_BITS(resp, 56, 4);
	card->cid.serial		= UNSTUFF_BITS(resp, 24, 32);
	card->cid.year			= UNSTUFF_BITS(resp, 12, 8);
	card->cid.month			= UNSTUFF_BITS(resp, 8, 4);
	card->cid.year += 2000; /* SD cards year offset */
}
Contributors
 | Person | Tokens | Prop | Commits | CommitProp | 
| pierre ossman | pierre ossman | 223 | 100.00% | 1 | 100.00% | 
 | Total | 223 | 100.00% | 1 | 100.00% | 
/*
 * Given a 128-bit response, decode to our card CSD structure.
 */
static int mmc_decode_csd(struct mmc_card *card)
{
	struct mmc_csd *csd = &card->csd;
	unsigned int e, m, csd_struct;
	u32 *resp = card->raw_csd;
	csd_struct = UNSTUFF_BITS(resp, 126, 2);
	switch (csd_struct) {
	case 0:
		m = UNSTUFF_BITS(resp, 115, 4);
		e = UNSTUFF_BITS(resp, 112, 3);
		csd->tacc_ns	 = (tacc_exp[e] * tacc_mant[m] + 9) / 10;
		csd->tacc_clks	 = UNSTUFF_BITS(resp, 104, 8) * 100;
		m = UNSTUFF_BITS(resp, 99, 4);
		e = UNSTUFF_BITS(resp, 96, 3);
		csd->max_dtr	  = tran_exp[e] * tran_mant[m];
		csd->cmdclass	  = UNSTUFF_BITS(resp, 84, 12);
		e = UNSTUFF_BITS(resp, 47, 3);
		m = UNSTUFF_BITS(resp, 62, 12);
		csd->capacity	  = (1 + m) << (e + 2);
		csd->read_blkbits = UNSTUFF_BITS(resp, 80, 4);
		csd->read_partial = UNSTUFF_BITS(resp, 79, 1);
		csd->write_misalign = UNSTUFF_BITS(resp, 78, 1);
		csd->read_misalign = UNSTUFF_BITS(resp, 77, 1);
		csd->dsr_imp = UNSTUFF_BITS(resp, 76, 1);
		csd->r2w_factor = UNSTUFF_BITS(resp, 26, 3);
		csd->write_blkbits = UNSTUFF_BITS(resp, 22, 4);
		csd->write_partial = UNSTUFF_BITS(resp, 21, 1);
		if (UNSTUFF_BITS(resp, 46, 1)) {
			csd->erase_size = 1;
		} else if (csd->write_blkbits >= 9) {
			csd->erase_size = UNSTUFF_BITS(resp, 39, 7) + 1;
			csd->erase_size <<= csd->write_blkbits - 9;
		}
		break;
	case 1:
		/*
                 * This is a block-addressed SDHC or SDXC card. Most
                 * interesting fields are unused and have fixed
                 * values. To avoid getting tripped by buggy cards,
                 * we assume those fixed values ourselves.
                 */
		mmc_card_set_blockaddr(card);
		csd->tacc_ns	 = 0; /* Unused */
		csd->tacc_clks	 = 0; /* Unused */
		m = UNSTUFF_BITS(resp, 99, 4);
		e = UNSTUFF_BITS(resp, 96, 3);
		csd->max_dtr	  = tran_exp[e] * tran_mant[m];
		csd->cmdclass	  = UNSTUFF_BITS(resp, 84, 12);
		csd->c_size	  = UNSTUFF_BITS(resp, 48, 22);
		/* SDXC cards have a minimum C_SIZE of 0x00FFFF */
		if (csd->c_size >= 0xFFFF)
			mmc_card_set_ext_capacity(card);
		m = UNSTUFF_BITS(resp, 48, 22);
		csd->capacity     = (1 + m) << 10;
		csd->read_blkbits = 9;
		csd->read_partial = 0;
		csd->write_misalign = 0;
		csd->read_misalign = 0;
		csd->r2w_factor = 4; /* Unused */
		csd->write_blkbits = 9;
		csd->write_partial = 0;
		csd->erase_size = 1;
		break;
	default:
		pr_err("%s: unrecognised CSD structure version %d\n",
			mmc_hostname(card->host), csd_struct);
		return -EINVAL;
	}
	card->erase_size = csd->erase_size;
	return 0;
}
Contributors
 | Person | Tokens | Prop | Commits | CommitProp | 
| pierre ossman | pierre ossman | 452 | 80.28% | 2 | 33.33% | 
| adrian hunter | adrian hunter | 69 | 12.26% | 1 | 16.67% | 
| arindam nath | arindam nath | 28 | 4.97% | 1 | 16.67% | 
| sascha hauer | sascha hauer | 13 | 2.31% | 1 | 16.67% | 
| girish k s | girish k s | 1 | 0.18% | 1 | 16.67% | 
 | Total | 563 | 100.00% | 6 | 100.00% | 
/*
 * Given a 64-bit response, decode to our card SCR structure.
 */
static int mmc_decode_scr(struct mmc_card *card)
{
	struct sd_scr *scr = &card->scr;
	unsigned int scr_struct;
	u32 resp[4];
	resp[3] = card->raw_scr[1];
	resp[2] = card->raw_scr[0];
	scr_struct = UNSTUFF_BITS(resp, 60, 4);
	if (scr_struct != 0) {
		pr_err("%s: unrecognised SCR structure version %d\n",
			mmc_hostname(card->host), scr_struct);
		return -EINVAL;
	}
	scr->sda_vsn = UNSTUFF_BITS(resp, 56, 4);
	scr->bus_widths = UNSTUFF_BITS(resp, 48, 4);
	if (scr->sda_vsn == SCR_SPEC_VER_2)
		/* Check if Physical Layer Spec v3.0 is supported */
		scr->sda_spec3 = UNSTUFF_BITS(resp, 47, 1);
	if (UNSTUFF_BITS(resp, 55, 1))
		card->erased_byte = 0xFF;
	else
		card->erased_byte = 0x0;
	if (scr->sda_spec3)
		scr->cmds = UNSTUFF_BITS(resp, 32, 2);
	return 0;
}
Contributors
 | Person | Tokens | Prop | Commits | CommitProp | 
| pierre ossman | pierre ossman | 120 | 64.52% | 2 | 33.33% | 
| adrian hunter | adrian hunter | 24 | 12.90% | 1 | 16.67% | 
| arindam nath | arindam nath | 22 | 11.83% | 1 | 16.67% | 
| andrei warkentin | andrei warkentin | 19 | 10.22% | 1 | 16.67% | 
| girish k s | girish k s | 1 | 0.54% | 1 | 16.67% | 
 | Total | 186 | 100.00% | 6 | 100.00% | 
/*
 * Fetch and process SD Status register.
 */
static int mmc_read_ssr(struct mmc_card *card)
{
	unsigned int au, es, et, eo;
	int err, i;
	u32 *ssr;
	if (!(card->csd.cmdclass & CCC_APP_SPEC)) {
		pr_warn("%s: card lacks mandatory SD Status function\n",
			mmc_hostname(card->host));
		return 0;
	}
	ssr = kmalloc(64, GFP_KERNEL);
	if (!ssr)
		return -ENOMEM;
	err = mmc_app_sd_status(card, ssr);
	if (err) {
		pr_warn("%s: problem reading SD Status register\n",
			mmc_hostname(card->host));
		err = 0;
		goto out;
	}
	for (i = 0; i < 16; i++)
		ssr[i] = be32_to_cpu(ssr[i]);
	/*
         * UNSTUFF_BITS only works with four u32s so we have to offset the
         * bitfield positions accordingly.
         */
	au = UNSTUFF_BITS(ssr, 428 - 384, 4);
	if (au) {
		if (au <= 9 || card->scr.sda_spec3) {
			card->ssr.au = sd_au_size[au];
			es = UNSTUFF_BITS(ssr, 408 - 384, 16);
			et = UNSTUFF_BITS(ssr, 402 - 384, 6);
			if (es && et) {
				eo = UNSTUFF_BITS(ssr, 400 - 384, 2);
				card->ssr.erase_timeout = (et * 1000) / es;
				card->ssr.erase_offset = eo * 1000;
			}
		} else {
			pr_warn("%s: SD Status: Invalid Allocation Unit size\n",
				mmc_hostname(card->host));
		}
	}
out:
	kfree(ssr);
	return err;
}
Contributors
 | Person | Tokens | Prop | Commits | CommitProp | 
| adrian hunter | adrian hunter | 251 | 89.96% | 1 | 33.33% | 
| wolfram sang | wolfram sang | 22 | 7.89% | 1 | 33.33% | 
| joe perches | joe perches | 6 | 2.15% | 1 | 33.33% | 
 | Total | 279 | 100.00% | 3 | 100.00% | 
/*
 * Fetches and decodes switch information
 */
static int mmc_read_switch(struct mmc_card *card)
{
	int err;
	u8 *status;
	if (card->scr.sda_vsn < SCR_SPEC_VER_1)
		return 0;
	if (!(card->csd.cmdclass & CCC_SWITCH)) {
		pr_warn("%s: card lacks mandatory switch function, performance might suffer\n",
			mmc_hostname(card->host));
		return 0;
	}
	err = -EIO;
	status = kmalloc(64, GFP_KERNEL);
	if (!status) {
		pr_err("%s: could not allocate a buffer for "
			"switch capabilities.\n",
			mmc_hostname(card->host));
		return -ENOMEM;
	}
	/*
         * Find out the card's support bits with a mode 0 operation.
         * The argument does not matter, as the support bits do not
         * change with the arguments.
         */
	err = mmc_sd_switch(card, 0, 0, 0, status);
	if (err) {
		/*
                 * If the host or the card can't do the switch,
                 * fail more gracefully.
                 */
		if (err != -EINVAL && err != -ENOSYS && err != -EFAULT)
			goto out;
		pr_warn("%s: problem reading Bus Speed modes\n",
			mmc_hostname(card->host));
		err = 0;
		goto out;
	}
	if (status[13] & SD_MODE_HIGH_SPEED)
		card->sw_caps.hs_max_dtr = HIGH_SPEED_MAX_DTR;
	if (card->scr.sda_spec3) {
		card->sw_caps.sd3_bus_mode = status[13];
		/* Driver Strengths supported by the card */
		card->sw_caps.sd3_drv_type = status[9];
		card->sw_caps.sd3_curr_limit = status[7] | status[6] << 8;
	}
out:
	kfree(status);
	return err;
}
Contributors
 | Person | Tokens | Prop | Commits | CommitProp | 
| pierre ossman | pierre ossman | 125 | 52.30% | 5 | 41.67% | 
| arindam nath | arindam nath | 71 | 29.71% | 1 | 8.33% | 
| russell king | russell king | 18 | 7.53% | 1 | 8.33% | 
| subhash jadavani | subhash jadavani | 15 | 6.28% | 1 | 8.33% | 
| joe perches | joe perches | 4 | 1.67% | 1 | 8.33% | 
| aaron lu | aaron lu | 3 | 1.26% | 1 | 8.33% | 
| qiang liu | qiang liu | 2 | 0.84% | 1 | 8.33% | 
| girish k s | girish k s | 1 | 0.42% | 1 | 8.33% | 
 | Total | 239 | 100.00% | 12 | 100.00% | 
/*
 * Test if the card supports high-speed mode and, if so, switch to it.
 */
int mmc_sd_switch_hs(struct mmc_card *card)
{
	int err;
	u8 *status;
	if (card->scr.sda_vsn < SCR_SPEC_VER_1)
		return 0;
	if (!(card->csd.cmdclass & CCC_SWITCH))
		return 0;
	if (!(card->host->caps & MMC_CAP_SD_HIGHSPEED))
		return 0;
	if (card->sw_caps.hs_max_dtr == 0)
		return 0;
	status = kmalloc(64, GFP_KERNEL);
	if (!status) {
		pr_err("%s: could not allocate a buffer for "
			"switch capabilities.\n", mmc_hostname(card->host));
		return -ENOMEM;
	}
	err = mmc_sd_switch(card, 1, 0, 1, status);
	if (err)
		goto out;
	if ((status[16] & 0xF) != 1) {
		pr_warn("%s: Problem switching card into high-speed mode!\n",
			mmc_hostname(card->host));
		err = 0;
	} else {
		err = 1;
	}
out:
	kfree(status);
	return err;
}
Contributors
 | Person | Tokens | Prop | Commits | CommitProp | 
| pierre ossman | pierre ossman | 167 | 93.82% | 5 | 62.50% | 
| michal miroslaw | michal miroslaw | 8 | 4.49% | 1 | 12.50% | 
| joe perches | joe perches | 2 | 1.12% | 1 | 12.50% | 
| girish k s | girish k s | 1 | 0.56% | 1 | 12.50% | 
 | Total | 178 | 100.00% | 8 | 100.00% | 
static int sd_select_driver_type(struct mmc_card *card, u8 *status)
{
	int card_drv_type, drive_strength, drv_type;
	int err;
	card->drive_strength = 0;
	card_drv_type = card->sw_caps.sd3_drv_type | SD_DRIVER_TYPE_B;
	drive_strength = mmc_select_drive_strength(card,
						   card->sw_caps.uhs_max_dtr,
						   card_drv_type, &drv_type);
	if (drive_strength) {
		err = mmc_sd_switch(card, 1, 2, drive_strength, status);
		if (err)
			return err;
		if ((status[15] & 0xF) != drive_strength) {
			pr_warn("%s: Problem setting drive strength!\n",
				mmc_hostname(card->host));
			return 0;
		}
		card->drive_strength = drive_strength;
	}
	if (drv_type)
		mmc_set_driver_type(card->host, drv_type);
	return 0;
}
Contributors
 | Person | Tokens | Prop | Commits | CommitProp | 
| arindam nath | arindam nath | 92 | 66.19% | 1 | 12.50% | 
| adrian hunter | adrian hunter | 35 | 25.18% | 5 | 62.50% | 
| philip rakity | philip rakity | 11 | 7.91% | 1 | 12.50% | 
| joe perches | joe perches | 1 | 0.72% | 1 | 12.50% | 
 | Total | 139 | 100.00% | 8 | 100.00% | 
static void sd_update_bus_speed_mode(struct mmc_card *card)
{
	/*
         * If the host doesn't support any of the UHS-I modes, fallback on
         * default speed.
         */
	if (!mmc_host_uhs(card->host)) {
		card->sd_bus_speed = 0;
		return;
	}
	if ((card->host->caps & MMC_CAP_UHS_SDR104) &&
	    (card->sw_caps.sd3_bus_mode & SD_MODE_UHS_SDR104)) {
			card->sd_bus_speed = UHS_SDR104_BUS_SPEED;
	} else if ((card->host->caps & MMC_CAP_UHS_DDR50) &&
		   (card->sw_caps.sd3_bus_mode & SD_MODE_UHS_DDR50)) {
			card->sd_bus_speed = UHS_DDR50_BUS_SPEED;
	} else if ((card->host->caps & (MMC_CAP_UHS_SDR104 |
		    MMC_CAP_UHS_SDR50)) && (card->sw_caps.sd3_bus_mode &
		    SD_MODE_UHS_SDR50)) {
			card->sd_bus_speed = UHS_SDR50_BUS_SPEED;
	} else if ((card->host->caps & (MMC_CAP_UHS_SDR104 |
		    MMC_CAP_UHS_SDR50 | MMC_CAP_UHS_SDR25)) &&
		   (card->sw_caps.sd3_bus_mode & SD_MODE_UHS_SDR25)) {
			card->sd_bus_speed = UHS_SDR25_BUS_SPEED;
	} else if ((card->host->caps & (MMC_CAP_UHS_SDR104 |
		    MMC_CAP_UHS_SDR50 | MMC_CAP_UHS_SDR25 |
		    MMC_CAP_UHS_SDR12)) && (card->sw_caps.sd3_bus_mode &
		    SD_MODE_UHS_SDR12)) {
			card->sd_bus_speed = UHS_SDR12_BUS_SPEED;
	}
}
Contributors
 | Person | Tokens | Prop | Commits | CommitProp | 
| arindam nath | arindam nath | 177 | 87.19% | 1 | 33.33% | 
| subhash jadavani | subhash jadavani | 23 | 11.33% | 1 | 33.33% | 
| johan rudholm | johan rudholm | 3 | 1.48% | 1 | 33.33% | 
 | Total | 203 | 100.00% | 3 | 100.00% | 
static int sd_set_bus_speed_mode(struct mmc_card *card, u8 *status)
{
	int err;
	unsigned int timing = 0;
	switch (card->sd_bus_speed) {
	case UHS_SDR104_BUS_SPEED:
		timing = MMC_TIMING_UHS_SDR104;
		card->sw_caps.uhs_max_dtr = UHS_SDR104_MAX_DTR;
		break;
	case UHS_DDR50_BUS_SPEED:
		timing = MMC_TIMING_UHS_DDR50;
		card->sw_caps.uhs_max_dtr = UHS_DDR50_MAX_DTR;
		break;
	case UHS_SDR50_BUS_SPEED:
		timing = MMC_TIMING_UHS_SDR50;
		card->sw_caps.uhs_max_dtr = UHS_SDR50_MAX_DTR;
		break;
	case UHS_SDR25_BUS_SPEED:
		timing = MMC_TIMING_UHS_SDR25;
		card->sw_caps.uhs_max_dtr = UHS_SDR25_MAX_DTR;
		break;
	case UHS_SDR12_BUS_SPEED:
		timing = MMC_TIMING_UHS_SDR12;
		card->sw_caps.uhs_max_dtr = UHS_SDR12_MAX_DTR;
		break;
	default:
		return 0;
	}
	err = mmc_sd_switch(card, 1, 0, card->sd_bus_speed, status);
	if (err)
		return err;
	if ((status[16] & 0xF) != card->sd_bus_speed)
		pr_warn("%s: Problem setting bus speed mode!\n",
			mmc_hostname(card->host));
	else {
		mmc_set_timing(card->host, timing);
		mmc_set_clock(card->host, card->sw_caps.uhs_max_dtr);
	}
	return 0;
}
Contributors
 | Person | Tokens | Prop | Commits | CommitProp | 
| subhash jadavani | subhash jadavani | 107 | 54.87% | 1 | 33.33% | 
| arindam nath | arindam nath | 87 | 44.62% | 1 | 33.33% | 
| joe perches | joe perches | 1 | 0.51% | 1 | 33.33% | 
 | Total | 195 | 100.00% | 3 | 100.00% | 
/* Get host's max current setting at its current voltage */
static u32 sd_get_host_max_current(struct mmc_host *host)
{
	u32 voltage, max_current;
	voltage = 1 << host->ios.vdd;
	switch (voltage) {
	case MMC_VDD_165_195:
		max_current = host->max_current_180;
		break;
	case MMC_VDD_29_30:
	case MMC_VDD_30_31:
		max_current = host->max_current_300;
		break;
	case MMC_VDD_32_33:
	case MMC_VDD_33_34:
		max_current = host->max_current_330;
		break;
	default:
		max_current = 0;
	}
	return max_current;
}
Contributors
 | Person | Tokens | Prop | Commits | CommitProp | 
| aaron lu | aaron lu | 76 | 100.00% | 1 | 100.00% | 
 | Total | 76 | 100.00% | 1 | 100.00% | 
static int sd_set_current_limit(struct mmc_card *card, u8 *status)
{
	int current_limit = SD_SET_CURRENT_NO_CHANGE;
	int err;
	u32 max_current;
	/*
         * Current limit switch is only defined for SDR50, SDR104, and DDR50
         * bus speed modes. For other bus speed modes, we do not change the
         * current limit.
         */
	if ((card->sd_bus_speed != UHS_SDR50_BUS_SPEED) &&
	    (card->sd_bus_speed != UHS_SDR104_BUS_SPEED) &&
	    (card->sd_bus_speed != UHS_DDR50_BUS_SPEED))
		return 0;
	/*
         * Host has different current capabilities when operating at
         * different voltages, so find out its max current first.
         */
	max_current = sd_get_host_max_current(card->host);
	/*
         * We only check host's capability here, if we set a limit that is
         * higher than the card's maximum current, the card will be using its
         * maximum current, e.g. if the card's maximum current is 300ma, and
         * when we set current limit to 200ma, the card will draw 200ma, and
         * when we set current limit to 400/600/800ma, the card will draw its
         * maximum 300ma from the host.
         *
         * The above is incorrect: if we try to set a current limit that is
         * not supported by the card, the card can rightfully error out the
         * attempt, and remain at the default current limit.  This results
         * in a 300mA card being limited to 200mA even though the host
         * supports 800mA. Failures seen with SanDisk 8GB UHS cards with
         * an iMX6 host. --rmk
         */
	if (max_current >= 800 &&
	    card->sw_caps.sd3_curr_limit & SD_MAX_CURRENT_800)
		current_limit = SD_SET_CURRENT_LIMIT_800;
	else if (max_current >= 600 &&
		 card->sw_caps.sd3_curr_limit & SD_MAX_CURRENT_600)
		current_limit = SD_SET_CURRENT_LIMIT_600;
	else if (max_current >= 400 &&
		 card->sw_caps.sd3_curr_limit & SD_MAX_CURRENT_400)
		current_limit = SD_SET_CURRENT_LIMIT_400;
	else if (max_current >= 200 &&
		 card->sw_caps.sd3_curr_limit & SD_MAX_CURRENT_200)
		current_limit = SD_SET_CURRENT_LIMIT_200;
	if (current_limit != SD_SET_CURRENT_NO_CHANGE) {
		err = mmc_sd_switch(card, 1, 3, current_limit, status);
		if (err)
			return err;
		if (((status[15] >> 4) & 0x0F) != current_limit)
			pr_warn("%s: Problem setting current limit!\n",
				mmc_hostname(card->host));
	}
	return 0;
}
Contributors
 | Person | Tokens | Prop | Commits | CommitProp | 
| arindam nath | arindam nath | 129 | 63.24% | 1 | 20.00% | 
| aaron lu | aaron lu | 33 | 16.18% | 1 | 20.00% | 
| russell king | russell king | 33 | 16.18% | 1 | 20.00% | 
| philip rakity | philip rakity | 8 | 3.92% | 1 | 20.00% | 
| joe perches | joe perches | 1 | 0.49% | 1 | 20.00% | 
 | Total | 204 | 100.00% | 5 | 100.00% | 
/*
 * UHS-I specific initialization procedure
 */
static int mmc_sd_init_uhs_card(struct mmc_card *card)
{
	int err;
	u8 *status;
	if (!card->scr.sda_spec3)
		return 0;
	if (!(card->csd.cmdclass & CCC_SWITCH))
		return 0;
	status = kmalloc(64, GFP_KERNEL);
	if (!status) {
		pr_err("%s: could not allocate a buffer for "
			"switch capabilities.\n", mmc_hostname(card->host));
		return -ENOMEM;
	}
	/* Set 4-bit bus width */
	if ((card->host->caps & MMC_CAP_4_BIT_DATA) &&
	    (card->scr.bus_widths & SD_SCR_BUS_WIDTH_4)) {
		err = mmc_app_set_bus_width(card, MMC_BUS_WIDTH_4);
		if (err)
			goto out;
		mmc_set_bus_width(card->host, MMC_BUS_WIDTH_4);
	}
	/*
         * Select the bus speed mode depending on host
         * and card capability.
         */
	sd_update_bus_speed_mode(card);
	/* Set the driver strength for the card */
	err = sd_select_driver_type(card, status);
	if (err)
		goto out;
	/* Set current limit for the card */
	err = sd_set_current_limit(card, status);
	if (err)
		goto out;
	/* Set bus speed mode of the card */
	err = sd_set_bus_speed_mode(card, status);
	if (err)
		goto out;
	/*
         * SPI mode doesn't define CMD19 and tuning is only valid for SDR50 and
         * SDR104 mode SD-cards. Note that tuning is mandatory for SDR104.
         */
	if (!mmc_host_is_spi(card->host) &&
		(card->host->ios.timing == MMC_TIMING_UHS_SDR50 ||
		 card->host->ios.timing == MMC_TIMING_UHS_DDR50 ||
		 card->host->ios.timing == MMC_TIMING_UHS_SDR104)) {
		err = mmc_execute_tuning(card);
		/*
                 * As SD Specifications Part1 Physical Layer Specification
                 * Version 3.01 says, CMD19 tuning is available for unlocked
                 * cards in transfer state of 1.8V signaling mode. The small
                 * difference between v3.00 and 3.01 spec means that CMD19
                 * tuning is also available for DDR50 mode.
                 */
		if (err && card->host->ios.timing == MMC_TIMING_UHS_DDR50) {
			pr_warn("%s: ddr50 tuning failed\n",
				mmc_hostname(card->host));
			err = 0;
		}
	}
out:
	kfree(status);
	return err;
}
Contributors
 | Person | Tokens | Prop | Commits | CommitProp | 
| arindam nath | arindam nath | 198 | 70.46% | 4 | 36.36% | 
| weijun yang | weijun yang | 33 | 11.74% | 1 | 9.09% | 
| carlo caione | carlo caione | 24 | 8.54% | 1 | 9.09% | 
| subhash jadavani | subhash jadavani | 10 | 3.56% | 1 | 9.09% | 
| fredrik soderstedt | fredrik soderstedt | 10 | 3.56% | 1 | 9.09% | 
| sujit reddy thumma | sujit reddy thumma | 4 | 1.42% | 1 | 9.09% | 
| adrian hunter | adrian hunter | 1 | 0.36% | 1 | 9.09% | 
| girish k s | girish k s | 1 | 0.36% | 1 | 9.09% | 
 | Total | 281 | 100.00% | 11 | 100.00% | 
MMC_DEV_ATTR(cid, "%08x%08x%08x%08x\n", card->raw_cid[0], card->raw_cid[1],
	card->raw_cid[2], card->raw_cid[3]);
MMC_DEV_ATTR(csd, "%08x%08x%08x%08x\n", card->raw_csd[0], card->raw_csd[1],
	card->raw_csd[2], card->raw_csd[3]);
MMC_DEV_ATTR(scr, "%08x%08x\n", card->raw_scr[0], card->raw_scr[1]);
MMC_DEV_ATTR(date, "%02d/%04d\n", card->cid.month, card->cid.year);
MMC_DEV_ATTR(erase_size, "%u\n", card->erase_size << 9);
MMC_DEV_ATTR(preferred_erase_size, "%u\n", card->pref_erase << 9);
MMC_DEV_ATTR(fwrev, "0x%x\n", card->cid.fwrev);
MMC_DEV_ATTR(hwrev, "0x%x\n", card->cid.hwrev);
MMC_DEV_ATTR(manfid, "0x%06x\n", card->cid.manfid);
MMC_DEV_ATTR(name, "%s\n", card->cid.prod_name);
MMC_DEV_ATTR(oemid, "0x%04x\n", card->cid.oemid);
MMC_DEV_ATTR(serial, "0x%08x\n", card->cid.serial);
static struct attribute *sd_std_attrs[] = {
	&dev_attr_cid.attr,
	&dev_attr_csd.attr,
	&dev_attr_scr.attr,
	&dev_attr_date.attr,
	&dev_attr_erase_size.attr,
	&dev_attr_preferred_erase_size.attr,
	&dev_attr_fwrev.attr,
	&dev_attr_hwrev.attr,
	&dev_attr_manfid.attr,
	&dev_attr_name.attr,
	&dev_attr_oemid.attr,
	&dev_attr_serial.attr,
	NULL,
};
ATTRIBUTE_GROUPS(sd_std);
struct device_type sd_type = {
	.groups = sd_std_groups,
};
/*
 * Fetch CID from card.
 */
int mmc_sd_get_cid(struct mmc_host *host, u32 ocr, u32 *cid, u32 *rocr)
{
	int err;
	u32 max_current;
	int retries = 10;
	u32 pocr = ocr;
try_again:
	if (!retries) {
		ocr &= ~SD_OCR_S18R;
		pr_warn("%s: Skipping voltage switch\n", mmc_hostname(host));
	}
	/*
         * Since we're changing the OCR value, we seem to
         * need to tell some cards to go back to the idle
         * state.  We wait 1ms to give cards time to
         * respond.
         */
	mmc_go_idle(host);
	/*
         * If SD_SEND_IF_COND indicates an SD 2.0
         * compliant card and we should set bit 30
         * of the ocr to indicate that we can handle
         * block-addressed SDHC cards.
         */
	err = mmc_send_if_cond(host, ocr);
	if (!err)
		ocr |= SD_OCR_CCS;
	/*
         * If the host supports one of UHS-I modes, request the card
         * to switch to 1.8V signaling level. If the card has failed
         * repeatedly to switch however, skip this.
         */
	if (retries && mmc_host_uhs(host))
		ocr |= SD_OCR_S18R;
	/*
         * If the host can supply more than 150mA at current voltage,
         * XPC should be set to 1.
         */
	max_current = sd_get_host_max_current(host);
	if (max_current > 150)
		ocr |= SD_OCR_XPC;
	err = mmc_send_app_op_cond(host, ocr, rocr);
	if (err)
		return err;
	/*
         * In case CCS and S18A in the response is set, start Signal Voltage
         * Switch procedure. SPI mode doesn't support CMD11.
         */
	if (!mmc_host_is_spi(host) && rocr &&
	   ((*rocr & 0x41000000) == 0x41000000)) {
		err = mmc_set_signal_voltage(host, MMC_SIGNAL_VOLTAGE_180,
					pocr);
		if (err == -EAGAIN) {
			retries--;
			goto try_again;
		} else if (err) {
			retries = 0;
			goto try_again;
		}
	}
	if (mmc_host_is_spi(host))
		err = mmc_send_cid(host, cid);
	else
		err = mmc_all_send_cid(host, cid);
	return err;
}
Contributors
 | Person | Tokens | Prop | Commits | CommitProp | 
| pierre ossman | pierre ossman | 83 | 36.24% | 2 | 18.18% | 
| arindam nath | arindam nath | 64 | 27.95% | 2 | 18.18% | 
| johan rudholm | johan rudholm | 53 | 23.14% | 2 | 18.18% | 
| aaron lu | aaron lu | 14 | 6.11% | 1 | 9.09% | 
| ulf hansson | ulf hansson | 7 | 3.06% | 2 | 18.18% | 
| michal miroslaw | michal miroslaw | 7 | 3.06% | 1 | 9.09% | 
| joe perches | joe perches | 1 | 0.44% | 1 | 9.09% | 
 | Total | 229 | 100.00% | 11 | 100.00% | 
int mmc_sd_get_csd(struct mmc_host *host, struct mmc_card *card)
{
	int err;
	/*
         * Fetch CSD from card.
         */
	err = mmc_send_csd(card, card->raw_csd);
	if (err)
		return err;
	err = mmc_decode_csd(card);
	if (err)
		return err;
	return 0;
}
Contributors
 | Person | Tokens | Prop | Commits | CommitProp | 
| michal miroslaw | michal miroslaw | 27 | 50.00% | 1 | 25.00% | 
| pierre ossman | pierre ossman | 23 | 42.59% | 2 | 50.00% | 
| david brownell | david brownell | 4 | 7.41% | 1 | 25.00% | 
 | Total | 54 | 100.00% | 4 | 100.00% | 
static int mmc_sd_get_ro(struct mmc_host *host)
{
	int ro;
	/*
         * Some systems don't feature a write-protect pin and don't need one.
         * E.g. because they only have micro-SD card slot. For those systems
         * assume that the SD card is always read-write.
         */
	if (host->caps2 & MMC_CAP2_NO_WRITE_PROTECT)
		return 0;
	if (!host->ops->get_ro)
		return -1;
	ro = host->ops->get_ro(host);
	return ro;
}
Contributors
 | Person | Tokens | Prop | Commits | CommitProp | 
| lars-peter clausen | lars-peter clausen | 53 | 100.00% | 1 | 100.00% | 
 | Total | 53 | 100.00% | 1 | 100.00% | 
int mmc_sd_setup_card(struct mmc_host *host, struct mmc_card *card,
	bool reinit)
{
	int err;
	if (!reinit) {
		/*
                 * Fetch SCR from card.
                 */
		err = mmc_app_send_scr(card, card->raw_scr);
		if (err)
			return err;
		err = mmc_decode_scr(card);
		if (err)
			return err;
		/*
                 * Fetch and process SD Status register.
                 */
		err = mmc_read_ssr(card);
		if (err)
			return err;
		/* Erase init depends on CSD and SSR */
		mmc_init_erase(card);
		/*
                 * Fetch switch information from card.
                 */
		err = mmc_read_switch(card);
		if (err)
			return err;
	}
	/*
         * For SPI, enable CRC as appropriate.
         * This CRC enable is located AFTER the reading of the
         * card registers because some SDHC cards are not able
         * to provide valid CRCs for non-512-byte blocks.
         */
	if (mmc_host_is_spi(host)) {
		err = mmc_spi_set_crc(host, use_spi_crc);
		if (err)
			return err;
	}
	/*
         * Check if read-only switch is active.
         */
	if (!reinit) {
		int ro = mmc_sd_get_ro(host);
		if (ro < 0) {
			pr_warn("%s: host does not support reading read-only switch, assuming write-enable\n",
				mmc_hostname(host));
		} else if (ro > 0) {
			mmc_card_set_readonly(card);
		}
	}
	return 0;
}
Contributors
 | Person | Tokens | Prop | Commits | CommitProp | 
| michal miroslaw | michal miroslaw | 72 | 41.38% | 1 | 11.11% | 
| pierre ossman | pierre ossman | 57 | 32.76% | 2 | 22.22% | 
| adrian hunter | adrian hunter | 21 | 12.07% | 1 | 11.11% | 
| david brownell | david brownell | 9 | 5.17% | 1 | 11.11% | 
| wolfgang muees | wolfgang muees | 8 | 4.60% | 1 | 11.11% | 
| sujit reddy thumma | sujit reddy thumma | 3 | 1.72% | 1 | 11.11% | 
| joe perches | joe perches | 2 | 1.15% | 1 | 11.11% | 
| lars-peter clausen | lars-peter clausen | 2 | 1.15% | 1 | 11.11% | 
 | Total | 174 | 100.00% | 9 | 100.00% | 
unsigned mmc_sd_get_max_clock(struct mmc_card *card)
{
	unsigned max_dtr = (unsigned int)-1;
	if (mmc_card_hs(card)) {
		if (max_dtr > card->sw_caps.hs_max_dtr)
			max_dtr = card->sw_caps.hs_max_dtr;
	} else if (max_dtr > card->csd.max_dtr) {
		max_dtr = card->csd.max_dtr;
	}
	return max_dtr;
}
Contributors
 | Person | Tokens | Prop | Commits | CommitProp | 
| pierre ossman | pierre ossman | 54 | 76.06% | 1 | 33.33% | 
| michal miroslaw | michal miroslaw | 16 | 22.54% | 1 | 33.33% | 
| seungwon jeon | seungwon jeon | 1 | 1.41% | 1 | 33.33% | 
 | Total | 71 | 100.00% | 3 | 100.00% | 
/*
 * Handle the detection and initialisation of a card.
 *
 * In the case of a resume, "oldcard" will contain the card
 * we're trying to reinitialise.
 */
static int mmc_sd_init_card(struct mmc_host *host, u32 ocr,
	struct mmc_card *oldcard)
{
	struct mmc_card *card;
	int err;
	u32 cid[4];
	u32 rocr = 0;
	BUG_ON(!host);
	WARN_ON(!host->claimed);
	err = mmc_sd_get_cid(host, ocr, cid, &rocr);
	if (err)
		return err;
	if (oldcard) {
		if (memcmp(cid, oldcard->raw_cid, sizeof(cid)) != 0)
			return -ENOENT;
		card = oldcard;
	} else {
		/*
                 * Allocate card structure.
                 */
		card = mmc_alloc_card(host, &sd_type);
		if (IS_ERR(card))
			return PTR_ERR(card);
		card->ocr = ocr;
		card->type = MMC_TYPE_SD;
		memcpy(card->raw_cid, cid, sizeof(card->raw_cid));
	}
	/*
         * Call the optional HC's init_card function to handle quirks.
         */
	if (host->ops->init_card)
		host->ops->init_card(host, card);
	/*
         * For native busses:  get card RCA and quit open drain mode.
         */
	if (!mmc_host_is_spi(host)) {
		err = mmc_send_relative_addr(host, &card->rca);
		if (err)
			goto free_card;
	}
	if (!oldcard) {
		err = mmc_sd_get_csd(host, card);
		if (err)
			goto free_card;
		mmc_decode_cid(card);
	}
	/*
         * handling only for cards supporting DSR and hosts requesting
         * DSR configuration
         */
	if (card->csd.dsr_imp && host->dsr_req)
		mmc_set_dsr(host);
	/*
         * Select card, as all following commands rely on that.
         */
	if (!mmc_host_is_spi(host)) {
		err = mmc_select_card(card);
		if (err)
			goto free_card;
	}
	err = mmc_sd_setup_card(host, card, oldcard != NULL);
	if (err)
		goto free_card;
	/* Initialization sequence for UHS-I cards */
	if (rocr & SD_ROCR_S18A) {
		err = mmc_sd_init_uhs_card(card);
		if (err)
			goto free_card;
	} else {
		/*
                 * Attempt to change to high-speed (if supported)
                 */
		err = mmc_sd_switch_hs(card);
		if (err > 0)
			mmc_set_timing(card->host, MMC_TIMING_SD_HS);
		else if (err)
			goto free_card;
		/*
                 * Set bus speed.
                 */
		mmc_set_clock(host, mmc_sd_get_max_clock(card));
		/*
                 * Switch to wider bus (if supported).
                 */
		if ((host->caps & MMC_CAP_4_BIT_DATA) &&
			(card->scr.bus_widths & SD_SCR_BUS_WIDTH_4)) {
			err = mmc_app_set_bus_width(card, MMC_BUS_WIDTH_4);
			if (err)
				goto free_card;
			mmc_set_bus_width(host, MMC_BUS_WIDTH_4);
		}
	}
	host->card = card;
	return 0;
free_card:
	if (!oldcard)
		mmc_remove_card(card);
	return err;
}
Contributors
 | Person | Tokens | Prop | Commits | CommitProp | 
| michal miroslaw | michal miroslaw | 264 | 60.14% | 1 | 8.33% | 
| pierre ossman | pierre ossman | 77 | 17.54% | 4 | 33.33% | 
| arindam nath | arindam nath | 37 | 8.43% | 1 | 8.33% | 
| douglas anderson | douglas anderson | 20 | 4.56% | 1 | 8.33% | 
| sascha hauer | sascha hauer | 18 | 4.10% | 1 | 8.33% | 
| wei wang | wei wang | 9 | 2.05% | 1 | 8.33% | 
| ulf hansson | ulf hansson | 6 | 1.37% | 1 | 8.33% | 
| seungwon jeon | seungwon jeon | 5 | 1.14% | 1 | 8.33% | 
| anton vorontsov | anton vorontsov | 3 | 0.68% | 1 | 8.33% | 
 | Total | 439 | 100.00% | 12 | 100.00% | 
/*
 * Host is being removed. Free up the current card.
 */
static void mmc_sd_remove(struct mmc_host *host)
{
	BUG_ON(!host);
	BUG_ON(!host->card);
	mmc_remove_card(host->card);
	host->card = NULL;
}
Contributors
 | Person | Tokens | Prop | Commits | CommitProp | 
| pierre ossman | pierre ossman | 38 | 100.00% | 2 | 100.00% | 
 | Total | 38 | 100.00% | 2 | 100.00% | 
/*
 * Card detection - card is alive.
 */
static int mmc_sd_alive(struct mmc_host *host)
{
	return mmc_send_status(host->card, NULL);
}
Contributors
 | Person | Tokens | Prop | Commits | CommitProp | 
| adrian hunter | adrian hunter | 21 | 100.00% | 1 | 100.00% | 
 | Total | 21 | 100.00% | 1 | 100.00% | 
/*
 * Card detection callback from host.
 */
static void mmc_sd_detect(struct mmc_host *host)
{
	int err;
	BUG_ON(!host);
	BUG_ON(!host->card);
	mmc_get_card(host->card);
	/*
         * Just check if our card has been removed.
         */
	err = _mmc_detect_card_removed(host);
	mmc_put_card(host->card);
	if (err) {
		mmc_sd_remove(host);
		mmc_claim_host(host);
		mmc_detach_bus(host);
		mmc_power_off(host);
		mmc_release_host(host);
	}
}
Contributors
 | Person | Tokens | Prop | Commits | CommitProp | 
| pierre ossman | pierre ossman | 69 | 85.19% | 2 | 40.00% | 
| ulf hansson | ulf hansson | 11 | 13.58% | 2 | 40.00% | 
| adrian hunter | adrian hunter | 1 | 1.23% | 1 | 20.00% | 
 | Total | 81 | 100.00% | 5 | 100.00% | 
static int _mmc_sd_suspend(struct mmc_host *host)
{
	int err = 0;
	BUG_ON(!host);
	BUG_ON(!host->card);
	mmc_claim_host(host);
	if (mmc_card_suspended(host->card))
		goto out;
	if (!mmc_host_is_spi(host))
		err = mmc_deselect_cards(host);
	if (!err) {
		mmc_power_off(host);
		mmc_card_set_suspended(host->card);
	}
out:
	mmc_release_host(host);
	return err;
}
Contributors
 | Person | Tokens | Prop | Commits | CommitProp | 
| pierre ossman | pierre ossman | 38 | 41.76% | 1 | 14.29% | 
| ulf hansson | ulf hansson | 34 | 37.36% | 3 | 42.86% | 
| david brownell | david brownell | 8 | 8.79% | 1 | 14.29% | 
| jaehoon chung | jaehoon chung | 8 | 8.79% | 1 | 14.29% | 
| nicolas pitre | nicolas pitre | 3 | 3.30% | 1 | 14.29% | 
 | Total | 91 | 100.00% | 7 | 100.00% | 
/*
 * Callback for suspend
 */
static int mmc_sd_suspend(struct mmc_host *host)
{
	int err;
	err = _mmc_sd_suspend(host);
	if (!err) {
		pm_runtime_disable(&host->card->dev);
		pm_runtime_set_suspended(&host->card->dev);
	}
	return err;
}
Contributors
 | Person | Tokens | Prop | Commits | CommitProp | 
| ulf hansson | ulf hansson | 49 | 96.08% | 1 | 33.33% | 
| nicolas pitre | nicolas pitre | 1 | 1.96% | 1 | 33.33% | 
| pierre ossman | pierre ossman | 1 | 1.96% | 1 | 33.33% | 
 | Total | 51 | 100.00% | 3 | 100.00% | 
/*
 * This function tries to determine if the same card is still present
 * and, if so, restore all state to it.
 */
static int _mmc_sd_resume(struct mmc_host *host)
{
	int err = 0;
	BUG_ON(!host);
	BUG_ON(!host->card);
	mmc_claim_host(host);
	if (!mmc_card_suspended(host->card))
		goto out;
	mmc_power_up(host, host->card->ocr);
	err = mmc_sd_init_card(host, host->card->ocr, host->card);
	mmc_card_clr_suspended(host->card);
out:
	mmc_release_host(host);
	return err;
}
Contributors
 | Person | Tokens | Prop | Commits | CommitProp | 
| pierre ossman | pierre ossman | 51 | 54.84% | 3 | 33.33% | 
| ulf hansson | ulf hansson | 40 | 43.01% | 5 | 55.56% | 
| nicolas pitre | nicolas pitre | 2 | 2.15% | 1 | 11.11% | 
 | Total | 93 | 100.00% | 9 | 100.00% | 
/*
 * Callback for resume
 */
static int mmc_sd_resume(struct mmc_host *host)
{
	pm_runtime_enable(&host->card->dev);
	return 0;
}
Contributors
 | Person | Tokens | Prop | Commits | CommitProp | 
| ulf hansson | ulf hansson | 24 | 100.00% | 2 | 100.00% | 
 | Total | 24 | 100.00% | 2 | 100.00% | 
/*
 * Callback for runtime_suspend.
 */
static int mmc_sd_runtime_suspend(struct mmc_host *host)
{
	int err;
	if (!(host->caps & MMC_CAP_AGGRESSIVE_PM))
		return 0;
	err = _mmc_sd_suspend(host);
	if (err)
		pr_err("%s: error %d doing aggressive suspend\n",
			mmc_hostname(host), err);
	return err;
}
Contributors
 | Person | Tokens | Prop | Commits | CommitProp | 
| ulf hansson | ulf hansson | 53 | 98.15% | 2 | 66.67% | 
| masanari iida | masanari iida | 1 | 1.85% | 1 | 33.33% | 
 | Total | 54 | 100.00% | 3 | 100.00% | 
/*
 * Callback for runtime_resume.
 */
static int mmc_sd_runtime_resume(struct mmc_host *host)
{
	int err;
	err = _mmc_sd_resume(host);
	if (err && err != -ENOMEDIUM)
		pr_err("%s: error %d doing runtime resume\n",
			mmc_hostname(host), err);
	return 0;
}
Contributors
 | Person | Tokens | Prop | Commits | CommitProp | 
| ulf hansson | ulf hansson | 40 | 88.89% | 3 | 75.00% | 
| adrian hunter | adrian hunter | 5 | 11.11% | 1 | 25.00% | 
 | Total | 45 | 100.00% | 4 | 100.00% | 
static int mmc_sd_reset(struct mmc_host *host)
{
	mmc_power_cycle(host, host->card->ocr);
	return mmc_sd_init_card(host, host->card->ocr, host->card);
}
Contributors
 | Person | Tokens | Prop | Commits | CommitProp | 
| adrian hunter | adrian hunter | 16 | 42.11% | 1 | 20.00% | 
| johan rudholm | johan rudholm | 12 | 31.58% | 1 | 20.00% | 
| ulf hansson | ulf hansson | 8 | 21.05% | 2 | 40.00% | 
| ohad ben-cohen | ohad ben-cohen | 2 | 5.26% | 1 | 20.00% | 
 | Total | 38 | 100.00% | 5 | 100.00% | 
static const struct mmc_bus_ops mmc_sd_ops = {
	.remove = mmc_sd_remove,
	.detect = mmc_sd_detect,
	.runtime_suspend = mmc_sd_runtime_suspend,
	.runtime_resume = mmc_sd_runtime_resume,
	.suspend = mmc_sd_suspend,
	.resume = mmc_sd_resume,
	.alive = mmc_sd_alive,
	.shutdown = mmc_sd_suspend,
	.reset = mmc_sd_reset,
};
/*
 * Starting point for SD card init.
 */
int mmc_attach_sd(struct mmc_host *host)
{
	int err;
	u32 ocr, rocr;
	BUG_ON(!host);
	WARN_ON(!host->claimed);
	err = mmc_send_app_op_cond(host, 0, &ocr);
	if (err)
		return err;
	mmc_attach_bus(host, &mmc_sd_ops);
	if (host->ocr_avail_sd)
		host->ocr_avail = host->ocr_avail_sd;
	/*
         * We need to get OCR a different way for SPI.
         */
	if (mmc_host_is_spi(host)) {
		mmc_go_idle(host);
		err = mmc_spi_read_ocr(host, 0, &ocr);
		if (err)
			goto err;
	}
	rocr = mmc_select_voltage(host, ocr);
	/*
         * Can we support the voltage(s) of the card(s)?
         */
	if (!rocr) {
		err = -EINVAL;
		goto err;
	}
	/*
         * Detect and init the card.
         */
	err = mmc_sd_init_card(host, rocr, NULL);
	if (err)
		goto err;
	mmc_release_host(host);
	err = mmc_add_card(host->card);
	if (err)
		goto remove_card;
	mmc_claim_host(host);
	return 0;
remove_card:
	mmc_remove_card(host->card);
	host->card = NULL;
	mmc_claim_host(host);
err:
	mmc_detach_bus(host);
	pr_err("%s: error %d whilst initialising SD card\n",
		mmc_hostname(host), err);
	return err;
}
Contributors
 | Person | Tokens | Prop | Commits | CommitProp | 
| pierre ossman | pierre ossman | 137 | 61.71% | 7 | 50.00% | 
| david brownell | david brownell | 34 | 15.32% | 1 | 7.14% | 
| andy ross | andy ross | 22 | 9.91% | 1 | 7.14% | 
| takashi iwai | takashi iwai | 14 | 6.31% | 1 | 7.14% | 
| ulf hansson | ulf hansson | 9 | 4.05% | 2 | 14.29% | 
| sergei shtylyov | sergei shtylyov | 5 | 2.25% | 1 | 7.14% | 
| girish k s | girish k s | 1 | 0.45% | 1 | 7.14% | 
 | Total | 222 | 100.00% | 14 | 100.00% | 
Overall Contributors
 | Person | Tokens | Prop | Commits | CommitProp | 
| pierre ossman | pierre ossman | 2171 | 41.89% | 15 | 17.65% | 
| arindam nath | arindam nath | 906 | 17.48% | 7 | 8.24% | 
| adrian hunter | adrian hunter | 490 | 9.45% | 11 | 12.94% | 
| michal miroslaw | michal miroslaw | 396 | 7.64% | 1 | 1.18% | 
| ulf hansson | ulf hansson | 303 | 5.85% | 13 | 15.29% | 
| subhash jadavani | subhash jadavani | 155 | 2.99% | 2 | 2.35% | 
| aaron lu | aaron lu | 127 | 2.45% | 2 | 2.35% | 
| wolfram sang | wolfram sang | 104 | 2.01% | 1 | 1.18% | 
| johan rudholm | johan rudholm | 73 | 1.41% | 3 | 3.53% | 
| david brownell | david brownell | 64 | 1.23% | 1 | 1.18% | 
| lars-peter clausen | lars-peter clausen | 55 | 1.06% | 1 | 1.18% | 
| russell king | russell king | 51 | 0.98% | 1 | 1.18% | 
| weijun yang | weijun yang | 33 | 0.64% | 1 | 1.18% | 
| sascha hauer | sascha hauer | 31 | 0.60% | 1 | 1.18% | 
| carlo caione | carlo caione | 24 | 0.46% | 1 | 1.18% | 
| andy ross | andy ross | 22 | 0.42% | 1 | 1.18% | 
| douglas anderson | douglas anderson | 20 | 0.39% | 1 | 1.18% | 
| andrei warkentin | andrei warkentin | 19 | 0.37% | 1 | 1.18% | 
| philip rakity | philip rakity | 19 | 0.37% | 2 | 2.35% | 
| joe perches | joe perches | 18 | 0.35% | 1 | 1.18% | 
| takashi iwai | takashi iwai | 14 | 0.27% | 1 | 1.18% | 
| fredrik soderstedt | fredrik soderstedt | 10 | 0.19% | 1 | 1.18% | 
| wei wang | wei wang | 9 | 0.17% | 1 | 1.18% | 
| jaehoon chung | jaehoon chung | 8 | 0.15% | 1 | 1.18% | 
| wolfgang muees | wolfgang muees | 8 | 0.15% | 1 | 1.18% | 
| sujit reddy thumma | sujit reddy thumma | 7 | 0.14% | 1 | 1.18% | 
| nicolas pitre | nicolas pitre | 6 | 0.12% | 1 | 1.18% | 
| seungwon jeon | seungwon jeon | 6 | 0.12% | 1 | 1.18% | 
| girish k s | girish k s | 6 | 0.12% | 1 | 1.18% | 
| axel lin | axel lin | 6 | 0.12% | 1 | 1.18% | 
| sergei shtylyov | sergei shtylyov | 5 | 0.10% | 1 | 1.18% | 
| tejun heo | tejun heo | 3 | 0.06% | 1 | 1.18% | 
| mark brown | mark brown | 3 | 0.06% | 1 | 1.18% | 
| anton vorontsov | anton vorontsov | 3 | 0.06% | 1 | 1.18% | 
| paul gortmaker | paul gortmaker | 3 | 0.06% | 1 | 1.18% | 
| ohad ben-cohen | ohad ben-cohen | 2 | 0.04% | 1 | 1.18% | 
| qiang liu | qiang liu | 2 | 0.04% | 1 | 1.18% | 
| masanari iida | masanari iida | 1 | 0.02% | 1 | 1.18% | 
 | Total | 5183 | 100.00% | 85 | 100.00% | 
  
Information contained on this website is for historical information purposes only and does not indicate or represent copyright ownership.