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