linux下i2c子系统,Linux驱动子系统之I2C(2)

2  I2C子系统

2.1 LinuxI2C子系统架构

在内核中已经提供I2C子系统,所以在做I2C驱动之前,就必须要熟悉该子系统。

uid-27041925-id-3672693.html

2.2 三大组成部分

1、I2C核心(i2c-core)

I2C核心提供了I2C总线驱动和设备驱动的注册、注销方法,I2C通信方法(algorithm)上层的、与具体适配器无关的代码以及探测设备、检测设备地址的上层代码等。

2、I2C总线驱动(I2Cadapter/Algo driver)

I2C总线驱动是I2C适配器的软件实现,提供I2C适配器与从设备间完成数据通信的能力。

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

3、I2C客户驱动程序(I2Cclient driver)

I2C客户驱动是对I2C从设备的软件实现,一个具体的I2C客户驱动包括两个部分:一部分是i2c_driver,用于将设备挂接于i2c总线;另一部分是设备本身的驱动。

I2C客户驱动程序由i2c_driver和i2c_client来描述

2.3 所有的I2C驱动代码位于drivers/i2c目录下

I2c-core.c    实现I2C核心的功能

I2c-dev.c     通用的从设备驱动

Chips       特定的I2C设备驱动

Busses      I2C适配器的驱动

Algos       实现了一些I2C总线适配器的algorithm

2.4 I2C驱动编写的两种方法

从上面的图我们可以看到两种编写驱动方法,一种是利用系统提供的i2c-dev.c来实现一个i2c适配器的设备文件,然后通过在应用层操作I2C适配器来控制I2C设备;另一种是为I2C从设备独立编写一个设备驱动,不需要i2c-dev.c文件。

2.5 重要的数据结构

每次分析子系统免不了分析它的数据结构,OK我们先来分析一下。

I2c_adapter结构体代表I2C总线控制器

[cpp]

structi2c_adapter {

structmodule *owner;

unsigned intclass;/*classes to allow probing for */

conststructi2c_algorithm*algo;/* 总线上数据传输的算法*/

void*algo_data;/* algorithm 数据 */

inttimeout;/* injiffies */

intretries;/* 重试次数 */

structdevice dev;/* the adapter device */

intnr;

charname[48];/* 适配器名字 */

structcompletion dev_released;/* 用于同步 */

};

struct i2c_adapter {

struct module *owner;

unsigned int class; /*classes to allow probing for */

const struct i2c_algorithm*algo; /* 总线上数据传输的算法*/

void *algo_data; /* algorithm 数据 */

int timeout; /* injiffies */

int retries; /* 重试次数 */

struct device dev; /* the adapter device */

int nr;

char name[48]; /* 适配器名字 */

struct completion dev_released; /* 用于同步 */

};

I2c_algorithm对应一套通信方法

[cpp]

structi2c_algorithm {

int(*master_xfer)(structi2c_adapter *adap,structi2c_msg *msgs, intnum);

int(*smbus_xfer) (structi2c_adapter *adap, u16 addr,

unsigned shortflags, charread_write,

u8 command, intsize, unioni2c_smbus_data *data);

u32 (*functionality) (structi2c_adapter *);

};

struct i2c_algorithm {

int (*master_xfer)(struct i2c_adapter *adap, struct i2c_msg *msgs, intnum);

int (*smbus_xfer) (struct i2c_adapter *adap, u16 addr,

unsigned short flags, charread_write,

u8 command, int size, unioni2c_smbus_data *data);

u32 (*functionality) (structi2c_adapter *);

};

Functionality 函数用于返回algorithm所支持的通信协议,比如I2C_FUNC_I2C,I2C_FUNC_10BIT_ADDR等。

Master_xfer   函数实现总线上数据传输,与具体的适配器有关

Master_xfer函数实现模板

[cpp]

staticinti2c_adapter_xxx_xfer(structi2c_adapter *adap,structi2c_msg *msgs,intnum)

