?? s3c2410mci.c
字號(hào):
/* * linux/drivers/mmc/s3c2410mci.h - Samsung S3C2410 SDI Interface driver * * Copyright (C) 2004 Thomas Kleffel, 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/moduleparam.h>#include <linux/init.h>#include <linux/ioport.h>#include <linux/device.h>#include <linux/interrupt.h>#include <linux/blkdev.h>#include <linux/delay.h>#include <linux/err.h>#include <linux/dma-mapping.h>#include <linux/mmc/host.h>#include <linux/mmc/protocol.h>//#include <linux/clk.h>#include <asm/dma.h>#include <asm/dma-mapping.h>#include <asm/arch/dma.h>#include <asm/io.h>#include <asm/irq.h>#include <asm/hardware/clock.h>#include <asm/mach/mmc.h>#include <asm/arch/regs-sdi.h>#include <asm/arch/regs-gpio.h>#include <asm/arch/mmc.h>#include <asm/arch/regs-clock.h>//#define S3C2410SDI_DMA_BACKBUF#ifdef CONFIG_MMC_DEBUG#define DBG(x...) printk(KERN_INFO x)#else#define DBG(x...) do { } while (0)#endif#include "s3c2410mci.h"#define DRIVER_NAME "mmci-s3c2410"#define PFX DRIVER_NAME ": "#define RESSIZE(ressource) (((ressource)->end - (ressource)->start)+1)static struct s3c2410_dma_client s3c2410sdi_dma_client = { .name = "s3c2410-sdi",};/* * ISR for SDI Interface IRQ * Communication between driver and ISR works as follows: * host->mrq points to current request * host->complete_what tells the ISR when the request is considered done * COMPLETION_CMDSENT when the command was sent * COMPLETION_RSPFIN when a response was received * COMPLETION_XFERFINISH when the data transfer is finished * COMPLETION_XFERFINISH_RSPFIN both of the above. * host->complete_request is the completion-object the driver waits for * * 1) Driver sets up host->mrq and host->complete_what * 2) Driver prepares the transfer * 3) Driver enables interrupts * 4) Driver starts transfer * 5) Driver waits for host->complete_rquest * 6) ISR checks for request status (errors and success) * 6) ISR sets host->mrq->cmd->error and host->mrq->data->error * 7) ISR completes host->complete_request * 8) ISR disables interrupts * 9) Driver wakes up and takes care of the request*/static irqreturn_t s3c2410sdi_irq(int irq, void *dev_id, struct pt_regs *regs){ struct s3c2410sdi_host *host; u32 sdi_csta, sdi_dsta, sdi_dcnt; u32 sdi_cclear, sdi_dclear; unsigned long iflags; host = (struct s3c2410sdi_host *)dev_id; //Check for things not supposed to happen if(!host) return IRQ_HANDLED; sdi_csta = readl(host->base + S3C2410_SDICMDSTAT); sdi_dsta = readl(host->base + S3C2410_SDIDSTA); sdi_dcnt = readl(host->base + S3C2410_SDIDCNT); DBG(PFX "IRQ csta=0x%08x dsta=0x%08x dcnt:0x%08x\n", sdi_csta, sdi_dsta, sdi_dcnt); spin_lock_irqsave( &host->complete_lock, iflags); if( host->complete_what==COMPLETION_NONE ) { goto clear_imask; } if(!host->mrq) { goto clear_imask; } sdi_csta = readl(host->base + S3C2410_SDICMDSTAT); sdi_dsta = readl(host->base + S3C2410_SDIDSTA); sdi_dcnt = readl(host->base + S3C2410_SDIDCNT); sdi_cclear = 0; sdi_dclear = 0; if(sdi_csta & S3C2410_SDICMDSTAT_CMDTIMEOUT) { host->mrq->cmd->error = MMC_ERR_TIMEOUT; goto transfer_closed; } if(sdi_csta & S3C2410_SDICMDSTAT_CMDSENT) { if(host->complete_what == COMPLETION_CMDSENT) { host->mrq->cmd->error = MMC_ERR_NONE; goto transfer_closed; } sdi_cclear |= S3C2410_SDICMDSTAT_CMDSENT; } if(sdi_csta & S3C2410_SDICMDSTAT_CRCFAIL) { if (host->mrq->cmd->flags & MMC_RSP_LONG) { DBG(PFX "s3c2410 fixup : ignore CRC fail with long rsp\n"); } else { DBG(PFX "COMMAND CRC FAILED %x\n", sdi_csta); if(host->mrq->cmd->flags & MMC_RSP_CRC) { host->mrq->cmd->error = MMC_ERR_BADCRC; goto transfer_closed; } } sdi_cclear |= S3C2410_SDICMDSTAT_CRCFAIL; } if(sdi_csta & S3C2410_SDICMDSTAT_RSPFIN) { if(host->complete_what == COMPLETION_RSPFIN) { host->mrq->cmd->error = MMC_ERR_NONE; goto transfer_closed; } if(host->complete_what == COMPLETION_XFERFINISH_RSPFIN) { host->mrq->cmd->error = MMC_ERR_NONE; host->complete_what = COMPLETION_XFERFINISH; } sdi_cclear |= S3C2410_SDICMDSTAT_RSPFIN; } if(sdi_dsta & S3C2410_SDIDSTA_FIFOFAIL) { host->mrq->cmd->error = MMC_ERR_NONE; host->mrq->data->error = MMC_ERR_FIFO; goto transfer_closed; } if(sdi_dsta & S3C2410_SDIDSTA_RXCRCFAIL) { host->mrq->cmd->error = MMC_ERR_NONE; host->mrq->data->error = MMC_ERR_BADCRC; goto transfer_closed; } if(sdi_dsta & S3C2410_SDIDSTA_CRCFAIL) { host->mrq->cmd->error = MMC_ERR_NONE; host->mrq->data->error = MMC_ERR_BADCRC; goto transfer_closed; } if(sdi_dsta & S3C2410_SDIDSTA_DATATIMEOUT) { host->mrq->cmd->error = MMC_ERR_NONE; host->mrq->data->error = MMC_ERR_TIMEOUT; goto transfer_closed; } if(sdi_dsta & S3C2410_SDIDSTA_XFERFINISH) { if(host->complete_what == COMPLETION_XFERFINISH) { host->mrq->cmd->error = MMC_ERR_NONE; host->mrq->data->error = MMC_ERR_NONE; goto transfer_closed; } if(host->complete_what == COMPLETION_XFERFINISH_RSPFIN) { host->mrq->data->error = MMC_ERR_NONE; host->complete_what = COMPLETION_RSPFIN; } sdi_dclear |= S3C2410_SDIDSTA_XFERFINISH; } writel(sdi_cclear, host->base + S3C2410_SDICMDSTAT); writel(sdi_dclear, host->base + S3C2410_SDIDSTA); spin_unlock_irqrestore( &host->complete_lock, iflags); DBG(PFX "IRQ still waiting.\n"); return IRQ_HANDLED;transfer_closed: writel(sdi_cclear, host->base + S3C2410_SDICMDSTAT); writel(sdi_dclear, host->base + S3C2410_SDIDSTA); host->complete_what = COMPLETION_NONE; complete(&host->complete_request); writel(0, host->base + S3C2410_SDIIMSK); spin_unlock_irqrestore( &host->complete_lock, iflags); DBG(PFX "IRQ transfer closed.\n"); return IRQ_HANDLED; clear_imask: writel(0, host->base + S3C2410_SDIIMSK); spin_unlock_irqrestore( &host->complete_lock, iflags); DBG(PFX "IRQ clear imask.\n"); return IRQ_HANDLED;}/* * ISR for the CardDetect Pin*/static irqreturn_t s3c2410sdi_irq_cd(int irq, void *dev_id, struct pt_regs *regs){ struct s3c2410sdi_host *host = (struct s3c2410sdi_host *)dev_id; //printk("s3c2410sdi_irq_cd\n"); mmc_detect_change(host->mmc, S3C2410SDI_CDLATENCY); return IRQ_HANDLED;}void s3c2410sdi_dma_done_callback(s3c2410_dma_chan_t *dma_ch, void *buf_id, int size, s3c2410_dma_buffresult_t result){ unsigned long iflags; u32 sdi_csta, sdi_dsta,sdi_dcnt; struct s3c2410sdi_host *host = (struct s3c2410sdi_host *)buf_id; sdi_csta = readl(host->base + S3C2410_SDICMDSTAT); sdi_dsta = readl(host->base + S3C2410_SDIDSTA); sdi_dcnt = readl(host->base + S3C2410_SDIDCNT); DBG(PFX "DMAD csta=0x%08x dsta=0x%08x dcnt:0x%08x result:0x%08x\n", sdi_csta, sdi_dsta, sdi_dcnt, result); spin_lock_irqsave( &host->complete_lock, iflags); if(!host->mrq) goto out; if(!host->mrq->data) goto out; sdi_csta = readl(host->base + S3C2410_SDICMDSTAT); sdi_dsta = readl(host->base + S3C2410_SDIDSTA); sdi_dcnt = readl(host->base + S3C2410_SDIDCNT); if( result!=S3C2410_RES_OK ) { goto fail_request; } if(host->mrq->data->flags & MMC_DATA_READ) { if( sdi_dcnt>0 ) { goto fail_request; } } out: complete(&host->complete_dma); spin_unlock_irqrestore( &host->complete_lock, iflags); return;fail_request: host->mrq->data->error = MMC_ERR_FAILED; host->complete_what = COMPLETION_NONE; complete(&host->complete_request); writel(0, host->base + S3C2410_SDIIMSK); goto out;}void s3c2410sdi_dma_setup(struct s3c2410sdi_host *host, s3c2410_dmasrc_t source) { s3c2410_dma_devconfig(host->dma, source, 3, host->mem->start + S3C2410_SDIDATA); s3c2410_dma_config(host->dma, 4, (1<<23) | (2<<24)); s3c2410_dma_set_buffdone_fn(host->dma, s3c2410sdi_dma_done_callback); s3c2410_dma_setflags(host->dma, S3C2410_DMAF_AUTOSTART);}static void s3c2410sdi_request(struct mmc_host *mmc, struct mmc_request *mrq) { struct s3c2410sdi_host *host = mmc_priv(mmc); struct device *dev = mmc_dev(host->mmc); struct platform_device *pdev = to_platform_device(dev); u32 sdi_carg, sdi_ccon, sdi_timer; u32 sdi_bsize, sdi_dcon, sdi_imsk; int dma_len = 0; //u32 sdi_con; DBG(KERN_DEBUG PFX "request: [CMD] opcode:0x%02d arg:0x%08x flags:%x retries:%u\n", mrq->cmd->opcode, mrq->cmd->arg, mrq->cmd->flags, mrq->cmd->retries); DBG(PFX "request : %s mode\n",mmc->mode == MMC_MODE_MMC ? "mmc" : "sd"); sdi_ccon = mrq->cmd->opcode & S3C2410_SDICMDCON_INDEX; sdi_ccon|= S3C2410_SDICMDCON_SENDERHOST; sdi_ccon|= S3C2410_SDICMDCON_CMDSTART; sdi_carg = mrq->cmd->arg; //FIXME: Timer value ?! sdi_timer= 0xF000; sdi_bsize= 0; sdi_dcon = 0; sdi_imsk = 0; //enable interrupts for transmission errors sdi_imsk |= S3C2410_SDIIMSK_RESPONSEND; sdi_imsk |= S3C2410_SDIIMSK_CRCSTATUS; host->complete_what = COMPLETION_CMDSENT; if (mrq->cmd->flags & MMC_RSP_MASK) { host->complete_what = COMPLETION_RSPFIN; sdi_ccon |= S3C2410_SDICMDCON_WAITRSP; sdi_imsk |= S3C2410_SDIIMSK_CMDTIMEOUT; } else { //We need the CMDSENT-Interrupt only if we want are not waiting //for a response sdi_imsk |= S3C2410_SDIIMSK_CMDSENT; } if(mrq->cmd->flags & MMC_RSP_LONG) { sdi_ccon|= S3C2410_SDICMDCON_LONGRSP; } if(mrq->cmd->flags & MMC_RSP_CRC) { sdi_imsk |= S3C2410_SDIIMSK_RESPONSECRC; } if (mrq->data) { host->complete_what = COMPLETION_XFERFINISH_RSPFIN; sdi_bsize = (1 << mrq->data->blksz_bits); //fifo reset //sdi_con = readl(host->base + S3C2410_SDICON); //sdi_con|= S3C2410_SDICON_FIFORESET; //writel(sdi_con, host->base + S3C2410_SDICON); sdi_dcon = (mrq->data->blocks & S3C2410_SDIDCON_BLKNUM_MASK); sdi_dcon |= S3C2410_SDIDCON_DMAEN; sdi_imsk |= S3C2410_SDIIMSK_FIFOFAIL; sdi_imsk |= S3C2410_SDIIMSK_DATACRC; sdi_imsk |= S3C2410_SDIIMSK_DATATIMEOUT; sdi_imsk |= S3C2410_SDIIMSK_DATAFINISH; sdi_imsk |= 0xFFFFFFE0; DBG(PFX "request: [DAT] bsize:%u blocks:%u bytes:%u\n", sdi_bsize, mrq->data->blocks, mrq->data->blocks * sdi_bsize); if (host->bus_width == MMC_BUS_WIDTH_4) { sdi_dcon |= S3C2410_SDIDCON_WIDEBUS; } if(!(mrq->data->flags & MMC_DATA_STREAM)) { sdi_dcon |= S3C2410_SDIDCON_BLOCKMODE; } if(mrq->data->flags & MMC_DATA_WRITE) { sdi_dcon |= S3C2410_SDIDCON_TXAFTERRESP; sdi_dcon |= S3C2410_SDIDCON_XFER_TXSTART;
?? 快捷鍵說(shuō)明
復(fù)制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號(hào)
Ctrl + =
減小字號(hào)
Ctrl + -