Commit 6d312740 authored by H Hartley Sweeten's avatar H Hartley Sweeten Committed by Greg Kroah-Hartman

staging: comedi: addi_apci_3120: fix timer (*insn_config)

The timer subdevice in this driver does not follow the comedi API.

Fix the (*insn_config) to correctly arm, disarm, set the mode, and
get the status of the timer.

Remove the unnecessary, and broken, (*insn_write).

The new (*insn_config) does not enable the interrupt for timer 2.
Remove the interrupt support code for the timer.
Signed-off-by: default avatarH Hartley Sweeten <hsweeten@visionengravers.com>
Reviewed-by: default avatarIan Abbott <abbotti@mev.co.uk>
Signed-off-by: default avatarGreg Kroah-Hartman <gregkh@linuxfoundation.org>
parent 15cf0617
...@@ -40,19 +40,6 @@ This program is distributed in the hope that it will be useful, but WITHOUT ANY ...@@ -40,19 +40,6 @@ This program is distributed in the hope that it will be useful, but WITHOUT ANY
+----------+-----------+------------------------------------------------+ +----------+-----------+------------------------------------------------+
*/ */
#define APCI3120_START 1
#define APCI3120_STOP 0
/* TIMER DEFINE */
#define APCI3120_QUARTZ_A 70
#define APCI3120_QUARTZ_B 50
#define APCI3120_TIMER 1
#define APCI3120_WATCHDOG 2
#define APCI3120_TIMER_DISABLE 0
#define APCI3120_TIMER_ENABLE 1
#define APCI3120_COUNTER 3
static void apci3120_addon_write(struct comedi_device *dev, static void apci3120_addon_write(struct comedi_device *dev,
unsigned int val, unsigned int reg) unsigned int val, unsigned int reg)
{ {
...@@ -385,8 +372,6 @@ static irqreturn_t apci3120_interrupt(int irq, void *d) ...@@ -385,8 +372,6 @@ static irqreturn_t apci3120_interrupt(int irq, void *d)
if (devpriv->ctrl & APCI3120_CTRL_EXT_TRIG) if (devpriv->ctrl & APCI3120_CTRL_EXT_TRIG)
apci3120_exttrig_enable(dev, false); apci3120_exttrig_enable(dev, false);
apci3120_clr_timer2_interrupt(dev);
if (int_amcc & MASTER_ABORT_INT) if (int_amcc & MASTER_ABORT_INT)
dev_err(dev->class_dev, "AMCC IRQ - MASTER DMA ABORT!\n"); dev_err(dev->class_dev, "AMCC IRQ - MASTER DMA ABORT!\n");
if (int_amcc & TARGET_ABORT_INT) if (int_amcc & TARGET_ABORT_INT)
...@@ -412,28 +397,10 @@ static irqreturn_t apci3120_interrupt(int irq, void *d) ...@@ -412,28 +397,10 @@ static irqreturn_t apci3120_interrupt(int irq, void *d)
} }
if (status & APCI3120_STATUS_TIMER2_INT) { if (status & APCI3120_STATUS_TIMER2_INT) {
switch (devpriv->b_Timer2Mode) { /*
case APCI3120_COUNTER: * for safety...
break; * timer2 interrupts are not enabled in the driver
*/
case APCI3120_TIMER:
/* Send a signal to from kernel to user space */
send_sig(SIGIO, devpriv->tsk_Current, 0);
break;
case APCI3120_WATCHDOG:
/* Send a signal to from kernel to user space */
send_sig(SIGIO, devpriv->tsk_Current, 0);
break;
default:
/* disable Timer Interrupt */
devpriv->mode &= ~APCI3120_MODE_TIMER2_IRQ_ENA;
outb(devpriv->mode, dev->iobase + APCI3120_MODE_REG);
}
apci3120_clr_timer2_interrupt(dev); apci3120_clr_timer2_interrupt(dev);
} }
...@@ -441,8 +408,6 @@ static irqreturn_t apci3120_interrupt(int irq, void *d) ...@@ -441,8 +408,6 @@ static irqreturn_t apci3120_interrupt(int irq, void *d)
/* AMCC- Clear write complete interrupt (DMA) */ /* AMCC- Clear write complete interrupt (DMA) */
outl(AINT_WT_COMPLETE, devpriv->amcc + AMCC_OP_REG_INTCSR); outl(AINT_WT_COMPLETE, devpriv->amcc + AMCC_OP_REG_INTCSR);
apci3120_clr_timer2_interrupt(dev);
/* do some data transfer */ /* do some data transfer */
apci3120_interrupt_dma(irq, d); apci3120_interrupt_dma(irq, d);
} }
...@@ -454,157 +419,3 @@ static irqreturn_t apci3120_interrupt(int irq, void *d) ...@@ -454,157 +419,3 @@ static irqreturn_t apci3120_interrupt(int irq, void *d)
return IRQ_HANDLED; return IRQ_HANDLED;
} }
/*
* Configure Timer 2
*
* data[0] = TIMER configure as timer
* = WATCHDOG configure as watchdog
* data[1] = Timer constant
* data[2] = Timer2 interrupt (1)enable or(0) disable
*/
static int apci3120_config_insn_timer(struct comedi_device *dev,
struct comedi_subdevice *s,
struct comedi_insn *insn,
unsigned int *data)
{
struct apci3120_private *devpriv = dev->private;
unsigned int divisor;
if (!data[1])
dev_err(dev->class_dev, "No timer constant!\n");
devpriv->b_Timer2Interrupt = (unsigned char) data[2]; /* save info whether to enable or disable interrupt */
divisor = apci3120_ns_to_timer(dev, 2, data[1], CMDF_ROUND_DOWN);
apci3120_timer_enable(dev, 2, false);
/* disable timer 2 interrupt and reset operation mode (timer) */
devpriv->mode &= ~APCI3120_MODE_TIMER2_IRQ_ENA &
~APCI3120_MODE_TIMER2_AS_MASK;
/* Disable Eoc and Eos Interrupts */
devpriv->mode &= ~APCI3120_MODE_EOC_IRQ_ENA &
~APCI3120_MODE_EOS_IRQ_ENA;
outb(devpriv->mode, dev->iobase + APCI3120_MODE_REG);
if (data[0] == APCI3120_TIMER) { /* initialize timer */
/* Set the Timer 2 in mode 2(Timer) */
apci3120_timer_set_mode(dev, 2, APCI3120_TIMER_MODE2);
/* Set timer 2 delay */
apci3120_timer_write(dev, 2, divisor);
/* timer2 in Timer mode enabled */
devpriv->b_Timer2Mode = APCI3120_TIMER;
} else { /* Initialize Watch dog */
/* Set the Timer 2 in mode 5(Watchdog) */
apci3120_timer_set_mode(dev, 2, APCI3120_TIMER_MODE5);
/* Set timer 2 delay */
apci3120_timer_write(dev, 2, divisor);
/* watchdog enabled */
devpriv->b_Timer2Mode = APCI3120_WATCHDOG;
}
return insn->n;
}
/*
* To start and stop the timer
*
* data[0] = 1 (start)
* = 0 (stop)
* = 2 (write new value)
* data[1] = new value
*
* devpriv->b_Timer2Mode = 0 DISABLE
* = 1 Timer
* = 2 Watch dog
*/
static int apci3120_write_insn_timer(struct comedi_device *dev,
struct comedi_subdevice *s,
struct comedi_insn *insn,
unsigned int *data)
{
struct apci3120_private *devpriv = dev->private;
unsigned int divisor;
if ((devpriv->b_Timer2Mode != APCI3120_WATCHDOG)
&& (devpriv->b_Timer2Mode != APCI3120_TIMER)) {
dev_err(dev->class_dev, "timer2 not configured\n");
return -EINVAL;
}
if (data[0] == 2) { /* write new value */
if (devpriv->b_Timer2Mode != APCI3120_TIMER) {
dev_err(dev->class_dev,
"timer2 not configured in TIMER MODE\n");
return -EINVAL;
}
}
switch (data[0]) {
case APCI3120_START:
apci3120_clr_timer2_interrupt(dev);
if (devpriv->b_Timer2Mode == APCI3120_TIMER) { /* start timer */
/* Enable Timer */
devpriv->mode &= 0x0b;
devpriv->mode |= APCI3120_MODE_TIMER2_AS_TIMER;
} else { /* start watch dog */
/* Enable WatchDog */
devpriv->mode &= 0x0b;
devpriv->mode |= APCI3120_MODE_TIMER2_AS_WDOG;
}
/* enable disable interrupt */
if (devpriv->b_Timer2Interrupt) {
devpriv->mode |= APCI3120_MODE_TIMER2_IRQ_ENA;
/* save the task structure to pass info to user */
devpriv->tsk_Current = current;
} else {
devpriv->mode &= ~APCI3120_MODE_TIMER2_IRQ_ENA;
}
outb(devpriv->mode, dev->iobase + APCI3120_MODE_REG);
/* start timer */
if (devpriv->b_Timer2Mode == APCI3120_TIMER)
apci3120_timer_enable(dev, 2, true);
break;
case APCI3120_STOP:
/* disable timer 2 interrupt and reset operation mode (timer) */
devpriv->mode &= ~APCI3120_MODE_TIMER2_IRQ_ENA &
~APCI3120_MODE_TIMER2_AS_MASK;
outb(devpriv->mode, dev->iobase + APCI3120_MODE_REG);
apci3120_timer_enable(dev, 2, false);
apci3120_clr_timer2_interrupt(dev);
break;
case 2: /* write new value to Timer */
if (devpriv->b_Timer2Mode != APCI3120_TIMER) {
dev_err(dev->class_dev,
"timer2 not configured in TIMER MODE\n");
return -EINVAL;
}
divisor = apci3120_ns_to_timer(dev, 2, data[1],
CMDF_ROUND_DOWN);
/* Set timer 2 delay */
apci3120_timer_write(dev, 2, divisor);
break;
default:
return -EINVAL; /* Not a valid input */
}
return insn->n;
}
...@@ -139,9 +139,6 @@ struct apci3120_private { ...@@ -139,9 +139,6 @@ struct apci3120_private {
unsigned char timer_mode; unsigned char timer_mode;
unsigned char mode; unsigned char mode;
unsigned short ctrl; unsigned short ctrl;
unsigned char b_Timer2Mode;
unsigned char b_Timer2Interrupt;
struct task_struct *tsk_Current;
}; };
/* /*
...@@ -447,6 +444,83 @@ static int apci3120_do_insn_bits(struct comedi_device *dev, ...@@ -447,6 +444,83 @@ static int apci3120_do_insn_bits(struct comedi_device *dev,
return insn->n; return insn->n;
} }
static int apci3120_timer_insn_config(struct comedi_device *dev,
struct comedi_subdevice *s,
struct comedi_insn *insn,
unsigned int *data)
{
struct apci3120_private *devpriv = dev->private;
unsigned int divisor;
unsigned int status;
unsigned int mode;
unsigned int timer_mode;
switch (data[0]) {
case INSN_CONFIG_ARM:
apci3120_clr_timer2_interrupt(dev);
divisor = apci3120_ns_to_timer(dev, 2, data[1],
CMDF_ROUND_DOWN);
apci3120_timer_write(dev, 2, divisor);
apci3120_timer_enable(dev, 2, true);
break;
case INSN_CONFIG_DISARM:
apci3120_timer_enable(dev, 2, false);
apci3120_clr_timer2_interrupt(dev);
break;
case INSN_CONFIG_GET_COUNTER_STATUS:
data[1] = 0;
data[2] = COMEDI_COUNTER_ARMED | COMEDI_COUNTER_COUNTING |
COMEDI_COUNTER_TERMINAL_COUNT;
if (devpriv->ctrl & APCI3120_CTRL_GATE(2)) {
data[1] |= COMEDI_COUNTER_ARMED;
data[1] |= COMEDI_COUNTER_COUNTING;
}
status = inw(dev->iobase + APCI3120_STATUS_REG);
if (status & APCI3120_STATUS_TIMER2_INT) {
data[1] &= ~COMEDI_COUNTER_COUNTING;
data[1] |= COMEDI_COUNTER_TERMINAL_COUNT;
}
break;
case INSN_CONFIG_SET_COUNTER_MODE:
switch (data[1]) {
case I8254_MODE0:
mode = APCI3120_MODE_TIMER2_AS_COUNTER;
timer_mode = APCI3120_TIMER_MODE0;
break;
case I8254_MODE2:
mode = APCI3120_MODE_TIMER2_AS_TIMER;
timer_mode = APCI3120_TIMER_MODE2;
break;
case I8254_MODE4:
mode = APCI3120_MODE_TIMER2_AS_TIMER;
timer_mode = APCI3120_TIMER_MODE4;
break;
case I8254_MODE5:
mode = APCI3120_MODE_TIMER2_AS_WDOG;
timer_mode = APCI3120_TIMER_MODE5;
break;
default:
return -EINVAL;
}
apci3120_timer_enable(dev, 2, false);
apci3120_clr_timer2_interrupt(dev);
apci3120_timer_set_mode(dev, 2, timer_mode);
devpriv->mode &= ~APCI3120_MODE_TIMER2_AS_MASK;
devpriv->mode |= mode;
outb(devpriv->mode, dev->iobase + APCI3120_MODE_REG);
break;
default:
return -EINVAL;
}
return insn->n;
}
static int apci3120_timer_insn_read(struct comedi_device *dev, static int apci3120_timer_insn_read(struct comedi_device *dev,
struct comedi_subdevice *s, struct comedi_subdevice *s,
struct comedi_insn *insn, struct comedi_insn *insn,
...@@ -627,11 +701,10 @@ static int apci3120_auto_attach(struct comedi_device *dev, ...@@ -627,11 +701,10 @@ static int apci3120_auto_attach(struct comedi_device *dev,
/* Timer subdevice */ /* Timer subdevice */
s = &dev->subdevices[4]; s = &dev->subdevices[4];
s->type = COMEDI_SUBD_TIMER; s->type = COMEDI_SUBD_TIMER;
s->subdev_flags = SDF_WRITABLE | SDF_READABLE; s->subdev_flags = SDF_READABLE;
s->n_chan = 1; s->n_chan = 1;
s->maxdata = 0x00ffffff; s->maxdata = 0x00ffffff;
s->insn_write = apci3120_write_insn_timer; s->insn_config = apci3120_timer_insn_config;
s->insn_config = apci3120_config_insn_timer;
s->insn_read = apci3120_timer_insn_read; s->insn_read = apci3120_timer_insn_read;
return 0; return 0;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment