core.c 16.9 KB
Newer Older
Linus Torvalds's avatar
Linus Torvalds committed
1
/*
2
 *  linux/drivers/mmc/core/core.c
Linus Torvalds's avatar
Linus Torvalds committed
3
4
 *
 *  Copyright (C) 2003-2004 Russell King, All Rights Reserved.
5
 *  SD support Copyright (C) 2004 Ian Molton, All Rights Reserved.
6
 *  Copyright (C) 2005-2007 Pierre Ossman, All Rights Reserved.
7
 *  MMCv4 support Copyright (C) 2006 Philip Langdale, All Rights Reserved.
Linus Torvalds's avatar
Linus Torvalds committed
8
9
10
11
12
13
14
15
16
17
18
19
20
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License version 2 as
 * published by the Free Software Foundation.
 */
#include <linux/module.h>
#include <linux/init.h>
#include <linux/interrupt.h>
#include <linux/completion.h>
#include <linux/device.h>
#include <linux/delay.h>
#include <linux/pagemap.h>
#include <linux/err.h>
Pierre Ossman's avatar
Pierre Ossman committed
21
22
#include <asm/scatterlist.h>
#include <linux/scatterlist.h>
Linus Torvalds's avatar
Linus Torvalds committed
23
24
25

#include <linux/mmc/card.h>
#include <linux/mmc/host.h>
Pierre Ossman's avatar
Pierre Ossman committed
26
27
#include <linux/mmc/mmc.h>
#include <linux/mmc/sd.h>
Linus Torvalds's avatar
Linus Torvalds committed
28

29
#include "core.h"
30
31
#include "bus.h"
#include "host.h"
Pierre Ossman's avatar
Pierre Ossman committed
32
#include "sdio_bus.h"
Pierre Ossman's avatar
Pierre Ossman committed
33
34
35

#include "mmc_ops.h"
#include "sd_ops.h"
Pierre Ossman's avatar
Pierre Ossman committed
36
#include "sdio_ops.h"
Linus Torvalds's avatar
Linus Torvalds committed
37

Pierre Ossman's avatar
Pierre Ossman committed
38
39
extern int mmc_attach_mmc(struct mmc_host *host, u32 ocr);
extern int mmc_attach_sd(struct mmc_host *host, u32 ocr);
Pierre Ossman's avatar
Pierre Ossman committed
40
extern int mmc_attach_sdio(struct mmc_host *host, u32 ocr);
Linus Torvalds's avatar
Linus Torvalds committed
41

42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
static struct workqueue_struct *workqueue;

/*
 * Internal function. Schedule delayed work in the MMC work queue.
 */
static int mmc_schedule_delayed_work(struct delayed_work *work,
				     unsigned long delay)
{
	return queue_delayed_work(workqueue, work, delay);
}

/*
 * Internal function. Flush all scheduled work from the MMC work queue.
 */
static void mmc_flush_scheduled_work(void)
{
	flush_workqueue(workqueue);
}

Linus Torvalds's avatar
Linus Torvalds committed
61
/**
62
63
64
 *	mmc_request_done - finish processing an MMC request
 *	@host: MMC host which completed request
 *	@mrq: MMC request which request
Linus Torvalds's avatar
Linus Torvalds committed
65
66
 *
 *	MMC drivers should call this function when they have completed
67
 *	their processing of a request.
Linus Torvalds's avatar
Linus Torvalds committed
68
69
70
71
 */
void mmc_request_done(struct mmc_host *host, struct mmc_request *mrq)
{
	struct mmc_command *cmd = mrq->cmd;
72
73
	int err = cmd->error;

Linus Torvalds's avatar
Linus Torvalds committed
74
	if (err && cmd->retries) {
75
76
77
		pr_debug("%s: req failed (CMD%u): %d, retrying...\n",
			mmc_hostname(host), cmd->opcode, err);

Linus Torvalds's avatar
Linus Torvalds committed
78
79
80
		cmd->retries--;
		cmd->error = 0;
		host->ops->request(host, mrq);
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
	} else {
		pr_debug("%s: req done (CMD%u): %d: %08x %08x %08x %08x\n",
			mmc_hostname(host), cmd->opcode, err,
			cmd->resp[0], cmd->resp[1],
			cmd->resp[2], cmd->resp[3]);

		if (mrq->data) {
			pr_debug("%s:     %d bytes transferred: %d\n",
				mmc_hostname(host),
				mrq->data->bytes_xfered, mrq->data->error);
		}

		if (mrq->stop) {
			pr_debug("%s:     (CMD%u): %d: %08x %08x %08x %08x\n",
				mmc_hostname(host), mrq->stop->opcode,
				mrq->stop->error,
				mrq->stop->resp[0], mrq->stop->resp[1],
				mrq->stop->resp[2], mrq->stop->resp[3]);
		}

		if (mrq->done)
			mrq->done(mrq);
Linus Torvalds's avatar
Linus Torvalds committed
103
104
105
106
107
	}
}

EXPORT_SYMBOL(mmc_request_done);

108
static void
Linus Torvalds's avatar
Linus Torvalds committed
109
110
mmc_start_request(struct mmc_host *host, struct mmc_request *mrq)
{
Pierre Ossman's avatar
Pierre Ossman committed
111
112
113
114
#ifdef CONFIG_MMC_DEBUG
	unsigned int i, sz;
#endif

115
116
117
	pr_debug("%s: starting CMD%u arg %08x flags %08x\n",
		 mmc_hostname(host), mrq->cmd->opcode,
		 mrq->cmd->arg, mrq->cmd->flags);
Linus Torvalds's avatar
Linus Torvalds committed
118

119
120
121
122
123
	if (mrq->data) {
		pr_debug("%s:     blksz %d blocks %d flags %08x "
			"tsac %d ms nsac %d\n",
			mmc_hostname(host), mrq->data->blksz,
			mrq->data->blocks, mrq->data->flags,
124
			mrq->data->timeout_ns / 1000000,
125
126
127
128
129
130
131
132
133
			mrq->data->timeout_clks);
	}

	if (mrq->stop) {
		pr_debug("%s:     CMD%u arg %08x flags %08x\n",
			 mmc_hostname(host), mrq->stop->opcode,
			 mrq->stop->arg, mrq->stop->flags);
	}

Pierre Ossman's avatar
Pierre Ossman committed
134
	WARN_ON(!host->claimed);
Linus Torvalds's avatar
Linus Torvalds committed
135
136
137
138

	mrq->cmd->error = 0;
	mrq->cmd->mrq = mrq;
	if (mrq->data) {
139
		BUG_ON(mrq->data->blksz > host->max_blk_size);
140
141
142
		BUG_ON(mrq->data->blocks > host->max_blk_count);
		BUG_ON(mrq->data->blocks * mrq->data->blksz >
			host->max_req_size);
143

Pierre Ossman's avatar
Pierre Ossman committed
144
145
146
147
148
149
150
#ifdef CONFIG_MMC_DEBUG
		sz = 0;
		for (i = 0;i < mrq->data->sg_len;i++)
			sz += mrq->data->sg[i].length;
		BUG_ON(sz != mrq->data->blocks * mrq->data->blksz);
#endif

Linus Torvalds's avatar
Linus Torvalds committed
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
		mrq->cmd->data = mrq->data;
		mrq->data->error = 0;
		mrq->data->mrq = mrq;
		if (mrq->stop) {
			mrq->data->stop = mrq->stop;
			mrq->stop->error = 0;
			mrq->stop->mrq = mrq;
		}
	}
	host->ops->request(host, mrq);
}

static void mmc_wait_done(struct mmc_request *mrq)
{
	complete(mrq->done_data);
}

Pierre Ossman's avatar
Pierre Ossman committed
168
169
170
171
172
173
174
175
176
177
/**
 *	mmc_wait_for_req - start a request and wait for completion
 *	@host: MMC host to start command
 *	@mrq: MMC request to start
 *
 *	Start a new MMC custom command request for a host, and wait
 *	for the command to complete. Does not attempt to parse the
 *	response.
 */
void mmc_wait_for_req(struct mmc_host *host, struct mmc_request *mrq)
Linus Torvalds's avatar
Linus Torvalds committed
178
{
179
	DECLARE_COMPLETION_ONSTACK(complete);
Linus Torvalds's avatar
Linus Torvalds committed
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204

	mrq->done_data = &complete;
	mrq->done = mmc_wait_done;

	mmc_start_request(host, mrq);

	wait_for_completion(&complete);
}

EXPORT_SYMBOL(mmc_wait_for_req);