{

......

for(i = 0; i < num; i++) {

i2c_adapter_xxx_start();         /*产生起始位*/

if(msgs[i]->flags & I2C_M_RD) {/*读取*/

i2c_adapter_xxx_setaddr((msg->addr << 1) | 1);  /*发送从设备地址*/

i2c_adapter_xxx_wait_ack();   /*获得从设备的ACK*/

i2c_adapter_xxx_readbytes(msgs[i]->buf,msgs[i]->len);  /*读取len长度的数据到buf中*/

} else{

i2c_adapter_xxx_setaddr(msg->addr << 1);

i2c_adapter_xxx_wait_ack();

i2c_adapter_xxx_writebytes(msgs[i]->buf, msgs[i]->len);

}

}

i2c_adapter_xxx_stop(); /*产生停止位*/

}

static int i2c_adapter_xxx_xfer(structi2c_adapter *adap, struct i2c_msg *msgs, int num)

{

......

for (i = 0; i < num; i++) {

i2c_adapter_xxx_start(); /*产生起始位*/

if (msgs[i]->flags & I2C_M_RD) { /*读取*/

i2c_adapter_xxx_setaddr((msg->addr << 1) | 1); /*发送从设备地址*/

i2c_adapter_xxx_wait_ack(); /*获得从设备的ACK*/

i2c_adapter_xxx_readbytes(msgs[i]->buf,msgs[i]->len); /*读取len长度的数据到buf中*/

} else {

i2c_adapter_xxx_setaddr(msg->addr << 1);

i2c_adapter_xxx_wait_ack();

i2c_adapter_xxx_writebytes(msgs[i]->buf, msgs[i]->len);

}

}

i2c_adapter_xxx_stop(); /*产生停止位*/

}

上面调用的函数用于完成适配器的底层硬件操作,与I2C适配器和CPU的具体硬件直接相关,需要由工程师根据芯片的数据手册来实现。在内核源码中,针对不同的I2C适配器都有master_xfer的实现,风格与模板不尽相同,但是可以用该模板作为参考来看源代码,受益匪浅。

I2c_driver代表I2C从设备驱动

[cpp]

structi2c_driver {

unsignedint class;

int(*attach_adapter)(structi2c_adapter *) __deprecated;/*依附i2c适配器函数指针*/

int(*detach_adapter)(structi2c_adapter *) __deprecated;/*脱离i2c适配器函数指针*/

int(*probe)(structi2c_client*,conststructi2c_device_id *);

int(*remove)(structi2c_client*);

int(*suspend)(structi2c_client *, pm_message_t mesg);

int(*resume)(structi2c_client *);

void(*alert)(structi2c_client *, unsignedintdata);

int(*command)(structi2c_client *client, unsignedintcmd,void*arg);

structdevice_driver driver;

conststructi2c_device_id*id_table;/* 该驱动所支持的设备ID表 */

/*Device detection callback for automatic device creation */

int(*detect)(structi2c_client *,structi2c_board_info *);

constunsigned short*address_list;

structlist_head clients;

};

struct i2c_driver {

unsignedint class;

int(*attach_adapter)(struct i2c_adapter *) __deprecated; /*依附i2c适配器函数指针*/

int(*detach_adapter)(struct i2c_adapter *) __deprecated;/*脱离i2c适配器函数指针*/

int (*probe)(struct i2c_client*, const struct i2c_device_id *);

int (*remove)(struct i2c_client*);

int(*suspend)(struct i2c_client *, pm_message_t mesg);

int(*resume)(struct i2c_client *);

void(*alert)(struct i2c_client *, unsigned int data);

int(*command)(struct i2c_client *client, unsigned int cmd, void *arg);

struct device_driver driver;

const struct i2c_device_id*id_table; /* 该驱动所支持的设备ID表 */

/*Device detection callback for automatic device creation */

int(*detect)(struct i2c_client *, struct i2c_board_info *);

constunsigned short *address_list;

structlist_head clients;

};

在新内核中,attach_adapter和detach_adapter已经被probe和remove取代

Id_table用于i2c_driver和i2c_client的匹配

I2c_client代表I2C从设备

[cpp]

