cod*_*007 3 linux driver device i2c linux-kernel
我想从i2c slave读取,需要多次启动操作才能读取其寄存器值.
在某种程度上,我已经在Linux内核3.18.21中跟踪了I2C驱动程序,我发现它不支持多启动操作,我无法读取此I2C从设备(以太网供电管理器PD69104B1).
如果需要这个i2c从站或其他任何需要,我仍然可以找到扩展驱动程序的方法.
我使用i2c-tools 3.2.1.我试着
$ i2cdump -y 0 0x20
Run Code Online (Sandbox Code Playgroud)
但我可以看到相同的值,这意味着它每次都会读取第一个寄存器.
$ i2cget -y 0 0x20 0x12
Run Code Online (Sandbox Code Playgroud)
或任何其他寄存器地址返回与第一个寄存器相同的值.
这个slave支持两个读操作:
我尝试了所有可能的方法:
i2c_smbus_access()
i2c_smbus_write_byte()
i2c_smbus_read_block_data()
write()
read()
但是大部分时间i2c总线都会进入超时错误并挂起情况.
任何人都知道如何在Linux中实现这一目标?
这个I2C从器件需要独特的读周期:
方向改变:S Addr Wr [A] RegAddress [A] S Addr Rd [A] [RegValue] P
简短阅读:S Addr Rd [A] [RegValue] P.
这里从i2c slave返回的最后一个值不期望ACK.
我尝试使用I2C_M_NO_RD_ACK但没有多大帮助.我读了一些值,然后得到FF.
这个POE I2C从器件在SCL上有超过14ms的i2c时间,这有点让人怀疑.这看起来像i2c非标准,因为i2c可以在0HZ上工作,即SCL可以被主人拉伸,只要它想要.Linux绝对不是实时操作系统,因此无法保证实现此时间,并且可能会发生i2c slave SCL超时复位.这就是我目前的结论!
使用的I2C消息表示法来自:https: //www.kernel.org/doc/Documentation/i2c/i2c-protocol
为什么linux中不支持重复启动的i2c操作?
事实上,它们得到了支持.
如果您正在寻找在执行重复的启动条件的方式用户空间,你可能需要做ioctl()
有I2C_RDWR
要求,喜欢它的描述在这里(见原题最后的代码段),并在这里(代码有问题).
下面描述了在内核空间中执行重复启动的方法.
在Linux内核中,默认情况下,对组合(写入/读取)消息执行具有重复启动条件的 I2C读取操作.
以下是如何执行组合I2C传输的示例:
/**
* Read set of registers via I2C using "repeated start" condition.
*
* Two I2C messages are being sent by this function:
* 1. I2C write operation (write register address) with no STOP bit in the end
* 2. I2C read operation
*
* @client: I2C client structure
* @reg: register address (subaddress)
* @len: bytes count to read
* @buf: buffer which will contain read data
*
* Returns 0 on success or negative value on error.
*/
static int i2c_read_regs(struct i2c_client *client, u8 reg, u8 len, u8 *buf)
{
int ret;
struct i2c_msg msg[2] = {
{
.addr = client->addr,
.len = 1,
.buf = ®,
},
{
.addr = client->addr,
.flags = I2C_M_RD,
.len = len,
.buf = buf,
}
};
ret = i2c_transfer(client->adapter, msg, 2);
if (ret < 0) {
dev_err(&client->dev, "I2C read failed\n");
return ret;
}
return 0;
}
Run Code Online (Sandbox Code Playgroud)
要只读取1个字节(单个寄存器值),您可以使用下一个辅助函数:
/**
* Read one register via I2C using "repeated start" condition.
*
* @client: I2C client structure
* @reg: register address (subaddress)
* @val: variable to store read value
*
* Returns 0 on success or negative value on error.
*/
static int i2c_read_reg(struct i2c_client *client, u8 reg, u8 *val)
{
return i2c_read_regs(client, reg, 1, val);
}
Run Code Online (Sandbox Code Playgroud)
以下是i2c_read_regs(client, reg, 1, val)
电话的说明:
client->addr
reg
1
意味着我们要读取1个字节的数据(图片上的粉红色矩形)val
注意:如果您的I2C控制器(或其驱动程序)不支持在组合消息中重复启动,您仍然可以使用I2C的bit-bang实现,即i2c-gpio驱动程序.
如果没有任何作用,你可以尝试下一个作为最后的手段.出于某种原因,我不太记得了,为了使重复开始工作,我需要添加I2C_M_NOSTART
到.flags
第一条消息,像这样的:
struct i2c_msg msg[2] = {
{
.addr = client->addr,
.flags = I2C_M_NOSTART,
.len = 1,
.buf = ®,
},
{
.addr = client->addr,
.flags = I2C_M_RD,
.len = len,
.buf = buf,
}
};
Run Code Online (Sandbox Code Playgroud)
如Documentation/i2c/i2c-protocol
:
如果
I2C_M_NOSTART
为第一个部分消息设置变量,我们不会生成Addr
,但我们会生成startbitS
.
参考文献:
[1] STLinux上的I2C