/**
 *	mmc_wait_for_cmd - start a command and wait for completion
 *	@host: MMC host to start command
 *	@cmd: MMC command to start
 *	@retries: maximum number of retries
 *
 *	Start a new MMC command for a host, and wait for the command
 *	to complete.  Return any error that occurred while the command
 *	was executing.  Do not attempt to parse the response.
 */
int mmc_wait_for_cmd(struct mmc_host *host, struct mmc_command *cmd, int retries)
{
	struct mmc_request mrq;

205
	WARN_ON(!host->claimed);
Linus Torvalds's avatar
Linus Torvalds committed
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221

	memset(&mrq, 0, sizeof(struct mmc_request));

	memset(cmd->resp, 0, sizeof(cmd->resp));
	cmd->retries = retries;

	mrq.cmd = cmd;
	cmd->data = NULL;

	mmc_wait_for_req(host, &mrq);

	return cmd->error;
}

EXPORT_SYMBOL(mmc_wait_for_cmd);

222
223
224
225
/**
 *	mmc_set_data_timeout - set the timeout for a data command
 *	@data: data phase for command
 *	@card: the MMC card associated with the data transfer
Pierre Ossman's avatar
Pierre Ossman committed
226
227
228
 *
 *	Computes the data timeout parameters according to the
 *	correct algorithm given the card type.
229
 */
230
void mmc_set_data_timeout(struct mmc_data *data, const struct mmc_card *card)
231
232
233
{
	unsigned int mult;

234
235
236
237
238
239
240
241
242
	/*
	 * SDIO cards only define an upper 1 s limit on access.
	 */
	if (mmc_card_sdio(card)) {
		data->timeout_ns = 1000000000;
		data->timeout_clks = 0;
		return;
	}

243
244
245
246
247
248
249
250
251
	/*
	 * SD cards use a 100 multiplier rather than 10
	 */
	mult = mmc_card_sd(card) ? 100 : 10;

	/*
	 * Scale up the multiplier (and therefore the timeout) by
	 * the r2w factor for writes.
	 */
252
	if (data->flags & MMC_DATA_WRITE)
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
		mult <<= card->csd.r2w_factor;

	data->timeout_ns = card->csd.tacc_ns * mult;
	data->timeout_clks = card->csd.tacc_clks * mult;

	/*
	 * SD cards also have an upper limit on the timeout.
	 */
	if (mmc_card_sd(card)) {
		unsigned int timeout_us, limit_us;

		timeout_us = data->timeout_ns / 1000;
		timeout_us += data->timeout_clks * 1000 /
			(card->host->ios.clock / 1000);

268
		if (data->flags & MMC_DATA_WRITE)
269
270
271
272
			limit_us = 250000;
		else
			limit_us = 100000;

273
274
275
276
		/*
		 * SDHC cards always use these fixed values.
		 */
		if (timeout_us > limit_us || mmc_card_blockaddr(card)) {
277
278
279
280
281
282
283
			data->timeout_ns = limit_us * 1000;
			data->timeout_clks = 0;
		}
	}
}
EXPORT_SYMBOL(mmc_set_data_timeout);

Linus Torvalds's avatar
Linus Torvalds committed
284
/**
285
 *	__mmc_claim_host - exclusively claim a host
Linus Torvalds's avatar
Linus Torvalds committed
286
 *	@host: mmc host to claim
287
 *	@abort: whether or not the operation should be aborted
Linus Torvalds's avatar
Linus Torvalds committed
288
 *
289
290
291
292
 *	Claim a host for a set of operations.  If @abort is non null and
 *	dereference a non-zero value then this will return prematurely with
 *	that non-zero value without acquiring the lock.  Returns zero
 *	with the lock held otherwise.
Linus Torvalds's avatar
Linus Torvalds committed
293
 */
