Skip to content

Commit

Permalink
---
Browse files Browse the repository at this point in the history
yaml
---
r: 53563
b: refs/heads/master
c: 72dc9d9
h: refs/heads/master
i:
  53561: 7c32668
  53559: a225130
v: v3
  • Loading branch information
Alex Dubov authored and Pierre Ossman committed May 1, 2007
1 parent 71ef687 commit 6c6ef94
Show file tree
Hide file tree
Showing 3 changed files with 139 additions and 123 deletions.
2 changes: 1 addition & 1 deletion [refs]
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
---
refs/heads/master: dfef26d9aad4f983da232b259ee7f7faec479b2d
refs/heads/master: 72dc9d9619dd4682f4197e7a7f19af22fd6516a7
259 changes: 137 additions & 122 deletions trunk/drivers/mmc/tifm_sd.c
Original file line number Diff line number Diff line change
Expand Up @@ -70,19 +70,14 @@ module_param(fixed_timeout, bool, 0644);
#define TIFM_MMCSD_CMD_AC 0x2000
#define TIFM_MMCSD_CMD_ADTC 0x3000

typedef enum {
IDLE = 0,
CMD, /* main command ended */
BRS, /* block transfer finished */
SCMD, /* stop command ended */
CARD, /* card left busy state */
FIFO, /* FIFO operation completed (uncertain) */
READY
} card_state_t;

enum {
FIFO_RDY = 0x0001, /* hardware dependent value */
CARD_BUSY = 0x0010
CMD_READY = 0x0001,
FIFO_READY = 0x0002,
BRS_READY = 0x0004,
SCMD_ACTIVE = 0x0008,
SCMD_READY = 0x0010,
CARD_BUSY = 0x0020,
DATA_CARRY = 0x0040
};

