sdio_bus.c 7.9 KB
Newer Older
P
Pierre Ossman 已提交
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
/*
 *  linux/drivers/mmc/core/sdio_bus.c
 *
 *  Copyright 2007 Pierre Ossman
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or (at
 * your option) any later version.
 *
 * SDIO function driver model
 */

#include <linux/device.h>
#include <linux/err.h>
16
#include <linux/export.h>
17
#include <linux/slab.h>
18
#include <linux/pm_runtime.h>
19
#include <linux/pm_domain.h>
20
#include <linux/acpi.h>
P
Pierre Ossman 已提交
21 22

#include <linux/mmc/card.h>
23
#include <linux/mmc/host.h>
P
Pierre Ossman 已提交
24
#include <linux/mmc/sdio_func.h>
25
#include <linux/of.h>
P
Pierre Ossman 已提交
26

27
#include "core.h"
28
#include "sdio_cis.h"
P
Pierre Ossman 已提交
29 30
#include "sdio_bus.h"

31 32
#define to_sdio_driver(d)	container_of(d, struct sdio_driver, drv)

P
Pierre Ossman 已提交
33 34 35 36 37 38 39 40 41
/* show configuration fields */
#define sdio_config_attr(field, format_string)				\
static ssize_t								\
field##_show(struct device *dev, struct device_attribute *attr, char *buf)				\
{									\
	struct sdio_func *func;						\
									\
	func = dev_to_sdio_func (dev);					\
	return sprintf (buf, format_string, func->field);		\
42 43
}									\
static DEVICE_ATTR_RO(field)
P
Pierre Ossman 已提交
44 45 46 47 48 49 50 51 52 53 54 55

sdio_config_attr(class, "0x%02x\n");
sdio_config_attr(vendor, "0x%04x\n");
sdio_config_attr(device, "0x%04x\n");

static ssize_t modalias_show(struct device *dev, struct device_attribute *attr, char *buf)
{
	struct sdio_func *func = dev_to_sdio_func (dev);

	return sprintf(buf, "sdio:c%02Xv%04Xd%04X\n",
			func->class, func->vendor, func->device);
}
56 57 58 59 60 61 62 63
static DEVICE_ATTR_RO(modalias);

static struct attribute *sdio_dev_attrs[] = {
	&dev_attr_class.attr,
	&dev_attr_vendor.attr,
	&dev_attr_device.attr,
	&dev_attr_modalias.attr,
	NULL,
P
Pierre Ossman 已提交
64
};
65
ATTRIBUTE_GROUPS(sdio_dev);
P
Pierre Ossman 已提交
66

67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95
static const struct sdio_device_id *sdio_match_one(struct sdio_func *func,
	const struct sdio_device_id *id)
{
	if (id->class != (__u8)SDIO_ANY_ID && id->class != func->class)
		return NULL;
	if (id->vendor != (__u16)SDIO_ANY_ID && id->vendor != func->vendor)
		return NULL;
	if (id->device != (__u16)SDIO_ANY_ID && id->device != func->device)
		return NULL;
	return id;
}

static const struct sdio_device_id *sdio_match_device(struct sdio_func *func,
	struct sdio_driver *sdrv)
{
	const struct sdio_device_id *ids;

	ids = sdrv->id_table;

	if (ids) {
		while (ids->class || ids->vendor || ids->device) {
			if (sdio_match_one(func, ids))
				return ids;
			ids++;
		}
	}

	return NULL;
}
P
Pierre Ossman 已提交
96 97 98

static int sdio_bus_match(struct device *dev, struct device_driver *drv)
{
99 100 101 102 103 104 105
	struct sdio_func *func = dev_to_sdio_func(dev);
	struct sdio_driver *sdrv = to_sdio_driver(drv);

	if (sdio_match_device(func, sdrv))
		return 1;

	return 0;
P
Pierre Ossman 已提交
106 107 108
}

