OpenCores
URL https://opencores.org/ocsvn/test_project/test_project/trunk

Subversion Repositories test_project

[/] [test_project/] [trunk/] [linux_sd_driver/] [drivers/] [mmc/] [host/] [mmc_ocores.c] - Rev 82

Compare with Previous | Blame | View Log

/* -*- linux-c -*-
 *
 * OpenCores MMC Controller driver
 *
 * 
 * Command 51 and Command 2 hardcoded
 * 
 * 
 * 
 * Copyright (C) 2009 ORSoC, 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 as published
 * by the Free Software Foundation; version 2 of the License.
 *
 * This program is distributed in the hope that it will be useful, but
 * WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License along
 * with this program; if not, write to the Free Software Foundation, Inc.,
 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
 */
#include <linux/module.h>
#include <linux/init.h>
#include <linux/ioport.h>
#include <linux/platform_device.h>
#include <linux/delay.h>
#include <linux/interrupt.h>
#include <linux/err.h>
#include <linux/mmc/host.h>
#include <linux/dma-mapping.h>
#include <linux/scatterlist.h>
#include <linux/highmem.h>
#include <asm/board.h>
#include <asm/io.h>
#include <asm/irq.h>
#include <asm/mmc.h>
#include <asm/system.h>
#include <linux/mmc/card.h>
#include "mmc_ocores.h"
 
#define DRIVER_NAME "mmc-ocores"
 
#define NR_SG	1
 
 
 
 
struct ocores_host {
	struct mmc_host		*mmc;
	spinlock_t		lock;
	struct resource		*res;
	void __iomem		*base;
	unsigned int		cmdat;
	unsigned int		power_mode;
	struct ocores_platform_data *pdata;
	unsigned int		word_cnt;
	struct mmc_request	*mrq;
	struct mmc_command	*cmd;
	struct mmc_data		*data;
	int irq_cmd;
	int irq_dat;
	unsigned int flags;
	struct tasklet_struct finish_cmd;
	struct tasklet_struct finish_data;
	struct {
		unsigned int normal_int_status;
		unsigned int error_int_status;
		unsigned int data_int_status;
	} registers;
	int clock;
 
	/* DMA buffer used for transmitting */
 
 
	unsigned int total_length;
	unsigned int dma_len;
	int transfer_index;
 
	int free_tx_bd;
	int free_rx_bd;
	/* Latest in the scatterlist that has been enabled for transfer, but not freed */
	int in_use_index;
};
 
 
 
static void ocores_tasklet_finish_cmd(unsigned long param);
static void ocores_tasklet_finish_data(unsigned long param);
 
static inline void CMD_IRQ_ON(struct ocores_host *host, u32 mask)
{
	u32 val = readl(host->base  + SD_NOMAL_INT_SIGNAL_ENABLE);	
	val |= mask;
	writel (val, host->base  + SD_NOMAL_INT_SIGNAL_ENABLE);	
}
 
static inline void CMD_IRQ_OFF(struct ocores_host *host, u32 mask)
{
	u32 val = readl(host->base  + SD_NOMAL_INT_SIGNAL_ENABLE);
	val  &= ~mask;
	writel (val, host->base  + SD_NOMAL_INT_SIGNAL_ENABLE);
}
 
static inline void DAT_IRQ_ON(struct ocores_host *host, u32 mask)
{
 
 
	u32 val = readl(host->base  + SD_BD_ISER);	
	val |= mask;
	writel (mask, host->base  + SD_BD_ISER);
 
 
 
}
 
