/*
* linux/drivers/mmc/mmc.c
*
* Copyright (C) 2003-2004 Russell King, 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.
*/
#include <linux/config.h>
#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>
#include <linux/mmc/card.h>
#include <linux/mmc/host.h>
#include <linux/mmc/protocol.h>
#include "mmc.h"
#ifdef CONFIG_MMC_DEBUG
#define DBG(x...) printk(KERN_DEBUG x)
#else
#define DBG(x...) do { } while (0)
#endif
#define CMD_RETRIES 3
/*
* OCR Bit positions to 10s of Vdd mV.
*/
static const unsigned short mmc_ocr_bit_to_vdd[] = {
150, 155, 160, 165, 170, 180, 190, 200,
210, 220, 230, 240, 250, 260, 270, 280,
290, 300, 310, 320, 330, 340, 350, 360
};
static const unsigned int tran_exp[] = {
10000, 100000, 1000000, 10000000,
0, 0, 0, 0
};
static const unsigned char tran_mant[] = {
0, 10, 12, 13, 15, 20, 25, 30,
35, 40, 45, 50, 55, 60, 70, 80,
};
static const unsigned int tacc_exp[] = {
1, 10, 100, 1000, 10000, 100000, 1000000, 10000000,
};
static const unsigned int tacc_mant[] = {
0, 10, 12, 13, 15, 20, 25, 30,
35, 40, 45, 50, 55, 60, 70, 80,
};
/**
* mmc_request_done - finish processing an MMC command
* @host: MMC host which completed command
* @mrq: MMC request which completed
*
* MMC drivers should call this function when they have completed
* their processing of a command. This should be called before the
* data part of the command has completed.
*/
void mmc_request_done(struct mmc_host *host, struct mmc_request *mrq)
{
struct mmc_command *cmd = mrq->cmd;
int err = mrq->cmd->error;
DBG("MMC: req done (%02x): %d: %08x %08x %08x %08x\n", cmd->opcode,
err, cmd->resp[0], cmd->resp[1], cmd->resp[2], cmd->resp[3]);
if (err && cmd->retries) {
cmd->retries--;
cmd->error = 0;
host->ops->request(host, mrq);
} else if (mrq->done) {
mrq->done(mrq);
}
}
EXPORT_SYMBOL(mmc_request_done);
/**
* mmc_start_request - start a command on a host
* @host: MMC host to start command on
* @mrq: MMC request to start
*
* Queue a command on the specified host. We expect the
* caller to be holding the host lock with interrupts disabled.
*/
void
mmc_start_request(struct mmc_host *host, struct mmc_request *mrq)
{
DBG("MMC: starting cmd %02x arg %08x flags %08x\n",
mrq->cmd->opcode, mrq->cmd->arg, mrq->cmd->flags);
WARN_ON(host->card_busy == NULL);
mrq->cmd->error = 0;
mrq->cmd->mrq = mrq;
if (mrq->data) {
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);
}
EXPORT_SYMBOL(mmc_start_request);
static void mmc_wait_done(struct mmc_request *mrq)
{
complete(mrq->done_data);
}
int mmc_wait_for_req(struct mmc_host *host, struct mmc_request *mrq)
{
DECLARE_COMPLETION(complete);
mrq->done_data = &complete;
mrq->done = mmc_wait_done;
mmc_start_request(host, mrq);
wait_for_completion(&complete);
return 0;
}
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;
BUG_ON(host->card_busy == NULL);
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(