Skip to content

Commit

Permalink
staging: comedi: addi_apci_3501: simplify reading the eeprom
Browse files Browse the repository at this point in the history
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>
  • Loading branch information
H Hartley Sweeten authored and Greg Kroah-Hartman committed Jan 25, 2013
1 parent 87c38fb commit 25b9b87
Showing 1 changed file with 109 additions and 22 deletions.
131 changes: 109 additions & 22 deletions drivers/staging/comedi/drivers/addi_apci_3501.c
Original file line number Diff line number Diff line change
Expand Up @@ -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",
Expand Down Expand Up @@ -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;
}
Expand Down Expand Up @@ -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);
Expand All @@ -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,
Expand All @@ -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)
Expand All @@ -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;
Expand Down

0 comments on commit 25b9b87

Please sign in to comment.