linux eMMC驱动分析

该文详细介绍了在A5D36平台上eMMC驱动的初始化过程,包括设备树配置、mmc主机控制器申请、时钟配置、Tasklet机制处理中断、硬件中断启动、DMA配置、超时处理、mmc插槽初始化以及debugfs文件系统设置。驱动通过设备树获取参数,然后申请和配置mmc控制器,利用Tasklet处理中断状态机,配置DMA进行数据传输,并设置了超时软定时器。最后,初始化mmc插槽并进行mmc卡操作,如检测卡的存在、读写保护等。

目录

0.说明

1.设备树初始化

2.申请mmc主机控制器

3.配置mmc的时钟配置

4.4.启动tasklet(下半部延时任务处理),基于状态机处理硬件中断(上半部紧急的事务)

5.启动硬件atmci_interrupt中断,处理mmc控制器的状态

6.配置DMA

7.设置一个超时的软定时器

8.初始化mmc插槽

9.初始化debugfs文件系统

10.提供给上层的访问数据接口

11.启动信息

12. eMMC获取CSD


0.说明

基于A5D36平台eMMC驱动分析,设备和驱动匹配之后调用atmci_probe

1.设备树初始化

atmci_of_init
	of_property_read_u32(cnp, "reg", &slot_id)
	of_get_named_gpio(cnp, "cd-gpios", 0)
	of_property_read_u32(cnp, "bus-width",&pdata->slot[slot_id].bus_width //获取总线
	of_property_read_bool(cnp, "cd-inverted")
	of_property_read_bool(cnp, "non-removable")
	of_get_named_gpio(cnp, "wp-gpios", 0)

2.申请mmc主机控制器

struct atmel_mci *host = devm_kzalloc(&pdev->dev, sizeof(*host), GFP_KERNEL); //申请atmel host主机控制器

3.配置mmc的时钟配置

//3.配置mmc的时钟配置
host->mck = devm_clk_get(&pdev->dev, "mci_clk"); //mci_clk在哪里定义的???
host->bus_hz = clk_get_rate(host->mck); //host->bus_hz数值是多少???

4.4.启动tasklet(下半部延时任务处理),基于状态机处理硬件中断(上半部紧急的事务)

tasklet_init(&host->tasklet, atmci_tasklet_func, (unsigned long)host);
	atmci_tasklet_func
		case STATE_IDLE:	//状态空闲
			
		case STATE_SENDING_CMD: //发送命令中
			atmci_test_and_clear_pending(host, EVENT_CMD_RDY)	//条件成立,执行下面的流程
			atmci_set_completed(host, EVENT_CMD_RDY);	//设置完成命令 EVENT_CMD_RDY
			atmci_command_complete(host, mrq->cmd)	//从 atmci_interrupt -> ATMCI_CMDRDY 中获取到的数据处理,分几种情况
				state = STATE_END_REQUEST;	//命令错误,直接结束
				state = STATE_DATA_XFER; 	//数据传输
				state = STATE_WAITING_NOTBUSY;	//写空闲
				state = STATE_END_REQUEST;	//结束请求
		case STATE_DATA_XFER:	//数据传输
			atmci_test_and_clear_pending(host, EVENT_XFER_COMPLETE)
			atmci_set_completed(host, EVENT_XFER_COMPLETE);
			if (host->caps.need_notbusy_for_read_ops ||(host->data->flags & MMC_DATA_WRITE))
				state = STATE_WAITING_NOTBUSY;	//
			else if (host->mrq->stop) 
				state = STATE_SENDING_STOP;
			else
				state = STATE_END_REQUEST;
		case STATE_WAITING_NOTBUSY:	//非忙等待
			atmci_test_and_clear_pending(host, EVENT_NOTBUSY)
			atmci_set_completed(host, EVENT_NOTBUSY);
			if (host->mrq->stop) 
				state = STATE_SENDING_STOP;
			else
				state = STATE_END_REQUEST;
		case STATE_SENDING_STOP:	//发送停止
			atmci_test_and_clear_pending(host, EVENT_CMD_RDY)
			if (mrq->stop->error)
				state = STATE_END_REQUEST
			else
				state = STATE_WAITING_NOTBUSY;
		case STATE_END_REQUEST:	//停止请求
			state = STATE_IDLE

5.启动硬件atmci_interrupt中断,处理mmc控制器的状态

request_irq(irq, atmci_interrupt, 0, dev_name(&pdev->dev), host);
	atmci_interrupt		
		ATMCI_DATA_ERROR_FLAGS	//数据错误标识
			atmci_set_pending(host, EVENT_DATA_ERROR); //设置 EVENT_DATA_ERROR
			tasklet_schedule(&host->tasklet);	//任务调度
		ATMCI_TXBUFE	//数据发送为空
			atmci_pdc_complete
				atmci_set_pending(host, EVENT_XFER_COMPLETE); //设置 EVENT_XFER_COMPLETE
				tasklet_schedule(&host->tasklet);	//任务调度
		ATMCI_ENDTX		//数据结束发送	
		ATMCI_RXBUFF	//数据接收缓冲满
			atmci_pdc_complete
				sg_copy_from_buffer(host->data->sg, host->data->sg_len, host->buffer, transfer_size); //数据拷贝到host->data->sg,非常重要!!!
				atmci_set_pending(host, EVENT_XFER_COMPLETE); //设置 EVENT_XFER_COMPLETE
				tasklet_schedule(&host->tasklet);	//任务调度
		ATMCI_ENDRX		//数据结束接收
		ATMCI_BLKE		//数据块已结束
			atmci_set_pending(host, EVENT_NOTBUSY);
			tasklet_schedule(&host->tasklet);
		ATMCI_NOTBUSY	//数据不忙
			atmci_set_pending(host, EVENT_NOTBUSY);
			tasklet_schedule(&host->tasklet);
		ATMCI_RXRDY		//数据接收
			atmci_read_data_pio	//接收数据
				struct scatterlist	*sg = host->sg;		//以下是从寄存器提取数据到缓存
				void *buf = sg_virt(sg);
				value = atmci_readl(host, ATMCI_RDR);
				put_unaligned(value, (u32 *)(buf + offset));
				
				atmci_set_pending(host, EVENT_XFER_COMPLETE);	//设置 EVENT_XFER_COMPLETE
		ATMCI_TXRDY		//数据发送
			atmci_write_data_pio	//发送数据
				struct scatterlist	*sg = host->sg;		//以下是从缓存提取数据到寄存器
				void *buf = sg_virt(sg);
				value = get_unaligned((u32 *)(buf + offset));
				atmci_writel(host, ATMCI_TDR, value);	
				
				atmci_set_pending(host, EVENT_XFER_COMPLETE);	//设置 EVENT_XFER_COMPLETE
		ATMCI_CMDRDY
			atmci_set_pending(host, EVENT_CMD_RDY);	//设置 EVENT_CMD_RDY
			tasklet_schedule(&host->tasklet);		//任务调度
		ATMCI_SDIOIRQA | ATMCI_SDIOIRQB
			atmci_sdio_interrupt
				mmc_signal_sdio_irq

6.配置DMA

atmci_configure_dma
	if (ret == 0) {
		host->prepare_data = &atmci_prepare_data_dma;
		host->submit_data = &atmci_submit_data_dma;
		host->stop_transfer = &atmci_stop_transfer_dma;
	} else if (host->caps.has_pdc) {
		dev_info(&pdev->dev, "using PDC\n");
		host->prepare_data = &atmci_prepare_data_pdc;
		host->submit_data = &atmci_submit_data_pdc;
		host->stop_transfer = &atmci_stop_transfer_pdc;
	} else {
		dev_info(&pdev->dev, "using PIO\n");
		host->prepare_data = &atmci_prepare_data;
		host->submit_data = &atmci_submit_data;
		host->stop_transfer = &atmci_stop_transfer;
	}
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值