?? ads8344_driver.c
字號:
/* intitialize UART 1 & no channel select * * GPC10,11,14,15: Output, Pull-up, Init:0 * * GPC12: TxD1 * * GPC13: RxD1 * */ val32 = inl(S3C44B0X_PCONC); outl((val32&0x000FFFFF)|0x5F500000, S3C44B0X_PCONC); val32=inl(S3C44B0X_PUPC); outl((val32&0xFFFF33FF)|0x3000, S3C44B0X_PUPC); val32=inl(S3C44B0X_PDATC); outl((val32&0xFFFF33FF)|0x00000000, S3C44B0X_PDATC); /* * initialize ExtInt 2~7 * * Normal IRQ, * * Enable, * * both edge triggered * */ val32 = inl(S3C44B0X_INTMOD); outl((val32&0xFF1FFFFF), S3C44B0X_INTMOD); /* ExInt2~7: Normal IRQ */ val32 = inl(S3C44B0X_INTMSK); outl((val32&0xFF1FFFFF)|0x00000000, S3C44B0X_INTMSK); /* Enable ExInt2~7 */ val32=inl(S3C44B0X_EXTINT); outl((val32&0x888888FF)|0x77777700, S3C44B0X_EXTINT); /* ExInt2~7:both edge*/ val32=inl(S3C44B0X_PCONG); outl(val32|0x0000FFF0, S3C44B0X_PCONG); /* config PG2~7 as ExtInt2~7 */ /* initialize SIO */ val32=inl(S3C44B0X_PCONE); outl((val32&0xFFFF3FFF)|0x4000, S3C44B0X_PCONE); /* GPE7(ADS8344-/CS):output(01)*/ val32=inl(S3C44B0X_PUPE); outl((val32&0xFFFFFF7F)|0x00, S3C44B0X_PUPE); /* GPE7 activate pull up */ val32=inl(S3C44B0X_PDATE); outl( (val32&0xFFFFFF7F)|0x00000080, S3C44B0X_PDATE); /* GPE7(ADS8344/CS): high, * deselect ADS8344 */ /* Config GPF5, 6, 7, 8 * GPF5: SIOTxD * GPF6: Input * GPF7: SIORxD * GPF8: SIOCLK */ val32 = (inl(S3C44B0X_PCONF)&0x3ff)+(3<<19)+(3<<16)+(0<<13)+(3<<10); outl(val32, S3C44B0X_PCONF); val32 = (inl(S3C44B0X_PUPD)) & 0x01F; /* Active GPF5, 6, 7, 8 pull up */ outl(val32, S3C44B0X_PUPD); disable_irq(S3C44B0X_INTERRUPT); }/* * Reset bits used in each register to their default value. */static void release_adc_hardware(void) { int val32; /* reset s3c44b0 ADC */ outl(s3c44b0_adc_psr, S3C44B0X_ADCPSR); /* config prescaler */ val32=inl(S3C44B0X_ADCCON); outl(val32|0x20, S3C44B0X_ADCCON); /* Sleep ADC */ /* release channel select */ val32 = inl(S3C44B0X_PDATC); outl((val32&0xFFFF7FFF)|0x00000000, S3C44B0X_PDATC); /* reset PE7 to initial state: Input */ val32=inl(S3C44B0X_PCONE); outl((val32&0xFFFF3FFF)|0x000, S3C44B0X_PCONE); /* config GPE7: input(00) */ /* reset PF5~PF8 to initial state: Input */ // val32=inl(S3C44B0X_PCONF);// outl((val32&0xFFC003FF)|0x000000, S3C44B0X_PCONF); /* config GPF5~8: input(000) */ /* reset PG2~7 to initiate state: input(00)*/ val32=inl(S3C44B0X_PCONG); outl( (val32&0xFFFF000F)|0x00000000, S3C44B0X_PCONG); /* config PG2~7 as input */ EXT_AD_DESELECT; /* Add on Dec. 05 */ disable_irq(S3C44B0X_INTERRUPT_SIO); disable_irq(CHA_IRQ_0); disable_irq(CHA_IRQ_1); disable_irq(CHA_IRQ_2345); /* kill sample thread */ if (NULL != sample_ctrl.monitor_thread) { sample_shutdown = 1; send_sig(SIGKILL, sample_ctrl.monitor_thread, 1); } }static int init_adc_drv(void) { int err; init_adc_gpio(); /* * create a kernel thread for sensor ADC sampling */ sample_ctrl.monitor_thread = NULL; sample_ctrl.sample_ms = current_params.sample_ms; sample_shutdown = 0; if ((err = kernel_thread(adc_sample_thread, &sample_ctrl, 0)) < 0) return err; return 0;}static int ad_start_convert(int channel){ int cha_ctrl = 0; int ts_busy_flag; /* Add by Jesse for SIO sharing between TS and ADC */ ts_busy_flag = inl(S3C44B0X_SR_SIOBUSY); if (0xA5A5A5A5 == ts_busy_flag) return -1;/* End of add */ /* init SIO transfer */ ad_conv_state_shift(AD_CONV_ST0); set_SIO_transfer(); switch (channel) { case 0: cha_ctrl = AD_CTRL_CHA0; break; case 1: cha_ctrl = AD_CTRL_CHA1; break; case 2: cha_ctrl = AD_CTRL_CHA2; break; case 3: cha_ctrl = AD_CTRL_CHA3; break; case 4: cha_ctrl = AD_CTRL_CHA4; break; case 5: cha_ctrl = AD_CTRL_CHA5; break; default: release_SIO_transfer(); break; } sio_send_ad_ctrl(cha_ctrl); return 0;}static int ad_convert_is_end(void){ if(ad_conv_state == AD_CONV_END) return 1; else return 0;}static int adc_sample_thread(void *ctrl){ /* Periodically sample channel 0~5 to get A/D data and storage * into the specific A/D queues: * Work flow: * start: * If A/D is plugged in * If it is a dialog A/D * Open SIO to get AD conversion result * else * Fetch the data from interrupt queues and * forward to A/D queue * endif * endif * delay sample interval * go back to "start" for another loop */ int i, adc_timeout = 0; struct ctrl_info_t *h = (struct ctrl_info_t *) ctrl; lock_kernel(); daemonize(); reparent_to_init(); h->monitor_thread = current; sprintf(current->comm, "adc_sample_thread"); unlock_kernel(); /* only want to receive SIGKILL */ spin_lock_irq(¤t->sigmask_lock); siginitsetinv(¤t->blocked, ADC_THREAD_SHUTDOWN); recalc_sigpending(current); spin_unlock_irq(¤t->sigmask_lock); spin_lock_irq(&have_dat_lock); have_ad_data = 0; spin_unlock_irq(&have_dat_lock); while (1) { for (i = 0; i < 6; i++) { if ((SNR_IS_ON == current_params.cha[i].snr_online) && (SNR_OPER_NORMAL == current_params.cha[i].snr_oper) && (SNR_TYPE_ANALOG == current_params.cha[i].snr_type) ) { for (;;) { /* wait for A/D conversion end */ nsyadc_sleep(1); if (ad_convert_is_end()) { adc_queue_node.snr_value = ad_conv_val; ad_conv_state_shift(AD_CONV_IDLE); /* storage the conversion into the queue */ adc_queue_node.snr_channel = i; adc_queue_node.snr_type = current_params.cha[i].snr_type; do_gettimeofday(&adc_queue_node.ad_timeval); put_in_queue((char *)&adc_queue_node,SNR_DATITEM_LEN); spin_lock_irq(&have_dat_lock); have_ad_data = 1; spin_unlock_irq(&have_dat_lock); /* signal asynchronous readers that data arrives */ if(queue->fasync) kill_fasync(&queue->fasync, SIGIO, POLL_IN); wake_up_interruptible(&queue->proc_list); /* tell user space progs */ break; } if (++adc_timeout >= MAX_CONV_TIME) { ad_conv_state_shift(AD_CONV_IDLE); /* Add on Dec.05, 2007 */ break; } } } else if ((SNR_IS_ON == current_params.cha[i].snr_online) && (SNR_OPER_NORMAL == current_params.cha[i].snr_oper) && (SNR_TYPE_DIGITAL == current_params.cha[i].snr_type) && (AD_DIGIT_END == ad_digit_st[i]) ) { /* there is valid digit data */ adc_queue_node.snr_channel = i; adc_queue_node.snr_type = current_params.cha[i].snr_type; do_gettimeofday(&adc_queue_node.ad_timeval); adc_queue_node.snr_value = adc_digit_sample[i].ad_count_dur; put_in_queue((char *)&adc_queue_node,SNR_DATITEM_LEN); spin_lock_irq(&have_dat_lock); have_ad_data = 1; spin_unlock_irq(&have_dat_lock); spin_lock_irq(&digit_lock); ad_digit_st[i] = AD_DIGIT_BEGIN; spin_unlock_irq(&digit_lock); /* signal asynchronous readers that data arrives */ if(queue->fasync) kill_fasync(&queue->fasync, SIGIO, POLL_IN); wake_up_interruptible(&queue->proc_list); /* tell user space progs */ } } nsyadc_sleep(h->sample_ms); if (signal_pending(current)) { siginfo_t info; if (sample_shutdown) { /* Only honor the signal if we're cleaning up */ printk(KERN_WARNING "%s received signal.\n", current->comm); break; } /* * Someone else sent us a kill (probably * the shutdown scripts "Sending all * processes the KILL signal"). Just * dequeue it and ignore it. */ spin_lock_irq(¤t->sigmask_lock); (void)dequeue_signal(¤t->blocked, &info); spin_unlock_irq(¤t->sigmask_lock); } } /* while (1) */ return 0; }/*----------------------------------------------------------------------------*//* flow functions ------------------------------------------------------------*//* * Set ADS8344 and SIO parameters for transfer. */static void set_SIO_transfer(void) { int i; SET_SIOSBRDR(SIO_PRESCALER); /* Set baud rate */ SET_SIOIVTCNT(SIO_IVTCNT); /* Set SIO interval */ EXT_AD_SELECT; /* Select ADS8344. */ for (i = 0; i < 500; i++); CLEAR_SIO_IRQ; /* Consume residual irq from sio */ enable_irq(S3C44B0X_INTERRUPT_SIO);}/* * Clock the Burr-Brown to fall the AD_BUSY. * With a 'start' bit and PD1,PD0 = 00 to enable PENIRQ. * Used for the first pen irq after booting. And when error occures during * conversion that need an initialisation. */static void sio_send_ad_ctrl(int channel) { WRITE_SIODATA(channel); SIO_START; /* start SIO transmission */}/* * Release transfer settings. */static void release_SIO_transfer(void) { disable_irq(S3C44B0X_INTERRUPT_SIO); SIO_DISABLE; EXT_AD_DESELECT;}/* * Send ADS8344 control byte. */ static void set_ad_ctrl(int sio_cmd_data){ int i; for (i = 0; i < 500; i++); WRITE_SIODATA(sio_cmd_data); SIO_START; /* start SIO */}/* * Get A/D conversion result. */static void read_conv_dat(int bits){ short temp; switch (bits) { case BIT15_BIT9: /* * The first clock is used for BUSY signal, * the real data start from Bit 6: * SIODATA: Bit 7 6 5 4 3 2 1 0 * | X D15 D14 D13 D12 D11 D10 D9 * \/ * ad_conv_val : Bit 31-16 15 14 13 12 11 10 9 8 - 0 * X - X D15 D14 D13 D12 D11 D10 D9 X - X */ temp = SIODATA; ad_conv_val = (temp & 0x3F) << 6; break; case BIT8_BIT1: /* SIODATA : Bit 7 6 5 4 3 2 1 0 * | D8 D7 D6 D5 D4 D3 D2 D1 * \/ * ad_conv_val : Bit 31-16 D15-D9 D8 - D1 D0 * : 0 X - X D15-D9 D8 - D1 X */ temp = SIODATA; ad_conv_val |= ((temp << 1) & 0x1fe); break; case BIT0_BIT0: /* SIODATA : Bit 7 6 0 * | D0 X - X * \/ * ad_conv_val : Bit 31-16 D15-D1 D0 * : 0 X - X D15-D1 D0 */ temp = SIODATA; ad_conv_val |= ((temp >> 4) &0x5); ad_conv_val &= 0x0000FFFF; break; } }static void ad_conv_state_shift(int new_state){ spin_lock_irq(&conv_state_lock); ad_conv_state = new_state; spin_unlock_irq(&conv_state_lock); }/* * Get one char from the queue buffer. * AND the head with 'AD_BUF_SIZE -1' to have the loopback */static unsigned char get_char_from_queue(void) { unsigned char result; result = queue->buf[queue->tail]; /* queue->tail = (queue->tail + 1) & (AD_BUF_SIZE - 1); */ queue->tail = (queue->tail + 1) % (AD_BUF_SIZE); spin_lock_irq(&queue->lock); queue->count--; spin_unlock_irq(&queue->lock); return result;}/* * Write one event in the queue buffer. * Test if there is place for an event = the head cannot be just one event * length after the queue. */static void put_in_queue(char *in, int len) { unsigned long head = queue->head; /* unsigned long maxhead = (queue->tail - len) & (AD_BUF_SIZE - 1); */ int i; if ( (queue->count >= AD_BUF_SIZE) || ((queue->head + len) > AD_BUF_SIZE) ) { printk("%0: ADC queue is full !!!!\n", __file__); return; } for(i=0;i<len;i++) { queue->buf[head] = in[i]; head++; } queue->head = head; spin_lock_irq(&queue->lock); queue->count += len; spin_unlock_irq(&queue->lock); }/* * Test if queue is empty. */static inline int queue_empty(void) { /* return queue->head == queue->tail; */ return (queue->count == 0); }/*----------------------------------------------------------------------------*//* Interrupt functions -------------------------------------------------------*//* * sio interrupt service. *///static void handle_sio_irq(void)static void handle_sio_irq(int irq, void *dev_id, struct pt_regs *regs){ unsigned long flags; int ts_busy_flag;/* Add by Jesse for SIO sharing between TS and ADC */
?? 快捷鍵說明
復制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號
Ctrl + =
減小字號
Ctrl + -