static inline void DAT_IRQ_OFF(struct ocores_host *host, u32 mask)
{
	u32 val = readl(host->base  + SD_BD_ISER);
	val  &= ~mask;
	writel (val, host->base  + SD_BD_ISER);
}
 
 
static void ocores_pre_dma(struct ocores_host *host)
{
	unsigned int i,j;
	unsigned int off_scal;
	struct scatterlist *sg;
	struct mmc_command *cmd;
	struct mmc_data *data;
	unsigned long flags;
 
	off_scal=512;	
	if (host->mmc->card!= NULL){
 
		if (mmc_card_blockaddr(host->mmc->card))
			off_scal=1;
		else
			off_scal=512;	
	} 
	pr_debug("Pre block_offset %d\n", off_scal);
 
	cmd = host->cmd;
	if (!cmd) {
		pr_debug("no command\n");
		return;
	}
	data = cmd->data;
	if (!data) {
		pr_debug("no data\n");
		return;
	}
 
	/* Setup the next transfer */	
 
	sg = &data->sg[host->transfer_index++];
 
 
	if (data->flags & MMC_DATA_READ)
		host->dma_len = dma_map_sg(mmc_dev(host->mmc), sg, data->sg_len,  DMA_FROM_DEVICE);
	else
		host->dma_len = dma_map_sg(mmc_dev(host->mmc), sg, data->sg_len,  DMA_TO_DEVICE);
	pr_debug(KERN_ALERT "Dma address = %d, sg_dma_len %d, length = %d, sg_dma_len %d\n", sg_dma_address(&data->sg[0]),  sg_dma_len(&data->sg[0]), sg->length, host->dma_len); 
	printk(KERN_ALERT "Dma address = %d, sg_dma_len %d, length = %d, sg_dma_len %d\n", sg_dma_address(&data->sg[0]),  sg_dma_len(&data->sg[0]), sg->length, host->dma_len);
 
	for (i = 0; i < host->dma_len; i++) {
		unsigned int length = sg_dma_len(&data->sg[i]);
 
		if (length >= 512)
			length /=512;
		else
			length = 1;			
 
		//XXX:512 SD 1.0 card only.
		if (data->flags & MMC_DATA_READ){
			for (j = 0; j< length;j++) {								
				writel((sg_dma_address(&data->sg[i])+ 512*j), host->base + BD_RX);
				wmb();
				writel(cmd->arg+off_scal*j, host->base + BD_RX);
			}
			DAT_IRQ_ON (host,(TRE|CMDE|FIFOE|MRC|TRS));			
		}
		else{						
 
			for (j = 0; j< length;j++) {
 
				writel((sg_dma_address(&data->sg[i])+ 512*j), host->base + BD_TX);
				wmb();
				writel(cmd->arg+off_scal*j, host->base + BD_TX);				
 
			}
 
 
			DAT_IRQ_ON (host,(TRE|CMDE|FIFOE|MRC|TRS));
			pr_debug("pre dma write done\n");
		}	
 
 
	} 
 
 
 
}
 
 
 
static void ocores_start_cmd(struct ocores_host *host, struct mmc_command *cmd)
{
	unsigned int cmd_arg, cmd_command=0;
 
	struct mmc_data *data = cmd->data;
	//WARN_ON(host->cmd != NULL);
	host->cmd = cmd;
 
	//XXX:opcode == 51 not supported by hardware, hack here	    
	if (data && ( cmd->opcode != 51)&& ( cmd->opcode != 12)) {
       		if ( data->blksz & 0x3 ) {
			pr_debug("Unsupported block size\n");
			cmd->error = -EINVAL;
			mmc_request_done(host->mmc, host->mrq);
			return;
		} 
 
		data->bytes_xfered = 0;
		host->transfer_index = 0;
		host->in_use_index = 0;		
 
		if (data->flags & MMC_DATA_READ){  //Handle a read
			pr_debug(KERN_ALERT "%s: Data read dat Len %u\n", __FUNCTION__,host->total_length);
 
			host->total_length = 0;
			ocores_pre_dma(host); //Set up BD
 
		}
		else if (data->flags & MMC_DATA_WRITE){ //Handle write
				//cmdr |= AT91_MCI_TRCMD_START;
 
			host->total_length = data->sg->length; 
			pr_debug(KERN_ALERT "%s: Data write dat Len %u\n", __FUNCTION__,host->total_length);
 
			ocores_pre_dma(host); //Set up BD
 
		}
 
 
	}
	else{
			//Set up command
		cmd_arg = cmd->arg;
		cmd_command |= cmd->opcode << 8;
		cmd_command |= host->word_cnt << 6;
 
		if ( mmc_resp_type(cmd) == MMC_RSP_CRC  )
			cmd_command |= CRCE;
		if ( mmc_resp_type(cmd) == MMC_RSP_OPCODE  )
			cmd_command |= CICE;
 
		switch (mmc_resp_type(cmd)) {
		case MMC_RSP_NONE:
			cmd_command |= MMCOC_RSP_NONE;
			break;
		case MMC_RSP_R1:
			cmd_command |= MMCOC_RSP_48;
			break;
		case MMC_RSP_R1B:
			cmd_command |= MMCOC_RSP_48;
			break;
		case MMC_RSP_R2:
			cmd_command |= MMCOC_RSP_136;
			break;
		case MMC_RSP_R3:
			cmd_command |= MMCOC_RSP_48;
			break;
		default:
			printk(KERN_INFO "mmc_ocores: unhandled response type %02x\n",
			       mmc_resp_type(cmd));
		}
		 //Send Command
		CMD_IRQ_ON (host,(ECC|EEI));
		writel(cmd_command, host->base + SD_COMMAND);
		wmb();
		writel(cmd_arg, host->base + SD_ARG);	
		//printk(KERN_ALERT "%s: cmd_arg = %08x\n", __FUNCTION__, cmd_arg);
		//printk(KERN_ALERT "%s: cmd_command   = %08x\n", __FUNCTION__, cmd_command);
 
	}
 
 
}
 
