您的位置:首页 > 其它

davinci平台的I2C驱动(非GPIO口模拟i2c)

2013-10-28 13:57 501 查看
一、概述

前边介绍过将普通GPIO口模拟成I2C,本文介绍davinci平台的硬件I2C驱动。Linux的I2C体系结构分为3个组成部分:

1.I2C核心

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

2.I2C总线驱动

I2C总线驱动是对I2C硬件体系结构中适配器端的实现,适配器可由CPU控制,甚至直接集成在CPU内部。

I2C总线驱动主要包含了I2C适配器数据结构i2c_adapter、I2C适配器的algorithm数据结构i2c_algorithm和控制I2C适配器产生通信信号的函数。

经由I2C总线驱动的代码,我们可以控制I2C适配器以主控方式产生开始位、停止位、读写周期,以及以从设备方式被读写、产生ACK等。

3.I2C设备驱动

I2C设备驱动是对I2C硬件体系结构中设备端的实现,设备一般挂接在受CPU控制的I2C适配器上,通过I2C适配器与CPU交换数据。

I2C设备驱动主要包含了数据结构i2c_driver和i2c_client,我们需要根据具体设备实现其中的成员函数。

4.I2C驱动框架:

I2C驱动实在platform机制上实现的,因为linux内核存在I2c的总线i2c_bus_type,为什么还要注册在platform的虚拟总线上?这是因为使用platform 总线在驱动中大体有以下几个好处:

a) 使得设备被挂接在一个总线上,使配套的sysfs节点、设备电源管理都成为可能。

b) 隔离了BSP 和驱动。BSP 中定义platform 设备和设备使用的资源(可以使用platform_data的形式来包括platform 设备的设备),设备的具体配置信息。而在驱动中,只需要通过通用API 去获取资源和数据,做到了板相关代码和驱动代码的分离,使得驱动具有更好的可扩展性和跨平台性。

但是真正达i2c设备和驱动还是要注册在i2c_bus_type总线上。

所以i2c驱动框架如下:

(1).向内核注册i2c_bus_type总线。

(2).定义i2c的板级资源到platform_device结构中的resource字段,注册i2c的platform_device结构。

(3).注册i2c的platform_driver结构。注册时会调用platform_driver中的probe函数,即davinci_i2c_probe()函数。

(4).在davinci_i2c_probe()函数中,进行i2c内存资源的申请、中断申请、寄存器初始化、时钟设置等等(platform机制的优势),添加到davinci_i2c_dev结构(这个结构封装davinci平台cpu的i2c模块的所有资源,包括adapter,对底层硬件的操作也是通过此结构)。并注册davinci_i2c_dev结构中的adapter设备到i2c_bus_type总线上。(下面会注册该设备的驱动)

(5).接下来调用i2c_dev_init()函数中,注册adapter字符设备,创建与设备节点相关的sysfs文件系统文件和目录(为udev创建设备节点有关),注册adapter设备的驱动到i2c_bus_type总线上。驱动注册时,会扫描i2c_bus_type总线上的设备,将之前注册的adapter设备依附到此driver上。此时会将adapter设备与i2c_dev相关联起来,同时将此i2c_dev结构挂接到全局链表i2c_dev_list中,为用户空间使用时,打开设备方便找到该i2c_dev,再找到对应的adapter结构,再找到对应的davinci_i2c_dev结构,就可以对硬件进行操作了。

6.其中davinci_i2c_dev结构、i2c_dev结构和i2c_adapter结构的联系

adapter设备注册时,davinci_i2c_dev结构中的i2c_adapter结构的字段adapter指向前边注册的adapter。(davinci_i2c_dev.adapter->adapter)

adapter驱动注册时,i2c_dev结构中的i2c_adapter结构的字段adapter也指向前边注册的adapter。(i2c_dev.adapter->adapter)

i2c_dev结构用于上层使用,davinci_i2c_dev结构用于底层硬件操作使用,而两者共同指向的adapter结构将两者联系起来。当用户打i2c设备时,会首先找到i2c_dev结构,通过adapter字段找到底层的davinci_i2c_dev结构,进而就可以进行底层硬件寄存器的操作了。

驱动框架如下图:



二、下面介绍i2c各核心数据结构的定义和它们之间的连接关系。

1. 一个i2c适配器由i2c_adapter数据结构描述

/*

i2c adapter是软件上抽象出来的i2c总线控制器接口,i2c总线适配器(adapter)就是一条 i2c总线的控制器,i2c_adapter对应于物理上的一个适配器

物理上一条i2c总线可以挂接多个硬件设备(slave),一个CPU可以挂接多条i2c总线(想象一下PCI总线),i2c总线控制器就是CPU访问I2C总线的硬件接口,也就是你说的那几个寄存器
.

简单点了, 你的开发板上有几个I2C接口,就有几个adapter , 也就是有几条I2C bus , I2C CLIENT 对应的就是你的外围I2C 设备,有几个就有几个CLIENT
, 把这些设备插入开发板, 对应其中的一条BUS, 那么相应的就对应了其中的一个ADAPTER
, 接下来的就是 CLIENT 与 ADAPTER 勾搭成对了, 后面就是做该做的事了.

*/

struct i2c_adapter {

struct module *owner;/*所属模块*/

unsigned int id;
/*algorithm的类型,定义于i2c-id.h,以I2C_ALGO_开始*/

unsigned int
class;

struct i2c_algorithm *algo;/*总线通信方法结构体指针,一个i2c适配器上的i2c总线通信方法由其驱动程序提供的i2c_algorithm数据结构描述,由algo指针指向
*/

void *algo_data;
/* algorithm数据
*/

int (*client_register)(struct i2c_client
*);
/*client注册时调用*/

int (*client_unregister)(struct i2c_client
*);
/*client注销时调用*/

struct semaphore bus_lock;
/*控制并发访问的自旋锁*/

struct semaphore clist_lock;

int timeout;

int retries;
/*重试次数*/

struct device dev;
/* 适配器设备 */

struct class_device class_dev;
/* 类设备 */

int nr;

struct list_head clients;
/* client链表头,总线上每个设备的 i2c_client数据结构挂载在这里*/

struct list_head list;

char name[I2C_NAME_SIZE];
/*适配器名称*/

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

struct completion class_dev_released;

};

2.具体i2c适配器的通信方法由i2c_algorithm数据结构进行描述:

struct i2c_algorithm {

int (*master_xfer)(struct i2c_adapter
*adap, struct i2c_msg
*msgs,int num);//I2C传输函数指针

int (*smbus_xfer)
(struct i2c_adapter
*adap, u16 addr,unsigned short flags, char read_write,u8 command,
int size, union i2c_smbus_data
*data);//SMbus传输函数指针

u32 (*functionality)
(struct i2c_adapter
*);//返回适配器支持的功能

};

3. 一个i2c设备的驱动程序由i2c_driver数据结构描述,i2c_driver代表I2C从设备驱动,定义于include/linux/i2c.h:

struct i2c_driver {

unsigned int
class;

/* 这两个接口已经被probe和remove取代
*/

int (*attach_adapter)(struct i2c_adapter
*);//attach_adapter回调函数在安装i2c设备驱动程序模块时、或者在安装i2c适配器驱动程序模块时被调用,

//用于检测、认领设备并为设备分配i2c_client数据结构。

int (*detach_adapter)(struct i2c_adapter
*);//detach_client方法在卸载适配器或设备驱动程序模块时被调用,用于从总线上注销设备、并释放i2c_client及相应的私有数据结构。

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

int (*remove)(struct i2c_client
*);

void (*shutdown)(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表

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

const unsigned short
*address_list;

struct list_head clients;

};

4.一个i2c设备由i2c_client数据结构进行描述:

struct i2c_client {

unsigned int flags;
/* 标志
*/

/*需要说明的是,i2c设备的7位地址是就当前i2c总线而言的,是“相对地址”。不同的i2c总线上的设备可以使用相同的7位地址,

但是它们所在的i2c总线不同。所以在系统中一个i2c设备的“绝对地址”由二元组(i2c适配器的ID和设备在该总线上的7位地址)表示。

*/

unsigned short addr;
/* 低7位为芯片地址
*/

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

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

int usage_count;
/* 访问计数
*/

struct device dev;
/* 设备结构体 */

struct list_head list;
/* 链表头 */

char name[I2C_NAME_SIZE];
/* 设备名称
*/

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

};

5.下面分析一下i2c_driver、i2c_client、i2c_adapter和i2c_algorithm这4个数据结构的作用及其盘根错节的关系。

5.1 i2c_adapter与i2c_algorithm

i2c_adapter 对应于物理上的一个适配器,而i2c_algorithm对应一套通信方法。一个I2C适配器需要i2c_algorithm中提供的通信函数来控制适配器上产生特定的访问周期。缺少i2c_algorithm的i2c_adapter什么也做不了,因此i2c_adapter中包含其使用的 i2c_algorithm的指针。

i2c_algorithm中的关键函数master_xfer()用于产生I2C访问周期需要的信号,以i2c_msg(即I2C消息)为单位。

struct i2c_msg {//i2c_msg结构体:

__u16 addr;
/* 设备地址*/

__u16 flags;
/* 标志 */

__u16 len;
/* 消息长度*/

__u8 *buf;
/* 消息数据*/

};

5.2 i2c_driver与i2c_client

i2c_driver对应一套驱动方法,是纯粹的用于辅助作用的数据结构,它不对应于任何的物理实体。i2c_client对应于真实的物理设备,每个I2C设备都需要一个i2c_client来描述。i2c_client一般被包含在i2c字符设备的私有信息结构体中。同一类的i2c设备device对应一个驱动driver。driver与device的关系是一对多的关系。

i2c_driver 与i2c_client发生关联的时刻在i2c_driver的attach_adapter()函数被运行时。attach_adapter()会探测物理设备,当确定一个client存在时,把该client使用的i2c_client数据结构的adapter指针指向对应的i2c_adapter,
driver指针指向该i2c_driver,并会调用i2c_adapter的client_register()函数。相反的过程发生在 i2c_driver 的detach_client()函数被调用的时候。

5.3 i2c_adpater与i2c_client

i2c_adpater 与i2c_client的关系与I2C硬件体系中适配器和设备的关系一致,即i2c_client依附于i2c_adpater。由于一个适配器上可以连 接多个I2C设备,所以一个i2c_adpater也可以被多个i2c_client依附,i2c_adpater中包括依附于它的i2c_client 的链表。

三、I2C驱动的实现工作

一方面,适配器驱动可能是Linux内核本身还不包含的。另一方面,挂接在适配器上的具体设备驱动可能也是Linux不存在的。即便上述设备驱动都存在于Linux内核中,其基于的平台也可能与我们的电路板不一样。因此,工程师要实现的主要工作将包括:

6.1 提供I2C适配器的硬件驱动,探测、初始化I2C适配器(如申请I2C的I/O地址和中断号)、驱动CPU控制的I2C适配器从硬件上产生各种信号以及处理I2C中断等。

6.2 提供I2C适配器的algorithm,用具体适配器的xxx_xfer()函数填充i2c_algorithm的master_xfer指针,并把i2c_algorithm指针赋值给i2c_adapter的algo指针。

6.3 实现I2C设备驱动与i2c_driver接口,用具体设备yyy的yyy_attach_adapter()函数指针、 yyy_detach_client()函数指针和yyy_command()函数指针的赋值给i2c_driver的attach_adapter、
detach_adapter和detach_client指针。

6.4 实现I2C设备驱动的文件操作接口,即实现具体设备yyy的yyy_read()、yyy_write()和yyy_ioctl()函数等。

四、核心层提供的接口函数

1、增加/删除I2C适配器

int i2c_add_adapter(struct i2c_adapter
*adapter)

int i2c_del_adapter(struct i2c_adapter
*adap)

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

int i2c_register_driver(struct module
*owner, structi2c_driver
*driver)

static inline int i2c_add_driver(struct i2c_driver
*driver)

void i2c_del_driver(struct i2c_driver
*driver)

//i2c_add_driver是对i2c_register_driver简单的封装

3、i2c传输,发送和接收

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)

//i2c_master_send和i2c_master_recv是i2c_transfer的封装

//3.1.0的内核中已经没有i2c_attach_client和i2c_detach_client接口

4、I2C总线通信方法

我们需要为特定的I2C适配器实现其通信方法,主要实现i2c_algorithm结构体中的两个函数:

struct i2c_algorithm {

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

u32(*functionality)
(struct i2c_adapter
*);

};

Functionality函数用于返回algorithm所支持的通信协议;

Master_xfer函数在I2C适配器上完成数据的传输;

//Master_xfer函数实现模板

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_add_driver函数向I2C总线(i2c-core.c文件中注册的”i2c”总线)增加一个i2c_driver时,会遍历总线中的所有i2c_client,

调用总线注册的match函数I2C适配器上是否有与i2c_driver匹配的i2c_client,如果匹配会调用I2C注册的probe函数,然后再调用i2c_driver定义的probe来进行关联和初始化工作。

五、i2c的初始化

i2c子系统的初始化函数的执行先后顺序,结合vmlinux.lds和Makefile,可确定i2c初始化函数的执行顺序如下:

1./dricer/i2c/i2c-core.c中的函数:i2c_init()---------->postcore_initcall级别

2./arch/arm/mach-davinci/board-da850-evm.c中的函数:da850_evm_init()---------->arch_initcall级别

3.driver/i2c/buses/i2c-davinci.c中的函数:davinci_i2c_init_driver()---------->subsys_initcall级别

4./driver/i2c/i2c-dev.c中的函数:i2c_dev_init()---------->module_init级别

1.i2c总线注册

static int __init i2c_init(void)

