Ejemplo n.º 1
0
/*
 * Copy from sg to a dma block - used for transfers
 */
static inline void at91_mci_sg_to_dma(struct at91mci_host *host, struct mmc_data *data)
{
	unsigned int len, i, size;
	unsigned *dmabuf = host->buffer;

	size = data->blksz * data->blocks;
	len = data->sg_len;

	/* MCI1 rev2xx Data Write Operation and number of bytes erratum */
	if (at91mci_is_mci1rev2xx())
		if (host->total_length == 12)
			memset(dmabuf, 0, 12);

	/*
	 * 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++) {
		struct scatterlist *sg;
		int amount;
		unsigned int *sgbuffer;

		sg = &data->sg[i];

		sgbuffer = kmap_atomic(sg_page(sg), KM_BIO_SRC_IRQ) + sg->offset;
		amount = min(size, sg->length);
		size -= amount;

		if (cpu_is_at91rm9200()) {	/* AT91RM9200 errata */
			int index;

			for (index = 0; index < (amount / 4); index++)
				*dmabuf++ = swab32(sgbuffer[index]);
		} else {
			char *tmpv = (char *)dmabuf;
			memcpy(tmpv, sgbuffer, amount);
			tmpv += amount;
			dmabuf = (unsigned *)tmpv;
		}

		kunmap_atomic(sgbuffer, KM_BIO_SRC_IRQ);

		if (size == 0)
			break;
	}

	/*
	 * Check that we didn't get a request to transfer
	 * more data than can fit into the SG list.
	 */
	BUG_ON(size != 0);
}
Ejemplo n.º 2
0
static void at91_mci_enable(struct at91mci_host *host)
{
	unsigned int mr;

	at91_mci_write(host, AT91_MCI_CR, AT91_MCI_MCIEN);
	at91_mci_write(host, AT91_MCI_IDR, 0xffffffff);
	at91_mci_write(host, AT91_MCI_DTOR, AT91_MCI_DTOMUL_1M | AT91_MCI_DTOCYC);
	mr = AT91_MCI_PDCMODE | 0x34a;

	if (at91mci_is_mci1rev2xx())
		mr |= AT91_MCI_RDPROOF | AT91_MCI_WRPROOF;

	at91_mci_write(host, AT91_MCI_MR, mr);

	
	at91_mci_write(host, AT91_MCI_SDCR, host->board->slot_b);
}
Ejemplo n.º 3
0
static inline void at91_mci_sg_to_dma(struct at91mci_host *host, struct mmc_data *data)
{
	unsigned int len, i, size;
	unsigned *dmabuf = host->buffer;

	size = data->blksz * data->blocks;
	len = data->sg_len;

	
	if (at91mci_is_mci1rev2xx())
		if (host->total_length == 12)
			memset(dmabuf, 0, 12);

	for (i = 0; i < len; i++) {
		struct scatterlist *sg;
		int amount;
		unsigned int *sgbuffer;

		sg = &data->sg[i];

		sgbuffer = kmap_atomic(sg_page(sg)) + sg->offset;
		amount = min(size, sg->length);
		size -= amount;

		if (cpu_is_at91rm9200()) {	
			int index;

			for (index = 0; index < (amount / 4); index++)
				*dmabuf++ = swab32(sgbuffer[index]);
		} else {
			char *tmpv = (char *)dmabuf;
			memcpy(tmpv, sgbuffer, amount);
			tmpv += amount;
			dmabuf = (unsigned *)tmpv;
		}

		kunmap_atomic(sgbuffer);

		if (size == 0)
			break;
	}

	BUG_ON(size != 0);
}
Ejemplo n.º 4
0
static int __init at91_mci_probe(struct platform_device *pdev)
{
	struct mmc_host *mmc;
	struct at91mci_host *host;
	struct resource *res;
	int ret;

	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
	if (!res)
		return -ENXIO;

	if (!request_mem_region(res->start, resource_size(res), DRIVER_NAME))
		return -EBUSY;

	mmc = mmc_alloc_host(sizeof(struct at91mci_host), &pdev->dev);
	if (!mmc) {
		ret = -ENOMEM;
		dev_dbg(&pdev->dev, "couldn't allocate mmc host\n");
		goto fail6;
	}

	mmc->ops = &at91_mci_ops;
	mmc->f_min = 375000;
	mmc->f_max = 25000000;
	mmc->ocr_avail = MMC_VDD_32_33 | MMC_VDD_33_34;
	mmc->caps = 0;

	mmc->max_blk_size  = MCI_MAXBLKSIZE;
	mmc->max_blk_count = MCI_BLKATONCE;
	mmc->max_req_size  = MCI_BUFSIZE;
	mmc->max_segs      = MCI_BLKATONCE;
	mmc->max_seg_size  = MCI_BUFSIZE;

	host = mmc_priv(mmc);
	host->mmc = mmc;
	host->bus_mode = 0;
	host->board = pdev->dev.platform_data;
	if (host->board->wire4) {
		if (at91mci_is_mci1rev2xx())
			mmc->caps |= MMC_CAP_4_BIT_DATA;
		else
			dev_warn(&pdev->dev, "4 wire bus mode not supported"
				" - using 1 wire\n");
	}

	host->buffer = dma_alloc_coherent(&pdev->dev, MCI_BUFSIZE,
					&host->physical_address, GFP_KERNEL);
	if (!host->buffer) {
		ret = -ENOMEM;
		dev_err(&pdev->dev, "Can't allocate transmit buffer\n");
		goto fail5;
	}

	
	if (at91mci_is_mci1rev2xx()) {
		
		if (host->board->wire4 || !host->board->slot_b)
			mmc->caps |= MMC_CAP_SDIO_IRQ;
	}

	if (gpio_is_valid(host->board->det_pin)) {
		ret = gpio_request(host->board->det_pin, "mmc_detect");
		if (ret < 0) {
			dev_dbg(&pdev->dev, "couldn't claim card detect pin\n");
			goto fail4b;
		}
	}
	if (gpio_is_valid(host->board->wp_pin)) {
		ret = gpio_request(host->board->wp_pin, "mmc_wp");
		if (ret < 0) {
			dev_dbg(&pdev->dev, "couldn't claim wp sense pin\n");
			goto fail4;
		}
	}
	if (gpio_is_valid(host->board->vcc_pin)) {
		ret = gpio_request(host->board->vcc_pin, "mmc_vcc");
		if (ret < 0) {
			dev_dbg(&pdev->dev, "couldn't claim vcc switch pin\n");
			goto fail3;
		}
	}

	host->mci_clk = clk_get(&pdev->dev, "mci_clk");
	if (IS_ERR(host->mci_clk)) {
		ret = -ENODEV;
		dev_dbg(&pdev->dev, "no mci_clk?\n");
		goto fail2;
	}

	host->baseaddr = ioremap(res->start, resource_size(res));
	if (!host->baseaddr) {
		ret = -ENOMEM;
		goto fail1;
	}

	clk_enable(host->mci_clk);		
	at91_mci_disable(host);
	at91_mci_enable(host);

	host->irq = platform_get_irq(pdev, 0);
	ret = request_irq(host->irq, at91_mci_irq, IRQF_SHARED,
			mmc_hostname(mmc), host);
	if (ret) {
		dev_dbg(&pdev->dev, "request MCI interrupt failed\n");
		goto fail0;
	}

	setup_timer(&host->timer, at91_timeout_timer, (unsigned long)host);

	platform_set_drvdata(pdev, mmc);

	if (gpio_is_valid(host->board->det_pin)) {
		host->present = !gpio_get_value(host->board->det_pin);
	}
	else
		host->present = -1;

	mmc_add_host(mmc);

	if (gpio_is_valid(host->board->det_pin)) {
		ret = request_irq(gpio_to_irq(host->board->det_pin),
				at91_mmc_det_irq, 0, mmc_hostname(mmc), host);
		if (ret)
			dev_warn(&pdev->dev, "request MMC detect irq failed\n");
		else
			device_init_wakeup(&pdev->dev, 1);
	}

	pr_debug("Added MCI driver\n");

	return 0;

fail0:
	clk_disable(host->mci_clk);
	iounmap(host->baseaddr);
fail1:
	clk_put(host->mci_clk);
fail2:
	if (gpio_is_valid(host->board->vcc_pin))
		gpio_free(host->board->vcc_pin);
fail3:
	if (gpio_is_valid(host->board->wp_pin))
		gpio_free(host->board->wp_pin);
fail4:
	if (gpio_is_valid(host->board->det_pin))
		gpio_free(host->board->det_pin);
fail4b:
	if (host->buffer)
		dma_free_coherent(&pdev->dev, MCI_BUFSIZE,
				host->buffer, host->physical_address);
fail5:
	mmc_free_host(mmc);
fail6:
	release_mem_region(res->start, resource_size(res));
	dev_err(&pdev->dev, "probe failed, err %d\n", ret);
	return ret;
}
Ejemplo n.º 5
0
static void at91_mci_send_command(struct at91mci_host *host, struct mmc_command *cmd)
{
	unsigned int cmdr, mr;
	unsigned int block_length;
	struct mmc_data *data = cmd->data;

	unsigned int blocks;
	unsigned int ier = 0;

	host->cmd = cmd;

	
	if ((at91_mci_read(host, AT91_MCI_SR) & AT91_MCI_RTOE) && (cmd->opcode == 1)) {
		pr_debug("Clearing timeout\n");
		at91_mci_write(host, AT91_MCI_ARGR, 0);
		at91_mci_write(host, AT91_MCI_CMDR, AT91_MCI_OPDCMD);
		while (!(at91_mci_read(host, AT91_MCI_SR) & AT91_MCI_CMDRDY)) {
			
			pr_debug("Clearing: SR = %08X\n", at91_mci_read(host, AT91_MCI_SR));
		}
	}

	cmdr = cmd->opcode;

	if (mmc_resp_type(cmd) == MMC_RSP_NONE)
		cmdr |= AT91_MCI_RSPTYP_NONE;
	else {
		
		cmdr |= AT91_MCI_MAXLAT;
		
		if (mmc_resp_type(cmd) == MMC_RSP_R2)
			cmdr |= AT91_MCI_RSPTYP_136;
		else
			cmdr |= AT91_MCI_RSPTYP_48;
	}

	if (data) {

		if (cpu_is_at91rm9200() || cpu_is_at91sam9261()) {
			if (data->blksz & 0x3) {
				pr_debug("Unsupported block size\n");
				cmd->error = -EINVAL;
				mmc_request_done(host->mmc, host->request);
				return;
			}
			if (data->flags & MMC_DATA_STREAM) {
				pr_debug("Stream commands not supported\n");
				cmd->error = -EINVAL;
				mmc_request_done(host->mmc, host->request);
				return;
			}
		}

		block_length = data->blksz;
		blocks = data->blocks;

		
		if (data->flags & MMC_DATA_READ)
			cmdr |= (AT91_MCI_TRDIR | AT91_MCI_TRCMD_START);
		else if (data->flags & MMC_DATA_WRITE)
			cmdr |= AT91_MCI_TRCMD_START;

		if (cmd->opcode == SD_IO_RW_EXTENDED) {
			cmdr |= AT91_MCI_TRTYP_SDIO_BLOCK;
		} else {
			if (data->flags & MMC_DATA_STREAM)
				cmdr |= AT91_MCI_TRTYP_STREAM;
			if (data->blocks > 1)
				cmdr |= AT91_MCI_TRTYP_MULTIPLE;
		}
	}
	else {
		block_length = 0;
		blocks = 0;
	}

	if (host->flags & FL_SENT_STOP)
		cmdr |= AT91_MCI_TRCMD_STOP;

	if (host->bus_mode == MMC_BUSMODE_OPENDRAIN)
		cmdr |= AT91_MCI_OPDCMD;

	pr_debug("Sending command %d as %08X, arg = %08X, blocks = %d, length = %d (MR = %08X)\n",
		cmd->opcode, cmdr, cmd->arg, blocks, block_length, at91_mci_read(host, AT91_MCI_MR));

	if (!data) {
		at91_mci_write(host, ATMEL_PDC_PTCR, ATMEL_PDC_TXTDIS | ATMEL_PDC_RXTDIS);
		at91_mci_write(host, ATMEL_PDC_RPR, 0);
		at91_mci_write(host, ATMEL_PDC_RCR, 0);
		at91_mci_write(host, ATMEL_PDC_RNPR, 0);
		at91_mci_write(host, ATMEL_PDC_RNCR, 0);
		at91_mci_write(host, ATMEL_PDC_TPR, 0);
		at91_mci_write(host, ATMEL_PDC_TCR, 0);
		at91_mci_write(host, ATMEL_PDC_TNPR, 0);
		at91_mci_write(host, ATMEL_PDC_TNCR, 0);
		ier = AT91_MCI_CMDRDY;
	} else {
		
		mr = at91_mci_read(host, AT91_MCI_MR) & 0x5fff;
		mr |= (data->blksz & 0x3) ? AT91_MCI_PDCFBYTE : 0;
		mr |= (block_length << 16);
		mr |= AT91_MCI_PDCMODE;
		at91_mci_write(host, AT91_MCI_MR, mr);

		if (!(cpu_is_at91rm9200() || cpu_is_at91sam9261()))
			at91_mci_write(host, AT91_MCI_BLKR,
				AT91_MCI_BLKR_BCNT(blocks) |
				AT91_MCI_BLKR_BLKLEN(block_length));

		at91_mci_write(host, ATMEL_PDC_PTCR, ATMEL_PDC_RXTDIS | ATMEL_PDC_TXTDIS);

		if (cmdr & AT91_MCI_TRCMD_START) {
			data->bytes_xfered = 0;
			host->transfer_index = 0;
			host->in_use_index = 0;
			if (cmdr & AT91_MCI_TRDIR) {
				host->total_length = 0;

				at91_mci_write(host, ATMEL_PDC_RPR, host->physical_address);
				at91_mci_write(host, ATMEL_PDC_RCR, (data->blksz & 0x3) ?
					(blocks * block_length) : (blocks * block_length) / 4);
				at91_mci_write(host, ATMEL_PDC_RNPR, 0);
				at91_mci_write(host, ATMEL_PDC_RNCR, 0);

				ier = AT91_MCI_ENDRX ;
			}
			else {
				host->total_length = block_length * blocks;
				if (at91mci_is_mci1rev2xx())
					if (host->total_length < 12)
						host->total_length = 12;

				at91_mci_sg_to_dma(host, data);

				pr_debug("Transmitting %d bytes\n", host->total_length);

				at91_mci_write(host, ATMEL_PDC_TPR, host->physical_address);
				at91_mci_write(host, ATMEL_PDC_TCR, (data->blksz & 0x3) ?
						host->total_length : host->total_length / 4);

				ier = AT91_MCI_CMDRDY;
			}
		}
	}


	at91_mci_write(host, AT91_MCI_ARGR, cmd->arg);
	at91_mci_write(host, AT91_MCI_CMDR, cmdr);

	if (cmdr & AT91_MCI_TRCMD_START) {
		if (cmdr & AT91_MCI_TRDIR)
			at91_mci_write(host, ATMEL_PDC_PTCR, ATMEL_PDC_RXTEN);
	}

	
	at91_mci_write(host, AT91_MCI_IER, AT91_MCI_ERRORS | ier);
}
Ejemplo n.º 6
0
/*
 * Send a command
 */
