sdio_bus.c revision ed919b0125b26dcc052e44836f66e7e1f5c49c7e
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> 165a0e3ad6af8660be21ca98a971cd00f331318c05Tejun Heo#include <linux/slab.h> 1780fd933c44557c5261b80f8f8145b4fe071aeaf3Ohad Ben-Cohen#include <linux/pm_runtime.h> 18e29a7d73f4277eb92aa64e17017dea33460828efPierre Ossman 19e29a7d73f4277eb92aa64e17017dea33460828efPierre Ossman#include <linux/mmc/card.h> 20ed919b0125b26dcc052e44836f66e7e1f5c49c7eOhad Ben-Cohen#include <linux/mmc/host.h> 21e29a7d73f4277eb92aa64e17017dea33460828efPierre Ossman#include <linux/mmc/sdio_func.h> 22e29a7d73f4277eb92aa64e17017dea33460828efPierre Ossman 23b1538bcf75e2e11459947ec4d4329ed04fbe2b2cNicolas Pitre#include "sdio_cis.h" 24e29a7d73f4277eb92aa64e17017dea33460828efPierre Ossman#include "sdio_bus.h" 25e29a7d73f4277eb92aa64e17017dea33460828efPierre Ossman 26bcfe66e21ef78a078bb0de0bab532701996695d3Pierre Ossman/* show configuration fields */ 27bcfe66e21ef78a078bb0de0bab532701996695d3Pierre Ossman#define sdio_config_attr(field, format_string) \ 28bcfe66e21ef78a078bb0de0bab532701996695d3Pierre Ossmanstatic ssize_t \ 29bcfe66e21ef78a078bb0de0bab532701996695d3Pierre Ossmanfield##_show(struct device *dev, struct device_attribute *attr, char *buf) \ 30bcfe66e21ef78a078bb0de0bab532701996695d3Pierre Ossman{ \ 31bcfe66e21ef78a078bb0de0bab532701996695d3Pierre Ossman struct sdio_func *func; \ 32bcfe66e21ef78a078bb0de0bab532701996695d3Pierre Ossman \ 33bcfe66e21ef78a078bb0de0bab532701996695d3Pierre Ossman func = dev_to_sdio_func (dev); \ 34bcfe66e21ef78a078bb0de0bab532701996695d3Pierre Ossman return sprintf (buf, format_string, func->field); \ 35bcfe66e21ef78a078bb0de0bab532701996695d3Pierre Ossman} 36bcfe66e21ef78a078bb0de0bab532701996695d3Pierre Ossman 37bcfe66e21ef78a078bb0de0bab532701996695d3Pierre Ossmansdio_config_attr(class, "0x%02x\n"); 38bcfe66e21ef78a078bb0de0bab532701996695d3Pierre Ossmansdio_config_attr(vendor, "0x%04x\n"); 39bcfe66e21ef78a078bb0de0bab532701996695d3Pierre Ossmansdio_config_attr(device, "0x%04x\n"); 40bcfe66e21ef78a078bb0de0bab532701996695d3Pierre Ossman 41bcfe66e21ef78a078bb0de0bab532701996695d3Pierre Ossmanstatic ssize_t modalias_show(struct device *dev, struct device_attribute *attr, char *buf) 42bcfe66e21ef78a078bb0de0bab532701996695d3Pierre Ossman{ 43bcfe66e21ef78a078bb0de0bab532701996695d3Pierre Ossman struct sdio_func *func = dev_to_sdio_func (dev); 44bcfe66e21ef78a078bb0de0bab532701996695d3Pierre Ossman 45bcfe66e21ef78a078bb0de0bab532701996695d3Pierre Ossman return sprintf(buf, "sdio:c%02Xv%04Xd%04X\n", 46bcfe66e21ef78a078bb0de0bab532701996695d3Pierre Ossman func->class, func->vendor, func->device); 47bcfe66e21ef78a078bb0de0bab532701996695d3Pierre Ossman} 48bcfe66e21ef78a078bb0de0bab532701996695d3Pierre Ossman 4922bfc979d38f57d5b10d141990175d8fc47f6775Adrian Bunkstatic struct device_attribute sdio_dev_attrs[] = { 50bcfe66e21ef78a078bb0de0bab532701996695d3Pierre Ossman __ATTR_RO(class), 51bcfe66e21ef78a078bb0de0bab532701996695d3Pierre Ossman __ATTR_RO(vendor), 52bcfe66e21ef78a078bb0de0bab532701996695d3Pierre Ossman __ATTR_RO(device), 53bcfe66e21ef78a078bb0de0bab532701996695d3Pierre Ossman __ATTR_RO(modalias), 54bcfe66e21ef78a078bb0de0bab532701996695d3Pierre Ossman __ATTR_NULL, 55bcfe66e21ef78a078bb0de0bab532701996695d3Pierre Ossman}; 56bcfe66e21ef78a078bb0de0bab532701996695d3Pierre Ossman 573b38bea0d976513970f947806b08b9faca418e7aPierre Ossmanstatic const struct sdio_device_id *sdio_match_one(struct sdio_func *func, 583b38bea0d976513970f947806b08b9faca418e7aPierre Ossman const struct sdio_device_id *id) 593b38bea0d976513970f947806b08b9faca418e7aPierre Ossman{ 603b38bea0d976513970f947806b08b9faca418e7aPierre Ossman if (id->class != (__u8)SDIO_ANY_ID && id->class != func->class) 613b38bea0d976513970f947806b08b9faca418e7aPierre Ossman return NULL; 623b38bea0d976513970f947806b08b9faca418e7aPierre Ossman if (id->vendor != (__u16)SDIO_ANY_ID && id->vendor != func->vendor) 633b38bea0d976513970f947806b08b9faca418e7aPierre Ossman return NULL; 643b38bea0d976513970f947806b08b9faca418e7aPierre Ossman if (id->device != (__u16)SDIO_ANY_ID && id->device != func->device) 653b38bea0d976513970f947806b08b9faca418e7aPierre Ossman return NULL; 663b38bea0d976513970f947806b08b9faca418e7aPierre Ossman return id; 673b38bea0d976513970f947806b08b9faca418e7aPierre Ossman} 683b38bea0d976513970f947806b08b9faca418e7aPierre Ossman 693b38bea0d976513970f947806b08b9faca418e7aPierre Ossmanstatic const struct sdio_device_id *sdio_match_device(struct sdio_func *func, 703b38bea0d976513970f947806b08b9faca418e7aPierre Ossman struct sdio_driver *sdrv) 713b38bea0d976513970f947806b08b9faca418e7aPierre Ossman{ 723b38bea0d976513970f947806b08b9faca418e7aPierre Ossman const struct sdio_device_id *ids; 733b38bea0d976513970f947806b08b9faca418e7aPierre Ossman 743b38bea0d976513970f947806b08b9faca418e7aPierre Ossman ids = sdrv->id_table; 753b38bea0d976513970f947806b08b9faca418e7aPierre Ossman 763b38bea0d976513970f947806b08b9faca418e7aPierre Ossman if (ids) { 773b38bea0d976513970f947806b08b9faca418e7aPierre Ossman while (ids->class || ids->vendor || ids->device) { 783b38bea0d976513970f947806b08b9faca418e7aPierre Ossman if (sdio_match_one(func, ids)) 793b38bea0d976513970f947806b08b9faca418e7aPierre Ossman return ids; 803b38bea0d976513970f947806b08b9faca418e7aPierre Ossman ids++; 813b38bea0d976513970f947806b08b9faca418e7aPierre Ossman } 823b38bea0d976513970f947806b08b9faca418e7aPierre Ossman } 833b38bea0d976513970f947806b08b9faca418e7aPierre Ossman 843b38bea0d976513970f947806b08b9faca418e7aPierre Ossman return NULL; 853b38bea0d976513970f947806b08b9faca418e7aPierre Ossman} 86e29a7d73f4277eb92aa64e17017dea33460828efPierre Ossman 87e29a7d73f4277eb92aa64e17017dea33460828efPierre Ossmanstatic int sdio_bus_match(struct device *dev, struct device_driver *drv) 88e29a7d73f4277eb92aa64e17017dea33460828efPierre Ossman{ 893b38bea0d976513970f947806b08b9faca418e7aPierre Ossman struct sdio_func *func = dev_to_sdio_func(dev); 903b38bea0d976513970f947806b08b9faca418e7aPierre Ossman struct sdio_driver *sdrv = to_sdio_driver(drv); 913b38bea0d976513970f947806b08b9faca418e7aPierre Ossman 923b38bea0d976513970f947806b08b9faca418e7aPierre Ossman if (sdio_match_device(func, sdrv)) 933b38bea0d976513970f947806b08b9faca418e7aPierre Ossman return 1; 943b38bea0d976513970f947806b08b9faca418e7aPierre Ossman 953b38bea0d976513970f947806b08b9faca418e7aPierre Ossman return 0; 96e29a7d73f4277eb92aa64e17017dea33460828efPierre Ossman} 97e29a7d73f4277eb92aa64e17017dea33460828efPierre Ossman 98e29a7d73f4277eb92aa64e17017dea33460828efPierre Ossmanstatic int 997ac0326c3fd3f7cd2426dbbce896a0f8c91b962fAl Virosdio_bus_uevent(struct device *dev, struct kobj_uevent_env *env) 100e29a7d73f4277eb92aa64e17017dea33460828efPierre Ossman{ 101d59b66c7a575cfa8e01f483875d131e42b539bbcPierre Ossman struct sdio_func *func = dev_to_sdio_func(dev); 102d59b66c7a575cfa8e01f483875d131e42b539bbcPierre Ossman 1037ac0326c3fd3f7cd2426dbbce896a0f8c91b962fAl Viro if (add_uevent_var(env, 104d59b66c7a575cfa8e01f483875d131e42b539bbcPierre Ossman "SDIO_CLASS=%02X", func->class)) 105d59b66c7a575cfa8e01f483875d131e42b539bbcPierre Ossman return -ENOMEM; 106d59b66c7a575cfa8e01f483875d131e42b539bbcPierre Ossman 1077ac0326c3fd3f7cd2426dbbce896a0f8c91b962fAl Viro if (add_uevent_var(env, 108d59b66c7a575cfa8e01f483875d131e42b539bbcPierre Ossman "SDIO_ID=%04X:%04X", func->vendor, func->device)) 109d59b66c7a575cfa8e01f483875d131e42b539bbcPierre Ossman return -ENOMEM; 110d59b66c7a575cfa8e01f483875d131e42b539bbcPierre Ossman 1117ac0326c3fd3f7cd2426dbbce896a0f8c91b962fAl Viro if (add_uevent_var(env, 112d59b66c7a575cfa8e01f483875d131e42b539bbcPierre Ossman "MODALIAS=sdio:c%02Xv%04Xd%04X", 113d59b66c7a575cfa8e01f483875d131e42b539bbcPierre Ossman func->class, func->vendor, func->device)) 114d59b66c7a575cfa8e01f483875d131e42b539bbcPierre Ossman return -ENOMEM; 115d59b66c7a575cfa8e01f483875d131e42b539bbcPierre Ossman 116e29a7d73f4277eb92aa64e17017dea33460828efPierre Ossman return 0; 117e29a7d73f4277eb92aa64e17017dea33460828efPierre Ossman} 118e29a7d73f4277eb92aa64e17017dea33460828efPierre Ossman 119e29a7d73f4277eb92aa64e17017dea33460828efPierre Ossmanstatic int sdio_bus_probe(struct device *dev) 120e29a7d73f4277eb92aa64e17017dea33460828efPierre Ossman{ 1213b38bea0d976513970f947806b08b9faca418e7aPierre Ossman struct sdio_driver *drv = to_sdio_driver(dev->driver); 1223b38bea0d976513970f947806b08b9faca418e7aPierre Ossman struct sdio_func *func = dev_to_sdio_func(dev); 1233b38bea0d976513970f947806b08b9faca418e7aPierre Ossman const struct sdio_device_id *id; 1249a08f82b3cc522f727ace580a2aaee5402435bc8David Vrabel int ret; 1253b38bea0d976513970f947806b08b9faca418e7aPierre Ossman 1263b38bea0d976513970f947806b08b9faca418e7aPierre Ossman id = sdio_match_device(func, drv); 1273b38bea0d976513970f947806b08b9faca418e7aPierre Ossman if (!id) 1283b38bea0d976513970f947806b08b9faca418e7aPierre Ossman return -ENODEV; 1293b38bea0d976513970f947806b08b9faca418e7aPierre Ossman 13040bba0c1ca83a370f749c8bc9afda71cf79ebd91Ohad Ben-Cohen /* Unbound SDIO functions are always suspended. 13140bba0c1ca83a370f749c8bc9afda71cf79ebd91Ohad Ben-Cohen * During probe, the function is set active and the usage count 13240bba0c1ca83a370f749c8bc9afda71cf79ebd91Ohad Ben-Cohen * is incremented. If the driver supports runtime PM, 13340bba0c1ca83a370f749c8bc9afda71cf79ebd91Ohad Ben-Cohen * it should call pm_runtime_put_noidle() in its probe routine and 13440bba0c1ca83a370f749c8bc9afda71cf79ebd91Ohad Ben-Cohen * pm_runtime_get_noresume() in its remove routine. 13540bba0c1ca83a370f749c8bc9afda71cf79ebd91Ohad Ben-Cohen */ 136ed919b0125b26dcc052e44836f66e7e1f5c49c7eOhad Ben-Cohen if (func->card->host->caps & MMC_CAP_POWER_OFF_CARD) { 137ed919b0125b26dcc052e44836f66e7e1f5c49c7eOhad Ben-Cohen ret = pm_runtime_get_sync(dev); 138ed919b0125b26dcc052e44836f66e7e1f5c49c7eOhad Ben-Cohen if (ret < 0) 139ed919b0125b26dcc052e44836f66e7e1f5c49c7eOhad Ben-Cohen goto out; 140ed919b0125b26dcc052e44836f66e7e1f5c49c7eOhad Ben-Cohen } 14140bba0c1ca83a370f749c8bc9afda71cf79ebd91Ohad Ben-Cohen 1429a08f82b3cc522f727ace580a2aaee5402435bc8David Vrabel /* Set the default block size so the driver is sure it's something 1439a08f82b3cc522f727ace580a2aaee5402435bc8David Vrabel * sensible. */ 1449a08f82b3cc522f727ace580a2aaee5402435bc8David Vrabel sdio_claim_host(func); 1459a08f82b3cc522f727ace580a2aaee5402435bc8David Vrabel ret = sdio_set_block_size(func, 0); 1469a08f82b3cc522f727ace580a2aaee5402435bc8David Vrabel sdio_release_host(func); 1479a08f82b3cc522f727ace580a2aaee5402435bc8David Vrabel if (ret) 14840bba0c1ca83a370f749c8bc9afda71cf79ebd91Ohad Ben-Cohen goto disable_runtimepm; 14940bba0c1ca83a370f749c8bc9afda71cf79ebd91Ohad Ben-Cohen 15040bba0c1ca83a370f749c8bc9afda71cf79ebd91Ohad Ben-Cohen ret = drv->probe(func, id); 15140bba0c1ca83a370f749c8bc9afda71cf79ebd91Ohad Ben-Cohen if (ret) 15240bba0c1ca83a370f749c8bc9afda71cf79ebd91Ohad Ben-Cohen goto disable_runtimepm; 15340bba0c1ca83a370f749c8bc9afda71cf79ebd91Ohad Ben-Cohen 15440bba0c1ca83a370f749c8bc9afda71cf79ebd91Ohad Ben-Cohen return 0; 1559a08f82b3cc522f727ace580a2aaee5402435bc8David Vrabel 15640bba0c1ca83a370f749c8bc9afda71cf79ebd91Ohad Ben-Cohendisable_runtimepm: 157ed919b0125b26dcc052e44836f66e7e1f5c49c7eOhad Ben-Cohen if (func->card->host->caps & MMC_CAP_POWER_OFF_CARD) 158ed919b0125b26dcc052e44836f66e7e1f5c49c7eOhad Ben-Cohen pm_runtime_put_noidle(dev); 15940bba0c1ca83a370f749c8bc9afda71cf79ebd91Ohad Ben-Cohenout: 16040bba0c1ca83a370f749c8bc9afda71cf79ebd91Ohad Ben-Cohen return ret; 161e29a7d73f4277eb92aa64e17017dea33460828efPierre Ossman} 162e29a7d73f4277eb92aa64e17017dea33460828efPierre Ossman 163e29a7d73f4277eb92aa64e17017dea33460828efPierre Ossmanstatic int sdio_bus_remove(struct device *dev) 164e29a7d73f4277eb92aa64e17017dea33460828efPierre Ossman{ 1653b38bea0d976513970f947806b08b9faca418e7aPierre Ossman struct sdio_driver *drv = to_sdio_driver(dev->driver); 1663b38bea0d976513970f947806b08b9faca418e7aPierre Ossman struct sdio_func *func = dev_to_sdio_func(dev); 167ed919b0125b26dcc052e44836f66e7e1f5c49c7eOhad Ben-Cohen int ret = 0; 16840bba0c1ca83a370f749c8bc9afda71cf79ebd91Ohad Ben-Cohen 16940bba0c1ca83a370f749c8bc9afda71cf79ebd91Ohad Ben-Cohen /* Make sure card is powered before invoking ->remove() */ 170ed919b0125b26dcc052e44836f66e7e1f5c49c7eOhad Ben-Cohen if (func->card->host->caps & MMC_CAP_POWER_OFF_CARD) { 171ed919b0125b26dcc052e44836f66e7e1f5c49c7eOhad Ben-Cohen ret = pm_runtime_get_sync(dev); 172ed919b0125b26dcc052e44836f66e7e1f5c49c7eOhad Ben-Cohen if (ret < 0) 173ed919b0125b26dcc052e44836f66e7e1f5c49c7eOhad Ben-Cohen goto out; 174ed919b0125b26dcc052e44836f66e7e1f5c49c7eOhad Ben-Cohen } 1753b38bea0d976513970f947806b08b9faca418e7aPierre Ossman 1763b38bea0d976513970f947806b08b9faca418e7aPierre Ossman drv->remove(func); 1773b38bea0d976513970f947806b08b9faca418e7aPierre Ossman 178d1496c39e500857b8949cdb91af24e0eb8aae4d0Nicolas Pitre if (func->irq_handler) { 179d1496c39e500857b8949cdb91af24e0eb8aae4d0Nicolas Pitre printk(KERN_WARNING "WARNING: driver %s did not remove " 180d1496c39e500857b8949cdb91af24e0eb8aae4d0Nicolas Pitre "its interrupt handler!\n", drv->name); 181d1496c39e500857b8949cdb91af24e0eb8aae4d0Nicolas Pitre sdio_claim_host(func); 182d1496c39e500857b8949cdb91af24e0eb8aae4d0Nicolas Pitre sdio_release_irq(func); 183d1496c39e500857b8949cdb91af24e0eb8aae4d0Nicolas Pitre sdio_release_host(func); 184d1496c39e500857b8949cdb91af24e0eb8aae4d0Nicolas Pitre } 185d1496c39e500857b8949cdb91af24e0eb8aae4d0Nicolas Pitre 18640bba0c1ca83a370f749c8bc9afda71cf79ebd91Ohad Ben-Cohen /* First, undo the increment made directly above */ 187ed919b0125b26dcc052e44836f66e7e1f5c49c7eOhad Ben-Cohen if (func->card->host->caps & MMC_CAP_POWER_OFF_CARD) 188ed919b0125b26dcc052e44836f66e7e1f5c49c7eOhad Ben-Cohen pm_runtime_put_noidle(dev); 18940bba0c1ca83a370f749c8bc9afda71cf79ebd91Ohad Ben-Cohen 19040bba0c1ca83a370f749c8bc9afda71cf79ebd91Ohad Ben-Cohen /* Then undo the runtime PM settings in sdio_bus_probe() */ 191ed919b0125b26dcc052e44836f66e7e1f5c49c7eOhad Ben-Cohen if (func->card->host->caps & MMC_CAP_POWER_OFF_CARD) 192ed919b0125b26dcc052e44836f66e7e1f5c49c7eOhad Ben-Cohen pm_runtime_put_noidle(dev); 19340bba0c1ca83a370f749c8bc9afda71cf79ebd91Ohad Ben-Cohen 19440bba0c1ca83a370f749c8bc9afda71cf79ebd91Ohad Ben-Cohenout: 19540bba0c1ca83a370f749c8bc9afda71cf79ebd91Ohad Ben-Cohen return ret; 196e29a7d73f4277eb92aa64e17017dea33460828efPierre Ossman} 197e29a7d73f4277eb92aa64e17017dea33460828efPierre Ossman 19880fd933c44557c5261b80f8f8145b4fe071aeaf3Ohad Ben-Cohen#ifdef CONFIG_PM_RUNTIME 19980fd933c44557c5261b80f8f8145b4fe071aeaf3Ohad Ben-Cohen 200ed2a9785942b0986ac858f3f48d7fc5f7c7183deOhad Ben-Cohenstatic int sdio_bus_pm_prepare(struct device *dev) 201ed2a9785942b0986ac858f3f48d7fc5f7c7183deOhad Ben-Cohen{ 202ed919b0125b26dcc052e44836f66e7e1f5c49c7eOhad Ben-Cohen struct sdio_func *func = dev_to_sdio_func(dev); 203ed919b0125b26dcc052e44836f66e7e1f5c49c7eOhad Ben-Cohen 204ed2a9785942b0986ac858f3f48d7fc5f7c7183deOhad Ben-Cohen /* 205ed2a9785942b0986ac858f3f48d7fc5f7c7183deOhad Ben-Cohen * Resume an SDIO device which was suspended at run time at this 206ed2a9785942b0986ac858f3f48d7fc5f7c7183deOhad Ben-Cohen * point, in order to allow standard SDIO suspend/resume paths 207ed2a9785942b0986ac858f3f48d7fc5f7c7183deOhad Ben-Cohen * to keep working as usual. 208ed2a9785942b0986ac858f3f48d7fc5f7c7183deOhad Ben-Cohen * 209ed2a9785942b0986ac858f3f48d7fc5f7c7183deOhad Ben-Cohen * Ultimately, the SDIO driver itself will decide (in its 210ed2a9785942b0986ac858f3f48d7fc5f7c7183deOhad Ben-Cohen * suspend handler, or lack thereof) whether the card should be 211ed2a9785942b0986ac858f3f48d7fc5f7c7183deOhad Ben-Cohen * removed or kept, and if kept, at what power state. 212ed2a9785942b0986ac858f3f48d7fc5f7c7183deOhad Ben-Cohen * 213ed2a9785942b0986ac858f3f48d7fc5f7c7183deOhad Ben-Cohen * At this point, PM core have increased our use count, so it's 214ed2a9785942b0986ac858f3f48d7fc5f7c7183deOhad Ben-Cohen * safe to directly resume the device. After system is resumed 215ed2a9785942b0986ac858f3f48d7fc5f7c7183deOhad Ben-Cohen * again, PM core will drop back its runtime PM use count, and if 216ed2a9785942b0986ac858f3f48d7fc5f7c7183deOhad Ben-Cohen * needed device will be suspended again. 217ed2a9785942b0986ac858f3f48d7fc5f7c7183deOhad Ben-Cohen * 218ed2a9785942b0986ac858f3f48d7fc5f7c7183deOhad Ben-Cohen * The end result is guaranteed to be a power state that is 219ed2a9785942b0986ac858f3f48d7fc5f7c7183deOhad Ben-Cohen * coherent with the device's runtime PM use count. 220ed2a9785942b0986ac858f3f48d7fc5f7c7183deOhad Ben-Cohen * 221ed2a9785942b0986ac858f3f48d7fc5f7c7183deOhad Ben-Cohen * The return value of pm_runtime_resume is deliberately unchecked 222ed2a9785942b0986ac858f3f48d7fc5f7c7183deOhad Ben-Cohen * since there is little point in failing system suspend if a 223ed2a9785942b0986ac858f3f48d7fc5f7c7183deOhad Ben-Cohen * device can't be resumed. 224ed2a9785942b0986ac858f3f48d7fc5f7c7183deOhad Ben-Cohen */ 225ed919b0125b26dcc052e44836f66e7e1f5c49c7eOhad Ben-Cohen if (func->card->host->caps & MMC_CAP_POWER_OFF_CARD) 226ed919b0125b26dcc052e44836f66e7e1f5c49c7eOhad Ben-Cohen pm_runtime_resume(dev); 227ed2a9785942b0986ac858f3f48d7fc5f7c7183deOhad Ben-Cohen 228ed2a9785942b0986ac858f3f48d7fc5f7c7183deOhad Ben-Cohen return 0; 229ed2a9785942b0986ac858f3f48d7fc5f7c7183deOhad Ben-Cohen} 230ed2a9785942b0986ac858f3f48d7fc5f7c7183deOhad Ben-Cohen 23180fd933c44557c5261b80f8f8145b4fe071aeaf3Ohad Ben-Cohenstatic const struct dev_pm_ops sdio_bus_pm_ops = { 23280fd933c44557c5261b80f8f8145b4fe071aeaf3Ohad Ben-Cohen SET_RUNTIME_PM_OPS( 23380fd933c44557c5261b80f8f8145b4fe071aeaf3Ohad Ben-Cohen pm_generic_runtime_suspend, 23480fd933c44557c5261b80f8f8145b4fe071aeaf3Ohad Ben-Cohen pm_generic_runtime_resume, 23580fd933c44557c5261b80f8f8145b4fe071aeaf3Ohad Ben-Cohen pm_generic_runtime_idle 23680fd933c44557c5261b80f8f8145b4fe071aeaf3Ohad Ben-Cohen ) 237ed2a9785942b0986ac858f3f48d7fc5f7c7183deOhad Ben-Cohen .prepare = sdio_bus_pm_prepare, 23880fd933c44557c5261b80f8f8145b4fe071aeaf3Ohad Ben-Cohen}; 23980fd933c44557c5261b80f8f8145b4fe071aeaf3Ohad Ben-Cohen 24080fd933c44557c5261b80f8f8145b4fe071aeaf3Ohad Ben-Cohen#define SDIO_PM_OPS_PTR (&sdio_bus_pm_ops) 24180fd933c44557c5261b80f8f8145b4fe071aeaf3Ohad Ben-Cohen 24280fd933c44557c5261b80f8f8145b4fe071aeaf3Ohad Ben-Cohen#else /* !CONFIG_PM_RUNTIME */ 24380fd933c44557c5261b80f8f8145b4fe071aeaf3Ohad Ben-Cohen 24480fd933c44557c5261b80f8f8145b4fe071aeaf3Ohad Ben-Cohen#define SDIO_PM_OPS_PTR NULL 24580fd933c44557c5261b80f8f8145b4fe071aeaf3Ohad Ben-Cohen 24680fd933c44557c5261b80f8f8145b4fe071aeaf3Ohad Ben-Cohen#endif /* !CONFIG_PM_RUNTIME */ 24780fd933c44557c5261b80f8f8145b4fe071aeaf3Ohad Ben-Cohen 248e29a7d73f4277eb92aa64e17017dea33460828efPierre Ossmanstatic struct bus_type sdio_bus_type = { 249e29a7d73f4277eb92aa64e17017dea33460828efPierre Ossman .name = "sdio", 250bcfe66e21ef78a078bb0de0bab532701996695d3Pierre Ossman .dev_attrs = sdio_dev_attrs, 251e29a7d73f4277eb92aa64e17017dea33460828efPierre Ossman .match = sdio_bus_match, 252e29a7d73f4277eb92aa64e17017dea33460828efPierre Ossman .uevent = sdio_bus_uevent, 253e29a7d73f4277eb92aa64e17017dea33460828efPierre Ossman .probe = sdio_bus_probe, 254e29a7d73f4277eb92aa64e17017dea33460828efPierre Ossman .remove = sdio_bus_remove, 25580fd933c44557c5261b80f8f8145b4fe071aeaf3Ohad Ben-Cohen .pm = SDIO_PM_OPS_PTR, 256e29a7d73f4277eb92aa64e17017dea33460828efPierre Ossman}; 257e29a7d73f4277eb92aa64e17017dea33460828efPierre Ossman 258e29a7d73f4277eb92aa64e17017dea33460828efPierre Ossmanint sdio_register_bus(void) 259e29a7d73f4277eb92aa64e17017dea33460828efPierre Ossman{ 260e29a7d73f4277eb92aa64e17017dea33460828efPierre Ossman return bus_register(&sdio_bus_type); 261e29a7d73f4277eb92aa64e17017dea33460828efPierre Ossman} 262e29a7d73f4277eb92aa64e17017dea33460828efPierre Ossman 263e29a7d73f4277eb92aa64e17017dea33460828efPierre Ossmanvoid sdio_unregister_bus(void) 264e29a7d73f4277eb92aa64e17017dea33460828efPierre Ossman{ 265e29a7d73f4277eb92aa64e17017dea33460828efPierre Ossman bus_unregister(&sdio_bus_type); 266e29a7d73f4277eb92aa64e17017dea33460828efPierre Ossman} 267e29a7d73f4277eb92aa64e17017dea33460828efPierre Ossman 268f76c85154d320497bf1a939a98d6c432edcbd4a9Pierre Ossman/** 269f76c85154d320497bf1a939a98d6c432edcbd4a9Pierre Ossman * sdio_register_driver - register a function driver 270f76c85154d320497bf1a939a98d6c432edcbd4a9Pierre Ossman * @drv: SDIO function driver 271f76c85154d320497bf1a939a98d6c432edcbd4a9Pierre Ossman */ 272f76c85154d320497bf1a939a98d6c432edcbd4a9Pierre Ossmanint sdio_register_driver(struct sdio_driver *drv) 273f76c85154d320497bf1a939a98d6c432edcbd4a9Pierre Ossman{ 274f76c85154d320497bf1a939a98d6c432edcbd4a9Pierre Ossman drv->drv.name = drv->name; 275f76c85154d320497bf1a939a98d6c432edcbd4a9Pierre Ossman drv->drv.bus = &sdio_bus_type; 276f76c85154d320497bf1a939a98d6c432edcbd4a9Pierre Ossman return driver_register(&drv->drv); 277f76c85154d320497bf1a939a98d6c432edcbd4a9Pierre Ossman} 278f76c85154d320497bf1a939a98d6c432edcbd4a9Pierre OssmanEXPORT_SYMBOL_GPL(sdio_register_driver); 279f76c85154d320497bf1a939a98d6c432edcbd4a9Pierre Ossman 280f76c85154d320497bf1a939a98d6c432edcbd4a9Pierre Ossman/** 281f76c85154d320497bf1a939a98d6c432edcbd4a9Pierre Ossman * sdio_unregister_driver - unregister a function driver 282f76c85154d320497bf1a939a98d6c432edcbd4a9Pierre Ossman * @drv: SDIO function driver 283f76c85154d320497bf1a939a98d6c432edcbd4a9Pierre Ossman */ 284f76c85154d320497bf1a939a98d6c432edcbd4a9Pierre Ossmanvoid sdio_unregister_driver(struct sdio_driver *drv) 285f76c85154d320497bf1a939a98d6c432edcbd4a9Pierre Ossman{ 286f76c85154d320497bf1a939a98d6c432edcbd4a9Pierre Ossman drv->drv.bus = &sdio_bus_type; 287f76c85154d320497bf1a939a98d6c432edcbd4a9Pierre Ossman driver_unregister(&drv->drv); 288f76c85154d320497bf1a939a98d6c432edcbd4a9Pierre Ossman} 289f76c85154d320497bf1a939a98d6c432edcbd4a9Pierre OssmanEXPORT_SYMBOL_GPL(sdio_unregister_driver); 290f76c85154d320497bf1a939a98d6c432edcbd4a9Pierre Ossman 291e29a7d73f4277eb92aa64e17017dea33460828efPierre Ossmanstatic void sdio_release_func(struct device *dev) 292e29a7d73f4277eb92aa64e17017dea33460828efPierre Ossman{ 293e29a7d73f4277eb92aa64e17017dea33460828efPierre Ossman struct sdio_func *func = dev_to_sdio_func(dev); 294b1538bcf75e2e11459947ec4d4329ed04fbe2b2cNicolas Pitre 2951a632f8cdc33e7f8edca352164f0c96a75d08f08Pierre Ossman sdio_free_func_cis(func); 296e29a7d73f4277eb92aa64e17017dea33460828efPierre Ossman 297759bdc7af450404382e937c76722ae8736daef92Pierre Ossman if (func->info) 298759bdc7af450404382e937c76722ae8736daef92Pierre Ossman kfree(func->info); 299759bdc7af450404382e937c76722ae8736daef92Pierre Ossman 300e29a7d73f4277eb92aa64e17017dea33460828efPierre Ossman kfree(func); 301e29a7d73f4277eb92aa64e17017dea33460828efPierre Ossman} 302e29a7d73f4277eb92aa64e17017dea33460828efPierre Ossman 303e29a7d73f4277eb92aa64e17017dea33460828efPierre Ossman/* 304e29a7d73f4277eb92aa64e17017dea33460828efPierre Ossman * Allocate and initialise a new SDIO function structure. 305e29a7d73f4277eb92aa64e17017dea33460828efPierre Ossman */ 306e29a7d73f4277eb92aa64e17017dea33460828efPierre Ossmanstruct sdio_func *sdio_alloc_func(struct mmc_card *card) 307e29a7d73f4277eb92aa64e17017dea33460828efPierre Ossman{ 308e29a7d73f4277eb92aa64e17017dea33460828efPierre Ossman struct sdio_func *func; 309e29a7d73f4277eb92aa64e17017dea33460828efPierre Ossman 3109f2fcf99394b34769e3243a7f42a0ba8d21fc774Mariusz Kozlowski func = kzalloc(sizeof(struct sdio_func), GFP_KERNEL); 311e29a7d73f4277eb92aa64e17017dea33460828efPierre Ossman if (!func) 312e29a7d73f4277eb92aa64e17017dea33460828efPierre Ossman return ERR_PTR(-ENOMEM); 313e29a7d73f4277eb92aa64e17017dea33460828efPierre Ossman 314e29a7d73f4277eb92aa64e17017dea33460828efPierre Ossman func->card = card; 315e29a7d73f4277eb92aa64e17017dea33460828efPierre Ossman 316e29a7d73f4277eb92aa64e17017dea33460828efPierre Ossman device_initialize(&func->dev); 317e29a7d73f4277eb92aa64e17017dea33460828efPierre Ossman 318e29a7d73f4277eb92aa64e17017dea33460828efPierre Ossman func->dev.parent = &card->dev; 319e29a7d73f4277eb92aa64e17017dea33460828efPierre Ossman func->dev.bus = &sdio_bus_type; 320e29a7d73f4277eb92aa64e17017dea33460828efPierre Ossman func->dev.release = sdio_release_func; 321e29a7d73f4277eb92aa64e17017dea33460828efPierre Ossman 322e29a7d73f4277eb92aa64e17017dea33460828efPierre Ossman return func; 323e29a7d73f4277eb92aa64e17017dea33460828efPierre Ossman} 324e29a7d73f4277eb92aa64e17017dea33460828efPierre Ossman 325e29a7d73f4277eb92aa64e17017dea33460828efPierre Ossman/* 326e29a7d73f4277eb92aa64e17017dea33460828efPierre Ossman * Register a new SDIO function with the driver model. 327e29a7d73f4277eb92aa64e17017dea33460828efPierre Ossman */ 328e29a7d73f4277eb92aa64e17017dea33460828efPierre Ossmanint sdio_add_func(struct sdio_func *func) 329e29a7d73f4277eb92aa64e17017dea33460828efPierre Ossman{ 330e29a7d73f4277eb92aa64e17017dea33460828efPierre Ossman int ret; 331e29a7d73f4277eb92aa64e17017dea33460828efPierre Ossman 332d1b268630875a7713b5d468a0c03403c5b721c8eKay Sievers dev_set_name(&func->dev, "%s:%d", mmc_card_id(func->card), func->num); 333e29a7d73f4277eb92aa64e17017dea33460828efPierre Ossman 334e29a7d73f4277eb92aa64e17017dea33460828efPierre Ossman ret = device_add(&func->dev); 335e29a7d73f4277eb92aa64e17017dea33460828efPierre Ossman if (ret == 0) 336e29a7d73f4277eb92aa64e17017dea33460828efPierre Ossman sdio_func_set_present(func); 337e29a7d73f4277eb92aa64e17017dea33460828efPierre Ossman 338e29a7d73f4277eb92aa64e17017dea33460828efPierre Ossman return ret; 339e29a7d73f4277eb92aa64e17017dea33460828efPierre Ossman} 340e29a7d73f4277eb92aa64e17017dea33460828efPierre Ossman 341e29a7d73f4277eb92aa64e17017dea33460828efPierre Ossman/* 342e29a7d73f4277eb92aa64e17017dea33460828efPierre Ossman * Unregister a SDIO function with the driver model, and 343e29a7d73f4277eb92aa64e17017dea33460828efPierre Ossman * (eventually) free it. 3443d10a1ba0d37c8f5fd5afcdda00613fbb8a90bf5Daniel Drake * This function can be called through error paths where sdio_add_func() was 3453d10a1ba0d37c8f5fd5afcdda00613fbb8a90bf5Daniel Drake * never executed (because a failure occurred at an earlier point). 346e29a7d73f4277eb92aa64e17017dea33460828efPierre Ossman */ 347e29a7d73f4277eb92aa64e17017dea33460828efPierre Ossmanvoid sdio_remove_func(struct sdio_func *func) 348e29a7d73f4277eb92aa64e17017dea33460828efPierre Ossman{ 3493d10a1ba0d37c8f5fd5afcdda00613fbb8a90bf5Daniel Drake if (!sdio_func_present(func)) 3503d10a1ba0d37c8f5fd5afcdda00613fbb8a90bf5Daniel Drake return; 351e29a7d73f4277eb92aa64e17017dea33460828efPierre Ossman 3523d10a1ba0d37c8f5fd5afcdda00613fbb8a90bf5Daniel Drake device_del(&func->dev); 353e29a7d73f4277eb92aa64e17017dea33460828efPierre Ossman put_device(&func->dev); 354e29a7d73f4277eb92aa64e17017dea33460828efPierre Ossman} 355e29a7d73f4277eb92aa64e17017dea33460828efPierre Ossman 356