Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 25b9b873 authored by H Hartley Sweeten's avatar H Hartley Sweeten Committed by Greg Kroah-Hartman
Browse files

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: default avatarH Hartley Sweeten <hsweeten@visionengravers.com>
Cc: Ian Abbott <abbotti@mev.co.uk>
Signed-off-by: default avatarGreg Kroah-Hartman <gregkh@linuxfoundation.org>
parent 87c38fbe
Loading
Loading
Loading
Loading
+109 −22
Original line number Diff line number Diff line
@@ -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) {
	if (ao_n_chan) {
		s->type		= COMEDI_SUBD_AO;
		s->subdev_flags	= SDF_WRITEABLE | SDF_GROUND | SDF_COMMON;
		s->n_chan = devpriv->s_EeParameters.i_NbrAoChannel;
		s->n_chan	= ao_n_chan;
		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;
	} else {
		s->type		= COMEDI_SUBD_UNUSED;
	}

	/*  Allocate and Initialise DI Subdevice Structures */
	s = &dev->subdevices[2];
	s->type		= COMEDI_SUBD_DI;