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;}

MLPerf AI性能测试:榜单的份量究竟有多重?
无线局域网络简介(WLAN)
变频电机较于其他普通电机有何优势
弘瑞3D打印机系列,Z300Plus通用专业型上市
苹果OLED iPad Pro首批订单量减少30%
I2C控制器驱动介绍
VR应用在安全帽测量仪中 VR安全教育体验馆
保护走线
什么是RS485接口?
计算机视觉的概念和主要任务
双离合变速箱的种类以及优缺点
[组图]适合任何火腿试制的SLIM JIM天线
人脸识别体温检测有什么特性,它的优势是什么
华为Mate X被炒出高价 出现一机难求的情况
GSMA宣布下次MWC会议将于2021年6月28日至7月1日举行
钕铁硼磁铁会生锈吗?
科大讯飞AI智能键盘D1:语音打字AI智能PPT、AI写作提高办公效率
什么是网状Wi-Fi系统?它如何帮助实现更佳的居室覆盖?
注塑机防止电磁干扰的解决方案
浪潮和Nutanix合作推出浪潮inMerge1000超融合一体机