adc驱动实例(工作队列+等待队列+设备树+属性文件)

来源:互联网 发布:oppo应用分身软件 编辑:程序博客网 时间:2024/06/05 21:12

吐舌头驱动:

#include <linux/init.h>#include <linux/module.h>#include <linux/kernel.h>#include <linux/version.h>#include <linux/platform_device.h>#include <asm/io.h>#include <linux/cdev.h>#include <linux/slab.h>#include <asm/uaccess.h> #include <linux/kobject.h>#include <linux/fs.h>#include <linux/cdev.h>#include <linux/of.h>#include <linux/interrupt.h>#include <linux/highmem.h> #include <asm/kmap_types.h>#include <linux/wait.h>#define HIGH_RSL 4096 // 2^12#define LOW_RSL  1024 // 2^10/*DTSmyadc {compatible = "xadc";reg = <0x10010118 0x1>, <0x126C0000 0x20>;interrupt-parent = <&combiner>;interrupts = <10 3> ;};*/MODULE_LICENSE("Dual BSD/GPL");MODULE_DESCRIPTION("a simple adc_driver !");typedef struct {unsigned int    ADCCON;  //0unsigned int    NOVAL;   //4unsigned int    ADCDLY;  //8unsigned int    ADCDAT;  //12unsigned int    NOVAL1;  //16unsigned int    NOVAL2;  //20unsigned int    CLRINTADC;  //24unsigned int    ADCMUX;  //28                                                            }adc_t;struct ADC{dev_t num;int val;//readvalint val_ok_flag;int available;//adc aviliable  struct mutex lock;spinlock_t lock;int resolution;//ADC resolutionstruct cdev xadc_cdev;  //for  containor_of()struct resource *res;//create a platform driveradc_t  *adcaddr; struct class *xadc_class;//support hotplug functionstruct device *xadc_device;struct work_struct *xadc_work; //irq_bottom_sectionwait_queue_head_t readqueue;//wait IOstruct kobject *xadc_kobj;//support attr_file op}adc;struct attribute xadc_attrs[] = {[0] = {"xadc3", S_IRUGO |S_IWUSR},{}};ssize_t xadc_kobj_show(struct kobject *kobj, struct attribute *attr, char *buffer){if(0 == strcmp(attr->name, "xadc3")){if(adc.resolution == HIGH_RSL)printk("adc_resolution: HIGH_RSL(2^12)\n");elseprintk("adc_resolution: LOW_RSL(2^10)\n");return 0;}elsereturn -1;}ssize_t xadc_kobj_store(struct kobject *kobj, struct attribute *attr, const char *buffer, size_t size){iowrite32( ioread32( &(adc.adcaddr->ADCCON) ) & (~(1<<0)) , &(adc.adcaddr->ADCCON) );///STOP转换if(0 == strcmp(attr->name, "xadc3")) {if(0 == strncmp(buffer, "low",3)) {adc.resolution = LOW_RSL;iowrite32( ioread32( &(adc.adcaddr->ADCCON) ) & (~(1 << 16))  ,&(adc.adcaddr->ADCCON) );//resolution  10bitprintk("low resolution set ok!\n");}else if(0 == strncmp(buffer, "high",4)) {adc.resolution = HIGH_RSL;iowrite32( ioread32( &(adc.adcaddr->ADCCON) ) | (1 << 16) ,&(adc.adcaddr->ADCCON) );//resolution  12bitprintk("high resolution set ok!\n");}}    return size;}void xadc_kobj_release(struct kobject * k){kfree(k);return ;}struct sysfs_ops xadc_sysfs_ops = {.show = xadc_kobj_show,.store = xadc_kobj_store};struct kobj_type xadc_ktype = {.release = xadc_kobj_release,.sysfs_ops = &xadc_sysfs_ops,};int xadc_open(struct inode *i, struct file *f){spin_lock(&adc.lock);  //lockif(adc.available == 1)  //userful{adc.available = 0;spin_unlock(&adc.lock);  //unlockprintk("xadc open\n");return 0;}spin_unlock(&adc.lock);  //unlockreturn -EBUSY;}//read waitqueuessize_t xadc_read (struct file *f, char __user *p, size_t n, loff_t *off){iowrite32( ioread32( &(adc.adcaddr->ADCCON) ) | (1<<0) , &(adc.adcaddr->ADCCON) );///开始转换if(adc.val_ok_flag == 0){//let this procss go to sleepwait_event_interruptible(adc.readqueue, adc.val_ok_flag != 0);}if( copy_to_user(p, &(adc.val), sizeof(int)) )    //get val to userreturn -EFAULT;adc.val_ok_flag = 0;return  sizeof(int);}ssize_t xadc_write (struct file *f, const char __user *p, size_t n, loff_t *off){//copy_from_user(buf, p, n);return n;}#define LOW   0#define HIGH  1long xadc_ioctl(struct file *f, unsigned int resolution, unsigned long arg){iowrite32( ioread32( &(adc.adcaddr->ADCCON) ) & (~(1<<0)) , &(adc.adcaddr->ADCCON) );///STOP转换if(resolution < LOW || resolution > HIGH){printk("error type!\n");return -1;}if(resolution == LOW) {adc.resolution = LOW_RSL;iowrite32( ioread32( &(adc.adcaddr->ADCCON) ) & (~(1 << 16))  ,&(adc.adcaddr->ADCCON) );//resolution  10bitprintk("low resolution set ok!\n");}else if(resolution == HIGH){adc.resolution = HIGH_RSL;iowrite32( ioread32( &(adc.adcaddr->ADCCON) ) | (1 << 16) ,&(adc.adcaddr->ADCCON) );//resolution  12bitprintk("high resolution set ok!\n");}return 0;}int xadc_release(struct inode *inode, struct file *file){printk("xadc closed\n"); iowrite32( ioread32( &(adc.adcaddr->ADCCON) ) & (~(1<<0)) , &(adc.adcaddr->ADCCON) );///STOP转换adc.available = 1;  //usefulreturn 0;}struct file_operations xadc_ops = {.owner = THIS_MODULE,.open = xadc_open,.unlocked_ioctl  = xadc_ioctl,.read = xadc_read,.write = xadc_write ,.release = xadc_release};////////////////////////////////////////////////////////////////////irq_handler//deal_thingvoid adc_workfunc(struct work_struct *work){adc.val = ioread32( &(adc.adcaddr->ADCDAT) ) & 0xfff ;adc.val_ok_flag = 1;  //ok//woke up processeswake_up_interruptible(&adc.readqueue);return;}//irqirqreturn_t  xadc_handler(int n, void *dev){adc.xadc_work = kzalloc(GFP_ATOMIC, sizeof(struct work_struct));  //workstruct 将处理的事务交给内核线程中处理INIT_WORK(adc.xadc_work, adc_workfunc);schedule_work(adc.xadc_work);iowrite32( 0x12 , &(adc.adcaddr->CLRINTADC) ); //clear INTprintk("IRQ getval , adc3_val can be read!\n");return IRQ_HANDLED;}////////////////////////////////////////////////////////////////////driver int xadc_probe(struct platform_device *pdev){int ret = 0;printk("probe the adc_device!\n");//get adc_addradc.res = platform_get_resource(pdev, IORESOURCE_MEM, 1);printk("adc_baseaddr: %#x\n", adc.res->start);adc.adcaddr = ioremap(adc.res->start, adc.res->end-adc.res->start);//get adc_irqadc.res = platform_get_resource(pdev, IORESOURCE_IRQ, 0); printk("adc_irqnum:: %#x\n", adc.res->start);ret = request_irq(adc.res->start, xadc_handler, IRQF_DISABLED, "xadc_IRQ", NULL); //申请一个中断服务(需要获取中断号) 最后一个是中断函数的参数pdevprintk("adc_device info get !\n");//request cdev numret = alloc_chrdev_region(&adc.num, 0, 1, "xadc3");if(ret) {printk("devnum alloc fail!\n");return ret;}printk("devnum: %d  %d \n", MAJOR(adc.num) ,MINOR(adc.num));//init cdev fopscdev_init(&adc.xadc_cdev,  &xadc_ops);//register cdev into kernelret = cdev_add(&adc.xadc_cdev, adc.num , 1);if(ret) {printk("add cdev fail!\n");goto cdev_add_out;}//support hotplug functionadc.xadc_class = class_create(THIS_MODULE, "xadc");  //sys/class/adc.xadc_device = device_create(adc.xadc_class , NULL, adc.num, NULL, "adc%d", 3);  //dev///init device adc3iowrite32( ioread32( &(adc.adcaddr->ADCCON) ) & (~(1 << 16))  ,&(adc.adcaddr->ADCCON) );//resolutioniowrite32( ioread32( &(adc.adcaddr->ADCCON) ) | (1 << 14) , &(adc.adcaddr->ADCCON) );//enable prescaleriowrite32( (ioread32( &(adc.adcaddr->ADCCON) ) & (~(0xFF << 6))) | (19<<6) , &(adc.adcaddr->ADCCON) );//prescaleriowrite32( ioread32( &(adc.adcaddr->ADCCON) ) & (~(1 << 2)) , &(adc.adcaddr->ADCCON) );   //normaliowrite32( ioread32( &(adc.adcaddr->ADCMUX) ) | 0x3 , &(adc.adcaddr->ADCMUX) );   //adc 第三通道 adc.resolution = LOW_RSL;  //init resolutioninit_waitqueue_head(&adc.readqueue);  //init wait queueadc.available = 1;   //spin_lock_init(&adc.lock);spin_lock_init(&adc.lock);printk("adc.available!\n");//attr_fileadc.xadc_kobj = kzalloc(sizeof(struct kobject), GFP_KERNEL);kobject_init(adc.xadc_kobj, &xadc_ktype);ret = kobject_add(adc.xadc_kobj, NULL, "xadc3");ret = sysfs_create_file(adc.xadc_kobj, &xadc_attrs[0]);//successreturn 0;cdev_add_out:unregister_chrdev_region(adc.num, 1);  //release dev_num//errorreturn ret;}int xadc_remove(struct platform_device *pdev){//release  remapiounmap(adc.adcaddr);///释放中断 free_irq(adc.res->start, NULL);  //unregister cdev from kernelcdev_del(&adc.xadc_cdev);/*//release cdev objectkfree(&beep.xadc_cdev);*///release dev numunregister_chrdev_region(adc.num, 1); //support hotplug function//free devicedevice_del(adc.xadc_device);//free classclass_destroy(adc.xadc_class);//free attr_filesysfs_remove_file(adc.xadc_kobj, &xadc_attrs[0]);kobject_del(adc.xadc_kobj);kfree(adc.xadc_kobj);printk("adc_device remove !\n");return 0;}//multi_device tablestruct platform_device_id xadc_ids[] = {//support auto_install the driver[0] = {.name = "adc3"},[1] = {//null}};#ifdef CONFIG_OF//设备树匹配方式 struct of_device_id xadc_table[] = {{ .compatible = "xadc" },  //match  adc3{ } //NULL};#endifstruct platform_driver xadc_driver = {.probe = xadc_probe,.remove = xadc_remove,.id_table = xadc_ids,   //multi_device table.driver = {.name = "adc3",.of_match_table = of_match_ptr(xadc_table)     //设备树匹配选项 }};MODULE_DEVICE_TABLE(platform, xadc_ids);  //support auto_install the driver//driver install  and  release static int adcmodule_init(void){printk("xadc driver install\n");//add into platform busplatform_driver_register(&xadc_driver);return 0;}static void adcmodule_exit(void){printk("xad cdriver release\n");//del from platform busplatform_driver_unregister(&xadc_driver);return ;}module_init(adcmodule_init);module_exit(adcmodule_exit);

吐舌头测试:

#include <stdio.h>#include <sys/types.h>#include <sys/stat.h>#include <fcntl.h>#define LOW   0#define HIGH  1int main(int argc,char **argv){int chose;int fd;int val;int RES;while(1){printf("1.open adc  2.close adc  3.set high_resolution 4.set low_resolution 5.read adc_val \n");scanf("%d",&chose);switch(chose){case 1: printf("open\n"); fd = open("/dev/adc3", O_RDWR);if(-1 == fd){perror("open fail EBUSY\n");return -1;}break;case 2: printf("close\n"); close(fd);break;case 3: printf("set high_resolution, ");ioctl(fd, HIGH);RES = HIGH;printf("set ok!\n");break;case 4: printf("set low_resolution, ");ioctl(fd, LOW);RES = LOW;printf("set ok!\n");break;case 5: read(fd,&val,sizeof(int));if(RES == LOW)val = 1000 * (1.8/1024 * val);elseval = 1000 * (1.8/4096 * val);printf("readval: %d mV \n",val);break;default: printf("err type\n"); }}close(fd);return 0;}



0 0
原创粉丝点击