linux I2C核心、总线与设备驱动

一、 linux I2C体系结构

linux的I2C体系结构分为3个组成部分

1)I2C核心

I2C核心提供了I2C总线驱动与设备驱动的注册、注销方法,I2C通信方法(即Algorithm)上层的与具体适配器无关的代码及其探测设备、检测设备地址的上层代码等,如图:

2)I2C总线驱动

I2C总线驱动是对I2C硬件体系结构中适配器端的实现,适配器可由CPU控制,甚至可以直接集成在CPU内部。

I2C总线驱动 主要包含I2C适配器数据结构I2C_adaper、I2C适配器的Algorithm数据结构I2C_algorithm和控制I2C适配器产生通信信号的函数。经I2C总线驱动的代码,我们可以控制I2C适配器以主控方式产生开始位、停止位、读写周期,以及以从设备方式被读写、产生ACK等。

3)I2C设备驱动

I2C设备驱动(也称客户驱动)是对I2C硬件体系结构设备端的实现,设备一般挂接在受CPU控制的I2C的适配器上,通过I2C适配器与CPU交换数据。

I2C设备驱动主要包含数据结构I2c_driver和i2c_client,我们需要根据具体设备实现其中的成员函数。

在linux kernel中,所有的i2c设备都在sysfs文件系统中显示,存于/sys/bus/i2c/目录下,以适配器地址和芯片的地址的形式列出,例如:

在linux内核源码中的drivers目录下有一个i2c目录,而在I2C目录下包含如下文件和文件夹

1)i2c-core.c

这个文件实现了i2C核心的功能以及/proc/bus/i2c*接口 。

2)i2c-dev.c

实现了I2c适配器设备文件的功能,每个I2c适配器都被分配一个设备。通过适配器访问设备时的主设备号都为89,次设备号为0-255。应用程序通过"i2c-%d"(i2c-0,i2c-1,...,i2c-10,...)文件名并使用文件操作接口open()、write()、read()、ioctl()、和close()等来访问这个设备。

i2c-dev.c并不是针对特定都设备而设计都,只是提供了通用都read()、write()和ioctl()等接口,应用层可以借用这些接口访问挂接在适配器上的i2c设备的存储空间或寄存器,并控制i2c设备的工作方式。

3)busses文件夹

这个文件包含了一些I2c主机控制权的驱动,如i2c-tegra.c、i2c-omap.c、i2c-versatile.c、i2c-s3c2410.c等

4)algos文件夹

实现了一些i2c总线适配器的通信方法

此外,内核中i2c.h文件对i2c_adapter、i2c_algorithm、i2c_driver和i2c_client这4个数据结构进行了定义。理解这四个结构体的作用十分重要,他们的定义位于include/linux/i2c.h文件中

cpp 复制代码
 719 struct i2c_adapter {
 720     struct module *owner;
 721     unsigned int class;       /* classes to allow probing for */
 722     const struct i2c_algorithm *algo; /* the algorithm to access the bus */
 723     void *algo_data;
 724 
 725     /* data fields that are valid for all devices   */
 726     const struct i2c_lock_operations *lock_ops;
 727     struct rt_mutex bus_lock;
 728     struct rt_mutex mux_lock;
 729 
 730     int timeout;            /* in jiffies */
 731     int retries;
 732     struct device dev;      /* the adapter device */
 733     unsigned long locked_flags; /* owned by the I2C core */
 734 #define I2C_ALF_IS_SUSPENDED        0
 735 #define I2C_ALF_SUSPEND_REPORTED    1
 736 
 737     int nr;
 738     char name[48];
 739     struct completion dev_released;
 740 
 741     struct mutex userspace_clients_lock;
 742     struct list_head userspace_clients;
 743 
 744     struct i2c_bus_recovery_info *bus_recovery_info;
 745     const struct i2c_adapter_quirks *quirks;
 746 
 747     struct irq_domain *host_notify_domain;
 748     struct regulator *bus_regulator;
 749 };
