1驱动程序
/*************************************************************************> File Name: adc_wait.c> Author: yas> Mail: rage_yas@hotmail.com> Created Time: 2024年04月23日 星期二 17时20分42秒************************************************************************/#if 1
/*=========================The adc_wait driver=========================*//*==========头文件包含==========*/
#include <linux/init.h>
#include <linux/module.h>
#include <asm/uaccess.h>
#include <linux/irqreturn.h>
#include <linux/miscdevice.h>
#include <linux/interrupt.h>
#include <mach/irqs.h>
#include <linux/fs.h>
#include <asm/io.h>
#include <linux/wait.h>
#include <linux/sched.h>#define ADCCON (0x58000000)
#define ADCDAT0 (0x5800000C)
#define CLKCON (0x4C00000C)/*==========全局变量声明==========*/
static u32 *regADCCON;
static u32 *regADCDAT0;
static u32 *regCLKCON;int adc_result=0;
static wait_queue_head_t wq;
static int condition;/*==========函数声明==========*/
/*adc配置函数声明*/
static void adc_init(void);
/*adc驱动函数声明*/
static irqreturn_t adc_interrupt(int irq,void *p);static void ioremap_r(void);
static int __init adc_driver_init(void);static int adc_driver_open(struct inode *node,struct file *fp);
static ssize_t adc_driver_read(struct file *fp, char __user *user_buffer, size_t len, loff_t *offset);
static ssize_t adc_driver_write(struct file *fp, const char __user *user_buffer, size_t len, loff_t *offset);
static int adc_driver_close(struct inode *node, struct file *fp);static void iounmap_r(void);
static void __exit adc_driver_exit(void);/*******************************************************************************
* 函 数 名 : adc_interrupt
* 函数功能 : 处理中断任务
* 输 入 :
* irq : 中断号
* *p :中断处理函数传参,一般传【NULL】
* 输 出 :
* irqreturn_t :表示中断由该设备处理,是一个枚举类型
*******************************************************************************/
static irqreturn_t adc_interrupt(int irq,void *p)
{adc_result=*regADCDAT0 & 0x3FF;condition=1;//唤醒等待队列的条件wake_up(&wq);//唤醒等待队列return IRQ_HANDLED;
}
/*******************************************************************************
* 函 数 名 : adc_driver_open
* 函数功能 :
* 输 入 :
* 输 出 :
*******************************************************************************/
static int adc_driver_open(struct inode *node,struct file *fp)
{return 0;
}
/*******************************************************************************
* 函 数 名 : adc_driver_read
* 函数功能 :
* 输 入 :
* 输 出 :
*******************************************************************************/
static ssize_t adc_driver_read(struct file *fp, char __user *user_buffer, size_t len, loff_t *offset)
{ adc_result = *regADCDAT0 & 0x3FF;
// *regADCCON &= ~(1 << 1);condition = 0;wait_event_interruptible(wq, condition);copy_to_user(user_buffer, &adc_result, sizeof(adc_result));return sizeof(adc_result);
}
/*******************************************************************************
* 函 数 名 : adc_driver_write
* 函数功能 :
* 输 入 :
* 输 出 :
*******************************************************************************/
static ssize_t adc_driver_write(struct file *fp, const char __user *user_buffer, size_t len, loff_t *offset)
{return 0;
}
/*******************************************************************************
* 函 数 名 : adc_driver_close
* 函数功能 :
* 输 入 :
* 输 出 :
*******************************************************************************/
static int adc_driver_close(struct inode *node, struct file *fp)
{return 0;
}/*字符设备文件操作结构体*/
static struct file_operations fops =
{.owner = THIS_MODULE,.open = adc_driver_open,.read = adc_driver_read,.write = adc_driver_write,.release = adc_driver_close
};/*杂项设备结构体*/
static struct miscdevice adc_dev =
{.minor = MISC_DYNAMIC_MINOR,.name = "adc_r",.fops = &fops,
};/*******************************************************************************
* 函 数 名 : ioremap_r
* 函数功能 :
* 输 入 :
* 输 出 :
*******************************************************************************/
static void ioremap_r(void)
{regADCCON = ioremap(ADCCON, 4);regADCDAT0 = ioremap(ADCDAT0, 4);regCLKCON = ioremap(CLKCON, 4);
}
/*******************************************************************************
* 函 数 名 : adc_driver_init
* 函数功能 :
* 输 入 :
* 输 出 :
*******************************************************************************/
static int __init adc_driver_init(void)
{int ret;/* 1 注册杂项设备*/ret = misc_register(&adc_dev);if(ret < 0){printk("misc_register is failed\n");goto misc_register_err;}/* 2 注册中断-【中断号】-【中断处理函数指针】-【中断产生的条件和系统处理中断时的行为(这里处理中断时不响应其他中断)】-【给中断名命名】-【中断服务函数传参-NULL】*/ret = request_irq(IRQ_ADC, adc_interrupt, IRQF_DISABLED | IRQF_TRIGGER_NONE, "adc", NULL);if(ret < 0){printk("request_irq is failed\n");goto request_irq_err;}/* 3 初始化等待队列*/init_waitqueue_head(&wq);/* 4 寄存器映射*/ioremap_r();/* 5 开启adc时钟*/*regCLKCON |= (1 << 15);/* 6 adc配置初始化*/adc_init();return 0;request_irq_err:misc_deregister(&adc_dev);
misc_register_err:return -1;
}
/*******************************************************************************
* 函 数 名 : iounmap_r
* 函数功能 :
* 输 入 :
* 输 出 :
*******************************************************************************/
static void iounmap_r(void)
{iounmap(regADCCON);iounmap(regADCDAT0);iounmap(regCLKCON);
}
/*******************************************************************************
* 函 数 名 : adc_driver_exit
* 函数功能 :
* 输 入 :
* 输 出 :
*******************************************************************************/
static void __exit adc_driver_exit(void)
{iounmap_r();//寄存器反映射disable_irq(IRQ_ADC);//禁止中断free_irq(IRQ_ADC, NULL);//注销中断misc_deregister(&adc_dev);//注销杂项设备
}/*==========adc配置函数==========*/
/*******************************************************************************
* 函 数 名 : adc_init
* 函数功能 :
* 输 入 :
* 输 出 :
*******************************************************************************/
static void adc_init(void)
{u32 t=0;t=*regADCCON;t&=~((0X01<<14)|(0XFF<<6)|(0X01<<1));t|=(0X01<<14);t|=(0X31<<6);t&=~(0X07<<3);//选择通道0t&=~(0X01<<2);正常工作模式
// t&=~(0X01<<1);t|=(0X01<<1);//读启动方式*regADCCON=t;
}#if 0
/*******************************************************************************
* 函 数 名 : adc_convert
* 函数功能 :
* 输 入 :
* 输 出 :
*******************************************************************************/
static u32 adc_convert(void)
{*regADCCON|=(0X01<<0);while((*regADCCON&(0X01<<15))==0);return ADCDAT0&0X3FF;
}
#endifmodule_init(adc_driver_init);
module_exit(adc_driver_exit);MODULE_LICENSE("GPL");
MODULE_AUTHOR("XXX");
/*=========================The adc_wait driver=========================*/
#endif
2应用程序
/*************************************************************************> File Name: main.c> Author: yas> Mail: rage_yas@hotmail.com> Created Time: 2024年04月23日 星期二 17时20分42秒************************************************************************/#include<stdio.h>
#include<sys/types.h>
#include<sys/stat.h>
#include<fcntl.h>
#include<unistd.h>int main(void)
{#if 1
/*====================adc-r====================*/ int fd=0;int n=0;fd=open("dev/adc_r",O_RDWR);if(fd<0){printf("opening is failed\n");return -1;}while(1){read(fd,&n,4);printf("%d\n",n);
// sleep(1);}return 0;
/*========================================*/
#endif
}
3关于adc驱动
(1)这里adc驱动是采用字符设备驱动中的杂项驱动方式,所以主要应用的技术有:字符设备驱动,杂项驱动,内核中断,等待队列,adc硬件驱动配置。
(2)驱动流程:搭建字符设备驱动框架:定义字符设备结构体变量->编写字符设备结构体成员函数->编写adc驱动初始化函数(驱动加载函数)->编写adc驱动卸载函数建立杂项驱动:定义杂项设备结构体变量->注册杂项设备->注销杂项设备建立内核中断:注册中断->编写中断服务函数建立等待队列:定义等待队列头和等待条件->初始化等待队列->队列等待(读时等待)->唤醒队列(中断发生时唤醒)建立adc裸机配置:开启adc时钟发生寄存器->adc配置(硬件初始化)
(3)注意事项:由于adc是一种需要上电手动开启时钟开关,所以在进行adc硬件初始化操作之前需要先配置adc的时钟开关(CLKCON)