linux下I2c框架分析之终端设备(三)

linux下I2c框架分析之终端设备(三)
平台:君正x1000
内核:Linux3.5
经过前面两篇文章已经知道了i2c框架的大概结构和适配器注册,现在分析i2c终端设备的驱动,作为普通的驱动工程师,一般都是拿着已有的驱动修改适配产品的sensor,这就是修改的终端驱动了,对咱们也是很重要。

此时要关注一个关键的已经实例化的结构
I2c总线
i2c终端设备和驱动都挂载在它下面,match不断扫描device和driver两个链表进行匹配,在 /sys/bus/能看到这个i2c

struct bus_type i2c_bus_type = {    /*   \drivers\i2c\i2c-core.c  */
	.name		= "i2c",
	.match		= i2c_device_match, /* 匹配设备名和驱动名 */
	.probe		= i2c_device_probe, /* 匹配成功执行驱动probe函数 */
	.remove		= i2c_device_remove,
	.shutdown	= i2c_device_shutdown,
	.pm		= &i2c_device_pm_ops,
};

i2c终端的实例化使用i2c_board_info结构描述

struct i2c_board_info {    /*  \include\linux\i2c.h  */
	char		type[I2C_NAME_SIZE];		// 设备名
	unsigned short	flags;
	unsigned short	addr;	//地址
	void		*platform_data;
	struct dev_archdata	*archdata;
	struct device_node *of_node;
	struct acpi_dev_node acpi_node;
	int		irq;  //中断号
};

板级文件中使用I2C_BOARD_INFO初始化type和addr

#define I2C_BOARD_INFO(dev_type, dev_addr) \
	.type = dev_type, .addr = (dev_addr)

注册i2c终端设备
注册i2c终端设备有两种方法
方法一:
静态注册,使用此函数申请I2C设备信息结构体,将I2C总线号和设备信息赋值给设备信息结构体,并且将设备信息结构体的链表插入到__i2c_board_list中

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);
	...
		}
		devinfo->busnum = busnum;
		devinfo->board_info = *info;
		list_add_tail(&devinfo->list, &__i2c_board_list);
	}
	up_write(&__i2c_board_lock);
	return status;
}

还记得linux下I2c框架分析之适配器(二)中最后i2c_register_adapter接口实现吗

static int i2c_register_adapter(struct i2c_adapter *adap)
{        /*   \drivers\i2c\i2c-core.c   */
exit_recovery:
	/* create pre-declared device nodes */
	if (adap->nr < __i2c_first_dynamic_bus_num)
		//   扫描__i2c_board_list链表上挂接的所有的i2c次设备信息并与适配器进行匹配,匹配成功创建i2c次设备
		i2c_scan_static_board_info(adap); 
	.......
	return 0;
}

当终端设备插入到链表后就等待i2c_register_adapter函数注册适配器时调用i2c_scan_static_board_info(adap)函数通过遍历__i2c_board_list链表找到注册的设备,调用i2c_new_device函数把链表中的每个成员构造成一个i2c_client。

struct i2c_client *i2c_new_device(struct i2c_adapter *adap, struct i2c_board_info const *info)
{	/*  \drivers\i2c\i2c-core.c */
    struct i2c_client	*client;
    client->adapter = adap; // 设定设备的设配器
    client->addr = info->addr; // 地址
    client->irq = info->irq; // 中断号
    client->dev.bus = &i2c_bus_type; // 绑定总线
    device_register(&client->dev); // 向总线注册设备
    return client;
}
int device_register(struct device *dev)
{	/*  \drivers\base\core.c */
	device_initialize(dev);
	return device_add(dev);
}
int device_add(struct device *dev)
{	/*  \drivers\base\core.c */
    bus_add_device(dev);
    bus_probe_device(dev);
}
int bus_add_device(struct device *dev)
{ 	/*  \drivers\base\bus.c */
    /* 将设备添加到总线的设备链表中(bus->p->klist_devices) */
    klist_add_tail(&dev->p->knode_bus, &bus->p->klist_devices);
}
void bus_probe_device(struct device *dev)
{
	device_attach(dev);
}
int device_attach(struct device *dev)
{ /* \drivers\base\dd.c  将设备附加到驱动*/
    bus_for_each_drv(dev->bus, NULL, dev, __device_attach);
}
int bus_for_each_drv(struct bus_type *bus, struct device_driver *start,
		     void *data, int (*fn)(struct device_driver *, void *))
{	 /* \drivers\base\bus.c */
    /* 遍历总线的驱动链表上的所有驱动,调用fn函数指向__device_attach */
	while ((drv = next_driver(&i)) && !error)
		error = fn(drv, data);
}
static int __device_attach(struct device_driver *drv, void *data)
{
	struct device *dev = data;
	if (!driver_match_device(drv, dev))
		return 0;
	return driver_probe_device(drv, dev);
}

终端设备的注册咱们暂且先分析这,剩下的函数调用放到驱动中分析更合适明了;
方法二
从用户空间创建设备(详细阅读/Documentation/i2c/instantiating-devices文档)
执行命令cd /sys/class/i2c-adapter/,可以看到内容i2c-0 i2c-1 i2c-2,说明有多款适配器
< 做下面实验需要把内核中静态编译进的drv驱动给去掉,然后加载自己的drv驱动>
创建设备
echo at24c08 0x50 > /sys/class/i2c-adapter/i2c-0/new_device,导致i2c_new_device被调用,最后drv里的probe 函数就不会被调用。如果把地址改为0x51,那么也会在bus的dev链表中增加一个dev结构,所以这种方法也是不会判断地址是否正确。
删除设备
echo 0x50 > /sys/class/i2c-adapter/i2c-0/delete_device,导致i2c_unregister_device。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值