linux i2c子系统代码分析7 ---i2c适配器注册时机、方法以及例程

i2c适配器注册时机:

1、在paltform驱动中注册,在板级初始化时注册一个platform设备,然后在注册platform驱动时将i2c适配器注册。

这种方法属于适配器静态注册,是soc中i2c适配器通用注册方法,因为这样保证后续的i2c驱动注册以及i2c设备注册能找到匹配的适配器,i2c驱动和i2c设备注册在i2c适配器注册之后。

2、加载一个内核模块,在模块中完成i2c适配器注册,该方法是适配器动态注册,注意必须保证i2c驱动和i2c设备注册在i2c适配器注册之后

 

i2c适配器代表i2c外设,因此其要先与i2c驱动和设备注册

 

 

 

i2c适配注册方法、例程

1、内核模块的方法注册

下面简单例程,以说明情况为主,不做i2c适配器算法具体实现

 

#define DEBUG
#include <linux/module.h>
#include <linux/errno.h>
#include <linux/miscdevice.h>
#include <linux/fcntl.h>
#include <linux/i2c.h>

#include <linux/device.h>
#include <linux/init.h>
#include <linux/delay.h>
#include <linux/proc_fs.h>
#include <linux/workqueue.h>
#include <linux/interrupt.h>
#include <linux/spinlock.h>


#include <asm/uaccess.h>
#include <asm/system.h>
#include <asm/io.h>

int GpioI2cDataOpt(struct i2c_adapter *adapter,struct i2c_msg *msg,int num)
{
 printk("do a GpioI2cDataOpt\n");
 return 1;
}

struct i2c_algorithm GpioI2cOpt=
{
 .master_xfer=GpioI2cDataOpt

};

struct i2c_adapter SocI2cAdapter=
{
 .owner=THIS_MODULE,
 .algo=&GpioI2cOpt,
 .name="SocI2cAdapter"
};


static int __init I2cAdapterInit(void)
{
 i2c_add_adapter(&SocI2cAdapter);
 return 0;
}

static void __exit I2cAdapterExit(void)
{
 i2c_del_adapter(&SocI2cAdapter);

}

 

module_init(I2cAdapterInit);
module_exit(I2cAdapterExit);

MODULE_AUTHOR("xxxx");
MODULE_DESCRIPTION("xxx i2c adapter register");
MODULE_LICENSE("GPL");

 

 

关键在于struct i2c_adapter 结构体实例化以及i2c_algorithm   .master_xfer实例化

 i2c_add_adapter是动态分配总线号的注册方法。

 

 

 

2、platform平台总线驱动注册方式

 

platform总线是虚拟总线,cpu能直接通过总线访问的外设和模块设备挂载到该总线上。platform设备在arch_init阶段被注册,paltform驱动一般不动态加载而是编译进内核,从而来初始化soc外设设备。

1、注册platfrom设备

在kernel/arch/arm/mach-xxx/core.c中

 

static struct platform_device I2cDev=
{
 .name="I2cDev",
 .id=-1,
}; 

定义一个名为I2cDev的platform设备。

然后找到平台初始化函数

MACHINE_START(xxx, "xxx")
 .boot_params    = PLAT_PHYS_OFFSET + 0x100,
 .map_io         = xxx_map_io,
 .init_irq       = xxx_gic_init_irq,
 .timer          = &xxx_timer,
 .init_machine   = xxx_init,
MACHINE_END

.init_machine   = xxx_init,  为平台初始化函数

 

void __init xxx_init(void)
{
 xxxx

 platform_device_register(&I2cDev);
xxx

}

 platform_device_register(&I2cDev);  注册I2cDev platform设备到platform总线,此时驱动还没有注册,因此不会执行probe

 

 

2、注册platform驱动

因为platform驱动是为了初始化i2c外设,所以该驱动在内核目录为kernel/drivers/i2c/busses/下

建立一个i2c-Gpio.c驱动文件

#include <linux/kernel.h>
#include <linux/module.h>

#include <linux/i2c.h>
#include <linux/init.h>
#include <linux/time.h>
#include <linux/interrupt.h>
#include <linux/delay.h>
#include <linux/errno.h>
#include <linux/err.h>
#include <linux/platform_device.h>
#include <linux/clk.h>
#include <linux/cpufreq.h>
#include <linux/slab.h>
#include <linux/io.h>
#include <asm/irq.h>

int GpioI2cDataOpt(struct i2c_adapter *adapter,struct i2c_msg *msg,int num)
{
 printk("do a GpioI2cDataOpt\n");
 return 1;
}

struct i2c_algorithm GpioI2cOpt=
{
 .master_xfer=GpioI2cDataOpt

};

struct i2c_adapter GpioI2cAdapter=
{
 .owner=THIS_MODULE,
 .nr=1,
 .algo=&GpioI2cOpt,
 .name="GpioI2cAdapter"
};

static int xxx_i2c_probe(struct platform_device *pdev)
{
 i2c_add_numbered_adapter(&GpioI2cAdapter);
 return 0;

}
static int xxx_i2c_remove(struct platform_device *pdev)
{

 i2c_del_adapter(&GpioI2cAdapter);
 return 0;

}
static struct platform_driver I2cDevDriver = {
 .probe  = xxx_i2c_probe,
 .remove  = xxx_i2c_remove,
 .driver  = {
  .owner = THIS_MODULE,
  .name = "I2cDev",
 },
};

static int __init I2cDevInit(void)
{
 return platform_driver_register(&I2cDevDriver);
}
subsys_initcall(I2cDevInit);

static void __exit I2cDevExit(void)
{
 platform_driver_unregister(&I2cDevDriver);
}
module_exit(I2cDevExit);

MODULE_DESCRIPTION("xxx I2C Dev driver");
MODULE_AUTHOR("xxx");
MODULE_LICENSE("GPL");

 

关键在i2c_probe函数,该函数实现i2c适配器的注册功能。

 


 

 


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值