static int
A
Al Viro 已提交
109
sdio_bus_uevent(struct device *dev, struct kobj_uevent_env *env)
P
Pierre Ossman 已提交
110
{
P
Pierre Ossman 已提交
111 112
	struct sdio_func *func = dev_to_sdio_func(dev);

A
Al Viro 已提交
113
	if (add_uevent_var(env,
P
Pierre Ossman 已提交
114 115 116
			"SDIO_CLASS=%02X", func->class))
		return -ENOMEM;

A
Al Viro 已提交
117
	if (add_uevent_var(env, 
P
Pierre Ossman 已提交
118 119 120
			"SDIO_ID=%04X:%04X", func->vendor, func->device))
		return -ENOMEM;

A
Al Viro 已提交
121
	if (add_uevent_var(env,
P
Pierre Ossman 已提交
122 123 124 125
			"MODALIAS=sdio:c%02Xv%04Xd%04X",
			func->class, func->vendor, func->device))
		return -ENOMEM;

P
Pierre Ossman 已提交
126 127 128 129 130
	return 0;
}

static int sdio_bus_probe(struct device *dev)
{
131 132 133
	struct sdio_driver *drv = to_sdio_driver(dev->driver);
	struct sdio_func *func = dev_to_sdio_func(dev);
	const struct sdio_device_id *id;
134
	int ret;
135 136 137 138 139

	id = sdio_match_device(func, drv);
	if (!id)
		return -ENODEV;

140 141 142 143 144 145
	/* Unbound SDIO functions are always suspended.
	 * During probe, the function is set active and the usage count
	 * is incremented.  If the driver supports runtime PM,
	 * it should call pm_runtime_put_noidle() in its probe routine and
	 * pm_runtime_get_noresume() in its remove routine.
	 */
146 147 148
	if (func->card->host->caps & MMC_CAP_POWER_OFF_CARD) {
		ret = pm_runtime_get_sync(dev);
		if (ret < 0)
149
			goto disable_runtimepm;
150
	}
151

152 153 154 155 156 157
	/* Set the default block size so the driver is sure it's something
	 * sensible. */
	sdio_claim_host(func);
	ret = sdio_set_block_size(func, 0);
	sdio_release_host(func);
	if (ret)
158 159 160 161 162 163 164
		goto disable_runtimepm;

	ret = drv->probe(func, id);
	if (ret)
		goto disable_runtimepm;

	return 0;
165

166
disable_runtimepm:
167 168
	if (func->card->host->caps & MMC_CAP_POWER_OFF_CARD)
		pm_runtime_put_noidle(dev);
169
	return ret;
P
Pierre Ossman 已提交
170 171 172 173
}

static int sdio_bus_remove(struct device *dev)
{
174 175
	struct sdio_driver *drv = to_sdio_driver(dev->driver);
	struct sdio_func *func = dev_to_sdio_func(dev);
176
	int ret = 0;
177 178

	/* Make sure card is powered before invoking ->remove() */
179 180
	if (func->card->host->caps & MMC_CAP_POWER_OFF_CARD)
		pm_runtime_get_sync(dev);
181 182 183

	drv->remove(func);

184
	if (func->irq_handler) {
J
Joe Perches 已提交
185 186
		pr_warn("WARNING: driver %s did not remove its interrupt handler!\n",
			drv->name);
187 188 189 190 191
		sdio_claim_host(func);
		sdio_release_irq(func);
		sdio_release_host(func);
	}

192
	/* First, undo the increment made directly above */
193 194
	if (func->card->host->caps & MMC_CAP_POWER_OFF_CARD)
		pm_runtime_put_noidle(dev);
195 196

	/* Then undo the runtime PM settings in sdio_bus_probe() */
197
	if (func->card->host->caps & MMC_CAP_POWER_OFF_CARD)
198
		pm_runtime_put_sync(dev);
199 200

	return ret;
P
Pierre Ossman 已提交
201 202
}

203
static const struct dev_pm_ops sdio_bus_pm_ops = {
204
	SET_SYSTEM_SLEEP_PM_OPS(pm_generic_suspend, pm_generic_resume)
205 206 207
	SET_RUNTIME_PM_OPS(
		pm_generic_runtime_suspend,
		pm_generic_runtime_resume,
208
		NULL
209 210 211
	)
};

P
Pierre Ossman 已提交
212 213
static struct bus_type sdio_bus_type = {
	.name		= "sdio",
214
	.dev_groups	= sdio_dev_groups,
P
Pierre Ossman 已提交
215 216 217 218
	.match		= sdio_bus_match,
	.uevent		= sdio_bus_uevent,
	.probe		= sdio_bus_probe,
	.remove		= sdio_bus_remove,
219
	.pm		= &sdio_bus_pm_ops,
P
Pierre Ossman 已提交
220 221 222 223 224 225 226 227 228 229 230 231
};

