(1)vi at24cxx.c
#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>
static unsigned short ignore[] = { I2C_CLIENT_END };
static unsigned short normal_addr[] = { 0xA0, I2C_CLIENT_END };
static struct i2c_client_address_data addr_data = {
.normal_i2c = normal_addr,
.probe = ignore,
.ignore = ignore,
};
static int at24cxx_detect(struct i2c_adapter *adapter, int address, int kind)
{
printk("at24cxx detect\n");
return 0;
}
static int at24cxx_attach(struct i2c_adapter *adapter)
{
return i2c_probe(adapter, &addr_data, at24cxx_detect);
}
static int at24cxx_detach(struct i2c_client *client)
{
printk("at24cxx detach\n");
return 0;
}
static struct i2c_driver at24cxx_driver = {
.driver = {
.name = "at24cxx",
},
.attach_adapter = at24cxx_attach,
.detach_client = at24cxx_detach,
};
int __init at24cxx_init(void)
{
i2c_add_driver(&at24cxx_driver);
return 0;
}
void __exit at24cxx_exit(void)
{
i2c_del_driver(&at24cxx_driver);
}
module_init(at24cxx_init);
module_exit(at24cxx_exit);
MODULE_LICENSE("GPL");
测试驱动:
# insmod at24cxx.ko
i2c-adapter i2c-0: Invalid probe address 0xa0 //地址值只能是7位,呵呵!
IIC地址从0xa0改为0x50,然后再测试:
# insmod at24cxx.ko
加载成功,没有打印at24cxx detect。//原来JZ2440没有IIC设备,呵呵!
(2)vi at24cxx.c(强制匹配)
static unsigned short force_addr[] = {ANY_I2C_BUS, 0x50, I2C_CLIENT_END};
static unsigned short *forces[] = {force_addr,NULL};
static struct i2c_client_address_data addr_data = {
.normal_i2c = ignore,
.probe = ignore,
.ignore = ignore,
.forces = forces,
};
测试驱动:
# insmod at24cxx.ko
at24cxx detect
# rmmod at24cxx.ko
(3)vi at24cxx.c(构造i2c_client,用于收发数据)
static struct i2c_driver at24cxx_driver;
static int at24cxx_detect(struct i2c_adapter *adapter, int address, int kind)
{
struct i2c_client *new_client;
printk("at24cxx detect\n");
new_client = kzalloc(sizeof(struct i2c_client), GFP_KERNEL);
new_client->addr = address;
new_client->adapter = adapter;
new_client->driver = &at24cxx_driver;
strcpy(new_client->name, "at24cxx");
i2c_attach_client(new_client);
return 0;
}
static int at24cxx_detach(struct i2c_client *client)
{
printk("at24cxx detach\n");
i2c_detach_client(client);
kfree(i2c_get_clientdata(client));
return 0;
}
测试驱动:
# insmod at24cxx.ko
at24cxx detect
# rmmod at24cxx.ko
at24cxx detach
(4)vi at24cxx.c(增加字符设备驱动程序)
#include <linux/fs.h>
static int major;
ssize_t at24cxx_read (struct file *file, char __user *buf, size_t size, loff_t *offset)
{
return 0;
}
ssize_t at24cxx_write (struct file *file, const char __user *buf, size_t size, loff_t *offset)
{
return 0;
}
static struct file_operations at24cxx_fops ={
.owner = THIS_MODULE,
.read = at24cxx_read,
.write = at24cxx_write,
};
static struct class *cls;
struct i2c_client *at24cxx_client;
static int at24cxx_detect(struct i2c_adapter *adapter, int address, int kind)
{
printk("at24cxx detect\n");
at24cxx_client = kzalloc(sizeof(struct i2c_client), GFP_KERNEL);
at24cxx_client->addr = address;
at24cxx_client->adapter = adapter;
at24cxx_client->driver = &at24cxx_driver;
strcpy(at24cxx_client->name, "at24cxx");
i2c_attach_client(at24cxx_client);
major = register_chrdev(0, "at24cxx", &at24cxx_fops);
cls = class_create(THIS_MODULE, "at24cxx");
class_device_create(cls, NULL, MKDEV(major,0), NULL, "at24cxx");
return 0;
}
static int at24cxx_detach(struct i2c_client *client)
{
printk("at24cxx detach\n");
class_device_destroy(cls, MKDEV(major,0));
class_destroy(cls);
unregister_chrdev(major, "at24cxx");
i2c_detach_client(client);
kfree(i2c_get_clientdata(client));
return 0;
}
测试驱动:
# ls /dev/at24cxx -l
ls: /dev/at24cxx: No such file or directory
# insmod at24cxx.ko
at24cxx detect
# ls /dev/at24cxx -l
crw-rw---- 1 0 0 252, 0 Jan 1 00:01 /dev/at24cxx
# rmmod at24cxx.ko
at24cxx detach
# ls /dev/at24cxx -l
ls: /dev/at24cxx: No such file or directory
(5)vi at24cxx.c(使用I2C传输函数完成字符设备读写)
#include <asm/uaccess.h>
struct i2c_client *at24cxx_client;
ssize_t at24cxx_read (struct file *file, char __user *buf, size_t size, loff_t *offset)
{
unsigned char address;
unsigned char data;
struct i2c_msg msg[2];
int ret;
if(size != 1)
return -EINVAL;
copy_from_user(&address, buf, 1);
msg[0].addr = at24cxx_client->addr;
msg[0].buf = &address;
msg[0].len = 1;
msg[0].flags = 0;
msg[1].addr = at24cxx_client->addr;
msg[1].buf = &data;
msg[1].len = 1;
msg[1].flags = I2C_M_RD;
ret = i2c_transfer(at24cxx_client->adapter, msg, 2);
if(ret == 2)
{
copy_to_user(&buf[0], &data, 1);
return 1;
}
else
return -EIO;
}
ssize_t at24cxx_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;
if(size != 2)
return -EINVAL;
copy_from_user(val, buf, 2);
msg[0].addr = at24cxx_client->addr;
msg[0].buf = val;
msg[0].len = 2;
msg[0].flags = 0;
ret = i2c_transfer(at24cxx_client->adapter, msg, 1);
if(ret == 1)
return 2;
else
return -EIO;
}
static struct file_operations at24cxx_fops ={
.owner = THIS_MODULE,
.read = at24cxx_read,
.write = at24cxx_write,
};
测试程序:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
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/at24cxx", O_RDWR);
if (fd < 0)
{
printf("can't open /dev/at24cxx\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;
}
测试驱动:
无,JZ2440不支持IIC