设备树:
&i2c1 {
status = "okay"; //要配置为okay或者ok
drv-i2c-i2c2@50{
compatible ="rktest,drv-i2c2-test"; //匹配的名字 一个字符都不能错和设备驱动里的一致
reg =<0x50>;//设备地址 at24c02 A1,A1,A3都接地
};
};
i2c设备驱动:、
#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/module.h>
#include <linux/slab.h>
#include <linux/jiffies.h>
#include <linux/i2c.h>
#include <linux/mutex.h>
#include <linux/fs.h>
#include <asm/uaccess.h>
#include <linux/cdev.h>
#ifdef CONFIG_OF
#include <linux/of.h>
#include <linux/of_gpio.h>
#include <linux/of_platform.h>
#endif
#define SPEED 100 * 1000 //100k
static struct device *drv_i2c2_device;
static int major;
static struct class *drv_i2c2_class;
//static i2c_client *drv_i2c2_client;
struct drv_i2c2_pri {
struct cdev dev;
struct i2c_client *client;
};
struct drv_i2c2_pri dev_i2c2;
static ssize_t drv_i2c2_read(struct file *file, char __user *buf, size_t size, loff_t * offset)
{
unsigned char address;
unsigned char data[50];
struct i2c_msg msg[2];
int ret;
/* address = buf[0]
* data = buf[1]
*/
if (size != 1)
return -EINVAL;
copy_from_user(&address, buf, 1);
/* 数据传输三要素: 源,目的,长度 */
/* 读AT24CXX时,要先把要读的存储空间的地址发给它 */
msg[0].addr = dev_i2c2.client->addr; /* 目的 */
msg[0].buf = &address; /* 源 */
msg[0].len = 1; /* 地址=1 byte */
msg[0].flags = 0; /* 表示写 */
msg[0].scl_rate=SPEED;
/* 然后启动读操作 */
msg[1].addr = dev_i2c2.client->addr; /* 源 */
msg[1].buf = &data; /* 目的 */
msg[1].len = 10; /* 数据=1 byte */
msg[1].flags = 1; /* 表示读 */
msg[1].scl_rate=SPEED;
ret = i2c_transfer(dev_i2c2.client->adapter, msg, 2);
if (ret == 2)
{
copy_to_user(buf, &data, 1);
return 1;
}
else
return -EIO;
}
static ssize_t drv_i2c2_write(struct file *file, const char __user *buf, size_t size, loff_t *offset)
{
unsigned char val[2];
struct i2c_msg msg[1];
int ret;
/* address = buf[0]
* data = buf[1]
*/
if (size != 2)
return -EINVAL;
copy_from_user(val, buf, 2);
/* 数据传输三要素: 源,目的,长度 */
msg[0].addr =dev_i2c2.client->addr; /* 目的 */
msg[0].buf = val; /* 源 */
msg[0].len = 2; /* 地址+数据=2 byte */
msg[0].flags = 0; /* 表示写 */
msg[0].scl_rate=SPEED;
ret = i2c_transfer(dev_i2c2.client->adapter, msg, 1);
if (ret == 1)
return 2;
else
return -EIO;
}
static long drv_i2c2_ioctl(struct file *fp, unsigned int cmd, unsigned long arg)
{
int res = 0;
static char data[32];
switch(cmd){
case 0:
break;
case 1:
break;
case 2:
break;
default:
printk(KERN_INFO "invalid cmd");
break;
}
res = copy_to_user((void *)arg,&data,sizeof(data));
return 0;
}
static struct file_operations drv_i2c2_fops = {
.owner = THIS_MODULE,
.read = drv_i2c2_read,
.write = drv_i2c2_write,
.unlocked_ioctl =drv_i2c2_ioctl,
};
static int drv_i2c2_remove(struct i2c_client * client)
{
device_destroy(drv_i2c2_class,MKDEV(major, 0));
class_destroy(drv_i2c2_class);
//unregister_chrdev_region(MKDEV(global_major, 0), 1);
unregister_chrdev(major, "drv-i2c2-test");
return 0;
}
static int drv_i2c2_probe(struct i2c_client *client, const struct i2c_device_id *id)
{
printk(KERN_EMERG"i2c_client->driver->name:%s\n",client->driver->id_table->name);
//at24cxx_client = kzalloc(sizeof(struct i2c_client), GFP_KERNEL);
dev_i2c2.client = client;
/*system will auto allocate major*/
major = register_chrdev(0, "drv-i2c2", &drv_i2c2_fops);
/*create class*/
drv_i2c2_class = class_create(THIS_MODULE, "drv-i2c2");
/*create device for app*/
drv_i2c2_device = device_create(drv_i2c2_class, NULL, MKDEV(major, 0),NULL,"drv-i2c2-test");
return 0;
};
static const struct of_device_id of_drv_i2c2_match[] = {
{ .compatible = "rktest,drv-i2c2-test"},
{ },
};
static const struct i2c_device_id drv_i2c2_id[] = {};
static struct i2c_driver drv_i2c2_driver = {
.driver = {
.name = "drv-i2c2-driver",
.owner = THIS_MODULE,
.of_match_table = of_match_ptr(of_drv_i2c2_match),
},
.probe =drv_i2c2_probe,
.remove=drv_i2c2_remove,
.id_table=drv_i2c2_id,
//.attach_adapter = drv_i2c_attach,
//.detect=drv_i2c_detect,
//.address_list =address_list,
};
static int drv_i2c2_init(void)
{
static int ret;
ret=i2c_add_driver(&drv_i2c2_driver);//platform_driver_register(&drv_i2c_driver);//
printk(KERN_EMERG"drv_i2c2_init:%d\n",ret);
return 0;
}
static void drv_i2c2_exit(void)
{
printk(KERN_EMERG"drv_i2c2_exit:\n");
i2c_del_driver(&drv_i2c2_driver);
}
module_init(drv_i2c2_init);
module_exit(drv_i2c2_exit);
MODULE_LICENSE("GPL");
测试程序:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
/* i2c_test r addr
* i2c_test w addr val
*/
void print_usage(char *file)
{
printf("%s r addr\n", file);
printf("%s w addr val\n", file);
}
int main(int argc, char **argv)
{
int fd;
unsigned char buf[2];
if ((argc != 3) && (argc != 4))
{
print_usage(argv[0]);
return -1;
}
fd = open("/dev/drv-i2c-test", O_RDWR);
if (fd < 0)
{
printf("can't open /dev/drv-i2c-test\n");
return -1;
}
if (strcmp(argv[1], "r") == 0)
{
buf[0] = strtoul(argv[2], NULL, 0);
read(fd, buf, 1);
printf("data: %c, %d, 0x%2x\n", buf[0], buf[0], buf[0]);
}
else if (strcmp(argv[1], "w") == 0)
{
buf[0] = strtoul(argv[2], NULL, 0);
buf[1] = strtoul(argv[3], NULL, 0);
write(fd, buf, 2);
}
else
{
print_usage(argv[0]);
return -1;
}
return 0;
}