static void ocores_process_next(struct ocores_host *host)
{
	host->word_cnt=0;
 
	if (!(host->flags & FL_SENT_COMMAND)) {
		host->flags |= FL_SENT_COMMAND;
		ocores_start_cmd(host, host->mrq->cmd);
	}
	else if ((!(host->flags & FL_SENT_STOP)) && host->mrq->stop) {
		host->flags |= FL_SENT_STOP;
		ocores_start_cmd(host, host->mrq->stop);
	}
}
 
static void ocores_request(struct mmc_host *mmc, struct mmc_request *mrq)
{
	struct ocores_host *host = mmc_priv(mmc);
 
 
	host->mrq = mrq;
	host->flags = 0;
	ocores_process_next(host);
 
 
	//printk(KERN_ALERT "%s: exit\n", __FUNCTION__);
}
 
 
 
static int ocores_get_ro(struct mmc_host *mmc)
{
	/* struct ocores_host *host = mmc_priv(mmc); */
 
	printk(KERN_ALERT "%s: enter\n", __FUNCTION__);
 
 
	/* /\* Host doesn't support read only detection so assume writeable *\/ */
	return 0;
}
 
static void ocores_set_ios(struct mmc_host *mmc, struct mmc_ios *ios)
{
	struct ocores_host *host = mmc_priv(mmc);
	int clk_div, cmd_timeout;
	/* struct ocores_host *host = mmc_priv(mmc); */
 
	printk(KERN_ALERT "%s: clock = 0x%08x\n", __FUNCTION__, ios->clock);
	printk(KERN_ALERT "%s: vdd = 0x%04x\n", __FUNCTION__, ios->vdd);
	printk(KERN_ALERT "%s: bus_mode = 0x%02x\n", __FUNCTION__, ios->bus_mode);
	printk(KERN_ALERT "%s: power_mode = 0x%02x\n", __FUNCTION__, ios->power_mode);
	printk(KERN_ALERT "%s: bus_width = 0x%02x\n", __FUNCTION__, ios->bus_width);
	printk(KERN_ALERT "%s: timing = 0x%02x\n", __FUNCTION__, ios->timing);
 
	//Set clock divider and timeout registers
    	printk(KERN_ALERT "%s: host->base = %p\n", __FUNCTION__, host->base);
	if (ios->clock == 0) {
		//ocores_mci_write (host, SD_SOFTWARE_RST, SD_DISABLE);
	}
	else if (ios->clock != host->clock)
	{       
		host->clock = ios->clock;
		writel(SD_DISABLE, host->base + SD_SOFTWARE_RST);
		clk_div = ((SYS_CLK / ios->clock)-2 )/ 2;
		cmd_timeout = ((SYS_CLK/ios->clock) * 512);
 
		printk(KERN_ALERT " clk_div = 0x%02x\n", clk_div);
		printk(KERN_ALERT " cmd_timeout = 0x%02x\n", cmd_timeout);
 
		writel (clk_div, host->base  + SD_CLOCK_DIVIDER);
		writel (cmd_timeout, host->base  + SD_TIMEOUT);
 
 
		writel(SD_ENABLE, host->base + SD_SOFTWARE_RST);
	}
 
}
 
 
 
