ADC转换

| |
| #include <linux/errno.h> |
| #include <linux/kernel.h> |
| #include <linux/module.h> |
| #include <linux/slab.h> |
| #include <linux/input.h> |
| #include <linux/init.h> |
| #include <linux/serio.h> |
| #include <linux/delay.h> |
| #include <linux/clk.h> |
| #include <linux/wait.h> |
| #include <linux/sched.h> |
| #include <asm/io.h> |
| #include <asm/irq.h> |
| #include <asm/uaccess.h> |
| #include <mach/regs-clock.h> |
| #include <plat/regs-timer.h> |
| #include <plat/regs-adc.h> |
| #include <mach/regs-gpio.h> |
| #include <linux/cdev.h> |
| #include <linux/miscdevice.h> |
| #include <linux/semaphore.h> |
| #define DEVICE_NAME "ldr_adc" |
| |
| static void __iomem *base_addr; |
| |
| typedef struct |
| { |
| wait_queue_head_t wait; |
| int channel; |
| int prescale; |
| } ADC_DEV; |
| |
| |
| extern struct semaphore ADC_LOCK; |
| static struct class *ldr_adc_drv_class; |
| static int ownADC = 0; |
| |
| static ADC_DEV adcdev; |
| static volatile int ev_adc = 0; |
| static int adc_data; |
| |
| static struct clk *adc_clk; |
| |
| |
| |
| |
| #define START_ADC_AIN(ch, prescale) \ |
| \ |
| do \ |
| { \ |
| \ |
| iowrite32(S3C2410_ADCCON_PRSCEN | S3C2410_ADCCON_PRSCVL(prescale) \ |
| | S3C2410_ADCCON_SELMUX(ch), \ |
| base_addr + S3C2410_ADCCON); \ |
| \ |
| iowrite32(ioread32(base_addr + S3C2410_ADCCON) \ |
| | S3C2410_ADCCON_ENABLE_START, \ |
| base_addr + S3C2410_ADCCON); \ |
| \ |
| } \ |
| while (0) |
| |
| static irqreturn_t adc_handler(int irq, void *dev_id) |
| { |
| if (ownADC) |
| { |
| adc_data = ioread32(base_addr + S3C2410_ADCDAT0) & 0x3ff; |
| |
| ev_adc = 1; |
| wake_up_interruptible(&adcdev.wait); |
| } |
| return IRQ_HANDLED; |
| } |
| |
| static int s3c2440_adc_open(struct inode *inode, struct file *filp) |
| { |
| init_waitqueue_head(&adcdev.wait); |
| adcdev.channel = 0; |
| adcdev.prescale = 0xff; |
| |
| return 0; |
| } |
| |
| static int s3c2440_adc_close(struct inode *inode, struct file *filp) |
| { |
| return 0; |
| } |
| |
| static ssize_t s3c2440_adc_read(struct file *filp, char *buffer, size_t count, loff_t *ppos) |
| { |
| int ret; |
| |
| if (down_trylock(&ADC_LOCK)) |
| { |
| return -EBUSY; |
| } |
| |
| ownADC = 1; |
| START_ADC_AIN(adcdev.channel, adcdev.prescale); |
| wait_event_interruptible(adcdev.wait, ev_adc); |
| |
| ev_adc = 0; |
| |
| ret = copy_to_user(buffer, (char *)&adc_data, sizeof(adc_data)); |
| |
| ownADC = 0; |
| up(&ADC_LOCK); |
| |
| return sizeof(adc_data); |
| } |
| |
| static struct file_operations dev_fops = |
| { |
| .owner = THIS_MODULE, |
| .open = s3c2440_adc_open, |
| .read = s3c2440_adc_read, |
| .release = s3c2440_adc_close, |
| }; |
| |
| int major; |
| static int __init dev_init(void) |
| { |
| int ret; |
| |
| |
| base_addr = ioremap(S3C2410_PA_ADC, 0x20); |
| if (base_addr == NULL) |
| { |
| printk(KERN_ERR "Failed to remap ADC register\n"); |
| return -ENOMEM; |
| } |
| |
| |
| |
| adc_clk = clk_get(NULL, "adc"); |
| if (!adc_clk) |
| { |
| printk(KERN_ERR "Failed to get adc clk\n"); |
| return -ENOENT; |
| } |
| |
| clk_enable(adc_clk); |
| |
| iowrite32(0, base_addr + S3C2410_ADCTSC); |
| |
| |
| |
| |
| ret = request_irq(IRQ_ADC, adc_handler, IRQF_SHARED, DEVICE_NAME, &adcdev); |
| if (ret) |
| { |
| iounmap(base_addr); |
| printk(KERN_ERR "Failed to req adc_irq\n"); |
| return ret; |
| } |
| |
| major = register_chrdev(0, DEVICE_NAME, &dev_fops); |
| |
| ldr_adc_drv_class = class_create(THIS_MODULE, "ldr_adc"); |
| if (IS_ERR(ldr_adc_drv_class)) |
| { |
| printk(KERN_INFO "create ldr_adc_drv class error\n"); |
| return -1; |
| } |
| |
| device_create(ldr_adc_drv_class, NULL, MKDEV(major, 0), NULL, DEVICE_NAME); |
| |
| printk(KERN_INFO DEVICE_NAME " initialized\n"); |
| return ret; |
| } |
| |
| static void __exit dev_exit(void) |
| { |
| |
| unregister_chrdev(major, DEVICE_NAME); |
| device_destroy(ldr_adc_drv_class, MKDEV(major, 0)); |
| |
| free_irq(IRQ_ADC, &adcdev); |
| iounmap(base_addr); |
| |
| if (adc_clk) |
| { |
| clk_disable(adc_clk); |
| clk_put(adc_clk); |
| adc_clk = NULL; |
| } |
| |
| class_destroy(ldr_adc_drv_class); |
| printk(KERN_INFO "ldr_adc_driver is exited!\n"); |
| } |
| module_init(dev_init); |
| module_exit(dev_exit); |
| MODULE_LICENSE("GPL"); |
| |
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· winform 绘制太阳,地球,月球 运作规律
· AI与.NET技术实操系列(五):向量存储与相似性搜索在 .NET 中的实现
· 超详细:普通电脑也行Windows部署deepseek R1训练数据并当服务器共享给他人
· 上周热点回顾(3.3-3.9)
· AI 智能体引爆开源社区「GitHub 热点速览」