cpp 复制代码
 541 struct i2c_algorithm {
 542     /*
 543      * If an adapter algorithm can't do I2C-level access, set master_xfer
 544      * to NULL. If an adapter algorithm can do SMBus access, set
 545      * smbus_xfer. If set to NULL, the SMBus protocol is simulated
 546      * using common I2C messages.
 547      *
 548      * master_xfer should return the number of messages successfully
 549      * processed, or a negative value on error
 550      */
 551     int (*master_xfer)(struct i2c_adapter *adap, struct i2c_msg *msgs,
 552                int num);
 553     int (*master_xfer_atomic)(struct i2c_adapter *adap,
 554                    struct i2c_msg *msgs, int num);
 555     int (*smbus_xfer)(struct i2c_adapter *adap, u16 addr,
 556               unsigned short flags, char read_write,
 557               u8 command, int size, union i2c_smbus_data *data);
 558     int (*smbus_xfer_atomic)(struct i2c_adapter *adap, u16 addr,
 559                  unsigned short flags, char read_write,
 560                  u8 command, int size, union i2c_smbus_data *data);
 561 
 562     /* To determine what the adapter supports */
 563     u32 (*functionality)(struct i2c_adapter *adap);
 564 
 565 #if IS_ENABLED(CONFIG_I2C_SLAVE)
 566     int (*reg_slave)(struct i2c_client *client);
 567     int (*unreg_slave)(struct i2c_client *client);
 568 #endif
 569 };

上述代码551行master_xfer对应为I2c传输函数指针,i2c主机驱动的大部分工作也聚集在这里。上述第555行代码对应为SMbus传输函数指针,SMbus不需要增加额外引脚,与i2c总线相比,在访问时序上也有一定的差异。

cpp 复制代码
 271 struct i2c_driver {
 272     unsigned int class;
 273 
 274     /* Standard driver model interfaces */
 275     int (*probe)(struct i2c_client *client);
 276     void (*remove)(struct i2c_client *client);
 277 
 278 
 279     /* driver model interfaces that don't relate to enumeration  */
 280     void (*shutdown)(struct i2c_client *client);
 281 
 282     /* Alert callback, for example for the SMBus alert protocol.
 283      * The format and meaning of the data value depends on the protocol.
 284      * For the SMBus alert protocol, there is a single bit of data passed
 285      * as the alert response's low bit ("event flag").
 286      * For the SMBus Host Notify protocol, the data corresponds to the
 287      * 16-bit payload data reported by the slave device acting as master.
 288      */
 289     void (*alert)(struct i2c_client *client, enum i2c_alert_protocol protocol,
 290               unsigned int data);
 291 
 292     /* a ioctl like command that can be used to perform specific functions
 293      * with the device.
 294      */
 295     int (*command)(struct i2c_client *client, unsigned int cmd, void *arg);
 296 
 297     struct device_driver driver;
 298     const struct i2c_device_id *id_table;
 299 
 300     /* Device detection callback for automatic device creation */
 301     int (*detect)(struct i2c_client *client, struct i2c_board_info *info);
 302     const unsigned short *address_list;
 303     struct list_head clients;
 304 
 305     u32 flags;
 306 };
cpp 复制代码
 330 struct i2c_client {
 331     unsigned short flags;       /* div., see below      */
 332 #define I2C_CLIENT_PEC      0x04    /* Use Packet Error Checking */
 333 #define I2C_CLIENT_TEN      0x10    /* we have a ten bit chip address */
 334                     /* Must equal I2C_M_TEN below */
 335 #define I2C_CLIENT_SLAVE    0x20    /* we are the slave */
 336 #define I2C_CLIENT_HOST_NOTIFY  0x40    /* We want to use I2C host notify */
 337 #define I2C_CLIENT_WAKE     0x80    /* for board_info; true iff can wake */
 338 #define I2C_CLIENT_SCCB     0x9000  /* Use Omnivision SCCB protocol */
 339                     /* Must match I2C_M_STOP|IGNORE_NAK */
 340 
 341     unsigned short addr;        /* chip address - NOTE: 7bit    */
 342                     /* addresses are stored in the  */
 343                     /* _LOWER_ 7 bits       */
 344     char name[I2C_NAME_SIZE];
 345     struct i2c_adapter *adapter;    /* the adapter we sit on    */
 346     struct device dev;      /* the device structure     */
 347     int init_irq;           /* irq set at initialization    */
 348     int irq;            /* irq issued by device     */
 349     struct list_head detected;
 350 #if IS_ENABLED(CONFIG_I2C_SLAVE)
 351     i2c_slave_cb_t slave_cb;    /* callback for slave mode  */
 352 #endif
 353     void *devres_group_id;      /* ID of probe devres group */
 354 };

