【MMC子系统】四、MMC控制器驱动层

img
我的圈子: 高级工程师聚集地
我是董哥,高级嵌入式软件开发工程师,从事嵌入式Linux驱动开发和系统开发,曾就职于世界500强企业!
创作理念:专注分享高质量嵌入式文章,让大家读有所得!
img

文章目录

    • 4.1 通用驱动框架
    • 4.2 注册与注销函数
      • 4.2.1 probe函数
      • 4.2.2 remove函数
    • 4.3 ops函数实现
    • 4.4 PM接口

MMC控制器驱动层一般为chip manufacturer做的事,不同的芯片实现方式不尽相同。

Linux内核源码,相当大的一部分都是由Device Drivers程序代码组成,其次另一大部分就是那些你从来都没有听说过的Filesystem Format组成,真正核心的代码非常短小精悍的。

当然,设备驱动程序也有一套既定的框架,按照框架来编写,实现对应的接口就可以了,在这里,我们主要分析一下MMC控制器驱动的实现框架,不拘泥于细节。

下文以sunxi-mmc.c为例来分析,基于Linux4.19

 

4.1 通用驱动框架

static int sunxi_mmc_probe(struct platform_device *pdev) {.....
}static const struct of_device_id sunxi_mmc_of_match[] = {{ .compatible = "allwinner,sun4i-a10-mmc", .data = &sun4i_a10_cfg },{ .compatible = "allwinner,sun5i-a13-mmc", .data = &sun5i_a13_cfg },{ .compatible = "allwinner,sun7i-a20-mmc", .data = &sun7i_a20_cfg },{ .compatible = "allwinner,sun8i-a83t-emmc", .data = &sun8i_a83t_emmc_cfg },{ .compatible = "allwinner,sun9i-a80-mmc", .data = &sun9i_a80_cfg },{ .compatible = "allwinner,sun50i-a64-mmc", .data = &sun50i_a64_cfg },{ .compatible = "allwinner,sun50i-a64-emmc", .data = &sun50i_a64_emmc_cfg },{ /* sentinel */ }
};
MODULE_DEVICE_TABLE(of, sunxi_mmc_of_match);static const struct dev_pm_ops sunxi_mmc_pm_ops = {SET_RUNTIME_PM_OPS(sunxi_mmc_runtime_suspend,sunxi_mmc_runtime_resume,NULL)
};static struct platform_driver sunxi_mmc_driver = {.driver = {.name	= "sunxi-mmc",.of_match_table = of_match_ptr(sunxi_mmc_of_match),.pm = &sunxi_mmc_pm_ops,},.probe		= sunxi_mmc_probe,.remove		= sunxi_mmc_remove,
};
module_platform_driver(sunxi_mmc_driver);MODULE_DESCRIPTION("Allwinner's SD/MMC Card Controller Driver");
MODULE_LICENSE("GPL v2");
MODULE_AUTHOR("David Lanzendörfer <david.lanzendoerfer@o2s.ch>");
MODULE_ALIAS("platform:sunxi-mmc");

这套基本的框架,老生常谈,其主要功能就是:按照of_match_table匹配表,来实现platform_deviceplatform_driver的匹配,然后执行probe函数。

 

4.2 注册与注销函数

static int sunxi_mmc_probe(struct platform_device *pdev) {.....
}static int sunxi_mmc_remove(struct platform_device *pdev) {......
}

比较重要的两个函数,我们一般insmod xxx.ko后,执行完_init函数后,最终如果设备树和驱动匹配成功,会调用probe函数,相同,卸载驱动时,也会调用到remove函数。

4.2.1 probe函数

probe函数很长,我们挑重点来了解

static int sunxi_mmc_probe(struct platform_device *pdev)
{struct sunxi_mmc_host *host;struct mmc_host *mmc;int ret;mmc = mmc_alloc_host(sizeof(struct sunxi_mmc_host), &pdev->dev);if (!mmc) {dev_err(&pdev->dev, "mmc alloc host failed\n");return -ENOMEM;}platform_set_drvdata(pdev, mmc);host = mmc_priv(mmc);host->dev = &pdev->dev;host->mmc = mmc;spin_lock_init(&host->lock);// 1. 获取设备树资源ret = sunxi_mmc_resource_request(host, pdev);if (ret)goto error_free_host;......// 2. 初始化MMC控制器mmc->ops		= &sunxi_mmc_ops;mmc->max_blk_count	= 8192;mmc->max_blk_size	= 4096;mmc->max_segs		= PAGE_SIZE / sizeof(struct sunxi_idma_des);mmc->max_seg_size	= (1 << host->cfg->idma_des_size_bits);mmc->max_req_size	= mmc->max_seg_size * mmc->max_segs;/* 400kHz ~ 52MHz */mmc->f_min		=   400000;mmc->f_max		= 52000000;mmc->caps	       |= MMC_CAP_MMC_HIGHSPEED | MMC_CAP_SD_HIGHSPEED |MMC_CAP_ERASE | MMC_CAP_SDIO_IRQ;if (host->cfg->clk_delays || host->use_new_timings)mmc->caps      |= MMC_CAP_1_8V_DDR | MMC_CAP_3_3V_DDR;ret = mmc_of_parse(mmc);if (ret)goto error_free_dma;/* TODO: This driver doesn't support HS400 mode yet */mmc->caps2 &= ~MMC_CAP2_HS400;ret = sunxi_mmc_init_host(host);if (ret)goto error_free_dma;.......// 3. 将mmc控制器加入到子系统中ret = mmc_add_host(mmc);if (ret)goto error_free_dma;dev_info(&pdev->dev, "initialized, max. request size: %u KB%s\n",mmc->max_req_size >> 10,host->use_new_timings ? ", uses new timings mode" : "");return 0;error_free_dma:dma_free_coherent(&pdev->dev, PAGE_SIZE, host->sg_cpu, host->sg_dma);
error_free_host:mmc_free_host(mmc);return ret;
}

