unsigned int *data)
{
struct apci3120_private *devpriv = dev->private;
- unsigned short us_ConvertTiming, us_TmpValue, i;
+ unsigned int divisor;
+ unsigned int ns;
+ unsigned short us_TmpValue, i;
unsigned char b_Tmp;
/* fix conversion time to 10 us */
if (!devpriv->ui_EocEosConversionTime)
- us_ConvertTiming = 10;
+ ns = 10000;
else
- us_ConvertTiming = (unsigned short) (devpriv->ui_EocEosConversionTime / 1000); /* nano to useconds */
+ ns = devpriv->ui_EocEosConversionTime;
/* Clear software registers */
devpriv->b_TimerSelectMode = 0;
} else {
devpriv->tsk_Current = current; /* Save the current process task structure */
- /*
- * Testing if board have the new Quartz and calculate the time value
- * to set in the timer
- */
- us_TmpValue = inw(dev->iobase + APCI3120_RD_STATUS);
-
- /* EL250804: Testing if board APCI3120 have the new Quartz or if it is an APCI3001 */
- if ((us_TmpValue & 0x00B0) == 0x00B0
- || !strcmp(dev->board_name, "apci3001")) {
- us_ConvertTiming = (us_ConvertTiming * 2) - 2;
- } else {
- us_ConvertTiming =
- ((us_ConvertTiming * 12926) / 10000) - 1;
- }
+ divisor = apci3120_ns_to_timer(dev, 0, ns, CMDF_ROUND_NEAREST);
us_TmpValue = (unsigned short) devpriv->b_InterruptMode;
outb(b_Tmp, dev->iobase + APCI3120_TIMER_CRT0);
/* Set the conversion time */
- outw(us_ConvertTiming,
- dev->iobase + APCI3120_TIMER_VALUE);
+ outw(divisor, dev->iobase + APCI3120_TIMER_VALUE);
us_TmpValue =
(unsigned short) inw(dev->iobase + APCI3120_RD_STATUS);
outb(b_Tmp, dev->iobase + APCI3120_TIMER_CRT0);
/* Set the conversion time */
- outw(us_ConvertTiming,
- dev->iobase + APCI3120_TIMER_VALUE);
+ outw(divisor, dev->iobase + APCI3120_TIMER_VALUE);
/* Set the scan bit */
devpriv->b_ModeSelectRegister =
struct apci3120_private *devpriv = dev->private;
struct comedi_cmd *cmd = &s->async->cmd;
unsigned char b_Tmp;
- unsigned int ui_DelayTiming = 0;
- unsigned int ui_TimerValue1 = 0;
+ unsigned int divisor1 = 0;
unsigned int dmalen0 = 0;
unsigned int dmalen1 = 0;
unsigned int ui_TimerValue2 = 0;
- unsigned int ui_TimerValue0;
- unsigned int ui_ConvertTiming;
- unsigned short us_TmpValue;
+ unsigned int divisor0;
/* Resets the FIFO */
inb(dev->iobase + APCI3120_RESET_FIFO);
/* value for timer2 minus -2 has to be done */
ui_TimerValue2 = cmd->stop_arg - 2;
- ui_ConvertTiming = cmd->convert_arg;
-
- if (mode == 2)
- ui_DelayTiming = cmd->scan_begin_arg;
/* Initializes the sequence array */
if (!apci3120_setup_chan_list(dev, s, devpriv->ui_AiNbrofChannels,
cmd->chanlist, 0))
return -EINVAL;
- us_TmpValue = (unsigned short) inw(dev->iobase + APCI3120_RD_STATUS);
-
- /* EL241003 Begin: add this section to replace floats calculation by integer calculations */
- /* EL250804: Testing if board APCI3120 have the new Quartz or if it is an APCI3001 */
- if ((us_TmpValue & 0x00B0) == 0x00B0
- || !strcmp(dev->board_name, "apci3001")) {
- ui_TimerValue0 = ui_ConvertTiming * 2 - 2000;
- ui_TimerValue0 = ui_TimerValue0 / 1000;
-
- if (mode == 2) {
- ui_DelayTiming = ui_DelayTiming / 1000;
- ui_TimerValue1 = ui_DelayTiming * 2 - 200;
- ui_TimerValue1 = ui_TimerValue1 / 100;
- }
- } else {
- ui_ConvertTiming = ui_ConvertTiming / 1000;
- ui_TimerValue0 = ui_ConvertTiming * 12926 - 10000;
- ui_TimerValue0 = ui_TimerValue0 / 10000;
-
- if (mode == 2) {
- ui_DelayTiming = ui_DelayTiming / 1000;
- ui_TimerValue1 = ui_DelayTiming * 12926 - 1;
- ui_TimerValue1 = ui_TimerValue1 / 1000000;
- }
+ divisor0 = apci3120_ns_to_timer(dev, 0, cmd->convert_arg, cmd->flags);
+ if (mode == 2) {
+ divisor1 = apci3120_ns_to_timer(dev, 1, cmd->scan_begin_arg,
+ cmd->flags);
}
- /* EL241003 End */
if (devpriv->b_ExttrigEnable == APCI3120_ENABLE)
apci3120_exttrig_enable(dev); /* activate EXT trigger */
APCI3120_SELECT_TIMER_0_WORD;
outb(b_Tmp, dev->iobase + APCI3120_TIMER_CRT0);
/* Set the conversion time */
- outw(((unsigned short) ui_TimerValue0),
- dev->iobase + APCI3120_TIMER_VALUE);
+ outw(divisor0, dev->iobase + APCI3120_TIMER_VALUE);
break;
case 2:
APCI3120_SELECT_TIMER_1_WORD;
outb(b_Tmp, dev->iobase + APCI3120_TIMER_CRT0);
/* Set the conversion time */
- outw(((unsigned short) ui_TimerValue1),
- dev->iobase + APCI3120_TIMER_VALUE);
+ outw(divisor1, dev->iobase + APCI3120_TIMER_VALUE);
/* init timer0 in mode 2 */
devpriv->b_TimerSelectMode =
outb(b_Tmp, dev->iobase + APCI3120_TIMER_CRT0);
/* Set the conversion time */
- outw(((unsigned short) ui_TimerValue0),
- dev->iobase + APCI3120_TIMER_VALUE);
+ outw(divisor0, dev->iobase + APCI3120_TIMER_VALUE);
break;
}
unsigned int *data)
{
struct apci3120_private *devpriv = dev->private;
- unsigned int ui_Timervalue2;
- unsigned short us_TmpValue;
+ unsigned int divisor;
unsigned char b_Tmp;
if (!data[1])
devpriv->b_Timer2Interrupt = (unsigned char) data[2]; /* save info whether to enable or disable interrupt */
- ui_Timervalue2 = data[1] / 1000; /* convert nano seconds to u seconds */
-
- us_TmpValue = inw(dev->iobase + APCI3120_RD_STATUS);
-
- /*
- * EL250804: Testing if board APCI3120 have the new Quartz or if it
- * is an APCI3001 and calculate the time value to set in the timer
- */
- if ((us_TmpValue & 0x00B0) == 0x00B0
- || !strcmp(dev->board_name, "apci3001")) {
- /* Calculate the time value to set in the timer */
- ui_Timervalue2 = ui_Timervalue2 / 50;
- } else {
- /* Calculate the time value to set in the timer */
- ui_Timervalue2 = ui_Timervalue2 / 70;
- }
+ divisor = apci3120_ns_to_timer(dev, 2, data[1], CMDF_ROUND_DOWN);
/* Reset gate 2 of Timer 2 to disable it (Set Bit D14 to 0) */
devpriv->us_OutputRegister =
b_DigitalOutputRegister) & 0xF0) |
APCI3120_SELECT_TIMER_2_LOW_WORD;
outb(b_Tmp, dev->iobase + APCI3120_TIMER_CRT0);
- outw(ui_Timervalue2 & 0xffff,
- dev->iobase + APCI3120_TIMER_VALUE);
+ outw(divisor & 0xffff, dev->iobase + APCI3120_TIMER_VALUE);
/* Writing HIGH unsigned short */
b_Tmp = ((devpriv->
b_DigitalOutputRegister) & 0xF0) |
APCI3120_SELECT_TIMER_2_HIGH_WORD;
outb(b_Tmp, dev->iobase + APCI3120_TIMER_CRT0);
- outw((ui_Timervalue2 >> 16) & 0xffff,
+ outw((divisor >> 16) & 0xffff,
dev->iobase + APCI3120_TIMER_VALUE);
/* timer2 in Timer mode enabled */
devpriv->b_Timer2Mode = APCI3120_TIMER;
b_DigitalOutputRegister) & 0xF0) |
APCI3120_SELECT_TIMER_2_LOW_WORD;
outb(b_Tmp, dev->iobase + APCI3120_TIMER_CRT0);
- outw(ui_Timervalue2 & 0xffff,
- dev->iobase + APCI3120_TIMER_VALUE);
+ outw(divisor & 0xffff, dev->iobase + APCI3120_TIMER_VALUE);
/* Writing HIGH unsigned short */
b_Tmp = ((devpriv->
APCI3120_SELECT_TIMER_2_HIGH_WORD;
outb(b_Tmp, dev->iobase + APCI3120_TIMER_CRT0);
- outw((ui_Timervalue2 >> 16) & 0xffff,
+ outw((divisor >> 16) & 0xffff,
dev->iobase + APCI3120_TIMER_VALUE);
/* watchdog enabled */
devpriv->b_Timer2Mode = APCI3120_WATCHDOG;
unsigned int *data)
{
struct apci3120_private *devpriv = dev->private;
- unsigned int ui_Timervalue2 = 0;
- unsigned short us_TmpValue;
+ unsigned int divisor;
unsigned char b_Tmp;
if ((devpriv->b_Timer2Mode != APCI3120_WATCHDOG)
"timer2 not configured in TIMER MODE\n");
return -EINVAL;
}
-
- if (data[1])
- ui_Timervalue2 = data[1];
- else
- ui_Timervalue2 = 0;
}
switch (data[0]) {
"timer2 not configured in TIMER MODE\n");
return -EINVAL;
}
- us_TmpValue = inw(dev->iobase + APCI3120_RD_STATUS);
- /*
- * EL250804: Testing if board APCI3120 have the new Quartz or if it
- * is an APCI3001 and calculate the time value to set in the timer
- */
- if ((us_TmpValue & 0x00B0) == 0x00B0
- || !strcmp(dev->board_name, "apci3001")) {
- /* Calculate the time value to set in the timer */
- ui_Timervalue2 = ui_Timervalue2 / 50;
- } else {
- /* Calculate the time value to set in the timer */
- ui_Timervalue2 = ui_Timervalue2 / 70;
- }
+ divisor = apci3120_ns_to_timer(dev, 2, data[1],
+ CMDF_ROUND_DOWN);
+
/* Writing LOW unsigned short */
b_Tmp = ((devpriv->
b_DigitalOutputRegister) & 0xF0) |
APCI3120_SELECT_TIMER_2_LOW_WORD;
outb(b_Tmp, dev->iobase + APCI3120_TIMER_CRT0);
- outw(ui_Timervalue2 & 0xffff,
- dev->iobase + APCI3120_TIMER_VALUE);
+ outw(divisor & 0xffff, dev->iobase + APCI3120_TIMER_VALUE);
/* Writing HIGH unsigned short */
b_Tmp = ((devpriv->
APCI3120_SELECT_TIMER_2_HIGH_WORD;
outb(b_Tmp, dev->iobase + APCI3120_TIMER_CRT0);
- outw((ui_Timervalue2 >> 16) & 0xffff,
+ outw((divisor >> 16) & 0xffff,
dev->iobase + APCI3120_TIMER_VALUE);
break;
/*
* PCI BAR 1 register map (dev->iobase)
*/
+#define APCI3120_STATUS_TO_VERSION(x) (((x) >> 4) & 0xf)
#define APCI3120_AO_REG(x) (0x08 + (((x) / 4) * 2))
#define APCI3120_AO_MUX(x) (((x) & 0x3) << 14)
#define APCI3120_AO_DATA(x) ((x) << 0)
* PCI BAR 2 register map (devpriv->addon)
*/
+/*
+ * Board revisions
+ */
+#define APCI3120_REVA 0xa
+#define APCI3120_REVB 0xb
+#define APCI3120_REVA_OSC_BASE 70 /* 70ns = 14.29MHz */
+#define APCI3120_REVB_OSC_BASE 50 /* 50ns = 20MHz */
+
enum apci3120_boardid {
BOARD_APCI3120,
BOARD_APCI3001,
struct apci3120_private {
unsigned long amcc;
unsigned long addon;
+ unsigned int osc_base;
unsigned int ui_AiNbrofChannels;
unsigned int ui_AiChannelList[32];
unsigned int ui_AiReadData[32];
struct task_struct *tsk_Current;
};
+/*
+ * There are three timers on the board. They all use the same base
+ * clock with a fixed prescaler for each timer. The base clock used
+ * depends on the board version and type.
+ *
+ * APCI-3120 Rev A boards OSC = 14.29MHz base clock (~70ns)
+ * APCI-3120 Rev B boards OSC = 20MHz base clock (50ns)
+ * APCI-3001 boards OSC = 20MHz base clock (50ns)
+ *
+ * The prescalers for each timer are:
+ * Timer 0 CLK = OSC/10
+ * Timer 1 CLK = OSC/1000
+ * Timer 2 CLK = OSC/1000
+ */
+static unsigned int apci3120_ns_to_timer(struct comedi_device *dev,
+ unsigned int timer,
+ unsigned int ns,
+ unsigned int flags)
+{
+ struct apci3120_private *devpriv = dev->private;
+ unsigned int prescale = (timer == 0) ? 10 : 1000;
+ unsigned int timer_base = devpriv->osc_base * prescale;
+ unsigned int divisor;
+
+ switch (flags & CMDF_ROUND_MASK) {
+ case CMDF_ROUND_UP:
+ divisor = DIV_ROUND_UP(ns, timer_base);
+ break;
+ case CMDF_ROUND_DOWN:
+ divisor = ns / timer_base;
+ break;
+ case CMDF_ROUND_NEAREST:
+ default:
+ divisor = DIV_ROUND_CLOSEST(ns, timer_base);
+ break;
+ }
+
+ if (timer == 2) {
+ /* timer 2 is 24-bits */
+ if (divisor > 0x00ffffff)
+ divisor = 0x00ffffff;
+ } else {
+ /* timers 0 and 1 are 16-bits */
+ if (divisor > 0xffff)
+ divisor = 0xffff;
+ }
+ /* the timers require a minimum divisor of 2 */
+ if (divisor < 2)
+ divisor = 2;
+
+ return divisor;
+}
+
#include "addi-data/hwdrv_apci3120.c"
static void apci3120_dma_alloc(struct comedi_device *dev)
const struct apci3120_board *this_board = NULL;
struct apci3120_private *devpriv;
struct comedi_subdevice *s;
+ unsigned int status;
int ret;
if (context < ARRAY_SIZE(apci3120_boardtypes))
}
}
+ status = inw(dev->iobase + APCI3120_RD_STATUS);
+ if (APCI3120_STATUS_TO_VERSION(status) == APCI3120_REVB ||
+ context == BOARD_APCI3001)
+ devpriv->osc_base = APCI3120_REVB_OSC_BASE;
+ else
+ devpriv->osc_base = APCI3120_REVA_OSC_BASE;
+
ret = comedi_alloc_subdevices(dev, 5);
if (ret)
return ret;