All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH 1/2] regmap: irq: add support for configuration of trigger type
@ 2015-12-22 12:55 Laxman Dewangan
  2015-12-22 12:55 ` [PATCH 2/2] regmap: irq: add support to have callback pre/post irq handling Laxman Dewangan
  2016-01-05 17:41 ` [PATCH 1/2] regmap: irq: add support for configuration of trigger type Mark Brown
  0 siblings, 2 replies; 6+ messages in thread
From: Laxman Dewangan @ 2015-12-22 12:55 UTC (permalink / raw)
  To: broonie, gregkh; +Cc: linux-kernel, swarren, Laxman Dewangan

Some of devices supports the trigger level for interrupt
like rising/falling edge specially for GPIOs. The interrupt
support of such devices may have uses the generic regmap irq
framework for implementation.

Add support to configure the trigger type device interrupt
register via regmap-irq framework. The regmap-irq framework
configures the trigger register only if the details of trigger
type registers are provided.

Signed-off-by: Laxman Dewangan <ldewangan@nvidia.com>
---
 drivers/base/regmap/regmap-irq.c | 97 ++++++++++++++++++++++++++++++++++++++++
 include/linux/regmap.h           | 16 +++++++
 2 files changed, 113 insertions(+)

diff --git a/drivers/base/regmap/regmap-irq.c b/drivers/base/regmap/regmap-irq.c
index 4d2cb21..8aa1e2a 100644
--- a/drivers/base/regmap/regmap-irq.c
+++ b/drivers/base/regmap/regmap-irq.c
@@ -39,8 +39,11 @@ struct regmap_irq_chip_data {
 	unsigned int *mask_buf;
 	unsigned int *mask_buf_def;
 	unsigned int *wake_buf;
+	unsigned int *type_buf;
+	unsigned int *type_buf_def;
 
 	unsigned int irq_reg_stride;
+	unsigned int type_reg_stride;
 };
 
 static inline const
@@ -144,6 +147,22 @@ static void regmap_irq_sync_unlock(struct irq_data *data)
 		}
 	}
 
+	for (i = 0; i < d->chip->num_type_reg; i++) {
+		if (!d->type_buf_def[i])
+			continue;
+		reg = d->chip->type_base +
+			(i * map->reg_stride * d->type_reg_stride);
+		if (d->chip->type_invert)
+			ret = regmap_update_bits(d->map, reg,
+				d->type_buf_def[i], ~d->type_buf[i]);
+		else
+			ret = regmap_update_bits(d->map, reg,
+				d->type_buf_def[i], d->type_buf[i]);
+		if (ret != 0)
+			dev_err(d->map->dev, "Failed to sync type in %x\n",
+				reg);
+	}
+
 	if (d->chip->runtime_pm)
 		pm_runtime_put(map->dev);
 
@@ -178,6 +197,38 @@ static void regmap_irq_disable(struct irq_data *data)
 	d->mask_buf[irq_data->reg_offset / map->reg_stride] |= irq_data->mask;
 }
 
