在《 linux IIC子系统分析(四)——I2c bus初始化》 中我们创建了I2C 总线驱动,I2C adapter device 和adapter drivers也在这时创建
在《linux IIC子系统分析(七)——实例分析通过i2c-dev操作I2C设备》 我们实现了在应用层驱动I2C设备EEPROM
在《linux IIC子系统分析(九)——实例分析通过sysfs访问I2c设备》我们实现了通过sys导出的bin属性访问I2C设备EEPROM
在我们实际开发中,I2C 总线驱动一般芯片原厂会提供,我们开发一般是设计设备驱动。
在访问I2C设备驱动的方法中:
通过i2c-dev 从应用层驱动设备,这样的设计需要对I2C通讯协议非常熟悉,一般比较少使用。
通过sysfs导出的bin属性文件访问,这种方法多用了查看驱动设备的信息,实际使用它来操作设备较少。
下面介绍一种比较通用客户驱动程序开发的方法,其开发步骤为:
(1)注册板载I2C设备信息
(2)定义I2C驱动ID
(3)定义i2c_driver结构并完成其相应的函数
(4)模块初始化时添加/撤销时删除i2c_driver
(5)添加设备节点,sysfs bin属性
注册板载I2C信息,与上一章相同在/linux-2.6.32.2/arch/arm/mach-s3c2440/math-mini2440.c中添加:
#include <linux/i2c/at24.h>
#include <linux/i2c.h>
static struct s3c24xx_mci_pdata mini2440_mmc_cfg = {
.gpio_detect = S3C2410_GPG(8),
.gpio_wprotect = S3C2410_GPH(8),
.set_power = NULL,
.ocr_avail = MMC_VDD_32_33|MMC_VDD_33_34,
};
static struct at24_platform_data at24c02 = {
.byte_len = SZ_2K / 8,
.page_size = 8,
.flags = 0,
};
static struct i2c_board_info __initdata smdk_i2c_devices[] = {
/* more devices can be added using expansion connectors */
{
I2C_BOARD_INFO("24c02", 0x50),
.platform_data = &at24c02,
},
};
在函数static void __init mini2440_machine_init(void) 中添加:
i2c_register_board_info(0, smdk_i2c_devices, ARRAY_SIZE(smdk_i2c_devices));
添加驱动程序如下:
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/fs.h>
#include <linux/slab.h>
#include <linux/init.h>
#include <linux/list.h>
#include <linux/i2c.h>
#include <linux/i2c-dev.h>
#include <linux/smp_lock.h>
#include <linux/jiffies.h>
#include <asm/uaccess.h>
#include <linux/delay.h>
#define DEBUG 1
#ifdef DEBUG
#define dbg(x...) printk(x)
#else
#define dbg(x...) (void)(0)
#endif
#define I2C_MAJOR 89
#define DEVICE_NAME "at24c02"
static struct class *my_dev_class;
static struct i2c_client *my_client;
static struct i2c_driver my_i2c_driver;
static struct i2c_device_id my_ids[] = {
{"24c01",0x50},
{"24c02",0x50},
{"24c08",0x50},
{}
};
MODULE_DEVICE_TABLE(i2c,my_ids);
static int my_i2c_probe(struct i2c_client *client, const struct i2c_device_id *id)
{
int res;
struct device *dev;
dbg("probe:name = %s,flag =%d,addr = %d,adapter = %d,driver = %s\n",client->name,
client->flags,client->addr,client->adapter->nr,client->driver->driver.name );
dev = device_create(my_dev_class, &client->dev,
MKDEV(I2C_MAJOR, 0), NULL,
DEVICE_NAME);
if (IS_ERR(dev))
{
dbg("device create error\n");
goto out;
}
my_client = client;
return 0;
out:
return -1;
}
static int my_i2c_remove(struct i2c_client *client)
{
dbg("remove\n");
return 0;
}
static ssize_t at24c02_read(struct file *fd, char *buf, ssize_t count, loff_t *offset)
{
char *tmp;
int ret;
char data_byte;
char reg_addr = 0,i;
struct i2c_client *client = (struct i2c_client*) fd->private_data;
struct i2c_msg msgs[2];
dbg("read:count = %d,offset = %ld\n",count,*offset);
tmp = kmalloc(count,GFP_KERNEL);
if (!tmp)
{
dbg("malloc error in read function\n");
goto out;
}
reg_addr = *offset;
msgs[0].addr = client->addr;
msgs[0].flags = client->flags & (I2C_M_TEN|I2C_CLIENT_PEC) ;
msgs[0].len = 1;
msgs[0].buf = (char *)®_addr;
msgs[1].addr= client->addr;
msgs[1].flags = client->flags & (I2C_M_TEN|I2C_CLIENT_PEC);
msgs[1].flags |= I2C_M_RD;
msgs[1].len = count;
msgs[1].buf = (char*)tmp;
ret = i2c_transfer(client->adapter,&msgs,2);
if (ret != 2)
goto out;
if (copy_to_user(buf, tmp, count))
goto out;
kfree(tmp);
return count;
out:
kfree(tmp);
return -1;
}
static int at24c02_ioctl(struct file *fd, unsigned int cmd, unsigned long arg)
{
dbg("ioctl code ...\n");
return 0;
}
static ssize_t at24c02_write(struct file *fd, char *buf, ssize_t count, loff_t *offset)
{
int ret,i;
char *tmp;
int errflg;
struct i2c_msg msg;
struct i2c_client *client = (struct i2c_client*) fd->private_data;
char tmp_data[2];
dbg("write:count = %d,offset = %ld\n",count,*offset);
tmp = kmalloc(count, GFP_KERNEL);
if (!tmp)
goto out;
if (copy_from_user(tmp, buf, count))
goto out;
msg.addr = client->addr;
msg.flags = client->flags & (I2C_M_TEN | I2C_CLIENT_PEC);
for (i = 0; i < count; i++) {
msg.len = 2;
tmp_data[0] = *offset + i;
tmp_data[1] = tmp[i];
msg.buf = tmp_data;
ret = i2c_transfer(client->adapter,&msg,1);
if (ret != 1)
goto out;
msleep(1);
}
kfree(tmp);
return ((ret == 1) ? count:ret);
out:
kfree(tmp);
return -1;
}
static int at24c02_open(struct inode *inode, struct file *fd)
{
fd->private_data =(void*)my_client;
return 0;
}
static int at24c02_release(struct inode *inode, struct file *fd)
{
dbg("release\n");
fd->private_data = NULL;
return 0;
}
static const struct file_operations i2c_fops = {
.owner = THIS_MODULE,
.open = at24c02_open,
.read = at24c02_read,
.write = at24c02_write,
.unlocked_ioctl = at24c02_ioctl,
.release = at24c02_release,
};
static struct i2c_driver my_i2c_driver = {
.driver = {
.name = "i2c_demo",
.owner = THIS_MODULE,
},
.probe = my_i2c_probe,
.remove = my_i2c_remove,
.id_table = my_ids,
};
static int __init my_i2c_init(void)
{
int res;
res = register_chrdev(I2C_MAJOR,DEVICE_NAME,&i2c_fops);
if (res)
{
dbg("register_chrdev error\n");
return -1;
}
my_dev_class = class_create(THIS_MODULE, DEVICE_NAME);
if (IS_ERR(my_dev_class))
{
dbg("create class error\n");
unregister_chrdev(I2C_MAJOR, DEVICE_NAME);
return -1;
}
return i2c_add_driver(&my_i2c_driver);
}
static void __exit my_i2c_exit(void)
{
unregister_chrdev(I2C_MAJOR, DEVICE_NAME);
class_destroy(my_dev_class);
i2c_del_driver(&my_i2c_driver);
}
MODULE_AUTHOR("itspy<itspy.wei@gmail.com>");
MODULE_DESCRIPTION("i2c client driver demo");
MODULE_LICENSE("GPL");
module_init(my_i2c_init);
module_exit(my_i2c_exit);
将驱动程序编译成驱动模块添加到内核,可以查看到:
[root@FriendlyARM i2c-0]# ls
0-0050 name subsystem
delete_device new_device uevent
[root@FriendlyARM i2c-0]# cd 0-0050/
[root@FriendlyARM 0-0050]# ls
at24c02 driver modalias name subsystem uevent
[root@FriendlyARM 0-0050]# pwd
/sys/devices/platform/s3c2440-i2c/i2c-0/0-0050
[root@FriendlyARM 0-0050]# ls /dev -l
crw-rw---- 1 root root 10, 59 Jan 1 2000 adc
crw-rw---- 1 root root 89, 0 Jan 1 01:14 at24c02
crw-rw---- 1 root root 14, 4 Jan 1 2000 audio
这样就可以与正常驱动设备一样操作eeprom了。
由于各种原因,后续文章内容将更新到公众号,本平台将不再做更新。
CSDN上相关文章的测试工程代码,也统一放到了公众号上,可以免费免积分下载
有需要的可以扫下面二维码转到公众号,欢迎关注,欢迎提出您宝贵的意见和建议!
liwen01 2022.08.21