294
int __mmc_claim_host(struct mmc_host *host, atomic_t *abort)
Linus Torvalds's avatar
Linus Torvalds committed
295
296
297
{
	DECLARE_WAITQUEUE(wait, current);
	unsigned long flags;
298
	int stop;
Linus Torvalds's avatar
Linus Torvalds committed
299

300
301
	might_sleep();

Linus Torvalds's avatar
Linus Torvalds committed
302
303
304
305
	add_wait_queue(&host->wq, &wait);
	spin_lock_irqsave(&host->lock, flags);
	while (1) {
		set_current_state(TASK_UNINTERRUPTIBLE);
306
307
		stop = abort ? atomic_read(abort) : 0;
		if (stop || !host->claimed)
Linus Torvalds's avatar
Linus Torvalds committed
308
309
310
311
312
313
			break;
		spin_unlock_irqrestore(&host->lock, flags);
		schedule();
		spin_lock_irqsave(&host->lock, flags);
	}
	set_current_state(TASK_RUNNING);
314
315
316
317
	if (!stop)
		host->claimed = 1;
	else
		wake_up(&host->wq);
Linus Torvalds's avatar
Linus Torvalds committed
318
319
	spin_unlock_irqrestore(&host->lock, flags);
	remove_wait_queue(&host->wq, &wait);
320
	return stop;
Linus Torvalds's avatar
Linus Torvalds committed
321
322
}

323
EXPORT_SYMBOL(__mmc_claim_host);
Linus Torvalds's avatar
Linus Torvalds committed
324
325
326
327
328
329
330
331
332
333
334
335

/**
 *	mmc_release_host - release a host
 *	@host: mmc host to release
 *
 *	Release a MMC host, allowing others to claim the host
 *	for their operations.
 */
void mmc_release_host(struct mmc_host *host)
{
	unsigned long flags;

336
	WARN_ON(!host->claimed);
Linus Torvalds's avatar
Linus Torvalds committed
337
338

	spin_lock_irqsave(&host->lock, flags);
Pierre Ossman's avatar
Pierre Ossman committed
339
	host->claimed = 0;
Linus Torvalds's avatar
Linus Torvalds committed
340
341
342
343
344
345
346
	spin_unlock_irqrestore(&host->lock, flags);

	wake_up(&host->wq);
}

EXPORT_SYMBOL(mmc_release_host);

Pierre Ossman's avatar
Pierre Ossman committed
347
348
349
350
/*
 * Internal function that does the actual ios call to the host driver,
 * optionally printing some debug output.
 */
351
352
353
354
static inline void mmc_set_ios(struct mmc_host *host)
{
	struct mmc_ios *ios = &host->ios;

355
356
	pr_debug("%s: clock %uHz busmode %u powermode %u cs %u Vdd %u "
		"width %u timing %u\n",
357
358
		 mmc_hostname(host), ios->clock, ios->bus_mode,
		 ios->power_mode, ios->chip_select, ios->vdd,
359
		 ios->bus_width, ios->timing);
360

361
362
363
	host->ops->set_ios(host, ios);
}

Pierre Ossman's avatar
Pierre Ossman committed
364
365
366
/*
 * Control chip select pin on a host.
 */
Pierre Ossman's avatar
Pierre Ossman committed
367
void mmc_set_chip_select(struct mmc_host *host, int mode)
Linus Torvalds's avatar
Linus Torvalds committed
368
{
Pierre Ossman's avatar
Pierre Ossman committed
369
370
	host->ios.chip_select = mode;
	mmc_set_ios(host);
Linus Torvalds's avatar
Linus Torvalds committed
371
372
}

Pierre Ossman's avatar
Pierre Ossman committed
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
/*
 * Sets the host clock to the highest possible frequency that
 * is below "hz".
 */
void mmc_set_clock(struct mmc_host *host, unsigned int hz)
{
	WARN_ON(hz < host->f_min);

	if (hz > host->f_max)
		hz = host->f_max;

	host->ios.clock = hz;
	mmc_set_ios(host);
}

/*
 * Change the bus mode (open drain/push-pull) of a host.
 */
void mmc_set_bus_mode(struct mmc_host *host, unsigned int mode)
{
	host->ios.bus_mode = mode;
	mmc_set_ios(host);
}

/*
 * Change data bus width of a host.
 */
void mmc_set_bus_width(struct mmc_host *host, unsigned int width)
{
	host->ios.bus_width = width;
	mmc_set_ios(host);
}

Linus Torvalds's avatar
Linus Torvalds committed
406
407
408
409
/*
 * Mask off any voltages we don't support and select
 * the lowest voltage
 */
