wbsd.c 40.6 KB
Newer Older
L
Linus Torvalds 已提交
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28
/*
 *  linux/drivers/mmc/wbsd.c - Winbond W83L51xD SD/MMC driver
 *
 *  Copyright (C) 2004-2005 Pierre Ossman, All Rights Reserved.
 *
 * 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.
 *
 *
 * Warning!
 *
 * Changes to the FIFO system should be done with extreme care since
 * the hardware is full of bugs related to the FIFO. Known issues are:
 *
 * - FIFO size field in FSR is always zero.
 *
 * - FIFO interrupts tend not to work as they should. Interrupts are
 *   triggered only for full/empty events, not for threshold values.
 *
 * - On APIC systems the FIFO empty interrupt is sometimes lost.
 */

#include <linux/config.h>
#include <linux/module.h>
#include <linux/moduleparam.h>
#include <linux/init.h>
#include <linux/ioport.h>
29
#include <linux/platform_device.h>
L
Linus Torvalds 已提交
30
#include <linux/interrupt.h>
P
Pierre Ossman 已提交
31
#include <linux/dma-mapping.h>
L
Linus Torvalds 已提交
32
#include <linux/delay.h>
P
Pierre Ossman 已提交
33
#include <linux/pnp.h>
L
Linus Torvalds 已提交
34 35 36 37 38 39 40 41 42 43 44
#include <linux/highmem.h>
#include <linux/mmc/host.h>
#include <linux/mmc/protocol.h>

#include <asm/io.h>
#include <asm/dma.h>
#include <asm/scatterlist.h>

#include "wbsd.h"

#define DRIVER_NAME "wbsd"
45
#define DRIVER_VERSION "1.4"
L
Linus Torvalds 已提交
46 47 48 49 50 51 52 53 54 55 56

#ifdef CONFIG_MMC_DEBUG
#define DBG(x...) \
	printk(KERN_DEBUG DRIVER_NAME ": " x)
