mini6410 实现简单 adc驱动--友善版


在Linux设备驱动学习中,在参考别人的源码,会达到很好的学习效果。在这篇文章中我列出了友善之臂中的驱动程序和自己写的注释。

在后续的章节中会有本人muge0913驱动程序发放,简单易懂的程序,帮大家向嵌入式步步靠近。

  1. #include <linux/kernel.h>   
  2. #include <linux/module.h>   
  3. #include <linux/slab.h>   
  4. #include <linux/input.h>   
  5. #include <linux/init.h>   
  6. #include <linux/errno.h>   
  7. #include <linux/serio.h>   
  8. #include <linux/delay.h>   
  9. #include <linux/clk.h>   
  10. #include <linux/wait.h>   
  11. #include <linux/sched.h>   
  12. #include <linux/cdev.h>   
  13. #include <linux/miscdevice.h>   
  14.   
  15. #include <asm/io.h>   
  16. #include <asm/irq.h>   
  17. #include <asm/uaccess.h>   
  18.   
  19. #include <mach/map.h>   
  20. #include <mach/regs-clock.h>   
  21. #include <mach/regs-gpio.h>   
  22. #include <plat/regs-timer.h>   
  23. #include <plat/regs-adc.h>   
  24.   
  25. #undef DEBUG   
  26. //#define DEBUG   
  27. #ifdef DEBUG   
  28. #define DPRINTK(x...) {printk(__FUNCTION__"(%d): ",__LINE__);printk(##x);}   
  29. #else   
  30. #define DPRINTK(x...) (void)(0)   
  31. #endif   
  32.   
  33. #define DEVICE_NAME "adc"   
  34.   
  35. static void __iomem *base_addr;  
  36.   
  37. typedef struct {  
  38.     wait_queue_head_t wait;  
  39.     int channel;  
  40.     int prescale;  
  41. } ADC_DEV;  
  42.   
  43. #ifdef CONFIG_TOUCHSCREEN_MINI6410   
  44. extern int mini6410_adc_acquire_io(void);  
  45. extern void mini6410_adc_release_io(void);  
  46. #else   
  47. static inline int mini6410_adc_acquire_io(void) {  
  48.     return 0;  
  49. }  
  50. static inline void mini6410_adc_release_io(void) {  
  51.     /* Nothing */  
  52. }  
  53. #endif   
  54.   
  55. static int __ADC_locked = 0;  
  56.   
  57. static ADC_DEV adcdev;  
  58. static volatile int ev_adc = 0;  
  59. static int adc_data;  
  60.   
  61. static struct clk   *adc_clock;  
  62.   
  63. #define __ADCREG(name)  (*(volatile unsigned long *)(base_addr + name))   
  64. #define ADCCON          __ADCREG(S3C_ADCCON)    // ADC control   
  65. #define ADCTSC          __ADCREG(S3C_ADCTSC)    // ADC touch screen control   
  66. #define ADCDLY          __ADCREG(S3C_ADCDLY)    // ADC start or Interval Delay   
  67. #define ADCDAT0         __ADCREG(S3C_ADCDAT0)   // ADC conversion data 0   
  68. #define ADCDAT1         __ADCREG(S3C_ADCDAT1)   // ADC conversion data 1   
  69. #define ADCUPDN         __ADCREG(S3C_ADCUPDN)   // Stylus Up/Down interrupt status   
  70.   
  71. #define PRESCALE_DIS        (0 << 14)   
  72. #define PRESCALE_EN         (1 << 14)   
  73. #define PRSCVL(x)           ((x) << 6)   
  74. #define ADC_INPUT(x)        ((x) << 3)   
  75. #define ADC_START           (1 << 0)   
  76. #define ADC_ENDCVT          (1 << 15)   
  77.   
  78. #define START_ADC_AIN(ch, prescale) \   
  79.     do { \  
  80.         ADCCON = PRESCALE_EN | PRSCVL(prescale) | ADC_INPUT((ch)) ; \  
  81.         ADCCON |= ADC_START; \  
  82.     } while (0)  
  83.   
  84.   
  85. static irqreturn_t adcdone_int_handler(int irq, void *dev_id)  
  86. {  
  87.     if (__ADC_locked) {  
  88.         adc_data = ADCDAT0 & 0x3ff;  
  89.   
  90.         ev_adc = 1;  
  91.         wake_up_interruptible(&adcdev.wait);  
  92.   
  93.         /* clear interrupt */  
  94.         __raw_writel(0x0, base_addr + S3C_ADCCLRINT);  
  95.     }  
  96.   
  97.     return IRQ_HANDLED;  
  98. }  
  99.   
  100. static ssize_t s3c2410_adc_read(struct file *filp, char *buffer, size_t count, loff_t *ppos)  
  101. {  
  102.     char str[20];  
  103.     int value;  
  104.     size_t len;  
  105.   
  106.     if (mini6410_adc_acquire_io() == 0) {  
  107.         __ADC_locked = 1;  
  108.   
  109.         START_ADC_AIN(adcdev.channel, adcdev.prescale);  
  110.   
  111.         wait_event_interruptible(adcdev.wait, ev_adc);  
  112.         ev_adc = 0;  
  113.   
  114.         DPRINTK("AIN[%d] = 0x%04x, %d\n", adcdev.channel, adc_data, ADCCON & 0x80 ? 1:0);  
  115.   
  116.         value = adc_data;  
  117.   
  118.         __ADC_locked = 0;  
  119.         mini6410_adc_release_io();  
  120.     } else {  
  121.         value = -1;  
  122.     }  
  123.   
  124.     len = sprintf(str, "%d\n", value);  
  125.     if (count >= len) {  
  126.         int r = copy_to_user(buffer, str, len);  
  127.         return r ? r : len;  
  128.     } else {  
  129.         return -EINVAL;  
  130.     }  
  131. }  
  132.   
  133. static int s3c2410_adc_open(struct inode *inode, struct file *filp)  
  134. {  
  135.     init_waitqueue_head(&(adcdev.wait));  
  136.   
  137.     adcdev.channel=0;  
  138.     adcdev.prescale=0xff;  
  139.   
  140.     DPRINTK("adc opened\n");  
  141.     return 0;  
  142. }  
  143.   
  144. static int s3c2410_adc_release(struct inode *inode, struct file *filp)  
  145. {  
  146.     DPRINTK("adc closed\n");  
  147.     return 0;  
  148. }  
  149.   
  150.   
  151. static struct file_operations dev_fops = {  
  152.     owner:  THIS_MODULE,  
  153.     open:   s3c2410_adc_open,  
  154.     read:   s3c2410_adc_read,     
  155.     release:    s3c2410_adc_release,  
  156. };  
  157.   
  158. static struct miscdevice misc = {  
  159.     .minor  = MISC_DYNAMIC_MINOR,  
  160.     .name   = DEVICE_NAME,  
  161.     .fops   = &dev_fops,  
  162. };  
  163.   
  164. static int __init dev_init(void)  
  165. {  
  166.     int ret;  
  167.   
  168.     base_addr = ioremap(SAMSUNG_PA_ADC, 0x20);  
  169.     if (base_addr == NULL) {  
  170.         printk(KERN_ERR "Failed to remap register block\n");  
  171.         return -ENOMEM;  
  172.     }  
  173.   
  174.     adc_clock = clk_get(NULL, "adc");  
  175.     if (!adc_clock) {  
  176.         printk(KERN_ERR "failed to get adc clock source\n");  
  177.         return -ENOENT;  
  178.     }  
  179.     clk_enable(adc_clock);  
  180.       
  181.     /* normal ADC */  
  182.     ADCTSC = 0;  
  183.   
  184.     ret = request_irq(IRQ_ADC, adcdone_int_handler, IRQF_SHARED, DEVICE_NAME, &adcdev);  
  185.     if (ret) {  
  186.         iounmap(base_addr);  
  187.         return ret;  
  188.     }  
  189.   
  190.     ret = misc_register(&misc);  
  191.   
  192.     printk (DEVICE_NAME"\tinitialized\n");  
  193.     return ret;  
  194. }  
  195.   
  196. static void __exit dev_exit(void)  
  197. {  
  198.     free_irq(IRQ_ADC, &adcdev);  
  199.     iounmap(base_addr);  
  200.   
  201.     if (adc_clock) {  
  202.         clk_disable(adc_clock);  
  203.         clk_put(adc_clock);  
  204.         adc_clock = NULL;  
  205.     }  
  206.   
  207.     misc_deregister(&misc);  
  208. }  
  209.   
  210. module_init(dev_init);  
  211. module_exit(dev_exit);  
  212.   
  213. MODULE_LICENSE("GPL");  
  214. MODULE_AUTHOR("muge0913");  

相关内容