当前位置: 首页 > news >正文

I2C驱动(十二) -- 主控芯片的i2c_adapter驱动分析

相关文章

I2C驱动(一) – I2C协议
I2C驱动(二) – SMBus协议
I2C驱动(三) – 驱动中的几个重要结构
I2C驱动(四) – I2C-Tools介绍
I2C驱动(五) – 通用驱动i2c-dev.c分析
I2C驱动(六) – I2C驱动程序模型
I2C驱动(七) – 编写I2C设备驱动之i2c_driver
I2C驱动(八) – 编写I2C设备驱动之i2c_client
I2C驱动(九) – i2c_adapter控制器驱动框架编写
I2C驱动(十) – i2c_adapter控制器驱动完善与上机实验
I2C驱动(十一) – gpio模拟的i2c总线驱动i2c-gpio.c分析
I2C驱动(十二) – 主控芯片的i2c_adapter驱动分析

文章目录

  • 相关文章
  • 参考资料
  • 一、I2C-GPIO的缺点
  • 二、I2C控制器内部结构
    • 2.1 通用简化结构
    • 2.2 IMX6ULL的I2C控制器内部结构
  • 三、I2C控制器操作方法
  • 四、代码分析
    • 4.1 程序模型
    • 4.2 设备树
    • 4.3 驱动程序分析
  • 五、总结


参考资料

  • Linux内核真正的I2C控制器驱动程序
    • IMX6ULL: Linux-4.9.88\drivers\i2c\busses\i2c-imx.c
  • 芯片手册
    • IMXX6ULL:IMX6ULLRM.pdf
      • Chapter 31: I2C Controller (I2C)

一、I2C-GPIO的缺点

I2C驱动(十一) – gpio模拟的i2c总线驱动i2c-gpio.c分析中介绍了gpio模拟的i2c总线驱动程序。假设它是100kHz的频率,则传输一位数据的时间是10微秒,那么传输一个字节数据再加上回应信号、起始和终止信号,总时间就大于90微秒,这90微秒内CPU就完全被占住。如果传输数据量很大的话,效率就很低。

二、I2C控制器内部结构

2.1 通用简化结构

i2c控制器内部通常会包含有以下寄存器:

  • control_register:设置控制参数,例如频率等信息;
  • clock_module:时钟模块,提供时钟;
  • status_register:状态寄存器;
  • int_register:中断寄存器;
  • shift_register:移位寄存器;
  • tx_register:发送寄存器;
  • rx_register:接收寄存器;
    在这里插入图片描述
    假设要发送一个字节数据,只要把数据放入发送寄存器,i2c控制器就会自动通过移位寄存器一位一位的往外传输,这期间就可以休眠,不会占用CPU,当传输结束后,会发出一个中断信号,告诉CPU数据传输完成。
    如果是接收一个字节数据,外面的数据会经过移位寄存器一位一位的存放到接收寄存器,完成后会发出一个中断信号,这时候就可以去读接收寄存器中的数据。

2.2 IMX6ULL的I2C控制器内部结构

从结构图可以看出,它里面包含了:

  1. 频率寄存器
  2. 控制寄存器
  3. 状态寄存器
  4. 数据寄存器:发送和接收都经过这个寄存器
  5. 地址寄存器:如果作为从设备,可以给它设置一个地址
  6. 移位寄存器

![在这里插入图片描述](https://i-blog.csdnimg.cn/direct/16eb33333e364b85aefc89f4ca0147b2.png

三、I2C控制器操作方法

I2C控制器的操作步骤如下:

  • 使能时钟,设置时钟
  • 发送数据:
    • 把数据写入tx_register,等待中断发生
    • 中断发生后,判断状态:是否发生错误、是否得到回应信号(ACK)
    • 把下一个数据写入tx_register,等待中断:如此循环
  • 接收数据:
    • 设置controller_register,进入接收模式,启动接收,等待中断发生
    • 中断发生后,判断状态,读取rx_register得到数据
    • 如此循环

四、代码分析

4.1 程序模型

万能驱动模型:平台总线-设备-驱动模型。platform_device使用设备树来定义。platform_driverplatform_device匹配成功后调用probe函数,在probe函数中分配,设置,注册i2c_adapter结构体。
在这里插入图片描述

4.2 设备树

  • #address-cells #size-cells :用来指定它下面挂接的设备的地址表示方式;
  • compatible:和驱动程序进行比较;
  • reg:控制器的寄存器地址和大小;
  • interrupts:指定中断
  • clock:时钟
  • status:节点状态
i2c1: i2c@021a0000 {#address-cells = <1>;#size-cells = <0>;compatible = "fsl,imx6ul-i2c", "fsl,imx21-i2c";reg = <0x021a0000 0x4000>;interrupts = <GIC_SPI 36 IRQ_TYPE_LEVEL_HIGH>;clocks = <&clks IMX6UL_CLK_I2C1>;status = "disabled";   // 在包含它的文件中改为"okay"
};

4.3 驱动程序分析

先看入口函数:它里面注册了一个platform_driver结构体

static int __init i2c_adap_imx_init(void)
{/* 注册一个platform_driver */return platform_driver_register(&i2c_imx_driver);
}

platform_driver结构体中包含了of_match_table probe 函数,和设备树匹配成功后probe 函数就会被调用。

static struct platform_driver i2c_imx_driver = {.probe = i2c_imx_probe,.remove = i2c_imx_remove,.driver = {.name = DRIVER_NAME,.pm = I2C_IMX_PM_OPS,.of_match_table = i2c_imx_dt_ids,},.id_table = imx_i2c_devtype,
};

probe函数,里面做了一些设备树的解析和硬件设置,核心是i2c_adapter中的algo成员的设置。

static int i2c_imx_probe(struct platform_device *pdev)
{
...i2c_imx->adapter.algo		= &i2c_imx_algo; //核心
...
}

i2c_imx_algo中的 master_xfer成员实现了寄存器的操作。

static struct i2c_algorithm i2c_imx_algo = {.master_xfer	= i2c_imx_xfer,.functionality	= i2c_imx_func,
};

i2c_imx_xfer核心函数,需要结合芯片手册去分析。

static int i2c_imx_xfer(struct i2c_adapter *adapter,struct i2c_msg *msgs, int num)
{unsigned int i, temp;int result;bool is_lastmsg = false;bool enable_runtime_pm = false;struct imx_i2c_struct *i2c_imx = i2c_get_adapdata(adapter);dev_dbg(&i2c_imx->adapter.dev, "<%s>\n", __func__);if (!pm_runtime_enabled(i2c_imx->adapter.dev.parent)) {pm_runtime_enable(i2c_imx->adapter.dev.parent);enable_runtime_pm = true;}result = pm_runtime_get_sync(i2c_imx->adapter.dev.parent);if (result < 0)goto out;/* Start I2C transfer */result = i2c_imx_start(i2c_imx);if (result) {if (i2c_imx->adapter.bus_recovery_info) {i2c_recover_bus(&i2c_imx->adapter);result = i2c_imx_start(i2c_imx);}}if (result)goto fail0;/* read/write data */for (i = 0; i < num; i++) {if (i == num - 1)is_lastmsg = true;if (i) {dev_dbg(&i2c_imx->adapter.dev,"<%s> repeated start\n", __func__);temp = imx_i2c_read_reg(i2c_imx, IMX_I2C_I2CR);temp |= I2CR_RSTA;imx_i2c_write_reg(temp, i2c_imx, IMX_I2C_I2CR);result = i2c_imx_bus_busy(i2c_imx, 1);if (result)goto fail0;}dev_dbg(&i2c_imx->adapter.dev,"<%s> transfer message: %d\n", __func__, i);/* write/read data */
#ifdef CONFIG_I2C_DEBUG_BUStemp = imx_i2c_read_reg(i2c_imx, IMX_I2C_I2CR);dev_dbg(&i2c_imx->adapter.dev,"<%s> CONTROL: IEN=%d, IIEN=%d, MSTA=%d, MTX=%d, TXAK=%d, RSTA=%d\n",__func__,(temp & I2CR_IEN ? 1 : 0), (temp & I2CR_IIEN ? 1 : 0),(temp & I2CR_MSTA ? 1 : 0), (temp & I2CR_MTX ? 1 : 0),(temp & I2CR_TXAK ? 1 : 0), (temp & I2CR_RSTA ? 1 : 0));temp = imx_i2c_read_reg(i2c_imx, IMX_I2C_I2SR);dev_dbg(&i2c_imx->adapter.dev,"<%s> STATUS: ICF=%d, IAAS=%d, IBB=%d, IAL=%d, SRW=%d, IIF=%d, RXAK=%d\n",__func__,(temp & I2SR_ICF ? 1 : 0), (temp & I2SR_IAAS ? 1 : 0),(temp & I2SR_IBB ? 1 : 0), (temp & I2SR_IAL ? 1 : 0),(temp & I2SR_SRW ? 1 : 0), (temp & I2SR_IIF ? 1 : 0),(temp & I2SR_RXAK ? 1 : 0));
#endifif (msgs[i].flags & I2C_M_RD)result = i2c_imx_read(i2c_imx, &msgs[i], is_lastmsg);else {if (i2c_imx->dma && msgs[i].len >= DMA_THRESHOLD)result = i2c_imx_dma_write(i2c_imx, &msgs[i]);elseresult = i2c_imx_write(i2c_imx, &msgs[i]);}if (result)goto fail0;}fail0:/* Stop I2C transfer */i2c_imx_stop(i2c_imx);pm_runtime_mark_last_busy(i2c_imx->adapter.dev.parent);pm_runtime_put_autosuspend(i2c_imx->adapter.dev.parent);out:if (enable_runtime_pm)pm_runtime_disable(i2c_imx->adapter.dev.parent);dev_dbg(&i2c_imx->adapter.dev, "<%s> exit with: %s: %d\n", __func__,(result < 0) ? "error" : "success msg",(result < 0) ? result : num);return (result < 0) ? result : num;
}

五、总结

本文介绍了实际主控芯片的i2c_adapter驱动程序。


http://www.mrgr.cn/news/92991.html

相关文章:

  • 深度学习架构Seq2Seq-添加并理解注意力机制(一)
  • 【AI深度学习基础】Pandas完全指南入门篇:数据处理的瑞士军刀 (含完整代码)
  • MAC 本地搭建部署 dify(含 github访问超时+Docker镜像源拉取超时解决方案)
  • 洛谷 P11830 省选联考2025 幸运数字 题解
  • mapbox基础,使用点类型geojson加载symbol符号图层,用于标注文字
  • 回归算法模型总结
  • Bilibili 视频弹幕自动获取和自定义屏蔽词
  • 【牛客】第 k 小
  • vue3之echarts仪表盘
  • RPA 职业前景:个人职场发展的 “新机遇”
  • 动态SQL
  • 【经验分享】Ubuntu vmware虚拟机存储空间越来越小问题(已解决)
  • Unity 打包后EXE运行出现Field to Load il2cpp的一种情况
  • [KEIL]单片机技巧 01
  • 2025-03-03 学习记录--C/C++-PTA 7-38 数列求和-加强版
  • 【监督学习】支持向量机步骤及matlab实现
  • Excel的行高、列宽单位不统一?还是LaTeX靠谱
  • 从DNS到TCP:DNS解析流程和浏览器输入域名访问流程
  • Vue盲区扫雷
  • 大语言模型学习