diff options
Diffstat (limited to 'drivers/mmc')
-rw-r--r-- | drivers/mmc/core/mmc.c | 77 | ||||
-rw-r--r-- | drivers/mmc/host/sdhci-pltfm.c | 34 | ||||
-rw-r--r-- | drivers/mmc/host/sdhci-pltfm.h | 1 | ||||
-rw-r--r-- | drivers/mmc/host/sdhci-tegra.c | 49 |
4 files changed, 133 insertions, 28 deletions
diff --git a/drivers/mmc/core/mmc.c b/drivers/mmc/core/mmc.c index 2a7e43bc796..aa7d1d79b8c 100644 --- a/drivers/mmc/core/mmc.c +++ b/drivers/mmc/core/mmc.c @@ -247,12 +247,12 @@ static int mmc_read_ext_csd(struct mmc_card *card, u8 *ext_csd) return 0; /* Version is coded in the CSD_STRUCTURE byte in the EXT_CSD register */ + card->ext_csd.raw_ext_csd_structure = ext_csd[EXT_CSD_STRUCTURE]; if (card->csd.structure == 3) { - int ext_csd_struct = ext_csd[EXT_CSD_STRUCTURE]; - if (ext_csd_struct > 2) { + if (card->ext_csd.raw_ext_csd_structure > 2) { printk(KERN_ERR "%s: unrecognised EXT_CSD structure " "version %d\n", mmc_hostname(card->host), - ext_csd_struct); + card->ext_csd.raw_ext_csd_structure); err = -EINVAL; goto out; } @@ -266,6 +266,10 @@ static int mmc_read_ext_csd(struct mmc_card *card, u8 *ext_csd) goto out; } + card->ext_csd.raw_sectors[0] = ext_csd[EXT_CSD_SEC_CNT + 0]; + card->ext_csd.raw_sectors[1] = ext_csd[EXT_CSD_SEC_CNT + 1]; + card->ext_csd.raw_sectors[2] = ext_csd[EXT_CSD_SEC_CNT + 2]; + card->ext_csd.raw_sectors[3] = ext_csd[EXT_CSD_SEC_CNT + 3]; if (card->ext_csd.rev >= 2) { card->ext_csd.sectors = ext_csd[EXT_CSD_SEC_CNT + 0] << 0 | @@ -277,7 +281,7 @@ static int mmc_read_ext_csd(struct mmc_card *card, u8 *ext_csd) if (card->ext_csd.sectors > (2u * 1024 * 1024 * 1024) / 512) mmc_card_set_blockaddr(card); } - + card->ext_csd.raw_card_type = ext_csd[EXT_CSD_CARD_TYPE]; switch (ext_csd[EXT_CSD_CARD_TYPE] & EXT_CSD_CARD_TYPE_MASK) { case EXT_CSD_CARD_TYPE_DDR_52 | EXT_CSD_CARD_TYPE_52 | EXT_CSD_CARD_TYPE_26: @@ -307,6 +311,11 @@ static int mmc_read_ext_csd(struct mmc_card *card, u8 *ext_csd) mmc_hostname(card->host)); } + card->ext_csd.raw_s_a_timeout = ext_csd[EXT_CSD_S_A_TIMEOUT]; + card->ext_csd.raw_erase_timeout_mult = + ext_csd[EXT_CSD_ERASE_TIMEOUT_MULT]; + card->ext_csd.raw_hc_erase_grp_size = + ext_csd[EXT_CSD_HC_ERASE_GRP_SIZE]; if (card->ext_csd.rev >= 3) { u8 sa_shift = ext_csd[EXT_CSD_S_A_TIMEOUT]; card->ext_csd.part_config = ext_csd[EXT_CSD_PART_CONFIG]; @@ -334,6 +343,16 @@ static int mmc_read_ext_csd(struct mmc_card *card, u8 *ext_csd) card->ext_csd.boot_size = ext_csd[EXT_CSD_BOOT_MULT] << 17; } + card->ext_csd.raw_hc_erase_gap_size = + ext_csd[EXT_CSD_PARTITION_ATTRIBUTE]; + card->ext_csd.raw_sec_trim_mult = + ext_csd[EXT_CSD_SEC_TRIM_MULT]; + card->ext_csd.raw_sec_erase_mult = + ext_csd[EXT_CSD_SEC_ERASE_MULT]; + card->ext_csd.raw_sec_feature_support = + ext_csd[EXT_CSD_SEC_FEATURE_SUPPORT]; + card->ext_csd.raw_trim_mult = + ext_csd[EXT_CSD_TRIM_MULT]; if (card->ext_csd.rev >= 4) { /* * Enhanced area feature support -- check whether the eMMC @@ -341,7 +360,7 @@ static int mmc_read_ext_csd(struct mmc_card *card, u8 *ext_csd) * area offset and size to user by adding sysfs interface. */ if ((ext_csd[EXT_CSD_PARTITION_SUPPORT] & 0x2) && - (ext_csd[EXT_CSD_PARTITION_ATTRIBUTE] & 0x1)) { + (ext_csd[EXT_CSD_PARTITION_ATTRIBUTE] & 0x1)) { u8 hc_erase_grp_sz = ext_csd[EXT_CSD_HC_ERASE_GRP_SIZE]; u8 hc_wp_grp_sz = @@ -401,17 +420,17 @@ static inline void mmc_free_ext_csd(u8 *ext_csd) } -static int mmc_compare_ext_csds(struct mmc_card *card, u8 *ext_csd, - unsigned bus_width) +static int mmc_compare_ext_csds(struct mmc_card *card, unsigned bus_width) { u8 *bw_ext_csd; int err; + if (bus_width == MMC_BUS_WIDTH_1) + return 0; + err = mmc_get_ext_csd(card, &bw_ext_csd); - if (err) - return err; - if ((ext_csd == NULL || bw_ext_csd == NULL)) { + if (err || bw_ext_csd == NULL) { if (bus_width != MMC_BUS_WIDTH_1) err = -EINVAL; goto out; @@ -421,35 +440,40 @@ static int mmc_compare_ext_csds(struct mmc_card *card, u8 *ext_csd, goto out; /* only compare read only fields */ - err = (!(ext_csd[EXT_CSD_PARTITION_SUPPORT] == + err = (!(card->ext_csd.raw_partition_support == bw_ext_csd[EXT_CSD_PARTITION_SUPPORT]) && - (ext_csd[EXT_CSD_ERASED_MEM_CONT] == + (card->ext_csd.raw_erased_mem_count == bw_ext_csd[EXT_CSD_ERASED_MEM_CONT]) && - (ext_csd[EXT_CSD_REV] == + (card->ext_csd.rev == bw_ext_csd[EXT_CSD_REV]) && - (ext_csd[EXT_CSD_STRUCTURE] == + (card->ext_csd.raw_ext_csd_structure == bw_ext_csd[EXT_CSD_STRUCTURE]) && - (ext_csd[EXT_CSD_CARD_TYPE] == + (card->ext_csd.raw_card_type == bw_ext_csd[EXT_CSD_CARD_TYPE]) && - (ext_csd[EXT_CSD_S_A_TIMEOUT] == + (card->ext_csd.raw_s_a_timeout == bw_ext_csd[EXT_CSD_S_A_TIMEOUT]) && - (ext_csd[EXT_CSD_HC_WP_GRP_SIZE] == + (card->ext_csd.raw_hc_erase_gap_size == bw_ext_csd[EXT_CSD_HC_WP_GRP_SIZE]) && - (ext_csd[EXT_CSD_ERASE_TIMEOUT_MULT] == + (card->ext_csd.raw_erase_timeout_mult == bw_ext_csd[EXT_CSD_ERASE_TIMEOUT_MULT]) && - (ext_csd[EXT_CSD_HC_ERASE_GRP_SIZE] == + (card->ext_csd.raw_hc_erase_grp_size == bw_ext_csd[EXT_CSD_HC_ERASE_GRP_SIZE]) && - (ext_csd[EXT_CSD_SEC_TRIM_MULT] == + (card->ext_csd.raw_sec_trim_mult == bw_ext_csd[EXT_CSD_SEC_TRIM_MULT]) && - (ext_csd[EXT_CSD_SEC_ERASE_MULT] == + (card->ext_csd.raw_sec_erase_mult == bw_ext_csd[EXT_CSD_SEC_ERASE_MULT]) && - (ext_csd[EXT_CSD_SEC_FEATURE_SUPPORT] == + (card->ext_csd.raw_sec_feature_support == bw_ext_csd[EXT_CSD_SEC_FEATURE_SUPPORT]) && - (ext_csd[EXT_CSD_TRIM_MULT] == + (card->ext_csd.raw_trim_mult == bw_ext_csd[EXT_CSD_TRIM_MULT]) && - memcmp(&ext_csd[EXT_CSD_SEC_CNT], - &bw_ext_csd[EXT_CSD_SEC_CNT], - 4) != 0); + (card->ext_csd.raw_sectors[0] == + bw_ext_csd[EXT_CSD_SEC_CNT + 0]) && + (card->ext_csd.raw_sectors[1] == + bw_ext_csd[EXT_CSD_SEC_CNT + 1]) && + (card->ext_csd.raw_sectors[2] == + bw_ext_csd[EXT_CSD_SEC_CNT + 2]) && + (card->ext_csd.raw_sectors[3] == + bw_ext_csd[EXT_CSD_SEC_CNT + 3])); if (err) err = -EINVAL; @@ -770,7 +794,6 @@ static int mmc_init_card(struct mmc_host *host, u32 ocr, */ if (!(host->caps & MMC_CAP_BUS_WIDTH_TEST)) err = mmc_compare_ext_csds(card, - ext_csd, bus_width); else err = mmc_bus_test(card, bus_width); diff --git a/drivers/mmc/host/sdhci-pltfm.c b/drivers/mmc/host/sdhci-pltfm.c index dbab0407f4b..e231f917225 100644 --- a/drivers/mmc/host/sdhci-pltfm.c +++ b/drivers/mmc/host/sdhci-pltfm.c @@ -49,10 +49,30 @@ static struct sdhci_ops sdhci_pltfm_ops = { * Device probing/removal * * * \*****************************************************************************/ +#if defined(CONFIG_OF) +#include <linux/of_device.h> +static const struct of_device_id sdhci_dt_ids[] = { + { .compatible = "nvidia,tegra20-sdhci", .data = &sdhci_tegra_dt_pdata }, + { } +}; +MODULE_DEVICE_TABLE(platform, sdhci_dt_ids); + +static const struct of_device_id *sdhci_get_of_device_id(struct platform_device *pdev) +{ + return of_match_device(sdhci_dt_ids, &pdev->dev); +} +#else +#define sdhci_dt_ids NULL +static inline struct of_device_id *sdhci_get_of_device_id(struct platform_device *pdev) +{ + return NULL; +} +#endif static int __devinit sdhci_pltfm_probe(struct platform_device *pdev) { const struct platform_device_id *platid = platform_get_device_id(pdev); + const struct of_device_id *dtid = sdhci_get_of_device_id(pdev); struct sdhci_pltfm_data *pdata; struct sdhci_host *host; struct sdhci_pltfm_host *pltfm_host; @@ -61,6 +81,8 @@ static int __devinit sdhci_pltfm_probe(struct platform_device *pdev) if (platid && platid->driver_data) pdata = (void *)platid->driver_data; + else if (dtid && dtid->data) + pdata = dtid->data; else pdata = pdev->dev.platform_data; @@ -140,12 +162,21 @@ err: static int __devexit sdhci_pltfm_remove(struct platform_device *pdev) { - struct sdhci_pltfm_data *pdata = pdev->dev.platform_data; + const struct platform_device_id *platid = platform_get_device_id(pdev); + const struct of_device_id *dtid = sdhci_get_of_device_id(pdev); + struct sdhci_pltfm_data *pdata; struct sdhci_host *host = platform_get_drvdata(pdev); struct resource *iomem = platform_get_resource(pdev, IORESOURCE_MEM, 0); int dead; u32 scratch; + if (platid && platid->driver_data) + pdata = (void *)platid->driver_data; + else if (dtid && dtid->data) + pdata = dtid->data; + else + pdata = pdev->dev.platform_data; + dead = 0; scratch = readl(host->ioaddr + SDHCI_INT_STATUS); if (scratch == (u32)-1) @@ -203,6 +234,7 @@ static struct platform_driver sdhci_pltfm_driver = { .driver = { .name = "sdhci", .owner = THIS_MODULE, + .of_match_table = sdhci_dt_ids, }, .probe = sdhci_pltfm_probe, .remove = __devexit_p(sdhci_pltfm_remove), diff --git a/drivers/mmc/host/sdhci-pltfm.h b/drivers/mmc/host/sdhci-pltfm.h index 2b37016ad0a..2a438175839 100644 --- a/drivers/mmc/host/sdhci-pltfm.h +++ b/drivers/mmc/host/sdhci-pltfm.h @@ -24,5 +24,6 @@ extern struct sdhci_pltfm_data sdhci_cns3xxx_pdata; extern struct sdhci_pltfm_data sdhci_esdhc_imx_pdata; extern struct sdhci_pltfm_data sdhci_dove_pdata; extern struct sdhci_pltfm_data sdhci_tegra_pdata; +extern struct sdhci_pltfm_data sdhci_tegra_dt_pdata; #endif /* _DRIVERS_MMC_SDHCI_PLTFM_H */ diff --git a/drivers/mmc/host/sdhci-tegra.c b/drivers/mmc/host/sdhci-tegra.c index 343c97edba3..c9d4d282041 100644 --- a/drivers/mmc/host/sdhci-tegra.c +++ b/drivers/mmc/host/sdhci-tegra.c @@ -18,8 +18,10 @@ #include <linux/clk.h> #include <linux/io.h> #include <linux/gpio.h> +#include <linux/of_gpio.h> #include <linux/mmc/card.h> #include <linux/mmc/host.h> +#include <linux/slab.h> #include <mach/gpio.h> #include <mach/sdhci.h> @@ -216,6 +218,33 @@ out: return rc; } +static int tegra_sdhci_pltfm_dt_init(struct sdhci_host *host, + struct sdhci_pltfm_data *pdata) +{ + struct platform_device *pdev = to_platform_device(mmc_dev(host->mmc)); + struct tegra_sdhci_platform_data *plat; + + if (pdev->dev.platform_data) { + dev_err(&pdev->dev, "%s: platform_data not NULL; aborting\n", + __func__); + return -ENODEV; + } + + plat = kzalloc(sizeof(*plat), GFP_KERNEL); + if (!plat) + return -ENOMEM; + pdev->dev.platform_data = plat; + + plat->cd_gpio = of_get_gpio(pdev->dev.of_node, 0); + plat->wp_gpio = of_get_gpio(pdev->dev.of_node, 1); + plat->power_gpio = of_get_gpio(pdev->dev.of_node, 2); + + dev_info(&pdev->dev, "using gpios cd=%i, wp=%i power=%i\n", + plat->cd_gpio, plat->wp_gpio, plat->power_gpio); + + return tegra_sdhci_pltfm_init(host, pdata); +} + static void tegra_sdhci_pltfm_exit(struct sdhci_host *host) { struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); @@ -244,6 +273,16 @@ static void tegra_sdhci_pltfm_exit(struct sdhci_host *host) clk_put(pltfm_host->clk); } +static void tegra_sdhci_pltfm_dt_exit(struct sdhci_host *host) +{ + struct platform_device *pdev = to_platform_device(mmc_dev(host->mmc)); + + tegra_sdhci_pltfm_exit(host); + + kfree(pdev->dev.platform_data); + pdev->dev.platform_data = NULL; +} + static struct sdhci_ops tegra_sdhci_ops = { .get_ro = tegra_sdhci_get_ro, .read_l = tegra_sdhci_readl, @@ -261,3 +300,13 @@ struct sdhci_pltfm_data sdhci_tegra_pdata = { .init = tegra_sdhci_pltfm_init, .exit = tegra_sdhci_pltfm_exit, }; + +struct sdhci_pltfm_data sdhci_tegra_dt_pdata = { + .quirks = SDHCI_QUIRK_BROKEN_TIMEOUT_VAL | + SDHCI_QUIRK_SINGLE_POWER_WRITE | + SDHCI_QUIRK_NO_HISPD_BIT | + SDHCI_QUIRK_BROKEN_ADMA_ZEROLEN_DESC, + .ops = &tegra_sdhci_ops, + .init = tegra_sdhci_pltfm_dt_init, + .exit = tegra_sdhci_pltfm_dt_exit, +}; |