0
  • 聊天消息
  • 系统消息
  • 评论与回复
登录后你可以
  • 下载海量资料
  • 学习在线课程
  • 观看威廉希尔官方网站 视频
  • 写文章/发帖/加入社区
会员中心
创作中心

完善资料让更多小伙伴认识你,还能领取20积分哦,立即完善>

3天内不再提示

如何实例化i2c设备?实例化i2c设备的4种方式

冬至子 来源:嵌入式ABC 作者:小鱼 2023-10-17 11:18 次阅读

如何实例化i2c设备?4种方式如下:

  • 方法1:静态声明I2C设备
    • 通过devicetree声明I2C设备
    • 在板级文件中声明I2C设备
  • 方法2:显式实例化设备
  • 方法3:对某些设备的I2C总线进行探测
  • 方法4:从用户空间实例化

在本篇中,主要看一下方法1,3和方法4。对于方法2,在下一篇的一个I2C ADC/DAC的misc设备驱动实例中再加以详述。

通过devicetree声明I2C设备

/dts-v1/;
/plugin/;
/ {
       compatible = "brcm,bcm2835", "brcm,bcm2708", "brcm,bcm2709";




       fragment@0 {
          target = < &i2c1 >;
          __overlay__ {
                #address-cells = < 1 >;
                #size-cells = < 0 >;
                rtc@68 {
                        compatible = "maxim,ds3231";
                        reg = < 0x68 >;
                        #address-cells = < 2 >;
                        #size-cells = < 1 >;
                };      
          };
       };
    };

首先,写一个dts。

编译,并将生成的.dtbo到/boot/overlays

重启后,查看/dev可以看到rtc

通过板级文件中声明I2C设备

在架构板级文件中添加i2c设备信息,并注册到特定位置。看一个nxp imx开发板的电源芯片的实例,arch/arm/mach-imx/mach-mx35_3ds.c

static struct mc13xxx_platform_data mx35_3ds_mc13892_data = {
    .flags = MC13XXX_USE_RTC | MC13XXX_USE_TOUCHSCREEN,
    .regulators = {
        .num_regulators = ARRAY_SIZE(mx35_3ds_regulators),
        .regulators = mx35_3ds_regulators,
    },
};




#define GPIO_PMIC_INT IMX_GPIO_NR(2, 0)




static struct i2c_board_info mx35_3ds_i2c_mc13892 = {




    I2C_BOARD_INFO("mc13892", 0x08),
    .platform_data = &mx35_3ds_mc13892_data,
    /* irq number is run-time assigned */
};




static void __init imx35_3ds_init_mc13892(void)
{
    int ret = gpio_request_one(GPIO_PMIC_INT, GPIOF_DIR_IN, "pmic irq");




    if (ret) {
        pr_err("failed to get pmic irq: %dn", ret);
        return;
    }




    mx35_3ds_i2c_mc13892.irq = gpio_to_irq(GPIO_PMIC_INT);
    i2c_register_board_info(0, &mx35_3ds_i2c_mc13892, 1);
}

MC13892是面向i.MX51、i.MX37、i.MX3和i.MX27应用处理器的PMIC。在板级文件中定义了一个 i2c_board_info 结构体,使用i2c_register_board_info函数将i2c设备信息添加到特定链表。

i2c_register_board_info在/drivers/i2c/i2c-boardinfo.c中:

/**
* i2c_register_board_info - statically declare I2C devices
* @busnum: identifies the bus to which these devices belong
* @info: vector of i2c device descriptors
* @len: how many descriptors in the vector; may be zero to reserve
*    the specified bus number.
*
* Systems using the Linux I2C driver stack can declare tables of board info
* while they initialize.  This should be done in board-specific init code
* near arch_initcall() time, or equivalent, before any I2C adapter driver is
* registered.  For example, mainboard init code could define several devices,
* as could the init code for each daughtercard in a board stack.
*
* The I2C devices will be created later, after the adapter for the relevant
* bus has been registered.  After that moment, standard driver model tools
* are used to bind "new style" I2C drivers to the devices.  The bus number
* for any device declared using this routine is not available for dynamic
* allocation.
*
* The board info passed can safely be __initdata, but be careful of embedded
* pointers (for platform_data, functions, etc) since that won't be copied.
* Device properties are deep-copied though.
*/
int i2c_register_board_info(int busnum, struct i2c_board_info const *info, unsigned len)

对某些设备的I2C总线进行探测

有时没有关于I2C设备的足够信息,甚至无法调用i2c_new_scanned_device()。典型的例子是PC主板上的硬件监控芯片。有几十个模型,可能被分配在25个不同的地址。考虑到主板的庞大数量,几乎不可能建立一个正在使用的硬件监控芯片的详尽列表。幸运的是,大多数这些芯片都有制造商和设备ID寄存器,因此可以通过探测来识别它们。