下面分析这4个数据结构的作用及盘根错节的关系

  1. i2c_adapter(适配器)与i2_algorithm(算法,通信方法)

i2c_adapter对应于物理上的一个适配器,而i2c_algorithm对应一套通信方法。一个i2c适配器需要i2c_algorithm提供的通信函数来控制适配器产生特定的访问周期。缺少i2c_algorithm的i2c_adapter什么也做不了,因此i2c_adapter中包含所使用的i2c_algorithm的指针。

i2c_algorithm的关键函数master_xfer()用于产生访问周期需要的信号,以i2c_msg(即i2c信息)为单位。i2c_msg结构体也是非常重要的,它定义于include/uapi/linux/i2c.h(在uapi目录下,证明用户空间的应用也可能用这个结构体)中,下图给出了它的定义,其中的成员表明了i2c的传输地址、方向、缓冲区、缓冲区长度等信息。

cpp 复制代码
 73 struct i2c_msg {
 74     __u16 addr;
 75     __u16 flags;
 76 #define I2C_M_RD        0x0001  /* guaranteed to be 0x0001! */
 77 #define I2C_M_TEN       0x0010  /* use only if I2C_FUNC_10BIT_ADDR */
 78 #define I2C_M_DMA_SAFE      0x0200  /* use only in kernel space */
 79 #define I2C_M_RECV_LEN      0x0400  /* use only if I2C_FUNC_SMBUS_READ_BLOCK_DATA */
 80 #define I2C_M_NO_RD_ACK     0x0800  /* use only if I2C_FUNC_PROTOCOL_MANGLING */
 81 #define I2C_M_IGNORE_NAK    0x1000  /* use only if I2C_FUNC_PROTOCOL_MANGLING */
 82 #define I2C_M_REV_DIR_ADDR  0x2000  /* use only if I2C_FUNC_PROTOCOL_MANGLING */
 83 #define I2C_M_NOSTART       0x4000  /* use only if I2C_FUNC_NOSTART */
 84 #define I2C_M_STOP      0x8000  /* use only if I2C_FUNC_PROTOCOL_MANGLING */
 85     __u16 len;
 86     __u8 *buf;
 87 };

2)i2c_driver与i2c_client

i2c_driver对应于一套驱动方法,其主要成员函数是probe()、remove()、suspen()、resumu()等,另外,struct i2c_device_id形式的id_table是该驱动所支持的i2c设备的ID表。i2c_client对应于真实的物理设备,每个i2c设备都需要一个i2c_client来描述。i2c_driver与i2c_client的关系是一对多,一个i2c_driver可以支持多个同类型的i2c_clinet 。

i2c_client的信息通常在BSP的板文件中通过i2c_board_info填充,如下:

在i2c总线驱动i2c_bus_type的match()函数i2c_device_match()中,会调用i2c_match_id()函数匹配在板文件中定义的ID和i2c_driver所支持的ID表 。

3)i2c_adapter与i2c_client

i2c_adapter与i2c_cilent的关系与i2c硬件体系中适配器和设备的关系一致,即i2c_clinet依附于i2c_adapter。由于一个适配器可以连接多个i2c设备,所有一个i2c_adapter也可以被多个i2c_client依附,i2c_adapter中包含依附它的i2c_client的链表。

假设i2c总线适配器xxx上有两个使用相同驱动程序的yyyI2c设备,在打开该I2c总线的设备节点后,相关数据结构之间的逻辑组织关系如图:

从上面的分析可知,虽然i2c硬件体系结构比较简单,但是i2c体系结构在linux中的实现却相当复杂。当工程师拿到实际的电路板时 ,面对复杂的linux i2c子系统,应该如何下手写驱动呢?究竟有哪些是需要亲自做的,哪些是内核已经提供的呢?理清这个问题非常有意义,可以使我们做面对具体问题时迅速抓住重点。

一方面,适配器驱动可能是linux内核本身还不包含的;另一方面,挂接做适配器上的具体设备驱动可能也是linux内核还不包含的。因此,工程师要实现的主要工作如下:

1)提供I2c硬件适配器的硬件驱动,探测、初始化i2c适配器(如申请i2c的i/O地址和中断号)、驱动cpu控制的i2c适配器从硬件上产生各种信号以及处理i2c中断等。

2)提供i2c适配器的Algorithm,用具体适配器的xxx_xfer()函数填充i2c_algorithm的master_xfer指针,并把i2c_algorithm指针赋值给i2c_adapter的algo指针。