函数作用:从设备树获取配置信息,并初始化mmc控制器,最后将mmc加入到子系统中。

上面代码已经作了简单注释

4.2.2 remove函数

remove函数看起来就比较简单了,就是probe函数的反操作

static int sunxi_mmc_remove(struct platform_device *pdev)
{struct mmc_host	*mmc = platform_get_drvdata(pdev);struct sunxi_mmc_host *host = mmc_priv(mmc);// 1. 移除子系统mmc_remove_host(mmc);pm_runtime_force_suspend(&pdev->dev);disable_irq(host->irq);sunxi_mmc_disable(host);dma_free_coherent(&pdev->dev, PAGE_SIZE, host->sg_cpu, host->sg_dma);// 2. 释放mmc内存mmc_free_host(mmc);return 0;
}

函数作用:将mmc移除子系统,并释放内存。

 

更多干货可见:高级工程师聚集地,助力大家更上一层楼!

 

4.3 ops函数实现

了解过基本驱动框架的都知道,最为核心的就是ops相关的接口了,上层调用底层代码,全靠它。

probe函数中,我们看到mmc->ops = &sunxi_mmc_ops的代码,就是注册了ops结构体,最后通过mmc_add_host接口,打通核心层与MMC控制器驱动层的界限。

static const struct mmc_host_ops sunxi_mmc_ops = {.request	 = sunxi_mmc_request,.set_ios	 = sunxi_mmc_set_ios,.get_ro		 = mmc_gpio_get_ro,.get_cd		 = mmc_gpio_get_cd,.enable_sdio_irq = sunxi_mmc_enable_sdio_irq,.start_signal_voltage_switch = sunxi_mmc_volt_switch,.hw_reset	 = sunxi_mmc_hw_reset,.card_busy	 = sunxi_mmc_card_busy,
};
  • .request:上层发送命令请求
  • .set_ios:上层设置时钟频率,总线数量的接口
  • .get_ro:表示卡的读写状态
  • .get_cd:检测卡是否存在的接口
  • .enable_sdio_irq:提供给上层打开sdio中断的接口
  • .hw_reset:硬件重置接口
  • .card_busy:反映卡的状态接口

具体怎么实现,就是chip manufacturer做的事情,我们这里只需要知道,上层通过封装的接口,最终通过ops->xxx函数来将控制寄存器进行数据传输。

4.4 PM接口

PM就是我们说的Power Manager电源管理,用于功耗控制。

#ifdef CONFIG_PM
static int sunxi_mmc_runtime_resume(struct device *dev)
{struct mmc_host	*mmc = dev_get_drvdata(dev);struct sunxi_mmc_host *host = mmc_priv(mmc);int ret;ret = sunxi_mmc_enable(host);if (ret)return ret;sunxi_mmc_init_host(host);sunxi_mmc_set_bus_width(host, mmc->ios.bus_width);sunxi_mmc_set_clk(host, &mmc->ios);enable_irq(host->irq);return 0;
}static int sunxi_mmc_runtime_suspend(struct device *dev)
{struct mmc_host	*mmc = dev_get_drvdata(dev);struct sunxi_mmc_host *host = mmc_priv(mmc);/** When clocks are off, it's possible receiving* fake interrupts, which will stall the system.* Disabling the irq  will prevent this.*/disable_irq(host->irq);sunxi_mmc_reset_host(host);sunxi_mmc_disable(host);return 0;
}
#endif

其主要功能就是:确保休眠时,所有外设的时钟使能需要关闭,来确保功耗最低。

 

MMC控制器驱动就是就是这么简单,不需要过多了解的,咱们就先不关心,聚焦于整个框架。

img
欢迎关注 公号&星球【嵌入式艺术】,董哥原创!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.hqwc.cn/news/339104.html

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

