linux中I2C体系结构及4个核心数据结构

一、linux的I2C驱动体系结构分为4部分

1. i2c-core:

I2C核心,即i2c_core.c 。提供了I2C总线驱动和设备驱动的注册和注销方法,I2C通信algorithm上层的、与具体适配器无关的代码,以及探测设备、检测设备地址的上层代码等。

2. i2c-algorythm:

里面有I2C的通信方法(即algotithm),位于linux内核源代码drivers/i2c/algos/目录中。

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

位于linux内核源代码/drivers/i2c/buses目录中。

I2C总线驱动主要包含了I2C适配器数据结构i2c_adapter, I2C适配器算法algorithm书记结构i2c_algorithm.

各主芯片,具有I2C通信功能的CPU,都会有相应的一套I2C总线驱动程序。
如i2c_s3c2410.c,i2c_ambarella.c等。
包含了2个重要结构体i2c_adapter,i2c_algorithm。
还有个i2c_dev.c 把适配器转换成一个设备文件,提供通用的read(),write(),ioctl()等接口。
4. I2C设备驱动。 设备一般挂接在受CPU控制的I2C适配器上,通过I2C适配器与CPU交换数据。

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

I2C通信的设备端,如eeprom芯片,RTC芯片,AD芯片SAA7113H。
程序如:i2c_saa7113h.c ,i2c_ds1337.c等。
包含2个重要结构体:i2c_driver,i2c_client。
位于linux内核源代码/drivers/i2c/chips目录中。
二、代码位于/drivers/i2c/*, 主要文件:

i2c-core.c 实现了I2C核心功能及 /proc/bus/i2c*接口。

i2c-dev.c 实现了I2C适配器设备文件的功能,每一个I2C适配器都被分配一个设备。通过适配器访问设备时的主设备号都是89,次设备号为0~255。

应用程序通过open(),write(),read(),ioctl(),close()等文件操作接口,来访问"i2c-%d"(i2c-0, i2c-1, i2c-2, ***)文件。 即应用层可以借用这些接口,来访问挂接在适配器上的I2C设备的存储空间或寄存器,并控制I2C设备的工作方式。

三、4个关键结构体

1.i2c_adapter

  1. /*
     * i2c_adapter is the structure used to identify a physical i2c bus along
     * with the access algorithms necessary to access it.
     */
    struct i2c_adapter {
        struct module *owner;
        unsigned int id __deprecated;
        unsigned int class;         /* classes to allow probing for */
        const struct i2c_algorithm *algo; /* the algorithm to access the bus */
        void *algo_data;
        /* data fields that are valid for all devices    */
        struct rt_mutex bus_lock;
        int timeout;            /* in jiffies */
        int retries;
        struct device dev;        /* the adapter device */
        int nr;
        char name[48];
        struct completion dev_released;
        struct mutex userspace_clients_lock;
        struct list_head userspace_clients;
    };
    #define to_i2c_adapter(d) container_of(d, struct i2c_adapter, dev)

    2.i2c_client
    /**
     * struct i2c_client - represent an I2C slave device
     * @flags: I2C_CLIENT_TEN indicates the device uses a ten bit chip address;
     *    I2C_CLIENT_PEC indicates it uses SMBus Packet Error Checking
     * @addr: Address used on the I2C bus connected to the parent adapter.
     * @name: Indicates the type of the device, usually a chip name that's
     *    generic enough to hide second-sourcing and compatible revisions.
     * @adapter: manages the bus segment hosting this I2C device
     * @driver: device's driver, hence pointer to access routines
     * @dev: Driver model device node for the slave.
     * @irq: indicates the IRQ generated by this device (if any)
     * @detected: member of an i2c_driver.clients list or i2c-core's
     *    userspace_devices list
     *
     * An i2c_client identifies a single device (i.e. chip) connected to an
     * i2c bus. The behaviour exposed to Linux is defined by the driver
     * managing the device.
     */
    struct i2c_client {
        unsigned short flags;        /* div., see below        */
        unsigned short addr;        /* chip address - NOTE: 7bit    */
                        /* addresses are stored in the    */
                        /* _LOWER_ 7 bits        */
        char name[I2C_NAME_SIZE];
        struct i2c_adapter *adapter;    /* the adapter we sit on    */
        struct i2c_driver *driver;    /* and our access routines    */
        struct device dev;        /* the device structure        */
        int irq;            /* irq issued by device        */
        struct list_head detected;
    };
    #define to_i2c_client(d) container_of(d, struct i2c_client, dev)