{

int retval;

//设备模型中,关心总线,设备,驱动这三个实体,总线将设备和驱动绑定,在系统每注册一个设备的时候,会寻找与之匹配的驱动。

//相反,在系统每注册一个驱动的时候,寻找与之匹配的设备,匹配是由总线来完成的。 你还可以看一看链表的信息。它们都是关联的。

retval = bus_register(&i2c_bus_type);//可以发现i2c_inti的函数主要功能就是注册i2c总线,并且在sysfs文件系统/bus目录下创建i2c目录,并在i2c目录下建立devices和drivers目录等

if (retval)

return retval;

/*

static struct i2c_driver dummy_driver =
{

.driver.name
= "dummy",

.probe
= dummy_probe,

.remove
= dummy_remove,

.id_table
= dummy_id,

};

*/

retval = i2c_add_driver(&dummy_driver);//注册一个虚拟驱动

if (retval)

goto class_err;

return 0;

class_err:

bus_unregister(&i2c_bus_type);

return retval;

}

/*

struct bus_type i2c_bus_type =
{

.name =
"i2c",

.match = i2c_device_match,

.probe = i2c_device_probe,

.remove = i2c_device_remove,

.shutdown
= i2c_device_shutdown,

.pm =
&i2c_device_pm_ops,

};

match方法的用来进行client device和client driver的配对。在向总线i2c_bus_type注册设备或者驱动时会调用此方法。

probe方法在完成设备和驱动的配对后调用执行,i2c_bus_type的probe方法是通过传递进来的drv找到包含此drv的i2c_driver驱动,然后再去调用i2c_driver的probe方法,此处就是at24_probe。

为什么要这样呢?因为driver_register后,注册的是i2_driver->drv,而drv中的probe未初始化,我们需要调用的是i2c-driver的probe方法。

*/

2.设置i2c的复用管脚配置,以及注册i2c的platform_device设备

调用完函数i2c_init后,系统将成功创建i2c总线。初始化完毕总线后还需要接着初始化i2c设备和i2c驱动(一般是先初始化device),linux内核中的device初始化一般是通过platform device来初始化的,platform device的初始化在da850_evm_init().

static __init void da850_evm_init(void)

{

int ret;

char mask = 0;

//在archarmmach-davinciincludemachcommon.h中定义davinci_soc_info结构。

//而archarmmach-davincicommon.c中davinci_common_init()对其初始化。

//davinci_soc_info真正的定义在archarmmach-davincida850.c中,定义达芬奇架构的各类资源的地址等

struct davinci_soc_info *soc_info
= &davinci_soc_info;

//......

/* 寄存器端口配置为I2C

MUX_CFG(DA850, I2C0_SDA, 4, 12, 15, 2, false)

MUX_CFG(DA850, I2C0_SCL, 4, 8, 15, 2, false)

......

const short da850_i2c0_pins[] __initdata
= {

DA850_I2C0_SDA, DA850_I2C0_SCL,//修改1

-1

};

*/

ret = davinci_cfg_reg_list(da850_i2c0_pins);//i2c的复用管脚配置

if (ret)

pr_warning("da850_evm_init: i2c0 mux setup failed: %dn",ret);

/*

static struct resource i2c_davinci_resources[]
= {

{

.name
= "i2c_davinci",

.start
= 0x01C22000,

.end
= 0x01C2205C,

.flags
= IORESOURCE_MEM,

},

{

.start
= 15,

.end
= 16,

.flags
= IORESOURCE_IRQ,

},

};

static struct davinci_i2c_platform_data da850_davinci_i2c_pdata
= {//wbl test 0514

.bus_freq = 20,

.bus_delay = 100,

};

static struct platform_device davinci_i2c_device
= {//wbl test 0514

.name =
"i2c_davinci",

.num_resources
= ARRAY_SIZE(i2c_davinci_resources),

.resource
= i2c_davinci_resources,

.id = 1,

.dev =
{

.platform_data =
&da850_davinci_i2c_pdata,

},

};

*/

//注册i2c对应的platform设备,把它注册到总线platform_bus_type上,即在sys的platform目录下建立文件和目录,参见platform驱动

platform_device_register(&davinci_i2c_device);

//......

}

3.在完成platform_device的添加之后,i2c子系统将进行platform_driver的注册过程。platform_driver的注册通过调用初始化函数davinci_i2c_init_driver()函数来完成。

static struct platform_driver davinci_i2c_driver
= {

.probe = davinci_i2c_probe,

.remove = davinci_i2c_remove,

.driver =
{

.name =
"i2c_davinci",

.owner = THIS_MODULE,

.pm = davinci_i2c_pm_ops,

},

};

//i2c通信方法结构

static struct i2c_algorithm i2c_davinci_algo =
{

.master_xfer = i2c_davinci_xfer,

.functionality = i2c_davinci_func,

};

//davinci平台封装的i2c设备结构

struct davinci_i2c_dev {

struct device *dev;//内嵌device结构

void __iomem *base;//寄存器起始地址

struct completion cmd_complete;

struct clk *clk;//时钟

int cmd_err;

u8 *buf;//读写数据的buf

size_t buf_len;//读写数据长度

int irq;//中断号

int stop;

u8 terminate;

struct i2c_adapter adapter;//设备对应的adapter

#ifdef CONFIG_CPU_FREQ//是否支持cpu变频技术

struct completion xfr_complete;

struct notifier_block freq_transition;

#endif

struct davinci_i2c_platform_data *pdata;

};

//注册驱动

static int __init davinci_i2c_init_driver(void)

{

//platform_driver_register()同样也是进行其它的一些初始化后调用driver_register()将驱动注册到platform_bus_type总线上.

return platform_driver_register(&davinci_i2c_driver);

}

//driver_register()函数会扫描platform_bus_type总线上的设备与驱动进行配对,配对成功就会调用i2c的probe函数

//因为之前的platform_device的name为i2c_davinci与platform_driver的name一致,故会match成功

static int davinci_i2c_probe(struct platform_device
*pdev)

{

struct davinci_i2c_dev *dev;

struct i2c_adapter *adap;

struct resource *mem,
*irq,
*ioarea;

int r;

//获得platform_device设备对应的寄存器内存资源

mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);

if (!mem)
{

dev_err(&pdev->dev,
"no mem resource?n");

return -ENODEV;

}

//获得platform_device设备对应的中断资源

irq = platform_get_resource(pdev, IORESOURCE_IRQ, 0);

if (!irq)
{

dev_err(&pdev->dev,
"no irq resource?n");

return -ENODEV;

}

//申请寄存器的内存空间

ioarea = request_mem_region(mem->start, resource_size(mem),pdev->name);

if (!ioarea)
{

dev_err(&pdev->dev,
"I2C region already claimedn");

return -EBUSY;

}

//分配davinci_i2c_dev空间

dev = kzalloc(sizeof(struct davinci_i2c_dev), GFP_KERNEL);

if (!dev)
{

r = -ENOMEM;

goto err_release_region;

}

//初始化davinci_i2c_dev结构

init_completion(&dev->cmd_complete);

#ifdef CONFIG_CPU_FREQ

init_completion(&dev->xfr_complete);

#endif

dev->dev
= get_device(&pdev->dev);//将platform_device结构中的device字段赋值给davinci_i2c_dev结构中的device字段

dev->irq
= irq->start;//设置中断号

platform_set_drvdata(pdev, dev);//将davinci_i2c_dev结构的dev保存在platform_device结构中

//获得时钟并使能时钟

dev->clk
= clk_get(&pdev->dev,
NULL);

