struct adc_device {
struct platform_device *pdev;
struct platform_device *owner;
struct clk *clk;
struct s3c_adc_client *cur;
struct s3c_adc_client *ts_pend;
void __iomem *regs;
spinlock_t lock;
unsigned int prescale;
int irq;
};
下面这个结构体用来描述一个客户端:
structs3c_adc_client {
structplatform_device *pdev;
structlist_head pend; //用来构建客户请求列表
wait_queue_head_t *wait; //等待队列头,用来睡眠
unsignedint nr_samples;
int result;
unsignedchar is_ts; //是否是触摸屏
unsignedchar channel; //通道
void (*select_cb)(struct s3c_adc_client *c,unsigned selected);
void (*convert_cb)(struct s3c_adc_client *c,
unsigned val1, unsigned val2,
unsigned *samples_left); //转换回调函数
};
下面就是结构图
我们需要在我们的驱动中构建这个结构体,并且向adc通用驱动中注册这个结构体。注册函数为:
structs3c_adc_client *s3c_adc_register(struct platform_device *pdev,
void(*select)(struct s3c_adc_client *client,
unsigned int selected),
void(*conv)(struct s3c_adc_client *client,
unsigned d0, unsigned d1,
unsigned *samples_left),
unsignedint is_ts)
然后我们就可以读取相应通道的数据了:
ints3c_adc_read(struct s3c_adc_client *client, unsigned int ch);
现在我们开始写我们的驱动:
1、 构建我们的设备结构体
在arch/arm/mach-s3c2410/mach-smdk2410.c中添加如下内容
structplatform_device s3c_device_adc_convert = {
.name ="adc_convert",
.id =-1,
.dev.parent =&s3c_device_adc.dev,
};
2、 注册我们的设备
修改arch/arm/mach-s3c2410/mach-smdk2410.c,在结构体数组smdk2410_devices中添加我们的设备:
staticstruct platform_device *smdk2410_devices[] __initdata = {
……
&s3c_device_adc, //添加内容
&s3c_device_adc_convert, //添加内容
……
};
修改后重新编译内核
3、 构建我们的驱动
#include
#include
#include
#include
#include
#include
#include
#include
#include
MODULE_LICENSE ("GPL");
int adc_major = 250;
int adc_minor = 0;
int number_of_devices = 1;
struct s3c_adc_client *client;
struct cdev cdev;
dev_t devno = 0;
static ssize_t adc_convert_read(struct file *file, char __user *buff, size_t count, loff_t *offset)
{
unsigned data;
unsigned ch;
data = 10;
ch = 0;
data = s3c_adc_read(client, ch);
printk("data0 = %d\n", data);
if(copy_to_user(buff, (char *)&data, sizeof(data)))
return -EFAULT;
return 0;
}
static int adc_convert_open(struct inode *inode, struct file *file)
{
return 0;
}
static int adc_convert_release(struct inode *inode, struct file *file)
{
return 0;
}
static struct file_operations adc_convert_fops = {
.owner = THIS_MODULE,
.read = adc_convert_read,
.open = adc_convert_open,
.release = adc_convert_release,
};
static int __devinit adc_convert_probe( struct platform_device *pdev )
{
struct device *dev = &pdev->dev;
int ret = -EINVAL;
printk("function = %s\n", __func__);
devno = MKDEV(adc_major, adc_minor);
ret = register_chrdev_region(devno, number_of_devices, "adc_convert");
if( ret )
{
dev_err(dev, "failed to register device number\n");
goto err_register_chrdev_region;
}
cdev_init(&cdev, &adc_convert_fops);
cdev.owner = THIS_MODULE;
ret = cdev_add(&cdev, devno, number_of_devices);
if( ret )
{
dev_err(dev, "failed to add device\n");
goto err_cdev_add;
}
client = s3c_adc_register (pdev, NULL, NULL, 0);
if(IS_ERR( client ))
{
dev_err(dev, "failed to register adc client\n");
goto err_s3c_adc_register;
}
return 0;
err_s3c_adc_register:
cdev_del( &cdev );
err_cdev_add:
unregister_chrdev_region(devno, number_of_devices);
err_register_chrdev_region:
return ret;
}
static int __devexit adc_convert_remove(struct platform_device *pdev)
{
s3c_adc_release(client);
cdev_del( &cdev );
unregister_chrdev_region(devno, number_of_devices);
return 0;
}
static struct platform_driver adc_convert_driver = {
.driver = {
.name = "adc_convert",
.owner = THIS_MODULE,
},
.probe = adc_convert_probe,
.remove = __devexit_p(adc_convert_remove)
};
static int __init adc_convert_init (void)
{
return platform_driver_register( &adc_convert_driver );
}
static void __exit adc_convert_exit (void)
{
platform_driver_unregister( &adc_convert_driver );
}
module_init (adc_convert_init);
module_exit (adc_convert_exit);
4、 编译驱动,并加载到内核里,使用下面代码测试,即可读到相应通道的数据
#include
#include
#include
#include
#include
int main (void)
{
int fd;
int data;
fd = open ("/dev/adc",O_RDWR);
if (fd < 0) {
perror("open");
exit(0);
}
while(1)
{
read (fd, (char *)&data, sizeof(data));
printf("Voltage = %.2f\n", 3.3/1024*data);
sleep(1);
}
close (fd);
printf ("/dev/adc closed :)\n");
return 0;
}