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); 160ebe7dd45SAdrian Hunter if (ret) 161ebe7dd45SAdrian Hunter pm_generic_resume(dev); 162ebe7dd45SAdrian Hunter 1634101c16aSPierre Ossman return ret; 1644101c16aSPierre Ossman } 1654101c16aSPierre Ossman 1664101c16aSPierre Ossman static int mmc_bus_resume(struct device *dev) 1674101c16aSPierre Ossman { 168265cdc90SAndy Shevchenko struct mmc_card *card = mmc_dev_to_card(dev); 169986892caSUlf Hansson struct mmc_host *host = card->host; 170986892caSUlf Hansson int ret; 171986892caSUlf Hansson 172986892caSUlf Hansson ret = host->bus_ops->resume(host); 173986892caSUlf Hansson if (ret) 174986892caSUlf Hansson pr_warn("%s: error %d during resume (card was removed?)\n", 175986892caSUlf Hansson mmc_hostname(host), ret); 1764101c16aSPierre Ossman 1770967edc6SUlf Hansson ret = pm_generic_resume(dev); 1784101c16aSPierre Ossman return ret; 1794101c16aSPierre Ossman } 1800dd1bfebSChuanxiao Dong #endif 1814101c16aSPierre Ossman 182162d6f98SRafael J. Wysocki #ifdef CONFIG_PM 183516d5ccdSOhad Ben-Cohen static int mmc_runtime_suspend(struct device *dev) 184516d5ccdSOhad Ben-Cohen { 185516d5ccdSOhad Ben-Cohen struct mmc_card *card = mmc_dev_to_card(dev); 18612d01d0bSUlf Hansson struct mmc_host *host = card->host; 187516d5ccdSOhad Ben-Cohen 1885601aaf7SUlf Hansson return host->bus_ops->runtime_suspend(host); 189516d5ccdSOhad Ben-Cohen } 190516d5ccdSOhad Ben-Cohen 191516d5ccdSOhad Ben-Cohen static int mmc_runtime_resume(struct device *dev) 192516d5ccdSOhad Ben-Cohen { 193516d5ccdSOhad Ben-Cohen struct mmc_card *card = mmc_dev_to_card(dev); 19412d01d0bSUlf Hansson struct mmc_host *host = card->host; 195516d5ccdSOhad Ben-Cohen 1965601aaf7SUlf Hansson return host->bus_ops->runtime_resume(host); 197516d5ccdSOhad Ben-Cohen } 198162d6f98SRafael J. Wysocki #endif /* !CONFIG_PM */ 199516d5ccdSOhad Ben-Cohen 20032d317c6SChuanxiao Dong static const struct dev_pm_ops mmc_bus_pm_ops = { 2012e42da59SUlf Hansson SET_RUNTIME_PM_OPS(mmc_runtime_suspend, mmc_runtime_resume, NULL) 20232d317c6SChuanxiao Dong SET_SYSTEM_SLEEP_PM_OPS(mmc_bus_suspend, mmc_bus_resume) 20332d317c6SChuanxiao Dong }; 20432d317c6SChuanxiao Dong 2054101c16aSPierre Ossman static struct bus_type mmc_bus_type = { 2064101c16aSPierre Ossman .name = "mmc", 207f24fc57bSGreg Kroah-Hartman .dev_groups = mmc_dev_groups, 2084101c16aSPierre Ossman .match = mmc_bus_match, 2094101c16aSPierre Ossman .uevent = mmc_bus_uevent, 21096541bacSUlf Hansson .probe = mmc_bus_probe, 21196541bacSUlf Hansson .remove = mmc_bus_remove, 21276287748SUlf Hansson .shutdown = mmc_bus_shutdown, 21332d317c6SChuanxiao Dong .pm = &mmc_bus_pm_ops, 2144101c16aSPierre Ossman }; 2154101c16aSPierre Ossman 2164101c16aSPierre Ossman int mmc_register_bus(void) 2174101c16aSPierre Ossman { 2184101c16aSPierre Ossman return bus_register(&mmc_bus_type); 2194101c16aSPierre Ossman } 2204101c16aSPierre Ossman 2214101c16aSPierre Ossman void mmc_unregister_bus(void) 2224101c16aSPierre Ossman { 2234101c16aSPierre Ossman bus_unregister(&mmc_bus_type); 2244101c16aSPierre Ossman } 2254101c16aSPierre Ossman 2264101c16aSPierre Ossman /** 2274101c16aSPierre Ossman * mmc_register_driver - register a media driver 2284101c16aSPierre Ossman * @drv: MMC media driver 2294101c16aSPierre Ossman */ 23096541bacSUlf Hansson int mmc_register_driver(struct mmc_driver *drv) 2314101c16aSPierre Ossman { 23296541bacSUlf Hansson drv->drv.bus = &mmc_bus_type; 23396541bacSUlf Hansson return driver_register(&drv->drv); 2344101c16aSPierre Ossman } 23596541bacSUlf Hansson 2364101c16aSPierre Ossman EXPORT_SYMBOL(mmc_register_driver); 2374101c16aSPierre Ossman 2384101c16aSPierre Ossman /** 2394101c16aSPierre Ossman * mmc_unregister_driver - unregister a media driver 2404101c16aSPierre Ossman * @drv: MMC media driver 2414101c16aSPierre Ossman */ 24296541bacSUlf Hansson void mmc_unregister_driver(struct mmc_driver *drv) 2434101c16aSPierre Ossman { 24496541bacSUlf Hansson drv->drv.bus = &mmc_bus_type; 24596541bacSUlf Hansson driver_unregister(&drv->drv); 2464101c16aSPierre Ossman } 24796541bacSUlf Hansson 2484101c16aSPierre Ossman EXPORT_SYMBOL(mmc_unregister_driver); 2494101c16aSPierre Ossman 2504101c16aSPierre Ossman static void mmc_release_card(struct device *dev) 2514101c16aSPierre Ossman { 252265cdc90SAndy Shevchenko struct mmc_card *card = mmc_dev_to_card(dev); 2534101c16aSPierre Ossman 2541a632f8cSPierre Ossman sdio_free_common_cis(card); 2551a632f8cSPierre Ossman 256759bdc7aSPierre Ossman kfree(card->info); 257759bdc7aSPierre Ossman 2584101c16aSPierre Ossman kfree(card); 2594101c16aSPierre Ossman } 2604101c16aSPierre Ossman 2614101c16aSPierre Ossman /* 2624101c16aSPierre Ossman * Allocate and initialise a new MMC card structure. 2634101c16aSPierre Ossman */ 26451ec92e2SPierre Ossman struct mmc_card *mmc_alloc_card(struct mmc_host *host, struct device_type *type) 2654101c16aSPierre Ossman { 2664101c16aSPierre Ossman struct mmc_card *card; 2674101c16aSPierre Ossman 268733cb1e4SMariusz Kozlowski card = kzalloc(sizeof(struct mmc_card), GFP_KERNEL); 2694101c16aSPierre Ossman if (!card) 2704101c16aSPierre Ossman return ERR_PTR(-ENOMEM); 2714101c16aSPierre Ossman 2724101c16aSPierre Ossman card->host = host; 2734101c16aSPierre Ossman 2744101c16aSPierre Ossman device_initialize(&card->dev); 2754101c16aSPierre Ossman 2764101c16aSPierre Ossman card->dev.parent = mmc_classdev(host); 2774101c16aSPierre Ossman card->dev.bus = &mmc_bus_type; 2784101c16aSPierre Ossman card->dev.release = mmc_release_card; 27951ec92e2SPierre Ossman card->dev.type = type; 2804101c16aSPierre Ossman 2814101c16aSPierre Ossman return card; 2824101c16aSPierre Ossman } 2834101c16aSPierre Ossman 2844101c16aSPierre Ossman /* 2854101c16aSPierre Ossman * Register a new MMC card with the driver model. 2864101c16aSPierre Ossman */ 2874101c16aSPierre Ossman int mmc_add_card(struct mmc_card *card) 2884101c16aSPierre Ossman { 2894101c16aSPierre Ossman int ret; 290109b5bedSPierre Ossman const char *type; 2916500c8edSSubhash Jadavani const char *uhs_bus_speed_mode = ""; 2926500c8edSSubhash Jadavani static const char *const uhs_speeds[] = { 2936500c8edSSubhash Jadavani [UHS_SDR12_BUS_SPEED] = "SDR12 ", 2946500c8edSSubhash Jadavani [UHS_SDR25_BUS_SPEED] = "SDR25 ", 2956500c8edSSubhash Jadavani [UHS_SDR50_BUS_SPEED] = "SDR50 ", 2966500c8edSSubhash Jadavani [UHS_SDR104_BUS_SPEED] = "SDR104 ", 2976500c8edSSubhash Jadavani [UHS_DDR50_BUS_SPEED] = "DDR50 ", 2986500c8edSSubhash Jadavani }; 2996500c8edSSubhash Jadavani 3004101c16aSPierre Ossman 301d1b26863SKay Sievers dev_set_name(&card->dev, "%s:%04x", mmc_hostname(card->host), card->rca); 3024101c16aSPierre Ossman 303109b5bedSPierre Ossman switch (card->type) { 304109b5bedSPierre Ossman case MMC_TYPE_MMC: 305109b5bedSPierre Ossman type = "MMC"; 306109b5bedSPierre Ossman break; 307109b5bedSPierre Ossman case MMC_TYPE_SD: 308109b5bedSPierre Ossman type = "SD"; 3093a303511SArindam Nath if (mmc_card_blockaddr(card)) { 3103a303511SArindam Nath if (mmc_card_ext_capacity(card)) 3113a303511SArindam Nath type = "SDXC"; 3123a303511SArindam Nath else 313109b5bedSPierre Ossman type = "SDHC"; 3143a303511SArindam Nath } 315109b5bedSPierre Ossman break; 3165c4e6f13SPierre Ossman case MMC_TYPE_SDIO: 3175c4e6f13SPierre Ossman type = "SDIO"; 3185c4e6f13SPierre Ossman break; 3197310ece8SMichal Miroslaw case MMC_TYPE_SD_COMBO: 3207310ece8SMichal Miroslaw type = "SD-combo"; 3217310ece8SMichal Miroslaw if (mmc_card_blockaddr(card)) 3227310ece8SMichal Miroslaw type = "SDHC-combo"; 3239bc21848SMichał Mirosław break; 324109b5bedSPierre Ossman default: 325109b5bedSPierre Ossman type = "?"; 326109b5bedSPierre Ossman break; 327109b5bedSPierre Ossman } 328109b5bedSPierre Ossman 32971ef1ea4SJackey Shen if (mmc_card_uhs(card) && 3306500c8edSSubhash Jadavani (card->sd_bus_speed < ARRAY_SIZE(uhs_speeds))) 3316500c8edSSubhash Jadavani uhs_bus_speed_mode = uhs_speeds[card->sd_bus_speed]; 3326500c8edSSubhash Jadavani 333af517150SDavid Brownell if (mmc_host_is_spi(card->host)) { 334a3c76eb9SGirish K S pr_info("%s: new %s%s%s card on SPI\n", 335af517150SDavid Brownell mmc_hostname(card->host), 336cdc99179SSeungwon Jeon mmc_card_hs(card) ? "high speed " : "", 337cdc99179SSeungwon Jeon mmc_card_ddr52(card) ? "DDR " : "", 338af517150SDavid Brownell type); 339af517150SDavid Brownell } else { 34081ac2af6SShawn Lin pr_info("%s: new %s%s%s%s%s%s card at address %04x\n", 341109b5bedSPierre Ossman mmc_hostname(card->host), 342a303c531SPhilip Rakity mmc_card_uhs(card) ? "ultra high speed " : 343cdc99179SSeungwon Jeon (mmc_card_hs(card) ? "high speed " : ""), 3440a5b6438SSeungwon Jeon mmc_card_hs400(card) ? "HS400 " : 345a4924c71SGirish K S (mmc_card_hs200(card) ? "HS200 " : ""), 34681ac2af6SShawn Lin mmc_card_hs400es(card) ? "Enhanced strobe " : "", 347cdc99179SSeungwon Jeon mmc_card_ddr52(card) ? "DDR " : "", 3486500c8edSSubhash Jadavani uhs_bus_speed_mode, type, card->rca); 349af517150SDavid Brownell } 350109b5bedSPierre Ossman 351f4b7f927SHaavard Skinnemoen #ifdef CONFIG_DEBUG_FS 352f4b7f927SHaavard Skinnemoen mmc_add_card_debugfs(card); 353f4b7f927SHaavard Skinnemoen #endif 3542220eedfSKonstantin Dorfman mmc_init_context_info(card->host); 355f4b7f927SHaavard Skinnemoen 35625185f3fSSascha Hauer card->dev.of_node = mmc_of_find_child_device(card->host, 0); 35725185f3fSSascha Hauer 358ec076cd2SFu, Zhonghui device_enable_async_suspend(&card->dev); 359ec076cd2SFu, Zhonghui 3601a2727e9SViresh Kumar ret = device_add(&card->dev); 3611a2727e9SViresh Kumar if (ret) 3621a2727e9SViresh Kumar return ret; 3631a2727e9SViresh Kumar 3644101c16aSPierre Ossman mmc_card_set_present(card); 3654101c16aSPierre Ossman 3664101c16aSPierre Ossman return 0; 3674101c16aSPierre Ossman } 3684101c16aSPierre Ossman 3694101c16aSPierre Ossman /* 3704101c16aSPierre Ossman * Unregister a new MMC card with the driver model, and 3714101c16aSPierre Ossman * (eventually) free it. 3724101c16aSPierre Ossman */ 3734101c16aSPierre Ossman void mmc_remove_card(struct mmc_card *card) 3744101c16aSPierre Ossman { 375f690f440SAdrian Hunter struct mmc_host *host = card->host; 376f690f440SAdrian Hunter 377f4b7f927SHaavard Skinnemoen #ifdef CONFIG_DEBUG_FS 378f4b7f927SHaavard Skinnemoen mmc_remove_card_debugfs(card); 379f4b7f927SHaavard Skinnemoen #endif 380f4b7f927SHaavard Skinnemoen 381f690f440SAdrian Hunter if (host->cqe_enabled) { 382f690f440SAdrian Hunter host->cqe_ops->cqe_disable(host); 383f690f440SAdrian Hunter host->cqe_enabled = false; 384f690f440SAdrian Hunter } 385f690f440SAdrian Hunter 3864101c16aSPierre Ossman if (mmc_card_present(card)) { 387af517150SDavid Brownell if (mmc_host_is_spi(card->host)) { 388a3c76eb9SGirish K S pr_info("%s: SPI card removed\n", 389af517150SDavid Brownell mmc_hostname(card->host)); 390af517150SDavid Brownell } else { 391a3c76eb9SGirish K S pr_info("%s: card %04x removed\n", 392109b5bedSPierre Ossman mmc_hostname(card->host), card->rca); 393af517150SDavid Brownell } 3944101c16aSPierre Ossman device_del(&card->dev); 39525185f3fSSascha Hauer of_node_put(card->dev.of_node); 3964101c16aSPierre Ossman } 3974101c16aSPierre Ossman 3984101c16aSPierre Ossman put_device(&card->dev); 3994101c16aSPierre Ossman } 4004101c16aSPierre Ossman 401