X-Git-Url: https://git.karo-electronics.de/?a=blobdiff_plain;f=drivers%2Fstaging%2Fcomedi%2Fdrivers%2Fdas08.c;h=700a40b23c5fe8e2f27f0e179905bf6c03bff143;hb=57334a30c8da966e4470572d3096873e26c66076;hp=73f4c8dbbde3ff926eba8e3280d7dc72a985aaa1;hpb=7dedcca09e9a751fd14fdb8e9882d675b23b2c0e;p=karo-tx-linux.git diff --git a/drivers/staging/comedi/drivers/das08.c b/drivers/staging/comedi/drivers/das08.c index 73f4c8dbbde3..700a40b23c5f 100644 --- a/drivers/staging/comedi/drivers/das08.c +++ b/drivers/staging/comedi/drivers/das08.c @@ -1,21 +1,21 @@ /* - * comedi/drivers/das08.c - * comedi module for common DAS08 support (used by ISA/PCI/PCMCIA drivers) + * comedi/drivers/das08.c + * comedi module for common DAS08 support (used by ISA/PCI/PCMCIA drivers) * - * COMEDI - Linux Control and Measurement Device Interface - * Copyright (C) 2000 David A. Schleef - * Copyright (C) 2001,2002,2003 Frank Mori Hess - * Copyright (C) 2004 Salvador E. Tropea + * COMEDI - Linux Control and Measurement Device Interface + * Copyright (C) 2000 David A. Schleef + * Copyright (C) 2001,2002,2003 Frank Mori Hess + * Copyright (C) 2004 Salvador E. Tropea * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. */ #include @@ -27,85 +27,74 @@ #include "das08.h" /* - cio-das08.pdf - - "isa-das08" - - 0 a/d bits 0-3 start 8 bit - 1 a/d bits 4-11 start 12 bit - 2 eoc, ip1-3, irq, mux op1-4, inte, mux - 3 unused unused - 4567 8254 - 89ab 8255 - - requires hard-wiring for async ai - -*/ - -#define DAS08_LSB 0 -#define DAS08_MSB 1 -#define DAS08_TRIG_12BIT 1 -#define DAS08_STATUS 2 -#define DAS08_EOC (1<<7) -#define DAS08_IRQ (1<<3) -#define DAS08_IP(x) (((x)>>4)&0x7) -#define DAS08_CONTROL 2 -#define DAS08_MUX_MASK 0x7 -#define DAS08_MUX(x) ((x) & DAS08_MUX_MASK) -#define DAS08_INTE (1<<3) -#define DAS08_DO_MASK 0xf0 -#define DAS08_OP(x) (((x) << 4) & DAS08_DO_MASK) - + * Data format of DAS08_AI_LSB_REG and DAS08_AI_MSB_REG depends on + * 'ai_encoding' member of board structure: + * + * das08_encode12 : DATA[11..4] = MSB[7..0], DATA[3..0] = LSB[7..4]. + * das08_pcm_encode12 : DATA[11..8] = MSB[3..0], DATA[7..9] = LSB[7..0]. + * das08_encode16 : SIGN = MSB[7], MAGNITUDE[14..8] = MSB[6..0], + * MAGNITUDE[7..0] = LSB[7..0]. + * SIGN==0 for negative input, SIGN==1 for positive input. + * Note: when read a second time after conversion + * complete, MSB[7] is an "over-range" bit. + */ +#define DAS08_AI_LSB_REG 0x00 /* (R) AI least significant bits */ +#define DAS08_AI_MSB_REG 0x01 /* (R) AI most significant bits */ +#define DAS08_AI_TRIG_REG 0x01 /* (W) AI software trigger */ +#define DAS08_STATUS_REG 0x02 /* (R) status */ +#define DAS08_STATUS_AI_BUSY BIT(7) /* AI conversion in progress */ /* - cio-das08jr.pdf - - "das08/jr-ao" - - 0 a/d bits 0-3 unused - 1 a/d bits 4-11 start 12 bit - 2 eoc, mux mux - 3 di do - 4 unused ao0_lsb - 5 unused ao0_msb - 6 unused ao1_lsb - 7 unused ao1_msb - -*/ - -#define DAS08JR_DIO 3 -#define DAS08JR_AO_LSB(x) ((x) ? 6 : 4) -#define DAS08JR_AO_MSB(x) ((x) ? 7 : 5) + * The IRQ status bit is set to 1 by a rising edge on the external interrupt + * input (which may be jumpered to the pacer output). It is cleared by + * setting the INTE control bit to 0. Not present on "JR" boards. + */ +#define DAS08_STATUS_IRQ BIT(3) /* latched interrupt input */ +/* digital inputs (not "JR" boards) */ +#define DAS08_STATUS_DI(x) (((x) & 0x70) >> 4) +#define DAS08_CONTROL_REG 0x02 /* (W) control */ +/* + * Note: The AI multiplexor channel can also be read from status register using + * the same mask. + */ +#define DAS08_CONTROL_MUX_MASK 0x7 /* multiplexor channel mask */ +#define DAS08_CONTROL_MUX(x) ((x) & DAS08_CONTROL_MUX_MASK) /* mux channel */ +#define DAS08_CONTROL_INTE BIT(3) /* interrupt enable (not "JR" boards) */ +#define DAS08_CONTROL_DO_MASK 0xf0 /* digital outputs mask (not "JR") */ +/* digital outputs (not "JR" boards) */ +#define DAS08_CONTROL_DO(x) (((x) << 4) & DAS08_CONTROL_DO_MASK) +/* + * (R/W) programmable AI gain ("PGx" and "AOx" boards): + * + bits 3..0 (R/W) show/set the gain for the current AI mux channel + * + bits 6..4 (R) show the current AI mux channel + * + bit 7 (R) not unused + */ +#define DAS08_GAIN_REG 0x03 + +#define DAS08JR_DI_REG 0x03 /* (R) digital inputs ("JR" boards) */ +#define DAS08JR_DO_REG 0x03 /* (W) digital outputs ("JR" boards) */ +/* (W) analog output l.s.b. registers for 2 channels ("JR" boards) */ +#define DAS08JR_AO_LSB_REG(x) ((x) ? 0x06 : 0x04) +/* (W) analog output m.s.b. registers for 2 channels ("JR" boards) */ +#define DAS08JR_AO_MSB_REG(x) ((x) ? 0x07 : 0x05) +/* + * (R) update analog outputs ("JR" boards set for simultaneous output) + * (same register as digital inputs) + */ +#define DAS08JR_AO_UPDATE_REG 0x03 +/* (W) analog output l.s.b. registers for 2 channels ("AOx" boards) */ +#define DAS08AOX_AO_LSB_REG(x) ((x) ? 0x0a : 0x08) +/* (W) analog output m.s.b. registers for 2 channels ("AOx" boards) */ +#define DAS08AOX_AO_MSB_REG(x) ((x) ? 0x0b : 0x09) /* - cio-das08_aox.pdf - - "das08-aoh" - "das08-aol" - "das08-aom" - - 0 a/d bits 0-3 start 8 bit - 1 a/d bits 4-11 start 12 bit - 2 eoc, ip1-3, irq, mux op1-4, inte, mux - 3 mux, gain status gain control - 4567 8254 - 8 unused ao0_lsb - 9 unused ao0_msb - a unused ao1_lsb - b unused ao1_msb - 89ab - cdef 8255 -*/ - -#define DAS08AO_GAIN_CONTROL 3 -#define DAS08AO_GAIN_STATUS 3 - -#define DAS08AO_AO_LSB(x) ((x) ? 0xa : 8) -#define DAS08AO_AO_MSB(x) ((x) ? 0xb : 9) -#define DAS08AO_AO_UPDATE 8 + * (R) update analog outputs ("AOx" boards set for simultaneous output) + * (any of the analog output registers could be used for this) + */ +#define DAS08AOX_AO_UPDATE_REG 0x08 /* gainlist same as _pgx_ below */ -static const struct comedi_lrange range_das08_pgl = { +static const struct comedi_lrange das08_pgl_ai_range = { 9, { BIP_RANGE(10), BIP_RANGE(5), @@ -119,7 +108,7 @@ static const struct comedi_lrange range_das08_pgl = { } }; -static const struct comedi_lrange range_das08_pgh = { +static const struct comedi_lrange das08_pgh_ai_range = { 12, { BIP_RANGE(10), BIP_RANGE(5), @@ -136,7 +125,7 @@ static const struct comedi_lrange range_das08_pgh = { } }; -static const struct comedi_lrange range_das08_pgm = { +static const struct comedi_lrange das08_pgm_ai_range = { 9, { BIP_RANGE(10), BIP_RANGE(5), @@ -148,42 +137,28 @@ static const struct comedi_lrange range_das08_pgm = { UNI_RANGE(0.1), UNI_RANGE(0.01) } -}; /* - cio-das08jr.pdf - - "das08/jr-ao" - - 0 a/d bits 0-3 unused - 1 a/d bits 4-11 start 12 bit - 2 eoc, mux mux - 3 di do - 4 unused ao0_lsb - 5 unused ao0_msb - 6 unused ao1_lsb - 7 unused ao1_msb - - */ +}; static const struct comedi_lrange *const das08_ai_lranges[] = { - &range_unknown, - &range_bipolar5, - &range_das08_pgh, - &range_das08_pgl, - &range_das08_pgm, + [das08_pg_none] = &range_unknown, + [das08_bipolar5] = &range_bipolar5, + [das08_pgh] = &das08_pgh_ai_range, + [das08_pgl] = &das08_pgl_ai_range, + [das08_pgm] = &das08_pgm_ai_range, }; -static const int das08_pgh_gainlist[] = { +static const int das08_pgh_ai_gainlist[] = { 8, 0, 10, 2, 12, 4, 14, 6, 1, 3, 5, 7 }; -static const int das08_pgl_gainlist[] = { 8, 0, 2, 4, 6, 1, 3, 5, 7 }; -static const int das08_pgm_gainlist[] = { 8, 0, 10, 12, 14, 9, 11, 13, 15 }; - -static const int *const das08_gainlists[] = { - NULL, - NULL, - das08_pgh_gainlist, - das08_pgl_gainlist, - das08_pgm_gainlist, +static const int das08_pgl_ai_gainlist[] = { 8, 0, 2, 4, 6, 1, 3, 5, 7 }; +static const int das08_pgm_ai_gainlist[] = { 8, 0, 10, 12, 14, 9, 11, 13, 15 }; + +static const int *const das08_ai_gainlists[] = { + [das08_pg_none] = NULL, + [das08_bipolar5] = NULL, + [das08_pgh] = das08_pgh_ai_gainlist, + [das08_pgl] = das08_pgl_ai_gainlist, + [das08_pgm] = das08_pgm_ai_gainlist, }; static int das08_ai_eoc(struct comedi_device *dev, @@ -193,14 +168,15 @@ static int das08_ai_eoc(struct comedi_device *dev, { unsigned int status; - status = inb(dev->iobase + DAS08_STATUS); - if ((status & DAS08_EOC) == 0) + status = inb(dev->iobase + DAS08_STATUS_REG); + if ((status & DAS08_STATUS_AI_BUSY) == 0) return 0; return -EBUSY; } -static int das08_ai_rinsn(struct comedi_device *dev, struct comedi_subdevice *s, - struct comedi_insn *insn, unsigned int *data) +static int das08_ai_insn_read(struct comedi_device *dev, + struct comedi_subdevice *s, + struct comedi_insn *insn, unsigned int *data) { const struct das08_board_struct *thisboard = dev->board_ptr; struct das08_private_struct *devpriv = dev->private; @@ -214,49 +190,64 @@ static int das08_ai_rinsn(struct comedi_device *dev, struct comedi_subdevice *s, range = CR_RANGE(insn->chanspec); /* clear crap */ - inb(dev->iobase + DAS08_LSB); - inb(dev->iobase + DAS08_MSB); + inb(dev->iobase + DAS08_AI_LSB_REG); + inb(dev->iobase + DAS08_AI_MSB_REG); /* set multiplexer */ - /* lock to prevent race with digital output */ + /* lock to prevent race with digital output */ spin_lock(&dev->spinlock); - devpriv->do_mux_bits &= ~DAS08_MUX_MASK; - devpriv->do_mux_bits |= DAS08_MUX(chan); - outb(devpriv->do_mux_bits, dev->iobase + DAS08_CONTROL); + devpriv->do_mux_bits &= ~DAS08_CONTROL_MUX_MASK; + devpriv->do_mux_bits |= DAS08_CONTROL_MUX(chan); + outb(devpriv->do_mux_bits, dev->iobase + DAS08_CONTROL_REG); spin_unlock(&dev->spinlock); - if (s->range_table->length > 1) { + if (devpriv->pg_gainlist) { /* set gain/range */ range = CR_RANGE(insn->chanspec); outb(devpriv->pg_gainlist[range], - dev->iobase + DAS08AO_GAIN_CONTROL); + dev->iobase + DAS08_GAIN_REG); } for (n = 0; n < insn->n; n++) { /* clear over-range bits for 16-bit boards */ if (thisboard->ai_nbits == 16) - if (inb(dev->iobase + DAS08_MSB) & 0x80) + if (inb(dev->iobase + DAS08_AI_MSB_REG) & 0x80) dev_info(dev->class_dev, "over-range\n"); /* trigger conversion */ - outb_p(0, dev->iobase + DAS08_TRIG_12BIT); + outb_p(0, dev->iobase + DAS08_AI_TRIG_REG); ret = comedi_timeout(dev, s, insn, das08_ai_eoc, 0); if (ret) return ret; - msb = inb(dev->iobase + DAS08_MSB); - lsb = inb(dev->iobase + DAS08_LSB); + msb = inb(dev->iobase + DAS08_AI_MSB_REG); + lsb = inb(dev->iobase + DAS08_AI_LSB_REG); if (thisboard->ai_encoding == das08_encode12) { data[n] = (lsb >> 4) | (msb << 4); } else if (thisboard->ai_encoding == das08_pcm_encode12) { data[n] = (msb << 8) + lsb; } else if (thisboard->ai_encoding == das08_encode16) { - /* FPOS 16-bit boards are sign-magnitude */ + /* + * "JR" 16-bit boards are sign-magnitude. + * + * XXX The manual seems to imply that 0 is full-scale + * negative and 65535 is full-scale positive, but the + * original COMEDI patch to add support for the + * DAS08/JR/16 and DAS08/JR/16-AO boards have it + * encoded as sign-magnitude. Assume the original + * COMEDI code is correct for now. + */ + unsigned int magnitude = lsb | ((msb & 0x7f) << 8); + + /* + * MSB bit 7 is 0 for negative, 1 for positive voltage. + * COMEDI 16-bit bipolar data value for 0V is 0x8000. + */ if (msb & 0x80) - data[n] = (1 << 15) | lsb | ((msb & 0x7f) << 8); + data[n] = (1 << 15) + magnitude; else - data[n] = (1 << 15) - (lsb | (msb & 0x7f) << 8); + data[n] = (1 << 15) - magnitude; } else { dev_err(dev->class_dev, "bug! unknown ai encoding\n"); return -1; @@ -266,28 +257,28 @@ static int das08_ai_rinsn(struct comedi_device *dev, struct comedi_subdevice *s, return n; } -static int das08_di_rbits(struct comedi_device *dev, struct comedi_subdevice *s, - struct comedi_insn *insn, unsigned int *data) +static int das08_di_insn_bits(struct comedi_device *dev, + struct comedi_subdevice *s, + struct comedi_insn *insn, unsigned int *data) { data[0] = 0; - data[1] = DAS08_IP(inb(dev->iobase + DAS08_STATUS)); + data[1] = DAS08_STATUS_DI(inb(dev->iobase + DAS08_STATUS_REG)); return insn->n; } -static int das08_do_wbits(struct comedi_device *dev, - struct comedi_subdevice *s, - struct comedi_insn *insn, - unsigned int *data) +static int das08_do_insn_bits(struct comedi_device *dev, + struct comedi_subdevice *s, + struct comedi_insn *insn, unsigned int *data) { struct das08_private_struct *devpriv = dev->private; if (comedi_dio_update_state(s, data)) { /* prevent race with setting of analog input mux */ spin_lock(&dev->spinlock); - devpriv->do_mux_bits &= ~DAS08_DO_MASK; - devpriv->do_mux_bits |= DAS08_OP(s->state); - outb(devpriv->do_mux_bits, dev->iobase + DAS08_CONTROL); + devpriv->do_mux_bits &= ~DAS08_CONTROL_DO_MASK; + devpriv->do_mux_bits |= DAS08_CONTROL_DO(s->state); + outb(devpriv->do_mux_bits, dev->iobase + DAS08_CONTROL_REG); spin_unlock(&dev->spinlock); } @@ -296,23 +287,22 @@ static int das08_do_wbits(struct comedi_device *dev, return insn->n; } -static int das08jr_di_rbits(struct comedi_device *dev, - struct comedi_subdevice *s, - struct comedi_insn *insn, unsigned int *data) +static int das08jr_di_insn_bits(struct comedi_device *dev, + struct comedi_subdevice *s, + struct comedi_insn *insn, unsigned int *data) { data[0] = 0; - data[1] = inb(dev->iobase + DAS08JR_DIO); + data[1] = inb(dev->iobase + DAS08JR_DI_REG); return insn->n; } -static int das08jr_do_wbits(struct comedi_device *dev, - struct comedi_subdevice *s, - struct comedi_insn *insn, - unsigned int *data) +static int das08jr_do_insn_bits(struct comedi_device *dev, + struct comedi_subdevice *s, + struct comedi_insn *insn, unsigned int *data) { if (comedi_dio_update_state(s, data)) - outb(s->state, dev->iobase + DAS08JR_DIO); + outb(s->state, dev->iobase + DAS08JR_DO_REG); data[1] = s->state; @@ -329,15 +319,15 @@ static void das08_ao_set_data(struct comedi_device *dev, lsb = data & 0xff; msb = (data >> 8) & 0xff; if (thisboard->is_jr) { - outb(lsb, dev->iobase + DAS08JR_AO_LSB(chan)); - outb(msb, dev->iobase + DAS08JR_AO_MSB(chan)); + outb(lsb, dev->iobase + DAS08JR_AO_LSB_REG(chan)); + outb(msb, dev->iobase + DAS08JR_AO_MSB_REG(chan)); /* load DACs */ - inb(dev->iobase + DAS08JR_DIO); + inb(dev->iobase + DAS08JR_AO_UPDATE_REG); } else { - outb(lsb, dev->iobase + DAS08AO_AO_LSB(chan)); - outb(msb, dev->iobase + DAS08AO_AO_MSB(chan)); + outb(lsb, dev->iobase + DAS08AOX_AO_LSB_REG(chan)); + outb(msb, dev->iobase + DAS08AOX_AO_MSB_REG(chan)); /* load DACs */ - inb(dev->iobase + DAS08AO_AO_UPDATE); + inb(dev->iobase + DAS08AOX_AO_UPDATE_REG); } } @@ -379,7 +369,8 @@ int das08_common_attach(struct comedi_device *dev, unsigned long iobase) /* ai */ if (thisboard->ai_nbits) { s->type = COMEDI_SUBD_AI; - /* XXX some boards actually have differential + /* + * XXX some boards actually have differential * inputs instead of single ended. * The driver does nothing with arefs though, * so it's no big deal. @@ -388,8 +379,8 @@ int das08_common_attach(struct comedi_device *dev, unsigned long iobase) s->n_chan = 8; s->maxdata = (1 << thisboard->ai_nbits) - 1; s->range_table = das08_ai_lranges[thisboard->ai_pg]; - s->insn_read = das08_ai_rinsn; - devpriv->pg_gainlist = das08_gainlists[thisboard->ai_pg]; + s->insn_read = das08_ai_insn_read; + devpriv->pg_gainlist = das08_ai_gainlists[thisboard->ai_pg]; } else { s->type = COMEDI_SUBD_UNUSED; } @@ -425,8 +416,8 @@ int das08_common_attach(struct comedi_device *dev, unsigned long iobase) s->n_chan = thisboard->di_nchan; s->maxdata = 1; s->range_table = &range_digital; - s->insn_bits = - thisboard->is_jr ? das08jr_di_rbits : das08_di_rbits; + s->insn_bits = thisboard->is_jr ? das08jr_di_insn_bits : + das08_di_insn_bits; } else { s->type = COMEDI_SUBD_UNUSED; } @@ -439,8 +430,8 @@ int das08_common_attach(struct comedi_device *dev, unsigned long iobase) s->n_chan = thisboard->do_nchan; s->maxdata = 1; s->range_table = &range_digital; - s->insn_bits = - thisboard->is_jr ? das08jr_do_wbits : das08_do_wbits; + s->insn_bits = thisboard->is_jr ? das08jr_do_insn_bits : + das08_do_insn_bits; } else { s->type = COMEDI_SUBD_UNUSED; } @@ -485,5 +476,5 @@ static void __exit das08_exit(void) module_exit(das08_exit); MODULE_AUTHOR("Comedi http://www.comedi.org"); -MODULE_DESCRIPTION("Comedi low-level driver"); +MODULE_DESCRIPTION("Comedi common DAS08 support module"); MODULE_LICENSE("GPL");