1d2912cb1SThomas Gleixner // SPDX-License-Identifier: GPL-2.0-only 24101c16aSPierre Ossman /* 34101c16aSPierre Ossman * linux/drivers/mmc/core/bus.c 44101c16aSPierre Ossman * 54101c16aSPierre Ossman * Copyright (C) 2003 Russell King, All Rights Reserved. 64101c16aSPierre Ossman * Copyright (C) 2007 Pierre Ossman 74101c16aSPierre Ossman * 84101c16aSPierre Ossman * MMC card bus driver model 94101c16aSPierre Ossman */ 104101c16aSPierre Ossman 113ef77af1SPaul Gortmaker #include <linux/export.h> 124101c16aSPierre Ossman #include <linux/device.h> 134101c16aSPierre Ossman #include <linux/err.h> 145a0e3ad6STejun Heo #include <linux/slab.h> 150205a904SPaul Gortmaker #include <linux/stat.h> 1625185f3fSSascha Hauer #include <linux/of.h> 17516d5ccdSOhad Ben-Cohen #include <linux/pm_runtime.h> 184101c16aSPierre Ossman 194101c16aSPierre Ossman #include <linux/mmc/card.h> 204101c16aSPierre Ossman #include <linux/mmc/host.h> 214101c16aSPierre Ossman 224101c16aSPierre Ossman #include "core.h" 234facdde1SUlf Hansson #include "card.h" 245857b29bSUlf Hansson #include "host.h" 251a632f8cSPierre Ossman #include "sdio_cis.h" 264101c16aSPierre Ossman #include "bus.h" 274101c16aSPierre Ossman 2896541bacSUlf Hansson #define to_mmc_driver(d) container_of(d, struct mmc_driver, drv) 2996541bacSUlf Hansson 30f24fc57bSGreg Kroah-Hartman static ssize_t type_show(struct device *dev, 314101c16aSPierre Ossman struct device_attribute *attr, char *buf) 324101c16aSPierre Ossman { 33265cdc90SAndy Shevchenko struct mmc_card *card = mmc_dev_to_card(dev); 344101c16aSPierre Ossman 354101c16aSPierre Ossman switch (card->type) { 364101c16aSPierre Ossman case MMC_TYPE_MMC: 374101c16aSPierre Ossman return sprintf(buf, "MMC\n"); 384101c16aSPierre Ossman case MMC_TYPE_SD: 394101c16aSPierre Ossman return sprintf(buf, "SD\n"); 405c4e6f13SPierre Ossman case MMC_TYPE_SDIO: 415c4e6f13SPierre Ossman return sprintf(buf, "SDIO\n"); 427310ece8SMichal Miroslaw case MMC_TYPE_SD_COMBO: 437310ece8SMichal Miroslaw return sprintf(buf, "SDcombo\n"); 444101c16aSPierre Ossman default: 454101c16aSPierre Ossman return -EFAULT; 464101c16aSPierre Ossman } 474101c16aSPierre Ossman } 48f24fc57bSGreg Kroah-Hartman static DEVICE_ATTR_RO(type); 494101c16aSPierre Ossman 50f24fc57bSGreg Kroah-Hartman static struct attribute *mmc_dev_attrs[] = { 51f24fc57bSGreg Kroah-Hartman &dev_attr_type.attr, 52f24fc57bSGreg Kroah-Hartman NULL, 534101c16aSPierre Ossman }; 54f24fc57bSGreg Kroah-Hartman ATTRIBUTE_GROUPS(mmc_dev); 554101c16aSPierre Ossman 564101c16aSPierre Ossman /* 574101c16aSPierre Ossman * This currently matches any MMC driver to any MMC card - drivers 584101c16aSPierre Ossman * themselves make the decision whether to drive this card in their 594101c16aSPierre Ossman * probe method. 604101c16aSPierre Ossman */ 614101c16aSPierre Ossman static int mmc_bus_match(struct device *dev, struct device_driver *drv) 624101c16aSPierre Ossman { 634101c16aSPierre Ossman return 1; 644101c16aSPierre Ossman } 654101c16aSPierre Ossman 664101c16aSPierre Ossman static int 677eff2e7aSKay Sievers mmc_bus_uevent(struct device *dev, struct kobj_uevent_env *env) 684101c16aSPierre Ossman { 69265cdc90SAndy Shevchenko struct mmc_card *card = mmc_dev_to_card(dev); 709eb3a94dSPierre Ossman const char *type; 71b698f6abSPali Rohár unsigned int i; 727eff2e7aSKay Sievers int retval = 0; 734101c16aSPierre Ossman 744101c16aSPierre Ossman switch (card->type) { 754101c16aSPierre Ossman case MMC_TYPE_MMC: 769eb3a94dSPierre Ossman type = "MMC"; 774101c16aSPierre Ossman break; 784101c16aSPierre Ossman case MMC_TYPE_SD: 799eb3a94dSPierre Ossman type = "SD"; 804101c16aSPierre Ossman break; 815c4e6f13SPierre Ossman case MMC_TYPE_SDIO: 829eb3a94dSPierre Ossman type = "SDIO"; 835c4e6f13SPierre Ossman break; 847310ece8SMichal Miroslaw case MMC_TYPE_SD_COMBO: 857310ece8SMichal Miroslaw type = "SDcombo"; 867310ece8SMichal Miroslaw break; 879eb3a94dSPierre Ossman default: 889eb3a94dSPierre Ossman type = NULL; 894101c16aSPierre Ossman } 904101c16aSPierre Ossman 919eb3a94dSPierre Ossman if (type) { 927eff2e7aSKay Sievers retval = add_uevent_var(env, "MMC_TYPE=%s", type); 937eff2e7aSKay Sievers if (retval) 947eff2e7aSKay Sievers return retval; 959eb3a94dSPierre Ossman } 964101c16aSPierre Ossman 97254e1754SPali Rohár if (card->type == MMC_TYPE_SDIO || card->type == MMC_TYPE_SD_COMBO) { 98254e1754SPali Rohár retval = add_uevent_var(env, "SDIO_ID=%04X:%04X", 99254e1754SPali Rohár card->cis.vendor, card->cis.device); 100254e1754SPali Rohár if (retval) 101254e1754SPali Rohár return retval; 102b698f6abSPali Rohár 103b698f6abSPali Rohár retval = add_uevent_var(env, "SDIO_REVISION=%u.%u", 104b698f6abSPali Rohár card->major_rev, card->minor_rev); 105b698f6abSPali Rohár if (retval) 106b698f6abSPali Rohár return retval; 107b698f6abSPali Rohár 108b698f6abSPali Rohár for (i = 0; i < card->num_info; i++) { 109b698f6abSPali Rohár retval = add_uevent_var(env, "SDIO_INFO%u=%s", i+1, card->info[i]); 110b698f6abSPali Rohár if (retval) 111b698f6abSPali Rohár return retval; 112b698f6abSPali Rohár } 113254e1754SPali Rohár } 114254e1754SPali Rohár 115c03ac5e6SPali Rohár /* 116c03ac5e6SPali Rohár * SDIO (non-combo) cards are not handled by mmc_block driver and do not 117c03ac5e6SPali Rohár * have accessible CID register which used by mmc_card_name() function. 118c03ac5e6SPali Rohár */ 119c03ac5e6SPali Rohár if (card->type == MMC_TYPE_SDIO) 120c03ac5e6SPali Rohár return 0; 121c03ac5e6SPali Rohár 1227eff2e7aSKay Sievers retval = add_uevent_var(env, "MMC_NAME=%s", mmc_card_name(card)); 1236b0b6285SAndy Whitcroft if (retval) 1246b0b6285SAndy Whitcroft return retval; 1256b0b6285SAndy Whitcroft 1266b0b6285SAndy Whitcroft /* 1276b0b6285SAndy Whitcroft * Request the mmc_block device. Note: that this is a direct request 1286b0b6285SAndy Whitcroft * for the module it carries no information as to what is inserted. 1296b0b6285SAndy Whitcroft */ 1306b0b6285SAndy Whitcroft retval = add_uevent_var(env, "MODALIAS=mmc:block"); 1314101c16aSPierre Ossman 1327eff2e7aSKay Sievers return retval; 1334101c16aSPierre Ossman } 1344101c16aSPierre Ossman 13596541bacSUlf Hansson static int mmc_bus_probe(struct device *dev) 13696541bacSUlf Hansson { 13796541bacSUlf Hansson struct mmc_driver *drv = to_mmc_driver(dev->driver); 13896541bacSUlf Hansson struct mmc_card *card = mmc_dev_to_card(dev); 13996541bacSUlf Hansson 14096541bacSUlf Hansson return drv->probe(card); 14196541bacSUlf Hansson } 14296541bacSUlf Hansson 143*fc7a6209SUwe Kleine-König static void mmc_bus_remove(struct device *dev) 14496541bacSUlf Hansson { 14596541bacSUlf Hansson struct mmc_driver *drv = to_mmc_driver(dev->driver); 14696541bacSUlf Hansson struct mmc_card *card = mmc_dev_to_card(dev); 14796541bacSUlf Hansson 14896541bacSUlf Hansson drv->remove(card); 14996541bacSUlf Hansson } 15096541bacSUlf Hansson 15176287748SUlf Hansson static void mmc_bus_shutdown(struct device *dev) 15276287748SUlf Hansson { 15396541bacSUlf Hansson struct mmc_driver *drv = to_mmc_driver(dev->driver); 15476287748SUlf Hansson struct mmc_card *card = mmc_dev_to_card(dev); 1556b086bdeSUlf Hansson struct mmc_host *host = card->host; 1566b086bdeSUlf Hansson int ret; 15776287748SUlf Hansson 15896541bacSUlf Hansson if (dev->driver && drv->shutdown) 15996541bacSUlf Hansson drv->shutdown(card); 1606b086bdeSUlf Hansson 1616b086bdeSUlf Hansson if (host->bus_ops->shutdown) { 1626b086bdeSUlf Hansson ret = host->bus_ops->shutdown(host); 1636b086bdeSUlf Hansson if (ret) 1646b086bdeSUlf Hansson pr_warn("%s: error %d during shutdown\n", 1656b086bdeSUlf Hansson mmc_hostname(host), ret); 1666b086bdeSUlf Hansson } 16776287748SUlf Hansson } 16876287748SUlf Hansson 1690dd1bfebSChuanxiao Dong #ifdef CONFIG_PM_SLEEP 17032d317c6SChuanxiao Dong static int mmc_bus_suspend(struct device *dev) 1714101c16aSPierre Ossman { 172265cdc90SAndy Shevchenko struct mmc_card *card = mmc_dev_to_card(dev); 173986892caSUlf Hansson struct mmc_host *host = card->host; 174986892caSUlf Hansson int ret; 1754101c16aSPierre Ossman 1760967edc6SUlf Hansson ret = pm_generic_suspend(dev); 177986892caSUlf Hansson if (ret) 178986892caSUlf Hansson return ret; 179986892caSUlf Hansson 180986892caSUlf Hansson ret = host->bus_ops->suspend(host); 181ebe7dd45SAdrian Hunter if (ret) 182ebe7dd45SAdrian Hunter pm_generic_resume(dev); 183ebe7dd45SAdrian Hunter 1844101c16aSPierre Ossman return ret; 1854101c16aSPierre Ossman } 1864101c16aSPierre Ossman 1874101c16aSPierre Ossman static int mmc_bus_resume(struct device *dev) 1884101c16aSPierre Ossman { 189265cdc90SAndy Shevchenko struct mmc_card *card = mmc_dev_to_card(dev); 190986892caSUlf Hansson struct mmc_host *host = card->host; 191986892caSUlf Hansson int ret; 192986892caSUlf Hansson 193986892caSUlf Hansson ret = host->bus_ops->resume(host); 194986892caSUlf Hansson if (ret) 195986892caSUlf Hansson pr_warn("%s: error %d during resume (card was removed?)\n", 196986892caSUlf Hansson mmc_hostname(host), ret); 1974101c16aSPierre Ossman 1980967edc6SUlf Hansson ret = pm_generic_resume(dev); 1994101c16aSPierre Ossman return ret; 2004101c16aSPierre Ossman } 2010dd1bfebSChuanxiao Dong #endif 2024101c16aSPierre Ossman 203162d6f98SRafael J. Wysocki #ifdef CONFIG_PM 204516d5ccdSOhad Ben-Cohen static int mmc_runtime_suspend(struct device *dev) 205516d5ccdSOhad Ben-Cohen { 206516d5ccdSOhad Ben-Cohen struct mmc_card *card = mmc_dev_to_card(dev); 20712d01d0bSUlf Hansson struct mmc_host *host = card->host; 208516d5ccdSOhad Ben-Cohen 2095601aaf7SUlf Hansson return host->bus_ops->runtime_suspend(host); 210516d5ccdSOhad Ben-Cohen } 211516d5ccdSOhad Ben-Cohen 212516d5ccdSOhad Ben-Cohen static int mmc_runtime_resume(struct device *dev) 213516d5ccdSOhad Ben-Cohen { 214516d5ccdSOhad Ben-Cohen struct mmc_card *card = mmc_dev_to_card(dev); 21512d01d0bSUlf Hansson struct mmc_host *host = card->host; 216516d5ccdSOhad Ben-Cohen 2175601aaf7SUlf Hansson return host->bus_ops->runtime_resume(host); 218516d5ccdSOhad Ben-Cohen } 219162d6f98SRafael J. Wysocki #endif /* !CONFIG_PM */ 220516d5ccdSOhad Ben-Cohen 22132d317c6SChuanxiao Dong static const struct dev_pm_ops mmc_bus_pm_ops = { 2222e42da59SUlf Hansson SET_RUNTIME_PM_OPS(mmc_runtime_suspend, mmc_runtime_resume, NULL) 22332d317c6SChuanxiao Dong SET_SYSTEM_SLEEP_PM_OPS(mmc_bus_suspend, mmc_bus_resume) 22432d317c6SChuanxiao Dong }; 22532d317c6SChuanxiao Dong 2264101c16aSPierre Ossman static struct bus_type mmc_bus_type = { 2274101c16aSPierre Ossman .name = "mmc", 228f24fc57bSGreg Kroah-Hartman .dev_groups = mmc_dev_groups, 2294101c16aSPierre Ossman .match = mmc_bus_match, 2304101c16aSPierre Ossman .uevent = mmc_bus_uevent, 23196541bacSUlf Hansson .probe = mmc_bus_probe, 23296541bacSUlf Hansson .remove = mmc_bus_remove, 23376287748SUlf Hansson .shutdown = mmc_bus_shutdown, 23432d317c6SChuanxiao Dong .pm = &mmc_bus_pm_ops, 2354101c16aSPierre Ossman }; 2364101c16aSPierre Ossman 2374101c16aSPierre Ossman int mmc_register_bus(void) 2384101c16aSPierre Ossman { 2394101c16aSPierre Ossman return bus_register(&mmc_bus_type); 2404101c16aSPierre Ossman } 2414101c16aSPierre Ossman 2424101c16aSPierre Ossman void mmc_unregister_bus(void) 2434101c16aSPierre Ossman { 2444101c16aSPierre Ossman bus_unregister(&mmc_bus_type); 2454101c16aSPierre Ossman } 2464101c16aSPierre Ossman 2474101c16aSPierre Ossman /** 2484101c16aSPierre Ossman * mmc_register_driver - register a media driver 2494101c16aSPierre Ossman * @drv: MMC media driver 2504101c16aSPierre Ossman */ 25196541bacSUlf Hansson int mmc_register_driver(struct mmc_driver *drv) 2524101c16aSPierre Ossman { 25396541bacSUlf Hansson drv->drv.bus = &mmc_bus_type; 25496541bacSUlf Hansson return driver_register(&drv->drv); 2554101c16aSPierre Ossman } 25696541bacSUlf Hansson 2574101c16aSPierre Ossman EXPORT_SYMBOL(mmc_register_driver); 2584101c16aSPierre Ossman 2594101c16aSPierre Ossman /** 2604101c16aSPierre Ossman * mmc_unregister_driver - unregister a media driver 2614101c16aSPierre Ossman * @drv: MMC media driver 2624101c16aSPierre Ossman */ 26396541bacSUlf Hansson void mmc_unregister_driver(struct mmc_driver *drv) 2644101c16aSPierre Ossman { 26596541bacSUlf Hansson drv->drv.bus = &mmc_bus_type; 26696541bacSUlf Hansson driver_unregister(&drv->drv); 2674101c16aSPierre Ossman } 26896541bacSUlf Hansson 2694101c16aSPierre Ossman EXPORT_SYMBOL(mmc_unregister_driver); 2704101c16aSPierre Ossman 2714101c16aSPierre Ossman static void mmc_release_card(struct device *dev) 2724101c16aSPierre Ossman { 273265cdc90SAndy Shevchenko struct mmc_card *card = mmc_dev_to_card(dev); 2744101c16aSPierre Ossman 2751a632f8cSPierre Ossman sdio_free_common_cis(card); 2761a632f8cSPierre Ossman 277759bdc7aSPierre Ossman kfree(card->info); 278759bdc7aSPierre Ossman 2794101c16aSPierre Ossman kfree(card); 2804101c16aSPierre Ossman } 2814101c16aSPierre Ossman 2824101c16aSPierre Ossman /* 2834101c16aSPierre Ossman * Allocate and initialise a new MMC card structure. 2844101c16aSPierre Ossman */ 28551ec92e2SPierre Ossman struct mmc_card *mmc_alloc_card(struct mmc_host *host, struct device_type *type) 2864101c16aSPierre Ossman { 2874101c16aSPierre Ossman struct mmc_card *card; 2884101c16aSPierre Ossman 289733cb1e4SMariusz Kozlowski card = kzalloc(sizeof(struct mmc_card), GFP_KERNEL); 2904101c16aSPierre Ossman if (!card) 2914101c16aSPierre Ossman return ERR_PTR(-ENOMEM); 2924101c16aSPierre Ossman 2934101c16aSPierre Ossman card->host = host; 2944101c16aSPierre Ossman 2954101c16aSPierre Ossman device_initialize(&card->dev); 2964101c16aSPierre Ossman 2974101c16aSPierre Ossman card->dev.parent = mmc_classdev(host); 2984101c16aSPierre Ossman card->dev.bus = &mmc_bus_type; 2994101c16aSPierre Ossman card->dev.release = mmc_release_card; 30051ec92e2SPierre Ossman card->dev.type = type; 3014101c16aSPierre Ossman 3024101c16aSPierre Ossman return card; 3034101c16aSPierre Ossman } 3044101c16aSPierre Ossman 3054101c16aSPierre Ossman /* 3064101c16aSPierre Ossman * Register a new MMC card with the driver model. 3074101c16aSPierre Ossman */ 3084101c16aSPierre Ossman int mmc_add_card(struct mmc_card *card) 3094101c16aSPierre Ossman { 3104101c16aSPierre Ossman int ret; 311109b5bedSPierre Ossman const char *type; 3126500c8edSSubhash Jadavani const char *uhs_bus_speed_mode = ""; 3136500c8edSSubhash Jadavani static const char *const uhs_speeds[] = { 3146500c8edSSubhash Jadavani [UHS_SDR12_BUS_SPEED] = "SDR12 ", 3156500c8edSSubhash Jadavani [UHS_SDR25_BUS_SPEED] = "SDR25 ", 3166500c8edSSubhash Jadavani [UHS_SDR50_BUS_SPEED] = "SDR50 ", 3176500c8edSSubhash Jadavani [UHS_SDR104_BUS_SPEED] = "SDR104 ", 3186500c8edSSubhash Jadavani [UHS_DDR50_BUS_SPEED] = "DDR50 ", 3196500c8edSSubhash Jadavani }; 3206500c8edSSubhash Jadavani 3214101c16aSPierre Ossman 322d1b26863SKay Sievers dev_set_name(&card->dev, "%s:%04x", mmc_hostname(card->host), card->rca); 3234101c16aSPierre Ossman 324109b5bedSPierre Ossman switch (card->type) { 325109b5bedSPierre Ossman case MMC_TYPE_MMC: 326109b5bedSPierre Ossman type = "MMC"; 327109b5bedSPierre Ossman break; 328109b5bedSPierre Ossman case MMC_TYPE_SD: 329109b5bedSPierre Ossman type = "SD"; 3303a303511SArindam Nath if (mmc_card_blockaddr(card)) { 3313a303511SArindam Nath if (mmc_card_ext_capacity(card)) 3323a303511SArindam Nath type = "SDXC"; 3333a303511SArindam Nath else 334109b5bedSPierre Ossman type = "SDHC"; 3353a303511SArindam Nath } 336109b5bedSPierre Ossman break; 3375c4e6f13SPierre Ossman case MMC_TYPE_SDIO: 3385c4e6f13SPierre Ossman type = "SDIO"; 3395c4e6f13SPierre Ossman break; 3407310ece8SMichal Miroslaw case MMC_TYPE_SD_COMBO: 3417310ece8SMichal Miroslaw type = "SD-combo"; 3427310ece8SMichal Miroslaw if (mmc_card_blockaddr(card)) 3437310ece8SMichal Miroslaw type = "SDHC-combo"; 3449bc21848SMichał Mirosław break; 345109b5bedSPierre Ossman default: 346109b5bedSPierre Ossman type = "?"; 347109b5bedSPierre Ossman break; 348109b5bedSPierre Ossman } 349109b5bedSPierre Ossman 35071ef1ea4SJackey Shen if (mmc_card_uhs(card) && 3516500c8edSSubhash Jadavani (card->sd_bus_speed < ARRAY_SIZE(uhs_speeds))) 3526500c8edSSubhash Jadavani uhs_bus_speed_mode = uhs_speeds[card->sd_bus_speed]; 3536500c8edSSubhash Jadavani 354af517150SDavid Brownell if (mmc_host_is_spi(card->host)) { 355a3c76eb9SGirish K S pr_info("%s: new %s%s%s card on SPI\n", 356af517150SDavid Brownell mmc_hostname(card->host), 357cdc99179SSeungwon Jeon mmc_card_hs(card) ? "high speed " : "", 358cdc99179SSeungwon Jeon mmc_card_ddr52(card) ? "DDR " : "", 359af517150SDavid Brownell type); 360af517150SDavid Brownell } else { 36181ac2af6SShawn Lin pr_info("%s: new %s%s%s%s%s%s card at address %04x\n", 362109b5bedSPierre Ossman mmc_hostname(card->host), 363a303c531SPhilip Rakity mmc_card_uhs(card) ? "ultra high speed " : 364cdc99179SSeungwon Jeon (mmc_card_hs(card) ? "high speed " : ""), 3650a5b6438SSeungwon Jeon mmc_card_hs400(card) ? "HS400 " : 366a4924c71SGirish K S (mmc_card_hs200(card) ? "HS200 " : ""), 36781ac2af6SShawn Lin mmc_card_hs400es(card) ? "Enhanced strobe " : "", 368cdc99179SSeungwon Jeon mmc_card_ddr52(card) ? "DDR " : "", 3696500c8edSSubhash Jadavani uhs_bus_speed_mode, type, card->rca); 370af517150SDavid Brownell } 371109b5bedSPierre Ossman 372f4b7f927SHaavard Skinnemoen #ifdef CONFIG_DEBUG_FS 373f4b7f927SHaavard Skinnemoen mmc_add_card_debugfs(card); 374f4b7f927SHaavard Skinnemoen #endif 37525185f3fSSascha Hauer card->dev.of_node = mmc_of_find_child_device(card->host, 0); 37625185f3fSSascha Hauer 377ec076cd2SFu, Zhonghui device_enable_async_suspend(&card->dev); 378ec076cd2SFu, Zhonghui 3791a2727e9SViresh Kumar ret = device_add(&card->dev); 3801a2727e9SViresh Kumar if (ret) 3811a2727e9SViresh Kumar return ret; 3821a2727e9SViresh Kumar 3834101c16aSPierre Ossman mmc_card_set_present(card); 3844101c16aSPierre Ossman 3854101c16aSPierre Ossman return 0; 3864101c16aSPierre Ossman } 3874101c16aSPierre Ossman 3884101c16aSPierre Ossman /* 3894101c16aSPierre Ossman * Unregister a new MMC card with the driver model, and 3904101c16aSPierre Ossman * (eventually) free it. 3914101c16aSPierre Ossman */ 3924101c16aSPierre Ossman void mmc_remove_card(struct mmc_card *card) 3934101c16aSPierre Ossman { 394f690f440SAdrian Hunter struct mmc_host *host = card->host; 395f690f440SAdrian Hunter 396f4b7f927SHaavard Skinnemoen #ifdef CONFIG_DEBUG_FS 397f4b7f927SHaavard Skinnemoen mmc_remove_card_debugfs(card); 398f4b7f927SHaavard Skinnemoen #endif 399f4b7f927SHaavard Skinnemoen 4004101c16aSPierre Ossman if (mmc_card_present(card)) { 401af517150SDavid Brownell if (mmc_host_is_spi(card->host)) { 402a3c76eb9SGirish K S pr_info("%s: SPI card removed\n", 403af517150SDavid Brownell mmc_hostname(card->host)); 404af517150SDavid Brownell } else { 405a3c76eb9SGirish K S pr_info("%s: card %04x removed\n", 406109b5bedSPierre Ossman mmc_hostname(card->host), card->rca); 407af517150SDavid Brownell } 4084101c16aSPierre Ossman device_del(&card->dev); 40925185f3fSSascha Hauer of_node_put(card->dev.of_node); 4104101c16aSPierre Ossman } 4114101c16aSPierre Ossman 412f06391c4SFrank Li if (host->cqe_enabled) { 413f06391c4SFrank Li host->cqe_ops->cqe_disable(host); 414f06391c4SFrank Li host->cqe_enabled = false; 4154101c16aSPierre Ossman } 4164101c16aSPierre Ossman 417f06391c4SFrank Li put_device(&card->dev); 418f06391c4SFrank Li } 419