From 25b9b873d3e3c1ed25cd5a7551bfee0b42d4ed1d Mon Sep 17 00:00:00 2001 From: H Hartley Sweeten Date: Wed, 23 Jan 2013 12:42:02 -0700 Subject: [PATCH] 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 Cc: Ian Abbott Signed-off-by: Greg Kroah-Hartman --- .../staging/comedi/drivers/addi_apci_3501.c | 131 +++++++++++++++--- 1 file 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; -- 2.20.1