static irqreturn_t ocores_irq_cmd(int irq, void *devid)
{
	 struct ocores_host *host = (struct ocores_host *) devid;
 
	 disable_irq(host->irq_cmd);
 
	 	//printk(KERN_ALERT "%s: IRQ START***** Normal In  = %08x\n", __FUNCTION__, readl(host->base + SD_NORMAL_INT_STATUS));
 
	 host->registers.normal_int_status  = readl(host->base + SD_NORMAL_INT_STATUS);
	 rmb();
	 host->registers.error_int_status  = readl(host->base + SD_ERROR_INT_STATUS);
 
	 writel(0,host->base + SD_NORMAL_INT_STATUS);
	 writel(0,host->base + SD_ERROR_INT_STATUS);
 
	 //printk(KERN_ALERT "%s: IRQ END***** Error In  = %08x\n", __FUNCTION__, readl(host->base + SD_ERROR_INT_STATUS));
	 tasklet_schedule(&host->finish_cmd);
	 CMD_IRQ_OFF (host,(ECC|EEI));
	 enable_irq(host->irq_cmd);
 
	 return IRQ_HANDLED;
}
 
static irqreturn_t ocores_irq_dat(int irq, void *devid)
{
	 struct ocores_host *host = (struct ocores_host *) devid;
 
	 //disable_irq(host->irq_dat);
 
	 host->registers.data_int_status  = readl(host->base + SD_BD_ISR);	
 
	 writel(0,host->base + SD_BD_ISR);	
	 tasklet_schedule(&host->finish_data);
 
	 //enable_irq(host->irq_dat);
 
	 return IRQ_HANDLED;
 
 
 
 
}
 
static const struct mmc_host_ops ocores_ops = {
	.request		= ocores_request,
	.get_ro			= ocores_get_ro,
	.set_ios		= ocores_set_ios,
	/* .enable_sdio_irq	= ocores_enable_sdio_irq, */
};
 
