全部博文(396)
分类: 嵌入式
2018-09-07 21:06:16
下面介绍i2c设备操作相关函数
1、
kernel/driver/linux/i2c/i2c-core.c
struct i2c_client *
i2c_new_device(struct i2c_adapter *adap, struct i2c_board_info const *info) i2c适配器静态增加新i2c设备,根据 i2c_board_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;
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;
client->dev.of_node = info->of_node;
dev_set_name(&client->dev, "%d-%04x", i2c_adapter_id(adap),
client->addr);
status = device_register(&client->dev);
if (status)
goto out_err;
dev_dbg(&adap->dev, "client [%s] registered with bus id %s\n",
client->name, dev_name(&client->dev));
return client;
out_err:
dev_err(&adap->dev, "Failed to register i2c client %s at 0x%02x "
"(%d)\n", client->name, client->addr, status);
out_err_silent:
kfree(client);
return NULL;
}
client->adapter = adap; 给i2c设备设置适配器
client->dev.platform_data = info->platform_data;
client->dev.archdata = *info->archdata;
client->flags = info->flags;
client->addr = info->addr;
client->irq = info->irq;
上面是利用i2c板级信息给i2c设备赋值
strlcpy(client->name, info->type, sizeof(client->name)); 设置设备名称
i2c_check_client_addr_validity(client); 检查地址有效性
i2c_check_addr_busy(adap, client->addr); 检查设备地址是否和其他冲突
client->dev.parent = &client->adapter->dev;
client->dev.bus = &i2c_bus_type;
client->dev.type = &i2c_client_type;
client->dev.of_node = info->of_node;
上面是给i2c设备驱动模型的设备赋值
dev_set_name(&client->dev, "%d-%04x", i2c_adapter_id(adap),client->addr); 给设备驱动模型设备设置名称,名称是总线号以及设备地址组合
device_register(&client->dev); 注册设备到设备驱动模型
2、i2c_new_probed_device i2c适配器在不知道i2c设备地址情况下,探测该设备,然后依据i2c_board_info添加i2c设备
kernel/driver/linux/i2c/i2c-core.c
struct i2c_client *
i2c_new_probed_device(struct i2c_adapter *adap,
struct i2c_board_info *info,
unsigned short const *addr_list,
int (*probe)(struct i2c_adapter *, unsigned short addr))
{
int i;
if (!probe)
probe = i2c_default_probe;
for (i = 0; addr_list[i] != I2C_CLIENT_END; i++) {
/* Check address validity */
if (i2c_check_addr_validity(addr_list[i]) < 0) {
dev_warn(&adap->dev, "Invalid 7-bit address "
"0x%02x\n", addr_list[i]);
continue;
}
/* Check address availability */
if (i2c_check_addr_busy(adap, addr_list[i])) {
dev_dbg(&adap->dev, "Address 0x%02x already in "
"use, not probing\n", addr_list[i]);
continue;
}
/* Test address responsiveness */
if (probe(adap, addr_list[i]))
break;
}
if (addr_list[i] == I2C_CLIENT_END) {
dev_dbg(&adap->dev, "Probing failed, no device found\n");
return NULL;
}
info->addr = addr_list[i];
return i2c_new_device(adap, info);
}
f (!probe)
probe = i2c_default_probe; 如果没有probe函数就用默认的探测函数,i2c_default_probe是smbus协议探测函数。
for (i = 0; addr_list[i] != I2C_CLIENT_END; i++) 循环探测地址
i2c_check_addr_validity 检查地址有效性
i2c_check_addr_busy 检查地址是否被占用
probe(adap, addr_list[i]) 探测该地址设备
info->addr = addr_list[i]; 给板级信息赋地址值
i2c_new_device(adap, info); 注册该i2c设备
3、i2c_register_board_info 静态声明i2c设备
kernel/driver/linux/i2c/i2c-boardinfo.c
/**
* i2c_register_board_info - statically declare I2C devices
* @busnum: identifies the bus to which these devices belong
* @info: vector of i2c device descriptors
* @len: how many descriptors in the vector; may be zero to reserve
* the specified bus number.
*
* Systems using the Linux I2C driver stack can declare tables of board info
* while they initialize. This should be done in board-specific init code
* near arch_initcall() time, or equivalent, before any I2C adapter driver is
* registered. For example, mainboard init code could define several devices,
* as could the init code for each daughtercard in a board stack.
*
* The I2C devices will be created later, after the adapter for the relevant
* bus has been registered. After that moment, standard driver model tools
* are used to bind "new style" I2C drivers to the devices. The bus number
* for any device declared using this routine is not available for dynamic
* allocation.
*
* The board info passed can safely be __initdata, but be careful of embedded
* pointers (for platform_data, functions, etc) since that won't be copied.
*/
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);
}
up_write(&__i2c_board_lock);
return status;
}
down_write(&__i2c_board_lock); 写信号量
if (busnum >= __i2c_first_dynamic_bus_num)
__i2c_first_dynamic_bus_num = busnum + 1; 为了保证总线号唯一,动态设备号要大于静态设备号
for (status = 0; len; len--, info++) 将所有i2c_board_info加入板级信息链表
struct i2c_devinfo {
struct list_headlist;
int busnum;
struct i2c_board_infoboard_info;
};
list_add_tail(&devinfo->list, &__i2c_board_list); 将devinfo加入板级信息链表中