if (IS_ERR(dev->clk))
{

r = -ENODEV;

goto err_free_mem;

}

clk_enable(dev->clk);

//将寄存器的起始地址映射到内存

dev->base
= ioremap(mem->start, resource_size(mem));

if (!dev->base)
{

r = -EBUSY;

goto err_mem_ioremap;

}

//设置i2c器件的寄存器,设置时钟分频,设置中断,设置从地址等

i2c_davinci_init(dev);

//申请中断号,中断处理函数是i2c_davinci_isr()

r = request_irq(dev->irq, i2c_davinci_isr,
0, pdev->name, dev);

if (r)
{

dev_err(&pdev->dev,
"failure requesting irq %in", dev->irq);

goto err_unuse_clocks;

}

//与cpu变频技术有关

r = i2c_davinci_cpufreq_register(dev);

if (r)
{

dev_err(&pdev->dev,
"failed to register cpufreqn");

goto err_free_irq;

}

//初始化davinci_i2c_dev结构中对应的adapter字段

adap = &dev->adapter;

i2c_set_adapdata(adap, dev);//将davinci_i2c_dev结构的dev保存在adapter结构中

adap->owner
= THIS_MODULE;

adap->class
= I2C_CLASS_HWMON;

strlcpy(adap->name,
"DaVinci I2C adapter", sizeof(adap->name));

adap->algo
= &i2c_davinci_algo;//adapter的通信方法

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

adap->timeout
= DAVINCI_I2C_TIMEOUT;

adap->nr
= pdev->id;//1

//注册davinci_i2c_dev结构中对应的adapter设备(之后还会注册adapter的驱动)

r = i2c_add_numbered_adapter(adap);//将adapter设备注册到i2c_bus_type总线上

if (r)
{

dev_err(&pdev->dev,
"failure adding adaptern");

goto err_free_irq;

}

return 0;

err_free_irq:

free_irq(dev->irq, dev);

err_unuse_clocks:

iounmap(dev->base);

err_mem_ioremap:

clk_disable(dev->clk);

clk_put(dev->clk);

dev->clk
= NULL;

err_free_mem:

platform_set_drvdata(pdev,
NULL);

put_device(&pdev->dev);

kfree(dev);

err_release_region:

release_mem_region(mem->start, resource_size(mem));

return r;

}

static int i2c_davinci_init(struct davinci_i2c_dev
*dev)

{

struct davinci_i2c_platform_data *pdata
= dev->dev->platform_data;

if (!pdata)

pdata =
&davinci_i2c_platform_data_default;

//reset I2C,即使i2c无效

davinci_i2c_reset_ctrl(dev, 0);

//计算时钟分频

i2c_davinci_calc_clk_dividers(dev);

//为I2C提供从地址为0x08

davinci_i2c_write_reg(dev, DAVINCI_I2C_OAR_REG, 0x08);

//调试

dev_dbg(dev->dev,
"PSC = %dn",davinci_i2c_read_reg(dev, DAVINCI_I2C_PSC_REG));

dev_dbg(dev->dev,
"CLKL = %dn",davinci_i2c_read_reg(dev, DAVINCI_I2C_CLKL_REG));

dev_dbg(dev->dev,
"CLKH = %dn",davinci_i2c_read_reg(dev, DAVINCI_I2C_CLKH_REG));

dev_dbg(dev->dev,
"bus_freq = %dkHz, bus_delay = %dn",pdata->bus_freq, pdata->bus_delay);

//使能I2C器件

davinci_i2c_reset_ctrl(dev, 1);

//使能所有i2c中断

davinci_i2c_write_reg(dev, DAVINCI_I2C_IMR_REG, I2C_DAVINCI_INTR_ALL);

return 0;

}

static inline void davinci_i2c_reset_ctrl(struct davinci_i2c_dev
*i2c_dev,int val)

{

u16 w;

//读I2C Mode Register
(ICMDR)寄存器

w = davinci_i2c_read_reg(i2c_dev, DAVINCI_I2C_MDR_REG);

if (!val)//reset

w &=
~DAVINCI_I2C_MDR_IRS;
//DAVINCI_I2C_MDR_IRS
= BIT(5),即1<<5,即ICMDR寄存器第五位清0,表示reset i2c

else//enable

w |= DAVINCI_I2C_MDR_IRS;//ICMDR寄存器第五位置1,表示使能i2c

//重新写会ICMDR寄存器

davinci_i2c_write_reg(i2c_dev, DAVINCI_I2C_MDR_REG, w);

}

static inline void davinci_i2c_write_reg(struct davinci_i2c_dev
*i2c_dev,int reg, u16 val)

{

__raw_writew(val, i2c_dev->base
+ reg);

}

static inline u16 davinci_i2c_read_reg(struct davinci_i2c_dev
*i2c_dev,
int reg)

{

return __raw_readw(i2c_dev->base
+ reg);

}

static void i2c_davinci_calc_clk_dividers(struct davinci_i2c_dev
*dev)

{

struct davinci_i2c_platform_data *pdata
= dev->dev->platform_data;

u16 psc;

u32 clk;

u32 d;

u32 clkh;

u32 clkl;

u32 input_clock = clk_get_rate(dev->clk);

/* NOTE: I2C Clock divider programming info

* As per I2C specs the following formulas provide prescaler

* and low/high divider values

* input clk
--> PSC Div
----------->
ICCL/H Div --> output clock

* module clk

*

* output clk
= module clk /
(PSC + 1)
[ (ICCL
+ d) +
(ICCH + d)
]

*

* Thus,

* (ICCL
+ ICCH)
= clk = (input clk
/ ((psc
+1)
* output clk))
- 2d;

*

* where if PSC
== 0, d
= 7,

* if PSC
== 1, d
= 6

* if PSC
> 1 , d
= 5

*/

/*
get minimum of 7 MHz clock, but max of 12 MHz
*/

psc = (input_clock
/ 7000000)
- 1;

if ((input_clock
/ (psc
+ 1))
> 12000000)

psc++; /* better
to run under spec than over
*/

d = (psc
>= 2)
? 5 : 7
- psc;

clk = ((input_clock
/ (psc
+ 1))
/ (pdata->bus_freq
* 1000))
- (d
<< 1);

clkh = clk
>> 1;

clkl = clk
- clkh;

davinci_i2c_write_reg(dev, DAVINCI_I2C_PSC_REG, psc);

davinci_i2c_write_reg(dev, DAVINCI_I2C_CLKH_REG, clkh);

davinci_i2c_write_reg(dev, DAVINCI_I2C_CLKL_REG, clkl);

dev_dbg(dev->dev,
"input_clock = %d, CLK = %dn", input_clock, clk);

}

static inline void i2c_set_adapdata(struct i2c_adapter
*dev, void
*data)

{

dev_set_drvdata(&dev->dev, data);

}

int dev_set_drvdata(struct device
*dev, void
*data)

{

int error;

if (!dev->p)
{

error
= device_private_init(dev);//为dev->p分配空间,并且初始化

if (error)

return error;

}

dev->p->driver_data
= data;

return 0;

}

int device_private_init(struct device
*dev)

