regmap: regmap-irq/gpio-max77620: add level-irq support

Add level active IRQ support to regmap-irq irqchip. Change breaks
existing regmap-irq type setting. Convert the existing drivers which
use regmap-irq with trigger type setting (gpio-max77620) to work
with this new approach. So we do not magically support level-active
IRQs on gpio-max77620 - but add support to the regmap-irq for chips
which support them =)

We do not support distinguishing situation where HW supports rising
and falling edge detection but not both. Separating this would require
inventing yet another flags for IRQ types.

Signed-off-by: Matti Vaittinen <matti.vaittinen@fi.rohmeurope.com>
Signed-off-by: Mark Brown <broonie@kernel.org>
This commit is contained in:
Matti Vaittinen 2018-12-18 13:59:31 +02:00 committed by Mark Brown
parent 84267d1b18
commit 1c2928e3e3
No known key found for this signature in database
GPG key ID: 24D68B725D5487D0
3 changed files with 110 additions and 48 deletions

View file

@ -199,7 +199,7 @@ static void regmap_irq_enable(struct irq_data *data)
const struct regmap_irq *irq_data = irq_to_regmap_irq(d, data->hwirq); const struct regmap_irq *irq_data = irq_to_regmap_irq(d, data->hwirq);
unsigned int mask, type; unsigned int mask, type;
type = irq_data->type_falling_mask | irq_data->type_rising_mask; type = irq_data->type.type_falling_val | irq_data->type.type_rising_val;
/* /*
* The type_in_mask flag means that the underlying hardware uses * The type_in_mask flag means that the underlying hardware uses
@ -234,27 +234,42 @@ 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_irq_chip_data *d = irq_data_get_irq_chip_data(data);
struct regmap *map = d->map; struct regmap *map = d->map;
const struct regmap_irq *irq_data = irq_to_regmap_irq(d, data->hwirq); const struct regmap_irq *irq_data = irq_to_regmap_irq(d, data->hwirq);
int reg = irq_data->type_reg_offset / map->reg_stride; int reg;
const struct regmap_irq_type *t = &irq_data->type;
if (!(irq_data->type_rising_mask | irq_data->type_falling_mask)) if ((t->types_supported & type) != type)
return 0; return -ENOTSUPP;
d->type_buf[reg] &= ~(irq_data->type_falling_mask | reg = t->type_reg_offset / map->reg_stride;
irq_data->type_rising_mask);
if (t->type_reg_mask)
d->type_buf[reg] &= ~t->type_reg_mask;
else
d->type_buf[reg] &= ~(t->type_falling_val |
t->type_rising_val |
t->type_level_low_val |
t->type_level_high_val);
switch (type) { switch (type) {
case IRQ_TYPE_EDGE_FALLING: case IRQ_TYPE_EDGE_FALLING:
d->type_buf[reg] |= irq_data->type_falling_mask; d->type_buf[reg] |= t->type_falling_val;
break; break;
case IRQ_TYPE_EDGE_RISING: case IRQ_TYPE_EDGE_RISING:
d->type_buf[reg] |= irq_data->type_rising_mask; d->type_buf[reg] |= t->type_rising_val;
break; break;
case IRQ_TYPE_EDGE_BOTH: case IRQ_TYPE_EDGE_BOTH:
d->type_buf[reg] |= (irq_data->type_falling_mask | d->type_buf[reg] |= (t->type_falling_val |
irq_data->type_rising_mask); t->type_rising_val);
break; break;
case IRQ_TYPE_LEVEL_HIGH:
d->type_buf[reg] |= t->type_level_high_val;
break;
case IRQ_TYPE_LEVEL_LOW:
d->type_buf[reg] |= t->type_level_low_val;
break;
default: default:
return -EINVAL; return -EINVAL;
} }

View file

@ -25,60 +25,92 @@ struct max77620_gpio {
static const struct regmap_irq max77620_gpio_irqs[] = { static const struct regmap_irq max77620_gpio_irqs[] = {
[0] = { [0] = {
.mask = MAX77620_IRQ_LVL2_GPIO_EDGE0,
.type_rising_mask = MAX77620_CNFG_GPIO_INT_RISING,
.type_falling_mask = MAX77620_CNFG_GPIO_INT_FALLING,
.reg_offset = 0, .reg_offset = 0,
.type_reg_offset = 0, .mask = MAX77620_IRQ_LVL2_GPIO_EDGE0,
.type = {
.type_rising_val = MAX77620_CNFG_GPIO_INT_RISING,
.type_falling_val = MAX77620_CNFG_GPIO_INT_FALLING,
.type_reg_mask = MAX77620_CNFG_GPIO_INT_MASK,
.type_reg_offset = 0,
.types_supported = IRQ_TYPE_EDGE_BOTH,
},
}, },
[1] = { [1] = {
.mask = MAX77620_IRQ_LVL2_GPIO_EDGE1,
.type_rising_mask = MAX77620_CNFG_GPIO_INT_RISING,
.type_falling_mask = MAX77620_CNFG_GPIO_INT_FALLING,
.reg_offset = 0, .reg_offset = 0,
.type_reg_offset = 1, .mask = MAX77620_IRQ_LVL2_GPIO_EDGE1,
.type = {
.type_rising_val = MAX77620_CNFG_GPIO_INT_RISING,
.type_falling_val = MAX77620_CNFG_GPIO_INT_FALLING,
.type_reg_mask = MAX77620_CNFG_GPIO_INT_MASK,
.type_reg_offset = 1,
.types_supported = IRQ_TYPE_EDGE_BOTH,
},
}, },
[2] = { [2] = {
.mask = MAX77620_IRQ_LVL2_GPIO_EDGE2,
.type_rising_mask = MAX77620_CNFG_GPIO_INT_RISING,
.type_falling_mask = MAX77620_CNFG_GPIO_INT_FALLING,
.reg_offset = 0, .reg_offset = 0,
.type_reg_offset = 2, .mask = MAX77620_IRQ_LVL2_GPIO_EDGE2,
.type = {
.type_rising_val = MAX77620_CNFG_GPIO_INT_RISING,
.type_falling_val = MAX77620_CNFG_GPIO_INT_FALLING,
.type_reg_mask = MAX77620_CNFG_GPIO_INT_MASK,
.type_reg_offset = 2,
.types_supported = IRQ_TYPE_EDGE_BOTH,
},
}, },
[3] = { [3] = {
.mask = MAX77620_IRQ_LVL2_GPIO_EDGE3,
.type_rising_mask = MAX77620_CNFG_GPIO_INT_RISING,
.type_falling_mask = MAX77620_CNFG_GPIO_INT_FALLING,
.reg_offset = 0, .reg_offset = 0,
.type_reg_offset = 3, .mask = MAX77620_IRQ_LVL2_GPIO_EDGE3,
.type = {
.type_rising_val = MAX77620_CNFG_GPIO_INT_RISING,
.type_falling_val = MAX77620_CNFG_GPIO_INT_FALLING,
.type_reg_mask = MAX77620_CNFG_GPIO_INT_MASK,
.type_reg_offset = 3,
.types_supported = IRQ_TYPE_EDGE_BOTH,
},
}, },
[4] = { [4] = {
.mask = MAX77620_IRQ_LVL2_GPIO_EDGE4,
.type_rising_mask = MAX77620_CNFG_GPIO_INT_RISING,
.type_falling_mask = MAX77620_CNFG_GPIO_INT_FALLING,
.reg_offset = 0, .reg_offset = 0,
.type_reg_offset = 4, .mask = MAX77620_IRQ_LVL2_GPIO_EDGE4,
.type = {
.type_rising_val = MAX77620_CNFG_GPIO_INT_RISING,
.type_falling_val = MAX77620_CNFG_GPIO_INT_FALLING,
.type_reg_mask = MAX77620_CNFG_GPIO_INT_MASK,
.type_reg_offset = 4,
.types_supported = IRQ_TYPE_EDGE_BOTH,
},
}, },
[5] = { [5] = {
.mask = MAX77620_IRQ_LVL2_GPIO_EDGE5,
.type_rising_mask = MAX77620_CNFG_GPIO_INT_RISING,
.type_falling_mask = MAX77620_CNFG_GPIO_INT_FALLING,
.reg_offset = 0, .reg_offset = 0,
.type_reg_offset = 5, .mask = MAX77620_IRQ_LVL2_GPIO_EDGE5,
.type = {
.type_rising_val = MAX77620_CNFG_GPIO_INT_RISING,
.type_falling_val = MAX77620_CNFG_GPIO_INT_FALLING,
.type_reg_mask = MAX77620_CNFG_GPIO_INT_MASK,
.type_reg_offset = 5,
.types_supported = IRQ_TYPE_EDGE_BOTH,
},
}, },
[6] = { [6] = {
.mask = MAX77620_IRQ_LVL2_GPIO_EDGE6,
.type_rising_mask = MAX77620_CNFG_GPIO_INT_RISING,
.type_falling_mask = MAX77620_CNFG_GPIO_INT_FALLING,
.reg_offset = 0, .reg_offset = 0,
.type_reg_offset = 6, .mask = MAX77620_IRQ_LVL2_GPIO_EDGE6,
.type = {
.type_rising_val = MAX77620_CNFG_GPIO_INT_RISING,
.type_falling_val = MAX77620_CNFG_GPIO_INT_FALLING,
.type_reg_mask = MAX77620_CNFG_GPIO_INT_MASK,
.type_reg_offset = 6,
.types_supported = IRQ_TYPE_EDGE_BOTH,
},
}, },
[7] = { [7] = {
.mask = MAX77620_IRQ_LVL2_GPIO_EDGE7,
.type_rising_mask = MAX77620_CNFG_GPIO_INT_RISING,
.type_falling_mask = MAX77620_CNFG_GPIO_INT_FALLING,
.reg_offset = 0, .reg_offset = 0,
.type_reg_offset = 7, .mask = MAX77620_IRQ_LVL2_GPIO_EDGE7,
.type = {
.type_rising_val = MAX77620_CNFG_GPIO_INT_RISING,
.type_falling_val = MAX77620_CNFG_GPIO_INT_FALLING,
.type_reg_mask = MAX77620_CNFG_GPIO_INT_MASK,
.type_reg_offset = 7,
.types_supported = IRQ_TYPE_EDGE_BOTH,
},
}, },
}; };

View file

@ -1089,22 +1089,37 @@ int regmap_fields_read(struct regmap_field *field, unsigned int id,
int regmap_fields_update_bits_base(struct regmap_field *field, unsigned int id, int regmap_fields_update_bits_base(struct regmap_field *field, unsigned int id,
unsigned int mask, unsigned int val, unsigned int mask, unsigned int val,
bool *change, bool async, bool force); bool *change, bool async, bool force);
/**
* struct regmap_irq_type - IRQ type definitions.
*
* @type_reg_offset: Offset register for the irq type setting.
* @type_rising_val: Register value to configure RISING type irq.
* @type_falling_val: Register value to configure FALLING type irq.
* @type_level_low_val: Register value to configure LEVEL_LOW type irq.
* @type_level_high_val: Register value to configure LEVEL_HIGH type irq.
* @types_supported: logical OR of IRQ_TYPE_* flags indicating supported types.
*/
struct regmap_irq_type {
unsigned int type_reg_offset;
unsigned int type_reg_mask;
unsigned int type_rising_val;
unsigned int type_falling_val;
unsigned int type_level_low_val;
unsigned int type_level_high_val;
unsigned int types_supported;
};
/** /**
* struct regmap_irq - Description of an IRQ for the generic regmap irq_chip. * struct regmap_irq - Description of an IRQ for the generic regmap irq_chip.
* *
* @reg_offset: Offset of the status/mask register within the bank * @reg_offset: Offset of the status/mask register within the bank
* @mask: Mask used to flag/control the register. * @mask: Mask used to flag/control the register.
* @type_reg_offset: Offset register for the irq type setting. * @type: IRQ trigger type setting details if supported.
* @type_rising_mask: Mask bit to configure RISING type irq.
* @type_falling_mask: Mask bit to configure FALLING type irq.
*/ */
struct regmap_irq { struct regmap_irq {
unsigned int reg_offset; unsigned int reg_offset;
unsigned int mask; unsigned int mask;
unsigned int type_reg_offset; struct regmap_irq_type type;
unsigned int type_rising_mask;
unsigned int type_falling_mask;
}; };
#define REGMAP_IRQ_REG(_irq, _off, _mask) \ #define REGMAP_IRQ_REG(_irq, _off, _mask) \