📄 adc.c
字号:
#include <linux/config.h>#include <linux/module.h>#include <linux/kernel.h>#include <linux/init.h>#include <linux/sched.h>#include <linux/delay.h>#include <asm/hardware.h>#include <asm/semaphore.h>#include <asm/uaccess.h>#include <linux/kernel.h> #include <linux/slab.h> #include <linux/fs.h> #include <linux/errno.h> #include <linux/types.h> #include <linux/mm.h>#include <linux/kdev_t.h>#include <linux/cdev.h>#include <linux/delay.h>#include <asm/io.h>#include <linux/errno.h>#include <linux/input.h>#include <linux/init.h>#include <linux/serio.h>#include <asm/irq.h>#include <asm/arch/regs-adc.h>#include <asm/arch/map.h>#include <asm/arch/regs-irq.h>#include <asm/arch-s3c2410/map.h>#include <asm/arch-s3c2410/regs-adc.h>#include <asm/arch-s3c2410/regs-clock.h>#include "adc.h" #define DEVICE_NAME "adc"static int adc_major = 0;typedef struct { struct semaphore lock; wait_queue_head_t wait; int channel; int prescale;} ADC_DEV;static ADC_DEV adcdev;static irqreturn_t adcdone_int_handler(int irq,void *dev_id,struct pt_regs *regs){ wake_up(&adcdev.wait); return IRQ_HANDLED ;}static ssize_t s3c2410_adc_write(struct file *file, const char *buffer, size_t count, loff_t * ppos){ return 0;}static ssize_t s3c2410_adc_read(struct file *filp, char *buffer, size_t count, loff_t *ppos){ int ret = 0; if (down_interruptible(&adcdev.lock)) return -ERESTARTSYS; writel((readl(S3C2410_CLKCON) | S3C2410_CLKCON_ADC),S3C2410_CLKCON); writel((1<<14) | PRSCVL(adcdev.prescale) | ADC_INPUT(adcdev.channel) | 0x01 | 0x01, ADCCON); interruptible_sleep_on(&adcdev.wait); ret = readl(ADCDAT0); ret &= 0x3ff; copy_to_user(buffer, (char *)&ret, sizeof(ret)); up(&adcdev.lock); return sizeof(ret);}static int s3c2410_adc_open(struct inode *inode, struct file *filp){ int ret; ret = request_irq(IRQ_ADC, adcdone_int_handler, SA_INTERRUPT, DEVICE_NAME, NULL); if (ret) { return ret; } init_MUTEX(&adcdev.lock); init_waitqueue_head(&(adcdev.wait)); adcdev.channel=0; adcdev.prescale=255; return 0;}static int s3c2410_adc_release(struct inode *inode, struct file *filp){ free_irq(IRQ_ADC, NULL); printk( "adc closed\n"); return 0;}static void adc_setup_cdev(struct cdev *dev, int minor, struct file_operations *fops){ int err, devno = MKDEV(adc_major, minor); cdev_init(dev, fops); dev->owner = THIS_MODULE; dev->ops = fops; err = cdev_add (dev, devno, 1); /* Fail gracefully if need be */ if (err) printk (KERN_NOTICE "Error %d adding adc %d", err, minor);}static struct cdev *AdcDevs;static struct class *cclass;static struct file_operations adc_remap_ops = { .owner =THIS_MODULE, .open = s3c2410_adc_open, .read = s3c2410_adc_read, .write = s3c2410_adc_write, .release = s3c2410_adc_release,};int __init adc_init(void){ int result; dev_t dev = MKDEV(adc_major, 0); /* normal ADC */ writel(0,ADCTSC); //XP_PST(NOP_MODE); /* Figure out our device number. */ if (adc_major) result = register_chrdev_region(dev, 1, "adc"); else { result = alloc_chrdev_region(&dev, 0, 1, "adc"); adc_major = MAJOR(dev); } if (result < 0) { printk(KERN_WARNING "adc: unable to get major %d\n", adc_major); return result; } if (adc_major == 0) adc_major = result; AdcDevs = cdev_alloc(); adc_setup_cdev(AdcDevs, 0, &adc_remap_ops); printk("adc device installed, with major %d\n", adc_major); /*create device file */ cclass = class_create(THIS_MODULE, "adc_class"); if (IS_ERR(cclass)) { printk("Err: failed in creating class.\n"); return -1; } class_device_create(cclass, NULL, MKDEV(adc_major, 0), NULL, DEVICE_NAME); return 0;}static void adc_cleanup(void){ class_device_destroy(cclass, MKDEV(adc_major, 0)); class_destroy(cclass); cdev_del(AdcDevs); unregister_chrdev_region(MKDEV(adc_major, 0), 1); printk("adc device uninstalled\n");}module_init(adc_init);module_exit(adc_cleanup);MODULE_AUTHOR("Zhang");MODULE_LICENSE("GPL");
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -