staging: comedi: amplc_dio200: implement timer subdevice
Implement the timer subdevice for the new PCIe boards. The subdevice was previously marked as unused, but was reserved for this purpose. Signed-off-by: Ian Abbott <abbotti@mev.co.uk> Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
This commit is contained in:
parent
87276012ea
commit
18cbf973a9
@ -301,6 +301,8 @@
|
||||
/* Extra registers for new PCIe boards */
|
||||
#define DIO200_ENHANCE 0x20 /* 1 to enable enhanced features */
|
||||
#define DIO200_VERSION 0x24 /* Hardware version register */
|
||||
#define DIO200_TS_CONFIG 0x600 /* Timestamp timer config register */
|
||||
#define DIO200_TS_COUNT 0x602 /* Timestamp timer count register */
|
||||
|
||||
/*
|
||||
* Functions for constructing value for DIO_200_?CLK_SCE and
|
||||
@ -342,6 +344,22 @@ static const unsigned int clock_period[32] = {
|
||||
/* clock sources 12 and later reserved for enhanced boards */
|
||||
};
|
||||
|
||||
/*
|
||||
* Timestamp timer configuration register (for new PCIe boards).
|
||||
*/
|
||||
#define TS_CONFIG_RESET 0x100 /* Reset counter to zero. */
|
||||
#define TS_CONFIG_CLK_SRC_MASK 0x0FF /* Clock source. */
|
||||
#define TS_CONFIG_MAX_CLK_SRC 2 /* Maximum clock source value. */
|
||||
|
||||
/*
|
||||
* Periods of the timestamp timer clock sources in nanoseconds.
|
||||
*/
|
||||
static const unsigned int ts_clock_period[TS_CONFIG_MAX_CLK_SRC + 1] = {
|
||||
1, /* 1 nanosecond (but with 20 ns granularity). */
|
||||
1000, /* 1 microsecond. */
|
||||
1000000, /* 1 millisecond. */
|
||||
};
|
||||
|
||||
/*
|
||||
* Register region.
|
||||
*/
|
||||
@ -1621,6 +1639,118 @@ static void dio200_subdev_8255_cleanup(struct comedi_device *dev,
|
||||
kfree(subpriv);
|
||||
}
|
||||
|
||||
/*
|
||||
* Handle 'insn_read' for a timer subdevice.
|
||||
*/
|
||||
static int dio200_subdev_timer_read(struct comedi_device *dev,
|
||||
struct comedi_subdevice *s,
|
||||
struct comedi_insn *insn,
|
||||
unsigned int *data)
|
||||
{
|
||||
unsigned int n;
|
||||
|
||||
for (n = 0; n < insn->n; n++)
|
||||
data[n] = dio200_read32(dev, DIO200_TS_COUNT);
|
||||
return n;
|
||||
}
|
||||
|
||||
/*
|
||||
* Reset timer subdevice.
|
||||
*/
|
||||
static void dio200_subdev_timer_reset(struct comedi_device *dev,
|
||||
struct comedi_subdevice *s)
|
||||
{
|
||||
unsigned int clock;
|
||||
|
||||
clock = dio200_read32(dev, DIO200_TS_CONFIG) & TS_CONFIG_CLK_SRC_MASK;
|
||||
dio200_write32(dev, DIO200_TS_CONFIG, clock | TS_CONFIG_RESET);
|
||||
dio200_write32(dev, DIO200_TS_CONFIG, clock);
|
||||
}
|
||||
|
||||
/*
|
||||
* Get timer subdevice clock source and period.
|
||||
*/
|
||||
static void dio200_subdev_timer_get_clock_src(struct comedi_device *dev,
|
||||
struct comedi_subdevice *s,
|
||||
unsigned int *src,
|
||||
unsigned int *period)
|
||||
{
|
||||
unsigned int clk;
|
||||
|
||||
clk = dio200_read32(dev, DIO200_TS_CONFIG) & TS_CONFIG_CLK_SRC_MASK;
|
||||
*src = clk;
|
||||
*period = (clk < ARRAY_SIZE(ts_clock_period)) ?
|
||||
ts_clock_period[clk] : 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Set timer subdevice clock source.
|
||||
*/
|
||||
static int dio200_subdev_timer_set_clock_src(struct comedi_device *dev,
|
||||
struct comedi_subdevice *s,
|
||||
unsigned int src)
|
||||
{
|
||||
if (src > TS_CONFIG_MAX_CLK_SRC)
|
||||
return -EINVAL;
|
||||
dio200_write32(dev, DIO200_TS_CONFIG, src);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Handle 'insn_config' for a timer subdevice.
|
||||
*/
|
||||
static int dio200_subdev_timer_config(struct comedi_device *dev,
|
||||
struct comedi_subdevice *s,
|
||||
struct comedi_insn *insn,
|
||||
unsigned int *data)
|
||||
{
|
||||
int ret = 0;
|
||||
|
||||
switch (data[0]) {
|
||||
case INSN_CONFIG_RESET:
|
||||
dio200_subdev_timer_reset(dev, s);
|
||||
break;
|
||||
case INSN_CONFIG_SET_CLOCK_SRC:
|
||||
ret = dio200_subdev_timer_set_clock_src(dev, s, data[1]);
|
||||
if (ret < 0)
|
||||
ret = -EINVAL;
|
||||
break;
|
||||
case INSN_CONFIG_GET_CLOCK_SRC:
|
||||
dio200_subdev_timer_get_clock_src(dev, s, &data[1], &data[2]);
|
||||
break;
|
||||
default:
|
||||
ret = -EINVAL;
|
||||
break;
|
||||
}
|
||||
return ret < 0 ? ret : insn->n;
|
||||
}
|
||||
|
||||
/*
|
||||
* This function initializes a timer subdevice.
|
||||
*
|
||||
* Uses the timestamp timer registers. There is only one timestamp timer.
|
||||
*/
|
||||
static int dio200_subdev_timer_init(struct comedi_device *dev,
|
||||
struct comedi_subdevice *s)
|
||||
{
|
||||
s->type = COMEDI_SUBD_TIMER;
|
||||
s->subdev_flags = SDF_READABLE | SDF_LSAMPL;
|
||||
s->n_chan = 1;
|
||||
s->maxdata = 0xFFFFFFFF;
|
||||
s->insn_read = dio200_subdev_timer_read;
|
||||
s->insn_config = dio200_subdev_timer_config;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* This function cleans up a timer subdevice.
|
||||
*/
|
||||
static void dio200_subdev_timer_cleanup(struct comedi_device *dev,
|
||||
struct comedi_subdevice *s)
|
||||
{
|
||||
/* Nothing to do. */
|
||||
}
|
||||
|
||||
/*
|
||||
* This function does some special set-up for the PCIe boards
|
||||
* PCIe215, PCIe236, PCIe296.
|
||||
@ -1735,7 +1865,15 @@ static int dio200_common_attach(struct comedi_device *dev, unsigned int irq,
|
||||
}
|
||||
break;
|
||||
case sd_timer:
|
||||
/* TODO. Fall-thru to default for now. */
|
||||
/* Only on PCIe boards. */
|
||||
if (DO_PCI) {
|
||||
ret = dio200_subdev_timer_init(dev, s);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
} else {
|
||||
s->type = COMEDI_SUBD_UNUSED;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
s->type = COMEDI_SUBD_UNUSED;
|
||||
break;
|
||||
@ -1897,6 +2035,11 @@ static void dio200_detach(struct comedi_device *dev)
|
||||
case sd_intr:
|
||||
dio200_subdev_intr_cleanup(dev, s);
|
||||
break;
|
||||
case sd_timer:
|
||||
/* Only on PCIe boards. */
|
||||
if (DO_PCI)
|
||||
dio200_subdev_timer_cleanup(dev, s);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user