- #include <linux/module.h>
- #include <linux/kernel.h>
- #include <linux/init.h>
- #include <linux/sched.h>
- #include <mach/hardware.h>
- #include <linux/semaphore.h>
- #include <asm/uaccess.h>
- #include <linux/kernel.h> /* printk() */
- #include <linux/slab.h> /* kmalloc() */
- #include <linux/fs.h> /* everything... */
- #include <linux/errno.h> /* error codes */
- #include <linux/types.h> /* size_t */
- #include <linux/mm.h>
- #include <linux/kdev_t.h>
- #include <linux/cdev.h>
- #include <linux/delay.h>
- #include <asm/io.h>
- #include <asm/uaccess.h>
- #include <linux/errno.h>
- #include <linux/kernel.h>
- #include <linux/module.h>
- #include <linux/slab.h>
- #include <linux/input.h>
- #include <linux/init.h>
- #include <linux/serio.h>
- #include <asm/irq.h>
- #include <mach/map.h>
- #include <mach/regs-gpio.h>
- #include <mach/regs-irq.h>
- #include <mach/regs-clock.h>
- #include <asm/signal.h>
- volatile int f_nGetACK;
- #define UINT unsigned int
- #define I2C_MAGIC 'k'
- #define I2C_set _IO(I2C_MAGIC,1)
- #define I2C_MAJOR 259
- #define DEVICE_NAME "s3c2410_I2C"
- MODULE_LICENSE("GPL");
- MODULE_AUTHOR("farsight");
- MODULE_DESCRIPTION("s3c2410 I2C");
- char data[128]="\0";
- #define rGPECON *(volatile unsigned int *)S3C2410_GPECON
- #if 0
- #define S3C2410_I2C(x) (S3C2410_IICREG(x))
- #define S3C2410_IICCON S3C2410_I2C(0x00)
- #define S3C2410_IICSTAT S3C2410_I2C(0x04)
- #define S3C2410_IICADD S3C2410_I2C(0x08)
- #define S3C2410_IICDS S3C2410_I2C(0x0c)
- #define rIICCON *(volatile unsigned int *)S3C2410_IICCON
- #define rIICSTAT *(volatile unsigned int *)S3C2410_IICSTAT
- #define rIICADD *(volatile unsigned int *)S3C2410_IICADD
- #define rIICDS *(volatile unsigned int *)S3C2410_IICDS
- #define rGPECON *(volatile unsigned int *)S3C2410_GPECON
- #else
- #define rIICCON *(volatile unsigned int *)i2c_base
- #define rIICSTAT *(volatile unsigned int *)((unsigned int)i2c_base + 4)
- #define rIICADD *(volatile unsigned int *)((unsigned int)i2c_base + 8)
- #define rIICDS *(volatile unsigned int *)((unsigned int)i2c_base + 0xc)
- static volatile void __iomem *i2c_base;
- static struct resource *area = NULL;
- #endif
- #define CLKCON 0x4c00000c
- static volatile unsigned int *clkcon;
- static int I2C_major = I2C_MAJOR;
- static struct cdev I2C_cdev;
- /*********************************************************************************************
- * name: iic_int_24c04()
- * func: IIC interrupt handler
- * para: none
- * ret: none
- * modify:
- * comment:
- *********************************************************************************************/
- static irqreturn_t iic_int_24c04(int irq,void *dev_id,struct pt_regs *regs)
- {
- f_nGetACK = 1;
- return IRQ_HANDLED ;
- }
- /*********************************************************************************************
- * name: iic_write_24c040
- * func: write data to 24C040
- * para: unSlaveAddr --- input, chip slave address
- * unAddr --- input, data address
- * ucData --- input, data value
- * ret: none
- * modify:
- * comment:
- *********************************************************************************************/
- void iic_write_24c040(UINT unSlaveAddr,UINT unAddr,UINT ucData)
- {
- f_nGetACK = 0;
- // Send control byte
- rIICDS = unSlaveAddr; // 0xa0
- rIICSTAT = 0xf0; // Master Tx,Start
- while(f_nGetACK == 0);// Wait ACK
- f_nGetACK = 0;
- //Send address
- rIICDS = unAddr;
- rIICCON = 0xaf; // Resumes IIC operation.
- while(f_nGetACK == 0);// Wait ACK
- f_nGetACK = 0;
- // Send data
- rIICDS = ucData;
- rIICCON = 0xaf; // Resumes IIC operation.
- while(f_nGetACK == 0);// Wait ACK
- f_nGetACK = 0;
- // End send
- rIICSTAT = 0xd0; // Stop Master Tx condition
- rIICCON = 0xaf; // Resumes IIC operation.
- mdelay(10); // Wait until stop condtion is in effect.
- }
- /*********************************************************************************************
- * name: iic_read_24c040
- * func: read data from 24C040
- * para: unSlaveAddr --- input, chip slave address
- * unAddr --- input, data address
- * pData --- output, data pointer
- * ret: none
- * modify:
- * comment:
- *********************************************************************************************/
- void iic_read_24c040(UINT unSlaveAddr,UINT unAddr,unsigned char *pData)
- {
- char cRecvByte;
- f_nGetACK = 0;
- //Send control byte
- rIICDS = unSlaveAddr; // 0xa0
- rIICSTAT = 0xf0; // Master Tx,Start
- while(f_nGetACK == 0);// Wait ACK
- f_nGetACK = 0;
- // Send address
- rIICDS = unAddr;
- rIICCON = 0xaf; // Resumes IIC operation.
- while(f_nGetACK == 0);// Wait ACK
- f_nGetACK = 0;
- //Send control byte
- rIICDS = unSlaveAddr; // 0xa0
- rIICSTAT = 0xb0; // Master Rx,Start
- rIICCON = 0xaf; // Resumes IIC operation.
- mdelay(100);
- while(f_nGetACK == 0);// Wait ACK
- f_nGetACK = 0;
- //Get data
- rIICCON = 0x2f;
- mdelay(1);
- // Get data
- cRecvByte = rIICDS;
- // End receive
- rIICSTAT = 0x90; // Stop Master Rx condition
- rIICCON = 0xaf; // Resumes IIC operation.
- mdelay(10); // Wait until stop condtion is in effect.
- *pData = cRecvByte;
- }
- ssize_t I2C_read (struct file *filp, char *buff, size_t count, loff_t *offp)
- {
- ssize_t result = 0;
- int i;
- for(i=0; i<count; i++)
- data[i]=0;
- // Read 16 byte from 24C04
- for(i=0; i<count; i++)
- {
- iic_read_24c040(0xa0, i, &(data[i]));
- }
- data[count]='\0';
- if (copy_to_user (buff, data, count))
- result = -EFAULT;
- result=count;
- return result;
- }
- ssize_t I2C_write (struct file *filp, const char __user *buf, size_t count, loff_t *f_pos)
- {
- int i;
- ssize_t ret = 0;
- //printk ("Writing %d bytes\n", count);
- if (count>127) return -ENOMEM;
- if (count<0) return -EINVAL;
- if (copy_from_user (data, buf, count))
- {
- ret = -EFAULT;
- }
- else {
- data[127]='\0';
- //printk ("Received: %s\n", data);
- // Write 0 - 16 to 24C04
- for(i=0; i<count; i++)
- {
- iic_write_24c040(0xa0, i, data[i]);
- //mdelay(100);
- }
- //printk("write end\n");
- ret = count;
- }
- return ret;
- }
- static int I2C_open(struct inode *inode ,struct file *file)
- {
- int result;
- // Initialize iic
- rIICADD = 0x10; // S3C2410X slave address
- rIICCON = 0xaf; // Enable ACK, interrupt, SET IICCLK=MCLK/16
- rIICSTAT = 0x10; // Enable TX/RX
- rGPECON =(rGPECON&((~0xf)<<28))+(0xa<<28);
- //printk("rGPECON=%x\n",rGPECON);
- result = request_irq (IRQ_IIC, iic_int_24c04, IRQF_DISABLED, DEVICE_NAME, NULL);
- if (result) {
- printk(KERN_INFO "I2C: can't get assigned irq\n");
- }
- //printk(KERN_NOTICE"open the I2C now!\n");
- return 0;
- }
- static int I2C_release(struct inode *inode,struct file *file)
- {
- free_irq(IRQ_IIC, NULL);//ÊÍ·ÅÖжÏ×ÊÔŽ
- //printk("I2C closed\n");
- return 0;
- }
- static int I2C_ioctl(struct inode *inode,struct file *file,unsigned int cmd,unsigned long arg)
- {
- return 0;
- }
- //œ«É豞ע²áµœÏµÍ³Ö®ÖÐ
- static void I2C_setup_dev(struct cdev *dev,int minor,struct file_operations *fops)
- {
- int err;
- int devno=MKDEV(I2C_major,minor);
- cdev_init(dev,fops);
- dev->owner=THIS_MODULE;
- dev->ops=fops;
- err=cdev_add(dev,devno,1);
- if(err)
- printk(KERN_INFO"Error %d adding I2C %d\n",err,minor);
- }
- static struct file_operations I2C_remap_ops={
- .owner=THIS_MODULE,
- .open=I2C_open,
- .write = I2C_write,
- .read = I2C_read,
- .release=I2C_release,
- .ioctl=I2C_ioctl,
- };
- //×¢²áÉ豞Çý¶¯³ÌÐò£¬Ö÷ÒªÍê³ÉÖ÷É豞ºÅµÄ×¢²á
- static int __init s3c2410_I2C_init(void)
- {
- int result;
- dev_t dev = MKDEV(I2C_major,0);
- if(I2C_major)
- result = register_chrdev_region(dev,1,DEVICE_NAME);
- else
- {
- result = alloc_chrdev_region(&dev,0,1,DEVICE_NAME);
- I2C_major = MAJOR(dev);
- }
- if(result<0)
- {
- printk(KERN_WARNING"I2C:unable to get major %d\n",I2C_major);
- return result;
- }
- if(I2C_major == 0)
- I2C_major = result;
- printk(KERN_NOTICE"[DEBUG] I2C device major is %d\n",I2C_major);
- __raw_writel( (__raw_readl(S3C2410_CLKCON) | (1 << 16)), S3C2410_CLKCON);
- #if 0
- printk("\n S3C2410_CLKCON = %x \n", __raw_readl(S3C2410_CLKCON));
- area = request_mem_region(0x54000000, 16,"I2C");
- #endif
- i2c_base = ioremap(0x54000000, 16);
- clkcon = ioremap(CLKCON, 0x4);
- printk(KERN_INFO"i2c clock = %d\n", *clkcon & (0x1 << 16));
- *clkcon |= 0x1 << 16;
- I2C_setup_dev(&I2C_cdev,0,&I2C_remap_ops);
- return 0;
- }
- //Çý¶¯Ä£¿éжÔØ
- static void s3c2410_I2C_exit(void)
- {
- #if 0
- if (area) {
- release_resource(area);
- kfree(area);
- }
- #endif
- cdev_del(&I2C_cdev);
- unregister_chrdev_region(MKDEV(I2C_major,0),1);
- printk("I2C device uninstalled\n");
- }
- module_init(s3c2410_I2C_init);
- module_exit(s3c2410_I2C_exit);
原因是是早期版本的头文件,在该版本位置已经换掉了。
解决办法是使用find -name "xxx.h"查找到头文件对应的位置,然后将头文件添加进去。
另外一个错误:2410_I2C/I2C_drv.c:285: error: 'SA_INTERRUPT' undeclared (first use in this function
解决办法是SA_INTERRUPT定义在早期版本的内核,当前的内核没有定义该变量,而采用IRQF_DISABLE来代替
以上归根结底是版本的问题。
测试应用程序
- #include <stdio.h>
- #include <sys/types.h>
- #include <unistd.h>
- #include <fcntl.h>
- #include <time.h>
- #include <sys/ioctl.h>
- #define WATCHDOG_MAGIC 'k'
- #define FEED_DOG _IO(WATCHDOG_MAGIC,1)
- int main(int argc,char **argv)
- {
- int fd;
- char buff[]="farsight";
- //Žò¿ªI2C
- fd=open("/dev/i2c",O_RDWR);
- if(fd<0)
- {
- printf("cannot open the I2C device\n");
- return -1;
- }
- sleep(1);
- printf("buff_write=%s\n",buff);
- write (fd, buff, sizeof(buff));
- //printf(" read now!\n");
- memset (buff, '\0', sizeof(buff));
- //printf ("Read returns %d\n", read (fd, buff, sizeof(buff)));
- read (fd, buff, sizeof(buff));
- //read (fd, buff, 3);
- printf ("buff_read = %s\n", buff);
- close(fd);
- // while(1);
- // printf("end\n");
- return 0;
- }
与前面普通设备驱动1方法不同,这里的普通设备驱动利用i2c-core.c提供的i2c_transfer方法来实现设备驱动,而不是普通设备驱动1里面的通过操纵s3c2440的i2c寄存器来与设备通信
一、采用友善之臂的2.6.32.2内核,需要修改/linux-2.6.32.2/arch/arm/mach-s3c2440/mach-mini2440.c文件
1)添加 #include<linux/i2c.h>
2)在static struct platform_device *mini2440_devices[]前添加struct i2c_board_info i2c_devices[]结构体
//add
static struct i2c_board_info i2c_devices[] __initdata={
{I2C_BOARD_INFO("at24c08", 0x50), },
};
/* devices we initialise */
static struct platform_device *mini2440_devices[] __initdata = {
&s3c_device_usb,
&s3c_device_rtc,
&s3c_device_lcd,
&s3c_device_wdt,
&s3c_device_i2c0,//没有修改
&s3c_device_iis,
&mini2440_device_eth,
&s3c24xx_uda134x,
&s3c_device_nand,
&s3c_device_sdi,
&s3c_device_usbgadget,
};
3)在mini2440_machine_init(void)函数内添加i2c_register_board_info(0,i2c_devices,ARRAY_SIZE(i2c_devices));函数
static void __init mini2440_machine_init(void)
{
i2c_register_board_info(0,i2c_devices,ARRAY_SIZE(i2c_devices)); //add
#if defined (LCD_WIDTH)
s3c24xx_fb_set_platdata(&mini2440_fb_info);
#endif
s3c_i2c0_set_platdata(NULL);
s3c2410_gpio_cfgpin(S3C2410_GPC(0), S3C2410_GPC0_LEND);
s3c_device_nand.dev.platform_data = &friendly_arm_nand_info;
s3c_device_sdi.dev.platform_data = &mini2440_mmc_cfg;
platform_add_devices(mini2440_devices, ARRAY_SIZE(mini2440_devices));
s3c_pm_init();
}
二、在linux2.6.32.2/drivers/i2c/chips/目录下添加at24c08.c设备驱动文件,并对应的修改Kconfig和Makefile文件
#include <linux/init.h>
#include <linux/module.h>
#include <linux/i2c.h>
#include <linux/fs.h>
#include <linux/cdev.h>
#include <linux/device.h>
#include <linux/kdev_t.h>
#include <asm/uaccess.h>
#define major 155
static struct i2c_driver at24c08_driver;
static struct i2c_adapter *at24c08_adapter;
static unsigned short addr;
static struct class at24c08_cls = {
.name = "at24c08_cls",
};
ssize_t at24c08_read (struct file *filp, char __user *buf, size_t sz, loff_t *off)
{
struct i2c_msg msg[2];
unsigned char args, data;
if (sz != 1)
return -EINVAL;
copy_from_user((void *)&args, buf, 1);
/* 先传读地址 */
msg[0].addr = addr;
msg[0].buf = &args;
msg[0].len = 1;
msg[0].flags = 0;
/* 再 读 */
msg[1].addr = addr;
msg[1].buf = &data;
msg[1].len = 1;
msg[1].flags = 1; /* 读 */
if (2 == i2c_transfer(at24c08_adapter, msg, 2)) {
/* 读成功 */
copy_to_user((void *)buf, &data, 1);
return 1;
}
else
return -EIO;
}
ssize_t at24c08_write (struct file *filp, const char __user *buf, size_t sz, loff_t *off)
{
struct i2c_msg msg;
unsigned char args[2];
copy_from_user((void *)&args, buf, 2);
/* args[0] = addr, args[1] = val */
msg.addr = addr;
msg.buf = args;
msg.len = 2;
msg.flags = 0; /* 写 */
if(1 == i2c_transfer(at24c08_adapter,&msg, 1))
return 2;
else
return -EIO;
}
static struct file_operations at24c08_fops = {
.owner = THIS_MODULE,
.read = at24c08_read,
.write = at24c08_write,
};
static struct cdev cdev;
static int at24c08_probe(struct i2c_client *client, const struct i2c_device_id *dev_id)
{
register_chrdev_region(major, 1, "at24c08");
cdev_init(&cdev, &at24c08_fops);
cdev_add(&cdev, MKDEV(major, 0), 1);
class_register(&at24c08_cls);
device_create(&at24c08_cls, NULL, MKDEV(major, 0), NULL, "at24c08_dev");
return 0;
}
static int at24c08_remove(struct i2c_client *client)
{
device_destroy(&at24c08_cls, MKDEV(major, 0));
class_destroy(&at24c08_cls);
cdev_del(&cdev);
unregister_chrdev_region(MKDEV(major, 0), 1);
return 0;
}
static int at24c08_detect(struct i2c_client *client, int kind, struct i2c_board_info *bd_info)
{
strcpy(bd_info->type, "at24c08");
addr = bd_info->addr = client->addr;
at24c08_adapter = client->adapter;
return 0;
}
static const struct i2c_device_id at24c08_id[] = {
{"at24c08", 0},
{}
};
static unsigned short ignore[] = { I2C_CLIENT_END };
static const unsigned short normal_i2c[] = {0x50, I2C_CLIENT_END};
static const struct i2c_client_address_data addr_data = {
.normal_i2c = normal_i2c,
.probe = ignore,
.ignore = ignore,
};
static struct i2c_driver at24c08_driver= {
.probe = at24c08_probe,
.remove = at24c08_remove,
.driver = {
.name = "at24c08",
},
.id_table = at24c08_id,
.detect = at24c08_detect,
.address_data = &addr_data,
.class = I2C_CLASS_HWMON | I2C_CLASS_SPD,
};
static int at24c08_init(void)
{
i2c_add_driver(&at24c08_driver);
return 0;
}
static void at24c08_exit(void)
{
i2c_del_driver(&at24c08_driver);
return ;
}
module_init(at24c08_init);
module_exit(at24c08_exit);
MODULE_LICENSE("GPL");
MODULE_AUTHOR("100ask.net Young");
以上要说明的是为什么insmod at24c08.ko之后会在/dev/目录下自动创建/dev/at24c08_dev文件节点
主要归功于两个函数
static struct class at24c08_cls = { .name = "at24c08_cls", };
class_register(&at24c08_cls);
device_create(&at24c08_cls, NULL, MKDEV(major, 0), NULL, "at24c08_dev");
内核中定义了struct class结构体,顾名思义,一个struct class结构体类型变量对应一个类,内核同时提供了class_create(…)函数,可以用它来创建一个类,这个类存放于sysfs下面,一旦创建好了这个类,再调用device_create(…)函数来在/dev目录下创建相应的设备节点。这样,加载模块的时候,用户空间中的udev会自动响应device_create(…)函数,去/sysfs下寻找对应的类从而创建设备节点。
与class_create等价的函数是class_register,只是他们对应的注销函数不同class_unregister和class_destory。
三、在linux2.6.32.2目录下make menuconfig进行内核定制之后再make则会生成i2c-core.ko,i2c-s3c2440.ko,at24c08.ko等文件,将三个文件都insmod到内核中,在/dev/目录下会自动生成at24c08_dev文件节点,但是在重启之后会消失,因为insmod是动态加载的,如果在重启后还要有文件节点,则要将加载命令写到启动脚本中去。
i2c的设备驱动可以直接利用内核提供的i2c-dev.c文件提供的ioctl函数接口在应用层实现对i2c设备的读写,但是在应用层使用ioctl函数对应用程序员要求较高,需要自行构建msg结构体,必须了解设备的操作流程,时序之类的。
另外i2c设备的驱动也可以通过普通的设备驱动实现,像往常的驱动一样实现,然后在应用层就可以像读取普通文件一样操作,无需再考虑读写时序。其实普通的设备驱动也可以用两种方法实现,1)构建字符设备驱动,在open,read,write等函数中直接操作i2c总线的相关寄存器来读写i2c设备,但是这种方法因平台不同,设备不同都要重新写驱动,2)在设备驱动中调用i2c-core.c提供的i2c_transfer函数来实现和i2c设备的通信,这样只要对不同的设备写不同的驱动就行了。
下面就分别对i2c-dev驱动、普通设备驱动方法1和普通设备驱动方法2来介绍一下,共分为博客的三篇文章:1)i2c驱动之i2c-dev驱动,2)普通设备驱动1,3)普通设备驱动方法2(推荐方法)。
关于i2c设备驱动,自己在理解的过程中感觉比较好的资料的连接:
linux下I2C驱动架构全面分析 、 深入源代码设计i2c驱动 、 宋宝华老师i2c驱动架构视频
在/linux-2.6.32.2/drivers/i2c目录下
----Algos/ 一些i2c总线适配器通信的算法,个人感觉是用I/O口模拟实现i2c通信的算法
----Busses/ I2C总线驱动的方法,对应于s3c2440适配器驱动的文件是I2c-s3c2410.c
----Chips/ I2C设备驱动,具体到某个设备,比如at24c08等
----I2c-boardinfo.c
----I2c-core.c I2C核心文件,用于联系设备驱动和总线驱动,作为一个桥梁,有用的函数i2c_add_addapter
i2c_add_driver,和i2c_transfer函数
----I2c-dev.c 通用的i2c设备驱动
----Kconfig
----Makefile
开始在内核编译i2c-dev通用驱动
1)在linux-2.6.32.2/内核目录下make menuconfig,选择如下Device Drivers
2)进入Device Drivers目录,选择I2C Support,表示编译I2C驱动模块,会将i2c-core.c编译成模块文件i2c-core.ko
3)进入I2C support
4)选择模块化编译I2C device interface "M",则会将i2c-dev.c编译成i2c-dev.ko
5)选择I2C Hardware Bus support,并进入
选择s3c2410 I2c Driver则会将i2c-s3c2410.c编译成i2c-s3c2410.ko驱动模块
6)选择Miscellaneous I2c Chip Support,并进入
会提示让你选择编译具体的设备驱动,因为这里我们采用内核提供的通用设备驱动i2c-dev,所以这里的驱动就暂时不编译了
以上编译总共得到了3个驱动文件i2c-core.ko,i2c-dev.ko,i2c-s3c2410.ko
将这三个模块insmod到内核中,顺序是i2c-core.ko,i2c-s3c2410.ko,i2c-dev.ko,会自动创建/dev/i2c/0设备节点,然后就可以直接调用/dev/i2c/0文件节点进行访问设备了
之后应用程序员可以利用下面两种ioctl函数
ioctl(fd, I2C_RDWR, (unsigned long)&work_queue);或者
ioctl(file,I2C_SMBUS,&args);
进行与i2c设备通信了。
验证i2c应用程序:
- /*
- //作者:王磊
- //日期:2013.11.17
- //文件功能:实现ioctl函数调用,并操作i2c设备/dev/i2c/0进行读写数据
- //可以用i2c -r来检验数据是否已写入
- */
- #include<stdio.h>
- #include<linux/types.h>
- #include<fcntl.h>
- #include<unistd.h>
- #include<stdlib.h>
- #include<sys/types.h>
- #include<sys/ioctl.h>
- #include<errno.h>
- #include<assert.h>
- #include<string.h>
- #include<linux/i2c.h>
- #include<linux/i2c-dev.h>
- int main(int argc, char** argv)
- {
- struct i2c_rdwr_ioctl_data work_queue;
- unsigned int slave_address,reg_address,dat;
- unsigned int fd;
- int ret;
- char select;
- fd=open("/dev/i2c/0",O_RDWR);
- if(!fd)
- {
- printf("error on opening the device file\n");
- exit(1);
- }
- ioctl(fd,I2C_TIMEOUT,2);//超时时间
- ioctl(fd,I2C_RETRIES,1);//重复次数
- //nmsgs决定了有多少start信号,一个msgs对应一个start信号,但这个start信号又不能适用于repeat start
- //在nmsg个信号结束后总线会产生一个stop
- work_queue.nmsgs = 1;
- work_queue.msgs = (struct i2c_msg *)malloc(work_queue.nmsgs * sizeof(work_queue.msgs));
- if(!work_queue.msgs)
- {
- printf("memory alloc failed");
- close(fd);
- exit(1);
- }
- slave_address = 0x50;//24c08的访问地址是101000b
- printf("please select:w or r?\n");
- scanf("%c", &select);
- if('w' == select)
- {
- printf("please input:address,dat?(example:0x00,0x00)\n");
- scanf("%x,%x", ®_address, &dat);
- //往i2c里面写数据
- printf("began to write\n");
- work_queue.nmsgs = 1;
- (work_queue.msgs[0]).len = 2;//buf的长度
- (work_queue.msgs[0]).flags = 0;//write
- (work_queue.msgs[0]).addr = slave_address;//设备地址
- (work_queue.msgs[0]).buf = (unsigned char *)malloc(2);
- (work_queue.msgs[0]).buf[0] = reg_address;//写的地址
- (work_queue.msgs[0]).buf[1] = dat;//你要写的数据
- ret = ioctl(fd, I2C_RDWR, (unsigned long)&work_queue);
- if(ret < 0)
- printf("error during I2C_RDWR ioctl with error code %d\n", ret);
- }
- else if('r' == select)
- {
- printf("please input:address?(example:0x00)\n");
- scanf("%x", ®_address);
- //从i2c里面读出数据
- printf("began to read:");
- work_queue.nmsgs = 1;
- //先设定一下地址
- (work_queue.msgs[0]).flags = 0;//write
- (work_queue.msgs[0]).addr = slave_address;
- (work_queue.msgs[0]).len = 1;
- (work_queue.msgs[0]).buf = (unsigned char *)malloc(1);
- (work_queue.msgs[0]).buf[0] = reg_address;//因为上面buf已经分配过了
- ret = ioctl(fd, I2C_RDWR, (unsigned long)&work_queue);
- if(ret < 0)
- printf("error during I2C_RDWR ioctl with error code %d\n", ret);
- //因为i2c-dev不支持repeat start,所以只能将读数据操作中的写地址和读数据分为两次消息。
- //然后从刚才设定的地址处读
- work_queue.nmsgs = 1;
- (work_queue.msgs[0]).flags = I2C_M_RD;
- (work_queue.msgs[0]).addr = slave_address;
- (work_queue.msgs[0]).len = 1;
- (work_queue.msgs[0]).buf[0] = 0;//初始化读缓冲
- ret = ioctl(fd, I2C_RDWR, (unsigned long)&work_queue);
- if(ret < 0)
- printf("error during I2C_RDWR ioctl with error code %d\n", ret);
- printf("reg_address=0x%2x,dat=0x%2x\n", reg_address, work_queue.msgs[0].buf[0]);
- }
- close(fd);
- free((work_queue.msgs[0]).buf);
- free(work_queue.msgs);
- return 0;
- }