您的位置:首页 > 运维架构 > Linux

Linux I2C驱动分析(二)----I2C板级设备扫描和数据传输

2015-01-08 16:48 531 查看

一、板级设备扫描

        针对上一篇博客最后的i2c_scan_static_board_info(adap)函数处,首先先看下在系统启动的时候板级设备的注册。

        针对我现在使用的开发板,对于I2C设备注册程序如下:

点击(此处)折叠或打开

static struct i2c_board_info i2c_devices_info[]
= {

#ifdef CONFIG_SND_SOC_ALC5623

        {

                I2C_BOARD_INFO("alc5623", 0x1a),

                .platform_data
= &alc5623_data,

        },

#endif

#ifdef CONFIG_RTC_DRV_DS3231M

        {

                I2C_BOARD_INFO("ds3231m", 0x68),

                .platform_data
= NULL,

        },

#endif

#ifdef CONFIG_RTC_DRV_PCF8563

        {

                I2C_BOARD_INFO("pcf8563", 0x51),

                .platform_data
= NULL,

        },

#endif

};

static int __init gsc3280_i2c_devices_init(void)

{

    i2c_register_board_info(0, i2c_devices_info,
ARRAY_SIZE(i2c_devices_info));

    return 0;

}

device_initcall(gsc3280_i2c_devices_init);

       
在这里总共有三个I2C设备,名称分别为alc5623、ds3231m和pcf8563。宏I2C_BOARD_INFO的功能就是设置I2C设备的名称和地址,由device_initcall可以看出,gsc3280_i2c_devices_init()函数在系统启动的时候就会被调用,i2c_register_board_info()函数完成板级设备的注册,程序如下:

点击(此处)折叠或打开

DECLARE_RWSEM(__i2c_board_lock);

EXPORT_SYMBOL_GPL(__i2c_board_lock);

LIST_HEAD(__i2c_board_list);

EXPORT_SYMBOL_GPL(__i2c_board_list);

int __i2c_first_dynamic_bus_num;

EXPORT_SYMBOL_GPL(__i2c_first_dynamic_bus_num);

int __init

i2c_register_board_info(int busnum,

    struct i2c_board_info const
*info, unsigned
len)

{

    int status;

    down_write(&__i2c_board_lock);

    /* dynamic bus numbers will be assigned after the last static one
*/

    if (busnum
>= __i2c_first_dynamic_bus_num)

        __i2c_first_dynamic_bus_num = busnum
+ 1;

    for (status
= 0;
len; len--, info++)
{

        struct i2c_devinfo    *devinfo;

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

        if (!devinfo)
{

            pr_debug("i2c-core: can't register boardinfo!\n");

            status =
-ENOMEM;

            break;

        }

        devinfo->busnum
= busnum;

        devinfo->board_info
= *info;

        list_add_tail(&devinfo->list,
&__i2c_board_list);

    }

    up_write(&__i2c_board_lock);

    return status;

}

        上面的程序位于i2c-boardinfo.c中,i2c_register_board_info()函数的for循环中,首先会申请I2C设备信息结构体,如果申请成功,将I2C总线号和设备信息赋值给设备信息结构体,并且将设备信息结构体的链表插入到__i2c_board_list中,此处尤为重要,在本文的开头中所提的函数i2c_scan_static_board_info(adap);,此函数就是通过__i2c_board_list链表找到上面注册的设备信息,结合gsc3280_i2c_devices_init()函数和i2c_devices_info结构体,此处for循环的len为3,即正常情况下需要创建三个devinfo结构体,for循环结束后,__i2c_board_list链表中也就有了三个I2C设备的链表项,在程序的其他地方如果需要使用这里注册的设备结构信息,只需要遍历链表__i2c_board_list,通过总线号即可找到相应的设备信息。

       
接下来就可以看下函数i2c_scan_static_board_info(adap):

点击(此处)折叠或打开

static void i2c_scan_static_board_info(struct i2c_adapter
*adapter)