{

dev->p
= kzalloc(sizeof(*dev->p),
GFP_KERNEL);

if (!dev->p)

return -ENOMEM;

dev->p->device
= dev;

klist_init(&dev->p->klist_children,
klist_children_get,klist_children_put);

INIT_LIST_HEAD(&dev->p->deferred_probe);

return 0;

}

int i2c_add_numbered_adapter(struct i2c_adapter
*adap)

{

int id;

int status;

if (adap->nr
& ~MAX_ID_MASK)//adap->nr=1

return -EINVAL;

retry:

/*

在这里涉及到一个idr结构。idr结构本来是为了配合page cache中的radix tree而设计的。在这里我们只需要知道,它是一种高效的搜索树,且这个树预先存放了一些内存。避免在内存不够的时候出现问题。所以,在往idr中插入结构的时候,首先要调用idr_pre_get()为它预留足够的空闲内存,然后再调用idr_get_new_above()将结构插入idr中,该函数以参数的形式返回一个id.以后凭这个id就可以在idr中找到相对应的结构了。

*/

if (idr_pre_get(&i2c_adapter_idr, GFP_KERNEL)
== 0)

return -ENOMEM;

mutex_lock(&core_lock);//上锁

//它是将adapter结构插入到i2c_adapter_idr中,存放位置的id必须要大于或者等于adap->nr,然后将对应的id号存放在adapter->nr中

status = idr_get_new_above(&i2c_adapter_idr, adap, adap->nr,
&id);

if (status
== 0
&& id != adap->nr)
{

status =
-EBUSY;

idr_remove(&i2c_adapter_idr, id);

}

mutex_unlock(&core_lock);//解锁

if (status
==
-EAGAIN)

goto retry;

if (status
== 0)

status = i2c_register_adapter(adap);//对这个adapter进行进一步注册。

return status;

}

static int i2c_register_adapter(struct i2c_adapter
*adap)

{

int res = 0;

if (unlikely(WARN_ON(!i2c_bus_type.p)))
{

res =
-EAGAIN;

goto out_list;

}

/* Sanity checks
*/

if (unlikely(adap->name[0]
==
'0'))
{//adapter的name不为空

pr_err("i2c-core: Attempt to register an adapter with ""no name!n");

return -EINVAL;

}

if (unlikely(!adap->algo))
{//adapter的通信算法不能为空

pr_err("i2c-core: Attempt to register adapter '%s' with ""no algo!n", adap->name);

return -EINVAL;

}

rt_mutex_init(&adap->bus_lock);

mutex_init(&adap->userspace_clients_lock);

INIT_LIST_HEAD(&adap->userspace_clients);

//若没设置超时时间,则缺省为HZ。实际已经设置

if (adap->timeout
== 0)

adap->timeout
= HZ;

//adapter中内嵌的struct device结构进行必须的初始化

dev_set_name(&adap->dev,
"i2c-%d", adap->nr);//设置adapter->dev的设备名:i2c-1

adap->dev.bus
= &i2c_bus_type;//adapter中内嵌的struct device所在总线为i2c_bus_type

adap->dev.type
= &i2c_adapter_type;//adapter设备类型设为i2c_adapter_type

//adapter内嵌的struct device注册

res = device_register(&adap->dev);//注册adapter设备,即在sysfs文件系统的bus/i2c目录下创建adapter相应的文件和目录

if (res)

goto out_list;

dev_dbg(&adap->dev,
"adapter [%s] registeredn", adap->name);

//调用此函数i2c_scan_static_board_info之前,必须要调用i2c_register_board_info()将板子上的I2C设备信息预先注册到__i2c_board_list链表中,

//同时才会更改__i2c_first_dynamic_bus_num的值

if (adap->nr
< __i2c_first_dynamic_bus_num)//__i2c_first_dynamic_bus_num=0,adap->nr=1,不会调用下边的函数

i2c_scan_static_board_info(adap);//遍历__i2c_board_list中挂载的i2c_devinfo结构,每个都是一个i2c_client即i2c设备。

//若i2c设备(i2c_client)与adapter位于同一i2c总线上,则调用i2c_new_device()进行i2c设备(i2c_client)注册

/* Notify drivers
*/

mutex_lock(&core_lock);

//在新的适配器加入内核时调用函数 bus_for_each_drv时调用的函数。

//函数bus_for_each_drv是在总线类型为i2c_bus_type的驱动中找到一个驱动与新加入的适配器匹配。

bus_for_each_drv(&i2c_bus_type,
NULL, adap, __process_new_adapter);//遍历该总线上所有的driver,并设用attach_adapter,因为adapter的驱动还没注册,

//attach_adapter为空,设置会调用失败。

mutex_unlock(&core_lock);

return 0;

out_list:

mutex_lock(&core_lock);

idr_remove(&i2c_adapter_idr, adap->nr);

mutex_unlock(&core_lock);

return res;

}

4.i2c-dev模块为系统中所有的i2c适配器创建相应的/dev/i2c/%d字符设备节点,并注册设备访问方法,从而使得用户进程可以访问该i2c总线上的设备。

运行i2c_dev_init函数,注册adapter设备驱动,以_init为头的函数,在运行过后系统将回收其内存

//前边已经注册了adapter设备device_register(&adap->dev);下边要注册设备的驱动i2c_add_driver(&i2cdev_driver);

//驱动注册成功会和前边才注册的adapter设备相匹配i2cdev_attach_adapter(),匹配成功则创建设备文件。

static int __init i2c_dev_init(void)

{

int res;

printk(KERN_INFO
"i2c /dev entries drivern");

//register_chrdev函数最终会向系统注册主设备为I2C_MAJOR,此设备号为0~255的设备。这表示系统最多可以容纳256个i2c adapter,其中注册的结构体&i2cdev_fops,给用户空间提供了调用接口,就是个字符型驱动

/*当read()、write()、open()、close()、ioctl()等系统调用发生时就会调用到这些函数。

static const struct file_operations i2cdev_fops
= {

.owner = THIS_MODULE,

.llseek = no_llseek,

.read = i2cdev_read,

.write = i2cdev_write,

.unlocked_ioctl = i2cdev_ioctl,

.open = i2cdev_open,

.release = i2cdev_release,

};

*/

res = register_chrdev(I2C_MAJOR,
"i2c",
&i2cdev_fops);//注册i2C的字符设备

if (res)

goto out;

//创建设备类,字符设备注册完毕后通过class_create()函数初始化一个类i2c_dev_class,为sysfs系统创建一个i2c-dev的设备类

i2c_dev_class = class_create(THIS_MODULE,
"i2c-dev");

if (IS_ERR(i2c_dev_class))
{

res = PTR_ERR(i2c_dev_class);

goto out_unreg_chrdev;

}

//调用函数i2c_add_driver函数注册i2c driver。这里所说的i2c其实对应的是系统中所有的i2c类设备(包括i2c_client 和 adapter)。

/*

static struct i2c_driver i2cdev_driver =
{

.driver
= {

.name
= "dev_driver",

},

.attach_adapter
= i2cdev_attach_adapter,

.detach_adapter
= i2cdev_detach_adapter,

};

*/

//其作用在于为系统中所有已安装的i2c适配器调用i2cdev_driver的attach_adpter方法,

//即i2cdev_attach_adapter函数,为所有已安装的适配器创建相应的/dev/i2c-%d字符设备结点并注册设备访问方法。

res = i2c_add_driver(&i2cdev_driver);//注册adapter的驱动

if (res)

goto out_unreg_class;

return 0;

out_unreg_class:

class_destroy(i2c_dev_class);

out_unreg_chrdev:

unregister_chrdev(I2C_MAJOR,
"i2c");

out:

printk(KERN_ERR
"%s: Driver Initialisation failedn", __FILE__);

return res;

}