3. i2c_driver
    /**
     * struct i2c_driver - represent an I2C device driver
     * @class: What kind of i2c device we instantiate (for detect)
     * @attach_adapter: Callback for bus addition (for legacy drivers)
     * @detach_adapter: Callback for bus removal (for legacy drivers)
     * @probe: Callback for device binding
     * @remove: Callback for device unbinding
     * @shutdown: Callback for device shutdown
     * @suspend: Callback for device suspend
     * @resume: Callback for device resume
     * @alert: Alert callback, for example for the SMBus alert protocol
     * @command: Callback for bus-wide signaling (optional)
     * @driver: Device driver model driver
     * @id_table: List of I2C devices supported by this driver
     * @detect: Callback for device detection
     * @address_list: The I2C addresses to probe (for detect)
     * @clients: List of detected clients we created (for i2c-core use only)
     *
     * The driver.owner field should be set to the module owner of this driver.
     * The driver.name field should be set to the name of this driver.
     *
     * For automatic device detection, both @detect and @address_data must
     * be defined. @class should also be set, otherwise only devices forced
     * with module parameters will be created. The detect function must
     * fill at least the name field of the i2c_board_info structure it is
     * handed upon successful detection, and possibly also the flags field.
     *
     * If @detect is missing, the driver will still work fine for enumerated
     * devices. Detected devices simply won't be supported. This is expected
     * for the many I2C/SMBus devices which can't be detected reliably, and
     * the ones which can always be enumerated in practice.
     *
     * The i2c_client structure which is handed to the @detect callback is
     * not a real i2c_client. It is initialized just enough so that you can
     * call i2c_smbus_read_byte_data and friends on it. Don't do anything
     * else with it. In particular, calling dev_dbg and friends on it is
     * not allowed.
     */
    struct i2c_driver {
        unsigned int class;
        /* Notifies the driver that a new bus has appeared or is about to be
         * removed. You should avoid using this if you can, it will probably
         * be removed in a near future.
         */
        int (*attach_adapter)(struct i2c_adapter *);
        int (*detach_adapter)(struct i2c_adapter *);
        /* Standard driver model interfaces */
        int (*probe)(struct i2c_client *, const struct i2c_device_id *);
        int (*remove)(struct i2c_client *);
        /* driver model interfaces that don't relate to enumeration */
        void (*shutdown)(struct i2c_client *);
        int (*suspend)(struct i2c_client *, pm_message_t mesg);
        int (*resume)(struct i2c_client *);
        /* Alert callback, for example for the SMBus alert protocol.
         * The format and meaning of the data value depends on the protocol.
         * For the SMBus alert protocol, there is a single bit of data passed
         * as the alert response's low bit ("event flag").
         */
        void (*alert)(struct i2c_client *, unsigned int data);
        /* a ioctl like command that can be used to perform specific functions
         * with the device.
         */
        int (*command)(struct i2c_client *client, unsigned int cmd, void *arg);
        struct device_driver driver;
        const struct i2c_device_id *id_table;
        /* Device detection callback for automatic device creation */
        int (*detect)(struct i2c_client *, struct i2c_board_info *);
        const unsigned short *address_list;
        struct list_head clients;
    };
    #define to_i2c_driver(d) container_of(d, struct i2c_driver, driver)