static int ocores_probe(struct platform_device *pdev)
{
	struct mmc_host *mmc;
	struct ocores_host *host = NULL;
	struct resource *r;
	int ret;
 
 
	printk(KERN_ALERT "%s: enter\n", __FUNCTION__);
 
	r = platform_get_resource(pdev, IORESOURCE_MEM, 0);
 
	printk(KERN_ALERT "%s: resource %x, %x\n", __FUNCTION__, r->start, r->end);
 
	r = request_mem_region(r->start, r->end - r->start, DRIVER_NAME);
	if (!r) {
		return -EBUSY;
	}
 
	mmc = mmc_alloc_host(sizeof(struct ocores_host), &pdev->dev);
	if (!mmc) {
		ret = -ENOMEM;
		goto out;
	}
 
 
	mmc->ops = &ocores_ops;
 
	mmc->ocr_avail = MMC_VDD_32_33 | MMC_VDD_33_34;
	mmc->caps = MMC_CAP_4_BIT_DATA;
	mmc->f_min = 700000;  //SYS_CLK  60; 0.7 Mhz
	mmc->f_max = 6166666;  //SYS_CLK;   4.166 666 mhz
 
	mmc->max_blk_count =  4;//8; //XXX: 8
	mmc->max_hw_segs = 2;
	mmc->max_blk_size = MMCOC_MAX_BLOCK_SIZE;
	//mmc->max_seg_size = mmc->max_blk_count * mmc->max_blk_size;
 
 
	mmc->max_seg_size = PAGE_SIZE;
	mmc->max_req_size = mmc->max_seg_size;
	mmc->max_phys_segs = 1; //BD size
 
	host = mmc_priv(mmc);
 
	 /*XXX:  */
        host->clock = 0;
 
	host->mmc = mmc;
	host->cmdat = 0;
	host->registers.normal_int_status =0;
 
	printk("Free FBD \n");
	host->free_tx_bd=0;
	host->free_rx_bd=0;
	printk("Free EBD \n");
 
 
 
	tasklet_init(&host->finish_cmd, ocores_tasklet_finish_cmd,
		     (unsigned long) host);
 
	tasklet_init(&host->finish_data, ocores_tasklet_finish_data,
		     (unsigned long) host);
 
 
	spin_lock_init(&host->lock);
	host->res = r;
 
	host->base = ioremap(r->start, r->end - r->start +1);
	/* host->base = (void *)r->start; */
	if (!host->base) {
		ret = -ENOMEM;
		goto out;
	}
	host->free_tx_bd=readl( host->base + BD_STATUS );	
	host->free_tx_bd=host->free_tx_bd & 0x00ff;
	printk("Free TX BD = %d\n", host->free_tx_bd);
	host->free_rx_bd=readl( host->base + BD_STATUS );	
	host->free_rx_bd=(host->free_rx_bd & 0xff00)>>8;
	printk("Free TX BD = %d\n", host->free_rx_bd);
 
	host->pdata = pdev->dev.platform_data;
	mmc->ocr_avail = host->pdata->ocr_mask;
 
	host->irq_cmd = platform_get_irq_byname(pdev, "cmd_irq");
	ret = request_irq(host->irq_cmd, ocores_irq_cmd, IRQF_DISABLED, DRIVER_NAME, host);
	printk(KERN_ALERT "%s: IRQ dat resource  %x\n", __FUNCTION__, host->irq_cmd );
	printk(KERN_ALERT "%s: RET cmd irq %x\n", __FUNCTION__, ret);
	if (ret)
		goto out;
	disable_irq(host->irq_cmd);
 
	host->irq_dat = platform_get_irq_byname(pdev, "dat_irq");
	ret = request_irq(host->irq_dat, ocores_irq_dat, IRQF_DISABLED, DRIVER_NAME, host);
	printk(KERN_ALERT "%s: IRQ dat resource  %x\n", __FUNCTION__, host->irq_dat );
	printk(KERN_ALERT "%s: RET Dat irq  %x\n", __FUNCTION__, ret);
	if (ret)
		goto out;
	disable_irq(host->irq_dat);
 
 
 
	enable_irq(host->irq_cmd);
   	enable_irq(host->irq_dat);
	printk(KERN_ALERT "%s: host->base = %p\n", __FUNCTION__, host->base);
	printk(KERN_ALERT "%s: SD_BLOCK = %08x\n", __FUNCTION__, readl(host->base + SD_BLOCK));
	printk(KERN_ALERT "%s: host->pdata->ocr_mask = %08x\n", __FUNCTION__, host->pdata->ocr_mask);
 
	mmc_add_host(mmc);
 
	printk(KERN_ALERT "%s: exit\n", __FUNCTION__);
 
	return 0;
 
 out:
  	printk(KERN_ALERT "%s: ERROR REQUESTINING RESOURCES\n", __FUNCTION__);
	if (mmc) {
		mmc_free_host(mmc);
	}
	release_resource(r);
 
	return ret;
}
 