static inline int i2c_add_driver(struct i2c_driver
*driver)

{

return i2c_register_driver(THIS_MODULE, driver);

}

int i2c_register_driver(struct module
*owner, struct i2c_driver
*driver)

{

int res;

/* Can't register
until after driver model init
*/

if (unlikely(WARN_ON(!i2c_bus_type.p)))

return -EAGAIN;

//关联到i2c_bus_types

driver->driver.owner
= owner;

driver->driver.bus
= &i2c_bus_type;//设置i2c驱动的总线

//注册i2c_driver结构中内嵌的device_driver,即创建相应的sysfs文件系统的文件或属性文件

res = driver_register(&driver->driver);

if (res)

return res;

pr_debug("i2c-core: driver [%s] registeredn", driver->driver.name);

INIT_LIST_HEAD(&driver->clients);

/* Walk the adapters that are already present
*/

mutex_lock(&core_lock);

bus_for_each_dev(&i2c_bus_type,
NULL, driver, __process_new_driver);//遍历i2c_bus_type总线上所有的设备,与新加入的驱动相匹配,并调用驱动的attach_adapter

mutex_unlock(&core_lock);

return 0;

}

int bus_for_each_dev(struct bus_type
*bus, struct device
*start,void
*data,
int (*fn)(struct device
*, void
*))

{

struct klist_iter i;

struct device *dev;

int error
= 0;

if (!bus)

return -EINVAL;

klist_iter_init_node(&bus->p->klist_devices,
&i,(start
? &start->p->knode_bus
: NULL));
//将bus中的已注册的device列表放到迭代器中,方便索引

while ((dev
= next_device(&i))
&&
!error)
//将驱动逐个地与列表中每一个的device匹配,可能一个驱动匹配好几个设备

error
= fn(dev, data);
//这个fn就是上面传下来的__process_new_driver

klist_iter_exit(&i);

return error;

}

static int __process_new_driver(struct device
*dev, void
*data)

{

if (dev->type
!=
&i2c_adapter_type)//设备的类型是adapter,才能配对成功。由于之前已经注册过adapter设备了,所以在这里会找到adapter的设备

return 0;

//前边adapter的dev已经注册,这里会找到注册的i2c_adapter设备

return i2c_do_add_adapter(data, to_i2c_adapter(dev));

}

static int i2c_do_add_adapter(struct i2c_driver
*driver,struct i2c_adapter
*adap)

{

i2c_detect(adap, driver);//空函数

if (driver->attach_adapter)
{

driver->attach_adapter(adap);//调用i2cdev_attach_adapter()

}

return 0;

}

static int i2cdev_attach_adapter(struct i2c_adapter
*adap)

{

struct i2c_dev *i2c_dev;

int res;

/*打开一个i2c设备时,会看到此结构的用处:

struct i2c_dev {

struct list_head list;

struct i2c_adapter *adap;//指向对应的adapter

struct device *dev;

};

*/

i2c_dev = get_free_i2c_dev(adap);//创建一个i2c_dev结构,添加到全局链表i2c_dev_list中,并且指向adap(
i2c_dev->adap
= adap;)

if (IS_ERR(i2c_dev))

return PTR_ERR(i2c_dev);

/* 可见attach_adapter函数的作用就是调用device_create()函数 通过之前class_create的类信息在/dev下自动创建设备文件。

并且此设备的设备号是由固定的主设备号I2C_MAJOR 和 从设备号组成的,从设备号取的就是adapter的nr,此处为1。

并且可以推断出系统最多可以容纳0~255 总共256个i2c adapter。

*/

//创建adapter设备在sysfs文件系统中的相应文件或目录,并在sysfs文件系统类目录下的i2c-dev目录下创建i2c-1目录,此目录下创建设备节点的dev文件

//即/sys/class/i2c-dev/i2c-1/...(其中这里的i2c_dev->dev结构就是为创建目录i2c-1而使用的)

//系统启动后udev程序会根据sysfs文件系统相关的设备文件,创建设备节点,即i2c-1的设备节点

i2c_dev->dev
= device_create(i2c_dev_class,
&adap->dev,MKDEV(I2C_MAJOR, adap->nr),
NULL,"i2c-%d", adap->nr);

if (IS_ERR(i2c_dev->dev))
{

res = PTR_ERR(i2c_dev->dev);

goto error;

}

//为sysfs文件系统创建相应的属性文件

res = device_create_file(i2c_dev->dev,
&dev_attr_name);

if (res)

goto error_destroy;

pr_debug("i2c-dev: adapter [%s] registered as minor %dn",adap->name,
adap->nr);

return 0;

error_destroy:

device_destroy(i2c_dev_class, MKDEV(I2C_MAJOR, adap->nr));

error:

return_i2c_dev(i2c_dev);

return res;

}

六、i2c的打开、读、写

6.1 i2c设备的打开

static int i2cdev_open(struct inode
*inode, struct file
*file)

{

unsigned int minor
= iminor(inode);

struct i2c_client *client;

struct i2c_adapter *adap;

struct i2c_dev *i2c_dev;

//遍历i2c_dev_list链表,根据i2c_dev对应的adapter的索引值找到对应的i2c_dev结构

i2c_dev = i2c_dev_get_by_minor(minor);

if (!i2c_dev)

return -ENODEV;

//根据i2c_dev结构找到adapter

adap = i2c_get_adapter(i2c_dev->adap->nr);

if (!adap)

return -ENODEV;

//分配i2c_client结构空间

client = kzalloc(sizeof(*client), GFP_KERNEL);

if (!client)
{

i2c_put_adapter(adap);

return -ENOMEM;

}

snprintf(client->name, I2C_NAME_SIZE,
"i2c-dev %d", adap->nr);

client->driver
= &i2cdev_driver;//设备驱动(adapter 也是这个设备驱动,共用)

client->adapter
= adap;//依附的adapter

file->private_data
= client;//保存到文件的private_data字段中

return 0;

}

6.2 i2c的读数据

static ssize_t i2cdev_read(struct file
*file, char __user
*buf, size_t count,loff_t
*offset)

{

char *tmp;

int ret;

//找到相应的i2c_client

struct i2c_client *client
= file->private_data;

if (count
> 8192)

count = 8192;

tmp = kmalloc(count, GFP_KERNEL);

if (tmp
==
NULL)

return -ENOMEM;

pr_debug("i2c-dev: i2c-%d reading %zu bytes.n",iminor(file->f_path.dentry->d_inode),
count);

ret = i2c_master_recv(client, tmp, count);//读数据

if (ret
>= 0)

ret = copy_to_user(buf, tmp, count)
? -EFAULT
: ret;//读出数据拷贝到用户空间

kfree(tmp);

return ret;

}

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