4.i2c_algorithm
    /*
     * The following structs are for those who like to implement new bus drivers:
     * i2c_algorithm is the interface to a class of hardware solutions which can
     * be addressed using the same bus algorithms - i.e. bit-banging or the PCF8584
     * to name two of the most common.
     */
    struct i2c_algorithm {
        /* If an adapter algorithm can't do I2C-level access, set master_xfer
         to NULL. If an adapter algorithm can do SMBus access, set
         smbus_xfer. If set to NULL, the SMBus protocol is simulated
         using common I2C messages */
        /* master_xfer should return the number of messages successfully
         processed, or a negative value on error */
        int (*master_xfer)(struct i2c_adapter *adap, struct i2c_msg *msgs,
                 int num);
        int (*smbus_xfer) (struct i2c_adapter *adap, u16 addr,
                 unsigned short flags, char read_write,
                 u8 command, int size, union i2c_smbus_data *data);
        /* To determine what the adapter supports */
        u32 (*functionality) (struct i2c_adapter *);
    };

一、i2c_driver, i2c_client, i2c_adapter, i2c_algorithm 这4个数据结构的作用及关系

1.i2c_adapter 与 i2c_algorithm

i2c_adapter 对应物理上一个适配器,而i2c_algorithm对应一套通信算法。

I2C适配器需要i2c_algorithm中提供的通信函数,来控制适配器上产生特定的访问周期,缺少i2c_algorithm的i2c_adapter什么也做不了.

i2c_adapter中包含了其使用的i2c_algorithm的指针。

i2c_algorithm中关键函数是 master_xfer(),用于产生I2C访问周期的需要的信号,以i2c_msg为单位。

    /**
     * struct i2c_msg - an I2C transaction segment beginning with START
     * @addr: Slave address, either seven or ten bits. When this is a ten
     *    bit address, I2C_M_TEN must be set in @flags and the adapter
     *    must support I2C_FUNC_10BIT_ADDR.
     * @flags: I2C_M_RD is handled by all adapters. No other flags may be
     *    provided unless the adapter exported the relevant I2C_FUNC_*
     *    flags through i2c_check_functionality().
     * @len: Number of data bytes in @buf being read from or written to the
     *    I2C slave address. For read transactions where I2C_M_RECV_LEN
     *    is set, the caller guarantees that this buffer can hold up to
     *    32 bytes in addition to the initial length byte sent by the
     *    slave (plus, if used, the SMBus PEC); and this value will be
     *    incremented by the number of block data bytes received.
     * @buf: The buffer into which data is read, or from which it's written.
     *
     * An i2c_msg is the low level representation of one segment of an I2C
     * transaction. It is visible to drivers in the @i2c_transfer() procedure,
     * to userspace from i2c-dev, and to I2C adapter drivers through the
     * @i2c_adapter.@master_xfer() method.
     *
     * Except when I2C "protocol mangling" is used, all I2C adapters implement
     * the standard rules for I2C transactions. Each transaction begins with a
     * START. That is followed by the slave address, and a bit encoding read
     * versus write. Then follow all the data bytes, possibly including a byte
     * with SMBus PEC. The transfer terminates with a NAK, or when all those
     * bytes have been transferred and ACKed. If this is the last message in a
     * group, it is followed by a STOP. Otherwise it is followed by the next
     * @i2c_msg transaction segment, beginning with a (repeated) START.
     *
     * Alternatively, when the adapter supports I2C_FUNC_PROTOCOL_MANGLING then
     * passing certain @flags may have changed those standard protocol behaviors.
     * Those flags are only for use with broken/nonconforming slaves, and with
     * adapters which are known to support the specific mangling options they
     * need (one or more of IGNORE_NAK, NO_RD_ACK, NOSTART, and REV_DIR_ADDR).
     */
    struct i2c_msg {
        __u16 addr;    /* slave address            */ //设备地址
        __u16 flags;
    #define I2C_M_TEN        0x0010    /* this is a ten bit chip address */
    #define I2C_M_RD        0x0001    /* read data, from slave to master */
    #define I2C_M_NOSTART        0x4000    /* if I2C_FUNC_PROTOCOL_MANGLING */
    #define I2C_M_REV_DIR_ADDR    0x2000    /* if I2C_FUNC_PROTOCOL_MANGLING */
    #define I2C_M_IGNORE_NAK    0x1000    /* if I2C_FUNC_PROTOCOL_MANGLING */
    #define I2C_M_NO_RD_ACK        0x0800    /* if I2C_FUNC_PROTOCOL_MANGLING */
    #define I2C_M_RECV_LEN        0x0400    /* length will be first received byte */
        __u16 len;        /* msg length                */
        __u8 *buf;        /* pointer to msg data            */  //消息数据
    };
