According to an old GPL'ed driver at <ftp://ftp.mccdaq.com/downloads/iotech_software/DaqBoard_1000_2000_Series/Linux_driver_kernelv2.4.x/>, The CPLD status register can be checked to make sure that it is ready to accept the next 16-bit word of FPGA firmware data, but that doesn't work on older versions of the CPLD, where a simple delay should be used between successive writes. The current version of the Comedi driver just uses a delay between successive writes. Change it to check for the newer CPLD in the `daqboard2000_load_firmware()`, and change the firmware word writing function `daqboard2000_write_cpld()` to wait for the status bit (`DB2K_CPLD_STATUS_TXREADY`, previously called `DB2K_CPLD_TXDONE`) to be set for newer CPLD, or just delay for older CPLD. Return an error if it times out waiting for the status bit. The wait for the `DB2K_CPLD_STATUS_TXREADY` status bit to be set is performed by new function `daqboard2000_wait_cpld_txready()`, which returns 0 if the status bit is set within 100 microseconds, or `-ETIMEDOUT` if not. Signed-off-by: Ian Abbott <abbotti@xxxxxxxxx> --- drivers/staging/comedi/drivers/daqboard2000.c | 41 ++++++++++++++++++++++----- 1 file changed, 34 insertions(+), 7 deletions(-) diff --git a/drivers/staging/comedi/drivers/daqboard2000.c b/drivers/staging/comedi/drivers/daqboard2000.c index 4e3e81186bc3..626571fc1c01 100644 --- a/drivers/staging/comedi/drivers/daqboard2000.c +++ b/drivers/staging/comedi/drivers/daqboard2000.c @@ -240,7 +240,10 @@ static const struct comedi_lrange range_daqboard2000_ai = { /* CPLD status bits */ #define DB2K_CPLD_STATUS_INIT 0x0002 -#define DB2K_CPLD_STATUS_TXDONE 0x0004 +#define DB2K_CPLD_STATUS_TXREADY 0x0004 +#define DB2K_CPLD_VERSION_MASK 0xf000 +/* "New CPLD" signature. */ +#define DB2K_CPLD_VERSION_NEW 0x5000 struct daq200_boardtype { const char *name; @@ -489,14 +492,35 @@ static int daqboard2000_wait_cpld_init(struct comedi_device *dev) return result; } -static int daqboard2000_write_cpld(struct comedi_device *dev, u16 data) +static int daqboard2000_wait_cpld_txready(struct comedi_device *dev) { - int result = -EIO; + int i; + + for (i = 0; i < 100; i++) { + if (readw(dev->mmio + DB2K_REG_CPLD_STATUS) & + DB2K_CPLD_STATUS_TXREADY) { + return 0; + } + udelay(1); + } + return -ETIMEDOUT; +} + +static int daqboard2000_write_cpld(struct comedi_device *dev, u16 data, + bool new_cpld) +{ + int result = 0; - usleep_range(10, 20); + if (new_cpld) { + result = daqboard2000_wait_cpld_txready(dev); + if (result) + return result; + } else { + usleep_range(10, 20); + } writew(data, dev->mmio + DB2K_REG_CPLD_WDATA); - if (readw(dev->mmio + DB2K_REG_CPLD_STATUS) & DB2K_CPLD_STATUS_INIT) - result = 0; + if (!(readw(dev->mmio + DB2K_REG_CPLD_STATUS) & DB2K_CPLD_STATUS_INIT)) + result = -EIO; return result; } @@ -527,6 +551,7 @@ static int daqboard2000_load_firmware(struct comedi_device *dev, u32 cntrl; int retry; size_t i; + bool new_cpld; /* Look for FPGA start sequence in firmware. */ for (i = 0; i + 1 < len; i++) { @@ -561,10 +586,12 @@ static int daqboard2000_load_firmware(struct comedi_device *dev, if (result) continue; + new_cpld = (readw(dev->mmio + DB2K_REG_CPLD_STATUS) & + DB2K_CPLD_VERSION_MASK) == DB2K_CPLD_VERSION_NEW; for (; i < len; i += 2) { u16 data = (cpld_array[i] << 8) + cpld_array[i + 1]; - result = daqboard2000_write_cpld(dev, data); + result = daqboard2000_write_cpld(dev, data, new_cpld); if (result) break; } -- 2.11.0 _______________________________________________ devel mailing list devel@xxxxxxxxxxxxxxxxxxxxxx http://driverdev.linuxdriverproject.org/mailman/listinfo/driverdev-devel