int sdio_register_bus(void)
{
	return bus_register(&sdio_bus_type);
}

void sdio_unregister_bus(void)
{
	bus_unregister(&sdio_bus_type);
}

P
Pierre Ossman 已提交
232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254
/**
 *	sdio_register_driver - register a function driver
 *	@drv: SDIO function driver
 */
int sdio_register_driver(struct sdio_driver *drv)
{
	drv->drv.name = drv->name;
	drv->drv.bus = &sdio_bus_type;
	return driver_register(&drv->drv);
}
EXPORT_SYMBOL_GPL(sdio_register_driver);

/**
 *	sdio_unregister_driver - unregister a function driver
 *	@drv: SDIO function driver
 */
void sdio_unregister_driver(struct sdio_driver *drv)
{
	drv->drv.bus = &sdio_bus_type;
	driver_unregister(&drv->drv);
}
EXPORT_SYMBOL_GPL(sdio_unregister_driver);

P
Pierre Ossman 已提交
255 256 257
static void sdio_release_func(struct device *dev)
{
	struct sdio_func *func = dev_to_sdio_func(dev);
258

259
	sdio_free_func_cis(func);
P
Pierre Ossman 已提交
260

261
	kfree(func->info);
P
Pierre Ossman 已提交
262

P
Pierre Ossman 已提交
263 264 265 266 267 268 269 270 271 272
	kfree(func);
}

/*
 * Allocate and initialise a new SDIO function structure.
 */
struct sdio_func *sdio_alloc_func(struct mmc_card *card)
{
	struct sdio_func *func;

273
	func = kzalloc(sizeof(struct sdio_func), GFP_KERNEL);
P
Pierre Ossman 已提交
274 275 276 277 278 279 280 281 282 283 284 285 286 287
	if (!func)
		return ERR_PTR(-ENOMEM);

	func->card = card;

	device_initialize(&func->dev);

	func->dev.parent = &card->dev;
	func->dev.bus = &sdio_bus_type;
	func->dev.release = sdio_release_func;

	return func;
}

288 289 290 291
#ifdef CONFIG_ACPI
static void sdio_acpi_set_handle(struct sdio_func *func)
{
	struct mmc_host *host = func->card->host;
292
	u64 addr = ((u64)host->slotno << 16) | func->num;
293

294
	acpi_preset_companion(&func->dev, ACPI_COMPANION(host->parent), addr);
295 296 297 298 299
}
#else
static inline void sdio_acpi_set_handle(struct sdio_func *func) {}
#endif

300 301 302 303 304 305 306
static void sdio_set_of_node(struct sdio_func *func)
{
	struct mmc_host *host = func->card->host;

	func->dev.of_node = mmc_of_find_child_device(host, func->num);
}

P
Pierre Ossman 已提交
307 308 309 310 311 312 313
/*
 * Register a new SDIO function with the driver model.
 */
int sdio_add_func(struct sdio_func *func)
{
	int ret;

314
	dev_set_name(&func->dev, "%s:%d", mmc_card_id(func->card), func->num);
P
Pierre Ossman 已提交
315

316
	sdio_set_of_node(func);
317
	sdio_acpi_set_handle(func);
P
Pierre Ossman 已提交
318
	ret = device_add(&func->dev);
319
	if (ret == 0) {
P
Pierre Ossman 已提交
320
		sdio_func_set_present(func);
321
		dev_pm_domain_attach(&func->dev, false);
322
	}
P
Pierre Ossman 已提交
323 324 325 326 327 328 329

	return ret;
}

/*
 * Unregister a SDIO function with the driver model, and
 * (eventually) free it.
330 331
 * This function can be called through error paths where sdio_add_func() was
 * never executed (because a failure occurred at an earlier point).
P
Pierre Ossman 已提交
332 333 334
 */
void sdio_remove_func(struct sdio_func *func)
{
335 336
	if (!sdio_func_present(func))
		return;
P
Pierre Ossman 已提交
337

338
	dev_pm_domain_detach(&func->dev, false);
339
	device_del(&func->dev);
340
	of_node_put(func->dev.of_node);
P
Pierre Ossman 已提交
341 342 343
	put_device(&func->dev);
}