全球最实用的IT互联网信息网站!

AI人工智能P2P分享&下载搜索网页发布信息网站地图

当前位置:诺佳网 > 电子/半导体 > 接口/总线/驱动 >

I2C控制器驱动介绍

时间:2023-07-22 15:38

人气:

作者:admin

标签: 驱动  控制器 

导读:控制器驱动 I2C 总线驱动重点是 I2C 适配器驱动,这里要用到两个重要的数据结构:i2c_adapter 和 i2c_algorithm。其中,Linux 内核将 SOC 的 I2C 适配器(控制器)抽象成 i2c_adapter。 对于一个 I2C 适...

控制器驱动

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;
}
温馨提示:以上内容整理于网络,仅供参考,如果对您有帮助,留下您的阅读感言吧!
相关阅读
本类排行
相关标签
本类推荐

CPU | 内存 | 硬盘 | 显卡 | 显示器 | 主板 | 电源 | 键鼠 | 网站地图

Copyright © 2025-2035 诺佳网 版权所有 备案号:赣ICP备2025066733号
本站资料均来源互联网收集整理,作品版权归作者所有,如果侵犯了您的版权,请跟我们联系。

关注微信