Pierre Ossman's avatar
Pierre Ossman committed
410
u32 mmc_select_voltage(struct mmc_host *host, u32 ocr)
Linus Torvalds's avatar
Linus Torvalds committed
411
412
413
414
415
416
417
418
419
{
	int bit;

	ocr &= host->ocr_avail;

	bit = ffs(ocr);
	if (bit) {
		bit -= 1;

420
		ocr &= 3 << bit;
Linus Torvalds's avatar
Linus Torvalds committed
421
422

		host->ios.vdd = bit;
423
		mmc_set_ios(host);
Linus Torvalds's avatar
Linus Torvalds committed
424
425
426
427
428
429
430
	} else {
		ocr = 0;
	}

	return ocr;
}

Pierre Ossman's avatar
Pierre Ossman committed
431
/*
Pierre Ossman's avatar
Pierre Ossman committed
432
 * Select timing parameters for host.
Pierre Ossman's avatar
Pierre Ossman committed
433
 */
Pierre Ossman's avatar
Pierre Ossman committed
434
void mmc_set_timing(struct mmc_host *host, unsigned int timing)
Pierre Ossman's avatar
Pierre Ossman committed
435
{
Pierre Ossman's avatar
Pierre Ossman committed
436
437
	host->ios.timing = timing;
	mmc_set_ios(host);
Pierre Ossman's avatar
Pierre Ossman committed
438
439
}

Linus Torvalds's avatar
Linus Torvalds committed
440
/*
441
442
443
444
445
446
447
448
449
 * Apply power to the MMC stack.  This is a two-stage process.
 * First, we enable power to the card without the clock running.
 * We then wait a bit for the power to stabilise.  Finally,
 * enable the bus drivers and clock to the card.
 *
 * We must _NOT_ enable the clock prior to power stablising.
 *
 * If a host does all the power sequencing itself, ignore the
 * initial MMC_POWER_UP stage.
Linus Torvalds's avatar
Linus Torvalds committed
450
451
452
453
454
455
456
 */
static void mmc_power_up(struct mmc_host *host)
{
	int bit = fls(host->ocr_avail) - 1;

	host->ios.vdd = bit;
	host->ios.bus_mode = MMC_BUSMODE_OPENDRAIN;
Pierre Ossman's avatar
Pierre Ossman committed
457
	host->ios.chip_select = MMC_CS_DONTCARE;
Linus Torvalds's avatar
Linus Torvalds committed
458
	host->ios.power_mode = MMC_POWER_UP;
Pierre Ossman's avatar
Pierre Ossman committed
459
	host->ios.bus_width = MMC_BUS_WIDTH_1;
460
	host->ios.timing = MMC_TIMING_LEGACY;
461
	mmc_set_ios(host);
Linus Torvalds's avatar
Linus Torvalds committed
462
463
464
465
466

	mmc_delay(1);

	host->ios.clock = host->f_min;
	host->ios.power_mode = MMC_POWER_ON;
467
	mmc_set_ios(host);
Linus Torvalds's avatar
Linus Torvalds committed
468
469
470
471
472
473
474
475
476

	mmc_delay(2);
}

static void mmc_power_off(struct mmc_host *host)
{
	host->ios.clock = 0;
	host->ios.vdd = 0;
	host->ios.bus_mode = MMC_BUSMODE_OPENDRAIN;
Pierre Ossman's avatar
Pierre Ossman committed
477
	host->ios.chip_select = MMC_CS_DONTCARE;
Linus Torvalds's avatar
Linus Torvalds committed
478
	host->ios.power_mode = MMC_POWER_OFF;
Pierre Ossman's avatar
Pierre Ossman committed
479
	host->ios.bus_width = MMC_BUS_WIDTH_1;
480
	host->ios.timing = MMC_TIMING_LEGACY;
481
	mmc_set_ios(host);
Linus Torvalds's avatar
Linus Torvalds committed
482
483
}

484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
/*
 * Cleanup when the last reference to the bus operator is dropped.
 */
void __mmc_release_bus(struct mmc_host *host)
{
	BUG_ON(!host);
	BUG_ON(host->bus_refs);
	BUG_ON(!host->bus_dead);

	host->bus_ops = NULL;
}

/*
 * Increase reference count of bus operator
 */
static inline void mmc_bus_get(struct mmc_host *host)
{
	unsigned long flags;

	spin_lock_irqsave(&host->lock, flags);
	host->bus_refs++;
	spin_unlock_irqrestore(&host->lock, flags);
}

/*
 * Decrease reference count of bus operator and free it if
 * it is the last reference.
 */
static inline void mmc_bus_put(struct mmc_host *host)
{
	unsigned long flags;

	spin_lock_irqsave(&host->lock, flags);
	host->bus_refs--;
	if ((host->bus_refs == 0) && host->bus_ops)
		__mmc_release_bus(host);
	spin_unlock_irqrestore(&host->lock, flags);
}

Linus Torvalds's avatar
Linus Torvalds committed
523
/*
Pierre Ossman's avatar
Pierre Ossman committed
524
525
 * Assign a mmc bus handler to a host. Only one bus handler may control a
 * host at any given time.
Linus Torvalds's avatar
Linus Torvalds committed
526
 */
Pierre Ossman's avatar
Pierre Ossman committed
527
void mmc_attach_bus(struct mmc_host *host, const struct mmc_bus_ops *ops)
Linus Torvalds's avatar
Linus Torvalds committed
528
{
Pierre Ossman's avatar
Pierre Ossman committed
529
	unsigned long flags;
530

Pierre Ossman's avatar
Pierre Ossman committed
531
532
	BUG_ON(!host);
	BUG_ON(!ops);
533

534
	WARN_ON(!host->claimed);
535

Pierre Ossman's avatar
Pierre Ossman committed
536
	spin_lock_irqsave(&host->lock, flags);
537

Pierre Ossman's avatar
Pierre Ossman committed
538
539
	BUG_ON(host->bus_ops);
	BUG_ON(host->bus_refs);
Pierre Ossman's avatar
Pierre Ossman committed
540

Pierre Ossman's avatar
Pierre Ossman committed
541
542
543
	host->bus_ops = ops;
	host->bus_refs = 1;
	host->bus_dead = 0;
Pierre Ossman's avatar
Pierre Ossman committed
544

Pierre Ossman's avatar
Pierre Ossman committed
545
	spin_unlock_irqrestore(&host->lock, flags);
Pierre Ossman's avatar
Pierre Ossman committed
546
547
}

Pierre Ossman's avatar
Pierre Ossman committed
548
549
550
551
552
/*
 * Remove the current bus handler from a host. Assumes that there are
 * no interesting cards left, so the bus is powered down.
 */
void mmc_detach_bus(struct mmc_host *host)
553
{
Pierre Ossman's avatar
Pierre Ossman committed
554
	unsigned long flags;
555

Pierre Ossman's avatar
Pierre Ossman committed
556
	BUG_ON(!host);
557

558
559
	WARN_ON(!host->claimed);
	WARN_ON(!host->bus_ops);
560

Pierre Ossman's avatar
Pierre Ossman committed
561
	spin_lock_irqsave(&host->lock, flags);
562

Pierre Ossman's avatar
Pierre Ossman committed
563
	host->bus_dead = 1;
564

Pierre Ossman's avatar
Pierre Ossman committed
565
	spin_unlock_irqrestore(&host->lock, flags);
Linus Torvalds's avatar
Linus Torvalds committed
566

Pierre Ossman's avatar
Pierre Ossman committed
567
	mmc_power_off(host);
Linus Torvalds's avatar
Linus Torvalds committed
568

Pierre Ossman's avatar
Pierre Ossman committed
569
	mmc_bus_put(host);
Linus Torvalds's avatar
Linus Torvalds committed
570
571
572
573
574
}

/**
 *	mmc_detect_change - process change of state on a MMC socket
 *	@host: host which changed state.
575
 *	@delay: optional delay to wait before detection (jiffies)
Linus Torvalds's avatar
Linus Torvalds committed
576
 *
Pierre Ossman's avatar
Pierre Ossman committed
577
578
579
580
 *	MMC drivers should call this when they detect a card has been
 *	inserted or removed. The MMC layer will confirm that any
 *	present card is still functional, and initialize any newly
 *	inserted.
Linus Torvalds's avatar
Linus Torvalds committed
581
 */
582
void mmc_detect_change(struct mmc_host *host, unsigned long delay)
Linus Torvalds's avatar
Linus Torvalds committed
583
{
584
#ifdef CONFIG_MMC_DEBUG
585
	unsigned long flags;
Andrew Morton's avatar
Andrew Morton committed
586
	spin_lock_irqsave(&host->lock, flags);
587
	WARN_ON(host->removed);
Andrew Morton's avatar
Andrew Morton committed
588
	spin_unlock_irqrestore(&host->lock, flags);
589
590
#endif

David Howells's avatar
David Howells committed
591
	mmc_schedule_delayed_work(&host->detect, delay);
Linus Torvalds's avatar
Linus Torvalds committed
592
593
594
595
596
}

