Linux-3.6.6提供了两种访问IIC的方法,一种是基于devfs的方法,另一种是基于sysfs的方法,文中介绍第一种方法,下一篇文章介绍第二种方法。
在arch/arm/plat-samsung/devs.c文件已经定义了IIC平台设备及其资源:
static struct resource s3c_i2c0_resource[]= {
[0]= DEFINE_RES_MEM(S3C_PA_IIC,SZ_4K),
[1] = DEFINE_RES_IRQ(IRQ_IIC),
};
struct platform_device s3c_device_i2c0 = {
.name = "s3c2410-i2c",
#ifdef CONFIG_S3C_DEV_I2C1
.id = 0,
#else
.id = -1,
#endif
.num_resources = ARRAY_SIZE(s3c_i2c0_resource),
.resource = s3c_i2c0_resource,
};
并且通过arch/arm/mach-s3c24xx/mach-zhaocj2440.c文件中的zhaocj2440_init函数把IIC平台设备添加到了总线上。
在zhaocj2440_init函数中还有一条关于IIC的语句:
s3c_i2c0_set_platdata(NULL);
该语句在devs.c中被定义,作用是设置IIC的平台设备数据:
void __init s3c_i2c0_set_platdata(structs3c2410_platform_i2c *pd)
{
structs3c2410_platform_i2c *npd;
if(!pd) {
pd= &default_i2c_data;
pd->bus_num= 0;
}
//设置IIC平台设备的数据
npd= s3c_set_platdata(pd,sizeof(struct s3c2410_platform_i2c),
&s3c_device_i2c0);
//定义IIC的引脚——GPE14和GPE15
if(!npd->cfg_gpio)
npd->cfg_gpio= s3c_i2c0_cfg_gpio;
}
其中default_i2c_data定义为:
struct s3c2410_platform_i2c default_i2c_data__initdata = {
.flags =0, //标识
.slave_addr = 0x10, //从模式地址
.frequency = 100*1000, //频率
.sda_delay = 100, //数据传输延时
};
我们再来看看IIC的平台驱动。在drivers/i2c/busses/i2c-s3c2410.c文件中,IIC子系统的初始化为:
staticint __init i2c_adap_s3c_init(void)
{
return platform_driver_register(&s3c24xx_i2c_driver);
}
s3c24xx_i2c_driver为IIC的平台驱动:
staticstruct platform_driver s3c24xx_i2c_driver = {
.probe = s3c24xx_i2c_probe,
.remove = s3c24xx_i2c_remove,
.id_table = s3c24xx_driver_ids,
.driver = {
.owner = THIS_MODULE,
.name = "s3c-i2c",
.pm = S3C24XX_DEV_PM_OPS,
.of_match_table= of_match_ptr(s3c24xx_i2c_match),
},
};
在驱动列表s3c24xx_driver_ids中,可以找到"s3c2410-i2c",因此IIC的设备和驱动匹配上了:
staticstruct platform_device_id s3c24xx_driver_ids[]= {
{
.name = "s3c2410-i2c",
.driver_data = 0,
}, {
.name = "s3c2440-i2c",
.driver_data = QUIRK_S3C2440,
}, {
.name = "s3c2440-hdmiphy-i2c",
.driver_data = QUIRK_S3C2440 | QUIRK_HDMIPHY | QUIRK_NO_GPIO,
},{ },
};
按惯例,我们再来介绍s3c24xx_i2c_probe函数:
static int s3c24xx_i2c_probe(structplatform_device *pdev)
{
structs3c24xx_i2c *i2c;
structs3c2410_platform_i2c *pdata = NULL;
structresource *res;
intret;
if(!pdev->dev.of_node) {
//获得平台设备数据
pdata =pdev->dev.platform_data;
if(!pdata) {
dev_err(&pdev->dev,"no platform data\n");
return-EINVAL;
}
}
//申请内存空间
i2c = devm_kzalloc(&pdev->dev,sizeof(struct s3c24xx_i2c), GFP_KERNEL);
if(!i2c) {
dev_err(&pdev->dev,"no memory for state\n");
return-ENOMEM;
}
i2c->pdata =devm_kzalloc(&pdev->dev, sizeof(*pdata), GFP_KERNEL);
if(!i2c->pdata) {
ret= -ENOMEM;
gotoerr_noclk;
}
i2c->quirks = s3c24xx_get_device_quirks(pdev);
if (pdata)
memcpy(i2c->pdata, pdata, sizeof(*pdata));
else
s3c24xx_i2c_parse_dt(pdev->dev.of_node,i2c);
//为i2c结构赋值
strlcpy(i2c->adap.name, "s3c2410-i2c",sizeof(i2c->adap.name));
i2c->adap.owner = THIS_MODULE;
i2c->adap.algo = &s3c24xx_i2c_algorithm; //IIC算法
i2c->adap.retries = 2;
i2c->adap.class = I2C_CLASS_HWMON| I2C_CLASS_SPD;
i2c->tx_setup = 50;
spin_lock_init(&i2c->lock);
init_waitqueue_head(&i2c->wait);
/*find the clock and enable it */
i2c->dev = &pdev->dev;
i2c->clk = clk_get(&pdev->dev,"i2c"); //IIC时钟
if(IS_ERR(i2c->clk)) {
dev_err(&pdev->dev,"cannot get clock\n");
ret= -ENOENT;
gotoerr_noclk;
}
dev_dbg(&pdev->dev,"clock source %p\n", i2c->clk);
//IIC时钟使能
clk_enable(i2c->clk);
/*map the registers */
//获得内存资源,这里指的是IIC的寄存器
res= platform_get_resource(pdev, IORESOURCE_MEM, 0);
if(res == NULL) {
dev_err(&pdev->dev,"cannot find IO resource\n");
ret= -ENOENT;
gotoerr_clk;
}
//申请内存区域
i2c->ioarea =request_mem_region(res->start, resource_size(res),
pdev->name);
if(i2c->ioarea == NULL) {
dev_err(&pdev->dev,"cannot request IO\n");
ret= -ENXIO;
gotoerr_clk;
}
//内存重镜像
i2c->regs = ioremap(res->start,resource_size(res));
if(i2c->regs == NULL) {
dev_err(&pdev->dev,"cannot map IO\n");
ret = -ENXIO;
goto err_ioarea;
}
dev_dbg(&pdev->dev,"registers %p (%p, %p)\n",
i2c->regs, i2c->ioarea, res);
/*setup info block for the i2c core*/
i2c->adap.algo_data= i2c;
i2c->adap.dev.parent =&pdev->dev;
/*initialise the i2ccontroller */
//初始化IIC
ret= s3c24xx_i2c_init(i2c);
if(ret != 0)
gotoerr_iomap;
/*find the IRQ for this unit (note, this relies on the init call to
* ensure no current IRQs pending
*/
//得到IIC的中断
i2c->irq = ret = platform_get_irq(pdev,0);
if(ret <= 0) {
dev_err(&pdev->dev,"cannot find IRQ\n");
gotoerr_iomap;
}
//申请中断
ret= request_irq(i2c->irq,s3c24xx_i2c_irq, 0,
dev_name(&pdev->dev), i2c);
if(ret != 0) {
dev_err(&pdev->dev,"cannot claim IRQ %d\n", i2c->irq);
gotoerr_iomap;
}
ret= s3c24xx_i2c_register_cpufreq(i2c);
if(ret < 0) {
dev_err(&pdev->dev,"failed to register cpufreq notifier\n");
gotoerr_irq;
}
/*Note, previous versions of the driver used i2c_add_adapter()
* to add the bus at any number. We now passthe bus number via
* the platform data, so if unset it will nowdefault to always
* being bus 0.
*/
i2c->adap.nr = i2c->pdata->bus_num;
i2c->adap.dev.of_node =pdev->dev.of_node;
//使用静态总线号来声明IIC适配器
ret= i2c_add_numbered_adapter(&i2c->adap);
if(ret < 0) {
dev_err(&pdev->dev,"failed to add bus to i2ccore\n");
goto err_cpufreq;
}
of_i2c_register_devices(&i2c->adap);
platform_set_drvdata(pdev, i2c);
pm_runtime_enable(&pdev->dev);
pm_runtime_enable(&i2c->adap.dev);
dev_info(&pdev->dev,"%s: S3C I2C adapter\n", dev_name(&i2c->adap.dev));
clk_disable(i2c->clk);
return 0;
err_cpufreq:
s3c24xx_i2c_deregister_cpufreq(i2c);
err_irq:
free_irq(i2c->irq, i2c);
err_iomap:
iounmap(i2c->regs);
err_ioarea:
release_resource(i2c->ioarea);
kfree(i2c->ioarea);
err_clk:
clk_disable(i2c->clk);
clk_put(i2c->clk);
err_noclk:
returnret;
}
前面提到的IIC算法结构为:
static const struct i2c_algorithm s3c24xx_i2c_algorithm= {
.master_xfer = s3c24xx_i2c_xfer,
.functionality = s3c24xx_i2c_func,
};
在s3c24xx_i2c_xfer函数内,关键用到了s3c24xx_i2c_doxfer函数:
static int s3c24xx_i2c_doxfer(structs3c24xx_i2c *i2c,
struct i2c_msg *msgs, int num)
{
unsignedlong iicstat, timeout;
intspins = 20;
intret;
if(i2c->suspended)
return-EIO;
//设置寄存器,为传输数据做准备
ret= s3c24xx_i2c_set_master(i2c);
if(ret != 0) {
dev_err(i2c->dev, "cannot get bus (error%d)\n", ret);
ret= -EAGAIN;
gotoout;
}
spin_lock_irq(&i2c->lock);
i2c->msg =msgs; //数据
i2c->msg_num = num; //字节数
i2c->msg_ptr = 0;
i2c->msg_idx = 0;
i2c->state = STATE_START; //开始标识
s3c24xx_i2c_enable_irq(i2c); //开启IIC中断
s3c24xx_i2c_message_start(i2c,msgs); //开始传输,把数据头字节放在总线上
spin_unlock_irq(&i2c->lock);
timeout= wait_event_timeout(i2c->wait,i2c->msg_num == 0, HZ * 5);
ret= i2c->msg_idx;
/*having these next two as dev_err() makes life very
* noisy when doing an i2cdetect */
if(timeout == 0)
dev_dbg(i2c->dev, "timeout\n");
elseif (ret != num)
dev_dbg(i2c->dev, "incomplete xfer(%d)\n", ret);
/*ensure the stop has been through the bus */
dev_dbg(i2c->dev, "waiting for busidle\n");
/*first, try busy waiting briefly */
//等待传输结束
do{
cpu_relax();
iicstat= readl(i2c->regs +S3C2410_IICSTAT);
}while ((iicstat & S3C2410_IICSTAT_START)&& --spins);
/*if that timed out sleep */
if(!spins) {
msleep(1);
iicstat= readl(i2c->regs +S3C2410_IICSTAT);
}
if(iicstat & S3C2410_IICSTAT_START)
dev_warn(i2c->dev, "timeout waiting for busidle\n");
out:
returnret;
}
从上面的分析可以看出,s3c24xx_i2c_xfer的作用是在开启中断后把数据的头字节放到总线上。当数据真正开始传输的时候,就会触发IIC的中断,因此,实际的数据传输是在中断内完成的。我们来看看IIC的中断处理函数s3c24xx_i2c_irq:
static irqreturn_t s3c24xx_i2c_irq(int irqno, void *dev_id)
{
structs3c24xx_i2c *i2c = dev_id;
unsignedlong status;
unsignedlong tmp;
//读IICSTAT
status= readl(i2c->regs +S3C2410_IICSTAT);
//IIC仲裁失败
if(status & S3C2410_IICSTAT_ARBITR){
/*deal with arbitration loss */
dev_err(i2c->dev, "deal with arbitrationloss\n");
}
//如果总线处理闲置状况,则退出中断
if(i2c->state == STATE_IDLE) {
dev_dbg(i2c->dev, "IRQ: error i2c->state == IDLE\n");
//并清IIC中断悬挂标识
tmp =readl(i2c->regs +S3C2410_IICCON);
tmp&= ~S3C2410_IICCON_IRQPEND;
writel(tmp,i2c->regs + S3C2410_IICCON);
gotoout;
}
/*pretty much this leaves us with the fact that we've
* transmitted or received whatever byte welast sent */
i2c_s3c_irq_nextbyte(i2c, status);
out:
returnIRQ_HANDLED;
}
真正的传输函数出现了——i2c_s3c_irq_nextbyte:
static int i2c_s3c_irq_nextbyte(structs3c24xx_i2c *i2c, unsigned long iicstat)
{
unsignedlong tmp;
unsignedchar byte;
intret = 0;
switch(i2c->state) {
caseSTATE_IDLE: //空闲状态,什么也不做直接退出该函数
dev_err(i2c->dev, "%s: called inSTATE_IDLE\n", __func__);
gotoout;
caseSTATE_STOP: //数据传输结束
dev_err(i2c->dev, "%s: called inSTATE_STOP\n", __func__);
s3c24xx_i2c_disable_irq(i2c); //关闭中断
gotoout_ack; //跳到应答
caseSTATE_START: //传输开始,或者是传输结束为下一次传输做准备
/*last thing we did was send a start condition on the
* bus, or started a new i2c message
*/
if(iicstat & S3C2410_IICSTAT_LASTBIT&& //传输结束
!(i2c->msg->flags& I2C_M_IGNORE_NAK)){ //不忽略应答
/*ack was not received... */
dev_dbg(i2c->dev, "ack was notreceived\n");
s3c24xx_i2c_stop(i2c,-ENXIO); //由于从设备没有响应,而结束传输
gotoout_ack; //跳到应答
}
//判断此次传输是发送还是接受,即是读还是写
if(i2c->msg->flags & I2C_M_RD)
i2c->state = STATE_READ;
else
i2c->state = STATE_WRITE;
/*terminate the transfer if there is nothing to do
* as this is used by the i2c probe to find devices. */
//判断是否传输结束
if(is_lastmsg(i2c)&& i2c->msg->len== 0) {
s3c24xx_i2c_stop(i2c,0); //结束传输
gotoout_ack;
}
if(i2c->state ==STATE_READ) //读状态
goto prepare_read;
/*fall through to the write state, as we will need to
* send a byte as well */
caseSTATE_WRITE: //写入状态
/*we are writing data to the device... check for the
* end of the message, and if so, work out whatto do
*/
//从设备拒绝写入
if(!(i2c->msg->flags & I2C_M_IGNORE_NAK)) {
if(iicstat & S3C2410_IICSTAT_LASTBIT){
dev_dbg(i2c->dev, "WRITE: No Ack\n");
s3c24xx_i2c_stop(i2c,-ECONNREFUSED);
gotoout_ack;
}
}
retry_write:
if(!is_msgend(i2c)) { //信息传输尚未结束
byte= i2c->msg->buf[i2c->msg_ptr++];
writeb(byte,i2c->regs + S3C2410_IICDS); //写入数据
/*delay after writing the byte to allow the
* data setup time on the bus, as writing the
* data to the register causes the first bit
* to appear on SDA, and SCL will change as
* soon as the interrupt is acknowledged */
ndelay(i2c->tx_setup); //等待,延时
}else if (!is_lastmsg(i2c)) { //不是最后一组信息
/*we need to go to the next i2cmessage */
dev_dbg(i2c->dev, "WRITE: Next Message\n");
//为下一组信息传输做准备,即调整指针
i2c->msg_ptr = 0;
i2c->msg_idx++;
i2c->msg++;
/*check to see if we need to do another message */
if (i2c->msg->flags & I2C_M_NOSTART) {
if (i2c->msg->flags & I2C_M_RD) {
/* cannot do this, the controller
* forces us to send a new START
* when we change direction */
s3c24xx_i2c_stop(i2c,-EINVAL);
}
gotoretry_write;
}else {
/*send the new start */
//准备传输下一组信息
s3c24xx_i2c_message_start(i2c, i2c->msg);
i2c->state = STATE_START;
}
}else { //所有信息都传输结束
/*send stop */
s3c24xx_i2c_stop(i2c,0);
}
break;
caseSTATE_READ: //读入状态
/*we have a byte of data in the data register, do
* something with it, and then work out wetherwe are
* going to do any more read/write
*/
//读入数据
byte= readb(i2c->regs +S3C2410_IICDS);
i2c->msg->buf[i2c->msg_ptr++] = byte;
prepare_read:
if(is_msglast(i2c)) { //是当前信息的最后一个字节
/*last byte of buffer */
if(is_lastmsg(i2c)) //是最后一组信息,即再没有数据需要读入了
s3c24xx_i2c_disable_ack(i2c); //无需应答
}else if (is_msgend(i2c)) { //当前信息的尾部
/*ok, we've read the entire buffer, see if there
* is anything else we need to do */
if(is_lastmsg(i2c)) { //最后一组信息
/*last message, send stop and complete */
dev_dbg(i2c->dev, "READ: Send Stop\n");
s3c24xx_i2c_stop(i2c,0);
}else {
/*go to the next transfer */
dev_dbg(i2c->dev, "READ: NextTransfer\n");
i2c->msg_ptr = 0;
i2c->msg_idx++;
i2c->msg++;
}
}
break;
}
/*acknowlegde the IRQ and get back on with the work */
out_ack: //并清IIC中断悬挂标识
tmp= readl(i2c->regs +S3C2410_IICCON);
tmp&= ~S3C2410_IICCON_IRQPEND;
writel(tmp,i2c->regs + S3C2410_IICCON);
out:
returnret;
}
s3c24xx_i2c_probe函数中还用到了s3c24xx_i2c_init函数:
static int s3c24xx_i2c_init(structs3c24xx_i2c *i2c)
{
unsignedlong iicon = S3C2410_IICCON_IRQEN| S3C2410_IICCON_ACKEN;
structs3c2410_platform_i2c *pdata;
unsignedint freq;
/*get the plafrom data */
pdata = i2c->pdata;
/* inititalise the gpio */
//初始化IIC的引脚
if(pdata->cfg_gpio)
pdata->cfg_gpio(to_platform_device(i2c->dev));
else
if(s3c24xx_i2c_parse_dt_gpio(i2c))
return-EINVAL;
/*write slave address */
//写IICADD寄存器
writeb(pdata->slave_addr,i2c->regs + S3C2410_IICADD);
dev_info(i2c->dev, "slave address0x%02x\n", pdata->slave_addr);
//写IICCON,IIC应答使能,IIC中断使能
writel(iicon,i2c->regs + S3C2410_IICCON);
/*we need to work out the divisors for the clock... */
//分频
if(s3c24xx_i2c_clockrate(i2c, &freq) != 0) {
writel(0,i2c->regs + S3C2410_IICCON);
dev_err(i2c->dev, "cannot meet bus frequencyrequired\n");
return-EINVAL;
}
/*todo - check that the i2clines aren't being dragged anywhere */
dev_info(i2c->dev, "bus frequency set to %dKHz\n", freq);
dev_dbg(i2c->dev, "S3C2410_IICCON=0x%02lx\n", iicon);
return 0;
}
我们最后看看IIC的文件层drivers/i2c/i2c-dev.c:
static int __init i2c_dev_init(void)
{
int res;
printk(KERN_INFO "i2c /dev entries driver\n");
//注册字符设备
res =register_chrdev(I2C_MAJOR,"i2c",&i2cdev_fops);
if(res)
gotoout;
//创建子类
i2c_dev_class = class_create(THIS_MODULE,"i2c-dev");
if(IS_ERR(i2c_dev_class)){
res= PTR_ERR(i2c_dev_class);
gotoout_unreg_chrdev;
}
/*Keep track of adapters which will be added or removed later */
res= bus_register_notifier(&i2c_bus_type,&i2cdev_notifier);
if(res)
goto out_unreg_class;
/*Bind to already existing adapters right away */
//绑定现有的IIC适配器
i2c_for_each_dev(NULL, i2cdev_attach_adapter);
return0;
out_unreg_class:
class_destroy(i2c_dev_class);
out_unreg_chrdev:
unregister_chrdev(I2C_MAJOR, "i2c");
out:
printk(KERN_ERR"%s: Driver Initialisation failed\n", __FILE__);
returnres;
}
IIC的操作集i2cdev_fops:
static const struct file_operationsi2cdev_fops = {
.owner = THIS_MODULE,
.llseek = no_llseek,
.read = i2cdev_read,
.write = i2cdev_write,
.unlocked_ioctl = i2cdev_ioctl,
.open = i2cdev_open,
.release = i2cdev_release,
};
我们对i2cdev_read、i2cdev_write和i2cdev_ioctl这三个主要的函数进行分析:
static ssize_t i2cdev_read(struct file*file, char __user *buf, size_t count,
loff_t*offset)
{
char*tmp;
intret;
structi2c_client *client =file->private_data;
if(count > 8192)
count= 8192; //限制字节数
tmp= kmalloc(count, GFP_KERNEL); //开辟内存空间
if(tmp == NULL)
return-ENOMEM;
pr_debug("i2c-dev: i2c-%d reading %zu bytes.\n",
iminor(file->f_path.dentry->d_inode),count);
ret= i2c_master_recv(client, tmp,count); //以master形式接受数据
if(ret >= 0)
ret= copy_to_user(buf, tmp, count) ? -EFAULT : ret; //复制到用户程序中
kfree(tmp);
returnret;
}
static ssize_t i2cdev_write(struct file*file, const char __user *buf,
size_tcount, loff_t *offset)
{
intret;
char*tmp;
structi2c_client *client =file->private_data;
if(count > 8192)
count= 8192;
tmp= memdup_user(buf, count);
if(IS_ERR(tmp))
returnPTR_ERR(tmp);
pr_debug("i2c-dev: i2c-%d writing %zu bytes.\n",
iminor(file->f_path.dentry->d_inode),count);
ret= i2c_master_send(client, tmp,count); //以master形式发送数据
kfree(tmp);
returnret;
}
i2c_master_recv函数和i2c_master_send函数都在drviers/i2c/I2c-core.c文件内,而且这两个函数最终都是调用的i2c_transfer函数。
由于对IIC的读i2cdev_read和写i2cdev_write操作有一些局限性,而且这两个操作完全可以用i2cdev_ioctl来替代:
static long i2cdev_ioctl(struct file *file,unsigned int cmd, unsigned long arg)
{
structi2c_client *client =file->private_data;
unsignedlong funcs;
dev_dbg(&client->adapter->dev,"ioctl, cmd=0x%02x, arg=0x%02lx\n",
cmd, arg);
switch(cmd) {
caseI2C_SLAVE:
caseI2C_SLAVE_FORCE: //设置从设备地址
/*NOTE: devices set up to work with"new style" drivers
* can't use I2C_SLAVE, even when the device node is not
* bound to a driver. Only I2C_SLAVE_FORCE will work.
*
* Setting the PEC flag here won't affectkernel drivers,
* which will be using the i2c_client node registered with
* the driver model core. Likewise, when that client has
* the PEC flag already set, the i2c-dev driver won't see
* (or use) this setting.
*/
if((arg > 0x3ff) ||
(((client->flags & I2C_M_TEN)== 0) && arg > 0x7f))
return-EINVAL;
if(cmd == I2C_SLAVE&& i2cdev_check_addr(client->adapter, arg))
return-EBUSY;
/*REVISIT: address could become busy later */
client->addr= arg;
return0;
caseI2C_TENBIT: //设置7位地址还是10位地址
if (arg) //非零是十位
client->flags |= I2C_M_TEN;
else
client->flags &= ~I2C_M_TEN; //七位
return 0;
caseI2C_PEC:
if(arg)
client->flags |= I2C_CLIENT_PEC;
else
client->flags &= ~I2C_CLIENT_PEC;
return 0;
caseI2C_FUNCS: //返回控制器算法所支持的传输种类
funcs= i2c_get_functionality(client->adapter);
returnput_user(funcs, (unsigned long __user *)arg);
caseI2C_RDWR: //IIC的读写操作,master方式
returni2cdev_ioctl_rdrw(client, arg);
caseI2C_SMBUS: //IIC的SMBus传输方式
returni2cdev_ioctl_smbus(client, arg);
caseI2C_RETRIES: //重复次数
client->adapter->retries = arg;
break;
case I2C_TIMEOUT: //延时
/*For historical reasons, user-space sets the timeout
* value in units of 10 ms.
*/
client->adapter->timeout= msecs_to_jiffies(arg * 10);
break;
default:
/*NOTE: returning a fault code here couldcause trouble
* in buggy userspace code. Some old kernel bugs returned
* zero in this case, and userspace code mightaccidentally
* have depended on that bug.
*/
return-ENOTTY;
}
return0;
}
最主要的IIC读写操作i2cdev_ioctl_rdrw函数:
static noinline inti2cdev_ioctl_rdrw(struct i2c_client*client,
unsignedlong arg)
{
structi2c_rdwr_ioctl_data rdwr_arg;
structi2c_msg *rdwr_pa;
u8 __user **data_ptrs;
int i, res;
//复制用户空间中的数据
if(copy_from_user(&rdwr_arg,
(struct i2c_rdwr_ioctl_data __user *)arg,
sizeof(rdwr_arg)))
return-EFAULT;
/*Put an arbitrary limit on the number of messages that can
* be sent at once */
if(rdwr_arg.nmsgs > I2C_RDRW_IOCTL_MAX_MSGS)
return-EINVAL;
//从用户空间复制内存
rdwr_pa= memdup_user(rdwr_arg.msgs,
rdwr_arg.nmsgs * sizeof(struct i2c_msg));
if(IS_ERR(rdwr_pa))
returnPTR_ERR(rdwr_pa);
//开辟一段内存空间给data_ptrs
data_ptrs= kmalloc(rdwr_arg.nmsgs * sizeof(u8 __user *), GFP_KERNEL);
if(data_ptrs == NULL) {
kfree(rdwr_pa);
return -ENOMEM;
}
res = 0;
//复制数据
for (i = 0; i < rdwr_arg.nmsgs; i++) {
/* Limitthe size of the message to a sane amount */
if(rdwr_pa[i].len > 8192) {
res= -EINVAL;
break;
}
//复制数据
data_ptrs[i]= (u8 __user *)rdwr_pa[i].buf;
rdwr_pa[i].buf= memdup_user(data_ptrs[i], rdwr_pa[i].len);
if(IS_ERR(rdwr_pa[i].buf)) {
res = PTR_ERR(rdwr_pa[i].buf);
break;
}
/*
* If the message length is received from theslave (similar
* to SMBus block read), we must ensure thatthe buffer will
* be large enough to cope with a messagelength of
* I2C_SMBUS_BLOCK_MAXas this is the maximum underlying bus
* drivers allow. The first byte in the buffermust be
* pre-filled with the number of extra bytes,which must be
* at least one to hold the message length, butcan be
* greater (for example to account for achecksum byte at
* the end of the message.)
*/
if (rdwr_pa[i].flags & I2C_M_RECV_LEN) {
if (!(rdwr_pa[i].flags& I2C_M_RD) || //不是读命令
rdwr_pa[i].buf[0] < 1 ||
rdwr_pa[i].len < rdwr_pa[i].buf[0] +
I2C_SMBUS_BLOCK_MAX){
res = -EINVAL;
break; //退出for循环
}
rdwr_pa[i].len= rdwr_pa[i].buf[0];
}
}
if(res < 0) {
int j;
for (j = 0; j < i; ++j)
kfree(rdwr_pa[j].buf);
kfree(data_ptrs);
kfree(rdwr_pa);
returnres;
}
//IIC的传输数据
res= i2c_transfer(client->adapter,rdwr_pa, rdwr_arg.nmsgs);
//如果是读命令(数据传输方向是从设备向主设备),把数据传递给用户
while(i-- > 0) {
//读命令判断
if (res >= 0 &&(rdwr_pa[i].flags & I2C_M_RD)){
if(copy_to_user(data_ptrs[i], rdwr_pa[i].buf, //传输数据给用户
rdwr_pa[i].len))
res = -EFAULT;
}
kfree(rdwr_pa[i].buf);
}
kfree(data_ptrs);
kfree(rdwr_pa);
return res;
}
再来看看上面这个函数最关键的一条——i2c_transfer。i2cdev_write和i2cdev_read实际上也主要是调用这个函数,因此正如上文介绍的,完全可以用ioctl来代替read和write:
int i2c_transfer(struct i2c_adapter *adap, struct i2c_msg *msgs, int num)
{
intret;
/*REVISIT the fault reporting model here is weak:
*
* -When we get an error after receiving N bytes from a slave,
* there is no way to report "N".
*
* -When we get a NAK after transmitting N bytes to a slave,
* there is no way to report "N" ... or to let the master
* continueexecuting the rest of this combined message, if
* that's the appropriate response.
*
* -When for example "num" is two and we successfully complete
* thefirst message but get an error part way through the
* second, it's unclear whether that should be reported as
* one(discarding status on the second message) or errno
* (discarding status on the first one).
*/
if(adap->algo->master_xfer) { //IIC算法为master
#ifdefDEBUG
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);
}
//IIC传输数据
ret = __i2c_transfer(adap, msgs, num);
i2c_unlock_adapter(adap);
returnret;
}else {
dev_dbg(&adap->dev,"I2C leveltransfers not supported\n");
return-EOPNOTSUPP;
}
}
__i2c_transfer函数也在drviers/i2c/I2c-core.c文件内:
int __i2c_transfer(struct i2c_adapter *adap, struct i2c_msg *msgs, int num)
{
unsignedlong orig_jiffies;
intret, try;
/*Retry automatically on arbitration loss */
orig_jiffies= jiffies;
//根据所设置的重试次数来循环
for(ret = 0, try = 0; try <= adap->retries; try++) {
//使用master进行传输,即调用s3c24xx_i2c_xfer函数
ret =adap->algo->master_xfer(adap, msgs, num);
if (ret !=-EAGAIN)
break;
if(time_after(jiffies, orig_jiffies + adap->timeout)) //延时
break;
}
returnret;
}
在写应用程序的时候,如果我们要用I2C_RDWR这个命令,那么就要用到i2c_rdwr_ioctl_data结构(它是在include/linux/i2c-dev.h中定义的),所以我们给出它的定义:
struct i2c_rdwr_ioctl_data {
structi2c_msg __user *msgs; /* pointers to i2c_msgs */
__u32nmsgs; /* number of i2c_msgs */
};
struct i2c_msg {
__u16addr; /* slave address */
__u16flags;
#define I2C_M_TEN 0x0010 /* this is a ten bit chip address */
#define I2C_M_RD 0x0001 /* read data, from slave to master */
#define I2C_M_STOP 0x8000 /* if I2C_FUNC_PROTOCOL_MANGLING */
#define I2C_M_NOSTART 0x4000 /* if I2C_FUNC_NOSTART */
#define I2C_M_REV_DIR_ADDR 0x2000 /* if I2C_FUNC_PROTOCOL_MANGLING */
#define I2C_M_IGNORE_NAK 0x1000 /* if I2C_FUNC_PROTOCOL_MANGLING */
#define I2C_M_NO_RD_ACK 0x0800 /* if I2C_FUNC_PROTOCOL_MANGLING */
#define I2C_M_RECV_LEN 0x0400 /* length will be first received byte */
__u16len; /* msg length */
__u8*buf; /* pointer to msg data */
};
下面我们就来写访问IIC的应用程序。在开发板上,用IIC连接的设备是AT24C02的eeprom。我们首先用write和read来读写eeprom:
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <string.h>
//下面两个头文件是操作IIC的关键
#include <linux/i2c.h>
#include <linux/i2c-dev.h>
int main(void){
int fd, i;
char sendadd;
char buf[50];
fd = open("/dev/i2c-0", O_RDWR);
if(fd < 0){
printf("####i2ctest device open failed####/n");
return (-1);
}
ioctl(fd,I2C_TENBIT,0); //七位地址
//AT24C02的地址为0xa0,但由于是七位地址,最低一位是读写位,因此0xa0右移一位就变为0x50
if (ioctl(fd, I2C_SLAVE_FORCE, 0x50) < 0) {
printf("####i2cset slave address failed####/n");
return (-1);
}
ioctl(fd,I2C_TIMEOUT,1); //超时时间
ioctl(fd,I2C_RETRIES,2); //重复次数
sendaddr = 0x28; //这里设置读的地址为0x28
write(fd, &sendadd,1); //发送地址
read(fd, buf, 8); //连续读出8个数据
for(i=0; i<8; i++)
printf("buff[%d]=%x\n", i, buf[i]);
close(fd);
return 0;
}
上面的程序实现了读取AT24C02中从地址0x28开始的连续8个数据。下面的程序实现了从0x30地址开始,连续写入8个数据:
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <string.h>
#include <linux/i2c.h>
#include <linux/i2c-dev.h>
int main(void){
int fd;
charbuf[8]={0xef,0x9f,0x3,0x5a,0x2e,0x67,0x89,0x10}; //要写入的数据
//senddata为传输的数据,它包括第一个字节的地址信息,和后8个字节的写入数据信息
char senddata[9];
fd = open("/dev/i2c-0", O_RDWR);
if(fd < 0){
printf("####i2ctest device open failed####/n");
return (-1);
}
ioctl(fd,I2C_TENBIT,0);
if (ioctl(fd, I2C_SLAVE_FORCE, 0x50) < 0) {
printf("####i2cset slave address failed####/n");
return (-1);
}
ioctl(fd,I2C_TIMEOUT,1);
ioctl(fd,I2C_RETRIES,2);
memcpy(senddata+1,buf, 8);
senddata[0]=0x30; //要写入的地址
write(fd, senddata,9);
close(fd);
return 0;
}
下面我们再用ioctl的方法来实现读写功能:
/*******************
* iicr.c *
******************/
#include <stdio.h>
#include <linux/types.h>
#include <stdlib.h>
#include <fcntl.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/ioctl.h>
#include <errno.h>
#include<linux/i2c.h>
#include<linux/i2c-dev.h>
int main(int argc, char **argv)
{
int fd,ret;
struct i2c_rdwr_ioctl_data e2prom_data;
unsigned intreg_address;
fd=open("/dev/i2c-0",O_RDWR);
if(fd<0){
perror("open error");
exit(1);
}
sscanf(argv[1],"%x", ®_address); //转换参数类型,第一个参数为目标地址
e2prom_data.nmsgs=2;
/*
*因为操作时序中,最多是用到2个开始信号(字节读操作中),所以此将
*e2prom_data.nmsgs配置为2
*/
e2prom_data.msgs=(structi2c_msg*)malloc(e2prom_data.nmsgs*sizeof(structi2c_msg));
if(!e2prom_data.msgs){
perror("malloc error");
exit(1);
}
ioctl(fd,I2C_TIMEOUT,1);
ioctl(fd,I2C_RETRIES,2);
/***write datato e2prom**/
e2prom_data.nmsgs=2;
(e2prom_data.msgs[0]).len=1; //1个 e2prom 写入目标的地址
(e2prom_data.msgs[0]).addr=0x50; //e2prom 设备地址
(e2prom_data.msgs[0]).flags=0; //write
(e2prom_data.msgs[0]).buf=(unsignedchar*)malloc(1);
(e2prom_data.msgs[0]).buf[0]=reg_address; // e2prom 写入目标的地址
(e2prom_data.msgs[1]).len=1; //读出的数据
(e2prom_data.msgs[1]).addr=0x50; // e2prom 设备地址
(e2prom_data.msgs[1]).flags=I2C_M_RD; //read
(e2prom_data.msgs[1]).buf=(unsignedchar*)malloc(1);//存放返回值的地址。
(e2prom_data.msgs[1]).buf[0]=0; //初始化读缓冲
ret=ioctl(fd, I2C_RDWR, (unsigned long)&e2prom_data);
if(ret<0){
perror("ioctl error1");
exit(1);
}
printf("buf[0]=%x\n",(e2prom_data.msgs[1]).buf[0]);
close(fd);
return 0;
}
上面的程序实现了可以读取AT24C02中的任意一个地址数据的功能。而下面的程序实现了可以写入任意一个地址数据的功能,其中第一个参数内存地址,第二个参数为要写入的数据:
/***************
* iicw.c *
***************/
#include <stdio.h>
#include <linux/types.h>
#include <stdlib.h>
#include <fcntl.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/ioctl.h>
#include <errno.h>
#include<string.h>
#include<linux/i2c.h>
#include<linux/i2c-dev.h>
int main(int argc, char *argv[])
{
int fd, ret;
struct i2c_rdwr_ioctl_data e2prom_data;
unsignedint reg_address,value;
fd=open("/dev/i2c-0",O_RDWR);
if(fd<0){
perror("open error");
}
sscanf(argv[1],"%x", ®_address); //目标地址
sscanf(argv[2],"%x", &value); //要写入的数据
e2prom_data.nmsgs=1;
e2prom_data.msgs=(structi2c_msg*)malloc(e2prom_data.nmsgs*sizeof(structi2c_msg));
if(!e2prom_data.msgs){
perror("malloc error");
exit(1);
}
ioctl(fd,I2C_TIMEOUT,1);
ioctl(fd,I2C_RETRIES,2);
e2prom_data.nmsgs=1;
(e2prom_data.msgs[0]).len=2; //1个 e2prom 写入目标的地址和1个数据
(e2prom_data.msgs[0]).addr=0x50; //e2prom 设备地址
(e2prom_data.msgs[0]).flags=0; //write
(e2prom_data.msgs[0]).buf=(unsignedchar*)malloc(2);
(e2prom_data.msgs[0]).buf[0]=reg_address; // e2prom 写入目标的地址
(e2prom_data.msgs[0]).buf[1]=value; //要写入的数据
ret=ioctl(fd,I2C_RDWR,(unsigned long)&e2prom_data);
if(ret<0){
perror("ioctl error2");
}
close(fd);
return 0;
}
正如前面介绍的,用ioctl完全可以实现read和write的功能,但ioctl一次只能读写一个字节,而read和write可以一次读写多个字节。