struct tifm_sd {
Expand All @@ -92,7 +87,7 @@ struct tifm_sd {
open_drain:1,
no_dma:1;
unsigned short cmd_flags;
card_state_t state;

unsigned int clk_freq;
unsigned int clk_div;
unsigned long timeout_jiffies;
Expand Down Expand Up @@ -234,170 +229,191 @@ static void tifm_sd_fetch_resp(struct mmc_command *cmd, struct tifm_dev *sock)
| readl(sock->addr + SOCK_MMCSD_RESPONSE + 0x00);
}

static void tifm_sd_process_cmd(struct tifm_dev *sock, struct tifm_sd *host,
unsigned int host_status)
static void tifm_sd_check_status(struct tifm_sd *host)
{
struct tifm_dev *sock = host->dev;
struct mmc_command *cmd = host->req->cmd;

change_state:
switch (host->state) {
case IDLE:
if (cmd->error != MMC_ERR_NONE)
goto finish_request;

if (!(host->cmd_flags & CMD_READY))
return;
case CMD:
if (host_status & (TIFM_MMCSD_EOC | TIFM_MMCSD_CERR)) {
tifm_sd_fetch_resp(cmd, sock);
if (cmd->data) {
host->state = BRS;
} else {
host->state = READY;
}
goto change_state;
}
break;
case BRS:
if (tifm_sd_transfer_data(sock, host, host_status)) {
if (cmd->data->flags & MMC_DATA_WRITE) {
host->state = CARD;
} else {
if (host->no_dma) {
if (host->req->stop) {
tifm_sd_exec(host, host->req->stop);
host->state = SCMD;
} else {
host->state = READY;
}
} else {
host->state = FIFO;
}
}
goto change_state;
}
break;
case SCMD:
if (host_status & TIFM_MMCSD_EOC) {
tifm_sd_fetch_resp(host->req->stop, sock);
host->state = READY;
goto change_state;

if (cmd->data) {
if (cmd->data->error != MMC_ERR_NONE) {
if ((host->cmd_flags & SCMD_ACTIVE)
&& !(host->cmd_flags & SCMD_READY))
return;

goto finish_request;
}
break;
case CARD:
dev_dbg(&sock->dev, "waiting for CARD, have %zd blocks\n",
host->written_blocks);
if (!(host->cmd_flags & CARD_BUSY)
&& (host->written_blocks == cmd->data->blocks)) {
if (host->no_dma) {
if (host->req->stop) {

if (!(host->cmd_flags & BRS_READY))
return;

if (!(host->no_dma || (host->cmd_flags & FIFO_READY)))
return;

if (cmd->data->flags & MMC_DATA_WRITE) {
if (host->req->stop) {
if (!(host->cmd_flags & SCMD_ACTIVE)) {
host->cmd_flags |= SCMD_ACTIVE;
writel(TIFM_MMCSD_EOFB
| readl(sock->addr
+ SOCK_MMCSD_INT_ENABLE),
sock->addr
+ SOCK_MMCSD_INT_ENABLE);
tifm_sd_exec(host, host->req->stop);
host->state = SCMD;
return;
} else {
host->state = READY;
if (!(host->cmd_flags & SCMD_READY)
|| (host->cmd_flags & CARD_BUSY))
return;
writel((~TIFM_MMCSD_EOFB)
& readl(sock->addr
+ SOCK_MMCSD_INT_ENABLE),
sock->addr
+ SOCK_MMCSD_INT_ENABLE);
}
} else {
host->state = FIFO;
if (host->cmd_flags & CARD_BUSY)
return;
writel((~TIFM_MMCSD_EOFB)
& readl(sock->addr
+ SOCK_MMCSD_INT_ENABLE),
sock->addr + SOCK_MMCSD_INT_ENABLE);
}
goto change_state;
}
break;
case FIFO:
if (host->cmd_flags & FIFO_RDY) {
host->cmd_flags &= ~FIFO_RDY;
} else {
if (host->req->stop) {
tifm_sd_exec(host, host->req->stop);
host->state = SCMD;
} else {
host->state = READY;
if (!(host->cmd_flags & SCMD_ACTIVE)) {
host->cmd_flags |= SCMD_ACTIVE;
tifm_sd_exec(host, host->req->stop);
return;
} else {
if (!(host->cmd_flags & SCMD_READY))
return;
}
}
goto change_state;
}
break;
case READY:
tasklet_schedule(&host->finish_tasklet);
return;
}

finish_request:
tasklet_schedule(&host->finish_tasklet);
}

/* Called from interrupt handler */
static void tifm_sd_data_event(struct tifm_dev *sock)
{
struct tifm_sd *host;
unsigned int fifo_status = 0;
struct mmc_data *r_data = NULL;

spin_lock(&sock->lock);
host = mmc_priv((struct mmc_host*)tifm_get_drvdata(sock));

fifo_status = readl(sock->addr + SOCK_DMA_FIFO_STATUS);
writel(fifo_status, sock->addr + SOCK_DMA_FIFO_STATUS);
dev_dbg(&sock->dev, "data event: fifo_status %x, flags %x\n",
fifo_status, host->cmd_flags);

host->cmd_flags |= fifo_status & FIFO_RDY;
if (host->req) {
r_data = host->req->cmd->data;

if (host->req)
tifm_sd_process_cmd(sock, host, 0);
if (r_data && (fifo_status & TIFM_FIFO_READY)) {
host->cmd_flags |= FIFO_READY;
tifm_sd_check_status(host);
}
}

dev_dbg(&sock->dev, "fifo_status %x\n", fifo_status);
writel(fifo_status, sock->addr + SOCK_DMA_FIFO_STATUS);
spin_unlock(&sock->lock);

}

/* Called from interrupt handler */
static void tifm_sd_card_event(struct tifm_dev *sock)
{
struct tifm_sd *host;
unsigned int host_status = 0;
int error_code = 0;
int cmd_error = MMC_ERR_NONE;
struct mmc_command *cmd = NULL;
unsigned long flags;

spin_lock(&sock->lock);
host = mmc_priv((struct mmc_host*)tifm_get_drvdata(sock));
host_status = readl(sock->addr + SOCK_MMCSD_STATUS);
dev_dbg(&sock->dev, "host event: host_status %x, flags %x\n",
host_status, host->cmd_flags);


host_status = readl(sock->addr + SOCK_MMCSD_STATUS);
writel(host_status, sock->addr + SOCK_MMCSD_STATUS);

if (!host->req)
goto done;
if (host->req) {
cmd = host->req->cmd;

if (host_status & TIFM_MMCSD_ERRMASK) {
if (host_status & (TIFM_MMCSD_CTO | TIFM_MMCSD_DTO))
error_code = MMC_ERR_TIMEOUT;
else if (host_status
& (TIFM_MMCSD_CCRC | TIFM_MMCSD_DCRC))
error_code = MMC_ERR_BADCRC;
writel(host_status & TIFM_MMCSD_ERRMASK,
sock->addr + SOCK_MMCSD_STATUS);
if (host_status & TIFM_MMCSD_CTO)
cmd_error = MMC_ERR_TIMEOUT;
else if (host_status & TIFM_MMCSD_CCRC)
cmd_error = MMC_ERR_BADCRC;

if (cmd->data) {
if (host_status & TIFM_MMCSD_DTO)
cmd->data->error = MMC_ERR_TIMEOUT;
else if (host_status & TIFM_MMCSD_DCRC)
cmd->data->error = MMC_ERR_BADCRC;
}

writel(TIFM_FIFO_INT_SETALL,
sock->addr + SOCK_DMA_FIFO_INT_ENABLE_CLEAR);
writel(TIFM_DMA_RESET, sock->addr + SOCK_DMA_CONTROL);

if (host->req->stop) {
if (host->state == SCMD) {
host->req->stop->error = error_code;
} else if (host->state == BRS
|| host->state == CARD
|| host->state == FIFO) {
host->req->cmd->error = error_code;
if (host->cmd_flags & SCMD_ACTIVE) {
host->req->stop->error = cmd_error;
host->cmd_flags |= SCMD_READY;
} else {
cmd->error = cmd_error;
host->cmd_flags |= SCMD_ACTIVE;
tifm_sd_exec(host, host->req->stop);
host->state = SCMD;
goto done;
} else {
host->req->cmd->error = error_code;
}
} else {
host->req->cmd->error = error_code;
} else
cmd->error = cmd_error;
} else {
if (host_status & (TIFM_MMCSD_EOC | TIFM_MMCSD_CERR)) {
if (!(host->cmd_flags & CMD_READY)) {
host->cmd_flags |= CMD_READY;
tifm_sd_fetch_resp(cmd, sock);
} else if (host->cmd_flags & SCMD_ACTIVE) {
host->cmd_flags |= SCMD_READY;
tifm_sd_fetch_resp(host->req->stop,
sock);
}
}
host->state = READY;
if (host_status & TIFM_MMCSD_BRS)
host->cmd_flags |= BRS_READY;
}

if (host_status & TIFM_MMCSD_CB)
host->cmd_flags |= CARD_BUSY;
if ((host_status & TIFM_MMCSD_EOFB)
&& (host->cmd_flags & CARD_BUSY)) {
host->written_blocks++;
host->cmd_flags &= ~CARD_BUSY;
if (host->no_dma && cmd->data) {
if (host_status & TIFM_MMCSD_AE)
writel(host_status & TIFM_MMCSD_AE,
sock->addr + SOCK_MMCSD_STATUS);

if (host_status & (TIFM_MMCSD_AE | TIFM_MMCSD_AF
| TIFM_MMCSD_BRS)) {
local_irq_save(flags);
tifm_sd_transfer_data(sock, host, host_status);
local_irq_restore(flags);
host_status &= ~TIFM_MMCSD_AE;
}
}

if (host->req)
tifm_sd_process_cmd(sock, host, host_status);
if (host_status & TIFM_MMCSD_EOFB)
host->cmd_flags &= ~CARD_BUSY;
else if (host_status & TIFM_MMCSD_CB)
host->cmd_flags |= CARD_BUSY;

tifm_sd_check_status(host);
}
done:
dev_dbg(&sock->dev, "host_status %x\n", host_status);
writel(host_status, sock->addr + SOCK_MMCSD_STATUS);
spin_unlock(&sock->lock);
}

Expand Down Expand Up @@ -522,7 +538,7 @@ static void tifm_sd_request(struct mmc_host *mmc, struct mmc_request *mrq)

host->req = mrq;
mod_timer(&host->timer, jiffies + host->timeout_jiffies);
host->state = CMD;
host->cmd_flags = 0;
writel(TIFM_CTRL_LED | readl(sock->addr + SOCK_CONTROL),
sock->addr + SOCK_CONTROL);
tifm_sd_exec(host, mrq->cmd);
Expand Down Expand Up @@ -553,7 +569,6 @@ static void tifm_sd_end_cmd(unsigned long data)
del_timer(&host->timer);
mrq = host->req;
host->req = NULL;
host->state = IDLE;

if (!mrq) {
printk(KERN_ERR DRIVER_NAME ": no request to complete?\n");
Expand Down
1 change: 1 addition & 0 deletions trunk/include/linux/tifm.h
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,7 @@ enum {
#define TIFM_SOCK_STATE_POWERED 0x00000080

#define TIFM_FIFO_ENABLE 0x00000001 /* Meaning of this constant is unverified */
#define TIFM_FIFO_READY 0x00000001 /* Meaning of this constant is unverified */
#define TIFM_FIFO_INT_SETALL 0x0000ffff
#define TIFM_FIFO_INTMASK 0x00000005 /* Meaning of this constant is unverified */

Expand Down

0 comments on commit 6c6ef94

Please sign in to comment.