1,ltc2451_i2c_drv.c
#include <linux/init.h>
#include <linux/module.h>
#include <linux/i2c.h>
#include <linux/miscdevice.h>
#include <linux/slab.h>
#include <linux/fs.h>
#include <asm/uaccess.h>
//设计一个驱动针对不同的设备的不同数据(私有)
struct LTC2451_Private{
char *name; //描述
int version;//版本
};
//设计一个全局的设备对象
struct i2c_ltc2451_global{
struct i2c_client *client;//描述了一个从设备的信息---从设备地址,名字
struct LTC2451_Private *private;
struct miscdevice i2c_misc;
};
//全局的指针
struct i2c_ltc2451_global *ltc2451_dev;
int ltc2451_i2c_recv(const struct i2c_client * client, char * buf, int count)
{
int ret;
struct i2c_adapter *adapter = client->adapter;//描述控制器, 比如编号,算法
struct i2c_msg msg;//传输的数据包
msg.addr = client->addr;//数据包传输給哪个从设备
msg.flags = I2C_M_RD; //读还是写-- 1读,0写
msg.len = count;//数据大小bytes
msg.buf = buf;
//参数1--适配器,来自于client
//参数2--传输的消息体--数据包
//参数3--消息体的个数
//返回值--正确为消息的个数,错误为负数
//i2c_transfer(struct i2c_adapter * adap, struct i2c_msg * msgs, int num)
ret = i2c_transfer(adapter, &msg, 1);
return ret==1?count:ret;
}
ssize_t ltc2451_i2c_read (struct file *filp, char __user *buf, size_t count, loff_t *fops)
{
int ret;
char *temp = NULL;
printk("------%s--------\n", __FUNCTION__);
//简单的参数判断
if(count != 2 )
{
printk("------count:%d--------\n",count);
return -EINVAL;
}
//动态的分配一个空间,用于存放从硬件获取到的数据
temp = kzalloc(count, GFP_KERNEL);
//i2c_master_recv(const struct i2c_client * client, char * buf, int count);
//i2c_master_send(const struct i2c_client * client, const char * buf, int count);
// 1,从硬件中获取数据
ret = ltc2451_i2c_recv(ltc2451_dev->client, temp, count);
printk("ret:%d, temp[0]:%x, temp[1]:%x\n",ret, temp[0], temp[1]);
if(ret < 0)
{
printk("ltc2451_dev_i2c_recv error\n");
goto err_free;
}
// 2, 将数据传递给用户
ret = copy_to_user(buf, temp, count);
if(ret > 0)
{
printk("copy to user error\n");
ret = -EFAULT;
goto err_free;
}
kfree(temp);
return count;
err_free:
kfree(temp);
return ret;
}
int ltc2451_i2c_open (struct inode *inode, struct file *filp)
{
printk("------%s--------\n", __FUNCTION__);
//一般也是做初始化
return 0;
}
int ltc2451_i2c_close (struct inode *inode, struct file *flip)
{
printk("------%s--------\n", __FUNCTION__);
return 0;
}
const struct file_operations ltc2451_i2c_fops = {
.open = ltc2451_i2c_open,
.read = ltc2451_i2c_read,
.release = ltc2451_i2c_close,
};
int ltc2451_i2c_probe(struct i2c_client *client, const struct i2c_device_id *id)//为什么是id
{
struct LTC2451_Private *p = (struct LTC2451_Private *)id->driver_data;
printk("-------%s-------\n",__FUNCTION__);
printk("client name = %s\n", id->name);//
printk("client addr = %X\n", client->addr);
printk("name descriptoin : %s \n", p->name);
printk("verison : 0x%x \n", p->version);
ltc2451_dev = kzalloc(sizeof(struct i2c_ltc2451_global), GFP_KERNEL);//GFP_KERNEL
//记录当前匹配之后的i2c client
ltc2451_dev->client = client;
ltc2451_dev->private = (struct LTC2451_Private *)id->driver_data;
//实现fops
ltc2451_dev->i2c_misc.fops = <c2451_i2c_fops;
ltc2451_dev->i2c_misc.minor = 200; //MISC_DYNAMIC_MINOR,
ltc2451_dev->i2c_misc.name = "i2c_ltc2451"; //指定设备节点的名字 /dev/i2c_ltc2451
//注册一个混杂设备驱动,函数里面已经封装了申请设备号,创建设备文件等过程
misc_register(<c2451_dev->i2c_misc);
// 4,根据实际情况去初始化从设备硬件---at24 上电就可以工作
return 0;
}
int ltc2451_i2c_remove(struct i2c_client *client)
{
printk("------%s--------\n", __FUNCTION__);
misc_deregister(<c2451_dev->i2c_misc);
kfree(ltc2451_dev);
return 0;
}
struct LTC2451_Private ltc2451_private = {
.name = "ltc2451 test ",
.version = 0x1234,
};
//名字必须与内核中的arch/arm/mach-s5pv210/mach-smdkv210.c中i2c_board_info结构体对应
const struct i2c_device_id ltc2451_i2c_id_table[] = {
{"ltc2451",(unsigned long)<c2451_private},//注意
};
//描述了一个从设备的操作方法
struct i2c_driver ltc2451_i2c_drv = {
.probe = ltc2451_i2c_probe,
.remove = ltc2451_i2c_remove,
.driver = { //父类,一定要初始化
.name = "ltc2451_drv", //该名字不会用于进行匹配#
}, //主要的作用是用来产生一个文件 /sys/bus/i2c/drivers/at24_drv
.id_table = ltc2451_i2c_id_table, //用于和i2c client进行匹配的名字列表
};
static int __init ltc2451_drv_init(void)
{
//注册一个i2c driver
return i2c_add_driver(<c2451_i2c_drv);
}
static void __exit ltc2451_drv_exit(void)
{
i2c_del_driver(<c2451_i2c_drv);
}
module_init(ltc2451_drv_init);
module_exit(ltc2451_drv_exit);
MODULE_LICENSE("GPL"); // 描述模块的许可证
MODULE_AUTHOR("aston"); // 描述模块的作者
MODULE_DESCRIPTION("module test"); // 描述模块的介绍信息
MODULE_ALIAS("alias xxx"); // 描述模块的别名信息
2,mach-x210.c
/* I2C0 */
static struct i2c_board_info i2c_devs0[] __initdata = {
#ifdef CONFIG_SND_SOC_WM8580
{
I2C_BOARD_INFO("wm8580", 0x1b),
},
#endif
#ifdef CONFIG_EEPROM_at240cxx
{
I2C_BOARD_INFO("at240c64", (0xa0>>1)),
},
#endif
#ifdef CONFIG_LTC2451_I2C
{
I2C_BOARD_INFO("ltc2451", (0x28>>1)),
},
#endif
};
3,\drivers\misc\ltc2451\Kconfig
menu "LTC2451 support"
config LTC2451_I2C
tristate "LTC2451 I2C support"
help
16bit ADC
If unsure, say N.
endmenu
4,\drivers\misc\ltc2451\Makefile
obj-$(CONFIG_LTC2451_I2C) += ltc2451_i2c_drv.o
5,\drivers\misc\Kconfig
source "drivers/misc/ltc2451/Kconfig"
6,\drivers\misc\Makefile
obj-y += ltc2451/
7,make menuconfig
Device Drivers —>
[*] Misc devices --->
LTC2451 support --->
<*> LTC2451 I2C support