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

📄 omap_hsmmc.c

📁 omap3 linux 2.6 用nocc去除了冗余代码
💻 C
📖 第 1 页 / 共 4 页
字号:
/* * drivers/mmc/omap_hsmmc.c * * Driver for OMAP2430/3430 MMC controller. * * Copyright (C) 2006-2007 Texas Instruments, Inc * Author: Texas Instruments * * 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. * * THIS PACKAGE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. */#include <linux/module.h>#include <linux/init.h>#include <linux/interrupt.h>#include <linux/delay.h>#include <linux/dma-mapping.h>#include <linux/platform_device.h>#include <linux/timer.h>#include <linux/i2c.h>#include <linux/mmc/mmc.h>#include <linux/mmc/sd.h>#include <linux/mmc/sdio.h>#include <linux/mmc/host.h>#include <linux/mmc/core.h>#include <linux/mmc/card.h>#include <asm/io.h>#include <asm/irq.h>#include <asm/dma.h>#include <asm/mach-types.h>#include <asm/arch/twl4030.h>#include <asm/hardware.h>#include <asm/arch/board.h>#include <asm/arch/cpu.h>#include <asm/arch/clock.h>#include <asm/semaphore.h>#include "omap_hsmmc.h"#include <asm/scatterlist.h>#include <linux/notifier.h>#include <linux/pm.h>/* TAG for Aggressive Power changes in MMC *///#define AGGR_PM_CAP 1#undef AGGR_PM_CAP#define mmc_clk_enable_aggressive(host)		/* NULL */#define mmc_clk_disable_aggressive(host)	/* NULL */extern int enable_mmc_power(int slot);extern int disable_mmc_power(int slot);extern int mask_carddetect_int(int slot);extern int unmask_carddetect_int(int slot);extern int setup_mmc_carddetect_irq(int irq);extern int switch_power_mode(int power_mode);extern ssize_t mmc_omap_show_cover_switch(struct device *dev, struct					device_attribute *attr, char *buf);extern ssize_t set_mmc_carddetect(struct device *dev, struct device_attribute				*attr, const char *buf, size_t count);DEVICE_ATTR(mmc_cover_switch, S_IRUGO, mmc_omap_show_cover_switch, NULL);DEVICE_ATTR(mmc_card_detect, S_IWUSR, NULL, set_mmc_carddetect);#define MMC_CARD_NONE 4#define MAX_CRC_RETRY 1struct mmc_omap_host *saved_host1, *saved_host2;struct mmc_omap_host {	int		suspended;	struct		mmc_host *mmc;	struct		mmc_request *mrq;	struct		mmc_command *cmd;	struct		mmc_data *data;	struct		timer_list detect_timer;	struct		resource *mem_res;	void		__iomem *base;	void		*mapbase;	struct		clk *fclk, *iclk, *dbclk;	/* Required for a 3430 ES1.0 Sil errata fix */	struct		clk *gptfck;	unsigned int	id;	int		irq;	int		card_detect_irq;	unsigned char	bus_mode;	struct		semaphore sem;	unsigned char	datadir;	u32		*buffer;	u32		bytesleft;	int		use_dma, dma_ch;	unsigned int	dma_len;	unsigned int	sg_dma_len;	unsigned int	dma_dir;	int chain_id;	struct omap_dma_channel_params params;	u32 chains_requested;/* Number of chains to be requested */	u32 extra_chain_reqd;/* if there is a need of last chaining*/	u32 no_of_chain_reqd;/*No of times callback called*/	u32 current_cb_cnt;	int brs_received;	int dma_done;	int dma_is_read;	spinlock_t dma_lock;	unsigned int sg_len;	int sg_idx;	u32 buffer_bytes_left;	u32 total_bytes_left;	struct		work_struct mmc_carddetect_work;	int		initstream;	/*Added for CRC retry*/	bool card_detected;	u32 rca, mod_addr, org_addr;	int is_high_capacity;	int flag_err, cmd_12,cmd_13, crc_retry;};static spinlock_t mmc_gpt_lock;static int gptfclk_counter;static int mmc_clk_counter [NO_OF_MMC_HOSTS];#define OMAP_MMC_STAT_BRR						  1 << 5#define OMAP_MMC_STAT_BWR						  1 << 4#define NO_OF_DMA_CHAINS_USED 2//This will work  with 2 chains currentlystatic void mmc_chain_dma(struct mmc_omap_host *host, struct mmc_data *data);static int mmc_omap_get_dma_channel(struct mmc_omap_host *host, struct mmc_data *data);static int mmc_clk_enable (struct mmc_omap_host *host){	int hostid = host->id - 1;	/* 3430-ES1.0  Sil errata fix */	if (is_sil_rev_less_than(OMAP3430_REV_ES2_0)) {		spin_lock(&mmc_gpt_lock);		if (!gptfclk_counter) {			if (clk_enable(host->gptfck) != 0) {				dev_dbg(mmc_dev(host->mmc),					"Unable to enable gptfck clock \n");				goto clk_en_err;			}		}		gptfclk_counter ++;		spin_unlock(&mmc_gpt_lock);	}	if (!mmc_clk_counter[hostid]) {		if (clk_enable(host->iclk) != 0)			goto clk_en_err1;		if (clk_enable(host->fclk) != 0)			goto clk_en_err2;	}	mmc_clk_counter[hostid] ++;	return 0;clk_en_err2:	/* On fclk failure */	clk_disable(host->iclk);clk_en_err1:	/* On iclk failure */	if (is_sil_rev_less_than(OMAP3430_REV_ES2_0)) {		spin_lock(&mmc_gpt_lock);		gptfclk_counter --;		if (!gptfclk_counter)			clk_disable(host->gptfck);		spin_unlock(&mmc_gpt_lock);	}clk_en_err:	dev_dbg(mmc_dev(host->mmc),		"Unable to enable MMC clocks \n");	spin_unlock(&mmc_gpt_lock);	return -1;}static int mmc_clk_disable (struct mmc_omap_host *host){	int hostid = host->id - 1;	mmc_clk_counter[hostid] --;	if (!mmc_clk_counter[hostid]) {		clk_disable(host->fclk);		clk_disable(host->iclk);	}	/* 3430-ES1.0  Sil errata fix */	if (is_sil_rev_less_than(OMAP3430_REV_ES2_0)) {		spin_lock(&mmc_gpt_lock);		gptfclk_counter --;		if (!gptfclk_counter)			clk_disable(host->gptfck);		spin_unlock(&mmc_gpt_lock);	}	return 0;}/* * Stop clock to the card */static void omap_mmc_stop_clock(struct mmc_omap_host *host){	/* Stop clock to the card */	OMAP_HSMMC_WRITE(host->base, SYSCTL,			OMAP_HSMMC_READ(host->base, SYSCTL) & ~CEN);	if ((OMAP_HSMMC_READ(host->base, SYSCTL) & CEN) != 0x0)		dev_dbg(mmc_dev(host->mmc), "MMC clock not stoped,"					"clock freq can not be altered\n");}/* * Send init stream sequence to the card before sending IDLE command */static void send_init_stream(struct mmc_omap_host *host){	int reg = 0, status;	typeof(jiffies) timeout;	disable_irq(host->irq);	OMAP_HSMMC_WRITE(host->base, ISE, INT_CLEAR);	OMAP_HSMMC_WRITE(host->base, IE, INT_CLEAR);	OMAP_HSMMC_WRITE(host->base, CON,			OMAP_HSMMC_READ(host->base, CON) | INIT_STREAM);	OMAP_HSMMC_WRITE(host->base, CMD, INIT_STREAM_CMD);	timeout = jiffies + msecs_to_jiffies(MMC_TIMEOUT_MS);	while ((reg != CC) && time_before(jiffies, timeout)) {		reg = OMAP_HSMMC_READ(host->base, STAT) & CC;	}	OMAP_HSMMC_WRITE(host->base, CON,			OMAP_HSMMC_READ(host->base, CON) & ~INIT_STREAM);	status = OMAP_HSMMC_READ(host->base, STAT);	OMAP_HSMMC_WRITE(host->base, STAT, status);	enable_irq(host->irq);}/* * Configure the resptype, cmdtype and send the given command to the card */static voidmmc_omap_start_command18(struct mmc_omap_host *host, struct mmc_command *cmd){	int  cmdreg = 0, resptype = 0, cmdtype = 0;	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_READ_MULTIPLE_BLOCK << 24) | (resptype << 16) | (cmdtype << 22);	cmdreg |= DP_SELECT | DDIR | MSBS | BCE | DMA_EN;	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->mod_addr);	OMAP_HSMMC_WRITE(host->base, CMD, cmdreg);}/* * Configure the resptype, cmdtype and send the given command to the card */static voidmmc_omap_start_command(struct mmc_omap_host *host, struct mmc_command *cmd){	int  cmdreg = 0, resptype = 0, cmdtype = 0;	dev_dbg(mmc_dev(host->mmc), "%s: CMD%d, argument 0x%08x\n",			mmc_hostname(host->mmc), cmd->opcode, cmd->arg);	host->cmd = cmd;	mmc_clk_enable_aggressive(host);	/* Clear status bits and enable interrupts */	OMAP_HSMMC_WRITE(host->base, STAT, OMAP_HSMMC_STAT_CLEAR);	switch (RSP_TYPE(mmc_resp_type(cmd))) {	case RSP_TYPE(MMC_RSP_R1):	case RSP_TYPE(MMC_RSP_R3):		/* resp 1, resp 1b */		resptype = 2;		break;	case RSP_TYPE(MMC_RSP_R2):		resptype = 1;		break;	default:		break;	}	cmdreg = (cmd->opcode << 24) | (resptype << 16) | (cmdtype << 22);	if (cmd->opcode == MMC_SEND_CSD)		host->rca = cmd->arg;	if (cmd->opcode == MMC_READ_MULTIPLE_BLOCK)		host->org_addr = cmd->arg;	if (cmd->opcode == MMC_READ_SINGLE_BLOCK		|| cmd->opcode == MMC_READ_MULTIPLE_BLOCK		|| cmd->opcode == SD_APP_SEND_SCR		|| (cmd->opcode == SD_SWITCH && cmd->arg == 0xfffff1)		|| (cmd->opcode == SD_SWITCH && cmd->arg == 0x80fffff1)		|| (cmd->opcode == MMC_SEND_EXT_CSD && cmd->arg == 0)) {		if (host->use_dma)			cmdreg |= DP_SELECT | DDIR | MSBS | BCE | DMA_EN;		else			cmdreg |= DP_SELECT | DDIR | MSBS | BCE;	} else if (cmd->opcode == MMC_WRITE_BLOCK		|| cmd->opcode == MMC_WRITE_MULTIPLE_BLOCK) {		if (host->use_dma)			cmdreg |= DP_SELECT | MSBS | BCE | DMA_EN;		else			cmdreg |= DP_SELECT | MSBS | BCE;		cmdreg &= ~(DDIR);	}	if (cmd->opcode == MMC_GO_IDLE_STATE || cmd->opcode == MMC_SEND_OP_COND		|| cmd->opcode == MMC_ALL_SEND_CID)		OMAP_HSMMC_WRITE(host->base, CON,				OMAP_HSMMC_READ(host->base, CON) | OD);	if (cmd->opcode == MMC_GO_IDLE_STATE) {		if (host->initstream == 0) {			send_init_stream(host);			host->initstream = 1;		}	}	OMAP_HSMMC_WRITE(host->base, ISE, INT_EN_MASK);	OMAP_HSMMC_WRITE(host->base, IE, INT_EN_MASK);	OMAP_HSMMC_WRITE(host->base, ARG, cmd->arg);	OMAP_HSMMC_WRITE(host->base, CMD, cmdreg);}/* * Notify the xfer done on MMC/SD cards to the core */static voidmmc_omap_xfer_done(struct mmc_omap_host *host, struct mmc_data *data){	if(host->use_dma)	{		/* Un-map the memory required for DMA */		dma_unmap_sg(mmc_dev(host->mmc), data->sg, host->sg_len,			host->dma_dir);	}	/* Reset the variables as transfer is complete */	host->data = NULL;	host->sg_len = 0;	host->sg_dma_len = 0;	host->datadir = OMAP_MMC_DATADIR_NONE;	if (data->error == MMC_ERR_NONE)		data->bytes_xfered += data->blocks * (data->blksz);	else		data->bytes_xfered = 0;	mmc_clk_disable_aggressive(host);	if (!data->stop) {		host->mrq = NULL;		mmc_request_done(host->mmc, data->mrq);		return;	}	/* Send the stop command. Remember FCLK is not stopped before this call */	mmc_omap_start_command(host, data->stop);}static voidmmc_omap_end_of_data(struct mmc_omap_host *host, struct mmc_data *data){	unsigned long flags;	int done;	if (!host->use_dma) {		mmc_omap_xfer_done(host, data);		return;	}	done = 0;	spin_lock_irqsave(&host->dma_lock, flags);	if (host->dma_done)		done = 1;	else		host->brs_received = 1;	spin_unlock_irqrestore(&host->dma_lock, flags);	if (done)		mmc_omap_xfer_done(host, data);}static voidmmc_omap_dma_done(struct mmc_omap_host *host, struct mmc_data *data){	unsigned long flags;	int done;	done = 0;	spin_lock_irqsave(&host->dma_lock, flags);	if (host->brs_received)		done = 1;	else		host->dma_done = 1;	spin_unlock_irqrestore(&host->dma_lock, flags);	if (done)		mmc_omap_xfer_done(host, data);}/* * Notify the core about command completion */static voidmmc_omap_cmd_done(struct mmc_omap_host *host, struct mmc_command *cmd){	host->cmd = NULL;	if (cmd->flags & MMC_RSP_PRESENT) {		if (cmd->flags & MMC_RSP_136) {			/* response type 2 */			cmd->resp[3] = OMAP_HSMMC_READ(host->base, RSP10);			cmd->resp[2] = OMAP_HSMMC_READ(host->base, RSP32);			cmd->resp[1] = OMAP_HSMMC_READ(host->base, RSP54);			cmd->resp[0] = OMAP_HSMMC_READ(host->base, RSP76);		} else {			/* response types 1, 1b, 3, 4, 5, 6 */			cmd->resp[0] = OMAP_HSMMC_READ(host->base, RSP10);		}	}	if(cmd->opcode == SD_APP_OP_COND)	{		if(cmd->resp[0] & 0x40000000)		{			host->is_high_capacity = 1;		}		else		{			host->is_high_capacity = 0;		}	}	if(cmd->opcode == MMC_SEND_OP_COND)	{		if(cmd->resp[0] & 0x40000000)		{			host->is_high_capacity = 1;		}		else		{			host->is_high_capacity = 0;		}	}		if (host->data == NULL || cmd->error != MMC_ERR_NONE) {			dev_dbg(mmc_dev(host->mmc), "%s: End request, err %x\n",					mmc_hostname(host->mmc), cmd->error);			host->mrq = NULL;			mmc_clk_disable_aggressive(host);			mmc_request_done(host->mmc, cmd->mrq);		}}/* * Dma cleaning in case of command errors */static void mmc_dma_cleanup(struct mmc_omap_host *host){	int dma_ch;	host->data->error |= MMC_ERR_TIMEOUT;	if(host->mmc->mode == MMC_MODE_SDIO)	{		if (host->use_dma && host->dma_ch != -1) {			dma_unmap_sg(mmc_dev(host->mmc), host->data->sg, host->dma_len,				host->dma_dir);			dma_ch = host->dma_ch;			host->dma_ch = -1;			omap_free_dma(dma_ch);		}	}	else	{		if (host->use_dma) {			omap_stop_dma_chain_transfers(host->chain_id);			dma_unmap_sg(mmc_dev(host->mmc), host->data->sg, host->sg_len,				host->dma_dir);			omap_free_dma_chain(host->chain_id);			mmc_omap_dma_done(host, host->data);			host->chain_id = -1;		}	}	host->data = NULL;	host->datadir = OMAP_MMC_DATADIR_NONE;}/* PIO only */static voidmmc_omap_sg_to_buf(struct mmc_omap_host *host){	struct scatterlist *sg;	sg = host->data->sg + host->sg_idx;	host->buffer_bytes_left = sg->length;	host->buffer = page_address(sg->page) + sg->offset;	if (host->buffer_bytes_left > host->total_bytes_left)		host->buffer_bytes_left = host->total_bytes_left;}/* PIO only */static voidmmc_omap_xfer_data(struct mmc_omap_host *host, int write){	int n;	if (host->buffer_bytes_left == 0) {		host->sg_idx++;		BUG_ON(host->sg_idx == host->sg_len);		mmc_omap_sg_to_buf(host);	}	n = 64;	if (n > host->buffer_bytes_left)		n = host->buffer_bytes_left;	host->buffer_bytes_left -= n;	host->total_bytes_left -= n;	host->data->bytes_xfered += n;

⌨️ 快捷键说明

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