EXPORT_SYMBOL(mmc_detect_change);


597
void mmc_rescan(struct work_struct *work)
Linus Torvalds's avatar
Linus Torvalds committed
598
{
David Howells's avatar
David Howells committed
599
600
	struct mmc_host *host =
		container_of(work, struct mmc_host, detect.work);
Pierre Ossman's avatar
Pierre Ossman committed
601
602
	u32 ocr;
	int err;
Linus Torvalds's avatar
Linus Torvalds committed
603

Pierre Ossman's avatar
Pierre Ossman committed
604
	mmc_bus_get(host);
605

Pierre Ossman's avatar
Pierre Ossman committed
606
	if (host->bus_ops == NULL) {
Linus Torvalds's avatar
Linus Torvalds committed
607
		/*
Pierre Ossman's avatar
Pierre Ossman committed
608
609
		 * Only we can add a new handler, so it's safe to
		 * release the lock here.
Linus Torvalds's avatar
Linus Torvalds committed
610
		 */
Pierre Ossman's avatar
Pierre Ossman committed
611
		mmc_bus_put(host);
Linus Torvalds's avatar
Linus Torvalds committed
612

Pierre Ossman's avatar
Pierre Ossman committed
613
		mmc_claim_host(host);
Linus Torvalds's avatar
Linus Torvalds committed
614

Pierre Ossman's avatar
Pierre Ossman committed
615
616
		mmc_power_up(host);
		mmc_go_idle(host);
Linus Torvalds's avatar
Linus Torvalds committed
617

Pierre Ossman's avatar
Pierre Ossman committed
618
		mmc_send_if_cond(host, host->ocr_avail);
Linus Torvalds's avatar
Linus Torvalds committed
619

Pierre Ossman's avatar
Pierre Ossman committed
620
621
622
623
624
625
626
627
628
629
630
631
632
		/*
		 * First we search for SDIO...
		 */
		err = mmc_send_io_op_cond(host, 0, &ocr);
		if (!err) {
			if (mmc_attach_sdio(host, ocr))
				mmc_power_off(host);
			return;
		}

		/*
		 * ...then normal SD...
		 */
Pierre Ossman's avatar
Pierre Ossman committed
633
		err = mmc_send_app_op_cond(host, 0, &ocr);
Pierre Ossman's avatar
Pierre Ossman committed
634
		if (!err) {
Pierre Ossman's avatar
Pierre Ossman committed
635
636
			if (mmc_attach_sd(host, ocr))
				mmc_power_off(host);
Pierre Ossman's avatar
Pierre Ossman committed
637
638
639
640
641
642
643
644
645
			return;
		}

		/*
		 * ...and finally MMC.
		 */
		err = mmc_send_op_cond(host, 0, &ocr);
		if (!err) {
			if (mmc_attach_mmc(host, ocr))
Pierre Ossman's avatar
Pierre Ossman committed
646
				mmc_power_off(host);
Pierre Ossman's avatar
Pierre Ossman committed
647
			return;
Pierre Ossman's avatar
Pierre Ossman committed
648
		}
Pierre Ossman's avatar
Pierre Ossman committed
649
650
651

		mmc_release_host(host);
		mmc_power_off(host);
Pierre Ossman's avatar
Pierre Ossman committed
652
653
654
655
656
657
	} else {
		if (host->bus_ops->detect && !host->bus_dead)
			host->bus_ops->detect(host);

		mmc_bus_put(host);
	}
Linus Torvalds's avatar
Linus Torvalds committed
658
659
}

660
void mmc_start_host(struct mmc_host *host)
Linus Torvalds's avatar
Linus Torvalds committed
661
{
662
663
	mmc_power_off(host);
	mmc_detect_change(host, 0);
Linus Torvalds's avatar
Linus Torvalds committed
664
665
}

