summaryrefslogtreecommitdiff
path: root/drivers/staging/comedi/drivers/addi_apci_3501.c
diff options
context:
space:
mode:
authorH Hartley Sweeten <hsweeten@visionengravers.com>2013-01-23 12:42:02 -0700
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>2013-01-25 12:00:29 -0800
commit25b9b873d3e3c1ed25cd5a7551bfee0b42d4ed1d (patch)
treed940d2c8ac635e0e7c5394a9711474e8b6c85a93 /drivers/staging/comedi/drivers/addi_apci_3501.c
parent87c38fbed5bb706785be9171ed4a9b41faf17e13 (diff)
downloadlinux-rt-25b9b873d3e3c1ed25cd5a7551bfee0b42d4ed1d.tar.gz
staging: comedi: addi_apci_3501: simplify reading the eeprom
The only value in the eeprom that is used by this driver is the number of analog output channels. Copy the necessary code from addi_eeprom.c to this driver and refactor it so that we can get the value needed. Signed-off-by: H Hartley Sweeten <hsweeten@visionengravers.com> Cc: Ian Abbott <abbotti@mev.co.uk> Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Diffstat (limited to 'drivers/staging/comedi/drivers/addi_apci_3501.c')
-rw-r--r--drivers/staging/comedi/drivers/addi_apci_3501.c131
1 files changed, 109 insertions, 22 deletions
diff --git a/drivers/staging/comedi/drivers/addi_apci_3501.c b/drivers/staging/comedi/drivers/addi_apci_3501.c
index 48f7c82b2a9c..332e9a0a68d0 100644
--- a/drivers/staging/comedi/drivers/addi_apci_3501.c
+++ b/drivers/staging/comedi/drivers/addi_apci_3501.c
@@ -4,9 +4,28 @@
#include "addi-data/addi_common.h"
-#include "addi-data/addi_eeprom.c"
#include "addi-data/hwdrv_apci3501.c"
+/*
+ * AMCC S5933 NVRAM
+ */
+#define NVRAM_USER_DATA_START 0x100
+
+#define NVCMD_BEGIN_READ (0x7 << 5)
+#define NVCMD_LOAD_LOW (0x4 << 5)
+#define NVCMD_LOAD_HIGH (0x5 << 5)
+
+/*
+ * Function types stored in the eeprom
+ */
+#define EEPROM_DIGITALINPUT 0
+#define EEPROM_DIGITALOUTPUT 1
+#define EEPROM_ANALOGINPUT 2
+#define EEPROM_ANALOGOUTPUT 3
+#define EEPROM_TIMER 4
+#define EEPROM_WATCHDOG 5
+#define EEPROM_TIMER_WATCHDOG_COUNTER 10
+
static const struct addi_board apci3501_boardtypes[] = {
{
.pc_DriverName = "apci3501",
@@ -50,19 +69,90 @@ static int apci3501_do_insn_bits(struct comedi_device *dev,
return insn->n;
}
+static void apci3501_eeprom_wait(unsigned long iobase)
+{
+ unsigned char val;
+
+ do {
+ val = inb(iobase + AMCC_OP_REG_MCSR_NVCMD);
+ } while (val & 0x80);
+}
+
+static unsigned short apci3501_eeprom_readw(unsigned long iobase,
+ unsigned short addr)
+{
+ unsigned short val = 0;
+ unsigned char tmp;
+ unsigned char i;
+
+ /* Add the offset to the start of the user data */
+ addr += NVRAM_USER_DATA_START;
+
+ for (i = 0; i < 2; i++) {
+ /* Load the low 8 bit address */
+ outb(NVCMD_LOAD_LOW, iobase + AMCC_OP_REG_MCSR_NVCMD);
+ apci3501_eeprom_wait(iobase);
+ outb((addr + i) & 0xff, iobase + AMCC_OP_REG_MCSR_NVDATA);
+ apci3501_eeprom_wait(iobase);
+
+ /* Load the high 8 bit address */
+ outb(NVCMD_LOAD_HIGH, iobase + AMCC_OP_REG_MCSR_NVCMD);
+ apci3501_eeprom_wait(iobase);
+ outb(((addr + i) >> 8) & 0xff,
+ iobase + AMCC_OP_REG_MCSR_NVDATA);
+ apci3501_eeprom_wait(iobase);
+
+ /* Read the eeprom data byte */
+ outb(NVCMD_BEGIN_READ, iobase + AMCC_OP_REG_MCSR_NVCMD);
+ apci3501_eeprom_wait(iobase);
+ tmp = inb(iobase + AMCC_OP_REG_MCSR_NVDATA);
+ apci3501_eeprom_wait(iobase);
+
+ if (i == 0)
+ val |= tmp;
+ else
+ val |= (tmp << 8);
+ }
+
+ return val;
+}
+
+static int apci3501_eeprom_get_ao_n_chan(struct comedi_device *dev)
+{
+ struct addi_private *devpriv = dev->private;
+ unsigned long iobase = devpriv->i_IobaseAmcc;
+ unsigned char nfuncs;
+ int i;
+
+ nfuncs = apci3501_eeprom_readw(iobase, 10) & 0xff;
+
+ /* Read functionality details */
+ for (i = 0; i < nfuncs; i++) {
+ unsigned short offset = i * 4;
+ unsigned short addr;
+ unsigned char func;
+ unsigned short val;
+
+ func = apci3501_eeprom_readw(iobase, 12 + offset) & 0x3f;
+ addr = apci3501_eeprom_readw(iobase, 14 + offset);
+
+ if (func == EEPROM_ANALOGOUTPUT) {
+ val = apci3501_eeprom_readw(iobase, addr + 10);
+ return (val >> 4) & 0x3ff;
+ }
+ }
+ return 0;
+}
+
static int apci3501_eeprom_insn_read(struct comedi_device *dev,
struct comedi_subdevice *s,
struct comedi_insn *insn,
unsigned int *data)
{
- const struct addi_board *this_board = comedi_board(dev);
struct addi_private *devpriv = dev->private;
- unsigned short w_Address = CR_CHAN(insn->chanspec);
- unsigned short w_Data;
+ unsigned short addr = CR_CHAN(insn->chanspec);
- w_Data = addi_eeprom_readw(devpriv->i_IobaseAmcc,
- this_board->pc_EepromChip, 2 * w_Address);
- data[0] = w_Data;
+ data[0] = apci3501_eeprom_readw(devpriv->i_IobaseAmcc, 2 * addr);
return insn->n;
}
@@ -164,6 +254,7 @@ static int apci3501_auto_attach(struct comedi_device *dev,
const struct addi_board *this_board;
struct addi_private *devpriv;
struct comedi_subdevice *s;
+ int ao_n_chan;
int ret, n_subdevices;
this_board = addi_find_boardinfo(dev, pcidev);
@@ -184,8 +275,7 @@ static int apci3501_auto_attach(struct comedi_device *dev,
dev->iobase = pci_resource_start(pcidev, 1);
devpriv->i_IobaseAmcc = pci_resource_start(pcidev, 0);
- /* Initialize parameters that can be overridden in EEPROM */
- devpriv->s_EeParameters.i_NbrAoChannel = this_board->i_NbrAoChannel;
+ ao_n_chan = apci3501_eeprom_get_ao_n_chan(dev);
if (pcidev->irq > 0) {
ret = request_irq(pcidev->irq, apci3501_interrupt, IRQF_SHARED,
@@ -194,8 +284,6 @@ static int apci3501_auto_attach(struct comedi_device *dev,
dev->irq = pcidev->irq;
}
- addi_eeprom_read_info(dev, pci_resource_start(pcidev, 0));
-
n_subdevices = 7;
ret = comedi_alloc_subdevices(dev, n_subdevices);
if (ret)
@@ -207,19 +295,18 @@ static int apci3501_auto_attach(struct comedi_device *dev,
/* Allocate and Initialise AO Subdevice Structures */
s = &dev->subdevices[1];
- if (devpriv->s_EeParameters.i_NbrAoChannel) {
- s->type = COMEDI_SUBD_AO;
- s->subdev_flags = SDF_WRITEABLE | SDF_GROUND | SDF_COMMON;
- s->n_chan = devpriv->s_EeParameters.i_NbrAoChannel;
- s->maxdata = 0x3fff;
- s->len_chanlist =
- devpriv->s_EeParameters.i_NbrAoChannel;
- s->range_table = &range_apci3501_ao;
- s->insn_config = i_APCI3501_ConfigAnalogOutput;
- s->insn_write = i_APCI3501_WriteAnalogOutput;
+ if (ao_n_chan) {
+ s->type = COMEDI_SUBD_AO;
+ s->subdev_flags = SDF_WRITEABLE | SDF_GROUND | SDF_COMMON;
+ s->n_chan = ao_n_chan;
+ s->maxdata = 0x3fff;
+ s->range_table = &range_apci3501_ao;
+ s->insn_config = i_APCI3501_ConfigAnalogOutput;
+ s->insn_write = i_APCI3501_WriteAnalogOutput;
} else {
- s->type = COMEDI_SUBD_UNUSED;
+ s->type = COMEDI_SUBD_UNUSED;
}
+
/* Allocate and Initialise DI Subdevice Structures */
s = &dev->subdevices[2];
s->type = COMEDI_SUBD_DI;