1e29a7d73f4277eb92aa64e17017dea33460828efPierre Ossman/* 2e29a7d73f4277eb92aa64e17017dea33460828efPierre Ossman * linux/drivers/mmc/core/sdio_bus.c 3e29a7d73f4277eb92aa64e17017dea33460828efPierre Ossman * 4e29a7d73f4277eb92aa64e17017dea33460828efPierre Ossman * Copyright 2007 Pierre Ossman 5e29a7d73f4277eb92aa64e17017dea33460828efPierre Ossman * 6e29a7d73f4277eb92aa64e17017dea33460828efPierre Ossman * This program is free software; you can redistribute it and/or modify 7e29a7d73f4277eb92aa64e17017dea33460828efPierre Ossman * it under the terms of the GNU General Public License as published by 8e29a7d73f4277eb92aa64e17017dea33460828efPierre Ossman * the Free Software Foundation; either version 2 of the License, or (at 9e29a7d73f4277eb92aa64e17017dea33460828efPierre Ossman * your option) any later version. 10e29a7d73f4277eb92aa64e17017dea33460828efPierre Ossman * 11e29a7d73f4277eb92aa64e17017dea33460828efPierre Ossman * SDIO function driver model 12e29a7d73f4277eb92aa64e17017dea33460828efPierre Ossman */ 13e29a7d73f4277eb92aa64e17017dea33460828efPierre Ossman 14e29a7d73f4277eb92aa64e17017dea33460828efPierre Ossman#include <linux/device.h> 15e29a7d73f4277eb92aa64e17017dea33460828efPierre Ossman#include <linux/err.h> 163ef77af154b03776c6c662c68c6332719e9eecacPaul Gortmaker#include <linux/export.h> 175a0e3ad6af8660be21ca98a971cd00f331318c05Tejun Heo#include <linux/slab.h> 1880fd933c44557c5261b80f8f8145b4fe071aeaf3Ohad Ben-Cohen#include <linux/pm_runtime.h> 19e29a7d73f4277eb92aa64e17017dea33460828efPierre Ossman 20e29a7d73f4277eb92aa64e17017dea33460828efPierre Ossman#include <linux/mmc/card.h> 21ed919b0125b26dcc052e44836f66e7e1f5c49c7eOhad Ben-Cohen#include <linux/mmc/host.h> 22e29a7d73f4277eb92aa64e17017dea33460828efPierre Ossman#include <linux/mmc/sdio_func.h> 23e29a7d73f4277eb92aa64e17017dea33460828efPierre Ossman 24b1538bcf75e2e11459947ec4d4329ed04fbe2b2cNicolas Pitre#include "sdio_cis.h" 25e29a7d73f4277eb92aa64e17017dea33460828efPierre Ossman#include "sdio_bus.h" 26e29a7d73f4277eb92aa64e17017dea33460828efPierre Ossman 27e01587a794fa2ee14d3559a7d919af7e386a03e4San Mehat#ifdef CONFIG_MMC_EMBEDDED_SDIO 28e01587a794fa2ee14d3559a7d919af7e386a03e4San Mehat#include <linux/mmc/host.h> 29e01587a794fa2ee14d3559a7d919af7e386a03e4San Mehat#endif 30e01587a794fa2ee14d3559a7d919af7e386a03e4San Mehat 31bcfe66e21ef78a078bb0de0bab532701996695d3Pierre Ossman/* show configuration fields */ 32bcfe66e21ef78a078bb0de0bab532701996695d3Pierre Ossman#define sdio_config_attr(field, format_string) \ 33bcfe66e21ef78a078bb0de0bab532701996695d3Pierre Ossmanstatic ssize_t \ 34bcfe66e21ef78a078bb0de0bab532701996695d3Pierre Ossmanfield##_show(struct device *dev, struct device_attribute *attr, char *buf) \ 35bcfe66e21ef78a078bb0de0bab532701996695d3Pierre Ossman{ \ 36bcfe66e21ef78a078bb0de0bab532701996695d3Pierre Ossman struct sdio_func *func; \ 37bcfe66e21ef78a078bb0de0bab532701996695d3Pierre Ossman \ 38bcfe66e21ef78a078bb0de0bab532701996695d3Pierre Ossman func = dev_to_sdio_func (dev); \ 39bcfe66e21ef78a078bb0de0bab532701996695d3Pierre Ossman return sprintf (buf, format_string, func->field); \ 40bcfe66e21ef78a078bb0de0bab532701996695d3Pierre Ossman} 41bcfe66e21ef78a078bb0de0bab532701996695d3Pierre Ossman 42bcfe66e21ef78a078bb0de0bab532701996695d3Pierre Ossmansdio_config_attr(class, "0x%02x\n"); 43bcfe66e21ef78a078bb0de0bab532701996695d3Pierre Ossmansdio_config_attr(vendor, "0x%04x\n"); 44bcfe66e21ef78a078bb0de0bab532701996695d3Pierre Ossmansdio_config_attr(device, "0x%04x\n"); 45bcfe66e21ef78a078bb0de0bab532701996695d3Pierre Ossman 46bcfe66e21ef78a078bb0de0bab532701996695d3Pierre Ossmanstatic ssize_t modalias_show(struct device *dev, struct device_attribute *attr, char *buf) 47bcfe66e21ef78a078bb0de0bab532701996695d3Pierre Ossman{ 48bcfe66e21ef78a078bb0de0bab532701996695d3Pierre Ossman struct sdio_func *func = dev_to_sdio_func (dev); 49bcfe66e21ef78a078bb0de0bab532701996695d3Pierre Ossman 50bcfe66e21ef78a078bb0de0bab532701996695d3Pierre Ossman return sprintf(buf, "sdio:c%02Xv%04Xd%04X\n", 51bcfe66e21ef78a078bb0de0bab532701996695d3Pierre Ossman func->class, func->vendor, func->device); 52bcfe66e21ef78a078bb0de0bab532701996695d3Pierre Ossman} 53bcfe66e21ef78a078bb0de0bab532701996695d3Pierre Ossman 5422bfc979d38f57d5b10d141990175d8fc47f6775Adrian Bunkstatic struct device_attribute sdio_dev_attrs[] = { 55bcfe66e21ef78a078bb0de0bab532701996695d3Pierre Ossman __ATTR_RO(class), 56bcfe66e21ef78a078bb0de0bab532701996695d3Pierre Ossman __ATTR_RO(vendor), 57bcfe66e21ef78a078bb0de0bab532701996695d3Pierre Ossman __ATTR_RO(device), 58bcfe66e21ef78a078bb0de0bab532701996695d3Pierre Ossman __ATTR_RO(modalias), 59bcfe66e21ef78a078bb0de0bab532701996695d3Pierre Ossman __ATTR_NULL, 60bcfe66e21ef78a078bb0de0bab532701996695d3Pierre Ossman}; 61bcfe66e21ef78a078bb0de0bab532701996695d3Pierre Ossman 623b38bea0d976513970f947806b08b9faca418e7aPierre Ossmanstatic const struct sdio_device_id *sdio_match_one(struct sdio_func *func, 633b38bea0d976513970f947806b08b9faca418e7aPierre Ossman const struct sdio_device_id *id) 643b38bea0d976513970f947806b08b9faca418e7aPierre Ossman{ 653b38bea0d976513970f947806b08b9faca418e7aPierre Ossman if (id->class != (__u8)SDIO_ANY_ID && id->class != func->class) 663b38bea0d976513970f947806b08b9faca418e7aPierre Ossman return NULL; 673b38bea0d976513970f947806b08b9faca418e7aPierre Ossman if (id->vendor != (__u16)SDIO_ANY_ID && id->vendor != func->vendor) 683b38bea0d976513970f947806b08b9faca418e7aPierre Ossman return NULL; 693b38bea0d976513970f947806b08b9faca418e7aPierre Ossman if (id->device != (__u16)SDIO_ANY_ID && id->device != func->device) 703b38bea0d976513970f947806b08b9faca418e7aPierre Ossman return NULL; 713b38bea0d976513970f947806b08b9faca418e7aPierre Ossman return id; 723b38bea0d976513970f947806b08b9faca418e7aPierre Ossman} 733b38bea0d976513970f947806b08b9faca418e7aPierre Ossman 743b38bea0d976513970f947806b08b9faca418e7aPierre Ossmanstatic const struct sdio_device_id *sdio_match_device(struct sdio_func *func, 753b38bea0d976513970f947806b08b9faca418e7aPierre Ossman struct sdio_driver *sdrv) 763b38bea0d976513970f947806b08b9faca418e7aPierre Ossman{ 773b38bea0d976513970f947806b08b9faca418e7aPierre Ossman const struct sdio_device_id *ids; 783b38bea0d976513970f947806b08b9faca418e7aPierre Ossman 793b38bea0d976513970f947806b08b9faca418e7aPierre Ossman ids = sdrv->id_table; 803b38bea0d976513970f947806b08b9faca418e7aPierre Ossman 813b38bea0d976513970f947806b08b9faca418e7aPierre Ossman if (ids) { 823b38bea0d976513970f947806b08b9faca418e7aPierre Ossman while (ids->class || ids->vendor || ids->device) { 833b38bea0d976513970f947806b08b9faca418e7aPierre Ossman if (sdio_match_one(func, ids)) 843b38bea0d976513970f947806b08b9faca418e7aPierre Ossman return ids; 853b38bea0d976513970f947806b08b9faca418e7aPierre Ossman ids++; 863b38bea0d976513970f947806b08b9faca418e7aPierre Ossman } 873b38bea0d976513970f947806b08b9faca418e7aPierre Ossman } 883b38bea0d976513970f947806b08b9faca418e7aPierre Ossman 893b38bea0d976513970f947806b08b9faca418e7aPierre Ossman return NULL; 903b38bea0d976513970f947806b08b9faca418e7aPierre Ossman} 91e29a7d73f4277eb92aa64e17017dea33460828efPierre Ossman 92e29a7d73f4277eb92aa64e17017dea33460828efPierre Ossmanstatic int sdio_bus_match(struct device *dev, struct device_driver *drv) 93e29a7d73f4277eb92aa64e17017dea33460828efPierre Ossman{ 943b38bea0d976513970f947806b08b9faca418e7aPierre Ossman struct sdio_func *func = dev_to_sdio_func(dev); 953b38bea0d976513970f947806b08b9faca418e7aPierre Ossman struct sdio_driver *sdrv = to_sdio_driver(drv); 963b38bea0d976513970f947806b08b9faca418e7aPierre Ossman 973b38bea0d976513970f947806b08b9faca418e7aPierre Ossman if (sdio_match_device(func, sdrv)) 983b38bea0d976513970f947806b08b9faca418e7aPierre Ossman return 1; 993b38bea0d976513970f947806b08b9faca418e7aPierre Ossman 1003b38bea0d976513970f947806b08b9faca418e7aPierre Ossman return 0; 101e29a7d73f4277eb92aa64e17017dea33460828efPierre Ossman} 102e29a7d73f4277eb92aa64e17017dea33460828efPierre Ossman 103e29a7d73f4277eb92aa64e17017dea33460828efPierre Ossmanstatic int 1047ac0326c3fd3f7cd2426dbbce896a0f8c91b962fAl Virosdio_bus_uevent(struct device *dev, struct kobj_uevent_env *env) 105e29a7d73f4277eb92aa64e17017dea33460828efPierre Ossman{ 106d59b66c7a575cfa8e01f483875d131e42b539bbcPierre Ossman struct sdio_func *func = dev_to_sdio_func(dev); 107d59b66c7a575cfa8e01f483875d131e42b539bbcPierre Ossman 1087ac0326c3fd3f7cd2426dbbce896a0f8c91b962fAl Viro if (add_uevent_var(env, 109d59b66c7a575cfa8e01f483875d131e42b539bbcPierre Ossman "SDIO_CLASS=%02X", func->class)) 110d59b66c7a575cfa8e01f483875d131e42b539bbcPierre Ossman return -ENOMEM; 111d59b66c7a575cfa8e01f483875d131e42b539bbcPierre Ossman 1127ac0326c3fd3f7cd2426dbbce896a0f8c91b962fAl Viro if (add_uevent_var(env, 113d59b66c7a575cfa8e01f483875d131e42b539bbcPierre Ossman "SDIO_ID=%04X:%04X", func->vendor, func->device)) 114d59b66c7a575cfa8e01f483875d131e42b539bbcPierre Ossman return -ENOMEM; 115d59b66c7a575cfa8e01f483875d131e42b539bbcPierre Ossman 1167ac0326c3fd3f7cd2426dbbce896a0f8c91b962fAl Viro if (add_uevent_var(env, 117d59b66c7a575cfa8e01f483875d131e42b539bbcPierre Ossman "MODALIAS=sdio:c%02Xv%04Xd%04X", 118d59b66c7a575cfa8e01f483875d131e42b539bbcPierre Ossman func->class, func->vendor, func->device)) 119d59b66c7a575cfa8e01f483875d131e42b539bbcPierre Ossman return -ENOMEM; 120d59b66c7a575cfa8e01f483875d131e42b539bbcPierre Ossman 121e29a7d73f4277eb92aa64e17017dea33460828efPierre Ossman return 0; 122e29a7d73f4277eb92aa64e17017dea33460828efPierre Ossman} 123e29a7d73f4277eb92aa64e17017dea33460828efPierre Ossman 124e29a7d73f4277eb92aa64e17017dea33460828efPierre Ossmanstatic int sdio_bus_probe(struct device *dev) 125e29a7d73f4277eb92aa64e17017dea33460828efPierre Ossman{ 1263b38bea0d976513970f947806b08b9faca418e7aPierre Ossman struct sdio_driver *drv = to_sdio_driver(dev->driver); 1273b38bea0d976513970f947806b08b9faca418e7aPierre Ossman struct sdio_func *func = dev_to_sdio_func(dev); 1283b38bea0d976513970f947806b08b9faca418e7aPierre Ossman const struct sdio_device_id *id; 1299a08f82b3cc522f727ace580a2aaee5402435bc8David Vrabel int ret; 1303b38bea0d976513970f947806b08b9faca418e7aPierre Ossman 1313b38bea0d976513970f947806b08b9faca418e7aPierre Ossman id = sdio_match_device(func, drv); 1323b38bea0d976513970f947806b08b9faca418e7aPierre Ossman if (!id) 1333b38bea0d976513970f947806b08b9faca418e7aPierre Ossman return -ENODEV; 1343b38bea0d976513970f947806b08b9faca418e7aPierre Ossman 13540bba0c1ca83a370f749c8bc9afda71cf79ebd91Ohad Ben-Cohen /* Unbound SDIO functions are always suspended. 13640bba0c1ca83a370f749c8bc9afda71cf79ebd91Ohad Ben-Cohen * During probe, the function is set active and the usage count 13740bba0c1ca83a370f749c8bc9afda71cf79ebd91Ohad Ben-Cohen * is incremented. If the driver supports runtime PM, 13840bba0c1ca83a370f749c8bc9afda71cf79ebd91Ohad Ben-Cohen * it should call pm_runtime_put_noidle() in its probe routine and 13940bba0c1ca83a370f749c8bc9afda71cf79ebd91Ohad Ben-Cohen * pm_runtime_get_noresume() in its remove routine. 14040bba0c1ca83a370f749c8bc9afda71cf79ebd91Ohad Ben-Cohen */ 141ed919b0125b26dcc052e44836f66e7e1f5c49c7eOhad Ben-Cohen if (func->card->host->caps & MMC_CAP_POWER_OFF_CARD) { 142ed919b0125b26dcc052e44836f66e7e1f5c49c7eOhad Ben-Cohen ret = pm_runtime_get_sync(dev); 143ed919b0125b26dcc052e44836f66e7e1f5c49c7eOhad Ben-Cohen if (ret < 0) 144ed919b0125b26dcc052e44836f66e7e1f5c49c7eOhad Ben-Cohen goto out; 145ed919b0125b26dcc052e44836f66e7e1f5c49c7eOhad Ben-Cohen } 14640bba0c1ca83a370f749c8bc9afda71cf79ebd91Ohad Ben-Cohen 1479a08f82b3cc522f727ace580a2aaee5402435bc8David Vrabel /* Set the default block size so the driver is sure it's something 1489a08f82b3cc522f727ace580a2aaee5402435bc8David Vrabel * sensible. */ 1499a08f82b3cc522f727ace580a2aaee5402435bc8David Vrabel sdio_claim_host(func); 1509a08f82b3cc522f727ace580a2aaee5402435bc8David Vrabel ret = sdio_set_block_size(func, 0); 1519a08f82b3cc522f727ace580a2aaee5402435bc8David Vrabel sdio_release_host(func); 1529a08f82b3cc522f727ace580a2aaee5402435bc8David Vrabel if (ret) 15340bba0c1ca83a370f749c8bc9afda71cf79ebd91Ohad Ben-Cohen goto disable_runtimepm; 15440bba0c1ca83a370f749c8bc9afda71cf79ebd91Ohad Ben-Cohen 15540bba0c1ca83a370f749c8bc9afda71cf79ebd91Ohad Ben-Cohen ret = drv->probe(func, id); 15640bba0c1ca83a370f749c8bc9afda71cf79ebd91Ohad Ben-Cohen if (ret) 15740bba0c1ca83a370f749c8bc9afda71cf79ebd91Ohad Ben-Cohen goto disable_runtimepm; 15840bba0c1ca83a370f749c8bc9afda71cf79ebd91Ohad Ben-Cohen 15940bba0c1ca83a370f749c8bc9afda71cf79ebd91Ohad Ben-Cohen return 0; 1609a08f82b3cc522f727ace580a2aaee5402435bc8David Vrabel 16140bba0c1ca83a370f749c8bc9afda71cf79ebd91Ohad Ben-Cohendisable_runtimepm: 162ed919b0125b26dcc052e44836f66e7e1f5c49c7eOhad Ben-Cohen if (func->card->host->caps & MMC_CAP_POWER_OFF_CARD) 163ed919b0125b26dcc052e44836f66e7e1f5c49c7eOhad Ben-Cohen pm_runtime_put_noidle(dev); 16440bba0c1ca83a370f749c8bc9afda71cf79ebd91Ohad Ben-Cohenout: 16540bba0c1ca83a370f749c8bc9afda71cf79ebd91Ohad Ben-Cohen return ret; 166e29a7d73f4277eb92aa64e17017dea33460828efPierre Ossman} 167e29a7d73f4277eb92aa64e17017dea33460828efPierre Ossman 168e29a7d73f4277eb92aa64e17017dea33460828efPierre Ossmanstatic int sdio_bus_remove(struct device *dev) 169e29a7d73f4277eb92aa64e17017dea33460828efPierre Ossman{ 1703b38bea0d976513970f947806b08b9faca418e7aPierre Ossman struct sdio_driver *drv = to_sdio_driver(dev->driver); 1713b38bea0d976513970f947806b08b9faca418e7aPierre Ossman struct sdio_func *func = dev_to_sdio_func(dev); 172ed919b0125b26dcc052e44836f66e7e1f5c49c7eOhad Ben-Cohen int ret = 0; 17340bba0c1ca83a370f749c8bc9afda71cf79ebd91Ohad Ben-Cohen 17440bba0c1ca83a370f749c8bc9afda71cf79ebd91Ohad Ben-Cohen /* Make sure card is powered before invoking ->remove() */ 175ecc024419a13da1e589aebc422d9d1e3c0124ba4Ohad Ben-Cohen if (func->card->host->caps & MMC_CAP_POWER_OFF_CARD) 176ecc024419a13da1e589aebc422d9d1e3c0124ba4Ohad Ben-Cohen pm_runtime_get_sync(dev); 1773b38bea0d976513970f947806b08b9faca418e7aPierre Ossman 1783b38bea0d976513970f947806b08b9faca418e7aPierre Ossman drv->remove(func); 1793b38bea0d976513970f947806b08b9faca418e7aPierre Ossman 180d1496c39e500857b8949cdb91af24e0eb8aae4d0Nicolas Pitre if (func->irq_handler) { 181a3c76eb9d4a1e68a69dd880cf0bcb8a52418b993Girish K S pr_warning("WARNING: driver %s did not remove " 182d1496c39e500857b8949cdb91af24e0eb8aae4d0Nicolas Pitre "its interrupt handler!\n", drv->name); 183d1496c39e500857b8949cdb91af24e0eb8aae4d0Nicolas Pitre sdio_claim_host(func); 184d1496c39e500857b8949cdb91af24e0eb8aae4d0Nicolas Pitre sdio_release_irq(func); 185d1496c39e500857b8949cdb91af24e0eb8aae4d0Nicolas Pitre sdio_release_host(func); 186d1496c39e500857b8949cdb91af24e0eb8aae4d0Nicolas Pitre } 187d1496c39e500857b8949cdb91af24e0eb8aae4d0Nicolas Pitre 18840bba0c1ca83a370f749c8bc9afda71cf79ebd91Ohad Ben-Cohen /* First, undo the increment made directly above */ 189ed919b0125b26dcc052e44836f66e7e1f5c49c7eOhad Ben-Cohen if (func->card->host->caps & MMC_CAP_POWER_OFF_CARD) 190ed919b0125b26dcc052e44836f66e7e1f5c49c7eOhad Ben-Cohen pm_runtime_put_noidle(dev); 19140bba0c1ca83a370f749c8bc9afda71cf79ebd91Ohad Ben-Cohen 19240bba0c1ca83a370f749c8bc9afda71cf79ebd91Ohad Ben-Cohen /* Then undo the runtime PM settings in sdio_bus_probe() */ 193ed919b0125b26dcc052e44836f66e7e1f5c49c7eOhad Ben-Cohen if (func->card->host->caps & MMC_CAP_POWER_OFF_CARD) 194297c7f2f158f7dfa9ab5813260ff954f9c2f83d2Ohad Ben-Cohen pm_runtime_put_sync(dev); 19540bba0c1ca83a370f749c8bc9afda71cf79ebd91Ohad Ben-Cohen 19640bba0c1ca83a370f749c8bc9afda71cf79ebd91Ohad Ben-Cohen return ret; 197e29a7d73f4277eb92aa64e17017dea33460828efPierre Ossman} 198e29a7d73f4277eb92aa64e17017dea33460828efPierre Ossman 199e841a7c69b708eeaf784fd517978006e8319b03aRafael J. Wysocki#ifdef CONFIG_PM 200e841a7c69b708eeaf784fd517978006e8319b03aRafael J. Wysocki 201e841a7c69b708eeaf784fd517978006e8319b03aRafael J. Wysockistatic int pm_no_operation(struct device *dev) 202e841a7c69b708eeaf784fd517978006e8319b03aRafael J. Wysocki{ 203e841a7c69b708eeaf784fd517978006e8319b03aRafael J. Wysocki return 0; 204e841a7c69b708eeaf784fd517978006e8319b03aRafael J. Wysocki} 20580fd933c44557c5261b80f8f8145b4fe071aeaf3Ohad Ben-Cohen 20680fd933c44557c5261b80f8f8145b4fe071aeaf3Ohad Ben-Cohenstatic const struct dev_pm_ops sdio_bus_pm_ops = { 207e841a7c69b708eeaf784fd517978006e8319b03aRafael J. Wysocki SET_SYSTEM_SLEEP_PM_OPS(pm_no_operation, pm_no_operation) 20880fd933c44557c5261b80f8f8145b4fe071aeaf3Ohad Ben-Cohen SET_RUNTIME_PM_OPS( 20980fd933c44557c5261b80f8f8145b4fe071aeaf3Ohad Ben-Cohen pm_generic_runtime_suspend, 21080fd933c44557c5261b80f8f8145b4fe071aeaf3Ohad Ben-Cohen pm_generic_runtime_resume, 21180fd933c44557c5261b80f8f8145b4fe071aeaf3Ohad Ben-Cohen pm_generic_runtime_idle 21280fd933c44557c5261b80f8f8145b4fe071aeaf3Ohad Ben-Cohen ) 21380fd933c44557c5261b80f8f8145b4fe071aeaf3Ohad Ben-Cohen}; 21480fd933c44557c5261b80f8f8145b4fe071aeaf3Ohad Ben-Cohen 21580fd933c44557c5261b80f8f8145b4fe071aeaf3Ohad Ben-Cohen#define SDIO_PM_OPS_PTR (&sdio_bus_pm_ops) 21680fd933c44557c5261b80f8f8145b4fe071aeaf3Ohad Ben-Cohen 217e841a7c69b708eeaf784fd517978006e8319b03aRafael J. Wysocki#else /* !CONFIG_PM */ 21880fd933c44557c5261b80f8f8145b4fe071aeaf3Ohad Ben-Cohen 21980fd933c44557c5261b80f8f8145b4fe071aeaf3Ohad Ben-Cohen#define SDIO_PM_OPS_PTR NULL 22080fd933c44557c5261b80f8f8145b4fe071aeaf3Ohad Ben-Cohen 221e841a7c69b708eeaf784fd517978006e8319b03aRafael J. Wysocki#endif /* !CONFIG_PM */ 22280fd933c44557c5261b80f8f8145b4fe071aeaf3Ohad Ben-Cohen 223e29a7d73f4277eb92aa64e17017dea33460828efPierre Ossmanstatic struct bus_type sdio_bus_type = { 224e29a7d73f4277eb92aa64e17017dea33460828efPierre Ossman .name = "sdio", 225bcfe66e21ef78a078bb0de0bab532701996695d3Pierre Ossman .dev_attrs = sdio_dev_attrs, 226e29a7d73f4277eb92aa64e17017dea33460828efPierre Ossman .match = sdio_bus_match, 227e29a7d73f4277eb92aa64e17017dea33460828efPierre Ossman .uevent = sdio_bus_uevent, 228e29a7d73f4277eb92aa64e17017dea33460828efPierre Ossman .probe = sdio_bus_probe, 229e29a7d73f4277eb92aa64e17017dea33460828efPierre Ossman .remove = sdio_bus_remove, 23080fd933c44557c5261b80f8f8145b4fe071aeaf3Ohad Ben-Cohen .pm = SDIO_PM_OPS_PTR, 231e29a7d73f4277eb92aa64e17017dea33460828efPierre Ossman}; 232e29a7d73f4277eb92aa64e17017dea33460828efPierre Ossman 233e29a7d73f4277eb92aa64e17017dea33460828efPierre Ossmanint sdio_register_bus(void) 234e29a7d73f4277eb92aa64e17017dea33460828efPierre Ossman{ 235e29a7d73f4277eb92aa64e17017dea33460828efPierre Ossman return bus_register(&sdio_bus_type); 236e29a7d73f4277eb92aa64e17017dea33460828efPierre Ossman} 237e29a7d73f4277eb92aa64e17017dea33460828efPierre Ossman 238e29a7d73f4277eb92aa64e17017dea33460828efPierre Ossmanvoid sdio_unregister_bus(void) 239e29a7d73f4277eb92aa64e17017dea33460828efPierre Ossman{ 240e29a7d73f4277eb92aa64e17017dea33460828efPierre Ossman bus_unregister(&sdio_bus_type); 241e29a7d73f4277eb92aa64e17017dea33460828efPierre Ossman} 242e29a7d73f4277eb92aa64e17017dea33460828efPierre Ossman 243f76c85154d320497bf1a939a98d6c432edcbd4a9Pierre Ossman/** 244f76c85154d320497bf1a939a98d6c432edcbd4a9Pierre Ossman * sdio_register_driver - register a function driver 245f76c85154d320497bf1a939a98d6c432edcbd4a9Pierre Ossman * @drv: SDIO function driver 246f76c85154d320497bf1a939a98d6c432edcbd4a9Pierre Ossman */ 247f76c85154d320497bf1a939a98d6c432edcbd4a9Pierre Ossmanint sdio_register_driver(struct sdio_driver *drv) 248f76c85154d320497bf1a939a98d6c432edcbd4a9Pierre Ossman{ 249f76c85154d320497bf1a939a98d6c432edcbd4a9Pierre Ossman drv->drv.name = drv->name; 250f76c85154d320497bf1a939a98d6c432edcbd4a9Pierre Ossman drv->drv.bus = &sdio_bus_type; 251f76c85154d320497bf1a939a98d6c432edcbd4a9Pierre Ossman return driver_register(&drv->drv); 252f76c85154d320497bf1a939a98d6c432edcbd4a9Pierre Ossman} 253f76c85154d320497bf1a939a98d6c432edcbd4a9Pierre OssmanEXPORT_SYMBOL_GPL(sdio_register_driver); 254f76c85154d320497bf1a939a98d6c432edcbd4a9Pierre Ossman 255f76c85154d320497bf1a939a98d6c432edcbd4a9Pierre Ossman/** 256f76c85154d320497bf1a939a98d6c432edcbd4a9Pierre Ossman * sdio_unregister_driver - unregister a function driver 257f76c85154d320497bf1a939a98d6c432edcbd4a9Pierre Ossman * @drv: SDIO function driver 258f76c85154d320497bf1a939a98d6c432edcbd4a9Pierre Ossman */ 259f76c85154d320497bf1a939a98d6c432edcbd4a9Pierre Ossmanvoid sdio_unregister_driver(struct sdio_driver *drv) 260f76c85154d320497bf1a939a98d6c432edcbd4a9Pierre Ossman{ 261f76c85154d320497bf1a939a98d6c432edcbd4a9Pierre Ossman drv->drv.bus = &sdio_bus_type; 262f76c85154d320497bf1a939a98d6c432edcbd4a9Pierre Ossman driver_unregister(&drv->drv); 263f76c85154d320497bf1a939a98d6c432edcbd4a9Pierre Ossman} 264f76c85154d320497bf1a939a98d6c432edcbd4a9Pierre OssmanEXPORT_SYMBOL_GPL(sdio_unregister_driver); 265f76c85154d320497bf1a939a98d6c432edcbd4a9Pierre Ossman 266e29a7d73f4277eb92aa64e17017dea33460828efPierre Ossmanstatic void sdio_release_func(struct device *dev) 267e29a7d73f4277eb92aa64e17017dea33460828efPierre Ossman{ 268e29a7d73f4277eb92aa64e17017dea33460828efPierre Ossman struct sdio_func *func = dev_to_sdio_func(dev); 269b1538bcf75e2e11459947ec4d4329ed04fbe2b2cNicolas Pitre 270e01587a794fa2ee14d3559a7d919af7e386a03e4San Mehat#ifdef CONFIG_MMC_EMBEDDED_SDIO 271e01587a794fa2ee14d3559a7d919af7e386a03e4San Mehat /* 272e01587a794fa2ee14d3559a7d919af7e386a03e4San Mehat * If this device is embedded then we never allocated 273e01587a794fa2ee14d3559a7d919af7e386a03e4San Mehat * cis tables for this func 274e01587a794fa2ee14d3559a7d919af7e386a03e4San Mehat */ 275e01587a794fa2ee14d3559a7d919af7e386a03e4San Mehat if (!func->card->host->embedded_sdio_data.funcs) 276e01587a794fa2ee14d3559a7d919af7e386a03e4San Mehat#endif 277e01587a794fa2ee14d3559a7d919af7e386a03e4San Mehat sdio_free_func_cis(func); 278e29a7d73f4277eb92aa64e17017dea33460828efPierre Ossman 279759bdc7af450404382e937c76722ae8736daef92Pierre Ossman if (func->info) 280759bdc7af450404382e937c76722ae8736daef92Pierre Ossman kfree(func->info); 281759bdc7af450404382e937c76722ae8736daef92Pierre Ossman 282e29a7d73f4277eb92aa64e17017dea33460828efPierre Ossman kfree(func); 283e29a7d73f4277eb92aa64e17017dea33460828efPierre Ossman} 284e29a7d73f4277eb92aa64e17017dea33460828efPierre Ossman 285e29a7d73f4277eb92aa64e17017dea33460828efPierre Ossman/* 286e29a7d73f4277eb92aa64e17017dea33460828efPierre Ossman * Allocate and initialise a new SDIO function structure. 287e29a7d73f4277eb92aa64e17017dea33460828efPierre Ossman */ 288e29a7d73f4277eb92aa64e17017dea33460828efPierre Ossmanstruct sdio_func *sdio_alloc_func(struct mmc_card *card) 289e29a7d73f4277eb92aa64e17017dea33460828efPierre Ossman{ 290e29a7d73f4277eb92aa64e17017dea33460828efPierre Ossman struct sdio_func *func; 291e29a7d73f4277eb92aa64e17017dea33460828efPierre Ossman 2929f2fcf99394b34769e3243a7f42a0ba8d21fc774Mariusz Kozlowski func = kzalloc(sizeof(struct sdio_func), GFP_KERNEL); 293e29a7d73f4277eb92aa64e17017dea33460828efPierre Ossman if (!func) 294e29a7d73f4277eb92aa64e17017dea33460828efPierre Ossman return ERR_PTR(-ENOMEM); 295e29a7d73f4277eb92aa64e17017dea33460828efPierre Ossman 296e29a7d73f4277eb92aa64e17017dea33460828efPierre Ossman func->card = card; 297e29a7d73f4277eb92aa64e17017dea33460828efPierre Ossman 298e29a7d73f4277eb92aa64e17017dea33460828efPierre Ossman device_initialize(&func->dev); 299e29a7d73f4277eb92aa64e17017dea33460828efPierre Ossman 300e29a7d73f4277eb92aa64e17017dea33460828efPierre Ossman func->dev.parent = &card->dev; 301e29a7d73f4277eb92aa64e17017dea33460828efPierre Ossman func->dev.bus = &sdio_bus_type; 302e29a7d73f4277eb92aa64e17017dea33460828efPierre Ossman func->dev.release = sdio_release_func; 303e29a7d73f4277eb92aa64e17017dea33460828efPierre Ossman 304e29a7d73f4277eb92aa64e17017dea33460828efPierre Ossman return func; 305e29a7d73f4277eb92aa64e17017dea33460828efPierre Ossman} 306e29a7d73f4277eb92aa64e17017dea33460828efPierre Ossman 307e29a7d73f4277eb92aa64e17017dea33460828efPierre Ossman/* 308e29a7d73f4277eb92aa64e17017dea33460828efPierre Ossman * Register a new SDIO function with the driver model. 309e29a7d73f4277eb92aa64e17017dea33460828efPierre Ossman */ 310e29a7d73f4277eb92aa64e17017dea33460828efPierre Ossmanint sdio_add_func(struct sdio_func *func) 311e29a7d73f4277eb92aa64e17017dea33460828efPierre Ossman{ 312e29a7d73f4277eb92aa64e17017dea33460828efPierre Ossman int ret; 313e29a7d73f4277eb92aa64e17017dea33460828efPierre Ossman 314d1b268630875a7713b5d468a0c03403c5b721c8eKay Sievers dev_set_name(&func->dev, "%s:%d", mmc_card_id(func->card), func->num); 315e29a7d73f4277eb92aa64e17017dea33460828efPierre Ossman 316e29a7d73f4277eb92aa64e17017dea33460828efPierre Ossman ret = device_add(&func->dev); 317e29a7d73f4277eb92aa64e17017dea33460828efPierre Ossman if (ret == 0) 318e29a7d73f4277eb92aa64e17017dea33460828efPierre Ossman sdio_func_set_present(func); 319e29a7d73f4277eb92aa64e17017dea33460828efPierre Ossman 320e29a7d73f4277eb92aa64e17017dea33460828efPierre Ossman return ret; 321e29a7d73f4277eb92aa64e17017dea33460828efPierre Ossman} 322e29a7d73f4277eb92aa64e17017dea33460828efPierre Ossman 323e29a7d73f4277eb92aa64e17017dea33460828efPierre Ossman/* 324e29a7d73f4277eb92aa64e17017dea33460828efPierre Ossman * Unregister a SDIO function with the driver model, and 325e29a7d73f4277eb92aa64e17017dea33460828efPierre Ossman * (eventually) free it. 3263d10a1ba0d37c8f5fd5afcdda00613fbb8a90bf5Daniel Drake * This function can be called through error paths where sdio_add_func() was 3273d10a1ba0d37c8f5fd5afcdda00613fbb8a90bf5Daniel Drake * never executed (because a failure occurred at an earlier point). 328e29a7d73f4277eb92aa64e17017dea33460828efPierre Ossman */ 329e29a7d73f4277eb92aa64e17017dea33460828efPierre Ossmanvoid sdio_remove_func(struct sdio_func *func) 330e29a7d73f4277eb92aa64e17017dea33460828efPierre Ossman{ 3313d10a1ba0d37c8f5fd5afcdda00613fbb8a90bf5Daniel Drake if (!sdio_func_present(func)) 3323d10a1ba0d37c8f5fd5afcdda00613fbb8a90bf5Daniel Drake return; 333e29a7d73f4277eb92aa64e17017dea33460828efPierre Ossman 3343d10a1ba0d37c8f5fd5afcdda00613fbb8a90bf5Daniel Drake device_del(&func->dev); 335e29a7d73f4277eb92aa64e17017dea33460828efPierre Ossman put_device(&func->dev); 336e29a7d73f4277eb92aa64e17017dea33460828efPierre Ossman} 337e29a7d73f4277eb92aa64e17017dea33460828efPierre Ossman 338