static void ocores_tasklet_finish_cmd(unsigned long param)
{
	struct ocores_host *host = (struct ocores_host *) param;
 
	struct mmc_data *data;
	struct scatterlist *sg;	
	data = host->cmd->data;
	sg = &data->sg[0];
 
	//printk(KERN_ALERT " CMD TASKLET RUNNS************\n");
	//Check For Transmissions errors
	if ((host->registers.normal_int_status & EI) == EI)
	{
		printk(KERN_ALERT "TRANSMISSION ERROR DETECTED");
		switch ( host->registers.error_int_status )
     	 	{
		case (CTE):
			pr_debug("Card took too long to respond\n");
			host->mrq->cmd->error = -ETIMEDOUT ;
			if (host->mrq->stop)
				host->mrq->stop->error = -ETIMEDOUT ;
     	 		break;
		case (CCRC  ):
			pr_debug(" CRC  problem with the received or sent data\n");
			host->mrq->cmd->error = -EILSEQ;
			if (host->mrq->stop)	
				host->mrq->stop->error = -EILSEQ ;
     	 		break;
		case (CIE  ):
			pr_debug("Index problem with the received or sent data\n");
			host->mrq->cmd->error = -EILSEQ;
			if (host->mrq->stop)
				host->mrq->stop->error = -EILSEQ ;
     	 		break;
		}
 
		mmc_request_done(host->mmc, host->mrq);
	}
	else
	{         
		if ( mmc_resp_type(host->mrq->cmd) == MMC_RSP_R2      )   //Long response
		{
			printk(KERN_ALERT "Long Response, Word Cnt %d, RESP  * = %08x\n ",host->word_cnt,readl(host->base + SD_RESP1));
 
			if (host->mrq->cmd->opcode == 2) { //XXX: Hack until supported long response
				host->mrq->cmd->resp[0]  =  readl(host->base + SD_RESP1);
				host->mrq->cmd->resp[1]  =  0x01302331;
				host->mrq->cmd->resp[2]  =  0x195abdef;
				host->mrq->cmd->resp[3]  =  0x195abdef;
				mmc_request_done(host->mmc, host->mrq);			
			} //XXX: Hack until supported long response
			else if(host->mrq->cmd->opcode == 51)
			{
				host->mrq->cmd->resp[0] = 0x900;
				host->mrq->cmd->resp[1] = 0xaaa;
				host->mrq->cmd->resp[2] = 0xbbb;
				host->mrq->cmd->resp[3] = 0xccc;
				host->mrq->data->bytes_xfered =8;
				dma_unmap_sg(mmc_dev(host->mmc), sg, data->sg_len, DMA_FROM_DEVICE);
				mmc_request_done(host->mmc, host->mrq);	
			} 
 
 
 
			else {
				host->word_cnt+=1;
				switch(host->word_cnt-1)
				{
				case (0):
					host->mrq->cmd->resp[0]  =  readl(host->base + SD_RESP1);
					ocores_start_cmd(host, host->mrq->cmd);
					break;
				case (1):
					host->mrq->cmd->resp[1]  =  readl(host->base + SD_RESP1);
					ocores_start_cmd(host, host->mrq->cmd);
					break;
				case (2):
					host->mrq->cmd->resp[2]  =  readl(host->base + SD_RESP1);
					ocores_start_cmd(host, host->mrq->cmd);
					break;
				case (3):
					host->mrq->cmd->resp[3]  =  readl(host->base + SD_RESP1);
					mmc_request_done(host->mmc, host->mrq);
					break;
				}
			}
		}
		else  //Short response
		{
			host->mrq->cmd->error = 0 ;
 
			if (host->mrq->stop)
				host->mrq->stop->resp[0] = readl(host->base + SD_RESP1);
			else
				host->mrq->cmd->resp[0] = readl(host->base + SD_RESP1);
			//printk(KERN_ALERT "Short Response CMD RSP * = %08x\n", host->mrq->cmd->resp[0]);
			mmc_request_done(host->mmc, host->mrq);
		}
	}
 
}
static void ocores_tasklet_finish_data(unsigned long param)
{
	struct ocores_host *host = (struct ocores_host *) param;
 
 
	struct mmc_data *data;
	struct scatterlist *sg;
	int free_bd,i;
	int *adr;
	data = host->cmd->data;
	sg = &data->sg[0]; //XXX:O Change to dynamic later?
 
 
 
	//IF read operation
 
	if ((host->registers.data_int_status & TRS) == TRS){ 			           
		if (data->flags & MMC_DATA_READ){
			free_bd=readl( host->base + BD_STATUS );
			free_bd=(free_bd&0xff00)>>8;
			//printk(KERN_ALERT " DATA READ TASKLET RUNNS*** Free BD %d\n", free_bd);
			if (free_bd == host->free_rx_bd) {
				dma_unmap_sg(mmc_dev(host->mmc), sg, sg->length, DMA_FROM_DEVICE);
				host->mrq->cmd->resp[0]  =  readl(host->base + SD_RESP1);
 
				DAT_IRQ_OFF (host,(TRE|CMDE|FIFOE|MRC|TRS));
				data->bytes_xfered = sg->length;		
 
				if (host->mrq->stop) 	
					host->mrq->stop->resp[0] = readl(host->base + SD_RESP1);
 
 
				mmc_request_done(host->mmc, host->mrq);
 
			}
		} else if (data->flags & MMC_DATA_WRITE){
			free_bd=readl( host->base + BD_STATUS );
			free_bd=(free_bd&0x00FF);
			//printk(KERN_ALERT " DATA WRITE TASKLET RUNNS*** Free BD %d\n", free_bd);
			if (free_bd == host->free_tx_bd) {
				dma_unmap_sg(mmc_dev(host->mmc), sg, sg->length, DMA_TO_DEVICE);
				host->mrq->cmd->resp[0]  =  readl(host->base + SD_RESP1);
 
				DAT_IRQ_OFF (host,(TRE|CMDE|FIFOE|MRC|TRS));
				data->bytes_xfered = sg->length;	
 
 
				if (host->mrq->stop) 		
					host->mrq->stop->resp[0] = readl(host->base + SD_RESP1);
 
 
				mmc_request_done(host->mmc, host->mrq);
 
			}
 
		}
 
	}		
	else {  printk(KERN_ALERT "DATA TRANS ERROR %d\n", host->registers.data_int_status);
 
				data->error = -ETIMEDOUT;
			if ((host->registers.data_int_status & MRC) == MRC)
				data->error = -ETIMEDOUT;
			if ((host->registers.data_int_status &  CMDE) ==  CMDE)		
				data->error = -EILSEQ;
			data->bytes_xfered =0;
 
		host->mrq->cmd->resp[0]  =  readl(host->base + SD_RESP1);
		dma_unmap_sg(mmc_dev(host->mmc), sg, data->sg_len, DMA_FROM_DEVICE);
		DAT_IRQ_OFF (host,(TRE|FIFOE|MRC|TRS));	
		mmc_request_done(host->mmc, host->mrq);	
 
 
	}
 
 
 
 
 
 
 
 
}
static int ocores_remove(struct platform_device *pdev)
{
	struct mmc_host *mmc = platform_get_drvdata(pdev);
	struct ocores_host *host;
	struct resource *r;
	r = platform_get_resource(pdev, IORESOURCE_MEM, 0);
 
	printk(KERN_ALERT "%s: enter\n", __FUNCTION__);
 
	platform_set_drvdata(pdev, NULL);
 
	tasklet_kill(&host->finish_cmd);
	tasklet_kill(&host->finish_data);
 
	free_irq(host->irq_cmd, host);
	free_irq(host->irq_dat, host);
 
	iounmap(host->base);
 
	release_mem_region(r->start, r->end - r->start + 1);
	if (mmc) {
		struct ocores_host *host = mmc_priv(mmc);
 
		mmc_remove_host(mmc);
 
		release_resource(host->res);
 
		mmc_free_host(mmc);
	}
 
	printk(KERN_ALERT "%s: exit\n", __FUNCTION__);
 
	return 0;
}
 
