通过光敏电阻传感器获取外界光线的变化,并通过ADC采样,上报,获取阻值。电路接口图如下。
驱动实现
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/fs.h>
#include <linux/of.h>
#include <linux/init.h>
#include <linux/delay.h>
#include <linux/gpio.h>
#include <linux/of_device.h>
#include <linux/of_platform.h>
#include <plat/gpio-cfg.h>
#include <mach/regs-gpio.h>
#include <linux/input.h>
#include <linux/clk.h>
#include <linux/interrupt.h>
#include <linux/sched.h>
#include <asm/uaccess.h>
#include <asm/irq.h>
#include <asm/io.h>
//#define DEB_PRINTk printk
#define DEB_PRINTk(...)
#define LM393_MAJOR 253 /* 主设备号 */
struct s3c_adc_regs {
unsigned long adccon;
unsigned long adctsc;
unsigned long adcdly;
unsigned long adcdat0;
unsigned long adcdat1;
unsigned long adcupdn;
};
struct s3c_adc_dev {
wait_queue_head_t wait;
int data;
int flag;
};
static volatile struct s3c_adc_regs *s3c_adc_regs;
static struct s3c_adc_dev s3c_adc_dev;
static struct class *lm393_class;
static struct clk *clock;
//ADC中断服务
static irqreturn_t adc_irq(int irq, void *dev_id)
{
s3c_adc_dev.data = (s3c_adc_regs->adcdat0 & 0x3ff); //获取转换数据
s3c_adc_dev.flag = 1;
wake_up_interruptible(&s3c_adc_dev.wait); //唤醒等待事件
return IRQ_HANDLED;
}
static int lm393_drv_open (struct inode *inode, struct file *file)
{
s3c_adc_regs->adccon = (1<<14) | (49<<6) | (0x01<<3);
s3c_adc_regs->adcdly = 0xff;
s3c_adc_dev.data = 0;
s3c_adc_dev.flag = 0;
init_waitqueue_head(&s3c_adc_dev.wait); //初始化等待事件
return 0;
}
static ssize_t lm393_drv_read (struct file *file, char __user *buf, size_t count, loff_t * ppos)
{
int err;
/* [15] : ECFLG, 1 = End of A/D conversion
* [14] : PRSCEN, 1 = A/D converter prescaler enable
* [13:6]: PRSCVL, adc clk = PCLK / (PRSCVL + 1)
* [5:3] : SEL_MUX, 000 = AIN 0
* [2] : STDBM
* [0] : 1 = A/D conversion starts and this bit is cleared after the startup.
*/
s3c_adc_regs->adccon |= (0x01) | (0x01<<14) | (0x01<<3) | (49<<6);
wait_event_interruptible(s3c_adc_dev.wait, s3c_adc_dev.flag); //等待ADC转换完成
s3c_adc_dev.flag = 0;
err = copy_to_user(buf,(char*)&s3c_adc_dev.data,sizeof(s3c_adc_dev.data));
return err? -EFAULT:sizeof(s3c_adc_dev.data);
}
/*字符设备的相关操作实现*/
static struct file_operations lm393_drv_fops = {
.owner = THIS_MODULE,
.open = lm393_drv_open,
.read = lm393_drv_read,
};
static int __init lm393_drv_init(void)
{
int retval = 0;
retval = register_chrdev(0, "lm393_drv", &lm393_drv_fops);
if (retval < 0)
{
DEB_PRINTk(" can't register major number\n");
return retval;
}
lm393_class = class_create(THIS_MODULE, "lm393_drv");
device_create(lm393_class, NULL, MKDEV(LM393_MAJOR, 0), NULL, "lm393"); // /dev/lm393
s3c_adc_regs = ioremap(0x58000000, sizeof(struct s3c_adc_regs)); //地址映射
clock = clk_get(NULL, "adc"); //获取ADC 时钟并启动操作
if (!clock)
{
DEB_PRINTk(KERN_ERR "failed to get adc clock source\n");
return -ENOENT;
}
clk_enable(clock);
retval = request_irq(IRQ_ADC, adc_irq, IRQF_SAMPLE_RANDOM, "adc", NULL); //申请ADC中断服务
if (retval) {
DEB_PRINTk("Error requesting IRQ_ADC\n");
return -1;
}
DEB_PRINTk("Register success!\n");
return 0;
}
static void __exit lm393_drv_exit(void)
{
iounmap(s3c_adc_regs);
unregister_chrdev(LM393_MAJOR, "lm393_drv"); // 卸载
device_destroy(lm393_class, MKDEV(LM393_MAJOR, 0));
class_destroy(lm393_class);
DEB_PRINTk("Unregister success!\n");
}
module_init(lm393_drv_init);
module_exit(lm393_drv_exit);
MODULE_LICENSE("GPL v2");
验证测试
## 测试程序
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <stdio.h>
#define DEB_PRINTF printf
//#define DEB_PRINTF(...)
int main(int argc, char **argv)
{
int i, ret, fd, adc_data;
char result[4];
DEB_PRINTF("will open fd... \n");
if((fd = open("/dev/lm393",O_RDONLY)) < 0 )
{
DEB_PRINTF("open device lm393 fail.\n");
return -1;
}
else
{
DEB_PRINTF("Open Device lm393 Successful!!\n");
}
ret = read(fd, result, sizeof(result));
if(ret != sizeof(result))
{
DEB_PRINTF("read wrong\n");
DEB_PRINTF("ret = %d\n", ret);
return -1;
}
else
{
DEB_PRINTF("read success !\n");
}
for (i = 0; i < ret; i++)
{
adc_data = result[0] + (int)(result[1]<<8);
DEB_PRINTF("adc value = %d (%.2f V) \n",adc_data, adc_data/1024.0*3.3);
}
close(fd);
return 0;
}
测试结果如图