和菜鸟一起学linux总线驱动之初识i2c驱动数据传输流程

时间:2023-01-13 08:59:11


 

      

先看下linux中的i2c的数据流程图吧。这里主要是用gpio模拟的i2c的。


 

和菜鸟一起学linux总线驱动之初识i2c驱动数据传输流程

还是具体看下代码吧,流程只是个大概,和i2c的总线协议差不多的。

 

首先从数据调用来看吧。一般的都是通过

i2c_transfer来来实现的,

 



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) {

#ifdef DEBUG

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

dev_dbg(&adap->dev, "master_xfer[%d] %c, addr=0x%02x, "

"len=%d%s\n", ret, (msgs[ret].flags & I2C_M_RD)

? 'R' : 'W', msgs[ret].addr, msgs[ret].len,

(msgs[ret].flags & I2C_M_RECV_LEN) ? "+" : "");

}

#endif



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

ret = i2c_trylock_adapter(adap);

if (!ret)

/* I2C activity is ongoing. */

return -EAGAIN;

} else {

i2c_lock_adapter(adap);

}



/* Retry automatically on arbitration loss */

orig_jiffies = jiffies;

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

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

if (ret != -EAGAIN)

break;

if (time_after(jiffies, orig_jiffies + adap->timeout))

break;

}

i2c_unlock_adapter(adap);



return ret;

} else {

dev_dbg(&adap->dev, "I2C level transfers not supported\n");

return -EOPNOTSUPP;

}

}

 

adap->algo->master_xfer,通过这个函数指针,这个函数指针赋值先看下面的代码

 

在drivers/i2c/busses/i2c-gpio.c中

 



static int __devinit i2c_gpio_probe(struct platform_device *pdev)

{

struct i2c_gpio_platform_data *pdata;

struct i2c_algo_bit_data *bit_data;

struct i2c_adapter *adap;

int ret;



pdata = pdev->dev.platform_data;

if (!pdata)

return -ENXIO;



ret = -ENOMEM;

adap = kzalloc(sizeof(struct i2c_adapter), GFP_KERNEL);

if (!adap)

goto err_alloc_adap;

bit_data = kzalloc(sizeof(struct i2c_algo_bit_data), GFP_KERNEL);

if (!bit_data)

goto err_alloc_bit_data;



ret = gpio_request(pdata->sda_pin, "sda");

if (ret)

goto err_request_sda;

ret = gpio_request(pdata->scl_pin, "scl");

if (ret)

goto err_request_scl;



if (pdata->sda_is_open_drain) {

gpio_direction_output(pdata->sda_pin, 1);

bit_data->setsda = i2c_gpio_setsda_val;

} else {

gpio_direction_input(pdata->sda_pin);

bit_data->setsda = i2c_gpio_setsda_dir;

}



if (pdata->scl_is_open_drain || pdata->scl_is_output_only) {

gpio_direction_output(pdata->scl_pin, 1);

bit_data->setscl = i2c_gpio_setscl_val;

} else {

gpio_direction_input(pdata->scl_pin);

bit_data->setscl = i2c_gpio_setscl_dir;

}



if (!pdata->scl_is_output_only)

bit_data->getscl = i2c_gpio_getscl;

bit_data->getsda = i2c_gpio_getsda;



if (pdata->udelay)

bit_data->udelay = pdata->udelay;

else if (pdata->scl_is_output_only)

bit_data->udelay = 50; /* 10 kHz */

else

bit_data->udelay = 5; /* 100 kHz */



if (pdata->timeout)

bit_data->timeout = pdata->timeout;

else

bit_data->timeout = HZ / 10; /* 100 ms */



bit_data->data = pdata;



adap->owner = THIS_MODULE;

snprintf(adap->name, sizeof(adap->name), "i2c-gpio%d", pdev->id);

adap->algo_data = bit_data;

adap->class = I2C_CLASS_HWMON | I2C_CLASS_SPD;

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



/*

* If "dev->id" is negative we consider it as zero.

* The reason to do so is to avoid sysfs names that only make

* sense when there are multiple adapters.

*/

adap->nr = (pdev->id != -1) ? pdev->id : 0;

ret = i2c_bit_add_numbered_bus(adap);

if (ret)

goto err_add_bus;



platform_set_drvdata(pdev, adap);



dev_info(&pdev->dev, "using pins %u (SDA) and %u (SCL%s)\n",

pdata->sda_pin, pdata->scl_pin,

pdata->scl_is_output_only

? ", no clock stretching" : "");



return 0;



err_add_bus:

gpio_free(pdata->scl_pin);

err_request_scl:

gpio_free(pdata->sda_pin);

err_request_sda:

kfree(bit_data);

err_alloc_bit_data:

kfree(adap);

err_alloc_adap:

return ret;

}

 