2. i2c_driver and i2c_client.

i2c_driver是一套驱动方法,用于辅助作用的数据结构,不对应任何物理实体。

i2c_client对应真实的物理设备,每个I2C设备都需要一个i2c_client来描述。

i2c_client一般被包含在I2C字符设备的私有信息结构体中,private_data.

i2c_driver的attach_adapter()函数被运行时,i2c_adapter()会探测物理设备,当确定一个client存在时,把该client使用的i2c_client数据结构的adapter指针指向对应的i2c_adapter, driver指针指向i2c_driver,并会调用i2c_adapter的client_register()函数。

相反的过程发生在i2c_driver的detach_client()函数被调用的时候。

3.i2c_adapter 与 i2c_client

i2c_adapter 与 i2c_client 关系相当于适配器和设备的关系,i2c_client 依附于 i2c_adapter.

一个适配器可以连接多个I2C设备,所以一个 i2c_adapter 可以被多个 i2c_client 依附。

i2c_adapter 中有依附于它的 i2c_client 的链表。

二、I2C模块中工程师需要实现的工作:

1. 写I2C适配器的驱动: 探测、初始化I2C适配器(如申请I2C的I/O地址,中断号)、驱动I2C适配器在硬件上产生各种信号,及处理I2C中断等。

2. 写I2C适配器的algorithm:用具体适配器的xxx_xfer函数填充i2c_algorithm的master_xfer指针,并把i2c_algorithm指针赋值给i2c_adapter的algo指针。

3. 写I2C设备驱动:实现I2C设备驱动与i2c_driver的接口,用具体设备yyy的yyy_attach_adapter()函数指针,yyy_detach_client()函数指针,和yyy_commond()函数指针,赋值给i2c_driver的attach_adater,detach_adapter,和detach_client指针。

4.实现I2C设备驱动的文件操作接口: 即实现具体设备yyy的 yyy_read(),yyy_write(),yyy_ioctl().

前两个工作属于I2C总线驱动,后两个属于I2C设备驱动。



  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
请优化(不是并行化,而是从cache、函数调用开销、编译等方面优化)下面的串行程序,测试每个优化措施的效果。用Linux环境,编译器不限(gcc,icc等都可以)。以报告形式上传。 #include <stdio.h> #include <stdlib.h> #include <math.h> #define M 1500 #define NM 2000 #define N 2500 void generate_matrix(double *A, long m, long n) { long i, j; for (i=0; i<m; i++) for (j=0; j<n; j++) { A[i*n + j] = rand()/(RAND_MAX+1.0); //0 - 1 A[i*n + j] = 2*A[i*n + j] - 1; //-1 - +1 } } double handle_data(double data) { return sqrt(fabs(data)); } void handle_matrix(double *A, double *B, double *C, long m, long nm, long n) { long i, j, k; double s; for (i=0; i<m; i++) { for (j=0; j<n; j++) { s = 0; for (k=0; k<nm; k++) s += A[i*nm + k] * B[k*n + j]; C[i*n + j] = handle_data(s); } } } double sum_matrix(double *A, long m, long n) { long i, j; double s = 0; for (i=0; i<m; i++) for (j=0; j<n; j++) s += A[i*n + j]; return s; } int main() { double *A = (double *)malloc(M * NM * sizeof(double)); double *B = (double *)malloc(NM * N * sizeof(double)); double *C = (double *)malloc(M * N * sizeof(double)); generate_matrix(A, M, NM); generate_matrix(B, NM, N); struct timeval begin_time, end_time; double run_time_ms; gettimeofday(&begin_time); handle_matrix(A, B, C, M, NM, N); gettimeofday(&end_time); run_time_ms = (end_time.tv_sec - begin_time.tv_sec)*1000 + (end_time.tv_usec - begin_time.tv_usec)*1.0/1000; printf("run_time = %lfms\n", run_time_ms); printf("Sum = %.4f\n", sum_matrix(C, M, N)); free(A); free(B); free(C); return 0; }
03-25

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值