{

    struct i2c_devinfo    *devinfo;

    down_read(&__i2c_board_lock);

    list_for_each_entry(devinfo,
&__i2c_board_list, list)
{

        if (devinfo->busnum
== adapter->nr

                &&
!i2c_new_device(adapter,

                        &devinfo->board_info))

            dev_err(&adapter->dev,

                "Can't create device at 0x%02x\n",

                devinfo->board_info.addr);

    }

    up_read(&__i2c_board_lock);

}

       
从上面程序可以看到,语句list_for_each_entry(devinfo,
&__i2c_board_list, list)
实现对__i2c_board_list的遍历,if语句的前半部分“devinfo->busnum
== adapter->nr”判断是否是需要寻找的结构体,如果是,就调用函数i2c_new_device()创建新的I2C设备,i2c_new_device函数如下:

点击(此处)折叠或打开

struct i2c_client *

i2c_new_device(struct i2c_adapter
*adap, struct i2c_board_info
const *info)

{

    struct i2c_client    *client;

    int            status;

    client = kzalloc(sizeof
*client, GFP_KERNEL);

    if (!client)

        return NULL;

    client->adapter
= adap;

    client->dev.platform_data
= info->platform_data;

    if (info->archdata)

        client->dev.archdata
= *info->archdata;

    client->flags
= info->flags;

    client->addr
= info->addr;

    client->irq
= info->irq;

    strlcpy(client->name, info->type,
sizeof(client->name));

    /* Check
for address validity
*/

    status = i2c_check_client_addr_validity(client);

    if (status)
{

        dev_err(&adap->dev,
"Invalid %d-bit I2C address 0x%02hx\n",

            client->flags
& I2C_CLIENT_TEN ? 10
: 7, client->addr);

        goto out_err_silent;

    }

    /* Check
for address business
*/

    status = i2c_check_addr_busy(adap, client->addr);

    if (status)

        goto out_err;

    client->dev.parent
= &client->adapter->dev;

    client->dev.bus
= &i2c_bus_type;

    client->dev.type
= &i2c_client_type;

    client->dev.of_node
= info->of_node;

    dev_set_name(&client->dev,
"%d-%04x", i2c_adapter_id(adap),

         client->addr);

    status = device_register(&client->dev);

    if (status)

        goto out_err;

    dev_dbg(&adap->dev,
"client [%s] registered with bus id %s\n",

        client->name, dev_name(&client->dev));

    return client;

out_err:

    dev_err(&adap->dev,
"Failed to register i2c client %s at 0x%02x "

        "(%d)\n", client->name, client->addr,
status);

out_err_silent:

    kfree(client);

    return NULL;

}

EXPORT_SYMBOL_GPL(i2c_new_device);

       
从函数i2c_new_device()中可以看到,此函数创建了i2c_client结构体,对结构体的内容进行了注册,设备信息进行了填充,对于本文所使用的开发板,如果程序执行正常,系统启动成功后,在内存中就有了三个

i2c_client结构体了,分别对应alc5623、ds3231m和pcf8563。

       
到此位置,I2C总线驱动,I2C设备的注册和相应结构体的申请就已经完成了,接下来看下常用的I2C数据传输函数,I2C设备驱动主要调用这些数据传输接口完成数据的传输。

二、I2C数据传输

       
I2C数据传输分为两种,一种为符合I2C协议的普通数据传输,另外一种为符合SMBUS协议的数据传输,接下来我们首先看下符合I2C协议的普通数据传输。

1、I2C协议的普通数据传输

       
I2C协议普通数据传输的接口函数基本为i2c_master_send和i2c_master_recv,查看其函数发现,最后都是调用i2c_transfer函数实现传输的,i2c_transfer函数如下:

点击(此处)折叠或打开

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

{

    int ret;

    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 = mutex_trylock(&adap->bus_lock);

            if
(!ret)

                /* I2C activity
is ongoing.
*/

                return -EAGAIN;

        } else
{

            mutex_lock_nested(&adap->bus_lock, adap->level);

        }

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

        mutex_unlock(&adap->bus_lock);

        return ret;

    } else
{

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

        return -ENOSYS;

    }

}

       
因为在这里的同步用的是mutex。首先判断是否允许睡眠,如果不允许,尝试获锁,如果获锁失败,则返回。这样的操作是避免进入睡眠,我们在后面也可以看到,实际的传输工作交给了adap->algo->master_xfer()完成,也就是我们在(一)中注册的algorithm中的i2c_gsc_func函数。