3)实现i2c设备驱动中的i2c_driver接口,具体设备yyy的yyy_probe()、yyy_remove()、yyy_suspen()、yyy_resume()函数指针和i2c_device_id设备ID表赋值给i2c_driver的probe、remove、suspend、resume和id_table指针。

4)实现i2c设备所对应类型的具体驱动,i2c_driver只是实现设备与总线的挂接,而挂接在总线上的设备则千差万别。例如,如果是字符设备,就实现文件操作接口,即实现具体设备yyy的yyy_read()、yyy_write()和yyy_ioctl函数等;如果是声卡就实现ALSA驱动。

上述工作中前两个属于I2c总线驱动,后两个属于i2c设备驱动。

二、 linux I2c核心

I2c核心(drivers/i2c/i2c-core-base.c) 中提供了一组不依赖于硬件平台的接口函数,这个文件一般不需要被工程师修改,但是理解其中的主要函数非常关键,因为i2c总线驱动和设备驱动以i2c核心作为纽带。i2c核心的主要函数如下。

1)增加、删除i2c_adapter

2)增加/删除i2c_dirver

3)i2c传输、发送和接收

i2c_transfer()函数用于进行i2c适配器和i2c设备之间的一组消息交互,其中第2个参数是指向i2c_msg数组的指针,所以i2c_transfer()一次可以传输多个i2c_msg(考虑到很多外设的读写波形比较复杂,比如读寄存器可能要先写,所以需要两个以上的消息)。而对于时序比较简单的外设,i2c_maste_send()函数和i2c_master_recv()函数内部都会调用i2c_transfer()函数分别完成一条写消息和读消息。

i2c_transfer()函数本身不具备驱动适配器物理硬件以完成消息交互的能力,它只是寻找到与i2c_adapter对应的i2c_algorithm,并使用i2c_algorithm的master_xfer()函数真正驱动硬件流程。

三、 linux I2c适配器驱动

3.1 I2c适配器驱动的注册与注销

由于I2c总线控制器通常是在内存上的,所以本身也连接在platform总线上,要通过platform_driver和platform_device的匹配来执行。因此尽管i2c适配器给别人提供了总线,它自己也被认为是接在platform总线上的一个客户。linux的总线、设备和驱动模型实际上是一个树形结构,每个节点虽然可能成为别人的总线控制器,但是自己也被认为是从上一级总线枚举出来的。

通常我们会在与I2c适配器所对应的platform_driver的probe()函数中完成两个工作。

1)初始化I2c适配器所使用的硬件资源,如申请I/O地址、中断号、时钟等

  1. 通过i2c_add_adapter()添加i2c_adapter的数据结构,当然这个i2c_adapter数据结构的成员已经被xxx适配器的相应函数指针初始化。

通常我们会在platform_driver的remove()函数中完成与加载函数相反的工作

3)释放i2c适配器所使用的硬件资源,如释放I/O地址、中断号、时钟等。

4)通过i2c_del_adapter()删除i2c_adapter的数据结构

上诉代码中的xxx_adpater_hw_init()和xxx_adpater_hw_free()函数的实现都与具体的CPU和i2c适配硬件直接相关。

3.2 I2c总线的通信方法

我们需要为特定的i2c适配器实现通信方法,主要是实现i2c_algorithm的functionality()函数和master_xfer()函数。

functionality()函数非常,用于返回algorithm所支持的通信协议,如I2C_FUNC_I2C、I2C_FUNC_10BIT_ADDR、I2C_FUNC_SMBUS_READ_BYTE、I2C_FUNC_SMBUS_WRITE_BYTE等。

master_xfer()函数在i2c适配器上完成传递给它的i2c_msg数组中的每个I2C消息。

四、 linux I2c设备驱动

I2c设备驱动要使用i2c_driver和i2c_client数据结构并填充i2c_driver中的成员函数。i2c_client一般被包含在设备的私有信息结构体yyy_data中,而i2c_driver则适合被定义为全局变量并初始化。

4.1 linux I2c设备驱动的模块加载与卸载

i2c设备驱动的模块加载函数通过i2c核心的i2c_add_driver()API函数添加i2c_driver的工作,而模块卸载函数需要做相反的工作:通过i2c核心的i2c_del_driver()函数删除i2c_dirver 。模板如下:

4.2、 linux I2c设备驱动的数据传输

