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

📄 pxa3xx_controller.c

📁 基于PXA3XX的SD驱动
💻 C
📖 第 1 页 / 共 3 页
字号:
		host->ios.bus_width = host->bus_width;}#ifdef CONFIG_DVFMstatic int pxa3xx_mmc_dvfm_notifier(unsigned cmd, void *client_data, void *info){	struct pxa_mss_host *pxa_host = (struct pxa_mss_host *)client_data;	switch (cmd) {	case FV_NOTIFIER_QUERY_SET :		if (pxa_host->dma_run)			return -1;		break;	case FV_NOTIFIER_PRE_SET :		break;	case FV_NOTIFIER_POST_SET :		break;	}	return 0;}#endif/* *  send command by setting CMDAT reg of MMC/SD/SDIO controller. *  Note: to hide info about SD/SDIO. */static void pxa_mss_handle_request(struct mss_host *host, 		struct mss_ll_request *llreq){	struct pxa_mss_host *pxa_host = host->private;	struct mss_cmd *cmd;	struct mss_card *card = host->active_card;	u32 cmd_dat = 0;	dbg("pxammc %d acitive slot %x\n", host->id + 1,		(pxa_host->active_slot) ? pxa_host->active_slot->id : -1);	if (pxa_host->active_slot != card->slot) {		dbg("pxammc %d change acitive slot to %d\n", host->id + 1, 				card->slot->id);		pxa_mss_slot_select(card->slot);		pxa_host->active_slot = card->slot;	}	pxa_host->cmd = llreq->cmd;	pxa_host->data = llreq->data;	pxa_host->llreq = llreq;	cmd = pxa_host->cmd;//	printk("====>%s:Read to send CMD :%d, cmd flag 0x%x\n", __FUNCTION__, cmd->opcode, cmd->flags);	dbg("Read to send CMD :0x%x, cmd flag 0x%x", cmd->opcode, cmd->flags);	if (cmd->flags & MSS_CMD_INIT)		cmd_dat |= MMC_CMDAT_INIT;	if (cmd->flags & MSS_CMD_STOP)		cmd_dat |= MMC_CMDAT_STOP;	if (cmd->flags & MSS_CMD_SDIO_EN || host->sdio_int)		cmd_dat |= MMC_CMDAT_SDIO_INT;	if (llreq->data) {		dbg("data flags 0x%x", llreq->data->flags);		if (llreq->data->flags & MSS_DATA_WRITE)			cmd_dat |= MMC_CMDAT_WRITE;		pxa_host_setup_data(pxa_host, llreq->data);		cmd_dat |= (MMC_CMDAT_DATA | MMC_CMDAT_DMA);		cmd_dat &= ~MMC_CMDAT_BUSY;		dbg("data nob %d, block_len %d", llreq->data->blocks, 				llreq->data->blksz);		if (llreq->data->flags & MSS_DATA_STREAM)			cmd_dat |= MMC_CMDAT_STREAM;	} else {		writel(0, pxa_host->base + MMC_NUMBLK);		writel(0, pxa_host->base + MMC_BLKLEN);	}	dbg("cmd rtype %d", cmd->rtype);	switch (cmd->rtype) {		case MSS_RESPONSE_NONE:			cmd_dat |= MMC_CMDAT_RESP_FMT_NONE;			break;		case MSS_RESPONSE_R1B:			cmd_dat |= MMC_CMDAT_BUSY;			/* Fall through */		case MSS_RESPONSE_R1:		case MSS_RESPONSE_R4:		case MSS_RESPONSE_R5:		case MSS_RESPONSE_R6:		case MSS_RESPONSE_R7:			cmd_dat |= MMC_CMDAT_RESP_FMT_R1;			break;		case MSS_RESPONSE_R2_CID:		case MSS_RESPONSE_R2_CSD:			cmd_dat |= MMC_CMDAT_RESP_FMT_R2;			break;		case MSS_RESPONSE_R3:			cmd_dat |= MMC_CMDAT_RESP_FMT_R3;			break;	}	dbg("card bus width %d", card->bus_width);	if (card->bus_width == MSS_BUSWIDTH_4BIT)		cmd_dat |= MMC_CMDAT_4DAT;		writel(cmd->opcode, pxa_host->base + MMC_CMD);	writel(cmd->arg >> 16, pxa_host->base + MMC_ARGH);	writel(cmd->arg & 0xffff, pxa_host->base + MMC_ARGL);	writel(cmd_dat, pxa_host->base + MMC_CMDAT);		dbg("Read out MMC_CMD 0x%x",readl(pxa_host->base+MMC_CMD));	dbg("Read out MMC_ARGH 0x%x",readl(pxa_host->base+MMC_ARGH));	dbg("Read out MMC_ARGL 0x%x",readl(pxa_host->base+MMC_ARGL));	dbg("Read out MMC_CMDAT 0x%x",readl(pxa_host->base+MMC_CMDAT));	dbg("Read out MMC_CLKRT 0x%x",readl(pxa_host->base+MMC_CLKRT));	dbg("Read out MMC_NUMBLK 0x%x",readl(pxa_host->base+MMC_NUMBLK));	dbg("Read out MMC_BLKSZ 0x%x",readl(pxa_host->base+MMC_BLKLEN));	if (llreq->data && llreq->data->sg_len) {		pxa_host->dma_run = 1;		DDADR(pxa_host->dma) = pxa_host->sg_dma;		/* start DMA */		DCSR(pxa_host->dma) |= DCSR_RUN; 		dbg("enable dma %d, DDADR: 0x%x, DCSR: 0x%x", pxa_host->dma, 				DDADR(pxa_host->dma), DCSR(pxa_host->dma));	}	pxa_host_enable_int(pxa_host, MMC_I_MASK_END_CMD_RES | MMC_I_MASK_RES_ERR);	}static void pxa_mss_enable_sdio_int(struct mss_host *host, int enable){	unsigned long flags;	struct pxa_mss_host *pxa_host = host->private;		local_irq_save(flags);	if (enable) {		host->sdio_int = MSS_SDIO_INT_EN;		pxa_host_enable_int(pxa_host, MMC_I_MASK_SDIO_INT);	}	else {		host->sdio_int = MSS_SDIO_INT_DIS;		pxa_host_disable_int(pxa_host, MMC_I_MASK_SDIO_INT);	}	local_irq_restore(flags);}/* * DMA irq handler. devid represent pxa_mss_controller_device for dma interrupt * is to pxa_controller */static void pxa_host_dma_irq(int dma, void *devid){	unsigned int dcsr;	struct pxa_mss_host *pxa_host;	struct mss_card *card;	struct mss_cmd *cmd;	struct mss_data *data;	dbg("DMA IRQ");	pxa_host = (struct pxa_mss_host *)devid;	card = pxa_host->host->active_card;	data = pxa_host->data;	if (!card) {		printk(KERN_ERR "Can not find card\n");		BUG();	}	cmd = pxa_host->cmd;	dcsr = DCSR(dma);	DCSR(dma) &= ~DCSR_STOPIRQEN;		dbg("dma int dcsr:0x%x, DSADR:0x%x, DCMD:0x%x", dcsr, DSADR(dma),		       	DCMD(dma));	if (dcsr & DCSR_BUSERR) {		/* dbg("DCSR_BUSEER"); */		cmd->error = MSS_ERROR_DMA;		data->bytes_xfered = 0;		pxa_host_disable_int(pxa_host, MMC_I_MASK_DATA_TRAN_DONE | 				MMC_I_MASK_DAT_ERR | MMC_I_MASK_TINT);		pxa_host->llreq->done(pxa_host->llreq);	}	else if (dcsr & DCSR_STOPSTATE) {		if (data && (data->flags & MSS_DATA_WRITE))			writel(BUF_PART_FULL, pxa_host->base + MMC_PRTBUF); 		if (data && (data->flags & MSS_DATA_WRITE) && 				cmd->rtype == MSS_RESPONSE_R1B)			pxa_host_enable_int(pxa_host, MMC_I_REG_PRG_DONE);		/* dbg("sg index:%d, dma_len:%d", pxa_host->sg_idx, 				pxa_host->dma_len); */		else if (data && (data->flags & 					(MSS_DATA_WRITE | MSS_DATA_READ))) {			pxa_host_enable_int(pxa_host, MMC_I_MASK_DATA_TRAN_DONE				       	| MMC_I_MASK_TINT);		} else {			printk(KERN_ERR "ERROR in SLOT_DMA_IRQ, neither WRITE"				       " nor READ or sg_idx exceed dma_len");			dump_stack();		}	}	pxa_host->dma_run = 0;		return;	}/* *  slot INT routine for commands with R1B response type */static int pxa_host_r1b_irq(struct pxa_mss_host *pxa_host, 		u32  ireg, u32 stat, u32 mask){	struct mss_host *host;	struct mss_cmd *cmd;	/* dbg("host%d, I_REG: 0x%x, STAT: 0x%x, MASK: 0x%x\n", 	pxa_host->host->id, (u32)ireg, (u32)stat, (u32)mask); */	host = pxa_host->host;	cmd = pxa_host->cmd;		if ((ireg & MMC_I_REG_END_CMD_RES) 			&& (!(mask & MMC_I_MASK_END_CMD_RES)) ) {		pxa_host_disable_int(pxa_host, 				MMC_I_MASK_END_CMD_RES | MMC_I_MASK_RES_ERR);		pxa_host_get_response(pxa_host, cmd);		if (ireg & MMC_I_REG_RES_ERR) {			pxa_host_set_error(cmd, stat);			/* dbg("in RES_ERROR, prepare to cmd_complete");*/			pxa_host->llreq->done(pxa_host->llreq);			return 1;		}				pxa_host_enable_int(pxa_host, MMC_I_MASK_PRG_DONE);		return 1;	}	if ((ireg & MMC_I_REG_PRG_DONE) && (!(mask & MMC_I_MASK_PRG_DONE)) ) {		pxa_host_disable_int(pxa_host, MMC_I_MASK_PRG_DONE);		/* dbg("in PRG_DONE, prepare to cmd_complete\n"); */		pxa_host->llreq->done(pxa_host->llreq); 	}	return 1;}/* *  slot INT routine for write commands with data buffer */static int pxa_host_write_irq(struct pxa_mss_host *pxa_host,		u32 ireg, u32 stat, u32 mask){	struct mss_host *host;	struct mss_cmd *cmd;	host = pxa_host->host;	cmd = pxa_host->cmd;		if ((ireg & MMC_I_REG_END_CMD_RES) && \		(!(mask & MMC_I_MASK_END_CMD_RES)) ) {		pxa_host_disable_int(pxa_host, 			MMC_I_MASK_END_CMD_RES | MMC_I_MASK_RES_ERR);		if (ireg & MMC_I_REG_RES_ERR) {			pxa_host_set_error(cmd, stat);			return 1;		}			pxa_host_get_response(pxa_host, cmd);		return 1;	}	if ((ireg & MMC_I_REG_TINT) && (!(mask & MMC_I_MASK_TINT))) {		stat = readl(pxa_host->base + MMC_STAT);		pxa_host_disable_int(pxa_host, \			MMC_I_MASK_DATA_TRAN_DONE | \			MMC_I_MASK_DAT_ERR | \			MMC_I_MASK_TINT);		pxa_host_set_error(cmd, stat);		/* dbg("DATA/TIMEOUT error.  I_REG: 0x%x, STAT: 0x%x, 		 I_MASK: 0x%x. prepare to cmd_complete", MMC_I_REG, MMC_STAT, 		 MMC_I_MASK); */		pxa_host->llreq->done(pxa_host->llreq);		return 1;	}		/* wait for DMA interrupt, DATA WRITE done once DATA_TRAN_DONE 	 * interrupt occurred 	 */	if ((ireg & MMC_I_REG_DATA_TRAN_DONE) 			&& (!(mask & MMC_I_MASK_DATA_TRAN_DONE)) ) {		/* Note: must not disable DATA_ERROR interrupt, 		 * for it may be occured again!!! 		 */		pxa_host_disable_int(pxa_host, 				MMC_I_MASK_DATA_TRAN_DONE |				MMC_I_MASK_DAT_ERR |				MMC_I_MASK_TINT);		pxa_host_enable_int(pxa_host, MMC_I_MASK_PRG_DONE); 		return 1;	}			if ((ireg & MMC_I_REG_PRG_DONE) && (!(mask & MMC_I_MASK_PRG_DONE)) ) {		/* pxa_host_get_response(pxa_host, cmd); */		pxa_host_disable_int(pxa_host, MMC_I_MASK_PRG_DONE);		/* dbg("in PRG_DONE, prepare to cmd_complete"); */		pxa_host->llreq->done(pxa_host->llreq); 	}	return 1;}/** *  pxa_slot_read_irq *  @card: mss_card_device *  @ireg: value of MMCx_I_REG *  @stat: value of MMCx_STAT *  @mask: value of MMCx_I_MASK * *  slot INT routine for read commands with data buffer */static int pxa_host_read_irq(struct pxa_mss_host *pxa_host,		u32 ireg, u32 stat, u32 mask){	struct mss_host *host;	struct mss_cmd *cmd;	host = pxa_host->host;	cmd = pxa_host->cmd;	if ((ireg & MMC_I_REG_END_CMD_RES) 			&& (!(mask & MMC_I_MASK_END_CMD_RES))) {		pxa_host_disable_int(pxa_host, 				MMC_I_MASK_END_CMD_RES | MMC_I_MASK_RES_ERR);		if (ireg & MMC_I_REG_RES_ERR) {			pxa_host_set_error(cmd, stat);			pxa_host_enable_int(pxa_host, MMC_I_MASK_TINT);			return 1;	  	}	  	pxa_host_get_response(pxa_host, cmd);		/* DATA_TRAN_DONE is not enabled now */		pxa_host_enable_int(pxa_host, MMC_I_MASK_TINT);		return 1;	}	if ((ireg & MMC_I_REG_TINT) && (!(mask & MMC_I_MASK_TINT))) {		stat = readl(pxa_host->base + MMC_STAT);		pxa_host_disable_int(pxa_host, \			MMC_I_MASK_DATA_TRAN_DONE | \			MMC_I_MASK_DAT_ERR | \			MMC_I_MASK_TINT);		pxa_host_set_error(cmd, stat);		pxa_host->llreq->done(pxa_host->llreq);		return 1;	}	/* wait for DMA interrupt, DATA READ done 	 * once DATA_TRAN_DONE interrupt occurred 	 */	if ((ireg & MMC_I_REG_DATA_TRAN_DONE) && \		(!(mask & MMC_I_MASK_DATA_TRAN_DONE))) {		pxa_host_disable_int(pxa_host, \			MMC_I_MASK_DATA_TRAN_DONE | \			MMC_I_MASK_DAT_ERR | \			MMC_I_MASK_TINT);		/* check data error */                if (ireg & MMC_I_MASK_DAT_ERR) {                        stat = readl(pxa_host->base + MMC_STAT);                        pxa_host_set_error(cmd, stat);                }		/* dbg("in DATA_TRAN_DONE, prepare to cmd_complete");*/		pxa_host->llreq->done(pxa_host->llreq); 		return 1;	}		return 1;}/** *  pxa_slot_other_irq *  @card: mss_card_device *  @ireg: value of MMCx_I_REG *  @stat: value of MMCx_STAT *  @mask: value of MMCx_I_MASK * *  slot INT routine for commands other than R1B, write and read commands */static int pxa_host_other_irq(struct pxa_mss_host *pxa_host, 		u32  ireg, u32 stat, u32 mask){	struct mss_cmd *cmd = pxa_host->cmd;	if ((ireg & MMC_I_REG_RES_ERR) && (!(mask & MMC_I_MASK_RES_ERR))){		pxa_host_disable_int(pxa_host, 			MMC_I_MASK_END_CMD_RES | \			MMC_I_MASK_RES_ERR);		pxa_host_get_response(pxa_host, cmd);		pxa_host_set_error(cmd, stat);		/* dbg("in RES_ERROR, prepare to cmd_complete\n"); */		pxa_host->llreq->done(pxa_host->llreq);		return 1;	} else if((ireg & MMC_I_REG_END_CMD_RES) && \			(!(mask & MMC_I_MASK_END_CMD_RES))) {		pxa_host_disable_int(pxa_host, \			MMC_I_MASK_END_CMD_RES | \			MMC_I_MASK_RES_ERR);		pxa_host_get_response(pxa_host, cmd);		pxa_host->llreq->done(pxa_host->llreq);	}		return 1;}static void sdio_interrupt_handler(struct work_struct *work){ 	struct pxa_slot * pxa_slot;  	struct pxa_mss_host * pxa_host;  	struct mss_card * card;	struct mss_driver *drv; 		pxa_slot = container_of(work, struct pxa_slot, sdio_int);	if (pxa_slot && pxa_slot->slot && pxa_slot->slot->host)		pxa_host = pxa_slot->slot->host->private;	else		goto out;	if (pxa_host && pxa_host->active_slot)		card = pxa_host->active_slot->card;	else		goto out;		if(pxa_host && pxa_host->active_slot && pxa_host->active_slot->card)	{		drv = container_of(pxa_host->active_slot->card->dev.driver,                                struct mss_driver, driver);	}	if (drv->sdio_int_handler)		drv->sdio_int_handler(card);	else		return;	out:	dbg("null pointer occurred\n");	return;}/** *  pxa_slot_irq *  @irq: IRQ number *  @devid: pointer to pxa_mss_controller_device *  @regs: interrupt context * *  response interrupt and sdio interrupt handler.  *  devid represent pxa_mss_controller_device because  *  interrupt is to pxa_controller */static irqreturn_t pxa_host_irq(int irq, void *devid){	struct pxa_mss_host *pxa_host;	struct mss_cmd *cmd;	struct mss_data *data;	struct mss_driver *drv;	struct mss_card *card;	u32 ireg, stat, mask;	pxa_host = (struct pxa_mss_host *)devid;	cmd = pxa_host->cmd;	data = pxa_host->data;	card = pxa_host->host->active_card;	ireg = readl(pxa_host->base + MMC_I_REG);	stat = readl(pxa_host->base + MMC_STAT);	mask = readl(pxa_host->base + MMC_I_MASK);//	printk("%s:host%d irq, I_REG:0x%x, STAT:0x%x, I_MASK:0x%x, CLKRT:0x%x," //			"RESTO:0x%x, RDTO:0x%x\n", __FUNCTION__,//			pxa_host->host->id, ireg, stat, mask, //			readl(pxa_host->base + MMC_CLKRT), //			readl(pxa_host->base + MMC_RESTO),//			readl(pxa_host->base + MMC_RDTO));	dbg("host%d irq, I_REG:0x%x, STAT:0x%x, I_MASK:0x%x, CLKRT:0x%x," 			"RESTO:0x%x, RDTO:0x%x\n", 			pxa_host->host->id, ireg, stat, mask, 			readl(pxa_host->base + MMC_CLKRT), 			readl(pxa_host->base + MMC_RESTO),			readl(pxa_host->base + MMC_RDTO));	if (data) {		if (data->flags & MSS_DATA_WRITE) {			pxa_host_write_irq(pxa_host, ireg, stat, mask);		}		if (data->flags & MSS_DATA_READ) {			pxa_host_read_irq(pxa_host, ireg, stat, mask);		}	}	else if ((cmd->rtype == MSS_RESPONSE_R1B) && (!data || !data->sg_len))		pxa_host_r1b_irq(pxa_host, ireg, stat, mask);	else		pxa_host_other_irq(pxa_host, ireg, stat, mask);			/* handle sdio interrupt, wakeup sdio int IRQ handler thread */	if ((ireg & MMC_I_REG_SDIO_INT) && (!(mask & MMC_I_MASK_SDIO_INT))) {		struct pxa_slot *pxa_slot = pxa_host->active_slot->private;		dbg("SDIO interrupt ocurred");		pxa_host_disable_int(pxa_host, MMC_I_MASK_SDIO_INT);		pxa_host->host->sdio_int = MSS_SDIO_INT_DIS;		if (!pxa_host->active_slot->card ||		    !pxa_host->active_slot->card->dev.driver)			return IRQ_HANDLED;		drv = container_of(pxa_host->active_slot->card->dev.driver, 				struct mss_driver, driver);		/* application driver sdio_int_handler should 		 * get card from work_struct. e.g,		 * sdio_int_handler(struct work_struct *work)		 * { 		 * 	struct pxa_slot * pxa_slot = 		 * 		contrainer_of(work, struct pxa_slot, sdio_int.work);		 * 	struct pxa_mss_host * pxa_host = 		 * 		pxa_slot->slot->host->private;		 * 	struct mss_card * card = pxa_host->active_slot->card;		 * 	...		 * }		 */		INIT_WORK(&pxa_slot->sdio_int, 				(void (*)(void *))sdio_interrupt_handler);		queue_work(pxa_host->sdio_work_queue, &pxa_slot->sdio_int);	}	return IRQ_HANDLED;}/** *  pxa_slot_gpio_irq *  @irq: IRQ number *  @devid: pointer to mss_slot *  @regs: interrupt context * *  hot-plug interrupt handler. devid represent slot  *  because hot-plug is slot-specific.  */static irqreturn_t pxa_slot_gpio_irq(int irq, void *devid){	struct mss_slot *slot = (struct mss_slot *)devid;	struct pxa_slot *pxa_slot = slot->private;	struct pxa_mss_host *pxa_host = slot->host->private;	dbg("Slot :%d, inttrupt", slot->id);

⌨️ 快捷键说明

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