i.MX6ULL终结者Linux I2C驱动实验IMX6ULL的I2C总线驱动分析

本文分析了i.MX6ULL平台的Linux I2C总线驱动,包括设备树配置、驱动文件i2c-imx.c中的关键函数,如i2c_imx_probe和i2c_imx_algo。驱动初始化涉及寄存器映射、中断注册、频率设置等,并通过master_xfer函数完成与I2C设备的通信。
摘要由CSDN通过智能技术生成

在上一节中我们了解了I2C框架分为I2C核心、I2C总线驱动和I2C设备驱动三部分。其中I2C总线驱动就是SOC的I2C控制器驱动,一般来说都是SOC厂家实现好的。而I2C设备驱动是用户根据自己不同的设备具体实现的。
在imx6ull平台下,NXP官方已经实现好了I2C总线驱动,下面简单分析一下。
首先要找到设备树中关于I2C控制器的设备节点。打开imx6ull.dtsi文件,有如下内容:

1 i2c1: i2c@021a0000 {
    
2      #address-cells = <1>; 
3      #size-cells = <0>; 
4      compatible = "fsl,imx6ul-i2c", "fsl,imx21-i2c"; 
5      reg = <0x021a0000 0x4000>; 
6      interrupts = <GIC_SPI 36 IRQ_TYPE_LEVEL_HIGH>; 
7      clocks = <&clks IMX6UL_CLK_I2C1>; 
8      status = "disabled";
9 }; 

根据I2C1设备节点中的compatible属性值"fsl,imx6ul-i2c"和"fsl,imx21-i2c",我们就可以在内核中找到相应的驱动文件,在Linux内核源码中搜索这两个字符串,可以找到驱动文件为drivers/i2c/busses/i2c-imx.c,有下面部分内容:

