All of lore.kernel.org
 help / color / mirror / Atom feed
From: Syed Nayyar Waris <syednwaris@gmail.com>
To: William Breathitt Gray <vilhelm.gray@gmail.com>
Cc: jic23@kernel.org, kernel@pengutronix.de,
	linux-stm32@st-md-mailman.stormreply.com,
	a.fatoum@pengutronix.de, kamel.bouhara@bootlin.com,
	gwendal@chromium.org, alexandre.belloni@bootlin.com,
	david@lechnology.com, linux-iio@vger.kernel.org,
	linux-kernel@vger.kernel.org,
	linux-arm-kernel@lists.infradead.org,
	patrick.havelange@essensium.com, fabrice.gasnier@st.com,
	mcoquelin.stm32@gmail.com, alexandre.torgue@st.com,
	o.rempel@pengutronix.de
Subject: Re: [PATCH v10 33/33] counter: 104-quad-8: Add IRQ support for the ACCES 104-QUAD-8
Date: Thu, 15 Apr 2021 20:55:03 +0530	[thread overview]
Message-ID: <20210415152503.GL8933@syed> (raw)
In-Reply-To: <24f0eacf6d2e320c2ed1bc20e07a6e723da75737.1616150619.git.vilhelm.gray@gmail.com>

On Fri, Mar 19, 2021 at 08:00:52PM +0900, William Breathitt Gray wrote:
> The LSI/CSI LS7266R1 chip provides programmable output via the FLG pins.
> When interrupts are enabled on the ACCES 104-QUAD-8, they occur whenever
> FLG1 is active. Four functions are available for the FLG1 signal: Carry,
> Compare, Carry-Borrow, and Index.
> 
> 	Carry:
> 		Interrupt generated on active low Carry signal. Carry
> 		signal toggles every time the respective channel's
> 		counter overflows.
> 
> 	Compare:
> 		Interrupt generated on active low Compare signal.
> 		Compare signal toggles every time respective channel's
> 		preset register is equal to the respective channel's
> 		counter.
> 
> 	Carry-Borrow:
> 		Interrupt generated on active low Carry signal and
> 		active low Borrow signal. Carry signal toggles every
> 		time the respective channel's counter overflows. Borrow
> 		signal toggles every time the respective channel's
> 		counter underflows.
> 
> 	Index:
> 		Interrupt generated on active high Index signal.
> 
> These four functions correspond respectivefly to the following four
> Counter event types: COUNTER_EVENT_OVERFLOW, COUNTER_EVENT_THRESHOLD,
> COUNTER_EVENT_OVERFLOW_UNDERFLOW, and COUNTER_EVENT_INDEX. Interrupts
> push Counter events to event channel X, where 'X' is the respective
> channel whose FLG1 activated.
> 
> This patch adds IRQ support for the ACCES 104-QUAD-8. The interrupt line
> numbers for the devices may be configured via the irq array module
> parameter.
> 
> Cc: Syed Nayyar Waris <syednwaris@gmail.com>
> Signed-off-by: William Breathitt Gray <vilhelm.gray@gmail.com>
> ---
>  drivers/counter/104-quad-8.c | 167 +++++++++++++++++++++++++++++++++--
>  drivers/counter/Kconfig      |   6 +-
>  2 files changed, 164 insertions(+), 9 deletions(-)

Acked-by: Syed Nayyar Waris <syednwaris@gmail.com>

