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);//选择通道0
t&=~(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;
}
#endif
module_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)