控制器驱动
I2C 总线驱动重点是 I2C 适配器驱动,这里要用到两个重要的数据结构:i2c_adapter 和 i2c_algorithm。其中,Linux 内核将 SOC 的 I2C 适配器(控制器)抽象成 i2c_adapter。
对于一个 I2C 适配器,肯定要对外提供读写 API 函数,设备驱动程序可以使用这些 API 函数来完成读写操作。i2c_algorithm 就是 I2C 适配器与 I2C 设备进行通信的方法。
I2C 总线驱动,或者说 I2C 适配器驱动的主要工作就是初始化 i2c_adapter 结构体变量,然后设置 i2c_algorithm 中的 master_xfer 函数。完成以后通过 i2c_add_numbered_adapter 或 i2c_add_adapter 这两个函数向系统注册设置好的 i2c_adapter。
I2C 控制器驱动加载
设备树 mt6885.dts
驱动
驱动和设备树匹配以后,probe 函数开始执行,重要的地方博主都进行了注释,不重要的部分进行了删除。
static int mt_i2c_probe(struct platform_device *pdev)
{
int ret = 0;
struct mt_i2c *i2c; //控制器结构体
unsigned int clk_src_in_hz;
struct resource *res;
const struct of_device_id *of_id;
//申请内存
i2c = devm_kzalloc(&pdev- >dev, sizeof(struct mt_i2c), GFP_KERNEL);
//获取设备树节点
ret = mt_i2c_parse_dt(pdev- >dev.of_node, i2c);
//从设备树获取 I2C 控制器寄存器物理基地址
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
//进行内存映射,得到 Linux 内核使用的虚拟地址
i2c- >base = devm_ioremap_resource(&pdev- >dev, res);
.....
//获取中断号
i2c- >irqnr = platform_get_irq(pdev, 0);
init_waitqueue_head(&i2c- >wait);
//请求中断,中断服务函数为 mt_i2c_irq
ret = devm_request_irq(&pdev- >dev, i2c- >irqnr, mt_i2c_irq,
IRQF_NO_SUSPEND | IRQF_TRIGGER_NONE, I2C_DRV_NAME, i2c);
of_id = of_match_node(mtk_i2c_of_match, pdev- >dev.of_node);
//填充 adapter 结构体各个参数
i2c- >dev_comp = of_id- >data;
i2c- >i2c_pll_info = &i2c_pll_info;
i2c- >adap.dev.of_node = pdev- >dev.of_node;
i2c- >dev = &i2c- >adap.dev;
i2c- >adap.dev.parent = &pdev- >dev;
i2c- >adap.owner = THIS_MODULE;
i2c- >adap.algo = &mt_i2c_algorithm;
i2c- >adap.algo_data = NULL;
i2c- >adap.timeout = 2 * HZ;
i2c- >adap.retries = 1;
i2c- >adap.nr = i2c- >id;
spin_lock_init(&i2c- >cg_lock);
......
mutex_init(&i2c- >i2c_mutex);
ret = i2c_set_speed(i2c, clk_src_in_hz);
ret = mt_i2c_clock_enable(i2c);
mt_i2c_init_hw(i2c);
mt_i2c_clock_disable(i2c);
// DMA 相关
if (i2c- >ch_offset_default)
i2c- >dma_buf.vaddr = dma_alloc_coherent(&pdev- >dev,
(PAGE_SIZE * 2), &i2c- >dma_buf.paddr, GFP_KERNEL);
else
i2c- >dma_buf.vaddr = dma_alloc_coherent(&pdev- >dev,
PAGE_SIZE, &i2c- >dma_buf.paddr, GFP_KERNEL);
if (i2c- >dma_buf.vaddr == NULL) {
dev_info(&pdev- >dev, "dma_alloc_coherent failn");
return -ENOMEM;
}
i2c_set_adapdata(&i2c- >adap, i2c);
//向 Linux 内核注册 i2c_adapter
ret = i2c_add_numbered_adapter(&i2c- >adap);
platform_set_drvdata(pdev, i2c);
return 0;
}
声明:本文内容及配图由入驻作者撰写或者入驻合作网站授权转载。文章观点仅代表作者本人,不代表电子发烧友网立场。文章及其配图仅供工程师学习之用,如有内容侵权或者其他违规问题,请联系本站处理。
举报投诉
-
控制器
+关注
关注
112文章
15223浏览量
171192 -
驱动
+关注
关注
11文章
1717浏览量
84345 -
I2C
+关注
关注
28文章
1346浏览量
120823
发布评论请先 登录
相关推荐
请问dm385 使用i2c 3访问控制器超时,需要改驱动哪些东西?
大家好:我使用dm385 i2c 1访问tvp7002能正常访问,但是使用i2c 3访问寄存器,出现控制器超时。我是在a8这侧访问的。请问驱动
发表于 07-25 09:54
不使用处理器的I2C控制器
嗨,我需要一个I2C内核来控制串行eeprom。在Web上的大多数I2C示例中,使用了微处理器。但我想只使用FPGA。我怎样才能做到这一点?有没有人有
发表于 03-13 13:08
【工程源码】基于FPGA的cmos_init OV5640摄像头I2C接口控制器
配套有简单的应用说明文档。大家可以根据应用说明文档介绍的方法将该控制器加入到自己的设计中并使用。特别声明,整个代码包括I2C控制器由小梅哥团队开发,可供广大网友学习使用。
发表于 02-14 17:29
能使用内置的I2C控制器或使用软件吗
刚开始的时候,我有一个带有I2C接口的PIC12F1820。读取外部串行EEPROM的最好方法是什么?1)我应该使用内置的I2C控制器或使用软件吗?2)有标准的
发表于 05-14 08:14
I2C总线简单介绍
1.I2C简单介绍I2C(Inter-Integrated Circuit)总线是一种由PHILIPS公司开发的两线式串行总线,用于连接微控制器及其外围设备。
发表于 01-14 07:10
I2c协议和时序的相关资料推荐
从设备adapter i2c 控制器对象数据包对象读写数据设备树中添加MPU6050信息内核选配添加设备树节点编写驱动程序 mpu6050_i2c_drv.cI2c协议和时序
发表于 02-10 06:51
linux移植MPU6050的I2C驱动过程分享
有MPU6050的例程,测试后很好用,如下图(梦幻联动一下:树莓派PICO+freeRTOS)因为pico上有现成的能用的例程,所以改一改之后直接移植到linux上首先介绍一下linux下的I2C框架①、I2C 总线
发表于 02-10 06:48
评论