linux i2c 架构,linux之i2c子系统架构

20180110182318147847.png

总线驱动

4.1 概述

I2C总线驱动是I2C适配器的软件实现,提供I2C适配器与从设备间完成数据通信的能力,比如起始,停止,应答信号和master_xfer的实现函数。

I2C总线驱动由i2c_adapter和i2c_algorithm来描述

4.2 S3c2440I2C控制器的硬件描述

S3c2440处理器内部集成了一个I2C控制器,通过四个寄存器来进行控制:

IICCON     I2C控制寄存器

IICSTAT     I2C状态寄存器

IICDS       I2C收发数据移位寄存器

IICADD     I2C地址寄存器

通过IICCON,IICDS,IICADD寄存器操作,可在I2C总线上产生开始位、停止位、数据和地址,而传输的状态则通过IICSTAT寄存器来获取。

4.3 i2c-s3c2410总线驱动分析(platform_driver)

I2C总线驱动代码在drivers/i2c/busses/i2c-s3c2410.c,这个代码同样支持s3c2410,s3c6410,s5pc110等Samsung 系列的芯片。

初始化模块和卸载模块

static int __init i2c_adap_s3c_init(void)

{

returnplatform_driver_register(&s3c24xx_i2c_driver);

}

static void __exit i2c_adap_s3c_exit(void)

{

platform_driver_unregister(&s3c24xx_i2c_driver);

}

总线驱动是基于platform来实现的,很符合设备驱动模型的思想。

static struct platform_drivers3c24xx_i2c_driver = {

.probe                = s3c24xx_i2c_probe,

.remove            = s3c24xx_i2c_remove,

.id_table  = s3c24xx_driver_ids,

.driver                = {

.owner     = THIS_MODULE,

.name       = "s3c-i2c",

.pm  = S3C24XX_DEV_PM_OPS,

.of_match_table= s3c24xx_i2c_match,

},

};

s3c24xx_i2c_probe函数

当调用platform_driver_register函数注册platform_driver结构体时,如果platformdevice 和 platform driver匹配成功后,会调用probe函数,来初始化适配器硬件。

static int s3c24xx_i2c_probe(structplatform_device *pdev)

{

……

/*初始化适配器信息 */

strlcpy(i2c->adap.name,"s3c2410-i2c", sizeof(i2c->adap.name));

i2c->adap.owner   = THIS_MODULE;

i2c->adap.algo    = &s3c24xx_i2c_algorithm;

i2c->adap.retries= 2;

i2c->adap.class   = I2C_CLASS_HWMON | I2C_CLASS_SPD;

i2c->tx_setup     = 50;

/*初始化自旋锁和等待队列头 */

spin_lock_init(&i2c->lock);

init_waitqueue_head(&i2c->wait);

/*映射寄存器 */

res= platform_get_resource(pdev, IORESOURCE_MEM, 0);

i2c->ioarea= request_mem_region(res->start, resource_size(res),

pdev->name);

i2c->regs= ioremap(res->start, resource_size(res));

/*设置I2C核心需要的信息 */

i2c->adap.algo_data= i2c;

i2c->adap.dev.parent= &pdev->dev;

/*初始化I2C控制器 */

ret= s3c24xx_i2c_init(i2c);

/*申请中断 */

i2c->irq= ret = platform_get_irq(pdev, 0);

ret= request_irq(i2c->irq, s3c24xx_i2c_irq, 0,

dev_name(&pdev->dev), i2c);

/* 注册I2C适配器 */

ret= i2c_add_numbered_adapter(&i2c->adap);

……

}

Probe主要工作是时能硬件并申请I2C适配器使用的IO地址,中断号等,然后向I2C核心添加这个适配器。I2c_adapter注册过程i2c_add_numbered_adapter->i2c_register_adapter

I2C总线通信方法

static const struct i2c_algorithms3c24xx_i2c_algorithm = {

.master_xfer             = s3c24xx_i2c_xfer,

.functionality             = s3c24xx_i2c_func,

};

s3c24xx_i2c_xfer函数是总线通信方式的具体实现,依赖于s3c24xx_i2c_doxfer和s3c24xx_i2c_message_start两个函数;

static int s3c24xx_i2c_doxfer(structs3c24xx_i2c *i2c,

struct i2c_msg *msgs, int num)

{

ret =s3c24xx_i2c_set_master(i2c);

i2c->msg     = msgs;

i2c->msg_num= num;

i2c->msg_ptr= 0;

i2c->msg_idx= 0;

i2c->state   = STATE_START;

s3c24xx_i2c_message_start(i2c,msgs);

}

首先设置s3c I2C设备器为主设备,然后调用s3c24xx_i2c_message_start函数启动I2C消息传输。

s3c24xx_i2c_func函数返回适配器所支持的通信功能。

4.4 适配器的设备资源(platform_device)

S3c2440的I2C总线驱动是基于platform来实现,前面我们分析了platformdriver部分,再来看下platform device部分。

在arch/arm/plat-samsung/dev-i2c0.c文件中定义了platform_device结构体以及I2C控制器的资源信息:

static struct resource s3c_i2c_resource[] ={

[0]= {

.start= S3C_PA_IIC,

.end   = S3C_PA_IIC + SZ_4K - 1,

.flags= IORESOURCE_MEM,

},

[1]= {

.start= IRQ_IIC,

.end  = IRQ_IIC,

.flags= IORESOURCE_IRQ,

},

};

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,

};

struct s3c2410_platform_i2cdefault_i2c_data __initdata = {

.flags                  = 0,

.slave_addr      = 0x10,  /* I2C适配器的地址 */

.frequency        = 100*1000,  /* 总线频率 */

.sda_delay        = 100,   /* SDA边沿延迟时间ns */

};

void __init s3c_i2c0_set_platdata(structs3c2410_platform_i2c *pd)

{

structs3c2410_platform_i2c *npd;

if(!pd)

pd= &default_i2c_data;

npd= s3c_set_platdata(pd, sizeof(struct s3c2410_platform_i2c),

&s3c_device_i2c0);

if(!npd->cfg_gpio)

npd->cfg_gpio= s3c_i2c0_cfg_gpio;

}

在板文件中把platform_device注册进内核:

static struct platform_device*mini2440_devices[] __initdata = {

……

&s3c_device_i2c0,

……

};

调用s3c_i2c0_set_platdata 函数把适配器具体的数据赋值给dev.platform_data:

static void __init mini2440_init(void)

{

……

s3c_i2c0_set_platdata(NULL);

}

I2C总线驱动就分析到这里。

原文:http://www.cnblogs.com/chd-zhangbo/p/5199224.html

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值