首页 > 编程语言 >I2C 驱动编程接口

I2C 驱动编程接口

时间:2023-01-24 14:08:08浏览次数:48  
标签:reset i2c adapter 编程 接口 client msg I2C


1、通信接口

i2c发送或者接收一次数据都以数据包 struct i2c_msg 封装


struct i2c_msg { 

__u16 addr; // 从机地址

__u16 flags; // 标志

#define I2C_M_TEN 0x0010 // 十位地址标志

#define I2C_M_RD 0x0001 // 接收数据标志

__u16 len; // 数据长度

__u8 *buf; // 数据指针

};

其中addr为从机地址;flags则是这次通信的标志,发送数据为0,接收数据则为 I2C_M_RD;len为此次通信的数据字节数;buf 为发送或接收数据的指针。在设备驱动中我们通常调用 i2c-core 定义的接口 i2c_master_send 和 i2c_master_recv 来发送或接收一次数据。


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

{

int ret;

struct i2c_adapter *adap=client->adapter; // 获取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); // 调用平台接口发送数据



/* If everything went ok (i.e. 1 msg transmitted), return #bytes

transmitted, else error code. */

return (ret == 1) ? count : ret; // 如果发送成功就返回字节数

}

EXPORT_SYMBOL(i2c_master_send);

i2c_master_send 接口的三个参数:client 为此次与主机通信的从机,buf 为发送的数据指针,count 为发送数据的字节数。

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

{

struct i2c_adapter *adap=client->adapter; // 获取adapter信息

struct i2c_msg msg; // 定义一个临时的数据包

int ret;



msg.addr = client->addr; // 将从机地址写入数据包

msg.flags = client->flags & I2C_M_TEN; // 将从机标志并入数据包

msg.flags |= I2C_M_RD; // 将此次通信的标志并入数据包

msg.len = count; // 将此次接收的数据字节数写入数据包

msg.buf = buf;



ret = i2c_transfer(adap, &msg, 1); // 调用平台接口接收数据



/* If everything went ok (i.e. 1 msg transmitted), return #bytes

transmitted, else error code. */

return (ret == 1) ? count : ret; // 如果接收成功就返回字节数

}

EXPORT_SYMBOL(i2c_master_recv);

i2c_master_recv 接口的三个参数:client 为此次与主机通信的从机,buf 为接收的数据指针,count 为接收数据的字节数。我们看一下 i2c_transfer 接口的参数说明:

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

其中 adap 为此次主机与从机通信的适配器;msgs 为通信的数据包,这里可以是单个或多个数据包;num 用于指定数据包的个数,如果大于1则表明将进行不止一次的通信。通信一次就需要寻址一次,如果需要多次通信就需要多次寻址,前面2个接口都是进行一次通信,所以 num 为1;有的情况下我们要读一个寄存器的值,就需要先向从机发送一个寄存器地址然后再接收数据,这样如果想自己封装一个接口就需要将 num 设置为2。接口的返回值如果失败则为负数,如果成功则返回传输的数据包个数。比如读一个寄存器的接口可以按照如下方式封装:

static int read_reg(struct i2c_client *client, unsigned char reg, unsigned char *data) 

{

int ret;



struct i2c_msg msgs[] = {

{

.addr = client->addr,

.flags = 0,

.len = 1,

.buf = ®, // 寄存器地址

},

{

.addr = client->addr,

.flags = I2C_M_RD,

.len = 1,

.buf = data, // 寄存器的值

},

};



ret = i2c_transfer(client->adapter, msgs, 2); // 这里 num = 2,通信成功 ret = 2

if (ret < 0)

tp_err("%s error: %d\n", __func__, ret);



return ret;

}

还可调用前面所述的接口封装:

static unsigned char read_reg(struct i2c_client *client, unsigned char reg) 

{

unsigned char buf;



i2c_master_send(client, ®, 1); // 发送寄存器地址

i2c_master_recv(client, &buf, 1); // 接收寄存器的值



return buf;

}

2、reset 接口最近因为平台的i2c总线经常发生死锁,用逻辑分析仪检测发现通常为SDA和SCL都被拉低,于是在i2c-core中加入了reset机制,总体思路如下:

(1)在i2c.driver和i2c.adapter的结构中加入reset接口,即每一个i2c设备都可以注册reset函数,每条i2c总线都有相应的reset接口

(2)当发生死锁时,首先根据i2c-timeout的信息获取当前通信的设备地址和总线编号,然后依次执行当前总线下所有i2c设备的reset函数,再尝试发送是否成功;如果总线仍然处于死锁状态则执行i2c.adapter的reset函数;如果总线还是处于死锁状态就重启机器;总共3层reset机制

(3)i2c.driver的reset函数一般操作设备的reset pin或者电源(需要根据硬件设计进行相应操作)

(4)i2c.adapter的reset函数首选进行SCL的模拟解锁方案,然后再是操作整个总线上设备的电源(需要根据硬件设计进行相应操作)