看到了

ret = i2c_bit_add_numbered_bus(adap);

然后这个函数是在

Drivers/i2c/algo/i2c-algo-bit.c中

 



int i2c_bit_add_numbered_bus(struct i2c_adapter *adap)

{

return __i2c_bit_add_bus(adap, i2c_add_numbered_adapter);

}

然后



int i2c_bit_add_bus(struct i2c_adapter *adap)

{

return __i2c_bit_add_bus(adap, i2c_add_adapter);

}

 

接着调用这个函数



static int __i2c_bit_add_bus(struct i2c_adapter *adap,

int (*add_adapter)(struct i2c_adapter *))

{

struct i2c_algo_bit_data *bit_adap = adap->algo_data;

int ret;



if (bit_test) {

ret = test_bus(adap);

if (ret < 0)

return -ENODEV;

}



/* register new adapter to i2c module... */

adap->algo = &i2c_bit_algo;

adap->retries = 3;



ret = add_adapter(adap);

if (ret < 0)

return ret;



/* Complain if SCL can't be read */

if (bit_adap->getscl == NULL) {

dev_warn(&adap->dev, "Not I2C compliant: can't read SCL\n");

dev_warn(&adap->dev, "Bus may be unreliable\n");

}

return 0;

}

 

然后可以看到这两句

adap->algo = &i2c_bit_algo;

adap->retries = 3;

 

算法指向了i2c_bit_algo,尝试3次。

 

接着,我们回到刚才的调用adap->algo->master_xfer。然后就是

 



static const struct i2c_algorithm i2c_bit_algo = {

.master_xfer = bit_xfer,

.functionality = bit_func,

};

 

这个函数指针调用的是bit_xfer函数

 



static int bit_xfer(struct i2c_adapter *i2c_adap,

struct i2c_msg msgs[], int num)

{

struct i2c_msg *pmsg;

struct i2c_algo_bit_data *adap = i2c_adap->algo_data;

int i, ret;

unsigned short nak_ok;



if (adap->pre_xfer) {

ret = adap->pre_xfer(i2c_adap);

if (ret < 0)

return ret;

}



bit_dbg(3, &i2c_adap->dev, "emitting start condition\n");

i2c_start(adap);

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

pmsg = &msgs[i];

nak_ok = pmsg->flags & I2C_M_IGNORE_NAK;

if (!(pmsg->flags & I2C_M_NOSTART)) {

if (i) {

bit_dbg(3, &i2c_adap->dev, "emitting "

"repeated start condition\n");

i2c_repstart(adap);

}

ret = bit_doAddress(i2c_adap, pmsg);

if ((ret != 0) && !nak_ok) {

bit_dbg(1, &i2c_adap->dev, "NAK from "

"device addr 0x%02x msg #%d\n",

msgs[i].addr, i);

goto bailout;

}

}

if (pmsg->flags & I2C_M_RD) {

/* read bytes into buffer*/

ret = readbytes(i2c_adap, pmsg);

if (ret >= 1)

bit_dbg(2, &i2c_adap->dev, "read %d byte%s\n",

ret, ret == 1 ? "" : "s");

if (ret < pmsg->len) {

if (ret >= 0)

ret = -EREMOTEIO;

goto bailout;

}

} else {

/* write bytes from buffer */

ret = sendbytes(i2c_adap, pmsg);

if (ret >= 1)

bit_dbg(2, &i2c_adap->dev, "wrote %d byte%s\n",

ret, ret == 1 ? "" : "s");

if (ret < pmsg->len) {

if (ret >= 0)

ret = -EREMOTEIO;

goto bailout;

}

}

}

ret = i;



bailout:

bit_dbg(3, &i2c_adap->dev, "emitting stop condition\n");

i2c_stop(adap);



if (adap->post_xfer)

adap->post_xfer(i2c_adap);

return ret;

}

 

这里就是算法的所有过程了。根据协议来,先发个i2c_start(adap);



/* --- other auxiliary functions --------------------------------------      */

static void i2c_start(struct i2c_algo_bit_data *adap)

{

/* assert: scl, sda are high */

setsda(adap, 0);

udelay(adap->udelay);

scllo(adap);

}

 

 

然后再发送设备地址,ret = bit_doAddress(i2c_adap, pmsg);



static int bit_doAddress(struct i2c_adapter *i2c_adap, struct i2c_msg *msg)

