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

 

       吃个晚饭,画个流程图,没想到已经这么晚了。还是速度把这篇文章搞定,收拾回去了。

先看下linux中的i2c的数据流程图吧。这里主要是用gpio模拟的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的数据流程就是这样了。具体的很多细节都没有分析,可以通过细读代码来理解。

posted on 2012-09-11 07:52  吴一达  阅读(772)  评论(0编辑  收藏  举报

导航