在这种情况下,I2C设备既没有显式声明也没有实例化。相反,一旦这些设备的驱动程序被加载,I2C -core就会探测它们,如果找到了,就会自动实例化一个I2C设备。为了防止此机制的任何不当行为,适用以下限制:

  • I2C设备驱动程序必须实现detect()方法,该方法通过从任意寄存器读取来识别受支持的设备。
  • 只有那些可能有支持设备并同意被探测的总线才会被探测。例如,这避免了探测电视适配器上的硬件监控芯片。

detect何时调用?

i2c_driver注册的时候,i2c_core会在所有已经注册的i2c_adapter上探测address_list中的所有地址,硬件探测成功之后后调用i2c_driver的detect成员,然后根据detect填充的info建立一个i2c_client。

例如,MAX1668温度传感器的驱动实现,/drivers/hwmon/max1668.c

static struct i2c_driver max1668_driver = {
    .class = I2C_CLASS_HWMON,
    .driver = {
          .name    = "max1668",
          },
    .probe = max1668_probe,
    .id_table = max1668_id,
    .detect    = max1668_detect,
    .address_list = max1668_addr_list,
};




module_i2c_driver(max1668_driver);

其中,detect函数

/* Return 0 if detection is successful, -ENODEV otherwise */
static int max1668_detect(struct i2c_client *client,
              struct i2c_board_info *info)
{
    struct i2c_adapter *adapter = client- >adapter;
    const char *type_name;
    int man_id, dev_id;




    if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA))
        return -ENODEV;




    /* Check for unsupported part */
    man_id = i2c_smbus_read_byte_data(client, MAX1668_REG_MAN_ID);
    if (man_id != MAN_ID_MAXIM)
        return -ENODEV;




    dev_id = i2c_smbus_read_byte_data(client, MAX1668_REG_DEV_ID);
    if (dev_id < 0)
        return -ENODEV;




    type_name = NULL;
    if (dev_id == DEV_ID_MAX1668)
        type_name = "max1668";
    else if (dev_id == DEV_ID_MAX1805)
        type_name = "max1805";
    else if (dev_id == DEV_ID_MAX1989)
        type_name = "max1989";




    if (!type_name)
        return -ENODEV;




    strlcpy(info- >type, type_name, I2C_NAME_SIZE);




    return 0;
}

树莓派为例,i2c_add_adapter会在bcm2835_i2c_probe调用

static int bcm2835_i2c_probe(struct platform_device *pdev)

在i2c_register_adapter 中会调用,bus_for_each_drv 来来通知所有总线类型是i2c_bus_type的driver。

/* Notify drivers */
    mutex_lock(&core_lock);
    bus_for_each_drv(&i2c_bus_type, NULL, adap, __process_new_adapter);
    mutex_unlock(&core_lock);
static int __process_new_adapter(struct device_driver *d, void *data)
{
    return i2c_do_add_adapter(to_i2c_driver(d), data);
}

在i2c_do_add_adapter->i2c_detect->i2c_detect_address 中有一段关键code

err = driver- >detect(temp_client, &info);
    if (err) {
        /* -ENODEV is returned if the detection fails. We catch it
           here as this isn't an error. */
        return err == -ENODEV ? 0 : err;
    }

从用户空间实例化

用户空间通过两个sysfs属性文件来建立和删除i2c_client:new_device和delete_device。

  • new_device有两个参数:i2c设备的名字(字符串)和地址(以0x开头的16进制数)。
  • delete_device只有一个参数:设备的地址。
pi@raspberrypi:/sys/class/i2c-adapter/i2c-1 $ ls
delete_device  device  i2c-dev  name  new_device  of_node  power  subsystem  uevent

添加rtc设备

pi@raspberrypi:/sys/class/i2c-adapter/i2c-1 $ echo ds3231 0x68 | sudo tee new_device 
ds3231 0x68

方法2:显式实例化设备,在下一篇"在Linux系统里如何编写一个PCF8591的驱动,完成ADC数据采集,DAC数据输出"中再详述。

PCF8591 是一个单片集成、单独供电、低功耗、8-bit CMOS数据获取器件。PCF8591 具有 4 个interwetten与威廉的赔率体系 输入、1 个模拟输出和 1个串行 I2C 总线接口。

PCF8591 的 3 个地址引脚 A0, A1 和 A2 可用于硬件地址编程,允许在同个 I2C 总线上接入 8 个 PCF8591 器件,而无需额外的硬件。在 PCF8591 器件上输入输出的地址、控制和数据信号都是通过双线双向 I2C 总线以串行的方式进行传输。

声明:本文内容及配图由入驻作者撰写或者入驻合作网站授权转载。文章观点仅代表作者本人,不代表电子发烧友网立场。文章及其配图仅供工程师学习之用,如有内容侵权或者其他违规问题,请联系本站处理。 举报投诉
  • 处理器
    +关注

    关注

    68

    文章

    19336

    浏览量

    230192
  • 驱动器
    +关注

    关注

    53

    文章

    8256

    浏览量

    146579
  • 寄存器
    +关注

    关注

    31

    文章

    5357

    浏览量

    120618
  • I2C总线
    +关注

    关注

    8

    文章

    391

    浏览量

    61021
  • 电源芯片
    +关注

    关注

    43

    文章

    1096

    浏览量

    77126
收藏 人收藏

    评论

    相关推荐

    I2C总线规范与I2C器件C51读写程序

    I2C总线规范与I2C器件C51读写程序:本文简要介绍了I2C总线,并给出了I2C器件的C51读
    发表于 08-22 17:51 93次下载

    I2C Guid I2C指南

    I2C Guid  I2C指南 The I2C bus is used in a wide rangeof applications because it is simpleand
    发表于 04-23 13:55 36次下载

    PIC单片机读写I2C实例源程序一

    PIC单片机读写I2C实例源程序一 ; this route is used I2C EESROM write and; read; addressing mode is indirectSTART BSF RB_
    发表于 01-16 11:47 2776次阅读

    i2c

    单片机i2c总线操作;单片机i2c总线操作;单片机i2c总线操作;
    发表于 05-17 11:09 35次下载

    I2C总线原理及应用实例

    I2C总线原理及应用实例
    发表于 09-22 11:41 17次下载
    <b class='flag-5'>I2C</b>总线原理及应用<b class='flag-5'>实例</b>

    树莓派怎样连接多个I2C设备

     简单。 i2c是一辆公共汽车。总线的目的是与多个设备通信。将设备并行连接到同一i2c总线。您可以使用总线一。
    的头像 发表于 11-13 09:27 1.9w次阅读
    树莓派怎样连接多个<b class='flag-5'>I2C</b><b class='flag-5'>设备</b>

    干货:I2C总线最全教程讲解

      裸机操作篇 本文以三星exynos4412为例讲解I2C时序,并挂载在I2C控制器mpu6050陀螺仪的数据读取实例。通过本篇文章,读者可以理解I2C时序,以及如何基于三星
    的头像 发表于 02-20 15:04 1.3w次阅读
    干货:<b class='flag-5'>I2C</b>总线最全教程讲解

    嵌入式内核及驱动开发-09IIC子系统框架使用(I2C协议和时序,I2C驱动框架,I2C设备驱动开发,MPU6050硬件连接

    文章目录I2c协议和时序I2c介绍I2c硬件连接I2c总线的信号I2c总线写时序I2c总线读时序
    发表于 12-06 14:06 17次下载
    嵌入式内核及驱动开发-09IIC子系统框架使用(<b class='flag-5'>I2C</b>协议和时序,<b class='flag-5'>I2C</b>驱动框架,<b class='flag-5'>I2C</b>从<b class='flag-5'>设备</b>驱动开发,MPU6050硬件连接

    硬件I2C与模拟I2C

    硬件I2C对应芯片上的I2C外设,有相应I2C驱动电路,其所使用的I2C管脚也是专用的,因而效率要远高于软件模拟的I2C;一般也较为稳定,但
    发表于 12-28 19:14 81次下载
    硬件<b class='flag-5'>I2C</b>与模拟<b class='flag-5'>I2C</b>

    Gowin I2C Master/Slave用户指南

    Gowin I2C Master 和 Slave 用户指南主要包括功能简介、信号定义、工 作原理、实例等,旨在帮助用户快速了解 Gowin I2C Master IP 和 Slav
    发表于 09-15 10:07 1次下载
    Gowin <b class='flag-5'>I2C</b> Master/Slave用户指南

    I2C子系统SW Architecture

    通过 i2c-core 将 i2c 设备驱动和 i2c 总线驱动进行了分离,从而使得 i2c 设备
    的头像 发表于 07-22 16:01 965次阅读
    <b class='flag-5'>I2C</b>子系统SW Architecture

    I2CI3C的区别有哪些

    I2CI3C 主要区别如下: I2C 虽然也是两条线,但是很多时候传感器需要一条额外的中断线,来告诉主控数据已经准备好。I3C 允许从设备
    的头像 发表于 07-22 16:20 7059次阅读
    <b class='flag-5'>I2C</b>和<b class='flag-5'>I3C</b>的区别有哪些

    如何解决I2C器件死锁的问题?

    如何解决I2C器件死锁的问题? I2C总线是一流行的串行通信协议,在许多嵌入式系统中使用。I2C可以连接多个从属设备到一个主控
    的头像 发表于 09-12 11:18 2507次阅读

    什么是串口转I2C?有什么特点?

    什么是串口转I2C?有什么特点?  串口转I2C是一设备,用于将串行通信接口(通常称为串口)转换为I2C信号。
    的头像 发表于 09-14 17:52 1327次阅读

    i2c采样是上升沿吗?

    数据。在本文中,我们将详细讨论I2C采样的工作原理,采样时机以及如何进行I2C采样。 I2C采样的原理 I2C采样是基于I2C通讯协议的,该
    的头像 发表于 09-19 17:16 2796次阅读