{

unsigned short flags = msg->flags;

unsigned short nak_ok = msg->flags & I2C_M_IGNORE_NAK;

struct i2c_algo_bit_data *adap = i2c_adap->algo_data;



unsigned char addr;

int ret, retries;



retries = nak_ok ? 0 : i2c_adap->retries;



if (flags & I2C_M_TEN) {

/* a ten bit address */

addr = 0xf0 | ((msg->addr >> 7) & 0x06);

bit_dbg(2, &i2c_adap->dev, "addr0: %d\n", addr);

/* try extended address code...*/

ret = try_address(i2c_adap, addr, retries);

if ((ret != 1) && !nak_ok) {

dev_err(&i2c_adap->dev,

"died at extended address code\n");

return -EREMOTEIO;

}

/* the remaining 8 bit address */

ret = i2c_outb(i2c_adap, msg->addr & 0xff);

if ((ret != 1) && !nak_ok) {

/* the chip did not ack / xmission error occurred */

dev_err(&i2c_adap->dev, "died at 2nd address code\n");

return -EREMOTEIO;

}

if (flags & I2C_M_RD) {

bit_dbg(3, &i2c_adap->dev, "emitting repeated "

"start condition\n");

i2c_repstart(adap);

/* okay, now switch into reading mode */

addr |= 0x01;

ret = try_address(i2c_adap, addr, retries);

if ((ret != 1) && !nak_ok) {

dev_err(&i2c_adap->dev,

"died at repeated address code\n");

return -EREMOTEIO;

}

}

} else { /* normal 7bit address */

addr = msg->addr << 1;

if (flags & I2C_M_RD)

addr |= 1;

if (flags & I2C_M_REV_DIR_ADDR)

addr ^= 1;

ret = try_address(i2c_adap, addr, retries);

if ((ret != 1) && !nak_ok)

return -ENXIO;

}



return 0;

}

 

这里尝试3次,ret = try_address(i2c_adap, addr, retries);



static int try_address(struct i2c_adapter *i2c_adap,

unsigned char addr, int retries)

{

struct i2c_algo_bit_data *adap = i2c_adap->algo_data;

int i, ret = 0;



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

ret = i2c_outb(i2c_adap, addr);

if (ret == 1 || i == retries)

break;

bit_dbg(3, &i2c_adap->dev, "emitting stop condition\n");

i2c_stop(adap);

udelay(adap->udelay);

yield();

bit_dbg(3, &i2c_adap->dev, "emitting start condition\n");

i2c_start(adap);

}

if (i && ret)

bit_dbg(1, &i2c_adap->dev, "Used %d tries to %s client at "

"0x%02x: %s\n", i + 1,

addr & 1 ? "read from" : "write to", addr >> 1,

ret == 1 ? "success" : "failed, timeout?");

return ret;

}

 

这个ret = i2c_outb(i2c_adap, addr);是发送一个字节的函数,其具体就是通过gpio的拉高拉低来实现的

 



/* send a byte without start cond., look for arbitration,

check ackn. from slave */

/* returns:

* 1 if the device acknowledged

* 0 if the device did not ack

* -ETIMEDOUT if an error occurred (while raising the scl line)

*/

static int i2c_outb(struct i2c_adapter *i2c_adap, unsigned char c)

{

int i;

int sb;

int ack;

struct i2c_algo_bit_data *adap = i2c_adap->algo_data;



/* assert: scl is low */

for (i = 7; i >= 0; i--) {

sb = (c >> i) & 1;

setsda(adap, sb);

udelay((adap->udelay + 1) / 2);

if (sclhi(adap) < 0) { /* timed out */

bit_dbg(1, &i2c_adap->dev, "i2c_outb: 0x%02x, "

"timeout at bit #%d\n", (int)c, i);

return -ETIMEDOUT;

}

/* FIXME do arbitration here:

* if (sb && !getsda(adap)) -> ouch! Get out of here.

*

* Report a unique code, so higher level code can retry

* the whole (combined) message and *NOT* issue STOP.

*/

scllo(adap);

}

sdahi(adap);

if (sclhi(adap) < 0) { /* timeout */

bit_dbg(1, &i2c_adap->dev, "i2c_outb: 0x%02x, "

"timeout at ack\n", (int)c);

return -ETIMEDOUT;

}



/* read ack: SDA should be pulled down by slave, or it may

* NAK (usually to report problems with the data we wrote).

*/

ack = !getsda(adap); /* ack: sda is pulled low -> success */

bit_dbg(2, &i2c_adap->dev, "i2c_outb: 0x%02x %s\n", (int)c,

ack ? "A" : "NA");



scllo(adap);

return ack;

/* assert: scl is low (sda undef) */

}

 