#define DBGF(f, x...) \
	printk(KERN_DEBUG DRIVER_NAME " [%s()]: " f, __func__ , ##x)
#else
#define DBG(x...)	do { } while (0)
#define DBGF(x...)	do { } while (0)
#endif

P
Pierre Ossman 已提交
57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72
/*
 * Device resources
 */

#ifdef CONFIG_PNP

static const struct pnp_device_id pnp_dev_table[] = {
	{ "WEC0517", 0 },
	{ "WEC0518", 0 },
	{ "", 0 },
};

MODULE_DEVICE_TABLE(pnp, pnp_dev_table);

#endif /* CONFIG_PNP */

A
Adrian Bunk 已提交
73 74 75 76 77 78 79
static const int config_ports[] = { 0x2E, 0x4E };
static const int unlock_codes[] = { 0x83, 0x87 };

static const int valid_ids[] = {
	0x7112,
	};

P
Pierre Ossman 已提交
80 81 82 83 84 85 86 87 88
#ifdef CONFIG_PNP
static unsigned int nopnp = 0;
#else
static const unsigned int nopnp = 1;
#endif
static unsigned int io = 0x248;
static unsigned int irq = 6;
static int dma = 2;

L
Linus Torvalds 已提交
89 90 91 92 93 94
/*
 * Basic functions
 */

static inline void wbsd_unlock_config(struct wbsd_host* host)
{
P
Pierre Ossman 已提交
95
	BUG_ON(host->config == 0);
96

L
Linus Torvalds 已提交
97 98 99 100 101 102
	outb(host->unlock_code, host->config);
	outb(host->unlock_code, host->config);
}

static inline void wbsd_lock_config(struct wbsd_host* host)
{
P
Pierre Ossman 已提交
103
	BUG_ON(host->config == 0);
104

L
Linus Torvalds 已提交
105 106 107 108 109
	outb(LOCK_CODE, host->config);
}

static inline void wbsd_write_config(struct wbsd_host* host, u8 reg, u8 value)
{
P
Pierre Ossman 已提交
110
	BUG_ON(host->config == 0);
111

L
Linus Torvalds 已提交
112 113 114 115 116 117
	outb(reg, host->config);
	outb(value, host->config + 1);
}

static inline u8 wbsd_read_config(struct wbsd_host* host, u8 reg)
{
P
Pierre Ossman 已提交
118
	BUG_ON(host->config == 0);
119

L
Linus Torvalds 已提交
120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142
	outb(reg, host->config);
	return inb(host->config + 1);
}

static inline void wbsd_write_index(struct wbsd_host* host, u8 index, u8 value)
{
	outb(index, host->base + WBSD_IDXR);
	outb(value, host->base + WBSD_DATAR);
}

static inline u8 wbsd_read_index(struct wbsd_host* host, u8 index)
{
	outb(index, host->base + WBSD_IDXR);
	return inb(host->base + WBSD_DATAR);
}

/*
 * Common routines
 */

static void wbsd_init_device(struct wbsd_host* host)
{
	u8 setup, ier;
143

L
Linus Torvalds 已提交
144 145 146 147 148 149
	/*
	 * Reset chip (SD/MMC part) and fifo.
	 */
	setup = wbsd_read_index(host, WBSD_IDX_SETUP);
	setup |= WBSD_FIFO_RESET | WBSD_SOFT_RESET;
	wbsd_write_index(host, WBSD_IDX_SETUP, setup);
150

P
Pierre Ossman 已提交
151 152 153 154 155 156
	/*
	 * Set DAT3 to input
	 */
	setup &= ~WBSD_DAT3_H;
	wbsd_write_index(host, WBSD_IDX_SETUP, setup);
	host->flags &= ~WBSD_FIGNORE_DETECT;
157

L
Linus Torvalds 已提交
158 159 160 161 162 163 164 165 166
	/*
	 * Read back default clock.
	 */
	host->clk = wbsd_read_index(host, WBSD_IDX_CLK);

	/*
	 * Power down port.
	 */
	outb(WBSD_POWER_N, host->base + WBSD_CSR);
167

L
Linus Torvalds 已提交
168 169 170 171
	/*
	 * Set maximum timeout.
	 */
	wbsd_write_index(host, WBSD_IDX_TAAC, 0x7F);
172

P
Pierre Ossman 已提交
173 174 175 176 177 178 179
	/*
	 * Test for card presence
	 */
	if (inb(host->base + WBSD_CSR) & WBSD_CARDPRESENT)
		host->flags |= WBSD_FCARD_PRESENT;
	else
		host->flags &= ~WBSD_FCARD_PRESENT;
180

L
Linus Torvalds 已提交
181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202
	/*
	 * Enable interesting interrupts.
	 */
	ier = 0;
	ier |= WBSD_EINT_CARD;
	ier |= WBSD_EINT_FIFO_THRE;
	ier |= WBSD_EINT_CCRC;
	ier |= WBSD_EINT_TIMEOUT;
	ier |= WBSD_EINT_CRC;
	ier |= WBSD_EINT_TC;

	outb(ier, host->base + WBSD_EIR);

	/*
	 * Clear interrupts.
	 */
	inb(host->base + WBSD_ISR);
}

static void wbsd_reset(struct wbsd_host* host)
{
	u8 setup;
203

L
Linus Torvalds 已提交
204
	printk(KERN_ERR DRIVER_NAME ": Resetting chip\n");
205

L
Linus Torvalds 已提交
206 207 208 209 210 211 212 213 214 215 216
	/*
	 * Soft reset of chip (SD/MMC part).
	 */
	setup = wbsd_read_index(host, WBSD_IDX_SETUP);
	setup |= WBSD_SOFT_RESET;
	wbsd_write_index(host, WBSD_IDX_SETUP, setup);
}

static void wbsd_request_end(struct wbsd_host* host, struct mmc_request* mrq)
{
	unsigned long dmaflags;
217

L
Linus Torvalds 已提交
218
	DBGF("Ending request, cmd (%x)\n", mrq->cmd->opcode);
219

L
Linus Torvalds 已提交
220 221 222 223 224 225 226 227 228 229 230 231 232 233 234
	if (host->dma >= 0)
	{
		/*
		 * Release ISA DMA controller.
		 */
		dmaflags = claim_dma_lock();
		disable_dma(host->dma);
		clear_dma_ff(host->dma);
		release_dma_lock(dmaflags);

		/*
		 * Disable DMA on host.
		 */
		wbsd_write_index(host, WBSD_IDX_DMA, 0);
	}
235

L
Linus Torvalds 已提交
236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277
	host->mrq = NULL;

	/*
	 * MMC layer might call back into the driver so first unlock.
	 */
	spin_unlock(&host->lock);
	mmc_request_done(host->mmc, mrq);
	spin_lock(&host->lock);
}

/*
 * Scatter/gather functions
 */

static inline void wbsd_init_sg(struct wbsd_host* host, struct mmc_data* data)
{
	/*
	 * Get info. about SG list from data structure.
	 */
	host->cur_sg = data->sg;
	host->num_sg = data->sg_len;

	host->offset = 0;
	host->remain = host->cur_sg->length;
}

static inline int wbsd_next_sg(struct wbsd_host* host)
{
	/*
	 * Skip to next SG entry.
	 */
	host->cur_sg++;
	host->num_sg--;

	/*
	 * Any entries left?
	 */
	if (host->num_sg > 0)
	  {
	    host->offset = 0;
	    host->remain = host->cur_sg->length;
	  }
278

L
Linus Torvalds 已提交
279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299
	return host->num_sg;
}

static inline char* wbsd_kmap_sg(struct wbsd_host* host)
{
	host->mapped_sg = kmap_atomic(host->cur_sg->page, KM_BIO_SRC_IRQ) +
		host->cur_sg->offset;
	return host->mapped_sg;
}

static inline void wbsd_kunmap_sg(struct wbsd_host* host)
{
	kunmap_atomic(host->mapped_sg, KM_BIO_SRC_IRQ);
}

static inline void wbsd_sg_to_dma(struct wbsd_host* host, struct mmc_data* data)
{
	unsigned int len, i, size;
	struct scatterlist* sg;
	char* dmabuf = host->dma_buffer;
	char* sgbuf;
300

L
Linus Torvalds 已提交
301
	size = host->size;
302

L
Linus Torvalds 已提交
303 304
	sg = data->sg;
	len = data->sg_len;
305

L
Linus Torvalds 已提交
306 307 308 309 310 311 312 313 314 315 316 317 318 319
	/*
	 * Just loop through all entries. Size might not
	 * be the entire list though so make sure that
	 * we do not transfer too much.
	 */
	for (i = 0;i < len;i++)
	{
		sgbuf = kmap_atomic(sg[i].page, KM_BIO_SRC_IRQ) + sg[i].offset;
		if (size < sg[i].length)
			memcpy(dmabuf, sgbuf, size);
		else
			memcpy(dmabuf, sgbuf, sg[i].length);
		kunmap_atomic(sgbuf, KM_BIO_SRC_IRQ);
		dmabuf += sg[i].length;
320

L
Linus Torvalds 已提交
321 322 323 324
		if (size < sg[i].length)
			size = 0;
		else
			size -= sg[i].length;
325

L
Linus Torvalds 已提交
326 327 328
		if (size == 0)
			break;
	}
329

L
Linus Torvalds 已提交
330 331 332 333
	/*
	 * Check that we didn't get a request to transfer
	 * more data than can fit into the SG list.
	 */
334

L
Linus Torvalds 已提交
335
	BUG_ON(size != 0);
336

L
Linus Torvalds 已提交
337 338 339 340 341 342 343 344 345
	host->size -= size;
}

static inline void wbsd_dma_to_sg(struct wbsd_host* host, struct mmc_data* data)
{
	unsigned int len, i, size;
	struct scatterlist* sg;
	char* dmabuf = host->dma_buffer;
	char* sgbuf;
346

L
Linus Torvalds 已提交
347
	size = host->size;
348

L
Linus Torvalds 已提交
349 350
	sg = data->sg;
	len = data->sg_len;
351

L
Linus Torvalds 已提交
352 353 354 355 356 357 358 359 360 361 362 363 364 365
	/*
	 * Just loop through all entries. Size might not
	 * be the entire list though so make sure that
	 * we do not transfer too much.
	 */
	for (i = 0;i < len;i++)
	{
		sgbuf = kmap_atomic(sg[i].page, KM_BIO_SRC_IRQ) + sg[i].offset;
		if (size < sg[i].length)
			memcpy(sgbuf, dmabuf, size);
		else
			memcpy(sgbuf, dmabuf, sg[i].length);
		kunmap_atomic(sgbuf, KM_BIO_SRC_IRQ);
		dmabuf += sg[i].length;
366

L
Linus Torvalds 已提交
367 368 369 370
		if (size < sg[i].length)
			size = 0;
		else
			size -= sg[i].length;
371

L
Linus Torvalds 已提交
372 373 374
		if (size == 0)
			break;
	}
375

L
Linus Torvalds 已提交
376 377 378 379
	/*
	 * Check that we didn't get a request to transfer
	 * more data than can fit into the SG list.
	 */
380

L
Linus Torvalds 已提交
381
	BUG_ON(size != 0);
382

L
Linus Torvalds 已提交
383 384 385 386 387 388
	host->size -= size;
}

/*
 * Command handling
 */
389

L
Linus Torvalds 已提交
390 391 392 393 394 395 396 397 398 399 400
static inline void wbsd_get_short_reply(struct wbsd_host* host,
	struct mmc_command* cmd)
{
	/*
	 * Correct response type?
	 */
	if (wbsd_read_index(host, WBSD_IDX_RSPLEN) != WBSD_RSP_SHORT)
	{
		cmd->error = MMC_ERR_INVALID;
		return;
	}
401

L
Linus Torvalds 已提交
402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417
	cmd->resp[0] =
		wbsd_read_index(host, WBSD_IDX_RESP12) << 24;
	cmd->resp[0] |=
		wbsd_read_index(host, WBSD_IDX_RESP13) << 16;
	cmd->resp[0] |=
		wbsd_read_index(host, WBSD_IDX_RESP14) << 8;
	cmd->resp[0] |=
		wbsd_read_index(host, WBSD_IDX_RESP15) << 0;
	cmd->resp[1] =
		wbsd_read_index(host, WBSD_IDX_RESP16) << 24;
}

static inline void wbsd_get_long_reply(struct wbsd_host* host,
	struct mmc_command* cmd)
{
	int i;
418

L
Linus Torvalds 已提交
419 420 421 422 423 424 425 426
	/*
	 * Correct response type?
	 */
	if (wbsd_read_index(host, WBSD_IDX_RSPLEN) != WBSD_RSP_LONG)
	{
		cmd->error = MMC_ERR_INVALID;
		return;
	}
427

L
Linus Torvalds 已提交
428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444
	for (i = 0;i < 4;i++)
	{
		cmd->resp[i] =
			wbsd_read_index(host, WBSD_IDX_RESP1 + i * 4) << 24;
		cmd->resp[i] |=
			wbsd_read_index(host, WBSD_IDX_RESP2 + i * 4) << 16;
		cmd->resp[i] |=
			wbsd_read_index(host, WBSD_IDX_RESP3 + i * 4) << 8;
		cmd->resp[i] |=
			wbsd_read_index(host, WBSD_IDX_RESP4 + i * 4) << 0;
	}
}

static void wbsd_send_command(struct wbsd_host* host, struct mmc_command* cmd)
{
	int i;
	u8 status, isr;
445

L
Linus Torvalds 已提交
446 447 448 449 450 451 452 453
	DBGF("Sending cmd (%x)\n", cmd->opcode);

	/*
	 * Clear accumulated ISR. The interrupt routine
	 * will fill this one with events that occur during
	 * transfer.
	 */
	host->isr = 0;
454

L
Linus Torvalds 已提交
455 456 457 458 459 460
	/*
	 * Send the command (CRC calculated by host).
	 */
	outb(cmd->opcode, host->base + WBSD_CMDR);
	for (i = 3;i >= 0;i--)
		outb((cmd->arg >> (i * 8)) & 0xff, host->base + WBSD_CMDR);
461

L
Linus Torvalds 已提交
462
	cmd->error = MMC_ERR_NONE;
463

L
Linus Torvalds 已提交
464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479
	/*
	 * Wait for the request to complete.
	 */
	do {
		status = wbsd_read_index(host, WBSD_IDX_STATUS);
	} while (status & WBSD_CARDTRAFFIC);

	/*
	 * Do we expect a reply?
	 */
	if ((cmd->flags & MMC_RSP_MASK) != MMC_RSP_NONE)
	{
		/*
		 * Read back status.
		 */
		isr = host->isr;
480

L
Linus Torvalds 已提交
481 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
		/* Card removed? */
		if (isr & WBSD_INT_CARD)
			cmd->error = MMC_ERR_TIMEOUT;
		/* Timeout? */
		else if (isr & WBSD_INT_TIMEOUT)
			cmd->error = MMC_ERR_TIMEOUT;
		/* CRC? */
		else if ((cmd->flags & MMC_RSP_CRC) && (isr & WBSD_INT_CRC))
			cmd->error = MMC_ERR_BADCRC;
		/* All ok */
		else
		{
			if ((cmd->flags & MMC_RSP_MASK) == MMC_RSP_SHORT)
				wbsd_get_short_reply(host, cmd);
			else
				wbsd_get_long_reply(host, cmd);
		}
	}

	DBGF("Sent cmd (%x), res %d\n", cmd->opcode, cmd->error);
}

/*
 * Data functions
 */

static void wbsd_empty_fifo(struct wbsd_host* host)
{
	struct mmc_data* data = host->mrq->cmd->data;
	char* buffer;
	int i, fsr, fifo;
512

L
Linus Torvalds 已提交
513 514 515 516 517
	/*
	 * Handle excessive data.
	 */
	if (data->bytes_xfered == host->size)
		return;
518

L
Linus Torvalds 已提交
519 520 521 522 523 524 525 526 527 528 529
	buffer = wbsd_kmap_sg(host) + host->offset;

	/*
	 * Drain the fifo. This has a tendency to loop longer
	 * than the FIFO length (usually one block).
	 */
	while (!((fsr = inb(host->base + WBSD_FSR)) & WBSD_FIFO_EMPTY))
	{
		/*
		 * The size field in the FSR is broken so we have to
		 * do some guessing.
530
		 */
L
Linus Torvalds 已提交
531 532 533 534 535 536
		if (fsr & WBSD_FIFO_FULL)
			fifo = 16;
		else if (fsr & WBSD_FIFO_FUTHRE)
			fifo = 8;
		else
			fifo = 1;
537

L
Linus Torvalds 已提交
538 539 540 541 542 543 544 545
		for (i = 0;i < fifo;i++)
		{
			*buffer = inb(host->base + WBSD_DFR);
			buffer++;
			host->offset++;
			host->remain--;

			data->bytes_xfered++;
546

L
Linus Torvalds 已提交
547 548 549 550 551
			/*
			 * Transfer done?
			 */
			if (data->bytes_xfered == host->size)
			{
552
				wbsd_kunmap_sg(host);
L
Linus Torvalds 已提交
553 554
				return;
			}
555

L
Linus Torvalds 已提交
556 557 558 559 560 561
			/*
			 * End of scatter list entry?
			 */
			if (host->remain == 0)
			{
				wbsd_kunmap_sg(host);
562

L
Linus Torvalds 已提交
563 564 565 566 567 568 569 570 571 572 573 574
				/*
				 * Get next entry. Check if last.
				 */
				if (!wbsd_next_sg(host))
				{
					/*
					 * We should never reach this point.
					 * It means that we're trying to
					 * transfer more blocks than can fit
					 * into the scatter list.
					 */
					BUG_ON(1);
575

L
Linus Torvalds 已提交
576
					host->size = data->bytes_xfered;
577

L
Linus Torvalds 已提交
578 579
					return;
				}
580

L
Linus Torvalds 已提交
581 582 583 584
				buffer = wbsd_kmap_sg(host);
			}
		}
	}
585

L
Linus Torvalds 已提交
586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601
	wbsd_kunmap_sg(host);

	/*
	 * This is a very dirty hack to solve a
	 * hardware problem. The chip doesn't trigger
	 * FIFO threshold interrupts properly.
	 */
	if ((host->size - data->bytes_xfered) < 16)
		tasklet_schedule(&host->fifo_tasklet);
}

static void wbsd_fill_fifo(struct wbsd_host* host)
{
	struct mmc_data* data = host->mrq->cmd->data;
	char* buffer;
	int i, fsr, fifo;
602

L
Linus Torvalds 已提交
603 604 605 606 607 608 609 610 611 612 613 614 615 616 617 618 619 620
	/*
	 * Check that we aren't being called after the
	 * entire buffer has been transfered.
	 */
	if (data->bytes_xfered == host->size)
		return;

	buffer = wbsd_kmap_sg(host) + host->offset;

	/*
	 * Fill the fifo. This has a tendency to loop longer
	 * than the FIFO length (usually one block).
	 */
	while (!((fsr = inb(host->base + WBSD_FSR)) & WBSD_FIFO_FULL))
	{
		/*
		 * The size field in the FSR is broken so we have to
		 * do some guessing.
621
		 */
L
Linus Torvalds 已提交
622 623 624 625 626 627 628 629 630 631 632 633 634
		if (fsr & WBSD_FIFO_EMPTY)
			fifo = 0;
		else if (fsr & WBSD_FIFO_EMTHRE)
			fifo = 8;
		else
			fifo = 15;

		for (i = 16;i > fifo;i--)
		{
			outb(*buffer, host->base + WBSD_DFR);
			buffer++;
			host->offset++;
			host->remain--;
635

L
Linus Torvalds 已提交
636
			data->bytes_xfered++;
637

L
Linus Torvalds 已提交
638 639 640 641 642 643 644 645 646 647 648 649 650 651 652
			/*
			 * Transfer done?
			 */
			if (data->bytes_xfered == host->size)
			{
				wbsd_kunmap_sg(host);
				return;
			}

			/*
			 * End of scatter list entry?
			 */
			if (host->remain == 0)
			{
				wbsd_kunmap_sg(host);
653

L
Linus Torvalds 已提交
654 655 656 657 658 659 660 661 662 663 664 665
				/*
				 * Get next entry. Check if last.
				 */
				if (!wbsd_next_sg(host))
				{
					/*
					 * We should never reach this point.
					 * It means that we're trying to
					 * transfer more blocks than can fit
					 * into the scatter list.
					 */
					BUG_ON(1);
666

L
Linus Torvalds 已提交
667
					host->size = data->bytes_xfered;
668

L
Linus Torvalds 已提交
669 670
					return;
				}
671

L
Linus Torvalds 已提交
672 673 674 675
				buffer = wbsd_kmap_sg(host);
			}
		}
	}
676

L
Linus Torvalds 已提交
677
	wbsd_kunmap_sg(host);
678

P
Pierre Ossman 已提交
679 680 681 682 683 684
	/*
	 * The controller stops sending interrupts for
	 * 'FIFO empty' under certain conditions. So we
	 * need to be a bit more pro-active.
	 */
	tasklet_schedule(&host->fifo_tasklet);
L
Linus Torvalds 已提交
685 686 687 688 689 690 691 692 693 694 695 696
}

static void wbsd_prepare_data(struct wbsd_host* host, struct mmc_data* data)
{
	u16 blksize;
	u8 setup;
	unsigned long dmaflags;

	DBGF("blksz %04x blks %04x flags %08x\n",
		1 << data->blksz_bits, data->blocks, data->flags);
	DBGF("tsac %d ms nsac %d clk\n",
		data->timeout_ns / 1000000, data->timeout_clks);
697

L
Linus Torvalds 已提交
698 699 700 701 702 703 704 705 706 707 708 709 710
	/*
	 * Calculate size.
	 */
	host->size = data->blocks << data->blksz_bits;

	/*
	 * Check timeout values for overflow.
	 * (Yes, some cards cause this value to overflow).
	 */
	if (data->timeout_ns > 127000000)
		wbsd_write_index(host, WBSD_IDX_TAAC, 127);
	else
		wbsd_write_index(host, WBSD_IDX_TAAC, data->timeout_ns/1000000);
711

L
Linus Torvalds 已提交
712 713 714 715
	if (data->timeout_clks > 255)
		wbsd_write_index(host, WBSD_IDX_NSAC, 255);
	else
		wbsd_write_index(host, WBSD_IDX_NSAC, data->timeout_clks);
716

L
Linus Torvalds 已提交
717 718 719 720 721 722
	/*
	 * Inform the chip of how large blocks will be
	 * sent. It needs this to determine when to
	 * calculate CRC.
	 *
	 * Space for CRC must be included in the size.
723
	 * Two bytes are needed for each data line.
L
Linus Torvalds 已提交
724
	 */
725 726 727 728 729 730 731 732 733 734
	if (host->bus_width == MMC_BUS_WIDTH_1)
	{
		blksize = (1 << data->blksz_bits) + 2;

		wbsd_write_index(host, WBSD_IDX_PBSMSB, (blksize >> 4) & 0xF0);
		wbsd_write_index(host, WBSD_IDX_PBSLSB, blksize & 0xFF);
	}
	else if (host->bus_width == MMC_BUS_WIDTH_4)
	{
		blksize = (1 << data->blksz_bits) + 2 * 4;
735

736 737 738 739 740 741 742 743 744
		wbsd_write_index(host, WBSD_IDX_PBSMSB, ((blksize >> 4) & 0xF0)
			| WBSD_DATA_WIDTH);
		wbsd_write_index(host, WBSD_IDX_PBSLSB, blksize & 0xFF);
	}
	else
	{
		data->error = MMC_ERR_INVALID;
		return;
	}
L
Linus Torvalds 已提交
745 746 747 748 749 750 751 752 753

	/*
	 * Clear the FIFO. This is needed even for DMA
	 * transfers since the chip still uses the FIFO
	 * internally.
	 */
	setup = wbsd_read_index(host, WBSD_IDX_SETUP);
	setup |= WBSD_FIFO_RESET;
	wbsd_write_index(host, WBSD_IDX_SETUP, setup);
754

L
Linus Torvalds 已提交
755 756 757 758
	/*
	 * DMA transfer?
	 */
	if (host->dma >= 0)
759
	{
L
Linus Torvalds 已提交
760 761 762 763 764 765 766 767 768
		/*
		 * The buffer for DMA is only 64 kB.
		 */
		BUG_ON(host->size > 0x10000);
		if (host->size > 0x10000)
		{
			data->error = MMC_ERR_INVALID;
			return;
		}
769

L
Linus Torvalds 已提交
770 771 772 773 774 775
		/*
		 * Transfer data from the SG list to
		 * the DMA buffer.
		 */
		if (data->flags & MMC_DATA_WRITE)
			wbsd_sg_to_dma(host, data);
776

L
Linus Torvalds 已提交
777 778
		/*
		 * Initialise the ISA DMA controller.
779
		 */
L
Linus Torvalds 已提交
780 781 782 783 784 785 786 787 788 789 790 791 792 793 794 795 796 797 798 799 800 801 802 803 804
		dmaflags = claim_dma_lock();
		disable_dma(host->dma);
		clear_dma_ff(host->dma);
		if (data->flags & MMC_DATA_READ)
			set_dma_mode(host->dma, DMA_MODE_READ & ~0x40);
		else
			set_dma_mode(host->dma, DMA_MODE_WRITE & ~0x40);
		set_dma_addr(host->dma, host->dma_addr);
		set_dma_count(host->dma, host->size);

		enable_dma(host->dma);
		release_dma_lock(dmaflags);

		/*
		 * Enable DMA on the host.
		 */
		wbsd_write_index(host, WBSD_IDX_DMA, WBSD_DMA_ENABLE);
	}
	else
	{
		/*
		 * This flag is used to keep printk
		 * output to a minimum.
		 */
		host->firsterr = 1;
805

L
Linus Torvalds 已提交
806 807 808 809
		/*
		 * Initialise the SG list.
		 */
		wbsd_init_sg(host, data);
810

L
Linus Torvalds 已提交
811 812 813 814
		/*
		 * Turn off DMA.
		 */
		wbsd_write_index(host, WBSD_IDX_DMA, 0);
815

L
Linus Torvalds 已提交
816 817 818 819 820 821 822 823 824 825 826 827 828 829 830
		/*
		 * Set up FIFO threshold levels (and fill
		 * buffer if doing a write).
		 */
		if (data->flags & MMC_DATA_READ)
		{
			wbsd_write_index(host, WBSD_IDX_FIFOEN,
				WBSD_FIFOEN_FULL | 8);
		}
		else
		{
			wbsd_write_index(host, WBSD_IDX_FIFOEN,
				WBSD_FIFOEN_EMPTY | 8);
			wbsd_fill_fifo(host);
		}
831 832
	}

L
Linus Torvalds 已提交
833 834 835 836 837 838 839 840
	data->error = MMC_ERR_NONE;
}

static void wbsd_finish_data(struct wbsd_host* host, struct mmc_data* data)
{
	unsigned long dmaflags;
	int count;
	u8 status;
841

L
Linus Torvalds 已提交
842 843 844 845 846 847 848 849 850 851 852 853 854 855 856 857
	WARN_ON(host->mrq == NULL);

	/*
	 * Send a stop command if needed.
	 */
	if (data->stop)
		wbsd_send_command(host, data->stop);

	/*
	 * Wait for the controller to leave data
	 * transfer state.
	 */
	do
	{
		status = wbsd_read_index(host, WBSD_IDX_STATUS);
	} while (status & (WBSD_BLOCK_READ | WBSD_BLOCK_WRITE));
858

L
Linus Torvalds 已提交
859 860 861 862 863 864 865 866 867
	/*
	 * DMA transfer?
	 */
	if (host->dma >= 0)
	{
		/*
		 * Disable DMA on the host.
		 */
		wbsd_write_index(host, WBSD_IDX_DMA, 0);
868

L
Linus Torvalds 已提交
869 870 871 872 873 874 875 876
		/*
		 * Turn of ISA DMA controller.
		 */
		dmaflags = claim_dma_lock();
		disable_dma(host->dma);
		clear_dma_ff(host->dma);
		count = get_dma_residue(host->dma);
		release_dma_lock(dmaflags);
877

L
Linus Torvalds 已提交
878 879 880 881 882 883 884
		/*
		 * Any leftover data?
		 */
		if (count)
		{
			printk(KERN_ERR DRIVER_NAME ": Incomplete DMA "
				"transfer. %d bytes left.\n", count);
885

L
Linus Torvalds 已提交
886 887 888 889 890 891 892 893 894 895
			data->error = MMC_ERR_FAILED;
		}
		else
		{
			/*
			 * Transfer data from DMA buffer to
			 * SG list.
			 */
			if (data->flags & MMC_DATA_READ)
				wbsd_dma_to_sg(host, data);
896

L
Linus Torvalds 已提交
897 898 899
			data->bytes_xfered = host->size;
		}
	}
900

L
Linus Torvalds 已提交
901
	DBGF("Ending data transfer (%d bytes)\n", data->bytes_xfered);
902

L
Linus Torvalds 已提交
903 904 905
	wbsd_request_end(host, host->mrq);
}

P
Pierre Ossman 已提交
906 907 908 909 910
/*****************************************************************************\
 *                                                                           *
 * MMC layer callbacks                                                       *
 *                                                                           *
\*****************************************************************************/
L
Linus Torvalds 已提交
911 912 913 914 915 916 917 918 919 920 921 922 923 924 925 926

static void wbsd_request(struct mmc_host* mmc, struct mmc_request* mrq)
{
	struct wbsd_host* host = mmc_priv(mmc);
	struct mmc_command* cmd;

	/*
	 * Disable tasklets to avoid a deadlock.
	 */
	spin_lock_bh(&host->lock);

	BUG_ON(host->mrq != NULL);

	cmd = mrq->cmd;

	host->mrq = mrq;
927

L
Linus Torvalds 已提交
928 929 930 931
	/*
	 * If there is no card in the slot then
	 * timeout immediatly.
	 */
P
Pierre Ossman 已提交
932
	if (!(host->flags & WBSD_FCARD_PRESENT))
L
Linus Torvalds 已提交
933 934 935 936 937 938 939 940 941 942 943
	{
		cmd->error = MMC_ERR_TIMEOUT;
		goto done;
	}

	/*
	 * Does the request include data?
	 */
	if (cmd->data)
	{
		wbsd_prepare_data(host, cmd->data);
944

L
Linus Torvalds 已提交
945 946 947
		if (cmd->data->error != MMC_ERR_NONE)
			goto done;
	}
948

L
Linus Torvalds 已提交
949 950 951 952 953 954
	wbsd_send_command(host, cmd);

	/*
	 * If this is a data transfer the request
	 * will be finished after the data has
	 * transfered.
955
	 */
L
Linus Torvalds 已提交
956 957 958 959 960 961 962 963 964 965 966 967
	if (cmd->data && (cmd->error == MMC_ERR_NONE))
	{
		/*
		 * Dirty fix for hardware bug.
		 */
		if (host->dma == -1)
			tasklet_schedule(&host->fifo_tasklet);

		spin_unlock_bh(&host->lock);

		return;
	}
968

L
Linus Torvalds 已提交
969 970 971 972 973 974 975 976 977 978
done:
	wbsd_request_end(host, mrq);

	spin_unlock_bh(&host->lock);
}

static void wbsd_set_ios(struct mmc_host* mmc, struct mmc_ios* ios)
{
	struct wbsd_host* host = mmc_priv(mmc);
	u8 clk, setup, pwr;
979

980 981 982
	DBGF("clock %uHz busmode %u powermode %u cs %u Vdd %u width %u\n",
	     ios->clock, ios->bus_mode, ios->power_mode, ios->chip_select,
	     ios->vdd, ios->bus_width);
L
Linus Torvalds 已提交
983 984 985 986 987 988 989 990 991

	spin_lock_bh(&host->lock);

	/*
	 * Reset the chip on each power off.
	 * Should clear out any weird states.
	 */
	if (ios->power_mode == MMC_POWER_OFF)
		wbsd_init_device(host);
992

L
Linus Torvalds 已提交
993 994 995 996 997 998 999 1000 1001 1002 1003 1004 1005 1006 1007 1008 1009 1010 1011
	if (ios->clock >= 24000000)
		clk = WBSD_CLK_24M;
	else if (ios->clock >= 16000000)
		clk = WBSD_CLK_16M;
	else if (ios->clock >= 12000000)
		clk = WBSD_CLK_12M;
	else
		clk = WBSD_CLK_375K;

	/*
	 * Only write to the clock register when
	 * there is an actual change.
	 */
	if (clk != host->clk)
	{
		wbsd_write_index(host, WBSD_IDX_CLK, clk);
		host->clk = clk;
	}

P
Pierre Ossman 已提交
1012 1013 1014
	/*
	 * Power up card.
	 */
L
Linus Torvalds 已提交
1015 1016 1017 1018 1019 1020 1021
	if (ios->power_mode != MMC_POWER_OFF)
	{
		pwr = inb(host->base + WBSD_CSR);
		pwr &= ~WBSD_POWER_N;
		outb(pwr, host->base + WBSD_CSR);
	}

P
Pierre Ossman 已提交
1022 1023 1024
	/*
	 * MMC cards need to have pin 1 high during init.
	 * It wreaks havoc with the card detection though so
1025
	 * that needs to be disabled.
P
Pierre Ossman 已提交
1026 1027
	 */
	setup = wbsd_read_index(host, WBSD_IDX_SETUP);
1028
	if (ios->chip_select == MMC_CS_HIGH)
P
Pierre Ossman 已提交
1029
	{
1030
		BUG_ON(ios->bus_width != MMC_BUS_WIDTH_1);
P
Pierre Ossman 已提交
1031 1032 1033 1034 1035
		setup |= WBSD_DAT3_H;
		host->flags |= WBSD_FIGNORE_DETECT;
	}
	else
	{
P
Pierre Ossman 已提交
1036 1037 1038
		if (setup & WBSD_DAT3_H)
		{
			setup &= ~WBSD_DAT3_H;
1039

P
Pierre Ossman 已提交
1040 1041 1042 1043 1044 1045
			/*
			 * We cannot resume card detection immediatly
			 * because of capacitance and delays in the chip.
			 */
			mod_timer(&host->ignore_timer, jiffies + HZ/100);
		}
P
Pierre Ossman 已提交
1046 1047
	}
	wbsd_write_index(host, WBSD_IDX_SETUP, setup);
1048

1049 1050 1051 1052 1053 1054
	/*
	 * Store bus width for later. Will be used when
	 * setting up the data transfer.
	 */
	host->bus_width = ios->bus_width;

L
Linus Torvalds 已提交
1055 1056 1057
	spin_unlock_bh(&host->lock);
}

1058 1059 1060 1061 1062 1063 1064 1065 1066 1067 1068 1069 1070 1071 1072 1073 1074 1075 1076 1077 1078 1079
static int wbsd_get_ro(struct mmc_host* mmc)
{
	struct wbsd_host* host = mmc_priv(mmc);
	u8 csr;

	spin_lock_bh(&host->lock);

	csr = inb(host->base + WBSD_CSR);
	csr |= WBSD_MSLED;
	outb(csr, host->base + WBSD_CSR);

	mdelay(1);

	csr = inb(host->base + WBSD_CSR);
	csr &= ~WBSD_MSLED;
	outb(csr, host->base + WBSD_CSR);

	spin_unlock_bh(&host->lock);

	return csr & WBSD_WRPT;
}

P
Pierre Ossman 已提交
1080 1081 1082
static struct mmc_host_ops wbsd_ops = {
	.request	= wbsd_request,
	.set_ios	= wbsd_set_ios,
1083
	.get_ro		= wbsd_get_ro,
P
Pierre Ossman 已提交
1084 1085 1086 1087 1088 1089 1090 1091
};

/*****************************************************************************\
 *                                                                           *
 * Interrupt handling                                                        *
 *                                                                           *
\*****************************************************************************/

1092 1093 1094 1095 1096 1097 1098 1099 1100 1101 1102 1103 1104 1105 1106 1107 1108 1109 1110 1111 1112 1113 1114 1115 1116
/*
 * Helper function to reset detection ignore
 */

static void wbsd_reset_ignore(unsigned long data)
{
	struct wbsd_host *host = (struct wbsd_host*)data;

	BUG_ON(host == NULL);

	DBG("Resetting card detection ignore\n");

	spin_lock_bh(&host->lock);

	host->flags &= ~WBSD_FIGNORE_DETECT;

	/*
	 * Card status might have changed during the
	 * blackout.
	 */
	tasklet_schedule(&host->card_tasklet);

	spin_unlock_bh(&host->lock);
}

L
Linus Torvalds 已提交
1117 1118 1119 1120
/*
 * Tasklets
 */

1121
static inline struct mmc_data* wbsd_get_data(struct wbsd_host* host)
L
Linus Torvalds 已提交
1122 1123 1124 1125 1126 1127 1128 1129 1130 1131 1132 1133
{
	WARN_ON(!host->mrq);
	if (!host->mrq)
		return NULL;

	WARN_ON(!host->mrq->cmd);
	if (!host->mrq->cmd)
		return NULL;

	WARN_ON(!host->mrq->cmd->data);
	if (!host->mrq->cmd->data)
		return NULL;
1134

L
Linus Torvalds 已提交
1135 1136 1137 1138 1139 1140 1141
	return host->mrq->cmd->data;
}

static void wbsd_tasklet_card(unsigned long param)
{
	struct wbsd_host* host = (struct wbsd_host*)param;
	u8 csr;
1142
	int delay = -1;
1143

L
Linus Torvalds 已提交
1144
	spin_lock(&host->lock);
1145

P
Pierre Ossman 已提交
1146 1147 1148 1149 1150
	if (host->flags & WBSD_FIGNORE_DETECT)
	{
		spin_unlock(&host->lock);
		return;
	}
1151

L
Linus Torvalds 已提交
1152 1153
	csr = inb(host->base + WBSD_CSR);
	WARN_ON(csr == 0xff);
1154

L
Linus Torvalds 已提交
1155
	if (csr & WBSD_CARDPRESENT)
P
Pierre Ossman 已提交
1156 1157 1158 1159 1160
	{
		if (!(host->flags & WBSD_FCARD_PRESENT))
		{
			DBG("Card inserted\n");
			host->flags |= WBSD_FCARD_PRESENT;
1161

1162
			delay = 500;
P
Pierre Ossman 已提交
1163 1164 1165
		}
	}
	else if (host->flags & WBSD_FCARD_PRESENT)
L
Linus Torvalds 已提交
1166 1167
	{
		DBG("Card removed\n");
P
Pierre Ossman 已提交
1168
		host->flags &= ~WBSD_FCARD_PRESENT;
1169

L
Linus Torvalds 已提交
1170 1171 1172 1173 1174
		if (host->mrq)
		{
			printk(KERN_ERR DRIVER_NAME
				": Card removed during transfer!\n");
			wbsd_reset(host);
1175

L
Linus Torvalds 已提交
1176 1177 1178
			host->mrq->cmd->error = MMC_ERR_FAILED;
			tasklet_schedule(&host->finish_tasklet);
		}
1179

1180
		delay = 0;
1181
	}
1182 1183 1184 1185 1186 1187 1188 1189 1190

	/*
	 * Unlock first since we might get a call back.
	 */

	spin_unlock(&host->lock);

	if (delay != -1)
		mmc_detect_change(host->mmc, msecs_to_jiffies(delay));
L
Linus Torvalds 已提交
1191 1192 1193 1194 1195 1196
}

static void wbsd_tasklet_fifo(unsigned long param)
{
	struct wbsd_host* host = (struct wbsd_host*)param;
	struct mmc_data* data;
1197

L
Linus Torvalds 已提交
1198
	spin_lock(&host->lock);
1199

L
Linus Torvalds 已提交
1200 1201
	if (!host->mrq)
		goto end;
1202

L
Linus Torvalds 已提交
1203 1204 1205 1206 1207 1208 1209 1210 1211 1212 1213 1214 1215 1216 1217 1218 1219 1220
	data = wbsd_get_data(host);
	if (!data)
		goto end;

	if (data->flags & MMC_DATA_WRITE)
		wbsd_fill_fifo(host);
	else
		wbsd_empty_fifo(host);

	/*
	 * Done?
	 */
	if (host->size == data->bytes_xfered)
	{
		wbsd_write_index(host, WBSD_IDX_FIFOEN, 0);
		tasklet_schedule(&host->finish_tasklet);
	}

1221
end:
L
Linus Torvalds 已提交
1222 1223 1224 1225 1226 1227 1228
	spin_unlock(&host->lock);
}

static void wbsd_tasklet_crc(unsigned long param)
{
	struct wbsd_host* host = (struct wbsd_host*)param;
	struct mmc_data* data;
1229

L
Linus Torvalds 已提交
1230
	spin_lock(&host->lock);
1231

L
Linus Torvalds 已提交
1232 1233
	if (!host->mrq)
		goto end;
1234

L
Linus Torvalds 已提交
1235 1236 1237
	data = wbsd_get_data(host);
	if (!data)
		goto end;
1238

L
Linus Torvalds 已提交
1239 1240 1241
	DBGF("CRC error\n");

	data->error = MMC_ERR_BADCRC;
1242

L
Linus Torvalds 已提交
1243 1244
	tasklet_schedule(&host->finish_tasklet);

1245
end:
L
Linus Torvalds 已提交
1246 1247 1248 1249 1250 1251 1252
	spin_unlock(&host->lock);
}

static void wbsd_tasklet_timeout(unsigned long param)
{
	struct wbsd_host* host = (struct wbsd_host*)param;
	struct mmc_data* data;
1253

L
Linus Torvalds 已提交
1254
	spin_lock(&host->lock);
1255

L
Linus Torvalds 已提交
1256 1257
	if (!host->mrq)
		goto end;
1258

L
Linus Torvalds 已提交
1259 1260 1261
	data = wbsd_get_data(host);
	if (!data)
		goto end;
1262

L
Linus Torvalds 已提交
1263 1264 1265
	DBGF("Timeout\n");

	data->error = MMC_ERR_TIMEOUT;
1266

L
Linus Torvalds 已提交
1267 1268
	tasklet_schedule(&host->finish_tasklet);

1269
end:
L
Linus Torvalds 已提交
1270 1271 1272 1273 1274 1275 1276
	spin_unlock(&host->lock);
}

static void wbsd_tasklet_finish(unsigned long param)
{
	struct wbsd_host* host = (struct wbsd_host*)param;
	struct mmc_data* data;
1277

L
Linus Torvalds 已提交
1278
	spin_lock(&host->lock);
1279

L
Linus Torvalds 已提交
1280 1281 1282
	WARN_ON(!host->mrq);
	if (!host->mrq)
		goto end;
1283

L
Linus Torvalds 已提交
1284 1285 1286 1287 1288
	data = wbsd_get_data(host);
	if (!data)
		goto end;

	wbsd_finish_data(host, data);
1289 1290

end:
L
Linus Torvalds 已提交
1291 1292 1293 1294 1295 1296 1297
	spin_unlock(&host->lock);
}

static void wbsd_tasklet_block(unsigned long param)
{
	struct wbsd_host* host = (struct wbsd_host*)param;
	struct mmc_data* data;
1298

L
Linus Torvalds 已提交
1299 1300 1301 1302 1303 1304 1305 1306
	spin_lock(&host->lock);

	if ((wbsd_read_index(host, WBSD_IDX_CRCSTATUS) & WBSD_CRC_MASK) !=
		WBSD_CRC_OK)
	{
		data = wbsd_get_data(host);
		if (!data)
			goto end;
1307

L
Linus Torvalds 已提交
1308 1309 1310
		DBGF("CRC error\n");

		data->error = MMC_ERR_BADCRC;
1311

L
Linus Torvalds 已提交
1312 1313 1314
		tasklet_schedule(&host->finish_tasklet);
	}

1315
end:
L
Linus Torvalds 已提交
1316 1317 1318 1319 1320 1321 1322 1323 1324 1325 1326
	spin_unlock(&host->lock);
}

/*
 * Interrupt handling
 */

static irqreturn_t wbsd_irq(int irq, void *dev_id, struct pt_regs *regs)
{
	struct wbsd_host* host = dev_id;
	int isr;
1327

L
Linus Torvalds 已提交
1328 1329 1330 1331 1332 1333 1334
	isr = inb(host->base + WBSD_ISR);

	/*
	 * Was it actually our hardware that caused the interrupt?
	 */
	if (isr == 0xff || isr == 0x00)
		return IRQ_NONE;
1335

L
Linus Torvalds 已提交
1336 1337 1338 1339 1340 1341 1342 1343 1344 1345 1346 1347 1348 1349 1350 1351 1352
	host->isr |= isr;

	/*
	 * Schedule tasklets as needed.
	 */
	if (isr & WBSD_INT_CARD)
		tasklet_schedule(&host->card_tasklet);
	if (isr & WBSD_INT_FIFO_THRE)
		tasklet_schedule(&host->fifo_tasklet);
	if (isr & WBSD_INT_CRC)
		tasklet_hi_schedule(&host->crc_tasklet);
	if (isr & WBSD_INT_TIMEOUT)
		tasklet_hi_schedule(&host->timeout_tasklet);
	if (isr & WBSD_INT_BUSYEND)
		tasklet_hi_schedule(&host->block_tasklet);
	if (isr & WBSD_INT_TC)
		tasklet_schedule(&host->finish_tasklet);
1353

L
Linus Torvalds 已提交
1354 1355 1356
	return IRQ_HANDLED;
}

P
Pierre Ossman 已提交
1357 1358 1359 1360 1361 1362
/*****************************************************************************\
 *                                                                           *
 * Device initialisation and shutdown                                        *
 *                                                                           *
\*****************************************************************************/

L
Linus Torvalds 已提交
1363
/*
P
Pierre Ossman 已提交
1364
 * Allocate/free MMC structure.
L
Linus Torvalds 已提交
1365 1366
 */

P
Pierre Ossman 已提交
1367 1368 1369 1370
static int __devinit wbsd_alloc_mmc(struct device* dev)
{
	struct mmc_host* mmc;
	struct wbsd_host* host;
1371

P
Pierre Ossman 已提交
1372 1373 1374 1375 1376 1377
	/*
	 * Allocate MMC structure.
	 */
	mmc = mmc_alloc_host(sizeof(struct wbsd_host), dev);
	if (!mmc)
		return -ENOMEM;
1378

P
Pierre Ossman 已提交
1379 1380 1381 1382 1383 1384 1385 1386 1387 1388 1389 1390
	host = mmc_priv(mmc);
	host->mmc = mmc;

	host->dma = -1;

	/*
	 * Set host parameters.
	 */
	mmc->ops = &wbsd_ops;
	mmc->f_min = 375000;
	mmc->f_max = 24000000;
	mmc->ocr_avail = MMC_VDD_32_33|MMC_VDD_33_34;
1391
	mmc->caps = MMC_CAP_4_BIT_DATA;
1392

P
Pierre Ossman 已提交
1393
	spin_lock_init(&host->lock);
1394

1395
	/*
1396
	 * Set up timers
1397
	 */
1398 1399 1400
	init_timer(&host->ignore_timer);
	host->ignore_timer.data = (unsigned long)host;
	host->ignore_timer.function = wbsd_reset_ignore;
1401

P
Pierre Ossman 已提交
1402 1403 1404 1405 1406 1407
	/*
	 * Maximum number of segments. Worst case is one sector per segment
	 * so this will be 64kB/512.
	 */
	mmc->max_hw_segs = 128;
	mmc->max_phys_segs = 128;
1408

P
Pierre Ossman 已提交
1409 1410 1411 1412 1413
	/*
	 * Maximum number of sectors in one transfer. Also limited by 64kB
	 * buffer.
	 */
	mmc->max_sectors = 128;
1414

P
Pierre Ossman 已提交
1415 1416 1417 1418 1419
	/*
	 * Maximum segment size. Could be one segment with the maximum number
	 * of segments.
	 */
	mmc->max_seg_size = mmc->max_sectors * 512;
1420

P
Pierre Ossman 已提交
1421
	dev_set_drvdata(dev, mmc);
1422

P
Pierre Ossman 已提交
1423 1424 1425 1426 1427 1428
	return 0;
}

static void __devexit wbsd_free_mmc(struct device* dev)
{
	struct mmc_host* mmc;
1429
	struct wbsd_host* host;
1430

P
Pierre Ossman 已提交
1431 1432 1433
	mmc = dev_get_drvdata(dev);
	if (!mmc)
		return;
1434

1435 1436
	host = mmc_priv(mmc);
	BUG_ON(host == NULL);
1437

1438
	del_timer_sync(&host->ignore_timer);
1439

P
Pierre Ossman 已提交
1440
	mmc_free_host(mmc);
1441

P
Pierre Ossman 已提交
1442 1443 1444 1445 1446 1447 1448 1449
	dev_set_drvdata(dev, NULL);
}

/*
 * Scan for known chip id:s
 */

static int __devinit wbsd_scan(struct wbsd_host* host)
L
Linus Torvalds 已提交
1450 1451 1452
{
	int i, j, k;
	int id;
1453

L
Linus Torvalds 已提交
1454 1455 1456 1457 1458 1459 1460 1461
	/*
	 * Iterate through all ports, all codes to
	 * find hardware that is in our known list.
	 */
	for (i = 0;i < sizeof(config_ports)/sizeof(int);i++)
	{
		if (!request_region(config_ports[i], 2, DRIVER_NAME))
			continue;
1462

L
Linus Torvalds 已提交
1463 1464 1465
		for (j = 0;j < sizeof(unlock_codes)/sizeof(int);j++)
		{
			id = 0xFFFF;
1466

P
Pierre Ossman 已提交
1467 1468 1469 1470
			host->config = config_ports[i];
			host->unlock_code = unlock_codes[j];

			wbsd_unlock_config(host);
1471

L
Linus Torvalds 已提交
1472 1473 1474 1475 1476
			outb(WBSD_CONF_ID_HI, config_ports[i]);
			id = inb(config_ports[i] + 1) << 8;

			outb(WBSD_CONF_ID_LO, config_ports[i]);
			id |= inb(config_ports[i] + 1);
1477

P
Pierre Ossman 已提交
1478 1479
			wbsd_lock_config(host);

L
Linus Torvalds 已提交
1480 1481 1482
			for (k = 0;k < sizeof(valid_ids)/sizeof(int);k++)
			{
				if (id == valid_ids[k])
1483
				{
L
Linus Torvalds 已提交
1484
					host->chip_id = id;
1485

L
Linus Torvalds 已提交
1486 1487 1488
					return 0;
				}
			}
1489

L
Linus Torvalds 已提交
1490 1491 1492 1493 1494 1495
			if (id != 0xFFFF)
			{
				DBG("Unknown hardware (id %x) found at %x\n",
					id, config_ports[i]);
			}
		}
1496

L
Linus Torvalds 已提交
1497 1498
		release_region(config_ports[i], 2);
	}
1499

P
Pierre Ossman 已提交
1500 1501 1502
	host->config = 0;
	host->unlock_code = 0;

L
Linus Torvalds 已提交
1503 1504 1505
	return -ENODEV;
}

P
Pierre Ossman 已提交
1506 1507 1508 1509 1510
/*
 * Allocate/free io port ranges
 */

static int __devinit wbsd_request_region(struct wbsd_host* host, int base)
L
Linus Torvalds 已提交
1511 1512 1513
{
	if (io & 0x7)
		return -EINVAL;
1514

P
Pierre Ossman 已提交
1515
	if (!request_region(base, 8, DRIVER_NAME))
L
Linus Torvalds 已提交
1516
		return -EIO;
1517

L
Linus Torvalds 已提交
1518
	host->base = io;
1519

L
Linus Torvalds 已提交
1520 1521 1522
	return 0;
}

P
Pierre Ossman 已提交
1523
static void __devexit wbsd_release_regions(struct wbsd_host* host)
L
Linus Torvalds 已提交
1524 1525 1526
{
	if (host->base)
		release_region(host->base, 8);
1527

P
Pierre Ossman 已提交
1528
	host->base = 0;
L
Linus Torvalds 已提交
1529 1530 1531

	if (host->config)
		release_region(host->config, 2);
1532

P
Pierre Ossman 已提交
1533
	host->config = 0;
L
Linus Torvalds 已提交
1534 1535
}

P
Pierre Ossman 已提交
1536 1537 1538 1539 1540
/*
 * Allocate/free DMA port and buffer
 */

static void __devinit wbsd_request_dma(struct wbsd_host* host, int dma)
L
Linus Torvalds 已提交
1541 1542 1543
{
	if (dma < 0)
		return;
1544

L
Linus Torvalds 已提交
1545 1546
	if (request_dma(dma, DRIVER_NAME))
		goto err;
1547

L
Linus Torvalds 已提交
1548 1549 1550 1551
	/*
	 * We need to allocate a special buffer in
	 * order for ISA to be able to DMA to it.
	 */
P
Pierre Ossman 已提交
1552
	host->dma_buffer = kmalloc(WBSD_DMA_SIZE,
L
Linus Torvalds 已提交
1553 1554 1555 1556 1557 1558 1559
		GFP_NOIO | GFP_DMA | __GFP_REPEAT | __GFP_NOWARN);
	if (!host->dma_buffer)
		goto free;

	/*
	 * Translate the address to a physical address.
	 */
P
Pierre Ossman 已提交
1560 1561
	host->dma_addr = dma_map_single(host->mmc->dev, host->dma_buffer,
		WBSD_DMA_SIZE, DMA_BIDIRECTIONAL);
1562

L
Linus Torvalds 已提交
1563 1564 1565 1566 1567 1568 1569 1570 1571 1572 1573 1574
	/*
	 * ISA DMA must be aligned on a 64k basis.
	 */
	if ((host->dma_addr & 0xffff) != 0)
		goto kfree;
	/*
	 * ISA cannot access memory above 16 MB.
	 */
	else if (host->dma_addr >= 0x1000000)
		goto kfree;

	host->dma = dma;
1575

L
Linus Torvalds 已提交
1576
	return;
1577

L
Linus Torvalds 已提交
1578 1579 1580 1581 1582
kfree:
	/*
	 * If we've gotten here then there is some kind of alignment bug
	 */
	BUG_ON(1);
1583

P
Pierre Ossman 已提交
1584 1585 1586
	dma_unmap_single(host->mmc->dev, host->dma_addr, WBSD_DMA_SIZE,
		DMA_BIDIRECTIONAL);
	host->dma_addr = (dma_addr_t)NULL;
1587

L
Linus Torvalds 已提交
1588 1589 1590 1591 1592 1593 1594 1595 1596 1597 1598
	kfree(host->dma_buffer);
	host->dma_buffer = NULL;

free:
	free_dma(dma);

err:
	printk(KERN_WARNING DRIVER_NAME ": Unable to allocate DMA %d. "
		"Falling back on FIFO.\n", dma);
}

P
Pierre Ossman 已提交
1599 1600 1601 1602 1603 1604 1605 1606 1607
static void __devexit wbsd_release_dma(struct wbsd_host* host)
{
	if (host->dma_addr)
		dma_unmap_single(host->mmc->dev, host->dma_addr, WBSD_DMA_SIZE,
			DMA_BIDIRECTIONAL);
	if (host->dma_buffer)
		kfree(host->dma_buffer);
	if (host->dma >= 0)
		free_dma(host->dma);
1608

P
Pierre Ossman 已提交
1609 1610 1611 1612
	host->dma = -1;
	host->dma_buffer = NULL;
	host->dma_addr = (dma_addr_t)NULL;
}
L
Linus Torvalds 已提交
1613 1614

/*
P
Pierre Ossman 已提交
1615
 * Allocate/free IRQ.
L
Linus Torvalds 已提交
1616 1617
 */

P
Pierre Ossman 已提交
1618
static int __devinit wbsd_request_irq(struct wbsd_host* host, int irq)
L
Linus Torvalds 已提交
1619 1620
{
	int ret;
1621

L
Linus Torvalds 已提交
1622
	/*
P
Pierre Ossman 已提交
1623
	 * Allocate interrupt.
L
Linus Torvalds 已提交
1624
	 */
P
Pierre Ossman 已提交
1625 1626 1627 1628

	ret = request_irq(irq, wbsd_irq, SA_SHIRQ, DRIVER_NAME, host);
	if (ret)
		return ret;
1629

P
Pierre Ossman 已提交
1630 1631
	host->irq = irq;

L
Linus Torvalds 已提交
1632
	/*
P
Pierre Ossman 已提交
1633
	 * Set up tasklets.
L
Linus Torvalds 已提交
1634
	 */
P
Pierre Ossman 已提交
1635 1636 1637 1638 1639 1640
	tasklet_init(&host->card_tasklet, wbsd_tasklet_card, (unsigned long)host);
	tasklet_init(&host->fifo_tasklet, wbsd_tasklet_fifo, (unsigned long)host);
	tasklet_init(&host->crc_tasklet, wbsd_tasklet_crc, (unsigned long)host);
	tasklet_init(&host->timeout_tasklet, wbsd_tasklet_timeout, (unsigned long)host);
	tasklet_init(&host->finish_tasklet, wbsd_tasklet_finish, (unsigned long)host);
	tasklet_init(&host->block_tasklet, wbsd_tasklet_block, (unsigned long)host);
1641

P
Pierre Ossman 已提交
1642 1643
	return 0;
}
L
Linus Torvalds 已提交
1644

P
Pierre Ossman 已提交
1645 1646 1647 1648
static void __devexit wbsd_release_irq(struct wbsd_host* host)
{
	if (!host->irq)
		return;
L
Linus Torvalds 已提交
1649

P
Pierre Ossman 已提交
1650
	free_irq(host->irq, host);
1651

P
Pierre Ossman 已提交
1652
	host->irq = 0;
1653

P
Pierre Ossman 已提交
1654 1655 1656 1657 1658 1659 1660 1661 1662 1663 1664 1665 1666 1667 1668 1669
	tasklet_kill(&host->card_tasklet);
	tasklet_kill(&host->fifo_tasklet);
	tasklet_kill(&host->crc_tasklet);
	tasklet_kill(&host->timeout_tasklet);
	tasklet_kill(&host->finish_tasklet);
	tasklet_kill(&host->block_tasklet);
}

/*
 * Allocate all resources for the host.
 */

static int __devinit wbsd_request_resources(struct wbsd_host* host,
	int base, int irq, int dma)
{
	int ret;
1670

L
Linus Torvalds 已提交
1671 1672 1673
	/*
	 * Allocate I/O ports.
	 */
P
Pierre Ossman 已提交
1674
	ret = wbsd_request_region(host, base);
L
Linus Torvalds 已提交
1675
	if (ret)
P
Pierre Ossman 已提交
1676
		return ret;
L
Linus Torvalds 已提交
1677 1678

	/*
P
Pierre Ossman 已提交
1679
	 * Allocate interrupt.
L
Linus Torvalds 已提交
1680
	 */
P
Pierre Ossman 已提交
1681 1682 1683 1684 1685 1686 1687 1688
	ret = wbsd_request_irq(host, irq);
	if (ret)
		return ret;

	/*
	 * Allocate DMA.
	 */
	wbsd_request_dma(host, dma);
1689

P
Pierre Ossman 已提交
1690 1691 1692 1693 1694 1695 1696 1697 1698 1699 1700 1701 1702 1703 1704 1705 1706 1707
	return 0;
}

/*
 * Release all resources for the host.
 */

static void __devexit wbsd_release_resources(struct wbsd_host* host)
{
	wbsd_release_dma(host);
	wbsd_release_irq(host);
	wbsd_release_regions(host);
}

/*
 * Configure the resources the chip should use.
 */

P
Pierre Ossman 已提交
1708
static void wbsd_chip_config(struct wbsd_host* host)
P
Pierre Ossman 已提交
1709
{
P
Pierre Ossman 已提交
1710 1711
	wbsd_unlock_config(host);

P
Pierre Ossman 已提交
1712 1713
	/*
	 * Reset the chip.
1714
	 */
P
Pierre Ossman 已提交
1715 1716
	wbsd_write_config(host, WBSD_CONF_SWRST, 1);
	wbsd_write_config(host, WBSD_CONF_SWRST, 0);
L
Linus Torvalds 已提交
1717 1718 1719 1720 1721

	/*
	 * Select SD/MMC function.
	 */
	wbsd_write_config(host, WBSD_CONF_DEVICE, DEVICE_SD);
1722

L
Linus Torvalds 已提交
1723 1724 1725
	/*
	 * Set up card detection.
	 */
P
Pierre Ossman 已提交
1726
	wbsd_write_config(host, WBSD_CONF_PINS, WBSD_PINS_DETECT_GP11);
1727

L
Linus Torvalds 已提交
1728
	/*
P
Pierre Ossman 已提交
1729
	 * Configure chip
L
Linus Torvalds 已提交
1730 1731 1732
	 */
	wbsd_write_config(host, WBSD_CONF_PORT_HI, host->base >> 8);
	wbsd_write_config(host, WBSD_CONF_PORT_LO, host->base & 0xff);
1733

P
Pierre Ossman 已提交
1734
	wbsd_write_config(host, WBSD_CONF_IRQ, host->irq);
1735

P
Pierre Ossman 已提交
1736 1737
	if (host->dma >= 0)
		wbsd_write_config(host, WBSD_CONF_DRQ, host->dma);
1738

L
Linus Torvalds 已提交
1739
	/*
P
Pierre Ossman 已提交
1740
	 * Enable and power up chip.
L
Linus Torvalds 已提交
1741
	 */
P
Pierre Ossman 已提交
1742 1743
	wbsd_write_config(host, WBSD_CONF_ENABLE, 1);
	wbsd_write_config(host, WBSD_CONF_POWER, 0x20);
P
Pierre Ossman 已提交
1744 1745

	wbsd_lock_config(host);
P
Pierre Ossman 已提交
1746 1747 1748 1749 1750
}

/*
 * Check that configured resources are correct.
 */
1751

P
Pierre Ossman 已提交
1752
static int wbsd_chip_validate(struct wbsd_host* host)
P
Pierre Ossman 已提交
1753 1754
{
	int base, irq, dma;
1755

P
Pierre Ossman 已提交
1756 1757
	wbsd_unlock_config(host);

L
Linus Torvalds 已提交
1758
	/*
P
Pierre Ossman 已提交
1759
	 * Select SD/MMC function.
L
Linus Torvalds 已提交
1760
	 */
P
Pierre Ossman 已提交
1761
	wbsd_write_config(host, WBSD_CONF_DEVICE, DEVICE_SD);
1762

L
Linus Torvalds 已提交
1763
	/*
P
Pierre Ossman 已提交
1764
	 * Read configuration.
L
Linus Torvalds 已提交
1765
	 */
P
Pierre Ossman 已提交
1766 1767
	base = wbsd_read_config(host, WBSD_CONF_PORT_HI) << 8;
	base |= wbsd_read_config(host, WBSD_CONF_PORT_LO);
1768

P
Pierre Ossman 已提交
1769
	irq = wbsd_read_config(host, WBSD_CONF_IRQ);
1770

P
Pierre Ossman 已提交
1771
	dma = wbsd_read_config(host, WBSD_CONF_DRQ);
1772

P
Pierre Ossman 已提交
1773 1774
	wbsd_lock_config(host);

L
Linus Torvalds 已提交
1775
	/*
P
Pierre Ossman 已提交
1776
	 * Validate against given configuration.
L
Linus Torvalds 已提交
1777
	 */
P
Pierre Ossman 已提交
1778 1779 1780 1781 1782 1783
	if (base != host->base)
		return 0;
	if (irq != host->irq)
		return 0;
	if ((dma != host->dma) && (host->dma != -1))
		return 0;
1784

P
Pierre Ossman 已提交
1785 1786 1787
	return 1;
}

P
Pierre Ossman 已提交
1788 1789 1790 1791 1792 1793 1794 1795 1796 1797 1798 1799 1800 1801
/*
 * Powers down the SD function
 */

static void wbsd_chip_poweroff(struct wbsd_host* host)
{
	wbsd_unlock_config(host);

	wbsd_write_config(host, WBSD_CONF_DEVICE, DEVICE_SD);
	wbsd_write_config(host, WBSD_CONF_ENABLE, 0);

	wbsd_lock_config(host);
}

P
Pierre Ossman 已提交
1802 1803 1804 1805 1806 1807 1808 1809 1810 1811 1812 1813
/*****************************************************************************\
 *                                                                           *
 * Devices setup and shutdown                                                *
 *                                                                           *
\*****************************************************************************/

static int __devinit wbsd_init(struct device* dev, int base, int irq, int dma,
	int pnp)
{
	struct wbsd_host* host = NULL;
	struct mmc_host* mmc = NULL;
	int ret;
1814

P
Pierre Ossman 已提交
1815 1816 1817
	ret = wbsd_alloc_mmc(dev);
	if (ret)
		return ret;
1818

P
Pierre Ossman 已提交
1819 1820
	mmc = dev_get_drvdata(dev);
	host = mmc_priv(mmc);
1821

L
Linus Torvalds 已提交
1822
	/*
P
Pierre Ossman 已提交
1823
	 * Scan for hardware.
L
Linus Torvalds 已提交
1824
	 */
P
Pierre Ossman 已提交
1825 1826 1827 1828 1829 1830 1831 1832 1833 1834 1835 1836 1837 1838 1839
	ret = wbsd_scan(host);
	if (ret)
	{
		if (pnp && (ret == -ENODEV))
		{
			printk(KERN_WARNING DRIVER_NAME
				": Unable to confirm device presence. You may "
				"experience lock-ups.\n");
		}
		else
		{
			wbsd_free_mmc(dev);
			return ret;
		}
	}
1840

L
Linus Torvalds 已提交
1841
	/*
P
Pierre Ossman 已提交
1842
	 * Request resources.
L
Linus Torvalds 已提交
1843
	 */
P
Pierre Ossman 已提交
1844 1845 1846 1847 1848 1849 1850
	ret = wbsd_request_resources(host, io, irq, dma);
	if (ret)
	{
		wbsd_release_resources(host);
		wbsd_free_mmc(dev);
		return ret;
	}
1851

L
Linus Torvalds 已提交
1852
	/*
P
Pierre Ossman 已提交
1853
	 * See if chip needs to be configured.
L
Linus Torvalds 已提交
1854
	 */
P
Pierre Ossman 已提交
1855 1856 1857 1858 1859 1860 1861 1862 1863 1864 1865 1866 1867
	if (pnp && (host->config != 0))
	{
		if (!wbsd_chip_validate(host))
		{
			printk(KERN_WARNING DRIVER_NAME
				": PnP active but chip not configured! "
				"You probably have a buggy BIOS. "
				"Configuring chip manually.\n");
			wbsd_chip_config(host);
		}
	}
	else
		wbsd_chip_config(host);
1868

L
Linus Torvalds 已提交
1869 1870 1871 1872 1873
	/*
	 * Power Management stuff. No idea how this works.
	 * Not tested.
	 */
#ifdef CONFIG_PM
P
Pierre Ossman 已提交
1874
	if (host->config)
P
Pierre Ossman 已提交
1875 1876
	{
		wbsd_unlock_config(host);
P
Pierre Ossman 已提交
1877
		wbsd_write_config(host, WBSD_CONF_PME, 0xA0);
P
Pierre Ossman 已提交
1878 1879
		wbsd_lock_config(host);
	}
L
Linus Torvalds 已提交
1880
#endif
P
Pierre Ossman 已提交
1881 1882 1883 1884
	/*
	 * Allow device to initialise itself properly.
	 */
	mdelay(5);
L
Linus Torvalds 已提交
1885 1886 1887 1888 1889

	/*
	 * Reset the chip into a known state.
	 */
	wbsd_init_device(host);
1890

L
Linus Torvalds 已提交
1891 1892
	mmc_add_host(mmc);

R
Russell King 已提交
1893
	printk(KERN_INFO "%s: W83L51xD", mmc_hostname(mmc));
P
Pierre Ossman 已提交
1894 1895 1896 1897 1898 1899 1900 1901 1902 1903
	if (host->chip_id != 0)
		printk(" id %x", (int)host->chip_id);
	printk(" at 0x%x irq %d", (int)host->base, (int)host->irq);
	if (host->dma >= 0)
		printk(" dma %d", (int)host->dma);
	else
		printk(" FIFO");
	if (pnp)
		printk(" PnP");
	printk("\n");
L
Linus Torvalds 已提交
1904 1905 1906 1907

	return 0;
}

P
Pierre Ossman 已提交
1908
static void __devexit wbsd_shutdown(struct device* dev, int pnp)
L
Linus Torvalds 已提交
1909 1910 1911
{
	struct mmc_host* mmc = dev_get_drvdata(dev);
	struct wbsd_host* host;
1912

L
Linus Torvalds 已提交
1913
	if (!mmc)
P
Pierre Ossman 已提交
1914
		return;
L
Linus Torvalds 已提交
1915 1916

	host = mmc_priv(mmc);
1917

L
Linus Torvalds 已提交
1918 1919
	mmc_remove_host(mmc);

P
Pierre Ossman 已提交
1920 1921 1922
	/*
	 * Power down the SD/MMC function.
	 */
P
Pierre Ossman 已提交
1923
	if (!pnp)
P
Pierre Ossman 已提交
1924
		wbsd_chip_poweroff(host);
1925

P
Pierre Ossman 已提交
1926
	wbsd_release_resources(host);
1927

P
Pierre Ossman 已提交
1928 1929
	wbsd_free_mmc(dev);
}
L
Linus Torvalds 已提交
1930

P
Pierre Ossman 已提交
1931 1932 1933 1934 1935 1936 1937 1938 1939 1940 1941 1942 1943 1944 1945 1946 1947 1948 1949 1950 1951 1952 1953 1954 1955 1956
/*
 * Non-PnP
 */

static int __devinit wbsd_probe(struct device* dev)
{
	return wbsd_init(dev, io, irq, dma, 0);
}

static int __devexit wbsd_remove(struct device* dev)
{
	wbsd_shutdown(dev, 0);

	return 0;
}

/*
 * PnP
 */

#ifdef CONFIG_PNP

static int __devinit
wbsd_pnp_probe(struct pnp_dev * pnpdev, const struct pnp_device_id *dev_id)
{
	int io, irq, dma;
1957

P
Pierre Ossman 已提交
1958 1959 1960 1961 1962 1963 1964 1965 1966
	/*
	 * Get resources from PnP layer.
	 */
	io = pnp_port_start(pnpdev, 0);
	irq = pnp_irq(pnpdev, 0);
	if (pnp_dma_valid(pnpdev, 0))
		dma = pnp_dma(pnpdev, 0);
	else
		dma = -1;
1967

P
Pierre Ossman 已提交
1968
	DBGF("PnP resources: port %3x irq %d dma %d\n", io, irq, dma);
1969

P
Pierre Ossman 已提交
1970 1971
	return wbsd_init(&pnpdev->dev, io, irq, dma, 1);
}
L
Linus Torvalds 已提交
1972

P
Pierre Ossman 已提交
1973 1974 1975
static void __devexit wbsd_pnp_remove(struct pnp_dev * dev)
{
	wbsd_shutdown(&dev->dev, 1);
L
Linus Torvalds 已提交
1976 1977
}

P
Pierre Ossman 已提交
1978 1979
#endif /* CONFIG_PNP */

L
Linus Torvalds 已提交
1980 1981 1982 1983 1984
/*
 * Power management
 */

#ifdef CONFIG_PM
P
Pierre Ossman 已提交
1985

1986
static int wbsd_suspend(struct device *dev, pm_message_t state)
L
Linus Torvalds 已提交
1987
{
P
Pierre Ossman 已提交
1988 1989 1990 1991 1992 1993 1994 1995 1996 1997 1998 1999 2000 2001 2002 2003
	struct mmc_host *mmc = dev_get_drvdata(dev);
	struct wbsd_host *host;
	int ret;

	if (!mmc)
		return 0;

	DBG("Suspending...\n");

	ret = mmc_suspend_host(mmc, state);
	if (!ret)
		return ret;

	host = mmc_priv(mmc);

	wbsd_chip_poweroff(host);
L
Linus Torvalds 已提交
2004 2005 2006 2007

	return 0;
}

2008
static int wbsd_resume(struct device *dev)
L
Linus Torvalds 已提交
2009
{
P
Pierre Ossman 已提交
2010 2011
	struct mmc_host *mmc = dev_get_drvdata(dev);
	struct wbsd_host *host;
L
Linus Torvalds 已提交
2012

P
Pierre Ossman 已提交
2013 2014 2015 2016 2017 2018 2019 2020 2021 2022 2023 2024 2025 2026 2027 2028 2029
	if (!mmc)
		return 0;

	DBG("Resuming...\n");

	host = mmc_priv(mmc);

	wbsd_chip_config(host);

	/*
	 * Allow device to initialise itself properly.
	 */
	mdelay(5);

	wbsd_init_device(host);

	return mmc_resume_host(mmc);
L
Linus Torvalds 已提交
2030
}
P
Pierre Ossman 已提交
2031 2032 2033

#else /* CONFIG_PM */

L
Linus Torvalds 已提交
2034 2035
#define wbsd_suspend NULL
#define wbsd_resume NULL
P
Pierre Ossman 已提交
2036 2037

#endif /* CONFIG_PM */
L
Linus Torvalds 已提交
2038

P
Pierre Ossman 已提交
2039
static struct platform_device *wbsd_device;
L
Linus Torvalds 已提交
2040 2041 2042 2043 2044 2045

static struct device_driver wbsd_driver = {
	.name		= DRIVER_NAME,
	.bus		= &platform_bus_type,
	.probe		= wbsd_probe,
	.remove		= wbsd_remove,
2046

L
Linus Torvalds 已提交
2047 2048 2049 2050
	.suspend	= wbsd_suspend,
	.resume		= wbsd_resume,
};

P
Pierre Ossman 已提交
2051 2052 2053 2054 2055 2056 2057 2058 2059 2060 2061
#ifdef CONFIG_PNP

static struct pnp_driver wbsd_pnp_driver = {
	.name		= DRIVER_NAME,
	.id_table	= pnp_dev_table,
	.probe		= wbsd_pnp_probe,
	.remove		= wbsd_pnp_remove,
};

#endif /* CONFIG_PNP */

L
Linus Torvalds 已提交
2062 2063 2064 2065 2066 2067 2068
/*
 * Module loading/unloading
 */

static int __init wbsd_drv_init(void)
{
	int result;
2069

L
Linus Torvalds 已提交
2070 2071 2072 2073 2074
	printk(KERN_INFO DRIVER_NAME
		": Winbond W83L51xD SD/MMC card interface driver, "
		DRIVER_VERSION "\n");
	printk(KERN_INFO DRIVER_NAME ": Copyright(c) Pierre Ossman\n");

P
Pierre Ossman 已提交
2075 2076 2077 2078 2079 2080 2081 2082 2083
#ifdef CONFIG_PNP

	if (!nopnp)
	{
		result = pnp_register_driver(&wbsd_pnp_driver);
		if (result < 0)
			return result;
	}

2084 2085
#endif /* CONFIG_PNP */

P
Pierre Ossman 已提交
2086 2087 2088 2089 2090 2091 2092 2093 2094 2095 2096
	if (nopnp)
	{
		result = driver_register(&wbsd_driver);
		if (result < 0)
			return result;

		wbsd_device = platform_device_register_simple(DRIVER_NAME, -1,
			NULL, 0);
		if (IS_ERR(wbsd_device))
			return PTR_ERR(wbsd_device);
	}
L
Linus Torvalds 已提交
2097 2098 2099 2100 2101 2102

	return 0;
}

static void __exit wbsd_drv_exit(void)
{
P
Pierre Ossman 已提交
2103 2104 2105 2106
#ifdef CONFIG_PNP

	if (!nopnp)
		pnp_unregister_driver(&wbsd_pnp_driver);
2107 2108

#endif /* CONFIG_PNP */
P
Pierre Ossman 已提交
2109 2110 2111 2112

	if (nopnp)
	{
		platform_device_unregister(wbsd_device);
2113

P
Pierre Ossman 已提交
2114 2115
		driver_unregister(&wbsd_driver);
	}
L
Linus Torvalds 已提交
2116 2117 2118 2119 2120 2121

	DBG("unloaded\n");
}

module_init(wbsd_drv_init);
module_exit(wbsd_drv_exit);
P
Pierre Ossman 已提交
2122 2123 2124
#ifdef CONFIG_PNP
module_param(nopnp, uint, 0444);
#endif
L
Linus Torvalds 已提交
2125 2126 2127 2128 2129 2130 2131 2132
module_param(io, uint, 0444);
module_param(irq, uint, 0444);
module_param(dma, int, 0444);

MODULE_LICENSE("GPL");
MODULE_DESCRIPTION("Winbond W83L51xD SD/MMC card interface driver");
MODULE_VERSION(DRIVER_VERSION);

P
Pierre Ossman 已提交
2133 2134 2135
#ifdef CONFIG_PNP
MODULE_PARM_DESC(nopnp, "Scan for device instead of relying on PNP. (default 0)");
#endif
L
Linus Torvalds 已提交
2136 2137 2138
MODULE_PARM_DESC(io, "I/O base to allocate. Must be 8 byte aligned. (default 0x248)");
MODULE_PARM_DESC(irq, "IRQ to allocate. (default 6)");
MODULE_PARM_DESC(dma, "DMA channel to allocate. -1 for no DMA. (default 2)");