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> 19516d5ccdSOhad Ben-Cohen #include <linux/pm_runtime.h> 204101c16aSPierre Ossman 214101c16aSPierre Ossman #include <linux/mmc/card.h> 224101c16aSPierre Ossman #include <linux/mmc/host.h> 234101c16aSPierre Ossman 244101c16aSPierre Ossman #include "core.h" 251a632f8cSPierre Ossman #include "sdio_cis.h" 264101c16aSPierre Ossman #include "bus.h" 274101c16aSPierre Ossman 284101c16aSPierre Ossman #define to_mmc_driver(d) container_of(d, struct mmc_driver, drv) 294101c16aSPierre Ossman 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; 717eff2e7aSKay Sievers int retval = 0; 724101c16aSPierre Ossman 734101c16aSPierre Ossman switch (card->type) { 744101c16aSPierre Ossman case MMC_TYPE_MMC: 759eb3a94dSPierre Ossman type = "MMC"; 764101c16aSPierre Ossman break; 774101c16aSPierre Ossman case MMC_TYPE_SD: 789eb3a94dSPierre Ossman type = "SD"; 794101c16aSPierre Ossman break; 805c4e6f13SPierre Ossman case MMC_TYPE_SDIO: 819eb3a94dSPierre Ossman type = "SDIO"; 825c4e6f13SPierre Ossman break; 837310ece8SMichal Miroslaw case MMC_TYPE_SD_COMBO: 847310ece8SMichal Miroslaw type = "SDcombo"; 857310ece8SMichal Miroslaw break; 869eb3a94dSPierre Ossman default: 879eb3a94dSPierre Ossman type = NULL; 884101c16aSPierre Ossman } 894101c16aSPierre Ossman 909eb3a94dSPierre Ossman if (type) { 917eff2e7aSKay Sievers retval = add_uevent_var(env, "MMC_TYPE=%s", type); 927eff2e7aSKay Sievers if (retval) 937eff2e7aSKay Sievers return retval; 949eb3a94dSPierre Ossman } 954101c16aSPierre Ossman 967eff2e7aSKay Sievers retval = add_uevent_var(env, "MMC_NAME=%s", mmc_card_name(card)); 976b0b6285SAndy Whitcroft if (retval) 986b0b6285SAndy Whitcroft return retval; 996b0b6285SAndy Whitcroft 1006b0b6285SAndy Whitcroft /* 1016b0b6285SAndy Whitcroft * Request the mmc_block device. Note: that this is a direct request 1026b0b6285SAndy Whitcroft * for the module it carries no information as to what is inserted. 1036b0b6285SAndy Whitcroft */ 1046b0b6285SAndy Whitcroft retval = add_uevent_var(env, "MODALIAS=mmc:block"); 1054101c16aSPierre Ossman 1067eff2e7aSKay Sievers return retval; 1074101c16aSPierre Ossman } 1084101c16aSPierre Ossman 1094101c16aSPierre Ossman static int mmc_bus_probe(struct device *dev) 1104101c16aSPierre Ossman { 1114101c16aSPierre Ossman struct mmc_driver *drv = to_mmc_driver(dev->driver); 112265cdc90SAndy Shevchenko struct mmc_card *card = mmc_dev_to_card(dev); 1134101c16aSPierre Ossman 1144101c16aSPierre Ossman return drv->probe(card); 1154101c16aSPierre Ossman } 1164101c16aSPierre Ossman 1174101c16aSPierre Ossman static int mmc_bus_remove(struct device *dev) 1184101c16aSPierre Ossman { 1194101c16aSPierre Ossman struct mmc_driver *drv = to_mmc_driver(dev->driver); 120265cdc90SAndy Shevchenko struct mmc_card *card = mmc_dev_to_card(dev); 1214101c16aSPierre Ossman 1224101c16aSPierre Ossman drv->remove(card); 1234101c16aSPierre Ossman 1244101c16aSPierre Ossman return 0; 1254101c16aSPierre Ossman } 1264101c16aSPierre Ossman 12776287748SUlf Hansson static void mmc_bus_shutdown(struct device *dev) 12876287748SUlf Hansson { 12976287748SUlf Hansson struct mmc_driver *drv = to_mmc_driver(dev->driver); 13076287748SUlf Hansson struct mmc_card *card = mmc_dev_to_card(dev); 1316b086bdeSUlf Hansson struct mmc_host *host = card->host; 1326b086bdeSUlf Hansson int ret; 13376287748SUlf Hansson 134203bb5afSUlf Hansson if (dev->driver && drv->shutdown) 13576287748SUlf Hansson drv->shutdown(card); 1366b086bdeSUlf Hansson 1376b086bdeSUlf Hansson if (host->bus_ops->shutdown) { 1386b086bdeSUlf Hansson ret = host->bus_ops->shutdown(host); 1396b086bdeSUlf Hansson if (ret) 1406b086bdeSUlf Hansson pr_warn("%s: error %d during shutdown\n", 1416b086bdeSUlf Hansson mmc_hostname(host), ret); 1426b086bdeSUlf Hansson } 14376287748SUlf Hansson } 14476287748SUlf Hansson 1450dd1bfebSChuanxiao Dong #ifdef CONFIG_PM_SLEEP 14632d317c6SChuanxiao Dong static int mmc_bus_suspend(struct device *dev) 1474101c16aSPierre Ossman { 1484101c16aSPierre Ossman struct mmc_driver *drv = to_mmc_driver(dev->driver); 149265cdc90SAndy Shevchenko struct mmc_card *card = mmc_dev_to_card(dev); 150986892caSUlf Hansson struct mmc_host *host = card->host; 151986892caSUlf Hansson int ret; 1524101c16aSPierre Ossman 153986892caSUlf Hansson if (dev->driver && drv->suspend) { 15432d317c6SChuanxiao Dong ret = drv->suspend(card); 155986892caSUlf Hansson if (ret) 156986892caSUlf Hansson return ret; 157986892caSUlf Hansson } 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 { 1654101c16aSPierre Ossman struct mmc_driver *drv = to_mmc_driver(dev->driver); 166265cdc90SAndy Shevchenko struct mmc_card *card = mmc_dev_to_card(dev); 167986892caSUlf Hansson struct mmc_host *host = card->host; 168986892caSUlf Hansson int ret; 169986892caSUlf Hansson 170986892caSUlf Hansson ret = host->bus_ops->resume(host); 171986892caSUlf Hansson if (ret) 172986892caSUlf Hansson pr_warn("%s: error %d during resume (card was removed?)\n", 173986892caSUlf Hansson mmc_hostname(host), ret); 1744101c16aSPierre Ossman 1754101c16aSPierre Ossman if (dev->driver && drv->resume) 1764101c16aSPierre Ossman ret = drv->resume(card); 177986892caSUlf Hansson 1784101c16aSPierre Ossman return ret; 1794101c16aSPierre Ossman } 1800dd1bfebSChuanxiao Dong #endif 1814101c16aSPierre Ossman 182516d5ccdSOhad Ben-Cohen #ifdef CONFIG_PM_RUNTIME 183516d5ccdSOhad Ben-Cohen 184516d5ccdSOhad Ben-Cohen static int mmc_runtime_suspend(struct device *dev) 185516d5ccdSOhad Ben-Cohen { 186516d5ccdSOhad Ben-Cohen struct mmc_card *card = mmc_dev_to_card(dev); 18712d01d0bSUlf Hansson struct mmc_host *host = card->host; 188516d5ccdSOhad Ben-Cohen 1895601aaf7SUlf Hansson return host->bus_ops->runtime_suspend(host); 190516d5ccdSOhad Ben-Cohen } 191516d5ccdSOhad Ben-Cohen 192516d5ccdSOhad Ben-Cohen static int mmc_runtime_resume(struct device *dev) 193516d5ccdSOhad Ben-Cohen { 194516d5ccdSOhad Ben-Cohen struct mmc_card *card = mmc_dev_to_card(dev); 19512d01d0bSUlf Hansson struct mmc_host *host = card->host; 196516d5ccdSOhad Ben-Cohen 1975601aaf7SUlf Hansson return host->bus_ops->runtime_resume(host); 198516d5ccdSOhad Ben-Cohen } 199516d5ccdSOhad Ben-Cohen 200516d5ccdSOhad Ben-Cohen static int mmc_runtime_idle(struct device *dev) 201516d5ccdSOhad Ben-Cohen { 20245f0a85cSRafael J. Wysocki return 0; 203516d5ccdSOhad Ben-Cohen } 204516d5ccdSOhad Ben-Cohen 205516d5ccdSOhad Ben-Cohen #endif /* !CONFIG_PM_RUNTIME */ 206516d5ccdSOhad Ben-Cohen 20732d317c6SChuanxiao Dong static const struct dev_pm_ops mmc_bus_pm_ops = { 20832d317c6SChuanxiao Dong SET_RUNTIME_PM_OPS(mmc_runtime_suspend, mmc_runtime_resume, 20932d317c6SChuanxiao Dong mmc_runtime_idle) 21032d317c6SChuanxiao Dong SET_SYSTEM_SLEEP_PM_OPS(mmc_bus_suspend, mmc_bus_resume) 21132d317c6SChuanxiao Dong }; 21232d317c6SChuanxiao Dong 2134101c16aSPierre Ossman static struct bus_type mmc_bus_type = { 2144101c16aSPierre Ossman .name = "mmc", 215f24fc57bSGreg Kroah-Hartman .dev_groups = mmc_dev_groups, 2164101c16aSPierre Ossman .match = mmc_bus_match, 2174101c16aSPierre Ossman .uevent = mmc_bus_uevent, 2184101c16aSPierre Ossman .probe = mmc_bus_probe, 2194101c16aSPierre Ossman .remove = mmc_bus_remove, 22076287748SUlf Hansson .shutdown = mmc_bus_shutdown, 22132d317c6SChuanxiao Dong .pm = &mmc_bus_pm_ops, 2224101c16aSPierre Ossman }; 2234101c16aSPierre Ossman 2244101c16aSPierre Ossman int mmc_register_bus(void) 2254101c16aSPierre Ossman { 2264101c16aSPierre Ossman return bus_register(&mmc_bus_type); 2274101c16aSPierre Ossman } 2284101c16aSPierre Ossman 2294101c16aSPierre Ossman void mmc_unregister_bus(void) 2304101c16aSPierre Ossman { 2314101c16aSPierre Ossman bus_unregister(&mmc_bus_type); 2324101c16aSPierre Ossman } 2334101c16aSPierre Ossman 2344101c16aSPierre Ossman /** 2354101c16aSPierre Ossman * mmc_register_driver - register a media driver 2364101c16aSPierre Ossman * @drv: MMC media driver 2374101c16aSPierre Ossman */ 2384101c16aSPierre Ossman int mmc_register_driver(struct mmc_driver *drv) 2394101c16aSPierre Ossman { 2404101c16aSPierre Ossman drv->drv.bus = &mmc_bus_type; 2414101c16aSPierre Ossman return driver_register(&drv->drv); 2424101c16aSPierre Ossman } 2434101c16aSPierre Ossman 2444101c16aSPierre Ossman EXPORT_SYMBOL(mmc_register_driver); 2454101c16aSPierre Ossman 2464101c16aSPierre Ossman /** 2474101c16aSPierre Ossman * mmc_unregister_driver - unregister a media driver 2484101c16aSPierre Ossman * @drv: MMC media driver 2494101c16aSPierre Ossman */ 2504101c16aSPierre Ossman void mmc_unregister_driver(struct mmc_driver *drv) 2514101c16aSPierre Ossman { 2524101c16aSPierre Ossman drv->drv.bus = &mmc_bus_type; 2534101c16aSPierre Ossman driver_unregister(&drv->drv); 2544101c16aSPierre Ossman } 2554101c16aSPierre Ossman 2564101c16aSPierre Ossman EXPORT_SYMBOL(mmc_unregister_driver); 2574101c16aSPierre Ossman 2584101c16aSPierre Ossman static void mmc_release_card(struct device *dev) 2594101c16aSPierre Ossman { 260265cdc90SAndy Shevchenko struct mmc_card *card = mmc_dev_to_card(dev); 2614101c16aSPierre Ossman 2621a632f8cSPierre Ossman sdio_free_common_cis(card); 2631a632f8cSPierre Ossman 264759bdc7aSPierre Ossman kfree(card->info); 265759bdc7aSPierre Ossman 2664101c16aSPierre Ossman kfree(card); 2674101c16aSPierre Ossman } 2684101c16aSPierre Ossman 2694101c16aSPierre Ossman /* 2704101c16aSPierre Ossman * Allocate and initialise a new MMC card structure. 2714101c16aSPierre Ossman */ 27251ec92e2SPierre Ossman struct mmc_card *mmc_alloc_card(struct mmc_host *host, struct device_type *type) 2734101c16aSPierre Ossman { 2744101c16aSPierre Ossman struct mmc_card *card; 2754101c16aSPierre Ossman 276733cb1e4SMariusz Kozlowski card = kzalloc(sizeof(struct mmc_card), GFP_KERNEL); 2774101c16aSPierre Ossman if (!card) 2784101c16aSPierre Ossman return ERR_PTR(-ENOMEM); 2794101c16aSPierre Ossman 2804101c16aSPierre Ossman card->host = host; 2814101c16aSPierre Ossman 2824101c16aSPierre Ossman device_initialize(&card->dev); 2834101c16aSPierre Ossman 2844101c16aSPierre Ossman card->dev.parent = mmc_classdev(host); 2854101c16aSPierre Ossman card->dev.bus = &mmc_bus_type; 2864101c16aSPierre Ossman card->dev.release = mmc_release_card; 28751ec92e2SPierre Ossman card->dev.type = type; 2884101c16aSPierre Ossman 2894101c16aSPierre Ossman return card; 2904101c16aSPierre Ossman } 2914101c16aSPierre Ossman 2924101c16aSPierre Ossman /* 2934101c16aSPierre Ossman * Register a new MMC card with the driver model. 2944101c16aSPierre Ossman */ 2954101c16aSPierre Ossman int mmc_add_card(struct mmc_card *card) 2964101c16aSPierre Ossman { 2974101c16aSPierre Ossman int ret; 298109b5bedSPierre Ossman const char *type; 2996500c8edSSubhash Jadavani const char *uhs_bus_speed_mode = ""; 3006500c8edSSubhash Jadavani static const char *const uhs_speeds[] = { 3016500c8edSSubhash Jadavani [UHS_SDR12_BUS_SPEED] = "SDR12 ", 3026500c8edSSubhash Jadavani [UHS_SDR25_BUS_SPEED] = "SDR25 ", 3036500c8edSSubhash Jadavani [UHS_SDR50_BUS_SPEED] = "SDR50 ", 3046500c8edSSubhash Jadavani [UHS_SDR104_BUS_SPEED] = "SDR104 ", 3056500c8edSSubhash Jadavani [UHS_DDR50_BUS_SPEED] = "DDR50 ", 3066500c8edSSubhash Jadavani }; 3076500c8edSSubhash Jadavani 3084101c16aSPierre Ossman 309d1b26863SKay Sievers dev_set_name(&card->dev, "%s:%04x", mmc_hostname(card->host), card->rca); 3104101c16aSPierre Ossman 311109b5bedSPierre Ossman switch (card->type) { 312109b5bedSPierre Ossman case MMC_TYPE_MMC: 313109b5bedSPierre Ossman type = "MMC"; 314109b5bedSPierre Ossman break; 315109b5bedSPierre Ossman case MMC_TYPE_SD: 316109b5bedSPierre Ossman type = "SD"; 3173a303511SArindam Nath if (mmc_card_blockaddr(card)) { 3183a303511SArindam Nath if (mmc_card_ext_capacity(card)) 3193a303511SArindam Nath type = "SDXC"; 3203a303511SArindam Nath else 321109b5bedSPierre Ossman type = "SDHC"; 3223a303511SArindam Nath } 323109b5bedSPierre Ossman break; 3245c4e6f13SPierre Ossman case MMC_TYPE_SDIO: 3255c4e6f13SPierre Ossman type = "SDIO"; 3265c4e6f13SPierre Ossman break; 3277310ece8SMichal Miroslaw case MMC_TYPE_SD_COMBO: 3287310ece8SMichal Miroslaw type = "SD-combo"; 3297310ece8SMichal Miroslaw if (mmc_card_blockaddr(card)) 3307310ece8SMichal Miroslaw type = "SDHC-combo"; 3319bc21848SMichał Mirosław break; 332109b5bedSPierre Ossman default: 333109b5bedSPierre Ossman type = "?"; 334109b5bedSPierre Ossman break; 335109b5bedSPierre Ossman } 336109b5bedSPierre Ossman 33771ef1ea4SJackey Shen if (mmc_card_uhs(card) && 3386500c8edSSubhash Jadavani (card->sd_bus_speed < ARRAY_SIZE(uhs_speeds))) 3396500c8edSSubhash Jadavani uhs_bus_speed_mode = uhs_speeds[card->sd_bus_speed]; 3406500c8edSSubhash Jadavani 341af517150SDavid Brownell if (mmc_host_is_spi(card->host)) { 342a3c76eb9SGirish K S pr_info("%s: new %s%s%s card on SPI\n", 343af517150SDavid Brownell mmc_hostname(card->host), 344af517150SDavid Brownell mmc_card_highspeed(card) ? "high speed " : "", 3450f8d8ea6SAdrian Hunter mmc_card_ddr_mode(card) ? "DDR " : "", 346af517150SDavid Brownell type); 347af517150SDavid Brownell } else { 3486500c8edSSubhash Jadavani pr_info("%s: new %s%s%s%s%s card at address %04x\n", 349109b5bedSPierre Ossman mmc_hostname(card->host), 350a303c531SPhilip Rakity mmc_card_uhs(card) ? "ultra high speed " : 3513a303511SArindam Nath (mmc_card_highspeed(card) ? "high speed " : ""), 352a4924c71SGirish K S (mmc_card_hs200(card) ? "HS200 " : ""), 3530f8d8ea6SAdrian Hunter mmc_card_ddr_mode(card) ? "DDR " : "", 3546500c8edSSubhash Jadavani uhs_bus_speed_mode, type, card->rca); 355af517150SDavid Brownell } 356109b5bedSPierre Ossman 357f4b7f927SHaavard Skinnemoen #ifdef CONFIG_DEBUG_FS 358f4b7f927SHaavard Skinnemoen mmc_add_card_debugfs(card); 359f4b7f927SHaavard Skinnemoen #endif 3602220eedfSKonstantin Dorfman mmc_init_context_info(card->host); 361f4b7f927SHaavard Skinnemoen 3621a2727e9SViresh Kumar ret = device_add(&card->dev); 3631a2727e9SViresh Kumar if (ret) 3641a2727e9SViresh Kumar return ret; 3651a2727e9SViresh Kumar 3664101c16aSPierre Ossman mmc_card_set_present(card); 3674101c16aSPierre Ossman 3684101c16aSPierre Ossman return 0; 3694101c16aSPierre Ossman } 3704101c16aSPierre Ossman 3714101c16aSPierre Ossman /* 3724101c16aSPierre Ossman * Unregister a new MMC card with the driver model, and 3734101c16aSPierre Ossman * (eventually) free it. 3744101c16aSPierre Ossman */ 3754101c16aSPierre Ossman void mmc_remove_card(struct mmc_card *card) 3764101c16aSPierre Ossman { 377f4b7f927SHaavard Skinnemoen #ifdef CONFIG_DEBUG_FS 378f4b7f927SHaavard Skinnemoen mmc_remove_card_debugfs(card); 379f4b7f927SHaavard Skinnemoen #endif 380f4b7f927SHaavard Skinnemoen 3814101c16aSPierre Ossman if (mmc_card_present(card)) { 382af517150SDavid Brownell if (mmc_host_is_spi(card->host)) { 383a3c76eb9SGirish K S pr_info("%s: SPI card removed\n", 384af517150SDavid Brownell mmc_hostname(card->host)); 385af517150SDavid Brownell } else { 386a3c76eb9SGirish K S pr_info("%s: card %04x removed\n", 387109b5bedSPierre Ossman mmc_hostname(card->host), card->rca); 388af517150SDavid Brownell } 3894101c16aSPierre Ossman device_del(&card->dev); 3904101c16aSPierre Ossman } 3914101c16aSPierre Ossman 3924101c16aSPierre Ossman put_device(&card->dev); 3934101c16aSPierre Ossman } 3944101c16aSPierre Ossman 395