在i2c设备上读写数据的时序且数据通常通过i2c_msg数组进行组织,最后通过i2c_transfer()函数完成。

4.3、 linux的i2c-dev.c文件分析

i2c-dev.c完全可以被看作一个i2c设备驱动,不过,它实现的i2c-client是虚拟的,临时的。主要是为了方便从用户空间操作i2c外设。i2c-dev.c针对每个i2c适配器生成一个主设备号为89的设备文件,实现了i2c_driver的成员函数及其文件操作接口,因此i2c-dev.c的主体是"i2c_driver成员函数+字符设备驱动"。

i2c-dev.c提供的i2cdev_read()、i2cdec_write()函数对应于用户空间要使用的read()和write()文件操作接口,这两个函数分别调用i2c核心的i2c_maser_recv()和i2c_master_send()函数来构造一条i2c消息并引发适配器Algorithm通信函数的调用,以完成消息的传输,它对应下面的时序:

但是,很遗憾,大多数稍微复杂一点的i2c设备的读写流程并不对应一条消息,往往需要两条甚至多条消息来进行一次读写周期(即下面图示模式),在这种情况下,在应用层仍然调用read()、write()文件API来读写I2c设备,将不能正确地读写。

鉴于以上原因,i2c-dev.c中i2cdev_read()和i2cdec_write()函数不具备太强的通用性,没有太大的实用价值,只能适用非RepStart模式的情况。对于由两条以上消息组成的读写 ,在用户空间需要组织i2c_msg消息数组并调用I2C_RDWR IOCTL命令。

常用的IOCTL包括I2C_SLAVE(设置从设备地址)、I2C_RETRIES(没有收到设备ACK情况下的重试次数,默认为1)、I2C_TIMEOU(超时)以及I2C_RDWR。

五、Tegra I2c总线驱动实例

NVIDIA Tegra I2c总线总线驱动位于drivers/i2c/busses/i2c-tegra.c文件中,这里不具体研究它的硬件细节,只看一下驱动框架和流程。

I2c总线驱动是一个单独的驱动,在模块的加载和卸载函数中,只需要注册和注销platform_driver结构体。

cpp 复制代码
1629 static const struct of_device_id tegra_i2c_of_match[] = {
1630     { .compatible = "nvidia,tegra194-i2c", .data = &tegra194_i2c_hw, },
1631     { .compatible = "nvidia,tegra186-i2c", .data = &tegra186_i2c_hw, },
1632 #if IS_ENABLED(CONFIG_ARCH_TEGRA_210_SOC)
1633     { .compatible = "nvidia,tegra210-i2c-vi", .data = &tegra210_i2c_hw, },
1634 #endif
1635     { .compatible = "nvidia,tegra210-i2c", .data = &tegra210_i2c_hw, },
1636     { .compatible = "nvidia,tegra124-i2c", .data = &tegra124_i2c_hw, },
1637     { .compatible = "nvidia,tegra114-i2c", .data = &tegra114_i2c_hw, },
1638     { .compatible = "nvidia,tegra30-i2c", .data = &tegra30_i2c_hw, },
1639     { .compatible = "nvidia,tegra20-i2c", .data = &tegra20_i2c_hw, },
1640 #if IS_ENABLED(CONFIG_ARCH_TEGRA_2x_SOC)
1641     { .compatible = "nvidia,tegra20-i2c-dvc", .data = &tegra20_i2c_hw, },
1642 #endif
1643     {},
1644 };
1645 MODULE_DEVICE_TABLE(of, tegra_i2c_of_match);

1967 static struct platform_driver tegra_i2c_driver = {
1968     .probe = tegra_i2c_probe,
1969     .remove_new = tegra_i2c_remove,
1970     .driver = {
1971         .name = "tegra-i2c",
1972         .of_match_table = tegra_i2c_of_match,
1973         .acpi_match_table = tegra_i2c_acpi_match,
1974         .pm = &tegra_i2c_pm,
1975     },
1976 };
1977 module_platform_driver(tegra_i2c_driver);

当在arch/arm/mach-tegra下创建一个名字为tegra-i2c的同名的platform_device,或者在tegra的设备树中添加了tegra_i2c_of_match匹配表兼容的节点后,上述platform_driver中的probe()函数就会执行。

其中probe指针指向的tegra_i2c_probe()函数将被调用。以初始化,适配器硬件、申请适配器要的内存、时钟、中断等资源,最终注册适配器。