244 static struct platform_device_id imx_i2c_devtype[] = {
    
245        {
    
246            .name = "imx1-i2c", 
247            .driver_data = (kernel_ulong_t)&imx1_i2c_hwdata, 
248        }, {
    
249            .name = "imx21-i2c", 
250            .driver_data = (kernel_ulong_t)&imx21_i2c_hwdata, 
251        }, {
    
252        /* sentinel */ 
253        } 
254 }; 
255 MODULE_DEVICE_TABLE(platform, imx_i2c_devtype); 
256 
257 static const struct of_device_id i2c_imx_dt_ids[] = {
    
258        {
    .compatible = "fsl,imx1-i2c", .data = &imx1_i2c_hwdata, }, 
259        {
    .compatible = "fsl,imx21-i2c", .data = &imx21_i2c_hwdata, }, 
260        {
    .compatible = "fsl,vf610-i2c", .data = &vf610_i2c_hwdata, }, 
261        {
    /* sentinel */ } 
262 }; 
263 MODULE_DEVICE_TABLE(of, i2c_imx_dt_ids); 
...... 
1119 static struct platform_driver i2c_imx_driver = {
    
1120       .probe = i2c_imx_probe, 
1121       .remove = i2c_imx_remove, 
1122       .driver = {
    
1123               .name = DRIVER_NAME, 
1124               .owner = THIS_MODULE, 
1125               .of_match_table = i2c_imx_dt_ids, 
1126               .pm 
  • 1
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
下面是一个简单的 MX6ULL Linux 24C02 EEPROM 驱动框架,仅供参考: ```c #include <linux/module.h> #include <linux/kernel.h> #include <linux/init.h> #include <linux/i2c.h> #include <linux/device.h> #include <linux/err.h> #define EEPROM_ADDR 0x50 #define EEPROM_PAGE_SIZE 8 /* MX6ULL 24C02 EEPROM 驱动数据结构体 */ struct mx6ull_eeprom { struct i2c_client *client; u8 *buffer; }; /* MX6ULL 24C02 EEPROM 驱动读函数 */ static int mx6ull_eeprom_read(struct i2c_client *client, u16 addr, u8 *buffer, u32 count) { struct i2c_msg msg[2]; u8 addr_buf[2]; int ret; addr_buf[0] = addr >> 8; addr_buf[1] = addr & 0xFF; msg[0].addr = client->addr; msg[0].flags = 0; msg[0].len = 2; msg[0].buf = addr_buf; msg[1].addr = client->addr; msg[1].flags = I2C_M_RD; msg[1].len = count; msg[1].buf = buffer; ret = i2c_transfer(client->adapter, msg, 2); if (ret == 2) return 0; return -EIO; } /* MX6ULL 24C02 EEPROM 驱动写函数 */ static int mx6ull_eeprom_write(struct i2c_client *client, u16 addr, const u8 *buffer, u32 count) { struct i2c_msg msg; u8 *buf; int ret, wrote = 0; buf = kmalloc(EEPROM_PAGE_SIZE + 2, GFP_KERNEL); if (!buf) return -ENOMEM; while (count > 0) { u32 chunk_size = min_t(u32, count, EEPROM_PAGE_SIZE); buf[0] = addr >> 8; buf[1] = addr & 0xFF; memcpy(&buf[2], buffer + wrote, chunk_size); msg.addr = client->addr; msg.flags = 0; msg.len = chunk_size + 2; msg.buf = buf; ret = i2c_transfer(client->adapter, &msg, 1); if (ret != 1) { kfree(buf); return -EIO; } msleep(5); addr += chunk_size; wrote += chunk_size; count -= chunk_size; } kfree(buf); return 0; } /* MX6ULL 24C02 EEPROM 驱动读取函数 */ static ssize_t mx6ull_eeprom_read_from_eeprom(struct file *file, char __user *buf, size_t count, loff_t *ppos) { struct mx6ull_eeprom *eeprom = file->private_data; int ret; if (*ppos + count > 256) return -EINVAL; mutex_lock(&eeprom->client->dev.mutex); ret = mx6ull_eeprom_read(eeprom->client, *ppos, eeprom->buffer, count); if (ret == 0) { if (copy_to_user(buf, eeprom->buffer, count)) ret = -EFAULT; else *ppos += count; } mutex_unlock(&eeprom->client->dev.mutex); return ret; } /* MX6ULL 24C02 EEPROM 驱动写入函数 */ static ssize_t mx6ull_eeprom_write_to_eeprom(struct file *file, const char __user *buf, size_t count, loff_t *ppos) { struct mx6ull_eeprom *eeprom = file->private_data; int ret; if (*ppos + count > 256) return -EINVAL; if (copy_from_user(eeprom->buffer, buf, count)) return -EFAULT; mutex_lock(&eeprom->client->dev.mutex); ret = mx6ull_eeprom_write(eeprom->client, *ppos, eeprom->buffer, count); if (ret == 0) *ppos += count; mutex_unlock(&eeprom->client->dev.mutex); return ret; } /* MX6ULL 24C02 EEPROM 驱动文件操作结构体 */ static const struct file_operations mx6ull_eeprom_fops = { .owner = THIS_MODULE, .read = mx6ull_eeprom_read_from_eeprom, .write = mx6ull_eeprom_write_to_eeprom, }; /* MX6ULL 24C02 EEPROM 驱动设备树匹配列表 */ static const struct of_device_id mx6ull_eeprom_of_match[] = { { .compatible = "fsl,imx6ull-eeprom", }, {}, }; MODULE_DEVICE_TABLE(of, mx6ull_eeprom_of_match); /* MX6ULL 24C02 EEPROM 驱动 I2C 设备 ID 列表 */ static const struct i2c_device_id mx6ull_eeprom_id[] = { { "mx6ull-eeprom", 0 }, {}, }; MODULE_DEVICE_TABLE(i2c, mx6ull_eeprom_id); /* MX6ULL 24C02 EEPROM 驱动匹配函数 */ static int mx6ull_eeprom_driver_probe(struct i2c_client *client, const struct i2c_device_id *id) { struct mx6ull_eeprom *eeprom; struct device *dev; int ret; /* 分配 MX6ULL 24C02 EEPROM 驱动数据结构体 */ eeprom = devm_kzalloc(&client->dev, sizeof(struct mx6ull_eeprom), GFP_KERNEL); if (!eeprom) return -ENOMEM; /* 初始化 MX6ULL 24C02 EEPROM 驱动数据结构体 */ eeprom->client = client; eeprom->buffer = kmalloc(EEPROM_PAGE_SIZE, GFP_KERNEL); if (!eeprom->buffer) return -ENOMEM; /* 注册 MX6ULL 24C02 EEPROM 驱动文件节点 */ dev = &client->dev; if (!devm_create_file(dev, &dev_attr_eeprom)) { dev_err(dev, "failed to create sysfs entry\n"); return -ENOMEM; } /* 注册 MX6ULL 24C02 EEPROM 驱动文件操作结构体 */ ret = alloc_chrdev_region(&eeprom->devno, 0, 1, "mx6ull-eeprom"); if (ret < 0) return ret; cdev_init(&eeprom->cdev, &mx6ull_eeprom_fops); eeprom->cdev.owner = THIS_MODULE; ret = cdev_add(&eeprom->cdev, eeprom->devno, 1); if (ret < 0) goto out_unregister_region; device_create(mx6ull_eeprom_class, NULL, eeprom->devno, NULL, "mx6ull-eeprom"); i2c_set_clientdata(client, eeprom); return 0; out_unregister_region: unregister_chrdev_region(eeprom->devno, 1); return ret; } /* MX6ULL 24C02 EEPROM 驱动移除函数 */ static int mx6ull_eeprom_driver_remove(struct i2c_client *client) { struct mx6ull_eeprom *eeprom = i2c_get_clientdata(client); device_destroy(mx6ull_eeprom_class, eeprom->devno); cdev_del(&eeprom->cdev); unregister_chrdev_region(eeprom->devno, 1); kfree(eeprom->buffer); return 0; } /* MX6ULL 24C02 EEPROM 驱动 I2C 设备结构体 */ static struct i2c_driver mx6ull_eeprom_driver = { .driver = { .name = "mx6ull-eeprom", .of_match_table = mx6ull_eeprom_of_match, }, .probe = mx6ull_eeprom_driver_probe, .remove = mx6ull_eeprom_driver_remove, .id_table = mx6ull_eeprom_id, }; module_i2c_driver(mx6ull_eeprom_driver); MODULE_LICENSE("GPL"); MODULE_AUTHOR("Your Name"); MODULE_DESCRIPTION("MX6ULL 24C02 EEPROM Driver"); ``` 当然,以上代码只是一个简单的框架,具体的实现还需要根据具体的硬件平台和 24C02 EEPROM 来进行相应的修改和实现。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值