+static int regmap_irq_set_type(struct irq_data *data, unsigned int type)
+{
+	struct regmap_irq_chip_data *d = irq_data_get_irq_chip_data(data);
+	struct regmap *map = d->map;
+	const struct regmap_irq *irq_data = irq_to_regmap_irq(d, data->hwirq);
+	int reg = irq_data->type_reg_offset / map->reg_stride;
+
+	if (!(irq_data->type_rising_mask | irq_data->type_falling_mask))
+		return 0;
+
+	d->type_buf[reg] &= ~(irq_data->type_falling_mask |
+					irq_data->type_rising_mask);
+	switch (type) {
+	case IRQ_TYPE_EDGE_FALLING:
+		d->type_buf[reg] |= irq_data->type_falling_mask;
+		break;
+
+	case IRQ_TYPE_EDGE_RISING:
+		d->type_buf[reg] |= irq_data->type_rising_mask;
+		break;
+
+	case IRQ_TYPE_EDGE_BOTH:
+		d->type_buf[reg] |= (irq_data->type_falling_mask |
+					irq_data->type_rising_mask);
+		break;
+
+	default:
+		return -EINVAL;
+	}
+	return 0;
+}
+
 static int regmap_irq_set_wake(struct irq_data *data, unsigned int on)
 {
 	struct regmap_irq_chip_data *d = irq_data_get_irq_chip_data(data);
@@ -204,6 +255,7 @@ static const struct irq_chip regmap_irq_chip = {
 	.irq_bus_sync_unlock	= regmap_irq_sync_unlock,
 	.irq_disable		= regmap_irq_disable,
 	.irq_enable		= regmap_irq_enable,
+	.irq_set_type		= regmap_irq_set_type,
 	.irq_set_wake		= regmap_irq_set_wake,
 };
 
@@ -408,6 +460,18 @@ int regmap_add_irq_chip(struct regmap *map, int irq, int irq_flags,
 			goto err_alloc;
 	}
 
+	if (chip->num_type_reg) {
+		d->type_buf_def = kcalloc(chip->num_type_reg,
+					sizeof(unsigned int), GFP_KERNEL);
+		if (!d->type_buf_def)
+			goto err_alloc;
+
+		d->type_buf = kcalloc(chip->num_type_reg, sizeof(unsigned int),
+				      GFP_KERNEL);
+		if (!d->type_buf)
+			goto err_alloc;
+	}
+
 	d->irq_chip = regmap_irq_chip;
 	d->irq_chip.name = chip->name;
 	d->irq = irq;
@@ -420,6 +484,8 @@ int regmap_add_irq_chip(struct regmap *map, int irq, int irq_flags,
 	else
 		d->irq_reg_stride = 1;
 
+	d->type_reg_stride = chip->type_reg_stride ? : 1;
+
 	if (!map->use_single_read && map->reg_stride == 1 &&
 	    d->irq_reg_stride == 1) {
 		d->status_reg_buf = kmalloc_array(chip->num_regs,
@@ -512,6 +578,33 @@ int regmap_add_irq_chip(struct regmap *map, int irq, int irq_flags,
 		}
 	}
 
+	if (chip->num_type_reg) {
+		for (i = 0; i < chip->num_irqs; i++) {
+			reg = chip->irqs[i].type_reg_offset / map->reg_stride;
+			d->type_buf_def[reg] |= chip->irqs[i].type_rising_mask |
+					chip->irqs[i].type_falling_mask;
+		}
+		for (i = 0; i < chip->num_type_reg; ++i) {
+			if (!d->type_buf_def[i])
+				continue;
+
+			reg = chip->type_base +
+				(i * map->reg_stride * d->type_reg_stride);
+			if (chip->type_invert)
+				ret = regmap_update_bits(map, reg,
+					d->type_buf_def[i], 0xFF);
+			else
+				ret = regmap_update_bits(map, reg,
+					d->type_buf_def[i], 0x0);
+			if (ret != 0) {
+				dev_err(map->dev,
+					"Failed to set type in 0x%x: %x\n",
+					reg, ret);
+				goto err_alloc;
+			}
+		}
+	}
+
 	if (irq_base)
 		d->domain = irq_domain_add_legacy(map->dev->of_node,
 						  chip->num_irqs, irq_base, 0,
@@ -542,6 +635,8 @@ int regmap_add_irq_chip(struct regmap *map, int irq, int irq_flags,
 err_domain:
 	/* Should really dispose of the domain but... */
 err_alloc:
+	kfree(d->type_buf);
+	kfree(d->type_buf_def);
 	kfree(d->wake_buf);
 	kfree(d->mask_buf_def);
 	kfree(d->mask_buf);
@@ -565,6 +660,8 @@ void regmap_del_irq_chip(int irq, struct regmap_irq_chip_data *d)
 
 	free_irq(irq, d);
 	irq_domain_remove(d->domain);
+	kfree(d->type_buf);
+	kfree(d->type_buf_def);
 	kfree(d->wake_buf);
 	kfree(d->mask_buf_def);
 	kfree(d->mask_buf);
diff --git a/include/linux/regmap.h b/include/linux/regmap.h
index 4d9a1a0..1839434 100644
--- a/include/linux/regmap.h
+++ b/include/linux/regmap.h
@@ -788,10 +788,16 @@ int regmap_fields_update_bits(struct regmap_field *field,  unsigned int id,
  *
  * @reg_offset: Offset of the status/mask register within the bank
  * @mask:       Mask used to flag/control the register.
+ * @type_reg_offset: Offset register for the irq type setting.
+ * @type_rising_mask: Mask bit to configure RISING type irq.
+ * @type_falling_mask: Mask bit to configure FALLING type irq.
  */
 struct regmap_irq {
 	unsigned int reg_offset;
 	unsigned int mask;
+	unsigned int type_reg_offset;
+	unsigned int type_rising_mask;
+	unsigned int type_falling_mask;
 };
 
 #define REGMAP_IRQ_REG(_irq, _off, _mask)		\
@@ -811,18 +817,23 @@ struct regmap_irq {
  * @ack_base:    Base ack address. If zero then the chip is clear on read.
  *               Using zero value is possible with @use_ack bit.
  * @wake_base:   Base address for wake enables.  If zero unsupported.
+ * @type_base:   Base address for irq type.  If zero unsupported.
  * @irq_reg_stride:  Stride to use for chips where registers are not contiguous.
  * @init_ack_masked: Ack all masked interrupts once during initalization.
  * @mask_invert: Inverted mask register: cleared bits are masked out.
  * @use_ack:     Use @ack register even if it is zero.
  * @ack_invert:  Inverted ack register: cleared bits for ack.
  * @wake_invert: Inverted wake register: cleared bits are wake enabled.
+ * @type_invert: Invert the type flags.
  * @runtime_pm:  Hold a runtime PM lock on the device when accessing it.
  *
  * @num_regs:    Number of registers in each control bank.
  * @irqs:        Descriptors for individual IRQs.  Interrupt numbers are
  *               assigned based on the index in the array of the interrupt.
  * @num_irqs:    Number of descriptors.
+ * @num_type_reg:    Number of type registers.
+ * @type_reg_stride: Stride to use for chips where type registers are not
+ *			contiguous.
  */
 struct regmap_irq_chip {
 	const char *name;
@@ -832,6 +843,7 @@ struct regmap_irq_chip {
 	unsigned int unmask_base;
 	unsigned int ack_base;
 	unsigned int wake_base;
+	unsigned int type_base;
 	unsigned int irq_reg_stride;
 	bool init_ack_masked:1;
 	bool mask_invert:1;
@@ -839,11 +851,15 @@ struct regmap_irq_chip {
 	bool ack_invert:1;
 	bool wake_invert:1;
 	bool runtime_pm:1;
+	bool type_invert:1;
 
 	int num_regs;
 
 	const struct regmap_irq *irqs;
 	int num_irqs;
+
+	int num_type_reg;
+	unsigned int type_reg_stride;
 };
 
 struct regmap_irq_chip_data;
-- 
2.1.4


^ permalink raw reply related	[flat|nested] 6+ messages in thread

* [PATCH 2/2] regmap: irq: add support to have callback pre/post irq handling
  2015-12-22 12:55 [PATCH 1/2] regmap: irq: add support for configuration of trigger type Laxman Dewangan
@ 2015-12-22 12:55 ` Laxman Dewangan
  2016-01-05 17:43   ` Mark Brown
  2016-01-05 17:41 ` [PATCH 1/2] regmap: irq: add support for configuration of trigger type Mark Brown
  1 sibling, 1 reply; 6+ messages in thread
From: Laxman Dewangan @ 2015-12-22 12:55 UTC (permalink / raw)
  To: broonie, gregkh; +Cc: linux-kernel, swarren, Laxman Dewangan

Some of devices like MAXIM MAX77620 required to have the chip
specific configuration before processing interrupt and after
interrupt handling is done.

For such devices to use the generic regmap-irq, add callback APIs
for pre/post irq callback which gets called from interrupt handler
of regmap irq thread to have device specific configurations.

Signed-off-by: Laxman Dewangan <ldewangan@nvidia.com>
---
 drivers/base/regmap/regmap-irq.c | 15 +++++++++++----
 include/linux/regmap.h           | 11 +++++++++++
 2 files changed, 22 insertions(+), 4 deletions(-)

diff --git a/drivers/base/regmap/regmap-irq.c b/drivers/base/regmap/regmap-irq.c
index 8aa1e2a..00dc6e9 100644
--- a/drivers/base/regmap/regmap-irq.c
+++ b/drivers/base/regmap/regmap-irq.c
@@ -268,13 +268,16 @@ static irqreturn_t regmap_irq_thread(int irq, void *d)
 	bool handled = false;
 	u32 reg;
 
+	if (chip->pre_irq)
+		chip->pre_irq(chip->pre_post_irq_data);
+
 	if (chip->runtime_pm) {
 		ret = pm_runtime_get_sync(map->dev);
 		if (ret < 0) {
 			dev_err(map->dev, "IRQ thread failed to resume: %d\n",
 				ret);
 			pm_runtime_put(map->dev);
-			return IRQ_NONE;
+			goto exit;
 		}
 	}
 
@@ -296,7 +299,7 @@ static irqreturn_t regmap_irq_thread(int irq, void *d)
 		if (ret != 0) {
 			dev_err(map->dev, "Failed to read IRQ status: %d\n",
 				ret);
-			return IRQ_NONE;
+			goto exit;
 		}
 
 		for (i = 0; i < data->chip->num_regs; i++) {
@@ -312,7 +315,7 @@ static irqreturn_t regmap_irq_thread(int irq, void *d)
 				break;
 			default:
 				BUG();
-				return IRQ_NONE;
+				goto exit;
 			}
 		}
 
@@ -329,7 +332,7 @@ static irqreturn_t regmap_irq_thread(int irq, void *d)
 					ret);
 				if (chip->runtime_pm)
 					pm_runtime_put(map->dev);
-				return IRQ_NONE;
+				goto exit;
 			}
 		}
 	}
@@ -365,6 +368,10 @@ static irqreturn_t regmap_irq_thread(int irq, void *d)
 	if (chip->runtime_pm)
 		pm_runtime_put(map->dev);
 
+exit:
+	if (chip->post_irq)
+		chip->post_irq(chip->pre_post_irq_data);
+
 	if (handled)
 		return IRQ_HANDLED;
 	else
diff --git a/include/linux/regmap.h b/include/linux/regmap.h
index 1839434..ba2d30b 100644
--- a/include/linux/regmap.h
+++ b/include/linux/regmap.h
@@ -834,6 +834,13 @@ struct regmap_irq {
  * @num_type_reg:    Number of type registers.
  * @type_reg_stride: Stride to use for chips where type registers are not
  *			contiguous.
+ * @pre_irq:	The callback that is to be executed initially, before the main
+ *		handling in regmap irq	handler when an interrupt occurs.
+ * @post_irq:	The callback that is to be executed after the main handling in
+ *		the regmap irq handler when an interrupt occurs.
+ * @pre_post_irq_data: The driver specific data that is the parameter for the
+ *		pre_irq and post_irq callbacks.
+ *
  */
 struct regmap_irq_chip {
 	const char *name;
@@ -860,6 +867,10 @@ struct regmap_irq_chip {
 
 	int num_type_reg;
 	unsigned int type_reg_stride;
+
+	int (*pre_irq)(void *irq_data);
+	int (*post_irq)(void *irq_data);
+	void *pre_post_irq_data;
 };
 
 struct regmap_irq_chip_data;
-- 
2.1.4


^ permalink raw reply related	[flat|nested] 6+ messages in thread

* Re: [PATCH 1/2] regmap: irq: add support for configuration of trigger type
  2015-12-22 12:55 [PATCH 1/2] regmap: irq: add support for configuration of trigger type Laxman Dewangan
  2015-12-22 12:55 ` [PATCH 2/2] regmap: irq: add support to have callback pre/post irq handling Laxman Dewangan
@ 2016-01-05 17:41 ` Mark Brown
  2016-01-06  5:48   ` Laxman Dewangan
  1 sibling, 1 reply; 6+ messages in thread
From: Mark Brown @ 2016-01-05 17:41 UTC (permalink / raw)
  To: Laxman Dewangan; +Cc: gregkh, linux-kernel, swarren

[-- Attachment #1: Type: text/plain, Size: 260 bytes --]

On Tue, Dec 22, 2015 at 06:25:26PM +0530, Laxman Dewangan wrote:

> +	d->type_reg_stride = chip->type_reg_stride ? : 1;
> +

Please don't abuse the ternery operator, especially not the GCC
extension - that's much less clear than just writing the if statement.

[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 473 bytes --]

^ permalink raw reply	[flat|nested] 6+ messages in thread

* Re: [PATCH 2/2] regmap: irq: add support to have callback pre/post irq handling
  2015-12-22 12:55 ` [PATCH 2/2] regmap: irq: add support to have callback pre/post irq handling Laxman Dewangan
@ 2016-01-05 17:43   ` Mark Brown
  2016-01-06  6:04     ` Laxman Dewangan
  0 siblings, 1 reply; 6+ messages in thread
From: Mark Brown @ 2016-01-05 17:43 UTC (permalink / raw)
  To: Laxman Dewangan; +Cc: gregkh, linux-kernel, swarren

[-- Attachment #1: Type: text/plain, Size: 260 bytes --]

On Tue, Dec 22, 2015 at 06:25:27PM +0530, Laxman Dewangan wrote:
> Some of devices like MAXIM MAX77620 required to have the chip
> specific configuration before processing interrupt and after
> interrupt handling is done.

I'd like to see the user for this...

[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 473 bytes --]

^ permalink raw reply	[flat|nested] 6+ messages in thread

* Re: [PATCH 1/2] regmap: irq: add support for configuration of trigger type
  2016-01-05 17:41 ` [PATCH 1/2] regmap: irq: add support for configuration of trigger type Mark Brown
@ 2016-01-06  5:48   ` Laxman Dewangan
  0 siblings, 0 replies; 6+ messages in thread
From: Laxman Dewangan @ 2016-01-06  5:48 UTC (permalink / raw)
  To: Mark Brown; +Cc: gregkh, linux-kernel, swarren


On Tuesday 05 January 2016 11:11 PM, Mark Brown wrote:
> * PGP Signed by an unknown key
>
> On Tue, Dec 22, 2015 at 06:25:26PM +0530, Laxman Dewangan wrote:
>
>> +	d->type_reg_stride = chip->type_reg_stride ? : 1;
>> +
> Please don't abuse the ternery operator, especially not the GCC
> extension - that's much less clear than just writing the if statement.
>

Sure, I will not use this in my future coding.
Thanks for correcting this before applying.


^ permalink raw reply	[flat|nested] 6+ messages in thread

* Re: [PATCH 2/2] regmap: irq: add support to have callback pre/post irq handling
  2016-01-05 17:43   ` Mark Brown
@ 2016-01-06  6:04     ` Laxman Dewangan
  0 siblings, 0 replies; 6+ messages in thread
From: Laxman Dewangan @ 2016-01-06  6:04 UTC (permalink / raw)
  To: Mark Brown; +Cc: gregkh, linux-kernel, swarren

Resending as previous response was denied by linux-kernel due to html 
format.

On Tuesday 05 January 2016 11:13 PM, Mark Brown wrote:
> * PGP Signed by an unknown key
>
> On Tue, Dec 22, 2015 at 06:25:27PM +0530, Laxman Dewangan wrote:
>> Some of devices like MAXIM MAX77620 required to have the chip
>> specific configuration before processing interrupt and after
>> interrupt handling is done.
> I'd like to see the user for this...
>

This will be there in my next coming patches for PMIC driver from Maxim 
Semiconductor MAX77620/MAX20024.

Per datasheet:

Upon the interrupt hardware line going low (nIRQ=0), the software is 
switched to the priority decoder which decides in what order all 
interrupts to the processor are serviced and therefore, will transfer 
control to the PMIC interrupt service routine appropriately.

* The first task for the processor is to mask the PMIC interrupt by 
setting GLBLM.
     o This forces nIRQ to go high-impedance in which case it will be 
pulled high by the external pull-up resistor.
     o Forcing nRIQ to go high-impedance ensures that any interrupts 
that occur within the PMIC while the PMIC interrupt service routine is 
being executed will cause a subsequent falling edge on the processor 
interrupt line.

* The next task is to read the IRQTOP register and maintain a local 
copy. Note that IRQTOP is cleared when read.
    // Handle all interrupts which occurred from PMIC.

* Once all interrupts have been checked and serviced, the interrupt 
service routine un-masks the hardware interrupt line by clearing (GLBLM).


And typical code will be:

int max77620_top_irq_chip_pre_irq(void *data)
{
         struct max77620_chip *chip = data;

         ret = max77620_reg_update(chip->dev, MAX77620_PWR_SLAVE,
                 MAX77620_REG_INTENLBT, MAX77620_GLBLM_MASK,
                 MAX77620_GLBLM_MASK);
         ::::
}

int max77620_top_irq_chip_post_irq(void *data)
{
         struct max77620_chip *chip = data;

         ret = max77620_reg_update(chip->dev, MAX77620_PWR_SLAVE,
                 MAX77620_REG_INTENLBT, MAX77620_GLBLM_MASK, 0);
         ::::
}

static struct regmap_irq_chip max77620_top_irq_chip = {
         .pre_irq = max77620_top_irq_chip_pre_irq,
         .post_irq = max77620_top_irq_chip_post_irq,
};

^ permalink raw reply	[flat|nested] 6+ messages in thread

end of thread, other threads:[~2016-01-06  6:14 UTC | newest]

Thread overview: 6+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2015-12-22 12:55 [PATCH 1/2] regmap: irq: add support for configuration of trigger type Laxman Dewangan
2015-12-22 12:55 ` [PATCH 2/2] regmap: irq: add support to have callback pre/post irq handling Laxman Dewangan
2016-01-05 17:43   ` Mark Brown
2016-01-06  6:04     ` Laxman Dewangan
2016-01-05 17:41 ` [PATCH 1/2] regmap: irq: add support for configuration of trigger type Mark Brown
2016-01-06  5:48   ` Laxman Dewangan

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.