Chinaunix首页 | 论坛 | 博客
  • 博客访问: 2294060
  • 博文数量: 393
  • 博客积分: 0
  • 博客等级: 民兵
  • 技术积分: 4178
  • 用 户 组: 普通用户
  • 注册时间: 2016-07-04 13:04
文章分类

全部博文(393)

文章存档

2020年(8)

2019年(24)

2018年(135)

2017年(158)

2016年(68)

我的朋友

分类: 嵌入式

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加入板级信息链表中

阅读(471) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~