(5)重启是最后的一层机制,此时无法恢复设备的正常使用就只能重启了因为i2c.adapter层的需要,在i2c-core中加入了遍历当前总线所有设备并执行设备reset函数的接口i2c_reset_device:

/**

* i2c_reset_device - reset I2C device when bus dead

* @adapter: the adapter being reset

* @addr: the device address

*/

static int __i2c_reset_device(struct device *dev, void *addrp)

{

struct i2c_client *client = to_i2c_client(dev);

int addr = *(int *)addrp;



if (client && client->driver && client->driver->reset)

return client->driver->reset();



return 0;

}



int i2c_reset_device(struct i2c_adapter *adapter, int addr)

{

return device_for_each_child(&adapter->dev, &addr, __i2c_reset_device);

}

EXPORT_SYMBOL(i2c_reset_device);

需要注意的是i2c.driver的reset函数返回值需要为0,不然device_for_each_child不会继续后面的遍历。用GPIO模拟SCL解锁的参考代码如下:

static int i2c_reset_adapter(void) 

{

int counter = 0;



gpio_request(I2C_BUS_DATA, "gpioxx");

gpio_request(I2C_BUS_CLK, "gpioxx");

/* try to recover I2C bus */

gpio_direction_input(I2C_BUS_DATA);



if (!__gpio_get_value(I2C_BUS_DATA)) {

while((!__gpio_get_value(I2C_BUS_DATA)) && ++counter < 10)

{

udelay(5);

gpio_direction_output(I2C_BUS_CLK, 1);

udelay(5);

gpio_direction_output(I2C_BUS_CLK, 0);

}

i2c_err("try to recover i2c bus, retry times are %d\n",counter);

if (counter < 10) {

udelay(5);

gpio_direction_output(I2C_BUS_DATA, 0);

udelay(5);

gpio_direction_output(I2C_BUS_CLK, 1);

udelay(5);

gpio_direction_output(I2C_BUS_DATA, 1);

msleep(10);

} else {

i2c_err("try to recover i2c bus failed!\n");

}

}



gpio_free(I2C_BUS_DATA);

gpio_free(I2C_BUS_CLK);



return 0;

}

标签:reset,i2c,adapter,编程,接口,client,msg,I2C
From: https://blog.51cto.com/tody/6022265

相关文章

  • Shell编程
    Shell是一个命令行解释器,接受应用程序或者用户的命令,然后调用操作系统的内核.sh是Linux批处理脚本文件的后缀名,是一组命令sh是bash的一个软链接也就是一个快捷方式 运......
  • 假如女人是一种编程语言
    “面向过程”和“面向对象”。“面向对象”的女人以寻找终身伴侣为目标,而“面向过程”的,则以经历难以忘怀的爱情时光为己任。各位程序猿当然也要按需选择最适合自己的“编程......
  • Python实现网络通信——TCP编程
    TCP编程  服务器端代码'''connect(address)链接远程计算机send(bytes[,flags])发送数据recv(bufsize[,flags])发送数据bind(address)绑定地址liste......
  • 第七章(接口)
    接口定义接口代表一种调用契约,是多个方法声明的集合Go接口实现机制很简洁,只要目标类型方法集合包含接口声明的全部方法,就被视为实现了该接口,无须做显式声明。目标......
  • 编程软件基础知识(杂记)
    1电脑知识1.12编译型语言和解释型语言编程语言分为编译型语言和解释型语言2.1编译型语言C和C++这两种语言是编译型语言,编译型语言的特点是执行速度快,缺点是什么呢?......
  • (八)Java网络编程
    Java网络编程1、tcp和udp的区别TCP,TransmissionControlProtocol的缩写,即传输控制协议。1)面向连接,即必须在双方建立可靠连接之后,才会收发数据2)信息包头20个字节3)......
  • 新人入门编程如何选择编程语言
    新人入门编程选择编程语言时,应该考虑以下几点:易学性:选择易于学习和理解的编程语言,可以让新人更快地入门。应用领域:根据自己的兴趣和未来发展规划来选择适合自己的编程语言......
  • 通用8位SPI接口模块——verilog实现
    本次设计一个八位的SPI的接口模块,可以修改输出的频率,也可以通过修改参数来设置通信模式。本模块是设定生成一个目标输出频率的二倍计数器,然后通关计数的值来输出响应的信......
  • Python的UDP网络编程
    UDP编程通信协议有,UDP和TCP模式:1、TCP适用于效率较低,精度较高的场景(文件传输、电子邮件)2、UDP适用于效率较高(视频在线点播,网络语音通话等)接下来的代码介绍的是UDP协议......
  • 网络编程
    目录网络编程一、OSI七层协议1.OSI七层协议之物理链接层2.OSI七层协议之数据链路层3.OSI七层协议之网络层4.OSI七层协议之传输层5.OSI七层协议之会话层6.OSI七层协议之表示......