14101c16aSPierre Ossman /* 24101c16aSPierre Ossman * linux/drivers/mmc/core/bus.c 34101c16aSPierre Ossman * 44101c16aSPierre Ossman * Copyright (C) 2003 Russell King, All Rights Reserved. 54101c16aSPierre Ossman * Copyright (C) 2007 Pierre Ossman 64101c16aSPierre Ossman * 74101c16aSPierre Ossman * This program is free software; you can redistribute it and/or modify 84101c16aSPierre Ossman * it under the terms of the GNU General Public License version 2 as 94101c16aSPierre Ossman * published by the Free Software Foundation. 104101c16aSPierre Ossman * 114101c16aSPierre Ossman * MMC card bus driver model 124101c16aSPierre Ossman */ 134101c16aSPierre Ossman 143ef77af1SPaul Gortmaker #include <linux/export.h> 154101c16aSPierre Ossman #include <linux/device.h> 164101c16aSPierre Ossman #include <linux/err.h> 175a0e3ad6STejun Heo #include <linux/slab.h> 180205a904SPaul Gortmaker #include <linux/stat.h> 1925185f3fSSascha Hauer #include <linux/of.h> 20516d5ccdSOhad Ben-Cohen #include <linux/pm_runtime.h> 214101c16aSPierre Ossman 224101c16aSPierre Ossman #include <linux/mmc/card.h> 234101c16aSPierre Ossman #include <linux/mmc/host.h> 244101c16aSPierre Ossman 254101c16aSPierre Ossman #include "core.h" 264facdde1SUlf Hansson #include "card.h" 275857b29bSUlf Hansson #include "host.h" 281a632f8cSPierre Ossman #include "sdio_cis.h" 294101c16aSPierre Ossman #include "bus.h" 304101c16aSPierre Ossman 3196541bacSUlf Hansson #define to_mmc_driver(d) container_of(d, struct mmc_driver, drv) 3296541bacSUlf Hansson 33f24fc57bSGreg Kroah-Hartman static ssize_t type_show(struct device *dev, 344101c16aSPierre Ossman struct device_attribute *attr, char *buf) 354101c16aSPierre Ossman { 36265cdc90SAndy Shevchenko struct mmc_card *card = mmc_dev_to_card(dev); 374101c16aSPierre Ossman 384101c16aSPierre Ossman switch (card->type) { 394101c16aSPierre Ossman case MMC_TYPE_MMC: 404101c16aSPierre Ossman return sprintf(buf, "MMC\n"); 414101c16aSPierre Ossman case MMC_TYPE_SD: 424101c16aSPierre Ossman return sprintf(buf, "SD\n"); 435c4e6f13SPierre Ossman case MMC_TYPE_SDIO: 445c4e6f13SPierre Ossman return sprintf(buf, "SDIO\n"); 457310ece8SMichal Miroslaw case MMC_TYPE_SD_COMBO: 467310ece8SMichal Miroslaw return sprintf(buf, "SDcombo\n"); 474101c16aSPierre Ossman default: 484101c16aSPierre Ossman return -EFAULT; 494101c16aSPierre Ossman } 504101c16aSPierre Ossman } 51f24fc57bSGreg Kroah-Hartman static DEVICE_ATTR_RO(type); 524101c16aSPierre Ossman 53f24fc57bSGreg Kroah-Hartman static struct attribute *mmc_dev_attrs[] = { 54f24fc57bSGreg Kroah-Hartman &dev_attr_type.attr, 55f24fc57bSGreg Kroah-Hartman NULL, 564101c16aSPierre Ossman }; 57f24fc57bSGreg Kroah-Hartman ATTRIBUTE_GROUPS(mmc_dev); 584101c16aSPierre Ossman 594101c16aSPierre Ossman /* 604101c16aSPierre Ossman * This currently matches any MMC driver to any MMC card - drivers 614101c16aSPierre Ossman * themselves make the decision whether to drive this card in their 624101c16aSPierre Ossman * probe method. 634101c16aSPierre Ossman */ 644101c16aSPierre Ossman static int mmc_bus_match(struct device *dev, struct device_driver *drv) 654101c16aSPierre Ossman { 664101c16aSPierre Ossman return 1; 674101c16aSPierre Ossman } 684101c16aSPierre Ossman 694101c16aSPierre Ossman static int 707eff2e7aSKay Sievers mmc_bus_uevent(struct device *dev, struct kobj_uevent_env *env) 714101c16aSPierre Ossman { 72265cdc90SAndy Shevchenko struct mmc_card *card = mmc_dev_to_card(dev); 739eb3a94dSPierre Ossman const char *type; 747eff2e7aSKay Sievers int retval = 0; 754101c16aSPierre Ossman 764101c16aSPierre Ossman switch (card->type) { 774101c16aSPierre Ossman case MMC_TYPE_MMC: 789eb3a94dSPierre Ossman type = "MMC"; 794101c16aSPierre Ossman break; 804101c16aSPierre Ossman case MMC_TYPE_SD: 819eb3a94dSPierre Ossman type = "SD"; 824101c16aSPierre Ossman break; 835c4e6f13SPierre Ossman case MMC_TYPE_SDIO: 849eb3a94dSPierre Ossman type = "SDIO"; 855c4e6f13SPierre Ossman break; 867310ece8SMichal Miroslaw case MMC_TYPE_SD_COMBO: 877310ece8SMichal Miroslaw type = "SDcombo"; 887310ece8SMichal Miroslaw break; 899eb3a94dSPierre Ossman default: 909eb3a94dSPierre Ossman type = NULL; 914101c16aSPierre Ossman } 924101c16aSPierre Ossman 939eb3a94dSPierre Ossman if (type) { 947eff2e7aSKay Sievers retval = add_uevent_var(env, "MMC_TYPE=%s", type); 957eff2e7aSKay Sievers if (retval) 967eff2e7aSKay Sievers return retval; 979eb3a94dSPierre Ossman } 984101c16aSPierre Ossman 997eff2e7aSKay Sievers retval = add_uevent_var(env, "MMC_NAME=%s", mmc_card_name(card)); 1006b0b6285SAndy Whitcroft if (retval) 1016b0b6285SAndy Whitcroft return retval; 1026b0b6285SAndy Whitcroft 1036b0b6285SAndy Whitcroft /* 1046b0b6285SAndy Whitcroft * Request the mmc_block device. Note: that this is a direct request 1056b0b6285SAndy Whitcroft * for the module it carries no information as to what is inserted. 1066b0b6285SAndy Whitcroft */ 1076b0b6285SAndy Whitcroft retval = add_uevent_var(env, "MODALIAS=mmc:block"); 1084101c16aSPierre Ossman 1097eff2e7aSKay Sievers return retval; 1104101c16aSPierre Ossman } 1114101c16aSPierre Ossman 11296541bacSUlf Hansson static int mmc_bus_probe(struct device *dev) 11396541bacSUlf Hansson { 11496541bacSUlf Hansson struct mmc_driver *drv = to_mmc_driver(dev->driver); 11596541bacSUlf Hansson struct mmc_card *card = mmc_dev_to_card(dev); 11696541bacSUlf Hansson 11796541bacSUlf Hansson return drv->probe(card); 11896541bacSUlf Hansson } 11996541bacSUlf Hansson 12096541bacSUlf Hansson static int mmc_bus_remove(struct device *dev) 12196541bacSUlf Hansson { 12296541bacSUlf Hansson struct mmc_driver *drv = to_mmc_driver(dev->driver); 12396541bacSUlf Hansson struct mmc_card *card = mmc_dev_to_card(dev); 12496541bacSUlf Hansson 12596541bacSUlf Hansson drv->remove(card); 12696541bacSUlf Hansson 12796541bacSUlf Hansson return 0; 12896541bacSUlf Hansson } 12996541bacSUlf Hansson 13076287748SUlf Hansson static void mmc_bus_shutdown(struct device *dev) 13176287748SUlf Hansson { 13296541bacSUlf Hansson struct mmc_driver *drv = to_mmc_driver(dev->driver); 13376287748SUlf Hansson struct mmc_card *card = mmc_dev_to_card(dev); 1346b086bdeSUlf Hansson struct mmc_host *host = card->host; 1356b086bdeSUlf Hansson int ret; 13676287748SUlf Hansson 13796541bacSUlf Hansson if (dev->driver && drv->shutdown) 13896541bacSUlf Hansson drv->shutdown(card); 1396b086bdeSUlf Hansson 1406b086bdeSUlf Hansson if (host->bus_ops->shutdown) { 1416b086bdeSUlf Hansson ret = host->bus_ops->shutdown(host); 1426b086bdeSUlf Hansson if (ret) 1436b086bdeSUlf Hansson pr_warn("%s: error %d during shutdown\n", 1446b086bdeSUlf Hansson mmc_hostname(host), ret); 1456b086bdeSUlf Hansson } 14676287748SUlf Hansson } 14776287748SUlf Hansson 1480dd1bfebSChuanxiao Dong #ifdef CONFIG_PM_SLEEP 14932d317c6SChuanxiao Dong static int mmc_bus_suspend(struct device *dev) 1504101c16aSPierre Ossman { 151265cdc90SAndy Shevchenko struct mmc_card *card = mmc_dev_to_card(dev); 152986892caSUlf Hansson struct mmc_host *host = card->host; 153986892caSUlf Hansson int ret; 1544101c16aSPierre Ossman 1550967edc6SUlf Hansson ret = pm_generic_suspend(dev); 156986892caSUlf Hansson if (ret) 157986892caSUlf Hansson return ret; 158986892caSUlf Hansson 159986892caSUlf Hansson ret = host->bus_ops->suspend(host); 1604101c16aSPierre Ossman return ret; 1614101c16aSPierre Ossman } 1624101c16aSPierre Ossman 1634101c16aSPierre Ossman static int mmc_bus_resume(struct device *dev) 1644101c16aSPierre Ossman { 165265cdc90SAndy Shevchenko struct mmc_card *card = mmc_dev_to_card(dev); 166986892caSUlf Hansson struct mmc_host *host = card->host; 167986892caSUlf Hansson int ret; 168986892caSUlf Hansson 169986892caSUlf Hansson ret = host->bus_ops->resume(host); 170986892caSUlf Hansson if (ret) 171986892caSUlf Hansson pr_warn("%s: error %d during resume (card was removed?)\n", 172986892caSUlf Hansson mmc_hostname(host), ret); 1734101c16aSPierre Ossman 1740967edc6SUlf Hansson ret = pm_generic_resume(dev); 1754101c16aSPierre Ossman return ret; 1764101c16aSPierre Ossman } 1770dd1bfebSChuanxiao Dong #endif 1784101c16aSPierre Ossman 179162d6f98SRafael J. Wysocki #ifdef CONFIG_PM 180516d5ccdSOhad Ben-Cohen static int mmc_runtime_suspend(struct device *dev) 181516d5ccdSOhad Ben-Cohen { 182516d5ccdSOhad Ben-Cohen struct mmc_card *card = mmc_dev_to_card(dev); 18312d01d0bSUlf Hansson struct mmc_host *host = card->host; 184516d5ccdSOhad Ben-Cohen 1855601aaf7SUlf Hansson return host->bus_ops->runtime_suspend(host); 186516d5ccdSOhad Ben-Cohen } 187516d5ccdSOhad Ben-Cohen 188516d5ccdSOhad Ben-Cohen static int mmc_runtime_resume(struct device *dev) 189516d5ccdSOhad Ben-Cohen { 190516d5ccdSOhad Ben-Cohen struct mmc_card *card = mmc_dev_to_card(dev); 19112d01d0bSUlf Hansson struct mmc_host *host = card->host; 192516d5ccdSOhad Ben-Cohen 1935601aaf7SUlf Hansson return host->bus_ops->runtime_resume(host); 194516d5ccdSOhad Ben-Cohen } 195162d6f98SRafael J. Wysocki #endif /* !CONFIG_PM */ 196516d5ccdSOhad Ben-Cohen 19732d317c6SChuanxiao Dong static const struct dev_pm_ops mmc_bus_pm_ops = { 1982e42da59SUlf Hansson SET_RUNTIME_PM_OPS(mmc_runtime_suspend, mmc_runtime_resume, NULL) 19932d317c6SChuanxiao Dong SET_SYSTEM_SLEEP_PM_OPS(mmc_bus_suspend, mmc_bus_resume) 20032d317c6SChuanxiao Dong }; 20132d317c6SChuanxiao Dong 2024101c16aSPierre Ossman static struct bus_type mmc_bus_type = { 2034101c16aSPierre Ossman .name = "mmc", 204f24fc57bSGreg Kroah-Hartman .dev_groups = mmc_dev_groups, 2054101c16aSPierre Ossman .match = mmc_bus_match, 2064101c16aSPierre Ossman .uevent = mmc_bus_uevent, 20796541bacSUlf Hansson .probe = mmc_bus_probe, 20896541bacSUlf Hansson .remove = mmc_bus_remove, 20976287748SUlf Hansson .shutdown = mmc_bus_shutdown, 21032d317c6SChuanxiao Dong .pm = &mmc_bus_pm_ops, 2114101c16aSPierre Ossman }; 2124101c16aSPierre Ossman 2134101c16aSPierre Ossman int mmc_register_bus(void) 2144101c16aSPierre Ossman { 2154101c16aSPierre Ossman return bus_register(&mmc_bus_type); 2164101c16aSPierre Ossman } 2174101c16aSPierre Ossman 2184101c16aSPierre Ossman void mmc_unregister_bus(void) 2194101c16aSPierre Ossman { 2204101c16aSPierre Ossman bus_unregister(&mmc_bus_type); 2214101c16aSPierre Ossman } 2224101c16aSPierre Ossman 2234101c16aSPierre Ossman /** 2244101c16aSPierre Ossman * mmc_register_driver - register a media driver 2254101c16aSPierre Ossman * @drv: MMC media driver 2264101c16aSPierre Ossman */ 22796541bacSUlf Hansson int mmc_register_driver(struct mmc_driver *drv) 2284101c16aSPierre Ossman { 22996541bacSUlf Hansson drv->drv.bus = &mmc_bus_type; 23096541bacSUlf Hansson return driver_register(&drv->drv); 2314101c16aSPierre Ossman } 23296541bacSUlf Hansson 2334101c16aSPierre Ossman EXPORT_SYMBOL(mmc_register_driver); 2344101c16aSPierre Ossman 2354101c16aSPierre Ossman /** 2364101c16aSPierre Ossman * mmc_unregister_driver - unregister a media driver 2374101c16aSPierre Ossman * @drv: MMC media driver 2384101c16aSPierre Ossman */ 23996541bacSUlf Hansson void mmc_unregister_driver(struct mmc_driver *drv) 2404101c16aSPierre Ossman { 24196541bacSUlf Hansson drv->drv.bus = &mmc_bus_type; 24296541bacSUlf Hansson driver_unregister(&drv->drv); 2434101c16aSPierre Ossman } 24496541bacSUlf Hansson 2454101c16aSPierre Ossman EXPORT_SYMBOL(mmc_unregister_driver); 2464101c16aSPierre Ossman 2474101c16aSPierre Ossman static void mmc_release_card(struct device *dev) 2484101c16aSPierre Ossman { 249265cdc90SAndy Shevchenko struct mmc_card *card = mmc_dev_to_card(dev); 2504101c16aSPierre Ossman 2511a632f8cSPierre Ossman sdio_free_common_cis(card); 2521a632f8cSPierre Ossman 253759bdc7aSPierre Ossman kfree(card->info); 254759bdc7aSPierre Ossman 2554101c16aSPierre Ossman kfree(card); 2564101c16aSPierre Ossman } 2574101c16aSPierre Ossman 2584101c16aSPierre Ossman /* 2594101c16aSPierre Ossman * Allocate and initialise a new MMC card structure. 2604101c16aSPierre Ossman */ 26151ec92e2SPierre Ossman struct mmc_card *mmc_alloc_card(struct mmc_host *host, struct device_type *type) 2624101c16aSPierre Ossman { 2634101c16aSPierre Ossman struct mmc_card *card; 2644101c16aSPierre Ossman 265733cb1e4SMariusz Kozlowski card = kzalloc(sizeof(struct mmc_card), GFP_KERNEL); 2664101c16aSPierre Ossman if (!card) 2674101c16aSPierre Ossman return ERR_PTR(-ENOMEM); 2684101c16aSPierre Ossman 2694101c16aSPierre Ossman card->host = host; 2704101c16aSPierre Ossman 2714101c16aSPierre Ossman device_initialize(&card->dev); 2724101c16aSPierre Ossman 2734101c16aSPierre Ossman card->dev.parent = mmc_classdev(host); 2744101c16aSPierre Ossman card->dev.bus = &mmc_bus_type; 2754101c16aSPierre Ossman card->dev.release = mmc_release_card; 27651ec92e2SPierre Ossman card->dev.type = type; 2774101c16aSPierre Ossman 2784101c16aSPierre Ossman return card; 2794101c16aSPierre Ossman } 2804101c16aSPierre Ossman 2814101c16aSPierre Ossman /* 2824101c16aSPierre Ossman * Register a new MMC card with the driver model. 2834101c16aSPierre Ossman */ 2844101c16aSPierre Ossman int mmc_add_card(struct mmc_card *card) 2854101c16aSPierre Ossman { 2864101c16aSPierre Ossman int ret; 287109b5bedSPierre Ossman const char *type; 2886500c8edSSubhash Jadavani const char *uhs_bus_speed_mode = ""; 2896500c8edSSubhash Jadavani static const char *const uhs_speeds[] = { 2906500c8edSSubhash Jadavani [UHS_SDR12_BUS_SPEED] = "SDR12 ", 2916500c8edSSubhash Jadavani [UHS_SDR25_BUS_SPEED] = "SDR25 ", 2926500c8edSSubhash Jadavani [UHS_SDR50_BUS_SPEED] = "SDR50 ", 2936500c8edSSubhash Jadavani [UHS_SDR104_BUS_SPEED] = "SDR104 ", 2946500c8edSSubhash Jadavani [UHS_DDR50_BUS_SPEED] = "DDR50 ", 2956500c8edSSubhash Jadavani }; 2966500c8edSSubhash Jadavani 2974101c16aSPierre Ossman 298d1b26863SKay Sievers dev_set_name(&card->dev, "%s:%04x", mmc_hostname(card->host), card->rca); 2994101c16aSPierre Ossman 300109b5bedSPierre Ossman switch (card->type) { 301109b5bedSPierre Ossman case MMC_TYPE_MMC: 302109b5bedSPierre Ossman type = "MMC"; 303109b5bedSPierre Ossman break; 304109b5bedSPierre Ossman case MMC_TYPE_SD: 305109b5bedSPierre Ossman type = "SD"; 3063a303511SArindam Nath if (mmc_card_blockaddr(card)) { 3073a303511SArindam Nath if (mmc_card_ext_capacity(card)) 3083a303511SArindam Nath type = "SDXC"; 3093a303511SArindam Nath else 310109b5bedSPierre Ossman type = "SDHC"; 3113a303511SArindam Nath } 312109b5bedSPierre Ossman break; 3135c4e6f13SPierre Ossman case MMC_TYPE_SDIO: 3145c4e6f13SPierre Ossman type = "SDIO"; 3155c4e6f13SPierre Ossman break; 3167310ece8SMichal Miroslaw case MMC_TYPE_SD_COMBO: 3177310ece8SMichal Miroslaw type = "SD-combo"; 3187310ece8SMichal Miroslaw if (mmc_card_blockaddr(card)) 3197310ece8SMichal Miroslaw type = "SDHC-combo"; 3209bc21848SMichał Mirosław break; 321109b5bedSPierre Ossman default: 322109b5bedSPierre Ossman type = "?"; 323109b5bedSPierre Ossman break; 324109b5bedSPierre Ossman } 325109b5bedSPierre Ossman 32671ef1ea4SJackey Shen if (mmc_card_uhs(card) && 3276500c8edSSubhash Jadavani (card->sd_bus_speed < ARRAY_SIZE(uhs_speeds))) 3286500c8edSSubhash Jadavani uhs_bus_speed_mode = uhs_speeds[card->sd_bus_speed]; 3296500c8edSSubhash Jadavani 330af517150SDavid Brownell if (mmc_host_is_spi(card->host)) { 331a3c76eb9SGirish K S pr_info("%s: new %s%s%s card on SPI\n", 332af517150SDavid Brownell mmc_hostname(card->host), 333cdc99179SSeungwon Jeon mmc_card_hs(card) ? "high speed " : "", 334cdc99179SSeungwon Jeon mmc_card_ddr52(card) ? "DDR " : "", 335af517150SDavid Brownell type); 336af517150SDavid Brownell } else { 33781ac2af6SShawn Lin pr_info("%s: new %s%s%s%s%s%s card at address %04x\n", 338109b5bedSPierre Ossman mmc_hostname(card->host), 339a303c531SPhilip Rakity mmc_card_uhs(card) ? "ultra high speed " : 340cdc99179SSeungwon Jeon (mmc_card_hs(card) ? "high speed " : ""), 3410a5b6438SSeungwon Jeon mmc_card_hs400(card) ? "HS400 " : 342a4924c71SGirish K S (mmc_card_hs200(card) ? "HS200 " : ""), 34381ac2af6SShawn Lin mmc_card_hs400es(card) ? "Enhanced strobe " : "", 344cdc99179SSeungwon Jeon mmc_card_ddr52(card) ? "DDR " : "", 3456500c8edSSubhash Jadavani uhs_bus_speed_mode, type, card->rca); 346af517150SDavid Brownell } 347109b5bedSPierre Ossman 348f4b7f927SHaavard Skinnemoen #ifdef CONFIG_DEBUG_FS 349f4b7f927SHaavard Skinnemoen mmc_add_card_debugfs(card); 350f4b7f927SHaavard Skinnemoen #endif 3512220eedfSKonstantin Dorfman mmc_init_context_info(card->host); 352f4b7f927SHaavard Skinnemoen 35325185f3fSSascha Hauer card->dev.of_node = mmc_of_find_child_device(card->host, 0); 35425185f3fSSascha Hauer 355ec076cd2SFu, Zhonghui device_enable_async_suspend(&card->dev); 356ec076cd2SFu, Zhonghui 3571a2727e9SViresh Kumar ret = device_add(&card->dev); 3581a2727e9SViresh Kumar if (ret) 3591a2727e9SViresh Kumar return ret; 3601a2727e9SViresh Kumar 3614101c16aSPierre Ossman mmc_card_set_present(card); 3624101c16aSPierre Ossman 3634101c16aSPierre Ossman return 0; 3644101c16aSPierre Ossman } 3654101c16aSPierre Ossman 3664101c16aSPierre Ossman /* 3674101c16aSPierre Ossman * Unregister a new MMC card with the driver model, and 3684101c16aSPierre Ossman * (eventually) free it. 3694101c16aSPierre Ossman */ 3704101c16aSPierre Ossman void mmc_remove_card(struct mmc_card *card) 3714101c16aSPierre Ossman { 372f690f440SAdrian Hunter struct mmc_host *host = card->host; 373f690f440SAdrian Hunter 374f4b7f927SHaavard Skinnemoen #ifdef CONFIG_DEBUG_FS 375f4b7f927SHaavard Skinnemoen mmc_remove_card_debugfs(card); 376f4b7f927SHaavard Skinnemoen #endif 377f4b7f927SHaavard Skinnemoen 378f690f440SAdrian Hunter if (host->cqe_enabled) { 379f690f440SAdrian Hunter host->cqe_ops->cqe_disable(host); 380f690f440SAdrian Hunter host->cqe_enabled = false; 381f690f440SAdrian Hunter } 382f690f440SAdrian Hunter 3834101c16aSPierre Ossman if (mmc_card_present(card)) { 384af517150SDavid Brownell if (mmc_host_is_spi(card->host)) { 385a3c76eb9SGirish K S pr_info("%s: SPI card removed\n", 386af517150SDavid Brownell mmc_hostname(card->host)); 387af517150SDavid Brownell } else { 388a3c76eb9SGirish K S pr_info("%s: card %04x removed\n", 389109b5bedSPierre Ossman mmc_hostname(card->host), card->rca); 390af517150SDavid Brownell } 3914101c16aSPierre Ossman device_del(&card->dev); 39225185f3fSSascha Hauer of_node_put(card->dev.of_node); 3934101c16aSPierre Ossman } 3944101c16aSPierre Ossman 3954101c16aSPierre Ossman put_device(&card->dev); 3964101c16aSPierre Ossman } 3974101c16aSPierre Ossman 398