#ifdef CONFIG_PM
static int ocores_suspend(struct platform_device *dev, pm_message_t state)
{
	struct mmc_host *mmc = platform_get_drvdata(dev);
	int ret = 0;
 
	printk(KERN_ALERT "%s: enter\n", __FUNCTION__);
 
	if (mmc) {
		ret = mmc_suspend_host(mmc, state);
	}
 
	printk(KERN_ALERT "%s: exit\n", __FUNCTION__);
 
	return ret;
}
 
static int ocores_resume(struct platform_device *dev)
{
	struct mmc_host *mmc = platform_get_drvdata(dev);
	int ret = 0;
 
	printk(KERN_ALERT "%s: enter\n", __FUNCTION__);
 
	if (mmc) {
		ret = mmc_resume_host(mmc);
	}
 
	printk(KERN_ALERT "%s: exit\n", __FUNCTION__);
 
	return ret;
}
#else
#define ocores_suspend	NULL
#define ocores_resume	NULL
#endif
 
static struct platform_driver ocores_driver = {
	.probe		= ocores_probe,
	.remove		= ocores_remove,
	.suspend	= ocores_suspend,
	.resume		= ocores_resume,
	.driver		= {
		.name	= DRIVER_NAME,
	},
};
 
static int __init ocores_init(void)
{
	printk(KERN_ALERT "%s: registering ocores platform_driver\n", __FUNCTION__);
 
	return platform_driver_register(&ocores_driver);
}
 
static void __exit ocores_exit(void)
{
	printk(KERN_ALERT "%s: unregistering ocores platform_driver\n", __FUNCTION__);
 
	platform_driver_unregister(&ocores_driver);
}
 
module_init(ocores_init);
module_exit(ocores_exit);
 
MODULE_DESCRIPTION("OpenCores Multimedia Card Interface Driver");
MODULE_LICENSE("GPL");
 

Compare with Previous | Blame | View Log

powered by: WebSVN 2.1.0

© copyright 1999-2024 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.