arm+i2c+linux,ARM-Linux s3c2440 之I2C分析

原标题:ARM-Linux s3c2440 之I2C分析

内核版本linux-2.6.30.4

I2C在 中是Bus下的一个子系统. 它由客户驱动(client driver),i2c-core核心,i2c适配器驱动(adapter driver) ,算法aglorithm组成。 中有两个i2c现适配器.作为platform_device设备在系统启动先时被注册和添加。下面我们分析i2c(设备,驱动, )的实现过程.

//填充设备资源

//struct resource结构体描述了挂接在cpu总线上的设备实体资源

//.start:i2c寄存器起始地址; .end:i2c寄存器结束地址; .flag:描述设备实体的共性和特性标志

static struct resource s3c_i2c_resource[] = {

[0] = {//i2c-0

.start = S3C_PA_IIC,

.end = S3C_PA_IIC + SZ_4K - 1,

.flags = IORESOURCE_MEM,

},

[1] = {//i2c-1

.start = IRQ_IIC,

.end = IRQ_IIC,

.flags = IORESOURCE_IRQ,

},

};

/i2c适配器初始化时数据

static struct s3c2410_platform_i2c default_i2c_data0 __initdata = {

.flags = 0,

.slave_addr = 0x10,

.frency = 100*1000,

.sda_delay = 100,

};

//声明i2c适配器为platform_device

struct platform_device s3c_device_i2c0 = {

.name = "s3c2410-i2c",

#ifdef CONFIG_S3C_DEV_I2C1

.id = 0,

#else

.id = -1,

#endif

.num_resources = ARRAY_SIZE(s3c_i2c_resource),

.resource = s3c_i2c_resource,

};

static struct s3c2410_platform_i2c default_i2c_data0 __initdata = {

.flags = 0,

.slave_addr = 0x10,

.frequency = 100*1000,

.sda_delay = 100,

};

//添加i2c适配器:

static struct platform_device *smdk2440_devices[] __initdata = {

...

&s3c_device_i2c0,

...

};

//添加plat_from_data

void __init s3c_i2c0_set_platdata(struct s3c2410_platform_i2c *pd)

{

struct s3c2410_platform_i2c *npd;

if (!pd)

pd = &default_i2c_data0;

npd = kmemdup(pd, sizeof(struct s3c2410_platform_i2c), GFP_KERNEL);

if (!npd)

printk(KERN_ERR "%s: no memory for platform data\n", __func__);

else if (!npd->cfg_gpio)

npd->cfg_gpio = s3c_i2c0_cfg_gpio; //i2c引脚配置

s3c_device_i2c0.dev.platform_data = npd; //挂接plat_form_data数据

}

//定义好上面相关结构后,在smdk2440_machine_init()中被注册和添加成platform_device

static void __init smdk2440_machine_init(void)

{

s3c24xx_fb_set_platdata(&smdk2440_fb_info);

s3c_i2c0_set_platdata(NULL);

...

//注册和添加platform_device

platform_add_devices(smdk2440_devices, ARRAY_SIZE(smdk2440_devices));

...

}

其中 smdk2440_machine_init在被赋值在MACHINE_START中

在start_kernel()-->setup_arch()时被调用,但值得注意的是i2c适配器并没有被初始化,因为还没有驱动!

通过下面可以知道platform_device_register()和device_register()的区别:

platform_add_devices()-->platform_device_register()-->

platform_device_add()--> device-->add()

platfrom_bus_init()时也将添加一个名叫platform的设备(struct device platform_bus):

plat_form_bus_init()-->device_register()-->device_register()

-->device-->add()

但这个设备是虚拟的,所有platform_device_add()后的设备都是在/devices/platform/下

因为所有plaform_device 的父母亲都是platform_bus,是在platform_device_add()中

if (!pdev->dev.parent)

pdev->dev.parent = &platform_bus;

我想这也就是platform_device_register()和device_register()区别吧

在reset_init()-->kernel_init()-->do_basic_setup()

-->driver_init()-->platform_bus_init()完成platform_bus总线的注册

但是现在i2c适配器并没有和驱动绑上,因为到系现在为止驱动还没有出现呢(初始化)

只有做好前面一些的准备功夫,i2c适配器驱动才能初始化,这个是需要按照顺序来的。

s3c2440-i2c适配器驱动的初始化在drivers/i2c/bus/i2c-s3c2410.c中实现

并且作为platform_driver注册。

//填充driver结构并完成相应probe,remove等函数

static struct platform_driver s3c2440_i2c_driver = {

.probe = s3c24xx_i2c_probe,

.remove = s3c24xx_i2c_remove,

.suspend_late = s3c24xx_i2c_suspend_late,

.resume = s3c24xx_i2c_resume,

.driver = {

.owner = THIS_MODULE,

.name = "s3c2440-i2c", //

},

};

//初始化并注册platform_driver

static int __init i2c_adap_s3c_init(void)

{

int ret;

ret = platform_driver_register(&s3c2410_i2c_driver);//

if (ret == 0) {

printk("register s3c2440_i2c_driver.....\n");

ret = platform_driver_register(&s3c2440_i2c_driver);

if (ret)

{

printk("register s3c2410_i2c_driver.....\n");

platform_driver_unregister(&s3c2410_i2c_driver);

}

}

return ret;

}

subsys_initcall(i2c_adap_s3c_init);

这样适配器就和驱动绑定上了,过程是这样的:

platform_driver_register()-->driver_register()-->bus_add_driver()-->driver_attach()

__driver_attach()-->driver_probe_device()-->s3c24xx_i2c_probe()

并且在s3c24xx_i2c_probe()的时候调用

i2c_add_numbered_adapter(&i2c->adap);

最后添加自己为i2c总线的适配器。这样分析过程也就结束了。

责任编辑:

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值