[openGL]在ubuntu20.06上搭建openGL环境

就在刚刚, 我跑上了一个6小时后出结果的测试程序. 离下班还有很久, 于是我打开了接单群 , 发现了很多可以写的openGL项目. 但是!!我的电脑现在是ubuntu呀, 但是不要慌!!!接下来我一步一步教你如何完美搭建一个ubuntu上的openGL环境. 保证一个坑也不会踩! 文章目录 创建项目工作…

win7添加access的odbc数据源

从控制面板打开odbc数据源&#xff1b;如果像下面没有access的驱动程序&#xff0c; 根据资料&#xff0c;打开C盘-Windows-SysWow64-odbcad32.exe&#xff0c;看一下就有了&#xff1b; 然后添加用户DSN&#xff0c;选中access的驱动程序&#xff0c; 自己输入一个数据源名&am…

linux搭建zabbix

1、访问官网地址&#xff0c;选择对应的版本等 在下方会有命令列出来&#xff0c;按照实际情况运行命令 a. Install Zabbix repository # wget https://repo.zabbix.com/zabbix/6.4/debian/pool/main/z/zabbix-release/zabbix-release_6.4-1debian12_all.deb # dpkg -i zabb…

从0到1实现html文件转换为markdown文档(进度0.1)

Spider-Man 前言准备环境1、node.js2、git 执行指令顺序报错及其解决方案一、npm 错误&#xff01;可以在以下位置找到此运行的完整日志解决方案 二、没有修改权限解决方案&#xff1a; 注意事项总结 前言 当我们处理文档时&#xff0c;常常会遇到将HTML文档转换为Markdown文档…

e2studio开发LPS28DFW气压计(1)----轮询获取气压计数据

e2studio开发LPS28DFW气压计.1--轮询获取气压计数据 概述视频教学样品申请完整代码下载产品特性通信模式速率新建工程工程模板保存工程路径芯片配置工程模板选择时钟设置UART配置UART属性配置设置e2studio堆栈e2studio的重定向printf设置R_SCI_UART_Open()函数原型回调函数user…

项目经理快速晋升应当具备的四个能力

项目的成功与失败都直接压在项目经理的肩上。不论问题的根源在何处&#xff0c;最终承担责任的总是项目经理。身为项目经理&#xff0c;你务必清楚&#xff0c;自己背负的是何等的重任。 1、计划能力 计划是行动的灯塔&#xff0c;若管理者无法制定计划&#xff0c;又如何引…

怎么加密VMware虚拟机?

加密 VMware VM 的先决条件 在创建加密虚拟机之前&#xff0c;以下几点值得注意。 1. 确保需要加密的虚拟机已关闭。 2. 创建虚拟机加密存储策略。 3. 与KMS 建立可信连接并选择默认KMS。 4. 验证您是否拥有所需的权限&#xff1a; 密码操作。加密新的。如果主机加密模式…

多机TCP通讯之hello world(C++)

文章目录 TCP是什么准备工作CMakeLists.txt服务端代码客户端代码参考 TCP是什么 TCP&#xff08;传输控制协议&#xff09;是一种在计算机网络中广泛使用的协议&#xff0c;它提供了可靠的、面向连接的数据传输服务。TCP 是 OSI 模型中的传输层协议&#xff0c;它确保了数据的…

CMake入门教程【高级篇】qmake转cmake

&#x1f608;「CSDN主页」&#xff1a;传送门 &#x1f608;「Bilibil首页」&#xff1a;传送门 &#x1f608;「动动你的小手」&#xff1a;点赞&#x1f44d;收藏⭐️评论&#x1f4dd; 文章目录 1. 概述2.qmake与cmake的差异3. qmake示例4.qmake转cmake示例5.MOC、UIC和RCC…

03-JVM虚拟机-课堂笔记

3-JVM虚拟机 灵魂三问&#xff1a; JVM是什么&#xff1f; JVM广义上指的是一种规范。狭义上的是JDK中的JVM虚拟机。 为什么要学习JVM&#xff1f; 面试过程中&#xff0c;经常会被问到JVM。 研发过程中&#xff0c;肯定会面临一些重难点问题与JVM有关系。例如&#xff1a…

WEB之HTML练习

第一题&#xff1a;用户注册界面 HTML代码&#xff1a; <!DOCTYPE html> <html lang"en"> <head><meta charset"UTF-8"><meta name"viewport" content"widthdevice-width, initial-scale1.0"><titl…

学习笔记之——3D Gaussian Splatting源码解读

之前博客对3DGS进行了学习与调研 学习笔记之——3D Gaussian Splatting及其在SLAM与自动驾驶上的应用调研-CSDN博客文章浏览阅读450次。论文主页3D Gaussian Splatting是最近NeRF方面的突破性工作&#xff0c;它的特点在于重建质量高的情况下还能接入传统光栅化&#xff0c;优…