static void at91_mci_send_command(struct at91mci_host *host, struct mmc_command *cmd)
{
	unsigned int cmdr, mr;
	unsigned int block_length;
	struct mmc_data *data = cmd->data;

	unsigned int blocks;
	unsigned int ier = 0;

	host->cmd = cmd;

	/* Needed for leaving busy state before CMD1 */
	if ((at91_mci_read(host, AT91_MCI_SR) & AT91_MCI_RTOE) && (cmd->opcode == 1)) {
		pr_debug("Clearing timeout\n");
		at91_mci_write(host, AT91_MCI_ARGR, 0);
		at91_mci_write(host, AT91_MCI_CMDR, AT91_MCI_OPDCMD);
		while (!(at91_mci_read(host, AT91_MCI_SR) & AT91_MCI_CMDRDY)) {
			/* spin */
			pr_debug("Clearing: SR = %08X\n", at91_mci_read(host, AT91_MCI_SR));
		}
	}

	cmdr = cmd->opcode;

	if (mmc_resp_type(cmd) == MMC_RSP_NONE)
		cmdr |= AT91_MCI_RSPTYP_NONE;
	else {
		/* if a response is expected then allow maximum response latancy */
		cmdr |= AT91_MCI_MAXLAT;
		/* set 136 bit response for R2, 48 bit response otherwise */
		if (mmc_resp_type(cmd) == MMC_RSP_R2)
			cmdr |= AT91_MCI_RSPTYP_136;
		else
			cmdr |= AT91_MCI_RSPTYP_48;
	}

	if (data) {

		if (cpu_is_at91rm9200() || cpu_is_at91sam9261()) {
			if (data->blksz & 0x3) {
				pr_debug("Unsupported block size\n");
				cmd->error = -EINVAL;
				mmc_request_done(host->mmc, host->request);
				return;
			}
			if (data->flags & MMC_DATA_STREAM) {
				pr_debug("Stream commands not supported\n");
				cmd->error = -EINVAL;
				mmc_request_done(host->mmc, host->request);
				return;
			}
		}

		block_length = data->blksz;
		blocks = data->blocks;

		/* always set data start - also set direction flag for read */
		if (data->flags & MMC_DATA_READ)
			cmdr |= (AT91_MCI_TRDIR | AT91_MCI_TRCMD_START);
		else if (data->flags & MMC_DATA_WRITE)
			cmdr |= AT91_MCI_TRCMD_START;

		if (cmd->opcode == SD_IO_RW_EXTENDED) {
			cmdr |= AT91_MCI_TRTYP_SDIO_BLOCK;
		} else {
			if (data->flags & MMC_DATA_STREAM)
				cmdr |= AT91_MCI_TRTYP_STREAM;
			if (data->blocks > 1)
				cmdr |= AT91_MCI_TRTYP_MULTIPLE;
		}
	}
	else {
		block_length = 0;
		blocks = 0;
	}

	if (host->flags & FL_SENT_STOP)
		cmdr |= AT91_MCI_TRCMD_STOP;

	if (host->bus_mode == MMC_BUSMODE_OPENDRAIN)
		cmdr |= AT91_MCI_OPDCMD;

	/*
	 * Set the arguments and send the command
	 */
	pr_debug("Sending command %d as %08X, arg = %08X, blocks = %d, length = %d (MR = %08X)\n",
		cmd->opcode, cmdr, cmd->arg, blocks, block_length, at91_mci_read(host, AT91_MCI_MR));

	if (!data) {
		at91_mci_write(host, ATMEL_PDC_PTCR, ATMEL_PDC_TXTDIS | ATMEL_PDC_RXTDIS);
		at91_mci_write(host, ATMEL_PDC_RPR, 0);
		at91_mci_write(host, ATMEL_PDC_RCR, 0);
		at91_mci_write(host, ATMEL_PDC_RNPR, 0);
		at91_mci_write(host, ATMEL_PDC_RNCR, 0);
		at91_mci_write(host, ATMEL_PDC_TPR, 0);
		at91_mci_write(host, ATMEL_PDC_TCR, 0);
		at91_mci_write(host, ATMEL_PDC_TNPR, 0);
		at91_mci_write(host, ATMEL_PDC_TNCR, 0);
		ier = AT91_MCI_CMDRDY;
	} else {
		/* zero block length and PDC mode */
		mr = at91_mci_read(host, AT91_MCI_MR) & 0x5fff;
		mr |= (data->blksz & 0x3) ? AT91_MCI_PDCFBYTE : 0;
		mr |= (block_length << 16);
		mr |= AT91_MCI_PDCMODE;
		at91_mci_write(host, AT91_MCI_MR, mr);

		if (!(cpu_is_at91rm9200() || cpu_is_at91sam9261()))
			at91_mci_write(host, AT91_MCI_BLKR,
				AT91_MCI_BLKR_BCNT(blocks) |
				AT91_MCI_BLKR_BLKLEN(block_length));

		/*
		 * Disable the PDC controller
		 */
		at91_mci_write(host, ATMEL_PDC_PTCR, ATMEL_PDC_RXTDIS | ATMEL_PDC_TXTDIS);

		if (cmdr & AT91_MCI_TRCMD_START) {
			data->bytes_xfered = 0;
			host->transfer_index = 0;
			host->in_use_index = 0;
			if (cmdr & AT91_MCI_TRDIR) {
				/*
				 * Handle a read
				 */
				host->total_length = 0;

				at91_mci_write(host, ATMEL_PDC_RPR, host->physical_address);
				at91_mci_write(host, ATMEL_PDC_RCR, (data->blksz & 0x3) ?
					(blocks * block_length) : (blocks * block_length) / 4);
				at91_mci_write(host, ATMEL_PDC_RNPR, 0);
				at91_mci_write(host, ATMEL_PDC_RNCR, 0);

				ier = AT91_MCI_ENDRX /* | AT91_MCI_RXBUFF */;
			}
			else {
				/*
				 * Handle a write
				 */
				host->total_length = block_length * blocks;
				/*
				 * MCI1 rev2xx Data Write Operation and
				 * number of bytes erratum
				 */
				if (at91mci_is_mci1rev2xx())
					if (host->total_length < 12)
						host->total_length = 12;

				at91_mci_sg_to_dma(host, data);

				pr_debug("Transmitting %d bytes\n", host->total_length);

				at91_mci_write(host, ATMEL_PDC_TPR, host->physical_address);
				at91_mci_write(host, ATMEL_PDC_TCR, (data->blksz & 0x3) ?
						host->total_length : host->total_length / 4);

				ier = AT91_MCI_CMDRDY;
			}
		}
	}

	/*
	 * Send the command and then enable the PDC - not the other way round as
	 * the data sheet says
	 */

	at91_mci_write(host, AT91_MCI_ARGR, cmd->arg);
	at91_mci_write(host, AT91_MCI_CMDR, cmdr);

	if (cmdr & AT91_MCI_TRCMD_START) {
		if (cmdr & AT91_MCI_TRDIR)
			at91_mci_write(host, ATMEL_PDC_PTCR, ATMEL_PDC_RXTEN);
	}

	/* Enable selected interrupts */
	at91_mci_write(host, AT91_MCI_IER, AT91_MCI_ERRORS | ier);
}
Ejemplo n.º 7
0
/*
 * Probe for the device
 */