666
void mmc_stop_host(struct mmc_host *host)
Linus Torvalds's avatar
Linus Torvalds committed
667
{
668
#ifdef CONFIG_MMC_DEBUG
669
670
	unsigned long flags;
	spin_lock_irqsave(&host->lock, flags);
671
	host->removed = 1;
672
	spin_unlock_irqrestore(&host->lock, flags);
673
674
675
676
#endif

	mmc_flush_scheduled_work();

Pierre Ossman's avatar
Pierre Ossman committed
677
678
679
680
681
682
683
684
	mmc_bus_get(host);
	if (host->bus_ops && !host->bus_dead) {
		if (host->bus_ops->remove)
			host->bus_ops->remove(host);

		mmc_claim_host(host);
		mmc_detach_bus(host);
		mmc_release_host(host);
Linus Torvalds's avatar
Linus Torvalds committed
685
	}
Pierre Ossman's avatar
Pierre Ossman committed
686
687
688
	mmc_bus_put(host);

	BUG_ON(host->card);
Linus Torvalds's avatar
Linus Torvalds committed
689
690
691
692
693
694
695
696
697
698
699

	mmc_power_off(host);
}

#ifdef CONFIG_PM

/**
 *	mmc_suspend_host - suspend a host
 *	@host: mmc host
 *	@state: suspend mode (PM_SUSPEND_xxx)
 */
700
int mmc_suspend_host(struct mmc_host *host, pm_message_t state)
Linus Torvalds's avatar
Linus Torvalds committed
701
{
Pierre Ossman's avatar
Pierre Ossman committed
702
703
	mmc_flush_scheduled_work();

Pierre Ossman's avatar
Pierre Ossman committed
704
705
	mmc_bus_get(host);
	if (host->bus_ops && !host->bus_dead) {
706
707
708
709
710
711
712
713
714
715
		if (host->bus_ops->suspend)
			host->bus_ops->suspend(host);
		if (!host->bus_ops->resume) {
			if (host->bus_ops->remove)
				host->bus_ops->remove(host);

			mmc_claim_host(host);
			mmc_detach_bus(host);
			mmc_release_host(host);
		}
Pierre Ossman's avatar
Pierre Ossman committed
716
	}
Pierre Ossman's avatar
Pierre Ossman committed
717
718
	mmc_bus_put(host);

Linus Torvalds's avatar
Linus Torvalds committed
719
720
721
722
723
724
725
726
727
728
729
730
731
	mmc_power_off(host);

	return 0;
}

EXPORT_SYMBOL(mmc_suspend_host);

/**
 *	mmc_resume_host - resume a previously suspended host
 *	@host: mmc host
 */
int mmc_resume_host(struct mmc_host *host)
{
732
733
734
735
736
737
738
739
740
741
742
743
744
	mmc_bus_get(host);
	if (host->bus_ops && !host->bus_dead) {
		mmc_power_up(host);
		BUG_ON(!host->bus_ops->resume);
		host->bus_ops->resume(host);
	}
	mmc_bus_put(host);

	/*
	 * We add a slight delay here so that resume can progress
	 * in parallel.
	 */
	mmc_detect_change(host, 1);
Linus Torvalds's avatar
Linus Torvalds committed
745
746
747
748
749
750
751
752

	return 0;
}

EXPORT_SYMBOL(mmc_resume_host);

#endif

753
754
755
756
757
758
759
760
761
static int __init mmc_init(void)
{
	int ret;

	workqueue = create_singlethread_workqueue("kmmcd");
	if (!workqueue)
		return -ENOMEM;

	ret = mmc_register_bus();
Pierre Ossman's avatar
Pierre Ossman committed
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
	if (ret)
		goto destroy_workqueue;

	ret = mmc_register_host_class();
	if (ret)
		goto unregister_bus;

	ret = sdio_register_bus();
	if (ret)
		goto unregister_host_class;

	return 0;

unregister_host_class:
	mmc_unregister_host_class();
unregister_bus:
	mmc_unregister_bus();
destroy_workqueue:
	destroy_workqueue(workqueue);

782
783
784
785
786
	return ret;
}

static void __exit mmc_exit(void)
{
Pierre Ossman's avatar
Pierre Ossman committed
787
	sdio_unregister_bus();
788
789
790
791
792
	mmc_unregister_host_class();
	mmc_unregister_bus();
	destroy_workqueue(workqueue);
}

793
subsys_initcall(mmc_init);
794
795
module_exit(mmc_exit);

Linus Torvalds's avatar
Linus Torvalds committed
796
MODULE_LICENSE("GPL");