然后根据if (pmsg->flags & I2C_M_RD)这个来判断是发送数据,还是接收数据。

如果是接收数据,那么

 



ret = readbytes(i2c_adap, pmsg);

 



static int readbytes(struct i2c_adapter *i2c_adap, struct i2c_msg *msg)

{

int inval;

int rdcount = 0; /* counts bytes read */

unsigned char *temp = msg->buf;

int count = msg->len;

const unsigned flags = msg->flags;



while (count > 0) {

inval = i2c_inb(i2c_adap);

if (inval >= 0) {

*temp = inval;

rdcount++;

} else { /* read timed out */

break;

}



temp++;

count--;



/* Some SMBus transactions require that we receive the

transaction length as the first read byte. */

if (rdcount == 1 && (flags & I2C_M_RECV_LEN)) {

if (inval <= 0 || inval > I2C_SMBUS_BLOCK_MAX) {

if (!(flags & I2C_M_NO_RD_ACK))

acknak(i2c_adap, 0);

dev_err(&i2c_adap->dev, "readbytes: invalid "

"block length (%d)\n", inval);

return -EREMOTEIO;

}

/* The original count value accounts for the extra

bytes, that is, either 1 for a regular transaction,

or 2 for a PEC transaction. */

count += inval;

msg->len += inval;

}



bit_dbg(2, &i2c_adap->dev, "readbytes: 0x%02x %s\n",

inval,

(flags & I2C_M_NO_RD_ACK)

? "(no ack/nak)"

: (count ? "A" : "NA"));



if (!(flags & I2C_M_NO_RD_ACK)) {

inval = acknak(i2c_adap, count);

if (inval < 0)

return inval;

}

}

return rdcount;

}

 

然后通过这个inval = i2c_inb(i2c_adap);

 



static int i2c_inb(struct i2c_adapter *i2c_adap)

{

/* read byte via i2c port, without start/stop sequence */

/* acknowledge is sent in i2c_read. */

int i;

unsigned char indata = 0;

struct i2c_algo_bit_data *adap = i2c_adap->algo_data;



/* assert: scl is low */

sdahi(adap);

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

if (sclhi(adap) < 0) { /* timeout */

bit_dbg(1, &i2c_adap->dev, "i2c_inb: timeout at bit "

"#%d\n", 7 - i);

return -ETIMEDOUT;

}

indata *= 2;

if (getsda(adap))

indata |= 0x01;

setscl(adap, 0);

udelay(i == 7 ? adap->udelay / 2 : adap->udelay);

}

/* assert: scl is low */

return indata;

}

 

这样就把数据接收到了。

 

如果是发送数据的话,那么就是ret = sendbytes(i2c_adap, pmsg);

 



static int sendbytes(struct i2c_adapter *i2c_adap, struct i2c_msg *msg)

{

const unsigned char *temp = msg->buf;

int count = msg->len;

unsigned short nak_ok = msg->flags & I2C_M_IGNORE_NAK;

int retval;

int wrcount = 0;



while (count > 0) {

retval = i2c_outb(i2c_adap, *temp);



/* OK/ACK; or ignored NAK */

if ((retval > 0) || (nak_ok && (retval == 0))) {

count--;

temp++;

wrcount++;



/* A slave NAKing the master means the slave didn't like

* something about the data it saw. For example, maybe

* the SMBus PEC was wrong.

*/

} else if (retval == 0) {

dev_err(&i2c_adap->dev, "sendbytes: NAK bailout.\n");

return -EIO;



/* Timeout; or (someday) lost arbitration

*

* FIXME Lost ARB implies retrying the transaction from

* the first message, after the "winning" master issues

* its STOP. As a rule, upper layer code has no reason

* to know or care about this ... it is *NOT* an error.

*/

} else {

dev_err(&i2c_adap->dev, "sendbytes: error %d\n",

retval);

return retval;

}

}

return wrcount;

}

 

然后通过retval = i2c_outb(i2c_adap, *temp);

发送出给从机。

 

最后

i2c_stop(adap);

 

数据发送完了

 



static void i2c_stop(struct i2c_algo_bit_data *adap)

{

/* assert: scl is low */

sdalo(adap);

sclhi(adap);

setsda(adap, 1);

udelay(adap->udelay);

}

 

好了,整个gpio模拟的i2c的数据流程就是这样了。具体的很多细节都没有分析,可以通过细读代码来理解。