diff options
Diffstat (limited to 'drivers/mmc/core/quirks.c')
| -rw-r--r-- | drivers/mmc/core/quirks.c | 89 | 
1 files changed, 42 insertions, 47 deletions
diff --git a/drivers/mmc/core/quirks.c b/drivers/mmc/core/quirks.c index 11118b74eb2..3a596217029 100644 --- a/drivers/mmc/core/quirks.c +++ b/drivers/mmc/core/quirks.c @@ -1,7 +1,8 @@  /* - *  This file contains work-arounds for many known sdio hardware - *  bugs. + *  This file contains work-arounds for many known SD/MMC + *  and SDIO hardware bugs.   * + *  Copyright (c) 2011 Andrei Warkentin <andreiw@motorola.com>   *  Copyright (c) 2011 Pierre Tardy <tardyp@gmail.com>   *  Inspired from pci fixup code:   *  Copyright (c) 1999 Martin Mares <mj@ucw.cz> @@ -11,34 +12,14 @@  #include <linux/types.h>  #include <linux/kernel.h>  #include <linux/mmc/card.h> -#include <linux/mod_devicetable.h> -/* - *  The world is not perfect and supplies us with broken mmc/sdio devices. - *  For at least a part of these bugs we need a work-around - */ - -struct mmc_fixup { -	u16 vendor, device;	/* You can use SDIO_ANY_ID here of course */ -	void (*vendor_fixup)(struct mmc_card *card, int data); -	int data; -}; - -/* - * This hook just adds a quirk unconditionnally - */ -static void __maybe_unused add_quirk(struct mmc_card *card, int data) -{ -	card->quirks |= data; -} +#ifndef SDIO_VENDOR_ID_TI +#define SDIO_VENDOR_ID_TI		0x0097 +#endif -/* - * This hook just removes a quirk unconditionnally - */ -static void __maybe_unused remove_quirk(struct mmc_card *card, int data) -{ -	card->quirks &= ~data; -} +#ifndef SDIO_DEVICE_ID_TI_WL1271 +#define SDIO_DEVICE_ID_TI_WL1271	0x4076 +#endif  /*   * This hook just adds a quirk for all sdio devices @@ -49,33 +30,47 @@ static void add_quirk_for_sdio_devices(struct mmc_card *card, int data)  		card->quirks |= data;  } -#ifndef SDIO_VENDOR_ID_TI -#define SDIO_VENDOR_ID_TI		0x0097 -#endif - -#ifndef SDIO_DEVICE_ID_TI_WL1271 -#define SDIO_DEVICE_ID_TI_WL1271	0x4076 -#endif -  static const struct mmc_fixup mmc_fixup_methods[] = {  	/* by default sdio devices are considered CLK_GATING broken */  	/* good cards will be whitelisted as they are tested */ -	{ SDIO_ANY_ID, SDIO_ANY_ID, -		add_quirk_for_sdio_devices, MMC_QUIRK_BROKEN_CLK_GATING }, -	{ SDIO_VENDOR_ID_TI, SDIO_DEVICE_ID_TI_WL1271, -		remove_quirk, MMC_QUIRK_BROKEN_CLK_GATING }, -	{ 0 } +	SDIO_FIXUP(SDIO_ANY_ID, SDIO_ANY_ID, +		   add_quirk_for_sdio_devices, +		   MMC_QUIRK_BROKEN_CLK_GATING), + +	SDIO_FIXUP(SDIO_VENDOR_ID_TI, SDIO_DEVICE_ID_TI_WL1271, +		   remove_quirk, MMC_QUIRK_BROKEN_CLK_GATING), + +	SDIO_FIXUP(SDIO_VENDOR_ID_TI, SDIO_DEVICE_ID_TI_WL1271, +		   add_quirk, MMC_QUIRK_NONSTD_FUNC_IF), + +	SDIO_FIXUP(SDIO_VENDOR_ID_TI, SDIO_DEVICE_ID_TI_WL1271, +		   add_quirk, MMC_QUIRK_DISABLE_CD), + +	END_FIXUP  }; -void mmc_fixup_device(struct mmc_card *card) +void mmc_fixup_device(struct mmc_card *card, const struct mmc_fixup *table)  {  	const struct mmc_fixup *f; +	u64 rev = cid_rev_card(card); + +	/* Non-core specific workarounds. */ +	if (!table) +		table = mmc_fixup_methods; -	for (f = mmc_fixup_methods; f->vendor_fixup; f++) { -		if ((f->vendor == card->cis.vendor -		     || f->vendor == (u16) SDIO_ANY_ID) && -		    (f->device == card->cis.device -		     || f->device == (u16) SDIO_ANY_ID)) { +	for (f = table; f->vendor_fixup; f++) { +		if ((f->manfid == CID_MANFID_ANY || +		     f->manfid == card->cid.manfid) && +		    (f->oemid == CID_OEMID_ANY || +		     f->oemid == card->cid.oemid) && +		    (f->name == CID_NAME_ANY || +		     !strncmp(f->name, card->cid.prod_name, +			      sizeof(card->cid.prod_name))) && +		    (f->cis_vendor == card->cis.vendor || +		     f->cis_vendor == (u16) SDIO_ANY_ID) && +		    (f->cis_device == card->cis.device || +		     f->cis_device == (u16) SDIO_ANY_ID) && +		    rev >= f->rev_start && rev <= f->rev_end) {  			dev_dbg(&card->dev, "calling %pF\n", f->vendor_fixup);  			f->vendor_fixup(card, f->data);  		}  |