> 
> diff --git a/drivers/counter/104-quad-8.c b/drivers/counter/104-quad-8.c
> index d46b8101f207..09b0b0ba8fe7 100644
> --- a/drivers/counter/104-quad-8.c
> +++ b/drivers/counter/104-quad-8.c
> @@ -11,6 +11,7 @@
>  #include <linux/errno.h>
>  #include <linux/io.h>
>  #include <linux/ioport.h>
> +#include <linux/interrupt.h>
>  #include <linux/isa.h>
>  #include <linux/kernel.h>
>  #include <linux/module.h>
> @@ -25,6 +26,10 @@ static unsigned int num_quad8;
>  module_param_hw_array(base, uint, ioport, &num_quad8, 0);
>  MODULE_PARM_DESC(base, "ACCES 104-QUAD-8 base addresses");
>  
> +static unsigned int irq[max_num_isa_dev(QUAD8_EXTENT)];
> +module_param_hw_array(irq, uint, irq, NULL, 0);
> +MODULE_PARM_DESC(irq, "ACCES 104-QUAD-8 interrupt line numbers");
> +
>  #define QUAD8_NUM_COUNTERS 8
>  
>  /**
> @@ -38,6 +43,8 @@ MODULE_PARM_DESC(base, "ACCES 104-QUAD-8 base addresses");
>   * @quadrature_scale:	array of quadrature mode scale configurations
>   * @ab_enable:		array of A and B inputs enable configurations
>   * @preset_enable:	array of set_to_preset_on_index attribute configurations
> + * @irq_trigger:	array of current IRQ trigger function configurations
> + * @next_irq_trigger:	array of next IRQ trigger function configurations
>   * @synchronous_mode:	array of index function synchronous mode configurations
>   * @index_polarity:	array of index function polarity configurations
>   * @cable_fault_enable:	differential encoder cable status enable configurations
> @@ -53,13 +60,17 @@ struct quad8 {
>  	unsigned int quadrature_scale[QUAD8_NUM_COUNTERS];
>  	unsigned int ab_enable[QUAD8_NUM_COUNTERS];
>  	unsigned int preset_enable[QUAD8_NUM_COUNTERS];
> +	unsigned int irq_trigger[QUAD8_NUM_COUNTERS];
> +	unsigned int next_irq_trigger[QUAD8_NUM_COUNTERS];
>  	unsigned int synchronous_mode[QUAD8_NUM_COUNTERS];
>  	unsigned int index_polarity[QUAD8_NUM_COUNTERS];
>  	unsigned int cable_fault_enable;
>  	unsigned int base;
>  };
>  
> +#define QUAD8_REG_INTERRUPT_STATUS 0x10
>  #define QUAD8_REG_CHAN_OP 0x11
> +#define QUAD8_REG_INDEX_INTERRUPT 0x12
>  #define QUAD8_REG_INDEX_INPUT_LEVELS 0x16
>  #define QUAD8_DIFF_ENCODER_CABLE_STATUS 0x17
>  /* Borrow Toggle flip-flop */
> @@ -92,8 +103,8 @@ struct quad8 {
>  #define QUAD8_RLD_CNTR_OUT 0x10
>  /* Transfer Preset Register LSB to FCK Prescaler */
>  #define QUAD8_RLD_PRESET_PSC 0x18
> -#define QUAD8_CHAN_OP_ENABLE_COUNTERS 0x00
>  #define QUAD8_CHAN_OP_RESET_COUNTERS 0x01
> +#define QUAD8_CHAN_OP_ENABLE_INTERRUPT_FUNC 0x04
>  #define QUAD8_CMR_QUADRATURE_X1 0x08
>  #define QUAD8_CMR_QUADRATURE_X2 0x10
>  #define QUAD8_CMR_QUADRATURE_X4 0x18
> @@ -378,13 +389,103 @@ static int quad8_action_read(struct counter_device *counter,
>  	}
>  }
>  
> +enum {
> +	QUAD8_EVENT_NONE = -1,
> +	QUAD8_EVENT_CARRY = 0,
> +	QUAD8_EVENT_COMPARE = 1,
> +	QUAD8_EVENT_CARRY_BORROW = 2,
> +	QUAD8_EVENT_INDEX = 3,
> +};
> +
> +static int quad8_events_configure(struct counter_device *counter)
> +{
> +	struct quad8 *const priv = counter->priv;
> +	unsigned long irq_enabled = 0;
> +	unsigned long irqflags;
> +	size_t channel;
> +	unsigned long ior_cfg;
> +	unsigned long base_offset;
> +
> +	spin_lock_irqsave(&priv->lock, irqflags);
> +
> +	/* Enable interrupts for the requested channels, disable for the rest */
> +	for (channel = 0; channel < QUAD8_NUM_COUNTERS; channel++) {
> +		if (priv->next_irq_trigger[channel] == QUAD8_EVENT_NONE)
> +			continue;
> +
> +		if (priv->irq_trigger[channel] != priv->next_irq_trigger[channel]) {
> +			/* Save new IRQ function configuration */
> +			priv->irq_trigger[channel] = priv->next_irq_trigger[channel];
> +
> +			/* Load configuration to I/O Control Register */
> +			ior_cfg = priv->ab_enable[channel] |
> +				  priv->preset_enable[channel] << 1 |
> +				  priv->irq_trigger[channel] << 3;
> +			base_offset = priv->base + 2 * channel + 1;
> +			outb(QUAD8_CTR_IOR | ior_cfg, base_offset);
> +		}
> +
> +		/* Reset next IRQ trigger function configuration */
> +		priv->next_irq_trigger[channel] = QUAD8_EVENT_NONE;
> +
> +		/* Enable IRQ line */
> +		irq_enabled |= BIT(channel);
> +	}
> +
> +	outb(irq_enabled, priv->base + QUAD8_REG_INDEX_INTERRUPT);
> +
> +	spin_unlock_irqrestore(&priv->lock, irqflags);
> +
> +	return 0;
> +}
> +
> +static int quad8_watch_validate(struct counter_device *counter,
> +				const struct counter_watch *watch)
> +{
> +	struct quad8 *const priv = counter->priv;
> +
> +	if (watch->channel > QUAD8_NUM_COUNTERS - 1)
> +		return -EINVAL;
> +
> +	switch (watch->event) {
> +	case COUNTER_EVENT_OVERFLOW:
> +		if (priv->next_irq_trigger[watch->channel] == QUAD8_EVENT_NONE)
> +			priv->next_irq_trigger[watch->channel] = QUAD8_EVENT_CARRY;
> +		else if (priv->next_irq_trigger[watch->channel] != QUAD8_EVENT_CARRY)
> +			return -EINVAL;
> +		return 0;
> +	case COUNTER_EVENT_THRESHOLD:
> +		if (priv->next_irq_trigger[watch->channel] == QUAD8_EVENT_NONE)
> +			priv->next_irq_trigger[watch->channel] = QUAD8_EVENT_COMPARE;
> +		else if (priv->next_irq_trigger[watch->channel] != QUAD8_EVENT_COMPARE)
> +			return -EINVAL;
> +		return 0;
> +	case COUNTER_EVENT_OVERFLOW_UNDERFLOW:
> +		if (priv->next_irq_trigger[watch->channel] == QUAD8_EVENT_NONE)
> +			priv->next_irq_trigger[watch->channel] = QUAD8_EVENT_CARRY_BORROW;
> +		else if (priv->next_irq_trigger[watch->channel] != QUAD8_EVENT_CARRY_BORROW)
> +			return -EINVAL;
> +		return 0;
> +	case COUNTER_EVENT_INDEX:
> +		if (priv->next_irq_trigger[watch->channel] == QUAD8_EVENT_NONE)
> +			priv->next_irq_trigger[watch->channel] = QUAD8_EVENT_INDEX;
> +		else if (priv->next_irq_trigger[watch->channel] != QUAD8_EVENT_INDEX)
> +			return -EINVAL;
> +		return 0;
> +	default:
> +		return -EINVAL;
> +	}
> +}
> +
>  static const struct counter_ops quad8_ops = {
>  	.signal_read = quad8_signal_read,
>  	.count_read = quad8_count_read,
>  	.count_write = quad8_count_write,
>  	.function_read = quad8_function_read,
>  	.function_write = quad8_function_write,
> -	.action_read = quad8_action_read
> +	.action_read = quad8_action_read,
> +	.events_configure = quad8_events_configure,
> +	.watch_validate = quad8_watch_validate,
>  };
>  
>  static const char *const quad8_index_polarity_modes[] = {
> @@ -579,7 +680,8 @@ static int quad8_count_enable_write(struct counter_device *counter,
>  
>  	priv->ab_enable[count->id] = enable;
>  
> -	ior_cfg = enable | priv->preset_enable[count->id] << 1;
> +	ior_cfg = enable | priv->preset_enable[count->id] << 1 |
> +		  priv->irq_trigger[count->id] << 3;
>  
>  	/* Load I/O control configuration */
>  	outb(QUAD8_CTR_IOR | ior_cfg, base_offset + 1);
> @@ -728,7 +830,8 @@ static int quad8_count_preset_enable_write(struct counter_device *counter,
>  
>  	priv->preset_enable[count->id] = preset_enable;
>  
> -	ior_cfg = priv->ab_enable[count->id] | preset_enable << 1;
> +	ior_cfg = priv->ab_enable[count->id] | preset_enable << 1 |
> +		  priv->irq_trigger[count->id] << 3;
>  
>  	/* Load I/O control configuration to Input / Output Control Register */
>  	outb(QUAD8_CTR_IOR | ior_cfg, base_offset);
> @@ -980,11 +1083,54 @@ static struct counter_count quad8_counts[] = {
>  	QUAD8_COUNT(7, "Channel 8 Count")
>  };
>  
> +static irqreturn_t quad8_irq_handler(int irq, void *private)
> +{
> +	struct quad8 *const priv = private;
> +	const unsigned long base = priv->base;
> +	unsigned long irq_status;
> +	unsigned long channel;
> +	u8 event;
> +
> +	irq_status = inb(base + QUAD8_REG_INTERRUPT_STATUS);
> +	if (!irq_status)
> +		return IRQ_NONE;
> +
> +	for_each_set_bit(channel, &irq_status, QUAD8_NUM_COUNTERS) {
> +		switch (priv->irq_trigger[channel]) {
> +		case QUAD8_EVENT_CARRY:
> +			event = COUNTER_EVENT_OVERFLOW;
> +				break;
> +		case QUAD8_EVENT_COMPARE:
> +			event = COUNTER_EVENT_THRESHOLD;
> +				break;
> +		case QUAD8_EVENT_CARRY_BORROW:
> +			event = COUNTER_EVENT_OVERFLOW_UNDERFLOW;
> +				break;
> +		case QUAD8_EVENT_INDEX:
> +			event = COUNTER_EVENT_INDEX;
> +				break;
> +		default:
> +			/* should never reach this path */
> +			WARN_ONCE(true, "invalid interrupt trigger function %u configured for channel %lu\n",
> +				  priv->irq_trigger[channel], channel);
> +			continue;
> +		}
> +
> +		counter_push_event(&priv->counter, event, channel);
> +	}
> +
> +	/* Clear pending interrupts on device */
> +	outb(QUAD8_CHAN_OP_ENABLE_INTERRUPT_FUNC, base + QUAD8_REG_CHAN_OP);
> +
> +	return IRQ_HANDLED;
> +}
> +
>  static int quad8_probe(struct device *dev, unsigned int id)
>  {
>  	struct quad8 *priv;
>  	int i, j;
>  	unsigned int base_offset;
> +	int err;
>  
>  	if (!devm_request_region(dev, base[id], QUAD8_EXTENT, dev_name(dev))) {
>  		dev_err(dev, "Unable to lock port addresses (0x%X-0x%X)\n",
> @@ -1009,6 +1155,8 @@ static int quad8_probe(struct device *dev, unsigned int id)
>  
>  	spin_lock_init(&priv->lock);
>  
> +	/* Reset Index/Interrupt Register */
> +	outb(0x00, base[id] + QUAD8_REG_INDEX_INTERRUPT);
>  	/* Reset all counters and disable interrupt function */
>  	outb(QUAD8_CHAN_OP_RESET_COUNTERS, base[id] + QUAD8_REG_CHAN_OP);
>  	/* Set initial configuration for all counters */
> @@ -1035,11 +1183,18 @@ static int quad8_probe(struct device *dev, unsigned int id)
>  		outb(QUAD8_CTR_IOR, base_offset + 1);
>  		/* Disable index function; negative index polarity */
>  		outb(QUAD8_CTR_IDR, base_offset + 1);
> +		/* Initialize next IRQ trigger function configuration */
> +		priv->next_irq_trigger[i] = QUAD8_EVENT_NONE;
>  	}
>  	/* Disable Differential Encoder Cable Status for all channels */
>  	outb(0xFF, base[id] + QUAD8_DIFF_ENCODER_CABLE_STATUS);
> -	/* Enable all counters */
> -	outb(QUAD8_CHAN_OP_ENABLE_COUNTERS, base[id] + QUAD8_REG_CHAN_OP);
> +	/* Enable all counters and enable interrupt function */
> +	outb(QUAD8_CHAN_OP_ENABLE_INTERRUPT_FUNC, base[id] + QUAD8_REG_CHAN_OP);
> +
> +	err = devm_request_irq(dev, irq[id], quad8_irq_handler, IRQF_SHARED,
> +			       priv->counter.name, priv);
> +	if (err)
> +		return err;
>  
>  	return devm_counter_register(dev, &priv->counter);
>  }
> diff --git a/drivers/counter/Kconfig b/drivers/counter/Kconfig
> index 5328705aa09c..2c2862dd46a5 100644
> --- a/drivers/counter/Kconfig
> +++ b/drivers/counter/Kconfig
> @@ -23,11 +23,11 @@ config 104_QUAD_8
>  	  A counter's respective error flag may be cleared by performing a write
>  	  operation on the respective count value attribute. Although the
>  	  104-QUAD-8 counters have a 25-bit range, only the lower 24 bits may be
> -	  set, either directly or via the counter's preset attribute. Interrupts
> -	  are not supported by this driver.
> +	  set, either directly or via the counter's preset attribute.
>  
>  	  The base port addresses for the devices may be configured via the base
> -	  array module parameter.
> +	  array module parameter. The interrupt line numbers for the devices may
> +	  be configured via the irq array module parameter.
>  
>  config INTERRUPT_CNT
>  	tristate "Interrupt counter driver"
> -- 
> 2.30.2
> 

WARNING: multiple messages have this Message-ID (diff)
From: Syed Nayyar Waris <syednwaris@gmail.com>
To: William Breathitt Gray <vilhelm.gray@gmail.com>
Cc: jic23@kernel.org, kernel@pengutronix.de,
	linux-stm32@st-md-mailman.stormreply.com,
	a.fatoum@pengutronix.de, kamel.bouhara@bootlin.com,
	gwendal@chromium.org, alexandre.belloni@bootlin.com,
	david@lechnology.com, linux-iio@vger.kernel.org,
	linux-kernel@vger.kernel.org,
	linux-arm-kernel@lists.infradead.org,
	patrick.havelange@essensium.com, fabrice.gasnier@st.com,
	mcoquelin.stm32@gmail.com, alexandre.torgue@st.com,
	o.rempel@pengutronix.de
Subject: Re: [PATCH v10 33/33] counter: 104-quad-8: Add IRQ support for the ACCES 104-QUAD-8
Date: Thu, 15 Apr 2021 20:55:03 +0530	[thread overview]
Message-ID: <20210415152503.GL8933@syed> (raw)
In-Reply-To: <24f0eacf6d2e320c2ed1bc20e07a6e723da75737.1616150619.git.vilhelm.gray@gmail.com>

On Fri, Mar 19, 2021 at 08:00:52PM +0900, William Breathitt Gray wrote:
> The LSI/CSI LS7266R1 chip provides programmable output via the FLG pins.
> When interrupts are enabled on the ACCES 104-QUAD-8, they occur whenever
> FLG1 is active. Four functions are available for the FLG1 signal: Carry,
> Compare, Carry-Borrow, and Index.
> 
> 	Carry:
> 		Interrupt generated on active low Carry signal. Carry
> 		signal toggles every time the respective channel's
> 		counter overflows.
> 
> 	Compare:
> 		Interrupt generated on active low Compare signal.
> 		Compare signal toggles every time respective channel's
> 		preset register is equal to the respective channel's
> 		counter.
> 
> 	Carry-Borrow:
> 		Interrupt generated on active low Carry signal and
> 		active low Borrow signal. Carry signal toggles every
> 		time the respective channel's counter overflows. Borrow
> 		signal toggles every time the respective channel's
> 		counter underflows.
> 
> 	Index:
> 		Interrupt generated on active high Index signal.
> 
> These four functions correspond respectivefly to the following four
> Counter event types: COUNTER_EVENT_OVERFLOW, COUNTER_EVENT_THRESHOLD,
> COUNTER_EVENT_OVERFLOW_UNDERFLOW, and COUNTER_EVENT_INDEX. Interrupts
> push Counter events to event channel X, where 'X' is the respective
> channel whose FLG1 activated.
> 
> This patch adds IRQ support for the ACCES 104-QUAD-8. The interrupt line
> numbers for the devices may be configured via the irq array module
> parameter.
> 
> Cc: Syed Nayyar Waris <syednwaris@gmail.com>
> Signed-off-by: William Breathitt Gray <vilhelm.gray@gmail.com>
> ---
>  drivers/counter/104-quad-8.c | 167 +++++++++++++++++++++++++++++++++--
>  drivers/counter/Kconfig      |   6 +-
>  2 files changed, 164 insertions(+), 9 deletions(-)

Acked-by: Syed Nayyar Waris <syednwaris@gmail.com>

> 
> diff --git a/drivers/counter/104-quad-8.c b/drivers/counter/104-quad-8.c
> index d46b8101f207..09b0b0ba8fe7 100644
> --- a/drivers/counter/104-quad-8.c
> +++ b/drivers/counter/104-quad-8.c
> @@ -11,6 +11,7 @@
>  #include <linux/errno.h>
>  #include <linux/io.h>
>  #include <linux/ioport.h>
> +#include <linux/interrupt.h>
>  #include <linux/isa.h>
>  #include <linux/kernel.h>
>  #include <linux/module.h>
> @@ -25,6 +26,10 @@ static unsigned int num_quad8;
>  module_param_hw_array(base, uint, ioport, &num_quad8, 0);
>  MODULE_PARM_DESC(base, "ACCES 104-QUAD-8 base addresses");
>  
> +static unsigned int irq[max_num_isa_dev(QUAD8_EXTENT)];
> +module_param_hw_array(irq, uint, irq, NULL, 0);
> +MODULE_PARM_DESC(irq, "ACCES 104-QUAD-8 interrupt line numbers");
> +
>  #define QUAD8_NUM_COUNTERS 8
>  
>  /**
> @@ -38,6 +43,8 @@ MODULE_PARM_DESC(base, "ACCES 104-QUAD-8 base addresses");
>   * @quadrature_scale:	array of quadrature mode scale configurations
>   * @ab_enable:		array of A and B inputs enable configurations
>   * @preset_enable:	array of set_to_preset_on_index attribute configurations
> + * @irq_trigger:	array of current IRQ trigger function configurations
> + * @next_irq_trigger:	array of next IRQ trigger function configurations
>   * @synchronous_mode:	array of index function synchronous mode configurations
>   * @index_polarity:	array of index function polarity configurations
>   * @cable_fault_enable:	differential encoder cable status enable configurations
> @@ -53,13 +60,17 @@ struct quad8 {
>  	unsigned int quadrature_scale[QUAD8_NUM_COUNTERS];
>  	unsigned int ab_enable[QUAD8_NUM_COUNTERS];
>  	unsigned int preset_enable[QUAD8_NUM_COUNTERS];
> +	unsigned int irq_trigger[QUAD8_NUM_COUNTERS];
> +	unsigned int next_irq_trigger[QUAD8_NUM_COUNTERS];
>  	unsigned int synchronous_mode[QUAD8_NUM_COUNTERS];
>  	unsigned int index_polarity[QUAD8_NUM_COUNTERS];
>  	unsigned int cable_fault_enable;
>  	unsigned int base;
>  };
>  
> +#define QUAD8_REG_INTERRUPT_STATUS 0x10
>  #define QUAD8_REG_CHAN_OP 0x11
> +#define QUAD8_REG_INDEX_INTERRUPT 0x12
>  #define QUAD8_REG_INDEX_INPUT_LEVELS 0x16
>  #define QUAD8_DIFF_ENCODER_CABLE_STATUS 0x17
>  /* Borrow Toggle flip-flop */
> @@ -92,8 +103,8 @@ struct quad8 {
>  #define QUAD8_RLD_CNTR_OUT 0x10
>  /* Transfer Preset Register LSB to FCK Prescaler */
>  #define QUAD8_RLD_PRESET_PSC 0x18
> -#define QUAD8_CHAN_OP_ENABLE_COUNTERS 0x00
>  #define QUAD8_CHAN_OP_RESET_COUNTERS 0x01
> +#define QUAD8_CHAN_OP_ENABLE_INTERRUPT_FUNC 0x04
>  #define QUAD8_CMR_QUADRATURE_X1 0x08
>  #define QUAD8_CMR_QUADRATURE_X2 0x10
>  #define QUAD8_CMR_QUADRATURE_X4 0x18
> @@ -378,13 +389,103 @@ static int quad8_action_read(struct counter_device *counter,
>  	}
>  }
>  
> +enum {
> +	QUAD8_EVENT_NONE = -1,
> +	QUAD8_EVENT_CARRY = 0,
> +	QUAD8_EVENT_COMPARE = 1,
> +	QUAD8_EVENT_CARRY_BORROW = 2,
> +	QUAD8_EVENT_INDEX = 3,
> +};
> +
> +static int quad8_events_configure(struct counter_device *counter)
> +{
> +	struct quad8 *const priv = counter->priv;
> +	unsigned long irq_enabled = 0;
> +	unsigned long irqflags;
> +	size_t channel;
> +	unsigned long ior_cfg;
> +	unsigned long base_offset;
> +
> +	spin_lock_irqsave(&priv->lock, irqflags);
> +
> +	/* Enable interrupts for the requested channels, disable for the rest */
> +	for (channel = 0; channel < QUAD8_NUM_COUNTERS; channel++) {
> +		if (priv->next_irq_trigger[channel] == QUAD8_EVENT_NONE)
> +			continue;
> +
> +		if (priv->irq_trigger[channel] != priv->next_irq_trigger[channel]) {
> +			/* Save new IRQ function configuration */
> +			priv->irq_trigger[channel] = priv->next_irq_trigger[channel];
> +
> +			/* Load configuration to I/O Control Register */
> +			ior_cfg = priv->ab_enable[channel] |
> +				  priv->preset_enable[channel] << 1 |
> +				  priv->irq_trigger[channel] << 3;
> +			base_offset = priv->base + 2 * channel + 1;
> +			outb(QUAD8_CTR_IOR | ior_cfg, base_offset);
> +		}
> +
> +		/* Reset next IRQ trigger function configuration */
> +		priv->next_irq_trigger[channel] = QUAD8_EVENT_NONE;
> +
> +		/* Enable IRQ line */
> +		irq_enabled |= BIT(channel);
> +	}
> +
> +	outb(irq_enabled, priv->base + QUAD8_REG_INDEX_INTERRUPT);
> +
> +	spin_unlock_irqrestore(&priv->lock, irqflags);
> +
> +	return 0;
> +}
> +
> +static int quad8_watch_validate(struct counter_device *counter,
> +				const struct counter_watch *watch)
> +{
> +	struct quad8 *const priv = counter->priv;
> +
> +	if (watch->channel > QUAD8_NUM_COUNTERS - 1)
> +		return -EINVAL;
> +
> +	switch (watch->event) {
> +	case COUNTER_EVENT_OVERFLOW:
> +		if (priv->next_irq_trigger[watch->channel] == QUAD8_EVENT_NONE)
> +			priv->next_irq_trigger[watch->channel] = QUAD8_EVENT_CARRY;
> +		else if (priv->next_irq_trigger[watch->channel] != QUAD8_EVENT_CARRY)
> +			return -EINVAL;
> +		return 0;
> +	case COUNTER_EVENT_THRESHOLD:
> +		if (priv->next_irq_trigger[watch->channel] == QUAD8_EVENT_NONE)
> +			priv->next_irq_trigger[watch->channel] = QUAD8_EVENT_COMPARE;
> +		else if (priv->next_irq_trigger[watch->channel] != QUAD8_EVENT_COMPARE)
> +			return -EINVAL;
> +		return 0;
> +	case COUNTER_EVENT_OVERFLOW_UNDERFLOW:
> +		if (priv->next_irq_trigger[watch->channel] == QUAD8_EVENT_NONE)
> +			priv->next_irq_trigger[watch->channel] = QUAD8_EVENT_CARRY_BORROW;
> +		else if (priv->next_irq_trigger[watch->channel] != QUAD8_EVENT_CARRY_BORROW)
> +			return -EINVAL;
> +		return 0;
> +	case COUNTER_EVENT_INDEX:
> +		if (priv->next_irq_trigger[watch->channel] == QUAD8_EVENT_NONE)
> +			priv->next_irq_trigger[watch->channel] = QUAD8_EVENT_INDEX;
> +		else if (priv->next_irq_trigger[watch->channel] != QUAD8_EVENT_INDEX)
> +			return -EINVAL;
> +		return 0;
> +	default:
> +		return -EINVAL;
> +	}
> +}
> +
>  static const struct counter_ops quad8_ops = {
>  	.signal_read = quad8_signal_read,
>  	.count_read = quad8_count_read,
>  	.count_write = quad8_count_write,
>  	.function_read = quad8_function_read,
>  	.function_write = quad8_function_write,
> -	.action_read = quad8_action_read
> +	.action_read = quad8_action_read,
> +	.events_configure = quad8_events_configure,
> +	.watch_validate = quad8_watch_validate,
>  };
>  
>  static const char *const quad8_index_polarity_modes[] = {
> @@ -579,7 +680,8 @@ static int quad8_count_enable_write(struct counter_device *counter,
>  
>  	priv->ab_enable[count->id] = enable;
>  
> -	ior_cfg = enable | priv->preset_enable[count->id] << 1;
> +	ior_cfg = enable | priv->preset_enable[count->id] << 1 |
> +		  priv->irq_trigger[count->id] << 3;
>  
>  	/* Load I/O control configuration */
>  	outb(QUAD8_CTR_IOR | ior_cfg, base_offset + 1);
> @@ -728,7 +830,8 @@ static int quad8_count_preset_enable_write(struct counter_device *counter,
>  
>  	priv->preset_enable[count->id] = preset_enable;
>  
> -	ior_cfg = priv->ab_enable[count->id] | preset_enable << 1;
> +	ior_cfg = priv->ab_enable[count->id] | preset_enable << 1 |
> +		  priv->irq_trigger[count->id] << 3;
>  
>  	/* Load I/O control configuration to Input / Output Control Register */
>  	outb(QUAD8_CTR_IOR | ior_cfg, base_offset);
> @@ -980,11 +1083,54 @@ static struct counter_count quad8_counts[] = {
>  	QUAD8_COUNT(7, "Channel 8 Count")
>  };
>  
> +static irqreturn_t quad8_irq_handler(int irq, void *private)
> +{
> +	struct quad8 *const priv = private;
> +	const unsigned long base = priv->base;
> +	unsigned long irq_status;
> +	unsigned long channel;
> +	u8 event;
> +
> +	irq_status = inb(base + QUAD8_REG_INTERRUPT_STATUS);
> +	if (!irq_status)
> +		return IRQ_NONE;
> +
> +	for_each_set_bit(channel, &irq_status, QUAD8_NUM_COUNTERS) {
> +		switch (priv->irq_trigger[channel]) {
> +		case QUAD8_EVENT_CARRY:
> +			event = COUNTER_EVENT_OVERFLOW;
> +				break;
> +		case QUAD8_EVENT_COMPARE:
> +			event = COUNTER_EVENT_THRESHOLD;
> +				break;
> +		case QUAD8_EVENT_CARRY_BORROW:
> +			event = COUNTER_EVENT_OVERFLOW_UNDERFLOW;
> +				break;
> +		case QUAD8_EVENT_INDEX:
> +			event = COUNTER_EVENT_INDEX;
> +				break;
> +		default:
> +			/* should never reach this path */
> +			WARN_ONCE(true, "invalid interrupt trigger function %u configured for channel %lu\n",
> +				  priv->irq_trigger[channel], channel);
> +			continue;
> +		}
> +
> +		counter_push_event(&priv->counter, event, channel);
> +	}
> +
> +	/* Clear pending interrupts on device */
> +	outb(QUAD8_CHAN_OP_ENABLE_INTERRUPT_FUNC, base + QUAD8_REG_CHAN_OP);
> +
> +	return IRQ_HANDLED;
> +}
> +
>  static int quad8_probe(struct device *dev, unsigned int id)
>  {
>  	struct quad8 *priv;
>  	int i, j;
>  	unsigned int base_offset;
> +	int err;
>  
>  	if (!devm_request_region(dev, base[id], QUAD8_EXTENT, dev_name(dev))) {
>  		dev_err(dev, "Unable to lock port addresses (0x%X-0x%X)\n",
> @@ -1009,6 +1155,8 @@ static int quad8_probe(struct device *dev, unsigned int id)
>  
>  	spin_lock_init(&priv->lock);
>  
> +	/* Reset Index/Interrupt Register */
> +	outb(0x00, base[id] + QUAD8_REG_INDEX_INTERRUPT);
>  	/* Reset all counters and disable interrupt function */
>  	outb(QUAD8_CHAN_OP_RESET_COUNTERS, base[id] + QUAD8_REG_CHAN_OP);
>  	/* Set initial configuration for all counters */
> @@ -1035,11 +1183,18 @@ static int quad8_probe(struct device *dev, unsigned int id)
>  		outb(QUAD8_CTR_IOR, base_offset + 1);
>  		/* Disable index function; negative index polarity */
>  		outb(QUAD8_CTR_IDR, base_offset + 1);
> +		/* Initialize next IRQ trigger function configuration */
> +		priv->next_irq_trigger[i] = QUAD8_EVENT_NONE;
>  	}
>  	/* Disable Differential Encoder Cable Status for all channels */
>  	outb(0xFF, base[id] + QUAD8_DIFF_ENCODER_CABLE_STATUS);
> -	/* Enable all counters */
> -	outb(QUAD8_CHAN_OP_ENABLE_COUNTERS, base[id] + QUAD8_REG_CHAN_OP);
> +	/* Enable all counters and enable interrupt function */
> +	outb(QUAD8_CHAN_OP_ENABLE_INTERRUPT_FUNC, base[id] + QUAD8_REG_CHAN_OP);
> +
> +	err = devm_request_irq(dev, irq[id], quad8_irq_handler, IRQF_SHARED,
> +			       priv->counter.name, priv);
> +	if (err)
> +		return err;
>  
>  	return devm_counter_register(dev, &priv->counter);
>  }
> diff --git a/drivers/counter/Kconfig b/drivers/counter/Kconfig
> index 5328705aa09c..2c2862dd46a5 100644
> --- a/drivers/counter/Kconfig
> +++ b/drivers/counter/Kconfig
> @@ -23,11 +23,11 @@ config 104_QUAD_8
>  	  A counter's respective error flag may be cleared by performing a write
>  	  operation on the respective count value attribute. Although the
>  	  104-QUAD-8 counters have a 25-bit range, only the lower 24 bits may be
> -	  set, either directly or via the counter's preset attribute. Interrupts
> -	  are not supported by this driver.
> +	  set, either directly or via the counter's preset attribute.
>  
>  	  The base port addresses for the devices may be configured via the base
> -	  array module parameter.
> +	  array module parameter. The interrupt line numbers for the devices may
> +	  be configured via the irq array module parameter.
>  
>  config INTERRUPT_CNT
>  	tristate "Interrupt counter driver"
> -- 
> 2.30.2
> 

_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

  reply	other threads:[~2021-04-15 15:25 UTC|newest]

Thread overview: 109+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2021-03-19 11:00 [PATCH v10 00/33] Introduce the Counter character device interface William Breathitt Gray
2021-03-19 11:00 ` William Breathitt Gray
2021-03-19 11:00 ` [PATCH v10 01/33] docs: counter: Consolidate Counter sysfs attributes documentation William Breathitt Gray
2021-03-19 11:00   ` William Breathitt Gray
2021-03-19 11:00 ` [PATCH v10 02/33] docs: counter: Fix spelling William Breathitt Gray
2021-03-19 11:00   ` William Breathitt Gray
2021-03-19 11:00 ` [PATCH v10 03/33] counter: 104-quad-8: Remove pointless comment William Breathitt Gray
2021-03-19 11:00   ` William Breathitt Gray
2021-04-15 15:13   ` Syed Nayyar Waris
2021-04-15 15:13     ` Syed Nayyar Waris
2021-03-19 11:00 ` [PATCH v10 04/33] counter: 104-quad-8: Return error when invalid mode during ceiling_write William Breathitt Gray
2021-03-19 11:00   ` William Breathitt Gray
2021-04-15 15:14   ` Syed Nayyar Waris
2021-04-15 15:14     ` Syed Nayyar Waris
2021-03-19 11:00 ` [PATCH v10 05/33] counter: 104-quad-8: Annotate hardware config module parameter William Breathitt Gray
2021-03-19 11:00   ` William Breathitt Gray
2021-04-15 15:15   ` Syed Nayyar Waris
2021-04-15 15:15     ` Syed Nayyar Waris
2021-03-19 11:00 ` [PATCH v10 06/33] counter: 104-quad-8: Add const qualifiers for quad8_preset_register_set William Breathitt Gray
2021-03-19 11:00   ` William Breathitt Gray
2021-04-15 15:16   ` Syed Nayyar Waris
2021-04-15 15:16     ` Syed Nayyar Waris
2021-03-19 11:00 ` [PATCH v10 07/33] counter: 104-quad-8: Add const qualifier for functions_list array William Breathitt Gray
2021-03-19 11:00   ` William Breathitt Gray
2021-04-15 15:17   ` Syed Nayyar Waris
2021-04-15 15:17     ` Syed Nayyar Waris
2021-03-19 11:00 ` [PATCH v10 08/33] counter: interrupt-cnt: " William Breathitt Gray
2021-03-19 11:00   ` William Breathitt Gray
2021-03-19 11:00 ` [PATCH v10 09/33] counter: microchip-tcb-capture: " William Breathitt Gray
2021-03-19 11:00   ` William Breathitt Gray
2021-03-19 11:00 ` [PATCH v10 10/33] counter: stm32-lptimer-cnt: " William Breathitt Gray
2021-03-19 11:00   ` William Breathitt Gray
2021-03-22 16:22   ` [Linux-stm32] " Fabrice Gasnier
2021-03-22 16:22     ` Fabrice Gasnier
2021-03-19 11:00 ` [PATCH v10 11/33] counter: stm32-timer-cnt: " William Breathitt Gray
2021-03-19 11:00   ` William Breathitt Gray
2021-03-22 16:22   ` [Linux-stm32] " Fabrice Gasnier
2021-03-22 16:22     ` Fabrice Gasnier
2021-03-19 11:00 ` [PATCH v10 12/33] counter: 104-quad-8: Add const qualifier for actions_list array William Breathitt Gray
2021-03-19 11:00   ` William Breathitt Gray
2021-04-15 15:18   ` Syed Nayyar Waris
2021-04-15 15:18     ` Syed Nayyar Waris
2021-03-19 11:00 ` [PATCH v10 13/33] counter: ftm-quaddec: " William Breathitt Gray
2021-03-19 11:00   ` William Breathitt Gray
2021-03-19 11:00 ` [PATCH v10 14/33] counter: interrupt-cnt: " William Breathitt Gray
2021-03-19 11:00   ` William Breathitt Gray
2021-03-19 11:00 ` [PATCH v10 15/33] counter: microchip-tcb-capture: " William Breathitt Gray
2021-03-19 11:00   ` William Breathitt Gray
2021-03-19 11:00 ` [PATCH v10 16/33] counter: stm32-lptimer-cnt: " William Breathitt Gray
2021-03-19 11:00   ` William Breathitt Gray
2021-03-22 16:23   ` [Linux-stm32] " Fabrice Gasnier
2021-03-22 16:23     ` Fabrice Gasnier
2021-03-19 11:00 ` [PATCH v10 17/33] counter: stm32-timer-cnt: " William Breathitt Gray
2021-03-19 11:00   ` William Breathitt Gray
2021-03-22 16:24   ` [Linux-stm32] " Fabrice Gasnier
2021-03-22 16:24     ` Fabrice Gasnier
2021-03-19 11:00 ` [PATCH v10 18/33] counter: Return error code on invalid modes William Breathitt Gray
2021-03-19 11:00   ` William Breathitt Gray
2021-03-22 16:26   ` [Linux-stm32] " Fabrice Gasnier
2021-03-22 16:26     ` Fabrice Gasnier
2021-04-15 15:19   ` Syed Nayyar Waris
2021-04-15 15:19     ` Syed Nayyar Waris
2021-03-19 11:00 ` [PATCH v10 19/33] counter: Standardize to ERANGE for limit exceeded errors William Breathitt Gray
2021-03-19 11:00   ` William Breathitt Gray
2021-03-22 16:29   ` [Linux-stm32] " Fabrice Gasnier
2021-03-22 16:29     ` Fabrice Gasnier
2021-04-15 15:20   ` Syed Nayyar Waris
2021-04-15 15:20     ` Syed Nayyar Waris
2021-03-19 11:00 ` [PATCH v10 20/33] counter: Rename counter_signal_value to counter_signal_level William Breathitt Gray
2021-03-19 11:00   ` William Breathitt Gray
2021-04-15 15:21   ` Syed Nayyar Waris
2021-04-15 15:21     ` Syed Nayyar Waris
2021-03-19 11:00 ` [PATCH v10 21/33] counter: Rename counter_count_function to counter_function William Breathitt Gray
2021-03-19 11:00   ` William Breathitt Gray
2021-03-22 16:31   ` [Linux-stm32] " Fabrice Gasnier
2021-03-22 16:31     ` Fabrice Gasnier
2021-04-15 15:22   ` Syed Nayyar Waris
2021-04-15 15:22     ` Syed Nayyar Waris
2021-03-19 11:00 ` [PATCH v10 22/33] counter: Internalize sysfs interface code William Breathitt Gray
2021-03-22 16:44   ` [Linux-stm32] " Fabrice Gasnier
2021-03-22 16:44     ` Fabrice Gasnier
2021-03-23  9:17     ` William Breathitt Gray
2021-03-23  9:17       ` William Breathitt Gray
2021-03-19 11:00 ` [PATCH v10 23/33] counter: Update counter.h comments to reflect sysfs internalization William Breathitt Gray
2021-03-19 11:00   ` William Breathitt Gray
2021-03-19 11:00 ` [PATCH v10 24/33] docs: counter: Update " William Breathitt Gray
2021-03-19 11:00   ` William Breathitt Gray
2021-03-19 11:00 ` [PATCH v10 25/33] counter: Move counter enums to uapi header William Breathitt Gray
2021-03-19 11:00   ` William Breathitt Gray
2021-03-19 11:00 ` [PATCH v10 26/33] counter: Add character device interface William Breathitt Gray
2021-03-19 11:00   ` William Breathitt Gray
2021-03-19 11:00 ` [PATCH v10 27/33] docs: counter: Document " William Breathitt Gray
2021-03-19 11:00   ` William Breathitt Gray
2021-03-19 11:00 ` [PATCH v10 28/33] tools/counter: Create Counter tools William Breathitt Gray
2021-03-19 11:00   ` William Breathitt Gray
2021-03-19 11:00 ` [PATCH v10 29/33] counter: Implement signalZ_action_component_id sysfs attribute William Breathitt Gray
2021-03-19 11:00   ` William Breathitt Gray
2021-03-19 11:00 ` [PATCH v10 30/33] counter: Implement *_component_id sysfs attributes William Breathitt Gray
2021-03-19 11:00   ` William Breathitt Gray
2021-03-19 11:00 ` [PATCH v10 31/33] counter: Implement events_queue_size sysfs attribute William Breathitt Gray
2021-03-19 11:00   ` William Breathitt Gray
2021-03-19 11:00 ` [PATCH v10 32/33] counter: 104-quad-8: Replace mutex with spinlock William Breathitt Gray
2021-03-19 11:00   ` William Breathitt Gray
2021-04-15 15:24   ` Syed Nayyar Waris
2021-04-15 15:24     ` Syed Nayyar Waris
2021-03-19 11:00 ` [PATCH v10 33/33] counter: 104-quad-8: Add IRQ support for the ACCES 104-QUAD-8 William Breathitt Gray
2021-03-19 11:00   ` William Breathitt Gray
2021-04-15 15:25   ` Syed Nayyar Waris [this message]
2021-04-15 15:25     ` Syed Nayyar Waris

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20210415152503.GL8933@syed \
    --to=syednwaris@gmail.com \
    --cc=a.fatoum@pengutronix.de \
    --cc=alexandre.belloni@bootlin.com \
    --cc=alexandre.torgue@st.com \
    --cc=david@lechnology.com \
    --cc=fabrice.gasnier@st.com \
    --cc=gwendal@chromium.org \
    --cc=jic23@kernel.org \
    --cc=kamel.bouhara@bootlin.com \
    --cc=kernel@pengutronix.de \
    --cc=linux-arm-kernel@lists.infradead.org \
    --cc=linux-iio@vger.kernel.org \
    --cc=linux-kernel@vger.kernel.org \
    --cc=linux-stm32@st-md-mailman.stormreply.com \
    --cc=mcoquelin.stm32@gmail.com \
    --cc=o.rempel@pengutronix.de \
    --cc=patrick.havelange@essensium.com \
    --cc=vilhelm.gray@gmail.com \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.