From: H Hartley Sweeten Date: Wed, 24 Jul 2013 19:13:04 +0000 (-0700) Subject: staging: comedi: ii_pci20kc: cleanup the ao subdevice X-Git-Tag: Ubuntu-snapdragon-4.4.0-1050.54~11876^2~550 X-Git-Url: https://git.proxmox.com/?a=commitdiff_plain;h=87a61614e3cd841cb6d73878b46d8e858418e536;p=mirror_ubuntu-artful-kernel.git staging: comedi: ii_pci20kc: cleanup the ao subdevice The PCI-20006M-1 and PCI-20006M-2 modules can both provide an analog output subdevice in this driver. Fix the module init code to detect both of them. The analog output can support +/-5, 0-10, or +/-10 volt ranges depending on jumpers on the board. Report all the ranges to the user instead of relying on the configuration options to set the range. The user can then select the appropriate range depending on how they have configured the hardware. Tidy up the (*insn_{read,write})() functions to work like the comedi core expects. Signed-off-by: H Hartley Sweeten Cc: Ian Abbott Signed-off-by: Greg Kroah-Hartman --- diff --git a/drivers/staging/comedi/drivers/ii_pci20kc.c b/drivers/staging/comedi/drivers/ii_pci20kc.c index e86a2b5399ce..1119a1a33135 100644 --- a/drivers/staging/comedi/drivers/ii_pci20kc.c +++ b/drivers/staging/comedi/drivers/ii_pci20kc.c @@ -63,11 +63,6 @@ Options: 7 second option for module 3 options for PCI-20006M: - first: Analog output channel 0 range configuration - 0 bipolar 10 (-10V -- +10V) - 1 unipolar 10 (0V -- +10V) - 2 bipolar 5 (-5V -- 5V) - second: Analog output channel 1 range configuration options for PCI-20341M: first: Analog input gain configuration @@ -117,15 +112,16 @@ options for PCI-20341M: #define II20K_CTRL23_DIO2_IN (1 << 4) #define II20K_CTRL23_DIO3_IN (1 << 1) +#define II20K_ID_PCI20006M_1 0xe2 /* 1 AO channels */ +#define II20K_ID_PCI20006M_2 0xe3 /* 2 AO channels */ +#define II20K_AO_STRB_REG(x) (0x0b + ((x) * 0x08)) +#define II20K_AO_LSB_REG(x) (0x0d + ((x) * 0x08)) +#define II20K_AO_MSB_REG(x) (0x0e + ((x) * 0x08)) +#define II20K_AO_STRB_BOTH_REG 0x1b + #define PCI20341_ID 0x77 -#define PCI20006_ID 0xe3 #define PCI20xxx_EMPTY_ID 0xff -#define PCI20006_LCHAN0 0x0d -#define PCI20006_STROBE0 0x0b -#define PCI20006_LCHAN1 0x15 -#define PCI20006_STROBE1 0x13 - #define PCI20341_INIT 0x04 #define PCI20341_REPMODE 0x00 /* single shot mode */ #define PCI20341_PACER 0x00 /* Hardware Pacer disabled */ @@ -144,6 +140,14 @@ options for PCI-20341M: #define PCI20341_MUX 0x04 /* Enable on-board MUX */ #define PCI20341_SCANLIST 0x80 /* Channel/Gain Scan List */ +/* the AO range is set by jumpers on the 20006M module */ +static const struct comedi_lrange ii20k_ao_ranges = { + 3, { + BIP_RANGE(5), /* Chan 0 - W1/W3 in Chan 1 - W2/W4 in */ + UNI_RANGE(10), /* Chan 0 - W1/W3 out Chan 1 - W2/W4 in */ + BIP_RANGE(10) /* Chan 0 - W1/W3 in Chan 1 - W2/W4 out */ + } +}; static const struct comedi_lrange range_bipolar0_5 = { 1, { BIP_RANGE(0.5) @@ -162,12 +166,6 @@ static const struct comedi_lrange range_bipolar0_025 = { } }; -static const struct comedi_lrange *ii20k_ao_ranges[] = { - &range_bipolar10, - &range_unipolar10, - &range_bipolar5, -}; - static const struct comedi_lrange *const ii20k_ai_ranges[] = { &range_bipolar5, &range_bipolar0_5, @@ -179,7 +177,6 @@ static const int pci20341_timebase[] = { 0x00, 0x00, 0x00, 0x04 }; static const int pci20341_settling_time[] = { 0x58, 0x58, 0x93, 0x99 }; struct ii20k_ao_private { - const struct comedi_lrange *ao_range_list[2]; unsigned int last_data[2]; }; @@ -207,10 +204,13 @@ static int ii20k_ao_insn_read(struct comedi_device *dev, unsigned int *data) { struct ii20k_ao_private *ao_spriv = s->private; + unsigned int chan = CR_CHAN(insn->chanspec); + int i; - data[0] = ao_spriv->last_data[CR_CHAN(insn->chanspec)]; + for (i = 0; i < insn->n; i++) + data[i] = ao_spriv->last_data[chan]; - return 1; + return insn->n; } static int ii20k_ao_insn_write(struct comedi_device *dev, @@ -220,32 +220,25 @@ static int ii20k_ao_insn_write(struct comedi_device *dev, { struct ii20k_ao_private *ao_spriv = s->private; void __iomem *iobase = ii20k_module_iobase(dev, s); - int hi, lo; - unsigned int boarddata; + unsigned int chan = CR_CHAN(insn->chanspec); + unsigned int val = ao_spriv->last_data[chan]; + int i; - ao_spriv->last_data[CR_CHAN(insn->chanspec)] = data[0]; - boarddata = (((unsigned int)data[0] + 0x8000) & 0xffff); - /* comedi-data -> board-data */ - lo = (boarddata & 0xff); - hi = ((boarddata >> 8) & 0xff); - - switch (CR_CHAN(insn->chanspec)) { - case 0: - writeb(lo, iobase + PCI20006_LCHAN0); - writeb(hi, iobase + PCI20006_LCHAN0 + 1); - writeb(0x00, iobase + PCI20006_STROBE0); - break; - case 1: - writeb(lo, iobase + PCI20006_LCHAN1); - writeb(hi, iobase + PCI20006_LCHAN1 + 1); - writeb(0x00, iobase + PCI20006_STROBE1); - break; - default: - dev_warn(dev->class_dev, "ao channel Error!\n"); - return -EINVAL; + for (i = 0; i < insn->n; i++) { + val = data[i]; + + /* munge data */ + val += ((s->maxdata + 1) >> 1); + val &= s->maxdata; + + writeb(val & 0xff, iobase + II20K_AO_LSB_REG(chan)); + writeb((val >> 8) & 0xff, iobase + II20K_AO_MSB_REG(chan)); + writeb(0x00, iobase + II20K_AO_STRB_REG(chan)); } - return 1; + ao_spriv->last_data[chan] = val; + + return insn->n; } static int ii20k_ai_insn_read(struct comedi_device *dev, @@ -470,30 +463,22 @@ static int ii20k_init_module(struct comedi_device *dev, struct ii20k_ai_private *ai_spriv; void __iomem *iobase = ii20k_module_iobase(dev, s); unsigned int opt0 = it->options[(2 * s->index) + 2]; - unsigned int opt1 = it->options[(2 * s->index) + 3]; unsigned char id; id = readb(iobase + II20K_ID_REG); switch (id) { - case PCI20006_ID: - if (opt0 < 0 || opt0 > 2) - opt0 = 0; - if (opt1 < 0 || opt1 > 2) - opt1 = 0; - + case II20K_ID_PCI20006M_1: + case II20K_ID_PCI20006M_2: ao_spriv = comedi_alloc_spriv(s, sizeof(*ao_spriv)); if (!ao_spriv) return -ENOMEM; - ao_spriv->ao_range_list[0] = ii20k_ao_ranges[opt0]; - ao_spriv->ao_range_list[1] = ii20k_ao_ranges[opt1]; - /* Analog Output subdevice */ s->type = COMEDI_SUBD_AO; s->subdev_flags = SDF_WRITABLE; - s->n_chan = 2; + s->n_chan = (id == II20K_ID_PCI20006M_2) ? 2 : 1; s->maxdata = 0xffff; - s->range_table_list = ao_spriv->ao_range_list; + s->range_table = &ii20k_ao_ranges; s->insn_read = ii20k_ao_insn_read; s->insn_write = ii20k_ao_insn_write; break;