{

struct i2c_adapter *adap
= client->adapter;

struct i2c_msg msg;

int ret;

msg.addr = client->addr;//应用程序会通过ioctl(i2c_fd,I2C_SLAVE,slaveaddr)来设置client的地址

msg.flags
= client->flags
& I2C_M_TEN;//是否设置过10位地址

msg.flags
|= I2C_M_RD;//读数据标志

msg.len
= count;//读数据长度

msg.buf = buf;//数据存储空间

ret = i2c_transfer(adap,
&msg, 1);//传输1个msg

return (ret
== 1)
? count : ret;

}

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

{

unsigned long orig_jiffies;

int ret, try;

if (adap->algo->master_xfer)
{//存在通信方法

if (in_atomic()
|| irqs_disabled())
{

ret = i2c_trylock_adapter(adap);

if
(!ret)/* I2C activity
is ongoing.
*/

return -EAGAIN;

} else
{

i2c_lock_adapter(adap);//给adapter上锁

}

orig_jiffies = jiffies;

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

ret = adap->algo->master_xfer(adap,
msgs, num);//最终转换为i2c_algorithm中的master_xfer传输,调用i2c_davinci_xfer()

if
(ret !=
-EAGAIN)

break;

if
(time_after(jiffies, orig_jiffies
+ adap->timeout))//retry间隔时间

break;

}

i2c_unlock_adapter(adap);//给adapter解锁

return ret;

} else
{

dev_dbg(&adap->dev,
"I2C level transfers not supportedn");

return -EOPNOTSUPP;

}

}

static int i2c_davinci_xfer(struct i2c_adapter
*adap, struct i2c_msg msgs[],
int num)

{

struct davinci_i2c_dev *dev
= i2c_get_adapdata(adap);

int i;

int ret;

dev_dbg(dev->dev,
"%s: msgs: %dn", __func__, num);

ret = i2c_davinci_wait_bus_not_busy(dev, 1);//读ICSTR寄存器查看i2c是否忙,忙则等待到timeout

if (ret
< 0)
{

dev_warn(dev->dev,
"timeout waiting for bus readyn");

return ret;

}

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

ret = i2c_davinci_xfer_msg(adap,
&msgs[i],
(i ==
(num - 1)));//发送一个msg

dev_dbg(dev->dev,
"%s [%d/%d] ret: %dn", __func__, i
+ 1, num,ret);

if (ret
< 0)

return ret;

}

#ifdef CONFIG_CPU_FREQ //cpu变频支持

complete(&dev->xfr_complete);

#endif

return num;

}

static int i2c_davinci_xfer_msg(struct i2c_adapter
*adap, struct i2c_msg
*msg,
int stop)

{

struct davinci_i2c_dev *dev
= i2c_get_adapdata(adap);

struct davinci_i2c_platform_data *pdata
= dev->dev->platform_data;

u32 flag;

u16 w;

int r;

if (!pdata)

pdata =
&davinci_i2c_platform_data_default;

/* Introduce a delay, required
for some boards (e.g Davinci EVM)
*/

if (pdata->bus_delay)//i2c等待时间为100us

udelay(pdata->bus_delay);

//设置从地址

davinci_i2c_write_reg(dev, DAVINCI_I2C_SAR_REG, msg->addr);

dev->buf
= msg->buf;

dev->buf_len
= msg->len;

dev->stop
= stop;

//写入数据计数寄存器,即把要读多少个数据写入寄存器ICCNT

davinci_i2c_write_reg(dev, DAVINCI_I2C_CNT_REG, dev->buf_len);

INIT_COMPLETION(dev->cmd_complete);

dev->cmd_err
= 0;

//设置使能I2C和设置I2C为主设备

flag = DAVINCI_I2C_MDR_IRS
| DAVINCI_I2C_MDR_MST;

/*
if the slave address is ten bit address, enable XA bit
*/

if (msg->flags
& I2C_M_TEN)//如果从设备是10位地址模式

flag |= DAVINCI_I2C_MDR_XA;//设置主设备也为10位地址模式

if (!(msg->flags
& I2C_M_RD))

flag |= DAVINCI_I2C_MDR_TRX;//设置主设备为接收模式

if (msg->len
== 0)

flag |= DAVINCI_I2C_MDR_RM;//repeat模式

//使能I2C的接收和发送中断

w = davinci_i2c_read_reg(dev, DAVINCI_I2C_IMR_REG);

if (msg->flags
& I2C_M_RD)

w |= DAVINCI_I2C_IMR_RRDY;

else

w |= DAVINCI_I2C_IMR_XRDY;

davinci_i2c_write_reg(dev, DAVINCI_I2C_IMR_REG, w);

dev->terminate
= 0;

//写入配置模式寄存器I2C Mode Register
(ICMDR)

davinci_i2c_write_reg(dev, DAVINCI_I2C_MDR_REG, flag);

/*

* First byte should be
set here, not after interrupt,

* because transmit-data-ready interrupt can come before

* NACK-interrupt during sending of previous message
and

* ICDXR may have wrong data

* It also saves us one interrupt, slightly faster

*/

if ((!(msg->flags
& I2C_M_RD))
&& dev->buf_len)
{//如果不是读模式,则向发送寄存器写出一个数据,后续数据会通过发送中断自动发送完成,直到dev->buf_len为0

davinci_i2c_write_reg(dev, DAVINCI_I2C_DXR_REG,
*dev->buf++);

dev->buf_len--;

}

/*
Set STT to begin transmit
now DXR is loaded
*/

flag |= DAVINCI_I2C_MDR_STT;//产生起始位

if (stop
&& msg->len
!= 0)//stop=0,不需设置停止位

flag |= DAVINCI_I2C_MDR_STP;

davinci_i2c_write_reg(dev, DAVINCI_I2C_MDR_REG, flag);//产生起始位,准备读数据

//等待读指令完成,这是在I2C中断中i2c_davinci_isr()完成读数据后,会complete(&dev->cmd_complete);

r = wait_for_completion_interruptible_timeout(&dev->cmd_complete,dev->adapter.timeout);

if (r
== 0)
{//返回0表示timeout,返回错误

dev_err(dev->dev,
"controller timed outn");

i2c_recover_bus(dev);

i2c_davinci_init(dev);

dev->buf_len
= 0;

return -ETIMEDOUT;

}

if (dev->buf_len)
{//读取到足够数据或者写完数据,dev->buf_len应该为0

/* This should be 0
if all bytes were transferred
or dev->cmd_err denotes an
error.A signal may have aborted the transfer.*/

if (r
>= 0)
{

dev_err(dev->dev,
"abnormal termination buf_len=%in",dev->buf_len);

r =
-EREMOTEIO;

}

dev->terminate
= 1;

wmb();

dev->buf_len
= 0;

}

if (r
< 0)

return r;

//没有错误,则返回读到的数据个数

if (likely(!dev->cmd_err))

return msg->len;

/* We have an
error */

if (dev->cmd_err
& DAVINCI_I2C_STR_AL)
{

i2c_davinci_init(dev);

return -EIO;

}

if (dev->cmd_err
& DAVINCI_I2C_STR_NACK)
{

if (msg->flags
& I2C_M_IGNORE_NAK)

return msg->len;

if (stop)
{

w = davinci_i2c_read_reg(dev, DAVINCI_I2C_MDR_REG);

w |= DAVINCI_I2C_MDR_STP;

davinci_i2c_write_reg(dev, DAVINCI_I2C_MDR_REG, w);

}

return -EREMOTEIO;

}

return -EIO;

}

static irqreturn_t i2c_davinci_isr(int this_irq, void
*dev_id)

{

struct davinci_i2c_dev *dev
= dev_id;

u32 stat;

int count
= 0;

u16 w;

while ((stat
= davinci_i2c_read_reg(dev, DAVINCI_I2C_IVR_REG)))
{//读I2C Interrupt Vector Register
(ICIVR)判断中断类型

dev_dbg(dev->dev,
"%s: stat=0x%xn", __func__, stat);

if (count++
== 100)
{

dev_warn(dev->dev,
"Too much work in one IRQn");

break;

}

switch (stat)
{

case DAVINCI_I2C_IVR_AL://Arbitration-lost interrupt

/* Arbitration lost, must retry
*/

dev->cmd_err
|= DAVINCI_I2C_STR_AL;

dev->buf_len
= 0;

complete(&dev->cmd_complete);

break;

case DAVINCI_I2C_IVR_NACK://No-acknowledgment interrupt

dev->cmd_err
|= DAVINCI_I2C_STR_NACK;

dev->buf_len
= 0;

complete(&dev->cmd_complete);

break;

case DAVINCI_I2C_IVR_ARDY://Register-access-ready
interrupt

davinci_i2c_write_reg(dev,DAVINCI_I2C_STR_REG, DAVINCI_I2C_STR_ARDY);

if
(((dev->buf_len
== 0)
&&
(dev->stop
!= 0))
||(dev->cmd_err
& DAVINCI_I2C_STR_NACK))
{

w = davinci_i2c_read_reg(dev,DAVINCI_I2C_MDR_REG);

w |= DAVINCI_I2C_MDR_STP;

davinci_i2c_write_reg(dev,DAVINCI_I2C_MDR_REG, w);

}

complete(&dev->cmd_complete);

break;

case DAVINCI_I2C_IVR_RDR://接受数据中断

if
(dev->buf_len)
{

*dev->buf++
=davinci_i2c_read_reg(dev,DAVINCI_I2C_DRR_REG);//从接受寄存器ICDRR中读取数据

dev->buf_len--;

if
(dev->buf_len)

continue;

davinci_i2c_write_reg(dev,DAVINCI_I2C_STR_REG,DAVINCI_I2C_IMR_RRDY);//表明接受寄存器ICDRR中的数据已经拷贝完毕

}
else {

/* signal can terminate transfer
*/

terminate_read(dev);

}

break;

case DAVINCI_I2C_IVR_XRDY://发送数据中断interrupt

if
(dev->buf_len)
{

davinci_i2c_write_reg(dev, DAVINCI_I2C_DXR_REG,*dev->buf++);//要发送的数据写入到发送寄存器中

dev->buf_len--;

if
(dev->buf_len)

continue;

w = davinci_i2c_read_reg(dev,DAVINCI_I2C_IMR_REG);

w &=
~DAVINCI_I2C_IMR_XRDY;

davinci_i2c_write_reg(dev,DAVINCI_I2C_IMR_REG,w);//禁止发送中断,在i2c_davinci_xfer()函数中,当数据要再次发送时,会再使能发送中断的

}
else {

/* signal can terminate transfer
*/

terminate_write(dev);

}

break;

case DAVINCI_I2C_IVR_SCD://Stop condition detected interrupt

davinci_i2c_write_reg(dev,DAVINCI_I2C_STR_REG, DAVINCI_I2C_STR_SCD);

complete(&dev->cmd_complete);

break;

case DAVINCI_I2C_IVR_AAS://Address-as-slave
interrupt

dev_dbg(dev->dev,
"Address as slave interruptn");

break;

default:

dev_warn(dev->dev,
"Unrecognized irq stat %dn", stat);

break;

}

}

return count ? IRQ_HANDLED
: IRQ_NONE;

}

6.3 i2c的写数据

static ssize_t i2cdev_write(struct file
*file, const char __user
*buf,size_t count, loff_t
*offset)

{

int ret;

char *tmp;

struct i2c_client *client
= file->private_data;

if (count
> 8192)

count = 8192;

tmp = memdup_user(buf, count);

if (IS_ERR(tmp))

return PTR_ERR(tmp);

pr_debug("i2c-dev: i2c-%d writing %zu bytes.n",iminor(file->f_path.dentry->d_inode),
count);

ret = i2c_master_send(client, tmp, count);

kfree(tmp);

return ret;

}

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

{

int ret;

struct i2c_adapter *adap
= client->adapter;

struct i2c_msg msg;

msg.addr = client->addr;

msg.flags
= client->flags
& I2C_M_TEN;

msg.len
= count;

msg.buf =
(char *)buf;

ret = i2c_transfer(adap,
&msg, 1);//同上

return (ret
== 1)
? count : ret;

}

疑问点:

static int i2c_davinci_cpufreq_transition(struct notifier_block *nb,unsigned long val, void *data)

{

struct davinci_i2c_dev *dev;

dev = container_of(nb, struct davinci_i2c_dev, freq_transition);

if (val == CPUFREQ_PRECHANGE) {

//wait_for_completion(&dev->xfr_complete);//也要注销掉,否则程序一直等在这里

davinci_i2c_reset_ctrl(dev, 0);

} else if (val == CPUFREQ_POSTCHANGE) {

i2c_davinci_calc_clk_dividers(dev);

davinci_i2c_reset_ctrl(dev, 1);

}

return 0;

}

如果不把这一行wait_for_completion(&dev->xfr_complete);注销掉,linux启动时程序会一直在这里等待。

发现唤醒它的地方在:

static int i2c_davinci_xfer(struct i2c_adapter *adap, struct i2c_msg msgs[], int num)

{

struct davinci_i2c_dev *dev = i2c_get_adapdata(adap);

int i;

int ret;

dev_dbg(dev->dev, "%s: msgs: %d\n", __func__, num);

ret = i2c_davinci_wait_bus_not_busy(dev, 1);

if (ret < 0) {

dev_warn(dev->dev, "timeout waiting for bus ready\n");

return ret;

}

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

ret = i2c_davinci_xfer_msg(adap, &msgs[i], (i == (num - 1)));

dev_dbg(dev->dev, "%s [%d/%d] ret: %d\n", __func__, i + 1, num,

ret);

if (ret < 0)

return ret;

}

#ifdef CONFIG_CPU_FREQ

complete(&dev->xfr_complete);//只有在这里唤醒

#endif

return num;

}

但是当cpu实现变频时,就会触发i2c_davinci_cpufreq_transition(),但是此时一定要等i2c发送或接受一次数据,才能唤醒吗?实在不能理解。

请高手们能不能帮忙解答一下,thanks!!!
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: