I2C设备驱动基于newstyle方式的疑问
本帖最后由 yypotato1985 于 2012-05-23 18:39 编辑最近在学习ARM-LINUX下的I2C设备驱动,我用的linux内核是linux2.6.32版本,开发板是mini2440,我现在在写ADT7410这款温度传感器的的设备驱动,它是基于I2C通信的。
但是我的驱动可以通过内核模块挂载到开发板上,但是通过测试程序却不能打开这个设备。我的这个框架是将I2C设备驱动封装在字符驱动里的。请大家帮我看看是怎么回事。驱动里暂时没有实现IOCTL的功能。只是有读写,初始化的功能。芯片的地址是0x48.
/*
ADT7410温度传感器设备驱动,基于linux I2C Probe(new-style)方式
*/
/*定义调用库函数*/
#include <linux/module.h>
#include <linux/init.h>
#include <linux/kernel.h>
#include <linux/fs.h>
#include <asm/uaccess.h>
#include <linux/i2c.h>
#include <linux/cdev.h>
#include <linux/slab.h>
#include <linux/list.h>
#include <linux/delay.h>
/*定义ADT7410相关寄存器*/
#define Temperature_Value_MSB_Register 0x00
#define Temperature_Value_LSB_Register 0x01
#define Status_Register 0x02
#define Configuration_Register 0x03
#define T_high_Setpoint_MSB_Register 0x04
#define T_high_Setpoint_LSB_Register 0x05
#define T_low_Setpoint_MSB_Register 0x06
#define T_low_Setpoint_LSB_Register 0x07
#define T_crit_Setpoint_MSB_Register 0x08
#define T_crit_Setpoint_LSB_Register 0x09
#define T_hyst_Setpoint_Register 0x0A
#define ID_Register 0x0B
/*定义字符设备主设备号*/
#define adt7410_MAJOR 0
static int adt7410_major = adt7410_MAJOR;
/*定义字符设备结构体*/
struct adt7410_dev {
struct i2c_client *client;
struct cdev cdev;
};
/*创建字符设备结构体实例*/
struct adt7410_dev *adt7410_devp;
/*打开字符设备*/
static int adt7410_open(struct inode *inode, struct file *file)
{
//struct adt7410_dev *dev;
//dev = container_of(inode->i_cdev,struct adt7410_dev,cdev);
file->private_data = dev;
return 0;
}
/*释放字符设备*/
static int adt7410_release(struct inode *inodep, struct file *file)
{
file->private_data = NULL;
return 0;
}
/*定义write*/
static int adt7410_write(struct i2c_client *client,uint8_t reg,uint8_t data)
{
unsigned char buffer;
buffer = reg;
buffer = data;
if(2 != i2c_master_send(client,buffer,2))
{
printk(KERN_ERR "ADT7410 I2C WRITE FAIL! \n");
return -1;
}
return 0;
}
/*定义read*/
static int adt7410_read(struct i2c_client *client,uint8_t *data)
{
if(1 != i2c_master_recv(client,data,1))
{
printk(KERN_ERR "ADT7410 I2C READ FAIL!\n");
return -1;
}
return 0;
}
/*定义ioctl*/
//static int adt7410_ioctl(struct inode *inode,struct file *file,
// unsigned int cmd,unsigned long arg)
//{
// switch(cmd)
//}
/* 定义并填充file_operations */
static const struct file_operations adt7410_fops = {
.owner= THIS_MODULE,
.open= adt7410_open,
.read= adt7410_read,
.write= adt7410_write,
.release = adt7410_release,
//.ioctl = adt7410_ioctl,
};
/*建立字符设备*/
static void adt7410_setup_cdev(struct adt7410_dev *dev, int index)
{
int err, devnum = MKDEV(adt7410_major, index);
/* 设置cdev*/
cdev_init(&dev->cdev, &adt7410_fops);
dev->cdev.owner = THIS_MODULE;
dev->cdev.ops = &adt7410_fops;
/* 注册cdev */
err = cdev_add(&dev->cdev, devnum, 1);
if (err)
printk(KERN_NOTICE"Error %d adding adt7410 %d", err, index);
}
/*字符设备驱动注册*/
static int __devinit adt7410_probe(struct i2c_client *client,const struct i2c_device_id *id)
{
int ret;
dev_t devnum = MKDEV(adt7410_major, 0);
/* 申请设备号 */
if (adt7410_major)
ret = register_chrdev_region(devnum, 1, "adt7410");
else {
ret = alloc_chrdev_region(&devnum, 0, 1, "adt7410");
adt7410_major = MAJOR(devnum);
}
if (ret < 0)
return ret;
/* 分配cdev */
adt7410_devp = kmalloc(sizeof(struct adt7410_dev), GFP_KERNEL);
if (!adt7410_devp){
ret = -ENOMEM;
goto fail_malloc;
}
/*初始化adt7410寄存器*/
adt7410_write(&adt7410_devp->client,Configuration_Register,0x1C);
//adt7410_read(&adt7410_devp->client,Temperature_Value_MSB_Register);
memset(adt7410_devp, 0, sizeof(struct adt7410_dev));
adt7410_devp->client = client;
/* 设置并注册cdev */
adt7410_setup_cdev(adt7410_devp, 0);
return 0;
fail_malloc:
unregister_chrdev_region(devnum, 1);
return ret;
}
/*字符设备驱动注销*/
static int __devexit adt7410_remove(struct i2c_client *client)
{
cdev_del(&adt7410_devp->cdev);
kfree(adt7410_devp);
unregister_chrdev_region(MKDEV(adt7410_major, 0), 1);
return 0;
}
/*注册i2c设备*/
static const struct i2c_device_id adt7410_id[] = {
{ "adt7410", 0 },
{ }
};
MODULE_DEVICE_TABLE(i2c, adt7410_id);
static struct i2c_board_info __initdata adt7410_i2c_board_info[] = {
{
I2C_BOARD_INFO("adt7410", 0x48),/*0x48是ADT7410地址*/
},
};
/*定义并填充i2c_driver:*/
static struct i2c_driver adt7410_driver = {
.driver = {
.name = "adt7410",
.owner = THIS_MODULE,
},
.probe = adt7410_probe,
.remove = __devexit_p(adt7410_remove),
.id_table = adt7410_id,
};
/*注册i2c驱动*/
static int __init adt7410_init(void)
{
printk(KERN_INFO "The adt7410 driver is init!\n");
return i2c_add_driver(&adt7410_driver);
i2c_register_board_info(1, adt7410_i2c_board_info,ARRAY_SIZE(adt7410_i2c_board_info));
}
/*注销i2c驱动*/
static void __exit adt7410_exit(void)
{
printk(KERN_INFO "The adt7410 driver is exit!\n");
i2c_del_driver(&adt7410_driver);
}
module_init(adt7410_init);
module_exit(adt7410_exit);
MODULE_AUTHOR("Yang yu 313889744@qq.com");
MODULE_LICENSE("Dual BSD/GPL");
MODULE_DESCRIPTION("ADT7410 I2C Driver");
唉,自己顶一下,没人可以帮忙吗?:outu: 本帖最后由 youjujun 于 2012-05-24 15:00 编辑
帮你顶起。 额。。。就么有人帮忙看看吗? mach-mini2440.c添加的:
//////////////////////////////添加i2c信息////////////////////////////
static struct i2c_board_info __initdata adt7410_i2c_board_info[] = {
{
I2C_BOARD_INFO("adt7410", 0x4,/*0x48是ADT7410地址*/
},
};
//////////////////////////////添加i2c信息////////////////////////////
static void __init mini2440_machine_init(void)
{
i2c_register_board_info(0,adt7410_i2c_board_info,ARRAY_SIZE(adt7410_i2c_board_info));
}
注意:这一步非常重要,因为你不在板文件中添加i2c信息,那么用i2c_add_drive时就会探
测不到你i2c设备,也就没法执行你的xxxx_probe函数,你的驱动也就无法使用。
哦,意思是还要把i2c_register_board_info(0,adt7410_i2c_board_info,ARRAY_SIZE(adt7410_i2c_board_info));
放到内核里去? 修改一下下面吧:
/*注册i2c驱动*/
static int __init adt7410_init(void)
{
printk(KERN_INFO "The adt7410 driver is init!\n";
return i2c_add_driver(&adt7410_driver);------------------------------------(1)
i2c_register_board_info(1, adt7410_i2c_board_info,ARRAY_SIZE(adt7410_i2c_board_info)); ------------(2)
}
(1) (2)两句交换 1,2句换过的,但是编译的时候要出现警告。。 楼主最后问题解决了吗 最近我也在学I2C驱动,有很多疑问,想向楼主请教。
1 new style方式的i2c驱动,为什么不需要参照具体设备的读写时序,比如adt7140,读写的时候应该有固定时序的,先写什么再写什么延迟多少us等等。为什么驱动中不需要涉及呢?难道是读写时序是在应用程序中体现。
页:
[1]
2