linux ------ I2C 子系统及设备驱动

    1. I2C 子系统框架图

        

                从框架中看,用户应用通过/sys或者/dev中的设备节点来访问I2C设备。内核空间中的I2C分I2C client driver、I2C-Core与I2C Adapter driver三部分。其中I2C-Core是linux内核实现好的代码,I2C Adapter driver是具体CPU硬件平台的host 控制器驱动,一般平台商提供这部分驱动。I2C Client driver是具体的外设驱动,我们一般关心的是这部分代码。

 

    2. I2C 设备驱动框架图

        以下是I2C框架流程图:

       

    3. I2C 驱动相关接口函数

         (1). I2C注册、注销函数

                static inline int i2c_add_driver(struct i2c_driver *driver);       /* 注册一个I2C设备驱动 */

                void i2c_del_driver(struct i2c_driver *driver);                           /* 注销一个I2C设备驱动 */

                int __init i2c_register_board_info(int busnum, struct i2c_board_info const *info, unsigned len);  //注册I2C设备板级信息。

         (2). I2C读写数据函数

                a. 接收(read)数据函数

                    //接收一个字节,寄存器为上次发送的地址。

                    s32 i2c_smbus_read_byte(const struct i2c_client *client);   

                    //从具体I2C设备的寄存器中读一个字节,command表示寄存器地址。      

                    s32 i2c_smbus_read_byte_data(const struct i2c_client *client, u8 command);      

                    //从具体I2C设备的寄存器中读2个字节,command表示寄存器地址。 

                    s32 i2c_smbus_read_word_data(const struct i2c_client *client, u8 command);    

                    //从具体I2C设备的寄存器中读一段数据, command表示寄存器地址。

                    s32 i2c_smbus_read_block_data(const struct i2c_client *client, u8 command, u8 *values);

                b. 发送(write)数据函数

                    //向具体外设发送一个字节,寄存器为上次发送的地址。

                    s32 i2c_smbus_write_byte(const struct i2c_client *client, u8 value);

                    //向具体寄存器发送一个字节。

                    s32 i2c_smbus_write_byte_data(const struct i2c_client *client, u8 command, u8 value);

                    //向具体寄存器发送2个字节。

                    s32 i2c_smbus_write_word_data(const struct i2c_client *client, u8 command, u16 value);

                    //向具体寄存器发送一段数据。

                    s32 i2c_smbus_write_block_data(const struct i2c_client *client, u8 command, u8 length, const u8 *values);

    4. I2C 驱动相关数据结构

         struct i2c_board_info {
                    char  type[I2C_NAME_SIZE];
                    unsigned short flags;
                    unsigned short addr;
                    void  *platform_data;
                    struct dev_archdata *archdata;
                    struct device_node *of_node;
                    int  irq;
          };

          I2C 设备信息数据结构,蓝色的type与addr成员必须初始化具体的值,其中type是具体的设备名称,addr是I2C地址。

        注意:addr=chip_address>>1,意思就是addr是实际I2C地址的高7位。

         struct i2c_driver {
                   unsigned int class;

                   int (*attach_adapter)(struct i2c_adapter *) __deprecated;
                   int (*detach_adapter)(struct i2c_adapter *) __deprecated;

                   /* 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 *);

                   void (*alert)(struct i2c_client *, unsigned int data);

                   int (*command)(struct i2c_client *client, unsigned int cmd, void *arg);

                   struct device_driver driver;
                   const struct i2c_device_id *id_table;

                   int (*detect)(struct i2c_client *, struct i2c_board_info *);
                   const unsigned short *address_list;
                   struct list_head clients;
         };

         I2C 驱动相关数据结构,我们通常要实现此结构体的蓝色部分标示的成员。
               
driver:驱动名称
                id_table:此驱动支持的设备ID表
         4个函数指针:
               
probe: 驱动的侦测函数接口,由总线控制器驱动调用。
                remove: 卸载驱动的函数接口。
                suspend: 休眠函数接口,用于节省电能等场合。
                resume: 唤醒函数接口,使从休眠中醒来。
                如果没有实现相应函数的功能,那置为NULL值即可。

 

    5. I2C 例子驱动及实现代码

         (1). 包含头文件

                #include  <linux/i2c.h>

         (2). 定义及实现probe函数,比如:

               int akm8975_probe(struct i2c_client *client, const struct i2c_device_id *id)

         (3). 定义及实现remove函数

               static int akm8975_remove(struct i2c_client *client)

          (4). 定义及初始化i2c_device_id

                 static const struct i2c_device_id akm8975_id[]= {
                           {"akm8975", 0 },
                           { }
                  };

          (5). 定义及初始化i2c_driver数据结构

                static struct i2c_driver akm8975_driver = {
                           .probe  = akm8975_probe,
                           .remove  = akm8975_remove,
                           .id_table = akm8975_id,
                           .driver = {
                                     .name = "akm8975", 

                            },
                };

           (6). 在模块初始化函数中调用 i2c_add_driver 把I2C驱动加入I2C子系统

                  static int __init akm8975_init(void)
                  {
                           return i2c_add_driver(&akm8975_driver);
                  }

           (7). 在模块卸载函数中调用i2c_del_driver删掉I2C驱动

                  static void __exit akm8975_exit(void)
                  {
                          i2c_del_driver(&akm8975_driver);
                  }

           (8). 定义及初始化i2c_board_info

                 static struct i2c_board_info akm8975_i2c_info[] __initdata = {
                          {
                                   I2C_BOARD_INFO("akm8975", 0x0e),
                                   .platform_data =  &akm_platform_data_8975,
                                   .flags = I2C_CLIENT_WAKE,

                          },
                  };

           (9). 调用函数i2c_register_board_info注册i2c_board_info到系统

                  i2c_register_board_info(MSM_GSBI1_QUP_I2C_BUS_ID, akm8975_i2c_info, ARRAY_SIZE(akm8975_i2c_info));

 

          
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值