structi2c_client {

unsigned shortflags;/*I2C_CLIENT_TEN:使用10位从地址,I2C_CLIENT_PEC:使用SMBus包错误检测*/

unsignedshort addr;                 /* chipaddress - NOTE: 7bit    */

charname[I2C_NAME_SIZE];

structi2c_adapter *adapter;/* 依附的i2c_adapter   */

structi2c_driver *driver;/* 依附的i2c_driver*/

structdevice dev;             /* the devicestructure             */

intirq;                         /* irq issuedby device               */

structlist_head detected;

};

struct i2c_client {

unsigned short flags; /*I2C_CLIENT_TEN:使用10位从地址,I2C_CLIENT_PEC:使用SMBus包错误检测*/

unsignedshort addr; /* chipaddress - NOTE: 7bit */

charname[I2C_NAME_SIZE];

struct i2c_adapter *adapter; /* 依附的i2c_adapter */

struct i2c_driver *driver; /* 依附的i2c_driver*/

structdevice dev; /* the devicestructure */

intirq; /* irq issuedby device */

structlist_head detected;

};

2.6 核心层提供的接口函数

1、  增加/删除I2C适配器

int i2c_add_adapter(struct i2c_adapter *adapter)

int i2c_del_adapter(struct i2c_adapter *adap)

[cpp]

staticinti2c_register_adapter(structi2c_adapter *adap)

{

res = device_register(&adap->dev);

if(adap->nr

i2c_scan_static_board_info(adap);

bus_for_each_drv(&i2c_bus_type, NULL, adap, __process_new_adapter);

}

static int i2c_register_adapter(struct i2c_adapter *adap)

{

res = device_register(&adap->dev);

if (adap->nr Device_register(&adap->dev)  向I2C总线注册一个adapter设备

i2c_scan_static_board_info(adap)   注册所有已知的i2c_client

2、  增加/删除I2C从设备驱动

[cpp]

inti2c_add_driver(structi2c_driver *driver)

voidi2c_del_driver(structi2c_driver *driver)

inti2c_register_driver(structmodule *owner,structi2c_driver *driver)

{

/* add the driver to the list of i2c drivers inthe driver core */

driver->driver.owner = owner;

driver->driver.bus = &i2c_bus_type;

res = driver_register(&driver->driver);

/* Walk the adapters that are already present*/

i2c_for_each_dev(driver, __process_new_driver);

}

int i2c_add_driver(struct i2c_driver *driver)

void i2c_del_driver(struct i2c_driver *driver)

inti2c_register_driver(struct module *owner, struct i2c_driver *driver)

{

/* add the driver to the list of i2c drivers inthe driver core */

driver->driver.owner = owner;

driver->driver.bus = &i2c_bus_type;

res = driver_register(&driver->driver);

/* Walk the adapters that are already present*/

i2c_for_each_dev(driver, __process_new_driver);

}

driver_register(&driver->driver)   向I2C总线注册一个i2c_driver

3、  i2c传输,发送和接收

[cpp]

inti2c_transfer(structi2c_adapter *adap,structi2c_msg*msgs,intnum)

inti2c_master_send(conststructi2c_client *client, constchar *buf,intcount)

inti2c_master_recv(conststructi2c_client *client,char*buf,intcount)

inti2c_transfer(structi2c_adapter *adap,structi2c_msg *msgs,intnum)

{

if(adap->algo->master_xfer) {

for(ret = 0,try= 0;try<=adap->retries;try++) {

ret = adap->algo->master_xfer(adap, msgs,num);

}

}

}

int i2c_transfer(struct i2c_adapter *adap, struct i2c_msg*msgs, int num)

int i2c_master_send(const struct i2c_client *client, constchar *buf, int count)

int i2c_master_recv(const struct i2c_client *client, char*buf, int count)

int i2c_transfer(structi2c_adapter *adap, struct i2c_msg *msgs, int num)

{

if (adap->algo->master_xfer) {

for (ret = 0, try = 0; try <=adap->retries; try++) {

ret = adap->algo->master_xfer(adap, msgs,num);

}

}

}

最终会调用到适配器实现的master_xfer函数来完成数据传输工作

参考资料:《essential Linux device drivers》

《linux设备驱动开发详解》

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值