2、SMBUS协议I2C数据传输

       
SMBUS协议的具体内容可以参考网络,在I2C驱动中,符合SMBUS协议传输的函数很多,包括i2c_smbus_read_byte、i2c_smbus_write_byte、i2c_smbus_read_byte_data、i2c_smbus_write_byte_data、i2c_smbus_read_word_data和i2c_smbus_write_word_data等,阅读这些函数发现,程序里面都是根据SMBUS协议和函数功能,完成对函数i2c_smbus_xfer形参的赋值,最后调用此函数来实现传输。接下来看下i2c_smbus_xfer函数:

点击(此处)折叠或打开

s32 i2c_smbus_xfer(struct i2c_adapter
*adapter, u16 addr, unsigned short flags,

         char read_write, u8 command,
int protocol,

         union i2c_smbus_data *data)

{

    unsigned long orig_jiffies;

    int try;

    s32 res;

    flags &= I2C_M_TEN
| I2C_CLIENT_PEC;

    if (adapter->algo->smbus_xfer)
{

        i2c_lock_adapter(adapter);

        /* Retry automatically
on arbitration loss
*/

        orig_jiffies = jiffies;

        for (res
= 0, try
= 0; try <= adapter->retries; try++)
{

            res = adapter->algo->smbus_xfer(adapter,
addr, flags,

                            read_write, command,

                            protocol, data);

            if
(res !=
-EAGAIN)

                break;

            if
(time_after(jiffies,

                 orig_jiffies + adapter->timeout))

                break;

        }

        i2c_unlock_adapter(adapter);

    } else

        res = i2c_smbus_xfer_emulated(adapter, addr, flags, read_write,

                     command, protocol, data);

    return res;

}

          如果adapter有smbus_xfer()函数,则直接调用它发送数据。否则也就是在adapter不支持smbus协议的情况下,调用i2c_smbus_xfer_emulated()继续处理。根据(一)中的总线驱动是不支持smbus协议的。继续看函数i2c_smbus_xfer_emulated。

点击(此处)折叠或打开

static s32 i2c_smbus_xfer_emulated(struct i2c_adapter
* adapter, u16 addr,

                                  unsigned short flags,

                                  char read_write, u8 command,
int size,

                                  union i2c_smbus_data
* data)

{

    /* So we need
to generate a series of msgs.
In the case of writing, we

      need to use only one message; when reading, we need two. We initialize

      most things with sane defaults,
to keep the code below somewhat

      simpler.
*/

    //写操作只会进行一次交互,而读操作,有时会有两次操作.

    //因为有时候读操作要先写command,再从总线上读数据

    //在这里为了代码的简洁,使用了两个缓存区,将两种情况统一起来.

    unsigned char msgbuf0[I2C_SMBUS_BLOCK_MAX+3];

    unsigned char msgbuf1[I2C_SMBUS_BLOCK_MAX+2];

    //一般来说,读操作要交互两次,例外的情况我们在下面会接着分析

    int num = read_write
== I2C_SMBUS_READ?2:1;

    //与设备交互的数据,一般在msg[0]存放写入设备的信息,在msb[1]里存放接收到的

    //信息,不过也有例外的

    //msg[2]的初始化,默认发送缓存区占一个字节,无接收缓存

    struct i2c_msg msg[2]
= {
{ addr, flags, 1, msgbuf0
},

                              { addr, flags
| I2C_M_RD, 0, msgbuf1
}

                            };

    int i;

    u8 partial_pec = 0;

    //将要发送的信息copy到发送缓存区的第一字节

    msgbuf0[0]
= command;

    switch(size)
{

        //quick类型,它并不传输有效数据,只是将地址写到总线上,等待应答即可

        //所以将发送缓存区长度置为0。再根据读/写操作,调整msg[0]的标志位

        //这类传输只需要一次总线交互

    case I2C_SMBUS_QUICK:

        msg[0].len
= 0;

        /* Special
case: The read/write field
is used as data */

        msg[0].flags
= flags |
(read_write==I2C_SMBUS_READ)?I2C_M_RD:0;

        num = 1;

        break;

    case I2C_SMBUS_BYTE:

        //BYTE类型指一次写和读只有一个字节.这种情况下,读和写都只会交互一次

        //这种类型的读有例外,它读取出来的数据不是放在msg[1]中的,而是存放在msg[0]

        if (read_write
== I2C_SMBUS_READ)
{

            /* Special
case: only a
*/

            msg[0].flags
= I2C_M_RD | flags;

            num = 1;

        }

        break;

    case I2C_SMBUS_BYTE_DATA:

        //Byte_Data是指命令+数据的传输形式,在这种情况下,写只需要一次交互,读却要两次

        //第一次将command写到总线上,第二次要转换方向,要将设备地址和read标志写入总线.

        //应回答之后再进行read操作

        //写操作占两字节,分别是command+data,读操作的有效数据只有一个字节

        //交互次数用初始化值就可以了

        if (read_write
== I2C_SMBUS_READ)

            msg[1].len
= 1;

        else {

            msg[0].len
= 2;

            msgbuf0[1]
= data->byte;

        }

        break;

    case I2C_SMBUS_WORD_DATA:

        //Word_Data是指命令+双字节的形式.这种情况跟Byte_Data的情况类似

        //两者相比只是交互的数据大小不同

        if (read_write
== I2C_SMBUS_READ)

            msg[1].len
= 2;

        else {

            msg[0].len=3;

            msgbuf0[1]
= data->word
& 0xff;

            msgbuf0[2]
= data->word
>> 8;

        }

        break;

    case I2C_SMBUS_PROC_CALL:

        //Proc_Call的方式与write 的Word_Data相似,只不过写完Word_Data之后,要等待它的应答

        //应该它需要交互两次,一次写一次读

        num = 2;
/* Special
case */

        read_write = I2C_SMBUS_READ;

        msg[0].len
= 3;

        msg[1].len
= 2;

        msgbuf0[1]
= data->word
& 0xff;

        msgbuf0[2]
= data->word
>> 8;

        break;

    case I2C_SMBUS_BLOCK_DATA:

        //Block_Data:指command+N段数据的情况.

        //如果是读操作,它首先要写command到总线,然后再读N段数据,要写的command已经

        //放在msg[0]了,现在只需要将msg[1]的标志置I2C_M_RECV_LEN位,msg[1]有效长度为1字节,因为

        //adapter驱动会处理好的,现在还不知道要传多少段数据.

        //对于写的情况:msg[1]照例不需要.将要写的数据全部都放到msb[0]中.相应的也要更新

        //msg[0]中的缓存区长度

        if (read_write
== I2C_SMBUS_READ)
{

            msg[1].flags
|= I2C_M_RECV_LEN;

            msg[1].len
= 1;
/* block length will be added by

                      the underlying bus driver */

        } else
{

            //data->block[0]表示后面有多少段数据.总长度要加2是因为command+count+N段数据

            msg[0].len
= data->block[0]
+ 2;

            if
(msg[0].len
> I2C_SMBUS_BLOCK_MAX
+ 2) {

                dev_err(&adapter->dev,
"smbus_access called with "

                      "invalid block write size (%d)/n",

                      data->block[0]);

                return -1;

            }

            for
(i = 1; i
< msg[0].len; i++)

                msgbuf0 = data->block[i-1];

        }

        break;

    case I2C_SMBUS_BLOCK_PROC_CALL:

        //Proc_Call:表示写完Block_Data之后,要等它的应答消息它和Block_Data相比,只是多了一部份应答而已

        num = 2;
/* Another special
case */

        read_write = I2C_SMBUS_READ;

        if (data->block[0]
> I2C_SMBUS_BLOCK_MAX)
{

            dev_err(&adapter->dev,
"%s called with invalid "

                "block proc call size (%d)/n", __func__,

                data->block[0]);

            return -1;

        }

        msg[0].len
= data->block[0]
+ 2;

        for (i
= 1; i
< msg[0].len; i++)

            msgbuf0 = data->block[i-1];

        msg[1].flags
|= I2C_M_RECV_LEN;

        msg[1].len
= 1;
/* block length will be added by

                  the underlying bus driver */

        break;

    case I2C_SMBUS_I2C_BLOCK_DATA:

        //I2c Block_Data与Block_Data相似,只不过read的时候,数据长度是预先定义好了的.另外

        //与Block_Data相比,中间不需要传输Count字段.(Count表示数据段数目)

        if (read_write
== I2C_SMBUS_READ)
{

            msg[1].len
= data->block[0];

        } else
{

            msg[0].len
= data->block[0]
+ 1;

            if
(msg[0].len
> I2C_SMBUS_BLOCK_MAX
+ 1) {

                dev_err(&adapter->dev,
"i2c_smbus_xfer_emulated called with "

                      "invalid block write size (%d)/n",

                      data->block[0]);

                return -1;

            }

            for
(i = 1; i
<= data->block[0];
i++)

                msgbuf0 = data->block;

        }

        break;

    default:

        dev_err(&adapter->dev,
"smbus_access called with invalid size (%d)/n",

              size);

        return -1;

    }

    //如果启用了PEC.Quick和I2c Block_Data是不支持PEC的

    i = ((flags
& I2C_CLIENT_PEC)
&& size
!= I2C_SMBUS_QUICK

                      && size
!= I2C_SMBUS_I2C_BLOCK_DATA);

    if (i)
{

        /* Compute PEC
if first message is a write
*/

        //如果第一个操作是写操作

        if (!(msg[0].flags
& I2C_M_RD))
{

            //如果只是写操作

            if
(num == 1)
/* Write only
*/

                //如果只有写操作,写缓存区要扩充一个字节,用来存放计算出来的PEC

                i2c_smbus_add_pec(&msg[0]);

            else
/* Write followed by read
*/

                //如果后面还有读操作,先计算前面写部份的PEC(注意这种情况下不需要

                //扩充写缓存区,因为不需要发送PEC.只会接收到PEC)

                partial_pec = i2c_smbus_msg_pec(0,
&msg[0]);

        }

        /* Ask
for PEC if last message
is a read */

        //如果最后一次是读消息.还要接收到来自slave的PEC.所以接收缓存区要扩充一个字节

        if (msg[num-1].flags
& I2C_M_RD)

            msg[num-1].len++;

    }

    if (i2c_transfer(adapter, msg, num)
< 0)

        return -1;

    /* Check PEC
if last message is a read
*/

    //操作完了之后,如果最后一个操作是PEC的读操作.检验后面的PEC是否正确

    if (i
&&
(msg[num-1].flags
& I2C_M_RD))
{

        if (i2c_smbus_check_pec(partial_pec,
&msg[num-1])
< 0)

            return -1;

    }

    //操作完了,现在可以将数据放到data部份返回了.

    if (read_write
== I2C_SMBUS_READ)

        switch(size)
{

            case I2C_SMBUS_BYTE:

                data->byte
= msgbuf0[0];

                break;

            case I2C_SMBUS_BYTE_DATA:

                data->byte
= msgbuf1[0];

                break;

            case I2C_SMBUS_WORD_DATA:

            case I2C_SMBUS_PROC_CALL:

                data->word
= msgbuf1[0]
| (msgbuf1[1]
<< 8);

                break;

            case I2C_SMBUS_I2C_BLOCK_DATA:

                for
(i = 0; i
< data->block[0]; i++)

                    data->block[i+1]
= msgbuf1;

                break;

            case I2C_SMBUS_BLOCK_DATA:

            case I2C_SMBUS_BLOCK_PROC_CALL:

                for
(i = 0; i
< msgbuf1[0]
+ 1; i++)

                    data->block
= msgbuf1;

                break;

        }

    return 0;

}

       
此处也是调用i2c_transfer函数实现数据的最终传输的,在上面已经讲述了此函数。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  linux RTC pcf8356