⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 omap_hsmmc.c

📁 omap3 linux 2.6 用nocc去除了冗余代码
💻 C
📖 第 1 页 / 共 4 页
字号:
	if (write) {		__raw_writesw(host->base + OMAP_HSMMC_DATA, host->buffer, n);	} else {		__raw_readsw(host->base + OMAP_HSMMC_DATA, host->buffer, n);	}}/* * Configure the resptype, cmdtype and send the given command to the card */static voidmmc_omap_start_command13(struct mmc_omap_host *host, struct mmc_command *cmd){	int  cmdreg = 0, resptype = 0, cmdtype = 0;	unsigned long flags;	mmc_clk_enable_aggressive(host);	/* Clear status bits and enable interrupts */	OMAP_HSMMC_WRITE(host->base, STAT, OMAP_HSMMC_STAT_CLEAR);	resptype = 2;	cmdreg = (MMC_SEND_STATUS << 24) | (resptype << 16) | (cmdtype << 22);	OMAP_HSMMC_WRITE(host->base, ISE, INT_EN_MASK);	OMAP_HSMMC_WRITE(host->base, IE, INT_EN_MASK);	OMAP_HSMMC_WRITE(host->base, ARG, host->rca);	OMAP_HSMMC_WRITE(host->base, CMD, cmdreg);	spin_lock_irqsave(&host->dma_lock, flags);	host->cmd_13 = 1;	spin_unlock_irqrestore(&host->dma_lock, flags);}/* * Notify the core about command completion */static voidmmc_omap_err_cmd_done(struct mmc_omap_host *host, struct mmc_command *cmd){	cmd->resp[0] = OMAP_HSMMC_READ(host->base, RSP10);	mmc_clk_disable_aggressive(host);	if(host->cmd_13 == 1)	{		if(cmd->resp[0] != 0x900)			dev_dbg(mmc_dev(host->mmc),				"%s:CMD response error cmd->resp[0]%x\n",				mmc_hostname(host->mmc),cmd->resp[0]);	}}static intmmc_omap_err_calc(struct mmc_omap_host *host){	unsigned sg_len_remain;	struct mmc_data *data = host->data;	unsigned long flags;	if(unlikely(host == NULL))	{		return -1;	}	/* Enable DMA */	host->use_dma = 1;	spin_lock_irqsave(&host->dma_lock, flags);	if(host->extra_chain_reqd == 0)	{		if(host->data->sg_len <= NO_OF_DMA_CHAINS_USED)			host->sg_idx = 0;		else			host->sg_idx = host->sg_idx-NO_OF_DMA_CHAINS_USED;	}	else	{		if(host->sg_idx == host->data->sg_len)			host->sg_idx = host->data->sg_len;		else			host->sg_idx = host->sg_idx-NO_OF_DMA_CHAINS_USED;	}	if(host->sg_idx == host->data->sg_len)		sg_len_remain =1;	else		sg_len_remain = data->sg_len - host->sg_idx;	if(sg_len_remain >= NO_OF_DMA_CHAINS_USED)	{		host->chains_requested = NO_OF_DMA_CHAINS_USED;	}	else	{		host->chains_requested = 1;	}	if(host->data->sg_len <= NO_OF_DMA_CHAINS_USED)	{		host->extra_chain_reqd = 0;		host->no_of_chain_reqd = 0;		host->current_cb_cnt = 0;	}	else	{		host->no_of_chain_reqd = sg_len_remain/NO_OF_DMA_CHAINS_USED;		host->extra_chain_reqd= sg_len_remain%NO_OF_DMA_CHAINS_USED;		host->current_cb_cnt = 1;	}	spin_unlock_irqrestore(&host->dma_lock, flags);	return 0;}/* * Routine to configure block leangth for MMC/SD/SDIO cards * and intiate the transfer. */static intmmc_omap_err_prepare_data(struct mmc_omap_host *host){	int i;	unsigned count=0, count1=0;	struct mmc_data *data = host->data;	if(unlikely(host == NULL))	{		return -1;	}	mmc_clk_enable_aggressive(host);		if (host->use_dma && host->chain_id != -1) {		omap_stop_dma_chain_transfers(host->chain_id);/*		  dma_unmap_sg(mmc_dev(host->mmc), data->sg, host->sg_len,			host->dma_dir);*/		omap_free_dma_chain(host->chain_id);		host->chain_id = -1;	}	for(i = 0 ;i < host->sg_idx; i++)	{		count1 += (sg_dma_len(&data->sg[i])/data->blksz);	}	for(i = host->sg_idx ;i < (host->chains_requested+host->sg_idx); i++)	{		count += (sg_dma_len(&data->sg[i])/data->blksz);	}	OMAP_HSMMC_WRITE(host->base, BLK, (host->data->blksz));	OMAP_HSMMC_WRITE(host->base, BLK,					OMAP_HSMMC_READ(host->base,					BLK) | (count << 16));	host->mod_addr = host->org_addr;	if(host->is_high_capacity ==1)		host->mod_addr += count1;//as card is high capacity	else		host->mod_addr += (count1*512);//as card is not high capacity	host->datadir = (host->data->flags & MMC_DATA_WRITE) ?			OMAP_MMC_DATADIR_WRITE : OMAP_MMC_DATADIR_READ;	if (mmc_omap_get_dma_channel(host, data) == 0)	{		enum dma_data_direction dma_data_dir;		if (data->flags & MMC_DATA_WRITE)			dma_data_dir = DMA_TO_DEVICE;		else			dma_data_dir = DMA_FROM_DEVICE;		host->total_bytes_left = 0;		mmc_chain_dma(host, host->data);		host->brs_received = 0;		host->dma_done = 0;		/* Enable DMA */		host->use_dma = 1;	}	mmc_clk_disable_aggressive(host);		return 0;}/* * Notify the xfer done on MMC/SD cards to the core */static voidmmc_omap_read_err_done(struct mmc_omap_host *host, struct mmc_data *data){	unsigned long flags;	spin_lock_irqsave(&host->dma_lock, flags);	host->flag_err = 1;	host->cmd_12 = 1;	spin_unlock_irqrestore(&host->dma_lock, flags);	mmc_clk_disable_aggressive(host);	mmc_omap_start_command(host, data->stop);}/* * Notify the xfer done on MMC/SD cards to the core */static voidmmc_omap_err_done(struct mmc_omap_host *host, struct mmc_data *data){	host->data = NULL;	if (host->use_dma && host->chain_id != -1) {		omap_stop_dma_chain_transfers(host->chain_id);		dma_unmap_sg(mmc_dev(host->mmc), data->sg, host->sg_len,			host->dma_dir);		omap_free_dma_chain(host->chain_id);		host->chain_id = -1;	}	host->datadir = OMAP_MMC_DATADIR_NONE;	host->sg_dma_len = 0;	mmc_clk_disable_aggressive(host);	if (!data->stop) {		host->mrq = NULL;		mmc_request_done(host->mmc, data->mrq);		return;	}	mmc_omap_start_command(host, data->stop);}/* * The MMC controller IRQ handler */static irqreturn_t mmc_omap_irq(int irq, void *dev_id){	struct mmc_omap_host *host = (struct mmc_omap_host *)dev_id;	int end_command, end_transfer, status, read_crc =0;	unsigned long flags;	typeof(jiffies) timeout;	if (unlikely(host == NULL))	{		return IRQ_HANDLED;	}	if(unlikely(host->cmd == NULL && host->data == NULL)) {		status = OMAP_HSMMC_READ(host->base, STAT);		if (status != 0) {			OMAP_HSMMC_WRITE(host->base, STAT, status);		}		mmc_clk_disable_aggressive(host);		return IRQ_HANDLED;	}	end_command = 0;	end_transfer = 0;	if (host->cmd) {		if (host->cmd->opcode == MMC_SELECT_CARD			|| host->cmd->opcode == MMC_SWITCH) {			timeout = jiffies + msecs_to_jiffies(MMC_TIMEOUT_MS);			while (time_before(jiffies, timeout)) {				if ((OMAP_HSMMC_READ(host->base, STAT)					& CC) == CC)					break;			}		}	}	status = OMAP_HSMMC_READ(host->base, STAT);	dev_dbg(mmc_dev(host->mmc), "Status in IRQ %x\n", status);	if(unlikely(host->use_dma == 0))	{		if (host->total_bytes_left != 0) {			if ((status & OMAP_MMC_STAT_BRR) ||				(status & TC))				mmc_omap_xfer_data(host, 0);			if (status & OMAP_MMC_STAT_BWR)				mmc_omap_xfer_data(host, 1);		}	}	if (status & (OMAP_HSMMC_ERR)) {		if (status & (OMAP_HSMMC_CMD_TIMEOUT) ||			status & (OMAP_HSMMC_CMD_CRC)) {			if (host->cmd) {				if (status & (OMAP_HSMMC_CMD_TIMEOUT)) {					/*					 * Timeouts are normal in case of					 * MMC_SEND_STATUS					 */					if (host->cmd->opcode !=						MMC_ALL_SEND_CID)						dev_dbg(mmc_dev(host->mmc),							"CMD Timeout CMD%d\n",							host->cmd->opcode);					host->cmd->error |= MMC_ERR_TIMEOUT;				} else {					dev_dbg(mmc_dev(host->mmc),						"%s: Command CRC error CMD%d\n",						mmc_hostname(host->mmc),						host->cmd->opcode);					host->cmd->error |= MMC_ERR_BADCRC;				}				end_command = 1;			}			if (host->data)				mmc_dma_cleanup(host);		}		if (status & (OMAP_HSMMC_DATA_TIMEOUT) ||			status & (OMAP_HSMMC_DATA_CRC)) {			if (host->data) {				if (status & (OMAP_HSMMC_DATA_TIMEOUT)) {					dev_dbg(mmc_dev(host->mmc),						"%s:Data timeout\n",						mmc_hostname(host->mmc));					mmc_dma_cleanup(host);				} else {					if(host->data->flags & MMC_DATA_READ)					{						read_crc = 1;						if(host->flag_err == 1)						{							dev_dbg(mmc_dev(host->mmc),								"%s:Data CRC for the second time\n",								mmc_hostname(host->mmc));							spin_lock_irqsave(&host->dma_lock, flags);							host->crc_retry++;							host->flag_err = 0;							spin_unlock_irqrestore(&host->dma_lock, flags);							if(host->crc_retry == MAX_CRC_RETRY)							{								spin_lock_irqsave(&host->dma_lock, flags);								host->mod_addr = host->org_addr = 0;								host->flag_err = host->cmd_12 = host->cmd_13 = 0;								spin_unlock_irqrestore(&host->dma_lock, flags);								host->data->error |= MMC_ERR_BADCRC;								mmc_omap_err_done(host, host->data);							}						}				   }					else						host->data->error |= MMC_ERR_BADCRC;					dev_dbg(mmc_dev(host->mmc),							"%s: Data CRC error,"							" bytes left %d\n",							mmc_hostname(host->mmc),							host->bytesleft);				}				end_transfer = 1;			}		}		if (status & OMAP_HSMMC_CARD_ERR) {			dev_dbg(mmc_dev(host->mmc),				"MMC%d: Card status error (CMD%d)\n",				host->id, host->cmd->opcode);			if (host->cmd) {				host->cmd->error |= MMC_ERR_FAILED;				end_command = 1;			}			if (host->data) {				host->data->error |= MMC_ERR_FAILED;				end_transfer = 1;			}		}	}	OMAP_HSMMC_WRITE(host->base, STAT, status);	if(host->flag_err == 1)	{		if(host->cmd_12 == 1)		{			if (status & CC) {				mmc_omap_err_cmd_done(host, host->cmd);				spin_lock_irqsave(&host->dma_lock, flags);				host->cmd_12 =0;				spin_unlock_irqrestore(&host->dma_lock, flags);				mmc_omap_start_command13(host, host->cmd);				return IRQ_HANDLED;			}		}		if(host->cmd_13 == 1)		{			if (status & CC) {				mmc_omap_err_cmd_done(host, host->cmd);				spin_lock_irqsave(&host->dma_lock, flags);				host->cmd_13 =0;				spin_unlock_irqrestore(&host->dma_lock, flags);				mmc_omap_err_prepare_data(host);				omap_start_dma_chain_transfers(host->chain_id);				mmc_omap_start_command18(host, host->cmd);				return IRQ_HANDLED;			}		}		return IRQ_HANDLED;	}	if (end_command || (status & CC)) {		mmc_omap_cmd_done(host, host->cmd);	}	if (host->mmc->mode == MMC_MODE_MMC		|| host->mmc->mode == MMC_MODE_SD){		if (end_transfer){			if(read_crc)			{				mmc_omap_err_calc(host);				mmc_omap_read_err_done(host, host->data);			}			else				mmc_omap_err_done(host, host->data);			}		else if (status & TC)			mmc_omap_end_of_data(host, host->data);	}	return IRQ_HANDLED;}/* * Turn the socket power ON/OFF */static int mmc_omap_power(struct mmc_omap_host *host, int on){	int ret = 0;	if (on){		if (machine_is_omap_2430sdp() ||					machine_is_omap_3430sdp() ||					machine_is_omap_3430labrador() ||					machine_is_omap3evm() || machine_is_omap3_beagle() )			ret = enable_mmc_power(host->id);	} else {		if (machine_is_omap_2430sdp() ||					machine_is_omap_3430sdp() ||					machine_is_omap_3430labrador() ||					machine_is_omap3evm() || machine_is_omap3_beagle() )			ret = disable_mmc_power(host->id);	}	return ret;}/* * power switching module for mmc slot 1 * power_mode=0 switches to 1.8V * power_mode=1 switches to 3V * Caller makes sure that it calls on  slot 1 with correct cpu revision */static int omap_mmc_switch_opcond(struct mmc_omap_host *host, int power_mode){	int ret = 0;	mmc_clk_disable(host);	if (cpu_is_omap2430())		clk_disable(host->dbclk);	ret = mmc_omap_power(host,0);	if (ret != 0)		dev_dbg(mmc_dev(host->mmc),"Unable to disable power to MMC1\n");		if (machine_is_omap_2430sdp() ||					machine_is_omap_3430sdp() ||					machine_is_omap_3430labrador() ||					machine_is_omap3evm() || machine_is_omap3_beagle() ) {		if (switch_power_mode(power_mode))			dev_dbg(mmc_dev(host->mmc), "Unable to switch operating"				"voltage to the card\n");	}	mmc_clk_enable(host);	if (cpu_is_omap2430()) {		if (clk_enable(host->dbclk) != 0)			dev_dbg(mmc_dev(host->mmc),				"Unable to enable MMC1 debounce clock"				"while switching power\n");	}	OMAP_HSMMC_WRITE(host->base, HCTL,			OMAP_HSMMC_READ(host->base, HCTL) & SDVSCLR);	if (power_mode == 0) {		OMAP_HSMMC_WRITE(host->base, HCTL,			OMAP_HSMMC_READ(host->base, HCTL) | SDVS18);	} else {		OMAP_HSMMC_WRITE(host->base, HCTL,			OMAP_HSMMC_READ(host->base, HCTL) | SDVS30);		host->initstream = 0;	}	OMAP_HSMMC_WRITE(host->base, HCTL,			OMAP_HSMMC_READ(host->base, HCTL) | SDBP);	return 0;}/* * Work Item to notify the core about card insertion/removal */static void mmc_omap_detect(struct work_struct *work){	struct mmc_omap_host *host = container_of(work, struct mmc_omap_host,		mmc_carddetect_work);	mmc_clk_enable_aggressive(host);	if (cpu_is_omap34xx() || (cpu_is_omap2430()		&& omap2_cpu_rev() == 2)) {		if (host->id == OMAP_MMC1_DEVID) {			if (!(OMAP_HSMMC_READ(host->base, HCTL)				& SDVSDET)) {				if (omap_mmc_switch_opcond(host, 1) != 0)					dev_dbg(mmc_dev(host->mmc),					"mmc_omap_detect:switch"					"command operation failed\n");				host->mmc->ios.vdd =					fls(host->mmc->ocr_avail) - 1;			}		}	}	mmc_detect_change(host->mmc, (HZ * 200) / 1000);	mmc_clk_disable_aggressive(host);}/* * Interrupt service routine for handling card insertion and removal */static irqreturn_t mmc_omap_irq_cd(int irq, void *dev_id){	struct mmc_omap_host *host = (struct mmc_omap_host *)dev_id;	unsigned long flags;	if (machine_is_omap_2430sdp() ||			machine_is_omap_3430sdp() ||			machine_is_omap_3430labrador() ||			machine_is_omap3evm() || machine_is_omap3_beagle() )	{		spin_lock_irqsave(&host->dma_lock, flags);		host->card_detected = 1;		host->mmc->mode = MMC_CARD_NONE;		host->rca = host->mod_addr = host->org_addr = 0;		host->is_high_capacity = 0;		host->flag_err = host->cmd_12 = host->cmd_13 = 0;		spin_unlock_irqrestore(&host->dma_lock, flags);		schedule_work(&host->mmc_carddetect_work);	}	else		dev_dbg(mmc_dev(host->mmc), "Place to implement MMC hotplug"			"implementation based on what the other"			"board can support\n");	return IRQ_HANDLED;}

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -