⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 ads8344_driver.c

📁 Linux/S3C44B0下ADS8344驱动源码
💻 C
📖 第 1 页 / 共 3 页
字号:
/*----------------------------------------------------------------------------*//* adc.c, V1.0 2007/07/21 Jesse Jiang * * linux/drivers/char/adc.c - AD converter driver main entity                            * * Author: Jesse Jiang <jiangxiaogen@sina.com> * Copyright (C) 2007~2008 * * * Updates history: * ----------------------------------------------------------- *   2007-07-21    Jesse Jiang   v1.0  initial *   2007-12-03    Jesse Jiang   fix the bug on queue management * * Hardware:   MCU: Samsung S3C44B0X *             For analog converter: Burr-Brown ADS8344 *             For digital count   : ExtInt2~7 *             For online check    : AIN0~5 *             For A/D type check  : PC10~15 * * OS:         uClinux version 2.4.20 * * Analog Input: *                ADS8344        S3C44B0X , I/O Config *                BUSY       ---->  PF6   , Input, Busy ind in low level *                /CS        ---->  PE7   , Ouput, Enable by low level *                DIN        ---->  PF5   , SIOTxD *                DOUT       ---->  PF7   , SIORxD *                DCLK       ---->  PF8   , SIOCLK * Digital Count: *                Channel0~5 ---->  ExtInt2~7          * * Online Check: *                Channel0~5 ---->  AIN0~5 * * A/D Type Check: *                SIF6_CS    ---->  PC15 , Output *                SIF6_A2    ---->  PC10 , Output *                SIF6_A1    ---->  PC11 , Output *                SIF6_A0    ---->  PC14 , Output * *                TXD1       ---->  PC12 , TxD1 *                RXD1       ---->  PC13 , RxD1 * *                PC15(CS) PC14(A0) PC11(A1) PC10(A2) * Chan. Select0:    1       0         0        0      *             1:    1       0         0        1      *             2:    1       0         1        0      *             3:    1       0         1        1      *             4:    1       1         0        0      *             5:    1       1         0        1   * * General work flow: *  1. Create a kerner thread in adc_open *  2. Poll 6-channel internal ADC to see whether there *     exists any external A/D converter connected *  3. If yes, send enquiry command to get external A/D *     converter types *  4. If yes, check ExtInt to get the count for digital  *     A/D, and check ADS8344 to get A/D conversion  *     result. *  *//*----------------------------------------------------------------------------*/#ifndef __KERNEL__#define __KERNEL__#endif#include <linux/kernel.h>     /* We're doing kernel work */#include <linux/module.h>     /* Specifically, a module */#include <linux/interrupt.h>  /* We want interrupts */#include <linux/miscdevice.h> /* for misc_register() and misc_deregister() */#include <linux/fs.h>         /* for struct 'file_operations' */#include <linux/timer.h>     /* for timeout interrupts */#include <linux/param.h>     /* for HZ. HZ = 100 and the timer step is 1/100 */#include <linux/sched.h>     /* for jiffies definition. jiffies is incremented                              * once for each clock tick; thus it's incremented                              * HZ times per secondes.*/#include <linux/mm.h>        /* for verify_area */#include <linux/slab.h>      /* for kmalloc */#include <linux/init.h>#include <linux/errno.h>#include <linux/smp_lock.h>#include <linux/nsyadc.h>#include <asm/io.h>#include <asm/uaccess.h>#include <asm/system.h>#include <asm/irq.h>#include <asm/arch/irqs.h>#include <asm/arch/s3c44b0x.h>/*----------------------------------------------------------------------------*/static const char* __file__ = __FILE__;/*----------------------------------------------------------------------------*//* * Kernel compatibility. * Kernel > 2.2.3, include/linux/version.h contain a macro for KERNEL_VERSION */#include <linux/version.h>#ifndef KERNEL_VERSION#define KERNEL_VERSION(a,b,c)  (((a) << 16) + ((b) << 8) + (c))#endif/* * Conditional compilation. LINUX_VERSION_CODE is the code of this version * (as per KERNEL_VERSION) */#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,2,0))#include <asm/uaccess.h>    /* for put_user     */#include <linux/poll.h>     /* for polling fnct */#endif/* *  Should move to linux\include\msicdevice.h */#define NSY_ADC_MINOR    18/*----------------------------------------------------------------------------*//* ADC main entity------------------------------------------------------------*//* The item length in buffer queue */#define DATA_LENGTH       sizeof(struct adc_conv_info)/* Size of the buffer for the event queue */#define AD_BUF_SIZE        (256*DATA_LENGTH) /* 256*DATA_LENGTH, Modify for queue bug fix *//* signal to quit adc poll & sample threads */#define ADC_THREAD_SHUTDOWN  (sigmask(SIGKILL))                               /* |sigmask(SIGINT)|sigmask(SIGTERM))*/                                 /*----------------------------------------------------------------------------*//* Digital A/D conversion-----------------------------------------------------*//* Interrupt for digital sampling */#define CHA_IRQ_0     (S3C44B0X_INTERRUPT_EINT2)#define CHA_IRQ_1     (S3C44B0X_INTERRUPT_EINT3)#define CHA_IRQ_2345  (S3C44B0X_INTERRUPT_EINT4567)#define CLEAR_SIO_IRQ     { outl(0x00000010, S3C44B0X_I_ISPC); }#define CLEAR_CHA0_IRQ    { outl(0x00800000, S3C44B0X_I_ISPC); }#define CLEAR_CHA1_IRQ    { outl(0x00400000, S3C44B0X_I_ISPC); }#define CLEAR_CHA2345_IRQ { outb(0x0f, S3C44B0X_EXTINPND);\                            outl(0x00200000, S3C44B0X_I_ISPC);\                          }                            /*----------------------------------------------------------------------------*//* Analog A/D conversion------------------------------------------------------*/#define MAX_CONV_TIME  (50) /* Maximum conversion time for analog ADC:ms *//* SIO baudrate = MCLK/2/(Prescaler+1) */#define SIO_PRESCALER  (119)#define SIO_IVTCNT     (1)/* SIO control bits. */#define SIOCONT_BIT_CLK     (1<<7)#define SIOCONT_BIT_DIR     (1<<6)#define SIOCONT_BIT_TXRX    (1<<5)#define SIOCONT_BIT_EDGE    (1<<4)#define SIOCONT_BIT_START   (1<<3)#define SIOCONT_BIT_OPER    (1<<2)#define SIOCONT_BIT_MODE1   (1<<1)#define SIOCONT_BIT_MODE0   (1<<0)/* SIO initial definition  * Internal clock * MSB first * Transmit/Recevie * Falling edge * No action * Non hand-shaking * Interrupt mode */#define SIOCONT_INIT ( SIOCONT_BIT_CLK       *0 | \                       SIOCONT_BIT_DIR       *0 | \                       SIOCONT_BIT_TXRX         | \                       SIOCONT_BIT_EDGE         | \                       SIOCONT_BIT_START     *0 | \                       SIOCONT_BIT_OPER      *0 | \                       SIOCONT_BIT_MODE1     *0 | \                       SIOCONT_BIT_MODE0           )#define SIOCONT_DISABLE ((inl(S3C44B0X_SIOCON)&0xFFFFFFFC)|0x00)#define SIOCONT_ENABLE  ((inl(S3C44B0X_SIOCON)&0xFFFFFFFC)|0x01)#define SIOCONT_START   ((inl(S3C44B0X_SIOCON)&0xFFFFFFF7)|0x08)#define SIOCONT_STOP    ((inl(S3C44B0X_SIOCON)&0xFFFFFFF7)|0x00)/* SIO transfer definitions */#define WRITE_SIODATA(x) {outl(x, S3C44B0X_SIODAT);}#define SET_SIOCON(x)    {outl(x, S3C44B0X_SIOCON);}#define SET_SIOSBRDR(x)  {outl(x, S3C44B0X_SBRDR); }#define SET_SIOIVTCNT(x) {outl(x, S3C44B0X_ITVCNT); }#define SIODATA          (inb(S3C44B0X_SIODAT))#define SIO_INIT    { SET_SIOCON(SIOCONT_INIT); }     /* init SIO           */#define SIO_ENABLE  { SET_SIOCON(SIOCONT_ENABLE); }   /* enable SIO         */#define SIO_DISABLE { SET_SIOCON(SIOCONT_DISABLE); }  /* disable SIO        */#define SIO_START   { SET_SIOCON(SIOCONT_START); }    /* start SIO transfer */#define SIO_STOP    { SET_SIOCON(SIOCONT_STOP); }     /* stop SIO transfer  *//* ADS8344 control bits */#define ADS8344_START_BIT (1<<7)#define ADS8344_A2        (1<<6)#define ADS8344_A1        (1<<5)#define ADS8344_A0        (1<<4)#define ADS8344_NOP       (1<<3)  #define ADS8344_SER_DFR   (1<<2)  /* High: Single mode,                                    * Low: differential mode                                    */#define ADS8344_PD1       (1<<1)  #define ADS8344_PD0       (1<<0)  /* AD control bytes */#define AD_CTRL_CHA0   ( ADS8344_START_BIT   | \                         ADS8344_A2          | \                         ADS8344_A1          | \                         ADS8344_A0          | \                         ADS8344_NOP       *0| \                         ADS8344_SER_DFR     | \                         ADS8344_PD1       *1| \                         ADS8344_PD0       *1 )                         #define AD_CTRL_CHA1   ( ADS8344_START_BIT   | \                         ADS8344_A2        *1| \                         ADS8344_A1        *1| \                         ADS8344_A0        *0| \                         ADS8344_NOP       *1| \                         ADS8344_SER_DFR     | \                         ADS8344_PD1       *1| \                         ADS8344_PD0       *0 )                         #define AD_CTRL_CHA2   ( ADS8344_START_BIT   | \                         ADS8344_A2        *0| \                         ADS8344_A1        *0| \                         ADS8344_A0        *1| \                         ADS8344_NOP       *1| \                         ADS8344_SER_DFR     | \                         ADS8344_PD1       *0| \                         ADS8344_PD0       *1 )                         #define AD_CTRL_CHA3   ( ADS8344_START_BIT   | \                         ADS8344_A2        *1| \                         ADS8344_A1        *1| \                         ADS8344_A0        *0| \                         ADS8344_NOP       *1| \                         ADS8344_SER_DFR     | \                         ADS8344_PD1       *1| \                         ADS8344_PD0       *1  )                         #define AD_CTRL_CHA4   ( ADS8344_START_BIT   | \                         ADS8344_A2        *0| \                         ADS8344_A1        *1| \                         ADS8344_A0        *0| \                         ADS8344_NOP       *1| \                         ADS8344_SER_DFR     | \                         ADS8344_PD1       *1| \                         ADS8344_PD0       *1 )                        #define AD_CTRL_CHA5   ( ADS8344_START_BIT   | \                         ADS8344_A2        *1| \                         ADS8344_A1        *1| \                         ADS8344_A0        *0| \                         ADS8344_NOP       *0| \                         ADS8344_SER_DFR     | \                         ADS8344_PD1       *1| \                         ADS8344_PD0       *1  )/* * Generate clock to fall pull BUSY signal. * No start bit to avoid generating a BUSY at end of the transfer. */#define SIODATA_NULL    ( ADS8344_START_BIT *0| \                          ADS8344_A2        *1| \                          ADS8344_A1        *1| \                          ADS8344_A0        *1| \                          ADS8344_NOP       *1| \                          ADS8344_SER_DFR   *1| \                          ADS8344_PD1       *1| \                          ADS8344_PD0       *1 )/* ADS8344 A/D conversion states. */#define AD_CONV_ERROR       (-1)#define AD_CONV_IDLE        (0)#define AD_CONV_ST0         (1)#define AD_CONV_ST1         (2)#define AD_CONV_ST2         (3)#define AD_CONV_ST3         (4)#define AD_CONV_END         (5)/* ADS8344 conversion value bits */#define BIT15_BIT9         (0)#define BIT8_BIT1          (1)#define BIT0_BIT0          (2)/* Digital Sensor conversion state */#define AD_DIGIT_BEGIN    (0)#define AD_DIGIT_RUNNING  (1)#define AD_DIGIT_END      (2)#define EXT_AD_SELECT   { ads8344_select(); }#define EXT_AD_DESELECT { ads8344_deselect(); }#define TS_7843_DESELECT   { ads7843_deselect(); }/*----------------------------------------------------------------------------*//* predefinitions ------------------------------------------------------------*/static void handle_sio_irq(int irq, void *dev_id, struct pt_regs *regs);static void handle_cha0_irq(int irq, void *dev_id, struct pt_regs *regs);static void handle_cha1_irq(int irq, void *dev_id, struct pt_regs *regs);static void handle_cha2345_irq(int irq, void *dev_id, struct pt_regs *regs);static int adc_sample_thread(void *ctrl);static void ad_conv_state_shift(int new_state);static void put_in_queue(char *in, int len);static void release_SIO_transfer(void);static void set_SIO_transfer(void);static void sio_send_ad_ctrl(int channel);static ssize_t adc_read (struct file *file, char *buff, size_t len, loff_t *offset);static unsigned int adc_poll(struct file *file, poll_table *table);static int adc_ioctl(struct inode *inode, struct file *file,unsigned int cmd,unsigned long arg);static int adc_open(struct inode *inode, struct file *file);static int adc_release(struct inode *inode, struct file *file);static int adc_fasync(int inode, struct file *file, int mode);/*----------------------------------------------------------------------------*//* structure -----------------------------------------------------------------*/struct adc_queue {  unsigned long head;  unsigned long tail;  unsigned long count;  /* Add for queue bug fix */  spinlock_t lock;  wait_queue_head_t proc_list;  struct fasync_struct *fasync;  unsigned char buf[AD_BUF_SIZE];};struct adc_digit_data{  int ad_count_dur;  /* Unit: us for duration */  struct timeval first_int;  struct timeval second_int;  };struct ctrl_info_t {  struct task_struct *monitor_thread;   int sample_ms;};/*----------------------------------------------------------------------------*//* Variables -----------------------------------------------------------------*//* thread variables */struct ctrl_info_t sample_ctrl;static volatile char sample_shutdown = 0;/* adc drv parameters. */static struct adc_drv_params   current_params;/* adc buffer queue */static struct adc_queue *queue;static volatile int    device_open = 0;   /* number of open device to prevent concurrent                                  * access to the same device                                  */static volatile int have_ad_data = 0;spinlock_t have_dat_lock = SPIN_LOCK_UNLOCKED;/* A/D conversion info: a item variable in the queue. */static struct adc_conv_info   adc_queue_node;                                                                    /* ADS8344 conversion state */static volatile int ad_conv_state;spinlock_t conv_state_lock = SPIN_LOCK_UNLOCKED;/* ADS8344 conversion value */static volatile unsigned short ad_conv_val = 0;/* digital sample variable: to storage sampling data */static struct adc_digit_data adc_digit_sample[6];static volatile int ad_digit_st[6];                             static int s3c44b0_adc_psr = 128; //0xF; /* default value */static spinlock_t digit_lock = SPIN_LOCK_UNLOCKED;/*----------------------------------------------------------------------------*//* internal support functions ------------------------------------------------*/                                  /* * nsyadc_sleep: Delay, unit in ms */static void nsyadc_sleep(int delay){  set_current_state(TASK_UNINTERRUPTIBLE);  schedule_timeout(HZ*delay/1000);}/*----------------------------------------------------------------------------*//* Init & release functions --------------------------------------------------*//* * Set default values for the params of the driver. */static void init_adc_settings(void) {  int i;    current_params.version_req = ADC_VERSION;  current_params.sample_ms = 20;    for (i = 0; i < 6; i++)  {    current_params.cha[i].snr_online = SNR_IS_OFF;    current_params.cha[i].snr_type   = SNR_TYPE_UNKNOWN;    current_params.cha[i].snr_mode   = SNR_MODE_UNKNOWN;    current_params.cha[i].snr_id     = SNR_ID_UNKNOWN;    current_params.cha[i].snr_oper   = SNR_OPER_UNKNOWN;  }  current_params.deglitch_on = 1;  current_params.event_queue_on = 1;    adc_queue_node.snr_type  = SNR_TYPE_UNKNOWN;  adc_queue_node.snr_value = SNR_VAL_INVALID;    do_gettimeofday(&adc_queue_node.ad_timeval);    for (i = 0; i < 6; i++)  {    ad_digit_st[i] = AD_DIGIT_BEGIN;    adc_digit_sample[i].ad_count_dur = 0;    adc_digit_sample[i].first_int.tv_sec  = 0;        adc_digit_sample[i].first_int.tv_usec = 0;    adc_digit_sample[i].second_int.tv_sec  = 0;    adc_digit_sample[i].second_int.tv_usec = 0;  }    ad_conv_state = AD_CONV_IDLE;}/* * to select chip ADS8344 */static void ads8344_select (void){  int val32;    /* Set PE7 to low level */  val32 = inl(S3C44B0X_PDATE);  outl((val32&0xFFFFFF18)|0x00000000, S3C44B0X_PDATE); /* GPE7: (ADS8344-/CS) low*/}/* * to deselect chip ADS8344 */static void ads8344_deselect (void){  int val32;    /* Set PE7 to high level */  val32 = inl(S3C44B0X_PDATE);  outl((val32&0xFFFFFF18)|0x00000048, S3C44B0X_PDATE); /* GPE7: (ADS8344-/CS) high*/}/* * to deselece chip 7843 */static void ads7843_deselect (void){	int i, val32;	  /* Set PE5 to high level */  val32 = inl(S3C44B0X_PDATF) |0xef;  outl(val32, S3C44B0X_PDATF); /* GPE5: (ADS7843-/CS) high*/    for (i = 0; i < 500; i++); /* Wait for ADS7843 to be stable */}  static void init_adc_gpio(void) {   unsigned int val32;    /* initialize s3c44b0 ADC */  val32 = inl(S3C44B0X_CLKCON) | (1 << 12);  outl(val32, S3C44B0X_CLKCON);      outl(s3c44b0_adc_psr, S3C44B0X_ADCPSR); /* config prescaler */    val32 = inl(S3C44B0X_ADCCON) | 0x20;  outl(val32, S3C44B0X_ADCCON);           /* Sleep ADC */    

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -