From 02d1c6e827073ebb65d9f92c169c024ae2d20ddc Mon Sep 17 00:00:00 2001 From: "Spencer E. Olson" Date: Wed, 3 Oct 2018 14:56:07 -0600 Subject: [PATCH] staging: comedi: ni_mio_common: implement output selection of GPFO_{0, 1} Implement the ability to route various signals to NI_CtrOut(x) pin. This pin is also known as GPFO_{0,1} in the DAQ STC. Signed-off-by: Spencer E. Olson Reviewed-by: Ian Abbott Signed-off-by: Greg Kroah-Hartman --- .../staging/comedi/drivers/ni_mio_common.c | 106 ++++++++++++++++++ drivers/staging/comedi/drivers/ni_stc.h | 6 +- 2 files changed, 111 insertions(+), 1 deletion(-) diff --git a/drivers/staging/comedi/drivers/ni_mio_common.c b/drivers/staging/comedi/drivers/ni_mio_common.c index d4c0fd07059b..d0c403a9a226 100644 --- a/drivers/staging/comedi/drivers/ni_mio_common.c +++ b/drivers/staging/comedi/drivers/ni_mio_common.c @@ -5532,6 +5532,77 @@ static void ni_rtsi_init(struct comedi_device *dev) set_rgout0_reg(0, dev); } +/* Get route of GPFO_i/CtrOut pins */ +static inline int ni_get_gout_routing(unsigned int dest, + struct comedi_device *dev) +{ + struct ni_private *devpriv = dev->private; + unsigned int reg = devpriv->an_trig_etc_reg; + + switch (dest) { + case 0: + if (reg & NISTC_ATRIG_ETC_GPFO_0_ENA) + return NISTC_ATRIG_ETC_GPFO_0_SEL_TO_SRC(reg); + break; + case 1: + if (reg & NISTC_ATRIG_ETC_GPFO_1_ENA) + return NISTC_ATRIG_ETC_GPFO_1_SEL_TO_SRC(reg); + break; + } + + return -EINVAL; +} + +/* Set route of GPFO_i/CtrOut pins */ +static inline int ni_disable_gout_routing(unsigned int dest, + struct comedi_device *dev) +{ + struct ni_private *devpriv = dev->private; + + switch (dest) { + case 0: + devpriv->an_trig_etc_reg &= ~NISTC_ATRIG_ETC_GPFO_0_ENA; + break; + case 1: + devpriv->an_trig_etc_reg &= ~NISTC_ATRIG_ETC_GPFO_1_ENA; + break; + default: + return -EINVAL; + } + + ni_stc_writew(dev, devpriv->an_trig_etc_reg, NISTC_ATRIG_ETC_REG); + return 0; +} + +/* Set route of GPFO_i/CtrOut pins */ +static inline int ni_set_gout_routing(unsigned int src, unsigned int dest, + struct comedi_device *dev) +{ + struct ni_private *devpriv = dev->private; + + switch (dest) { + case 0: + /* clear reg */ + devpriv->an_trig_etc_reg &= ~NISTC_ATRIG_ETC_GPFO_0_SEL(-1); + /* set reg */ + devpriv->an_trig_etc_reg |= NISTC_ATRIG_ETC_GPFO_0_ENA + | NISTC_ATRIG_ETC_GPFO_0_SEL(src); + break; + case 1: + /* clear reg */ + devpriv->an_trig_etc_reg &= ~NISTC_ATRIG_ETC_GPFO_1_SEL; + src = src ? NISTC_ATRIG_ETC_GPFO_1_SEL : 0; + /* set reg */ + devpriv->an_trig_etc_reg |= NISTC_ATRIG_ETC_GPFO_1_ENA | src; + break; + default: + return -EINVAL; + } + + ni_stc_writew(dev, devpriv->an_trig_etc_reg, NISTC_ATRIG_ETC_REG); + return 0; +} + /* * Retrieves the current source of the output selector for the given * destination. If the terminal for the destination is not already configured @@ -5563,6 +5634,16 @@ static int get_output_select_source(int dest, struct comedi_device *dev) reg = get_ith_rtsi_brd_reg(i, dev); } } + } else if (dest >= NI_CtrOut(0) && dest <= NI_CtrOut(-1)) { + /* + * not handled by ni_tio. Only available for GPFO registers in + * e/m series. + */ + dest -= NI_CtrOut(0); + if (dest > 1) + /* there are only two g_out outputs. */ + return -EINVAL; + reg = ni_get_gout_routing(dest, dev); } else { dev_dbg(dev->class_dev, "%s: unhandled destination (%d) queried\n", __func__, dest); @@ -5640,6 +5721,17 @@ static int connect_route(unsigned int src, unsigned int dest, ni_set_rtsi_direction(dev, dest, COMEDI_OUTPUT); ni_set_rtsi_routing(dev, dest, reg); + } else if (dest >= NI_CtrOut(0) && dest <= NI_CtrOut(-1)) { + /* + * not handled by ni_tio. Only available for GPFO registers in + * e/m series. + */ + dest -= NI_CtrOut(0); + if (dest > 1) + /* there are only two g_out outputs. */ + return -EINVAL; + if (ni_set_gout_routing(src, dest, dev)) + return -EINVAL; } else { return -EINVAL; } @@ -5688,6 +5780,16 @@ static int disconnect_route(unsigned int src, unsigned int dest, reg = default_rtsi_routing[dest - TRIGGER_LINE(0)]; ni_set_rtsi_direction(dev, dest, COMEDI_INPUT); ni_set_rtsi_routing(dev, dest, reg); + } else if (dest >= NI_CtrOut(0) && dest <= NI_CtrOut(-1)) { + /* + * not handled by ni_tio. Only available for GPFO registers in + * e/m series. + */ + dest -= NI_CtrOut(0); + if (dest > 1) + /* there are only two g_out outputs. */ + return -EINVAL; + reg = ni_disable_gout_routing(dest, dev); } else { return -EINVAL; } @@ -6147,6 +6249,10 @@ static int ni_E_init(struct comedi_device *dev, s->private = gpct; } + /* Initialize GPFO_{0,1} to produce output of counters */ + ni_set_gout_routing(0, 0, dev); /* output of counter 0; DAQ STC, p338 */ + ni_set_gout_routing(0, 1, dev); /* output of counter 1; DAQ STC, p338 */ + /* Frequency output subdevice */ s = &dev->subdevices[NI_FREQ_OUT_SUBDEV]; s->type = COMEDI_SUBD_COUNTER; diff --git a/drivers/staging/comedi/drivers/ni_stc.h b/drivers/staging/comedi/drivers/ni_stc.h index 1867b64e23cf..6c023b40fb53 100644 --- a/drivers/staging/comedi/drivers/ni_stc.h +++ b/drivers/staging/comedi/drivers/ni_stc.h @@ -284,11 +284,15 @@ #define NISTC_ATRIG_ETC_REG 61 #define NISTC_ATRIG_ETC_GPFO_1_ENA BIT(15) #define NISTC_ATRIG_ETC_GPFO_0_ENA BIT(14) -#define NISTC_ATRIG_ETC_GPFO_0_SEL(x) (((x) & 0x3) << 11) +#define NISTC_ATRIG_ETC_GPFO_0_SEL(x) (((x) & 0x7) << 11) +#define NISTC_ATRIG_ETC_GPFO_0_SEL_TO_SRC(x) (((x) >> 11) & 0x7) #define NISTC_ATRIG_ETC_GPFO_1_SEL BIT(7) +#define NISTC_ATRIG_ETC_GPFO_1_SEL_TO_SRC(x) (((x) >> 7) & 0x1) #define NISTC_ATRIG_ETC_DRV BIT(4) #define NISTC_ATRIG_ETC_ENA BIT(3) #define NISTC_ATRIG_ETC_MODE(x) (((x) & 0x7) << 0) +#define NISTC_GPFO_0_G_OUT 0 /* input to GPFO_0_SEL for Ctr0Out */ +#define NISTC_GPFO_1_G_OUT 0 /* input to GPFO_1_SEL for Ctr1Out */ #define NISTC_AI_START_STOP_REG 62 #define NISTC_AI_START_POLARITY BIT(15)