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