static int __init at91_mci_probe(struct platform_device *pdev)
{
	struct mmc_host *mmc;
	struct at91mci_host *host;
	struct resource *res;
	int ret;

	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
	if (!res)
		return -ENXIO;

	if (!request_mem_region(res->start, res->end - res->start + 1, DRIVER_NAME))
		return -EBUSY;

	mmc = mmc_alloc_host(sizeof(struct at91mci_host), &pdev->dev);
	if (!mmc) {
		ret = -ENOMEM;
		dev_dbg(&pdev->dev, "couldn't allocate mmc host\n");
		goto fail6;
	}

	mmc->ops = &at91_mci_ops;
	mmc->f_min = 375000;
	mmc->f_max = 25000000;
	mmc->ocr_avail = MMC_VDD_32_33 | MMC_VDD_33_34;
	mmc->caps = 0;

	mmc->max_blk_size = 4095;
	mmc->max_blk_count = mmc->max_req_size;

	host = mmc_priv(mmc);
	host->mmc = mmc;
	host->buffer = NULL;
	host->bus_mode = 0;
	host->board = pdev->dev.platform_data;
	if (host->board->wire4) {
		if (at91mci_is_mci1rev2xx())
			mmc->caps |= MMC_CAP_4_BIT_DATA;
		else
			dev_warn(&pdev->dev, "4 wire bus mode not supported"
				" - using 1 wire\n");
	}

	/* Add SDIO capability when available */
	if (at91mci_is_mci1rev2xx()) {
		/* at91mci MCI1 rev2xx sdio interrupt erratum */
		if (host->board->wire4 || !host->board->slot_b)
			mmc->caps |= MMC_CAP_SDIO_IRQ;
	}

	/*
	 * Reserve GPIOs ... board init code makes sure these pins are set
	 * up as GPIOs with the right direction (input, except for vcc)
	 */
	if (host->board->det_pin) {
		ret = gpio_request(host->board->det_pin, "mmc_detect");
		if (ret < 0) {
			dev_dbg(&pdev->dev, "couldn't claim card detect pin\n");
			goto fail5;
		}
	}
	if (host->board->wp_pin) {
		ret = gpio_request(host->board->wp_pin, "mmc_wp");
		if (ret < 0) {
			dev_dbg(&pdev->dev, "couldn't claim wp sense pin\n");
			goto fail4;
		}
	}
	if (host->board->vcc_pin) {
		ret = gpio_request(host->board->vcc_pin, "mmc_vcc");
		if (ret < 0) {
			dev_dbg(&pdev->dev, "couldn't claim vcc switch pin\n");
			goto fail3;
		}
	}

	/*
	 * Get Clock
	 */
	host->mci_clk = clk_get(&pdev->dev, "mci_clk");
	if (IS_ERR(host->mci_clk)) {
		ret = -ENODEV;
		dev_dbg(&pdev->dev, "no mci_clk?\n");
		goto fail2;
	}

	/*
	 * Map I/O region
	 */
	host->baseaddr = ioremap(res->start, res->end - res->start + 1);
	if (!host->baseaddr) {
		ret = -ENOMEM;
		goto fail1;
	}

	/*
	 * Reset hardware
	 */
	clk_enable(host->mci_clk);		/* Enable the peripheral clock */
	at91_mci_disable(host);
	at91_mci_enable(host);

	/*
	 * Allocate the MCI interrupt
	 */
	host->irq = platform_get_irq(pdev, 0);
	ret = request_irq(host->irq, at91_mci_irq, IRQF_SHARED,
			mmc_hostname(mmc), host);
	if (ret) {
		dev_dbg(&pdev->dev, "request MCI interrupt failed\n");
		goto fail0;
	}

	setup_timer(&host->timer, at91_timeout_timer, (unsigned long)host);

	platform_set_drvdata(pdev, mmc);

	/*
	 * Add host to MMC layer
	 */
	if (host->board->det_pin) {
		host->present = !gpio_get_value(host->board->det_pin);
	}
	else
		host->present = -1;

	mmc_add_host(mmc);

	/*
	 * monitor card insertion/removal if we can
	 */
	if (host->board->det_pin) {
		ret = request_irq(gpio_to_irq(host->board->det_pin),
				at91_mmc_det_irq, 0, mmc_hostname(mmc), host);
		if (ret)
			dev_warn(&pdev->dev, "request MMC detect irq failed\n");
		else
			device_init_wakeup(&pdev->dev, 1);
	}

	pr_debug("Added MCI driver\n");

	return 0;

fail0:
	clk_disable(host->mci_clk);
	iounmap(host->baseaddr);
fail1:
	clk_put(host->mci_clk);
fail2:
	if (host->board->vcc_pin)
		gpio_free(host->board->vcc_pin);
fail3:
	if (host->board->wp_pin)
		gpio_free(host->board->wp_pin);
fail4:
	if (host->board->det_pin)
		gpio_free(host->board->det_pin);
fail5:
	mmc_free_host(mmc);
fail6:
	release_mem_region(res->start, res->end - res->start + 1);
	dev_err(&pdev->dev, "probe failed, err %d\n", ret);
	return ret;
}