staging: comedi: s626: remove forward declarations 1
PATCH 3/12 staging: comedi: s626: remove forward declarations 1
Move the s626_attach and s626_detach functions down to match the coding style of the other comedi drivers. Then remove the forward declarations that are no longer needed.
Signed-off-by H Hartley Sweeten <[email protected]>
Cc Ian Abbott <[email protected]>
Cc Frank Mori Hess <[email protected]>
Cc Greg Kroah-Hartman <[email protected]>
--- drivers/staging/comedi/drivers/s626.c | 4572 ++++++++++++++++----------------- 1 file changed, 2256 insertions(+), 2316 deletions(-)
drivers/staging/comedi/drivers/s626.c +2256 -2316
@@ -207,70 +207,22 @@ static struct dio_private *dio_private_word[]={#define devpriv ((struct s626_private *)dev->private)#define diopriv ((struct dio_private *)s->private) -/* ioctl routines */ -static int s626_ai_insn_config (struct comedi_device *dev, -struct comedi_subdevice *s, -struct comedi_insn *insn,unsigned int *data); -/* static int s626_ai_rinsn(struct comedi_device *dev,struct comedi_subdevice *s,struct comedi_insn *insn,unsigned int *data); */ -static int s626_ai_insn_read (struct comedi_device *dev, -struct comedi_subdevice *s, -struct comedi_insn *insn,unsigned int *data); -static int s626_ai_cmd (struct comedi_device *dev,struct comedi_subdevice *s); -static int s626_ai_cmdtest (struct comedi_device *dev, -struct comedi_subdevice *s,struct comedi_cmd *cmd); -static int s626_ai_cancel (struct comedi_device *dev, -struct comedi_subdevice *s); -static int s626_ao_winsn (struct comedi_device *dev,struct comedi_subdevice *s, -struct comedi_insn *insn,unsigned int *data); -static int s626_ao_rinsn (struct comedi_device *dev,struct comedi_subdevice *s, -struct comedi_insn *insn,unsigned int *data); -static int s626_dio_insn_bits (struct comedi_device *dev, -struct comedi_subdevice *s, -struct comedi_insn *insn,unsigned int *data); -static int s626_dio_insn_config (struct comedi_device *dev, -struct comedi_subdevice *s, -struct comedi_insn *insn,unsigned int *data);static int s626_dio_set_irq (struct comedi_device *dev,unsigned int chan);static int s626_dio_reset_irq (struct comedi_device *dev,unsigned int gruop,unsigned int mask);static int s626_dio_clear_irq (struct comedi_device *dev); -static int s626_enc_insn_config (struct comedi_device *dev, -struct comedi_subdevice *s, -struct comedi_insn *insn,unsigned int *data); -static int s626_enc_insn_read (struct comedi_device *dev, -struct comedi_subdevice *s, -struct comedi_insn *insn,unsigned int *data); -static int s626_enc_insn_write (struct comedi_device *dev, -struct comedi_subdevice *s, -struct comedi_insn *insn,unsigned int *data);static int s626_ns_to_timer (int *nanosec,int round_mode); -static int s626_ai_load_polllist (uint8_t *ppl,struct comedi_cmd *cmd); -static int s626_ai_inttrig (struct comedi_device *dev, -struct comedi_subdevice *s,unsigned int trignum); -static irqreturn_t s626_irq_handler (int irq,void *d); -static unsigned int s626_ai_reg_to_uint (int data); -/* static unsigned int s626_uint_to_reg(struct comedi_subdevice *s, int data); */ - -/* end ioctl routines */ /* internal routines */ -static void s626_dio_init (struct comedi_device *dev); -static void ResetADC (struct comedi_device *dev,uint8_t * ppl); -static void LoadTrimDACs (struct comedi_device *dev);static void WriteTrimDAC (struct comedi_device *dev,uint8_t LogicalChan,uint8_t DacData);static uint8_t I2Cread (struct comedi_device *dev,uint8_t addr);static uint32_t I2Chandshake (struct comedi_device *dev,uint32_t val);static void SetDAC (struct comedi_device *dev,uint16_t chan,short dacdata);static void SendDAC (struct comedi_device *dev,uint32_t val); -static void WriteMISC2 (struct comedi_device *dev,uint16_t NewImage);static void DEBItransfer (struct comedi_device *dev);static uint16_t DEBIread (struct comedi_device *dev,uint16_t addr);static void DEBIwrite (struct comedi_device *dev,uint16_t addr,uint16_t wdata); -static void DEBIreplace (struct comedi_device *dev,uint16_t addr,uint16_t mask, -uint16_t wdata); -static void CloseDMAB (struct comedi_device *dev,struct bufferDMA *pdma, -size_t bsize);/* COUNTER OBJECT ------------------------------------------------ */ struct enc_private {
@@ -295,7 +247,6 @@ struct enc_private {#define encpriv ((struct enc_private *)(dev->subdevices+5)->private) -/* counters routines */ static void s626_timer_load (struct comedi_device *dev,struct enc_private *k,int tick);static uint32_t ReadLatch (struct comedi_device *dev,struct enc_private *k);
@@ -315,7 +266,6 @@ static uint16_t GetEnable_A(struct comedi_device *dev, struct enc_private *k);static uint16_t GetEnable_B (struct comedi_device *dev,struct enc_private *k);static void SetLatchSource (struct comedi_device *dev,struct enc_private *k,uint16_t value); -/* static uint16_t GetLatchSource(struct comedi_device *dev, struct enc_private *k ); */ static void SetLoadTrig_A (struct comedi_device *dev,struct enc_private *k,uint16_t Trig); static void SetLoadTrig_B(struct comedi_device *dev, struct enc_private *k,
@@ -328,20 +278,10 @@ static void SetIntSrc_A(struct comedi_device *dev, struct enc_private *k, uint16_t IntSource);static uint16_t GetIntSrc_A (struct comedi_device *dev,struct enc_private *k);static uint16_t GetIntSrc_B (struct comedi_device *dev,struct enc_private *k); -/* static void SetClkMult(struct comedi_device *dev, struct enc_private *k, uint16_t value ) ; */ -/* static uint16_t GetClkMult(struct comedi_device *dev, struct enc_private *k ) ; */ -/* static void SetIndexPol(struct comedi_device *dev, struct enc_private *k, uint16_t value ); */ -/* static uint16_t GetClkPol(struct comedi_device *dev, struct enc_private *k ) ; */ -/* static void SetIndexSrc( struct comedi_device *dev,struct enc_private *k, uint16_t value ); */ -/* static uint16_t GetClkSrc( struct comedi_device *dev,struct enc_private *k ); */ -/* static void SetIndexSrc( struct comedi_device *dev,struct enc_private *k, uint16_t value ); */ -/* static uint16_t GetIndexSrc( struct comedi_device *dev,struct enc_private *k ); */ static void PulseIndex_A (struct comedi_device *dev,struct enc_private *k);static void PulseIndex_B (struct comedi_device *dev,struct enc_private *k);static void Preload (struct comedi_device *dev,struct enc_private *k,uint32_t value); -static void CountersInit (struct comedi_device *dev); -/* end internal routines */ /* Counter objects constructor. */
@@ -486,2814 +426,2814 @@ static const struct comedi_lrange s626_range_table = { 2, { } }; -static int s626_attach (struct comedi_device *dev,struct comedi_devconfig *it) +static unsigned int s626_ai_reg_to_uint (int data) { -/* uint8_t PollList; */ -/* uint16_t AdcData; */ -/* uint16_t StartVal; */ -/* uint16_t index; */ -/* unsigned int data[16]; */ -int result; -int i; -int ret; -resource_size_t resourceStart; -dma_addr_t appdma; -struct comedi_subdevice *s; -struct pci_dev *pdev =NULL ; +unsigned int tempdata; -if (alloc_private (dev,sizeof (struct s626_private )) <0 ) -return -ENOMEM ; + tempdata = (data >>18 ); +if (tempdata &0x2000 ) + tempdata &=0x1fff ; +else + tempdata += (1 <<13 ); -for (i =0 ; i <ARRAY_SIZE (s626_boards) && !pdev; i++) { -do { - pdev =pci_get_subsys (s626_boards[i].vendor_id, - s626_boards[i].device_id, - s626_boards[i].subvendor_id, - s626_boards[i].subdevice_id, - pdev); +return tempdata; +} -if ((it->options[0 ] || it->options[1 ]) && pdev) { -/* matches requested bus/slot */ -if (pdev->bus->number == it->options[0 ] && -PCI_SLOT (pdev->devfn) == it->options[1 ]) -break ; - }else -break ; - }while (1 ); - } - devpriv->pdev = pdev; +/* static unsigned int s626_uint_to_reg(struct comedi_subdevice *s, int data){ */ +/* return 0; */ +/* } */ -if (pdev ==NULL ) { -printk (KERN_ERR "s626_attach: Board not present!!!\n" ); -return -ENODEV ; - } +static irqreturn_t s626_irq_handler (int irq,void *d) +{ +struct comedi_device *dev = d; +struct comedi_subdevice *s; +struct comedi_cmd *cmd; +struct enc_private *k; +unsigned long flags; +int32_t *readaddr; +uint32_t irqtype, irqstatus; +int i =0 ; +short tempdata; +uint8_t group; +uint16_t irqbit; - result =comedi_pci_enable (pdev,"s626" ); -if (result <0 ) { -printk (KERN_ERR "s626_attach: comedi_pci_enable fails\n" ); -return -ENODEV ; - } - devpriv->got_regions =1 ; +DEBUG ("s626_irq_handler: interrupt request received!!!\n" ); - resourceStart =pci_resource_start (devpriv->pdev,0 ); +if (dev->attached ==0 ) +return IRQ_NONE ; +/* lock to avoid race with comedi_poll */ +spin_lock_irqsave (&dev->spinlock, flags); - devpriv->base_addr =ioremap (resourceStart,SIZEOF_ADDRESS_SPACE ); -if (devpriv->base_addr ==NULL ) { -printk (KERN_ERR "s626_attach: IOREMAP failed\n" ); -return -ENODEV ; - } +/* save interrupt enable register state */ + irqstatus =readl (devpriv->base_addr +P_IER ); -if (devpriv->base_addr) { -/* disable master interrupt */ -writel (0 , devpriv->base_addr +P_IER ); +/* read interrupt type */ + irqtype =readl (devpriv->base_addr +P_ISR ); -/* soft reset */ -writel (MC1_SOFT_RESET , devpriv->base_addr +P_MC1 ); +/* disable master interrupt */ +writel (0 , devpriv->base_addr +P_IER ); -/* DMA FIXME DMA// */ -DEBUG ("s626_attach: DMA ALLOCATION\n" ); +/* clear interrupt */ +writel (irqtype, devpriv->base_addr +P_ISR ); -/* adc buffer allocation */ - devpriv->allocatedBuf =0 ; +/* do somethings */ +DEBUG ("s626_irq_handler: interrupt type %d\n" , irqtype); - devpriv->ANABuf.LogicalBase = -pci_alloc_consistent (devpriv->pdev,DMABUF_SIZE , &appdma); +switch (irqtype) { +case IRQ_RPS1 :/* end_of_scan occurs */ -if (devpriv->ANABuf.LogicalBase ==NULL ) { -printk (KERN_ERR "s626_attach: DMA Memory mapping error\n" ); -return -ENOMEM ; - } +DEBUG ("s626_irq_handler: RPS1 irq detected\n" ); - devpriv->ANABuf.PhysicalBase = appdma; +/* manage ai subdevice */ + s = dev->subdevices; + cmd = &(s->async->cmd); -DEBUG - ("s626_attach: AllocDMAB ADC Logical=%p, bsize=%d, Physical=0x%x\n" , - devpriv->ANABuf.LogicalBase,DMABUF_SIZE , - (uint32_t ) devpriv->ANABuf.PhysicalBase); +/* Init ptr to DMA buffer that holds new ADC data. We skip the +* first uint16_t in the buffer because it contains junk data from +* the final ADC of the previous poll list scan. +*/ + readaddr = (int32_t *) devpriv->ANABuf.LogicalBase +1 ; - devpriv->allocatedBuf++; +/* get the data and hand it over to comedi */ +for (i =0 ; i < (s->async->cmd.chanlist_len); i++) { +/* Convert ADC data to 16-bit integer values and copy to application */ +/* buffer. */ + tempdata =s626_ai_reg_to_uint ((int )*readaddr); + readaddr++; - devpriv->RPSBuf.LogicalBase = -pci_alloc_consistent (devpriv->pdev,DMABUF_SIZE , &appdma); +/* put data into read buffer */ +/* comedi_buf_put(s->async, tempdata); */ +if (cfc_write_to_buffer (s, tempdata) ==0 ) +printk + ("s626_irq_handler: cfc_write_to_buffer error!\n" ); -if (devpriv->RPSBuf.LogicalBase ==NULL ) { -printk (KERN_ERR "s626_attach: DMA Memory mapping error\n" ); -return -ENOMEM ; +DEBUG ("s626_irq_handler: ai channel %d acquired: %d\n" , + i, tempdata); } - devpriv->RPSBuf.PhysicalBase = appdma; - -DEBUG - ("s626_attach: AllocDMAB RPS Logical=%p, bsize=%d, Physical=0x%x\n" , - devpriv->RPSBuf.LogicalBase,DMABUF_SIZE , - (uint32_t ) devpriv->RPSBuf.PhysicalBase); +/* end of scan occurs */ + s->async->events |=COMEDI_CB_EOS ; - devpriv->allocatedBuf++; +if (!(devpriv->ai_continous)) + devpriv->ai_sample_count--; +if (devpriv->ai_sample_count <=0 ) { + devpriv->ai_cmd_running =0 ; - } +/* Stop RPS program. */ +MC_DISABLE (P_MC1 ,MC1_ERPS1 ); - dev->board_ptr = s626_boards; - dev->board_name = thisboard->name; +/* send end of acquisition */ + s->async->events |=COMEDI_CB_EOA ; - ret =comedi_alloc_subdevices (dev,6 ); -if (ret) -return ret; +/* disable master interrupt */ + irqstatus =0 ; + } - dev->iobase = (unsigned long )devpriv->base_addr; - dev->irq = devpriv->pdev->irq; +if (devpriv->ai_cmd_running && cmd->scan_begin_src ==TRIG_EXT ) { +DEBUG + ("s626_irq_handler: enable interrupt on dio channel %d\n" , + cmd->scan_begin_arg); -/* set up interrupt handler */ -if (dev->irq ==0 ) { -printk (KERN_ERR " unknown irq (bad)\n" ); - }else { - ret =request_irq (dev->irq, s626_irq_handler,IRQF_SHARED , -"s626" , dev); +s626_dio_set_irq (dev, cmd->scan_begin_arg); -if (ret <0 ) { -printk (KERN_ERR " irq not available\n" ); - dev->irq =0 ; +DEBUG ("s626_irq_handler: External trigger is set!!!\n" ); } - } - -DEBUG ("s626_attach: -- it opts %d,%d --\n" , - it->options[0 ], it->options[1 ]); +/* tell comedi that data is there */ +DEBUG ("s626_irq_handler: events %d\n" , s->async->events); +comedi_event (dev, s); +break ; +case IRQ_GPIO3 :/* check dio and conter interrupt */ - s = dev->subdevices +0 ; -/* analog input subdevice */ - dev->read_subdev = s; -/* we support single-ended (ground) and differential */ - s->type =COMEDI_SUBD_AI ; - s->subdev_flags =SDF_READABLE |SDF_DIFF |SDF_CMD_READ ; - s->n_chan = thisboard->ai_chans; - s->maxdata = (0xffff >>2 ); - s->range_table = &s626_range_table; - s->len_chanlist = thisboard->ai_chans;/* This is the maximum chanlist -length that the board can -handle */ - s->insn_config = s626_ai_insn_config; - s->insn_read = s626_ai_insn_read; - s->do_cmd = s626_ai_cmd; - s->do_cmdtest = s626_ai_cmdtest; - s->cancel = s626_ai_cancel; +DEBUG ("s626_irq_handler: GPIO3 irq detected\n" ); - s = dev->subdevices +1 ; -/* analog output subdevice */ - s->type =COMEDI_SUBD_AO ; - s->subdev_flags =SDF_WRITABLE |SDF_READABLE ; - s->n_chan = thisboard->ao_chans; - s->maxdata = (0x3fff ); - s->range_table = &range_bipolar10; - s->insn_write = s626_ao_winsn; - s->insn_read = s626_ao_rinsn; +/* manage ai subdevice */ + s = dev->subdevices; + cmd = &(s->async->cmd); - s = dev->subdevices +2 ; -/* digital I/O subdevice */ - s->type =COMEDI_SUBD_DIO ; - s->subdev_flags =SDF_WRITABLE |SDF_READABLE ; - s->n_chan =S626_DIO_CHANNELS ; - s->maxdata =1 ; - s->io_bits =0xffff ; - s->private = &dio_private_A; - s->range_table = &range_digital; - s->insn_config = s626_dio_insn_config; - s->insn_bits = s626_dio_insn_bits; +/* s626_dio_clear_irq(dev); */ - s = dev->subdevices +3 ; -/* digital I/O subdevice */ - s->type =COMEDI_SUBD_DIO ; - s->subdev_flags =SDF_WRITABLE |SDF_READABLE ; - s->n_chan =16 ; - s->maxdata =1 ; - s->io_bits =0xffff ; - s->private = &dio_private_B; - s->range_table = &range_digital; - s->insn_config = s626_dio_insn_config; - s->insn_bits = s626_dio_insn_bits; +for (group =0 ; group <S626_DIO_BANKS ; group++) { + irqbit =0 ; +/* read interrupt type */ + irqbit =DEBIread (dev, + ((struct dio_private *)(dev-> + subdevices + +2 + + group)-> + private)->RDCapFlg); - s = dev->subdevices +4 ; -/* digital I/O subdevice */ - s->type =COMEDI_SUBD_DIO ; - s->subdev_flags =SDF_WRITABLE |SDF_READABLE ; - s->n_chan =16 ; - s->maxdata =1 ; - s->io_bits =0xffff ; - s->private = &dio_private_C; - s->range_table = &range_digital; - s->insn_config = s626_dio_insn_config; - s->insn_bits = s626_dio_insn_bits; +/* check if interrupt is generated from dio channels */ +if (irqbit) { +s626_dio_reset_irq (dev, group, irqbit); +DEBUG + ("s626_irq_handler: check interrupt on dio group %d %d\n" , + group, i); +if (devpriv->ai_cmd_running) { +/* check if interrupt is an ai acquisition start trigger */ +if ((irqbit >> (cmd->start_arg - + (16 * group))) + ==1 && cmd->start_src ==TRIG_EXT ) { +DEBUG + ("s626_irq_handler: Edge capture interrupt received from channel %d\n" , + cmd->start_arg); - s = dev->subdevices +5 ; -/* encoder (counter) subdevice */ - s->type =COMEDI_SUBD_COUNTER ; - s->subdev_flags =SDF_WRITABLE |SDF_READABLE |SDF_LSAMPL ; - s->n_chan = thisboard->enc_chans; - s->private = enc_private_data; - s->insn_config = s626_enc_insn_config; - s->insn_read = s626_enc_insn_read; - s->insn_write = s626_enc_insn_write; - s->maxdata =0xffffff ; - s->range_table = &range_unknown; +/* Start executing the RPS program. */ +MC_ENABLE (P_MC1 ,MC1_ERPS1 ); -/* stop ai_command */ - devpriv->ai_cmd_running =0 ; +DEBUG + ("s626_irq_handler: acquisition start triggered!!!\n" ); -if (devpriv->base_addr && (devpriv->allocatedBuf ==2 )) { -dma_addr_t pPhysBuf; -uint16_t chan; +if (cmd->scan_begin_src == +TRIG_EXT ) { +DEBUG + ("s626_ai_cmd: enable interrupt on dio channel %d\n" , + cmd-> + scan_begin_arg); -/* enab DEBI and audio pins, enable I2C interface. */ -MC_ENABLE (P_MC1 ,MC1_DEBI |MC1_AUDIO |MC1_I2C ); -/* Configure DEBI operating mode. */ -WR7146 (P_DEBICFG ,DEBI_CFG_SLAVE16 /* Local bus is 16 */ -/* bits wide. */ - | (DEBI_TOUT <<DEBI_CFG_TOUT_BIT ) +s626_dio_set_irq (dev, + cmd->scan_begin_arg); -/* Declare DEBI */ -/* transfer timeout */ -/* interval. */ - |DEBI_SWAP /* Set up byte lane */ -/* steering. */ - |DEBI_CFG_INTEL );/* Intel-compatible */ -/* local bus (DEBI */ -/* never times out). */ -DEBUG ("s626_attach: %d debi init -- %d\n" , -DEBI_CFG_SLAVE16 | (DEBI_TOUT <<DEBI_CFG_TOUT_BIT ) | -DEBI_SWAP |DEBI_CFG_INTEL , -DEBI_CFG_INTEL |DEBI_CFG_TOQ |DEBI_CFG_INCQ | -DEBI_CFG_16Q ); +DEBUG + ("s626_irq_handler: External scan trigger is set!!!\n" ); + } + } +if ((irqbit >> (cmd->scan_begin_arg - + (16 * group))) + ==1 + && cmd->scan_begin_src == +TRIG_EXT ) { +DEBUG + ("s626_irq_handler: Edge capture interrupt received from channel %d\n" , + cmd->scan_begin_arg); -/* DEBI INIT S626 WR7146( P_DEBICFG, DEBI_CFG_INTEL | DEBI_CFG_TOQ */ -/* | DEBI_CFG_INCQ| DEBI_CFG_16Q); //end */ +/* Trigger ADC scan loop start by setting RPS Signal 0. */ +MC_ENABLE (P_MC2 ,MC2_ADC_RPS ); -/* Paging is disabled. */ -WR7146 (P_DEBIPAGE ,DEBI_PAGE_DISABLE );/* Disable MMU paging. */ +DEBUG + ("s626_irq_handler: scan triggered!!! %d\n" , + devpriv->ai_sample_count); +if (cmd->convert_src == +TRIG_EXT ) { -/* Init GPIO so that ADC Start* is negated. */ -WR7146 (P_GPIO ,GPIO_BASE |GPIO1_HI ); +DEBUG + ("s626_ai_cmd: enable interrupt on dio channel %d group %d\n" , + cmd->convert_arg - + (16 * group), + group); -/* IsBoardRevA is a boolean that indicates whether the board is RevA. -* -* VERSION 2.01 CHANGE: REV A & B BOARDS NOW SUPPORTED BY DYNAMIC -* EEPROM ADDRESS SELECTION. Initialize the I2C interface, which -* is used to access the onboard serial EEPROM. The EEPROM's I2C -* DeviceAddress is hardwired to a value that is dependent on the -* 626 board revision. On all board revisions, the EEPROM stores -* TrimDAC calibration constants for analog I/O. On RevB and -* higher boards, the DeviceAddress is hardwired to 0 to enable -* the EEPROM to also store the PCI SubVendorID and SubDeviceID; -* this is the address at which the SAA7146 expects a -* configuration EEPROM to reside. On RevA boards, the EEPROM -* device address, which is hardwired to 4, prevents the SAA7146 -* from retrieving PCI sub-IDs, so the SAA7146 uses its built-in -* default values, instead. -*/ + devpriv->ai_convert_count + = cmd->chanlist_len; -/* devpriv->I2Cards= IsBoardRevA ? 0xA8 : 0xA0; // Set I2C EEPROM */ -/* DeviceType (0xA0) */ -/* and DeviceAddress<<1. */ +s626_dio_set_irq (dev, + cmd->convert_arg); - devpriv->I2CAdrs =0xA0 ;/* I2C device address for onboard */ -/* eeprom(revb) */ +DEBUG + ("s626_irq_handler: External convert trigger is set!!!\n" ); + } -/* Issue an I2C ABORT command to halt any I2C operation in */ -/* progress and reset BUSY flag. */ -WR7146 (P_I2CSTAT ,I2C_CLKSEL |I2C_ABORT ); -/* Write I2C control: abort any I2C activity. */ -MC_ENABLE (P_MC2 ,MC2_UPLD_IIC ); -/* Invoke command upload */ -while ((RR7146 (P_MC2 ) &MC2_UPLD_IIC ) ==0 ) - ; -/* and wait for upload to complete. */ +if (cmd->convert_src == +TRIG_TIMER ) { + k = &encpriv[5 ]; + devpriv->ai_convert_count + = cmd->chanlist_len; + k->SetEnable (dev, k, +CLKENAB_ALWAYS ); + } + } +if ((irqbit >> (cmd->convert_arg - + (16 * group))) + ==1 + && cmd->convert_src ==TRIG_EXT ) { +DEBUG + ("s626_irq_handler: Edge capture interrupt received from channel %d\n" , + cmd->convert_arg); -/* Per SAA7146 data sheet, write to STATUS reg twice to -* reset all I2C error flags. */ -for (i =0 ; i <2 ; i++) { -WR7146 (P_I2CSTAT ,I2C_CLKSEL ); -/* Write I2C control: reset error flags. */ -MC_ENABLE (P_MC2 ,MC2_UPLD_IIC );/* Invoke command upload */ -while (!MC_TEST (P_MC2 ,MC2_UPLD_IIC )) - ; -/* and wait for upload to complete. */ - } +/* Trigger ADC scan loop start by setting RPS Signal 0. */ +MC_ENABLE (P_MC2 ,MC2_ADC_RPS ); -/* Init audio interface functional attributes: set DAC/ADC -* serial clock rates, invert DAC serial clock so that -* DAC data setup times are satisfied, enable DAC serial -* clock out. -*/ +DEBUG + ("s626_irq_handler: adc convert triggered!!!\n" ); -WR7146 (P_ACON2 ,ACON2_INIT ); + devpriv->ai_convert_count--; -/* Set up TSL1 slot list, which is used to control the -* accumulation of ADC data: RSD1 = shift data in on SD1. -* SIB_A1 = store data uint8_t at next available location in -* FB BUFFER1 register. */ -WR7146 (P_TSL1 ,RSD1 |SIB_A1 ); -/* Fetch ADC high data uint8_t. */ -WR7146 (P_TSL1 +4 ,RSD1 |SIB_A1 |EOS ); -/* Fetch ADC low data uint8_t; end of TSL1. */ +if (devpriv->ai_convert_count > +0 ) { -/* enab TSL1 slot list so that it executes all the time. */ -WR7146 (P_ACON1 ,ACON1_ADCSTART ); +DEBUG + ("s626_ai_cmd: enable interrupt on dio channel %d group %d\n" , + cmd->convert_arg - + (16 * group), + group); -/* Initialize RPS registers used for ADC. */ +s626_dio_set_irq (dev, + cmd->convert_arg); -/* Physical start of RPS program. */ -WR7146 (P_RPSADDR1 , (uint32_t ) devpriv->RPSBuf.PhysicalBase); +DEBUG + ("s626_irq_handler: External trigger is set!!!\n" ); + } + } + } +break ; + } + } -WR7146 (P_RPSPAGE1 ,0 ); -/* RPS program performs no explicit mem writes. */ -WR7146 (P_RPS1_TOUT ,0 );/* Disable RPS timeouts. */ +/* read interrupt type */ + irqbit =DEBIread (dev,LP_RDMISC2 ); -/* SAA7146 BUG WORKAROUND. Initialize SAA7146 ADC interface -* to a known state by invoking ADCs until FB BUFFER 1 -* register shows that it is correctly receiving ADC data. -* This is necessary because the SAA7146 ADC interface does -* not start up in a defined state after a PCI reset. -*/ +/* check interrupt on counters */ +DEBUG ("s626_irq_handler: check counters interrupt %d\n" , + irqbit); -/* PollList = EOPL; // Create a simple polling */ -/* // list for analog input */ -/* // channel 0. */ -/* ResetADC( dev, &PollList ); */ +if (irqbit &IRQ_COINT1A ) { +DEBUG + ("s626_irq_handler: interrupt on counter 1A overflow\n" ); + k = &encpriv[0 ]; -/* s626_ai_rinsn(dev,dev->subdevices,NULL,data); //( &AdcData ); // */ -/* //Get initial ADC */ -/* //value. */ +/* clear interrupt capture flag */ + k->ResetCapFlags (dev, k); + } +if (irqbit &IRQ_COINT2A ) { +DEBUG + ("s626_irq_handler: interrupt on counter 2A overflow\n" ); + k = &encpriv[1 ]; -/* StartVal = data[0]; */ - -/* // VERSION 2.01 CHANGE: TIMEOUT ADDED TO PREVENT HANGED EXECUTION. */ -/* // Invoke ADCs until the new ADC value differs from the initial */ -/* // value or a timeout occurs. The timeout protects against the */ -/* // possibility that the driver is restarting and the ADC data is a */ -/* // fixed value resulting from the applied ADC analog input being */ -/* // unusually quiet or at the rail. */ +/* clear interrupt capture flag */ + k->ResetCapFlags (dev, k); + } +if (irqbit &IRQ_COINT3A ) { +DEBUG + ("s626_irq_handler: interrupt on counter 3A overflow\n" ); + k = &encpriv[2 ]; -/* for ( index = 0; index < 500; index++ ) */ -/* { */ -/* s626_ai_rinsn(dev,dev->subdevices,NULL,data); */ -/* AdcData = data[0]; //ReadADC( &AdcData ); */ -/* if ( AdcData != StartVal ) */ -/* break; */ -/* } */ +/* clear interrupt capture flag */ + k->ResetCapFlags (dev, k); + } +if (irqbit &IRQ_COINT1B ) { +DEBUG + ("s626_irq_handler: interrupt on counter 1B overflow\n" ); + k = &encpriv[3 ]; -/* end initADC */ +/* clear interrupt capture flag */ + k->ResetCapFlags (dev, k); + } +if (irqbit &IRQ_COINT2B ) { +DEBUG + ("s626_irq_handler: interrupt on counter 2B overflow\n" ); + k = &encpriv[4 ]; -/* init the DAC interface */ +/* clear interrupt capture flag */ + k->ResetCapFlags (dev, k); -/* Init Audio2's output DMAC attributes: burst length = 1 -* DWORD, threshold = 1 DWORD. -*/ -WR7146 (P_PCI_BT_A ,0 ); +if (devpriv->ai_convert_count >0 ) { + devpriv->ai_convert_count--; +if (devpriv->ai_convert_count ==0 ) + k->SetEnable (dev, k,CLKENAB_INDEX ); -/* Init Audio2's output DMA physical addresses. The protection -* address is set to 1 DWORD past the base address so that a -* single DWORD will be transferred each time a DMA transfer is -* enabled. */ +if (cmd->convert_src ==TRIG_TIMER ) { +DEBUG + ("s626_irq_handler: conver timer trigger!!! %d\n" , + devpriv->ai_convert_count); - pPhysBuf = - devpriv->ANABuf.PhysicalBase + - (DAC_WDMABUF_OS *sizeof (uint32_t )); +/* Trigger ADC scan loop start by setting RPS Signal 0. */ +MC_ENABLE (P_MC2 ,MC2_ADC_RPS ); + } + } + } +if (irqbit &IRQ_COINT3B ) { +DEBUG + ("s626_irq_handler: interrupt on counter 3B overflow\n" ); + k = &encpriv[5 ]; -WR7146 (P_BASEA2_OUT , (uint32_t ) pPhysBuf);/* Buffer base adrs. */ -WR7146 (P_PROTA2_OUT , (uint32_t ) (pPhysBuf +sizeof (uint32_t )));/* Protection address. */ +/* clear interrupt capture flag */ + k->ResetCapFlags (dev, k); -/* Cache Audio2's output DMA buffer logical address. This is -* where DAC data is buffered for A2 output DMA transfers. */ - devpriv->pDacWBuf = - (uint32_t *) devpriv->ANABuf.LogicalBase +DAC_WDMABUF_OS ; +if (cmd->scan_begin_src ==TRIG_TIMER ) { +DEBUG + ("s626_irq_handler: scan timer trigger!!!\n" ); -/* Audio2's output channels does not use paging. The protection -* violation handling bit is set so that the DMAC will -* automatically halt and its PCI address pointer will be reset -* when the protection address is reached. */ +/* Trigger ADC scan loop start by setting RPS Signal 0. */ +MC_ENABLE (P_MC2 ,MC2_ADC_RPS ); + } -WR7146 (P_PAGEA2_OUT ,8 ); +if (cmd->convert_src ==TRIG_TIMER ) { +DEBUG + ("s626_irq_handler: convert timer trigger is set\n" ); + k = &encpriv[4 ]; + devpriv->ai_convert_count = cmd->chanlist_len; + k->SetEnable (dev, k,CLKENAB_ALWAYS ); + } + } + } -/* Initialize time slot list 2 (TSL2), which is used to control -* the clock generation for and serialization of data to be sent -* to the DAC devices. Slot 0 is a NOP that is used to trap TSL -* execution; this permits other slots to be safely modified -* without first turning off the TSL sequencer (which is -* apparently impossible to do). Also, SD3 (which is driven by a -* pull-up resistor) is shifted in and stored to the MSB of -* FB_BUFFER2 to be used as evidence that the slot sequence has -* not yet finished executing. -*/ +/* enable interrupt */ +writel (irqstatus, devpriv->base_addr +P_IER ); -SETVECT (0 ,XSD2 |RSD3 |SIB_A2 |EOS ); -/* Slot 0: Trap TSL execution, shift 0xFF into FB_BUFFER2. */ +DEBUG ("s626_irq_handler: exit interrupt service routine.\n" ); -/* Initialize slot 1, which is constant. Slot 1 causes a -* DWORD to be transferred from audio channel 2's output FIFO -* to the FIFO's output buffer so that it can be serialized -* and sent to the DAC during subsequent slots. All remaining -* slots are dynamically populated as required by the target -* DAC device. -*/ -SETVECT (1 ,LF_A2 ); -/* Slot 1: Fetch DWORD from Audio2's output FIFO. */ +spin_unlock_irqrestore (&dev->spinlock, flags); +return IRQ_HANDLED ; +} -/* Start DAC's audio interface (TSL2) running. */ -WR7146 (P_ACON1 ,ACON1_DACSTART ); +/* +* this functions build the RPS program for hardware driven acquistion +*/ +static void ResetADC (struct comedi_device *dev,uint8_t *ppl) +{ + registeruint32_t *pRPS; +uint32_t JmpAdrs; +uint16_t i; +uint16_t n; +uint32_t LocalPPL; +struct comedi_cmd *cmd = &(dev->subdevices->async->cmd); -/* end init DAC interface */ +/* Stop RPS program in case it is currently running. */ +MC_DISABLE (P_MC1 ,MC1_ERPS1 ); -/* Init Trim DACs to calibrated values. Do it twice because the -* SAA7146 audio channel does not always reset properly and -* sometimes causes the first few TrimDAC writes to malfunction. -*/ +/* Set starting logical address to write RPS commands. */ + pRPS = (uint32_t *) devpriv->RPSBuf.LogicalBase; -LoadTrimDACs (dev); -LoadTrimDACs (dev);/* Insurance. */ +/* Initialize RPS instruction pointer. */ +WR7146 (P_RPSADDR1 , (uint32_t ) devpriv->RPSBuf.PhysicalBase); -/* Manually init all gate array hardware in case this is a soft -* reset (we have no way of determining whether this is a warm -* or cold start). This is necessary because the gate array will -* reset only in response to a PCI hard reset; there is no soft -* reset function. */ +/* Construct RPS program in RPSBuf DMA buffer */ -/* Init all DAC outputs to 0V and init all DAC setpoint and -* polarity images. -*/ -for (chan =0 ; chan <S626_DAC_CHANNELS ; chan++) -SetDAC (dev, chan,0 ); +if (cmd !=NULL && cmd->scan_begin_src !=TRIG_FOLLOW ) { +DEBUG ("ResetADC: scan_begin pause inserted\n" ); +/* Wait for Start trigger. */ + *pRPS++ =RPS_PAUSE |RPS_SIGADC ; + *pRPS++ =RPS_CLRSIGNAL |RPS_SIGADC ; + } -/* Init image of WRMISC2 Battery Charger Enabled control bit. -* This image is used when the state of the charger control bit, -* which has no direct hardware readback mechanism, is queried. -*/ - devpriv->ChargeEnabled =0 ; +/* SAA7146 BUG WORKAROUND Do a dummy DEBI Write. This is necessary +* because the first RPS DEBI Write following a non-RPS DEBI write +* seems to always fail. If we don't do this dummy write, the ADC +* gain might not be set to the value required for the first slot in +* the poll list; the ADC gain would instead remain unchanged from +* the previously programmed value. +*/ + *pRPS++ =RPS_LDREG | (P_DEBICMD >>2 ); +/* Write DEBI Write command and address to shadow RAM. */ -/* Init image of watchdog timer interval in WRMISC2. This image -* maintains the value of the control bits of MISC2 are -* continuously reset to zero as long as the WD timer is disabled. -*/ - devpriv->WDInterval =0 ; + *pRPS++ =DEBI_CMD_WRWORD |LP_GSEL ; + *pRPS++ =RPS_LDREG | (P_DEBIAD >>2 ); +/* Write DEBI immediate data to shadow RAM: */ -/* Init Counter Interrupt enab mask for RDMISC2. This mask is -* applied against MISC2 when testing to determine which timer -* events are requesting interrupt service. -*/ - devpriv->CounterIntEnabs =0 ; + *pRPS++ =GSEL_BIPOLAR5V ; +/* arbitrary immediate data value. */ -/* Init counters. */ -CountersInit (dev); + *pRPS++ =RPS_CLRSIGNAL |RPS_DEBI ; +/* Reset "shadow RAM uploaded" flag. */ + *pRPS++ =RPS_UPLOAD |RPS_DEBI ;/* Invoke shadow RAM upload. */ + *pRPS++ =RPS_PAUSE |RPS_DEBI ;/* Wait for shadow upload to finish. */ -/* Without modifying the state of the Battery Backup enab, disable -* the watchdog timer, set DIO channels 0-5 to operate in the -* standard DIO (vs. counter overflow) mode, disable the battery -* charger, and reset the watchdog interval selector to zero. +/* Digitize all slots in the poll list. This is implemented as a +* for loop to limit the slot count to 16 in case the application +* forgot to set the EOPL flag in the final slot. +*/ +for (devpriv->AdcItems =0 ; devpriv->AdcItems <16 ; devpriv->AdcItems++) { +/* Convert application's poll list item to private board class +* format. Each app poll list item is an uint8_t with form +* (EOPL,x,x,RANGE,CHAN<3:0>), where RANGE code indicates 0 = +* +-10V, 1 = +-5V, and EOPL = End of Poll List marker. */ -WriteMISC2 (dev, (uint16_t ) (DEBIread (dev, -LP_RDMISC2 ) & -MISC2_BATT_ENABLE )); + LocalPPL = + (*ppl <<8 ) | (*ppl &0x10 ?GSEL_BIPOLAR5V : +GSEL_BIPOLAR10V ); -/* Initialize the digital I/O subsystem. */ -s626_dio_init (dev); +/* Switch ADC analog gain. */ + *pRPS++ =RPS_LDREG | (P_DEBICMD >>2 );/* Write DEBI command */ +/* and address to */ +/* shadow RAM. */ + *pRPS++ =DEBI_CMD_WRWORD |LP_GSEL ; + *pRPS++ =RPS_LDREG | (P_DEBIAD >>2 );/* Write DEBI */ +/* immediate data to */ +/* shadow RAM. */ + *pRPS++ = LocalPPL; + *pRPS++ =RPS_CLRSIGNAL |RPS_DEBI ;/* Reset "shadow RAM uploaded" */ +/* flag. */ + *pRPS++ =RPS_UPLOAD |RPS_DEBI ;/* Invoke shadow RAM upload. */ + *pRPS++ =RPS_PAUSE |RPS_DEBI ;/* Wait for shadow upload to */ +/* finish. */ -/* enable interrupt test */ -/* writel(IRQ_GPIO3 | IRQ_RPS1,devpriv->base_addr+P_IER); */ - } +/* Select ADC analog input channel. */ + *pRPS++ =RPS_LDREG | (P_DEBICMD >>2 ); +/* Write DEBI command and address to shadow RAM. */ + *pRPS++ =DEBI_CMD_WRWORD |LP_ISEL ; + *pRPS++ =RPS_LDREG | (P_DEBIAD >>2 ); +/* Write DEBI immediate data to shadow RAM. */ + *pRPS++ = LocalPPL; + *pRPS++ =RPS_CLRSIGNAL |RPS_DEBI ; +/* Reset "shadow RAM uploaded" flag. */ -DEBUG ("s626_attach: comedi%d s626 attached %04x\n" , dev->minor, - (uint32_t ) devpriv->base_addr); + *pRPS++ =RPS_UPLOAD |RPS_DEBI ; +/* Invoke shadow RAM upload. */ -return 1 ; -} + *pRPS++ =RPS_PAUSE |RPS_DEBI ; +/* Wait for shadow upload to finish. */ -static unsigned int s626_ai_reg_to_uint (int data) -{ -unsigned int tempdata; +/* Delay at least 10 microseconds for analog input settling. +* Instead of padding with NOPs, we use RPS_JUMP instructions +* here; this allows us to produce a longer delay than is +* possible with NOPs because each RPS_JUMP flushes the RPS' +* instruction prefetch pipeline. +*/ + JmpAdrs = + (uint32_t ) devpriv->RPSBuf.PhysicalBase + + (uint32_t ) ((unsigned long )pRPS - + (unsigned long )devpriv->RPSBuf.LogicalBase); +for (i =0 ; i < (10 *RPSCLK_PER_US /2 ); i++) { + JmpAdrs +=8 ;/* Repeat to implement time delay: */ + *pRPS++ =RPS_JUMP ;/* Jump to next RPS instruction. */ + *pRPS++ = JmpAdrs; + } - tempdata = (data >>18 ); -if (tempdata &0x2000 ) - tempdata &=0x1fff ; -else - tempdata += (1 <<13 ); +if (cmd !=NULL && cmd->convert_src !=TRIG_NOW ) { +DEBUG ("ResetADC: convert pause inserted\n" ); +/* Wait for Start trigger. */ + *pRPS++ =RPS_PAUSE |RPS_SIGADC ; + *pRPS++ =RPS_CLRSIGNAL |RPS_SIGADC ; + } +/* Start ADC by pulsing GPIO1. */ + *pRPS++ =RPS_LDREG | (P_GPIO >>2 );/* Begin ADC Start pulse. */ + *pRPS++ =GPIO_BASE |GPIO1_LO ; + *pRPS++ =RPS_NOP ; +/* VERSION 2.03 CHANGE: STRETCH OUT ADC START PULSE. */ + *pRPS++ =RPS_LDREG | (P_GPIO >>2 );/* End ADC Start pulse. */ + *pRPS++ =GPIO_BASE |GPIO1_HI ; -return tempdata; -} +/* Wait for ADC to complete (GPIO2 is asserted high when ADC not +* busy) and for data from previous conversion to shift into FB +* BUFFER 1 register. +*/ + *pRPS++ =RPS_PAUSE |RPS_GPIO2 ;/* Wait for ADC done. */ -/* static unsigned int s626_uint_to_reg(struct comedi_subdevice *s, int data){ */ -/* return 0; */ -/* } */ +/* Transfer ADC data from FB BUFFER 1 register to DMA buffer. */ + *pRPS++ =RPS_STREG | (BUGFIX_STREG (P_FB_BUFFER1 ) >>2 ); + *pRPS++ = + (uint32_t ) devpriv->ANABuf.PhysicalBase + + (devpriv->AdcItems <<2 ); -static irqreturn_t s626_irq_handler (int irq,void *d) -{ -struct comedi_device *dev = d; -struct comedi_subdevice *s; -struct comedi_cmd *cmd; -struct enc_private *k; -unsigned long flags; -int32_t *readaddr; -uint32_t irqtype, irqstatus; -int i =0 ; -short tempdata; -uint8_t group; -uint16_t irqbit; +/* If this slot's EndOfPollList flag is set, all channels have */ +/* now been processed. */ +if (*ppl++ &EOPL ) { + devpriv->AdcItems++;/* Adjust poll list item count. */ +break ;/* Exit poll list processing loop. */ + } + } +DEBUG ("ResetADC: ADC items %d\n" , devpriv->AdcItems); -DEBUG ("s626_irq_handler: interrupt request received!!!\n" ); +/* VERSION 2.01 CHANGE: DELAY CHANGED FROM 250NS to 2US. Allow the +* ADC to stabilize for 2 microseconds before starting the final +* (dummy) conversion. This delay is necessary to allow sufficient +* time between last conversion finished and the start of the dummy +* conversion. Without this delay, the last conversion's data value +* is sometimes set to the previous conversion's data value. +*/ +for (n =0 ; n < (2 *RPSCLK_PER_US ); n++) + *pRPS++ =RPS_NOP ; -if (dev->attached ==0 ) -return IRQ_NONE ; -/* lock to avoid race with comedi_poll */ -spin_lock_irqsave (&dev->spinlock, flags); +/* Start a dummy conversion to cause the data from the last +* conversion of interest to be shifted in. +*/ + *pRPS++ =RPS_LDREG | (P_GPIO >>2 );/* Begin ADC Start pulse. */ + *pRPS++ =GPIO_BASE |GPIO1_LO ; + *pRPS++ =RPS_NOP ; +/* VERSION 2.03 CHANGE: STRETCH OUT ADC START PULSE. */ + *pRPS++ =RPS_LDREG | (P_GPIO >>2 );/* End ADC Start pulse. */ + *pRPS++ =GPIO_BASE |GPIO1_HI ; -/* save interrupt enable register state */ - irqstatus =readl (devpriv->base_addr +P_IER ); +/* Wait for the data from the last conversion of interest to arrive +* in FB BUFFER 1 register. +*/ + *pRPS++ =RPS_PAUSE |RPS_GPIO2 ;/* Wait for ADC done. */ -/* read interrupt type */ - irqtype =readl (devpriv->base_addr +P_ISR ); +/* Transfer final ADC data from FB BUFFER 1 register to DMA buffer. */ + *pRPS++ =RPS_STREG | (BUGFIX_STREG (P_FB_BUFFER1 ) >>2 );/* */ + *pRPS++ = + (uint32_t ) devpriv->ANABuf.PhysicalBase + (devpriv->AdcItems <<2 ); -/* disable master interrupt */ -writel (0 , devpriv->base_addr +P_IER ); +/* Indicate ADC scan loop is finished. */ +/* *pRPS++= RPS_CLRSIGNAL | RPS_SIGADC ; // Signal ReadADC() that scan is done. */ -/* clear interrupt */ -writel (irqtype, devpriv->base_addr +P_ISR ); +/* invoke interrupt */ +if (devpriv->ai_cmd_running ==1 ) { +DEBUG ("ResetADC: insert irq in ADC RPS task\n" ); + *pRPS++ =RPS_IRQ ; + } +/* Restart RPS program at its beginning. */ + *pRPS++ =RPS_JUMP ;/* Branch to start of RPS program. */ + *pRPS++ = (uint32_t ) devpriv->RPSBuf.PhysicalBase; -/* do somethings */ -DEBUG ("s626_irq_handler: interrupt type %d\n" , irqtype); +/* End of RPS program build */ +} -switch (irqtype) { -case IRQ_RPS1 :/* end_of_scan occurs */ +/* TO COMPLETE, IF NECESSARY */ +static int s626_ai_insn_config (struct comedi_device *dev, +struct comedi_subdevice *s, +struct comedi_insn *insn,unsigned int *data) +{ -DEBUG ("s626_irq_handler: RPS1 irq detected\n" ); +return -EINVAL ; +} -/* manage ai subdevice */ - s = dev->subdevices; - cmd = &(s->async->cmd); +/* static int s626_ai_rinsn(struct comedi_device *dev,struct comedi_subdevice *s,struct comedi_insn *insn,unsigned int *data) */ +/* { */ +/* register uint8_t i; */ +/* register int32_t *readaddr; */ -/* Init ptr to DMA buffer that holds new ADC data. We skip the -* first uint16_t in the buffer because it contains junk data from -* the final ADC of the previous poll list scan. -*/ - readaddr = (int32_t *) devpriv->ANABuf.LogicalBase +1 ; +/* DEBUG("as626_ai_rinsn: ai_rinsn enter\n"); */ -/* get the data and hand it over to comedi */ -for (i =0 ; i < (s->async->cmd.chanlist_len); i++) { -/* Convert ADC data to 16-bit integer values and copy to application */ -/* buffer. */ - tempdata =s626_ai_reg_to_uint ((int )*readaddr); - readaddr++; +/* Trigger ADC scan loop start by setting RPS Signal 0. */ +/* MC_ENABLE( P_MC2, MC2_ADC_RPS ); */ -/* put data into read buffer */ -/* comedi_buf_put(s->async, tempdata); */ -if (cfc_write_to_buffer (s, tempdata) ==0 ) -printk - ("s626_irq_handler: cfc_write_to_buffer error!\n" ); +/* Wait until ADC scan loop is finished (RPS Signal 0 reset). */ +/* while ( MC_TEST( P_MC2, MC2_ADC_RPS ) ); */ -DEBUG ("s626_irq_handler: ai channel %d acquired: %d\n" , - i, tempdata); - } +/* Init ptr to DMA buffer that holds new ADC data. We skip the +* first uint16_t in the buffer because it contains junk data from +* the final ADC of the previous poll list scan. +*/ +/* readaddr = (uint32_t *)devpriv->ANABuf.LogicalBase + 1; */ -/* end of scan occurs */ - s->async->events |=COMEDI_CB_EOS ; +/* Convert ADC data to 16-bit integer values and copy to application buffer. */ +/* for ( i = 0; i < devpriv->AdcItems; i++ ) { */ +/* *data = s626_ai_reg_to_uint( *readaddr++ ); */ +/* DEBUG("s626_ai_rinsn: data %d\n",*data); */ +/* data++; */ +/* } */ -if (!(devpriv->ai_continous)) - devpriv->ai_sample_count--; -if (devpriv->ai_sample_count <=0 ) { - devpriv->ai_cmd_running =0 ; +/* DEBUG("s626_ai_rinsn: ai_rinsn escape\n"); */ +/* return i; */ +/* } */ -/* Stop RPS program. */ -MC_DISABLE (P_MC1 ,MC1_ERPS1 ); +static int s626_ai_insn_read (struct comedi_device *dev, +struct comedi_subdevice *s, +struct comedi_insn *insn,unsigned int *data) +{ +uint16_t chan =CR_CHAN (insn->chanspec); +uint16_t range =CR_RANGE (insn->chanspec); +uint16_t AdcSpec =0 ; +uint32_t GpioImage; +int n; -/* send end of acquisition */ - s->async->events |=COMEDI_CB_EOA ; +/* interrupt call test */ +/* writel(IRQ_GPIO3,devpriv->base_addr+P_PSR); */ +/* Writing a logical 1 into any of the RPS_PSR bits causes the +* corresponding interrupt to be generated if enabled +*/ -/* disable master interrupt */ - irqstatus =0 ; - } +DEBUG ("s626_ai_insn_read: entering\n" ); -if (devpriv->ai_cmd_running && cmd->scan_begin_src ==TRIG_EXT ) { -DEBUG - ("s626_irq_handler: enable interrupt on dio channel %d\n" , - cmd->scan_begin_arg); +/* Convert application's ADC specification into form +* appropriate for register programming. +*/ +if (range ==0 ) + AdcSpec = (chan <<8 ) | (GSEL_BIPOLAR5V ); +else + AdcSpec = (chan <<8 ) | (GSEL_BIPOLAR10V ); -s626_dio_set_irq (dev, cmd->scan_begin_arg); +/* Switch ADC analog gain. */ +DEBIwrite (dev,LP_GSEL , AdcSpec);/* Set gain. */ -DEBUG ("s626_irq_handler: External trigger is set!!!\n" ); - } -/* tell comedi that data is there */ -DEBUG ("s626_irq_handler: events %d\n" , s->async->events); -comedi_event (dev, s); -break ; -case IRQ_GPIO3 :/* check dio and conter interrupt */ +/* Select ADC analog input channel. */ +DEBIwrite (dev,LP_ISEL , AdcSpec);/* Select channel. */ -DEBUG ("s626_irq_handler: GPIO3 irq detected\n" ); +for (n =0 ; n < insn->n; n++) { -/* manage ai subdevice */ - s = dev->subdevices; - cmd = &(s->async->cmd); +/* Delay 10 microseconds for analog input settling. */ +udelay (10 ); -/* s626_dio_clear_irq(dev); */ +/* Start ADC by pulsing GPIO1 low. */ + GpioImage =RR7146 (P_GPIO ); +/* Assert ADC Start command */ +WR7146 (P_GPIO , GpioImage & ~GPIO1_HI ); +/* and stretch it out. */ +WR7146 (P_GPIO , GpioImage & ~GPIO1_HI ); +WR7146 (P_GPIO , GpioImage & ~GPIO1_HI ); +/* Negate ADC Start command. */ +WR7146 (P_GPIO , GpioImage |GPIO1_HI ); -for (group =0 ; group <S626_DIO_BANKS ; group++) { - irqbit =0 ; -/* read interrupt type */ - irqbit =DEBIread (dev, - ((struct dio_private *)(dev-> - subdevices + -2 + - group)-> - private)->RDCapFlg); - -/* check if interrupt is generated from dio channels */ -if (irqbit) { -s626_dio_reset_irq (dev, group, irqbit); -DEBUG - ("s626_irq_handler: check interrupt on dio group %d %d\n" , - group, i); -if (devpriv->ai_cmd_running) { -/* check if interrupt is an ai acquisition start trigger */ -if ((irqbit >> (cmd->start_arg - - (16 * group))) - ==1 && cmd->start_src ==TRIG_EXT ) { -DEBUG - ("s626_irq_handler: Edge capture interrupt received from channel %d\n" , - cmd->start_arg); +/* Wait for ADC to complete (GPIO2 is asserted high when */ +/* ADC not busy) and for data from previous conversion to */ +/* shift into FB BUFFER 1 register. */ -/* Start executing the RPS program. */ -MC_ENABLE (P_MC1 ,MC1_ERPS1 ); +/* Wait for ADC done. */ +while (!(RR7146 (P_PSR ) &PSR_GPIO2 )) + ; -DEBUG - ("s626_irq_handler: acquisition start triggered!!!\n" ); +/* Fetch ADC data. */ +if (n !=0 ) + data[n -1 ] =s626_ai_reg_to_uint (RR7146 (P_FB_BUFFER1 )); -if (cmd->scan_begin_src == -TRIG_EXT ) { -DEBUG - ("s626_ai_cmd: enable interrupt on dio channel %d\n" , - cmd-> - scan_begin_arg); +/* Allow the ADC to stabilize for 4 microseconds before +* starting the next (final) conversion. This delay is +* necessary to allow sufficient time between last +* conversion finished and the start of the next +* conversion. Without this delay, the last conversion's +* data value is sometimes set to the previous +* conversion's data value. +*/ +udelay (4 ); + } -s626_dio_set_irq (dev, - cmd->scan_begin_arg); +/* Start a dummy conversion to cause the data from the +* previous conversion to be shifted in. */ + GpioImage =RR7146 (P_GPIO ); -DEBUG - ("s626_irq_handler: External scan trigger is set!!!\n" ); - } - } -if ((irqbit >> (cmd->scan_begin_arg - - (16 * group))) - ==1 - && cmd->scan_begin_src == -TRIG_EXT ) { -DEBUG - ("s626_irq_handler: Edge capture interrupt received from channel %d\n" , - cmd->scan_begin_arg); +/* Assert ADC Start command */ +WR7146 (P_GPIO , GpioImage & ~GPIO1_HI ); +/* and stretch it out. */ +WR7146 (P_GPIO , GpioImage & ~GPIO1_HI ); +WR7146 (P_GPIO , GpioImage & ~GPIO1_HI ); +/* Negate ADC Start command. */ +WR7146 (P_GPIO , GpioImage |GPIO1_HI ); -/* Trigger ADC scan loop start by setting RPS Signal 0. */ -MC_ENABLE (P_MC2 ,MC2_ADC_RPS ); +/* Wait for the data to arrive in FB BUFFER 1 register. */ -DEBUG - ("s626_irq_handler: scan triggered!!! %d\n" , - devpriv->ai_sample_count); -if (cmd->convert_src == -TRIG_EXT ) { +/* Wait for ADC done. */ +while (!(RR7146 (P_PSR ) &PSR_GPIO2 )) + ; -DEBUG - ("s626_ai_cmd: enable interrupt on dio channel %d group %d\n" , - cmd->convert_arg - - (16 * group), - group); +/* Fetch ADC data from audio interface's input shift register. */ - devpriv->ai_convert_count - = cmd->chanlist_len; +/* Fetch ADC data. */ +if (n !=0 ) + data[n -1 ] =s626_ai_reg_to_uint (RR7146 (P_FB_BUFFER1 )); -s626_dio_set_irq (dev, - cmd->convert_arg); +DEBUG ("s626_ai_insn_read: samples %d, data %d\n" , n, data[n -1 ]); -DEBUG - ("s626_irq_handler: External convert trigger is set!!!\n" ); - } +return n; +} -if (cmd->convert_src == -TRIG_TIMER ) { - k = &encpriv[5 ]; - devpriv->ai_convert_count - = cmd->chanlist_len; - k->SetEnable (dev, k, -CLKENAB_ALWAYS ); - } - } -if ((irqbit >> (cmd->convert_arg - - (16 * group))) - ==1 - && cmd->convert_src ==TRIG_EXT ) { -DEBUG - ("s626_irq_handler: Edge capture interrupt received from channel %d\n" , - cmd->convert_arg); +static int s626_ai_load_polllist (uint8_t *ppl,struct comedi_cmd *cmd) +{ -/* Trigger ADC scan loop start by setting RPS Signal 0. */ -MC_ENABLE (P_MC2 ,MC2_ADC_RPS ); +int n; -DEBUG - ("s626_irq_handler: adc convert triggered!!!\n" ); +for (n =0 ; n < cmd->chanlist_len; n++) { +if (CR_RANGE ((cmd->chanlist)[n]) ==0 ) + ppl[n] = (CR_CHAN ((cmd->chanlist)[n])) | (RANGE_5V ); +else + ppl[n] = (CR_CHAN ((cmd->chanlist)[n])) | (RANGE_10V ); + } +if (n !=0 ) + ppl[n -1 ] |=EOPL ; - devpriv->ai_convert_count--; +return n; +} -if (devpriv->ai_convert_count > -0 ) { +static int s626_ai_inttrig (struct comedi_device *dev, +struct comedi_subdevice *s,unsigned int trignum) +{ +if (trignum !=0 ) +return -EINVAL ; -DEBUG - ("s626_ai_cmd: enable interrupt on dio channel %d group %d\n" , - cmd->convert_arg - - (16 * group), - group); +DEBUG ("s626_ai_inttrig: trigger adc start..." ); -s626_dio_set_irq (dev, - cmd->convert_arg); +/* Start executing the RPS program. */ +MC_ENABLE (P_MC1 ,MC1_ERPS1 ); -DEBUG - ("s626_irq_handler: External trigger is set!!!\n" ); - } - } - } -break ; - } - } + s->async->inttrig =NULL ; -/* read interrupt type */ - irqbit =DEBIread (dev,LP_RDMISC2 ); +DEBUG (" done\n" ); -/* check interrupt on counters */ -DEBUG ("s626_irq_handler: check counters interrupt %d\n" , - irqbit); +return 1 ; +} -if (irqbit &IRQ_COINT1A ) { -DEBUG - ("s626_irq_handler: interrupt on counter 1A overflow\n" ); - k = &encpriv[0 ]; +/* TO COMPLETE */ +static int s626_ai_cmd (struct comedi_device *dev,struct comedi_subdevice *s) +{ -/* clear interrupt capture flag */ - k->ResetCapFlags (dev, k); - } -if (irqbit &IRQ_COINT2A ) { -DEBUG - ("s626_irq_handler: interrupt on counter 2A overflow\n" ); - k = &encpriv[1 ]; +uint8_t ppl[16 ]; +struct comedi_cmd *cmd = &s->async->cmd; +struct enc_private *k; +int tick; -/* clear interrupt capture flag */ - k->ResetCapFlags (dev, k); - } -if (irqbit &IRQ_COINT3A ) { -DEBUG - ("s626_irq_handler: interrupt on counter 3A overflow\n" ); - k = &encpriv[2 ]; +DEBUG ("s626_ai_cmd: entering command function\n" ); -/* clear interrupt capture flag */ - k->ResetCapFlags (dev, k); - } -if (irqbit &IRQ_COINT1B ) { -DEBUG - ("s626_irq_handler: interrupt on counter 1B overflow\n" ); - k = &encpriv[3 ]; +if (devpriv->ai_cmd_running) { +printk (KERN_ERR "s626_ai_cmd: Another ai_cmd is running %d\n" , + dev->minor); +return -EBUSY ; + } +/* disable interrupt */ +writel (0 , devpriv->base_addr +P_IER ); -/* clear interrupt capture flag */ - k->ResetCapFlags (dev, k); - } -if (irqbit &IRQ_COINT2B ) { -DEBUG - ("s626_irq_handler: interrupt on counter 2B overflow\n" ); - k = &encpriv[4 ]; +/* clear interrupt request */ +writel (IRQ_RPS1 |IRQ_GPIO3 , devpriv->base_addr +P_ISR ); -/* clear interrupt capture flag */ - k->ResetCapFlags (dev, k); +/* clear any pending interrupt */ +s626_dio_clear_irq (dev); +/* s626_enc_clear_irq(dev); */ -if (devpriv->ai_convert_count >0 ) { - devpriv->ai_convert_count--; -if (devpriv->ai_convert_count ==0 ) - k->SetEnable (dev, k,CLKENAB_INDEX ); +/* reset ai_cmd_running flag */ + devpriv->ai_cmd_running =0 ; -if (cmd->convert_src ==TRIG_TIMER ) { -DEBUG - ("s626_irq_handler: conver timer trigger!!! %d\n" , - devpriv->ai_convert_count); +/* test if cmd is valid */ +if (cmd ==NULL ) { +DEBUG ("s626_ai_cmd: NULL command\n" ); +return -EINVAL ; + }else { +DEBUG ("s626_ai_cmd: command received!!!\n" ); + } -/* Trigger ADC scan loop start by setting RPS Signal 0. */ -MC_ENABLE (P_MC2 ,MC2_ADC_RPS ); - } - } - } -if (irqbit &IRQ_COINT3B ) { -DEBUG - ("s626_irq_handler: interrupt on counter 3B overflow\n" ); - k = &encpriv[5 ]; +if (dev->irq ==0 ) { +comedi_error (dev, +"s626_ai_cmd: cannot run command without an irq" ); +return -EIO ; + } -/* clear interrupt capture flag */ - k->ResetCapFlags (dev, k); +s626_ai_load_polllist (ppl, cmd); + devpriv->ai_cmd_running =1 ; + devpriv->ai_convert_count =0 ; -if (cmd->scan_begin_src ==TRIG_TIMER ) { -DEBUG - ("s626_irq_handler: scan timer trigger!!!\n" ); +switch (cmd->scan_begin_src) { +case TRIG_FOLLOW : +break ; +case TRIG_TIMER : +/* set a conter to generate adc trigger at scan_begin_arg interval */ + k = &encpriv[5 ]; + tick =s626_ns_to_timer ((int *)&cmd->scan_begin_arg, + cmd->flags &TRIG_ROUND_MASK ); -/* Trigger ADC scan loop start by setting RPS Signal 0. */ -MC_ENABLE (P_MC2 ,MC2_ADC_RPS ); - } +/* load timer value and enable interrupt */ +s626_timer_load (dev, k, tick); + k->SetEnable (dev, k,CLKENAB_ALWAYS ); -if (cmd->convert_src ==TRIG_TIMER ) { -DEBUG - ("s626_irq_handler: convert timer trigger is set\n" ); - k = &encpriv[4 ]; - devpriv->ai_convert_count = cmd->chanlist_len; - k->SetEnable (dev, k,CLKENAB_ALWAYS ); - } - } - } +DEBUG ("s626_ai_cmd: scan trigger timer is set with value %d\n" , + tick); -/* enable interrupt */ -writel (irqstatus, devpriv->base_addr +P_IER ); +break ; +case TRIG_EXT : +/* set the digital line and interrupt for scan trigger */ +if (cmd->start_src !=TRIG_EXT ) +s626_dio_set_irq (dev, cmd->scan_begin_arg); -DEBUG ("s626_irq_handler: exit interrupt service routine.\n" ); +DEBUG ("s626_ai_cmd: External scan trigger is set!!!\n" ); -spin_unlock_irqrestore (&dev->spinlock, flags); -return IRQ_HANDLED ; -} +break ; + } -static void s626_detach (struct comedi_device *dev) -{ -if (devpriv) { -/* stop ai_command */ - devpriv->ai_cmd_running =0 ; +switch (cmd->convert_src) { +case TRIG_NOW : +break ; +case TRIG_TIMER : +/* set a conter to generate adc trigger at convert_arg interval */ + k = &encpriv[4 ]; + tick =s626_ns_to_timer ((int *)&cmd->convert_arg, + cmd->flags &TRIG_ROUND_MASK ); -if (devpriv->base_addr) { -/* interrupt mask */ -WR7146 (P_IER ,0 );/* Disable master interrupt. */ -WR7146 (P_ISR ,IRQ_GPIO3 |IRQ_RPS1 );/* Clear board's IRQ status flag. */ +/* load timer value and enable interrupt */ +s626_timer_load (dev, k, tick); + k->SetEnable (dev, k,CLKENAB_INDEX ); -/* Disable the watchdog timer and battery charger. */ -WriteMISC2 (dev,0 ); +DEBUG + ("s626_ai_cmd: convert trigger timer is set with value %d\n" , + tick); +break ; +case TRIG_EXT : +/* set the digital line and interrupt for convert trigger */ +if (cmd->scan_begin_src !=TRIG_EXT + && cmd->start_src ==TRIG_EXT ) +s626_dio_set_irq (dev, cmd->convert_arg); -/* Close all interfaces on 7146 device. */ -WR7146 (P_MC1 ,MC1_SHUTDOWN ); -WR7146 (P_ACON1 ,ACON1_BASE ); +DEBUG ("s626_ai_cmd: External convert trigger is set!!!\n" ); -CloseDMAB (dev, &devpriv->RPSBuf,DMABUF_SIZE ); -CloseDMAB (dev, &devpriv->ANABuf,DMABUF_SIZE ); - } +break ; + } -if (dev->irq) -free_irq (dev->irq, dev); -if (devpriv->base_addr) -iounmap (devpriv->base_addr); -if (devpriv->pdev) { -if (devpriv->got_regions) -comedi_pci_disable (devpriv->pdev); -pci_dev_put (devpriv->pdev); - } +switch (cmd->stop_src) { +case TRIG_COUNT : +/* data arrives as one packet */ + devpriv->ai_sample_count = cmd->stop_arg; + devpriv->ai_continous =0 ; +break ; +case TRIG_NONE : +/* continous acquisition */ + devpriv->ai_continous =1 ; + devpriv->ai_sample_count =0 ; +break ; } -} -/* -* this functions build the RPS program for hardware driven acquistion -*/ -static void ResetADC (struct comedi_device *dev,uint8_t *ppl) -{ - registeruint32_t *pRPS; -uint32_t JmpAdrs; -uint16_t i; -uint16_t n; -uint32_t LocalPPL; -struct comedi_cmd *cmd = &(dev->subdevices->async->cmd); +ResetADC (dev, ppl); -/* Stop RPS program in case it is currently running. */ -MC_DISABLE (P_MC1 ,MC1_ERPS1 ); +switch (cmd->start_src) { +case TRIG_NOW : +/* Trigger ADC scan loop start by setting RPS Signal 0. */ +/* MC_ENABLE( P_MC2, MC2_ADC_RPS ); */ -/* Set starting logical address to write RPS commands. */ - pRPS = (uint32_t *) devpriv->RPSBuf.LogicalBase; +/* Start executing the RPS program. */ +MC_ENABLE (P_MC1 ,MC1_ERPS1 ); -/* Initialize RPS instruction pointer. */ -WR7146 (P_RPSADDR1 , (uint32_t ) devpriv->RPSBuf.PhysicalBase); +DEBUG ("s626_ai_cmd: ADC triggered\n" ); + s->async->inttrig =NULL ; +break ; +case TRIG_EXT : +/* configure DIO channel for acquisition trigger */ +s626_dio_set_irq (dev, cmd->start_arg); -/* Construct RPS program in RPSBuf DMA buffer */ +DEBUG ("s626_ai_cmd: External start trigger is set!!!\n" ); -if (cmd !=NULL && cmd->scan_begin_src !=TRIG_FOLLOW ) { -DEBUG ("ResetADC: scan_begin pause inserted\n" ); -/* Wait for Start trigger. */ - *pRPS++ =RPS_PAUSE |RPS_SIGADC ; - *pRPS++ =RPS_CLRSIGNAL |RPS_SIGADC ; + s->async->inttrig =NULL ; +break ; +case TRIG_INT : + s->async->inttrig = s626_ai_inttrig; +break ; } -/* SAA7146 BUG WORKAROUND Do a dummy DEBI Write. This is necessary -* because the first RPS DEBI Write following a non-RPS DEBI write -* seems to always fail. If we don't do this dummy write, the ADC -* gain might not be set to the value required for the first slot in -* the poll list; the ADC gain would instead remain unchanged from -* the previously programmed value. -*/ - *pRPS++ =RPS_LDREG | (P_DEBICMD >>2 ); -/* Write DEBI Write command and address to shadow RAM. */ +/* enable interrupt */ +writel (IRQ_GPIO3 |IRQ_RPS1 , devpriv->base_addr +P_IER ); - *pRPS++ =DEBI_CMD_WRWORD |LP_GSEL ; - *pRPS++ =RPS_LDREG | (P_DEBIAD >>2 ); -/* Write DEBI immediate data to shadow RAM: */ +DEBUG ("s626_ai_cmd: command function terminated\n" ); - *pRPS++ =GSEL_BIPOLAR5V ; -/* arbitrary immediate data value. */ +return 0 ; +} - *pRPS++ =RPS_CLRSIGNAL |RPS_DEBI ; -/* Reset "shadow RAM uploaded" flag. */ - *pRPS++ =RPS_UPLOAD |RPS_DEBI ;/* Invoke shadow RAM upload. */ - *pRPS++ =RPS_PAUSE |RPS_DEBI ;/* Wait for shadow upload to finish. */ +static int s626_ai_cmdtest (struct comedi_device *dev, +struct comedi_subdevice *s,struct comedi_cmd *cmd) +{ +int err =0 ; +int tmp; -/* Digitize all slots in the poll list. This is implemented as a -* for loop to limit the slot count to 16 in case the application -* forgot to set the EOPL flag in the final slot. -*/ -for (devpriv->AdcItems =0 ; devpriv->AdcItems <16 ; devpriv->AdcItems++) { -/* Convert application's poll list item to private board class -* format. Each app poll list item is an uint8_t with form -* (EOPL,x,x,RANGE,CHAN<3:0>), where RANGE code indicates 0 = -* +-10V, 1 = +-5V, and EOPL = End of Poll List marker. -*/ - LocalPPL = - (*ppl <<8 ) | (*ppl &0x10 ?GSEL_BIPOLAR5V : -GSEL_BIPOLAR10V ); +/* cmdtest tests a particular command to see if it is valid. Using +* the cmdtest ioctl, a user can create a valid cmd and then have it +* executes by the cmd ioctl. +* +* cmdtest returns 1,2,3,4 or 0, depending on which tests the +* command passes. */ -/* Switch ADC analog gain. */ - *pRPS++ =RPS_LDREG | (P_DEBICMD >>2 );/* Write DEBI command */ -/* and address to */ -/* shadow RAM. */ - *pRPS++ =DEBI_CMD_WRWORD |LP_GSEL ; - *pRPS++ =RPS_LDREG | (P_DEBIAD >>2 );/* Write DEBI */ -/* immediate data to */ -/* shadow RAM. */ - *pRPS++ = LocalPPL; - *pRPS++ =RPS_CLRSIGNAL |RPS_DEBI ;/* Reset "shadow RAM uploaded" */ -/* flag. */ - *pRPS++ =RPS_UPLOAD |RPS_DEBI ;/* Invoke shadow RAM upload. */ - *pRPS++ =RPS_PAUSE |RPS_DEBI ;/* Wait for shadow upload to */ -/* finish. */ +/* step 1: make sure trigger sources are trivially valid */ -/* Select ADC analog input channel. */ - *pRPS++ =RPS_LDREG | (P_DEBICMD >>2 ); -/* Write DEBI command and address to shadow RAM. */ - *pRPS++ =DEBI_CMD_WRWORD |LP_ISEL ; - *pRPS++ =RPS_LDREG | (P_DEBIAD >>2 ); -/* Write DEBI immediate data to shadow RAM. */ - *pRPS++ = LocalPPL; - *pRPS++ =RPS_CLRSIGNAL |RPS_DEBI ; -/* Reset "shadow RAM uploaded" flag. */ + tmp = cmd->start_src; + cmd->start_src &=TRIG_NOW |TRIG_INT |TRIG_EXT ; +if (!cmd->start_src || tmp != cmd->start_src) + err++; - *pRPS++ =RPS_UPLOAD |RPS_DEBI ; -/* Invoke shadow RAM upload. */ + tmp = cmd->scan_begin_src; + cmd->scan_begin_src &=TRIG_TIMER |TRIG_EXT |TRIG_FOLLOW ; +if (!cmd->scan_begin_src || tmp != cmd->scan_begin_src) + err++; - *pRPS++ =RPS_PAUSE |RPS_DEBI ; -/* Wait for shadow upload to finish. */ + tmp = cmd->convert_src; + cmd->convert_src &=TRIG_TIMER |TRIG_EXT |TRIG_NOW ; +if (!cmd->convert_src || tmp != cmd->convert_src) + err++; -/* Delay at least 10 microseconds for analog input settling. -* Instead of padding with NOPs, we use RPS_JUMP instructions -* here; this allows us to produce a longer delay than is -* possible with NOPs because each RPS_JUMP flushes the RPS' -* instruction prefetch pipeline. -*/ - JmpAdrs = - (uint32_t ) devpriv->RPSBuf.PhysicalBase + - (uint32_t ) ((unsigned long )pRPS - - (unsigned long )devpriv->RPSBuf.LogicalBase); -for (i =0 ; i < (10 *RPSCLK_PER_US /2 ); i++) { - JmpAdrs +=8 ;/* Repeat to implement time delay: */ - *pRPS++ =RPS_JUMP ;/* Jump to next RPS instruction. */ - *pRPS++ = JmpAdrs; - } + tmp = cmd->scan_end_src; + cmd->scan_end_src &=TRIG_COUNT ; +if (!cmd->scan_end_src || tmp != cmd->scan_end_src) + err++; -if (cmd !=NULL && cmd->convert_src !=TRIG_NOW ) { -DEBUG ("ResetADC: convert pause inserted\n" ); -/* Wait for Start trigger. */ - *pRPS++ =RPS_PAUSE |RPS_SIGADC ; - *pRPS++ =RPS_CLRSIGNAL |RPS_SIGADC ; - } -/* Start ADC by pulsing GPIO1. */ - *pRPS++ =RPS_LDREG | (P_GPIO >>2 );/* Begin ADC Start pulse. */ - *pRPS++ =GPIO_BASE |GPIO1_LO ; - *pRPS++ =RPS_NOP ; -/* VERSION 2.03 CHANGE: STRETCH OUT ADC START PULSE. */ - *pRPS++ =RPS_LDREG | (P_GPIO >>2 );/* End ADC Start pulse. */ - *pRPS++ =GPIO_BASE |GPIO1_HI ; + tmp = cmd->stop_src; + cmd->stop_src &=TRIG_COUNT |TRIG_NONE ; +if (!cmd->stop_src || tmp != cmd->stop_src) + err++; -/* Wait for ADC to complete (GPIO2 is asserted high when ADC not -* busy) and for data from previous conversion to shift into FB -* BUFFER 1 register. -*/ - *pRPS++ =RPS_PAUSE |RPS_GPIO2 ;/* Wait for ADC done. */ +if (err) +return 1 ; -/* Transfer ADC data from FB BUFFER 1 register to DMA buffer. */ - *pRPS++ =RPS_STREG | (BUGFIX_STREG (P_FB_BUFFER1 ) >>2 ); - *pRPS++ = - (uint32_t ) devpriv->ANABuf.PhysicalBase + - (devpriv->AdcItems <<2 ); +/* step 2: make sure trigger sources are unique and mutually +compatible */ -/* If this slot's EndOfPollList flag is set, all channels have */ -/* now been processed. */ -if (*ppl++ &EOPL ) { - devpriv->AdcItems++;/* Adjust poll list item count. */ -break ;/* Exit poll list processing loop. */ - } +/* note that mutual compatibility is not an issue here */ +if (cmd->scan_begin_src !=TRIG_TIMER && + cmd->scan_begin_src !=TRIG_EXT + && cmd->scan_begin_src !=TRIG_FOLLOW ) + err++; +if (cmd->convert_src !=TRIG_TIMER && + cmd->convert_src !=TRIG_EXT && cmd->convert_src !=TRIG_NOW ) + err++; +if (cmd->stop_src !=TRIG_COUNT && cmd->stop_src !=TRIG_NONE ) + err++; + +if (err) +return 2 ; + +/* step 3: make sure arguments are trivially compatible */ + +if (cmd->start_src !=TRIG_EXT && cmd->start_arg !=0 ) { + cmd->start_arg =0 ; + err++; } -DEBUG ("ResetADC: ADC items %d\n" , devpriv->AdcItems); -/* VERSION 2.01 CHANGE: DELAY CHANGED FROM 250NS to 2US. Allow the -* ADC to stabilize for 2 microseconds before starting the final -* (dummy) conversion. This delay is necessary to allow sufficient -* time between last conversion finished and the start of the dummy -* conversion. Without this delay, the last conversion's data value -* is sometimes set to the previous conversion's data value. -*/ -for (n =0 ; n < (2 *RPSCLK_PER_US ); n++) - *pRPS++ =RPS_NOP ; +if (cmd->start_src ==TRIG_EXT && cmd->start_arg >39 ) { + cmd->start_arg =39 ; + err++; + } -/* Start a dummy conversion to cause the data from the last -* conversion of interest to be shifted in. -*/ - *pRPS++ =RPS_LDREG | (P_GPIO >>2 );/* Begin ADC Start pulse. */ - *pRPS++ =GPIO_BASE |GPIO1_LO ; - *pRPS++ =RPS_NOP ; -/* VERSION 2.03 CHANGE: STRETCH OUT ADC START PULSE. */ - *pRPS++ =RPS_LDREG | (P_GPIO >>2 );/* End ADC Start pulse. */ - *pRPS++ =GPIO_BASE |GPIO1_HI ; +if (cmd->scan_begin_src ==TRIG_EXT && cmd->scan_begin_arg >39 ) { + cmd->scan_begin_arg =39 ; + err++; + } -/* Wait for the data from the last conversion of interest to arrive -* in FB BUFFER 1 register. -*/ - *pRPS++ =RPS_PAUSE |RPS_GPIO2 ;/* Wait for ADC done. */ +if (cmd->convert_src ==TRIG_EXT && cmd->convert_arg >39 ) { + cmd->convert_arg =39 ; + err++; + } +#define MAX_SPEED 200000/* in nanoseconds */ +#define MIN_SPEED 2000000000/* in nanoseconds */ -/* Transfer final ADC data from FB BUFFER 1 register to DMA buffer. */ - *pRPS++ =RPS_STREG | (BUGFIX_STREG (P_FB_BUFFER1 ) >>2 );/* */ - *pRPS++ = - (uint32_t ) devpriv->ANABuf.PhysicalBase + (devpriv->AdcItems <<2 ); +if (cmd->scan_begin_src ==TRIG_TIMER ) { +if (cmd->scan_begin_arg <MAX_SPEED ) { + cmd->scan_begin_arg =MAX_SPEED ; + err++; + } +if (cmd->scan_begin_arg >MIN_SPEED ) { + cmd->scan_begin_arg =MIN_SPEED ; + err++; + } + }else { +/* external trigger */ +/* should be level/edge, hi/lo specification here */ +/* should specify multiple external triggers */ +/* if(cmd->scan_begin_arg>9){ */ +/* cmd->scan_begin_arg=9; */ +/* err++; */ +/* } */ + } +if (cmd->convert_src ==TRIG_TIMER ) { +if (cmd->convert_arg <MAX_SPEED ) { + cmd->convert_arg =MAX_SPEED ; + err++; + } +if (cmd->convert_arg >MIN_SPEED ) { + cmd->convert_arg =MIN_SPEED ; + err++; + } + }else { +/* external trigger */ +/* see above */ +/* if(cmd->convert_arg>9){ */ +/* cmd->convert_arg=9; */ +/* err++; */ +/* } */ + } -/* Indicate ADC scan loop is finished. */ -/* *pRPS++= RPS_CLRSIGNAL | RPS_SIGADC ; // Signal ReadADC() that scan is done. */ +if (cmd->scan_end_arg != cmd->chanlist_len) { + cmd->scan_end_arg = cmd->chanlist_len; + err++; + } +if (cmd->stop_src ==TRIG_COUNT ) { +if (cmd->stop_arg >0x00ffffff ) { + cmd->stop_arg =0x00ffffff ; + err++; + } + }else { +/* TRIG_NONE */ +if (cmd->stop_arg !=0 ) { + cmd->stop_arg =0 ; + err++; + } + } -/* invoke interrupt */ -if (devpriv->ai_cmd_running ==1 ) { -DEBUG ("ResetADC: insert irq in ADC RPS task\n" ); - *pRPS++ =RPS_IRQ ; +if (err) +return 3 ; + +/* step 4: fix up any arguments */ + +if (cmd->scan_begin_src ==TRIG_TIMER ) { + tmp = cmd->scan_begin_arg; +s626_ns_to_timer ((int *)&cmd->scan_begin_arg, + cmd->flags &TRIG_ROUND_MASK ); +if (tmp != cmd->scan_begin_arg) + err++; + } +if (cmd->convert_src ==TRIG_TIMER ) { + tmp = cmd->convert_arg; +s626_ns_to_timer ((int *)&cmd->convert_arg, + cmd->flags &TRIG_ROUND_MASK ); +if (tmp != cmd->convert_arg) + err++; +if (cmd->scan_begin_src ==TRIG_TIMER && + cmd->scan_begin_arg < + cmd->convert_arg * cmd->scan_end_arg) { + cmd->scan_begin_arg = + cmd->convert_arg * cmd->scan_end_arg; + err++; + } } -/* Restart RPS program at its beginning. */ - *pRPS++ =RPS_JUMP ;/* Branch to start of RPS program. */ - *pRPS++ = (uint32_t ) devpriv->RPSBuf.PhysicalBase; -/* End of RPS program build */ +if (err) +return 4 ; + +return 0 ; } -/* TO COMPLETE, IF NECESSARY */ -static int s626_ai_insn_config (struct comedi_device *dev, -struct comedi_subdevice *s, -struct comedi_insn *insn,unsigned int *data) +static int s626_ai_cancel (struct comedi_device *dev,struct comedi_subdevice *s) { +/* Stop RPS program in case it is currently running. */ +MC_DISABLE (P_MC1 ,MC1_ERPS1 ); -return -EINVAL ; -} - -/* static int s626_ai_rinsn(struct comedi_device *dev,struct comedi_subdevice *s,struct comedi_insn *insn,unsigned int *data) */ -/* { */ -/* register uint8_t i; */ -/* register int32_t *readaddr; */ +/* disable master interrupt */ +writel (0 , devpriv->base_addr +P_IER ); -/* DEBUG("as626_ai_rinsn: ai_rinsn enter\n"); */ + devpriv->ai_cmd_running =0 ; -/* Trigger ADC scan loop start by setting RPS Signal 0. */ -/* MC_ENABLE( P_MC2, MC2_ADC_RPS ); */ +return 0 ; +} -/* Wait until ADC scan loop is finished (RPS Signal 0 reset). */ -/* while ( MC_TEST( P_MC2, MC2_ADC_RPS ) ); */ +/* This function doesn't require a particular form, this is just what +* happens to be used in some of the drivers. It should convert ns +* nanoseconds to a counter value suitable for programming the device. +* Also, it should adjust ns so that it cooresponds to the actual time +* that the device will use. */ +static int s626_ns_to_timer (int *nanosec,int round_mode) +{ +int divider, base; -/* Init ptr to DMA buffer that holds new ADC data. We skip the -* first uint16_t in the buffer because it contains junk data from -* the final ADC of the previous poll list scan. -*/ -/* readaddr = (uint32_t *)devpriv->ANABuf.LogicalBase + 1; */ + base =500 ;/* 2MHz internal clock */ -/* Convert ADC data to 16-bit integer values and copy to application buffer. */ -/* for ( i = 0; i < devpriv->AdcItems; i++ ) { */ -/* *data = s626_ai_reg_to_uint( *readaddr++ ); */ -/* DEBUG("s626_ai_rinsn: data %d\n",*data); */ -/* data++; */ -/* } */ +switch (round_mode) { +case TRIG_ROUND_NEAREST : +default : + divider = (*nanosec + base /2 ) / base; +break ; +case TRIG_ROUND_DOWN : + divider = (*nanosec) / base; +break ; +case TRIG_ROUND_UP : + divider = (*nanosec + base -1 ) / base; +break ; + } -/* DEBUG("s626_ai_rinsn: ai_rinsn escape\n"); */ -/* return i; */ -/* } */ + *nanosec = base * divider; +return divider -1 ; +} -static int s626_ai_insn_read (struct comedi_device *dev, -struct comedi_subdevice *s, -struct comedi_insn *insn,unsigned int *data) +static int s626_ao_winsn (struct comedi_device *dev,struct comedi_subdevice *s, +struct comedi_insn *insn,unsigned int *data) { + +int i;uint16_t chan =CR_CHAN (insn->chanspec); -uint16_t range =CR_RANGE (insn->chanspec); -uint16_t AdcSpec =0 ; -uint32_t GpioImage; -int n; +int16_t dacdata; -/* interrupt call test */ -/* writel(IRQ_GPIO3,devpriv->base_addr+P_PSR); */ -/* Writing a logical 1 into any of the RPS_PSR bits causes the -* corresponding interrupt to be generated if enabled -*/ - -DEBUG ("s626_ai_insn_read: entering\n" ); - -/* Convert application's ADC specification into form -* appropriate for register programming. -*/ -if (range ==0 ) - AdcSpec = (chan <<8 ) | (GSEL_BIPOLAR5V ); -else - AdcSpec = (chan <<8 ) | (GSEL_BIPOLAR10V ); +for (i =0 ; i < insn->n; i++) { + dacdata = (int16_t ) data[i]; + devpriv->ao_readback[CR_CHAN (insn->chanspec)] = data[i]; + dacdata -= (0x1fff ); -/* Switch ADC analog gain. */ -DEBIwrite (dev,LP_GSEL , AdcSpec);/* Set gain. */ +SetDAC (dev, chan, dacdata); + } -/* Select ADC analog input channel. */ -DEBIwrite (dev,LP_ISEL , AdcSpec);/* Select channel. */ +return i; +} -for (n =0 ; n < insn->n; n++) { +static int s626_ao_rinsn (struct comedi_device *dev,struct comedi_subdevice *s, +struct comedi_insn *insn,unsigned int *data) +{ +int i; -/* Delay 10 microseconds for analog input settling. */ -udelay (10 ); +for (i =0 ; i < insn->n; i++) + data[i] = devpriv->ao_readback[CR_CHAN (insn->chanspec)]; -/* Start ADC by pulsing GPIO1 low. */ - GpioImage =RR7146 (P_GPIO ); -/* Assert ADC Start command */ -WR7146 (P_GPIO , GpioImage & ~GPIO1_HI ); -/* and stretch it out. */ -WR7146 (P_GPIO , GpioImage & ~GPIO1_HI ); -WR7146 (P_GPIO , GpioImage & ~GPIO1_HI ); -/* Negate ADC Start command. */ -WR7146 (P_GPIO , GpioImage |GPIO1_HI ); +return i; +} -/* Wait for ADC to complete (GPIO2 is asserted high when */ -/* ADC not busy) and for data from previous conversion to */ -/* shift into FB BUFFER 1 register. */ +/* *************** DIGITAL I/O FUNCTIONS *************** +* All DIO functions address a group of DIO channels by means of +* "group" argument. group may be 0, 1 or 2, which correspond to DIO +* ports A, B and C, respectively. +*/ -/* Wait for ADC done. */ -while (!(RR7146 (P_PSR ) &PSR_GPIO2 )) - ; +static void s626_dio_init (struct comedi_device *dev) +{ +uint16_t group; +struct comedi_subdevice *s; -/* Fetch ADC data. */ -if (n !=0 ) - data[n -1 ] =s626_ai_reg_to_uint (RR7146 (P_FB_BUFFER1 )); +/* Prepare to treat writes to WRCapSel as capture disables. */ +DEBIwrite (dev,LP_MISC1 ,MISC1_NOEDCAP ); -/* Allow the ADC to stabilize for 4 microseconds before -* starting the next (final) conversion. This delay is -* necessary to allow sufficient time between last -* conversion finished and the start of the next -* conversion. Without this delay, the last conversion's -* data value is sometimes set to the previous -* conversion's data value. -*/ -udelay (4 ); +/* For each group of sixteen channels ... */ +for (group =0 ; group <S626_DIO_BANKS ; group++) { + s = dev->subdevices +2 + group; +DEBIwrite (dev, diopriv->WRIntSel,0 );/* Disable all interrupts. */ +DEBIwrite (dev, diopriv->WRCapSel,0xFFFF );/* Disable all event */ +/* captures. */ +DEBIwrite (dev, diopriv->WREdgSel,0 );/* Init all DIOs to */ +/* default edge */ +/* polarity. */ +DEBIwrite (dev, diopriv->WRDOut,0 );/* Program all outputs */ +/* to inactive state. */ } +DEBUG ("s626_dio_init: DIO initialized\n" ); +} -/* Start a dummy conversion to cause the data from the -* previous conversion to be shifted in. */ - GpioImage =RR7146 (P_GPIO ); - -/* Assert ADC Start command */ -WR7146 (P_GPIO , GpioImage & ~GPIO1_HI ); -/* and stretch it out. */ -WR7146 (P_GPIO , GpioImage & ~GPIO1_HI ); -WR7146 (P_GPIO , GpioImage & ~GPIO1_HI ); -/* Negate ADC Start command. */ -WR7146 (P_GPIO , GpioImage |GPIO1_HI ); - -/* Wait for the data to arrive in FB BUFFER 1 register. */ +/* DIO devices are slightly special. Although it is possible to +* implement the insn_read/insn_write interface, it is much more +* useful to applications if you implement the insn_bits interface. +* This allows packed reading/writing of the DIO channels. The comedi +* core can convert between insn_bits and insn_read/write */ -/* Wait for ADC done. */ -while (!(RR7146 (P_PSR ) &PSR_GPIO2 )) - ; +static int s626_dio_insn_bits (struct comedi_device *dev, +struct comedi_subdevice *s, +struct comedi_insn *insn,unsigned int *data) +{ +/* +* The insn data consists of a mask in data[0] and the new data in +* data[1]. The mask defines which bits we are concerning about. +* The new data must be anded with the mask. Each channel +* corresponds to a bit. +*/ +if (data[0 ]) { +/* Check if requested ports are configured for output */ +if ((s->io_bits & data[0 ]) != data[0 ]) +return -EIO ; -/* Fetch ADC data from audio interface's input shift register. */ + s->state &= ~data[0 ]; + s->state |= data[0 ] & data[1 ]; -/* Fetch ADC data. */ -if (n !=0 ) - data[n -1 ] =s626_ai_reg_to_uint (RR7146 (P_FB_BUFFER1 )); +/* Write out the new digital output lines */ -DEBUG ("s626_ai_insn_read: samples %d, data %d\n" , n, data[n -1 ]); +DEBIwrite (dev, diopriv->WRDOut, s->state); + } + data[1 ] =DEBIread (dev, diopriv->RDDIn); -return n; +return insn->n; } -static int s626_ai_load_polllist (uint8_t *ppl,struct comedi_cmd *cmd) +static int s626_dio_insn_config (struct comedi_device *dev, +struct comedi_subdevice *s, +struct comedi_insn *insn,unsigned int *data) { -int n; - -for (n =0 ; n < cmd->chanlist_len; n++) { -if (CR_RANGE ((cmd->chanlist)[n]) ==0 ) - ppl[n] = (CR_CHAN ((cmd->chanlist)[n])) | (RANGE_5V ); -else - ppl[n] = (CR_CHAN ((cmd->chanlist)[n])) | (RANGE_10V ); +switch (data[0 ]) { +case INSN_CONFIG_DIO_QUERY : + data[1 ] = + (s-> + io_bits & (1 <<CR_CHAN (insn->chanspec))) ?COMEDI_OUTPUT : +COMEDI_INPUT ; +return insn->n; +break ; +case COMEDI_INPUT : + s->io_bits &= ~(1 <<CR_CHAN (insn->chanspec)); +break ; +case COMEDI_OUTPUT : + s->io_bits |=1 <<CR_CHAN (insn->chanspec); +break ; +default : +return -EINVAL ; +break ; } -if (n !=0 ) - ppl[n -1 ] |=EOPL ; +DEBIwrite (dev, diopriv->WRDOut, s->io_bits); -return n; +return 1 ; } -static int s626_ai_inttrig (struct comedi_device *dev, -struct comedi_subdevice *s,unsigned int trignum) +static int s626_dio_set_irq (struct comedi_device *dev,unsigned int chan) { -if (trignum !=0 ) -return -EINVAL ; +unsigned int group; +unsigned int bitmask; +unsigned int status; -DEBUG ("s626_ai_inttrig: trigger adc start..." ); +/* select dio bank */ + group = chan /16 ; + bitmask =1 << (chan - (16 * group)); +DEBUG ("s626_dio_set_irq: enable interrupt on dio channel %d group %d\n" , + chan - (16 * group), group); -/* Start executing the RPS program. */ -MC_ENABLE (P_MC1 ,MC1_ERPS1 ); +/* set channel to capture positive edge */ + status =DEBIread (dev, + ((struct dio_private *)(dev->subdevices +2 + + group)->private)->RDEdgSel); +DEBIwrite (dev, + ((struct dio_private *)(dev->subdevices +2 + + group)->private)->WREdgSel, + bitmask | status); - s->async->inttrig =NULL ; +/* enable interrupt on selected channel */ + status =DEBIread (dev, + ((struct dio_private *)(dev->subdevices +2 + + group)->private)->RDIntSel); +DEBIwrite (dev, + ((struct dio_private *)(dev->subdevices +2 + + group)->private)->WRIntSel, + bitmask | status); -DEBUG (" done\n" ); +/* enable edge capture write command */ +DEBIwrite (dev,LP_MISC1 ,MISC1_EDCAP ); -return 1 ; +/* enable edge capture on selected channel */ + status =DEBIread (dev, + ((struct dio_private *)(dev->subdevices +2 + + group)->private)->RDCapSel); +DEBIwrite (dev, + ((struct dio_private *)(dev->subdevices +2 + + group)->private)->WRCapSel, + bitmask | status); + +return 0 ; } -/* TO COMPLETE */ -static int s626_ai_cmd (struct comedi_device *dev,struct comedi_subdevice *s) +static int s626_dio_reset_irq (struct comedi_device *dev,unsigned int group, +unsigned int mask) { +DEBUG + ("s626_dio_reset_irq: disable interrupt on dio channel %d group %d\n" , + mask, group); -uint8_t ppl[16 ]; -struct comedi_cmd *cmd = &s->async->cmd; -struct enc_private *k; -int tick; +/* disable edge capture write command */ +DEBIwrite (dev,LP_MISC1 ,MISC1_NOEDCAP ); -DEBUG ("s626_ai_cmd: entering command function\n" ); +/* enable edge capture on selected channel */ +DEBIwrite (dev, + ((struct dio_private *)(dev->subdevices +2 + + group)->private)->WRCapSel, mask); -if (devpriv->ai_cmd_running) { -printk (KERN_ERR "s626_ai_cmd: Another ai_cmd is running %d\n" , - dev->minor); -return -EBUSY ; - } -/* disable interrupt */ -writel (0 , devpriv->base_addr +P_IER ); +return 0 ; +} -/* clear interrupt request */ -writel (IRQ_RPS1 |IRQ_GPIO3 , devpriv->base_addr +P_ISR ); +static int s626_dio_clear_irq (struct comedi_device *dev) +{ +unsigned int group; -/* clear any pending interrupt */ -s626_dio_clear_irq (dev); -/* s626_enc_clear_irq(dev); */ +/* disable edge capture write command */ +DEBIwrite (dev,LP_MISC1 ,MISC1_NOEDCAP ); -/* reset ai_cmd_running flag */ - devpriv->ai_cmd_running =0 ; - -/* test if cmd is valid */ -if (cmd ==NULL ) { -DEBUG ("s626_ai_cmd: NULL command\n" ); -return -EINVAL ; - }else { -DEBUG ("s626_ai_cmd: command received!!!\n" ); - } - -if (dev->irq ==0 ) { -comedi_error (dev, -"s626_ai_cmd: cannot run command without an irq" ); -return -EIO ; +for (group =0 ; group <S626_DIO_BANKS ; group++) { +/* clear pending events and interrupt */ +DEBIwrite (dev, + ((struct dio_private *)(dev->subdevices +2 + + group)->private)->WRCapSel, +0xffff ); } -s626_ai_load_polllist (ppl, cmd); - devpriv->ai_cmd_running =1 ; - devpriv->ai_convert_count =0 ; - -switch (cmd->scan_begin_src) { -case TRIG_FOLLOW : -break ; -case TRIG_TIMER : -/* set a conter to generate adc trigger at scan_begin_arg interval */ - k = &encpriv[5 ]; - tick =s626_ns_to_timer ((int *)&cmd->scan_begin_arg, - cmd->flags &TRIG_ROUND_MASK ); - -/* load timer value and enable interrupt */ -s626_timer_load (dev, k, tick); - k->SetEnable (dev, k,CLKENAB_ALWAYS ); - -DEBUG ("s626_ai_cmd: scan trigger timer is set with value %d\n" , - tick); +return 0 ; +} -break ; -case TRIG_EXT : -/* set the digital line and interrupt for scan trigger */ -if (cmd->start_src !=TRIG_EXT ) -s626_dio_set_irq (dev, cmd->scan_begin_arg); +/* Now this function initializes the value of the counter (data[0]) +and set the subdevice. To complete with trigger and interrupt +configuration */ +static int s626_enc_insn_config (struct comedi_device *dev, +struct comedi_subdevice *s, +struct comedi_insn *insn,unsigned int *data) +{ +uint16_t Setup = (LOADSRC_INDX <<BF_LOADSRC ) |/* Preload upon */ +/* index. */ + (INDXSRC_SOFT <<BF_INDXSRC ) |/* Disable hardware index. */ + (CLKSRC_COUNTER <<BF_CLKSRC ) |/* Operating mode is Counter. */ + (CLKPOL_POS <<BF_CLKPOL ) |/* Active high clock. */ +/* ( CNTDIR_UP << BF_CLKPOL ) | // Count direction is Down. */ + (CLKMULT_1X <<BF_CLKMULT ) |/* Clock multiplier is 1x. */ + (CLKENAB_INDEX <<BF_CLKENAB ); +/* uint16_t DisableIntSrc=TRUE; */ +/* uint32_t Preloadvalue; //Counter initial value */ +uint16_t valueSrclatch =LATCHSRC_AB_READ ; +uint16_t enab =CLKENAB_ALWAYS ; +struct enc_private *k = &encpriv[CR_CHAN (insn->chanspec)]; -DEBUG ("s626_ai_cmd: External scan trigger is set!!!\n" ); +DEBUG ("s626_enc_insn_config: encoder config\n" ); -break ; - } +/* (data==NULL) ? (Preloadvalue=0) : (Preloadvalue=data[0]); */ -switch (cmd->convert_src) { -case TRIG_NOW : -break ; -case TRIG_TIMER : -/* set a conter to generate adc trigger at convert_arg interval */ - k = &encpriv[4 ]; - tick =s626_ns_to_timer ((int *)&cmd->convert_arg, - cmd->flags &TRIG_ROUND_MASK ); + k->SetMode (dev, k, Setup, TRUE); +Preload (dev, k, *(insn->data)); + k->PulseIndex (dev, k); +SetLatchSource (dev, k, valueSrclatch); + k->SetEnable (dev, k, (uint16_t ) (enab !=0 )); -/* load timer value and enable interrupt */ -s626_timer_load (dev, k, tick); - k->SetEnable (dev, k,CLKENAB_INDEX ); +return insn->n; +} -DEBUG - ("s626_ai_cmd: convert trigger timer is set with value %d\n" , - tick); -break ; -case TRIG_EXT : -/* set the digital line and interrupt for convert trigger */ -if (cmd->scan_begin_src !=TRIG_EXT - && cmd->start_src ==TRIG_EXT ) -s626_dio_set_irq (dev, cmd->convert_arg); +static int s626_enc_insn_read (struct comedi_device *dev, +struct comedi_subdevice *s, +struct comedi_insn *insn,unsigned int *data) +{ -DEBUG ("s626_ai_cmd: External convert trigger is set!!!\n" ); +int n; +struct enc_private *k = &encpriv[CR_CHAN (insn->chanspec)]; -break ; - } +DEBUG ("s626_enc_insn_read: encoder read channel %d\n" , +CR_CHAN (insn->chanspec)); -switch (cmd->stop_src) { -case TRIG_COUNT : -/* data arrives as one packet */ - devpriv->ai_sample_count = cmd->stop_arg; - devpriv->ai_continous =0 ; -break ; -case TRIG_NONE : -/* continous acquisition */ - devpriv->ai_continous =1 ; - devpriv->ai_sample_count =0 ; -break ; - } +for (n =0 ; n < insn->n; n++) + data[n] =ReadLatch (dev, k); -ResetADC (dev, ppl); +DEBUG ("s626_enc_insn_read: encoder sample %d\n" , data[n]); -switch (cmd->start_src) { -case TRIG_NOW : -/* Trigger ADC scan loop start by setting RPS Signal 0. */ -/* MC_ENABLE( P_MC2, MC2_ADC_RPS ); */ +return n; +} -/* Start executing the RPS program. */ -MC_ENABLE (P_MC1 ,MC1_ERPS1 ); +static int s626_enc_insn_write (struct comedi_device *dev, +struct comedi_subdevice *s, +struct comedi_insn *insn,unsigned int *data) +{ -DEBUG ("s626_ai_cmd: ADC triggered\n" ); - s->async->inttrig =NULL ; -break ; -case TRIG_EXT : -/* configure DIO channel for acquisition trigger */ -s626_dio_set_irq (dev, cmd->start_arg); +struct enc_private *k = &encpriv[CR_CHAN (insn->chanspec)]; -DEBUG ("s626_ai_cmd: External start trigger is set!!!\n" ); +DEBUG ("s626_enc_insn_write: encoder write channel %d\n" , +CR_CHAN (insn->chanspec)); - s->async->inttrig =NULL ; -break ; -case TRIG_INT : - s->async->inttrig = s626_ai_inttrig; -break ; - } +/* Set the preload register */ +Preload (dev, k, data[0 ]); -/* enable interrupt */ -writel (IRQ_GPIO3 |IRQ_RPS1 , devpriv->base_addr +P_IER ); +/* Software index pulse forces the preload register to load */ +/* into the counter */ + k->SetLoadTrig (dev, k,0 ); + k->PulseIndex (dev, k); + k->SetLoadTrig (dev, k,2 ); -DEBUG ("s626_ai_cmd: command function terminated\n" ); +DEBUG ("s626_enc_insn_write: End encoder write\n" ); -return 0 ; +return 1 ; } -static int s626_ai_cmdtest (struct comedi_device *dev, -struct comedi_subdevice *s,struct comedi_cmd *cmd) +static void s626_timer_load (struct comedi_device *dev,struct enc_private *k, +int tick) { -int err =0 ; -int tmp; +uint16_t Setup = (LOADSRC_INDX <<BF_LOADSRC ) |/* Preload upon */ +/* index. */ + (INDXSRC_SOFT <<BF_INDXSRC ) |/* Disable hardware index. */ + (CLKSRC_TIMER <<BF_CLKSRC ) |/* Operating mode is Timer. */ + (CLKPOL_POS <<BF_CLKPOL ) |/* Active high clock. */ + (CNTDIR_DOWN <<BF_CLKPOL ) |/* Count direction is Down. */ + (CLKMULT_1X <<BF_CLKMULT ) |/* Clock multiplier is 1x. */ + (CLKENAB_INDEX <<BF_CLKENAB ); +uint16_t valueSrclatch =LATCHSRC_A_INDXA ; +/* uint16_t enab=CLKENAB_ALWAYS; */ -/* cmdtest tests a particular command to see if it is valid. Using -* the cmdtest ioctl, a user can create a valid cmd and then have it -* executes by the cmd ioctl. -* -* cmdtest returns 1,2,3,4 or 0, depending on which tests the -* command passes. */ + k->SetMode (dev, k, Setup, FALSE); -/* step 1: make sure trigger sources are trivially valid */ +/* Set the preload register */ +Preload (dev, k, tick); - tmp = cmd->start_src; - cmd->start_src &=TRIG_NOW |TRIG_INT |TRIG_EXT ; -if (!cmd->start_src || tmp != cmd->start_src) - err++; +/* Software index pulse forces the preload register to load */ +/* into the counter */ + k->SetLoadTrig (dev, k,0 ); + k->PulseIndex (dev, k); - tmp = cmd->scan_begin_src; - cmd->scan_begin_src &=TRIG_TIMER |TRIG_EXT |TRIG_FOLLOW ; -if (!cmd->scan_begin_src || tmp != cmd->scan_begin_src) - err++; +/* set reload on counter overflow */ + k->SetLoadTrig (dev, k,1 ); - tmp = cmd->convert_src; - cmd->convert_src &=TRIG_TIMER |TRIG_EXT |TRIG_NOW ; -if (!cmd->convert_src || tmp != cmd->convert_src) - err++; +/* set interrupt on overflow */ + k->SetIntSrc (dev, k,INTSRC_OVER ); - tmp = cmd->scan_end_src; - cmd->scan_end_src &=TRIG_COUNT ; -if (!cmd->scan_end_src || tmp != cmd->scan_end_src) - err++; +SetLatchSource (dev, k, valueSrclatch); +/* k->SetEnable(dev,k,(uint16_t)(enab != 0)); */ +} - tmp = cmd->stop_src; - cmd->stop_src &=TRIG_COUNT |TRIG_NONE ; -if (!cmd->stop_src || tmp != cmd->stop_src) - err++; +/* *********** DAC FUNCTIONS *********** */ -if (err) -return 1 ; +/* Slot 0 base settings. */ +#define VECT0 (XSD2 | RSD3 | SIB_A2) +/* Slot 0 always shifts in 0xFF and store it to FB_BUFFER2. */ -/* step 2: make sure trigger sources are unique and mutually -compatible */ +/* TrimDac LogicalChan-to-PhysicalChan mapping table. */ +static uint8_t trimchan[] = {10 ,9 ,8 ,3 ,2 ,7 ,6 ,1 ,0 ,5 ,4 }; -/* note that mutual compatibility is not an issue here */ -if (cmd->scan_begin_src !=TRIG_TIMER && - cmd->scan_begin_src !=TRIG_EXT - && cmd->scan_begin_src !=TRIG_FOLLOW ) - err++; -if (cmd->convert_src !=TRIG_TIMER && - cmd->convert_src !=TRIG_EXT && cmd->convert_src !=TRIG_NOW ) - err++; -if (cmd->stop_src !=TRIG_COUNT && cmd->stop_src !=TRIG_NONE ) - err++; +/* TrimDac LogicalChan-to-EepromAdrs mapping table. */ +static uint8_t trimadrs[] = {0x40 ,0x41 ,0x42 ,0x50 ,0x51 ,0x52 ,0x53 ,0x60 ,0x61 ,0x62 ,0x63 }; -if (err) -return 2 ; +static void LoadTrimDACs (struct comedi_device *dev) +{ + registeruint8_t i; -/* step 3: make sure arguments are trivially compatible */ +/* Copy TrimDac setpoint values from EEPROM to TrimDacs. */ +for (i =0 ; i <ARRAY_SIZE (trimchan); i++) +WriteTrimDAC (dev, i,I2Cread (dev, trimadrs[i])); +} -if (cmd->start_src !=TRIG_EXT && cmd->start_arg !=0 ) { - cmd->start_arg =0 ; - err++; - } - -if (cmd->start_src ==TRIG_EXT && cmd->start_arg >39 ) { - cmd->start_arg =39 ; - err++; - } - -if (cmd->scan_begin_src ==TRIG_EXT && cmd->scan_begin_arg >39 ) { - cmd->scan_begin_arg =39 ; - err++; - } - -if (cmd->convert_src ==TRIG_EXT && cmd->convert_arg >39 ) { - cmd->convert_arg =39 ; - err++; - } -#define MAX_SPEED 200000/* in nanoseconds */ -#define MIN_SPEED 2000000000/* in nanoseconds */ - -if (cmd->scan_begin_src ==TRIG_TIMER ) { -if (cmd->scan_begin_arg <MAX_SPEED ) { - cmd->scan_begin_arg =MAX_SPEED ; - err++; - } -if (cmd->scan_begin_arg >MIN_SPEED ) { - cmd->scan_begin_arg =MIN_SPEED ; - err++; - } - }else { -/* external trigger */ -/* should be level/edge, hi/lo specification here */ -/* should specify multiple external triggers */ -/* if(cmd->scan_begin_arg>9){ */ -/* cmd->scan_begin_arg=9; */ -/* err++; */ -/* } */ - } -if (cmd->convert_src ==TRIG_TIMER ) { -if (cmd->convert_arg <MAX_SPEED ) { - cmd->convert_arg =MAX_SPEED ; - err++; - } -if (cmd->convert_arg >MIN_SPEED ) { - cmd->convert_arg =MIN_SPEED ; - err++; - } - }else { -/* external trigger */ -/* see above */ -/* if(cmd->convert_arg>9){ */ -/* cmd->convert_arg=9; */ -/* err++; */ -/* } */ - } +static void WriteTrimDAC (struct comedi_device *dev,uint8_t LogicalChan, +uint8_t DacData) +{ +uint32_t chan; -if (cmd->scan_end_arg != cmd->chanlist_len) { - cmd->scan_end_arg = cmd->chanlist_len; - err++; - } -if (cmd->stop_src ==TRIG_COUNT ) { -if (cmd->stop_arg >0x00ffffff ) { - cmd->stop_arg =0x00ffffff ; - err++; - } - }else { -/* TRIG_NONE */ -if (cmd->stop_arg !=0 ) { - cmd->stop_arg =0 ; - err++; - } - } +/* Save the new setpoint in case the application needs to read it back later. */ + devpriv->TrimSetpoint[LogicalChan] = (uint8_t ) DacData; -if (err) -return 3 ; +/* Map logical channel number to physical channel number. */ + chan = (uint32_t ) trimchan[LogicalChan]; -/* step 4: fix up any arguments */ +/* Set up TSL2 records for TrimDac write operation. All slots shift +* 0xFF in from pulled-up SD3 so that the end of the slot sequence +* can be detected. +*/ -if (cmd->scan_begin_src ==TRIG_TIMER ) { - tmp = cmd->scan_begin_arg; -s626_ns_to_timer ((int *)&cmd->scan_begin_arg, - cmd->flags &TRIG_ROUND_MASK ); -if (tmp != cmd->scan_begin_arg) - err++; - } -if (cmd->convert_src ==TRIG_TIMER ) { - tmp = cmd->convert_arg; -s626_ns_to_timer ((int *)&cmd->convert_arg, - cmd->flags &TRIG_ROUND_MASK ); -if (tmp != cmd->convert_arg) - err++; -if (cmd->scan_begin_src ==TRIG_TIMER && - cmd->scan_begin_arg < - cmd->convert_arg * cmd->scan_end_arg) { - cmd->scan_begin_arg = - cmd->convert_arg * cmd->scan_end_arg; - err++; - } - } +SETVECT (2 ,XSD2 |XFIFO_1 |WS3 ); +/* Slot 2: Send high uint8_t to target TrimDac. */ +SETVECT (3 ,XSD2 |XFIFO_0 |WS3 ); +/* Slot 3: Send low uint8_t to target TrimDac. */ +SETVECT (4 ,XSD2 |XFIFO_3 |WS1 ); +/* Slot 4: Send NOP high uint8_t to DAC0 to keep clock running. */ +SETVECT (5 ,XSD2 |XFIFO_2 |WS1 |EOS ); +/* Slot 5: Send NOP low uint8_t to DAC0. */ -if (err) -return 4 ; +/* Construct and transmit target DAC's serial packet: +* ( 0000 AAAA ), ( DDDD DDDD ),( 0x00 ),( 0x00 ) where A<3:0> is the +* DAC channel's address, and D<7:0> is the DAC setpoint. Append a +* WORD value (that writes a channel 0 NOP command to a non-existent +* main DAC channel) that serves to keep the clock running after the +* packet has been sent to the target DAC. +*/ -return 0 ; +/* Address the DAC channel within the trimdac device. */ +SendDAC (dev, ((uint32_t ) chan <<8 ) + | (uint32_t ) DacData);/* Include DAC setpoint data. */ } -static int s626_ai_cancel (struct comedi_device *dev,struct comedi_subdevice *s) -{ -/* Stop RPS program in case it is currently running. */ -MC_DISABLE (P_MC1 ,MC1_ERPS1 ); - -/* disable master interrupt */ -writel (0 , devpriv->base_addr +P_IER ); +/* ************** EEPROM ACCESS FUNCTIONS ************** */ +/* Read uint8_t from EEPROM. */ - devpriv->ai_cmd_running =0 ; +static uint8_t I2Cread (struct comedi_device *dev,uint8_t addr) +{ +uint8_t rtnval; -return 0 ; -} +/* Send EEPROM target address. */ +if (I2Chandshake (dev,I2C_B2 (I2C_ATTRSTART ,I2CW ) +/* Byte2 = I2C command: write to I2C EEPROM device. */ + |I2C_B1 (I2C_ATTRSTOP , addr) +/* Byte1 = EEPROM internal target address. */ + |I2C_B0 (I2C_ATTRNOP ,0 ))) {/* Byte0 = Not sent. */ +/* Abort function and declare error if handshake failed. */ +DEBUG ("I2Cread: error handshake I2Cread a\n" ); +return 0 ; + } +/* Execute EEPROM read. */ +if (I2Chandshake (dev,I2C_B2 (I2C_ATTRSTART ,I2CR ) -/* This function doesn't require a particular form, this is just what -* happens to be used in some of the drivers. It should convert ns -* nanoseconds to a counter value suitable for programming the device. -* Also, it should adjust ns so that it cooresponds to the actual time -* that the device will use. */ -static int s626_ns_to_timer (int *nanosec,int round_mode) -{ -int divider, base; +/* Byte2 = I2C */ +/* command: read */ +/* from I2C EEPROM */ +/* device. */ + |I2C_B1 (I2C_ATTRSTOP ,0 ) - base =500 ;/* 2MHz internal clock */ +/* Byte1 receives */ +/* uint8_t from */ +/* EEPROM. */ + |I2C_B0 (I2C_ATTRNOP ,0 ))) {/* Byte0 = Not sent. */ -switch (round_mode) { -case TRIG_ROUND_NEAREST : -default : - divider = (*nanosec + base /2 ) / base; -break ; -case TRIG_ROUND_DOWN : - divider = (*nanosec) / base; -break ; -case TRIG_ROUND_UP : - divider = (*nanosec + base -1 ) / base; -break ; +/* Abort function and declare error if handshake failed. */ +DEBUG ("I2Cread: error handshake I2Cread b\n" ); +return 0 ; } - - *nanosec = base * divider; -return divider -1 ; +/* Return copy of EEPROM value. */ + rtnval = (uint8_t ) (RR7146 (P_I2CCTRL ) >>16 ); +return rtnval; } -static int s626_ao_winsn (struct comedi_device *dev,struct comedi_subdevice *s, -struct comedi_insn *insn,unsigned int *data) +static uint32_t I2Chandshake (struct comedi_device *dev,uint32_t val) { +/* Write I2C command to I2C Transfer Control shadow register. */ +WR7146 (P_I2CCTRL , val); -int i; -uint16_t chan =CR_CHAN (insn->chanspec); -int16_t dacdata; - -for (i =0 ; i < insn->n; i++) { - dacdata = (int16_t ) data[i]; - devpriv->ao_readback[CR_CHAN (insn->chanspec)] = data[i]; - dacdata -= (0x1fff ); - -SetDAC (dev, chan, dacdata); - } +/* Upload I2C shadow registers into working registers and wait for */ +/* upload confirmation. */ -return i; -} +MC_ENABLE (P_MC2 ,MC2_UPLD_IIC ); +while (!MC_TEST (P_MC2 ,MC2_UPLD_IIC )) + ; -static int s626_ao_rinsn (struct comedi_device *dev,struct comedi_subdevice *s, -struct comedi_insn *insn,unsigned int *data) -{ -int i; +/* Wait until I2C bus transfer is finished or an error occurs. */ +while ((RR7146 (P_I2CCTRL ) & (I2C_BUSY |I2C_ERR )) ==I2C_BUSY ) + ; -for (i =0 ; i < insn->n; i++) - data[i] = devpriv->ao_readback[CR_CHAN (insn->chanspec)]; +/* Return non-zero if I2C error occurred. */ +return RR7146 (P_I2CCTRL ) &I2C_ERR ; -return i; } -/* *************** DIGITAL I/O FUNCTIONS *************** -* All DIO functions address a group of DIO channels by means of -* "group" argument. group may be 0, 1 or 2, which correspond to DIO -* ports A, B and C, respectively. -*/ +/* Private helper function: Write setpoint to an application DAC channel. */ -static void s626_dio_init (struct comedi_device *dev) +static void SetDAC (struct comedi_device *dev,uint16_t chan,short dacdata) { -uint16_t group; -struct comedi_subdevice *s; + registeruint16_t signmask; + registeruint32_t WSImage; -/* Prepare to treat writes to WRCapSel as capture disables. */ -DEBIwrite (dev,LP_MISC1 ,MISC1_NOEDCAP ); +/* Adjust DAC data polarity and set up Polarity Control Register */ +/* image. */ + signmask =1 << chan; +if (dacdata <0 ) { + dacdata = -dacdata; + devpriv->Dacpol |= signmask; + }else + devpriv->Dacpol &= ~signmask; -/* For each group of sixteen channels ... */ -for (group =0 ; group <S626_DIO_BANKS ; group++) { - s = dev->subdevices +2 + group; -DEBIwrite (dev, diopriv->WRIntSel,0 );/* Disable all interrupts. */ -DEBIwrite (dev, diopriv->WRCapSel,0xFFFF );/* Disable all event */ -/* captures. */ -DEBIwrite (dev, diopriv->WREdgSel,0 );/* Init all DIOs to */ -/* default edge */ -/* polarity. */ -DEBIwrite (dev, diopriv->WRDOut,0 );/* Program all outputs */ -/* to inactive state. */ - } -DEBUG ("s626_dio_init: DIO initialized\n" ); -} - -/* DIO devices are slightly special. Although it is possible to -* implement the insn_read/insn_write interface, it is much more -* useful to applications if you implement the insn_bits interface. -* This allows packed reading/writing of the DIO channels. The comedi -* core can convert between insn_bits and insn_read/write */ +/* Limit DAC setpoint value to valid range. */ +if ((uint16_t ) dacdata >0x1FFF ) + dacdata =0x1FFF ; -static int s626_dio_insn_bits (struct comedi_device *dev, -struct comedi_subdevice *s, -struct comedi_insn *insn,unsigned int *data) -{ -/* -* The insn data consists of a mask in data[0] and the new data in -* data[1]. The mask defines which bits we are concerning about. -* The new data must be anded with the mask. Each channel -* corresponds to a bit. +/* Set up TSL2 records (aka "vectors") for DAC update. Vectors V2 +* and V3 transmit the setpoint to the target DAC. V4 and V5 send +* data to a non-existent TrimDac channel just to keep the clock +* running after sending data to the target DAC. This is necessary +* to eliminate the clock glitch that would otherwise occur at the +* end of the target DAC's serial data stream. When the sequence +* restarts at V0 (after executing V5), the gate array automatically +* disables gating for the DAC clock and all DAC chip selects. */ -if (data[0 ]) { -/* Check if requested ports are configured for output */ -if ((s->io_bits & data[0 ]) != data[0 ]) -return -EIO ; - s->state &= ~data[0 ]; - s->state |= data[0 ] & data[1 ]; - -/* Write out the new digital output lines */
Lines of this file are not shown. View the raw message.
The rest of this diff is not shown. View the raw message.
Signature · 1 line
1.7.11
Part of the diff is not shown here. View the raw message.