上述代码中提到tegra_i2c_dev结构体可进行适配器所有信息的封装,类似私有信息结构体。下图是tegra_i2c_dev结构体的定义。我们在编程中要时刻牢记linux这个编程习惯,这实际上也是面向对象的一种体现。

cpp 复制代码
 260 struct tegra_i2c_dev {
 261     struct device *dev;
 262     struct i2c_adapter adapter;
 263 
 264     const struct tegra_i2c_hw_feature *hw;
 265     struct reset_control *rst;
 266     unsigned int cont_id;
 267     unsigned int irq;
 268 
 269     phys_addr_t base_phys;
 270     void __iomem *base;
 271 
 272     struct clk_bulk_data clocks[2];
 273     unsigned int nclocks;
 274 
 275     struct clk *div_clk;
 276     struct i2c_timings timings;
 277 
 278     struct completion msg_complete;
 279     size_t msg_buf_remaining;
 280     unsigned int msg_len;
 281     int msg_err;
 282     u8 *msg_buf;
 283 
 284     struct completion dma_complete;
 285     struct dma_chan *dma_chan;
 286     unsigned int dma_buf_size;
 287     struct device *dma_dev;
 288     dma_addr_t dma_phys;
 289     void *dma_buf;
 290 
 291     bool multimaster_mode;
 292     bool atomic_mode;
 293     bool dma_mode;
 294     bool msg_read;
 295     bool is_dvc;
 296     bool is_vi;
 297 };

tegra_i2c_probe()函数中的platform_set_drvdata(pdev,i2c_dev)和i2c_set_adapterdata(&I2C_dev->adapter,i2c_dev)已经把这个结构体的实例依附到了platform_device和i2c_adapter的私有数据上了,在其他地方只要用到相应的方法就可以把这个结构体的实例取出来。

从前面的白图代码60行可以看出,于i2c适配器对应的i2c_algorithm结构体实例为tera_i2c_algo,下图给出定义

上诉代码第一行指定了Tera I2c总线通信传输函数tegra_i2c_xfer(),这个函数非常关键,所有在i2c总线上对设备的访问最终应该由它完成。下图为这个重要函数以及其依赖的tegra_i2c_xfer_msg()函数的源码:

cpp 复制代码
1213 static int tegra_i2c_xfer_msg(struct tegra_i2c_dev *i2c_dev,
1214                   struct i2c_msg *msg,
1215                   enum msg_end_type end_state)
1216 {
1217     unsigned long time_left, xfer_time = 100;
1218     size_t xfer_size;
1219     u32 int_mask;
1220     int err;
1221 
1222     err = tegra_i2c_flush_fifos(i2c_dev);
1223     if (err)
1224         return err;
1225 
1226     i2c_dev->msg_buf = msg->buf;
1227     i2c_dev->msg_len = msg->len;
1228 
1229     i2c_dev->msg_err = I2C_ERR_NONE;
1230     i2c_dev->msg_read = !!(msg->flags & I2C_M_RD);
1231     reinit_completion(&i2c_dev->msg_complete);
1232 
1233     /*
1234      * For SMBUS block read command, read only 1 byte in the first transfer.
1235      * Adjust that 1 byte for the next transfer in the msg buffer and msg
1236      * length.
1237      */
1238     if (msg->flags & I2C_M_RECV_LEN) {
1239         if (end_state == MSG_END_CONTINUE) {
1240             i2c_dev->msg_len = 1;
1241         } else {
1242             i2c_dev->msg_buf += 1;
1243             i2c_dev->msg_len -= 1;
1244         }
1245     }
1246 
1247     i2c_dev->msg_buf_remaining = i2c_dev->msg_len;
1248 
1249     if (i2c_dev->msg_read)
1250         xfer_size = i2c_dev->msg_len;
1251     else
1252         xfer_size = i2c_dev->msg_len + I2C_PACKET_HEADER_SIZE;
1253 
1254     xfer_size = ALIGN(xfer_size, BYTES_PER_FIFO_WORD);
1255 
1256     i2c_dev->dma_mode = xfer_size > I2C_PIO_MODE_PREFERRED_LEN &&
1257                 i2c_dev->dma_buf && !i2c_dev->atomic_mode;
1258 
1259     tegra_i2c_config_fifo_trig(i2c_dev, xfer_size);
1260 
1261     /*
1262      * Transfer time in mSec = Total bits / transfer rate
1263      * Total bits = 9 bits per byte (including ACK bit) + Start & stop bits
1264      */
1265     xfer_time += DIV_ROUND_CLOSEST(((xfer_size * 9) + 2) * MSEC_PER_SEC,
1266                        i2c_dev->timings.bus_freq_hz);
1267 
1268     int_mask = I2C_INT_NO_ACK | I2C_INT_ARBITRATION_LOST;
1269     tegra_i2c_unmask_irq(i2c_dev, int_mask);
1270 
1271     if (i2c_dev->dma_mode) {
1272         if (i2c_dev->msg_read) {
1273             dma_sync_single_for_device(i2c_dev->dma_dev,
1274                            i2c_dev->dma_phys,
1275                            xfer_size, DMA_FROM_DEVICE);
1276 
1277             err = tegra_i2c_dma_submit(i2c_dev, xfer_size);
1278             if (err)
1279                 return err;
1280         } else {
1281             dma_sync_single_for_cpu(i2c_dev->dma_dev,
1282                         i2c_dev->dma_phys,
1283                         xfer_size, DMA_TO_DEVICE);
1284         }
1285     }
1286 
1287     tegra_i2c_push_packet_header(i2c_dev, msg, end_state);
1288 
1289     if (!i2c_dev->msg_read) {
1290         if (i2c_dev->dma_mode) {
1291             memcpy(i2c_dev->dma_buf + I2C_PACKET_HEADER_SIZE,
1292                    msg->buf, i2c_dev->msg_len);
1293 
1294             dma_sync_single_for_device(i2c_dev->dma_dev,
1295                            i2c_dev->dma_phys,
1296                            xfer_size, DMA_TO_DEVICE);
1297 
1298             err = tegra_i2c_dma_submit(i2c_dev, xfer_size);
1299             if (err)
1300                 return err;
1301         } else {
1302             tegra_i2c_fill_tx_fifo(i2c_dev);
1303         }
1304     }
1305 
1306     if (i2c_dev->hw->has_per_pkt_xfer_complete_irq)
1307         int_mask |= I2C_INT_PACKET_XFER_COMPLETE;
1308 
1309     if (!i2c_dev->dma_mode) {
1310         if (msg->flags & I2C_M_RD)
1311             int_mask |= I2C_INT_RX_FIFO_DATA_REQ;
1312         else if (i2c_dev->msg_buf_remaining)
1313             int_mask |= I2C_INT_TX_FIFO_DATA_REQ;
1314     }
1315 
1316     tegra_i2c_unmask_irq(i2c_dev, int_mask);
1317     dev_dbg(i2c_dev->dev, "unmasked IRQ: %02x\n",
1318         i2c_readl(i2c_dev, I2C_INT_MASK));
1319 
1320     if (i2c_dev->dma_mode) {
1321         time_left = tegra_i2c_wait_completion(i2c_dev,
1322                               &i2c_dev->dma_complete,
1323                               xfer_time);
1324 
1325         /*
1326          * Synchronize DMA first, since dmaengine_terminate_sync()
1327          * performs synchronization after the transfer's termination
1328          * and we want to get a completion if transfer succeeded.
1329          */
1330         dmaengine_synchronize(i2c_dev->dma_chan);
1331         dmaengine_terminate_sync(i2c_dev->dma_chan);
1332 
1333         if (!time_left && !completion_done(&i2c_dev->dma_complete)) {
1334             dev_err(i2c_dev->dev, "DMA transfer timed out\n");
1335             tegra_i2c_init(i2c_dev);
1336             return -ETIMEDOUT;
1337         }
1338 
1339         if (i2c_dev->msg_read && i2c_dev->msg_err == I2C_ERR_NONE) {
1340             dma_sync_single_for_cpu(i2c_dev->dma_dev,
1341                         i2c_dev->dma_phys,
1342                         xfer_size, DMA_FROM_DEVICE);
1343 
1344             memcpy(i2c_dev->msg_buf, i2c_dev->dma_buf, i2c_dev->msg_len);
1345         }
1346     }
1347 
1348     time_left = tegra_i2c_wait_completion(i2c_dev, &i2c_dev->msg_complete,
1349                           xfer_time);
1350 
1351     tegra_i2c_mask_irq(i2c_dev, int_mask);
1352 
1353     if (time_left == 0) {
1354         dev_err(i2c_dev->dev, "I2C transfer timed out\n");
1355         tegra_i2c_init(i2c_dev);
1356         return -ETIMEDOUT;
1357     }
1358 
1359     dev_dbg(i2c_dev->dev, "transfer complete: %lu %d %d\n",
1360         time_left, completion_done(&i2c_dev->msg_complete),
1361         i2c_dev->msg_err);
1362 
1363     i2c_dev->dma_mode = false;
1364 
1365     err = tegra_i2c_error_recover(i2c_dev, msg);
1366     if (err)
1367         return err;
1368 
1369     return 0;
1370 }



1372 static int tegra_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg msgs[],
1373               int num)
1374 {
1375     struct tegra_i2c_dev *i2c_dev = i2c_get_adapdata(adap);
1376     int i, ret;
1377 
1378     ret = pm_runtime_get_sync(i2c_dev->dev);
1379     if (ret < 0) {
1380         dev_err(i2c_dev->dev, "runtime resume failed %d\n", ret);
1381         pm_runtime_put_noidle(i2c_dev->dev);
1382         return ret;
1383     }
1384 
1385     for (i = 0; i < num; i++) {
1386         enum msg_end_type end_type = MSG_END_STOP;
1387 
1388         if (i < (num - 1)) {
1389             /* check whether follow up message is coming */
1390             if (msgs[i + 1].flags & I2C_M_NOSTART)
1391                 end_type = MSG_END_CONTINUE;
1392             else
1393                 end_type = MSG_END_REPEAT_START;
1394         }
1395         /* If M_RECV_LEN use ContinueXfer to read the first byte */
1396         if (msgs[i].flags & I2C_M_RECV_LEN) {
1397             ret = tegra_i2c_xfer_msg(i2c_dev, &msgs[i], MSG_END_CONTINUE);
1398             if (ret)
1399                 break;
1400             /* Set the msg length from first byte */
1401             msgs[i].len += msgs[i].buf[0];
1402             dev_dbg(i2c_dev->dev, "reading %d bytes\n", msgs[i].len);
1403         }
1404         ret = tegra_i2c_xfer_msg(i2c_dev, &msgs[i], end_type);
1405         if (ret)
1406             break;
1407     }
1408 
1409     pm_runtime_put(i2c_dev->dev);
1410 
1411     return ret ?: i;
1412 }

从代码层面上看,第35行的for循环遍历所有的i2c_msg,每个i2c_msg则由tegra_i2c_xfer_msg()函数处理,它每次发起硬件操作后,实际上需要通过wait_for_completion_timeout()等待传输的完成,因此这里面就会有一个被调度出去的过程。中断到来且i2c的包传输结束的时候,就是唤醒这个睡眠进程的时候。

六、 总结

linux的i2c驱动体系相当复杂,它主要由3部分组成,即i2c核心、i2c总线驱动和i2c设备驱动。I2c核心是i2c总线驱动和i2c设备驱动的中间枢纽,它以通用的、与平台的无关的接口是实现了i2c中设备与适配器的沟通。i2c总线驱动填充i2c_adapter和i2c_algorithm结构体,i2c设备驱动填充i2c_driver结构体并实现其本身所对应设备类型的驱动。

另外,系统中i2c-dev.c文件定义的主设备号89的设备可以方便地给应用程序提供读写i2c设备寄存器的能力,使得工程师在大多数时候并不需要为具体的i2c设备驱动定义文件操作接口。

相关推荐
小晶晶京京10 分钟前
day34-LNMP详解
linux·运维·服务器
画个太阳作晴天11 分钟前
A12预装app
linux·服务器·前端
fengyehongWorld1 小时前
Linux crontab定时任务
linux·运维
shuangrenlong1 小时前
ubuntu更新chrome版本
linux·chrome·ubuntu
碎像1 小时前
Linux上配置环境变量
linux·运维·服务器
敲上瘾2 小时前
Linux系统cgroups资源精细化控制基础
linux·测试工具·docker·压力测试·cgroups
起个昵称吧2 小时前
线程相关编程、线程间通信、互斥锁
linux·算法
myzzb3 小时前
基于uiautomation的自动化流程RPA开源开发演示
运维·python·学习·算法·自动化·rpa
Ronin3054 小时前
【Linux系统】进程间通信:System V IPC——共享内存
linux·服务器·system v 共享内存