I2C设备驱动流程

来源:互联网 发布:ubuntu vim使用 编辑:程序博客网 时间:2024/04/30 02:04
 

I2C设备驱动流程

一、I2C设备驱动流程

1) i2c_register_board_info定义I2C器件信息(Name,Address,etc.

static struct i2c_board_info __initdata pi2c_board_info[] = {

       {

              I2C_BOARD_INFO("max1586", 0x14),

              .platform_data = &max1587a_info,

       },

};

 

i2c_register_board_info(1, ARRAY_AND_SIZE(pi2c_board_info));

/* 1表示该I2C设备挂在I2C-1上 ,注册I2C adapt时相应的id = 1 */

 

/* i2c */

static struct i2c_gpio_platform_data i2c_bus_data = {

       .sda_pin = VIPER_RTC_I2C_SDA_GPIO,

       .scl_pin = VIPER_RTC_I2C_SCL_GPIO,

       .udelay  = 10,

       .timeout = HZ,

};

 

static struct platform_device i2c_bus_device = {

       .name          = "i2c-gpio",

       .id         = 1,   /* /sys/class/i2c-adapt/i2c-1  */

       .dev = {

              .platform_data = &i2c_bus_data,

       }

};

 

将I2C器件信息注册到I2C的器件列表中:

struct i2c_devinfo {

       struct list_head list;                   /* 双向链表   */

       int                busnum;

       struct i2c_board_info     board_info;     /* i2c器件信息 */

};

 

int __init

i2c_register_board_info(int busnum,

       struct i2c_board_info const *info, unsigned len)

{

       int status;

       down_write(&__i2c_board_lock);

 

       /* dynamic bus numbers will be assigned after the last static one */

       if (busnum >= __i2c_first_dynamic_bus_num)

              __i2c_first_dynamic_bus_num = busnum + 1;

       for (status = 0; len; len--, info++) {

              struct i2c_devinfo   *devinfo;

              devinfo = kzalloc(sizeof(*devinfo), GFP_KERNEL);

              if (!devinfo) {

                     pr_debug("i2c-core: can't register boardinfo!/n");

                     status = -ENOMEM;

                     break;

              }

 

              devinfo->busnum = busnum;

              devinfo->board_info = *info;

              list_add_tail(&devinfo->list, &__i2c_board_list);

              /* 加入__i2c_board_list 链表中 */

       }

       up_write(&__i2c_board_lock);

       return status;

}

 

2) 注册I2C device

i2c_register_adapter -> i2c_scan_static_board_info -> i2c_new_device

struct i2c_client *

i2c_new_device(struct i2c_adapter *adap, struct i2c_board_info const *info)

{

       struct i2c_client       *client;

       int                status;

       client = kzalloc(sizeof *client, GFP_KERNEL);

       if (!client)

              return NULL;

       client->adapter = adap;

       client->dev.platform_data = info->platform_data;

       if (info->archdata)

              client->dev.archdata = *info->archdata;

 

       client->flags = info->flags;

       client->addr = info->addr;   /* 取得I2C器件地址 */

       client->irq = info->irq;

       strlcpy(client->name, info->type, sizeof(client->name));

 

       /* Check for address validity */

       status = i2c_check_client_addr_validity(client);

       if (status) {

              dev_err(&adap->dev, "Invalid %d-bit I2C address 0x%02hx/n",

                     client->flags & I2C_CLIENT_TEN ? 10 : 7, client->addr);

              goto out_err_silent;

       }

       /* Check for address business */

       status = i2c_check_addr_busy(adap, client->addr);

       if (status)

              goto out_err;

       client->dev.parent = &client->adapter->dev;

       client->dev.bus = &i2c_bus_type;

       client->dev.type = &i2c_client_type;

 

       dev_set_name(&client->dev, "%d-%04x", i2c_adapter_id(adap),

                   client->addr);

       status = device_register(&client->dev);   /* 注册器件 */

       if (status)

              goto out_err;

    …

}

 

3) I2C读写

static inline int pm860x_read_device(struct i2c_client *i2c,

                                 int reg, int bytes, void *dest)

{

       unsigned char data;

       int ret;

       data = (unsigned char)reg;

       ret = i2c_master_send(i2c, &data, 1);  /* 写地址 */

       if (ret < 0)

              return ret;

       ret = i2c_master_recv(i2c, dest, bytes);  /* 读数据 */

       if (ret < 0)

              return ret;

       return 0;

}

 

static inline int pm860x_write_device(struct i2c_client *i2c,

                                  int reg, int bytes, void *src)

{

       unsigned char buf[bytes + 1];

       int ret;

       buf[0] = (unsigned char)reg;

       memcpy(&buf[1], src, bytes);

       ret = i2c_master_send(i2c, buf, bytes + 1);  /* 写地址&数据 */

       if (ret < 0)

              return ret;

       return 0;

}

 

/* i2c-core.c 函数 */

int i2c_master_send(struct i2c_client *client, const char *buf, int count)

{

       int ret;

       struct i2c_adapter *adap = client->adapter;

       struct i2c_msg msg;

       msg.addr = client->addr;  /*  I2C器件地址 */

       msg.flags = client->flags & I2C_M_TEN;

       msg.len = count;

       msg.buf = (char *)buf;

       ret = i2c_transfer(adap, &msg, 1);

 

       /* If everything went ok (i.e. 1 msg transmitted), return #bytes

          transmitted, else error code. */

       return (ret == 1) ? count : ret;

}

 

int i2c_master_recv(struct i2c_client *client, char *buf, int count)

{

       struct i2c_adapter *adap = client->adapter;

       struct i2c_msg msg;

       int ret;

       msg.addr = client->addr;

       msg.flags = client->flags & I2C_M_TEN;

       msg.flags |= I2C_M_RD;

       msg.len = count;

       msg.buf = buf;

       ret = i2c_transfer(adap, &msg, 1);

 

       /* If everything went ok (i.e. 1 msg transmitted), return #bytes

          transmitted, else error code. */

       return (ret == 1) ? count : ret;

}

 

 

 

 

二、I2C时序

1)  START/STOP时序

 

 

2)  I2C器件地址结构(bit7~Bit1)

 

 

FIXME:”1” Read, “0” Write

3) 字节写

START + ( Device address +W ) + (Register Address) + (Data) + STOP

 

4) 多字节写

 

5) *读操作

 

START + (Device Address + w) + (Register Address) +RESTART + (Device Address + R) +(Data) +STOP

0 0
原创粉丝点击